summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore39
-rw-r--r--CREDITS59
-rw-r--r--Changelog613
-rw-r--r--INSTALL18
-rw-r--r--INSTALL.md17
-rw-r--r--LICENSE.md (renamed from LICENSE)72
-rw-r--r--MAINTAINERS582
-rw-r--r--Makefile135
l---------README1
-rw-r--r--README.md22
-rw-r--r--RELEASE2
-rw-r--r--RELEASE_NOTES81
-rw-r--r--arch.mak5
-rw-r--r--avconv.c2679
-rw-r--r--avplay.c3014
-rw-r--r--avprobe.c975
-rw-r--r--cmdutils.c976
-rw-r--r--cmdutils.h142
-rw-r--r--cmdutils_common_opts.h23
-rw-r--r--cmdutils_opencl.c274
-rw-r--r--common.mak93
-rw-r--r--compat/aix/math.h14
-rw-r--r--compat/avisynth/avisynth_c.h880
-rw-r--r--compat/avisynth/avisynth_c_25.h68
-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-xconfigure1411
-rw-r--r--doc/APIchanges1303
-rw-r--r--doc/Doxyfile18
-rw-r--r--doc/Makefile161
-rw-r--r--doc/RELEASE_NOTES75
-rw-r--r--doc/authors.texi11
-rw-r--r--doc/avplay.texi184
-rw-r--r--doc/avprobe.texi141
-rw-r--r--doc/avtools-common-opts.texi193
-rw-r--r--doc/avutil.txt36
-rw-r--r--doc/bitstream_filters.texi87
-rw-r--r--doc/bootstrap.min.css5
-rw-r--r--doc/build_system.txt31
-rw-r--r--doc/codecs.texi1141
-rw-r--r--doc/decoders.texi193
-rw-r--r--doc/default.css165
-rw-r--r--doc/demuxers.texi432
-rw-r--r--doc/developer.texi422
-rw-r--r--doc/devices.texi25
-rwxr-xr-xdoc/doxy-wrapper.sh8
-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.texi1790
-rw-r--r--doc/errno.txt174
-rw-r--r--doc/eval.texi156
-rw-r--r--doc/examples/Makefile43
-rw-r--r--doc/examples/README23
-rw-r--r--doc/examples/avio_reading.c134
-rw-r--r--doc/examples/decoding_encoding.c (renamed from doc/examples/avcodec.c)341
-rw-r--r--doc/examples/demuxing_decoding.c386
-rw-r--r--doc/examples/extract_mvs.c185
-rw-r--r--doc/examples/filter_audio.c8
-rw-r--r--doc/examples/filtering_audio.c280
-rw-r--r--doc/examples/filtering_video.c261
-rw-r--r--doc/examples/metadata.c4
-rw-r--r--doc/examples/muxing.c (renamed from doc/examples/output.c)457
-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.c97
-rw-r--r--doc/examples/transcoding.c579
-rw-r--r--doc/faq.texi314
-rw-r--r--doc/fate.texi247
-rw-r--r--doc/fate_config.sh.template29
-rw-r--r--doc/ffmpeg-bitstream-filters.texi45
-rw-r--r--doc/ffmpeg-codecs.texi42
-rw-r--r--doc/ffmpeg-devices.texi42
-rw-r--r--doc/ffmpeg-filters.texi42
-rw-r--r--doc/ffmpeg-formats.texi42
-rw-r--r--doc/ffmpeg-protocols.texi42
-rw-r--r--doc/ffmpeg-resampler.texi44
-rw-r--r--doc/ffmpeg-scaler.texi43
-rw-r--r--doc/ffmpeg-utils.texi42
-rw-r--r--doc/ffmpeg.texi (renamed from doc/avconv.texi)862
-rw-r--r--doc/ffmpeg.txt47
-rw-r--r--doc/ffplay.texi305
-rw-r--r--doc/ffprobe.texi681
-rw-r--r--doc/ffprobe.xsd336
-rw-r--r--doc/ffserver.conf371
-rw-r--r--doc/ffserver.texi907
-rw-r--r--doc/fftools-common-opts.texi331
-rw-r--r--doc/filter_design.txt270
-rw-r--r--doc/filters.texi10074
-rw-r--r--doc/formats.texi228
-rw-r--r--doc/general.texi313
-rw-r--r--doc/git-howto.texi93
-rw-r--r--doc/git-howto.txt272
-rw-r--r--doc/indevs.texi893
-rw-r--r--doc/issue_tracker.txt194
-rw-r--r--doc/libavcodec.texi48
-rw-r--r--doc/libavdevice.texi45
-rw-r--r--doc/libavfilter.texi92
-rw-r--r--doc/libavformat.texi48
-rw-r--r--doc/libavutil.texi62
-rw-r--r--doc/libswresample.texi70
-rw-r--r--doc/libswscale.texi63
-rw-r--r--doc/metadata.texi20
-rw-r--r--doc/mips.txt75
-rw-r--r--doc/multithreading.txt4
-rw-r--r--doc/muxers.texi834
-rw-r--r--doc/nut.texi5
-rw-r--r--doc/optimization.txt8
-rw-r--r--doc/outdevs.texi425
-rw-r--r--doc/platform.texi72
-rw-r--r--doc/print_options.c10
-rw-r--r--doc/protocols.texi657
-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.pm221
-rw-r--r--[-rwxr-xr-x]doc/texi2pod.pl75
-rw-r--r--doc/texidep.pl32
-rw-r--r--doc/utils.texi1067
-rw-r--r--doc/viterbi.txt109
-rw-r--r--doc/writing_filters.txt424
-rw-r--r--ffmpeg.c3896
-rw-r--r--ffmpeg.h (renamed from avconv.h)171
-rw-r--r--ffmpeg_dxva2.c (renamed from avconv_dxva2.c)13
-rw-r--r--ffmpeg_filter.c (renamed from avconv_filter.c)462
-rw-r--r--ffmpeg_opt.c (renamed from avconv_opt.c)1070
-rw-r--r--ffmpeg_vda.c (renamed from avconv_vda.c)10
-rw-r--r--ffmpeg_vdpau.c (renamed from avconv_vdpau.c)80
-rw-r--r--ffplay.c3854
-rw-r--r--ffprobe.c3177
-rw-r--r--ffserver.c3749
-rw-r--r--ffserver_config.c1224
-rw-r--r--ffserver_config.h129
-rw-r--r--libavcodec/012v.c159
-rw-r--r--libavcodec/4xm.c165
-rw-r--r--libavcodec/8bps.c31
-rw-r--r--libavcodec/8svx.c119
-rw-r--r--libavcodec/Makefile221
-rw-r--r--libavcodec/a64colors.h8
-rw-r--r--libavcodec/a64enc.h55
-rw-r--r--libavcodec/a64multienc.c61
-rw-r--r--libavcodec/a64tables.h8
-rw-r--r--libavcodec/aac.h39
-rw-r--r--libavcodec/aac_ac3_parser.c8
-rw-r--r--libavcodec/aac_ac3_parser.h8
-rw-r--r--libavcodec/aac_adtstoasc_bsf.c15
-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.c26
-rw-r--r--libavcodec/aacdec.c348
-rw-r--r--libavcodec/aacdectab.h8
-rw-r--r--libavcodec/aacenc.c48
-rw-r--r--libavcodec/aacenc.h20
-rw-r--r--libavcodec/aacps.c32
-rw-r--r--libavcodec/aacps.h8
-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.c115
-rw-r--r--libavcodec/aacsbr.c115
-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.c8
-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/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/opus_imdct_init.c8
-rw-r--r--libavcodec/aarch64/opus_imdct_neon.S8
-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.c8
-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.c271
-rw-r--r--libavcodec/ac3dec.h54
-rw-r--r--libavcodec/ac3dec_data.c8
-rw-r--r--libavcodec/ac3dec_data.h8
-rw-r--r--libavcodec/ac3dec_fixed.c195
-rw-r--r--libavcodec/ac3dec_float.c91
-rw-r--r--libavcodec/ac3dsp.c80
-rw-r--r--libavcodec/ac3dsp.h18
-rw-r--r--libavcodec/ac3enc.c72
-rw-r--r--libavcodec/ac3enc.h8
-rw-r--r--libavcodec/ac3enc_fixed.c23
-rw-r--r--libavcodec/ac3enc_float.c24
-rw-r--r--libavcodec/ac3enc_opts_template.c8
-rw-r--r--libavcodec/ac3enc_template.c45
-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.c56
-rw-r--r--libavcodec/acelp_vectors.h63
-rw-r--r--libavcodec/adpcm.c377
-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.c66
-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.c12
-rw-r--r--libavcodec/aic.c30
-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.c134
-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.c114
-rw-r--r--libavcodec/amr.h8
-rw-r--r--libavcodec/amrnbdata.h12
-rw-r--r--libavcodec/amrnbdec.c78
-rw-r--r--libavcodec/amrwbdata.h10
-rw-r--r--libavcodec/amrwbdec.c73
-rw-r--r--libavcodec/anm.c16
-rw-r--r--libavcodec/ansi.c92
-rw-r--r--libavcodec/apedec.c71
-rw-r--r--libavcodec/arm/Makefile5
-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/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.c12
-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/fmtconvert_vfp_armv6.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/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.c (renamed from libavcodec/arm/apedsp_init_arm.c)12
-rw-r--r--libavcodec/arm/lossless_audiodsp_neon.S (renamed from libavcodec/arm/apedsp_neon.S)10
-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.S8
-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.c211
-rw-r--r--libavcodec/ass.h85
-rw-r--r--libavcodec/ass_split.c529
-rw-r--r--libavcodec/ass_split.h192
-rw-r--r--libavcodec/assdec.c78
-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.c100
-rw-r--r--libavcodec/atrac.c11
-rw-r--r--libavcodec/atrac.h11
-rw-r--r--libavcodec/atrac1.c19
-rw-r--r--libavcodec/atrac1data.h10
-rw-r--r--libavcodec/atrac3.c57
-rw-r--r--libavcodec/atrac3data.h8
-rw-r--r--libavcodec/atrac3plus.c48
-rw-r--r--libavcodec/atrac3plus.h16
-rw-r--r--libavcodec/atrac3plus_data.h8
-rw-r--r--libavcodec/atrac3plusdec.c33
-rw-r--r--libavcodec/atrac3plusdsp.c8
-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.h84
-rw-r--r--libavcodec/audiodsp.c8
-rw-r--r--libavcodec/audiodsp.h8
-rw-r--r--libavcodec/aura.c12
-rw-r--r--libavcodec/avcodec.h1066
-rw-r--r--libavcodec/avcodecres.rc55
-rw-r--r--libavcodec/avdct.c134
-rw-r--r--libavcodec/avdct.h82
-rw-r--r--libavcodec/avfft.c10
-rw-r--r--libavcodec/avfft.h8
-rw-r--r--libavcodec/avpacket.c253
-rw-r--r--libavcodec/avpicture.c75
-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.c113
-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.c107
-rw-r--r--libavcodec/bitstream_filter.c21
-rw-r--r--libavcodec/blockdsp.c10
-rw-r--r--libavcodec/blockdsp.h9
-rw-r--r--libavcodec/bmp.c80
-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.c25
-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.c253
-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/cavs.c78
-rw-r--r--libavcodec/cavs.h12
-rw-r--r--libavcodec/cavs_parser.c8
-rw-r--r--libavcodec/cavsdata.c15
-rw-r--r--libavcodec/cavsdec.c122
-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/cdgraphics.c36
-rw-r--r--libavcodec/cdxl.c29
-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.c23
-rw-r--r--libavcodec/cngdec.c32
-rw-r--r--libavcodec/cngenc.c12
-rw-r--r--libavcodec/codec_desc.c528
-rw-r--r--libavcodec/cook.c79
-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/dca.c14
-rw-r--r--libavcodec/dca.h10
-rw-r--r--libavcodec/dca_parser.c20
-rw-r--r--libavcodec/dcadata.h8
-rw-r--r--libavcodec/dcadec.c787
-rw-r--r--libavcodec/dcadsp.c8
-rw-r--r--libavcodec/dcadsp.h10
-rw-r--r--libavcodec/dcaenc.c975
-rw-r--r--libavcodec/dcaenc.h113
-rw-r--r--libavcodec/dcahuff.h8
-rw-r--r--libavcodec/dct-test.c93
-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.c571
-rw-r--r--libavcodec/dirac_dwt.h123
-rw-r--r--libavcodec/dirac_parser.c18
-rw-r--r--libavcodec/diracdec.c2002
-rw-r--r--libavcodec/diracdsp.c201
-rw-r--r--libavcodec/diracdsp.h67
-rw-r--r--libavcodec/dnxhd_parser.c50
-rw-r--r--libavcodec/dnxhddata.c714
-rw-r--r--libavcodec/dnxhddata.h18
-rw-r--r--libavcodec/dnxhddec.c93
-rw-r--r--libavcodec/dnxhdenc.c145
-rw-r--r--libavcodec/dnxhdenc.h10
-rw-r--r--libavcodec/dpcm.c21
-rw-r--r--libavcodec/dpx.c334
-rw-r--r--libavcodec/dpx_parser.c114
-rw-r--r--libavcodec/dpxenc.c207
-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/dump_extradata_bsf.c13
-rw-r--r--libavcodec/dv.c47
-rw-r--r--libavcodec/dv.h19
-rw-r--r--libavcodec/dv_profile.c42
-rw-r--r--libavcodec/dv_profile.h22
-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.c10
-rw-r--r--libavcodec/dvbsubdec.c504
-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.c161
-rw-r--r--libavcodec/dvdsub_parser.c15
-rw-r--r--libavcodec/dvdsubdec.c271
-rw-r--r--libavcodec/dvdsubenc.c429
-rw-r--r--libavcodec/dvenc.c40
-rw-r--r--libavcodec/dxa.c100
-rw-r--r--libavcodec/dxtory.c46
-rw-r--r--libavcodec/dxva2.c8
-rw-r--r--libavcodec/dxva2.h12
-rw-r--r--libavcodec/dxva2_h264.c16
-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.c8
-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.c53
-rw-r--r--libavcodec/eatgq.c24
-rw-r--r--libavcodec/eatgv.c38
-rw-r--r--libavcodec/eatqi.c17
-rw-r--r--libavcodec/elbg.c55
-rw-r--r--libavcodec/elbg.h16
-rw-r--r--libavcodec/error_resilience.c298
-rw-r--r--libavcodec/error_resilience.h13
-rw-r--r--libavcodec/escape124.c43
-rw-r--r--libavcodec/escape130.c18
-rw-r--r--libavcodec/evrcdata.h1499
-rw-r--r--libavcodec/evrcdec.c917
-rw-r--r--libavcodec/exif.c142
-rw-r--r--libavcodec/exif.h170
-rw-r--r--libavcodec/exr.c132
-rw-r--r--libavcodec/faandct.h8
-rw-r--r--libavcodec/faanidct.c8
-rw-r--r--libavcodec/faanidct.h8
-rw-r--r--libavcodec/faxcompr.c34
-rw-r--r--libavcodec/faxcompr.h8
-rw-r--r--libavcodec/fdctdsp.c8
-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.c164
-rw-r--r--libavcodec/ffv1.h65
-rw-r--r--libavcodec/ffv1dec.c647
-rw-r--r--libavcodec/ffv1enc.c757
-rw-r--r--libavcodec/ffwavesynth.c481
-rw-r--r--libavcodec/fic.c37
-rw-r--r--libavcodec/flac.c11
-rw-r--r--libavcodec/flac.h8
-rw-r--r--libavcodec/flac_parser.c112
-rw-r--r--libavcodec/flacdata.c10
-rw-r--r--libavcodec/flacdata.h10
-rw-r--r--libavcodec/flacdec.c82
-rw-r--r--libavcodec/flacdsp.c14
-rw-r--r--libavcodec/flacdsp.h15
-rw-r--r--libavcodec/flacdsp_lpc_template.c26
-rw-r--r--libavcodec/flacdsp_template.c8
-rw-r--r--libavcodec/flacenc.c79
-rw-r--r--libavcodec/flashsv.c50
-rw-r--r--libavcodec/flashsv2enc.c920
-rw-r--r--libavcodec/flashsvenc.c20
-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.c303
-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.c56
-rw-r--r--libavcodec/g722.c8
-rw-r--r--libavcodec/g722.h8
-rw-r--r--libavcodec/g722dec.c14
-rw-r--r--libavcodec/g722enc.c15
-rw-r--r--libavcodec/g723_1.c1304
-rw-r--r--libavcodec/g723_1_data.h171
-rw-r--r--libavcodec/g726.c49
-rw-r--r--libavcodec/g729.h (renamed from libavcodec/x86/audiodsp.h)24
-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.h140
-rw-r--r--libavcodec/gif.c266
-rw-r--r--libavcodec/gif.h49
-rw-r--r--libavcodec/gifdec.c472
-rw-r--r--libavcodec/golomb-test.c12
-rw-r--r--libavcodec/golomb.c8
-rw-r--r--libavcodec/golomb.h42
-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.c86
-rw-r--r--libavcodec/h261enc.c111
-rw-r--r--libavcodec/h263.c8
-rw-r--r--libavcodec/h263.h13
-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.c189
-rw-r--r--libavcodec/h263dsp.c8
-rw-r--r--libavcodec/h263dsp.h8
-rw-r--r--libavcodec/h264.c639
-rw-r--r--libavcodec/h264.h147
-rw-r--r--libavcodec/h264_cabac.c66
-rw-r--r--libavcodec/h264_cavlc.c124
-rw-r--r--libavcodec/h264_direct.c17
-rw-r--r--libavcodec/h264_loopfilter.c20
-rw-r--r--libavcodec/h264_mb.c97
-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.c134
-rw-r--r--libavcodec/h264_picture.c43
-rw-r--r--libavcodec/h264_ps.c146
-rw-r--r--libavcodec/h264_refs.c99
-rw-r--r--libavcodec/h264_sei.c185
-rw-r--r--libavcodec/h264_slice.c485
-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.h10
-rw-r--r--libavcodec/h264dsp.c25
-rw-r--r--libavcodec/h264dsp.h8
-rw-r--r--libavcodec/h264dsp_template.c46
-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.c2030
-rw-r--r--libavcodec/hevc.h191
-rw-r--r--libavcodec/hevc_cabac.c1071
-rw-r--r--libavcodec/hevc_filter.c740
-rw-r--r--libavcodec/hevc_mvs.c514
-rw-r--r--libavcodec/hevc_parser.c245
-rw-r--r--libavcodec/hevc_ps.c341
-rw-r--r--libavcodec/hevc_refs.c91
-rw-r--r--libavcodec/hevc_sei.c105
-rw-r--r--libavcodec/hevcdsp.c178
-rw-r--r--libavcodec/hevcdsp.h127
-rw-r--r--libavcodec/hevcdsp_template.c1849
-rw-r--r--libavcodec/hevcpred.c19
-rw-r--r--libavcodec/hevcpred.h45
-rw-r--r--libavcodec/hevcpred_template.c287
-rw-r--r--libavcodec/hnm4video.c97
-rw-r--r--libavcodec/hpel_template.c8
-rw-r--r--libavcodec/hpeldsp.c10
-rw-r--r--libavcodec/hpeldsp.h9
-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.c712
-rw-r--r--libavcodec/huffyuvdsp.c43
-rw-r--r--libavcodec/huffyuvdsp.h29
-rw-r--r--libavcodec/huffyuvenc.c557
-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.c53
-rw-r--r--libavcodec/imcdata.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.c12
-rw-r--r--libavcodec/indeo2data.h8
-rw-r--r--libavcodec/indeo3.c100
-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.c19
-rw-r--r--libavcodec/internal.h76
-rw-r--r--libavcodec/interplayvideo.c64
-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.c134
-rw-r--r--libavcodec/ituh263enc.c35
-rw-r--r--libavcodec/ivi_common.c88
-rw-r--r--libavcodec/ivi_common.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.c154
-rw-r--r--libavcodec/jpeglsdec.h8
-rw-r--r--libavcodec/jpeglsenc.c26
-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.c45
-rw-r--r--libavcodec/lclenc.c32
-rw-r--r--libavcodec/libaacplus.c141
-rw-r--r--libavcodec/libavcodec.v3
-rw-r--r--libavcodec/libcelt_dec.c140
-rw-r--r--libavcodec/libfaac.c30
-rw-r--r--libavcodec/libfdk-aacdec.c14
-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.c27
-rw-r--r--libavcodec/libopencore-amr.c42
-rw-r--r--libavcodec/libopenjpegdec.c145
-rw-r--r--libavcodec/libopenjpegenc.c460
-rw-r--r--libavcodec/libopus.c8
-rw-r--r--libavcodec/libopus.h8
-rw-r--r--libavcodec/libopusdec.c51
-rw-r--r--libavcodec/libopusenc.c49
-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.c32
-rw-r--r--libavcodec/libspeexenc.c17
-rw-r--r--libavcodec/libstagefright.cpp590
-rw-r--r--libavcodec/libtheoraenc.c72
-rw-r--r--libavcodec/libtwolame.c18
-rw-r--r--libavcodec/libutvideo.h70
-rw-r--r--libavcodec/libutvideodec.cpp272
-rw-r--r--libavcodec/libutvideoenc.cpp246
-rw-r--r--libavcodec/libvo-aacenc.c20
-rw-r--r--libavcodec/libvo-amrwbenc.c20
-rw-r--r--libavcodec/libvorbisdec.c199
-rw-r--r--libavcodec/libvorbisenc.c (renamed from libavcodec/libvorbis.c)104
-rw-r--r--libavcodec/libvpx.c21
-rw-r--r--libavcodec/libvpx.h10
-rw-r--r--libavcodec/libvpxdec.c83
-rw-r--r--libavcodec/libvpxenc.c409
-rw-r--r--libavcodec/libwavpackenc.c8
-rw-r--r--libavcodec/libwebpenc.c100
-rw-r--r--libavcodec/libx264.c244
-rw-r--r--libavcodec/libx265.c10
-rw-r--r--libavcodec/libxavs.c26
-rw-r--r--libavcodec/libxvid.c132
-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.c71
-rw-r--r--libavcodec/loco.c93
-rw-r--r--libavcodec/lossless_audiodsp.c49
-rw-r--r--libavcodec/lossless_audiodsp.h (renamed from libavcodec/apedsp.h)25
-rw-r--r--libavcodec/lossless_videodsp.c128
-rw-r--r--libavcodec/lossless_videodsp.h40
-rw-r--r--libavcodec/lpc.c18
-rw-r--r--libavcodec/lpc.h13
-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.h10
-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.c128
-rw-r--r--libavcodec/me_cmp.h29
-rw-r--r--libavcodec/metasound.c10
-rw-r--r--libavcodec/metasound_data.c16
-rw-r--r--libavcodec/metasound_data.h8
-rw-r--r--libavcodec/microdvddec.c365
-rw-r--r--libavcodec/mimic.c23
-rw-r--r--libavcodec/mips/Makefile20
-rw-r--r--libavcodec/mips/aaccoder_mips.c2498
-rw-r--r--libavcodec/mips/aacdec_mips.c831
-rw-r--r--libavcodec/mips/aacdec_mips.h249
-rw-r--r--libavcodec/mips/aacpsdsp_mips.c459
-rw-r--r--libavcodec/mips/aacpsy_mips.h230
-rw-r--r--libavcodec/mips/aacsbr_mips.c618
-rw-r--r--libavcodec/mips/aacsbr_mips.h493
-rw-r--r--libavcodec/mips/ac3dsp_mips.c412
-rw-r--r--libavcodec/mips/acelp_filters_mips.c216
-rw-r--r--libavcodec/mips/acelp_vectors_mips.c101
-rw-r--r--libavcodec/mips/amrwbdec_mips.c187
-rw-r--r--libavcodec/mips/amrwbdec_mips.h62
-rw-r--r--libavcodec/mips/celp_filters_mips.c288
-rw-r--r--libavcodec/mips/celp_math_mips.c89
-rw-r--r--libavcodec/mips/compute_antialias_fixed.h250
-rw-r--r--libavcodec/mips/compute_antialias_float.h182
-rw-r--r--libavcodec/mips/fft_mips.c534
-rw-r--r--libavcodec/mips/fmtconvert_mips.c342
-rw-r--r--libavcodec/mips/iirfilter_mips.c204
-rw-r--r--libavcodec/mips/lsp_mips.h109
-rw-r--r--libavcodec/mips/mathops.h8
-rw-r--r--libavcodec/mips/mpegaudiodsp_mips_fixed.c907
-rw-r--r--libavcodec/mips/mpegaudiodsp_mips_float.c1250
-rw-r--r--libavcodec/mips/sbrdsp_mips.c940
-rw-r--r--libavcodec/mjpeg.c12
-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.c1158
-rw-r--r--libavcodec/mjpegdec.h24
-rw-r--r--libavcodec/mjpegenc.c119
-rw-r--r--libavcodec/mjpegenc.h10
-rw-r--r--libavcodec/mjpegenc_common.c136
-rw-r--r--libavcodec/mjpegenc_common.h17
-rw-r--r--libavcodec/mlp.c8
-rw-r--r--libavcodec/mlp.h10
-rw-r--r--libavcodec/mlp_parser.c90
-rw-r--r--libavcodec/mlp_parser.h14
-rw-r--r--libavcodec/mlpdec.c132
-rw-r--r--libavcodec/mlpdsp.c8
-rw-r--r--libavcodec/mlpdsp.h8
-rw-r--r--libavcodec/mmvideo.c31
-rw-r--r--libavcodec/motion-test.c152
-rw-r--r--libavcodec/motion_est.c98
-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.c113
-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.c37
-rw-r--r--libavcodec/mpeg12.h8
-rw-r--r--libavcodec/mpeg12data.c76
-rw-r--r--libavcodec/mpeg12data.h11
-rw-r--r--libavcodec/mpeg12dec.c537
-rw-r--r--libavcodec/mpeg12enc.c184
-rw-r--r--libavcodec/mpeg4audio.c18
-rw-r--r--libavcodec/mpeg4audio.h8
-rw-r--r--libavcodec/mpeg4data.h8
-rw-r--r--libavcodec/mpeg4video.c8
-rw-r--r--libavcodec/mpeg4video.h14
-rw-r--r--libavcodec/mpeg4video_parser.c23
-rw-r--r--libavcodec/mpeg4video_parser.h8
-rw-r--r--libavcodec/mpeg4videodec.c500
-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.c18
-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.c10
-rw-r--r--libavcodec/mpegaudiodec_template.c115
-rw-r--r--libavcodec/mpegaudiodecheader.c21
-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_fixed.c41
-rw-r--r--libavcodec/mpegaudioenc_float.c42
-rw-r--r--libavcodec/mpegaudioenc_template.c (renamed from libavcodec/mpegaudioenc.c)90
-rw-r--r--libavcodec/mpegaudiotab.h8
-rw-r--r--libavcodec/mpegutils.c8
-rw-r--r--libavcodec/mpegutils.h8
-rw-r--r--libavcodec/mpegvideo.c1406
-rw-r--r--libavcodec/mpegvideo.h74
-rw-r--r--libavcodec/mpegvideo_enc.c614
-rw-r--r--libavcodec/mpegvideo_motion.c60
-rw-r--r--libavcodec/mpegvideo_parser.c43
-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.c81
-rw-r--r--libavcodec/msrledec.h8
-rw-r--r--libavcodec/mss1.c26
-rw-r--r--libavcodec/mss12.c17
-rw-r--r--libavcodec/mss12.h22
-rw-r--r--libavcodec/mss2.c41
-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.c18
-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.c9
-rw-r--r--libavcodec/nellymoserenc.c24
-rw-r--r--libavcodec/neon/mpegvideo.c8
-rw-r--r--libavcodec/noise_bsf.c19
-rw-r--r--libavcodec/nuv.c67
-rw-r--r--libavcodec/old_codec_ids.h397
-rw-r--r--libavcodec/on2avc.c19
-rw-r--r--libavcodec/on2avcdata.c28
-rw-r--r--libavcodec/on2avcdata.h28
-rw-r--r--libavcodec/options.c95
-rw-r--r--libavcodec/options_table.h129
-rw-r--r--libavcodec/opus.c19
-rw-r--r--libavcodec/opus.h47
-rw-r--r--libavcodec/opus_celt.c12
-rw-r--r--libavcodec/opus_imdct.c8
-rw-r--r--libavcodec/opus_imdct.h8
-rw-r--r--libavcodec/opus_parser.c147
-rw-r--r--libavcodec/opus_silk.c8
-rw-r--r--libavcodec/opusdec.c66
-rw-r--r--libavcodec/paf.h28
-rw-r--r--libavcodec/pafaudio.c12
-rw-r--r--libavcodec/pafvideo.c41
-rw-r--r--libavcodec/pamenc.c75
-rw-r--r--libavcodec/parser.c65
-rw-r--r--libavcodec/parser.h8
-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.c50
-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.c895
-rw-r--r--libavcodec/pngdsp.c8
-rw-r--r--libavcodec/pngdsp.h8
-rw-r--r--libavcodec/pngenc.c158
-rw-r--r--libavcodec/pnm.c68
-rw-r--r--libavcodec/pnm.h8
-rw-r--r--libavcodec/pnm_parser.c8
-rw-r--r--libavcodec/pnmdec.c113
-rw-r--r--libavcodec/pnmenc.c22
-rw-r--r--libavcodec/ppc/Makefile7
-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.c10
-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.c8
-rw-r--r--libavcodec/ppc/h264dsp.c8
-rw-r--r--libavcodec/ppc/h264qpel.c8
-rw-r--r--libavcodec/ppc/h264qpel_template.c8
-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.c33
-rw-r--r--libavcodec/ppc/lossless_audiodsp_altivec.c (renamed from libavcodec/ppc/apedsp_altivec.c)12
-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.c8
-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.c8
-rw-r--r--libavcodec/ppc/videodsp_ppc.c8
-rw-r--r--libavcodec/ppc/vorbisdsp_altivec.c8
-rw-r--r--libavcodec/ppc/vp3dsp_altivec.c8
-rw-r--r--libavcodec/ppc/vp8dsp_altivec.c8
-rw-r--r--libavcodec/proresdata.c8
-rw-r--r--libavcodec/proresdata.h8
-rw-r--r--libavcodec/proresdec.h55
-rw-r--r--libavcodec/proresdec2.c689
-rw-r--r--libavcodec/proresdec_lgpl.c (renamed from libavcodec/proresdec.c)20
-rw-r--r--libavcodec/proresdsp.c16
-rw-r--r--libavcodec/proresdsp.h13
-rw-r--r--libavcodec/proresenc_anatoliy.c636
-rw-r--r--libavcodec/proresenc_kostya.c (renamed from libavcodec/proresenc.c)66
-rw-r--r--libavcodec/psymodel.c38
-rw-r--r--libavcodec/psymodel.h10
-rw-r--r--libavcodec/pthread.c8
-rw-r--r--libavcodec/pthread_frame.c170
-rw-r--r--libavcodec/pthread_internal.h8
-rw-r--r--libavcodec/pthread_slice.c85
-rw-r--r--libavcodec/ptx.c20
-rw-r--r--libavcodec/put_bits.h37
-rw-r--r--libavcodec/qcelpdata.h40
-rw-r--r--libavcodec/qcelpdec.c46
-rw-r--r--libavcodec/qdm2.c135
-rw-r--r--libavcodec/qdm2_tablegen.c8
-rw-r--r--libavcodec/qdm2_tablegen.h29
-rw-r--r--libavcodec/qdm2data.h8
-rw-r--r--libavcodec/qdrw.c14
-rw-r--r--libavcodec/qpeg.c61
-rw-r--r--libavcodec/qpel_template.c10
-rw-r--r--libavcodec/qpeldsp.c56
-rw-r--r--libavcodec/qpeldsp.h8
-rw-r--r--libavcodec/qtrle.c78
-rw-r--r--libavcodec/qtrleenc.c160
-rw-r--r--libavcodec/r210dec.c29
-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.c29
-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.c72
-rw-r--r--libavcodec/ratecontrol.h16
-rw-r--r--libavcodec/raw.c94
-rw-r--r--libavcodec/raw.h18
-rw-r--r--libavcodec/rawdec.c228
-rw-r--r--libavcodec/rawenc.c21
-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.c16
-rw-r--r--libavcodec/rle.c8
-rw-r--r--libavcodec/rle.h8
-rw-r--r--libavcodec/rnd_avg.h11
-rw-r--r--libavcodec/roqaudioenc.c16
-rw-r--r--libavcodec/roqvideo.c8
-rw-r--r--libavcodec/roqvideo.h12
-rw-r--r--libavcodec/roqvideodec.c38
-rw-r--r--libavcodec/roqvideoenc.c99
-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.c25
-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.c8
-rw-r--r--libavcodec/s3tc.h8
-rw-r--r--libavcodec/samidec.c160
-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.c23
-rw-r--r--libavcodec/sgirledec.c18
-rw-r--r--libavcodec/sh4/README6
-rw-r--r--libavcodec/shorten.c90
-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.c171
-rw-r--r--libavcodec/smc.c18
-rw-r--r--libavcodec/smvjpegdec.c209
-rw-r--r--libavcodec/snow.c723
-rw-r--r--libavcodec/snow.h719
-rw-r--r--libavcodec/snow_dwt.c865
-rw-r--r--libavcodec/snow_dwt.h127
-rw-r--r--libavcodec/snowdata.h132
-rw-r--r--libavcodec/snowdec.c606
-rw-r--r--libavcodec/snowenc.c2025
-rw-r--r--libavcodec/sonic.c1094
-rw-r--r--libavcodec/sp5x.h10
-rw-r--r--libavcodec/sp5xdec.c19
-rw-r--r--libavcodec/sparc/README6
-rw-r--r--libavcodec/srtdec.c145
-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.c76
-rw-r--r--libavcodec/svq1enc.c84
-rw-r--r--libavcodec/svq1enc.h10
-rw-r--r--libavcodec/svq1enc_cb.h8
-rw-r--r--libavcodec/svq3.c129
-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.h18
-rw-r--r--libavcodec/tak.c58
-rw-r--r--libavcodec/tak.h13
-rw-r--r--libavcodec/tak_parser.c32
-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/textdec.c164
-rw-r--r--libavcodec/thread.h23
-rw-r--r--libavcodec/tiertexseqv.c14
-rw-r--r--libavcodec/tiff.c917
-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.c235
-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.c108
-rw-r--r--libavcodec/truespeech.c12
-rw-r--r--libavcodec/truespeech_data.h8
-rw-r--r--libavcodec/tscc.c22
-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.c32
-rw-r--r--libavcodec/twinvq.h8
-rw-r--r--libavcodec/twinvq_data.h8
-rw-r--r--libavcodec/twinvqdec.c10
-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.c1909
-rw-r--r--libavcodec/utvideo.c8
-rw-r--r--libavcodec/utvideo.h8
-rw-r--r--libavcodec/utvideodec.c27
-rw-r--r--libavcodec/utvideoenc.c47
-rw-r--r--libavcodec/v210dec.c128
-rw-r--r--libavcodec/v210dec.h36
-rw-r--r--libavcodec/v210enc.c24
-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.c14
-rw-r--r--libavcodec/vaapi.c33
-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_mpeg.c48
-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.c18
-rw-r--r--libavcodec/vble.c106
-rw-r--r--libavcodec/vc1.c126
-rw-r--r--libavcodec/vc1.h28
-rw-r--r--libavcodec/vc1_block.c58
-rw-r--r--libavcodec/vc1_common.h8
-rw-r--r--libavcodec/vc1_loopfilter.c24
-rw-r--r--libavcodec/vc1_mc.c83
-rw-r--r--libavcodec/vc1_parser.c21
-rw-r--r--libavcodec/vc1_pred.c58
-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.c246
-rw-r--r--libavcodec/vc1dsp.c192
-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.c75
-rw-r--r--libavcodec/vda_h264_dec.c273
-rw-r--r--libavcodec/vda_internal.h8
-rw-r--r--libavcodec/vdpau.c383
-rw-r--r--libavcodec/vdpau.h44
-rw-r--r--libavcodec/vdpau_h264.c8
-rw-r--r--libavcodec/vdpau_internal.h34
-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.h40
-rw-r--r--libavcodec/videodsp.c9
-rw-r--r--libavcodec/videodsp.h27
-rw-r--r--libavcodec/videodsp_template.c34
-rw-r--r--libavcodec/vima.c18
-rw-r--r--libavcodec/vmdaudio.c26
-rw-r--r--libavcodec/vmdvideo.c91
-rw-r--r--libavcodec/vmnc.c33
-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.c49
-rw-r--r--libavcodec/vorbis_parser.h27
-rw-r--r--libavcodec/vorbis_parser_internal.h23
-rw-r--r--libavcodec/vorbisdec.c202
-rw-r--r--libavcodec/vorbisdsp.c8
-rw-r--r--libavcodec/vorbisdsp.h8
-rw-r--r--libavcodec/vorbisenc.c62
-rw-r--r--libavcodec/vp3.c135
-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.c317
-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.c147
-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.c3779
-rw-r--r--libavcodec/vp9.h355
-rw-r--r--libavcodec/vp9_parser.c118
-rw-r--r--libavcodec/vp9block.c1684
-rw-r--r--libavcodec/vp9data.c2133
-rw-r--r--libavcodec/vp9data.h2173
-rw-r--r--libavcodec/vp9dsp.c1532
-rw-r--r--libavcodec/vp9dsp.h118
-rw-r--r--libavcodec/vp9mvs.c352
-rw-r--r--libavcodec/vp9prob.c274
-rw-r--r--libavcodec/vqavideo.c104
-rw-r--r--libavcodec/wavpack.c227
-rw-r--r--libavcodec/wavpack.h194
-rw-r--r--libavcodec/wavpackenc.c2995
-rw-r--r--libavcodec/wavpackenc.h664
-rw-r--r--libavcodec/webp.c93
-rw-r--r--libavcodec/webvttdec.c102
-rw-r--r--libavcodec/webvttenc.c219
-rw-r--r--libavcodec/wma.c28
-rw-r--r--libavcodec/wma.h12
-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.c49
-rw-r--r--libavcodec/wmaenc.c85
-rw-r--r--libavcodec/wmalosslessdec.c132
-rw-r--r--libavcodec/wmaprodata.h8
-rw-r--r--libavcodec/wmaprodec.c61
-rw-r--r--libavcodec/wmavoice.c32
-rw-r--r--libavcodec/wmavoice_data.h8
-rw-r--r--libavcodec/wmv2.c36
-rw-r--r--libavcodec/wmv2.h10
-rw-r--r--libavcodec/wmv2dec.c12
-rw-r--r--libavcodec/wmv2dsp.c8
-rw-r--r--libavcodec/wmv2dsp.h8
-rw-r--r--libavcodec/wmv2enc.c28
-rw-r--r--libavcodec/wnv1.c18
-rw-r--r--libavcodec/ws-snd1.c14
-rw-r--r--libavcodec/x86/Makefile55
-rw-r--r--libavcodec/x86/ac3dsp.asm8
-rw-r--r--libavcodec/x86/ac3dsp_init.c13
-rw-r--r--libavcodec/x86/audiodsp.asm100
-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.c145
-rw-r--r--libavcodec/x86/constants.c26
-rw-r--r--libavcodec/x86/constants.h25
-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.c32
-rw-r--r--libavcodec/x86/dct32.asm12
-rw-r--r--libavcodec/x86/dct_init.c10
-rw-r--r--libavcodec/x86/deinterlace.asm8
-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.asm329
-rw-r--r--libavcodec/x86/flacdsp_init.c117
-rw-r--r--libavcodec/x86/fmtconvert.asm46
-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/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.asm16
-rw-r--r--libavcodec/x86/h264_i386.h14
-rw-r--r--libavcodec/x86/h264_idct.asm8
-rw-r--r--libavcodec/x86/h264_idct_10bit.asm24
-rw-r--r--libavcodec/x86/h264_intrapred.asm13
-rw-r--r--libavcodec/x86/h264_intrapred_10bit.asm52
-rw-r--r--libavcodec/x86/h264_intrapred_init.c8
-rw-r--r--libavcodec/x86/h264_qpel.c26
-rw-r--r--libavcodec/x86/h264_qpel_10bit.asm10
-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.asm8
-rw-r--r--libavcodec/x86/h264chroma_init.c8
-rw-r--r--libavcodec/x86/h264dsp_init.c10
-rw-r--r--libavcodec/x86/hevc_deblock.asm456
-rw-r--r--libavcodec/x86/hevc_idct.asm122
-rw-r--r--libavcodec/x86/hevc_mc.asm1385
-rw-r--r--libavcodec/x86/hevc_res_add.asm388
-rw-r--r--libavcodec/x86/hevcdsp.h156
-rw-r--r--libavcodec/x86/hevcdsp_init.c621
-rw-r--r--libavcodec/x86/hpeldsp.asm318
-rw-r--r--libavcodec/x86/hpeldsp.h23
-rw-r--r--libavcodec/x86/hpeldsp_init.c80
-rw-r--r--libavcodec/x86/hpeldsp_mmx.c53
-rw-r--r--libavcodec/x86/hpeldsp_rnd_template.c39
-rw-r--r--libavcodec/x86/huffyuvdsp.asm172
-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.asm (renamed from libavcodec/x86/apedsp.asm)22
-rw-r--r--libavcodec/x86/lossless_audiodsp_init.c (renamed from libavcodec/x86/apedsp_init.c)12
-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.h13
-rw-r--r--libavcodec/x86/me_cmp.asm645
-rw-r--r--libavcodec/x86/me_cmp_init.c938
-rw-r--r--libavcodec/x86/mlpdsp.asm196
-rw-r--r--libavcodec/x86/mlpdsp_init.c (renamed from libavcodec/x86/mlpdsp.c)37
-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.asm8
-rw-r--r--libavcodec/x86/pngdsp_init.c8
-rw-r--r--libavcodec/x86/proresdsp.asm132
-rw-r--r--libavcodec/x86/proresdsp_init.c10
-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.c70
-rw-r--r--libavcodec/x86/sbrdsp.asm216
-rw-r--r--libavcodec/x86/sbrdsp_init.c30
-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/vc1dsp.asm8
-rw-r--r--libavcodec/x86/vc1dsp.h8
-rw-r--r--libavcodec/x86/vc1dsp_init.c15
-rw-r--r--libavcodec/x86/vc1dsp_mmx.c126
-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.asm8
-rw-r--r--libavcodec/x86/vp3dsp_init.c71
-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.c16
-rw-r--r--libavcodec/x86/vp8dsp_loopfilter.asm8
-rw-r--r--libavcodec/x86/vp9dsp_init.c484
-rw-r--r--libavcodec/x86/vp9intrapred.asm1554
-rw-r--r--libavcodec/x86/vp9itxfm.asm1670
-rw-r--r--libavcodec/x86/vp9lpf.asm816
-rw-r--r--libavcodec/x86/vp9mc.asm (renamed from libavcodec/x86/vp9dsp.asm)220
-rw-r--r--libavcodec/x86/w64xmmtest.c15
-rw-r--r--libavcodec/x86/xvididct.h8
-rw-r--r--libavcodec/x86/xvididct_init.c8
-rw-r--r--libavcodec/x86/xvididct_mmx.c17
-rw-r--r--libavcodec/x86/xvididct_sse2.c35
-rw-r--r--libavcodec/xan.c104
-rw-r--r--libavcodec/xbmdec.c125
-rw-r--r--libavcodec/xbmenc.c33
-rw-r--r--libavcodec/xface.c381
-rw-r--r--libavcodec/xface.h95
-rw-r--r--libavcodec/xfacedec.c188
-rw-r--r--libavcodec/xfaceenc.c238
-rw-r--r--libavcodec/xiph.c12
-rw-r--r--libavcodec/xiph.h12
-rw-r--r--libavcodec/xl.c15
-rw-r--r--libavcodec/xsubdec.c17
-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.c123
-rw-r--r--libavcodec/zmbvenc.c12
-rw-r--r--libavdevice/Makefile44
-rw-r--r--libavdevice/alldevices.c28
-rw-r--r--libavdevice/alsa-audio-common.c137
-rw-r--r--libavdevice/alsa-audio-dec.c69
-rw-r--r--libavdevice/alsa-audio-enc.c69
-rw-r--r--libavdevice/alsa-audio.h24
-rw-r--r--libavdevice/avdevice.c205
-rw-r--r--libavdevice/avdevice.h428
-rw-r--r--libavdevice/avdeviceres.rc55
-rw-r--r--libavdevice/avfoundation.m855
-rw-r--r--libavdevice/bktr.c34
-rw-r--r--libavdevice/caca.c241
-rw-r--r--libavdevice/decklink_common.cpp229
-rw-r--r--libavdevice/decklink_common.h98
-rw-r--r--libavdevice/decklink_common_c.h32
-rw-r--r--libavdevice/decklink_dec.cpp531
-rw-r--r--libavdevice/decklink_dec.h32
-rw-r--r--libavdevice/decklink_dec_c.c54
-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.c1100
-rw-r--r--libavdevice/dshow_capture.h279
-rw-r--r--libavdevice/dshow_common.c190
-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.c362
-rw-r--r--libavdevice/dv1394.c13
-rw-r--r--libavdevice/dv1394.h8
-rw-r--r--libavdevice/fbdev_common.c134
-rw-r--r--libavdevice/fbdev_common.h38
-rw-r--r--libavdevice/fbdev_dec.c (renamed from libavdevice/fbdev.c)109
-rw-r--r--libavdevice/fbdev_enc.c220
-rw-r--r--libavdevice/gdigrab.c636
-rw-r--r--libavdevice/iec61883.c498
-rw-r--r--libavdevice/jack_audio.c33
-rw-r--r--libavdevice/lavfi.c436
-rw-r--r--libavdevice/libavdevice.v2
-rw-r--r--libavdevice/libcdio.c11
-rw-r--r--libavdevice/libdc1394.c9
-rw-r--r--libavdevice/openal-dec.c253
-rw-r--r--libavdevice/opengl_enc.c1306
-rw-r--r--libavdevice/opengl_enc_shaders.h188
-rw-r--r--libavdevice/oss_audio.c25
-rw-r--r--libavdevice/oss_audio.h8
-rw-r--r--libavdevice/oss_audio_dec.c13
-rw-r--r--libavdevice/oss_audio_enc.c20
-rw-r--r--libavdevice/pulse.c195
-rw-r--r--libavdevice/pulse_audio_common.c249
-rw-r--r--libavdevice/pulse_audio_common.h38
-rw-r--r--libavdevice/pulse_audio_dec.c373
-rw-r--r--libavdevice/pulse_audio_enc.c796
-rw-r--r--libavdevice/qtkit.m358
-rw-r--r--libavdevice/sdl.c375
-rw-r--r--libavdevice/sndio_common.c10
-rw-r--r--libavdevice/sndio_common.h10
-rw-r--r--libavdevice/sndio_dec.c9
-rw-r--r--libavdevice/sndio_enc.c19
-rw-r--r--libavdevice/timefilter.c52
-rw-r--r--libavdevice/timefilter.h27
-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.c927
-rw-r--r--libavdevice/v4l2enc.c119
-rw-r--r--libavdevice/version.h16
-rw-r--r--libavdevice/vfwcap.c52
-rw-r--r--libavdevice/x11grab.c146
-rw-r--r--libavdevice/xcbgrab.c33
-rw-r--r--libavdevice/xv.c383
-rw-r--r--libavfilter/Makefile173
-rw-r--r--libavfilter/aeval.c466
-rw-r--r--libavfilter/af_adelay.c282
-rw-r--r--libavfilter/af_aecho.c359
-rw-r--r--libavfilter/af_afade.c300
-rw-r--r--libavfilter/af_aformat.c29
-rw-r--r--libavfilter/af_amerge.c351
-rw-r--r--libavfilter/af_amix.c65
-rw-r--r--libavfilter/af_anull.c27
-rw-r--r--libavfilter/af_apad.c161
-rw-r--r--libavfilter/af_aphaser.c294
-rw-r--r--libavfilter/af_aresample.c351
-rw-r--r--libavfilter/af_asetnsamples.c196
-rw-r--r--libavfilter/af_asetrate.c119
-rw-r--r--libavfilter/af_ashowinfo.c55
-rw-r--r--libavfilter/af_astats.c274
-rw-r--r--libavfilter/af_astreamsync.c240
-rw-r--r--libavfilter/af_asyncts.c39
-rw-r--r--libavfilter/af_atempo.c1202
-rw-r--r--libavfilter/af_biquads.c620
-rw-r--r--libavfilter/af_bs2b.c16
-rw-r--r--libavfilter/af_channelmap.c38
-rw-r--r--libavfilter/af_channelsplit.c40
-rw-r--r--libavfilter/af_compand.c147
-rw-r--r--libavfilter/af_earwax.c172
-rw-r--r--libavfilter/af_flanger.c241
-rw-r--r--libavfilter/af_join.c61
-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.c212
-rw-r--r--libavfilter/af_silenceremove.c479
-rw-r--r--libavfilter/af_volume.c208
-rw-r--r--libavfilter/af_volume.h36
-rw-r--r--libavfilter/af_volumedetect.c159
-rw-r--r--libavfilter/all_channel_layouts.inc68
-rw-r--r--libavfilter/allfilters.c143
-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.c223
-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.c807
-rw-r--r--libavfilter/avf_showspectrum.c532
-rw-r--r--libavfilter/avf_showwaves.c333
-rw-r--r--libavfilter/avfilter.c635
-rw-r--r--libavfilter/avfilter.h462
-rw-r--r--libavfilter/avfiltergraph.c620
-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.c106
-rw-r--r--libavfilter/bufferqueue.h121
-rw-r--r--libavfilter/buffersink.c426
-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.c488
-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.c507
-rw-r--r--libavfilter/f_sendcmd.c576
-rw-r--r--libavfilter/f_zmq.c275
-rw-r--r--libavfilter/fifo.c12
-rw-r--r--libavfilter/filtfmts.c77
-rw-r--r--libavfilter/formats.c340
-rw-r--r--libavfilter/formats.h65
-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.h33
-rw-r--r--libavfilter/gradfun.h16
-rw-r--r--libavfilter/graphdump.c165
-rw-r--r--libavfilter/graphparser.c133
-rw-r--r--libavfilter/internal.h163
-rw-r--r--libavfilter/lavfutils.c104
-rw-r--r--libavfilter/lavfutils.h43
-rw-r--r--libavfilter/libmpcodecs/av_helpers.h27
-rw-r--r--libavfilter/libmpcodecs/cpudetect.h60
-rw-r--r--libavfilter/libmpcodecs/img_format.c244
-rw-r--r--libavfilter/libmpcodecs/img_format.h309
-rw-r--r--libavfilter/libmpcodecs/libvo/fastmemcpy.h99
-rw-r--r--libavfilter/libmpcodecs/libvo/video_out.h300
-rw-r--r--libavfilter/libmpcodecs/mp_image.c257
-rw-r--r--libavfilter/libmpcodecs/mp_image.h159
-rw-r--r--libavfilter/libmpcodecs/mp_msg.h166
-rw-r--r--libavfilter/libmpcodecs/mpc_info.h43
-rw-r--r--libavfilter/libmpcodecs/vf.h169
-rw-r--r--libavfilter/libmpcodecs/vf_eq.c240
-rw-r--r--libavfilter/libmpcodecs/vf_eq2.c519
-rw-r--r--libavfilter/libmpcodecs/vf_fspp.c2124
-rw-r--r--libavfilter/libmpcodecs/vf_ilpack.c458
-rw-r--r--libavfilter/libmpcodecs/vf_pp7.c491
-rw-r--r--libavfilter/libmpcodecs/vf_softpulldown.c163
-rw-r--r--libavfilter/libmpcodecs/vf_uspp.c394
-rw-r--r--libavfilter/libmpcodecs/vfcap.h56
-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.c88
-rw-r--r--libavfilter/src_movie.c609
-rw-r--r--libavfilter/thread.h8
-rw-r--r--libavfilter/transform.c201
-rw-r--r--libavfilter/transform.h127
-rw-r--r--libavfilter/trim.c123
-rw-r--r--libavfilter/unsharp.h81
-rw-r--r--libavfilter/unsharp_opencl.c389
-rw-r--r--libavfilter/unsharp_opencl.h34
-rw-r--r--libavfilter/unsharp_opencl_kernel.h286
-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.c132
-rw-r--r--libavfilter/vf_blackdetect.c209
-rw-r--r--libavfilter/vf_blackframe.c72
-rw-r--r--libavfilter/vf_blend.c465
-rw-r--r--libavfilter/vf_boxblur.c99
-rw-r--r--libavfilter/vf_codecview.c244
-rw-r--r--libavfilter/vf_colorbalance.c213
-rw-r--r--libavfilter/vf_colorchannelmixer.c360
-rw-r--r--libavfilter/vf_colormatrix.c411
-rw-r--r--libavfilter/vf_copy.c22
-rw-r--r--libavfilter/vf_crop.c160
-rw-r--r--libavfilter/vf_cropdetect.c76
-rw-r--r--libavfilter/vf_curves.c570
-rw-r--r--libavfilter/vf_dctdnoiz.c776
-rw-r--r--libavfilter/vf_decimate.c403
-rw-r--r--libavfilter/vf_dejudder.c187
-rw-r--r--libavfilter/vf_delogo.c125
-rw-r--r--libavfilter/vf_deshake.c575
-rw-r--r--libavfilter/vf_drawbox.c333
-rw-r--r--libavfilter/vf_drawtext.c1372
-rw-r--r--libavfilter/vf_edgedetect.c394
-rw-r--r--libavfilter/vf_elbg.c212
-rw-r--r--libavfilter/vf_extractplanes.c335
-rw-r--r--libavfilter/vf_fade.c303
-rw-r--r--libavfilter/vf_field.c111
-rw-r--r--libavfilter/vf_fieldmatch.c984
-rw-r--r--libavfilter/vf_fieldorder.c97
-rw-r--r--libavfilter/vf_format.c70
-rw-r--r--libavfilter/vf_fps.c85
-rw-r--r--libavfilter/vf_framepack.c8
-rw-r--r--libavfilter/vf_framestep.c101
-rw-r--r--libavfilter/vf_frei0r.c175
-rw-r--r--libavfilter/vf_geq.c280
-rw-r--r--libavfilter/vf_gradfun.c54
-rw-r--r--libavfilter/vf_hflip.c141
-rw-r--r--libavfilter/vf_histeq.c281
-rw-r--r--libavfilter/vf_histogram.c376
-rw-r--r--libavfilter/vf_hqdn3d.c74
-rw-r--r--libavfilter/vf_hqdn3d.h12
-rw-r--r--libavfilter/vf_hqx.c562
-rw-r--r--libavfilter/vf_hue.c453
-rw-r--r--libavfilter/vf_idet.c405
-rw-r--r--libavfilter/vf_idet.h76
-rw-r--r--libavfilter/vf_il.c212
-rw-r--r--libavfilter/vf_interlace.c60
-rw-r--r--libavfilter/vf_kerndeint.c318
-rw-r--r--libavfilter/vf_lenscorrection.c229
-rw-r--r--libavfilter/vf_libopencv.c64
-rw-r--r--libavfilter/vf_lut.c237
-rw-r--r--libavfilter/vf_lut3d.c815
-rw-r--r--libavfilter/vf_mcdeint.c315
-rw-r--r--libavfilter/vf_mergeplanes.c313
-rw-r--r--libavfilter/vf_mp.c792
-rw-r--r--libavfilter/vf_mpdecimate.c249
-rw-r--r--libavfilter/vf_noise.c351
-rw-r--r--libavfilter/vf_noise.h64
-rw-r--r--libavfilter/vf_null.c23
-rw-r--r--libavfilter/vf_overlay.c674
-rw-r--r--libavfilter/vf_owdenoise.c342
-rw-r--r--libavfilter/vf_pad.c209
-rw-r--r--libavfilter/vf_perspective.c483
-rw-r--r--libavfilter/vf_phase.c329
-rw-r--r--libavfilter/vf_pixdesctest.c38
-rw-r--r--libavfilter/vf_pp.c193
-rw-r--r--libavfilter/vf_psnr.c386
-rw-r--r--libavfilter/vf_pullup.c780
-rw-r--r--libavfilter/vf_pullup.h71
-rw-r--r--libavfilter/vf_removelogo.c585
-rw-r--r--libavfilter/vf_rotate.c567
-rw-r--r--libavfilter/vf_sab.c339
-rw-r--r--libavfilter/vf_scale.c401
-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.c71
-rw-r--r--libavfilter/vf_shuffleplanes.c10
-rw-r--r--libavfilter/vf_signalstats.c481
-rw-r--r--libavfilter/vf_smartblur.c304
-rw-r--r--libavfilter/vf_spp.c469
-rw-r--r--libavfilter/vf_spp.h59
-rw-r--r--libavfilter/vf_stereo3d.c664
-rw-r--r--libavfilter/vf_subtitles.c445
-rw-r--r--libavfilter/vf_super2xsai.c352
-rw-r--r--libavfilter/vf_swapuv.c110
-rw-r--r--libavfilter/vf_telecine.c285
-rw-r--r--libavfilter/vf_thumbnail.c239
-rw-r--r--libavfilter/vf_tile.c245
-rw-r--r--libavfilter/vf_tinterlace.c400
-rw-r--r--libavfilter/vf_transpose.c219
-rw-r--r--libavfilter/vf_unsharp.c225
-rw-r--r--libavfilter/vf_vflip.c24
-rw-r--r--libavfilter/vf_vidstabdetect.c219
-rw-r--r--libavfilter/vf_vidstabtransform.c320
-rw-r--r--libavfilter/vf_vignette.c346
-rw-r--r--libavfilter/vf_w3fdif.c394
-rw-r--r--libavfilter/vf_xbr.c759
-rw-r--r--libavfilter/vf_yadif.c253
-rw-r--r--libavfilter/vf_zoompan.c309
-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.c337
-rw-r--r--libavfilter/vsrc_color.c202
-rw-r--r--libavfilter/vsrc_life.c450
-rw-r--r--libavfilter/vsrc_mandelbrot.c430
-rw-r--r--libavfilter/vsrc_movie.c286
-rw-r--r--libavfilter/vsrc_mptestsrc.c361
-rw-r--r--libavfilter/vsrc_nullsrc.c136
-rw-r--r--libavfilter/vsrc_testsrc.c766
-rw-r--r--libavfilter/x86/Makefile8
-rw-r--r--libavfilter/x86/af_volume.asm10
-rw-r--r--libavfilter/x86/af_volume_init.c8
-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_noise.c144
-rw-r--r--libavfilter/x86/vf_pullup.asm178
-rw-r--r--libavfilter/x86/vf_pullup_init.c41
-rw-r--r--libavfilter/x86/vf_spp.c233
-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.c31
-rw-r--r--libavformat/Makefile163
-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.c16
-rw-r--r--libavformat/aea.c8
-rw-r--r--libavformat/afc.c79
-rw-r--r--libavformat/aiff.h14
-rw-r--r--libavformat/aiffdec.c105
-rw-r--r--libavformat/aiffenc.c198
-rw-r--r--libavformat/allformats.c108
-rw-r--r--libavformat/amr.c28
-rw-r--r--libavformat/anm.c10
-rw-r--r--libavformat/apc.c19
-rw-r--r--libavformat/ape.c52
-rw-r--r--libavformat/apetag.c92
-rw-r--r--libavformat/apetag.h12
-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.c318
-rw-r--r--libavformat/asfenc.c240
-rw-r--r--libavformat/assdec.c261
-rw-r--r--libavformat/assenc.c195
-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.c8
-rw-r--r--libavformat/avc.h8
-rw-r--r--libavformat/avformat.h741
-rw-r--r--libavformat/avformatres.rc55
-rw-r--r--libavformat/avi.h8
-rw-r--r--libavformat/avidec.c507
-rw-r--r--libavformat/avienc.c135
-rw-r--r--libavformat/avio.c120
-rw-r--r--libavformat/avio.h116
-rw-r--r--libavformat/avio_internal.h25
-rw-r--r--libavformat/aviobuf.c231
-rw-r--r--libavformat/avisynth.c48
-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.c40
-rw-r--r--libavformat/bintext.c388
-rw-r--r--libavformat/bit.c156
-rw-r--r--libavformat/bluray.c235
-rw-r--r--libavformat/bmv.c8
-rw-r--r--libavformat/boadec.c78
-rw-r--r--libavformat/brstm.c297
-rw-r--r--libavformat/c93.c10
-rw-r--r--libavformat/cache.c140
-rw-r--r--libavformat/caf.c56
-rw-r--r--libavformat/caf.h8
-rw-r--r--libavformat/cafdec.c55
-rw-r--r--libavformat/cafenc.c286
-rw-r--r--libavformat/cavsvideodec.c10
-rw-r--r--libavformat/cdg.c22
-rw-r--r--libavformat/cdxl.c53
-rw-r--r--libavformat/cinedec.c325
-rw-r--r--libavformat/concat.c13
-rw-r--r--libavformat/concatdec.c635
-rw-r--r--libavformat/crcenc.c9
-rw-r--r--libavformat/crypto.c14
-rw-r--r--libavformat/cutils.c29
-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/dtsdec.c77
-rw-r--r--libavformat/dtshddec.c139
-rw-r--r--libavformat/dump.c62
-rw-r--r--libavformat/dv.c176
-rw-r--r--libavformat/dv.h10
-rw-r--r--libavformat/dvenc.c118
-rw-r--r--libavformat/dxa.c36
-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.c643
-rw-r--r--libavformat/ffmenc.c281
-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.c86
-rw-r--r--libavformat/flacenc.c39
-rw-r--r--libavformat/flacenc.h8
-rw-r--r--libavformat/flacenc_header.c8
-rw-r--r--libavformat/flic.c25
-rw-r--r--libavformat/flv.h32
-rw-r--r--libavformat/flvdec.c324
-rw-r--r--libavformat/flvenc.c161
-rw-r--r--libavformat/format.c200
-rw-r--r--libavformat/framecrcenc.c53
-rw-r--r--libavformat/framehash.c11
-rw-r--r--libavformat/frmdec.c110
-rw-r--r--libavformat/ftp.c801
-rw-r--r--libavformat/g722.c11
-rw-r--r--libavformat/g723_1.c10
-rw-r--r--libavformat/g729dec.c103
-rw-r--r--libavformat/gif.c386
-rw-r--r--libavformat/gifdec.c334
-rw-r--r--libavformat/golomb_tab.c1
-rw-r--r--libavformat/gopher.c8
-rw-r--r--libavformat/gsmdec.c13
-rw-r--r--libavformat/gxf.c85
-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.c21
-rw-r--r--libavformat/hevc.c10
-rw-r--r--libavformat/hevc.h10
-rw-r--r--libavformat/hevcdec.c8
-rw-r--r--libavformat/hls.c1518
-rw-r--r--libavformat/hlsenc.c200
-rw-r--r--libavformat/hlsproto.c10
-rw-r--r--libavformat/hnm.c12
-rw-r--r--libavformat/http.c252
-rw-r--r--libavformat/http.h14
-rw-r--r--libavformat/httpauth.c13
-rw-r--r--libavformat/httpauth.h8
-rw-r--r--libavformat/icecast.c56
-rw-r--r--libavformat/icodec.c182
-rw-r--r--libavformat/icoenc.c203
-rw-r--r--libavformat/id3v1.c15
-rw-r--r--libavformat/id3v1.h8
-rw-r--r--libavformat/id3v2.c419
-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.h63
-rw-r--r--libavformat/img2_alias_pix.c73
-rw-r--r--libavformat/img2_brender_pix.c57
-rw-r--r--libavformat/img2dec.c581
-rw-r--r--libavformat/img2enc.c133
-rw-r--r--libavformat/ingenientdec.c21
-rw-r--r--libavformat/internal.h96
-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.h50
-rw-r--r--libavformat/iss.c28
-rw-r--r--libavformat/iv8.c8
-rw-r--r--libavformat/ivfdec.c8
-rw-r--r--libavformat/ivfenc.c13
-rw-r--r--libavformat/jacosubdec.c271
-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.c150
-rw-r--r--libavformat/librtmp.c13
-rw-r--r--libavformat/libsmbclient.c212
-rw-r--r--libavformat/libssh.c318
-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.c16
-rw-r--r--libavformat/m4vdec.c22
-rw-r--r--libavformat/matroska.c57
-rw-r--r--libavformat/matroska.h56
-rw-r--r--libavformat/matroskadec.c1198
-rw-r--r--libavformat/matroskaenc.c807
-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.c203
-rw-r--r--libavformat/microdvdenc.c67
-rw-r--r--libavformat/mkvtimestamp_v2.c50
-rw-r--r--libavformat/mlvdec.c463
-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.c29
-rw-r--r--libavformat/mov.c1151
-rw-r--r--libavformat/mov_chan.c13
-rw-r--r--libavformat/mov_chan.h8
-rw-r--r--libavformat/movenc.c1387
-rw-r--r--libavformat/movenc.h28
-rw-r--r--libavformat/movenchint.c23
-rw-r--r--libavformat/mp3dec.c247
-rw-r--r--libavformat/mp3enc.c152
-rw-r--r--libavformat/mpc.c19
-rw-r--r--libavformat/mpc8.c38
-rw-r--r--libavformat/mpeg.c596
-rw-r--r--libavformat/mpeg.h11
-rw-r--r--libavformat/mpegenc.c75
-rw-r--r--libavformat/mpegts.c913
-rw-r--r--libavformat/mpegts.h25
-rw-r--r--libavformat/mpegtsenc.c451
-rw-r--r--libavformat/mpegvideodec.c55
-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.c546
-rw-r--r--libavformat/mvdec.c34
-rw-r--r--libavformat/mvi.c12
-rw-r--r--libavformat/mxf.c13
-rw-r--r--libavformat/mxf.h21
-rw-r--r--libavformat/mxfdec.c708
-rw-r--r--libavformat/mxfenc.c612
-rw-r--r--libavformat/mxg.c24
-rw-r--r--libavformat/ncdec.c10
-rw-r--r--libavformat/network.c56
-rw-r--r--libavformat/network.h31
-rw-r--r--libavformat/nistspheredec.c131
-rw-r--r--libavformat/noproxy-test.c8
-rw-r--r--libavformat/nsvdec.c65
-rw-r--r--libavformat/nullenc.c10
-rw-r--r--libavformat/nut.c193
-rw-r--r--libavformat/nut.h16
-rw-r--r--libavformat/nutdec.c270
-rw-r--r--libavformat/nutenc.c484
-rw-r--r--libavformat/nuv.c101
-rw-r--r--libavformat/oggdec.c397
-rw-r--r--libavformat/oggdec.h9
-rw-r--r--libavformat/oggenc.c67
-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.c137
-rw-r--r--libavformat/oma.c8
-rw-r--r--libavformat/oma.h8
-rw-r--r--libavformat/omadec.c28
-rw-r--r--libavformat/omaenc.c13
-rw-r--r--libavformat/options.c22
-rw-r--r--libavformat/options_table.h43
-rw-r--r--libavformat/os_support.c9
-rw-r--r--libavformat/os_support.h32
-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.c16
-rw-r--r--libavformat/qtpalette.h8
-rw-r--r--libavformat/r3d.c19
-rw-r--r--libavformat/rawdec.c174
-rw-r--r--libavformat/rawdec.h17
-rw-r--r--libavformat/rawenc.c85
-rw-r--r--libavformat/rawenc.h8
-rw-r--r--libavformat/rawvideodec.c40
-rw-r--r--libavformat/rdt.c36
-rw-r--r--libavformat/rdt.h8
-rw-r--r--libavformat/realtextdec.c156
-rw-r--r--libavformat/redspark.c170
-rw-r--r--libavformat/replaygain.c11
-rw-r--r--libavformat/replaygain.h8
-rw-r--r--libavformat/riff.c50
-rw-r--r--libavformat/riff.h37
-rw-r--r--libavformat/riffdec.c65
-rw-r--r--libavformat/riffenc.c97
-rw-r--r--libavformat/rl2.c27
-rw-r--r--libavformat/rm.c8
-rw-r--r--libavformat/rm.h10
-rw-r--r--libavformat/rmdec.c227
-rw-r--r--libavformat/rmenc.c17
-rw-r--r--libavformat/rmsipr.c8
-rw-r--r--libavformat/rmsipr.h8
-rw-r--r--libavformat/rpl.c33
-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.c85
-rw-r--r--libavformat/rtp.c11
-rw-r--r--libavformat/rtp.h8
-rw-r--r--libavformat/rtpdec.c18
-rw-r--r--libavformat/rtpdec.h12
-rw-r--r--libavformat/rtpdec_amr.c8
-rw-r--r--libavformat/rtpdec_asf.c23
-rw-r--r--libavformat/rtpdec_formats.h13
-rw-r--r--libavformat/rtpdec_g726.c8
-rw-r--r--libavformat/rtpdec_h261.c203
-rw-r--r--libavformat/rtpdec_h263.c8
-rw-r--r--libavformat/rtpdec_h263_rfc2190.c8
-rw-r--r--libavformat/rtpdec_h264.c10
-rw-r--r--libavformat/rtpdec_hevc.c22
-rw-r--r--libavformat/rtpdec_ilbc.c8
-rw-r--r--libavformat/rtpdec_jpeg.c31
-rw-r--r--libavformat/rtpdec_latm.c13
-rw-r--r--libavformat/rtpdec_mpeg12.c8
-rw-r--r--libavformat/rtpdec_mpeg4.c14
-rw-r--r--libavformat/rtpdec_mpegts.c20
-rw-r--r--libavformat/rtpdec_qcelp.c8
-rw-r--r--libavformat/rtpdec_qdm2.c16
-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_xiph.c22
-rw-r--r--libavformat/rtpenc.c29
-rw-r--r--libavformat/rtpenc.h13
-rw-r--r--libavformat/rtpenc_aac.c8
-rw-r--r--libavformat/rtpenc_amr.c8
-rw-r--r--libavformat/rtpenc_chain.c12
-rw-r--r--libavformat/rtpenc_chain.h8
-rw-r--r--libavformat/rtpenc_h261.c57
-rw-r--r--libavformat/rtpenc_h263.c12
-rw-r--r--libavformat/rtpenc_h263_rfc2190.c23
-rw-r--r--libavformat/rtpenc_h264.c8
-rw-r--r--libavformat/rtpenc_hevc.c8
-rw-r--r--libavformat/rtpenc_jpeg.c8
-rw-r--r--libavformat/rtpenc_latm.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.c52
-rw-r--r--libavformat/rtpproto.h8
-rw-r--r--libavformat/rtsp.c87
-rw-r--r--libavformat/rtsp.h21
-rw-r--r--libavformat/rtspcodes.h125
-rw-r--r--libavformat/rtspdec.c43
-rw-r--r--libavformat/rtspenc.c17
-rw-r--r--libavformat/samidec.c140
-rw-r--r--libavformat/sapdec.c13
-rw-r--r--libavformat/sapenc.c15
-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.c39
-rw-r--r--libavformat/sdr2.c121
-rw-r--r--libavformat/seek-test.c43
-rw-r--r--libavformat/seek.c12
-rw-r--r--libavformat/seek.h8
-rw-r--r--libavformat/segafilm.c87
-rw-r--r--libavformat/segment.c832
-rw-r--r--libavformat/sierravmd.c91
-rw-r--r--libavformat/siff.c62
-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.c24
-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.c344
-rw-r--r--libavformat/swfenc.c26
-rw-r--r--libavformat/takdec.c50
-rw-r--r--libavformat/tcp.c42
-rw-r--r--libavformat/tedcaptionsdec.c366
-rw-r--r--libavformat/tee.c497
-rw-r--r--libavformat/thp.c51
-rw-r--r--libavformat/tiertexseq.c10
-rw-r--r--libavformat/tls.c60
-rw-r--r--libavformat/tmv.c10
-rw-r--r--libavformat/tta.c91
-rw-r--r--libavformat/tty.c43
-rw-r--r--libavformat/txd.c33
-rw-r--r--libavformat/udp.c373
-rw-r--r--libavformat/uncodedframecrcenc.c172
-rw-r--r--libavformat/unix.c11
-rw-r--r--libavformat/url-test.c8
-rw-r--r--libavformat/url.c8
-rw-r--r--libavformat/url.h18
-rw-r--r--libavformat/urldecode.c8
-rw-r--r--libavformat/urldecode.h8
-rw-r--r--libavformat/utils.c2227
-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.h8
-rw-r--r--libavformat/vocdec.c12
-rw-r--r--libavformat/vocenc.c22
-rw-r--r--libavformat/vorbiscomment.c9
-rw-r--r--libavformat/vorbiscomment.h8
-rw-r--r--libavformat/vplayerdec.c128
-rw-r--r--libavformat/vqf.c29
-rw-r--r--libavformat/w64.c50
-rw-r--r--libavformat/w64.h31
-rw-r--r--libavformat/wavdec.c363
-rw-r--r--libavformat/wavenc.c467
-rw-r--r--libavformat/wc3movie.c21
-rw-r--r--libavformat/webmdashenc.c386
-rw-r--r--libavformat/webpenc.c169
-rw-r--r--libavformat/webvttdec.c223
-rw-r--r--libavformat/webvttenc.c100
-rw-r--r--libavformat/westwood_aud.c12
-rw-r--r--libavformat/westwood_vqa.c53
-rw-r--r--libavformat/wtv.h60
-rw-r--r--libavformat/wtv_common.c84
-rw-r--r--libavformat/wtvdec.c (renamed from libavformat/wtv.c)326
-rw-r--r--libavformat/wtvenc.c845
-rw-r--r--libavformat/wv.c8
-rw-r--r--libavformat/wv.h8
-rw-r--r--libavformat/wvdec.c22
-rw-r--r--libavformat/wvenc.c12
-rw-r--r--libavformat/xa.c11
-rw-r--r--libavformat/xmv.c194
-rw-r--r--libavformat/xwma.c33
-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/audio_convert_init.c8
-rw-r--r--libavresample/arm/audio_convert_neon.S8
-rw-r--r--libavresample/arm/neontest.c8
-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/Makefile58
-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.c12
-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.c8
-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.c14
-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.h8
-rw-r--r--libavutil/attributes.h44
-rw-r--r--libavutil/audio_fifo.c10
-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.c186
-rw-r--r--libavutil/avstring.h148
-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.h216
-rw-r--r--libavutil/bswap.h10
-rw-r--r--libavutil/buffer.c41
-rw-r--r--libavutil/buffer.h19
-rw-r--r--libavutil/buffer_internal.h10
-rw-r--r--libavutil/cast5.c541
-rw-r--r--libavutil/cast5.h67
-rw-r--r--libavutil/channel_layout.c198
-rw-r--r--libavutil/channel_layout.h58
-rw-r--r--libavutil/colorspace.h8
-rw-r--r--libavutil/common.h79
-rw-r--r--libavutil/cpu.c162
-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.c55
-rw-r--r--libavutil/dict.h58
-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.c106
-rw-r--r--libavutil/error.h80
-rw-r--r--libavutil/eval.c239
-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.h20
-rw-r--r--libavutil/file_open.c52
-rw-r--r--libavutil/fixed_dsp.c98
-rw-r--r--libavutil/fixed_dsp.h144
-rw-r--r--libavutil/float_dsp.c50
-rw-r--r--libavutil/float_dsp.h11
-rw-r--r--libavutil/frame.c190
-rw-r--r--libavutil/frame.h178
-rw-r--r--libavutil/hash.c239
-rw-r--r--libavutil/hash.h112
-rw-r--r--libavutil/hmac.c128
-rw-r--r--libavutil/hmac.h12
-rw-r--r--libavutil/imgutils.c143
-rw-r--r--libavutil/imgutils.h70
-rw-r--r--libavutil/integer.c196
-rw-r--r--libavutil/integer.h86
-rw-r--r--libavutil/internal.h55
-rw-r--r--libavutil/intfloat.h8
-rw-r--r--libavutil/intmath.c8
-rw-r--r--libavutil/intmath.h48
-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.c321
-rw-r--r--libavutil/log.h90
-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.c175
-rw-r--r--libavutil/mem.h126
-rw-r--r--libavutil/mips/Makefile1
-rw-r--r--libavutil/mips/float_dsp_mips.c383
-rw-r--r--libavutil/mips/intreadwrite.h8
-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.c815
-rw-r--r--libavutil/opencl.h298
-rw-r--r--libavutil/opencl_internal.c59
-rw-r--r--libavutil/opencl_internal.h33
-rw-r--r--libavutil/opt.c1271
-rw-r--r--libavutil/opt.h334
-rw-r--r--libavutil/parseutils.c292
-rw-r--r--libavutil/parseutils.h77
-rw-r--r--libavutil/pca.c248
-rw-r--r--libavutil/pca.h35
-rw-r--r--libavutil/pixdesc.c848
-rw-r--r--libavutil/pixdesc.h90
-rw-r--r--libavutil/pixelutils.c219
-rw-r--r--libavutil/pixelutils.h52
-rw-r--r--libavutil/pixfmt.h161
-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.h8
-rw-r--r--libavutil/ppc/timer.h15
-rw-r--r--libavutil/ppc/types_altivec.h8
-rw-r--r--libavutil/ppc/util_altivec.h43
-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.c73
-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.c515
-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.c129
-rw-r--r--libavutil/sha.h12
-rw-r--r--libavutil/sha512.c345
-rw-r--r--libavutil/sha512.h75
-rw-r--r--libavutil/softfloat.c71
-rw-r--r--libavutil/softfloat.h132
-rw-r--r--libavutil/stereo3d.c8
-rw-r--r--libavutil/stereo3d.h8
-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.h16
-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/utf8.c73
-rw-r--r--libavutil/utils.c72
-rw-r--r--libavutil/version.h33
-rw-r--r--libavutil/x86/Makefile4
-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/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.c58
-rw-r--r--libavutil/x86/timer.h9
-rw-r--r--libavutil/x86/w64xmmtest.h8
-rw-r--r--libavutil/x86/x86inc.asm23
-rw-r--r--libavutil/x86/x86util.asm104
-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.c1067
-rw-r--r--libpostproc/postprocess.h107
-rw-r--r--libpostproc/postprocess_altivec_template.c1210
-rw-r--r--libpostproc/postprocess_internal.h178
-rw-r--r--libpostproc/postprocess_template.c3727
-rw-r--r--libpostproc/postprocres.rc55
-rw-r--r--libpostproc/version.h45
-rw-r--r--library.mak21
-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.c509
-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.c100
-rw-r--r--libswresample/swresample-test.c416
-rw-r--r--libswresample/swresample.c853
-rw-r--r--libswresample/swresample.h534
-rw-r--r--libswresample/swresample_frame.c158
-rw-r--r--libswresample/swresample_internal.h203
-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.asm482
-rw-r--r--libswresample/x86/audio_convert_init.c146
-rw-r--r--libswresample/x86/rematrix.asm250
-rw-r--r--libswresample/x86/rematrix_init.c83
-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.c666
-rw-r--r--libswscale/log2_tab.c1
-rw-r--r--libswscale/options.c31
-rw-r--r--libswscale/output.c1027
-rw-r--r--libswscale/ppc/swscale_altivec.c244
-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.c664
-rw-r--r--libswscale/swscale.h22
-rw-r--r--libswscale/swscale_internal.h270
-rw-r--r--libswscale/swscale_unscaled.c1355
-rw-r--r--libswscale/swscaleres.rc55
-rw-r--r--libswscale/utils.c1011
-rw-r--r--libswscale/version.h12
-rw-r--r--libswscale/x86/Makefile4
-rw-r--r--libswscale/x86/hscale_fast_bilinear_simd.c374
-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.c215
-rw-r--r--libswscale/x86/scale.asm14
-rw-r--r--libswscale/x86/swscale.c146
-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.c125
-rw-r--r--presets/libvpx-1080p.ffpreset (renamed from presets/libvpx-720p.avpreset)4
-rw-r--r--presets/libvpx-1080p50_60.ffpreset (renamed from presets/libvpx-1080p50_60.avpreset)4
-rw-r--r--presets/libvpx-360p.ffpreset (renamed from presets/libvpx-360p.avpreset)4
-rw-r--r--presets/libvpx-720p.ffpreset (renamed from presets/libvpx-1080p.avpreset)4
-rw-r--r--presets/libvpx-720p50_60.ffpreset (renamed from presets/libvpx-720p50_60.avpreset)4
-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/Makefile82
-rw-r--r--tests/audiogen.c8
-rw-r--r--tests/base64.c8
-rwxr-xr-xtests/copycooker.sh30
-rwxr-xr-xtests/fate-run.sh94
-rw-r--r--tests/fate-valgrind.supp31
-rwxr-xr-xtests/fate.sh18
-rw-r--r--tests/fate/aac.mak23
-rw-r--r--tests/fate/ac3.mak11
-rw-r--r--tests/fate/acodec.mak80
-rw-r--r--tests/fate/adpcm.mak15
-rw-r--r--tests/fate/audio.mak41
-rw-r--r--tests/fate/avformat.mak26
-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.mak283
-rw-r--r--tests/fate/flac.mak4
-rw-r--r--tests/fate/gif.mak27
-rw-r--r--tests/fate/h264.mak366
-rw-r--r--tests/fate/hevc.mak99
-rw-r--r--tests/fate/image.mak52
-rw-r--r--tests/fate/libavresample.mak14
-rw-r--r--tests/fate/libavutil.mak38
-rw-r--r--tests/fate/libswresample.mak401
-rw-r--r--tests/fate/lossless-audio.mak27
-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.mak2
-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.mak37
-rw-r--r--tests/fate/real.mak9
-rw-r--r--tests/fate/screen.mak17
-rw-r--r--tests/fate/seek.mak40
-rw-r--r--tests/fate/subtitles.mak69
-rw-r--r--tests/fate/utvideo.mak2
-rw-r--r--tests/fate/vcodec.mak128
-rw-r--r--tests/fate/video.mak179
-rw-r--r--tests/fate/voice.mak24
-rw-r--r--tests/fate/vpx.mak25
-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.sh144
-rw-r--r--tests/lena.pnm109
-rw-r--r--tests/md5.sh2
-rw-r--r--tests/ref/acodec/adpcm-adx2
-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/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/fate/4xm-130
-rw-r--r--tests/ref/fate/4xm-2320
-rw-r--r--tests/ref/fate/8bps24
-rw-r--r--tests/ref/fate/aasc1
-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/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/bethsoft-vid140
-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/cllc-argb1
-rw-r--r--tests/ref/fate/cllc-rgb1
-rw-r--r--tests/ref/fate/cllc-yuy2-noblock1
-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-partial157
-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/dirac3
-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_default663
-rw-r--r--tests/ref/fate/ffprobe_flat599
-rw-r--r--tests/ref/fate/ffprobe_ini678
-rw-r--r--tests/ref/fate/ffprobe_json641
-rw-r--r--tests/ref/fate/ffprobe_xml57
-rw-r--r--tests/ref/fate/fic-avi1
-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-framepack-frameseq26
-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-idet1
-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-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-gbrap1
-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-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-copy209
-rw-r--r--tests/ref/fate/filter-pixfmts-crop156
-rw-r--r--tests/ref/fate/filter-pixfmts-field119
-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-hflip156
-rw-r--r--tests/ref/fate/filter-pixfmts-histeq6
-rw-r--r--tests/ref/fate/filter-pixfmts-il118
-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-null209
-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-scale209
-rw-r--r--tests/ref/fate/filter-pixfmts-super2xsai14
-rw-r--r--tests/ref/fate/filter-pixfmts-swapuv62
-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-vflip209
-rw-r--r--tests/ref/fate/filter-pp1
-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-scale2002
-rw-r--r--tests/ref/fate/filter-scale5002
-rw-r--r--tests/ref/fate/filter-select1
-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-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/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-restore3
-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/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/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-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/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/opt90
-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-microdvd23
-rw-r--r--tests/ref/fate/sub-microdvd-remuxbin0 -> 436 bytes
-rw-r--r--tests/ref/fate/sub-movtext15
-rw-r--r--tests/ref/fate/sub-movtextenc1
-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/sub2video96
-rw-r--r--tests/ref/fate/svq1300
-rw-r--r--tests/ref/fate/svq3360
-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/truemotion1-241
-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/v2102
-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/vp51
-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-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/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-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/fate/zmbv-8bit1
-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/mxf12
-rw-r--r--tests/ref/lavf/mxf_d104
-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-mp28
-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/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-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-voc24
-rw-r--r--tests/ref/seek/lavf-wav30
-rw-r--r--tests/ref/seek/lavf-wtv48
-rw-r--r--tests/ref/seek/vsynth2-asv140
-rw-r--r--tests/ref/seek/vsynth2-asv240
-rw-r--r--tests/ref/seek/vsynth2-dnxhd-1080i24
-rw-r--r--tests/ref/seek/vsynth2-dnxhd-720p24
-rw-r--r--tests/ref/seek/vsynth2-dnxhd-720p-rd24
-rw-r--r--tests/ref/seek/vsynth2-dv54
-rw-r--r--tests/ref/seek/vsynth2-dv-41154
-rw-r--r--tests/ref/seek/vsynth2-dv-5054
-rw-r--r--tests/ref/seek/vsynth2-ffv140
-rw-r--r--tests/ref/seek/vsynth2-flashsv40
-rw-r--r--tests/ref/seek/vsynth2-flv40
-rw-r--r--tests/ref/seek/vsynth2-h26128
-rw-r--r--tests/ref/seek/vsynth2-h2638
-rw-r--r--tests/ref/seek/vsynth2-h263p28
-rw-r--r--tests/ref/seek/vsynth2-huffyuv40
-rw-r--r--tests/ref/seek/vsynth2-ljpeg40
-rw-r--r--tests/ref/seek/vsynth2-mjpeg30
-rw-r--r--tests/ref/seek/vsynth2-mpeg146
-rw-r--r--tests/ref/seek/vsynth2-mpeg1b36
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-42264
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-idct-int64
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-ilace64
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-ivlc-qprd64
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-thread64
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-thread-ivlc64
-rw-r--r--tests/ref/seek/vsynth2-mpeg432
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-adap16
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-error40
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-nr28
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-nsse46
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-qpel40
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-qprd16
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-rc28
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-thread24
-rw-r--r--tests/ref/seek/vsynth2-msmpeg48
-rw-r--r--tests/ref/seek/vsynth2-msmpeg4v28
-rw-r--r--tests/ref/seek/vsynth2-roqvideo2
-rw-r--r--tests/ref/seek/vsynth2-rv1017
-rw-r--r--tests/ref/seek/vsynth2-rv2014
-rw-r--r--tests/ref/seek/vsynth2-snow46
-rw-r--r--tests/ref/seek/vsynth2-snow-ll46
-rw-r--r--tests/ref/seek/vsynth2-svq124
-rw-r--r--tests/ref/seek/vsynth2-wmv18
-rw-r--r--tests/ref/seek/vsynth2-wmv216
-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-cljr6
-rw-r--r--tests/ref/vsynth/vsynth1-dnxhd-1080i6
-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-h2634
-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-jpegls6
-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-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-adv4
-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-msmpeg46
-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-rgb6
-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-v2102
-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-y41p4
-rw-r--r--tests/ref/vsynth/vsynth1-yuv2
-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-cljr6
-rw-r--r--tests/ref/vsynth/vsynth2-dnxhd-1080i6
-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-rd4
-rw-r--r--tests/ref/vsynth/vsynth2-dnxhd_1080i4
-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-504
-rw-r--r--tests/ref/vsynth/vsynth2-dv_4114
-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-flv8
-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-h263p6
-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-jpegls6
-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-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-adap6
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg4-adv2
-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-qprd6
-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-msmpeg48
-rw-r--r--tests/ref/vsynth/vsynth2-msmpeg4v28
-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-rgb6
-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-v2102
-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-y41p4
-rw-r--r--tests/ref/vsynth/vsynth2-yuv2
-rw-r--r--tests/ref/vsynth/vsynth2-yuv44
-rw-r--r--tests/ref/vsynth/vsynth2-zlib4
-rw-r--r--tests/ref/vsynth/vsynth2-zmbv4
-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-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-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-yuv4
-rw-r--r--tests/ref/vsynth/vsynth3-yuv44
-rw-r--r--tests/ref/vsynth/vsynth3-zlib4
-rw-r--r--tests/ref/vsynth1/cljr4
-rw-r--r--tests/ref/vsynth1/yuv4
-rw-r--r--tests/ref/vsynth2/cljr4
-rw-r--r--tests/ref/vsynth2/huffyuv4
-rw-r--r--tests/ref/vsynth2/yuv4
-rwxr-xr-xtests/regression-funcs.sh26
-rw-r--r--tests/rotozoom.c8
-rw-r--r--tests/test.ffmeta9
-rw-r--r--tests/tiny_psnr.c168
-rw-r--r--tests/tiny_ssim.c246
-rw-r--r--tests/utils.c16
-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/crypto_bench.c407
-rw-r--r--tools/cws2fws.c14
-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.c33
-rw-r--r--tools/ismindex.c14
-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.c72
-rw-r--r--tools/qt-faststart.c18
-rw-r--r--tools/seek_print.c105
-rw-r--r--tools/trasher.c13
-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
4117 files changed, 363218 insertions, 78698 deletions
diff --git a/.gitignore b/.gitignore
index 19bb757..793d33a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,44 +19,71 @@
*.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_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
/tools/probetest
/tools/qt-faststart
/tools/trasher
+/tools/seek_print
+/tools/uncoded_frame
+/tools/zmqsend
diff --git a/CREDITS b/CREDITS
index 4a53778..e29f0b8 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 c51fa8f..c25fafd 100644
--- a/Changelog
+++ b/Changelog
@@ -2,153 +2,314 @@ 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
+- 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
-
-version 11:
-- libx265 encoder
+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
+- support for H.261 RTP payload format (RFC 4587)
+- 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
@@ -161,44 +322,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
@@ -268,23 +531,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
@@ -294,44 +574,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
@@ -339,6 +602,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
@@ -350,6 +614,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
@@ -396,7 +661,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
@@ -409,11 +674,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:
@@ -654,6 +954,7 @@ version 0.5:
- Gopher client support
- MXF D-10 muxer
- generic metadata API
+- flash ScreenVideo2 encoder
version 0.4.9-pre1:
@@ -856,7 +1157,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 ac5dc5d..0000000
--- 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 0000000..5db9122
--- /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.md
index 701e6e1..dd39b90 100644
--- a/LICENSE
+++ b/LICENSE.md
@@ -1,27 +1,56 @@
-Libav:
-======
+#FFmpeg:
-Most files in Libav are under the GNU Lesser General Public License version 2.1
+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
-Libav.
+FFmpeg.
-Some optional parts of Libav are licensed under the GNU General Public License
+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, Libav's license changes to GPL v2+.
+configure to activate them. In this case, FFmpeg's license changes to GPL v2+.
-Specifically, the GPL parts of Libav are
+Specifically, the GPL parts of FFmpeg are:
+- libpostproc
+- libmpcodecs
+- 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_cropdetect.c
+ - vf_decimate.c
- vf_delogo.c
+ - vf_geq.c
+ - vf_histeq.c
- vf_hqdn3d.c
- vf_interlace.c
+ - vf_kerndeint.c
+ - vf_mcdeint.c
+ - vf_mp.c
+ - vf_owdenoise.c
+ - vf_perspective.c
+ - vf_phase.c
+ - vf_pp.c
+ - vf_pullup.c
+ - vf_sab.c
+ - vf_smartblur.c
+ - vf_spp.c
+ - vf_stereo3d.c
+ - vf_super2xsai.c
+ - vf_tinterlace.c
+ - vf_xbr.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
@@ -41,26 +70,37 @@ There are a handful of files under other licensing terms, namely:
external libraries
==================
-Libav can be combined with a number of external libraries, which sometimes
+FFmpeg 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
+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 Libav, the
+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 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.
+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 0000000..ef120e4
--- /dev/null
+++ b/MAINTAINERS
@@ -0,0 +1,582 @@
+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
+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
+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
+ 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
+ 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
+ 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
+ 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
+ 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_h261.*, rtpenc_h261.* Thomas Volkert
+ rtpdec_hevc.*, rtpenc_hevc.* Thomas Volkert
+ rtpdec_asf.* Ronald S. Bultje
+ 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.4 Michael Niedermayer
+2.2 Michael Niedermayer
+1.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 cc016b3..1e1dbb3 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 MIPS32R2-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 : 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 42061c0..0000000
--- a/README
+++ /dev/null
@@ -1 +0,0 @@
-README.md \ No newline at end of file
diff --git a/README.md b/README.md
index 2dc668a..04089e4 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,15 +11,15 @@ 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 analisys tool to inspect
multimedia content.
* Additional small tools such as `aviocat`, `ismindex` and `qt-faststart`.
@@ -27,14 +27,14 @@ such as audio, video, subtitles and related metadata.
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 27383c3..5360d2e 100644
--- a/RELEASE
+++ b/RELEASE
@@ -1 +1 @@
-11_beta2
+2.4.git
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
new file mode 100644
index 0000000..5499cfd
--- /dev/null
+++ b/RELEASE_NOTES
@@ -0,0 +1,81 @@
+ ┌────────────────────────────────────────â”
+ │ RELEASE NOTES for FFmpeg 2.4 "Fresnel" │
+ └────────────────────────────────────────┘
+
+ The FFmpeg Project proudly presents FFmpeg 2.4 "Fresnel", just 2 months
+ after the release of 2.3. Since this wasn't a long time ago, the Changelog
+ is a bit short this time.
+
+ The most important thing in this release is the major version bump of the
+ libraries. This means that this release is neither ABI-compatible nor
+ fully API-compatible. But on the other hand it is aligned with the Libav
+ 11 release series, and will as a result probably end up being maintained for
+ a long time.
+
+ As usual, if you have any question on this release or any FFmpeg related
+ topic, feel free to join us on the #ffmpeg IRC channel (on
+ irc.freenode.net).
+
+ ┌────────────────────────────â”
+ │ đŸ”¨ API Information │
+ └────────────────────────────┘
+
+ FFmpeg 2.4 includes the following library versions:
+
+ • libavutil 54.7.100
+ • libavcodec 56.1.100
+ • libavformat 56.4.101
+ • libavdevice 56.0.100
+ • libavfilter 5.1.100
+ • libswscale 3.0.100
+ • libswresample 1.1.100
+ • libpostproc 53.0.100
+
+ Important API changes since 2.3:
+
+ • The new field mime_type was added to AVProbeData, which can
+ cause crashes, if it is not initialized.
+ • Some deprecated functions were removed.
+ • The avfilter_graph_parse function was made compatible with Libav.
+ • The Matroska demuxer now outputs verbatim ASS packets.
+
+ Please refer to the doc/APIchanges file for more information.
+
+ ┌────────────────────────────â”
+ │ ★ List of New Features │
+ └────────────────────────────┘
+
+ ┌────────────────────────────â”
+ │ libavformat │
+ └────────────────────────────┘
+
+ • Icecast protocol.
+ • API for live metadata updates through event flags.
+ • UTF-16 support in text subtitles formats.
+ • The ASS muxer now reorders the Dialogue events properly.
+
+ ┌────────────────────────────â”
+ │ libavfilter │
+ └────────────────────────────┘
+
+ • Ported lenscorrection filter from frei0r filter.
+ • Large optimizations in dctdnoiz to make it usable.
+ • Added codecview filter to visualize information exported by some codecs.
+ • Added silenceremove filter.
+
+ ┌────────────────────────────â”
+ │ libavutil │
+ └────────────────────────────┘
+
+ • Added clip() function in eval.
+
+ ┌────────────────────────────â”
+ │ â  Behaviour changes │
+ └────────────────────────────┘
+
+ • dctdnoiz filter now uses a block size of 8x8 instead of 16x16 by default
+ • -vismv option is deprecated in favor of the codecview filter
+ • libmodplug is now detected through pkg-config
+ • HTML documentation generation through texi2html is deprecated in
+ favor of makeinfo/texi2any
+ • ICY metadata are now requested by default with the HTTP protocol
diff --git a/arch.mak b/arch.mak
index 4bfc883..0e866d8 100644
--- a/arch.mak
+++ b/arch.mak
@@ -4,6 +4,11 @@ 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_MIPS32R2) += $(MIPS32R2-OBJS) $(MIPS32R2-OBJS-yes)
+OBJS-$(HAVE_MIPSDSPR1) += $(MIPSDSPR1-OBJS) $(MIPSDSPR1-OBJS-yes)
+OBJS-$(HAVE_MIPSDSPR2) += $(MIPSDSPR2-OBJS) $(MIPSDSPR2-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 8e76863..0000000
--- a/avconv.c
+++ /dev/null
@@ -1,2679 +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->enc_ctx;
- 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)))
- av_log(NULL, AV_LOG_ERROR, "Error while filtering.\n");
-
- 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);
- exit_program(1);
- }
- 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->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");
- } else {
- ret = av_opt_set_dict(ost->enc_ctx, &ost->encoder_opts);
- if (ret < 0)
- return ret;
- }
-
- 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;
- }
-
- /* 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 = "?";
-
- if (in_codec) {
- decoder_name = in_codec->name;
- in_codec_name = avcodec_descriptor_get(in_codec->id)->name;
- if (!strcmp(decoder_name, in_codec_name))
- decoder_name = "native";
- }
-
- if (out_codec) {
- encoder_name = out_codec->name;
- out_codec_name = avcodec_descriptor_get(out_codec->id)->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;
-
- 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;
-
- av_log(NULL, AV_LOG_ERROR, "Error while filtering.\n");
- 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/avplay.c b/avplay.c
deleted file mode 100644
index 9148c04..0000000
--- a/avplay.c
+++ /dev/null
@@ -1,3014 +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/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
-
-/* 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;
-
- /* 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_dlog(NULL, "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, *filt_format;
- 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;
-
- if ((ret = avfilter_graph_create_filter(&filt_format,
- avfilter_get_by_name("format"),
- "format", "yuv420p", NULL, graph)) < 0)
- return ret;
- if ((ret = avfilter_link(filt_format, 0, filt_out, 0)) < 0)
- return ret;
-
-
- 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 = filt_format;
- 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, filt_format, 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 ((ret = configure_video_filters(graph, is, vfilters)) < 0)
- goto the_end;
- filt_in = is->in_video_filter;
- filt_out = is->out_video_filter;
-#endif
-
- 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_dlog(NULL, "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_dlog(NULL, "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_dlog(NULL, "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();
- 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", ""},
- { 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 5fc9ad5..0000000
--- a/avprobe.c
+++ /dev/null
@@ -1,975 +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/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 {
- const char *name;
- PrintElementType type;
- int64_t index;
- int64_t nb_elems;
-} PrintElement;
-
-typedef struct {
- PrintElement *prefix;
- int level;
- void (*print_header)(void);
- void (*print_footer)(void);
-
- void (*print_array_header) (const char *name);
- void (*print_array_footer) (const char *name);
- 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)
-{
- if (octx.prefix[octx.level -1].nb_elems)
- 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)
-{
- ini_escape_print(key);
- avio_printf(probe_out, "=%"PRId64"\n", 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)
-{
- 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)
-{
- 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 (octx.prefix[octx.level -1].nb_elems)
- avio_printf(probe_out, ",\n");
- AVP_INDENT();
- avio_printf(probe_out, "\"%s\" : %"PRId64"", key, 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);
- 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);
- 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)
-{
- if (octx.print_array_header)
- octx.print_array_header(name);
-
- probe_group_enter(name, ARRAY);
-}
-
-static void probe_array_footer(const char *name)
-{
- probe_group_leave();
- if (octx.print_array_footer)
- octx.print_array_footer(name);
-}
-
-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");
- while (!av_read_frame(fmt_ctx, &pkt))
- show_packet(fmt_ctx, &pkt);
- probe_array_footer("packets");
-}
-
-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("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");
-
- 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");
- for (i = 0; i < fmt_ctx->nb_streams; i++)
- show_stream(fmt_ctx, i);
- probe_array_footer("streams");
- }
-
- 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_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_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 eff011c..b777396 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,13 +30,17 @@
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/mathematics.h"
#include "libavutil/imgutils.h"
#include "libavutil/parseutils.h"
@@ -45,8 +49,8 @@
#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 +59,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 = 2014;
+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 +83,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 +95,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 +166,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 +191,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);
@@ -287,7 +316,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;
}
}
@@ -420,59 +450,141 @@ 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);
+}
+
void parse_loglevel(int argc, char **argv, const OptionDef *options)
{
int idx = locate_option(argc, argv, options, "loglevel");
+ const char *env;
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;
}
@@ -517,6 +629,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;
@@ -527,6 +640,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));
@@ -556,7 +670,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);
@@ -584,6 +698,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);
}
@@ -600,6 +715,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);
@@ -614,8 +730,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;
@@ -698,12 +818,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;
}
@@ -721,8 +842,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);
@@ -742,6 +877,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
@@ -770,6 +1023,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) { \
@@ -777,7 +1031,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, \
@@ -786,7 +1040,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", \
@@ -808,37 +1062,88 @@ 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 on %s %s with %s\n",
+ indent, __DATE__, __TIME__, 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"
@@ -851,8 +1156,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"
@@ -866,8 +1172,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"
@@ -880,8 +1187,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"
@@ -895,23 +1203,35 @@ 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 avclass->category == AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT ||
+ avclass->category == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT ||
+ avclass->category == AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT ||
+ avclass->category == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT ||
+ avclass->category == AV_CLASS_CATEGORY_DEVICE_OUTPUT ||
+ avclass->category == AV_CLASS_CATEGORY_DEVICE_INPUT;
+}
+
+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;
@@ -920,6 +1240,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;
@@ -928,6 +1251,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;
@@ -950,9 +1276,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) { \
@@ -970,7 +1306,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)) {
@@ -1014,7 +1351,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 '?';
}
}
@@ -1030,6 +1369,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;
@@ -1044,7 +1413,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"
@@ -1056,9 +1426,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" : ".");
@@ -1087,30 +1462,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))
@@ -1119,6 +1501,7 @@ static void print_codecs(int encoder)
printf("\n");
}
}
+ av_free(codecs);
}
int show_decoders(void *optctx, const char *opt, const char *arg)
@@ -1163,16 +1546,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 = Commmand 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;
@@ -1206,6 +1635,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;
@@ -1239,13 +1697,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);
}
}
@@ -1304,6 +1762,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;
@@ -1315,7 +1774,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");
@@ -1323,24 +1784,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
@@ -1390,16 +1861,23 @@ int read_yesno(void)
int cmdutils_read_file(const char *filename, char **bufptr, size_t *size)
{
int ret;
- FILE *f = fopen(filename, "rb");
+ 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;
}
fseek(f, 0, SEEK_END);
*size = ftell(f);
fseek(f, 0, SEEK_SET);
+ if (*size == (size_t)-1) {
+ ret = AVERROR(errno);
+ av_log(NULL, AV_LOG_ERROR, "IO error: %s\n", strerror(errno));
+ fclose(f);
+ return ret;
+ }
*bufptr = av_malloc(*size + 1);
if (!*bufptr) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate file buffer\n");
@@ -1410,9 +1888,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 {
@@ -1424,58 +1902,47 @@ int cmdutils_read_file(const char *filename, char **bufptr, size_t *size)
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");
}
@@ -1487,85 +1954,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) /* 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,
@@ -1609,7 +2001,8 @@ AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
}
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);
@@ -1632,7 +2025,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");
@@ -1663,14 +2056,183 @@ void *grow_array(void *array, int elem_size, int *size, int new_size)
return array;
}
-const char *media_type_string(enum AVMediaType media_type)
+#if CONFIG_AVDEVICE
+static int print_device_sources(AVInputFormat *fmt, AVDictionary *opts)
{
- 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";
+ int ret, i;
+ AVFormatContext *dev = NULL;
+ AVDeviceInfoList *device_list = NULL;
+ AVDictionary *tmp_opts = 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;
}
+
+ /* TODO: avformat_open_input calls read_header callback which is not necessary.
+ Function like avformat_alloc_output_context2 for input could be helpful here. */
+ av_dict_copy(&tmp_opts, opts, 0);
+ if ((ret = avformat_open_input(&dev, NULL, fmt, &tmp_opts)) < 0) {
+ printf("Cannot open device: %s.\n", fmt->name);
+ goto fail;
+ }
+
+ if ((ret = avdevice_list_devices(dev, &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:
+ av_dict_free(&tmp_opts);
+ avdevice_free_list_devices(&device_list);
+ avformat_close_input(&dev);
+ return ret;
}
+
+static int print_device_sinks(AVOutputFormat *fmt, AVDictionary *opts)
+{
+ int ret, i;
+ AVFormatContext *dev = NULL;
+ AVDeviceInfoList *device_list = NULL;
+ AVDictionary *tmp_opts = 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 = avformat_alloc_output_context2(&dev, fmt, NULL, NULL)) < 0) {
+ printf("Cannot open device: %s.\n", fmt->name);
+ goto fail;
+ }
+ av_dict_copy(&tmp_opts, opts, 0);
+ av_opt_set_dict2(dev, &tmp_opts, AV_OPT_SEARCH_CHILDREN);
+
+ if ((ret = avdevice_list_devices(dev, &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:
+ av_dict_free(&tmp_opts);
+ avdevice_free_list_devices(&device_list);
+ avformat_free_context(dev);
+ 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 && strcmp(fmt->name, dev))
+ continue;
+ print_device_sources(fmt, opts);
+ }
+ } while (fmt);
+ do {
+ fmt = av_input_video_device_next(fmt);
+ if (fmt) {
+ if (dev && strcmp(fmt->name, dev))
+ 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 && strcmp(fmt->name, dev))
+ continue;
+ print_device_sinks(fmt, opts);
+ }
+ } while (fmt);
+ do {
+ fmt = av_output_video_device_next(fmt);
+ if (fmt) {
+ if (dev && strcmp(fmt->name, dev))
+ 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 d90ad45..f6ad44c 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,4 @@ 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 */
+#endif /* CMDUTILS_H */
diff --git a/cmdutils_common_opts.h b/cmdutils_common_opts.h
index 8693f59..758dac1 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 0000000..3dfd156
--- /dev/null
+++ b/cmdutils_opencl.c
@@ -0,0 +1,274 @@
+/*
+ * 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 "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;
+ strcpy(devices[count].device_name, device_node->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 9244fd3..a493792 100644
--- a/common.mak
+++ b/common.mak
@@ -5,9 +5,94 @@
# first so "all" becomes default target
all: all-yes
+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 +100,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,12 +132,13 @@ $(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
DISTCLEANSUFFIXES = *.pc
LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a
@@ -64,4 +151,4 @@ 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))
diff --git a/compat/aix/math.h b/compat/aix/math.h
index 380f878..65a89c4 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 0000000..2d3002a
--- /dev/null
+++ b/compat/avisynth/avisynth_c.h
@@ -0,0 +1,880 @@
+// 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__
+
+#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
+
+typedef unsigned char BYTE;
+#ifdef __GNUC__
+typedef long long int INT64;
+#else
+typedef __int64 INT64;
+#endif
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// Constants
+//
+
+#ifndef __AVISYNTH_H__
+enum { AVISYNTH_INTERFACE_VERSION = 4 };
+#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 = 1 << 3,
+ AVS_CS_SHIFT_SAMPLE_BITS = 1 << 4,
+
+ 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 {
+ 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_yv24(const AVS_VideoInfo * p)
+ { return (p->pixel_type & AVS_CS_PLANAR_MASK) == (AVS_CS_YV24 & AVS_CS_PLANAR_FILTER); }
+
+AVSC_INLINE int avs_is_yv16(const AVS_VideoInfo * p)
+ { return (p->pixel_type & AVS_CS_PLANAR_MASK) == (AVS_CS_YV16 & AVS_CS_PLANAR_FILTER); }
+
+AVSC_INLINE int avs_is_yv12(const AVS_VideoInfo * p)
+ { return (p->pixel_type & AVS_CS_PLANAR_MASK) == (AVS_CS_YV12 & AVS_CS_PLANAR_FILTER); }
+
+AVSC_INLINE int avs_is_yv411(const AVS_VideoInfo * p)
+ { return (p->pixel_type & AVS_CS_PLANAR_MASK) == (AVS_CS_YV411 & AVS_CS_PLANAR_FILTER); }
+
+AVSC_INLINE int avs_is_y8(const AVS_VideoInfo * p)
+ { return (p->pixel_type & AVS_CS_PLANAR_MASK) == (AVS_CS_Y8 & AVS_CS_PLANAR_FILTER); }
+
+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_color_space(const AVS_VideoInfo * p, int c_space)
+ { return avs_is_planar(p) ? ((p->pixel_type & AVS_CS_PLANAR_MASK) == (c_space & AVS_CS_PLANAR_FILTER)) : ((p->pixel_type & c_space) == 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_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 {
+ 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_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_sizeUV;
+ else return 0;
+ case AVS_PLANAR_U_ALIGNED: case AVS_PLANAR_V_ALIGNED:
+ if (p->pitchUV) {
+ r = (p->row_sizeUV+AVS_FRAME_ALIGN-1)&(~(AVS_FRAME_ALIGN-1)); // Aligned rowsize
+ if (r < p->pitchUV)
+ return r;
+ return p->row_sizeUV;
+ } 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->heightUV;
+ return 0;
+ }
+ return p->height;}
+
+AVSC_INLINE const BYTE* avs_get_read_ptr(const AVS_VideoFrame * p) {
+ return p->vfb->data + p->offset;}
+
+AVSC_INLINE const BYTE* 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 BYTE* 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 BYTE* 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;
+ }
+ }
+}
+
+
+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_SSE4_2 = 0x800, // Nehalem
+};
+
+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, 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,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
+
+
+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_error);
+ 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);
+};
+
+#undef AVSC_DECLARE_FUNC
+
+
+AVSC_INLINE AVS_Library * avs_load_library() {
+ AVS_Library *library = (AVS_Library *)malloc(sizeof(AVS_Library));
+ if (!library)
+ 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_error);
+ 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);
+
+#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)
+ return;
+ FreeLibrary(library->handle);
+ free(library);
+}
+#endif
+
+#endif
diff --git a/compat/avisynth/avisynth_c_25.h b/compat/avisynth/avisynth_c_25.h
new file mode 100644
index 0000000..9288761
--- /dev/null
+++ b/compat/avisynth/avisynth_c_25.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2011 FFmpegSource Project
+//
+// 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.
+
+/* these are defines/functions that are used and were changed in the switch to 2.6
+ * and are needed to maintain full compatility with 2.5 */
+
+enum {
+ AVS_CS_YV12_25 = 1<<3 | AVS_CS_YUV | AVS_CS_PLANAR, // y-v-u, planar
+ AVS_CS_I420_25 = 1<<4 | AVS_CS_YUV | AVS_CS_PLANAR, // y-u-v, planar
+};
+
+AVSC_INLINE int avs_get_height_p_25(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 int avs_get_row_size_p_25(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_is_yv12_25(const AVS_VideoInfo * p)
+ { return ((p->pixel_type & AVS_CS_YV12_25) == AVS_CS_YV12_25)||((p->pixel_type & AVS_CS_I420_25) == AVS_CS_I420_25); }
diff --git a/compat/avisynth/avxsynth_c.h b/compat/avisynth/avxsynth_c.h
new file mode 100644
index 0000000..b20f460
--- /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; 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
+//
+#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 0000000..ff367d5
--- /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 0000000..5476afe
--- /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 c69f728..1f0d3ab 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 9150bc8..7ea374a 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 b7adf60..41a641f 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 0af7b54..c64653f 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 0000000..f02113c
--- /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 0000000..441ac43
--- /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 97d7067..d46f96d 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 258909f..3a9452e 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 b686d4d..6234cc5 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 0000000..3cb5ebe
--- /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 3748289..87e816f 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 766f9c2..8ad4777 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]
--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-postproc disable libpostproc build
+ --disable-avfilter disable libavfilter build
+ --enable-avresample enable libavresample build [no]
--disable-pthreads disable pthreads [auto]
--disable-w32threads disable Win32 threads [auto]
+ --disable-os2threads disable OS/2 threads [auto]
--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,12 +146,13 @@ 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-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
@@ -177,53 +193,88 @@ Individual component options:
External library support:
--enable-avisynth enable reading of AviSynth script files [no]
- --enable-bzlib enable bzlib [autodetect]
+ --disable-bzlib disable bzlib [autodetect]
+ --enable-fontconfig enable fontconfig
--enable-frei0r enable frei0r video filtering
--enable-gnutls enable gnutls [no]
+ --disable-iconv disable iconv [autodetect]
+ --enable-ladspa enable LADSPA audio filtering
+ --enable-libaacplus enable AAC+ encoding via libaacplus [no]
+ --enable-libass enable libass subtitles rendering [no]
+ --enable-libbluray enable BluRay reading using libbluray [no]
--enable-libbs2b enable bs2b DSP library [no]
+ --enable-libcaca enable textual display using libcaca
+ --enable-libcelt enable CELT decoding via libcelt [no]
--enable-libcdio enable audio CD grabbing with libcdio
--enable-libdc1394 enable IIDC-1394 grabbing using libdc1394
and libraw1394 [no]
--enable-libfaac enable AAC encoding via libfaac [no]
--enable-libfdk-aac enable AAC de/encoding via libfdk-aac [no]
+ --enable-libflite enable flite (voice synthesis) support via libflite [no]
--enable-libfreetype enable libfreetype [no]
+ --enable-libfribidi enable libfribidi [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-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]
--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 enable X11 grabbing using XCB [auto]
--enable-libxcb-shm enable X11 grabbing shm communication [auto]
--enable-libxcb-xfixes enable X11 grabbing mouse rendering [auto]
--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-openal enable OpenAL 1.1 capture support [no]
+ --enable-opencl enable OpenCL code
+ --enable-opengl enable OpenGL rendering [no]
--enable-openssl enable openssl [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
@@ -231,15 +282,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
@@ -248,6 +305,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]
@@ -266,7 +324,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
@@ -293,14 +351,27 @@ 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
+ --disable-mips32r2 disable MIPS32R2 optimizations
+ --disable-mipsdspr1 disable MIPS DSP ASE R1 optimizations
+ --disable-mipsdspr2 disable MIPS DSP ASE R2 optimizations
+ --disable-mipsfpu disable floating point MIPS optimizations
+ --disable-fast-unaligned consider unaligned accesses slow
-Developer options (useful when working on Libav itself):
+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;
@@ -347,7 +418,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
@@ -357,7 +428,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
@@ -383,7 +454,7 @@ sh_quote(){
}
cleanws(){
- echo "$@" | sed 's/^ *//;s/ */ /g;s/ *$//'
+ echo "$@" | sed 's/^ *//;s/ */ /g;s/ *$//;s/\\r//g'
}
filter(){
@@ -635,6 +706,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;
}
}
}"
@@ -677,6 +754,10 @@ add_cflags(){
append CFLAGS $($cflags_filter "$@")
}
+add_cxxflags(){
+ append CXXFLAGS $($cflags_filter "$@")
+}
+
add_asflags(){
append ASFLAGS $($asflags_filter "$@")
}
@@ -690,7 +771,7 @@ add_ldexeflags(){
}
add_stripflags(){
- append STRIPFLAGS "$@"
+ append ASMSTRIPFLAGS "$@"
}
add_extralibs(){
@@ -720,6 +801,11 @@ check_cmd(){
"$@" >> $logfile 2>&1
}
+check_stat(){
+ log check_stat "$@"
+ stat "$1" >> $logfile 2>&1
+}
+
cc_o(){
eval printf '%s\\n' $CC_O
}
@@ -735,6 +821,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
@@ -775,7 +875,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(){
@@ -784,9 +884,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
@@ -833,9 +935,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
}
@@ -851,7 +961,7 @@ test_stripflags(){
check_cc <<EOF
int main(void) { return 0; }
EOF
- check_cmd $strip $STRIPFLAGS "$@" $TMPO
+ check_cmd $strip $ASMSTRIPFLAGS "$@" $TMPO
}
check_stripflags(){
@@ -870,12 +980,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
@@ -888,10 +1010,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
}
@@ -908,7 +1030,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(){
@@ -940,13 +1081,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 "$@" &&
@@ -955,7 +1105,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(){
@@ -1015,7 +1165,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(){
@@ -1044,6 +1194,14 @@ require2(){
check_lib2 "$headers" $func "$@" || die "ERROR: $name not found"
}
+require_cpp(){
+ name="$1"
+ headers="$2"
+ classes="$3"
+ shift 3
+ check_lib_cpp "$headers" "$classes" "$@" || die "ERROR: $name not found"
+}
+
require_pkg_config(){
pkg="$1"
check_pkg_config "$@" || die "ERROR: $pkg not found"
@@ -1051,6 +1209,26 @@ require_pkg_config(){
add_extralibs $(get_safe ${pkg}_libs)
}
+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)
+}
+
hostcc_e(){
eval printf '%s\\n' $HOSTCC_E
}
@@ -1131,39 +1309,72 @@ COMPONENT_LIST="
"
EXAMPLE_LIST="
- avcodec_example
+ avio_reading_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
+ 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
libfaac
libfdk_aac
+ libflite
libfontconfig
libfreetype
+ libfribidi
+ libgme
libgsm
+ libiec61883
libilbc
+ libmodplug
libmp3lame
+ libnut
libopencore_amrnb
libopencore_amrwb
libopencv
libopenjpeg
libopus
libpulse
+ libquvi
librtmp
libschroedinger
+ libshine
+ libsmbclient
+ libsoxr
libspeex
+ libssh
+ libstagefright_h264
libtheora
libtwolame
+ libutvideo
+ libv4l2
+ libvidstab
libvo_aacenc
libvo_amrwbenc
libvorbis
@@ -1177,19 +1388,35 @@ EXTERNAL_LIBRARY_LIST="
libxcb_shm
libxcb_xfixes
libxvid
+ libzmq
+ libzvbi
+ lzma
+ 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
"
@@ -1199,6 +1426,7 @@ HWACCEL_LIST="
vaapi
vda
vdpau
+ xvmc
"
LIBRARY_LIST="
@@ -1208,6 +1436,8 @@ LIBRARY_LIST="
avformat
avresample
avutil
+ postproc
+ swresample
swscale
"
@@ -1218,26 +1448,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
@@ -1246,17 +1480,21 @@ 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
xmm_clobber_test
"
THREADS_LIST="
pthreads
+ os2threads
w32threads
"
@@ -1301,6 +1539,14 @@ ARCH_EXT_LIST_ARM="
neon
vfp
vfpv3
+ setend
+"
+
+ARCH_EXT_LIST_MIPS="
+ mipsfpu
+ mips32r2
+ mipsdspr1
+ mipsdspr2
"
ARCH_EXT_LIST_X86_SIMD="
@@ -1326,6 +1572,7 @@ ARCH_EXT_LIST_PPC="
dcbzl
ldbrx
ppc4xx
+ vsx
"
ARCH_EXT_LIST_X86="
@@ -1338,8 +1585,8 @@ ARCH_EXT_LIST="
$ARCH_EXT_LIST_ARM
$ARCH_EXT_LIST_PPC
$ARCH_EXT_LIST_X86
+ $ARCH_EXT_LIST_MIPS
loongson
- vis
"
ARCH_FEATURES="
@@ -1349,15 +1596,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="
@@ -1369,14 +1619,17 @@ 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
+ CL_cl_h
dev_bktr_ioctl_bt848_h
dev_bktr_ioctl_meteor_h
dev_ic_bt8xx_h
@@ -1385,12 +1638,15 @@ HEADERS_LIST="
direct_h
dlfcn_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
@@ -1402,6 +1658,8 @@ HEADERS_LIST="
sys_time_h
sys_un_h
sys_videoio_h
+ termios_h
+ udplite_h
unistd_h
windows_h
winsock2_h
@@ -1414,6 +1672,7 @@ INTRINSICS_LIST="
MATH_FUNCS="
atanf
atan2f
+ cbrt
cbrtf
cosf
exp2
@@ -1439,6 +1698,7 @@ MATH_FUNCS="
"
SYSTEM_FUNCS="
+ access
aligned_malloc
clock_gettime
closesocket
@@ -1459,11 +1719,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
@@ -1471,18 +1735,20 @@ SYSTEM_FUNCS="
mmap
mprotect
nanosleep
+ PeekNamedPipe
posix_memalign
+ pthread_cancel
sched_getaffinity
SetConsoleTextAttribute
setmode
setrlimit
Sleep
strerror_r
- strptime
sysconf
sysctl
usleep
VirtualAlloc
+ wglGetProcAddress
"
TOOLCHAIN_FEATURES="
@@ -1494,9 +1760,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
@@ -1513,9 +1783,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
"
@@ -1537,11 +1809,17 @@ HAVE_LIST="
$TYPES_LIST
atomics_native
dos_paths
+ dxva2api_cobj
dxva2_lib
libc_msvcrt
libdc1394_1
libdc1394_2
+ makeinfo
+ makeinfo_html
+ perl
+ pod2man
sdl
+ texi2html
threads
vdpau_x11
xlib
@@ -1557,9 +1835,11 @@ CONFIG_EXTRA="
bswapdsp
cabac
dvprofile
+ exif
faandct
faanidct
fdctdsp
+ frame_thread_encoder
gcrypt
golomb
gplv3
@@ -1576,6 +1856,8 @@ CONFIG_EXTRA="
iirfilter
intrax8
lgplv3
+ llauddsp
+ llviddsp
lpc
me_cmp
mpeg_er
@@ -1612,6 +1894,7 @@ CMDLINE_SELECT="
lto
optimizations
rpath
+ stripping
"
PATHS_LIST="
@@ -1630,18 +1913,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
@@ -1649,19 +1937,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
"
@@ -1677,11 +1973,18 @@ 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"
+mips32r2_deps="mips"
+mipsdspr1_deps="mips"
+mipsdspr2_deps="mips"
+
altivec_deps="ppc"
ppc4xx_deps="ppc"
+vsx_deps="ppc"
cpunop_deps="i686"
x86_64_select="i686"
@@ -1722,12 +2025,11 @@ fast_unaligned_if_any="aarch64 ppc x86"
simd_align_16_if_any="altivec neon sse"
# system capabilities
-log2_deps="!libc_msvcrt"
symver_if_any="symver_asm_label symver_gnu_asm"
# 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"
@@ -1739,6 +2041,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"
@@ -1746,7 +2049,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"
# decoders / encoders
@@ -1754,6 +2057,7 @@ aac_decoder_select="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 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"
@@ -1761,8 +2065,9 @@ 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 mpegvideoenc"
+ape_decoder_select="bswapdsp llauddsp"
asv1_decoder_select="blockdsp bswapdsp idctdsp"
asv1_encoder_select="bswapdsp fdctdsp pixblockdsp"
asv2_decoder_select="blockdsp bswapdsp idctdsp"
@@ -1770,6 +2075,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"
bink_decoder_select="blockdsp hpeldsp"
binkaudio_dct_decoder_select="mdct rdft dct sinewin wma_freqs"
binkaudio_rdft_decoder_select="mdct rdft sinewin wma_freqs"
@@ -1780,17 +2086,18 @@ cook_decoder_select="audiodsp mdct sinewin"
cscd_decoder_select="lzo"
cscd_decoder_suggest="zlib"
dca_decoder_select="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"
@@ -1798,15 +2105,16 @@ 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"
+g2m_decoder_select="blockdsp idctdsp 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"
@@ -1816,8 +2124,8 @@ h263p_encoder_select="h263_encoder"
h264_decoder_select="cabac golomb h264chroma h264dsp h264pred h264qpel startcode videodsp"
h264_decoder_suggest="error_resilience"
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"
@@ -1831,7 +2139,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"
+mjpeg_decoder_select="blockdsp hpeldsp exif idctdsp"
mjpeg_encoder_select="aandcttables mpegvideoenc"
mjpegb_decoder_select="mjpeg_decoder"
mlp_decoder_select="mlp_parser"
@@ -1850,10 +2158,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"
@@ -1867,16 +2176,18 @@ 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"
-png_decoder_deps="zlib"
-png_encoder_deps="zlib"
-png_encoder_select="huffyuvencdsp"
-prores_decoder_select="idctdsp"
+opus_decoder_deps="swresample"
+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"
@@ -1885,6 +2196,11 @@ 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"
@@ -1893,12 +2209,12 @@ svq3_decoder_suggest="zlib"
tak_decoder_select="audiodsp"
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"
@@ -1914,8 +2230,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"
@@ -1928,73 +2245,105 @@ 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"
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_dxva2_hwaccel_deps="dxva2"
h264_dxva2_hwaccel_select="h264_decoder"
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"
+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_dxva2_hwaccel_deps="dxva2"
mpeg2_dxva2_hwaccel_select="mpeg2video_decoder"
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_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_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_parser_select="mpegvideo startcode vc1_decoder"
# external libraries
+libaacplus_encoder_deps="libaacplus"
+libcelt_decoder_deps="libcelt"
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"
@@ -2006,16 +2355,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"
@@ -2025,21 +2379,27 @@ libvpx_vp9_encoder_deps="libvpx"
libwavpack_encoder_deps="libwavpack"
libwebp_encoder_deps="libwebp"
libx264_encoder_deps="libx264"
+libx264rgb_encoder_deps="libx264"
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"
# 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"
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"
@@ -2048,8 +2408,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"
@@ -2057,7 +2421,7 @@ matroska_muxer_select="riffenc"
mmf_muxer_select="riffenc"
mov_demuxer_select="riffdec"
mov_demuxer_suggest="zlib"
-mov_muxer_select="riffenc rtpenc_chain"
+mov_muxer_select="riffenc rtpenc_chain ac3_parser"
mp3_demuxer_select="mpegaudio_parser"
mp4_muxer_select="mov_muxer"
mpegts_muxer_select="adts_muxer latm_muxer"
@@ -2082,41 +2446,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 -framework CoreGraphics"
+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"
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"
@@ -2127,6 +2522,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"
@@ -2145,32 +2542,92 @@ 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"
cropdetect_filter_deps="gpl"
delogo_filter_deps="gpl"
+deshake_filter_select="pixelutils"
drawtext_filter_deps="libfreetype"
+ebur128_filter_deps="gpl"
+flite_filter_deps="libflite"
frei0r_filter_deps="frei0r dlopen"
frei0r_filter_extralibs='$ldl'
frei0r_src_filter_deps="frei0r dlopen"
frei0r_src_filter_extralibs='$ldl'
+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"
+ladspa_filter_extralibs='$ldl'
+mcdeint_filter_deps="avcodec gpl"
+movie_filter_deps="avcodec avformat"
+mp_filter_deps="gpl avcodec swscale inline_asm"
+mpdecimate_filter_deps="gpl"
+mpdecimate_filter_select="pixelutils"
+mptestsrc_filter_deps="gpl"
+negate_filter_deps="lut_filter"
+perspective_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"
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"
+xbr_filter_deps="gpl"
+zmq_filter_deps="libzmq"
+zoompan_filter_deps="swscale"
# examples
+avio_reading="avformat avcodec 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"
-transcode_aac_example_deps="avcodec avformat avresample"
+muxing_example_deps="avcodec avformat avutil swscale"
+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"
@@ -2178,21 +2635,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"
-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
@@ -2201,8 +2666,8 @@ 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'
@@ -2211,39 +2676,57 @@ 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"
+ranlib_default="ranlib"
+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
-# By default, enable only those hwaccels that have no external dependencies.
-enable dxva2 vdpau
+sws_max_filter_size_default=256
+set_default sws_max_filter_size
+
+# Enable hwaccels by default.
+enable dxva2 vaapi vda vdpau xvmc
+enable xlib
# build settings
SHFLAGS='-shared -Wl,-soname,$$(@F)'
@@ -2269,6 +2752,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'
@@ -2303,7 +2788,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(){
@@ -2426,11 +2911,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')
@@ -2451,6 +2934,8 @@ for opt do
;;
--help|-h) show_help
;;
+ --fatal-warnings) enable fatal_warnings
+ ;;
*)
optname="${opt%%=*}"
optname="${optname#--}"
@@ -2468,7 +2953,7 @@ done
disabled logging && logfile=/dev/null
-echo "# $0 $LIBAV_CONFIGURATION" > $logfile
+echo "# $0 $FFMPEG_CONFIGURATION" > $logfile
set >> $logfile
test -n "$cross_prefix" && enable cross_compile
@@ -2480,13 +2965,17 @@ 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"
+test -n "$valgrind" && toolchain="valgrind-memcheck"
+
case "$toolchain" in
clang-asan)
cc_default="clang"
@@ -2500,7 +2989,7 @@ case "$toolchain" in
;;
clang-usan)
cc_default="clang"
- add_cflags -fsanitize=undefined -O1
+ add_cflags -fsanitize=undefined
add_ldflags -fsanitize=undefined
;;
gcc-asan)
@@ -2519,17 +3008,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).
@@ -2571,7 +3060,8 @@ case "$toolchain" in
;;
esac
-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
@@ -2580,6 +3070,11 @@ if ! $pkg_config --version >/dev/null 2>&1; then
pkg_config=false
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() {
case $1 in
mingw32*|win32|win64|cygwin*|*-dos|freedos|opendos|os/2*|symbian) echo .exe ;;
@@ -2594,7 +3089,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(){
@@ -2614,8 +3113,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
@@ -2712,6 +3213,7 @@ msvc_flags(){
-Wall) echo -W4 -wd4244 -wd4127 -wd4018 -wd4389 \
-wd4146 -wd4057 -wd4204 -wd4706 -wd4305 \
-wd4152 -wd4324 -we4013 -wd4100 -wd4214 \
+ -wd4554 \
-wd4273 -wd4701 ;;
esac
done
@@ -2725,6 +3227,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
}
@@ -2757,9 +3269,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 ;;
@@ -2815,7 +3334,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"
@@ -2841,6 +3362,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)
@@ -2914,7 +3436,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
@@ -2944,6 +3466,7 @@ probe_cc(){
if [ $pfx = hostcc ]; then
append _cflags -Dsnprintf=_snprintf
fi
+ disable stripping
elif $_cc 2>&1 | grep -q Intel; then
_type=icl
_ident=$($cc 2>&1 | head -n1)
@@ -2964,9 +3487,9 @@ probe_cc(){
_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
+ # -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'
+ _cflags='-D_USE_MATH_DEFINES -FIstdlib.h -Dstrtoll=_strtoi64 -Qms0 -Qvec- -Qsimd- -GS -fp:precise'
if [ $pfx = hostcc ]; then
append _cflags -Dsnprintf=_snprintf
fi
@@ -3018,7 +3541,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
@@ -3060,6 +3583,7 @@ else
fi
add_cflags $extra_cflags
+add_cxxflags $extra_cxxflags
add_asflags $extra_cflags
if test -n "$sysroot"; then
@@ -3067,6 +3591,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"
@@ -3102,7 +3629,7 @@ case "$arch" in
aarch64|arm64)
arch="aarch64"
;;
- arm*)
+ arm*|iPad*|iPhone*)
arch="arm"
;;
mips*|IP*)
@@ -3126,7 +3653,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
@@ -3204,7 +3731,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
@@ -3236,9 +3766,32 @@ elif enabled mips; then
cpuflags="-march=$cpu"
+ case $cpu in
+ 24kc)
+ disable mipsfpu
+ disable mipsdspr1
+ disable mipsdspr2
+ ;;
+ 24kf*)
+ disable mipsdspr1
+ disable mipsdspr2
+ ;;
+ 24kec|34kc|1004kc)
+ disable mipsfpu
+ disable mipsdspr2
+ ;;
+ 24kef*|34kf*|1004kf*)
+ disable mipsdspr2
+ ;;
+ 74kc)
+ disable mipsfpu
+ ;;
+ esac
+
elif enabled ppc; then
disable ldbrx
+ disable vsx
case $(tolower $cpu) in
601|ppc601|powerpc601)
@@ -3266,7 +3819,7 @@ elif enabled ppc; then
g5|970|ppc970|powerpc970)
cpuflags="-mcpu=970"
;;
- power[3-7]*)
+ power[3-8]*)
cpuflags="-mcpu=$cpu"
;;
cell)
@@ -3314,7 +3867,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
@@ -3348,6 +3902,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>
@@ -3395,10 +3950,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
@@ -3441,6 +4004,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
@@ -3457,11 +4021,13 @@ 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)'
@@ -3483,21 +4049,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
;;
@@ -3510,6 +4085,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"
@@ -3538,6 +4114,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"
@@ -3553,6 +4130,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
@@ -3573,6 +4151,7 @@ case $target_os in
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
@@ -3609,6 +4188,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)
@@ -3637,6 +4217,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__
@@ -3666,10 +4250,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
@@ -3710,7 +4300,7 @@ 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
@@ -3732,19 +4322,30 @@ 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
+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
@@ -3802,6 +4403,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" ] ;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
@@ -3822,7 +4429,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
@@ -3833,8 +4440,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}
@@ -3850,6 +4458,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
@@ -3864,7 +4474,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
@@ -3872,7 +4485,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
@@ -3886,6 +4499,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' \
@@ -3903,18 +4517,26 @@ EOF
elif enabled mips; then
check_inline_asm loongson '"dmult.g $1, $2, $3"'
+ enabled mips32r2 && add_cflags "-mips32r2" && add_asflags "-mips32r2" &&
+ check_inline_asm mips32r2 '"rotr $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"'
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"'
@@ -3941,12 +4563,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
@@ -3965,6 +4590,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"'
@@ -3976,7 +4604,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"
@@ -3988,8 +4621,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
@@ -4005,6 +4638,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=
@@ -4053,17 +4687,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
@@ -4078,16 +4713,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 strptime
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
@@ -4095,18 +4732,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 cl/cl.h
check_header direct.h
check_header dlfcn.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
@@ -4114,12 +4758,14 @@ 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 vdpau/vdpau.h
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
@@ -4134,28 +4780,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
@@ -4166,57 +4822,115 @@ for func in $MATH_FUNCS; do
done
# these are off by default, so fail if requested and not available
-enabled avisynth && { { check_header "avisynth/avisynth_c.h" && check_lib2 "windows.h" LoadLibrary; } ||
- { check_header "avxsynth/avxsynth_c.h" && check_lib2 "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 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 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 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 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 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 libopencv && require_pkg_config opencv opencv/cxcore.h cvCreateImageHeader
+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 && { { check_pkg_config smbclient libsmbclient.h smbc_init &&
+ require_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 && require_pkg_config "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion
+enabled libx264 && { { check_pkg_config x264 "stdint.h x264.h" x264_encoder_encode &&
+ require_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 >= 17" ||
die "ERROR: libx265 version must be >= 17."; }
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 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; } ||
@@ -4231,27 +4945,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; } ||
@@ -4262,41 +5002,52 @@ 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
if enabled libcdio; then
check_lib2 "cdio/cdda.h cdio/paranoia.h" cdio_cddap_open -lcdio_paranoia -lcdio_cdda -lcdio ||
- check_lib2 "cdio/paranoia/cdda.h cdio/paranoia/paranoia.h" cdio_cddap_open -lcdio_paranoia -lcdio_cdda -lcdio
+ check_lib2 "cdio/paranoia/cdda.h cdio/paranoia/paranoia.h" cdio_cddap_open -lcdio_paranoia -lcdio_cdda -lcdio ||
+ die "ERROR: libcdio-paranoia not 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
+if ! disabled libxcb; then
check_pkg_config xcb xcb/xcb.h xcb_connect || {
enabled libxcb && die "ERROR: libxcb 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"
+ add_cflags $xcb_cflags $xcb_shm_cflags $xcb_xfixes_cflags
+ add_extralibs $xcb_libs $xcb_shm_libs $xcb_xfixes_libs
+fi
fi
if enabled x11grab; then
@@ -4305,15 +5056,34 @@ 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 vaapi &&
+ check_lib va/va.h vaInitialize -lva ||
+ disable vaapi
+
enabled vdpau &&
check_cpp_condition vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP" ||
disable 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
@@ -4322,12 +5092,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(){
@@ -4342,13 +5113,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 \
@@ -4358,6 +5129,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
@@ -4367,8 +5139,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
@@ -4406,28 +5180,39 @@ 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
+ check_cflags -wd144,167,188,556,1292,1419,10006,10148,10156
# 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 &&
@@ -4442,11 +5227,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 -Wformat
enabled extra_warnings || check_disable_warning -Wno-maybe-uninitialized
elif enabled llvm_gcc; then
check_cflags -mllvm -stack-alignment=16
@@ -4484,10 +5270,14 @@ 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 onwards actually has log2.
+ check_cpp_condition crtversion.h "_VC_CRT_MAJOR_VERSION >= 12" || disable log2
fi
case $as_type in
@@ -4511,6 +5301,8 @@ case $target_os in
;;
esac
+enable frame_thread_encoder
+
enabled asm || { arch=c; disable $ARCH_LIST $ARCH_EXT_LIST; }
check_deps $CONFIG_LIST \
@@ -4518,12 +5310,47 @@ check_deps $CONFIG_LIST \
$HAVE_LIST \
$ALL_COMPONENTS \
-enabled_all dxva2 CoTaskMemFree &&
- prepend avconv_libs $($ldflags_filter "-lole32") &&
+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 dxva2 dxva2api_cobj CoTaskMemFree &&
+ prepend ffmpeg_libs $($ldflags_filter "-lole32") &&
enable dxva2_lib
! enabled_any memalign posix_memalign aligned_malloc &&
- enabled $simd_align_16 && enable memalign_hack
+ 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
@@ -4538,11 +5365,28 @@ 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 ebur128_filter && enabled swresample && prepend avfilter_deps "swresample"
+enabled elbg_filter && prepend avfilter_deps "avcodec"
+enabled mcdeint_filter && prepend avfilter_deps "avcodec"
enabled movie_filter && prepend avfilter_deps "avformat avcodec"
+enabled mp_filter && prepend avfilter_deps "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 opus_decoder && prepend avcodec_deps "avresample"
+enabled lavfi_indev && prepend avdevice_deps "avfilter"
+
+enabled opus_decoder && prepend avcodec_deps "swresample"
expand_deps(){
lib_deps=${1}_deps
@@ -4551,6 +5395,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"
@@ -4565,6 +5412,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
@@ -4597,22 +5447,38 @@ 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 "MIPS32R2 enabled ${mips32r2-no}"
+ echo "MIPS DSP R1 enabled ${mipsdspr1-no}"
+ echo "MIPS DSP R2 enabled ${mipsdspr2-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
@@ -4641,15 +5507,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
@@ -4659,10 +5529,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
@@ -4676,25 +5550,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
@@ -4704,6 +5586,7 @@ SLIBSUF=$SLIBSUF
EXESUF=$EXESUF
EXTRA_VERSION=$extra_version
CCDEP=$CCDEP
+CXXDEP=$CXXDEP
CCDEP_FLAGS=$CCDEP_FLAGS
ASDEP=$ASDEP
ASDEP_FLAGS=$ASDEP_FLAGS
@@ -4727,13 +5610,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}
@@ -4744,7 +5627,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(){
@@ -4752,6 +5636,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
@@ -4771,18 +5656,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 2014
+#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
@@ -4793,13 +5686,18 @@ fi
enabled getenv || echo "#define getenv(x) NULL" >> $TMPH
+
+mkdir -p doc
+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
@@ -4819,12 +5717,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(){
@@ -4837,7 +5738,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
@@ -4849,30 +5750,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 44af215..7c5ab9b 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,21 +7,17 @@ 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:
-2014-11-xx - xxxxxxx - lavf 56.06.3 - avformat.h
- Add AVFormatContext.avoid_negative_ts.
-
2014-11-xx - xxxxxxx - lavc 56.6.0 - vorbis_parser.h
Add a public API for parsing vorbis packets.
-2014-10-xx - xxxxxxx - lavu 54.5.0 - time.h
- Add av_gettime_relative().
-
2014-10-xx - xxxxxxx - lavc 56.5.0 - avcodec.h
Replace AVCodecContext.time_base used for decoding
with AVCodecContext.framerate.
@@ -40,16 +36,49 @@ API changes, most recent first:
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-xx - xxxxxxx - lavc 56.1.0 - avcodec.h
+2014-10-02 - xxxxxxx - lavc 56.2.100 - avcodec.h
+2014-10-02 - xxxxxxx - 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.
+
+2014-10-02 - xxxxxxx - lavu 54.8.100 - avstring.h
+ Add av_match_list()
+
+2014-09-24 - xxxxxxx - libpostproc 53.1.100
+ Add visualization support
+
+2014-09-xx - xxxxxxx - 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-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-xx - xxxxxxx - lavf 56.03.0 - avformat.h
+2014-08-25 - 215db29 / b263f8f - lavf 56.3.100 / 56.3.0 - avformat.h
Add AVFormatContext.max_ts_probe.
-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.
@@ -57,334 +86,733 @@ 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 - xxxxxxx - 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 - xxxxxxx - 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-xx - xxxxxxx - 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 - lavu 52.84.100 - 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-xx - xxxxxxx - lavu 52.82.0 - fifo.h
+ Add av_fifo_freep() function.
+
+2014-05-02 - ba52fb11 - lavu 52.81.0 - 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-29 - 1bf6396 - lavc 55.60.100 - avcodec.h
+ Add AVCodecDescriptor.mime_types field.
+
+2014-04-29 - xxxxxxx - lavu 52.80.0 - 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-XX - xxxxxxx - lavf xx.xx.1xx - 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-xx - xxxxxxx - lavd 55.10.100 - avdevice.h
+ Add avdevice_list_devices() and avdevice_free_list_devices()
+
+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 - c98f316 - lavu 53.3.0 - frame.h
+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 - xxxxxxx - 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-11 - b9fb59d,9431356,d7b3ee9 - lavc 55.28.1 - avcodec.h
+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 - 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()
@@ -402,68 +830,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.
@@ -471,23 +894,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.
@@ -495,101 +921,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()
@@ -601,144 +1016,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:
@@ -746,220 +1182,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<-------------------------------------
- 0.7 branch was cut here
------------------------------>8--------------------------------------
+-------- 8< --------- FFmpeg 0.7 was cut here -------- 8< ---------
-2011-06-16 - 05e84c9, 25de595 - lavf 53.2.0 - avformat.h
+
+
+-------- 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.
+
+2011-06-12 - 6119b23 - lavfi 2.16.0 - avfilter_graph_parse()
+ Change avfilter_graph_parse() signature.
+
+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
@@ -980,9 +1567,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
@@ -1015,11 +1605,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.
@@ -1049,6 +1639,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.
@@ -1416,6 +2012,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().
@@ -1433,10 +2032,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 58f7dfb..8697e6c 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 1c205a5..2502922 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -1,39 +1,78 @@
-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_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_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_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)
@@ -43,55 +82,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=" " $< > $@
+doc/%.3: doc/%.pod $(GENTEXI)
+ $(M)pod2man --section=3 --center=" " --release=" " $< > $@
$(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 bda4789..0000000
--- 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 0000000..6c8c1d7
--- /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/avplay.texi b/doc/avplay.texi
deleted file mode 100644
index d526213..0000000
--- a/doc/avplay.texi
+++ /dev/null
@@ -1,184 +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.
-@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 7e6fedf..0000000
--- 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 8468eca..0000000
--- a/doc/avtools-common-opts.texi
+++ /dev/null
@@ -1,193 +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.
-
-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
-@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 0847683..0000000
--- 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 6e7f878..58ebddd 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,82 @@ 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.
@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 +96,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 +119,26 @@ 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 noise
-@section remove_extradata
+Damages the contents of packets without damaging the container. Can be
+used for fuzzing or testing error resilience/concealment.
+
+@example
+ffmpeg -i INPUT -c copy -bsf noise output.mkv
+@end example
+
+@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 0000000..6f68017
--- /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 c3dede7..2efde5c 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:
@@ -9,16 +9,25 @@ V
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 +36,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 0000000..35068c7
--- /dev/null
+++ b/doc/codecs.texi
@@ -0,0 +1,1141 @@
+@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 unsensical 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 reproducable 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
+@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 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 c3573a6..ae20cea 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
@@ -32,7 +62,7 @@ AC-3 audio decoder.
This decoder implements part of ATSC A/52:2010 and ETSI TS 102 366, as well as
the undocumented RealAudio 3 (a.k.a. dnet).
-@subsubsection AC-3 Decoder Options
+@subsection AC-3 Decoder Options
@table @option
@@ -53,4 +83,159 @@ Loud sounds are fully compressed. Soft sounds are enhanced.
@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 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 0000000..bf50200
--- /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 2f2f464..e582322 100644
--- a/doc/demuxers.texi
+++ b/doc/demuxers.texi
@@ -1,30 +1,243 @@
@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 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 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 a suffix which is used to automatically
+determine the format of the images contained in the files.
-The pattern may contain the string "%d" or "%0@var{N}d", which
+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 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 +245,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 +257,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.
-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:
+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
+
+@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 00e2b60..8b1f150 100644
--- a/doc/developer.texi
+++ b/doc/developer.texi
@@ -11,87 +11,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 +67,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 +112,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 +154,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 +178,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 +208,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
@@ -266,7 +228,7 @@ autocmd InsertEnter * match ForbiddenWhitespace /\t\|\s\+\%#\@@<!$/
For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}:
@example
-(c-add-style "libav"
+(c-add-style "ffmpeg"
'("k&r"
(c-basic-offset . 4)
(indent-tabs-mode . nil)
@@ -275,7 +237,7 @@ For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}:
(statement-cont . (c-lineup-assignments +)))
)
)
-(setq c-default-style "libav")
+(setq c-default-style "ffmpeg")
@end example
@section Development Policy
@@ -291,20 +253,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 +271,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 +285,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
+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
-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 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 +377,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 +438,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 +473,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 +501,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
+Was the patch generated with git format-patch or send-email?
+
+@item
+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 Libav git master branch?
+Is the patch against latest FFmpeg git master branch?
@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.)
+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 +562,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 +580,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 +591,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 +622,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 inlcuded 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 introductionary 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 +670,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 +699,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 +718,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 +726,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 +740,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 +752,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 +763,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 0000000..5e74a96
--- /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 d38dd0b..d88f60e 100755
--- a/doc/doxy-wrapper.sh
+++ b/doc/doxy-wrapper.sh
@@ -2,14 +2,12 @@
SRC_PATH="${1}"
DOXYFILE="${2}"
+DOXYGEN="${3}"
-shift 2
+shift 3
-doxygen - <<EOF
+$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
EOF
diff --git a/doc/doxy/doxy_stylesheet.css b/doc/doxy/doxy_stylesheet.css
deleted file mode 100644
index d6dadde..0000000
--- 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 101e6fe..0000000
--- 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 312990c..0000000
--- 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 94d8340..c0e9890 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,764 @@ Selected by Encoder (default)
@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.
-@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}.
+@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.
+
+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 +1260,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 +1510,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 +2077,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).
-
-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
+@section mpeg2
-@item smart
+MPEG-2 video encoder.
-@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.
-
-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
-@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
+@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
-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}
@@ -816,3 +2182,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 0000000..31cab26
--- /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 e1fd7ee..0000000
--- 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 0000000..07251fe
--- /dev/null
+++ b/doc/examples/Makefile
@@ -0,0 +1,43 @@
+# 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_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
+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 0000000..c1ce619
--- /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/avio_reading.c b/doc/examples/avio_reading.c
new file mode 100644
index 0000000..02474e9
--- /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/avcodec.c b/doc/examples/decoding_encoding.c
index 1478881..556fe98 100644
--- a/doc/examples/avcodec.c
+++ b/doc/examples/decoding_encoding.c
@@ -1,47 +1,44 @@
/*
- * copyright (c) 2001 Fabrice Bellard
+ * Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * 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:
*
- * 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.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
*
- * 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
+ * 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 avcodec.c
- * Note that this library only handles codecs (mpeg, mpeg4, etc...),
- * not file formats (avi, vob, etc...). See library 'libavformat' for the
+ * @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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#ifdef HAVE_AV_CONFIG_H
-#undef HAVE_AV_CONFIG_H
-#endif
+#include <math.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"
+#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
@@ -115,16 +112,20 @@ static void audio_encode_example(const char *filename)
uint16_t *samples;
float t, tincr;
- printf("Audio encoding\n");
+ 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");
+ 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;
@@ -132,7 +133,7 @@ static void audio_encode_example(const char *filename)
/* 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",
+ fprintf(stderr, "Encoder does not support sample format %s",
av_get_sample_fmt_name(c->sample_fmt));
exit(1);
}
@@ -144,20 +145,20 @@ static void audio_encode_example(const char *filename)
/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
+ fprintf(stderr, "Could not open codec\n");
exit(1);
}
f = fopen(filename, "wb");
if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
+ 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");
+ fprintf(stderr, "Could not allocate audio frame\n");
exit(1);
}
@@ -169,9 +170,13 @@ static void audio_encode_example(const char *filename)
* 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",
+ fprintf(stderr, "Could not allocate %d bytes for samples buffer\n",
buffer_size);
exit(1);
}
@@ -179,14 +184,14 @@ static void audio_encode_example(const char *filename)
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");
+ 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++) {
+ for (i = 0; i < 200; i++) {
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = 0;
@@ -201,9 +206,23 @@ static void audio_encode_example(const char *filename)
/* encode the samples */
ret = avcodec_encode_audio2(c, &pkt, frame, &got_output);
if (ret < 0) {
- fprintf(stderr, "error encoding audio frame\n");
+ 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);
@@ -232,26 +251,30 @@ static void audio_decode_example(const char *outfilename, const char *filename)
av_init_packet(&avpkt);
- printf("Audio decoding\n");
+ 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");
+ 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");
+ fprintf(stderr, "Could not open codec\n");
exit(1);
}
f = fopen(filename, "rb");
if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
+ fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
outfile = fopen(outfilename, "wb");
@@ -269,7 +292,7 @@ static void audio_decode_example(const char *outfilename, const char *filename)
if (!decoded_frame) {
if (!(decoded_frame = av_frame_alloc())) {
- fprintf(stderr, "out of memory\n");
+ fprintf(stderr, "Could not allocate audio frame\n");
exit(1);
}
}
@@ -284,10 +307,17 @@ static void audio_decode_example(const char *outfilename, const char *filename)
int data_size = av_samples_get_buffer_size(NULL, c->channels,
decoded_frame->nb_samples,
c->sample_fmt, 1);
+ if (data_size < 0) {
+ /* This should not occur, checking just for paranoia */
+ fprintf(stderr, "Failed to calculate data size\n");
+ exit(1);
+ }
fwrite(decoded_frame->data[0], 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
@@ -313,27 +343,30 @@ static void audio_decode_example(const char *outfilename, const char *filename)
/*
* Video encoding example
*/
-static void video_encode_example(const char *filename)
+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 *picture;
+ AVFrame *frame;
AVPacket pkt;
uint8_t endcode[] = { 0, 0, 1, 0xb7 };
- printf("Video encoding\n");
+ printf("Encode video file %s\n", filename);
/* find the mpeg1 video encoder */
- codec = avcodec_find_encoder(AV_CODEC_ID_MPEG1VIDEO);
+ codec = avcodec_find_encoder(codec_id);
if (!codec) {
- fprintf(stderr, "codec not found\n");
+ fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
- picture = av_frame_alloc();
+ if (!c) {
+ fprintf(stderr, "Could not allocate video codec context\n");
+ exit(1);
+ }
/* put sample parameters */
c->bit_rate = 400000;
@@ -341,35 +374,52 @@ static void video_encode_example(const char *filename)
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->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");
+ fprintf(stderr, "Could not open codec\n");
exit(1);
}
f = fopen(filename, "wb");
if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
+ 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;
- ret = av_image_alloc(picture->data, picture->linesize, c->width, 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 alloc raw picture buffer\n");
+ fprintf(stderr, "Could not allocate 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++) {
+ for (i = 0; i < 25; i++) {
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = 0;
@@ -377,31 +427,31 @@ static void video_encode_example(const char *filename)
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;
+ 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++) {
- picture->data[1][y * picture->linesize[1] + x] = 128 + y + i * 2;
- picture->data[2][y * picture->linesize[2] + x] = 64 + x + i * 5;
+ 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;
}
}
- picture->pts = i;
+ frame->pts = i;
/* encode the image */
- ret = avcodec_encode_video2(c, &pkt, picture, &got_output);
+ ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
if (ret < 0) {
- fprintf(stderr, "error encoding frame\n");
+ fprintf(stderr, "Error encoding frame\n");
exit(1);
}
if (got_output) {
- printf("encoding frame %3d (size=%5d)\n", i, pkt.size);
+ printf("Write frame %3d (size=%5d)\n", i, pkt.size);
fwrite(pkt.data, 1, pkt.size, f);
av_free_packet(&pkt);
}
@@ -413,12 +463,12 @@ static void video_encode_example(const char *filename)
ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
if (ret < 0) {
- fprintf(stderr, "error encoding frame\n");
+ fprintf(stderr, "Error encoding frame\n");
exit(1);
}
if (got_output) {
- printf("encoding frame %3d (size=%5d)\n", i, pkt.size);
+ printf("Write frame %3d (size=%5d)\n", i, pkt.size);
fwrite(pkt.data, 1, pkt.size, f);
av_free_packet(&pkt);
}
@@ -430,8 +480,8 @@ static void video_encode_example(const char *filename)
avcodec_close(c);
av_free(c);
- av_freep(&picture->data[0]);
- av_frame_free(&picture);
+ av_freep(&frame->data[0]);
+ av_frame_free(&frame);
printf("\n");
}
@@ -445,22 +495,49 @@ static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
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);
+ 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, got_picture, len;
+ int frame_count;
FILE *f;
- AVFrame *picture;
+ AVFrame *frame;
uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
- char buf[1024];
AVPacket avpkt;
av_init_packet(&avpkt);
@@ -468,17 +545,20 @@ static void video_decode_example(const char *outfilename, const char *filename)
/* 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");
+ 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");
+ fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
- picture = av_frame_alloc();
+ 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 */
@@ -489,20 +569,24 @@ static void video_decode_example(const char *outfilename, const char *filename)
/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
+ 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);
+ fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
- frame = 0;
- for(;;) {
+ 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;
@@ -523,26 +607,9 @@ static void video_decode_example(const char *outfilename, const char *filename)
/* 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);
+ while (avpkt.size > 0)
+ if (decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 0) < 0)
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
@@ -550,46 +617,48 @@ static void video_decode_example(const char *outfilename, const char *filename)
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++;
- }
+ decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 1);
fclose(f);
avcodec_close(c);
av_free(c);
- av_frame_free(&picture);
+ av_frame_free(&frame);
printf("\n");
}
int main(int argc, char **argv)
{
- const char *filename;
+ const char *output_type;
/* 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";
+ 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.sw", "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 {
- filename = argv[1];
+ fprintf(stderr, "Invalid output type '%s', choose between 'h264', 'mp2', or 'mpg'\n",
+ output_type);
+ return 1;
}
- // audio_decode_example("/tmp/test.sw", filename);
- video_decode_example("/tmp/test%d.pgm", filename);
-
return 0;
}
diff --git a/doc/examples/demuxing_decoding.c b/doc/examples/demuxing_decoding.c
new file mode 100644
index 0000000..2ce4018
--- /dev/null
+++ b/doc/examples/demuxing_decoding.c
@@ -0,0 +1,386 @@
+/*
+ * 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 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 (*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,
+ video_dec_ctx->pix_fmt, video_dec_ctx->width, video_dec_ctx->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;
+ 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 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;
+ }
+ }
+
+ 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 */
+ ret = av_image_alloc(video_dst_data, video_dst_linesize,
+ video_dec_ctx->width, video_dec_ctx->height,
+ video_dec_ctx->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(video_dec_ctx->pix_fmt), video_dec_ctx->width, video_dec_ctx->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 0000000..d6fd613
--- /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 60fe107..01761dc 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 0000000..46595fb
--- /dev/null
+++ b/doc/examples/filtering_audio.c
@@ -0,0 +1,280 @@
+/*
+ * 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;
+ }
+
+ /* 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 ((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 0000000..8d59573
--- /dev/null
+++ b/doc/examples/filtering_video.c
@@ -0,0 +1,261 @@
+/*
+ * 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();
+ 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,
+ 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;
+ }
+
+ /* 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;
+ }
+
+ /* 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 ((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 f4c6eee..f73c267 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/output.c b/doc/examples/muxing.c
index 0534554..3ec2eb6 100644
--- a/doc/examples/output.c
+++ b/doc/examples/muxing.c
@@ -24,9 +24,9 @@
* @file
* libavformat API example.
*
- * @example output.c
* Output a media file in any supported libavformat format. The default
* codecs are used.
+ * @example muxing.c
*/
#include <stdlib.h>
@@ -34,17 +34,17 @@
#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"
+#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>
-/* 5 seconds stream duration */
-#define STREAM_DURATION 5.0
+#define STREAM_DURATION 10.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
@@ -55,6 +55,7 @@ typedef struct OutputStream {
/* pts of the next frame that will be generated */
int64_t next_pts;
+ int samples_count;
AVFrame *frame;
AVFrame *tmp_frame;
@@ -62,75 +63,121 @@ typedef struct OutputStream {
float t, tincr, tincr2;
struct SwsContext *sws_ctx;
- AVAudioResampleContext *avr;
+ struct SwrContext *swr_ctx;
} OutputStream;
-/**************************************************************/
-/* audio output */
+static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt)
+{
+ AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
-/*
- * add an audio output stream
- */
-static void add_audio_stream(OutputStream *ost, AVFormatContext *oc,
- enum AVCodecID codec_id)
+ 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;
- AVCodec *codec;
- int ret;
+ int i;
- /* find the audio encoder */
- codec = avcodec_find_encoder(codec_id);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
+ /* 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);
+ ost->st = avformat_new_stream(oc, *codec);
if (!ost->st) {
- fprintf(stderr, "Could not alloc stream\n");
+ fprintf(stderr, "Could not allocate stream\n");
exit(1);
}
-
+ ost->st->id = oc->nb_streams-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;
+ 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;
- ost->st->time_base = (AVRational){ 1, c->sample_rate };
+ default:
+ break;
+ }
- // some formats want stream headers to be separate
+ /* 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);
- }
}
+/**************************************************************/
+/* audio output */
+
static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
uint64_t channel_layout,
int sample_rate, int nb_samples)
@@ -159,16 +206,21 @@ static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
return frame;
}
-static void open_audio(AVFormatContext *oc, OutputStream *ost)
+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 */
- if (avcodec_open2(c, NULL, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
+ 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);
}
@@ -185,8 +237,29 @@ static void open_audio(AVFormatContext *oc, OutputStream *ost)
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);
+ 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
@@ -202,8 +275,7 @@ static AVFrame *get_audio_frame(OutputStream *ost)
STREAM_DURATION, (AVRational){ 1, 1 }) >= 0)
return NULL;
-
- for (j = 0; j < frame->nb_samples; j++) {
+ 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;
@@ -211,62 +283,37 @@ static AVFrame *get_audio_frame(OutputStream *ost)
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);
+ frame->pts = ost->next_pts;
+ ost->next_pts += frame->nb_samples;
- /* 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;
+ return frame;
}
/*
* 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)
+static int write_audio_frame(AVFormatContext *oc, OutputStream *ost)
{
+ AVCodecContext *c;
+ AVPacket pkt = { 0 }; // data and size must be 0;
AVFrame *frame;
- int got_output = 0;
int ret;
+ int got_packet;
+ int dst_nb_samples;
+
+ av_init_packet(&pkt);
+ c = ost->st->codec;
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);
- }
- }
+ /* 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);
- 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
@@ -275,92 +322,41 @@ static int process_audio_stream(AVFormatContext *oc, OutputStream *ost)
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);
- }
+ /* 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 resampling\n");
- exit(1);
- } else if (frame && ret != ost->frame->nb_samples) {
- fprintf(stderr, "Too few samples returned from lavr\n");
+ fprintf(stderr, "Error while writing audio frame: %s\n",
+ av_err2str(ret));
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;
+ return (frame || got_packet) ? 0 : 1;
}
/**************************************************************/
/* 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;
@@ -384,22 +380,26 @@ static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
return picture;
}
-static void open_video(AVFormatContext *oc, OutputStream *ost)
+static void open_video(AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg)
{
- AVCodecContext *c;
+ int ret;
+ AVCodecContext *c = ost->st->codec;
+ AVDictionary *opt = NULL;
- c = ost->st->codec;
+ av_dict_copy(&opt, opt_arg, 0);
/* open the codec */
- if (avcodec_open2(c, NULL, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
+ 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 the encoded raw picture. */
+ /* 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 picture\n");
+ fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
@@ -466,12 +466,13 @@ static AVFrame *get_video_frame(OutputStream *ost)
SCALE_FLAGS, NULL, NULL, NULL);
if (!ost->sws_ctx) {
fprintf(stderr,
- "Cannot initialize the conversion context\n");
+ "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, ost->tmp_frame->data, ost->tmp_frame->linesize,
+ 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);
@@ -521,20 +522,19 @@ static int write_video_frame(AVFormatContext *oc, OutputStream *ost)
/* encode the image */
ret = avcodec_encode_video2(c, &pkt, frame, &got_packet);
if (ret < 0) {
- fprintf(stderr, "Error encoding a video frame\n");
+ fprintf(stderr, "Error encoding video frame: %s\n", av_err2str(ret));
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);
+ ret = write_frame(oc, &c->time_base, ost->st, &pkt);
+ } else {
+ ret = 0;
}
}
- if (ret != 0) {
- fprintf(stderr, "Error while writing video frame\n");
+
+ if (ret < 0) {
+ fprintf(stderr, "Error while writing video frame: %s\n", av_err2str(ret));
exit(1);
}
@@ -547,7 +547,7 @@ static void close_stream(AVFormatContext *oc, OutputStream *ost)
av_frame_free(&ost->frame);
av_frame_free(&ost->tmp_frame);
sws_freeContext(ost->sws_ctx);
- avresample_free(&ost->avr);
+ swr_free(&ost->swr_ctx);
}
/**************************************************************/
@@ -559,52 +559,51 @@ int main(int argc, char **argv)
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) {
+ 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"
+ "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);
+ }
- /* Autodetect the output format from the name. default is MPEG. */
- fmt = av_guess_format(NULL, filename, NULL);
- if (!fmt) {
+ /* 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");
- fmt = av_guess_format("mpeg", NULL, NULL);
+ avformat_alloc_output_context2(&oc, NULL, "mpeg", filename);
}
- if (!fmt) {
- fprintf(stderr, "Could not find suitable output format\n");
+ if (!oc)
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);
+ 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_video_stream(&video_st, oc, fmt->video_codec);
+ 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_audio_stream(&audio_st, oc, fmt->audio_codec);
+ add_stream(&audio_st, oc, &audio_codec, fmt->audio_codec);
have_audio = 1;
encode_audio = 1;
}
@@ -612,22 +611,30 @@ int main(int argc, char **argv)
/* 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);
+ open_video(oc, video_codec, &video_st, opt);
+
if (have_audio)
- open_audio(oc, &audio_st);
+ 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)) {
- if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) {
- fprintf(stderr, "Could not open '%s'\n", filename);
+ 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. */
- avformat_write_header(oc, NULL);
+ 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 */
@@ -636,7 +643,7 @@ int main(int argc, char **argv)
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);
+ encode_audio = !write_audio_frame(oc, &audio_st);
}
}
diff --git a/doc/examples/remuxing.c b/doc/examples/remuxing.c
new file mode 100644
index 0000000..39d9dee
--- /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_close(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 0000000..f35e7e1
--- /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 0000000..587f3ab
--- /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 6206afe..cee447f 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 48000
@@ -51,7 +52,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));
@@ -226,52 +227,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;
}
@@ -390,30 +385,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;
}
@@ -450,7 +436,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. */
@@ -487,7 +473,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;
@@ -649,7 +635,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;
@@ -753,10 +739,7 @@ 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) {
diff --git a/doc/examples/transcoding.c b/doc/examples/transcoding.c
new file mode 100644
index 0000000..759c628
--- /dev/null
+++ b/doc/examples/transcoding.c
@@ -0,0 +1,579 @@
+/*
+ * 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);
+
+ /* 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_close(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 b400124..fdcb46d 100644
--- a/doc/faq.texi
+++ b/doc/faq.texi
@@ -1,8 +1,8 @@
\input texinfo @c -*- texinfo -*-
-@settitle Libav FAQ
+@settitle FFmpeg FAQ
@titlepage
-@center @titlefont{Libav FAQ}
+@center @titlefont{FFmpeg FAQ}
@end titlepage
@top
@@ -11,23 +11,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 +79,25 @@ 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.
+
@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 +105,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 +128,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 +137,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 +169,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 +188,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 +214,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 +239,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 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 +307,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 +346,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 +356,80 @@ 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.
+
+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.
-@command{avconv} prints an error like
+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?
-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}.
+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.
-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.
+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.
@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. Read the Developers Guide of the Libav documentation. Alternatively,
+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}.
+
+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 +440,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}.
+
+@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.
-Libav is a pure C project, so to use the libraries within your C++ application
+@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 0185d87..4e5cbd7 100644
--- a/doc/fate.texi
+++ b/doc/fate.texi
@@ -1,83 +1,177 @@
\input texinfo @c -*- texinfo -*-
-@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.
+
+ 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.
-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 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
+`--samples=<path to the samples directory>'. Afterwards you can
+invoke the makefile targets without setting the 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.
+
+@example
+FATE_SAMPLES=fate-suite/ make fate
+@end example
+
+@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
+
+To use a custom wrapper to run the test, pass @option{--target-exec} to
+@command{configure} or set the @var{TARGET_EXEC} Make variable.
-@chapter Manual Run
-FATE regression test can be run through @command{make}.
-Specific Makefile targets and Makefile variables are available:
-@anchor{Makefile target}
-@section FATE Makefile targets
+@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 `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 <arch>-<os>-<compiler>-<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 `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 @option
-@item fate-list
-List all fate/regression test targets.
+@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
+
+ 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 fate-rsync
-Shortcut to download the fate test samples to the specified testsuite location.
+Download/synchronize sample files to the configured samples directory.
+
+@item fate-list
+Will list all fate/regression test targets.
@item fate
Run the FATE test suite (requires the fate-suite dataset).
@end table
-@section FATE Makefile variables
+@section Makefile variables
+
@table @option
@item V
Verbosity level, can be set to 0, 1 or 2.
-
-@table @option
-@item 0
-show just the test arguments
-
-@item 1
-show just the command used in the test
-
-@item 2
-show everything
-@end table
+ @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
@@ -92,77 +186,20 @@ Specify which threading strategy test, either @var{slice} or @var{frame},
by default @var{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 @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}.
@item GEN
Set to @var{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
-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}.
-The current server fingerprint is @var{a4:99:d7:d3:1c:92:0d:56:d6:d5:61:be:01:ae:7d:e6}
diff --git a/doc/fate_config.sh.template b/doc/fate_config.sh.template
new file mode 100644
index 0000000..1487c1d
--- /dev/null
+++ b/doc/fate_config.sh.template
@@ -0,0 +1,29 @@
+slot= # some unique identifier
+repo=git://source.ffmpeg.org/ffmpeg.git # the source repository
+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 0000000..e33e005
--- /dev/null
+++ b/doc/ffmpeg-bitstream-filters.texi
@@ -0,0 +1,45 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 0000000..6f8f5a3
--- /dev/null
+++ b/doc/ffmpeg-codecs.texi
@@ -0,0 +1,42 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 0000000..b44bd72
--- /dev/null
+++ b/doc/ffmpeg-devices.texi
@@ -0,0 +1,42 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 0000000..bb920ce
--- /dev/null
+++ b/doc/ffmpeg-filters.texi
@@ -0,0 +1,42 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 0000000..e205caa
--- /dev/null
+++ b/doc/ffmpeg-formats.texi
@@ -0,0 +1,42 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 0000000..d992e75
--- /dev/null
+++ b/doc/ffmpeg-protocols.texi
@@ -0,0 +1,42 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 0000000..5bef789
--- /dev/null
+++ b/doc/ffmpeg-resampler.texi
@@ -0,0 +1,44 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 0000000..c4ddc09
--- /dev/null
+++ b/doc/ffmpeg-scaler.texi
@@ -0,0 +1,43 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 0000000..581e2ea
--- /dev/null
+++ b/doc/ffmpeg-utils.texi
@@ -0,0 +1,42 @@
+\input texinfo @c -*- texinfo -*-
+
+@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/avconv.texi b/doc/ffmpeg.texi
index 37733bc..d774aba 100644
--- a/doc/avconv.texi
+++ b/doc/ffmpeg.texi
@@ -1,8 +1,8 @@
\input texinfo @c -*- texinfo -*-
-@settitle avconv Documentation
+@settitle ffmpeg Documentation
@titlepage
-@center @titlefont{avconv Documentation}
+@center @titlefont{ffmpeg Documentation}
@end titlepage
@top
@@ -11,37 +11,31 @@
@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
+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
-avconv is a very fast video and audio converter that can also grab from
+@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.
-avconv reads from an arbitrary number of input "files" (which can be regular
+@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). 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).
+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
+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.
+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
@@ -56,22 +50,22 @@ 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:
+To set the video bitrate of the output file to 64 kbit/s:
@example
-avconv -i input.avi -b 64k output.avi
+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
-avconv -i input.avi -r 24 output.avi
+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
-avconv -r 1 -i input.m2v -r 24 output.avi
+ffmpeg -r 1 -i input.m2v -r 24 output.avi
@end example
@end itemize
@@ -82,7 +76,7 @@ The format option may be needed for raw input files.
@chapter Detailed description
@c man begin DETAILED DESCRIPTION
-The transcoding process in @command{avconv} for each output can be described by
+The transcoding process in @command{ffmpeg} for each output can be described by
the following diagram:
@example
@@ -106,22 +100,22 @@ the following diagram:
@end example
-@command{avconv} calls the libavformat library (containing demuxers) to read
+@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{avconv} tries to keep them synchronized by
+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 again. Finally those are
+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{avconv} can process raw audio and video frames using
+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{avconv} distinguishes between two types of filtergraphs -
+graph. @command{ffmpeg} distinguishes between two types of filtergraphs:
simple and complex.
@subsection Simple filtergraphs
@@ -133,11 +127,11 @@ an additional step between decoding and encoding:
_________ ______________
| | | |
| decoded | | encoded data |
-| frames |\ /| packets |
-|_________| \ / |______________|
+| frames |\ _ | packets |
+|_________| \ /||______________|
\ __________ /
- simple \ | | / encoder
- filtergraph \| filtered |/
+ simple _\|| | / encoder
+ filtergraph | filtered |/
| frames |
|__________|
@@ -162,7 +156,7 @@ 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
+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:
@@ -187,19 +181,21 @@ input. They can be represented with the following diagram:
@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
+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{avconv} omit the decoding and encoding
+@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:
+diagram above will, in this case, simplify to this:
@example
_______ ______________ ________
@@ -211,7 +207,7 @@ diagram above will in this case simplify to this:
@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
+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
@@ -219,12 +215,14 @@ filters is obviously also impossible, since filters work on uncompressed data.
@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.
+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 @code{-vn/-an/-sn} options. For
+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.
@@ -233,15 +231,15 @@ described.
@chapter Options
@c man begin OPTIONS
-@include avtools-common-opts.texi
+@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 autodetected for input
-files and guessed from file extension for output files, so this option is not
+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})
@@ -251,39 +249,53 @@ input file name
Overwrite output files without asking.
@item -n (@emph{global})
-Immediately exit when output files already exist.
+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 reencoded.
+the stream is not to be re-encoded.
For example
@example
-avconv -i INPUT -map 0 -c:v libx264 -c:a copy OUTPUT
+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
-avconv -i INPUT -map 0 -c copy -c:v:1 libx264 -c:a:137 libvorbis OUTPUT
+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{output})
-Stop writing the output after its duration reaches @var{duration}.
+@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.
+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{avconv} will seek to the closest seek point before @var{position}.
+@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
@@ -295,11 +307,20 @@ 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.
+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.
@@ -313,12 +334,12 @@ 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
+ffmpeg -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
+ffmpeg -i INPUT -metadata:s:a:0 language=eng OUTPUT
@end example
@item -target @var{type} (@emph{output})
@@ -328,34 +349,46 @@ Specify target file type (@code{vcd}, @code{svcd}, @code{dvd}, @code{dv},
(bitrate, codecs, buffer sizes) are then set automatically. You can just type:
@example
-avconv -i myfile.avi -target vcd /tmp/vcd.mpg
+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
-avconv -i myfile.avi -target vcd -bf 2 /tmp/vcd.mpg
+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 record. This is an alias for @code{-frames:d}.
+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} is
+Use fixed quality scale (VBR). The meaning of @var{q}/@var{qscale} 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.
+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
@@ -366,7 +399,34 @@ read.
Specify the preset for matching stream(s).
@item -stats (@emph{global})
-Print encoding progress/statistics. On by default.
+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
@@ -379,7 +439,7 @@ 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
+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).
@@ -390,11 +450,11 @@ 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
+ffmpeg -dump_attachment:t:0 out.ttf -i INPUT
@end example
To extract all attachments to files determined by the @code{filename} tag:
@example
-avconv -dump_attachment:t "" INPUT
+ffmpeg -dump_attachment:t "" -i INPUT
@end example
Technical note -- attachments are implemented as codec extradata, so this
@@ -407,16 +467,18 @@ attachments.
@table @option
@item -vframes @var{number} (@emph{output})
-Set the number of video frames to record. This is an alias for @code{-frames:v}.
+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} (note that this actually causes the @code{fps} filter to be
-inserted to the end of the corresponding filtergraph).
+frame rate @var{fps}.
@item -s[:@var{stream_specifier}] @var{size} (@emph{input/output,per-stream})
Set frame size.
@@ -429,68 +491,7 @@ 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
+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}.
@@ -500,6 +501,10 @@ 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.
@@ -515,38 +520,56 @@ 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
+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 ``av2pass''. The complete file name will be
+prefix is ``ffmpeg2pass''. The complete file name will be
@file{PREFIX-N.log}, where N is a number specific to the output
-stream.
+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}.
+@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
+@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
-
+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}
@@ -558,13 +581,61 @@ 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.
+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.
-The timestamps must be specified in ascending order.
+
+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
@@ -594,7 +665,7 @@ 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}
+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.
@@ -621,7 +692,7 @@ If this option is not specified, the default adapter is used.
@table @option
@item -aframes @var{number} (@emph{output})
-Set the number of audio frames to record. This is an alias for @code{-frames:a}.
+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
@@ -641,27 +712,60 @@ 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}.
+
+@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:
+@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:
+@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
@@ -689,7 +793,7 @@ graphs (see the @option{-filter_complex} option) to the output file.
For example, to map ALL streams from the first input file to output
@example
-avconv -i INPUT -map 0 output
+ffmpeg -i INPUT -map 0 output
@end example
For example, if you have two audio streams in the first input file,
@@ -697,7 +801,7 @@ 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
+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}.
@@ -707,26 +811,82 @@ For example, to select the stream with index 2 from input file
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
+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
-avconv -i INPUT -map 0:v -map 0:a:2 OUTPUT
+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
-avconv -i INPUT -map 0 -map -0:a:1 OUTPUT
+ffmpeg -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
+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 -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.
@@ -758,12 +918,12 @@ file index can be used to create a dummy mapping that just disables automatic co
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
+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
-avconv -i in.mkv -map_metadata:s:a 0:g out.mkv
+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.
@@ -773,41 +933,63 @@ 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 -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 avconv has been running for @var{duration} seconds.
+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
+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 passthrough
+@item 0, passthrough
Each frame is passed with its timestamp from the demuxer to the muxer.
-@item cfr
+@item 1, cfr
Frames will be duplicated and dropped to achieve exactly the requested
-constant framerate.
-@item vfr
+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 auto
+@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.
@@ -817,11 +999,53 @@ 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.
+
+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
-Copy timestamps from input to output.
-@item -copytb
-Copy input stream time base from input to output when stream copying.
+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
@@ -839,28 +1063,37 @@ 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
+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{bistream_filters} is
+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
-avconv -i h264.mp4 -c:v copy -bsf:v h264_mp4toannexb -an out.h264
+ffmpeg -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
+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 filter graph, i.e. one with arbitrary number of inputs and/or
+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 filter graph, as described in @ref{Filtergraph syntax}.
+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}
@@ -876,7 +1109,7 @@ 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
+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,
@@ -887,21 +1120,25 @@ 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
+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
-avconv -i video.mkv -i image.png -filter_complex 'overlay' out.mkv
+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
-avconv -filter_complex 'color=red' -t 5 out.mkv
+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
@@ -913,7 +1150,90 @@ This option enables or disables accurate seeking in input files with the
transcoding. Use @option{-noaccurate_seek} to disable it, which may be useful
e.g. when copying some streams and transcoding the others.
+@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 -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.
+
+Preset 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}.
@c man end OPTIONS
@chapter Tips
@@ -921,13 +1241,13 @@ e.g. when copying some streams and transcoding the others.
@itemize
@item
-For streaming at very low bitrate application, use a low frame rate
+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
-avconv -g 3 -r 3 -t 10 -b 50k -s qcif -f rv10 /tmp/b.rm
+ffmpeg -g 3 -r 3 -t 10 -b:v 50k -s qcif -f rv10 /tmp/b.rm
@end example
@item
@@ -966,43 +1286,48 @@ 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.
+@file{presets} directory in the FFmpeg 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})
+preset name as input. FFmpeg searches for a file named @var{preset_name}.avpreset in
+the directories @file{$AVCONV_DATADIR} (if set), and @file{$HOME/.ffmpeg}, and in
+the data directory defined at configuration time (usually @file{$PREFIX/share/ffmpeg})
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
+If you specify the input format and device then ffmpeg can grab video
and audio directly.
@example
-avconv -f oss -i /dev/dsp -f video4linux2 -i /dev/video0 /tmp/out.mpg
+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 avconv with any TV viewer such as
+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 avconv via
+Grab the X11 display with ffmpeg via
@example
-avconv -f x11grab -s cif -r 25 -i :0.0 /tmp/out.mpg
+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
-avconv -f x11grab -s cif -r 25 -i :0.0+10,20 /tmp/out.mpg
+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
@@ -1010,7 +1335,7 @@ 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:
+Any supported file format and protocol can serve as input to ffmpeg:
Examples:
@itemize
@@ -1018,7 +1343,7 @@ Examples:
You can use YUV files as input:
@example
-avconv -i /tmp/test%d.Y /tmp/out.mpg
+ffmpeg -i /tmp/test%d.Y /tmp/out.mpg
@end example
It will use the files:
@@ -1030,13 +1355,13 @@ It will use the files:
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.
+if ffmpeg cannot guess it.
@item
You can input from a raw YUV420P file:
@example
-avconv -i /tmp/test.yuv /tmp/out.avi
+ffmpeg -i /tmp/test.yuv /tmp/out.avi
@end example
test.yuv is a file containing raw YUV planar data. Each frame is composed
@@ -1047,14 +1372,14 @@ horizontal resolution.
You can output to a raw YUV420P file:
@example
-avconv -i mydivx.avi hugefile.yuv
+ffmpeg -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
+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
@@ -1064,7 +1389,7 @@ to MPEG file a.mpg.
You can also do audio and video conversions at the same time:
@example
-avconv -i /tmp/a.wav -ar 22050 /tmp/a.mp2
+ffmpeg -i /tmp/a.wav -ar 22050 /tmp/a.mp2
@end example
Converts a.wav to MPEG audio at 22050 Hz sample rate.
@@ -1074,7 +1399,7 @@ 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
+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
@@ -1085,7 +1410,7 @@ stream, in the order of the definition of output streams.
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
+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
@@ -1097,14 +1422,14 @@ 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}.
+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
-avconv -i foo.avi -r 1 -s WxH -f image2 foo-%03d.jpeg
+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
@@ -1117,7 +1442,7 @@ 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
+ffmpeg -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
@@ -1125,11 +1450,21 @@ 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 -i 'foo-*.jpeg' -r 12 -s WxH foo.avi
+@end example
+
@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
+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
@@ -1138,43 +1473,86 @@ 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
+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
-avconv -i src.ext -lmax 21*QP2LAMBDA dst.ext
+ffmpeg -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 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
-@include metadata.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 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
+@setfilename ffmpeg
+@settitle ffmpeg video converter
@end ignore
diff --git a/doc/ffmpeg.txt b/doc/ffmpeg.txt
new file mode 100644
index 0000000..a028ca2
--- /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 0000000..3c85417
--- /dev/null
+++ b/doc/ffplay.texi
@@ -0,0 +1,305 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 -threads @var{count}
+Set the thread count. By default, @command{ffplay} automatically detects a
+suitable number of threads to use.
+@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 -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 presentation 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 0000000..5c90470
--- /dev/null
+++ b/doc/ffprobe.texi
@@ -0,0 +1,681 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 ('\n'), carriage
+return ('\r'), a tab ('\t'), a form feed ('\f'), the escaping
+character ('\') or the item separator character @var{SEP} are escaped using C-like fashioned
+escaping, so that a newline is converted to the sequence "\n", a
+carriage return to "\r", '\' to "\\" and the separator @var{SEP} is
+converted to "\@var{SEP}".
+
+@item csv
+Perform CSV-like escaping, as described in RFC4180. Strings
+containing a newline ('\n'), a carriage return ('\r'), a double quote
+('"'), 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 '.'.
+
+@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
+'.' is the subgroup separator
+@item
+newline, '\t', '\f', '\b' and the following characters are escaped
+@item
+'\' is the escape character
+@item
+'#' is the comment indicator
+@item
+'=' is the key/value separator
+@item
+':' 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 ":".
+
+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 0000000..c2cab37
--- /dev/null
+++ b/doc/ffprobe.xsd
@@ -0,0 +1,336 @@
+<?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: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="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: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="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"/>
+
+ <!-- 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" use="required"/>
+ <xsd:attribute name="build_time" type="xsd:string" use="required"/>
+ <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 0000000..b756961
--- /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 0000000..77273d2
--- /dev/null
+++ b/doc/ffserver.texi
@@ -0,0 +1,907 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 allow 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:
+@example
+ _________ __________
+ | | | |
+ffmpeg 1 -----| feed 1 |-----| stream 1 |
+ \ |_________|\ |__________|
+ \ \
+ \ \ __________
+ \ \ | |
+ \ \| stream 2 |
+ \ |__________|
+ \
+ \ _________ __________
+ \ | | | |
+ \| feed 2 |-----| stream 3 |
+ |_________| |__________|
+
+ _________ __________
+ | | | |
+ffmpeg 2 -----| feed 3 |-----| stream 4 |
+ |_________| |__________|
+
+ _________ __________
+ | | | |
+ | file 1 |-----| stream 5 |
+ |_________| |__________|
+@end example
+
+@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.
+@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 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{option} @var{value} (@emph{encoding,audio})
+Set generic option for audio stream.
+
+@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{option} @var{value} (@emph{encoding,video})
+Set generic option for video stream.
+
+@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 0000000..0e8f849
--- /dev/null
+++ b/doc/fftools-common-opts.texi
@@ -0,0 +1,331 @@
+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.
+
+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 number or a string containing one of the following values:
+@table @samp
+@item quiet
+Show nothing at all; be silent.
+@item panic
+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
+Only show fatal errors. These are errors after which the process absolutely
+cannot continue after.
+@item error
+Show all errors, including ones which can be recovered from.
+@item warning
+Show all warnings and errors. Any message related to possibly
+incorrect or unexpected events will be shown.
+@item info
+Show informative messages during processing. This is in addition to
+warnings and errors. This is the default value.
+@item verbose
+Same as @code{info}, except more verbose.
+@item debug
+Show everything, including debugging information.
+@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 @code{FFREPORT} to any value has the
+same effect. If the value is a ':'-separated key=value sequence, these
+options will affect the report; options 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 option is 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 level
+@end table
+
+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 xop
+@item fma4
+@item 3dnow
+@item 3dnowext
+@item cmov
+@end table
+@item ARM
+@table @samp
+@item armv5te
+@item armv6
+@item armv6t2
+@item vfp
+@item vfpv3
+@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
+Benchmark all available OpenCL devices and show the results. This option
+is only available when FFmpeg has been compiled with @code{--enable-opencl}.
+
+@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 0000000..fca24a9
--- /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 28e3292..53f4cb2 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.
+
+@example
+ [main]
+input --> split ---------------------> overlay --> output
+ | ^
+ |[tmp] [flip]|
+ +-----> crop --> vflip -------+
+@end example
+
+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
@@ -19,7 +116,7 @@ output pads is called a "sink".
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
+options in @command{ffmpeg} and @option{-vf} in @command{ffplay}, and by the
@code{avfilter_graph_parse()}/@code{avfilter_graph_parse2()} functions defined in
@file{libavfilter/avfilter.h}.
@@ -55,6 +152,12 @@ 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
@@ -69,7 +172,7 @@ terminated when the next special character (belonging to the set
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
@@ -112,21 +215,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 +564,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 +575,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 +703,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
-This filter accepts the following parameters:
+@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
-@table @option
+@section asetnsamples
-@item expr
-The expression which is evaluated into the output timebase.
+Set the number of samples per each output audio frame.
-@end table
+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.
-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).
+The filter accepts the following options:
-The default value for the input is @var{intb}.
+@table @option
-Some examples:
+@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.
+
+@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
+asetnsamples=n=1234:p=0
+@end example
-# Set the timebase to 1/10:
-settb=0.1
+@section asetrate
-# Set the timebase to 1001/1000:
-settb=1+0.001
+Set the sample rate without altering the PCM data.
+This will result in a change of speed and pitch.
-# Set the timebase to 2*intb:
-settb=2*intb
+The filter accepts the following options:
-# Set the default timebase value:
-settb=AVTB
-
-# 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 +875,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 +888,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 +912,94 @@ 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
+@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 miliseconds). Allowed range is @code{[0.1 - 10]}.
+@end table
+
+A description of each shown parameter follows:
+
+@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.
-For example,
+@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 +1026,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 +1061,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 +1083,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 +1108,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,32 +1254,8 @@ Feed level (in Hz).
@end table
-@section channelsplit
-Split each channel from an input audio stream into a separate output stream.
-
-It accepts the following parameters:
-@table @option
-@item channel_layout
-The channel layout of the input stream. The default is "stereo".
-@end table
-
-For example, assuming a stereo input MP3 file,
-@example
-avconv -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
-'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.
It accepts the following parameters:
@@ -523,14 +1278,40 @@ output channels, preserving indices.
For example, assuming a 5.1+downmix input MOV file,
@example
-avconv -i in.mov -filter 'channelmap=map=DL-FL|DR-FR' out.wav
+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
-avconv -i in.wav -filter 'channelmap=1|2|0|5|3|4:channel_layout=5.1' out.wav
+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:
+@table @option
+@item channel_layout
+The channel layout of the input stream. The default is "stereo".
+@end table
+
+For example, assuming a stereo input MP3 file,
+@example
+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
+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 compand
@@ -553,7 +1334,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 +1389,141 @@ compand=.1|.1:.1|.1:-45.1/-45.1|-45/-900|0/-900:.01:45:-90:.1
@end example
@end itemize
+@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 regeneneration (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 valu 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 +1550,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 remap efficiently 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=1: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 threated 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 +1957,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 +1966,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 +2005,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 +2082,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
+
+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{sample_rate} specifies the sample rate, and defaults to 44100.
+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
-@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.
+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.
-Check the channel_layout_map definition in
-@file{libavutil/channel_layout.c} for the mapping between strings and
-channel layout values.
+@c man end AUDIO FILTERS
-Some examples:
-@example
-# Set the sample rate to 48000 Hz and the channel layout to CH_LAYOUT_MONO
-anullsrc=48000:4
+@chapter Audio Sources
+@c man begin AUDIO SOURCES
-# The same as above
-anullsrc=48000:mono
-@end example
+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 +2165,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 corresponging 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 synthetize 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 +2461,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 +2626,150 @@ 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, thresh
+The threshold below which a pixel value is considered black; it defaults to
+@code{32}.
+
+@end table
+
+@section blend
+
+Blend two video frames into each other.
+
+It 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.
+
+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 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 threshold
-The threshold below which a pixel value is considered black; it defaults to 32.
+@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}.
+@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}.
+@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
+@end itemize
+
@section boxblur
Apply a boxblur algorithm to the input video.
@@ -855,58 +2778,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 +2856,177 @@ 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 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 +3039,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 +3125,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
+Appply 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 +3220,9 @@ 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). An intensity value greater
+to the set value is considered non-black. It defaults to 24.
@item round
The value which the width/height should be divisible by. It defaults to
@@ -1058,16 +3230,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 allow to process 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 +3502,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 +3518,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 +3540,86 @@ 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 drawbox
Draw a colored box on the input image.
@@ -1116,130 +3627,251 @@ 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
-# Draw a box with color red and an opacity of 50%
-drawbox=x=10:y=20:width=200:height=60:color=red@@0.5"
+@item
+Draw a box with color red and an opacity of 50%:
+@example
+drawbox=10:20:200:60:red@@0.5
@end example
-@section drawtext
+The previous example can be specified as:
+@example
+drawbox=x=10:y=20:w=200:h=60:color=red@@0.5
+@end example
-Draw a text string or text from a specified file on top of a video, using the
-libfreetype library.
+@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
-To enable compilation of this filter, you need to configure Libav with
-@code{--enable-libfreetype}.
-To enable default font fallback and the @var{font} option you need to
-configure Libav with @code{--enable-libfontconfig}.
+@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
-The filter also recognizes strftime() sequences in the provided text
-and expands them accordingly. Check the documentation of strftime().
+@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 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 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 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 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 textfile
-A text file containing text to be drawn. The text must be a sequence
-of UTF-8 encoded characters.
+@item thickness, t
+The expression which sets the thickness of the grid line. Default value is @code{1}.
-This parameter is mandatory if no text string is specified with the
-parameter @var{text}.
+See below for the list of accepted constants.
+@end table
-If both text and textfile are specified, an error is thrown.
+The parameters for @var{x}, @var{y}, @var{w} and @var{h} and @var{t} are expressions containing the
+following constants:
-@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 dar
+The input display aspect ratio, it is the same as (@var{w} / @var{h}) * @var{sar}.
-@item x, y
-The computed values for @var{x} and @var{y}. They are evaluated for
-each new frame.
-
-@item main_w, main_h
-The main input width and height.
+@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 W, H
-These are the same as @var{main_w} and @var{main_h}.
+@item in_h, ih
+@item in_w, iw
+The input grid cell width and height.
-@item text_w, text_h
-The rendered text's width and height.
+@item sar
+The input sample aspect ratio.
-@item w, h
-These are the same as @var{text_w} and @var{text_h}.
+@item x
+@item y
+The x and y coordinates of some point of grid intersection (meant to configure offset).
-@item n
-The number of frames processed, starting from 0.
+@item w
+@item h
+The width and height of the drawn cell.
@item t
-The timestamp, expressed in seconds. It's NAN if the input timestamp is unknown.
+The thickness of the drawn cell.
+
+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
-The default value of @var{x} and @var{y} is 0.
+@subsection Examples
-@item fontsize
-The font size to be used for drawing text.
-The default value of @var{fontsize} is 16.
+@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 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
+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
-@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".
+@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 FFmpeg with
+@code{--enable-libfreetype}.
+To enable default font fallback and the @var{font} option you need to
+configure FFmpeg with @code{--enable-libfontconfig}.
+To enable the @var{text_shaping} option, you need to configure FFmpeg with
+@code{--enable-libfribidi}.
+
+@subsection Syntax
+
+It accepts the following parameters:
+
+@table @option
@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 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.
-@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".
+The default value of @var{boxcolor} is "white".
+
+@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 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.
+
+The default value of @var{bordercolor} is "black".
+
+@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 fix_bounds
+If true, check and fix text coords to avoid clipping.
+
+@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.
+
+The default value of @var{fontcolor} is "black".
+
+@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.
+
+@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 fontsize
+The font size to be used for drawing text.
+The default value of @var{fontsize} is 16.
+
+@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.
@@ -1262,47 +3894,427 @@ 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
+
+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
-For example the command:
+@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 '\', 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 'x', 'X', 'd' and
+'u'. They are treated exactly as in the 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 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.
@@ -1310,34 +4322,428 @@ 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.
+
+@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 the first 30 frames of video
-fade=type=in:nb_frames=30
+fade=in:0:30
+@end example
-# Fade out the last 45 frames of a 200-frame video
+The command above is equivalent to:
+@example
+fade=t=in:s=0:n=30
+@end example
+
+@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
-# 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
+@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
-# Make the first 5 frames black, then fade in from frame 5-24
-fade=type=in:start_frame=5:nb_frames=20
+@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 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
+
+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:
+
+@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
@@ -1353,7 +4759,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.
@@ -1368,7 +4774,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
@@ -1380,6 +4786,7 @@ framework.
It does not take parameters.
+@anchor{format}
@section format
Convert the input video to one of the specified pixel formats.
@@ -1395,26 +4802,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
@@ -1426,6 +4857,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
@@ -1465,19 +4917,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:
@@ -1499,35 +4962,183 @@ 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 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.
@@ -1553,23 +5164,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
+gradfun=3.5:8
+@end example
+
+@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
-# Default parameters
-gradfun=strength=1.2:radius=16
+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.
-# Omitting the radius
-gradfun=1.2
+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
@@ -1596,6 +5448,242 @@ 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.
+@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
@@ -1626,6 +5714,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
+distrortion. 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
+distrortion. 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
@@ -1636,19 +5858,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
@@ -1663,11 +5896,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
@@ -1701,35 +5931,253 @@ 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 mp
+
+Apply an MPlayer filter to the input video.
+
+This filter provides a wrapper around some of the filters of
+MPlayer/MEncoder.
+
+This wrapper is considered experimental. Some of the wrapped filters
+may not work properly and we may drop support for them, as they will
+be implemented natively into FFmpeg. Thus you should avoid
+depending on them when writing portable scripts.
+
+The filter accepts the parameters:
+@var{filter_name}[:=]@var{filter_params}
+
+@var{filter_name} is the name of a supported MPlayer filter,
+@var{filter_params} is a string containing the parameters accepted by
+the named filter.
+
+The list of the currently supported filters follows:
+@table @var
+@item eq2
+@item eq
+@item fspp
+@item ilpack
+@item pp7
+@item softpulldown
+@item uspp
+@end table
+
+The parameter syntax and behavior for the listed filters are the same
+of the corresponding MPlayer filters. For detailed instructions check
+the "VIDEO FILTERS" section in the MPlayer manual.
+
+@subsection Examples
+
+@itemize
+@item
+Adjust gamma, brightness, contrast:
+@example
+mp=eq2=1.0:2:0.5
+@end example
+@end itemize
+
+See also mplayer(1), @url{http://www.mplayerhq.hu/}.
+
+@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.
@@ -1751,15 +6199,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
@@ -1770,7 +6274,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:
@@ -1787,7 +6291,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.
@@ -1879,30 +6383,15 @@ video on which the second input is overlayed.
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 overlayed 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
@@ -1917,40 +6406,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
@@ -1960,19 +6638,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.
@@ -1982,71 +6660,231 @@ 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
+
+@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
@@ -2060,367 +6898,853 @@ 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
-@table @option
+@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
-@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.
+@section psnr
-@end table
+Obtain the average, maximum and minimum PSNR (Peak Signal to Noise
+Ratio) between two input videos.
-The expression can contain the following constants:
+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:
+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
+
+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 removelogo
+
+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.
+
+The filter accepts the following options:
+
@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.
+@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
-@item key
-This is 1 if the filtered frame is a key-frame, 0 otherwise.
+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.
+
+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.
+
+@section rotate
+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".
+
+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 generalsyntax 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 default value of the select expression is "1".
+The expressions for the angle and the output size can contain the
+following constants and functions:
-Some examples:
+@table @option
+@item n
+sequential number of the input frame, starting from 0. It is always NAN
+before the first frame is filtered.
-@example
-# Select all the frames in input
-select
+@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.
-# The above is the same as
-select=expr=1
+@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.
-# Skip all frames
-select=expr=0
+@item in_w, iw
+@item in_h, ih
+the input video width and height
-# Select only I-frames
-select='expr=eq(pict_type\,I)'
+@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
-# Select one frame per 100
-select='not(mod(n\,100))'
+@item rotw(a)
+@item roth(a)
+the minimal width/height required for completely containing the input
+video rotated by @var{a} radians.
-# Select only frames contained in the 10-20 time interval
-select='gte(t\,10)*lte(t\,20)'
+These are only available when computing the @option{out_w} and
+@option{out_h} expressions.
+@end table
-# Select only I frames contained in the 10-20 time interval
-select='gte(t\,10)*lte(t\,20)*eq(pict_type\,I)'
+@subsection Examples
-# Select frames with a minimum distance of 10 seconds
-select='isnan(prev_selected_t)+gte(t-prev_selected_t\,10)'
+@itemize
+@item
+Rotate the input by PI/6 radians clockwise:
+@example
+rotate=PI/6
@end example
-@anchor{setdar}
-@section setdar
+@item
+Rotate the input by PI/6 radians counter-clockwise:
+@example
+rotate=-PI/6
+@end example
-Set the Display Aspect Ratio for the filter output video.
+@item
+Rotate the input by 45 degrees clockwise:
+@example
+rotate=45*PI/180
+@end example
-This is done by changing the specified Sample (aka Pixel) Aspect
-Ratio, according to the following equation:
-@math{DAR = HORIZONTAL_RESOLUTION / VERTICAL_RESOLUTION * SAR}
+@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
-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.
+@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
-It accepts the following parameters:
+@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 dar
-The output display aspect ratio.
+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 parameter @var{dar} is an expression containing
-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 E, PI, PHI
-These are approximated values for the mathematical constants e
-(Euler's number), pi (Greek pi), and phi (the golden ratio).
+@item width, w
+@item height, h
+Set the output video dimension expression. Default value is the input
+dimension.
-@item w, h
-The input width and height.
+If the value is 0, the input width is used for the output.
-@item a
-This is the same as @var{w} / @var{h}.
+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 sar
-The input sample aspect ratio.
+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 dar
-The input display aspect ratio. It is the same as
-(@var{w} / @var{h}) * @var{sar}.
+See below for the list of accepted constants for use in the dimension
+expression.
-@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 interl
+Set the interlacing mode. It accepts the following values:
+
+@table @samp
+@item 1
+Force interlaced aware scaling.
+
+@item 0
+Do not apply interlaced scaling.
+
+@item -1
+Select interlaced aware scaling depending on whether the source frames
+are flagged as interlaced or not.
@end table
-To change the display aspect ratio to 16:9, specify:
-@example
-setdar=dar=16/9
-# The above is equivalent to
-setdar=dar=1.77777
-@end example
+Default value is @samp{0}.
-Also see the the @ref{setsar} filter documentation.
+@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.
-@section setpts
+@item size, s
+Set the video size. For the syntax of this option, check the "Video size"
+section in the ffmpeg-utils manual.
-Change the PTS (presentation timestamp) of the input video frames.
+@item in_color_matrix
+@item out_color_matrix
+Set in/output YCbCr color space type.
-It accepts the following parameters:
+This allows the autodetected value to be overridden as well as allows forcing
+a specific value used for the output and encoder.
-@table @option
+If not specified, the color space type depends on the pixel format.
-@item expr
-The expression which is evaluated for each frame to construct its timestamp.
+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
-The expression is evaluated through the eval API and can contain the following
-constants:
+@item in_range
+@item out_range
+Set in/output YCbCr sample range.
-@table @option
-@item PTS
-The presentation timestamp in input.
+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:
-@item E, PI, PHI
-These are approximated values for the mathematical constants e
-(Euler's number), pi (Greek pi), and phi (the golden ratio).
+@table @samp
+@item auto
+Choose automatically.
-@item N
-The count of the input frame, starting from 0.
+@item jpeg/full/pc
+Set full range (0-255 in case of 8-bit luma).
-@item STARTPTS
-The PTS of the first video frame.
+@item mpeg/tv
+Set "MPEG" range (16-235 in case of 8-bit luma).
+@end table
-@item INTERLACED
-State whether the current frame is interlaced.
+@item force_original_aspect_ratio
+Enable decreasing or increasing output video width or height if necessary to
+keep the original aspect ratio. Possible values:
-@item PREV_INPTS
-The previous input PTS.
+@table @samp
+@item disable
+Scale the video as specified and disable this feature.
-@item PREV_OUTPTS
-The previous output PTS.
+@item decrease
+The output video dimensions will automatically be decreased if needed.
-@item RTCTIME
-The wallclock (RTC) time in microseconds.
+@item increase
+The output video dimensions will automatically be increased if needed.
-@item RTCSTART
-The wallclock (RTC) time at the start of the movie in microseconds.
+@end table
-@item TB
-The timebase of the input timestamps.
+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
-Some examples:
+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
+
+@item
+Scale the input to 2x with forced interlaced scaling:
+@example
+scale=2*iw:2*ih:interl=1
+@end example
+
+@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
-@anchor{setsar}
-@section setsar
+@item
+Seek Greek harmony:
+@example
+scale=iw:1/PHI*iw
+scale=ih*PHI:ih
+@end example
-Set the Sample (aka Pixel) Aspect Ratio for the filter output video.
+@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
@@ -2450,48 +7774,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
@@ -2501,7 +7841,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
@@ -2527,8 +7867,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 "Video size"
+section in the ffmpeg-utils manual.
@item i
The type of interlaced mode ("P" for "progressive", "T" for top field first, "B"
@@ -2545,11 +7885,11 @@ 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 shuffleplanes
@@ -2578,21 +7918,678 @@ 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
+
+@item
+Output specific data about the minimum and maximum values of the Y plane per frame:
+@example
+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)
-Create 5 copies of the input video:
+@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
-avconv -i INPUT -filter_complex split=5 OUTPUT
+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
+
+@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 "Video size" section in
+the ffmpeg-utils manual. 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.
+@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
+
+@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 "Video size" section in the ffmpeg-utils manual.
+
+@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 areaFor 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.
+
+@item drop_odd, 1
+Only output even frames, odd frames are dropped, generating a frame with
+unchanged height at half frame rate.
+
+@item drop_even, 2
+Only output odd frames, even frames are dropped, generating a frame with
+unchanged height at half frame rate.
+
+@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.
+
+@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.
+
+@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.
+
+@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.
+@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.
@@ -2602,14 +8599,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
@@ -2617,7 +8611,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
@@ -2625,7 +8619,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
@@ -2633,7 +8627,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
@@ -2642,17 +8636,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.
@@ -2674,6 +8701,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
@@ -2693,16 +8725,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.
@@ -2710,56 +8745,472 @@ 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_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_x
-Set the luma matrix horizontal 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_msize_y
-Set the luma matrix vertical size. It must be an integer between 3
-and 13. The default value is 5.
+Negative values will blur the input video, while positive values will
+sharpen it, a value of zero will disable the effect.
-@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.
+Default value is 1.0.
-@item chroma_msize_x
-Set the chroma matrix horizontal 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_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_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
-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_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
+
+@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.
-# Use the default values with @command{avconv}
-./avconv -i in.avi -vf "unsharp" out.mp4
+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
+
+@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
@@ -2767,56 +9218,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
@@ -2835,6 +9374,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 "Video size" section in the ffmpeg-utils
+manual.
+
@item width
The input video width.
@@ -2842,14 +9386,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:
@@ -2860,131 +9413,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 "Video size" section in the ffmpeg-utils manual.
+
+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
+
+@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
+
+@item
+Specify a more elaborated initial pattern:
+@example
+cellauto=p='@@@@ @@ @@@@':s=100x400:full=0:rule=18
+@end example
+
+@end itemize
-Read a video stream from a movie container.
+@section mandelbrot
-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.
+Generate a Mandelbrot set fractal, and progressively zoom towards the
+point specified with @var{start_x} and @var{start_y}.
-It accepts the following parameters:
+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.
+
+This source accepts the following options:
+
+@table @option
+
+@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".
-@section nullsrc
+@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.
-Null video source: never return images. It is mainly useful as a
-template and to be employed in analysis / debugging tools.
+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
-It accepts a string of the form
-@var{width}:@var{height}:@var{timebase} as an optional parameter.
+Default value is "all", which will cycle through the list of all tests.
+@end table
-@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).
+Some examples:
+@example
+mptestsrc=t=dc_luma
+@end example
-@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".
+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
+"Video size" section in the ffmpeg-utils manual.
@item framerate
The framerate of the generated video. It may be a string of the form
@@ -3000,19 +9694,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 overlayed 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
+"Video size" section in the ffmpeg-utils manual.
+
+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.
@@ -3021,10 +9865,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
+"Video size" section in the ffmpeg-utils manual. The default value is
+"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
@@ -3036,16 +9893,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:
@@ -3054,7 +9916,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
@@ -3068,8 +9954,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
@@ -3078,3 +9969,1370 @@ 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 "Video size"
+section in the ffmpeg-utils manual. 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 "Video size" section in the ffmpeg-utils manual. 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 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
+
+@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 "Video size" section in the ffmpeg-utils manual. 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 "Video size" section in the ffmpeg-utils manual. Default value
+is "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 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 0000000..bca8924
--- /dev/null
+++ b/doc/formats.texi
@@ -0,0 +1,228 @@
+@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 allow to detect 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 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 reproducable 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 allow to detect 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 ae59941..dd19fcc 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -11,12 +11,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 +32,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 +54,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 +62,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 +70,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 +78,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 +86,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 +94,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 +102,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 +110,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
@@ -106,75 +119,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
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 in
-classic AviSynth's CVS repository is not compatible as it has not been
-updated to support AviSynth 2.6. 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} for 32-bit builds and
+@url{http://avisynth.nl, AviSynth 2.5 or 2.6} for 32-bit builds and
@url{http://avs-plus.net, AviSynth+ 0.1} for 32-bit and 64-bit builds.
-The necessary @file{avisynth_c.h} header is the variant in the @file{extras/}
-directory of the @url{https://www.videolan.org/developers/x264.html, x264}
-source tree. For convenience, this header is also available from a
-@url{https://github.com/qyot27/avisynth_headers, temporary repository}
-along with an installation routine.
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
@@ -182,6 +198,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
@@ -190,21 +208,33 @@ 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 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.
@@ -215,9 +245,10 @@ library:
@tab Multimedia format used by Delphine Software games.
@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
@@ -228,6 +259,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
@@ -235,6 +267,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.
@@ -245,15 +279,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
@@ -264,11 +304,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
@@ -276,6 +322,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
@@ -305,6 +354,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
@@ -313,6 +363,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
@@ -323,6 +374,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
@@ -343,7 +395,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
@@ -369,16 +421,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.
@@ -391,14 +446,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 Text files @tab @tab X
@item THP @tab @tab X
@tab Used on the Nintendo GameCube.
@@ -406,10 +462,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
@@ -420,16 +477,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
@@ -439,7 +496,6 @@ 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 BMP @tab X @tab X
@tab Microsoft BMP image
@item BRender PIX @tab @tab X
@@ -450,8 +506,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
@@ -468,7 +523,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
@@ -485,6 +539,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
@@ -500,14 +556,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
@@ -528,13 +582,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
@@ -554,10 +613,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
@@ -579,10 +639,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
@@ -618,6 +678,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
@@ -626,8 +687,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.
@@ -667,9 +728,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
@@ -679,8 +742,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
@@ -699,6 +762,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
@@ -716,6 +781,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
@@ -734,6 +801,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
@@ -748,10 +818,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
@@ -777,19 +850,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
@@ -810,14 +885,16 @@ 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 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
@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
@@ -825,11 +902,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
@@ -843,9 +926,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
@@ -858,9 +940,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
@@ -897,19 +981,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
@@ -929,21 +1018,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
@@ -959,7 +1068,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
@@ -976,18 +1087,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 5a8e2a3..750662a 100644
--- a/doc/git-howto.texi
+++ b/doc/git-howto.texi
@@ -1,9 +1,9 @@
\input texinfo @c -*- texinfo -*-
-@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 +39,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 +53,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,
@@ -85,7 +85,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 +96,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 +127,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 +261,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 +276,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 +299,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
@@ -381,60 +381,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 036b567..0000000
--- 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 8ff64a7..5d2a308 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 allow to access
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,222 @@ 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 specifiying 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 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.
+
+@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}
+
+@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
+
+@end itemize
+
@section dv1394
Linux DV 1394 input device.
@@ -72,18 +275,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 maxiumum 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 +433,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 +461,199 @@ 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.
+
+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
+
+@end itemize
+
+@section libcdio
+
+Audio-CD input device based on cdio.
+
+To enable this input device during configuration you need libcdio
+installed on your system. 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 /dev/sr0,
+you may run the command:
+@example
+ffmpeg -f libcdio -i /dev/sr0 cd.wav
+@end example
+
@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 +662,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 +673,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 +757,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,19 +780,106 @@ 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 usage examples of the video4linux2 devices with avconv and avplay:
-
+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
+Grab and show the input of a video4linux2 device:
@example
-# Grab and show the input of a video4linux2 device.
-avplay -f video4linux2 -framerate 30 -video_size hd720 /dev/video0
+ffplay -f video4linux2 -framerate 30 -video_size hd720 /dev/video0
+@end example
-# 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
+@item
+Grab and record the input of a video4linux2 device, leave the
+frame rate and size as previously set:
+@example
+ffmpeg -f video4linux2 -input_format mjpeg -i /dev/video0 out.mpeg
@end example
+@end itemize
+
+For more information about Video4Linux, check @url{http://linuxtv.org/}.
+
+@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
@@ -291,7 +893,10 @@ other filename will be interpreted as device number 0.
X11 video input device.
-This device allows to capture a region of an X11 display.
+Depends on X11, Xext, and Xfixes. Requires the configure option
+@code{--enable-x11grab}.
+
+This device allows one to capture a region of an X11 display.
The filename passed as input has the syntax:
@example
@@ -309,24 +914,30 @@ default to 0.
Check the X11 documentation (e.g. man X) for more detailed information.
-Use the @file{dpyinfo} program for getting basic information about the
+Use the @command{dpyinfo} 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
@@ -334,29 +945,95 @@ zero) to the edge of region.
For example:
@example
-avconv -f x11grab -follow_mouse centered -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
-# 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
+To follow only when the mouse pointer reaches within 100 pixels to edge:
+@example
+ffmpeg -f x11grab -follow_mouse 100 -framerate 25 -video_size cif -i :0.0 out.mpg
@end example
-@subsection @var{show_region} AVOption
+@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.
-The syntax is:
+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.
+
+For example:
+@example
+ffmpeg -f x11grab -show_region 1 -framerate 25 -video_size cif -i :0.0+10,20 out.mpg
+@end example
+
+With @var{follow_mouse}:
@example
--show_region 1
+ffmpeg -f x11grab -follow_mouse centered -show_region 1 -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 video_size
+Set the video frame size. Default value is @code{vga}.
-For example:
+@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.
+@end table
+
+@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 always
+uyvy422, 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 currently is limited to 2 (stereo).
+
+@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}.
+
+@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
-avconv -f x11grab -show_region 1 -r 25 -s cif -i :0.0+10,20 out.mpg
+ffmpeg -f decklink -list_formats 1 -i 'Intensity Pro'
+@end example
-# With follow_mouse
-avconv -f x11grab -follow_mouse centered -show_region 1 -r 25 -s cif -i :0.0 out.mpg
+@item
+Capture video clip at 1080i50 (format 11):
+@example
+ffmpeg -f decklink -i 'Intensity Pro@@11' -acodec copy -vcodec copy output.avi
@end example
+@end itemize
+
+
@c man end INPUT DEVICES
diff --git a/doc/issue_tracker.txt b/doc/issue_tracker.txt
new file mode 100644
index 0000000..095c04c
--- /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 0000000..618f9f6
--- /dev/null
+++ b/doc/libavcodec.texi
@@ -0,0 +1,48 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 0000000..d5f790b
--- /dev/null
+++ b/doc/libavdevice.texi
@@ -0,0 +1,45 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 84bad29..4f82944 100644
--- a/doc/libavfilter.texi
+++ b/doc/libavfilter.texi
@@ -9,84 +9,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 0000000..85e49cb
--- /dev/null
+++ b/doc/libavformat.texi
@@ -0,0 +1,48 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 0000000..5ec7e84
--- /dev/null
+++ b/doc/libavutil.texi
@@ -0,0 +1,62 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 0000000..383e537
--- /dev/null
+++ b/doc/libswresample.texi
@@ -0,0 +1,70 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 0000000..818e988
--- /dev/null
+++ b/doc/libswscale.texi
@@ -0,0 +1,63 @@
+\input texinfo @c -*- texinfo -*-
+
+@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 cfaf491..b7fc789 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:
@@ -53,7 +53,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 +65,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 0000000..8c6779f
--- /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 9b27b10..2b992fc 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 d71eb09..c6ba604 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,254 @@ 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
-For example to compute the CRC of each decoded frame in the input, and
-store it in the file @file{out.crc}:
+@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 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 one or more segment files. The output filename
+specifies the playlist filename.
-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.
+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_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}.
@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 +329,91 @@ 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
-@table @option
-@item -start_number @var{number}
-Start the sequence from @var{number}.
+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.
-@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.
+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
+Start the sequence from the specified number. Default value is 1. Must
+be a non-negative number.
+
+@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
-
-@table @option
+@item stereo_mode
+Set stereo 3D video layout of two views in a single video track.
-@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 +449,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 +471,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 +518,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 +537,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 +571,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 +591,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 +637,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 +658,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
@@ -428,20 +681,49 @@ Set the service_id (default 0x0001) also known as program in DVB.
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_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 +741,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 +764,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 wihout 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
@@ -506,44 +795,397 @@ situations, giving a small seek granularity at the cost of additional container
overhead.
@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
+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}.
-Every segment starts with a video keyframe, if a video stream is present.
+@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.
+
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 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.
+
+@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.
@end table
+@subsection Example
@example
-avconv -i in.mkv -c copy -map 0 -f segment -list out.list out%03d.nut
+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
@c man end MUXERS
diff --git a/doc/nut.texi b/doc/nut.texi
index 042c88a..fee12da 100644
--- a/doc/nut.texi
+++ b/doc/nut.texi
@@ -17,6 +17,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 +134,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 b3dca64..94a4277 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?
@@ -195,7 +195,7 @@ 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 dd7bd64..e68653f 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 d4a6618..ca76492 100644
--- a/doc/platform.texi
+++ b/doc/platform.texi
@@ -1,8 +1,8 @@
\input texinfo @c -*- texinfo -*-
-@settitle Platform Specific information
+@settitle Platform Specific Information
@titlepage
-@center @titlefont{Platform Specific information}
+@center @titlefont{Platform Specific Information}
@end titlepage
@top
@@ -11,7 +11,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 +26,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 +40,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 +59,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 +85,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 or MinGW-w64
+FFmpeg can be built to run natively on Windows using the MinGW or MinGW-w64
toolchains. Install the latest versions of MSYS and MinGW or MinGW-w64 from
@url{http://www.mingw.org/} or @url{http://mingw-w64.sourceforge.net/}.
You can find detailed installation instructions in the download section and
@@ -107,17 +112,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:
@@ -183,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
@@ -203,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
@@ -255,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
@@ -272,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:
@@ -280,7 +286,7 @@ In order to run FATE you will also need the following "Utils" packages:
bc, 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
@@ -290,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
@@ -322,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.
@@ -338,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.
@@ -376,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 aa75a00..ec8d839 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
*/
@@ -113,6 +113,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 4957aff..dc2fdb1 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,11 +14,51 @@ 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.
@@ -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.
+Allow to read from or write to a file.
+
+A file URL can have the form:
+@example
+file:@var{filename}
+@end example
+
+where @var{filename} is the path of the file to read.
-For example to read from a file @file{input.mpeg} with @command{avconv}
+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
-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 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).
+
+Allow to 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
+
+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,6 +267,11 @@ 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.
@@ -138,9 +279,23 @@ Set initial byte offset.
Try to limit the request to bytes preceding this offset.
@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 +313,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 +333,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 +361,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
@@ -227,20 +386,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 +529,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 +581,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
+
+Allow to 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 +676,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 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 +764,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 +804,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 +861,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 +946,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 +980,125 @@ 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:
+subfile,,start,183241728,end,366490624,,:archive.tar
+
@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{microseconds}
+Set listen timeout, expressed in microseconds.
@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 +1106,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 +1124,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 +1139,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 +1186,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 +1212,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 0000000..f9eef03
--- /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 0000000..23d6393
--- /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 0000000..9d5778d
--- /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 89728b5..0000000
--- 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 0000000..6843fda
--- /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 0000000..2d192a3
--- /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 a42637a..c41be2e 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 0000000..75dc0d3
--- /dev/null
+++ b/doc/t2h.pm
@@ -0,0 +1,221 @@
+# 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General 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);
+
+# TOC and Chapter headings link
+set_from_init_file('TOC_LINKS', 1);
+
+# 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>
+ <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);
+
+# 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 e4eb61c..6127dd8 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,14 +156,14 @@ 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)$/) {
@@ -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/;
@@ -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 0000000..0996903
--- /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 0000000..b0455af
--- /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
+@code{'} and @code{\} 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 '\'.
+
+@item
+All characters enclosed between '' are included literally in the
+parsed string. The quote character @code{'} 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 @code{\} 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)
+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 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)
+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.
+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 9782546..0000000
--- 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 0000000..c7923e8
--- /dev/null
+++ b/doc/writing_filters.txt
@@ -0,0 +1,424 @@
+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.
+
+ - cp libavfilter/vf_{edgedetect,foobar}.c
+ - sed -i s/edgedetect/foobar/g -i libavfilter/vf_foobar.c
+ - sed -i s/EdgeDetect/Foobar/g -i 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 tests/lena.pnm -vf foobar foobar.png
+
+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 0000000..1fd0ece
--- /dev/null
+++ b/ffmpeg.c
@@ -0,0 +1,3896 @@
+/*
+ * 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 "libavformat/os_support.h"
+
+#include "libavformat/ffm.h" // not public API
+
+# 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
+
+static void free_input_threads(void);
+
+
+/* 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
+ avformat_network_deinit();
+
+ 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) && 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_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_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);
+ } 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->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;
+ 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 && 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);
+ }
+
+ /* 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 *in_picture)
+{
+ int ret, format_video_sync;
+ AVPacket pkt;
+ AVCodecContext *enc = ost->enc_ctx;
+ AVCodecContext *mux_enc = ost->st->codec;
+ int nb_frames, i;
+ double sync_ipts, delta;
+ double duration = 0;
+ int frame_size = 0;
+ InputStream *ist = NULL;
+
+ if (ost->source_index >= 0)
+ ist = input_streams[ost->source_index];
+
+ if(ist && ist->st->start_time != AV_NOPTS_VALUE && ist->st->first_dts != AV_NOPTS_VALUE && ost->frame_rate.num)
+ duration = 1/(av_q2d(ost->frame_rate) * av_q2d(enc->time_base));
+
+ sync_ipts = in_picture->pts;
+ delta = sync_ipts - ost->sync_opts + duration;
+
+ /* by default, we output a single frame */
+ 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;
+ }
+ }
+
+ 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;
+ 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 (delta < -1.1)
+ nb_frames = 0;
+ else if (delta > 1.1)
+ nb_frames = lrintf(delta);
+ 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);
+ if (nb_frames == 0) {
+ 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, in_picture->pts);
+ return;
+ } else if (nb_frames > 1) {
+ 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 - 1;
+ av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1);
+ }
+
+ /* duplicates frame if needed */
+ for (i = 0; i < nb_frames; i++) {
+ av_init_packet(&pkt);
+ pkt.data = NULL;
+ pkt.size = 0;
+
+ 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. */
+ mux_enc->coded_frame->interlaced_frame = in_picture->interlaced_frame;
+ mux_enc->coded_frame->top_field_first = in_picture->top_field_first;
+ if (mux_enc->coded_frame->interlaced_frame)
+ mux_enc->field_order = mux_enc->coded_frame->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;
+ }
+
+ 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);
+ }
+}
+
+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->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 = 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", av_get_picture_type_char(enc->coded_frame->pict_type));
+ }
+}
+
+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(void)
+{
+ AVFrame *filtered_frame = NULL;
+ int i;
+ int64_t frame_pts;
+
+ /* 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) {
+ 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));
+ }
+ break;
+ }
+ if (ost->finished) {
+ av_frame_unref(filtered_frame);
+ continue;
+ }
+ frame_pts = AV_NOPTS_VALUE;
+ if (filtered_frame->pts != AV_NOPTS_VALUE) {
+ int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time;
+ filtered_frame->pts = 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:
+ filtered_frame->pts = frame_pts;
+ 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 time_base:%d/%d\n",
+ av_ts2str(filtered_frame->pts), av_ts2timestr(filtered_frame->pts, &enc->time_base),
+ enc->time_base.num, enc->time_base.den);
+ }
+
+ do_video_out(of->ctx, ost, filtered_frame);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ filtered_frame->pts = frame_pts;
+ 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, "\n");
+ 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));
+ }
+
+ secs = pts / AV_TIME_BASE;
+ us = 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);
+ 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");
+ else snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ "bitrate=%6.1fkbits/s", 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) {
+ if (print_stats==1 && AV_LOG_INFO > av_log_get_level()) {
+ fprintf(stderr, "%s \r", buf);
+ } else
+ av_log(NULL, AV_LOG_INFO, "%s \r", buf);
+
+ 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_close(progress_avio);
+ progress_avio = NULL;
+ }
+ }
+
+ 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 (!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;
+ AVFormatContext **avc = av_malloc_array(nb_output_files, sizeof(*avc));
+
+ 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);
+ exit_program(1);
+ }
+ 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];
+ 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->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;
+ 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);
+
+ 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;
+ 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;
+ 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)
+ 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->filter && !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];
+ }
+ 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 (ost->filter && !(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;
+ } else {
+ 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;
+ 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;
+ }
+ }
+ }
+ }
+ }
+
+ /* 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");
+ } 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;
+ }
+ }
+
+ 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->codec->codec= ost->enc_ctx->codec;
+
+ // copy timebase while removing common factors
+ ost->st->time_base = av_add_q(ost->enc_ctx->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 = "?";
+
+ if (in_codec) {
+ decoder_name = in_codec->name;
+ in_codec_name = avcodec_descriptor_get(in_codec->id)->name;
+ if (!strcmp(decoder_name, in_codec_name))
+ decoder_name = "native";
+ }
+
+ if (out_codec) {
+ encoder_name = out_codec->name;
+ out_codec_name = avcodec_descriptor_get(out_codec->id)->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();
+ }
+
+ 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);
+ }
+ }
+ }
+ } 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;
+ 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, 0);
+ 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,
+ 8, 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;
+
+ 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();
+
+ if (ret == AVERROR_EOF) {
+ ret = reap_filters();
+ 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();
+}
+
+/*
+ * 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;
+
+ av_log(NULL, AV_LOG_ERROR, "Error while filtering.\n");
+ 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_dict_free(&ost->encoder_opts);
+ av_dict_free(&ost->swr_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
+}
+
+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/avconv.h b/ffmpeg.h
index b932d7e..c456603 100644
--- a/avconv.h
+++ b/ffmpeg.h
@@ -1,28 +1,29 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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 AVCONV_H
-#define AVCONV_H
+#ifndef FFMPEG_H
+#define FFMPEG_H
#include "config.h"
#include <stdint.h>
#include <stdio.h>
+#include <signal.h>
#if HAVE_PTHREADS
#include <pthread.h>
@@ -39,14 +40,22 @@
#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,
@@ -73,12 +82,10 @@ typedef struct StreamMap {
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 {
+ int file_idx, stream_idx, channel_idx; // input
+ int ofile_idx, ostream_idx; // output
+} AudioChannelMap;
typedef struct OptionsContext {
OptionGroup *g;
@@ -117,9 +124,8 @@ typedef struct OptionsContext {
/* 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;
+ 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;
@@ -129,6 +135,7 @@ typedef struct OptionsContext {
int chapters_input_file;
int64_t recording_time;
+ int64_t stop_time;
uint64_t limit_filesize;
float mux_preload;
float mux_max_delay;
@@ -167,6 +174,8 @@ typedef struct OptionsContext {
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;
@@ -175,14 +184,28 @@ typedef struct OptionsContext {
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;
} OptionsContext;
typedef struct InputFilter {
@@ -207,6 +230,7 @@ typedef struct FilterGraph {
const char *graph_desc;
AVFilterGraph *graph;
+ int reconfiguration;
InputFilter **inputs;
int nb_inputs;
@@ -218,7 +242,11 @@ 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' */
+ 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;
@@ -226,15 +254,23 @@ typedef struct InputStream {
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 */
+ * several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */
int64_t next_dts;
- /* dts of the last packet read for this stream */
- int64_t last_dts;
- PtsCorrectionContext pts_ctx;
+ 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 resample_height;
int resample_width;
@@ -245,11 +281,29 @@ typedef struct InputStream {
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;
@@ -277,25 +331,42 @@ 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 */
+ 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 */
int64_t recording_time;
- int nb_streams; /* number of stream that avconv is aware of; may be different
+ 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 finished; /* the thread has exited */
+ int non_blocking; /* reading packets from the thread should not block */
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;
+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 */
@@ -305,7 +376,6 @@ typedef struct OutputStream {
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
@@ -324,29 +394,41 @@ typedef struct OutputStream {
int force_fps;
int top_field_first;
- float frame_aspect_ratio;
+ 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;
- int finished; /* no more packets should be written for this stream */
+ 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;
- enum AVPixelFormat pix_fmts[2];
+ int keep_pix_fmt;
AVCodecParserContext *parser;
@@ -364,9 +446,9 @@ 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;
+ 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;
@@ -388,44 +470,59 @@ extern char *vstats_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 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 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 reset_options(OptionsContext *o);
+
+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 avconv_parse_options(int argc, char **argv);
+int ffmpeg_parse_options(int argc, char **argv);
int vdpau_init(AVCodecContext *s);
int dxva2_init(AVCodecContext *s);
int vda_init(AVCodecContext *s);
-#endif /* AVCONV_H */
+#endif /* FFMPEG_H */
diff --git a/avconv_dxva2.c b/ffmpeg_dxva2.c
index 4457a21..3c91d26 100644
--- a/avconv_dxva2.c
+++ b/ffmpeg_dxva2.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 @@
#include <d3d9.h>
#include <dxva2api.h>
-#include "avconv.h"
+#include "ffmpeg.h"
#include "libavcodec/dxva2.h"
@@ -121,9 +121,10 @@ static void dxva2_destroy_decoder(AVCodecContext *s)
{
InputStream *ist = s->opaque;
DXVA2Context *ctx = ist->hwaccel_ctx;
+ int i;
if (ctx->surfaces) {
- for (int i = 0; i < ctx->num_surfaces; i++) {
+ for (i = 0; i < ctx->num_surfaces; i++) {
if (ctx->surfaces[i])
IDirect3DSurface9_Release(ctx->surfaces[i]);
}
diff --git a/avconv_filter.c b/ffmpeg_filter.c
index e54da56..0555cf6 100644
--- a/avconv_filter.c
+++ b/ffmpeg_filter.c
@@ -1,39 +1,149 @@
/*
- * avconv filter configuration
+ * ffmpeg filter configuration
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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 "avconv.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/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) \
@@ -49,7 +159,7 @@ static char *choose_ ## var ## s(OutputStream *ost) \
int len; \
\
if (avio_open_dyn_buf(&s) < 0) \
- exit(1); \
+ exit_program(1); \
\
for (p = ost->enc->supported_list; *p != none; p++) { \
get_name(*p); \
@@ -62,8 +172,8 @@ static char *choose_ ## var ## s(OutputStream *ost) \
return NULL; \
}
-DEF_CHOOSE_FORMAT(enum AVPixelFormat, pix_fmt, pix_fmts, AV_PIX_FMT_NONE,
- GET_PIX_FMT_NAME)
+// 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)
@@ -79,12 +189,12 @@ FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
FilterGraph *fg = av_mallocz(sizeof(*fg));
if (!fg)
- exit(1);
+ 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(1);
+ exit_program(1);
fg->outputs[0]->ost = ost;
fg->outputs[0]->graph = fg;
@@ -92,7 +202,7 @@ FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
GROW_ARRAY(fg->inputs, fg->nb_inputs);
if (!(fg->inputs[0] = av_mallocz(sizeof(*fg->inputs[0]))))
- exit(1);
+ exit_program(1);
fg->inputs[0]->ist = ist;
fg->inputs[0]->graph = fg;
@@ -115,7 +225,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
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);
+ exit_program(1);
}
if (in->name) {
@@ -125,14 +235,17 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
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",
+ av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtergraph description %s.\n",
file_idx, fg->graph_desc);
- exit(1);
+ exit_program(1);
}
s = input_files[file_idx]->ctx;
for (i = 0; i < s->nb_streams; i++) {
- if (s->streams[i]->codec->codec_type != type)
+ 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];
@@ -142,7 +255,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
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);
+ exit_program(1);
}
ist = input_streams[input_files[file_idx]->ist_index + st->index];
} else {
@@ -156,18 +269,18 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
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);
+ exit_program(1);
}
}
av_assert0(ist);
ist->discard = 0;
- ist->decoding_needed = 1;
+ 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(1);
+ exit_program(1);
fg->inputs[fg->nb_inputs - 1]->ist = ist;
fg->inputs[fg->nb_inputs - 1]->graph = fg;
@@ -201,11 +314,11 @@ static int insert_trim(int64_t start_time, int64_t duration,
return AVERROR(ENOMEM);
if (duration != INT64_MAX) {
- ret = av_opt_set_double(ctx, "duration", (double)duration / 1e6,
+ ret = av_opt_set_int(ctx, "durationi", duration,
AV_OPT_SEARCH_CHILDREN);
}
if (ret >= 0 && start_time != AV_NOPTS_VALUE) {
- ret = av_opt_set_double(ctx, "start", (double)start_time / 1e6,
+ ret = av_opt_set_int(ctx, "starti", start_time,
AV_OPT_SEARCH_CHILDREN);
}
if (ret < 0) {
@@ -241,6 +354,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
ret = avfilter_graph_create_filter(&ofilter->filter,
avfilter_get_by_name("buffersink"),
name, NULL, NULL, fg->graph);
+
if (ret < 0)
return ret;
@@ -281,7 +395,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
pad_idx = 0;
}
- if (ost->frame_rate.num) {
+ if (ost->frame_rate.num && 0) {
AVFilterContext *fps;
char args[255];
@@ -326,13 +440,47 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
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);
@@ -343,18 +491,17 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
if (sample_fmts || sample_rates || channel_layouts) {
AVFilterContext *format;
char args[256];
- int len = 0;
+ args[0] = 0;
if (sample_fmts)
- len += snprintf(args + len, sizeof(args) - len, "sample_fmts=%s:",
+ av_strlcatf(args, sizeof(args), "sample_fmts=%s:",
sample_fmts);
if (sample_rates)
- len += snprintf(args + len, sizeof(args) - len, "sample_rates=%s:",
+ av_strlcatf(args, sizeof(args), "sample_rates=%s:",
sample_rates);
if (channel_layouts)
- len += snprintf(args + len, sizeof(args) - len, "channel_layouts=%s:",
+ av_strlcatf(args, sizeof(args), "channel_layouts=%s:",
channel_layouts);
- args[len - 1] = 0;
av_freep(&sample_fmts);
av_freep(&sample_rates);
@@ -376,6 +523,27 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
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,
@@ -397,7 +565,7 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
AVIOContext *pb; \
\
if (avio_open_dyn_buf(&pb) < 0) \
- exit(1); \
+ exit_program(1); \
\
avio_printf(pb, "%s", ctx->filter->name); \
if (nb_pads > 1) \
@@ -418,6 +586,43 @@ int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOu
}
}
+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)
{
@@ -427,22 +632,46 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
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;
- char args[255], name[255];
+ AVBPrint args;
+ char name[255];
int ret, pad_idx = 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;
- 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);
+ 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, NULL, fg->graph)) < 0)
+ args.str, NULL, fg->graph)) < 0)
return ret;
last_filter = ifilter->filter;
@@ -463,6 +692,23 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
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);
ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
@@ -482,72 +728,87 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
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];
+ AVBPrint args;
+ char 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,
+ 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),
- ist->dec_ctx->channel_layout);
+ 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, NULL,
+ 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) {
- 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;
+ 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);
+ }
- ret = avfilter_link(last_filter, 0, async, 0);
- if (ret < 0)
- return ret;
+// 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);
+// }
- last_filter = async;
- }
if (audio_volume != 256) {
- AVFilterContext *volume;
+ char args[256];
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(args, sizeof(args), "%f", audio_volume / 256.);
+ AUTO_INSERT_FILTER_INPUT("-vol", "volume", args);
}
snprintf(name, sizeof(name), "trim for input stream %d:%d",
@@ -569,6 +830,12 @@ static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
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);
@@ -595,6 +862,15 @@ int configure_filtergraph(FilterGraph *fg)
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))) {
@@ -603,6 +879,10 @@ int configure_filtergraph(FilterGraph *fg)
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)
@@ -618,8 +898,11 @@ int configure_filtergraph(FilterGraph *fg)
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)
+ 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) {
@@ -636,7 +919,7 @@ int configure_filtergraph(FilterGraph *fg)
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);
+ exit_program(1);
fg->outputs[fg->nb_outputs - 1]->graph = fg;
fg->outputs[fg->nb_outputs - 1]->out_tmp = cur;
cur = cur->next;
@@ -644,6 +927,17 @@ int configure_filtergraph(FilterGraph *fg)
}
}
+ 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;
}
diff --git a/avconv_opt.c b/ffmpeg_opt.c
index 2d06912..77ef0c4 100644
--- a/avconv_opt.c
+++ b/ffmpeg_opt.c
@@ -1,26 +1,26 @@
/*
- * avconv option parsing
+ * ffmpeg option parsing
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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 "avconv.h"
+#include "ffmpeg.h"
#include "cmdutils.h"
#include "libavformat/avformat.h"
@@ -53,6 +53,16 @@
}\
}
+#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 },
@@ -70,25 +80,34 @@ char *vstats_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;
+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 copy_tb = 1;
+int start_at_zero = 0;
+int copy_tb = -1;
+int debug_ts = 0;
int exit_on_error = 0;
-int print_stats = 1;
+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 file_skip = 0;
-static int video_discard = 0;
-static int intra_dc_precision = 8;
-static int using_stdin = 0;
+static int no_file_overwrite = 0;
+static int do_psnr = 0;
static int input_sync;
+static int override_ffserver = 0;
static void uninit_options(OptionsContext *o)
{
@@ -117,14 +136,16 @@ static void uninit_options(OptionsContext *o)
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->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;
@@ -151,28 +172,25 @@ static AVDictionary *strip_specifiers(AVDictionary *dict)
return ret;
}
-static double parse_frame_aspect_ratio(const char *arg)
+static int opt_sameq(void *optctx, const char *opt, const char *arg)
{
- int x = 0, y = 0;
- double ar = 0;
- const char *p;
- char *end;
+ 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);
+}
- 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);
+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);
+}
- if (!ar) {
- av_log(NULL, AV_LOG_FATAL, "Incorrect aspect ratio specification.\n");
- exit_program(1);
- }
- return ar;
+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)
@@ -204,7 +222,7 @@ 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;
+ int sync_file_idx = -1, sync_stream_idx = 0;
char *p, *sync;
char *map;
@@ -302,6 +320,65 @@ static int opt_attach(void *optctx, const char *opt, const char *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;
+}
+
/**
* Parse a metadata specifier passed as 'arg' parameter.
* @param arg metadata string to parse
@@ -339,7 +416,7 @@ static void parse_meta_type(char *arg, char *type, int *index, const char **stre
static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
{
AVDictionary **meta_in = NULL;
- AVDictionary **meta_out;
+ AVDictionary **meta_out = NULL;
int i, ret = 0;
char type_in, type_out;
const char *istream_spec = NULL, *ostream_spec = NULL;
@@ -348,6 +425,16 @@ static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFor
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')
@@ -416,6 +503,21 @@ static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFor
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=%FT%T%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;
@@ -471,6 +573,8 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
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);
@@ -497,6 +601,19 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
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");
@@ -511,6 +628,12 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
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;
@@ -523,6 +646,9 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
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"))
@@ -560,6 +686,8 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
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;
@@ -569,7 +697,19 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
break;
case AVMEDIA_TYPE_DATA:
- case AVMEDIA_TYPE_SUBTITLE:
+ 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;
@@ -581,25 +721,27 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
static void assert_file_overwrite(const char *filename)
{
- if (file_overwrite && file_skip) {
+ if (file_overwrite && no_file_overwrite) {
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) {
+ 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()) {
- fprintf(stderr, "Not overwriting - exiting\n");
+ av_log(NULL, AV_LOG_FATAL, "Not overwriting - exiting\n");
exit_program(1);
}
+ term_init();
}
else {
- fprintf(stderr,"File '%s' already exists. Exiting.\n", filename);
+ av_log(NULL, AV_LOG_FATAL, "File '%s' already exists. Exiting.\n", filename);
exit_program(1);
}
}
@@ -645,11 +787,14 @@ static int open_input_file(OptionsContext *o, const char *filename)
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
+ char * video_codec_name = NULL;
+ char * audio_codec_name = NULL;
+ char *subtitle_codec_name = NULL;
+ int scan_all_pmts_set = 0;
if (o->format) {
if (!(file_iformat = av_find_input_format(o->format))) {
@@ -661,8 +806,8 @@ static int open_input_file(OptionsContext *o, const char *filename)
if (!strcmp(filename, "-"))
filename = "pipe:";
- using_stdin |= !strncmp(filename, "pipe:", 5) ||
- !strcmp(filename, "/dev/stdin");
+ stdin_interaction &= strncmp(filename, "pipe:", 5) &&
+ strcmp(filename, "/dev/stdin");
/* get default parameters from command line */
ic = avformat_alloc_context();
@@ -671,8 +816,7 @@ static int open_input_file(OptionsContext *o, const char *filename)
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);
+ 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
@@ -681,9 +825,7 @@ static int open_input_file(OptionsContext *o, const char *filename)
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);
+ 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) {
@@ -702,15 +844,40 @@ static int open_input_file(OptionsContext *o, const char *filename)
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");
+
+ 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;
+
+ 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));
+
ic->flags |= AVFMT_FLAG_NONBLOCK;
ic->interrupt_callback = int_cb;
- /* open the input file with generic libav function */
+ 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 */
@@ -726,8 +893,10 @@ static int open_input_file(OptionsContext *o, const char *filename)
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);
+ if (ic->nb_streams == 0) {
+ avformat_close_input(&ic);
+ exit_program(1);
+ }
}
timestamp = (o->start_time == AV_NOPTS_VALUE) ? 0 : o->start_time;
@@ -737,7 +906,7 @@ static int open_input_file(OptionsContext *o, const char *filename)
/* if seeking requested, we execute it */
if (o->start_time != AV_NOPTS_VALUE) {
- ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
+ ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, 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);
@@ -760,7 +929,8 @@ static int open_input_file(OptionsContext *o, const char *filename)
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->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;
@@ -779,8 +949,13 @@ static int open_input_file(OptionsContext *o, const char *filename)
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)
+ 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,
@@ -878,7 +1053,7 @@ static void choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *
}
}
-static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type)
+static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type, int source_index)
{
OutputStream *ost;
AVStream *st = avformat_new_stream(oc, NULL);
@@ -886,6 +1061,7 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
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");
@@ -949,6 +1125,16 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
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) {
@@ -986,9 +1172,18 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
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->pix_fmts[0] = ost->pix_fmts[1] = AV_PIX_FMT_NONE;
+ 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;
@@ -1044,68 +1239,99 @@ 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) {
+ 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 (filter_script)
- return read_file(filter_script);
- else if (filter)
- return av_strdup(filter);
+ 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 OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
+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_aspect_ratio = NULL;
+ char *frame_rate = NULL, *frame_aspect_ratio = NULL;
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO);
+ 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)
- ost->frame_aspect_ratio = parse_frame_aspect_ratio(frame_aspect_ratio);
+ 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_rate = NULL, *frame_size = 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_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);
}
+ 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))) {
@@ -1114,6 +1340,16 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
}
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))) {
@@ -1131,6 +1367,7 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
av_log(NULL, AV_LOG_FATAL, "error parsing rc_override\n");
exit_program(1);
}
+ /* FIXME realloc failure */
video_enc->rc_override =
av_realloc(video_enc->rc_override,
sizeof(RcOverride) * (i + 1));
@@ -1148,15 +1385,20 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
if (p) p++;
}
video_enc->rc_override_count = i;
- video_enc->intra_dc_precision = intra_dc_precision - 8;
+
+ 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) {
+ if (do_pass & 1) {
video_enc->flags |= CODEC_FLAG_PASS1;
- } else {
+ 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);
}
}
@@ -1182,21 +1424,28 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
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)
+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);
+ 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;
@@ -1211,19 +1460,54 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
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)
+static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
{
OutputStream *ost;
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA);
+ 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);
@@ -1232,24 +1516,38 @@ static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc)
return ost;
}
-static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc)
+static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
{
- OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT);
+ 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)
+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);
+ 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;
}
@@ -1270,7 +1568,7 @@ static int opt_streamid(void *optctx, const char *opt, const char *arg)
exit_program(1);
}
*p++ = '\0';
- idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, INT_MAX);
+ 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;
@@ -1283,7 +1581,7 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata)
AVChapter **tmp;
int i;
- tmp = av_realloc(os->chapters, sizeof(*os->chapters) * (is->nb_chapters + os->nb_chapters));
+ tmp = av_realloc_f(os->chapters, is->nb_chapters + os->nb_chapters, sizeof(*os->chapters));
if (!tmp)
return AVERROR(ENOMEM);
os->chapters = tmp;
@@ -1319,6 +1617,55 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata)
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;
+ AVCodecContext *avctx;
+
+ 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);
+ }
+ ost = new_output_stream(o, s, codec->type, -1);
+ st = ost->st;
+ avctx = st->codec;
+ ost->enc = codec;
+
+ // FIXME: a more elegant solution is needed
+ memcpy(st, ic->streams[i], sizeof(AVStream));
+ st->cur_dts = 0;
+ st->info = av_malloc(sizeof(*st->info));
+ memcpy(st->info, ic->streams[i]->info, sizeof(*st->info));
+ st->codec= avctx;
+ avcodec_copy_context(st->codec, ic->streams[i]->codec);
+
+ 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 (ost->enc_ctx->priv_data) {
+ av_opt_free(ost->enc_ctx->priv_data);
+ av_freep(&ost->enc_ctx->priv_data);
+ }
+ }
+
+ avformat_close_input(&ic);
+ return err;
+}
+
static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
AVFormatContext *oc)
{
@@ -1326,8 +1673,8 @@ static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
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;
+ 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");
@@ -1346,6 +1693,18 @@ static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
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);
@@ -1380,6 +1739,21 @@ static int open_output_file(OptionsContext *o, const char *filename)
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)
@@ -1396,33 +1770,18 @@ static int open_output_file(OptionsContext *o, const char *filename)
if (!strcmp(filename, "-"))
filename = "pipe:";
- oc = avformat_alloc_context();
+ err = avformat_alloc_output_context2(&oc, NULL, o->format, filename);
if (!oc) {
- print_error(filename, AVERROR(ENOMEM));
+ print_error(filename, err);
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;
+ file_oformat= oc->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++) {
@@ -1443,33 +1802,73 @@ static int open_output_file(OptionsContext *o, const char *filename)
}
}
- 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;\
+ /* 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 && oc->oformat->video_codec != AV_CODEC_ID_NONE) {
+ 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 &&
- ist->st->codec->width * ist->st->codec->height > area) {
- area = ist->st->codec->width * ist->st->codec->height;
+ new_area > area) {
+ if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ continue;
+ area = new_area;
idx = i;
}
}
- NEW_STREAM(video, idx);
+ if (idx >= 0)
+ new_video_stream(o, oc, idx);
}
/* audio: most channels */
- if (!o->audio_disable && oc->oformat->audio_codec != AV_CODEC_ID_NONE) {
+ 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];
@@ -1479,15 +1878,36 @@ static int open_output_file(OptionsContext *o, const char *filename)
idx = i;
}
}
- NEW_STREAM(audio, idx);
+ if (idx >= 0)
+ new_audio_stream(o, oc, idx);
}
/* subtitles: pick first */
- if (!o->subtitle_disable && oc->oformat->subtitle_codec != AV_CODEC_ID_NONE) {
+ 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) {
- NEW_STREAM(subtitle, i);
- break;
+ 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;
+ }
}
}
/* do something with data? */
@@ -1516,29 +1936,34 @@ static int open_output_file(OptionsContext *o, const char *filename)
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);
+ "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); 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;
+ 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;
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;
}
}
}
@@ -1567,18 +1992,29 @@ loop_end:
}
avio_read(pb, attachment, len);
- ost = new_attachment_stream(o, oc);
+ ost = new_attachment_stream(o, oc, -1);
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;
+ ost->finished = 1;
+ ost->enc_ctx->extradata = attachment;
+ ost->enc_ctx->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);
}
+ 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++) {
@@ -1593,8 +2029,13 @@ loop_end:
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)
+ 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,
@@ -1603,6 +2044,10 @@ loop_end:
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 "
@@ -1631,15 +2076,13 @@ loop_end:
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) {
- uint8_t buf[64];
- snprintf(buf, sizeof(buf), "%d", (int)(o->mux_preload*AV_TIME_BASE));
- av_dict_set(&of->opts, "preload", buf, 0);
+ 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);
- oc->flags |= AVFMT_FLAG_NONBLOCK;
/* copy metadata */
for (i = 0; i < o->nb_metadata_map; i++) {
@@ -1676,9 +2119,13 @@ loop_end:
!o->metadata_chapters_manual);
/* copy global metadata by default */
- if (!o->metadata_global_manual && nb_input_files)
+ 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;
@@ -1686,6 +2133,8 @@ loop_end:
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);
}
/* process manually set metadata */
@@ -1693,7 +2142,7 @@ loop_end:
AVDictionary **m;
char type, *val;
const char *stream_spec;
- int index = 0, j, ret;
+ int index = 0, j, ret = 0;
val = strchr(o->metadata[i].u.str, '=');
if (!val) {
@@ -1793,7 +2242,7 @@ static int opt_target(void *optctx, const char *opt, const char *arg)
parse_option(o, "r", frame_rates[norm], options);
opt_default(NULL, "g", norm == PAL ? "15" : "18");
- opt_default(NULL, "b", "1150000");
+ opt_default(NULL, "b:v", "1150000");
opt_default(NULL, "maxrate", "1150000");
opt_default(NULL, "minrate", "1150000");
opt_default(NULL, "bufsize", "327680"); // 40*1024*8;
@@ -1803,7 +2252,7 @@ static int opt_target(void *optctx, const char *opt, const char *arg)
parse_option(o, "ac", "2", options);
opt_default(NULL, "packetsize", "2324");
- opt_default(NULL, "muxrate", "3528"); // 2352 * 75 / 50;
+ 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
@@ -1819,14 +2268,14 @@ static int opt_target(void *optctx, const char *opt, const char *arg)
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", "2040000");
+ opt_default(NULL, "b:v", "2040000");
opt_default(NULL, "maxrate", "2516000");
opt_default(NULL, "minrate", "0"); // 1145000;
opt_default(NULL, "bufsize", "1835008"); // 224*1024*8;
- opt_default(NULL, "flags", "+scan_offset");
-
+ opt_default(NULL, "scan_offset", "1");
opt_default(NULL, "b:a", "224000");
parse_option(o, "ar", "44100", options);
@@ -1841,15 +2290,16 @@ static int opt_target(void *optctx, const char *opt, const char *arg)
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", "6000000");
+ opt_default(NULL, "b:v", "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, "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);
@@ -1871,8 +2321,8 @@ static int opt_target(void *optctx, const char *opt, const char *arg)
return AVERROR(EINVAL);
}
- av_dict_copy(&o->g->codec_opts, codec_opts, 0);
- av_dict_copy(&o->g->format_opts, format_opts, 0);
+ 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;
}
@@ -1913,22 +2363,124 @@ static int opt_data_frames(void *optctx, const char *opt, const char *arg)
return parse_option(o, "frames:d", arg, options);
}
-static int opt_video_tag(void *optctx, const char *opt, const char *arg)
+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;
- return parse_option(o, "tag:v", arg, options);
+ 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_audio_tag(void *optctx, const char *opt, const char *arg)
+static int opt_old2new(void *optctx, const char *opt, const char *arg)
{
OptionsContext *o = optctx;
- return parse_option(o, "tag:a", arg, options);
+ 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_subtitle_tag(void *optctx, const char *opt, const char *arg)
+static int opt_bitrate(void *optctx, const char *opt, const char *arg)
{
OptionsContext *o = optctx;
- return parse_option(o, "tag:s", arg, options);
+
+ 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)
@@ -1948,12 +2500,24 @@ 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;
@@ -1969,7 +2533,7 @@ static int opt_channel_layout(void *optctx, const char *opt, const char *arg)
return AVERROR(EINVAL);
}
snprintf(layout_str, sizeof(layout_str), "%"PRIu64, layout);
- ret = opt_default(NULL, opt, layout_str);
+ ret = opt_default_new(o, opt, layout_str);
if (ret < 0)
return ret;
@@ -2082,16 +2646,19 @@ void show_help_default(const char *opt, const char *arg)
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);
- show_help_children(avfilter_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM);
+#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)
{
- printf("Hyper fast Audio and Video encoder\n");
- printf("usage: %s [options] [[infile options] -i infile]... {[outfile options] outfile}...\n", program_name);
- printf("\n");
+ 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 {
@@ -2137,7 +2704,7 @@ static int open_files(OptionGroupList *l, const char *inout,
return 0;
}
-int avconv_parse_options(int argc, char **argv)
+int ffmpeg_parse_options(int argc, char **argv)
{
OptionParseContext octx;
uint8_t error[128];
@@ -2183,6 +2750,23 @@ fail:
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 */
@@ -2192,7 +2776,7 @@ const OptionDef options[] = {
"force format", "fmt" },
{ "y", OPT_BOOL, { &file_overwrite },
"overwrite output files" },
- { "n", OPT_BOOL, { &file_skip },
+ { "n", OPT_BOOL, { &no_file_overwrite },
"never overwrite output files" },
{ "c", HAS_ARG | OPT_STRING | OPT_SPEC |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(codec_names) },
@@ -2207,6 +2791,8 @@ const OptionDef options[] = {
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",
@@ -2218,6 +2804,8 @@ const OptionDef options[] = {
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 |
@@ -2232,13 +2820,21 @@ const OptionDef options[] = {
{ "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, { .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 record", "number" },
+ "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 },
@@ -2259,35 +2855,50 @@ const OptionDef options[] = {
"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" },
+ { "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 record", "number" },
+ "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_DOUBLE |
- OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(qscale) },
+ { "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 filterchain", "filter_list" },
+ "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 },
@@ -2298,14 +2909,21 @@ const OptionDef options[] = {
{ "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", "" },
/* 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" },
+ "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_STRING | OPT_SPEC |
+ { "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 |
@@ -2314,40 +2932,53 @@ const OptionDef options[] = {
{ "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) },
+ { "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" },
- { "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" },
+ { "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 or 2)", "n" },
+ "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 },
- "video filters", "filter list" },
+ "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_OUTPUT, { .off = OFFSET(top_field_first) },
+ OPT_INPUT | 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 },
+ OPT_OUTPUT, { .func_arg = opt_old2new },
"force video tag/fourcc", "fourcc/tag" },
{ "qphist", OPT_VIDEO | OPT_BOOL | OPT_EXPERT , { &qp_hist },
"show QP histogram" },
@@ -2360,16 +2991,23 @@ const OptionDef options[] = {
{ "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
/* 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" },
+ "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 |
@@ -2378,13 +3016,13 @@ const OptionDef options[] = {
{ "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) },
+ { "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_audio_tag },
+ 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" },
@@ -2395,17 +3033,27 @@ const OptionDef options[] = {
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" },
+ "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_OUTPUT, { .off = OFFSET(subtitle_disable) },
+ { "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_subtitle_tag }
+ { "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 */
@@ -2413,13 +3061,29 @@ const OptionDef options[] = {
"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", "" },
{ "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/avconv_vda.c b/ffmpeg_vda.c
index 40f87c4..b9f0975 100644
--- a/avconv_vda.c
+++ b/ffmpeg_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
*/
@@ -20,7 +20,7 @@
#include "libavcodec/vda.h"
#include "libavutil/imgutils.h"
-#include "avconv.h"
+#include "ffmpeg.h"
typedef struct VDAContext {
AVFrame *tmp_frame;
diff --git a/avconv_vdpau.c b/ffmpeg_vdpau.c
index 37b50f6..14a3773 100644
--- a/avconv_vdpau.c
+++ b/ffmpeg_vdpau.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
*/
@@ -23,7 +23,7 @@
#include <X11/Xlib.h>
-#include "avconv.h"
+#include "ffmpeg.h"
#include "libavcodec/vdpau.h"
@@ -42,6 +42,11 @@ typedef struct VDPAUContext {
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;
@@ -54,6 +59,8 @@ typedef struct VDPAUContext {
VdpYCbCrFormat vdpau_format;
} VDPAUContext;
+int vdpau_api_ver = 2;
+
static void vdpau_uninit(AVCodecContext *s)
{
InputStream *ist = s->opaque;
@@ -63,6 +70,9 @@ static void vdpau_uninit(AVCodecContext *s)
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);
@@ -184,6 +194,7 @@ 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;
@@ -232,6 +243,11 @@ do {
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);
@@ -260,6 +276,14 @@ do {
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;
@@ -277,10 +301,56 @@ fail:
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)
diff --git a/ffplay.c b/ffplay.c
new file mode 100644
index 0000000..f79161d
--- /dev/null
+++ b/ffplay.c
@@ -0,0 +1,3854 @@
+/*
+ * 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/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 flushed;
+ int packet_pending;
+ SDL_cond *empty_queue_cond;
+ int64_t start_pts;
+ AVRational start_pts_tb;
+ int64_t next_pts;
+ AVRational next_pts_tb;
+} Decoder;
+
+typedef struct VideoState {
+ SDL_Thread *read_tid;
+ SDL_Thread *video_tid;
+ SDL_Thread *audio_tid;
+ AVInputFormat *iformat;
+ int no_background;
+ 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;
+
+ SDL_Thread *subtitle_tid;
+ 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;
+
+ 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 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 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;
+
+ d->flushed = 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->flushed = 1;
+ 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 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));
+ }
+ {
+ 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.pts_drift - is->vidclk.pts;
+ 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;
+
+ /* 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_dlog(NULL, "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) {
+ AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0);
+ if (rotate_tag && *rotate_tag->value && strcmp(rotate_tag->value, "0")) {
+ if (!strcmp(rotate_tag->value, "90")) {
+ INSERT_FILT("transpose", "clock");
+ } else if (!strcmp(rotate_tag->value, "180")) {
+ INSERT_FILT("hflip", NULL);
+ INSERT_FILT("vflip", NULL);
+ } else if (!strcmp(rotate_tag->value, "270")) {
+ INSERT_FILT("transpose", "cclock");
+ } else {
+ char rotate_buf[64];
+ snprintf(rotate_buf, sizeof(rotate_buf), "%s*PI/180", rotate_tag->value);
+ 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 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;
+#endif
+
+ 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_dlog(NULL, "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;
+ }
+
+ 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];
+
+ packet_queue_start(&is->audioq);
+ 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;
+ }
+ is->audio_tid = SDL_CreateThread(audio_thread, is);
+ SDL_PauseAudio(0);
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ is->video_stream = stream_index;
+ is->video_st = ic->streams[stream_index];
+
+ packet_queue_start(&is->videoq);
+ decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);
+ is->video_tid = SDL_CreateThread(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];
+
+ packet_queue_start(&is->subtitleq);
+ decoder_init(&is->subdec, avctx, &is->subtitleq, is->continue_read_thread);
+ 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);
+ frame_queue_signal(&is->sampq);
+ SDL_CloseAudio();
+ SDL_WaitThread(is->audio_tid, NULL);
+
+ decoder_destroy(&is->auddec);
+ packet_queue_flush(&is->audioq);
+ 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:
+ packet_queue_abort(&is->videoq);
+
+ /* note: we also signal this mutex to make sure we deblock the
+ video thread in all cases */
+ frame_queue_signal(&is->pictq);
+
+ SDL_WaitThread(is->video_tid, NULL);
+
+ decoder_destroy(&is->viddec);
+ packet_queue_flush(&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 */
+ frame_queue_signal(&is->subpq);
+
+ SDL_WaitThread(is->subtitle_tid, NULL);
+
+ decoder_destroy(&is->subdec);
+ packet_queue_flush(&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;
+ }
+}
+
+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;
+ int eof = 0;
+ 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;
+
+ 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;
+
+ ic = avformat_alloc_context();
+ 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);
+
+ 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 && !subtitle_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);
+ }
+
+ 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;
+ 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)) && !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);
+ 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 {
+ 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_in_play_range = duration == AV_NOPTS_VALUE ||
+ (pkt->pts - (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 (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);
+ }
+ 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_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", "" },
+ { "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 0000000..24ecafd
--- /dev/null
+++ b/ffprobe.c
@@ -0,0 +1,3177 @@
+/*
+ * 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/hash.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/dict.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 {
+ 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_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_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, { -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, -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_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
+
+ StringValidation 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);
+}
+
+#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 {
+ 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 {
+ 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 {
+ 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 (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);
+ 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("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");
+ }
+ 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);
+
+ 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;
+ }
+ 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;
+
+ if ((err = avformat_find_stream_info(fmt_ctx, opts)) < 0) {
+ print_error(filename, err);
+ return err;
+ }
+ for (i = 0; i < orig_nb_streams; i++)
+ av_dict_free(&opts[i]);
+ av_freep(&opts);
+
+ 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;
+ 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)
+ return ret;
+
+#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:
+ 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("build_date", __DATE__);
+ print_str("build_time", __TIME__);
+ 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 0000000..ea2a2ae
--- /dev/null
+++ b/ffserver.c
@@ -0,0 +1,3749 @@
+/*
+ * 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,
+};
+
+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 int http_parse_request(HTTPContext *c);
+static int http_send_data(HTTPContext *c);
+static void compute_status(HTTPContext *c);
+static int open_input_stream(HTTPContext *c, const char *info);
+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) {
+ 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)
+{
+ if (no_launch)
+ return;
+
+ for (; feed; feed = feed->next) {
+ if (feed->child_argv && !feed->pid) {
+ feed->pid_start = time(0);
+
+ feed->pid = fork();
+
+ if (feed->pid < 0) {
+ http_log("Unable to create children\n");
+ exit(1);
+ }
+ if (!feed->pid) {
+ /* In child */
+ char pathname[1024];
+ char *slash;
+ int i;
+
+ /* 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");
+
+ 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;
+
+ default_port = 6000;
+ for(stream = config.first_stream; stream; stream = stream->next) {
+ if (stream->is_multicast) {
+ unsigned random0 = av_lfg_get(&random_state);
+ unsigned 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) {
+ 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;
+
+ if(!(poll_table = av_mallocz_array(config.nb_max_http_connections + 2, sizeof(*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) {
+ if (ctx->oformat) {
+ /* prepare header */
+ if (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;
+
+ 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:
+ len = recv(c->fd, c->buffer_ptr, 1, 0);
+ if (len < 0) {
+ if (ff_neterrno() != AVERROR(EAGAIN) &&
+ ff_neterrno() != AVERROR(EINTR))
+ return -1;
+ } else if (len == 0) {
+ return -1;
+ } else {
+ /* search for end of request. */
+ uint8_t *ptr;
+ 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;
+ }
+ } else {
+ 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;
+ }
+ } else {
+ 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;
+ }
+ } else {
+ 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;
+ }
+ } else {
+ 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 */
+ for(;;) {
+ if (fgets(line, sizeof(line), f) == NULL)
+ break;
+ 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) != 0)) {
+ /* 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) {
+ 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) {
+ 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 */
+ if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 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;
+ }
+
+ 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 != 0)
+ /* 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;
+ } else
+ 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") != 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");
+ }
+
+ if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
+ !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
+ goto sdp_done;
+ if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
+ !(avs = av_malloc(avc->nb_streams * sizeof(*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")) {
+ /* 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(NULL);
+ memcpy(fst->codec, codec, sizeof(AVCodecContext));
+ if (codec->extradata_size) {
+ fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ memcpy(fst->codec->extradata, codec->extradata,
+ codec->extradata_size);
+ }
+ } 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++) {
+ st = feed->streams[i];
+ av1 = st->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;
+ 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;
+ // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
+ 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);
+ if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 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_close(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 */
+ feed->child_argv = 0;
+ }
+ }
+ }
+
+ 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 0000000..ac89063
--- /dev/null
+++ b/ffserver_config.c
@@ -0,0 +1,1224 @@
+/*
+ * 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"
+
+/* 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;
+
+ p = *pp;
+ while (av_isspace(*p)) p++;
+ q = buf;
+ quote = 0;
+ if (*p == '\"' || *p == '\'')
+ quote = *p++;
+ for(;;) {
+ if (quote) {
+ if (*p == quote)
+ break;
+ } else {
+ if (av_isspace(*p))
+ break;
+ }
+ if (*p == '\0')
+ 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' is not 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)
+{
+ AVStream *st;
+
+ if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
+ return;
+
+ /* compute default parameters */
+ switch(av->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ if (av->bit_rate == 0)
+ av->bit_rate = 64000;
+ if (av->sample_rate == 0)
+ av->sample_rate = 22050;
+ if (av->channels == 0)
+ av->channels = 1;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ if (av->bit_rate == 0)
+ av->bit_rate = 64000;
+ if (av->time_base.num == 0){
+ av->time_base.den = 5;
+ av->time_base.num = 1;
+ }
+ if (av->width == 0 || av->height == 0) {
+ av->width = 160;
+ av->height = 128;
+ }
+ /* Bitrate tolerance is less for streaming */
+ if (av->bit_rate_tolerance == 0)
+ av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
+ (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
+ if (av->qmin == 0)
+ av->qmin = 3;
+ if (av->qmax == 0)
+ av->qmax = 31;
+ if (av->max_qdiff == 0)
+ av->max_qdiff = 3;
+ av->qcompress = 0.5;
+ av->qblur = 0.5;
+
+ if (!av->nsse_weight)
+ av->nsse_weight = 8;
+
+ av->frame_skip_cmp = FF_CMP_DCTMAX;
+ if (!av->me_method)
+ av->me_method = ME_EPZS;
+
+ /* FIXME: rc_buffer_aggressivity and rc_eq are deprecated */
+ av->rc_buffer_aggressivity = 1.0;
+
+ if (!av->rc_eq)
+ av->rc_eq = av_strdup("tex^qComp");
+ if (!av->i_quant_factor)
+ av->i_quant_factor = -0.8;
+ if (!av->b_quant_factor)
+ av->b_quant_factor = 1.25;
+ if (!av->b_quant_offset)
+ av->b_quant_offset = 1.25;
+ if (!av->rc_max_rate)
+ av->rc_max_rate = av->bit_rate * 2;
+
+ if (av->rc_max_rate && !av->rc_buffer_size) {
+ av->rc_buffer_size = av->rc_max_rate;
+ }
+
+
+ break;
+ default:
+ abort();
+ }
+
+ st = av_mallocz(sizeof(AVStream));
+ if (!st)
+ return;
+ st->codec = av;
+ stream->streams[stream->nb_streams++] = st;
+}
+
+static enum AVCodecID opt_codec(const char *name, enum AVMediaType type)
+{
+ AVCodec *codec = avcodec_find_encoder_by_name(name);
+
+ if (!codec || codec->type != type)
+ return AV_CODEC_ID_NONE;
+ return codec->id;
+}
+
+static int ffserver_opt_default(const char *opt, const char *arg,
+ AVCodecContext *avctx, int type)
+{
+ int ret = 0;
+ const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
+ if(o)
+ ret = av_opt_set(avctx, opt, arg, 0);
+ return ret;
+}
+
+static int ffserver_opt_preset(const char *arg,
+ AVCodecContext *avctx, int type,
+ enum AVCodecID *audio_id, enum AVCodecID *video_id)
+{
+ FILE *f=NULL;
+ char filename[1000], tmp[1000], tmp2[1000], line[1000];
+ int ret = 0;
+ AVCodec *codec = NULL;
+
+ if (avctx)
+ codec = avcodec_find_encoder(avctx->codec_id);
+
+ if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
+ codec ? codec->name : NULL))) {
+ fprintf(stderr, "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){
+ fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
+ ret = AVERROR(EINVAL);
+ break;
+ }
+ if (audio_id && !strcmp(tmp, "acodec")) {
+ *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
+ } else if (video_id && !strcmp(tmp, "vcodec")){
+ *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
+ } else if(!strcmp(tmp, "scodec")) {
+ /* opt_subtitle_codec(tmp2); */
+ } else if (avctx && (ret = ffserver_opt_default(tmp, tmp2, avctx, type)) < 0) {
+ fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as "
+ "'%s' = '%s'\n", filename, line, tmp, tmp2);
+ 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);
+ (*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, int line_num, 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, 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, int line_num, 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, 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, AVDictionary **dict,
+ int type, FFServerConfig *config, int line_num)
+{
+ int ret = 0;
+ AVDictionaryEntry *e;
+ const AVOption *o = av_opt_find(config->dummy_ctx, opt, NULL, type | AV_OPT_FLAG_ENCODING_PARAM, AV_OPT_SEARCH_CHILDREN);
+ if (!o) {
+ report_config_error(config->filename, line_num, AV_LOG_ERROR,
+ &config->errors, "Option not found: %s\n", opt);
+ } else if ((ret = av_opt_set(config->dummy_ctx, opt, arg, AV_OPT_SEARCH_CHILDREN)) < 0) {
+ report_config_error(config->filename, 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, opt, NULL, 0))) {
+ if ((o->type == AV_OPT_TYPE_FLAGS) && arg && (arg[0] == '+' || arg[0] == '-'))
+ return av_dict_set(dict, opt, arg, AV_DICT_APPEND);
+ report_config_error(config->filename, line_num, AV_LOG_ERROR,
+ &config->errors,
+ "Redeclaring value of the option %s, previous value: %s\n",
+ opt, e->value);
+ } else if (av_dict_set(dict, opt, arg, 0) < 0) {
+ return AVERROR(ENOMEM);
+ }
+ return 0;
+}
+
+#define ERROR(...) report_config_error(config->filename, line_num, AV_LOG_ERROR, &config->errors, __VA_ARGS__)
+#define WARNING(...) report_config_error(config->filename, line_num, AV_LOG_WARNING, &config->warnings, __VA_ARGS__)
+
+static int ffserver_parse_config_global(FFServerConfig *config, const char *cmd,
+ const char **p, int line_num)
+{
+ 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, line_num,
+ "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, line_num,
+ "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, line_num,
+ "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, line_num,
+ "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
+ ERROR("Incorrect keyword: '%s'\n", cmd);
+ return 0;
+}
+
+static int ffserver_parse_config_feed(FFServerConfig *config, const char *cmd, const char **p,
+ int line_num, 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(64 * sizeof(char *));
+ if (!feed->child_argv)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < 62; 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,
+ 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 void ffserver_apply_stream_config(AVCodecContext *enc, const AVDictionary *conf, AVDictionary **opts)
+{
+ AVDictionaryEntry *e;
+
+ /* Return values from ffserver_set_*_param are ignored.
+ Values are initially parsed and checked before inserting to
+ AVDictionary. */
+
+ //video params
+ if ((e = av_dict_get(conf, "VideoBitRateRangeMin", NULL, 0)))
+ ffserver_set_int_param(&enc->rc_min_rate, e->value, 1000, INT_MIN,
+ INT_MAX, NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "VideoBitRateRangeMax", NULL, 0)))
+ ffserver_set_int_param(&enc->rc_max_rate, e->value, 1000, INT_MIN,
+ INT_MAX, NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "Debug", NULL, 0)))
+ ffserver_set_int_param(&enc->debug, e->value, 0, INT_MIN, INT_MAX,
+ NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "Strict", NULL, 0)))
+ ffserver_set_int_param(&enc->strict_std_compliance, e->value, 0,
+ INT_MIN, INT_MAX, NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "VideoBufferSize", NULL, 0)))
+ ffserver_set_int_param(&enc->rc_buffer_size, e->value, 8*1024,
+ INT_MIN, INT_MAX, NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "VideoBitRateTolerance", NULL, 0)))
+ ffserver_set_int_param(&enc->bit_rate_tolerance, e->value, 1000,
+ INT_MIN, INT_MAX, NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "VideoBitRate", NULL, 0)))
+ ffserver_set_int_param(&enc->bit_rate, e->value, 1000, INT_MIN,
+ INT_MAX, NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "VideoSizeWidth", NULL, 0)))
+ ffserver_set_int_param(&enc->width, e->value, 0, INT_MIN, INT_MAX,
+ NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "VideoSizeHeight", NULL, 0)))
+ ffserver_set_int_param(&enc->height, e->value, 0, INT_MIN, INT_MAX,
+ NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "PixelFormat", NULL, 0))) {
+ int val;
+ ffserver_set_int_param(&val, e->value, 0, INT_MIN, INT_MAX, NULL, 0,
+ NULL);
+ enc->pix_fmt = val;
+ }
+ if ((e = av_dict_get(conf, "VideoGopSize", NULL, 0)))
+ ffserver_set_int_param(&enc->gop_size, e->value, 0, INT_MIN, INT_MAX,
+ NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "VideoFrameRateNum", NULL, 0)))
+ ffserver_set_int_param(&enc->time_base.num, e->value, 0, INT_MIN,
+ INT_MAX, NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "VideoFrameRateDen", NULL, 0)))
+ ffserver_set_int_param(&enc->time_base.den, e->value, 0, INT_MIN,
+ INT_MAX, NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "VideoQDiff", NULL, 0)))
+ ffserver_set_int_param(&enc->max_qdiff, e->value, 0, INT_MIN, INT_MAX,
+ NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "VideoQMax", NULL, 0)))
+ ffserver_set_int_param(&enc->qmax, e->value, 0, INT_MIN, INT_MAX, NULL,
+ 0, NULL);
+ if ((e = av_dict_get(conf, "VideoQMin", NULL, 0)))
+ ffserver_set_int_param(&enc->qmin, e->value, 0, INT_MIN, INT_MAX, NULL,
+ 0, NULL);
+ if ((e = av_dict_get(conf, "LumiMask", NULL, 0)))
+ ffserver_set_float_param(&enc->lumi_masking, e->value, 0, -FLT_MAX,
+ FLT_MAX, NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "DarkMask", NULL, 0)))
+ ffserver_set_float_param(&enc->dark_masking, e->value, 0, -FLT_MAX,
+ FLT_MAX, NULL, 0, NULL);
+ if (av_dict_get(conf, "BitExact", NULL, 0))
+ enc->flags |= CODEC_FLAG_BITEXACT;
+ if (av_dict_get(conf, "DctFastint", NULL, 0))
+ enc->dct_algo = FF_DCT_FASTINT;
+ if (av_dict_get(conf, "IdctSimple", NULL, 0))
+ enc->idct_algo = FF_IDCT_SIMPLE;
+ if (av_dict_get(conf, "VideoHighQuality", NULL, 0))
+ enc->mb_decision = FF_MB_DECISION_BITS;
+ if ((e = av_dict_get(conf, "VideoTag", NULL, 0)))
+ enc->codec_tag = MKTAG(e->value[0], e->value[1], e->value[2], e->value[3]);
+ if (av_dict_get(conf, "Qscale", NULL, 0)) {
+ enc->flags |= CODEC_FLAG_QSCALE;
+ ffserver_set_int_param(&enc->global_quality, e->value, FF_QP2LAMBDA,
+ INT_MIN, INT_MAX, NULL, 0, NULL);
+ }
+ if (av_dict_get(conf, "Video4MotionVector", NULL, 0)) {
+ enc->mb_decision = FF_MB_DECISION_BITS; //FIXME remove
+ enc->flags |= CODEC_FLAG_4MV;
+ }
+ //audio params
+ if ((e = av_dict_get(conf, "AudioChannels", NULL, 0)))
+ ffserver_set_int_param(&enc->channels, e->value, 0, INT_MIN, INT_MAX,
+ NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "AudioSampleRate", NULL, 0)))
+ ffserver_set_int_param(&enc->sample_rate, e->value, 0, INT_MIN,
+ INT_MAX, NULL, 0, NULL);
+ if ((e = av_dict_get(conf, "AudioBitRate", NULL, 0)))
+ ffserver_set_int_param(&enc->bit_rate, e->value, 0, INT_MIN, INT_MAX,
+ NULL, 0, NULL);
+
+ av_opt_set_dict2(enc, opts, AV_OPT_SEARCH_CHILDREN);
+}
+
+static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd, const char **p,
+ int line_num, 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_ctx = avcodec_alloc_context3(NULL);
+ if (!config->dummy_ctx) {
+ av_free(stream);
+ return AVERROR(ENOMEM);
+ }
+ 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->audio_id = stream->fmt->audio_codec;
+ config->video_id = stream->fmt->video_codec;
+ } else {
+ config->audio_id = AV_CODEC_ID_NONE;
+ config->video_id = AV_CODEC_ID_NONE;
+ }
+ *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->audio_id = stream->fmt->audio_codec;
+ config->video_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("'%s' option in configuration file is deprecated, "
+ "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);
+ config->audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO);
+ if (config->audio_id == AV_CODEC_ID_NONE)
+ ERROR("Unknown AudioCodec: %s\n", arg);
+ } else if (!av_strcasecmp(cmd, "VideoCodec")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ config->video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO);
+ if (config->video_id == AV_CODEC_ID_NONE)
+ ERROR("Unknown VideoCodec: %s\n", arg);
+ } 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, 0, FLT_MAX, config, line_num,
+ "Invalid %s: %s\n", cmd, arg);
+ if (av_dict_set_int(&config->audio_conf, cmd, lrintf(f), 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "AudioChannels")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(NULL, arg, 0, 1, 8, config, line_num,
+ "Invalid %s: %s, valid range is 1-8.", cmd, arg);
+ if (av_dict_set(&config->audio_conf, cmd, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(NULL, arg, 0, 0, INT_MAX, config, line_num,
+ "Invalid %s: %s", cmd, arg);
+ if (av_dict_set(&config->audio_conf, cmd, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
+ int minrate, maxrate;
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
+ if (av_dict_set_int(&config->video_conf, "VideoBitRateRangeMin", minrate, 0) < 0 ||
+ av_dict_set_int(&config->video_conf, "VideoBitRateRangeMax", maxrate, 0) < 0)
+ goto nomem;
+ } else
+ ERROR("Incorrect format for VideoBitRateRange -- should be "
+ "<min>-<max>: %s\n", arg);
+ } else if (!av_strcasecmp(cmd, "Debug")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(NULL, arg, 0, INT_MIN, INT_MAX, config, line_num,
+ "Invalid %s: %s", cmd, arg);
+ if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "Strict")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(NULL, arg, 0, INT_MIN, INT_MAX, config, line_num,
+ "Invalid %s: %s", cmd, arg);
+ if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(NULL, arg, 8*1024, 0, INT_MAX, config, line_num,
+ "Invalid %s: %s", cmd, arg);
+ if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(NULL, arg, 1000, INT_MIN, INT_MAX, config,
+ line_num, "Invalid %s: %s", cmd, arg);
+ if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(NULL, arg, 1000, 0, INT_MAX, config, line_num,
+ "Invalid %s: %s", cmd, arg);
+ if (av_dict_set(&config->video_conf, cmd, arg, 0) < 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 (av_dict_set_int(&config->video_conf, "VideoSizeWidth", w, 0) < 0 ||
+ av_dict_set_int(&config->video_conf, "VideoSizeHeight", h, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
+ AVRational frame_rate;
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (av_parse_video_rate(&frame_rate, arg) < 0) {
+ ERROR("Incorrect frame rate: %s\n", arg);
+ } else {
+ if (av_dict_set_int(&config->video_conf, "VideoFrameRateNum", frame_rate.num, 0) < 0 ||
+ av_dict_set_int(&config->video_conf, "VideoFrameRateDen", frame_rate.den, 0) < 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);
+ if (av_dict_set_int(&config->video_conf, cmd, pix_fmt, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(NULL, arg, 0, INT_MIN, INT_MAX, config, line_num,
+ "Invalid %s: %s", cmd, arg);
+ if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
+ if (av_dict_set(&config->video_conf, cmd, "1", 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
+ if (av_dict_set(&config->video_conf, cmd, "", 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
+ if (av_dict_set(&config->video_conf, cmd, "", 0) < 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, &config->video_opts, AV_OPT_FLAG_VIDEO_PARAM ,config, line_num);
+ else
+ ret = ffserver_save_avoption(arg, arg2, &config->audio_opts, AV_OPT_FLAG_AUDIO_PARAM ,config, line_num);
+ if (ret < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
+ !av_strcasecmp(cmd, "AVPresetAudio")) {
+ char **preset = NULL;
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (!av_strcasecmp(cmd, "AVPresetVideo")) {
+ preset = &config->video_preset;
+ ffserver_opt_preset(arg, NULL, 0, NULL, &config->video_id);
+ } else {
+ preset = &config->audio_preset;
+ ffserver_opt_preset(arg, NULL, 0, &config->audio_id, NULL);
+ }
+ *preset = av_strdup(arg);
+ if (!preset)
+ return AVERROR(ENOMEM);
+ } else if (!av_strcasecmp(cmd, "VideoTag")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (strlen(arg) == 4) {
+ if (av_dict_set(&config->video_conf, "VideoTag", "arg", 0) < 0)
+ goto nomem;
+ }
+ } else if (!av_strcasecmp(cmd, "BitExact")) {
+ if (av_dict_set(&config->video_conf, cmd, "", 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "DctFastint")) {
+ if (av_dict_set(&config->video_conf, cmd, "", 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "IdctSimple")) {
+ if (av_dict_set(&config->video_conf, cmd, "", 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "Qscale")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(NULL, arg, 0, 1, 31, config, line_num,
+ "%s out of range\n", cmd);
+ if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoQMax")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(NULL, arg, 0, 1, 31, config, line_num,
+ "%s out of range\n", cmd);
+ if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoQMin")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(NULL, arg, 0, 1, 31, config, line_num,
+ "%s out of range\n", cmd);
+ if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "LumiMask")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_float_param(NULL, arg, 0, -FLT_MAX, FLT_MAX, config,
+ line_num, "Invalid %s: %s", cmd, arg);
+ if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "DarkMask")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_float_param(NULL, arg, 0, -FLT_MAX, FLT_MAX, config,
+ line_num, "Invalid %s: %s", cmd, arg);
+ if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "NoVideo")) {
+ config->video_id = AV_CODEC_ID_NONE;
+ } else if (!av_strcasecmp(cmd, "NoAudio")) {
+ config->audio_id = AV_CODEC_ID_NONE;
+ } else if (!av_strcasecmp(cmd, "ACL")) {
+ ffserver_parse_acl_row(stream, NULL, NULL, *p, config->filename,
+ 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, line_num,
+ "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,
+ line_num, "Invalid MulticastTTL: %s\n", arg);
+ stream->multicast_ttl = val;
+ } else if (!av_strcasecmp(cmd, "NoLoop")) {
+ stream->loop = 0;
+ } else if (!av_strcasecmp(cmd, "</Stream>")) {
+ if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm")) {
+ if (config->audio_id != AV_CODEC_ID_NONE) {
+ AVCodecContext *audio_enc = avcodec_alloc_context3(avcodec_find_encoder(config->audio_id));
+ if (config->audio_preset &&
+ ffserver_opt_preset(arg, audio_enc, AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_ENCODING_PARAM,
+ NULL, NULL) < 0)
+ ERROR("Could not apply preset '%s'\n", arg);
+ ffserver_apply_stream_config(audio_enc, config->audio_conf,
+ &config->audio_opts);
+ add_codec(stream, audio_enc);
+ }
+ if (config->video_id != AV_CODEC_ID_NONE) {
+ AVCodecContext *video_enc = avcodec_alloc_context3(avcodec_find_encoder(config->video_id));
+ if (config->video_preset &&
+ ffserver_opt_preset(arg, video_enc, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_ENCODING_PARAM,
+ NULL, NULL) < 0)
+ ERROR("Could not apply preset '%s'\n", arg);
+ ffserver_apply_stream_config(video_enc, config->video_conf,
+ &config->video_opts);
+ add_codec(stream, video_enc);
+ }
+ }
+ av_dict_free(&config->video_opts);
+ av_dict_free(&config->video_conf);
+ av_dict_free(&config->audio_opts);
+ av_dict_free(&config->audio_conf);
+ av_freep(&config->video_preset);
+ av_freep(&config->audio_preset);
+ avcodec_free_context(&config->dummy_ctx);
+ *pstream = NULL;
+ } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
+ ffserver_get_arg(stream->feed_filename, sizeof(stream->feed_filename),
+ p);
+ } 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->video_conf);
+ av_dict_free(&config->audio_opts);
+ av_dict_free(&config->audio_conf);
+ av_freep(&config->video_preset);
+ av_freep(&config->audio_preset);
+ avcodec_free_context(&config->dummy_ctx);
+ return AVERROR(ENOMEM);
+}
+
+static int ffserver_parse_config_redirect(FFServerConfig *config, const char *cmd, const char **p,
+ int line_num, 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;
+ int line_num = 0;
+ 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;
+ last_stream = &config->first_stream;
+ config->first_feed = NULL;
+ last_feed = &config->first_feed;
+ config->errors = config->warnings = 0;
+
+ for(;;) {
+ if (fgets(line, sizeof(line), f) == NULL)
+ break;
+ 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 {
+ if ((ret = ffserver_parse_config_feed(config, cmd, &p, line_num, &feed)) < 0)
+ break;
+ if (opening) {
+ /* add in stream list */
+ *last_stream = feed;
+ last_stream = &feed->next;
+ /* add in feed list */
+ *last_feed = feed;
+ 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 {
+ if ((ret = ffserver_parse_config_stream(config, cmd, &p, line_num, &stream)) < 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 {
+ if ((ret = ffserver_parse_config_redirect(config, cmd, &p, line_num, &redirect)) < 0)
+ break;
+ if (opening) {
+ /* add in stream list */
+ *last_stream = redirect;
+ last_stream = &redirect->next;
+ }
+ }
+ } else {
+ ffserver_parse_config_global(config, cmd, &p, line_num);
+ }
+ }
+ if (stream || feed || redirect)
+ ERROR("Not closed tag %s\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
diff --git a/ffserver_config.h b/ffserver_config.h
new file mode 100644
index 0000000..6b64dc5
--- /dev/null
+++ b/ffserver_config.h
@@ -0,0 +1,129 @@
+/*
+ * 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;
+ // Following variables MUST NOT be used outside configuration parsing code.
+ enum AVCodecID audio_id;
+ enum AVCodecID video_id;
+ AVDictionary *video_opts; /* AVOptions for video encoder */
+ AVDictionary *video_conf; /* Values stored in video AVCodecContext.fields */
+ AVDictionary *audio_opts; /* AVOptions for audio encoder */
+ AVDictionary *audio_conf; /* Values stored in audio AVCodecContext.fields */
+ char *video_preset;
+ char *audio_preset;
+ AVCodecContext *dummy_ctx; /* Used internally to test AVOptions. Not to be used anywhere else */
+} 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);
+
+#endif /* FFSERVER_CONFIG_H */
diff --git a/libavcodec/012v.c b/libavcodec/012v.c
new file mode 100644
index 0000000..c2b6a35
--- /dev/null
+++ b/libavcodec/012v.c
@@ -0,0 +1,159 @@
+/*
+ * 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 = 0, 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) {
+ av_log(avctx, AV_LOG_ERROR, "Width 1 not supported.\n");
+ 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;
+
+ y = (uint16_t *)pic->data[0];
+ u = (uint16_t *)pic->data[1];
+ v = (uint16_t *)pic->data[2];
+ line_end = avpkt->data + stride;
+
+ while (line++ < avctx->height) {
+ while (1) {
+ uint32_t t = AV_RL32(src);
+ src += 4;
+ *u++ = t << 6 & 0xFFC0;
+ *y++ = t >> 4 & 0xFFC0;
+ *v++ = t >> 14 & 0xFFC0;
+
+ if (src >= line_end - 1) {
+ *y = 0x80;
+ src++;
+ line_end += stride;
+ 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]);
+ break;
+ }
+
+ t = AV_RL32(src);
+ src += 4;
+ *y++ = t << 6 & 0xFFC0;
+ *u++ = t >> 4 & 0xFFC0;
+ *y++ = t >> 14 & 0xFFC0;
+ if (src >= line_end - 2) {
+ if (!(width & 1)) {
+ *y = 0x80;
+ src += 2;
+ }
+ line_end += stride;
+ 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]);
+ break;
+ }
+
+ t = AV_RL32(src);
+ src += 4;
+ *v++ = t << 6 & 0xFFC0;
+ *y++ = t >> 4 & 0xFFC0;
+ *u++ = t >> 14 & 0xFFC0;
+
+ if (src >= line_end - 1) {
+ *y = 0x80;
+ src++;
+ line_end += stride;
+ 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]);
+ break;
+ }
+
+ t = AV_RL32(src);
+ src += 4;
+ *y++ = t << 6 & 0xFFC0;
+ *v++ = t >> 4 & 0xFFC0;
+ *y++ = t >> 14 & 0xFFC0;
+
+ if (src >= line_end - 2) {
+ if (width & 1) {
+ *y = 0x80;
+ src += 2;
+ }
+ line_end += stride;
+ 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]);
+ break;
+ }
+ }
+ }
+
+ *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 b248d87..3a25622 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 3fd15e0..e00bdfc 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 b973771..26496e5 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 66aa0ce..6c625ce 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1,9 +1,12 @@
+include $(SUBDIR)../config.mak
+
NAME = avcodec
HEADERS = avcodec.h \
avfft.h \
dv_profile.h \
dxva2.h \
+ old_codec_ids.h \
vaapi.h \
vda.h \
vdpau.h \
@@ -12,6 +15,8 @@ HEADERS = avcodec.h \
xvmc.h \
OBJS = allcodecs.o \
+ audioconvert.o \
+ avdct.o \
avpacket.o \
avpicture.o \
bitstream.o \
@@ -20,11 +25,12 @@ OBJS = allcodecs.o \
dv_profile.o \
fmtconvert.o \
imgconvert.o \
- log2_tab.o \
mathtables.o \
options.o \
parser.o \
raw.o \
+ resample.o \
+ resample2.o \
utils.o \
vorbis_parser.o \
xiph.o \
@@ -37,13 +43,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_GOLOMB) += golomb.o
OBJS-$(CONFIG_H263DSP) += h263dsp.o
@@ -59,9 +68,11 @@ OBJS-$(CONFIG_IDCTDSP) += idctdsp.o simple_idct.o jrevdct.o
OBJS-$(CONFIG_IIRFILTER) += iirfilter.o
OBJS-$(CONFIG_INTRAX8) += intrax8.o intrax8dsp.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_QPELDSP) += qpeldsp.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
@@ -88,6 +100,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 \
@@ -97,7 +110,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
@@ -115,10 +129,16 @@ 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 mjpeg.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_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
@@ -130,12 +150,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 mjpeg.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
@@ -147,21 +175,30 @@ OBJS-$(CONFIG_CAVS_DECODER) += cavs.o cavsdec.o cavsdsp.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
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 \
synth_filter.o
+OBJS-$(CONFIG_DCA_ENCODER) += dcaenc.o dca.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_DVBSUB_DECODER) += dvbsubdec.o
@@ -185,14 +222,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
@@ -200,7 +240,9 @@ OBJS-$(CONFIG_FRAPS_DECODER) += fraps.o
OBJS-$(CONFIG_FRWU_DECODER) += frwu.o
OBJS-$(CONFIG_G2M_DECODER) += g2meet.o mjpeg.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
@@ -216,6 +258,7 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o h264_cabac.o h264_cavlc.o \
h264_direct.o h264_loopfilter.o \
h264_mb.o h264_picture.o h264_ps.o \
h264_refs.o h264_sei.o h264_slice.o
+OBJS-$(CONFIG_H264_VDA_DECODER) += vda_h264_dec.o
OBJS-$(CONFIG_HEVC_DECODER) += hevc.o hevc_mvs.o hevc_ps.o hevc_sei.o \
hevc_cabac.o hevc_refs.o hevcpred.o \
hevcdsp.o hevc_filter.o
@@ -223,6 +266,7 @@ OBJS-$(CONFIG_HNM4_VIDEO_DECODER) += hnm4video.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
@@ -232,6 +276,9 @@ OBJS-$(CONFIG_INDEO4_DECODER) += indeo4.o ivi_common.o ivi_dsp.o
OBJS-$(CONFIG_INDEO5_DECODER) += indeo5.o ivi_common.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
@@ -247,6 +294,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 mjpeg.o
OBJS-$(CONFIG_MJPEG_ENCODER) += mjpegenc.o mjpeg.o mjpegenc_common.o
@@ -254,10 +302,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
@@ -268,12 +320,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
@@ -284,6 +337,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
@@ -310,12 +364,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 \
@@ -326,13 +384,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
@@ -345,7 +406,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
@@ -358,28 +421,45 @@ 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_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
@@ -387,6 +467,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
@@ -395,7 +479,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
@@ -411,11 +496,15 @@ 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
+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
@@ -426,6 +515,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 \
@@ -435,14 +525,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
@@ -467,12 +564,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
@@ -480,11 +581,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
@@ -504,7 +607,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
@@ -515,6 +620,7 @@ OBJS-$(CONFIG_ADPCM_G722_DECODER) += g722.o g722dec.o
OBJS-$(CONFIG_ADPCM_G722_ENCODER) += g722.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
@@ -522,8 +628,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
@@ -540,6 +648,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_DXVA2) += dxva2.o
@@ -547,57 +656,69 @@ OBJS-$(CONFIG_VAAPI) += vaapi.o
OBJS-$(CONFIG_VDA) += vda.o
OBJS-$(CONFIG_VDPAU) += vdpau.o
-OBJS-$(CONFIG_H263_VAAPI_HWACCEL) += vaapi_mpeg4.o
+OBJS-$(CONFIG_H263_VAAPI_HWACCEL) += vaapi_mpeg4.o vaapi_mpeg.o
OBJS-$(CONFIG_H263_VDPAU_HWACCEL) += vdpau_mpeg4.o
OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o
OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o
OBJS-$(CONFIG_H264_VDA_HWACCEL) += vda_h264.o
OBJS-$(CONFIG_H264_VDPAU_HWACCEL) += vdpau_h264.o
OBJS-$(CONFIG_MPEG1_VDPAU_HWACCEL) += vdpau_mpeg12.o
+OBJS-$(CONFIG_MPEG1_XVMC_HWACCEL) += mpegvideo_xvmc.o
OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL) += dxva2_mpeg2.o
-OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL) += vaapi_mpeg2.o
+OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL) += vaapi_mpeg2.o vaapi_mpeg.o
OBJS-$(CONFIG_MPEG2_VDPAU_HWACCEL) += vdpau_mpeg12.o
-OBJS-$(CONFIG_MPEG4_VAAPI_HWACCEL) += vaapi_mpeg4.o
+OBJS-$(CONFIG_MPEG2_XVMC_HWACCEL) += mpegvideo_xvmc.o
+OBJS-$(CONFIG_MPEG4_VAAPI_HWACCEL) += vaapi_mpeg4.o vaapi_mpeg.o
OBJS-$(CONFIG_MPEG4_VDPAU_HWACCEL) += vdpau_mpeg4.o
OBJS-$(CONFIG_VC1_DXVA2_HWACCEL) += dxva2_vc1.o
-OBJS-$(CONFIG_VC1_VAAPI_HWACCEL) += vaapi_vc1.o
+OBJS-$(CONFIG_VC1_VAAPI_HWACCEL) += vaapi_vc1.o vaapi_mpeg.o
OBJS-$(CONFIG_VC1_VDPAU_HWACCEL) += vdpau_vc1.o
# libavformat dependencies
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_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_RTPDEC) += mjpeg.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_LIBFAAC_ENCODER) += libfaac.o
OBJS-$(CONFIG_LIBFDK_AAC_DECODER) += libfdk-aacdec.o
OBJS-$(CONFIG_LIBFDK_AAC_ENCODER) += libfdk-aacenc.o
@@ -621,13 +742,18 @@ 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
@@ -639,6 +765,7 @@ 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 \
@@ -653,9 +780,12 @@ OBJS-$(CONFIG_COOK_PARSER) += cook_parser.o
OBJS-$(CONFIG_DCA_PARSER) += dca_parser.o dca.o
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
@@ -666,6 +796,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 \
@@ -681,6 +812,7 @@ OBJS-$(CONFIG_VC1_PARSER) += vc1_parser.o vc1.o vc1data.o vc1dsp.o
h263.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 \
@@ -692,6 +824,8 @@ OBJS-$(CONFIG_IMX_DUMP_HEADER_BSF) += imx_dump_header_bsf.o
OBJS-$(CONFIG_MJPEG2JPEG_BSF) += mjpeg2jpeg_bsf.o mjpeg.o
OBJS-$(CONFIG_MJPEGA_DUMP_HEADER_BSF) += mjpega_dump_header_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
@@ -700,32 +834,50 @@ 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 \
$(ARCH)/vp56_arith.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_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 \
+
+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 \
@@ -750,7 +902,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))
@@ -761,7 +913,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 d977426..a9cdb6f 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 65c1d30..0000000
--- 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 786074f..fc00d3f 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,7 +24,6 @@
* a64 video encoder - multicolor modes
*/
-#include "a64enc.h"
#include "a64colors.h"
#include "a64tables.h"
#include "elbg.h"
@@ -37,6 +36,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};
@@ -166,11 +187,11 @@ 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 +220,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_malloc_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");
@@ -260,7 +281,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;
@@ -314,15 +335,13 @@ static int a64multi_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
/* 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);
+ if ((ret = ff_alloc_packet2(avctx, pkt, req_size)) < 0)
return ret;
- }
buf = pkt->data;
/* calc optimal new charset + charmaps */
- ff_init_elbg(meta, 32, 1000 * c->mc_lifetime, best_cb, CHARSET_CHARS, 50, charmap, &c->randctx);
- ff_do_elbg (meta, 32, 1000 * c->mc_lifetime, best_cb, CHARSET_CHARS, 50, charmap, &c->randctx);
+ avpriv_init_elbg(meta, 32, 1000 * c->mc_lifetime, best_cb, CHARSET_CHARS, 50, charmap, &c->randctx);
+ avpriv_do_elbg (meta, 32, 1000 * c->mc_lifetime, best_cb, CHARSET_CHARS, 50, charmap, &c->randctx);
/* create colorram map and a c64 readable charset */
render_charset(avctx, charset, colram);
@@ -332,7 +351,6 @@ static int a64multi_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
/* advance pointers */
buf += charset_size;
- charset += charset_size;
}
/* write x frames to buf */
@@ -376,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"),
@@ -388,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)"),
@@ -401,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 b95c5ce..a955ef4 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 375e6b1..e8de1e8 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,
@@ -245,6 +245,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 +260,8 @@ typedef struct ChannelElement {
/**
* main AAC context
*/
-typedef struct AACContext {
+struct AACContext {
+ AVClass *class;
AVCodecContext *avctx;
AVFrame *frame;
@@ -273,6 +275,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;
/** @} */
/**
@@ -303,9 +306,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 d3da9b7..7fefda5 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 99286f0..c2506a5 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 733b08d..b1515fd 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,6 +87,7 @@ 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);
@@ -112,7 +113,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 fdaa5f8..cb93ba9 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 b2c6c95..33a179f 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 8a05ec5..bf71e59 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 a5fd1cf..5105dae 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 2994bce..d0814ac 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 6319efc..d0584ef 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 35b98a9..5bf6a9c 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
*/
@@ -53,7 +53,7 @@ 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
};
@@ -506,7 +506,7 @@ static void codebook_trellis_rate(AACEncContext *s, SingleChannelElement *sce,
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;
@@ -776,7 +776,6 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
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++) {
@@ -875,7 +874,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 +952,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;
@@ -1112,26 +1110,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 d2d51f5..2793881 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"
@@ -108,12 +110,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 +138,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
@@ -152,6 +160,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 - (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 +196,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++) {
@@ -427,6 +440,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 +487,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 +500,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 +537,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 +573,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 +592,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 +621,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 +636,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 +704,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 +750,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 +773,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);
@@ -865,9 +947,9 @@ static int decode_audio_specific_config(AACContext *ac,
GetBitContext gb;
int i, ret;
- av_dlog(avctx, "extradata size %d\n", avctx->extradata_size);
- for (i = 0; i < avctx->extradata_size; i++)
- av_dlog(avctx, "%02x ", avctx->extradata[i]);
+ av_dlog(avctx, "audio specific config size %d\n", bit_size >> 3);
+ for (i = 0; i < bit_size >> 3; i++)
+ av_dlog(avctx, "%02x ", data[i]);
av_dlog(avctx, "\n");
if ((ret = init_get_bits(&gb, data, bit_size)) < 0)
@@ -931,7 +1013,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;
@@ -985,6 +1067,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;
@@ -993,6 +1077,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) {
@@ -1031,6 +1117,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);
@@ -1091,7 +1182,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);
@@ -1195,13 +1286,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,
@@ -1219,10 +1310,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;
}
/**
@@ -1253,7 +1347,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) {
@@ -1355,12 +1449,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);
}
@@ -1425,7 +1519,7 @@ static void decode_mid_side_stereo(ChannelElement *cpe, GetBitContext *gb,
idx++)
cpe->ms_mask[idx] = get_bits1(gb);
} else if (ms_present == 2) {
- memset(cpe->ms_mask, 1, cpe->ch[0].ics.num_window_groups * cpe->ch[0].ics.max_sfb * sizeof(cpe->ms_mask[0]));
+ memset(cpe->ms_mask, 1, sizeof(cpe->ms_mask[0]) * cpe->ch[0].ics.num_window_groups * cpe->ch[0].ics.max_sfb);
}
}
@@ -1875,7 +1969,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)
@@ -2159,6 +2253,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.
*
@@ -2171,7 +2291,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:
@@ -2202,6 +2327,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:
@@ -2224,7 +2351,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;
@@ -2316,10 +2443,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])
@@ -2466,7 +2593,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;
@@ -2612,36 +2739,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);
@@ -2649,6 +2776,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_WARNING, "ChannelElement %d.%d missing \n", type, i);
}
}
}
@@ -2663,10 +2793,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) {
@@ -2682,6 +2814,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;
@@ -2736,6 +2883,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) {
@@ -2764,13 +2912,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;
@@ -2798,6 +2947,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",
@@ -2806,6 +2958,7 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data,
goto fail;
}
samples = 1024;
+ che->present = 1;
}
switch (elem_type) {
@@ -2813,6 +2966,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:
@@ -2845,9 +2999,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;
@@ -2857,7 +3012,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;
}
@@ -2895,12 +3050,31 @@ 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));
+ }
+
+ *got_frame_ptr = !!samples;
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);
@@ -2921,8 +3095,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);
@@ -2939,6 +3117,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;
@@ -2950,7 +3137,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;
@@ -2988,7 +3175,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
@@ -3037,7 +3224,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;
@@ -3080,9 +3271,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;
@@ -3195,7 +3386,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
@@ -3203,7 +3394,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;
@@ -3233,7 +3424,7 @@ static int latm_decode_frame(AVCodecContext *avctx, void *out,
return AVERROR_INVALIDDATA;
}
- if ((err = aac_decode_frame_int(avctx, out, got_frame_ptr, &gb)) < 0)
+ if ((err = aac_decode_frame_int(avctx, out, got_frame_ptr, &gb, avpkt)) < 0)
return err;
return muxlength;
@@ -3250,6 +3441,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",
@@ -3265,6 +3502,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,
};
/*
@@ -3286,4 +3526,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 4c23f2d..4a12b4f 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 fa0ac00..be0c950 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
*/
@@ -145,7 +145,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 },
@@ -384,8 +384,7 @@ static void encode_scale_factors(AVCodecContext *avctx, AACEncContext *s,
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");
+ av_assert0(diff >= 0 && diff <= 120);
off = sce->sf_idx[w*16 + i];
put_bits(&s->pb, ff_aac_scalefactor_bits[diff], ff_aac_scalefactor_code[diff]);
}
@@ -478,7 +477,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)
{
@@ -568,14 +567,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;
@@ -709,8 +709,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++)
@@ -768,9 +768,12 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
if (ret = ff_psy_init(&s->psy, avctx, 2, sizes, lengths, s->chan_map[0], grouping))
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();
@@ -792,6 +795,11 @@ 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"},
{NULL}
};
@@ -802,6 +810,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)"),
@@ -811,6 +826,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 dec445c..ecd6811 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,18 @@
#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;
} AACEncOptions;
struct AACEncContext;
@@ -82,4 +92,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 8f55c7f..20012f9 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
*/
@@ -139,7 +139,7 @@ static int ps_read_extension_data(GetBitContext *gb, PSContext *ps, int ps_exten
return get_bits_count(gb) - count;
}
-static void ipdopd_reset(int8_t *opd_hist, int8_t *ipd_hist)
+static void ipdopd_reset(int8_t *ipd_hist, int8_t *opd_hist)
{
int i;
for (i = 0; i < PS_MAX_NR_IPDOPD; i++) {
@@ -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;
diff --git a/libavcodec/aacps.h b/libavcodec/aacps.h
index e8a195a..29323ff 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
*/
diff --git a/libavcodec/aacps_tablegen.c b/libavcodec/aacps_tablegen.c
index 537b6ba..f56930b 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 a53f9fa..ca1112d 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 675bd8e..7431cae 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 88e731f..5dc1a6a 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 dc380b1..0ef3023 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 66cf6d5..9eeb836 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];
@@ -705,7 +747,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 +837,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 76c1014..ebe2520 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,
@@ -744,7 +751,7 @@ static int read_sbr_grid(AACContext *ac, SpectralBandReplication *sbr,
if (ch_data->bs_frame_class == FIXFIX) {
idx = ch_data->bs_num_env >> 1;
} else if (ch_data->bs_frame_class & 1) { // FIXVAR or VARVAR
- idx = ch_data->bs_num_env - FFMAX(bs_pointer - 1, 1);
+ idx = ch_data->bs_num_env - FFMAX((int)bs_pointer - 1, 1);
} else { // VARFIX
if (!bs_pointer)
idx = 1;
@@ -929,7 +936,9 @@ static void read_sbr_extension(AACContext *ac, SpectralBandReplication *sbr,
}
break;
default:
- avpriv_request_sample(ac->avctx, "Reserved SBR extensions");
+ // some files contain 0-padding
+ if (bs_extension_id || *num_bits_left > 16 || show_bits(gb, *num_bits_left))
+ avpriv_request_sample(ac->avctx, "Reserved SBR extensions");
skip_bits_long(gb, *num_bits_left); // bs_fill_bits
*num_bits_left = 0;
break;
@@ -1118,7 +1127,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;
}
@@ -1127,7 +1141,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;
}
@@ -1136,9 +1155,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] =
@@ -1153,6 +1178,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)
@@ -1170,11 +1196,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],
@@ -1220,6 +1248,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)
@@ -1573,10 +1602,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;
@@ -1606,7 +1631,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;
@@ -1636,13 +1660,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;
@@ -1675,13 +1703,13 @@ void ff_sbr_apply(AACContext *ac, SpectralBandReplication *sbr, int id_aac,
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,
@@ -1695,7 +1723,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);
@@ -1703,7 +1731,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);
@@ -1730,3 +1758,14 @@ void ff_sbr_apply(AACContext *ac, SpectralBandReplication *sbr, int id_aac,
&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 9bc5e29..f5e33ab 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 0000000..c3c0f0c
--- /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 0000000..56fdccc
--- /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 f309059..c667e0b 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 ee9a735..eb882e8 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 d19b3fd..5ed8508 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 0c5b573..97013d2 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 daccb7b..b0a2f44 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 45b5c40..8defd7c 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 e12953e..6b9b77e 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 589e82d..8514d3b 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 5f88bed..54c13a4 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 c7679ab..2af62be 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 d1025c7..486079f 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 b106f11..ed5e4bd 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
*/
diff --git a/libavcodec/aarch64/h264dsp_neon.S b/libavcodec/aarch64/h264dsp_neon.S
index 9b4610a..4ec35f2 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 99c2cb5..04b5a47 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 4beb11b..77f41d9 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 731dc06..d27cfac 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 6bc4c09..144ae2b 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 2978290..a491c17 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/mdct_neon.S b/libavcodec/aarch64/mdct_neon.S
index bccd832..1fd199c 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 a8b2baf..b945146 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 808576a..733fc84 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 f1072b7..619aec6 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 0414829..6e41f37 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/opus_imdct_init.c b/libavcodec/aarch64/opus_imdct_init.c
index 1a776dc..3fa9a11 100644
--- a/libavcodec/aarch64/opus_imdct_init.c
+++ b/libavcodec/aarch64/opus_imdct_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/opus_imdct_neon.S b/libavcodec/aarch64/opus_imdct_neon.S
index 5f6c502..6234309 100644
--- a/libavcodec/aarch64/opus_imdct_neon.S
+++ b/libavcodec/aarch64/opus_imdct_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/rv40dsp_init_aarch64.c b/libavcodec/aarch64/rv40dsp_init_aarch64.c
index 0bb404f..764bc1e 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 11cd81e..e59e55e 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 7ce5a7d..24067cc 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 59b697d..6f667a6 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 3559b54..c796f95 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 11f71f1..e76feeb 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 468e394..65ef782 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 99e5b50..29e132f 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
*/
diff --git a/libavcodec/ac3.h b/libavcodec/ac3.h
index f2cb6c3..871640b 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 5ea09f8..131e180 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 9322550..f37387d 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 4876ac0..969e37f 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] = {
@@ -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);
+
+#if (USE_FIXED)
+ s->fdsp = avpriv_alloc_fixed_dsp(avctx->flags & CODEC_FLAG_BITEXACT);
+#else
avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+#endif
+
ff_ac3dsp_init(&s->ac3dsp, avctx->flags & CODEC_FLAG_BITEXACT);
ff_fmt_convert_init(&s->fmt_conv, avctx);
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]);
}
}
@@ -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,6 +563,10 @@ static void ac3_decode_transform_coeffs_ch(AC3DecodeContext *s, int ch_index, ma
break;
default: /* 6 to 15 */
/* Shift mantissa and sign-extend it. */
+ if (bap > 15) {
+ av_log(s->avctx, AV_LOG_ERROR, "bap %d is invalid in plain AC-3\n", bap);
+ bap = 15;
+ }
mantissa = get_sbits(gbc, quantization_tab[bap]);
mantissa <<= 24 - quantization_tab[bap];
break;
@@ -643,20 +680,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);
+#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]);
+#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 +838,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 +871,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];
+#endif
if (end_subband > 7)
end_subband += end_subband - 7;
dst_start_freq = dst_start_freq * 12 + 25;
@@ -843,7 +894,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,18 +915,40 @@ 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 spx_coord_exp, spx_coord_mant;
- float nratio, sblend, nblend, spx_coord;
+ INTFLOAT nratio, sblend, nblend;
+#if USE_FIXED
+ int64_t accu;
+ /* calculate blending factors */
+ bandsize = s->spx_band_sizes[bnd];
+ accu = (int64_t)((bin << 23) + (bandsize << 22)) * 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 = 0x800000;
+ 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];
@@ -883,6 +957,7 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
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 +966,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,14 +1334,24 @@ 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 */
@@ -1284,19 +1376,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 +1414,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;
@@ -1375,7 +1472,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 +1506,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 +1531,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 +1551,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 +1635,12 @@ 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);
+#if (USE_FIXED)
+ av_freep(&s->fdsp);
+#endif
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 babd0a7..a213bc0 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;
+#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;
diff --git a/libavcodec/ac3dec_data.c b/libavcodec/ac3dec_data.c
index 272a963..d0a9b1e 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 c0a584e..975b52e 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 0000000..cb3b251
--- /dev/null
+++ b/libavcodec/ac3dec_fixed.c
@@ -0,0 +1,195 @@
+/*
+ * 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 "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 0000000..e7fc5cb
--- /dev/null
+++ b/libavcodec/ac3dec_float.c
@@ -0,0 +1,91 @@
+/*
+ * 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 "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 25bd6e3..b746817 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 6ca0c5b..ed98c8c 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 13666ef..8fc9952 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
*/
@@ -273,7 +273,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 +1210,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 +1283,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 +1383,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 +2019,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);
@@ -2250,7 +2248,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 +2327,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 +2393,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 +2405,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 76b6d7f..74da612 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
*/
diff --git a/libavcodec/ac3enc_fixed.c b/libavcodec/ac3enc_fixed.c
index 2bb82ef..9d39026 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 d106d1b..fa6e509 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.
diff --git a/libavcodec/ac3enc_opts_template.c b/libavcodec/ac3enc_opts_template.c
index a08c70d..83113b8 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 79b4946..3e02408 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)
{
@@ -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 3cd07f9..d62d8bf 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 83edec5..74cbd9e 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 93bec65..9ab758b 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 6a9ebd9..7a3061b 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 1965772..3ecec01 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 7b5b33d..2aade2f 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 0c660ac..86851a3 100644
--- a/libavcodec/acelp_vectors.c
+++ b/libavcodec/acelp_vectors.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
*/
@@ -50,6 +50,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 +239,12 @@ 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)
+ do {
+ out[x] += y;
+ y *= in->pitch_fac;
+ x += in->pitch_lag;
+ } while (x < size && repeats);
}
}
@@ -234,9 +255,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 d6226bf..fae834d 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 c6bc4d0..2f95a6f 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 = nibble & ((1 << shift) - 1);
+ 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;
@@ -225,6 +250,27 @@ static inline short adpcm_ms_expand_nibble(ADPCMChannelStatus *c, int nibble)
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(predictor, -2048, 2047);
+ 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 +344,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 +373,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 +471,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 +484,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 +505,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 +520,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 +564,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 +576,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 +626,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 +667,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 +679,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 +749,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 +777,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 +856,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 +921,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 +960,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 +1067,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 +1255,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 +1265,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;
}
+ }
- *samples++ = adpcm_ima_expand_nibble(&c->status[0], lo, 3);
- *samples++ = adpcm_ima_expand_nibble(&c->status[0], hi, 3);
+ for (n = nb_samples >> (1 - st); n > 0; n--) {
+ int v = bytestream2_get_byteu(&gb);
+
+ *samples++ = adpcm_ima_qt_expand_nibble(&c->status[0 ], v >> 4, 3);
+ *samples++ = adpcm_ima_qt_expand_nibble(&c->status[st], v & 0xf, 3);
}
break;
case AV_CODEC_ID_ADPCM_CT:
@@ -1189,7 +1317,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 +1351,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 +1454,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((prev + 0x20) >> 6, -0x200000, 0x1fffff);
+
+ 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 +1530,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 +1551,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 +1567,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 16facb6..fcbb70b 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 3bc5de2..9c38360 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 a46cb5b..b179d65 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 341dda4..ea6cc23 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;
@@ -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],
diff --git a/libavcodec/adx.c b/libavcodec/adx.c
index d941d7b..cd88b16 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 9ae84dc..08f749a 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 706e242..1fa718f 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 14fddf5..5115ced 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 e730811..05e3245 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
*/
@@ -133,10 +133,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 dac9d8b..3472301 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;
diff --git a/libavcodec/alac.c b/libavcodec/alac.c
index 5272f84..aec7bb4 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 {
+ AVClass *class;
AVCodecContext *avctx;
GetBitContext gb;
int channels;
@@ -75,6 +78,9 @@ typedef struct {
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];
}
@@ -326,14 +335,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) {
@@ -358,6 +371,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);
@@ -368,16 +383,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++) {
@@ -393,6 +414,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;
}
@@ -406,7 +458,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;
@@ -418,7 +471,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;
}
@@ -447,7 +500,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;
}
@@ -459,7 +515,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]);
}
@@ -476,7 +532,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);
}
@@ -524,24 +581,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;
@@ -557,7 +616,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;
@@ -572,6 +631,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)"),
@@ -581,5 +661,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 9e13119..0bcb06c 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 ebb1f33..650d6dc 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 401f26f..ce63da6 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 8969e17..bdc4c72 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 47e0612..1fcea08 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 bd74e0b..d08abd8 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
*/
@@ -81,7 +81,9 @@ void avcodec_register_all(void)
REGISTER_HWACCEL(H264_VDA, h264_vda);
REGISTER_HWACCEL(H264_VDA_OLD, h264_vda_old);
REGISTER_HWACCEL(H264_VDPAU, h264_vdpau);
+ REGISTER_HWACCEL(MPEG1_XVMC, mpeg1_xvmc);
REGISTER_HWACCEL(MPEG1_VDPAU, mpeg1_vdpau);
+ REGISTER_HWACCEL(MPEG2_XVMC, mpeg2_xvmc);
REGISTER_HWACCEL(MPEG2_DXVA2, mpeg2_dxva2);
REGISTER_HWACCEL(MPEG2_VAAPI, mpeg2_vaapi);
REGISTER_HWACCEL(MPEG2_VDPAU, mpeg2_vdpau);
@@ -100,14 +102,18 @@ 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 (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);
@@ -118,13 +124,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);
@@ -146,7 +154,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);
@@ -157,8 +165,11 @@ 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_VDA, h264_vda);
+ REGISTER_DECODER(H264_VDPAU, h264_vdpau);
REGISTER_DECODER(HEVC, hevc);
REGISTER_DECODER(HNM4_VIDEO, hnm4_video);
REGISTER_ENCDEC (HUFFYUV, huffyuv);
@@ -170,7 +181,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);
@@ -190,14 +201,21 @@ 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);
@@ -214,12 +232,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);
@@ -228,19 +249,21 @@ 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(THEORA, theora);
- REGISTER_ENCODER(LIBTWOLAME, libtwolame);
REGISTER_DECODER(THP, thp);
REGISTER_DECODER(TIERTEXSEQVIDEO, tiertexseqvideo);
REGISTER_ENCDEC (TIFF, tiff);
@@ -254,10 +277,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);
@@ -275,14 +302,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);
@@ -291,7 +324,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);
@@ -304,11 +337,18 @@ 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_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);
@@ -321,6 +361,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);
@@ -341,14 +382,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);
@@ -367,17 +410,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);
@@ -385,7 +429,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);
@@ -396,7 +440,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);
@@ -405,6 +451,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);
@@ -412,7 +459,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);
@@ -425,16 +474,33 @@ void avcodec_register_all(void)
REGISTER_DECODER(ADPCM_VIMA, adpcm_vima);
REGISTER_DECODER(ADPCM_XA, adpcm_xa);
REGISTER_ENCDEC (ADPCM_YAMAHA, adpcm_yamaha);
+ REGISTER_DECODER(VIMA, vima);
/* subtitles */
+ REGISTER_ENCDEC (SSA, ssa);
REGISTER_ENCDEC (ASS, ass);
REGISTER_ENCDEC (DVBSUB, dvbsub);
REGISTER_ENCDEC (DVDSUB, dvdsub);
+ REGISTER_DECODER(JACOSUB, jacosub);
+ REGISTER_DECODER(MICRODVD, microdvd);
+ REGISTER_ENCDEC (MOVTEXT, movtext);
+ REGISTER_DECODER(MPL2, mpl2);
REGISTER_DECODER(PGSSUB, pgssub);
- REGISTER_DECODER(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_ENCODER(LIBFAAC, libfaac);
REGISTER_ENCDEC (LIBFDK_AAC, libfdk_aac);
REGISTER_ENCDEC (LIBGSM, libgsm);
@@ -446,19 +512,31 @@ 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, libwebp);
REGISTER_ENCODER(LIBX264, libx264);
+ REGISTER_ENCODER(LIBX264RGB, libx264rgb);
REGISTER_ENCODER(LIBX265, libx265);
REGISTER_ENCODER(LIBXAVS, libxavs);
REGISTER_ENCODER(LIBXVID, libxvid);
+ REGISTER_DECODER(LIBZVBI_TELETEXT, libzvbi_teletext);
+ REGISTER_ENCODER(LIBAACPLUS, libaacplus);
+
+ /* text */
+ REGISTER_DECODER(BINTEXT, bintext);
+ REGISTER_DECODER(XBIN, xbin);
+ REGISTER_DECODER(IDF, idf);
/* parsers */
REGISTER_PARSER(AAC, aac);
@@ -471,8 +549,10 @@ void avcodec_register_all(void)
REGISTER_PARSER(DCA, dca);
REGISTER_PARSER(DIRAC, dirac);
REGISTER_PARSER(DNXHD, dnxhd);
+ REGISTER_PARSER(DPX, dpx);
REGISTER_PARSER(DVBSUB, dvbsub);
REGISTER_PARSER(DVDSUB, dvdsub);
+ REGISTER_PARSER(DVD_NAV, dvd_nav);
REGISTER_PARSER(FLAC, flac);
REGISTER_PARSER(GSM, gsm);
REGISTER_PARSER(H261, h261);
@@ -494,6 +574,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);
@@ -503,6 +584,7 @@ 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(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 0000000..796d976
--- /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 0000000..827721e
--- /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 0000000..ded439d
--- /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 0000000..8d54807
--- /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 0000000..985182c
--- /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 0000000..df386c4
--- /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 0000000..1923ebb
--- /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 0000000..bf98495
--- /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 0000000..f545df9
--- /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 0000000..8f36019
--- /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 0000000..2399085
--- /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 0000000..126fe26
--- /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 0000000..866b762
--- /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 0000000..f05577a
--- /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 0000000..04be0ce
--- /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 b1965a8..cfece44 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 {
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);
@@ -352,13 +355,21 @@ static av_cold int read_specific_config(ALSDecContext *ctx)
if (!(sconf->chan_pos = av_malloc(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++) {
+ int idx;
+
+ idx = get_bits(&gb, chan_pos_bits);
+ if (idx >= avctx->channels) {
+ 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 +403,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 +439,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 +561,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 +584,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 +684,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 +725,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 +983,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 +991,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 +1045,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 +1151,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 +1199,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 +1224,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;
}
@@ -1237,7 +1256,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;
}
@@ -1252,14 +1271,16 @@ 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++) {
unsigned int smp;
unsigned int begin = 1;
unsigned int 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;
@@ -1291,8 +1312,6 @@ static int revert_channel_correlation(ALSDecContext *ctx, ALSBlockData *bd,
bd->raw_samples[smp] += y >> 7;
}
}
-
- dep++;
}
return 0;
@@ -1367,7 +1386,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;
}
@@ -1423,6 +1442,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;
}
@@ -1482,19 +1502,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) {
@@ -1504,7 +1528,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) {
@@ -1744,7 +1768,7 @@ 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)) {
+ (avctx->err_recognition & (AV_EF_CRCCHECK|AV_EF_CAREFUL))) {
ctx->crc_buffer = av_malloc(sizeof(*ctx->crc_buffer) *
ctx->cur_frame_length *
avctx->channels *
diff --git a/libavcodec/amr.h b/libavcodec/amr.h
index 676c963..1ac73ab 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 b7d1b89..435fd99 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 7692cf0..43ddb62 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);
@@ -400,7 +414,8 @@ static void decode_pitch_vector(AMRContext *p,
/* 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 81f8b47..8390582 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 668c84d..bf668bb 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 {
AMRWBFrame frame; ///< AMRWB parameters decoded from bitstream
@@ -84,6 +86,11 @@ typedef struct {
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 3d5affb..79a87dd 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
*/
@@ -117,10 +117,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 +126,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 556bfe4..92981cc 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 {
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 344c85b..383b7fe 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--;
@@ -541,9 +524,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 {
@@ -619,10 +606,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 < 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;
@@ -922,7 +913,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 +933,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];
@@ -1449,7 +1440,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 +1463,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
@@ -1491,7 +1483,6 @@ static int ape_decode_frame(AVCodecContext *avctx, void *data,
av_log(avctx, AV_LOG_ERROR, "Error reading frame header\n");
return AVERROR_INVALIDDATA;
}
-
}
if (!s->data) {
@@ -1516,10 +1507,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 +1552,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/arm/Makefile b/libavcodec/arm/Makefile
index 6cbb0b9..e0af6bc 100644
--- a/libavcodec/arm/Makefile
+++ b/libavcodec/arm/Makefile
@@ -19,6 +19,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
@@ -31,10 +32,10 @@ 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_DCA_DECODER) += arm/dcadsp_init_arm.o
OBJS-$(CONFIG_FLAC_DECODER) += arm/flacdsp_init_arm.o \
arm/flacdsp_arm.o
+OBJS-$(CONFIG_FLAC_ENCODER) += arm/flacdsp_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,7 +129,7 @@ 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_LLAUDDSP) += arm/lossless_audiodsp_neon.o
NEON-OBJS-$(CONFIG_DCA_DECODER) += arm/dcadsp_neon.o \
arm/synth_filter_neon.o
NEON-OBJS-$(CONFIG_RV30_DECODER) += arm/rv34dsp_neon.o
diff --git a/libavcodec/arm/aac.h b/libavcodec/arm/aac.h
index 4f143cb..cafa881 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 6326376..e04787c 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 fb00900..a93bbfe 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 ed8eb37..1aea190 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 2028d0b..1d2563d 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 a48353a..a3c32ff 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 f97b190..89d0ae8 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/asm-offsets.h b/libavcodec/arm/asm-offsets.h
index 0ea2f04..a2174b0 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 e97e804..213660d 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 ea9ec3c..74aa52a 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 af53272..f7bd162 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 dfb998d..ab32cef 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 6d9c2c3..2688d36 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 a0c0367..3b86a71 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 5081cf0..62b51fc 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 98df2c6..9fc63cb 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 6ff5f1a..fdbf86b 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 4aed576..6e87111 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 5400484..a549515 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 70580cd..cdc4136 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 c9114d4..2e09f0e 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 70e5c1c..f9076b3 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 2f749e4..b60bb9f 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 faddc00..57a8cfb 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 bc143c1..5087f5f 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 c4d8918..8b9ae2a 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 130d529..1abe45a 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 d4441da..f8861c5 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 0530cf7..df1b19c 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)
+ if (bps <= 16 && CONFIG_FLAC_DECODER)
c->lpc = ff_flac_lpc_16_arm;
}
diff --git a/libavcodec/arm/fmtconvert_init_arm.c b/libavcodec/arm/fmtconvert_init_arm.c
index 7c5bd91..37319ed 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 e11e82c..4662e28 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 4e43f42..b14af45 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/fmtconvert_vfp_armv6.S b/libavcodec/arm/fmtconvert_vfp_armv6.S
index fb12de1..7b012bc 100644
--- a/libavcodec/arm/fmtconvert_vfp_armv6.S
+++ b/libavcodec/arm/fmtconvert_vfp_armv6.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/libavcodec/arm/h264chroma_init_arm.c b/libavcodec/arm/h264chroma_init_arm.c
index 6f36553..13f7e0d 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 ee7011b..77ed3c0 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 7afd350..88dfd75 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;
+ if(chroma_format_idc == 1){
c->h264_v_loop_filter_chroma = ff_h264_v_loop_filter_chroma_neon;
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 5e75565..274a547 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 f588f3e..4f68bdb 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 bbfe63f..6ba7592 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 332f94b..4dc47ba 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 01615b5..71237be 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 6c51250..21336c6 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/hpeldsp_arm.S b/libavcodec/arm/hpeldsp_arm.S
index 0f8092e..219f793 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 a864152..5f3c774 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 f1abc32..a8bd459 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 6390660..1977b13 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 67a500d..967a8e0 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 76d4eaf..d9feadd 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 90bc3cb..cf4a6cf 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 168d64b..39cef3a 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 34f467e..057eff9 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 9012b82..d7bc5cd 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 c180d73..a6e77d6 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 8207c31..da5da06 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 251165d..3d881e1 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 8f0c49b..a3470a8 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 c94f7b6..b70c5b0 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 7095879..1911a33 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 42f3739..72c4c77 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/apedsp_init_arm.c b/libavcodec/arm/lossless_audiodsp_init_arm.c
index 47ea034..981a39a 100644
--- a/libavcodec/arm/apedsp_init_arm.c
+++ b/libavcodec/arm/lossless_audiodsp_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
*/
@@ -23,12 +23,12 @@
#include "libavutil/attributes.h"
#include "libavutil/cpu.h"
#include "libavutil/arm/cpu.h"
-#include "libavcodec/apedsp.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_apedsp_init_arm(APEDSPContext *c)
+av_cold void ff_llauddsp_init_arm(LLAudDSPContext *c)
{
int cpu_flags = av_get_cpu_flags();
diff --git a/libavcodec/arm/apedsp_neon.S b/libavcodec/arm/lossless_audiodsp_neon.S
index 7cfbf43..ba7c45f 100644
--- a/libavcodec/arm/apedsp_neon.S
+++ b/libavcodec/arm/lossless_audiodsp_neon.S
@@ -2,20 +2,20 @@
* ARM NEON optimised integer operations
* Copyright (c) 2009 Kostya 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 @@ function ff_scalarproduct_and_madd_int16_neon, export=1
vst1.16 {q10}, [r12,:128]!
subs r3, r3, #16
vst1.16 {q13}, [r12,:128]!
- bne 1b
+ bgt 1b
vpadd.s32 d16, d0, d1
vpadd.s32 d17, d2, d3
diff --git a/libavcodec/arm/mathops.h b/libavcodec/arm/mathops.h
index 45ac67d..dc57c55 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 c77be59..365c5e7 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 bfe259c..a6952fa 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 f3fe668..43f6d14 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 436e20d..fa5a823 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 819d901..eb48b38 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 cf7d367..069e76a 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 3c88021..d98f807 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 4cdd10c..34a5f61 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 49bd0bc..977abb6 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 e73aee6..98e0c8a 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 34e9cf1..918be16 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 17e3a5b..709ae6b 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 3c44cd8..88c5f4f 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 4426e15..8687d6b 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 3e1f7b5..1889d7a 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 99db501..ab0dad7 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 ab9ba3e..4bfe835 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 716a607..787bc4b 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 b77bcd7..a3b5b8e 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 4c925a4..b10ea78 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 f20769b..76d7509 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 7d01d53..781d976 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 5ce787b..8bfe90b 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 a29123f..3d4a83d 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 df3e461..c24854d 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 6bd45eb..099f88c 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 4da7967..4fb69f9 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 610397f..e66abd6 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 bf9ee3d..c630073 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 bf509ee..d1f10b7 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 6072346..79cf5d4 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 a1cde8d..c3e573c 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 d7996c1..cf25d9d 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 64078b2..a46f009 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 62bb667..5417be7 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 5d79e50..596734c 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 30f059f..cd01ac5 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 a6a97c8..5f2c759 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 9ded7a2..bb873e6 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 fa87ede..c4f4db9 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 a708759..112cbb8 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 bbd0a61..55bcce5 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
@
diff --git a/libavcodec/arm/videodsp_init_arm.c b/libavcodec/arm/videodsp_init_arm.c
index 20c6e4a..a89abb2 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 832191f..1ea1f34 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 853ba2d..f4b3d80 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 7df876c..79ce54f 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 11e1f1c..d924636 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 58bd97d..2942d48 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 6bc9456..feb1247 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 4ec41ed..ed68321 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 10b4d0f..03dd28d 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 93b2788..965342d 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 3863dc3..e7d25a4 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 0d55e0f..7281d0b 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 03100cd..1adcbbd 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 aa77dba..8b80176 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 febe4e7..a5bcd73 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 2b6c775..53f1f23 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 544332c..5319346 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 098050a..3a37cee 100644
--- a/libavcodec/ass.c
+++ b/libavcodec/ass.c
@@ -1,66 +1,75 @@
/*
- * 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: 384\r\n"
+ "PlayResY: 288\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) : "",
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 +78,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 +88,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';
+ 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(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 594b5f3..77218bf 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,7 @@
#define AVCODEC_ASS_H
#include "avcodec.h"
+#include "libavutil/bprint.h"
/**
* @name Default values for ASS style
@@ -39,6 +40,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 +70,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 +117,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 0000000..cc4f961
--- /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(*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(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(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 0000000..c912252
--- /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 7a69582..11dbde0 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);
- if (!avctx->extradata)
+ 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 caf266e..5dc3b09 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 b9e93f7..14fdf73 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 18f7a95..e2cdc81 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 9d1be5f..18e2faa 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 98baaec..2b2080e 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,9 +26,12 @@
#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"
#include "mpeg12data.h"
@@ -49,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;
@@ -57,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);
}
}
@@ -141,7 +148,7 @@ static inline void asv2_encode_block(ASV1Context *a, int16_t block[64])
a->q_intra_matrix[index + 9] + (1 << 15)) >> 16))
ccp |= 1;
- assert(i || ccp < 8);
+ 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
@@ -149,13 +156,13 @@ static inline void 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]);
}
}
}
@@ -214,13 +221,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++) {
@@ -275,17 +321,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 +
@@ -297,20 +337,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",
@@ -320,7 +358,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 },
};
@@ -335,7 +372,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 },
};
diff --git a/libavcodec/atrac.c b/libavcodec/atrac.c
index f36db9e..12e8997 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 8909323..05208bb 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 9a89785..d059d75 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
*/
@@ -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];
@@ -343,6 +341,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))) ||
diff --git a/libavcodec/atrac1data.h b/libavcodec/atrac1data.h
index d4b8cd0..62c218b 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 31f4844..d9f1348 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"
@@ -105,8 +106,8 @@ typedef struct ATRAC3Context {
int scrambled_stream;
//@}
- AtracGCContext gainc_ctx;
- FFTContext mdct_ctx;
+ AtracGCContext gainc_ctx;
+ FFTContext mdct_ctx;
FmtConvertContext fmt_conv;
AVFloatDSPContext fdsp;
} ATRAC3Context;
@@ -189,8 +190,8 @@ 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);
ff_mdct_end(&q->mdct_ctx);
@@ -409,17 +410,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])
@@ -428,8 +429,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;
}
@@ -520,7 +521,7 @@ static void reverse_matrixing(float *su1, float *su2, int *prev_code,
}
break;
default:
- assert(0);
+ av_assert1(0);
}
}
}
@@ -675,7 +676,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],
@@ -749,10 +750,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) {
@@ -773,7 +772,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;
@@ -793,6 +792,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;
@@ -803,6 +803,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 */
@@ -831,7 +835,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);
@@ -868,8 +872,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",
@@ -912,7 +918,7 @@ static av_cold int atrac3_decode_init(AVCodecContext *avctx)
avpriv_float_dsp_init(&q->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
ff_fmt_convert_init(&q->fmt_conv, avctx);
- q->units = av_mallocz(sizeof(*q->units) * avctx->channels);
+ q->units = av_mallocz_array(avctx->channels, sizeof(*q->units));
if (!q->units) {
atrac3_decode_close(avctx);
return AVERROR(ENOMEM);
@@ -928,7 +934,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 4f5c122..5d91274 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 f337fab..f7a42cc 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
diff --git a/libavcodec/atrac3plus.h b/libavcodec/atrac3plus.h
index e56c444..1b001fa 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 5026a59..2a107ee 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 ddbfb53..3699580 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
*/
@@ -67,7 +67,7 @@ typedef struct ATRAC3PContext {
static av_cold int atrac3p_decode_close(AVCodecContext *avctx)
{
- av_free(((ATRAC3PContext *)(avctx->priv_data))->ch_units);
+ av_freep(&((ATRAC3PContext *)(avctx->priv_data))->ch_units);
return 0;
}
@@ -148,6 +148,8 @@ static av_cold int atrac3p_decode_init(AVCodecContext *avctx)
return AVERROR(EINVAL);
}
+ ff_atrac3p_init_vlcs();
+
avpriv_float_dsp_init(&ctx->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
/* initialize IPQF */
@@ -164,8 +166,8 @@ 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);
+ ctx->ch_units = av_mallocz_array(ctx->num_channel_blocks, sizeof(*ctx->ch_units));
+
if (!ctx->ch_units) {
atrac3p_decode_close(avctx);
return AVERROR(ENOMEM);
@@ -383,13 +385,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 468f098..3522af1 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
*/
diff --git a/libavcodec/audio_frame_queue.c b/libavcodec/audio_frame_queue.c
index 82c16a1..4f6bccc 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;
- av_dlog(afq->avctx, "remaining delay = %d\n", afq->remaining_delay);
- av_dlog(afq->avctx, "remaining samples = %d\n", afq->remaining_samples);
- av_dlog(afq->avctx, "frames:\n");
- f = afq->frame_queue;
- while (f) {
- av_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 4a29770..2e317bb 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 0000000..5e46fae
--- /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 0000000..556ab31
--- /dev/null
+++ b/libavcodec/audioconvert.h
@@ -0,0 +1,84 @@
+/*
+ * 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
+
+/**
+ * @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 f7e6167..85b5a74 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 58205a1..b55bf85 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 a32c18b..8d0f16a 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 b3c6419..eac3fc7 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,21 +275,50 @@ 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_BRENDER_PIX= MKBETAG('B','P','I','X'),
+ AV_CODEC_ID_Y41P = MKBETAG('Y','4','1','P'),
+ AV_CODEC_ID_ESCAPE130 = MKBETAG('E','1','3','0'),
+ AV_CODEC_ID_EXR = MKBETAG('0','E','X','R'),
+ AV_CODEC_ID_AVRP = MKBETAG('A','V','R','P'),
+
+ AV_CODEC_ID_012V = MKBETAG('0','1','2','V'),
+ AV_CODEC_ID_G2M = MKBETAG( 0 ,'G','2','M'),
+ AV_CODEC_ID_AVUI = MKBETAG('A','V','U','I'),
+ AV_CODEC_ID_AYUV = MKBETAG('A','Y','U','V'),
+ AV_CODEC_ID_TARGA_Y216 = MKBETAG('T','2','1','6'),
+ AV_CODEC_ID_V308 = MKBETAG('V','3','0','8'),
+ AV_CODEC_ID_V408 = MKBETAG('V','4','0','8'),
+ AV_CODEC_ID_YUV4 = MKBETAG('Y','U','V','4'),
+ AV_CODEC_ID_SANM = MKBETAG('S','A','N','M'),
+ AV_CODEC_ID_PAF_VIDEO = MKBETAG('P','A','F','V'),
+ AV_CODEC_ID_AVRN = MKBETAG('A','V','R','n'),
+ AV_CODEC_ID_CPIA = MKBETAG('C','P','I','A'),
+ AV_CODEC_ID_XFACE = MKBETAG('X','F','A','C'),
+ AV_CODEC_ID_SGIRLE = MKBETAG('S','G','I','R'),
+ AV_CODEC_ID_MVC1 = MKBETAG('M','V','C','1'),
+ AV_CODEC_ID_MVC2 = MKBETAG('M','V','C','2'),
+ AV_CODEC_ID_SNOW = MKBETAG('S','N','O','W'),
+ AV_CODEC_ID_WEBP = MKBETAG('W','E','B','P'),
+ AV_CODEC_ID_SMVJPEG = MKBETAG('S','M','V','J'),
+ AV_CODEC_ID_HEVC = MKBETAG('H','2','6','5'),
+#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC
+ AV_CODEC_ID_VP7 = MKBETAG('V','P','7','0'),
/* various PCM "codecs" */
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
@@ -324,8 +350,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,
@@ -358,7 +387,14 @@ 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'),
+ AV_CODEC_ID_VIMA = MKBETAG('V','I','M','A'),
+ AV_CODEC_ID_ADPCM_AFC = MKBETAG('A','F','C',' '),
+ AV_CODEC_ID_ADPCM_IMA_OKI = MKBETAG('O','K','I',' '),
+ AV_CODEC_ID_ADPCM_DTK = MKBETAG('D','T','K',' '),
+ AV_CODEC_ID_ADPCM_IMA_RAD = MKBETAG('R','A','D',' '),
+ AV_CODEC_ID_ADPCM_G726LE = MKBETAG('6','2','7','G'),
/* AMR */
AV_CODEC_ID_AMR_NB = 0x12000,
@@ -438,12 +474,24 @@ 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_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.
@@ -456,10 +504,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
@@ -468,6 +539,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
};
/**
@@ -492,6 +567,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;
/**
@@ -519,6 +601,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
@@ -528,7 +620,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
@@ -552,6 +644,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
};
/**
@@ -564,6 +657,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
};
@@ -664,9 +758,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)
@@ -684,7 +782,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 */
/**
@@ -769,6 +873,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.
@@ -917,6 +1029,70 @@ enum AVPacketSideDataType {
* Stereoscopic 3D information in form of the AVStereo3D struct.
*/
AV_PKT_DATA_STEREO3D,
+
+ /**
+ * Recommmends skipping the specified number of samples
+ * @code
+ * u32le number of samples to skip from start of this packet
+ * u32le number of samples to skip from end of this packet
+ * u8 reason for start skip
+ * u8 reason for end skip (0=padding silence, 1=convergence)
+ * @endcode
+ */
+ AV_PKT_DATA_SKIP_SAMPLES=70,
+
+ /**
+ * An AV_PKT_DATA_JP_DUALMONO side data packet indicates that
+ * the packet may contain "dual mono" audio specific to Japanese DTV
+ * and if it is true, recommends only the selected channel to be used.
+ * @code
+ * u8 selected channels (0=mail/left, 1=sub/right, 2=both)
+ * @endcode
+ */
+ AV_PKT_DATA_JP_DUALMONO,
+
+ /**
+ * A list of zero terminated key/value strings. There is no end marker for
+ * the list, so it is required to rely on the side data size to stop.
+ */
+ AV_PKT_DATA_STRINGS_METADATA,
+
+ /**
+ * Subtitle event position
+ * @code
+ * u32le x1
+ * u32le y1
+ * u32le x2
+ * u32le y2
+ * @endcode
+ */
+ AV_PKT_DATA_SUBTITLE_POSITION,
+
+ /**
+ * Data found in BlockAdditional element of matroska container. There is
+ * no end marker for the data, so it is required to rely on the side data
+ * size to recognize the end. 8 byte id (as found in BlockAddId) followed
+ * by data.
+ */
+ AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
+
+ /**
+ * The optional first identifier line of a WebVTT cue.
+ */
+ AV_PKT_DATA_WEBVTT_IDENTIFIER,
+
+ /**
+ * The optional settings (rendering instructions) that immediately
+ * follow the timestamp specifier of a WebVTT cue.
+ */
+ AV_PKT_DATA_WEBVTT_SETTINGS,
+
+ /**
+ * A list of zero terminated key/value strings. There is no end marker for
+ * the list, so it is required to rely on the side data size to stop. This
+ * side data includes updated metadata which appeared in the stream.
+ */
+ AV_PKT_DATA_METADATA_UPDATE,
};
typedef struct AVPacketSideData {
@@ -933,7 +1109,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.
*
@@ -1045,6 +1221,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 {
@@ -1156,7 +1334,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.
@@ -1169,6 +1347,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.
@@ -1187,6 +1367,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.
@@ -1217,7 +1402,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
@@ -1239,7 +1424,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
*/
@@ -1248,7 +1433,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
*/
@@ -1459,6 +1644,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
@@ -1564,7 +1751,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 */
@@ -1777,7 +1964,7 @@ typedef struct AVCodecContext {
/** Field order
* - encoding: set by libavcodec
- * - decoding: Set by libavcodec
+ * - decoding: Set by user.
*/
enum AVFieldOrder field_order;
@@ -1841,7 +2028,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;
@@ -1860,9 +2047,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;
@@ -2016,6 +2204,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.
@@ -2119,7 +2309,7 @@ typedef struct AVCodecContext {
/**
* maximum bitrate
* - encoding: Set by user.
- * - decoding: unused
+ * - decoding: Set by libavcodec.
*/
int rc_max_rate;
@@ -2245,9 +2435,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;
@@ -2352,6 +2542,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
@@ -2380,17 +2571,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
@@ -2411,9 +2605,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
@@ -2434,8 +2634,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
@@ -2497,6 +2697,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).
@@ -2517,10 +2718,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
/**
@@ -2607,7 +2808,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
*/
@@ -2695,6 +2896,7 @@ 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
/**
* level
@@ -2705,21 +2907,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.
*/
@@ -2793,15 +2995,148 @@ 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.
* - encoding: unused
*/
AVRational framerate;
+
+ /**
+ * Timebase in which pkt_dts/pts and AVPacket.dts/pts are.
+ * Code outside libavcodec should access this field using:
+ * av_codec_{get,set}_pkt_timebase(avctx)
+ * - encoding unused.
+ * - decoding set by user.
+ */
+ AVRational pkt_timebase;
+
+ /**
+ * AVCodecDescriptor
+ * Code outside libavcodec should access this field using:
+ * av_codec_{get,set}_codec_descriptor(avctx)
+ * - encoding: unused.
+ * - decoding: set by libavcodec.
+ */
+ const AVCodecDescriptor *codec_descriptor;
+
+#if !FF_API_LOWRES
+ /**
+ * low resolution decoding, 1-> 1/2 size, 2->1/4 size
+ * - encoding: unused
+ * - decoding: Set by user.
+ * Code outside libavcodec should access this field using:
+ * av_codec_{get,set}_lowres(avctx)
+ */
+ int lowres;
+#endif
+
+ /**
+ * Current statistics for PTS correction.
+ * - decoding: maintained and used by libavcodec, not intended to be used by user apps
+ * - encoding: unused
+ */
+ int64_t pts_correction_num_faulty_pts; /// Number of incorrect PTS values so far
+ int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far
+ int64_t pts_correction_last_pts; /// PTS of the last frame
+ int64_t pts_correction_last_dts; /// DTS of the last frame
+
+ /**
+ * Character encoding of the input subtitles file.
+ * - decoding: set by user
+ * - encoding: unused
+ */
+ char *sub_charenc;
+
+ /**
+ * Subtitles character encoding mode. Formats or codecs might be adjusting
+ * this setting (if they are doing the conversion themselves for instance).
+ * - decoding: set by libavcodec
+ * - encoding: unused
+ */
+ int sub_charenc_mode;
+#define FF_SUB_CHARENC_MODE_DO_NOTHING -1 ///< do nothing (demuxer outputs a stream supposed to be already in UTF-8, or the codec is bitmap for instance)
+#define FF_SUB_CHARENC_MODE_AUTOMATIC 0 ///< libavcodec will select the mode itself
+#define FF_SUB_CHARENC_MODE_PRE_DECODER 1 ///< the AVPacket data needs to be recoded to UTF-8 before being fed to the decoder, requires iconv
+
+ /**
+ * Skip processing alpha if supported by codec.
+ * Note that if the format uses pre-multiplied alpha (common with VP6,
+ * and recommended due to better video quality/compression)
+ * the image will look as if alpha-blended onto a black background.
+ * However for formats that do not use pre-multiplied alpha
+ * there might be serious artefacts (though e.g. libswscale currently
+ * assumes pre-multiplied alpha anyway).
+ * Code outside libavcodec should access this field using AVOptions
+ *
+ * - decoding: set by user
+ * - encoding: unused
+ */
+ int skip_alpha;
+
+ /**
+ * Number of samples to skip after a discontinuity
+ * - decoding: unused
+ * - encoding: set by libavcodec
+ */
+ int seek_preroll;
+
+#if !FF_API_DEBUG_MV
+ /**
+ * debug motion vectors
+ * Code outside libavcodec should access this field using AVOptions
+ * - encoding: Set by user.
+ * - decoding: Set by user.
+ */
+ int debug_mv;
+#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames
+#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames
+#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames
+#endif
+
+ /**
+ * custom intra quantization matrix
+ * Code outside libavcodec should access this field using av_codec_g/set_chroma_intra_matrix()
+ * - encoding: Set by user, can be NULL.
+ * - decoding: unused.
+ */
+ uint16_t *chroma_intra_matrix;
+
+ /**
+ * dump format separator.
+ * can be ", " or "\n " or anything else
+ * Code outside libavcodec should access this field using AVOptions
+ * (NO direct access).
+ * - encoding: Set by user.
+ * - decoding: Set by user.
+ */
+ uint8_t *dump_separator;
+
+ /**
+ * ',' seperated list of allowed decoders.
+ * If NULL then all are allowed
+ * - encoding: unused
+ * - decoding: set by user through AVOPtions (NO direct access)
+ */
+ char *codec_whitelist;
} AVCodecContext;
+AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx);
+void av_codec_set_pkt_timebase (AVCodecContext *avctx, AVRational val);
+
+const AVCodecDescriptor *av_codec_get_codec_descriptor(const AVCodecContext *avctx);
+void av_codec_set_codec_descriptor(AVCodecContext *avctx, const AVCodecDescriptor *desc);
+
+int av_codec_get_lowres(const AVCodecContext *avctx);
+void av_codec_set_lowres(AVCodecContext *avctx, int val);
+
+int av_codec_get_seek_preroll(const AVCodecContext *avctx);
+void av_codec_set_seek_preroll(AVCodecContext *avctx, int val);
+
+uint16_t *av_codec_get_chroma_intra_matrix(const AVCodecContext *avctx);
+void av_codec_set_chroma_intra_matrix(AVCodecContext *avctx, uint16_t *val);
+
/**
* AVProfile.
*/
@@ -2843,7 +3178,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}
@@ -2911,6 +3246,10 @@ typedef struct AVCodec {
void (*flush)(AVCodecContext *);
} AVCodec;
+int av_codec_get_max_lowres(const AVCodec *codec);
+
+struct MpegEncContext;
+
/**
* @defgroup lavc_hwaccel AVHWAccel
* @{
@@ -2985,6 +3324,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
@@ -3014,6 +3354,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
@@ -3056,11 +3407,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;
@@ -3068,9 +3421,6 @@ typedef struct AVPicture {
* @}
*/
-#define AVPALETTE_SIZE 1024
-#define AVPALETTE_COUNT 256
-
enum AVSubtitleType {
SUBTITLE_NONE,
@@ -3109,10 +3459,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;
@@ -3211,13 +3562,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
*/
@@ -3388,6 +3755,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
@@ -3427,6 +3808,29 @@ 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);
+
+/**
+ * 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.
@@ -3451,7 +3855,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.
@@ -3573,6 +3977,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
@@ -3621,7 +4107,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.
@@ -3654,7 +4140,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
@@ -3665,7 +4151,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.
@@ -3677,9 +4163,17 @@ 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.
+ *
* @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.
*/
@@ -3737,6 +4231,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];
@@ -3909,7 +4404,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,
@@ -3943,6 +4438,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.
*
@@ -3956,11 +4481,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
@@ -3984,6 +4510,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.
*
@@ -4029,21 +4575,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.
+ *
+ * Call avpicture_free() to free it.
*
- * @see avpicture_fill()
+ * @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
*
- * @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
+ * @see av_image_alloc(), avpicture_fill()
*/
int avpicture_alloc(AVPicture *picture, enum AVPixelFormat pix_fmt, int width, int height);
@@ -4057,58 +4703,64 @@ int avpicture_alloc(AVPicture *picture, enum AVPixelFormat pix_fmt, int width, i
void avpicture_free(AVPicture *picture);
/**
- * Fill in the AVPicture fields.
- * The fields of the given AVPicture are filled in by using the 'ptr' address
- * which points to the image data buffer. Depending on the specified picture
- * format, one or multiple image data pointers and line sizes will be set.
- * If a planar format is specified, several pointers will be set pointing to
- * the different picture planes and the line sizes of the different planes
- * will be stored in the lines_sizes array.
- * Call with ptr == NULL to get the required size for the ptr buffer.
+ * 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.
*
- * To allocate the buffer and fill in the AVPicture fields in one call,
+ * 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 AVPicture whose fields are to be filled in
- * @param ptr Buffer which will contain or contains the actual image data
- * @param pix_fmt The format in which the picture data is stored.
- * @param width the width of the image in pixels
- * @param height the height of the image in pixels
- * @return size of the image data in bytes
+ * @param picture the picture to be filled in
+ * @param ptr buffer where the image data is stored, or NULL
+ * @param pix_fmt the pixel format of the image
+ * @param width the width of the image in pixels
+ * @param height the height of the image in pixels
+ * @return the size in bytes required for src, a negative error code
+ * in case of failure
+ *
+ * @see av_image_fill_arrays()
*/
-int avpicture_fill(AVPicture *picture, 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.
- * The data is stored compactly, without any gaps for alignment or padding
- * which may be applied by avpicture_fill().
*
- * @see avpicture_get_size()
+ * avpicture_get_size() can be used to compute the required size for
+ * the buffer to fill.
*
- * @param[in] src AVPicture containing image data
- * @param[in] pix_fmt The format in which the picture data is stored.
- * @param[in] width the width of the image in pixels.
- * @param[in] height the height of the image in pixels.
- * @param[out] dest A buffer into which picture data will be copied.
- * @param[in] dest_size The size of 'dest'.
- * @return The number of bytes written to dest, or a negative value (error code) on error.
+ * @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.
- * Note that this returns the size of a compact representation as generated
- * by avpicture_layout(), which can be smaller than the size required for e.g.
- * avpicture_fill().
*
- * @param pix_fmt the given picture format
- * @param width the width of the image
- * @param height the height of the image
- * @return Image data size in bytes or -1 on error (e.g. too large dimensions).
+ * @param pix_fmt picture pixel format
+ * @param width picture width
+ * @param height picture height
+ * @return the computed picture buffer size or a negative error code
+ * in case of error
+ *
+ * @see av_image_get_buffer_size().
*/
int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height);
@@ -4123,7 +4775,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);
@@ -4161,10 +4813,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
@@ -4173,29 +4836,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);
@@ -4205,7 +4847,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.
@@ -4217,9 +4859,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);
@@ -4262,7 +4921,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.
*
@@ -4275,7 +4939,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,
@@ -4301,6 +4967,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.
@@ -4340,28 +5014,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
@@ -4373,7 +5117,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
@@ -4389,7 +5133,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
@@ -4454,6 +5198,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 0000000..4b69686
--- /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 0000000..a01a6b7
--- /dev/null
+++ b/libavcodec/avdct.c
@@ -0,0 +1,134 @@
+/*
+ * 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"},
+{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;
+
+#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 0000000..380efe1
--- /dev/null
+++ b/libavcodec/avdct.h
@@ -0,0 +1,82 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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);
+} 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 513f57e..2200f37 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);
diff --git a/libavcodec/avfft.h b/libavcodec/avfft.h
index e2e727d..0c0f9b8 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 25eabdb..3c26046 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,150 @@ uint8_t *av_packet_get_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
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 +533,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 a50bbc4..0484dc3 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,71 +31,24 @@
#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)
{
- int ret;
-
- if ((ret = av_image_check_size(width, height, 0, NULL)) < 0)
- return ret;
-
- if ((ret = av_image_fill_linesizes(picture->linesize, pix_fmt, width)) < 0)
- return ret;
-
- return av_image_fill_pointers(picture->data, pix_fmt,
- height, ptr, picture->linesize);
+ 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)
{
- int i, j, nb_planes = 0, linesizes[4];
- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
- int size = avpicture_get_size(pix_fmt, width, height);
-
- if (size > dest_size || size < 0)
- return AVERROR(EINVAL);
-
- for (i = 0; i < desc->nb_components; i++)
- nb_planes = FFMAX(desc->comp[i].plane, nb_planes);
-
- nb_planes++;
-
- av_image_fill_linesizes(linesizes, pix_fmt, width);
- for (i = 0; i < nb_planes; i++) {
- int h, shift = (i == 1 || i == 2) ? desc->log2_chroma_h : 0;
- const unsigned char *s = src->data[i];
- h = (height + (1 << shift) - 1) >> shift;
-
- for (j = 0; j < h; j++) {
- memcpy(dest, s, linesizes[i]);
- dest += linesizes[i];
- s += src->linesize[i];
- }
- }
-
- if (desc->flags & AV_PIX_FMT_FLAG_PAL)
- memcpy((unsigned char *)(((size_t)dest + 3) & ~3),
- src->data[1], 256 * 4);
-
- return size;
+ return av_image_copy_to_buffer(dest, dest_size,
+ (const uint8_t * const*)src->data, src->linesize,
+ pix_fmt, width, height, 1);
}
int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height)
{
- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
- AVPicture dummy_pict;
- int ret;
-
- if (!desc)
- return AVERROR(EINVAL);
- if ((ret = av_image_check_size(width, height, 0, NULL)) < 0)
- return ret;
- if (desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL)
- // do not include palette for these pseudo-paletted formats
- return width * height;
- return avpicture_fill(&dummy_pict, NULL, pix_fmt, width, height);
+ return av_image_get_buffer_size(pix_fmt, width, height, 1);
}
int avpicture_alloc(AVPicture *picture,
@@ -113,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 528b7ad..85f42b5 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 0000000..7a50a5c
--- /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 eb2da66..976d325 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
*/
@@ -58,12 +58,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;
@@ -85,8 +83,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 0000000..7fb644c
--- /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 0000000..700b8cb
--- /dev/null
+++ b/libavcodec/avuienc.c
@@ -0,0 +1,113 @@
+/*
+ * 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"
+
+static av_cold int avui_encode_init(AVCodecContext *avctx)
+{
+ avctx->coded_frame = av_frame_alloc();
+
+ 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->coded_frame) {
+ av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
+ return AVERROR(ENOMEM);
+ }
+ if (!(avctx->extradata = av_mallocz(24 + FF_INPUT_BUFFER_PADDING_SIZE)))
+ return AVERROR(ENOMEM);
+ avctx->extradata_size = 24;
+ 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;
+ }
+
+
+ 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_freep(&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 7e93a27..37cd22e 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 5cbbdfd..d5b5d0a 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 75b6710..77bca49 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 0000000..afb3461
--- /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 ad8baae..1a6817b 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 3d5b490..4893736 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 e34585b..bc3d25c 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 eb9cd0a..064ee7e 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
*/
@@ -82,14 +82,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
@@ -306,9 +306,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 */
@@ -317,10 +319,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 3da6b7e..57619be 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 0dfe12c..9d70e23 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 418afb9..f319d1f 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 0000000..97fceb1
--- /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 0000000..21428ba
--- /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 27e658b..8018489 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 8e9f657..d041643 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 "mathops.h"
#include "get_bits.h"
@@ -106,17 +108,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;
}
@@ -162,19 +163,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);
av_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++) {
@@ -192,8 +190,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];
av_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;
}
@@ -228,11 +227,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;
}
@@ -263,7 +268,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,
@@ -271,42 +276,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;
- }
- av_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);
@@ -317,15 +336,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 f524d3e..3275326 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));
@@ -52,13 +54,14 @@ AVBitStreamFilterContext *av_bitstream_filter_init(const char *name)
bsf->priv_data_size ? av_mallocz(bsf->priv_data_size) : NULL;
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 e3d2ca1..f5259f6 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 32c671c..c7ad265 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 15c33a0..458fd0c 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,7 +212,7 @@ 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",
@@ -246,20 +248,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 +298,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 +328,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 a472f59..fb21090 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 b85dd8b..c9493dc 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 a14fc61..2a1956d 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 0f8c224..0e473df 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 ebc8e7a..5143b2a 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"
@@ -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 25aebed..02d922f 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 6700cfd..a6e1ec0 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 fd10a88..f167d77 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 3eab225..c2cb601 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 c7cc682..ad3fa3b 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 b6f56f0..81a75dd 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,160 @@ 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;
+}
+
+#ifdef TEST
+#define SIZE 10240
+
+#include "libavutil/lfg.h"
+#include "avcodec.h"
- 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;
+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);
+ }
+}
- 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;
+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;
+ 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++){
+START_TIMER
+ put_cabac_bypass(&c, r[i]&1);
+STOP_TIMER("put_cabac_bypass")
+ }
+
+ for(i=0; i<SIZE; i++){
+START_TIMER
+ put_cabac(&c, state, r[i]&1);
+STOP_TIMER("put_cabac")
+ }
+
+ put_cabac_terminate(&c, 1);
+
+ ff_init_cabac_decoder(&c, b, SIZE);
+
+ memset(state, 0, sizeof(state));
+
+ for(i=0; i<SIZE; i++){
+START_TIMER
+ if( (r[i]&1) != get_cabac_bypass(&c) )
+ av_log(NULL, AV_LOG_ERROR, "CABAC bypass failure at %d\n", i);
+STOP_TIMER("get_cabac_bypass")
+ }
+
+ for(i=0; i<SIZE; i++){
+START_TIMER
+ if( (r[i]&1) != get_cabac_noinline(&c, state) )
+ av_log(NULL, AV_LOG_ERROR, "CABAC failure at %d\n", i);
+STOP_TIMER("get_cabac")
+ }
+ if(!get_cabac_terminate(&c))
+ av_log(NULL, AV_LOG_ERROR, "where's the Terminator?\n");
+
+ return 0;
+}
+
+#endif /* TEST */
diff --git a/libavcodec/cabac.h b/libavcodec/cabac.h
index 426f338..f9eafed 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 4b8f1bc..15dba29 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 0000000..ed54447
--- /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 0000000..a637912
--- /dev/null
+++ b/libavcodec/cabac_tablegen.h
@@ -0,0 +1,108 @@
+/*
+ * Header file for hardcoded CABAC table
+ *
+ * Copyright (c) 2014 Reimar Döffinger <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/cavs.c b/libavcodec/cavs.c
index 2be50a7..45d815a 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
*/
@@ -74,15 +74,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;
@@ -148,6 +149,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]);
}
@@ -160,6 +163,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]);
}
@@ -233,9 +238,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 {
@@ -527,7 +537,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 + (src->x >> 31)) >> 9;
*d_y = (src->y * distp * den + 256 + (src->y >> 31)) >> 9;
@@ -574,7 +584,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 ||
@@ -704,7 +714,7 @@ int ff_cavs_next_mb(AVSContext *h)
*
****************************************************************************/
-void ff_cavs_init_pic(AVSContext *h)
+int ff_cavs_init_pic(AVSContext *h)
{
int i;
@@ -725,6 +735,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;
}
/*****************************************************************************
@@ -742,16 +754,16 @@ void 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));
}
@@ -810,16 +822,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 cfae055..12f3962 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,7 +271,7 @@ 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);
+int ff_cavs_init_pic(AVSContext *h);
void 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 84f647c..6067a39 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 4e4a131..2835a4b 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 d0c72a7..42306cc 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,32 @@ 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);
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 +591,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 +603,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 +674,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 +761,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 +798,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 +807,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 +846,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 +855,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 +894,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 +908,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 +1012,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 +1042,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) {
@@ -1093,6 +1130,10 @@ static int decode_seq_header(AVSContext *h)
"Width/height changing in CAVS");
return AVERROR_PATCHWELCOME;
}
+ if (width <= 0 || height <= 0) {
+ av_log(h->avctx, AV_LOG_ERROR, "Dimensions invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
h->width = width;
h->height = height;
@@ -1139,12 +1180,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 +1213,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 cc78989..91f6d73 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 248afd5..847f5c4 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 e92c0f1..e0a8e63 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 60d900a..d8c77c2 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/cdgraphics.c b/libavcodec/cdgraphics.c
index c3e42e7..340df44 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 80a3671..13ad57c 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);
}
}
@@ -115,6 +123,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 +264,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 +289,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 61474f5..a81fd88 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 c328258..f644ec3 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 a9ebef6..a96b1ae 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 ed3f8c0..18d3ad9 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 2c63ff2..023a86b 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 2149cfd..3f5281a 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 9ed7496..2b93fa9 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 caf14cb..f651c48 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 {
- 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 0000000..7277345
--- /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 e74d1fa..68c8771 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 2c31555..c672f80 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 f081c68..9c710bb 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
*/
@@ -412,11 +412,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)
@@ -428,11 +425,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)
@@ -443,11 +437,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 89f5c81..c49e903 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 98f3c4e..bf5f7bf 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);
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index c21c57e..eeb4505 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,
},
{
@@ -1161,7 +1265,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,
},
{
@@ -1178,6 +1282,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,
@@ -1200,6 +1305,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,
@@ -1214,6 +1320,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,
@@ -1235,6 +1342,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,
@@ -1277,6 +1385,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_TIFF,
@@ -1284,6 +1393,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,
@@ -1306,6 +1416,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,
@@ -1327,6 +1438,7 @@ 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"),
},
/* various PCM "codecs" */
@@ -1376,13 +1488,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,
@@ -1455,10 +1569,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,
},
{
@@ -1529,7 +1650,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,
@@ -1751,6 +1872,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",
@@ -2251,6 +2407,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",
@@ -2292,6 +2466,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 */
{
@@ -2299,42 +2515,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,
@@ -2346,7 +2576,277 @@ 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,
+ },
+
+ {
+ .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,
+ },
+ {
+ .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 056c7d9..0cc01d0 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;
@@ -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;
}
@@ -1046,7 +1053,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 +1087,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 +1199,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;
}
}
diff --git a/libavcodec/cook_parser.c b/libavcodec/cook_parser.c
index f140e90..6dbbfd8 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 c4c26fa..7b9cba3 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 10718cc..9ed451f 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 92b8295..9af83f4 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 0000000..9036cb3
--- /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 0000000..001afa4
--- /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 9ae7e33..e875dd7 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 {
+ 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 f628ba1..6e8e461 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/dca.c b/libavcodec/dca.c
index 6cc74ba..22be88f 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
*/
@@ -31,7 +35,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 0037de2..70dade5 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
*/
@@ -42,7 +42,7 @@ 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);
#endif /* AVCODEC_DCA_H */
diff --git a/libavcodec/dca_parser.c b/libavcodec/dca_parser.c
index 276d873..9fa6d0d 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
*/
@@ -37,7 +37,7 @@ typedef struct DCAParseContext {
#define IS_MARKER(state, i, buf, buf_size) \
((state == DCA_MARKER_14B_LE && (i < buf_size - 2) && (buf[i + 1] & 0xF0) == 0xF0 && buf[i + 2] == 0x07) || \
(state == DCA_MARKER_14B_BE && (i < buf_size - 2) && buf[i + 1] == 0x07 && (buf[i + 2] & 0xF0) == 0xF0) || \
- state == DCA_MARKER_RAW_LE || state == DCA_MARKER_RAW_BE)
+ state == DCA_MARKER_RAW_LE || state == DCA_MARKER_RAW_BE || state == DCA_HD_MARKER)
/**
* Find the end of the current frame in the bitstream.
@@ -58,11 +58,7 @@ static int dca_find_frame_end(DCAParseContext *pc1, const uint8_t *buf,
for (i = 0; i < buf_size; i++) {
state = (state << 8) | buf[i];
if (IS_MARKER(state, i, buf, buf_size)) {
- if (pc1->lastmarker && state == pc1->lastmarker) {
- start_found = 1;
- i++;
- break;
- } else if (!pc1->lastmarker) {
+ if (!pc1->lastmarker || state == pc1->lastmarker || pc1->lastmarker == DCA_HD_MARKER) {
start_found = 1;
pc1->lastmarker = state;
i++;
@@ -77,7 +73,7 @@ static int dca_find_frame_end(DCAParseContext *pc1, const uint8_t *buf,
state = (state << 8) | buf[i];
if (state == DCA_HD_MARKER && !pc1->hd_pos)
pc1->hd_pos = pc1->size;
- if (state == pc1->lastmarker && IS_MARKER(state, i, buf, buf_size)) {
+ if (IS_MARKER(state, i, buf, buf_size) && (state == pc1->lastmarker || pc1->lastmarker == DCA_HD_MARKER)) {
if (pc1->framesize > pc1->size)
continue;
pc->frame_start_found = 0;
@@ -110,7 +106,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/dcadata.h b/libavcodec/dcadata.h
index 7c37d3a..582f14d 100644
--- a/libavcodec/dcadata.h
+++ b/libavcodec/dcadata.h
@@ -3,20 +3,20 @@
* 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
*/
diff --git a/libavcodec/dcadec.c b/libavcodec/dcadec.c
index 8ca8c34..300dc2e 100644
--- a/libavcodec/dcadec.c
+++ b/libavcodec/dcadec.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
*/
@@ -45,7 +45,6 @@
#include "get_bits.h"
#include "internal.h"
#include "mathops.h"
-#include "put_bits.h"
#include "synth_filter.h"
#if ARCH_ARM
@@ -60,6 +59,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)
enum DCAMode {
DCA_MONO = 0,
@@ -95,6 +96,68 @@ enum DCAExSSSpeakerMask {
DCA_EXSS_REAR_HIGH_LEFT_RIGHT = 0x8000,
};
+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,
+};
+
+static const uint32_t 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 */
+};
+
enum DCAExtensionMask {
DCA_EXT_CORE = 0x001, ///< core in core substream
DCA_EXT_XXCH = 0x002, ///< XXCh channels extension in core substream
@@ -286,7 +349,7 @@ static av_always_inline int get_bitalloc(GetBitContext *gb, BitAlloc *ba,
}
typedef struct {
- AVClass *class; ///< class for AVOptions
+ const AVClass *class; ///< class for AVOptions
AVCodecContext *avctx;
/* Frame header */
int frame_type; ///< type of the current frame
@@ -386,6 +449,20 @@ typedef struct {
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;
+
/* ExSS header parser */
int static_fields; ///< static fields present
int mix_metadata; ///< mixing metadata present
@@ -402,6 +479,8 @@ typedef struct {
FmtConvertContext fmt_conv;
} DCAContext;
+static float dca_dmix_code(unsigned code);
+
static const uint16_t dca_vlc_offs[] = {
0, 512, 640, 768, 1282, 1794, 2436, 3080, 3770, 4454, 5364,
5372, 5380, 5388, 5392, 5396, 5412, 5420, 5428, 5460, 5492, 5508,
@@ -472,16 +551,95 @@ 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;
+ }
- s->total_channels = get_bits(&s->gb, 3) + 1 + base_channel;
+ nchans = get_bits(&s->gb, 3) + 1;
+ 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;
@@ -517,9 +675,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;
@@ -591,6 +756,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;
}
@@ -652,7 +818,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)
@@ -827,6 +993,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]);
@@ -838,8 +1005,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 = 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 = scale_factor_quant7[quant7];
/* Quantization step size * scale factor */
lfe_scale = 0.035 * s->lfe_scale_factor;
@@ -1005,7 +1176,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:
@@ -1197,7 +1368,7 @@ static int dca_subsubframe(DCAContext *s, int base_channel, int block_index)
else if (s->predictor_history)
sum += 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);
}
}
}
@@ -1206,7 +1377,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;
@@ -1255,7 +1426,7 @@ static int dca_filter_channels(DCAContext *s, int block_index)
if (s->lfe) {
lfe_interpolation_fir(s, s->lfe, 2 * s->lfe,
s->lfe_data + 2 * s->lfe * (block_index + 4),
- s->samples_chanptr[dca_lfe_index[s->amode]]);
+ s->samples_chanptr[s->lfe_index]);
/* Outputs 20bits pcm samples */
}
@@ -1613,26 +1784,246 @@ static int dca_exss_parse_asset_header(DCAContext *s)
return 0;
}
+static int 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;
+ }
+
+ /* 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;
+
+ if (s->scalefactor_huffman[chan_base+i] == 6) {
+ scale_table = scale_factor_quant7;
+ } else {
+ scale_table = scale_factor_quant6;
+ }
+
+ nbits = anctemp[i];
+
+ for(j = 0; j < active_bands[chset][i]; j++) {
+ if(abits_high[i][j] > 0) {
+ scale_table_high[i][j][0] =
+ scale_table[get_bits(&s->gb, nbits)];
+
+ if(xbr_tmode && s->transition_mode[i][j]) {
+ scale_table_high[i][j][1] =
+ scale_table[get_bits(&s->gb, nbits)];
+ }
+ }
+ }
+ }
+ }
+
+ /* 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 = 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 */
+static int 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;
+}
+
/**
* Parse extension substream header (HD)
*/
static void dca_exss_parse_header(DCAContext *s)
{
+ int asset_size[8];
int ss_index;
int blownup;
int num_audiop = 1;
int num_assets = 1;
int active_ss_mask[8];
int i, j;
+ int start_posn;
+ int hdrsize;
+ uint32_t mkr;
if (get_bits_left(&s->gb) < 52)
return;
+ start_posn = get_bits_count(&s->gb) - 32;
+
skip_bits(&s->gb, 8); // user data
ss_index = get_bits(&s->gb, 2);
blownup = get_bits1(&s->gb);
- skip_bits(&s->gb, 8 + 4 * blownup); // header_size
+ hdrsize = get_bits(&s->gb, 8 + 4 * blownup) + 1; // header_size
skip_bits(&s->gb, 16 + 4 * blownup); // hd_size
s->static_fields = get_bits1(&s->gb);
@@ -1684,8 +2075,10 @@ static void dca_exss_parse_header(DCAContext *s)
}
}
+ av_assert0(num_assets > 0); // silence a warning
+
for (i = 0; i < num_assets; i++)
- skip_bits_long(&s->gb, 16 + 4 * blownup); // asset size
+ asset_size[i] = get_bits_long(&s->gb, 16 + 4 * blownup);
for (i = 0; i < num_assets; i++) {
if (dca_exss_parse_asset_header(s))
@@ -1694,13 +2087,38 @@ static void dca_exss_parse_header(DCAContext *s)
/* not parsed further, we were only interested in the extensions mask
* from the asset header */
+
+ j = get_bits_count(&s->gb);
+ if (start_posn + hdrsize * 8 > j)
+ skip_bits_long(&s->gb, start_posn + hdrsize * 8 - j);
+
+ for (i = 0; i < num_assets; i++) {
+ start_posn = get_bits_count(&s->gb);
+ mkr = get_bits_long(&s->gb, 32);
+
+ /* parse extensions that we know about */
+ if (mkr == 0x655e315e) {
+ dca_xbr_parse_frame(s);
+ } else if (mkr == 0x47004a03) {
+ dca_xxch_decode_frame(s);
+ s->core_ext_mask |= DCA_EXT_XXCH; /* xxx use for chan reordering */
+ } else {
+ av_log(s->avctx, AV_LOG_DEBUG,
+ "DTS-ExSS: unknown marker = 0x%08x\n", mkr);
+ }
+
+ /* skip to end of block */
+ j = get_bits_count(&s->gb);
+ if (start_posn + asset_size[i] * 8 > j)
+ skip_bits_long(&s->gb, start_posn + asset_size[i] * 8 - j);
+ }
}
static float dca_dmix_code(unsigned code)
{
int sign = (code >> 8) - 1;
code &= 0xff;
- return ((dca_dmixtable[code] ^ sign) - sign) * (1.0 / (1U << 15));
+ return ((dca_dmixtable[code] ^ sign) - sign) * (1.0 / (1 << 15));
}
/**
@@ -1713,18 +2131,29 @@ 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;
s->xch_present = 0;
- s->dca_buffer_size = ff_dca_convert_bitstream(buf, buf_size, s->dca_buffer,
+ s->dca_buffer_size = avpriv_dca_convert_bitstream(buf, buf_size, 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");
@@ -1751,6 +2180,49 @@ 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(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(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] = dca_default_coeffs[am][i][0];
+ s->downmix_coef[i][1] = dca_default_coeffs[am][i][1];
+ }
+ }
+ av_dlog(s->avctx, "Stereo downmix coeffs:\n");
+ for (i = 0; i < num_core_channels + !!s->lfe; i++) {
+ av_dlog(s->avctx, "L, input channel %d = %f\n", i,
+ s->downmix_coef[i][0]);
+ av_dlog(s->avctx, "R, input channel %d = %f\n", i,
+ s->downmix_coef[i][1]);
+ }
+ av_dlog(s->avctx, "\n");
+ }
+
if (s->ext_coding)
s->core_ext_mask = dca_ext_audio_descr_mask[s->ext_descr];
else
@@ -1760,7 +2232,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);
@@ -1797,8 +2269,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))) {
@@ -1814,6 +2291,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;
+ dca_xxch_decode_frame(s);
break;
case 0x1d95f262: {
@@ -1853,107 +2331,154 @@ 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 = 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 = dca_channel_reorder_lfe_xch[s->amode];
+ avctx->channel_layout |= AV_CH_BACK_CENTER;
+ if (s->lfe) {
+ avctx->channel_layout |= AV_CH_LOW_FREQUENCY;
+ s->channel_order_tab = dca_channel_reorder_lfe_xch[s->amode];
+ } else {
+ s->channel_order_tab = 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 = 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 = dca_channel_reorder_lfe[s->amode];
+ } else
+ s->channel_order_tab = 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 = 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 = dca_channel_reorder_lfe[s->amode];
- } else
- s->channel_order_tab = 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 |= 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(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(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] = dca_default_coeffs[am][i][0];
- s->downmix_coef[i][1] = 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 = map_xxch_to_native[i];
+ posn = av_popcount(channel_layout & (lavc - 1));
+ s->xxch_order_tab[j++] = posn;
+ }
}
+
}
- av_dlog(s->avctx, "Stereo downmix coeffs:\n");
- for (i = 0; i < num_core_channels + !!s->lfe; i++) {
- av_dlog(s->avctx, "L, input channel %d = %f\n", i,
- s->downmix_coef[i][0]);
- av_dlog(s->avctx, "R, input channel %d = %f\n", i,
- s->downmix_coef[i][1]);
- }
- av_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;
+ }
+
+ 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;
}
- avctx->channels = channels;
/* get output buffer */
frame->nb_samples = 256 * (s->sample_blocks / 8);
- 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 */
@@ -1997,6 +2522,53 @@ FF_ENABLE_DEPRECATION_WARNINGS
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;
+ }
+
+ }
}
/* update lfe history */
@@ -2080,6 +2652,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 34b5da2..b32d962 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 0fa75a5..abf577b 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 0000000..905cdc9
--- /dev/null
+++ b/libavcodec/dcaenc.c
@@ -0,0 +1,975 @@
+/*
+ * 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 DCA_SUBBANDS 32
+#define SUBFRAMES 1
+#define SUBSUBFRAMES 2
+#define SUBBAND_SAMPLES (SUBFRAMES * SUBSUBFRAMES * 8)
+#define AUBANDS 25
+
+typedef struct DCAContext {
+ 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][DCA_SUBBANDS][MAX_CHANNELS];
+ int32_t quantized[SUBBAND_SAMPLES][DCA_SUBBANDS][MAX_CHANNELS];
+ int32_t peak_cb[DCA_SUBBANDS][MAX_CHANNELS];
+ int32_t downsampled_lfe[DCA_LFE_SAMPLES];
+ int32_t masking_curve_cb[SUBSUBFRAMES][256];
+ int abits[DCA_SUBBANDS][MAX_CHANNELS];
+ int scale_factor[DCA_SUBBANDS][MAX_CHANNELS];
+ softfloat quant[DCA_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;
+} DCAContext;
+
+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)
+{
+ DCAContext *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; dca_bit_rates[i] < avctx->bit_rate; i++)
+ ;
+ c->bitrate_index = i;
+ avctx->bit_rate = 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 * lfe_fir_64[i]);
+ lfe_fir_64i[511 - i] = (int32_t)(0x01ffffff * lfe_fir_64[i]);
+ }
+
+ for (i = 0; i < 512; i++) {
+ band_interpolation[0][i] = (int32_t)(0x1000000000ULL * fir_32bands_perfect[i]);
+ band_interpolation[1][i] = (int32_t)(0x1000000000ULL * 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 = 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 = 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(DCAContext *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(DCAContext *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)(DCAContext *c, int band1, int band2, int f,
+ int32_t spectrum1, int32_t spectrum2, int channel,
+ int32_t * arg);
+
+static void walk_band_low(DCAContext *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(DCAContext *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(DCAContext *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(DCAContext *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(DCAContext *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(DCAContext *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(DCAContext *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(DCAContext *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(DCAContext *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(DCAContext *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(DCAContext *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(DCAContext *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, DCA_SUBBANDS - 2);
+
+ /* High frequency VQ start subband */
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ put_bits(&c->pb, 5, DCA_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(DCAContext *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;
+ int32_t mask = (1 << bits) - 1;
+ put_bits(&c->pb, bits, c->quantized[ss * 8 + i][band][ch] & mask);
+ }
+ }
+}
+
+static void put_subframe(DCAContext *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 < DCA_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 < DCA_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 < DCA_SUBBANDS; band++)
+ put_bits(&c->pb, 1, 0); /* codebook A4 */
+ }
+
+ /* Scale factors */
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ for (band = 0; band < DCA_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 < DCA_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)
+{
+ DCAContext *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(DCAContext),
+ .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 0000000..0443ca6
--- /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 79be493..9388b63 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 f337576..30eca3e 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){
+ DECLARE_ALIGNED(16, static 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 */
@@ -84,8 +98,8 @@ static const struct algo idct_tab[] = {
#elif ARCH_X86
#include "x86/dct-test.c"
#else
-static const struct algo fdct_tab_arch[] = { 0 };
-static const struct algo idct_tab_arch[] = { 0 };
+static const struct algo fdct_tab_arch[] = { { 0 } };
+static const struct algo idct_tab_arch[] = { { 0 } };
#endif
#define AANSCALE_BITS 12
@@ -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 4dbbff8..9cabc4f 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 4a31f54..05297ba 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 110338d..f4b2471 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 64efe8b..9025d5e 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 ef37ce9..597c9bb 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 272e0db..fb53d53 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 ae3dec5..851014b 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 a93b70d..f6fde88 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 6fa4edc..f13291e 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 5e13a84..07db919 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 e5b79b0..b0f955b 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 0000000..bf91392
--- /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 0000000..a1fa96b
--- /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 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 0000000..96d8bae
--- /dev/null
+++ b/libavcodec/dirac_dwt.c
@@ -0,0 +1,571 @@
+/*
+ * 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 inline int mirror(int v, int m)
+{
+ while ((unsigned)v > (unsigned)m) {
+ v = -v;
+ if (v < 0)
+ v += 2 * m;
+ }
+ return v;
+}
+
+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 + mirror(y+1, height-1)*stride;
+ b[3] = d->buffer + 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 + mirror(y+3, height-1)*stride;
+ b[5] = d->buffer + 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 + mirror(-3-1, height-1)*stride;
+ cs->b[1] = buffer + mirror(-3 , height-1)*stride;
+ cs->b[2] = buffer + mirror(-3+1, height-1)*stride;
+ cs->b[3] = buffer + 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 + mirror(-1-1, height-1)*stride;
+ cs->b[1] = buffer + 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 -1;
+ }
+
+ 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 0000000..e5e447b
--- /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 5c9d266..45ded5a 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 0000000..aa8e2b0
--- /dev/null
+++ b/libavcodec/diracdec.c
@@ -0,0 +1,2002 @@
+/*
+ * 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 void 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));
+
+ 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;
+ bufsize -= bytes*8;
+ }
+
+ 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);
+}
+
+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 };
+ static const uint8_t default_bsep[] = { 4, 8, 12, 16 };
+
+ 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 -1;
+ }
+
+ 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 = default_bsep[idx-1];
+ s->plane[0].ybsep = default_bsep[idx-1];
+ }
+ /*[DIRAC_STD] 11.2.4 motion_data_dimensions()
+ Calculated in function dirac_unpack_block_motion_data */
+
+ 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 -1;
+ }
+ 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 -1;
+ }
+ 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 -1;
+ }
+
+ /*[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 -1;
+ }
+
+ /*[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 -1;
+ }
+
+ /* [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 -1; \
+ }\
+ 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 -1;
+ 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;
+
+ 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)
+ decode_lowdelay(s);
+ }
+
+ 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() */
+ }
+ if (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))
+ return -1;
+
+ 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)
+{
+ int retire, picnum;
+ int i, j, refnum, refdist;
+ 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);
+ refdist = INT_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;
+ }
+ }
+
+ /* retire the reference frames that are not used anymore */
+ if (s->current_picture->avframe->reference) {
+ retire = picnum + dirac_get_se_golomb(gb);
+ 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) {
+ if (dirac_unpack_prediction_parameters(s)) /* [DIRAC_STD] 11.2 Picture Prediction Data. picture_prediction() */
+ return -1;
+ if (dirac_unpack_block_motion_data(s)) /* [DIRAC_STD] 12. Block motion data syntax */
+ return -1;
+ }
+ if (dirac_unpack_idwt_params(s)) /* [DIRAC_STD] 11.3 Wavelet transform data */
+ return -1;
+
+ 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 = buf[4];
+ unsigned tmp;
+
+ if (size < DATA_UNIT_HEADER_SIZE)
+ return -1;
+
+ 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 */
+ if (avpriv_dirac_parse_sequence_header(avctx, &s->gb, &s->source))
+ return -1;
+
+ avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift);
+
+ if (alloc_sequence_buffers(s))
+ return -1;
+
+ 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 -1;
+ }
+
+ /* 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 -1;
+ }
+
+ 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 -1;
+ }
+ 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() */
+ if (dirac_decode_picture_header(s))
+ return -1;
+
+ /* [DIRAC_STD] 13.0 Transform data syntax. transform_data() */
+ if (dirac_decode_frame_internal(s))
+ return -1;
+ }
+ 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, data_unit_size, buf_idx = 0;
+ int ret;
+
+ /* 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 (buf_idx + data_unit_size > buf_size || !data_unit_size) {
+ if(buf_idx + data_unit_size > buf_size)
+ 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() */
+ if (dirac_decode_data_unit(avctx, buf+buf_idx, data_unit_size))
+ {
+ av_log(s->avctx, AV_LOG_ERROR,"Error in dirac_decode_data_unit\n");
+ return -1;
+ }
+ 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 0000000..3b8c39d
--- /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
+
+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 0000000..613ca5b
--- /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 0de3561..fffb98f 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 0edaeec..7ea9191 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[] = {
@@ -296,63 +298,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,
- 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,
-};
-
-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] = {
@@ -445,63 +427,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] = {
@@ -594,63 +556,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,
+ 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, 1, 1, 1, 1, 1, 1, 1, 1, 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_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] = {
@@ -721,61 +663,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,
+ 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, 1, 1, 1, 1, 1, 1, 1, 1, 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,
@@ -865,63 +788,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,
+ 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 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] = {
@@ -1014,143 +917,134 @@ 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,
+ 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, 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,
- 1, 1, 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,
};
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 } },
+ { 350, 390, 440, 730, 880 },
+ { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } },
};
int ff_dnxhd_get_cid_table(int cid)
@@ -1162,6 +1056,14 @@ 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 ff_dnxhd_find_cid(AVCodecContext *avctx, int bit_depth)
{
int i, j;
@@ -1173,7 +1075,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;
}
@@ -1181,3 +1083,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 66b0349..d5629e2 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,24 @@ 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);
#endif /* AVCODEC_DNXHDDATA_H */
diff --git a/libavcodec/dnxhddec.c b/libavcodec/dnxhddec.c
index ca67990..0680074 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];
ff_free_vlc(&ctx->ac_vlc);
@@ -132,7 +142,7 @@ static int dnxhd_decode_header(DNXHDContext *ctx, AVFrame *frame,
ctx->is_444 = 0;
if (buf[0x4] == 0x2) {
- ctx->avctx->pix_fmt = AV_PIX_FMT_YUV444P10;
+ ctx->pix_fmt = AV_PIX_FMT_YUV444P10;
ctx->avctx->bits_per_raw_sample = 10;
if (ctx->bit_depth != 10) {
ff_blockdsp_init(&ctx->bdsp, ctx->avctx);
@@ -142,7 +152,7 @@ static int dnxhd_decode_header(DNXHDContext *ctx, AVFrame *frame,
}
ctx->is_444 = 1;
} else if (buf[0x21] & 0x40) {
- ctx->avctx->pix_fmt = AV_PIX_FMT_YUV422P10;
+ ctx->pix_fmt = AV_PIX_FMT_YUV422P10;
ctx->avctx->bits_per_raw_sample = 10;
if (ctx->bit_depth != 10) {
ff_blockdsp_init(&ctx->bdsp, ctx->avctx);
@@ -151,7 +161,7 @@ static int dnxhd_decode_header(DNXHDContext *ctx, AVFrame *frame,
ctx->decode_dct_block = dnxhd_decode_dct_block_10;
}
} else {
- ctx->avctx->pix_fmt = AV_PIX_FMT_YUV422P;
+ ctx->pix_fmt = AV_PIX_FMT_YUV422P;
ctx->avctx->bits_per_raw_sample = 8;
if (ctx->bit_depth != 8) {
ff_blockdsp_init(&ctx->bdsp, ctx->avctx);
@@ -191,7 +201,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));
av_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\n");
return AVERROR_INVALIDDATA;
}
@@ -207,24 +217,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;
}
}
@@ -240,41 +258,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);
@@ -311,6 +335,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);
@@ -398,6 +430,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;
@@ -414,16 +447,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;
}
@@ -438,7 +475,7 @@ decode_coding_unit:
}
*got_frame = 1;
- return buf_size;
+ return avpkt->size;
}
static av_cold int dnxhd_decode_close(AVCodecContext *avctx)
@@ -460,5 +497,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 c49ad7e..f5a803b 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);
@@ -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 c3248a2..7ef0b96 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 5ab2331..ecc7a29 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 c796387..3b78486 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,220 @@ 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);
- buf += 825;
+ 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 += 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
+ elements = 4;
+ break;
+ case 50: // RGB
+ elements = 3;
+ 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;
+ 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;
}
- break;
+ for (i = 0; i < 3; i++)
+ ptr[i] += p->linesize[i];
+ }
+ break;
+ case 16:
+ elements *= 2;
+ case 8:
+ av_image_copy_plane(ptr[0], p->linesize[0],
+ buf, stride,
+ elements * avctx->width, avctx->height);
+ break;
}
*got_frame = 1;
@@ -211,7 +357,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
new file mode 100644
index 0000000..dd2a335
--- /dev/null
+++ b/libavcodec/dpx_parser.c
@@ -0,0 +1,114 @@
+/*
+ * DPX parser
+ * 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
+ * DPX parser
+ */
+
+#include "libavutil/bswap.h"
+#include "parser.h"
+
+typedef struct DPXParseContext {
+ ParseContext pc;
+ uint32_t index;
+ uint32_t fsize;
+ uint32_t remaining_size;
+ int is_be;
+} DPXParseContext;
+
+static int dpx_parse(AVCodecParserContext *s, AVCodecContext *avctx,
+ const uint8_t **poutbuf, int *poutbuf_size,
+ const uint8_t *buf, int buf_size)
+{
+ DPXParseContext *d = s->priv_data;
+ uint32_t state = d->pc.state;
+ int next = END_NOT_FOUND;
+ int i = 0;
+
+ s->pict_type = AV_PICTURE_TYPE_I;
+
+ *poutbuf_size = 0;
+ if (buf_size == 0)
+ next = 0;
+
+ if (!d->pc.frame_start_found) {
+ for (; i < buf_size; i++) {
+ state = (state << 8) | buf[i];
+ if (state == MKBETAG('S','D','P','X') ||
+ state == MKTAG('S','D','P','X')) {
+ d->pc.frame_start_found = 1;
+ d->is_be = state == MKBETAG('S','D','P','X');
+ d->index = 0;
+ break;
+ }
+ }
+ d->pc.state = state;
+ } else {
+ if (d->remaining_size) {
+ i = FFMIN(d->remaining_size, buf_size);
+ d->remaining_size -= i;
+ if (d->remaining_size)
+ goto flush;
+ }
+ }
+
+ for (;d->pc.frame_start_found && i < buf_size; i++) {
+ d->pc.state = (d->pc.state << 8) | buf[i];
+ d->index++;
+ if (d->index == 17) {
+ d->fsize = d->is_be ? d->pc.state : av_bswap32(d->pc.state);
+ if (d->fsize <= 1664) {
+ d->pc.frame_start_found = 0;
+ goto flush;
+ }
+ if (d->fsize > buf_size - i + 19)
+ d->remaining_size = d->fsize - buf_size + i - 19;
+ else
+ i += d->fsize - 19;
+
+ break;
+ } else if (d->index > 17) {
+ if (d->pc.state == MKBETAG('S','D','P','X') ||
+ d->pc.state == MKTAG('S','D','P','X')) {
+ next = i - 3;
+ break;
+ }
+ }
+ }
+
+flush:
+ if (ff_combine_frame(&d->pc, next, &buf, &buf_size) < 0)
+ return buf_size;
+
+ d->pc.frame_start_found = 0;
+
+ *poutbuf = buf;
+ *poutbuf_size = buf_size;
+ return next;
+}
+
+AVCodecParser ff_dpx_parser = {
+ .codec_ids = { AV_CODEC_ID_DPX },
+ .priv_data_size = sizeof(DPXParseContext),
+ .parser_parse = dpx_parse,
+ .parser_close = ff_parse_close,
+};
diff --git a/libavcodec/dpxenc.c b/libavcodec/dpxenc.c
index 4de71cf..aca745b 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,23 +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);
@@ -176,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 0000000..dbeb9fe
--- /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 0000000..6afb416
--- /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 0000000..f1dfd4b
--- /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 969e4ae..b336d2c 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 b56a581..48fb635 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/dump_extradata_bsf.c b/libavcodec/dump_extradata_bsf.c
index 17d9434..2dcbf8f 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
*/
@@ -47,7 +47,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 81d28d1..2bc7fc5 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)
@@ -185,8 +185,6 @@ 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 +202,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 +243,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 +269,4 @@ av_cold int ff_dvvideo_init(AVCodecContext *avctx)
return 0;
}
+
diff --git a/libavcodec/dv.h b/libavcodec/dv.h
index b458aea..5d28263 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 74c529d..b301cbf 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,11 +288,29 @@ 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)
{
@@ -299,3 +326,4 @@ const AVDVProfile *av_dv_codec_profile(int width, int height,
return NULL;
}
+
diff --git a/libavcodec/dv_profile.h b/libavcodec/dv_profile.h
index 5ad7b4f..d4437c9 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.
*
diff --git a/libavcodec/dv_profile_internal.h b/libavcodec/dv_profile_internal.h
index f93e7ca..67d3a2b 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 9b2b954..2579341 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 b69721b..941b557 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 720e786..dd84a07 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 295e03b..d15c891 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"
diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c
index 3d6e313..261e161 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
*/
@@ -23,6 +23,7 @@
#include "get_bits.h"
#include "bytestream.h"
#include "libavutil/colorspace.h"
+#include "libavutil/opt.h"
#define DVBSUB_PAGE_SEGMENT 0x10
#define DVBSUB_REGION_SEGMENT 0x11
@@ -152,6 +153,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];
@@ -178,6 +180,7 @@ typedef struct DVBSubObjectDisplay {
typedef struct DVBSubObject {
int id;
+ int version;
int type;
@@ -197,6 +200,7 @@ typedef struct DVBSubRegionDisplay {
typedef struct DVBSubRegion {
int id;
+ int version;
int width;
int height;
@@ -207,6 +211,7 @@ typedef struct DVBSubRegion {
uint8_t *pbuf;
int buf_size;
+ int dirty;
DVBSubObjectDisplay *display_list;
@@ -223,15 +228,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;
@@ -297,53 +306,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;
- /* Should already be null */
- if (ctx->object_list)
- av_log(0, AV_LOG_ERROR, "Memory deallocation error!\n");
+ delete_region_display_list(ctx, region);
+
+ av_freep(&region->pbuf);
+ av_freep(&region);
+ }
}
static av_cold int dvbsub_init_decoder(AVCodecContext *avctx)
@@ -351,15 +366,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;
@@ -428,13 +450,19 @@ 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;
@@ -442,16 +470,18 @@ static av_cold int dvbsub_close_decoder(AVCodecContext *avctx)
static int dvbsub_read_2bit_string(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);
@@ -512,14 +542,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;
@@ -547,16 +577,18 @@ static int dvbsub_read_2bit_string(uint8_t *destbuf, int dbuf_len,
static int dvbsub_read_4bit_string(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);
@@ -636,14 +668,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)
@@ -668,12 +700,14 @@ static int dvbsub_read_4bit_string(uint8_t *destbuf, int dbuf_len,
static int dvbsub_read_8bit_string(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)++;
@@ -693,19 +727,20 @@ 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++;
+ }
}
}
}
@@ -716,7 +751,127 @@ static int dvbsub_read_8bit_string(uint8_t *destbuf, int dbuf_len,
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)
@@ -735,6 +890,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
av_dlog(avctx, "DVB pixel block size %d, %s field:\n", buf_size,
top_bottom ? "bottom" : "top");
@@ -749,21 +905,22 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis
if (i % 16)
av_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;
}
@@ -776,9 +933,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(pbuf + (y_pos * region->width),
+ region->width, &buf, buf_end - buf,
+ non_mod, map_table, x_pos);
break;
case 0x11:
if (region->depth < 4) {
@@ -791,9 +948,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(pbuf + (y_pos * region->width),
+ region->width, &buf, buf_end - buf,
+ non_mod, map_table, x_pos);
break;
case 0x12:
if (region->depth < 8) {
@@ -801,9 +958,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(pbuf + (y_pos * region->width),
+ region->width, &buf, buf_end - buf,
+ non_mod, NULL, x_pos);
break;
case 0x20:
@@ -838,7 +995,6 @@ static void 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;
@@ -869,7 +1025,8 @@ static void 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);
@@ -877,9 +1034,9 @@ static void 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);
}
@@ -891,13 +1048,14 @@ static void dvbsub_parse_object_segment(AVCodecContext *avctx,
}
-static void dvbsub_parse_clut_segment(AVCodecContext *avctx,
+static int dvbsub_parse_clut_segment(AVCodecContext *avctx,
const uint8_t *buf, int buf_size)
{
DVBSubContext *ctx = avctx->priv_data;
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;
@@ -915,6 +1073,7 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx,
av_dlog(avctx, "\n");
clut_id = *buf++;
+ version = ((*buf)>>4)&15;
buf += 1;
clut = get_clut(ctx, clut_id);
@@ -925,11 +1084,16 @@ static void 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++;
@@ -937,7 +1101,7 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx,
if (depth == 0) {
av_log(avctx, AV_LOG_ERROR, "Invalid clut depth 0x%x!\n", *buf);
- return;
+ return 0;
}
full_range = (*buf++) & 1;
@@ -963,14 +1127,21 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx,
YUV_TO_RGB2_CCIR(r, g, b, y);
av_dlog(avctx, "clut %d := (%d,%d,%d,%d)\n", entry_id, r, g, b, alpha);
+ if (!!(depth & 0x80) + !!(depth & 0x40) + !!(depth & 0x20) > 1) {
+ av_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;
}
@@ -981,6 +1152,7 @@ static void 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;
@@ -997,11 +1169,13 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx,
region = av_mallocz(sizeof(DVBSubRegion));
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);
@@ -1017,6 +1191,7 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx,
region->pbuf = av_malloc(region->buf_size);
fill = 1;
+ region->dirty = 0;
}
region->depth = 1 << (((*buf++) >> 2) & 7);
@@ -1026,9 +1201,10 @@ static void 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)
@@ -1086,7 +1262,7 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx,
}
static void 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;
@@ -1095,22 +1271,36 @@ static void 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;
- ctx->time_out = *buf++;
+ timeout = *buf++;
+ version = ((*buf)>>4) & 15;
page_state = ((*buf++) >> 2) & 3;
+ if (ctx->version == version) {
+ return;
+ }
+
+ ctx->time_out = timeout;
+ ctx->version = version;
+
av_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++;
@@ -1138,7 +1328,6 @@ static void dvbsub_parse_page_segment(AVCodecContext *avctx,
display->next = ctx->display_list;
ctx->display_list = display;
- ctx->display_list_size++;
av_dlog(avctx, "Region %d, (%d,%d)\n", region_id, display->x_pos, display->y_pos);
}
@@ -1148,7 +1337,7 @@ static void dvbsub_parse_page_segment(AVCodecContext *avctx,
tmp_display_list = display->next;
- av_free(display);
+ av_freep(&display);
}
}
@@ -1213,7 +1402,7 @@ static void save_display_set(DVBSubContext *ctx)
clut = get_clut(ctx, region->clut);
- if (clut == 0)
+ if (!clut)
clut = &default_clut;
switch (region->depth) {
@@ -1242,7 +1431,7 @@ static void save_display_set(DVBSubContext *ctx)
png_save2(filename, pbuf, width, height);
- av_free(pbuf);
+ av_freep(&pbuf);
}
fileno_index++;
@@ -1277,111 +1466,33 @@ static void 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;
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;
}
}
-static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf,
- int buf_size, AVSubtitle *sub)
+static void dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf,
+ 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;
}
static int dvbsub_decode(AVCodecContext *avctx,
@@ -1397,6 +1508,8 @@ static int dvbsub_decode(AVCodecContext *avctx,
int page_id;
int segment_length;
int i;
+ int ret = 0;
+ int got_segment = 0;
av_dlog(avctx, "DVB sub packet:\n");
@@ -1425,31 +1538,42 @@ 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) {
av_dlog(avctx, "incomplete or broken packet");
- return -1;
+ ret = -1;
+ goto end;
}
if (page_id == ctx->composition_id || page_id == ctx->ancillary_id ||
ctx->composition_id == -1 || ctx->ancillary_id == -1) {
switch (segment_type) {
case DVBSUB_PAGE_SEGMENT:
- dvbsub_parse_page_segment(avctx, p, segment_length);
+ dvbsub_parse_page_segment(avctx, p, segment_length, sub, data_size);
+ got_segment |= 1;
break;
case DVBSUB_REGION_SEGMENT:
dvbsub_parse_region_segment(avctx, p, segment_length);
+ got_segment |= 2;
break;
case DVBSUB_CLUT_SEGMENT:
- dvbsub_parse_clut_segment(avctx, p, segment_length);
+ ret = dvbsub_parse_clut_segment(avctx, p, segment_length);
+ if (ret < 0) goto end;
+ got_segment |= 4;
break;
case DVBSUB_OBJECT_SEGMENT:
dvbsub_parse_object_segment(avctx, p, segment_length);
+ got_segment |= 8;
break;
case DVBSUB_DISPLAYDEFINITION_SEGMENT:
dvbsub_parse_display_definition_segment(avctx, p, segment_length);
break;
case DVBSUB_DISPLAY_SEGMENT:
- *data_size = dvbsub_display_end_segment(avctx, p, segment_length, sub);
+ dvbsub_display_end_segment(avctx, p, segment_length, sub, data_size);
+ got_segment |= 16;
break;
default:
av_dlog(avctx, "Subtitling segment type 0x%x, page id %d, length %d\n",
@@ -1460,10 +1584,37 @@ static int dvbsub_decode(AVCodecContext *avctx,
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",
@@ -1474,4 +1625,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 0000000..6e2352d
--- /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 985cda7..231569a 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 8e7c0fb..e0ed043 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 a1235d3..4f0d0f6 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,
+};
+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) {
av_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;
}
@@ -383,18 +504,21 @@ static int dvvideo_decode_frame(AVCodecContext *avctx, void *data,
vsc_pack = buf + 80 * 5 + 48 + 5;
if (*vsc_pack == dv_video_control) {
apt = buf[4] & 0x07;
- is16_9 = (vsc_pack && ((vsc_pack[2] & 0x07) == 0x02 ||
- (!apt && (vsc_pack[2] & 0x07) == 0x07)));
+ is16_9 = (vsc_pack[2] & 0x07) == 0x02 ||
+ (!apt && (vsc_pack[2] & 0x07) == 0x07);
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 2ad3b33..32a945e 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 5d6db41..bb28d9e 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,24 @@
#include "libavutil/attributes.h"
#include "libavutil/colorspace.h"
+#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
#include "libavutil/avstring.h"
-typedef struct DVDSubContext {
- uint32_t palette[16];
- int has_palette;
+typedef struct DVDSubContext
+{
+ AVClass *class;
+ uint32_t palette[16];
+ char *palette_str;
+ int has_palette;
+ uint8_t colormap[4];
+ uint8_t alpha[256];
+ uint8_t *buf;
+ 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)
@@ -125,17 +137,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 +172,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 +192,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 +214,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 +235,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 +346,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);
bitmap = av_malloc(w * h);
sub_header->rects = av_mallocz(sizeof(*sub_header->rects));
@@ -335,15 +363,14 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
buf, offset2, buf_size, is_8bit);
sub_header->rects[0]->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
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;
@@ -351,8 +378,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;
@@ -360,15 +392,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;
}
@@ -439,16 +463,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"
@@ -457,15 +484,35 @@ 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 > 0xffff - buf_size) {
+ av_log(avctx, AV_LOG_WARNING, "Attempt to reconstruct "
+ "too large SPU packets aborted.\n");
+ av_freep(&ctx->buf);
+ return AVERROR_INVALIDDATA;
+ }
+ ctx->buf = av_realloc(ctx->buf, ctx->buf_size + buf_size);
+ if (!ctx->buf)
+ return AVERROR(ENOMEM);
+ 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)
@@ -476,10 +523,25 @@ static int dvdsub_decode(AVCodecContext *avctx,
AVSubtitle *sub = data;
int is_menu;
+ if (ctx->buf) {
+ 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;
@@ -487,58 +549,123 @@ 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++);
av_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
+ av_freep(&ctx->buf);
+ 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 dvdsub_parse_extradata(AVCodecContext *avctx)
+{
+ DVDSubContext *ctx = (DVDSubContext*) avctx->priv_data;
+ char *dataorig, *data;
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) {
int ret = ff_set_dimensions(avctx, w, h);
- if (ret < 0)
+ if (ret < 0) {
+ av_free(dataorig);
return ret;
+ }
}
}
- cur += strcspn(cur, "\n\r");
- cur += strspn(cur, "\n\r");
+
+ data += pos;
+ data += strspn(data, "\n\r");
}
- av_free(data);
+
+ av_free(dataorig);
+ return 1;
+}
+
+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->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;
+ av_freep(&ctx->buf);
+ 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 },
+ { "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"),
@@ -547,4 +674,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 f62e943e..425f0af 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 6d98d49..5d810e3 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
*/
@@ -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);
@@ -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 989fcb9..c8e3f71 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 662cd9f..4d8b7b2 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 * 9L / 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 * 3L / 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 * 3L) {
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])
{
@@ -410,7 +410,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 +424,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 +444,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,
@@ -475,7 +474,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 +512,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 +526,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 +546,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,
@@ -579,7 +576,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;
diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c
index 9ee22c8..c1c7681 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 d9017c6..be246d7 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 4132cd7..6deccc3 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(struct dxva_context *ctx, const H264Context
((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(struct dxva_context *ctx, const H264Context
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(struct dxva_context *ctx, const H264Context *h, DXVA_Qmatrix_H264 *qm)
@@ -274,7 +274,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 = h->qscale - h->pps.init_qp;
slice->redundant_pic_cnt = h->redundant_pic_count;
if (h->slice_type == AV_PICTURE_TYPE_B)
diff --git a/libavcodec/dxva2_internal.h b/libavcodec/dxva2_internal.h
index b775e6c..427c1ff 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 65624e3..7ef4a6c 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 1524b51..3beeb9f 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) |
((ctx->cfg->ConfigIntraResidUnsigned != 0) << 6) |
((ctx->cfg->ConfigResidDiffAccelerator != 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;
@@ -186,8 +205,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 b0416f3..b159e16 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 4d88ce0..10a67f1 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 b9d079c..8e931fd 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
*/
diff --git a/libavcodec/eac3enc.c b/libavcodec/eac3enc.c
index 3aa2d54..e1d61f6 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 a92a24c..7d61559 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 c5ce9a5..d1b7c68 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 5b2db44..e4840f2 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 e78de04..6b9ec1c 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 a226a83..813a2d1 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;
@@ -172,13 +178,14 @@ 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;
}
block[j] = level;
}
CLOSE_READER(re, &s->gb);
}
+ return 0;
}
static int decode_motion(GetBitContext *gb)
@@ -192,10 +199,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) {
@@ -204,21 +211,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)
@@ -263,16 +271,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");
@@ -293,11 +306,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;
@@ -314,7 +329,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 3d20c6c..771dc2f 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 c400b56..b4d3d1d 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 256b6b4..34fc30d 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 0aa8e16..9bbb6d8 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{
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
-void ff_init_elbg(int *points, int dim, int numpoints, int *codebook,
+void avpriv_init_elbg(int *points, int dim, int numpoints, int *codebook,
int numCB, int max_steps, int *closest_cb,
AVLFG *rand_state)
{
@@ -332,14 +343,14 @@ void 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));
for (i=0; i<numpoints/8; i++) {
k = (i*BIG_PRIME) % numpoints;
memcpy(temp_points + i*dim, points + k*dim, dim*sizeof(int));
}
- ff_init_elbg(temp_points, dim, numpoints/8, codebook, numCB, 2*max_steps, closest_cb, rand_state);
- ff_do_elbg(temp_points, dim, numpoints/8, codebook, numCB, 2*max_steps, closest_cb, rand_state);
+ avpriv_init_elbg(temp_points, dim, numpoints/8, codebook, numCB, 2*max_steps, closest_cb, rand_state);
+ avpriv_do_elbg(temp_points, dim, numpoints/8, codebook, numCB, 2*max_steps, closest_cb, rand_state);
av_free(temp_points);
@@ -350,7 +361,7 @@ void ff_init_elbg(int *points, int dim, int numpoints, int *codebook,
}
-void ff_do_elbg(int *points, int dim, int numpoints, int *codebook,
+void avpriv_do_elbg(int *points, int dim, int numpoints, int *codebook,
int numCB, int max_steps, int *closest_cb,
AVLFG *rand_state)
{
@@ -358,9 +369,9 @@ void 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;
- 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;
@@ -368,12 +379,12 @@ void 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));
elbg->rand_state = rand_state;
diff --git a/libavcodec/elbg.h b/libavcodec/elbg.h
index b8ea489..22fb53f 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
*/
@@ -37,7 +37,7 @@
* @param closest_cb Return the closest codebook to each point. Must be allocated.
* @param rand_state A random number generator state. Should be already initialized by av_lfg_init().
*/
-void ff_do_elbg(int *points, int dim, int numpoints, int *codebook,
+void avpriv_do_elbg(int *points, int dim, int numpoints, int *codebook,
int numCB, int num_steps, int *closest_cb,
AVLFG *rand_state);
@@ -45,10 +45,10 @@ void 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.
*/
-void ff_init_elbg(int *points, int dim, int numpoints, int *codebook,
+void 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 b1ca2d9..c72c562 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
*/
@@ -43,7 +43,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 {
@@ -136,11 +136,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;
@@ -151,66 +213,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);
}
/**
@@ -380,6 +397,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)) ||
@@ -430,6 +455,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)
@@ -544,7 +571,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 {
@@ -659,6 +686,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];
@@ -673,15 +703,11 @@ static int is_intra_more_likely(ERContext *s)
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;
@@ -715,6 +741,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);
@@ -726,6 +753,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;
}
@@ -740,6 +768,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
@@ -756,7 +795,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) {
@@ -805,41 +844,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))
+ if (prev_status != (ER_MV_END | ER_DC_END | ER_AC_END)) {
+ s->error_occurred = 1;
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++) {
@@ -851,6 +941,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;
@@ -871,7 +962,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;
@@ -894,7 +986,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;
@@ -921,6 +1013,7 @@ void ff_er_frame_end(ERContext *s)
}
}
+#if 1
/* backward mark errors */
distance = 9999999;
for (error_type = 1; error_type <= 3; error_type++) {
@@ -945,6 +1038,7 @@ void ff_er_frame_end(ERContext *s)
distance = 9999999;
}
}
+#endif
/* forward mark errors */
error = 0;
@@ -959,22 +1053,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)
@@ -982,15 +1077,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;
@@ -1018,7 +1113,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
@@ -1055,7 +1150,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;
@@ -1073,6 +1168,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;
@@ -1093,13 +1189,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++) {
@@ -1109,7 +1201,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;
@@ -1144,15 +1236,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++) {
@@ -1160,7 +1254,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;
@@ -1174,6 +1268,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
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 */
@@ -1206,6 +1301,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 7b9ec19..171af08 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];
@@ -72,6 +72,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 6c4654c..2816741 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 bc865a3..466b2b5 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 0000000..8cfc202
--- /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 0000000..20d0fe7
--- /dev/null
+++ b/libavcodec/evrcdec.c
@@ -0,0 +1,917 @@
+/*
+ * 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;
+
+ init_get_bits(&e->gb, buf, 8 * buf_size);
+ 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 0000000..fa30f05
--- /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 0000000..2f509ba
--- /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 4aa6eaf..b56fe2e 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
*/
@@ -27,13 +27,17 @@
* For more information on the OpenEXR format, visit:
* http://openexr.com/
*
- * exr_flt2uint() and exr_halflt2uint() is credited to Reimar Döffinger
+ * exr_flt2uint() and exr_halflt2uint() is credited to Reimar Döffinger.
+ * exr_half2float() is credited to Aaftab Munshi; Dan Ginsburg, Dave Shreiner.
+ *
*/
#include <zlib.h>
+#include <float.h>
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
+#include "libavutil/intfloat.h"
#include "avcodec.h"
#include "bytestream.h"
@@ -106,8 +110,75 @@ typedef struct EXRContext {
EXRThreadData *thread_data;
const char *layer;
+
+ float gamma;
+
+ uint16_t gamma_table[65536];
+
} EXRContext;
+/* -15 stored using a single precision bias of 127 */
+#define HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP 0x38000000
+/* max exponent value in single precision that will be converted
+ * to Inf or Nan when stored as a half-float */
+#define HALF_FLOAT_MAX_BIASED_EXP_AS_SINGLE_FP_EXP 0x47800000
+
+/* 255 is the max exponent biased value */
+#define FLOAT_MAX_BIASED_EXP (0xFF << 23)
+
+#define HALF_FLOAT_MAX_BIASED_EXP (0x1F << 10)
+
+/*
+ * Convert a half float as a uint16_t into a full float.
+ *
+ * @param hf half float as uint16_t
+ *
+ * @return float value
+ */
+static union av_intfloat32 exr_half2float(uint16_t hf)
+{
+ unsigned int sign = (unsigned int)(hf >> 15);
+ unsigned int mantissa = (unsigned int)(hf & ((1 << 10) - 1));
+ unsigned int exp = (unsigned int)(hf & HALF_FLOAT_MAX_BIASED_EXP);
+ union av_intfloat32 f;
+
+ if (exp == HALF_FLOAT_MAX_BIASED_EXP) {
+ // we have a half-float NaN or Inf
+ // half-float NaNs will be converted to a single precision NaN
+ // half-float Infs will be converted to a single precision Inf
+ exp = FLOAT_MAX_BIASED_EXP;
+ if (mantissa)
+ mantissa = (1 << 23) - 1; // set all bits to indicate a NaN
+ } else if (exp == 0x0) {
+ // convert half-float zero/denorm to single precision value
+ if (mantissa) {
+ mantissa <<= 1;
+ exp = HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP;
+ // check for leading 1 in denorm mantissa
+ while ((mantissa & (1 << 10))) {
+ // for every leading 0, decrement single precision exponent by 1
+ // and shift half-float mantissa value to the left
+ mantissa <<= 1;
+ exp -= (1 << 23);
+ }
+ // clamp the mantissa to 10-bits
+ mantissa &= ((1 << 10) - 1);
+ // shift left to generate single-precision mantissa of 23-bits
+ mantissa <<= 13;
+ }
+ } else {
+ // shift left to generate single-precision mantissa of 23-bits
+ mantissa <<= 13;
+ // generate single precision biased exponent value
+ exp = (exp << 13) + HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP;
+ }
+
+ f.i = (sign << 31) | exp | mantissa;
+
+ return f;
+}
+
+
/**
* Convert from 32-bit float as uint32_t to uint16_t.
*
@@ -653,8 +724,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);
}
@@ -773,6 +844,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
int bxmin = s->xmin * 2 * s->desc->nb_components;
int i, x, buf_size = s->buf_size;
int ret;
+ float one_gamma = 1.0f / s->gamma;
line_offset = AV_RL64(s->gb.buffer + jobnr * 8);
// Check if the buffer has the required bytes needed from the offset
@@ -852,18 +924,30 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
if (s->pixel_type == EXR_FLOAT) {
// 32-bit
for (x = 0; x < xdelta; x++) {
- *ptr_x++ = exr_flt2uint(bytestream_get_le32(&r));
- *ptr_x++ = exr_flt2uint(bytestream_get_le32(&g));
- *ptr_x++ = exr_flt2uint(bytestream_get_le32(&b));
+ union av_intfloat32 t;
+ t.i = bytestream_get_le32(&r);
+ if ( t.f > 0.0f ) /* avoid negative values */
+ t.f = powf(t.f, one_gamma);
+ *ptr_x++ = exr_flt2uint(t.i);
+
+ t.i = bytestream_get_le32(&g);
+ if ( t.f > 0.0f )
+ t.f = powf(t.f, one_gamma);
+ *ptr_x++ = exr_flt2uint(t.i);
+
+ t.i = bytestream_get_le32(&b);
+ if ( t.f > 0.0f )
+ t.f = powf(t.f, one_gamma);
+ *ptr_x++ = exr_flt2uint(t.i);
if (channel_buffer[3])
*ptr_x++ = exr_flt2uint(bytestream_get_le32(&a));
}
} else {
// 16-bit
for (x = 0; x < xdelta; x++) {
- *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&r));
- *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&g));
- *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&b));
+ *ptr_x++ = s->gamma_table[bytestream_get_le16(&r)];
+ *ptr_x++ = s->gamma_table[bytestream_get_le16(&g)];
+ *ptr_x++ = s->gamma_table[bytestream_get_le16(&b)];
if (channel_buffer[3])
*ptr_x++ = exr_halflt2uint(bytestream_get_le16(&a));
}
@@ -1262,7 +1346,10 @@ static int decode_frame(AVCodecContext *avctx, void *data,
static av_cold int decode_init(AVCodecContext *avctx)
{
+ uint32_t i;
+ union av_intfloat32 t;
EXRContext *s = avctx->priv_data;
+ float one_gamma = 1.0f / s->gamma;
s->avctx = avctx;
s->xmin = ~0;
@@ -1281,6 +1368,23 @@ static av_cold int decode_init(AVCodecContext *avctx)
s->w = 0;
s->h = 0;
+ if ( one_gamma > 0.9999f && one_gamma < 1.0001f ) {
+ for ( i = 0; i < 65536; ++i ) {
+ s->gamma_table[i] = exr_halflt2uint(i);
+ }
+ } else {
+ for ( i = 0; i < 65536; ++i ) {
+ t = exr_half2float(i);
+ /* If negative value we reuse half value */
+ if ( t.f <= 0.0f ) {
+ s->gamma_table[i] = exr_halflt2uint(i);
+ } else {
+ t.f = powf(t.f, one_gamma);
+ s->gamma_table[i] = exr_flt2uint(t.i);
+ }
+ }
+ }
+
// allocate thread data, used for non EXR_RAW compreesion types
s->thread_data = av_mallocz_array(avctx->thread_count, sizeof(EXRThreadData));
if (!s->thread_data)
@@ -1323,6 +1427,8 @@ static av_cold int decode_end(AVCodecContext *avctx)
static const AVOption options[] = {
{ "layer", "Set the decoding layer", OFFSET(layer),
AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, VD },
+ { "gamma", "Set the float gamma value when decoding (experimental/unsupported)", OFFSET(gamma),
+ AV_OPT_TYPE_FLOAT, { .dbl = 1.0f }, 0.001, FLT_MAX, VD },
{ NULL },
};
diff --git a/libavcodec/faandct.h b/libavcodec/faandct.h
index 59d5ff3..c5ef96d 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 2e9ce9c..ca82f77 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 0c01520..4cd2c78 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 4cbda3f..155f78d 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;
}
@@ -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;
@@ -290,6 +297,8 @@ int ff_ccitt_unpack(AVCodecContext *avctx, const uint8_t *src, int srcsize,
ref[1] = 0;
ref[2] = 0;
init_get_bits(&gb, src, srcsize * 8);
+ 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 +309,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 8157f1f..53d1168 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 f299eae..c4b7358 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
*/
diff --git a/libavcodec/fdctdsp.h b/libavcodec/fdctdsp.h
index 944dc6d..3e1f683 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 d6ea987..330211e 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 0000000..4bd11ce
--- /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 a449ec0..0a8f7d0 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 b7c83cf..ba26f81 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 7daae24..64f0f63 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 bad4821..3d3bd2f 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 0000000..fbdbf84
--- /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 ed4cffa..73cc98d 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 0000000..4d74f8a
--- /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 0000000..e5e54b6
--- /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 808f317..23ea453 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 d1a6a83..ab58a60 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;
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++) {
FFV1Context *fs = av_mallocz(sizeof(*fs));
@@ -203,6 +124,10 @@ av_cold int ffv1_init_slice_contexts(FFV1Context *f)
int sxe = f->avctx->width * (sx + 1) / f->num_h_slices;
int sys = f->avctx->height * sy / f->num_v_slices;
int sye = f->avctx->height * (sy + 1) / f->num_v_slices;
+
+ if (!fs)
+ return AVERROR(ENOMEM);
+
f->slice_context[i] = fs;
memcpy(fs, f, sizeof(*fs));
memset(fs->rc_stat2, 0, sizeof(fs->rc_stat2));
@@ -212,7 +137,7 @@ 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)
return AVERROR(ENOMEM);
@@ -225,7 +150,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);
@@ -262,11 +187,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 5c3bdc1..5081397 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;
- 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,8 +123,20 @@ 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)
@@ -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 50b220f..c408f16 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);
av_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;
@@ -195,29 +205,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 +239,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 +257,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 +283,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 +339,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 +412,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], 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 +452,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;
}
@@ -429,7 +478,7 @@ static int read_quant_table(RangeCoder *c, int16_t *quant_table, int scale)
unsigned len = get_symbol(c, state, 0) + 1;
if (len > 128 - i)
- return -1;
+ return AVERROR_INVALIDDATA;
while (len--) {
quant_table[i] = scale * v;
@@ -453,7 +502,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 +522,15 @@ 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);
}
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 +542,21 @@ 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->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 +579,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 +593,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
@@ -597,96 +662,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 +730,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);
+ }
av_dlog(f->avctx, "%d %d %d\n",
f->chroma_h_shift, f->chroma_v_shift, f->avctx->pix_fmt);
@@ -732,16 +765,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 +785,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 +833,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 +847,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)
{
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
@@ -834,10 +861,22 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void *data,
int i, ret;
uint8_t keystate = 128;
const 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->cur = p = f->picture.f;
+ 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 +896,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 +922,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 +940,142 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void *data,
} else
fs->c.bytestream_end = (uint8_t *)(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, (const uint8_t **)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;
- av_frame_free(&s->last_picture);
+ {
+ FFV1Context bak = *fdst;
+ memcpy(fdst, fsrc, sizeof(*fdst));
+ memcpy(fdst->initial_states, bak.initial_states, sizeof(fdst->initial_states));
+ memcpy(fdst->slice_context, bak.slice_context , sizeof(fdst->slice_context));
+ fdst->picture = bak.picture;
+ fdst->last_picture = bak.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_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 +1086,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 93630b4..cf2a13d 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,39 @@ 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, uint8_t *src[3], int w, int h,
- int stride[3])
+static int encode_rgb_frame(FFV1Context *s, 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 +422,29 @@ static void encode_rgb_frame(FFV1Context *s, uint8_t *src[3], int w, int h,
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 = *((uint32_t *)(src[0] + x * 4 + stride[0] * y));
- b = v & 0xFF;
- g = (v >> 8) & 0xFF;
+ unsigned v = *((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 = *((uint16_t *)(src[0] + x * 2 + stride[0] * y));
- g = *((uint16_t *)(src[1] + x * 2 + stride[1] * y));
- r = *((uint16_t *)(src[2] + x * 2 + stride[2] * y));
+ b = *((uint16_t*)(src[0] + x*2 + stride[0]*y));
+ g = *((uint16_t*)(src[1] + x*2 + stride[1]*y));
+ r = *((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 +452,20 @@ static void encode_rgb_frame(FFV1Context *s, uint8_t *src[3], int w, int h,
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 +505,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 +549,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 +601,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 +630,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 +660,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 +718,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 +731,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 +746,21 @@ 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;
break;
case AV_PIX_FMT_RGB32:
- s->colorspace = 1;
+ s->colorspace = 1;
s->transparency = 1;
+ s->chroma_planes = 1;
+ break;
+ case AV_PIX_FMT_0RGB32:
+ s->colorspace = 1;
+ s->chroma_planes = 1;
break;
case AV_PIX_FMT_GBRP9:
if (!avctx->bits_per_raw_sample)
@@ -654,55 +768,58 @@ 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) {
+ 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);
}
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 +846,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 +862,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 +891,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 +900,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 +914,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((a + b) / gob_count, 0, 255)];
+ 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((a + b) / gob_count, 0, 255)];
}
+ }
}
+ 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 +990,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, 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 = *((uint32_t*)(src[0] + x*4 + stride[0]*y));
+ b = v & 0xFF;
+ g = (v >> 8) & 0xFF;
+ r = (v >> 16) & 0xFF;
+ } else {
+ b = *((uint16_t*)(src[0] + x*2 + stride[0]*y));
+ g = *((uint16_t*)(src[1] + x*2 + stride[1]*y));
+ r = *((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 +1106,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;
+ 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 +1131,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 {
- 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 +1263,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 +1300,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 +1323,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 +1345,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 0000000..4a5031a
--- /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_free(ws->inter);
+ av_free(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_free(ws->sin);
+ av_free(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 8512ef3..adc8a25 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;
}
@@ -281,8 +282,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 +308,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 +320,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 3e51fde..5ff004e 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 3229682..f1307c7 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 bf2c118..0e45ab0 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,
@@ -267,13 +269,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 +289,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 +412,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 +439,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 +450,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 +489,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 +520,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 +585,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;
@@ -566,15 +609,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 {
@@ -611,10 +654,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;
}
@@ -623,10 +667,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 +706,9 @@ 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)
+ return AVERROR(ENOMEM);
return 0;
}
@@ -675,8 +723,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 820c3aa..1954f32 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 f566377..e2c1e5d 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 6cce692..9b1e428 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,8 @@
#include <limits.h>
+#include "libavutil/avassert.h"
+#include "libavutil/crc.h"
#include "avcodec.h"
#include "internal.h"
#include "get_bits.h"
@@ -41,6 +43,9 @@
#include "flac.h"
#include "flacdata.h"
#include "flacdsp.h"
+#include "thread.h"
+#include "unary.h"
+
typedef struct FLACContext {
FLACSTREAMINFO
@@ -106,7 +111,7 @@ static av_cold int flac_decode_init(AVCodecContext *avctx)
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->channels, s->bps);
s->got_streaminfo = 1;
return 0;
@@ -124,6 +129,9 @@ static void dump_headers(AVCodecContext *avctx, FLACStreaminfo *s)
static int allocate_buffers(FLACContext *s)
{
int buf_size;
+ int ret;
+
+ av_assert0(s->max_blocksize);
buf_size = av_samples_get_buffer_size(NULL, s->channels, s->max_blocksize,
AV_SAMPLE_FMT_S32P, 0);
@@ -134,9 +142,10 @@ static int allocate_buffers(FLACContext *s)
if (!s->decoded_buffer)
return AVERROR(ENOMEM);
- return av_samples_fill_arrays((uint8_t **)s->decoded, NULL,
+ ret = av_samples_fill_arrays((uint8_t **)s->decoded, NULL,
s->decoded_buffer, s->channels,
s->max_blocksize, AV_SAMPLE_FMT_S32P, 0);
+ return ret < 0 ? ret : 0;
}
/**
@@ -164,7 +173,7 @@ static int parse_streaminfo(FLACContext *s, const uint8_t *buf, int buf_size)
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->channels, s->bps);
s->got_streaminfo = 1;
return 0;
@@ -213,6 +222,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 +260,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++) {
@@ -350,7 +366,6 @@ 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 ||
(left < bps && !show_bits_long(&s->gb, left)) ||
!show_bits_long(&s->gb, bps)) {
@@ -359,8 +374,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) {
@@ -458,7 +472,7 @@ static int decode_frame(FLACContext *s)
ret = allocate_buffers(s);
if (ret < 0)
return ret;
- ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt, s->bps);
+ ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt, s->channels, s->bps);
s->got_streaminfo = 1;
dump_headers(s->avctx, (FLACStreaminfo *)s);
}
@@ -483,6 +497,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;
@@ -497,6 +512,16 @@ static int flac_decode_frame(AVCodecContext *avctx, void *data,
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,19 +538,26 @@ 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->blocksize, s->sample_shift);
@@ -544,6 +576,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->max_blocksize)
+ return allocate_buffers(s);
+ return 0;
+}
+
static av_cold int flac_decode_close(AVCodecContext *avctx)
{
FLACContext *s = avctx->priv_data;
@@ -562,10 +605,11 @@ 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 },
};
diff --git a/libavcodec/flacdsp.c b/libavcodec/flacdsp.c
index b916869..a83eb83 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,7 +85,7 @@ 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) {
@@ -127,5 +127,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 33184b5..417381c 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
*/
@@ -28,10 +28,11 @@ typedef struct FLACDSPContext {
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);
+ 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 269e64b..5d532e0 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 0affe22..62c0a15 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 1160da2..e66ef3d 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"
@@ -79,7 +80,7 @@ typedef struct FlacSubframe {
int shift;
RiceContext rc;
int32_t samples[FLAC_MAX_BLOCKSIZE];
- int32_t residual[FLAC_MAX_BLOCKSIZE+1];
+ int32_t residual[FLAC_MAX_BLOCKSIZE+11];
} FlacSubframe;
typedef struct FlacFrame {
@@ -156,7 +157,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++) {
@@ -250,8 +251,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 */
@@ -277,7 +281,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;
}
@@ -292,7 +297,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];
@@ -331,13 +336,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;
}
@@ -348,20 +353,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) {
@@ -369,7 +374,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);
@@ -397,11 +402,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);
@@ -619,13 +646,13 @@ static uint64_t calc_rice_params(RiceContext *rc, int pmin, int pmax,
uint32_t *udata;
uint64_t sums[MAX_PARTITION_ORDER+1][MAX_PARTITIONS];
- 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;
- udata = av_malloc(n * sizeof(uint32_t));
+ udata = av_malloc_array(n, sizeof(uint32_t));
for (i = 0; i < n; i++)
udata[i] = (2*data[i]) ^ (data[i]>>31);
@@ -1260,10 +1287,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);
@@ -1310,7 +1335,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" },
@@ -1345,7 +1370,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 de7979c..8791a2d 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]));
av_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 0000000..1c016f2
--- /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 * 8);
+
+ 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(s->frame_blocks, s->rows * s->cols * sizeof(Block));
+ s->key_blocks = av_realloc(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 71c81bd..a6d7caa 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);
@@ -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 68f45b4..5bd5fb6 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 801e357..561cfe0 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 0a6f268..5b2bed5 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 e14a105..070b528 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 63f62c3..fb4302c 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
*/
@@ -98,4 +98,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 bd833ef..30abcc3 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
*/
@@ -109,5 +109,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 0000000..6eae8b5
--- /dev/null
+++ b/libavcodec/frame_thread_encoder.c
@@ -0,0 +1,303 @@
+/*
+ * 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){
+ if(!(avctx->flags & CODEC_FLAG_INPUT_PRESERVED)){
+ AVFrame *new = av_frame_alloc();
+ if(!new)
+ return AVERROR(ENOMEM);
+ pthread_mutex_lock(&c->buffer_mutex);
+ ret = ff_get_buffer(c->parent_avctx, new, 0);
+ pthread_mutex_unlock(&c->buffer_mutex);
+ if(ret<0)
+ return ret;
+ new->pts = frame->pts;
+ new->quality = frame->quality;
+ new->pict_type = frame->pict_type;
+ av_image_copy(new->data, new->linesize, (const uint8_t **)frame->data, frame->linesize,
+ avctx->pix_fmt, avctx->width, avctx->height);
+ frame = new;
+ }
+
+ task.index = c->task_index;
+ task.indata = (void*)frame;
+ 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 0000000..1da0ce1
--- /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 4b4b02c..c49866e 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 568b94f..c778dbd 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 33934f1..0cd502b 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
*/
@@ -384,6 +384,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) {
@@ -400,7 +402,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);
@@ -422,6 +424,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;
}
@@ -455,8 +459,8 @@ 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);
if (!c->framebuf)
@@ -465,7 +469,7 @@ static int g2m_init_buffers(G2MContext *c)
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);
@@ -501,7 +505,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) {
@@ -551,7 +555,6 @@ static int g2m_load_cursor(AVCodecContext *avctx, G2MContext *c,
bits <<= 1;
}
}
- dst += c->cursor_stride - c->cursor_w * 4;
}
dst = c->cursor;
@@ -583,7 +586,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
@@ -597,7 +599,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:
@@ -682,12 +683,12 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data,
magic = bytestream2_get_be32(&bc);
if ((magic & ~0xF) != MKBETAG('G', '2', 'M', '0') ||
- (magic & 0xF) < 2 || (magic & 0xF) > 4) {
+ (magic & 0xF) < 2 || (magic & 0xF) > 5) {
av_log(avctx, AV_LOG_ERROR, "Wrong magic %08X\n", magic);
return AVERROR_INVALIDDATA;
}
- if ((magic & 0xF) != 4) {
+ if ((magic & 0xF) < 4) {
av_log(avctx, AV_LOG_ERROR, "G2M2 and G2M3 are not yet supported\n");
return AVERROR(ENOSYS);
}
@@ -703,6 +704,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",
@@ -722,19 +724,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);
@@ -749,7 +754,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);
@@ -758,11 +764,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);
@@ -838,11 +846,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 a911bc7..2c04c40 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 71d03fc..3f89827 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 26f288b..14bd67e 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
*/
@@ -77,7 +77,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 };
@@ -94,10 +94,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/g722enc.c b/libavcodec/g722enc.c
index be43794..dac7c87 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"
@@ -236,7 +237,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 {\
@@ -356,10 +357,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 bbdb404..66afd6a 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 {
- 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 {
- 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 04f8a06..38a6c59 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 {
+ int index; ///< postfilter backward/forward lag
+ int16_t opt_gain; ///< optimal gain
+ int16_t sc_gain; ///< scaling gain
+} PPFParam;
+
+/**
+ * Harmonic filter parameters
+ */
+typedef struct {
+ int index;
+ int gain;
+} HFParam;
+
+/**
+ * Optimized fixed codebook excitation parameters
+ */
+typedef struct {
+ 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 62aeb79..b0331d8 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 */
@@ -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/x86/audiodsp.h b/libavcodec/g729.h
index 321056b..6168313 100644
--- a/libavcodec/x86/audiodsp.h
+++ b/libavcodec/g729.h
@@ -1,25 +1,29 @@
/*
- * This file is part of Libav.
+ * G.729, G729 Annex D decoders
+ * Copyright (c) 2008 Vladimir Voroshilov
*
- * 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
*/
+#ifndef AVCODEC_G729_H
+#define AVCODEC_G729_H
-#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);
+/**
+ * subframe size
+ */
+#define SUBFRAME_SIZE 40
-#endif /* AVCODEC_X86_AUDIODSP_H */
+#endif // AVCODEC_G729_H
diff --git a/libavcodec/g729data.h b/libavcodec/g729data.h
new file mode 100644
index 0000000..365ca47
--- /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 0000000..6eb057f
--- /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) {
+ 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 = ctx->rand_value & ((1 << format->fc_indexes_bits) - 1);
+
+ 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 buf_size;
+}
+
+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_DR1,
+};
diff --git a/libavcodec/g729postfilter.c b/libavcodec/g729postfilter.c
new file mode 100644
index 0000000..9a775c4
--- /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 0000000..89e3e40
--- /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 3339c12..b9dec4f 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)
@@ -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)
{
@@ -625,6 +690,7 @@ static inline int get_xbits_trace(GetBitContext *s, int n, const char *file,
#else //TRACE
#define tprintf(p, ...) { }
+#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 c6c37b6..27d054e 100644
--- a/libavcodec/gif.c
+++ b/libavcodec/gif.c
@@ -1,113 +1,195 @@
/*
- * 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 {
+ const AVClass *class;
LZWState *lzw;
uint8_t *buf;
+ AVFrame *last_frame;
+ int flags;
+ uint32_t palette[AVPALETTE_COUNT]; ///< local reference palette for !pal8
+ 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 = -1;
const uint8_t *ptr;
+
+ /* Crop image */
+ // TODO support with palette change
+ 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);
+ }
+ }
+
+ /* TODO: support with palette change (pal8) */
+ if ((s->flags & GF_TRANSDIFF) && s->last_frame && !palette) {
+ 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 = 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;
+ }
+ }
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 (trans >= 0) {
+ 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 +204,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 +211,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);
@@ -138,30 +224,49 @@ static av_cold int gif_encode_init(AVCodecContext *avctx)
avctx->coded_frame->key_frame = 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 */
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];
+ }
+
+ 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 +283,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 +317,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 0000000..b4cf665
--- /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 cdb7f23..90de38b 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;
- av_dlog(s->avctx, "gif: image x=%d y=%d w=%d h=%d\n", left, top, width, height);
+ av_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:
@@ -125,77 +271,95 @@ static int gif_read_image(GifState *s, AVFrame *frame)
case 1:
y1 += 8;
ptr += linesize * 8;
- if (y1 >= height) {
- y1 = pass ? 2 : 4;
- ptr = ptr1 + linesize * y1;
- pass++;
- }
break;
case 2:
y1 += 4;
ptr += linesize * 4;
- if (y1 >= height) {
- y1 = 1;
- ptr = ptr1 + linesize;
- pass++;
- }
break;
case 3:
y1 += 2;
ptr += linesize * 2;
break;
}
+ while (y1 >= height) {
+ y1 = 4 >> pass;
+ ptr = ptr1 + linesize * y1;
+ pass++;
+ }
} else {
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;
- /* extension */
- ext_code = bytestream2_get_byte(&s->gb);
- ext_len = bytestream2_get_byte(&s->gb);
+ /* 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;
+
+ ext_code = bytestream2_get_byteu(&s->gb);
+ ext_len = bytestream2_get_byteu(&s->gb);
- av_dlog(s->avctx, "gif: ext_code=0x%x len=%d\n", ext_code, ext_len);
+ av_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;
- av_dlog(s->avctx, "gif: gce_flags=%x delay=%d tcolor=%d disposal=%d\n",
- gce_flags, s->gce_delay,
+ av_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;
+ av_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);
- av_dlog(s->avctx, "gif: ext_len1=%d\n", ext_len);
+ av_dlog(s->avctx, "ext_len1=%d\n", ext_len);
}
return 0;
}
@@ -204,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;
+ }
- av_dlog(s->avctx, "gif: screen_w=%d screen_h=%d bpp=%d global_palette=%d\n",
+ av_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;
}
@@ -251,23 +419,24 @@ static int gif_parse_next_image(GifState *s, AVFrame *frame)
int code = bytestream2_get_byte(&s->gb);
int ret;
- av_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)
@@ -276,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);
}
@@ -316,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)"),
@@ -329,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 e740a20..2dfe917 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 550c41e..937ac22 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 22a87c6..81d8aee 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(0, 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,7 +195,11 @@ 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);
+ 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);
@@ -328,7 +336,9 @@ static inline int get_ur_golomb_jpegls(GetBitContext *gb, int k, int limit,
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);
}
@@ -467,7 +477,7 @@ 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) {
@@ -488,8 +498,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,7 +536,7 @@ 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)
@@ -543,7 +553,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 238cb73..53d65c4 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 c0befc7..9a3b94e 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 b763ce8..c4cde92 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 c9b3183..d90c69b 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 f5581d5..b57194b 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 0b54dc5..0c60813 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 b9783f1..9836905 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 ad7e28b..5586462 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 2469424..9c31557 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 a81ccdf..a9891ed 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 4d1c997..9064f1a 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;
}
@@ -257,7 +255,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 +300,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 +385,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 +438,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 +520,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
@@ -600,11 +614,10 @@ retry:
s->parse_context = pc;
}
- if (!s->context_initialized)
+ if (!s->context_initialized) {
if ((ret = ff_mpv_common_init(s)) < 0)
return ret;
- if (!s->context_initialized) {
ret = ff_set_dimensions(avctx, s->width, s->height);
if (ret < 0)
return ret;
@@ -637,12 +650,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;
@@ -668,4 +681,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 f24e590..75211a0 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
@@ -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) {
@@ -247,16 +253,18 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64],
if ((cbp | mvd | s->dquant) == 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;
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) {
@@ -268,7 +276,7 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64],
h->mtype += 3;
if (cbp || s->dquant)
h->mtype++;
- assert(h->mtype > 1);
+ av_assert1(h->mtype > 1);
}
if (s->dquant)
@@ -286,18 +294,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 +312,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 +366,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 9019548..b08e32e 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 dbbe7ce..54ce2a5 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
@@ -67,8 +67,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];
@@ -120,7 +120,6 @@ 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);
int ff_h263_get_gob_height(MpegEncContext *s);
void ff_h263_encode_motion(MpegEncContext * s, int val, int f_code);
diff --git a/libavcodec/h263_parser.c b/libavcodec/h263_parser.c
index 71e047a..2e7d493 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 5bd715f..565a222 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 c966aab..1cd965f 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 31e014a..4ef7825 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)
@@ -53,14 +56,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 +70,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 +117,12 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx)
}
s->codec_id = avctx->codec->id;
+ if (avctx->stream_codec_tag == AV_RL32("l263") && 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 +178,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 +190,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 +242,8 @@ static int decode_slice(MpegEncContext *s)
s->mv_type = MV_TYPE_16X16;
av_dlog(s, "%d %d %06X\n",
ret, get_bits_count(&s->gb), show_bits(&s->gb, 24));
+
+ tprintf(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 +280,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->err_recognition & AV_EF_IGNORE_ERR)
+ continue;
return AVERROR_INVALIDDATA;
}
@@ -286,7 +296,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 +309,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 +330,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 +369,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->err_recognition & AV_EF_BUFFER))
+ (s->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 +404,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;
s->flags = avctx->flags;
@@ -401,6 +431,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");
@@ -412,13 +444,27 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return buf_size;
}
+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 < 20)) // 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;
@@ -435,11 +481,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) {
@@ -450,6 +493,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);
@@ -474,25 +525,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,
@@ -562,6 +597,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);
@@ -579,14 +619,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 ||
@@ -604,7 +644,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 &&
@@ -613,12 +653,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) {
@@ -629,26 +665,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);
@@ -677,5 +733,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 70ecdb9..a70ff24 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 40f041c..d2cc2ff 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 a392054..222bf58 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,9 +25,12 @@
* @author Michael Niedermayer <michaelni@gmx.at>
*/
+#define UNCHECKED_BITSTREAM_READER 1
+
#include "libavutil/avassert.h"
#include "libavutil/display.h"
#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
#include "libavutil/stereo3d.h"
#include "libavutil/timer.h"
#include "internal.h"
@@ -46,11 +49,18 @@
#include "rectangle.h"
#include "svq3.h"
#include "thread.h"
+#include "vdpau_internal.h"
#include <assert.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)
@@ -61,19 +71,28 @@ static void h264_er_decode_mb(void *opaque, int ref, int mv_dir, int mv_type,
h->mb_y = mb_y;
h->mb_xy = mb_x + mb_y * h->mb_stride;
memset(h->non_zero_count_cache, 0, sizeof(h->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 >= h->ref_count[0])
ref = 0;
+ if (!h->ref_list[0][ref].f.data[0]) {
+ av_log(h->avctx, AV_LOG_DEBUG, "Reference not available for error concealing\n");
+ ref = 0;
+ }
+ if ((h->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 * h->mb_xy],
2, 2, 2, ref, 1);
fill_rectangle(&h->ref_cache[0][scan8[0]], 4, 4, 8, ref, 1);
fill_rectangle(h->mv_cache[0][scan8[0]], 4, 4, 8,
pack16to32((*mv)[0][0][0], (*mv)[0][0][1]), 4);
- assert(!FRAME_MBAFF(h));
+ h->mb_mbaff =
+ h->mb_field_decoding_flag = 0;
ff_h264_hl_decode_mb(h);
}
@@ -196,18 +215,18 @@ int ff_h264_check_intra_pred_mode(H264Context *h, int mode, int is_chroma)
if ((h->left_samples_available & 0x8080) != 0x8080) {
mode = left[mode];
- if (is_chroma && (h->left_samples_available & 0x8080)) {
- // mad cow disease mode, aka MBAFF + constrained_intra_pred
- mode = ALZHEIMER_DC_L0T_PRED8x8 +
- (!(h->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",
h->mb_x, h->mb_y);
return AVERROR_INVALIDDATA;
}
+ if (is_chroma && (h->left_samples_available & 0x8080)) {
+ // mad cow disease mode, aka MBAFF + constrained_intra_pred
+ mode = ALZHEIMER_DC_L0T_PRED8x8 +
+ (!(h->left_samples_available & 0x8000)) +
+ 2 * (mode == DC_128_PRED8x8);
+ }
}
return mode;
@@ -229,7 +248,7 @@ const uint8_t *ff_h264_decode_nal(H264Context *h, const uint8_t *src,
#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; \
} \
@@ -274,21 +293,26 @@ const uint8_t *ff_h264_decode_nal(H264Context *h, const uint8_t *src,
}
#endif
- if (i >= length - 1) { // no escaped 0
- *dst_length = length;
- *consumed = length + 1; // +1 for the header
- return src;
- }
-
// use second escape buffer for inter data
bufidx = h->nal_unit_type == NAL_DPC ? 1 : 0;
- av_fast_malloc(&h->rbsp_buffer[bufidx], &h->rbsp_buffer_size[bufidx],
- length + FF_INPUT_BUFFER_PADDING_SIZE);
+
+ av_fast_padded_malloc(&h->rbsp_buffer[bufidx], &h->rbsp_buffer_size[bufidx], length+MAX_MBPAIR_SIZE);
dst = h->rbsp_buffer[bufidx];
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) {
@@ -296,7 +320,7 @@ const uint8_t *ff_h264_decode_nal(H264Context *h, const uint8_t *src,
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;
@@ -404,11 +428,11 @@ void ff_h264_free_tables(H264Context *h, int free_rbsp)
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, i;
- 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)
FF_ALLOCZ_OR_GOTO(h->avctx, h->non_zero_count,
big_mb_num * 48 * sizeof(uint8_t), fail)
FF_ALLOCZ_OR_GOTO(h->avctx, h->slice_table_base,
@@ -417,10 +441,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);
FF_ALLOCZ_OR_GOTO(h->avctx, h->direct_table,
4 * big_mb_num * sizeof(uint8_t), fail);
FF_ALLOCZ_OR_GOTO(h->avctx, h->list_counts,
@@ -449,7 +473,7 @@ int ff_h264_alloc_tables(H264Context *h)
if (!h->DPB) {
h->DPB = av_mallocz_array(H264_MAX_PICTURE_COUNT, sizeof(*h->DPB));
if (!h->DPB)
- return AVERROR(ENOMEM);
+ goto fail;
for (i = 0; i < H264_MAX_PICTURE_COUNT; i++)
av_frame_unref(&h->DPB[i].f);
av_frame_unref(&h->cur_pic.f);
@@ -475,10 +499,10 @@ int ff_h264_context_init(H264Context *h)
int yc_size = y_size + 2 * c_size;
int x, y, i;
- FF_ALLOCZ_OR_GOTO(h->avctx, h->top_borders[0],
- h->mb_width * 16 * 3 * sizeof(uint8_t) * 2, fail)
- FF_ALLOCZ_OR_GOTO(h->avctx, h->top_borders[1],
- h->mb_width * 16 * 3 * sizeof(uint8_t) * 2, fail)
+ FF_ALLOCZ_ARRAY_OR_GOTO(h->avctx, h->top_borders[0],
+ h->mb_width, 16 * 3 * sizeof(uint8_t) * 2, fail)
+ FF_ALLOCZ_ARRAY_OR_GOTO(h->avctx, h->top_borders[1],
+ h->mb_width, 16 * 3 * sizeof(uint8_t) * 2, fail)
h->ref_cache[0][scan8[5] + 1] =
h->ref_cache[0][scan8[7] + 1] =
@@ -541,20 +565,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,
@@ -565,7 +592,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) {
@@ -579,7 +606,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) {
@@ -590,14 +617,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;
}
av_cold int ff_h264_decode_init(AVCodecContext *avctx)
@@ -611,12 +638,17 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)
h->bit_depth_luma = 8;
h->chroma_format_idc = 1;
+ h->avctx->bits_per_raw_sample = 8;
+ h->cur_chroma_format_idc = 1;
+
ff_h264dsp_init(&h->h264dsp, 8, 1);
+ av_assert0(h->sps.bit_depth_chroma == 0);
ff_h264chroma_init(&h->h264chroma, h->sps.bit_depth_chroma);
ff_h264qpel_init(&h->h264qpel, 8);
ff_h264_pred_init(&h->hpc, h->avctx->codec_id, 8, 1);
h->dequant_coeff_pps = -1;
+ h->current_sps_id = -1;
/* needed so that IDCT permutation is known early */
if (CONFIG_ERROR_RESILIENCE)
@@ -650,20 +682,26 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)
for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++)
h->last_pocs[i] = INT_MIN;
h->prev_poc_msb = 1 << 16;
+ h->prev_frame_num = -1;
h->x264_build = -1;
+ h->sei_fpa.frame_packing_arrangement_cancel_flag = -1;
ff_h264_reset_sei(h);
- h->recovery_frame = -1;
- h->frame_recovered = 0;
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)
- 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 &&
@@ -674,6 +712,8 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)
avctx->internal->allocate_progress = 1;
+ ff_h264_flush_change(h);
+
return 0;
}
@@ -686,6 +726,10 @@ static int decode_init_thread_copy(AVCodecContext *avctx)
memset(h->sps_buffers, 0, sizeof(h->sps_buffers));
memset(h->pps_buffers, 0, sizeof(h->pps_buffers));
+ h->rbsp_buffer[0] = NULL;
+ h->rbsp_buffer[1] = NULL;
+ h->rbsp_buffer_size[0] = 0;
+ h->rbsp_buffer_size[1] = 0;
h->context_initialized = 0;
return 0;
@@ -704,7 +748,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;
@@ -792,9 +835,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;
@@ -824,6 +865,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 &&
@@ -832,14 +874,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 */
@@ -856,107 +900,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);
-
- 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++;
- }
+ out_of_order = out->poc < h->next_outputed_poc;
- 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) {
@@ -1039,24 +1047,33 @@ int ff_pred_weight_table(H264Context *h)
*/
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->outputed_poc = 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;
+ }
h->first_field = 0;
memset(h->ref_list[0], 0, sizeof(h->ref_list[0]));
memset(h->ref_list[1], 0, sizeof(h->ref_list[1]));
@@ -1065,6 +1082,9 @@ void ff_h264_flush_change(H264Context *h)
ff_h264_reset_sei(h);
h->recovery_frame = -1;
h->frame_recovered = 0;
+ h->list_count = 0;
+ h->current_slice = 0;
+ h->mmco_reset = 1;
}
/* forget old pics after a seek */
@@ -1073,7 +1093,7 @@ static void flush_dpb(AVCodecContext *avctx)
H264Context *h = avctx->priv_data;
int i;
- for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++) {
+ for (i = 0; i <= MAX_DELAYED_PIC_COUNT; i++) {
if (h->delayed_pic[i])
h->delayed_pic[i]->reference = 0;
h->delayed_pic[i] = NULL;
@@ -1222,7 +1242,15 @@ int ff_h264_set_parameter_from_sps(H264Context *h)
if (h->avctx->bits_per_raw_sample != h->sps.bit_depth_luma ||
h->cur_chroma_format_idc != h->sps.chroma_format_idc) {
- 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");
+ return AVERROR_INVALIDDATA;
+ }
+ 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) {
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;
@@ -1233,6 +1261,7 @@ int ff_h264_set_parameter_from_sps(H264Context *h)
ff_h264qpel_init(&h->h264qpel, h->sps.bit_depth_luma);
ff_h264_pred_init(&h->hpc, h->avctx->codec_id, h->sps.bit_depth_luma,
h->sps.chroma_format_idc);
+
if (CONFIG_ERROR_RESILIENCE)
ff_me_cmp_init(&h->mecc, h->avctx);
ff_videodsp_init(&h->vdsp, h->sps.bit_depth_luma);
@@ -1248,26 +1277,34 @@ int ff_h264_set_parameter_from_sps(H264Context *h)
int ff_set_ref_count(H264Context *h)
{
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 (h->slice_type_nos != AV_PICTURE_TYPE_I) {
+ unsigned max[2];
+ max[0] = max[1] = h->picture_structure == PICT_FRAME ? 15 : 31;
+
if (h->slice_type_nos == AV_PICTURE_TYPE_B)
h->direct_spatial_mv_pred = get_bits1(&h->gb);
num_ref_idx_active_override_flag = get_bits1(&h->gb);
if (num_ref_idx_active_override_flag) {
ref_count[0] = get_ue_golomb(&h->gb) + 1;
- if (ref_count[0] < 1)
- return AVERROR_INVALIDDATA;
if (h->slice_type_nos == AV_PICTURE_TYPE_B) {
ref_count[1] = get_ue_golomb(&h->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]);
+ h->ref_count[0] = h->ref_count[1] = 0;
+ h->list_count = 0;
+ return AVERROR_INVALIDDATA;
}
if (h->slice_type_nos == AV_PICTURE_TYPE_B)
@@ -1279,14 +1316,6 @@ int ff_set_ref_count(H264Context *h)
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");
- h->ref_count[0] = h->ref_count[1] = 0;
- return AVERROR_INVALIDDATA;
- }
-
if (list_count != h->list_count ||
ref_count[0] != h->ref_count[0] ||
ref_count[1] != h->ref_count[1]) {
@@ -1299,40 +1328,7 @@ int ff_set_ref_count(H264Context *h)
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,
@@ -1359,6 +1355,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) {
int nalsize = 0;
@@ -1374,6 +1371,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, buf + buf_index, &dst_length, &consumed,
@@ -1401,8 +1400,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(&h->gb, ptr, bit_length);
- if (!get_ue_golomb(&h->gb))
+ if (!get_ue_golomb(&h->gb) ||
+ !first_slice ||
+ first_slice != h->nal_unit_type)
nals_needed = nal_index;
+ if (!first_slice)
+ first_slice = h->nal_unit_type;
}
}
@@ -1419,8 +1422,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;
@@ -1429,6 +1437,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);
@@ -1454,6 +1469,8 @@ static int decode_nal_units(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;
}
hx = h->thread_context[context_count];
@@ -1470,8 +1487,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",
- hx->nal_unit_type, buf_index, buf_size, dst_length);
+ "NAL %d/%d at %d/%d length %d\n",
+ hx->nal_unit_type, hx->nal_ref_idc, buf_index, buf_size, dst_length);
if (h->is_avc && (nalsize != consumed) && nalsize)
av_log(h->avctx, AV_LOG_DEBUG,
@@ -1487,30 +1504,48 @@ 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
+ if ( !(avctx->active_thread_type & FF_THREAD_FRAME)
+ || nals_needed >= nal_index)
+ h->au_pps_id = -1;
+ /* 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) &&
- (hx->nal_unit_type != NAL_PPS &&
- hx->nal_unit_type != NAL_SPS)) {
- if (hx->nal_unit_type < NAL_AUD ||
- hx->nal_unit_type > NAL_AUXILIARY_SLICE)
- av_log(avctx, AV_LOG_INFO,
- "Ignoring NAL unit %d during extradata parsing\n",
+ if (parse_extradata) {
+ switch (hx->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",
hx->nal_unit_type);
- hx->nal_unit_type = NAL_FF_IGNORE;
+ // fall through to next case
+ case NAL_AUXILIARY_SLICE:
+ hx->nal_unit_type = NAL_FF_IGNORE;
+ }
}
+
err = 0;
+
switch (hx->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)
+ 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(&hx->gb, ptr, bit_length);
hx->intra_gb_ptr =
@@ -1520,14 +1555,22 @@ again:
if ((err = ff_h264_decode_slice_header(hx, h)))
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 || hx->slice_type_nos != AV_PICTURE_TYPE_I)
+ h->valid_recovery_point = 1;
+
+ if ( h->recovery_frame < 0
+ || ((h->recovery_frame - h->frame_num) & ((1 << h->sps.log2_max_frame_num)-1)) > h->sei_recovery_frame_cnt) {
+ h->recovery_frame = (h->frame_num + h->sei_recovery_frame_cnt) &
+ ((1 << h->sps.log2_max_frame_num) - 1);
+
+ if (!h->valid_recovery_point)
+ h->recovery_frame = h->frame_num;
+ }
}
h->cur_pic_ptr->f.key_frame |=
- (hx->nal_unit_type == NAL_IDR_SLICE) ||
- (h->sei_recovery_frame_cnt >= 0);
+ (hx->nal_unit_type == NAL_IDR_SLICE);
if (hx->nal_unit_type == NAL_IDR_SLICE ||
h->recovery_frame == h->frame_num) {
@@ -1538,7 +1581,13 @@ again:
// "recovered".
if (hx->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))
@@ -1547,22 +1596,26 @@ again:
if (h->avctx->hwaccel &&
(ret = h->avctx->hwaccel->start_frame(h->avctx, NULL, 0)) < 0)
return ret;
+ if (CONFIG_H264_VDPAU_DECODER &&
+ h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
+ ff_vdpau_h264_picture_start(h);
}
- if (hx->redundant_pic_count == 0 &&
- (avctx->skip_frame < AVDISCARD_NONREF ||
- hx->nal_ref_idc) &&
- (avctx->skip_frame < AVDISCARD_BIDIR ||
- hx->slice_type_nos != AV_PICTURE_TYPE_B) &&
- (avctx->skip_frame < AVDISCARD_NONKEY ||
- hx->slice_type_nos == AV_PICTURE_TYPE_I) &&
- avctx->skip_frame < AVDISCARD_ALL) {
+ if (hx->redundant_pic_count == 0) {
if (avctx->hwaccel) {
ret = avctx->hwaccel->decode_slice(avctx,
&buf[buf_index - consumed],
consumed);
if (ret < 0)
return ret;
+ } 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++;
}
@@ -1579,7 +1632,7 @@ again:
hx->intra_gb_ptr =
hx->inter_gb_ptr = NULL;
- if ((err = ff_h264_decode_slice_header(hx, h)) < 0) {
+ if ((err = ff_h264_decode_slice_header(hx, h))) {
/* make sure data_partitioning is cleared if it was set
* before, so we don't try decoding a slice without a valid
* slice header later */
@@ -1597,6 +1650,9 @@ again:
init_get_bits(&hx->inter_gb, ptr, bit_length);
hx->inter_gb_ptr = &hx->inter_gb;
+ av_log(h->avctx, AV_LOG_ERROR, "Partitioned H.264 support is incomplete\n");
+ break;
+
if (hx->redundant_pic_count == 0 &&
hx->intra_gb_ptr &&
hx->data_partitioning &&
@@ -1604,7 +1660,7 @@ again:
(avctx->skip_frame < AVDISCARD_NONREF || hx->nal_ref_idc) &&
(avctx->skip_frame < AVDISCARD_BIDIR ||
hx->slice_type_nos != AV_PICTURE_TYPE_B) &&
- (avctx->skip_frame < AVDISCARD_NONKEY ||
+ (avctx->skip_frame < AVDISCARD_NONINTRA ||
hx->slice_type_nos == AV_PICTURE_TYPE_I) &&
avctx->skip_frame < AVDISCARD_ALL)
context_count++;
@@ -1617,19 +1673,18 @@ 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 && (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));
+ 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));
ff_h264_decode_seq_parameter_set(h);
}
- ret = ff_h264_set_parameter_from_sps(h);
- if (ret < 0)
- goto end;
-
break;
case NAL_PPS:
init_get_bits(&h->gb, ptr, bit_length);
@@ -1658,10 +1713,11 @@ 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");
h->ref_count[0] = h->ref_count[1] = h->list_count = 0;
- } else if (err == 1) {
+ } else if (err == SLICE_SINGLETHREAD) {
/* Slice could not be decoded in parallel mode, copy down
* NAL unit stuff to context 0 and restart. Note that
* rbsp_buffer is not transferred, but since we no longer
@@ -1703,26 +1759,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)
{
@@ -1731,6 +1815,8 @@ 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;
@@ -1739,12 +1825,11 @@ static int h264_decode_frame(AVCodecContext *avctx, void *data,
h->data_partitioning = 0;
/* 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];
@@ -1763,7 +1848,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;
@@ -1771,19 +1857,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;
}
@@ -1795,16 +1892,25 @@ out:
ff_h264_field_end(h, 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);
+ 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, h->er.mbskip_table,
+ 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);
+ }
}
}
@@ -1830,6 +1936,7 @@ 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);
@@ -1854,6 +1961,19 @@ static const AVProfile profiles[] = {
{ FF_PROFILE_UNKNOWN },
};
+static const AVOption h264_options[] = {
+ {"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},
+ {NULL}
+};
+
+static const AVClass h264_class = {
+ .class_name = "H264 Decoder",
+ .item_name = av_default_item_name,
+ .option = h264_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_h264_decoder = {
.name = "h264",
.long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
@@ -1870,4 +1990,31 @@ AVCodec ff_h264_decoder = {
.init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),
.update_thread_context = ONLY_IF_THREADS_ENABLED(ff_h264_update_thread_context),
.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 cd4bf87..b94f06b 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
*/
@@ -36,6 +36,7 @@
#include "h264dsp.h"
#include "h264pred.h"
#include "h264qpel.h"
+#include "internal.h" // for avpriv_find_start_code()
#include "me_cmp.h"
#include "mpegutils.h"
#include "parser.h"
@@ -43,8 +44,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 +54,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,10 +69,10 @@
#define MAX_SLICES 16
#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(h) (h)->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
@@ -89,11 +92,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 +106,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 +133,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 +156,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 +252,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 {
@@ -262,6 +292,7 @@ typedef struct MMCO {
typedef struct H264Picture {
struct AVFrame f;
+ uint8_t avframe_padding[1024]; // hack to allow linking to a avutil with larger AVFrame
ThreadFrame tf;
AVBufferRef *qscale_table_buf;
@@ -287,7 +318,7 @@ 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
@@ -295,6 +326,12 @@ typedef struct H264Picture {
int needs_realloc; ///< picture needs to be reallocated (eg due to a frame size change)
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;
/**
@@ -398,9 +435,12 @@ typedef struct H264Context {
ptrdiff_t mb_linesize; ///< may be equal to s->linesize or s->linesize * 2, for mbaff
ptrdiff_t mb_uvlinesize;
+ 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];
@@ -457,7 +497,7 @@ typedef struct H264Context {
GetBitContext *inter_gb_ptr;
const uint8_t *intra_pcm_ptr;
- DECLARE_ALIGNED(16, int16_t, mb)[16 * 48 * 2]; ///< as a dct coeffecient is int32_t in high depth, we need to reserve twice the space.
+ DECLARE_ALIGNED(16, int16_t, mb)[16 * 48 * 2]; ///< as a dct coefficient is int32_t in high depth, we need to reserve twice the space.
DECLARE_ALIGNED(16, int16_t, mb_luma_dc)[3][16 * 2];
int16_t mb_padding[256 * 2]; ///< as mb is addressed by scantable[i] and scantable is uint8_t we can either check that i is not too large or ensure that there is some unused stuff after mb
@@ -486,12 +526,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;
@@ -588,7 +628,7 @@ typedef struct H264Context {
struct H264Context *thread_context[H264_MAX_THREADS];
/**
- * 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;
@@ -611,6 +651,7 @@ typedef struct H264Context {
enum AVPictureType pict_type;
int last_slice_type;
+ unsigned int last_ref_count[2];
/** @} */
/**
@@ -668,6 +709,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.
*
@@ -688,6 +736,8 @@ typedef struct H264Context {
int frame_recovered; ///< Initial frame has been completely recovered
+ int has_recovery_point;
+
int luma_weight_flag[2]; ///< 7.4.3.2 luma_weight_lX_flag
int chroma_weight_flag[2]; ///< 7.4.3.2 chroma_weight_lX_flag
@@ -697,6 +747,12 @@ typedef struct H264Context {
int cur_chroma_format_idc;
uint8_t *bipred_scratchpad;
+
+ 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;
uint8_t *edge_emu_buffer;
int16_t *dc_val_base;
@@ -710,7 +766,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];
/**
@@ -793,7 +849,7 @@ int ff_h264_check_intra4x4_pred_mode(H264Context *h);
int ff_h264_check_intra_pred_mode(H264Context *h, int mode, int is_chroma);
void ff_h264_hl_decode_mb(H264Context *h);
-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);
@@ -831,6 +887,12 @@ void ff_h264_filter_mb(H264Context *h, int mb_x, int mb_y,
*/
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
* / / /
@@ -1031,6 +1093,34 @@ static av_always_inline int get_dct8x8_allowed(H264Context *h)
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, int in_setup);
int ff_h264_ref_picture(H264Context *h, H264Picture *dst, H264Picture *src);
@@ -1045,6 +1135,9 @@ int ff_pred_weight_table(H264Context *h);
int ff_set_ref_count(H264Context *h);
int ff_h264_decode_slice_header(H264Context *h, H264Context *h0);
+#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);
@@ -1053,4 +1146,6 @@ void ff_h264_flush_change(H264Context *h);
void ff_h264_free_tables(H264Context *h, int free_rbsp);
+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 5a7cdf0..c2e183d 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,8 +26,10 @@
*/
#define CABAC(h) 1
+#define UNCHECKED_BITSTREAM_READER 1
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "libavutil/timer.h"
#include "config.h"
#include "cabac.h"
@@ -44,8 +46,6 @@
#include "x86/h264_i386.h"
#endif
-#include <assert.h>
-
/* Cabac pre state table */
static const int8_t cabac_context_init_I[1024][2] =
@@ -1621,7 +1621,9 @@ decode_cabac_residual_internal(H264Context *h, int16_t *block,
cc.range = h->cabac.range;
cc.low = h->cabac.low;
cc.bytestream= h->cabac.bytestream;
+#if !UNCHECKED_BITSTREAM_READER || ARCH_AARCH64
cc.bytestream_end = h->cabac.bytestream_end;
+#endif
#else
#define CC &h->cabac
#endif
@@ -1670,7 +1672,7 @@ decode_cabac_residual_internal(H264Context *h, int16_t *block,
}
#endif
}
- assert(coeff_count > 0);
+ av_assert2(coeff_count > 0);
if( is_dc ) {
if( cat == 3 )
@@ -1682,7 +1684,7 @@ decode_cabac_residual_internal(H264Context *h, int16_t *block,
if( max_coeff == 64 )
fill_rectangle(&h->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 );
h->non_zero_count_cache[scan8[n]] = coeff_count;
}
}
@@ -1711,7 +1713,7 @@ decode_cabac_residual_internal(H264Context *h, int16_t *block,
\
if( coeff_abs >= 15 ) { \
int j = 0; \
- while( get_cabac_bypass( CC ) ) { \
+ while(get_cabac_bypass( CC ) && j<30) { \
j++; \
} \
\
@@ -1885,6 +1887,7 @@ int ff_h264_decode_mb_cabac(H264Context *h) {
int dct8x8_allowed= h->pps.transform_8x8_mode;
int decode_chroma = h->sps.chroma_format_idc == 1 || h->sps.chroma_format_idc == 2;
const int pixel_shift = h->pixel_shift;
+ unsigned local_ref_count[2];
mb_xy = h->mb_xy = h->mb_x + h->mb_y*h->mb_stride;
@@ -1927,7 +1930,7 @@ int ff_h264_decode_mb_cabac(H264Context *h) {
if( h->slice_type_nos == AV_PICTURE_TYPE_B ) {
int ctx = 0;
- assert(h->slice_type_nos == AV_PICTURE_TYPE_B);
+ av_assert2(h->slice_type_nos == AV_PICTURE_TYPE_B);
if( !IS_DIRECT( h->left_type[LTOP]-1 ) )
ctx++;
@@ -1980,7 +1983,7 @@ int ff_h264_decode_mb_cabac(H264Context *h) {
mb_type= decode_cabac_intra_mb_type(h, 3, 1);
if(h->slice_type == AV_PICTURE_TYPE_SI && mb_type)
mb_type--;
- assert(h->slice_type_nos == AV_PICTURE_TYPE_I);
+ av_assert2(h->slice_type_nos == AV_PICTURE_TYPE_I);
decode_intra_mb:
partition_count = 0;
cbp= i_mb_type_info[mb_type].cbp;
@@ -2026,6 +2029,9 @@ decode_intra_mb:
return 0;
}
+ local_ref_count[0] = h->ref_count[0] << MB_MBAFF(h);
+ local_ref_count[1] = h->ref_count[1] << MB_MBAFF(h);
+
fill_decode_caches(h, mb_type);
if( IS_INTRA( mb_type ) ) {
@@ -2094,11 +2100,10 @@ decode_intra_mb:
for( i = 0; i < 4; i++ ) {
if(IS_DIRECT(h->sub_mb_type[i])) continue;
if(IS_DIR(h->sub_mb_type[i], 0, list)){
- int rc = h->ref_count[list] << MB_MBAFF(h);
- if (rc > 1) {
+ if (local_ref_count[list] > 1) {
ref[list][i] = decode_cabac_mb_ref( h, list, 4*i );
- if (ref[list][i] >= (unsigned) rc) {
- av_log(h->avctx, AV_LOG_ERROR, "Reference %d >= %d\n", ref[list][i], rc);
+ if (ref[list][i] >= (unsigned)local_ref_count[list]) {
+ av_log(h->avctx, AV_LOG_ERROR, "Reference %d >= %d\n", ref[list][i], local_ref_count[list]);
return -1;
}
}else
@@ -2180,11 +2185,11 @@ decode_intra_mb:
if(IS_16X16(mb_type)){
for(list=0; list<h->list_count; list++){
if(IS_DIR(mb_type, 0, list)){
- int ref, rc = h->ref_count[list] << MB_MBAFF(h);
- if (rc > 1) {
+ int ref;
+ if (local_ref_count[list] > 1) {
ref= decode_cabac_mb_ref(h, list, 0);
- if (ref >= (unsigned) rc) {
- av_log(h->avctx, AV_LOG_ERROR, "Reference %d >= %d\n", ref, rc);
+ if (ref >= (unsigned)local_ref_count[list]) {
+ av_log(h->avctx, AV_LOG_ERROR, "Reference %d >= %d\n", ref, local_ref_count[list]);
return -1;
}
}else
@@ -2208,11 +2213,11 @@ decode_intra_mb:
for(list=0; list<h->list_count; list++){
for(i=0; i<2; i++){
if(IS_DIR(mb_type, i, list)){
- int ref, rc = h->ref_count[list] << MB_MBAFF(h);
- if (rc > 1) {
+ int ref;
+ if (local_ref_count[list] > 1) {
ref= decode_cabac_mb_ref( h, list, 8*i );
- if (ref >= (unsigned) rc) {
- av_log(h->avctx, AV_LOG_ERROR, "Reference %d >= %d\n", ref, rc);
+ if (ref >= (unsigned)local_ref_count[list]) {
+ av_log(h->avctx, AV_LOG_ERROR, "Reference %d >= %d\n", ref, local_ref_count[list]);
return -1;
}
}else
@@ -2239,15 +2244,15 @@ decode_intra_mb:
}
}
}else{
- assert(IS_8X16(mb_type));
+ av_assert2(IS_8X16(mb_type));
for(list=0; list<h->list_count; list++){
for(i=0; i<2; i++){
if(IS_DIR(mb_type, i, list)){ //FIXME optimize
- int ref, rc = h->ref_count[list] << MB_MBAFF(h);
- if (rc > 1) {
+ int ref;
+ if (local_ref_count[list] > 1) {
ref= decode_cabac_mb_ref( h, list, 4*i );
- if (ref >= (unsigned) rc) {
- av_log(h->avctx, AV_LOG_ERROR, "Reference %d >= %d\n", ref, rc);
+ if (ref >= (unsigned)local_ref_count[list]) {
+ av_log(h->avctx, AV_LOG_ERROR, "Reference %d >= %d\n", ref, local_ref_count[list]);
return -1;
}
}else
@@ -2285,6 +2290,11 @@ decode_intra_mb:
cbp = decode_cabac_mb_cbp_luma( h );
if(decode_chroma)
cbp |= decode_cabac_mb_cbp_chroma( h ) << 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] = h->cbp = cbp;
diff --git a/libavcodec/h264_cavlc.c b/libavcodec/h264_cavlc.c
index 0ab0355..ca587a4 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,
@@ -359,7 +360,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];
@@ -478,7 +479,7 @@ static int decode_residual(H264Context *h, GetBitContext *gb, int16_t *block, in
trailing_ones= coeff_token&3;
tprintf(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);
@@ -510,7 +511,7 @@ static int decode_residual(H264Context *h, GetBitContext *gb, int16_t *block, in
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");
@@ -518,6 +519,7 @@ static int decode_residual(H264Context *h, GetBitContext *gb, int16_t *block, in
}
level_code += (1<<(prefix-3))-4096;
}
+ level_code += get_bits(gb, prefix-3); //part
}
if(trailing_ones < 3) level_code += 2;
@@ -547,9 +549,15 @@ static int decode_residual(H264Context *h, GetBitContext *gb, int16_t *block, in
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;
@@ -564,13 +572,13 @@ static int decode_residual(H264Context *h, GetBitContext *gb, int16_t *block, in
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);
}
}
@@ -580,7 +588,7 @@ static int decode_residual(H264Context *h, GetBitContext *gb, int16_t *block, in
((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; \
@@ -595,7 +603,7 @@ static int decode_residual(H264Context *h, GetBitContext *gb, int16_t *block, in
((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; \
@@ -608,18 +616,17 @@ static int decode_residual(H264Context *h, GetBitContext *gb, int16_t *block, in
} \
}
- if (zeros_left < 0) {
- av_log(h->avctx, AV_LOG_ERROR,
- "negative number of zero coeffs at %d %d\n", h->mb_x, h->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", h->mb_x, h->mb_y);
+ return -1;
+ }
+
return 0;
}
@@ -635,7 +642,7 @@ static av_always_inline int decode_luma_residual(H264Context *h, GetBitContext *
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++){
@@ -696,6 +703,7 @@ int ff_h264_decode_mb_cavlc(H264Context *h){
int dct8x8_allowed= h->pps.transform_8x8_mode;
int decode_chroma = h->sps.chroma_format_idc == 1 || h->sps.chroma_format_idc == 2;
const int pixel_shift = h->pixel_shift;
+ unsigned local_ref_count[2];
mb_xy = h->mb_xy = h->mb_x + h->mb_y*h->mb_stride;
@@ -704,7 +712,7 @@ int ff_h264_decode_mb_cavlc(H264Context *h){
down the code */
if(h->slice_type_nos != AV_PICTURE_TYPE_I){
if(h->mb_skip_run==-1)
- h->mb_skip_run= get_ue_golomb(&h->gb);
+ h->mb_skip_run= get_ue_golomb_long(&h->gb);
if (h->mb_skip_run--) {
if(FRAME_MBAFF(h) && (h->mb_y&1) == 0){
@@ -740,7 +748,7 @@ int ff_h264_decode_mb_cavlc(H264Context *h){
goto decode_intra_mb;
}
}else{
- assert(h->slice_type_nos == AV_PICTURE_TYPE_I);
+ av_assert2(h->slice_type_nos == AV_PICTURE_TYPE_I);
if(h->slice_type == AV_PICTURE_TYPE_SI && mb_type)
mb_type--;
decode_intra_mb:
@@ -780,6 +788,9 @@ decode_intra_mb:
return 0;
}
+ local_ref_count[0] = h->ref_count[0] << MB_MBAFF(h);
+ local_ref_count[1] = h->ref_count[1] << MB_MBAFF(h);
+
fill_decode_neighbors(h, mb_type);
fill_decode_caches(h, mb_type);
@@ -846,7 +857,7 @@ decode_intra_mb:
h->ref_cache[1][scan8[12]] = PART_NOT_AVAILABLE;
}
}else{
- assert(h->slice_type_nos == AV_PICTURE_TYPE_P); //FIXME SP correct ?
+ av_assert2(h->slice_type_nos == AV_PICTURE_TYPE_P); //FIXME SP correct ?
for(i=0; i<4; i++){
h->sub_mb_type[i]= get_ue_golomb_31(&h->gb);
if(h->sub_mb_type[i] >=4){
@@ -859,7 +870,7 @@ decode_intra_mb:
}
for(list=0; list<h->list_count; list++){
- int ref_count = IS_REF0(mb_type) ? 1 : h->ref_count[list] << MB_MBAFF(h);
+ int ref_count = IS_REF0(mb_type) ? 1 : local_ref_count[list];
for(i=0; i<4; i++){
if(IS_DIRECT(h->sub_mb_type[i])) continue;
if(IS_DIR(h->sub_mb_type[i], 0, list)){
@@ -939,14 +950,13 @@ decode_intra_mb:
for(list=0; list<h->list_count; list++){
unsigned int val;
if(IS_DIR(mb_type, 0, list)){
- int rc = h->ref_count[list] << MB_MBAFF(h);
- if (rc == 1) {
+ if(local_ref_count[list]==1){
val= 0;
- } else if (rc == 2) {
+ } else if(local_ref_count[list]==2){
val= get_bits1(&h->gb)^1;
}else{
val= get_ue_golomb_31(&h->gb);
- if (val >= rc) {
+ if (val >= local_ref_count[list]){
av_log(h->avctx, AV_LOG_ERROR, "ref %u overflow\n", val);
return -1;
}
@@ -970,14 +980,13 @@ decode_intra_mb:
for(i=0; i<2; i++){
unsigned int val;
if(IS_DIR(mb_type, i, list)){
- int rc = h->ref_count[list] << MB_MBAFF(h);
- if (rc == 1) {
+ if(local_ref_count[list] == 1) {
val= 0;
- } else if (rc == 2) {
+ } else if(local_ref_count[list] == 2) {
val= get_bits1(&h->gb)^1;
}else{
val= get_ue_golomb_31(&h->gb);
- if (val >= rc) {
+ if (val >= local_ref_count[list]){
av_log(h->avctx, AV_LOG_ERROR, "ref %u overflow\n", val);
return -1;
}
@@ -1003,19 +1012,18 @@ decode_intra_mb:
}
}
}else{
- assert(IS_8X16(mb_type));
+ av_assert2(IS_8X16(mb_type));
for(list=0; list<h->list_count; list++){
for(i=0; i<2; i++){
unsigned int val;
if(IS_DIR(mb_type, i, list)){ //FIXME optimize
- int rc = h->ref_count[list] << MB_MBAFF(h);
- if (rc == 1) {
+ if(local_ref_count[list]==1){
val= 0;
- } else if (rc == 2) {
+ } else if(local_ref_count[list]==2){
val= get_bits1(&h->gb)^1;
}else{
val= get_ue_golomb_31(&h->gb);
- if (val >= rc) {
+ if (val >= local_ref_count[list]){
av_log(h->avctx, AV_LOG_ERROR, "ref %u overflow\n", val);
return -1;
}
@@ -1064,6 +1072,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)){
@@ -1116,12 +1129,15 @@ decode_intra_mb:
if( decode_luma_residual(h, 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, gb, h->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;
}
}
@@ -1130,7 +1146,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)][h->chroma_qp[chroma_idx]];
int16_t *mb = h->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, gb, mb, index, scan + 1, qmul, 15) < 0)
@@ -1143,28 +1159,6 @@ decode_intra_mb:
fill_rectangle(&h->non_zero_count_cache[scan8[16]], 4, 4, 8, 0, 1);
fill_rectangle(&h->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, gb, h->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)][h->chroma_qp[chroma_idx]];
- for(i4x4=0; i4x4<4; i4x4++){
- const int index= 16 + 16*chroma_idx + i4x4;
- if( decode_residual(h, gb, h->mb + (16*index << pixel_shift), index, scan + 1, qmul, 15) < 0){
- return -1;
- }
- }
- }
- }else{
- fill_rectangle(&h->non_zero_count_cache[scan8[16]], 4, 4, 8, 0, 1);
- fill_rectangle(&h->non_zero_count_cache[scan8[32]], 4, 4, 8, 0, 1);
- }
}
}else{
fill_rectangle(&h->non_zero_count_cache[scan8[ 0]], 4, 4, 8, 0, 1);
diff --git a/libavcodec/h264_direct.c b/libavcodec/h264_direct.c
index f983898..3289fe4 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
*/
@@ -229,6 +229,7 @@ static void pred_spatial_direct_motion(H264Context *const h, int *mb_type)
else
mv[list] = AV_RN32A(C);
}
+ av_assert2(ref[list] < (h->ref_count[list] << !!FRAME_MBAFF(h)));
} else {
int mask = ~(MB_TYPE_L0 << (2 * list));
mv[list] = 0;
@@ -314,8 +315,8 @@ single_col:
await_reference_mb_row(h, &h->ref_list[1][0], mb_y);
- l1mv0 = &h->ref_list[1][0].motion_val[0][h->mb2b_xy[mb_xy]];
- l1mv1 = &h->ref_list[1][0].motion_val[1][h->mb2b_xy[mb_xy]];
+ l1mv0 = (void*)&h->ref_list[1][0].motion_val[0][h->mb2b_xy[mb_xy]];
+ l1mv1 = (void*)&h->ref_list[1][0].motion_val[1][h->mb2b_xy[mb_xy]];
l1ref0 = &h->ref_list[1][0].ref_index[0][4 * mb_xy];
l1ref1 = &h->ref_list[1][0].ref_index[1][4 * mb_xy];
if (!b8_stride) {
@@ -537,8 +538,8 @@ single_col:
await_reference_mb_row(h, &h->ref_list[1][0], mb_y);
- l1mv0 = &h->ref_list[1][0].motion_val[0][h->mb2b_xy[mb_xy]];
- l1mv1 = &h->ref_list[1][0].motion_val[1][h->mb2b_xy[mb_xy]];
+ l1mv0 = (void*)&h->ref_list[1][0].motion_val[0][h->mb2b_xy[mb_xy]];
+ l1mv1 = (void*)&h->ref_list[1][0].motion_val[1][h->mb2b_xy[mb_xy]];
l1ref0 = &h->ref_list[1][0].ref_index[0][4 * mb_xy];
l1ref1 = &h->ref_list[1][0].ref_index[1][4 * mb_xy];
if (!b8_stride) {
diff --git a/libavcodec/h264_loopfilter.c b/libavcodec/h264_loopfilter.c
index a15130c..a7b6878 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,
@@ -243,7 +241,7 @@ static av_always_inline void h264_filter_mb_fast_internal(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);
@@ -416,7 +414,7 @@ static av_always_inline void h264_filter_mb_fast_internal(H264Context *h,
}
void ff_h264_filter_mb_fast( H264Context *h, int mb_x, int mb_y, uint8_t *img_y, 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, mb_x, mb_y, img_y, img_cb, img_cr, linesize, uvlinesize);
return;
@@ -580,7 +578,9 @@ static av_always_inline void filter_mb_dir(H264Context *h, int mb_x, int mb_y, u
// 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;
+ //tprintf(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]);
tprintf(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++) tprintf(h->avctx, " bS[%d]:%d", i, bS[i]); tprintf(h->avctx, "\n"); }
chroma_qp_avg[0] = (h->chroma_qp[0] + get_chroma_qp(h, 0, h->cur_pic.qscale_table[mbm_xy]) + 1) >> 1;
chroma_qp_avg[1] = (h->chroma_qp[1] + get_chroma_qp(h, 1, h->cur_pic.qscale_table[mbm_xy]) + 1) >> 1;
if( dir == 0 ) {
@@ -663,7 +663,9 @@ static av_always_inline void filter_mb_dir(H264Context *h, int mb_x, int mb_y, u
// 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];
+ //tprintf(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]);
tprintf(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++) tprintf(h->avctx, " bS[%d]:%d", i, bS[i]); tprintf(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) {
@@ -704,7 +706,7 @@ void ff_h264_filter_mb( H264Context *h, int mb_x, int mb_y, uint8_t *img_y, uint
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 + h->slice_alpha_c0_offset - qp_bd_offset;
int b = 52 + h->slice_beta_offset - qp_bd_offset;
diff --git a/libavcodec/h264_mb.c b/libavcodec/h264_mb.c
index 61d68ab..7feae57 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,13 +40,13 @@ static inline int get_lowest_part_list_y(H264Context *h, H264Picture *pic, int n
int height, int y_offset, int list)
{
int raw_my = h->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(H264Context *h, int refs[2][48], int n,
@@ -118,7 +118,7 @@ static void await_references(H264Context *h)
} 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 = h->sub_mb_type[i];
@@ -150,7 +150,7 @@ static void await_references(H264Context *h)
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, refs, n + j, 4, sub_y_offset,
@@ -420,10 +420,12 @@ static av_always_inline void mc_part_weighted(H264Context *h, int n, int square,
int weight1 = 64 - weight0;
luma_weight_avg(dest_y, tmp_y, h->mb_linesize,
height, 5, weight0, weight1, 0);
- chroma_weight_avg(dest_cb, tmp_cb, h->mb_uvlinesize,
- chroma_height, 5, weight0, weight1, 0);
- chroma_weight_avg(dest_cr, tmp_cr, h->mb_uvlinesize,
- chroma_height, 5, weight0, weight1, 0);
+ if (!CONFIG_GRAY || !(h->flags & CODEC_FLAG_GRAY)) {
+ chroma_weight_avg(dest_cb, tmp_cb, h->mb_uvlinesize,
+ chroma_height, 5, weight0, weight1, 0);
+ chroma_weight_avg(dest_cr, tmp_cr, h->mb_uvlinesize,
+ chroma_height, 5, weight0, weight1, 0);
+ }
} else {
luma_weight_avg(dest_y, tmp_y, h->mb_linesize, height,
h->luma_log2_weight_denom,
@@ -431,18 +433,20 @@ static av_always_inline void mc_part_weighted(H264Context *h, int n, int square,
h->luma_weight[refn1][1][0],
h->luma_weight[refn0][0][1] +
h->luma_weight[refn1][1][1]);
- chroma_weight_avg(dest_cb, tmp_cb, h->mb_uvlinesize, chroma_height,
- h->chroma_log2_weight_denom,
- h->chroma_weight[refn0][0][0][0],
- h->chroma_weight[refn1][1][0][0],
- h->chroma_weight[refn0][0][0][1] +
- h->chroma_weight[refn1][1][0][1]);
- chroma_weight_avg(dest_cr, tmp_cr, h->mb_uvlinesize, chroma_height,
- h->chroma_log2_weight_denom,
- h->chroma_weight[refn0][0][1][0],
- h->chroma_weight[refn1][1][1][0],
- h->chroma_weight[refn0][0][1][1] +
- h->chroma_weight[refn1][1][1][1]);
+ if (!CONFIG_GRAY || !(h->flags & CODEC_FLAG_GRAY)) {
+ chroma_weight_avg(dest_cb, tmp_cb, h->mb_uvlinesize, chroma_height,
+ h->chroma_log2_weight_denom,
+ h->chroma_weight[refn0][0][0][0],
+ h->chroma_weight[refn1][1][0][0],
+ h->chroma_weight[refn0][0][0][1] +
+ h->chroma_weight[refn1][1][0][1]);
+ chroma_weight_avg(dest_cr, tmp_cr, h->mb_uvlinesize, chroma_height,
+ h->chroma_log2_weight_denom,
+ h->chroma_weight[refn0][0][1][0],
+ h->chroma_weight[refn1][1][1][0],
+ h->chroma_weight[refn0][0][1][1] +
+ h->chroma_weight[refn1][1][1][1]);
+ }
}
} else {
int list = list1 ? 1 : 0;
@@ -456,15 +460,17 @@ static av_always_inline void mc_part_weighted(H264Context *h, int n, int square,
h->luma_log2_weight_denom,
h->luma_weight[refn][list][0],
h->luma_weight[refn][list][1]);
- if (h->use_weight_chroma) {
- chroma_weight_op(dest_cb, h->mb_uvlinesize, chroma_height,
- h->chroma_log2_weight_denom,
- h->chroma_weight[refn][list][0][0],
- h->chroma_weight[refn][list][0][1]);
- chroma_weight_op(dest_cr, h->mb_uvlinesize, chroma_height,
- h->chroma_log2_weight_denom,
- h->chroma_weight[refn][list][1][0],
- h->chroma_weight[refn][list][1][1]);
+ if (!CONFIG_GRAY || !(h->flags & CODEC_FLAG_GRAY)) {
+ if (h->use_weight_chroma) {
+ chroma_weight_op(dest_cb, h->mb_uvlinesize, chroma_height,
+ h->chroma_log2_weight_denom,
+ h->chroma_weight[refn][list][0][0],
+ h->chroma_weight[refn][list][0][1]);
+ chroma_weight_op(dest_cr, h->mb_uvlinesize, chroma_height,
+ h->chroma_log2_weight_denom,
+ h->chroma_weight[refn][list][1][0],
+ h->chroma_weight[refn][list][1][1]);
+ }
}
}
}
@@ -487,9 +493,7 @@ static av_always_inline void prefetch_motion(H264Context *h, int list,
h->vdsp.prefetch(src[1] + off, h->linesize, 4);
h->vdsp.prefetch(src[2] + off, h->linesize, 4);
} else {
- off = ((mx >> 1) << pixel_shift) +
- ((my >> 1) + (h->mb_x & 7)) * h->uvlinesize +
- (64 << pixel_shift);
+ off= (((mx>>1)+64)<<pixel_shift) + ((my>>1) + (h->mb_x&7))*h->uvlinesize;
h->vdsp.prefetch(src[1] + off, src[2] - src[1], 2);
}
}
@@ -555,10 +559,8 @@ static av_always_inline void xchg_mb_border(H264Context *h, uint8_t *src_y,
XCHG(h->top_borders[top_idx][h->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);
@@ -571,9 +573,7 @@ static av_always_inline void xchg_mb_border(H264Context *h, uint8_t *src_y,
XCHG(h->top_borders[top_idx][h->mb_x + 1] + (16 << pixel_shift), src_cb + (17 << pixel_shift), 1);
XCHG(h->top_borders[top_idx][h->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);
@@ -630,7 +630,12 @@ static av_always_inline void hl_decode_mb_predict_luma(H264Context *h,
uint8_t *const ptr = dest_y + block_offset[i];
const int dir = h->intra4x4_pred_mode_cache[scan8[i]];
if (transform_bypass && h->sps.profile_idc == 244 && dir <= 1) {
- h->hpc.pred8x8l_add[dir](ptr, h->mb + (i * 16 + p * 256 << pixel_shift), linesize);
+ if (h->x264_build != -1) {
+ h->hpc.pred8x8l_add[dir](ptr, h->mb + (i * 16 + p * 256 << pixel_shift), linesize);
+ } else
+ h->hpc.pred8x8l_filter_add[dir](ptr, h->mb + (i * 16 + p * 256 << pixel_shift),
+ (h-> topleft_samples_available << i) & 0x8000,
+ (h->topright_samples_available << i) & 0x4000, linesize);
} else {
const int nnz = h->non_zero_count_cache[scan8[i + p * 16]];
h->hpc.pred8x8l[dir](ptr, (h->topleft_samples_available << i) & 0x8000,
@@ -663,7 +668,7 @@ static av_always_inline void hl_decode_mb_predict_luma(H264Context *h,
uint64_t tr_high;
if (dir == DIAG_DOWN_LEFT_PRED || dir == VERT_LEFT_PRED) {
const int topright_avail = (h->topright_samples_available << i) & 0x8000;
- assert(h->mb_y || linesize <= block_offset[i]);
+ av_assert2(h->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 5b2917f..7c9d72b 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)(H264Context *h)
}
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, h->intra_pcm_ptr,
@@ -116,13 +116,10 @@ static av_noinline void FUNC(hl_decode_mb)(H264Context *h)
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)(H264Context *h)
memcpy(dest_y + i * linesize, h->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 = h->intra_pcm_ptr + 256;
diff --git a/libavcodec/h264_mc_template.c b/libavcodec/h264_mc_template.c
index c085cc3..0e4e477 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
*/
@@ -72,7 +72,7 @@ static void MCFUNC(hl_motion)(H264Context *h, uint8_t *dest_y,
const int mb_xy = h->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);
@@ -104,7 +104,7 @@ static void MCFUNC(hl_motion)(H264Context *h, uint8_t *dest_y,
} 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 = h->sub_mb_type[i];
@@ -142,7 +142,7 @@ static void MCFUNC(hl_motion)(H264Context *h, uint8_t *dest_y,
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 3b212e5..ae96ee9 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 f7c3887..5f1e9a1 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(H264Context *h, const int16_t **C,
int i, int list, int part_width)
@@ -103,7 +103,7 @@ static av_always_inline void pred_motion(H264Context *const h, int n,
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
@@ -482,7 +482,7 @@ static void fill_decode_caches(H264Context *h, int mb_type)
} 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))) {
h->topleft_samples_available &= 0xDF5F;
h->left_samples_available &= 0x5F5F;
@@ -607,7 +607,7 @@ static void fill_decode_caches(H264Context *h, int mb_type)
int16_t(*mv)[2] = h->cur_pic.motion_val[list];
if (!USES_LIST(mb_type, list))
continue;
- assert(!(IS_DIRECT(mb_type) && !h->direct_spatial_mv_pred));
+ av_assert2(!(IS_DIRECT(mb_type) && !h->direct_spatial_mv_pred));
if (USES_LIST(top_type, list)) {
const int b_xy = h->mb2b_xy[top_xy] + 3 * b_stride;
@@ -664,7 +664,7 @@ static void fill_decode_caches(H264Context *h, int mb_type)
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 +
(h->topleft_partition & 2 * b_stride);
diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
index 2ed3dd0..6e87efa 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,24 +34,40 @@
#include "internal.h"
#include "mpegutils.h"
-#include <assert.h>
-
static int h264_find_frame_end(H264Context *h, const uint8_t *buf,
int buf_size)
{
- int i;
+ int i, j;
uint32_t state;
ParseContext *pc = &h->parse_context;
+ 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)
@@ -68,26 +86,40 @@ static int h264_find_frame_end(H264Context *h, 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 {
- 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)
@@ -170,14 +202,15 @@ 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)
{
H264Context *h = s->priv_data;
- 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 */
@@ -187,17 +220,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:
@@ -214,10 +261,13 @@ static inline int parse_nal_units(AVCodecParserContext *s,
}
break;
}
- ptr = ff_h264_decode_nal(h, buf, &dst_length, &consumed, src_length);
+ ptr = ff_h264_decode_nal(h, 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:
@@ -238,7 +288,7 @@ static inline int parse_nal_units(AVCodecParserContext *s,
h->prev_poc_lsb = 0;
/* fall through */
case NAL_SLICE:
- get_ue_golomb(&h->gb); // skip first_mb_in_slice
+ get_ue_golomb_long(&h->gb); // skip first_mb_in_slice
slice_type = get_ue_golomb_31(&h->gb);
s->pict_type = golomb_to_pict_type[slice_type % 5];
if (h->sei_recovery_frame_cnt >= 0) {
@@ -265,6 +315,9 @@ static inline int parse_nal_units(AVCodecParserContext *s,
h->sps = *h->sps_buffers[h->pps.sps_id];
h->frame_num = get_bits(&h->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;
+
avctx->profile = ff_h264_get_profile(&h->sps);
avctx->level = h->sps.level_idc;
@@ -389,10 +442,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;
}
@@ -409,14 +463,13 @@ static int h264_parse(AVCodecParserContext *s,
h->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);
}
}
@@ -432,13 +485,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(h, &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;
@@ -464,16 +519,19 @@ static int h264_split(AVCodecContext *avctx,
int i;
uint32_t state = -1;
int has_sps = 0;
+ int has_pps = 0;
for (i = 0; i <= buf_size; i++) {
if ((state & 0xFFFFFF1F) == 0x107)
has_sps = 1;
- /* if((state&0xFFFFFF1F) == 0x101 ||
+ if ((state & 0xFFFFFF1F) == 0x108)
+ has_pps = 1;
+ /* if ((state&0xFFFFFF1F) == 0x101 ||
* (state&0xFFFFFF1F) == 0x102 ||
* (state&0xFFFFFF1F) == 0x105) {
* }
*/
- if ((state & 0xFFFFFF00) == 0x100 && (state & 0xFFFFFF1F) != 0x106 &&
+ if ((state & 0xFFFFFF00) == 0x100 && ((state & 0xFFFFFF1F) != 0x106 || has_pps) &&
(state & 0xFFFFFF1F) != 0x107 && (state & 0xFFFFFF1F) != 0x108 &&
(state & 0xFFFFFF1F) != 0x109 && (state & 0xFFFFFF1F) != 0x10d &&
(state & 0xFFFFFF1F) != 0x10f) {
@@ -494,7 +552,7 @@ static void close(AVCodecParserContext *s)
H264Context *h = s->priv_data;
ParseContext *pc = &h->parse_context;
- av_free(pc->buffer);
+ av_freep(&pc->buffer);
ff_h264_free_context(h);
}
diff --git a/libavcodec/h264_picture.c b/libavcodec/h264_picture.c
index 1d7461b..b6bdae4 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)
{
@@ -115,7 +116,12 @@ int ff_h264_ref_picture(H264Context *h, H264Picture *dst, H264Picture *src)
dst->field_picture = src->field_picture;
dst->needs_realloc = src->needs_realloc;
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:
@@ -123,11 +129,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;
@@ -141,8 +149,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, int in_setup)
{
@@ -150,9 +158,9 @@ int ff_h264_field_end(H264Context *h, 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) {
@@ -171,6 +179,10 @@ int ff_h264_field_end(H264Context *h, 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
/*
* FIXME: Error handling code does not seem to support interlaced
@@ -184,16 +196,15 @@ int ff_h264_field_end(H264Context *h, 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)) {
- h264_set_erpic(&h->er.cur_pic, h->cur_pic_ptr);
- h264_set_erpic(&h->er.last_pic,
- h->ref_count[0] ? &h->ref_list[0][0] : NULL);
- h264_set_erpic(&h->er.next_pic,
- h->ref_count[1] ? &h->ref_list[1][0] : NULL);
+ if (!FIELD_PICTURE(h) && h->current_slice && !h->sps.new) {
+ ff_h264_set_erpic(&h->er.cur_pic, h->cur_pic_ptr);
ff_er_frame_end(&h->er);
}
#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 b439fa8..2013670 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
*/
@@ -70,13 +70,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] = {
@@ -182,6 +204,11 @@ 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);
@@ -207,7 +234,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,6 +260,7 @@ 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));
@@ -283,13 +312,11 @@ 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
}
}
@@ -327,10 +354,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 +373,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 +391,11 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
"Different chroma and luma bit depth");
goto fail;
}
+ if (sps->bit_depth_luma > 14U || sps->bit_depth_chroma > 14U) {
+ 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 +418,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 +445,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 +471,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 +483,8 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
int crop_right = get_ue_golomb(&h->gb);
int crop_top = get_ue_golomb(&h->gb);
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,6 +511,17 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
crop_left);
}
+ 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;
sps->crop_right = crop_right * step_x;
sps->crop_top = crop_top * step_y;
@@ -485,7 +538,7 @@ 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;
}
@@ -495,7 +548,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,
@@ -507,13 +560,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;
@@ -531,21 +586,32 @@ 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)
{
unsigned int pps_id = get_ue_golomb(&h->gb);
PPS *pps;
- const int qp_bd_offset = 6 * (h->sps.bit_depth_luma - 8);
+ SPS *sps;
+ int qp_bd_offset;
int bits_left;
if (pps_id >= MAX_PPS_COUNT) {
av_log(h->avctx, AV_LOG_ERROR, "pps_id %u out of range\n", pps_id);
return AVERROR_INVALIDDATA;
- } else if (h->sps.bit_depth_luma > 10) {
- av_log(h->avctx, AV_LOG_ERROR,
- "Unimplemented luma bit depth=%d (max=10)\n",
- h->sps.bit_depth_luma);
- return AVERROR_PATCHWELCOME;
}
pps = av_mallocz(sizeof(PPS));
@@ -557,6 +623,19 @@ int ff_h264_decode_picture_parameter_set(H264Context *h, int bit_length)
av_log(h->avctx, AV_LOG_ERROR, "sps_id %u out of range\n", pps->sps_id);
goto fail;
}
+ sps = h->sps_buffers[pps->sps_id];
+ qp_bd_offset = 6 * (sps->bit_depth_luma - 8);
+ if (sps->bit_depth_luma > 14) {
+ av_log(h->avctx, AV_LOG_ERROR,
+ "Invalid luma bit depth=%d\n",
+ sps->bit_depth_luma);
+ 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\n",
+ sps->bit_depth_luma);
+ goto fail;
+ }
pps->cabac = get_bits1(&h->gb);
pps->pic_order_present = get_bits1(&h->gb);
@@ -621,8 +700,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);
@@ -632,10 +710,8 @@ int ff_h264_decode_picture_parameter_set(H264Context *h, int bit_length)
pps->chroma_qp_index_offset[1] = pps->chroma_qp_index_offset[0];
}
- build_qp_table(pps, 0, pps->chroma_qp_index_offset[0],
- h->sps.bit_depth_luma);
- build_qp_table(pps, 1, pps->chroma_qp_index_offset[1],
- h->sps.bit_depth_luma);
+ build_qp_table(pps, 0, pps->chroma_qp_index_offset[0], sps->bit_depth_luma);
+ build_qp_table(pps, 1, pps->chroma_qp_index_offset[1], sps->bit_depth_luma);
if (pps->chroma_qp_index_offset[0] != pps->chroma_qp_index_offset[1])
pps->chroma_qp_diff = 1;
diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c
index 03c1b9c..12da921 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"
@@ -76,16 +77,18 @@ static int build_def_list(H264Picture *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);
}
@@ -133,13 +136,14 @@ int ff_h264_fill_default_ref_list(H264Context *h)
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 < h->ref_count[list])
memset(&h->default_ref_list[list][len], 0, sizeof(H264Picture) * (h->ref_count[list] - len));
@@ -163,6 +167,7 @@ int ff_h264_fill_default_ref_list(H264Context *h)
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 < h->ref_count[0])
memset(&h->default_ref_list[0][len], 0, sizeof(H264Picture) * (h->ref_count[0] - len));
@@ -324,13 +329,19 @@ int ff_h264_decode_ref_pic_list_reordering(H264Context *h)
}
for (list = 0; list < h->list_count; list++) {
for (index = 0; index < h->ref_count[list]; index++) {
- if (!h->ref_list[list][index].f.buf[0]) {
- av_log(h->avctx, AV_LOG_ERROR, "Missing reference picture\n");
- if (h->default_ref_list[list][0].f.buf[0])
+ if ( !h->ref_list[list][index].f.buf[0]
+ || (!FIELD_PICTURE(h) && (h->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].f.buf[0]
+ && !(!FIELD_PICTURE(h) && (h->default_ref_list[list][0].reference&3) != 3))
COPY_PICTURE(&h->ref_list[list][index], &h->default_ref_list[list][0]);
else
return -1;
}
+ av_assert0(av_buffer_get_ref_count(h->ref_list[list][index].f.buf[0]) > 0);
}
}
@@ -340,7 +351,7 @@ int ff_h264_decode_ref_pic_list_reordering(H264Context *h)
void ff_h264_fill_mbaff_ref_list(H264Context *h)
{
int list, i, j;
- for (list = 0; list < 2; list++) { //FIXME try list_count
+ for (list = 0; list < h->list_count; list++) {
for (i = 0; i < h->ref_count[list]; i++) {
H264Picture *frame = &h->ref_list[list][i];
H264Picture *field = &h->ref_list[list][16 + 2 * i];
@@ -487,6 +498,9 @@ void ff_h264_remove_all_refs(H264Context *h)
h->short_ref[i] = NULL;
}
h->short_ref_count = 0;
+
+ memset(h->default_ref_list, 0, sizeof(h->default_ref_list));
+ memset(h->ref_list, 0, sizeof(h->ref_list));
}
/**
@@ -528,8 +542,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;
@@ -540,10 +557,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;
@@ -562,8 +577,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;
@@ -572,6 +587,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);
@@ -592,7 +608,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;
@@ -633,10 +649,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;
@@ -664,6 +691,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);
}
@@ -702,8 +731,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
@@ -728,8 +756,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 = (h->cur_pic_ptr->frame_num - pic->frame_num) & ((1 << h->sps.log2_max_frame_num)-1);
+ 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;
}
@@ -737,7 +789,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
@@ -803,6 +855,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 52ff2ff..8e1697a 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 42d0c95..53f61ca 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,
@@ -255,6 +259,9 @@ static int alloc_picture(H264Context *h, H264Picture *pic)
h->linesize = pic->f.linesize[0];
h->uvlinesize = pic->f.linesize[1];
+ 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;
@@ -266,6 +273,18 @@ static int alloc_picture(H264Context *h, H264Picture *pic)
pic->hwaccel_picture_private = pic->hwaccel_priv_buf->data;
}
}
+ if (!h->avctx->hwaccel && CONFIG_GRAY && 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);
@@ -383,6 +402,8 @@ void 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) {
@@ -424,9 +445,9 @@ static void clone_tables(H264Context *dst, H264Context *src, int i)
#define IN_RANGE(a, b, size) (((a) >= (b)) && ((a) < ((b) + (size))))
#undef REBASE_PICTURE
#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,
@@ -464,8 +485,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, int reinit);
@@ -477,7 +498,7 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
int context_reinitialized = 0;
int i, ret;
- if (dst == src || !h1->context_initialized)
+ if (dst == src)
return 0;
if (inited &&
@@ -503,21 +524,37 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
h->mb_num = h1->mb_num;
h->mb_stride = h1->mb_stride;
h->b_stride = h1->b_stride;
+ // SPS/PPS
+ if ((ret = copy_parameter_set((void **)h->sps_buffers,
+ (void **)h1->sps_buffers,
+ MAX_SPS_COUNT, sizeof(SPS))) < 0)
+ return ret;
+ h->sps = h1->sps;
+ if ((ret = copy_parameter_set((void **)h->pps_buffers,
+ (void **)h1->pps_buffers,
+ MAX_PPS_COUNT, sizeof(PPS))) < 0)
+ return ret;
+ h->pps = h1->pps;
if ((err = h264_slice_header_init(h, 1)) < 0) {
- av_log(h->avctx, AV_LOG_ERROR, "h264_slice_header_init() failed");
+ av_log(h->avctx, AV_LOG_ERROR, "h264_slice_header_init() failed\n");
return err;
}
context_reinitialized = 1;
- /* update linesize on resize. The decoder doesn't
- * necessarily call h264_frame_start in the new thread */
- h->linesize = h1->linesize;
- h->uvlinesize = h1->uvlinesize;
-
- /* copy block_offset since frame_start may not be called */
- memcpy(h->block_offset, h1->block_offset, sizeof(h->block_offset));
+#if 0
+ h264_set_parameter_from_sps(h);
+ //Note we set context_reinitialized which will cause h264_set_parameter_from_sps to be reexecuted
+ h->cur_chroma_format_idc = h1->cur_chroma_format_idc;
+#endif
}
+ /* update linesize on resize for h264. The h264 decoder doesn't
+ * necessarily call ff_mpv_frame_start in the new thread */
+ h->linesize = h1->linesize;
+ h->uvlinesize = h1->uvlinesize;
+
+ /* copy block_offset since frame_start may not be called */
+ memcpy(h->block_offset, h1->block_offset, sizeof(h->block_offset));
if (!inited) {
for (i = 0; i < MAX_SPS_COUNT; i++)
@@ -526,18 +563,21 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
for (i = 0; i < MAX_PPS_COUNT; i++)
av_freep(h->pps_buffers + i);
- memcpy(h, h1, sizeof(*h1));
+ av_freep(&h->rbsp_buffer[0]);
+ av_freep(&h->rbsp_buffer[1]);
+ memcpy(h, h1, offsetof(H264Context, intra_pcm_ptr));
+ memcpy(&h->cabac, &h1->cabac,
+ sizeof(H264Context) - offsetof(H264Context, cabac));
+ av_assert0((void*)&h->cabac == &h->mb_padding + 1);
+
memset(h->sps_buffers, 0, sizeof(h->sps_buffers));
memset(h->pps_buffers, 0, sizeof(h->pps_buffers));
+
memset(&h->er, 0, sizeof(h->er));
memset(&h->mb, 0, sizeof(h->mb));
memset(&h->mb_luma_dc, 0, sizeof(h->mb_luma_dc));
memset(&h->mb_padding, 0, sizeof(h->mb_padding));
- h->context_initialized = 0;
-
memset(&h->cur_pic, 0, sizeof(h->cur_pic));
- av_frame_unref(&h->cur_pic.f);
- h->cur_pic.tf.f = &h->cur_pic.f;
h->avctx = dst;
h->DPB = NULL;
@@ -545,6 +585,28 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
h->mb_type_pool = NULL;
h->ref_index_pool = NULL;
h->motion_val_pool = NULL;
+ h->intra4x4_pred_mode= NULL;
+ h->non_zero_count = NULL;
+ h->slice_table_base = NULL;
+ h->slice_table = NULL;
+ h->cbp_table = NULL;
+ h->chroma_pred_mode_table = NULL;
+ memset(h->mvd_table, 0, sizeof(h->mvd_table));
+ h->direct_table = NULL;
+ h->list_counts = NULL;
+ h->mb2b_xy = NULL;
+ h->mb2br_xy = NULL;
+ for (i = 0; i < 2; i++) {
+ h->rbsp_buffer[i] = NULL;
+ h->rbsp_buffer_size[i] = 0;
+ }
+
+ if (h1->context_initialized) {
+ h->context_initialized = 0;
+
+ memset(&h->cur_pic, 0, sizeof(h->cur_pic));
+ av_frame_unref(&h->cur_pic.f);
+ h->cur_pic.tf.f = &h->cur_pic.f;
ret = ff_h264_alloc_tables(h);
if (ret < 0) {
@@ -556,17 +618,13 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
av_log(dst, AV_LOG_ERROR, "context_init() failed.\n");
return ret;
}
-
- for (i = 0; i < 2; i++) {
- h->rbsp_buffer[i] = NULL;
- h->rbsp_buffer_size[i] = 0;
}
+
h->bipred_scratchpad = NULL;
h->edge_emu_buffer = NULL;
h->thread_context[0] = h;
-
- h->context_initialized = 1;
+ h->context_initialized = h1->context_initialized;
}
h->avctx->coded_height = h1->avctx->coded_height;
@@ -580,28 +638,22 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
h->droppable = h1->droppable;
h->low_delay = h1->low_delay;
- for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) {
+ for (i = 0; h->DPB && i < H264_MAX_PICTURE_COUNT; i++) {
ff_h264_unref_picture(h, &h->DPB[i]);
- if (h1->DPB[i].f.buf[0] &&
+ if (h1->DPB && h1->DPB[i].f.buf[0] &&
(ret = ff_h264_ref_picture(h, &h->DPB[i], &h1->DPB[i])) < 0)
return ret;
}
h->cur_pic_ptr = REBASE_PICTURE(h1->cur_pic_ptr, h, h1);
ff_h264_unref_picture(h, &h->cur_pic);
- if ((ret = ff_h264_ref_picture(h, &h->cur_pic, &h1->cur_pic)) < 0)
+ if (h1->cur_pic.f.buf[0] && (ret = ff_h264_ref_picture(h, &h->cur_pic, &h1->cur_pic)) < 0)
return ret;
h->workaround_bugs = h1->workaround_bugs;
h->low_delay = h1->low_delay;
h->droppable = h1->droppable;
- /* frame_start may not be called for the next thread (if it's decoding
- * a bottom field) so this has to be allocated here */
- err = alloc_scratch_buffers(h, h1->linesize);
- if (err < 0)
- return err;
-
// extradata/NAL handling
h->is_avc = h1->is_avc;
@@ -642,7 +694,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 (context_reinitialized)
ff_h264_set_parameter_from_sps(h);
@@ -660,7 +712,6 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
h->outputed_poc = h->next_outputed_poc;
h->recovery_frame = h1->recovery_frame;
- h->frame_recovered = h1->frame_recovered;
return err;
}
@@ -670,6 +721,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;
@@ -684,6 +746,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.
@@ -692,17 +755,29 @@ 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->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)
+ if (CONFIG_ERROR_RESILIENCE) {
ff_er_frame_start(&h->er);
+ ff_h264_set_erpic(&h->er.last_pic, NULL);
+ ff_h264_set_erpic(&h->er.next_pic, NULL);
+ }
assert(h->linesize && h->uvlinesize);
@@ -717,20 +792,6 @@ static int h264_frame_start(H264Context *h)
h->block_offset[48 + 32 + i] = (4 * ((scan8[i] - scan8[0]) & 7) << pixel_shift) + 8 * h->uvlinesize * ((scan8[i] - scan8[0]) >> 3);
}
- /* can't be in alloc_tables because linesize isn't known there.
- * FIXME: redo bipred weight to not require extra buffer? */
- for (i = 0; i < h->slice_context_count; i++)
- if (h->thread_context[i]) {
- ret = alloc_scratch_buffers(h->thread_context[i], h->linesize);
- if (ret < 0)
- return ret;
- }
-
- /* 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().
@@ -915,13 +976,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]);
@@ -929,19 +990,19 @@ 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 ));
}
}
@@ -973,10 +1034,11 @@ static int clone_slice(H264Context *dst, H264Context *src)
return 0;
}
-static enum AVPixelFormat get_pixel_format(H264Context *h)
+static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
{
enum AVPixelFormat pix_fmts[2];
const enum AVPixelFormat *choices = pix_fmts;
+ int i;
pix_fmts[1] = AV_PIX_FMT_NONE;
@@ -1003,8 +1065,32 @@ static enum AVPixelFormat get_pixel_format(H264Context *h)
else
pix_fmts[0] = AV_PIX_FMT_YUV420P10;
break;
+ case 12:
+ if (CHROMA444(h)) {
+ if (h->avctx->colorspace == AVCOL_SPC_RGB) {
+ pix_fmts[0] = AV_PIX_FMT_GBRP12;
+ } else
+ pix_fmts[0] = AV_PIX_FMT_YUV444P12;
+ } else if (CHROMA422(h))
+ pix_fmts[0] = AV_PIX_FMT_YUV422P12;
+ else
+ pix_fmts[0] = AV_PIX_FMT_YUV420P12;
+ break;
+ case 14:
+ if (CHROMA444(h)) {
+ if (h->avctx->colorspace == AVCOL_SPC_RGB) {
+ pix_fmts[0] = AV_PIX_FMT_GBRP14;
+ } else
+ pix_fmts[0] = AV_PIX_FMT_YUV444P14;
+ } else if (CHROMA422(h))
+ pix_fmts[0] = AV_PIX_FMT_YUV422P14;
+ else
+ pix_fmts[0] = AV_PIX_FMT_YUV420P14;
+ break;
case 8:
if (CHROMA444(h)) {
+ if (h->avctx->colorspace == AVCOL_SPC_YCGCO)
+ av_log(h->avctx, AV_LOG_WARNING, "Detected unsupported YCgCo colorspace.\n");
if (h->avctx->colorspace == AVCOL_SPC_RGB)
pix_fmts[0] = AV_PIX_FMT_GBRP;
else if (h->avctx->color_range == AVCOL_RANGE_JPEG)
@@ -1031,7 +1117,10 @@ static enum AVPixelFormat get_pixel_format(H264Context *h)
return AVERROR_INVALIDDATA;
}
- 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 */
@@ -1041,6 +1130,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 &&
@@ -1091,7 +1182,7 @@ static int h264_slice_header_init(H264Context *h, int reinit)
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);
}
if (reinit)
@@ -1103,7 +1194,7 @@ static int h264_slice_header_init(H264Context *h, int reinit)
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 (nb_slices > H264_MAX_THREADS || (nb_slices > h->mb_height && h->mb_height)) {
@@ -1122,16 +1213,20 @@ static int h264_slice_header_init(H264Context *h, int reinit)
ret = ff_h264_context_init(h);
if (ret < 0) {
av_log(h->avctx, AV_LOG_ERROR, "context_init() failed.\n");
- return ret;
+ goto fail;
}
} else {
for (i = 1; i < h->slice_context_count; i++) {
H264Context *c;
c = h->thread_context[i] = av_mallocz(sizeof(H264Context));
- if (!c)
- return AVERROR(ENOMEM);
+ if (!c) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
c->avctx = h->avctx;
- c->mecc = h->mecc;
+ if (CONFIG_ERROR_RESILIENCE) {
+ c->mecc = h->mecc;
+ }
c->vdsp = h->vdsp;
c->h264dsp = h->h264dsp;
c->h264qpel = h->h264qpel;
@@ -1139,6 +1234,7 @@ static int h264_slice_header_init(H264Context *h, int reinit)
c->sps = h->sps;
c->pps = h->pps;
c->pixel_shift = h->pixel_shift;
+ c->cur_chroma_format_idc = h->cur_chroma_format_idc;
c->width = h->width;
c->height = h->height;
c->linesize = h->linesize;
@@ -1165,13 +1261,28 @@ static int h264_slice_header_init(H264Context *h, int reinit)
for (i = 0; i < h->slice_context_count; i++)
if ((ret = ff_h264_context_init(h->thread_context[i])) < 0) {
av_log(h->avctx, AV_LOG_ERROR, "context_init() failed.\n");
- return ret;
+ goto fail;
}
}
h->context_initialized = 1;
return 0;
+fail:
+ ff_h264_free_tables(h, 0);
+ 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;
+ }
}
/**
@@ -1190,15 +1301,15 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
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;
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(&h->gb);
+ first_mb_in_slice = get_ue_golomb_long(&h->gb);
if (first_mb_in_slice == 0) { // FIXME better field boundary detection
if (h0->current_slice && h->cur_pic_ptr && FIELD_PICTURE(h)) {
@@ -1229,10 +1340,6 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
h->slice_type_fixed = 0;
slice_type = golomb_to_pict_type[slice_type];
- if (slice_type == AV_PICTURE_TYPE_I ||
- (h0->current_slice != 0 && slice_type == h0->last_slice_type)) {
- default_ref_list_done = 1;
- }
h->slice_type = slice_type;
h->slice_type_nos = slice_type & 3;
@@ -1242,6 +1349,15 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
return AVERROR_INVALIDDATA;
}
+ if (
+ (h->avctx->skip_frame >= AVDISCARD_NONREF && !h->nal_ref_idc) ||
+ (h->avctx->skip_frame >= AVDISCARD_BIDIR && h->slice_type_nos == AV_PICTURE_TYPE_B) ||
+ (h->avctx->skip_frame >= AVDISCARD_NONINTRA && h->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 = h->slice_type;
@@ -1256,6 +1372,12 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
pps_id);
return AVERROR_INVALIDDATA;
}
+ if (h0->au_pps_id >= 0 && pps_id != h0->au_pps_id) {
+ av_log(h->avctx, AV_LOG_ERROR,
+ "PPS change from %d to %d forbidden\n",
+ h0->au_pps_id, pps_id);
+ return AVERROR_INVALIDDATA;
+ }
h->pps = *h0->pps_buffers[pps_id];
if (!h0->sps_buffers[h->pps.sps_id]) {
@@ -1266,11 +1388,18 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
}
if (h->pps.sps_id != h->sps.sps_id ||
+ h->pps.sps_id != h->current_sps_id ||
h0->sps_buffers[h->pps.sps_id]->new) {
- h0->sps_buffers[h->pps.sps_id]->new = 0;
h->sps = *h0->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->avctx->bits_per_raw_sample != 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) {
h->bit_depth_luma = h->sps.bit_depth_luma;
@@ -1285,9 +1414,17 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
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->avctx->bits_per_raw_sample != h->sps.bit_depth_luma
+ || h->cur_chroma_format_idc != h->sps.chroma_format_idc
+ || av_cmp_q(h->sps.sar, h->avctx->sample_aspect_ratio)
+ || h->mb_width != h->sps.mb_width
+ || h->mb_height != h->sps.mb_height * (2 - h->sps.frame_mbs_only_flag)
+ ));
+ if (non_j_pixfmt(h0->avctx->pix_fmt) != non_j_pixfmt(get_pixel_format(h0, 0)))
+ must_reinit = 1;
h->mb_width = h->sps.mb_width;
h->mb_height = h->sps.mb_height * (2 - h->sps.frame_mbs_only_flag);
@@ -1306,8 +1443,8 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
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;
@@ -1317,7 +1454,8 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
}
}
- if (h->context_initialized && needs_reinit) {
+ if (h->context_initialized &&
+ (must_reinit || needs_reinit)) {
if (h != h0) {
av_log(h->avctx, AV_LOG_ERROR,
"changing width %d -> %d / height %d -> %d on "
@@ -1330,12 +1468,12 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
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, 1)) < 0) {
av_log(h->avctx, AV_LOG_ERROR,
@@ -1350,7 +1488,7 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
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;
@@ -1376,6 +1514,10 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
if (h->sps.frame_mbs_only_flag) {
h->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(&h->gb);
if (field_pic_flag) {
bottom_field_flag = get_bits1(&h->gb);
@@ -1425,17 +1567,23 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
* 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 (h0->first_field) {
assert(h0->cur_pic_ptr);
assert(h0->cur_pic_ptr->f.buf[0]);
assert(h0->cur_pic_ptr->reference != DELAYED_PIC_REF);
+ /* Mark old field/frame as completed */
+ if (h0->cur_pic_ptr->tf.owner == h0->avctx) {
+ ff_thread_report_progress(&h0->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(&h0->cur_pic_ptr->tf, INT_MAX,
last_pic_structure == PICT_TOP_FIELD);
}
@@ -1445,7 +1593,7 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
* 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(&h0->cur_pic_ptr->tf, INT_MAX,
last_pic_structure == PICT_TOP_FIELD);
}
@@ -1472,11 +1620,14 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
}
}
- while (h->frame_num != h->prev_frame_num &&
+ while (h->frame_num != h->prev_frame_num && !h0->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) {
h0->first_field = 0;
@@ -1486,6 +1637,7 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
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);
@@ -1532,6 +1684,8 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
h0->first_field = FIELD_PICTURE(h);
} else {
if (h0->cur_pic_ptr->frame_num != h->frame_num) {
+ ff_thread_report_progress(&h0->cur_pic_ptr->tf, INT_MAX,
+ h0->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. */
@@ -1555,13 +1709,32 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
} 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));
+ }
+ h0->last_slice_type = -1;
}
if (h != h0 && (ret = clone_slice(h, h0)) < 0)
return ret;
+ /* can't be in alloc_tables because linesize isn't known there.
+ * FIXME: redo bipred weight to not require extra buffer? */
+ for (i = 0; i < h->slice_context_count; i++)
+ if (h->thread_context[i]) {
+ ret = alloc_scratch_buffers(h->thread_context[i], h->linesize);
+ if (ret < 0)
+ return ret;
+ }
+
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");
@@ -1572,7 +1745,7 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
FIELD_OR_MBAFF_PICTURE(h);
if (h->picture_structure == PICT_BOTTOM_FIELD)
h->resync_mb_y = h->mb_y = h->mb_y + 1;
- assert(h->mb_y < h->mb_height);
+ av_assert1(h->mb_y < h->mb_height);
if (h->picture_structure == PICT_FRAME) {
h->curr_pic_num = h->frame_num;
@@ -1607,11 +1780,14 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
ret = ff_set_ref_count(h);
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 &&
+ (h0->current_slice == 0 ||
+ slice_type != h0->last_slice_type ||
+ memcmp(h0->last_ref_count, h0->ref_count, sizeof(h0->ref_count)))) {
+
ff_h264_fill_default_ref_list(h);
+ }
if (h->slice_type_nos != AV_PICTURE_TYPE_I) {
ret = ff_h264_decode_ref_pic_list_reordering(h);
@@ -1718,6 +1894,8 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
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 &&
h->slice_type_nos != AV_PICTURE_TYPE_I) ||
(h->avctx->skip_loop_filter >= AVDISCARD_BIDIR &&
h->slice_type_nos == AV_PICTURE_TYPE_B) ||
@@ -1734,13 +1912,16 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
h0->max_contexts = 1;
if (!h0->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");
h0->single_decode_warning = 1;
}
if (h != h0) {
av_log(h->avctx, AV_LOG_ERROR,
"Deblocking switched inside frame.\n");
- return 1;
+ return SLICE_SINGLETHREAD;
}
}
}
@@ -1752,10 +1933,16 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
6 * (h->sps.bit_depth_luma - 8);
h0->last_slice_type = slice_type;
+ memcpy(h0->last_ref_count, h0->ref_count, sizeof(h0->last_ref_count));
h->slice_num = ++h0->current_slice;
- if (h->slice_num >= MAX_SLICES) {
- av_log(h->avctx, AV_LOG_ERROR,
- "Too many slices, increase MAX_SLICES and recompile\n");
+
+ if (h->slice_num)
+ h0->slice_row[(h->slice_num-1)&(MAX_SLICES-1)]= h->resync_mb_y;
+ if ( h0->slice_row[h->slice_num&(MAX_SLICES-1)] + 3 >= h->resync_mb_y
+ && h0->slice_row[h->slice_num&(MAX_SLICES-1)] <= h->resync_mb_y
+ && h->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", h->slice_num, MAX_SLICES);
}
for (j = 0; j < 2; j++) {
@@ -1791,6 +1978,15 @@ int ff_h264_decode_slice_header(H264Context *h, H264Context *h0)
(h->ref_list[j][i].reference & 3);
}
+ if (h->ref_count[0]) ff_h264_set_erpic(&h->er.last_pic, &h->ref_list[0][0]);
+ if (h->ref_count[1]) ff_h264_set_erpic(&h->er.next_pic, &h->ref_list[1][0]);
+
+ h->er.ref_count = h->ref_count[0];
+ h0->au_pps_id = pps_id;
+ h->sps.new =
+ h0->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",
@@ -1847,7 +2043,7 @@ static av_always_inline void fill_filter_caches_inter(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] = h->ref2frm[h->slice_table[top_xy] & (MAX_SLICES - 1)][0] + (MB_MBAFF(h) ? 20 : 2);
+ int (*ref2frm)[64] = (void*)(h->ref2frm[h->slice_table[top_xy] & (MAX_SLICES - 1)][0] + (MB_MBAFF(h) ? 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]];
@@ -1862,7 +2058,7 @@ static av_always_inline void fill_filter_caches_inter(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] = h->ref2frm[h->slice_table[left_xy[LTOP]] & (MAX_SLICES - 1)][0] + (MB_MBAFF(h) ? 20 : 2);
+ int (*ref2frm)[64] =(void*)( h->ref2frm[h->slice_table[left_xy[LTOP]] & (MAX_SLICES - 1)][0] + (MB_MBAFF(h) ? 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]);
@@ -1895,7 +2091,7 @@ static av_always_inline void fill_filter_caches_inter(H264Context *h,
{
int8_t *ref = &h->cur_pic.ref_index[list][4 * mb_xy];
- int (*ref2frm)[64] = h->ref2frm[h->slice_num & (MAX_SLICES - 1)][0] + (MB_MBAFF(h) ? 20 : 2);
+ int (*ref2frm)[64] = (void*)(h->ref2frm[h->slice_num & (MAX_SLICES - 1)][0] + (MB_MBAFF(h) ? 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);
@@ -2168,7 +2364,7 @@ static void decode_finish_row(H264Context *h)
ff_h264_draw_horiz_band(h, top, height);
- if (h->droppable)
+ if (h->droppable || h->er.error_occurred)
return;
ff_thread_report_progress(&h->cur_pic_ptr->tf, top + height - 1,
@@ -2178,12 +2374,11 @@ static void decode_finish_row(H264Context *h)
static void er_add_slice(H264Context *h, int startx, int starty,
int endx, int endy, int status)
{
-#if CONFIG_ERROR_RESILIENCE
- ERContext *er = &h->er;
+ if (CONFIG_ERROR_RESILIENCE) {
+ ERContext *er = &h->er;
- er->ref_count = h->ref_count[0];
- ff_er_add_slice(er, startx, starty, endx, endy, status);
-#endif
+ ff_er_add_slice(er, startx, starty, endx, endy, status);
+ }
}
static int decode_slice(struct AVCodecContext *avctx, void *arg)
@@ -2193,10 +2388,22 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg)
h->mb_skip_run = -1;
+ av_assert0(h->block_offset[15] == (4 * ((scan8[15] - scan8[0]) & 7) << h->pixel_shift) + 4 * h->linesize * ((scan8[15] - scan8[0]) >> 3));
+
h->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->er.error_status_table) {
+ const int start_i = av_clip(h->resync_mb_x + h->resync_mb_y * h->mb_width, 0, h->mb_num - 1);
+ if (start_i) {
+ int prev_status = h->er.error_status_table[h->er.mb_index2xy[start_i - 1]];
+ prev_status &= ~ VP_START;
+ if (prev_status != (ER_MV_END | ER_DC_END | ER_AC_END))
+ h->er.error_occurred = 1;
+ }
+ }
+
if (h->pps.cabac) {
/* realign */
align_get_bits(&h->gb);
@@ -2237,9 +2444,11 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg)
loop_filter(h, lf_x_start, h->mb_x + 1);
return 0;
}
- if (ret < 0 || h->cabac.bytestream > h->cabac.bytestream_end + 2) {
+ if (h->cabac.bytestream > h->cabac.bytestream_end + 2 )
+ av_log(h->avctx, AV_LOG_DEBUG, "bytestream overread %"PTRDIFF_SPECIFIER"\n", h->cabac.bytestream_end - h->cabac.bytestream);
+ if (ret < 0 || h->cabac.bytestream > h->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",
h->mb_x, h->mb_y,
h->cabac.bytestream_end - h->cabac.bytestream);
er_add_slice(h, h->resync_mb_x, h->resync_mb_y, h->mb_x,
@@ -2308,14 +2517,15 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg)
tprintf(h->avctx, "slice end %d %d\n",
get_bits_count(&h->gb), h->gb.size_in_bits);
- if (get_bits_left(&h->gb) == 0) {
+ if ( get_bits_left(&h->gb) == 0
+ || get_bits_left(&h->gb) > 0 && !(h->avctx->err_recognition & AV_EF_AGGRESSIVE)) {
er_add_slice(h, h->resync_mb_x, h->resync_mb_y,
h->mb_x - 1, h->mb_y, ER_MB_END);
return 0;
} else {
er_add_slice(h, h->resync_mb_x, h->resync_mb_y,
- h->mb_x - 1, h->mb_y, ER_MB_END);
+ h->mb_x, h->mb_y, ER_MB_END);
return AVERROR_INVALIDDATA;
}
@@ -2356,20 +2566,21 @@ int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count)
H264Context *hx;
int i;
- if (h->mb_y >= h->mb_height) {
- av_log(h->avctx, AV_LOG_ERROR,
- "Input contains more MB rows than the frame height.\n");
- return AVERROR_INVALIDDATA;
- }
+ av_assert0(h->mb_y < h->mb_height);
- if (h->avctx->hwaccel)
+ if (h->avctx->hwaccel ||
+ h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
return 0;
if (context_count == 1) {
return decode_slice(avctx, &h);
} else {
+ av_assert0(context_count > 0);
for (i = 1; i < context_count; i++) {
hx = h->thread_context[i];
- hx->er.error_count = 0;
+ if (CONFIG_ERROR_RESILIENCE) {
+ hx->er.error_count = 0;
+ }
+ hx->x264_build = h->x264_build;
}
avctx->execute(avctx, decode_slice, h->thread_context,
@@ -2381,8 +2592,10 @@ int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count)
h->mb_y = hx->mb_y;
h->droppable = hx->droppable;
h->picture_structure = hx->picture_structure;
- for (i = 1; i < context_count; i++)
- h->er.error_count += h->thread_context[i]->er.error_count;
+ if (CONFIG_ERROR_RESILIENCE) {
+ for (i = 1; i < context_count; i++)
+ h->er.error_count += h->thread_context[i]->er.error_count;
+ }
}
return 0;
diff --git a/libavcodec/h264addpx_template.c b/libavcodec/h264addpx_template.c
index cdbfc67..046b6c2 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 d5146de..5b3e13b 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 93064fe..d4b8a0e 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 028ed13..072b5e0 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 6b40b39..38f3258 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,
diff --git a/libavcodec/h264dsp.c b/libavcodec/h264dsp.c
index c8edbd0..ddcd6e6 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;
}
diff --git a/libavcodec/h264dsp.h b/libavcodec/h264dsp.h
index c4be235..85ea40b 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
*/
diff --git a/libavcodec/h264dsp_template.c b/libavcodec/h264dsp_template.c
index 3d99cfc..4d5faf0 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,7 +35,7 @@ static void FUNCC(weight_h264_pixels ## W)(uint8_t *_block, int stride, int heig
{ \
int y; \
pixel *block = (pixel*)_block; \
- stride /= sizeof(pixel); \
+ stride >>= sizeof(pixel)-1; \
offset <<= (log2_denom + (BIT_DEPTH-8)); \
if(log2_denom) offset += 1<<(log2_denom-1); \
for (y = 0; y < height; y++, block += stride) { \
@@ -66,7 +66,7 @@ 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); \
+ stride >>= sizeof(pixel)-1; \
offset <<= (BIT_DEPTH-8); \
offset = ((offset + 1) | 1) << log2_denom; \
for (y = 0; y < height; y++, dst += stride, src += stride) { \
@@ -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,14 +228,14 @@ 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;
if( tc <= 0 ) {
@@ -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 ea08d03..6a771af 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 816a825..17e0051 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 83c2a95..abf888e 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 b782a25..044fc90 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 5c4ef17..6708292 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 48baec8..f684433 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 ec46da2..5f1bfa3 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 97ce195..d71130d 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 e846ac9..27c5b8f 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 9b3d339..464aaab 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(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((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->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)
@@ -254,7 +147,7 @@ static void pred_weight_table(HEVCContext *s, GetBitContext *gb)
s->sh.luma_log2_weight_denom = get_ue_golomb_long(gb);
if (s->sps->chroma_format_idc != 0) {
int delta = get_se_golomb(gb);
- s->sh.chroma_log2_weight_denom = av_clip_c(s->sh.luma_log2_weight_denom + delta, 0, 7);
+ s->sh.chroma_log2_weight_denom = av_clip(s->sh.luma_log2_weight_denom + delta, 0, 7);
}
for (i = 0; i < s->sh.nb_refs[L0]; i++) {
@@ -264,7 +157,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 {
@@ -282,7 +175,7 @@ static void pred_weight_table(HEVCContext *s, GetBitContext *gb)
int delta_chroma_weight_l0 = get_se_golomb(gb);
int delta_chroma_offset_l0 = get_se_golomb(gb);
s->sh.chroma_weight_l0[i][j] = (1 << s->sh.chroma_log2_weight_denom) + delta_chroma_weight_l0;
- s->sh.chroma_offset_l0[i][j] = av_clip_c((delta_chroma_offset_l0 - ((128 * s->sh.chroma_weight_l0[i][j])
+ s->sh.chroma_offset_l0[i][j] = av_clip((delta_chroma_offset_l0 - ((128 * s->sh.chroma_weight_l0[i][j])
>> s->sh.chroma_log2_weight_denom) + 128), -128, 127);
}
} else {
@@ -318,7 +211,7 @@ static void pred_weight_table(HEVCContext *s, GetBitContext *gb)
int delta_chroma_weight_l1 = get_se_golomb(gb);
int delta_chroma_offset_l1 = get_se_golomb(gb);
s->sh.chroma_weight_l1[i][j] = (1 << s->sh.chroma_log2_weight_denom) + delta_chroma_weight_l1;
- s->sh.chroma_offset_l1[i][j] = av_clip_c((delta_chroma_offset_l1 - ((128 * s->sh.chroma_weight_l1[i][j])
+ s->sh.chroma_offset_l1[i][j] = av_clip((delta_chroma_offset_l1 - ((128 * s->sh.chroma_weight_l1[i][j])
>> s->sh.chroma_log2_weight_denom) + 128), -128, 127);
}
} else {
@@ -347,7 +240,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;
@@ -383,6 +276,24 @@ static int decode_lt_rps(HEVCContext *s, LongTermRPS *rps, GetBitContext *gb)
return 0;
}
+static int get_buffer_sao(HEVCContext *s, AVFrame *frame, const HEVCSPS *sps)
+{
+ int ret, i;
+
+ frame->width = s->avctx->coded_width + 2;
+ frame->height = s->avctx->coded_height + 2;
+ if ((ret = ff_get_buffer(s->avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
+ return ret;
+ for (i = 0; frame->data[i]; i++) {
+ int offset = frame->linesize[i] + (1 << sps->pixel_shift);
+ frame->data[i] += offset;
+ }
+ frame->width = s->avctx->coded_width;
+ frame->height = s->avctx->coded_height;
+
+ return 0;
+}
+
static int set_sps(HEVCContext *s, const HEVCSPS *sps)
{
int ret;
@@ -424,10 +335,8 @@ static int set_sps(HEVCContext *s, const HEVCSPS *sps)
if (sps->sao_enabled) {
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;
+ ret = get_buffer_sao(s, s->tmp_frame, sps);
+ s->sao_frame = s->tmp_frame;
}
s->sps = sps;
@@ -455,9 +364,9 @@ 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;
+ int i, j, ret;
// Coded parameters
sh->first_slice_in_pic_flag = get_bits1(gb);
@@ -467,6 +376,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);
@@ -481,10 +391,18 @@ 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);
if (ret < 0)
@@ -713,6 +631,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;
@@ -754,20 +677,52 @@ static int hls_slice_header(HEVCContext *s)
sh->num_entry_point_offsets = get_ue_golomb_long(gb);
if (sh->num_entry_point_offsets > 0) {
int offset_len = get_ue_golomb_long(gb) + 1;
-
- for (i = 0; i < sh->num_entry_point_offsets; i++)
- skip_bits(gb, offset_len);
- }
+ int segments = offset_len >> 4;
+ int rest = (offset_len & 15);
+ av_freep(&sh->entry_point_offset);
+ av_freep(&sh->offset);
+ av_freep(&sh->size);
+ sh->entry_point_offset = av_malloc_array(sh->num_entry_point_offsets, sizeof(int));
+ sh->offset = av_malloc_array(sh->num_entry_point_offsets, sizeof(int));
+ sh->size = av_malloc_array(sh->num_entry_point_offsets, sizeof(int));
+ if (!sh->entry_point_offset || !sh->offset || !sh->size) {
+ sh->num_entry_point_offsets = 0;
+ av_log(s->avctx, AV_LOG_ERROR, "Failed to allocate memory\n");
+ return AVERROR(ENOMEM);
+ }
+ for (i = 0; i < sh->num_entry_point_offsets; i++) {
+ int val = 0;
+ for (j = 0; j < segments; j++) {
+ val <<= 16;
+ val += get_bits(gb, 16);
+ }
+ if (rest) {
+ val <<= rest;
+ val += get_bits(gb, rest);
+ }
+ sh->entry_point_offset[i] = val + 1; // +1; // +1 to get the size
+ }
+ if (s->threads_number > 1 && (s->pps->num_tile_rows > 1 || s->pps->num_tile_columns > 1)) {
+ s->enable_parallel_tiles = 0; // TODO: you can enable tiles in parallel here
+ s->threads_number = 1;
+ } else
+ s->enable_parallel_tiles = 0;
+ } else
+ s->enable_parallel_tiles = 0;
}
if (s->pps->slice_header_extension_present_flag) {
unsigned int length = get_ue_golomb_long(gb);
+ if (length*8LL > get_bits_left(gb)) {
+ av_log(s->avctx, AV_LOG_ERROR, "too many slice_header_extension_data_bytes\n");
+ return AVERROR_INVALIDDATA;
+ }
for (i = 0; i < length; i++)
skip_bits(gb, 8); // slice_header_extension_data_byte
}
// Inferred parameters
- sh->slice_qp = 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,
@@ -785,13 +740,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;
}
@@ -812,10 +774,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;
@@ -832,6 +793,9 @@ static void hls_sao_param(HEVCContext *s, int rx, int ry)
}
for (c_idx = 0; c_idx < 3; 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;
@@ -867,13 +831,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] <<= log2_sao_offset_scale;
}
}
}
@@ -881,385 +846,46 @@ 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_c(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;
- }
-
- 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;
+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);
- 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 trafo_depth, int blk_idx,
- int cbf_luma, int cbf_cb, int cbf_cr)
+ 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);
@@ -1279,41 +905,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 (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 (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]);
+ 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 (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) {
+ 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;
}
@@ -1336,17 +1088,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 &&
@@ -1365,14 +1134,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 (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);
@@ -1401,8 +1177,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, trafo_depth,
@@ -1431,8 +1209,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];
@@ -1442,7 +1219,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;
@@ -1453,38 +1233,20 @@ 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);
+ s->hevcdsp.put_pcm(dst0, stride0, cb_size, cb_size, &gb, s->sps->pcm.bit_depth);
+ s->hevcdsp.put_pcm(dst1, stride1,
+ cb_size >> s->sps->hshift[1],
+ cb_size >> s->sps->vshift[1],
+ &gb, s->sps->pcm.bit_depth_chroma);
+ 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);
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;
- }
-
- 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;
- }
-}
-
/**
- * 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
@@ -1495,49 +1257,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);
- 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.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 interpolation process
+ * 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)
@@ -1549,87 +1409,182 @@ 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 = mv->x & ((1 << (2 + hshift)) - 1);
+ intptr_t my = mv->y & ((1 << (2 + vshift)) - 1);
+ intptr_t _mx = mx << (1 - hshift);
+ intptr_t _my = my << (1 - vshift);
+
+ x_off += mv->x >> (2 + hshift);
+ y_off += mv->y >> (2 + vshift);
+ src0 += y_off * srcstride + (x_off << s->sps->pixel_shift);
if (x_off < EPEL_EXTRA_BEFORE || y_off < EPEL_EXTRA_AFTER ||
x_off >= pic_width - block_w - EPEL_EXTRA_AFTER ||
y_off >= pic_height - block_h - EPEL_EXTRA_AFTER) {
const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
+ int offset0 = EPEL_EXTRA_BEFORE * (srcstride + (1 << s->sps->pixel_shift));
+ int buf_offset0 = EPEL_EXTRA_BEFORE *
+ (edge_emu_stride + (1 << s->sps->pixel_shift));
+ s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src0 - offset0,
+ edge_emu_stride, srcstride,
+ block_w + EPEL_EXTRA, block_h + EPEL_EXTRA,
+ x_off - EPEL_EXTRA_BEFORE,
+ y_off - EPEL_EXTRA_BEFORE,
+ pic_width, pic_height);
+
+ src0 = lc->edge_emu_buffer + buf_offset0;
+ srcstride = edge_emu_stride;
+ }
+ if (!weight_flag)
+ s->hevcdsp.put_hevc_epel_uni[idx][!!my][!!mx](dst0, dststride, src0, srcstride,
+ block_h, _mx, _my, block_w);
+ else
+ s->hevcdsp.put_hevc_epel_uni_w[idx][!!my][!!mx](dst0, dststride, src0, srcstride,
+ block_h, s->sh.chroma_log2_weight_denom,
+ chroma_weight, chroma_offset, _mx, _my, block_w);
+}
+
+/**
+ * 8.5.3.2.2.2 Chroma sample bidirectional interpolation process
+ *
+ * @param s HEVC decoding context
+ * @param dst target buffer for block data at block position
+ * @param dststride stride of the dst buffer
+ * @param ref0 reference picture0 buffer at origin (0, 0)
+ * @param mv0 motion vector0 (relative to block position) to get pixel data from
+ * @param x_off horizontal position of block from origin (0, 0)
+ * @param y_off vertical position of block from origin (0, 0)
+ * @param block_w width of block
+ * @param block_h height of block
+ * @param ref1 reference picture1 buffer at origin (0, 0)
+ * @param mv1 motion vector1 (relative to block position) to get pixel data from
+ * @param current_mv current motion vector structure
+ * @param cidx chroma component(cb, cr)
+ */
+static void chroma_mc_bi(HEVCContext *s, uint8_t *dst0, ptrdiff_t dststride, AVFrame *ref0, AVFrame *ref1,
+ int x_off, int y_off, int block_w, int block_h, struct MvField *current_mv, int cidx)
+{
+ HEVCLocalContext *lc = s->HEVClc;
+ uint8_t *src1 = ref0->data[cidx+1];
+ uint8_t *src2 = ref1->data[cidx+1];
+ ptrdiff_t src1stride = ref0->linesize[cidx+1];
+ ptrdiff_t src2stride = ref1->linesize[cidx+1];
+ int weight_flag = (s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
+ (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag);
+ int pic_width = s->sps->width >> s->sps->hshift[1];
+ int pic_height = s->sps->height >> s->sps->vshift[1];
+ Mv *mv0 = &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 = mv0->x & ((1 << (2 + hshift)) - 1);
+ intptr_t my0 = mv0->y & ((1 << (2 + vshift)) - 1);
+ intptr_t mx1 = mv1->x & ((1 << (2 + hshift)) - 1);
+ intptr_t my1 = mv1->y & ((1 << (2 + vshift)) - 1);
+ intptr_t _mx0 = mx0 << (1 - hshift);
+ intptr_t _my0 = my0 << (1 - vshift);
+ intptr_t _mx1 = mx1 << (1 - hshift);
+ intptr_t _my1 = my1 << (1 - vshift);
+
+ int x_off0 = x_off + (mv0->x >> (2 + hshift));
+ int y_off0 = y_off + (mv0->y >> (2 + vshift));
+ int x_off1 = x_off + (mv1->x >> (2 + hshift));
+ int y_off1 = y_off + (mv1->y >> (2 + vshift));
+ int idx = ff_hevc_pel_weight[block_w];
+ src1 += y_off0 * src1stride + (int)((unsigned)x_off0 << s->sps->pixel_shift);
+ src2 += y_off1 * src2stride + (int)((unsigned)x_off1 << s->sps->pixel_shift);
+
+ if (x_off0 < EPEL_EXTRA_BEFORE || y_off0 < EPEL_EXTRA_AFTER ||
+ x_off0 >= pic_width - block_w - EPEL_EXTRA_AFTER ||
+ y_off0 >= pic_height - block_h - EPEL_EXTRA_AFTER) {
+ const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
int offset1 = EPEL_EXTRA_BEFORE * (src1stride + (1 << s->sps->pixel_shift));
int buf_offset1 = EPEL_EXTRA_BEFORE *
(edge_emu_stride + (1 << s->sps->pixel_shift));
- 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 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 }}};
@@ -1638,9 +1593,6 @@ 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;
-
uint8_t *dst0 = POS(0, x0, y0);
uint8_t *dst1 = POS(1, x0, y0);
uint8_t *dst2 = POS(2, x0, y0);
@@ -1689,6 +1641,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
} else {
enum InterPredIdc inter_pred_idc = PRED_L0;
ff_hevc_set_neighbour_available(s, x0, y0, nPbW, nPbH);
+ current_mv.pred_flag = 0;
if (s->sh.slice_type == B_SLICE)
inter_pred_idc = ff_hevc_inter_pred_idc_decode(s, nPbW, nPbH);
@@ -1697,8 +1650,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
ref_idx[0] = ff_hevc_ref_idx_lx_decode(s, s->sh.nb_refs[L0]);
current_mv.ref_idx[0] = ref_idx[0];
}
- current_mv.pred_flag[0] = 1;
- hls_mvd_coding(s, x0, y0, 0);
+ current_mv.pred_flag = PF_L0;
+ ff_hevc_hls_mvd_coding(s, x0, y0, 0);
mvp_flag[0] = ff_hevc_mvp_lx_flag_decode(s);
ff_hevc_luma_mv_mvp_mode(s, x0, y0, nPbW, nPbH, log2_cb_size,
partIdx, merge_idx, &current_mv,
@@ -1716,10 +1669,10 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
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);
}
- current_mv.pred_flag[1] = 1;
+ current_mv.pred_flag += PF_L1;
mvp_flag[1] = ff_hevc_mvp_lx_flag_decode(s);
ff_hevc_luma_mv_mvp_mode(s, x0, y0, nPbW, nPbH, log2_cb_size,
partIdx, merge_idx, &current_mv,
@@ -1737,148 +1690,69 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
}
}
- 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]);
-
- luma_mc(s, tmp, tmpstride, ref0->frame,
- &current_mv.mv[0], 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_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]);
-
- if (!ref1)
- return;
-
- 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]);
- HEVCFrame *ref0 = refPicList[0].ref[current_mv.ref_idx[0]];
- HEVCFrame *ref1 = refPicList[1].ref[current_mv.ref_idx[1]];
-
- if (!ref0 || !ref1)
- return;
-
- 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 (current_mv.pred_flag == PF_L0) {
+ int x0_c = x0 >> s->sps->hshift[1];
+ int y0_c = y0 >> s->sps->vshift[1];
+ int nPbW_c = nPbW >> s->sps->hshift[1];
+ int nPbH_c = nPbH >> s->sps->vshift[1];
+
+ luma_mc_uni(s, dst0, s->frame->linesize[0], ref0->frame,
+ &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]]);
+
+ 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]]);
+
+ 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);
+
+ 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);
}
}
@@ -1888,7 +1762,7 @@ 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;
@@ -1958,15 +1832,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;
}
}
@@ -1986,10 +1852,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;
@@ -2015,14 +1885,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];
+ }
}
}
@@ -2030,7 +1928,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;
@@ -2041,22 +1939,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;
@@ -2080,17 +1981,22 @@ static int hls_coding_unit(HEVCContext *s, int x0, int y0, int log2_cb_size)
if (s->sh.slice_type != I_SLICE) {
uint8_t skip_flag = ff_hevc_skip_flag_decode(s, x0, y0, x_cb, y_cb);
- lc->cu.pred_mode = MODE_SKIP;
x = y_cb * min_cb_width + x_cb;
for (y = 0; y < length; y++) {
memset(&s->skip_flag[x], skip_flag, length);
x += min_cb_width;
}
lc->cu.pred_mode = skip_flag ? MODE_SKIP : MODE_INTER;
+ } else {
+ 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)
@@ -2126,37 +2032,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;
}
}
@@ -2167,12 +2073,13 @@ static int hls_coding_unit(HEVCContext *s, int x0, int y0, int log2_cb_size)
lc->cu.rqt_root_cbf = ff_hevc_no_residual_syntax_flag_decode(s);
}
if (lc->cu.rqt_root_cbf) {
+ const static int cbf[2] = { 0 };
lc->cu.max_trafo_depth = lc->cu.pred_mode == MODE_INTRA ?
s->sps->max_transform_hierarchy_depth_intra + lc->cu.intra_split_flag :
s->sps->max_transform_hierarchy_depth_inter;
ret = hls_transform_tree(s, x0, y0, x0, y0, x0, y0,
log2_cb_size,
- log2_cb_size, 0, 0, 0, 0);
+ log2_cb_size, 0, 0, cbf, cbf);
if (ret < 0)
return ret;
} else {
@@ -2183,7 +2090,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++) {
@@ -2191,7 +2098,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;
}
@@ -2199,11 +2111,13 @@ 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 qp_block_mask = (1<<(s->sps->log2_ctb_size - s->pps->diff_cu_qp_delta_depth)) - 1;
int split_cu;
- lc->ct.depth = cb_depth;
+ 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) {
@@ -2217,31 +2131,63 @@ 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) {
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;
- SUBDIVIDE(x0, y0);
- SUBDIVIDE(x1, y0);
- SUBDIVIDE(x0, y1);
- SUBDIVIDE(x1, y1);
+ if (more_data && x1 < s->sps->width) {
+ more_data = hls_coding_quadtree(s, x1, y0, log2_cb_size - 1, cb_depth + 1);
+ if (more_data < 0)
+ return more_data;
+ }
+ if (more_data && y1 < s->sps->height) {
+ more_data = hls_coding_quadtree(s, x0, y1, log2_cb_size - 1, cb_depth + 1);
+ if (more_data < 0)
+ return more_data;
+ }
+ if (more_data && x1 < s->sps->width &&
+ y1 < s->sps->height) {
+ more_data = hls_coding_quadtree(s, x1, y1, log2_cb_size - 1, cb_depth + 1);
+ if (more_data < 0)
+ return more_data;
+ }
+
+ if(((x0 + (1<<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;
@@ -2250,7 +2196,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;
@@ -2264,7 +2210,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;
}
@@ -2297,14 +2242,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];
@@ -2321,10 +2279,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);
@@ -2333,18 +2293,181 @@ 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 (!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)
@@ -2358,39 +2481,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;
@@ -2442,23 +2538,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;
@@ -2474,6 +2571,11 @@ 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)
@@ -2484,7 +2586,7 @@ static int hevc_frame_start(HEVCContext *s)
return 0;
fail:
- if (s->ref)
+ if (s->ref && s->threads_type == FF_THREAD_FRAME)
ff_thread_report_progress(&s->ref->tf, INT_MAX, 0);
s->ref = NULL;
return ret;
@@ -2492,7 +2594,7 @@ fail:
static int decode_nal_unit(HEVCContext *s, const uint8_t *nal, int length)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
GetBitContext *gb = &lc->gb;
int ctb_addr_ts, ret;
@@ -2594,13 +2696,12 @@ static int decode_nal_unit(HEVCContext *s, const uint8_t *nal, int length)
}
}
- 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, length);
+ 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) {
@@ -2630,12 +2731,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) { \
@@ -2707,6 +2809,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;
@@ -2730,6 +2843,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
@@ -2752,21 +2866,24 @@ 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));
@@ -2777,17 +2894,30 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length)
s->nals = tmp;
memset(s->nals + s->nals_allocated, 0,
(new_size - s->nals_allocated) * sizeof(*tmp));
+ av_reallocp_array(&s->skipped_bytes_nal, new_size, sizeof(*s->skipped_bytes_nal));
+ av_reallocp_array(&s->skipped_bytes_pos_size_nal, new_size, sizeof(*s->skipped_bytes_pos_size_nal));
+ av_reallocp_array(&s->skipped_bytes_pos_nal, new_size, sizeof(*s->skipped_bytes_pos_nal));
+ s->skipped_bytes_pos_size_nal[s->nals_allocated] = 1024; // initial buffer size
+ s->skipped_bytes_pos_nal[s->nals_allocated] = av_malloc_array(s->skipped_bytes_pos_size_nal[s->nals_allocated], sizeof(*s->skipped_bytes_pos));
s->nals_allocated = new_size;
}
- 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);
@@ -2802,7 +2932,11 @@ 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++) {
- int ret = decode_nal_unit(s, s->nals[i].data, s->nals[i].size);
+ int ret;
+ s->skipped_bytes = s->skipped_bytes_nal[i];
+ s->skipped_bytes_pos = s->skipped_bytes_pos_nal[i];
+
+ ret = decode_nal_unit(s, s->nals[i].data, s->nals[i].size);
if (ret < 0) {
av_log(s->avctx, AV_LOG_WARNING,
"Error parsing NAL unit #%d.\n", i);
@@ -2811,7 +2945,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;
@@ -2936,7 +3070,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;
@@ -2975,6 +3111,15 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
av_freep(&s->md5_ctx);
+ 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);
+
av_frame_free(&s->tmp_frame);
av_frame_free(&s->output_frame);
@@ -2989,6 +3134,26 @@ 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_buffer_unref(&s->current_sps);
+
+ av_freep(&s->sh.entry_point_offset);
+ av_freep(&s->sh.offset);
+ av_freep(&s->sh.size);
+
+ for (i = 1; i < s->threads_number; i++) {
+ HEVCLocalContext *lc = s->HEVClcList[i];
+ if (lc) {
+ av_freep(&s->HEVClcList[i]);
+ av_freep(&s->sList[i]);
+ }
+ }
+ if (s->HEVClc == s->HEVClcList[0])
+ s->HEVClc = NULL;
+ av_freep(&s->HEVClcList[0]);
for (i = 0; i < s->nals_allocated; i++)
av_freep(&s->nals[i].rbsp_buffer);
@@ -3005,6 +3170,16 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
s->avctx = avctx;
+ s->HEVClc = av_mallocz(sizeof(HEVCLocalContext));
+ if (!s->HEVClc)
+ goto fail;
+ s->HEVClcList[0] = s->HEVClc;
+ s->sList[0] = s;
+
+ s->cabac_state = av_malloc(HEVC_CONTEXTS);
+ if (!s->cabac_state)
+ goto fail;
+
s->tmp_frame = av_frame_alloc();
if (!s->tmp_frame)
goto fail;
@@ -3029,6 +3204,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
ff_bswapdsp_init(&s->bdsp);
s->context_initialized = 1;
+ s->eos = 0;
return 0;
@@ -3059,6 +3235,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]) {
@@ -3086,17 +3264,29 @@ static int hevc_update_thread_context(AVCodecContext *dst,
}
}
+ av_buffer_unref(&s->current_sps);
+ if (s0->current_sps) {
+ s->current_sps = av_buffer_ref(s0->current_sps);
+ if (!s->current_sps)
+ return AVERROR(ENOMEM);
+ }
+
if (s->sps != s0->sps)
- ret = set_sps(s, s0->sps);
+ if ((ret = set_sps(s, s0->sps)) < 0)
+ return ret;
s->seq_decode = s0->seq_decode;
s->seq_output = s0->seq_output;
s->pocTid0 = s0->pocTid0;
s->max_ra = s0->max_ra;
+ s->eos = s0->eos;
s->is_nalff = s0->is_nalff;
s->nal_length_size = s0->nal_length_size;
+ s->threads_number = s0->threads_number;
+ s->threads_type = s0->threads_type;
+
if (s0->eos) {
s->seq_decode = (s->seq_decode + 1) & 0xff;
s->max_ra = INT_MAX;
@@ -3182,6 +3372,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) {
@@ -3190,6 +3388,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;
}
@@ -3221,12 +3424,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 },
};
@@ -3251,6 +3457,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 93c5125..7205a78 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 {
@@ -568,11 +600,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;
@@ -594,10 +631,6 @@ typedef struct SliceHeader {
int slice_ctb_addr_rs;
} SliceHeader;
-typedef struct CodingTree {
- int depth; ///< ctDepth
-} CodingTree;
-
typedef struct CodingUnit {
int x;
int y;
@@ -623,8 +656,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 {
@@ -642,15 +674,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 {
@@ -661,6 +702,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;
@@ -698,24 +740,11 @@ typedef struct HEVCNAL {
const uint8_t *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;
@@ -724,18 +753,22 @@ 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;
+ DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer2)[(MAX_PB_SIZE + 7) * EDGE_EMU_BUFFER_STRIDE * 2];
+ DECLARE_ALIGNED(16, int16_t, tmp [MAX_PB_SIZE * MAX_PB_SIZE]);
+
+ int ct_depth;
CodingUnit cu;
PredictionUnit pu;
NeighbourAvailable na;
@@ -753,9 +786,18 @@ 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;
@@ -772,6 +814,8 @@ typedef struct HEVCContext {
AVBufferRef *sps_list[MAX_SPS_COUNT];
AVBufferRef *pps_list[MAX_PPS_COUNT];
+ AVBufferRef *current_sps;
+
AVBufferPool *tab_mvf_pool;
AVBufferPool *rpl_tab_pool;
@@ -789,6 +833,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;
@@ -828,6 +873,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;
@@ -844,6 +901,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;
@@ -857,6 +916,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,
@@ -866,6 +927,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.
*/
@@ -921,32 +985,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.
@@ -961,6 +1004,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,
@@ -972,18 +1017,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 276cd33..3862df7 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);
}
@@ -365,13 +539,16 @@ static void cabac_init_state(HEVCContext *s)
int init_value = init_values[init_type][i];
int m = (init_value >> 4) * 5 - 45;
int n = ((init_value & 15) << 3) - 16;
- int pre = 2 * (((m * av_clip_c(s->sh.slice_qp, 0, 51)) >> 4) + n) - 127;
+ int pre = 2 * (((m * av_clip(s->sh.slice_qp, 0, 51)) >> 4) + n) - 127;
pre ^= pre >> 31;
if (pre > 124)
pre = 124 + (pre & 1);
- s->HEVClc.cabac_state[i] = pre;
+ 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)
@@ -478,9 +661,9 @@ int ff_hevc_skip_flag_decode(HEVCContext *s, int x0, int y0, int x_cb, int y_cb)
int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
- if (s->HEVClc.ctb_left_flag || x0b)
+ 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)
@@ -529,9 +728,9 @@ int ff_hevc_split_coding_unit_flag_decode(HEVCContext *s, int ct_depth, int x0,
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 ff_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 = ff_hevc_transform_skip_flag_decode(s, c_idx);
+ }
+
+ if (c_idx == 0) {
+ qp = qp_y + s->sps->qp_bd_offset;
+ } else {
+ int qp_i, offset;
+
+ if (c_idx == 1)
+ offset = s->pps->cb_qp_offset + s->sh.slice_cb_qp_offset +
+ lc->tu.cu_qp_offset_cb;
+ else
+ offset = s->pps->cr_qp_offset + s->sh.slice_cr_qp_offset +
+ lc->tu.cu_qp_offset_cr;
+
+ qp_i = av_clip(qp_y + offset, - s->sps->qp_bd_offset, 57);
+ if (s->sps->chroma_format_idc == 1) {
+ if (qp_i < 30)
+ qp = qp_i;
+ else if (qp_i > 43)
+ qp = qp_i - 6;
+ else
+ qp = qp_c[qp_i - 30];
+ } else {
+ if (qp_i > 51)
+ qp = 51;
+ else
+ qp = qp_i;
+ }
+
+ qp += s->sps->qp_bd_offset;
+ }
+
+ shift = s->sps->bit_depth + log2_trafo_size - 5;
+ add = 1 << (shift-1);
+ scale = level_scale[rem6[qp]] << (div6[qp]);
+ scale_m = 16; // default when no custom scaling lists.
+ dc_scale = 16;
+
+ if (s->sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) {
+ const ScalingList *sl = s->pps->scaling_list_data_present_flag ?
+ &s->pps->scaling_list : &s->sps->scaling_list;
+ int matrix_id = lc->cu.pred_mode != MODE_INTRA;
+
+ matrix_id = 3 * matrix_id + c_idx;
+
+ scale_matrix = sl->sl[log2_trafo_size - 2][matrix_id];
+ if (log2_trafo_size >= 4)
+ dc_scale = sl->sl_dc[log2_trafo_size - 4][matrix_id];
+ }
+ } else {
+ shift = 0;
+ add = 0;
+ scale = 0;
+ dc_scale = 0;
+ }
+
+ 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 91a1e1f..3aaf3e5 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
@@ -58,29 +60,31 @@ static int chroma_tc(HEVCContext *s, int qp_y, int c_idx, int tc_offset)
else
offset = s->pps->cr_qp_offset;
- qp_i = av_clip_c(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];
+ qp_i = av_clip(qp_y + offset, 0, 57);
+ if (s->sps->chroma_format_idc == 1) {
+ if (qp_i < 30)
+ qp = qp_i;
+ else if (qp_i > 43)
+ qp = qp_i - 6;
+ else
+ qp = qp_c[qp_i - 30];
+ } else {
+ qp = av_clip(qp_i, 0, 51);
+ }
- idxt = av_clip_c(qp + DEFAULT_INTRA_TC_OFFSET + tc_offset, 0, 53);
+ 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)
@@ -173,14 +140,46 @@ static int get_qPy(HEVCContext *s, int xC, int yC)
}
static void copy_CTB(uint8_t *dst, uint8_t *src,
- int width, int height, int stride)
+ int width, int height, int stride_dst, int stride_src)
{
int i;
for (i = 0; i < height; i++) {
memcpy(dst, src, width);
- dst += stride;
- src += stride;
+ dst += stride_dst;
+ src += stride_src;
+ }
+}
+
+static void restore_tqb_pixels(HEVCContext *s, 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;
+ ptrdiff_t stride_dst = s->sao_frame->linesize[c_idx];
+ ptrdiff_t stride_src = s->frame->linesize[c_idx];
+ 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;
+ 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 = &s->frame->data[c_idx][ ((y << s->sps->log2_min_pu_size) >> vshift) * stride_src + (((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_dst + (((x << s->sps->log2_min_pu_size) >> hshift) << s->sps->pixel_shift)];
+ for (n = 0; n < (min_pu_size >> vshift); n++) {
+ memcpy(src, dst, len);
+ src += stride_src;
+ dst += stride_dst;
+ }
+ }
+ }
+ }
}
}
@@ -188,128 +187,127 @@ 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;
+ 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;
+ 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 stride_dst = s->sao_frame->linesize[c_idx];
+ int ctb_size_h = (1 << (s->sps->log2_ctb_size)) >> s->sps->hshift[c_idx];
+ int ctb_size_v = (1 << (s->sps->log2_ctb_size)) >> s->sps->vshift[c_idx];
+ int width = FFMIN(ctb_size_h, (s->sps->width >> s->sps->hshift[c_idx]) - x0);
+ int height = FFMIN(ctb_size_v, (s->sps->height >> s->sps->vshift[c_idx]) - y0);
+ uint8_t *src = &s->frame->data[c_idx][y0 * stride_src + (x0 << s->sps->pixel_shift)];
+ uint8_t *dst = &s->sao_frame->data[c_idx][y0 * stride_dst + (x0 << s->sps->pixel_shift)];
+
+ switch (sao->type_idx[c_idx]) {
+ case SAO_BAND:
+ copy_CTB(dst, src, width << s->sps->pixel_shift, height, stride_dst, stride_src);
+ s->hevcdsp.sao_band_filter(src, dst,
+ stride_src, stride_dst,
+ sao,
+ edges, width,
+ height, c_idx);
+ restore_tqb_pixels(s, x, y, width, height, c_idx);
+ sao->type_idx[c_idx] = SAO_APPLIED;
+ break;
+ case SAO_EDGE:
+ {
+ uint8_t left_pixels = !edges[0] && (CTB(s->sao, x_ctb-1, y_ctb).type_idx[c_idx] != SAO_APPLIED);
+ if (!edges[1]) {
+ uint8_t top_left = !edges[0] && (CTB(s->sao, x_ctb-1, y_ctb-1).type_idx[c_idx] != SAO_APPLIED);
+ uint8_t top_right = !edges[2] && (CTB(s->sao, x_ctb+1, y_ctb-1).type_idx[c_idx] != SAO_APPLIED);
+ if (CTB(s->sao, x_ctb , y_ctb-1).type_idx[c_idx] == 0)
+ memcpy( dst - stride_dst - (top_left << s->sps->pixel_shift),
+ src - stride_src - (top_left << s->sps->pixel_shift),
+ (top_left + width + top_right) << s->sps->pixel_shift);
+ else {
+ if (top_left)
+ memcpy( dst - stride_dst - (1 << s->sps->pixel_shift),
+ src - stride_src - (1 << s->sps->pixel_shift),
+ 1 << s->sps->pixel_shift);
+ if(top_right)
+ memcpy( dst - stride_dst + (width << s->sps->pixel_shift),
+ src - stride_src + (width << s->sps->pixel_shift),
+ 1 << s->sps->pixel_shift);
+ }
+ }
+ if (!edges[3]) { // bottom and bottom right
+ uint8_t bottom_left = !edges[0] && (CTB(s->sao, x_ctb-1, y_ctb+1).type_idx[c_idx] != SAO_APPLIED);
+ memcpy( dst + height * stride_dst - (bottom_left << s->sps->pixel_shift),
+ src + height * stride_src - (bottom_left << s->sps->pixel_shift),
+ (width + 1 + bottom_left) << s->sps->pixel_shift);
}
+ copy_CTB(dst - (left_pixels << s->sps->pixel_shift),
+ src - (left_pixels << s->sps->pixel_shift),
+ (width + 1 + left_pixels) << s->sps->pixel_shift, height, stride_dst, stride_src);
+ s->hevcdsp.sao_edge_filter[restore](src, dst,
+ stride_src, stride_dst,
+ sao,
+ edges, width,
+ height, c_idx,
+ vert_edge,
+ horiz_edge,
+ diag_edge);
+ restore_tqb_pixels(s, x, y, width, height, c_idx);
+ sao->type_idx[c_idx] = SAO_APPLIED;
+ break;
+ }
}
}
}
@@ -338,18 +336,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 +358,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 +373,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 +403,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,37 +437,61 @@ 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];
+ 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(!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 + 8, y - 1) + get_qPy(s, x + 8, y) + 1) >> 1 : 0;
+ 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;
- 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)];
+ 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 + 8, y - 1);
- no_q[0] = get_pcm(s, x, y);
- no_q[1] = get_pcm(s, x + 8, y);
+ 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);
@@ -505,79 +505,65 @@ static void deblocking_filter_CTB(HEVCContext *s, int x0, int y0)
}
}
-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 +572,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 +597,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 +610,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 +635,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 +697,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 48cd234..318e7a2 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,7 +41,7 @@ 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;
+ HEVCLocalContext *lc = s->HEVClc;
int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
@@ -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;
}
@@ -141,14 +115,14 @@ static av_always_inline void mv_scale(Mv *dst, Mv *src, int td, int tb)
{
int tx, scale_factor;
- td = av_clip_int8_c(td);
- tb = av_clip_int8_c(tb);
+ td = av_clip_int8(td);
+ tb = av_clip_int8(tb);
tx = (0x4000 + abs(td / 2)) / td;
- scale_factor = av_clip_c((tb * tx + 32) >> 6, -4096, 4095);
- dst->x = av_clip_int16_c((scale_factor * src->x + 127 +
- (scale_factor * src->x < 0)) >> 8);
- dst->y = av_clip_int16_c((scale_factor * src->y + 127 +
- (scale_factor * src->y < 0)) >> 8);
+ scale_factor = av_clip((tb * tx + 32) >> 6, -4096, 4095);
+ dst->x = av_clip_int16((scale_factor * src->x + 127 +
+ (scale_factor * src->x < 0)) >> 8);
+ dst->y = av_clip_int16((scale_factor * src->y + 127 +
+ (scale_factor * src->y < 0)) >> 8);
}
static int check_mvset(Mv *mvLXCol, Mv *mvCol,
@@ -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);
-
- if (isDiffMER(s, xB0, yB0, x0, y0))
- is_available_b0 = 0;
+ is_available_b0 = AVAILABLE(cand_up_right, B0) &&
+ xB0 < s->sps->width &&
+ PRED_BLOCK_AVAILABLE(B0) &&
+ !is_diff_mer(s, xB0, yB0, x0, y0);
- if (is_available_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);
-
- if (isDiffMER(s, xA0, yA0, x0, y0))
- is_available_a0 = 0;
+ is_available_a0 = AVAILABLE(cand_bottom_left, A0) &&
+ yA0 < s->sps->height &&
+ PRED_BLOCK_AVAILABLE(A0) &&
+ !is_diff_mer(s, xA0, yA0, x0, y0);
- if (is_available_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_available_b2 = AVAILABLE(cand_up_left, B2) &&
+ !is_diff_mer(s, xB2, yB2, x0, y0);
- 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 ac2c6f5..834b93b 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;
@@ -116,10 +305,46 @@ static int hevc_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
return 0;
}
+static int hevc_init(AVCodecParserContext *s)
+{
+ HEVCContext *h = &((HEVCParseContext *)s->priv_data)->h;
+ h->HEVClc = av_mallocz(sizeof(HEVCLocalContext));
+ h->skipped_bytes_pos_size = INT_MAX;
+
+ return 0;
+}
+
+static void hevc_close(AVCodecParserContext *s)
+{
+ int i;
+ HEVCContext *h = &((HEVCParseContext *)s->priv_data)->h;
+ ParseContext *pc = &((HEVCParseContext *)s->priv_data)->pc;
+
+ av_freep(&h->skipped_bytes_pos);
+ av_freep(&h->HEVClc);
+ av_freep(&pc->buffer);
+
+ for (i = 0; i < FF_ARRAY_ELEMS(h->vps_list); i++)
+ av_buffer_unref(&h->vps_list[i]);
+ for (i = 0; i < FF_ARRAY_ELEMS(h->sps_list); i++)
+ av_buffer_unref(&h->sps_list[i]);
+ for (i = 0; i < FF_ARRAY_ELEMS(h->pps_list); i++)
+ av_buffer_unref(&h->pps_list[i]);
+
+ av_buffer_unref(&h->current_sps);
+ h->sps = NULL;
+
+ for (i = 0; i < h->nals_allocated; i++)
+ av_freep(&h->nals[i].rbsp_buffer);
+ av_freep(&h->nals);
+ h->nals_allocated = 0;
+}
+
AVCodecParser ff_hevc_parser = {
.codec_ids = { AV_CODEC_ID_HEVC },
- .priv_data_size = sizeof(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 bc18990..4e1c561 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"
@@ -73,7 +72,7 @@ static const AVRational vui_sar[] = {
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;
@@ -88,7 +87,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;
@@ -106,6 +106,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);
@@ -193,10 +199,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);
@@ -207,6 +217,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);
@@ -220,34 +232,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++) {
@@ -262,10 +295,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;
@@ -309,20 +342,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));
@@ -359,7 +398,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);
@@ -369,7 +409,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;
@@ -384,6 +424,11 @@ 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 - 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]
@@ -407,6 +452,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;
+ }
+
av_buffer_unref(&s->vps_list[vps_id]);
s->vps_list[vps_id] = vps_buf;
return 0;
@@ -419,8 +470,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");
@@ -473,7 +525,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;
@@ -499,9 +558,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);
@@ -546,20 +620,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. */
@@ -603,13 +682,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;
@@ -651,7 +744,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) {
@@ -661,8 +755,8 @@ 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");
+ if (!(sps->chroma_format_idc == 1 || sps->chroma_format_idc == 2 || sps->chroma_format_idc == 3)) {
+ avpriv_report_missing_feature(s->avctx, "chroma_format_idc != {1, 2, 3}\n");
ret = AVERROR_PATCHWELCOME;
goto err;
}
@@ -670,6 +764,9 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
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,
@@ -711,21 +808,32 @@ 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 == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P;
+ if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P;
+ if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P;
+ break;
+ case 9:
+ if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P9;
+ if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P9;
+ if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P9;
+ break;
+ case 10:
+ if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P10;
+ if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P10;
+ if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P10;
+ break;
+ case 12:
+ if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P12;
+ if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P12;
+ if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P12;
+ break;
+ default:
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);
@@ -800,7 +908,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;
}
@@ -855,8 +963,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;
@@ -906,6 +1048,7 @@ 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);
@@ -936,6 +1079,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; "
@@ -956,6 +1105,12 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
if (s->pps_list[i] && ((HEVCPPS*)s->pps_list[i]->data)->sps_id == sps_id)
av_buffer_unref(&s->pps_list[i]);
}
+ if (s->sps_list[sps_id] && s->sps == (HEVCSPS*)s->sps_list[sps_id]->data) {
+ av_buffer_unref(&s->current_sps);
+ s->current_sps = av_buffer_ref(s->sps_list[sps_id]);
+ if (!s->current_sps)
+ s->sps = NULL;
+ }
av_buffer_unref(&s->sps_list[sps_id]);
s->sps_list[sps_id] = sps_buf;
}
@@ -980,16 +1135,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;
@@ -1018,6 +1209,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);
@@ -1164,7 +1356,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;
}
@@ -1178,7 +1370,14 @@ 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) {
+ pps_range_extensions(s, pps, sps);
+ }
+ }
// Inferred parameters
pps->col_bd = av_malloc_array(pps->num_tile_columns + 1, sizeof(*pps->col_bd));
@@ -1228,14 +1427,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;
}
@@ -1290,8 +1488,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;
@@ -1301,10 +1504,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;
+ }
+
av_buffer_unref(&s->pps_list[pps_id]);
s->pps_list[pps_id] = pps_buf;
diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c
index 658ead7..b3a9787 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
*/
@@ -53,8 +53,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];
}
@@ -105,8 +104,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);
return frame;
-
fail:
ff_hevc_unref_frame(s, frame, ~0);
return NULL;
@@ -158,6 +158,16 @@ 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) &&
@@ -177,16 +187,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;
@@ -194,8 +204,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);
@@ -211,6 +221,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;
@@ -357,7 +407,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 978a0e3..5bb5c90 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,59 @@ 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
+
+ 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 +158,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 +194,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 0abee9b..3eae541 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,110 @@ 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 = FUNC(sao_band_filter_0, depth); \
+ hevcdsp->sao_edge_filter[0] = FUNC(sao_edge_filter_0, depth); \
+ hevcdsp->sao_edge_filter[1] = FUNC(sao_edge_filter_1, depth); \
+ \
+ QPEL_FUNCS(depth); \
+ QPEL_UNI_FUNCS(depth); \
+ QPEL_BI_FUNCS(depth); \
+ EPEL_FUNCS(depth); \
+ EPEL_UNI_FUNCS(depth); \
+ EPEL_BI_FUNCS(depth); \
+ \
hevcdsp->hevc_h_loop_filter_luma = FUNC(hevc_h_loop_filter_luma, depth); \
hevcdsp->hevc_v_loop_filter_luma = FUNC(hevc_v_loop_filter_luma, depth); \
hevcdsp->hevc_h_loop_filter_chroma = FUNC(hevc_h_loop_filter_chroma, depth); \
@@ -174,7 +230,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 +240,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;
diff --git a/libavcodec/hevcdsp.h b/libavcodec/hevcdsp.h
index aad96db..ced3b99 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,104 @@
#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)(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);
+
+ void (*sao_edge_filter[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][4];
+extern const int8_t ff_hevc_qpel_filters[3][16];
-extern const int8_t ff_hevc_epel_filters[7][16];
+void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth);
#endif /* AVCODEC_HEVCDSP_H */
diff --git a/libavcodec/hevcdsp_template.c b/libavcodec/hevcdsp_template.c
index 8dcc83d..8a843f5 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,14 +35,14 @@ 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;
}
}
-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)
{
int x, y;
@@ -57,7 +59,7 @@ static void FUNC(transquant_bypass4x4)(uint8_t *_dst, int16_t *coeffs,
}
}
-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)
{
int x, y;
@@ -74,7 +76,7 @@ static void FUNC(transquant_bypass8x8)(uint8_t *_dst, int16_t *coeffs,
}
}
-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)
{
int x, y;
@@ -91,7 +93,7 @@ static void FUNC(transquant_bypass16x16)(uint8_t *_dst, int16_t *coeffs,
}
}
-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)
{
int x, y;
@@ -108,24 +110,52 @@ static void FUNC(transquant_bypass32x32)(uint8_t *_dst, int16_t *coeffs,
}
}
-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++;
+ }
+ }
}
}
@@ -149,17 +179,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++;
@@ -168,323 +194,238 @@ 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
-static void FUNC(sao_band_filter)(uint8_t *_dst, uint8_t *_src,
- ptrdiff_t stride, SAOParams *sao,
+#undef SET
+#undef SCALE
+#undef ADD_AND_SCALE
+
+static void FUNC(sao_band_filter_0)(uint8_t *_dst, uint8_t *_src,
+ ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao,
int *borders, int width, int height,
- int c_idx, int class)
+ int c_idx)
{
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];
+ int16_t *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) ? 1 : ((a) == (b) ? 0 : -1))
-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, ptrdiff_t stride_src, SAOParams *sao,
+ int width, int height,
+ int c_idx, int init_x, int init_y) {
-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
+ };
+ int16_t *sao_offset_val = sao->offset_val[c_idx];
+ int sao_eo_class = sao->eo_class[c_idx];
+ pixel *dst = (pixel *)_dst;
+ pixel *src = (pixel *)_src;
-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);
+ int y_stride_src = init_y * stride_src;
+ int y_stride_dst = init_y * stride_dst;
+ int pos_0_0 = pos[sao_eo_class][0][0];
+ int pos_0_1 = pos[sao_eo_class][0][1];
+ int pos_1_0 = pos[sao_eo_class][1][0];
+ int pos_1_1 = pos[sao_eo_class][1][1];
+ int x, y;
+
+ int y_stride_0_1 = (init_y + pos_0_1) * stride_src;
+ int y_stride_1_1 = (init_y + pos_1_1) * stride_src;
+ for (y = init_y; y < height; y++) {
+ for (x = init_x; x < width; x++) {
+ int diff0 = CMP(src[x + y_stride_src], src[x + pos_0_0 + y_stride_0_1]);
+ int diff1 = CMP(src[x + y_stride_src], src[x + pos_1_0 + y_stride_1_1]);
+ int offset_val = edge_idx[2 + diff0 + diff1];
+ dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + sao_offset_val[offset_val]);
+ }
+ y_stride_src += stride_src;
+ y_stride_dst += stride_dst;
+ y_stride_0_1 += stride_src;
+ y_stride_1_1 += stride_src;
+ }
}
static void FUNC(sao_edge_filter_0)(uint8_t *_dst, uint8_t *_src,
- ptrdiff_t stride, SAOParams *sao,
+ 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);
-
- 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--;
}
@@ -497,523 +438,727 @@ static void FUNC(sao_edge_filter_0)(uint8_t *_dst, uint8_t *_src,
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
+ FUNC(sao_edge_filter)((uint8_t *)dst, (uint8_t *)src, stride_dst, stride_src, sao, width, height, c_idx, init_x, init_y);
}
static void FUNC(sao_edge_filter_1)(uint8_t *_dst, uint8_t *_src,
- ptrdiff_t stride, SAOParams *sao,
+ 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--;
}
}
+ FUNC(sao_edge_filter)((uint8_t *)dst, (uint8_t *)src, stride_dst, stride_src, sao, width, height, c_idx, init_x, init_y);
+
{
+ 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;
@@ -1026,49 +1171,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);
@@ -1078,71 +1275,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;
+ }
- shift = 14 - BIT_DEPTH;
- log2Wd = denom + shift;
- offset = 1 << (log2Wd - 1);
- wx = wlxFlag;
- ox = olxFlag * (1 << (BIT_DEPTH - 8));
+ tmp = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;
+ filter = ff_hevc_epel_filters[my - 1];
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift);
+ tmp += MAX_PB_SIZE;
+ dst += dststride;
+ src2 += MAX_PB_SIZE;
+ }
+}
+
+static void FUNC(put_hevc_epel_uni_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_epel_filters[mx - 1];
+ int shift = denom + 14 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+ ox = ox * (1 << (BIT_DEPTH - 8));
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
- 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]
@@ -1293,21 +1692,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),
@@ -1315,7 +1714,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 1ba2487..4598229 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 0000000..7f14a76
--- /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 53b9c59..8124230 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 size_in_luma_pu_v = PU(size_in_luma_v);
+ int size_in_luma_pu_h = PU(size_in_luma_h);
int on_pu_edge_x = !(x0 & ((1 << s->sps->log2_min_pu_size) - 1));
int on_pu_edge_y = !(y0 & ((1 << s->sps->log2_min_pu_size) - 1));
- if (!size_in_luma_pu)
- size_in_luma_pu++;
+ 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 b200e89..d8c51d0 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
*/
@@ -36,8 +36,8 @@
typedef struct Hnm4VideoContext {
uint8_t version;
- uint16_t width;
- uint16_t height;
+ int width;
+ int height;
uint8_t *current;
uint8_t *previous;
uint8_t *buffer1;
@@ -78,7 +78,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);
@@ -99,11 +99,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--) {
@@ -146,7 +146,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);
@@ -156,7 +157,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) {
@@ -167,6 +173,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--;
@@ -175,6 +185,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;
@@ -187,17 +201,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) {
@@ -262,6 +287,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++;
@@ -270,6 +299,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;
@@ -278,14 +311,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;
}
@@ -359,17 +397,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)
@@ -382,6 +426,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);
@@ -421,7 +468,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 81d3892..fccfe76 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 25694c5..7763760 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 d037cba..07c293a 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/huffman.c b/libavcodec/huffman.c
index dec2197..2866eef 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) {
+ 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 043e6e3..6ab23ae 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 da5c52f..4921555 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 aed1537..c18247e 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 1ad81f7..3b2b0f7 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;
- for (u = 0; u < 256; u++) {
+ if ((sign_extend(y, 8) & (s->vlc_n-1)) != y)
+ continue;
+ 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)
@@ -255,23 +277,28 @@ 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,9 +307,20 @@ 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;
@@ -320,36 +358,189 @@ static av_cold int decode_init(AVCodecContext *avctx)
return ret;
}
- 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:
+ return AVERROR_INVALIDDATA;
+ }
+ 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:
+ return AVERROR_INVALIDDATA;
+ }
}
+ 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");
+ return AVERROR_INVALIDDATA;
+ }
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;
}
- if ((ret = ff_huffyuv_alloc_temp(s)) < 0)
+ if ((ret = ff_huffyuv_alloc_temp(s)) < 0) {
+ ff_huffyuv_common_end(s);
return ret;
+ }
return 0;
}
@@ -359,13 +550,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 +570,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 +743,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 +847,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 +887,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 +918,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 +994,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 +1149,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,18 +1171,16 @@ 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;
+ left[A] = 0;
if ((y & s->interlaced) == 0 &&
y < s->height - 1 - s->interlaced) {
s->hdsp.add_bytes(p->data[0] + p->linesize[0] * y,
@@ -758,7 +1197,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;
}
}
@@ -777,7 +1217,7 @@ static av_cold int decode_end(AVCodecContext *avctx)
ff_huffyuv_common_end(s);
av_freep(&s->bitstream_buffer);
- for (i = 0; i < 6; i++)
+ for (i = 0; i < 8; i++)
ff_free_vlc(&s->vlc[i]);
return 0;
diff --git a/libavcodec/huffyuvdsp.c b/libavcodec/huffyuvdsp.c
index b5a714d..e8a05f6 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 5e84e3a..78b2bca 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
*/
@@ -21,17 +21,28 @@
#include <stdint.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 47fe2a5..c7e69d5 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
*/
/**
@@ -30,32 +32,66 @@
#include "huffyuv.h"
#include "huffman.h"
#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)
{
@@ -117,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 {
@@ -141,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();
@@ -160,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;
@@ -177,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) {
@@ -189,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;
@@ -198,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;
@@ -245,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;
@@ -339,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;
@@ -396,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 \
@@ -448,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;
}
@@ -631,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");
}
@@ -644,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);
@@ -684,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"),
@@ -693,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
@@ -709,8 +1092,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
},
};
diff --git a/libavcodec/huffyuvencdsp.c b/libavcodec/huffyuvencdsp.c
index 6c30877..95fcc19 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 603c36f..3a49b4a 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 70c98d6..7765376 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
*/
@@ -76,7 +76,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
@@ -170,7 +170,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;
@@ -189,7 +189,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++];
@@ -204,6 +204,8 @@ static void idcin_decode_vlcs(IdcinContext *s, AVFrame *frame)
prev = node_num;
}
}
+
+ return 0;
}
static int idcin_decode_frame(AVCodecContext *avctx,
@@ -220,12 +222,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 a9b8727..b497221 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) {
+ 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 c49a4ca..538b716 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 112c2ca..ce06b36 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 {
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 40a543d..cb5871c 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 bc65a96..6f7bba6 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 500f564..dcedbd6 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"
@@ -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;
@@ -356,7 +365,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 +459,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;
@@ -887,6 +901,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;
@@ -997,7 +1018,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 +1027,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];
@@ -1044,7 +1063,15 @@ static av_cold int imc_decode_close(AVCodecContext * avctx)
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 +1081,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 +1097,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 8e99391..64e7c71 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/imgconvert.c b/libavcodec/imgconvert.c
index 365dc54..158bc73 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];
@@ -504,3 +455,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 56d89b2..0ce626d 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 5f5493f..be43fbc 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
*/
@@ -53,7 +53,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 4221e9e..cccac44 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
*/
@@ -149,10 +149,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 ed8d83c..0d6d82f 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 f74ac42..d38765e 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"
@@ -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;
@@ -937,12 +953,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;
@@ -1040,17 +1052,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 +1094,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 +1108,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 28c9bb6..e7e28a3 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 35f266e..ed4272b 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
*/
@@ -183,6 +183,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;
@@ -270,6 +271,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);
@@ -327,6 +329,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;
@@ -335,13 +341,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) {
@@ -349,25 +358,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,
@@ -375,10 +388,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 */
@@ -422,6 +444,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;
}
@@ -440,7 +467,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;
@@ -455,6 +482,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;
@@ -494,8 +526,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) {
@@ -561,6 +595,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 8311c68..efc5a65 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
*/
@@ -61,7 +61,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 5a112f9..71a54d5 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 f4252b5..a6217d0 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 e34da5c..5ed1cdb 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
*/
@@ -58,14 +58,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 +81,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))
@@ -115,9 +115,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 3b2ae40..dcb2113 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
*/
@@ -35,6 +35,14 @@
#define FF_SANE_NB_CHANNELS 63U
+#if HAVE_AVX
+# define STRIDE_ALIGN 32
+#elif HAVE_SIMD_ALIGN_16
+# define STRIDE_ALIGN 16
+#else
+# define STRIDE_ALIGN 8
+#endif
+
typedef struct FramePool {
/**
* Pools for each data plane. For audio all the planes have the same size,
@@ -78,6 +86,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.
@@ -97,6 +113,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;
@@ -107,6 +136,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.
@@ -115,6 +146,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);
+int ff_unlock_avcodec(void);
+
int avpriv_lock_avformat(void);
int avpriv_unlock_avformat(void);
@@ -132,6 +175,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.
@@ -141,6 +185,8 @@ int avpriv_unlock_avformat(void);
* @param size the minimum required packet size
* @return 0 on success, negative error code on failure
*/
+int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int64_t size);
+
int ff_alloc_packet(AVPacket *avpkt, int size);
/**
@@ -149,6 +195,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);
}
@@ -166,9 +214,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 af7aa13..96c0cd1 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);
}
- av_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
+ av_dlog(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));
}
- av_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
+ av_dlog(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;
- av_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
+ av_dlog(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);
- av_dlog(NULL, " motion bytes = %d, %d\n", x, y);
+ av_dlog(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);
- av_dlog(NULL, " motion bytes = %d, %d\n", x, y);
+ av_dlog(s->avctx, "motion bytes = %d, %d\n", x, y);
return copy_from(s, s->second_last_frame, frame, x, y);
}
@@ -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 303b926..017536d 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 6967317..9981785 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 1115945..1b34f89 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 5c3cc4a..1e4a3af 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 6bf01f3..375906b 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 da78e5d..4a07ac2 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"
@@ -101,11 +102,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);
@@ -128,6 +127,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;
}
}
@@ -201,27 +201,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
*/
@@ -345,7 +324,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)) {
@@ -439,7 +418,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;
@@ -482,7 +461,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->err_recognition & AV_EF_BITSTREAM)
+ if(s->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT))
return -1;
}
if (level == 255)
@@ -500,39 +479,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;
@@ -546,9 +553,7 @@ retry:
}
j = scan_table[i];
block[j] = level;
- if (last)
- break;
- i++;
+ }
}
not_coded:
if (s->mb_intra && s->h263_aic) {
@@ -563,11 +568,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)
@@ -575,6 +582,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;
}
@@ -604,7 +612,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{
@@ -744,15 +752,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{
@@ -871,6 +877,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) {
@@ -960,6 +970,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) {
@@ -1027,6 +1039,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;
@@ -1071,6 +1084,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;
@@ -1099,9 +1116,8 @@ 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) {
@@ -1127,7 +1143,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 5f15b2f..43ad080 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
*/
@@ -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);
@@ -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) {
@@ -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_common.c b/libavcodec/ivi_common.c
index 7c4d53e..3795081 100644
--- a/libavcodec/ivi_common.c
+++ b/libavcodec/ivi_common.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);
@@ -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_common.h b/libavcodec/ivi_common.h
index e2cc593..9fec960 100644
--- a/libavcodec/ivi_common.h
+++ b/libavcodec/ivi_common.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 ecc49b3..89121ac 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 11c2f5c..15562b6 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
*/
@@ -64,6 +64,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 0000000..ddb0b68
--- /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
+ ))
+ 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;
+
+ 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))
+ 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))
+ 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))
+ 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))
+ return ret;
+ if (ret = put_cod(s))
+ return ret;
+ if (ret = put_qcd(s, 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))
+ 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))
+ 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 0000000..c3665ae
--- /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 0000000..2f94956
--- /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);
+ 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 ed6b7ff..6a39578 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 c6a1638..3ea2f5d 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 2ccd078..644e25d 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 b96b7e2..acdba62 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 5135297..17ee541 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
+#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 6e04c3a..a7c7f53 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 45a32c0..de1ddb9 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 6642a53..ceceda3 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 f08340d..b6d296d 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 52a4500..216c486 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
*/
@@ -38,10 +38,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 eae3943..c8997c7 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 df72ca3..bb8c264 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
*/
@@ -39,7 +39,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
@@ -50,27 +50,79 @@
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];
+ s->picture_ptr->format =
+ s->avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ for (i=s->palette_index; i<=maxtab; i++) {
+ pal[i] = 0;
+ for (j=0; j<wt; j++) {
+ pal[i] |= 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);
@@ -148,6 +200,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;
@@ -207,11 +261,19 @@ 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");
+ return;
+ }
+
/* decode run termination value */
Rb = R(last, x);
RItype = (FFABS(Ra - Rb) <= state->near) ? 1 : 0;
@@ -297,21 +359,23 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near,
else
shift = point_transform + (16 - s->bits);
- av_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);
- av_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++) {
@@ -333,12 +397,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) {
@@ -355,6 +420,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 d60a87b..0cafaba 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 3af6412..2f02332 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"
@@ -263,11 +264,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);
@@ -308,7 +307,11 @@ static int encode_picture_ls(AVCodecContext *avctx, AVPacket *pkt,
ls_store_lse(state, &pb);
- zero = av_mallocz(p->linesize[0]);
+ zero = av_mallocz(FFABS(p->linesize[0]));
+ if (!zero) {
+ av_free(state);
+ return AVERROR(ENOMEM);
+ }
last = zero;
cur = p->data[0];
if (avctx->pix_fmt == AV_PIX_FMT_GRAY8) {
@@ -359,8 +362,8 @@ static int encode_picture_ls(AVCodecContext *avctx, AVPacket *pkt,
}
}
- av_free(zero);
- av_free(state);
+ av_freep(&zero);
+ av_freep(&state);
/* the specification says that after doing 0xff escaping unused bits in
* the last byte must be set to 0, so just append 7 "optional" zero-bits
@@ -428,6 +431,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/jrevdct.c b/libavcodec/jrevdct.c
index 8261269..55a7392 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 bb347e0..47e8edc 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
*/
@@ -140,24 +140,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)
@@ -167,12 +171,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);
@@ -180,9 +182,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;
@@ -200,7 +203,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 1b7313d..bf32aeb 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 89b569a..4185c42 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 d58e775..b81ba75 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 {
- 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 5da8bb2..f879c35 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 e9b0098..2c6d70c 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 edfb18f..37ac2cf 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 e4f066e..dfdfea0 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 6fdb897..3820f58 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 4e7e170..b60c0e9 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 9c60697..ca62b42 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
@@ -174,10 +181,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
unsigned int mthread_inlen, mthread_outlen;
unsigned int len = buf_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;
- }
outptr = frame->data[0]; // Output image pointer
@@ -186,8 +191,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 == width * height * 3 ||
+ 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);
@@ -471,6 +483,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 +509,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 +543,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 878d1e1..201d357 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,7 +41,9 @@
#include <stdio.h>
#include <stdlib.h>
+#include "libavutil/avassert.h"
#include "avcodec.h"
+#include "internal.h"
#include "lcl.h"
#include "libavutil/internal.h"
#include "libavutil/mem.h"
@@ -70,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");
@@ -131,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)
@@ -142,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;
@@ -196,5 +197,6 @@ 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 },
};
diff --git a/libavcodec/libaacplus.c b/libavcodec/libaacplus.c
new file mode 100644
index 0000000..545e240
--- /dev/null
+++ b/libavcodec/libaacplus.c
@@ -0,0 +1,141 @@
+/*
+ * 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);
+ 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 bf14807..c923cd3 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 0000000..4e62fe5
--- /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/libfaac.c b/libavcodec/libfaac.c
index ad51a03..69c186b 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 2c2abae..90cd956 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
@@ -195,8 +195,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;
}
@@ -319,10 +319,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;
@@ -364,10 +362,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 d45fad2..3eadb36 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 da95cc7..8740108 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 8f51321..b06ec64 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 af693bd..9fdd3c8 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 23f1581..d8a444d 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;
@@ -97,6 +97,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 +106,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 */
@@ -208,6 +207,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 +252,8 @@ static int mp3lame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
av_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 +271,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 0704e94..b2ad839 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);
av_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/libopenjpegdec.c b/libavcodec/libopenjpegdec.c
index c7697a5..0cf46e6 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
@@ -48,70 +53,69 @@
#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
+#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 {
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,36 @@ 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;
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(av_pix_fmt_desc_get(picture->format)->comp[x].depth_minus1 + 1 - image->comps[x].prec, 8), 0);
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 +209,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 +217,21 @@ 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;
int index, x, y;
+ int adjust[4];
+ for (x = 0; x < image->numcomps; x++)
+ adjust[x] = FFMAX(FFMIN(av_pix_fmt_desc_get(picture->format)->comp[x].depth_minus1 + 1 - image->comps[x].prec, 8), 0);
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 +285,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 +311,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 +324,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 +408,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 +427,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 2c2109f..66633f4 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,9 +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 {
AVClass *avclass;
opj_image_t *image;
+ opj_cio_t *stream;
opj_cparameters_t enc_params;
opj_cinfo_t *compress;
opj_event_mgr_t event_mgr;
@@ -66,37 +73,41 @@ 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 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:
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 +117,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 +152,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,16 +181,45 @@ 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;
+
+ if (ctx->cinema_mode > 0) {
+ ctx->enc_params.irreversible = 1;
+ ctx->enc_params.tcp_mct = 1;
+ ctx->enc_params.tile_size_on = 0;
+ /* no subsampling */
+ ctx->enc_params.cp_tdx=1;
+ ctx->enc_params.cp_tdy=1;
+ ctx->enc_params.subsampling_dx = 1;
+ ctx->enc_params.subsampling_dy = 1;
+ /* Tile and Image shall be at (0,0) */
+ ctx->enc_params.cp_tx0 = 0;
+ ctx->enc_params.cp_ty0 = 0;
+ ctx->enc_params.image_offset_x0 = 0;
+ ctx->enc_params.image_offset_y0 = 0;
+ /* Codeblock size= 32*32 */
+ ctx->enc_params.cblockw_init = 32;
+ ctx->enc_params.cblockh_init = 32;
+ ctx->enc_params.csty |= 0x01;
+ /* No ROI */
+ ctx->enc_params.roi_compno = -1;
+
+ if (ctx->enc_params.prog_order != CPRL) {
+ av_log(avctx, AV_LOG_ERROR, "prog_order forced to CPRL\n");
+ ctx->enc_params.prog_order = CPRL;
+ }
+ ctx->enc_params.tp_flag = 'C';
+ ctx->enc_params.tp_on = 1;
+ }
ctx->compress = opj_create_compress(ctx->format);
if (!ctx->compress) {
@@ -169,118 +227,247 @@ static av_cold int libopenjpeg_encode_init(AVCodecContext *avctx)
return AVERROR(ENOMEM);
}
- 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;
}
+ opj_setup_encoder(ctx->compress, &ctx->enc_params, ctx->image);
+
+ ctx->stream = opj_cio_open((opj_common_ptr) ctx->compress, NULL, 0);
+ if (!ctx->stream) {
+ av_log(avctx, AV_LOG_ERROR, "Error creating the cio stream\n");
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ avctx->coded_frame = av_frame_alloc();
+ if (!avctx->coded_frame) {
+ av_log(avctx, AV_LOG_ERROR, "Error allocating coded frame\n");
+ goto fail;
+ }
+ 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.error_handler = error_callback;
ctx->event_mgr.warning_handler = warning_callback;
opj_set_event_mgr((opj_common_ptr) ctx->compress, &ctx->event_mgr, avctx);
return 0;
fail:
- av_freep(&ctx->compress);
+ opj_cio_close(ctx->stream);
+ ctx->stream = NULL;
+ opj_destroy_compress(ctx->compress);
+ ctx->compress = NULL;
+ opj_image_destroy(ctx->image);
+ ctx->image = NULL;
av_freep(&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_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] >> 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 int libopenjpeg_copy_packed16(AVCodecContext *avctx, const AVFrame *frame, opj_image_t *image)
+{
+ int compno;
+ 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_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];
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_unpacked8(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;
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,
@@ -289,25 +476,45 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
LibOpenJPEGContext *ctx = avctx->priv_data;
opj_cinfo_t *compress = ctx->compress;
opj_image_t *image = ctx->image;
- opj_cio_t *stream;
+ opj_cio_t *stream = ctx->stream;
+ 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);
+ 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 +524,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 +563,26 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
break;
}
- 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);
+ if (!cpyresult) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Could not copy the frame data to the internal image buffer\n");
+ return -1;
}
+ cio_seek(stream, 0);
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);
return 0;
}
@@ -369,8 +590,12 @@ static av_cold int libopenjpeg_encode_close(AVCodecContext *avctx)
{
LibOpenJPEGContext *ctx = avctx->priv_data;
+ opj_cio_close(ctx->stream);
+ ctx->stream = NULL;
opj_destroy_compress(ctx->compress);
+ ctx->compress = NULL;
opj_image_destroy(ctx->image);
+ ctx->image = NULL;
av_freep(&avctx->coded_frame);
return 0;
}
@@ -396,15 +621,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 +645,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_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 b511415..16395c7 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 b08257d..a8223d1 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 398450f..8436302 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 da6194a..6bb4862 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. */
@@ -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 fc9188c..9f0b25c 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,7 +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));
- avpicture_alloc(p_pic, avctx->pix_fmt, y_width, y_height);
+ if (!p_pic || avpicture_alloc(p_pic, avctx->pix_fmt, y_width, y_height) < 0) {
+ av_free(p_pic);
+ return NULL;
+ }
p_frame = schro_frame_new();
p_frame->format = schro_frame_fmt;
diff --git a/libavcodec/libschroedinger.h b/libavcodec/libschroedinger.h
index 5481f92..12fe57c 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 0c5a3fb..dca3379 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",
@@ -310,10 +306,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 3dc1481..294fb06 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"
@@ -378,10 +379,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 0000000..48333bb
--- /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;
+ long 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 d00696e..5e149a5 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
*/
@@ -43,14 +43,24 @@ 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')) {
+ if (!avctx->extradata || avctx->extradata && avctx->extradata_size < 47) {
+ av_log(avctx, AV_LOG_ERROR, "Missing or invalid extradata.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (avctx->extradata[37] != 10) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported quality mode.\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ 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 +83,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 +124,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
@@ -149,6 +159,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 98f89b2..21238aa 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 {
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 0000000..44d7ea1
--- /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 75b0a16..4c90822 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,7 +96,7 @@ 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,
@@ -113,7 +113,7 @@ static int get_stats(AVCodecContext *avctx, int eos)
return 0;
#else
av_log(avctx, AV_LOG_ERROR, "libtheora too old to support 2pass\n");
- return -1;
+ return AVERROR(ENOSUP);
#endif
}
@@ -127,7 +127,7 @@ 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);
@@ -139,7 +139,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 +148,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 +160,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 +197,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 +218,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 +228,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 +253,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);
@@ -276,8 +276,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;
}
@@ -290,8 +290,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);
@@ -309,12 +309,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);
@@ -327,14 +327,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
diff --git a/libavcodec/libtwolame.c b/libavcodec/libtwolame.c
index 400985a..dc18857 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) {
@@ -148,8 +152,8 @@ static int twolame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
if (ret < 0) // twolame error
return AVERROR_UNKNOWN;
- avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples);
if (frame) {
+ avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples);
if (frame->pts != AV_NOPTS_VALUE)
avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding);
} else {
@@ -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 0000000..5fb1174
--- /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 0000000..e4b87a8
--- /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 0000000..3298e64
--- /dev/null
+++ b/libavcodec/libutvideoenc.cpp
@@ -0,0 +1,246 @@
+/*
+ * 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;
+
+ 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.
+ */
+ utv->buf_size = avpicture_get_size(avctx->pix_fmt,
+ avctx->width, avctx->height);
+ 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");
+ 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_freep(&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 6dd7117..7b38d51 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
*/
@@ -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 da3941b..fe19e71 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/libvorbisdec.c b/libavcodec/libvorbisdec.c
new file mode 100644
index 0000000..b703b65
--- /dev/null
+++ b/libavcodec/libvorbisdec.c
@@ -0,0 +1,199 @@
+/*
+ * 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];
+ unsigned char *headers[3], *extradata = avccontext->extradata;
+
+ vorbis_info_init(&context->vi) ;
+ vorbis_comment_init(&context->vc) ;
+
+ if(! avccontext->extradata_size || ! p) {
+ av_log(avccontext, AV_LOG_ERROR, "vorbis extradata absent\n");
+ return -1;
+ }
+
+ 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");
+ return -1;
+ }
+ 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);
+ return -1;
+ }
+
+ 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);
+ return -1;
+ }
+ }
+
+ 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 ;
+}
+
+
+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/libvorbis.c b/libavcodec/libvorbisenc.c
index f7ea253..4d16b75 100644
--- a/libavcodec/libvorbis.c
+++ b/libavcodec/libvorbisenc.c
@@ -1,42 +1,34 @@
/*
- * copyright (c) 2002 Mark Hills <mark@pogo.org.uk>
+ * Copyright (c) 2002 Mark Hills <mark@pogo.org.uk>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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
- * Vorbis encoding support via libvorbisenc.
- * @author Mark Hills <mark@pogo.org.uk>
- */
-
#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 "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
@@ -47,7 +39,7 @@
#define BUFFER_SIZE (1024 * 64)
-typedef struct LibvorbisContext {
+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 */
@@ -56,14 +48,13 @@ typedef struct LibvorbisContext {
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;
+} LibvorbisEncContext;
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 },
+ { "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 }
};
@@ -72,8 +63,12 @@ static const AVCodecDefault defaults[] = {
{ NULL },
};
-static const AVClass class = { "libvorbis", av_default_item_name, options, LIBAVUTIL_VERSION_INT };
-
+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)
{
@@ -87,7 +82,7 @@ static int vorbis_error_to_averror(int ov_err)
static av_cold int libvorbis_setup(vorbis_info *vi, AVCodecContext *avctx)
{
- LibvorbisContext *s = avctx->priv_data;
+ LibvorbisEncContext *s = avctx->priv_data;
double cfreq;
int ret;
@@ -117,14 +112,14 @@ static av_cold int libvorbis_setup(vorbis_info *vi, AVCodecContext *avctx)
/* 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;
+ 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;
+ goto error; /* should not happen */
}
/* impulse block bias */
@@ -133,6 +128,35 @@ static av_cold int libvorbis_setup(vorbis_info *vi, AVCodecContext *avctx)
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;
@@ -149,7 +173,7 @@ static int xiph_len(int l)
static av_cold int libvorbis_encode_close(AVCodecContext *avctx)
{
- LibvorbisContext *s = avctx->priv_data;
+ LibvorbisEncContext *s = avctx->priv_data;
/* notify vorbisenc this is EOF */
if (s->dsp_initialized)
@@ -159,7 +183,7 @@ static av_cold int libvorbis_encode_close(AVCodecContext *avctx)
vorbis_dsp_clear(&s->vd);
vorbis_info_clear(&s->vi);
- av_fifo_free(s->pkt_fifo);
+ av_fifo_freep(&s->pkt_fifo);
ff_af_queue_close(&s->afq);
av_freep(&avctx->extradata);
@@ -170,7 +194,7 @@ static av_cold int libvorbis_encode_close(AVCodecContext *avctx)
static av_cold int libvorbis_encode_init(AVCodecContext *avctx)
{
- LibvorbisContext *s = avctx->priv_data;
+ LibvorbisEncContext *s = avctx->priv_data;
ogg_packet header, header_comm, header_code;
uint8_t *p;
unsigned int offset;
@@ -194,7 +218,8 @@ static av_cold int libvorbis_encode_init(AVCodecContext *avctx)
}
vorbis_comment_init(&s->vc);
- vorbis_comment_add_tag(&s->vc, "encoder", LIBAVCODEC_IDENT);
+ 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))) {
@@ -221,7 +246,7 @@ static av_cold int libvorbis_encode_init(AVCodecContext *avctx)
offset += header_comm.bytes;
memcpy(&p[offset], header_code.packet, header_code.bytes);
offset += header_code.bytes;
- assert(offset == avctx->extradata_size);
+ av_assert0(offset == avctx->extradata_size);
s->vp = av_vorbis_parse_init(avctx->extradata, avctx->extradata_size);
if (!s->vp) {
@@ -249,7 +274,7 @@ error:
static int libvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
const AVFrame *frame, int *got_packet_ptr)
{
- LibvorbisContext *s = avctx->priv_data;
+ LibvorbisEncContext *s = avctx->priv_data;
ogg_packet op;
int ret, duration;
@@ -273,7 +298,7 @@ static int libvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
if ((ret = ff_af_queue_add(&s->afq, frame)) < 0)
return ret;
} else {
- if (!s->eof)
+ 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);
@@ -291,7 +316,7 @@ static int libvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
/* 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");
+ 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);
@@ -313,10 +338,8 @@ static int libvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
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");
+ 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);
@@ -325,9 +348,12 @@ static int libvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
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) {
+ if (!avctx->initial_padding && s->afq.frames) {
avctx->initial_padding = duration;
- s->afq.remaining_delay += 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);
@@ -339,16 +365,16 @@ static int libvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
AVCodec ff_libvorbis_encoder = {
.name = "libvorbis",
- .long_name = NULL_IF_CONFIG_SMALL("libvorbis Vorbis"),
+ .long_name = NULL_IF_CONFIG_SMALL("libvorbis"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_VORBIS,
- .priv_data_size = sizeof(LibvorbisContext),
+ .priv_data_size = sizeof(LibvorbisEncContext),
.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,
+ .priv_class = &vorbis_class,
.defaults = defaults,
};
diff --git a/libavcodec/libvpx.c b/libavcodec/libvpx.c
index 20f4484..5d29893 100644
--- a/libavcodec/libvpx.c
+++ b/libavcodec/libvpx.c
@@ -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
*/
@@ -22,14 +22,9 @@
#include "libvpx.h"
-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;
- }
- return 0;
+ if ( vpx_codec_version_major() < 1
+ || (vpx_codec_version_major() == 1 && vpx_codec_version_minor() < 3))
+ codec->capabilities |= CODEC_CAP_EXPERIMENTAL;
}
diff --git a/libavcodec/libvpx.h b/libavcodec/libvpx.h
index cb1ed09..36a275c 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 6052207..7faef3a 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,62 @@ 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;
+ 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;
+ }
+ 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 +134,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 +154,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 +190,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 +202,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 86e4be9..30940a1 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)
@@ -122,7 +161,7 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx,
width, "g_lag_in_frames:", cfg->g_lag_in_frames);
av_log(avctx, level, "rate control settings\n"
" %*s%u\n %*s%u\n %*s%u\n %*s%u\n"
- " %*s%d\n %*s%p(%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 +208,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,6 +250,8 @@ 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_freep(&avctx->stats_out);
@@ -221,16 +264,28 @@ static av_cold int vpx_init(AVCodecContext *avctx,
{
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;
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(!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 +293,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 +302,59 @@ 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
- enccfg.rc_target_bitrate = av_rescale_rnd(avctx->bit_rate, 1, 1000,
- AV_ROUND_NEAR_INF);
-
- 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)
+ 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->qmin > 0)
+ if (avctx->bit_rate) {
+ enccfg.rc_target_bitrate = av_rescale_rnd(avctx->bit_rate, 1, 1000,
+ 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 (avctx->qmin >= 0)
enccfg.rc_min_quantizer = avctx->qmin;
- if (avctx->qmax > 0)
+ 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);
+ }
+ }
+
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 +366,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,7 +388,7 @@ static av_cold int vpx_init(AVCodecContext *avctx,
ctx->twopass_stats.buf = av_malloc(ctx->twopass_stats.sz);
if (!ctx->twopass_stats.buf) {
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);
return AVERROR(ENOMEM);
}
@@ -324,20 +409,30 @@ static av_cold int vpx_init(AVCodecContext *avctx,
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)
@@ -347,7 +442,8 @@ static av_cold int vpx_init(AVCodecContext *avctx,
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_TOKEN_PARTITIONS, av_log2(avctx->slices));
#if FF_API_MPV_OPT
FF_DISABLE_DEPRECATION_WARNINGS
if (avctx->mb_threshold) {
@@ -358,12 +454,36 @@ 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,
(unsigned char*)1);
+ 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) {
av_log(avctx, AV_LOG_ERROR, "Error allocating coded frame\n");
@@ -374,13 +494,39 @@ 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 +539,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 +552,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 +596,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 +613,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 +623,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,16 +637,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_free(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;
@@ -491,7 +677,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;
@@ -506,6 +699,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;
@@ -518,6 +712,20 @@ 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);
+ memset(u_plane, 0x80, frame->linesize[1] * frame->height);
+ rawimg_alpha->planes[VPX_PLANE_U] = u_plane;
+ v_plane = av_malloc(frame->linesize[2] * frame->height);
+ 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;
@@ -529,6 +737,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) {
@@ -544,40 +762,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" },
@@ -594,9 +859,9 @@ static av_cold int vp8_init(AVCodecContext *avctx)
}
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,
};
@@ -610,7 +875,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,
};
@@ -619,16 +884,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);
}
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,
};
@@ -645,5 +907,6 @@ AVCodec ff_libvpx_vp9_encoder = {
.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 34ec013..77d98a2 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 b981f48..95d56ac 100644
--- a/libavcodec/libwebpenc.c
+++ b/libavcodec/libwebpenc.c
@@ -2,20 +2,20 @@
* 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
*/
@@ -41,6 +41,9 @@ typedef struct LibWebPContext {
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;
} LibWebPContext;
static int libwebp_error_to_averror(int err)
@@ -62,10 +65,9 @@ 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->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",
@@ -144,8 +146,8 @@ static int libwebp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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) {
+ 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;
@@ -158,22 +160,80 @@ static int libwebp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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 (avctx->pix_fmt == AV_PIX_FMT_YUVA420P) {
+ 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;
}
@@ -231,7 +291,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,6 +303,15 @@ end:
return ret;
}
+static int libwebp_encode_close(AVCodecContext *avctx)
+{
+ LibWebPContext *s = avctx->priv_data;
+
+ av_frame_free(&s->ref);
+
+ return 0;
+}
+
#define OFFSET(x) offsetof(LibWebPContext, x)
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
@@ -251,9 +324,13 @@ static const AVOption options[] = {
{ "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 AVClass class = {
.class_name = "libwebp",
.item_name = av_default_item_name,
@@ -275,6 +352,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/libx264.c b/libavcodec/libx264.c
index 6388b6c..5952a0d 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) {
@@ -282,6 +315,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) {
@@ -290,10 +337,19 @@ static int convert_pix_fmt(enum AVPixelFormat pix_fmt)
case AV_PIX_FMT_YUV420P9:
case AV_PIX_FMT_YUV420P10: return X264_CSP_I420;
case AV_PIX_FMT_YUV422P:
+ case AV_PIX_FMT_YUVJ422P:
case AV_PIX_FMT_YUV422P10: return X264_CSP_I422;
case AV_PIX_FMT_YUV444P:
+ 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;
@@ -310,6 +366,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);
@@ -317,7 +377,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);
}
@@ -329,6 +398,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;
@@ -357,10 +428,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;
@@ -391,6 +466,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)
@@ -435,6 +532,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)
@@ -454,25 +558,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;
@@ -487,11 +634,33 @@ static av_cold int X264_init(AVCodecContext *avctx)
x4->params.i_slice_count = avctx->slices;
x4->params.vui.b_fullrange = 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;
+ 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;
@@ -554,7 +723,9 @@ static const enum AVPixelFormat pix_fmts_8bit[] = {
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_YUVJ420P,
AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUVJ422P,
AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUVJ444P,
AV_PIX_FMT_NV12,
AV_PIX_FMT_NV16,
AV_PIX_FMT_NONE
@@ -571,6 +742,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)
{
@@ -589,6 +767,10 @@ 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 },
@@ -634,27 +816,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" },
@@ -683,7 +876,22 @@ 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,
};
+
+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 a3bf2dc..923c750 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
*/
@@ -229,7 +229,7 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
ret = x265_encoder_encode(ctx->encoder, &nal, &nnal,
pic ? &x265pic : NULL, &x265pic_out);
if (ret < 0)
- return AVERROR_UNKNOWN;
+ return AVERROR_EXTERNAL;
if (!nnal)
return 0;
diff --git a/libavcodec/libxavs.c b/libavcodec/libxavs.c
index 7a74e36..92dcece 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;
}
@@ -355,7 +353,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();
@@ -394,10 +392,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 +408,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 +431,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 35a76eb..aee9dac 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,17 +25,26 @@
* @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"
#include "avcodec.h"
+#include "internal.h"
#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.
*/
@@ -48,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 */
@@ -60,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 */
@@ -77,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
*
@@ -107,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),
@@ -353,26 +365,28 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx)
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;
@@ -415,7 +429,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;
@@ -474,7 +488,7 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx)
if (!x->twopassbuffer || !x->old_twopassbuffer) {
av_log(avctx, AV_LOG_ERROR,
"Xvid: Cannot allocate 2-pass log buffers\n");
- return -1;
+ goto fail;
}
x->twopassbuffer[0] =
x->old_twopassbuffer[0] = 0;
@@ -486,26 +500,25 @@ 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 == -1) {
av_log(avctx, AV_LOG_ERROR, "Xvid: Cannot write 2-pass pipe\n");
- return -1;
+ goto fail;
}
+ x->twopassfd = fd;
if (!avctx->stats_in) {
av_log(avctx, AV_LOG_ERROR,
"Xvid: No 2-pass information loaded for second pass\n");
- return -1;
+ goto fail;
}
if (strlen(avctx->stats_in) >
write(fd, avctx->stats_in, strlen(avctx->stats_in))) {
- close(fd);
av_log(avctx, AV_LOG_ERROR, "Xvid: Cannot write to 2-pass pipe\n");
- return -1;
+ goto fail;
}
- close(fd);
rc2pass2.filename = x->twopassfile;
plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass2;
plugins[xvid_enc_create.num_plugins].param = &rc2pass2;
@@ -523,12 +536,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;
@@ -549,6 +556,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;
@@ -636,11 +648,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;
+ goto fail;
}
x->encoder_handle = xvid_enc_create.handle;
@@ -649,6 +663,9 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx)
return AVERROR(ENOMEM);
return 0;
+fail:
+ xvid_encode_close(avctx);
+ return -1;
}
static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
@@ -664,11 +681,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*mb_height*MAX_MB_BYTES + FF_MIN_BUFFER_SIZE)) < 0)
return ret;
- }
/* Start setting up the frame */
xvid_enc_frame.version = XVID_VERSION;
@@ -682,7 +696,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 */
@@ -703,11 +717,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;
@@ -770,7 +786,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 -1;
+ return AVERROR_EXTERNAL;
}
}
@@ -778,16 +794,24 @@ static av_cold int xvid_encode_close(AVCodecContext *avctx)
{
struct xvid_context *x = avctx->priv_data;
- xvid_encore(x->encoder_handle, XVID_ENC_DESTROY, NULL, NULL);
+ if(x->encoder_handle)
+ xvid_encore(x->encoder_handle, XVID_ENC_DESTROY, NULL, NULL);
+ x->encoder_handle = NULL;
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 15f908f..bffe07d 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 68140a6..f92bef1 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 -1;
- }
-#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 -1;
- }
- 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 == -1) {
av_log(NULL, AV_LOG_ERROR, "Can't create temporary pass2 file.\n");
return -1;
@@ -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", strerror(errno));
+ 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 0000000..15c1a5d
--- /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 fbb024b..19ae151 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
*/
@@ -77,7 +77,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;
}
@@ -86,9 +86,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;
@@ -213,25 +219,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);
@@ -240,6 +249,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);
@@ -263,7 +273,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 ||
@@ -289,21 +298,7 @@ static av_cold int ljpeg_encode_init(AVCodecContext *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,
@@ -326,12 +321,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 6be081d..bf52c49 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
*/
@@ -132,7 +132,10 @@ static int loco_decode_plane(LOCOContext *l, uint8_t *data, int width, int heigh
int val;
int i, j;
- init_get_bits(&rc.gb, buf, buf_size*8);
+ if(buf_size<=0)
+ return -1;
+
+ init_get_bits8(&rc.gb, buf, buf_size);
rc.save = 0;
rc.run = 0;
rc.run2 = 0;
@@ -175,88 +178,70 @@ 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);
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 +288,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 0000000..32f4c9e
--- /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/apedsp.h b/libavcodec/lossless_audiodsp.h
index 64e2749..4c27502 100644
--- a/libavcodec/apedsp.h
+++ b/libavcodec/lossless_audiodsp.h
@@ -3,29 +3,29 @@
* 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
*/
-#ifndef AVCODEC_APEDSP_H
-#define AVCODEC_APEDSP_H
+#ifndef AVCODEC_LLAUDDSP_H
+#define AVCODEC_LLAUDDSP_H
#include <stdint.h>
-typedef struct APEDSPContext {
+typedef struct LLAudDSPContext {
/**
* Calculate scalar product of v1 and v2,
* and v1[i] += v3[i] * mul
@@ -35,10 +35,11 @@ typedef struct APEDSPContext {
const int16_t *v2,
const int16_t *v3,
int len, int mul);
-} APEDSPContext;
+} LLAudDSPContext;
-void ff_apedsp_init_arm(APEDSPContext *c);
-void ff_apedsp_init_ppc(APEDSPContext *c);
-void ff_apedsp_init_x86(APEDSPContext *c);
+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_APEDSP_H */
+#endif /* AVCODEC_LLAUDDSP_H */
diff --git a/libavcodec/lossless_videodsp.c b/libavcodec/lossless_videodsp.c
new file mode 100644
index 0000000..3491621
--- /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 0000000..040902e
--- /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 1482e57..f54f6f8 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);
@@ -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 6b3f80e..b36b19e 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,7 @@
#define AVCODEC_LPC_H
#include <stdint.h>
+#include "libavutil/avassert.h"
#define ORDER_METHOD_EST 0
#define ORDER_METHOD_2LEVEL 1
@@ -66,7 +67,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
@@ -155,6 +156,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 8a05aed..17f59ea 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 4b95567..46a2d47 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 fae5687..6832c12 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 d925d35..4653c1c 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 7c37bf2..03080ee 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 25c6b70..6eaa296 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.h b/libavcodec/mathops.h
index 7af13e1..87fca0c 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
diff --git a/libavcodec/mathtables.c b/libavcodec/mathtables.c
index 47695bc..a07ac50 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 9e06861..a32cb00 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 0000000..5a34dfe
--- /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 a0a62b3..cff2d21 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 bad890e..7fa8bcc 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 6b70e37..051adae 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;
@@ -124,7 +126,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]);
@@ -166,23 +168,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);
@@ -216,6 +214,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 9fcc937..1355a23 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"
@@ -407,6 +412,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");
@@ -434,7 +447,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
@@ -486,7 +499,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
@@ -538,7 +551,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);
@@ -605,7 +618,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);
@@ -623,7 +636,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);
@@ -652,7 +665,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);
@@ -696,7 +709,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)];
@@ -727,7 +740,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);
@@ -768,7 +781,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)];
@@ -801,20 +814,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,
- int 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, \
+ int 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) \
@@ -839,20 +856,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,
- int 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, \
+ int 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, \
@@ -890,8 +910,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 */
@@ -925,14 +968,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 05ae30b..0e3b922 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 },
@@ -48,6 +62,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];
@@ -63,11 +79,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 dd9ffe0..2dab135 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 8aa53e5..ed23cdf 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[] = {
diff --git a/libavcodec/metasound_data.h b/libavcodec/metasound_data.h
index 4925516..5c33411 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 0000000..b20aac5
--- /dev/null
+++ b/libavcodec/microdvddec.c
@@ -0,0 +1,365 @@
+/*
+ * 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"
+
+static char *microdvd_load_tags(struct microdvd_tag *tags, char *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':
+ if (*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 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 88ee5d3..24724fa 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 0000000..6537b43
--- /dev/null
+++ b/libavcodec/mips/Makefile
@@ -0,0 +1,20 @@
+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 += 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
diff --git a/libavcodec/mips/aaccoder_mips.c b/libavcodec/mips/aaccoder_mips.c
new file mode 100644
index 0000000..8595913
--- /dev/null
+++ b/libavcodec/mips/aaccoder_mips.c
@@ -0,0 +1,2498 @@
+/*
+ * 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];
+
+ 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)
+ : [in_int]"r"(in_int)
+ : "t0", "t1", "t2", "t3",
+ "t4", "t5", "t6", "t7",
+ "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;
+
+ 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)
+ : [in_int]"r"(in_int)
+ : "t0", "t1", "t2", "t3", "t4",
+ "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;
+
+ 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)
+ : [in_int]"r"(in_int)
+ : "t0", "t1", "t2", "t3",
+ "t4", "t5", "t6", "t7",
+ "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;
+
+ 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)
+ : [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;
+
+ 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)
+ : [in_int]"r"(in_int)
+ : "t0", "t1", "t2", "t3", "t4",
+ "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;
+
+ 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)
+ : [in_int]"r"(in_int)
+ : "t0", "t1", "t2", "t3", "t4",
+ "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;
+
+ 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)
+ : [in_int]"r"(in_int)
+ : "t0", "t1", "t2", "t3", "t4",
+ "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];
+
+ 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)
+ : [in_int]"r"(in_int)
+ : "t0", "t1", "t2", "t3",
+ "t4", "t5", "t6", "t7",
+ "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;
+
+ 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", "t1", "t2", "t3", "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];
+
+ 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)
+ : [in_int]"r"(in_int)
+ : "t0", "t1", "t2", "t3",
+ "t4", "t5", "t6", "t7",
+ "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;
+
+ 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", "t1", "t2", "t3", "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;
+
+ 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", "t1", "t2", "t3", "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;
+
+ 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", "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;
+
+ 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)
+ : [in_int]"r"(in_int)
+ : "t0", "t1", "t2", "t3",
+ "t4", "t5", "t6", "t7",
+ "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;
+
+ 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", "t1", "t2", "t3", "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;
+
+ 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)
+ : [in_int]"r"(in_int)
+ : "t0", "t1", "t2", "t3",
+ "t4", "t5", "t6", "t7",
+ "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;
+
+ 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)
+ : [in_int]"r"(in_int)
+ : "t0", "t1", "t2", "t3", "t4",
+ "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;
+
+ 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)
+ : [in_int]"r"(in_int)
+ : "t0", "t1", "t2", "t3", "t4",
+ "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;
+
+ 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"
+
+ ".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", "t5"
+ );
+
+ 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 0000000..e403366
--- /dev/null
+++ b/libavcodec/mips/aacdec_mips.c
@@ -0,0 +1,831 @@
+/*
+ * 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"
+
+#if HAVE_INLINE_ASM
+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 *buf1 = saved;
+ float *buf2 = out;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ int loop_end;
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 1792 \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"
+ "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"
+ " 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),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf1),
+ [dst]"+r"(buf2)
+ :
+ : "memory"
+ );
+ }
+
+ 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 *buf1 = buf + 64;
+ float *buf2 = out + 576;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ int loop_end;
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 1792 \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"
+ "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"
+ " 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),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf1),
+ [dst]"+r"(buf2)
+ :
+ : "memory"
+ );
+ }
+ }
+ }
+
+ // 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 *buf1 = buf + 7*128 + 64;
+ float *buf2 = saved + 448;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ int loop_end;
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 256 \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"
+ "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"
+ " 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),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf1),
+ [dst]"+r"(buf2)
+ :
+ : "memory"
+ );
+ }
+ } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) {
+ float *buf1 = buf + 512;
+ float *buf2 = saved;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ int loop_end;
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 1792 \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"
+ "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"
+ " 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),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf1),
+ [dst]"+r"(buf2)
+ :
+ : "memory"
+ );
+ {
+ float *buf1 = buf + 7*128 + 64;
+ float *buf2 = saved + 448;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ int loop_end;
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 256 \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"
+ "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"
+ " 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),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf1),
+ [dst]"+r"(buf2)
+ :
+ : "memory"
+ );
+ }
+ } else { // LONG_STOP or ONLY_LONG
+ float *buf1 = buf + 512;
+ float *buf2 = saved;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ int loop_end;
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 2048 \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"
+ "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"
+ " 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),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf1),
+ [dst]"+r"(buf2)
+ :
+ : "memory"
+ );
+ }
+}
+
+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"
+ "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"
+ "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 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;
+ int i;
+ int loop_end, loop_end1, loop_end2;
+ float temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp10, temp11;
+
+ if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
+ float *buf = saved;
+ float *buf0 = saved_ltp;
+ float *p_saved_ltp = saved_ltp + 576;
+ float *ptr1 = &saved_ltp[512];
+ float *ptr2 = &ac->buf_mdct[1023];
+ float *ptr3 = (float*)&swindow[63];
+ loop_end1 = (int)(p_saved_ltp + 448);
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 2048 \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"
+ "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"
+ " 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),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf),
+ [dst]"+r"(buf0)
+ :
+ : "memory"
+ );
+
+ /* 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"
+ "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);
+ for (i = 0; i < 16; i++){
+ /* 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"
+ "addiu %[ptr1], %[ptr1], 16 \n\t"
+ "addiu %[ptr2], %[ptr2], -16 \n\t"
+ "addiu %[ptr3], %[ptr3], -16 \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),
+ [ptr1]"+r"(ptr1), [ptr2]"+r"(ptr2), [ptr3]"+r"(ptr3)
+ :
+ : "memory"
+ );
+ }
+ } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) {
+ float *buff0 = saved;
+ float *buff1 = saved_ltp;
+ float *ptr1 = &saved_ltp[512];
+ float *ptr2 = &ac->buf_mdct[1023];
+ float *ptr3 = (float*)&swindow[63];
+ loop_end = (int)(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"
+ "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"
+ " 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);
+ for (i = 0; i < 16; i++){
+ /* loop unrolled 8 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"
+ "addiu %[ptr1], %[ptr1], 16 \n\t"
+ "addiu %[ptr2], %[ptr2], -16 \n\t"
+ "addiu %[ptr3], %[ptr3], -16 \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),
+ [ptr1]"+r"(ptr1), [ptr2]"+r"(ptr2), [ptr3]"+r"(ptr3)
+ :
+ : "memory"
+ );
+ }
+ } else { // LONG_STOP or ONLY_LONG
+ float *ptr1, *ptr2, *ptr3;
+ ac->fdsp.vector_fmul_reverse(saved_ltp, ac->buf_mdct + 512, &lwindow[512], 512);
+
+ ptr1 = &saved_ltp[512];
+ ptr2 = &ac->buf_mdct[1023];
+ ptr3 = (float*)&lwindow[511];
+
+ for (i = 0; i < 512; i+=4){
+ /* 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"
+ "addiu %[ptr1], %[ptr1], 16 \n\t"
+ "addiu %[ptr2], %[ptr2], -16 \n\t"
+ "addiu %[ptr3], %[ptr3], -16 \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),
+ [ptr1]"+r"(ptr1), [ptr2]"+r"(ptr2),
+ [ptr3]"+r"(ptr3)
+ :
+ : "memory"
+ );
+ }
+ }
+
+ {
+ float *buf1 = sce->ltp_state+1024;
+ float *buf2 = sce->ltp_state;
+ float *buf3 = sce->ret;
+ float *buf4 = sce->ltp_state+1024;
+ float *buf5 = saved_ltp;
+ float *buf6 = sce->ltp_state+2048;
+
+ /* loops unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 4096 \n\t"
+ "addiu %[loop_end1], %[src1], 4096 \n\t"
+ "addiu %[loop_end2], %[src2], 4096 \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"
+ "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"
+ " addiu %[dst], %[dst], 32 \n\t"
+ "2: \n\t"
+ "lw %[temp0], 0(%[src1]) \n\t"
+ "lw %[temp1], 4(%[src1]) \n\t"
+ "lw %[temp2], 8(%[src1]) \n\t"
+ "lw %[temp3], 12(%[src1]) \n\t"
+ "lw %[temp4], 16(%[src1]) \n\t"
+ "lw %[temp5], 20(%[src1]) \n\t"
+ "lw %[temp6], 24(%[src1]) \n\t"
+ "lw %[temp7], 28(%[src1]) \n\t"
+ "addiu %[src1], %[src1], 32 \n\t"
+ "sw %[temp0], 0(%[dst1]) \n\t"
+ "sw %[temp1], 4(%[dst1]) \n\t"
+ "sw %[temp2], 8(%[dst1]) \n\t"
+ "sw %[temp3], 12(%[dst1]) \n\t"
+ "sw %[temp4], 16(%[dst1]) \n\t"
+ "sw %[temp5], 20(%[dst1]) \n\t"
+ "sw %[temp6], 24(%[dst1]) \n\t"
+ "sw %[temp7], 28(%[dst1]) \n\t"
+ "bne %[src1], %[loop_end1], 2b \n\t"
+ " addiu %[dst1], %[dst1], 32 \n\t"
+ "3: \n\t"
+ "lw %[temp0], 0(%[src2]) \n\t"
+ "lw %[temp1], 4(%[src2]) \n\t"
+ "lw %[temp2], 8(%[src2]) \n\t"
+ "lw %[temp3], 12(%[src2]) \n\t"
+ "lw %[temp4], 16(%[src2]) \n\t"
+ "lw %[temp5], 20(%[src2]) \n\t"
+ "lw %[temp6], 24(%[src2]) \n\t"
+ "lw %[temp7], 28(%[src2]) \n\t"
+ "addiu %[src2], %[src2], 32 \n\t"
+ "sw %[temp0], 0(%[dst2]) \n\t"
+ "sw %[temp1], 4(%[dst2]) \n\t"
+ "sw %[temp2], 8(%[dst2]) \n\t"
+ "sw %[temp3], 12(%[dst2]) \n\t"
+ "sw %[temp4], 16(%[dst2]) \n\t"
+ "sw %[temp5], 20(%[dst2]) \n\t"
+ "sw %[temp6], 24(%[dst2]) \n\t"
+ "sw %[temp7], 28(%[dst2]) \n\t"
+ "bne %[src2], %[loop_end2], 3b \n\t"
+ " addiu %[dst2], %[dst2], 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),
+ [loop_end]"=&r"(loop_end), [loop_end1]"=&r"(loop_end1),
+ [loop_end2]"=&r"(loop_end2), [src]"+r"(buf1),
+ [dst]"+r"(buf2), [src1]"+r"(buf3), [dst1]"+r"(buf4),
+ [src2]"+r"(buf5), [dst2]"+r"(buf6)
+ :
+ : "memory"
+ );
+ }
+}
+#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 0000000..9ba3079
--- /dev/null
+++ b/libavcodec/mips/aacdec_mips.h
@@ -0,0 +1,249 @@
+/*
+ * 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"
+
+#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], 15 \n\t"
+ "ext %[temp4], %[idx], 4, 4 \n\t"
+ "sll %[temp3], %[temp3], 2 \n\t"
+ "sll %[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"
+ "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], 3 \n\t"
+ "ext %[temp1], %[idx], 2, 2 \n\t"
+ "ext %[temp2], %[idx], 4, 2 \n\t"
+ "ext %[temp3], %[idx], 6, 2 \n\t"
+ "sll %[temp0], %[temp0], 2 \n\t"
+ "sll %[temp1], %[temp1], 2 \n\t"
+ "sll %[temp2], %[temp2], 2 \n\t"
+ "sll %[temp3], %[temp3], 2 \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"
+ "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], 15 \n\t"
+ "ext %[temp1], %[idx], 4, 4 \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"
+ "sll %[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"
+ "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"
+ "and %[temp1], %[idx], 3 \n\t"
+ "ext %[temp2], %[idx], 2, 2 \n\t"
+ "ext %[temp3], %[idx], 4, 2 \n\t"
+ "ext %[temp4], %[idx], 6, 2 \n\t"
+ "sll %[temp1], %[temp1], 2 \n\t"
+ "sll %[temp2], %[temp2], 2 \n\t"
+ "sll %[temp3], %[temp3], 2 \n\t"
+ "sll %[temp4], %[temp4], 2 \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"
+ "ext %[temp2], %[idx], 12, 1 \n\t"
+ "ext %[temp3], %[idx], 13, 1 \n\t"
+ "ext %[temp4], %[idx], 14, 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"
+ "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 0000000..4730a7f
--- /dev/null
+++ b/libavcodec/mips/aacpsdsp_mips.c
@@ -0,0 +1,459 @@
+/*
+ * 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"
+
+#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"
+ "addiu %[out1], %[out1], 32 \n\t"
+ "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"
+ "addiu %[out1], %[out1], 1024 \n\t"
+ "addiu %[out2], %[out2], 1024 \n\t"
+ "addiu %[in1], %[in1], 32 \n\t"
+ "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"
+ "addiu %[out1], %[out1], -7164 \n\t"
+ "addiu %[out2], %[out2], -7164 \n\t"
+ "addiu %[in1], %[in1], 32 \n\t"
+ "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"
+ "addiu %[dst0], %[dst0], 16 \n\t"
+ "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"
+ "addiu %[p_d], %[p_d], 8 \n\t"
+ "mul.s %[temp0], %[temp0], %[temp2] \n\t"
+ "mul.s %[temp1], %[temp1], %[temp2] \n\t"
+ "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"
+ " 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], 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];
+ float *p_t_gain = (float*)transient_gain;
+ 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;
+
+ len = (int)((int*)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"
+ "addiu %[p_ap_delay], %[p_ap_delay], 8 \n\t"
+ "sub.s %[temp1], %[temp9], %[temp1] \n\t"
+ "addiu %[p_t_gain], %[p_t_gain], 4 \n\t"
+ "madd.s %[temp2], %[temp2], %[ag2], %[temp0] \n\t"
+ "addiu %[p_delay], %[p_delay], 8 \n\t"
+ "madd.s %[temp3], %[temp3], %[ag2], %[temp1] \n\t"
+ "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], %[len], 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),
+ [len]"r"(len), [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;
+
+ len = (int)((int*)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"
+ "addiu %[l], %[l], 8 \n\t"
+ "mul.s %[temp2], %[h1], %[l_re] \n\t"
+ "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], %[len], 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), [len]"r"(len)
+ : "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 0000000..d1353c4
--- /dev/null
+++ b/libavcodec/mips/aacpsy_mips.h
@@ -0,0 +1,230 @@
+/*
+ * 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
+
+#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"
+ "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"
+ " 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 0000000..53a5fd0
--- /dev/null
+++ b/libavcodec/mips/aacsbr_mips.c
@@ -0,0 +1,618 @@
+/*
+ * 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"
+
+#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"
+ "addiu %[p_x1_low], %[p_x1_low], 32 \n\t"
+ "bne %[p_x1_low], %[loop_end], 1b \n\t"
+ "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"
+ "addiu %[p_x_low], %[p_x_low], 32 \n\t"
+ "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"
+ "addiu %[p_x1_low], %[p_x1_low], 32 \n\t"
+ "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"
+ "addiu %[x1], %[x1], 32 \n\t"
+ "bne %[x1], %[j], 1b \n\t"
+ "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"
+ "addiu %[x1], %[x1], 256 \n\t"
+ "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"
+ "addiu %[x1], %[x1], 256 \n\t"
+ "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"
+ "addiu %[x1], %[x1], 256 \n\t"
+ "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"
+ "addiu %[x1], %[x1], 256 \n\t"
+ "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"
+ "addiu %[pok], %[pok], 16 \n\t"
+ "addiu %[g_temp1], %[g_temp1], 16 \n\t"
+ "addiu %[pok1], %[pok1], 16 \n\t"
+ "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"
+ "addiu %[pok], %[pok], 4 \n\t"
+ "addiu %[g_temp1], %[g_temp1], 4 \n\t"
+ "addiu %[pok1], %[pok1], 4 \n\t"
+ "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"
+ "addiu %[in], %[in], 8 \n\t"
+ "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 0000000..8e6ad7d
--- /dev/null
+++ b/libavcodec/mips/aacsbr_mips.h
@@ -0,0 +1,493 @@
+/*
+ * 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"
+
+#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"
+ "addiu %[w0], %[w0], 32 \n\t"
+ "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"
+ "addiu %[w0], %[w0], 32 \n\t"
+ "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
+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"
+ "addiu %[dst], %[dst], 16 \n\t"
+ "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t"
+ "lwc1 %[temp9], 2056(%[s0]) \n\t"
+ "addiu %[s0], %[s0], 16 \n\t"
+ "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t"
+ "lwc1 %[temp10], 4108(%[v0]) \n\t"
+ "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"
+ "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 */
+#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 0000000..f33c6f1
--- /dev/null
+++ b/libavcodec/mips/ac3dsp_mips.c
@@ -0,0 +1,412 @@
+/*
+ * 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"
+
+
+#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"
+ "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"
+ "addiu %[bap1], %[bap1], 2 \n\t"
+ "bnez %[cond], 2b \n\t"
+ "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"
+ "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"
+ "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)
+{
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ __asm__ volatile (
+ "andi %[temp3], %[len], 3 \n\t"
+ "addu %[temp2], %[bap], %[len] \n\t"
+ "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"
+ "addu %[temp0], %[mant_cnt], %[temp0] \n\t"
+ "sll %[temp5], %[temp5], 1 \n\t"
+ "addu %[temp5], %[mant_cnt], %[temp5] \n\t"
+ "lhu %[temp1], 0(%[temp0]) \n\t"
+ "sll %[temp6], %[temp6], 1 \n\t"
+ "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"
+ "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"
+ "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"
+ "addiu %[temp2], %[temp2], -1 \n\t"
+ "sll %[temp0], %[temp0], 1 \n\t"
+ "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 && HAVE_MIPS32R2
+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,*matrix_p, **samples_x, **samples_end, **samples_sw;
+
+ __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], 2 \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"
+ "lw %[samples_p], 0(%[samples_x]) \n\t"
+ "addiu %[i3], %[i], 12 \n\t"
+ "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"
+ "addiu %[matrix_p], 8 \n\t"
+ "addiu %[samples_x], 4 \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"
+ " lw %[samples_p], 0(%[samples_x]) \n\t"
+
+ "lw %[samples_p], 4(%[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"
+ "lw %[samples_p], 0(%[samples_x]) \n\t"
+ "addiu %[i3], %[i], 12 \n\t"
+ "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"
+ "addiu %[matrix_p], 8 \n\t"
+ "addiu %[samples_x], 4 \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"
+ " lw %[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 && HAVE_MIPS32R2
+ 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 0000000..c8d980a
--- /dev/null
+++ b/libavcodec/mips/acelp_filters_mips.c
@@ -0,0 +1,216 @@
+ /*
+ * 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"
+
+#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"
+ "addiu %[p_in_p], %[p_in_p], 4 \n\t"
+ "madd.s %[v],%[v], %[in_val_p],%[fc_val_p] \n\t"
+ "addiu %[p_in_m], %[p_in_m], -4 \n\t"
+ "addu %[p_filter_coeffs_p], %[p_filter_coeffs_p], %[prec] \n\t"
+ "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"
+ "addiu %[out], 32 \n\t"
+ "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 0000000..8770df8
--- /dev/null
+++ b/libavcodec/mips/acelp_vectors_mips.c
@@ -0,0 +1,101 @@
+/*
+ * 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"
+
+#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"
+ "addiu %[in_a], 8 \n\t"
+ "addiu %[in_b], 8 \n\t"
+ "swc1 $f2, 0(%[out]) \n\t"
+ "swc1 $f5, 4(%[out]) \n\t"
+ "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 0000000..1d6ed2d
--- /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 0000000..a469918
--- /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 0000000..ef5b07b
--- /dev/null
+++ b/libavcodec/mips/celp_filters_mips.c
@@ -0,0 +1,288 @@
+/*
+ * 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"
+
+#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"
+ "addiu %[p_out], -8 \n\t"
+ "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"
+ "addiu %[p_filter_coeffs], 4 \n\t"
+ "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"
+ "addiu %[p_filter_coeffs], 8 \n\t"
+ "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 0000000..d7ccc23
--- /dev/null
+++ b/libavcodec/mips/celp_math_mips.c
@@ -0,0 +1,89 @@
+/*
+ * 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"
+
+#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"
+ "addiu %[a], %[a], 4 \n\t"
+ "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 0000000..a967f67
--- /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 0000000..e84abda
--- /dev/null
+++ b/libavcodec/mips/compute_antialias_float.h
@@ -0,0 +1,182 @@
+/*
+ * 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
+
+#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"
+ "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 0000000..691f2db
--- /dev/null
+++ b/libavcodec/mips/fft_mips.c
@@ -0,0 +1,534 @@
+/*
+ * 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"
+
+/**
+ * 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);
+ int s_n = s->nbits;
+ int tem1, tem2;
+ 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;
+ */
+ __asm__ volatile (
+ "li %[tem1], 16 \n\t"
+ "sub %[s_n], %[tem1], %[s_n] \n\t"
+ "li %[tem2], 10923 \n\t"
+ "srav %[tem2], %[tem2], %[s_n] \n\t"
+ "ori %[num_t],%[tem2], 1 \n\t"
+ : [num_t]"=r"(num_transforms), [s_n]"+r"(s_n),
+ [tem1]"=&r"(tem1), [tem2]"=&r"(tem2)
+ );
+
+
+ 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;
+ */
+ __asm__ volatile (
+ "sra %[num_t], %[num_t], 1 \n\t"
+ "ori %[num_t], %[num_t], 1 \n\t"
+
+ : [num_t] "+r" (num_transforms)
+ );
+ 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"
+ "addiu %[tcos1], %[tcos1], 8 \t\n"
+ "addiu %[tsin1], %[tsin1], 8 \t\n"
+ "addiu %[in1], %[in1], 16 \t\n"
+ "nmsub.s %[temp11], %[temp11], %[temp8], %[temp7] \t\n"
+ "madd.s %[temp12], %[temp12], %[temp8], %[temp6] \t\n"
+ "addiu %[in2], %[in2], -16 \t\n"
+ "addiu %[in3], %[in3], 16 \t\n"
+ "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 0000000..8a0265f
--- /dev/null
+++ b/libavcodec/mips/fmtconvert_mips.c
@@ -0,0 +1,342 @@
+/*
+ * 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"
+
+#if HAVE_INLINE_ASM
+#if HAVE_MIPSDSPR1
+static void float_to_int16_mips(int16_t *dst, const float *src, long len)
+{
+ const float *src_end = src + len;
+ int ret0, ret1, ret2, ret3, ret4, ret5, ret6, ret7;
+ float src0, src1, src2, src3, src4, src5, src6, src7;
+
+ /*
+ * loop is 8 times unrolled in assembler in order to achieve better performance
+ */
+ __asm__ volatile(
+ "beq %[len], $zero, fti16_end%= \n\t"
+ "fti16_lp%=: \n\t"
+ "lwc1 %[src0], 0(%[src]) \n\t"
+ "lwc1 %[src1], 4(%[src]) \n\t"
+ "lwc1 %[src2], 8(%[src]) \n\t"
+ "lwc1 %[src3], 12(%[src]) \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"
+ "mfc1 %[ret0], %[src0] \n\t"
+ "mfc1 %[ret1], %[src1] \n\t"
+ "mfc1 %[ret2], %[src2] \n\t"
+ "mfc1 %[ret3], %[src3] \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"
+ "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"
+ "addiu %[src], 32 \n\t"
+ "shll_s.w %[ret0], %[ret0], 16 \n\t"
+ "shll_s.w %[ret1], %[ret1], 16 \n\t"
+ "shll_s.w %[ret2], %[ret2], 16 \n\t"
+ "shll_s.w %[ret3], %[ret3], 16 \n\t"
+ "srl %[ret0], %[ret0], 16 \n\t"
+ "srl %[ret1], %[ret1], 16 \n\t"
+ "srl %[ret2], %[ret2], 16 \n\t"
+ "srl %[ret3], %[ret3], 16 \n\t"
+ "sh %[ret0], 0(%[dst]) \n\t"
+ "sh %[ret1], 2(%[dst]) \n\t"
+ "sh %[ret2], 4(%[dst]) \n\t"
+ "sh %[ret3], 6(%[dst]) \n\t"
+ "mfc1 %[ret4], %[src4] \n\t"
+ "mfc1 %[ret5], %[src5] \n\t"
+ "mfc1 %[ret6], %[src6] \n\t"
+ "mfc1 %[ret7], %[src7] \n\t"
+ "shll_s.w %[ret4], %[ret4], 16 \n\t"
+ "shll_s.w %[ret5], %[ret5], 16 \n\t"
+ "shll_s.w %[ret6], %[ret6], 16 \n\t"
+ "shll_s.w %[ret7], %[ret7], 16 \n\t"
+ "srl %[ret4], %[ret4], 16 \n\t"
+ "srl %[ret5], %[ret5], 16 \n\t"
+ "srl %[ret6], %[ret6], 16 \n\t"
+ "srl %[ret7], %[ret7], 16 \n\t"
+ "sh %[ret4], 8(%[dst]) \n\t"
+ "sh %[ret5], 10(%[dst]) \n\t"
+ "sh %[ret6], 12(%[dst]) \n\t"
+ "sh %[ret7], 14(%[dst]) \n\t"
+ "addiu %[dst], 16 \n\t"
+ "bne %[src], %[src_end], fti16_lp%= \n\t"
+ "fti16_end%=: \n\t"
+ : [ret0]"=&r"(ret0), [ret1]"=&r"(ret1), [ret2]"=&r"(ret2), [ret3]"=&r"(ret3),
+ [ret4]"=&r"(ret4), [ret5]"=&r"(ret5), [ret6]"=&r"(ret6), [ret7]"=&r"(ret7),
+ [src0]"=&f"(src0), [src1]"=&f"(src1), [src2]"=&f"(src2), [src3]"=&f"(src3),
+ [src4]"=&f"(src4), [src5]"=&f"(src5), [src6]"=&f"(src6), [src7]"=&f"(src7),
+ [src]"+r"(src), [dst]"+r"(dst)
+ : [src_end]"r"(src_end), [len]"r"(len)
+ : "memory"
+ );
+}
+
+static void float_to_int16_interleave_mips(int16_t *dst, const float **src, long len,
+ int channels)
+{
+ int c, ch2 = channels <<1;
+ int ret0, ret1, ret2, ret3, ret4, ret5, ret6, ret7;
+ float src0, src1, src2, src3, src4, src5, src6, src7;
+ int16_t *dst_ptr0, *dst_ptr1, *dst_ptr2, *dst_ptr3;
+ int16_t *dst_ptr4, *dst_ptr5, *dst_ptr6, *dst_ptr7;
+ const float *src_ptr, *src_ptr2, *src_end;
+
+ if (channels == 2) {
+ src_ptr = &src[0][0];
+ src_ptr2 = &src[1][0];
+ src_end = src_ptr + len;
+
+ __asm__ volatile (
+ "fti16i2_lp%=: \n\t"
+ "lwc1 %[src0], 0(%[src_ptr]) \n\t"
+ "lwc1 %[src1], 0(%[src_ptr2]) \n\t"
+ "addiu %[src_ptr], 4 \n\t"
+ "cvt.w.s $f9, %[src0] \n\t"
+ "cvt.w.s $f10, %[src1] \n\t"
+ "mfc1 %[ret0], $f9 \n\t"
+ "mfc1 %[ret1], $f10 \n\t"
+ "shll_s.w %[ret0], %[ret0], 16 \n\t"
+ "shll_s.w %[ret1], %[ret1], 16 \n\t"
+ "addiu %[src_ptr2], 4 \n\t"
+ "srl %[ret0], %[ret0], 16 \n\t"
+ "srl %[ret1], %[ret1], 16 \n\t"
+ "sh %[ret0], 0(%[dst]) \n\t"
+ "sh %[ret1], 2(%[dst]) \n\t"
+ "addiu %[dst], 4 \n\t"
+ "bne %[src_ptr], %[src_end], fti16i2_lp%= \n\t"
+ : [ret0]"=&r"(ret0), [ret1]"=&r"(ret1),
+ [src0]"=&f"(src0), [src1]"=&f"(src1),
+ [src_ptr]"+r"(src_ptr), [src_ptr2]"+r"(src_ptr2),
+ [dst]"+r"(dst)
+ : [src_end]"r"(src_end)
+ : "memory"
+ );
+ } else {
+ for (c = 0; c < channels; c++) {
+ src_ptr = &src[c][0];
+ dst_ptr0 = &dst[c];
+ src_end = src_ptr + len;
+ /*
+ * loop is 8 times unrolled in assembler in order to achieve better performance
+ */
+ __asm__ volatile(
+ "fti16i_lp%=: \n\t"
+ "lwc1 %[src0], 0(%[src_ptr]) \n\t"
+ "lwc1 %[src1], 4(%[src_ptr]) \n\t"
+ "lwc1 %[src2], 8(%[src_ptr]) \n\t"
+ "lwc1 %[src3], 12(%[src_ptr]) \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"
+ "mfc1 %[ret0], %[src0] \n\t"
+ "mfc1 %[ret1], %[src1] \n\t"
+ "mfc1 %[ret2], %[src2] \n\t"
+ "mfc1 %[ret3], %[src3] \n\t"
+ "lwc1 %[src4], 16(%[src_ptr]) \n\t"
+ "lwc1 %[src5], 20(%[src_ptr]) \n\t"
+ "lwc1 %[src6], 24(%[src_ptr]) \n\t"
+ "lwc1 %[src7], 28(%[src_ptr]) \n\t"
+ "addu %[dst_ptr1], %[dst_ptr0], %[ch2] \n\t"
+ "addu %[dst_ptr2], %[dst_ptr1], %[ch2] \n\t"
+ "addu %[dst_ptr3], %[dst_ptr2], %[ch2] \n\t"
+ "addu %[dst_ptr4], %[dst_ptr3], %[ch2] \n\t"
+ "addu %[dst_ptr5], %[dst_ptr4], %[ch2] \n\t"
+ "addu %[dst_ptr6], %[dst_ptr5], %[ch2] \n\t"
+ "addu %[dst_ptr7], %[dst_ptr6], %[ch2] \n\t"
+ "addiu %[src_ptr], 32 \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"
+ "shll_s.w %[ret0], %[ret0], 16 \n\t"
+ "shll_s.w %[ret1], %[ret1], 16 \n\t"
+ "shll_s.w %[ret2], %[ret2], 16 \n\t"
+ "shll_s.w %[ret3], %[ret3], 16 \n\t"
+ "srl %[ret0], %[ret0], 16 \n\t"
+ "srl %[ret1], %[ret1], 16 \n\t"
+ "srl %[ret2], %[ret2], 16 \n\t"
+ "srl %[ret3], %[ret3], 16 \n\t"
+ "sh %[ret0], 0(%[dst_ptr0]) \n\t"
+ "sh %[ret1], 0(%[dst_ptr1]) \n\t"
+ "sh %[ret2], 0(%[dst_ptr2]) \n\t"
+ "sh %[ret3], 0(%[dst_ptr3]) \n\t"
+ "mfc1 %[ret4], %[src4] \n\t"
+ "mfc1 %[ret5], %[src5] \n\t"
+ "mfc1 %[ret6], %[src6] \n\t"
+ "mfc1 %[ret7], %[src7] \n\t"
+ "shll_s.w %[ret4], %[ret4], 16 \n\t"
+ "shll_s.w %[ret5], %[ret5], 16 \n\t"
+ "shll_s.w %[ret6], %[ret6], 16 \n\t"
+ "shll_s.w %[ret7], %[ret7], 16 \n\t"
+ "srl %[ret4], %[ret4], 16 \n\t"
+ "srl %[ret5], %[ret5], 16 \n\t"
+ "srl %[ret6], %[ret6], 16 \n\t"
+ "srl %[ret7], %[ret7], 16 \n\t"
+ "sh %[ret4], 0(%[dst_ptr4]) \n\t"
+ "sh %[ret5], 0(%[dst_ptr5]) \n\t"
+ "sh %[ret6], 0(%[dst_ptr6]) \n\t"
+ "sh %[ret7], 0(%[dst_ptr7]) \n\t"
+ "addu %[dst_ptr0], %[dst_ptr7], %[ch2] \n\t"
+ "bne %[src_ptr], %[src_end], fti16i_lp%= \n\t"
+ : [ret0]"=&r"(ret0), [ret1]"=&r"(ret1), [ret2]"=&r"(ret2), [ret3]"=&r"(ret3),
+ [ret4]"=&r"(ret4), [ret5]"=&r"(ret5), [ret6]"=&r"(ret6), [ret7]"=&r"(ret7),
+ [src0]"=&f"(src0), [src1]"=&f"(src1), [src2]"=&f"(src2), [src3]"=&f"(src3),
+ [src4]"=&f"(src4), [src5]"=&f"(src5), [src6]"=&f"(src6), [src7]"=&f"(src7),
+ [dst_ptr1]"=&r"(dst_ptr1), [dst_ptr2]"=&r"(dst_ptr2), [dst_ptr3]"=&r"(dst_ptr3),
+ [dst_ptr4]"=&r"(dst_ptr4), [dst_ptr5]"=&r"(dst_ptr5), [dst_ptr6]"=&r"(dst_ptr6),
+ [dst_ptr7]"=&r"(dst_ptr7), [dst_ptr0]"+r"(dst_ptr0), [src_ptr]"+r"(src_ptr)
+ : [ch2]"r"(ch2), [src_end]"r"(src_end)
+ : "memory"
+ );
+ }
+ }
+}
+#endif /* HAVE_MIPSDSPR1 */
+
+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"
+
+ "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;*/
+ "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
+#if HAVE_MIPSDSPR1
+ c->float_to_int16_interleave = float_to_int16_interleave_mips;
+ c->float_to_int16 = float_to_int16_mips;
+#endif
+ c->int32_to_float_fmul_scalar = int32_to_float_fmul_scalar_mips;
+#endif
+}
diff --git a/libavcodec/mips/iirfilter_mips.c b/libavcodec/mips/iirfilter_mips.c
new file mode 100644
index 0000000..a5646cd
--- /dev/null
+++ b/libavcodec/mips/iirfilter_mips.c
@@ -0,0 +1,204 @@
+/*
+ * 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
+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_INLINE_ASM */
+
+void ff_iir_filter_init_mips(FFIIRFilterContext *f) {
+#if HAVE_INLINE_ASM
+ f->filter_flt = ff_iir_filter_flt_mips;
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/mips/lsp_mips.h b/libavcodec/mips/lsp_mips.h
new file mode 100644
index 0000000..c55ef03
--- /dev/null
+++ b/libavcodec/mips/lsp_mips.h
@@ -0,0 +1,109 @@
+/*
+ * 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
+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"
+ "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"
+ "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 dd80f68..368290a 100644
--- a/libavcodec/mips/mathops.h
+++ b/libavcodec/mips/mathops.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/mips/mpegaudiodsp_mips_fixed.c b/libavcodec/mips/mpegaudiodsp_mips_fixed.c
new file mode 100644
index 0000000..047a833
--- /dev/null
+++ b/libavcodec/mips/mpegaudiodsp_mips_fixed.c
@@ -0,0 +1,907 @@
+ /*
+ * 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 "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"
+ "addi %[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"
+ "addi %[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"
+ "addi %[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"
+ "addi %[w], %[w], 4 \n\t"
+ "addi %[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 0000000..beb8e78
--- /dev/null
+++ b/libavcodec/mips/mpegaudiodsp_mips_float.c
@@ -0,0 +1,1250 @@
+/*
+ * 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 "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"
+ "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"
+ "addu %[w], %[window], 4 \t\n"
+ "nmsub.s %[sum], %[sum], %[in3], %[in4] \t\n"
+ "addu %[w2], %[window], 124 \t\n"
+ "addiu %[p], %[synth_buf], 68 \t\n"
+ "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"
+ "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"
+ "addiu %[w], %[w], 4 \t\n"
+ "nmsub.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "addiu %[w2], %[w2], -4 \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "addu %[j], %[j], 4 \t\n"
+ "addiu %[p], 4 \t\n"
+ "swc1 %[sum], 0(%[samples]) \t\n"
+ "addiu %[p2], -4 \t\n"
+ "swc1 %[sum2], 0(%[samples2]) \t\n"
+ "addu %[samples], %[samples], %[incr1] \t\n"
+ "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"
+ );
+}
+
+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;
+}
+
+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"
+ );
+}
+
+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++;
+ }
+}
+
+void ff_mpadsp_init_mipsfpu(MPADSPContext *s)
+{
+ s->apply_window_float = ff_mpadsp_apply_window_mips_float;
+ s->imdct36_blocks_float = ff_imdct36_blocks_mips_float;
+ s->dct32_float = ff_dct32_mips_float;
+}
diff --git a/libavcodec/mips/sbrdsp_mips.c b/libavcodec/mips/sbrdsp_mips.c
new file mode 100644
index 0000000..d4460ba
--- /dev/null
+++ b/libavcodec/mips/sbrdsp_mips.c
@@ -0,0 +1,940 @@
+/*
+ * 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"
+
+#if HAVE_INLINE_ASM
+static void sbr_neg_odd_64_mips(float *x)
+{
+ int Temp1, Temp2, Temp3, Temp4, Temp5;
+ float *x1 = &x[1];
+ float *x_end = x1 + 64;
+
+ /* loop unrolled 4 times */
+ __asm__ volatile (
+ "lui %[Temp5], 0x8000 \n\t"
+ "1: \n\t"
+ "lw %[Temp1], 0(%[x1]) \n\t"
+ "lw %[Temp2], 8(%[x1]) \n\t"
+ "lw %[Temp3], 16(%[x1]) \n\t"
+ "lw %[Temp4], 24(%[x1]) \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"
+ "sw %[Temp1], 0(%[x1]) \n\t"
+ "sw %[Temp2], 8(%[x1]) \n\t"
+ "sw %[Temp3], 16(%[x1]) \n\t"
+ "sw %[Temp4], 24(%[x1]) \n\t"
+ "addiu %[x1], %[x1], 32 \n\t"
+ "bne %[x1], %[x_end], 1b \n\t"
+
+ : [Temp1]"=&r"(Temp1), [Temp2]"=&r"(Temp2),
+ [Temp3]"=&r"(Temp3), [Temp4]"=&r"(Temp4),
+ [Temp5]"=&r"(Temp5), [x1]"+r"(x1)
+ : [x_end]"r"(x_end)
+ : "memory"
+ );
+}
+
+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"
+ "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"
+ "addiu %[z3], %[z3], 20 \n\t"
+ "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"
+ "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"
+ "addiu %[z1], %[z1], 16 \n\t"
+ "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"
+ "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"
+ "addiu %[src0], %[src0], 64 \n\t"
+ "addiu %[src1], %[src1], -64 \n\t"
+ "addiu %[v0], %[v0], 64 \n\t"
+ "addiu %[v1], %[v1], -64 \n\t"
+
+ : [v0]"+r"(v0), [v1]"+r"(v1), [src0]"+r"(psrc0), [src1]"+r"(psrc1),
+ [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp8]"=&f"(temp8),
+ [temp9]"=&f"(temp9), [temp10]"=&f"(temp10), [temp11]"=&f"(temp11)
+ :
+ :"memory"
+ );
+ }
+}
+
+static void sbr_autocorrelate_mips(const float x[40][2], float phi[3][2][2])
+{
+ int i;
+ float real_sum_0 = 0.0f;
+ float real_sum_1 = 0.0f;
+ float real_sum_2 = 0.0f;
+ float imag_sum_1 = 0.0f;
+ float imag_sum_2 = 0.0f;
+ float *p_x, *p_phi;
+ float temp0, temp1, temp2, temp3, temp4, temp5, temp6;
+ float temp7, temp_r, temp_r1, temp_r2, temp_r3, temp_r4;
+ p_x = (float*)&x[0][0];
+ p_phi = &phi[0][0][0];
+
+ __asm__ volatile (
+ "lwc1 %[temp0], 8(%[p_x]) \n\t"
+ "lwc1 %[temp1], 12(%[p_x]) \n\t"
+ "lwc1 %[temp2], 16(%[p_x]) \n\t"
+ "lwc1 %[temp3], 20(%[p_x]) \n\t"
+ "lwc1 %[temp4], 24(%[p_x]) \n\t"
+ "lwc1 %[temp5], 28(%[p_x]) \n\t"
+ "mul.s %[temp_r], %[temp1], %[temp1] \n\t"
+ "mul.s %[temp_r1], %[temp1], %[temp3] \n\t"
+ "mul.s %[temp_r2], %[temp1], %[temp2] \n\t"
+ "mul.s %[temp_r3], %[temp1], %[temp5] \n\t"
+ "mul.s %[temp_r4], %[temp1], %[temp4] \n\t"
+ "madd.s %[temp_r], %[temp_r], %[temp0], %[temp0] \n\t"
+ "madd.s %[temp_r1], %[temp_r1], %[temp0], %[temp2] \n\t"
+ "msub.s %[temp_r2], %[temp_r2], %[temp0], %[temp3] \n\t"
+ "madd.s %[temp_r3], %[temp_r3], %[temp0], %[temp4] \n\t"
+ "msub.s %[temp_r4], %[temp_r4], %[temp0], %[temp5] \n\t"
+ "add.s %[real_sum_0], %[real_sum_0], %[temp_r] \n\t"
+ "add.s %[real_sum_1], %[real_sum_1], %[temp_r1] \n\t"
+ "add.s %[imag_sum_1], %[imag_sum_1], %[temp_r2] \n\t"
+ "add.s %[real_sum_2], %[real_sum_2], %[temp_r3] \n\t"
+ "add.s %[imag_sum_2], %[imag_sum_2], %[temp_r4] \n\t"
+ "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"
+ "addiu %[p_x], %[p_x], 24 \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [real_sum_0]"+f"(real_sum_0), [real_sum_1]"+f"(real_sum_1),
+ [imag_sum_1]"+f"(imag_sum_1), [real_sum_2]"+f"(real_sum_2),
+ [temp_r]"=&f"(temp_r), [temp_r1]"=&f"(temp_r1),
+ [temp_r2]"=&f"(temp_r2), [temp_r3]"=&f"(temp_r3),
+ [temp_r4]"=&f"(temp_r4), [p_x]"+r"(p_x),
+ [imag_sum_2]"+f"(imag_sum_2)
+ :
+ : "memory"
+ );
+ }
+ __asm__ volatile (
+ "lwc1 %[temp0], -296(%[p_x]) \n\t"
+ "lwc1 %[temp1], -292(%[p_x]) \n\t"
+ "lwc1 %[temp2], 8(%[p_x]) \n\t"
+ "lwc1 %[temp3], 12(%[p_x]) \n\t"
+ "lwc1 %[temp4], -288(%[p_x]) \n\t"
+ "lwc1 %[temp5], -284(%[p_x]) \n\t"
+ "lwc1 %[temp6], -280(%[p_x]) \n\t"
+ "lwc1 %[temp7], -276(%[p_x]) \n\t"
+ "madd.s %[temp_r], %[real_sum_0], %[temp0], %[temp0] \n\t"
+ "madd.s %[temp_r1], %[real_sum_0], %[temp2], %[temp2] \n\t"
+ "madd.s %[temp_r2], %[real_sum_1], %[temp0], %[temp4] \n\t"
+ "madd.s %[temp_r3], %[imag_sum_1], %[temp0], %[temp5] \n\t"
+ "madd.s %[temp_r], %[temp_r], %[temp1], %[temp1] \n\t"
+ "madd.s %[temp_r1], %[temp_r1], %[temp3], %[temp3] \n\t"
+ "madd.s %[temp_r2], %[temp_r2], %[temp1], %[temp5] \n\t"
+ "nmsub.s %[temp_r3], %[temp_r3], %[temp1], %[temp4] \n\t"
+ "lwc1 %[temp4], 16(%[p_x]) \n\t"
+ "lwc1 %[temp5], 20(%[p_x]) \n\t"
+ "swc1 %[temp_r], 40(%[p_phi]) \n\t"
+ "swc1 %[temp_r1], 16(%[p_phi]) \n\t"
+ "swc1 %[temp_r2], 24(%[p_phi]) \n\t"
+ "swc1 %[temp_r3], 28(%[p_phi]) \n\t"
+ "madd.s %[temp_r], %[real_sum_1], %[temp2], %[temp4] \n\t"
+ "madd.s %[temp_r1], %[imag_sum_1], %[temp2], %[temp5] \n\t"
+ "madd.s %[temp_r2], %[real_sum_2], %[temp0], %[temp6] \n\t"
+ "madd.s %[temp_r3], %[imag_sum_2], %[temp0], %[temp7] \n\t"
+ "madd.s %[temp_r], %[temp_r], %[temp3], %[temp5] \n\t"
+ "nmsub.s %[temp_r1], %[temp_r1], %[temp3], %[temp4] \n\t"
+ "madd.s %[temp_r2], %[temp_r2], %[temp1], %[temp7] \n\t"
+ "nmsub.s %[temp_r3], %[temp_r3], %[temp1], %[temp6] \n\t"
+ "swc1 %[temp_r], 0(%[p_phi]) \n\t"
+ "swc1 %[temp_r1], 4(%[p_phi]) \n\t"
+ "swc1 %[temp_r2], 8(%[p_phi]) \n\t"
+ "swc1 %[temp_r3], 12(%[p_phi]) \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp_r]"=&f"(temp_r),
+ [real_sum_0]"+f"(real_sum_0), [real_sum_1]"+f"(real_sum_1),
+ [real_sum_2]"+f"(real_sum_2), [imag_sum_1]"+f"(imag_sum_1),
+ [temp_r2]"=&f"(temp_r2), [temp_r3]"=&f"(temp_r3),
+ [temp_r1]"=&f"(temp_r1), [p_phi]"+r"(p_phi),
+ [imag_sum_2]"+f"(imag_sum_2)
+ : [p_x]"r"(p_x)
+ : "memory"
+ );
+}
+
+static void sbr_hf_gen_mips(float (*X_high)[2], const float (*X_low)[2],
+ const float alpha0[2], const float alpha1[2],
+ float bw, int start, int end)
+{
+ float alpha[4];
+ int i;
+ float *p_x_low = (float*)&X_low[0][0] + 2*start;
+ float *p_x_high = &X_high[0][0] + 2*start;
+ float temp0, temp1, temp2, temp3, temp4, temp5, temp6;
+ float temp7, temp8, temp9, temp10, temp11, temp12;
+
+ alpha[0] = alpha1[0] * bw * bw;
+ alpha[1] = alpha1[1] * bw * bw;
+ alpha[2] = alpha0[0] * bw;
+ alpha[3] = alpha0[1] * bw;
+
+ for (i = start; i < end; i++) {
+ __asm__ volatile (
+ "lwc1 %[temp0], -16(%[p_x_low]) \n\t"
+ "lwc1 %[temp1], -12(%[p_x_low]) \n\t"
+ "lwc1 %[temp2], -8(%[p_x_low]) \n\t"
+ "lwc1 %[temp3], -4(%[p_x_low]) \n\t"
+ "lwc1 %[temp5], 0(%[p_x_low]) \n\t"
+ "lwc1 %[temp6], 4(%[p_x_low]) \n\t"
+ "lwc1 %[temp7], 0(%[alpha]) \n\t"
+ "lwc1 %[temp8], 4(%[alpha]) \n\t"
+ "lwc1 %[temp9], 8(%[alpha]) \n\t"
+ "lwc1 %[temp10], 12(%[alpha]) \n\t"
+ "addiu %[p_x_high], %[p_x_high], 8 \n\t"
+ "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)
+{
+ float *p_y, *p_x, *p_g;
+ float temp0, temp1, temp2;
+ int loop_end;
+
+ p_g = (float*)&g_filt[0];
+ p_y = &Y[0][0];
+ p_x = (float*)&X_high[0][ixh][0];
+ loop_end = (int)((int*)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"
+ "addiu %[p_g], %[p_g], 4 \n\t"
+ "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"
+ " 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"
+ "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"
+ "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"
+ "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"
+ "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->neg_odd_64 = sbr_neg_odd_64_mips;
+ 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;
+ s->autocorrelate = sbr_autocorrelate_mips;
+ s->hf_gen = sbr_hf_gen_mips;
+ s->hf_g_filt = sbr_hf_g_filt_mips;
+
+ s->hf_apply_noise[0] = sbr_hf_apply_noise_0_mips;
+ s->hf_apply_noise[1] = sbr_hf_apply_noise_1_mips;
+ s->hf_apply_noise[2] = sbr_hf_apply_noise_2_mips;
+ s->hf_apply_noise[3] = sbr_hf_apply_noise_3_mips;
+#endif /* HAVE_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/mjpeg.c b/libavcodec/mjpeg.c
index a353851..bdd7b19 100644
--- a/libavcodec/mjpeg.c
+++ b/libavcodec/mjpeg.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/mjpeg.h b/libavcodec/mjpeg.h
index bd3b1e8..73db1dd 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
*/
@@ -128,6 +128,7 @@ static inline void put_marker(PutBitContext *p, int code)
#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 59734c9..6adeaf0 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 ab65461..e548b00 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 ed32d5a..3947c82 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
*/
@@ -88,7 +88,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 66cf2d4..f6ee705 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
*/
@@ -54,6 +54,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 */
@@ -121,7 +122,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;
}
@@ -132,13 +133,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;
@@ -161,4 +166,5 @@ AVCodec ff_mjpegb_decoder = {
.close = ff_mjpeg_decode_end,
.decode = mjpegb_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
};
diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index 01e11be..b350f44 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,17 +30,20 @@
* 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 "mjpeg.h"
#include "mjpegdec.h"
#include "jpeglsdec.h"
+#include "tiff.h"
+#include "exif.h"
+#include "bytestream.h"
static int build_vlc(VLC *vlc, const uint8_t *bits_table,
@@ -52,7 +55,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);
@@ -82,6 +85,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;
@@ -103,6 +117,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;
@@ -110,19 +125,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;
@@ -138,10 +162,10 @@ int ff_mjpeg_decode_dqt(MJpegDecodeContext *s)
len = get_bits(&s->gb, 16) - 2;
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)
@@ -150,7 +174,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
@@ -220,25 +244,39 @@ int ff_mjpeg_decode_dht(MJpegDecodeContext *s)
int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
{
- int len, nb_components, i, width, height, pix_fmt_id, ret;
+ int len, nb_components, i, width, height, bits, pix_fmt_id, ret;
+ int h_count[MAX_COMPONENTS];
+ int v_count[MAX_COMPONENTS];
+
+ s->cur_scan = 0;
+ s->upscale_h = s->upscale_v = 0;
/* XXX: verify len field validity */
len = get_bits(&s->gb, 16);
- s->bits = get_bits(&s->gb, 8);
+ 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)
- s->bits = 9;
- if (s->bits == 9 && !s->pegasus_rct)
+ bits = 9;
+ if (bits == 9 && !s->pegasus_rct)
s->rct = 1; // FIXME ugly
- if (s->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;
@@ -258,7 +296,7 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
return AVERROR_INVALIDDATA;
}
}
- if (s->ls && !(s->bits <= 8 || nb_components == 1)) {
+ if (s->ls && !(bits <= 8 || nb_components == 1)) {
avpriv_report_missing_feature(s->avctx,
"JPEG-LS that is not <= 8 "
"bits/component or 16-bit gray");
@@ -267,28 +305,32 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
s->nb_components = nb_components;
s->h_max = 1;
s->v_max = 1;
+ memset(h_count, 0, sizeof(h_count));
+ memset(v_count, 0, sizeof(v_count));
for (i = 0; i < nb_components; i++) {
/* component id */
s->component_id[i] = get_bits(&s->gb, 8) - 1;
- s->h_count[i] = get_bits(&s->gb, 4);
- s->v_count[i] = get_bits(&s->gb, 4);
+ h_count[i] = get_bits(&s->gb, 4);
+ v_count[i] = get_bits(&s->gb, 4);
/* compute hmax and vmax (only used in interleaved case) */
- if (s->h_count[i] > s->h_max)
- s->h_max = s->h_count[i];
- if (s->v_count[i] > s->v_max)
- s->v_max = s->v_count[i];
+ if (h_count[i] > s->h_max)
+ s->h_max = h_count[i];
+ if (v_count[i] > s->v_max)
+ s->v_max = v_count[i];
s->quant_index[i] = get_bits(&s->gb, 8);
- 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 (!s->h_count[i] || !s->v_count[i]) {
+ }
+ if (!h_count[i] || !v_count[i]) {
av_log(s->avctx, AV_LOG_ERROR,
"Invalid sampling factor in component %d %d:%d\n",
- i, s->h_count[i], s->v_count[i]);
+ i, h_count[i], v_count[i]);
return AVERROR_INVALIDDATA;
}
av_log(s->avctx, AV_LOG_DEBUG, "component %d %d:%d id: %d quant:%d\n",
- i, s->h_count[i], s->v_count[i],
+ i, h_count[i], v_count[i],
s->component_id[i], s->quant_index[i]);
}
@@ -297,15 +339,20 @@ 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 */
- /* XXX: also check h_count and v_count */
- if (width != s->width || height != s->height) {
+ 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 &&
@@ -325,7 +372,16 @@ 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) |
(s->h_count[1] << 20) | (s->v_count[1] << 16) |
@@ -339,38 +395,154 @@ 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 |= 1 << (j/2);
+ else s->upscale_v |= 1 << (j/2);
+ }
+ }
+
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 {
- s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P;
+ 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 {
+ 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 |= 6;
+ s->upscale_h |= 6;
+ } else if (s->adobe_transform == 2 && s->bits <= 8) {
+ s->avctx->pix_fmt = AV_PIX_FMT_YUVA444P;
+ s->upscale_v |= 6;
+ s->upscale_h |= 6;
+ 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;
+ case 0x14121200:
+ case 0x22211100:
+ case 0x22112100:
+ 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->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 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) {
+ s->upscale_h = 6;
+ } else if (pix_fmt_id == 0x24111100) {
+ s->upscale_v = 6;
+ }
+ 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:
+unk_pixfmt:
av_log(s->avctx, AV_LOG_ERROR, "Unhandled pixel format 0x%x\n", pix_fmt_id);
+ s->upscale_h = s->upscale_v = 0;
+ return AVERROR_PATCHWELCOME;
+ }
+ if ((s->upscale_h || 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) {
+ s->upscale_h = s->upscale_v = 0;
if (s->nb_components > 1)
s->avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ 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
@@ -384,15 +556,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;
av_dlog(s->avctx, "%d %d %d %d %d %d\n",
@@ -403,6 +573,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);
@@ -411,8 +586,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));
@@ -424,11 +601,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)
@@ -445,7 +622,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;
}
@@ -493,7 +670,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;
}
@@ -667,46 +844,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) {
@@ -714,24 +946,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];
+ }
+ }
}
}
}
@@ -741,48 +996,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++;
@@ -792,7 +1087,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];
@@ -801,16 +1097,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++;
@@ -827,18 +1137,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];
@@ -871,27 +1221,29 @@ 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 (!s->progressive) {
if (copy_mb)
- s->hdsp.put_pixels_tab[1][0](ptr,
- reference_data[c] + block_offset,
- linesize[c], 8);
+ 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 (s->bits & 7)
+ shift_output(s, ptr, linesize[c]);
}
} else {
int block_idx = s->block_stride[c] * (v * mb_y + y) +
@@ -899,9 +1251,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);
@@ -919,74 +1271,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);
@@ -998,31 +1328,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);
@@ -1052,27 +1386,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 */
@@ -1089,10 +1431,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 */
@@ -1101,9 +1443,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);
@@ -1113,8 +1456,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,
@@ -1125,16 +1467,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;
}
}
@@ -1145,7 +1486,7 @@ next_field:
GetBitContext bak = s->gb;
align_get_bits(&bak);
if (show_bits(&bak, 16) == 0xFFD1) {
- av_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;
@@ -1178,22 +1519,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
@@ -1201,12 +1544,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);
@@ -1218,7 +1558,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);
@@ -1247,26 +1587,26 @@ 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")) {
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;
@@ -1276,19 +1616,106 @@ static int mjpeg_decode_app(MJpegDecodeContext *s)
s->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;
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 */
@@ -1330,15 +1757,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);
@@ -1355,22 +1782,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:
av_dlog(NULL, "find_marker skipped %d bytes\n", skipped);
@@ -1416,7 +1840,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;
@@ -1425,8 +1849,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++];
@@ -1434,7 +1856,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;
}
}
@@ -1475,11 +1897,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) {
@@ -1489,21 +1917,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)
@@ -1520,6 +1949,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");
@@ -1538,7 +1969,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:
@@ -1547,39 +1978,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");
@@ -1589,43 +2018,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);
@@ -1645,21 +2065,180 @@ 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 (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_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 & (1<<p)))
+ continue;
+ if (p==1 || p==2) {
+ w = FF_CEIL_RSHIFT(w, hshift);
+ h = FF_CEIL_RSHIFT(h, vshift);
+ }
+ if (s->upscale_v & (1<<p))
+ h = (h+1)>>1;
+ av_assert0(w > 0);
+ for (i = 0; i < h; i++) {
+ 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;
+ }
+ line += s->linesize[p];
+ }
+ }
+ }
+ if (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_YUVA444P ||
+ 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 & (1<<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;
@@ -1670,13 +2249,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;
@@ -1688,9 +2272,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[] = {
@@ -1715,10 +2307,13 @@ 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,
};
-
+#endif
+#if CONFIG_THP_DECODER
AVCodec ff_thp_decoder = {
.name = "thp",
.long_name = NULL_IF_CONFIG_SMALL("Nintendo Gamecube THP video"),
@@ -1728,5 +2323,8 @@ 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,
};
+#endif
diff --git a/libavcodec/mjpegdec.h b/libavcodec/mjpegdec.h
index aa4703a..deacabe 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;
+ int upscale_h;
+ int upscale_v;
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 a460886..14701e2 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"
@@ -44,6 +42,11 @@ 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);
@@ -75,7 +78,7 @@ av_cold int ff_mjpeg_encode_init(MpegEncContext *s)
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)
@@ -121,7 +124,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]);
@@ -136,23 +139,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)"),
@@ -162,7 +226,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 a4d684c..069d43c 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
*/
@@ -51,6 +51,6 @@ typedef struct MJpegContext {
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 adb335e..8a5b99f 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
*/
@@ -52,20 +54,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 */
@@ -96,7 +121,7 @@ static void jpeg_put_comments(AVCodecContext *avctx, PutBitContext *p)
put_marker(p, APP0);
put_bits(p, 16, 16);
avpriv_put_string(p, "JFIF", 1); /* this puts the trailing zero-byte too */
- put_bits(p, 16, 0x0201); /* v 1.02 */
+ put_bits(p, 16, 0x0102); /* v 1.02 */
put_bits(p, 8, 0); /* units type: 0 - aspect ratio */
put_bits(p, 16, avctx->sample_aspect_ratio.num);
put_bits(p, 16, avctx->sample_aspect_ratio.den);
@@ -128,22 +153,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;
@@ -152,21 +177,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 */
@@ -184,13 +229,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);
@@ -217,20 +262,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);
- assert((size&7) == 0);
+ flush_put_bits(pb);
+ size = put_bits_count(pb) - start * 8;
+
+ av_assert1((size&7) == 0);
size >>= 3;
ff_count=0;
@@ -275,21 +337,25 @@ static void escape_FF(PutBitContext *pb, int start)
}
}
-void ff_mjpeg_encode_stuffing(PutBitContext * pbc)
+void 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;
+
+ 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;
+
+ for(i=0; i<3; i++)
+ s->last_dc[i] = 128 << s->intra_dc_precision;
}
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 b48911e..38b9b3f 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);
+void 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 9615b66..87f7c77 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 5a4ee5f..05d8dba 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
*/
@@ -45,7 +45,7 @@
/** Maximum number of substreams that can be decoded.
* MLP's limit is 2. TrueHD supports at least up to 3.
*/
-#define MAX_SUBSTREAMS 3
+#define MAX_SUBSTREAMS 4
/** which multiple of 48000 the maximum sample rate is */
#define MAX_RATEFACTOR 4
diff --git a/libavcodec/mlp_parser.c b/libavcodec/mlp_parser.c
index 075227f..deaa844 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;
@@ -119,6 +119,23 @@ static uint64_t truehd_layout(int chanmap)
return layout;
}
+static int ff_mlp_get_major_sync_size(const uint8_t * buf, int bufsize)
+{
+ int has_extension, extensions = 0;
+ int size = 28;
+ if (bufsize < 28)
+ return -1;
+
+ if (AV_RB32(buf) == 0xf8726fba) {
+ has_extension = buf[25] & 1;
+ if (has_extension) {
+ extensions = buf[26] >> 4;
+ size += 2 + extensions * 2;
+ }
+ }
+ return size;
+}
+
/** Read a major sync info header - contains high level information about
* the stream - sample rate, channel arrangement etc. Most of this
* information is not actually necessary for decoding, only for playback.
@@ -127,18 +144,19 @@ static uint64_t truehd_layout(int chanmap)
int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
{
- int ratebits, channel_arrangement;
+ int ratebits, channel_arrangement, header_size;
uint16_t checksum;
- assert(get_bits_count(gb) == 0);
+ av_assert1(get_bits_count(gb) == 0);
- if (gb->size_in_bits < 28 << 3) {
+ 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) {
av_log(log, AV_LOG_ERROR, "packet too short, unable to read major sync\n");
return -1;
}
- checksum = ff_mlp_checksum16(gb->buffer, 26);
- if (checksum != AV_RL16(gb->buffer+26)) {
+ checksum = ff_mlp_checksum16(gb->buffer, header_size - 2);
+ if (checksum != AV_RL16(gb->buffer+header_size-2)) {
av_log(log, AV_LOG_ERROR, "major sync info header checksum error\n");
return AVERROR_INVALIDDATA;
}
@@ -147,6 +165,7 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
return AVERROR_INVALIDDATA;
mh->stream_type = get_bits(gb, 8);
+ mh->header_size = header_size;
if (mh->stream_type == 0xbb) {
mh->group1_bits = mlp_quants[get_bits(gb, 4)];
@@ -158,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;
@@ -174,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;
@@ -197,7 +218,7 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
mh->num_substreams = get_bits(gb, 4);
- skip_bits_long(gb, 4 + 11 * 8);
+ skip_bits_long(gb, 4 + (header_size - 17) * 8);
return 0;
}
@@ -228,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;
@@ -249,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;
}
@@ -267,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;
}
@@ -324,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
@@ -332,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) ==
@@ -357,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) ==
@@ -377,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 7530fac..0c0109e 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
*/
@@ -32,6 +32,7 @@
typedef struct MLPHeaderInfo
{
int stream_type; ///< 0xBB for MLP, 0xBA for TrueHD
+ int header_size; ///< Size of the major sync header, in bytes
int group1_bits; ///< The bit depth of the first substream
int group2_bits; ///< Bit depth of the second substream (MLP only)
@@ -39,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")
@@ -61,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 624efc1..490d107 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];
//@}
@@ -132,6 +132,9 @@ typedef struct MLPDecodeContext {
/// Current access unit being read has a major sync.
int is_major_sync_unit;
+ /// Size of the major sync unit, in bytes
+ int major_sync_header_size;
+
/// Set if a valid major sync block has been read. Otherwise no decoding is possible.
uint8_t params_valid;
@@ -141,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
@@ -153,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;
@@ -346,11 +352,15 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb)
return AVERROR_PATCHWELCOME;
}
+ m->major_sync_header_size = mh.header_size;
+
m->access_unit_size = mh.access_unit_size;
m->access_unit_size_pow2 = mh.access_unit_size_pow2;
m->num_substreams = mh.num_substreams;
- m->max_decoded_substream = m->num_substreams - 1;
+
+ /* limit to decoding 3 substreams, as the 4th is used by Dolby Atmos for non-audio data */
+ m->max_decoded_substream = FFMIN(m->num_substreams - 1, 2);
m->avctx->sample_rate = mh.group1_samplerate;
m->avctx->frame_size = mh.access_unit_size;
@@ -373,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)
@@ -385,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.
*
@@ -472,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;
}
@@ -484,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;
}
@@ -512,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) {
@@ -596,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;
@@ -614,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");
@@ -669,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;
}
}
@@ -788,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;
}
@@ -814,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;
}
@@ -854,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. */
@@ -992,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) {
@@ -1010,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],
@@ -1024,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,
@@ -1091,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;
@@ -1105,7 +1142,7 @@ static int read_access_unit(AVCodecContext *avctx, void* data,
if (read_major_sync(m, &gb) < 0)
goto error;
m->is_major_sync_unit = 1;
- header_size += 28;
+ header_size += m->major_sync_header_size;
}
if (!m->params_valid) {
@@ -1254,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;
@@ -1270,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)"),
@@ -1280,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 aded554..3ae8c37 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 acd48fc..a0edeb7 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/mmvideo.c b/libavcodec/mmvideo.c
index d80c832..9a7c10c 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;
@@ -68,17 +68,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;
}
/**
@@ -106,9 +104,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;
@@ -122,7 +123,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)
*/
@@ -193,13 +194,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;
@@ -220,7 +219,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 0000000..7cfe41c
--- /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 a765b26..c5bbf35 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
*/
@@ -116,7 +116,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;
@@ -158,14 +158,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);
@@ -303,13 +303,12 @@ 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;
}
@@ -364,12 +363,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;
@@ -395,10 +396,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;
@@ -522,6 +522,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;
@@ -529,8 +530,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;
@@ -543,6 +544,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);
@@ -569,10 +572,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);
@@ -584,6 +588,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];
@@ -611,6 +620,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);
@@ -745,8 +763,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;
}
@@ -843,6 +861,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;
@@ -871,9 +893,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);
@@ -1051,7 +1073,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;
@@ -1429,7 +1451,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;
@@ -1646,12 +1668,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 01936c6..ae2cbde 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 da2727f..19da10a 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 410b76f..14b7b9b 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 e6c32c7..4ffe74c 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 506750f..123c7a5 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
*/
@@ -35,9 +35,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,
@@ -51,7 +50,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 0000000..1c7ffea
--- /dev/null
+++ b/libavcodec/movtextdec.c
@@ -0,0 +1,113 @@
+/*
+ * 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"
+
+static int text_to_ass(AVBPrint *buf, const char *text, const char *text_end)
+{
+ while (text < text_end) {
+ switch (*text) {
+ case '\r':
+ break;
+ case '\n':
+ av_bprintf(buf, "\\N");
+ break;
+ default:
+ av_bprint_chars(buf, *text, 1);
+ break;
+ }
+ 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;
+ const char *ptr = avpkt->data;
+ const char *end;
+
+ 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.
+ */
+ end = ptr + FFMIN(2 + AV_RB16(ptr), 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});
+
+ // Note that the spec recommends lines be no longer than 2048 characters.
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+ text_to_ass(&buf, ptr, end);
+ 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 0000000..1b8f454
--- /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 0000000..df45532
--- /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 763ea2c..7af30bd 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 cdf49c1..4cb85748 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 2185aec..0f1e34a 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 f205ffe..5609e8f 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 ee05a93..29c65f9 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 2940b30..22c2be4 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 6005e21..8491037 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 15724f3..64fb4ab 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 be5227f..fc43a53 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--;
@@ -235,3 +241,4 @@ int ff_mpeg1_find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size,
pc->state = state;
return END_NOT_FOUND;
}
+
diff --git a/libavcodec/mpeg12.h b/libavcodec/mpeg12.h
index 9132dc3..b4ebd23 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 ccc3d2d..e8c4a5d 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 633a291..65b9485 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 b66bdc1..baa8e81 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,6 +25,7 @@
* MPEG-1/2 decoder
*/
+#define UNCHECKED_BITSTREAM_READER 1
#include <inttypes.h>
#include "libavutil/attributes.h"
@@ -43,6 +44,7 @@
#include "mpegvideo.h"
#include "thread.h"
#include "version.h"
+#include "vdpau_internal.h"
#include "xvmc_internal.h"
typedef struct Mpeg1Context {
@@ -61,7 +63,7 @@ typedef struct Mpeg1Context {
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;
@@ -158,15 +160,16 @@ static inline int mpeg1_decode_block_intra(MpegEncContext *s,
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 +177,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 +187,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 +207,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 +305,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 +472,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 +506,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 +520,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 +530,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:
@@ -605,6 +623,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 +667,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 +684,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 +722,7 @@ static inline int get_qscale(MpegEncContext *s)
return qscale << 1;
}
+
/* motion type (for MPEG-2) */
#define MT_FIELD 1
#define MT_FRAME 2
@@ -714,7 +736,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64])
av_dlog(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) {
@@ -729,11 +751,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 -1;
+ }
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;
@@ -813,13 +836,9 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64])
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->flags2 & CODEC_FLAG2_FAST) {
@@ -837,11 +856,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 {
@@ -860,10 +880,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);
@@ -943,6 +963,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
}
}
} 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)) {
@@ -959,6 +980,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 -1;
+ }
s->mv_type = MV_TYPE_DMV;
for (i = 0; i < 2; i++) {
if (USES_LIST(mb_type, i)) {
@@ -1027,17 +1052,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 -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, cbp);
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif /* FF_API_XVMC */
if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
if (s->flags2 & CODEC_FLAG2_FAST) {
@@ -1100,9 +1121,12 @@ 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;
- s->mpeg_enc_ctx.flags = avctx->flags;
- s->mpeg_enc_ctx.flags2 = avctx->flags2;
/* we need some permutation to store matrices,
* until the decoder sets the real permutation. */
@@ -1138,11 +1162,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++;
@@ -1162,24 +1183,32 @@ 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
#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
};
@@ -1194,27 +1223,44 @@ 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 (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.
@@ -1232,13 +1278,14 @@ static int mpeg_decode_postinit(AVCodecContext *avctx)
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 ||
+ (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;
}
if ((s->width == 0) || (s->height == 0))
@@ -1248,7 +1295,12 @@ static int mpeg_decode_postinit(AVCodecContext *avctx)
if (ret < 0)
return ret;
- avctx->bit_rate = s->bit_rate;
+ 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_info = s->aspect_ratio_info;
s1->save_width = s->width;
s1->save_height = s->height;
@@ -1268,7 +1320,7 @@ static int mpeg_decode_postinit(AVCodecContext *avctx)
// 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;
@@ -1313,14 +1365,7 @@ static int mpeg_decode_postinit(AVCodecContext *avctx)
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. */
@@ -1355,20 +1400,23 @@ static int mpeg1_decode_picture(AVCodecContext *avctx, const uint8_t *buf,
return -1;
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 -1;
+ 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 -1;
+ f_code += !f_code;
s->mpeg_f_code[1][0] = f_code;
s->mpeg_f_code[1][1] = f_code;
}
@@ -1416,8 +1464,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);
}
@@ -1492,7 +1540,7 @@ static int load_matrix(MpegEncContext *s, uint16_t matrix0[64],
return -1;
}
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;
@@ -1538,6 +1586,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);
@@ -1550,32 +1603,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 +1716,6 @@ static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size)
return -1;
}
-#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,14 +1732,17 @@ 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;
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;
@@ -1735,8 +1755,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;
@@ -1766,7 +1786,7 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y,
return -1;
}
- 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);
@@ -1806,13 +1826,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 (mpeg_decode_mb(s, s->block) < 0)
return -1;
@@ -1844,22 +1860,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);
@@ -1877,15 +1893,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 -1;
} 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);
}
@@ -1951,6 +1988,10 @@ 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;
av_dlog(s, "y %d %d %d %d\n", s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y);
return 0;
@@ -1992,7 +2033,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)
@@ -2018,15 +2062,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);
@@ -2037,7 +2074,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++;
@@ -2047,7 +2085,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);
}
}
@@ -2072,13 +2111,13 @@ 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 -1;
}
s->frame_rate_index = get_bits(&s->gb, 4);
@@ -2124,17 +2163,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->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;
}
@@ -2149,6 +2190,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;
@@ -2156,14 +2198,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 (ff_mpv_common_init(s) < 0)
@@ -2184,9 +2219,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;
@@ -2249,9 +2290,23 @@ 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 (buf_size > 29){
+ int i;
+ for(i=0; i<20; i++)
+ if (!memcmp(p+i, "\0TMPGEXS\0", 9)){
+ s->tmpgexs= 1;
+ }
+
+/* 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");*/
+ }
+
/* we parse the DTG active format information */
if (buf_end - p >= 5 &&
p[0] == 'D' && p[1] == 'T' && p[2] == 'G' && p[3] == '1') {
@@ -2310,32 +2365,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,
@@ -2347,6 +2396,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 */
@@ -2358,6 +2408,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,
@@ -2366,6 +2417,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;
@@ -2376,13 +2431,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 */
@@ -2390,7 +2449,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);
@@ -2400,12 +2460,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;
@@ -2489,14 +2561,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);
@@ -2507,13 +2615,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->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
@@ -2560,12 +2668,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];
@@ -2608,11 +2722,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;
- av_dlog(avctx, "fill_buffer\n");
if (buf_size == 0 || (buf_size == 4 && AV_RB32(buf) == SEQ_END_CODE)) {
/* special case for last picture */
@@ -2637,20 +2751,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)
@@ -2658,7 +2785,6 @@ static void flush(AVCodecContext *avctx)
Mpeg1Context *s = avctx->priv_data;
s->sync = 0;
- s->closed_gop = 0;
ff_mpeg_flush(avctx);
}
@@ -2698,6 +2824,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)
};
@@ -2714,9 +2841,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)
@@ -2752,3 +2895,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 5fc5e36..9795b7f 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->flags & CODEC_FLAG_CLOSED_GOP));
+ put_bits(&s->pb, 1, !!(s->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],
@@ -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)
@@ -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/mpeg4audio.c b/libavcodec/mpeg4audio.c
index 0fb9b96..68448e6 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,7 +84,8 @@ int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf,
GetBitContext gb;
int specific_config_bitindex;
- init_get_bits(&gb, buf, bit_size);
+ if (bit_size <= 0 || init_get_bits(&gb, buf, bit_size) < 0)
+ return AVERROR_INVALIDDATA;
c->object_type = get_object_type(&gb);
c->sample_rate = get_sample_rate(&gb, &c->sampling_index);
c->chan_config = get_bits(&gb, 4);
@@ -123,8 +126,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 e71122d..0f41045 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
*/
diff --git a/libavcodec/mpeg4data.h b/libavcodec/mpeg4data.h
index 87bb539..1ac5840 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 84fa26b..38ed5af 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 22d6d59..e83692c 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
*/
@@ -84,6 +84,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 +93,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 +150,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,7 +227,7 @@ static inline int ff_mpeg4_pred_dc(MpegEncContext *s, int n, int level,
} else {
level += pred;
ret = level;
- if (s->err_recognition & AV_EF_BITSTREAM) {
+ if (s->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);
diff --git a/libavcodec/mpeg4video_parser.c b/libavcodec/mpeg4video_parser.c
index 246bb9c..b7718f6 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 < 0)
+ 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 0f56e7f..50f8b44 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 ff37826..846b691 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;
@@ -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->err_recognition & AV_EF_BITSTREAM) {
+ if (s->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->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->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->err_recognition & AV_EF_BITSTREAM) {
+ if (s->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);
}
+ tprintf(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);
+ skip_bits1(gb);
+ 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) {
@@ -1707,7 +1745,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb)
}
} 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;
}
@@ -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 &&
@@ -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;
}
@@ -2019,8 +2078,9 @@ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb)
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");
+ av_log(s->avctx, AV_LOG_INFO, "Video uses a non-standard and "
+ "wasteful way to store B-frames ('packed B-frames'). "
+ "Consider using a tool like VirtualDub or avidemux to fix it.\n");
ctx->showed_packed_warning = 1;
}
}
@@ -2046,6 +2106,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->stream_codec_tag == AV_RL32("XVID") ||
s->codec_tag == AV_RL32("XVID") ||
@@ -2066,8 +2134,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;
}
@@ -2076,6 +2225,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 &&
@@ -2115,6 +2265,10 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb)
av_log(s->avctx, AV_LOG_ERROR,
"my guess is %d bits ;)\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)
@@ -2155,12 +2309,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 */
@@ -2169,6 +2333,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 &&
@@ -2205,6 +2372,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 -1;
+ }
ctx->intra_dc_threshold = ff_mpeg4_dc_threshold[get_bits(gb, 3)];
if (!s->progressive_sequence) {
s->top_field_first = get_bits1(gb);
@@ -2250,6 +2421,7 @@ 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");
+ s->f_code = 1;
return -1; // makes no sense to continue, as there is nothing left from the image then
}
} else
@@ -2257,22 +2429,31 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb)
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 -1; // 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) {
@@ -2335,8 +2516,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
@@ -2430,64 +2611,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)
@@ -2495,33 +2645,31 @@ 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,
+ 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,
@@ -2545,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;
}
@@ -2560,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 =
@@ -2570,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 */
@@ -2621,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 = {
@@ -2636,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 e9bc85f..5751432a 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->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 7a1b6b2..3d90582 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 1968184..bd74fbb 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 1a83635..cba5299 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 b556801..1591a17 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 58ea452..79dbf63 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;
@@ -63,27 +64,30 @@ static int mpegaudio_parse(AVCodecParserContext *s1,
}else{
while(i<buf_size){
int ret, sr, channels, bit_rate, frame_size;
+ enum AVCodecID codec_id;
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);
}
}
break;
diff --git a/libavcodec/mpegaudio_tablegen.c b/libavcodec/mpegaudio_tablegen.c
index b4c240b..90c9de4 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 8a3e51a..86b2cd3 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 009a02a..0569281 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 2b8ff65..29a2658 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 6f21b0c..904c885 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 3a76055..35f07fa 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"
diff --git a/libavcodec/mpegaudiodec_template.c b/libavcodec/mpegaudiodec_template.c
index e9c7850..1c97d72 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"
@@ -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);
@@ -386,7 +392,7 @@ static av_cold void decode_init_static(void)
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);
@@ -808,7 +814,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 +828,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 +943,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 +970,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,7 +1137,7 @@ found2:
/* ms stereo ONLY */
/* NOTE: the 1/sqrt(2) normalization factor is included in the
global gain */
-#if CONFIG_FLOAT
+#if USE_FLOATS
s->fdsp.butterflies_float(g0->sb_hybrid, g1->sb_hybrid, 576);
#else
tab0 = g0->sb_hybrid;
@@ -1146,7 +1152,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 +1209,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 +1379,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 */
av_dlog(s->avctx, "seekback:%d, lastbuf:%d\n",
main_data_begin, s->last_buf_size);
@@ -1372,7 +1389,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 +1571,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 +1585,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 +1593,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 +1642,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 +1675,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 +1705,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 +1724,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 +1819,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 +1913,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 +1928,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 +1936,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 +1955,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 +1969,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 25e7319..5db1957 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
*/
@@ -112,7 +112,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,16 +125,16 @@ 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:
- avctx->codec_id = AV_CODEC_ID_MP3;
+ *codec_id = AV_CODEC_ID_MP3;
if (s->lsf)
*frame_size = 576;
else
@@ -147,3 +147,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 764e8ab..444b85f 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 1221657..accd12b 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 58ea1d1..5fe3444 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 909c652..a722a2f 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 5cf86b8..4550de9 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 3c49a56..83c9d66 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 2d8d53e..c45b136 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 621bbd4..62454ca 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_fixed.c b/libavcodec/mpegaudioenc_fixed.c
new file mode 100644
index 0000000..022b6fe
--- /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 0000000..4d4ab2d
--- /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.c b/libavcodec/mpegaudioenc_template.c
index 4e074a5..1bf9471 100644
--- a/libavcodec/mpegaudioenc.c
+++ b/libavcodec/mpegaudioenc_template.c
@@ -2,20 +2,20 @@
* The simplest mpeg audio layer 2 encoder
* 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
*/
@@ -64,7 +64,12 @@ typedef struct MpegAudioContext {
int16_t filter_bank[512];
int scale_factor_table[64];
unsigned char scale_diff_table[128];
+#if USE_FLOATS
float scale_factor_inv_table[64];
+#else
+ int8_t scale_factor_shift[64];
+ unsigned short scale_factor_mult[64];
+#endif
unsigned short total_quant_bits[17]; /* total number of bits per allocation group */
} MpegAudioContext;
@@ -103,10 +108,15 @@ static av_cold int MPA_encode_init(AVCodecContext *avctx)
s->freq_index = i;
/* encoding bitrate & frequency */
- for(i=0;i<15;i++) {
+ 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);
@@ -149,11 +159,17 @@ static av_cold int MPA_encode_init(AVCodecContext *avctx)
}
for(i=0;i<64;i++) {
- v = (int)(pow(2.0, (3 - i) / 3.0) * (1 << 20));
+ v = (int)(exp2((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);
+#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;
@@ -397,7 +413,7 @@ static void compute_scale_factors(MpegAudioContext *s,
av_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);
+ av_assert2(index >=0 && index <= 63);
sf[i] = index;
}
@@ -459,7 +475,7 @@ static void compute_scale_factors(MpegAudioContext *s,
sf[1] = sf[2] = sf[0];
break;
default:
- assert(0); //cannot happen
+ av_assert2(0); //cannot happen
code = 0; /* kill warning */
}
@@ -579,7 +595,7 @@ static void compute_bit_allocation(MpegAudioContext *s,
}
}
*padding = max_frame_size - current_frame_size;
- assert(*padding >= 0);
+ av_assert0(*padding >= 0);
}
/*
@@ -668,14 +684,36 @@ static void encode_frame(MpegAudioContext *s,
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 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;
- assert(q[m] >= 0 && q[m] < steps);
+ av_assert2(q[m] >= 0 && q[m] < steps);
}
bits = ff_mpa_quant_bits[qindex];
if (bits < 0) {
@@ -725,10 +763,8 @@ static int MPA_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
}
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");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, MPA_MAX_CODED_FRAME_SIZE)) < 0)
return ret;
- }
init_put_bits(&s->pb, avpkt->data, avpkt->size);
@@ -743,25 +779,7 @@ static int MPA_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
}
static const AVCodecDefault mp2_defaults[] = {
- { "b", "384000" },
+ { "b", "0" },
{ 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/mpegaudiotab.h b/libavcodec/mpegaudiotab.h
index d30ef1b..42d42d8 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 bc430f0..62cc36a 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 9446724..6d59c22 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 da9f24f..f84557b 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;
@@ -370,19 +360,46 @@ static void mpeg_er_decode_mb(void *opaque, int ref, int mv_dir, int mv_type,
s->dest[1] = s->current_picture.f->data[1] + (s->mb_y * (16 >> s->chroma_y_shift) * s->uvlinesize) + s->mb_x * (16 >> s->chroma_x_shift);
s->dest[2] = s->current_picture.f->data[2] + (s->mb_y * (16 >> s->chroma_y_shift) * s->uvlinesize) + s->mb_x * (16 >> s->chroma_x_shift);
- assert(ref == 0);
+ if (ref)
+ av_log(s->avctx, AV_LOG_DEBUG, "Interlaced error concealment is not fully implemented\n");
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_me_cmp_init(&s->mecc, s->avctx);
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;
@@ -395,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)
@@ -425,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;
@@ -534,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);
@@ -570,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;
@@ -582,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;
}
@@ -618,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;
@@ -727,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;
}
@@ -784,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 =
@@ -902,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) {
@@ -915,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;
@@ -937,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, &s->picture[i]);
if (s1->picture[i].f->buf[0] &&
@@ -947,7 +1003,7 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst,
#define UPDATE_PICTURE(pic)\
do {\
ff_mpeg_unref_picture(s, &s->pic);\
- if (s1->pic.f->buf[0])\
+ if (s1->pic.f && s1->pic.f->buf[0])\
ret = ff_mpeg_ref_picture(s, &s->pic, &s1->pic);\
else\
ret = update_picture_tables(&s->pic, &s1->pic);\
@@ -966,6 +1022,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,
@@ -1004,7 +1061,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
@@ -1054,6 +1110,22 @@ 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;
+ s->flags = avctx->flags;
+ s->flags2 = avctx->flags2;
+
+ /* convert fourcc to upper case */
+ s->codec_tag = avpriv_toupper4(avctx->codec_tag);
+
+ s->stream_codec_tag = avpriv_toupper4(avctx->stream_codec_tag);
+}
+
static int init_er(MpegEncContext *s)
{
ERContext *er = &s->er;
@@ -1104,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;
@@ -1122,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);
@@ -1182,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;
@@ -1276,14 +1332,10 @@ av_cold int ff_mpv_common_init(MpegEncContext *s)
s->flags2 = s->avctx->flags2;
/* set chroma shifts */
- av_pix_fmt_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);
+ avcodec_get_chroma_sub_sample(s->avctx->pix_fmt,
+ &s->chroma_x_shift,
+ &s->chroma_y_shift);
- s->stream_codec_tag = avpriv_toupper4(s->avctx->stream_codec_tag);
FF_ALLOCZ_OR_GOTO(s->avctx, s->picture,
MAX_PICTURE_COUNT * sizeof(Picture), fail);
@@ -1309,17 +1361,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));
@@ -1341,7 +1391,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:
@@ -1354,7 +1404,7 @@ av_cold int ff_mpv_common_init(MpegEncContext *s)
* Is used during resolution changes to avoid a full reinitialization of the
* codec.
*/
-static int free_context_frame(MpegEncContext *s)
+static void free_context_frame(MpegEncContext *s)
{
int i, j, k;
@@ -1396,18 +1446,20 @@ static int 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);
s->linesize = s->uvlinesize = 0;
-
- return 0;
}
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]);
@@ -1418,8 +1470,7 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s)
} else
free_duplicate_context(s);
- if ((err = free_context_frame(s)) < 0)
- return err;
+ free_context_frame(s);
if (s->picture)
for (i = 0; i < MAX_PICTURE_COUNT; i++) {
@@ -1437,8 +1488,8 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s)
s->mb_height = (s->height + 15) / 16;
if ((s->width || s->height) &&
- av_image_check_size(s->width, s->height, 0, s->avctx))
- return AVERROR_INVALIDDATA;
+ (err = av_image_check_size(s->width, s->height, 0, s->avctx)) < 0)
+ goto fail;
if ((err = init_context_frame(s)))
goto fail;
@@ -1454,7 +1505,7 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s)
}
for (i = 0; i < nb_slices; i++) {
- if (init_duplicate_context(s->thread_context[i]) < 0)
+ if ((err = init_duplicate_context(s->thread_context[i])) < 0)
goto fail;
s->thread_context[i]->start_mb_y =
(s->mb_height * (i) + nb_slices / 2) / nb_slices;
@@ -1462,7 +1513,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;
@@ -1579,9 +1631,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;
@@ -1591,9 +1647,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,6 +1688,8 @@ static void release_unused_pictures(MpegEncContext *s)
static inline int pic_is_unused(MpegEncContext *s, Picture *pic)
{
+ if (pic == s->last_picture_ptr)
+ return 0;
if (!pic->f->buf[0])
return 1;
if (pic->needs_realloc && !(pic->reference & DELAYED_PIC_REF))
@@ -1645,7 +1703,7 @@ static int find_unused_picture(MpegEncContext *s, int shared)
if (shared) {
for (i = 0; i < MAX_PICTURE_COUNT; i++) {
- if (!s->picture[i].f->buf[0])
+ if (!s->picture[i].f->buf[0] && &s->picture[i] != s->last_picture_ptr)
return i;
}
} else {
@@ -1655,7 +1713,21 @@ static int find_unused_picture(MpegEncContext *s, int shared)
}
}
- return AVERROR_INVALIDDATA;
+ av_log(s->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(MpegEncContext *s, int shared)
@@ -1672,6 +1744,22 @@ int ff_find_unused_picture(MpegEncContext *s, 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.
@@ -1682,6 +1770,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 &&
@@ -1770,11 +1863,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 */
@@ -1786,21 +1882,30 @@ 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);
+ 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);
@@ -1816,7 +1921,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;
@@ -1826,6 +1932,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, &s->last_picture);
if (s->last_picture_ptr->f->buf[0] &&
@@ -1841,12 +1951,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;
@@ -1877,12 +1983,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;
}
@@ -1890,119 +1993,934 @@ 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)
+{
+ if (dst_x == src_x && dst_y == src_y)
+ return 0;
+ 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)
+ 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[x + y * mb_stride];
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
+ }
+ }
+ 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->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->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->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);
}
}
@@ -2116,18 +3034,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 */
@@ -2158,15 +3073,17 @@ FF_ENABLE_DEPRECATION_WARNINGS
else if (!is_mpeg12 && (s->h263_pred || s->h263_aic))
s->mbintra_table[mb_xy]=1;
- if ((s->flags&CODEC_FLAG_PSNR) || !(s->encoding && (s->intra_only || s->pict_type==AV_PICTURE_TYPE_B) && s->avctx->mb_decision != FF_MB_DECISION_RD)) { //FIXME precalc
+ if ( (s->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;
int dct_linesize, dct_offset;
op_pixels_func (*op_pix)[4];
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 */
@@ -2175,7 +3092,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;
@@ -2215,19 +3132,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);
+ }
}
}
@@ -2273,17 +3202,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
@@ -2325,17 +3254,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
@@ -2354,23 +3283,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;
@@ -2394,7 +3325,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));
}
}
}
@@ -2444,6 +3375,7 @@ void ff_mpeg_flush(AVCodecContext *avctx){
ff_mpeg_unref_picture(s, &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 63052a9..cadf6f2 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];
@@ -319,7 +325,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) */
@@ -338,11 +344,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
@@ -352,6 +361,7 @@ typedef struct MpegEncContext {
BlockDSPContext bdsp;
FDCTDSPContext fdsp;
+ H264ChromaContext h264chroma;
HpelDSPContext hdsp;
IDCTDSPContext idsp;
MECmpContext mecc;
@@ -438,13 +448,15 @@ typedef struct MpegEncContext {
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 */
@@ -455,6 +467,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
@@ -487,6 +500,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
@@ -537,6 +551,7 @@ typedef struct MpegEncContext {
/* MJPEG specific */
struct MJpegContext *mjpeg_ctx;
+ int esc_pos;
/* MSMPEG4 specific */
int mv_table_index;
@@ -578,11 +593,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;
@@ -596,7 +613,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
@@ -632,7 +654,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;
@@ -672,7 +694,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" },\
@@ -721,8 +745,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);
@@ -731,6 +758,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);
@@ -749,7 +777,15 @@ int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt,
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(MpegEncContext *s, int shared);
void ff_denoise_dct(MpegEncContext *s, int16_t *block);
@@ -758,6 +794,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);
@@ -784,7 +821,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;
@@ -877,4 +914,5 @@ int ff_mpeg_ref_picture(MpegEncContext *s, Picture *dst, Picture *src);
void ff_mpeg_unref_picture(MpegEncContext *s, 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 8775eac..27153cf 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;
@@ -305,6 +332,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;
@@ -313,6 +341,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 precission
+ 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) {
@@ -346,9 +392,33 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
s->loop_filter = !!(s->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) * 112L / 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 - 15000000L) * (760-320) / (38400000 - 15000000);
+ } else if(avctx->rc_max_rate >= 2000000) {
+ avctx->rc_buffer_size = 80 + (avctx->rc_max_rate - 2000000L) * (320- 80) / (15000000 - 2000000);
+ } else if(avctx->rc_max_rate >= 384000) {
+ avctx->rc_buffer_size = 40 + (avctx->rc_max_rate - 384000L) * ( 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;
}
@@ -363,7 +433,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;
}
@@ -384,9 +454,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 &&
@@ -425,18 +495,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->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");
@@ -444,7 +570,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;
@@ -494,6 +621,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");
@@ -502,14 +630,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;
@@ -529,8 +660,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;
@@ -540,11 +670,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,
@@ -569,6 +706,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 ||
@@ -593,13 +731,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;
}
@@ -704,9 +842,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);
@@ -723,8 +858,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);
@@ -736,15 +873,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;
@@ -891,6 +1020,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 +1088,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 {
@@ -988,8 +1120,14 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg)
pic_arg->linesize[1] != s->uvlinesize ||
pic_arg->linesize[2] != s->uvlinesize)
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;
- av_dlog(s->avctx, "%d %d %td %td\n", pic_arg->linesize[0],
+ av_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, direct);
@@ -1029,6 +1167,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;
@@ -1036,12 +1180,21 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg)
if (src_stride == dst_stride)
memcpy(dst, src, src_stride * h);
else {
- while (h--) {
- memcpy(dst, src, w);
- dst += dst_stride;
+ int h2 = h;
+ uint8_t *dst2 = dst;
+ while (h2--) {
+ memcpy(dst2, src, w);
+ dst2 += dst_stride;
src += src_stride;
}
}
+ if ((s->width & 15) || (s->height & (vpad-1))) {
+ s->mpvencdsp.draw_edges(dst, dst_stride,
+ w, h,
+ 16>>h_shift,
+ vpad>>v_shift,
+ EDGE_BOTTOM);
+ }
}
}
}
@@ -1078,19 +1231,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;
@@ -1123,7 +1280,7 @@ static int estimate_best_b_count(MpegEncContext *s)
int64_t best_rd = INT64_MAX;
int best_b_count = -1;
- assert(scale >= 0 && scale <= 3);
+ av_assert0(scale >= 0 && scale <= 3);
//emms_c();
//s->next_picture_ptr->quality;
@@ -1153,29 +1310,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);
}
@@ -1238,6 +1397,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];
@@ -1247,19 +1419,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->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;
@@ -1408,25 +1567,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,
@@ -1441,14 +1601,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, &s->picture[i]);
- }
- }
-
s->avctx->coded_frame = s->current_picture_ptr->f;
}
@@ -1539,7 +1691,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);
}
@@ -1564,8 +1716,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,
@@ -1590,7 +1745,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;
@@ -1610,7 +1771,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) {
@@ -1640,17 +1801,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->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];
}
@@ -1662,6 +1826,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) {
@@ -1716,7 +1881,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;
@@ -1744,7 +1909,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, &s->picture[i]);
+ }
+
+ av_assert1((s->frame_bits & 7) == 0);
pkt->size = s->frame_bits / 8;
*got_packet = !!pkt->size;
@@ -1868,15 +2040,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;
@@ -1918,27 +2092,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) {
@@ -1959,8 +2137,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;
}
}
@@ -1977,11 +2157,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 {
@@ -2037,6 +2222,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;
@@ -2058,10 +2244,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 */
@@ -2083,12 +2269,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;
}
@@ -2110,17 +2296,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]) {
@@ -2166,6 +2352,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
@@ -2216,18 +2408,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){
@@ -2318,7 +2512,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);
@@ -2364,7 +2558,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;
}
@@ -2414,6 +2608,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++) {
@@ -2440,6 +2636,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;
@@ -2467,7 +2665,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 +2729,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);
@@ -2552,7 +2752,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));
@@ -2590,6 +2795,29 @@ static int encode_thread(AVCodecContext *c, void *arg){
int dmin= INT_MAX;
int dir;
+ if ( s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < MAX_MB_BYTES
+ && s->slice_context_count == 1
+ && s->pb.buf == s->avctx->internal->byte_buffer) {
+ int new_size = s->avctx->internal->byte_buffer_size
+ + s->avctx->internal->byte_buffer_size/4
+ + s->mb_width*MAX_MB_BYTES;
+ 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, new_size);
+ if (new_buffer) {
+ 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) < MAX_MB_BYTES){
av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
return -1;
@@ -2597,7 +2825,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;
}
}
@@ -2623,6 +2851,9 @@ static int encode_thread(AVCodecContext *c, void *arg){
if(s->start_mb_y == mb_y && mb_y > 0 && mb_x==0) is_gob_start=1;
switch(s->codec_id){
+ case AV_CODEC_ID_H261:
+ is_gob_start=0;//FIXME
+ break;
case AV_CODEC_ID_H263:
case AV_CODEC_ID_H263P:
if(!s->h263_slice_structured)
@@ -2633,6 +2864,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){
@@ -2644,7 +2878,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) {
@@ -2851,8 +3085,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;
@@ -2870,7 +3105,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);
@@ -2880,7 +3115,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);
@@ -3110,13 +3345,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);
}
@@ -3169,9 +3404,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++){
@@ -3224,7 +3459,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){
@@ -3280,6 +3515,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);
@@ -3322,7 +3564,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;
- av_dlog(s, "Scene change detected, encoding as I Frame %d %d\n",
+ if(s->msmpeg4_version >= 3)
+ s->no_rounding=1;
+ av_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);
}
@@ -3387,17 +3631,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;
}
@@ -3410,12 +3687,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)
@@ -3442,7 +3720,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;
@@ -3533,7 +3811,7 @@ 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];
+ qmat = n < 4 ? s->q_intra_matrix[qscale] : s->q_chroma_intra_matrix[qscale];
if(s->mpeg_quant || s->out_format == FMT_MPEG1)
bias= 1<<(QMAT_SHIFT-1);
length = s->intra_ac_vlc_length;
@@ -3579,7 +3857,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;
@@ -3613,9 +3891,9 @@ 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{ //MPEG1
j = s->idsp.idct_permutation[scantable[i]]; // FIXME: optimize
@@ -3644,7 +3922,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;
@@ -3670,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 + score_tab[i-run];
@@ -3703,7 +3981,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];
@@ -3736,7 +4014,7 @@ 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;
@@ -3762,7 +4040,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;
@@ -3878,8 +4156,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);
@@ -3945,7 +4223,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;
@@ -3989,7 +4267,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){
@@ -4017,7 +4295,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] ];
@@ -4050,7 +4328,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;
@@ -4079,7 +4357,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);
@@ -4111,7 +4389,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
@@ -4139,7 +4417,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;
@@ -4202,7 +4480,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 f33db34..e7a585d 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"
@@ -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)) {
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;
}
@@ -308,7 +307,7 @@ void mpeg_motion_internal(MpegEncContext *s,
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)) {
+ (unsigned)src_y > FFMAX( v_edge_pos - (motion_y & 1) - h , 0)) {
if (is_mpeg12 ||
s->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
s->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
@@ -324,19 +323,20 @@ void mpeg_motion_internal(MpegEncContext *s,
s->h_edge_pos, s->v_edge_pos);
ptr_y = s->edge_emu_buffer;
if (!CONFIG_GRAY || !(s->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;
}
}
@@ -394,7 +394,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 +469,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]) {
@@ -537,7 +537,7 @@ static inline void qpel_motion(MpegEncContext *s,
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)) {
+ (unsigned)src_y > FFMAX( v_edge_pos - (motion_y & 3) - h, 0)) {
s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr_y,
s->linesize, s->linesize,
17, 17 + field_based,
@@ -545,19 +545,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->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;
}
}
@@ -671,7 +672,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]);
@@ -898,8 +899,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 +914,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 +944,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 +965,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 d657818..0159421 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,8 @@ 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 bit_rate = 0;
+ int vbv_delay = 0;
//FIXME replace the crap with get_bits()
s->repeat_pict = 0;
@@ -55,6 +57,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:
@@ -67,8 +71,9 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s,
}
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:
@@ -87,12 +92,13 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s,
pc->width |=(horiz_size_ext << 12);
pc->height |=( vert_size_ext << 12);
- avctx->bit_rate += (bit_rate_ext << 18) * 400;
+ 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;
+ 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 +144,16 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s,
}
}
the_end: ;
+ 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 +183,7 @@ static int mpegvideo_parse(AVCodecParserContext *s,
function should be negligible for uncorrupted streams */
mpegvideo_extract_headers(s, avctx, buf, buf_size);
av_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 +195,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 fb2dd80..d4631cb 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 915a844..a58e45a 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 b0f45db..293e254 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 109bbe5..860c2d8 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 91a292a..e12f4c6 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 0000000..ca95dc8
--- /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 0144581..f2d1e3b 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 a65433e..c0827bd 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 889763a..3625069 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 0000000..97d352b
--- /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 be5062a..4c4ddb4 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 adbda9a..b2a1a62 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 95b5c93..7300af3 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 0a8ecd9..db77ce1 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 cf291af..8eb07e9 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 ca2dac1..24a10d9 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 191f81a..94ea3c2 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
*/
@@ -26,6 +26,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"
@@ -102,6 +103,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) {
@@ -115,6 +117,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;
}
}
@@ -163,6 +166,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);
@@ -172,6 +176,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]);
@@ -281,18 +286,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]);
}
@@ -362,6 +368,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){
@@ -579,8 +586,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) {
@@ -590,6 +600,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;
}
@@ -646,7 +657,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];
@@ -832,8 +842,9 @@ int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block,
i-= 192;
if(i&(~63)){
const int left= get_bits_left(&s->gb);
- if(((i+192 == 64 && level/qmul==-1) || !(s->err_recognition&AV_EF_BITSTREAM)) && left>=0){
+ if(((i+192 == 64 && level/qmul==-1) || !(s->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);
@@ -910,6 +921,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
@@ -926,6 +938,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
@@ -942,6 +955,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
@@ -958,6 +972,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 45ef208..e7f51db 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 "mpeg4video.h"
#include "msmpeg4.h"
@@ -150,8 +149,8 @@ av_cold void 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;
@@ -274,14 +273,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,
@@ -494,7 +494,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 4b39c92..260ad80 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 af2a247..4d3da5b 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
*/
@@ -138,7 +138,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 +156,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 +171,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 +184,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 +205,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 a594de3..3f66636 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 a67a942..6bb524b 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)
diff --git a/libavcodec/mss12.c b/libavcodec/mss12.c
index d4b621f..7d54d29 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,7 +652,7 @@ 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);
diff --git a/libavcodec/mss12.h b/libavcodec/mss12.h
index 5b1fee8..f953167 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 d71d308..4d53f8a 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)
{
@@ -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 aa13577..c5fc1f8 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 61c3a04..7368abb 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 9a0b1fb..075685b 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 11abb2d..0397add 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 b2cc550..2f9827d 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 9198acc..c5b8e07 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,7 @@ 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);
+ init_get_bits8(&gb, buf + HEADER_SIZE, (buf_size - HEADER_SIZE));
mb_width = FFALIGN(width, 16) >> 4;
mb_height = FFALIGN(height, 16) >> 4;
diff --git a/libavcodec/msvideo1.c b/libavcodec/msvideo1.c
index 7fd8633..88397be 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 0000000..5e6cdfa
--- /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 7cc0329..69f0ee2 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 bfaae34..fbd4767 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,4 +344,5 @@ AVCodec ff_mxpeg_decoder = {
.close = mxpeg_decode_end,
.decode = mxpeg_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
};
diff --git a/libavcodec/nellymoserdec.c b/libavcodec/nellymoserdec.c
index 3b9b77c..ef16fd6 100644
--- a/libavcodec/nellymoserdec.c
+++ b/libavcodec/nellymoserdec.c
@@ -142,16 +142,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);
@@ -163,13 +166,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++) {
diff --git a/libavcodec/nellymoserenc.c b/libavcodec/nellymoserenc.c
index 98c2b39..78f1092 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:
@@ -138,8 +138,8 @@ 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);
@@ -173,9 +173,9 @@ static av_cold int encode_init(AVCodecContext *avctx)
avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
/* 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 +231,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;
}
@@ -392,10 +392,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 fe952ae..a96ae51 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 3e552e2..4f609de 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,7 +32,12 @@ 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++){
@@ -44,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 c31ff11..048ad6f 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/old_codec_ids.h b/libavcodec/old_codec_ids.h
new file mode 100644
index 0000000..c7aa0e0
--- /dev/null
+++ b/libavcodec/old_codec_ids.h
@@ -0,0 +1,397 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_OLD_CODEC_IDS_H
+#define AVCODEC_OLD_CODEC_IDS_H
+
+/*
+ * This header exists to prevent new codec IDs from being accidentally added to
+ * the deprecated list.
+ * Do not include it directly. It will be removed on next major bump
+ *
+ * Do not add new items to this list. Use the AVCodecID enum instead.
+ */
+
+ CODEC_ID_NONE = AV_CODEC_ID_NONE,
+
+ /* video codecs */
+ CODEC_ID_MPEG1VIDEO,
+ CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding
+#if FF_API_XVMC
+ CODEC_ID_MPEG2VIDEO_XVMC,
+#endif
+ CODEC_ID_H261,
+ CODEC_ID_H263,
+ CODEC_ID_RV10,
+ CODEC_ID_RV20,
+ CODEC_ID_MJPEG,
+ CODEC_ID_MJPEGB,
+ CODEC_ID_LJPEG,
+ CODEC_ID_SP5X,
+ CODEC_ID_JPEGLS,
+ CODEC_ID_MPEG4,
+ CODEC_ID_RAWVIDEO,
+ CODEC_ID_MSMPEG4V1,
+ CODEC_ID_MSMPEG4V2,
+ CODEC_ID_MSMPEG4V3,
+ CODEC_ID_WMV1,
+ CODEC_ID_WMV2,
+ CODEC_ID_H263P,
+ CODEC_ID_H263I,
+ CODEC_ID_FLV1,
+ CODEC_ID_SVQ1,
+ CODEC_ID_SVQ3,
+ CODEC_ID_DVVIDEO,
+ CODEC_ID_HUFFYUV,
+ CODEC_ID_CYUV,
+ CODEC_ID_H264,
+ CODEC_ID_INDEO3,
+ CODEC_ID_VP3,
+ CODEC_ID_THEORA,
+ CODEC_ID_ASV1,
+ CODEC_ID_ASV2,
+ CODEC_ID_FFV1,
+ CODEC_ID_4XM,
+ CODEC_ID_VCR1,
+ CODEC_ID_CLJR,
+ CODEC_ID_MDEC,
+ CODEC_ID_ROQ,
+ CODEC_ID_INTERPLAY_VIDEO,
+ CODEC_ID_XAN_WC3,
+ CODEC_ID_XAN_WC4,
+ CODEC_ID_RPZA,
+ CODEC_ID_CINEPAK,
+ CODEC_ID_WS_VQA,
+ CODEC_ID_MSRLE,
+ CODEC_ID_MSVIDEO1,
+ CODEC_ID_IDCIN,
+ CODEC_ID_8BPS,
+ CODEC_ID_SMC,
+ CODEC_ID_FLIC,
+ CODEC_ID_TRUEMOTION1,
+ CODEC_ID_VMDVIDEO,
+ CODEC_ID_MSZH,
+ CODEC_ID_ZLIB,
+ CODEC_ID_QTRLE,
+ CODEC_ID_TSCC,
+ CODEC_ID_ULTI,
+ CODEC_ID_QDRAW,
+ CODEC_ID_VIXL,
+ CODEC_ID_QPEG,
+ CODEC_ID_PNG,
+ CODEC_ID_PPM,
+ CODEC_ID_PBM,
+ CODEC_ID_PGM,
+ CODEC_ID_PGMYUV,
+ CODEC_ID_PAM,
+ CODEC_ID_FFVHUFF,
+ CODEC_ID_RV30,
+ CODEC_ID_RV40,
+ CODEC_ID_VC1,
+ CODEC_ID_WMV3,
+ CODEC_ID_LOCO,
+ CODEC_ID_WNV1,
+ CODEC_ID_AASC,
+ CODEC_ID_INDEO2,
+ CODEC_ID_FRAPS,
+ CODEC_ID_TRUEMOTION2,
+ CODEC_ID_BMP,
+ CODEC_ID_CSCD,
+ CODEC_ID_MMVIDEO,
+ CODEC_ID_ZMBV,
+ CODEC_ID_AVS,
+ CODEC_ID_SMACKVIDEO,
+ CODEC_ID_NUV,
+ CODEC_ID_KMVC,
+ CODEC_ID_FLASHSV,
+ CODEC_ID_CAVS,
+ CODEC_ID_JPEG2000,
+ CODEC_ID_VMNC,
+ CODEC_ID_VP5,
+ CODEC_ID_VP6,
+ CODEC_ID_VP6F,
+ CODEC_ID_TARGA,
+ CODEC_ID_DSICINVIDEO,
+ CODEC_ID_TIERTEXSEQVIDEO,
+ CODEC_ID_TIFF,
+ CODEC_ID_GIF,
+ CODEC_ID_DXA,
+ CODEC_ID_DNXHD,
+ CODEC_ID_THP,
+ CODEC_ID_SGI,
+ CODEC_ID_C93,
+ CODEC_ID_BETHSOFTVID,
+ CODEC_ID_PTX,
+ CODEC_ID_TXD,
+ CODEC_ID_VP6A,
+ CODEC_ID_AMV,
+ CODEC_ID_VB,
+ CODEC_ID_PCX,
+ CODEC_ID_SUNRAST,
+ CODEC_ID_INDEO4,
+ CODEC_ID_INDEO5,
+ CODEC_ID_MIMIC,
+ CODEC_ID_RL2,
+ CODEC_ID_ESCAPE124,
+ CODEC_ID_DIRAC,
+ CODEC_ID_BFI,
+ CODEC_ID_CMV,
+ CODEC_ID_MOTIONPIXELS,
+ CODEC_ID_TGV,
+ CODEC_ID_TGQ,
+ CODEC_ID_TQI,
+ CODEC_ID_AURA,
+ CODEC_ID_AURA2,
+ CODEC_ID_V210X,
+ CODEC_ID_TMV,
+ CODEC_ID_V210,
+ CODEC_ID_DPX,
+ CODEC_ID_MAD,
+ CODEC_ID_FRWU,
+ CODEC_ID_FLASHSV2,
+ CODEC_ID_CDGRAPHICS,
+ CODEC_ID_R210,
+ CODEC_ID_ANM,
+ CODEC_ID_BINKVIDEO,
+ CODEC_ID_IFF_ILBM,
+ CODEC_ID_IFF_BYTERUN1,
+ CODEC_ID_KGV1,
+ CODEC_ID_YOP,
+ CODEC_ID_VP8,
+ CODEC_ID_PICTOR,
+ CODEC_ID_ANSI,
+ CODEC_ID_A64_MULTI,
+ CODEC_ID_A64_MULTI5,
+ CODEC_ID_R10K,
+ CODEC_ID_MXPEG,
+ CODEC_ID_LAGARITH,
+ CODEC_ID_PRORES,
+ CODEC_ID_JV,
+ CODEC_ID_DFA,
+ CODEC_ID_WMV3IMAGE,
+ CODEC_ID_VC1IMAGE,
+ CODEC_ID_UTVIDEO,
+ CODEC_ID_BMV_VIDEO,
+ CODEC_ID_VBLE,
+ CODEC_ID_DXTORY,
+ CODEC_ID_V410,
+ CODEC_ID_XWD,
+ CODEC_ID_CDXL,
+ CODEC_ID_XBM,
+ CODEC_ID_ZEROCODEC,
+ CODEC_ID_MSS1,
+ CODEC_ID_MSA1,
+ CODEC_ID_TSCC2,
+ CODEC_ID_MTS2,
+ CODEC_ID_CLLC,
+ CODEC_ID_Y41P = MKBETAG('Y','4','1','P'),
+ CODEC_ID_ESCAPE130 = MKBETAG('E','1','3','0'),
+ CODEC_ID_EXR = MKBETAG('0','E','X','R'),
+ CODEC_ID_AVRP = MKBETAG('A','V','R','P'),
+
+ CODEC_ID_G2M = MKBETAG( 0 ,'G','2','M'),
+ CODEC_ID_AVUI = MKBETAG('A','V','U','I'),
+ CODEC_ID_AYUV = MKBETAG('A','Y','U','V'),
+ CODEC_ID_V308 = MKBETAG('V','3','0','8'),
+ CODEC_ID_V408 = MKBETAG('V','4','0','8'),
+ CODEC_ID_YUV4 = MKBETAG('Y','U','V','4'),
+ CODEC_ID_SANM = MKBETAG('S','A','N','M'),
+ CODEC_ID_PAF_VIDEO = MKBETAG('P','A','F','V'),
+ CODEC_ID_SNOW = AV_CODEC_ID_SNOW,
+
+ /* various PCM "codecs" */
+ CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
+ CODEC_ID_PCM_S16LE = 0x10000,
+ CODEC_ID_PCM_S16BE,
+ CODEC_ID_PCM_U16LE,
+ CODEC_ID_PCM_U16BE,
+ CODEC_ID_PCM_S8,
+ CODEC_ID_PCM_U8,
+ CODEC_ID_PCM_MULAW,
+ CODEC_ID_PCM_ALAW,
+ CODEC_ID_PCM_S32LE,
+ CODEC_ID_PCM_S32BE,
+ CODEC_ID_PCM_U32LE,
+ CODEC_ID_PCM_U32BE,
+ CODEC_ID_PCM_S24LE,
+ CODEC_ID_PCM_S24BE,
+ CODEC_ID_PCM_U24LE,
+ CODEC_ID_PCM_U24BE,
+ CODEC_ID_PCM_S24DAUD,
+ CODEC_ID_PCM_ZORK,
+ CODEC_ID_PCM_S16LE_PLANAR,
+ CODEC_ID_PCM_DVD,
+ CODEC_ID_PCM_F32BE,
+ CODEC_ID_PCM_F32LE,
+ CODEC_ID_PCM_F64BE,
+ CODEC_ID_PCM_F64LE,
+ CODEC_ID_PCM_BLURAY,
+ CODEC_ID_PCM_LXF,
+ CODEC_ID_S302M,
+ CODEC_ID_PCM_S8_PLANAR,
+
+ /* various ADPCM codecs */
+ CODEC_ID_ADPCM_IMA_QT = 0x11000,
+ CODEC_ID_ADPCM_IMA_WAV,
+ CODEC_ID_ADPCM_IMA_DK3,
+ CODEC_ID_ADPCM_IMA_DK4,
+ CODEC_ID_ADPCM_IMA_WS,
+ CODEC_ID_ADPCM_IMA_SMJPEG,
+ CODEC_ID_ADPCM_MS,
+ CODEC_ID_ADPCM_4XM,
+ CODEC_ID_ADPCM_XA,
+ CODEC_ID_ADPCM_ADX,
+ CODEC_ID_ADPCM_EA,
+ CODEC_ID_ADPCM_G726,
+ CODEC_ID_ADPCM_CT,
+ CODEC_ID_ADPCM_SWF,
+ CODEC_ID_ADPCM_YAMAHA,
+ CODEC_ID_ADPCM_SBPRO_4,
+ CODEC_ID_ADPCM_SBPRO_3,
+ CODEC_ID_ADPCM_SBPRO_2,
+ CODEC_ID_ADPCM_THP,
+ CODEC_ID_ADPCM_IMA_AMV,
+ CODEC_ID_ADPCM_EA_R1,
+ CODEC_ID_ADPCM_EA_R3,
+ CODEC_ID_ADPCM_EA_R2,
+ CODEC_ID_ADPCM_IMA_EA_SEAD,
+ CODEC_ID_ADPCM_IMA_EA_EACS,
+ CODEC_ID_ADPCM_EA_XAS,
+ CODEC_ID_ADPCM_EA_MAXIS_XA,
+ CODEC_ID_ADPCM_IMA_ISS,
+ CODEC_ID_ADPCM_G722,
+ CODEC_ID_ADPCM_IMA_APC,
+ CODEC_ID_VIMA = MKBETAG('V','I','M','A'),
+
+ /* AMR */
+ CODEC_ID_AMR_NB = 0x12000,
+ CODEC_ID_AMR_WB,
+
+ /* RealAudio codecs*/
+ CODEC_ID_RA_144 = 0x13000,
+ CODEC_ID_RA_288,
+
+ /* various DPCM codecs */
+ CODEC_ID_ROQ_DPCM = 0x14000,
+ CODEC_ID_INTERPLAY_DPCM,
+ CODEC_ID_XAN_DPCM,
+ CODEC_ID_SOL_DPCM,
+
+ /* audio codecs */
+ CODEC_ID_MP2 = 0x15000,
+ CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3
+ CODEC_ID_AAC,
+ CODEC_ID_AC3,
+ CODEC_ID_DTS,
+ CODEC_ID_VORBIS,
+ CODEC_ID_DVAUDIO,
+ CODEC_ID_WMAV1,
+ CODEC_ID_WMAV2,
+ CODEC_ID_MACE3,
+ CODEC_ID_MACE6,
+ CODEC_ID_VMDAUDIO,
+ CODEC_ID_FLAC,
+ CODEC_ID_MP3ADU,
+ CODEC_ID_MP3ON4,
+ CODEC_ID_SHORTEN,
+ CODEC_ID_ALAC,
+ CODEC_ID_WESTWOOD_SND1,
+ CODEC_ID_GSM, ///< as in Berlin toast format
+ CODEC_ID_QDM2,
+ CODEC_ID_COOK,
+ CODEC_ID_TRUESPEECH,
+ CODEC_ID_TTA,
+ CODEC_ID_SMACKAUDIO,
+ CODEC_ID_QCELP,
+ CODEC_ID_WAVPACK,
+ CODEC_ID_DSICINAUDIO,
+ CODEC_ID_IMC,
+ CODEC_ID_MUSEPACK7,
+ CODEC_ID_MLP,
+ CODEC_ID_GSM_MS, /* as found in WAV */
+ CODEC_ID_ATRAC3,
+ CODEC_ID_VOXWARE,
+ CODEC_ID_APE,
+ CODEC_ID_NELLYMOSER,
+ CODEC_ID_MUSEPACK8,
+ CODEC_ID_SPEEX,
+ CODEC_ID_WMAVOICE,
+ CODEC_ID_WMAPRO,
+ CODEC_ID_WMALOSSLESS,
+ CODEC_ID_ATRAC3P,
+ CODEC_ID_EAC3,
+ CODEC_ID_SIPR,
+ CODEC_ID_MP1,
+ CODEC_ID_TWINVQ,
+ CODEC_ID_TRUEHD,
+ CODEC_ID_MP4ALS,
+ CODEC_ID_ATRAC1,
+ CODEC_ID_BINKAUDIO_RDFT,
+ CODEC_ID_BINKAUDIO_DCT,
+ CODEC_ID_AAC_LATM,
+ CODEC_ID_QDMC,
+ CODEC_ID_CELT,
+ CODEC_ID_G723_1,
+ CODEC_ID_G729,
+ CODEC_ID_8SVX_EXP,
+ CODEC_ID_8SVX_FIB,
+ CODEC_ID_BMV_AUDIO,
+ CODEC_ID_RALF,
+ CODEC_ID_IAC,
+ CODEC_ID_ILBC,
+ CODEC_ID_FFWAVESYNTH = MKBETAG('F','F','W','S'),
+ CODEC_ID_SONIC = MKBETAG('S','O','N','C'),
+ CODEC_ID_SONIC_LS = MKBETAG('S','O','N','L'),
+ CODEC_ID_PAF_AUDIO = MKBETAG('P','A','F','A'),
+ CODEC_ID_OPUS = MKBETAG('O','P','U','S'),
+
+ /* subtitle codecs */
+ CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs.
+ CODEC_ID_DVD_SUBTITLE = 0x17000,
+ CODEC_ID_DVB_SUBTITLE,
+ CODEC_ID_TEXT, ///< raw UTF-8 text
+ CODEC_ID_XSUB,
+ CODEC_ID_SSA,
+ CODEC_ID_MOV_TEXT,
+ CODEC_ID_HDMV_PGS_SUBTITLE,
+ CODEC_ID_DVB_TELETEXT,
+ CODEC_ID_SRT,
+ CODEC_ID_MICRODVD = MKBETAG('m','D','V','D'),
+ CODEC_ID_EIA_608 = MKBETAG('c','6','0','8'),
+ CODEC_ID_JACOSUB = MKBETAG('J','S','U','B'),
+ CODEC_ID_SAMI = MKBETAG('S','A','M','I'),
+ CODEC_ID_REALTEXT = MKBETAG('R','T','X','T'),
+ CODEC_ID_SUBVIEWER = MKBETAG('S','u','b','V'),
+
+ /* other specific kind of codecs (generally used for attachments) */
+ CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs.
+ CODEC_ID_TTF = 0x18000,
+ CODEC_ID_BINTEXT = MKBETAG('B','T','X','T'),
+ CODEC_ID_XBIN = MKBETAG('X','B','I','N'),
+ CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'),
+ CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'),
+
+ CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like CODEC_ID_NONE) but lavf should attempt to identify it
+
+ CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS
+ * stream (only used by libavformat) */
+ CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems
+ * stream (only used by libavformat) */
+ CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information.
+
+#endif /* AVCODEC_OLD_CODEC_IDS_H */
diff --git a/libavcodec/on2avc.c b/libavcodec/on2avc.c
index 60f451c..e5e7cc3 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
*/
@@ -172,7 +172,7 @@ static int on2avc_decode_band_scales(On2AVCContext *c, GetBitContext *gb)
} else {
scale += get_vlc2(gb, c->scale_diff.table, 9, 3) - 60;
}
- if (scale < 0 || scale > 128) {
+ if (scale < 0 || scale > 127) {
av_log(c->avctx, AV_LOG_ERROR, "Invalid scale value %d\n",
scale);
return AVERROR_INVALIDDATA;
@@ -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;
@@ -908,6 +908,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
diff --git a/libavcodec/on2avcdata.c b/libavcodec/on2avcdata.c
index d039f23..abe5983 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 39d2911..7f498e5 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 c00dca0..461e4a1 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,17 +83,28 @@ 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_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 };
@@ -97,6 +115,7 @@ int avcodec_get_context_defaults3(AVCodecContext *s, const AVCodec *codec)
s->sample_aspect_ratio = (AVRational){0,1};
s->pix_fmt = AV_PIX_FMT_NONE;
s->sample_fmt = AV_SAMPLE_FMT_NONE;
+ s->timecode_frame_start = -1;
s->reordered_opaque = AV_NOPTS_VALUE;
if(codec && codec->priv_data_size){
@@ -164,9 +183,17 @@ int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
src, dest);
return AVERROR(EINVAL);
}
+
+ av_opt_free(dest);
+
memcpy(dest, src, sizeof(*dest));
+ av_opt_copy(dest, src);
dest->priv_data = orig_priv_data;
+
+ if (orig_priv_data)
+ av_opt_copy(orig_priv_data, src->priv_data);
+
dest->codec = orig_codec;
/* set values specific to opened codecs back to their default state */
@@ -205,8 +232,8 @@ int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
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;
@@ -228,3 +255,55 @@ 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;
+}
diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
index 2cf82e6..b72fbb1 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,12 @@ 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" },
+{"iter", "iter motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_ITER }, INT_MIN, INT_MAX, V|E, "me_method" },
{"extradata_size", NULL, OFFSET(extradata_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX},
{"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 +117,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 +162,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 +183,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 +230,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 +262,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 +292,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 +318,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"},
@@ -320,13 +334,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,6 +363,7 @@ static const AVOption avcodec_options[] = {
{"dts_hd_ma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_DTS_HD_MA }, INT_MIN, INT_MAX, A|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},
@@ -359,18 +374,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},
@@ -389,7 +405,7 @@ static const AVOption avcodec_options[] = {
{"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"},
@@ -416,7 +432,7 @@ static const AVOption avcodec_options[] = {
{"iec61966_2_1", "IEC 61966-2-1", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_IEC61966_2_1 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"},
{"bt2020_10bit", "BT.2020 - 10 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT2020_10 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"},
{"bt2020_12bit", "BT.2020 - 12 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT2020_12 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"},
-{"colorspace", "color space", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64 = AVCOL_SPC_UNSPECIFIED }, 1, AVCOL_SPC_NB-1, V|E|D, "colorspace_type"},
+{"colorspace", "color space", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64 = AVCOL_SPC_UNSPECIFIED }, 0, AVCOL_SPC_NB-1, V|E|D, "colorspace_type"},
{"rgb", "RGB", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_RGB }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"},
{"bt709", "BT.709", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_BT709 }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"},
{"unspecified", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"},
@@ -441,7 +457,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"},
@@ -454,19 +470,24 @@ 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 },
{NULL},
};
diff --git a/libavcodec/opus.c b/libavcodec/opus.c
index 91021ce..6b3d3c3 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
*/
@@ -290,10 +290,6 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx,
OpusContext *s)
{
static const uint8_t default_channel_map[2] = { 0, 1 };
- uint8_t default_extradata[19] = {
- 'O', 'p', 'u', 's', 'H', 'e', 'a', 'd',
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- };
int (*channel_reorder)(int, int) = channel_reorder_unknown;
@@ -308,9 +304,8 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx,
"Multichannel configuration without extradata.\n");
return AVERROR(EINVAL);
}
- default_extradata[9] = (avctx->channels == 1) ? 1 : 2;
- extradata = default_extradata;
- extradata_size = sizeof(default_extradata);
+ extradata = opus_default_extradata;
+ extradata_size = sizeof(opus_default_extradata);
} else {
extradata = avctx->extradata;
extradata_size = avctx->extradata_size;
@@ -330,7 +325,7 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx,
avctx->delay = AV_RL16(extradata + 10);
- channels = extradata[9];
+ channels = avctx->extradata ? extradata[9] : (avctx->channels == 1) ? 1 : 2;
if (!channels) {
av_log(avctx, AV_LOG_ERROR, "Zero channel count specified in the extadata\n");
return AVERROR_INVALIDDATA;
diff --git a/libavcodec/opus.h b/libavcodec/opus.h
index c2fac06..6b02b55 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,10 +57,19 @@
#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))
+#define OPUS_TS_HEADER 0x7FE0 // 0x3ff (11 bits)
+#define OPUS_TS_MASK 0xFFE0 // top 11 bits
+
+static const uint8_t opus_default_extradata[30] = {
+ 'O', 'p', 'u', 's', 'H', 'e', 'a', 'd',
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
enum OpusMode {
OPUS_MODE_SILK,
OPUS_MODE_HYBRID,
@@ -95,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 {
@@ -135,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 */
diff --git a/libavcodec/opus_celt.c b/libavcodec/opus_celt.c
index af3e549..e8a8de7 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
*/
@@ -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);
}
diff --git a/libavcodec/opus_imdct.c b/libavcodec/opus_imdct.c
index 38674ed..0a6fca9 100644
--- a/libavcodec/opus_imdct.c
+++ b/libavcodec/opus_imdct.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_imdct.h b/libavcodec/opus_imdct.h
index d4bff9a..0ca4d97 100644
--- a/libavcodec/opus_imdct.h
+++ b/libavcodec/opus_imdct.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/opus_parser.c b/libavcodec/opus_parser.c
index 8a2bc22..b128a40 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
*/
@@ -27,49 +27,162 @@
#include "avcodec.h"
#include "opus.h"
+#include "parser.h"
+#include "bytestream.h"
typedef struct OpusParseContext {
OpusContext ctx;
OpusPacket pkt;
int extradata_parsed;
+ ParseContext pc;
+ int ts_framing;
} OpusParseContext;
-static int opus_parse(AVCodecParserContext *ctx, AVCodecContext *avctx,
- const uint8_t **poutbuf, int *poutbuf_size,
- const uint8_t *buf, int buf_size)
+static const uint8_t *parse_opus_ts_header(const uint8_t *start, int *payload_len, int buf_len)
+{
+ const uint8_t *buf = start + 1;
+ int start_trim_flag, end_trim_flag, control_extension_flag, control_extension_length;
+ uint8_t flags;
+
+ GetByteContext gb;
+ bytestream2_init(&gb, buf, buf_len);
+
+ flags = bytestream2_get_byte(&gb);
+ start_trim_flag = (flags >> 4) & 1;
+ end_trim_flag = (flags >> 3) & 1;
+ control_extension_flag = (flags >> 2) & 1;
+
+ *payload_len = 0;
+ while (bytestream2_peek_byte(&gb) == 0xff)
+ *payload_len += bytestream2_get_byte(&gb);
+
+ *payload_len += bytestream2_get_byte(&gb);
+
+ if (start_trim_flag)
+ bytestream2_skip(&gb, 2);
+ if (end_trim_flag)
+ bytestream2_skip(&gb, 2);
+ if (control_extension_flag) {
+ control_extension_length = bytestream2_get_byte(&gb);
+ bytestream2_skip(&gb, control_extension_length);
+ }
+
+ return buf + bytestream2_tell(&gb);
+}
+
+/**
+ * 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 opus_find_frame_end(AVCodecParserContext *ctx, AVCodecContext *avctx,
+ const uint8_t *buf, int buf_size, int *header_len)
{
OpusParseContext *s = ctx->priv_data;
- int ret;
+ ParseContext *pc = &s->pc;
+ int ret, start_found, i = 0, payload_len = 0;
+ const uint8_t *payload;
+ uint32_t state;
+ uint16_t hdr;
+ *header_len = 0;
if (!buf_size)
return 0;
+ start_found = pc->frame_start_found;
+ state = pc->state;
+ payload = buf;
+
+ /* Check if we're using Opus in MPEG-TS framing */
+ if (!s->ts_framing && buf_size > 2) {
+ hdr = AV_RB16(buf);
+ if ((hdr & OPUS_TS_MASK) == OPUS_TS_HEADER)
+ s->ts_framing = 1;
+ }
+
+ if (s->ts_framing && !start_found) {
+ for (i = 0; i < buf_size-2; i++) {
+ state = (state << 8) | payload[i];
+ if ((state & OPUS_TS_MASK) == OPUS_TS_HEADER) {
+ payload = parse_opus_ts_header(payload, &payload_len, buf_size - i);
+ *header_len = payload - buf;
+ start_found = 1;
+ break;
+ }
+ }
+ }
+
+ if (!s->ts_framing)
+ payload_len = buf_size;
+
if (avctx->extradata && !s->extradata_parsed) {
ret = ff_opus_parse_extradata(avctx, &s->ctx);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Error parsing Ogg extradata.\n");
- goto fail;
+ return AVERROR_INVALIDDATA;
}
av_freep(&s->ctx.channel_maps);
s->extradata_parsed = 1;
}
- ret = ff_opus_parse_packet(&s->pkt, buf, buf_size, s->ctx.nb_streams > 1);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error parsing Opus packet header.\n");
- goto fail;
+ if (payload_len <= buf_size && (!s->ts_framing || start_found)) {
+ ret = ff_opus_parse_packet(&s->pkt, payload, payload_len, s->ctx.nb_streams > 1);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Error parsing Opus packet header.\n");
+ pc->frame_start_found = 0;
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->duration = s->pkt.frame_count * s->pkt.frame_duration;
}
- ctx->duration = s->pkt.frame_count * s->pkt.frame_duration;
+ if (s->ts_framing) {
+ if (start_found) {
+ if (payload_len + *header_len <= buf_size) {
+ pc->frame_start_found = 0;
+ pc->state = -1;
+ return payload_len + *header_len;
+ }
+ }
+
+ pc->frame_start_found = start_found;
+ pc->state = state;
+ return END_NOT_FOUND;
+ }
-fail:
- *poutbuf = buf;
- *poutbuf_size = buf_size;
return buf_size;
}
+static int opus_parse(AVCodecParserContext *ctx, AVCodecContext *avctx,
+ const uint8_t **poutbuf, int *poutbuf_size,
+ const uint8_t *buf, int buf_size)
+{
+ OpusParseContext *s = ctx->priv_data;
+ ParseContext *pc = &s->pc;
+ int next, header_len;
+
+ next = opus_find_frame_end(ctx, avctx, buf, buf_size, &header_len);
+
+ if (s->ts_framing && next != AVERROR_INVALIDDATA &&
+ ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
+ *poutbuf = NULL;
+ *poutbuf_size = 0;
+ return buf_size;
+ }
+
+ if (next == AVERROR_INVALIDDATA){
+ *poutbuf = NULL;
+ *poutbuf_size = 0;
+ return buf_size;
+ }
+
+ *poutbuf = buf + header_len;
+ *poutbuf_size = buf_size - header_len;
+ return next;
+}
+
AVCodecParser ff_opus_parser = {
.codec_ids = { AV_CODEC_ID_OPUS },
.priv_data_size = sizeof(OpusParseContext),
.parser_parse = opus_parse,
+ .parser_close = ff_parse_close
};
diff --git a/libavcodec/opus_silk.c b/libavcodec/opus_silk.c
index 3552484..7a89479 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 bf3a54b..b28edfb 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,7 +40,7 @@
#include "libavutil/channel_layout.h"
#include "libavutil/opt.h"
-#include "libavresample/avresample.h"
+#include "libswresample/swresample.h"
#include "avcodec.h"
#include "celp_filters.h"
@@ -114,9 +114,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 +155,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 +219,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 +233,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 +373,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 +405,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;
@@ -555,7 +554,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);
@@ -577,7 +576,7 @@ 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);
@@ -627,16 +626,17 @@ static av_cold int opus_decode_init(AVCodecContext *avctx)
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 0000000..ce8245f
--- /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 52aaabf..aaaef5e 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 650d036..a27afed 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 8535d3d..64ab2b5 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,53 @@ 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_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 +100,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 +148,6 @@ 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_MONOBLACK, AV_PIX_FMT_NONE
},
};
diff --git a/libavcodec/parser.c b/libavcodec/parser.c
index 6d20516..d1e1574 100644
--- a/libavcodec/parser.c
+++ b/libavcodec/parser.c
@@ -3,26 +3,27 @@
* 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/atomic.h"
#include "libavutil/mem.h"
#include "parser.h"
@@ -39,20 +40,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 ||
@@ -65,31 +67,30 @@ 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;
s->dts_ref_dts_delta = INT_MIN;
s->pts_dts_delta = INT_MIN;
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)
@@ -103,8 +104,10 @@ void ff_fetch_timestamp(AVCodecParserContext *s, int off, int remove)
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->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]){
+
s->dts = s->cur_frame_dts[i];
s->pts = s->cur_frame_pts[i];
s->pos = s->cur_frame_pos[i];
@@ -209,7 +212,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);
}
}
@@ -240,8 +243,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;
@@ -256,9 +261,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,
diff --git a/libavcodec/parser.h b/libavcodec/parser.h
index ea1cae2..7fe0e11 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
*/
diff --git a/libavcodec/pcm-bluray.c b/libavcodec/pcm-bluray.c
index 7e4dcf8..695bc31 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 f68af36..e4184a5 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)
av_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 e06712e..0a4ad0b 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 7b4bc8c..bf8e7fb 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 79d6561..1387210 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 61c971e..6487aa5 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 4bf7377..f48063b 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 b832ae7..6da7a56 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 6217c40..36f1f82 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
@@ -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
@@ -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 33c4545..1bc51bc 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 71423f9..ebde68b 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 8094d14..d4b8590 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 71d3cf1..d1e9102 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 d9d2fde..98eacd4 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 cd75dc1..ef52b51 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 b8c72ee..948c2f7 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 c66caf3..74f2964 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 fa7f7cc..57b73c1 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -2,40 +2,43 @@
* 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 "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 last_picture;
+ ThreadFrame picture;
int state;
int width, height;
@@ -53,7 +56,11 @@ typedef struct PNGDecContext {
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 +69,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 +95,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 +153,6 @@ static void png_put_interlaced_row(uint8_t *dst, int width,
if ((mask << j) & 0x80)
s += bpp;
}
- }
break;
}
}
@@ -168,7 +194,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 +217,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 +238,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 +255,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:
@@ -252,46 +275,21 @@ static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type,
}
}
-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;
- }
-}
-
-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);
+/* 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 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)
@@ -301,15 +299,6 @@ static void png_handle_row(PNGDecContext *s)
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
@@ -317,17 +306,28 @@ static void png_handle_row(PNGDecContext *s)
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) {
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;
@@ -341,15 +341,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,
s->color_type, s->last_row);
}
s->y++;
if (s->y == s->height) {
+ memset(s->last_row, 0, s->row_size);
for (;;) {
if (s->pass == NB_PASSES - 1) {
s->state |= PNG_ALLIMAGE;
@@ -376,14 +377,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,201 +403,453 @@ 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)
- return -1;
+ 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;
- bytestream2_init(&s->gb, buf + 8, buf_size - 8);
- s->y = s->state = 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;
+ }
+
+ 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;
+ 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;
+ 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 = (avctx->width * 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->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->width);
+ s->crow_size = s->pass_row_size + 1;
+ }
+ av_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_frame_common(AVCodecContext *avctx, PNGDecContext *s,
+ AVFrame *p, AVPacket *avpkt)
+{
+ AVDictionary *metadata = NULL;
+ uint32_t tag, length;
- /* 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)
+ if (bytestream2_get_bytes_left(&s->gb) <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "%d bytes left\n", bytestream2_get_bytes_left(&s->gb));
+ if ( s->state & PNG_ALLIMAGE
+ && avctx->strict_std_compliance <= FF_COMPLIANCE_NORMAL)
+ goto exit_loop;
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");
goto fail;
+ }
tag = bytestream2_get_le32(&s->gb);
- av_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 (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 (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;
- av_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))
- 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;
- }
- av_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)
+ if (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))) {
goto fail;
+ }
bytestream2_skip(&s->gb, 4); /* crc */
goto exit_loop;
default:
@@ -606,50 +860,124 @@ 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)) {
+ if (s->last_picture.f->data[0]) {
+ if ( !(avpkt->flags & AV_PKT_FLAG_KEY) && avctx->codec_tag != AV_RL32("MPNG")
+ && s->last_picture.f->width == p->width
+ && s->last_picture.f->height== p->height
+ && s->last_picture.f->format== p->format
+ ) {
int i, j;
uint8_t *pd = p->data[0];
- uint8_t *pd_last = s->prev->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 < s->width * s->bpp; i++)
+ for (i = 0; i < ls; i++)
pd[i] += pd_last[i];
pd += s->image_linesize;
pd_last += s->image_linesize;
}
}
}
+ 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 AVERROR_INVALIDDATA;
+}
+
+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, "Missing png signature\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ 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;
+ }
- av_frame_unref(s->prev);
- if ((ret = av_frame_ref(s->prev, p)) < 0)
- goto fail;
+ 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;
+}
+
+static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
+{
+ PNGDecContext *psrc = src->priv_data;
+ PNGDecContext *pdst = dst->priv_data;
+
+ if (dst == src)
+ return 0;
+
+ ff_thread_release_buffer(dst, &pdst->picture);
+ if (psrc->picture.f->data[0])
+ return ff_thread_ref_frame(&pdst->picture, &psrc->picture);
+
+ return 0;
}
static av_cold int png_dec_init(AVCodecContext *avctx)
{
PNGDecContext *s = avctx->priv_data;
- s->prev = av_frame_alloc();
- if (!s->prev)
+ s->avctx = avctx;
+ s->last_picture.f = av_frame_alloc();
+ s->picture.f = av_frame_alloc();
+ if (!s->last_picture.f || !s->picture.f)
return AVERROR(ENOMEM);
- ff_pngdsp_init(&s->dsp);
+ if (!avctx->internal->is_copy) {
+ avctx->internal->allocate_progress = 1;
+ ff_pngdsp_init(&s->dsp);
+ }
return 0;
}
@@ -658,7 +986,16 @@ 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->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;
}
@@ -671,6 +1008,8 @@ 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*/,
};
diff --git a/libavcodec/pngdsp.c b/libavcodec/pngdsp.c
index c0e9402..d275316 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 98d29a8..1475b0c 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
*/
diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c
index 3d11f37..401b1a2 100644
--- a/libavcodec/pngenc.c
+++ b/libavcodec/pngenc.c
@@ -2,37 +2,38 @@
* 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"
-/* TODO:
- * - add 2, 4 and 16 bit depth support
- */
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
#include <zlib.h>
#define IOBUF_SIZE 4096
typedef struct PNGEncContext {
+ AVClass *class;
HuffYUVEncDSPContext hdsp;
uint8_t *bytestream;
@@ -43,6 +44,8 @@ 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
} PNGEncContext;
static void png_get_interlaced_row(uint8_t *dst, int row_size,
@@ -52,8 +55,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 +115,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 +141,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 +164,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,23 +190,6 @@ 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)
{
@@ -235,12 +237,12 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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 bits_per_pixel, pass_row_size, enc_row_size;
+ int64_t 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);
@@ -253,7 +255,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
bit_depth = 16;
color_type = PNG_COLOR_TYPE_RGB;
break;
- case AV_PIX_FMT_RGB32:
+ case AV_PIX_FMT_RGBA:
bit_depth = 8;
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
break;
@@ -269,6 +271,10 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
bit_depth = 8;
color_type = PNG_COLOR_TYPE_GRAY;
break;
+ case AV_PIX_FMT_GRAY8A:
+ bit_depth = 8;
+ color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
+ break;
case AV_PIX_FMT_MONOBLACK:
bit_depth = 1;
color_type = PNG_COLOR_TYPE_GRAY;
@@ -295,15 +301,13 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return -1;
enc_row_size = deflateBound(&s->zstream, row_size);
- max_packet_size = avctx->height * (enc_row_size +
+ max_packet_size = avctx->height * (int64_t)(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);
+ if (max_packet_size > INT_MAX)
+ return AVERROR(ENOMEM);
+ if ((ret = ff_alloc_packet2(avctx, pkt, max_packet_size)) < 0)
return ret;
- }
s->bytestream_start =
s->bytestream = pkt->data;
@@ -319,19 +323,14 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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) {
+ if (is_progressive) {
top_buf = av_malloc(row_size + 1);
if (!top_buf)
goto fail;
}
/* write png header */
- memcpy(s->bytestream, ff_pngsig, 8);
+ AV_WB64(s->bytestream, PNGSIG);
s->bytestream += 8;
AV_WB32(s->buf, avctx->width);
@@ -344,6 +343,17 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
png_write_chunk(&s->bytestream, MKTAG('I', 'H', 'D', 'R'), s->buf, 13);
+ 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);
+
/* put the palette if needed */
if (color_type == PNG_COLOR_TYPE_PALETTE) {
int has_alpha, alpha, i;
@@ -358,7 +368,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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);
@@ -387,10 +397,6 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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,
ptr, avctx->width);
@@ -405,11 +411,6 @@ 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);
@@ -442,7 +443,6 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
the_end:
av_free(crow_base);
av_free(progressive_buf);
- av_free(rgba_buf);
av_free(top_buf);
deflateEnd(&s->zstream);
return ret;
@@ -455,6 +455,23 @@ static av_cold int png_enc_init(AVCodecContext *avctx)
{
PNGEncContext *s = avctx->priv_data;
+ 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)
return AVERROR(ENOMEM);
@@ -470,6 +487,13 @@ 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;
+ }
+
return 0;
}
@@ -479,6 +503,21 @@ static av_cold int png_enc_close(AVCodecContext *avctx)
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,
+};
+
AVCodec ff_png_encoder = {
.name = "png",
.long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
@@ -488,9 +527,14 @@ AVCodec ff_png_encoder = {
.init = png_enc_init,
.close = png_enc_close,
.encode2 = encode_frame,
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
.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_MONOBLACK, AV_PIX_FMT_NONE
},
+ .priv_class = &pngenc_class,
};
diff --git a/libavcodec/pnm.c b/libavcodec/pnm.c
index 1c380b0..502e550 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,35 @@ 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 == 255)
+ avctx->pix_fmt = AV_PIX_FMT_GRAY8A;
} 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 +144,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 +162,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 5fc6513..5bc0aad 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 2e00c0a..2a9e3e1 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 9074d9b..c84b6eb 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,8 +96,12 @@ 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;
@@ -84,35 +113,47 @@ static int pnm_decode_frame(AVCodecContext *avctx, void *data,
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 +171,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 +184,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 +193,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 +243,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 7513552..e6c3635 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 c6ff0f1..6f7eeb7 100644
--- a/libavcodec/ppc/Makefile
+++ b/libavcodec/ppc/Makefile
@@ -4,9 +4,10 @@ OBJS += ppc/fmtconvert_altivec.o \
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_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
@@ -22,7 +23,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/asm.S b/libavcodec/ppc/asm.S
index 141dee9..a3edeed 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 36506ce..c88c3d9 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 679bc04..0059b3b 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 37fd8bb..2328516 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 7471035..437f815 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 51417a5..f2efc5d 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 }
diff --git a/libavcodec/ppc/fft_altivec.S b/libavcodec/ppc/fft_altivec.S
index c92b30b..aab669e 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 8fcc033..675fa33 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 0000000..e92975f
--- /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 0000000..a85475d
--- /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 14aaf6b..10a7169 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 6d656d4..876efec 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 293fef5..7436e11 100644
--- a/libavcodec/ppc/h264chroma_template.c
+++ b/libavcodec/ppc/h264chroma_template.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/h264dsp.c b/libavcodec/ppc/h264dsp.c
index 31dc141..7fc7e0b 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
*/
diff --git a/libavcodec/ppc/h264qpel.c b/libavcodec/ppc/h264qpel.c
index f840277..4a01f17 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
*/
diff --git a/libavcodec/ppc/h264qpel_template.c b/libavcodec/ppc/h264qpel_template.c
index fe83146..360e9e3 100644
--- a/libavcodec/ppc/h264qpel_template.c
+++ b/libavcodec/ppc/h264qpel_template.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/hpeldsp_altivec.c b/libavcodec/ppc/hpeldsp_altivec.c
index fd6ae73..87a1f05 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 98dd80e..590809f 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 7c34a67..6701524 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 17f7dbb..5ef514b 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;
@@ -234,9 +250,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/apedsp_altivec.c b/libavcodec/ppc/lossless_audiodsp_altivec.c
index d8bf4bd..1ebb0f4 100644
--- a/libavcodec/ppc/apedsp_altivec.c
+++ b/libavcodec/ppc/lossless_audiodsp_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
*/
@@ -27,7 +27,7 @@
#include "libavutil/cpu.h"
#include "libavutil/ppc/cpu.h"
#include "libavutil/ppc/types_altivec.h"
-#include "libavcodec/apedsp.h"
+#include "libavcodec/lossless_audiodsp.h"
#if HAVE_ALTIVEC
static int32_t scalarproduct_and_madd_int16_altivec(int16_t *v1,
@@ -71,7 +71,7 @@ static int32_t scalarproduct_and_madd_int16_altivec(int16_t *v1,
}
#endif /* HAVE_ALTIVEC */
-av_cold void ff_apedsp_init_ppc(APEDSPContext *c)
+av_cold void ff_llauddsp_init_ppc(LLAudDSPContext *c)
{
#if HAVE_ALTIVEC
if (!PPC_ALTIVEC(av_get_cpu_flags()))
diff --git a/libavcodec/ppc/mathops.h b/libavcodec/ppc/mathops.h
index 34ddb11..dbd714f 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 88c7fea..e280ea4 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,
int line_size, 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,
int line_size, 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 + line_size;
/* Due to the fact that pix3 = pix2 + line_size, 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,
int line_size, int h)
{
- int i, s = 0;
+ int i;
+ int __attribute__((aligned(16))) s = 0;
uint8_t *pix3 = pix2 + line_size;
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 + line_size, 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,
int line_size, 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,
int line_size, 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,
int line_size, 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,
int line_size, 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, int 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, int 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 c37f8ec..ddfe5dc 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 9ae849f..ce53ae4 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
*/
diff --git a/libavcodec/ppc/mpegvideodsp.c b/libavcodec/ppc/mpegvideodsp.c
index 2bdf909..7696954 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 b5348e6..e91ba5d 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_vsx_st(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_vsx_st(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 698d655..9bbdf96 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 564f129..4e25e25 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 90c3d27..2128b56 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
*/
diff --git a/libavcodec/ppc/videodsp_ppc.c b/libavcodec/ppc/videodsp_ppc.c
index b9e003b..9157022 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 43f4d03..d7557c8 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 bce49e3..9d81b3f 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
*/
diff --git a/libavcodec/ppc/vp8dsp_altivec.c b/libavcodec/ppc/vp8dsp_altivec.c
index e010dee..91ff8cc 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
*/
diff --git a/libavcodec/proresdata.c b/libavcodec/proresdata.c
index fcaf32a..9849b5c 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 1e5d05e..ee8278d 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.h b/libavcodec/proresdec.h
new file mode 100644
index 0000000..14ede5d
--- /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 0000000..4d04a0a
--- /dev/null
+++ b/libavcodec/proresdec2.c
@@ -0,0 +1,689 @@
+/*
+ * 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->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.c b/libavcodec/proresdec_lgpl.c
index 03f63d9..f2e24ec 100644
--- a/libavcodec/proresdec.c
+++ b/libavcodec/proresdec_lgpl.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
*/
@@ -86,7 +86,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
ctx->slice_data = NULL;
avctx->bits_per_raw_sample = PRORES_BITS_PER_SAMPLE;
- ff_proresdsp_init(&ctx->dsp);
+ ff_proresdsp_init(&ctx->dsp, avctx);
ctx->scantable_type = -1; // set scantable type to uninitialized
memset(ctx->qmat_luma, 4, 64);
@@ -140,6 +140,7 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf,
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:
@@ -505,8 +506,9 @@ static void unpack_alpha(GetBitContext *gb, uint16_t *dst, int num_coeffs,
dst[idx++] = alpha_val >> 6;
else
dst[idx++] = (alpha_val << 2) | (alpha_val >> 6);
- if (idx >= num_coeffs - 1)
+ if (idx >= num_coeffs) {
break;
+ }
} while (get_bits1(gb));
val = get_bits(gb, 4);
if (!val)
@@ -618,7 +620,7 @@ static int decode_slice(AVCodecContext *avctx, void *tdata)
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];
+ 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 */
@@ -768,8 +770,8 @@ static av_cold int decode_close(AVCodecContext *avctx)
}
-AVCodec ff_prores_decoder = {
- .name = "prores",
+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,
diff --git a/libavcodec/proresdsp.c b/libavcodec/proresdsp.c
index 3af2f0b..82d6009 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 e8a3ea9..159862e 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_anatoliy.c b/libavcodec/proresenc_anatoliy.c
new file mode 100644
index 0000000..f471f49
--- /dev/null
+++ b/libavcodec/proresenc_anatoliy.c
@@ -0,0 +1,636 @@
+/*
+ * 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,
+ mask;
+
+ /* 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) {
+ mask = (1 << rice_order) - 1;
+ put_bits(pb, (val >> rice_order), 0);
+ put_bits(pb, 1, 1);
+ put_bits(pb, rice_order, val & mask);
+ } 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;
+ DECLARE_ALIGNED(16, int16_t, blocks)[DEFAULT_SLICE_MB_WIDTH << 8], *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 << 3);
+
+ 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_freep(&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.c b/libavcodec/proresenc_kostya.c
index 3a82c2c..5f432a9 100644
--- a/libavcodec/proresenc.c
+++ b/libavcodec/proresenc_kostya.c
@@ -3,20 +3,23 @@
*
* Copyright (c) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This encoder appears to be based on Anatoliy Wassermans considering
+ * similarities in the bugs.
*
- * 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,6 +40,7 @@
#define MAX_PLANES 4
enum {
+ PRORES_PROFILE_AUTO = -1,
PRORES_PROFILE_PROXY = 0,
PRORES_PROFILE_LT,
PRORES_PROFILE_STANDARD,
@@ -935,7 +939,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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;
+ 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;
*avctx->coded_frame = *pic;
@@ -944,10 +949,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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");
+ if ((ret = ff_alloc_packet2(avctx, pkt, pkt_size + FF_MIN_BUFFER_SIZE)) < 0)
return ret;
- }
orig_buf = pkt->data;
@@ -1026,9 +1029,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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;
+ 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;
@@ -1074,10 +1077,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
}
- if (ctx->pictures_per_frame == 1)
- picture_size = buf - picture_size_pos - 6;
- else
- picture_size = buf - picture_size_pos + 1;
+ picture_size = buf - (picture_size_pos - 1);
bytestream_put_be32(&picture_size_pos, picture_size);
}
@@ -1101,7 +1101,7 @@ static av_cold int encode_close(AVCodecContext *avctx)
if (ctx->tdata) {
for (i = 0; i < avctx->thread_count; i++)
- av_free(ctx->tdata[i].nodes);
+ av_freep(&ctx->tdata[i].nodes);
}
av_freep(&ctx->tdata);
av_freep(&ctx->slice_q);
@@ -1147,7 +1147,23 @@ static av_cold int encode_init(AVCodecContext *avctx)
"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);
@@ -1248,16 +1264,16 @@ static av_cold int encode_init(AVCodecContext *avctx)
ctx->bits_per_mb += ls * 4;
}
- ctx->frame_size_upper_bound = ctx->pictures_per_frame *
- ctx->slices_per_picture *
+ 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 *
+ 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);
}
@@ -1281,8 +1297,10 @@ 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" },
+ { .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 },
@@ -1323,8 +1341,8 @@ static const AVClass proresenc_class = {
.version = LIBAVUTIL_VERSION_INT,
};
-AVCodec ff_prores_encoder = {
- .name = "prores",
+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,
diff --git a/libavcodec/psymodel.c b/libavcodec/psymodel.c
index a2af611..059cbef 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 1cc3066..75261ba 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 682fd05..407ca2e 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 effc9a5..5a4ab84 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"
@@ -77,6 +79,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 +96,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 +121,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 +143,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 +166,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 +231,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 +273,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 +282,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 +310,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 +363,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 +423,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 +477,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 +495,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 +515,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 +539,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 +552,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,6 +569,7 @@ 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);
@@ -570,7 +619,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 +635,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 +697,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 +740,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 +789,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 +803,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 +814,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 5dfd0b2..6a2f378 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 d7c73f0..b948e16 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)
@@ -112,7 +120,7 @@ void ff_slice_thread_free(AVCodecContext *avctx)
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->workers);
av_freep(&avctx->internal->thread_ctx);
}
@@ -175,7 +183,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 +201,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 +231,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 76fff26..8c3abd7 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 17666fa..8858caa 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
*/
@@ -31,6 +31,7 @@
#include <assert.h>
#include "libavutil/intreadwrite.h"
+#include "libavutil/avassert.h"
typedef struct PutBitContext {
uint32_t bit_buf;
@@ -62,6 +63,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 +155,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,6 +164,7 @@ 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;
@@ -158,6 +178,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,7 +192,7 @@ 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));
}
@@ -207,8 +228,8 @@ 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);
s->buf_ptr += n;
}
diff --git a/libavcodec/qcelpdata.h b/libavcodec/qcelpdata.h
index 319833e..931c990 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 7d9427c..6f08607 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;
}
@@ -770,7 +771,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 94bda91..339fe4b 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
*/
@@ -168,7 +168,7 @@ typedef struct {
/// 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;
@@ -375,7 +375,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));
@@ -694,7 +701,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
@@ -730,7 +738,7 @@ static void fill_coding_method_array(sb_int8_array tone_level_idx,
for (j = 0; j < 64; j++)
acc += tone_level_idx_temp[ch][sb][j];
- multres = 0x66666667 * (acc * 10);
+ multres = 0x66666667LL * (acc * 10);
esp_40 = (multres >> 32) / 8 + ((multres & 0xffffffff) >> 31);
for (ch = 0; ch < nb_channels; ch++)
for (sb = 0; sb < 30; sb++)
@@ -806,7 +814,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 +822,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 +854,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 +879,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 +920,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 +938,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 +955,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 +975,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 +1017,7 @@ static void synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb,
} // j loop
} // channel loop
} // subband loop
+ return 0;
}
/**
@@ -1002,24 +1030,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 +1059,7 @@ static void init_quantized_coeffs_elem0(int8_t *quantized_coeffs,
level += diff;
i += run;
}
+ return 0;
}
/**
@@ -1102,7 +1134,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 +1152,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 +1166,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 +1237,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 +1270,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 +1430,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 +1750,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 +1775,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 +1865,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 +1895,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 +1918,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 +1957,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 +2031,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 +2053,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 59d82df..a7a9fb6 100644
--- a/libavcodec/qdm2_tablegen.c
+++ b/libavcodec/qdm2_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/qdm2_tablegen.h b/libavcodec/qdm2_tablegen.h
index bb73d92..13ec9be 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
*/
@@ -37,7 +37,7 @@
#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 +54,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 +66,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;
}
}
}
diff --git a/libavcodec/qdm2data.h b/libavcodec/qdm2data.h
index ad6ea88..355d613 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 c365bfd..3f82e5b 100644
--- a/libavcodec/qdrw.c
+++ b/libavcodec/qdrw.c
@@ -2,20 +2,20 @@
* QuickDraw (qdrw) 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
*/
@@ -43,10 +43,8 @@ static int decode_frame(AVCodecContext *avctx,
uint32_t *pal;
int r, g, b;
- 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;
@@ -82,7 +80,7 @@ static int decode_frame(AVCodecContext *avctx,
buf++;
b = *buf++;
buf++;
- pal[idx] = (r << 16) | (g << 8) | b;
+ pal[idx] = 0xFFU << 24 | r << 16 | g << 8 | b;
}
p->palette_has_changed = 1;
diff --git a/libavcodec/qpeg.c b/libavcodec/qpeg.c
index 4de1655..d61bcea 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,12 @@ static void qpeg_decode_inter(QpegContext *qctx, uint8_t *dst,
int filled = 0;
int orig_height;
+ if(!refdata)
+ refdata= dst;
+
/* copy prev frame */
for(i = 0; i < height; i++)
- memcpy(refdata + (i * width), dst + (i * stride), width);
+ memcpy(dst + (i * stride), refdata + (i * stride), width);
orig_height = height;
height--;
@@ -134,7 +136,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 +163,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 +200,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 +256,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 +267,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 +282,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 +300,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 +327,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 +349,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 2106160..e52a78c 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 1d0422a..1c0ec63 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 4ad141d..b51420a 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/qtrle.c b/libavcodec/qtrle.c
index 28f1720..b367643 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 7c98bea..d723188 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 6adaac0..cbebf7c 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
*/
@@ -39,7 +39,8 @@ 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;
if (avpkt->size < 4 * aligned_width * avctx->height) {
@@ -57,8 +58,13 @@ 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_AVRP) {
+ pixel = av_le2ne32(*src++);
+ } else {
+ pixel = av_be2ne32(*src++);
+ }
if (avctx->codec_id==AV_CODEC_ID_R210) {
b = pixel << 6;
g = (pixel >> 4) & 0xffc0;
@@ -103,3 +109,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 0000000..d61cd75
--- /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++ >> 4;
+ if (avctx->codec_id == AV_CODEC_ID_R210)
+ pixel = (r << 20) | (g << 10) | b >> 2;
+ else
+ pixel = (r << 22) | (g << 12) | b;
+ 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_freep(&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 355badd..696a49e 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 81d6964..df74790 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 3be3877..29c7822 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 fd04766..3ad3f4e 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 215786c..968672c 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
*/
@@ -67,6 +67,11 @@ static av_cold int ra288_decode_init(AVCodecContext *avctx)
avctx->channel_layout = AV_CH_LAYOUT_MONO;
avctx->sample_fmt = AV_SAMPLE_FMT_FLT;
+ if (avctx->block_align <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "unsupported block align\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
avpriv_float_dsp_init(&ractx->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
return 0;
@@ -104,14 +109,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,6 +144,8 @@ static void do_hybrid_window(RA288Context *ractx,
MAX_BACKWARD_FILTER_LEN +
MAX_BACKWARD_FILTER_NONREC, 16)]);
+ av_assert2(order>=0);
+
ractx->fdsp.vector_fmul(work, window, hist, FFALIGN(order + n + non_rec, 16));
convolve(buffer1, work + order , n , order);
@@ -191,13 +198,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)];
diff --git a/libavcodec/ra288.h b/libavcodec/ra288.h
index 9f4beeb..d30e49a 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 ebcdf6f..8a319ac 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 83eb970..9a84e45 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 af0a8c0..29fb909 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 4c88169..d36fbd7 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 e18878d..d05e2ee 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
*/
@@ -47,7 +47,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,
@@ -64,6 +64,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) {
@@ -125,6 +130,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,
@@ -148,6 +160,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->flags & CODEC_FLAG_PASS2) {
int i;
@@ -193,7 +207,7 @@ av_cold int ff_rate_control_init(MpegEncContext *s)
assert(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,
@@ -276,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);
}
}
}
@@ -301,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;
@@ -315,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;
}
@@ -491,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;
@@ -737,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();
@@ -750,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->flags & CODEC_FLAG_PASS2) {
assert(picture_number >= 0);
- assert(picture_number < rcc->num_entries);
+ 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 {
@@ -796,7 +819,7 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run)
assert(pict_type == rce->new_pict_type);
q = rce->new_qscale / br_compensation;
- av_dlog(s, "%f %f %f last:%d var:%d type:%d//\n", q, rce->new_qscale,
+ av_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 =
@@ -825,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;
@@ -858,7 +880,7 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run)
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,
@@ -893,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;
@@ -902,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 */
@@ -929,8 +951,8 @@ 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));
toobig = 0;
for (step = 256 * 256; step > 0.0000001; step *= 0.5) {
@@ -949,6 +971,12 @@ static int init_pass2(MpegEncContext *s)
assert(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];
diff --git a/libavcodec/ratecontrol.h b/libavcodec/ratecontrol.h
index 63ebeb2..eeb4bb9 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 541ef7a..62ad338 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 bf66671..24bf4cc 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 3b69e49..28792a1 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,27 @@ 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);
+ }
+ 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 +181,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 +205,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 +254,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 +274,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 +325,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 +341,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 +368,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 bca0d08..c579230 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
*/
@@ -35,9 +35,8 @@ static av_cold int raw_encode_init(AVCodecContext *avctx)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
- avctx->coded_frame = avctx->priv_data;
+ avctx->coded_frame = av_frame_alloc();
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);
@@ -52,7 +51,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)
@@ -69,12 +68,18 @@ static int raw_encode(AVCodecContext *avctx, AVPacket *pkt,
return 0;
}
+static av_cold int raw_close(AVCodecContext *avctx)
+{
+ av_frame_free(&avctx->coded_frame);
+ return 0;
+}
+
AVCodec ff_rawvideo_encoder = {
.name = "rawvideo",
.long_name = NULL_IF_CONFIG_SMALL("raw video"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_RAWVIDEO,
- .priv_data_size = sizeof(AVFrame),
.init = raw_encode_init,
.encode2 = raw_encode,
+ .close = raw_close,
};
diff --git a/libavcodec/rdft.c b/libavcodec/rdft.c
index 1965253..e85219e 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 8ff620f..37c40e7 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 0000000..870953b
--- /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 73e8b0a..594a760 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 460482a..e880b95 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 0000000..c45aa16
--- /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 0000000..cd9fe1c
--- /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 367cc98..2897ec5 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 54b3e6a..6e63ed1 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],
diff --git a/libavcodec/rle.c b/libavcodec/rle.c
index cbbde93..d2ec68c 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 00261d3..2485132 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 412cda5..344775e 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 f97d5d6..b0b76d0 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
*/
@@ -147,6 +147,8 @@ static int roq_dpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
context->input_frames++;
return 0;
}
+ }
+ if (context->input_frames < 8) {
in = context->frame_buffer;
}
@@ -155,15 +157,13 @@ static int roq_dpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
context->lastSample[1] &= 0xFF00;
}
- if (context->input_frames == 7 || !in)
+ if (context->input_frames == 7)
data_size = avctx->channels * context->buffered_samples;
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 b0fd6ba..8eda93c 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 3f00022..3da6eaa 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 ac7d4ba..b716e25 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 af0089f..1c5970f 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.
@@ -248,7 +249,7 @@ static void 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));
/* Map to the ROQ quadtree order */
for (y=0; y<enc->height; y+=16)
@@ -540,7 +541,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,16 +799,16 @@ static void generate_codebook(RoqContext *enc, RoqTempdata *tempdata,
int i, j, k;
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 (size == 4)
- closest_cb = av_malloc(6*c_size*inputCount*sizeof(int));
+ closest_cb = av_malloc_array(6*c_size, inputCount*sizeof(int));
else
closest_cb = tempdata->closest_cb2;
- ff_init_elbg(points, 6*c_size, inputCount, codebook, cbsize, 1, closest_cb, &enc->randctx);
- ff_do_elbg(points, 6*c_size, inputCount, codebook, cbsize, 1, closest_cb, &enc->randctx);
+ avpriv_init_elbg(points, 6*c_size, inputCount, codebook, cbsize, 1, closest_cb, &enc->randctx);
+ avpriv_do_elbg(points, 6*c_size, inputCount, codebook, cbsize, 1, closest_cb, &enc->randctx);
if (size == 4)
av_free(closest_cb);
@@ -833,8 +834,8 @@ static void 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;
/* Subsample YUV data */
@@ -847,11 +848,11 @@ static void generate_new_codebooks(RoqContext *enc, RoqTempdata *tempData)
}
/* Create 4x4 codebooks */
- generate_codebook(enc, tempData, points, max, results4, 4, MAX_CBS_4x4);
+ generate_codebook(enc, tempData, points, max, results4, 4, (enc->quake3_compat ? MAX_CBS_4x4-1 : MAX_CBS_4x4));
- 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));
/* Create 2x2 codebooks */
generate_codebook(enc, tempData, points, max*4, enc->cb2x2, 2, MAX_CBS_2x2);
@@ -880,7 +881,7 @@ static void generate_new_codebooks(RoqContext *enc, RoqTempdata *tempData)
av_free(results4);
}
-static void roq_encode_video(RoqContext *enc)
+static int roq_encode_video(RoqContext *enc)
{
RoqTempdata *tempData = enc->tmpData;
int i;
@@ -901,10 +902,14 @@ static void 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;
@@ -935,6 +940,8 @@ static void roq_encode_video(RoqContext *enc)
av_free(tempData->closest_cb2);
enc->framesSinceKeyframe++;
+
+ return 0;
}
static av_cold int roq_encode_end(AVCodecContext *avctx)
@@ -962,11 +969,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;
@@ -984,16 +996,16 @@ 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));
return 0;
}
@@ -1041,10 +1053,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 */
@@ -1054,11 +1064,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);
@@ -1067,7 +1075,8 @@ static int roq_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
/* Encode the actual frame */
- roq_encode_video(enc);
+ if ((ret = roq_encode_video(enc)) < 0)
+ return ret;
pkt->size = enc->out_buf - pkt->data;
if (enc->framesSinceKeyframe == 1)
@@ -1077,6 +1086,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"),
@@ -1086,7 +1109,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 83dde7a..732b09a 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 67eeff8..8e02bce 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 cd30079..d22ff40 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 e5b76f0..7097b29 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,
}
}
+
av_dlog(avctx, "qscale=%d\n", s->qscale);
/* default quantization values */
@@ -687,6 +707,8 @@ static int rv10_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
const uint8_t *slices_hdr = NULL;
av_dlog(avctx, "*****frame %d size=%d\n", avctx->frame_number, buf_size);
+ s->flags = avctx->flags;
+ s->flags2 = avctx->flags2;
/* no supplementary picture */
if (buf_size == 0) {
@@ -744,11 +766,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 +796,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 +814,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 ca76052..2541132 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 4462bde..03275c7 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 1675ea2..fd8fd4f 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;
}
@@ -261,8 +266,12 @@ static av_cold int rv30_decode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR, "Extradata is too small.\n");
return -1;
}
- r->rpr = (avctx->extradata[1] & 7) >> 1;
- r->rpr = FFMIN(r->rpr + 1, 3);
+
+ 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->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 5ee3048..5c4cb97 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 50f4186..8b205e0 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 26ab7e4..a232ab2 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 c32c089..870164c 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 8af7443..6a07a5f 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 3064124..4b2701f 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 7234ee8..c3f245e 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 1aa80cf..2e9ec4e 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 f4670c1..aa29357 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 b7e113c..043fd72 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
*/
@@ -229,8 +229,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;
@@ -357,7 +360,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 42328af..36f9f91 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 da3efb4..19b0e93 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 2f63fc2..15119a1 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 36384fb..7639a0f 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 0000000..540ac29
--- /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 * 8);
+ 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 d35cf2a..4743d78 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
*/
diff --git a/libavcodec/s3tc.h b/libavcodec/s3tc.h
index 25237b9..2d77b3a 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 0000000..7705f93
--- /dev/null
+++ b/libavcodec/samidec.c
@@ -0,0 +1,160 @@
+/*
+ * 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++;
+ }
+ 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 41c6551..9e5ec54 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 a47ad6e..e28fccd 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 b7917dc..e4f053b 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 07235c6..1c1bcdf 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 3c47d3a..5ec891e 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 ebca2e8..3ddbf77 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 bfc0995..21026af 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;
@@ -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 d7bc5a9..69d012e 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 0000000..8dd61fe
--- /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 c93ba6b..4c9cc06 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;
}
@@ -175,13 +178,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 +200,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 +221,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 +247,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 +262,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 },
@@ -429,13 +425,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 +441,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 +505,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 +562,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 +601,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 +677,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 f61e9e6..eeb6279 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 7f14aae..154e297 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 b287c4f..789db8d 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 be38dbc..1fa0e95 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 478036d..2268fd5 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 90a75c2..561ae3e 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 1ee225b..2b9c4f2 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 98607f2..4cb9485 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 4cdea67..34f7f99 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 f7fcb34..9c8f684 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 ec60c29..16a653d 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 92037a4..0dbc113 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 ba69303..518bdad 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,19 @@ 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;
+ 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 +641,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 +660,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 +708,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 +736,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 +760,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 +778,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 46903ab..01271b3 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
*/
@@ -70,7 +70,7 @@ typedef struct SmcContext {
row_ptr += stride * 4; \
} \
total_blocks--; \
- if (total_blocks < 0) \
+ if (total_blocks < 0 + !!n_blocks) \
{ \
av_log(s->avctx, AV_LOG_INFO, "warning: block counter just went negative (this should not happen)\n"); \
return; \
@@ -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 0000000..69327cd
--- /dev/null
+++ b/libavcodec/smvjpegdec.c
@@ -0,0 +1,209 @@
+/*
+ * 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 PixelFormat 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_init(AVCodecContext *avctx)
+{
+ SMVJpegDecodeContext *s = avctx->priv_data;
+ AVCodec *codec;
+ AVDictionary *thread_opt = NULL;
+ int ret = 0;
+
+ 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])
+ 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 = -1;
+ }
+
+ codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG);
+ if (!codec) {
+ av_log(avctx, AV_LOG_ERROR, "MJPEG codec not found\n");
+ ret = -1;
+ }
+
+ 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 (ff_codec_open2_recursive(s->avctx, codec, &thread_opt) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "MJPEG codec failed to open\n");
+ ret = -1;
+ }
+ av_dict_free(&thread_opt);
+
+ 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);
+ } 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 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 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 0000000..3701707
--- /dev/null
+++ b/libavcodec/snow.c
@@ -0,0 +1,723 @@
+/*
+ * 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
+
+ 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>>= s->chroma_h_shift;
+ 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 ? s->avctx->width >>s->chroma_h_shift : s->avctx->width;
+ int h= is_chroma ? s->avctx->height>>s->chroma_v_shift : s->avctx->height;
+ int ls= frame->linesize[p];
+ uint8_t *src= frame->data[p];
+
+ halfpel[1][p] = (uint8_t*) av_malloc(ls * (h + 2 * EDGE_WIDTH)) + EDGE_WIDTH * (1 + ls);
+ halfpel[2][p] = (uint8_t*) av_malloc(ls * (h + 2 * EDGE_WIDTH)) + EDGE_WIDTH * (1 + ls);
+ halfpel[3][p] = (uint8_t*) av_malloc(ls * (h + 2 * EDGE_WIDTH)) + EDGE_WIDTH * (1 + ls);
+ if (!halfpel[1][p] || !halfpel[2][p] || !halfpel[3][p])
+ return AVERROR(ENOMEM);
+
+ 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]));
+ }
+}
+
+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 < s->nb_planes; plane_index++){
+ 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];
+
+ 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 0000000..6f1fca3
--- /dev/null
+++ b/libavcodec/snow.h
@@ -0,0 +1,719 @@
+/*
+ * 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 "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;
+
+ 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;
+}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 0000000..63ff7a0
--- /dev/null
+++ b/libavcodec/snow_dwt.c
@@ -0,0 +1,865 @@
+/*
+ * 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;
+ 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);
+
+ 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 inline int mirror(int v, int m)
+{
+ while ((unsigned)v > (unsigned)m) {
+ v = -v;
+ if (v < 0)
+ v += 2 * m;
+ }
+ return v;
+}
+
+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 + mirror(-2 - 1, height - 1) * stride;
+ DWTELEM *b1 = buffer + mirror(-2, height - 1) * stride;
+
+ for (y = -2; y < height; y += 2) {
+ DWTELEM *b2 = buffer + mirror(y + 1, height - 1) * stride;
+ DWTELEM *b3 = buffer + 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 + mirror(-4 - 1, height - 1) * stride;
+ DWTELEM *b1 = buffer + mirror(-4, height - 1) * stride;
+ DWTELEM *b2 = buffer + mirror(-4 + 1, height - 1) * stride;
+ DWTELEM *b3 = buffer + mirror(-4 + 2, height - 1) * stride;
+
+ for (y = -4; y < height; y += 2) {
+ DWTELEM *b4 = buffer + mirror(y + 3, height - 1) * stride;
+ DWTELEM *b5 = buffer + 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,
+ mirror(-1 - 1, height - 1) * stride_line);
+ cs->b1 = slice_buffer_get_line(sb, 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 + mirror(-1 - 1, height - 1) * stride;
+ cs->b1 = buffer + 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,
+ mirror(y + 1, height - 1) *
+ stride_line);
+ IDWTELEM *b3 = slice_buffer_get_line(sb,
+ 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 + mirror(y + 1, height - 1) * stride;
+ IDWTELEM *b3 = buffer + 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, mirror(-3 - 1, height - 1) * stride_line);
+ cs->b1 = slice_buffer_get_line(sb, mirror(-3, height - 1) * stride_line);
+ cs->b2 = slice_buffer_get_line(sb, mirror(-3 + 1, height - 1) * stride_line);
+ cs->b3 = slice_buffer_get_line(sb, 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 + mirror(-3 - 1, height - 1) * stride;
+ cs->b1 = buffer + mirror(-3, height - 1) * stride;
+ cs->b2 = buffer + mirror(-3 + 1, height - 1) * stride;
+ cs->b3 = buffer + 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,
+ mirror(y + 3, height - 1) *
+ stride_line);
+ IDWTELEM *b5 = slice_buffer_get_line(sb,
+ 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 + mirror(y + 3, height - 1) * stride;
+ IDWTELEM *b5 = buffer + 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 ff_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 ff_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;
+ ff_spatial_idwt_init(cs, buffer, width, height, stride, type,
+ decomposition_count);
+ for (y = 0; y < height; y += 4)
+ ff_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, int 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, int 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, int 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, int 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, int 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, int 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, int line_size, int h)
+{
+ return w_c(v, pix1, pix2, line_size, 32, h, 0);
+}
+
+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;
+}
+
+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 0000000..e929189
--- /dev/null
+++ b/libavcodec/snow_dwt.h
@@ -0,0 +1,127 @@
+/*
+ * 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 <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, int line_size, int h);
+int ff_w97_32_c(struct MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, int 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 0000000..490fdf8
--- /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 0000000..327157b
--- /dev/null
+++ b/libavcodec/snowdec.c
@@ -0,0 +1,606 @@
+/*
+ * 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);
+ }
+}
+
+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];
+ int 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) {
+ ff_snow_common_end(avctx->priv_data);
+ 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;
+ //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
+ );
+
+ 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)
+ 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*/,
+};
diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c
new file mode 100644
index 0000000..c790d9b
--- /dev/null
+++ b/libavcodec/snowenc.c
@@ -0,0 +1,2025 @@
+/*
+ * 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) {
+ ff_snow_common_end(avctx->priv_data);
+ return ret;
+ }
+ ff_mpegvideoencdsp_init(&s->mpvencdsp, avctx);
+
+ ff_snow_alloc_blocks(s);
+
+ s->version=0;
+
+ s->m.avctx = avctx;
+ s->m.flags = avctx->flags;
+ 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();
+ if (!s->input_picture)
+ 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( ROUNDED_DIV(ab<<LOG2_OBMC_MAX, aa), 0, 255); //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);
+
+//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{
+ 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, block->mx+4*(i-j), block->my+(4*j), obmc_edged, &best_rd);
+ dia_change |= check_block_inter(s, mb_x, mb_y, block->mx-4*(i-j), block->my-(4*j), obmc_edged, &best_rd);
+ dia_change |= check_block_inter(s, mb_x, mb_y, block->mx+4*(i-j), block->my-(4*j), obmc_edged, &best_rd);
+ dia_change |= check_block_inter(s, mb_x, mb_y, block->mx-4*(i-j), block->my+(4*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_ERROR, "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<(height>>vshift); y++)
+ memcpy(&s->input_picture->data[i][y * s->input_picture->linesize[i]],
+ &pict->data[i][y * pict->linesize[i]],
+ width>>hshift);
+ s->mpvencdsp.draw_edges(s->input_picture->data[i], s->input_picture->linesize[i],
+ width >> hshift, 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);
+ avctx->coded_frame= s->current_picture;
+
+ 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.flags= s->avctx->flags;
+ 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_free(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 },
+ { 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,
+};
+
+
+#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(width * sizeof(DWTELEM));
+ s.temp_idwt_buffer = av_mallocz(width * sizeof(IDWTELEM));
+
+ 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 0000000..a5e573a
--- /dev/null
+++ b/libavcodec/sonic.c
@@ -0,0 +1,1094 @@
+/*
+ * 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 void 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));
+
+ 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);
+}
+
+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));
+ 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)
+ 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
+ modified_levinson_durbin(s->window, s->window_size,
+ s->predictor_k, s->num_taps, s->channels, s->tap_quant);
+ 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)
+ {
+ s->channels = get_bits(&gb, 2);
+ s->samplerate = samplerate_table[get_bits(&gb, 4)];
+ av_log(avctx, AV_LOG_INFO, "Sonicv2 chans: %d samprate: %d\n",
+ s->channels, s->samplerate);
+ }
+
+ if (s->channels > MAX_CHANNELS)
+ {
+ 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));
+ 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));
+
+ 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 1577302..ecd6e8d 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 ca6b9fd..7496198 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
*/
@@ -72,7 +72,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)
@@ -90,9 +90,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)"),
@@ -103,8 +104,10 @@ AVCodec ff_sp5x_decoder = {
.close = ff_mjpeg_decode_end,
.decode = sp5x_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
};
-
+#endif
+#if CONFIG_AMV_DECODER
AVCodec ff_amv_decoder = {
.name = "amv",
.long_name = NULL_IF_CONFIG_SMALL("AMV Video"),
@@ -114,4 +117,6 @@ AVCodec ff_amv_decoder = {
.init = ff_mjpeg_decode_init,
.close = ff_mjpeg_decode_end,
.decode = sp5x_decode_frame,
+ .max_lowres = 3,
};
+#endif
diff --git a/libavcodec/sparc/README b/libavcodec/sparc/README
new file mode 100644
index 0000000..f9f2349
--- /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 bbc8061..6d0c9bb 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 {
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];
@@ -60,13 +67,12 @@ static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
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);
+ av_bprintf(dst, "{\\an1}{\\move(%d,%d,%d,%d)}", x1, y1, x2, y2);
else
- out += snprintf(out, out_end-out, "{\\an1}{\\pos(%d,%d)}", x1, y1);
+ av_bprintf(dst, "{\\an1}{\\pos(%d,%d)}", x1, y1);
}
- for (; out < out_end && !end && *in; in++) {
+ for (; !end && *in; in++) {
switch (*in) {
case '\r':
break;
@@ -75,27 +81,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 +117,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 +152,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 +164,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 +172,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 0000000..3287970
--- /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 d34981e..940bbb7 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 f38ce54..cfa02b0 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 0000000..a008828
--- /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 ffa685c..d9918f4 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((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 d9fe307..d162e63 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 8e90a6c..cff8c85 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 545df80..909b0bf 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 70b5c37..88d61d1 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 e0d2154..b821a44 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 e22cd60..41485d2 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 834279d..f5d298d 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 14ff41c..052b618 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
*/
@@ -114,12 +114,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 +154,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)
@@ -345,8 +344,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 +387,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 +399,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 +407,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 +415,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 +499,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 +511,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 +519,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 +554,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 +571,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 +592,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 +619,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);
@@ -637,7 +636,7 @@ static int svq1_decode_frame(AVCodecContext *avctx, void *data,
return AVERROR_INVALIDDATA;
}
- av_fast_malloc(s->pkt_swapped, &s->pkt_swapped_allocated,
+ av_fast_padded_malloc(&s->pkt_swapped, &s->pkt_swapped_allocated,
buf_size);
if (!s->pkt_swapped)
return AVERROR(ENOMEM);
@@ -649,12 +648,14 @@ static int svq1_decode_frame(AVCodecContext *avctx, void *data,
src = (uint32_t *)(s->pkt_swapped + 4);
+ if (buf_size < 36)
+ return AVERROR_INVALIDDATA;
+
for (i = 0; i < 4; i++)
src[i] = ((src[i] << 16) | (src[i] >> 16)) ^ src[7 - i];
}
result = svq1_decode_frame_header(avctx, cur);
-
if (result != 0) {
av_dlog(avctx, "Error in svq1_decode_frame_header %i\n", result);
return result;
@@ -699,8 +700,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;
@@ -818,6 +819,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 d70bba3..288da1f 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];
+ DECLARE_ALIGNED(16, int16_t, block)[7][256];
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);
@@ -327,8 +335,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);
}
@@ -353,8 +360,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;
@@ -368,8 +375,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] &
@@ -410,10 +416,10 @@ 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);
+ 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, mx - pred_x, 1);
ff_h263_encode_motion(&s->m, my - pred_y, 1);
s->reorder_pb[5] = s->m.pb;
@@ -421,12 +427,12 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane,
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];
@@ -437,8 +443,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]);
}
}
@@ -462,6 +466,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]);
@@ -567,12 +572,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");
@@ -580,13 +582,11 @@ 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 ||
+ (ret = ff_get_buffer(avctx, s->last_picture, 0)) < 0) {
return ret;
- ret = ff_get_buffer(avctx, s->last_picture, 0);
- if (ret < 0)
- return ret;
- s->scratchbuf = av_malloc(s->current_picture->linesize[0] * 16 * 2);
+ }
+ s->scratchbuf = av_malloc(s->current_picture->linesize[0] * 16 * 3);
}
FFSWAP(AVFrame*, s->current_picture, s->last_picture);
diff --git a/libavcodec/svq1enc.h b/libavcodec/svq1enc.h
index 516e875..740d2ff 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
*/
@@ -69,7 +69,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 a5cd179..1edb4ec 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 fc2120b..9459329 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>
@@ -80,6 +81,8 @@ typedef struct {
int unknown_flag;
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;
@@ -617,7 +624,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;
@@ -687,7 +694,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;
}
@@ -803,8 +810,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);
}
@@ -838,8 +845,8 @@ static int svq3_decode_slice_header(AVCodecContext *avctx)
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 (h->mb_x > 0) {
@@ -868,25 +875,25 @@ 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;
}
- if (ff_h264_decode_init(avctx) < 0)
- return -1;
+ if ((ret = ff_h264_decode_init(avctx)) < 0)
+ goto fail;
ff_hpeldsp_init(&s->hdsp, avctx->flags);
ff_tpeldsp_init(&s->tdsp);
h->flags = avctx->flags;
h->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;
@@ -917,8 +924,10 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
int frame_size_code;
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' */
@@ -972,8 +981,10 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
/* unknown field */
skip_bits1(&gb);
- 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);
avctx->has_b_frames = !h->low_delay;
@@ -990,9 +1001,11 @@ 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);
av_log(avctx, AV_LOG_DEBUG, "watermark size: %ux%u\n",
@@ -1005,7 +1018,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;
@@ -1015,7 +1029,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
}
}
@@ -1030,12 +1045,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)
@@ -1105,10 +1123,11 @@ 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;
int buf_size = avpkt->size;
+ int left;
+ uint8_t *buf;
int ret, m, i;
/* special case for last picture */
@@ -1123,10 +1142,20 @@ static int svq3_decode_frame(AVCodecContext *avctx, void *data,
return 0;
}
- init_get_bits(&h->gb, buf, 8 * buf_size);
-
h->mb_x = h->mb_y = h->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;
@@ -1147,7 +1176,7 @@ static int svq3_decode_frame(AVCodecContext *avctx, void *data,
h->cur_pic_ptr = s->cur_pic;
av_frame_unref(&h->cur_pic.f);
- h->cur_pic = *s->cur_pic;
+ memcpy(&h->cur_pic.tf, &s->cur_pic->tf, sizeof(h->cur_pic) - offsetof(H264Picture, tf));
ret = av_frame_ref(&h->cur_pic.f, &s->cur_pic->f);
if (ret < 0)
return ret;
@@ -1166,6 +1195,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;
@@ -1178,6 +1208,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;
@@ -1267,7 +1298,7 @@ static int svq3_decode_frame(AVCodecContext *avctx, void *data,
return -1;
}
- if (mb_type != 0)
+ if (mb_type != 0 || h->cbp)
ff_h264_hl_decode_mb(h);
if (h->pict_type != AV_PICTURE_TYPE_B && !h->low_delay)
@@ -1281,6 +1312,18 @@ static int svq3_decode_frame(AVCodecContext *avctx, void *data,
h->low_delay);
}
+ left = buf_size*8 - get_bits_count(&h->gb);
+
+ if (h->mb_y != h->mb_height || h->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, h->mb_y, h->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])
@@ -1317,6 +1360,10 @@ static av_cold int svq3_decode_end(AVCodecContext *avctx)
ff_h264_free_context(h);
+ av_freep(&s->buf);
+ s->buf_size = 0;
+ av_freep(&h->edge_emu_buffer);
+
return 0;
}
diff --git a/libavcodec/svq3.h b/libavcodec/svq3.h
index a20e620..5007a8c 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 d0ace40..d49ffe6 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 f842c70..b63fd77 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 daa89fe..5107912 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); \
diff --git a/libavcodec/tak.c b/libavcodec/tak.c
index 867a84b..ed41ca8 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 fa91149..e8e2dac 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 295df24..5d8460c 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)
@@ -67,23 +61,22 @@ 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 (!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 +84,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 +93,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 +117,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 b0e84ea..5810a01 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(v >> filter_quant, -8192, 8191) << dshift) - *decoded;
+ *decoded++ = v;
+ s->residues[filter_order + i] = v >> dshift;
+ }
- v = (av_clip(v >> filter_quant, -8192, 8191) << 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(v >> 10, -8192, 8191) << dshift) - *p1;
+ *p1++ = v;
+ }
- p1[i] = (av_clip(v >> 10, -8192, 8191) << 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);
@@ -765,7 +760,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) {
@@ -774,9 +769,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);
@@ -864,7 +859,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");
@@ -905,12 +900,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;
}
@@ -922,10 +935,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 f077c03..b0c9b55 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 f4ef553..c2f5224 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 0000000..5f4eeaa
--- /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 7679029..d4483ec 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/textdec.c b/libavcodec/textdec.c
new file mode 100644
index 0000000..c9f02a2
--- /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 864e67e..c848d7a 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 33b2579..7c62208 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 3b2fc7d..0870e31 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,12 @@
#if CONFIG_ZLIB
#include <zlib.h>
#endif
+#if CONFIG_LZMA
+#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 +43,8 @@
#include "lzw.h"
#include "mathops.h"
#include "tiff.h"
+#include "tiff_data.h"
+#include "thread.h"
typedef struct TiffContext {
AVCodecContext *avctx;
@@ -52,33 +57,260 @@ typedef struct TiffContext {
int le;
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)
{
- return le ? bytestream2_get_le16(gb) : bytestream2_get_be16(gb);
+ 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 unsigned tget_long(GetByteContext *gb, int le)
+static int add_metadata(int count, int type,
+ const char *name, const char *sep, TiffContext *s, AVFrame *frame)
{
- return le ? bytestream2_get_le32(gb) : bytestream2_get_be32(gb);
+ 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 unsigned tget(GetByteContext *gb, int type, int le)
+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)
{
- 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;
+ 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 int deinvert_buffer(TiffContext *s, const uint8_t *src, int size)
+{
+ 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 void unpack_yuv(TiffContext *s, AVFrame *p,
+ const uint8_t *src, int lnum)
+{
+ 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++;
+ }
}
}
@@ -89,7 +321,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;
@@ -104,9 +336,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;
@@ -115,6 +347,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,
@@ -125,7 +364,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;
}
@@ -134,11 +381,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);
@@ -161,23 +473,54 @@ 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;
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, "
@@ -185,7 +528,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;
@@ -197,6 +558,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;
@@ -204,59 +571,128 @@ 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;
- switch (s->bpp * 10 + s->bppcount) {
+ 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;
@@ -271,7 +707,22 @@ 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;
+ break;
+ case 1243:
+ s->avctx->pix_fmt = AV_PIX_FMT_GBRP;
+ break;
+ case 1324:
+ s->avctx->pix_fmt = AV_PIX_FMT_GBRAP;
+ break;
+ case 1483:
+ s->avctx->pix_fmt = s->le ? AV_PIX_FMT_GBRP16LE : AV_PIX_FMT_GBRP16BE;
+ break;
+ case 1644:
+ s->avctx->pix_fmt = s->le ? AV_PIX_FMT_GBRAP16LE : AV_PIX_FMT_GBRAP16BE;
break;
default:
av_log(s->avctx, AV_LOG_ERROR,
@@ -279,64 +730,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)
{
- unsigned tag, type, count, off, value = 0;
+ 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, 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) {
@@ -347,31 +814,37 @@ 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;
}
}
+ 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;
+ }
break;
case TIFF_SAMPLES_PER_PIXEL:
if (count != 1) {
@@ -379,6 +852,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;
@@ -409,8 +887,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);
@@ -444,6 +926,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;
@@ -453,11 +946,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:
@@ -489,25 +982,32 @@ 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;
break;
}
case TIFF_PLANAR:
- if (value == 2) {
- avpriv_report_missing_feature(s->avctx, "Planar format");
- return AVERROR_PATCHWELCOME;
+ 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)
@@ -517,6 +1017,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,
@@ -525,6 +1156,7 @@ static int tiff_decode_tag(TiffContext *s)
return AVERROR_INVALIDDATA;
}
}
+end:
bytestream2_seek(&s->gb, start, SEEK_SET);
return 0;
}
@@ -534,8 +1166,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;
+ int le, ret, plane, planes;
int i, j, entries, stride;
unsigned soff, ssize;
uint8_t *dst;
@@ -545,78 +1178,93 @@ 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) {
av_log(avctx, AV_LOG_WARNING, "Image data size missing\n");
s->stripsize = avpkt->size - s->stripoff;
}
- stride = p->linesize[0];
- dst = p->data[0];
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;
@@ -624,7 +1272,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;
@@ -633,16 +1281,28 @@ static int decode_frame(AVCodecContext *avctx,
dst += s->rps * stride;
}
if (s->predictor == 2) {
- dst = p->data[0];
+ 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) {
+ if (s->avctx->pix_fmt == AV_PIX_FMT_RGB48LE ||
+ s->avctx->pix_fmt == AV_PIX_FMT_RGBA64LE ||
+ 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) {
+ } 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_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));
@@ -658,13 +1318,22 @@ static int decode_frame(AVCodecContext *avctx,
}
if (s->photometric == TIFF_PHOTOMETRIC_WHITE_IS_ZERO) {
- dst = p->data[0];
+ dst = p->data[plane];
for (i = 0; i < s->height; i++) {
- for (j = 0; j < p->linesize[0]; j++)
- dst[j] = 255 - dst[j];
+ for (j = 0; j < p->linesize[plane]; j++)
+ dst[j] = (s->avctx->pix_fmt == AV_PIX_FMT_PAL8 ? (1<<s->bpp) - 1 : 255) - dst[j];
dst += stride;
}
}
+ }
+
+ if (s->planar && s->bppcount > 2) {
+ FFSWAP(uint8_t*, p->data[0], p->data[2]);
+ FFSWAP(int, p->linesize[0], p->linesize[2]);
+ FFSWAP(uint8_t*, p->data[0], p->data[1]);
+ FFSWAP(int, p->linesize[0], p->linesize[1]);
+ }
+
*got_frame = 1;
return avpkt->size;
@@ -676,6 +1345,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();
@@ -687,7 +1358,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;
}
@@ -700,5 +1374,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 68ac695..3f692af 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 0000000..35119af
--- /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 0000000..03558c3
--- /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 0000000..88c2256
--- /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 0000000..57515f9
--- /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 b28f72b..38ff780 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 void 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);
- check_size(s, count * type_sizes2[type]);
+ check_size(s, count * (int64_t)type_sizes2[type]);
tnput(s->buf, count, ptr_val, type, 0);
}
@@ -143,14 +154,14 @@ static void 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, -1 returned
+ * @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, -1 is returned
*/
static int encode_strip(TiffEncoderContext *s, const int8_t *src,
uint8_t *dst, int n, int compr)
@@ -190,84 +201,86 @@ 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++;
+ }
}
}
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 };
- int ret;
- int is_yuv = 0;
- uint8_t *yuv_line = NULL;
+ uint32_t res[2] = { s->dpi, 1 }; // image resolution (72/1)
+ uint16_t bpp_tab[4];
+ int ret = -1;
+ 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_RGB48LE:
- case AV_PIX_FMT_GRAY16LE:
+ case AV_PIX_FMT_RGBA64LE:
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:
+ alpha = avctx->pix_fmt == AV_PIX_FMT_GRAY8A;
+ 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:
@@ -276,6 +289,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return -1;
}
+ 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)
@@ -289,14 +305,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;
@@ -312,18 +327,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;
@@ -342,12 +360,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,
@@ -361,9 +379,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) {
@@ -372,17 +391,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],
@@ -391,17 +410,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);
+ }
s->num_entries = 0;
@@ -414,14 +434,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);
@@ -439,10 +466,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
@@ -461,33 +492,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" },
@@ -513,14 +551,15 @@ 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_GRAY8, AV_PIX_FMT_GRAY16LE,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_PAL8, AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_GRAY8A, AV_PIX_FMT_GRAY16LE,
AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_MONOWHITE,
- AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P,
- 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_YUV410P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_RGB48LE,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_RGBA64LE,
AV_PIX_FMT_NONE
},
.priv_class = &tiffenc_class,
diff --git a/libavcodec/tmv.c b/libavcodec/tmv.c
index f04a5f5..e525a73 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 7ea1da4..cc4fed3 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 9c67d60..3732f17 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 5dffb4e..660ecf5 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 e950450..3e58143 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 122643d..18d7c1e 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;
@@ -973,6 +1005,8 @@ static av_cold int decode_end(AVCodecContext *avctx)
av_free(l->U2_base);
av_free(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 34b7c3b..b00a45f 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 6e9806a..73ebda5 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 8619934..628a6b3 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 */
@@ -134,7 +135,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
break;
case 32: avctx->pix_fmt = AV_PIX_FMT_RGB32; 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 bd1854b..92210f7 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 70a06e5..4586da7 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 4d2e2a0..5fdbac8 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_free(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 0000000..bf793a4
--- /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 0000000..48c4cd0
--- /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 0000000..30b7ab9
--- /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 0000000..56930f1
--- /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 0000000..ccd41a9
--- /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 e1b1c7b..f117220 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
*/
@@ -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);
diff --git a/libavcodec/twinvq.h b/libavcodec/twinvq.h
index 7601e5b..c4e9688 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
*/
diff --git a/libavcodec/twinvq_data.h b/libavcodec/twinvq_data.h
index 01a54a5..375acc2 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 65028a6..67ce031 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
*/
@@ -312,7 +312,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 8f12291..ad1a015 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) < (w/4) * (h/4) * 8)
+ return AVERROR_INVALIDDATA;
ff_decode_dxt1(&gb, ptr, w, h, stride);
break;
case FF_S3TC_DXT3:
+ if (bytestream2_get_bytes_left(&gb) < (w/4) * (h/4) * 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 186f1a6..6b76214 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 0bd83ff..7061d83 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 d14929f..908dc93 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 8cbd47b..bf2a5b9 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,121 @@
#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
+
+#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 +195,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 +216,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 +229,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 +273,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:
@@ -198,6 +294,7 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
case AV_PIX_FMT_YUV422P:
case AV_PIX_FMT_YUV440P:
case AV_PIX_FMT_YUV444P:
+ case AV_PIX_FMT_GBRAP:
case AV_PIX_FMT_GBRP:
case AV_PIX_FMT_GRAY8:
case AV_PIX_FMT_GRAY16BE:
@@ -213,26 +310,65 @@ 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_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;
@@ -242,18 +378,25 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
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) ||
@@ -262,16 +405,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++)
@@ -293,6 +445,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)
@@ -307,7 +482,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 {
@@ -315,10 +490,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) {
@@ -373,7 +548,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;
@@ -387,7 +565,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;
@@ -434,17 +612,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]);
@@ -506,6 +686,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;
@@ -529,39 +732,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[] = {
@@ -570,56 +745,52 @@ int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame)
{ AV_PKT_DATA_STEREO3D, AV_FRAME_DATA_STEREO3D },
};
- 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,
@@ -627,8 +798,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)
@@ -651,19 +820,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 && hwaccel->alloc_frame) {
ret = hwaccel->alloc_frame(avctx, frame);
@@ -673,7 +895,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
@@ -696,7 +918,7 @@ FF_DISABLE_DEPRECATION_WARNINGS
* avcodec_default_get_buffer
*/
if (frame->buf[0])
- return 0;
+ goto end0;
priv = av_mallocz(sizeof(*priv));
if (!priv) {
@@ -753,7 +975,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);
@@ -772,6 +994,7 @@ do { \
av_buffer_unref(&dummy_buf);
+end0:
frame->width = avctx->width;
frame->height = avctx->height;
@@ -797,13 +1020,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);
@@ -828,9 +1067,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);
}
@@ -865,6 +1114,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);
@@ -955,6 +1215,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;
@@ -975,30 +1237,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)
@@ -1007,6 +1259,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);
+ return ret;
+}
+
int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
{
int ret = 0;
@@ -1016,12 +1320,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)
@@ -1033,18 +1337,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) {
- av_log(avctx, AV_LOG_ERROR, "insufficient thread locking around avcodec_open/close()\n");
- ret = -1;
- goto end;
- }
+ ret = ff_lock_avcodec(avctx);
+ if (ret < 0)
+ return ret;
avctx->internal = av_mallocz(sizeof(AVCodecInternal));
if (!avctx->internal) {
@@ -1084,17 +1379,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);
}
@@ -1126,14 +1431,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;
}
@@ -1144,7 +1460,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);
+ 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;
@@ -1153,6 +1481,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) {
@@ -1167,7 +1508,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;
}
@@ -1176,12 +1520,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)
@@ -1192,60 +1542,93 @@ 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 ( 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;
}
}
@@ -1254,19 +1637,51 @@ 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);
- }
+ ff_unlock_avcodec();
if (options) {
av_dict_free(options);
*options = tmp;
@@ -1285,10 +1700,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;
@@ -1298,8 +1734,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
@@ -1311,10 +1749,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.
*/
@@ -1328,6 +1774,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)
@@ -1359,10 +1806,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;
@@ -1383,28 +1831,36 @@ 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;
}
/* 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;
}
@@ -1425,9 +1881,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;
}
@@ -1448,6 +1929,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;
@@ -1456,16 +1938,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);
@@ -1479,14 +2089,40 @@ int attribute_align_arg avcodec_encode_video2(AVCodecContext *avctx,
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;
}
@@ -1496,6 +2132,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;
@@ -1509,13 +2147,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;
@@ -1573,6 +2246,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;
@@ -1591,7 +2276,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) {
@@ -1614,50 +2299,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);
@@ -1666,53 +2376,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);
+ av_log(avctx, AV_LOG_DEBUG, "skip %d samples due to side data\n",
+ avctx->internal->skip_samples);
+ discard_padding = AV_RL32(side + 4);
+ 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",
+ 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)
@@ -1722,21 +2600,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;
}
@@ -1761,14 +2796,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]);
@@ -1793,10 +2837,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) {
@@ -1848,27 +2921,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)
@@ -1878,7 +2948,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,
@@ -1893,75 +2963,91 @@ 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_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 (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 (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 (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",
@@ -1979,7 +3065,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);
}
@@ -1996,20 +3082,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);
@@ -2019,18 +3093,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) {
@@ -2045,6 +3127,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);
}
}
@@ -2063,18 +3148,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)
@@ -2084,6 +3181,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);
}
@@ -2091,20 +3191,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:
@@ -2133,6 +3242,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) {
@@ -2163,8 +3293,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 */
@@ -2173,16 +3303,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;
@@ -2223,6 +3353,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 */
@@ -2233,6 +3367,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;
@@ -2254,6 +3392,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) {
@@ -2271,11 +3412,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);
}
@@ -2285,8 +3430,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;
@@ -2295,6 +3444,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;
}
@@ -2331,7 +3491,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);
@@ -2348,8 +3508,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);
}
@@ -2357,14 +3517,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)
@@ -2404,6 +3565,39 @@ int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op))
return 0;
}
+int ff_lock_avcodec(AVCodecContext *log_ctx)
+{
+ if (lockmgr_cb) {
+ if ((*lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN))
+ return -1;
+ }
+ entangled_thread_counter++;
+ if (entangled_thread_counter != 1) {
+ av_log(log_ctx, AV_LOG_ERROR, "Insufficient thread locking around avcodec_open/close()\n");
+ 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;
+ entangled_thread_counter--;
+ if (lockmgr_cb) {
+ if ((*lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE))
+ return -1;
+ }
+
+ return 0;
+}
+
int avpriv_lock_avformat(void)
{
if (lockmgr_cb) {
@@ -2427,7 +3621,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)
@@ -2451,6 +3645,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;
@@ -2475,10 +3674,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)
@@ -2496,13 +3723,31 @@ 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;
+ 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 eb5a924..308adb7 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 718273c..78c3ec5 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 7d75c59..b565c10 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;
@@ -224,7 +225,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];
@@ -284,7 +285,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];
@@ -335,12 +336,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 8dc208b..355fdb1 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
*/
@@ -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 8827397..ae03952 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)
+ 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)
+ 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 0000000..a8db7d6
--- /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 v210_x86_init(V210DecContext *s);
+
+#endif /* AVCODEC_V210DEC_H */
diff --git a/libavcodec/v210enc.c b/libavcodec/v210enc.c
index ef0d6ab..1e53bdb 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
*/
@@ -57,10 +57,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const uint16_t *v = (const uint16_t*)pic->data[2];
PutByteContext p;
- if ((ret = ff_alloc_packet(pkt, avctx->height * stride)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, avctx->height * stride)) < 0)
return ret;
- }
bytestream2_init_writer(&p, pkt->data, pkt->size);
@@ -88,13 +86,13 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
val = CLIP(*y++);
if (w == avctx->width - 2)
bytestream2_put_le32u(&p, val);
- }
- if (w < avctx->width - 3) {
- val |= (CLIP(*u++) << 10) | (CLIP(*y++) << 20);
- bytestream2_put_le32u(&p, val);
+ if (w < avctx->width - 3) {
+ val |= (CLIP(*u++) << 10) | (CLIP(*y++) << 20);
+ bytestream2_put_le32u(&p, val);
- val = CLIP(*v++) | (CLIP(*y++) << 10);
- bytestream2_put_le32u(&p, val);
+ val = CLIP(*v++) | (CLIP(*y++) << 10);
+ bytestream2_put_le32u(&p, val);
+ }
}
bytestream2_set_buffer(&p, 0, line_padding);
diff --git a/libavcodec/v210x.c b/libavcodec/v210x.c
index 2922c05..6330715 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 0000000..1d31f0a
--- /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 0000000..c6c5ac5
--- /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_freep(&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 0000000..be442fa
--- /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 0000000..20f08c7
--- /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_freep(&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 07be502..e7a9c0e 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 77b32d7..0e2e82a 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;
diff --git a/libavcodec/vaapi.c b/libavcodec/vaapi.c
index b2dc41d..db4d29d 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;
@@ -194,26 +197,4 @@ void ff_vaapi_common_end_frame(AVCodecContext *avctx)
vactx->slice_params_alloc = 0;
}
-int ff_vaapi_mpeg_end_frame(AVCodecContext *avctx)
-{
- struct vaapi_context * const vactx = avctx->hwaccel_context;
- MpegEncContext *s = avctx->priv_data;
- int ret;
-
- ret = ff_vaapi_commit_slices(vactx);
- if (ret < 0)
- goto finish;
-
- ret = ff_vaapi_render_picture(vactx,
- ff_vaapi_get_surface_id(s->current_picture_ptr->f));
- if (ret < 0)
- goto finish;
-
- ff_mpeg_draw_horiz_band(s, 0, s->avctx->height);
-
-finish:
- ff_vaapi_common_end_frame(avctx);
- return ret;
-}
-
/* @} */
diff --git a/libavcodec/vaapi.h b/libavcodec/vaapi.h
index 39e8825..815a27e 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 651a50b..8eb8a66 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],
@@ -259,7 +259,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 d0fa7ae..918c718 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_mpeg.c b/libavcodec/vaapi_mpeg.c
new file mode 100644
index 0000000..63879e5
--- /dev/null
+++ b/libavcodec/vaapi_mpeg.c
@@ -0,0 +1,48 @@
+/*
+ * Video Acceleration API (video decoding)
+ * HW decode acceleration for MPEG-2, MPEG-4, H.264 and VC-1
+ *
+ * Copyright (C) 2013 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
+ */
+
+#include "avcodec.h"
+#include "vaapi_internal.h"
+
+int ff_vaapi_mpeg_end_frame(AVCodecContext *avctx)
+{
+ struct vaapi_context * const vactx = avctx->hwaccel_context;
+ MpegEncContext *s = avctx->priv_data;
+ int ret;
+
+ ret = ff_vaapi_commit_slices(vactx);
+ if (ret < 0)
+ goto finish;
+
+ ret = ff_vaapi_render_picture(vactx,
+ ff_vaapi_get_surface_id(s->current_picture_ptr->f));
+ if (ret < 0)
+ goto finish;
+
+ ff_mpeg_draw_horiz_band(s, 0, s->avctx->height);
+
+finish:
+ ff_vaapi_common_end_frame(avctx);
+ return ret;
+}
+
diff --git a/libavcodec/vaapi_mpeg2.c b/libavcodec/vaapi_mpeg2.c
index 31e0218..0d9059b 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
*/
@@ -116,8 +116,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 4ca1445..23556af 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
*/
@@ -124,25 +124,14 @@ static int vaapi_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer
av_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 8886b0b..bba46d3 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
*/
@@ -24,7 +24,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) {
@@ -128,7 +128,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 56094d8..3c89a29 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);
}
diff --git a/libavcodec/vble.c b/libavcodec/vble.c
index 4d5cd96..1bf25ba 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 {
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 6f11910..b3955f2 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
*/
@@ -47,21 +47,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 +122,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++;
@@ -293,7 +282,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 +293,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);
@@ -380,8 +370,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 +428,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 +490,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 +518,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 +527,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 +542,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))) {
@@ -601,32 +605,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 =
@@ -650,8 +666,8 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
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;
}
@@ -846,6 +862,8 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
v->numref = 0;
v->p_frame_skipped = 0;
if (v->second_field) {
+ if(v->fcm!=2 || v->field_mode!=1)
+ return -1;
v->s.pict_type = (v->fptype & 1) ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I;
if (v->fptype & 4)
v->s.pict_type = (v->fptype & 1) ? AV_PICTURE_TYPE_BI : AV_PICTURE_TYPE_B;
@@ -869,12 +887,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.mb_height = v->s.height + 15 >> 4;
switch (get_unary(gb, 0, 4)) {
@@ -905,6 +926,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 +939,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 +950,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 +963,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 */
}
@@ -1100,7 +1125,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);
@@ -1183,8 +1208,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;
}
@@ -1207,6 +1232,7 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
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);
diff --git a/libavcodec/vc1.h b/libavcodec/vc1.h
index 0c4958c..eefb613 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 acd5145..6f84228 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
*/
@@ -50,20 +50,6 @@ 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)
{
@@ -290,6 +276,7 @@ static av_always_inline void get_mvdata_interlaced(VC1Context *v, int *dmv_x,
}
}
else {
+ av_assert0(index < esc);
if (extend_x)
offs_tab = offset_table2;
else
@@ -759,7 +746,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;
@@ -971,7 +958,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;
@@ -1602,7 +1589,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);
@@ -1649,7 +1636,8 @@ static int vc1_decode_p_mb_intfr(VC1Context *v)
s->current_picture.motion_val[1][s->block_index[i]][1] = 0;
}
s->current_picture.mb_type[mb_pos] = MB_TYPE_INTRA;
- s->mb_intra = v->is_intra[s->mb_x] = 1;
+ s->mb_intra = 1;
+ v->is_intra[s->mb_x] = 0x3F;
for (i = 0; i < 6; i++)
v->mb_type[0][s->block_index[i]] = 1;
fieldtx = v->fieldtx_plane[mb_pos] = get_bits1(gb);
@@ -1810,15 +1798,16 @@ 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
- s->mb_intra = v->is_intra[s->mb_x] = 1;
+ s->mb_intra = 1;
+ v->is_intra[s->mb_x] = 0x3F;
s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][0] = 0;
s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][1] = 0;
s->current_picture.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA;
@@ -2088,14 +2077,15 @@ 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);
if (idx_mbmode <= 1) { // intra MB
- s->mb_intra = v->is_intra[s->mb_x] = 1;
+ s->mb_intra = 1;
+ v->is_intra[s->mb_x] = 0x3F;
s->current_picture.motion_val[1][s->block_index[0]][0] = 0;
s->current_picture.motion_val[1][s->block_index[0]][1] = 0;
s->current_picture.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA;
@@ -2144,6 +2134,7 @@ static void vc1_decode_b_mb_intfi(VC1Context *v)
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)
@@ -2166,12 +2157,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);
@@ -2279,6 +2274,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);
@@ -2314,7 +2311,8 @@ static int vc1_decode_b_mb_intfr(VC1Context *v)
s->mv[1][i][1] = s->current_picture.motion_val[1][s->block_index[i]][1] = 0;
}
s->current_picture.mb_type[mb_pos] = MB_TYPE_INTRA;
- s->mb_intra = v->is_intra[s->mb_x] = 1;
+ s->mb_intra = 1;
+ v->is_intra[s->mb_x] = 0x3F;
for (i = 0; i < 6; i++)
v->mb_type[0][s->block_index[i]] = 1;
fieldtx = v->fieldtx_plane[mb_pos] = get_bits1(gb);
diff --git a/libavcodec/vc1_common.h b/libavcodec/vc1_common.h
index 788d324..cd67b17 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
*/
diff --git a/libavcodec/vc1_loopfilter.c b/libavcodec/vc1_loopfilter.c
index 1b76d83..95c4519 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
*/
@@ -209,7 +209,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;
@@ -224,14 +224,14 @@ static av_always_inline void vc1_apply_p_v_loop_filter(VC1Context *v, int block_
if (block_num > 3) {
bottom_cbp = v->cbp[s->mb_x] >> (block_num * 4);
- bottom_is_intra = v->is_intra[s->mb_x] >> (block_num * 4);
+ bottom_is_intra = v->is_intra[s->mb_x] >> block_num;
mv = &v->luma_mv[s->mb_x - s->mb_stride];
mv_stride = s->mb_stride;
} else {
bottom_cbp = (block_num < 2) ? (mb_cbp >> ((block_num + 2) * 4))
: (v->cbp[s->mb_x] >> ((block_num - 2) * 4));
- bottom_is_intra = (block_num < 2) ? (mb_is_intra >> ((block_num + 2) * 4))
- : (v->is_intra[s->mb_x] >> ((block_num - 2) * 4));
+ bottom_is_intra = (block_num < 2) ? (mb_is_intra >> (block_num + 2))
+ : (v->is_intra[s->mb_x] >> (block_num - 2));
mv_stride = s->b8_stride;
mv = &s->current_picture.motion_val[0][s->block_index[block_num] - 2 * mv_stride];
}
@@ -273,7 +273,7 @@ static av_always_inline void vc1_apply_p_h_loop_filter(VC1Context *v, int block_
int mb_cbp = v->cbp[s->mb_x - 1 - s->mb_stride],
block_cbp = mb_cbp >> (block_num * 4), right_cbp,
mb_is_intra = v->is_intra[s->mb_x - 1 - s->mb_stride],
- block_is_intra = mb_is_intra >> (block_num * 4), right_is_intra;
+ block_is_intra = mb_is_intra >> block_num, right_is_intra;
int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize, ttblk;
uint8_t *dst;
@@ -288,13 +288,13 @@ static av_always_inline void vc1_apply_p_h_loop_filter(VC1Context *v, int block_
if (block_num > 3) {
right_cbp = v->cbp[s->mb_x - s->mb_stride] >> (block_num * 4);
- right_is_intra = v->is_intra[s->mb_x - s->mb_stride] >> (block_num * 4);
+ right_is_intra = v->is_intra[s->mb_x - s->mb_stride] >> block_num;
mv = &v->luma_mv[s->mb_x - s->mb_stride - 1];
} else {
right_cbp = (block_num & 1) ? (v->cbp[s->mb_x - s->mb_stride] >> ((block_num - 1) * 4))
: (mb_cbp >> ((block_num + 1) * 4));
- right_is_intra = (block_num & 1) ? (v->is_intra[s->mb_x - s->mb_stride] >> ((block_num - 1) * 4))
- : (mb_is_intra >> ((block_num + 1) * 4));
+ right_is_intra = (block_num & 1) ? (v->is_intra[s->mb_x - s->mb_stride] >> (block_num - 1))
+ : (mb_is_intra >> (block_num + 1));
mv = &s->current_picture.motion_val[0][s->block_index[block_num] - s->b8_stride * 2 - 2];
}
if (block_is_intra & 1 || right_is_intra & 1 || mv[0][0] != mv[1][0] || mv[0][1] != mv[1][1]) {
diff --git a/libavcodec/vc1_mc.c b/libavcodec/vc1_mc.c
index e3a75d5..09e8fac 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
*/
@@ -85,7 +85,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];
@@ -145,7 +145,8 @@ 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;
srcY -= s->mspel * (1 + s->linesize);
s->vdsp.emulated_edge_mc(s->edge_emu_buffer, srcY,
@@ -154,16 +155,18 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir)
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;
@@ -215,11 +218,7 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir)
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)
@@ -277,7 +276,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;
@@ -302,7 +301,7 @@ 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;
+ int tx, ty;
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];
@@ -326,6 +325,8 @@ void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg)
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;
+ default:
+ av_assert0(0);
}
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;
@@ -431,9 +432,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)
@@ -577,7 +578,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];
@@ -707,21 +708,26 @@ 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--;
+ v_edge_pos = (s->v_edge_pos >> 1) - 1;
+
if (fieldmv && (uvsrc_y & 1) && uvsrc_y < 2)
uvsrc_y--;
if (use_ic
@@ -844,7 +850,8 @@ 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;
srcY -= s->mspel * (1 + s->linesize);
s->vdsp.emulated_edge_mc(s->edge_emu_buffer, srcY,
@@ -853,16 +860,18 @@ void ff_vc1_interp_mc(VC1Context *v)
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;
@@ -919,11 +928,7 @@ void ff_vc1_interp_mc(VC1Context *v)
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] + off , srcY , s->linesize, v->rnd);
} else { // hpel mc
dxy = (my & 2) | ((mx & 2) >> 1);
diff --git a/libavcodec/vc1_parser.c b/libavcodec/vc1_parser.c
index 7d8d016..3a2308e 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
*/
@@ -63,6 +63,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 +76,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 +112,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 +239,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;
@@ -265,6 +271,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 6a54fe4..cf1dce6 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
*/
@@ -468,7 +468,7 @@ void ff_vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y,
MpegEncContext *s = &v->s;
int xy, wrap, off = 0;
int A[2], B[2], C[2];
- int px, py;
+ int px = 0, py = 0;
int a_valid = 0, b_valid = 0, c_valid = 0;
int field_a, field_b, field_c; // 0: same, 1: opposit
int total_valid, num_samefield, num_oppfield;
@@ -602,11 +602,10 @@ 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]; }
- } else
- px = py = 0;
+ 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 {
if (a_valid)
@@ -645,28 +644,28 @@ 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];
- } else px = py = 0;
+ } /*else px = py = 0;*/
} else {
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];
- } else if (c_valid) {
+ } /*else if (c_valid) {
px = C[0];
py = C[1];
- } else
- px = py = 0;
+ }*/
}
} else if (total_valid == 1) {
px = (a_valid) ? A[0] : ((b_valid) ? B[0] : C[0]);
py = (a_valid) ? A[1] : ((b_valid) ? B[1] : C[1]);
- } else
- px = py = 0;
+ }
}
/* store MV using signed modulus of MV range defined in 4.11 */
@@ -698,6 +697,8 @@ 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 */
@@ -710,13 +711,15 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2],
xy = s->block_index[0];
if (s->mb_intra) {
- s->current_picture.motion_val[0][xy + 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);
@@ -727,12 +730,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;
}
diff --git a/libavcodec/vc1_pred.h b/libavcodec/vc1_pred.h
index 34c9c1a..4d47f86 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 73ebe40..a70b44a 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 70cead8..fc9ba6d 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 66c569b..763cd48 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 ed8253a..da6724c 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])
@@ -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);
@@ -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;
@@ -421,8 +433,18 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx)
avctx->pix_fmt = AV_PIX_FMT_GRAY8;
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 +459,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) {
@@ -472,16 +494,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 +557,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 +613,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->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 +637,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 +665,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 +688,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 +700,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 +726,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 +739,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 +786,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 +807,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 +847,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 +866,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 +927,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 +938,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 +970,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 +1005,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 +1030,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;
}
}
@@ -996,6 +1110,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 a193dd7..73e1001 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 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 682f682..e2f75ac 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 161704f..f8281ea 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 f71fb16..170580f 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 9aa5d29..12330aa 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 c7f6a74..61fb3c0 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;
}
@@ -383,7 +418,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 0000000..c00e7e4
--- /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 9d0ed80..457916b 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 93b53dd..f7116f4 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 ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile,
int level)
{
@@ -82,7 +89,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;
@@ -90,6 +102,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;
@@ -208,6 +221,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;
@@ -216,11 +230,33 @@ int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
if (val < 0)
return val;
+#if FF_API_BUFS_VDPAU
+FF_DISABLE_DEPRECATION_WARNINGS
+ hwctx->info = pic_ctx->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);
}
@@ -262,6 +298,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->slice_num;
+ 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, 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 24c3b02..d686ef4 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
@@ -181,19 +200,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. */
@@ -201,6 +222,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 4103328..c8307bc 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 16493b0..e1ea430 100644
--- a/libavcodec/vdpau_internal.h
+++ b/libavcodec/vdpau_internal.h
@@ -4,30 +4,35 @@
*
* 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 "avcodec.h"
+#include "mpeg4video.h"
#include "mpegvideo.h"
#include "version.h"
@@ -37,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
#if !FF_API_BUFS_VDPAU
union AVVDPAUPictureInfo {
VdpPictureInfoH264 h264;
@@ -105,6 +112,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 +124,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 421abe9..c47e50e 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 978456a..9141bec 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 4f87c52..ffd6505 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 fd774a7..5d2c9a2 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 6
-#define LIBAVCODEC_VERSION_MICRO 0
+#define LIBAVCODEC_VERSION_MINOR 12
+#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \
@@ -51,6 +51,24 @@
#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 +132,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 +168,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 e6d9303..ba618a7 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 04c012a..fc01a31 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 28b8c32..f4ff2ba 100644
--- a/libavcodec/videodsp_template.c
+++ b/libavcodec/videodsp_template.c
@@ -1,42 +1,46 @@
/*
- * 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 +55,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 14a3bca..ba3f07a 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,13 @@ AVCodec ff_adpcm_vima_decoder = {
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
};
+
+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,
+};
diff --git a/libavcodec/vmdaudio.c b/libavcodec/vmdaudio.c
index 66c5865..3be0ff8 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 aaeff43..fa0fbe3 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;
}
@@ -347,7 +352,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 +369,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 +390,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 +410,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 +439,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 16984fb..46bd52e 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",
@@ -545,9 +558,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 66fa21b..86d1040 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 5ae20ac..98dd14f 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 bafb77b..063a075 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 a1e743e..a51aaec 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 231706c..0d72fb1 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:
@@ -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,22 @@ 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
+ 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 +247,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 +259,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 +308,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 7b12900..0f73537 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
*/
@@ -27,6 +27,8 @@
#ifndef AVCODEC_VORBIS_PARSE_H
#define AVCODEC_VORBIS_PARSE_H
+#include <stdint.h>
+
typedef struct AVVorbisParseContext AVVorbisParseContext;
/**
@@ -43,6 +45,23 @@ 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
+
+/**
+ * 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 8f76af7..49481ee 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 d7fec98..2ad5b4f 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"
@@ -146,7 +151,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;
@@ -189,37 +194,41 @@ static void vorbis_free(vorbis_context *vc)
av_freep(&vc->channel_residues);
av_freep(&vc->saved);
- 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,7 +378,7 @@ static int vorbis_parse_setup_hdr_codebooks(vorbis_context *vc)
}
// Weed out unused vlcs and build codevector vector
- codebook_setup->codevectors = used_entries ? av_mallocz(used_entries *
+ codebook_setup->codevectors = used_entries ? av_mallocz_array(used_entries,
codebook_setup->dimensions *
sizeof(*codebook_setup->codevectors))
: NULL;
@@ -552,7 +561,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);
@@ -631,8 +640,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);
@@ -692,8 +701,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,
@@ -706,7 +714,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)
@@ -799,7 +807,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);
@@ -834,7 +842,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);
@@ -961,12 +969,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];
@@ -975,12 +983,12 @@ 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);
@@ -1185,7 +1193,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;
@@ -1201,28 +1209,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;
av_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];
av_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;
}
@@ -1303,7 +1314,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
+ )
{
int p, j, i;
unsigned c_p_c = vc->codebooks[vr->classbook].dimensions;
@@ -1316,11 +1329,16 @@ static av_always_inline int setup_classifs(vorbis_context *vc,
av_dlog(NULL, "Classword: %u\n", temp);
+ if ((int)temp < 0)
+ return temp;
+
+ av_assert0(vr->classifications > 1); //needed for inverse[]
+
if (temp <= 65536) {
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;
}
@@ -1328,13 +1346,13 @@ static av_always_inline int setup_classifs(vorbis_context *vc,
for (i = partition_count + c_p_c - 1; i >= partition_count; i--) {
temp2 = temp / vr->classifications;
- 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;
}
@@ -1355,6 +1373,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)
@@ -1369,8 +1388,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;
+ }
}
av_dlog(NULL, " residue type 0/1/2 decode begin, ch: %d cpc %d \n", ch, c_p_c);
@@ -1381,7 +1405,9 @@ 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) {
- setup_classifs(vc, vr, do_not_decode, ch_used, partition_count);
+ int ret;
+ if ((ret = setup_classifs(vc, vr, do_not_decode, ch_used, partition_count, ptns_to_read)) < 0)
+ return ret;
}
for (i = 0; (i < c_p_c) && (partition_count < ptns_to_read); ++i) {
for (j_times_ptns_to_read = 0, j = 0; j < ch_used; ++j) {
@@ -1477,6 +1503,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;
}
@@ -1529,7 +1563,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];
@@ -1562,9 +1596,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)
@@ -1699,12 +1735,49 @@ static int vorbis_decode_frame(AVCodecContext *avctx, void *data,
av_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++)
@@ -1756,7 +1829,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 c37e2c4..362a276 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 ea41c40..7abec4e 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 10c7932..c06093e 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 {
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 fec8766..8aca83a 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 */
@@ -258,6 +262,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;
@@ -275,16 +293,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);
@@ -310,7 +323,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
@@ -401,7 +414,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));
@@ -1019,7 +1032,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++)
@@ -1598,20 +1611,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);
@@ -1655,22 +1662,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] ||
@@ -1723,7 +1732,7 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx)
s->avctx = avctx;
s->width = FFALIGN(avctx->width, 16);
s->height = FFALIGN(avctx->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);
@@ -1731,7 +1740,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
@@ -1742,8 +1751,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,13 +1997,44 @@ static int vp3_decode_frame(AVCodecContext *avctx,
init_get_bits(&gb, buf, buf_size * 8);
+#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++)
@@ -2030,10 +2069,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]));
@@ -2062,10 +2100,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)
@@ -2256,6 +2292,10 @@ 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 */
}
@@ -2401,6 +2441,8 @@ static av_cold int theora_decode_init(AVCodecContext *avctx)
int header_len[3];
int i;
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+
s->theora = 1;
if (!avctx->extradata_size) {
@@ -2431,7 +2473,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 e8fdcca..7ee046c 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 da325c0..da31f6d 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 af687ec..d8a3e0a 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 3099a7e..b95adae 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 b609282..1923d63 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 b9d3c87..ba39b56 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 -1;
}
- 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,155 +516,183 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return -1;
}
- 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;
+ if (ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF) < 0)
+ return -1;
+
+ 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 -1;
- }
+ if (res == VP56_SIZE_CHANGE) {
+ if (vp56_size_changed(s)) {
+ av_frame_unref(p);
+ return -1;
}
+ }
- if (!is_alpha) {
- if (ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return -1;
+ 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 -1;
- }
+ av_frame_unref(p);
+ return -1;
}
+ }
- 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;
+ }
- stride_y = p->linesize[0];
- stride_uv = p->linesize[1];
+ if (s->parse_coeff_models(s))
+ goto next;
+ 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);
@@ -682,10 +718,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;
@@ -702,6 +742,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 f2ed770..56c3091 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 989c76a..0080370 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 21907bd..3be268c 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 5e09d24..fa533ec 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 389d359..7807baa 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 270a3ca..6061b7e 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 b11b99d..e16ff2d 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 d10a640..a18b8ff 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_free(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 2de90e7..539e19a 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 54a96ed..67c6be0 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 f437fee..147c4f9 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);
@@ -196,6 +204,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;
@@ -286,7 +295,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;
@@ -407,7 +416,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;
@@ -418,16 +427,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);
}
}
}
@@ -443,8 +452,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;
@@ -453,15 +465,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;
@@ -484,6 +497,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;
@@ -532,7 +550,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;
}
}
@@ -695,11 +713,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);
@@ -739,7 +758,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;
@@ -767,6 +786,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)
{
@@ -957,8 +986,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 {
@@ -1057,8 +1086,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 {
@@ -1082,7 +1111,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);
}
@@ -1090,7 +1119,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;
@@ -1125,7 +1154,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,
@@ -1134,9 +1163,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;
@@ -1151,7 +1181,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);
@@ -1315,6 +1345,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
@@ -1755,7 +1786,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);
@@ -1763,7 +1795,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);
@@ -2224,7 +2257,7 @@ static void vp8_decode_mv_mb_modes(AVCodecContext *avctx, VP8Frame *cur_frame,
#define update_pos(td, mb_y, mb_x)
#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;
@@ -2345,7 +2378,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;
@@ -2404,6 +2449,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)
@@ -2419,9 +2476,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;
@@ -2514,10 +2571,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)
@@ -2537,7 +2592,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];
@@ -2650,6 +2706,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;
@@ -2659,9 +2716,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 */
@@ -2703,7 +2764,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 2919a14..b650892 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 8f6459c..afc7f99 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 b49dea9..f9dbf56 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 4e4012f..e1a91bb 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 4864cf7..5fdd3af 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 50b84ae..7b7deb3 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -4,99 +4,397 @@
* 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"
#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;
+} 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, uses_2pass, last_uses_2pass;
+ int row, row7, col, col7;
+ uint8_t *dst[3];
+ ptrdiff_t y_stride, uv_stride;
+
+ // 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];
+ ThreadFrame refs[8], next_refs[8];
+#define CUR_FRAME 0
+#define LAST_FRAME 1
+ VP9Frame frames[2];
+
+ 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;
+ 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[8];
+ } 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(8, uint8_t, left_uv_nnz_ctx)[2][8];
+ 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)[71*80];
+
+ // 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];
+ DECLARE_ALIGNED(32, uint8_t, tmp_uv)[2][32*32];
+} 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;
- for (i = 0; i < FF_ARRAY_ELEMS(s->refs); i++)
- av_frame_unref(s->refs[i]);
+ 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);
+
+ // retain segmentation map if it doesn't update
+ if (s->segmentation.enabled && !s->segmentation.update_map &&
+ !s->intraonly && !s->keyframe && !s->errorres) {
+ memcpy(f->segmentation_map, s->frames[LAST_FRAME].segmentation_map, sz);
+ }
+
+ return 0;
+}
+
+static void vp9_unref_frame(AVCodecContext *ctx, VP9Frame *f)
+{
+ ff_thread_release_buffer(ctx, &f->tf);
+ av_buffer_unref(&f->extradata);
+}
+
+static int vp9_ref_frame(AVCodecContext *ctx, VP9Frame *dst, VP9Frame *src)
+{
+ 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;
+
+ return 0;
}
-static int update_size(AVCodecContext *avctx, int w, int h)
+static int update_size(AVCodecContext *ctx, int w, int h)
{
- VP9Context *s = avctx->priv_data;
+ VP9Context *s = ctx->priv_data;
uint8_t *p;
- 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)
+ return 0;
- if (w <= 0 || h <= 0)
- return AVERROR_INVALIDDATA;
+ ctx->width = w;
+ ctx->height = h;
+ 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]);
+ p = av_malloc(s->sb_cols * (240 + 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);
+ assign(s->intra_pred_data[1], uint8_t *, 32);
+ assign(s->intra_pred_data[2], uint8_t *, 32);
+ 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_partition_ctx, uint8_t *, 8);
+ assign(s->above_skip_ctx, uint8_t *, 8);
+ assign(s->above_txfm_ctx, uint8_t *, 8);
+ assign(s->above_uv_nnz_ctx[0], uint8_t *, 8);
+ assign(s->above_uv_nnz_ctx[1], 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);
+
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)
+static int update_block_buffers(AVCodecContext *ctx)
+{
+ VP9Context *s = ctx->priv_data;
+
+ if (s->b_base && s->block_base && s->block_alloc_using_2pass == s->uses_2pass)
+ return 0;
+
+ av_free(s->b_base);
+ av_free(s->block_base);
+ if (s->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 + 128) * sbs * 3);
+ if (!s->b_base || !s->block_base)
+ return AVERROR(ENOMEM);
+ s->uvblock_base[0] = s->block_base + sbs * 64 * 64;
+ s->uvblock_base[1] = s->uvblock_base[0] + sbs * 32 * 32;
+ s->eob_base = (uint8_t *) (s->uvblock_base[1] + sbs * 32 * 32);
+ s->uveob_base[0] = s->eob_base + 256 * sbs;
+ s->uveob_base[1] = s->uveob_base[0] + 64 * sbs;
+ } else {
+ s->b_base = av_malloc(sizeof(VP9Block));
+ s->block_base = av_mallocz((64 * 64 + 128) * 3);
+ if (!s->b_base || !s->block_base)
+ return AVERROR(ENOMEM);
+ s->uvblock_base[0] = s->block_base + 64 * 64;
+ s->uvblock_base[1] = s->uvblock_base[0] + 32 * 32;
+ s->eob_base = (uint8_t *) (s->uvblock_base[1] + 32 * 32);
+ s->uveob_base[0] = s->eob_base + 256;
+ s->uveob_base[1] = s->uveob_base[0] + 64;
+ }
+ s->block_alloc_using_2pass = s->uses_2pass;
+
+ return 0;
+}
+
+// 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 +402,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 +433,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 +454,59 @@ 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 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;
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");
+ av_log(ctx, AV_LOG_ERROR, "Reserved bit should be zero\n");
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_uses_2pass = s->uses_2pass;
+ 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");
+ av_log(ctx, AV_LOG_ERROR, "RGB not supported in profile 0\n");
return AVERROR_INVALIDDATA;
}
- s->fullrange = get_bits1(&s->gb);
+ s->fullrange = get_bits1(&s->gb);
// for profile 1, here follows the subsampling bits
s->refreshrefmask = 0xff;
w = get_bits(&s->gb, 16) + 1;
@@ -226,11 +514,11 @@ 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;
}
s->refreshrefmask = get_bits(&s->gb, 8);
@@ -246,33 +534,37 @@ static int decode_frame_header(AVCodecContext *avctx,
s->signbias[1] = get_bits1(&s->gb);
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");
+ 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;
@@ -290,16 +582,15 @@ static int decode_frame_header(AVCodecContext *avctx,
}
}
}
-
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 */
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,10 +598,10 @@ 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));
@@ -318,9 +609,9 @@ static int decode_frame_header(AVCodecContext *avctx,
/* 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;
@@ -330,19 +621,28 @@ static int decode_frame_header(AVCodecContext *avctx,
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_ERROR,
+ "Reference segmap (temp=%d,update=%d) enabled on size-change!\n",
+ s->segmentation.temporal, s->segmentation.update_map);
+ 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,17 +665,17 @@ 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[qydc];
+ s->segmentation.feat[i].qmul[0][1] = vp9_ac_qlookup[qyac];
+ s->segmentation.feat[i].qmul[1][0] = vp9_dc_qlookup[quvdc];
+ s->segmentation.feat[i].qmul[1][1] = vp9_ac_qlookup[quvac];
sh = s->filter.level >= 32;
if (s->segmentation.feat[i].lf_enabled) {
@@ -384,7 +684,7 @@ static int decode_frame_header(AVCodecContext *avctx,
else
lflvl = s->filter.level + s->segmentation.feat[i].lf_val;
} else {
- lflvl = s->filter.level;
+ lflvl = s->filter.level;
}
s->segmentation.feat[i].lflvl[0][0] =
s->segmentation.feat[i].lflvl[0][1] =
@@ -400,10 +700,9 @@ static int decode_frame_header(AVCodecContext *avctx,
}
/* 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)) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to initialize decoder for %dx%d\n", w, h);
+ return res;
}
for (s->tiling.log2_tile_cols = 0;
(s->sb_cols >> s->tiling.log2_tile_cols) > 64;
@@ -417,56 +716,51 @@ 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) + 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 +801,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 +890,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 +899,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 +907,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,123 +944,2285 @@ 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;
+ 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) {
+ 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[LAST_FRAME].mv[row * s->sb_cols * 8 + col];
+
+ if (!s->last_uses_2pass)
+ ff_thread_await_progress(&s->frames[LAST_FRAME].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[LAST_FRAME].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 w4 = FFMIN(s->cols - col, bwh_tab[1][b->bs][0]);
+ int h4 = FFMIN(s->rows - row, bwh_tab[1][b->bs][1]), 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) {
+ int pred = 8, x;
+ uint8_t *refsegmap = s->frames[LAST_FRAME].segmentation_map;
+
+ if (!s->last_uses_2pass)
+ ff_thread_await_progress(&s->frames[LAST_FRAME].tf, row >> 3, 0);
+ for (y = 0; y < h4; y++)
+ for (x = 0; x < w4; x++)
+ pred = FFMIN(pred, refsegmap[(y + row) * 8 * s->sb_cols + x + col]);
+ 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],
+ w4, h4, 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, 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 + (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);
+ }
+ }
+ }
+ if (!--band_left)
+ band_left = band_counts[++band];
+ if (is_tx32x32)
+ 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_b(VP56RangeCoder *c, 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(c, coef, n_coeffs, 0, cnt, eob, p,
+ nnz, scan, nb, band_counts, qmul);
+}
+
+static int decode_coeffs_b32(VP56RangeCoder *c, 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)
{
- VP9Context *s = avctx->priv_data;
- int c = ((s->above_partition_ctx[col] >> (3 - bl)) & 1) |
+ return decode_coeffs_b_generic(c, coef, n_coeffs, 1, cnt, eob, p,
+ nnz, scan, nb, band_counts, qmul);
+}
+
+static void decode_coeffs(AVCodecContext *ctx)
+{
+ 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];
+
+#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 = decode_coeffs_b##v(&s->c, s->block + 16 * n, 16 * step * step, \
+ c, e, p, a[x] + l[y], yscans[txtp], \
+ ynbs[txtp], y_band_counts, qmul[0]); \
+ a[x] = l[y] = !!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) \
+ for (n = 0, y = 0; y < end_y; y += step) { \
+ for (x = 0; x < end_x; x += step, n += step * step) { \
+ res = decode_coeffs_b(&s->c, s->uvblock[pl] + 16 * n, \
+ 16 * step * step, c, e, p, a[x] + l[y], \
+ uvscan, uvnb, uv_band_counts, qmul[1]); \
+ a[x] = l[y] = !!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 >>= 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];
+ 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);
+ // a 64x64 (max) uv block can ever only contain 1 tx32x32 block
+ // so there is no need to loop
+ res = decode_coeffs_b32(&s->c, s->uvblock[pl],
+ 1024, c, e, p, a[0] + l[0],
+ uvscan, uvnb, uv_band_counts, qmul[1]);
+ a[0] = l[0] = !!res;
+ AV_WN16A(&s->uveob[pl][0], res);
+ SPLAT_CTX(8);
+ break;
+ }
+ }
+}
+
+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, *topleft;
+ 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 n_px_need = 4 << tx, i, 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[n_px_need - 1 - i] = dst[i * stride - 1];
+ } else {
+ for (i = 0; i < n_px_have; i++)
+ l[n_px_need - 1 - i] = dst[i * stride - 1];
+ memset(l, l[n_px_need - n_px_have], n_px_need - n_px_have);
+ }
+ } else {
+ memset(l, 129, 4 << tx);
+ }
+ }
+
+ return mode;
+}
+
+static void intra_recon(AVCodecContext *ctx, ptrdiff_t y_off, ptrdiff_t uv_off)
+{
+ 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, [64]);
+ LOCAL_ALIGNED_32(uint8_t, l, [32]);
+
+ 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];
+ 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);
+ 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, eob);
+ }
+ dst_r += 4 * step1d * s->frames[CUR_FRAME].tf.f->linesize[0];
+ dst += 4 * step1d * s->y_stride;
+ }
+
+ // U/V
+ w4 >>= 1;
+ end_x >>= 1;
+ end_y >>= 1;
+ 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,
+ ptr_r += 4 * uvstep1d, n += step) {
+ int mode = b->uvmode;
+ uint8_t *a = &a_buf[16];
+ 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->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, eob);
+ }
+ dst_r += 4 * uvstep1d * s->frames[CUR_FRAME].tf.f->linesize[1];
+ dst += 4 * uvstep1d * s->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,
+ ThreadFrame *ref_frame,
+ ptrdiff_t y, ptrdiff_t x, const VP56mv *mv,
+ int bw, int bh, int w, int h)
+{
+ int mx = mv->x, my = mv->y, th;
+
+ 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
+ // 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,
+ 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, dst_stride, ref, 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,
+ ThreadFrame *ref_frame,
+ ptrdiff_t y, ptrdiff_t x, const VP56mv *mv,
+ int bw, int bh, int w, int h)
+{
+ int mx = mv->x, my = mv->y, th;
+
+ 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
+ // 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) >> 5;
+ 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,
+ 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, dst_stride, ref_u, 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, dst_stride, ref_v, 80, 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);
+ }
+}
+
+static void inter_recon(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;
+
+ 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) {
+ if (b->bs == BS_8x4) {
+ mc_luma_dir(s, s->dsp.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);
+ mc_luma_dir(s, s->dsp.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);
+
+ if (b->comp) {
+ mc_luma_dir(s, s->dsp.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);
+ mc_luma_dir(s, s->dsp.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);
+ }
+ } else if (b->bs == BS_4x8) {
+ mc_luma_dir(s, s->dsp.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);
+ mc_luma_dir(s, s->dsp.mc[4][b->filter][0], s->dst[0] + 4, ls_y,
+ ref1->data[0], ref1->linesize[0], tref1,
+ row << 3, (col << 3) + 4, &b->mv[1][0], 4, 8, w1, h1);
+
+ if (b->comp) {
+ mc_luma_dir(s, s->dsp.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);
+ mc_luma_dir(s, s->dsp.mc[4][b->filter][1], s->dst[0] + 4, ls_y,
+ ref2->data[0], ref2->linesize[0], tref2,
+ row << 3, (col << 3) + 4, &b->mv[1][1], 4, 8, w2, h2);
+ }
+ } 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], s->dst[0], ls_y,
+ ref1->data[0], ref1->linesize[0], tref1,
+ row << 3, col << 3, &b->mv[0][0], 4, 4, w1, h1);
+ mc_luma_dir(s, s->dsp.mc[4][b->filter][0], s->dst[0] + 4, ls_y,
+ ref1->data[0], ref1->linesize[0], tref1,
+ row << 3, (col << 3) + 4, &b->mv[1][0], 4, 4, w1, h1);
+ mc_luma_dir(s, s->dsp.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], 4, 4, w1, h1);
+ mc_luma_dir(s, s->dsp.mc[4][b->filter][0],
+ s->dst[0] + 4 * ls_y + 4, ls_y,
+ ref1->data[0], ref1->linesize[0], tref1,
+ (row << 3) + 4, (col << 3) + 4, &b->mv[3][0], 4, 4, w1, h1);
+
+ if (b->comp) {
+ mc_luma_dir(s, s->dsp.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, 4, w2, h2);
+ mc_luma_dir(s, s->dsp.mc[4][b->filter][1], s->dst[0] + 4, ls_y,
+ ref2->data[0], ref2->linesize[0], tref2,
+ row << 3, (col << 3) + 4, &b->mv[1][1], 4, 4, w2, h2);
+ mc_luma_dir(s, s->dsp.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], 4, 4, w2, h2);
+ mc_luma_dir(s, s->dsp.mc[4][b->filter][1],
+ s->dst[0] + 4 * ls_y + 4, ls_y,
+ ref2->data[0], ref2->linesize[0], tref2,
+ (row << 3) + 4, (col << 3) + 4, &b->mv[3][1], 4, 4, w2, h2);
+ }
+ }
+ } 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;
+
+ mc_luma_dir(s, s->dsp.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],bw, bh, w1, h1);
+
+ if (b->comp)
+ mc_luma_dir(s, s->dsp.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], bw, bh, w2, h2);
+ }
+
+ // 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;
+
+ w1 = (w1 + 1) >> 1;
+ h1 = (h1 + 1) >> 1;
+ if (b->comp) {
+ w2 = (w2 + 1) >> 1;
+ h2 = (h2 + 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],
+ 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, &mvuv, bw, bh, w1, h1);
+
+ 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],
+ 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, &mvuv, bw, bh, w2, h2);
+ }
+ }
+
+ 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 = 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, 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, eob);
+ }
+ dst += 4 * s->y_stride * step1d;
+ }
+
+ // uv itxfm add
+ end_x >>= 1;
+ end_y >>= 1;
+ 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, 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, eob);
+ }
+ dst += 4 * uvstep1d * s->uv_stride;
+ }
+ }
+ }
+}
+
+static av_always_inline void mask_edges(struct 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;
+ }
+ }
+}
+
+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 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 - (w4 * 2 == (1 << b->tx) || h4 * 2 == (1 << b->tx));
+
+ if (!b->skip) {
+ decode_coeffs(ctx);
+ } 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) \
+ do { \
+ SPLAT_ZERO_CTX(s->dir##_y_##var[off * 2], n * 2); \
+ SPLAT_ZERO_CTX(s->dir##_uv_##var[0][off], n); \
+ SPLAT_ZERO_CTX(s->dir##_uv_##var[1][off], n); \
+ } while (0)
+
+ switch (w4) {
+ case 1: SPLAT_ZERO_YUV(above, nnz_ctx, col, 1); break;
+ case 2: SPLAT_ZERO_YUV(above, nnz_ctx, col, 2); break;
+ case 4: SPLAT_ZERO_YUV(above, nnz_ctx, col, 4); break;
+ case 8: SPLAT_ZERO_YUV(above, nnz_ctx, col, 8); break;
+ }
+ switch (h4) {
+ case 1: SPLAT_ZERO_YUV(left, nnz_ctx, row7, 1); break;
+ case 2: SPLAT_ZERO_YUV(left, nnz_ctx, row7, 2); break;
+ case 4: SPLAT_ZERO_YUV(left, nnz_ctx, row7, 4); break;
+ case 8: SPLAT_ZERO_YUV(left, nnz_ctx, row7, 8); break;
+ }
+ }
+ if (s->pass == 1) {
+ s->b++;
+ s->block += w4 * h4 * 64;
+ s->uvblock[0] += w4 * h4 * 16;
+ s->uvblock[1] += w4 * h4 * 16;
+ s->eob += 4 * w4 * h4;
+ s->uveob[0] += w4 * h4;
+ s->uveob[1] += w4 * h4;
+
+ 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 = 64;
+ } 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 = 32;
+ } else {
+ s->dst[1] = f->data[1] + uvoff;
+ s->dst[2] = f->data[2] + uvoff;
+ s->uv_stride = f->linesize[1];
+ }
+ if (b->intra) {
+ intra_recon(ctx, yoff, uvoff);
+ } else {
+ inter_recon(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, 64, h, 0, 0);
+ o += bw;
+ }
+ }
+ }
+ if (emu[1]) {
+ int w = FFMIN(s->cols - col, w4) * 4, h = FFMIN(s->rows - row, h4) * 4, 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](f->data[1] + uvoff + o, f->linesize[1],
+ s->tmp_uv[0] + o, 32, h, 0, 0);
+ s->dsp.mc[n][0][0][0][0](f->data[2] + uvoff + o, f->linesize[2],
+ s->tmp_uv[1] + o, 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), 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, 0, row7, col7, x_end, y_end, 0, 0, b->tx, skip_inter);
+ mask_edges(lflvl, 1, 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;
+ s->uvblock[0] += w4 * h4 * 16;
+ s->uvblock[1] += w4 * h4 * 16;
+ s->eob += 4 * w4 * h4;
+ s->uveob[0] += w4 * h4;
+ s->uveob[1] += w4 * h4;
+ }
+}
+
+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 ? 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];
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 * 4 * uv_stride;
+ 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;
+ uvoff += hbs * 4;
+ 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, uvoff + 4 * hbs, bl + 1);
+ yoff += hbs * 8 * y_stride;
+ uvoff += hbs * 4 * uv_stride;
+ decode_sb(ctx, row + hbs, col, lflvl, yoff, uvoff, bl + 1);
+ decode_sb(ctx, row + hbs, col + hbs, lflvl,
+ yoff + 8 * hbs, uvoff + 4 * hbs, 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, uvoff + 4 * hbs, 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 * 4 * uv_stride;
+ 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];
- 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 * 4 * uv_stride;
+ 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;
+ uvoff += hbs * 4;
+ 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,
+ uvoff + 4 * hbs, bl + 1);
+ yoff += hbs * 8 * y_stride;
+ uvoff += hbs * 4 * uv_stride;
+ decode_sb_mem(ctx, row + hbs, col, lflvl, yoff, uvoff, bl + 1);
+ decode_sb_mem(ctx, row + hbs, col + hbs, lflvl,
+ yoff + 8 * hbs, uvoff + 4 * hbs, bl + 1);
+ } else {
+ yoff += hbs * 8;
+ uvoff += hbs * 4;
+ 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 * 4 * uv_stride;
+ 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 void loopfilter_sb(AVCodecContext *ctx, struct VP9Filter *lflvl,
+ int row, int col, ptrdiff_t yoff, ptrdiff_t uvoff)
{
- 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];
+ VP9Context *s = ctx->priv_data;
+ AVFrame *f = s->frames[CUR_FRAME].tf.f;
+ uint8_t *dst = f->data[0] + yoff, *lvl = lflvl->level;
+ ptrdiff_t ls_y = f->linesize[0], ls_uv = f->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). */
+ // 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) {
@@ -776,7 +3230,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
uint8_t *hmask2 = lflvl->mask[0][0][y + 1];
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) {
@@ -792,7 +3246,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
s->dsp.loop_filter_8[2][0](ptr, ls_y, E, I, H);
}
} else if (hm2 & x) {
- L = l[8];
+ L = l[8];
H |= (L >> 4) << 8;
E |= s->filter.mblim_lut[L] << 8;
I |= s->filter.lim_lut[L] << 8;
@@ -818,7 +3272,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
if (hm23 & x) {
- L = l[8];
+ L = l[8];
H |= (L >> 4) << 8;
E |= s->filter.mblim_lut[L] << 8;
I |= s->filter.lim_lut[L] << 8;
@@ -838,7 +3292,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
// block1
// filter edges between rows, Y plane (e.g. ------)
// block2
- dst = s->cur_frame->data[0] + yoff;
+ dst = f->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];
@@ -858,7 +3312,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
s->dsp.loop_filter_8[2][1](ptr, ls_y, E, I, H);
}
} else if (vm & (x << 1)) {
- L = l[1];
+ L = l[1];
H |= (L >> 4) << 8;
E |= s->filter.mblim_lut[L] << 8;
I |= s->filter.lim_lut[L] << 8;
@@ -882,7 +3336,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
if (vm3 & (x << 1)) {
- L = l[1];
+ L = l[1];
H |= (L >> 4) << 8;
E |= s->filter.mblim_lut[L] << 8;
I |= s->filter.lim_lut[L] << 8;
@@ -902,7 +3356,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
// same principle but for U/V planes
for (p = 0; p < 2; p++) {
lvl = lflvl->level;
- dst = s->cur_frame->data[1 + p] + uvoff;
+ dst = f->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];
@@ -913,8 +3367,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
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];
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
if (hmask1[0] & x) {
if (hmask2[0] & x) {
@@ -924,7 +3377,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
s->dsp.loop_filter_8[2][0](ptr, ls_uv, E, I, H);
}
} else if (hm2 & x) {
- L = l[16];
+ L = l[16];
H |= (L >> 4) << 8;
E |= s->filter.mblim_lut[L] << 8;
I |= s->filter.lim_lut[L] << 8;
@@ -937,8 +3390,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
}
} 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];
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
s->dsp.loop_filter_8[!!(hmask2[1] & x)]
[0](ptr + 8 * ls_uv, ls_uv, E, I, H);
@@ -949,7 +3401,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
}
}
lvl = lflvl->level;
- dst = s->cur_frame->data[1 + p] + uvoff;
+ dst = f->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];
@@ -958,8 +3410,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
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];
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
if (vmask[0] & x) {
if (vmask[0] & (x << 2)) {
@@ -969,7 +3420,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
s->dsp.loop_filter_8[2][1](ptr, ls_uv, E, I, H);
}
} else if (vm & (x << 2)) {
- L = l[2];
+ L = l[2];
H |= (L >> 4) << 8;
E |= s->filter.mblim_lut[L] << 8;
I |= s->filter.lim_lut[L] << 8;
@@ -982,8 +3433,7 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
}
} 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];
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
s->dsp.loop_filter_8[!!(vmask[1] & (x << 2))]
[1](ptr + 8, ls_uv, E, I, H);
@@ -998,294 +3448,639 @@ static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
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);
+ }
+
+ // 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;
- ret = av_frame_ref(frame, s->refs[ref]);
- if (ret < 0)
- return ret;
+ 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);
+ }
+}
+
+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 < 2; 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;
+ ptrdiff_t yoff, uvoff, ls_y, ls_uv;
+ AVFrame *f;
+
+ 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;
*got_frame = 1;
return 0;
}
- data += ret;
- size -= ret;
-
- s->cur_frame = frame;
+ data += res;
+ size -= res;
+
+ if (s->frames[LAST_FRAME].tf.f->data[0])
+ vp9_unref_frame(ctx, &s->frames[LAST_FRAME]);
+ if (!s->keyframe && s->frames[CUR_FRAME].tf.f->data[0] &&
+ (res = vp9_ref_frame(ctx, &s->frames[LAST_FRAME], &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 ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
+ ls_y = f->linesize[0];
+ ls_uv =f->linesize[1];
- 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;
+ // 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 {
+ res = ff_thread_ref_frame(&s->next_refs[i], &s->refs[i]);
+ }
+ if (res < 0)
+ return res;
+ }
if (s->fullrange)
- avctx->color_range = AVCOL_RANGE_JPEG;
+ ctx->color_range = AVCOL_RANGE_JPEG;
else
- avctx->color_range = AVCOL_RANGE_MPEG;
+ ctx->color_range = AVCOL_RANGE_MPEG;
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;
+ case 1: ctx->colorspace = AVCOL_SPC_BT470BG; break;
+ case 2: ctx->colorspace = AVCOL_SPC_BT709; break;
+ case 3: ctx->colorspace = AVCOL_SPC_SMPTE170M; break;
+ case 4: ctx->colorspace = AVCOL_SPC_SMPTE240M; break;
}
// main tile decode loop
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_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->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];
+
+ 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;
+
+ 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;
+ }
+ }
- return 0;
-}
+ for (row = s->tiling.tile_row_start; row < s->tiling.tile_row_end;
+ row += 8, yoff += ls_y * 64, uvoff += ls_uv * 32) {
+ struct VP9Filter *lflvl_ptr = s->lflvl;
+ ptrdiff_t yoff2 = yoff, uvoff2 = uvoff;
-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;
+ 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, 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_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));
+ }
}
- ret = vp9_decode_frame(avctx, frame, got_frame, data, sz);
- if (ret < 0)
- return ret;
- data += sz;
- size -= sz;
+ 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);
+ memcpy(s->intra_pred_data[1],
+ f->data[1] + uvoff + 31 * ls_uv,
+ 4 * s->cols);
+ memcpy(s->intra_pred_data[2],
+ f->data[2] + uvoff + 31 * ls_uv,
+ 4 * s->cols);
+ }
+
+ // 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, uvoff2 += 32, 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 0;
}
-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 < 2; 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 < 2; 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;
-
- avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ VP9Context *s = ctx->priv_data;
+ ctx->internal->allocate_progress = 1;
+ ctx->pix_fmt = AV_PIX_FMT_YUV420P;
ff_vp9dsp_init(&s->dsp);
ff_videodsp_init(&s->vdsp, 8);
+ s->filter.sharpness = -1;
- 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);
+ return init_frames(ctx);
+}
+
+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 < 2; 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->uses_2pass = ssrc->uses_2pass;
+ 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;
}
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),
};
diff --git a/libavcodec/vp9.h b/libavcodec/vp9.h
index 0a6c6ee..9a29416 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,343 +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;
- 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[8];
- } 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_parser.c b/libavcodec/vp9_parser.c
new file mode 100644
index 0000000..af033c2
--- /dev/null
+++ b/libavcodec/vp9_parser.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2008 Michael Niedermayer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "parser.h"
+
+typedef struct VP9ParseContext {
+ int n_frames; // 1-8
+ int size[8];
+} VP9ParseContext;
+
+static void parse_frame(AVCodecParserContext *ctx, const uint8_t *buf, int size)
+{
+ 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;
+ }
+}
+
+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 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; \
+ av_log(avctx, AV_LOG_ERROR, \
+ "Superframe packet size too big: %u > %d\n", \
+ sz, size); \
+ return 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 caf3bcc..0000000
--- a/libavcodec/vp9block.c
+++ /dev/null
@@ -1,1684 +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 = 8, 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 374fa8b..0000000
--- 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 a52cc0a..625b60e 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,2130 @@
#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[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,
+};
+
+static const int16_t 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,
+};
+
+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 c83defe..6356add 100644
--- a/libavcodec/vp9dsp.c
+++ b/libavcodec/vp9dsp.c
@@ -4,28 +4,27 @@
* 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/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]
@@ -85,10 +84,10 @@ static void vert_32x32_c(uint8_t *dst, ptrdiff_t 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);
+ AV_WN32A(dst + stride * 0, left[3] * 0x01010101U);
+ AV_WN32A(dst + stride * 1, left[2] * 0x01010101U);
+ AV_WN32A(dst + stride * 2, left[1] * 0x01010101U);
+ AV_WN32A(dst + stride * 3, left[0] * 0x01010101U);
}
static void hor_8x8_c(uint8_t *dst, ptrdiff_t stride,
@@ -97,7 +96,7 @@ static void hor_8x8_c(uint8_t *dst, ptrdiff_t stride,
int y;
for (y = 0; y < 8; y++) {
- AV_WN64A(dst, left[y] * 0x0101010101010101ULL);
+ AV_WN64A(dst, left[7 - y] * 0x0101010101010101ULL);
dst += stride;
}
}
@@ -108,7 +107,7 @@ static void hor_16x16_c(uint8_t *dst, ptrdiff_t stride,
int y;
for (y = 0; y < 16; y++) {
- uint64_t p8 = left[y] * 0x0101010101010101ULL;
+ uint64_t p8 = left[15 - y] * 0x0101010101010101ULL;
AV_WN64A(dst + 0, p8);
AV_WN64A(dst + 8, p8);
@@ -122,7 +121,7 @@ static void hor_32x32_c(uint8_t *dst, ptrdiff_t stride,
int y;
for (y = 0; y < 32; y++) {
- uint64_t p8 = left[y] * 0x0101010101010101ULL;
+ uint64_t p8 = left[31 - y] * 0x0101010101010101ULL;
AV_WN64A(dst + 0, p8);
AV_WN64A(dst + 8, p8);
@@ -138,13 +137,13 @@ static void tm_4x4_c(uint8_t *dst, ptrdiff_t stride,
int y, tl = top[-1];
for (y = 0; y < 4; y++) {
- int l_m_tl = left[y] - tl;
+ int l_m_tl = left[3 - 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;
+ dst += stride;
}
}
@@ -154,7 +153,7 @@ static void tm_8x8_c(uint8_t *dst, ptrdiff_t stride,
int y, tl = top[-1];
for (y = 0; y < 8; y++) {
- int l_m_tl = left[y] - tl;
+ int l_m_tl = left[7 - y] - tl;
dst[0] = av_clip_uint8(top[0] + l_m_tl);
dst[1] = av_clip_uint8(top[1] + l_m_tl);
@@ -164,7 +163,7 @@ static void tm_8x8_c(uint8_t *dst, ptrdiff_t stride,
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;
+ dst += stride;
}
}
@@ -174,25 +173,25 @@ static void tm_16x16_c(uint8_t *dst, ptrdiff_t stride,
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);
+ int l_m_tl = left[15 - 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;
+ dst += stride;
}
}
@@ -202,18 +201,18 @@ static void tm_32x32_c(uint8_t *dst, ptrdiff_t stride,
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);
+ int l_m_tl = left[31 - 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);
@@ -236,16 +235,15 @@ static void tm_32x32_c(uint8_t *dst, ptrdiff_t stride,
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;
+ 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);
+ 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);
@@ -257,10 +255,9 @@ 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);
+ ((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++) {
@@ -273,14 +270,11 @@ 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);
+ ((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++) {
@@ -294,22 +288,16 @@ 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);
+ ((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++) {
@@ -324,8 +312,7 @@ static void dc_32x32_c(uint8_t *dst, ptrdiff_t 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);
+ 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);
@@ -337,8 +324,8 @@ 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);
+ ((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++) {
@@ -351,10 +338,9 @@ 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);
+ ((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++) {
@@ -368,14 +354,12 @@ 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);
+ ((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++) {
@@ -402,8 +386,8 @@ 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);
+ ((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++) {
@@ -416,10 +400,9 @@ 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);
+ ((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++) {
@@ -433,14 +416,12 @@ 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);
+ ((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++) {
@@ -598,41 +579,30 @@ static void diag_downleft_4x4_c(uint8_t *dst, ptrdiff_t stride,
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); \
- } \
+ 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)
@@ -643,49 +613,34 @@ 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); \
+ l0 = left[3], l1 = left[2], l2 = left[1], l3 = left[0];
+
+ 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[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); \
}
def_diag_downright(8)
@@ -696,57 +651,45 @@ 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); \
- } \
+ l0 = left[3], l1 = left[2], l2 = left[1];
+
+ 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[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); \
+ memcpy(dst + (j*2 + 1)*stride, vo + size/2 - 1 - j, size); \
+ } \
}
def_vert_right(8)
@@ -756,53 +699,40 @@ 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],
+ 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];
- 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); \
+ 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[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); \
}
def_hor_down(8)
@@ -815,48 +745,38 @@ static void vert_left_4x4_c(uint8_t *dst, ptrdiff_t stride,
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); \
- } \
+ 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)
@@ -866,49 +786,38 @@ 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); \
- } \
+ int l0 = left[3], l1 = left[2], l2 = left[1], l3 = left[0];
+
+ 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[size - i - 1] + left[size - i - 2] + 1) >> 1; \
+ v[i*2 + 1] = (left[size - i - 1] + left[size - i - 2] * 2 + left[size - i - 3] + 2) >> 2; \
+ } \
+ v[size*2 - 4] = (left[1] + left[0] + 1) >> 1; \
+ v[size*2 - 3] = (left[1] + left[0] * 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[0], \
+ 2 + j*2 - size); \
+ } \
}
def_hor_up(8)
@@ -919,22 +828,22 @@ def_hor_up(32)
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
+#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);
@@ -944,46 +853,60 @@ static av_cold void vp9dsp_intrapred_init(VP9DSPContext *dsp)
#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)
+#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; \
+ int16_t tmp[sz * sz], out[sz]; \
+\
+ 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_uint8(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_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, 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) in[(x) * stride]
+
+static av_always_inline void idct4_1d(const int16_t *in, ptrdiff_t stride,
+ int16_t *out, 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;
+ 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;
@@ -991,8 +914,8 @@ static av_always_inline void idct4_1d(int16_t *out, const int16_t *in,
out[3] = t0 - t3;
}
-static av_always_inline void iadst4_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
+static av_always_inline void iadst4_1d(const int16_t *in, ptrdiff_t stride,
+ int16_t *out, int pass)
{
int t0, t1, t2, t3;
@@ -1009,19 +932,19 @@ static av_always_inline void iadst4_1d(int16_t *out, const int16_t *in,
itxfm_wrap(4, 4)
-static av_always_inline void idct8_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
+static av_always_inline void idct8_1d(const int16_t *in, ptrdiff_t stride,
+ int16_t *out, 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;
+ 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;
@@ -1045,8 +968,8 @@ static av_always_inline void idct8_1d(int16_t *out, const int16_t *in,
out[7] = t0 - t7;
}
-static av_always_inline void iadst8_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
+static av_always_inline void iadst8_1d(const int16_t *in, ptrdiff_t stride,
+ int16_t *out, int pass)
{
int t0, t0a, t1, t1a, t2, t2a, t3, t3a, t4, t4a, t5, t5a, t6, t6a, t7, t7a;
@@ -1059,14 +982,14 @@ static av_always_inline void iadst8_1d(int16_t *out, const int16_t *in,
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;
+ 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;
@@ -1091,15 +1014,15 @@ static av_always_inline void iadst8_1d(int16_t *out, const int16_t *in,
itxfm_wrap(8, 5)
-static av_always_inline void idct16_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
+static av_always_inline void idct16_1d(const int16_t *in, ptrdiff_t stride,
+ int16_t *out, 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;
+ 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;
@@ -1115,29 +1038,29 @@ static av_always_inline void idct16_1d(int16_t *out, const int16_t *in,
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;
+ 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;
+ t13a = ( t13 * 6270 - t10 * 15137 + (1 << 13)) >> 14;
t0a = t0 + t7;
t1a = t1 + t6a;
@@ -1161,16 +1084,16 @@ static av_always_inline void idct16_1d(int16_t *out, const int16_t *in,
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[ 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;
@@ -1179,8 +1102,8 @@ static av_always_inline void idct16_1d(int16_t *out, const int16_t *in,
out[15] = t0a - t15a;
}
-static av_always_inline void iadst16_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
+static av_always_inline void iadst16_1d(const int16_t *in, ptrdiff_t stride,
+ int16_t *out, 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;
@@ -1229,14 +1152,14 @@ static av_always_inline void iadst16_1d(int16_t *out, const int16_t *in,
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;
+ 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;
@@ -1246,79 +1169,79 @@ static av_always_inline void iadst16_1d(int16_t *out, const int16_t *in,
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;
+ 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[ 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[ 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[ 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[ 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)
+static av_always_inline void idct32_1d(const int16_t *in, ptrdiff_t stride,
+ int16_t *out, int pass)
{
- 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 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;
@@ -1353,20 +1276,20 @@ static av_always_inline void idct32_1d(int16_t *out, const int16_t *in,
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;
+ 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;
+ 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;
+ 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;
+ t25a = ( t25 * 13623 - t22 * 9102 + (1 << 13)) >> 14;
t0a = t0 + t7;
t1a = t1 + t6a;
@@ -1401,35 +1324,35 @@ static av_always_inline void idct32_1d(int16_t *out, const int16_t *in,
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;
+ 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;
@@ -1449,23 +1372,23 @@ static av_always_inline void idct32_1d(int16_t *out, const int16_t *in,
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;
+ 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;
+ 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;
@@ -1490,10 +1413,10 @@ static av_always_inline void idct32_1d(int16_t *out, const int16_t *in,
out[31] = t0 - t31;
}
-itxfm_wrapper(idct, idct, 32, 6)
+itxfm_wrapper(idct, idct, 32, 6, 1)
-static av_always_inline void iwht4_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
+static av_always_inline void iwht4_1d(const int16_t *in, ptrdiff_t stride,
+ int16_t *out, int pass)
{
int t0, t1, t2, t3, t4;
@@ -1523,7 +1446,7 @@ static av_always_inline void iwht4_1d(int16_t *out, const int16_t *in,
out[3] = t3;
}
-itxfm_wrapper(iwht, iwht, 4, 0)
+itxfm_wrapper(iwht, iwht, 4, 0, 0)
#undef IN
#undef itxfm_wrapper
@@ -1531,30 +1454,29 @@ itxfm_wrapper(iwht, iwht, 4, 0)
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);
+#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(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,
+static av_always_inline void loop_filter(uint8_t *dst, int E, int I, int H,
ptrdiff_t stridea, ptrdiff_t strideb,
int wd)
{
@@ -1637,16 +1559,18 @@ static av_always_inline void loop_filter(uint8_t *dst, ptrdiff_t stride,
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;
+ int f = av_clip_int8(3 * (q0 - p0) + av_clip_int8(p1 - q1)), f1, f2;
+
+ f1 = FFMIN(f + 4, 127) >> 3;
+ 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;
+ int f = av_clip_int8(3 * (q0 - p0)), f1, f2;
+
+ f1 = FFMIN(f + 4, 127) >> 3;
+ f2 = FFMIN(f + 3, 127) >> 3;
dst[strideb * -1] = av_clip_uint8(p0 + f2);
dst[strideb * +0] = av_clip_uint8(q0 - f1);
@@ -1659,17 +1583,17 @@ static av_always_inline void loop_filter(uint8_t *dst, ptrdiff_t stride,
}
}
-#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_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, 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)
+#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)
@@ -1678,13 +1602,13 @@ 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); \
+#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)
@@ -1692,21 +1616,18 @@ 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_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)
+#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)
@@ -1738,9 +1659,8 @@ static av_cold void vp9dsp_loopfilter_init(VP9DSPContext *dsp)
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,
+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 {
@@ -1751,9 +1671,8 @@ static av_always_inline void copy_c(uint8_t *dst, const uint8_t *src,
} while (--h);
}
-static av_always_inline void avg_c(uint8_t *dst, const uint8_t *src,
- ptrdiff_t dst_stride,
- ptrdiff_t src_stride,
+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)
{
do {
@@ -1767,18 +1686,17 @@ static av_always_inline void avg_c(uint8_t *dst, const uint8_t *src,
} 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 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)
+fpel_fn(copy, sz) \
+fpel_fn(avg, sz)
copy_avg_fn(64)
copy_avg_fn(32)
@@ -1841,19 +1759,18 @@ static const int8_t vp9_subpel_filters[3][15][8] = {
}
};
-#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] + \
+#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,
+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 int8_t *filter, int avg)
{
@@ -1861,25 +1778,23 @@ static av_always_inline void do_8tap_1d_c(uint8_t *dst, const uint8_t *src,
int x;
for (x = 0; x < w; x++)
- if (avg)
+ if (avg) {
dst[x] = (dst[x] + FILTER_8TAP(src, x, filter, ds) + 1) >> 1;
- else
+ } 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); \
+#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 int8_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)
@@ -1889,9 +1804,8 @@ 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,
+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 int8_t *filterx,
const int8_t *filtery, int avg)
{
@@ -1906,7 +1820,7 @@ static av_always_inline void do_8tap_2d_c(uint8_t *dst, const uint8_t *src,
tmp_ptr[x] = FILTER_8TAP(src, x, filterx, 1);
tmp_ptr += 64;
- src += src_stride;
+ src += src_stride;
} while (--tmp_h);
tmp_ptr = tmp + 64 * 3;
@@ -1914,27 +1828,24 @@ static av_always_inline void do_8tap_2d_c(uint8_t *dst, const uint8_t *src,
int x;
for (x = 0; x < w; x++)
- if (avg)
+ if (avg) {
dst[x] = (dst[x] + FILTER_8TAP(tmp_ptr, x, filtery, 64) + 1) >> 1;
- else
+ } 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); \
+#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 int8_t *filterx, \
+ const int8_t *filtery) \
+{ \
+ do_8tap_2d_c(dst, dst_stride, src, src_stride, w, h, filterx, filtery, opa); \
}
filter_8tap_2d_fn(put, 0)
@@ -1944,62 +1855,53 @@ filter_8tap_2d_fn(avg, 1)
#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) \
+#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 - 1]); \
+}
+
+#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 - 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)
+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)
{
do {
int x;
for (x = 0; x < w; x++)
- if (avg)
+ if (avg) {
dst[x] = (dst[x] + FILTER_BILIN(src, x, mxy, ds) + 1) >> 1;
- else
+ } 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); \
+#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)
@@ -2009,12 +1911,9 @@ 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)
+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)
{
uint8_t tmp[64 * 65], *tmp_ptr = tmp;
int tmp_h = h + 1;
@@ -2026,7 +1925,7 @@ static av_always_inline void do_bilin_2d_c(uint8_t *dst,
tmp_ptr[x] = FILTER_BILIN(src, x, mx, 1);
tmp_ptr += 64;
- src += src_stride;
+ src += src_stride;
} while (--tmp_h);
tmp_ptr = tmp;
@@ -2034,25 +1933,23 @@ static av_always_inline void do_bilin_2d_c(uint8_t *dst,
int x;
for (x = 0; x < w; x++)
- if (avg)
+ if (avg) {
dst[x] = (dst[x] + FILTER_BILIN(tmp_ptr, x, my, 64) + 1) >> 1;
- else
+ } 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); \
+#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)
@@ -2062,48 +1959,42 @@ bilin_2d_fn(avg, 1)
#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 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); \
+}
+
+#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(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)
@@ -2117,14 +2008,14 @@ filter_fn_set(avg)
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); \
+#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);
@@ -2136,22 +2027,22 @@ static av_cold void vp9dsp_mc_init(VP9DSPContext *dsp)
#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_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) \
+#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); \
+#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);
@@ -2169,6 +2060,5 @@ av_cold void ff_vp9dsp_init(VP9DSPContext *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);
}
diff --git a/libavcodec/vp9dsp.h b/libavcodec/vp9dsp.h
new file mode 100644
index 0000000..db0a92e
--- /dev/null
+++ b/libavcodec/vp9dsp.h
@@ -0,0 +1,118 @@
+/*
+ * 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 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];
+} VP9DSPContext;
+
+void ff_vp9dsp_init(VP9DSPContext *dsp);
+
+void ff_vp9dsp_init_x86(VP9DSPContext *dsp);
+
+#endif /* AVCODEC_VP9DSP_H */
diff --git a/libavcodec/vp9mvs.c b/libavcodec/vp9mvs.c
deleted file mode 100644
index 1f65aaa..0000000
--- 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 b8a7c22..0000000
--- 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 86f2fcf..4dcebd4 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,26 @@ 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);
- av_dlog(NULL, " opcode %02X: ", opcode);
+ start = bytestream2_tell(&s->gb);
+ while (bytestream2_tell(&s->gb) - start < src_size) {
+ opcode = bytestream2_get_byte(&s->gb);
+ av_dlog(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);
- av_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);
+ av_dlog(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 +259,9 @@ static int decode_format80(GetByteContext *gb, int src_size,
} else if (opcode == 0xFE) {
- count = bytestream2_get_le16(gb);
- color = bytestream2_get_byte(gb);
- av_dlog(NULL, "(2) set %X bytes to %02X\n", count, color);
+ count = bytestream2_get_le16(&s->gb);
+ color = bytestream2_get_byte(&s->gb);
+ av_dlog(s->avctx, "(2) set %X bytes to %02X\n", count, color);
CHECK_COUNT();
memset(&dest[dest_index], color, count);
dest_index += count;
@@ -270,8 +269,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);
- av_dlog(NULL, "(3) copy %X bytes from absolute pos %X\n", count, src_pos);
+ src_pos = bytestream2_get_le16(&s->gb);
+ av_dlog(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 +280,16 @@ static int decode_format80(GetByteContext *gb, int src_size,
} else if (opcode > 0x80) {
count = opcode & 0x3F;
- av_dlog(NULL, "(4) copy %X bytes from source to dest\n", count);
+ av_dlog(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);
- av_dlog(NULL, "(5) copy %X bytes from relpos %X\n", count, src_pos);
+ src_pos = bytestream2_get_byte(&s->gb) | ((opcode & 0x0F) << 8);
+ av_dlog(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 +303,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 +378,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 +395,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 +413,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 +422,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 +431,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 +440,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 +452,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 +464,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 +533,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 +554,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 +583,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 +607,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 cbc5b04..1ad3901 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;
}
@@ -638,6 +491,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 +559,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 +589,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 +623,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 +784,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 +864,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 +879,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 +903,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 +994,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 +1054,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 +1112,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 0000000..6cb49a1
--- /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 0000000..63971c6
--- /dev/null
+++ b/libavcodec/wavpackenc.c
@@ -0,0 +1,2995 @@
+/*
+ * 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 < (1L << 16))
+ dbits = nbits_table[v >> 8] + 8;
+ else if (v < (1L << 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) < (1L << 16) ? nbits_table[(av) >> 8] + 8 : \
+ ((av) < (1L << 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;
+ int32_t value, mask = (1 << sent_bits) - 1;
+ 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++) {
+ value = (samples_l[i] >> pre_shift) & mask;
+ put_bits(pb, sent_bits, value);
+ }
+ } else {
+ for (i = 0; i < nb_samples; i++) {
+ value = (samples_l[i] >> pre_shift) & mask;
+ put_bits(pb, sent_bits, value);
+ value = (samples_r[i] >> pre_shift) & mask;
+ put_bits(pb, sent_bits, value);
+ }
+ }
+}
+
+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 0000000..9dd2a01
--- /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 b98fa4d..4b1c8e7 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);
@@ -1022,7 +1028,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];
@@ -1055,16 +1061,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);
}
}
@@ -1330,6 +1353,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)
@@ -1349,6 +1373,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 };
@@ -1422,10 +1447,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 0000000..1284a17
--- /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 0000000..9f67a2e
--- /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 cb7a16d..ecc7e41 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
*/
@@ -47,10 +47,10 @@ static av_cold void 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));
i = 2;
level = 1;
k = 0;
@@ -135,6 +135,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 */
@@ -375,9 +379,9 @@ 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]);
}
return 0;
diff --git a/libavcodec/wma.h b/libavcodec/wma.h
index 3a9de40..6e5198a 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
*/
@@ -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 */
diff --git a/libavcodec/wma_common.c b/libavcodec/wma_common.c
index cf76f5c..c01e0f4 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 61b1a35..55404af 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 82cef3b..03a283f 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 415c83b..85c5f69 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 58bffed..641cb18 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 2141e38..6c3f28f 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
*/
@@ -94,6 +94,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;
@@ -475,6 +485,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 +517,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)
@@ -811,7 +830,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 +839,17 @@ 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) {
+ av_log(avctx, AV_LOG_ERROR, "nb_frames is %d\n", nb_frames);
+ return AVERROR_INVALIDDATA;
+ }
} 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 +926,13 @@ static int wma_decode_superframe(AVCodecContext *avctx, void *data,
samples_offset += s->frame_len;
}
- av_dlog(s->avctx, "%d %d %d %d outbytes:%td eaten:%d\n",
+ av_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 +948,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 +963,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 +979,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 e801663..6337779 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);
}
@@ -71,7 +69,7 @@ static av_cold int encode_init(AVCodecContext *avctx)
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 +88,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;
@@ -153,7 +149,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 +157,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 +182,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 +191,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 +227,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 +282,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 +308,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 +341,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 +354,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 +373,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 +408,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 +421,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 +435,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 b8a1776..8e2ac5f 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
@@ -125,7 +128,7 @@ typedef struct WmallDecodeCtx {
int8_t acfilter_order;
int8_t acfilter_scaling;
int64_t acfilter_coeffs[16];
- int acfilter_prevvalues[2][16];
+ int acfilter_prevvalues[WMALL_MAX_CHANNELS][16];
int8_t mclms_order;
int8_t mclms_scaling;
@@ -143,33 +146,33 @@ 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];
+ DECLARE_ALIGNED(16, int16_t, lms_updates)[MAX_ORDER * 2];
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;
@@ -180,7 +183,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) {
@@ -345,11 +354,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 +463,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 +495,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 +525,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,7 +545,7 @@ 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;
}
@@ -649,10 +669,10 @@ static void mclms_update(WmallDecodeCtx *s, int icoef, int *pred)
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,35 +708,11 @@ 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];
- }
-
if (recent)
recent--;
else {
@@ -777,6 +773,9 @@ static void use_normal_update_speed(WmallDecodeCtx *s, int ich)
s->update_speed[ich] = 8;
}
+/** Get sign of integer (1 for positive, -1 for negative and 0 for zero) */
+#define WMASIGN(x) ((x > 0) - (x < 0))
+
static void revert_cdlms(WmallDecodeCtx *s, int ch,
int coef_begin, int coef_end)
{
@@ -787,12 +786,19 @@ 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,
+ s->cdlms[ch][ilms].order,
+ 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)
@@ -955,7 +961,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]) {
@@ -1022,8 +1028,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 +1041,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,8 +1079,11 @@ 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;
}
}
@@ -1182,9 +1190,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 f8a52bf..5382479 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 afe6ac2..56d6d32 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
*/
@@ -177,7 +177,7 @@ typedef struct WMAProDecodeCtx {
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
@@ -308,6 +308,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 +344,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 +422,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 +448,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 +505,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 +686,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)
{
@@ -1043,7 +1058,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);
@@ -1145,7 +1160,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 +1190,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 +1201,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 {
@@ -1381,7 +1398,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 +1471,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 +1480,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 +1488,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 +1603,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 0d91077..c2737ab 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 7f14fb8..cbf65b0 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 555d30e..d102f36 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->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 03a8514..cb5b14e 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
*/
diff --git a/libavcodec/wmv2dec.c b/libavcodec/wmv2dec.c
index 8bdf5e1..d9cbfd1 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
*/
@@ -460,6 +460,8 @@ static av_cold int wmv2_decode_init(AVCodecContext *avctx)
{
Wmv2Context *const w = avctx->priv_data;
+ avctx->flags |= CODEC_FLAG_EMU_EDGE;
+
if (ff_msmpeg4_decode_init(avctx) < 0)
return -1;
diff --git a/libavcodec/wmv2dsp.c b/libavcodec/wmv2dsp.c
index 2e3a3ff..40e0bef 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 f2f258e..0bf9489 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 e4e51d3..62e99c0 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);
@@ -171,10 +173,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 +211,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 +235,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 7676c89..99aee3c 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;
}
@@ -134,10 +132,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 fe6f812..6929cbf 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 3cec000..2fa56b9 100644
--- a/libavcodec/x86/Makefile
+++ b/libavcodec/x86/Makefile
@@ -4,17 +4,21 @@ 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_H263DSP) += x86/h263dsp_init.o
OBJS-$(CONFIG_H264CHROMA) += x86/h264chroma_init.o
OBJS-$(CONFIG_H264DSP) += x86/h264dsp_init.o
OBJS-$(CONFIG_H264PRED) += x86/h264_intrapred_init.o
OBJS-$(CONFIG_H264QPEL) += x86/h264_qpel.o
OBJS-$(CONFIG_HPELDSP) += x86/hpeldsp_init.o
+OBJS-$(CONFIG_LLAUDDSP) += x86/lossless_audiodsp_init.o
+OBJS-$(CONFIG_LLVIDDSP) += x86/lossless_videodsp_init.o
OBJS-$(CONFIG_HUFFYUVDSP) += x86/huffyuvdsp_init.o
OBJS-$(CONFIG_HUFFYUVENCDSP) += x86/huffyuvencdsp_mmx.o
OBJS-$(CONFIG_IDCTDSP) += x86/idctdsp_init.o
@@ -33,41 +37,42 @@ 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_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_V210_DECODER) += x86/v210-init.o
+OBJS-$(CONFIG_TTA_DECODER) += x86/ttadsp_init.o
+OBJS-$(CONFIG_TRUEHD_DECODER) += x86/mlpdsp_init.o
OBJS-$(CONFIG_VC1_DECODER) += x86/vc1dsp_init.o
OBJS-$(CONFIG_VORBIS_DECODER) += x86/vorbisdsp_init.o
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 +83,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_H263DSP) += x86/h263_loopfilter.o
YASM-OBJS-$(CONFIG_H264CHROMA) += x86/h264_chromamc.o \
x86/h264_chromamc_10bit.o
@@ -100,6 +112,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
@@ -112,14 +127,22 @@ 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_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
+YASM-OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp.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_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
@@ -127,4 +150,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 817d5a3..b244416 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
;******************************************************************************
diff --git a/libavcodec/x86/ac3dsp_init.c b/libavcodec/x86/ac3dsp_init.c
index cd638b9..30a85f9 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
diff --git a/libavcodec/x86/audiodsp.asm b/libavcodec/x86/audiodsp.asm
index f2e831d..273b9ef 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_init.c b/libavcodec/x86/audiodsp_init.c
index 743f5a3..a2ce231 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 cb55059..0000000
--- 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 0000000..c793858
--- /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 b529424..0000000
--- 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 0000000..7780184
--- /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 17a6cb1..ec060c9 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 ba40f2d..c042e56 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 d1701bf..3510336 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 b323a10..190f6ee 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,7 +139,7 @@ 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];
+ DECLARE_ALIGNED(16, int16_t, b2)[64];
for(i=0; i<2; i++){
DECLARE_ALIGNED(8, uint64_t, tmp);
@@ -198,7 +198,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 +212,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 +230,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 +271,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 +300,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 +340,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 +366,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 +378,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 +389,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 +462,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 +475,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 +493,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 +542,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 +565,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 5b8d1b2..aa3df00 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,8 +22,6 @@
#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(16, const xmm_reg, ff_pw_3) = { 0x0003000300030003ULL, 0x0003000300030003ULL };
@@ -43,11 +41,21 @@ DECLARE_ALIGNED(16, const xmm_reg, ff_pw_64) = { 0x0040004000400040ULL, 0x004
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(32, const ymm_reg, ff_pw_256) = { 0x0100010001000100ULL, 0x0100010001000100ULL,
+ 0x0100010001000100ULL, 0x0100010001000100ULL };
DECLARE_ALIGNED(16, const xmm_reg, ff_pw_512) = { 0x0200020002000200ULL, 0x0200020002000200ULL };
DECLARE_ALIGNED(16, const xmm_reg, ff_pw_1019) = { 0x03FB03FB03FB03FBULL, 0x03FB03FB03FB03FBULL };
+DECLARE_ALIGNED(16, const xmm_reg, ff_pw_1024) = { 0x0400040004000400ULL, 0x0400040004000400ULL };
+DECLARE_ALIGNED(16, const xmm_reg, ff_pw_2048) = { 0x0800080008000800ULL, 0x0800080008000800ULL };
+DECLARE_ALIGNED(16, const xmm_reg, ff_pw_8192) = { 0x2000200020002000ULL, 0x2000200020002000ULL };
+DECLARE_ALIGNED(16, const xmm_reg, ff_pw_m1) = { 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_1) = { 0x0101010101010101ULL, 0x0101010101010101ULL,
+ 0x0101010101010101ULL, 0x0101010101010101ULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pb_3) = { 0x0303030303030303ULL, 0x0303030303030303ULL,
+ 0x0303030303030303ULL, 0x0303030303030303ULL };
DECLARE_ALIGNED(16, const xmm_reg, ff_pb_80) = { 0x8080808080808080ULL, 0x8080808080808080ULL };
DECLARE_ALIGNED(8, const uint64_t, ff_pb_FC) = 0xFCFCFCFCFCFCFCFCULL;
+
+DECLARE_ALIGNED(16, const xmm_reg, ff_ps_neg) = { 0x8000000080000000ULL, 0x8000000080000000ULL };
diff --git a/libavcodec/x86/constants.h b/libavcodec/x86/constants.h
index f38fbe3..e75fff9 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,12 +25,13 @@
#include "libavutil/x86/asm.h"
-extern const uint64_t ff_wtwo;
-
+extern const xmm_reg ff_pw_1;
+extern const xmm_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;
@@ -42,10 +43,18 @@ 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 xmm_reg ff_pw_512;
+extern const xmm_reg ff_pw_1024;
+extern const xmm_reg ff_pw_2048;
+extern const xmm_reg ff_pw_8192;
+extern const xmm_reg ff_pw_m1;
-extern const xmm_reg ff_pb_1;
-extern const xmm_reg ff_pb_3;
+extern const ymm_reg ff_pb_1;
+extern const ymm_reg ff_pb_3;
+extern const xmm_reg ff_pb_80;
extern const xmm_reg ff_pb_F8;
extern const uint64_t ff_pb_FC;
+extern const xmm_reg ff_ps_neg;
+
#endif /* AVCODEC_X86_CONSTANTS_H */
diff --git a/libavcodec/x86/dca.h b/libavcodec/x86/dca.h
deleted file mode 100644
index 11d45ae..0000000
--- 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 c42ee23..1ac2378 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 9acb818..bb86c26 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 9d4aaf5..3414cb0 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,27 @@
#include "xvididct.h"
#include "simple_idct.h"
+#if ARCH_X86_64 && HAVE_MMX && HAVE_YASM
+void ff_prores_idct_put_10_sse2(uint16_t *dst, int linesize,
+ int16_t *block, int16_t *qmat);
+
+static void ff_prores_idct_put_10_sse2_wrap(int16_t *dst){
+ DECLARE_ALIGNED(16, static int16_t, qmat)[64];
+ DECLARE_ALIGNED(16, static int16_t, tmp)[64];
+ int i;
+
+ for(i=0; i<64; i++){
+ qmat[i]=4;
+ tmp[i]= dst[i];
+ }
+ ff_prores_idct_put_10_sse2(dst, 16, tmp, qmat);
+
+ for(i=0; i<64; i++) {
+ dst[i] -= 512;
+ }
+}
+#endif
+
static const struct algo fdct_tab_arch[] = {
#if HAVE_MMX_INLINE
{ "MMX", ff_fdct_mmx, FF_IDCT_PERM_NONE, AV_CPU_FLAG_MMX },
@@ -48,6 +69,9 @@ static const struct algo idct_tab_arch[] = {
#endif
#if HAVE_SSE2_INLINE
{ "XVID-SSE2", ff_xvid_idct_sse2, FF_IDCT_PERM_SSE2, AV_CPU_FLAG_SSE2, 1 },
+#if ARCH_X86_64 && HAVE_YASM
+ { "PR-SSE2", ff_prores_idct_put_10_sse2_wrap, FF_IDCT_PERM_TRANSPOSE, AV_CPU_FLAG_SSE2, 1 },
+#endif
#endif
#endif /* CONFIG_MPEG4_DECODER */
{ 0 }
diff --git a/libavcodec/x86/dct32.asm b/libavcodec/x86/dct32.asm
index 9c147b9..c70f6c9 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 7bda5e8..30c8f12 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 70d000e..baa9249 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
;******************************************************************************
diff --git a/libavcodec/x86/dirac_dwt.c b/libavcodec/x86/dirac_dwt.c
new file mode 100644
index 0000000..3c51ea6
--- /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 0000000..126b290
--- /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 0000000..11df5e3
--- /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 0000000..8985854
--- /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 0000000..d3cf9f1
--- /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 d39b07b..9dd6d51 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 f1ff7bd..fd6f150 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 0000000..658acc1
--- /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 6528b57..112566d 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 c94a977..648cdc5 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 4e8e4eb..0cb5fd6 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 e4744a3..877997e 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 a604956..398091e 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 7ca72c5..5682230 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 0000000..cedf083
--- /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 0000000..d60a6e4
--- /dev/null
+++ b/libavcodec/x86/flacdsp.asm
@@ -0,0 +1,329 @@
+;******************************************************************************
+;* 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 || WIN64
+ movd m3, r4m
+%if ARCH_X86_32
+ mov lend, lenm
+%endif
+%else ; UNIX64
+ movd m3, r4d
+%endif
+ 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 || WIN64
+ movd m3, r4m
+%if ARCH_X86_32
+ mov lend, lenm
+%endif
+%else ; UNIX64
+ movd m3, r4d
+%endif
+ 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);
+;-----------------------------------------------------------------------------------------
+%macro TRANSPOSE8x4D 9
+ 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
+%endmacro
+
+;%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
+ movd m%3, r4m
+%if %2 == 6
+ DEFINE_ARGS out, in0, in1, in2, in3, in4, in5
+ %define lend dword r3m
+%else
+ mov lend, lenm
+%endif
+%elif WIN64
+ movd m%3, r4m
+%else ; UNIX64
+ movd m%3, r4d
+%endif
+
+%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 0000000..d04af45
--- /dev/null
+++ b/libavcodec/x86/flacdsp_init.c
@@ -0,0 +1,117 @@
+/*
+ * 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)) {
+ if (bps > 16)
+ c->lpc = 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)) {
+ if (bps > 16)
+ c->lpc = ff_flac_lpc_32_xop;
+ }
+#endif
+
+#if CONFIG_FLAC_ENCODER
+ if (EXTERNAL_SSE4(cpu_flags)) {
+ if (CONFIG_GPL && bps == 16)
+ c->lpc_encode = ff_flac_enc_lpc_16_sse4;
+ }
+#endif
+#endif /* HAVE_YASM */
+}
diff --git a/libavcodec/x86/fmtconvert.asm b/libavcodec/x86/fmtconvert.asm
index 8184376..19595f7 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
;******************************************************************************
@@ -77,6 +77,44 @@ 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
;------------------------------------------------------------------------------
; void ff_float_to_int16(int16_t *dst, const float *src, long len);
diff --git a/libavcodec/x86/fmtconvert_init.c b/libavcodec/x86/fmtconvert_init.c
index 3d75df9..cbb96e2 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);
void ff_float_to_int16_3dnow(int16_t *dst, const float *src, long len);
void ff_float_to_int16_sse (int16_t *dst, const float *src, long len);
@@ -134,12 +138,14 @@ 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;
c->float_to_int16 = ff_float_to_int16_sse;
c->float_to_int16_interleave = float_to_int16_interleave_sse;
c->float_interleave = float_interleave_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;
c->float_to_int16 = ff_float_to_int16_sse2;
c->float_to_int16_interleave = float_to_int16_interleave_sse2;
}
diff --git a/libavcodec/x86/fpel.asm b/libavcodec/x86/fpel.asm
index b581471..0e3b444 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 88d1415..4d93959 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 eef05ec..0000000
--- 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/h263_loopfilter.asm b/libavcodec/x86/h263_loopfilter.asm
index 673f795..2fcd1a2 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 d4fab98..ab81063 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 cc41f00..107ae51 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 7b00351..c358482 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 d2067c8..14c8205 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 d049c62..d8ace17 100644
--- a/libavcodec/x86/h264_deblock_10bit.asm
+++ b/libavcodec/x86/h264_deblock_10bit.asm
@@ -7,20 +7,20 @@
;* 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
;******************************************************************************
@@ -418,9 +418,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 +717,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 +806,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 +924,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 bb881c3..ef65cf8 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
*/
@@ -38,7 +38,7 @@
//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 +55,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 +131,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
@@ -198,7 +200,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 313791a..7fafe19 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 b7d5105..5c3acb1 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
;******************************************************************************
@@ -83,8 +83,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 +119,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 +159,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 +226,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 +301,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 +340,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 +549,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 +591,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 df657a4..c88d91b 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 55790a9..b60a210 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,7 @@
SECTION_RODATA
+cextern pw_512
cextern pw_16
cextern pw_8
cextern pw_4
@@ -35,7 +36,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 +82,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 +121,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 +163,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 +218,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 +247,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 +559,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 +618,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 +654,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 +711,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 +780,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 +855,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 +926,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 +988,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 0e572b1..528b92e 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 9ca6d7e..b4cb9b1 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);\
@@ -339,7 +339,7 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc21_ ## MMX(uint8_t *dst, const uin
DECLARE_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);\
}\
@@ -349,7 +349,7 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc23_ ## MMX(uint8_t *dst, const uin
DECLARE_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);\
}\
@@ -359,7 +359,7 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc12_ ## MMX(uint8_t *dst, const uin
DECLARE_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);\
}\
@@ -369,7 +369,7 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc32_ ## MMX(uint8_t *dst, const uin
DECLARE_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 f92c4aa..d65660d 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
;******************************************************************************
@@ -28,7 +28,7 @@ SECTION_RODATA 32
cextern pw_16
cextern pw_1
-cextern pb_0
+pb_0: times 32 db 0 ; we do not use cextern here as old llvm-gcc fails to align it correctly
pw_pixel_max: times 8 dw ((1 << 10)-1)
diff --git a/libavcodec/x86/h264_qpel_8bit.asm b/libavcodec/x86/h264_qpel_8bit.asm
index bc6c725..2d287ba 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 d1873af..b4fb9db 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 961ec8c..5d94962 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
;******************************************************************************
diff --git a/libavcodec/x86/h264chroma_init.c b/libavcodec/x86/h264chroma_init.c
index 8ec8a79..e08af27 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 134d594..35db200 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 45b8703..f92cb2c 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,14 @@
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
+pw_pixel_max_12: times 8 dw ((1 << 12)-1)
+pw_pixel_max_10: times 8 dw ((1 << 10)-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 +58,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 +77,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 +90,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 +115,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 +131,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 +198,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 +230,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 +284,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
@@ -356,17 +323,17 @@ ALIGN 16
%if %1 > 8
shl betaq, %1 - 8
%endif
- movd m13, betaq
+ movd m13, betad
SPLATW m13, m13, 0
;end beta calculations
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 +347,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 +355,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 +385,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 +415,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 +426,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 +527,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 +571,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
@@ -620,7 +586,7 @@ ALIGN 16
paddw m15, m2; p1'
;beta calculations
- movd m10, betaq
+ movd m10, betad
SPLATW m10, m10, 0
movd m13, r7d; 1dp0 + 1dp3
@@ -658,117 +624,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 +793,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 +818,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 +863,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 0000000..481726d
--- /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 0000000..eaa070c
--- /dev/null
+++ b/libavcodec/x86/hevc_mc.asm
@@ -0,0 +1,1385 @@
+; /*
+; * 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
+pw_8: times 8 dw (1 << 9)
+pw_10: times 8 dw (1 << 11)
+pw_12: times 8 dw (1 << 13)
+pw_bi_8: times 8 dw (1 << 8)
+pw_bi_10: times 8 dw (1 << 10)
+pw_bi_12: times 8 dw (1 << 12)
+max_pixels_10: times 8 dw ((1 << 10)-1)
+max_pixels_12: times 8 dw ((1 << 12)-1)
+zero: times 4 dd 0
+one_per_32: times 4 dd 1
+
+SECTION .text
+%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, 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
+
+%define MAX_PB_SIZE 64
+
+%define hevc_qpel_filters_sse4_14 hevc_qpel_filters_sse4_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
+ movdqa %3, [%2] ; load data from source2
+ movq %4, [%2+16] ; load data from source2
+%else
+ movdqa %3, [%2] ; load data from source2
+ movdqa %4, [%2+16] ; load data from source2
+%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
+%else
+ movdqu %4, [%3] ; load data from source
+%endif
+%endmacro
+
+%macro SIMPLE_8LOAD 5 ;width, bitd, tab, r1, r2
+%if %1 == 2 || (%2 == 8 && %1 <= 4)
+ movq %4, [%3] ; load data from source2
+%elif %1 == 4 || (%2 == 8 && %1 <= 8)
+ movdqa %4, [%3] ; load data from source2
+%elif %1 <= 12
+ movdqa %4, [%3] ; load data from source2
+ movq %5, [%3+16] ; load data from source2
+%else
+ movdqa %4, [%3] ; load data from source2
+ movdqa %5, [%3+16] ; load data from source2
+%endif
+%endmacro
+
+%macro EPEL_FILTER 2-4 ; bit depth, filter index
+%ifdef PIC
+ lea rfilterq, [hevc_epel_filters_sse4_%1]
+%else
+ %define rfilterq hevc_epel_filters_sse4_%1
+%endif
+ sub %2q, 1
+ shl %2q, 5 ; multiply by 32
+%if %0 == 2
+ movdqa m14, [rfilterq + %2q] ; get 2 first values of filters
+ movdqa m15, [rfilterq + %2q+16] ; get 2 last values of filters
+%else
+ movdqa %3, [rfilterq + %2q] ; get 2 first values of filters
+ movdqa %4, [rfilterq + %2q+16] ; get 2 last values of filters
+%endif
+%endmacro
+
+%macro EPEL_HV_FILTER 1
+%ifdef PIC
+ lea rfilterq, [hevc_epel_filters_sse4_%1]
+%else
+ %define rfilterq hevc_epel_filters_sse4_%1
+%endif
+ sub mxq, 1
+ sub myq, 1
+ shl mxq, 5 ; multiply by 32
+ shl myq, 5 ; multiply by 32
+ movdqa m14, [rfilterq + mxq] ; get 2 first values of filters
+ movdqa m15, [rfilterq + mxq+16] ; get 2 last values of filters
+ lea r3srcq, [srcstrideq*3]
+
+%ifdef PIC
+ lea rfilterq, [hevc_epel_filters_sse4_10]
+%else
+ %define rfilterq hevc_epel_filters_sse4_10
+%endif
+ movdqa m12, [rfilterq + myq] ; get 2 first values of filters
+ movdqa m13, [rfilterq + myq+16] ; get 2 last values of filters
+%endmacro
+
+%macro QPEL_FILTER 2
+%ifdef PIC
+ lea rfilterq, [hevc_qpel_filters_sse4_%1]
+%else
+ %define rfilterq hevc_qpel_filters_sse4_%1
+%endif
+ lea %2q, [%2q*8-8]
+ movdqa m12, [rfilterq + %2q*8] ; get 4 first values of filters
+ movdqa m13, [rfilterq + %2q*8 + 16] ; get 4 first values of filters
+ movdqa m14, [rfilterq + %2q*8 + 32] ; get 4 first values of filters
+ movdqa m15, [rfilterq + %2q*8 + 48] ; get 4 first values of filters
+%endmacro
+
+%macro EPEL_LOAD 4
+%ifdef PIC
+ lea rfilterq, [%2]
+%else
+ %define rfilterq %2
+%endif
+%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, [rfilterq ]
+%ifnum %3
+ %%load m1, [rfilterq+ %3]
+ %%load m2, [rfilterq+2*%3]
+ %%load m3, [rfilterq+3*%3]
+%else
+ %%load m1, [rfilterq+ %3q]
+ %%load m2, [rfilterq+2*%3q]
+ %%load m3, [rfilterq+r3srcq]
+%endif
+
+%if %1 == 8
+%if %4 > 8
+ SBUTTERFLY bw, 0, 1, 10
+ SBUTTERFLY bw, 2, 3, 10
+%else
+ punpcklbw m0, m1
+ punpcklbw m2, m3
+%endif
+%else
+%if %4 > 4
+ SBUTTERFLY wd, 0, 1, 10
+ SBUTTERFLY wd, 2, 3, 10
+%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 movdqu
+%endif
+%else
+%if %3 == 2
+%define %%load movd
+%elif %3 == 4
+%define %%load movq
+%else
+%define %%load movdqu
+%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
+ punpcklwd m0, m1
+ punpcklwd m2, m3
+ punpcklwd m4, m5
+ punpcklwd 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
+ punpckldq m0, m1
+ punpckldq m2, m3
+ punpckldq m4, m5
+ punpckldq m6, m7
+%endif
+%endif
+%endmacro
+
+%macro QPEL_V_LOAD 5
+ lea %5q, [%2]
+ sub %5q, r3srcq
+ movdqu m0, [%5q ] ;load x- 3*srcstride
+ movdqu m1, [%5q+ %3q ] ;load x- 2*srcstride
+ movdqu m2, [%5q+ 2*%3q ] ;load x-srcstride
+ movdqu m3, [%2 ] ;load x
+ movdqu m4, [%2+ %3q] ;load x+stride
+ movdqu m5, [%2+ 2*%3q] ;load x+2*stride
+ movdqu m6, [%2+r3srcq] ;load x+3*stride
+ movdqu 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
+ PEL_10STORE8 %1, %2, %3
+ movdqa [%1+16], %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
+ movdqa [%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 ;width, bitdepth
+%if %2 == 8
+%if %1 > 8
+ punpckhbw m1, m0, m2
+ psllw m1, 14-%2
+%endif
+ punpcklbw m0, m2
+%endif
+ psllw m0, 14-%2
+%endmacro
+
+
+%macro EPEL_COMPUTE 4 ; bitdepth, width, filter1, filter2
+%if %1 == 8
+ pmaddubsw m0, %3 ;x1*c1+x2*c2
+ pmaddubsw m2, %4 ;x3*c3+x4*c4
+ paddw m0, m2
+%if %2 > 8
+ pmaddubsw m1, %3
+ pmaddubsw m3, %4
+ paddw m1, m3
+%endif
+%else
+ pmaddwd m0, %3
+ pmaddwd m2, %4
+ paddd m0, m2
+%if %2 > 4
+ pmaddwd m1, %3
+ pmaddwd m3, %4
+ paddd m1, m3
+%endif
+%if %1 != 8
+ psrad m0, %1-8
+ psrad m1, %1-8
+%endif
+ packssdw m0, m1
+%endif
+%endmacro
+
+%macro QPEL_HV_COMPUTE 4 ; width, bitdepth, filter idx
+%ifdef PIC
+ lea rfilterq, [hevc_qpel_filters_sse4_%2]
+%else
+ %define rfilterq hevc_qpel_filters_sse4_%2
+%endif
+
+%if %2 == 8
+ pmaddubsw m0, [rfilterq + %3q*8 ] ;x1*c1+x2*c2
+ pmaddubsw m2, [rfilterq + %3q*8+16] ;x3*c3+x4*c4
+ pmaddubsw m4, [rfilterq + %3q*8+32] ;x5*c5+x6*c6
+ pmaddubsw m6, [rfilterq + %3q*8+48] ;x7*c7+x8*c8
+ paddw m0, m2
+ paddw m4, m6
+ paddw m0, m4
+%else
+ pmaddwd m0, [rfilterq + %3q*8 ]
+ pmaddwd m2, [rfilterq + %3q*8+16]
+ pmaddwd m4, [rfilterq + %3q*8+32]
+ pmaddwd m6, [rfilterq + %3q*8+48]
+ 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+16]
+ pmaddwd m5, [rfilterq + %3q*8+32]
+ pmaddwd m7, [rfilterq + %3q*8+48]
+ 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 ; width, bitdepth
+%if %2 == 8
+ 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 ; width, bitd, src1l, src1h, scr2l, scr2h, pw
+ paddsw %3, %5
+%if %1 > 8
+ paddsw %4, %6
+%endif
+ UNI_COMPUTE %1, %2, %3, %4, %7
+%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
+ pminsw %3, [max_pixels_%2]
+ pmaxsw %3, [zero]
+%if %1 > 8
+ pminsw %4, [max_pixels_%2]
+ pmaxsw %4, [zero]
+%endif
+%endif
+%endmacro
+
+INIT_XMM sse4 ; adds ff_ and _sse4 to function name
+; ******************************
+; 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
+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
+ PEL_10STORE%1 dstq, m0, m1
+ LOOP_END dst, src, srcstride
+ RET
+
+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
+
+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
+ BI_COMPUTE %1, %2, m0, m1, m3, m4, m5
+ 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 width, int height, int mx, int my,
+; int16_t* mcbuffer)
+; ******************************
+
+
+%macro HEVC_PUT_HEVC_EPEL 2
+cglobal hevc_put_hevc_epel_h%1_%2, 5, 6, 6, dst, src, srcstride, height, mx, rfilter
+%assign %%stride ((%2 + 7)/8)
+ EPEL_FILTER %2, mx, m4, m5
+.loop
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m4, m5
+ PEL_10STORE%1 dstq, m0, m1
+ LOOP_END dst, src, srcstride
+ RET
+
+cglobal hevc_put_hevc_uni_epel_h%1_%2, 6, 7, 7, dst, dststride, src, srcstride, height, mx, rfilter
+%assign %%stride ((%2 + 7)/8)
+ movdqa m6, [pw_%2]
+ EPEL_FILTER %2, mx, m4, m5
+.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, 7, dst, dststride, src, srcstride, src2, height, mx, rfilter
+ movdqa m6, [pw_bi_%2]
+ EPEL_FILTER %2, mx, m4, m5
+.loop
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m4, m5
+ SIMPLE_BILOAD %1, src2q, m2, m3
+ BI_COMPUTE %1, %2, m0, m1, m2, m3, m6
+ 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 width, int height, int mx, int my,
+; int16_t* mcbuffer)
+; ******************************
+
+cglobal hevc_put_hevc_epel_v%1_%2, 6, 7, 6, dst, src, srcstride, height, r3src, my, rfilter
+ lea r3srcq, [srcstrideq*3]
+ sub srcq, srcstrideq
+ EPEL_FILTER %2, my, m4, m5
+.loop
+ EPEL_LOAD %2, srcq, srcstride, %1
+ EPEL_COMPUTE %2, %1, m4, m5
+ PEL_10STORE%1 dstq, m0, m1
+ LOOP_END dst, src, srcstride
+ RET
+
+cglobal hevc_put_hevc_uni_epel_v%1_%2, 7, 8, 7, dst, dststride, src, srcstride, height, r3src, my, rfilter
+ lea r3srcq, [srcstrideq*3]
+ movdqa m6, [pw_%2]
+ sub srcq, srcstrideq
+ EPEL_FILTER %2, my, m4, m5
+.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, 8, 9, 7, dst, dststride, src, srcstride, src2, height, r3src, my, rfilter
+ lea r3srcq, [srcstrideq*3]
+ movdqa m6, [pw_bi_%2]
+ sub srcq, srcstrideq
+ EPEL_FILTER %2, my, m4, m5
+.loop
+ EPEL_LOAD %2, srcq, srcstride, %1
+ EPEL_COMPUTE %2, %1, m4, m5
+ SIMPLE_BILOAD %1, src2q, m2, m3
+ BI_COMPUTE %1, %2, m0, m1, m2, m3, m6
+ 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 width, int height, int mx, int my)
+; ******************************
+
+%macro HEVC_PUT_HEVC_EPEL_HV 2
+cglobal hevc_put_hevc_epel_hv%1_%2, 6, 8, 12 , dst, src, srcstride, height, mx, my, r3src, rfilter
+%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
+ SWAP m4, m0
+ add srcq, srcstrideq
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+ SWAP m5, m0
+ add srcq, srcstrideq
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+ SWAP m6, m0
+ add srcq, srcstrideq
+.loop
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+ 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
+ PEL_10STORE%1 dstq, m0, m1
+ movdqa m4, m5
+ movdqa m5, m6
+ movdqa m6, m7
+ LOOP_END dst, src, srcstride
+ RET
+
+cglobal hevc_put_hevc_uni_epel_hv%1_%2, 7, 9, 12 , dst, dststride, src, srcstride, height, mx, my, r3src, rfilter
+%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
+ SWAP m4, m0
+ add srcq, srcstrideq
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+ SWAP m5, m0
+ add srcq, srcstrideq
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+ SWAP m6, m0
+ add srcq, srcstrideq
+.loop
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+ 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
+ UNI_COMPUTE %1, %2, m0, m1, [pw_%2]
+ PEL_%2STORE%1 dstq, m0, m1
+ movdqa m4, m5
+ movdqa m5, m6
+ movdqa m6, m7
+ 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, 10, 16, dst, dststride, src, srcstride, src2, height, mx, my, r3src, rfilter
+%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
+ SWAP m4, m0
+ add srcq, srcstrideq
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+ SWAP m5, m0
+ add srcq, srcstrideq
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+ SWAP m6, m0
+ add srcq, srcstrideq
+.loop
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+ 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
+ SIMPLE_BILOAD %1, src2q, m8, m9
+ BI_COMPUTE %1, %2, m0, m1, m8, m9, [pw_bi_%2]
+ PEL_%2STORE%1 dstq, m0, m1
+ movdqa m4, m5
+ movdqa m5, m6
+ movdqa m6, m7
+ 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 width, int height, int mx, int my)
+; ******************************
+
+%macro HEVC_PUT_HEVC_QPEL 2
+cglobal hevc_put_hevc_qpel_h%1_%2, 5, 6, 15, dst, src, srcstride, height, mx, rfilter
+ QPEL_FILTER %2, mx
+.loop
+ QPEL_H_LOAD %2, srcq, %1, 10
+ QPEL_COMPUTE %1, %2
+%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, 15 , dst, dststride, src, srcstride, height, mx, rfilter
+ movdqa 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
+%if %2 > 8
+ packssdw m0, m1
+%endif
+ SIMPLE_BILOAD %1, src2q, m10, m11
+ BI_COMPUTE %1, %2, m0, m1, m10, m11, m9
+ 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 width, int height, int mx, int my)
+; ******************************
+
+cglobal hevc_put_hevc_qpel_v%1_%2, 6, 8, 15, dst, src, srcstride, height, r3src, my, rfilter
+ lea r3srcq, [srcstrideq*3]
+ QPEL_FILTER %2, my
+.loop
+ QPEL_V_LOAD %2, srcq, srcstride, %1, r7
+ QPEL_COMPUTE %1, %2
+%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, 7, 9, 15, dst, dststride, src, srcstride, height, r3src, my, rfilter
+ 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, 8, 10, 16, dst, dststride, src, srcstride, src2, height, r3src, my, rfilter
+ movdqa m9, [pw_bi_%2]
+ lea r3srcq, [srcstrideq*3]
+ QPEL_FILTER %2, my
+.loop
+ SIMPLE_BILOAD %1, src2q, m10, m11
+ QPEL_V_LOAD %2, srcq, srcstride, %1, r9
+ QPEL_COMPUTE %1, %2
+%if %2 > 8
+ packssdw m0, m1
+%endif
+ BI_COMPUTE %1, %2, m0, m1, m10, m11, m9
+ 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, 12, dst, src, srcstride, height, mx, my, r3src, rfilter
+ lea mxq, [mxq*8-8]
+ lea myq, [myq*8-8]
+ 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, 12 , dst, dststride, src, srcstride, height, mx, my, r3src, rfilter
+ lea mxq, [mxq*8-8]
+ lea myq, [myq*8-8]
+ 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
+ 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
+ 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
+ lea mxq, [mxq*8-8]
+ lea myq, [myq*8-8]
+ 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, srcstride, 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, srcstride, 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, [one_per_32]
+ 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
+ pminsw m0, [max_pixels_%2]
+ pmaxsw m0, [zero]
+%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, 5, 7, 10, dst, dststride, src, srcstride, src2, height, denom, wx0, wx1, ox0, ox1
+ mov r6d, denomm
+%if %1 <= 4
+ pxor m1, m1
+%endif
+ movd m2, wx0m ; WX0
+ lea r6d, [r6d+14-%2] ; shift = 14 - bitd + denom
+ movd m3, wx1m ; WX1
+ movd m0, r6d ; shift
+%if %1 <= 4
+ punpcklwd m2, m1
+ punpcklwd m3, m1
+%else
+ punpcklwd m2, m2
+ punpcklwd m3, m3
+%endif
+ inc r6d
+ movd m5, r6d ; shift+1
+ pshufd m2, m2, 0
+ mov r6d, ox0m
+ pshufd m3, m3, 0
+ add r6d, ox1m
+%if %2 != 8
+ shl r6d, %2-8 ; ox << (bitd - 8)
+%endif
+ inc r6d
+ movd m4, r6d ; offset
+ pshufd m4, m4, 0
+ mov r6d, heightm
+ 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
+ pminsw m0, [max_pixels_%2]
+ pmaxsw m0, [zero]
+%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 r6d ; cmp height
+ jnz .loop ; height loop
+ RET
+%endmacro
+
+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 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
+
+%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 0000000..24b88ee
--- /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_RODATA 32
+max_pixels_10: times 16 dw ((1 << 10)-1)
+
+
+SECTION .text
+
+;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/hevcdsp.h b/libavcodec/x86/hevcdsp.h
new file mode 100644
index 0000000..8dea142
--- /dev/null
+++ b/libavcodec/x86/hevcdsp.h
@@ -0,0 +1,156 @@
+/*
+ * 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, ptrdiff_t _srcstride, 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, ptrdiff_t _srcstride, 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);
+///////////////////////////////////////////////////////////////////////////////
+// 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);
+
+///////////////////////////////////////////////////////////////////////////////
+// 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);
+
+
+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 04203c2..eaa97e1 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,627 @@ 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 LFL_FUNCS(type, depth) \
- LFL_FUNC(h, depth, ssse3) \
- LFL_FUNC(v, depth, ssse3)
+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, 8, 64, sse4);
+mc_rep_funcs(epel_hv, 8, 8, 48, sse4);
+mc_rep_funcs(epel_hv, 8, 8, 32, sse4);
+mc_rep_funcs(epel_hv, 8, 8, 24, sse4);
+mc_rep_funcs(epel_hv, 8, 8, 16, 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, ptrdiff_t _srcstride,\
+ 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, _srcstride, \
+ 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, ptrdiff_t _srcstride, \
+ 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, _srcstride, 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, MAX_PB_SIZE, 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, MAX_PB_SIZE, _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 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 )
-LFC_FUNCS(uint8_t, 8)
-LFC_FUNCS(uint8_t, 10)
-LFL_FUNCS(uint8_t, 8)
-LFL_FUNCS(uint8_t, 10)
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;
+ }
+ 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_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;
+ }
+ 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;
+
+ 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;
+ }
+
+ 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;
+ }
+ }
+ 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;
+
+ 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;
+ }
+
+ 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;
+ }
+ }
+ 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;
+ }
}
}
diff --git a/libavcodec/x86/hpeldsp.asm b/libavcodec/x86/hpeldsp.asm
index 073f7f9..2cef8e6 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 47b0b8b..5fae990 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 1cc3bac..bcae22f 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,8 +236,8 @@ 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) {
@@ -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,8 +272,8 @@ 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) {
@@ -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 c93c78e..0000000
--- 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 d854e8a..8cbc412 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 436abc8..cc48556 100644
--- a/libavcodec/x86/huffyuvdsp.asm
+++ b/libavcodec/x86/huffyuvdsp.asm
@@ -1,21 +1,22 @@
;******************************************************************************
;* 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
;******************************************************************************
@@ -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
@@ -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 75537d7..3ced3c0 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 8ffaced..63d8e3c 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 0000000..0aa7345
--- /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 22df3dd..daa4e79 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 853c6a3..2c26a98 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 7285b1d..0000000
--- 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 633fcd9..ce30b42 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 e4affab..3e65a76 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/apedsp.asm b/libavcodec/x86/lossless_audiodsp.asm
index d721ebd..64b769f 100644
--- a/libavcodec/x86/apedsp.asm
+++ b/libavcodec/x86/lossless_audiodsp.asm
@@ -1,20 +1,20 @@
;******************************************************************************
;* 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
;******************************************************************************
@@ -58,14 +58,7 @@ cglobal scalarproduct_and_madd_int16, 4,4,8, v1, v2, v3, order, mul
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
+ HADDD m6, m0
movd eax, m6
RET
%endmacro
@@ -159,9 +152,6 @@ SCALARPRODUCT_LOOP 4
SCALARPRODUCT_LOOP 2
SCALARPRODUCT_LOOP 0
.end:
- movhlps m0, m6
- paddd m6, m0
- pshuflw m0, m6, 0x4e
- paddd m6, m0
+ HADDD m6, m0
movd eax, m6
RET
diff --git a/libavcodec/x86/apedsp_init.c b/libavcodec/x86/lossless_audiodsp_init.c
index f692c2b..4879dff 100644
--- a/libavcodec/x86/apedsp_init.c
+++ b/libavcodec/x86/lossless_audiodsp_init.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 "libavutil/attributes.h"
#include "libavutil/cpu.h"
#include "libavutil/x86/cpu.h"
-#include "libavcodec/apedsp.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,
@@ -31,7 +31,7 @@ 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)
+av_cold void ff_llauddsp_init_x86(LLAudDSPContext *c)
{
int cpu_flags = av_get_cpu_flags();
diff --git a/libavcodec/x86/lossless_videodsp.asm b/libavcodec/x86/lossless_videodsp.asm
new file mode 100644
index 0000000..e6c23e7
--- /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 0000000..6589024
--- /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 ea5d2ea..3a9493f 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 a62094e..1cca05d 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
*/
@@ -24,6 +24,7 @@
#include "config.h"
#include "libavutil/common.h"
+#include "libavutil/x86/asm.h"
#if HAVE_INLINE_ASM
@@ -88,6 +89,7 @@ static inline av_const int mid_pred(int a, int b, int c)
return i;
}
+#if HAVE_6REGS
#define COPY3_IF_LT(x, y, a, b, c, d)\
__asm__ volatile(\
"cmpl %0, %3 \n\t"\
@@ -97,10 +99,11 @@ __asm__ volatile(\
: "+&r" (x), "+&r" (a), "+r" (c)\
: "r" (y), "r" (b), "r" (d)\
);
+#endif /* HAVE_6REGS */
#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 1a87f37..95b99c4 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
@@ -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,
+; int 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,608 @@ 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, int 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
+ movsxdifnidn lsizeq, lsized
+ 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, int 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, int 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, int 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, int 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,
+; int 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,
+; int 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 e93b67b..6dc59f5 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,
- int line_size, 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 * line_size */
- "lea (%1, %3, 2), %1 \n" /* pix2 += 2 * line_size */
-
- "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" ((x86_reg) line_size), "m" (h)
- : "%ecx");
-
- return tmp;
-}
-
-static int sse16_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
- int line_size, 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" ((x86_reg) line_size), "m" (h)
- : "%ecx");
-
- return tmp;
-}
-
-static int hf_noise8_mmx(uint8_t *pix1, int line_size, 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" ((x86_reg) line_size), "g" (h - 2)
- : "%ecx");
-
- return tmp;
-}
-
-static int hf_noise16_mmx(uint8_t *pix1, int line_size, 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,
+ int line_size, int h);
+int ff_sse16_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int line_size, int h);
+int ff_sse16_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int line_size, int h);
+int ff_hf_noise8_mmx(uint8_t *pix1, int lsize, int h);
+int ff_hf_noise16_mmx(uint8_t *pix1, int lsize, int h);
+int ff_sad8_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int stride, int h);
+int ff_sad16_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int stride, int h);
+int ff_sad16_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int stride, int h);
+int ff_sad8_x2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int stride, int h);
+int ff_sad16_x2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int stride, int h);
+int ff_sad16_x2_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int stride, int h);
+int ff_sad8_y2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int stride, int h);
+int ff_sad16_y2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int stride, int h);
+int ff_sad16_y2_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int stride, int h);
+int ff_sad8_approx_xy2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int stride, int h);
+int ff_sad16_approx_xy2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int stride, int h);
+int ff_sad16_approx_xy2_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int stride, int h);
+int ff_vsad_intra8_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int line_size, int h);
+int ff_vsad_intra16_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int line_size, int h);
+int ff_vsad_intra16_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int line_size, int h);
+int ff_vsad8_approx_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int line_size, int h);
+int ff_vsad16_approx_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int line_size, int h);
+int ff_vsad16_approx_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ int line_size, int h);
- "movq %%mm6, %%mm0\n"
- "psrlq $32, %%mm6\n"
- "paddd %%mm6, %%mm0\n"
- "movd %%mm0, %1\n"
- : "+r" (pix1), "=r" (tmp)
- : "r" ((x86_reg) line_size), "g" (h - 2)
- : "%ecx");
+#define hadamard_func(cpu) \
+ int ff_hadamard8_diff_ ## cpu(MpegEncContext *s, uint8_t *src1, \
+ uint8_t *src2, int stride, int h); \
+ int ff_hadamard8_diff16_ ## cpu(MpegEncContext *s, uint8_t *src1, \
+ uint8_t *src2, int stride, int h);
- return tmp + hf_noise8_mmx(pix + 8, line_size, 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,
int line_size, 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, line_size, h);
else
- score1 = sse16_mmx(c, pix1, pix2, line_size, h);
- score2 = hf_noise16_mmx(pix1, line_size, h) -
- hf_noise16_mmx(pix2, line_size, h);
+ score1 = ff_sse16_mmx(c, pix1, pix2, line_size, h);
+ score2 = ff_hf_noise16_mmx(pix1, line_size, h) + ff_hf_noise8_mmx(pix1+8, line_size, h)
+ - ff_hf_noise16_mmx(pix2, line_size, h) - ff_hf_noise8_mmx(pix2+8, line_size, 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,
int line_size, int h)
{
- int score1 = sse8_mmx(c, pix1, pix2, line_size, h);
- int score2 = hf_noise8_mmx(pix1, line_size, h) -
- hf_noise8_mmx(pix2, line_size, h);
+ int score1 = ff_sse8_mmx(c, pix1, pix2, line_size, h);
+ int score2 = ff_hf_noise8_mmx(pix1, line_size, h) -
+ ff_hf_noise8_mmx(pix2, line_size, 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,
int line_size, int h)
{
int tmp;
- assert((((int) pix) & 7) == 0);
- assert((line_size & 7) == 0);
+ av_assert2((((int) pix) & 7) == 0);
+ av_assert2((line_size & 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,
- int line_size, int h)
-{
- int tmp;
-
- assert((((int) pix) & 7) == 0);
- assert((line_size & 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" ((x86_reg) line_size), "m" (h)
- : "%ecx");
-
- return tmp;
-}
-#undef SUM
-
static int vsad16_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
int line_size, int h)
{
int tmp;
- assert((((int) pix1) & 7) == 0);
- assert((((int) pix2) & 7) == 0);
- assert((line_size & 7) == 0);
+ av_assert2((((int) pix1) & 7) == 0);
+ av_assert2((((int) pix2) & 7) == 0);
+ av_assert2((line_size & 7) == 0);
#define SUM(in0, in1, out0, out1) \
"movq (%0), %%mm2\n" \
@@ -624,190 +270,15 @@ 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,
- int line_size, int h)
-{
- int tmp;
-
- assert((((int) pix1) & 7) == 0);
- assert((((int) pix2) & 7) == 0);
- assert((line_size & 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" ((x86_reg) line_size), "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, int stride, int h)
{
- x86_reg len = -(stride * h);
+ x86_reg len = -(x86_reg)stride * h;
__asm__ volatile (
".p2align 4 \n\t"
"1: \n\t"
@@ -840,133 +311,10 @@ static inline void sad8_1_mmx(uint8_t *blk1, uint8_t *blk2, int stride, int h)
: "r" (blk1 - len), "r" (blk2 - len), "r" ((x86_reg) stride));
}
-static inline void sad8_1_mmxext(uint8_t *blk1, uint8_t *blk2,
- int 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" ((x86_reg) stride));
-}
-
-static int sad16_sse2(MpegEncContext *v, uint8_t *blk2, uint8_t *blk1,
- int 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" ((x86_reg) stride));
- return ret;
-}
-
-static inline void sad8_x2a_mmxext(uint8_t *blk1, uint8_t *blk2,
- int 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" ((x86_reg) stride));
-}
-
-static inline void sad8_y2a_mmxext(uint8_t *blk1, uint8_t *blk2,
- int 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" ((x86_reg) stride));
-}
-
-static inline void sad8_4_mmxext(uint8_t *blk1, uint8_t *blk2,
- int 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" ((x86_reg) stride));
-}
-
static inline void sad8_2_mmx(uint8_t *blk1a, uint8_t *blk1b, uint8_t *blk2,
int stride, int h)
{
- x86_reg len = -(stride * h);
+ x86_reg len = -(x86_reg)stride * h;
__asm__ volatile (
".p2align 4 \n\t"
"1: \n\t"
@@ -1004,7 +352,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, int stride, int h)
{
- x86_reg len = -(stride * h);
+ x86_reg len = -(x86_reg)stride * h;
__asm__ volatile (
"movq (%1, %%"REG_a"), %%mm0 \n\t"
"movq 1(%1, %%"REG_a"), %%mm2 \n\t"
@@ -1028,7 +376,7 @@ static inline void sad8_4_mmx(uint8_t *blk1, uint8_t *blk2, int stride, int h)
"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"
@@ -1052,7 +400,7 @@ static inline void sad8_4_mmx(uint8_t *blk1, uint8_t *blk2, int stride, int h)
" js 1b \n\t"
: "+a" (len)
: "r" (blk1 - len), "r" (blk1 - len + stride), "r" (blk2 - len),
- "r" ((x86_reg) stride));
+ "r" ((x86_reg) stride), "m" (round_tab[2]));
}
static inline int sum_mmx(void)
@@ -1070,15 +418,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, int stride, int h)
{
sad8_2_mmx(blk1, blk1 + 1, blk2, stride, h);
@@ -1093,7 +432,7 @@ static inline void sad8_y2a_mmx(uint8_t *blk1, uint8_t *blk2, int stride, int h)
static int sad8_ ## suf(MpegEncContext *v, uint8_t *blk2, \
uint8_t *blk1, int stride, int h) \
{ \
- assert(h == 8); \
+ av_assert2(h == 8); \
__asm__ volatile ( \
"pxor %%mm7, %%mm7 \n\t" \
"pxor %%mm6, %%mm6 \n\t" \
@@ -1107,7 +446,7 @@ static int sad8_ ## suf(MpegEncContext *v, uint8_t *blk2, \
static int sad8_x2_ ## suf(MpegEncContext *v, uint8_t *blk2, \
uint8_t *blk1, int stride, int h) \
{ \
- assert(h == 8); \
+ av_assert2(h == 8); \
__asm__ volatile ( \
"pxor %%mm7, %%mm7 \n\t" \
"pxor %%mm6, %%mm6 \n\t" \
@@ -1122,7 +461,7 @@ static int sad8_x2_ ## suf(MpegEncContext *v, uint8_t *blk2, \
static int sad8_y2_ ## suf(MpegEncContext *v, uint8_t *blk2, \
uint8_t *blk1, int stride, int h) \
{ \
- assert(h == 8); \
+ av_assert2(h == 8); \
__asm__ volatile ( \
"pxor %%mm7, %%mm7 \n\t" \
"pxor %%mm6, %%mm6 \n\t" \
@@ -1137,7 +476,7 @@ static int sad8_y2_ ## suf(MpegEncContext *v, uint8_t *blk2, \
static int sad8_xy2_ ## suf(MpegEncContext *v, uint8_t *blk2, \
uint8_t *blk1, int stride, int h) \
{ \
- assert(h == 8); \
+ av_assert2(h == 8); \
__asm__ volatile ( \
"pxor %%mm7, %%mm7 \n\t" \
"pxor %%mm6, %%mm6 \n\t" \
@@ -1207,32 +546,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,
- int line_size, int h);
-
-#define hadamard_func(cpu) \
- int ff_hadamard8_diff_ ## cpu(MpegEncContext *s, uint8_t *src1, \
- uint8_t *src2, int stride, int h); \
- int ff_hadamard8_diff16_ ## cpu(MpegEncContext *s, uint8_t *src1, \
- uint8_t *src2, int 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;
@@ -1245,77 +567,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 0000000..ce656af
--- /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_init.c
index 72fc637..dc0bc58 100644
--- a/libavcodec/x86/mlpdsp.c
+++ b/libavcodec/x86/mlpdsp_init.c
@@ -2,32 +2,47 @@
* MLP DSP functions x86-optimized
* Copyright (c) 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
*/
#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
+#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;
@@ -45,12 +60,12 @@ 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,
+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 *iirtable[5] = { &ff_mlp_iirorder_0, &ff_mlp_iirorder_1,
+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 };
@@ -179,9 +194,13 @@ static void mlp_filter_channel_x86(int32_t *state, const int32_t *coeff,
av_cold void ff_mlpdsp_init_x86(MLPDSPContext *c)
{
-#if HAVE_7REGS && HAVE_INLINE_ASM
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 533b4a7..2723167 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 1395156..b0028ce 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 0e5dd0f..941a8e2 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 47349d1..b410511 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 8d8d687..882d486 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 1274c13..1899ba2 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 9326ee7..aec73f8 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 7732e73..2a4db61 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 c8fd1b2..7c5377b 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 9582e0b..4d06a44 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 c05f3da..8e23ccf 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
;******************************************************************************
diff --git a/libavcodec/x86/pngdsp_init.c b/libavcodec/x86/pngdsp_init.c
index 34a3da3..7dca62c 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 a0e97b3..255eb24 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
@@ -422,7 +318,9 @@ 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 e82dac0..d647788 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
*/
@@ -32,7 +32,7 @@ void ff_prores_idct_put_10_sse4(uint16_t *dst, int linesize,
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();
diff --git a/libavcodec/x86/qpel.asm b/libavcodec/x86/qpel.asm
index 27a1c63..4e72d50 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 8f65550..dc0f900 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 cdefe50..3268d90 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 a9fb132..c9fd71e 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 4d9c35b..7732d65 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 586e4e9..99c56f9 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 0a242b5..fdd81a0 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 e006c76..2900e2d 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);
@@ -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 d7164b6..6f2e4f4 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,13 @@ 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_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 +142,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 +161,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 +249,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 +320,128 @@ 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
diff --git a/libavcodec/x86/sbrdsp_init.c b/libavcodec/x86/sbrdsp_init.c
index 9600852..a2aca74 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,25 @@ 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);
+
av_cold void ff_sbrdsp_init_x86(SBRDSPContext *s)
{
int cpu_flags = av_get_cpu_flags();
@@ -48,10 +64,16 @@ 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;
}
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;
}
}
diff --git a/libavcodec/x86/simple_idct.c b/libavcodec/x86/simple_idct.c
index 71763db..1d46212 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 4fc2914..4a98732 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 0000000..2778489
--- /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 */
+
+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 0000000..24ee70f
--- /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 02b0a84..0000000
--- 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 0000000..40b4b0e
--- /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 0000000..8f48949
--- /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 0000000..47dc87f
--- /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 0000000..02c5eaa
--- /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 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 0000000..400a1f3
--- /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/vc1dsp.asm b/libavcodec/x86/vc1dsp.asm
index adf08d7d..546688c 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 9b6c8ad..fdd4de1 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 aff4b26..2bef5f5 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 046affb..77a8e35 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" \
); \
}
@@ -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 53b9e82..25d4364 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 8ee8370..885cdf1 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 c54650e..b25d838 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 bbd8319..bc1cc43 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 fc8a047..24496ae 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
;******************************************************************************
diff --git a/libavcodec/x86/vp3dsp_init.c b/libavcodec/x86/vp3dsp_init.c
index ed38a8e..cc3eba4 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
*/
@@ -21,6 +23,7 @@
#include "libavutil/attributes.h"
#include "libavutil/cpu.h"
#include "libavutil/x86/cpu.h"
+#include "libavutil/x86/asm.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/vp3dsp.h"
#include "config.h"
@@ -39,10 +42,70 @@ 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);
+#if HAVE_MMX_INLINE
+
+#define MOVQ_BFE(regd) \
+ __asm__ volatile ( \
+ "pcmpeqd %%"#regd", %%"#regd" \n\t" \
+ "paddb %%"#regd", %%"#regd" \n\t" ::)
+
+#define PAVGBP_MMX_NO_RND(rega, regb, regr, regc, regd, regp) \
+ "movq "#rega", "#regr" \n\t" \
+ "movq "#regc", "#regp" \n\t" \
+ "pand "#regb", "#regr" \n\t" \
+ "pand "#regd", "#regp" \n\t" \
+ "pxor "#rega", "#regb" \n\t" \
+ "pxor "#regc", "#regd" \n\t" \
+ "pand %%mm6, "#regb" \n\t" \
+ "pand %%mm6, "#regd" \n\t" \
+ "psrlq $1, "#regb" \n\t" \
+ "psrlq $1, "#regd" \n\t" \
+ "paddb "#regb", "#regr" \n\t" \
+ "paddb "#regd", "#regp" \n\t"
+
+#if HAVE_6REGS
+static void put_vp_no_rnd_pixels8_l2_mmx(uint8_t *dst, const uint8_t *a, const uint8_t *b, ptrdiff_t stride, int h)
+{
+// START_TIMER
+ MOVQ_BFE(mm6);
+ __asm__ volatile(
+ "1: \n\t"
+ "movq (%1), %%mm0 \n\t"
+ "movq (%2), %%mm1 \n\t"
+ "movq (%1,%4), %%mm2 \n\t"
+ "movq (%2,%4), %%mm3 \n\t"
+ PAVGBP_MMX_NO_RND(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5)
+ "movq %%mm4, (%3) \n\t"
+ "movq %%mm5, (%3,%4) \n\t"
+
+ "movq (%1,%4,2), %%mm0 \n\t"
+ "movq (%2,%4,2), %%mm1 \n\t"
+ "movq (%1,%5), %%mm2 \n\t"
+ "movq (%2,%5), %%mm3 \n\t"
+ "lea (%1,%4,4), %1 \n\t"
+ "lea (%2,%4,4), %2 \n\t"
+ PAVGBP_MMX_NO_RND(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5)
+ "movq %%mm4, (%3,%4,2) \n\t"
+ "movq %%mm5, (%3,%5) \n\t"
+ "lea (%3,%4,4), %3 \n\t"
+ "subl $4, %0 \n\t"
+ "jnz 1b \n\t"
+ :"+r"(h), "+r"(a), "+r"(b), "+r"(dst)
+ :"r"((x86_reg)stride), "r"((x86_reg)3L*stride)
+ :"memory");
+// STOP_TIMER("put_vp_no_rnd_pixels8_l2_mmx")
+}
+#endif /*HAVE_6REGS */
+#endif /* HAVE_MMX_INLINE */
+
av_cold void ff_vp3dsp_init_x86(VP3DSPContext *c, int flags)
{
int cpu_flags = av_get_cpu_flags();
+#if HAVE_6REGS && HAVE_MMX_INLINE
+ c->put_no_rnd_pixels_l2 = put_vp_no_rnd_pixels8_l2_mmx;
+#endif /* HAVE_6REGS && HAVE_MMX_INLINE */
+
#if ARCH_X86_32
if (EXTERNAL_MMX(cpu_flags)) {
c->idct_put = ff_vp3_idct_put_mmx;
diff --git a/libavcodec/x86/vp56_arith.h b/libavcodec/x86/vp56_arith.h
index 0a69368..810cc8d 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 80f8ca5..3d874ea 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 cd94f3e..82baee7 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 adc9730..538b3f4 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 e5afd49..6668f91 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
*/
@@ -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 5d792e8..98bb669 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_init.c b/libavcodec/x86/vp9dsp_init.c
index ce58c08..2790024 100644
--- a/libavcodec/x86/vp9dsp_init.c
+++ b/libavcodec/x86/vp9dsp_init.c
@@ -1,187 +1,277 @@
/*
* 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) \
+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 int8_t (*filter)[32])
+#define mc_funcs(sz, opt) \
+mc_func(put, sz, h, opt); \
+mc_func(avg, sz, h, opt); \
+mc_func(put, sz, v, opt); \
+mc_func(avg, sz, v, opt)
+
+mc_funcs(4, ssse3);
+mc_funcs(8, ssse3);
+#if ARCH_X86_64
+mc_funcs(16, ssse3);
+mc_funcs(32, avx2);
+#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) \
+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 int8_t (*filter)[32]) \
+{ \
+ 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) \
+mc_rep_func(put, sz, hsz, h, opt); \
+mc_rep_func(avg, sz, hsz, h, opt); \
+mc_rep_func(put, sz, hsz, v, opt); \
+mc_rep_func(avg, sz, hsz, v, opt)
+
+#if ARCH_X86_32
+mc_rep_funcs(16, 8, ssse3);
+#endif
+mc_rep_funcs(32, 16, ssse3);
+mc_rep_funcs(64, 32, ssse3);
+#if ARCH_X86_64 && HAVE_AVX2_EXTERNAL
+mc_rep_funcs(64, 32, avx2);
+#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];
+
+#define filter_8tap_2d_fn(op, sz, f, 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_ssse3[f][mx - 1]); \
+ ff_vp9_##op##_8tap_1d_v_##sz##_##opt(dst, dst_stride, temp + 3 * 64, 64, \
+ h, ff_filters_ssse3[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) \
+filter_8tap_2d_fn(op, sz, FILTER_8TAP_REGULAR, regular, align, opt) \
+filter_8tap_2d_fn(op, sz, FILTER_8TAP_SHARP, sharp, align, opt) \
+filter_8tap_2d_fn(op, sz, FILTER_8TAP_SMOOTH, smooth, align, opt)
+
+#define filters_8tap_2d_fn2(op, align, opt) \
+filters_8tap_2d_fn(op, 64, align, opt) \
+filters_8tap_2d_fn(op, 32, align, opt) \
+filters_8tap_2d_fn(op, 16, align, opt) \
+filters_8tap_2d_fn(op, 8, align, opt) \
+filters_8tap_2d_fn(op, 4, align, opt)
+
+filters_8tap_2d_fn2(put, 16, ssse3)
+filters_8tap_2d_fn2(avg, 16, ssse3)
+#if ARCH_X86_64 && HAVE_AVX2_EXTERNAL
+filters_8tap_2d_fn(put, 64, 32, avx2)
+filters_8tap_2d_fn(put, 32, 32, avx2)
+filters_8tap_2d_fn(avg, 64, 32, avx2)
+filters_8tap_2d_fn(avg, 32, 32, avx2)
+#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, 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_ssse3[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) \
+filter_8tap_1d_fn(op, sz, FILTER_8TAP_REGULAR, regular, dir, dvar, opt) \
+filter_8tap_1d_fn(op, sz, FILTER_8TAP_SHARP, sharp, dir, dvar, opt) \
+filter_8tap_1d_fn(op, sz, FILTER_8TAP_SMOOTH, smooth, dir, dvar, opt)
+
+#define filters_8tap_1d_fn2(op, sz, opt) \
+filters_8tap_1d_fn(op, sz, h, mx, opt) \
+filters_8tap_1d_fn(op, sz, v, my, opt)
+
+#define filters_8tap_1d_fn3(op, opt) \
+filters_8tap_1d_fn2(op, 64, opt) \
+filters_8tap_1d_fn2(op, 32, opt) \
+filters_8tap_1d_fn2(op, 16, opt) \
+filters_8tap_1d_fn2(op, 8, opt) \
+filters_8tap_1d_fn2(op, 4, opt)
+
+filters_8tap_1d_fn3(put, ssse3)
+filters_8tap_1d_fn3(avg, ssse3)
+#if ARCH_X86_64 && HAVE_AVX2_EXTERNAL
+filters_8tap_1d_fn2(put, 64, avx2)
+filters_8tap_1d_fn2(put, 32, avx2)
+filters_8tap_1d_fn2(avg, 64, avx2)
+filters_8tap_1d_fn2(avg, 32, avx2)
+#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_funcs(4, ssse3);
+itxfm_funcs(8, ssse3);
+itxfm_funcs(8, avx);
+itxfm_funcs(16, ssse3);
+itxfm_funcs(16, avx);
+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)
+
+#define ipred_funcs(type, opt) \
+ipred_func(4, type, opt); \
+ipred_func(8, type, opt); \
+ipred_func(16, type, opt); \
+ipred_func(32, type, opt)
+
+ipred_funcs(dc, ssse3);
+ipred_funcs(dc_left, ssse3);
+ipred_funcs(dc_top, ssse3);
+
+#undef ipred_funcs
+
+ipred_func(8, v, mmx);
+ipred_func(16, v, sse2);
+ipred_func(32, v, sse2);
+
+#define ipred_func_set(size, type, opt1, opt2) \
+ipred_func(size, type, opt1); \
+ipred_func(size, type, opt2)
+
+#define ipred_funcs(type, opt1, opt2) \
+ipred_func(4, type, opt1); \
+ipred_func_set(8, type, opt1, opt2); \
+ipred_func_set(16, type, opt1, opt2); \
+ipred_func_set(32, type, opt1, opt2)
+
+ipred_funcs(h, ssse3, avx);
+ipred_funcs(tm, ssse3, avx);
+ipred_funcs(dl, ssse3, avx);
+ipred_funcs(dr, ssse3, avx);
+ipred_funcs(hu, ssse3, avx);
+ipred_funcs(hd, ssse3, avx);
+ipred_funcs(vl, ssse3, avx);
+ipred_funcs(vr, ssse3, avx);
+
+ipred_func(32, dc, avx2);
+ipred_func(32, dc_left, avx2);
+ipred_func(32, dc_top, avx2);
+ipred_func(32, v, avx2);
+ipred_func(32, h, avx2);
+ipred_func(32, tm, avx2);
+
+#undef ipred_funcs
+#undef ipred_func_set
+#undef ipred_func
+
#endif /* HAVE_YASM */
av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp)
@@ -189,52 +279,166 @@ av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp)
#if HAVE_YASM
int 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_ ## type ## sz ## _ ## opt
-
+#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
+ 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) \
+#define init_subpel2_32_64(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(1, idx, idxh, idxv, 32, dir, type, opt)
+
+#define init_subpel2(idx, idxh, idxv, dir, type, opt) \
+ init_subpel2_32_64(idx, idxh, idxv, 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) \
+#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)
+ init_subpel2(idx, 0, 1, v, type, opt); \
+ init_subpel2(idx, 1, 0, h, type, opt)
+
+#define init_lpf(opt) do { \
+ if (ARCH_X86_64) { \
+ 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(tx, sz, opt) do { \
+ dsp->intra_pred[tx][HOR_PRED] = ff_vp9_ipred_h_##sz##x##sz##_##opt; \
+ dsp->intra_pred[tx][DIAG_DOWN_LEFT_PRED] = ff_vp9_ipred_dl_##sz##x##sz##_##opt; \
+ dsp->intra_pred[tx][DIAG_DOWN_RIGHT_PRED] = ff_vp9_ipred_dr_##sz##x##sz##_##opt; \
+ dsp->intra_pred[tx][HOR_DOWN_PRED] = ff_vp9_ipred_hd_##sz##x##sz##_##opt; \
+ dsp->intra_pred[tx][VERT_LEFT_PRED] = ff_vp9_ipred_vl_##sz##x##sz##_##opt; \
+ dsp->intra_pred[tx][HOR_UP_PRED] = ff_vp9_ipred_hu_##sz##x##sz##_##opt; \
+ if (ARCH_X86_64 || tx != TX_32X32) { \
+ dsp->intra_pred[tx][VERT_RIGHT_PRED] = ff_vp9_ipred_vr_##sz##x##sz##_##opt; \
+ dsp->intra_pred[tx][TM_VP8_PRED] = ff_vp9_ipred_tm_##sz##x##sz##_##opt; \
+ } \
+} while (0)
+#define init_dc_ipred(tx, sz, opt) do { \
+ init_ipred(tx, sz, opt); \
+ dsp->intra_pred[tx][DC_PRED] = ff_vp9_ipred_dc_##sz##x##sz##_##opt; \
+ dsp->intra_pred[tx][LEFT_DC_PRED] = ff_vp9_ipred_dc_left_##sz##x##sz##_##opt; \
+ dsp->intra_pred[tx][TOP_DC_PRED] = ff_vp9_ipred_dc_top_##sz##x##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;
+ dsp->intra_pred[TX_8X8][VERT_PRED] = ff_vp9_ipred_v_8x8_mmx;
+ }
+
+ if (EXTERNAL_MMXEXT(cpu_flags)) {
+ init_fpel(4, 1, 4, avg, mmxext);
+ init_fpel(3, 1, 8, avg, 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);
}
if (EXTERNAL_SSE2(cpu_flags)) {
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->intra_pred[TX_16X16][VERT_PRED] = ff_vp9_ipred_v_16x16_sse2;
+ dsp->intra_pred[TX_32X32][VERT_PRED] = ff_vp9_ipred_v_32x32_sse2;
}
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;
+ if (ARCH_X86_64) {
+ 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_dc_ipred(TX_4X4, 4, ssse3);
+ init_dc_ipred(TX_8X8, 8, ssse3);
+ init_dc_ipred(TX_16X16, 16, ssse3);
+ init_dc_ipred(TX_32X32, 32, ssse3);
+ }
+
+ if (EXTERNAL_AVX(cpu_flags)) {
+ if (ARCH_X86_64) {
+ 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_ipred(TX_8X8, 8, avx);
+ init_ipred(TX_16X16, 16, avx);
+ init_ipred(TX_32X32, 32, avx);
+ }
+
+ 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_subpel2_32_64(0, 1, 1, hv, put, avx2);
+ init_subpel2_32_64(0, 0, 1, v, put, avx2);
+ init_subpel2_32_64(0, 1, 0, h, put, avx2);
+ init_subpel2_32_64(1, 1, 1, hv, avg, avx2);
+ init_subpel2_32_64(1, 0, 1, v, avg, avx2);
+ init_subpel2_32_64(1, 1, 0, h, avg, avx2);
+#endif
+ }
+ dsp->intra_pred[TX_32X32][DC_PRED] = ff_vp9_ipred_dc_32x32_avx2;
+ dsp->intra_pred[TX_32X32][LEFT_DC_PRED] = ff_vp9_ipred_dc_left_32x32_avx2;
+ dsp->intra_pred[TX_32X32][TOP_DC_PRED] = ff_vp9_ipred_dc_top_32x32_avx2;
+ dsp->intra_pred[TX_32X32][VERT_PRED] = ff_vp9_ipred_v_32x32_avx2;
+ dsp->intra_pred[TX_32X32][HOR_PRED] = ff_vp9_ipred_h_32x32_avx2;
+ dsp->intra_pred[TX_32X32][TM_VP8_PRED] = ff_vp9_ipred_tm_32x32_avx2;
}
#undef init_fpel
diff --git a/libavcodec/x86/vp9intrapred.asm b/libavcodec/x86/vp9intrapred.asm
new file mode 100644
index 0000000..c710793
--- /dev/null
+++ b/libavcodec/x86/vp9intrapred.asm
@@ -0,0 +1,1554 @@
+;******************************************************************************
+;* 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_7to1_9x0: db 7, 6, 5, 4
+pb_3to1_5x0: db 3, 2, 1
+ times 9 db 0
+pb_Fto0: db 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+
+pb_2: times 32 db 2
+pb_15: times 16 db 15
+
+cextern pb_1
+cextern pb_3
+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)
+
+INIT_MMX ssse3
+cglobal vp9_ipred_dc_4x4, 4, 4, 0, dst, stride, l, a
+ movd m0, [lq]
+ punpckldq m0, [aq]
+ pxor m1, m1
+ psadbw m0, m1
+ pmulhrsw m0, [pw_4096]
+ pshufb m0, m1
+ 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
+
+INIT_MMX ssse3
+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
+ pmulhrsw m0, [pw_2048]
+ pshufb m0, m2
+ 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 ssse3
+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
+ pmulhrsw m0, [pw_1024]
+ pshufb m0, m2
+ 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 ssse3
+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
+ pmulhrsw m0, [pw_512]
+ pshufb m0, m4
+ 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
+
+%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_FUNCS 2 ; dir (top or left), arg (a or l)
+INIT_MMX ssse3
+cglobal vp9_ipred_dc_%1_4x4, 4, 4, 0, dst, stride, l, a
+ movd m0, [%2q]
+ pxor m1, m1
+ psadbw m0, m1
+ pmulhrsw m0, [pw_8192]
+ pshufb m0, m1
+ 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
+
+INIT_MMX ssse3
+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
+ pmulhrsw m0, [pw_4096]
+ pshufb m0, m1
+ 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 ssse3
+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
+ pmulhrsw m0, [pw_2048]
+ pshufb m0, m2
+ 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 ssse3
+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
+ pmulhrsw m0, [pw_1024]
+ pshufb m0, m2
+ 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
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+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
+
+DC_1D_FUNCS top, a
+DC_1D_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 sse2
+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 sse2
+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
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+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
+%endif
+
+; h
+
+INIT_XMM ssse3
+cglobal vp9_ipred_h_4x4, 3, 4, 1, dst, stride, l, stride3
+ movd m0, [lq]
+ pshufb m0, [pb_4x3_4x2_4x1_4x0]
+ 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
+
+%macro H_XMM_FUNCS 1
+INIT_XMM %1
+cglobal vp9_ipred_h_8x8, 3, 5, 4, dst, stride, l, stride3, cnt
+ mova m2, [pb_8x1_8x0]
+ mova m3, [pb_8x3_8x2]
+ lea stride3q, [strideq*3]
+ mov cntq, 1
+.loop:
+ movd m0, [lq+cntq*4]
+ pshufb m1, m0, m3
+ pshufb m0, m2
+ 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
+
+INIT_XMM %1
+cglobal vp9_ipred_h_16x16, 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, 3
+.loop:
+ movd m3, [lq+cntq*4]
+ 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
+
+INIT_XMM %1
+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 m3, [lq+cntq*4]
+ pshufb m0, m3, m7
+ pshufb m1, m3, m6
+ mova [dstq+strideq*0+ 0], m0
+ mova [dstq+strideq*0+16], m0
+ mova [dstq+strideq*1+ 0], m1
+ mova [dstq+strideq*1+16], m1
+ pshufb m2, m3, m5
+ pshufb m3, m4
+ 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
+
+H_XMM_FUNCS ssse3
+H_XMM_FUNCS avx
+
+%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
+
+INIT_MMX ssse3
+cglobal vp9_ipred_tm_4x4, 4, 4, 0, dst, stride, l, a
+ pxor m1, m1
+ pinsrw m2, [aq-1], 0
+ movd m0, [aq]
+ DEFINE_ARGS dst, stride, l, cnt
+ mova m3, [pw_m256]
+ mova m4, [pw_m255]
+ pshufb m2, m3
+ punpcklbw m0, m1
+ psubw m0, m2
+ mov cntq, 1
+.loop:
+ pinsrw m2, [lq+cntq*2], 0
+ pshufb m1, m2, m4
+ pshufb m2, m3
+ paddw m1, m0
+ paddw m2, m0
+ packuswb m1, m1
+ packuswb m2, m2
+ movd [dstq+strideq*0], m1
+ movd [dstq+strideq*1], m2
+ lea dstq, [dstq+strideq*2]
+ dec cntq
+ jge .loop
+ RET
+
+%macro TM_XMM_FUNCS 1
+INIT_XMM %1
+cglobal vp9_ipred_tm_8x8, 4, 4, 5, dst, stride, l, a
+ pxor m1, m1
+ pinsrw m2, [aq-1], 0
+ movh m0, [aq]
+ DEFINE_ARGS dst, stride, l, cnt
+ mova m3, [pw_m256]
+ mova m4, [pw_m255]
+ pshufb m2, m3
+ punpcklbw m0, m1
+ psubw m0, m2
+ mov cntq, 3
+.loop:
+ pinsrw m2, [lq+cntq*2], 0
+ pshufb m1, m2, m4
+ pshufb m2, m3
+ paddw m1, m0
+ paddw m2, m0
+ packuswb m1, m2
+ movh [dstq+strideq*0], m1
+ movhps [dstq+strideq*1], m1
+ lea dstq, [dstq+strideq*2]
+ dec cntq
+ jge .loop
+ RET
+
+INIT_XMM %1
+cglobal vp9_ipred_tm_16x16, 4, 4, 8, dst, stride, l, a
+ pxor m3, m3
+ pinsrw m2, [aq-1], 0
+ 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, 7
+.loop:
+ pinsrw m7, [lq+cntq*2], 0
+ 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
+
+%if ARCH_X86_64
+INIT_XMM %1
+cglobal vp9_ipred_tm_32x32, 4, 4, 14, 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
+ mova m8, [pw_m256]
+ mova m9, [pw_m255]
+ pshufb m4, m8
+ 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
+ mov cntq, 15
+.loop:
+ pinsrw m13, [lq+cntq*2], 0
+ pshufb m7, m13, m9
+ pshufb m13, m8
+ paddw m4, m7, m0
+ paddw m5, m7, m1
+ paddw m6, m7, m2
+ paddw m7, m3
+ paddw m10, m13, m0
+ paddw m11, m13, m1
+ paddw m12, m13, m2
+ paddw m13, m3
+ packuswb m4, m5
+ packuswb m6, m7
+ packuswb m10, m11
+ packuswb m12, m13
+ mova [dstq+strideq*0+ 0], m4
+ mova [dstq+strideq*0+16], m6
+ mova [dstq+strideq*1+ 0], m10
+ mova [dstq+strideq*1+16], m12
+ lea dstq, [dstq+strideq*2]
+ dec cntq
+ jge .loop
+ RET
+%endif
+%endmacro
+
+TM_XMM_FUNCS ssse3
+TM_XMM_FUNCS avx
+
+%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
+
+INIT_MMX ssse3
+cglobal vp9_ipred_dl_4x4, 4, 4, 0, dst, stride, l, a
+ movq m1, [aq]
+ pshufb m0, m1, [pb_0to5_2x7]
+ pshufb m2, m1, [pb_2to6_3x7]
+ 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
+
+%macro DL_XMM_FUNCS 1
+INIT_XMM %1
+cglobal vp9_ipred_dl_8x8, 4, 4, 4, dst, stride, stride5, a
+ movq m0, [aq]
+ lea stride5q, [strideq*5]
+ pshufb m1, m0, [pb_1to6_10x7]
+ psrldq m2, m1, 1
+ shufps m0, m1, q3210
+ 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
+
+INIT_XMM %1
+cglobal vp9_ipred_dl_16x16, 4, 4, 6, dst, stride, l, a
+ mova m5, [pb_1toE_2xF]
+ mova m0, [aq]
+ pshufb m1, m0, m5
+ pshufb m2, m1, m5
+ pshufb m4, m0, [pb_15]
+ LOWPASS 0, 1, 2, 3
+ DEFINE_ARGS dst, stride, cnt, stride9
+ lea stride9q, [strideq*3]
+ mov cntd, 4
+ lea stride9q, [stride9q*3]
+
+.loop:
+ movhlps m4, m0
+ mova [dstq+strideq*0], m0
+ pshufb m0, m5
+ mova [dstq+strideq*8], m4
+ movhlps m4, m0
+ mova [dstq+strideq*1], m0
+ pshufb m0, m5
+ mova [dstq+stride9q ], m4
+ lea dstq, [dstq+strideq*2]
+ dec cntd
+ jg .loop
+ RET
+
+INIT_XMM %1
+cglobal vp9_ipred_dl_32x32, 4, 5, 8, dst, stride, cnt, a, dst16
+ mova m5, [pb_1toE_2xF]
+ mova m0, [aq]
+ mova m1, [aq+16]
+ palignr m2, m1, m0, 1
+ palignr m3, m1, m0, 2
+ LOWPASS 0, 2, 3, 4
+ pshufb m2, m1, m5
+ pshufb m3, m2, m5
+ pshufb m6, m1, [pb_15]
+ LOWPASS 1, 2, 3, 4
+ mova m7, m6
+ 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
+%else
+ palignr m2, m1, m0, 1
+ pshufb m1, m5
+ mova m0, m2
+%endif
+ add dstq, strideq
+ add dst16q, strideq
+ dec cntd
+ jg .loop
+ RET
+%endmacro
+
+DL_XMM_FUNCS ssse3
+DL_XMM_FUNCS avx
+
+; dr
+
+INIT_MMX ssse3
+cglobal vp9_ipred_dr_4x4, 4, 4, 0, dst, stride, l, a
+ movd m0, [lq]
+ punpckldq m0, [aq-1]
+ movd m1, [aq+3]
+ DEFINE_ARGS dst, stride, stride3
+ lea stride3q, [strideq*3]
+ palignr m1, m0, 1
+ 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
+
+%macro DR_XMM_FUNCS 1
+INIT_XMM %1
+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
+ 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
+
+INIT_XMM %1
+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
+ palignr m3, m2, m1, 15
+ LOWPASS 3, 2, 4, 5
+ pslldq m0, m1, 1
+ palignr m2, m1, 1
+ 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
+ pslldq m0, 1
+ mova [dstq+strideq*1 ], m3
+ movhps [dstq+stride9q +0], m0
+ movq [dstq+stride9q +8], m3
+ palignr m3, m0, 15
+ pslldq m0, 1
+ lea dstq, [dstq+strideq*2]
+ dec cntd
+ jg .loop
+ RET
+
+INIT_XMM %1
+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
+ palignr m6, m4, m3, 15
+ LOWPASS 5, 4, 6, 7
+ palignr m4, m3, 1
+ palignr m6, m3, m2, 15
+ LOWPASS 4, 3, 6, 7
+ palignr m3, m2, 1
+ palignr m6, m2, m1, 15
+ LOWPASS 3, 2, 6, 7
+ palignr m2, m1, 1
+ 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
+ palignr m4, m3, 15
+ palignr m3, m2, 15
+ pslldq m2, 1
+ add dstq, strideq
+ dec cntd
+ jg .loop
+ RET
+%endmacro
+
+DR_XMM_FUNCS ssse3
+DR_XMM_FUNCS avx
+
+; vl
+
+INIT_MMX ssse3
+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 1
+INIT_XMM %1
+cglobal vp9_ipred_vl_8x8, 4, 4, 4, dst, stride, l, a
+ movq m0, [aq]
+ pshufb m0, [pb_0to6_9x7]
+ 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
+
+INIT_XMM %1
+cglobal vp9_ipred_vl_16x16, 4, 4, 5, dst, stride, l, a
+ mova m0, [aq]
+ mova m4, [pb_1toE_2xF]
+ DEFINE_ARGS dst, stride, stride3, cnt
+ lea stride3q, [strideq*3]
+ pshufb m1, m0, m4
+ pshufb m2, m1, m4
+ LOWPASS 2, 1, 0, 3
+ pavgb m1, m0
+ mov cntd, 4
+.loop:
+ mova [dstq+strideq*0], m1
+ mova [dstq+strideq*1], m2
+ pshufb m1, m4
+ pshufb m2, m4
+ mova [dstq+strideq*2], m1
+ mova [dstq+stride3q ], m2
+ pshufb m1, m4
+ pshufb m2, m4
+ lea dstq, [dstq+strideq*4]
+ dec cntd
+ jg .loop
+ RET
+
+INIT_XMM %1
+cglobal vp9_ipred_vl_32x32, 4, 4, 7, dst, stride, l, a
+ mova m0, [aq]
+ mova m5, [aq+16]
+ mova m4, [pb_1toE_2xF]
+ DEFINE_ARGS dst, stride, dst16, cnt
+ palignr m2, m5, m0, 1
+ palignr m3, m5, m0, 2
+ lea dst16q, [dstq +strideq*8]
+ LOWPASS 3, 2, 0, 6
+ pavgb m2, m0
+ pshufb m0, m5, m4
+ pshufb m1, m0, m4
+ lea dst16q, [dst16q+strideq*8]
+ LOWPASS 1, 0, 5, 6
+ pavgb m0, m5
+ pshufb m5, [pb_15]
+ 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
+%else
+ palignr m6, %3, %2, 1
+ pshufb %3, m4
+ mova %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
+
+VL_XMM_FUNCS ssse3
+VL_XMM_FUNCS avx
+
+; vr
+
+INIT_MMX ssse3
+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
+ 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
+
+ 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
+ RET
+
+%macro VR_XMM_FUNCS 1
+INIT_XMM %1
+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
+ 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
+
+ punpcklqdq m0, m1 ; ABCDEFGHxxVUTSRQ
+ movq [dstq+strideq*0], m0
+ pshufb m0, [pb_6xm1_BDF_0to6] ; xxxxxxUSQABCDEFG
+ movhps [dstq+strideq*1], m1
+ pshufb m1, [pb_6xm1_246_8toE] ; xxxxxxVTRIJKLMNO
+ movhps [dstq+strideq*2], m0
+ pslldq m0, 1
+ movhps [dstq+stride3q ], m1
+ lea dstq, [dstq+strideq*4]
+ pslldq m1, 1
+ movhps [dstq+strideq*0], m0
+ pslldq m0, 1
+ movhps [dstq+strideq*1], m1
+ pslldq m1, 1
+ movhps [dstq+strideq*2], m0
+ movhps [dstq+stride3q ], m1
+ RET
+
+INIT_XMM %1
+cglobal vp9_ipred_vr_16x16, 4, 4, 6, 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
+ LOWPASS 3, 1, 0, 4
+ pavgb m0, m1
+ palignr m1, m2, 1
+ pslldq m4, m2, 1
+ LOWPASS 1, 2, 4, 5
+ pshufb m1, [pb_02468ACE_13579BDF]
+ mov cntd, 4
+
+.loop:
+ movlhps m2, m1
+ mova [dstq+strideq*0], m0
+ mova [dstq+strideq*1], m3
+ palignr m4, m0, m1, 15
+ palignr m5, m3, m2, 15
+ mova [dstq+strideq*2], m4
+ mova [dstq+stride3q ], m5
+ lea dstq, [dstq+strideq*4]
+ palignr m0, m1, 14
+ palignr m3, m2, 14
+ pslldq m1, 2
+ dec cntd
+ jg .loop
+ RET
+
+%if ARCH_X86_64
+INIT_XMM %1
+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
+ palignr m4, m2, m0, 14
+ LOWPASS 4, 3, 2, 5
+ pavgb m3, m2
+ mova m2, [lq+16]
+ palignr m5, m1, m2, 15
+ LOWPASS 5, 1, 0, 6
+ pavgb m0, m1
+ mova m6, [lq]
+ palignr m1, m2, 1
+ palignr m7, m2, m6, 15
+ LOWPASS 1, 2, 7, 8
+ palignr m2, m6, 1
+ pslldq m7, m6, 1
+ LOWPASS 2, 6, 7, 8
+ pshufb m1, [pb_02468ACE_13579BDF]
+ pshufb m2, [pb_02468ACE_13579BDF]
+ DEFINE_ARGS dst, stride, dst16, cnt
+ lea dst16q, [dstq +strideq*8]
+ lea dst16q, [dst16q+strideq*8]
+ SBUTTERFLY qdq, 2, 1, 6
+ 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
+ palignr %3, %2, 15
+ 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
+%endif
+%endmacro
+
+VR_XMM_FUNCS ssse3
+VR_XMM_FUNCS avx
+
+; hd
+
+INIT_MMX ssse3
+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 1
+INIT_XMM %1
+cglobal vp9_ipred_hd_8x8, 4, 4, 4, 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
+ movhps [dstq +strideq*2], m3
+ movq [dst4q+strideq*2], m3
+ palignr m3, m2, m1, 4
+ movhps [dstq +strideq*1], m3
+ movq [dst4q+strideq*1], m3
+ palignr m2, m1, 6
+ movhps [dstq +strideq*0], m2
+ movq [dst4q+strideq*0], m2
+ RET
+
+INIT_XMM %1
+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
+ palignr m2, m3, m0, 2
+ 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
+%else
+ palignr m3, m2, m1, 2
+ palignr m0, m5, m2, 2
+ mova m1, m3
+ mova m2, m0
+%endif
+ psrldq m5, 2
+ jg .loop
+ RET
+
+INIT_XMM %1
+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
+ palignr m3, m2, 1
+ LOWPASS 4, 3, 2, 6
+ palignr m3, m2, m1, 2
+ palignr m2, m1, 1
+ LOWPASS 3, 2, 1, 6
+ pavgb m2, m1
+ palignr m6, m1, m0, 1
+ palignr m1, m0, 2
+ 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
+%else
+ 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
+%endif
+ jg .loop
+ RET
+%endmacro
+
+HD_XMM_FUNCS ssse3
+HD_XMM_FUNCS avx
+
+INIT_MMX ssse3
+cglobal vp9_ipred_hu_4x4, 3, 3, 0, dst, stride, l
+ movd m0, [lq]
+ pshufb m0, [pb_3to1_5x0]
+ 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
+ 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
+
+%macro HU_XMM_FUNCS 1
+INIT_XMM %1
+cglobal vp9_ipred_hu_8x8, 3, 4, 4, dst, stride, l
+ movq m0, [lq]
+ pshufb m0, [pb_7to1_9x0]
+ 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
+ movq [dstq +strideq*1], m0
+ movhps [dst4q+strideq*1], m0
+ palignr m0, m2, m1, 4
+ movq [dstq +strideq*2], m0
+ movhps [dst4q+strideq*2], m0
+ palignr m2, m1, 6
+ movq [dstq +stride3q ], m2
+ movhps [dst4q+stride3q ], m2
+ RET
+
+INIT_XMM %1
+cglobal vp9_ipred_hu_16x16, 3, 4, 5, dst, stride, l
+ mova m0, [lq]
+ pshufb m0, [pb_Fto0]
+ mova m3, [pb_2toE_3xF]
+ pshufb m1, m0, [pb_1toE_2xF]
+ pshufb m2, m0, m3
+ LOWPASS 2, 1, 0, 4
+ pavgb m1, m0
+ DEFINE_ARGS dst, stride, stride9, cnt
+ lea stride9q, [strideq *3]
+ mov cntd, 4
+ lea stride9q, [stride9q*3]
+ SBUTTERFLY bw, 1, 2, 0
+
+.loop:
+ mova [dstq+strideq*0], m1
+ mova [dstq+strideq*8], m2
+ palignr m0, m2, m1, 2
+ pshufb m2, m3
+ mova [dstq+strideq*1], m0
+ mova [dstq+stride9q ], m2
+ palignr m1, m2, m0, 2
+ pshufb m2, m3
+ lea dstq, [dstq+strideq*2]
+ dec cntd
+ jg .loop
+ RET
+
+INIT_XMM %1
+cglobal vp9_ipred_hu_32x32, 3, 7, 7, dst, stride, l
+ mova m0, [lq]
+ mova m1, [lq+16]
+ mova m2, [pb_Fto0]
+ mova m4, [pb_2toE_3xF]
+ pshufb m0, m2
+ pshufb m1, m2
+ palignr m2, m0, m1, 1
+ palignr m3, m0, m1, 2
+ LOWPASS 3, 2, 1, 5
+ pavgb m2, m1
+ pshufb m1, m0, m4
+ pshufb m5, m0, [pb_1toE_2xF]
+ 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
+ pshufb m6, m1, [pb_15]
+
+.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
+%else
+ 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
+%endif
+ add stride0q, strideq
+ dec cntd
+ jg .loop
+ RET
+%endmacro
+
+HU_XMM_FUNCS ssse3
+HU_XMM_FUNCS avx
+
+; FIXME 127, 128, 129 ?
diff --git a/libavcodec/x86/vp9itxfm.asm b/libavcodec/x86/vp9itxfm.asm
new file mode 100644
index 0000000..6cce0aa
--- /dev/null
+++ b/libavcodec/x86/vp9itxfm.asm
@@ -0,0 +1,1670 @@
+;******************************************************************************
+;* 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
+
+%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
+
+pd_8192: times 4 dd 8192
+
+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
+ 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
+ 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
+ mova m5, [pw_2048]
+ pmulhrsw m0, m5 ; (x*2048 + (1<<14))>>15 <=> (x+8)>>4
+ pmulhrsw m1, m5
+ VP9_STORE_2X 0, 1, 6, 7, 4
+ lea dstq, [dstq+2*strideq]
+ pmulhrsw m2, m5
+ pmulhrsw m3, m5
+ VP9_STORE_2X 2, 3, 6, 7, 4
+%endmacro
+
+INIT_MMX ssse3
+cglobal vp9_idct_idct_4x4_add, 4,4,0, dst, stride, block, eob
+
+ cmp eobd, 4 ; 2x2 or smaller
+ jg .idctfull
+
+ cmp eobd, 1 ; faster path for when only DC is set
+ jne .idct2x2
+
+ movd m0, [blockq]
+ mova m5, [pw_11585x2]
+ pmulhrsw m0, m5
+ pmulhrsw m0, m5
+ pshufw m0, m0, 0
+ pxor m4, m4
+ movh [blockq], m4
+ pmulhrsw m0, [pw_2048] ; (x*2048 + (1<<14))>>15 <=> (x+8)>>4
+ VP9_STORE_2X 0, 0, 6, 7, 4
+ lea dstq, [dstq+2*strideq]
+ VP9_STORE_2X 0, 0, 6, 7, 4
+ RET
+
+; 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
+ TRANSPOSE4x4W 0, 1, 2, 3, 4
+ 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
+
+.idctfull: ; generic full 4x4 idct/idct
+ mova m0, [blockq+ 0]
+ mova m1, [blockq+ 8]
+ mova m2, [blockq+16]
+ mova m3, [blockq+24]
+ mova m6, [pw_11585x2]
+ 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
+
+;-------------------------------------------------------------------------------------------
+; 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
+ paddw m3, m0
+ 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]
+ psubw m3, m2
+ paddd xmm0, xmm2
+ paddd xmm3, [pd_8192]
+ paddd xmm2, [pd_8192]
+ paddd xmm1, xmm3
+ paddd xmm0, xmm3
+ paddd xmm4, xmm2
+ psrad xmm1, 14
+ psrad xmm0, 14
+ psrad xmm4, 14
+ pmulhrsw m3, [pw_13377x2] ; out2
+ packssdw xmm0, xmm0
+ packssdw xmm1, xmm1
+ packssdw xmm4, xmm4
+ movdq2q m0, xmm0 ; out3
+ movdq2q m1, xmm1 ; out0
+ movdq2q m2, xmm4 ; out1
+ SWAP 0, 1, 2, 3
+%endmacro
+
+%macro IADST4_FN 5
+INIT_MMX %5
+cglobal vp9_%1_%3_4x4_add, 3, 3, 8, dst, stride, block, eob
+ mova m0, [blockq+ 0]
+ mova m1, [blockq+ 8]
+ mova m2, [blockq+16]
+ mova m3, [blockq+24]
+ mova m6, [pw_11585x2]
+ mova m7, [pd_8192] ; rounding
+ 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, ssse3
+IADST4_FN iadst, IADST4, idct, IDCT4, ssse3
+IADST4_FN iadst, IADST4, iadst, IADST4, ssse3
+
+%if ARCH_X86_64 ; TODO: 32-bit? (32-bit limited to 8 xmm reg, we use more)
+
+;-------------------------------------------------------------------------------------------
+; 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, 10, 4 ; m3=t0+t7, m10=t0-t7
+ SUMSUB_BA w, 1, 2, 4 ; m1=t1+t6, m2=t1-t6
+ SUMSUB_BA w, 11, 0, 4 ; m11=t2+t5, m0=t2-t5
+ SUMSUB_BA w, 9, 8, 4 ; m9=t3+t4, m8=t3-t4
+ SWAP 11, 10, 2
+ SWAP 3, 9, 0
+%endmacro
+
+%macro VP9_IDCT8_1D 0
+ SUMSUB_BA w, 8, 0, 4 ; m8=IN(0)+IN(4) m0=IN(0)-IN(4)
+ pmulhrsw m8, m12 ; m8=t0a
+ pmulhrsw m0, m12 ; m0=t1a
+ VP9_UNPACK_MULSUB_2W_4X 2, 10, 15137, 6270, m7, 4, 5 ; m2=t2a, m10=t3a
+ VP9_UNPACK_MULSUB_2W_4X 1, 11, 16069, 3196, m7, 4, 5 ; m1=t4a, m11=t7a
+ VP9_UNPACK_MULSUB_2W_4X 9, 3, 9102, 13623, m7, 4, 5 ; m9=t5a, m3=t6a
+ SUMSUB_BA w, 10, 8, 4 ; m10=t0a+t3a (t0), m8=t0a-t3a (t3)
+ SUMSUB_BA w, 2, 0, 4 ; m2=t1a+t2a (t1), m0=t1a-t2a (t2)
+ SUMSUB_BA w, 9, 1, 4 ; m9=t4a+t5a (t4), m1=t4a-t5a (t5a)
+ SUMSUB_BA w, 3, 11, 4 ; m3=t7a+t6a (t7), m11=t7a-t6a (t6a)
+ SUMSUB_BA w, 1, 11, 4 ; m1=t6a+t5a (t6), m11=t6a-t5a (t5)
+ pmulhrsw m1, m12 ; m1=t6
+ pmulhrsw m11, m12 ; m11=t5
+ VP9_IDCT8_1D_FINALIZE
+%endmacro
+
+%macro VP9_IDCT8_4x4_1D 0
+ pmulhrsw m0, m12 ; m0=t1a/t0a
+ pmulhrsw m10, m2, [pw_15137x2] ; m10=t3a
+ pmulhrsw m2, [pw_6270x2] ; m2=t2a
+ pmulhrsw m11, m1, [pw_16069x2] ; m11=t7a
+ pmulhrsw m1, [pw_3196x2] ; m1=t4a
+ pmulhrsw m9, m3, [pw_9102x2] ; m9=-t5a
+ pmulhrsw m3, [pw_13623x2] ; m3=t6a
+ psubw m8, m0, m10 ; m8=t0a-t3a (t3)
+ paddw m10, m0 ; m10=t0a+t3a (t0)
+ SUMSUB_BA w, 2, 0, 4 ; m2=t1a+t2a (t1), m0=t1a-t2a (t2)
+ SUMSUB_BA w, 9, 1, 4 ; m1=t4a+t5a (t4), m9=t4a-t5a (t5a)
+ SWAP 1, 9
+ SUMSUB_BA w, 3, 11, 4 ; m3=t7a+t6a (t7), m11=t7a-t6a (t6a)
+ SUMSUB_BA w, 1, 11, 4 ; m1=t6a+t5a (t6), m11=t6a-t5a (t5)
+ pmulhrsw m1, m12 ; m1=t6
+ pmulhrsw m11, m12 ; m11=t5
+ VP9_IDCT8_1D_FINALIZE
+%endmacro
+
+; TODO: a lot of t* copies can probably be removed and merged with
+; following SUMSUBs from VP9_IDCT8_1D_FINALIZE with AVX
+%macro VP9_IDCT8_2x2_1D 0
+ pmulhrsw m0, m12 ; m0=t0
+ mova m3, m1
+ pmulhrsw m1, m6 ; m1=t4
+ pmulhrsw m3, m7 ; m3=t7
+ mova m2, m0 ; m2=t1
+ mova m10, m0 ; m10=t2
+ mova m8, m0 ; m8=t3
+ mova m11, m3 ; t5 = t7a ...
+ mova m9, m3 ; t6 = t7a ...
+ psubw m11, m1 ; t5 = t7a - t4a
+ paddw m9, m1 ; t6 = t7a + t4a
+ pmulhrsw m11, m12 ; m11=t5
+ pmulhrsw m9, m12 ; m9=t6
+ SWAP 0, 10
+ SWAP 9, 1
+ VP9_IDCT8_1D_FINALIZE
+%endmacro
+
+%macro VP9_IDCT8_WRITEOUT 0
+ mova m5, [pw_1024]
+ pmulhrsw m0, m5 ; (x*1024 + (1<<14))>>15 <=> (x+16)>>5
+ pmulhrsw m1, m5
+ VP9_STORE_2X 0, 1, 6, 7, 4
+ lea dstq, [dstq+2*strideq]
+ pmulhrsw m2, m5
+ pmulhrsw m3, m5
+ VP9_STORE_2X 2, 3, 6, 7, 4
+ lea dstq, [dstq+2*strideq]
+ pmulhrsw m8, m5
+ pmulhrsw m9, m5
+ VP9_STORE_2X 8, 9, 6, 7, 4
+ lea dstq, [dstq+2*strideq]
+ pmulhrsw m10, m5
+ pmulhrsw m11, m5
+ VP9_STORE_2X 10, 11, 6, 7, 4
+%endmacro
+
+%macro VP9_IDCT_IDCT_8x8_ADD_XMM 1
+INIT_XMM %1
+cglobal vp9_idct_idct_8x8_add, 4,4,13, dst, stride, block, eob
+
+ mova m12, [pw_11585x2] ; often used
+
+ 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
+
+ movd m0, [blockq]
+ pmulhrsw m0, m12
+ pmulhrsw m0, m12
+ SPLATW m0, m0, 0
+ pxor m4, m4
+ movd [blockq], m4
+ mova m5, [pw_1024]
+ pmulhrsw m0, m5 ; (x*1024 + (1<<14))>>15 <=> (x+16)>>5
+ VP9_STORE_2X 0, 0, 6, 7, 4
+ lea dstq, [dstq+2*strideq]
+ VP9_STORE_2X 0, 0, 6, 7, 4
+ lea dstq, [dstq+2*strideq]
+ VP9_STORE_2X 0, 0, 6, 7, 4
+ lea dstq, [dstq+2*strideq]
+ VP9_STORE_2X 0, 0, 6, 7, 4
+ RET
+
+; 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]
+ mova m6, [pw_3196x2]
+ mova m7, [pw_16069x2]
+ VP9_IDCT8_2x2_1D
+ TRANSPOSE8x8W 0, 1, 2, 3, 8, 9, 10, 11, 4
+ VP9_IDCT8_2x2_1D
+ pxor m4, m4 ; used for the block reset, and VP9_STORE_2X
+ movd [blockq+ 0], m4
+ movd [blockq+16], m4
+ VP9_IDCT8_WRITEOUT
+ RET
+
+.idcthalf:
+ movh m0, [blockq + 0]
+ movh m1, [blockq +16]
+ movh m2, [blockq +32]
+ movh m3, [blockq +48]
+ VP9_IDCT8_4x4_1D
+ TRANSPOSE8x8W 0, 1, 2, 3, 8, 9, 10, 11, 4
+ VP9_IDCT8_4x4_1D
+ pxor m4, m4
+ movh [blockq+ 0], m4
+ movh [blockq+16], m4
+ movh [blockq+32], m4
+ movh [blockq+48], m4
+ VP9_IDCT8_WRITEOUT
+ RET
+
+.idctfull: ; generic full 8x8 idct/idct
+ mova m0, [blockq+ 0] ; IN(0)
+ mova m1, [blockq+ 16] ; IN(1)
+ mova m2, [blockq+ 32] ; IN(2)
+ mova m3, [blockq+ 48] ; IN(3)
+ mova m8, [blockq+ 64] ; IN(4)
+ mova m9, [blockq+ 80] ; IN(5)
+ mova m10, [blockq+ 96] ; IN(6)
+ mova m11, [blockq+112] ; IN(7)
+ mova m7, [pd_8192] ; rounding
+ VP9_IDCT8_1D
+ TRANSPOSE8x8W 0, 1, 2, 3, 8, 9, 10, 11, 4
+ VP9_IDCT8_1D
+
+ pxor m4, m4 ; used for the block reset, and VP9_STORE_2X
+ ZERO_BLOCK blockq, 16, 8, m4
+ VP9_IDCT8_WRITEOUT
+ RET
+%endmacro
+
+VP9_IDCT_IDCT_8x8_ADD_XMM ssse3
+VP9_IDCT_IDCT_8x8_ADD_XMM avx
+
+;---------------------------------------------------------------------------------------------
+; void vp9_iadst_iadst_8x8_add_<opt>(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob);
+;---------------------------------------------------------------------------------------------
+
+%macro VP9_IADST8_1D 0 ; input/output=m0/1/2/3/8/9/10/11
+ VP9_UNPACK_MULSUB_2D_4X 11, 0, 4, 5, 16305, 1606 ; m11/4=t1[d], m0/5=t0[d]
+ VP9_UNPACK_MULSUB_2D_4X 3, 8, 6, 13, 10394, 12665 ; m3/6=t5[d], m8/13=t4[d]
+ VP9_RND_SH_SUMSUB_BA 8, 0, 13, 5, 14, m7 ; m8=t0[w], m0=t4[w]
+ VP9_RND_SH_SUMSUB_BA 3, 11, 6, 4, 14, m7 ; m3=t1[w], m11=t5[w]
+
+ VP9_UNPACK_MULSUB_2D_4X 9, 2, 4, 5, 14449, 7723 ; m9/4=t3[d], m2/5=t2[d]
+ VP9_UNPACK_MULSUB_2D_4X 1, 10, 6, 13, 4756, 15679 ; m1/6=t7[d], m10/13=t6[d]
+ VP9_RND_SH_SUMSUB_BA 10, 2, 13, 5, 14, m7 ; m10=t2[w], m2=t6[w]
+ VP9_RND_SH_SUMSUB_BA 1, 9, 6, 4, 14, m7 ; m1=t3[w], m9=t7[w]
+
+ ; m8=t0, m3=t1, m10=t2, m1=t3, m0=t4, m11=t5, m2=t6, m9=t7
+
+ VP9_UNPACK_MULSUB_2D_4X 0, 11, 4, 5, 15137, 6270 ; m0/4=t5[d], m11/5=t4[d]
+ VP9_UNPACK_MULSUB_2D_4X 9, 2, 6, 13, 6270, 15137 ; m9/6=t6[d], m2/13=t7[d]
+ VP9_RND_SH_SUMSUB_BA 9, 11, 6, 5, 14, m7
+ psignw m9, [pw_m1] ; m9=out1[w], m11=t6[w]
+ VP9_RND_SH_SUMSUB_BA 2, 0, 13, 4, 14, m7 ; m2=out6[w], m0=t7[w]
+
+ SUMSUB_BA w, 10, 8, 14 ; m10=out0[w], m8=t2[w]
+ SUMSUB_BA w, 1, 3, 14
+ psignw m1, [pw_m1] ; m1=out7[w], m3=t3[w]
+
+ ; m10=out0, m9=out1, m8=t2, m3=t3, m11=t6, m0=t7, m2=out6, m1=out7
+
+ SUMSUB_BA w, 3, 8, 4
+ SUMSUB_BA w, 0, 11, 5
+ pmulhrsw m3, m12
+ pmulhrsw m11, m12
+ pmulhrsw m8, m12 ; out4
+ pmulhrsw m0, m12 ; out2
+ psignw m3, [pw_m1] ; out3
+ psignw m11, [pw_m1] ; out5
+
+ ; m10=out0, m9=out1, m0=out2, m3=out3, m8=out4, m11=out5, m2=out6, m1=out7
+
+ SWAP 0, 10, 2
+ SWAP 11, 1, 9
+%endmacro
+
+%macro IADST8_FN 5
+INIT_XMM %5
+cglobal vp9_%1_%3_8x8_add, 3, 3, 15, dst, stride, block, eob
+ mova m0, [blockq+ 0] ; IN(0)
+ mova m1, [blockq+ 16] ; IN(1)
+ mova m2, [blockq+ 32] ; IN(2)
+ mova m3, [blockq+ 48] ; IN(3)
+ mova m8, [blockq+ 64] ; IN(4)
+ mova m9, [blockq+ 80] ; IN(5)
+ mova m10, [blockq+ 96] ; IN(6)
+ mova m11, [blockq+112] ; IN(7)
+
+ mova m12, [pw_11585x2] ; often used
+ mova m7, [pd_8192] ; rounding
+ VP9_%2_1D
+ TRANSPOSE8x8W 0, 1, 2, 3, 8, 9, 10, 11, 4
+ VP9_%4_1D
+
+ pxor m4, m4 ; used for the block reset, and VP9_STORE_2X
+ ZERO_BLOCK blockq, 16, 8, m4
+ VP9_IDCT8_WRITEOUT
+ RET
+%endmacro
+
+IADST8_FN idct, IDCT8, iadst, IADST8, ssse3
+IADST8_FN idct, IDCT8, iadst, IADST8, avx
+IADST8_FN iadst, IADST8, idct, IDCT8, ssse3
+IADST8_FN iadst, IADST8, idct, IDCT8, avx
+IADST8_FN iadst, IADST8, iadst, IADST8, ssse3
+IADST8_FN iadst, IADST8, iadst, IADST8, avx
+
+;---------------------------------------------------------------------------------------------
+; void vp9_idct_idct_16x16_add_<opt>(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob);
+;---------------------------------------------------------------------------------------------
+
+; at the end of this macro, m7 is stored in stack_scratch
+; 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
+%macro VP9_IDCT16_1D_START 4 ; src, nnzc, stride, stack_scratch
+%if %2 <= 4
+ mova m3, [%1+ 1*%3] ; IN(1)
+ mova m12, [%1+ 2*%3] ; IN(2)
+ mova m0, [%1+ 3*%3] ; IN(3)
+
+ pmulhrsw m15, m12, [pw_16069x2] ; t6-7
+ pmulhrsw m12, [pw_3196x2] ; t4-5
+ 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
+
+ paddw m14, m15, m12
+ psubw m13, m15, m12
+ pmulhrsw m13, [pw_11585x2] ; t5
+ pmulhrsw m14, [pw_11585x2] ; t6
+
+ VP9_UNPACK_MULSUB_2W_4X 2, 5, 4, 3, 15137, 6270, [pd_8192], 10, 11 ; t9, t14
+ VP9_UNPACK_MULSUB_2W_4X 6, 1, 0, 7, 6270, m15137, [pd_8192], 10, 11 ; t10, 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
+%else
+ mova m5, [%1+ 1*%3] ; IN(1)
+ mova m14, [%1+ 2*%3] ; IN(2)
+ mova m6, [%1+ 3*%3] ; IN(3)
+ mova m9, [%1+ 4*%3] ; IN(4)
+ mova m7, [%1+ 5*%3] ; IN(5)
+ mova m15, [%1+ 6*%3] ; IN(6)
+ mova m4, [%1+ 7*%3] ; IN(7)
+%if %2 <= 8
+ pmulhrsw m8, m9, [pw_15137x2] ; t3
+ pmulhrsw m9, [pw_6270x2] ; t2
+ pmulhrsw m13, m14, [pw_16069x2] ; t7
+ pmulhrsw m14, [pw_3196x2] ; t4
+ pmulhrsw m12, m15, [pw_m9102x2] ; t5
+ pmulhrsw m15, [pw_13623x2] ; t6
+ pmulhrsw m2, m5, [pw_16305x2] ; t15
+ pmulhrsw m5, [pw_1606x2] ; t8
+ pmulhrsw m3, m4, [pw_m10394x2] ; t9
+ pmulhrsw m4, [pw_12665x2] ; t14
+ pmulhrsw m0, m7, [pw_14449x2] ; t13
+ pmulhrsw m7, [pw_7723x2] ; t10
+ pmulhrsw m1, m6, [pw_m4756x2] ; t11
+ pmulhrsw m6, [pw_15679x2] ; t12
+%else
+ mova m3, [%1+ 9*%3] ; IN(9)
+ mova m12, [%1+10*%3] ; IN(10)
+ mova m0, [%1+11*%3] ; IN(11)
+ mova m8, [%1+12*%3] ; IN(12)
+ mova m1, [%1+13*%3] ; IN(13)
+ mova m13, [%1+14*%3] ; IN(14)
+ 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 9, 8, 15137, 6270, [pd_8192], 10, 11 ; t2, t3
+ VP9_UNPACK_MULSUB_2W_4X 14, 13, 16069, 3196, [pd_8192], 10, 11 ; t4, t7
+ VP9_UNPACK_MULSUB_2W_4X 12, 15, 9102, 13623, [pd_8192], 10, 11 ; t5, t6
+ VP9_UNPACK_MULSUB_2W_4X 5, 2, 16305, 1606, [pd_8192], 10, 11 ; t8, t15
+ VP9_UNPACK_MULSUB_2W_4X 3, 4, 10394, 12665, [pd_8192], 10, 11 ; t9, t14
+ VP9_UNPACK_MULSUB_2W_4X 7, 0, 14449, 7723, [pd_8192], 10, 11 ; t10, t13
+ VP9_UNPACK_MULSUB_2W_4X 1, 6, 4756, 15679, [pd_8192], 10, 11 ; 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, 12, 14, 10 ; t4, t5
+ SUMSUB_BA w, 15, 13, 10 ; t7, t6
+ SUMSUB_BA w, 3, 5, 10 ; t8, t9
+ SUMSUB_BA w, 7, 1, 10 ; t11, t10
+ SUMSUB_BA w, 0, 6, 10 ; t12, t13
+ SUMSUB_BA w, 4, 2, 10 ; t15, t14
+
+ ; 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
+
+ SUMSUB_BA w, 14, 13, 10
+ pmulhrsw m13, [pw_11585x2] ; t5
+ pmulhrsw m14, [pw_11585x2] ; t6
+ VP9_UNPACK_MULSUB_2W_4X 2, 5, 15137, 6270, [pd_8192], 10, 11 ; t9, t14
+ VP9_UNPACK_MULSUB_2W_4X 6, 1, 6270, m15137, [pd_8192], 10, 11 ; t10, t13
+%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, 10 ; t8, t11
+ SUMSUB_BA w, 6, 2, 10 ; t9, t10
+ SUMSUB_BA w, 0, 4, 10 ; t15, t12
+ SUMSUB_BA w, 1, 5, 10 ; 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
+
+ SUMSUB_BA w, 2, 5, 10
+ SUMSUB_BA w, 3, 4, 10
+ pmulhrsw m5, [pw_11585x2] ; t10
+ pmulhrsw m4, [pw_11585x2] ; t11
+ pmulhrsw m3, [pw_11585x2] ; t12
+ pmulhrsw m2, [pw_11585x2] ; t13
+
+ ; backup first register
+ mova [%4], m7
+
+ ; 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
+
+ ; from load/start
+%if %2 <= 4
+ mova m11, [%1+ 0*%3] ; IN(0)
+ pmulhrsw m11, [pw_11585x2] ; t0-t3
+
+ psubw m8, m11, m15
+ paddw m15, m11
+ psubw m9, m11, m14
+ paddw m14, m11
+ psubw m10, m11, m13
+ paddw m13, m11
+%else
+ mova m10, [%1+ 0*%3] ; IN(0)
+%if %2 <= 8
+ pmulhrsw m10, [pw_11585x2] ; t0 and t1
+ psubw m11, m10, m8
+ paddw m8, m10
+%else
+ mova m11, [%1+ 8*%3] ; IN(8)
+
+ ; from 3 stages back
+ SUMSUB_BA w, 11, 10, 7
+ pmulhrsw m11, [pw_11585x2] ; t0
+ pmulhrsw m10, [pw_11585x2] ; t1
+
+ ; from 2 stages back
+ SUMSUB_BA w, 8, 11, 7 ; t0, t3
+%endif
+ SUMSUB_BA w, 9, 10, 7 ; t1, t2
+
+ ; from 1 stage back
+ SUMSUB_BA w, 15, 8, 7 ; t0, t7
+ SUMSUB_BA w, 14, 9, 7 ; t1, t6
+ SUMSUB_BA w, 13, 10, 7 ; t2, t5
+%endif
+ SUMSUB_BA w, 12, 11, 7 ; t3, t4
+
+ 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
+%endmacro
+
+%macro VP9_IDCT16_1D 2-3 16 ; src, pass, nnzc
+ VP9_IDCT16_1D_START %1, %3, 32, tmpq+32
+
+%if %2 == 1
+ ; backup a different register
+ mova [tmpq+16], m15
+ mova m7, [tmpq+32]
+
+ 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+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 ; %2 == 2
+ ; backup more registers
+ mova [tmpq+64], m8
+ mova [tmpq+96], m9
+
+ pxor m7, m7
+ pmulhrsw m0, [pw_512]
+ pmulhrsw m1, [pw_512]
+ VP9_STORE_2X 0, 1, 8, 9, 7
+ lea dstq, [dstq+strideq*2]
+ pmulhrsw m2, [pw_512]
+ pmulhrsw m3, [pw_512]
+ VP9_STORE_2X 2, 3, 8, 9, 7
+ lea dstq, [dstq+strideq*2]
+ pmulhrsw m4, [pw_512]
+ pmulhrsw m5, [pw_512]
+ VP9_STORE_2X 4, 5, 8, 9, 7
+ lea dstq, [dstq+strideq*2]
+
+ ; restore from cache
+ SWAP 0, 7 ; move zero from m7 to m0
+ mova m7, [tmpq+32]
+ mova m8, [tmpq+64]
+ mova m9, [tmpq+96]
+
+ SUMSUB_BA w, 6, 9, 1 ; t6, t9
+ SUMSUB_BA w, 7, 8, 1 ; t7, t8
+
+ pmulhrsw m6, [pw_512]
+ pmulhrsw m7, [pw_512]
+ VP9_STORE_2X 6, 7, 1, 2, 0
+ lea dstq, [dstq+strideq*2]
+ pmulhrsw m8, [pw_512]
+ pmulhrsw m9, [pw_512]
+ VP9_STORE_2X 8, 9, 1, 2, 0
+ lea dstq, [dstq+strideq*2]
+ pmulhrsw m10, [pw_512]
+ pmulhrsw m11, [pw_512]
+ VP9_STORE_2X 10, 11, 1, 2, 0
+ lea dstq, [dstq+strideq*2]
+ pmulhrsw m12, [pw_512]
+ pmulhrsw m13, [pw_512]
+ VP9_STORE_2X 12, 13, 1, 2, 0
+ lea dstq, [dstq+strideq*2]
+ pmulhrsw m14, [pw_512]
+ pmulhrsw m15, [pw_512]
+ VP9_STORE_2X 14, 15, 1, 2, 0
+%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
+ ; 2x2=eob=3, 4x4=eob=10
+ cmp eobd, 38
+ jg .idctfull
+ cmp eobd, 1 ; faster path for when only DC is set
+ jne .idct8x8
+
+ ; dc-only
+ movd m0, [blockq]
+ mova m1, [pw_11585x2]
+ pmulhrsw m0, m1
+ pmulhrsw m0, m1
+ SPLATW m0, m0, q0000
+ pmulhrsw m0, [pw_512]
+ 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
+.idct8x8:
+ mov tmpq, rsp
+ VP9_IDCT16_1D blockq, 1, 8
+
+ mov cntd, 2
+ mov dst_bakq, dstq
+.loop2_8x8:
+ VP9_IDCT16_1D tmpq, 2, 8
+ 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
+
+.idctfull:
+ mov cntd, 2
+ mov tmpq, rsp
+.loop1_full:
+ VP9_IDCT16_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_IDCT16_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
+
+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 m8, [%1+ 7*32] ; in7
+ mova m9, [%1+ 8*32] ; in8
+
+ VP9_UNPACK_MULSUB_2D_4X 1, 0, 2, 3, 16364, 804 ; m1/2=t1[d], m0/3=t0[d]
+ VP9_UNPACK_MULSUB_2D_4X 8, 9, 11, 10, 11003, 12140 ; m8/11=t9[d], m9/10=t8[d]
+ VP9_RND_SH_SUMSUB_BA 9, 0, 10, 3, 4, [pd_8192] ; m9=t0[w], m0=t8[w]
+ VP9_RND_SH_SUMSUB_BA 8, 1, 11, 2, 4, [pd_8192] ; m8=t1[w], m1=t9[w]
+
+ mova m11, [%1+ 2*32] ; in2
+ mova m10, [%1+13*32] ; in13
+ mova m3, [%1+ 5*32] ; in5
+ mova m2, [%1+10*32] ; in10
+
+ VP9_UNPACK_MULSUB_2D_4X 10, 11, 6, 7, 15893, 3981 ; m10/6=t3[d], m11/7=t2[d]
+ VP9_UNPACK_MULSUB_2D_4X 3, 2, 4, 5, 8423, 14053 ; m3/4=t11[d], m2/5=t10[d]
+ VP9_RND_SH_SUMSUB_BA 2, 11, 5, 7, 12, [pd_8192] ; m2=t2[w], m11=t10[w]
+ VP9_RND_SH_SUMSUB_BA 3, 10, 4, 6, 12, [pd_8192] ; m3=t3[w], m10=t11[w]
+
+ mova [tmpq+ 0*%%str], m9 ; make some scratch space (t0:m9->r0)
+ mova m4, [%1+ 4*32] ; in4
+ mova m5, [%1+11*32] ; in11
+ mova m12, [%1+ 3*32] ; in3
+ mova m13, [%1+12*32] ; in12
+
+ VP9_UNPACK_MULSUB_2D_4X 5, 4, 7, 6, 14811, 7005 ; m5/7=t5[d], m4/6=t4[d]
+ VP9_UNPACK_MULSUB_2D_4X 12, 13, 14, 15, 5520, 15426 ; m12/14=t13[d], m13/15=t12[d]
+ VP9_RND_SH_SUMSUB_BA 13, 4, 15, 6, 9, [pd_8192] ; m13=t4[w], m4=t12[w]
+ VP9_RND_SH_SUMSUB_BA 12, 5, 14, 7, 9, [pd_8192] ; m12=t5[w], m5=t13[w]
+
+ mova [tmpq+ 2*%%str], m8 ; t1:m9->r2
+ mova [tmpq+ 3*%%str], m2 ; t2:m2->r3
+ mova [tmpq+ 4*%%str], m3 ; t3:m3->r4
+ mova [tmpq+ 5*%%str], m13 ; t4:m13->r5
+ mova m2, [%1+ 6*32] ; in6
+ mova m3, [%1+ 9*32] ; in9
+ mova m8, [%1+ 1*32] ; in1
+ mova m9, [%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 8, 9, 13, 14, 2404, 16207 ; m8/13=t15[d], m9/14=t14[d]
+ VP9_RND_SH_SUMSUB_BA 9, 2, 14, 6, 15, [pd_8192] ; m9=t6[w], m2=t14[w]
+ VP9_RND_SH_SUMSUB_BA 8, 3, 13, 7, 15, [pd_8192] ; m8=t7[w], m3=t15[w]
+
+ ; r0=t0, r2=t1, r3=t2, r4=t3, r5=t4, m12=t5, m9=t6, m8=t7
+ ; m0=t8, m1=t9, m11=t10, m10=t11, m4=t12, m5=t13, m2=t14, m3=t15
+
+ ; handle t8-15 first
+ VP9_UNPACK_MULSUB_2D_4X 0, 1, 6, 7, 16069, 3196 ; m1/7=t8[d], m0/6=t9[d]
+ VP9_UNPACK_MULSUB_2D_4X 5, 4, 13, 14, 3196, 16069 ; m5/13=t12[d], m4/14=t13[d]
+ VP9_RND_SH_SUMSUB_BA 5, 1, 13, 7, 15, [pd_8192] ; m5=t8[w], m1=t12[w]
+ VP9_RND_SH_SUMSUB_BA 4, 0, 14, 6, 15, [pd_8192] ; m4=t9[w], m0=t13[w]
+
+ VP9_UNPACK_MULSUB_2D_4X 11, 10, 6, 7, 9102, 13623 ; m11/6=t11[d], m10/7=t10[d]
+ VP9_UNPACK_MULSUB_2D_4X 3, 2, 13, 14, 13623, 9102 ; m3/13=t14[d], m2/14=t15[d]
+ VP9_RND_SH_SUMSUB_BA 3, 10, 13, 7, 15, [pd_8192] ; m3=t10[w], m10=t14[w]
+ VP9_RND_SH_SUMSUB_BA 2, 11, 14, 6, 15, [pd_8192] ; m2=t11[w], m11=t15[w]
+
+ ; m5=t8, m4=t9, m3=t10, m2=t11, m1=t12, m0=t13, m10=t14, m11=t15
+
+ VP9_UNPACK_MULSUB_2D_4X 1, 0, 6, 7, 15137, 6270 ; m1/6=t13[d], m0/7=t12[d]
+ VP9_UNPACK_MULSUB_2D_4X 11, 10, 13, 14, 6270, 15137 ; m11/13=t14[d], m10/14=t15[d]
+ VP9_RND_SH_SUMSUB_BA 11, 0, 13, 7, 15, [pd_8192] ; m11=out2[w], m0=t14[w]
+ VP9_RND_SH_SUMSUB_BA 10, 1, 14, 6, 15, [pd_8192]
+ psignw m10, [pw_m1] ; m10=out13[w], m1=t15[w]
+
+ SUMSUB_BA w, 3, 5, 15
+ psignw m3, [pw_m1] ; m3=out1[w], m5=t10[w]
+ SUMSUB_BA w, 2, 4, 15 ; m2=out14[w], m4=t11[w]
+
+ SUMSUB_BA w, 5, 4, 15
+ pmulhrsw m5, [pw_11585x2] ; m5=out6[w]
+ pmulhrsw m4, [pw_11585x2] ; m4=out9[w]
+ SUMSUB_BA w, 1, 0, 15
+ pmulhrsw m1, [pw_m11585x2] ; m1=out5[w]
+ pmulhrsw m0, [pw_11585x2] ; m0=out10[w]
+
+ ; m3=out1, m11=out2, m1=out5, m5=out6, m4=out9, m0=out10, m10=out13, m2=out14
+
+ mova m6, [tmpq+ 0*%%str]
+ mova m7, [tmpq+ 2*%%str]
+ mova m13, [tmpq+ 3*%%str]
+ mova m14, [tmpq+ 4*%%str]
+ mova m15, [tmpq+ 5*%%str]
+ mova [tmpq+ 8*%%str], m5
+ mova [tmpq+ 9*%%str], m4
+ mova [tmpq+10*%%str], m0
+ mova [tmpq+11*%%str], m10
+ mova [tmpq+12*%%str], m2
+
+ ; m6=t0, m7=t1, m13=t2, m14=t3, m15=t4, m12=t5, m9=t6, m8=t7
+ ; m3=out1, m11=out2, m1=out5, r8=out6, r9=out9, r10=out10, r11=out13, r12=out14
+
+ SUMSUB_BA w, 15, 6, 0 ; m15=t0[w], m6=t4[w]
+ SUMSUB_BA w, 12, 7, 0 ; m12=t1[w], m7=t5[w]
+ SUMSUB_BA w, 9, 13, 0 ; m9=t2[w], m13=t6[w]
+ SUMSUB_BA w, 8, 14, 0 ; m8=t3[w], m14=t7[w]
+
+ VP9_UNPACK_MULSUB_2D_4X 6, 7, 0, 2, 15137, 6270 ; m6/0=t5[d], m7/2=t4[d]
+ VP9_UNPACK_MULSUB_2D_4X 14, 13, 4, 5, 6270, 15137 ; m14/4=t6[d], m13/5=t7[d]
+ VP9_RND_SH_SUMSUB_BA 14, 7, 4, 2, 10, [pd_8192]
+ psignw m14, [pw_m1] ; m14=out3[w], m7=t6[w]
+ VP9_RND_SH_SUMSUB_BA 13, 6, 5, 0, 10, [pd_8192] ; m13=out12[w], m6=t7[w]
+ SUMSUB_BA w, 9, 15, 10 ; m9=out0[w], m15=t2[w]
+ SUMSUB_BA w, 8, 12, 10
+ psignw m8, [pw_m1] ; m8=out15[w], m12=t3[w]
+
+ SUMSUB_BA w, 12, 15, 10
+ pmulhrsw m12, [pw_m11585x2] ; m12=out7[w]
+ pmulhrsw m15, [pw_11585x2] ; m15=out8[w]
+ SUMSUB_BA w, 7, 6, 10
+ pmulhrsw m7, [pw_11585x2] ; m7=out4[w]
+ pmulhrsw m6, [pw_11585x2] ; m6=out11[w]
+
+ ; m9=out0, m14=out3, m7=out4, m12=out7, m15=out8, m6=out11, m13=out12, m8=out15
+ ; m3=out1, m11=out2, m1=out5, r8=out6, r9=out9, r10=out10, r11=out13, r12=out14
+
+%if %2 == 1
+ mova m0, [tmpq+ 8*%%str]
+ TRANSPOSE8x8W 9, 3, 11, 14, 7, 1, 0, 12, 2
+ mova [tmpq+ 0*16], m9
+ mova [tmpq+ 2*16], m3
+ mova [tmpq+ 4*16], m11
+ mova [tmpq+ 6*16], m14
+ mova m9, [tmpq+ 9*%%str]
+ mova m3, [tmpq+10*%%str]
+ mova m11, [tmpq+11*%%str]
+ mova m14, [tmpq+12*%%str]
+ mova [tmpq+ 8*16], m7
+ mova [tmpq+10*16], m1
+ mova [tmpq+12*16], m0
+ mova [tmpq+14*16], m12
+
+ TRANSPOSE8x8W 15, 9, 3, 6, 13, 11, 14, 8, 2
+ mova [tmpq+ 1*16], m15
+ mova [tmpq+ 3*16], m9
+ mova [tmpq+ 5*16], m3
+ mova [tmpq+ 7*16], m6
+ mova [tmpq+ 9*16], m13
+ mova [tmpq+11*16], m11
+ mova [tmpq+13*16], m14
+ mova [tmpq+15*16], m8
+%else
+ mova m5, [tmpq+ 8*%%str]
+ pxor m0, m0
+
+ pmulhrsw m9, [pw_512]
+ pmulhrsw m3, [pw_512]
+ VP9_STORE_2X 9, 3, 2, 4, 0
+ lea dstq, [dstq+strideq*2]
+ pmulhrsw m11, [pw_512]
+ pmulhrsw m14, [pw_512]
+ VP9_STORE_2X 11, 14, 2, 4, 0
+ lea dstq, [dstq+strideq*2]
+ pmulhrsw m7, [pw_512]
+ pmulhrsw m1, [pw_512]
+ VP9_STORE_2X 7, 1, 2, 4, 0
+ lea dstq, [dstq+strideq*2]
+ pmulhrsw m5, [pw_512]
+ pmulhrsw m12, [pw_512]
+ VP9_STORE_2X 5, 12, 2, 4, 0
+ lea dstq, [dstq+strideq*2]
+
+ mova m9, [tmpq+ 9*%%str]
+ mova m3, [tmpq+10*%%str]
+ mova m11, [tmpq+11*%%str]
+ mova m14, [tmpq+12*%%str]
+
+ pmulhrsw m15, [pw_512]
+ pmulhrsw m9, [pw_512]
+ VP9_STORE_2X 15, 9, 2, 4, 0
+ lea dstq, [dstq+strideq*2]
+ pmulhrsw m3, [pw_512]
+ pmulhrsw m6, [pw_512]
+ VP9_STORE_2X 3, 6, 2, 4, 0
+ lea dstq, [dstq+strideq*2]
+ pmulhrsw m13, [pw_512]
+ pmulhrsw m11, [pw_512]
+ VP9_STORE_2X 13, 11, 2, 4, 0
+ lea dstq, [dstq+strideq*2]
+ pmulhrsw m14, [pw_512]
+ pmulhrsw m8, [pw_512]
+ VP9_STORE_2X 14, 8, 2, 4, 0
+%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
+
+IADST16_FN idct, IDCT16, iadst, IADST16, ssse3
+IADST16_FN idct, IDCT16, iadst, IADST16, avx
+IADST16_FN iadst, IADST16, idct, IDCT16, ssse3
+IADST16_FN iadst, IADST16, idct, IDCT16, avx
+IADST16_FN iadst, IADST16, iadst, IADST16, ssse3
+IADST16_FN iadst, IADST16, iadst, IADST16, avx
+
+;---------------------------------------------------------------------------------------------
+; 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+ 4*%%str
+
+ ; backup a different register
+ mova [tmpq+30*%%str], m15 ; t15
+ mova m7, [tmpq+ 4*%%str]
+
+ SUMSUB_BA w, 6, 9, 15 ; t6, t9
+ SUMSUB_BA w, 7, 8, 15 ; t7, t8
+
+ ; 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
+ mova [tmpq+24*%%str], m6 ; t6
+ mova [tmpq+28*%%str], m7 ; t7
+ mova [tmpq+ 2*%%str], m8 ; t8
+ mova [tmpq+ 6*%%str], m9 ; t9
+ mova [tmpq+10*%%str], m10 ; t10
+ mova [tmpq+14*%%str], m11 ; t11
+ mova [tmpq+18*%%str], m12 ; t12
+ mova [tmpq+22*%%str], m13 ; t13
+ mova [tmpq+26*%%str], m14 ; t14
+
+ ; then, secondly, do t16-31
+%if %3 <= 8
+ mova m4, [%1+ 1*64]
+ mova m3, [%1+ 3*64]
+ mova m0, [%1+ 5*64]
+ mova m7, [%1+ 7*64]
+
+ pmulhrsw m11, m4, [pw_16364x2] ;t31
+ pmulhrsw m4, [pw_804x2] ;t16
+ pmulhrsw m8, m7, [pw_m5520x2] ;t19
+ pmulhrsw m7, [pw_15426x2] ;t28
+ pmulhrsw m15, m0, [pw_15893x2] ;t27
+ pmulhrsw m0, [pw_3981x2] ;t20
+ pmulhrsw m12, m3, [pw_m2404x2] ;t23
+ pmulhrsw m3, [pw_16207x2] ;t24
+
+ ; m4=t16/17, m8=t18/19, m0=t20/21, m12=t22/23,
+ ; m3=t24/25, m15=t26/27, m7=t28/29, m11=t30/31
+
+ VP9_UNPACK_MULSUB_2W_4X 5, 10, 11, 4, 16069, 3196, [pd_8192], 6, 9 ; t17, t30
+ VP9_UNPACK_MULSUB_2W_4X 9, 6, 7, 8, 3196, m16069, [pd_8192], 1, 14 ; t18, t29
+ ; from 1 stage forward
+ SUMSUB_BA w, 8, 4, 1
+ ; temporary storage
+ mova [tmpq+17*%%str], m8 ; t16
+ mova [tmpq+21*%%str], m4 ; t19
+ VP9_UNPACK_MULSUB_2W_4X 1, 14, 15, 0, 9102, 13623, [pd_8192], 4, 8 ; t21, t26
+ VP9_UNPACK_MULSUB_2W_4X 13, 2, 3, 12, 13623, m9102, [pd_8192], 4, 8 ; t22, t25
+
+ ; 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
+%else
+ mova m10, [%1+ 1*64]
+ mova m13, [%1+ 3*64]
+ mova m14, [%1+ 5*64]
+ mova m9, [%1+ 7*64]
+ mova m8, [%1+ 9*64]
+ mova m15, [%1+11*64]
+ mova m12, [%1+13*64]
+ mova m11, [%1+15*64]
+%if %3 <= 16
+ pmulhrsw m5, m10, [pw_16364x2]
+ pmulhrsw m10, [pw_804x2]
+ pmulhrsw m4, m11, [pw_m11003x2]
+ pmulhrsw m11, [pw_12140x2]
+ pmulhrsw m7, m8, [pw_14811x2]
+ pmulhrsw m8, [pw_7005x2]
+ pmulhrsw m6, m9, [pw_m5520x2]
+ pmulhrsw m9, [pw_15426x2]
+ pmulhrsw m1, m14, [pw_15893x2]
+ pmulhrsw m14, [pw_3981x2]
+ pmulhrsw m0, m15, [pw_m8423x2]
+ pmulhrsw m15, [pw_14053x2]
+%else
+ mova m4, [%1+17*64]
+ mova m0, [%1+21*64]
+ mova m7, [%1+23*64]
+ mova m6, [%1+25*64]
+ mova m1, [%1+27*64]
+ mova m5, [%1+31*64]
+
+ ; m10=in1, m4=in17, m8=in9, m6=in25, m14=in5, m0=in21, m12=in13, m2=in29,
+ ; m13=in3, m3=in19, m15=in11, m1=in27, m9=in7, m7=in23, m11=in15, m5=in31
+
+ VP9_UNPACK_MULSUB_2W_4X 10, 5, 16364, 804, [pd_8192], 2, 3 ; t16, t31
+ VP9_UNPACK_MULSUB_2W_4X 4, 11, 11003, 12140, [pd_8192], 2, 3 ; t17, t30
+ VP9_UNPACK_MULSUB_2W_4X 8, 7, 14811, 7005, [pd_8192], 2, 3 ; t18, t29
+ VP9_UNPACK_MULSUB_2W_4X 6, 9, 5520, 15426, [pd_8192], 2, 3 ; t19, t28
+ VP9_UNPACK_MULSUB_2W_4X 14, 1, 15893, 3981, [pd_8192], 2, 3 ; t20, t27
+ VP9_UNPACK_MULSUB_2W_4X 0, 15, 8423, 14053, [pd_8192], 2, 3 ; t21, t26
+%endif
+
+ ; from 1 stage forward
+ SUMSUB_BA w, 4, 10, 2
+ SUMSUB_BA w, 8, 6, 2
+ ; from 2 stages forward
+ SUMSUB_BA w, 8, 4, 2
+ ; temporary storage
+ mova [tmpq+17*%%str], m8 ; t16
+ mova [tmpq+21*%%str], m4 ; t19
+%if %3 <= 16
+ pmulhrsw m3, m12, [pw_13160x2]
+ pmulhrsw m12, [pw_9760x2]
+ pmulhrsw m2, m13, [pw_m2404x2]
+ pmulhrsw m13, [pw_16207x2]
+%else
+ mova m2, [%1+29*64]
+ mova m3, [%1+19*64]
+ VP9_UNPACK_MULSUB_2W_4X 12, 3, 13160, 9760, [pd_8192], 4, 8 ; t22, t25
+ VP9_UNPACK_MULSUB_2W_4X 2, 13, 2404, 16207, [pd_8192], 4, 8 ; t23, t24
+%endif
+
+ ; m10=t16, m4=t17, m8=t18, m6=t19, m14=t20, m0=t21, m12=t22, m2=t23,
+ ; m13=t24, m3=t25, m15=t26, m1=t27, m9=t28, m7=t29, m11=t30, m5=t31
+
+ SUMSUB_BA w, 0, 14, 4
+ SUMSUB_BA w, 12, 2, 4
+ SUMSUB_BA w, 3, 13, 4
+ SUMSUB_BA w, 15, 1, 4
+ SUMSUB_BA w, 7, 9, 4
+ SUMSUB_BA w, 11, 5, 4
+
+ ; m4=t16, m10=t17, m6=t18, m8=t19, m0=t20, m14=t21, m2=t22, m12=t23,
+ ; m3=t24, m13=t25, m1=t26, m15=t27, m7=t28, m9=t29, m5=t30, m11=t31
+
+ VP9_UNPACK_MULSUB_2W_4X 5, 10, 16069, 3196, [pd_8192], 4, 8 ; t17, t30
+ VP9_UNPACK_MULSUB_2W_4X 9, 6, 3196, m16069, [pd_8192], 4, 8 ; t18, t29
+ VP9_UNPACK_MULSUB_2W_4X 1, 14, 9102, 13623, [pd_8192], 4, 8 ; t21, t26
+ VP9_UNPACK_MULSUB_2W_4X 13, 2, 13623, m9102, [pd_8192], 4, 8 ; 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
+
+ SUMSUB_BA w, 9, 5, 4
+ SUMSUB_BA w, 1, 13, 4
+ SUMSUB_BA w, 0, 12, 4
+ SUMSUB_BA w, 15, 3, 4
+ SUMSUB_BA w, 14, 2, 4
+ SUMSUB_BA w, 6, 10, 4
+ SUMSUB_BA w, 7, 11, 4
+
+ ; 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
+
+ mova m8, [tmpq+17*%%str] ; t16
+ ; from 2 stages forward
+ SUMSUB_BA w, 0, 8, 4
+ SUMSUB_BA w, 15, 7, 4
+ ; from 3 stages forward
+ SUMSUB_BA w, 8, 7, 4
+ pmulhrsw m7, [pw_11585x2]
+ pmulhrsw m8, [pw_11585x2]
+ ; store t16/t23
+ mova [tmpq+ 1*%%str], m0 ; t16
+ mova [tmpq+29*%%str], m7 ; t23
+
+ mova m4, [tmpq+21*%%str] ; t19
+ VP9_UNPACK_MULSUB_2W_4X 10, 5, 15137, 6270, [pd_8192], 0, 7 ; t18, t29
+ VP9_UNPACK_MULSUB_2W_4X 11, 4, 15137, 6270, [pd_8192], 0, 7 ; t19, t28
+ VP9_UNPACK_MULSUB_2W_4X 3, 12, 6270, m15137, [pd_8192], 0, 7 ; t20, t27
+ VP9_UNPACK_MULSUB_2W_4X 2, 13, 6270, m15137, [pd_8192], 0, 7 ; t21, t26
+
+ ; m8=t16, m9=t17, m10=t18, m11=t19, m3=t20, m2=t21, m1=t22, m0=t23,
+ ; m15=t24, m14=t25, m13=t26, m12=t27, m4=t28, m5=t29, m6=t30, m7=t31
+
+ SUMSUB_BA w, 1, 9, 0
+ SUMSUB_BA w, 2, 10, 0
+ SUMSUB_BA w, 3, 11, 0
+ SUMSUB_BA w, 12, 4, 0
+ SUMSUB_BA w, 13, 5, 0
+ SUMSUB_BA w, 14, 6, 0
+
+ ; 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
+
+ SUMSUB_BA w, 9, 6, 0
+ SUMSUB_BA w, 10, 5, 0
+ SUMSUB_BA w, 11, 4, 0
+
+ pmulhrsw m6, [pw_11585x2]
+ pmulhrsw m9, [pw_11585x2]
+ pmulhrsw m5, [pw_11585x2]
+ pmulhrsw m10, [pw_11585x2]
+ pmulhrsw m4, [pw_11585x2]
+ pmulhrsw m11, [pw_11585x2]
+
+ ; 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
+
+ ; store t17-19 (and t20-22 for pass 1) - keep t24-31 in registers for
+ ; final sumsub in pass 1, or keep t20-22 and t24-31 in registers for
+ ; final sumsub of pass 2
+ mova [tmpq+ 5*%%str], m1 ; t17
+ mova [tmpq+ 9*%%str], m2 ; t18
+ mova [tmpq+13*%%str], m3 ; t19
+
+ ; then do final pass to sumsub+store the two halves
+%if %2 == 1
+ mova [tmpq+17*%%str], m4 ; t20
+ mova [tmpq+21*%%str], m5 ; t21
+ mova [tmpq+25*%%str], m6 ; t22
+
+ mova m0, [tmpq+ 0*%%str] ; t0
+ mova m1, [tmpq+ 4*%%str] ; t1
+ mova m2, [tmpq+ 8*%%str] ; t2
+ mova m3, [tmpq+12*%%str] ; t3
+ mova m4, [tmpq+16*%%str] ; t4
+ mova m5, [tmpq+20*%%str] ; t5
+ mova m6, [tmpq+24*%%str] ; t6
+
+ SUMSUB_BA w, 15, 0, 7
+ mova [tmpq+ 3*%%str], m0 ; t15
+ mova m7, [tmpq+28*%%str] ; t7
+ SUMSUB_BA w, 14, 1, 0
+ SUMSUB_BA w, 13, 2, 0
+ SUMSUB_BA w, 12, 3, 0
+ SUMSUB_BA w, 11, 4, 0
+ SUMSUB_BA w, 10, 5, 0
+ SUMSUB_BA w, 9, 6, 0
+ SUMSUB_BA w, 8, 7, 0
+
+ TRANSPOSE8x8W 15, 14, 13, 12, 11, 10, 9, 8, 0
+ mova [tmpq+ 0*%%str], m15
+ mova [tmpq+ 4*%%str], m14
+ mova [tmpq+ 8*%%str], m13
+ mova [tmpq+12*%%str], m12
+ mova [tmpq+16*%%str], m11
+ mova [tmpq+20*%%str], m10
+ mova [tmpq+24*%%str], m9
+ mova [tmpq+28*%%str], m8
+
+ mova m0, [tmpq+ 3*%%str] ; t15
+ TRANSPOSE8x8W 7, 6, 5, 4, 3, 2, 1, 0, 8
+ mova [tmpq+ 3*%%str], m7
+ mova [tmpq+ 7*%%str], m6
+ mova [tmpq+11*%%str], m5
+ mova [tmpq+15*%%str], m4
+ mova [tmpq+19*%%str], m3
+ mova [tmpq+23*%%str], m2
+ mova [tmpq+27*%%str], m1
+ mova [tmpq+31*%%str], m0
+
+ mova m15, [tmpq+ 2*%%str] ; t8
+ mova m14, [tmpq+ 6*%%str] ; t9
+ mova m13, [tmpq+10*%%str] ; t10
+ mova m12, [tmpq+14*%%str] ; t11
+ mova m11, [tmpq+18*%%str] ; t12
+ mova m10, [tmpq+22*%%str] ; t13
+ mova m9, [tmpq+26*%%str] ; t14
+ mova m8, [tmpq+30*%%str] ; t15
+ mova m7, [tmpq+ 1*%%str] ; t16
+ mova m6, [tmpq+ 5*%%str] ; t17
+ mova m5, [tmpq+ 9*%%str] ; t18
+ mova m4, [tmpq+13*%%str] ; t19
+ mova m3, [tmpq+17*%%str] ; t20
+ mova m2, [tmpq+21*%%str] ; t21
+ mova m1, [tmpq+25*%%str] ; t22
+
+ SUMSUB_BA w, 7, 8, 0
+ mova [tmpq+ 2*%%str], m8
+ mova m0, [tmpq+29*%%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
+ ; 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
+ pxor m7, m7
+
+%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
+ pmulhrsw m%4, [pw_512]
+ pmulhrsw m%3, [pw_512]
+ VP9_STORE_2X %4, %3, %5, %6, %7
+%if %8 == 1
+ add dstq, stride2q
+%endif
+ pmulhrsw m%2, [pw_512]
+ pmulhrsw m%1, [pw_512]
+ VP9_STORE_2X %2, %1, %5, %6, %7, dst_endq
+%if %8 == 1
+ sub dst_endq, stride2q
+%endif
+%endmacro
+
+ ; store t0-1 and t30-31
+ mova m0, [tmpq+ 0*%%str]
+ mova m1, [tmpq+ 4*%%str]
+ %%STORE_2X2 0, 1, 14, 15, 2, 3, 7
+
+ ; store t2-3 and t28-29
+ mova m0, [tmpq+ 8*%%str]
+ mova m1, [tmpq+12*%%str]
+ %%STORE_2X2 0, 1, 12, 13, 2, 3, 7
+
+ ; store t4-5 and t26-27
+ mova m0, [tmpq+16*%%str]
+ mova m1, [tmpq+20*%%str]
+ %%STORE_2X2 0, 1, 10, 11, 2, 3, 7
+
+ ; store t6-7 and t24-25
+ mova m0, [tmpq+24*%%str]
+ mova m1, [tmpq+28*%%str]
+ %%STORE_2X2 0, 1, 8, 9, 2, 3, 7
+
+ ; store t8-9 and t22-23
+ mova m0, [tmpq+ 2*%%str]
+ mova m1, [tmpq+ 6*%%str]
+ mova m8, [tmpq+29*%%str]
+ %%STORE_2X2 0, 1, 6, 8, 2, 3, 7
+
+ ; store t10-11 and t20-21
+ mova m0, [tmpq+10*%%str]
+ mova m1, [tmpq+14*%%str]
+ %%STORE_2X2 0, 1, 4, 5, 2, 3, 7
+
+ ; store t12-13 and t18-19
+ mova m0, [tmpq+18*%%str]
+ mova m1, [tmpq+22*%%str]
+ mova m5, [tmpq+13*%%str]
+ mova m4, [tmpq+ 9*%%str]
+ %%STORE_2X2 0, 1, 4, 5, 2, 3, 7
+
+ ; store t14-17
+ mova m0, [tmpq+26*%%str]
+ mova m1, [tmpq+30*%%str]
+ mova m5, [tmpq+ 5*%%str]
+ mova m4, [tmpq+ 1*%%str]
+ %%STORE_2X2 0, 1, 4, 5, 2, 3, 7, 0
+%endif
+%endmacro
+
+%macro VP9_IDCT_IDCT_32x32_ADD_XMM 1
+INIT_XMM %1
+cglobal vp9_idct_idct_32x32_add, 4, 9, 16, 2048, dst, stride, block, eob
+ cmp eobd, 135
+ jg .idctfull
+ cmp eobd, 34
+ jg .idct16x16
+ cmp eobd, 1
+ jg .idct8x8
+
+ ; dc-only case
+ movd m0, [blockq]
+ mova m1, [pw_11585x2]
+ pmulhrsw m0, m1
+ pmulhrsw m0, m1
+ SPLATW m0, m0, q0000
+ pmulhrsw m0, [pw_512]
+ pxor m5, m5
+ movd [blockq], m5
+ DEFINE_ARGS dst, stride, block, cnt
+%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
+
+ DEFINE_ARGS dst_bak, stride, block, cnt, dst, stride30, dst_end, stride2, tmp
+.idct8x8:
+ mov tmpq, rsp
+ VP9_IDCT32_1D blockq, 1, 8
+
+ 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, [dst_bakq+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
+ ZERO_BLOCK blockq, 64, 8, m7
+ RET
+
+.idct16x16:
+ 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
+ sub blockq, 32
+
+ 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, [dst_bakq+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
+ ZERO_BLOCK blockq, 64, 16, m7
+ RET
+
+.idctfull:
+ mov cntd, 4
+ mov tmpq, rsp
+.loop1_full:
+ VP9_IDCT32_1D blockq, 1
+ add blockq, 16
+ add tmpq, 512
+ dec cntd
+ jg .loop1_full
+ sub blockq, 64
+
+ mov stride30q, strideq ; stride
+ lea stride2q, [strideq*2] ; stride*2
+ shl stride30q, 5 ; stride*32
+ mov cntd, 4
+ mov tmpq, rsp
+ sub stride30q, stride2q ; stride*30
+.loop2_full:
+ mov dstq, dst_bakq
+ lea dst_endq, [dst_bakq+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
+ ZERO_BLOCK blockq, 64, 32, m7
+ RET
+%endmacro
+
+VP9_IDCT_IDCT_32x32_ADD_XMM ssse3
+VP9_IDCT_IDCT_32x32_ADD_XMM avx
+
+%endif ; x86-64
diff --git a/libavcodec/x86/vp9lpf.asm b/libavcodec/x86/vp9lpf.asm
new file mode 100644
index 0000000..416f08f
--- /dev/null
+++ b/libavcodec/x86/vp9lpf.asm
@@ -0,0 +1,816 @@
+;******************************************************************************
+;* VP9 loop filter SIMD optimizations
+;*
+;* Copyright (C) 2013-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 "libavutil/x86/x86util.asm"
+
+%if ARCH_X86_64
+
+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
+
+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
+
+; %1 = abs(%2-%3)
+%macro ABSSUB 4 ; dst, src1 (RO), src2 (RO), tmp
+ psubusb %1, %3, %2
+ psubusb %4, %2, %3
+ por %1, %4
+%endmacro
+
+; %1 = %1<=%2
+%macro CMP_LTE 3-4 ; src/dst, cmp, tmp, pb_80
+%if %0 == 4
+ pxor %1, %4
+%endif
+ pcmpgtb %3, %2, %1 ; cmp > src?
+ pcmpeqb %1, %2 ; cmp == src? XXX: avoid this with a -1/+1 well placed?
+ por %1, %3 ; cmp >= src?
+%endmacro
+
+; %1 = abs(%2-%3) <= %4
+%macro ABSSUB_CMP 6-7 [pb_80]; dst, src1, src2, cmp, tmp1, tmp2, [pb_80]
+ ABSSUB %1, %2, %3, %6 ; dst = abs(src1-src2)
+ CMP_LTE %1, %4, %6, %7 ; 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 FILTER_SUBx2_ADDx2 8 ; %1=dst %2=h/l %3=cache %4=sub1 %5=sub2 %6=add1 %7=add2 %8=rshift
+ punpck%2bw %3, %4, m0
+ psubw %1, %3
+ punpck%2bw %3, %5, m0
+ psubw %1, %3
+ punpck%2bw %3, %6, m0
+ paddw %1, %3
+ punpck%2bw %3, %7, m0
+ paddw %3, %1
+ psraw %1, %3, %8
+%endmacro
+
+%macro FILTER_INIT 8 ; tmp1, tmp2, cacheL, cacheH, dstp, filterid, mask, source
+ FILTER%6_INIT %1, l, %3
+ FILTER%6_INIT %2, h, %4
+ packuswb %1, %2
+ MASK_APPLY %1, %8, %7, %2
+ mova %5, %1
+%endmacro
+
+%macro FILTER_UPDATE 11-14 ; tmp1, tmp2, cacheL, cacheH, dstp, -, -, +, +, rshift, mask, [source], [preload reg + value]
+%if %0 == 13 ; no source + preload
+ mova %12, %13
+%elif %0 == 14 ; source + preload
+ mova %13, %14
+%endif
+ FILTER_SUBx2_ADDx2 %1, l, %3, %6, %7, %8, %9, %10
+ FILTER_SUBx2_ADDx2 %2, h, %4, %6, %7, %8, %9, %10
+ packuswb %1, %2
+%if %0 == 12 || %0 == 14
+ MASK_APPLY %1, %12, %11, %2
+%else
+ MASK_APPLY %1, %5, %11, %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 5 ; dst, u8, i8, tmp1, tmp2
+ EXTRACT_POS_NEG %3, %4, %5
+ psubusb %1, %2, %4 ; sub the negatives
+ paddusb %1, %5 ; add the positives
+%endmacro
+
+; clip_u8(u8 - i8)
+%macro SIGN_SUB 5 ; dst, u8, i8, tmp1, tmp2
+ EXTRACT_POS_NEG %3, %4, %5
+ psubusb %1, %2, %5 ; sub the positives
+ paddusb %1, %4 ; add the negatives
+%endmacro
+
+%macro FILTER6_INIT 3 ; %1=dst %2=h/l %3=cache
+ punpck%2bw %1, m14, m0 ; p3: B->W
+ paddw %3, %1, %1 ; p3*2
+ paddw %3, %1 ; p3*3
+ punpck%2bw %1, m15, m0 ; p2: B->W
+ paddw %3, %1 ; p3*3 + p2
+ paddw %3, %1 ; p3*3 + p2*2
+ punpck%2bw %1, m10, m0 ; p1: B->W
+ paddw %3, %1 ; p3*3 + p2*2 + p1
+ punpck%2bw %1, m11, m0 ; p0: B->W
+ paddw %3, %1 ; p3*3 + p2*2 + p1 + p0
+ punpck%2bw %1, m12, m0 ; q0: B->W
+ 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 3 ; %1=dst %2=h/l %3=cache
+ punpck%2bw %1, m2, m0 ; p7: B->W
+ psllw %3, %1, 3 ; p7*8
+ psubw %3, %1 ; p7*7
+ punpck%2bw %1, m3, m0 ; p6: B->W
+ paddw %3, %1 ; p7*7 + p6
+ paddw %3, %1 ; p7*7 + p6*2
+ punpck%2bw %1, m8, m0 ; p5: B->W
+ paddw %3, %1 ; p7*7 + p6*2 + p5
+ punpck%2bw %1, m9, m0 ; p4: B->W
+ paddw %3, %1 ; p7*7 + p6*2 + p5 + p4
+ punpck%2bw %1, m14, m0 ; p3: B->W
+ paddw %3, %1 ; p7*7 + p6*2 + p5 + p4 + p3
+ punpck%2bw %1, m15, m0 ; p2: B->W
+ paddw %3, %1 ; p7*7 + p6*2 + p5 + .. + p2
+ punpck%2bw %1, m10, m0 ; p1: B->W
+ paddw %3, %1 ; p7*7 + p6*2 + p5 + .. + p1
+ punpck%2bw %1, m11, m0 ; p0: B->W
+ paddw %3, %1 ; p7*7 + p6*2 + p5 + .. + p0
+ punpck%2bw %1, m12, m0 ; q0: B->W
+ paddw %3, %1 ; 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
+
+; transpose 16 half lines (high part) to 8 full centered lines
+%macro TRANSPOSE16x8B 16
+ punpcklbw m%1, m%2
+ punpcklbw m%3, m%4
+ punpcklbw m%5, m%6
+ punpcklbw m%7, m%8
+ punpcklbw m%9, m%10
+ punpcklbw m%11, m%12
+ punpcklbw m%13, m%14
+ punpcklbw m%15, m%16
+ SBUTTERFLY wd, %1, %3, %2
+ SBUTTERFLY wd, %5, %7, %2
+ SBUTTERFLY wd, %9, %11, %2
+ SBUTTERFLY wd, %13, %15, %2
+ SBUTTERFLY dq, %1, %5, %2
+ SBUTTERFLY dq, %3, %7, %2
+ SBUTTERFLY dq, %9, %13, %2
+ SBUTTERFLY dq, %11, %15, %2
+ SBUTTERFLY qdq, %1, %9, %2
+ SBUTTERFLY qdq, %3, %11, %2
+ SBUTTERFLY qdq, %5, %13, %2
+ SBUTTERFLY qdq, %7, %15, %2
+ SWAP %5, %1
+ SWAP %6, %9
+ SWAP %7, %1
+ SWAP %8, %13
+ SWAP %9, %3
+ SWAP %10, %11
+ SWAP %11, %1
+ SWAP %12, %15
+%endmacro
+
+%macro DEFINE_REAL_P7_TO_Q7 0-1 0
+%define P7 dst1q + 2*mstrideq + %1
+%define P6 dst1q + mstrideq + %1
+%define P5 dst1q + %1
+%define P4 dst1q + strideq + %1
+%define P3 dstq + 4*mstrideq + %1
+%define P2 dstq + mstride3q + %1
+%define P1 dstq + 2*mstrideq + %1
+%define P0 dstq + mstrideq + %1
+%define Q0 dstq + %1
+%define Q1 dstq + strideq + %1
+%define Q2 dstq + 2*strideq + %1
+%define Q3 dstq + stride3q + %1
+%define Q4 dstq + 4*strideq + %1
+%define Q5 dst2q + mstrideq + %1
+%define Q6 dst2q + %1
+%define Q7 dst2q + strideq + %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 2 ; %1=v/h %2=size1
+ lea mstrideq, [strideq]
+ neg mstrideq
+
+ lea stride3q, [strideq+2*strideq]
+ mov mstride3q, stride3q
+ neg mstride3q
+
+%ifidn %1, h
+%if %2 > 16
+%define movx movh
+ lea dstq, [dstq + 8*strideq - 4]
+%else
+%define movx movu
+ lea dstq, [dstq + 8*strideq - 8] ; go from top center (h pos) to center left (v pos)
+%endif
+%endif
+
+ lea dst1q, [dstq + 2*mstride3q] ; dst1q = &dst[stride * -6]
+ lea dst2q, [dstq + 2* stride3q] ; dst2q = &dst[stride * +6]
+
+ 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]
+ movx m6, [P1]
+ movx m7, [P0]
+ 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 P7 rsp + 0
+%define P6 rsp + 16
+%define P5 rsp + 32
+%define P4 rsp + 48
+%define P3 rsp + 64
+%define P2 rsp + 80
+%define P1 rsp + 96
+%define P0 rsp + 112
+%define Q0 rsp + 128
+%define Q1 rsp + 144
+%define Q2 rsp + 160
+%define Q3 rsp + 176
+%define Q4 rsp + 192
+%define Q5 rsp + 208
+%define Q6 rsp + 224
+%define Q7 rsp + 240
+
+%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
+ TRANSPOSE16x8B 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+%endif
+ 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
+%endif
+
+ ; 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
+%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
+ ABSSUB_CMP m5, m8, m9, m2, m6, m7, m0 ; m5 = abs(p3-p2) <= I
+ ABSSUB_CMP m1, m9, m10, m2, m6, m7, m0 ; m1 = abs(p2-p1) <= I
+ pand m5, m1
+ ABSSUB_CMP m1, m10, m11, m2, m6, m7, m0 ; m1 = abs(p1-p0) <= I
+ pand m5, m1
+ ABSSUB_CMP m1, m12, m13, m2, m6, m7, m0 ; m1 = abs(q1-q0) <= I
+ pand m5, m1
+ ABSSUB_CMP m1, m13, m14, m2, m6, m7, m0 ; m1 = abs(q2-q1) <= I
+ pand m5, m1
+ ABSSUB_CMP m1, m14, m15, m2, m6, m7, m0 ; m1 = abs(q3-q2) <= I
+ pand m5, m1
+ ABSSUB m1, m11, m12, m7 ; abs(p0-q0)
+ paddusb m1, m1 ; abs(p0-q0) * 2
+ ABSSUB m2, m10, m13, 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 m4, m3, m1 ; E > X?
+ pcmpeqb m3, m1 ; E == X?
+ por m3, m4 ; E >= X?
+ pand m3, m5 ; fm final value
+
+ ; (m3: fm, m8..15: p3 p2 p1 p0 q0 q1 q2 q3)
+ ; calc flat8in (if not 44_16) and hev masks
+ mova m6, [pb_81] ; [1 1 1 1 ...] ^ 0x80
+%if %2 != 44
+ ABSSUB_CMP m2, m8, m11, m6, m4, m5 ; abs(p3 - p0) <= 1
+ mova m8, [pb_80]
+ ABSSUB_CMP m1, m9, m11, m6, m4, m5, m8 ; abs(p2 - p0) <= 1
+ pand m2, m1
+ ABSSUB m4, m10, m11, 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, m8
+ pxor m4, m8
+ pcmpgtb m0, m4, m7 ; abs(p1 - p0) > H (1/2 hev condition)
+ CMP_LTE m4, m6, m5 ; abs(p1 - p0) <= 1
+ pand m2, m4 ; (flat8in)
+ ABSSUB m4, m13, m12, m1 ; abs(q1 - q0)
+ pxor m4, m8
+ pcmpgtb m5, m4, m7 ; abs(q1 - q0) > H (2/2 hev condition)
+ por m0, m5 ; hev final value
+ CMP_LTE m4, m6, m5 ; abs(q1 - q0) <= 1
+ pand m2, m4 ; (flat8in)
+ ABSSUB_CMP m1, m14, m12, m6, m4, m5, m8 ; abs(q2 - q0) <= 1
+ pand m2, m1
+ ABSSUB_CMP m1, m15, m12, m6, m4, m5, m8 ; abs(q3 - q0) <= 1
+ pand m2, m1 ; flat8in final value
+%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, m10, m11, m1 ; abs(p1 - p0)
+ pxor m4, m6
+ pcmpgtb m0, m4, m7 ; abs(p1 - p0) > H (1/2 hev condition)
+ ABSSUB m4, m13, m12, 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
+ mova m8, [P7]
+ mova m9, [P6]
+ ABSSUB_CMP m1, m8, m11, m6, m4, m5 ; abs(p7 - p0) <= 1
+ ABSSUB_CMP m7, m9, m11, m6, m4, m5 ; abs(p6 - p0) <= 1
+ pand m1, m7
+ mova m8, [P5]
+ mova m9, [P4]
+ ABSSUB_CMP m7, m8, m11, m6, m4, m5 ; abs(p5 - p0) <= 1
+ pand m1, m7
+ ABSSUB_CMP m7, m9, m11, m6, m4, m5 ; abs(p4 - p0) <= 1
+ pand m1, m7
+ mova m14, [Q4]
+ mova m15, [Q5]
+ ABSSUB_CMP m7, m14, m12, m6, m4, m5 ; abs(q4 - q0) <= 1
+ pand m1, m7
+ ABSSUB_CMP m7, m15, m12, m6, m4, m5 ; abs(q5 - q0) <= 1
+ pand m1, m7
+ mova m14, [Q6]
+ mova m15, [Q7]
+ ABSSUB_CMP m7, m14, m12, m6, m4, m5 ; abs(q4 - q0) <= 1
+ pand m1, m7
+ ABSSUB_CMP m7, m15, m12, m6, m4, m5 ; abs(q5 - q0) <= 1
+ pand m1, m7 ; flat8out final value
+%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
+%endif
+ pxor m15, m12, m6 ; q0 ^ 0x80
+ pxor m14, m11, m6 ; p0 ^ 0x80
+ psubsb m15, m14 ; (signed) q0 - p0
+ pxor m4, m10, m6 ; p1 ^ 0x80
+ pxor m5, m13, m6 ; q1 ^ 0x80
+ psubsb m4, m5 ; (signed) p1 - q1
+ paddsb m4, m15 ; (q0 - p0) + (p1 - q1)
+ paddsb m4, m15 ; 2*(q0 - p0) + (p1 - q1)
+ paddsb m4, m15 ; 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)
+ mova m14, [pb_10] ; will be reused in filter4()
+ SRSHIFT3B_2X m6, m4, m14, m7 ; f1 and f2 sign byte shift by 3
+ SIGN_SUB m7, m12, m6, m5, m9 ; m7 = q0 - f1
+ SIGN_ADD m8, m11, m4, m5, m9 ; m8 = p0 + f2
+%if %2 != 44
+ pandn m6, m2, m3 ; ~mask(in) & mask(fm)
+ pand m6, m0 ; (~mask(in) & mask(fm)) & mask(hev)
+%else
+ pand m6, m3, m0
+%endif
+ MASK_APPLY m7, m12, m6, m5 ; m7 = filter2(q0) & mask / we write it in filter4()
+ MASK_APPLY m8, m11, m6, m5 ; m8 = filter2(p0) & mask / we write it in filter4()
+
+ ; (m0: hev, [m1: flat8out], [m2: flat8in], m3: fm, m7..m8: q0' p0', m10..13: p1 p0 q0 q1, m14: pb_10, m15: q0-p0)
+ ; filter4()
+ mova m4, m15
+ paddsb m15, m4 ; 2 * (q0 - p0)
+ paddsb m15, m4 ; 3 * (q0 - p0)
+ paddsb m6, m15, [pb_4] ; m6: f1 = clip(f + 4, 127)
+ paddsb m15, [pb_3] ; m15: f2 = clip(f + 3, 127)
+ SRSHIFT3B_2X m6, m15, m14, m9 ; f1 and f2 sign byte shift by 3
+%if %2 != 44
+%define p0tmp m7
+%define q0tmp m9
+ pandn m5, m2, m3 ; ~mask(in) & mask(fm)
+ pandn m0, m5 ; ~mask(hev) & (~mask(in) & mask(fm))
+%else
+%define p0tmp m1
+%define q0tmp m2
+ pandn m0, m3
+%endif
+ SIGN_SUB q0tmp, m12, m6, m4, m14 ; q0 - f1
+ MASK_APPLY q0tmp, m7, m0, m5 ; filter4(q0) & mask
+ mova [Q0], q0tmp
+ SIGN_ADD p0tmp, m11, m15, m4, m14 ; p0 + f2
+ MASK_APPLY p0tmp, m8, m0, m5 ; filter4(p0) & mask
+ mova [P0], p0tmp
+ paddb m6, [pb_80] ;
+ pxor m8, m8 ; f=(f1+1)>>1
+ pavgb m6, m8 ;
+ psubb m6, [pb_40] ;
+ SIGN_ADD m7, m10, m6, m8, m9 ; p1 + f
+ SIGN_SUB m4, m13, m6, m8, m9 ; q1 - f
+ MASK_APPLY m7, m10, m0, m14 ; m7 = filter4(p1)
+ MASK_APPLY m4, m13, m0, m14 ; m4 = filter4(q1)
+ mova [P1], m7
+ mova [Q1], m4
+
+ ; ([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)
+ pandn m3, m1, m2 ; ~mask(out) & (mask(fm) & mask(in))
+%endif
+ mova m14, [P3]
+ mova m15, [P2]
+ mova m8, [Q2]
+ mova m9, [Q3]
+ FILTER_INIT m4, m5, m6, m7, [P2], 6, m3, m15 ; [p2]
+ FILTER_UPDATE m6, m7, m4, m5, [P1], m14, m15, m10, m13, 3, m3 ; [p1] -p3 -p2 +p1 +q1
+ FILTER_UPDATE m4, m5, m6, m7, [P0], m14, m10, m11, m8, 3, m3 ; [p0] -p3 -p1 +p0 +q2
+ FILTER_UPDATE m6, m7, m4, m5, [Q0], m14, m11, m12, m9, 3, m3 ; [q0] -p3 -p0 +q0 +q3
+ FILTER_UPDATE m4, m5, m6, m7, [Q1], m15, m12, m13, m9, 3, m3 ; [q1] -p2 -q0 +q1 +q3
+ FILTER_UPDATE m6, m7, m4, m5, [Q2], m10, m13, m8, m9, 3, m3, m8 ; [q2] -p1 -q1 +q2 +q3
+%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]
+ mova m8, [P5]
+ mova m9, [P4]
+ FILTER_INIT m4, m5, m6, m7, [P6], 14, m1, m3
+ FILTER_UPDATE m6, m7, m4, m5, [P5], m2, m3, m8, m13, 4, m1, m8 ; [p5] -p7 -p6 +p5 +q1
+ FILTER_UPDATE m4, m5, m6, m7, [P4], m2, m8, m9, m13, 4, m1, m9, m13, [Q2] ; [p4] -p7 -p5 +p4 +q2
+ FILTER_UPDATE m6, m7, m4, m5, [P3], m2, m9, m14, m13, 4, m1, m14, m13, [Q3] ; [p3] -p7 -p4 +p3 +q3
+ FILTER_UPDATE m4, m5, m6, m7, [P2], m2, m14, m15, m13, 4, m1, m13, [Q4] ; [p2] -p7 -p3 +p2 +q4
+ FILTER_UPDATE m6, m7, m4, m5, [P1], m2, m15, m10, m13, 4, m1, m13, [Q5] ; [p1] -p7 -p2 +p1 +q5
+ FILTER_UPDATE m4, m5, m6, m7, [P0], m2, m10, m11, m13, 4, m1, m13, [Q6] ; [p0] -p7 -p1 +p0 +q6
+ FILTER_UPDATE m6, m7, m4, m5, [Q0], m2, m11, m12, m13, 4, m1, m13, [Q7] ; [q0] -p7 -p0 +q0 +q7
+ FILTER_UPDATE m4, m5, m6, m7, [Q1], m3, m12, m2, m13, 4, m1, m2, [Q1] ; [q1] -p6 -q0 +q1 +q7
+ FILTER_UPDATE m6, m7, m4, m5, [Q2], m8, m2, m3, m13, 4, m1, m3, [Q2] ; [q2] -p5 -q1 +q2 +q7
+ FILTER_UPDATE m4, m5, m6, m7, [Q3], m9, m3, m8, m13, 4, m1, m8, m8, [Q3] ; [q3] -p4 -q2 +q3 +q7
+ FILTER_UPDATE m6, m7, m4, m5, [Q4], m14, m8, m9, m13, 4, m1, m9, m9, [Q4] ; [q4] -p3 -q3 +q4 +q7
+ FILTER_UPDATE m4, m5, m6, m7, [Q5], m15, m9, m14, m13, 4, m1, m14, m14, [Q5] ; [q5] -p2 -q4 +q5 +q7
+ FILTER_UPDATE m6, m7, m4, m5, [Q6], m10, m14, m15, m13, 4, m1, m15, m15, [Q6] ; [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]
+ mova m6, [P1]
+ mova m7, [P0]
+ 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
+%elif %2 == 44
+ SWAP 0, 7 ; m0 = p1
+ SWAP 3, 4 ; m3 = q1
+ DEFINE_REAL_P7_TO_Q7 2
+ SBUTTERFLY bw, 0, 1, 8
+ SBUTTERFLY bw, 2, 3, 8
+ SBUTTERFLY wd, 0, 2, 8
+ SBUTTERFLY wd, 1, 3, 8
+ SBUTTERFLY dq, 0, 4, 8
+ SBUTTERFLY dq, 1, 5, 8
+ SBUTTERFLY dq, 2, 6, 8
+ SBUTTERFLY dq, 3, 7, 8
+ movd [P7], m0
+ punpckhqdq m0, m8
+ movd [P6], m0
+ movd [Q0], m1
+ punpckhqdq m1, m9
+ movd [Q1], m1
+ movd [P3], m2
+ punpckhqdq m2, m10
+ movd [P2], m2
+ movd [Q4], m3
+ punpckhqdq m3, m11
+ movd [Q5], m3
+ movd [P5], m4
+ punpckhqdq m4, m12
+ movd [P4], m4
+ movd [Q2], m5
+ punpckhqdq m5, m13
+ movd [Q3], m5
+ movd [P1], m6
+ punpckhqdq m6, m14
+ movd [P0], m6
+ movd [Q6], m7
+ punpckhqdq m7, m8
+ movd [Q7], m7
+%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]
+ mova m6, [Q2]
+ mova m7, [Q3]
+ DEFINE_REAL_P7_TO_Q7
+ 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
+ movh [P7], m0
+ punpckhqdq m0, m8
+ movh [P6], m0
+ movh [Q0], m1
+ punpckhqdq m1, m9
+ movh [Q1], m1
+ movh [P3], m2
+ punpckhqdq m2, m10
+ movh [P2], m2
+ movh [Q4], m3
+ punpckhqdq m3, m11
+ movh [Q5], m3
+ movh [P5], m4
+ punpckhqdq m4, m12
+ movh [P4], m4
+ movh [Q2], m5
+ punpckhqdq m5, m13
+ movh [Q3], m5
+ movh [P1], m6
+ punpckhqdq m6, m14
+ movh [P0], m6
+ movh [Q6], m7
+ punpckhqdq m7, m8
+ movh [Q7], m7
+%endif
+%endif
+
+ RET
+%endmacro
+
+%macro LPF_16_VH 2
+INIT_XMM %2
+cglobal vp9_loop_filter_v_%1_16, 5,10,16, dst, stride, E, I, H, mstride, dst1, dst2, stride3, mstride3
+ LOOPFILTER v, %1
+cglobal vp9_loop_filter_h_%1_16, 5,10,16, 256, dst, stride, E, I, H, mstride, dst1, dst2, stride3, mstride3
+ LOOPFILTER h, %1
+%endmacro
+
+%macro LPF_16_VH_ALL_OPTS 1
+LPF_16_VH %1, sse2
+LPF_16_VH %1, ssse3
+LPF_16_VH %1, avx
+%endmacro
+
+LPF_16_VH_ALL_OPTS 16
+LPF_16_VH_ALL_OPTS 44
+LPF_16_VH_ALL_OPTS 48
+LPF_16_VH_ALL_OPTS 84
+LPF_16_VH_ALL_OPTS 88
+
+%endif ; x86-64
diff --git a/libavcodec/x86/vp9dsp.asm b/libavcodec/x86/vp9mc.asm
index 6488f30..59e636d 100644
--- a/libavcodec/x86/vp9dsp.asm
+++ b/libavcodec/x86/vp9mc.asm
@@ -1,39 +1,38 @@
;******************************************************************************
-;* VP9 SIMD optimizations
+;* VP9 MC SIMD optimizations
;*
;* 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/x86/x86util.asm"
-SECTION_RODATA
+SECTION_RODATA 32
-; FIXME share with vp8dsp.asm
-pw_256: times 8 dw 256
+cextern pw_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
+times 16 db %1, %2
+times 16 db %3, %4
+times 16 db %5, %6
+times 16 db %7, %8
%endmacro
-; int8_t ff_filters_ssse3[3][15][4][16]
+; int8_t ff_filters_ssse3[3][15][4][32]
const filters_ssse3 ; smooth
F8_TAPS -3, -1, 32, 64, 38, 1, -3, 0
F8_TAPS -2, -2, 29, 63, 41, 2, -3, 0
@@ -87,13 +86,13 @@ 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
+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+16]
- mova m9, [filteryq+32]
- mova m10, [filteryq+48]
+ mova m8, [filteryq+32]
+ mova m9, [filteryq+64]
+ mova m10, [filteryq+96]
%endif
.loop:
movh m0, [srcq-3]
@@ -115,9 +114,9 @@ cglobal %1_8tap_1d_h_ %+ %%px, 6, 6, 11, dst, src, dstride, sstride, h, filtery
pmaddubsw m4, m9
pmaddubsw m1, m10
%else
- pmaddubsw m2, [filteryq+16]
- pmaddubsw m4, [filteryq+32]
- pmaddubsw m1, [filteryq+48]
+ pmaddubsw m2, [filteryq+32]
+ pmaddubsw m4, [filteryq+64]
+ pmaddubsw m1, [filteryq+96]
%endif
paddw m0, m2
paddw m4, m1
@@ -145,30 +144,91 @@ 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, m2
+ paddw m1, m3
+ paddw m4, m6
+ paddw m5, m7
+ paddsw m0, m4
+ paddsw m1, m5
+ 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_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
+cglobal vp9_%1_8tap_1d_v_ %+ %%px, 6, 8, 11, dst, dstride, src, sstride, h, filtery, src4, sstride3
%else
-cglobal %1_8tap_1d_v_ %+ %%px, 4, 7, 11, dst, src, dstride, sstride, filtery, src4, sstride3
+cglobal vp9_%1_8tap_1d_v_ %+ %%px, 4, 7, 11, dst, dstride, src, 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
+ lea sstride3q, [sstrideq*3]
+ lea src4q, [srcq+sstrideq]
+ sub srcq, sstride3q
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]
+ 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?
+ ; 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]
@@ -189,9 +249,9 @@ cglobal %1_8tap_1d_v_ %+ %%px, 4, 7, 11, dst, src, dstride, sstride, filtery, sr
pmaddubsw m4, m9
pmaddubsw m1, m10
%else
- pmaddubsw m2, [filteryq+16]
- pmaddubsw m4, [filteryq+32]
- pmaddubsw m1, [filteryq+48]
+ pmaddubsw m2, [filteryq+32]
+ pmaddubsw m4, [filteryq+64]
+ pmaddubsw m1, [filteryq+96]
%endif
paddw m0, m2
paddw m4, m1
@@ -219,6 +279,76 @@ 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, m2
+ paddw m1, m3
+ paddw m4, m6
+ paddw m5, m7
+ paddsw m0, m4
+ paddsw m1, m5
+ 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
@@ -228,12 +358,12 @@ filter_v_fn avg
%define %%dstfn mova
%endif
-%if %2 <= 16
-cglobal %1%2, 5, 7, 4, dst, src, dstride, sstride, h, dstride3, sstride3
+%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 %1%2, 5, 5, 4, dst, src, dstride, sstride, h
+cglobal vp9_%1%2, 5, 5, 4, dst, dstride, src, sstride, h
%endif
.loop:
%%srcfn m0, [srcq]
@@ -259,10 +389,12 @@ cglobal %1%2, 5, 5, 4, dst, src, dstride, sstride, h
%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 sse
+INIT_MMX mmxext
fpel_fn avg, 4, strideq, strideq*2, stride3q, 4
fpel_fn avg, 8, strideq, strideq*2, stride3q, 4
INIT_XMM sse
@@ -273,5 +405,15 @@ 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 2f064ca..25e833f 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.h b/libavcodec/x86/xvididct.h
index 13a4e85..e8586fe 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
*/
diff --git a/libavcodec/x86/xvididct_init.c b/libavcodec/x86/xvididct_init.c
index e4f7345..8c22784 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
*/
diff --git a/libavcodec/x86/xvididct_mmx.c b/libavcodec/x86/xvididct_mmx.c
index e371142..57aa8c0 100644
--- a/libavcodec/x86/xvididct_mmx.c
+++ b/libavcodec/x86/xvididct_mmx.c
@@ -22,20 +22,20 @@
*
* conversion to gcc syntax by 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 Foundation,
+ * 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 @@
#include "libavutil/mem.h"
#include "libavcodec/avcodec.h"
+#include "libavcodec/idctdsp.h"
#include "idctdsp.h"
#include "xvididct.h"
@@ -497,13 +498,13 @@ void ff_xvid_idct_mmx(short *block)
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);
+ ff_put_pixels_clamped(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);
+ ff_add_pixels_clamped(block, dest, line_size);
}
#endif /* HAVE_MMX_INLINE */
@@ -536,13 +537,13 @@ void ff_xvid_idct_mmxext(short *block)
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);
+ ff_put_pixels_clamped(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);
+ ff_add_pixels_clamped(block, dest, line_size);
}
#endif /* HAVE_MMXEXT_INLINE */
diff --git a/libavcodec/x86/xvididct_sse2.c b/libavcodec/x86/xvididct_sse2.c
index d4f0169..51a5d9d 100644
--- a/libavcodec/x86/xvididct_sse2.c
+++ b/libavcodec/x86/xvididct_sse2.c
@@ -9,7 +9,7 @@
*
* Originally from dct/x86_asm/fdct_sse2_skal.asm in Xvid.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
* Vertical pass is an implementation of the scheme:
* Loeffler C., Ligtenberg A., and Moschytz C.S.:
@@ -23,25 +23,26 @@
*
* More details at http://skal.planet-d.net/coding/dct.html
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more 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,
+ * 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"
+#include "libavcodec/idctdsp.h"
+
#include "idctdsp.h"
#include "xvididct.h"
@@ -146,7 +147,7 @@ DECLARE_ASM_CONST(16, int32_t, walkenIdctRounders)[] = {
#endif
-#define ROUND(x) "paddd "MANGLE(x)
+#define ROUND(x) "paddd "x
#define JZ(reg, to) \
"testl "reg","reg" \n\t" \
@@ -342,17 +343,17 @@ DECLARE_ASM_CONST(16, int32_t, walkenIdctRounders)[] = {
"movdqa %%xmm6, 4*16("dct") \n\t" \
"movdqa "SREG2", 7*16("dct") \n\t"
-inline void ff_xvid_idct_sse2(short *block)
+av_extern_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))
+ iMTX_MULT("(%0)", MANGLE(iTab1), ROUND(MANGLE(walkenIdctRounders)), PUT_EVEN(ROW0))
+ iMTX_MULT("1*16(%0)", MANGLE(iTab2), ROUND("1*16+"MANGLE(walkenIdctRounders)), PUT_ODD(ROW1))
+ iMTX_MULT("2*16(%0)", MANGLE(iTab3), ROUND("2*16+"MANGLE(walkenIdctRounders)), 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))
+ iMTX_MULT("3*16(%0)", MANGLE(iTab4), ROUND("3*16+"MANGLE(walkenIdctRounders)), 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))
@@ -367,20 +368,20 @@ inline void ff_xvid_idct_sse2(short *block)
"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))
+ iMTX_MULT("5*16(%0)", MANGLE(iTab4), ROUND("4*16+"MANGLE(walkenIdctRounders)), PUT_ODD(ROW5))
JZ("%%edx", "1f")
"4: \n\t"
- iMTX_MULT("6*16(%0)", MANGLE(iTab3), ROUND(walkenIdctRounders + 5 * 16), PUT_EVEN(ROW6))
+ iMTX_MULT("6*16(%0)", MANGLE(iTab3), ROUND("5*16+"MANGLE(walkenIdctRounders)), PUT_EVEN(ROW6))
JZ("%%esi", "1f")
"5: \n\t"
- iMTX_MULT("7*16(%0)", MANGLE(iTab2), ROUND(walkenIdctRounders + 5 * 16), PUT_ODD(ROW7))
+ iMTX_MULT("7*16(%0)", MANGLE(iTab2), ROUND("5*16+"MANGLE(walkenIdctRounders)), PUT_ODD(ROW7))
#if ARCH_X86_32
iLLM_HEAD
#endif
iLLM_PASS("%0")
"6: \n\t"
: "+r" (block)
- :
+ : NAMED_CONSTRAINTS_ARRAY(m127,iTab1,walkenIdctRounders,iTab2,iTab3,iTab4,tan3,tan1,tan2,sqrt2)
: XMM_CLOBBERS("%xmm0", "%xmm1", "%xmm2", "%xmm3",
"%xmm4", "%xmm5", "%xmm6", "%xmm7", )
#if ARCH_X86_64
@@ -393,13 +394,13 @@ inline void ff_xvid_idct_sse2(short *block)
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);
+ ff_put_pixels_clamped(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);
+ ff_add_pixels_clamped(block, dest, line_size);
}
#endif /* HAVE_SSE2_INLINE */
diff --git a/libavcodec/xan.c b/libavcodec/xan.c
index 4bf1d87..968464c 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:
@@ -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 c26f343..143e3a2 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 517e569..a752bdf 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 0000000..0ebf2f2
--- /dev/null
+++ b/libavcodec/xface.c
@@ -0,0 +1,381 @@
+/*
+ * 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 "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) {
+ 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 */
+ 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) {
+ 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 0000000..cd59ba0
--- /dev/null
+++ b/libavcodec/xface.h
@@ -0,0 +1,95 @@
+/*
+ * 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 92 symbols. In order to express 48x48=2304
+ * bits, we need a total of 354 digits, as given by:
+ * ceil(lg_92(2^2304)) = 354
+ */
+#define XFACE_MAX_DIGITS 354
+
+#define XFACE_BITSPERWORD 8
+#define XFACE_WORDCARRY (1 << XFACE_BITSPERWORD)
+#define XFACE_WORDMASK (XFACE_WORDCARRY - 1)
+
+#define XFACE_MAX_WORDS ((XFACE_PIXELS * 2 + XFACE_BITSPERWORD - 1) / XFACE_BITSPERWORD)
+
+/* 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 {
+ int range;
+ int 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 0000000..d045cb6
--- /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 0000000..e213c9d
--- /dev/null
+++ b/libavcodec/xfaceenc.c
@@ -0,0 +1,238 @@
+/*
+ * 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"
+
+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 {
+ const 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;
+ while (b.nb_words) {
+ uint8_t r;
+ ff_big_div(&b, XFACE_PRINTS, &r);
+ 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_freep(&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 PixelFormat[]) { AV_PIX_FMT_MONOWHITE, AV_PIX_FMT_NONE },
+};
diff --git a/libavcodec/xiph.c b/libavcodec/xiph.c
index 7c3c710..49b978d 100644
--- a/libavcodec/xiph.c
+++ b/libavcodec/xiph.c
@@ -1,27 +1,27 @@
/*
- * 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 avpriv_split_xiph_headers(const uint8_t *extradata, int extradata_size,
int first_header_size, uint8_t *header_start[3],
int header_len[3])
{
diff --git a/libavcodec/xiph.h b/libavcodec/xiph.h
index afaece7..b8ddbbe 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,7 +36,7 @@
* @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 avpriv_split_xiph_headers(const uint8_t *extradata, int extradata_size,
int first_header_size, uint8_t *header_start[3],
int header_len[3]);
diff --git a/libavcodec/xl.c b/libavcodec/xl.c
index 8e9bdc6..2d1da1d 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 3d85973..174d74e 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
*/
@@ -56,12 +56,11 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
int w, h, x, y, i;
int64_t packet_time = 0;
GetBitContext gb;
-
- memset(sub, 0, sizeof(*sub));
+ int has_alpha = avctx->codec_tag == MKTAG('D','X','S','A');
// check that at least header fits
if (buf_size < 27 + 7 * 2 + 4 * 3) {
- 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;
}
@@ -108,8 +107,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
for (i = 0; i < sub->rects[0]->nb_colors; i++)
((uint32_t*)sub->rects[0]->pict.data[1])[i] = bytestream_get_be24(&buf);
// make all except background (first entry) non-transparent
- for (i = 1; i < sub->rects[0]->nb_colors; i++)
- ((uint32_t*)sub->rects[0]->pict.data[1])[i] |= 0xff000000;
+ for (i = 0; i < sub->rects[0]->nb_colors; i++)
+ ((uint32_t*)sub->rects[0]->pict.data[1])[i] |= (has_alpha ? *buf++ : (i ? 0xff : 0)) << 24;
// process RLE-compressed data
init_get_bits(&gb, buf, (buf_end - buf) * 8);
diff --git a/libavcodec/xsubenc.c b/libavcodec/xsubenc.c
index fc46fb8..7070854 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 ca89703..e9fab70 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 499f819..f7dfba4 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 950ed18..c2e187c 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 9018e4a..d365ef0 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 f41e2cd..d046046 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 f6ccb96..62dfdac 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 54599a0..06fa4a0 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 d77a50f..b261cdf 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 0000000..9d1e531
--- /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 < 1.5 * 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;
+
+ 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 0000000..8f67944
--- /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_freep(&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 3434fd9..c6b19ec 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 0000000..00ccf58
--- /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 0000000..ed0fc77
--- /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_freep(&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 eeba2de..9f6c37c 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 f49cbdb..c16d912 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,13 @@ 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 */
c->flags = buf[0];
buf++; len--;
if (c->flags & ZMBV_KEYFRAME) {
+ void *decode_intra = NULL;
+ c->decode_intra= NULL;
hi_ver = buf[0];
lo_ver = buf[1];
c->comp = buf[2];
@@ -447,29 +445,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 +489,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 +505,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 +516,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 +541,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 +584,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 d7b518d..2d56a13 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 2a21832..e44c88a 100644
--- a/libavdevice/Makefile
+++ b/libavdevice/Makefile
@@ -1,3 +1,5 @@
+include $(SUBDIR)../config.mak
+
NAME = avdevice
HEADERS = avdevice.h \
@@ -8,22 +10,45 @@ OBJS = alldevices.o \
# input/output devices
OBJS-$(CONFIG_ALSA_INDEV) += alsa-audio-common.o \
- alsa-audio-dec.o
+ alsa-audio-dec.o timefilter.o
OBJS-$(CONFIG_ALSA_OUTDEV) += alsa-audio-common.o \
alsa-audio-enc.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.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_audio.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_audio.o oss_audio_dec.o
OBJS-$(CONFIG_OSS_OUTDEV) += oss_audio.o oss_audio_enc.o
-OBJS-$(CONFIG_PULSE_INDEV) += pulse.o
+OBJS-$(CONFIG_PULSE_INDEV) += pulse_audio_dec.o \
+ pulse_audio_common.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_common.o sndio_dec.o
OBJS-$(CONFIG_SNDIO_OUTDEV) += sndio_common.o sndio_enc.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
@@ -31,6 +56,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-audio.h
SKIPHEADERS-$(HAVE_SNDIO_H) += sndio_common.h
diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c
index 5dbe277..26aecf2 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-audio-common.c b/libavdevice/alsa-audio-common.c
index 21f1594..749897f 100644
--- a/libavdevice/alsa-audio-common.c
+++ b/libavdevice/alsa-audio-common.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
@@ -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;
}
@@ -360,3 +343,55 @@ int ff_alsa_extend_reorder_buf(AlsaData *s, int min_size)
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;
+ }
+ 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-audio-dec.c b/libavdevice/alsa-audio-dec.c
index 0687a4a..7f8f8cd 100644
--- a/libavdevice/alsa-audio-dec.c
+++ b/libavdevice/alsa-audio-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
*/
@@ -46,10 +46,12 @@
*/
#include <alsa/asoundlib.h>
-#include "libavformat/avformat.h"
#include "libavformat/internal.h"
#include "libavutil/opt.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/time.h"
+#include "avdevice.h"
#include "alsa-audio.h"
static av_cold int audio_read_header(AVFormatContext *s1)
@@ -58,7 +60,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) {
@@ -74,35 +75,17 @@ 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;
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;
@@ -114,16 +97,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);
@@ -136,20 +118,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 },
@@ -161,6 +148,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 = {
@@ -170,6 +158,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-audio-enc.c b/libavdevice/alsa-audio-enc.c
index bb4575f..43d097d 100644
--- a/libavdevice/alsa-audio-enc.c
+++ b/libavdevice/alsa-audio-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
*/
@@ -38,19 +38,26 @@
*/
#include <alsa/asoundlib.h>
-#include "libavformat/avformat.h"
+#include "libavutil/time.h"
+#include "libavformat/internal.h"
+#include "avdevice.h"
#include "alsa-audio.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,
@@ -61,6 +68,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;
@@ -77,6 +85,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))
@@ -101,6 +113,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"),
@@ -110,5 +163,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/alsa-audio.h b/libavdevice/alsa-audio.h
index 26eaee6..cf0e942 100644
--- a/libavdevice/alsa-audio.h
+++ b/libavdevice/alsa-audio.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_AUDIO_H */
diff --git a/libavdevice/avdevice.c b/libavdevice/avdevice.c
index 5a5c762..6a75bd7 100644
--- a/libavdevice/avdevice.c
+++ b/libavdevice/avdevice.c
@@ -1,36 +1,229 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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 "config.h"
+#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_INT,
+ {.i64 = AV_SAMPLE_FMT_NONE}, -1, 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_INT64,
+ {.i64 = -1}, -1, INT_MAX, E|D|A },
+ { "pixel_format", "pixel format", OFFSET(pixel_format), AV_OPT_TYPE_INT,
+ {.i64 = AV_PIX_FMT_NONE}, -1, 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 *av_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 av_device_next(d, 0, AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT,
+ AV_CLASS_CATEGORY_DEVICE_INPUT);
+}
+
+AVInputFormat *av_input_video_device_next(AVInputFormat *d)
+{
+ return av_device_next(d, 0, AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
+ AV_CLASS_CATEGORY_DEVICE_INPUT);
+}
+
+AVOutputFormat *av_output_audio_device_next(AVOutputFormat *d)
+{
+ return av_device_next(d, 1, AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT,
+ AV_CLASS_CATEGORY_DEVICE_OUTPUT);
+}
+
+AVOutputFormat *av_output_video_device_next(AVOutputFormat *d)
+{
+ return av_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 (!s->control_message_cb)
+ return AVERROR(ENOSYS);
+ return s->control_message_cb(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;
+}
+
+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_free(dev->device_name);
+ av_free(dev->device_description);
+ av_free(dev);
+ }
+ }
+ av_free(list->devices);
+ av_freep(device_list);
}
diff --git a/libavdevice/avdevice.h b/libavdevice/avdevice.h
index 39166a5..a395228 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,419 @@ 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);
+
#endif /* AVDEVICE_AVDEVICE_H */
diff --git a/libavdevice/avdeviceres.rc b/libavdevice/avdeviceres.rc
new file mode 100644
index 0000000..e13e73d
--- /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 0000000..1a7eb5b
--- /dev/null
+++ b/libavdevice/avfoundation.m
@@ -0,0 +1,855 @@
+/*
+ * 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/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 __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;
+
+ 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);
+ }
+}
+
+static int add_video_device(AVFormatContext *s, AVCaptureDevice *video_device)
+{
+ AVFContext *ctx = (AVFContext*)s->priv_data;
+ NSError *error = nil;
+ AVCaptureInput* capture_input = nil;
+
+ 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;
+ }
+
+ // select pixel format
+ struct AVFPixelFormatSpec pxl_fmt_spec;
+ 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;
+ NSNumber *pixel_format = [NSNumber numberWithUnsignedInt:pxl_fmt_spec.avf_id];
+ NSDictionary *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];
+
+ dispatch_queue_t 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];
+
+ 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];
+
+ dispatch_queue_t 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;
+
+ // 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) {
+ return 1;
+ }
+
+ ctx->video_stream_index = stream->index;
+
+ avpriv_set_pts_info(stream, 64, 1, avf_time_base);
+
+ CVImageBufferRef image_buffer = CMSampleBufferGetImageBuffer(ctx->current_frame);
+ CGSize 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;
+
+ // Take stream info from the first frame.
+ while (ctx->audio_frames_captured < 1) {
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
+ }
+
+ lock_frames(ctx);
+
+ AVStream* stream = avformat_new_stream(s, NULL);
+
+ if (!stream) {
+ return 1;
+ }
+
+ ctx->audio_stream_index = stream->index;
+
+ avpriv_set_pts_info(stream, 64, 1, avf_time_base);
+
+ CMFormatDescriptionRef 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_packed) {
+ stream->codec->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE;
+ } 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];
+ AVFContext *ctx = (AVFContext*)s->priv_data;
+ ctx->first_pts = av_gettime();
+ ctx->first_audio_pts = av_gettime();
+ uint32_t num_screens = 0;
+
+ pthread_mutex_init(&ctx->frame_lock, NULL);
+ pthread_cond_init(&ctx->frame_wait_cond, NULL);
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+ CGGetActiveDisplayList(0, NULL, &num_screens);
+#endif
+
+ // List devices if requested
+ if (ctx->list_devices) {
+ av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n");
+ NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
+ int index = 0;
+ 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 __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;
+ }
+
+ // Find capture device
+ AVCaptureDevice *video_device = nil;
+ AVCaptureDevice *audio_device = nil;
+
+ NSArray *video_devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
+ ctx->num_video_devices = [video_devices count];
+
+ // 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 = [video_devices objectAtIndex:ctx->video_device_index];
+ } else if (ctx->video_device_index < ctx->num_video_devices + num_screens) {
+#if __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];
+ video_device = (AVCaptureDevice*) capture_screen_input;
+#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 video_devices) {
+ if (!strncmp(ctx->video_filename, [[device localizedName] UTF8String], strlen(ctx->video_filename))) {
+ video_device = device;
+ break;
+ }
+ }
+
+#if __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;
+ }
+ }
+#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];
+
+ 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 {
+ lock_frames(ctx);
+
+ CVImageBufferRef image_buffer = CMSampleBufferGetImageBuffer(ctx->current_frame);
+
+ if (ctx->current_frame != nil) {
+ if (av_new_packet(pkt, (int)CVPixelBufferGetDataSize(image_buffer)) < 0) {
+ return AVERROR(EIO);
+ }
+
+ pkt->pts = pkt->dts = av_rescale_q(av_gettime() - ctx->first_pts,
+ AV_TIME_BASE_Q,
+ avf_time_base_q);
+ pkt->stream_index = ctx->video_stream_index;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+
+ CVPixelBufferLockBaseAddress(image_buffer, 0);
+
+ void* 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);
+ }
+
+ pkt->pts = pkt->dts = av_rescale_q(av_gettime() - ctx->first_audio_pts,
+ AV_TIME_BASE_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;
+
+ OSStatus ret = CMBlockBufferCopyDataBytes(block_buffer, 0, pkt->size, ctx->audio_buffer);
+ if (ret != kCMBlockBufferNoErr) {
+ return AVERROR(EIO);
+ }
+
+ int 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},
+ { 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 695e13f..6c5a834 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;
if (idev < 0 || idev > 4)
{
@@ -248,15 +247,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;
@@ -279,20 +272,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;
@@ -333,7 +324,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 },
};
@@ -343,6 +334,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 0000000..ff54940
--- /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 0000000..9a9e44b
--- /dev/null
+++ b/libavdevice/decklink_common.cpp
@@ -0,0 +1,229 @@
+/*
+ * 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) != S_OK) {
+ 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
+#else
+#define DECKLINK_STR const char *
+#define DECKLINK_STRDUP av_strdup
+#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);
+ /* free() is needed for a string returned by the DeckLink SDL. */
+ free((void *) 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 0000000..544da27
--- /dev/null
+++ b/libavdevice/decklink_common.h
@@ -0,0 +1,98 @@
+/*
+ * 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);
+char *dup_wchar_to_utf8(wchar_t *w);
+#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 0000000..861a51a
--- /dev/null
+++ b/libavdevice/decklink_common_c.h
@@ -0,0 +1,32 @@
+/*
+ * 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;
+};
+
diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
new file mode 100644
index 0000000..77a0fe5
--- /dev/null
+++ b/libavdevice/decklink_dec.cpp
@@ -0,0 +1,531 @@
+/*
+ * 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) {
+ 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->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->codec->width = ctx->bmd_width;
+ st->codec->height = ctx->bmd_height;
+
+ st->codec->pix_fmt = AV_PIX_FMT_UYVY422;
+ 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;
+ 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, 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 0000000..6bd9226
--- /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 0000000..2aea277
--- /dev/null
+++ b/libavdevice/decklink_dec_c.c
@@ -0,0 +1,54 @@
+/*
+ * 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 },
+ { 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 0000000..6c5450f
--- /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 0000000..6086947
--- /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 0000000..c3c9018
--- /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 0000000..a543249
--- /dev/null
+++ b/libavdevice/dshow.c
@@ -0,0 +1,1100 @@
+/*
+ * 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 "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/opt.h"
+#include "libavformat/internal.h"
+#include "libavformat/riff.h"
+#include "avdevice.h"
+#include "dshow_capture.h"
+#include "libavcodec/raw.h"
+
+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;
+
+ 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;
+};
+
+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_free(ctx->device_name[0]);
+ if (ctx->device_name[1])
+ av_free(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_destruct_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;
+
+ if(dropscore[++ctx->video_frame_num%ndropscores] <= buffer_fullness) {
+ av_log(s, AV_LOG_ERROR,
+ "real-time buffer[%s] too full (%d%% of size: %d)! frame dropped!\n", ctx->device_name[devtype], 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, 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";
+
+ r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[devtype],
+ (IEnumMoniker **) &classenum, 0);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices.\n",
+ devtypename);
+ return AVERROR(EIO);
+ }
+
+ while (!device_filter && IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK) {
+ IPropertyBag *bag = NULL;
+ char *buf = NULL;
+ VARIANT var;
+
+ 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;
+
+ buf = dup_wchar_to_utf8(var.bstrVal);
+
+ if (pfilter) {
+ if (strcmp(device_name, buf))
+ goto fail1;
+
+ if (!skip--)
+ IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *) &device_filter);
+ } else {
+ av_log(avctx, AV_LOG_INFO, " \"%s\"\n", buf);
+ }
+
+fail1:
+ if (buf)
+ av_free(buf);
+ 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.\n",
+ devtypename);
+ 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;
+
+ 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++) {
+ IAMStreamConfig_GetStreamCaps(config, i, &type, (void *) caps);
+
+#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);
+ if (caps)
+ 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;
+}
+
+/**
+ * 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,
+ 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";
+
+ 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;
+
+ 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\n",
+ devtypename);
+ }
+ 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;
+
+ 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;
+
+ if (!ppin) {
+ char *buf = dup_wchar_to_utf8(info.achName);
+ av_log(avctx, AV_LOG_INFO, " Pin \"%s\"\n", buf);
+ av_free(buf);
+ dshow_cycle_formats(avctx, devtype, pin, NULL);
+ 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);
+ while (!device_pin && IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK) {
+ if (IsEqualGUID(&type->majortype, mediatype[devtype])) {
+ device_pin = pin;
+ goto next;
+ }
+ CoTaskMemFree(type);
+ }
+
+next:
+ if (types)
+ IEnumMediaTypes_Release(types);
+ if (p)
+ IKsPropertySet_Release(p);
+ if (device_pin != pin)
+ IPin_Release(pin);
+ }
+
+ 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.
+ *
+ * @param devenum device enumerator used for accessing the device
+ */
+static int
+dshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum,
+ enum dshowDeviceType devtype)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ IBaseFilter *device_filter = NULL;
+ int r;
+
+ if ((r = dshow_cycle_devices(avctx, devenum, devtype, &device_filter)) < 0)
+ return r;
+ ctx->device_filter[devtype] = device_filter;
+ if ((r = dshow_cycle_pins(avctx, devtype, device_filter, NULL)) < 0)
+ return r;
+
+ return 0;
+}
+
+static int
+dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
+ enum dshowDeviceType devtype)
+{
+ 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;
+ int ret = AVERROR(EIO);
+ int r;
+
+ const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" };
+
+ if ((r = dshow_cycle_devices(avctx, devenum, devtype, &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, 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;
+
+ 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 = IGraphBuilder_ConnectDirect(graph, device_pin, (IPin *) capture_pin, NULL);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not connect pins\n");
+ goto error;
+ }
+
+ ret = 0;
+
+error:
+ 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\n");
+ dshow_cycle_devices(avctx, devenum, VideoDevice, NULL);
+ av_log(avctx, AV_LOG_INFO, "DirectShow audio devices\n");
+ dshow_cycle_devices(avctx, devenum, AudioDevice, NULL);
+ ret = AVERROR_EXIT;
+ goto error;
+ }
+ if (ctx->list_options) {
+ if (ctx->device_name[VideoDevice])
+ dshow_list_device_options(avctx, devenum, VideoDevice);
+ if (ctx->device_name[AudioDevice])
+ dshow_list_device_options(avctx, devenum, AudioDevice);
+ ret = AVERROR_EXIT;
+ goto error;
+ }
+
+ if (ctx->device_name[VideoDevice]) {
+ if ((r = dshow_open_device(avctx, devenum, VideoDevice)) < 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)) < 0 ||
+ (r = dshow_add_device(avctx, AudioDevice)) < 0) {
+ ret = r;
+ 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 filter\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 },
+ { "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 },
+ { "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 },
+ { 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 0000000..e4b4dce
--- /dev/null
+++ b/libavdevice/dshow_capture.h
@@ -0,0 +1,279 @@
+/*
+ * 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
+#include <windows.h>
+#define NO_DSHOW_STRSAFE
+#include <dshow.h>
+#include <dvdmedia.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);
+
+#if DSHOWDEBUG
+extern const AVClass *ff_dshow_context_class_ptr;
+#define dshowdebug(...) av_log(&ff_dshow_context_class_ptr, AV_LOG_DEBUG, __VA_ARGS__)
+#else
+#define dshowdebug(...)
+#endif
+
+static inline void nothing(void *foo)
+{
+}
+
+struct GUIDoffset {
+ const GUID *iid;
+ int offset;
+};
+
+enum dshowDeviceType {
+ VideoDevice = 0,
+ AudioDevice = 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 {
+ IEnumPinsVtbl *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);
+
+#endif /* AVDEVICE_DSHOW_H */
diff --git a/libavdevice/dshow_common.c b/libavdevice/dshow_common.c
new file mode 100644
index 0000000..f7f0dfb
--- /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_enummediatypes.c b/libavdevice/dshow_enummediatypes.c
new file mode 100644
index 0000000..5b69a5b
--- /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 0000000..e5c11cb
--- /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 0000000..7360adc
--- /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 0000000..1c0dca2
--- /dev/null
+++ b/libavdevice/dshow_pin.c
@@ -0,0 +1,362 @@
+/*
+ * 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;
+ int index;
+ int64_t curtime;
+
+ dshowdebug("libAVMemInputPin_Receive(%p)\n", this);
+
+ if (!sample)
+ return E_POINTER;
+
+ if (devtype == VideoDevice) {
+ /* PTS from video devices is unreliable. */
+ IReferenceClock *clock = pin->filter->clock;
+ IReferenceClock_GetTime(clock, &curtime);
+ } else {
+ int64_t dummy;
+ IMediaSample_GetTime(sample, &curtime, &dummy);
+ 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;
+
+ 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 d259e1a..c8241e3 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--;
@@ -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 9710ff5..b76d633 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_common.c b/libavdevice/fbdev_common.c
new file mode 100644
index 0000000..713e4fd
--- /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_free(device->device_name);
+ av_free(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 0000000..7b81a8d
--- /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.c b/libavdevice/fbdev_dec.c
index a83b4f1..f56408c 100644
--- a/libavdevice/fbdev.c
+++ b/libavdevice/fbdev_dec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2009 Giliard B. de Freitas <giliarde@gmail.com>
* Copyright (C) 2002 Gunnar Monell <gmo@linux.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
*/
@@ -41,46 +41,14 @@
#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;
-}
+#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
- 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
@@ -100,13 +68,7 @@ static av_cold int fbdev_read_header(AVFormatContext *avctx)
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;
- }
+ const char* device;
if (!(st = avformat_new_stream(avctx, NULL)))
return AVERROR(ENOMEM);
@@ -116,32 +78,34 @@ static av_cold int fbdev_read_header(AVFormatContext *avctx)
if (avctx->flags & AVFMT_FLAG_NONBLOCK)
flags |= O_NONBLOCK;
- if ((fbdev->fd = avpriv_open(avctx->filename, flags)) == -1) {
+ 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_strerror(ret, errbuf, sizeof(errbuf));
av_log(avctx, AV_LOG_ERROR,
"Could not open framebuffer device '%s': %s\n",
- avctx->filename, errbuf);
+ device, av_err2str(ret));
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);
+ "FBIOGET_VSCREENINFO: %s\n", av_err2str(ret));
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);
+ "FBIOGET_FSCREENINFO: %s\n", av_err2str(ret));
goto fail;
}
- pix_fmt = get_pixfmt_from_fb_varinfo(&fbdev->varinfo);
+ 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,
@@ -158,8 +122,7 @@ static av_cold int fbdev_read_header(AVFormatContext *avctx)
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);
+ av_log(avctx, AV_LOG_ERROR, "Error in mmap(): %s\n", av_err2str(ret));
goto fail;
}
@@ -168,7 +131,7 @@ static av_cold int fbdev_read_header(AVFormatContext *avctx)
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->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;
@@ -197,30 +160,30 @@ static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
fbdev->time_frame = av_gettime();
/* wait based on the frame rate */
- curtime = av_gettime();
- delay = fbdev->time_frame - curtime;
- av_dlog(avctx,
- "time_frame:%"PRId64" curtime:%"PRId64" delay:%"PRId64"\n",
- fbdev->time_frame, curtime, delay);
- if (delay > 0) {
+ while (1) {
+ curtime = av_gettime();
+ delay = fbdev->time_frame - curtime;
+ av_dlog(avctx,
+ "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);
}
- /* 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);
+ "Error refreshing variable info: %s\n", av_err2str(AVERROR(errno)));
}
pkt->pts = curtime;
@@ -230,7 +193,6 @@ static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
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;
@@ -244,16 +206,21 @@ static av_cold int fbdev_read_close(AVFormatContext *avctx)
{
FBDevContext *fbdev = avctx->priv_data;
- munmap(fbdev->data, fbdev->frame_size);
+ 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), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC },
+ { "framerate","", OFFSET(framerate_q), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC },
{ NULL },
};
@@ -262,6 +229,7 @@ static const AVClass fbdev_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
};
AVInputFormat ff_fbdev_demuxer = {
@@ -271,6 +239,7 @@ AVInputFormat ff_fbdev_demuxer = {
.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 0000000..28efc71
--- /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 0000000..9a185d4
--- /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 0000000..6d5ec4a
--- /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_free(packet->buf);
+ av_free(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 (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 (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_free(packet->buf);
+ av_free(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/jack_audio.c b/libavdevice/jack_audio.c
index 7bdc229..0c52a8e 100644
--- a/libavdevice/jack_audio.c
+++ b/libavdevice/jack_audio.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
*/
@@ -32,6 +32,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
@@ -151,7 +152,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);
@@ -163,7 +163,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));
self->buffer_size = jack_get_buffer_size(self->client);
/* Register JACK ports */
@@ -187,18 +187,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;
@@ -208,14 +206,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)
@@ -226,8 +224,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);
}
@@ -338,6 +336,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 0000000..1398ece
--- /dev/null
+++ b/libavdevice/lavfi.c
@@ -0,0 +1,436 @@
+/*
+ * 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;
+ AVFrame *decoded_frame;
+} 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->sinks);
+ avfilter_graph_free(&lavfi->graph);
+ av_frame_free(&lavfi->decoded_frame);
+
+ 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_close(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);
+
+ 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));
+
+ 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;
+ if (!strcmp(inout->name, "out"))
+ stream_idx = 0;
+ else if (sscanf(inout->name, "out%d\n", &stream_idx) != 1) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Invalid outpad name '%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;
+ }
+
+ /* 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(avctx->nb_streams, 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 < avctx->nb_streams; 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 (!(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 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;
+
+ /* iterate through all the graph sinks. Select the sink with the
+ * minimum PTS */
+ for (i = 0; i < avctx->nb_streams; 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);
+ }
+
+ 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 663af85..de7278c 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 06ddb4a..16a4b26 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;
@@ -177,6 +177,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 f030e3e..e9bd4c9 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
*/
@@ -112,6 +112,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 0000000..4c4ba28
--- /dev/null
+++ b/libavdevice/openal-dec.c
@@ -0,0 +1,253 @@
+/*
+ * 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 */
+ av_new_packet(pkt, nb_samples*ad->sample_step);
+ 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 0000000..5f5b800
--- /dev/null
+++ b/libavdevice/opengl_enc.c
@@ -0,0 +1,1306 @@
+/*
+ * 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
+#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 0000000..ed8b3d3
--- /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_audio.c b/libavdevice/oss_audio.c
index 4feb937..4eb6a50 100644
--- a/libavdevice/oss_audio.c
+++ b/libavdevice/oss_audio.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_audio.h"
@@ -64,8 +65,11 @@ 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, strerror(errno));
+ }
+ }
s->frame_size = OSS_AUDIO_BLOCK_SIZE;
@@ -80,7 +84,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", strerror(errno));
+ }
#if HAVE_BIGENDIAN
if (tmp & AFMT_S16_BE) {
diff --git a/libavdevice/oss_audio.h b/libavdevice/oss_audio.h
index 87ac4ad..8258028 100644
--- a/libavdevice/oss_audio.h
+++ b/libavdevice/oss_audio.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_audio_dec.c b/libavdevice/oss_audio_dec.c
index 601d91c..1f86d06 100644
--- a/libavdevice/oss_audio_dec.c
+++ b/libavdevice/oss_audio_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_audio.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_audio_enc.c b/libavdevice/oss_audio_enc.c
index 688982a..5d3bded 100644
--- a/libavdevice/oss_audio_enc.c
+++ b/libavdevice/oss_audio_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_audio.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 2136ee3..0000000
--- a/libavdevice/pulse.c
+++ /dev/null
@@ -1,195 +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 "libavformat/avformat.h"
-#include "libavformat/internal.h"
-#include "libavutil/time.h"
-#include "libavutil/opt.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 0000000..5a2568b
--- /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_free(new_device->device_description);
+ av_free(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 0000000..02534f7
--- /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 0000000..316cc4a
--- /dev/null
+++ b/libavdevice/pulse_audio_dec.c
@@ -0,0 +1,373 @@
+/*
+ * 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 "libavformat/avformat.h"
+#include "libavformat/internal.h"
+#include "libavutil/opt.h"
+#include "libavutil/time.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 0000000..bc4d1f0
--- /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 0000000..aa8fa16
--- /dev/null
+++ b/libavdevice/qtkit.m
@@ -0,0 +1,358 @@
+/*
+ * 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>
+ */
+
+#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 0000000..b98aae5
--- /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_common.c b/libavdevice/sndio_common.c
index 1bea6c5..19f39be 100644
--- a/libavdevice/sndio_common.c
+++ b/libavdevice/sndio_common.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 "sndio_common.h"
diff --git a/libavdevice/sndio_common.h b/libavdevice/sndio_common.h
index 2f70213..74f41f5 100644
--- a/libavdevice/sndio_common.h
+++ b/libavdevice/sndio_common.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 58caaa1..37c6983 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
*/
@@ -104,6 +104,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 6f69b9e..205cf24 100644
--- a/libavdevice/sndio_enc.c
+++ b/libavdevice/sndio_enc.c
@@ -2,28 +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 "sndio_common.h"
static av_cold int audio_write_header(AVFormatContext *s1)
@@ -77,6 +76,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"),
@@ -90,4 +96,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 a497351..9d38f93 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 2235db6..cb3d0a7 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/v4l.c b/libavdevice/v4l.c
new file mode 100644
index 0000000..d33f714
--- /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 0000000..196c09b
--- /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 0000000..40c7164
--- /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 302639d..8695645 100644
--- a/libavdevice/v4l2.c
+++ b/libavdevice/v4l2.c
@@ -1,57 +1,40 @@
/*
- * 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"
+
+#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,100 +42,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 },
};
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;
}
@@ -160,33 +172,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,
@@ -196,87 +207,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",
@@ -297,26 +265,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 : %9s : %20s :",
fmt_name ? fmt_name : "Unsupported",
vfd.description);
} else if (vfd.flags & V4L2_FMT_FLAG_COMPRESSED &&
type & V4L_COMPFORMATS) {
- AVCodec *codec = avcodec_find_encoder(codec_id);
- av_log(ctx, AV_LOG_INFO, "C : %9s : %20s :",
+ AVCodec *codec = avcodec_find_decoder(codec_id);
+ av_log(ctx, AV_LOG_INFO, "Compressed: %9s : %20s :",
codec ? codec->name : "Unsupported",
vfd.description);
} else {
@@ -324,18 +293,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;
@@ -346,35 +337,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);
-
return AVERROR(ENOMEM);
}
@@ -384,33 +366,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;
}
}
@@ -425,27 +400,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;
+ }
+ }
+#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);
}
- avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1);
+#endif
+ return 0;
}
static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt)
@@ -455,30 +496,18 @@ 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);
-
/* 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;
-
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;
}
@@ -490,11 +519,17 @@ 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);
+ /* 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;
+
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);
-
+ enqueue_buffer(s, &buf);
return AVERROR_INVALIDDATA;
}
@@ -504,18 +539,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;
@@ -533,22 +566,24 @@ 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];
}
@@ -557,8 +592,7 @@ 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 = {
@@ -567,27 +601,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;
@@ -602,270 +630,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);
}
-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 allow to change 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_header(AVFormatContext *s1)
+static int v4l2_read_probe(AVProbeData *p)
{
- struct video_data *s = s1->priv_data;
+ if (av_strstart(p->filename, "/dev/video", NULL))
+ return AVPROBE_SCORE_MAX - 1;
+ return 0;
+}
+
+static int v4l2_read_header(AVFormatContext *ctx)
+{
+ 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;
+ 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;
}
@@ -877,33 +992,45 @@ 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;
}
#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 },
};
@@ -912,12 +1039,14 @@ 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,
diff --git a/libavdevice/v4l2enc.c b/libavdevice/v4l2enc.c
new file mode 100644
index 0000000..ac4068c
--- /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 9453234..3e427f0 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 3
+#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 b47de1b..00fb48b 100644
--- a/libavdevice/vfwcap.c
+++ b/libavdevice/vfwcap.c
@@ -2,30 +2,30 @@
* 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
*/
-#include "libavformat/avformat.h"
#include "libavformat/internal.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#include <windows.h>
#include <vfw.h>
+#include "avdevice.h"
/* Some obsolete versions of MinGW32 before 4.0.0 lack this. */
#ifndef HWND_MESSAGE
@@ -154,7 +154,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;
@@ -242,7 +242,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;
@@ -288,7 +288,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);
@@ -302,7 +302,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);
@@ -310,16 +310,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;
}
}
@@ -338,19 +343,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);
@@ -365,10 +368,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;
@@ -394,31 +397,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);
}
@@ -465,6 +468,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 3aa4294..3a833eb 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>
@@ -51,12 +52,13 @@
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/XShm.h>
+#include "avdevice.h"
+
#include "libavutil/log.h"
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#include "libavutil/time.h"
-#include "libavformat/avformat.h"
#include "libavformat/internal.h"
/** X11 device demuxer context */
@@ -66,9 +68,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 */
@@ -79,8 +80,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;
@@ -190,6 +194,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;
@@ -217,9 +223,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",
@@ -250,39 +261,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);
@@ -315,9 +321,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");
@@ -339,7 +347,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;
@@ -350,6 +358,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;
@@ -358,7 +379,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;
}
@@ -369,8 +390,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;
@@ -386,14 +408,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;
@@ -513,6 +546,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);
@@ -575,7 +618,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;
}
@@ -614,13 +657,17 @@ static int x11grab_read_close(AVFormatContext *s1)
#define OFFSET(x) offsetof(X11GrabContext, x)
#define DEC AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
- { "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 },
};
@@ -629,6 +676,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 5055fde..2fdb992 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
*/
@@ -47,7 +47,9 @@ typedef struct XCBGrabContext {
xcb_connection_t *conn;
xcb_screen_t *screen;
xcb_window_t window;
+#if CONFIG_LIBXCB_SHM
xcb_shm_seg_t segment;
+#endif
int64_t time_frame;
AVRational time_base;
@@ -92,6 +94,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,
@@ -488,7 +491,6 @@ static int create_stream(AVFormatContext *s)
{
XCBGrabContext *c = s->priv_data;
AVStream *st = avformat_new_stream(s, NULL);
- const char *opts = strchr(s->filename, '+');
xcb_get_geometry_cookie_t gc;
xcb_get_geometry_reply_t *geo;
int ret;
@@ -504,9 +506,6 @@ static int create_stream(AVFormatContext *s)
if (ret < 0)
return ret;
- if (opts)
- sscanf(opts, "%d,%d", &c->x, &c->y);
-
avpriv_set_pts_info(st, 64, 1, 1000000);
gc = xcb_get_geometry(c->conn, c->screen->root);
@@ -577,11 +576,13 @@ static void setup_window(AVFormatContext *s)
XCB_COPY_FROM_PARENT,
mask, values);
+#if XCB_SHAPE_RECTANGLES
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);
@@ -593,8 +594,20 @@ static av_cold int xcbgrab_read_header(AVFormatContext *s)
XCBGrabContext *c = s->priv_data;
int screen_num, ret;
const xcb_setup_t *setup;
+ char *display_name = av_strdup(s->filename);
+
+ if (s->filename) {
+ if (!display_name)
+ return AVERROR(ENOMEM);
- c->conn = xcb_connect(s->filename, &screen_num);
+ 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(display_name, &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 ? s->filename : "default", ret);
@@ -610,7 +623,9 @@ static av_cold int xcbgrab_read_header(AVFormatContext *s)
return AVERROR(EIO);
}
+#if CONFIG_LIBXCB_SHM
c->segment = xcb_generate_id(c->conn);
+#endif
ret = create_stream(s);
diff --git a/libavdevice/xv.c b/libavdevice/xv.c
new file mode 100644
index 0000000..c19c15c
--- /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 7b94f22..2c56e38 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,238 @@ 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_COMPAND_FILTER) += af_compand.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_COLORMATRIX_FILTER) += vf_colormatrix.o
OBJS-$(CONFIG_COPY_FILTER) += vf_copy.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_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_EXTRACTPLANES_FILTER) += vf_extractplanes.o
OBJS-$(CONFIG_FADE_FILTER) += vf_fade.o
+OBJS-$(CONFIG_FIELD_FILTER) += vf_field.o
+OBJS-$(CONFIG_FIELDMATCH_FILTER) += vf_fieldmatch.o
OBJS-$(CONFIG_FIELDORDER_FILTER) += vf_fieldorder.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_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_MP_FILTER) += vf_mp.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_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_PSNR_FILTER) += vf_psnr.o dualinput.o framesync.o
+OBJS-$(CONFIG_PULLUP_FILTER) += vf_pullup.o
+OBJS-$(CONFIG_REMOVELOGO_FILTER) += bbox.o lswsutils.o lavfutils.o vf_removelogo.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_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_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_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
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/mp_image.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/img_format.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_eq2.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_eq.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_fspp.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_ilpack.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_pp7.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_softpulldown.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_uspp.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
+
+# 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 0000000..45629a9
--- /dev/null
+++ b/libavfilter/aeval.c
@@ -0,0 +1,466 @@
+/*
+ * 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);
+}
+
+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 };
+
+ ff_set_common_formats (ctx, ff_make_format_list(sample_fmts));
+ 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 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 0000000..ef60f43
--- /dev/null
+++ b/libavfilter/af_adelay.c
@@ -0,0 +1,282 @@
+/*
+ * 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
+ };
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_set_common_channel_layouts(ctx, 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;
+}
+
+#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 0000000..c26fdd4
--- /dev/null
+++ b/libavfilter/af_aecho.c
@@ -0,0 +1,359 @@
+/*
+ * 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
+ };
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_set_common_channel_layouts(ctx, 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;
+}
+
+#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 0000000..806f6f6
--- /dev/null
+++ b/libavfilter/af_afade.c
@@ -0,0 +1,300 @@
+/*
+ * 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
+ };
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_set_common_channel_layouts(ctx, 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 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 f074673..5fd0308 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 { \
@@ -118,7 +114,7 @@ static int query_formats(AVFilterContext *ctx)
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());
+ ff_all_channel_counts());
return 0;
}
@@ -146,7 +142,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 0000000..0a0a79f
--- /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 bfba150..47cbb45 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;
}
@@ -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.
@@ -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;
@@ -533,10 +528,17 @@ static av_cold void uninit(AVFilterContext *ctx)
static int query_formats(AVFilterContext *ctx)
{
AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layouts;
+
+ 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_channel_layouts(ctx, layouts);
ff_set_common_samplerates(ctx, ff_all_samplerates());
return 0;
}
@@ -552,17 +554,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 6d7caf3..fff456e 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 0000000..eafc705
--- /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 0000000..9d8f696
--- /dev/null
+++ b/libavfilter/af_aphaser.c
@@ -0,0 +1,294 @@
+/*
+ * 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;
+
+ enum WaveType 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
+ };
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_set_common_channel_layouts(ctx, 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;
+}
+
+#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;
+ 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 0000000..57ac397
--- /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 0000000..e830643
--- /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 0000000..0d06915
--- /dev/null
+++ b/libavfilter/af_asetrate.c
@@ -0,0 +1,119 @@
+/*
+ * 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 };
+
+ ff_formats_ref(ff_make_format_list(sample_rates),
+ &ctx->outputs[0]->in_samplerates);
+ return 0;
+}
+
+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 57120c1..ee95029 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 "audio.h"
@@ -45,24 +46,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;
@@ -168,12 +153,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(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];
@@ -187,11 +177,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);
@@ -214,19 +206,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[] = {
@@ -234,7 +223,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 0000000..60ccd73
--- /dev/null
+++ b/libavfilter/af_astats.c
@@ -0,0 +1,274 @@
+/*
+ * 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
+ };
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_set_common_channel_layouts(ctx, 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 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;
+
+ 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 0000000..becfe34
--- /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 e662c84..5f8e1f6 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 0000000..fcd0cb0
--- /dev/null
+++ b/libavfilter/af_atempo.c
@@ -0,0 +1,1202 @@
+/*
+ * 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
+ };
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts) {
+ return AVERROR(ENOMEM);
+ }
+ ff_set_common_channel_layouts(ctx, 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 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 0000000..02bf9db
--- /dev/null
+++ b/libavfilter/af_biquads.c
@@ -0,0 +1,620 @@
+/*
+ * 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;
+ enum WidthType 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 *p = ctx->priv;
+
+ if (p->filter_type != biquad) {
+ if (p->frequency <= 0 || p->width <= 0) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid frequency %f and/or width %f <= 0\n",
+ p->frequency, p->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
+ };
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_set_common_channel_layouts(ctx, 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;
+}
+
+#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 *p = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ double A = exp(p->gain / 40 * log(10.));
+ double w0 = 2 * M_PI * p->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",
+ p->frequency, inlink->sample_rate);
+ return AVERROR(EINVAL);
+ }
+
+ switch (p->width_type) {
+ case NONE:
+ alpha = 0.0;
+ break;
+ case HERTZ:
+ alpha = sin(w0) / (2 * p->frequency / p->width);
+ break;
+ case OCTAVE:
+ alpha = sin(w0) * sinh(log(2.) / 2 * p->width * w0 / sin(w0));
+ break;
+ case QFACTOR:
+ alpha = sin(w0) / (2 * p->width);
+ break;
+ case SLOPE:
+ alpha = sin(w0) / 2 * sqrt((A + 1 / A) * (1 / p->width - 1) + 2);
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ switch (p->filter_type) {
+ case biquad:
+ break;
+ case equalizer:
+ p->a0 = 1 + alpha / A;
+ p->a1 = -2 * cos(w0);
+ p->a2 = 1 - alpha / A;
+ p->b0 = 1 + alpha * A;
+ p->b1 = -2 * cos(w0);
+ p->b2 = 1 - alpha * A;
+ break;
+ case bass:
+ p->a0 = (A + 1) + (A - 1) * cos(w0) + 2 * sqrt(A) * alpha;
+ p->a1 = -2 * ((A - 1) + (A + 1) * cos(w0));
+ p->a2 = (A + 1) + (A - 1) * cos(w0) - 2 * sqrt(A) * alpha;
+ p->b0 = A * ((A + 1) - (A - 1) * cos(w0) + 2 * sqrt(A) * alpha);
+ p->b1 = 2 * A * ((A - 1) - (A + 1) * cos(w0));
+ p->b2 = A * ((A + 1) - (A - 1) * cos(w0) - 2 * sqrt(A) * alpha);
+ break;
+ case treble:
+ p->a0 = (A + 1) - (A - 1) * cos(w0) + 2 * sqrt(A) * alpha;
+ p->a1 = 2 * ((A - 1) - (A + 1) * cos(w0));
+ p->a2 = (A + 1) - (A - 1) * cos(w0) - 2 * sqrt(A) * alpha;
+ p->b0 = A * ((A + 1) + (A - 1) * cos(w0) + 2 * sqrt(A) * alpha);
+ p->b1 =-2 * A * ((A - 1) + (A + 1) * cos(w0));
+ p->b2 = A * ((A + 1) + (A - 1) * cos(w0) - 2 * sqrt(A) * alpha);
+ break;
+ case bandpass:
+ if (p->csg) {
+ p->a0 = 1 + alpha;
+ p->a1 = -2 * cos(w0);
+ p->a2 = 1 - alpha;
+ p->b0 = sin(w0) / 2;
+ p->b1 = 0;
+ p->b2 = -sin(w0) / 2;
+ } else {
+ p->a0 = 1 + alpha;
+ p->a1 = -2 * cos(w0);
+ p->a2 = 1 - alpha;
+ p->b0 = alpha;
+ p->b1 = 0;
+ p->b2 = -alpha;
+ }
+ break;
+ case bandreject:
+ p->a0 = 1 + alpha;
+ p->a1 = -2 * cos(w0);
+ p->a2 = 1 - alpha;
+ p->b0 = 1;
+ p->b1 = -2 * cos(w0);
+ p->b2 = 1;
+ break;
+ case lowpass:
+ if (p->poles == 1) {
+ p->a0 = 1;
+ p->a1 = -exp(-w0);
+ p->a2 = 0;
+ p->b0 = 1 + p->a1;
+ p->b1 = 0;
+ p->b2 = 0;
+ } else {
+ p->a0 = 1 + alpha;
+ p->a1 = -2 * cos(w0);
+ p->a2 = 1 - alpha;
+ p->b0 = (1 - cos(w0)) / 2;
+ p->b1 = 1 - cos(w0);
+ p->b2 = (1 - cos(w0)) / 2;
+ }
+ break;
+ case highpass:
+ if (p->poles == 1) {
+ p->a0 = 1;
+ p->a1 = -exp(-w0);
+ p->a2 = 0;
+ p->b0 = (1 - p->a1) / 2;
+ p->b1 = -p->b0;
+ p->b2 = 0;
+ } else {
+ p->a0 = 1 + alpha;
+ p->a1 = -2 * cos(w0);
+ p->a2 = 1 - alpha;
+ p->b0 = (1 + cos(w0)) / 2;
+ p->b1 = -(1 + cos(w0));
+ p->b2 = (1 + cos(w0)) / 2;
+ }
+ break;
+ case allpass:
+ p->a0 = 1 + alpha;
+ p->a1 = -2 * cos(w0);
+ p->a2 = 1 - alpha;
+ p->b0 = 1 - alpha;
+ p->b1 = -2 * cos(w0);
+ p->b2 = 1 + alpha;
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ p->a1 /= p->a0;
+ p->a2 /= p->a0;
+ p->b0 /= p->a0;
+ p->b1 /= p->a0;
+ p->b2 /= p->a0;
+
+ p->cache = av_realloc_f(p->cache, sizeof(ChanCache), inlink->channels);
+ if (!p->cache)
+ return AVERROR(ENOMEM);
+ memset(p->cache, 0, sizeof(ChanCache) * inlink->channels);
+
+ switch (inlink->format) {
+ case AV_SAMPLE_FMT_S16P: p->filter = biquad_s16; break;
+ case AV_SAMPLE_FMT_S32P: p->filter = biquad_s32; break;
+ case AV_SAMPLE_FMT_FLTP: p->filter = biquad_flt; break;
+ case AV_SAMPLE_FMT_DBLP: p->filter = biquad_dbl; break;
+ default: av_assert0(0);
+ }
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
+{
+ BiquadsContext *p = 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++)
+ p->filter(buf->extended_data[ch],
+ out_buf->extended_data[ch], nb_samples,
+ &p->cache[ch].i1, &p->cache[ch].i2,
+ &p->cache[ch].o1, &p->cache[ch].o2,
+ p->b0, p->b1, p->b2, p->a1, p->a2);
+
+ if (buf != out_buf)
+ av_frame_free(&buf);
+
+ return ff_filter_frame(outlink, out_buf);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ BiquadsContext *p = ctx->priv;
+
+ av_freep(&p->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 *p = ctx->priv; \
+ p->class = &name_##_class; \
+ p->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 25e7867..3dd0bcd 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
*/
@@ -168,16 +168,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 3035405..c3454c5 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);
@@ -291,10 +287,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 +318,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);
@@ -389,7 +391,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 +412,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 5b410fd..b3756e2 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_compand.c b/libavfilter/af_compand.c
index f21c861..4ca73c4 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,7 +104,7 @@ 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
};
@@ -145,14 +132,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 +147,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 +165,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 +195,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 +218,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 +228,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 +262,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 +281,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 +291,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 +303,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 +329,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 +354,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 +365,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 +398,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 +415,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 +435,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 +523,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 +542,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_earwax.c b/libavfilter/af_earwax.c
new file mode 100644
index 0000000..c310997
--- /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 0000000..5ff3786
--- /dev/null
+++ b/libavfilter/af_flanger.c
@@ -0,0 +1,241 @@
+/*
+ * 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
+ };
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_set_common_channel_layouts(ctx, 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 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 e684cb9..a1717c6 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;
- }
+ 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];
@@ -229,9 +221,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 +248,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());
@@ -479,6 +472,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 +507,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 0000000..2057e6d
--- /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 0000000..4ba77a7
--- /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 0000000..c419857
--- /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 fbe6105..d65d4bc 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 0000000..687d2e7
--- /dev/null
+++ b/libavfilter/af_silencedetect.c
@@ -0,0 +1,212 @@
+/*
+ * 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
+ };
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_set_common_channel_layouts(ctx, 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 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 0000000..02b64ce
--- /dev/null
+++ b/libavfilter/af_silenceremove.c
@@ -0,0 +1,479 @@
+/*
+ * 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
+ };
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_set_common_channel_layouts(ctx, 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 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 11d85a1..9900d22 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,39 +86,48 @@ 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 av_cold int init(AVFilterContext *ctx)
+static int set_expr(AVExpr **pexpr, const char *expr, void *log_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]);
+ 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;
+ 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);
+}
+
static int query_formats(AVFilterContext *ctx)
{
VolumeContext *vol = ctx->priv;
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,21 +136,19 @@ 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
}
};
- layouts = ff_all_channel_layouts();
+ layouts = ff_all_channel_counts();
if (!layouts)
return AVERROR(ENOMEM);
ff_set_common_channel_layouts(ctx, layouts);
@@ -185,8 +212,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;
@@ -221,6 +246,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 +285,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,8 +379,23 @@ 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)) {
@@ -335,6 +446,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 +476,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 6bd89ac..e78e042 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,
@@ -46,6 +69,11 @@ typedef struct VolumeContext {
const AVClass *class;
AVFloatDSPContext fdsp;
enum PrecisionType precision;
+ enum EvalMode eval_mode;
+ const char *volume_expr;
+ AVExpr *volume_pexpr;
+ double var_values[VAR_VARS_NB];
+
enum ReplayGainType replaygain;
double replaygain_preamp;
int replaygain_noclip;
diff --git a/libavfilter/af_volumedetect.c b/libavfilter/af_volumedetect.c
new file mode 100644
index 0000000..5de115e
--- /dev/null
+++ b/libavfilter/af_volumedetect.c
@@ -0,0 +1,159 @@
+/*
+ * 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);
+ ff_set_common_formats(ctx, formats);
+
+ return 0;
+}
+
+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 0000000..878e1f5
--- /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 67a298d..2352d44 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,210 @@ 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(COMPAND, compand, 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(COLORMATRIX, colormatrix, vf);
REGISTER_FILTER(COPY, copy, 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(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(EXTRACTPLANES, extractplanes, vf);
REGISTER_FILTER(FADE, fade, vf);
+ REGISTER_FILTER(FIELD, field, vf);
+ REGISTER_FILTER(FIELDMATCH, fieldmatch, vf);
REGISTER_FILTER(FIELDORDER, fieldorder, 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(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(MP, mp, 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(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(PSNR, psnr, vf);
+ REGISTER_FILTER(PULLUP, pullup, vf);
+ REGISTER_FILTER(REMOVELOGO, removelogo, 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(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(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(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);
+
+ /* 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 +257,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 44f547d..9b53d3f 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 0000000..aa34461
--- /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 b1a449c..28d4500 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 0000000..098a1dd
--- /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 0000000..68e1398
--- /dev/null
+++ b/libavfilter/asrc_sine.c
@@ -0,0 +1,223 @@
+/*
+ * 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 };
+
+ ff_set_common_formats (ctx, ff_make_format_list(sample_fmts));
+ 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 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 b332e9e..1e1d8e0 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 4684b6c..3335c96 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 0000000..e0d9015
--- /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(0, 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 0000000..d3d0e20
--- /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 0000000..f9ebc0f
--- /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;
+ enum VectorScopeMode 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 *p, unsigned x, unsigned y)
+{
+ const int linesize = p->outpicref->linesize[0];
+ uint8_t *dst;
+
+ if (p->zoom > 1) {
+ if (y >= p->h || x >= p->w)
+ return;
+ } else {
+ y = FFMIN(y, p->h - 1);
+ x = FFMIN(x, p->w - 1);
+ }
+
+ dst = &p->outpicref->data[0][y * linesize + x * 4];
+ dst[0] = FFMIN(dst[0] + p->contrast[0], 255);
+ dst[1] = FFMIN(dst[1] + p->contrast[1], 255);
+ dst[2] = FFMIN(dst[2] + p->contrast[2], 255);
+}
+
+static void fade(AudioVectorScopeContext *p)
+{
+ const int linesize = p->outpicref->linesize[0];
+ int i, j;
+
+ if (p->fade[0] || p->fade[1] || p->fade[2]) {
+ uint8_t *d = p->outpicref->data[0];
+ for (i = 0; i < p->h; i++) {
+ for (j = 0; j < p->w*4; j+=4) {
+ d[j+0] = FFMAX(d[j+0] - p->fade[0], 0);
+ d[j+1] = FFMAX(d[j+1] - p->fade[1], 0);
+ d[j+2] = FFMAX(d[j+2] - p->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 *p = ctx->priv;
+ int nb_samples;
+
+ nb_samples = FFMAX(1024, ((double)inlink->sample_rate / av_q2d(p->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 *p = outlink->src->priv;
+
+ outlink->w = p->w;
+ outlink->h = p->h;
+ outlink->sample_aspect_ratio = (AVRational){1,1};
+ outlink->frame_rate = p->frame_rate;
+
+ p->hw = p->w / 2;
+ p->hh = p->h / 2;
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AudioVectorScopeContext *p = ctx->priv;
+ const int hw = p->hw;
+ const int hh = p->hh;
+ unsigned x, y;
+ const double zoom = p->zoom;
+ int i;
+
+ if (!p->outpicref || p->outpicref->width != outlink->w ||
+ p->outpicref->height != outlink->h) {
+ av_frame_free(&p->outpicref);
+ p->outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!p->outpicref) {
+ av_frame_free(&insamples);
+ return AVERROR(ENOMEM);
+ }
+
+ for (i = 0; i < outlink->h; i++)
+ memset(p->outpicref->data[0] + i * p->outpicref->linesize[0], 0, outlink->w * 4);
+ }
+ p->outpicref->pts = insamples->pts;
+
+ fade(p);
+
+ 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 (p->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(p, 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 (p->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(p, x, y);
+ }
+ break;
+ }
+
+ av_frame_free(&insamples);
+
+ return ff_filter_frame(outlink, av_frame_clone(p->outpicref));
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ AudioVectorScopeContext *p = ctx->priv;
+
+ av_frame_free(&p->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 0000000..266bb36
--- /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_free(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 0000000..e650f74
--- /dev/null
+++ b/libavfilter/avf_showcqt.c
@@ -0,0 +1,807 @@
+/*
+ * 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 */
+ 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 },
+ { "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(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;
+ float g = 1.0f / s->gamma;
+ 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]);
+ result[x][3] = result[x][1];
+ result[x][0] = 255.0f * powf(FFMIN(1.0f,result[x][0]), g);
+ result[x][1] = 255.0f * powf(FFMIN(1.0f,result[x][1]), g);
+ result[x][2] = 255.0f * powf(FFMIN(1.0f,result[x][2]), g);
+ }
+
+ 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 0000000..24116da
--- /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
+ enum DisplayMode mode; ///< channel display mode
+ enum ColorMode color_mode; ///< display color scheme
+ enum DisplayScale 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
+ enum WindowFunc 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 0000000..fa34a52
--- /dev/null
+++ b/libavfilter/avf_showwaves.c
@@ -0,0 +1,333 @@
+/*
+ * 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/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,
+};
+
+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;
+ enum ShowWavesMode mode;
+ int split_channels;
+ void (*draw_sample)(uint8_t *buf, int height, int linesize,
+ int16_t sample, int16_t *prev_y, int intensity);
+} 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);
+}
+
+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 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)
+ push_frame(outlink);
+ return ret;
+}
+
+#define MAX_INT16 ((1<<15) -1)
+
+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, MAX_INT16);
+ 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, MAX_INT16);
+ 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, MAX_INT16);
+ 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, UINT16_MAX);
+ const int start = (height - h) / 2;
+ const int end = start + h;
+ for (k = start; k < end; k++)
+ buf[k * linesize] += intensity;
+}
+
+static int 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;
+ int linesize = outpicref ? outpicref->linesize[0] : 0;
+ 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++) {
+ if (!showwaves->outpicref) {
+ showwaves->outpicref = outpicref =
+ ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!outpicref)
+ return AVERROR(ENOMEM);
+ outpicref->width = outlink->w;
+ outpicref->height = outlink->h;
+ outpicref->pts = insamples->pts +
+ av_rescale_q((p - (int16_t *)insamples->data[0]) / nb_channels,
+ (AVRational){ 1, inlink->sample_rate },
+ outlink->time_base);
+ linesize = outpicref->linesize[0];
+ for (j = 0; j < outlink->h; j++)
+ memset(outpicref->data[0] + j * linesize, 0, outlink->w);
+ }
+ for (j = 0; j < nb_channels; j++) {
+ uint8_t *buf = outpicref->data[0] + showwaves->buf_idx;
+ 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;
+ }
+
+ av_frame_free(&insamples);
+ return ret;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ ShowWavesContext *showwaves = ctx->priv;
+
+ 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;
+}
+
+static const AVFilterPad showwaves_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = 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,
+};
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 4098973..963f5e6 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,82 @@
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
-#include "video.h"
+
+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_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
+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);
+}
+
+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 +119,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 +136,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 +153,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 +224,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 +233,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 +263,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 (inlink && !link->frame_rate.num && !link->frame_rate.den)
+ link->frame_rate = inlink->frame_rate;
- if (link->src->nb_inputs) {
+ 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 +313,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_dlog(ctx,
- "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 +327,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_dlog(ctx,
- "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,13 +339,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 -1;
+ 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)
@@ -275,7 +386,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
@@ -289,18 +490,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;
}
@@ -332,10 +546,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)
@@ -350,10 +564,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;
@@ -362,18 +582,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,
@@ -425,22 +647,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;
}
@@ -490,13 +712,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);
@@ -519,41 +744,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_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value);
- av_dict_set(options, o->name, val, 0);
+ 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
@@ -590,7 +867,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);
@@ -612,51 +891,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);
@@ -678,22 +926,58 @@ 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);
+#if CONFIG_MP_FILTER
+ if (!strcmp(filter->filter->name, "mp")) {
+ char *escaped;
+
+ if (!strncmp(args, "filter=", 7))
+ args += 7;
+ ret = av_escape(&escaped, args, ":=", AV_ESCAPE_MODE_BACKSLASH, 0);
+ if (ret < 0) {
+ av_log(filter, AV_LOG_ERROR, "Unable to escape MPlayer filters arg '%s'\n", args);
+ goto fail;
+ }
+ ret = process_options(filter, &options, escaped);
+ av_free(escaped);
+ } else
+#endif
+ ret = process_options(filter, &options, args);
if (ret < 0)
goto fail;
}
@@ -730,15 +1014,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;
@@ -747,6 +1036,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);
@@ -769,7 +1059,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:
@@ -787,7 +1077,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);
@@ -795,6 +1112,78 @@ 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")) {
+ 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 1b42086..b5220b9 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,16 @@
* @{
*/
+#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 "libavcodec/avcodec.h"
-
-#include <stddef.h>
#include "libavfilter/version.h"
@@ -61,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;
@@ -114,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
@@ -122,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;
/**
@@ -135,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;
/**
@@ -186,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.
@@ -229,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.
@@ -252,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;
@@ -278,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.
*/
@@ -286,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.
*/
@@ -309,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);
@@ -329,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.
*/
@@ -337,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);
@@ -413,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
@@ -550,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;
/**
@@ -561,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
@@ -598,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;
@@ -607,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
};
/**
@@ -629,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
@@ -652,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;
@@ -683,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;
};
/**
@@ -698,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
@@ -719,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
@@ -740,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);
@@ -758,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);
@@ -941,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
@@ -1000,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;
/**
@@ -1019,19 +1260,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
/**
@@ -1065,11 +1308,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);
@@ -1115,9 +1373,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
@@ -1127,6 +1395,43 @@ 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.
+ *
+ * @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.
@@ -1141,21 +1446,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,
@@ -1163,6 +1460,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 0fc385c..a859ecb 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 ff_avfilter_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,131 @@ int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)
return ret;
if ((ret = graph_config_links(graphctx, log_ctx)))
return ret;
+ if ((ret = ff_avfilter_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;
+
+ 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;
+
+ 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 47174ef..b31d581 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 0000000..8be6247
--- /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 0000000..be9b2e6
--- /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 0000000..eb73154
--- /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 fd0b18f..0327952 100644
--- a/libavfilter/buffer.c
+++ b/libavfilter/buffer.c
@@ -1,32 +1,39 @@
/*
- * 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)
@@ -35,19 +42,32 @@ void ff_avfilter_default_free_buffer(AVFilterBuffer *ptr)
av_free(ptr);
}
+static void 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);
+ memcpy(dst->qp_table, src->qp_table, qsize);
+ }
+}
+
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 +77,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 +99,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 +123,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 +150,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 0000000..f5e5df2
--- /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 2894a5b..525f97b 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,119 @@
#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 (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 +166,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 +181,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 +194,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 +274,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 +288,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 +314,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 +329,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 +576,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 +590,6 @@ static const AVFilterPad avfilter_asink_abuffer_inputs[] = {
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.filter_frame = filter_frame,
- .needs_fifo = 1
},
{ NULL }
};
@@ -244,9 +597,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 83a8bd9..24cd2fe 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 00e28f8..27d3db0 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(0, 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_frame_unref(frame); \
ret = AVERROR(ENOMEM); \
@@ -224,7 +271,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);
@@ -241,7 +288,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);
@@ -250,41 +297,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 */
@@ -294,48 +347,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);
}
@@ -345,9 +409,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;
}
@@ -360,8 +426,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)
@@ -383,7 +448,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:
@@ -404,14 +471,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;
}
@@ -419,18 +487,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)
@@ -457,7 +523,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,
@@ -465,6 +530,7 @@ AVFilter ff_vsrc_buffer = {
.inputs = NULL,
.outputs = avfilter_vsrc_buffer_outputs,
+ .priv_class = &buffer_class,
};
static const AVFilterPad avfilter_asrc_abuffer_outputs[] = {
@@ -482,7 +548,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,
@@ -490,4 +555,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 0ca4d96..ea34c04 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 0000000..becd6c2
--- /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 0000000..2821248
--- /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 0000000..5b0a241
--- /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 0000000..dd45d6f
--- /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 e837760..4437c2c 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,29 +26,49 @@
#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;
@@ -70,7 +93,7 @@ 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);
memset(line[plane], dst_color[plane], line_size);
}
@@ -89,11 +112,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 +134,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 73f482e..5ffffe7 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 0000000..45f6810
--- /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 0000000..0ec0ea7
--- /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 0000000..c18ae79
--- /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 0000000..95401cf
--- /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 0000000..188ce91
--- /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;
+ enum mode 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 0000000..546a940
--- /dev/null
+++ b/libavfilter/f_select.c
@@ -0,0 +1,507 @@
+/*
+ * 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 {
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_NONE
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ }
+ 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 0000000..c30f49f
--- /dev/null
+++ b/libavfilter/f_sendcmd.c
@@ -0,0 +1,576 @@
+/*
+ * 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;
+
+ 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) {
+ av_log(ctx, AV_LOG_ERROR,
+ "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;
+
+ 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_free(cmd->target);
+ av_free(cmd->command);
+ av_free(cmd->arg);
+ }
+ av_free(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 0000000..d6c3c65
--- /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 a414585..e477cff 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 40649c7..c1025b9 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,17 @@ int main(int argc, char **argv)
AVFilterGraph *graph_ctx;
const char *filter_name;
const char *filter_args = NULL;
- int i, j;
+ int i;
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 */
@@ -74,12 +115,12 @@ int main(int argc, char **argv)
/* create a link for each of the input pads */
for (i = 0; i < filter_ctx->nb_inputs; i++) {
AVFilterLink *link = av_mallocz(sizeof(AVFilterLink));
- 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++) {
AVFilterLink *link = av_mallocz(sizeof(AVFilterLink));
- 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;
}
@@ -88,23 +129,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);
avfilter_free(filter_ctx);
avfilter_graph_free(&graph_ctx);
diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index 24a4fab..8160429 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,26 +255,58 @@ 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 COPY_INT_LIST(list_copy, list, type) { \
+ int count = 0; \
+ if (list) \
+ for (count = 0; list[count] != -1; count++) \
+ ; \
+ list_copy = av_calloc(count+1, sizeof(type)); \
+ if (list_copy) { \
+ memcpy(list_copy, list, sizeof(type) * count); \
+ list_copy[count] = -1; \
+ } \
+}
+
+#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_free(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));
+AVFilterChannelLayouts *avfilter_make_format64_list(const int64_t *fmts)
+{
+ MAKE_FORMAT_LIST(AVFilterChannelLayouts,
+ channel_layouts, nb_channel_layouts);
if (count)
- formats->formats = av_malloc(sizeof(*formats->formats) * count);
- formats->nb_formats = count;
- memcpy(formats->formats, fmts, sizeof(*formats->formats) * count);
+ memcpy(formats->channel_layouts, fmts,
+ sizeof(*formats->channel_layouts) * count);
return formats;
}
@@ -193,17 +325,19 @@ do { \
\
(*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)
@@ -227,12 +361,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);
@@ -248,6 +392,18 @@ 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;
+}
+
+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;
}
@@ -338,13 +494,13 @@ void ff_formats_changeref(AVFilterFormats **oldref, AVFilterFormats **newref)
int count = 0, i; \
\
for (i = 0; i < ctx->nb_inputs; i++) { \
- if (ctx->inputs[i]) { \
+ if (ctx->inputs[i] && !ctx->inputs[i]->out_fmts) { \
ref(fmts, &ctx->inputs[i]->out_fmts); \
count++; \
} \
} \
for (i = 0; i < ctx->nb_outputs; i++) { \
- if (ctx->outputs[i]) { \
+ if (ctx->outputs[i] && !ctx->outputs[i]->in_fmts) { \
ref(fmts, &ctx->outputs[i]->in_fmts); \
count++; \
} \
@@ -382,7 +538,8 @@ void ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
ff_formats_ref, formats);
}
-int ff_default_query_formats(AVFilterContext *ctx)
+static int default_query_formats_common(AVFilterContext *ctx,
+ AVFilterChannelLayouts *(layouts)(void))
{
enum AVMediaType type = ctx->inputs && ctx->inputs [0] ? ctx->inputs [0]->type :
ctx->outputs && ctx->outputs[0] ? ctx->outputs[0]->type :
@@ -390,9 +547,122 @@ int ff_default_query_formats(AVFilterContext *ctx)
ff_set_common_formats(ctx, ff_all_formats(type));
if (type == AVMEDIA_TYPE_AUDIO) {
- ff_set_common_channel_layouts(ctx, ff_all_channel_layouts());
+ ff_set_common_channel_layouts(ctx, layouts());
ff_set_common_samplerates(ctx, ff_all_samplerates());
}
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 2e44792..468eac8 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,12 +123,21 @@ 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.
@@ -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.
diff --git a/libavfilter/framesync.c b/libavfilter/framesync.c
new file mode 100644
index 0000000..12db50c
--- /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 0000000..2072781
--- /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 0000000..bee9c00
--- /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 0000000..37ea2aa
--- /dev/null
+++ b/libavfilter/generate_wave_table.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+
+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 f6f7311..eb1f1eb 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 0000000..3d702c6
--- /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 e20dd62..7e25282 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
*/
@@ -89,17 +89,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);
@@ -118,8 +118,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;
}
@@ -131,10 +133,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;
}
/**
@@ -151,7 +154,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)
@@ -384,7 +387,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;
@@ -399,18 +402,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++;
@@ -425,16 +427,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);
@@ -448,6 +451,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)
@@ -509,4 +513,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/internal.h b/libavfilter/internal.h
index 6a752dc..308b115 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,32 @@
#include "libavutil/internal.h"
#include "avfilter.h"
+#include "avfiltergraph.h"
+#include "formats.h"
#include "thread.h"
#include "version.h"
+#include "video.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 +72,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 +80,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 +169,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_dlog(NULL, "%-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);
+
+/**
+ * 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_dlog_link(void *ctx, AVFilterLink *link, int end);
+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 +258,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 +309,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 +346,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
diff --git a/libavfilter/lavfutils.c b/libavfilter/lavfutils.c
new file mode 100644
index 0000000..80310d2
--- /dev/null
+++ b/libavfilter/lavfutils.c
@@ -0,0 +1,104 @@
+/*
+ * 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;
+
+ 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;
+ }
+
+ if ((ret = avcodec_open2(codec_ctx, codec, NULL)) < 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_freep(&frame);
+
+ 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 0000000..2d5308f
--- /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/libmpcodecs/av_helpers.h b/libavfilter/libmpcodecs/av_helpers.h
new file mode 100644
index 0000000..90b67d5
--- /dev/null
+++ b/libavfilter/libmpcodecs/av_helpers.h
@@ -0,0 +1,27 @@
+/*
+ * Generic libav* helpers
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_AV_HELPERS_H
+#define MPLAYER_AV_HELPERS_H
+
+void ff_init_avcodec(void);
+void ff_init_avformat(void);
+
+#endif /* MPLAYER_AV_HELPERS_H */
diff --git a/libavfilter/libmpcodecs/cpudetect.h b/libavfilter/libmpcodecs/cpudetect.h
new file mode 100644
index 0000000..710f6e6
--- /dev/null
+++ b/libavfilter/libmpcodecs/cpudetect.h
@@ -0,0 +1,60 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_CPUDETECT_H
+#define MPLAYER_CPUDETECT_H
+
+#define CPUTYPE_I386 3
+#define CPUTYPE_I486 4
+#define CPUTYPE_I586 5
+#define CPUTYPE_I686 6
+
+#include "libavutil/x86_cpu.h"
+
+typedef struct cpucaps_s {
+ int cpuType;
+ int cpuModel;
+ int cpuStepping;
+ int hasMMX;
+ int hasMMX2;
+ int has3DNow;
+ int has3DNowExt;
+ int hasSSE;
+ int hasSSE2;
+ int hasSSE3;
+ int hasSSSE3;
+ int hasSSE4;
+ int hasSSE42;
+ int hasSSE4a;
+ int hasAVX;
+ int isX86;
+ unsigned cl_size; /* size of cache line */
+ int hasAltiVec;
+ int hasTSC;
+} CpuCaps;
+
+extern CpuCaps ff_gCpuCaps;
+
+void ff_do_cpuid(unsigned int ax, unsigned int *p);
+
+void ff_GetCpuCaps(CpuCaps *caps);
+
+/* returned value is malloc()'ed so free() it after use */
+char *ff_GetCpuFriendlyName(unsigned int regs[], unsigned int regs2[]);
+
+#endif /* MPLAYER_CPUDETECT_H */
diff --git a/libavfilter/libmpcodecs/img_format.c b/libavfilter/libmpcodecs/img_format.c
new file mode 100644
index 0000000..dd07f00
--- /dev/null
+++ b/libavfilter/libmpcodecs/img_format.c
@@ -0,0 +1,244 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "img_format.h"
+#include "stdio.h"
+#include "libavutil/bswap.h"
+
+const char *ff_vo_format_name(int format)
+{
+ static char unknown_format[20];
+ switch(format)
+ {
+ case IMGFMT_RGB1: return "RGB 1-bit";
+ case IMGFMT_RGB4: return "RGB 4-bit";
+ case IMGFMT_RG4B: return "RGB 4-bit per byte";
+ case IMGFMT_RGB8: return "RGB 8-bit";
+ case IMGFMT_RGB12: return "RGB 12-bit";
+ case IMGFMT_RGB15: return "RGB 15-bit";
+ case IMGFMT_RGB16: return "RGB 16-bit";
+ case IMGFMT_RGB24: return "RGB 24-bit";
+// case IMGFMT_RGB32: return "RGB 32-bit";
+ case IMGFMT_RGB48LE: return "RGB 48-bit LE";
+ case IMGFMT_RGB48BE: return "RGB 48-bit BE";
+ case IMGFMT_RGB64LE: return "RGB 64-bit LE";
+ case IMGFMT_RGB64BE: return "RGB 64-bit BE";
+ case IMGFMT_BGR1: return "BGR 1-bit";
+ case IMGFMT_BGR4: return "BGR 4-bit";
+ case IMGFMT_BG4B: return "BGR 4-bit per byte";
+ case IMGFMT_BGR8: return "BGR 8-bit";
+ case IMGFMT_BGR12: return "BGR 12-bit";
+ case IMGFMT_BGR15: return "BGR 15-bit";
+ case IMGFMT_BGR16: return "BGR 16-bit";
+ case IMGFMT_BGR24: return "BGR 24-bit";
+// case IMGFMT_BGR32: return "BGR 32-bit";
+ case IMGFMT_ABGR: return "ABGR";
+ case IMGFMT_BGRA: return "BGRA";
+ case IMGFMT_ARGB: return "ARGB";
+ case IMGFMT_RGBA: return "RGBA";
+ case IMGFMT_XYZ12LE: return "XYZ 36-bit LE";
+ case IMGFMT_XYZ12BE: return "XYZ 36-bit BE";
+ case IMGFMT_GBR24P: return "Planar GBR 24-bit";
+ case IMGFMT_GBR12P: return "Planar GBR 36-bit";
+ case IMGFMT_GBR14P: return "Planar GBR 42-bit";
+ case IMGFMT_YVU9: return "Planar YVU9";
+ case IMGFMT_IF09: return "Planar IF09";
+ case IMGFMT_YV12: return "Planar YV12";
+ case IMGFMT_I420: return "Planar I420";
+ case IMGFMT_IYUV: return "Planar IYUV";
+ case IMGFMT_CLPL: return "Planar CLPL";
+ case IMGFMT_Y800: return "Planar Y800";
+ case IMGFMT_Y8: return "Planar Y8";
+ case IMGFMT_Y8A: return "Planar Y8 with alpha";
+ case IMGFMT_Y16_LE: return "Planar Y16 little-endian";
+ case IMGFMT_Y16_BE: return "Planar Y16 big-endian";
+ case IMGFMT_420P16_LE: return "Planar 420P 16-bit little-endian";
+ case IMGFMT_420P16_BE: return "Planar 420P 16-bit big-endian";
+ case IMGFMT_420P14_LE: return "Planar 420P 14-bit little-endian";
+ case IMGFMT_420P14_BE: return "Planar 420P 14-bit big-endian";
+ case IMGFMT_420P12_LE: return "Planar 420P 12-bit little-endian";
+ case IMGFMT_420P12_BE: return "Planar 420P 12-bit big-endian";
+ case IMGFMT_420P10_LE: return "Planar 420P 10-bit little-endian";
+ case IMGFMT_420P10_BE: return "Planar 420P 10-bit big-endian";
+ case IMGFMT_420P9_LE: return "Planar 420P 9-bit little-endian";
+ case IMGFMT_420P9_BE: return "Planar 420P 9-bit big-endian";
+ case IMGFMT_422P16_LE: return "Planar 422P 16-bit little-endian";
+ case IMGFMT_422P16_BE: return "Planar 422P 16-bit big-endian";
+ case IMGFMT_422P14_LE: return "Planar 422P 14-bit little-endian";
+ case IMGFMT_422P14_BE: return "Planar 422P 14-bit big-endian";
+ case IMGFMT_422P12_LE: return "Planar 422P 12-bit little-endian";
+ case IMGFMT_422P12_BE: return "Planar 422P 12-bit big-endian";
+ case IMGFMT_422P10_LE: return "Planar 422P 10-bit little-endian";
+ case IMGFMT_422P10_BE: return "Planar 422P 10-bit big-endian";
+ case IMGFMT_422P9_LE: return "Planar 422P 9-bit little-endian";
+ case IMGFMT_422P9_BE: return "Planar 422P 9-bit big-endian";
+ case IMGFMT_444P16_LE: return "Planar 444P 16-bit little-endian";
+ case IMGFMT_444P16_BE: return "Planar 444P 16-bit big-endian";
+ case IMGFMT_444P14_LE: return "Planar 444P 14-bit little-endian";
+ case IMGFMT_444P14_BE: return "Planar 444P 14-bit big-endian";
+ case IMGFMT_444P12_LE: return "Planar 444P 12-bit little-endian";
+ case IMGFMT_444P12_BE: return "Planar 444P 12-bit big-endian";
+ case IMGFMT_444P10_LE: return "Planar 444P 10-bit little-endian";
+ case IMGFMT_444P10_BE: return "Planar 444P 10-bit big-endian";
+ case IMGFMT_444P9_LE: return "Planar 444P 9-bit little-endian";
+ case IMGFMT_444P9_BE: return "Planar 444P 9-bit big-endian";
+ case IMGFMT_420A: return "Planar 420P with alpha";
+ case IMGFMT_444P: return "Planar 444P";
+ case IMGFMT_444A: return "Planar 444P with alpha";
+ case IMGFMT_422P: return "Planar 422P";
+ case IMGFMT_422A: return "Planar 422P with alpha";
+ case IMGFMT_411P: return "Planar 411P";
+ case IMGFMT_440P: return "Planar 440P";
+ case IMGFMT_NV12: return "Planar NV12";
+ case IMGFMT_NV21: return "Planar NV21";
+ case IMGFMT_HM12: return "Planar NV12 Macroblock";
+ case IMGFMT_IUYV: return "Packed IUYV";
+ case IMGFMT_IY41: return "Packed IY41";
+ case IMGFMT_IYU1: return "Packed IYU1";
+ case IMGFMT_IYU2: return "Packed IYU2";
+ case IMGFMT_UYVY: return "Packed UYVY";
+ case IMGFMT_UYNV: return "Packed UYNV";
+ case IMGFMT_cyuv: return "Packed CYUV";
+ case IMGFMT_Y422: return "Packed Y422";
+ case IMGFMT_YUY2: return "Packed YUY2";
+ case IMGFMT_YUNV: return "Packed YUNV";
+ case IMGFMT_YVYU: return "Packed YVYU";
+ case IMGFMT_Y41P: return "Packed Y41P";
+ case IMGFMT_Y211: return "Packed Y211";
+ case IMGFMT_Y41T: return "Packed Y41T";
+ case IMGFMT_Y42T: return "Packed Y42T";
+ case IMGFMT_V422: return "Packed V422";
+ case IMGFMT_V655: return "Packed V655";
+ case IMGFMT_CLJR: return "Packed CLJR";
+ case IMGFMT_YUVP: return "Packed YUVP";
+ case IMGFMT_UYVP: return "Packed UYVP";
+ case IMGFMT_MPEGPES: return "Mpeg PES";
+ case IMGFMT_ZRMJPEGNI: return "Zoran MJPEG non-interlaced";
+ case IMGFMT_ZRMJPEGIT: return "Zoran MJPEG top field first";
+ case IMGFMT_ZRMJPEGIB: return "Zoran MJPEG bottom field first";
+ case IMGFMT_XVMC_MOCO_MPEG2: return "MPEG1/2 Motion Compensation";
+ case IMGFMT_XVMC_IDCT_MPEG2: return "MPEG1/2 Motion Compensation and IDCT";
+ case IMGFMT_VDPAU_MPEG1: return "MPEG1 VDPAU acceleration";
+ case IMGFMT_VDPAU_MPEG2: return "MPEG2 VDPAU acceleration";
+ case IMGFMT_VDPAU_H264: return "H.264 VDPAU acceleration";
+ case IMGFMT_VDPAU_MPEG4: return "MPEG-4 Part 2 VDPAU acceleration";
+ case IMGFMT_VDPAU_WMV3: return "WMV3 VDPAU acceleration";
+ case IMGFMT_VDPAU_VC1: return "VC1 VDPAU acceleration";
+ }
+ snprintf(unknown_format,20,"Unknown 0x%04x",format);
+ return unknown_format;
+}
+
+int ff_mp_get_chroma_shift(int format, int *x_shift, int *y_shift, int *component_bits)
+{
+ int xs = 0, ys = 0;
+ int bpp;
+ int err = 0;
+ int bits = 8;
+ if ((format & 0xff0000f0) == 0x34000050)
+ format = av_bswap32(format);
+ if ((format & 0xf00000ff) == 0x50000034) {
+ switch (format >> 24) {
+ case 0x50:
+ break;
+ case 0x51:
+ bits = 16;
+ break;
+ case 0x52:
+ bits = 10;
+ break;
+ case 0x53:
+ bits = 9;
+ break;
+ default:
+ err = 1;
+ break;
+ }
+ switch (format & 0x00ffffff) {
+ case 0x00343434: // 444
+ xs = 0;
+ ys = 0;
+ break;
+ case 0x00323234: // 422
+ xs = 1;
+ ys = 0;
+ break;
+ case 0x00303234: // 420
+ xs = 1;
+ ys = 1;
+ break;
+ case 0x00313134: // 411
+ xs = 2;
+ ys = 0;
+ break;
+ case 0x00303434: // 440
+ xs = 0;
+ ys = 1;
+ break;
+ default:
+ err = 1;
+ break;
+ }
+ } else switch (format) {
+ case IMGFMT_444A:
+ xs = 0;
+ ys = 0;
+ break;
+ case IMGFMT_422A:
+ xs = 1;
+ ys = 0;
+ break;
+ case IMGFMT_420A:
+ case IMGFMT_I420:
+ case IMGFMT_IYUV:
+ case IMGFMT_YV12:
+ xs = 1;
+ ys = 1;
+ break;
+ case IMGFMT_IF09:
+ case IMGFMT_YVU9:
+ xs = 2;
+ ys = 2;
+ break;
+ case IMGFMT_Y8:
+ case IMGFMT_Y800:
+ xs = 31;
+ ys = 31;
+ break;
+ case IMGFMT_NV12:
+ case IMGFMT_NV21:
+ xs = 1;
+ ys = 1;
+ // TODO: allowing this though currently breaks
+ // things all over the place.
+ err = 1;
+ break;
+ default:
+ err = 1;
+ break;
+ }
+ if (x_shift) *x_shift = xs;
+ if (y_shift) *y_shift = ys;
+ if (component_bits) *component_bits = bits;
+ bpp = 8 + ((16 >> xs) >> ys);
+ if (format == IMGFMT_420A || format == IMGFMT_422A || format == IMGFMT_444A)
+ bpp += 8;
+ bpp *= (bits + 7) >> 3;
+ return err ? 0 : bpp;
+}
diff --git a/libavfilter/libmpcodecs/img_format.h b/libavfilter/libmpcodecs/img_format.h
new file mode 100644
index 0000000..b5c0b90
--- /dev/null
+++ b/libavfilter/libmpcodecs/img_format.h
@@ -0,0 +1,309 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_IMG_FORMAT_H
+#define MPLAYER_IMG_FORMAT_H
+
+#include "config.h"
+
+/* RGB/BGR Formats */
+
+#define IMGFMT_RGB_MASK 0xFFFFFF00
+#define IMGFMT_RGB (('R'<<24)|('G'<<16)|('B'<<8))
+#define IMGFMT_RGB1 (IMGFMT_RGB|1)
+#define IMGFMT_RGB4 (IMGFMT_RGB|4)
+#define IMGFMT_RGB4_CHAR (IMGFMT_RGB|4|128) // RGB4 with 1 pixel per byte
+#define IMGFMT_RGB8 (IMGFMT_RGB|8)
+#define IMGFMT_RGB12 (IMGFMT_RGB|12)
+#define IMGFMT_RGB15 (IMGFMT_RGB|15)
+#define IMGFMT_RGB16 (IMGFMT_RGB|16)
+#define IMGFMT_RGB24 (IMGFMT_RGB|24)
+#define IMGFMT_RGB32 (IMGFMT_RGB|32)
+#define IMGFMT_RGB48LE (IMGFMT_RGB|48)
+#define IMGFMT_RGB48BE (IMGFMT_RGB|48|128)
+#define IMGFMT_RGB64LE (IMGFMT_RGB|64)
+#define IMGFMT_RGB64BE (IMGFMT_RGB|64|128)
+
+#define IMGFMT_BGR_MASK 0xFFFFFF00
+#define IMGFMT_BGR (('B'<<24)|('G'<<16)|('R'<<8))
+#define IMGFMT_BGR1 (IMGFMT_BGR|1)
+#define IMGFMT_BGR4 (IMGFMT_BGR|4)
+#define IMGFMT_BGR4_CHAR (IMGFMT_BGR|4|128) // BGR4 with 1 pixel per byte
+#define IMGFMT_BGR8 (IMGFMT_BGR|8)
+#define IMGFMT_BGR12 (IMGFMT_BGR|12)
+#define IMGFMT_BGR15 (IMGFMT_BGR|15)
+#define IMGFMT_BGR16 (IMGFMT_BGR|16)
+#define IMGFMT_BGR24 (IMGFMT_BGR|24)
+#define IMGFMT_BGR32 (IMGFMT_BGR|32)
+
+#define IMGFMT_XYZ_MASK 0xFFFFFF00
+#define IMGFMT_XYZ (('X'<<24)|('Y'<<16)|('Z'<<8))
+#define IMGFMT_XYZ12LE (IMGFMT_XYZ|12)
+#define IMGFMT_XYZ12BE (IMGFMT_XYZ|12|128)
+
+#define IMGFMT_GBR24P (('G'<<24)|('B'<<16)|('R'<<8)|24)
+#define IMGFMT_GBR12PLE (('G'<<24)|('B'<<16)|('R'<<8)|36)
+#define IMGFMT_GBR12PBE (('G'<<24)|('B'<<16)|('R'<<8)|36|128)
+#define IMGFMT_GBR14PLE (('G'<<24)|('B'<<16)|('R'<<8)|42)
+#define IMGFMT_GBR14PBE (('G'<<24)|('B'<<16)|('R'<<8)|42|128)
+
+#if HAVE_BIGENDIAN
+#define IMGFMT_ABGR IMGFMT_RGB32
+#define IMGFMT_BGRA (IMGFMT_RGB32|128)
+#define IMGFMT_ARGB IMGFMT_BGR32
+#define IMGFMT_RGBA (IMGFMT_BGR32|128)
+#define IMGFMT_RGB64NE IMGFMT_RGB64BE
+#define IMGFMT_RGB48NE IMGFMT_RGB48BE
+#define IMGFMT_RGB12BE IMGFMT_RGB12
+#define IMGFMT_RGB12LE (IMGFMT_RGB12|128)
+#define IMGFMT_RGB15BE IMGFMT_RGB15
+#define IMGFMT_RGB15LE (IMGFMT_RGB15|128)
+#define IMGFMT_RGB16BE IMGFMT_RGB16
+#define IMGFMT_RGB16LE (IMGFMT_RGB16|128)
+#define IMGFMT_BGR12BE IMGFMT_BGR12
+#define IMGFMT_BGR12LE (IMGFMT_BGR12|128)
+#define IMGFMT_BGR15BE IMGFMT_BGR15
+#define IMGFMT_BGR15LE (IMGFMT_BGR15|128)
+#define IMGFMT_BGR16BE IMGFMT_BGR16
+#define IMGFMT_BGR16LE (IMGFMT_BGR16|128)
+#define IMGFMT_XYZ12 IMGFMT_XYZ12BE
+#define IMGFMT_GBR12P IMGFMT_GBR12PBE
+#define IMGFMT_GBR14P IMGFMT_GBR14PBE
+#else
+#define IMGFMT_ABGR (IMGFMT_BGR32|128)
+#define IMGFMT_BGRA IMGFMT_BGR32
+#define IMGFMT_ARGB (IMGFMT_RGB32|128)
+#define IMGFMT_RGBA IMGFMT_RGB32
+#define IMGFMT_RGB64NE IMGFMT_RGB64LE
+#define IMGFMT_RGB48NE IMGFMT_RGB48LE
+#define IMGFMT_RGB12BE (IMGFMT_RGB12|128)
+#define IMGFMT_RGB12LE IMGFMT_RGB12
+#define IMGFMT_RGB15BE (IMGFMT_RGB15|128)
+#define IMGFMT_RGB15LE IMGFMT_RGB15
+#define IMGFMT_RGB16BE (IMGFMT_RGB16|128)
+#define IMGFMT_RGB16LE IMGFMT_RGB16
+#define IMGFMT_BGR12BE (IMGFMT_BGR12|128)
+#define IMGFMT_BGR12LE IMGFMT_BGR12
+#define IMGFMT_BGR15BE (IMGFMT_BGR15|128)
+#define IMGFMT_BGR15LE IMGFMT_BGR15
+#define IMGFMT_BGR16BE (IMGFMT_BGR16|128)
+#define IMGFMT_BGR16LE IMGFMT_BGR16
+#define IMGFMT_XYZ12 IMGFMT_XYZ12LE
+#define IMGFMT_GBR12P IMGFMT_GBR12PLE
+#define IMGFMT_GBR14P IMGFMT_GBR14PLE
+#endif
+
+/* old names for compatibility */
+#define IMGFMT_RG4B IMGFMT_RGB4_CHAR
+#define IMGFMT_BG4B IMGFMT_BGR4_CHAR
+
+#define IMGFMT_IS_RGB(fmt) (((fmt)&IMGFMT_RGB_MASK)==IMGFMT_RGB)
+#define IMGFMT_IS_BGR(fmt) (((fmt)&IMGFMT_BGR_MASK)==IMGFMT_BGR)
+#define IMGFMT_IS_XYZ(fmt) (((fmt)&IMGFMT_XYZ_MASK)==IMGFMT_XYZ)
+
+#define IMGFMT_RGB_DEPTH(fmt) ((fmt)&0x7F)
+#define IMGFMT_BGR_DEPTH(fmt) ((fmt)&0x7F)
+#define IMGFMT_XYZ_DEPTH(fmt) ((fmt)&0x7F)
+
+
+/* Planar YUV Formats */
+
+#define IMGFMT_YVU9 0x39555659
+#define IMGFMT_IF09 0x39304649
+#define IMGFMT_YV12 0x32315659
+#define IMGFMT_I420 0x30323449
+#define IMGFMT_IYUV 0x56555949
+#define IMGFMT_CLPL 0x4C504C43
+#define IMGFMT_Y800 0x30303859
+#define IMGFMT_Y8 0x20203859
+#define IMGFMT_NV12 0x3231564E
+#define IMGFMT_NV21 0x3132564E
+#define IMGFMT_Y16_LE 0x20363159
+
+/* unofficial Planar Formats, FIXME if official 4CC exists */
+#define IMGFMT_444P 0x50343434
+#define IMGFMT_422P 0x50323234
+#define IMGFMT_411P 0x50313134
+#define IMGFMT_440P 0x50303434
+#define IMGFMT_HM12 0x32314D48
+#define IMGFMT_Y16_BE 0x59313620
+
+// Gray with alpha
+#define IMGFMT_Y8A 0x59320008
+// 4:2:0 planar with alpha
+#define IMGFMT_420A 0x41303234
+// 4:2:2 planar with alpha
+#define IMGFMT_422A 0x41323234
+// 4:4:4 planar with alpha
+#define IMGFMT_444A 0x41343434
+
+#define IMGFMT_444P16_LE 0x51343434
+#define IMGFMT_444P16_BE 0x34343451
+#define IMGFMT_444P14_LE 0x54343434
+#define IMGFMT_444P14_BE 0x34343454
+#define IMGFMT_444P12_LE 0x55343434
+#define IMGFMT_444P12_BE 0x34343455
+#define IMGFMT_444P10_LE 0x52343434
+#define IMGFMT_444P10_BE 0x34343452
+#define IMGFMT_444P9_LE 0x53343434
+#define IMGFMT_444P9_BE 0x34343453
+#define IMGFMT_422P16_LE 0x51323234
+#define IMGFMT_422P16_BE 0x34323251
+#define IMGFMT_422P14_LE 0x54323234
+#define IMGFMT_422P14_BE 0x34323254
+#define IMGFMT_422P12_LE 0x55323234
+#define IMGFMT_422P12_BE 0x34323255
+#define IMGFMT_422P10_LE 0x52323234
+#define IMGFMT_422P10_BE 0x34323252
+#define IMGFMT_422P9_LE 0x53323234
+#define IMGFMT_422P9_BE 0x34323253
+#define IMGFMT_420P16_LE 0x51303234
+#define IMGFMT_420P16_BE 0x34323051
+#define IMGFMT_420P14_LE 0x54303234
+#define IMGFMT_420P14_BE 0x34323054
+#define IMGFMT_420P12_LE 0x55303234
+#define IMGFMT_420P12_BE 0x34323055
+#define IMGFMT_420P10_LE 0x52303234
+#define IMGFMT_420P10_BE 0x34323052
+#define IMGFMT_420P9_LE 0x53303234
+#define IMGFMT_420P9_BE 0x34323053
+#if HAVE_BIGENDIAN
+#define IMGFMT_444P16 IMGFMT_444P16_BE
+#define IMGFMT_444P14 IMGFMT_444P14_BE
+#define IMGFMT_444P12 IMGFMT_444P12_BE
+#define IMGFMT_444P10 IMGFMT_444P10_BE
+#define IMGFMT_444P9 IMGFMT_444P9_BE
+#define IMGFMT_422P16 IMGFMT_422P16_BE
+#define IMGFMT_422P14 IMGFMT_422P14_BE
+#define IMGFMT_422P12 IMGFMT_422P12_BE
+#define IMGFMT_422P10 IMGFMT_422P10_BE
+#define IMGFMT_422P9 IMGFMT_422P9_BE
+#define IMGFMT_420P16 IMGFMT_420P16_BE
+#define IMGFMT_420P14 IMGFMT_420P14_BE
+#define IMGFMT_420P12 IMGFMT_420P12_BE
+#define IMGFMT_420P10 IMGFMT_420P10_BE
+#define IMGFMT_420P9 IMGFMT_420P9_BE
+#define IMGFMT_Y16 IMGFMT_Y16_BE
+#define IMGFMT_IS_YUVP16_NE(fmt) IMGFMT_IS_YUVP16_BE(fmt)
+#else
+#define IMGFMT_444P16 IMGFMT_444P16_LE
+#define IMGFMT_444P14 IMGFMT_444P14_LE
+#define IMGFMT_444P12 IMGFMT_444P12_LE
+#define IMGFMT_444P10 IMGFMT_444P10_LE
+#define IMGFMT_444P9 IMGFMT_444P9_LE
+#define IMGFMT_422P16 IMGFMT_422P16_LE
+#define IMGFMT_422P14 IMGFMT_422P14_LE
+#define IMGFMT_422P12 IMGFMT_422P12_LE
+#define IMGFMT_422P10 IMGFMT_422P10_LE
+#define IMGFMT_422P9 IMGFMT_422P9_LE
+#define IMGFMT_420P16 IMGFMT_420P16_LE
+#define IMGFMT_420P14 IMGFMT_420P14_LE
+#define IMGFMT_420P12 IMGFMT_420P12_LE
+#define IMGFMT_420P10 IMGFMT_420P10_LE
+#define IMGFMT_420P9 IMGFMT_420P9_LE
+#define IMGFMT_Y16 IMGFMT_Y16_LE
+#define IMGFMT_IS_YUVP16_NE(fmt) IMGFMT_IS_YUVP16_LE(fmt)
+#endif
+
+#define IMGFMT_IS_YUVP16_LE(fmt) (((fmt - 0x51000034) & 0xfc0000ff) == 0)
+#define IMGFMT_IS_YUVP16_BE(fmt) (((fmt - 0x34000051) & 0xff0000fc) == 0)
+#define IMGFMT_IS_YUVP16(fmt) (IMGFMT_IS_YUVP16_LE(fmt) || IMGFMT_IS_YUVP16_BE(fmt))
+
+/**
+ * \brief Find the corresponding full 16 bit format, i.e. IMGFMT_420P10_LE -> IMGFMT_420P16_LE
+ * \return normalized format ID or 0 if none exists.
+ */
+static inline int normalize_yuvp16(int fmt) {
+ if (IMGFMT_IS_YUVP16_LE(fmt))
+ return (fmt & 0x00ffffff) | 0x51000000;
+ if (IMGFMT_IS_YUVP16_BE(fmt))
+ return (fmt & 0xffffff00) | 0x00000051;
+ return 0;
+}
+
+/* Packed YUV Formats */
+
+#define IMGFMT_IUYV 0x56595549 // Interlaced UYVY
+#define IMGFMT_IY41 0x31435949 // Interlaced Y41P
+#define IMGFMT_IYU1 0x31555949
+#define IMGFMT_IYU2 0x32555949
+#define IMGFMT_UYVY 0x59565955
+#define IMGFMT_UYNV 0x564E5955 // Exactly same as UYVY
+#define IMGFMT_cyuv 0x76757963 // upside-down UYVY
+#define IMGFMT_Y422 0x32323459 // Exactly same as UYVY
+#define IMGFMT_YUY2 0x32595559
+#define IMGFMT_YUNV 0x564E5559 // Exactly same as YUY2
+#define IMGFMT_YVYU 0x55595659
+#define IMGFMT_Y41P 0x50313459
+#define IMGFMT_Y211 0x31313259
+#define IMGFMT_Y41T 0x54313459 // Y41P, Y lsb = transparency
+#define IMGFMT_Y42T 0x54323459 // UYVY, Y lsb = transparency
+#define IMGFMT_V422 0x32323456 // upside-down UYVY?
+#define IMGFMT_V655 0x35353656
+#define IMGFMT_CLJR 0x524A4C43
+#define IMGFMT_YUVP 0x50565559 // 10-bit YUYV
+#define IMGFMT_UYVP 0x50565955 // 10-bit UYVY
+
+/* Compressed Formats */
+#define IMGFMT_MPEGPES (('M'<<24)|('P'<<16)|('E'<<8)|('S'))
+#define IMGFMT_MJPEG (('M')|('J'<<8)|('P'<<16)|('G'<<24))
+/* Formats that are understood by zoran chips, we include
+ * non-interlaced, interlaced top-first, interlaced bottom-first */
+#define IMGFMT_ZRMJPEGNI (('Z'<<24)|('R'<<16)|('N'<<8)|('I'))
+#define IMGFMT_ZRMJPEGIT (('Z'<<24)|('R'<<16)|('I'<<8)|('T'))
+#define IMGFMT_ZRMJPEGIB (('Z'<<24)|('R'<<16)|('I'<<8)|('B'))
+
+// I think that this code could not be used by any other codec/format
+#define IMGFMT_XVMC 0x1DC70000
+#define IMGFMT_XVMC_MASK 0xFFFF0000
+#define IMGFMT_IS_XVMC(fmt) (((fmt)&IMGFMT_XVMC_MASK)==IMGFMT_XVMC)
+//these are chroma420
+#define IMGFMT_XVMC_MOCO_MPEG2 (IMGFMT_XVMC|0x02)
+#define IMGFMT_XVMC_IDCT_MPEG2 (IMGFMT_XVMC|0x82)
+
+// VDPAU specific format.
+#define IMGFMT_VDPAU 0x1DC80000
+#define IMGFMT_VDPAU_MASK 0xFFFF0000
+#define IMGFMT_IS_VDPAU(fmt) (((fmt)&IMGFMT_VDPAU_MASK)==IMGFMT_VDPAU)
+#define IMGFMT_VDPAU_MPEG1 (IMGFMT_VDPAU|0x01)
+#define IMGFMT_VDPAU_MPEG2 (IMGFMT_VDPAU|0x02)
+#define IMGFMT_VDPAU_H264 (IMGFMT_VDPAU|0x03)
+#define IMGFMT_VDPAU_WMV3 (IMGFMT_VDPAU|0x04)
+#define IMGFMT_VDPAU_VC1 (IMGFMT_VDPAU|0x05)
+#define IMGFMT_VDPAU_MPEG4 (IMGFMT_VDPAU|0x06)
+
+#define IMGFMT_IS_HWACCEL(fmt) (IMGFMT_IS_VDPAU(fmt) || IMGFMT_IS_XVMC(fmt))
+
+typedef struct {
+ void* data;
+ int size;
+ int id; // stream id. usually 0x1E0
+ int timestamp; // pts, 90000 Hz counter based
+} vo_mpegpes_t;
+
+const char *ff_vo_format_name(int format);
+
+/**
+ * Calculates the scale shifts for the chroma planes for planar YUV
+ *
+ * \param component_bits bits per component
+ * \return bits-per-pixel for format if successful (i.e. format is 3 or 4-planes planar YUV), 0 otherwise
+ */
+int ff_mp_get_chroma_shift(int format, int *x_shift, int *y_shift, int *component_bits);
+
+#endif /* MPLAYER_IMG_FORMAT_H */
diff --git a/libavfilter/libmpcodecs/libvo/fastmemcpy.h b/libavfilter/libmpcodecs/libvo/fastmemcpy.h
new file mode 100644
index 0000000..5a17d01
--- /dev/null
+++ b/libavfilter/libmpcodecs/libvo/fastmemcpy.h
@@ -0,0 +1,99 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with MPlayer; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MPLAYER_FASTMEMCPY_H
+#define MPLAYER_FASTMEMCPY_H
+
+#include <inttypes.h>
+#include <string.h>
+#include <stddef.h>
+
+void * fast_memcpy(void * to, const void * from, size_t len);
+void * mem2agpcpy(void * to, const void * from, size_t len);
+
+#if ! defined(CONFIG_FASTMEMCPY) || ! (HAVE_MMX || HAVE_MMX2 || HAVE_AMD3DNOW /* || HAVE_SSE || HAVE_SSE2 */)
+#define mem2agpcpy(a,b,c) memcpy(a,b,c)
+#define fast_memcpy(a,b,c) memcpy(a,b,c)
+#endif
+
+static inline void * mem2agpcpy_pic(void * dst, const void * src, int bytesPerLine, int height, int dstStride, int srcStride)
+{
+ int i;
+ void *retval=dst;
+
+ if(dstStride == srcStride)
+ {
+ if (srcStride < 0) {
+ src = (const uint8_t*)src + (height-1)*srcStride;
+ dst = (uint8_t*)dst + (height-1)*dstStride;
+ srcStride = -srcStride;
+ }
+
+ mem2agpcpy(dst, src, srcStride*height);
+ }
+ else
+ {
+ for(i=0; i<height; i++)
+ {
+ mem2agpcpy(dst, src, bytesPerLine);
+ src = (const uint8_t*)src + srcStride;
+ dst = (uint8_t*)dst + dstStride;
+ }
+ }
+
+ return retval;
+}
+
+#define memcpy_pic(d, s, b, h, ds, ss) memcpy_pic2(d, s, b, h, ds, ss, 0)
+#define my_memcpy_pic(d, s, b, h, ds, ss) memcpy_pic2(d, s, b, h, ds, ss, 1)
+
+/**
+ * \param limit2width always skip data between end of line and start of next
+ * instead of copying the full block when strides are the same
+ */
+static inline void * memcpy_pic2(void * dst, const void * src,
+ int bytesPerLine, int height,
+ int dstStride, int srcStride, int limit2width)
+{
+ int i;
+ void *retval=dst;
+
+ if(!limit2width && dstStride == srcStride)
+ {
+ if (srcStride < 0) {
+ src = (const uint8_t*)src + (height-1)*srcStride;
+ dst = (uint8_t*)dst + (height-1)*dstStride;
+ srcStride = -srcStride;
+ }
+
+ fast_memcpy(dst, src, srcStride*height);
+ }
+ else
+ {
+ for(i=0; i<height; i++)
+ {
+ fast_memcpy(dst, src, bytesPerLine);
+ src = (const uint8_t*)src + srcStride;
+ dst = (uint8_t*)dst + dstStride;
+ }
+ }
+
+ return retval;
+}
+
+#endif /* MPLAYER_FASTMEMCPY_H */
diff --git a/libavfilter/libmpcodecs/libvo/video_out.h b/libavfilter/libmpcodecs/libvo/video_out.h
new file mode 100644
index 0000000..49d3098
--- /dev/null
+++ b/libavfilter/libmpcodecs/libvo/video_out.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) Aaron Holtzman - Aug 1999
+ * Strongly modified, most parts rewritten: A'rpi/ESP-team - 2000-2001
+ * (C) MPlayer developers
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_VIDEO_OUT_H
+#define MPLAYER_VIDEO_OUT_H
+
+#include <inttypes.h>
+#include <stdarg.h>
+
+//#include "sub/font_load.h"
+#include "../img_format.h"
+//#include "vidix/vidix.h"
+
+
+#define ROTATE(t, x, y) do { \
+ t rot_tmp = x; \
+ x = y; \
+ y = -rot_tmp; \
+} while(0)
+
+#define VO_EVENT_EXPOSE 1
+#define VO_EVENT_RESIZE 2
+#define VO_EVENT_KEYPRESS 4
+#define VO_EVENT_REINIT 8
+#define VO_EVENT_MOVE 16
+#define VO_EVENT_MOUSE 32
+
+/* Obsolete: VOCTRL_QUERY_VAA 1 */
+/* does the device support the required format */
+#define VOCTRL_QUERY_FORMAT 2
+/* signal a device reset seek */
+#define VOCTRL_RESET 3
+/* true if vo driver can use GUI created windows */
+#define VOCTRL_GUISUPPORT 4
+/* used to switch to fullscreen */
+#define VOCTRL_FULLSCREEN 5
+/* signal a device pause */
+#define VOCTRL_PAUSE 7
+/* start/resume playback */
+#define VOCTRL_RESUME 8
+/* libmpcodecs direct rendering: */
+#define VOCTRL_GET_IMAGE 9
+#define VOCTRL_DRAW_IMAGE 13
+#define VOCTRL_SET_SPU_PALETTE 14
+/* decoding ahead: */
+#define VOCTRL_GET_NUM_FRAMES 10
+#define VOCTRL_GET_FRAME_NUM 11
+#define VOCTRL_SET_FRAME_NUM 12
+#define VOCTRL_GET_PANSCAN 15
+#define VOCTRL_SET_PANSCAN 16
+/* equalizer controls */
+#define VOCTRL_SET_EQUALIZER 17
+#define VOCTRL_GET_EQUALIZER 18
+/* Frame duplication */
+#define VOCTRL_DUPLICATE_FRAME 20
+// ... 21
+#define VOCTRL_START_SLICE 21
+
+#define VOCTRL_ONTOP 25
+#define VOCTRL_ROOTWIN 26
+#define VOCTRL_BORDER 27
+#define VOCTRL_DRAW_EOSD 28
+#define VOCTRL_GET_EOSD_RES 29
+
+#define VOCTRL_SET_DEINTERLACE 30
+#define VOCTRL_GET_DEINTERLACE 31
+
+#define VOCTRL_UPDATE_SCREENINFO 32
+
+// Vo can be used by xover
+#define VOCTRL_XOVERLAY_SUPPORT 22
+
+#define VOCTRL_XOVERLAY_SET_COLORKEY 24
+typedef struct {
+ uint32_t x11; // The raw x11 color
+ uint16_t r,g,b;
+} mp_colorkey_t;
+
+#define VOCTRL_XOVERLAY_SET_WIN 23
+typedef struct {
+ int x,y;
+ int w,h;
+} mp_win_t;
+
+#define VO_TRUE 1
+#define VO_FALSE 0
+#define VO_ERROR -1
+#define VO_NOTAVAIL -2
+#define VO_NOTIMPL -3
+
+#define VOFLAG_FULLSCREEN 0x01
+#define VOFLAG_MODESWITCHING 0x02
+#define VOFLAG_SWSCALE 0x04
+#define VOFLAG_FLIPPING 0x08
+#define VOFLAG_HIDDEN 0x10 //< Use to create a hidden window
+#define VOFLAG_STEREO 0x20 //< Use to create a stereo-capable window
+#define VOFLAG_DEPTH 0x40 //< Request a depth buffer
+#define VOFLAG_XOVERLAY_SUB_VO 0x10000
+
+typedef struct vo_info_s
+{
+ /* driver name ("Matrox Millennium G200/G400" */
+ const char *name;
+ /* short name (for config strings) ("mga") */
+ const char *short_name;
+ /* author ("Aaron Holtzman <aholtzma@ess.engr.uvic.ca>") */
+ const char *author;
+ /* any additional comments */
+ const char *comment;
+} vo_info_t;
+
+typedef struct vo_functions_s
+{
+ const vo_info_t *info;
+ /*
+ * Preinitializes driver (real INITIALIZATION)
+ * arg - currently it's vo_subdevice
+ * returns: zero on successful initialization, non-zero on error.
+ */
+ int (*preinit)(const char *arg);
+ /*
+ * Initialize (means CONFIGURE) the display driver.
+ * params:
+ * width,height: image source size
+ * d_width,d_height: size of the requested window size, just a hint
+ * fullscreen: flag, 0=windowd 1=fullscreen, just a hint
+ * title: window title, if available
+ * format: fourcc of pixel format
+ * returns : zero on successful initialization, non-zero on error.
+ */
+ int (*config)(uint32_t width, uint32_t height, uint32_t d_width,
+ uint32_t d_height, uint32_t fullscreen, char *title,
+ uint32_t format);
+
+ /*
+ * Control interface
+ */
+ int (*control)(uint32_t request, void *data, ...);
+
+ /*
+ * Display a new RGB/BGR frame of the video to the screen.
+ * params:
+ * src[0] - pointer to the image
+ */
+ int (*draw_frame)(uint8_t *src[]);
+
+ /*
+ * Draw a planar YUV slice to the buffer:
+ * params:
+ * src[3] = source image planes (Y,U,V)
+ * stride[3] = source image planes line widths (in bytes)
+ * w,h = width*height of area to be copied (in Y pixels)
+ * x,y = position at the destination image (in Y pixels)
+ */
+ int (*draw_slice)(uint8_t *src[], int stride[], int w,int h, int x,int y);
+
+ /*
+ * Draws OSD to the screen buffer
+ */
+ void (*draw_osd)(void);
+
+ /*
+ * Blit/Flip buffer to the screen. Must be called after each frame!
+ */
+ void (*flip_page)(void);
+
+ /*
+ * This func is called after every frames to handle keyboard and
+ * other events. It's called in PAUSE mode too!
+ */
+ void (*check_events)(void);
+
+ /*
+ * Closes driver. Should restore the original state of the system.
+ */
+ void (*uninit)(void);
+} vo_functions_t;
+
+const vo_functions_t* init_best_video_out(char** vo_list);
+int config_video_out(const vo_functions_t *vo, uint32_t width, uint32_t height,
+ uint32_t d_width, uint32_t d_height, uint32_t flags,
+ char *title, uint32_t format);
+void list_video_out(void);
+
+// NULL terminated array of all drivers
+extern const vo_functions_t* const video_out_drivers[];
+
+extern int vo_flags;
+
+extern int vo_config_count;
+
+extern int xinerama_screen;
+extern int xinerama_x;
+extern int xinerama_y;
+
+// correct resolution/bpp on screen: (should be autodetected by vo_init())
+extern int vo_depthonscreen;
+extern int vo_screenwidth;
+extern int vo_screenheight;
+
+// requested resolution/bpp: (-x -y -bpp options)
+extern int vo_dx;
+extern int vo_dy;
+extern int vo_dwidth;
+extern int vo_dheight;
+extern int vo_dbpp;
+
+extern int vo_grabpointer;
+extern int vo_doublebuffering;
+extern int vo_directrendering;
+extern int vo_vsync;
+extern int vo_fsmode;
+extern float vo_panscan;
+extern float vo_border_pos_x;
+extern float vo_border_pos_y;
+extern int vo_rotate;
+extern int vo_adapter_num;
+extern int vo_refresh_rate;
+extern int vo_keepaspect;
+extern int vo_rootwin;
+extern int vo_ontop;
+extern int vo_border;
+
+extern int vo_gamma_gamma;
+extern int vo_gamma_brightness;
+extern int vo_gamma_saturation;
+extern int vo_gamma_contrast;
+extern int vo_gamma_hue;
+extern int vo_gamma_red_intensity;
+extern int vo_gamma_green_intensity;
+extern int vo_gamma_blue_intensity;
+
+extern int vo_nomouse_input;
+extern int enable_mouse_movements;
+
+extern int vo_pts;
+extern float vo_fps;
+
+extern char *vo_subdevice;
+
+extern int vo_colorkey;
+
+extern char *vo_winname;
+extern char *vo_wintitle;
+
+extern int64_t WinID;
+
+typedef struct {
+ float min;
+ float max;
+ } range_t;
+
+float range_max(range_t *r);
+int in_range(range_t *r, float f);
+range_t *str2range(char *s);
+extern char *monitor_hfreq_str;
+extern char *monitor_vfreq_str;
+extern char *monitor_dotclock_str;
+
+struct mp_keymap {
+ int from;
+ int to;
+};
+int lookup_keymap_table(const struct mp_keymap *map, int key);
+struct vo_rect {
+ int left, right, top, bottom, width, height;
+};
+void calc_src_dst_rects(int src_width, int src_height, struct vo_rect *src, struct vo_rect *dst,
+ struct vo_rect *borders, const struct vo_rect *crop);
+void vo_mouse_movement(int posx, int posy);
+
+static inline int apply_border_pos(int full, int part, float pos) {
+ if (pos >= 0.0 && pos <= 1.0) {
+ return pos*(full - part);
+ }
+ if (pos < 0)
+ return pos * part;
+ return full - part + (pos - 1) * part;
+}
+
+#endif /* MPLAYER_VIDEO_OUT_H */
diff --git a/libavfilter/libmpcodecs/mp_image.c b/libavfilter/libmpcodecs/mp_image.c
new file mode 100644
index 0000000..0e4d6d7
--- /dev/null
+++ b/libavfilter/libmpcodecs/mp_image.c
@@ -0,0 +1,257 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#include "img_format.h"
+#include "mp_image.h"
+
+#include "libvo/fastmemcpy.h"
+//#include "libavutil/mem.h"
+#include "libavutil/imgutils.h"
+
+void ff_mp_image_alloc_planes(mp_image_t *mpi) {
+ uint32_t temp[256];
+ if (avpriv_set_systematic_pal2(temp, ff_mp2ff_pix_fmt(mpi->imgfmt)) >= 0)
+ mpi->flags |= MP_IMGFLAG_RGB_PALETTE;
+
+ // IF09 - allocate space for 4. plane delta info - unused
+ if (mpi->imgfmt == IMGFMT_IF09) {
+ mpi->planes[0]=av_malloc(mpi->bpp*mpi->width*(mpi->height+2)/8+
+ mpi->chroma_width*mpi->chroma_height);
+ } else
+ mpi->planes[0]=av_malloc(mpi->bpp*mpi->width*(mpi->height+2)/8);
+ if (mpi->flags&MP_IMGFLAG_PLANAR) {
+ int bpp = IMGFMT_IS_YUVP16(mpi->imgfmt)? 2 : 1;
+ // YV12/I420/YVU9/IF09. feel free to add other planar formats here...
+ mpi->stride[0]=mpi->stride[3]=bpp*mpi->width;
+ if(mpi->num_planes > 2){
+ mpi->stride[1]=mpi->stride[2]=bpp*mpi->chroma_width;
+ if(mpi->flags&MP_IMGFLAG_SWAPPED){
+ // I420/IYUV (Y,U,V)
+ mpi->planes[1]=mpi->planes[0]+mpi->stride[0]*mpi->height;
+ mpi->planes[2]=mpi->planes[1]+mpi->stride[1]*mpi->chroma_height;
+ if (mpi->num_planes > 3)
+ mpi->planes[3]=mpi->planes[2]+mpi->stride[2]*mpi->chroma_height;
+ } else {
+ // YV12,YVU9,IF09 (Y,V,U)
+ mpi->planes[2]=mpi->planes[0]+mpi->stride[0]*mpi->height;
+ mpi->planes[1]=mpi->planes[2]+mpi->stride[1]*mpi->chroma_height;
+ if (mpi->num_planes > 3)
+ mpi->planes[3]=mpi->planes[1]+mpi->stride[1]*mpi->chroma_height;
+ }
+ } else {
+ // NV12/NV21
+ mpi->stride[1]=mpi->chroma_width;
+ mpi->planes[1]=mpi->planes[0]+mpi->stride[0]*mpi->height;
+ }
+ } else {
+ mpi->stride[0]=mpi->width*mpi->bpp/8;
+ if (mpi->flags & MP_IMGFLAG_RGB_PALETTE) {
+ mpi->planes[1] = av_malloc(1024);
+ memcpy(mpi->planes[1], temp, 1024);
+ }
+ }
+ mpi->flags|=MP_IMGFLAG_ALLOCATED;
+}
+
+mp_image_t* ff_alloc_mpi(int w, int h, unsigned long int fmt) {
+ mp_image_t* mpi = ff_new_mp_image(w,h);
+
+ ff_mp_image_setfmt(mpi,fmt);
+ ff_mp_image_alloc_planes(mpi);
+
+ return mpi;
+}
+
+void ff_copy_mpi(mp_image_t *dmpi, mp_image_t *mpi) {
+ if(mpi->flags&MP_IMGFLAG_PLANAR){
+ memcpy_pic(dmpi->planes[0],mpi->planes[0], mpi->w, mpi->h,
+ dmpi->stride[0],mpi->stride[0]);
+ memcpy_pic(dmpi->planes[1],mpi->planes[1], mpi->chroma_width, mpi->chroma_height,
+ dmpi->stride[1],mpi->stride[1]);
+ memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->chroma_width, mpi->chroma_height,
+ dmpi->stride[2],mpi->stride[2]);
+ } else {
+ memcpy_pic(dmpi->planes[0],mpi->planes[0],
+ mpi->w*(dmpi->bpp/8), mpi->h,
+ dmpi->stride[0],mpi->stride[0]);
+ }
+}
+
+void ff_mp_image_setfmt(mp_image_t* mpi,unsigned int out_fmt){
+ mpi->flags&=~(MP_IMGFLAG_PLANAR|MP_IMGFLAG_YUV|MP_IMGFLAG_SWAPPED);
+ mpi->imgfmt=out_fmt;
+ // compressed formats
+ if(out_fmt == IMGFMT_MPEGPES ||
+ out_fmt == IMGFMT_ZRMJPEGNI || out_fmt == IMGFMT_ZRMJPEGIT || out_fmt == IMGFMT_ZRMJPEGIB ||
+ IMGFMT_IS_HWACCEL(out_fmt)){
+ mpi->bpp=0;
+ return;
+ }
+ mpi->num_planes=1;
+ if (IMGFMT_IS_RGB(out_fmt)) {
+ if (IMGFMT_RGB_DEPTH(out_fmt) < 8 && !(out_fmt&128))
+ mpi->bpp = IMGFMT_RGB_DEPTH(out_fmt);
+ else
+ mpi->bpp=(IMGFMT_RGB_DEPTH(out_fmt)+7)&(~7);
+ return;
+ }
+ if (IMGFMT_IS_BGR(out_fmt)) {
+ if (IMGFMT_BGR_DEPTH(out_fmt) < 8 && !(out_fmt&128))
+ mpi->bpp = IMGFMT_BGR_DEPTH(out_fmt);
+ else
+ mpi->bpp=(IMGFMT_BGR_DEPTH(out_fmt)+7)&(~7);
+ mpi->flags|=MP_IMGFLAG_SWAPPED;
+ return;
+ }
+ if (IMGFMT_IS_XYZ(out_fmt)) {
+ mpi->bpp=3*((IMGFMT_XYZ_DEPTH(out_fmt) + 7) & ~7);
+ return;
+ }
+ mpi->num_planes=3;
+ if (out_fmt == IMGFMT_GBR24P) {
+ mpi->bpp=24;
+ mpi->flags|=MP_IMGFLAG_PLANAR;
+ return;
+ } else if (out_fmt == IMGFMT_GBR12P) {
+ mpi->bpp=36;
+ mpi->flags|=MP_IMGFLAG_PLANAR;
+ return;
+ } else if (out_fmt == IMGFMT_GBR14P) {
+ mpi->bpp=42;
+ mpi->flags|=MP_IMGFLAG_PLANAR;
+ return;
+ }
+ mpi->flags|=MP_IMGFLAG_YUV;
+ if (ff_mp_get_chroma_shift(out_fmt, NULL, NULL, NULL)) {
+ mpi->flags|=MP_IMGFLAG_PLANAR;
+ mpi->bpp = ff_mp_get_chroma_shift(out_fmt, &mpi->chroma_x_shift, &mpi->chroma_y_shift, NULL);
+ mpi->chroma_width = mpi->width >> mpi->chroma_x_shift;
+ mpi->chroma_height = mpi->height >> mpi->chroma_y_shift;
+ }
+ switch(out_fmt){
+ case IMGFMT_I420:
+ case IMGFMT_IYUV:
+ mpi->flags|=MP_IMGFLAG_SWAPPED;
+ case IMGFMT_YV12:
+ return;
+ case IMGFMT_420A:
+ case IMGFMT_422A:
+ case IMGFMT_444A:
+ case IMGFMT_IF09:
+ mpi->num_planes=4;
+ case IMGFMT_YVU9:
+ case IMGFMT_444P:
+ case IMGFMT_422P:
+ case IMGFMT_411P:
+ case IMGFMT_440P:
+ case IMGFMT_444P16_LE:
+ case IMGFMT_444P16_BE:
+ case IMGFMT_444P14_LE:
+ case IMGFMT_444P14_BE:
+ case IMGFMT_444P12_LE:
+ case IMGFMT_444P12_BE:
+ case IMGFMT_444P10_LE:
+ case IMGFMT_444P10_BE:
+ case IMGFMT_444P9_LE:
+ case IMGFMT_444P9_BE:
+ case IMGFMT_422P16_LE:
+ case IMGFMT_422P16_BE:
+ case IMGFMT_422P14_LE:
+ case IMGFMT_422P14_BE:
+ case IMGFMT_422P12_LE:
+ case IMGFMT_422P12_BE:
+ case IMGFMT_422P10_LE:
+ case IMGFMT_422P10_BE:
+ case IMGFMT_422P9_LE:
+ case IMGFMT_422P9_BE:
+ case IMGFMT_420P16_LE:
+ case IMGFMT_420P16_BE:
+ case IMGFMT_420P14_LE:
+ case IMGFMT_420P14_BE:
+ case IMGFMT_420P12_LE:
+ case IMGFMT_420P12_BE:
+ case IMGFMT_420P10_LE:
+ case IMGFMT_420P10_BE:
+ case IMGFMT_420P9_LE:
+ case IMGFMT_420P9_BE:
+ return;
+ case IMGFMT_Y16_LE:
+ case IMGFMT_Y16_BE:
+ mpi->bpp=16;
+ case IMGFMT_Y800:
+ case IMGFMT_Y8:
+ /* they're planar ones, but for easier handling use them as packed */
+ mpi->flags&=~MP_IMGFLAG_PLANAR;
+ mpi->num_planes=1;
+ return;
+ case IMGFMT_Y8A:
+ mpi->num_planes=2;
+ return;
+ case IMGFMT_UYVY:
+ mpi->flags|=MP_IMGFLAG_SWAPPED;
+ case IMGFMT_YUY2:
+ mpi->chroma_x_shift = 1;
+ mpi->bpp=16;
+ mpi->num_planes=1;
+ return;
+ case IMGFMT_NV12:
+ mpi->flags|=MP_IMGFLAG_SWAPPED;
+ case IMGFMT_NV21:
+ mpi->flags|=MP_IMGFLAG_PLANAR;
+ mpi->bpp=12;
+ mpi->num_planes=2;
+ mpi->chroma_width=(mpi->width>>0);
+ mpi->chroma_height=(mpi->height>>1);
+ mpi->chroma_x_shift=0;
+ mpi->chroma_y_shift=1;
+ return;
+ }
+ ff_mp_msg(MSGT_DECVIDEO,MSGL_WARN,"mp_image: unknown out_fmt: 0x%X\n",out_fmt);
+ mpi->bpp=0;
+}
+
+mp_image_t* ff_new_mp_image(int w,int h){
+ mp_image_t* mpi = malloc(sizeof(mp_image_t));
+ if(!mpi) return NULL; // error!
+ memset(mpi,0,sizeof(mp_image_t));
+ mpi->width=mpi->w=w;
+ mpi->height=mpi->h=h;
+ return mpi;
+}
+
+void ff_free_mp_image(mp_image_t* mpi){
+ if(!mpi) return;
+ if(mpi->flags&MP_IMGFLAG_ALLOCATED){
+ /* because we allocate the whole image at once */
+ av_free(mpi->planes[0]);
+ if (mpi->flags & MP_IMGFLAG_RGB_PALETTE)
+ av_free(mpi->planes[1]);
+ }
+ free(mpi);
+}
+
diff --git a/libavfilter/libmpcodecs/mp_image.h b/libavfilter/libmpcodecs/mp_image.h
new file mode 100644
index 0000000..aedf451
--- /dev/null
+++ b/libavfilter/libmpcodecs/mp_image.h
@@ -0,0 +1,159 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_MP_IMAGE_H
+#define MPLAYER_MP_IMAGE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#undef printf //FIXME
+#undef fprintf //FIXME
+#include "mp_msg.h"
+#include "libavutil/avutil.h"
+#include "libavutil/avassert.h"
+#undef realloc
+#undef malloc
+#undef free
+#undef rand
+#undef srand
+#undef printf
+#undef strncpy
+#define ASMALIGN(ZEROBITS) ".p2align " #ZEROBITS "\n\t"
+#define CODEC_FLAG2_MEMC_ONLY 0x00001000 ///< Only do ME/MC (I frames -> ref, P frame -> ME+MC).
+
+enum AVPixelFormat ff_mp2ff_pix_fmt(int mp);
+
+//--------- codec's requirements (filled by the codec/vf) ---------
+
+//--- buffer content restrictions:
+// set if buffer content shouldn't be modified:
+#define MP_IMGFLAG_PRESERVE 0x01
+// set if buffer content will be READ.
+// This can be e.g. for next frame's MC: (I/P mpeg frames) -
+// then in combination with MP_IMGFLAG_PRESERVE - or it
+// can be because a video filter or codec will read a significant
+// amount of data while processing that frame (e.g. blending something
+// onto the frame, MV based intra prediction).
+// A frame marked like this should not be placed in to uncachable
+// video RAM for example.
+#define MP_IMGFLAG_READABLE 0x02
+
+//--- buffer width/stride/plane restrictions: (used for direct rendering)
+// stride _have_to_ be aligned to MB boundary: [for DR restrictions]
+#define MP_IMGFLAG_ACCEPT_ALIGNED_STRIDE 0x4
+// stride should be aligned to MB boundary: [for buffer allocation]
+#define MP_IMGFLAG_PREFER_ALIGNED_STRIDE 0x8
+// codec accept any stride (>=width):
+#define MP_IMGFLAG_ACCEPT_STRIDE 0x10
+// codec accept any width (width*bpp=stride -> stride%bpp==0) (>=width):
+#define MP_IMGFLAG_ACCEPT_WIDTH 0x20
+//--- for planar formats only:
+// uses only stride[0], and stride[1]=stride[2]=stride[0]>>mpi->chroma_x_shift
+#define MP_IMGFLAG_COMMON_STRIDE 0x40
+// uses only planes[0], and calculates planes[1,2] from width,height,imgfmt
+#define MP_IMGFLAG_COMMON_PLANE 0x80
+
+#define MP_IMGFLAGMASK_RESTRICTIONS 0xFF
+
+//--------- color info (filled by ff_mp_image_setfmt() ) -----------
+// set if number of planes > 1
+#define MP_IMGFLAG_PLANAR 0x100
+// set if it's YUV colorspace
+#define MP_IMGFLAG_YUV 0x200
+// set if it's swapped (BGR or YVU) plane/byteorder
+#define MP_IMGFLAG_SWAPPED 0x400
+// set if you want memory for palette allocated and managed by ff_vf_get_image etc.
+#define MP_IMGFLAG_RGB_PALETTE 0x800
+
+#define MP_IMGFLAGMASK_COLORS 0xF00
+
+// codec uses drawing/rendering callbacks (draw_slice()-like thing, DR method 2)
+// [the codec will set this flag if it supports callbacks, and the vo _may_
+// clear it in get_image() if draw_slice() not implemented]
+#define MP_IMGFLAG_DRAW_CALLBACK 0x1000
+// set if it's in video buffer/memory: [set by vo/vf's get_image() !!!]
+#define MP_IMGFLAG_DIRECT 0x2000
+// set if buffer is allocated (used in destination images):
+#define MP_IMGFLAG_ALLOCATED 0x4000
+
+// buffer type was printed (do NOT set this flag - it's for INTERNAL USE!!!)
+#define MP_IMGFLAG_TYPE_DISPLAYED 0x8000
+
+// codec doesn't support any form of direct rendering - it has own buffer
+// allocation. so we just export its buffer pointers:
+#define MP_IMGTYPE_EXPORT 0
+// codec requires a static WO buffer, but it does only partial updates later:
+#define MP_IMGTYPE_STATIC 1
+// codec just needs some WO memory, where it writes/copies the whole frame to:
+#define MP_IMGTYPE_TEMP 2
+// I+P type, requires 2+ independent static R/W buffers
+#define MP_IMGTYPE_IP 3
+// I+P+B type, requires 2+ independent static R/W and 1+ temp WO buffers
+#define MP_IMGTYPE_IPB 4
+// Upper 16 bits give desired buffer number, -1 means get next available
+#define MP_IMGTYPE_NUMBERED 5
+// Doesn't need any buffer, incomplete image (probably a first field only)
+// we need this type to be able to differentiate between half frames and
+// all other cases
+#define MP_IMGTYPE_INCOMPLETE 6
+
+#define MP_MAX_PLANES 4
+
+#define MP_IMGFIELD_ORDERED 0x01
+#define MP_IMGFIELD_TOP_FIRST 0x02
+#define MP_IMGFIELD_REPEAT_FIRST 0x04
+#define MP_IMGFIELD_TOP 0x08
+#define MP_IMGFIELD_BOTTOM 0x10
+#define MP_IMGFIELD_INTERLACED 0x20
+
+typedef struct mp_image {
+ unsigned int flags;
+ unsigned char type;
+ int number;
+ unsigned char bpp; // bits/pixel. NOT depth! for RGB it will be n*8
+ unsigned int imgfmt;
+ int width,height; // stored dimensions
+ int x,y,w,h; // visible dimensions
+ unsigned char* planes[MP_MAX_PLANES];
+ int stride[MP_MAX_PLANES];
+ char * qscale;
+ int qstride;
+ int pict_type; // 0->unknown, 1->I, 2->P, 3->B
+ int fields;
+ int qscale_type; // 0->mpeg1/4/h263, 1->mpeg2
+ int num_planes;
+ /* these are only used by planar formats Y,U(Cb),V(Cr) */
+ int chroma_width;
+ int chroma_height;
+ int chroma_x_shift; // horizontal
+ int chroma_y_shift; // vertical
+ int usage_count;
+ /* for private use by filter or vo driver (to store buffer id or dmpi) */
+ void* priv;
+} mp_image_t;
+
+void ff_mp_image_setfmt(mp_image_t* mpi,unsigned int out_fmt);
+mp_image_t* ff_new_mp_image(int w,int h);
+void ff_free_mp_image(mp_image_t* mpi);
+
+mp_image_t* ff_alloc_mpi(int w, int h, unsigned long int fmt);
+void ff_mp_image_alloc_planes(mp_image_t *mpi);
+void ff_copy_mpi(mp_image_t *dmpi, mp_image_t *mpi);
+
+#endif /* MPLAYER_MP_IMAGE_H */
diff --git a/libavfilter/libmpcodecs/mp_msg.h b/libavfilter/libmpcodecs/mp_msg.h
new file mode 100644
index 0000000..51cdff3
--- /dev/null
+++ b/libavfilter/libmpcodecs/mp_msg.h
@@ -0,0 +1,166 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_MP_MSG_H
+#define MPLAYER_MP_MSG_H
+
+#include <stdarg.h>
+
+// defined in mplayer.c and mencoder.c
+extern int verbose;
+
+// verbosity elevel:
+
+/* Only messages level MSGL_FATAL-MSGL_STATUS should be translated,
+ * messages level MSGL_V and above should not be translated. */
+
+#define MSGL_FATAL 0 // will exit/abort
+#define MSGL_ERR 1 // continues
+#define MSGL_WARN 2 // only warning
+#define MSGL_HINT 3 // short help message
+#define MSGL_INFO 4 // -quiet
+#define MSGL_STATUS 5 // v=0
+#define MSGL_V 6 // v=1
+#define MSGL_DBG2 7 // v=2
+#define MSGL_DBG3 8 // v=3
+#define MSGL_DBG4 9 // v=4
+#define MSGL_DBG5 10 // v=5
+
+#define MSGL_FIXME 1 // for conversions from printf where the appropriate MSGL is not known; set equal to ERR for obtrusiveness
+#define MSGT_FIXME 0 // for conversions from printf where the appropriate MSGT is not known; set equal to GLOBAL for obtrusiveness
+
+// code/module:
+
+#define MSGT_GLOBAL 0 // common player stuff errors
+#define MSGT_CPLAYER 1 // console player (mplayer.c)
+#define MSGT_GPLAYER 2 // gui player
+
+#define MSGT_VO 3 // libvo
+#define MSGT_AO 4 // libao
+
+#define MSGT_DEMUXER 5 // demuxer.c (general stuff)
+#define MSGT_DS 6 // demux stream (add/read packet etc)
+#define MSGT_DEMUX 7 // fileformat-specific stuff (demux_*.c)
+#define MSGT_HEADER 8 // fileformat-specific header (*header.c)
+
+#define MSGT_AVSYNC 9 // mplayer.c timer stuff
+#define MSGT_AUTOQ 10 // mplayer.c auto-quality stuff
+
+#define MSGT_CFGPARSER 11 // cfgparser.c
+
+#define MSGT_DECAUDIO 12 // av decoder
+#define MSGT_DECVIDEO 13
+
+#define MSGT_SEEK 14 // seeking code
+#define MSGT_WIN32 15 // win32 dll stuff
+#define MSGT_OPEN 16 // open.c (stream opening)
+#define MSGT_DVD 17 // open.c (DVD init/read/seek)
+
+#define MSGT_PARSEES 18 // parse_es.c (mpeg stream parser)
+#define MSGT_LIRC 19 // lirc_mp.c and input lirc driver
+
+#define MSGT_STREAM 20 // stream.c
+#define MSGT_CACHE 21 // cache2.c
+
+#define MSGT_MENCODER 22
+
+#define MSGT_XACODEC 23 // XAnim codecs
+
+#define MSGT_TV 24 // TV input subsystem
+
+#define MSGT_OSDEP 25 // OS-dependent parts
+
+#define MSGT_SPUDEC 26 // spudec.c
+
+#define MSGT_PLAYTREE 27 // Playtree handeling (playtree.c, playtreeparser.c)
+
+#define MSGT_INPUT 28
+
+#define MSGT_VFILTER 29
+
+#define MSGT_OSD 30
+
+#define MSGT_NETWORK 31
+
+#define MSGT_CPUDETECT 32
+
+#define MSGT_CODECCFG 33
+
+#define MSGT_SWS 34
+
+#define MSGT_VOBSUB 35
+#define MSGT_SUBREADER 36
+
+#define MSGT_AFILTER 37 // Audio filter messages
+
+#define MSGT_NETST 38 // Netstream
+
+#define MSGT_MUXER 39 // muxer layer
+
+#define MSGT_OSD_MENU 40
+
+#define MSGT_IDENTIFY 41 // -identify output
+
+#define MSGT_RADIO 42
+
+#define MSGT_ASS 43 // libass messages
+
+#define MSGT_LOADER 44 // dll loader messages
+
+#define MSGT_STATUSLINE 45 // playback/encoding status line
+
+#define MSGT_TELETEXT 46 // Teletext decoder
+
+#define MSGT_MAX 64
+
+
+extern char *ff_mp_msg_charset;
+extern int ff_mp_msg_color;
+extern int ff_mp_msg_module;
+
+extern int ff_mp_msg_levels[MSGT_MAX];
+extern int ff_mp_msg_level_all;
+
+
+void ff_mp_msg_init(void);
+int ff_mp_msg_test(int mod, int lev);
+
+#include "config.h"
+
+void ff_mp_msg_va(int mod, int lev, const char *format, va_list va);
+#ifdef __GNUC__
+void ff_mp_msg(int mod, int lev, const char *format, ... ) __attribute__ ((format (printf, 3, 4)));
+# ifdef MP_DEBUG
+# define mp_dbg(mod,lev, args... ) ff_mp_msg(mod, lev, ## args )
+# else
+ // only useful for developers, disable but check syntax
+# define mp_dbg(mod,lev, args... ) do { if (0) ff_mp_msg(mod, lev, ## args ); } while (0)
+# endif
+#else // not GNU C
+void ff_mp_msg(int mod, int lev, const char *format, ... );
+# ifdef MP_DEBUG
+# define mp_dbg(mod,lev, ... ) ff_mp_msg(mod, lev, __VA_ARGS__)
+# else
+ // only useful for developers, disable but check syntax
+# define mp_dbg(mod,lev, ... ) do { if (0) ff_mp_msg(mod, lev, __VA_ARGS__); } while (0)
+# endif
+#endif /* __GNUC__ */
+
+const char* ff_filename_recode(const char* filename);
+
+#endif /* MPLAYER_MP_MSG_H */
diff --git a/libavfilter/libmpcodecs/mpc_info.h b/libavfilter/libmpcodecs/mpc_info.h
new file mode 100644
index 0000000..8554699
--- /dev/null
+++ b/libavfilter/libmpcodecs/mpc_info.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_MPC_INFO_H
+#define MPLAYER_MPC_INFO_H
+
+typedef struct mp_codec_info_s
+{
+ /* codec long name ("Autodesk FLI/FLC Animation decoder" */
+ const char *name;
+ /* short name (same as driver name in codecs.conf) ("dshow") */
+ const char *short_name;
+ /* interface author/maintainer */
+ const char *maintainer;
+ /* codec author ("Aaron Holtzman <aholtzma@ess.engr.uvic.ca>") */
+ const char *author;
+ /* any additional comments */
+ const char *comment;
+} mp_codec_info_t;
+
+#define CONTROL_OK 1
+#define CONTROL_TRUE 1
+#define CONTROL_FALSE 0
+#define CONTROL_UNKNOWN -1
+#define CONTROL_ERROR -2
+#define CONTROL_NA -3
+
+#endif /* MPLAYER_MPC_INFO_H */
diff --git a/libavfilter/libmpcodecs/vf.h b/libavfilter/libmpcodecs/vf.h
new file mode 100644
index 0000000..d8fc66b
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf.h
@@ -0,0 +1,169 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_VF_H
+#define MPLAYER_VF_H
+
+//#include "m_option.h"
+#include "mp_image.h"
+
+//extern m_obj_settings_t* vf_settings;
+//extern const m_obj_list_t vf_obj_list;
+
+struct vf_instance;
+struct vf_priv_s;
+
+typedef struct vf_info_s {
+ const char *info;
+ const char *name;
+ const char *author;
+ const char *comment;
+ int (*vf_open)(struct vf_instance *vf,char* args);
+ // Ptr to a struct dscribing the options
+ const void* opts;
+} vf_info_t;
+
+#define NUM_NUMBERED_MPI 50
+
+typedef struct vf_image_context_s {
+ mp_image_t* static_images[2];
+ mp_image_t* temp_images[1];
+ mp_image_t* export_images[1];
+ mp_image_t* numbered_images[NUM_NUMBERED_MPI];
+ int static_idx;
+} vf_image_context_t;
+
+typedef struct vf_format_context_t {
+ int have_configured;
+ int orig_width, orig_height, orig_fmt;
+} vf_format_context_t;
+
+typedef struct vf_instance {
+ const vf_info_t* info;
+ // funcs:
+ int (*config)(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt);
+ int (*control)(struct vf_instance *vf,
+ int request, void* data);
+ int (*query_format)(struct vf_instance *vf,
+ unsigned int fmt);
+ void (*get_image)(struct vf_instance *vf,
+ mp_image_t *mpi);
+ int (*put_image)(struct vf_instance *vf,
+ mp_image_t *mpi, double pts);
+ void (*start_slice)(struct vf_instance *vf,
+ mp_image_t *mpi);
+ void (*draw_slice)(struct vf_instance *vf,
+ unsigned char** src, int* stride, int w,int h, int x, int y);
+ void (*uninit)(struct vf_instance *vf);
+
+ int (*continue_buffered_image)(struct vf_instance *vf);
+ // caps:
+ unsigned int default_caps; // used by default query_format()
+ unsigned int default_reqs; // used by default config()
+ // data:
+ int w, h;
+ vf_image_context_t imgctx;
+ vf_format_context_t fmt;
+ struct vf_instance *next;
+ mp_image_t *dmpi;
+ struct vf_priv_s* priv;
+} vf_instance_t;
+
+// control codes:
+#include "mpc_info.h"
+
+typedef struct vf_seteq_s
+{
+ const char *item;
+ int value;
+} vf_equalizer_t;
+
+#define VFCTRL_QUERY_MAX_PP_LEVEL 4 /* test for postprocessing support (max level) */
+#define VFCTRL_SET_PP_LEVEL 5 /* set postprocessing level */
+#define VFCTRL_SET_EQUALIZER 6 /* set color options (brightness,contrast etc) */
+#define VFCTRL_GET_EQUALIZER 8 /* gset color options (brightness,contrast etc) */
+#define VFCTRL_DRAW_OSD 7
+#define VFCTRL_CHANGE_RECTANGLE 9 /* Change the rectangle boundaries */
+#define VFCTRL_FLIP_PAGE 10 /* Tell the vo to flip pages */
+#define VFCTRL_DUPLICATE_FRAME 11 /* For encoding - encode zero-change frame */
+#define VFCTRL_SKIP_NEXT_FRAME 12 /* For encoding - drop the next frame that passes through */
+#define VFCTRL_FLUSH_FRAMES 13 /* For encoding - flush delayed frames */
+#define VFCTRL_SCREENSHOT 14 /* Make a screenshot */
+#define VFCTRL_INIT_EOSD 15 /* Select EOSD renderer */
+#define VFCTRL_DRAW_EOSD 16 /* Render EOSD */
+#define VFCTRL_GET_PTS 17 /* Return last pts value that reached vf_vo*/
+#define VFCTRL_SET_DEINTERLACE 18 /* Set deinterlacing status */
+#define VFCTRL_GET_DEINTERLACE 19 /* Get deinterlacing status */
+
+#include "vfcap.h"
+
+//FIXME this should be in a common header, but i dunno which
+#define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly
+
+
+// functions:
+void ff_vf_mpi_clear(mp_image_t* mpi,int x0,int y0,int w,int h);
+mp_image_t* ff_vf_get_image(vf_instance_t* vf, unsigned int outfmt, int mp_imgtype, int mp_imgflag, int w, int h);
+
+vf_instance_t* vf_open_plugin(const vf_info_t* const* filter_list, vf_instance_t* next, const char *name, char **args);
+vf_instance_t* vf_open_filter(vf_instance_t* next, const char *name, char **args);
+vf_instance_t* ff_vf_add_before_vo(vf_instance_t **vf, char *name, char **args);
+vf_instance_t* vf_open_encoder(vf_instance_t* next, const char *name, char *args);
+
+unsigned int ff_vf_match_csp(vf_instance_t** vfp,const unsigned int* list,unsigned int preferred);
+void ff_vf_clone_mpi_attributes(mp_image_t* dst, mp_image_t* src);
+void ff_vf_queue_frame(vf_instance_t *vf, int (*)(vf_instance_t *));
+int ff_vf_output_queued_frame(vf_instance_t *vf);
+
+// default wrappers:
+int ff_vf_next_config(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt);
+int ff_vf_next_control(struct vf_instance *vf, int request, void* data);
+void ff_vf_extra_flip(struct vf_instance *vf);
+int ff_vf_next_query_format(struct vf_instance *vf, unsigned int fmt);
+int ff_vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts);
+void ff_vf_next_draw_slice (struct vf_instance *vf, unsigned char** src, int* stride, int w,int h, int x, int y);
+
+vf_instance_t* ff_append_filters(vf_instance_t* last);
+
+void ff_vf_uninit_filter(vf_instance_t* vf);
+void ff_vf_uninit_filter_chain(vf_instance_t* vf);
+
+int ff_vf_config_wrapper(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt);
+
+static inline int norm_qscale(int qscale, int type)
+{
+ switch (type) {
+ case 0: // MPEG-1
+ return qscale;
+ case 1: // MPEG-2
+ return qscale >> 1;
+ case 2: // H264
+ return qscale >> 2;
+ case 3: // VP56
+ return (63 - qscale + 2) >> 2;
+ }
+ return qscale;
+}
+
+#endif /* MPLAYER_VF_H */
diff --git a/libavfilter/libmpcodecs/vf_eq.c b/libavfilter/libmpcodecs/vf_eq.c
new file mode 100644
index 0000000..f8efa84
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_eq.c
@@ -0,0 +1,240 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; 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 <string.h>
+#include <inttypes.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "cpudetect.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+
+#include "libvo/video_out.h"
+
+struct vf_priv_s {
+ unsigned char *buf;
+ int brightness;
+ int contrast;
+};
+
+#if HAVE_MMX && HAVE_6REGS
+static void process_MMX(unsigned char *dest, int dstride, unsigned char *src, int sstride,
+ int w, int h, int brightness, int contrast)
+{
+ int i;
+ int pel;
+ int dstep = dstride-w;
+ int sstep = sstride-w;
+ short brvec[4];
+ short contvec[4];
+
+ contrast = ((contrast+100)*256*16)/100;
+ brightness = ((brightness+100)*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"
+ ASMALIGN(4)
+ "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" (dest)
+ : "0" (src), "1" (dest), "r" (w>>3), "r" (brvec), "r" (contvec)
+ : "%eax"
+ );
+
+ for (i = w&7; i; i--)
+ {
+ pel = ((*src++* contrast)>>12) + brightness;
+ if(pel&768) pel = (-pel)>>31;
+ *dest++ = pel;
+ }
+
+ src += sstep;
+ dest += dstep;
+ }
+ __asm__ volatile ( "emms \n\t" ::: "memory" );
+}
+#endif
+
+static void process_C(unsigned char *dest, int dstride, unsigned char *src, int sstride,
+ int w, int h, int brightness, int contrast)
+{
+ int i;
+ int pel;
+ int dstep = dstride-w;
+ int sstep = sstride-w;
+
+ contrast = ((contrast+100)*256*256)/100;
+ brightness = ((brightness+100)*511)/200-128 - contrast/512;
+
+ while (h--) {
+ for (i = w; i; i--)
+ {
+ pel = ((*src++* contrast)>>16) + brightness;
+ if(pel&768) pel = (-pel)>>31;
+ *dest++ = pel;
+ }
+ src += sstep;
+ dest += dstep;
+ }
+}
+
+static void (*process)(unsigned char *dest, int dstride, unsigned char *src, int sstride,
+ int w, int h, int brightness, int contrast);
+
+/* FIXME: add packed yuv version of process */
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
+{
+ mp_image_t *dmpi;
+
+ dmpi=ff_vf_get_image(vf->next, mpi->imgfmt,
+ MP_IMGTYPE_EXPORT, 0,
+ mpi->w, mpi->h);
+
+ dmpi->stride[0] = mpi->stride[0];
+ dmpi->planes[1] = mpi->planes[1];
+ dmpi->planes[2] = mpi->planes[2];
+ dmpi->stride[1] = mpi->stride[1];
+ dmpi->stride[2] = mpi->stride[2];
+
+ if (!vf->priv->buf) vf->priv->buf = malloc(mpi->stride[0]*mpi->h);
+
+ if ((vf->priv->brightness == 0) && (vf->priv->contrast == 0))
+ dmpi->planes[0] = mpi->planes[0];
+ else {
+ dmpi->planes[0] = vf->priv->buf;
+ process(dmpi->planes[0], dmpi->stride[0],
+ mpi->planes[0], mpi->stride[0],
+ mpi->w, mpi->h, vf->priv->brightness,
+ vf->priv->contrast);
+ }
+
+ return ff_vf_next_put_image(vf,dmpi, pts);
+}
+
+static int control(struct vf_instance *vf, int request, void* data)
+{
+ vf_equalizer_t *eq;
+
+ switch (request) {
+ case VFCTRL_SET_EQUALIZER:
+ eq = data;
+ if (!strcmp(eq->item,"brightness")) {
+ vf->priv->brightness = eq->value;
+ return CONTROL_TRUE;
+ }
+ else if (!strcmp(eq->item,"contrast")) {
+ vf->priv->contrast = eq->value;
+ return CONTROL_TRUE;
+ }
+ break;
+ case VFCTRL_GET_EQUALIZER:
+ eq = data;
+ if (!strcmp(eq->item,"brightness")) {
+ eq->value = vf->priv->brightness;
+ return CONTROL_TRUE;
+ }
+ else if (!strcmp(eq->item,"contrast")) {
+ eq->value = vf->priv->contrast;
+ return CONTROL_TRUE;
+ }
+ break;
+ }
+ return ff_vf_next_control(vf, request, data);
+}
+
+static int query_format(struct vf_instance *vf, unsigned int fmt)
+{
+ switch (fmt) {
+ case IMGFMT_YVU9:
+ case IMGFMT_IF09:
+ case IMGFMT_YV12:
+ case IMGFMT_I420:
+ case IMGFMT_IYUV:
+ case IMGFMT_CLPL:
+ case IMGFMT_Y800:
+ case IMGFMT_Y8:
+ case IMGFMT_NV12:
+ case IMGFMT_NV21:
+ case IMGFMT_444P:
+ case IMGFMT_422P:
+ case IMGFMT_411P:
+ return ff_vf_next_query_format(vf, fmt);
+ }
+ return 0;
+}
+
+static void uninit(struct vf_instance *vf)
+{
+ free(vf->priv->buf);
+ free(vf->priv);
+}
+
+static int vf_open(vf_instance_t *vf, char *args)
+{
+ vf->control=control;
+ vf->query_format=query_format;
+ vf->put_image=put_image;
+ vf->uninit=uninit;
+
+ vf->priv = malloc(sizeof(struct vf_priv_s));
+ memset(vf->priv, 0, sizeof(struct vf_priv_s));
+ if (args) sscanf(args, "%d:%d", &vf->priv->brightness, &vf->priv->contrast);
+
+ process = process_C;
+#if HAVE_MMX && HAVE_6REGS
+ if(ff_gCpuCaps.hasMMX) process = process_MMX;
+#endif
+
+ return 1;
+}
+
+const vf_info_t ff_vf_info_eq = {
+ "soft video equalizer",
+ "eq",
+ "Richard Felker",
+ "",
+ vf_open,
+};
diff --git a/libavfilter/libmpcodecs/vf_eq2.c b/libavfilter/libmpcodecs/vf_eq2.c
new file mode 100644
index 0000000..0356813
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_eq2.c
@@ -0,0 +1,519 @@
+/*
+ * Software equalizer (brightness, contrast, gamma, saturation)
+ *
+ * Hampa Hug <hampa@hampa.ch> (original LUT gamma/contrast/brightness filter)
+ * Daniel Moreno <comac@comac.darktech.org> (saturation, R/G/B gamma support)
+ * Richard Felker (original MMX contrast/brightness code (vf_eq.c))
+ * Michael Niedermayer <michalni@gmx.at> (LUT16)
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; 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 <string.h>
+#include <math.h>
+#include <inttypes.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "cpudetect.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+
+#define LUT16
+
+/* Per channel parameters */
+typedef struct eq2_param_t {
+ unsigned char lut[256];
+#ifdef LUT16
+ uint16_t lut16[256*256];
+#endif
+ int lut_clean;
+
+ void (*adjust) (struct eq2_param_t *par, unsigned char *dst, unsigned char *src,
+ unsigned w, unsigned h, unsigned dstride, unsigned sstride);
+
+ double c;
+ double b;
+ double g;
+ double w;
+} eq2_param_t;
+
+typedef struct vf_priv_s {
+ eq2_param_t param[3];
+
+ double contrast;
+ double brightness;
+ double saturation;
+
+ double gamma;
+ double gamma_weight;
+ double rgamma;
+ double ggamma;
+ double bgamma;
+
+ unsigned buf_w[3];
+ unsigned buf_h[3];
+ unsigned char *buf[3];
+} vf_eq2_t;
+
+
+static
+void create_lut (eq2_param_t *par)
+{
+ unsigned i;
+ double g, v;
+ double lw, gw;
+
+ g = par->g;
+ gw = par->w;
+ lw = 1.0 - gw;
+
+ if ((g < 0.001) || (g > 1000.0)) {
+ g = 1.0;
+ }
+
+ g = 1.0 / g;
+
+ for (i = 0; i < 256; i++) {
+ v = (double) i / 255.0;
+ v = par->c * (v - 0.5) + 0.5 + par->b;
+
+ if (v <= 0.0) {
+ par->lut[i] = 0;
+ }
+ else {
+ v = v*lw + pow(v, g)*gw;
+
+ if (v >= 1.0) {
+ par->lut[i] = 255;
+ }
+ else {
+ par->lut[i] = (unsigned char) (256.0 * v);
+ }
+ }
+ }
+
+#ifdef LUT16
+ for(i=0; i<256*256; i++){
+ par->lut16[i]= par->lut[i&0xFF] + (par->lut[i>>8]<<8);
+ }
+#endif
+
+ par->lut_clean = 1;
+}
+
+#if HAVE_MMX && HAVE_6REGS
+static
+void affine_1d_MMX (eq2_param_t *par, unsigned char *dst, unsigned char *src,
+ unsigned w, unsigned h, unsigned dstride, unsigned sstride)
+{
+ unsigned i;
+ int contrast, brightness;
+ unsigned dstep, sstep;
+ int pel;
+ short brvec[4];
+ short contvec[4];
+
+// printf("\nmmx: src=%p dst=%p w=%d h=%d ds=%d ss=%d\n",src,dst,w,h,dstride,sstride);
+
+ contrast = (int) (par->c * 256 * 16);
+ brightness = ((int) (100.0 * par->b + 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;
+
+ sstep = sstride - w;
+ dstep = dstride - w;
+
+ while (h-- > 0) {
+ __asm__ volatile (
+ "movq (%5), %%mm3 \n\t"
+ "movq (%6), %%mm4 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "movl %4, %%eax\n\t"
+ ASMALIGN(4)
+ "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 > 0; i--) {
+ pel = ((*src++ * contrast) >> 12) + brightness;
+ if (pel & 768) {
+ pel = (-pel) >> 31;
+ }
+ *dst++ = pel;
+ }
+
+ src += sstep;
+ dst += dstep;
+ }
+
+ __asm__ volatile ( "emms \n\t" ::: "memory" );
+}
+#endif
+
+static
+void apply_lut (eq2_param_t *par, unsigned char *dst, unsigned char *src,
+ unsigned w, unsigned h, unsigned dstride, unsigned sstride)
+{
+ unsigned i, j, w2;
+ unsigned char *lut;
+ uint16_t *lut16;
+
+ if (!par->lut_clean) {
+ create_lut (par);
+ }
+
+ lut = par->lut;
+#ifdef LUT16
+ lut16 = par->lut16;
+ w2= (w>>3)<<2;
+ for (j = 0; j < h; j++) {
+ uint16_t *src16= (uint16_t*)src;
+ uint16_t *dst16= (uint16_t*)dst;
+ for (i = 0; i < w2; i+=4) {
+ dst16[i+0] = lut16[src16[i+0]];
+ dst16[i+1] = lut16[src16[i+1]];
+ dst16[i+2] = lut16[src16[i+2]];
+ dst16[i+3] = lut16[src16[i+3]];
+ }
+ i <<= 1;
+#else
+ w2= (w>>3)<<3;
+ for (j = 0; j < h; j++) {
+ for (i = 0; i < w2; i+=8) {
+ dst[i+0] = lut[src[i+0]];
+ dst[i+1] = lut[src[i+1]];
+ dst[i+2] = lut[src[i+2]];
+ dst[i+3] = lut[src[i+3]];
+ dst[i+4] = lut[src[i+4]];
+ dst[i+5] = lut[src[i+5]];
+ dst[i+6] = lut[src[i+6]];
+ dst[i+7] = lut[src[i+7]];
+ }
+#endif
+ for (; i < w; i++) {
+ dst[i] = lut[src[i]];
+ }
+
+ src += sstride;
+ dst += dstride;
+ }
+}
+
+static
+int put_image (vf_instance_t *vf, mp_image_t *src, double pts)
+{
+ unsigned i;
+ vf_eq2_t *eq2;
+ mp_image_t *dst;
+ unsigned long img_n,img_c;
+
+ eq2 = vf->priv;
+
+ if ((eq2->buf_w[0] != src->w) || (eq2->buf_h[0] != src->h)) {
+ eq2->buf_w[0] = src->w;
+ eq2->buf_h[0] = src->h;
+ eq2->buf_w[1] = eq2->buf_w[2] = src->w >> src->chroma_x_shift;
+ eq2->buf_h[1] = eq2->buf_h[2] = src->h >> src->chroma_y_shift;
+ img_n = eq2->buf_w[0]*eq2->buf_h[0];
+ if(src->num_planes>1){
+ img_c = eq2->buf_w[1]*eq2->buf_h[1];
+ eq2->buf[0] = realloc (eq2->buf[0], img_n + 2*img_c);
+ eq2->buf[1] = eq2->buf[0] + img_n;
+ eq2->buf[2] = eq2->buf[1] + img_c;
+ } else
+ eq2->buf[0] = realloc (eq2->buf[0], img_n);
+ }
+
+ dst = ff_vf_get_image (vf->next, src->imgfmt, MP_IMGTYPE_EXPORT, 0, src->w, src->h);
+
+ for (i = 0; i < ((src->num_planes>1)?3:1); i++) {
+ if (eq2->param[i].adjust) {
+ dst->planes[i] = eq2->buf[i];
+ dst->stride[i] = eq2->buf_w[i];
+
+ eq2->param[i].adjust (&eq2->param[i], dst->planes[i], src->planes[i],
+ eq2->buf_w[i], eq2->buf_h[i], dst->stride[i], src->stride[i]);
+ }
+ else {
+ dst->planes[i] = src->planes[i];
+ dst->stride[i] = src->stride[i];
+ }
+ }
+
+ return ff_vf_next_put_image (vf, dst, pts);
+}
+
+static
+void check_values (eq2_param_t *par)
+{
+ /* yuck! floating point comparisons... */
+
+ if ((par->c == 1.0) && (par->b == 0.0) && (par->g == 1.0)) {
+ par->adjust = NULL;
+ }
+#if HAVE_MMX && HAVE_6REGS
+ else if (par->g == 1.0 && ff_gCpuCaps.hasMMX) {
+ par->adjust = &affine_1d_MMX;
+ }
+#endif
+ else {
+ par->adjust = &apply_lut;
+ }
+}
+
+static
+void print_values (vf_eq2_t *eq2)
+{
+ ff_mp_msg (MSGT_VFILTER, MSGL_V, "vf_eq2: c=%.2f b=%.2f g=%.4f s=%.2f \n",
+ eq2->contrast, eq2->brightness, eq2->gamma, eq2->saturation
+ );
+}
+
+static
+void set_contrast (vf_eq2_t *eq2, double c)
+{
+ eq2->contrast = c;
+ eq2->param[0].c = c;
+ eq2->param[0].lut_clean = 0;
+ check_values (&eq2->param[0]);
+ print_values (eq2);
+}
+
+static
+void set_brightness (vf_eq2_t *eq2, double b)
+{
+ eq2->brightness = b;
+ eq2->param[0].b = b;
+ eq2->param[0].lut_clean = 0;
+ check_values (&eq2->param[0]);
+ print_values (eq2);
+}
+
+static
+void set_gamma (vf_eq2_t *eq2, double g)
+{
+ eq2->gamma = g;
+
+ eq2->param[0].g = eq2->gamma * eq2->ggamma;
+ eq2->param[1].g = sqrt (eq2->bgamma / eq2->ggamma);
+ eq2->param[2].g = sqrt (eq2->rgamma / eq2->ggamma);
+ eq2->param[0].w = eq2->param[1].w = eq2->param[2].w = eq2->gamma_weight;
+
+ eq2->param[0].lut_clean = 0;
+ eq2->param[1].lut_clean = 0;
+ eq2->param[2].lut_clean = 0;
+
+ check_values (&eq2->param[0]);
+ check_values (&eq2->param[1]);
+ check_values (&eq2->param[2]);
+
+ print_values (eq2);
+}
+
+static
+void set_saturation (vf_eq2_t *eq2, double s)
+{
+ eq2->saturation = s;
+
+ eq2->param[1].c = s;
+ eq2->param[2].c = s;
+
+ eq2->param[1].lut_clean = 0;
+ eq2->param[2].lut_clean = 0;
+
+ check_values (&eq2->param[1]);
+ check_values (&eq2->param[2]);
+
+ print_values (eq2);
+}
+
+static
+int control (vf_instance_t *vf, int request, void *data)
+{
+ vf_equalizer_t *eq;
+
+ switch (request) {
+ case VFCTRL_SET_EQUALIZER:
+ eq = (vf_equalizer_t *) data;
+
+ if (strcmp (eq->item, "gamma") == 0) {
+ set_gamma (vf->priv, exp (log (8.0) * eq->value / 100.0));
+ return CONTROL_TRUE;
+ }
+ else if (strcmp (eq->item, "contrast") == 0) {
+ set_contrast (vf->priv, (1.0 / 100.0) * (eq->value + 100));
+ return CONTROL_TRUE;
+ }
+ else if (strcmp (eq->item, "brightness") == 0) {
+ set_brightness (vf->priv, (1.0 / 100.0) * eq->value);
+ return CONTROL_TRUE;
+ }
+ else if (strcmp (eq->item, "saturation") == 0) {
+ set_saturation (vf->priv, (double) (eq->value + 100) / 100.0);
+ return CONTROL_TRUE;
+ }
+ break;
+
+ case VFCTRL_GET_EQUALIZER:
+ eq = (vf_equalizer_t *) data;
+ if (strcmp (eq->item, "gamma") == 0) {
+ eq->value = (int) (100.0 * log (vf->priv->gamma) / log (8.0));
+ return CONTROL_TRUE;
+ }
+ else if (strcmp (eq->item, "contrast") == 0) {
+ eq->value = (int) (100.0 * vf->priv->contrast) - 100;
+ return CONTROL_TRUE;
+ }
+ else if (strcmp (eq->item, "brightness") == 0) {
+ eq->value = (int) (100.0 * vf->priv->brightness);
+ return CONTROL_TRUE;
+ }
+ else if (strcmp (eq->item, "saturation") == 0) {
+ eq->value = (int) (100.0 * vf->priv->saturation) - 100;
+ return CONTROL_TRUE;
+ }
+ break;
+ }
+
+ return ff_vf_next_control (vf, request, data);
+}
+
+static
+int query_format (vf_instance_t *vf, unsigned fmt)
+{
+ switch (fmt) {
+ case IMGFMT_YVU9:
+ case IMGFMT_IF09:
+ case IMGFMT_YV12:
+ case IMGFMT_I420:
+ case IMGFMT_IYUV:
+ case IMGFMT_Y800:
+ case IMGFMT_Y8:
+ case IMGFMT_444P:
+ case IMGFMT_422P:
+ case IMGFMT_411P:
+ return ff_vf_next_query_format (vf, fmt);
+ }
+
+ return 0;
+}
+
+static
+void uninit (vf_instance_t *vf)
+{
+ if (vf->priv) {
+ free (vf->priv->buf[0]);
+ free (vf->priv);
+ }
+}
+
+static
+int vf_open(vf_instance_t *vf, char *args)
+{
+ unsigned i;
+ vf_eq2_t *eq2;
+ double par[8];
+
+ vf->control = control;
+ vf->query_format = query_format;
+ vf->put_image = put_image;
+ vf->uninit = uninit;
+
+ vf->priv = malloc (sizeof (vf_eq2_t));
+ eq2 = vf->priv;
+
+ for (i = 0; i < 3; i++) {
+ eq2->buf[i] = NULL;
+ eq2->buf_w[i] = 0;
+ eq2->buf_h[i] = 0;
+
+ eq2->param[i].adjust = NULL;
+ eq2->param[i].c = 1.0;
+ eq2->param[i].b = 0.0;
+ eq2->param[i].g = 1.0;
+ eq2->param[i].lut_clean = 0;
+ }
+
+ eq2->contrast = 1.0;
+ eq2->brightness = 0.0;
+ eq2->saturation = 1.0;
+
+ eq2->gamma = 1.0;
+ eq2->gamma_weight = 1.0;
+ eq2->rgamma = 1.0;
+ eq2->ggamma = 1.0;
+ eq2->bgamma = 1.0;
+
+ if (args) {
+ par[0] = 1.0;
+ par[1] = 1.0;
+ par[2] = 0.0;
+ par[3] = 1.0;
+ par[4] = 1.0;
+ par[5] = 1.0;
+ par[6] = 1.0;
+ par[7] = 1.0;
+ sscanf (args, "%lf:%lf:%lf:%lf:%lf:%lf:%lf:%lf",
+ par, par + 1, par + 2, par + 3, par + 4, par + 5, par + 6, par + 7
+ );
+
+ eq2->rgamma = par[4];
+ eq2->ggamma = par[5];
+ eq2->bgamma = par[6];
+ eq2->gamma_weight = par[7];
+
+ set_gamma (eq2, par[0]);
+ set_contrast (eq2, par[1]);
+ set_brightness (eq2, par[2]);
+ set_saturation (eq2, par[3]);
+ }
+
+ return 1;
+}
+
+const vf_info_t ff_vf_info_eq2 = {
+ "Software equalizer",
+ "eq2",
+ "Hampa Hug, Daniel Moreno, Richard Felker",
+ "",
+ &vf_open,
+ NULL
+};
diff --git a/libavfilter/libmpcodecs/vf_fspp.c b/libavfilter/libmpcodecs/vf_fspp.c
new file mode 100644
index 0000000..c4a36ef
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_fspp.c
@@ -0,0 +1,2124 @@
+/*
+ * Copyright (C) 2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2005 Nikolaj Poroshin <porosh3@psu.ru>
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * This implementation is based on an algorithm described in
+ * "Aria Nosratinia Embedded Post-Processing for
+ * Enhancement of Compressed Images (1999)"
+ * (http://citeseer.nj.nec.com/nosratinia99embedded.html)
+ * Further, with splitting (i)dct into hor/ver passes, one of them can be
+ * performed once per block, not pixel. This allows for much better speed.
+ */
+
+/*
+ Heavily optimized version of SPP filter by Nikolaj
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <math.h>
+
+#include "config.h"
+
+#include "mp_msg.h"
+#include "cpudetect.h"
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+#include "av_helpers.h"
+#include "libvo/fastmemcpy.h"
+
+#include "libavutil/internal.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mem.h"
+#include "libavutil/x86/asm.h"
+#include "libavcodec/avcodec.h"
+
+#undef free
+#undef malloc
+
+//===========================================================================//
+#define BLOCKSZ 12
+
+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
+};
+
+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, },
+};
+
+struct vf_priv_s { //align 16 !
+ 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 temp_stride;
+ int qp;
+ int mpeg2;
+ int prev_q;
+ uint8_t *src;
+ int16_t *temp;
+ int bframes;
+ char *non_b_qp;
+};
+
+
+#if !HAVE_MMX
+
+//This func reads from 1 slice, 1 and clears 0 & 1
+static void store_slice_c(uint8_t *dst, int16_t *src, int dst_stride, int src_stride, int width, int height, int 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, int dst_stride, int src_stride, int width, int height, int 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(struct vf_priv_s *p,int q)
+{
+ int a;
+ for(a=0;a<64;a++)
+ ((short*)p->threshold_mtx)[a]=q * ((short*)p->threshold_mtx_noq)[a];//ints faster in C
+}
+
+static void column_fidct_c(int16_t* thr_adr, int16_t *data, int16_t *output, int cnt);
+static void row_idct_c(int16_t* workspace,
+ int16_t* output_adr, int output_stride, int cnt);
+static void row_fdct_c(int16_t *data, const uint8_t *pixels, int line_size, int cnt);
+
+//this is rather ugly, but there is no need for function pointers
+#define store_slice_s store_slice_c
+#define store_slice2_s store_slice2_c
+#define mul_thrmat_s mul_thrmat_c
+#define column_fidct_s column_fidct_c
+#define row_idct_s row_idct_c
+#define row_fdct_s row_fdct_c
+
+#else /* HAVE_MMX */
+
+//This func reads from 1 slice, 1 and clears 0 & 1
+static void store_slice_mmx(uint8_t *dst, int16_t *src, long dst_stride, long src_stride, long width, long height, long log2_scale)
+{
+ const uint8_t *od=&dither[0][0];
+ const uint8_t *end=&dither[height][0];
+ width = (width+7)&~7;
+ dst_stride-=width;
+ //src_stride=(src_stride-width)*2;
+ __asm__ volatile(
+ "mov %5, %%"REG_d" \n\t"
+ "mov %6, %%"REG_S" \n\t"
+ "mov %7, %%"REG_D" \n\t"
+ "mov %1, %%"REG_a" \n\t"
+ "movd %%"REG_d", %%mm5 \n\t"
+ "xor $-1, %%"REG_d" \n\t"
+ "mov %%"REG_a", %%"REG_c" \n\t"
+ "add $7, %%"REG_d" \n\t"
+ "neg %%"REG_a" \n\t"
+ "sub %0, %%"REG_c" \n\t"
+ "add %%"REG_c", %%"REG_c" \n\t"
+ "movd %%"REG_d", %%mm2 \n\t"
+ "mov %%"REG_c", %1 \n\t"
+ "mov %2, %%"REG_d" \n\t"
+ "shl $4, %%"REG_a" \n\t"
+
+ "2: \n\t"
+ "movq (%%"REG_d"), %%mm3 \n\t"
+ "movq %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ "punpcklbw %%mm7, %%mm3 \n\t"
+ "punpckhbw %%mm7, %%mm4 \n\t"
+ "mov %0, %%"REG_c" \n\t"
+ "psraw %%mm5, %%mm3 \n\t"
+ "psraw %%mm5, %%mm4 \n\t"
+ "1: \n\t"
+ "movq %%mm7, (%%"REG_S",%%"REG_a") \n\t"
+ "movq (%%"REG_S"), %%mm0 \n\t"
+ "movq 8(%%"REG_S"), %%mm1 \n\t"
+
+ "movq %%mm7, 8(%%"REG_S",%%"REG_a") \n\t"
+ "paddw %%mm3, %%mm0 \n\t"
+ "paddw %%mm4, %%mm1 \n\t"
+
+ "movq %%mm7, (%%"REG_S") \n\t"
+ "psraw %%mm2, %%mm0 \n\t"
+ "psraw %%mm2, %%mm1 \n\t"
+
+ "movq %%mm7, 8(%%"REG_S") \n\t"
+ "packuswb %%mm1, %%mm0 \n\t"
+ "add $16, %%"REG_S" \n\t"
+
+ "movq %%mm0, (%%"REG_D") \n\t"
+ "add $8, %%"REG_D" \n\t"
+ "sub $8, %%"REG_c" \n\t"
+ "jg 1b \n\t"
+ "add %1, %%"REG_S" \n\t"
+ "add $8, %%"REG_d" \n\t"
+ "add %3, %%"REG_D" \n\t"
+ "cmp %4, %%"REG_d" \n\t"
+ "jl 2b \n\t"
+
+ :
+ : "m" (width), "m" (src_stride), "erm" (od), "m" (dst_stride), "erm" (end),
+ "m" (log2_scale), "m" (src), "m" (dst) //input
+ : "%"REG_a, "%"REG_c, "%"REG_d, "%"REG_S, "%"REG_D
+ );
+}
+
+//This func reads from 2 slices, 0 & 2 and clears 2-nd
+static void store_slice2_mmx(uint8_t *dst, int16_t *src, long dst_stride, long src_stride, long width, long height, long log2_scale)
+{
+ const uint8_t *od=&dither[0][0];
+ const uint8_t *end=&dither[height][0];
+ width = (width+7)&~7;
+ dst_stride-=width;
+ //src_stride=(src_stride-width)*2;
+ __asm__ volatile(
+ "mov %5, %%"REG_d" \n\t"
+ "mov %6, %%"REG_S" \n\t"
+ "mov %7, %%"REG_D" \n\t"
+ "mov %1, %%"REG_a" \n\t"
+ "movd %%"REG_d", %%mm5 \n\t"
+ "xor $-1, %%"REG_d" \n\t"
+ "mov %%"REG_a", %%"REG_c" \n\t"
+ "add $7, %%"REG_d" \n\t"
+ "sub %0, %%"REG_c" \n\t"
+ "add %%"REG_c", %%"REG_c" \n\t"
+ "movd %%"REG_d", %%mm2 \n\t"
+ "mov %%"REG_c", %1 \n\t"
+ "mov %2, %%"REG_d" \n\t"
+ "shl $5, %%"REG_a" \n\t"
+
+ "2: \n\t"
+ "movq (%%"REG_d"), %%mm3 \n\t"
+ "movq %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ "punpcklbw %%mm7, %%mm3 \n\t"
+ "punpckhbw %%mm7, %%mm4 \n\t"
+ "mov %0, %%"REG_c" \n\t"
+ "psraw %%mm5, %%mm3 \n\t"
+ "psraw %%mm5, %%mm4 \n\t"
+ "1: \n\t"
+ "movq (%%"REG_S"), %%mm0 \n\t"
+ "movq 8(%%"REG_S"), %%mm1 \n\t"
+ "paddw %%mm3, %%mm0 \n\t"
+
+ "paddw (%%"REG_S",%%"REG_a"), %%mm0 \n\t"
+ "paddw %%mm4, %%mm1 \n\t"
+ "movq 8(%%"REG_S",%%"REG_a"), %%mm6 \n\t"
+
+ "movq %%mm7, (%%"REG_S",%%"REG_a") \n\t"
+ "psraw %%mm2, %%mm0 \n\t"
+ "paddw %%mm6, %%mm1 \n\t"
+
+ "movq %%mm7, 8(%%"REG_S",%%"REG_a") \n\t"
+ "psraw %%mm2, %%mm1 \n\t"
+ "packuswb %%mm1, %%mm0 \n\t"
+
+ "movq %%mm0, (%%"REG_D") \n\t"
+ "add $16, %%"REG_S" \n\t"
+ "add $8, %%"REG_D" \n\t"
+ "sub $8, %%"REG_c" \n\t"
+ "jg 1b \n\t"
+ "add %1, %%"REG_S" \n\t"
+ "add $8, %%"REG_d" \n\t"
+ "add %3, %%"REG_D" \n\t"
+ "cmp %4, %%"REG_d" \n\t"
+ "jl 2b \n\t"
+
+ :
+ : "m" (width), "m" (src_stride), "erm" (od), "m" (dst_stride), "erm" (end),
+ "m" (log2_scale), "m" (src), "m" (dst) //input
+ : "%"REG_a, "%"REG_c, "%"REG_d, "%"REG_D, "%"REG_S
+ );
+}
+
+static void mul_thrmat_mmx(struct vf_priv_s *p, int q)
+{
+ uint64_t *adr=&p->threshold_mtx_noq[0];
+ __asm__ volatile(
+ "movd %0, %%mm7 \n\t"
+ "add $8*8*2, %%"REG_D" \n\t"
+ "movq 0*8(%%"REG_S"), %%mm0 \n\t"
+ "punpcklwd %%mm7, %%mm7 \n\t"
+ "movq 1*8(%%"REG_S"), %%mm1 \n\t"
+ "punpckldq %%mm7, %%mm7 \n\t"
+ "pmullw %%mm7, %%mm0 \n\t"
+
+ "movq 2*8(%%"REG_S"), %%mm2 \n\t"
+ "pmullw %%mm7, %%mm1 \n\t"
+
+ "movq 3*8(%%"REG_S"), %%mm3 \n\t"
+ "pmullw %%mm7, %%mm2 \n\t"
+
+ "movq %%mm0, 0*8(%%"REG_D") \n\t"
+ "movq 4*8(%%"REG_S"), %%mm4 \n\t"
+ "pmullw %%mm7, %%mm3 \n\t"
+
+ "movq %%mm1, 1*8(%%"REG_D") \n\t"
+ "movq 5*8(%%"REG_S"), %%mm5 \n\t"
+ "pmullw %%mm7, %%mm4 \n\t"
+
+ "movq %%mm2, 2*8(%%"REG_D") \n\t"
+ "movq 6*8(%%"REG_S"), %%mm6 \n\t"
+ "pmullw %%mm7, %%mm5 \n\t"
+
+ "movq %%mm3, 3*8(%%"REG_D") \n\t"
+ "movq 7*8+0*8(%%"REG_S"), %%mm0 \n\t"
+ "pmullw %%mm7, %%mm6 \n\t"
+
+ "movq %%mm4, 4*8(%%"REG_D") \n\t"
+ "movq 7*8+1*8(%%"REG_S"), %%mm1 \n\t"
+ "pmullw %%mm7, %%mm0 \n\t"
+
+ "movq %%mm5, 5*8(%%"REG_D") \n\t"
+ "movq 7*8+2*8(%%"REG_S"), %%mm2 \n\t"
+ "pmullw %%mm7, %%mm1 \n\t"
+
+ "movq %%mm6, 6*8(%%"REG_D") \n\t"
+ "movq 7*8+3*8(%%"REG_S"), %%mm3 \n\t"
+ "pmullw %%mm7, %%mm2 \n\t"
+
+ "movq %%mm0, 7*8+0*8(%%"REG_D") \n\t"
+ "movq 7*8+4*8(%%"REG_S"), %%mm4 \n\t"
+ "pmullw %%mm7, %%mm3 \n\t"
+
+ "movq %%mm1, 7*8+1*8(%%"REG_D") \n\t"
+ "movq 7*8+5*8(%%"REG_S"), %%mm5 \n\t"
+ "pmullw %%mm7, %%mm4 \n\t"
+
+ "movq %%mm2, 7*8+2*8(%%"REG_D") \n\t"
+ "movq 7*8+6*8(%%"REG_S"), %%mm6 \n\t"
+ "pmullw %%mm7, %%mm5 \n\t"
+
+ "movq %%mm3, 7*8+3*8(%%"REG_D") \n\t"
+ "movq 14*8+0*8(%%"REG_S"), %%mm0 \n\t"
+ "pmullw %%mm7, %%mm6 \n\t"
+
+ "movq %%mm4, 7*8+4*8(%%"REG_D") \n\t"
+ "movq 14*8+1*8(%%"REG_S"), %%mm1 \n\t"
+ "pmullw %%mm7, %%mm0 \n\t"
+
+ "movq %%mm5, 7*8+5*8(%%"REG_D") \n\t"
+ "pmullw %%mm7, %%mm1 \n\t"
+
+ "movq %%mm6, 7*8+6*8(%%"REG_D") \n\t"
+ "movq %%mm0, 14*8+0*8(%%"REG_D") \n\t"
+ "movq %%mm1, 14*8+1*8(%%"REG_D") \n\t"
+
+ : "+g" (q), "+S" (adr), "+D" (adr)
+ :
+ );
+}
+
+static void column_fidct_mmx(int16_t* thr_adr, int16_t *data, int16_t *output, int cnt);
+static void row_idct_mmx(int16_t* workspace,
+ int16_t* output_adr, int output_stride, int cnt);
+static void row_fdct_mmx(int16_t *data, const uint8_t *pixels, int line_size, int cnt);
+
+#define store_slice_s store_slice_mmx
+#define store_slice2_s store_slice2_mmx
+#define mul_thrmat_s mul_thrmat_mmx
+#define column_fidct_s column_fidct_mmx
+#define row_idct_s row_idct_mmx
+#define row_fdct_s row_fdct_mmx
+#endif // HAVE_MMX
+
+static void filter(struct vf_priv_s *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);//((width+16+15)&(~15))
+ const int step=6-p->log2_count;
+ const int qps= 3 + 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);
+
+ //p->src=src-src_stride*8-8;//!
+ if (!src || !dst) return; // HACK avoid crash for Y8 colourspace
+ for(y=0; y<height; y++){
+ int index= 8 + 8*stride + y*stride;
+ fast_memcpy(p->src + index, src + y*src_stride, width);//this line can be avoided by using DR & user fr.buffers
+ 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++){
+ fast_memcpy(p->src + ( 7-y)*stride, p->src + ( y+8)*stride, stride);
+ fast_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
+ qy=y-4;
+ if (qy>height-1) qy=height-1;
+ if (qy<0) qy=0;
+ qy=(qy>>qps)*qp_stride;
+ row_fdct_s(block, p->src + y*stride +2-(y&1), stride, 2);
+ for(x0=0; x0<width+8-8*(BLOCKSZ-1); x0+=8*(BLOCKSZ-1)){
+ row_fdct_s(block+8*8, p->src + y*stride+8+x0 +2-(y&1), stride, 2*(BLOCKSZ-1));
+ if(p->qp)
+ column_fidct_s((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>>qps)];
+ t=norm_qscale(t, p->mpeg2);
+ if (t!=p->prev_q) p->prev_q=t, mul_thrmat_s(p, t);
+ column_fidct_s((int16_t*)(&p->threshold_mtx[0]), block+x*8, block3+x*8, 8); //yes, this is a HOTSPOT
+ }
+ row_idct_s(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)
+ row_fdct_s(block+8*8, p->src + y*stride+8+x0 +2-(y&1), stride, (es-4)>>2);
+ column_fidct_s((int16_t*)(&p->threshold_mtx[0]), block, block3, es&(~1));
+ row_idct_s(block3+0*8, p->temp + (y&15)*stride+x0+2-(y&1), stride, es>>2);
+ {const int y1=y-8+step;//l5-7 l4-6
+ if (!(y1&7) && y1) {
+ if (y1&8) store_slice_s(dst + (y1-8)*dst_stride, p->temp+ 8 +8*stride,
+ dst_stride, stride, width, 8, 5-p->log2_count);
+ else store_slice2_s(dst + (y1-8)*dst_stride, p->temp+ 8 +0*stride,
+ dst_stride, stride, width, 8, 5-p->log2_count);
+ } }
+ }
+
+ if (y&7) { // == height & 7
+ if (y&8) store_slice_s(dst + ((y-8)&~7)*dst_stride, p->temp+ 8 +8*stride,
+ dst_stride, stride, width, y&7, 5-p->log2_count);
+ else store_slice2_s(dst + ((y-8)&~7)*dst_stride, p->temp+ 8 +0*stride,
+ dst_stride, stride, width, y&7, 5-p->log2_count);
+ }
+}
+
+static int config(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt)
+{
+ int h= (height+16+15)&(~15);
+
+ vf->priv->temp_stride= (width+16+15)&(~15);
+ vf->priv->temp= (int16_t*)av_mallocz(vf->priv->temp_stride*3*8*sizeof(int16_t));
+ //this can also be avoided, see above
+ vf->priv->src = (uint8_t*)av_malloc(vf->priv->temp_stride*h*sizeof(uint8_t));
+
+ return ff_vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
+}
+
+static void get_image(struct vf_instance *vf, mp_image_t *mpi)
+{
+ if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
+ // ok, we can do pp in-place (or pp disabled):
+ vf->dmpi=ff_vf_get_image(vf->next,mpi->imgfmt,
+ mpi->type, mpi->flags, mpi->width, mpi->height);
+ mpi->planes[0]=vf->dmpi->planes[0];
+ mpi->stride[0]=vf->dmpi->stride[0];
+ mpi->width=vf->dmpi->width;
+ if(mpi->flags&MP_IMGFLAG_PLANAR){
+ mpi->planes[1]=vf->dmpi->planes[1];
+ mpi->planes[2]=vf->dmpi->planes[2];
+ mpi->stride[1]=vf->dmpi->stride[1];
+ mpi->stride[2]=vf->dmpi->stride[2];
+ }
+ mpi->flags|=MP_IMGFLAG_DIRECT;
+}
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
+{
+ mp_image_t *dmpi;
+ if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
+ // no DR, so get a new image! hope we'll get DR buffer:
+ dmpi=ff_vf_get_image(vf->next,mpi->imgfmt,
+ MP_IMGTYPE_TEMP,
+ MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
+ mpi->width,mpi->height);
+ ff_vf_clone_mpi_attributes(dmpi, mpi);
+ }else{
+ dmpi=vf->dmpi;
+ }
+
+ vf->priv->mpeg2= mpi->qscale_type;
+ if(mpi->pict_type != 3 && mpi->qscale && !vf->priv->qp){
+ int w = mpi->qstride;
+ int h = (mpi->h + 15) >> 4;
+ if (!w) {
+ w = (mpi->w + 15) >> 4;
+ h = 1;
+ }
+ if(!vf->priv->non_b_qp)
+ vf->priv->non_b_qp= malloc(w*h);
+ fast_memcpy(vf->priv->non_b_qp, mpi->qscale, w*h);
+ }
+ if(vf->priv->log2_count || !(mpi->flags&MP_IMGFLAG_DIRECT)){
+ char *qp_tab= vf->priv->non_b_qp;
+ if(vf->priv->bframes || !qp_tab)
+ qp_tab= mpi->qscale;
+
+ if(qp_tab || vf->priv->qp){
+ filter(vf->priv, dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0],
+ mpi->w, mpi->h, qp_tab, mpi->qstride, 1);
+ filter(vf->priv, dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1],
+ mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, qp_tab, mpi->qstride, 0);
+ filter(vf->priv, dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2],
+ mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, qp_tab, mpi->qstride, 0);
+ }else{
+ memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, dmpi->stride[0], mpi->stride[0]);
+ memcpy_pic(dmpi->planes[1], mpi->planes[1], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[1], mpi->stride[1]);
+ memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[2], mpi->stride[2]);
+ }
+ }
+
+#if HAVE_MMX
+ if(ff_gCpuCaps.hasMMX) __asm__ volatile ("emms\n\t");
+#endif
+#if HAVE_MMX2
+ if(ff_gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t");
+#endif
+ return ff_vf_next_put_image(vf,dmpi, pts);
+}
+
+static void uninit(struct vf_instance *vf)
+{
+ if(!vf->priv) return;
+
+ av_free(vf->priv->temp);
+ vf->priv->temp= NULL;
+ av_free(vf->priv->src);
+ vf->priv->src= NULL;
+ //free(vf->priv->avctx);
+ //vf->priv->avctx= NULL;
+ free(vf->priv->non_b_qp);
+ vf->priv->non_b_qp= NULL;
+
+ av_free(vf->priv);
+ vf->priv=NULL;
+}
+
+//===========================================================================//
+
+static int query_format(struct vf_instance *vf, unsigned int fmt)
+{
+ switch(fmt){
+ case IMGFMT_YVU9:
+ case IMGFMT_IF09:
+ case IMGFMT_YV12:
+ case IMGFMT_I420:
+ case IMGFMT_IYUV:
+ case IMGFMT_CLPL:
+ case IMGFMT_Y800:
+ case IMGFMT_Y8:
+ case IMGFMT_444P:
+ case IMGFMT_422P:
+ case IMGFMT_411P:
+ return ff_vf_next_query_format(vf,fmt);
+ }
+ return 0;
+}
+
+static int control(struct vf_instance *vf, int request, void* data)
+{
+ switch(request){
+ case VFCTRL_QUERY_MAX_PP_LEVEL:
+ return 5;
+ case VFCTRL_SET_PP_LEVEL:
+ vf->priv->log2_count= *((unsigned int*)data);
+ if (vf->priv->log2_count < 4) vf->priv->log2_count=4;
+ return CONTROL_TRUE;
+ }
+ return ff_vf_next_control(vf,request,data);
+}
+
+static int vf_open(vf_instance_t *vf, char *args)
+{
+ int i=0, bias;
+ int custom_threshold_m[64];
+ int log2c=-1;
+
+ vf->config=config;
+ vf->put_image=put_image;
+ vf->get_image=get_image;
+ vf->query_format=query_format;
+ vf->uninit=uninit;
+ vf->control= control;
+ vf->priv=av_mallocz(sizeof(struct vf_priv_s));//assumes align 16 !
+
+ ff_init_avcodec();
+
+ //vf->priv->avctx= avcodec_alloc_context();
+ //dsputil_init(&vf->priv->dsp, vf->priv->avctx);
+
+ vf->priv->log2_count= 4;
+ vf->priv->bframes = 0;
+
+ if (args) sscanf(args, "%d:%d:%d:%d", &log2c, &vf->priv->qp, &i, &vf->priv->bframes);
+
+ if( log2c >=4 && log2c <=5 )
+ vf->priv->log2_count = log2c;
+ else if( log2c >= 6 )
+ vf->priv->log2_count = 5;
+
+ if(vf->priv->qp < 0)
+ vf->priv->qp = 0;
+
+ if (i < -15) i = -15;
+ if (i > 32) i = 32;
+
+ bias= (1<<4)+i; //regulable
+ vf->priv->prev_q=0;
+ //
+ for(i=0;i<64;i++) //FIXME: tune custom_threshold[] and remove this !
+ custom_threshold_m[i]=(int)(custom_threshold[i]*(bias/71.)+ 0.5);
+ for(i=0;i<8;i++){
+ vf->priv->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);
+ vf->priv->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 (vf->priv->qp) vf->priv->prev_q=vf->priv->qp, mul_thrmat_s(vf->priv, vf->priv->qp);
+
+ return 1;
+}
+
+const vf_info_t ff_vf_info_fspp = {
+ "fast simple postprocess",
+ "fspp",
+ "Michael Niedermayer, Nikolaj Poroshin",
+ "",
+ vf_open,
+ NULL
+};
+
+//====================================================================
+//Specific spp's dct, idct and threshold functions
+//I'd prefer to have them in the separate file.
+
+//#define MANGLE(a) #a
+
+//typedef int16_t int16_t; //! only int16_t
+
+#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)
+
+#if HAVE_MMX
+
+DECLARE_ASM_CONST(8, uint64_t, MM_FIX_0_382683433)=FIX64(0.382683433, 14);
+DECLARE_ALIGNED(8, uint64_t, ff_MM_FIX_0_541196100)=FIX64(0.541196100, 14);
+DECLARE_ALIGNED(8, uint64_t, ff_MM_FIX_0_707106781)=FIX64(0.707106781, 14);
+DECLARE_ASM_CONST(8, uint64_t, MM_FIX_1_306562965)=FIX64(1.306562965, 14);
+
+DECLARE_ASM_CONST(8, uint64_t, MM_FIX_1_414213562_A)=FIX64(1.414213562, 14);
+
+DECLARE_ASM_CONST(8, uint64_t, MM_FIX_1_847759065)=FIX64(1.847759065, 13);
+DECLARE_ASM_CONST(8, uint64_t, MM_FIX_2_613125930)=FIX64(-2.613125930, 13); //-
+DECLARE_ASM_CONST(8, uint64_t, MM_FIX_1_414213562)=FIX64(1.414213562, 13);
+DECLARE_ASM_CONST(8, uint64_t, MM_FIX_1_082392200)=FIX64(1.082392200, 13);
+//for t3,t5,t7 == 0 shortcut
+DECLARE_ASM_CONST(8, uint64_t, MM_FIX_0_847759065)=FIX64(0.847759065, 14);
+DECLARE_ASM_CONST(8, uint64_t, MM_FIX_0_566454497)=FIX64(0.566454497, 14);
+DECLARE_ASM_CONST(8, uint64_t, MM_FIX_0_198912367)=FIX64(0.198912367, 14);
+
+DECLARE_ASM_CONST(8, uint64_t, MM_DESCALE_RND)=C64(4);
+DECLARE_ASM_CONST(8, uint64_t, MM_2)=C64(2);
+
+#else /* !HAVE_MMX */
+
+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);
+
+#endif
+
+#if !HAVE_MMX
+
+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;
+ }
+}
+
+#else /* HAVE_MMX */
+
+static void column_fidct_mmx(int16_t* thr_adr, int16_t *data, int16_t *output, int cnt)
+{
+ DECLARE_ALIGNED(8, uint64_t, temps)[4];
+ __asm__ volatile(
+ ASMALIGN(4)
+ "1: \n\t"
+ "movq "DCTSIZE_S"*0*2(%%"REG_S"), %%mm1 \n\t"
+ //
+ "movq "DCTSIZE_S"*3*2(%%"REG_S"), %%mm7 \n\t"
+ "movq %%mm1, %%mm0 \n\t"
+
+ "paddw "DCTSIZE_S"*7*2(%%"REG_S"), %%mm1 \n\t" //t0
+ "movq %%mm7, %%mm3 \n\t"
+
+ "paddw "DCTSIZE_S"*4*2(%%"REG_S"), %%mm7 \n\t" //t3
+ "movq %%mm1, %%mm5 \n\t"
+
+ "movq "DCTSIZE_S"*1*2(%%"REG_S"), %%mm6 \n\t"
+ "psubw %%mm7, %%mm1 \n\t" //t13
+
+ "movq "DCTSIZE_S"*2*2(%%"REG_S"), %%mm2 \n\t"
+ "movq %%mm6, %%mm4 \n\t"
+
+ "paddw "DCTSIZE_S"*6*2(%%"REG_S"), %%mm6 \n\t" //t1
+ "paddw %%mm7, %%mm5 \n\t" //t10
+
+ "paddw "DCTSIZE_S"*5*2(%%"REG_S"), %%mm2 \n\t" //t2
+ "movq %%mm6, %%mm7 \n\t"
+
+ "paddw %%mm2, %%mm6 \n\t" //t11
+ "psubw %%mm2, %%mm7 \n\t" //t12
+
+ "movq %%mm5, %%mm2 \n\t"
+ "paddw %%mm6, %%mm5 \n\t" //d0
+ // i0 t13 t12 i3 i1 d0 - d4
+ "psubw %%mm6, %%mm2 \n\t" //d4
+ "paddw %%mm1, %%mm7 \n\t"
+
+ "movq 4*16(%%"REG_d"), %%mm6 \n\t"
+ "psllw $2, %%mm7 \n\t"
+
+ "psubw 0*16(%%"REG_d"), %%mm5 \n\t"
+ "psubw %%mm6, %%mm2 \n\t"
+
+ "paddusw 0*16(%%"REG_d"), %%mm5 \n\t"
+ "paddusw %%mm6, %%mm2 \n\t"
+
+ "pmulhw "MANGLE(ff_MM_FIX_0_707106781)", %%mm7 \n\t"
+ //
+ "paddw 0*16(%%"REG_d"), %%mm5 \n\t"
+ "paddw %%mm6, %%mm2 \n\t"
+
+ "psubusw 0*16(%%"REG_d"), %%mm5 \n\t"
+ "psubusw %%mm6, %%mm2 \n\t"
+
+//This func is totally compute-bound, operates at huge speed. So, DC shortcut
+// at this place isn't worthwhile due to BTB miss penalty (checked on Pent. 3).
+//However, typical numbers: nondc - 29%%, dc - 46%%, zero - 25%%. All <> 0 case is very rare.
+ "paddw "MANGLE(MM_2)", %%mm5 \n\t"
+ "movq %%mm2, %%mm6 \n\t"
+
+ "paddw %%mm5, %%mm2 \n\t"
+ "psubw %%mm6, %%mm5 \n\t"
+
+ "movq %%mm1, %%mm6 \n\t"
+ "paddw %%mm7, %%mm1 \n\t" //d2
+
+ "psubw 2*16(%%"REG_d"), %%mm1 \n\t"
+ "psubw %%mm7, %%mm6 \n\t" //d6
+
+ "movq 6*16(%%"REG_d"), %%mm7 \n\t"
+ "psraw $2, %%mm5 \n\t"
+
+ "paddusw 2*16(%%"REG_d"), %%mm1 \n\t"
+ "psubw %%mm7, %%mm6 \n\t"
+ // t7 d2 /t11 t4 t6 - d6 /t10
+
+ "paddw 2*16(%%"REG_d"), %%mm1 \n\t"
+ "paddusw %%mm7, %%mm6 \n\t"
+
+ "psubusw 2*16(%%"REG_d"), %%mm1 \n\t"
+ "paddw %%mm7, %%mm6 \n\t"
+
+ "psubw "DCTSIZE_S"*4*2(%%"REG_S"), %%mm3 \n\t"
+ "psubusw %%mm7, %%mm6 \n\t"
+
+ //movq [edi+"DCTSIZE_S"*2*2], mm1
+ //movq [edi+"DCTSIZE_S"*6*2], mm6
+ "movq %%mm1, %%mm7 \n\t"
+ "psraw $2, %%mm2 \n\t"
+
+ "psubw "DCTSIZE_S"*6*2(%%"REG_S"), %%mm4 \n\t"
+ "psubw %%mm6, %%mm1 \n\t"
+
+ "psubw "DCTSIZE_S"*7*2(%%"REG_S"), %%mm0 \n\t"
+ "paddw %%mm7, %%mm6 \n\t" //'t13
+
+ "psraw $2, %%mm6 \n\t" //paddw mm6, MM_2 !! ---
+ "movq %%mm2, %%mm7 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_1_414213562_A)", %%mm1 \n\t"
+ "paddw %%mm6, %%mm2 \n\t" //'t0
+
+ "movq %%mm2, 0*8+%3 \n\t" //!
+ "psubw %%mm6, %%mm7 \n\t" //'t3
+
+ "movq "DCTSIZE_S"*2*2(%%"REG_S"), %%mm2 \n\t"
+ "psubw %%mm6, %%mm1 \n\t" //'t12
+
+ "psubw "DCTSIZE_S"*5*2(%%"REG_S"), %%mm2 \n\t" //t5
+ "movq %%mm5, %%mm6 \n\t"
+
+ "movq %%mm7, 3*8+%3 \n\t"
+ "paddw %%mm2, %%mm3 \n\t" //t10
+
+ "paddw %%mm4, %%mm2 \n\t" //t11
+ "paddw %%mm0, %%mm4 \n\t" //t12
+
+ "movq %%mm3, %%mm7 \n\t"
+ "psubw %%mm4, %%mm3 \n\t"
+
+ "psllw $2, %%mm3 \n\t"
+ "psllw $2, %%mm7 \n\t" //opt for P6
+
+ "pmulhw "MANGLE(MM_FIX_0_382683433)", %%mm3 \n\t"
+ "psllw $2, %%mm4 \n\t"
+
+ "pmulhw "MANGLE(ff_MM_FIX_0_541196100)", %%mm7 \n\t"
+ "psllw $2, %%mm2 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_1_306562965)", %%mm4 \n\t"
+ "paddw %%mm1, %%mm5 \n\t" //'t1
+
+ "pmulhw "MANGLE(ff_MM_FIX_0_707106781)", %%mm2 \n\t"
+ "psubw %%mm1, %%mm6 \n\t" //'t2
+ // t7 't12 't11 t4 t6 - 't13 't10 ---
+
+ "paddw %%mm3, %%mm7 \n\t" //z2
+
+ "movq %%mm5, 1*8+%3 \n\t"
+ "paddw %%mm3, %%mm4 \n\t" //z4
+
+ "movq 3*16(%%"REG_d"), %%mm3 \n\t"
+ "movq %%mm0, %%mm1 \n\t"
+
+ "movq %%mm6, 2*8+%3 \n\t"
+ "psubw %%mm2, %%mm1 \n\t" //z13
+
+//===
+ "paddw %%mm2, %%mm0 \n\t" //z11
+ "movq %%mm1, %%mm5 \n\t"
+
+ "movq 5*16(%%"REG_d"), %%mm2 \n\t"
+ "psubw %%mm7, %%mm1 \n\t" //d3
+
+ "paddw %%mm7, %%mm5 \n\t" //d5
+ "psubw %%mm3, %%mm1 \n\t"
+
+ "movq 1*16(%%"REG_d"), %%mm7 \n\t"
+ "psubw %%mm2, %%mm5 \n\t"
+
+ "movq %%mm0, %%mm6 \n\t"
+ "paddw %%mm4, %%mm0 \n\t" //d1
+
+ "paddusw %%mm3, %%mm1 \n\t"
+ "psubw %%mm4, %%mm6 \n\t" //d7
+
+ // d1 d3 - - - d5 d7 -
+ "movq 7*16(%%"REG_d"), %%mm4 \n\t"
+ "psubw %%mm7, %%mm0 \n\t"
+
+ "psubw %%mm4, %%mm6 \n\t"
+ "paddusw %%mm2, %%mm5 \n\t"
+
+ "paddusw %%mm4, %%mm6 \n\t"
+ "paddw %%mm3, %%mm1 \n\t"
+
+ "paddw %%mm2, %%mm5 \n\t"
+ "paddw %%mm4, %%mm6 \n\t"
+
+ "psubusw %%mm3, %%mm1 \n\t"
+ "psubusw %%mm2, %%mm5 \n\t"
+
+ "psubusw %%mm4, %%mm6 \n\t"
+ "movq %%mm1, %%mm4 \n\t"
+
+ "por %%mm5, %%mm4 \n\t"
+ "paddusw %%mm7, %%mm0 \n\t"
+
+ "por %%mm6, %%mm4 \n\t"
+ "paddw %%mm7, %%mm0 \n\t"
+
+ "packssdw %%mm4, %%mm4 \n\t"
+ "psubusw %%mm7, %%mm0 \n\t"
+
+ "movd %%mm4, %%"REG_a" \n\t"
+ "or %%"REG_a", %%"REG_a" \n\t"
+ "jnz 2f \n\t"
+ //movq [edi+"DCTSIZE_S"*3*2], mm1
+ //movq [edi+"DCTSIZE_S"*5*2], mm5
+ //movq [edi+"DCTSIZE_S"*1*2], mm0
+ //movq [edi+"DCTSIZE_S"*7*2], mm6
+ // t4 t5 - - - t6 t7 -
+ //--- t4 (mm0) may be <>0; mm1, mm5, mm6 == 0
+//Typical numbers: nondc - 19%%, dc - 26%%, zero - 55%%. zero case alone isn't worthwhile
+ "movq 0*8+%3, %%mm4 \n\t"
+ "movq %%mm0, %%mm1 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_0_847759065)", %%mm0 \n\t" //tmp6
+ "movq %%mm1, %%mm2 \n\t"
+
+ "movq "DCTSIZE_S"*0*2(%%"REG_D"), %%mm5 \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_0_566454497)", %%mm1 \n\t" //tmp5
+ "paddw %%mm4, %%mm5 \n\t"
+
+ "movq 1*8+%3, %%mm6 \n\t"
+ //paddw mm3, MM_2
+ "psraw $2, %%mm3 \n\t" //tmp7
+
+ "pmulhw "MANGLE(MM_FIX_0_198912367)", %%mm2 \n\t" //-tmp4
+ "psubw %%mm3, %%mm4 \n\t"
+
+ "movq "DCTSIZE_S"*1*2(%%"REG_D"), %%mm7 \n\t"
+ "paddw %%mm3, %%mm5 \n\t"
+
+ "movq %%mm4, "DCTSIZE_S"*7*2(%%"REG_D") \n\t"
+ "paddw %%mm6, %%mm7 \n\t"
+
+ "movq 2*8+%3, %%mm3 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+
+ "movq "DCTSIZE_S"*2*2(%%"REG_D"), %%mm4 \n\t"
+ "paddw %%mm0, %%mm7 \n\t"
+
+ "movq %%mm5, "DCTSIZE_S"*0*2(%%"REG_D") \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+
+ "movq %%mm6, "DCTSIZE_S"*6*2(%%"REG_D") \n\t"
+ "psubw %%mm1, %%mm3 \n\t"
+
+ "movq "DCTSIZE_S"*5*2(%%"REG_D"), %%mm5 \n\t"
+ "paddw %%mm1, %%mm4 \n\t"
+
+ "movq "DCTSIZE_S"*3*2(%%"REG_D"), %%mm6 \n\t"
+ "paddw %%mm3, %%mm5 \n\t"
+
+ "movq 3*8+%3, %%mm0 \n\t"
+ "add $8, %%"REG_S" \n\t"
+
+ "movq %%mm7, "DCTSIZE_S"*1*2(%%"REG_D") \n\t"
+ "paddw %%mm0, %%mm6 \n\t"
+
+ "movq %%mm4, "DCTSIZE_S"*2*2(%%"REG_D") \n\t"
+ "psubw %%mm2, %%mm0 \n\t"
+
+ "movq "DCTSIZE_S"*4*2(%%"REG_D"), %%mm7 \n\t"
+ "paddw %%mm2, %%mm6 \n\t"
+
+ "movq %%mm5, "DCTSIZE_S"*5*2(%%"REG_D") \n\t"
+ "paddw %%mm0, %%mm7 \n\t"
+
+ "movq %%mm6, "DCTSIZE_S"*3*2(%%"REG_D") \n\t"
+
+ "movq %%mm7, "DCTSIZE_S"*4*2(%%"REG_D") \n\t"
+ "add $8, %%"REG_D" \n\t"
+ "jmp 4f \n\t"
+
+ "2: \n\t"
+ //--- non DC2
+ //psraw mm1, 2 w/o it -> offset. thr1, thr1, thr1 (actually thr1, thr1, thr1-1)
+ //psraw mm5, 2
+ //psraw mm0, 2
+ //psraw mm6, 2
+ "movq %%mm5, %%mm3 \n\t"
+ "psubw %%mm1, %%mm5 \n\t"
+
+ "psllw $1, %%mm5 \n\t" //'z10
+ "paddw %%mm1, %%mm3 \n\t" //'z13
+
+ "movq %%mm0, %%mm2 \n\t"
+ "psubw %%mm6, %%mm0 \n\t"
+
+ "movq %%mm5, %%mm1 \n\t"
+ "psllw $1, %%mm0 \n\t" //'z12
+
+ "pmulhw "MANGLE(MM_FIX_2_613125930)", %%mm1 \n\t" //-
+ "paddw %%mm0, %%mm5 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_1_847759065)", %%mm5 \n\t" //'z5
+ "paddw %%mm6, %%mm2 \n\t" //'z11
+
+ "pmulhw "MANGLE(MM_FIX_1_082392200)", %%mm0 \n\t"
+ "movq %%mm2, %%mm7 \n\t"
+
+ //---
+ "movq 0*8+%3, %%mm4 \n\t"
+ "psubw %%mm3, %%mm2 \n\t"
+
+ "psllw $1, %%mm2 \n\t"
+ "paddw %%mm3, %%mm7 \n\t" //'t7
+
+ "pmulhw "MANGLE(MM_FIX_1_414213562)", %%mm2 \n\t" //'t11
+ "movq %%mm4, %%mm6 \n\t"
+ //paddw mm7, MM_2
+ "psraw $2, %%mm7 \n\t"
+
+ "paddw "DCTSIZE_S"*0*2(%%"REG_D"), %%mm4 \n\t"
+ "psubw %%mm7, %%mm6 \n\t"
+
+ "movq 1*8+%3, %%mm3 \n\t"
+ "paddw %%mm7, %%mm4 \n\t"
+
+ "movq %%mm6, "DCTSIZE_S"*7*2(%%"REG_D") \n\t"
+ "paddw %%mm5, %%mm1 \n\t" //'t12
+
+ "movq %%mm4, "DCTSIZE_S"*0*2(%%"REG_D") \n\t"
+ "psubw %%mm7, %%mm1 \n\t" //'t6
+
+ "movq 2*8+%3, %%mm7 \n\t"
+ "psubw %%mm5, %%mm0 \n\t" //'t10
+
+ "movq 3*8+%3, %%mm6 \n\t"
+ "movq %%mm3, %%mm5 \n\t"
+
+ "paddw "DCTSIZE_S"*1*2(%%"REG_D"), %%mm3 \n\t"
+ "psubw %%mm1, %%mm5 \n\t"
+
+ "psubw %%mm1, %%mm2 \n\t" //'t5
+ "paddw %%mm1, %%mm3 \n\t"
+
+ "movq %%mm5, "DCTSIZE_S"*6*2(%%"REG_D") \n\t"
+ "movq %%mm7, %%mm4 \n\t"
+
+ "paddw "DCTSIZE_S"*2*2(%%"REG_D"), %%mm7 \n\t"
+ "psubw %%mm2, %%mm4 \n\t"
+
+ "paddw "DCTSIZE_S"*5*2(%%"REG_D"), %%mm4 \n\t"
+ "paddw %%mm2, %%mm7 \n\t"
+
+ "movq %%mm3, "DCTSIZE_S"*1*2(%%"REG_D") \n\t"
+ "paddw %%mm2, %%mm0 \n\t" //'t4
+
+ // 't4 't6 't5 - - - - 't7
+ "movq %%mm7, "DCTSIZE_S"*2*2(%%"REG_D") \n\t"
+ "movq %%mm6, %%mm1 \n\t"
+
+ "paddw "DCTSIZE_S"*4*2(%%"REG_D"), %%mm6 \n\t"
+ "psubw %%mm0, %%mm1 \n\t"
+
+ "paddw "DCTSIZE_S"*3*2(%%"REG_D"), %%mm1 \n\t"
+ "paddw %%mm0, %%mm6 \n\t"
+
+ "movq %%mm4, "DCTSIZE_S"*5*2(%%"REG_D") \n\t"
+ "add $8, %%"REG_S" \n\t"
+
+ "movq %%mm6, "DCTSIZE_S"*4*2(%%"REG_D") \n\t"
+
+ "movq %%mm1, "DCTSIZE_S"*3*2(%%"REG_D") \n\t"
+ "add $8, %%"REG_D" \n\t"
+
+ "4: \n\t"
+//=part 2 (the same)===========================================================
+ "movq "DCTSIZE_S"*0*2(%%"REG_S"), %%mm1 \n\t"
+ //
+ "movq "DCTSIZE_S"*3*2(%%"REG_S"), %%mm7 \n\t"
+ "movq %%mm1, %%mm0 \n\t"
+
+ "paddw "DCTSIZE_S"*7*2(%%"REG_S"), %%mm1 \n\t" //t0
+ "movq %%mm7, %%mm3 \n\t"
+
+ "paddw "DCTSIZE_S"*4*2(%%"REG_S"), %%mm7 \n\t" //t3
+ "movq %%mm1, %%mm5 \n\t"
+
+ "movq "DCTSIZE_S"*1*2(%%"REG_S"), %%mm6 \n\t"
+ "psubw %%mm7, %%mm1 \n\t" //t13
+
+ "movq "DCTSIZE_S"*2*2(%%"REG_S"), %%mm2 \n\t"
+ "movq %%mm6, %%mm4 \n\t"
+
+ "paddw "DCTSIZE_S"*6*2(%%"REG_S"), %%mm6 \n\t" //t1
+ "paddw %%mm7, %%mm5 \n\t" //t10
+
+ "paddw "DCTSIZE_S"*5*2(%%"REG_S"), %%mm2 \n\t" //t2
+ "movq %%mm6, %%mm7 \n\t"
+
+ "paddw %%mm2, %%mm6 \n\t" //t11
+ "psubw %%mm2, %%mm7 \n\t" //t12
+
+ "movq %%mm5, %%mm2 \n\t"
+ "paddw %%mm6, %%mm5 \n\t" //d0
+ // i0 t13 t12 i3 i1 d0 - d4
+ "psubw %%mm6, %%mm2 \n\t" //d4
+ "paddw %%mm1, %%mm7 \n\t"
+
+ "movq 1*8+4*16(%%"REG_d"), %%mm6 \n\t"
+ "psllw $2, %%mm7 \n\t"
+
+ "psubw 1*8+0*16(%%"REG_d"), %%mm5 \n\t"
+ "psubw %%mm6, %%mm2 \n\t"
+
+ "paddusw 1*8+0*16(%%"REG_d"), %%mm5 \n\t"
+ "paddusw %%mm6, %%mm2 \n\t"
+
+ "pmulhw "MANGLE(ff_MM_FIX_0_707106781)", %%mm7 \n\t"
+ //
+ "paddw 1*8+0*16(%%"REG_d"), %%mm5 \n\t"
+ "paddw %%mm6, %%mm2 \n\t"
+
+ "psubusw 1*8+0*16(%%"REG_d"), %%mm5 \n\t"
+ "psubusw %%mm6, %%mm2 \n\t"
+
+//This func is totally compute-bound, operates at huge speed. So, DC shortcut
+// at this place isn't worthwhile due to BTB miss penalty (checked on Pent. 3).
+//However, typical numbers: nondc - 29%%, dc - 46%%, zero - 25%%. All <> 0 case is very rare.
+ "paddw "MANGLE(MM_2)", %%mm5 \n\t"
+ "movq %%mm2, %%mm6 \n\t"
+
+ "paddw %%mm5, %%mm2 \n\t"
+ "psubw %%mm6, %%mm5 \n\t"
+
+ "movq %%mm1, %%mm6 \n\t"
+ "paddw %%mm7, %%mm1 \n\t" //d2
+
+ "psubw 1*8+2*16(%%"REG_d"), %%mm1 \n\t"
+ "psubw %%mm7, %%mm6 \n\t" //d6
+
+ "movq 1*8+6*16(%%"REG_d"), %%mm7 \n\t"
+ "psraw $2, %%mm5 \n\t"
+
+ "paddusw 1*8+2*16(%%"REG_d"), %%mm1 \n\t"
+ "psubw %%mm7, %%mm6 \n\t"
+ // t7 d2 /t11 t4 t6 - d6 /t10
+
+ "paddw 1*8+2*16(%%"REG_d"), %%mm1 \n\t"
+ "paddusw %%mm7, %%mm6 \n\t"
+
+ "psubusw 1*8+2*16(%%"REG_d"), %%mm1 \n\t"
+ "paddw %%mm7, %%mm6 \n\t"
+
+ "psubw "DCTSIZE_S"*4*2(%%"REG_S"), %%mm3 \n\t"
+ "psubusw %%mm7, %%mm6 \n\t"
+
+ //movq [edi+"DCTSIZE_S"*2*2], mm1
+ //movq [edi+"DCTSIZE_S"*6*2], mm6
+ "movq %%mm1, %%mm7 \n\t"
+ "psraw $2, %%mm2 \n\t"
+
+ "psubw "DCTSIZE_S"*6*2(%%"REG_S"), %%mm4 \n\t"
+ "psubw %%mm6, %%mm1 \n\t"
+
+ "psubw "DCTSIZE_S"*7*2(%%"REG_S"), %%mm0 \n\t"
+ "paddw %%mm7, %%mm6 \n\t" //'t13
+
+ "psraw $2, %%mm6 \n\t" //paddw mm6, MM_2 !! ---
+ "movq %%mm2, %%mm7 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_1_414213562_A)", %%mm1 \n\t"
+ "paddw %%mm6, %%mm2 \n\t" //'t0
+
+ "movq %%mm2, 0*8+%3 \n\t" //!
+ "psubw %%mm6, %%mm7 \n\t" //'t3
+
+ "movq "DCTSIZE_S"*2*2(%%"REG_S"), %%mm2 \n\t"
+ "psubw %%mm6, %%mm1 \n\t" //'t12
+
+ "psubw "DCTSIZE_S"*5*2(%%"REG_S"), %%mm2 \n\t" //t5
+ "movq %%mm5, %%mm6 \n\t"
+
+ "movq %%mm7, 3*8+%3 \n\t"
+ "paddw %%mm2, %%mm3 \n\t" //t10
+
+ "paddw %%mm4, %%mm2 \n\t" //t11
+ "paddw %%mm0, %%mm4 \n\t" //t12
+
+ "movq %%mm3, %%mm7 \n\t"
+ "psubw %%mm4, %%mm3 \n\t"
+
+ "psllw $2, %%mm3 \n\t"
+ "psllw $2, %%mm7 \n\t" //opt for P6
+
+ "pmulhw "MANGLE(MM_FIX_0_382683433)", %%mm3 \n\t"
+ "psllw $2, %%mm4 \n\t"
+
+ "pmulhw "MANGLE(ff_MM_FIX_0_541196100)", %%mm7 \n\t"
+ "psllw $2, %%mm2 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_1_306562965)", %%mm4 \n\t"
+ "paddw %%mm1, %%mm5 \n\t" //'t1
+
+ "pmulhw "MANGLE(ff_MM_FIX_0_707106781)", %%mm2 \n\t"
+ "psubw %%mm1, %%mm6 \n\t" //'t2
+ // t7 't12 't11 t4 t6 - 't13 't10 ---
+
+ "paddw %%mm3, %%mm7 \n\t" //z2
+
+ "movq %%mm5, 1*8+%3 \n\t"
+ "paddw %%mm3, %%mm4 \n\t" //z4
+
+ "movq 1*8+3*16(%%"REG_d"), %%mm3 \n\t"
+ "movq %%mm0, %%mm1 \n\t"
+
+ "movq %%mm6, 2*8+%3 \n\t"
+ "psubw %%mm2, %%mm1 \n\t" //z13
+
+//===
+ "paddw %%mm2, %%mm0 \n\t" //z11
+ "movq %%mm1, %%mm5 \n\t"
+
+ "movq 1*8+5*16(%%"REG_d"), %%mm2 \n\t"
+ "psubw %%mm7, %%mm1 \n\t" //d3
+
+ "paddw %%mm7, %%mm5 \n\t" //d5
+ "psubw %%mm3, %%mm1 \n\t"
+
+ "movq 1*8+1*16(%%"REG_d"), %%mm7 \n\t"
+ "psubw %%mm2, %%mm5 \n\t"
+
+ "movq %%mm0, %%mm6 \n\t"
+ "paddw %%mm4, %%mm0 \n\t" //d1
+
+ "paddusw %%mm3, %%mm1 \n\t"
+ "psubw %%mm4, %%mm6 \n\t" //d7
+
+ // d1 d3 - - - d5 d7 -
+ "movq 1*8+7*16(%%"REG_d"), %%mm4 \n\t"
+ "psubw %%mm7, %%mm0 \n\t"
+
+ "psubw %%mm4, %%mm6 \n\t"
+ "paddusw %%mm2, %%mm5 \n\t"
+
+ "paddusw %%mm4, %%mm6 \n\t"
+ "paddw %%mm3, %%mm1 \n\t"
+
+ "paddw %%mm2, %%mm5 \n\t"
+ "paddw %%mm4, %%mm6 \n\t"
+
+ "psubusw %%mm3, %%mm1 \n\t"
+ "psubusw %%mm2, %%mm5 \n\t"
+
+ "psubusw %%mm4, %%mm6 \n\t"
+ "movq %%mm1, %%mm4 \n\t"
+
+ "por %%mm5, %%mm4 \n\t"
+ "paddusw %%mm7, %%mm0 \n\t"
+
+ "por %%mm6, %%mm4 \n\t"
+ "paddw %%mm7, %%mm0 \n\t"
+
+ "packssdw %%mm4, %%mm4 \n\t"
+ "psubusw %%mm7, %%mm0 \n\t"
+
+ "movd %%mm4, %%"REG_a" \n\t"
+ "or %%"REG_a", %%"REG_a" \n\t"
+ "jnz 3f \n\t"
+ //movq [edi+"DCTSIZE_S"*3*2], mm1
+ //movq [edi+"DCTSIZE_S"*5*2], mm5
+ //movq [edi+"DCTSIZE_S"*1*2], mm0
+ //movq [edi+"DCTSIZE_S"*7*2], mm6
+ // t4 t5 - - - t6 t7 -
+ //--- t4 (mm0) may be <>0; mm1, mm5, mm6 == 0
+//Typical numbers: nondc - 19%%, dc - 26%%, zero - 55%%. zero case alone isn't worthwhile
+ "movq 0*8+%3, %%mm4 \n\t"
+ "movq %%mm0, %%mm1 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_0_847759065)", %%mm0 \n\t" //tmp6
+ "movq %%mm1, %%mm2 \n\t"
+
+ "movq "DCTSIZE_S"*0*2(%%"REG_D"), %%mm5 \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_0_566454497)", %%mm1 \n\t" //tmp5
+ "paddw %%mm4, %%mm5 \n\t"
+
+ "movq 1*8+%3, %%mm6 \n\t"
+ //paddw mm3, MM_2
+ "psraw $2, %%mm3 \n\t" //tmp7
+
+ "pmulhw "MANGLE(MM_FIX_0_198912367)", %%mm2 \n\t" //-tmp4
+ "psubw %%mm3, %%mm4 \n\t"
+
+ "movq "DCTSIZE_S"*1*2(%%"REG_D"), %%mm7 \n\t"
+ "paddw %%mm3, %%mm5 \n\t"
+
+ "movq %%mm4, "DCTSIZE_S"*7*2(%%"REG_D") \n\t"
+ "paddw %%mm6, %%mm7 \n\t"
+
+ "movq 2*8+%3, %%mm3 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+
+ "movq "DCTSIZE_S"*2*2(%%"REG_D"), %%mm4 \n\t"
+ "paddw %%mm0, %%mm7 \n\t"
+
+ "movq %%mm5, "DCTSIZE_S"*0*2(%%"REG_D") \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+
+ "movq %%mm6, "DCTSIZE_S"*6*2(%%"REG_D") \n\t"
+ "psubw %%mm1, %%mm3 \n\t"
+
+ "movq "DCTSIZE_S"*5*2(%%"REG_D"), %%mm5 \n\t"
+ "paddw %%mm1, %%mm4 \n\t"
+
+ "movq "DCTSIZE_S"*3*2(%%"REG_D"), %%mm6 \n\t"
+ "paddw %%mm3, %%mm5 \n\t"
+
+ "movq 3*8+%3, %%mm0 \n\t"
+ "add $24, %%"REG_S" \n\t"
+
+ "movq %%mm7, "DCTSIZE_S"*1*2(%%"REG_D") \n\t"
+ "paddw %%mm0, %%mm6 \n\t"
+
+ "movq %%mm4, "DCTSIZE_S"*2*2(%%"REG_D") \n\t"
+ "psubw %%mm2, %%mm0 \n\t"
+
+ "movq "DCTSIZE_S"*4*2(%%"REG_D"), %%mm7 \n\t"
+ "paddw %%mm2, %%mm6 \n\t"
+
+ "movq %%mm5, "DCTSIZE_S"*5*2(%%"REG_D") \n\t"
+ "paddw %%mm0, %%mm7 \n\t"
+
+ "movq %%mm6, "DCTSIZE_S"*3*2(%%"REG_D") \n\t"
+
+ "movq %%mm7, "DCTSIZE_S"*4*2(%%"REG_D") \n\t"
+ "add $24, %%"REG_D" \n\t"
+ "sub $2, %%"REG_c" \n\t"
+ "jnz 1b \n\t"
+ "jmp 5f \n\t"
+
+ "3: \n\t"
+ //--- non DC2
+ //psraw mm1, 2 w/o it -> offset. thr1, thr1, thr1 (actually thr1, thr1, thr1-1)
+ //psraw mm5, 2
+ //psraw mm0, 2
+ //psraw mm6, 2
+ "movq %%mm5, %%mm3 \n\t"
+ "psubw %%mm1, %%mm5 \n\t"
+
+ "psllw $1, %%mm5 \n\t" //'z10
+ "paddw %%mm1, %%mm3 \n\t" //'z13
+
+ "movq %%mm0, %%mm2 \n\t"
+ "psubw %%mm6, %%mm0 \n\t"
+
+ "movq %%mm5, %%mm1 \n\t"
+ "psllw $1, %%mm0 \n\t" //'z12
+
+ "pmulhw "MANGLE(MM_FIX_2_613125930)", %%mm1 \n\t" //-
+ "paddw %%mm0, %%mm5 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_1_847759065)", %%mm5 \n\t" //'z5
+ "paddw %%mm6, %%mm2 \n\t" //'z11
+
+ "pmulhw "MANGLE(MM_FIX_1_082392200)", %%mm0 \n\t"
+ "movq %%mm2, %%mm7 \n\t"
+
+ //---
+ "movq 0*8+%3, %%mm4 \n\t"
+ "psubw %%mm3, %%mm2 \n\t"
+
+ "psllw $1, %%mm2 \n\t"
+ "paddw %%mm3, %%mm7 \n\t" //'t7
+
+ "pmulhw "MANGLE(MM_FIX_1_414213562)", %%mm2 \n\t" //'t11
+ "movq %%mm4, %%mm6 \n\t"
+ //paddw mm7, MM_2
+ "psraw $2, %%mm7 \n\t"
+
+ "paddw "DCTSIZE_S"*0*2(%%"REG_D"), %%mm4 \n\t"
+ "psubw %%mm7, %%mm6 \n\t"
+
+ "movq 1*8+%3, %%mm3 \n\t"
+ "paddw %%mm7, %%mm4 \n\t"
+
+ "movq %%mm6, "DCTSIZE_S"*7*2(%%"REG_D") \n\t"
+ "paddw %%mm5, %%mm1 \n\t" //'t12
+
+ "movq %%mm4, "DCTSIZE_S"*0*2(%%"REG_D") \n\t"
+ "psubw %%mm7, %%mm1 \n\t" //'t6
+
+ "movq 2*8+%3, %%mm7 \n\t"
+ "psubw %%mm5, %%mm0 \n\t" //'t10
+
+ "movq 3*8+%3, %%mm6 \n\t"
+ "movq %%mm3, %%mm5 \n\t"
+
+ "paddw "DCTSIZE_S"*1*2(%%"REG_D"), %%mm3 \n\t"
+ "psubw %%mm1, %%mm5 \n\t"
+
+ "psubw %%mm1, %%mm2 \n\t" //'t5
+ "paddw %%mm1, %%mm3 \n\t"
+
+ "movq %%mm5, "DCTSIZE_S"*6*2(%%"REG_D") \n\t"
+ "movq %%mm7, %%mm4 \n\t"
+
+ "paddw "DCTSIZE_S"*2*2(%%"REG_D"), %%mm7 \n\t"
+ "psubw %%mm2, %%mm4 \n\t"
+
+ "paddw "DCTSIZE_S"*5*2(%%"REG_D"), %%mm4 \n\t"
+ "paddw %%mm2, %%mm7 \n\t"
+
+ "movq %%mm3, "DCTSIZE_S"*1*2(%%"REG_D") \n\t"
+ "paddw %%mm2, %%mm0 \n\t" //'t4
+
+ // 't4 't6 't5 - - - - 't7
+ "movq %%mm7, "DCTSIZE_S"*2*2(%%"REG_D") \n\t"
+ "movq %%mm6, %%mm1 \n\t"
+
+ "paddw "DCTSIZE_S"*4*2(%%"REG_D"), %%mm6 \n\t"
+ "psubw %%mm0, %%mm1 \n\t"
+
+ "paddw "DCTSIZE_S"*3*2(%%"REG_D"), %%mm1 \n\t"
+ "paddw %%mm0, %%mm6 \n\t"
+
+ "movq %%mm4, "DCTSIZE_S"*5*2(%%"REG_D") \n\t"
+ "add $24, %%"REG_S" \n\t"
+
+ "movq %%mm6, "DCTSIZE_S"*4*2(%%"REG_D") \n\t"
+
+ "movq %%mm1, "DCTSIZE_S"*3*2(%%"REG_D") \n\t"
+ "add $24, %%"REG_D" \n\t"
+ "sub $2, %%"REG_c" \n\t"
+ "jnz 1b \n\t"
+ "5: \n\t"
+
+ : "+S"(data), "+D"(output), "+c"(cnt), "=o"(temps)
+ : "d"(thr_adr)
+ NAMED_CONSTRAINTS_ADD(ff_MM_FIX_0_707106781,MM_2,MM_FIX_1_414213562_A,MM_FIX_1_414213562,MM_FIX_0_382683433,
+ ff_MM_FIX_0_541196100,MM_FIX_1_306562965,MM_FIX_0_847759065)
+ NAMED_CONSTRAINTS_ADD(MM_FIX_0_566454497,MM_FIX_0_198912367,MM_FIX_2_613125930,MM_FIX_1_847759065,
+ MM_FIX_1_082392200)
+ : "%"REG_a
+ );
+}
+
+#endif // HAVE_MMX
+
+#if !HAVE_MMX
+
+static void row_idct_c(int16_t* workspace,
+ int16_t* output_adr, int 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
+ }
+}
+
+#else /* HAVE_MMX */
+
+static void row_idct_mmx (int16_t* workspace,
+ int16_t* output_adr, int output_stride, int cnt)
+{
+ DECLARE_ALIGNED(8, uint64_t, temps)[4];
+ __asm__ volatile(
+ "lea (%%"REG_a",%%"REG_a",2), %%"REG_d" \n\t"
+ "1: \n\t"
+ "movq "DCTSIZE_S"*0*2(%%"REG_S"), %%mm0 \n\t"
+ //
+
+ "movq "DCTSIZE_S"*1*2(%%"REG_S"), %%mm1 \n\t"
+ "movq %%mm0, %%mm4 \n\t"
+
+ "movq "DCTSIZE_S"*2*2(%%"REG_S"), %%mm2 \n\t"
+ "punpcklwd %%mm1, %%mm0 \n\t"
+
+ "movq "DCTSIZE_S"*3*2(%%"REG_S"), %%mm3 \n\t"
+ "punpckhwd %%mm1, %%mm4 \n\t"
+
+ //transpose 4x4
+ "movq %%mm2, %%mm7 \n\t"
+ "punpcklwd %%mm3, %%mm2 \n\t"
+
+ "movq %%mm0, %%mm6 \n\t"
+ "punpckldq %%mm2, %%mm0 \n\t" //0
+
+ "punpckhdq %%mm2, %%mm6 \n\t" //1
+ "movq %%mm0, %%mm5 \n\t"
+
+ "punpckhwd %%mm3, %%mm7 \n\t"
+ "psubw %%mm6, %%mm0 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_1_414213562_A)", %%mm0 \n\t"
+ "movq %%mm4, %%mm2 \n\t"
+
+ "punpckldq %%mm7, %%mm4 \n\t" //2
+ "paddw %%mm6, %%mm5 \n\t"
+
+ "punpckhdq %%mm7, %%mm2 \n\t" //3
+ "movq %%mm4, %%mm1 \n\t"
+
+ "psllw $2, %%mm0 \n\t"
+ "paddw %%mm2, %%mm4 \n\t" //t10
+
+ "movq "DCTSIZE_S"*0*2+"DCTSIZE_S"(%%"REG_S"), %%mm3 \n\t"
+ "psubw %%mm2, %%mm1 \n\t" //t11
+
+ "movq "DCTSIZE_S"*1*2+"DCTSIZE_S"(%%"REG_S"), %%mm2 \n\t"
+ "psubw %%mm5, %%mm0 \n\t"
+
+ "movq %%mm4, %%mm6 \n\t"
+ "paddw %%mm5, %%mm4 \n\t" //t0
+
+ "psubw %%mm5, %%mm6 \n\t" //t3
+ "movq %%mm1, %%mm7 \n\t"
+
+ "movq "DCTSIZE_S"*2*2+"DCTSIZE_S"(%%"REG_S"), %%mm5 \n\t"
+ "paddw %%mm0, %%mm1 \n\t" //t1
+
+ "movq %%mm4, 0*8+%3 \n\t" //t0
+ "movq %%mm3, %%mm4 \n\t"
+
+ "movq %%mm6, 1*8+%3 \n\t" //t3
+ "punpcklwd %%mm2, %%mm3 \n\t"
+
+ //transpose 4x4
+ "movq "DCTSIZE_S"*3*2+"DCTSIZE_S"(%%"REG_S"), %%mm6 \n\t"
+ "punpckhwd %%mm2, %%mm4 \n\t"
+
+ "movq %%mm5, %%mm2 \n\t"
+ "punpcklwd %%mm6, %%mm5 \n\t"
+
+ "psubw %%mm0, %%mm7 \n\t" //t2
+ "punpckhwd %%mm6, %%mm2 \n\t"
+
+ "movq %%mm3, %%mm0 \n\t"
+ "punpckldq %%mm5, %%mm3 \n\t" //4
+
+ "punpckhdq %%mm5, %%mm0 \n\t" //5
+ "movq %%mm4, %%mm5 \n\t"
+
+ //
+ "movq %%mm3, %%mm6 \n\t"
+ "punpckldq %%mm2, %%mm4 \n\t" //6
+
+ "psubw %%mm0, %%mm3 \n\t" //z10
+ "punpckhdq %%mm2, %%mm5 \n\t" //7
+
+ "paddw %%mm0, %%mm6 \n\t" //z13
+ "movq %%mm4, %%mm2 \n\t"
+
+ "movq %%mm3, %%mm0 \n\t"
+ "psubw %%mm5, %%mm4 \n\t" //z12
+
+ "pmulhw "MANGLE(MM_FIX_2_613125930)", %%mm0 \n\t" //-
+ "paddw %%mm4, %%mm3 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_1_847759065)", %%mm3 \n\t" //z5
+ "paddw %%mm5, %%mm2 \n\t" //z11 >
+
+ "pmulhw "MANGLE(MM_FIX_1_082392200)", %%mm4 \n\t"
+ "movq %%mm2, %%mm5 \n\t"
+
+ "psubw %%mm6, %%mm2 \n\t"
+ "paddw %%mm6, %%mm5 \n\t" //t7
+
+ "pmulhw "MANGLE(MM_FIX_1_414213562)", %%mm2 \n\t" //t11
+ "paddw %%mm3, %%mm0 \n\t" //t12
+
+ "psllw $3, %%mm0 \n\t"
+ "psubw %%mm3, %%mm4 \n\t" //t10
+
+ "movq 0*8+%3, %%mm6 \n\t"
+ "movq %%mm1, %%mm3 \n\t"
+
+ "psllw $3, %%mm4 \n\t"
+ "psubw %%mm5, %%mm0 \n\t" //t6
+
+ "psllw $3, %%mm2 \n\t"
+ "paddw %%mm0, %%mm1 \n\t" //d1
+
+ "psubw %%mm0, %%mm2 \n\t" //t5
+ "psubw %%mm0, %%mm3 \n\t" //d6
+
+ "paddw %%mm2, %%mm4 \n\t" //t4
+ "movq %%mm7, %%mm0 \n\t"
+
+ "paddw %%mm2, %%mm7 \n\t" //d2
+ "psubw %%mm2, %%mm0 \n\t" //d5
+
+ "movq "MANGLE(MM_DESCALE_RND)", %%mm2 \n\t" //4
+ "psubw %%mm5, %%mm6 \n\t" //d7
+
+ "paddw 0*8+%3, %%mm5 \n\t" //d0
+ "paddw %%mm2, %%mm1 \n\t"
+
+ "paddw %%mm2, %%mm5 \n\t"
+ "psraw $3, %%mm1 \n\t"
+
+ "paddw %%mm2, %%mm7 \n\t"
+ "psraw $3, %%mm5 \n\t"
+
+ "paddw (%%"REG_D"), %%mm5 \n\t"
+ "psraw $3, %%mm7 \n\t"
+
+ "paddw (%%"REG_D",%%"REG_a"), %%mm1 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+
+ "paddw (%%"REG_D",%%"REG_a",2), %%mm7 \n\t"
+ "paddw %%mm2, %%mm3 \n\t"
+
+ "movq %%mm5, (%%"REG_D") \n\t"
+ "paddw %%mm2, %%mm6 \n\t"
+
+ "movq %%mm1, (%%"REG_D",%%"REG_a") \n\t"
+ "psraw $3, %%mm0 \n\t"
+
+ "movq %%mm7, (%%"REG_D",%%"REG_a",2) \n\t"
+ "add %%"REG_d", %%"REG_D" \n\t" //3*ls
+
+ "movq 1*8+%3, %%mm5 \n\t" //t3
+ "psraw $3, %%mm3 \n\t"
+
+ "paddw (%%"REG_D",%%"REG_a",2), %%mm0 \n\t"
+ "psubw %%mm4, %%mm5 \n\t" //d3
+
+ "paddw (%%"REG_D",%%"REG_d"), %%mm3 \n\t"
+ "psraw $3, %%mm6 \n\t"
+
+ "paddw 1*8+%3, %%mm4 \n\t" //d4
+ "paddw %%mm2, %%mm5 \n\t"
+
+ "paddw (%%"REG_D",%%"REG_a",4), %%mm6 \n\t"
+ "paddw %%mm2, %%mm4 \n\t"
+
+ "movq %%mm0, (%%"REG_D",%%"REG_a",2) \n\t"
+ "psraw $3, %%mm5 \n\t"
+
+ "paddw (%%"REG_D"), %%mm5 \n\t"
+ "psraw $3, %%mm4 \n\t"
+
+ "paddw (%%"REG_D",%%"REG_a"), %%mm4 \n\t"
+ "add $"DCTSIZE_S"*2*4, %%"REG_S" \n\t" //4 rows
+
+ "movq %%mm3, (%%"REG_D",%%"REG_d") \n\t"
+ "movq %%mm6, (%%"REG_D",%%"REG_a",4) \n\t"
+ "movq %%mm5, (%%"REG_D") \n\t"
+ "movq %%mm4, (%%"REG_D",%%"REG_a") \n\t"
+
+ "sub %%"REG_d", %%"REG_D" \n\t"
+ "add $8, %%"REG_D" \n\t"
+ "dec %%"REG_c" \n\t"
+ "jnz 1b \n\t"
+
+ : "+S"(workspace), "+D"(output_adr), "+c"(cnt), "=o"(temps)
+ : "a"(output_stride*sizeof(short))
+ NAMED_CONSTRAINTS_ADD(MM_FIX_1_414213562_A,MM_FIX_2_613125930,MM_FIX_1_847759065,MM_FIX_1_082392200,
+ MM_FIX_1_414213562,MM_DESCALE_RND)
+ : "%"REG_d
+ );
+}
+
+#endif // HAVE_MMX
+
+#if !HAVE_MMX
+
+static void row_fdct_c(int16_t *data, const uint8_t *pixels, int 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;
+ }
+}
+
+#else /* HAVE_MMX */
+
+static void row_fdct_mmx(int16_t *data, const uint8_t *pixels, int line_size, int cnt)
+{
+ DECLARE_ALIGNED(8, uint64_t, temps)[4];
+ __asm__ volatile(
+ "lea (%%"REG_a",%%"REG_a",2), %%"REG_d" \n\t"
+ "6: \n\t"
+ "movd (%%"REG_S"), %%mm0 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+
+ "movd (%%"REG_S",%%"REG_a"), %%mm1 \n\t"
+ "punpcklbw %%mm7, %%mm0 \n\t"
+
+ "movd (%%"REG_S",%%"REG_a",2), %%mm2 \n\t"
+ "punpcklbw %%mm7, %%mm1 \n\t"
+
+ "punpcklbw %%mm7, %%mm2 \n\t"
+ "add %%"REG_d", %%"REG_S" \n\t"
+
+ "movq %%mm0, %%mm5 \n\t"
+ //
+
+ "movd (%%"REG_S",%%"REG_a",4), %%mm3 \n\t" //7 ;prefetch!
+ "movq %%mm1, %%mm6 \n\t"
+
+ "movd (%%"REG_S",%%"REG_d"), %%mm4 \n\t" //6
+ "punpcklbw %%mm7, %%mm3 \n\t"
+
+ "psubw %%mm3, %%mm5 \n\t"
+ "punpcklbw %%mm7, %%mm4 \n\t"
+
+ "paddw %%mm3, %%mm0 \n\t"
+ "psubw %%mm4, %%mm6 \n\t"
+
+ "movd (%%"REG_S",%%"REG_a",2), %%mm3 \n\t" //5
+ "paddw %%mm4, %%mm1 \n\t"
+
+ "movq %%mm5, %3 \n\t" //t7
+ "punpcklbw %%mm7, %%mm3 \n\t"
+
+ "movq %%mm6, %4 \n\t" //t6
+ "movq %%mm2, %%mm4 \n\t"
+
+ "movd (%%"REG_S"), %%mm5 \n\t" //3
+ "paddw %%mm3, %%mm2 \n\t"
+
+ "movd (%%"REG_S",%%"REG_a"), %%mm6 \n\t" //4
+ "punpcklbw %%mm7, %%mm5 \n\t"
+
+ "psubw %%mm3, %%mm4 \n\t"
+ "punpcklbw %%mm7, %%mm6 \n\t"
+
+ "movq %%mm5, %%mm3 \n\t"
+ "paddw %%mm6, %%mm5 \n\t" //t3
+
+ "psubw %%mm6, %%mm3 \n\t" //t4 ; t0 t1 t2 t4 t5 t3 - -
+ "movq %%mm0, %%mm6 \n\t"
+
+ "movq %%mm1, %%mm7 \n\t"
+ "psubw %%mm5, %%mm0 \n\t" //t13
+
+ "psubw %%mm2, %%mm1 \n\t"
+ "paddw %%mm2, %%mm7 \n\t" //t11
+
+ "paddw %%mm0, %%mm1 \n\t"
+ "movq %%mm7, %%mm2 \n\t"
+
+ "psllw $2, %%mm1 \n\t"
+ "paddw %%mm5, %%mm6 \n\t" //t10
+
+ "pmulhw "MANGLE(ff_MM_FIX_0_707106781)", %%mm1 \n\t"
+ "paddw %%mm6, %%mm7 \n\t" //d2
+
+ "psubw %%mm2, %%mm6 \n\t" //d3
+ "movq %%mm0, %%mm5 \n\t"
+
+ //transpose 4x4
+ "movq %%mm7, %%mm2 \n\t"
+ "punpcklwd %%mm6, %%mm7 \n\t"
+
+ "paddw %%mm1, %%mm0 \n\t" //d0
+ "punpckhwd %%mm6, %%mm2 \n\t"
+
+ "psubw %%mm1, %%mm5 \n\t" //d1
+ "movq %%mm0, %%mm6 \n\t"
+
+ "movq %4, %%mm1 \n\t"
+ "punpcklwd %%mm5, %%mm0 \n\t"
+
+ "punpckhwd %%mm5, %%mm6 \n\t"
+ "movq %%mm0, %%mm5 \n\t"
+
+ "punpckldq %%mm7, %%mm0 \n\t" //0
+ "paddw %%mm4, %%mm3 \n\t"
+
+ "punpckhdq %%mm7, %%mm5 \n\t" //1
+ "movq %%mm6, %%mm7 \n\t"
+
+ "movq %%mm0, "DCTSIZE_S"*0*2(%%"REG_D") \n\t"
+ "punpckldq %%mm2, %%mm6 \n\t" //2
+
+ "movq %%mm5, "DCTSIZE_S"*1*2(%%"REG_D") \n\t"
+ "punpckhdq %%mm2, %%mm7 \n\t" //3
+
+ "movq %%mm6, "DCTSIZE_S"*2*2(%%"REG_D") \n\t"
+ "paddw %%mm1, %%mm4 \n\t"
+
+ "movq %%mm7, "DCTSIZE_S"*3*2(%%"REG_D") \n\t"
+ "psllw $2, %%mm3 \n\t" //t10
+
+ "movq %3, %%mm2 \n\t"
+ "psllw $2, %%mm4 \n\t" //t11
+
+ "pmulhw "MANGLE(ff_MM_FIX_0_707106781)", %%mm4 \n\t" //z3
+ "paddw %%mm2, %%mm1 \n\t"
+
+ "psllw $2, %%mm1 \n\t" //t12
+ "movq %%mm3, %%mm0 \n\t"
+
+ "pmulhw "MANGLE(ff_MM_FIX_0_541196100)", %%mm0 \n\t"
+ "psubw %%mm1, %%mm3 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_0_382683433)", %%mm3 \n\t" //z5
+ "movq %%mm2, %%mm5 \n\t"
+
+ "pmulhw "MANGLE(MM_FIX_1_306562965)", %%mm1 \n\t"
+ "psubw %%mm4, %%mm2 \n\t" //z13
+
+ "paddw %%mm4, %%mm5 \n\t" //z11
+ "movq %%mm2, %%mm6 \n\t"
+
+ "paddw %%mm3, %%mm0 \n\t" //z2
+ "movq %%mm5, %%mm7 \n\t"
+
+ "paddw %%mm0, %%mm2 \n\t" //d4
+ "psubw %%mm0, %%mm6 \n\t" //d5
+
+ "movq %%mm2, %%mm4 \n\t"
+ "paddw %%mm3, %%mm1 \n\t" //z4
+
+ //transpose 4x4
+ "punpcklwd %%mm6, %%mm2 \n\t"
+ "paddw %%mm1, %%mm5 \n\t" //d6
+
+ "punpckhwd %%mm6, %%mm4 \n\t"
+ "psubw %%mm1, %%mm7 \n\t" //d7
+
+ "movq %%mm5, %%mm6 \n\t"
+ "punpcklwd %%mm7, %%mm5 \n\t"
+
+ "punpckhwd %%mm7, %%mm6 \n\t"
+ "movq %%mm2, %%mm7 \n\t"
+
+ "punpckldq %%mm5, %%mm2 \n\t" //4
+ "sub %%"REG_d", %%"REG_S" \n\t"
+
+ "punpckhdq %%mm5, %%mm7 \n\t" //5
+ "movq %%mm4, %%mm5 \n\t"
+
+ "movq %%mm2, "DCTSIZE_S"*0*2+"DCTSIZE_S"(%%"REG_D") \n\t"
+ "punpckldq %%mm6, %%mm4 \n\t" //6
+
+ "movq %%mm7, "DCTSIZE_S"*1*2+"DCTSIZE_S"(%%"REG_D") \n\t"
+ "punpckhdq %%mm6, %%mm5 \n\t" //7
+
+ "movq %%mm4, "DCTSIZE_S"*2*2+"DCTSIZE_S"(%%"REG_D") \n\t"
+ "add $4, %%"REG_S" \n\t"
+
+ "movq %%mm5, "DCTSIZE_S"*3*2+"DCTSIZE_S"(%%"REG_D") \n\t"
+ "add $"DCTSIZE_S"*2*4, %%"REG_D" \n\t" //4 rows
+ "dec %%"REG_c" \n\t"
+ "jnz 6b \n\t"
+
+ : "+S"(pixels), "+D"(data), "+c"(cnt), "=o"(temps), "=o"(temps[1])
+ : "a"(line_size)
+ NAMED_CONSTRAINTS_ADD(ff_MM_FIX_0_707106781,ff_MM_FIX_0_541196100,MM_FIX_0_382683433,MM_FIX_1_306562965)
+ : "%"REG_d);
+}
+
+#endif // HAVE_MMX
diff --git a/libavfilter/libmpcodecs/vf_ilpack.c b/libavfilter/libmpcodecs/vf_ilpack.c
new file mode 100644
index 0000000..fbf5817
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_ilpack.c
@@ -0,0 +1,458 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; 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 <string.h>
+#include <inttypes.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "cpudetect.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+#include "libavutil/attributes.h"
+#include "libavutil/x86/asm.h"
+
+typedef void (pack_func_t)(unsigned char *dst, unsigned char *y,
+ unsigned char *u, unsigned char *v, int w, int us, int vs);
+
+struct vf_priv_s {
+ int mode;
+ pack_func_t *pack[2];
+};
+
+static void pack_nn_C(unsigned char *dst, unsigned char *y,
+ unsigned char *u, unsigned char *v, int w,
+ int av_unused us, int av_unused vs)
+{
+ int j;
+ for (j = w/2; j; j--) {
+ *dst++ = *y++;
+ *dst++ = *u++;
+ *dst++ = *y++;
+ *dst++ = *v++;
+ }
+}
+
+static void pack_li_0_C(unsigned char *dst, unsigned char *y,
+ unsigned char *u, unsigned char *v, int w, int us, int vs)
+{
+ int j;
+ for (j = w/2; j; j--) {
+ *dst++ = *y++;
+ *dst++ = (u[us+us] + 7*u[0])>>3;
+ *dst++ = *y++;
+ *dst++ = (v[vs+vs] + 7*v[0])>>3;
+ u++; v++;
+ }
+}
+
+static void pack_li_1_C(unsigned char *dst, unsigned char *y,
+ unsigned char *u, unsigned char *v, int w, int us, int vs)
+{
+ int j;
+ for (j = w/2; j; j--) {
+ *dst++ = *y++;
+ *dst++ = (3*u[us+us] + 5*u[0])>>3;
+ *dst++ = *y++;
+ *dst++ = (3*v[vs+vs] + 5*v[0])>>3;
+ u++; v++;
+ }
+}
+
+#if HAVE_MMX
+static void pack_nn_MMX(unsigned char *dst, unsigned char *y,
+ unsigned char *u, unsigned char *v, int w,
+ int av_unused us, int av_unused vs)
+{
+ __asm__ volatile (""
+ ASMALIGN(4)
+ "1: \n\t"
+ "movq (%0), %%mm1 \n\t"
+ "movq (%0), %%mm2 \n\t"
+ "movq (%1), %%mm4 \n\t"
+ "movq (%2), %%mm6 \n\t"
+ "punpcklbw %%mm6, %%mm4 \n\t"
+ "punpcklbw %%mm4, %%mm1 \n\t"
+ "punpckhbw %%mm4, %%mm2 \n\t"
+
+ "add $8, %0 \n\t"
+ "add $4, %1 \n\t"
+ "add $4, %2 \n\t"
+ "movq %%mm1, (%3) \n\t"
+ "movq %%mm2, 8(%3) \n\t"
+ "add $16, %3 \n\t"
+ "decl %4 \n\t"
+ "jnz 1b \n\t"
+ "emms \n\t"
+ :
+ : "r" (y), "r" (u), "r" (v), "r" (dst), "r" (w/8)
+ : "memory"
+ );
+ pack_nn_C(dst, y, u, v, (w&7), 0, 0);
+}
+
+#if HAVE_EBX_AVAILABLE
+static void pack_li_0_MMX(unsigned char *dst, unsigned char *y,
+ unsigned char *u, unsigned char *v, int w, int us, int vs)
+{
+ __asm__ volatile (""
+ "push %%"REG_BP" \n\t"
+#if ARCH_X86_64
+ "mov %6, %%"REG_BP" \n\t"
+#else
+ "movl 4(%%"REG_d"), %%"REG_BP" \n\t"
+ "movl (%%"REG_d"), %%"REG_d" \n\t"
+#endif
+ "pxor %%mm0, %%mm0 \n\t"
+
+ ASMALIGN(4)
+ "2: \n\t"
+ "movq (%%"REG_S"), %%mm1 \n\t"
+ "movq (%%"REG_S"), %%mm2 \n\t"
+
+ "movq (%%"REG_a",%%"REG_d",2), %%mm4 \n\t"
+ "movq (%%"REG_b",%%"REG_BP",2), %%mm6 \n\t"
+ "punpcklbw %%mm0, %%mm4 \n\t"
+ "punpcklbw %%mm0, %%mm6 \n\t"
+ "movq (%%"REG_a"), %%mm3 \n\t"
+ "movq (%%"REG_b"), %%mm5 \n\t"
+ "punpcklbw %%mm0, %%mm3 \n\t"
+ "punpcklbw %%mm0, %%mm5 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "psrlw $3, %%mm4 \n\t"
+ "psrlw $3, %%mm6 \n\t"
+ "packuswb %%mm4, %%mm4 \n\t"
+ "packuswb %%mm6, %%mm6 \n\t"
+ "punpcklbw %%mm6, %%mm4 \n\t"
+ "punpcklbw %%mm4, %%mm1 \n\t"
+ "punpckhbw %%mm4, %%mm2 \n\t"
+
+ "movq %%mm1, (%%"REG_D") \n\t"
+ "movq %%mm2, 8(%%"REG_D") \n\t"
+
+ "movq 8(%%"REG_S"), %%mm1 \n\t"
+ "movq 8(%%"REG_S"), %%mm2 \n\t"
+
+ "movq (%%"REG_a",%%"REG_d",2), %%mm4 \n\t"
+ "movq (%%"REG_b",%%"REG_BP",2), %%mm6 \n\t"
+ "punpckhbw %%mm0, %%mm4 \n\t"
+ "punpckhbw %%mm0, %%mm6 \n\t"
+ "movq (%%"REG_a"), %%mm3 \n\t"
+ "movq (%%"REG_b"), %%mm5 \n\t"
+ "punpckhbw %%mm0, %%mm3 \n\t"
+ "punpckhbw %%mm0, %%mm5 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "psrlw $3, %%mm4 \n\t"
+ "psrlw $3, %%mm6 \n\t"
+ "packuswb %%mm4, %%mm4 \n\t"
+ "packuswb %%mm6, %%mm6 \n\t"
+ "punpcklbw %%mm6, %%mm4 \n\t"
+ "punpcklbw %%mm4, %%mm1 \n\t"
+ "punpckhbw %%mm4, %%mm2 \n\t"
+
+ "add $16, %%"REG_S" \n\t"
+ "add $8, %%"REG_a" \n\t"
+ "add $8, %%"REG_b" \n\t"
+
+ "movq %%mm1, 16(%%"REG_D") \n\t"
+ "movq %%mm2, 24(%%"REG_D") \n\t"
+ "add $32, %%"REG_D" \n\t"
+
+ "decl %%ecx \n\t"
+ "jnz 2b \n\t"
+ "emms \n\t"
+ "pop %%"REG_BP" \n\t"
+ :
+ : "S" (y), "D" (dst), "a" (u), "b" (v), "c" (w/16),
+#if ARCH_X86_64
+ "d" ((x86_reg)us), "r" ((x86_reg)vs)
+#else
+ "d" (&us)
+#endif
+ : "memory"
+ );
+ pack_li_0_C(dst, y, u, v, (w&15), us, vs);
+}
+
+static void pack_li_1_MMX(unsigned char *dst, unsigned char *y,
+ unsigned char *u, unsigned char *v, int w, int us, int vs)
+{
+ __asm__ volatile (""
+ "push %%"REG_BP" \n\t"
+#if ARCH_X86_64
+ "mov %6, %%"REG_BP" \n\t"
+#else
+ "movl 4(%%"REG_d"), %%"REG_BP" \n\t"
+ "movl (%%"REG_d"), %%"REG_d" \n\t"
+#endif
+ "pxor %%mm0, %%mm0 \n\t"
+
+ ASMALIGN(4)
+ "3: \n\t"
+ "movq (%%"REG_S"), %%mm1 \n\t"
+ "movq (%%"REG_S"), %%mm2 \n\t"
+
+ "movq (%%"REG_a",%%"REG_d",2), %%mm4 \n\t"
+ "movq (%%"REG_b",%%"REG_BP",2), %%mm6 \n\t"
+ "punpcklbw %%mm0, %%mm4 \n\t"
+ "punpcklbw %%mm0, %%mm6 \n\t"
+ "movq (%%"REG_a"), %%mm3 \n\t"
+ "movq (%%"REG_b"), %%mm5 \n\t"
+ "punpcklbw %%mm0, %%mm3 \n\t"
+ "punpcklbw %%mm0, %%mm5 \n\t"
+ "movq %%mm4, %%mm7 \n\t"
+ "paddw %%mm4, %%mm4 \n\t"
+ "paddw %%mm7, %%mm4 \n\t"
+ "movq %%mm6, %%mm7 \n\t"
+ "paddw %%mm6, %%mm6 \n\t"
+ "paddw %%mm7, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "psrlw $3, %%mm4 \n\t"
+ "psrlw $3, %%mm6 \n\t"
+ "packuswb %%mm4, %%mm4 \n\t"
+ "packuswb %%mm6, %%mm6 \n\t"
+ "punpcklbw %%mm6, %%mm4 \n\t"
+ "punpcklbw %%mm4, %%mm1 \n\t"
+ "punpckhbw %%mm4, %%mm2 \n\t"
+
+ "movq %%mm1, (%%"REG_D") \n\t"
+ "movq %%mm2, 8(%%"REG_D") \n\t"
+
+ "movq 8(%%"REG_S"), %%mm1 \n\t"
+ "movq 8(%%"REG_S"), %%mm2 \n\t"
+
+ "movq (%%"REG_a",%%"REG_d",2), %%mm4 \n\t"
+ "movq (%%"REG_b",%%"REG_BP",2), %%mm6 \n\t"
+ "punpckhbw %%mm0, %%mm4 \n\t"
+ "punpckhbw %%mm0, %%mm6 \n\t"
+ "movq (%%"REG_a"), %%mm3 \n\t"
+ "movq (%%"REG_b"), %%mm5 \n\t"
+ "punpckhbw %%mm0, %%mm3 \n\t"
+ "punpckhbw %%mm0, %%mm5 \n\t"
+ "movq %%mm4, %%mm7 \n\t"
+ "paddw %%mm4, %%mm4 \n\t"
+ "paddw %%mm7, %%mm4 \n\t"
+ "movq %%mm6, %%mm7 \n\t"
+ "paddw %%mm6, %%mm6 \n\t"
+ "paddw %%mm7, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+ "psrlw $3, %%mm4 \n\t"
+ "psrlw $3, %%mm6 \n\t"
+ "packuswb %%mm4, %%mm4 \n\t"
+ "packuswb %%mm6, %%mm6 \n\t"
+ "punpcklbw %%mm6, %%mm4 \n\t"
+ "punpcklbw %%mm4, %%mm1 \n\t"
+ "punpckhbw %%mm4, %%mm2 \n\t"
+
+ "add $16, %%"REG_S" \n\t"
+ "add $8, %%"REG_a" \n\t"
+ "add $8, %%"REG_b" \n\t"
+
+ "movq %%mm1, 16(%%"REG_D") \n\t"
+ "movq %%mm2, 24(%%"REG_D") \n\t"
+ "add $32, %%"REG_D" \n\t"
+
+ "decl %%ecx \n\t"
+ "jnz 3b \n\t"
+ "emms \n\t"
+ "pop %%"REG_BP" \n\t"
+ :
+ : "S" (y), "D" (dst), "a" (u), "b" (v), "c" (w/16),
+#if ARCH_X86_64
+ "d" ((x86_reg)us), "r" ((x86_reg)vs)
+#else
+ "d" (&us)
+#endif
+ : "memory"
+ );
+ pack_li_1_C(dst, y, u, v, (w&15), us, vs);
+}
+#endif /* HAVE_EBX_AVAILABLE */
+#endif
+
+static pack_func_t *pack_nn;
+static pack_func_t *pack_li_0;
+static pack_func_t *pack_li_1;
+
+static void ilpack(unsigned char *dst, unsigned char *src[3],
+ int dststride, int srcstride[3], int w, int h, pack_func_t *pack[2])
+{
+ int i;
+ unsigned char *y, *u, *v;
+ int ys = srcstride[0], us = srcstride[1], vs = srcstride[2];
+ int a, b;
+
+ y = src[0];
+ u = src[1];
+ v = src[2];
+
+ pack_nn(dst, y, u, v, w, 0, 0);
+ y += ys; dst += dststride;
+ pack_nn(dst, y, u+us, v+vs, w, 0, 0);
+ y += ys; dst += dststride;
+ for (i=2; i<h-2; i++) {
+ a = (i&2) ? 1 : -1;
+ b = (i&1) ^ ((i&2)>>1);
+ pack[b](dst, y, u, v, w, us*a, vs*a);
+ y += ys;
+ if ((i&3) == 1) {
+ u -= us;
+ v -= vs;
+ } else {
+ u += us;
+ v += vs;
+ }
+ dst += dststride;
+ }
+ pack_nn(dst, y, u, v, w, 0, 0);
+ y += ys; dst += dststride; u += us; v += vs;
+ pack_nn(dst, y, u, v, w, 0, 0);
+}
+
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
+{
+ mp_image_t *dmpi;
+
+ // hope we'll get DR buffer:
+ dmpi=ff_vf_get_image(vf->next, IMGFMT_YUY2,
+ MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
+ mpi->w, mpi->h);
+
+ ilpack(dmpi->planes[0], mpi->planes, dmpi->stride[0], mpi->stride, mpi->w, mpi->h, vf->priv->pack);
+
+ return ff_vf_next_put_image(vf,dmpi, pts);
+}
+
+static int config(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt)
+{
+ /* FIXME - also support UYVY output? */
+ return ff_vf_next_config(vf, width, height, d_width, d_height, flags, IMGFMT_YUY2);
+}
+
+
+static int query_format(struct vf_instance *vf, unsigned int fmt)
+{
+ /* FIXME - really any YUV 4:2:0 input format should work */
+ switch (fmt) {
+ case IMGFMT_YV12:
+ case IMGFMT_IYUV:
+ case IMGFMT_I420:
+ return ff_vf_next_query_format(vf,IMGFMT_YUY2);
+ }
+ return 0;
+}
+
+static int vf_open(vf_instance_t *vf, char *args)
+{
+ vf->config=config;
+ vf->query_format=query_format;
+ vf->put_image=put_image;
+ vf->priv = calloc(1, sizeof(struct vf_priv_s));
+ vf->priv->mode = 1;
+ if (args) sscanf(args, "%d", &vf->priv->mode);
+
+ pack_nn = pack_nn_C;
+ pack_li_0 = pack_li_0_C;
+ pack_li_1 = pack_li_1_C;
+#if HAVE_MMX
+ if(ff_gCpuCaps.hasMMX) {
+ pack_nn = pack_nn_MMX;
+#if HAVE_EBX_AVAILABLE
+ pack_li_0 = pack_li_0_MMX;
+ pack_li_1 = pack_li_1_MMX;
+#endif
+ }
+#endif
+
+ switch(vf->priv->mode) {
+ case 0:
+ vf->priv->pack[0] = vf->priv->pack[1] = pack_nn;
+ break;
+ default:
+ ff_mp_msg(MSGT_VFILTER, MSGL_WARN,
+ "ilpack: unknown mode %d (fallback to linear)\n",
+ vf->priv->mode);
+ /* Fallthrough */
+ case 1:
+ vf->priv->pack[0] = pack_li_0;
+ vf->priv->pack[1] = pack_li_1;
+ break;
+ }
+
+ return 1;
+}
+
+const vf_info_t ff_vf_info_ilpack = {
+ "4:2:0 planar -> 4:2:2 packed reinterlacer",
+ "ilpack",
+ "Richard Felker",
+ "",
+ vf_open,
+ NULL
+};
diff --git a/libavfilter/libmpcodecs/vf_pp7.c b/libavfilter/libmpcodecs/vf_pp7.c
new file mode 100644
index 0000000..89ed4fe
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_pp7.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2005 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; 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 <string.h>
+#include <inttypes.h>
+#include <math.h>
+
+#include "config.h"
+
+#include "mp_msg.h"
+#include "cpudetect.h"
+
+#if HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#include "libavutil/mem.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+#include "libvo/fastmemcpy.h"
+
+#define XMIN(a,b) ((a) < (b) ? (a) : (b))
+#define XMAX(a,b) ((a) > (b) ? (a) : (b))
+
+//===========================================================================//
+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, },
+};
+
+struct vf_priv_s {
+ int qp;
+ int mode;
+ int mpeg2;
+ int temp_stride;
+ uint8_t *src;
+};
+#if 0
+static inline void dct7_c(int16_t *dst, int s0, int s1, int s2, int s3, int step){
+ int s, d;
+ int dst2[64];
+//#define S0 (1024/0.37796447300922719759)
+#define C0 ((int)(1024*0.37796447300922719759+0.5)) //sqrt(1/7)
+#define C1 ((int)(1024*0.53452248382484879308/6+0.5)) //sqrt(2/7)/6
+
+#define C2 ((int)(1024*0.45221175985034745004/2+0.5))
+#define C3 ((int)(1024*0.36264567479870879474/2+0.5))
+
+//0.1962505182412941918 0.0149276808419397944-0.2111781990832339584
+#define C4 ((int)(1024*0.1962505182412941918+0.5))
+#define C5 ((int)(1024*0.0149276808419397944+0.5))
+//#define C6 ((int)(1024*0.2111781990832339584+0.5))
+#if 0
+ s= s0 + s1 + s2;
+ dst[0*step] = ((s + s3)*C0 + 512) >> 10;
+ s= (s - 6*s3)*C1 + 512;
+ d= (s0-s2)*C4 + (s1-s2)*C5;
+ dst[1*step] = (s + 2*d)>>10;
+ s -= d;
+ d= (s1-s0)*C2 + (s1-s2)*C3;
+ dst[2*step] = (s + d)>>10;
+ dst[3*step] = (s - d)>>10;
+#elif 1
+ s = s3+s3;
+ s3= s-s0;
+ s0= s+s0;
+ s = s2+s1;
+ s2= s2-s1;
+ dst[0*step]= s0 + s;
+ dst[2*step]= s0 - s;
+ dst[1*step]= 2*s3 + s2;
+ dst[3*step]= s3 - 2*s2;
+#else
+ int i,j,n=7;
+ for(i=0; i<7; i+=2){
+ dst2[i*step/2]= 0;
+ for(j=0; j<4; j++)
+ dst2[i*step/2] += src[j*step] * cos(i*M_PI/n*(j+0.5)) * sqrt((i?2.0:1.0)/n);
+ if(fabs(dst2[i*step/2] - dst[i*step/2]) > 20)
+ printf("%d %d %d (%d %d %d %d) -> (%d %d %d %d)\n", i,dst2[i*step/2], dst[i*step/2],src[0*step], src[1*step], src[2*step], src[3*step], dst[0*step], dst[1*step],dst[2*step],dst[3*step]);
+ }
+#endif
+}
+#endif
+
+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++;
+ }
+}
+
+#if HAVE_MMX
+static void dctB_mmx(int16_t *dst, int16_t *src){
+ __asm__ volatile (
+ "movq (%0), %%mm0 \n\t"
+ "movq 1*4*2(%0), %%mm1 \n\t"
+ "paddw 6*4*2(%0), %%mm0 \n\t"
+ "paddw 5*4*2(%0), %%mm1 \n\t"
+ "movq 2*4*2(%0), %%mm2 \n\t"
+ "movq 3*4*2(%0), %%mm3 \n\t"
+ "paddw 4*4*2(%0), %%mm2 \n\t"
+ "paddw %%mm3, %%mm3 \n\t" //s
+ "movq %%mm3, %%mm4 \n\t" //s
+ "psubw %%mm0, %%mm3 \n\t" //s-s0
+ "paddw %%mm0, %%mm4 \n\t" //s+s0
+ "movq %%mm2, %%mm0 \n\t" //s2
+ "psubw %%mm1, %%mm2 \n\t" //s2-s1
+ "paddw %%mm1, %%mm0 \n\t" //s2+s1
+ "movq %%mm4, %%mm1 \n\t" //s0'
+ "psubw %%mm0, %%mm4 \n\t" //s0'-s'
+ "paddw %%mm0, %%mm1 \n\t" //s0'+s'
+ "movq %%mm3, %%mm0 \n\t" //s3'
+ "psubw %%mm2, %%mm3 \n\t"
+ "psubw %%mm2, %%mm3 \n\t"
+ "paddw %%mm0, %%mm2 \n\t"
+ "paddw %%mm0, %%mm2 \n\t"
+ "movq %%mm1, (%1) \n\t"
+ "movq %%mm4, 2*4*2(%1) \n\t"
+ "movq %%mm2, 1*4*2(%1) \n\t"
+ "movq %%mm3, 3*4*2(%1) \n\t"
+ :: "r" (src), "r"(dst)
+ );
+}
+#endif
+
+static void (*dctB)(int16_t *dst, int16_t *src)= dctB_c;
+
+#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 const int thres[16]={
+ N/(SN0*SN0), N/(SN0*SN2), N/(SN0*SN0),N/(SN0*SN2),
+ N/(SN2*SN0), N/(SN2*SN2), N/(SN2*SN0),N/(SN2*SN2),
+ N/(SN0*SN0), N/(SN0*SN2), N/(SN0*SN0),N/(SN0*SN2),
+ N/(SN2*SN0), N/(SN2*SN2), N/(SN2*SN0),N/(SN2*SN2),
+};
+
+static int thres2[99][16];
+
+static void init_thres2(void){
+ int qp, i;
+ int bias= 0; //FIXME
+
+ for(qp=0; qp<99; qp++){
+ for(i=0; i<16; i++){
+ thres2[qp][i]= ((i&1)?SN2:SN0) * ((i&4)?SN2:SN0) * XMAX(1,qp) * (1<<2) - 1 - bias;
+ }
+ }
+}
+
+static int hardthresh_c(int16_t *src, int qp){
+ int i;
+ int a;
+
+ a= src[0] * factor[0];
+ for(i=1; i<16; i++){
+ unsigned int threshold1= 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(int16_t *src, int qp){
+ int i;
+ int a;
+
+ a= src[0] * factor[0];
+ for(i=1; i<16; i++){
+ unsigned int threshold1= 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(int16_t *src, int qp){
+ int i;
+ int a;
+
+ a= src[0] * factor[0];
+ for(i=1; i<16; i++){
+ unsigned int threshold1= 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 int (*requantize)(int16_t *src, int qp)= hardthresh_c;
+
+static void filter(struct vf_priv_s *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; // HACK avoid crash for Y8 colourspace
+ for(y=0; y<height; y++){
+ int index= 8 + 8*stride + y*stride;
+ fast_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++){
+ fast_memcpy(p_src + ( 7-y)*stride, p_src + ( y+8)*stride, stride);
+ fast_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= XMIN(x+8, width);
+
+ if(p->qp)
+ qp= p->qp;
+ else{
+ qp= qp_store[ (XMIN(x, width-1)>>qps) + (XMIN(y, height-1)>>qps) * qp_stride];
+ qp=norm_qscale(qp, p->mpeg2);
+ }
+ 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);
+
+ dctB(block, tp);
+
+ v= requantize(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 config(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt){
+ int h= (height+16+15)&(~15);
+
+ vf->priv->temp_stride= (width+16+15)&(~15);
+ vf->priv->src = av_malloc(vf->priv->temp_stride*(h+8)*sizeof(uint8_t));
+
+ return ff_vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
+}
+
+static void get_image(struct vf_instance *vf, mp_image_t *mpi){
+ if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
+ // ok, we can do pp in-place (or pp disabled):
+ vf->dmpi=ff_vf_get_image(vf->next,mpi->imgfmt,
+ mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height);
+ mpi->planes[0]=vf->dmpi->planes[0];
+ mpi->stride[0]=vf->dmpi->stride[0];
+ mpi->width=vf->dmpi->width;
+ if(mpi->flags&MP_IMGFLAG_PLANAR){
+ mpi->planes[1]=vf->dmpi->planes[1];
+ mpi->planes[2]=vf->dmpi->planes[2];
+ mpi->stride[1]=vf->dmpi->stride[1];
+ mpi->stride[2]=vf->dmpi->stride[2];
+ }
+ mpi->flags|=MP_IMGFLAG_DIRECT;
+}
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
+ mp_image_t *dmpi;
+
+ if(mpi->flags&MP_IMGFLAG_DIRECT){
+ dmpi=vf->dmpi;
+ }else{
+ // no DR, so get a new image! hope we'll get DR buffer:
+ dmpi=ff_vf_get_image(vf->next,mpi->imgfmt,
+ MP_IMGTYPE_TEMP,
+ MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
+ mpi->width,mpi->height);
+ ff_vf_clone_mpi_attributes(dmpi, mpi);
+ }
+
+ vf->priv->mpeg2= mpi->qscale_type;
+ if(mpi->qscale || vf->priv->qp){
+ filter(vf->priv, dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, mpi->qscale, mpi->qstride, 1);
+ filter(vf->priv, dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, mpi->qscale, mpi->qstride, 0);
+ filter(vf->priv, dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, mpi->qscale, mpi->qstride, 0);
+ }else{
+ memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, dmpi->stride[0], mpi->stride[0]);
+ memcpy_pic(dmpi->planes[1], mpi->planes[1], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[1], mpi->stride[1]);
+ memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[2], mpi->stride[2]);
+ }
+
+#if HAVE_MMX
+ if(ff_gCpuCaps.hasMMX) __asm__ volatile ("emms\n\t");
+#endif
+#if HAVE_MMX2
+ if(ff_gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t");
+#endif
+
+ return ff_vf_next_put_image(vf,dmpi, pts);
+}
+
+static void uninit(struct vf_instance *vf){
+ if(!vf->priv) return;
+
+ av_free(vf->priv->src);
+ vf->priv->src= NULL;
+
+ free(vf->priv);
+ vf->priv=NULL;
+}
+
+//===========================================================================//
+static int query_format(struct vf_instance *vf, unsigned int fmt){
+ switch(fmt){
+ case IMGFMT_YVU9:
+ case IMGFMT_IF09:
+ case IMGFMT_YV12:
+ case IMGFMT_I420:
+ case IMGFMT_IYUV:
+ case IMGFMT_CLPL:
+ case IMGFMT_Y800:
+ case IMGFMT_Y8:
+ case IMGFMT_444P:
+ case IMGFMT_422P:
+ case IMGFMT_411P:
+ return ff_vf_next_query_format(vf,fmt);
+ }
+ return 0;
+}
+
+static int control(struct vf_instance *vf, int request, void* data){
+ return ff_vf_next_control(vf,request,data);
+}
+
+static int vf_open(vf_instance_t *vf, char *args){
+ vf->config=config;
+ vf->put_image=put_image;
+ vf->get_image=get_image;
+ vf->query_format=query_format;
+ vf->uninit=uninit;
+ vf->control= control;
+ vf->priv=malloc(sizeof(struct vf_priv_s));
+ memset(vf->priv, 0, sizeof(struct vf_priv_s));
+
+ if (args) sscanf(args, "%d:%d", &vf->priv->qp, &vf->priv->mode);
+
+ if(vf->priv->qp < 0)
+ vf->priv->qp = 0;
+
+ init_thres2();
+
+ switch(vf->priv->mode){
+ case 0: requantize= hardthresh_c; break;
+ case 1: requantize= softthresh_c; break;
+ default:
+ case 2: requantize= mediumthresh_c; break;
+ }
+
+#if HAVE_MMX
+ if(ff_gCpuCaps.hasMMX){
+ dctB= dctB_mmx;
+ }
+#endif
+#if 0
+ if(ff_gCpuCaps.hasMMX){
+ switch(vf->priv->mode){
+ case 0: requantize= hardthresh_mmx; break;
+ case 1: requantize= softthresh_mmx; break;
+ }
+ }
+#endif
+
+ return 1;
+}
+
+const vf_info_t ff_vf_info_pp7 = {
+ "postprocess 7",
+ "pp7",
+ "Michael Niedermayer",
+ "",
+ vf_open,
+ NULL
+};
diff --git a/libavfilter/libmpcodecs/vf_softpulldown.c b/libavfilter/libmpcodecs/vf_softpulldown.c
new file mode 100644
index 0000000..556374e
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_softpulldown.c
@@ -0,0 +1,163 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; 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 <string.h>
+
+#include "config.h"
+#include "mp_msg.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+
+#include "libvo/fastmemcpy.h"
+
+struct vf_priv_s {
+ int state;
+ long long in;
+ long long out;
+};
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
+{
+ mp_image_t *dmpi;
+ int ret = 0;
+ int flags = mpi->fields;
+ int state = vf->priv->state;
+
+ dmpi = ff_vf_get_image(vf->next, mpi->imgfmt,
+ MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE |
+ MP_IMGFLAG_PRESERVE, mpi->width, mpi->height);
+
+ vf->priv->in++;
+
+ if ((state == 0 &&
+ !(flags & MP_IMGFIELD_TOP_FIRST)) ||
+ (state == 1 &&
+ flags & MP_IMGFIELD_TOP_FIRST)) {
+ ff_mp_msg(MSGT_VFILTER, MSGL_WARN,
+ "softpulldown: Unexpected field flags: state=%d top_field_first=%d repeat_first_field=%d\n",
+ state,
+ (flags & MP_IMGFIELD_TOP_FIRST) != 0,
+ (flags & MP_IMGFIELD_REPEAT_FIRST) != 0);
+ state ^= 1;
+ }
+
+ if (state == 0) {
+ ret = ff_vf_next_put_image(vf, mpi, MP_NOPTS_VALUE);
+ vf->priv->out++;
+ if (flags & MP_IMGFIELD_REPEAT_FIRST) {
+ my_memcpy_pic(dmpi->planes[0],
+ mpi->planes[0], mpi->w, mpi->h/2,
+ dmpi->stride[0]*2, mpi->stride[0]*2);
+ if (mpi->flags & MP_IMGFLAG_PLANAR) {
+ my_memcpy_pic(dmpi->planes[1],
+ mpi->planes[1],
+ mpi->chroma_width,
+ mpi->chroma_height/2,
+ dmpi->stride[1]*2,
+ mpi->stride[1]*2);
+ my_memcpy_pic(dmpi->planes[2],
+ mpi->planes[2],
+ mpi->chroma_width,
+ mpi->chroma_height/2,
+ dmpi->stride[2]*2,
+ mpi->stride[2]*2);
+ }
+ state=1;
+ }
+ } else {
+ my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0],
+ mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2,
+ dmpi->stride[0]*2, mpi->stride[0]*2);
+ if (mpi->flags & MP_IMGFLAG_PLANAR) {
+ my_memcpy_pic(dmpi->planes[1]+dmpi->stride[1],
+ mpi->planes[1]+mpi->stride[1],
+ mpi->chroma_width, mpi->chroma_height/2,
+ dmpi->stride[1]*2, mpi->stride[1]*2);
+ my_memcpy_pic(dmpi->planes[2]+dmpi->stride[2],
+ mpi->planes[2]+mpi->stride[2],
+ mpi->chroma_width, mpi->chroma_height/2,
+ dmpi->stride[2]*2, mpi->stride[2]*2);
+ }
+ ret = ff_vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
+ vf->priv->out++;
+ if (flags & MP_IMGFIELD_REPEAT_FIRST) {
+ ret |= ff_vf_next_put_image(vf, mpi, MP_NOPTS_VALUE);
+ vf->priv->out++;
+ state=0;
+ } else {
+ my_memcpy_pic(dmpi->planes[0],
+ mpi->planes[0], mpi->w, mpi->h/2,
+ dmpi->stride[0]*2, mpi->stride[0]*2);
+ if (mpi->flags & MP_IMGFLAG_PLANAR) {
+ my_memcpy_pic(dmpi->planes[1],
+ mpi->planes[1],
+ mpi->chroma_width,
+ mpi->chroma_height/2,
+ dmpi->stride[1]*2,
+ mpi->stride[1]*2);
+ my_memcpy_pic(dmpi->planes[2],
+ mpi->planes[2],
+ mpi->chroma_width,
+ mpi->chroma_height/2,
+ dmpi->stride[2]*2,
+ mpi->stride[2]*2);
+ }
+ }
+ }
+
+ vf->priv->state = state;
+
+ return ret;
+}
+
+static int config(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt)
+{
+ return ff_vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
+}
+
+static void uninit(struct vf_instance *vf)
+{
+ ff_mp_msg(MSGT_VFILTER, MSGL_INFO, "softpulldown: %lld frames in, %lld frames out\n", vf->priv->in, vf->priv->out);
+ free(vf->priv);
+}
+
+static int vf_open(vf_instance_t *vf, char *args)
+{
+ vf->config = config;
+ vf->put_image = put_image;
+ vf->uninit = uninit;
+ vf->default_reqs = VFCAP_ACCEPT_STRIDE;
+ vf->priv = calloc(1, sizeof(struct vf_priv_s));
+ vf->priv->state = 0;
+ return 1;
+}
+
+const vf_info_t ff_vf_info_softpulldown = {
+ "mpeg2 soft 3:2 pulldown",
+ "softpulldown",
+ "Tobias Diedrich <ranma+mplayer@tdiedrich.de>",
+ "",
+ vf_open,
+ NULL
+};
diff --git a/libavfilter/libmpcodecs/vf_uspp.c b/libavfilter/libmpcodecs/vf_uspp.c
new file mode 100644
index 0000000..c9d9c1f
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_uspp.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2005 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; 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 <string.h>
+#include <inttypes.h>
+#include <math.h>
+#include <assert.h>
+
+#include "config.h"
+
+#include "mp_msg.h"
+#include "cpudetect.h"
+
+#include "libavutil/mem.h"
+#include "libavcodec/avcodec.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+#include "av_helpers.h"
+#include "libvo/fastmemcpy.h"
+
+#define XMIN(a,b) ((a) < (b) ? (a) : (b))
+
+#define BLOCK 16
+
+//===========================================================================//
+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},
+{ 0, 0}, { 4, 4}, {12, 8}, { 8,12},
+{ 0, 0}, {10, 2}, { 4, 4}, {14, 6}, { 8, 8}, { 2,10}, {12,12}, { 6,14},
+
+{ 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},
+
+{ 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},
+
+{ 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},
+
+{ 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},
+
+{ 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}, { 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},
+};
+
+struct vf_priv_s {
+ int log2_count;
+ int qp;
+ int mode;
+ int mpeg2;
+ int temp_stride[3];
+ uint8_t *src[3];
+ int16_t *temp[3];
+ int outbuf_size;
+ uint8_t *outbuf;
+ AVCodecContext *avctx_enc[BLOCK*BLOCK];
+ AVFrame *frame;
+ AVFrame *frame_dec;
+};
+
+static void store_slice_c(uint8_t *dst, int16_t *src, int dst_stride, int src_stride, int width, int height, int log2_scale){
+ int y, x;
+
+#define STORE(pos) \
+ 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;
+
+ 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(struct vf_priv_s *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= width >>is_chroma;
+ int h= height>>is_chroma;
+ int stride= p->temp_stride[i];
+ int block= BLOCK>>is_chroma;
+
+ if (!src[i] || !dst[i])
+ continue; // HACK avoid crash for Y8 colourspace
+ for(y=0; y<h; y++){
+ int index= block + block*stride + y*stride;
+ fast_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++){
+ fast_memcpy(p->src[i] + ( block-1-y)*stride, p->src[i] + ( y+block )*stride, stride);
+ fast_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
+ p->frame->quality= norm_qscale(qp_store[0], p->mpeg2) * FF_QP2LAMBDA;
+// init per MB qscale stuff FIXME
+
+ for(i=0; i<count; i++){
+ const int x1= offset[i+count-1][0];
+ const int y1= offset[i+count-1][1];
+ int offset;
+ p->frame->data[0]= p->src[0] + x1 + y1 * p->frame->linesize[0];
+ p->frame->data[1]= p->src[1] + x1/2 + y1/2 * p->frame->linesize[1];
+ p->frame->data[2]= p->src[2] + x1/2 + y1/2 * p->frame->linesize[2];
+
+ avcodec_encode_video(p->avctx_enc[i], p->outbuf, p->outbuf_size, p->frame);
+ p->frame_dec = p->avctx_enc[i]->coded_frame;
+
+ offset= (BLOCK-x1) + (BLOCK-y1)*p->frame_dec->linesize[0];
+ //FIXME optimize
+ 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 ];
+ }
+ }
+ offset= (BLOCK/2-x1/2) + (BLOCK/2-y1/2)*p->frame_dec->linesize[1];
+ for(y=0; y<height/2; y++){
+ for(x=0; x<width/2; 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; // HACK avoid crash for Y8 colourspace
+ store_slice_c(dst[j], p->temp[j], dst_stride[j], p->temp_stride[j], width>>is_chroma, height>>is_chroma, 8-p->log2_count);
+ }
+}
+
+static int config(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt){
+ int i;
+ AVCodec *enc= avcodec_find_encoder(AV_CODEC_ID_SNOW);
+
+ for(i=0; i<3; i++){
+ int is_chroma= !!i;
+ int w= ((width + 4*BLOCK-1) & (~(2*BLOCK-1)))>>is_chroma;
+ int h= ((height + 4*BLOCK-1) & (~(2*BLOCK-1)))>>is_chroma;
+
+ vf->priv->temp_stride[i]= w;
+ vf->priv->temp[i]= malloc(vf->priv->temp_stride[i]*h*sizeof(int16_t));
+ vf->priv->src [i]= malloc(vf->priv->temp_stride[i]*h*sizeof(uint8_t));
+ }
+ for(i=0; i< (1<<vf->priv->log2_count); i++){
+ AVCodecContext *avctx_enc;
+ AVDictionary *opts = NULL;
+
+ avctx_enc=
+ vf->priv->avctx_enc[i]= avcodec_alloc_context3(NULL);
+ avctx_enc->width = width + BLOCK;
+ avctx_enc->height = height + BLOCK;
+ avctx_enc->time_base= (AVRational){1,25}; // meaningless
+ avctx_enc->gop_size = 300;
+ avctx_enc->max_b_frames= 0;
+ avctx_enc->pix_fmt = AV_PIX_FMT_YUV420P;
+ 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);
+ if (avcodec_open2(avctx_enc, enc, &opts) < 0)
+ return 0;
+ av_dict_free(&opts);
+ assert(avctx_enc->codec);
+ }
+ vf->priv->frame= av_frame_alloc();
+ vf->priv->frame_dec= av_frame_alloc();
+
+ vf->priv->outbuf_size= (width + BLOCK)*(height + BLOCK)*10;
+ vf->priv->outbuf= malloc(vf->priv->outbuf_size);
+
+ return ff_vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
+}
+
+static void get_image(struct vf_instance *vf, mp_image_t *mpi){
+ if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
+ // ok, we can do pp in-place (or pp disabled):
+ vf->dmpi=ff_vf_get_image(vf->next,mpi->imgfmt,
+ mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height);
+ mpi->planes[0]=vf->dmpi->planes[0];
+ mpi->stride[0]=vf->dmpi->stride[0];
+ mpi->width=vf->dmpi->width;
+ if(mpi->flags&MP_IMGFLAG_PLANAR){
+ mpi->planes[1]=vf->dmpi->planes[1];
+ mpi->planes[2]=vf->dmpi->planes[2];
+ mpi->stride[1]=vf->dmpi->stride[1];
+ mpi->stride[2]=vf->dmpi->stride[2];
+ }
+ mpi->flags|=MP_IMGFLAG_DIRECT;
+}
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
+ mp_image_t *dmpi;
+
+ if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
+ // no DR, so get a new image! hope we'll get DR buffer:
+ dmpi=ff_vf_get_image(vf->next,mpi->imgfmt,
+ MP_IMGTYPE_TEMP,
+ MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
+ mpi->width,mpi->height);
+ ff_vf_clone_mpi_attributes(dmpi, mpi);
+ }else{
+ dmpi=vf->dmpi;
+ }
+
+ vf->priv->mpeg2= mpi->qscale_type;
+ if(vf->priv->log2_count || !(mpi->flags&MP_IMGFLAG_DIRECT)){
+ if(mpi->qscale || vf->priv->qp){
+ filter(vf->priv, dmpi->planes, mpi->planes, dmpi->stride, mpi->stride, mpi->w, mpi->h, mpi->qscale, mpi->qstride);
+ }else{
+ memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, dmpi->stride[0], mpi->stride[0]);
+ memcpy_pic(dmpi->planes[1], mpi->planes[1], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[1], mpi->stride[1]);
+ memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[2], mpi->stride[2]);
+ }
+ }
+
+#if HAVE_MMX
+ if(ff_gCpuCaps.hasMMX) __asm__ volatile ("emms\n\t");
+#endif
+#if HAVE_MMX2
+ if(ff_gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t");
+#endif
+
+ return ff_vf_next_put_image(vf,dmpi, pts);
+}
+
+static void uninit(struct vf_instance *vf){
+ int i;
+ if(!vf->priv) return;
+
+ for(i=0; i<3; i++){
+ free(vf->priv->temp[i]);
+ vf->priv->temp[i]= NULL;
+ free(vf->priv->src[i]);
+ vf->priv->src[i]= NULL;
+ }
+ for(i=0; i<BLOCK*BLOCK; i++){
+ av_freep(&vf->priv->avctx_enc[i]);
+ }
+
+ free(vf->priv);
+ vf->priv=NULL;
+}
+
+//===========================================================================//
+static int query_format(struct vf_instance *vf, unsigned int fmt){
+ switch(fmt){
+ case IMGFMT_YV12:
+ case IMGFMT_I420:
+ case IMGFMT_IYUV:
+ case IMGFMT_Y800:
+ case IMGFMT_Y8:
+ return ff_vf_next_query_format(vf,fmt);
+ }
+ return 0;
+}
+
+static int control(struct vf_instance *vf, int request, void* data){
+ switch(request){
+ case VFCTRL_QUERY_MAX_PP_LEVEL:
+ return 8;
+ case VFCTRL_SET_PP_LEVEL:
+ vf->priv->log2_count= *((unsigned int*)data);
+ //FIXME we have to realloc a few things here
+ return CONTROL_TRUE;
+ }
+ return ff_vf_next_control(vf,request,data);
+}
+
+static int vf_open(vf_instance_t *vf, char *args){
+
+ int log2c=-1;
+
+ vf->config=config;
+ vf->put_image=put_image;
+ vf->get_image=get_image;
+ vf->query_format=query_format;
+ vf->uninit=uninit;
+ vf->control= control;
+ vf->priv=malloc(sizeof(struct vf_priv_s));
+ memset(vf->priv, 0, sizeof(struct vf_priv_s));
+
+ ff_init_avcodec();
+
+ vf->priv->log2_count= 4;
+
+ if (args) sscanf(args, "%d:%d:%d", &log2c, &vf->priv->qp, &vf->priv->mode);
+
+ if( log2c >=0 && log2c <=8 )
+ vf->priv->log2_count = log2c;
+
+ if(vf->priv->qp < 0)
+ vf->priv->qp = 0;
+
+// #if HAVE_MMX
+// if(ff_gCpuCaps.hasMMX){
+// store_slice= store_slice_mmx;
+// }
+// #endif
+
+ return 1;
+}
+
+const vf_info_t ff_vf_info_uspp = {
+ "ultra simple/slow postprocess",
+ "uspp",
+ "Michael Niedermayer",
+ "",
+ vf_open,
+ NULL
+};
diff --git a/libavfilter/libmpcodecs/vfcap.h b/libavfilter/libmpcodecs/vfcap.h
new file mode 100644
index 0000000..611d642
--- /dev/null
+++ b/libavfilter/libmpcodecs/vfcap.h
@@ -0,0 +1,56 @@
+/* VFCAP_* values: they are flags, returned by query_format():
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer is distributed in the hope that 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_VFCAP_H
+#define MPLAYER_VFCAP_H
+
+// set, if the given colorspace is supported (with or without conversion)
+#define VFCAP_CSP_SUPPORTED 0x1
+// set, if the given colorspace is supported _without_ conversion
+#define VFCAP_CSP_SUPPORTED_BY_HW 0x2
+// set if the driver/filter can draw OSD
+#define VFCAP_OSD 0x4
+// set if the driver/filter can handle compressed SPU stream
+#define VFCAP_SPU 0x8
+// scaling up/down by hardware, or software:
+#define VFCAP_HWSCALE_UP 0x10
+#define VFCAP_HWSCALE_DOWN 0x20
+#define VFCAP_SWSCALE 0x40
+// driver/filter can do vertical flip (upside-down)
+#define VFCAP_FLIP 0x80
+
+// driver/hardware handles timing (blocking)
+#define VFCAP_TIMER 0x100
+// driver _always_ flip image upside-down (for ve_vfw)
+#define VFCAP_FLIPPED 0x200
+// vf filter: accepts stride (put_image)
+// vo driver: has draw_slice() support for the given csp
+#define VFCAP_ACCEPT_STRIDE 0x400
+// filter does postprocessing (so you shouldn't scale/filter image before it)
+#define VFCAP_POSTPROC 0x800
+// filter cannot be reconfigured to different size & format
+#define VFCAP_CONSTANT 0x1000
+// filter can draw EOSD
+#define VFCAP_EOSD 0x2000
+// filter will draw EOSD at screen resolution (without scaling)
+#define VFCAP_EOSD_UNSCALED 0x4000
+// used by libvo and vf_vo, indicates the VO does not support draw_slice for this format
+#define VOCAP_NOSLICES 0x8000
+
+#endif /* MPLAYER_VFCAP_H */
diff --git a/libavfilter/log2_tab.c b/libavfilter/log2_tab.c
new file mode 100644
index 0000000..47a1df0
--- /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 0000000..ebb4f93
--- /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 0000000..f5f5320
--- /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 0000000..6d80fa8
--- /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 0000000..aca02e0
--- /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 dd3b174..070b3bd 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 fa7a0be..92b07fb 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_dlog(inlink->dst,
- "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_dlog(inlink->dst, " INTERLACED:%"PRId64,
+ (int64_t)setpts->var_values[VAR_INTERLACED]);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ av_dlog(inlink->dst, " 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_dlog(inlink->dst, " -> 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 169037f..83616c1 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 41395e7..6abd5ee 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
*/
@@ -70,10 +70,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 +94,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 +137,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 0000000..0b97b82
--- /dev/null
+++ b/libavfilter/src_movie.c
@@ -0,0 +1,609 @@
+/*
+ * 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);
+ 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 1cfea3e..5f347e8 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/transform.c b/libavfilter/transform.c
new file mode 100644
index 0000000..3fc547e
--- /dev/null
+++ b/libavfilter/transform.c
@@ -0,0 +1,201 @@
+/*
+ * 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;
+}
+
+static inline int mirror(int v, int m)
+{
+ while ((unsigned)v > (unsigned)m) {
+ v = -v;
+ if (v < 0)
+ v += 2 * m;
+ }
+ return v;
+}
+
+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 = mirror(x_s, width-1);
+ y_s = 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 0000000..07436bf
--- /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 2b57540..468dc03 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 0000000..c2aed64
--- /dev/null
+++ b/libavfilter/unsharp.h
@@ -0,0 +1,81 @@
+/*
+ * 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;
+ 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 0000000..5c6b5ef
--- /dev/null
+++ b/libavfilter/unsharp_opencl.c
@@ -0,0 +1,389 @@
+/*
+ * 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 compute_mask_matrix(cl_mem cl_mask_matrix, int step_x, int step_y)
+{
+ int i, j, ret = 0;
+ uint32_t *mask_matrix, *mask_x, *mask_y;
+ size_t size_matrix = sizeof(uint32_t) * (2 * step_x + 1) * (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;
+ }
+ mask_matrix = av_mallocz(size_matrix);
+ if (!mask_matrix) {
+ 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;
+ for (j = 0; j < 2 * step_y + 1; j++) {
+ for (i = 0; i < 2 * step_x + 1; i++) {
+ mask_matrix[i + j * (2 * step_x + 1)] = mask_y[j] * mask_x[i];
+ }
+ }
+ ret = av_opencl_buffer_write(cl_mask_matrix, (uint8_t *)mask_matrix, size_matrix);
+end:
+ av_freep(&mask_x);
+ av_freep(&mask_y);
+ av_freep(&mask_matrix);
+ return ret;
+}
+
+static int generate_mask(AVFilterContext *ctx)
+{
+ UnsharpContext *unsharp = ctx->priv;
+ int i, ret = 0, step_x[2], step_y[2];
+ cl_mem mask_matrix[2];
+ mask_matrix[0] = unsharp->opencl_ctx.cl_luma_mask;
+ mask_matrix[1] = unsharp->opencl_ctx.cl_chroma_mask;
+ 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 (!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 = compute_mask_matrix(mask_matrix[i], 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),
+ 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),
+ 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;
+ }
+ }
+ 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);
+ 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);
+ 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 0000000..3aefab6
--- /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 0000000..9c4fd65
--- /dev/null
+++ b/libavfilter/unsharp_opencl_kernel.h
@@ -0,0 +1,286 @@
+/*
+ * 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,
+ 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 uchar l[32][32];
+ local int lc[LU_RADIUS_X*LU_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 >= 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*LU_RADIUS_Y)
+ lc[indexL] = mask[indexL];
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ int idx, idy, maskIndex;
+ int sum = 0;
+ int steps_x = LU_RADIUS_X/2;
+ int steps_y = LU_RADIUS_Y/2;
+
+ \n#pragma unroll\n
+ for (i = -steps_y; i <= steps_y; i++) {
+ idy = 8 + i + threadIdx.y;
+ \n#pragma unroll\n
+ for (j = -steps_x; j <= steps_x; j++) {
+ idx = 8 + j + threadIdx.x;
+ maskIndex = (i + steps_y)*LU_RADIUS_X + j + steps_x;
+ sum += (int)l[idy][idx] * lc[maskIndex];
+ }
+ }
+ int temp = (int)l[threadIdx.y + 8][threadIdx.x + 8];
+ int res = temp + (((temp - (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,
+ 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 uchar l[32][32];
+ local int lc[CH_RADIUS_X*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*CH_RADIUS_Y)
+ lc[indexL] = mask[indexL];
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ int idx, idy, maskIndex;
+ int sum = 0;
+ int steps_x = CH_RADIUS_X/2;
+ int steps_y = CH_RADIUS_Y/2;
+
+ \n#pragma unroll\n
+ for (i = -steps_y; i <= steps_y; i++) {
+ idy = 8 + i + threadIdx.y;
+ \n#pragma unroll\n
+ for (j = -steps_x; j <= steps_x; j++) {
+ idx = 8 + j + threadIdx.x;
+ maskIndex = (i + steps_y)*CH_RADIUS_X + j + steps_x;
+ sum += (int)l[idy][idx] * lc[maskIndex];
+ }
+ }
+ int temp = (int)l[threadIdx.y + 8][threadIdx.x + 8];
+ int res = temp + (((temp - (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 70b08e5..6f61aee 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 2
+#define LIBAVFILTER_VERSION_MICRO 103
#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 0000000..5f0da35
--- /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 2c28213..84dbee9 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 0000000..1e6feff
--- /dev/null
+++ b/libavfilter/vf_bbox.c
@@ -0,0 +1,132 @@
+/*
+ * 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,
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ 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;
+ 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 0000000..87a7a23
--- /dev/null
+++ b/libavfilter/vf_blackdetect.c
@@ -0,0 +1,209 @@
+/*
+ * 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 8cbcc00..1be9fcc 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)
@@ -58,6 +58,10 @@ static int query_formats(AVFilterContext *ctx)
return 0;
}
+#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 +69,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 +78,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 +100,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 +131,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 0000000..8bf19ff
--- /dev/null
+++ b/libavfilter/vf_blend.c
@@ -0,0 +1,465 @@
+/*
+ * 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_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];
+} BlendContext;
+
+#define OFFSET(x) offsetof(BlendContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption blend_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" },
+ { "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},
+ { "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(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));
+ }
+
+ av_frame_free(&top_buf);
+
+ return dst_buf;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ BlendContext *b = ctx->priv;
+ int ret, plane;
+
+ 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_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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 av_cold void uninit(AVFilterContext *ctx)
+{
+ BlendContext *b = ctx->priv;
+ int i;
+
+ ff_dualinput_uninit(&b->dinput);
+ for (i = 0; i < FF_ARRAY_ELEMS(b->params); i++)
+ av_expr_free(b->params[i].e);
+}
+
+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,
+};
diff --git a/libavfilter/vf_boxblur.c b/libavfilter/vf_boxblur.c
index 4cbfe2c..1fa5135 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,7 +117,7 @@ static av_cold void uninit(AVFilterContext *ctx)
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_YUVA420P,
AV_PIX_FMT_YUV440P, AV_PIX_FMT_GRAY8,
@@ -139,14 +141,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(FFMAX(w, h))) ||
+ !(s->temp[1] = av_malloc(FFMAX(w, h))))
return AVERROR(ENOMEM);
- }
s->hsub = desc->log2_chroma_w;
s->vsub = desc->log2_chroma_h;
@@ -159,7 +156,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 +169,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 "
@@ -305,7 +302,7 @@ 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 };
@@ -316,13 +313,13 @@ 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);
- 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],
@@ -334,27 +331,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 },
+
+ { "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 },
-static const AVClass boxblur_class = {
- .class_name = "boxblur",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
+ { NULL }
};
+AVFILTER_DEFINE_CLASS(boxblur);
+
static const AVFilterPad avfilter_vf_boxblur_inputs[] = {
{
.name = "default",
@@ -381,7 +380,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 0000000..d777f97
--- /dev/null
+++ b/libavfilter/vf_codecview.c
@@ -0,0 +1,244 @@
+/*
+ * 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};
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 0000000..c151c33
--- /dev/null
+++ b/libavfilter/vf_colorbalance.c
@@ -0,0 +1,213 @@
+/*
+ * 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ ColorBalanceContext *cb = 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 + cb->cyan_red.shadows * shadows[r]);
+ r = av_clip_uint8(r + cb->cyan_red.midtones * midtones[r]);
+ r = av_clip_uint8(r + cb->cyan_red.highlights * highlights[r]);
+
+ g = av_clip_uint8(g + cb->magenta_green.shadows * shadows[g]);
+ g = av_clip_uint8(g + cb->magenta_green.midtones * midtones[g]);
+ g = av_clip_uint8(g + cb->magenta_green.highlights * highlights[g]);
+
+ b = av_clip_uint8(b + cb->yellow_blue.shadows * shadows[b]);
+ b = av_clip_uint8(b + cb->yellow_blue.midtones * midtones[b]);
+ b = av_clip_uint8(b + cb->yellow_blue.highlights * highlights[b]);
+
+ cb->lut[R][i] = r;
+ cb->lut[G][i] = g;
+ cb->lut[B][i] = b;
+ }
+
+ av_free(buffer);
+
+ ff_fill_rgba_map(cb->rgba_map, outlink->format);
+ cb->step = av_get_padded_bits_per_pixel(desc) >> 3;
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ColorBalanceContext *cb = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ const uint8_t roffset = cb->rgba_map[R];
+ const uint8_t goffset = cb->rgba_map[G];
+ const uint8_t boffset = cb->rgba_map[B];
+ const uint8_t aoffset = cb->rgba_map[A];
+ const int step = cb->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] = cb->lut[R][src[j + roffset]];
+ dst[j + goffset] = cb->lut[G][src[j + goffset]];
+ dst[j + boffset] = cb->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 0000000..c7e63b5
--- /dev/null
+++ b/libavfilter/vf_colorchannelmixer.c
@@ -0,0 +1,360 @@
+/*
+ * 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ ColorChannelMixerContext *cm = ctx->priv;
+ int i, j, size, *buffer;
+
+ ff_fill_rgba_map(cm->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;
+ }
+
+ cm->buffer = buffer = av_malloc(16 * size * sizeof(*cm->buffer));
+ if (!cm->buffer)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 4; j++, buffer += size)
+ cm->lut[i][j] = buffer;
+
+ for (i = 0; i < size; i++) {
+ cm->lut[R][R][i] = round(i * cm->rr);
+ cm->lut[R][G][i] = round(i * cm->rg);
+ cm->lut[R][B][i] = round(i * cm->rb);
+ cm->lut[R][A][i] = round(i * cm->ra);
+
+ cm->lut[G][R][i] = round(i * cm->gr);
+ cm->lut[G][G][i] = round(i * cm->gg);
+ cm->lut[G][B][i] = round(i * cm->gb);
+ cm->lut[G][A][i] = round(i * cm->ga);
+
+ cm->lut[B][R][i] = round(i * cm->br);
+ cm->lut[B][G][i] = round(i * cm->bg);
+ cm->lut[B][B][i] = round(i * cm->bb);
+ cm->lut[B][A][i] = round(i * cm->ba);
+
+ cm->lut[A][R][i] = round(i * cm->ar);
+ cm->lut[A][G][i] = round(i * cm->ag);
+ cm->lut[A][B][i] = round(i * cm->ab);
+ cm->lut[A][A][i] = round(i * cm->aa);
+ }
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ColorChannelMixerContext *cm = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ const uint8_t roffset = cm->rgba_map[R];
+ const uint8_t goffset = cm->rgba_map[G];
+ const uint8_t boffset = cm->rgba_map[B];
+ const uint8_t aoffset = cm->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(cm->lut[R][R][rin] +
+ cm->lut[R][G][gin] +
+ cm->lut[R][B][bin]);
+ dst[j + goffset] = av_clip_uint8(cm->lut[G][R][rin] +
+ cm->lut[G][G][gin] +
+ cm->lut[G][B][bin]);
+ dst[j + boffset] = av_clip_uint8(cm->lut[B][R][rin] +
+ cm->lut[B][G][gin] +
+ cm->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(cm->lut[R][R][rin] +
+ cm->lut[R][G][gin] +
+ cm->lut[R][B][bin]);
+ dst[j + goffset] = av_clip_uint8(cm->lut[G][R][rin] +
+ cm->lut[G][G][gin] +
+ cm->lut[G][B][bin]);
+ dst[j + boffset] = av_clip_uint8(cm->lut[B][R][rin] +
+ cm->lut[B][G][gin] +
+ cm->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(cm->lut[R][R][rin] +
+ cm->lut[R][G][gin] +
+ cm->lut[R][B][bin] +
+ cm->lut[R][A][ain]);
+ dst[j + goffset] = av_clip_uint8(cm->lut[G][R][rin] +
+ cm->lut[G][G][gin] +
+ cm->lut[G][B][bin] +
+ cm->lut[G][A][ain]);
+ dst[j + boffset] = av_clip_uint8(cm->lut[B][R][rin] +
+ cm->lut[B][G][gin] +
+ cm->lut[B][B][bin] +
+ cm->lut[B][A][ain]);
+ dst[j + aoffset] = av_clip_uint8(cm->lut[A][R][rin] +
+ cm->lut[A][G][gin] +
+ cm->lut[A][B][bin] +
+ cm->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(cm->lut[R][R][rin] +
+ cm->lut[R][G][gin] +
+ cm->lut[R][B][bin]);
+ dst[j + goffset] = av_clip_uint16(cm->lut[G][R][rin] +
+ cm->lut[G][G][gin] +
+ cm->lut[G][B][bin]);
+ dst[j + boffset] = av_clip_uint16(cm->lut[B][R][rin] +
+ cm->lut[B][G][gin] +
+ cm->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(cm->lut[R][R][rin] +
+ cm->lut[R][G][gin] +
+ cm->lut[R][B][bin] +
+ cm->lut[R][A][ain]);
+ dst[j + goffset] = av_clip_uint16(cm->lut[G][R][rin] +
+ cm->lut[G][G][gin] +
+ cm->lut[G][B][bin] +
+ cm->lut[G][A][ain]);
+ dst[j + boffset] = av_clip_uint16(cm->lut[B][R][rin] +
+ cm->lut[B][G][gin] +
+ cm->lut[B][B][bin] +
+ cm->lut[B][A][ain]);
+ dst[j + aoffset] = av_clip_uint16(cm->lut[A][R][rin] +
+ cm->lut[A][G][gin] +
+ cm->lut[A][B][bin] +
+ cm->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 *cm = ctx->priv;
+
+ av_freep(&cm->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_colormatrix.c b/libavfilter/vf_colormatrix.c
new file mode 100644
index 0000000..df78391
--- /dev/null
+++ b/libavfilter/vf_colormatrix.c
@@ -0,0 +1,411 @@
+/*
+ * 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;
+ enum ColorMode source, dest;
+ int mode;
+ int hsub, vsub;
+} ColorMatrixContext;
+
+#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" },
+ { "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 void process_frame_uyvy422(ColorMatrixContext *color,
+ AVFrame *dst, AVFrame *src)
+{
+ const unsigned char *srcp = src->data[0];
+ const int src_pitch = src->linesize[0];
+ const int height = src->height;
+ const int width = src->width*2;
+ unsigned char *dstp = dst->data[0];
+ const int dst_pitch = dst->linesize[0];
+ const int c2 = color->yuv_convert[color->mode][0][1];
+ const int c3 = color->yuv_convert[color->mode][0][2];
+ const int c4 = color->yuv_convert[color->mode][1][1];
+ const int c5 = color->yuv_convert[color->mode][1][2];
+ const int c6 = color->yuv_convert[color->mode][2][1];
+ const int c7 = color->yuv_convert[color->mode][2][2];
+ int x, y;
+
+ for (y = 0; y < height; 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;
+ }
+}
+
+static void process_frame_yuv422p(ColorMatrixContext *color,
+ AVFrame *dst, AVFrame *src)
+{
+ const unsigned char *srcpU = src->data[1];
+ const unsigned char *srcpV = src->data[2];
+ const unsigned char *srcpY = src->data[0];
+ const int src_pitchY = src->linesize[0];
+ const int src_pitchUV = src->linesize[1];
+ const int height = src->height;
+ const int width = src->width;
+ unsigned char *dstpU = dst->data[1];
+ unsigned char *dstpV = dst->data[2];
+ unsigned char *dstpY = dst->data[0];
+ const int dst_pitchY = dst->linesize[0];
+ const int dst_pitchUV = dst->linesize[1];
+ const int c2 = color->yuv_convert[color->mode][0][1];
+ const int c3 = color->yuv_convert[color->mode][0][2];
+ const int c4 = color->yuv_convert[color->mode][1][1];
+ const int c5 = color->yuv_convert[color->mode][1][2];
+ const int c6 = color->yuv_convert[color->mode][2][1];
+ const int c7 = color->yuv_convert[color->mode][2][2];
+ int x, y;
+
+ for (y = 0; y < height; 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;
+ }
+}
+
+static void process_frame_yuv420p(ColorMatrixContext *color,
+ AVFrame *dst, AVFrame *src)
+{
+ const unsigned char *srcpU = src->data[1];
+ const unsigned char *srcpV = src->data[2];
+ const unsigned char *srcpY = src->data[0];
+ const unsigned char *srcpN = src->data[0] + src->linesize[0];
+ const int src_pitchY = src->linesize[0];
+ const int src_pitchUV = src->linesize[1];
+ const int height = src->height;
+ const int width = src->width;
+ unsigned char *dstpU = dst->data[1];
+ unsigned char *dstpV = dst->data[2];
+ unsigned char *dstpY = dst->data[0];
+ unsigned char *dstpN = dst->data[0] + dst->linesize[0];
+ const int dst_pitchY = dst->linesize[0];
+ const int dst_pitchUV = dst->linesize[1];
+ const int c2 = color->yuv_convert[color->mode][0][1];
+ const int c3 = color->yuv_convert[color->mode][0][2];
+ const int c4 = color->yuv_convert[color->mode][1][1];
+ const int c5 = color->yuv_convert[color->mode][1][2];
+ const int c6 = color->yuv_convert[color->mode][2][1];
+ const int c7 = color->yuv_convert[color->mode][2][2];
+ int x, y;
+
+ for (y = 0; y < height; 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;
+ }
+}
+
+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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *link, AVFrame *in)
+{
+ AVFilterContext *ctx = link->dst;
+ ColorMatrixContext *color = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ 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);
+
+ 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;
+ 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);
+
+ if (in->format == AV_PIX_FMT_YUV422P)
+ process_frame_yuv422p(color, out, in);
+ else if (in->format == AV_PIX_FMT_YUV420P)
+ process_frame_yuv420p(color, out, in);
+ else
+ process_frame_uyvy422(color, out, in);
+
+ 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,
+};
diff --git a/libavfilter/vf_copy.c b/libavfilter/vf_copy.c
index 5e60f20..fb9a906 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_crop.c b/libavfilter/vf_crop.c
index 9e820d7..a2f029a 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,43 +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);
+ }
+ ff_set_common_formats(ctx, formats);
return 0;
}
@@ -149,34 +140,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 +181,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 +196,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 +234,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 +249,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 +272,9 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame)
s->x &= ~((1 << s->hsub) - 1);
s->y &= ~((1 << s->vsub) - 1);
- av_dlog(ctx, "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_dlog(ctx, "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 +294,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 +333,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 14c26c7..76aa7b2 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"
@@ -114,15 +112,21 @@ 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;
// 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;
@@ -139,7 +143,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
}
}
- for (y = frame->height - 1; y > s->y2; y--) {
+ for (y = frame->height - 1; y > FFMAX(s->y2, s->y1); y--) {
if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->width, bpp) > s->limit) {
s->y2 = y;
break;
@@ -153,7 +157,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
}
}
- for (y = frame->width - 1; y > s->x2; y--) {
+ for (y = frame->width - 1; y > FFMAX(s->x2, s->x1); y--) {
if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->height, bpp) > s->limit) {
s->x2 = y;
break;
@@ -183,6 +187,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 +207,24 @@ 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_INT, { .i64 = 24 }, 0, 255, 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 },
+ { 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 +238,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 0000000..b17c391
--- /dev/null
+++ b/libavfilter/vf_curves.c
@@ -0,0 +1,570 @@
+/*
+ * 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;
+ enum preset 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
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 0000000..a9017b1
--- /dev/null
+++ b/libavfilter/vf_dctdnoiz.c
@@ -0,0 +1,776 @@
+/*
+ * 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(linesize * s->pr_height * sizeof(*s->cbuf[i][0]));
+ s->cbuf[i][1] = av_malloc(linesize * s->pr_height * sizeof(*s->cbuf[i][1]));
+ s->cbuf[i][2] = av_malloc(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 / 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
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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_free(s->weights);
+ for (i = 0; i < 2; i++) {
+ av_free(s->cbuf[i][0]);
+ av_free(s->cbuf[i][1]);
+ av_free(s->cbuf[i][2]);
+ }
+ for (i = 0; i < s->nb_threads; i++) {
+ av_free(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 0000000..ffb9320
--- /dev/null
+++ b/libavfilter/vf_decimate.c
@@ -0,0 +1,403 @@
+/*
+ * 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
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 0000000..ab525b6
--- /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 dc58078..6ccdfb2 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,33 +154,24 @@ 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,
@@ -187,10 +196,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 +217,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 +230,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 +262,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 +284,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 0000000..b5d5457
--- /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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ return 0;
+}
+
+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_drawbox.c b/libavfilter/vf_drawbox.c
index ab14af2..115df88 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,35 +36,74 @@
#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",
+ 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,
+ 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,
@@ -76,20 +117,83 @@ static int query_formats(AVFilterContext *ctx)
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 */
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ /* 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(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,
+ 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 +209,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 +232,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
-static const AVClass drawbox_class = {
- .class_name = "drawbox",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
+#if CONFIG_DRAWBOX_FILTER
+
+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 +272,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 54a8847..d20f805 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,95 +108,134 @@ 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;
+ enum expansion_mode 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 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
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},
+ {"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, 72, 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 },
- { "fix_bounds", "if true, check and fix text coords to avoid clipping",
- OFFSET(fix_bounds), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, 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},
+ {"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" },
@@ -196,38 +251,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;
@@ -247,6 +295,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;
@@ -255,26 +304,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())) {
@@ -290,89 +353,235 @@ 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)
{
@@ -380,57 +589,45 @@ static av_cold int init(AVFilterContext *ctx)
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)))) {
@@ -439,55 +636,60 @@ 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));
+ ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
return 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;
}
@@ -495,325 +697,370 @@ 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;
- }
-
+ av_bprint_finalize(&s->expanded_text, NULL);
+ av_bprint_finalize(&s->expanded_fontcolor, NULL);
}
-static inline int is_newline(uint32_t c)
-{
- return c == '\n' || c == '\r' || c == '\f' || c == '\v';
-}
-
-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)
- /* 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)
+ 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] * (val) * 129; \
- 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)
+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] * (val) * 129; \
- *(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])
+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])
+static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp)
{
- int i, j, alpha;
-
- if (color[3] != 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)
+ int width, int height,
+ 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;);
@@ -824,19 +1071,21 @@ 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);
- } else {
- draw_glyph_yuv(frame, &glyph->bitmap,
- s->positions[i].x+x, s->positions[i].y+y, width, height,
- yuvcolor, s->hsub, s->vsub);
- }
+ x1 = s->positions[i].x+s->x+x - borderw;
+ y1 = s->positions[i].y+s->y+y - borderw;
+
+ 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);
}
return 0;
@@ -846,107 +1095,217 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame,
int width, int height)
{
DrawTextContext *s = ctx->priv;
- int ret;
+ AVFilterLink *inlink = ctx->inputs[0];
+
+ 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;
+
+ 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;
+ }
+
+ 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)) {
+
+ 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);
+
+ box_w = FFMIN(width - 1 , max_text_line_w);
+ box_h = FFMIN(height - 1, y + s->max_glyph_h);
/* 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);
+ ff_blend_rectangle(&s->dc, &s->boxcolor,
+ frame->data, frame->linesize, width, height,
+ s->x, s->y, box_w, box_h);
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)
+ &s->shadowcolor, s->shadowx, s->shadowy, 0)) < 0)
return ret;
}
+ if (s->borderw) {
+ if ((ret = draw_glyphs(s, frame, width, height,
+ &s->bordercolor, 0, 0, s->borderw)) < 0)
+ return ret;
+ }
if ((ret = draw_glyphs(s, frame, width, height,
- s->fontcolor_rgba,
- s->fontcolor,
- s->x,
- s->y)) < 0)
+ &s->fontcolor, 0, 0, 0)) < 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 int filter_frame(AVFilterLink *inlink, AVFrame *frame)
{
AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
DrawTextContext *s = ctx->priv;
- int ret = 0;
+ int ret;
- if ((ret = dtext_prepare_text(ctx)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Can't draw text\n");
- av_frame_free(&frame);
- return ret;
+ if (s->reload) {
+ if ((ret = load_textfile(ctx)) < 0)
+ return ret;
+#if CONFIG_LIBFRIBIDI
+ if (s->text_shaping)
+ if ((ret = shape_text(ctx)) < 0)
+ 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_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);
- s->draw = av_expr_eval(s->d_pexpr, s->var_values, &s->prng);
+ s->var_values[VAR_PICT_TYPE] = frame->pict_type;
+ s->metadata = av_frame_get_metadata(frame);
- normalize_double(&s->x, s->var_values[VAR_X]);
- normalize_double(&s->y, s->var_values[VAR_Y]);
+ draw_text(ctx, frame, frame->width, frame->height);
- 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;
- }
-
- s->x &= ~((1 << s->hsub) - 1);
- s->y &= ~((1 << s->vsub) - 1);
-
- av_dlog(ctx, "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_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);
- if (s->draw)
- draw_text(inlink->dst, frame, frame->width, frame->height);
-
- s->var_values[VAR_N] += 1.0;
-
- return ff_filter_frame(inlink->dst->outputs[0], frame);
+ 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 }
};
@@ -967,7 +1326,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 0000000..7316412
--- /dev/null
+++ b/libavfilter/vf_edgedetect.c
@@ -0,0 +1,394 @@
+/*
+ * 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;
+ enum FilterMode 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;
+
+ if (edgedetect->mode == MODE_WIRES) {
+ static const enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE};
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ } else if (edgedetect->mode == MODE_COLORMIX) {
+ static const enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_GBRP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE};
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ } else {
+ av_assert0(0);
+ }
+ return 0;
+}
+
+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 0000000..be0885d
--- /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 PixelFormat 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ return 0;
+}
+
+#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_extractplanes.c b/libavfilter/vf_extractplanes.c
new file mode 100644
index 0000000..fadd2dd
--- /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 *e = 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 (e->requested_planes & ~plane_avail) {
+ av_log(ctx, AV_LOG_ERROR, "Requested planes not available.\n");
+ return AVERROR(EINVAL);
+ }
+ if ((ret = av_image_fill_linesizes(e->linesize, inlink->format, inlink->w)) < 0)
+ return ret;
+
+ e->depth = (desc->comp[0].depth_minus1 + 1) >> 3;
+ e->step = av_get_padded_bits_per_pixel(desc) >> 3;
+ e->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++)
+ e->map[i] = rgba_map[e->map[i]];
+ }
+
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = ctx->inputs[0];
+ ExtractPlanesContext *e = ctx->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ const int output = outlink->srcpad - ctx->output_pads;
+
+ if (e->map[output] == 1 || e->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 *e = ctx->priv;
+ int i, eof = 0, ret = 0;
+
+ for (i = 0; i < ctx->nb_outputs; i++) {
+ AVFilterLink *outlink = ctx->outputs[i];
+ const int idx = e->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 (e->is_packed_rgb) {
+ extract_from_packed(out->data[0], out->linesize[0],
+ frame->data[0], frame->linesize[0],
+ outlink->w, outlink->h,
+ e->depth,
+ e->step, idx);
+ } else {
+ av_image_copy_plane(out->data[0], out->linesize[0],
+ frame->data[idx], frame->linesize[idx],
+ e->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 *e = ctx->priv;
+ int planes = (e->requested_planes & 0xf) | (e->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);
+ e->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 *e = ctx->priv;
+
+ e->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 eac0c2c..80ce75d 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,66 @@ 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
};
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ if (s->black_fade)
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ else
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts_rgb));
return 0;
}
+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;
@@ -89,6 +139,56 @@ static int config_props(AVFilterLink *inlink)
s->vsub = pixdesc->log2_chroma_h;
s->bpp = 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 +197,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 +207,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 +220,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 +242,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 +398,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_field.c b/libavfilter/vf_field.c
new file mode 100644
index 0000000..ed12379
--- /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;
+ enum FieldType type;
+ 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 0000000..e2aa60b
--- /dev/null
+++ b/libavfilter/vf_fieldmatch.c
@@ -0,0 +1,984 @@
+/*
+ * 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 (VapouSsynth) 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;
+ enum matching_mode mode;
+ int field;
+ int mchroma;
+ int y0, y1;
+ int64_t scthresh;
+ double scthresh_flt;
+ enum comb_matching_mode combmatch;
+ 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
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 c05d081..5cc612c 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_dlog(ctx,
"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_format.c b/libavfilter/vf_format.c
index 914089d..96cb7fd 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)))
@@ -144,16 +142,13 @@ static int query_formats(AVFilterContext *ctx)
#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 +168,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 +207,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 ea22d37..a38633d 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,13 +204,13 @@ 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 */
@@ -266,15 +265,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 +290,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 f5c761a..8a7d4e8 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
*/
diff --git a/libavfilter/vf_framestep.c b/libavfilter/vf_framestep.c
new file mode 100644
index 0000000..09945e1
--- /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 771443d..9f86838 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;
@@ -149,7 +152,8 @@ static int set_params(AVFilterContext *ctx, const char *params)
if (*params) {
if (!(param = av_get_token(&params, "|")))
return AVERROR(ENOMEM);
- params++; /* skip ':' */
+ if (*params)
+ params++; /* skip ':' */
ret = set_param(ctx, info, i, param);
av_free(param);
if (ret < 0)
@@ -208,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,
@@ -225,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);
@@ -379,19 +412,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[] = {
{
@@ -412,38 +440,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);
}
@@ -458,6 +471,7 @@ static int source_config_props(AVFilterLink *outlink)
outlink->w = s->w;
outlink->h = s->h;
outlink->time_base = s->time_base;
+ outlink->sample_aspect_ratio = (AVRational){1,1};
if (s->destruct && s->instance)
s->destruct(s->instance);
@@ -490,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[] = {
{
@@ -516,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_geq.c b/libavfilter/vf_geq.c
new file mode 100644
index 0000000..49a3e62
--- /dev/null
+++ b/libavfilter/vf_geq.c
@@ -0,0 +1,280 @@
+/*
+ * 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 PixelFormat 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 PixelFormat rgb_pix_fmts[] = {
+ AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
+ AV_PIX_FMT_NONE
+ };
+ if (geq->is_rgb) {
+ ff_set_common_formats(ctx, ff_make_format_list(rgb_pix_fmts));
+ } else
+ ff_set_common_formats(ctx, ff_make_format_list(yuv_pix_fmts));
+ return 0;
+}
+
+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 f7c4372..0da9e0b 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,9 +149,10 @@ 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
};
@@ -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 1eb8d69..519a609 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,38 +37,25 @@
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));
+ 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);
+ }
+
+ ff_set_common_formats(ctx, pix_fmts);
return 0;
}
@@ -76,41 +63,45 @@ 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 +109,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 +118,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 +129,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 +144,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 +191,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 0000000..6fdb7be
--- /dev/null
+++ b/libavfilter/vf_histeq.c
@@ -0,0 +1,281 @@
+/*
+ * 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;
+ enum HisteqAntibanding antibanding;
+ 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 PixelFormat 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 0000000..34656b5
--- /dev/null
+++ b/libavfilter/vf_histogram.c
@@ -0,0 +1,376 @@
+/*
+ * 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
+ enum HistogramMode mode;
+ 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;
+
+ 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);
+ }
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ return 0;
+}
+
+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 be6b761..0448c0d 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 void 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));
for (y = 0; y < h; y++, src += sstride, frame_ant += w)
for (x = 0; x < w; x++)
frame_ant[x] = LOAD(x);
@@ -230,15 +230,15 @@ 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
};
@@ -259,7 +259,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);
@@ -277,12 +277,14 @@ 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 direct, c;
- if (av_frame_is_writable(in)) {
+ if (av_frame_is_writable(in) && !ctx->is_disabled) {
direct = 1;
out = in;
} else {
@@ -294,17 +296,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)
@@ -314,21 +320,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[] = {
{
@@ -340,6 +341,7 @@ static const AVFilterPad avfilter_vf_hqdn3d_inputs[] = {
{ NULL }
};
+
static const AVFilterPad avfilter_vf_hqdn3d_outputs[] = {
{
.name = "default",
@@ -351,14 +353,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 a344518..be55400 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 0000000..4783381
--- /dev/null
+++ b/libavfilter/vf_hqx.c
@@ -0,0 +1,562 @@
+/*
+ * 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};
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 0000000..7843673
--- /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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ return 0;
+}
+
+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 0000000..ed21eea
--- /dev/null
+++ b/libavfilter/vf_idet.c
@@ -0,0 +1,405 @@
+/*
+ * 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 },
+ { 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;
+
+ if (idet->prev)
+ av_frame_free(&idet->prev);
+ idet->prev = idet->cur;
+ idet->cur = idet->next;
+ idet->next = picref;
+
+ if (!idet->cur)
+ return 0;
+
+ if (!idet->prev)
+ idet->prev = av_frame_clone(idet->cur);
+
+ 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);
+ }
+
+ 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) {
+ 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 (!idet->cur);
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ IDETContext *idet = ctx->priv;
+
+ av_log(ctx, AV_LOG_INFO, "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, AV_LOG_INFO, "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, AV_LOG_INFO, "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_YUV420P10,
+ AV_PIX_FMT_YUV422P10,
+ AV_PIX_FMT_YUV444P10,
+ AV_PIX_FMT_YUV420P16,
+ AV_PIX_FMT_YUV422P16,
+ AV_PIX_FMT_YUV444P16,
+ AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_NONE
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ return 0;
+}
+
+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 0000000..af759b4
--- /dev/null
+++ b/libavfilter/vf_idet.h
@@ -0,0 +1,76 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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;
+
+ 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 0000000..b19fea1
--- /dev/null
+++ b/libavfilter/vf_il.c
@@ -0,0 +1,212 @@
+/*
+ * 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;
+ enum FilterMode luma_mode, chroma_mode, alpha_mode;
+ 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);
+ }
+
+ ff_set_common_formats(ctx, formats);
+ return 0;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ IlContext *il = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int ret;
+
+ il->nb_planes = av_pix_fmt_count_planes(inlink->format);
+
+ il->has_alpha = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA);
+ if ((ret = av_image_fill_linesizes(il->linesize, inlink->format, inlink->w)) < 0)
+ return ret;
+
+ il->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 *il = 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],
+ il->linesize[0], inlink->h,
+ out->linesize[0], inpicref->linesize[0],
+ il->luma_mode, il->luma_swap);
+
+ for (comp = 1; comp < (il->nb_planes - il->has_alpha); comp++) {
+ interleave(out->data[comp], inpicref->data[comp],
+ il->linesize[comp], il->chroma_height,
+ out->linesize[comp], inpicref->linesize[comp],
+ il->chroma_mode, il->chroma_swap);
+ }
+
+ if (il->has_alpha) {
+ comp = il->nb_planes - 1;
+ interleave(out->data[comp], inpicref->data[comp],
+ il->linesize[comp], inlink->h,
+ out->linesize[comp], inpicref->linesize[comp],
+ il->alpha_mode, il->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 c534b0b..42e2c9a 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.
*/
@@ -46,12 +51,11 @@ 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()
} InterlaceContext;
#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,
@@ -63,13 +67,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 const enum AVPixelFormat formats_supported[] = {
AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P,
@@ -90,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)
@@ -113,8 +109,10 @@ 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;
av_log(ctx, AV_LOG_VERBOSE, "%s interlacing %s lowpass filter\n",
s->scan == MODE_TFF ? "tff" : "bff", (s->lowpass) ? "with" : "without");
@@ -131,7 +129,7 @@ static void copy_picture_field(AVFrame *src_frame, AVFrame *dst_frame,
int plane, i, j;
for (plane = 0; plane < desc->nb_components; plane++) {
- 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;
int linesize = av_image_get_linesize(inlink->format, inlink->w, plane);
uint8_t *dstp = dst_frame->data[plane];
const uint8_t *srcp = src_frame->data[plane];
@@ -194,7 +192,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;
}
@@ -206,7 +203,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
av_frame_copy_props(out, s->cur);
out->interlaced_frame = 1;
out->top_field_first = tff;
- out->pts /= 2; // adjust pts to new framerate
/* copy upper/lower field from cur */
copy_picture_field(s->cur, out, inlink, tff ? FIELD_UPPER : FIELD_LOWER, s->lowpass);
@@ -217,20 +213,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 +228,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 +239,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 0000000..5130208
--- /dev/null
+++ b/libavfilter/vf_kerndeint.c
@@ -0,0 +1,318 @@
+/*
+ * 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_free(kerndeint->tmp_data[0]);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum PixelFormat 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ return 0;
+}
+
+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 0000000..9fb1424
--- /dev/null
+++ b/libavfilter/vf_lenscorrection.c
@@ -0,0 +1,229 @@
+/*
+ * 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_NONE
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 bd3d59b..f55f552 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
*/
@@ -166,7 +166,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 */
@@ -259,17 +259,18 @@ 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 ((ret = parse_iplconvkernel(&dilate->kernel,
- *kernel_str ? kernel_str : default_kernel_str,
- ctx)) < 0)
+ else
+ kernel_str = av_strdup(default_kernel_str);
+ if (!kernel_str)
+ return AVERROR(ENOMEM);
+ if ((ret = parse_iplconvkernel(&dilate->kernel, kernel_str, ctx)) < 0)
return ret;
av_free(kernel_str);
- 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",
@@ -320,6 +321,10 @@ 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];
if (!strcmp(s->name, entry->name)) {
@@ -372,24 +377,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 }
@@ -404,17 +404,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 9299d40..0b7a2ca 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
@@ -182,15 +161,32 @@ static double compute_gammaval(void *opaque, double gamma)
return pow((val-minval)/(maxval-minval), gamma) * (maxval-minval)+minval;
}
+/**
+ * Compute Rec.709 gama 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 +195,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 +213,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 +230,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,14 +283,19 @@ 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 */
@@ -305,11 +303,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
outrow0 = out->data[0];
for (i = 0; i < in->height; i ++) {
+ int w = inlink->w;
+ const uint8_t (*tab)[256] = (const uint8_t (*)[256])s->lut;
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]];
+ for (j = 0; j < w; j++) {
+ switch (s->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 += s->step;
inrow += s->step;
}
@@ -318,77 +322,116 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
} 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);
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]];
+ for (i = 0; i < h; i++) {
+ const uint8_t *tab = s->lut[plane];
+ for (j = 0; j < w; j++)
+ outrow[j] = tab[inrow[j]];
inrow += in ->linesize[plane];
outrow += out->linesize[plane];
}
}
}
- 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 +440,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 +448,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 0000000..862ddde
--- /dev/null
+++ b/libavfilter/vf_lut3d.c
@@ -0,0 +1,815 @@
+/*
+ * 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;
+ enum interp_mode interpolation;
+ 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
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 0000000..2aa2e27
--- /dev/null
+++ b/libavfilter/vf_mcdeint.c
@@ -0,0 +1,315 @@
+/*
+ * 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;
+ enum MCDeintMode mode;
+ enum MCDeintParity parity;
+ 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 = 300;
+ 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);
+
+ 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 PixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ return 0;
+}
+
+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;
+ 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);
+ pkt.data = NULL; // packet data will be allocated by the encoder
+ pkt.size = 0;
+
+ 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 0000000..c76e82a
--- /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_mp.c b/libavfilter/vf_mp.c
new file mode 100644
index 0000000..9264e9b
--- /dev/null
+++ b/libavfilter/vf_mp.c
@@ -0,0 +1,792 @@
+/*
+ * 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 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
+ *
+ * Parts of this file have been stolen from mplayer
+ */
+
+/**
+ * @file
+ */
+
+#include "avfilter.h"
+#include "video.h"
+#include "formats.h"
+#include "internal.h"
+#include "libavutil/avassert.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+
+#include "libmpcodecs/vf.h"
+#include "libmpcodecs/img_format.h"
+#include "libmpcodecs/cpudetect.h"
+#include "libmpcodecs/av_helpers.h"
+#include "libmpcodecs/libvo/fastmemcpy.h"
+
+#include "libswscale/swscale.h"
+
+
+//FIXME maybe link the orig in
+//XXX: identical pix_fmt must be following with each others
+static const struct {
+ int fmt;
+ enum AVPixelFormat pix_fmt;
+} conversion_map[] = {
+ {IMGFMT_ARGB, AV_PIX_FMT_ARGB},
+ {IMGFMT_BGRA, AV_PIX_FMT_BGRA},
+ {IMGFMT_BGR24, AV_PIX_FMT_BGR24},
+ {IMGFMT_BGR16BE, AV_PIX_FMT_RGB565BE},
+ {IMGFMT_BGR16LE, AV_PIX_FMT_RGB565LE},
+ {IMGFMT_BGR15BE, AV_PIX_FMT_RGB555BE},
+ {IMGFMT_BGR15LE, AV_PIX_FMT_RGB555LE},
+ {IMGFMT_BGR12BE, AV_PIX_FMT_RGB444BE},
+ {IMGFMT_BGR12LE, AV_PIX_FMT_RGB444LE},
+ {IMGFMT_BGR8, AV_PIX_FMT_RGB8},
+ {IMGFMT_BGR4, AV_PIX_FMT_RGB4},
+ {IMGFMT_BGR1, AV_PIX_FMT_MONOBLACK},
+ {IMGFMT_RGB1, AV_PIX_FMT_MONOBLACK},
+ {IMGFMT_RG4B, AV_PIX_FMT_BGR4_BYTE},
+ {IMGFMT_BG4B, AV_PIX_FMT_RGB4_BYTE},
+ {IMGFMT_RGB48LE, AV_PIX_FMT_RGB48LE},
+ {IMGFMT_RGB48BE, AV_PIX_FMT_RGB48BE},
+ {IMGFMT_ABGR, AV_PIX_FMT_ABGR},
+ {IMGFMT_RGBA, AV_PIX_FMT_RGBA},
+ {IMGFMT_RGB24, AV_PIX_FMT_RGB24},
+ {IMGFMT_RGB16BE, AV_PIX_FMT_BGR565BE},
+ {IMGFMT_RGB16LE, AV_PIX_FMT_BGR565LE},
+ {IMGFMT_RGB15BE, AV_PIX_FMT_BGR555BE},
+ {IMGFMT_RGB15LE, AV_PIX_FMT_BGR555LE},
+ {IMGFMT_RGB12BE, AV_PIX_FMT_BGR444BE},
+ {IMGFMT_RGB12LE, AV_PIX_FMT_BGR444LE},
+ {IMGFMT_RGB8, AV_PIX_FMT_BGR8},
+ {IMGFMT_RGB4, AV_PIX_FMT_BGR4},
+ {IMGFMT_BGR8, AV_PIX_FMT_PAL8},
+ {IMGFMT_YUY2, AV_PIX_FMT_YUYV422},
+ {IMGFMT_UYVY, AV_PIX_FMT_UYVY422},
+ {IMGFMT_NV12, AV_PIX_FMT_NV12},
+ {IMGFMT_NV21, AV_PIX_FMT_NV21},
+ {IMGFMT_Y800, AV_PIX_FMT_GRAY8},
+ {IMGFMT_Y8, AV_PIX_FMT_GRAY8},
+ {IMGFMT_YVU9, AV_PIX_FMT_YUV410P},
+ {IMGFMT_IF09, AV_PIX_FMT_YUV410P},
+ {IMGFMT_YV12, AV_PIX_FMT_YUV420P},
+ {IMGFMT_I420, AV_PIX_FMT_YUV420P},
+ {IMGFMT_IYUV, AV_PIX_FMT_YUV420P},
+ {IMGFMT_411P, AV_PIX_FMT_YUV411P},
+ {IMGFMT_422P, AV_PIX_FMT_YUV422P},
+ {IMGFMT_444P, AV_PIX_FMT_YUV444P},
+ {IMGFMT_440P, AV_PIX_FMT_YUV440P},
+
+ {IMGFMT_420A, AV_PIX_FMT_YUVA420P},
+
+ {IMGFMT_420P16_LE, AV_PIX_FMT_YUV420P16LE},
+ {IMGFMT_420P16_BE, AV_PIX_FMT_YUV420P16BE},
+ {IMGFMT_422P16_LE, AV_PIX_FMT_YUV422P16LE},
+ {IMGFMT_422P16_BE, AV_PIX_FMT_YUV422P16BE},
+ {IMGFMT_444P16_LE, AV_PIX_FMT_YUV444P16LE},
+ {IMGFMT_444P16_BE, AV_PIX_FMT_YUV444P16BE},
+
+ // YUVJ are YUV formats that use the full Y range and not just
+ // 16 - 235 (see colorspaces.txt).
+ // Currently they are all treated the same way.
+ {IMGFMT_YV12, AV_PIX_FMT_YUVJ420P},
+ {IMGFMT_422P, AV_PIX_FMT_YUVJ422P},
+ {IMGFMT_444P, AV_PIX_FMT_YUVJ444P},
+ {IMGFMT_440P, AV_PIX_FMT_YUVJ440P},
+
+#if FF_API_XVMC
+ {IMGFMT_XVMC_MOCO_MPEG2, AV_PIX_FMT_XVMC_MPEG2_MC},
+ {IMGFMT_XVMC_IDCT_MPEG2, AV_PIX_FMT_XVMC_MPEG2_IDCT},
+#endif /* FF_API_XVMC */
+
+ {IMGFMT_VDPAU_MPEG1, AV_PIX_FMT_VDPAU_MPEG1},
+ {IMGFMT_VDPAU_MPEG2, AV_PIX_FMT_VDPAU_MPEG2},
+ {IMGFMT_VDPAU_H264, AV_PIX_FMT_VDPAU_H264},
+ {IMGFMT_VDPAU_WMV3, AV_PIX_FMT_VDPAU_WMV3},
+ {IMGFMT_VDPAU_VC1, AV_PIX_FMT_VDPAU_VC1},
+ {IMGFMT_VDPAU_MPEG4, AV_PIX_FMT_VDPAU_MPEG4},
+ {0, AV_PIX_FMT_NONE}
+};
+
+extern const vf_info_t ff_vf_info_eq2;
+extern const vf_info_t ff_vf_info_eq;
+extern const vf_info_t ff_vf_info_fspp;
+extern const vf_info_t ff_vf_info_ilpack;
+extern const vf_info_t ff_vf_info_pp7;
+extern const vf_info_t ff_vf_info_softpulldown;
+extern const vf_info_t ff_vf_info_uspp;
+
+
+static const vf_info_t* const filters[]={
+ &ff_vf_info_eq2,
+ &ff_vf_info_eq,
+ &ff_vf_info_fspp,
+ &ff_vf_info_ilpack,
+ &ff_vf_info_pp7,
+ &ff_vf_info_softpulldown,
+ &ff_vf_info_uspp,
+
+ NULL
+};
+
+/*
+Unsupported filters
+1bpp
+ass
+bmovl
+crop
+dvbscale
+flip
+expand
+format
+halfpack
+lavc
+lavcdeint
+noformat
+pp
+scale
+tfields
+vo
+yadif
+zrmjpeg
+*/
+
+CpuCaps ff_gCpuCaps; //FIXME initialize this so optims work
+
+enum AVPixelFormat ff_mp2ff_pix_fmt(int mp){
+ int i;
+ for(i=0; conversion_map[i].fmt && mp != conversion_map[i].fmt; i++)
+ ;
+ return mp == conversion_map[i].fmt ? conversion_map[i].pix_fmt : AV_PIX_FMT_NONE;
+}
+
+typedef struct {
+ const AVClass *class;
+ vf_instance_t vf;
+ vf_instance_t next_vf;
+ AVFilterContext *avfctx;
+ int frame_returned;
+ char *filter;
+ enum AVPixelFormat in_pix_fmt;
+} MPContext;
+
+#define OFFSET(x) offsetof(MPContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption mp_options[] = {
+ { "filter", "set MPlayer filter name and parameters", OFFSET(filter), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(mp);
+
+void ff_mp_msg(int mod, int lev, const char *format, ... ){
+ va_list va;
+ va_start(va, format);
+ //FIXME convert lev/mod
+ av_vlog(NULL, AV_LOG_DEBUG, format, va);
+ va_end(va);
+}
+
+int ff_mp_msg_test(int mod, int lev){
+ return 123;
+}
+
+void ff_init_avcodec(void)
+{
+ //we maybe should init but its kinda 1. unneeded 2. a bit impolite from here
+}
+
+//Exact copy of vf.c
+void ff_vf_clone_mpi_attributes(mp_image_t* dst, mp_image_t* src){
+ dst->pict_type= src->pict_type;
+ dst->fields = src->fields;
+ dst->qscale_type= src->qscale_type;
+ if(dst->width == src->width && dst->height == src->height){
+ dst->qstride= src->qstride;
+ dst->qscale= src->qscale;
+ }
+}
+
+//Exact copy of vf.c
+void ff_vf_next_draw_slice(struct vf_instance *vf,unsigned char** src, int * stride,int w, int h, int x, int y){
+ if (vf->next->draw_slice) {
+ vf->next->draw_slice(vf->next,src,stride,w,h,x,y);
+ return;
+ }
+ if (!vf->dmpi) {
+ ff_mp_msg(MSGT_VFILTER,MSGL_ERR,"draw_slice: dmpi not stored by vf_%s\n", vf->info->name);
+ return;
+ }
+ if (!(vf->dmpi->flags & MP_IMGFLAG_PLANAR)) {
+ memcpy_pic(vf->dmpi->planes[0]+y*vf->dmpi->stride[0]+vf->dmpi->bpp/8*x,
+ src[0], vf->dmpi->bpp/8*w, h, vf->dmpi->stride[0], stride[0]);
+ return;
+ }
+ memcpy_pic(vf->dmpi->planes[0]+y*vf->dmpi->stride[0]+x, src[0],
+ w, h, vf->dmpi->stride[0], stride[0]);
+ memcpy_pic(vf->dmpi->planes[1]+(y>>vf->dmpi->chroma_y_shift)*vf->dmpi->stride[1]+(x>>vf->dmpi->chroma_x_shift),
+ src[1], w>>vf->dmpi->chroma_x_shift, h>>vf->dmpi->chroma_y_shift, vf->dmpi->stride[1], stride[1]);
+ memcpy_pic(vf->dmpi->planes[2]+(y>>vf->dmpi->chroma_y_shift)*vf->dmpi->stride[2]+(x>>vf->dmpi->chroma_x_shift),
+ src[2], w>>vf->dmpi->chroma_x_shift, h>>vf->dmpi->chroma_y_shift, vf->dmpi->stride[2], stride[2]);
+}
+
+//Exact copy of vf.c
+void ff_vf_mpi_clear(mp_image_t* mpi,int x0,int y0,int w,int h){
+ int y;
+ if(mpi->flags&MP_IMGFLAG_PLANAR){
+ y0&=~1;h+=h&1;
+ if(x0==0 && w==mpi->width){
+ // full width clear:
+ memset(mpi->planes[0]+mpi->stride[0]*y0,0,mpi->stride[0]*h);
+ memset(mpi->planes[1]+mpi->stride[1]*(y0>>mpi->chroma_y_shift),128,mpi->stride[1]*(h>>mpi->chroma_y_shift));
+ memset(mpi->planes[2]+mpi->stride[2]*(y0>>mpi->chroma_y_shift),128,mpi->stride[2]*(h>>mpi->chroma_y_shift));
+ } else
+ for(y=y0;y<y0+h;y+=2){
+ memset(mpi->planes[0]+x0+mpi->stride[0]*y,0,w);
+ memset(mpi->planes[0]+x0+mpi->stride[0]*(y+1),0,w);
+ memset(mpi->planes[1]+(x0>>mpi->chroma_x_shift)+mpi->stride[1]*(y>>mpi->chroma_y_shift),128,(w>>mpi->chroma_x_shift));
+ memset(mpi->planes[2]+(x0>>mpi->chroma_x_shift)+mpi->stride[2]*(y>>mpi->chroma_y_shift),128,(w>>mpi->chroma_x_shift));
+ }
+ return;
+ }
+ // packed:
+ for(y=y0;y<y0+h;y++){
+ unsigned char* dst=mpi->planes[0]+mpi->stride[0]*y+(mpi->bpp>>3)*x0;
+ if(mpi->flags&MP_IMGFLAG_YUV){
+ unsigned int* p=(unsigned int*) dst;
+ int size=(mpi->bpp>>3)*w/4;
+ int i;
+#if HAVE_BIGENDIAN
+#define CLEAR_PACKEDYUV_PATTERN 0x00800080
+#define CLEAR_PACKEDYUV_PATTERN_SWAPPED 0x80008000
+#else
+#define CLEAR_PACKEDYUV_PATTERN 0x80008000
+#define CLEAR_PACKEDYUV_PATTERN_SWAPPED 0x00800080
+#endif
+ if(mpi->flags&MP_IMGFLAG_SWAPPED){
+ for(i=0;i<size-3;i+=4) p[i]=p[i+1]=p[i+2]=p[i+3]=CLEAR_PACKEDYUV_PATTERN_SWAPPED;
+ for(;i<size;i++) p[i]=CLEAR_PACKEDYUV_PATTERN_SWAPPED;
+ } else {
+ for(i=0;i<size-3;i+=4) p[i]=p[i+1]=p[i+2]=p[i+3]=CLEAR_PACKEDYUV_PATTERN;
+ for(;i<size;i++) p[i]=CLEAR_PACKEDYUV_PATTERN;
+ }
+ } else
+ memset(dst,0,(mpi->bpp>>3)*w);
+ }
+}
+
+int ff_vf_next_query_format(struct vf_instance *vf, unsigned int fmt){
+ return 1;
+}
+
+//used by delogo
+unsigned int ff_vf_match_csp(vf_instance_t** vfp,const unsigned int* list,unsigned int preferred){
+ return preferred;
+}
+
+mp_image_t* ff_vf_get_image(vf_instance_t* vf, unsigned int outfmt, int mp_imgtype, int mp_imgflag, int w, int h){
+ MPContext *m= (MPContext*)(((uint8_t*)vf) - offsetof(MPContext, next_vf));
+ mp_image_t* mpi=NULL;
+ int w2;
+ int number = mp_imgtype >> 16;
+
+ av_assert0(vf->next == NULL); // all existing filters call this just on next
+
+ //vf_dint needs these as it calls ff_vf_get_image() before configuring the output
+ if(vf->w==0 && w>0) vf->w=w;
+ if(vf->h==0 && h>0) vf->h=h;
+
+ av_assert0(w == -1 || w >= vf->w);
+ av_assert0(h == -1 || h >= vf->h);
+ av_assert0(vf->w > 0);
+ av_assert0(vf->h > 0);
+
+ av_log(m->avfctx, AV_LOG_DEBUG, "get_image: %d:%d, vf: %d:%d\n", w,h,vf->w,vf->h);
+
+ if (w == -1) w = vf->w;
+ if (h == -1) h = vf->h;
+
+ w2=(mp_imgflag&MP_IMGFLAG_ACCEPT_ALIGNED_STRIDE)?((w+15)&(~15)):w;
+
+ // Note: we should call libvo first to check if it supports direct rendering
+ // and if not, then fallback to software buffers:
+ switch(mp_imgtype & 0xff){
+ case MP_IMGTYPE_EXPORT:
+ if(!vf->imgctx.export_images[0]) vf->imgctx.export_images[0]=ff_new_mp_image(w2,h);
+ mpi=vf->imgctx.export_images[0];
+ break;
+ case MP_IMGTYPE_STATIC:
+ if(!vf->imgctx.static_images[0]) vf->imgctx.static_images[0]=ff_new_mp_image(w2,h);
+ mpi=vf->imgctx.static_images[0];
+ break;
+ case MP_IMGTYPE_TEMP:
+ if(!vf->imgctx.temp_images[0]) vf->imgctx.temp_images[0]=ff_new_mp_image(w2,h);
+ mpi=vf->imgctx.temp_images[0];
+ break;
+ case MP_IMGTYPE_IPB:
+ if(!(mp_imgflag&MP_IMGFLAG_READABLE)){ // B frame:
+ if(!vf->imgctx.temp_images[0]) vf->imgctx.temp_images[0]=ff_new_mp_image(w2,h);
+ mpi=vf->imgctx.temp_images[0];
+ break;
+ }
+ case MP_IMGTYPE_IP:
+ if(!vf->imgctx.static_images[vf->imgctx.static_idx]) vf->imgctx.static_images[vf->imgctx.static_idx]=ff_new_mp_image(w2,h);
+ mpi=vf->imgctx.static_images[vf->imgctx.static_idx];
+ vf->imgctx.static_idx^=1;
+ break;
+ case MP_IMGTYPE_NUMBERED:
+ if (number == -1) {
+ int i;
+ for (i = 0; i < NUM_NUMBERED_MPI; i++)
+ if (!vf->imgctx.numbered_images[i] || !vf->imgctx.numbered_images[i]->usage_count)
+ break;
+ number = i;
+ }
+ if (number < 0 || number >= NUM_NUMBERED_MPI) return NULL;
+ if (!vf->imgctx.numbered_images[number]) vf->imgctx.numbered_images[number] = ff_new_mp_image(w2,h);
+ mpi = vf->imgctx.numbered_images[number];
+ mpi->number = number;
+ break;
+ }
+ if(mpi){
+ mpi->type=mp_imgtype;
+ mpi->w=vf->w; mpi->h=vf->h;
+ // keep buffer allocation status & color flags only:
+// mpi->flags&=~(MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE|MP_IMGFLAG_DIRECT);
+ mpi->flags&=MP_IMGFLAG_ALLOCATED|MP_IMGFLAG_TYPE_DISPLAYED|MP_IMGFLAGMASK_COLORS;
+ // accept restrictions, draw_slice and palette flags only:
+ mpi->flags|=mp_imgflag&(MP_IMGFLAGMASK_RESTRICTIONS|MP_IMGFLAG_DRAW_CALLBACK|MP_IMGFLAG_RGB_PALETTE);
+ if(!vf->draw_slice) mpi->flags&=~MP_IMGFLAG_DRAW_CALLBACK;
+ if(mpi->width!=w2 || mpi->height!=h){
+// printf("vf.c: MPI parameters changed! %dx%d -> %dx%d \n", mpi->width,mpi->height,w2,h);
+ if(mpi->flags&MP_IMGFLAG_ALLOCATED){
+ if(mpi->width<w2 || mpi->height<h){
+ // need to re-allocate buffer memory:
+ av_free(mpi->planes[0]);
+ mpi->flags&=~MP_IMGFLAG_ALLOCATED;
+ ff_mp_msg(MSGT_VFILTER,MSGL_V,"vf.c: have to REALLOCATE buffer memory :(\n");
+ }
+// } else {
+ } {
+ mpi->width=w2; mpi->chroma_width=(w2 + (1<<mpi->chroma_x_shift) - 1)>>mpi->chroma_x_shift;
+ mpi->height=h; mpi->chroma_height=(h + (1<<mpi->chroma_y_shift) - 1)>>mpi->chroma_y_shift;
+ }
+ }
+ if(!mpi->bpp) ff_mp_image_setfmt(mpi,outfmt);
+ if(!(mpi->flags&MP_IMGFLAG_ALLOCATED) && mpi->type>MP_IMGTYPE_EXPORT){
+
+ av_assert0(!vf->get_image);
+ // check libvo first!
+ if(vf->get_image) vf->get_image(vf,mpi);
+
+ if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
+ // non-direct and not yet allocated image. allocate it!
+ if (!mpi->bpp) { // no way we can allocate this
+ ff_mp_msg(MSGT_DECVIDEO, MSGL_FATAL,
+ "ff_vf_get_image: Tried to allocate a format that can not be allocated!\n");
+ return NULL;
+ }
+
+ // check if codec prefer aligned stride:
+ if(mp_imgflag&MP_IMGFLAG_PREFER_ALIGNED_STRIDE){
+ int align=(mpi->flags&MP_IMGFLAG_PLANAR &&
+ mpi->flags&MP_IMGFLAG_YUV) ?
+ (8<<mpi->chroma_x_shift)-1 : 15; // -- maybe FIXME
+ w2=((w+align)&(~align));
+ if(mpi->width!=w2){
+#if 0
+ // we have to change width... check if we CAN co it:
+ int flags=vf->query_format(vf,outfmt); // should not fail
+ if(!(flags&3)) ff_mp_msg(MSGT_DECVIDEO,MSGL_WARN,"??? ff_vf_get_image{vf->query_format(outfmt)} failed!\n");
+// printf("query -> 0x%X \n",flags);
+ if(flags&VFCAP_ACCEPT_STRIDE){
+#endif
+ mpi->width=w2;
+ mpi->chroma_width=(w2 + (1<<mpi->chroma_x_shift) - 1)>>mpi->chroma_x_shift;
+// }
+ }
+ }
+
+ ff_mp_image_alloc_planes(mpi);
+// printf("clearing img!\n");
+ ff_vf_mpi_clear(mpi,0,0,mpi->width,mpi->height);
+ }
+ }
+ av_assert0(!vf->start_slice);
+ if(mpi->flags&MP_IMGFLAG_DRAW_CALLBACK)
+ if(vf->start_slice) vf->start_slice(vf,mpi);
+ if(!(mpi->flags&MP_IMGFLAG_TYPE_DISPLAYED)){
+ ff_mp_msg(MSGT_DECVIDEO,MSGL_V,"*** [%s] %s%s mp_image_t, %dx%dx%dbpp %s %s, %d bytes\n",
+ "NULL"/*vf->info->name*/,
+ (mpi->type==MP_IMGTYPE_EXPORT)?"Exporting":
+ ((mpi->flags&MP_IMGFLAG_DIRECT)?"Direct Rendering":"Allocating"),
+ (mpi->flags&MP_IMGFLAG_DRAW_CALLBACK)?" (slices)":"",
+ mpi->width,mpi->height,mpi->bpp,
+ (mpi->flags&MP_IMGFLAG_YUV)?"YUV":((mpi->flags&MP_IMGFLAG_SWAPPED)?"BGR":"RGB"),
+ (mpi->flags&MP_IMGFLAG_PLANAR)?"planar":"packed",
+ mpi->bpp*mpi->width*mpi->height/8);
+ ff_mp_msg(MSGT_DECVIDEO,MSGL_DBG2,"(imgfmt: %x, planes: %p,%p,%p strides: %d,%d,%d, chroma: %dx%d, shift: h:%d,v:%d)\n",
+ mpi->imgfmt, mpi->planes[0], mpi->planes[1], mpi->planes[2],
+ mpi->stride[0], mpi->stride[1], mpi->stride[2],
+ mpi->chroma_width, mpi->chroma_height, mpi->chroma_x_shift, mpi->chroma_y_shift);
+ mpi->flags|=MP_IMGFLAG_TYPE_DISPLAYED;
+ }
+
+ mpi->qscale = NULL;
+ mpi->usage_count++;
+ }
+// printf("\rVF_MPI: %p %p %p %d %d %d \n",
+// mpi->planes[0],mpi->planes[1],mpi->planes[2],
+// mpi->stride[0],mpi->stride[1],mpi->stride[2]);
+ return mpi;
+}
+
+int ff_vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts){
+ MPContext *m= (MPContext*)(((uint8_t*)vf) - offsetof(MPContext, vf));
+ AVFilterLink *outlink = m->avfctx->outputs[0];
+ AVFrame *picref = av_frame_alloc();
+ int i;
+
+ av_assert0(vf->next);
+
+ av_log(m->avfctx, AV_LOG_DEBUG, "ff_vf_next_put_image\n");
+
+ if (!picref)
+ goto fail;
+
+ picref->width = mpi->w;
+ picref->height = mpi->h;
+
+ for(i=0; conversion_map[i].fmt && mpi->imgfmt != conversion_map[i].fmt; i++);
+ picref->format = conversion_map[i].pix_fmt;
+
+ for(i=0; conversion_map[i].fmt && m->in_pix_fmt != conversion_map[i].pix_fmt; i++);
+ if (mpi->imgfmt == conversion_map[i].fmt)
+ picref->format = conversion_map[i].pix_fmt;
+
+ memcpy(picref->linesize, mpi->stride, FFMIN(sizeof(picref->linesize), sizeof(mpi->stride)));
+
+ for(i=0; i<4 && mpi->stride[i]; i++){
+ picref->data[i] = mpi->planes[i];
+ }
+
+ if(pts != MP_NOPTS_VALUE)
+ picref->pts= pts * av_q2d(outlink->time_base);
+
+ if(1) { // mp buffers are currently unsupported in libavfilter, we thus must copy
+ AVFrame *tofree = picref;
+ picref = av_frame_clone(picref);
+ av_frame_free(&tofree);
+ }
+
+ ff_filter_frame(outlink, picref);
+ m->frame_returned++;
+
+ return 1;
+fail:
+ av_frame_free(&picref);
+ return 0;
+}
+
+int ff_vf_next_config(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int voflags, unsigned int outfmt){
+
+ av_assert0(width>0 && height>0);
+ vf->next->w = width; vf->next->h = height;
+
+ return 1;
+#if 0
+ int flags=vf->next->query_format(vf->next,outfmt);
+ if(!flags){
+ // hmm. colorspace mismatch!!!
+ //this is fatal for us ATM
+ return 0;
+ }
+ ff_mp_msg(MSGT_VFILTER,MSGL_V,"REQ: flags=0x%X req=0x%X \n",flags,vf->default_reqs);
+ miss=vf->default_reqs - (flags&vf->default_reqs);
+ if(miss&VFCAP_ACCEPT_STRIDE){
+ // vf requires stride support but vf->next doesn't support it!
+ // let's insert the 'expand' filter, it does the job for us:
+ vf_instance_t* vf2=vf_open_filter(vf->next,"expand",NULL);
+ if(!vf2) return 0; // shouldn't happen!
+ vf->next=vf2;
+ }
+ vf->next->w = width; vf->next->h = height;
+ return 1;
+#endif
+}
+
+int ff_vf_next_control(struct vf_instance *vf, int request, void* data){
+ MPContext *m= (MPContext*)(((uint8_t*)vf) - offsetof(MPContext, vf));
+ av_log(m->avfctx, AV_LOG_DEBUG, "Received control %d\n", request);
+ return 0;
+}
+
+static int vf_default_query_format(struct vf_instance *vf, unsigned int fmt){
+ MPContext *m= (MPContext*)(((uint8_t*)vf) - offsetof(MPContext, vf));
+ int i;
+ av_log(m->avfctx, AV_LOG_DEBUG, "query %X\n", fmt);
+
+ for(i=0; conversion_map[i].fmt; i++){
+ if(fmt==conversion_map[i].fmt)
+ return 1; //we suport all
+ }
+ return 0;
+}
+
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ MPContext *m = ctx->priv;
+ int cpu_flags = av_get_cpu_flags();
+ char name[256];
+ const char *args;
+ int i;
+
+ ff_gCpuCaps.hasMMX = cpu_flags & AV_CPU_FLAG_MMX;
+ ff_gCpuCaps.hasMMX2 = cpu_flags & AV_CPU_FLAG_MMX2;
+ ff_gCpuCaps.hasSSE = cpu_flags & AV_CPU_FLAG_SSE;
+ ff_gCpuCaps.hasSSE2 = cpu_flags & AV_CPU_FLAG_SSE2;
+ ff_gCpuCaps.hasSSE3 = cpu_flags & AV_CPU_FLAG_SSE3;
+ ff_gCpuCaps.hasSSSE3 = cpu_flags & AV_CPU_FLAG_SSSE3;
+ ff_gCpuCaps.hasSSE4 = cpu_flags & AV_CPU_FLAG_SSE4;
+ ff_gCpuCaps.hasSSE42 = cpu_flags & AV_CPU_FLAG_SSE42;
+ ff_gCpuCaps.hasAVX = cpu_flags & AV_CPU_FLAG_AVX;
+ ff_gCpuCaps.has3DNow = cpu_flags & AV_CPU_FLAG_3DNOW;
+ ff_gCpuCaps.has3DNowExt = cpu_flags & AV_CPU_FLAG_3DNOWEXT;
+
+ m->avfctx= ctx;
+
+ args = m->filter;
+ if(!args || 1!=sscanf(args, "%255[^:=]", name)){
+ av_log(ctx, AV_LOG_ERROR, "Invalid parameter.\n");
+ return AVERROR(EINVAL);
+ }
+ args += strlen(name);
+ if (args[0] == '=')
+ args++;
+
+ for(i=0; ;i++){
+ if(!filters[i] || !strcmp(name, filters[i]->name))
+ break;
+ }
+
+ if(!filters[i]){
+ av_log(ctx, AV_LOG_ERROR, "Unknown filter %s\n", name);
+ return AVERROR(EINVAL);
+ }
+
+ av_log(ctx, AV_LOG_WARNING,
+ "'%s' is a wrapped MPlayer filter (libmpcodecs). This filter may be removed\n"
+ "once it has been ported to a native libavfilter.\n", name);
+
+ memset(&m->vf,0,sizeof(m->vf));
+ m->vf.info= filters[i];
+
+ m->vf.next = &m->next_vf;
+ m->vf.put_image = ff_vf_next_put_image;
+ m->vf.config = ff_vf_next_config;
+ m->vf.query_format= vf_default_query_format;
+ m->vf.control = ff_vf_next_control;
+ m->vf.default_caps=VFCAP_ACCEPT_STRIDE;
+ m->vf.default_reqs=0;
+ if(m->vf.info->opts)
+ av_log(ctx, AV_LOG_ERROR, "opts / m_struct_set is unsupported\n");
+#if 0
+ if(vf->info->opts) { // vf_vo get some special argument
+ const m_struct_t* st = vf->info->opts;
+ void* vf_priv = m_struct_alloc(st);
+ int n;
+ for(n = 0 ; args && args[2*n] ; n++)
+ m_struct_set(st,vf_priv,args[2*n],args[2*n+1]);
+ vf->priv = vf_priv;
+ args = NULL;
+ } else // Otherwise we should have the '_oldargs_'
+ if(args && !strcmp(args[0],"_oldargs_"))
+ args = (char**)args[1];
+ else
+ args = NULL;
+#endif
+ if(m->vf.info->vf_open(&m->vf, (char*)args)<=0){
+ av_log(ctx, AV_LOG_ERROR, "vf_open() of %s with arg=%s failed\n", name, args);
+ return -1;
+ }
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ MPContext *m = ctx->priv;
+ vf_instance_t *vf = &m->vf;
+
+ while(vf){
+ vf_instance_t *next = vf->next;
+ if(vf->uninit)
+ vf->uninit(vf);
+ ff_free_mp_image(vf->imgctx.static_images[0]);
+ ff_free_mp_image(vf->imgctx.static_images[1]);
+ ff_free_mp_image(vf->imgctx.temp_images[0]);
+ ff_free_mp_image(vf->imgctx.export_images[0]);
+ vf = next;
+ }
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *avfmts=NULL;
+ MPContext *m = ctx->priv;
+ enum AVPixelFormat lastpixfmt = AV_PIX_FMT_NONE;
+ int i;
+
+ for(i=0; conversion_map[i].fmt; i++){
+ av_log(ctx, AV_LOG_DEBUG, "query: %X\n", conversion_map[i].fmt);
+ if(m->vf.query_format(&m->vf, conversion_map[i].fmt)){
+ av_log(ctx, AV_LOG_DEBUG, "supported,adding\n");
+ if (conversion_map[i].pix_fmt != lastpixfmt) {
+ ff_add_format(&avfmts, conversion_map[i].pix_fmt);
+ lastpixfmt = conversion_map[i].pix_fmt;
+ }
+ }
+ }
+
+ if (!avfmts)
+ return -1;
+
+ //We assume all allowed input formats are also allowed output formats
+ ff_set_common_formats(ctx, avfmts);
+ return 0;
+}
+
+static int config_inprops(AVFilterLink *inlink)
+{
+ MPContext *m = inlink->dst->priv;
+ int i;
+ for(i=0; conversion_map[i].fmt && conversion_map[i].pix_fmt != inlink->format; i++);
+
+ av_assert0(conversion_map[i].fmt && inlink->w && inlink->h);
+
+ m->vf.fmt.have_configured = 1;
+ m->vf.fmt.orig_height = inlink->h;
+ m->vf.fmt.orig_width = inlink->w;
+ m->vf.fmt.orig_fmt = conversion_map[i].fmt;
+
+ if(m->vf.config(&m->vf, inlink->w, inlink->h, inlink->w, inlink->h, 0, conversion_map[i].fmt)<=0)
+ return -1;
+
+ return 0;
+}
+
+static int config_outprops(AVFilterLink *outlink)
+{
+ MPContext *m = outlink->src->priv;
+
+ outlink->w = m->next_vf.w;
+ outlink->h = m->next_vf.h;
+
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ MPContext *m = outlink->src->priv;
+ int ret;
+
+ av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame\n");
+
+ for(m->frame_returned=0; !m->frame_returned;){
+ ret=ff_request_frame(outlink->src->inputs[0]);
+ if(ret<0)
+ break;
+ }
+
+ av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame ret=%d\n", ret);
+ return ret;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
+{
+ MPContext *m = inlink->dst->priv;
+ int i;
+ double pts= MP_NOPTS_VALUE;
+ mp_image_t* mpi = ff_new_mp_image(inpic->width, inpic->height);
+
+ if(inpic->pts != AV_NOPTS_VALUE)
+ pts= inpic->pts / av_q2d(inlink->time_base);
+
+ for(i=0; conversion_map[i].fmt && conversion_map[i].pix_fmt != inlink->format; i++);
+ ff_mp_image_setfmt(mpi,conversion_map[i].fmt);
+ m->in_pix_fmt = inlink->format;
+
+ memcpy(mpi->planes, inpic->data, FFMIN(sizeof(inpic->data) , sizeof(mpi->planes)));
+ memcpy(mpi->stride, inpic->linesize, FFMIN(sizeof(inpic->linesize), sizeof(mpi->stride)));
+
+ if (inpic->interlaced_frame)
+ mpi->fields |= MP_IMGFIELD_INTERLACED;
+ if (inpic->top_field_first)
+ mpi->fields |= MP_IMGFIELD_TOP_FIRST;
+ if (inpic->repeat_pict)
+ mpi->fields |= MP_IMGFIELD_REPEAT_FIRST;
+
+ // mpi->flags|=MP_IMGFLAG_ALLOCATED; ?
+ mpi->flags |= MP_IMGFLAG_READABLE;
+ if(!av_frame_is_writable(inpic))
+ mpi->flags |= MP_IMGFLAG_PRESERVE;
+ if(m->vf.put_image(&m->vf, mpi, pts) == 0){
+ av_log(m->avfctx, AV_LOG_DEBUG, "put_image() says skip\n");
+ }else{
+ av_frame_free(&inpic);
+ }
+ ff_free_mp_image(mpi);
+ return 0;
+}
+
+static const AVFilterPad mp_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_inprops,
+ },
+ { NULL }
+};
+
+static const AVFilterPad mp_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = config_outprops,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_mp = {
+ .name = "mp",
+ .description = NULL_IF_CONFIG_SMALL("Apply a libmpcodecs filter to the input video."),
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(MPContext),
+ .query_formats = query_formats,
+ .inputs = mp_inputs,
+ .outputs = mp_outputs,
+ .priv_class = &mp_class,
+};
diff --git a/libavfilter/vf_mpdecimate.c b/libavfilter/vf_mpdecimate.c
new file mode 100644
index 0000000..3ed9602
--- /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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ return 0;
+}
+
+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 0000000..4acad8a
--- /dev/null
+++ b/libavfilter/vf_noise.c
@@ -0,0 +1,351 @@
+/*
+ * 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);
+ }
+
+ ff_set_common_formats(ctx, formats);
+ return 0;
+}
+
+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 0000000..2207ed9
--- /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 f872587..2355615 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 11e0a6f..80d99bd 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,211 @@ 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
+
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;
+ enum OverlayFormat { OVERLAY_FORMAT_YUV420, OVERLAY_FORMAT_YUV422, OVERLAY_FORMAT_YUV444, OVERLAY_FORMAT_RGB, OVERLAY_FORMAT_NB} format;
+ enum EvalMode { EVAL_MODE_INIT, EVAL_MODE_FRAME, EVAL_MODE_NB } eval_mode;
+
+ 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
- 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 +288,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 +348,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 +549,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;
+ OverlayContext *s = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
- av_assert0(!s->main);
- s->main = frame;
+ if (s->eval_mode == EVAL_MODE_FRAME) {
+ int64_t pos = av_frame_get_pkt_pos(mainpic);
- return 0;
-}
+ 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;
-static int filter_frame_overlay(AVFilterLink *inlink, AVFrame *frame)
-{
- OverlayContext *s = inlink->dst->priv;
-
- 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 +665,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 0000000..5b47f76
--- /dev/null
+++ b/libavfilter/vf_owdenoise.c
@@ -0,0 +1,342 @@
+/*
+ * 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 int mirror(int x, int w)
+{
+ while ((unsigned)x > (unsigned)w) {
+ x = -x;
+ if (x < 0)
+ x += 2 * w;
+ }
+ return x;
+}
+
+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[mirror(x - i, w - 1) * linesize]
+ + src[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 = mirror(x - i, w - 1) * linesize;
+ const int x1 = 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
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 634af4c..2d9b9d0 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,22 +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));
+ ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
return 0;
}
@@ -104,58 +87,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 +159,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 +213,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 +238,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 +283,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 +310,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 +356,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 +393,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_perspective.c b/libavfilter/vf_perspective.c
new file mode 100644
index 0000000..bf06d02
--- /dev/null
+++ b/libavfilter/vf_perspective.c
@@ -0,0 +1,483 @@
+/*
+ * 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/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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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;
+ }
+
+ 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(sum, 0, 255);
+ 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(sum, 0, 255);
+ 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 0000000..82dc603
--- /dev/null
+++ b/libavfilter/vf_phase.c
@@ -0,0 +1,329 @@
+/*
+ * 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;
+ enum PhaseMode mode;
+ 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 0c5b7a1..790dd0d 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 0000000..e33ac48
--- /dev/null
+++ b/libavfilter/vf_pp.c
@@ -0,0 +1,193 @@
+/*
+ * 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 PixelFormat 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
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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_psnr.c b/libavfilter/vf_psnr.c
new file mode 100644
index 0000000..082612a
--- /dev/null
+++ b/libavfilter/vf_psnr.c
@@ -0,0 +1,386 @@
+/*
+ * 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 PixelFormat 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 0000000..c38d0bb
--- /dev/null
+++ b/libavfilter/vf_pullup.c
@@ -0,0 +1,780 @@
+/*
+ * 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
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+#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 0000000..8f59335
--- /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_removelogo.c b/libavfilter/vf_removelogo.c
new file mode 100644
index 0000000..555517f
--- /dev/null
+++ b/libavfilter/vf_removelogo.c
@@ -0,0 +1,585 @@
+/*
+ * 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 };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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_rotate.c b/libavfilter/vf_rotate.c
new file mode 100644
index 0000000..8dec742
--- /dev/null
+++ b/libavfilter/vf_rotate.c
@@ -0,0 +1,567 @@
+/*
+ * 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 PixelFormat 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 0000000..aa38b53
--- /dev/null
+++ b/libavfilter/vf_sab.c
@@ -0,0 +1,339 @@
+/*
+ * 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
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ return 0;
+}
+
+#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;
+ if (iy < 0) iy = -iy;
+ else if (iy >= h) iy = h+h-iy-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;
+ if (iy < 0) iy = -iy;
+ else if (iy >= h) iy = h+h-iy-1;
+
+ for (dx = 0; dx < radius*2 + 1; dx++) {
+ int ix = x+dx - radius;
+ if (ix < 0) ix = -ix;
+ else if (ix >= w) ix = w+w-ix-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 73ea9d2..64b88c2 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 (h < -1) {
+ factor_h = -h;
}
- if (w == -1 && h == -1)
+
+ 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,132 @@ 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);
+
+ 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( 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 +472,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 +596,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 8d0e6c3..0000000
--- 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 0000000..42ce682
--- /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 0000000..eb4df74
--- /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;
+ enum SetFieldMode mode;
+} 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 ede1765..aa3bc83 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:%"PRId64" pts:%s pts_time:%s pos:%"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,14 @@ 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 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,
},
{ NULL }
};
@@ -161,10 +182,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_shuffleplanes.c b/libavfilter/vf_shuffleplanes.c
index 1bc77b0..80085cd 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 0000000..47545aa
--- /dev/null
+++ b/libavfilter/vf_signalstats.c
@@ -0,0 +1,481 @@
+/*
+ * 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
+ enum FilterMode outfilter;
+ int filters;
+ AVFrame *frame_prev;
+ char *vrep_line;
+ uint8_t rgba_color[4];
+ int yuv_color[3];
+} SignalstatsContext;
+
+#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 repitition", 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 repitition", 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_freep(&s->vrep_line);
+}
+
+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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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;
+
+ if (s->filters & 1<<FILTER_VREP) {
+ s->vrep_line = av_malloc(inlink->h * sizeof(*s->vrep_line));
+ if (!s->vrep_line)
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
+static void burn_frame(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(SignalstatsContext *s, const AVFrame *in, AVFrame *out, int y, int w, int h)
+{
+ int x, score = 0;
+ 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(SignalstatsContext *s, const AVFrame *in, AVFrame *out, int y, int w, int h)
+{
+ const uint8_t *p = in->data[0];
+ int lw = in->linesize[0];
+ int x, score = 0, filt;
+
+ if (y - 1 < 0 || y + 1 >= h)
+ return 0;
+
+ // 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 void filter_init_vrep(SignalstatsContext *s, const AVFrame *p, int w, int h)
+{
+ int i, y;
+ int lw = p->linesize[0];
+
+ for (y = VREP_START; y < h; y++) {
+ int totdiff = 0;
+ int y2lw = (y - VREP_START) * lw;
+ int ylw = y * lw;
+
+ for (i = 0; i < w; i++)
+ totdiff += abs(p->data[0][y2lw + i] - p->data[0][ylw + i]);
+
+ /* this value should be definable */
+ s->vrep_line[y] = totdiff < w;
+ }
+}
+
+static int filter_vrep(SignalstatsContext *s, const AVFrame *in, AVFrame *out, int y, int w, int h)
+{
+ int x, score = 0;
+
+ if (y < VREP_START)
+ return 0;
+
+ for (x = 0; x < w; x++) {
+ if (s->vrep_line[y]) {
+ score++;
+ if (out)
+ burn_frame(s, out, x, y);
+ }
+ }
+ return score;
+}
+
+static const struct {
+ const char *name;
+ void (*init)(SignalstatsContext *s, const AVFrame *p, int w, int h);
+ int (*process)(SignalstatsContext *s, const AVFrame *in, AVFrame *out, int y, int w, int h);
+} filters_def[] = {
+ {"TOUT", NULL, filter_tout},
+ {"VREP", filter_init_vrep, filter_vrep},
+ {"BRNG", NULL, filter_brng},
+ {NULL}
+};
+
+#define DEPTH 256
+
+static int filter_frame(AVFilterLink *link, AVFrame *in)
+{
+ SignalstatsContext *s = link->dst->priv;
+ AVFilterLink *outlink = link->dst->outputs[0];
+ AVFrame *out = in;
+ int i, j;
+ int w = 0, cw = 0, // in
+ pw = 0, cpw = 0; // prev
+ int yuv, yuvu, yuvv;
+ 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;
+
+ 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);
+
+ for (fil = 0; fil < FILT_NUMB; fil ++)
+ if ((s->filters & 1<<fil) && filters_def[fil].init)
+ filters_def[fil].init(s, in, link->w, link->h);
+
+ // Calculate luma histogram and difference with previous frame or field.
+ for (j = 0; j < link->h; j++) {
+ for (i = 0; i < link->w; i++) {
+ yuv = in->data[0][w + i];
+ histy[yuv]++;
+ dify += abs(in->data[0][w + i] - 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++) {
+ int sat, hue;
+
+ yuvu = in->data[1][cw+i];
+ yuvv = in->data[2][cw+i];
+ histu[yuvu]++;
+ difu += abs(in->data[1][cw+i] - prev->data[1][cpw+i]);
+ histv[yuvv]++;
+ difv += abs(in->data[2][cw+i] - prev->data[2][cpw+i]);
+
+ // int or round?
+ sat = hypot(yuvu - 128, yuvv - 128);
+ histsat[sat]++;
+ hue = floor((180 / M_PI) * atan2f(yuvu-128, yuvv-128) + 180);
+ histhue[hue]++;
+ }
+ cw += in->linesize[1];
+ cpw += prev->linesize[1];
+ }
+
+ for (j = 0; j < link->h; j++) {
+ for (fil = 0; fil < FILT_NUMB; fil ++) {
+ if (s->filters & 1<<fil) {
+ AVFrame *dbg = out != in && s->outfilter == fil ? out : NULL;
+ filtot[fil] += filters_def[fil].process(s, in, dbg, j, link->w, link->h);
+ }
+ }
+ }
+
+ // 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,
+};
diff --git a/libavfilter/vf_smartblur.c b/libavfilter/vf_smartblur.c
new file mode 100644
index 0000000..b09ec90
--- /dev/null
+++ b/libavfilter/vf_smartblur.c
@@ -0,0 +1,304 @@
+/*
+ * 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ return 0;
+}
+
+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 0000000..989e283
--- /dev/null
+++ b/libavfilter/vf_spp.c
@@ -0,0 +1,469 @@
+/*
+ * 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 inline void add_block(int16_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];
+ }
+}
+
+// XXX: export the function?
+static inline int 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;
+}
+
+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 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);
+
+ for (y = 0; y < height; y++) {
+ int index = 8 + 8*linesize + y*linesize;
+ memcpy(p->src + index, src + y*src_linesize, 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)*linesize, p->src + ( y+8)*linesize, linesize);
+ memcpy(p->src + (height+8+y)*linesize, p->src + (height-y+7)*linesize, linesize);
+ }
+
+ 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, 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 + index, 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)
+ 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);
+ }
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum PixelFormat 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_NONE
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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);
+
+ 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));
+ if (!spp->use_bframe_qp) {
+ /* we are assuming here the qp blocks will not be smaller that 16x16 */
+ spp->non_b_qp_alloc_size = FF_CEIL_RSHIFT(inlink->w, 4) * FF_CEIL_RSHIFT(inlink->h, 4);
+ spp->non_b_qp_table = av_calloc(spp->non_b_qp_alloc_size, sizeof(*spp->non_b_qp_table));
+ if (!spp->non_b_qp_table)
+ return AVERROR(ENOMEM);
+ }
+ 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;
+
+ /* 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 = FF_CEIL_RSHIFT(qp_stride, 4);
+ h = FF_CEIL_RSHIFT(inlink->h, 4);
+ }
+ 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);
+ filter(spp, out->data[1], in->data[1], out->linesize[1], in->linesize[1], cw, ch, qp_table, qp_stride, 0);
+ filter(spp, 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 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);
+ }
+
+ avcodec_dct_init(spp->dct);
+ 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;
+ }
+ if (ARCH_X86)
+ ff_spp_init_x86(spp);
+ 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 0000000..7e7e227
--- /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;
+ int16_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 0000000..2140120
--- /dev/null
+++ b/libavfilter/vf_stereo3d.c
@@ -0,0 +1,664 @@
+/*
+ * 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 {
+ enum StereoCode format;
+ 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;
+
+ 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;
+ }
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ return 0;
+}
+
+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 0000000..be4c6a5
--- /dev/null
+++ b/libavfilter/vf_subtitles.c
@@ -0,0 +1,445 @@
+/*
+ * 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;
+ 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)
+{
+ ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
+ return 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},
+ {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;
+
+ /* 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 0000000..686dac1
--- /dev/null
+++ b/libavfilter/vf_super2xsai.c
@@ -0,0 +1,352 @@
+/*
+ * 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 0000000..175e39c
--- /dev/null
+++ b/libavfilter/vf_swapuv.c
@@ -0,0 +1,110 @@
+/*
+ * 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);
+ }
+
+ ff_set_common_formats(ctx, formats);
+ return 0;
+}
+
+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 0000000..aea63ab
--- /dev/null
+++ b/libavfilter/vf_telecine.c
@@ -0,0 +1,285 @@
+/*
+ * 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;
+
+ AVRational pts;
+ double 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 *tc = ctx->priv;
+ const char *p;
+ int max = 0;
+
+ if (!strlen(tc->pattern)) {
+ av_log(ctx, AV_LOG_ERROR, "No pattern provided.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (p = tc->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);
+ tc->pts.num += 2;
+ tc->pts.den += *p - '0';
+ }
+
+ tc->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",
+ tc->pattern, tc->out_cnt, tc->pts.num, tc->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);
+ }
+
+ ff_set_common_formats(ctx, pix_fmts);
+ return 0;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ TelecineContext *tc = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int i, ret;
+
+ tc->temp = ff_get_video_buffer(inlink, inlink->w, inlink->h);
+ if (!tc->temp)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < tc->out_cnt; i++) {
+ tc->frame[i] = ff_get_video_buffer(inlink, inlink->w, inlink->h);
+ if (!tc->frame[i])
+ return AVERROR(ENOMEM);
+ }
+
+ if ((ret = av_image_fill_linesizes(tc->stride, inlink->format, inlink->w)) < 0)
+ return ret;
+
+ tc->planeheight[1] = tc->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
+ tc->planeheight[0] = tc->planeheight[3] = inlink->h;
+
+ tc->nb_planes = av_pix_fmt_count_planes(inlink->format);
+
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ TelecineContext *tc = 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(tc->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, tc->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);
+
+ tc->ts_unit = av_q2d(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 *tc = ctx->priv;
+ int i, len, ret = 0, nout = 0;
+
+ len = tc->pattern[tc->pattern_pos] - '0';
+
+ tc->pattern_pos++;
+ if (!tc->pattern[tc->pattern_pos])
+ tc->pattern_pos = 0;
+
+ if (!len) { // do not output any field from this frame
+ av_frame_free(&inpicref);
+ return 0;
+ }
+
+ if (tc->occupied) {
+ for (i = 0; i < tc->nb_planes; i++) {
+ // fill in the EARLIER field from the buffered pic
+ av_image_copy_plane(tc->frame[nout]->data[i] + tc->frame[nout]->linesize[i] * tc->first_field,
+ tc->frame[nout]->linesize[i] * 2,
+ tc->temp->data[i] + tc->temp->linesize[i] * tc->first_field,
+ tc->temp->linesize[i] * 2,
+ tc->stride[i],
+ (tc->planeheight[i] - tc->first_field + 1) / 2);
+ // fill in the LATER field from the new pic
+ av_image_copy_plane(tc->frame[nout]->data[i] + tc->frame[nout]->linesize[i] * !tc->first_field,
+ tc->frame[nout]->linesize[i] * 2,
+ inpicref->data[i] + inpicref->linesize[i] * !tc->first_field,
+ inpicref->linesize[i] * 2,
+ tc->stride[i],
+ (tc->planeheight[i] - !tc->first_field + 1) / 2);
+ }
+ nout++;
+ len--;
+ tc->occupied = 0;
+ }
+
+ while (len >= 2) {
+ // output THIS image as-is
+ for (i = 0; i < tc->nb_planes; i++)
+ av_image_copy_plane(tc->frame[nout]->data[i], tc->frame[nout]->linesize[i],
+ inpicref->data[i], inpicref->linesize[i],
+ tc->stride[i],
+ tc->planeheight[i]);
+ nout++;
+ len -= 2;
+ }
+
+ if (len >= 1) {
+ // copy THIS image to the buffer, we need it later
+ for (i = 0; i < tc->nb_planes; i++)
+ av_image_copy_plane(tc->temp->data[i], tc->temp->linesize[i],
+ inpicref->data[i], inpicref->linesize[i],
+ tc->stride[i],
+ tc->planeheight[i]);
+ tc->occupied = 1;
+ }
+
+ for (i = 0; i < nout; i++) {
+ AVFrame *frame = av_frame_clone(tc->frame[i]);
+
+ if (!frame) {
+ av_frame_free(&inpicref);
+ return AVERROR(ENOMEM);
+ }
+
+ frame->pts = outlink->frame_count * tc->ts_unit;
+ ret = ff_filter_frame(outlink, frame);
+ }
+ av_frame_free(&inpicref);
+
+ return ret;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ TelecineContext *tc = ctx->priv;
+ int i;
+
+ av_frame_free(&tc->temp);
+ for (i = 0; i < tc->out_cnt; i++)
+ av_frame_free(&tc->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 0000000..1883154
--- /dev/null
+++ b/libavfilter/vf_thumbnail.c
@@ -0,0 +1,239 @@
+/*
+ * 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
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 0000000..459ae46
--- /dev/null
+++ b/libavfilter/vf_tile.c
@@ -0,0 +1,245 @@
+/*
+ * 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)
+{
+ ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
+ return 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 0000000..7397beb
--- /dev/null
+++ b/libavfilter/vf_tinterlace.c
@@ -0,0 +1,400 @@
+/*
+ * 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"
+
+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;
+ enum TInterlaceMode mode; ///< interlace mode selected
+ 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];
+} TInterlaceContext;
+
+#define OFFSET(x) offsetof(TInterlaceContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+#define TINTERLACE_FLAG_VLPF 01
+
+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" },
+
+ {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 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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;
+
+ 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;
+ }
+ if (tinterlace->mode == MODE_INTERLACEX2) {
+ outlink->time_base.num = inlink->time_base.num;
+ outlink->time_base.den = inlink->time_base.den * 2;
+ outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2,1});
+ } else if (tinterlace->mode != MODE_PAD) {
+ outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2});
+ }
+
+ 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(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 plane, vsub = desc->log2_chroma_h;
+ int k = src_field == FIELD_UPPER_AND_LOWER ? 1 : 2;
+ int h, i;
+
+ for (plane = 0; plane < desc->nb_components; plane++) {
+ int lines = plane == 1 || plane == 2 ? FF_CEIL_RSHIFT(src_h, vsub) : src_h;
+ int linesize = av_image_get_linesize(format, w, plane);
+ uint8_t *dstp = dst[plane];
+ const uint8_t *srcp = src[plane];
+
+ if (linesize < 0)
+ return;
+
+ 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
+ for (i = 0; i < linesize; 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;
+ }
+ dstp += dstp_linesize;
+ srcp += srcp_linesize;
+ }
+ } else {
+ av_image_copy_plane(dstp, dst_linesize[plane] * (interleave ? 2 : 1),
+ srcp, src_linesize[plane]*k, linesize, 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(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(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(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(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(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(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;
+
+ 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;
+
+ 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(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(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);
+ }
+
+ 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 07602b9..d9b165c 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,36 +56,26 @@ typedef struct TransContext {
int hsub, vsub;
int pixsteps[4];
+ PassthroughType passthrough; ///< landscape passthrough mode enabled
enum TransposeDir dir;
} 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));
+ 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);
+ }
+
+
+ ff_set_common_formats(ctx, pix_fmts);
return 0;
}
@@ -91,6 +87,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 +126,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 +172,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 +303,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 d0d59e2..37053d9 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,17 +134,30 @@ 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
@@ -159,35 +168,49 @@ static int query_formats(AVFilterContext *ctx)
return 0;
}
-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;
@@ -199,6 +222,10 @@ 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 +235,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 +243,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 +300,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_vflip.c b/libavfilter/vf_vflip.c
index fa54985..4a4ae0e 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 0000000..1df6f74
--- /dev/null
+++ b/libavfilter/vf_vidstabdetect.c
@@ -0,0 +1,219 @@
+/*
+ * 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 0000000..9db6a46
--- /dev/null
+++ b/libavfilter/vf_vidstabtransform.c
@@ -0,0 +1,320 @@
+/*
+ * 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+
+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 0000000..806bd72
--- /dev/null
+++ b/libavfilter/vf_vignette.c
@@ -0,0 +1,346 @@
+/*
+ * 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
+};
+
+typedef struct {
+ const AVClass *class;
+ const AVPixFmtDescriptor *desc;
+ int backward;
+ enum EvalMode { EVAL_MODE_INIT, EVAL_MODE_FRAME, EVAL_MODE_NB } eval_mode;
+#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
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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] = 0;
+ s->var_values[VAR_T] = NAN;
+ s->var_values[VAR_PTS] = NAN;
+ }
+
+ s->angle = av_clipf(av_expr_eval(s->angle_pexpr, s->var_values, NULL), 0, M_PI_2);
+ 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 (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 0000000..3de7394
--- /dev/null
+++ b/libavfilter/vf_w3fdif.c
@@ -0,0 +1,394 @@
+/*
+ * 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ return 0;
+}
+
+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 0000000..90a4c6b
--- /dev/null
+++ b/libavfilter/vf_xbr.c
@@ -0,0 +1,759 @@
+/*
+ * 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 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
+ * 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
+ *
+ * @todo add threading and FATE test
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
+#include "libavutil/pixdesc.h"
+#include "internal.h"
+
+#define RGB_MASK 0x00FFFFFF
+#define LB_MASK 0x00FEFEFE
+#define RED_BLUE_MASK 0x00FF00FF
+#define GREEN_MASK 0x0000FF00
+
+typedef struct {
+ const AVClass *class;
+ int n;
+ uint32_t rgbtoyuv[1<<24];
+} XBRContext;
+
+#define OFFSET(x) offsetof(XBRContext, x)
+static const AVOption xbr_options[] = {
+ { "n", "set scale factor", OFFSET(n), AV_OPT_TYPE_INT, {.i64 = 3}, 2, 4, },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(xbr);
+
+static uint32_t df(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(dst, src) dst = ((src & LB_MASK) >> 1) + ((dst & LB_MASK) >> 1)
+
+#define ALPHA_BLEND_32_W(dst, src) \
+ dst = ((RED_BLUE_MASK & ((dst & RED_BLUE_MASK) + ((((src & RED_BLUE_MASK) - \
+ (dst & RED_BLUE_MASK))) >>3))) | (GREEN_MASK & ((dst & GREEN_MASK) + \
+ ((((src & GREEN_MASK) - (dst & GREEN_MASK))) >>3))))
+
+#define ALPHA_BLEND_64_W(dst, src) \
+ dst = ((RED_BLUE_MASK & ((dst & RED_BLUE_MASK) + ((((src & RED_BLUE_MASK) - \
+ (dst & RED_BLUE_MASK))) >>2))) | (GREEN_MASK & ((dst & GREEN_MASK) + \
+ ((((src & GREEN_MASK) - (dst & GREEN_MASK))) >>2))))
+
+#define ALPHA_BLEND_192_W(dst, src) \
+ dst = ((RED_BLUE_MASK & ((dst & RED_BLUE_MASK) + ((((src & RED_BLUE_MASK) - \
+ (dst & RED_BLUE_MASK)) * 3) >>2))) | (GREEN_MASK & ((dst & GREEN_MASK) + \
+ ((((src & GREEN_MASK) - (dst & GREEN_MASK)) * 3) >>2))))
+
+#define ALPHA_BLEND_224_W(dst, src) \
+ dst = ((RED_BLUE_MASK & ((dst & RED_BLUE_MASK) + ((((src & RED_BLUE_MASK) - \
+ (dst & RED_BLUE_MASK)) * 7) >>3))) | (GREEN_MASK & ((dst & GREEN_MASK) + \
+ ((((src & GREEN_MASK) - (dst & GREEN_MASK)) * 7) >>3))))
+
+#define LEFT_UP_2_2X(N3, N2, N1, PIXEL)\
+ ALPHA_BLEND_224_W(E[N3], PIXEL); \
+ ALPHA_BLEND_64_W( E[N2], PIXEL); \
+ E[N1] = E[N2]; \
+
+#define LEFT_2_2X(N3, N2, PIXEL)\
+ ALPHA_BLEND_192_W(E[N3], PIXEL); \
+ ALPHA_BLEND_64_W( E[N2], PIXEL); \
+
+#define UP_2_2X(N3, N1, PIXEL)\
+ ALPHA_BLEND_192_W(E[N3], PIXEL); \
+ ALPHA_BLEND_64_W( E[N1], PIXEL); \
+
+#define DIA_2X(N3, PIXEL)\
+ ALPHA_BLEND_128_W(E[N3], PIXEL); \
+
+#define eq(A, B, r2y)\
+ (df(A, B, r2y) < 155)\
+
+#define FILTRO(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,r2y) \
+ ex = (PE!=PH && PE!=PF); \
+ if ( ex )\
+ {\
+ e = (df(PE,PC,r2y)+df(PE,PG,r2y)+df(PI,H5,r2y)+df(PI,F4,r2y))+(df(PH,PF,r2y)<<2); \
+ i = (df(PH,PD,r2y)+df(PH,I5,r2y)+df(PF,I4,r2y)+df(PF,PB,r2y))+(df(PE,PI,r2y)<<2); \
+ if ((e<i) && ( !eq(PF,PB,r2y) && !eq(PH,PD,r2y) || eq(PE,PI,r2y) && (!eq(PF,I4,r2y) && !eq(PH,I5,r2y)) || eq(PE,PG,r2y) || eq(PE,PC,r2y)) )\
+ {\
+ ke=df(PF,PG,r2y); ki=df(PH,PC,r2y); \
+ ex2 = (PE!=PC && PB!=PC); ex3 = (PE!=PG && PD!=PG); px = (df(PE,PF,r2y) <= df(PE,PH,r2y)) ? PF : PH; \
+ if ( ((ke<<1)<=ki) && ex3 && (ke>=(ki<<1)) && ex2 ) \
+ {\
+ LEFT_UP_2_2X(N3, N2, N1, px)\
+ }\
+ else if ( ((ke<<1)<=ki) && ex3 ) \
+ {\
+ LEFT_2_2X(N3, N2, px);\
+ }\
+ else if ( (ke>=(ki<<1)) && ex2 ) \
+ {\
+ UP_2_2X(N3, N1, px);\
+ }\
+ else \
+ {\
+ DIA_2X(N3, px);\
+ }\
+ }\
+ else if (e<=i)\
+ {\
+ ALPHA_BLEND_128_W( E[N3], ((df(PE,PF,r2y) <= df(PE,PH,r2y)) ? PF : PH)); \
+ }\
+ }\
+
+static void xbr2x(AVFrame * input, AVFrame * output, const uint32_t * r2y)
+{
+ unsigned int e, i,px;
+ unsigned int ex, ex2, ex3;
+ unsigned int ke, ki;
+ int x,y;
+
+ int next_line = output->linesize[0]>>2;
+
+ for (y = 0; y < input->height; y++) {
+
+ uint32_t pprev;
+ uint32_t pprev2;
+
+ uint32_t * E = (uint32_t *)(output->data[0] + y * output->linesize[0] * 2);
+
+ /* middle. Offset of -8 is given */
+ uint32_t * sa2 = (uint32_t *)(input->data[0] + y * input->linesize[0] - 8);
+ /* up one */
+ uint32_t * sa1 = sa2 - (input->linesize[0]>>2);
+ /* up two */
+ uint32_t * sa0 = sa1 - (input->linesize[0]>>2);
+ /* down one */
+ uint32_t * sa3 = sa2 + (input->linesize[0]>>2);
+ /* down two */
+ uint32_t * sa4 = sa3 + (input->linesize[0]>>2);
+
+ 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;
+ }
+ }
+
+ pprev = pprev2 = 2;
+
+ for (x = 0; x < input->width; x++) {
+ uint32_t B1 = sa0[2];
+ uint32_t PB = sa1[2];
+ uint32_t PE = sa2[2];
+ uint32_t PH = sa3[2];
+ uint32_t H5 = sa4[2];
+
+ uint32_t A1 = sa0[pprev];
+ uint32_t PA = sa1[pprev];
+ uint32_t PD = sa2[pprev];
+ uint32_t PG = sa3[pprev];
+ uint32_t G5 = sa4[pprev];
+
+ uint32_t A0 = sa1[pprev2];
+ uint32_t D0 = sa2[pprev2];
+ uint32_t G0 = sa3[pprev2];
+
+ uint32_t C1 = 0;
+ uint32_t PC = 0;
+ uint32_t PF = 0;
+ uint32_t PI = 0;
+ uint32_t I5 = 0;
+
+ uint32_t C4 = 0;
+ uint32_t F4 = 0;
+ uint32_t I4 = 0;
+
+ if (x >= input->width - 2) {
+ if (x == input->width - 1) {
+ C1 = sa0[2];
+ PC = sa1[2];
+ PF = sa2[2];
+ PI = sa3[2];
+ I5 = sa4[2];
+
+ C4 = sa1[2];
+ F4 = sa2[2];
+ I4 = sa3[2];
+ } else {
+ C1 = sa0[3];
+ PC = sa1[3];
+ PF = sa2[3];
+ PI = sa3[3];
+ I5 = sa4[3];
+
+ C4 = sa1[3];
+ F4 = sa2[3];
+ I4 = sa3[3];
+ }
+ } else {
+ C1 = sa0[3];
+ PC = sa1[3];
+ PF = sa2[3];
+ PI = sa3[3];
+ I5 = sa4[3];
+
+ C4 = sa1[4];
+ F4 = sa2[4];
+ I4 = sa3[4];
+ }
+
+ E[0] = E[1] = E[next_line] = E[next_line + 1] = PE; // 0, 1, 2, 3
+
+ FILTRO(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, 0, 1, next_line, next_line+1,r2y);
+ FILTRO(PE, PC, PF, PB, PI, PA, PH, PD, PG, I4, A1, I5, H5, A0, D0, B1, C1, F4, C4, G5, G0, next_line, 0, next_line+1, 1,r2y);
+ FILTRO(PE, PA, PB, PD, PC, PG, PF, PH, PI, C1, G0, C4, F4, G5, H5, D0, A0, B1, A1, I4, I5, next_line+1, next_line, 1, 0,r2y);
+ FILTRO(PE, PG, PD, PH, PA, PI, PB, PF, PC, A0, I5, A1, B1, I4, F4, H5, G5, D0, G0, C1, C4, 1, next_line+1, 0, next_line,r2y);
+
+ sa0 += 1;
+ sa1 += 1;
+ sa2 += 1;
+ sa3 += 1;
+ sa4 += 1;
+
+ E += 2;
+
+ if (pprev2){
+ pprev2--;
+ pprev = 1;
+ }
+ }
+ }
+}
+#undef FILTRO
+
+#define LEFT_UP_2_3X(N7, N5, N6, N2, N8, PIXEL)\
+ ALPHA_BLEND_192_W(E[N7], PIXEL); \
+ ALPHA_BLEND_64_W( E[N6], PIXEL); \
+ E[N5] = E[N7]; \
+ E[N2] = E[N6]; \
+ E[N8] = PIXEL;\
+
+#define LEFT_2_3X(N7, N5, N6, N8, PIXEL)\
+ ALPHA_BLEND_192_W(E[N7], PIXEL); \
+ ALPHA_BLEND_64_W( E[N5], PIXEL); \
+ ALPHA_BLEND_64_W( E[N6], PIXEL); \
+ E[N8] = PIXEL;\
+
+#define UP_2_3X(N5, N7, N2, N8, PIXEL)\
+ ALPHA_BLEND_192_W(E[N5], PIXEL); \
+ ALPHA_BLEND_64_W( E[N7], PIXEL); \
+ ALPHA_BLEND_64_W( E[N2], PIXEL); \
+ E[N8] = PIXEL;\
+
+#define DIA_3X(N8, N5, N7, PIXEL)\
+ ALPHA_BLEND_224_W(E[N8], PIXEL); \
+ ALPHA_BLEND_32_W(E[N5], PIXEL); \
+ ALPHA_BLEND_32_W(E[N7], PIXEL); \
+
+#define FILTRO(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,r2y) \
+ ex = (PE!=PH && PE!=PF); \
+ if ( ex )\
+ {\
+ e = (df(PE,PC,r2y)+df(PE,PG,r2y)+df(PI,H5,r2y)+df(PI,F4,r2y))+(df(PH,PF,r2y)<<2); \
+ i = (df(PH,PD,r2y)+df(PH,I5,r2y)+df(PF,I4,r2y)+df(PF,PB,r2y))+(df(PE,PI,r2y)<<2); \
+ if ((e<i) && ( !eq(PF,PB,r2y) && !eq(PF,PC,r2y) || !eq(PH,PD,r2y) && !eq(PH,PG,r2y) || eq(PE,PI,r2y) && (!eq(PF,F4,r2y) && !eq(PF,I4,r2y) || !eq(PH,H5,r2y) && !eq(PH,I5,r2y)) || eq(PE,PG,r2y) || eq(PE,PC,r2y)) )\
+ {\
+ ke=df(PF,PG,r2y); ki=df(PH,PC,r2y); \
+ ex2 = (PE!=PC && PB!=PC); ex3 = (PE!=PG && PD!=PG); px = (df(PE,PF,r2y) <= df(PE,PH,r2y)) ? PF : PH; \
+ if ( ((ke<<1)<=ki) && ex3 && (ke>=(ki<<1)) && ex2 ) \
+ {\
+ LEFT_UP_2_3X(N7, N5, N6, N2, N8, px)\
+ }\
+ else if ( ((ke<<1)<=ki) && ex3 ) \
+ {\
+ LEFT_2_3X(N7, N5, N6, N8, px);\
+ }\
+ else if ( (ke>=(ki<<1)) && ex2 ) \
+ {\
+ UP_2_3X(N5, N7, N2, N8, px);\
+ }\
+ else \
+ {\
+ DIA_3X(N8, N5, N7, px);\
+ }\
+ }\
+ else if (e<=i)\
+ {\
+ ALPHA_BLEND_128_W( E[N8], ((df(PE,PF,r2y) <= df(PE,PH,r2y)) ? PF : PH)); \
+ }\
+ }\
+
+static void xbr3x(AVFrame *input, AVFrame *output, const uint32_t *r2y)
+{
+ const int nl = output->linesize[0]>>2;
+ const int nl1 = nl + nl;
+
+ unsigned int e, i,px;
+ unsigned int ex, ex2, ex3;
+ unsigned int ke, ki;
+
+ uint32_t pprev;
+ uint32_t pprev2;
+
+ int x,y;
+
+ for (y = 0; y < input->height; y++) {
+
+ uint32_t * E = (uint32_t *)(output->data[0] + y * output->linesize[0] * 3);
+
+ /* middle. Offset of -8 is given */
+ uint32_t * sa2 = (uint32_t *)(input->data[0] + y * input->linesize[0] - 8);
+ /* up one */
+ uint32_t * sa1 = sa2 - (input->linesize[0]>>2);
+ /* up two */
+ uint32_t * sa0 = sa1 - (input->linesize[0]>>2);
+ /* down one */
+ uint32_t * sa3 = sa2 + (input->linesize[0]>>2);
+ /* down two */
+ uint32_t * sa4 = sa3 + (input->linesize[0]>>2);
+
+ 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;
+ }
+ }
+
+ pprev = pprev2 = 2;
+
+ for (x = 0; x < input->width; x++){
+ uint32_t B1 = sa0[2];
+ uint32_t PB = sa1[2];
+ uint32_t PE = sa2[2];
+ uint32_t PH = sa3[2];
+ uint32_t H5 = sa4[2];
+
+ uint32_t A1 = sa0[pprev];
+ uint32_t PA = sa1[pprev];
+ uint32_t PD = sa2[pprev];
+ uint32_t PG = sa3[pprev];
+ uint32_t G5 = sa4[pprev];
+
+ uint32_t A0 = sa1[pprev2];
+ uint32_t D0 = sa2[pprev2];
+ uint32_t G0 = sa3[pprev2];
+
+ uint32_t C1 = 0;
+ uint32_t PC = 0;
+ uint32_t PF = 0;
+ uint32_t PI = 0;
+ uint32_t I5 = 0;
+
+ uint32_t C4 = 0;
+ uint32_t F4 = 0;
+ uint32_t I4 = 0;
+
+ if (x >= input->width - 2){
+ if (x == input->width - 1){
+ C1 = sa0[2];
+ PC = sa1[2];
+ PF = sa2[2];
+ PI = sa3[2];
+ I5 = sa4[2];
+
+ C4 = sa1[2];
+ F4 = sa2[2];
+ I4 = sa3[2];
+ } else {
+ C1 = sa0[3];
+ PC = sa1[3];
+ PF = sa2[3];
+ PI = sa3[3];
+ I5 = sa4[3];
+
+ C4 = sa1[3];
+ F4 = sa2[3];
+ I4 = sa3[3];
+ }
+ } else {
+ C1 = sa0[3];
+ PC = sa1[3];
+ PF = sa2[3];
+ PI = sa3[3];
+ I5 = sa4[3];
+
+ C4 = sa1[4];
+ F4 = sa2[4];
+ I4 = sa3[4];
+ }
+
+ E[0] = E[1] = E[2] = PE;
+ E[nl] = E[nl+1] = E[nl+2] = PE; // 3, 4, 5
+ E[nl1] = E[nl1+1] = E[nl1+2] = PE; // 6, 7, 8
+
+ FILTRO(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,r2y);
+ FILTRO(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,r2y);
+ FILTRO(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,r2y);
+ FILTRO(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,r2y);
+
+ sa0 += 1;
+ sa1 += 1;
+ sa2 += 1;
+ sa3 += 1;
+ sa4 += 1;
+
+ E += 3;
+
+ if (pprev2){
+ pprev2--;
+ pprev = 1;
+ }
+ }
+ }
+}
+#undef FILTRO
+
+#define LEFT_UP_2(N15, N14, N11, N13, N12, N10, N7, N3, PIXEL)\
+ ALPHA_BLEND_192_W(E[N13], PIXEL); \
+ ALPHA_BLEND_64_W( E[N12], PIXEL); \
+ E[N15] = E[N14] = E[N11] = PIXEL; \
+ E[N10] = E[N3] = E[N12]; \
+ E[N7] = E[N13]; \
+
+#define LEFT_2(N15, N14, N11, N13, N12, N10, PIXEL)\
+ ALPHA_BLEND_192_W(E[N11], PIXEL); \
+ ALPHA_BLEND_192_W(E[N13], PIXEL); \
+ ALPHA_BLEND_64_W( E[N10], PIXEL); \
+ ALPHA_BLEND_64_W( E[N12], PIXEL); \
+ E[N14] = PIXEL; \
+ E[N15] = PIXEL; \
+
+#define UP_2(N15, N14, N11, N3, N7, N10, PIXEL)\
+ ALPHA_BLEND_192_W(E[N14], PIXEL); \
+ ALPHA_BLEND_192_W(E[N7 ], PIXEL); \
+ ALPHA_BLEND_64_W( E[N10], PIXEL); \
+ ALPHA_BLEND_64_W( E[N3 ], PIXEL); \
+ E[N11] = PIXEL; \
+ E[N15] = PIXEL; \
+
+#define DIA(N15, N14, N11, PIXEL)\
+ ALPHA_BLEND_128_W(E[N11], PIXEL); \
+ ALPHA_BLEND_128_W(E[N14], PIXEL); \
+ E[N15] = PIXEL; \
+
+#define FILTRO(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,r2y) \
+ ex = (PE!=PH && PE!=PF); \
+ if ( ex )\
+ {\
+ e = (df(PE,PC,r2y)+df(PE,PG,r2y)+df(PI,H5,r2y)+df(PI,F4,r2y))+(df(PH,PF,r2y)<<2); \
+ i = (df(PH,PD,r2y)+df(PH,I5,r2y)+df(PF,I4,r2y)+df(PF,PB,r2y))+(df(PE,PI,r2y)<<2); \
+ if ((e<i) && ( !eq(PF,PB,r2y) && !eq(PH,PD,r2y) || eq(PE,PI,r2y) && (!eq(PF,I4,r2y) && !eq(PH,I5,r2y)) || eq(PE,PG,r2y) || eq(PE,PC,r2y)) )\
+ {\
+ ke=df(PF,PG,r2y); ki=df(PH,PC,r2y); \
+ ex2 = (PE!=PC && PB!=PC); ex3 = (PE!=PG && PD!=PG); px = (df(PE,PF,r2y) <= df(PE,PH,r2y)) ? PF : PH; \
+ if ( ((ke<<1)<=ki) && ex3 && (ke>=(ki<<1)) && ex2 ) \
+ {\
+ LEFT_UP_2(N15, N14, N11, N13, N12, N10, N7, N3, px)\
+ }\
+ else if ( ((ke<<1)<=ki) && ex3 ) \
+ {\
+ LEFT_2(N15, N14, N11, N13, N12, N10, px)\
+ }\
+ else if ( (ke>=(ki<<1)) && ex2 ) \
+ {\
+ UP_2(N15, N14, N11, N3, N7, N10, px)\
+ }\
+ else \
+ {\
+ DIA(N15, N14, N11, px)\
+ }\
+ }\
+ else if (e<=i)\
+ {\
+ ALPHA_BLEND_128_W( E[N15], ((df(PE,PF,r2y) <= df(PE,PH,r2y)) ? PF : PH)); \
+ }\
+ }\
+
+static void xbr4x(AVFrame *input, AVFrame *output, const uint32_t *r2y)
+{
+
+ const int nl = output->linesize[0]>>2;
+ const int nl1 = nl + nl;
+ const int nl2 = nl1 + nl;
+
+ unsigned int e, i, px;
+ unsigned int ex, ex2, ex3;
+ unsigned int ke, ki;
+
+ uint32_t pprev;
+ uint32_t pprev2;
+
+ int x, y;
+
+ for (y = 0; y < input->height; y++) {
+
+ uint32_t * E = (uint32_t *)(output->data[0] + y * output->linesize[0] * 4);
+
+ /* middle. Offset of -8 is given */
+ uint32_t * sa2 = (uint32_t *)(input->data[0] + y * input->linesize[0] - 8);
+ /* up one */
+ uint32_t * sa1 = sa2 - (input->linesize[0]>>2);
+ /* up two */
+ uint32_t * sa0 = sa1 - (input->linesize[0]>>2);
+ /* down one */
+ uint32_t * sa3 = sa2 + (input->linesize[0]>>2);
+ /* down two */
+ uint32_t * sa4 = sa3 + (input->linesize[0]>>2);
+
+ 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;
+ }
+ }
+
+ pprev = pprev2 = 2;
+
+ for (x = 0; x < input->width; x++) {
+ uint32_t B1 = sa0[2];
+ uint32_t PB = sa1[2];
+ uint32_t PE = sa2[2];
+ uint32_t PH = sa3[2];
+ uint32_t H5 = sa4[2];
+
+ uint32_t A1 = sa0[pprev];
+ uint32_t PA = sa1[pprev];
+ uint32_t PD = sa2[pprev];
+ uint32_t PG = sa3[pprev];
+ uint32_t G5 = sa4[pprev];
+
+ uint32_t A0 = sa1[pprev2];
+ uint32_t D0 = sa2[pprev2];
+ uint32_t G0 = sa3[pprev2];
+
+ uint32_t C1 = 0;
+ uint32_t PC = 0;
+ uint32_t PF = 0;
+ uint32_t PI = 0;
+ uint32_t I5 = 0;
+
+ uint32_t C4 = 0;
+ uint32_t F4 = 0;
+ uint32_t I4 = 0;
+
+ if (x >= input->width - 2) {
+ if (x == input->width - 1) {
+ C1 = sa0[2];
+ PC = sa1[2];
+ PF = sa2[2];
+ PI = sa3[2];
+ I5 = sa4[2];
+
+ C4 = sa1[2];
+ F4 = sa2[2];
+ I4 = sa3[2];
+ } else {
+ C1 = sa0[3];
+ PC = sa1[3];
+ PF = sa2[3];
+ PI = sa3[3];
+ I5 = sa4[3];
+
+ C4 = sa1[3];
+ F4 = sa2[3];
+ I4 = sa3[3];
+ }
+ } else {
+ C1 = sa0[3];
+ PC = sa1[3];
+ PF = sa2[3];
+ PI = sa3[3];
+ I5 = sa4[3];
+
+ C4 = sa1[4];
+ F4 = sa2[4];
+ I4 = sa3[4];
+ }
+
+ E[0] = E[1] = E[2] = E[3] = PE;
+ E[nl] = E[nl+1] = E[nl+2] = E[nl+3] = PE; // 4, 5, 6, 7
+ E[nl1] = E[nl1+1] = E[nl1+2] = E[nl1+3] = PE; // 8, 9, 10, 11
+ E[nl2] = E[nl2+1] = E[nl2+2] = E[nl2+3] = PE; // 12, 13, 14, 15
+
+ FILTRO(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,r2y);
+ FILTRO(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,r2y);
+ FILTRO(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,r2y);
+ FILTRO(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,r2y);
+
+ sa0 += 1;
+ sa1 += 1;
+ sa2 += 1;
+ sa3 += 1;
+ sa4 += 1;
+
+ E += 4;
+
+ if (pprev2){
+ pprev2--;
+ pprev = 1;
+ }
+ }
+ }
+}
+#undef FILTRO
+
+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,
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ XBRContext *xbr = ctx->priv;
+ const uint32_t *r2y = xbr->rgbtoyuv;
+
+ 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);
+ if (xbr->n == 4)
+ xbr4x(in, out, r2y);
+ else if (xbr->n == 3)
+ xbr3x(in, out, r2y);
+ else
+ xbr2x(in, out, r2y);
+
+ 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;
+ 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;
+ }
+ }
+ }
+
+ 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,
+};
diff --git a/libavfilter/vf_yadif.c b/libavfilter/vf_yadif.c
index 53c567c..70670c3 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,24 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame)
yadif->cur = yadif->next;
yadif->next = frame;
- if (!yadif->cur)
- return 0;
+ if (!yadif->cur &&
+ !(yadif->cur = av_frame_clone(yadif->next)))
+ return AVERROR(ENOMEM);
- if (yadif->auto_enable && !yadif->cur->interlaced_frame) {
+ 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->deint && !yadif->cur->interlaced_frame) || ctx->is_disabled) {
yadif->out = av_frame_clone(yadif->cur);
if (!yadif->out)
return AVERROR(ENOMEM);
@@ -333,9 +353,8 @@ 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);
+ if (!yadif->prev)
+ return 0;
yadif->out = ff_get_video_buffer(ctx->outputs[0], link->w, link->h);
if (!yadif->out)
@@ -368,7 +387,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 +400,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,16 +426,29 @@ 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_GBRAP,
AV_PIX_FMT_NONE
};
@@ -455,6 +459,7 @@ static int query_formats(AVFilterContext *ctx)
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 +467,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 +482,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 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"),
-static const AVClass yadif_class = {
- .class_name = "yadif",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
+ { "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 +530,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 +538,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 0000000..8f179e6
--- /dev/null
+++ b/libavfilter/vf_zoompan.c
@@ -0,0 +1,309 @@
+/*
+ * 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;
+ 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;
+
+ 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(&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
+ };
+
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 9f1103e..6a55483 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 f7e8e34..56c58d6 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 0000000..13544cf
--- /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 0000000..c6d6ced
--- /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 14b6b12..281721b 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 0000000..5e2df2d
--- /dev/null
+++ b/libavfilter/vsrc_cellauto.c
@@ -0,0 +1,337 @@
+/*
+ * 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 };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 3b506ec..0000000
--- 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 0000000..029e1bb
--- /dev/null
+++ b/libavfilter/vsrc_life.c
@@ -0,0 +1,450 @@
+/*
+ * 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_free(life->buf[0]);
+ av_free(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_free(life->buf[0]);
+ av_free(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 };
+ 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;
+ }
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ 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 0000000..255f2db
--- /dev/null
+++ b/libavfilter/vsrc_mandelbrot.c
@@ -0,0 +1,430 @@
+/*
+ * 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;
+ enum Outer outer;
+ enum Inner 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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 0e5df32..0000000
--- 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_dlog(outlink->src,
- "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 0000000..d045704
--- /dev/null
+++ b/libavfilter/vsrc_mptestsrc.c
@@ -0,0 +1,361 @@
+/*
+ * 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;
+ enum test_type test;
+} 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((int)floor(sum+0.5), 0, 255);
+ }
+ }
+}
+
+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
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 63e90fd..0000000
--- 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 e41625e..8814440 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,320 @@ 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 void color_fill_picture(AVFilterContext *ctx, AVFrame *picref)
+{
+ TestSourceContext *test = ctx->priv;
+ ff_fill_rectangle(&test->draw, &test->color,
+ picref->data, picref->linesize,
+ 0, 0, test->w, test->h);
+}
+
+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)
+{
+ ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
+ return 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,
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 const char *testsrc_get_name(void *ctx)
+static av_cold int nullsrc_init(AVFilterContext *ctx)
{
- return "testsrc";
+ TestSourceContext *test = ctx->priv;
+
+ test->fill_picture_fn = nullsrc_fill_picture;
+ return init(ctx);
}
-static const AVClass testsrc_class = {
- .class_name = "TestSourceContext",
- .item_name = testsrc_get_name,
- .option = testsrc_options,
+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 +463,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 +478,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 +573,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 +601,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 +638,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)
@@ -361,28 +666,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 +686,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 +708,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 +739,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)
@@ -466,15 +762,7 @@ 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 +782,290 @@ 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,
+};
- .inputs = NULL,
+#endif /* CONFIG_RGBTESTSRC_FILTER */
+
+#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,
+ };
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+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 16b1307..32145db 100644
--- a/libavfilter/x86/Makefile
+++ b/libavfilter/x86/Makefile
@@ -1,9 +1,15 @@
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_NOISE_FILTER) += x86/vf_noise.o
+OBJS-$(CONFIG_PULLUP_FILTER) += x86/vf_pullup_init.o
+OBJS-$(CONFIG_SPP_FILTER) += x86/vf_spp.o
OBJS-$(CONFIG_VOLUME_FILTER) += x86/af_volume_init.o
OBJS-$(CONFIG_YADIF_FILTER) += x86/vf_yadif_init.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_PULLUP_FILTER) += x86/vf_pullup.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 4e5ad22..f4cbcbc 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 c59e0ed..57c7eab 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_gradfun.asm b/libavfilter/x86/vf_gradfun.asm
index 00fcb16..3581f89 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 3f23bf6..c638a05 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 02632a1..961127e 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 06f9e00..b63916b 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 0000000..007e63d
--- /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 0000000..1147ca8
--- /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_noise.c b/libavfilter/x86/vf_noise.c
new file mode 100644
index 0000000..0a86cb0
--- /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_pullup.asm b/libavfilter/x86/vf_pullup.asm
new file mode 100644
index 0000000..d3a1955
--- /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 0000000..5b36b68
--- /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 0000000..eb46ddc
--- /dev/null
+++ b/libavfilter/x86/vf_spp.c
@@ -0,0 +1,233 @@
+/*
+ * 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;
+ switch (s->mode) {
+ case 0: s->requantize = hardthresh_mmx; break;
+ case 1: s->requantize = softthresh_mmx; break;
+ }
+ }
+#endif
+}
diff --git a/libavfilter/x86/vf_yadif.asm b/libavfilter/x86/vf_yadif.asm
index 3d8b2bc..a29620c 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 510a023..1460a64 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 0000000..8853e0d
--- /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 0000000..79d127d
--- /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 75e35c4..07f2cc9 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;
+ enum YADIFMode mode;
+ enum YADIFParity parity;
+ enum YADIFDeint deint;
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 6253ffb..240e5a4 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
*/
@@ -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)
@@ -222,9 +230,14 @@ 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;
}
@@ -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 ff887f0..9833ebb 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 \
@@ -32,6 +33,7 @@ OBJS-$(CONFIG_RTPDEC) += rdt.o \
rtpdec_amr.o \
rtpdec_asf.o \
rtpdec_g726.o \
+ rtpdec_h261.o \
rtpdec_h263.o \
rtpdec_h263_rfc2190.o \
rtpdec_h264.o \
@@ -50,47 +52,68 @@ 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_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
-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_DAUD_DEMUXER) += dauddec.o
OBJS-$(CONFIG_DAUD_MUXER) += daudenc.o
OBJS-$(CONFIG_DFA_DEMUXER) += dfa.o
@@ -98,7 +121,9 @@ 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_DTSHD_DEMUXER) += dtshddec.o
OBJS-$(CONFIG_DTS_DEMUXER) += dtsdec.o rawdec.o
OBJS-$(CONFIG_DTS_MUXER) += rawenc.o
OBJS-$(CONFIG_DV_DEMUXER) += dv.o
@@ -108,6 +133,9 @@ 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
@@ -121,17 +149,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
@@ -144,7 +177,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
@@ -152,37 +188,64 @@ 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_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
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
@@ -200,6 +263,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
@@ -208,6 +273,7 @@ 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
@@ -223,13 +289,18 @@ OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \
oggparsespeex.o \
oggparsetheora.o \
oggparsevorbis.o \
+ oggparsevp8.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
@@ -271,17 +342,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
@@ -289,6 +365,7 @@ OBJS-$(CONFIG_RTP_MUXER) += rtp.o \
rtpenc_aac.o \
rtpenc_latm.o \
rtpenc_amr.o \
+ rtpenc_h261.o \
rtpenc_h263.o \
rtpenc_h263_rfc2190.o \
rtpenc_hevc.o \
@@ -303,9 +380,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
@@ -317,45 +397,72 @@ 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
+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_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
@@ -363,15 +470,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
@@ -391,6 +509,7 @@ 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
@@ -398,6 +517,9 @@ OBJS-$(CONFIG_UNIX_PROTOCOL) += unix.o
OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o
+# Windows resource file
+SLIBOBJS-$(HAVE_GNU_WINDRES) += avformatres.o
+
SKIPHEADERS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh.h
SKIPHEADERS-$(CONFIG_NETWORK) += network.h rtsp.h
@@ -411,3 +533,4 @@ TOOLS = aviocat \
ismindex \
pktdumper \
probetest \
+ seek_print \
diff --git a/libavformat/a64.c b/libavformat/a64.c
index c8e8e64..a7f93a2 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 566c3e7..1b98e1d 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 4ceffa5..58ef44d 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 0000000..3f223d5
--- /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);
+
+ /*
+ 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 0000000..8a3661a
--- /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 5194e75..89c8869 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 {
+ 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 fc83ff2..ddaa201 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
*/
@@ -76,14 +76,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 7675009..15b9b1c 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
*/
diff --git a/libavformat/afc.c b/libavformat/afc.c
new file mode 100644
index 0000000..8dbd232
--- /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 f88f957..4470254 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 6243bcb..91ef2a4 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 */
@@ -136,16 +141,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 +162,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 +191,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);
@@ -228,6 +235,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 +267,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,11 +278,31 @@ 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;
default: /* Jump */
if (size & 1) /* Always even aligned */
@@ -305,15 +344,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 d4bffb3..90fc433 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 {
+ 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 bef155f..e82ef2b 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,55 +62,76 @@ 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_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_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_MUXDEMUX(DTS, dts);
+ REGISTER_DEMUXER (DTSHD, dtshd);
REGISTER_MUXDEMUX(DV, dv);
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);
@@ -120,28 +141,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);
@@ -162,6 +195,8 @@ 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);
@@ -170,6 +205,7 @@ void av_register_all(void)
REGISTER_MUXER (MXF_D10, mxf_d10);
REGISTER_DEMUXER (MXG, mxg);
REGISTER_DEMUXER (NC, nc);
+ REGISTER_DEMUXER (NISTSPHERE, nistsphere);
REGISTER_DEMUXER (NSV, nsv);
REGISTER_MUXER (NULL, null);
REGISTER_MUXDEMUX(NUT, nut);
@@ -199,29 +235,39 @@ 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_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);
@@ -232,42 +278,76 @@ 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 (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_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);
@@ -287,15 +367,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 afd062e..8f44de1 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 f781492..5196cb8 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 0b6c583..21bb514 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 d967a5d..fafc1df 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 {
@@ -88,10 +86,14 @@ typedef struct {
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,11 +260,11 @@ 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;
}
@@ -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 bd8d0ed..c8d1bdc 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)
@@ -94,14 +92,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 +126,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 +168,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 +230,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 36e3211..cf2a5f8 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/aqtitledec.c b/libavformat/aqtitledec.c
new file mode 100644
index 0000000..9508766
--- /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 ec34b50..80d24db 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 2f6722a..0c9598a 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 c261475..a402758 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 53388b4..8b80d63 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 85e800d..7f7bb4d 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 {
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;
@@ -98,12 +98,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) */
@@ -129,7 +125,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);
@@ -273,7 +269,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);
@@ -283,16 +279,20 @@ static void get_tag(AVFormatContext *s, const char *key, int type, int len, int
{
char *value;
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;
- 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);
@@ -304,7 +304,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;
@@ -369,17 +369,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);
@@ -407,6 +403,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,7 +429,7 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
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)
@@ -469,9 +466,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);
}
@@ -504,6 +503,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));
@@ -540,8 +541,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);
@@ -550,10 +553,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;
@@ -717,12 +728,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);
@@ -739,7 +754,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)
@@ -770,19 +785,30 @@ 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;
+ 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");
+ av_get_packet(pb, &pkt, len); 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");
}
}
}
@@ -796,8 +822,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;
@@ -896,20 +922,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
}
@@ -925,12 +951,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);
@@ -950,7 +976,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)
@@ -968,13 +994,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);
@@ -982,26 +1011,63 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb)
av_dlog(asf, "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
@@ -1014,18 +1080,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;
@@ -1033,16 +1099,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;
@@ -1064,12 +1126,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);
@@ -1084,13 +1144,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);
@@ -1100,7 +1160,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);
@@ -1119,41 +1180,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;
@@ -1170,7 +1231,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)
@@ -1194,6 +1255,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) {
@@ -1311,7 +1377,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;
@@ -1325,21 +1390,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);
@@ -1350,6 +1428,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;
@@ -1365,11 +1444,13 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index,
s->packet_size * s->packet_size +
s->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;
}
@@ -1380,8 +1461,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;
@@ -1404,17 +1484,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;
+ int ret = 0;
+
+ 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);
@@ -1425,6 +1508,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;
@@ -1448,11 +1532,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;
}
@@ -1462,8 +1547,7 @@ 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;
@@ -1484,19 +1568,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;
}
}
@@ -1504,6 +1593,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 79b44a7..fbf6158 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"
@@ -32,7 +33,8 @@
#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 +197,33 @@ typedef struct {
/* 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 +244,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 +292,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 +310,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 +353,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 +379,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 +398,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 +409,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 */
@@ -460,7 +495,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 +513,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 +528,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 +556,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 +564,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 +638,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 +652,11 @@ 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);
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
@@ -641,6 +675,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;
}
@@ -667,7 +704,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++)
@@ -706,20 +743,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);
@@ -734,7 +770,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;
@@ -757,7 +793,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
@@ -765,7 +801,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;
@@ -823,20 +859,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;
@@ -846,53 +927,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);
@@ -908,6 +974,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)
@@ -915,8 +982,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) {
@@ -928,7 +998,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;
}
@@ -939,7 +1009,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,
@@ -958,7 +1028,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 08c1222..c62e76f 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_dlog(NULL, "%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 751485d..bde1096 100644
--- a/libavformat/assenc.c
+++ b/libavformat/assenc.c
@@ -2,76 +2,214 @@
* 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"
+
+#include "libavutil/opt.h"
+
+typedef struct DialogueLine {
+ int readorder;
+ char *line;
+ struct DialogueLine *prev, *next;
+} DialogueLine;
typedef struct ASSContext{
- unsigned int extra_index;
+ 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;
}ASSContext;
static int write_header(AVFormatContext *s)
{
ASSContext *ass = s->priv_data;
AVCodecContext *avctx= s->streams[0]->codec;
- uint8_t *last= NULL;
- 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) {
+ avio_write(s->pb, avctx->extradata, avctx->extradata_size);
+ if (avctx->extradata[avctx->extradata_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(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++;
+ 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_free(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);
+}
- avio_write(s->pb, p, end-p);
- ass->extra_index += end-p;
+static void insert_dialogue(ASSContext *ass, DialogueLine *dialogue)
+{
+ DialogueLine *cur, *next = NULL, *prev = NULL;
- if(last && !memcmp(last, "[Events]", 8))
- break;
- last=p;
+ /* 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;
+ }
}
- avio_flush(s->pb);
+ /* 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;
+ }
+ }
- return 0;
+ 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);
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 +220,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 0000000..9de74aa
--- /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 0000000..4a399ea
--- /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 0000000..92c208d
--- /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 0000000..cf7a12c
--- /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 e682cbf..53702bc 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 ba78d4e..b64010f 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 9c7b548..4d77832 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 e639ed5..c927b47 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
*/
diff --git a/libavformat/avc.h b/libavformat/avc.h
index 2442e5f..c5e80ff 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 ade5d2f..3733549 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).
@@ -261,6 +261,8 @@
struct AVFormatContext;
+struct AVDeviceInfoList;
+struct AVDeviceCapabilitiesQuery;
/**
* @defgroup metadata_api Public Metadata API
@@ -272,7 +274,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.
*
@@ -399,6 +401,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
@@ -422,14 +427,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
@@ -499,8 +514,43 @@ 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);
} AVOutputFormat;
/**
* @}
@@ -527,7 +577,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;
@@ -636,6 +686,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;
/**
* @}
@@ -647,11 +715,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).
@@ -683,6 +759,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
@@ -734,10 +824,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;
@@ -796,6 +888,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;
/**
@@ -822,11 +916,25 @@ typedef struct AVStream {
/**
* Stream information used internally by av_find_stream_info()
*/
-#define MAX_STD_TIMEBASES (60*12+5)
+#define MAX_STD_TIMEBASES (60*12+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.
*/
@@ -840,6 +948,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;
@@ -872,8 +987,129 @@ 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 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;
+
} 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);
+
+/**
+ * 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
/**
@@ -889,6 +1125,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
@@ -901,6 +1154,24 @@ 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);
+
+
+/**
+ * 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;
/**
@@ -1011,7 +1282,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;
@@ -1040,19 +1311,20 @@ 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.
/**
- * 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;
@@ -1125,7 +1397,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;
@@ -1201,7 +1478,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
*/
@@ -1210,6 +1487,120 @@ typedef struct AVFormatContext {
#define AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE 1 ///< Shift timestamps so they are non negative
#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;
+
+ /**
+ * ',' seperated list of allowed decoders.
+ * If NULL then all are allowed
+ * - encoding: unused
+ * - decoding: set by user through AVOptions (NO direct access)
+ */
+ char *codec_whitelist;
+
+ /**
+ * ',' seperated list of allowed demuxers.
+ * If NULL then all are allowed
+ * - encoding: unused
+ * - decoding: set by user through AVOptions (NO direct access)
+ */
+ char *format_whitelist;
+
/*****************************************************************
* 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
@@ -1251,6 +1642,7 @@ typedef struct AVFormatContext {
/**
* Offset to remap timestamps to be non-negative.
* Expressed in timebase units.
+ * @see AVStream.mux_ts_offset
*/
int64_t offset;
@@ -1264,8 +1656,119 @@ typedef struct AVFormatContext {
* 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;
+
+ /**
+ * 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;
} 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);
+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);
+
+/**
+ * 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;
@@ -1303,7 +1806,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);
@@ -1369,6 +1871,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
@@ -1397,6 +1902,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
* @{
*/
@@ -1430,6 +1954,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
@@ -1441,9 +1974,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);
@@ -1469,6 +2010,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
@@ -1493,6 +2037,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.
@@ -1579,6 +2135,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
@@ -1710,6 +2267,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.
*
@@ -1744,6 +2339,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);
+
+
+/**
* @}
*/
@@ -1790,7 +2404,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);
/**
@@ -1804,8 +2418,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.
@@ -1827,6 +2441,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);
/**
@@ -1885,9 +2511,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,
@@ -1979,10 +2605,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 0000000..ffe61e0
--- /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 e05db9c..34da76f 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 c24a6c4..0cdcc08 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"
@@ -32,9 +34,8 @@
#include "dv.h"
#include "internal.h"
#include "riff.h"
-
-#undef NDEBUG
-#include <assert.h>
+#include "libavcodec/bytestream.h"
+#include "libavcodec/exif.h"
typedef struct AVIStream {
int64_t frame_offset; /* current frame (video) or byte (audio) counter
@@ -58,12 +59,16 @@ typedef struct AVIStream {
AVFormatContext *sub_ctx;
AVPacket sub_pkt;
uint8_t *sub_buffer;
+
+ int64_t seek_pos;
} AVIStream;
typedef struct {
+ 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;
@@ -72,9 +77,26 @@ typedef struct {
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' },
@@ -93,8 +115,8 @@ static int avi_load_index(AVFormatContext *s);
static int guess_ni_flag(AVFormatContext *s);
#define print_tag(str, tag, size) \
- av_dlog(NULL, "%s: tag=%c%c%c%c size=0x%x\n", \
- str, tag & 0xff, \
+ av_dlog(NULL, "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, \
@@ -151,7 +173,7 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num)
AVIStream *ast;
int i;
int64_t last_pos = -1;
- int64_t filesize = avio_size(s->pb);
+ int64_t filesize = avi->fsize;
av_dlog(s,
"longs_pre_entry:%d index_type:%d entries_in_use:%d "
@@ -194,14 +216,15 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num)
int key = len >= 0;
len &= 0x7FFFFFFF;
- av_dlog(s, "pos:%"PRId64", len:%X\n", pos, len);
-
- if (pb->eof_reached)
+#ifdef DEBUG_SEEK
+ av_log(s, AV_LOG_ERROR, "pos:%"PRId64", len:%X\n", pos, len);
+#endif
+ 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);
@@ -214,7 +237,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);
@@ -224,16 +247,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;
}
@@ -324,6 +352,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) {
@@ -352,6 +381,84 @@ 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;
+
+ 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;
+ st->codec->bit_rate = av_rescale(8*len, st->time_base.den, duration * st->time_base.num);
+ }
+ return 1;
+}
+
static int avi_read_header(AVFormatContext *s)
{
AVIContext *avi = s->priv_data;
@@ -366,6 +473,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;
@@ -373,8 +481,10 @@ static int avi_read_header(AVFormatContext *s)
if (ret < 0)
return ret;
- avi->fsize = avio_size(pb);
- if (avi->fsize <= 0)
+ 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;
/* first list tag */
@@ -382,7 +492,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);
@@ -402,7 +512,7 @@ static int avi_read_header(AVFormatContext *s)
if (size)
avi->movi_end = avi->movi_list + size + (size & 1);
else
- avi->movi_end = avio_size(pb);
+ avi->movi_end = avi->fsize;
av_dlog(NULL, "movi end=%"PRIx64"\n", avi->movi_end);
goto end_of_header;
} else if (tag1 == MKTAG('I', 'N', 'F', 'O'))
@@ -430,7 +540,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;
@@ -486,6 +596,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;
@@ -514,7 +626,7 @@ static int avi_read_header(AVFormatContext *s)
break;
}
- assert(stream_index < s->nb_streams);
+ av_assert0(stream_index < s->nb_streams);
st->codec->stream_codec_tag = handler;
avio_rl32(pb); /* flags */
@@ -545,6 +657,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");
+ return AVERROR_INVALIDDATA;
+ }
ast->sample_size = avio_rl32(pb); /* sample ssize */
ast->cum_len *= FFMAX(1, ast->sample_size);
av_dlog(s, "%"PRIu32" %"PRIu32" %d\n",
@@ -555,6 +671,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;
@@ -566,23 +683,34 @@ 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)
+ 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) {
@@ -593,7 +721,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')) {
@@ -603,17 +731,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
@@ -623,7 +747,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;
@@ -632,12 +756,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;
}
@@ -650,11 +774,8 @@ static int avi_read_header(AVFormatContext *s)
/* This is needed to get the pict type which is necessary
* for generating correct pts. */
st->need_parsing = AVSTREAM_PARSE_HEADERS;
- // 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) {
@@ -704,15 +825,27 @@ static int avi_read_header(AVFormatContext *s)
if (st->codec->stream_codec_tag == 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) {
+ 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;
@@ -723,9 +856,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;
@@ -774,7 +933,7 @@ static int avi_read_header(AVFormatContext *s)
if (s->error_recognition & AV_EF_EXPLODE)
goto fail;
avi->movi_list = avio_tell(pb) - 4;
- avi->movi_end = avio_size(pb);
+ avi->movi_end = avi->fsize;
goto end_of_header;
}
/* skip tag */
@@ -794,17 +953,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");
@@ -822,15 +996,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);
@@ -848,15 +1024,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;
@@ -869,6 +1055,7 @@ static int read_gab2_sub(AVStream *st, AVPacket *pkt)
return 1;
error:
+ av_freep(&ast->sub_ctx);
av_freep(&pb);
}
return 0;
@@ -908,7 +1095,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') {
@@ -918,6 +1105,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;
@@ -929,7 +1120,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++)
@@ -941,7 +1132,7 @@ start_sync:
n = get_stream_idx(d + 2);
av_dlog(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##
@@ -978,16 +1169,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;
@@ -1004,9 +1201,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) {
@@ -1017,7 +1214,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;
@@ -1039,7 +1236,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) {
@@ -1052,6 +1249,8 @@ start_sync:
}
}
+ if (pb->error)
+ return pb->error;
return AVERROR_EOF;
}
@@ -1108,10 +1307,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,
@@ -1126,15 +1322,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:
@@ -1161,8 +1360,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,
@@ -1184,7 +1384,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;
@@ -1195,7 +1395,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;
@@ -1219,17 +1419,34 @@ 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;
+ int i;
+ uint32_t state=-1;
+ for (i=0; i<FFMIN(size,256); i++) {
+ if (st->codec->codec_id == AV_CODEC_ID_MPEG4) {
+ if (state == 0x1B6) {
+ key= !(pkt->data[i]&0xC0);
+ break;
+ }
+ }else
+ break;
+ state= (state<<8) + pkt->data[i];
+ }
+ if (!key)
+ e->flags &= ~AVINDEX_KEYFRAME;
+ }
if (e->flags & AVINDEX_KEYFRAME)
pkt->flags |= AV_PKT_FLAG_KEY;
+ }
} else {
pkt->flags |= AV_PKT_FLAG_KEY;
}
@@ -1241,6 +1458,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;
}
@@ -1260,7 +1493,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)
@@ -1273,8 +1508,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);
@@ -1289,7 +1532,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;
}
@@ -1297,16 +1540,25 @@ static int avi_read_idx1(AVFormatContext *s, int size)
av_dlog(s, "%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;
}
@@ -1320,7 +1572,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;
@@ -1411,16 +1662,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_dlog(s, "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_dlog(s, "tag=%c%c%c%c size=0x%x\n",
tag & 0xff,
(tag >> 8) & 0xff,
@@ -1430,12 +1684,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
}
@@ -1460,7 +1719,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
@@ -1472,16 +1731,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;
@@ -1495,15 +1761,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;
@@ -1519,35 +1788,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_dlog(s, "%"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;
}
@@ -1597,4 +1877,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 417a8e9..e05e022 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:
@@ -52,14 +62,15 @@ typedef struct {
typedef struct {
int64_t frames_hdr_strm;
- int audio_strm_length;
+ int64_t audio_strm_length;
int packet_count;
int entry;
+ int max_size;
AVIIndex indexes;
} AVIStream;
-static inline AVIIentry *avi_get_ientry(AVIIndex *idx, int ent_id)
+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;
@@ -117,7 +128,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 +140,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);
}
@@ -147,11 +158,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 +266,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 +288,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 +303,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,20 +314,47 @@ 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) {
@@ -381,11 +432,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");
@@ -403,10 +461,13 @@ 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;
+ if (avi->riff_id > AVI_MASTER_INDEX_SIZE) {
+ av_log(s, AV_LOG_ERROR, "Invalid riff index %d > %d\n",
+ avi->riff_id, AVI_MASTER_INDEX_SIZE);
+ return AVERROR(EINVAL);
+ }
for (i = 0; i < s->nb_streams; i++) {
AVIStream *avist = s->streams[i]->priv_data;
@@ -515,15 +576,27 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
AVIStream *avist = s->streams[stream_index]->priv_data;
AVCodecContext *enc = s->streams[stream_index]->codec;
+ if (enc->codec_id == AV_CODEC_ID_H264 && enc->codec_tag == MKTAG('H','2','6','4') && pkt->size) {
+ int ret = ff_check_h264_startcode(s, s->streams[stream_index], pkt);
+ if (ret < 0)
+ return ret;
+ }
+ av_dlog(s, "dts:%s packet_count:%d stream_index:%d\n", av_ts2str(pkt->dts), avist->packet_count, stream_index);
while (enc->block_align == 0 && pkt->dts != AV_NOPTS_VALUE &&
- pkt->dts > avist->packet_count) {
+ pkt->dts > avist->packet_count && enc->codec_id != AV_CODEC_ID_XSUB && avist->packet_count) {
AVPacket empty_packet;
+ if (pkt->dts - avist->packet_count > 60000) {
+ av_log(s, AV_LOG_ERROR, "Too large number of skipped frames %"PRId64" > 60000\n", pkt->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(pkt->dts), avist->packet_count);
}
avist->packet_count++;
@@ -547,27 +620,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++;
}
@@ -626,9 +699,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 f68994c..326bb0a 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
*/
@@ -116,6 +116,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 +145,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 +215,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 +270,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 +294,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 +307,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 +349,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, h->prot->url_write);
+ return retry_transfer_wrapper(h, (unsigned char *)buf, size, size, (void*)h->prot->url_write);
}
int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
@@ -294,8 +362,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 */
@@ -309,17 +378,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) {
diff --git a/libavformat/avio.h b/libavformat/avio.h
index 3360e82..86f754e 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
@@ -115,11 +115,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
@@ -146,6 +193,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.
@@ -191,8 +239,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 +255,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 +272,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 +378,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 +396,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 +416,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 +498,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 a8bcadd..5864048 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 6923b78..da94a4a 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);
@@ -205,22 +224,34 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
offset += offset1;
}
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) {
/* 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 +260,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 +270,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 +294,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)
@@ -288,15 +343,22 @@ int avio_put_str16le(AVIOContext *s, const char *str)
{
const uint8_t *q = str;
int ret = 0;
+ int err = 0;
while (*q) {
uint32_t ch;
uint16_t tmp;
- GET_UTF8(ch, *q++, break;)
+ GET_UTF8(ch, *q++, goto invalid;)
PUT_UTF16(ch, tmp, avio_wl16(s, tmp); ret += 2;)
+ continue;
+invalid:
+ av_log(s, AV_LOG_ERROR, "Invaid UTF8 sequence in avio_put_str16le\n");
+ err = AVERROR(EINVAL);
}
avio_wl16(s, 0);
+ if (err)
+ return err;
ret += 2;
return ret;
}
@@ -316,7 +378,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 +397,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 +445,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 +469,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 +524,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 +536,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 +556,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 +605,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 +675,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_skip(s, -1);
buf[i] = 0;
return i;
@@ -692,11 +760,12 @@ int ffio_fdopen(AVIOContext **s, URLContext *h)
return AVERROR(ENOMEM);
*s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE, h,
- ffurl_read, ffurl_write, ffurl_seek);
+ (void*)ffurl_read, (void*)ffurl_write, (void*)ffurl_seek);
if (!*s) {
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) {
@@ -707,6 +776,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)
+ 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;
@@ -716,6 +811,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);
@@ -724,7 +820,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;
@@ -736,27 +832,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) {
@@ -807,6 +908,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);
}
@@ -858,6 +963,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 f94f7b7..c01d7e4 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
*/
@@ -27,25 +26,17 @@
/* Enable function pointer definitions for runtime loading. */
#define AVSC_NO_DECLSPEC
-/* Platform-specific directives for AviSynth vs AvxSynth.
- *
- * avisynth_c.h needs to be the one provided with x264, as
- * the one in AviSynth's CVS hasn't been updated to support
- * 2.6's extra colorspaces. A temporary source of that header,
- * installable from a GNU-style Makefile is available from
- * github.com/qyot27/avisynth_headers -- AvxSynth doesn't
- * require this kind of special treatment because like any
- * standard *nix application, it installs its headers
- * alongside its libs. */
+/* Platform-specific directives for AviSynth vs AvxSynth. */
#ifdef _WIN32
#include <windows.h>
#undef EXTERN_C
- #include <avisynth/avisynth_c.h>
+ #include "compat/avisynth/avisynth_c.h"
+ #include "compat/avisynth/avisynth_c_25.h"
#define AVISYNTH_LIB "avisynth"
#define USING_AVISYNTH
#else
#include <dlfcn.h>
- #include <avxsynth/avxsynth_c.h>
+ #include "compat/avisynth/avxsynth_c.h"
#if defined (__APPLE__)
#define AVISYNTH_LIB "libavxsynth.dylib"
#else
@@ -393,19 +384,6 @@ static int avisynth_open_file(AVFormatContext *s)
avs->clip = avs_library.avs_take_clip(val, avs->env);
avs->vi = avs_library.avs_get_video_info(avs->clip);
-#ifdef USING_AVISYNTH
- /* libav only supports AviSynth 2.6 on Windows. Since AvxSynth
- * identifies itself as interface version 3 like 2.5.8, this
- * needs to be special-cased. */
-
- if (avs_library.avs_get_version(avs->clip) == 3) {
- av_log(s, AV_LOG_ERROR,
- "AviSynth 2.5.8 not supported. Please upgrade to 2.6.\n");
- ret = AVERROR_UNKNOWN;
- goto fail;
- }
-#endif
-
/* Release the AVS_Value as it will go out of scope. */
avs_library.avs_release_value(val);
@@ -502,8 +480,18 @@ static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt,
src_p = avs_get_read_ptr_p(frame, plane);
pitch = avs_get_pitch_p(frame, plane);
+#ifdef USING_AVISYNTH
+ if (avs_library.avs_get_version(avs->clip) == 3) {
+ rowsize = avs_get_row_size_p_25(frame, plane);
+ planeheight = avs_get_height_p_25(frame, plane);
+ } else {
+ rowsize = avs_get_row_size_p(frame, plane);
+ planeheight = avs_get_height_p(frame, plane);
+ }
+#else
rowsize = avs_get_row_size_p(frame, plane);
planeheight = avs_get_height_p(frame, plane);
+#endif
/* Flip RGB video. */
if (avs_is_rgb24(avs->vi) || avs_is_rgb(avs->vi)) {
diff --git a/libavformat/avlanguage.c b/libavformat/avlanguage.c
index e606ef2..39f2560 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 2ec3e2d..7fb8968 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 0000000..a33134e
--- /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 d8042c5..b699dbf 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 135a3c4..40a4252 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 19060e7..cc7f494 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 4d2a735..395c8d9 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,12 @@ 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);
+ avio_seek(pb, vst->index_entries[0].pos, SEEK_SET);
bink->current_track = -1;
return 0;
@@ -206,7 +211,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 +293,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 0000000..217ea49
--- /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 0000000..7b807b9
--- /dev/null
+++ b/libavformat/bit.c
@@ -0,0 +1,156 @@
+/*
+ * 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;
+
+ enc->codec_id = AV_CODEC_ID_G729;
+ enc->channels = 1;
+ 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;
+
+ 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 0000000..d2c57aa
--- /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 b5572af..f7a6068 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 0000000..45f6b39
--- /dev/null
+++ b/libavformat/boadec.c
@@ -0,0 +1,78 @@
+/*
+ * 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"
+
+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->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->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 0000000..19a4a2a
--- /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 3f2a98f..93a61be 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 0000000..35f81e8
--- /dev/null
+++ b/libavformat/cache.c
@@ -0,0 +1,140 @@
+/*
+ * Input cache protocol.
+ * 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
+ *
+ * Based on file.c by Fabrice Bellard
+ */
+
+/**
+ * @TODO
+ * support non continuous caching
+ * support keeping files
+ * support filling with a background thread
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/file.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 Context {
+ int fd;
+ int64_t end;
+ int64_t pos;
+ URLContext *inner;
+} Context;
+
+static int cache_open(URLContext *h, const char *arg, int flags)
+{
+ 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, NULL);
+}
+
+static int cache_read(URLContext *h, unsigned char *buf, int size)
+{
+ Context *c= h->priv_data;
+ int r;
+
+ if(c->pos<c->end){
+ r = read(c->fd, buf, FFMIN(size, c->end - c->pos));
+ if(r>0)
+ c->pos += r;
+ return (-1 == r)?AVERROR(errno):r;
+ }else{
+ r = ffurl_read(c->inner, buf, size);
+ if(r > 0){
+ int r2= write(c->fd, buf, r);
+ av_assert0(r2==r); // FIXME handle cache failure
+ c->pos += r;
+ c->end += r;
+ }
+ return r;
+ }
+}
+
+static int64_t cache_seek(URLContext *h, int64_t pos, int whence)
+{
+ Context *c= h->priv_data;
+
+ if (whence == AVSEEK_SIZE) {
+ pos= ffurl_seek(c->inner, pos, whence);
+ if(pos <= 0){
+ pos= ffurl_seek(c->inner, -1, SEEK_END);
+ ffurl_seek(c->inner, c->end, SEEK_SET);
+ if(pos <= 0)
+ return c->end;
+ }
+ return pos;
+ }
+
+ pos= lseek(c->fd, pos, whence);
+ if(pos<0){
+ return pos;
+ }else if(pos <= c->end){
+ c->pos= pos;
+ return pos;
+ }else{
+ if(lseek(c->fd, c->pos, SEEK_SET) < 0) {
+ av_log(h, AV_LOG_ERROR, "Failure to seek in cache\n");
+ }
+ return AVERROR(EPIPE);
+ }
+}
+
+static int cache_close(URLContext *h)
+{
+ Context *c= h->priv_data;
+ close(c->fd);
+ ffurl_close(c->inner);
+
+ return 0;
+}
+
+URLProtocol ff_cache_protocol = {
+ .name = "cache",
+ .url_open = cache_open,
+ .url_read = cache_read,
+ .url_seek = cache_seek,
+ .url_close = cache_close,
+ .priv_data_size = sizeof(Context),
+};
diff --git a/libavformat/caf.c b/libavformat/caf.c
index cf128d5..c1ecc94 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 7ca4dc5..9c25f2c 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 4489eb2..7d518d7 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);
@@ -131,8 +131,7 @@ static int read_kuki_chunk(AVFormatContext *s, int64_t size)
}
avio_read(pb, preamble, ALAC_PREAMBLE);
- st->codec->extradata = av_mallocz(ALAC_HEADER + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!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.
@@ -155,13 +154,9 @@ static int read_kuki_chunk(AVFormatContext *s, int64_t size)
avio_read(pb, &st->codec->extradata[24], ALAC_NEW_KUKI - 12);
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)
+ 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 +204,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 +220,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 +240,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 +249,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 +287,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 +309,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 +338,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 +397,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 0000000..1708275
--- /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 fcca9e1..880f4ab 100644
--- a/libavformat/cavsvideodec.c
+++ b/libavformat/cavsvideodec.c
@@ -2,20 +2,20 @@
* 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
*/
@@ -61,7 +61,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 e699691..baf37d4 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 a2cba52..e3e379a 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
*/
@@ -39,6 +39,48 @@ typedef struct CDXLDemuxContext {
int audio_stream_index;
} 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;
@@ -68,7 +110,7 @@ static int cdxl_read_packet(AVFormatContext *s, AVPacket *pkt)
int64_t pos;
int ret;
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_EOF;
pos = avio_tell(pb);
@@ -180,6 +222,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 0000000..632f46c
--- /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 2fb3ba9..81fe970 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 0000000..2089883
--- /dev/null
+++ b/libavformat/concatdec.c
@@ -0,0 +1,635 @@
+/*
+ * 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 "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 delta;
+ ConcatStream *cs;
+
+ 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;
+
+ delta = av_rescale_q(cat->cur_file->start_time - cat->avf->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;
+ 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 925646b..3fdfea5 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 3bc33f2..a9b6e47 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
*/
@@ -59,7 +59,7 @@ static const AVClass crypto_class = {
.version = LIBAVUTIL_VERSION_INT,
};
-static int crypto_open(URLContext *h, const char *uri, int flags)
+static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary **options)
{
const char *nested_url;
int ret = 0;
@@ -83,7 +83,7 @@ static int crypto_open(URLContext *h, const char *uri, int flags)
goto err;
}
if ((ret = ffurl_open(&c->hd, nested_url, AVIO_FLAG_READ,
- &h->interrupt_callback, NULL)) < 0) {
+ &h->interrupt_callback, options)) < 0) {
av_log(h, AV_LOG_ERROR, "Unable to open input\n");
goto err;
}
@@ -161,7 +161,7 @@ static int crypto_close(URLContext *h)
URLProtocol ff_crypto_protocol = {
.name = "crypto",
- .url_open = crypto_open,
+ .url_open2 = crypto_open2,
.url_read = crypto_read,
.url_close = crypto_close,
.priv_data_size = sizeof(CryptoContext),
diff --git a/libavformat/cutils.c b/libavformat/cutils.c
index f5339a9..d86ba05 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/data_uri.c b/libavformat/data_uri.c
new file mode 100644
index 0000000..1598b99
--- /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 1855e84..f6e7491 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 416e895..99b18d3 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 c097d72..450bc21 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 f275212..e061ba5 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 8bb6814..7b55400 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 0000000..ae198b2
--- /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 6a7c8b9..4b5a934 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/dtsdec.c b/libavformat/dtsdec.c
index 9010711..f6a939a 100644
--- a/libavformat/dtsdec.c
+++ b/libavformat/dtsdec.c
@@ -2,24 +2,26 @@
* 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/get_bits.h"
+#include "libavcodec/dca.h"
#include "avformat.h"
#include "rawdec.h"
@@ -32,34 +34,71 @@ 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] = {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;
+ 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_MARKER_RAW_BE || state == DCA_MARKER_RAW_LE)
- markers[0]++;
+ if (state == DCA_MARKER_RAW_BE)
+ marker = 0;
+ else if (state == DCA_MARKER_RAW_LE)
+ marker = 1;
/* 14 bits big-endian bitstream */
- if (state == DCA_MARKER_14B_BE)
- if ((bytestream_get_be16(&bufp) & 0xFFF0) == 0x07F0)
- markers[1]++;
+ else if (state == DCA_MARKER_14B_BE &&
+ (bytestream_get_be16(&bufp) & 0xFFF0) == 0x07F0)
+ marker = 2;
/* 14 bits little-endian bitstream */
- if (state == DCA_MARKER_14B_LE)
- if ((bytestream_get_be16(&bufp) & 0xF0FF) == 0xF007)
- markers[2]++;
+ else if (state == DCA_MARKER_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;
+
+ markers[marker] ++;
}
- sum = markers[0] + markers[1] + markers[2];
- max = markers[1] > markers[0];
- max = markers[2] > markers[max] ? 2 : max;
+ sum = markers[0] + markers[1] + markers[2] + markers[3];
+ max = 0;
+ for (i=1; i<4; 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 0000000..0fd0304
--- /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 99188f0..56b37ff 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);
}
@@ -130,9 +133,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");
+ }
}
}
@@ -330,8 +346,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 */
@@ -351,20 +374,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)
@@ -417,8 +444,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 da201a3..095966c 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;
@@ -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,38 @@ 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;
+ 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 +504,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 +519,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 +536,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 +550,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;
@@ -520,31 +586,37 @@ static int dv_read_close(AVFormatContext *s)
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 e8b2d37..160c6ab 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/dvenc.c b/libavformat/dvenc.c
index a33973f..18fdf9f 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,27 @@ 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);
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 +361,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 +380,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 78e7290..6ad1c9f 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;
+ return AVERROR(ENOMEM);
ret = ff_get_wav_header(pb, ast->codec, fsize);
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 b56ba1c..57e5145 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 7c1fabe..d6a396b 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 0000000..c737892
--- /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 0000000..b392b8d
--- /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 0000000..448762b
--- /dev/null
+++ b/libavformat/ffmdec.c
@@ -0,0 +1,643 @@
+/*
+ * 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 "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;
+
+ 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;
+ 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) {
+ avio_seek(pb, -ffm->packet_size * 2LL, 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 ffm2_read_header(AVFormatContext *s)
+{
+ FFMContext *ffm = s->priv_data;
+ AVStream *st;
+ AVIOContext *pb = s->pb;
+ AVCodecContext *codec;
+ int ret;
+
+ 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'):
+ avio_rb32(pb); /* nb_streams */
+ avio_rb32(pb); /* total bitrate */
+ break;
+ case MKBETAG('C', 'O', 'M', 'M'):
+ 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);
+ }
+ avio_seek(pb, next, SEEK_SET);
+ id = avio_rb32(pb);
+ size = avio_rb32(pb);
+ next = avio_tell(pb) + size;
+ switch(id) {
+ case MKBETAG('S', 'T', 'V', 'I'):
+ codec->time_base.num = avio_rb32(pb);
+ codec->time_base.den = avio_rb32(pb);
+ 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'):
+ codec->sample_rate = avio_rb32(pb);
+ codec->channels = avio_rl16(pb);
+ codec->frame_size = avio_rl16(pb);
+ break;
+ }
+ break;
+ }
+ avio_seek(pb, next, SEEK_SET);
+ }
+
+ /* get until end of block reached */
+ while ((avio_tell(pb) % ffm->packet_size) != 0)
+ 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);
+ 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)
+ 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 0000000..eb809eb
--- /dev/null
+++ b/libavformat/ffmenc.c
@@ -0,0 +1,281 @@
+/*
+ * 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 "avformat.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(AVFormatContext *s)
+{
+ FFMContext *ffm = s->priv_data;
+ AVDictionaryEntry *t;
+ AVStream *st;
+ AVIOContext *pb = s->pb;
+ AVCodecContext *codec;
+ int bit_rate, i;
+
+ if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) {
+ int 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'));
+ if(avio_open_dyn_buf(&pb) < 0)
+ return AVERROR(ENOMEM);
+ /* specific info */
+ switch(codec->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ avio_wb32(pb, codec->time_base.num);
+ avio_wb32(pb, codec->time_base.den);
+ avio_wb16(pb, codec->width);
+ avio_wb16(pb, codec->height);
+ avio_wb16(pb, codec->gop_size);
+ avio_wb32(pb, codec->pix_fmt);
+ avio_w8(pb, codec->qmin);
+ avio_w8(pb, codec->qmax);
+ avio_w8(pb, codec->max_qdiff);
+ avio_wb16(pb, (int) (codec->qcompress * 10000.0));
+ avio_wb16(pb, (int) (codec->qblur * 10000.0));
+ avio_wb32(pb, codec->bit_rate_tolerance);
+ avio_put_str(pb, codec->rc_eq ? codec->rc_eq : "tex^qComp");
+ avio_wb32(pb, codec->rc_max_rate);
+ avio_wb32(pb, codec->rc_min_rate);
+ avio_wb32(pb, codec->rc_buffer_size);
+ avio_wb64(pb, av_double2int(codec->i_quant_factor));
+ avio_wb64(pb, av_double2int(codec->b_quant_factor));
+ avio_wb64(pb, av_double2int(codec->i_quant_offset));
+ avio_wb64(pb, av_double2int(codec->b_quant_offset));
+ avio_wb32(pb, codec->dct_algo);
+ avio_wb32(pb, codec->strict_std_compliance);
+ avio_wb32(pb, codec->max_b_frames);
+ avio_wb32(pb, codec->mpeg_quant);
+ avio_wb32(pb, codec->intra_dc_precision);
+ avio_wb32(pb, codec->me_method);
+ avio_wb32(pb, codec->mb_decision);
+ avio_wb32(pb, codec->nsse_weight);
+ avio_wb32(pb, codec->frame_skip_cmp);
+ avio_wb64(pb, av_double2int(codec->rc_buffer_aggressivity));
+ avio_wb32(pb, codec->codec_tag);
+ avio_w8(pb, codec->thread_count);
+ avio_wb32(pb, codec->coder_type);
+ avio_wb32(pb, codec->me_cmp);
+ avio_wb32(pb, codec->me_subpel_quality);
+ avio_wb32(pb, codec->me_range);
+ avio_wb32(pb, codec->keyint_min);
+ avio_wb32(pb, codec->scenechange_threshold);
+ avio_wb32(pb, codec->b_frame_strategy);
+ avio_wb64(pb, av_double2int(codec->qcompress));
+ avio_wb64(pb, av_double2int(codec->qblur));
+ avio_wb32(pb, codec->max_qdiff);
+ avio_wb32(pb, codec->refs);
+ write_header_chunk(s->pb, pb, MKBETAG('S', 'T', 'V', 'I'));
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ avio_wb32(pb, codec->sample_rate);
+ avio_wl16(pb, codec->channels);
+ avio_wl16(pb, codec->frame_size);
+ write_header_chunk(s->pb, pb, MKBETAG('S', 'T', 'A', 'U'));
+ 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 a5380ca..ae8778d 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 7dbf7ed..e226406 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 19fe6c9..a9adbb1 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 2837e9f..6511328 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 e4dee11..b76d4b7 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 8d1d2d8..7c9bc6d 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 a6b5537..669fd2e 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 c700582..4374b6f 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 8abdd9d..1a8dc19 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,6 +170,10 @@ static int flac_read_header(AVFormatContext *s)
return ret;
return 0;
+
+fail:
+ av_free(buffer);
+ return ret;
}
static int flac_probe(AVProbeData *p)
@@ -182,12 +183,61 @@ static int flac_probe(AVProbeData *p)
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 a686826..0eea942 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,17 +42,14 @@ 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;
+ const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT;
unsigned int len;
uint8_t *p, *p0;
@@ -77,12 +75,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(padding, 0, 16777215);
+
ret = ff_flac_write_header(s->pb, codec->extradata,
codec->extradata_size, 0);
if (ret)
@@ -105,7 +119,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 +127,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 54dd833..d5d53a5 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 4f9bb20..61833cc 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 2eb6f05..f5e9e84 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;
@@ -177,8 +176,8 @@ static int flic_read_header(AVFormatContext *s)
/* send over abbreviated FLIC header chunk */
av_free(st->codec->extradata);
- st->codec->extradata_size = 12;
- st->codec->extradata = av_malloc(12);
+ 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 fe0fc90..db9468f 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 2d5e50e..1c70a72 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 {
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 {
} 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_DATA
+ && s->streams[1]->codec->codec_type != AVMEDIA_TYPE_DATA))
+ 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;
}
@@ -391,10 +410,11 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
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)
@@ -483,6 +503,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") ||
@@ -517,6 +542,7 @@ 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,6 +551,7 @@ 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
@@ -543,10 +570,12 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos)
// 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_DATA)
+ dstream = stream;
}
// parse the second object (we want a mixed array)
@@ -571,6 +600,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 +614,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)
+ 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;
}
@@ -737,21 +766,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_dlog(s, "type:%d, size:%d, dts:%"PRId64"\n", type, size, dts);
- if (s->pb->eof_reached)
+ av_dlog(s, "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 +809,28 @@ 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) {
+ stream_type=FLV_STREAM_TYPE_DATA;
+ if (size > 13 + 1 + 4 && dts == 0) { // Header-type metadata stuff
+ meta_pos = avio_tell(s->pb);
+ if (flv_read_metabody(s, next) == 0) {
+ goto skip;
+ }
+ avio_seek(s->pb, meta_pos, SEEK_SET);
+ }
} else {
- if (type == FLV_TAG_TYPE_META && size > 13 + 1 + 4)
- if (flv_read_metabody(s, next) > 0) {
- 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);
-
+ 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 +843,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_DATA)
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_DATA};
+ 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_dlog(s, "%d %X %d \n", is_audio, flags, st->discard);
+ av_dlog(s, "%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,22 +882,30 @@ 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);
- 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);
avio_seek(s->pb, fsize - 3 - size, SEEK_SET);
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) >>
@@ -880,49 +928,59 @@ 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);
}
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;
- avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata,
- st->codec->extradata_size * 8, 1);
+ if (st->codec->codec_id == AV_CODEC_ID_AAC && 0) {
+ MPEG4AudioConfig cfg;
+
+ 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)
@@ -931,6 +989,7 @@ skip:
st->codec->sample_rate = cfg.sample_rate;
av_dlog(s, "mp4a config channels %d sample rate %d\n",
st->codec->channels, st->codec->sample_rate);
+ }
}
ret = AVERROR(EAGAIN);
@@ -946,31 +1005,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:
@@ -993,7 +1052,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,
@@ -1010,5 +1069,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 cc4c782..6266fb0 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 }
@@ -77,12 +80,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 {
@@ -105,9 +108,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);
}
}
@@ -148,8 +151,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;
@@ -213,8 +217,21 @@ static int flv_write_header(AVFormatContext *s)
}
video_enc = enc;
if (enc->codec_tag == 0) {
- av_log(s, AV_LOG_ERROR, "video codec not compatible with flv\n");
- return -1;
+ av_log(s, AV_LOG_ERROR, "Video codec '%s' for stream %d is not compatible with FLV\n",
+ avcodec_get_name(enc->codec_id), i);
+ return AVERROR(EINVAL);
+ }
+ 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);
+ }
}
break;
case AVMEDIA_TYPE_AUDIO:
@@ -226,17 +243,22 @@ static int flv_write_header(AVFormatContext *s)
audio_enc = enc;
if (get_audio_flags(s, enc) < 0)
return AVERROR_INVALIDDATA;
+ 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) {
- av_log(s, AV_LOG_ERROR, "codec not compatible with flv\n");
+ if (enc->codec_id != AV_CODEC_ID_TEXT && enc->codec_id != AV_CODEC_ID_NONE) {
+ av_log(s, AV_LOG_ERROR, "Data codec '%s' for stream %d is not compatible with FLV\n",
+ avcodec_get_name(enc->codec_id), i);
return AVERROR_INVALIDDATA;
}
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 */
@@ -338,6 +360,22 @@ static int flv_write_header(AVFormatContext *s)
}
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")
+ ){
+ 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);
@@ -364,7 +402,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);
@@ -407,7 +445,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);
}
@@ -436,12 +474,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;
@@ -453,9 +491,9 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
flags = enc->codec_tag;
if (flags == 0) {
av_log(s, AV_LOG_ERROR,
- "video codec %X not compatible with flv\n",
- enc->codec_id);
- return -1;
+ "Video codec '%s' is not compatible with FLV\n",
+ avcodec_get_name(enc->codec_id));
+ return AVERROR(EINVAL);
}
flags |= pkt->flags & AV_PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER;
@@ -463,7 +501,7 @@ 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;
@@ -474,11 +512,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");
+ }
if (flv->delay == AV_NOPTS_VALUE)
flv->delay = -pkt->dts;
@@ -500,26 +548,38 @@ 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) {
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);
@@ -527,7 +587,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]);
@@ -536,7 +599,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 24b7205..97f5657 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;
@@ -168,108 +164,121 @@ 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 (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 +286,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 +298,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 +319,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 4d5483a..805b542 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 6a6da98..a8357b0 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 0000000..a6f19af
--- /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 0000000..7faf4a5
--- /dev/null
+++ b/libavformat/ftp.c
@@ -0,0 +1,801 @@
+/*
+ * 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
+#define CREDENTIALS_BUFFER_SIZE 128
+
+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[512]; /**< Server address. */
+ char credencials[CREDENTIALS_BUFFER_SIZE]; /**< Authentication data */
+ char path[MAX_URL_SIZE]; /**< 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_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)
+{
+ const char *user = NULL, *pass = NULL;
+ char *end = NULL, buf[CONTROL_BUFFER_SIZE], credencials[CREDENTIALS_BUFFER_SIZE];
+ int err;
+ static const int user_codes[] = {331, 230, 0};
+ static const int pass_codes[] = {230, 0};
+
+ /* Authentication may be repeated, original string has to be saved */
+ av_strlcpy(credencials, s->credencials, sizeof(credencials));
+
+ user = av_strtok(credencials, ":", &end);
+ pass = av_strtok(end, ":", &end);
+
+ if (!user) {
+ user = "anonymous";
+ pass = s->anonymous_password ? s->anonymous_password : "nopassword";
+ }
+
+ snprintf(buf, sizeof(buf), "USER %s\r\n", user);
+ err = ftp_send_command(s, buf, user_codes, NULL);
+ if (err == 331) {
+ if (pass) {
+ snprintf(buf, sizeof(buf), "PASS %s\r\n", pass);
+ 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';
+ av_strlcpy(s->path, start, sizeof(s->path));
+
+ av_free(res);
+ 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];
+ int err;
+ 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),
+ s->credencials, sizeof(s->credencials),
+ s->hostname, sizeof(s->hostname),
+ &s->server_control_port,
+ path, sizeof(path),
+ url);
+
+ 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;
+ av_strlcat(s->path, path, sizeof(s->path));
+
+ 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");
+ ffurl_closep(&s->conn_control);
+ ffurl_closep(&s->conn_data);
+ 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)
+{
+ av_dlog(h, "ftp protocol close\n");
+
+ ftp_close_both_connections(h->priv_data);
+
+ 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 8052939..1a87c7d 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 b67c07c..4f3ce8f 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 0000000..794558e
--- /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 085c2e0..e817121 100644
--- a/libavformat/gif.c
+++ b/libavformat/gif.c
@@ -4,347 +4,194 @@
*
* 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 {
- 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 },
-};
-
-/* GIF header */
-static int gif_image_write_header(AVIOContext *pb, int width, int height,
+static int gif_image_write_header(AVFormatContext *s, int width, int height,
int loop_count, uint32_t *palette)
{
+ AVIOContext *pb = s->pb;
+ AVRational sar = s->streams[0]->codec->sample_aspect_ratio;
int i;
- unsigned int v;
+ int64_t aspect = 0;
+
+ if (sar.num > 0 && sar.den > 0) {
+ aspect = sar.num * 64LL / sar.den - 15;
+ if (aspect < 0 || aspect > 255)
+ aspect = 0;
+ }
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 {
+ if (palette) {
+ avio_w8(pb, 0xf7); /* flags: global clut, 256 entries */
+ avio_w8(pb, 0x1f); /* background color index */
+ avio_w8(pb, aspect);
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);
+ 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);
}
- /* 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
+ 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); // byte 15
- avio_w8(pb, 0x01); // byte 16
+ avio_w8(pb, 0x03); /* Length of Data Sub-Block */
+ avio_w8(pb, 0x01);
avio_wl16(pb, (uint16_t)loop_count);
- avio_w8(pb, 0x00); // byte 19
+ avio_w8(pb, 0x00); /* Data Sub-block Terminator */
}
-#endif
- return 0;
-}
-
-/* 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)
-{
- 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 */
-
- avio_w8(pb, 0x08);
-
- left = width * height;
-
- init_put_bits(&p, buffer, 130);
-
-/*
- * 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;
- }
- }
-
- 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;
- }
- avio_w8(pb, 0x00); /* end of image block */
return 0;
}
typedef struct {
- 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*/;
-
-/* XXX: do we reject audio streams or just ignore them ?
- * if (s->nb_streams > 1)
- * return -1;
- */
- gif->time = 0;
- gif->file_time = 0;
+ AVCodecContext *video_enc;
+ int width, height;
+ uint32_t palette[AVPALETTE_COUNT];
- 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;
+ width = video_enc->width;
+ height = video_enc->height;
- 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);
+ gif_image_write_header(s, width, height, gif->loop, NULL);
+ } else {
+ gif_image_write_header(s, width, height, 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;
AVIOContext *pb = s->pb;
- int jiffies;
+ uint8_t flags = 0x4, transparent_color_index = 0x1f;
+ 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;
+ }
+ if (palette) {
+ unsigned i, smallest_alpha = 0xff;
+
+ 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;
+ }
+ }
+ if (smallest_alpha < 128)
+ flags |= 0x1; /* Transparent Color Flag */
+ }
+
+ 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, flags);
+ avio_wl16(pb, gif->duration);
+ avio_w8(pb, transparent_color_index);
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;
+
+ if (!gif->prev_pkt) {
+ gif->prev_pkt = av_malloc(sizeof(*gif->prev_pkt));
+ if (!gif->prev_pkt)
+ return AVERROR(ENOMEM);
+ 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 +200,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 +221,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 0000000..7db5a27
--- /dev/null
+++ b/libavformat/gifdec.c
@@ -0,0 +1,334 @@
+/*
+ * 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 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;
+
+ /* 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 },
+ { "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 0000000..063fae3
--- /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 a149f7f..9dc155a 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 f9ecbaf..dbe557b 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 1895840..6c624f0 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,7 +556,7 @@ 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) {
diff --git a/libavformat/gxf.h b/libavformat/gxf.h
index c1ac399..dcdcdef 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 fea1d5d..12031f7 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 4a58050..a1d6821 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 4d826d8..145fb85 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 6fd45c1..76073dd 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 ae9275c..eec9bb8 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
*/
@@ -204,7 +204,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 +285,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)
@@ -323,6 +323,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 +333,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;
@@ -479,7 +480,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);
@@ -515,7 +516,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)
@@ -537,7 +538,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 37b35b4..45b00c4 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
*/
@@ -799,7 +799,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 03c43bd..796eaf4 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 65a3cdf..e36a051 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 8b52a35..f17b826 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
@@ -57,19 +66,28 @@ enum KeyType {
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 +99,86 @@ 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 {
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 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 +189,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 +232,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,29 +258,72 @@ 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);
}
}
@@ -199,24 +348,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 +536,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,
@@ -254,49 +561,58 @@ static int parse_playlist(HLSContext *c, const char *url,
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 +624,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,21 +675,269 @@ 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 int open_input(HLSContext *c, struct playlist *pls)
{
- struct segment *seg = var->segments[var->cur_seq_no - var->start_seq_no];
+ 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);
}
@@ -352,49 +946,101 @@ static int open_input(struct variant *var)
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;
}
- return 0;
+ ret = 0;
}
- return AVERROR(ENOSYS);
+ 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;
+ }
+ }
+
+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 +1064,205 @@ reload:
goto reload;
}
- ret = open_input(v);
- if (ret < 0)
+ 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);
return ret;
+ }
+ 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 with more than 3 segments, start at the
+ * third last segment. */
+ if (pls->n_segments > 3)
+ return pls->start_seq_no + pls->n_segments - 3;
+ }
+
+ /* 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
+ av_freep(&c->user_agent);
+ av_opt_get(u->priv_data, "user-agent", 0, (uint8_t**)&(c->user_agent));
+ if (c->user_agent && !strlen(c->user_agent))
+ av_freep(&c->user_agent);
+
+ // get the previous cookies & set back to null if string size is zero
+ av_freep(&c->cookies);
+ av_opt_get(u->priv_data, "cookies", 0, (uint8_t**)&(c->cookies));
+ if (c->cookies && !strlen(c->cookies))
+ av_freep(&c->cookies);
+
+ // get the previous headers & set back to null if string size is zero
+ av_freep(&c->headers);
+ av_opt_get(u->priv_data, "headers", 0, (uint8_t**)&(c->headers));
+ if (c->headers && !strlen(c->headers))
+ av_freep(&c->headers);
+ }
+
if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0)
goto fail;
@@ -464,17 +1271,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 +1289,141 @@ 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];
+ struct variant *var = c->variants[i];
+
+ 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);
+ }
+
+ /* Open the demuxer for each playlist */
+ for (i = 0; i < c->n_playlists; i++) {
+ struct playlist *pls = c->playlists[i];
AVInputFormat *in_fmt = NULL;
- char bitrate_str[20];
- AVProgram *program;
- if (v->n_segments == 0)
+ if (pls->n_segments == 0)
continue;
- if (!(v->ctx = avformat_alloc_context())) {
+ if (!(pls->ctx = avformat_alloc_context())) {
ret = AVERROR(ENOMEM);
goto fail;
}
- v->index = i;
- v->needed = 1;
- v->parent = s;
-
- /* 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);
+ 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 +1433,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 +1607,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 +1617,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)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index ad53df5..0525e70 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -2,26 +2,27 @@
* 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 <float.h>
#include <stdint.h>
+#include "libavutil/avassert.h"
#include "libavutil/mathematics.h"
#include "libavutil/parseutils.h"
#include "libavutil/avstring.h"
@@ -31,11 +32,19 @@
#include "avformat.h"
#include "internal.h"
-typedef struct ListEntry {
- char name[1024];
- int duration;
- struct ListEntry *next;
-} ListEntry;
+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),
+} HLSFlags;
typedef struct HLSContext {
const AVClass *class; // Class for private options.
@@ -43,21 +52,32 @@ 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
+
+ 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;
+
+ HLSSegment *segments;
+ HLSSegment *last_segment;
+
char *basename;
char *baseurl;
+ char *format_options_str;
+ AVDictionary *format_options;
+
AVIOContext *pb;
} HLSContext;
@@ -65,14 +85,17 @@ 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;
@@ -82,32 +105,37 @@ 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));
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->last_segment->next = en;
- hls->end_list = en;
+ hls->last_segment = en;
- if (hls->nb_entries >= hls->size) {
- en = hls->list;
- hls->list = en->next;
+ if (hls->max_nb_segments && hls->nb_entries >= hls->max_nb_segments) {
+ en = hls->segments;
+ hls->segments = en->next;
av_free(en);
} else
hls->nb_entries++;
@@ -117,9 +145,9 @@ static int append_entry(HLSContext *hls, uint64_t duration)
return 0;
}
-static void free_entries(HLSContext *hls)
+static void hls_free_segments(HLSContext *hls)
{
- ListEntry *p = hls->list, *en;
+ HLSSegment *p = hls->segments, *en;
while(p) {
en = p;
@@ -131,22 +159,23 @@ 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;
- 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;
if ((ret = avio_open2(&hls->pb, s->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);
}
avio_printf(hls->pb, "#EXTM3U\n");
- avio_printf(hls->pb, "#EXT-X-VERSION:3\n");
+ avio_printf(hls->pb, "#EXT-X-VERSION:%d\n", version);
if (hls->allowcache == 0 || hls->allowcache == 1) {
avio_printf(hls->pb, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES");
}
@@ -156,11 +185,14 @@ 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(hls->pb, "#EXTINF:%d,\n", en->duration);
+ for (en = hls->segments; en; en = en->next) {
+ avio_printf(hls->pb, "#EXTINF:%f,\n", en->duration);
+ if (hls->flags & HLS_SINGLE_FILE)
+ avio_printf(hls->pb, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n",
+ en->size, en->pos);
if (hls->baseurl)
avio_printf(hls->pb, "%s", hls->baseurl);
- avio_printf(hls->pb, "%s\n", en->name);
+ avio_printf(hls->pb, "%s\n", en->filename);
}
if (last)
@@ -177,9 +209,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,
@@ -198,12 +236,24 @@ static int hls_write_header(AVFormatContext *s)
int ret, i;
char *p;
const char *pattern = "%d.ts";
+ AVDictionary *options = NULL;
int basename_size = strlen(s->filename) + strlen(pattern) + 1;
hls->sequence = hls->start_sequence;
hls->recording_time = hls->time * AV_TIME_BASE;
hls->start_pts = AV_NOPTS_VALUE;
+ if (hls->flags & HLS_SINGLE_FILE)
+ pattern = ".ts";
+
+ 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;
@@ -242,11 +292,22 @@ static int hls_write_header(AVFormatContext *s)
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:
+
+ av_dict_free(&options);
if (ret) {
av_free(hls->basename);
if (hls->avf)
@@ -261,6 +322,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) {
@@ -271,26 +333,39 @@ 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);
+ 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)
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_close(oc->pb);
- ret = hls_start(s);
+ ret = hls_start(s);
+ }
if (ret)
return ret;
@@ -301,7 +376,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;
}
@@ -312,13 +387,14 @@ static int hls_write_trailer(struct AVFormatContext *s)
AVFormatContext *oc = hls->avf;
av_write_trailer(oc);
+ hls->size = avio_tell(hls->avf->pb) - hls->start_pos;
avio_closep(&oc->pb);
avformat_free_context(oc);
av_free(hls->basename);
- append_entry(hls, hls->duration);
+ hls_append_segment(hls, hls->duration, hls->start_pos, hls->size);
hls_window(s, 1);
- free_entries(hls);
+ hls_free_segments(hls);
avio_close(hls->pb);
return 0;
}
@@ -326,12 +402,16 @@ static int hls_write_trailer(struct AVFormatContext *s)
#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_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"},
+
{ NULL },
};
diff --git a/libavformat/hlsproto.c b/libavformat/hlsproto.c
index 751fef2..a569e92 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
*/
@@ -126,7 +126,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 54ac6c2..1320fa5 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 f82002c..dfc01ee 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 {
/* 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,9 @@ typedef struct {
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)
int icy;
/* how much data was read since the last ICY metadata packet */
int icy_data_read;
@@ -97,14 +101,16 @@ typedef struct {
#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 },
@@ -212,8 +218,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 +226,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 +235,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 +249,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)
@@ -270,13 +274,33 @@ int ff_http_do_new_request(URLContext *h, const char *uri)
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_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);
@@ -349,7 +373,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 +403,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 +436,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;
}
@@ -460,7 +484,7 @@ static int process_line(URLContext *h, char *line, int line_count,
p++;
s->http_code = strtol(p, &end, 10);
- av_dlog(NULL, "http_code=%d\n", s->http_code);
+ av_log(h, AV_LOG_DEBUG, "http_code=%d\n", s->http_code);
if ((ret = check_http_code(h, s->http_code, end)) < 0)
return ret;
@@ -484,7 +508,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 +524,29 @@ 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 (!s->cookies) {
+ if (!(s->cookies = av_strdup(p)))
+ return AVERROR(ENOMEM);
+ } else {
+ char *tmp = s->cookies;
+ size_t str_size = strlen(tmp) + strlen(p) + 2;
+ if (!(s->cookies = av_malloc(str_size))) {
+ s->cookies = tmp;
+ return AVERROR(ENOMEM);
+ }
+ snprintf(s->cookies, str_size, "%s\n%s", tmp, p);
+ av_free(tmp);
+ }
} else if (!av_strcasecmp(tag, "Icy-MetaInt")) {
s->icy_metaint = strtoll(p, NULL, 10);
} else if (!av_strncasecmp(tag, "Icy-", 4)) {
@@ -515,6 +560,103 @@ 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);
+
+ *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;
+
+ 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_free(cdomain);
+ av_free(cpath);
+ av_free(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 +677,7 @@ static int http_read_header(URLContext *h, int *new_location)
if ((err = http_get_line(s, line, sizeof(line))) < 0)
return err;
- av_dlog(NULL, "header='%s'\n", line);
+ av_log(h, AV_LOG_DEBUG, "header='%s'\n", line);
err = process_line(h, line, s->line_count, new_location);
if (err < 0)
@@ -545,6 +687,9 @@ 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 */
+
return err;
}
@@ -602,7 +747,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 +779,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 +809,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 +833,20 @@ 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;
- 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)
@@ -767,7 +925,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 +937,6 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size)
if (!s->chunksize)
return 0;
- break;
- }
}
size = FFMIN(size, s->chunksize);
}
@@ -792,6 +947,8 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size)
return http_buf_read(h, buf, size);
}
+// 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,7 +1098,7 @@ 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;
}
@@ -963,16 +1120,21 @@ static int64_t http_seek(URLContext *h, int64_t off, int whence)
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) {
@@ -1044,7 +1206,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 +1221,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 +1280,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 3d301a7..7d02713 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 b96da3e..dbe3eff 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 99bf43f..fc17c94 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
*/
diff --git a/libavformat/icecast.c b/libavformat/icecast.c
index 155396f..973c0c2 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);
@@ -129,6 +117,9 @@ static int icecast_open(URLContext *h, const char *uri, int flags)
av_dict_set(&opt_dict, "chunked_post", "0", 0);
if (NOT_EMPTY(s->content_type))
av_dict_set(&opt_dict, "content_type", s->content_type, 0);
+ else
+ av_dict_set(&opt_dict, "content_type", "audio/mpeg", 0);
+ av_dict_set(&opt_dict, "send_expect_100", s->legacy_icecast ? "0" : "1", 0);
if (NOT_EMPTY(s->user_agent))
av_dict_set(&opt_dict, "user_agent", s->user_agent, 0);
@@ -138,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++;
@@ -176,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 0000000..847f0ee
--- /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 0000000..53d4420
--- /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 87930ff..0617a9c 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",
@@ -202,7 +203,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 +215,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 7107073..d5dca35 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 e5f7486..cbf4375 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"
@@ -46,8 +59,9 @@ const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
};
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 +72,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,6 +170,48 @@ 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) < len)
+ return -1;
+ else if (!AV_RB32(tag) || is_tag(tag, len))
+ return 1;
+
+ return 0;
+}
+
/**
* Free GEOB type extra metadata.
*/
@@ -258,7 +315,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,14 +350,14 @@ 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);
}
/**
* Parse GEOB tag into a ID3v2ExtraMetaGEOB struct.
*/
static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen,
- char *tag, ID3v2ExtraMeta **extra_meta)
+ char *tag, ID3v2ExtraMeta **extra_meta, int isv34)
{
ID3v2ExtraMetaGEOB *geob_data = NULL;
ID3v2ExtraMeta *new_extra = NULL;
@@ -312,14 +369,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;
}
@@ -432,7 +489,7 @@ static void free_apic(void *obj)
}
static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen,
- char *tag, ID3v2ExtraMeta **extra_meta)
+ char *tag, ID3v2ExtraMeta **extra_meta, int isv34)
{
int enc, pic_type;
char mimetype[64];
@@ -454,7 +511,12 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen,
taglen--;
/* mimetype */
+ if (isv34) {
taglen -= avio_get_str(pb, taglen, mimetype, sizeof(mimetype));
+ } else {
+ avio_read(pb, mimetype, 3);
+ mimetype[3] = 0;
+ }
while (mime->id != AV_CODEC_ID_NONE) {
if (!av_strncasecmp(mime->str, mimetype, sizeof(mimetype))) {
id = mime->id;
@@ -487,7 +549,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);
@@ -505,17 +567,119 @@ fail:
avio_seek(pb, end, SEEK_SET);
}
+static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, 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,
+ 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;
void (*read)(AVFormatContext *, AVIOContext *, int, char *,
- ID3v2ExtraMeta **);
+ ID3v2ExtraMeta **, int isv34);
void (*free)(void *obj);
} 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 }
};
@@ -528,7 +692,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)))
@@ -538,19 +702,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:
@@ -576,7 +746,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;
@@ -585,35 +755,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])
@@ -623,57 +821,107 @@ 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' ||
(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
/* parse special meta tag */
- extra_func->read(s, pbx, tlen, tag, extra_meta);
+ 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 */
@@ -684,25 +932,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 */
@@ -710,15 +971,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)
@@ -733,6 +1006,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 7cb4296..9d7bf1c 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 89181c2..8b804c4 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 3aa0e3e..d7a46a1 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;
}
}
@@ -303,6 +307,8 @@ static int idcin_read_packet(AVFormatContext *s,
}
/* skip the number of decoded bytes (always equal to width * height) */
avio_skip(pb, 4);
+ if (chunk_size < 4)
+ return AVERROR_INVALIDDATA;
chunk_size -= 4;
ret= av_get_packet(pb, pkt, chunk_size);
if (ret < 0)
diff --git a/libavformat/idroqdec.c b/libavformat/idroqdec.c
index 82eff24..76bb392 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 2ce4d7d..28a3aba 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 6be0fb7..e7c240c 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 {
- 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 e44af48..3f154ce 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 847c613..d6f1244 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_SUNRAST, "sun" },
{ AV_CODEC_ID_SUNRAST, "ras" },
@@ -64,6 +64,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" },
@@ -72,8 +73,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 0000000..58a6833
--- /dev/null
+++ b/libavformat/img2.h
@@ -0,0 +1,63 @@
+/*
+ * 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
+
+typedef struct {
+ 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;
+ enum { PT_GLOB_SEQUENCE, PT_GLOB, PT_SEQUENCE } pattern_type;
+ 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 0000000..c2650ad
--- /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 0000000..ae6b3dd
--- /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 f7f0a11..a20868c 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 {
- 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, last_index;
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,92 @@ 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) {
+ char *p = s->path, *q, *dup;
+ int gerr;
+
+ 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) {
+ 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 = 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 +301,52 @@ 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;
+ }
+ }
+ 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 +355,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 +372,16 @@ 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->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 +393,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,11 +441,33 @@ 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]);
if (ret[i] > 0)
@@ -281,22 +477,72 @@ 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)
+{
+ VideoDemuxData *s = s1->priv_data;
+#if HAVE_GLOB
+ 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" },
+
+ { "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 }, 0, 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 +550,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 +558,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 +570,214 @@ 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;
+ } else {
+ return AVPROBE_SCORE_EXTENSION / 4;
+ }
+ return 0;
+}
+
+static int dpx_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+
+ if (AV_RN32(b) == AV_RN32("SDPX") || 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;
+
+ if (AV_RB16(b) != 0xFFD8 ||
+ AV_RB32(b) == 0xFFD8FFF7)
+ return 0;
+
+ b += 2;
+ for (i = 0; i < 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 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(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 13e6828..2b8b2d0 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 {
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,74 +56,111 @@ 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);
+ 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_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;
- }
+ if (desc->nb_components > 3) {
+ avio_write(pb[3], pkt->data + ysize + 2*usize, ysize);
+ avio_close(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]);
@@ -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 42b29ef..94c549c 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 d579db5..f7a79dd 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
*/
@@ -26,6 +26,10 @@
#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
@@ -48,9 +52,9 @@ struct AVFormatInternal {
* Muxing only.
*/
int nb_interleaved_streams;
-};
-void ff_dynarray_add(intptr_t **tab_ptr, int *nb_ptr, intptr_t elem);
+ int inject_global_side_data;
+};
#ifdef __GNUC__
#define dynarray_add(tab, nb_ptr, elem)\
@@ -58,12 +62,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
@@ -86,6 +90,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 *));
@@ -129,10 +134,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_write_interleaved_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.
@@ -251,6 +257,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().
*
@@ -320,6 +329,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.
*/
@@ -346,6 +357,15 @@ 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);
+
+/**
* Generate standard extradata for AVC-Intra based on width/height and field
* order.
*/
@@ -358,11 +378,61 @@ 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;
}
+/**
+ * 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);
+
#endif /* AVFORMAT_INTERNAL_H */
diff --git a/libavformat/ipmovie.c b/libavformat/ipmovie.c
index 60ae939..01e70e8 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_dlog(NULL, "create timer\n");
- if ((opcode_version > 0) || (opcode_size > 6)) {
+ if ((opcode_version > 0) || (opcode_size != 6)) {
av_dlog(NULL, "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_dlog(NULL, "initialize audio buffers\n");
- if ((opcode_version > 1) || (opcode_size > 10)) {
+ if (opcode_version > 1 || opcode_size > 10 || opcode_size < 6) {
av_dlog(NULL, "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_dlog(NULL, "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_dlog(NULL, "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_dlog(NULL, "set palette\n");
/* check for the logical maximum palette size
* (3 * 256 + 4 bytes) */
- if (opcode_size > 0x304) {
- av_dlog(NULL, "demux_ipmovie: set_palette opcode too large\n");
+ if (opcode_size > 0x304 || opcode_size < 4) {
+ av_dlog(NULL, "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_dlog(NULL, "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 0000000..a267c18
--- /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 0000000..f7f9c84
--- /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 0000000..f9533ec
--- /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 0000000..38f15fb
--- /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 5d10dca..1509021 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_VORBIS , 0xDD }, /* non standard, gpac uses it */
{ AV_CODEC_ID_DVD_SUBTITLE, 0xE0 }, /* non standard, see unsupported-embedded-subs-2.mp4 */
@@ -71,7 +72,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 */
@@ -95,9 +95,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) */
@@ -298,12 +306,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 },
};
@@ -431,14 +442,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_dlog(fc, "esds object type id 0x%02x\n", object_type_id);
len = ff_mp4_read_descr(fc, pb, &tag);
if (tag == MP4DecSpecificDescrTag) {
@@ -446,13 +466,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;
@@ -473,3 +490,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 0bc912a..52da1a3 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
*/
@@ -78,6 +78,7 @@ typedef struct MOVFragment {
unsigned duration;
unsigned size;
unsigned flags;
+ int64_t time;
} MOVFragment;
typedef struct MOVTrackExt {
@@ -93,8 +94,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;
@@ -109,14 +123,17 @@ typedef struct MOVStreamContext {
unsigned *stps_data; ///< partial sync sample for mpeg-2 open gop
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 empty_duration; ///< empty duration of the first edit list entry
+ int64_t start_time; ///< start time of the media
+ 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 +143,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,14 +151,20 @@ 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;
typedef struct MOVContext {
+ AVClass *avclass;
AVFormatContext *fc;
int time_scale;
int64_t duration; ///< duration of the longest track
@@ -154,7 +178,16 @@ typedef struct MOVContext {
unsigned trex_count;
int itunes_metadata; ///< metadata are itunes style
int chapter_track;
+ int use_absolute_path;
+ int ignore_editlist;
int64_t next_root_atom; ///< offset of the next root atom
+ 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;
} MOVContext;
int ff_mp4_read_descr_len(AVIOContext *pb);
@@ -219,5 +252,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 3f7f4fe..e994531 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 56909e3..38b7960 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 b3555f4..c0fdafb 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 3cd1616..5700f01 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,8 +30,9 @@ 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);
diff --git a/libavformat/jacosubdec.c b/libavformat/jacosubdec.c
new file mode 100644
index 0000000..9a28870
--- /dev/null
+++ b/libavformat/jacosubdec.c
@@ -0,0 +1,271 @@
+/*
+ * 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)
+ return ret;
+
+ /* 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;
+}
+
+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 0000000..a11e45a
--- /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 84d55da..21eb14d 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 {
- 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 {
@@ -54,8 +54,8 @@ typedef struct {
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 e5e2f87..cb79e84 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 {
AVClass *av_class;
@@ -33,6 +36,7 @@ typedef struct {
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 6f11d60..e90aef7 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 0000000..276477b
--- /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 0000000..158a630
--- /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 0000000..4a9a21a
--- /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 0000000..0a593cc
--- /dev/null
+++ b/libavformat/libquvi.c
@@ -0,0 +1,150 @@
+/*
+ * 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 ((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 74e2c49..67939b9 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
*/
@@ -169,7 +169,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags)
}
if (ctx->swfurl) {
av_strlcat(filename, " swfUrl=", len);
- av_strlcat(filename, ctx->pageurl, len);
+ av_strlcat(filename, ctx->swfurl, len);
}
if (ctx->flashver) {
av_strlcat(filename, " flashVer=", len);
@@ -234,6 +234,9 @@ static int rtmp_open(URLContext *s, const char *uri, int flags)
return 0;
fail:
av_freep(&ctx->temp_filename);
+ if (rc)
+ RTMP_Close(r);
+
return rc;
}
diff --git a/libavformat/libsmbclient.c b/libavformat/libsmbclient.c
new file mode 100644
index 0000000..8290d75
--- /dev/null
+++ b/libavformat/libsmbclient.c
@@ -0,0 +1,212 @@
+/*
+ * 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 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;
+}
+
+#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,
+ .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 0000000..3ec60cb
--- /dev/null
+++ b/libavformat/libssh.c
@@ -0,0 +1,318 @@
+/*
+ * 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_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 = 22, 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);
+
+ if (port <= 0 || port > 65535)
+ port = 22;
+
+ 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 1fb03e7..899f449 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 0000000..c41809b
--- /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 0000000..139c650
--- /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 0000000..0297bc1
--- /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 0000000..df61853
--- /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 0000000..b316ccd
--- /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 0000000..81aec59
--- /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 192d4b0..11d6da5 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
*/
@@ -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);
@@ -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 4a0af3c..d8ee530 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 237f26f..bc5007a 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,14 +59,20 @@ 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},
{"V_DIRAC" , AV_CODEC_ID_DIRAC},
@@ -80,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},
@@ -96,6 +107,8 @@ const CodecMime ff_mkv_mime_tags[] = {
{"image/tiff" , AV_CODEC_ID_TIFF},
{"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}
};
@@ -106,6 +119,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 d8f4f8e..391c56c 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,16 +269,32 @@ 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 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 a83589a..3b45c3b 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
*/
@@ -40,11 +40,13 @@
#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/time_internal.h"
#include "libavcodec/bytestream.h"
#include "libavcodec/flac.h"
@@ -70,6 +72,7 @@ typedef enum {
EBML_NEST,
EBML_PASS,
EBML_STOP,
+ EBML_SINT,
EBML_TYPE_COUNT
} EbmlType;
@@ -111,9 +114,15 @@ typedef struct {
} MatroskaTrackCompression;
typedef struct {
+ uint64_t algo;
+ EbmlBin key_id;
+} MatroskaTrackEncryption;
+
+typedef struct {
uint64_t scope;
uint64_t type;
MatroskaTrackCompression compression;
+ MatroskaTrackEncryption encryption;
} MatroskaTrackEncoding;
typedef struct {
@@ -122,8 +131,9 @@ typedef struct {
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 {
@@ -144,6 +154,15 @@ typedef struct {
} MatroskaTrackAudio;
typedef struct {
+ uint64_t uid;
+ uint64_t type;
+} MatroskaTrackPlane;
+
+typedef struct {
+ EbmlList combine_planes;
+} MatroskaTrackOperation;
+
+typedef struct {
uint64_t num;
uint64_t uid;
uint64_t type;
@@ -155,14 +174,17 @@ typedef struct {
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 {
@@ -241,6 +263,8 @@ typedef struct {
uint64_t time_scale;
double duration;
char *title;
+ char *muxingapp;
+ EbmlBin date_utc;
EbmlList tracks;
EbmlList attachments;
EbmlList chapters;
@@ -278,6 +302,9 @@ typedef struct {
int64_t reference;
uint64_t non_simple;
EbmlBin bin;
+ uint64_t additional_id;
+ EbmlBin additional;
+ int64_t discard_padding;
} MatroskaBlock;
static EbmlSyntax ebml_header[] = {
@@ -301,19 +328,20 @@ static EbmlSyntax matroska_info[] = {
{ 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[] = {
{ 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 },
@@ -339,10 +367,21 @@ static EbmlSyntax matroska_track_encoding_compression[] = {
{ 0 }
};
+static 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 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 }
};
@@ -352,6 +391,22 @@ static EbmlSyntax matroska_track_encodings[] = {
{ 0 }
};
+static EbmlSyntax matroska_track_plane[] = {
+ { MATROSKA_ID_TRACKPLANEUID, EBML_UINT, 0, offsetof(MatroskaTrackPlane,uid) },
+ { MATROSKA_ID_TRACKPLANETYPE, EBML_UINT, 0, offsetof(MatroskaTrackPlane,type) },
+ { 0 }
+};
+
+static EbmlSyntax matroska_track_combine_planes[] = {
+ { MATROSKA_ID_TRACKPLANE, EBML_NEST, sizeof(MatroskaTrackPlane), offsetof(MatroskaTrackOperation,combine_planes), {.n = matroska_track_plane} },
+ { 0 }
+};
+
+static EbmlSyntax matroska_track_operation[] = {
+ { MATROSKA_ID_TRACKCOMBINEPLANES, EBML_NEST, 0, 0, {.n = matroska_track_combine_planes} },
+ { 0 }
+};
+
static EbmlSyntax matroska_track[] = {
{ MATROSKA_ID_TRACKNUMBER, EBML_UINT, 0, offsetof(MatroskaTrack, num) },
{ MATROSKA_ID_TRACKNAME, EBML_UTF8, 0, offsetof(MatroskaTrack, name) },
@@ -360,14 +415,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,7 +434,6 @@ 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 }
};
@@ -434,6 +491,8 @@ static EbmlSyntax matroska_chapters[] = {
static 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 }
};
@@ -507,11 +566,24 @@ static EbmlSyntax matroska_segments[] = {
{ 0 }
};
+static EbmlSyntax matroska_blockmore[] = {
+ { MATROSKA_ID_BLOCKADDID, EBML_UINT, 0, offsetof(MatroskaBlock,additional_id) },
+ { MATROSKA_ID_BLOCKADDITIONAL, EBML_BIN, 0, offsetof(MatroskaBlock,additional) },
+ { 0 }
+};
+
+static EbmlSyntax matroska_blockadditions[] = {
+ { MATROSKA_ID_BLOCKMORE, EBML_NEST, 0, 0, {.n = matroska_blockmore} },
+ { 0 }
+};
+
static 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 }
@@ -583,7 +655,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 ||
@@ -636,7 +708,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 +772,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 +842,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);
}
@@ -897,16 +994,15 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska,
uint32_t id = syntax->id;
uint64_t length;
int res;
+ void *newelem;
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 +1024,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;
@@ -949,6 +1048,8 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska,
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)
@@ -1058,7 +1159,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 +1168,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;
@@ -1116,7 +1222,10 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size,
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);
+ if (pkt_data) {
+ result = inflate(&zstream, Z_NO_FLUSH);
+ } else
+ result = Z_MEM_ERROR;
} while (result == Z_OK && pkt_size < 10000000);
pkt_size = zstream.total_out;
inflateEnd(&zstream);
@@ -1148,7 +1257,10 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size,
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);
+ if (pkt_data) {
+ result = BZ2_bzDecompress(&bzstream);
+ } else
+ result = BZ_MEM_ERROR;
} while (result == BZ_OK && pkt_size < 10000000);
pkt_size = bzstream.total_out_lo32;
BZ2_bzDecompressEnd(&bzstream);
@@ -1175,63 +1287,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)
{
@@ -1375,27 +1430,21 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska)
continue;
}
- if (matroska_parse_seekhead_entry(matroska, i) < 0)
+ if (matroska_parse_seekhead_entry(matroska, i) < 0) {
+ // mark index as broken
+ matroska->cues_parsing_deferred = -1;
break;
+ }
}
}
-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;
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);
-
index_list = &matroska->index;
index = index_list->elem;
if (index_list->nb_elem &&
@@ -1418,6 +1467,21 @@ static void matroska_parse_cues(MatroskaDemuxContext *matroska)
}
}
+static void matroska_parse_cues(MatroskaDemuxContext *matroska) {
+ EbmlList *seekhead_list = &matroska->seekhead;
+ MatroskaSeekhead *seekhead = seekhead_list->elem;
+ int i;
+
+ for (i = 0; i < seekhead_list->nb_elem; i++)
+ if (seekhead[i].id == MATROSKA_ID_CUES)
+ break;
+ av_assert1(i <= seekhead_list->nb_elem);
+
+ if (matroska_parse_seekhead_entry(matroska, i) < 0)
+ matroska->cues_parsing_deferred = -1;
+ matroska_add_index_entries(matroska);
+}
+
static int matroska_aac_profile(char *codec_id)
{
static const char *const aac_profiles[] = { "MAIN", "LC", "SSR" };
@@ -1439,6 +1503,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 +1575,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 +1585,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 +1606,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 +1620,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 +1647,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 +1677,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 &&
@@ -1602,12 +1712,26 @@ static int matroska_parse_tracks(AVFormatContext *s)
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;
} else if (codec_id == AV_CODEC_ID_PCM_S16BE) {
switch (track->audio.bitdepth) {
case 8:
@@ -1651,7 +1775,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. */
@@ -1667,7 +1791,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,
@@ -1676,9 +1800,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 ||
@@ -1687,11 +1814,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);
@@ -1702,20 +1831,22 @@ 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) {
st->codec->block_align = track->audio.coded_framesize;
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];
}
@@ -1726,6 +1857,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;
@@ -1744,7 +1877,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);
@@ -1759,11 +1892,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);
@@ -1771,8 +1901,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,
@@ -1780,12 +1914,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 * 1000L
+ && st->avg_frame_rate.num > st->avg_frame_rate.den * 5L)
+ 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) {
+ av_dict_set(&s->streams[k]->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 &&
@@ -1798,11 +1960,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;
}
}
@@ -1829,13 +2014,19 @@ static int matroska_read_header(AVFormatContext *s)
ebml.version > EBML_VERSION ||
ebml.max_size > sizeof(uint64_t) ||
ebml.id_length > sizeof(uint32_t) ||
- ebml.doctype_version > 3) {
+ ebml.doctype_version > 3 ||
+ !ebml.doctype) {
av_log(matroska->ctx, AV_LOG_ERROR,
"EBML header using unsupported features\n"
"(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n",
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]))
@@ -1868,6 +2059,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)
@@ -1886,10 +2081,8 @@ static int matroska_read_header(AVFormatContext *s)
av_dict_set(&st->metadata, "mimetype", attachments[j].mime, 0);
st->codec->codec_id = AV_CODEC_ID_NONE;
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);
@@ -1913,11 +2106,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;
@@ -1988,7 +2185,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;
@@ -2003,18 +2200,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;
@@ -2039,10 +2236,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;
@@ -2052,10 +2249,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;
@@ -2082,7 +2279,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;
@@ -2112,7 +2309,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;
@@ -2236,18 +2433,134 @@ 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));
+ 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;
@@ -2266,18 +2579,19 @@ 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));
/* 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'));
@@ -2286,35 +2600,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:
@@ -2326,7 +2676,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;
@@ -2335,7 +2686,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");
@@ -2354,8 +2706,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;
@@ -2375,9 +2728,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,
@@ -2386,22 +2744,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 ||
@@ -2409,20 +2774,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:
@@ -2470,18 +2846,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;
}
@@ -2502,15 +2881,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;
@@ -2519,47 +2897,41 @@ 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);
- }
-
- if (ret == AVERROR_INVALIDDATA && pkt->data) {
- pkt->flags |= AV_PKT_FLAG_CORRUPT;
- return 0;
+ matroska_resync(matroska, pos);
}
- return ret;
+ return 0;
}
static int matroska_read_seek(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
MatroskaDemuxContext *matroska = s->priv_data;
- MatroskaTrack *tracks = matroska->tracks.elem;
+ MatroskaTrack *tracks = NULL;
AVStream *st = s->streams[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;
@@ -2567,10 +2939,11 @@ 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;
for (i = 0; i < matroska->tracks.nb_elem; i++) {
tracks[i].audio.pkt_cnt = 0;
tracks[i].audio.sub_packet_cnt = 0;
@@ -2581,21 +2954,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)
@@ -2615,6 +3005,355 @@ static int matroska_read_close(AVFormatContext *s)
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(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;
+ }
+
+ // 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);
+
+ // duration
+ buf = av_asprintf("%g", matroska->duration);
+ if (!buf) return AVERROR(ENOMEM);
+ av_dict_set(&s->streams[0]->metadata, DURATION, buf, 0);
+ av_free(buf);
+
+ // 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 webm_dash_manifest_cues(s);
+}
+
+static int webm_dash_manifest_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ return AVERROR_EOF;
+}
+
AVInputFormat ff_matroska_demuxer = {
.name = "matroska,webm",
.long_name = NULL_IF_CONFIG_SMALL("Matroska / WebM"),
@@ -2627,3 +3366,12 @@ 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,
+};
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 4ec474d..e8e8da0 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 {
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 {
@@ -81,6 +88,7 @@ typedef struct {
typedef struct {
int write_dts;
+ int has_cue;
int64_t ts_offset;
} mkv_track;
@@ -110,6 +118,10 @@ typedef struct MatroskaMuxContext {
int cluster_size_limit;
int64_t cues_pos;
int64_t cluster_time_limit;
+ int is_dash;
+ int dash_track_number;
+
+ uint32_t chapter_id_offset;
int wrote_chapters;
} MatroskaMuxContext;
@@ -118,13 +130,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 +149,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 +159,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 +186,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 +210,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 +257,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 +267,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 +291,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 +329,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 +393,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 +409,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 +446,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;
@@ -490,7 +540,7 @@ 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;
@@ -565,8 +615,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;
@@ -591,30 +644,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;
+ 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);
@@ -625,19 +694,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);
@@ -660,13 +738,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;
@@ -677,13 +755,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;
@@ -691,40 +769,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);
-
- // 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);
- }
+ put_ebml_uint(pb, MATROSKA_ID_VIDEOSTEREOMODE, format);
- 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;
@@ -734,6 +804,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;
@@ -745,62 +817,99 @@ 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)
get_aac_sample_rates(s, codec, &sample_rate, &output_sample_rate);
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 (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 (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_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) &&
@@ -825,10 +934,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;
@@ -850,19 +987,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);
@@ -874,7 +1018,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)
@@ -882,7 +1026,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;
}
@@ -914,7 +1062,7 @@ static int mkv_write_chapters(AVFormatContext *s)
AVDictionaryEntry *t = NULL;
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,
av_rescale_q(c->start, c->time_base, scale));
put_ebml_uint(pb, MATROSKA_ID_CHAPTERTIMEEND,
@@ -989,6 +1137,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"))
mkv_write_simpletag(s->pb, t);
@@ -996,14 +1145,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;
}
@@ -1011,7 +1172,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);
@@ -1021,10 +1182,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;
}
@@ -1056,6 +1217,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;
@@ -1085,9 +1247,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);
@@ -1101,14 +1279,40 @@ 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;
+
+ 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);
@@ -1118,7 +1322,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);
@@ -1156,6 +1360,18 @@ 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
@@ -1168,6 +1384,9 @@ static int mkv_write_header(AVFormatContext *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)
@@ -1196,6 +1415,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);
@@ -1227,68 +1447,6 @@ static int mkv_blockgroup_size(int pkt_size)
return size;
}
-static int ass_get_duration(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;
- start = 3600000 * sh + 60000 * sm + 1000 * ss + 10 * sc;
- end = 3600000 * eh + 60000 * em + 1000 * es + 10 * ec;
- 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(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;
@@ -1347,9 +1505,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",
@@ -1377,56 +1538,95 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb,
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)
@@ -1444,7 +1644,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;
@@ -1453,6 +1675,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");
@@ -1460,42 +1684,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);
@@ -1509,8 +1750,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;
@@ -1521,32 +1762,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);
+ cluster_size = avio_tell(mkv->dyn_bc);
}
- 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);
+ 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,
@@ -1564,8 +1813,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;
}
@@ -1578,12 +1830,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);
@@ -1602,7 +1854,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,
@@ -1614,7 +1866,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);
}
@@ -1632,7 +1884,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,
@@ -1648,7 +1900,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,
@@ -1669,7 +1921,7 @@ static int mkv_write_trailer(AVFormatContext *s)
}
end_ebml_master(pb, mkv->segment);
- av_free(mkv->tracks);
+ av_freep(&mkv->tracks);
av_freep(&mkv->cues->entries);
av_freep(&mkv->cues);
@@ -1693,12 +1945,39 @@ 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 }
+};
+
#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 },
{ NULL },
};
@@ -1726,9 +2005,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, 0
},
- .subtitle_codec = AV_CODEC_ID_SSA,
+ .subtitle_codec = AV_CODEC_ID_ASS,
.query_codec = mkv_query_codec,
.priv_class = &matroska_class,
};
@@ -1750,6 +2030,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,
@@ -1768,7 +2049,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),
@@ -1780,7 +2061,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 9249704..8e87f09 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 12ddde3..6af0a6e 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 77fb298..b9b6de7 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 eee3ee4..6586094 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 0000000..8cbc952
--- /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 0000000..ce3433c
--- /dev/null
+++ b/libavformat/microdvddec.c
@@ -0,0 +1,203 @@
+/*
+ * 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;
+ }
+ 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 0000000..4d84384
--- /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 0000000..7ba6691
--- /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 0000000..17bdb17
--- /dev/null
+++ b/libavformat/mlvdec.c
@@ -0,0 +1,463 @@
+/*
+ * 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 "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);
+ 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;
+ 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);
+ if (mlv->class[0]) {
+ vst = avformat_new_stream(avctx, NULL);
+ if (!vst)
+ return AVERROR(ENOMEM);
+ vst->id = 0;
+ 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");
+ }
+ }
+
+ mlv->class[1] = avio_rl16(pb);
+ if (mlv->class[1]) {
+ ast = avformat_new_stream(avctx, NULL);
+ if (!ast)
+ return AVERROR(ENOMEM);
+ ast->id = 1;
+ 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)
+ vst->nb_frames = avio_rl32(pb);
+ else
+ avio_skip(pb, 4);
+
+ if (ast)
+ ast->nb_frames = avio_rl32(pb);
+ else
+ avio_skip(pb, 4);
+
+ 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);
+ if (!filename)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < 100; i++) {
+ snprintf(filename + strlen(filename) - 2, 3, "%02d", i);
+ if (avio_open2(&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_close(mlv->pb[i]);
+ mlv->pb[i] = NULL;
+ 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_close(mlv->pb[i]);
+ mlv->pb[i] = NULL;
+ 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_close(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 8c9cbd7..4315802 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 61f1d7a..e963112 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 {
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 fb16a3c..7e60b3b 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 e89da41..57e3d7e 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 5e9d0bc..dac5d9f 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 {
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 4f896e0..c851187 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);
}
diff --git a/libavformat/mov.c b/libavformat/mov.c
index c22df1e..6ba7b96 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
*/
@@ -31,12 +31,15 @@
#include "libavutil/attributes.h"
#include "libavutil/channel_layout.h"
+#include "libavutil/display.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/intfloat.h"
#include "libavutil/mathematics.h"
#include "libavutil/time_internal.h"
#include "libavutil/avstring.h"
#include "libavutil/dict.h"
+#include "libavutil/opt.h"
+#include "libavutil/timecode.h"
#include "libavcodec/ac3tab.h"
#include "avformat.h"
#include "internal.h"
@@ -66,6 +69,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)
@@ -90,16 +94,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;
}
@@ -107,11 +108,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;
}
@@ -120,16 +118,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;
}
@@ -164,7 +160,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;
@@ -213,6 +209,17 @@ static int mov_read_covr(MOVContext *c, AVIOContext *pb, int type, int len)
return 0;
}
+static int mov_metadata_raw(MOVContext *c, AVIOContext *pb,
+ unsigned len, const char *key)
+{
+ char *value = av_malloc(len + 1);
+ if (!value)
+ return AVERROR(ENOMEM);
+ avio_read(pb, value, len);
+ value[len] = 0;
+ return av_dict_set(&c->fc->metadata, key, value, AV_DICT_DONT_STRDUP_VAL);
+}
+
static int mov_metadata_loci(MOVContext *c, AVIOContext *pb, unsigned len)
{
char language[4] = { 0 };
@@ -256,10 +263,11 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
#ifdef MOV_EXPORT_ALL_METADATA
char tmp_key[5];
#endif
- char str[1024], key2[16], language[4] = {0};
+ char key2[16], language[4] = {0};
+ char *str = NULL;
const char *key = NULL;
uint16_t langcode = 0;
- uint32_t data_type = 0, str_size;
+ uint32_t data_type = 0, str_size, str_size_alloc;
int (*parse)(MOVContext*, AVIOContext*, unsigned, const char*) = NULL;
switch (atom.type) {
@@ -268,8 +276,12 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
case MKTAG(0xa9,'A','R','T'): key = "artist"; break;
case MKTAG( 'a','A','R','T'): key = "album_artist"; break;
case MKTAG(0xa9,'w','r','t'): key = "composer"; break;
+ case MKTAG( 'c','p','i','l'): key = "compilation";
+ parse = mov_metadata_int8_no_padding; break;
case MKTAG( 'c','p','r','t'):
case MKTAG(0xa9,'c','p','y'): key = "copyright"; break;
+ case MKTAG(0xa9,'g','r','p'): key = "grouping"; break;
+ case MKTAG(0xa9,'l','y','r'): key = "lyrics"; break;
case MKTAG(0xa9,'c','m','t'):
case MKTAG(0xa9,'i','n','f'): key = "comment"; break;
case MKTAG(0xa9,'a','l','b'): key = "album"; break;
@@ -280,6 +292,8 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
case MKTAG(0xa9,'t','o','o'):
case MKTAG(0xa9,'s','w','r'): key = "encoder"; break;
case MKTAG(0xa9,'e','n','c'): key = "encoder"; break;
+ case MKTAG(0xa9,'m','a','k'): key = "make"; break;
+ case MKTAG(0xa9,'m','o','d'): key = "model"; break;
case MKTAG(0xa9,'x','y','z'): key = "location"; break;
case MKTAG( 'd','e','s','c'): key = "description";break;
case MKTAG( 'l','d','e','s'): key = "synopsis"; break;
@@ -300,8 +314,14 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
parse = mov_metadata_int8_no_padding; break;
case MKTAG( 'p','g','a','p'): key = "gapless_playback";
parse = mov_metadata_int8_no_padding; break;
+ case MKTAG( '@','P','R','M'):
+ return mov_metadata_raw(c, pb, atom.size, "premiere_version");
+ case MKTAG( '@','P','R','Q'):
+ return mov_metadata_raw(c, pb, atom.size, "quicktime_version");
case MKTAG( 'l','o','c','i'):
return mov_metadata_loci(c, pb, atom.size);
+ case MKTAG( 'X','M','P','_'):
+ return mov_metadata_raw(c, pb, atom.size, "xmp");
}
if (c->itunes_metadata && atom.size > 8) {
@@ -317,8 +337,8 @@ 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) {
@@ -341,15 +361,22 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (atom.size < 0)
return AVERROR_INVALIDDATA;
- str_size = FFMIN3(sizeof(str)-1, str_size, atom.size);
+ str_size_alloc = str_size << 1; // worst-case requirement for output string in case of utf8 coded input
+ str = av_malloc(str_size_alloc);
+ if (!str)
+ return AVERROR(ENOMEM);
if (parse)
parse(c, pb, str_size, key);
else {
if (data_type == 3 || (data_type == 0 && (langcode < 0x400 || langcode == 0x7fff))) { // MAC Encoded
- mov_read_mac_string(c, pb, str_size, str, sizeof(str));
+ 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;
@@ -361,7 +388,9 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
}
av_dlog(c->fc, "lang \"%3s\" ", language);
av_dlog(c->fc, "tag \"%s\" value \"%s\" atom \"%.4s\" %d %"PRId64"\n",
- key, str, (char*)&atom.type, str_size, atom.size);
+ key, str, (char*)&atom.type, str_size_alloc, atom.size);
+
+ av_freep(&str);
return 0;
}
@@ -416,6 +445,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);
@@ -465,7 +495,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);
@@ -492,7 +522,8 @@ 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)
+ return AVERROR_INVALIDDATA;
dref->dir[len] = 0;
for (j = 0; j < len; j++)
if (dref->dir[j] == ':')
@@ -512,6 +543,8 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom)
AVStream *st;
uint32_t type;
uint32_t av_unused ctype;
+ int title_size;
+ char *title_str;
if (c->fc->nb_streams < 1) // meta before first trak
return 0;
@@ -541,6 +574,19 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avio_rb32(pb); /* component flags */
avio_rb32(pb); /* component flags mask */
+ title_size = atom.size - 24;
+ if (title_size > 0) {
+ title_str = av_malloc(title_size + 1); /* Add null terminator */
+ if (!title_str)
+ return AVERROR(ENOMEM);
+ avio_read(pb, title_str, title_size);
+ title_str[title_size] = 0;
+ if (title_str[0])
+ av_dict_set(&st->metadata, "handler_name", title_str +
+ (!c->isom && title_str[0] == title_size - 1), 0);
+ av_freep(&title_str);
+ }
+
return 0;
}
@@ -634,6 +680,9 @@ static int mov_read_chan(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (atom.size < 16)
return 0;
+ /* skip version and flags */
+ avio_skip(pb, 4);
+
ff_mov_read_chan(c->fc, pb, st, atom.size - 4);
return 0;
@@ -647,7 +696,9 @@ static int mov_read_wfex(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
st = c->fc->streams[c->fc->nb_streams-1];
- ff_get_wav_header(pb, st->codec, atom.size);
+ if (ff_get_wav_header(pb, st->codec, atom.size) < 0) {
+ av_log(c->fc, AV_LOG_WARNING, "get_wav_header failed\n");
+ }
return 0;
}
@@ -689,7 +740,6 @@ 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};
@@ -699,8 +749,7 @@ static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
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)
@@ -721,6 +770,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' */
@@ -731,18 +786,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_dlog(c->fc, "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);
@@ -756,7 +829,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;
@@ -796,7 +869,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 */
@@ -813,6 +886,10 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
av_dlog(c->fc, "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 */
@@ -828,31 +905,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_dlog(c->fc, "Reading SMI %"PRId64" %s\n", atom.size, st->codec->extradata + 0x5a);
return 0;
}
@@ -865,7 +917,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_dlog(c->fc, "enda %d\n", little_endian);
if (little_endian == 1) {
switch (st->codec->codec_id) {
@@ -910,12 +962,12 @@ static int mov_read_colr(MOVContext *c, AVIOContext *pb, MOVAtom atom)
color_trc = avio_rb16(pb);
color_matrix = avio_rb16(pb);
- av_dlog(c->fc, "%s: pri %"PRIu16" trc %"PRIu16" matrix %"PRIu16"",
+ av_dlog(c->fc, "%s: pri %d trc %d matrix %d",
color_parameter_type, color_primaries, color_trc, color_matrix);
if (c->isom) {
uint8_t color_range = avio_r8(pb) >> 7;
- av_dlog(c->fc, " full %"PRIu8"", color_range)
+ av_dlog(c->fc, " full %"PRIu8"", color_range);
if (color_range)
st->codec->color_range = AVCOL_RANGE_JPEG;
else
@@ -952,7 +1004,7 @@ static int mov_read_colr(MOVContext *c, AVIOContext *pb, MOVAtom atom)
case 7: st->codec->colorspace = AVCOL_SPC_SMPTE240M; break;
}
}
- av_dlog(c->fc, "\n")
+ av_dlog(c->fc, "\n");
return 0;
}
@@ -992,7 +1044,8 @@ static int mov_read_fiel(MOVContext *c, AVIOContext *pb, MOVAtom atom)
}
/* 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;
@@ -1002,6 +1055,10 @@ static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (c->fc->nb_streams < 1) // will happen with jp2 files
return 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 */
+
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;
@@ -1013,10 +1070,78 @@ static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom)
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);
+ err = avio_read(pb, buf + 8, atom.size);
+ if (err < 0) {
+ return err;
+ } else if (err < atom.size) {
+ av_log(c->fc, AV_LOG_WARNING, "truncated extradata\n");
+ st->codec->extradata_size -= atom.size - err;
+ }
+ memset(buf + 8 + err, 0, FF_INPUT_BUFFER_PADDING_SIZE);
return 0;
}
+/* 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_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]);
+ }
+ }
+ 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_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)
{
AVStream *st;
@@ -1028,14 +1153,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)
+ 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)
@@ -1069,12 +1193,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);
}
+ if (st->codec->extradata_size > 1 && st->codec->extradata) {
+ av_log(c, AV_LOG_WARNING, "ignoring multiple glbl\n");
+ return 0;
+ }
av_free(st->codec->extradata);
- st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!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;
}
@@ -1082,6 +1208,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;
@@ -1094,13 +1221,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_free(st->codec->extradata);
+ if ((ret = ff_get_extradata(st->codec, pb, atom.size - 7)) < 0)
+ return ret;
+
return 0;
}
@@ -1122,13 +1247,10 @@ static int mov_read_strf(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if ((uint64_t)atom.size > (1<<30))
return AVERROR_INVALIDDATA;
+ avio_skip(pb, 40);
av_free(st->codec->extradata);
- st->codec->extradata = av_mallocz(atom.size - 40 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_get_extradata(st->codec, pb, atom.size - 40) < 0)
return AVERROR(ENOMEM);
- st->codec->extradata_size = atom.size - 40;
- avio_skip(pb, 40);
- avio_read(pb, st->codec->extradata, atom.size - 40);
return 0;
}
@@ -1208,7 +1330,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;
@@ -1253,8 +1377,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))
@@ -1267,12 +1394,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;
@@ -1283,7 +1413,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;
@@ -1303,7 +1433,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 */
@@ -1312,10 +1442,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);
@@ -1323,7 +1452,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);
}
}
}
@@ -1336,6 +1465,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 */
@@ -1351,7 +1481,9 @@ static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb,
// Read QT version 1 fields. In version 0 these do not exist.
av_dlog(c->fc, "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 */
@@ -1388,6 +1520,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:
@@ -1487,11 +1623,38 @@ static int mov_parse_stsd_data(MOVContext *c, AVIOContext *pb,
int 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 (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;
+ 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);
@@ -1526,6 +1689,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;
@@ -1546,6 +1713,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:
@@ -1554,6 +1724,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;
@@ -1565,17 +1738,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. */
@@ -1584,6 +1754,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;
}
@@ -1607,15 +1782,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;
}
@@ -1628,7 +1803,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
id = mov_codec_id(st, format);
- av_dlog(c->fc, "size=%"PRIu32" 4CC= %"PRIu8"%"PRIu8"%"PRIu8"%"PRIu8" codec_type=%d\n", size,
+ av_dlog(c->fc, "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);
@@ -1768,6 +1943,8 @@ 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 (entries >= UINT_MAX / sizeof(int))
@@ -1809,6 +1986,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;
@@ -1886,10 +2064,8 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
av_dlog(c->fc, "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);
+ return -1;
av_free(sc->stts_data);
sc->stts_data = av_malloc(entries * sizeof(*sc->stts_data));
@@ -1902,6 +2078,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;
@@ -1912,12 +2095,21 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
av_dlog(c->fc, "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;
@@ -1928,6 +2120,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;
@@ -1959,8 +2158,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_dlog(c->fc, "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;
@@ -2026,12 +2236,13 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
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);
+ if ((sc->empty_duration || sc->start_time) && mov->time_scale > 0) {
+ if (sc->empty_duration)
+ sc->empty_duration = av_rescale(sc->empty_duration, sc->time_scale, mov->time_scale);
+ sc->time_offset = sc->start_time - sc->empty_duration;
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) {
+ 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;
@@ -2049,11 +2260,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;
@@ -2066,10 +2277,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) {
@@ -2094,9 +2317,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++];
@@ -2108,6 +2336,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
av_dlog(mov->fc, "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;
@@ -2213,14 +2443,14 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
}
}
-static int mov_open_dref(AVIOContext **pb, char *src, MOVDref *ref,
- AVIOInterruptCB *int_cb)
+static int mov_open_dref(AVIOContext **pb, const char *src, MOVDref *ref,
+ AVIOInterruptCB *int_cb, int use_absolute_path, AVFormatContext *fc)
{
/* 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) {
char filename[1024];
- char *src_path;
+ const char *src_path;
int i, l;
/* find a source dir */
@@ -2252,11 +2482,26 @@ static int mov_open_dref(AVIOContext **pb, char *src, MOVDref *ref,
if (!avio_open2(pb, filename, AVIO_FLAG_READ, int_cb, NULL))
return 0;
}
+ } else if (use_absolute_path) {
+ av_log(fc, AV_LOG_WARNING, "Using absolute path on user request, "
+ "this is a possible security issue\n");
+ if (!avio_open2(pb, ref->path, AVIO_FLAG_READ, int_cb, NULL))
+ return 0;
}
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;
@@ -2284,12 +2529,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);
@@ -2297,14 +2537,17 @@ 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(&sc->pb, c->fc->filename, dref, &c->fc->interrupt_callback,
+ c->use_absolute_path, c->fc) < 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 &&
@@ -2312,6 +2555,12 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
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.
@@ -2358,11 +2607,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;
@@ -2396,9 +2652,18 @@ static int mov_read_replaygain(MOVContext *c, AVIOContext *pb, int size)
}
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);
@@ -2430,8 +2695,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:
@@ -2510,7 +2774,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) ||
@@ -2518,6 +2783,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);
@@ -2527,6 +2793,16 @@ 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[j][i];
+
+ 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
@@ -2557,6 +2833,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 */
@@ -2575,6 +2852,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 ?
@@ -2587,6 +2873,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_dlog(c->fc, "frag flags 0x%x\n", frag->flags);
return 0;
}
@@ -2609,6 +2914,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 */
@@ -2673,7 +2981,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);
@@ -2721,6 +3029,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;
@@ -2739,6 +3070,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)
@@ -2785,7 +3118,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 */
@@ -2824,9 +3157,10 @@ free_and_return:
static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
MOVStreamContext *sc;
- int i, edit_count, version;
+ int i, edit_count, version, edit_start_index = 0;
+ int unsupported = 0;
- 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;
@@ -2837,9 +3171,11 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if ((uint64_t)edit_count*12+8 > atom.size)
return AVERROR_INVALIDDATA;
+ av_dlog(c->fc, "track[%i].edit_count = %i\n", c->fc->nb_streams-1, edit_count);
for (i=0; i<edit_count; i++){
int64_t time;
int64_t duration;
+ int rate;
if (version == 1) {
duration = avio_rb64(pb);
time = avio_rb64(pb);
@@ -2847,22 +3183,131 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
duration = avio_rb32(pb); /* segment duration */
time = (int32_t)avio_rb32(pb); /* media time */
}
- avio_rb32(pb); /* Media rate */
- if (i == 0 && time >= -1) {
- sc->time_offset = time != -1 ? time : -duration;
- }
+ rate = avio_rb32(pb);
+ if (i == 0 && time == -1) {
+ sc->empty_duration = duration;
+ edit_start_index = 1;
+ } else if (i == edit_start_index && time >= 0)
+ sc->start_time = time;
+ else
+ unsupported = 1;
+
+ av_dlog(c->fc, "duration=%"PRId64" time=%"PRId64" rate=%f\n",
+ duration, time, rate / 65536.0);
}
- if (edit_count > 1)
+ if (unsupported)
av_log(c->fc, AV_LOG_WARNING, "multiple edit list entries, "
"a/v desync might occur, patch welcome\n");
- av_dlog(c->fc, "track[%i].edit_count = %i\n", c->fc->nb_streams-1, edit_count);
+ 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;
+ }
+
+ 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;
+}
+
+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;
+ }
+
return 0;
}
static const MOVParseTableEntry mov_default_parse_table[] = {
-{ MKTAG('a','v','s','s'), mov_read_extradata },
+{ MKTAG('A','C','L','R'), mov_read_avid },
+{ 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 },
@@ -2877,7 +3322,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 },
@@ -2887,8 +3332,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 },
@@ -2907,6 +3352,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 },
@@ -2922,6 +3368,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 }
};
@@ -2934,25 +3383,46 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
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;
+ avio_read(pb, buf, 8);
+ 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);
+ return 0;
+ }
+ }
+ total_size += 8;
+ if (a.size == 1) { /* 64 bit extended size */
+ a.size = avio_rb64(pb) - 8;
+ total_size += 8;
+ }
}
av_dlog(c->fc, "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)
@@ -3007,46 +3477,83 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
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',' ')) {
+ 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
@@ -3079,6 +3586,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;
@@ -3108,7 +3620,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);
}
}
@@ -3119,6 +3631,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;
@@ -3134,9 +3689,13 @@ static int mov_read_close(AVFormatContext *s)
av_freep(&sc->drefs[j].dir);
}
av_freep(&sc->drefs);
- if (sc->pb && sc->pb != s->pb)
+
+ sc->drefs_count = 0;
+
+ if (!sc->pb_is_copied)
avio_close(sc->pb);
+ sc->pb = NULL;
av_freep(&sc->chunk_offsets);
av_freep(&sc->stsc_data);
av_freep(&sc->sample_sizes);
@@ -3153,15 +3712,151 @@ 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, err;
+ int64_t pos = avio_tell(f);
+ uint32_t size = avio_rb32(f);
+ 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);
+ }
+ mov->fragment_index_count++;
+ if ((err = av_reallocp(&mov->fragment_index_data,
+ mov->fragment_index_count *
+ sizeof(MOVFragmentIndex*))) < 0) {
+ av_freep(&index);
+ return err;
+ }
+ mov->fragment_index_data[mov->fragment_index_count - 1] =
+ 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(
+ index->item_count * sizeof(MOVFragmentIndexItem));
+ if (!index->items) {
+ 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);
+ int32_t mfra_size;
+ int ret = -1;
+ if ((ret = avio_seek(f, stream_size - 4, SEEK_SET)) < 0) 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");
+ ret = -1;
+ goto fail;
+ }
+ if ((ret = avio_seek(f, -mfra_size, SEEK_CUR)) < 0) goto fail;
+ if (avio_rb32(f) != mfra_size) {
+ av_log(c->fc, AV_LOG_DEBUG, "doesn't look like mfra (size mismatch)\n");
+ ret = -1;
+ 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");
+ while (!read_tfra(c, f)) {
+ /* Empty */
+ }
+fail:
+ ret = avio_seek(f, original_pos, SEEK_SET);
+ if (ret < 0)
+ av_log(c->fc, AV_LOG_ERROR,
+ "failed to seek back after looking for mfra\n");
+ else
+ ret = 0;
+ 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;
@@ -3173,11 +3868,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);
@@ -3185,13 +3884,45 @@ static int mov_read_header(AVFormatContext *s)
}
av_dlog(mov->fc, "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;
@@ -3213,6 +3944,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;
@@ -3283,6 +4033,7 @@ 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) {
@@ -3292,7 +4043,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
avio_seek(s->pb, mov->next_root_atom, SEEK_SET);
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_dlog(s, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb));
goto retry;
@@ -3301,6 +4052,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",
@@ -3323,7 +4079,7 @@ 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);
+ avpriv_dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size, pkt->pos);
av_free(pkt->data);
pkt->size = 0;
ret = avpriv_dv_get_packet(mov->dv_demux, pkt);
@@ -3400,8 +4156,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);
@@ -3412,7 +4166,10 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
seek_timestamp = st->index_entries[sample].timestamp;
for (i = 0; i < s->nb_streams; i++) {
+ 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;
@@ -3422,6 +4179,34 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
return 0;
}
+static const AVOption options[] = {
+ {"use_absolute_path",
+ "allow using absolute path when opening alias, this is a possible security issue",
+ offsetof(MOVContext, use_absolute_path), FF_OPT_TYPE_INT, {.i64 = 0},
+ 0, 1, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_DECODING_PARAM},
+ {"ignore_editlist", "", offsetof(MOVContext, ignore_editlist), FF_OPT_TYPE_INT, {.i64 = 0},
+ 0, 1, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_DECODING_PARAM},
+ {"use_mfra_for",
+ "use mfra for fragment timestamps",
+ offsetof(MOVContext, use_mfra_for), FF_OPT_TYPE_INT, {.i64 = FF_MOV_FLAG_MFRA_AUTO},
+ -1, FF_MOV_FLAG_MFRA_PTS, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_DECODING_PARAM,
+ "use_mfra_for"},
+ {"auto", "auto", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_MFRA_AUTO}, 0, 0,
+ AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_DECODING_PARAM, "use_mfra_for" },
+ {"dts", "dts", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_MFRA_DTS}, 0, 0,
+ AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_DECODING_PARAM, "use_mfra_for" },
+ {"pts", "pts", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_MFRA_PTS}, 0, 0,
+ AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_DECODING_PARAM, "use_mfra_for" },
+ {NULL}
+};
+
+static const AVClass mov_class = {
+ .class_name = "mov,mp4,m4a,3gp,3g2,mj2",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVInputFormat ff_mov_demuxer = {
.name = "mov,mp4,m4a,3gp,3g2,mj2",
.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
@@ -3432,4 +4217,6 @@ AVInputFormat ff_mov_demuxer = {
.read_packet = mov_read_packet,
.read_close = mov_read_close,
.read_seek = mov_read_seek,
+ .priv_class = &mov_class,
+ .flags = AVFMT_NO_BYTE_SEEK,
};
diff --git a/libavformat/mov_chan.c b/libavformat/mov_chan.c
index aa7ba10..3b91ed7 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 {
@@ -570,6 +571,7 @@ int ff_mov_read_chan(AVFormatContext *s, AVIOContext *pb, AVStream *st,
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 +586,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 3fae939..ca28345 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 fa5fdad..8208e74 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,15 +31,19 @@
#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/opt.h"
#include "libavutil/dict.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/timecode.h"
#include "hevc.h"
#include "rtpenc.h"
#include "mov_chan.h"
@@ -50,6 +54,7 @@
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" },
@@ -60,13 +65,14 @@ static const AVOption options[] = {
{ "disable_chpl", "Disable Nero chapter atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DISABLE_CHPL}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "default_base_moof", "Set the default-base-is-moof flag in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DEFAULT_BASE_MOOF}, 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},
{ NULL },
@@ -80,6 +86,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;
@@ -116,13 +124,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
@@ -178,10 +188,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;
@@ -278,6 +288,212 @@ 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 */
+};
+
+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;
+}
+
+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).
@@ -288,6 +504,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;
@@ -297,10 +529,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");
@@ -333,12 +577,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
@@ -352,22 +594,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);
}
@@ -385,6 +647,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
@@ -403,9 +668,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 */
@@ -413,11 +680,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) {
@@ -577,13 +851,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;
@@ -606,9 +887,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 */
@@ -637,10 +926,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 ?
@@ -648,13 +948,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);
@@ -662,6 +977,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)
@@ -687,19 +1004,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);
@@ -728,7 +1032,11 @@ static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
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) */
+ 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 */
@@ -778,6 +1086,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');
@@ -809,8 +1118,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;
@@ -820,20 +1131,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;
}
@@ -841,11 +1152,141 @@ 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');
+ }
+ }
+ }
+
+ 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 },
@@ -866,15 +1307,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;
}
@@ -886,11 +1336,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
@@ -927,7 +1383,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') },
@@ -1021,9 +1477,36 @@ static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
return 16;
}
-static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
+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, MOVTrack *track)
+{
int64_t pos = avio_tell(pb);
char compressor_name[32] = { 0 };
@@ -1057,9 +1540,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);
@@ -1072,19 +1553,19 @@ 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)
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) {
@@ -1093,6 +1574,12 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *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 (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);
@@ -1121,9 +1608,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 */
@@ -1131,6 +1666,7 @@ 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);
}
@@ -1161,7 +1697,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 */
ctts_entries[0].count = 1;
ctts_entries[0].duration = track->cluster[0].cts;
for (i = 1; i < track->entry; i++) {
@@ -1202,7 +1738,7 @@ static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
entries = 1;
} else {
stts_entries = track->entry ?
- av_malloc(track->entry * sizeof(*stts_entries)) : /* worst case */
+ av_malloc_array(track->entry, sizeof(*stts_entries)) : /* worst case */
NULL;
for (i = 0; i < track->entry; i++) {
int duration = get_cluster_duration(track, i);
@@ -1237,6 +1773,7 @@ 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 */
@@ -1282,9 +1819,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 */
@@ -1295,7 +1855,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)
@@ -1341,16 +1930,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";
@@ -1419,14 +2011,14 @@ 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);
@@ -1486,6 +2078,24 @@ static int mov_write_mdia_tag(AVIOContext *pb, MOVMuxContext *mov,
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)
{
@@ -1493,6 +2103,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;
@@ -1541,16 +2152,19 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
avio_wb16(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 */
-
+ if (st && st->metadata) {
+ AVDictionaryEntry *rot = av_dict_get(st->metadata, "rotate", NULL, 0);
+ rotation = (rot && rot->value) ? atoi(rot->value) : 0;
+ }
+ 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 {
+ 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)) {
@@ -1647,6 +2261,7 @@ 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. */
+ av_assert0(av_rescale_rnd(track->cluster[0].dts, MOV_TIMESCALE, track->timescale, AV_ROUND_DOWN) <= 0);
start_ct = -FFMIN(track->cluster[0].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
@@ -1771,15 +2386,18 @@ static int mov_write_trak_tag(AVIOContext *pb, MOVMuxContext *mov,
avio_wb32(pb, 0); /* size */
ffio_wfourcc(pb, "trak");
mov_write_tkhd_tag(pb, mov, track, st);
- if (track->entry &&
- (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS ||
- track->cluster[0].dts || is_clcp_track(track))) {
+
+ av_assert2(mov->use_editlist >= 0);
+
+
+ if (track->entry) {
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);
@@ -1790,11 +2408,11 @@ 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);
}
}
@@ -1896,15 +2514,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) */
@@ -1990,28 +2600,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)
@@ -2025,7 +2686,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);
@@ -2037,7 +2699,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);
}
@@ -2056,6 +2726,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;
@@ -2129,9 +2819,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;
@@ -2152,9 +2839,13 @@ 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_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
} else {
/* iTunes meta data */
mov_write_meta_tag(pb_buf, mov, s);
@@ -2188,6 +2879,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;
@@ -2212,7 +2904,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);
@@ -2223,6 +2916,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)
{
@@ -2237,6 +2953,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)
@@ -2251,6 +2970,17 @@ 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)
@@ -2294,7 +3024,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
};
@@ -2307,7 +3037,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");
@@ -2500,7 +3231,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
};
@@ -2522,7 +3253,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
};
@@ -2546,8 +3277,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;
@@ -2928,10 +3658,8 @@ static int mov_flush_fragment(AVFormatContext *s)
if (!(mov->flags & FF_MOV_FLAG_EMPTY_MOOV) && mov->fragments == 0) {
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)
@@ -2940,12 +3668,9 @@ 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;
mov_write_moov_tag(s->pb, mov, s);
@@ -3068,6 +3793,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->fragments > 0) {
@@ -3099,19 +3839,32 @@ 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)) {
trk->vos_len = enc->extradata_size;
trk->vos_data = av_malloc(trk->vos_len);
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) {
@@ -3130,6 +3883,13 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
} else {
size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
}
+ } 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);
} else {
avio_write(pb, pkt->data, size);
}
@@ -3158,6 +3918,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;
@@ -3168,6 +3929,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
* of this packet to be what the previous packets duration implies. */
trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
}
+
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.
@@ -3186,6 +3948,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
"empty_moov.\n", 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");
@@ -3217,17 +3980,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;
@@ -3237,7 +3998,7 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
if (!pkt->size)
return 0; /* Discard 0 sized packets */
- 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);
@@ -3252,6 +4013,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);
}
}
@@ -3259,12 +4087,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');
@@ -3273,11 +4101,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];
@@ -3308,6 +4182,46 @@ 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);
+ 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);
+ 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
@@ -3367,18 +4281,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);
@@ -3453,8 +4369,8 @@ static int mov_write_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
MOVMuxContext *mov = s->priv_data;
- AVDictionaryEntry *t;
- int i, 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;
@@ -3471,6 +4387,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;
+
/* Set the FRAGMENT flag if any of the fragmentation methods are
* enabled. */
if (mov->max_fragment_duration || mov->max_fragment_size ||
@@ -3490,7 +4409,8 @@ static int mov_write_header(AVFormatContext *s)
av_log(s, AV_LOG_WARNING, "The faststart flag is incompatible "
"with fragmentation, disabling faststart\n");
mov->flags &= ~FF_MOV_FLAG_FASTSTART;
- }
+ } else
+ mov->reserved_moov_size = -1;
}
if (mov->use_editlist < 0) {
@@ -3518,10 +4438,20 @@ static int mov_write_header(AVFormatContext *s)
return AVERROR(EINVAL);
}
-
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);
}
@@ -3544,9 +4474,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);
@@ -3563,8 +4519,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,
@@ -3577,11 +4535,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"
@@ -3589,29 +4559,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;
@@ -3626,7 +4607,7 @@ 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)){
track->vos_len = st->codec->extradata_size;
track->vos_data = av_malloc(track->vos_len);
memcpy(track->vos_data, st->codec->extradata, track->vos_len);
@@ -3634,8 +4615,40 @@ static int mov_write_header(AVFormatContext *s)
}
}
+ 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 |
@@ -3654,7 +4667,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) {
@@ -3663,12 +4676,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)
@@ -3682,7 +4714,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)
@@ -3799,6 +4831,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.
@@ -3826,7 +4871,7 @@ 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");
@@ -3835,6 +4880,18 @@ static int mov_write_trailer(AVFormatContext *s)
avio_seek(pb, mov->reserved_moov_pos, SEEK_SET);
mov_write_moov_tag(pb, mov, s);
}
+ } else if (mov->reserved_moov_size > 0) {
+ int64_t size;
+ mov_write_moov_tag(pb, mov, s);
+ 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);
+ return -1;
+ }
+ 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);
}
@@ -4002,7 +5059,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 8349a18..89230ac 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
@@ -81,18 +82,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;
@@ -105,7 +113,7 @@ typedef struct MOVTrack {
int64_t start_dts;
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;
@@ -134,6 +142,8 @@ typedef struct MOVTrack {
int packet_entry;
int slices;
} vc1_info;
+
+ void *eac3_priv;
} MOVTrack;
typedef struct MOVMuxContext {
@@ -141,6 +151,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;
@@ -148,6 +159,8 @@ typedef struct MOVMuxContext {
int flags;
int rtp_flags;
+ int exact;
+
int iods_skip;
int iods_video_profile;
int iods_audio_profile;
@@ -160,6 +173,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;
diff --git a/libavformat/movenchint.c b/libavformat/movenchint.c
index a8f5f34..006aa09 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 5aee21f..8208dbb 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"
@@ -40,10 +41,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;
@@ -54,7 +60,7 @@ static int mp3_read_probe(AVProbeData *p)
int max_frames, first_frames = 0;
int fsize, frames, sample_rate;
uint32_t header;
- uint8_t *buf, *buf0, *buf2, *end;
+ const uint8_t *buf, *buf0, *buf2, *end;
AVCodecContext avctx;
buf0 = p->buf;
@@ -67,6 +73,8 @@ 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++) {
header = AV_RB32(buf2);
@@ -81,31 +89,13 @@ static int mp3_read_probe(AVProbeData *p)
}
// keep this in sync with ac3 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 && 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
}
@@ -113,22 +103,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 && 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,
@@ -146,7 +138,8 @@ 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);
/* Check for Xing / Info tag */
avio_skip(s->pb, xing_offtbl[c->lsf == 1][c->nb_channels == 1]);
@@ -159,12 +152,22 @@ 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;
+ } 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);
@@ -210,7 +213,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->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->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);
@@ -250,7 +271,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);
}
}
@@ -280,12 +301,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 */
@@ -294,14 +315,15 @@ 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;
@@ -312,17 +334,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);
@@ -338,15 +364,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;
@@ -356,38 +393,109 @@ 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->is_cbr
+ && st->duration > 0
+ && mp3->header_filesize > s->data_offset
+ && mp3->frames) {
+ int64_t filesize = avio_size(s->pb);
+ int64_t duration;
+ if (filesize <= s->data_offset)
+ filesize = mp3->header_filesize;
+ filesize -= s->data_offset;
+ duration = av_rescale(st->duration, filesize, mp3->header_filesize - s->data_offset);
+ ie = &ie1;
+ timestamp = av_clip64(timestamp, 0, duration);
+ ie->timestamp = timestamp;
+ ie->pos = av_rescale(timestamp, filesize, duration) + s->data_offset;
+ } else if (mp3->xing_toc) {
+ if (ret < 0)
+ return ret;
+
+ ie = &st->index_entries[ret];
+ } else {
+ st->skip_samples = timestamp <= 0 ? mp3->start_pad + 528 + 1 : 0;
- if (ret < 0)
- return ret;
+ return -1;
+ }
- ie = &st->index_entries[ret];
+ 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;
- 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;
+#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;
+ 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;
}
}
- return AVERROR_EOF;
+ ret = avio_seek(s->pb, best_pos, SEEK_SET);
+ if (ret < 0)
+ return ret;
+ ff_update_cur_dts(s, st, ie->timestamp);
+ st->skip_samples = ie->timestamp <= 0 ? mp3->start_pad + 528 + 1 : 0;
+ return 0;
}
+static const AVOption options[] = {
+ { "usetoc", "use table of contents", offsetof(MP3DecContext, usetoc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, 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)"),
@@ -398,4 +506,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 bb96039..d4b6af0 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,11 +455,22 @@ 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",
.long_name = NULL_IF_CONFIG_SMALL("MP2 (MPEG audio layer 2)"),
- .mime_type = "audio/x-mpeg",
+ .mime_type = "audio/mpeg",
.extensions = "mp2,m2a,mpa",
.audio_codec = AV_CODEC_ID_MP2,
.video_codec = AV_CODEC_ID_NONE,
@@ -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);
}
@@ -577,7 +616,7 @@ static int mp3_write_header(struct AVFormatContext *s)
AVOutputFormat ff_mp3_muxer = {
.name = "mp3",
.long_name = NULL_IF_CONFIG_SMALL("MP3 (MPEG audio layer 3)"),
- .mime_type = "audio/x-mpeg",
+ .mime_type = "audio/mpeg",
.extensions = "mp3",
.priv_data_size = sizeof(MP3Context),
.audio_codec = AV_CODEC_ID_MP3,
@@ -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 5e771ae..8f8ac9c 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 3564e81..a15dc25 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
*/
@@ -55,7 +55,7 @@ typedef struct {
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;
int br = 0;
@@ -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)
@@ -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,7 +220,7 @@ 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(tag == TAG_STREAMHDR)
@@ -241,9 +248,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 +257,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 +275,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 7c87517..e8e1b08 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,21 @@
#include "internal.h"
#include "mpeg.h"
+#if CONFIG_VOBSUB_DEMUXER
+# include "subtitles.h"
+# include "libavutil/bprint.h"
+#endif
+
#undef NDEBUG
#include <assert.h>
+#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 &&
@@ -80,37 +86,33 @@ static int mpegps_probe(AVProbeData *p)
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;
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;
}
@@ -118,25 +120,30 @@ typedef struct MpegDemuxContext {
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];
+#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 +168,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--;
@@ -198,6 +205,8 @@ 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);
+ /* 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 +246,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 +261,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 +346,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 +356,8 @@ redo:
len = avio_rb16(s->pb);
pts =
dts = AV_NOPTS_VALUE;
+ if (startcode != PRIVATE_STREAM_2)
+ {
/* stuffing */
for (;;) {
if (len < 1)
@@ -358,22 +432,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 +464,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 +498,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 +520,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 +532,20 @@ 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 {
+ codec_id = AV_CODEC_ID_MP2;
+ }
} else if (startcode >= 0x80 && startcode <= 0x87) {
type = AVMEDIA_TYPE_AUDIO;
codec_id = AV_CODEC_ID_AC3;
@@ -475,7 +556,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 +574,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,11 +587,25 @@ 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->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;
@@ -575,3 +657,341 @@ 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;
+ char *sub_name = NULL;
+ size_t fname_len;
+ char *ext, *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;
+
+ sub_name = av_strdup(s->filename);
+ fname_len = strlen(sub_name);
+ ext = 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, sub_name);
+
+ if (!(iformat = av_find_input_format("mpeg")))
+ return AVERROR_DEMUXER_NOT_FOUND;
+
+ vobsub->sub_ctx = avformat_alloc_context();
+ if (!vobsub->sub_ctx)
+ return AVERROR(ENOMEM);
+
+ if ((ret = ff_copy_whitelists(vobsub->sub_ctx, s)) < 0)
+ goto end;
+
+ ret = avformat_open_input(&vobsub->sub_ctx, sub_name, iformat, NULL);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Unable to open %s as MPEG subtitles\n", 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:
+ av_free(sub_name);
+ 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;
+}
+
+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",
+};
+#endif
diff --git a/libavformat/mpeg.h b/libavformat/mpeg.h
index d0b36ee..b43517c 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 fed03ed..d3af9e1 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
*/
@@ -70,6 +70,7 @@ typedef struct {
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;
@@ -269,8 +270,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;
}
@@ -325,7 +325,7 @@ 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 = 0.7*AV_TIME_BASE;
s->vcd_padding_bytes_written = 0;
s->vcd_padding_bitrate = 0;
@@ -352,6 +352,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) {
@@ -388,10 +397,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:
@@ -430,12 +445,18 @@ 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) {
@@ -494,7 +515,7 @@ 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:
@@ -921,7 +942,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;
}
@@ -953,7 +974,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,
@@ -963,14 +984,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)
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;
@@ -1085,14 +1108,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_dlog(ctx, "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);
@@ -1154,7 +1185,7 @@ static int mpeg_mux_end(AVFormatContext *ctx)
stream = ctx->streams[i]->priv_data;
assert(av_fifo_size(stream->fifo) == 0);
- av_fifo_free(stream->fifo);
+ av_fifo_freep(&stream->fifo);
}
return 0;
}
@@ -1162,7 +1193,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 b2ba9f7..97da0a3 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,8 +26,10 @@
#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"
#include "avformat.h"
#include "mpegts.h"
#include "internal.h"
@@ -54,6 +56,7 @@
enum MpegTSFilterType {
MPEGTS_PES,
MPEGTS_SECTION,
+ MPEGTS_PCR,
};
typedef struct MpegTSFilter MpegTSFilter;
@@ -84,6 +87,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;
@@ -96,6 +100,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 {
@@ -105,9 +112,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;
@@ -115,6 +124,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 */
@@ -126,6 +138,11 @@ struct MpegTSContext {
/** to detect seek */
int64_t last_pos;
+ int skip_changes;
+ int skip_clear;
+
+ int scan_all_pmts;
+
int resync_size;
/******************************************/
@@ -135,15 +152,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 },
};
@@ -212,13 +241,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)
@@ -237,28 +295,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
@@ -336,22 +414,27 @@ 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 (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);
}
}
-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_dlog(ts->stream, "Filter: pid=0x%x\n", pid);
@@ -362,11 +445,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;
@@ -386,24 +484,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;
@@ -428,28 +522,26 @@ static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter)
static int analyze(const uint8_t *buf, int size, int packet_size, int *index)
{
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++) {
- if (buf[i] == 0x47 && !(buf[i + 1] & 0x80) && (buf[i + 3] & 0x30)) {
+ for (i = 0; i < size - 3; i++) {
+ if (buf[i] == 0x47 && !(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 */
@@ -576,7 +668,11 @@ 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 },
{ 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC },
{ 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS },
@@ -593,6 +689,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 },
};
@@ -612,7 +710,15 @@ 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 },
};
@@ -630,10 +736,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;
}
}
@@ -641,6 +753,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;
@@ -656,7 +776,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) {
@@ -686,10 +807,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);
@@ -717,12 +851,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,
@@ -733,7 +870,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);
@@ -771,9 +913,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)
@@ -808,9 +950,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;
@@ -842,6 +985,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);
@@ -866,12 +1012,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_dlog(pes->stream,
"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;
@@ -955,10 +1101,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);
@@ -976,18 +1166,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;
@@ -1031,6 +1221,7 @@ typedef struct {
int descr_count;
int max_descr_count;
int level;
+ int predefined_SLConfigDescriptor_seen;
} MP4DescrParseContext;
static int init_MP4DescrParseContext(MP4DescrParseContext *d, AVFormatContext *s,
@@ -1154,6 +1345,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);
@@ -1161,8 +1357,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;
}
@@ -1278,7 +1475,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;
}
@@ -1314,13 +1511,28 @@ static void m4sl_cb(MpegTSFilter *filter, const uint8_t *section,
av_free(mp4_descr[i].dec_config_descr);
}
+static const uint8_t opus_coupled_stream_cnt[9] = {
+ 1, 0, 1, 1, 2, 2, 2, 3, 3
+};
+
+static const uint8_t opus_channel_map[8][8] = {
+ { 0 },
+ { 0,1 },
+ { 0,2,1 },
+ { 0,1,2,3 },
+ { 0,4,1,2,3 },
+ { 0,4,1,2,3,5 },
+ { 0,4,1,2,3,5,6 },
+ { 0,6,1,2,3,4,5,7 },
+};
+
int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type,
const uint8_t **pp, const uint8_t *desc_list_end,
Mp4Descr *mp4_descr, int mp4_descr_count, int pid,
MpegTSContext *ts)
{
const uint8_t *desc_end;
- int desc_len, desc_tag, desc_es_id;
+ int desc_len, desc_tag, desc_es_id, ext_desc_tag, channels, channel_config_code;
char language[252];
int i;
@@ -1336,7 +1548,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
av_dlog(fc, "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);
@@ -1363,7 +1575,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
case 0x1F: /* FMC descriptor */
get16(pp, desc_end);
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) &&
mp4_descr->dec_config_descr_len && mp4_descr->es_id == pid) {
AVIOContext pb;
ffio_init_context(&pb, mp4_descr->dec_config_descr,
@@ -1371,46 +1583,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) {
@@ -1441,6 +1725,53 @@ 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)
+ return AVERROR_INVALIDDATA;
+ if (st->codec->codec_id == AV_CODEC_ID_OPUS &&
+ ext_desc_tag == 0x80) { /* User defined (provisional Opus) */
+ if (!st->codec->extradata) {
+ st->codec->extradata = av_mallocz(sizeof(opus_default_extradata) +
+ FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codec->extradata)
+ return AVERROR(ENOMEM);
+
+ st->codec->extradata_size = sizeof(opus_default_extradata);
+ memcpy(st->codec->extradata, opus_default_extradata, sizeof(opus_default_extradata));
+
+ channel_config_code = get8(pp, desc_end);
+ if (channel_config_code < 0)
+ return AVERROR_INVALIDDATA;
+ if (channel_config_code <= 0x8) {
+ st->codec->extradata[9] = channels = channel_config_code ? channel_config_code : 2;
+ st->codec->extradata[18] = channels > 2;
+ st->codec->extradata[19] = channel_config_code;
+ if (channel_config_code == 0) { /* Dual Mono */
+ st->codec->extradata[18] = 255; /* Mapping */
+ st->codec->extradata[19] = 2; /* Stream Count */
+ }
+ st->codec->extradata[20] = opus_coupled_stream_cnt[channel_config_code];
+ memcpy(&st->codec->extradata[21], opus_channel_map[channels - 1], channels);
+ } else {
+ avpriv_request_sample(fc, "Opus in MPEG-TS - channel_config_code > 0x8");
+ }
+ st->need_parsing = AVSTREAM_PARSE_FULL;
+ }
+ }
+ break;
default:
break;
}
@@ -1471,18 +1802,23 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
if (parse_section_header(h, &p, p_end) < 0)
return;
- av_dlog(ts->stream, "sid=0x%x sec_num=%d/%d\n",
- h->id, h->sec_num, h->last_sec_num);
+ av_dlog(ts->stream, "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_dlog(ts->stream, "pcr_pid=0x%x\n", pcr_pid);
@@ -1519,7 +1855,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 (;;) {
@@ -1530,14 +1868,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;
@@ -1547,6 +1889,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 {
@@ -1555,6 +1899,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;
}
@@ -1572,11 +1918,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,
@@ -1593,6 +1939,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);
@@ -1604,6 +1953,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_dlog(ts->stream, "PAT:\n");
hex_dump_debug(ts->stream, section, section_len);
@@ -1614,6 +1964,10 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
return;
if (h->tid != PAT_TID)
return;
+ if (ts->skip_changes)
+ return;
+
+ ts->stream->ts_id = h->id;
clear_programs(ts);
for (;;) {
@@ -1625,20 +1979,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_dlog(ts->stream, "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)
@@ -1658,6 +2036,8 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
return;
if (h->tid != SDT_TID)
return;
+ if (ts->skip_changes)
+ return;
onid = get16(&p, p_end);
if (onid < 0)
return;
@@ -1684,7 +2064,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_dlog(ts->stream, "tag: 0x%02x len=%d\n",
@@ -1719,6 +2099,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)
{
@@ -1739,6 +2122,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 */
@@ -1759,7 +2143,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) {
@@ -1768,20 +2152,25 @@ 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) {
@@ -1808,17 +2197,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)
@@ -1829,10 +2275,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;
}
}
@@ -1856,7 +2303,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
@@ -1876,12 +2325,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;
@@ -1896,6 +2346,7 @@ static int handle_packets(MpegTSContext *ts, int nb_packets)
pes->state = MPEGTS_SKIP; /* skip until pes header */
}
ts->pids[i]->last_cc = -1;
+ ts->pids[i]->last_pcr = -1;
}
}
}
@@ -1904,11 +2355,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;
@@ -1924,30 +2379,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) * CHECK_COUNT / check_count;
- dvhs_score = analyze(p->buf, TS_DVHS_PACKET_SIZE * check_count,
- TS_DVHS_PACKET_SIZE, NULL) * CHECK_COUNT / check_count;
- fec_score = analyze(p->buf, TS_FEC_PACKET_SIZE * check_count,
- TS_FEC_PACKET_SIZE, NULL) * CHECK_COUNT / check_count;
- av_dlog(NULL, "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);
+ int dvhs_score = analyze(p->buf + TS_DVHS_PACKET_SIZE*i, TS_DVHS_PACKET_SIZE*left, TS_DVHS_PACKET_SIZE, NULL);
+ int fec_score = analyze(p->buf + TS_FEC_PACKET_SIZE *i, TS_FEC_PACKET_SIZE *left, TS_FEC_PACKET_SIZE , NULL);
+ 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;
}
@@ -1980,24 +2438,33 @@ 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 */
+ ffio_ensure_seekback(pb, probesize);
+
+ /* 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;
@@ -2005,14 +2472,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;
@@ -2072,7 +2538,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;
}
@@ -2135,6 +2601,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) {
@@ -2171,7 +2638,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;
@@ -2179,74 +2646,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;
@@ -2257,22 +2719,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) {
@@ -2282,12 +2745,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);
@@ -2301,8 +2766,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,
};
@@ -2314,8 +2778,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 7dbbf8d..84f3098 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 1082650..d73b75f 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"
@@ -78,6 +79,7 @@ typedef struct MpegTSWrite {
int pmt_start_pid;
int start_pid;
+ int m2ts_mode;
int reemit_pat_pmt; // backward compatibility
@@ -85,6 +87,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 */
@@ -183,7 +189,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 */
@@ -197,6 +203,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;
@@ -218,11 +225,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;
@@ -245,7 +252,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;
}
@@ -284,10 +291,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;
@@ -296,6 +310,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;
@@ -336,26 +364,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;
@@ -369,6 +453,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);
@@ -382,11 +476,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;
@@ -437,7 +532,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);
}
@@ -455,19 +550,41 @@ 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)
+{
+ return av_rescale(avio_tell(pb) + 11, 8 * PCR_TIME_BASE, ts->mux_rate) +
+ ts->first_pcr;
+}
+
+static void mpegts_prefix_m2ts_header(AVFormatContext *s)
+{
+ MpegTSWrite *ts = s->priv_data;
+ if (ts->m2ts_mode) {
+ int64_t pcr = get_pcr(s->priv_data, s->pb);
+ uint32_t tp_extra_header = pcr % 0x3fffffff;
+ tp_extra_header = AV_RB32(&tp_extra_header);
+ avio_write(s->pb, (unsigned char *) &tp_extra_header,
+ sizeof(tp_extra_header));
+ }
}
static void section_write_packet(MpegTSSection *s, const uint8_t *packet)
{
AVFormatContext *ctx = s->opaque;
+ mpegts_prefix_m2ts_header(ctx);
avio_write(ctx->pb, packet, TS_PACKET_SIZE);
}
@@ -521,10 +638,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 */
@@ -611,7 +728,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) {
@@ -629,9 +746,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) {
@@ -649,6 +767,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
@@ -665,13 +785,18 @@ static int mpegts_write_header(AVFormatContext *s)
service->pcr_packet_period,
ts->sdt_packet_period, ts->pat_packet_period);
- avio_flush(s->pb);
+ if (ts->m2ts_mode == -1) {
+ if (av_match_ext(s->filename, "m2ts")) {
+ ts->m2ts_mode = 1;
+ } else {
+ ts->m2ts_mode = 0;
+ }
+ }
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;
@@ -684,11 +809,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_free(service);
+ }
+ av_free(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;
@@ -697,7 +830,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++)
@@ -705,12 +838,6 @@ static void retransmit_si_info(AVFormatContext *s)
}
}
-static int64_t get_pcr(const MpegTSWrite *ts, AVIOContext *pb)
-{
- return av_rescale(avio_tell(pb) + 11, 8 * PCR_TIME_BASE, ts->mux_rate) +
- ts->first_pcr;
-}
-
static int write_pcr_bits(uint8_t *buf, int64_t pcr)
{
int64_t pcr_low = pcr % 300, pcr_high = pcr / 300;
@@ -737,6 +864,7 @@ static void mpegts_insert_null_packet(AVFormatContext *s)
*q++ = 0xff;
*q++ = 0x10;
memset(q, 0x0FF, TS_PACKET_SIZE - (q - buf));
+ mpegts_prefix_m2ts_header(s);
avio_write(s->pb, buf, TS_PACKET_SIZE);
}
@@ -762,6 +890,7 @@ static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st)
/* stuffing bytes */
memset(q, 0xFF, TS_PACKET_SIZE - (q - buf));
+ mpegts_prefix_m2ts_header(s);
avio_write(s->pb, buf, TS_PACKET_SIZE);
}
@@ -783,7 +912,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
@@ -799,7 +928,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;
}
@@ -824,14 +953,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) {
@@ -887,11 +1018,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;
@@ -902,10 +1035,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;
@@ -928,16 +1070,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;
@@ -958,8 +1121,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 */
@@ -990,12 +1173,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) {
+ 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) {
+ 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)
@@ -1006,8 +1227,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,
@@ -1022,13 +1243,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;
@@ -1036,12 +1259,9 @@ 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;
-
- 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;
- }
+ int ret = ff_check_h264_startcode(s, st, pkt);
+ if (ret < 0)
+ return ret;
do {
p = avpriv_find_start_code(p, buf_end, &state);
@@ -1078,6 +1298,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)
@@ -1094,9 +1316,36 @@ 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) {
+ 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);
@@ -1104,21 +1353,6 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
return 0;
}
- if (ts_st->payload_size + size > ts->pes_payload_size) {
- 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;
@@ -1148,7 +1382,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)
@@ -1202,10 +1435,13 @@ static const AVOption options[] = {
{ .i64 = 0x0001 }, 0x0001, 0xffff, AV_OPT_FLAG_ENCODING_PARAM },
{ "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.",
+ offsetof(MpegTSWrite, m2ts_mode), AV_OPT_TYPE_INT,
+ { .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 },
@@ -1225,6 +1461,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 },
@@ -1241,8 +1486,8 @@ static const AVClass mpegts_muxer_class = {
AVOutputFormat ff_mpegts_muxer = {
.name = "mpegts",
.long_name = NULL_IF_CONFIG_SMALL("MPEG-TS (MPEG-2 Transport Stream)"),
- .mime_type = "video/x-mpegts",
- .extensions = "ts,m2t",
+ .mime_type = "video/MP2T",
+ .extensions = "ts,m2t,m2ts,mts",
.priv_data_size = sizeof(MpegTSWrite),
.audio_codec = AV_CODEC_ID_MP2,
.video_codec = AV_CODEC_ID_MPEG2VIDEO,
diff --git a/libavformat/mpegvideodec.c b/libavformat/mpegvideodec.c
index 96b95a5..ade76d8 100644
--- a/libavformat/mpegvideodec.c
+++ b/libavformat/mpegvideodec.c
@@ -3,26 +3,28 @@
* 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"
+
#define SEQ_START_CODE 0x000001b3
#define GOP_START_CODE 0x000001b8
#define PICTURE_START_CODE 0x00000100
@@ -34,24 +36,53 @@
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;
+ int i, j;
+ uint32_t last = 0;
for(i=0; i<p->buf_size; i++){
code = (code<<8) + p->buf[i];
if ((code & 0xffffff00) == 0x100) {
switch(code){
- case SEQ_START_CODE: seq++; break;
+ case SEQ_START_CODE:
+ if (!(p->buf[i+1+3+1+2] & 0x20))
+ break;
+ j = i;
+ if (p->buf[j+8] & 2)
+ j+= 64;
+ if (j >= p->buf_size)
+ break;
+ if (p->buf[j+8] & 1)
+ j+= 64;
+ if (j >= p->buf_size)
+ break;
+ if (AV_RB24(p->buf + 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 9e21099..7b975e2 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 0000000..260b7be
--- /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 0000000..eddc594
--- /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 b6d30fe..60225af 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 7ad7618..addad24 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 87220ec..3fb4a01 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"
@@ -48,15 +49,134 @@
/**
* @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;
+}
+
+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 +199,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 +212,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 +230,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 +276,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 +296,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 +339,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 +347,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,6 +367,37 @@ 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;
@@ -244,11 +407,19 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options)
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 +429,30 @@ 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_dlog(s, "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);
+ av_dlog(s, "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 +465,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;
@@ -296,65 +492,118 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt)
((!(s->oformat->flags & AVFMT_TS_NONSTRICT) &&
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_dlog(s, "av_write_frame: pts2:%"PRId64" dts2:%"PRId64"\n",
- pkt->pts, pkt->dts);
+ av_dlog(s, "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;
if (!s->offset && pkt->dts != AV_NOPTS_VALUE &&
(pkt->dts < 0 || s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)) {
s->offset = -pkt->dts;
- s->offset_timebase = time_base;
+ s->offset_timebase = st->time_base;
+ }
+
+ if (s->offset && !offset) {
+ offset = st->mux_ts_offset =
+ av_rescale_q_rnd(s->offset,
+ s->offset_timebase,
+ st->time_base,
+ AV_ROUND_UP);
}
- if (s->offset)
- offset = av_rescale_q(s->offset, s->offset_timebase, time_base);
if (pkt->dts != AV_NOPTS_VALUE)
pkt->dts += offset;
if (pkt->pts != AV_NOPTS_VALUE)
pkt->pts += offset;
+ 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 %"PRId64" in stream %d.\n"
+ "timestamp %s in stream %d.\n"
"Try -max_interleave_delta 0 as a possible workaround.\n",
- pkt->dts, pkt->stream_index);
+ 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 +635,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 +652,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)
@@ -419,27 +680,58 @@ FF_DISABLE_DEPRECATION_WARNINGS
FF_ENABLE_DEPRECATION_WARNINGS
#endif
pkt->buf = NULL;
- // Duplicate the packet if it uses non-allocated memory
- if ((ret = av_dup_packet(&this_pktl->pkt)) < 0) {
- av_free(this_pktl);
- return ret;
+ pkt->side_data = NULL;
+ pkt->side_data_elems = 0;
+ 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->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->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->packet_buffer_end->next);
}
}
- assert(!*next_point);
+ av_assert1(!*next_point);
s->packet_buffer_end = this_pktl;
next_non_null:
@@ -459,6 +751,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;
@@ -470,6 +772,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) {
@@ -477,7 +780,24 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out,
return ret;
}
- if (s->max_interleave_delta > 0 && s->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->packet_buffer &&
+ !flush &&
+ s->internal->nb_interleaved_streams == stream_count+noninterleaved_count
+ ) {
AVPacket *top_pkt = &s->packet_buffer->pkt;
int64_t delta_dts = INT64_MIN;
int64_t top_dts = av_rescale_q(top_pkt->dts,
@@ -495,7 +815,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) {
@@ -505,23 +824,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->packet_buffer;
*out = pktl->pkt;
+ st = s->streams[out->stream_index];
s->packet_buffer = pktl->next;
if (!s->packet_buffer)
s->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);
@@ -560,8 +878,8 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
if (pkt) {
AVStream *st = s->streams[pkt->stream_index];
- av_dlog(s, "av_interleaved_write_frame size:%d dts:%" PRId64 " pts:%" PRId64 "\n",
- pkt->size, pkt->dts, pkt->pts);
+ av_dlog(s, "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;
@@ -593,6 +911,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);
@@ -619,15 +939,18 @@ int av_write_trailer(AVFormatContext *s)
if (ret < 0)
goto fail;
+ if(s->pb && s->pb->error)
+ goto fail;
}
if (s->oformat->write_trailer)
ret = s->oformat->write_trailer(s);
- if (!(s->oformat->flags & AVFMT_NOFILE))
- 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);
@@ -638,10 +961,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;
@@ -653,5 +986,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 e21ec06..c8a5ebf 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)
diff --git a/libavformat/mvi.c b/libavformat/mvi.c
index 03a1f40..a7cfcb9 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 19ee35f..4dc54d7 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,10 @@ 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 */
/* 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 */
diff --git a/libavformat/mxf.h b/libavformat/mxf.h
index 2443207..5b95efa 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,
@@ -48,11 +49,11 @@ enum MXFMetadataSetType {
};
enum MXFFrameLayout {
- FullFrame = 0,
- MixedFields,
- OneField,
- SegmentedFrame,
- SeparateFields
+ FullFrame = 0,
+ SeparateFields,
+ OneField,
+ MixedFields,
+ SegmentedFrame,
};
typedef struct KLVPacket {
@@ -67,7 +68,7 @@ typedef struct MXFCodecUL {
int id;
} MXFCodecUL;
-typedef struct MXFSamplesPerFrame {
+typedef struct {
struct AVRational time_base;
int samples_per_frame[6];
} MXFSamplesPerFrame;
diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index b71c80f..b533e2a 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 {
@@ -86,6 +89,7 @@ typedef struct {
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 {
@@ -117,6 +121,21 @@ typedef struct {
typedef struct {
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;
MXFSequence *sequence; /* mandatory, and only one */
UID sequence_ref;
int track_id;
@@ -176,6 +195,7 @@ typedef struct {
int tracks_count;
MXFDescriptor *descriptor; /* only one */
UID descriptor_ref;
+ char *name;
} MXFPackage;
typedef struct {
@@ -207,7 +227,6 @@ typedef struct {
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 +256,8 @@ typedef struct {
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 };
@@ -270,7 +291,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 +428,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 +447,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 +472,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 +502,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 +548,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 +565,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 +593,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 +606,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;
@@ -603,10 +632,11 @@ static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int siz
MXFContext *mxf = arg;
switch (tag) {
case 0x1901:
+ if (mxf->packages_refs)
+ av_log(mxf->fc, AV_LOG_VERBOSE, "Multiple packages_refs\n");
+ av_free(mxf->packages_refs);
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));
+ mxf->packages_refs = av_calloc(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 */
@@ -644,9 +674,7 @@ static int mxf_read_material_package(void *arg, AVIOContext *pb, int tag, int si
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));
+ package->tracks_refs = av_calloc(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 */
@@ -656,6 +684,34 @@ static int mxf_read_material_package(void *arg, AVIOContext *pb, int tag, int si
return 0;
}
+static int mxf_read_timecode_component(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
+{
+ MXFTimecodeComponent *mxf_timecode = arg;
+ switch(tag) {
+ 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;
+}
+
static int mxf_read_track(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
{
MXFTrack *track = arg;
@@ -692,9 +748,7 @@ static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, UID
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));
+ sequence->structural_components_refs = av_calloc(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 */
@@ -704,15 +758,34 @@ static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, UID
return 0;
}
+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_read_source_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));
+ package->tracks_refs = av_calloc(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 */
@@ -726,6 +799,8 @@ static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int size
case 0x4701:
avio_read(pb, package->descriptor_ref, 16);
break;
+ case 0x4402:
+ return mxf_read_utf16_string(pb, size, &package->name);
}
return 0;
}
@@ -735,29 +810,13 @@ 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);
- av_freep(&segment->temporal_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))))
return AVERROR(ENOMEM);
- }
for (i = 0; i < segment->nb_index_entries; i++) {
segment->temporal_offset_entries[i] = avio_r8(pb);
@@ -809,7 +868,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 +878,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);
@@ -832,9 +892,7 @@ static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int
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));
+ descriptor->sub_descriptors_refs = av_calloc(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 */
@@ -893,9 +951,11 @@ 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;
@@ -978,10 +1038,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 +1059,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 +1232,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,12 +1408,101 @@ 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_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 int mxf_parse_physical_source_package(MXFContext *mxf, MXFTrack *source_track, AVStream *st)
+{
+ MXFPackage *temp_package = NULL;
+ MXFPackage *physical_package = NULL;
+ MXFTrack *physical_track = NULL;
+ MXFStructuralComponent *component = NULL;
+ MXFStructuralComponent *sourceclip = NULL;
+ MXFTimecodeComponent *mxf_tc = NULL;
+ MXFPulldownComponent *mxf_pulldown = NULL;
+ int i, j, k;
+ AVTimecode tc;
+ int flags;
+ int64_t start_position;
+
+ for (i = 0; i < source_track->sequence->structural_components_count; i++) {
+ component = mxf_resolve_strong_ref(mxf, &source_track->sequence->structural_components_refs[i], SourceClip);
+ if (!component)
+ continue;
+
+ for (j = 0; j < mxf->packages_count; j++) {
+ temp_package = mxf_resolve_strong_ref(mxf, &mxf->packages_refs[j], SourcePackage);
+ if (!temp_package)
+ continue;
+ if (!memcmp(temp_package->package_uid, component->source_package_uid, 16)){
+ physical_package = temp_package;
+ sourceclip = component;
+ break;
+ }
+ }
+ if (!physical_package)
+ break;
+
+ /* 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++) {
+ component = mxf_resolve_strong_ref(mxf, &physical_track->sequence->structural_components_refs[k], TimecodeComponent);
+ if (!component){
+ /* timcode component may be located on a pulldown component */
+ component = mxf_resolve_strong_ref(mxf, &physical_track->sequence->structural_components_refs[k], PulldownComponent);
+ if (!component)
+ continue;
+ mxf_pulldown = (MXFPulldownComponent*)component;
+ component = mxf_resolve_strong_ref(mxf, &mxf_pulldown->input_segment_ref, TimecodeComponent);
+ if (!component)
+ continue;
+ }
+
+ mxf_tc = (MXFTimecodeComponent*)component;
+ 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)
@@ -1387,25 +1529,48 @@ 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;
}
+ for (j = 0; j < material_track->sequence->structural_components_count; j++) {
+ component = mxf_resolve_strong_ref(mxf, &material_track->sequence->structural_components_refs[j], TimecodeComponent);
+ if (!component)
+ continue;
+
+ 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++) {
- /* TODO: handle timecode component */
component = mxf_resolve_strong_ref(mxf, &material_track->sequence->structural_components_refs[j], SourceClip);
if (!component)
continue;
@@ -1526,7 +1691,18 @@ 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_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 +1710,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;
@@ -1573,16 +1745,14 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
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 +1766,16 @@ 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);
}
} 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 +1820,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,27 +1839,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;
@@ -1800,7 +1944,6 @@ static int mxf_read_identification_metadata(void *arg, AVIOContext *pb, int tag,
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 },
@@ -1815,7 +1958,7 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = {
{ { 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,0x0f,0x00 }, mxf_read_sequence, sizeof(MXFSequence), Sequence },
{ { 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,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 */
@@ -1829,6 +1972,8 @@ 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 },
@@ -1842,7 +1987,7 @@ 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) {
+ 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 */
@@ -1888,23 +2033,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_dlog(mxf->fc, "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 +2140,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_dlog(mxf->fc, "no last partition\n");
+ if (!mxf->footer_partition) {
+ av_dlog(mxf->fc, "no FooterPartition\n");
return 0;
}
- av_dlog(mxf->fc, "seeking to last partition\n");
+ av_dlog(mxf->fc, "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 +2181,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 +2198,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 +2221,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 */
@@ -2077,16 +2261,33 @@ 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 +2296,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 +2328,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 +2347,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 +2382,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 +2393,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",
@@ -2210,10 +2416,10 @@ 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;
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 +2427,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 +2454,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 +2474,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 +2512,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 +2533,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 +2547,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_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset);
if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) {
@@ -2377,9 +2583,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 "
@@ -2411,14 +2616,12 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
* 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 +2638,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 +2682,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,7 +2702,6 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
return 0;
}
-
static int mxf_read_close(AVFormatContext *s)
{
MXFContext *mxf = s->priv_data;
@@ -2525,6 +2727,7 @@ static int mxf_read_close(AVFormatContext *s)
case SourcePackage:
case MaterialPackage:
av_freep(&((MXFPackage *)mxf->metadata_sets[i])->tracks_refs);
+ av_freep(&((MXFPackage *)mxf->metadata_sets[i])->name);
break;
case IndexTableSegment:
seg = (MXFIndexTableSegment *)mxf->metadata_sets[i];
@@ -2542,10 +2745,12 @@ static int mxf_read_close(AVFormatContext *s)
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 +2758,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 +2829,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 2cf77df..a850239 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,16 +35,21 @@
#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/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;
@@ -69,9 +75,12 @@ typedef struct {
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 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 {
@@ -88,6 +97,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 +177,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 +289,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 +303,14 @@ 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;
} MXFContext;
static const uint8_t uuid_base[] = { 0xAD,0xAB,0x44,0x24,0x2f,0x25,0x4d,0xc7,0x92,0xff,0x29,0xbd };
@@ -280,6 +399,7 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = {
{ 0x3208, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x0B,0x00,0x00,0x00}}, /* Display Height */
{ 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 */
@@ -427,18 +547,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 +575,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);
@@ -477,7 +604,7 @@ static void mxf_write_preface(AVFormatContext *s)
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
@@ -500,7 +627,7 @@ static void mxf_write_identification(AVFormatContext *s)
{
MXFContext *mxf = s->priv_data;
AVIOContext *pb = s->pb;
- const char *company = "Libav";
+ const char *company = "FFmpeg";
const char *product = "OP1a Muxer";
const char *version;
int length;
@@ -665,7 +792,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 +800,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 +912,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+5+16+sc->interlaced*4+12+20;
+ 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);
@@ -809,7 +939,7 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke
// 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);
@@ -821,9 +951,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 +978,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,24 +994,31 @@ 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;
mxf_write_generic_desc(s, st, key, size+5+12+8+8);
@@ -889,7 +1032,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)
+ 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));
@@ -1177,9 +1334,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)));
}
}
@@ -1217,7 +1373,7 @@ 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);
+ klv_encode_ber_length(pb, 88 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count));
// write partition value
avio_wb16(pb, 1); // majorVersion
@@ -1280,6 +1436,243 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
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;
+
+ 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 };
+
+ 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;
+
+ 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 +1710,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 +1721,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 +1731,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,17 +1787,18 @@ 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_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;
+ AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
if (!s->nb_streams)
return -1;
@@ -1430,45 +1810,55 @@ static int mxf_write_header(AVFormatContext *s)
return AVERROR(ENOMEM);
st->priv_data = sc;
+ if ((i == 0) ^ (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)) {
+ 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;
- }
// 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;
+ 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 (!tcr)
+ tcr = av_dict_get(st->metadata, "timecode", NULL, 0);
+ if (tcr)
+ ret = av_timecode_init_from_string(&mxf->tc, rate, tcr->value, s);
+ else
+ ret = av_timecode_init(&mxf->tc, rate, 0, 0, s);
+ if (ret < 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) {
@@ -1522,7 +1912,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 +1932,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 +1944,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 +1951,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 +1960,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 +1972,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 +1989,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 +2006,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);
}
}
@@ -1696,6 +2069,21 @@ 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 (!mxf->header_written) {
@@ -1900,6 +2288,19 @@ 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,
+};
+
AVOutputFormat ff_mxf_muxer = {
.name = "mxf",
.long_name = NULL_IF_CONFIG_SMALL("MXF (Material eXchange Format)"),
@@ -1927,4 +2328,5 @@ AVOutputFormat ff_mxf_d10_muxer = {
.write_trailer = mxf_write_footer,
.flags = AVFMT_NOTIMESTAMPS,
.interleave_packet = mxf_interleave,
+ .priv_class = &mxf_d10_muxer_class,
};
diff --git a/libavformat/mxg.c b/libavformat/mxg.c
index 1d1488c..34977b8 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 40d8dac..062899f 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 6d308eb..9f02ec6 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)
{
@@ -73,7 +76,7 @@ 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());
for (i = 0; i < CRYPTO_num_locks(); i++)
pthread_mutex_init(&openssl_mutexes[i], NULL);
CRYPTO_set_locking_callback(openssl_lock);
@@ -147,6 +150,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 +225,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 +245,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 +260,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 +281,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 +295,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 09cee58..0d1081a 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
@@ -82,6 +83,18 @@ 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 0000000..2f17f9e
--- /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 e6cc421..4524764 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 670b867..05dfd53 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_dlog(s, "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_dlog(s, "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_dlog(s, "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_dlog(s, "NSV got infos; filepos %"PRId64"\n", avio_tell(pb));
@@ -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;
@@ -547,7 +546,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 +581,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;
@@ -627,7 +626,10 @@ null_chunk_retry:
if (bps != 16) {
av_dlog(s, "NSV AUDIO bit/sample != 16 (%d)!!!\n", bps);
}
- bps /= channels; // ???
+ if(channels)
+ bps /= channels; // ???
+ else
+ av_log(s, AV_LOG_WARNING, "Channels is 0\n");
if (bps == 8)
st[NSV_ST_AUDIO]->codec->codec_id = AV_CODEC_ID_PCM_U8;
samplerate /= 4;/* UGH ??? XXX */
@@ -717,10 +719,8 @@ static int nsv_read_close(AVFormatContext *s)
static int nsv_probe(AVProbeData *p)
{
- int i;
- int score;
- int vsize, asize, auxcount;
- score = 0;
+ int i, score = 0;
+
av_dlog(NULL, "nsv_probe(), buf_size %d\n", p->buf_size);
/* check file header */
/* streamed files might not have any header */
@@ -732,19 +732,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 829f2a8..7c08c39 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 43ae8a0..9224a96 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 }
};
@@ -40,24 +41,28 @@ const AVCodecTag ff_nut_data_tags[] = {
const AVCodecTag ff_nut_video_tags[] = {
{ 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 +72,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 +144,76 @@ 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_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 +229,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 +255,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 16f3c12..943081c 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 {
@@ -103,15 +105,21 @@ typedef struct NUTContext {
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 69057e9..ef29bdf 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);
@@ -72,8 +76,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 +103,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 +146,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 +184,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;
@@ -220,6 +236,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);
@@ -231,6 +249,8 @@ 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));
+ if (!nut->time_base)
+ return AVERROR(ENOMEM);
for (i = 0; i < nut->time_base_count; i++) {
GET_V(nut->time_base[i].num, tmp > 0 && tmp < (1ULL << 31));
@@ -298,7 +318,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;
@@ -318,11 +338,11 @@ static int decode_main_header(NUTContext *nut)
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);
}
@@ -331,7 +351,9 @@ static int decode_main_header(NUTContext *nut)
return AVERROR_INVALIDDATA;
}
- nut->stream = av_mallocz(sizeof(StreamContext) * stream_count);
+ nut->stream = av_calloc(stream_count, sizeof(StreamContext));
+ if (!nut->stream)
+ return AVERROR(ENOMEM);
for (i = 0; i < stream_count; i++)
avformat_new_stream(s, NULL);
@@ -365,6 +387,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);
@@ -374,6 +397,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);
@@ -399,13 +423,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);
- avio_read(bc, st->codec->extradata, st->codec->extradata_size);
+ if (ff_get_extradata(st->codec, bc, st->codec->extradata_size) < 0)
+ return AVERROR(ENOMEM);
}
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
@@ -526,6 +550,14 @@ 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 = st->r_frame_rate.den = 0;
+ continue;
+ }
+
if (metadata && av_strcasecmp(name, "Uses") &&
av_strcasecmp(name, "Depends") && av_strcasecmp(name, "Replaces")) {
if (event_flags)
@@ -546,7 +578,8 @@ 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;
@@ -557,7 +590,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);
@@ -575,8 +608,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;
@@ -584,6 +617,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;
@@ -592,23 +638,39 @@ static int find_and_decode_index(NUTContext *nut)
int i, j, syncpoint_count;
int64_t filesize = avio_size(bc);
int64_t *syncpoints;
+ uint64_t max_pts;
int8_t *has_keyframe;
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;
+ }
for (i = 0; i < syncpoint_count; i++) {
syncpoints[i] = ffio_read_varlen(bc);
if (syncpoints[i] <= 0)
@@ -628,7 +690,7 @@ 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--)
@@ -648,7 +710,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);
@@ -735,13 +797,123 @@ 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);
return 0;
}
+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;
+
+ 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;
+ get_str(bc, name, sizeof(name));
+ value = get_s(bc);
+
+ if (value == -1) {
+ get_str(bc, str_value, sizeof(str_value));
+ 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;
+
+ get_str(bc, type_str, sizeof(type_str));
+ 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)
{
@@ -781,7 +953,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)
@@ -852,7 +1024,23 @@ 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)
+ return AVERROR_INVALIDDATA;
+ if (read_sm_data(s, bc, pkt, 1, pkt->pos + size) < 0)
+ return AVERROR_INVALIDDATA;
+ 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)
+ return ret;
+ }
+ av_shrink_packet(pkt, nut->header_len[header_idx] + ret);
pkt->stream_index = stream_id;
if (stc->last_flags & FLAG_KEY)
@@ -878,7 +1066,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;
@@ -932,21 +1120,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,
@@ -967,6 +1152,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;
@@ -999,7 +1186,7 @@ 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);
@@ -1031,6 +1218,7 @@ static int nut_read_close(AVFormatContext *s)
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 08907ef..3424e26 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];
@@ -173,6 +171,19 @@ static void build_frame_code(AVFormatContext *s)
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) {
@@ -188,29 +199,32 @@ 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 (codec->has_b_frames) {
pred_count = 5;
@@ -233,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;
@@ -247,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;
@@ -286,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);
@@ -328,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);
@@ -346,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;
@@ -385,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++) {
@@ -408,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);
}
@@ -417,30 +419,17 @@ static int write_streamheader(AVFormatContext *avctx, AVIOContext *bc,
{
NUTContext *nut = avctx->priv_data;
AVCodecContext *codec = st->codec;
- 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);
@@ -516,20 +505,28 @@ 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];
+ 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) {
@@ -575,6 +572,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;
@@ -648,8 +697,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, "
@@ -658,12 +707,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);
@@ -674,8 +722,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);
@@ -712,7 +765,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);
@@ -720,9 +773,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;
}
@@ -740,6 +794,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)
@@ -772,24 +828,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))
@@ -798,15 +994,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++) {
@@ -817,20 +1012,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,
@@ -838,10 +1036,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)
@@ -874,10 +1087,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;
@@ -885,9 +1098,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;
}
@@ -906,9 +1118,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;
@@ -921,27 +1131,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,
@@ -949,19 +1156,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);
@@ -976,6 +1205,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 9336912..e7f0eea 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
*/
@@ -72,7 +72,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);
@@ -86,11 +86,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;
@@ -195,6 +192,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
@@ -236,7 +236,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);
@@ -262,10 +262,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);
@@ -303,6 +302,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"),
@@ -310,5 +384,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 ae9da3a..8f146e4 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"
@@ -47,6 +48,7 @@ static const struct ogg_codec * const ogg_codecs[] = {
&ff_flac_codec,
&ff_celt_codec,
&ff_opus_codec,
+ &ff_vp8_codec,
&ff_old_dirac_codec,
&ff_old_flac_codec,
&ff_ogm_video_codec,
@@ -56,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)
{
@@ -73,6 +78,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;
@@ -95,9 +102,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,
@@ -114,9 +122,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;
@@ -131,8 +141,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->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;
@@ -150,38 +168,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;
- memset(ogg->streams + idx, 0, sizeof(*ogg->streams));
+ if (!ogg->state || ogg->state->streams[i].private != os->private)
+ av_freep(&ogg->streams[i].private);
- os = ogg->streams + idx;
+ /* 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
+}
+
+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;
}
@@ -203,7 +288,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;
@@ -228,9 +323,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;
@@ -241,8 +342,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);
@@ -252,28 +355,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)
@@ -290,8 +384,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;
@@ -323,13 +423,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;
@@ -339,6 +446,8 @@ static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
int segp = 0, psize = 0;
av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
+ if (sid)
+ *sid = -1;
do {
idx = ogg->curidx;
@@ -389,8 +498,6 @@ static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
}
} while (!complete);
- av_dlog(s, "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,
@@ -434,8 +541,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)
@@ -444,6 +551,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;
}
@@ -462,43 +571,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_dlog(s, "found headers\n");
-
- return 0;
-}
-
static int ogg_get_length(AVFormatContext *s)
{
struct ogg *ogg = s->priv_data;
int i;
int64_t size, end;
+ int streams_left=0;
if (!s->pb->seekable)
return 0;
@@ -514,19 +592,44 @@ static int ogg_get_length(AVFormatContext *s)
ogg_save(s);
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);
+ ogg_save (s);
+ avio_seek (s->pb, s->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;
}
@@ -536,14 +639,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;
}
@@ -551,22 +658,41 @@ 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_dlog(s, "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
ogg_get_length(s);
- //fill the extradata in the per codec callbacks
return 0;
}
@@ -600,14 +726,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 {
@@ -621,6 +773,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;
@@ -639,7 +792,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,
@@ -648,22 +826,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;
}
@@ -674,6 +868,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
@@ -705,5 +904,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 b8f0a8b..7dc7716 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;
@@ -121,6 +127,7 @@ extern const struct ogg_codec ff_skeleton_codec;
extern const struct ogg_codec ff_speex_codec;
extern const struct ogg_codec ff_theora_codec;
extern const struct ogg_codec ff_vorbis_codec;
+extern const struct ogg_codec ff_vp8_codec;
int ff_vorbis_comment(AVFormatContext *ms, AVDictionary **m,
const uint8_t *buf, int size, int parse_picture);
diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c
index c7d6491..dda229e 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
*/
@@ -77,6 +77,8 @@ typedef struct {
#define PARAM AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
+ { "oggpagesize", "Set preferred Ogg page size.",
+ offsetof(OGGContext, pref_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, MAX_PAGE_SIZE, AV_OPT_FLAG_ENCODING_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",
@@ -84,9 +86,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,\
@@ -139,6 +141,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)
@@ -209,9 +216,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,7 +282,7 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st,
static uint8_t *ogg_write_vorbiscomment(int offset, int bitexact,
int *header_len, AVDictionary **m, int framing_bit)
{
- const char *vendor = bitexact ? "Libav" : LIBAVFORMAT_IDENT;
+ const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT;
int size;
uint8_t *p, *p0;
@@ -410,7 +422,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)
@@ -420,12 +432,13 @@ static int ogg_write_header(AVFormatContext *s)
AVStream *st = s->streams[i];
unsigned serial_num = i;
- 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 &&
@@ -441,6 +454,9 @@ static int ogg_write_header(AVFormatContext *s)
return -1;
}
oggstream = av_mallocz(sizeof(*oggstream));
+ if (!oggstream)
+ return AVERROR(ENOMEM);
+
oggstream->page.stream_index = i;
if (!(s->flags & AVFMT_FLAG_BITEXACT))
@@ -454,11 +470,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);
@@ -467,7 +485,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);
@@ -476,7 +494,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);
@@ -497,7 +515,7 @@ static int ogg_write_header(AVFormatContext *s)
}
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)
@@ -620,7 +638,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);
@@ -629,12 +647,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,
@@ -648,7 +673,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"),
@@ -666,7 +691,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"),
@@ -683,7 +708,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 7084e76..2c0c511 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 55a0b59..10fb07e 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 57bba68..c7fb446 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 913282a..54024e0 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 5931ab5..c8b02fa 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 5333e17..6c2105f 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 b2779e7..9b5c65f 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 d78f02d..91c70df 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 b2f9c8b..dd44337 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
new file mode 100644
index 0000000..5959d32
--- /dev/null
+++ b/libavformat/oggparsevp8.c
@@ -0,0 +1,137 @@
+/*
+ * On2 VP8 parser for Ogg
+ * 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/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+#include "oggdec.h"
+
+#define VP8_HEADER_SIZE 26
+
+static int vp8_header(AVFormatContext *s, int idx)
+{
+ struct ogg *ogg = s->priv_data;
+ struct ogg_stream *os = ogg->streams + idx;
+ uint8_t *p = os->buf + os->pstart;
+ AVStream *st = s->streams[idx];
+ AVRational framerate;
+
+ if (os->psize < 7 || p[0] != 0x4f)
+ return 0;
+
+ switch (p[5]){
+ case 0x01:
+ if (os->psize < VP8_HEADER_SIZE) {
+ av_log(s, AV_LOG_ERROR, "Invalid OggVP8 header packet");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (p[6] != 1) {
+ av_log(s, AV_LOG_WARNING, "Unknown OggVP8 version %d.%d\n", p[6], p[7]);
+ return AVERROR_INVALIDDATA;
+ }
+
+ st->codec->width = AV_RB16(p + 8);
+ st->codec->height = AV_RB16(p + 10);
+ st->sample_aspect_ratio.num = AV_RB24(p + 12);
+ st->sample_aspect_ratio.den = AV_RB24(p + 15);
+ framerate.den = AV_RB32(p + 18);
+ framerate.num = AV_RB32(p + 22);
+
+ avpriv_set_pts_info(st, 64, framerate.num, framerate.den);
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_VP8;
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ break;
+ case 0x02:
+ if (p[6] != 0x20)
+ return AVERROR_INVALIDDATA;
+ ff_vorbis_stream_comment(s, st, p + 7, os->psize - 7);
+ break;
+ default:
+ av_log(s, AV_LOG_ERROR, "Unknown VP8 header type 0x%02X\n", p[5]);
+ return AVERROR_INVALIDDATA;
+ }
+
+ return 1;
+}
+
+static uint64_t vp8_gptopts(AVFormatContext *s, int idx, uint64_t granule, int64_t *dts)
+{
+ struct ogg *ogg = s->priv_data;
+ struct ogg_stream *os = ogg->streams + idx;
+
+ uint64_t pts = (granule >> 32);
+ uint32_t dist = (granule >> 3) & 0x07ffffff;
+
+ if (!dist)
+ os->pflags |= AV_PKT_FLAG_KEY;
+
+ if (dts)
+ *dts = pts;
+
+ return pts;
+}
+
+static int vp8_packet(AVFormatContext *s, int idx)
+{
+ struct ogg *ogg = s->priv_data;
+ struct ogg_stream *os = ogg->streams + idx;
+ uint8_t *p = os->buf + os->pstart;
+
+ if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
+ int seg;
+ int duration;
+ uint8_t *last_pkt = p;
+ uint8_t *next_pkt;
+
+ seg = os->segp;
+ duration = (last_pkt[0] >> 4) & 1;
+ next_pkt = last_pkt += os->psize;
+ for (; seg < os->nsegs; seg++) {
+ if (os->segments[seg] < 255) {
+ duration += (last_pkt[0] >> 4) & 1;
+ last_pkt = next_pkt + os->segments[seg];
+ }
+ next_pkt += os->segments[seg];
+ }
+ os->lastpts = os->lastdts = vp8_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;
+ }
+ }
+
+ if (os->psize > 0)
+ os->pduration = (p[0] >> 4) & 1;
+
+ return 0;
+}
+
+const struct ogg_codec ff_vp8_codec = {
+ .magic = "OVP80",
+ .magicsize = 5,
+ .header = vp8_header,
+ .packet = vp8_packet,
+ .gptopts = vp8_gptopts,
+ .nb_header = 1,
+};
diff --git a/libavformat/oma.c b/libavformat/oma.c
index 27b5988..2702867 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 9a35da2..e2a187b 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 9d9c726..9f3d3aa 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
*/
@@ -174,13 +174,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 += 44L + taglen;
- if (datalen << 4 > size - pos)
+ if (pos + (((uint64_t)datalen) << 4) > size)
return -1;
av_des_init(&av_des, n_val, 192, 1);
@@ -299,7 +295,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;
@@ -355,12 +351,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
@@ -390,7 +384,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:
@@ -456,7 +450,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;
diff --git a/libavformat/omaenc.c b/libavformat/omaenc.c
index bfd552a..fe0669f 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 a5646df..e0d6df6 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)
@@ -111,6 +120,11 @@ AVFormatContext *avformat_alloc_context(void)
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 8372ef3..40f1e0a 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,37 @@
#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"},
+{"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 +73,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 650baea..f9d6eea 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"
diff --git a/libavformat/os_support.h b/libavformat/os_support.h
index f751d41..bc72e96 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
*/
@@ -33,11 +33,17 @@
#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__) */
@@ -48,8 +54,16 @@
#include <io.h>
#endif
#define mkdir(a, b) _mkdir(a)
-#else
-#include <sys/stat.h>
+#endif
+
+#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)
diff --git a/libavformat/paf.c b/libavformat/paf.c
index 18bf353..618994c 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 {
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 892e8ca..a57a4b6 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
*/
@@ -23,6 +23,24 @@
#include "avformat.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 30cbc86..9af36d5 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 1bbbc66..2584c33 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 e45ab84..3e4f308 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 0000000..5129b70
--- /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 8ae147f..ec966b3 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 e662ed7..fd50e54 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 3abfc18..18ab1cd 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 {
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 0000000..c678046
--- /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 30d362f..4d42197 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
*/
@@ -102,11 +102,9 @@ 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");
return AVERROR_INVALIDDATA;
@@ -141,7 +139,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 ecc85d3..7d6802f 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 74a1f2b..0719fb6 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_dlog(s, "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_dlog(s, "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_dlog(s, "seek frame num %d timestamp %"PRId64"\n",
frame_num, sample_time);
diff --git a/libavformat/rawdec.c b/libavformat/rawdec.c
index 09fdbc3..69b95bc 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,85 +82,51 @@ 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;
}
+static 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,
+};
+#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,
@@ -174,7 +136,73 @@ AVInputFormat ff_latm_demuxer = {
#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
@@ -214,5 +242,5 @@ AVInputFormat ff_shorten_demuxer = {
#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 a548778..328a4fb 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[];
@@ -49,7 +49,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 +58,13 @@ 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)
+
#endif /* AVFORMAT_RAWDEC_H */
diff --git a/libavformat/rawenc.c b/libavformat/rawenc.c
index eb50626..8b50fe1 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,
};
@@ -164,6 +208,7 @@ AVOutputFormat ff_h264_muxer = {
.extensions = "h264",
.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,
};
@@ -222,10 +269,11 @@ AVOutputFormat ff_mlp_muxer = {
AVOutputFormat ff_mpeg1video_muxer = {
.name = "mpeg1video",
.long_name = NULL_IF_CONFIG_SMALL("raw MPEG-1 video"),
- .mime_type = "video/x-mpeg",
+ .mime_type = "video/mpeg",
.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 daa5489..b552309 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 5f372c9..cbcae43 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 304f4cf..158a821 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;
- ffio_init_context(&pb, buf, len, 0, NULL, NULL, NULL, NULL);
+ ffio_init_context(&pb, (uint8_t *)buf, len, 0, NULL, NULL, NULL, NULL);
flags = (flags & RTP_FLAG_KEY) ? 2 : 0;
res = ff_rm_parse_packet (rdt->rmctx, &pb, st, rdt->rmst[st->index], len, pkt,
&seq, flags, *timestamp);
@@ -523,18 +523,27 @@ static PayloadContext *
rdt_new_context (void)
{
PayloadContext *rdt = av_mallocz(sizeof(PayloadContext));
- int ret;
if (!rdt)
return NULL;
- ret = avformat_open_input(&rdt->rmctx, "", &ff_rdt_demuxer, NULL);
- if (ret < 0) {
- av_free(rdt);
- return NULL;
- }
+
+ rdt->rmctx = avformat_alloc_context();
+ if (!rdt->rmctx)
+ av_freep(&rdt);
return rdt;
}
+static int
+rdt_init_context (AVFormatContext *s, int st_index, PayloadContext *rdt)
+{
+ int ret;
+
+ if ((ret = ff_copy_whitelists(rdt->rmctx, s)) < 0)
+ return ret;
+
+ return avformat_open_input(&rdt->rmctx, "", &ff_rdt_demuxer, NULL);
+}
+
static void
rdt_free_context (PayloadContext *rdt)
{
@@ -559,6 +568,7 @@ static RTPDynamicProtocolHandler rdt_ ## n ## _handler = { \
.codec_id = AV_CODEC_ID_NONE, \
.parse_sdp_a_line = rdt_parse_sdp_line, \
.alloc = rdt_new_context, \
+ .init = rdt_init_context, \
.free = rdt_free_context, \
.parse_packet = rdt_parse_packet \
}
diff --git a/libavformat/rdt.h b/libavformat/rdt.h
index bd16890..ce6026f 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 0000000..fff85d6
--- /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 0000000..13a7b37
--- /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 6c5b582..8b8c81a 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
*/
@@ -71,11 +71,12 @@ int ff_replaygain_export_raw(AVStream *st, int32_t tg, uint32_t tp,
{
AVPacketSideData *sd, *tmp;
AVReplayGain *replaygain;
+ int i;
if (tg == INT32_MIN && ag == INT32_MIN)
return 0;
- for (int i = 0; i < st->nb_side_data; i++) {
+ for (i = 0; i < st->nb_side_data; i++) {
AVPacketSideData *src_sd = &st->side_data[i];
if (src_sd->type == AV_PKT_DATA_REPLAYGAIN)
diff --git a/libavformat/replaygain.h b/libavformat/replaygain.h
index ea56c17..ceacb21 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 b91f8f1..8d7b1c2 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') },
@@ -39,6 +42,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_H264, MKTAG('V', '2', '6', '4') }, /* CCTV recordings */
{ 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('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') },
@@ -50,8 +54,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') },
@@ -90,7 +93,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') },
@@ -178,7 +180,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 */
@@ -238,7 +240,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') },
@@ -276,6 +282,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') },
@@ -314,6 +321,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_TARGA, MKTAG('t', 'g', 'a', ' ') },
{ AV_CODEC_ID_PNG, MKTAG('M', 'P', 'N', 'G') },
{ AV_CODEC_ID_PNG, MKTAG('P', 'N', 'G', '1') },
+ { AV_CODEC_ID_PNG, MKTAG('p', 'n', 'g', ' ') }, /* ImageJ */
{ AV_CODEC_ID_CLJR, MKTAG('C', 'L', 'J', 'R') },
{ AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
{ AV_CODEC_ID_RPZA, MKTAG('a', 'z', 'p', 'r') },
@@ -325,16 +333,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') },
@@ -343,9 +355,12 @@ 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') },
+ { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '5') },
{ AV_CODEC_ID_FIC, MKTAG('F', 'I', 'C', 'V') },
{ AV_CODEC_ID_PRORES, MKTAG('A', 'P', 'C', 'N') },
{ AV_CODEC_ID_NONE, 0 }
@@ -364,13 +379,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 },
@@ -386,6 +403,7 @@ const AVCodecTag ff_codec_wav_tags[] = {
{ AV_CODEC_ID_ADPCM_IMA_WAV, 0x0069 },
{ AV_CODEC_ID_METASOUND, 0x0075 },
{ 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 },
@@ -404,7 +422,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 },
@@ -445,3 +467,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 ddfb0fa..88a77b0 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);
-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);
@@ -91,10 +105,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 *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 74f93ac..09fee9d 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);
@@ -105,14 +110,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)
+ if (ff_get_extradata(codec, pb, cbSize) < 0)
return AVERROR(ENOMEM);
- avio_read(pb, codec->extradata, codec->extradata_size);
size -= cbSize;
}
@@ -132,7 +133,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 +156,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 +191,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 +222,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 +232,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 81b3b2d..5e85800 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, 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,
@@ -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 *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 5d30bf8..d354339 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 761be3f..0591a17 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 a06ea01..a72e8b7 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,
- int codec_data_size);
+ 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 38fb1ec..96b9e7f 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"
@@ -86,12 +88,8 @@ static int rm_read_extradata(AVIOContext *pb, AVCodecContext *avctx, unsigned si
{
if (size >= 1<<24)
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 +97,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);
@@ -128,9 +127,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")
@@ -140,6 +142,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;
@@ -149,6 +153,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 */
@@ -158,7 +163,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 */
@@ -175,6 +184,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 */
@@ -197,13 +207,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;
@@ -223,6 +237,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);
@@ -240,27 +255,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:
@@ -268,9 +279,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);
@@ -284,7 +305,7 @@ 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, int codec_data_size)
+ AVStream *st, RMStream *rst, int codec_data_size, const uint8_t *mime)
{
unsigned int v;
int size;
@@ -294,6 +315,21 @@ ff_rm_read_mdpr_codecdata (AVFormatContext *s, AVIOContext *pb,
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))
@@ -307,11 +343,38 @@ 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')) {
fail1:
- av_log(st->codec, AV_LOG_ERROR, "Unsupported video codec\n");
+ av_log(s, AV_LOG_WARNING, "Unsupported stream type %08x\n", v);
goto skip;
}
st->codec->codec_tag = avio_rl32(pb);
@@ -334,6 +397,9 @@ 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;
@@ -428,7 +494,7 @@ 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;
tag = avio_rl32(pb);
@@ -443,7 +509,7 @@ static int rm_read_header(AVFormatContext *s)
avio_skip(pb, tag_size - 8);
for(;;) {
- if (pb->eof_reached)
+ if (avio_feof(pb))
return -1;
tag = avio_rl32(pb);
tag_size = avio_rb32(pb);
@@ -465,7 +531,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 */
@@ -489,12 +556,14 @@ 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 (ff_rm_read_mdpr_codecdata(s, s->pb, st, st->priv_data,
- avio_rb32(pb)) < 0)
+ avio_rb32(pb), mime) < 0)
return -1;
break;
case MKTAG('D', 'A', 'T', 'A'):
@@ -547,7 +616,7 @@ static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_
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){
@@ -614,8 +683,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 silcense compiler warning
int type;
+ int ret;
hdr = avio_r8(pb); len--;
type = hdr >> 6;
@@ -628,34 +699,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;
@@ -664,12 +748,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;
@@ -714,17 +804,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) ||
@@ -744,14 +846,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;
}
@@ -810,7 +912,7 @@ 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)
@@ -837,7 +939,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;
@@ -846,7 +948,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) {
@@ -865,11 +969,13 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
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)
@@ -921,7 +1027,9 @@ 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;
@@ -953,6 +1061,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"),
@@ -962,6 +1082,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 9ff9f31..2e50ed3 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"
@@ -217,8 +217,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);
@@ -309,6 +309,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];
diff --git a/libavformat/rmsipr.c b/libavformat/rmsipr.c
index 89fbd0e..14ec8ea 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 c8d3d0a..2837336 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 b72b8d0..c1229e8 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)
@@ -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];
diff --git a/libavformat/rsd.c b/libavformat/rsd.c
new file mode 100644
index 0000000..bb2f3bc
--- /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[5];
+
+ 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 4ce61e7..7d88f0f 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 e3e88ea..1f65dd9 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 1612572..6e3ea0a 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 8ebcf81..6da9594 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 dc7ba5b..8fc8040 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 dfdd029..2312527 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 2799433..590a8c8 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 38c2f3d..7d6734d 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 5de8bde..cf262fc 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 34c68fb..0334ba5 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 37fbb5f..92172dc 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 149c153..a082b45 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 9511946..ba5adef 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
@@ -322,7 +322,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 +419,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 +1768,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 +2435,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;
@@ -2591,7 +2597,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 +2612,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 +2717,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 +2741,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) {
diff --git a/libavformat/rtp.c b/libavformat/rtp.c
index 0a3c411..4d41350 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 feaf167..66a4f3a 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 b5e5200..33205aa 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,
@@ -66,6 +72,7 @@ void ff_register_rtp_dynamic_payload_handlers(void)
ff_register_dynamic_payload_handler(&ff_g726_24_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_g726_32_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_g726_40_dynamic_handler);
+ ff_register_dynamic_payload_handler(&ff_h261_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_h263_1998_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_h263_2000_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_h263_rfc2190_dynamic_handler);
@@ -91,6 +98,7 @@ void ff_register_rtp_dynamic_payload_handlers(void)
ff_register_dynamic_payload_handler(&ff_theora_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_vorbis_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_vp8_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);
@@ -840,7 +848,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 46b08ce..7b41cc4 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
*/
@@ -173,9 +173,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_amr.c b/libavformat/rtpdec_amr.c
index 86348bb..31acfe7 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 61b1419..44c0a24 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"
@@ -102,6 +103,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 +114,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 +199,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_formats.h b/libavformat/rtpdec_formats.h
index 02335ed..803410e 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
*/
@@ -31,6 +31,10 @@
*/
int ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p);
+int ff_h261_handle_packet(AVFormatContext *ctx, PayloadContext *data,
+ AVStream *st, AVPacket *pkt, uint32_t *timestamp,
+ const uint8_t *buf, int len, uint16_t seq, int flags);
+
int ff_h263_handle_packet(AVFormatContext *ctx, PayloadContext *data,
AVStream *st, AVPacket *pkt, uint32_t *timestamp,
const uint8_t *buf, int len, uint16_t seq, int flags);
@@ -41,6 +45,7 @@ extern RTPDynamicProtocolHandler ff_g726_16_dynamic_handler;
extern RTPDynamicProtocolHandler ff_g726_24_dynamic_handler;
extern RTPDynamicProtocolHandler ff_g726_32_dynamic_handler;
extern RTPDynamicProtocolHandler ff_g726_40_dynamic_handler;
+extern RTPDynamicProtocolHandler ff_h261_dynamic_handler;
extern RTPDynamicProtocolHandler ff_h263_1998_dynamic_handler;
extern RTPDynamicProtocolHandler ff_h263_2000_dynamic_handler;
extern RTPDynamicProtocolHandler ff_h263_rfc2190_dynamic_handler;
diff --git a/libavformat/rtpdec_g726.c b/libavformat/rtpdec_g726.c
index 7b3f6cb..7e9ef56 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
new file mode 100644
index 0000000..43244bb
--- /dev/null
+++ b/libavformat/rtpdec_h261.c
@@ -0,0 +1,203 @@
+/*
+ * RTP parser for H.261 payload format (RFC 4587)
+ * Copyright (c) 2014 Thomas Volkert <thomas@homer-conferencing.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 "avformat.h"
+#include "rtpdec_formats.h"
+#include "libavcodec/get_bits.h"
+
+#define RTP_H261_PAYLOAD_HEADER_SIZE 4
+
+struct PayloadContext {
+ AVIOContext *buf;
+ uint8_t endbyte;
+ int endbyte_bits;
+ uint32_t timestamp;
+};
+
+static av_cold PayloadContext *h261_new_context(void)
+{
+ return av_mallocz(sizeof(PayloadContext));
+}
+
+static void h261_free_dyn_buffer(AVIOContext **dyn_buf)
+{
+ uint8_t *ptr_dyn_buffer;
+ avio_close_dyn_buf(*dyn_buf, &ptr_dyn_buffer);
+ av_free(ptr_dyn_buffer);
+ *dyn_buf = NULL;
+}
+
+static av_cold void h261_free_context(PayloadContext *pl_ctx)
+{
+ /* return if context is invalid */
+ if (!pl_ctx)
+ return;
+
+ /* free buffer if it is valid */
+ if (pl_ctx->buf) {
+ h261_free_dyn_buffer(&pl_ctx->buf);
+ }
+
+ /* free context */
+ av_free(pl_ctx);
+}
+
+static av_cold int h261_init(AVFormatContext *ctx, int st_index,
+ PayloadContext *data)
+{
+ //av_log(ctx, AV_LOG_DEBUG, "h261_init() for stream %d\n", st_index);
+
+ if (st_index < 0)
+ return 0;
+
+ ctx->streams[st_index]->need_parsing = AVSTREAM_PARSE_FULL;
+
+ return 0;
+}
+
+int ff_h261_handle_packet(AVFormatContext *ctx, PayloadContext *data,
+ AVStream *st, AVPacket *pkt, uint32_t *timestamp,
+ const uint8_t *buf, int len, uint16_t seq, int flags)
+{
+ int sbit, ebit, gobn, mbap, quant;
+ int res;
+
+ /* drop data of previous packets in case of non-continuous (loss) packet stream */
+ if (data->buf && data->timestamp != *timestamp) {
+ h261_free_dyn_buffer(&data->buf);
+ }
+
+ /* sanity check for size of input packet: 1 byte payload at least */
+ if (len < RTP_H261_PAYLOAD_HEADER_SIZE + 1) {
+ av_log(ctx, AV_LOG_ERROR, "Too short RTP/H.261 packet, got %d bytes\n", len);
+ return AVERROR_INVALIDDATA;
+ }
+
+ /*
+ decode the H.261 payload header according to section 4.1 of RFC 4587:
+ (uses 4 bytes between RTP header and H.261 stream per packet)
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |SBIT |EBIT |I|V| GOBN | MBAP | QUANT | HMVD | VMVD |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Start bit position (SBIT): 3 bits
+ End bit position (EBIT): 3 bits
+ INTRA-frame encoded data (I): 1 bit
+ Motion Vector flag (V): 1 bit
+ GOB number (GOBN): 4 bits
+ Macroblock address predictor (MBAP): 5 bits
+ Quantizer (QUANT): 5 bits
+ Horizontal motion vector data (HMVD): 5 bits
+ Vertical motion vector data (VMVD): 5 bits
+
+ */
+ sbit = (buf[0] >> 5) & 0x07;
+ ebit = (buf[0] >> 2) & 0x07;
+ gobn = (buf[1] >> 4) & 0x0f;
+ mbap = ((buf[1] << 1) & 0x1e) | ((buf[2] >> 7) & 0x01);
+ quant = (buf[2] >> 2) & 0x1f;
+
+ /* pass the H.261 payload header and continue with the actual payload */
+ buf += RTP_H261_PAYLOAD_HEADER_SIZE;
+ len -= RTP_H261_PAYLOAD_HEADER_SIZE;
+
+ /* start frame buffering with new dynamic buffer */
+ if (!data->buf) {
+ /* sanity check: a new frame starts with gobn=0, sbit=0, mbap=0, uqnat=0 */
+ if (!gobn && !sbit && !mbap && !quant){
+ res = avio_open_dyn_buf(&data->buf);
+ if (res < 0)
+ return res;
+ /* update the timestamp in the frame packet with the one from the RTP packet */
+ data->timestamp = *timestamp;
+ } else {
+ /* frame not started yet, need more packets */
+ return AVERROR(EAGAIN);
+ }
+ }
+
+ /* do the "byte merging" at the boundaries of two consecutive frame fragments */
+ if (data->endbyte_bits || sbit) {
+ if (data->endbyte_bits == sbit) {
+ data->endbyte |= buf[0] & (0xff >> sbit);
+ data->endbyte_bits = 0;
+ buf++;
+ len--;
+ avio_w8(data->buf, data->endbyte);
+ } else {
+ /* ebit/sbit values inconsistent, assuming packet loss */
+ GetBitContext gb;
+ init_get_bits(&gb, buf, len*8 - ebit);
+ skip_bits(&gb, sbit);
+ if (data->endbyte_bits) {
+ data->endbyte |= get_bits(&gb, 8 - data->endbyte_bits);
+ avio_w8(data->buf, data->endbyte);
+ }
+ while (get_bits_left(&gb) >= 8)
+ avio_w8(data->buf, get_bits(&gb, 8));
+ data->endbyte_bits = get_bits_left(&gb);
+ if (data->endbyte_bits)
+ data->endbyte = get_bits(&gb, data->endbyte_bits) <<
+ (8 - data->endbyte_bits);
+ ebit = 0;
+ len = 0;
+ }
+ }
+ if (ebit) {
+ if (len > 0)
+ avio_write(data->buf, buf, len - 1);
+ data->endbyte_bits = 8 - ebit;
+ data->endbyte = buf[len - 1] & (0xff << ebit);
+ } else {
+ avio_write(data->buf, buf, len);
+ }
+
+ /* RTP marker bit means: last fragment of current frame was received;
+ otherwise, an additional fragment is needed for the current frame */
+ if (!(flags & RTP_FLAG_MARKER))
+ return AVERROR(EAGAIN);
+
+ /* write the completed last byte from the "byte merging" */
+ if (data->endbyte_bits)
+ avio_w8(data->buf, data->endbyte);
+ data->endbyte_bits = 0;
+
+ /* close frame buffering and create resulting A/V packet */
+ res = ff_rtp_finalize_packet(pkt, &data->buf, st->index);
+ if (res < 0)
+ return res;
+
+ return 0;
+}
+
+RTPDynamicProtocolHandler ff_h261_dynamic_handler = {
+ .enc_name = "H261",
+ .codec_type = AVMEDIA_TYPE_VIDEO,
+ .codec_id = AV_CODEC_ID_H261,
+ .init = h261_init,
+ .parse_packet = ff_h261_handle_packet,
+ .alloc = h261_new_context,
+ .free = h261_free_context,
+ .static_payload_id = 31,
+};
diff --git a/libavformat/rtpdec_h263.c b/libavformat/rtpdec_h263.c
index b371491..ae4cc27 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 116db75..a227901 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 abf1f39..4dbbae7 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
*/
@@ -71,7 +71,7 @@ static int sdp_parse_fmtp_config_h264(AVFormatContext *s,
{
AVCodecContext *codec = stream->codec;
assert(codec->codec_id == AV_CODEC_ID_H264);
- assert(h264_data != NULL);
+ assert(h264_data);
if (!strcmp(attr, "packetization-mode")) {
av_log(s, AV_LOG_DEBUG, "RTP Packetization Mode: %d\n", atoi(value));
diff --git a/libavformat/rtpdec_hevc.c b/libavformat/rtpdec_hevc.c
index 3ed7cac..ac4c765 100644
--- a/libavformat/rtpdec_hevc.c
+++ b/libavformat/rtpdec_hevc.c
@@ -2,20 +2,20 @@
* 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
*
*/
@@ -389,6 +389,7 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
av_dlog(ctx, " 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) {
new_nal_header[0] = (rtp_pl[0] & 0x81) | (fu_type << 1);
new_nal_header[1] = rtp_pl[1];
@@ -417,11 +418,14 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
memcpy(pkt->data, buf, len);
}
} else {
- /* 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);
- res = 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);
+ res = AVERROR_INVALIDDATA;
+ } else {
+ res = AVERROR(EAGAIN);
+ }
}
break;
diff --git a/libavformat/rtpdec_ilbc.c b/libavformat/rtpdec_ilbc.c
index bff47c7..aa1579f 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 ed9c86c..ccd80ad 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
*/
@@ -106,7 +106,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;
@@ -132,6 +133,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));
@@ -226,7 +233,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");
@@ -242,6 +249,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,
@@ -332,7 +349,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 6ab3f78..3896482 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
*/
@@ -130,10 +130,7 @@ static int parse_fmtp_config(AVStream *st, 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_mpeg12.c b/libavformat/rtpdec_mpeg12.c
index b059fcf..d73ff1e 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 4aedeea..53921f2 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
*/
@@ -105,10 +105,8 @@ static int parse_fmtp_config(AVCodecContext *codec, 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)
+ if (ff_alloc_extradata(codec, len))
return AVERROR(ENOMEM);
- codec->extradata_size = len;
ff_hex_to_data(codec->extradata, value);
return 0;
}
@@ -139,7 +137,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;
diff --git a/libavformat/rtpdec_mpegts.c b/libavformat/rtpdec_mpegts.c
index b3ef261..0c2b717 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
*/
@@ -40,14 +40,14 @@ static void mpegts_free_context(PayloadContext *data)
if (!data)
return;
if (data->ts)
- ff_mpegts_parse_close(data->ts);
+ avpriv_mpegts_parse_close(data->ts);
av_free(data);
}
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;
@@ -72,8 +72,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;
@@ -83,8 +83,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 45a89ae..eebcdd0 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 0d7b5bb..e1dd62f 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);
@@ -193,7 +193,7 @@ static int qdm2_restore_block(PayloadContext *qdm, AVStream *st, AVPacket *pkt)
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 2d9c603..58253b6 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
*/
@@ -71,7 +71,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 aa880e5..98e8b58 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
*/
@@ -28,6 +28,7 @@
#include <string.h>
#include "libavutil/intreadwrite.h"
+#include "internal.h"
#include "rtp.h"
#include "rtpdec.h"
#include "rtpdec_formats.h"
@@ -60,11 +61,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 fc86ac1..b4b4f22 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_xiph.c b/libavformat/rtpdec_xiph.c
index 9e4fbc5..dc34f9e 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,12 +28,12 @@
*/
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/base64.h"
#include "libavcodec/bytestream.h"
-#include <assert.h>
-
+#include "internal.h"
#include "rtpdec.h"
#include "rtpdec_formats.h"
@@ -192,7 +192,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
@@ -256,7 +256,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;
}
@@ -278,7 +278,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;
}
@@ -289,11 +289,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 647a807..c608dfb 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
*/
@@ -49,6 +49,7 @@ static const AVClass rtp_muxer_class = {
static int is_supported(enum AVCodecID id)
{
switch(id) {
+ case AV_CODEC_ID_H261:
case AV_CODEC_ID_H263:
case AV_CODEC_ID_H263P:
case AV_CODEC_ID_H264:
@@ -97,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;
}
@@ -120,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) {
@@ -563,12 +567,19 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt)
case AV_CODEC_ID_H264:
ff_rtp_send_h264(s1, pkt->data, size);
break;
+ case AV_CODEC_ID_H261:
+ ff_rtp_send_h261(s1, pkt->data, size);
+ break;
case AV_CODEC_ID_H263:
if (s->flags & FF_RTP_FLAG_RFC2190) {
int mb_info_size = 0;
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 4a72a49..4eb98d8 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
@@ -81,6 +81,7 @@ typedef struct RTPMuxContext RTPMuxContext;
void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m);
void ff_rtp_send_h264(AVFormatContext *s1, const uint8_t *buf1, int size);
+void ff_rtp_send_h261(AVFormatContext *s1, const uint8_t *buf1, int size);
void ff_rtp_send_h263(AVFormatContext *s1, const uint8_t *buf1, int size);
void ff_rtp_send_h263_rfc2190(AVFormatContext *s1, const uint8_t *buf1, int size,
const uint8_t *mb_info, int mb_info_size);
@@ -93,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 1b2fa0a..be8f43a 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 73da8c8..bd1c197 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 773a7db..b2aa124 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);
diff --git a/libavformat/rtpenc_chain.h b/libavformat/rtpenc_chain.h
index 4117239..21c27c1 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
new file mode 100644
index 0000000..6f63703
--- /dev/null
+++ b/libavformat/rtpenc_h261.c
@@ -0,0 +1,57 @@
+/*
+ * RTP packetization for H.261 video (RFC 4587)
+ * Copyright (c) 2014 Thomas Volkert <thomas@homer-conferencing.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 "avformat.h"
+#include "rtpenc.h"
+
+void ff_rtp_send_h261(AVFormatContext *s1, const uint8_t *frame_buf, int frame_size)
+{
+ RTPMuxContext *rtp_ctx = s1->priv_data;
+ int processed_frame_size;
+ int last_packet_of_frame;
+ uint8_t *tmp_buf_ptr;
+
+ /* use the default 90 KHz time stamp */
+ rtp_ctx->timestamp = rtp_ctx->cur_timestamp;
+
+ /* continue as long as not all frame data is processed */
+ while (frame_size > 0) {
+ tmp_buf_ptr = rtp_ctx->buf;
+ *tmp_buf_ptr++ = 1; /* V=1 */
+ *tmp_buf_ptr++ = 0;
+ *tmp_buf_ptr++ = 0;
+ *tmp_buf_ptr++ = 0;
+
+ processed_frame_size = FFMIN(rtp_ctx->max_payload_size - 4, frame_size);
+
+ //XXX: parse the h.261 bitstream and improve frame splitting here
+
+ last_packet_of_frame = (processed_frame_size == frame_size);
+
+ memcpy(tmp_buf_ptr, frame_buf, processed_frame_size);
+ tmp_buf_ptr += processed_frame_size;
+
+ ff_rtp_send_data(s1, rtp_ctx->buf, tmp_buf_ptr - rtp_ctx->buf, last_packet_of_frame);
+
+ frame_buf += processed_frame_size;
+ frame_size -= processed_frame_size;
+ }
+}
diff --git a/libavformat/rtpenc_h263.c b/libavformat/rtpenc_h263.c
index 87f0bd7..9cea013 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 f714d01..34b3906 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.c b/libavformat/rtpenc_h264.c
index 395c3a4..d2b2ed8 100644
--- a/libavformat/rtpenc_h264.c
+++ b/libavformat/rtpenc_h264.c
@@ -2,20 +2,20 @@
* RTP packetization for H.264 (RFC3984)
* Copyright (c) 2008 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_hevc.c b/libavformat/rtpenc_hevc.c
index c6474dc..ce661fa 100644
--- a/libavformat/rtpenc_hevc.c
+++ b/libavformat/rtpenc_hevc.c
@@ -2,20 +2,20 @@
* RTP packetizer 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
*/
diff --git a/libavformat/rtpenc_jpeg.c b/libavformat/rtpenc_jpeg.c
index 9d0915b..c353329 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
*/
diff --git a/libavformat/rtpenc_latm.c b/libavformat/rtpenc_latm.c
index 6467677..4430c44 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_mpv.c b/libavformat/rtpenc_mpv.c
index 70248c4..4b45f51 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 d24c8bc..671d245 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 07086b1..bc40cf8 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 "avformat.h"
#include "rtpenc.h"
@@ -72,7 +73,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) {
// send previous packets now; no room for new data
diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c
index d5ecfc8..71e6f03 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
*/
@@ -204,6 +204,7 @@ static void build_udp_url(char *buf, int buf_size,
url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size);
if (connect)
url_add_option(buf, buf_size, "connect=1");
+ 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])
@@ -282,6 +283,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);
@@ -329,19 +331,35 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
}
}
- build_udp_url(buf, sizeof(buf),
- hostname, rtp_port, local_rtp_port, ttl, max_packet_size,
- connect, include_sources, exclude_sources);
- if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
- goto fail;
- if (local_rtp_port>=0 && local_rtcp_port<0)
- local_rtcp_port = ff_udp_get_local_port(s->rtp_hd) + 1;
-
- build_udp_url(buf, sizeof(buf),
- hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size,
- connect, include_sources, exclude_sources);
- 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(buf, sizeof(buf),
+ hostname, rtp_port, local_rtp_port, ttl, max_packet_size,
+ connect, include_sources, exclude_sources);
+ if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
+ goto fail;
+ local_rtp_port = ff_udp_get_local_port(s->rtp_hd);
+ if(local_rtp_port == 65535) {
+ local_rtp_port = -1;
+ continue;
+ }
+ if (local_rtcp_port<0) {
+ local_rtcp_port = local_rtp_port + 1;
+ build_udp_url(buf, sizeof(buf),
+ hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size,
+ connect, include_sources, exclude_sources);
+ if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) {
+ local_rtp_port = local_rtcp_port = -1;
+ continue;
+ }
+ break;
+ }
+ build_udp_url(buf, sizeof(buf),
+ hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size,
+ connect, include_sources, exclude_sources);
+ 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 */
diff --git a/libavformat/rtpproto.h b/libavformat/rtpproto.h
index 7acc80e..5b243fb 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 123d543..43071ea 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,7 +65,7 @@
#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" }, \
@@ -73,37 +74,40 @@
{ "data", "Data", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_DATA}, 0, 0, DEC, "allowed_media_types" }
#define RTSP_REORDERING_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 }
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 },
RTSP_REORDERING_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"),
RTSP_REORDERING_OPTS(),
{ NULL },
};
static const AVOption rtp_options[] = {
- RTSP_FLAG_OPTS("rtp_flags", "RTP flags"),
+ RTSP_FLAG_OPTS("rtp_flags", "set RTP flags"),
RTSP_REORDERING_OPTS(),
{ NULL },
};
@@ -435,7 +439,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
/* no corresponding stream */
if (rt->transport == RTSP_TRANSPORT_RAW) {
if (!rt->ts && CONFIG_RTPDEC)
- rt->ts = ff_mpegts_parse_open(s);
+ rt->ts = avpriv_mpegts_parse_open(s);
} else {
RTPDynamicProtocolHandler *handler;
handler = ff_rtp_handler_find_by_id(
@@ -654,7 +658,7 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
av_free(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;
}
@@ -724,7 +728,7 @@ void ff_rtsp_close_streams(AVFormatContext *s)
avformat_close_input(&rt->asf_ctx);
}
if (rt->ts && CONFIG_RTPDEC)
- ff_mpegts_parse_close(rt->ts);
+ avpriv_mpegts_parse_close(rt->ts);
av_free(rt->p);
av_free(rt->recvbuf);
}
@@ -1243,7 +1247,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);
@@ -1354,10 +1358,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. */
@@ -1411,7 +1411,6 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
&s->interrupt_callback, NULL))
goto rtp_opened;
}
-
av_log(s, AV_LOG_ERROR, "Unable to open an input RTP port\n");
err = AVERROR(EIO);
goto fail;
@@ -1479,7 +1478,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;
}
@@ -1738,12 +1737,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;
@@ -1778,7 +1779,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;
}
@@ -1797,6 +1798,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;
@@ -1804,6 +1807,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);
@@ -1988,7 +1995,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 (rt->ts && CONFIG_RTPDEC) {
- 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;
@@ -2105,6 +2112,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++;
@@ -2117,7 +2134,7 @@ redo:
}
}
} else if (rt->ts && CONFIG_RTPDEC) {
- 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;
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index e83ad54..a9f2f1e 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,9 +392,19 @@ 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;
} RTSPState;
#define RTSP_FLAG_FILTER_SRC 0x1 /**< Filter incoming UDP packets -
@@ -404,6 +414,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 31ab336..0ae490a 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 1f90590..fa7383c 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
*/
@@ -361,8 +361,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");
@@ -530,7 +532,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) {
@@ -562,7 +564,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;
@@ -589,12 +591,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 */
@@ -707,7 +709,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;
@@ -715,10 +717,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;
}
}
}
@@ -753,7 +755,7 @@ redo:
id = buf[0];
len = AV_RB16(buf + 1);
av_dlog(s, "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);
@@ -812,7 +814,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;
}
}
@@ -847,7 +849,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)
@@ -908,6 +910,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,
@@ -917,11 +920,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 3db53ac..e7707bb 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 0000000..948e1ed
--- /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 0280cea..2dd8524 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 89f7f99..f909557 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
*/
@@ -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 a125241..a2347b0 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 62d8e68..0ba9ae5 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 0000000..32822fb
--- /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 9cfaecc..d733895 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
*/
@@ -98,7 +98,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))
@@ -121,7 +121,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;
@@ -296,8 +296,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 a14a239..5bf9de6 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);
@@ -498,6 +498,19 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c,
payload_type, mode, config ? config : "");
break;
}
+ case AV_CODEC_ID_H261:
+ {
+ const char *pic_fmt = NULL;
+ /* only QCIF and CIF are specified as supported in RFC 4587 */
+ if (c->width == 176 && c->height == 144)
+ pic_fmt = "QCIF=1";
+ if (c->width == 352 && c->height == 288)
+ pic_fmt = "CIF=1";
+ av_strlcatf(buff, size, "a=rtpmap:%d H261/90000\r\n", payload_type);
+ if (pic_fmt)
+ av_strlcatf(buff, size, "a=fmtp:%d %s\r\n", payload_type, pic_fmt);
+ break;
+ }
case AV_CODEC_ID_H263:
case AV_CODEC_ID_H263P:
/* a=framesize is required by 3GPP TS 26.234 (PSS). It
@@ -530,7 +543,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)
@@ -667,6 +680,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 0000000..82405f69d
--- /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 143f0b5..8b0611d 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,28 @@ 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 {
+ argc = 1;
+ }
+ }
av_dict_set(&format_opts, "channels", "1", 0);
av_dict_set(&format_opts, "sample_rate", "22050", 0);
@@ -68,7 +87,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 +108,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 +130,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/seek.c b/libavformat/seek.c
index 9be8db9..2368b5e 100644
--- a/libavformat/seek.c
+++ b/libavformat/seek.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Ivan Schreter
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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 @@ int64_t ff_gen_syncpoint_search(AVFormatContext *s,
}
// Initialize syncpoint structures for each stream.
- sync = av_malloc(s->nb_streams * sizeof(AVSyncPoint));
+ sync = av_malloc_array(s->nb_streams, sizeof(AVSyncPoint));
if (!sync)
// cannot allocate helper structure
return -1;
@@ -402,7 +402,7 @@ AVParserState *ff_store_parser_state(AVFormatContext *s)
if (!state)
return NULL;
- state->stream_states = av_malloc(sizeof(AVParserStreamState) * s->nb_streams);
+ state->stream_states = av_malloc_array(s->nb_streams, sizeof(AVParserStreamState));
if (!state->stream_states) {
av_free(state);
return NULL;
diff --git a/libavformat/seek.h b/libavformat/seek.h
index 44cd369..3fa7ae3 100644
--- a/libavformat/seek.h
+++ b/libavformat/seek.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Ivan Schreter
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along 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/segafilm.c b/libavformat/segafilm.c
index 53e2066..b0f0c4e 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
@@ -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 52da6b9..4e0af7c 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -1,169 +1,492 @@
/*
- * 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 {
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
+ ListType 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
+
+ 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;
+
+ 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;
+ AVFormatContext *oc = seg->avf;
+ size_t size;
- 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));
+ if (seg->segment_idx_wrap)
+ seg->segment_idx %= seg->segment_idx_wrap;
+ 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);
+ }
- av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%d\n",
- FFMAX(0, seg->number - seg->size));
+ /* copy modified name in list entry */
+ size = strlen(av_basename(oc->filename)) + 1;
+ if (seg->entry_prefix)
+ size += strlen(seg->entry_prefix);
- 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);
- }
- av_get_frame_filename(buf, sizeof(buf), s->filename, i);
- avio_printf(seg->pb, "%s\n", buf);
- }
+ 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));
- if (last)
- avio_printf(seg->pb, "#EXT-X-ENDLIST\n");
-fail:
- avio_closep(&seg->pb);
- return ret;
+ 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 (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);
+ 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_free(entry->filename);
+ av_freep(&entry);
+ }
+
+ avio_close(seg->list_pb);
+ 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");
+ } 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_close(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;
+}
+
static int open_null_ctx(AVIOContext **ctx)
{
int buf_size = 32768;
@@ -184,31 +507,127 @@ static void close_null_ctx(AVIOContext *pb)
av_free(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 int seg_write_header(AVFormatContext *s)
{
SegmentContext *seg = s->priv_data;
AVFormatContext *oc = NULL;
- int ret, i;
+ AVDictionary *options = NULL;
+ int ret;
- 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->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 ((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);
@@ -227,25 +646,37 @@ 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)
+ &s->interrupt_callback, NULL)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename);
goto fail;
+ }
} else {
if ((ret = open_null_ctx(&oc->pb)) < 0)
goto fail;
}
- if ((ret = avformat_write_header(oc, NULL)) < 0) {
+ 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 (ret < 0) {
avio_close(oc->pb);
goto fail;
}
+ seg->segment_frame_count = 0;
+
+ if (oc->avoid_negative_ts > 0 && s->avoid_negative_ts < 0)
+ s->avoid_negative_ts = 1;
if (!seg->write_header_trailer) {
close_null_ctx(oc->pb);
@@ -254,20 +685,11 @@ static int seg_write_header(AVFormatContext *s)
goto fail;
}
- 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);
- }
- }
-
fail:
+ av_dict_free(&options);
if (ret) {
if (seg->list)
- avio_close(seg->pb);
+ avio_close(seg->list_pb);
if (seg->avf)
avformat_free_context(seg->avf);
}
@@ -277,55 +699,102 @@ 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 (seg->has_video) {
- can_split = st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
- pkt->flags & AV_PKT_FLAG_KEY;
+ 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->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 (ret < 0) {
- if (seg->list)
- avio_close(seg->pb);
- avformat_free_context(oc);
+ if (pkt->stream_index == seg->reference_stream_index) {
+ seg->frame_count++;
+ seg->segment_frame_count++;
}
return ret;
@@ -335,27 +804,35 @@ static int seg_write_trailer(struct AVFormatContext *s)
{
SegmentContext *seg = s->priv_data;
AVFormatContext *oc = seg->avf;
+ SegmentListEntry *cur, *next;
+
int ret;
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);
} 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_close(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_free(cur->filename);
+ av_free(cur);
+ cur = next;
}
-fail:
- avio_close(seg->pb);
avformat_free_context(oc);
return ret;
}
@@ -363,17 +840,39 @@ fail:
#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_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 },
+
{ "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 },
};
@@ -384,14 +883,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 8316388..2046f91 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);
}
@@ -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 8ba7c60..8da6c2f 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
*/
@@ -23,6 +23,7 @@
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
+#include "avio_internal.h"
enum SIFFTags{
TAG_SIFF = MKTAG('S', 'I', 'F', 'F'),
@@ -75,7 +76,7 @@ static int create_audio_stream(AVFormatContext *s, SIFFContext *c)
AVStream *ast;
ast = avformat_new_stream(s, NULL);
if (!ast)
- return -1;
+ return AVERROR(ENOMEM);
ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
ast->codec->codec_id = AV_CODEC_ID_PCM_U8;
ast->codec->channels = 1;
@@ -94,15 +95,15 @@ static int siff_parse_vbv1(AVFormatContext *s, SIFFContext *c, AVIOContext *pb)
if (avio_rl32(pb) != TAG_VBHD){
av_log(s, AV_LOG_ERROR, "Header chunk is missing\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
if(avio_rb32(pb) != 32){
av_log(s, AV_LOG_ERROR, "Header chunk size is incorrect\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
if(avio_rl16(pb) != 1){
av_log(s, AV_LOG_ERROR, "Incorrect header version\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
width = avio_rl16(pb);
height = avio_rl16(pb);
@@ -110,7 +111,7 @@ static int siff_parse_vbv1(AVFormatContext *s, SIFFContext *c, AVIOContext *pb)
c->frames = avio_rl16(pb);
if(!c->frames){
av_log(s, AV_LOG_ERROR, "File contains no frames ???\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
c->bits = avio_rl16(pb);
c->rate = avio_rl16(pb);
@@ -120,13 +121,15 @@ static int siff_parse_vbv1(AVFormatContext *s, SIFFContext *c, AVIOContext *pb)
st = avformat_new_stream(s, NULL);
if (!st)
- return -1;
+ return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_VB;
st->codec->codec_tag = MKTAG('V', 'B', 'V', '1');
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;
@@ -134,7 +137,7 @@ static int siff_parse_vbv1(AVFormatContext *s, SIFFContext *c, AVIOContext *pb)
c->has_audio = !!c->rate;
c->curstrm = -1;
if (c->has_audio && create_audio_stream(s, c) < 0)
- return -1;
+ return AVERROR(ENOMEM);
return 0;
}
@@ -142,11 +145,11 @@ static int siff_parse_soun(AVFormatContext *s, SIFFContext *c, AVIOContext *pb)
{
if (avio_rl32(pb) != TAG_SHDR){
av_log(s, AV_LOG_ERROR, "Header chunk is missing\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
if(avio_rb32(pb) != 8){
av_log(s, AV_LOG_ERROR, "Header chunk size is incorrect\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
avio_skip(pb, 4); //unknown value
c->rate = avio_rl16(pb);
@@ -160,24 +163,25 @@ static int siff_read_header(AVFormatContext *s)
AVIOContext *pb = s->pb;
SIFFContext *c = s->priv_data;
uint32_t tag;
+ int ret;
if (avio_rl32(pb) != TAG_SIFF)
- return -1;
+ return AVERROR_INVALIDDATA;
avio_skip(pb, 4); //ignore size
tag = avio_rl32(pb);
if (tag != TAG_VBV1 && tag != TAG_SOUN){
av_log(s, AV_LOG_ERROR, "Not a VBV file\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
- if (tag == TAG_VBV1 && siff_parse_vbv1(s, c, pb) < 0)
- return -1;
- if (tag == TAG_SOUN && siff_parse_soun(s, c, pb) < 0)
- return -1;
+ if (tag == TAG_VBV1 && (ret = siff_parse_vbv1(s, c, pb)) < 0)
+ return ret;
+ if (tag == TAG_SOUN && (ret = siff_parse_soun(s, c, pb)) < 0)
+ return ret;
if (avio_rl32(pb) != MKTAG('B', 'O', 'D', 'Y')){
av_log(s, AV_LOG_ERROR, "'BODY' chunk is missing\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
avio_skip(pb, 4); //ignore size
@@ -191,7 +195,7 @@ static int siff_read_packet(AVFormatContext *s, AVPacket *pkt)
if (c->has_video){
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);
@@ -203,13 +207,19 @@ static int siff_read_packet(AVFormatContext *s, AVPacket *pkt)
}
if (!c->curstrm){
- size = c->pktsize - c->sndsize;
- if (av_new_packet(pkt, size) < 0)
+ size = c->pktsize - c->sndsize - c->gmcsize - 2;
+ size = ffio_limit(s->pb, size);
+ if(size < 0 || c->pktsize < c->sndsize)
+ return AVERROR_INVALIDDATA;
+ 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{
@@ -225,7 +235,9 @@ static int siff_read_packet(AVFormatContext *s, AVPacket *pkt)
c->cur_frame++;
}else{
size = av_get_packet(s->pb, pkt, c->block_align);
- if(size <= 0)
+ if(!size)
+ return AVERROR_EOF;
+ if(size < 0)
return AVERROR(EIO);
pkt->duration = size;
}
diff --git a/libavformat/smacker.c b/libavformat/smacker.c
index 2fa531b..284cdc1 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 + 4L > 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 52e45e9..4edf5e8 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 c56fe46..995ddf2 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 a9ed28e..99ca2ff 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 551af89..430a497 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 ddd8da7..d6cdf90 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
*/
@@ -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;
@@ -432,7 +432,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
};
@@ -540,7 +540,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,
@@ -595,7 +595,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 1615b45..abb6989 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 92599b1..27d3551 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
*/
@@ -131,16 +131,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 e59531b..f4a12e9 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 ec94675..aec4284 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 4b8955c..95af10c 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 {
@@ -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 777ac47..604141a 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 f5b15eb..fee4ff71 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 2fb9477..7c04afa 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 f3acf48..18afd42 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
*/
@@ -94,7 +94,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,
@@ -397,15 +397,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));
@@ -522,13 +522,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 */
@@ -554,5 +554,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 9db5133..b35e50f 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 0000000..9bb83d6
--- /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 6659bfc..b6e8211 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 18ed177..3189f8f 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 f9b94d7..f9d6b17 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 0000000..b84c7e9
--- /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 0000000..0e84384
--- /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 0000000..67624fc
--- /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, int 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 int 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 0000000..eb719ea
--- /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, int 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 0000000..6b38533
--- /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 0000000..f1b0fdf
--- /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 0000000..48083b2
--- /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 e6adf69..1aa434a 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 8eb3f70..93a094c 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 d7a5314..528bc23 100644
--- a/libavformat/swfdec.c
+++ b/libavformat/swfdec.c
@@ -3,24 +3,26 @@
* 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 "swf.h"
@@ -37,8 +39,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,14 +55,53 @@ static int get_swf_tag(AVIOContext *pb, int *len_ptr)
static int swf_probe(AVProbeData *p)
{
+ 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;
+
+ if (p->buf[3] >= 20)
+ 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)
{
SWFContext *swf = s->priv_data;
@@ -68,14 +109,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 +144,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 +177,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 +208,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 +216,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 +226,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 +276,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 +444,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 +457,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 +514,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 a1fc7b3..3b6f9b3 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)
@@ -427,7 +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, &avio_write);
+ av_fifo_generic_read(swf->audio_fifo, pb, frame_size, (void*)avio_write);
put_swf_end_tag(s);
/* update FIFO */
@@ -456,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)
@@ -486,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);
@@ -500,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 584cbcc..3eb1a8e 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 a242611..0aabc9d 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", OFFSET(timeout), AV_OPT_TYPE_INT, { .i64 = 10000 }, INT_MIN, INT_MAX, .flags = D|E },
- { "listen_timeout", "Bind timeout", 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", 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)
}
} 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 0000000..68063fa
--- /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 0000000..681f943
--- /dev/null
+++ b/libavformat/tee.c
@@ -0,0 +1,497 @@
+/*
+ * 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_close(avf2->pb);
+ avf2->pb = NULL;
+ 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_close(avf2->pb)) < 0)
+ if (!ret_all)
+ ret_all = ret;
+ avf2->pb = NULL;
+ }
+ }
+ 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 e8ca04f..714cec6 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. */
diff --git a/libavformat/tiertexseq.c b/libavformat/tiertexseq.c
index 45300f9..659ba06 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 817aedc..d6a6be3 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,6 +24,9 @@
#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>
@@ -50,9 +53,6 @@
SSL_CTX_free(c->ctx); \
} while (0)
#endif
-#include "network.h"
-#include "os_support.h"
-#include "internal.h"
#if HAVE_POLL_H
#include <poll.h>
#endif
@@ -80,6 +80,7 @@ typedef struct {
#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 },
@@ -137,6 +138,31 @@ static int do_tls_poll(URLContext *h, int ret)
return 0;
}
+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)
{
TLSContext *c = h->priv_data;
@@ -199,8 +225,12 @@ static int tls_open(URLContext *h, const char *uri, int flags)
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);
@@ -218,7 +248,8 @@ static int tls_open(URLContext *h, const char *uri, int flags)
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_ptr(c->session, (gnutls_transport_ptr_t)
(intptr_t) c->fd);
@@ -269,8 +300,11 @@ static int tls_open(URLContext *h, const char *uri, int flags)
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));
@@ -286,7 +320,7 @@ static int tls_open(URLContext *h, const char *uri, int flags)
// 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 103ac4a..ad172f4 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 e5e6e71..7174fd5 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 {
@@ -31,11 +34,19 @@ typedef struct {
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,15 +55,16 @@ 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;
uint64_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);
+ 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);
@@ -60,27 +72,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)) {
+ 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);
@@ -89,17 +105,28 @@ 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) + 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);
framepos += size;
}
- avio_skip(s->pb, 4); // seektable crc
+ crc = ffio_get_checksum(s->pb) ^ UINT32_MAX;
+ if (crc != avio_rl32(s->pb)) {
+ 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;
@@ -107,19 +134,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;
+ if (s->pb->seekable) {
+ int64_t pos = avio_tell(s->pb);
+ ff_ape_parse_tag(s);
+ avio_seek(s->pb, pos, SEEK_SET);
}
- 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);
- }
- avio_seek(s->pb, start_offset, SEEK_SET);
- avio_read(s->pb, st->codec->extradata, st->codec->extradata_size);
return 0;
}
diff --git a/libavformat/tty.c b/libavformat/tty.c
index 0ae1510..909b550 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 {
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 e6522c3..cac37d5 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 bfa8cf2..828b741 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,31 +29,114 @@
#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 {
+ const AVClass *class;
int udp_fd;
int ttl;
+ int udplite_coverage;
int buffer_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 *local_addr;
+ int packet_size;
+ int timeout;
+ struct sockaddr_storage local_addr_storage;
} 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[] = {
+{"buffer_size", "set packet buffer size in bytes", OFFSET(buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E },
+{"localport", "set local port to bind to", OFFSET(local_port), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E },
+{"localaddr", "choose local IP address", OFFSET(local_addr), AV_OPT_TYPE_STRING, {.str = ""}, 0, 0, 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", "set size of UDP packets", OFFSET(packet_size), AV_OPT_TYPE_INT, {.i64 = 1472}, 0, INT_MAX, D|E },
+{"reuse", "explicitly allow or disallow reusing UDP sockets", OFFSET(reuse_socket), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E },
+{"broadcast", "explicitly allow or disallow broadcast destination", OFFSET(is_broadcast), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E },
+{"ttl", "set the time to live value (for 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, D|E },
+/* TODO 'sources', 'block' option */
+{"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 },
+{NULL}
+};
+
+static const AVClass udp_context_class = {
+ .class_name = "udp",
+ .item_name = av_default_item_name,
+ .option = options,
+ .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)
{
@@ -84,14 +167,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;
@@ -113,14 +199,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;
@@ -248,7 +337,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);
@@ -260,17 +349,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[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");
}
@@ -317,6 +409,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
@@ -378,6 +471,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)
{
@@ -416,12 +568,10 @@ 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);
-
- s->ttl = 16;
- s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE;
+ if (!s->buffer_size) /* if not set explicitly */
+ s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE;
p = strchr(uri, '?');
if (p) {
@@ -433,14 +583,28 @@ static int udp_open(URLContext *h, const char *uri, int flags)
s->reuse_socket = 1;
reuse_specified = 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->packet_size = strtol(buf, NULL, 10);
}
if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) {
s->buffer_size = strtol(buf, NULL, 10);
@@ -448,6 +612,13 @@ 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), "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));
}
@@ -461,7 +632,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->packet_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);
@@ -478,10 +661,12 @@ static int udp_open(URLContext *h, const char *uri, int flags)
if ((s->is_multicast || !s->local_port) && (h->flags & AVIO_FLAG_READ))
s->local_port = port;
- udp_fd = udp_socket_create(s, &my_addr, &len, localaddr);
+ udp_fd = udp_socket_create(s, &my_addr, &len, localaddr[0] ? localaddr : s->local_addr);
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.
*/
@@ -491,6 +676,25 @@ 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 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
@@ -526,7 +730,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) {
@@ -544,12 +748,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);
}
@@ -566,10 +778,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++)
@@ -577,10 +822,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);
@@ -588,6 +887,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;
}
@@ -617,8 +917,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;
}
@@ -630,5 +942,18 @@ URLProtocol ff_udp_protocol = {
.url_close = udp_close,
.url_get_file_handle = udp_get_file_handle,
.priv_data_size = sizeof(UDPContext),
+ .priv_data_class = &udp_context_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 0000000..414683f
--- /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 5c6f576..3977065 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 503b36e..a1da82e 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 92cd5f1..acfb0cf 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
*/
diff --git a/libavformat/url.h b/libavformat/url.h
index ca252aa..d0035f3 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 {
@@ -98,7 +99,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 +128,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 +180,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 +269,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
diff --git a/libavformat/urldecode.c b/libavformat/urldecode.c
index 49af9ba..283d912 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 b43f319..cb81ebc 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 3ea0ebd..8da8db4 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -1,21 +1,21 @@
/*
- * 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
*/
@@ -35,12 +35,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"
@@ -52,36 +55,149 @@
/**
* @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(AVFormatContext, format, AVCodec *, video_codec)
+MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, audio_codec)
+MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, subtitle_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)
+
+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 +205,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 +225,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 +259,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;
@@ -151,15 +271,17 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st,
{ "dts", AV_CODEC_ID_DTS, AVMEDIA_TYPE_AUDIO },
{ "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 +291,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->data_offset)
+ ic->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 +371,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,6 +404,10 @@ 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;
@@ -265,6 +419,15 @@ int avformat_open_input(AVFormatContext **ps, const char *filename,
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 +456,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->data_offset)
+ if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset)
s->data_offset = avio_tell(s->pb);
s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
@@ -331,44 +499,138 @@ 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->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++) {
+ 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 +642,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->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->raw_packet_buffer_remaining_size <= 0)
+ if ((err = probe_codec(s, st, NULL)) < 0)
+ return err;
+ if (st->request_probe <= 0) {
s->raw_packet_buffer = pktl->next;
s->raw_packet_buffer_remaining_size += pkt->size;
av_free(pktl);
@@ -409,6 +665,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 +679,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->raw_packet_buffer, pkt, &s->raw_packet_buffer_end);
@@ -451,8 +716,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.
*/
@@ -460,27 +737,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) {
+ *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
@@ -501,43 +783,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->packet_buffer_end)
+ return s->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->packet_buffer;
+ AVPacketList *pktl = s->packet_buffer ? s->packet_buffer : s->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 (i = 0; i<MAX_REORDER_DELAY+1; i++)
+ pts_buffer[i] = AV_NOPTS_VALUE;
- for (; pktl; pktl = pktl->next) {
+ 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;
}
@@ -545,12 +922,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->packet_buffer;
- int64_t cur_dts = 0;
+ AVPacketList *pktl = s->packet_buffer ? s->packet_buffer : s->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 ||
@@ -559,27 +939,36 @@ static void update_initial_durations(AVFormatContext *s, AVStream *st,
cur_dts -= duration;
}
}
- pktl = s->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->packet_buffer ? s->packet_buffer : s->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;
}
@@ -588,13 +977,43 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
{
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;
@@ -608,7 +1027,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).
@@ -617,23 +1039,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->packet_buffer)
- update_initial_durations(s, st, pkt->stream_index,
- pkt->duration);
}
}
+ if (pkt->duration != 0 && (s->packet_buffer || s->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,20 +1078,19 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
presentation_delayed = 1;
av_dlog(NULL,
- "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
+ "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;
@@ -681,58 +1106,40 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
* 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->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_dlog(NULL,
- "OUTdelayed:%d/%d pts:%"PRId64", dts:%"PRId64" cur_dts:%"PRId64"\n",
- presentation_delayed, delay, pkt->pts, pkt->dts, st->cur_dts);
+ av_dlog(NULL, "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;
@@ -766,6 +1173,9 @@ 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);
}
while (size > 0 || (pkt == &flush_pkt && got_output)) {
@@ -777,6 +1187,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;
@@ -810,19 +1221,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);
if (out_pkt.data == pkt->data && out_pkt.size == pkt->size) {
out_pkt.buf = pkt->buf;
@@ -870,6 +1280,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;
@@ -903,27 +1318,34 @@ 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) {
@@ -944,11 +1366,65 @@ 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->parse_queue)
ret = read_from_packet_buffer(&s->parse_queue, &s->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->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\n", st->skip_samples);
+ }
+ 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;
@@ -959,9 +1435,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;
@@ -971,15 +1449,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->packet_buffer
- ? read_from_packet_buffer(&s->packet_buffer,
- &s->packet_buffer_end, pkt)
- : read_frame_internal(s, pkt);
+ if (!genpts) {
+ ret = s->packet_buffer
+ ? read_from_packet_buffer(&s->packet_buffer,
+ &s->packet_buffer_end, pkt)
+ : read_frame_internal(s, pkt);
+ if (ret < 0)
+ return ret;
+ goto return_packet;
+ }
for (;;) {
- int ret;
AVPacketList *pktl = s->packet_buffer;
if (pktl) {
@@ -987,23 +1470,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->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->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->packet_buffer,
&s->packet_buffer_end, pkt);
+ goto return_packet;
+ }
}
ret = read_frame_internal(s, pkt);
@@ -1019,6 +1521,21 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt)
&s->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 */
@@ -1036,23 +1553,36 @@ 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 (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. */
@@ -1072,13 +1602,20 @@ 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;
}
}
@@ -1121,6 +1658,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) *
@@ -1136,7 +1682,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) {
@@ -1162,6 +1708,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);
@@ -1206,6 +1753,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)
{
@@ -1219,7 +1775,7 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index,
if (stream_index < 0)
return -1;
- av_dlog(s, "read_seek: %d %"PRId64"\n", stream_index, target_ts);
+ av_dlog(s, "read_seek: %d %s\n", stream_index, av_ts2str(target_ts));
ts_max =
ts_min = AV_NOPTS_VALUE;
@@ -1239,23 +1795,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_dlog(s, "using cached pos_min=0x%"PRIx64" dts_min=%"PRId64"\n",
- pos_min, ts_min);
+ av_dlog(s, "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_dlog(s, "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));
}
}
@@ -1268,11 +1824,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,
@@ -1281,45 +1876,35 @@ 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_dlog(s, "gen_seek: %d %"PRId64"\n", stream_index, target_ts);
+ av_dlog(s, "gen_seek: %d %s\n", stream_index, av_ts2str(target_ts));
if (ts_min == AV_NOPTS_VALUE) {
pos_min = s->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_max <= target_ts) {
+ *ts_ret = ts_max;
+ return pos_max;
+ }
+
if (ts_min > ts_max)
return -1;
else if (ts_min == ts_max)
@@ -1327,8 +1912,9 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
no_change = 0;
while (pos_min < pos_limit) {
- av_dlog(s, "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%"PRId64
- " dts_max=%"PRId64"\n", pos_min, pos_max, ts_min, ts_max);
+ av_dlog(s,
+ "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));
assert(pos_limit <= pos_max);
if (no_change == 0) {
@@ -1352,20 +1938,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_dlog(s, "%"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_dlog(s, "%"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;
@@ -1379,12 +1965,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_dlog(s, "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_dlog(s, "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;
}
@@ -1404,6 +1992,8 @@ static int seek_frame_byte(AVFormatContext *s, int stream_index,
avio_seek(s->pb, pos, SEEK_SET);
+ s->io_repositioned = 1;
+
return 0;
}
@@ -1425,9 +2015,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;
@@ -1444,9 +2035,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);
}
@@ -1512,10 +2108,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;
}
@@ -1525,15 +2133,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;
}
@@ -1543,13 +2169,19 @@ 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
}
/*******************************************************/
@@ -1581,12 +2213,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++) {
@@ -1594,13 +2228,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,
@@ -1608,17 +2253,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;
}
}
@@ -1644,7 +2305,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 */
@@ -1667,29 +2328,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->data_offset) {
+ filesize -= ic->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;
@@ -1698,9 +2367,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);
@@ -1708,11 +2379,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;
@@ -1733,31 +2405,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;
}
}
@@ -1778,15 +2495,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);
@@ -1807,56 +2525,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;
}
@@ -1864,11 +2601,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;
@@ -1882,7 +2621,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;
@@ -1894,18 +2633,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;
@@ -1945,6 +2692,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) {
@@ -1978,11 +2726,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;
}
@@ -2027,53 +2789,279 @@ static int get_std_framerate(int i)
if (i < 60 * 12)
return (i + 1) * 1001;
else
- return ((const int[]) { 24, 30, 60, 12, 15 })[i - 60 * 12] * 1000 * 12;
+ return ((const int[]) { 24, 30, 60, 12, 15, 48 })[i - 60 * 12] * 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 >= 101L * c->time_base.num ||
+ c->time_base.den < 5L * 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_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_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(NULL, 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 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);
+
+ if (!max_analyze_duration) {
+ if (!strcmp(ic->iformat->name, "flv") && !(ic->ctx_flags & AVFMTCTX_NOHEADER)) {
+ max_analyze_duration = 10*AV_TIME_BASE;
+ } else
+ max_analyze_duration = 5*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;
}
@@ -2092,24 +3080,29 @@ 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 &&
+ if (!(st->r_frame_rate.num && st->avg_frame_rate.num) &&
+ st->info->duration_count < fps_analyze_framecount &&
st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
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))
@@ -2122,14 +3115,23 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
/* 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;
}
@@ -2141,56 +3143,31 @@ 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->packet_buffer, &ic->packet_buffer_end);
+ {
pkt = add_to_pktbuf(&ic->packet_buffer, &pkt1,
&ic->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,
@@ -2224,24 +3201,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 >= max_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);
@@ -2257,7 +3252,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)
@@ -2267,31 +3262,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. */
@@ -2309,6 +3335,17 @@ 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;
+ }
+ }
} else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
if (!st->codec->bits_per_coded_sample)
st->codec->bits_per_coded_sample =
@@ -2334,26 +3371,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;
}
@@ -2362,12 +3433,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;
@@ -2381,20 +3452,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) {
@@ -2405,7 +3488,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;
}
@@ -2429,10 +3512,37 @@ 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(&s->streams[ --s->nb_streams ]);
+}
+
void avformat_free_context(AVFormatContext *s)
{
- int i, j;
- AVStream *st;
+ int i;
if (!s)
return;
@@ -2440,30 +3550,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);
@@ -2474,21 +3565,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;
@@ -2509,12 +3607,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)
@@ -2523,6 +3623,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 (s->iformat) {
@@ -2540,19 +3641,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;
}
@@ -2576,6 +3685,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;
}
@@ -2586,6 +3700,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];
@@ -2609,6 +3728,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);
@@ -2623,12 +3743,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;
}
@@ -2697,7 +3815,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;
@@ -2726,8 +3844,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
@@ -2736,9 +3857,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 '@' */
}
@@ -2823,11 +3945,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;
}
@@ -2896,21 +4020,14 @@ int ff_find_stream_index(AVFormatContext *s, int id)
int64_t ff_iso8601_to_unix_time(const char *datestr)
{
-#if HAVE_STRPTIME
struct tm time1 = { 0 }, time2 = { 0 };
char *ret1, *ret2;
- ret1 = strptime(datestr, "%Y - %m - %d %T", &time1);
- ret2 = strptime(datestr, "%Y - %m - %dT%T", &time2);
+ ret1 = av_small_strptime(datestr, "%Y - %m - %d %H:%M:%S", &time1);
+ ret2 = av_small_strptime(datestr, "%Y - %m - %dT%H:%M:%S", &time2);
if (ret2 && !ret1)
return av_timegm(&time2);
else
return av_timegm(&time1);
-#else
- av_log(NULL, AV_LOG_WARNING,
- "strptime() unavailable on this system, cannot convert "
- "the date string.\n");
- return 0;
-#endif
}
int avformat_query_codec(const AVOutputFormat *ofmt, enum AVCodecID codec_id,
@@ -2992,6 +4109,136 @@ 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 && 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) /* 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[] = {
@@ -3026,6 +4273,21 @@ int ff_generate_avci_extradata(AVStream *st)
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,
@@ -3036,8 +4298,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,
@@ -3059,6 +4321,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;
@@ -3072,24 +4349,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 f302c2b..3afe398 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 9d55fee..751333a 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 f8c5edb..4596175 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 6
-#define LIBAVFORMAT_VERSION_MICRO 4
+#define LIBAVFORMAT_VERSION_MINOR 12
+#define LIBAVFORMAT_VERSION_MICRO 103
#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 0000000..7287379
--- /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 1b7d499..2a97234 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 d2c0cb4..08db970 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
*/
diff --git a/libavformat/vocdec.c b/libavformat/vocdec.c
index 2fb8440..0b6b5a5 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
*/
@@ -75,7 +75,7 @@ ff_voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size)
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,7 +150,7 @@ 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;
diff --git a/libavformat/vocenc.c b/libavformat/vocenc.c
index ed10a96..0bb532e 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 ee06a57..cc9b662 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,6 +34,7 @@ const AVMetadataConv ff_vorbiscomment_metadata_conv[] = {
{ "ALBUMARTIST", "album_artist"},
{ "TRACKNUMBER", "track" },
{ "DISCNUMBER", "disc" },
+ { "DESCRIPTION", "comment" },
{ 0 }
};
diff --git a/libavformat/vorbiscomment.h b/libavformat/vorbiscomment.h
index d9ec099..f4212d2 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
*/
diff --git a/libavformat/vplayerdec.c b/libavformat/vplayerdec.c
new file mode 100644
index 0000000..619ccfd
--- /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 a43829b..15e8246 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);
}
diff --git a/libavformat/w64.c b/libavformat/w64.c
new file mode 100644
index 0000000..ef2d90a
--- /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 0000000..0ec3fa9
--- /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 f65a66a..9c4e2df 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,10 +38,25 @@
#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
} WAVDemuxContext;
#if CONFIG_WAV_DEMUXER
@@ -51,25 +67,27 @@ static int64_t next_tag(AVIOContext *pb, uint32_t *tag)
return avio_rl32(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;
+ if (avio_feof(pb))
+ return AVERROR_EOF;
size = next_tag(pb, &tag);
if (tag == tag1)
break;
- wav_seek_tag(pb, size, SEEK_CUR);
+ wav_seek_tag(wav, pb, size, SEEK_CUR);
}
return size;
}
@@ -92,6 +110,14 @@ 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, 14);
+ }
+}
+
static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream **st)
{
AVIOContext *pb = s->pb;
@@ -105,7 +131,9 @@ static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream **st)
ret = ff_get_wav_header(pb, (*st)->codec, size);
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 +195,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],
@@ -222,6 +250,10 @@ static int wav_read_header(AVFormatContext *s)
int ret, got_fmt = 0;
int64_t next_tag_ofs, data_ofs = -1;
+ wav->unaligned = avio_tell(s->pb) & 1;
+
+ wav->smv_data_ofs = -1;
+
/* check RIFF header */
tag = avio_rl32(pb);
@@ -237,7 +269,7 @@ static int wav_read_header(AVFormatContext *s)
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 +282,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 (;;) {
+ AVStream *vst;
size = next_tag(pb, &tag);
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");
@@ -300,22 +334,62 @@ static int wav_read_header(AVFormatContext *s)
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 +402,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 +435,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 +456,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 +555,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 +585,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 +608,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 +626,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 +634,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 +642,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);
+ 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 25f6ffc..bce4876 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,16 +46,49 @@
#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;
+ PeakFormat 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;
@@ -97,25 +143,198 @@ 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 void 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;
+ 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));
+ }
+
+ 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;
+}
+
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 +346,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 +373,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,33 +411,80 @@ 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;
avio_flush(pb);
if (s->pb->seekable) {
- ff_end_tag(pb, wav->data);
+ if (wav->write_peak != 2) {
+ ff_end_tag(pb, wav->data);
+ avio_flush(pb);
+ }
+
+ if (wav->write_peak && wav->peak_output) {
+ 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 {
+ 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);
+ }
+
+ 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);
}
}
+
+ if (wav->write_peak)
+ peak_free_buffers(s);
+
return 0;
}
@@ -194,6 +492,17 @@ static int wav_write_trailer(AVFormatContext *s)
#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 +528,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 c894253..7bd09e3 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/webmdashenc.c b/libavformat/webmdashenc.c
new file mode 100644
index 0000000..4536b7d
--- /dev/null
+++ b/libavformat/webmdashenc.c
@@ -0,0 +1,386 @@
+/*
+ * 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
+ */
+
+#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"
+
+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;
+} 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 void write_header(AVFormatContext *s)
+{
+ 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=\"static\"\n");
+ 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=\"urn:webm:dash:profile:webm-on-demand:2012\"");
+ avio_printf(s->pb, ">\n");
+}
+
+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, int id,
+ int output_width, int output_height,
+ int output_sample_rate) {
+ 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 (!irange || cues_start == NULL || cues_end == NULL || filename == NULL ||
+ !bandwidth) {
+ return -1;
+ }
+ avio_printf(s->pb, "<Representation id=\"%d\"", id);
+ avio_printf(s->pb, " bandwidth=\"%s\"", 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);
+ 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;
+}
+
+/*
+ * 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.
+ int width_in_as = 1, height_in_as = 1, sample_rate_in_as = 1;
+ if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ width_in_as = check_matching_width(s, as);
+ height_in_as = check_matching_height(s, as);
+ } else {
+ sample_rate_in_as = 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[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 (!kf || !strncmp(kf->value, "0", 1)) subsegmentStartsWithSAP = 0;
+ }
+ avio_printf(s->pb, " subsegmentStartsWithSAP=\"%d\"", subsegmentStartsWithSAP);
+ avio_printf(s->pb, ">\n");
+
+ for (i = 0; i < as->nb_streams; i++) {
+ write_representation(s, s->streams[as->streams[i]], w->representation_id++,
+ !width_in_as, !height_in_as, !sample_rate_in_as);
+ }
+ 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 -1;
+ 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)) {
+ w->as = av_realloc(w->as, sizeof(*w->as) * ++w->nb_as);
+ if (w->as == NULL) return -1;
+ 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 -1;
+ 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;
+ WebMDashMuxContext *w = s->priv_data;
+ parse_adaptation_sets(s);
+ write_header(s);
+ avio_printf(s->pb, "<Period id=\"0\"");
+ avio_printf(s->pb, " start=\"PT%gS\"", start);
+ avio_printf(s->pb, " duration=\"PT%gS\"", get_duration(s));
+ avio_printf(s->pb, " >\n");
+
+ for (i = 0; i < w->nb_as; i++) {
+ if (write_adaptation_set(s, i) < 0) return -1;
+ }
+
+ avio_printf(s->pb, "</Period>\n");
+ write_footer(s);
+ return 0;
+}
+
+static int webm_dash_manifest_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ return AVERROR_EOF;
+}
+
+static int webm_dash_manifest_write_trailer(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);
+ 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 },
+ { 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 0000000..ee110de
--- /dev/null
+++ b/libavformat/webpenc.c
@@ -0,0 +1,169 @@
+/*
+ * 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;
+} 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);
+
+ avio_write(s->pb, "RIFF\0\0\0\0WEBP", 12);
+
+ 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 (AV_RL32(w->last_pkt.data) == AV_RL32("RIFF"))
+ skip = 12;
+ 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;
+ }
+
+ w->frame_count ++;
+
+ 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;
+ int ret;
+
+ if ((ret = flush(s, 0, pkt->pts)) < 0)
+ return ret;
+
+ av_copy_packet(&w->last_pkt, pkt);
+
+ return 0;
+}
+
+static int webp_write_trailer(AVFormatContext *s)
+{
+ unsigned filesize;
+ 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);
+
+ 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 0000000..e457e8f
--- /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 0000000..b93993d
--- /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 611d223..5286875 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;
diff --git a/libavformat/westwood_vqa.c b/libavformat/westwood_vqa.c
index 77da375..c827fcd 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 = (uint8_t *)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.h b/libavformat/wtv.h
new file mode 100644
index 0000000..f26ad5e
--- /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 0000000..ce4349d
--- /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/wtv.c b/libavformat/wtvdec.c
index 5080d29..4009964 100644
--- a/libavformat/wtv.c
+++ b/libavformat/wtvdec.c
@@ -2,20 +2,20 @@
* Windows Television (WTV) demuxer
* Copyright (c) 2010-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
*/
@@ -30,12 +30,10 @@
#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 "wtv.h"
#include "mpegts.h"
/* Macros for formating GUIDs */
@@ -51,18 +49,12 @@
*
*/
-#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 {
- AVIOContext *pb_filesystem; /** file system (AVFormatContext->pb) */
+ 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 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;
@@ -71,7 +63,7 @@ typedef struct {
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 avio_seek(pb, (sector << WTV_SECTOR_BITS) + offset, SEEK_SET);
}
/**
@@ -85,7 +77,7 @@ static int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size)
if (wf->error || pb->error)
return -1;
- if (wf->position >= wf->length || pb->eof_reached)
+ if (wf->position >= wf->length || avio_feof(pb))
return 0;
buf_size = FFMIN(buf_size, wf->length - wf->position);
@@ -164,6 +156,7 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int
AVIOContext *pb;
WtvFile *wf;
uint8_t *buffer;
+ int64_t size;
if (seek_by_sector(s->pb, first_sector, 0) < 0)
return NULL;
@@ -180,7 +173,6 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int
}
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) {
@@ -188,13 +180,12 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int
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));
+ wf->sectors = av_malloc_array(nb_sectors1, 1 << WTV_SECTOR_BITS);
if (!wf->sectors) {
av_free(wf);
return NULL;
@@ -205,12 +196,12 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int
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;
}
+ wf->sector_bits = length & (1ULL<<63) ? WTV_SECTOR_BITS : WTV_BIGSECTOR_BITS;
if (!wf->nb_sectors) {
av_free(wf->sectors);
@@ -218,6 +209,10 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int
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)) {
@@ -252,9 +247,6 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int
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
@@ -271,7 +263,7 @@ static AVIOContext * wtvfile_open2(AVFormatContext *s, const uint8_t *buf, int b
int dir_length, name_size, first_sector, depth;
uint64_t file_length;
const uint8_t *name;
- if (ff_guidcmp(buf, dir_entry_guid)) {
+ 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;
@@ -284,7 +276,7 @@ static AVIOContext * wtvfile_open2(AVFormatContext *s, const uint8_t *buf, int b
"bad filename length, remaining directory entries ignored\n");
break;
}
- if (48 + name_size > buf_end - buf) {
+ 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;
}
@@ -313,8 +305,8 @@ static void wtvfile_close(AVIOContext *pb)
{
WtvFile *wf = pb->opaque;
av_free(wf->sectors);
- av_free(wf);
- av_free(pb->buffer);
+ av_freep(&pb->opaque);
+ av_freep(&pb->buffer);
av_free(pb);
}
@@ -329,10 +321,10 @@ typedef struct {
} WtvStream;
typedef struct {
- AVIOContext *pb; /** timeline file */
+ 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 */
+ 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) */
@@ -342,18 +334,6 @@ typedef struct {
} 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 =
@@ -376,10 +356,6 @@ static const ff_asf_guid EVENTID_AudioTypeSpanningEvent =
/* 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 =
@@ -390,8 +366,6 @@ 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 =
@@ -401,71 +375,57 @@ static const ff_asf_guid mediasubtype_dtvccdata =
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;
+ return ff_guidcmp(p->buf, ff_wtv_guid) ? 0 : AVPROBE_SCORE_MAX;
}
/**
* Convert win32 FILETIME to ISO-8601 string
+ * @return <0 on error
*/
-static void filetime_to_iso8601(char *buf, int buf_size, int64_t value)
+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) {
- if (!strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", tm))
- buf[0] = '\0';
- } else
- buf[0] = '\0';
+ 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 void crazytime_to_iso8601(char *buf, int buf_size, int64_t value)
+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) {
- if (!strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", tm))
- buf[0] = '\0';
- } else
- buf[0] = '\0';
+ 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 void oledate_to_iso8601(char *buf, int buf_size, int64_t value)
+static int oledate_to_iso8601(char *buf, int buf_size, int64_t value)
{
- time_t t = 631112400LL + 86400*av_int2double(value);
+ time_t t = (av_int2double(value) - 25569.0) * 86400;
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';
+ 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)
@@ -474,6 +434,7 @@ static void get_attachment(AVFormatContext *s, AVIOContext *pb, int length)
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));
@@ -490,22 +451,31 @@ static void get_attachment(AVFormatContext *s, AVIOContext *pb, int length)
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->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT;
- st->codec->extradata = av_mallocz(filesize);
st->id = -1;
- if (!st->codec->extradata)
+ ret = av_get_packet(pb, &st->attached_pic, filesize);
+ if (ret < 0)
goto done;
- st->codec->extradata_size = filesize;
- avio_read(pb, st->codec->extradata, filesize);
+ 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 = FFMAX(2*length, LEN_PRETTY_GUID) + 1;
- char *buf = av_malloc(buf_size);
+ 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;
@@ -522,14 +492,23 @@ static void get_tag(AVFormatContext *s, AVIOContext *pb, const char *key, int ty
} 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"))
+ !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);
@@ -561,14 +540,14 @@ static void parse_legacy_attrib(AVFormatContext *s, AVIOContext *pb)
{
ff_asf_guid guid;
int length, type;
- while(!pb->eof_reached) {
+ 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, metadata_guid)) {
+ 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;
@@ -590,7 +569,7 @@ static int parse_videoinfoheader2(AVFormatContext *s, AVStream *st)
AVIOContext *pb = wtv->pb;
avio_skip(pb, 72); // picture aspect ratio is unreliable
- ff_get_bmp_header(pb, st);
+ st->codec->codec_tag = ff_get_bmp_header(pb, st, NULL);
return 72 + 40;
}
@@ -663,12 +642,12 @@ static AVStream * new_stream(AVFormatContext *s, AVStream *st, int sid, int code
*/
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)
+ ff_asf_guid formattype, uint64_t size)
{
WtvContext *wtv = s->priv_data;
AVIOContext *pb = wtv->pb;
- if (!ff_guidcmp(subtype, mediasubtype_cpfilters_processed) &&
- !ff_guidcmp(formattype, format_cpfilters_processed)) {
+ 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;
@@ -686,16 +665,16 @@ static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid,
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)) {
+ } 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, format_waveformatex)) {
+ if (!ff_guidcmp(formattype, ff_format_waveformatex)) {
int ret = ff_get_wav_header(pb, st->codec, size);
if (ret < 0)
return NULL;
} else {
- if (ff_guidcmp(formattype, format_none))
+ 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);
}
@@ -713,18 +692,19 @@ static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid,
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)) {
+ } 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, format_videoinfo2)) {
+ 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, format_mpeg2_video)) {
- int consumed = parse_videoinfoheader2(s, st);
+ } 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, format_none))
+ 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);
}
@@ -732,7 +712,7 @@ static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid,
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);
+ 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));
@@ -742,7 +722,7 @@ static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid,
st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE);
if (!st)
return NULL;
- if (ff_guidcmp(formattype, format_none))
+ 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;
@@ -752,14 +732,14 @@ static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid,
st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE);
if (!st)
return NULL;
- if (ff_guidcmp(formattype, format_none))
+ 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_TELETEXT;
+ 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, format_none))
+ 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;
@@ -778,6 +758,26 @@ enum {
};
/**
+ * 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) {
+ int 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
@@ -788,19 +788,26 @@ static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_p
{
WtvContext *wtv = s->priv_data;
AVIOContext *pb = wtv->pb;
- while (!pb->eof_reached) {
+ while (!avio_feof(pb)) {
ff_asf_guid g;
int len, sid, consumed;
ff_get_guid(pb, &g);
len = avio_rl32(pb);
- if (len < 32)
- break;
+ 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, stream_guid)) {
+ 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;
@@ -813,9 +820,9 @@ static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_p
parse_media_type(s, 0, sid, mediatype, subtype, formattype, size);
consumed += 92 + size;
}
- } else if (!ff_guidcmp(g, stream2_guid)) {
+ } else if (!ff_guidcmp(g, ff_stream2_guid)) {
int stream_index = ff_find_stream_index(s, sid);
- if (stream_index >= 0 && !((WtvStream*)s->streams[stream_index]->priv_data)->seen_data) {
+ 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);
@@ -889,7 +896,7 @@ static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_p
}
consumed += 15;
}
- } else if (!ff_guidcmp(g, timestamp_guid)) {
+ } 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);
@@ -902,15 +909,14 @@ static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_p
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)) {
+ } 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) {
+ 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) {
@@ -918,10 +924,15 @@ static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_p
}
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 */ (const ff_asf_guid){0x12,0xF6,0x22,0xB6,0xAD,0x47,0x71,0x46,0xAD,0x6C,0x05,0xA9,0x8E,0x65,0xDE,0x3A}) ||
+ !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}) ||
@@ -934,9 +945,10 @@ static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_p
!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})) {
+ !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));
@@ -946,18 +958,6 @@ static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_p
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;
@@ -989,7 +989,7 @@ static int read_header(AVFormatContext *s)
return AVERROR_INVALIDDATA;
/* parse chunks up until first data chunk */
- wtv->pb = wtvfile_open(s, root, root_size, timeline_le16);
+ 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;
@@ -1003,7 +1003,7 @@ static int read_header(AVFormatContext *s)
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);
+ pb = wtvfile_open(s, root, root_size, ff_table_0_entries_legacy_attrib_le16);
if (pb) {
parse_legacy_attrib(s, pb);
wtvfile_close(pb);
@@ -1012,12 +1012,12 @@ static int read_header(AVFormatContext *s)
/* read seek index */
if (s->nb_streams) {
AVStream *st = s->streams[0];
- pb = wtvfile_open(s, root, root_size, table_0_entries_time_le16);
+ 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 (pb->eof_reached)
+ 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);
@@ -1025,13 +1025,13 @@ static int read_header(AVFormatContext *s)
wtvfile_close(pb);
if (wtv->nb_index_entries) {
- pb = wtvfile_open(s, root, root_size, timeline_table_0_entries_Events_le16);
+ 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 (pb->eof_reached)
+ if (avio_feof(pb))
break;
for (i = wtv->nb_index_entries - 1; i >= 0; i--) {
AVIndexEntry *e = wtv->index_entries + i;
@@ -1091,26 +1091,30 @@ static int read_seek(AVFormatContext *s, int stream_index,
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 (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;
- 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);
+ av_freep(&wtv->index_entries);
wtvfile_close(wtv->pb);
return 0;
}
diff --git a/libavformat/wtvenc.c b/libavformat/wtvenc.c
new file mode 100644
index 0000000..634545d
--- /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(*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 = 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 = 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 724256b..0f4f807 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 ef285d2..07d2e1b 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 1a2a722..76768cd 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)
diff --git a/libavformat/wvenc.c b/libavformat/wvenc.c
index 2e150e1..b0d74ca 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 57a36bc..43661de 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 bcb17f8..6eac4d2 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;
-
- uint32_t data_size;
- uint32_t data_offset;
+ int stream_index; ///< The decoder stream index for this video packet.
- uint32_t current_frame;
- uint32_t frame_count;
+ uint32_t data_size; ///< The size of the remaining video data.
+ uint64_t data_offset; ///< The offset of the video data within the file.
- /* Does the video packet contain extra data? */
- int has_extradata;
+ uint32_t current_frame; ///< The current frame within this video packet.
+ uint32_t frame_count; ///< The amount of frames within this video packet.
- /* Extra data */
- uint8_t extradata[4];
+ int has_extradata; ///< Does the video packet contain extra data?
+ uint8_t extradata[4]; ///< The extra data
- 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;
-
- XMVAudioTrack *audio_tracks;
+ uint16_t audio_track_count; ///< Number of audio track in this file.
- 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;
@@ -306,7 +297,7 @@ static int xmv_process_packet_header(AVFormatContext *s)
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 +328,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 +348,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 +378,12 @@ 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);
- vst->codec->extradata =
- av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE);
- vst->codec->extradata_size = 4;
+ ff_alloc_extradata(vst->codec, 4);
}
memcpy(vst->codec->extradata, xmv->video.extradata, 4);
@@ -411,6 +400,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 +455,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 +480,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 +495,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 45d74de..127c097 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;
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;
@@ -130,8 +130,10 @@ static int xwma_read_header(AVFormatContext *s)
/* parse the remaining RIFF chunks */
for (;;) {
- if (pb->eof_reached)
- return -1;
+ if (pb->eof_reached) {
+ ret = AVERROR_EOF;
+ goto end;
+ }
/* read next chunk tag */
tag = avio_rl32(pb);
size = avio_rl32(pb);
@@ -152,7 +154,8 @@ static int xwma_read_header(AVFormatContext *s)
/* Error out if there is more than one dpds chunk. */
if (dpds_table) {
av_log(s, AV_LOG_ERROR, "two dpds chunks present\n");
- return -1;
+ ret = AVERROR_INVALIDDATA;
+ goto end;
}
/* Compute the number of entries in the dpds chunk. */
@@ -164,7 +167,7 @@ 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.
@@ -184,8 +187,10 @@ static int xwma_read_header(AVFormatContext *s)
}
/* Determine overall data length */
- if (size < 0)
- return -1;
+ if (size < 0) {
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
if (!size) {
xwma->data_end = INT64_MAX;
} else
@@ -204,7 +209,8 @@ static int xwma_read_header(AVFormatContext *s)
av_log(s, AV_LOG_ERROR,
"Invalid bits_per_coded_sample %d for %d channels\n",
st->codec->bits_per_coded_sample, st->codec->channels);
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto end;
}
st->duration = total_decoded_bytes / bytes_per_sample;
@@ -239,9 +245,10 @@ static int xwma_read_header(AVFormatContext *s)
st->duration = (size<<3) * st->codec->sample_rate / st->codec->bit_rate;
}
+end:
av_free(dpds_table);
- return 0;
+ return ret;
}
static int xwma_read_packet(AVFormatContext *s, AVPacket *pkt)
diff --git a/libavformat/yop.c b/libavformat/yop.c
index ea3175e..07086d5 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 7891ed6..750f498 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 e5c4456..c02b291 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 2caa364..cc954fc 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 b9ca491..7d857a0 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 856f191..0b58244 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 020dd61..b5b0d1e 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 198cf86..e13e277 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 20e563d..e956ee6 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 9ef9977..d3dfb12 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 94aec58..d3c2cbf 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/audio_convert_init.c b/libavresample/arm/audio_convert_init.c
index bbb7bae..3d19a0e 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 98945c4..a120e87 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 d96d4d2..22afedb 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/audio_convert.c b/libavresample/audio_convert.c
index ef23912..5629034 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 d8e42d0..df15442 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 7a6fe745..c2f5450 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 1541976..b50bd40 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 8619c1a..9df1865 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 5bae5ab..0187d0f 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 5182ae1..5d92351 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 697b4ba..290ae94 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 b705a45..5eb55cb 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 0000000..e6d0d15
--- /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 17de829..2ae8d33 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 8db3714..c53e822 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 e59758c..fe6bd8f 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 6249f90..5f08cd7 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 4553b2c..bdc74a2 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 7e02cb1..be9f562 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 d8ddcc9..863852a 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 8ba8a09..e285445 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 34623a1..33ff2a2 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 1af1429..3e21f26 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 d85ca84..d88ddac 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 2c657b5..64ab039 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 7fc530e..2f05eee 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 2192e98..757f280 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 8349d5e..816d4b0 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 0ce9531..187a4a2 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 51a400e..0f42bd1 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 0f8ed08..6f90301 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -1,3 +1,5 @@
+include $(SUBDIR)../config.mak
+
NAME = avutil
HEADERS = adler32.h \
@@ -10,8 +12,10 @@ HEADERS = adler32.h \
avutil.h \
base64.h \
blowfish.h \
+ bprint.h \
bswap.h \
buffer.h \
+ cast5.h \
channel_layout.h \
common.h \
cpu.h \
@@ -23,6 +27,7 @@ HEADERS = adler32.h \
fifo.h \
file.h \
frame.h \
+ hash.h \
hmac.h \
imgutils.h \
intfloat.h \
@@ -33,30 +38,41 @@ 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 \
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,7 +81,9 @@ OBJS = adler32.o \
avstring.o \
base64.o \
blowfish.o \
+ bprint.o \
buffer.o \
+ cast5.o \
channel_layout.o \
cpu.o \
crc.o \
@@ -78,7 +96,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 +109,42 @@ 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 \
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 +152,42 @@ TESTPROGS = adler32 \
avstring \
base64 \
blowfish \
+ bprint \
+ cast5 \
cpu \
crc \
des \
+ 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 \
+ 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 b766e67..c6adf6e 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 0c001ce..1e735c5 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 37a7d8d..8ef077a 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 f5b1d89..cf1b9cc 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 37d34c9..4325071 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 776542c..02d790c 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 de841bb..b9d4986 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 8a8065c..579d022 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 53e3dbf..0dc69ec 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 3ba5e9a..638fb81 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)
{
@@ -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 edff275..09efbda 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 93d74b6..35559ce 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 8bc7d9a..ae5fdb7 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 8bdaa88..f1683e8 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 224409a..9b3b6ff 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 ec925ec..fe311cc 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 ff0105c..6787628 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 617bf5d..689aa77 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 61ff2ed..45508b8 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
*/
diff --git a/libavutil/arm/float_dsp_neon.S b/libavutil/arm/float_dsp_neon.S
index 559b565..3823227 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 9f920aa..7db2452 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 56fcdb3..fd52648 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 6eff733..2340a9a 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 eb46df8..f668c00 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 4bca877..5e8bc8e 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 8374039..1fa6308 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
*/
@@ -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 57a0c19..15906d2 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 9470e8e..5f9fc49 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 5c11b57..3cad24a 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 00c66cf..20b99df 100644
--- a/libavutil/atomic_win32.h
+++ b/libavutil/atomic_win32.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/attributes.h b/libavutil/attributes.h
index d7f2bb5..7d3f4a9 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
*/
@@ -32,6 +32,7 @@
# 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 b562537..c3aadfd 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
*/
@@ -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 e73123d..d21e6a1 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 b223d26..41f5e0e 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 857f024..e79d53f 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 e0049fe..c6fd3aa 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 eb5c95a..25c65b4 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;
@@ -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,23 @@ const char *av_dirname(char *path)
return path;
}
+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 +326,108 @@ 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[] = {
+ static const char * const strings[] = {
"''",
"",
":",
diff --git a/libavutil/avstring.h b/libavutil/avstring.h
index 7c30ee1..ffb7aa6 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.
@@ -228,6 +276,94 @@ const char *av_dirname(char *path);
*/
int av_match_name(const char *name, const char *names);
+enum AVEscapeMode {
+ AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode.
+ AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping.
+ AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping.
+};
+
+/**
+ * Consider spaces special and escape them even in the middle of the
+ * string.
+ *
+ * This is equivalent to adding the whitespace characters to the special
+ * characters lists, except it is guaranteed to use the exact same list
+ * of whitespace characters as the rest of libavutil.
+ */
+#define AV_ESCAPE_FLAG_WHITESPACE 0x01
+
+/**
+ * Escape only specified special characters.
+ * Without this flag, escape also any characters that may be considered
+ * special by av_get_token(), such as the single quote.
+ */
+#define AV_ESCAPE_FLAG_STRICT 0x02
+
+/**
+ * Escape string in src, and put the escaped string in an allocated
+ * string in *dst, which must be freed with av_free().
+ *
+ * @param dst pointer where an allocated string is put
+ * @param src string to escape, must be non-NULL
+ * @param special_chars string containing the special characters which
+ * need to be escaped, can be NULL
+ * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros.
+ * Any unknown value for mode will be considered equivalent to
+ * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without
+ * notice.
+ * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_ macros
+ * @return the length of the allocated string, or a negative error code in case of error
+ * @see av_bprint_escape()
+ */
+int av_escape(char **dst, const char *src, const char *special_chars,
+ enum AVEscapeMode mode, int flags);
+
+#define AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES 1 ///< accept codepoints over 0x10FFFF
+#define AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS 2 ///< accept non-characters - 0xFFFE and 0xFFFF
+#define AV_UTF8_FLAG_ACCEPT_SURROGATES 4 ///< accept UTF-16 surrogates codes
+#define AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES 8 ///< exclude control codes not accepted by XML
+
+#define AV_UTF8_FLAG_ACCEPT_ALL \
+ AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES|AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS|AV_UTF8_FLAG_ACCEPT_SURROGATES
+
+/**
+ * Read and decode a single UTF-8 code point (character) from the
+ * buffer in *buf, and update *buf to point to the next byte to
+ * decode.
+ *
+ * In case of an invalid byte sequence, the pointer will be updated to
+ * the next byte after the invalid sequence and the function will
+ * return an error code.
+ *
+ * Depending on the specified flags, the function will also fail in
+ * case the decoded code point does not belong to a valid range.
+ *
+ * @note For speed-relevant code a carefully implemented use of
+ * GET_UTF8() may be preferred.
+ *
+ * @param codep pointer used to return the parsed code in case of success.
+ * The value in *codep is set even in case the range check fails.
+ * @param bufp pointer to the address the first byte of the sequence
+ * to decode, updated by the function to point to the
+ * byte next after the decoded sequence
+ * @param buf_end pointer to the end of the buffer, points to the next
+ * byte past the last in the buffer. This is used to
+ * avoid buffer overreads (in case of an unfinished
+ * UTF-8 sequence towards the end of the buffer).
+ * @param flags a collection of AV_UTF8_FLAG_* flags
+ * @return >= 0 in case a sequence was successfully read, a negative
+ * value in case of invalid sequence
+ */
+int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end,
+ unsigned int flags);
+
+/**
+ * Check if a name is in a list.
+ * @returns 0 if not found, or the 1 based index where it has been found in the
+ * list.
+ */
+int av_match_list(const char *name, const char *list, char separator);
+
/**
* @}
*/
diff --git a/libavutil/avutil.h b/libavutil/avutil.h
index f056415..e6ebb6c 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 0000000..40a75eb
--- /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 725b035..03ebce8 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 4750cf5..514498e 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 2837a2f..363ed40 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 49d32a8..644573d 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 8437dd6..3821427 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 8c29536..0b00453 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 0000000..0a0d078
--- /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 0000000..d1682fc
--- /dev/null
+++ b/libavutil/bprint.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2012 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_BPRINT_H
+#define AVUTIL_BPRINT_H
+
+#include <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(size, ...) \
+ __VA_ARGS__ \
+ char reserved_padding[size - sizeof(struct { __VA_ARGS__ })];
+
+/**
+ * Buffer to print data progressively
+ *
+ * The string buffer grows as necessary and is always 0-terminated.
+ * The content of the string is never accessed, and thus is
+ * encoding-agnostic and can even hold binary data.
+ *
+ * Small buffers are kept in the structure itself, and thus require no
+ * memory allocation at all (unless the contents of the buffer is needed
+ * after the structure goes out of scope). This is almost as lightweight as
+ * declaring a local "char buf[512]".
+ *
+ * The length of the string can go beyond the allocated size: the buffer is
+ * then truncated, but the functions still keep account of the actual total
+ * length.
+ *
+ * In other words, buf->len can be greater than buf->size and records the
+ * total length of what would have been to the buffer if there had been
+ * enough memory.
+ *
+ * Append operations do not need to be tested for failure: if a memory
+ * allocation fails, data stop being appended to the buffer, but the length
+ * is still updated. This situation can be tested with
+ * av_bprint_is_complete().
+ *
+ * The size_max field determines several possible behaviours:
+ *
+ * size_max = -1 (= UINT_MAX) or any large value will let the buffer be
+ * reallocated as necessary, with an amortized linear cost.
+ *
+ * size_max = 0 prevents writing anything to the buffer: only the total
+ * length is computed. The write operations can then possibly be repeated in
+ * a buffer with exactly the necessary size
+ * (using size_init = size_max = len + 1).
+ *
+ * size_max = 1 is automatically replaced by the exact size available in the
+ * structure itself, thus ensuring no dynamic memory allocation. The
+ * internal buffer is large enough to hold a reasonable paragraph of text,
+ * such as the current paragraph.
+ */
+typedef struct AVBPrint {
+ FF_PAD_STRUCTURE(1024,
+ char *str; /**< string so far */
+ unsigned len; /**< length so far */
+ unsigned size; /**< allocated memory */
+ unsigned size_max; /**< maximum allocated memory */
+ char reserved_internal_buffer[1];
+ )
+} AVBPrint;
+
+/**
+ * Convenience macros for special values for av_bprint_init() size_max
+ * parameter.
+ */
+#define AV_BPRINT_SIZE_UNLIMITED ((unsigned)-1)
+#define AV_BPRINT_SIZE_AUTOMATIC 1
+#define AV_BPRINT_SIZE_COUNT_ONLY 0
+
+/**
+ * Init a print buffer.
+ *
+ * @param buf buffer to init
+ * @param size_init initial size (including the final 0)
+ * @param size_max maximum size;
+ * 0 means do not write anything, just count the length;
+ * 1 is replaced by the maximum value for automatic storage;
+ * any large value means that the internal buffer will be
+ * reallocated as needed up to that limit; -1 is converted to
+ * UINT_MAX, the largest limit possible.
+ * Check also AV_BPRINT_SIZE_* macros.
+ */
+void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max);
+
+/**
+ * Init a print buffer using a pre-existing buffer.
+ *
+ * The buffer will not be reallocated.
+ *
+ * @param buf buffer structure to init
+ * @param buffer byte buffer to use for the string data
+ * @param size size of buffer
+ */
+void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size);
+
+/**
+ * Append a formatted string to a print buffer.
+ */
+void av_bprintf(AVBPrint *buf, const char *fmt, ...) av_printf_format(2, 3);
+
+/**
+ * Append a formatted string to a print buffer.
+ */
+void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg);
+
+/**
+ * Append char c n times to a print buffer.
+ */
+void av_bprint_chars(AVBPrint *buf, char c, unsigned n);
+
+/**
+ * Append data to a print buffer.
+ *
+ * param buf bprint buffer to use
+ * param data pointer to data
+ * param size size of data
+ */
+void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size);
+
+struct tm;
+/**
+ * Append a formatted date and time to a print buffer.
+ *
+ * param buf bprint buffer to use
+ * param fmt date and time format string, see strftime()
+ * param tm broken-down time structure to translate
+ *
+ * @note due to poor design of the standard strftime function, it may
+ * produce poor results if the format string expands to a very long text and
+ * the bprint buffer is near the limit stated by the size_max option.
+ */
+void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm);
+
+/**
+ * Allocate bytes in the buffer for external use.
+ *
+ * @param[in] buf buffer structure
+ * @param[in] size required size
+ * @param[out] mem pointer to the memory area
+ * @param[out] actual_size size of the memory area after allocation;
+ * can be larger or smaller than size
+ */
+void av_bprint_get_buffer(AVBPrint *buf, unsigned size,
+ unsigned char **mem, unsigned *actual_size);
+
+/**
+ * Reset the string to "" but keep internal allocated data.
+ */
+void av_bprint_clear(AVBPrint *buf);
+
+/**
+ * Test if the print buffer is complete (not truncated).
+ *
+ * It may have been truncated due to a memory allocation failure
+ * or the size_max limit (compare size and size_max if necessary).
+ */
+static inline int av_bprint_is_complete(const AVBPrint *buf)
+{
+ return buf->len < buf->size;
+}
+
+/**
+ * Finalize a print buffer.
+ *
+ * The print buffer can no longer be used afterwards,
+ * but the len and size fields are still valid.
+ *
+ * @arg[out] ret_str if not NULL, used to return a permanent copy of the
+ * buffer contents, or NULL if memory allocation fails;
+ * if NULL, the buffer is discarded and freed
+ * @return 0 for success or error code (probably AVERROR(ENOMEM))
+ */
+int av_bprint_finalize(AVBPrint *buf, char **ret_str);
+
+/**
+ * Escape the content in src and append it to dstbuf.
+ *
+ * @param dstbuf already inited destination bprint buffer
+ * @param src string containing the text to escape
+ * @param special_chars string containing the special characters which
+ * need to be escaped, can be NULL
+ * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros.
+ * Any unknown value for mode will be considered equivalent to
+ * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without
+ * notice.
+ * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_* macros
+ */
+void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars,
+ enum AVEscapeMode mode, int flags);
+
+#endif /* AVUTIL_BPRINT_H */
diff --git a/libavutil/bswap.h b/libavutil/bswap.h
index 93a6016..91cb795 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 2b38081..e9bf54b 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
*/
@@ -122,7 +122,17 @@ 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)
@@ -239,14 +249,14 @@ void av_buffer_pool_uninit(AVBufferPool **ppool)
/* remove the whole buffer list from the pool and return it */
static BufferPoolEntry *get_pool(AVBufferPool *pool)
{
- BufferPoolEntry *cur = NULL, *last = NULL;
+ BufferPoolEntry *cur = *(void * volatile *)&pool->pool, *last = NULL;
- do {
- FFSWAP(BufferPoolEntry*, cur, last);
+ while (cur != last) {
+ last = cur;
cur = avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, last, NULL);
if (!cur)
return NULL;
- } while (cur != last);
+ }
return cur;
}
@@ -263,7 +273,7 @@ static void add_to_pool(BufferPoolEntry *buf)
while (end->next)
end = end->next;
- while ((cur = avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, NULL, buf))) {
+ 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;
@@ -276,6 +286,10 @@ static void pool_release_buffer(void *opaque, uint8_t *data)
{
BufferPoolEntry *buf = opaque;
AVBufferPool *pool = buf->pool;
+
+ if(CONFIG_MEMORY_POISONING)
+ memset(buf->data, FF_MEMORY_POISON, pool->size);
+
add_to_pool(buf);
if (!avpriv_atomic_int_add_and_fetch(&pool->refcount, -1))
buffer_pool_free(pool);
@@ -307,6 +321,7 @@ static AVBufferRef *pool_alloc_buffer(AVBufferPool *pool)
ret->buffer->free = pool_release_buffer;
avpriv_atomic_int_add_and_fetch(&pool->refcount, 1);
+ avpriv_atomic_int_add_and_fetch(&pool->nb_allocated, 1);
return ret;
}
@@ -318,6 +333,12 @@ AVBufferRef *av_buffer_pool_get(AVBufferPool *pool)
/* 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);
diff --git a/libavutil/buffer.h b/libavutil/buffer.h
index 56b4d02..b4399fd 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 cce83c3..c291908 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
*/
@@ -85,6 +85,8 @@ struct AVBufferPool {
*/
volatile int refcount;
+ volatile int nb_allocated;
+
int size;
AVBufferRef* (*alloc)(int size);
};
diff --git a/libavutil/cast5.c b/libavutil/cast5.c
new file mode 100644
index 0000000..c0d6d1e
--- /dev/null
+++ b/libavutil/cast5.c
@@ -0,0 +1,541 @@
+/*
+ * 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)
+{
+ 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);
+
+ 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_crypt(AVCAST5* cs, uint8_t* dst, const uint8_t* src, int count, int decrypt)
+{
+ while (count--) {
+ if (decrypt){
+ decipher(cs,dst,src);
+ } 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 uint8_t rpt2[2][16];
+ int i,j,err=0;
+ static 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;
+ }
+ }
+ }
+ av_free(cs);
+ return err;
+}
+#endif
diff --git a/libavutil/cast5.h b/libavutil/cast5.h
new file mode 100644
index 0000000..a4df6d8
--- /dev/null
+++ b/libavutil/cast5.h
@@ -0,0 +1,67 @@
+/*
+ * An implementation of the CAST128 algorithm as mentioned in RFC2144
+ * Copyright (c) 2014 Supraja Meedinti
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_CAST5_H
+#define AVUTIL_CAST5_H
+
+#include <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
+ *
+ * @param ctx an AVCAST5 context
+ * @param dst destination array, can be equal to src
+ * @param src source array, can be equal to dst
+ * @param count number of 8 byte blocks
+ * @param decrypt 0 for encryption, 1 for decryption
+ */
+void av_cast5_crypt(struct AVCAST5 *ctx, uint8_t *dst, const uint8_t *src, int count,int decrypt);
+/**
+ * @}
+ */
+#endif /* AVUTIL_CAST5_H */
diff --git a/libavutil/channel_layout.c b/libavutil/channel_layout.c
index 253c495..4c0677f 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 6a1f830..dea4d60 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/colorspace.h b/libavutil/colorspace.h
index 8757566..f438159 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 eb40e12..c82a3a6 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;
@@ -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;
}
/**
@@ -197,6 +229,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;
@@ -232,7 +284,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))
@@ -248,12 +300,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;\
@@ -371,6 +428,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
@@ -398,6 +458,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 354d21e..53c1227 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,39 @@
#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_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 +85,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)
@@ -148,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;
@@ -174,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
@@ -205,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
@@ -212,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" },
@@ -237,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");
}
@@ -252,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;
@@ -263,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':
@@ -287,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 7cecccc..277e489 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 3bfe8a8..3c6ce6d 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 eb22e33..d8b1c99 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 dcb7e2c..e86bf1d 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 ab0fc2f..57ad0a4 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 cda9812..2feb046 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 e4ea776..475e906 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
*/
@@ -35,7 +35,7 @@ int av_dict_count(const AVDictionary *m)
return m ? m->count : 0;
}
-AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
+AVDictionaryEntry *av_dict_get(FF_CONST_AVUTIL53 AVDictionary *m, const char *key,
const AVDictionaryEntry *prev, int flags)
{
unsigned int i, j;
@@ -77,8 +77,8 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value,
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);
+ if (flags & AV_DICT_DONT_STRDUP_KEY) av_free((void*)key);
+ if (flags & AV_DICT_DONT_STRDUP_VAL) av_free((void*)value);
return 0;
}
if (flags & AV_DICT_APPEND)
@@ -90,24 +90,26 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value,
} else {
AVDictionaryEntry *tmp = av_realloc(m->elems,
(m->count + 1) * sizeof(*m->elems));
- if (tmp)
- m->elems = tmp;
- else
- return AVERROR(ENOMEM);
+ if (!tmp)
+ goto err_out;
+ m->elems = tmp;
}
if (value) {
if (flags & AV_DICT_DONT_STRDUP_KEY)
- m->elems[m->count].key = key;
+ m->elems[m->count].key = (char*)(intptr_t)key;
else
m->elems[m->count].key = av_strdup(key);
if (flags & AV_DICT_DONT_STRDUP_VAL) {
- m->elems[m->count].value = value;
+ m->elems[m->count].value = (char*)(intptr_t)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;
+ char *newval = av_mallocz(len);
+ if (!newval)
+ goto err_out;
+ av_strlcat(newval, oldval, len);
+ av_freep(&oldval);
+ av_strlcat(newval, value, len);
+ m->elems[m->count].value = newval;
} else
m->elems[m->count].value = av_strdup(value);
m->count++;
@@ -118,6 +120,23 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value,
}
return 0;
+
+err_out:
+ if (!m->count) {
+ av_free(m->elems);
+ av_freep(pm);
+ }
+ if (flags & AV_DICT_DONT_STRDUP_KEY) av_free((void*)key);
+ if (flags & AV_DICT_DONT_STRDUP_VAL) av_free((void*)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);
+ return av_dict_set(pm, key, valuestr, flags);
}
static int parse_key_value_pair(AVDictionary **pm, const char **buf,
@@ -181,7 +200,7 @@ void av_dict_free(AVDictionary **pm)
av_freep(pm);
}
-void av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
+void av_dict_copy(AVDictionary **dst, FF_CONST_AVUTIL53 AVDictionary *src, int flags)
{
AVDictionaryEntry *t = NULL;
diff --git a/libavutil/dict.h b/libavutil/dict.h
index e4aee27..9b3381b 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,12 +89,19 @@ 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,
+AVDictionaryEntry *av_dict_get(FF_CONST_AVUTIL53 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
@@ -131,7 +163,7 @@ int av_dict_parse_string(AVDictionary **pm, const char *str,
* @param flags flags to use when setting entries in *dst
* @note metadata is read using the AV_DICT_IGNORE_SUFFIX flag
*/
-void av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags);
+void av_dict_copy(AVDictionary **dst, FF_CONST_AVUTIL53 AVDictionary *src, int flags);
/**
* Free all the memory allocated for an AVDictionary struct
diff --git a/libavutil/display.c b/libavutil/display.c
index 74aceb2..53e8aa2 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 7e37627..2cb930d 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 51505c8..c634c6a7 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 69969f6..221cf5b 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 0000000..4947d93
--- /dev/null
+++ b/libavutil/dynarray.h
@@ -0,0 +1,70 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_DYNARRAY_H
+#define AVUTIL_DYNARRAY_H
+
+#include "log.h"
+#include "mem.h"
+
+/**
+ * Add an element of to a dynamic array.
+ *
+ * The array is reallocated when its number of elements reaches powers of 2.
+ * Therefore, the amortized cost of adding an element is constant.
+ *
+ * In case of success, the pointer to the array is updated in order to
+ * point to the new grown array, and the size is incremented.
+ *
+ * @param av_size_max maximum size of the array, usually the MAX macro of
+ * the type of the size
+ * @param av_elt_size size of the elements in the array, in bytes
+ * @param av_array pointer to the array, must be a lvalue
+ * @param av_size size of the array, must be an integer lvalue
+ * @param av_success statement to execute on success; at this point, the
+ * size variable is not yet incremented
+ * @param av_failure statement to execute on failure; if this happens, the
+ * array and size are not changed; the statement can end
+ * with a return or a goto
+ */
+#define AV_DYNARRAY_ADD(av_size_max, av_elt_size, av_array, av_size, \
+ av_success, av_failure) \
+ do { \
+ size_t av_size_new = (av_size); \
+ if (!((av_size) & ((av_size) - 1))) { \
+ av_size_new = (av_size) ? (av_size) << 1 : 1; \
+ if (av_size_new > (av_size_max) / (av_elt_size)) { \
+ av_size_new = 0; \
+ } else { \
+ void *av_array_new = \
+ av_realloc((av_array), av_size_new * (av_elt_size)); \
+ if (!av_array_new) \
+ av_size_new = 0; \
+ else \
+ (av_array) = av_array_new; \
+ } \
+ } \
+ if (av_size_new) { \
+ { av_success } \
+ (av_size)++; \
+ } else { \
+ av_failure \
+ } \
+ } while (0)
+
+#endif /* AVUTIL_DYNARRAY_H */
diff --git a/libavutil/error.c b/libavutil/error.c
index 6803d2d..d2868ac 100644
--- a/libavutil/error.c
+++ b/libavutil/error.c
@@ -1,54 +1,82 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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 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" },
+};
+
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 +86,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 8be87cb..71df4da 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 31e9ebb..5099e57 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;
@@ -533,6 +693,7 @@ int av_expr_parse(AVExpr **expr, const char *s,
ret = AVERROR(EINVAL);
goto end;
}
+ e->var= av_mallocz(sizeof(double) *VARS);
*expr = e;
end:
av_free(w);
@@ -542,6 +703,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 +815,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 ccb29e7..6159b0f 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 dffaf54..77391ee 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(FF_CONST_AVUTIL53 AVFifoBuffer *f)
{
return (uint32_t)(f->wndx - f->rndx);
}
-int av_fifo_space(AVFifoBuffer *f)
+int av_fifo_space(FF_CONST_AVUTIL53 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 ea30f5d..dda7dd2 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(FF_CONST_AVUTIL53 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(FF_CONST_AVUTIL53 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 d2765b8..359d290 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 e3f02a8..a7364fe 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,16 @@ 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 -1 on error)
+ * and opened file name in **filename.
+ * @note On very old libcs it is necessary to set a secure umask before
+ * calling this, av_tempfile() can't call umask itself as it is used in
+ * libraries and could interfere with the calling application.
+ */
+int av_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx);
+
#endif /* AVUTIL_FILE_H */
diff --git a/libavutil/file_open.c b/libavutil/file_open.c
index 765eb60..f3164eb 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
*/
@@ -48,7 +48,7 @@ static int win32_open(const char *filename_utf8, int oflag, int pmode)
num_chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename_utf8, -1, NULL, 0);
if (num_chars <= 0)
goto fallback;
- filename_w = av_mallocz(sizeof(wchar_t) * num_chars);
+ filename_w = av_mallocz_array(num_chars, sizeof(wchar_t));
if (!filename_w) {
errno = ENOMEM;
return -1;
@@ -62,7 +62,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
@@ -85,9 +85,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 0000000..b99fea5
--- /dev/null
+++ b/libavutil/fixed_dsp.c
@@ -0,0 +1,98 @@
+/*
+ * 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_c(((((int64_t)s0*wj - (int64_t)s1*wi + 0x40000000) >> 31) + round) >> bits);
+ dst[j] = av_clip_int16_c(((((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));
+ 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 0000000..ff6f365
--- /dev/null
+++ b/libavutil/fixed_dsp.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_FIXED_DSP_H
+#define AVUTIL_FIXED_DSP_H
+
+#include <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 aabc800..78de1a1 100644
--- a/libavutil/float_dsp.c
+++ b/libavutil/float_dsp.c
@@ -1,18 +1,21 @@
/*
- * 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
*/
@@ -89,7 +92,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,6 +135,8 @@ 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);
}
#ifdef TEST
@@ -141,6 +146,12 @@ 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"
@@ -364,7 +375,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 +386,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 3142df4..7fc851b 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,6 @@ void ff_float_dsp_init_aarch64(AVFloatDSPContext *fdsp);
void ff_float_dsp_init_arm(AVFloatDSPContext *fdsp);
void ff_float_dsp_init_ppc(AVFloatDSPContext *fdsp, int strict);
void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp);
+void ff_float_dsp_init_mips(AVFloatDSPContext *fdsp);
#endif /* AVUTIL_FLOAT_DSP_H */
diff --git a/libavutil/frame.c b/libavutil/frame.c
index 48df311..4ee0630 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 */
@@ -61,6 +127,7 @@ AVFrame *av_frame_alloc(void)
if (!frame)
return NULL;
+ frame->extended_data = NULL;
get_frame_defaults(frame);
return frame;
@@ -87,21 +154,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;
@@ -125,11 +196,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,
@@ -139,9 +217,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);
@@ -179,7 +257,7 @@ 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);
@@ -192,6 +270,7 @@ 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;
@@ -213,7 +292,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);
@@ -222,7 +303,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);
@@ -241,14 +322,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;
@@ -294,6 +376,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);
}
@@ -314,8 +399,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]);
@@ -337,6 +423,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);
@@ -378,24 +465,38 @@ int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
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 = av_frame_new_side_data(dst, sd_src->type,
+ AVFrameSideData *sd_dst;
+ if ( sd_src->type == AV_FRAME_DATA_PANSCAN
+ && (src->width != dst->width || src->height != dst->height))
+ continue;
+ sd_dst = av_frame_new_side_data(dst, sd_src->type,
sd_src->size);
if (!sd_dst) {
for (i = 0; i < dst->nb_side_data; i++) {
@@ -408,6 +509,18 @@ int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
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;
}
@@ -417,9 +530,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;
@@ -491,8 +605,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);
@@ -503,7 +617,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;
}
@@ -511,14 +625,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);
@@ -555,3 +672,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 d3360c4..d335bee 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,
};
enum AVActiveFormatDescription {
@@ -131,12 +150,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];
@@ -147,6 +174,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.
*/
@@ -216,7 +248,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;
@@ -269,7 +303,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];
/**
@@ -366,7 +399,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
@@ -433,18 +465,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().
*
@@ -603,6 +760,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 0000000..7037b0d
--- /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 0000000..d4bcbf8
--- /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 f87728e..02bdc18 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;
@@ -160,28 +206,54 @@ 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);
+ // 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 28c2062..d36d4de 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 fc367d9..00b2031 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,9 +21,11 @@
* misc image utilities
*/
+#include "avassert.h"
#include "common.h"
#include "imgutils.h"
#include "internal.h"
+#include "intreadwrite.h"
#include "log.h"
#include "mathematics.h"
#include "pixdesc.h"
@@ -47,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 */
@@ -77,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;
@@ -190,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++)
@@ -257,6 +268,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;
@@ -289,8 +302,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],
@@ -298,3 +315,77 @@ void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4],
}
}
}
+
+int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4],
+ const uint8_t *src,
+ enum AVPixelFormat pix_fmt, int width, int height, int align)
+{
+ int ret, i;
+
+ if ((ret = av_image_check_size(width, height, 0, NULL)) < 0)
+ return ret;
+
+ if ((ret = av_image_fill_linesizes(dst_linesize, pix_fmt, width)) < 0)
+ return ret;
+
+ for (i = 0; i < 4; i++)
+ dst_linesize[i] = FFALIGN(dst_linesize[i], align);
+
+ if ((ret = av_image_fill_pointers(dst_data, pix_fmt, width, NULL, dst_linesize)) < 0)
+ return ret;
+
+ 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, int width, int height, int align)
+{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
+ uint8_t *data[4];
+ int linesize[4];
+
+ if (!desc)
+ return AVERROR(EINVAL);
+ if (av_image_check_size(width, height, 0, NULL) < 0)
+ return AVERROR(EINVAL);
+ if (desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL)
+ // do not include palette for these pseudo-paletted formats
+ return width * height;
+ return av_image_fill_arrays(data, linesize, NULL, pix_fmt, width, height, align);
+}
+
+int av_image_copy_to_buffer(uint8_t *dst, int dst_size,
+ const uint8_t * const src_data[4], const int src_linesize[4],
+ enum AVPixelFormat pix_fmt, int width, int height, int align)
+{
+ int i, j, nb_planes = 0, linesize[4];
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
+ int size = av_image_get_buffer_size(pix_fmt, width, height, align);
+
+ if (size > dst_size || size < 0)
+ return AVERROR(EINVAL);
+
+ for (i = 0; i < desc->nb_components; i++)
+ nb_planes = FFMAX(desc->comp[i].plane, nb_planes);
+ nb_planes++;
+
+ av_image_fill_linesizes(linesize, pix_fmt, width);
+ for (i = 0; i < nb_planes; i++) {
+ int h, shift = (i == 1 || i == 2) ? desc->log2_chroma_h : 0;
+ const uint8_t *src = src_data[i];
+ h = (height + (1 << shift) - 1) >> shift;
+
+ for (j = 0; j < h; j++) {
+ memcpy(dst, src, linesize[i]);
+ dst += FFALIGN(linesize[i], align);
+ src += src_linesize[i];
+ }
+ }
+
+ 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 50fa815..2ec246a 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
*/
@@ -118,6 +121,65 @@ void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4],
enum AVPixelFormat pix_fmt, int width, int height);
/**
+ * Setup the data pointers and linesizes based on the specified image
+ * parameters and the provided array.
+ *
+ * The fields of the given image are filled in by using the src
+ * address which points to the image data buffer. Depending on the
+ * specified pixel format, one or multiple image data pointers and
+ * line sizes will be set. If a planar format is specified, several
+ * pointers will be set pointing to the different picture planes and
+ * the line sizes of the different planes will be stored in the
+ * lines_sizes array. Call with !src to get the required
+ * size for the src buffer.
+ *
+ * To allocate the buffer and fill in the dst_data and dst_linesize in
+ * one call, use av_image_alloc().
+ *
+ * @param dst_data data pointers to be filled in
+ * @param dst_linesizes linesizes for the image in dst_data to be filled in
+ * @param src buffer which will contain or contains the actual image data, can be NULL
+ * @param pix_fmt the pixel format of the image
+ * @param width the width of the image in pixels
+ * @param height the height of the image in pixels
+ * @param align the value used in src for linesize alignment
+ * @return the size in bytes required for src, a negative error code
+ * in case of failure
+ */
+int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4],
+ const uint8_t *src,
+ enum AVPixelFormat pix_fmt, int width, int height, int align);
+
+/**
+ * Return the size in bytes of the amount of data required to store an
+ * image with the given parameters.
+ *
+ * @param[in] align the assumed linesize alignment
+ */
+int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align);
+
+/**
+ * Copy image data from an image into a buffer.
+ *
+ * av_image_get_buffer_size() can be used to compute the required size
+ * for the buffer to fill.
+ *
+ * @param dst a buffer into which picture data will be copied
+ * @param dst_size the size in bytes of dst
+ * @param src_data pointers containing the source image data
+ * @param src_linesizes linesizes for the image in src_data
+ * @param pix_fmt the pixel format of the source image
+ * @param width the width of the source image in pixels
+ * @param height the height of the source image in pixels
+ * @param align the assumed linesize alignment for dst
+ * @return the number of bytes written to dst, or a negative value
+ * (error code) on error
+ */
+int av_image_copy_to_buffer(uint8_t *dst, int dst_size,
+ const uint8_t * const src_data[4], const int src_linesize[4],
+ enum AVPixelFormat pix_fmt, int width, int height, int align);
+
+/**
* Check if the given dimension of an image is valid, meaning that all
* bytes of the image can be addressed with a signed int.
*
diff --git a/libavutil/integer.c b/libavutil/integer.c
new file mode 100644
index 0000000..5bcde0d
--- /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 0000000..45f733c
--- /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 aed9925..612b5f2 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,8 +36,11 @@
#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"
@@ -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)
@@ -81,6 +84,12 @@
# define INT_BIT (CHAR_BIT * sizeof(int))
#endif
+#define FF_MEMORY_POISON 0x2a
+
+#define MAKE_ACCESSORS(str, name, type, field) \
+ type av_##name##_get_##field(const str *s) { return s->field; } \
+ void av_##name##_set_##field(str *s, type v) { s->field = v; }
+
// Some broken preprocessors need a second expansion
// to be forced to tokenize __VA_ARGS__
#define E1(x) x
@@ -114,6 +123,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);\
@@ -132,6 +147,24 @@
}\
}
+#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)
@@ -150,12 +183,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.
@@ -213,6 +245,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
/**
@@ -222,4 +259,8 @@ int avpriv_open(const char *filename, int flags, ...);
int avpriv_set_systematic_pal2(uint32_t pal[256], enum AVPixelFormat pix_fmt);
+#if FF_API_GET_CHANNEL_LAYOUT_COMPAT
+uint64_t ff_get_channel_layout(const char *name, int compat);
+#endif
+
#endif /* AVUTIL_INTERNAL_H */
diff --git a/libavutil/intfloat.h b/libavutil/intfloat.h
index 38d26ad..fe3d7ec 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 8db425c..1f725c7 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 a5ee652..308c776 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
*/
@@ -35,21 +35,29 @@
* @{
*/
-#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 +73,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 +111,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 +154,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 f77fd60..51fbe30 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 4221e62..ffa2f1f 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 5e526c1..ec90562 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 d6c2cf8..6c17b28 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 f87c2cd..f77043b 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 27c0d5e..5635b5b 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 d38e40b..2091316 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,34 +34,88 @@
#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
+
static int av_log_level = AV_LOG_INFO;
static int flags;
-#if HAVE_SETCONSOLETEXTATTRIBUTE
+#if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE
#include <windows.h>
-static const uint8_t color[] = { 12, 12, 12, 14, 7, 10, 11 };
+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,
+ [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[] = { 0x41, 0x41, 0x11, 0x03, 9, 0x02, 0x06 };
-#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")
+
+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,
+ [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,
+};
+
#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") &&
@@ -75,8 +129,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");
@@ -85,25 +140,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)
@@ -111,56 +186,156 @@ 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));
}
- vsnprintf(line + strlen(line), sizeof(line) - strlen(line), fmt, vl);
+ av_vbprintf(part+3, fmt, vl);
- print_prefix = strlen(line) && line[strlen(line) - 1] == '\n';
+ 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;
+ }
+
+ if (level > av_log_level)
+ return;
+#if HAVE_PTHREADS
+ pthread_mutex_lock(&mutex);
+#endif
+
+ 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, 6), 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, 6), tint >> 8, part[2].str);
+ sanitize(part[3].str);
+ colored_fputs(av_clip(level >> 3, 0, 6), tint >> 8, part[3].str);
+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) =
@@ -180,7 +355,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)
@@ -198,6 +375,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;
@@ -207,14 +389,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, ...)
@@ -234,3 +416,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 4e4424a..e1ff09b 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
*/
@@ -25,6 +25,39 @@
#include "avutil.h"
#include "attributes.h"
+typedef enum {
+ AV_CLASS_CATEGORY_NA = 0,
+ AV_CLASS_CATEGORY_INPUT,
+ AV_CLASS_CATEGORY_OUTPUT,
+ AV_CLASS_CATEGORY_MUXER,
+ AV_CLASS_CATEGORY_DEMUXER,
+ AV_CLASS_CATEGORY_ENCODER,
+ AV_CLASS_CATEGORY_DECODER,
+ AV_CLASS_CATEGORY_FILTER,
+ AV_CLASS_CATEGORY_BITSTREAM_FILTER,
+ AV_CLASS_CATEGORY_SWSCALER,
+ AV_CLASS_CATEGORY_SWRESAMPLER,
+ AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT = 40,
+ AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
+ AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT,
+ AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT,
+ AV_CLASS_CATEGORY_DEVICE_OUTPUT,
+ AV_CLASS_CATEGORY_DEVICE_INPUT,
+ AV_CLASS_CATEGORY_NB, ///< not part of ABI/API
+}AVClassCategory;
+
+#define AV_IS_INPUT_DEVICE(category) \
+ (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) || \
+ ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT) || \
+ ((category) == AV_CLASS_CATEGORY_DEVICE_INPUT))
+
+#define AV_IS_OUTPUT_DEVICE(category) \
+ (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT) || \
+ ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT) || \
+ ((category) == AV_CLASS_CATEGORY_DEVICE_OUTPUT))
+
+struct AVOptionRanges;
+
/**
* Describe the class of an AVClass context structure. That is an
* arbitrary struct of which the first field is a pointer to an
@@ -87,6 +120,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;
/**
@@ -143,6 +195,8 @@ typedef struct AVClass {
*/
#define AV_LOG_DEBUG 48
+#define AV_LOG_MAX_OFFSET (AV_LOG_DEBUG - AV_LOG_QUIET)
+
/**
* @}
*/
@@ -212,6 +266,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.
@@ -242,6 +299,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);
/**
* av_dlog macros
@@ -251,7 +319,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
/**
@@ -260,10 +328,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 f6cbe79..0dbf07d 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 e458165..bca10ec 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 9d7e8f1..c034039 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 bf3eb9b..4465323 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 f36623a..126cffc 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 043dd0f..ac94488 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 efb993e..876bd55 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 29e4e7c..79702c8 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 b7bb65c..35a82e8 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 **ptrptr = ptr;
@@ -167,27 +212,20 @@ void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
{
void **ptrptr = ptr;
- void *ret;
- if (!size || nmemb >= INT_MAX / size)
+ *ptrptr = av_realloc_f(*ptrptr, nmemb, size);
+ if (!*ptrptr && nmemb && size)
return AVERROR(ENOMEM);
- if (!nmemb) {
- av_freep(ptr);
- return 0;
- }
- ret = av_realloc(*ptrptr, nmemb * size);
- if (!ret) {
- av_freep(ptr);
- return AVERROR(ENOMEM);
- }
- *ptrptr = ret;
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
@@ -210,6 +248,13 @@ 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;
@@ -242,6 +287,61 @@ 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 = *(void ***)tab_ptr;
+
+ AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
+ tab[*nb_ptr] = elem;
+ *(void ***)tab_ptr = tab;
+ }, {
+ return AVERROR(ENOMEM);
+ });
+ return 0;
+}
+
+void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
+{
+ void **tab = *(void ***)tab_ptr;
+
+ AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
+ tab[*nb_ptr] = elem;
+ *(void ***)tab_ptr = tab;
+ }, {
+ *nb_ptr = 0;
+ av_freep(tab_ptr);
+ });
+}
+
+void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
+ const uint8_t *elem_data)
+{
+ uint8_t *tab_elem_data = NULL;
+
+ AV_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, {
+ tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size;
+ if (elem_data)
+ memcpy(tab_elem_data, elem_data, elem_size);
+ else if (CONFIG_MEMORY_POISONING)
+ memset(tab_elem_data, FF_MEMORY_POISON, elem_size);
+ }, {
+ av_freep(tab_ptr);
+ *nb_ptr = 0;
+ });
+ return tab_elem_data;
+}
+
static void fill16(uint8_t *dst, int len)
{
uint32_t v = AV_RN16(dst - 2);
@@ -385,15 +485,22 @@ 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;
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);
+ *p = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size);
if (!*p)
min_size = 0;
*size = min_size;
+ return 1;
}
+
+void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
+{
+ ff_fast_malloc(ptr, size, min_size, 0);
+}
+
diff --git a/libavutil/mem.h b/libavutil/mem.h
index 9f667c2..2a1e36d 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 0000000..dbfa5aa
--- /dev/null
+++ b/libavutil/mips/Makefile
@@ -0,0 +1 @@
+OBJS += mips/float_dsp_mips.o
diff --git a/libavutil/mips/float_dsp_mips.c b/libavutil/mips/float_dsp_mips.c
new file mode 100644
index 0000000..06d52dc
--- /dev/null
+++ b/libavutil/mips/float_dsp_mips.c
@@ -0,0 +1,383 @@
+/*
+ * 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"
+
+#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"
+ "addiu %[s0], %[s0], 16 \n\t"
+ "addiu %[s1], %[s1], 16 \n\t"
+ "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"
+ "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"
+ "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)
+{
+ int i, j;
+ /*
+ * variables used in inline assembler
+ */
+ float * dst_i, * dst_j, * dst_i2, * dst_j2;
+ float temp, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ dst += len;
+ win += len;
+ src0 += len;
+
+ for (i = -len, j = len - 1; i < 0; i += 8, j -= 8) {
+
+ dst_i = dst + i;
+ dst_j = dst + j;
+
+ dst_i2 = dst + i + 4;
+ dst_j2 = dst + j - 4;
+
+ __asm__ volatile (
+ "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"
+
+ "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"
+
+ "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 %[temp4], %[s12], %[wi2] \n\t"
+ "mul.s %[temp5], %[s12], %[wj2] \n\t"
+ "mul.s %[temp6], %[s13], %[wi3] \n\t"
+ "mul.s %[temp7], %[s13], %[wj3] \n\t"
+
+ "msub.s %[temp4], %[temp4], %[s02], %[wj2] \n\t"
+ "madd.s %[temp5], %[temp5], %[s02], %[wi2] \n\t"
+ "msub.s %[temp6], %[temp6], %[s03], %[wj3] \n\t"
+ "madd.s %[temp7], %[temp7], %[s03], %[wi3] \n\t"
+
+ "swc1 %[temp4], 8(%[dst_i]) \n\t" /* dst[i+2] = s02*wj2 - s12*wi2; */
+ "swc1 %[temp5], -8(%[dst_j]) \n\t" /* dst[j-2] = s02*wi2 + s12*wj2; */
+ "swc1 %[temp6], 12(%[dst_i]) \n\t" /* dst[i+2] = s03*wj3 - s13*wi3; */
+ "swc1 %[temp7], -12(%[dst_j]) \n\t" /* dst[j-3] = s03*wi3 + s13*wj3; */
+ : [temp]"=&f"(temp), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7)
+ : [dst_j]"r"(dst_j), [dst_i]"r" (dst_i),
+ [s0] "f"(src0[i]), [wj] "f"(win[j]), [s1] "f"(src1[j]),
+ [wi] "f"(win[i]), [s01]"f"(src0[i + 1]),[wj1]"f"(win[j - 1]),
+ [s11]"f"(src1[j - 1]), [wi1]"f"(win[i + 1]), [s02]"f"(src0[i + 2]),
+ [wj2]"f"(win[j - 2]), [s12]"f"(src1[j - 2]),[wi2]"f"(win[i + 2]),
+ [s03]"f"(src0[i + 3]), [wj3]"f"(win[j - 3]), [s13]"f"(src1[j - 3]),
+ [wi3]"f"(win[i + 3])
+ : "memory"
+ );
+
+ __asm__ volatile (
+ "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"
+
+ "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"
+
+ "swc1 %[temp], 0(%[dst_i2]) \n\t" /* dst[i] = s0*wj - s1*wi; */
+ "swc1 %[temp1], 0(%[dst_j2]) \n\t" /* dst[j] = s0*wi + s1*wj; */
+ "swc1 %[temp2], 4(%[dst_i2]) \n\t" /* dst[i+1] = s01*wj1 - s11*wi1; */
+ "swc1 %[temp3], -4(%[dst_j2]) \n\t" /* dst[j-1] = s01*wi1 + s11*wj1; */
+
+ "mul.s %[temp4], %[s12], %[wi2] \n\t"
+ "mul.s %[temp5], %[s12], %[wj2] \n\t"
+ "mul.s %[temp6], %[s13], %[wi3] \n\t"
+ "mul.s %[temp7], %[s13], %[wj3] \n\t"
+
+ "msub.s %[temp4], %[temp4], %[s02], %[wj2] \n\t"
+ "madd.s %[temp5], %[temp5], %[s02], %[wi2] \n\t"
+ "msub.s %[temp6], %[temp6], %[s03], %[wj3] \n\t"
+ "madd.s %[temp7], %[temp7], %[s03], %[wi3] \n\t"
+
+ "swc1 %[temp4], 8(%[dst_i2]) \n\t" /* dst[i+2] = s02*wj2 - s12*wi2; */
+ "swc1 %[temp5], -8(%[dst_j2]) \n\t" /* dst[j-2] = s02*wi2 + s12*wj2; */
+ "swc1 %[temp6], 12(%[dst_i2]) \n\t" /* dst[i+2] = s03*wj3 - s13*wi3; */
+ "swc1 %[temp7], -12(%[dst_j2]) \n\t" /* dst[j-3] = s03*wi3 + s13*wj3; */
+ : [temp]"=&f"(temp),
+ [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), [temp3]"=&f"(temp3),
+ [temp4]"=&f"(temp4), [temp5]"=&f"(temp5), [temp6]"=&f"(temp6),
+ [temp7] "=&f" (temp7)
+ : [dst_j2]"r"(dst_j2), [dst_i2]"r"(dst_i2),
+ [s0] "f"(src0[i + 4]), [wj] "f"(win[j - 4]), [s1] "f"(src1[j - 4]),
+ [wi] "f"(win[i + 4]), [s01]"f"(src0[i + 5]),[wj1]"f"(win[j - 5]),
+ [s11]"f"(src1[j - 5]), [wi1]"f"(win[i + 5]), [s02]"f"(src0[i + 6]),
+ [wj2]"f"(win[j - 6]), [s12]"f"(src1[j - 6]),[wi2]"f"(win[i + 6]),
+ [s03]"f"(src0[i + 7]), [wj3]"f"(win[j - 7]), [s13]"f"(src1[j - 7]),
+ [wi3]"f"(win[i + 7])
+ : "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"
+ "addiu %[v1], %[v1], 16 \n\t"
+ "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"
+ "addiu %[src0], %[src0], 16 \n\t"
+ "addiu %[src1], %[src1], -16 \n\t"
+ "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/intreadwrite.h b/libavutil/mips/intreadwrite.h
index 4dabbe6..9ba0491 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
*/
diff --git a/libavutil/mips/libm_mips.h b/libavutil/mips/libm_mips.h
new file mode 100644
index 0000000..8853bbc
--- /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 0000000..30cfb99
--- /dev/null
+++ b/libavutil/motion_vector.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_MOTION_VECTOR_H
+#define AVUTIL_MOTION_VECTOR_H
+
+#include <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 0000000..701fa6a
--- /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 0000000..f29ed97
--- /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 d3e1e5b..cd1ed7c 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 0000000..36cb6fe
--- /dev/null
+++ b/libavutil/opencl.c
@@ -0,0 +1,815 @@
+/*
+ * 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]));
+ }
+ av_freep(&device_list->platform_node[i]->device_node);
+ 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;
+ 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,
+ sizeof(device_list->platform_node[i]->platform_name),
+ device_list->platform_node[i]->platform_name, NULL);
+ 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,
+ sizeof(device_node->device_name), 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)
+{
+ 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;
+ }
+ 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 0000000..4655cba
--- /dev/null
+++ b/libavutil/opencl.h
@@ -0,0 +1,298 @@
+/*
+ * 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
+
+#include "config.h"
+#if HAVE_CL_CL_H
+#include <CL/cl.h>
+#else
+#include <OpenCL/cl.h>
+#endif
+#include <stdint.h>
+#include "dict.h"
+
+#include "libavutil/version.h"
+
+#define AV_OPENCL_KERNEL( ... )# __VA_ARGS__
+
+#define AV_OPENCL_MAX_KERNEL_NAME_SIZE 150
+
+#define AV_OPENCL_MAX_DEVICE_NAME_SIZE 100
+
+#define AV_OPENCL_MAX_PLATFORM_NAME_SIZE 100
+
+typedef struct {
+ int device_type;
+ char device_name[AV_OPENCL_MAX_DEVICE_NAME_SIZE];
+ cl_device_id device_id;
+} AVOpenCLDeviceNode;
+
+typedef struct {
+ cl_platform_id platform_id;
+ char platform_name[AV_OPENCL_MAX_PLATFORM_NAME_SIZE];
+ int device_num;
+ AVOpenCLDeviceNode **device_node;
+} AVOpenCLPlatformNode;
+
+typedef struct {
+ int platform_num;
+ AVOpenCLPlatformNode **platform_node;
+} AVOpenCLDeviceList;
+
+typedef struct {
+ cl_platform_id platform_id;
+ cl_device_type device_type;
+ cl_context context;
+ cl_device_id device_id;
+ cl_command_queue command_queue;
+ char *platform_name;
+} AVOpenCLExternalEnv;
+
+/**
+ * Get OpenCL device list.
+ *
+ * It must be freed with av_opencl_free_device_list().
+ *
+ * @param device_list pointer to OpenCL environment device list,
+ * should be released by av_opencl_free_device_list()
+ *
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_get_device_list(AVOpenCLDeviceList **device_list);
+
+/**
+ * Free OpenCL device list.
+ *
+ * @param device_list pointer to OpenCL environment device list
+ * created by av_opencl_get_device_list()
+ */
+void av_opencl_free_device_list(AVOpenCLDeviceList **device_list);
+
+/**
+ * Set option in the global OpenCL context.
+ *
+ * This options affect the operation performed by the next
+ * av_opencl_init() operation.
+ *
+ * The currently accepted options are:
+ * - platform: set index of platform in device list
+ * - device: set index of device in device list
+ *
+ * See reference "OpenCL Specification Version: 1.2 chapter 5.6.4".
+ *
+ * @param key option key
+ * @param val option value
+ * @return >=0 on success, a negative error code in case of failure
+ * @see av_opencl_get_option()
+ */
+int av_opencl_set_option(const char *key, const char *val);
+
+/**
+ * Get option value from the global OpenCL context.
+ *
+ * @param key option key
+ * @param out_val pointer to location where option value will be
+ * written, must be freed with av_freep()
+ * @return >=0 on success, a negative error code in case of failure
+ * @see av_opencl_set_option()
+ */
+int av_opencl_get_option(const char *key, uint8_t **out_val);
+
+/**
+ * Free option values of the global OpenCL context.
+ *
+ */
+void av_opencl_free_option(void);
+
+/**
+ * Allocate OpenCL external environment.
+ *
+ * It must be freed with av_opencl_free_external_env().
+ *
+ * @return pointer to allocated OpenCL external environment
+ */
+AVOpenCLExternalEnv *av_opencl_alloc_external_env(void);
+
+/**
+ * Free OpenCL external environment.
+ *
+ * @param ext_opencl_env pointer to OpenCL external environment
+ * created by av_opencl_alloc_external_env()
+ */
+void av_opencl_free_external_env(AVOpenCLExternalEnv **ext_opencl_env);
+
+/**
+ * Get OpenCL error string.
+ *
+ * @param status OpenCL error code
+ * @return OpenCL error string
+ */
+const char *av_opencl_errstr(cl_int status);
+
+/**
+ * Register kernel code.
+ *
+ * The registered kernel code is stored in a global context, and compiled
+ * in the runtime environment when av_opencl_init() is called.
+ *
+ * @param kernel_code kernel code to be compiled in the OpenCL runtime environment
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_register_kernel_code(const char *kernel_code);
+
+/**
+ * Initialize the run time OpenCL environment
+ *
+ * @param ext_opencl_env external OpenCL environment, created by an
+ * application program, ignored if set to NULL
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env);
+
+/**
+ * compile specific OpenCL kernel source
+ *
+ * @param program_name pointer to a program name used for identification
+ * @param build_opts pointer to a string that describes the preprocessor
+ * build options to be used for building the program
+ * @return a cl_program object
+ */
+cl_program av_opencl_compile(const char *program_name, const char* build_opts);
+
+/**
+ * get OpenCL command queue
+ *
+ * @return a cl_command_queue object
+ */
+cl_command_queue av_opencl_get_command_queue(void);
+
+/**
+ * Create OpenCL buffer.
+ *
+ * The buffer is used to save the data used or created by an OpenCL
+ * kernel.
+ * The created buffer must be released with av_opencl_buffer_release().
+ *
+ * See clCreateBuffer() function reference for more information about
+ * the parameters.
+ *
+ * @param cl_buf pointer to OpenCL buffer
+ * @param cl_buf_size size in bytes of the OpenCL buffer to create
+ * @param flags flags used to control buffer attributes
+ * @param host_ptr host pointer of the OpenCL buffer
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr);
+
+/**
+ * Write OpenCL buffer with data from src_buf.
+ *
+ * @param dst_cl_buf pointer to OpenCL destination buffer
+ * @param src_buf pointer to source buffer
+ * @param buf_size size in bytes of the source and destination buffers
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size);
+
+/**
+ * Read data from OpenCL buffer to memory buffer.
+ *
+ * @param dst_buf pointer to destination buffer (CPU memory)
+ * @param src_cl_buf pointer to source OpenCL buffer
+ * @param buf_size size in bytes of the source and destination buffers
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size);
+
+/**
+ * Write image data from memory to OpenCL buffer.
+ *
+ * The source must be an array of pointers to image plane buffers.
+ *
+ * @param dst_cl_buf pointer to destination OpenCL buffer
+ * @param dst_cl_buf_size size in bytes of OpenCL buffer
+ * @param dst_cl_buf_offset the offset of the OpenCL buffer start position
+ * @param src_data array of pointers to source plane buffers
+ * @param src_plane_sizes array of sizes in bytes of the source plane buffers
+ * @param src_plane_num number of source image planes
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_buffer_write_image(cl_mem dst_cl_buf, size_t cl_buffer_size, int dst_cl_offset,
+ uint8_t **src_data, int *plane_size, int plane_num);
+
+/**
+ * Read image data from OpenCL buffer.
+ *
+ * @param dst_data array of pointers to destination plane buffers
+ * @param dst_plane_sizes array of pointers to destination plane buffers
+ * @param dst_plane_num number of destination image planes
+ * @param src_cl_buf pointer to source OpenCL buffer
+ * @param src_cl_buf_size size in bytes of OpenCL buffer
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_num,
+ cl_mem src_cl_buf, size_t cl_buffer_size);
+
+/**
+ * Release OpenCL buffer.
+ *
+ * @param cl_buf pointer to OpenCL buffer to release, which was
+ * previously filled with av_opencl_buffer_create()
+ */
+void av_opencl_buffer_release(cl_mem *cl_buf);
+
+/**
+ * Release OpenCL environment.
+ *
+ * The OpenCL environment is effectively released only if all the created
+ * kernels had been released with av_opencl_release_kernel().
+ */
+void av_opencl_uninit(void);
+
+/**
+ * Benchmark an OpenCL device with a user defined callback function. This function
+ * sets up an external OpenCL environment including context and command queue on
+ * the device then tears it down in the end. The callback function should perform
+ * the rest of the work.
+ *
+ * @param device pointer to the OpenCL device to be used
+ * @param platform cl_platform_id handle to which the device belongs to
+ * @param benchmark callback function to perform the benchmark, return a
+ * negative value in case of failure
+ * @return the score passed from the callback function, a negative error code in case
+ * of failure
+ */
+int64_t av_opencl_benchmark(AVOpenCLDeviceNode *device, cl_platform_id platform,
+ int64_t (*benchmark)(AVOpenCLExternalEnv *ext_opencl_env));
+
+#endif /* LIBAVUTIL_OPENCL_H */
diff --git a/libavutil/opencl_internal.c b/libavutil/opencl_internal.c
new file mode 100644
index 0000000..bdb4193
--- /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 0000000..dacd930
--- /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 28adef6..4e286ff 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,17 +27,30 @@
#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 <float.h>
+
+#if FF_API_OLD_AVOPTIONS
+const AVOption *av_next_option(void *obj, const AVOption *last)
+{
+ return av_opt_next(obj, last);
+}
+#endif
const AVOption *av_opt_next(void *obj, const AVOption *last)
{
AVClass *class = *(AVClass**)obj;
- if (!last && class->option && class->option[0].name)
+ if (!last && class && class->option && class->option[0].name)
return class->option;
if (last && last[1].name)
return ++last;
@@ -48,13 +61,18 @@ static int read_number(const AVOption *o, void *dst, double *num, int *den, int6
{
switch (o->type) {
case AV_OPT_TYPE_FLAGS: *intnum = *(unsigned int*)dst;return 0;
+ case AV_OPT_TYPE_PIXEL_FMT:
+ case AV_OPT_TYPE_SAMPLE_FMT:
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 +81,27 @@ 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);
+ av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n",
+ num*intnum/den, 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_FLAGS:
+ case AV_OPT_TYPE_PIXEL_FMT:
+ case AV_OPT_TYPE_SAMPLE_FMT:
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 +115,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 +126,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;
@@ -149,37 +169,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;
@@ -190,30 +242,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;
@@ -226,6 +386,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");
@@ -263,6 +455,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);
@@ -292,8 +510,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);
@@ -302,11 +520,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;
@@ -331,8 +685,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;
@@ -344,7 +699,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);
@@ -357,10 +714,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);
}
@@ -371,7 +756,7 @@ int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
return 0;
}
-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;
@@ -381,6 +766,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:
@@ -388,13 +775,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;
@@ -406,7 +831,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;
@@ -418,7 +843,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)
@@ -428,6 +887,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;
@@ -458,10 +962,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))
@@ -478,42 +1017,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' : '.');
@@ -522,6 +1085,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);
@@ -543,8 +1170,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;
@@ -555,25 +1195,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;
@@ -623,7 +1282,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)
@@ -654,6 +1313,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;
@@ -674,14 +1445,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) {
@@ -695,6 +1469,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)
{
@@ -704,9 +1483,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;
@@ -727,7 +1511,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;
@@ -755,6 +1539,199 @@ 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, 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);
+}
+
#ifdef TEST
typedef struct TestContext
@@ -765,6 +1742,18 @@ 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;
+ int64_t num64;
+ float flt;
+ double dbl;
} TestContext;
#define OFFSET(x) offsetof(TestContext, x)
@@ -775,13 +1764,24 @@ typedef struct TestContext
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" },
+{"toggle", "set toggle", OFFSET(toggle), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1 },
+{"rational", "set rational", OFFSET(rational), AV_OPT_TYPE_RATIONAL, {.dbl = 1}, 0, 10 },
+{"string", "set string", OFFSET(string), AV_OPT_TYPE_STRING, {.str = "default"}, CHAR_MIN, CHAR_MAX },
+{"flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 1}, 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" },
+{"size", "set size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE,{.str="200x300"}, 0, 0 },
+{"pix_fmt", "set pixfmt", OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_0BGR}, -1, INT_MAX},
+{"sample_fmt", "set samplefmt", OFFSET(sample_fmt), AV_OPT_TYPE_SAMPLE_FMT, {.i64 = AV_SAMPLE_FMT_S16}, -1, INT_MAX},
+{"video_rate", "set videorate", OFFSET(video_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0 },
+{"duration", "set duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 1000}, 0, INT64_MAX},
+{"color", "set color", OFFSET(color), AV_OPT_TYPE_COLOR, {.str = "pink"}, 0, 0},
+{"cl", "set channel layout", OFFSET(channel_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64 = AV_CH_LAYOUT_HEXAGONAL}, 0, INT64_MAX},
+{"bin", "set binary value", OFFSET(binary), AV_OPT_TYPE_BINARY, {.str="62696e00"}, 0, 0 },
+{"num64", "set num 64bit", OFFSET(num64), AV_OPT_TYPE_INT64, {.i64 = 1}, 0, 100 },
+{"flt", "set float", OFFSET(flt), AV_OPT_TYPE_FLOAT, {.dbl = 1.0/3}, 0, 100 },
+{"dbl", "set double", OFFSET(dbl), AV_OPT_TYPE_DOUBLE, {.dbl = 1.0/3}, 0, 100 },
{NULL},
};
@@ -800,10 +1800,37 @@ int main(void)
{
int i;
+ 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("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_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[] = {
"",
":",
"=",
@@ -823,20 +1850,92 @@ 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");
- av_log_set_level(AV_LOG_DEBUG);
+ 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_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_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 8413206..39365ac 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,8 @@
#include "avutil.h"
#include "dict.h"
#include "log.h"
+#include "pixfmt.h"
+#include "samplefmt.h"
/**
* @defgroup avoptions AVOptions
@@ -44,7 +46,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 +83,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 +163,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 +178,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 +228,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 +298,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 +310,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(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 +437,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 +463,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 +507,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 +523,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 +609,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.
*
@@ -497,11 +722,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 +763,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 +784,66 @@ 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, 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);
+
+/**
* @}
*/
diff --git a/libavutil/parseutils.c b/libavutil/parseutils.c
index 1ca0086..4708699 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 {
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 {
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,19 +461,26 @@ static int date_get_num(const char **pp,
return val;
}
-static const char *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;
for(;;) {
+ /* consume time string until a non whitespace char is found */
+ while (av_isspace(*fmt)) {
+ while (av_isspace(*p))
+ p++;
+ fmt++;
+ }
c = *fmt++;
if (c == '\0') {
- return p;
+ return (char *)p;
} else if (c == '%') {
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;
@@ -472,7 +540,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;
@@ -482,9 +550,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",
@@ -494,58 +564,41 @@ 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;
}
/* parse the year-month-day part */
for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) {
- q = small_strptime(p, date_fmt[i], &dt);
- if (q) {
+ q = av_small_strptime(p, date_fmt[i], &dt);
+ 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++;
/* parse the hour-minute-second part */
for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) {
- q = small_strptime(p, time_fmt[i], &dt);
- if (q) {
+ q = av_small_strptime(p, time_fmt[i], &dt);
+ if (q)
break;
- }
}
} else {
/* parse timestr as a duration */
@@ -554,16 +607,18 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration)
++p;
}
/* parse timestr as HH:MM:SS */
- q = 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;
@@ -571,35 +626,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;
}
@@ -645,6 +708,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");
@@ -692,6 +762,8 @@ int main(void)
int i;
uint8_t rgba[4];
static const char *const color_names[] = {
+ "bikeshed",
+ "RaNdOm",
"foo",
"red",
"Red ",
@@ -734,6 +806,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 0844abb..c80f0de 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,17 +135,43 @@ 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);
/**
+ * Parse the input string p according to the format string fmt and
+ * store its results in the structure dt.
+ * This implementation supports only a subset of the formats supported
+ * by the standard strptime().
+ *
+ * In particular it actually supports the parameters:
+ * - %H: the hour as a decimal number, using a 24-hour clock, in the
+ * range '00' through '23'
+ * - %J: hours as a decimal number, in the range '0' through INT_MAX
+ * - %M: the minute as a decimal number, using a 24-hour clock, in the
+ * range '00' through '59'
+ * - %S: the second as a decimal number, using a 24-hour clock, in the
+ * range '00' through '59'
+ * - %Y: the year as a decimal number, using the Gregorian calendar
+ * - %m: the month as a decimal number, in the range '1' through '12'
+ * - %d: the day of the month as a decimal number, in the range '1'
+ * through '31'
+ * - %%: a literal '%'
+ *
+ * @return a pointer to the first character not processed in this
+ * function call, or NULL in case the function fails to match all of
+ * the fmt string and therefore an error occurred
+ */
+char *av_small_strptime(const char *p, const char *fmt, struct tm *dt);
+
+/**
* Attempt to find a specific tag in a URL.
*
* syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done.
diff --git a/libavutil/pca.c b/libavutil/pca.c
new file mode 100644
index 0000000..f7ae350
--- /dev/null
+++ b/libavutil/pca.c
@@ -0,0 +1,248 @@
+/*
+ * 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));
+ 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));
+
+ 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 0000000..992bb2e
--- /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 baace8c..648d014 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,
@@ -551,7 +618,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 +655,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 +1044,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 +1056,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 +1068,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 +1081,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 +1094,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 +1106,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 +1118,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 +1130,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 +1142,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 +1154,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 +1178,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 +1226,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 +1346,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,12 +1490,66 @@ 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_DXVA2_VLD] = {
.name = "dxva2_vld",
.log2_chroma_w = 1,
.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,
@@ -1373,9 +1584,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,
},
@@ -1385,9 +1596,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,
},
@@ -1397,9 +1608,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,
},
@@ -1409,9 +1620,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,
},
@@ -1421,9 +1632,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,
},
@@ -1433,9 +1692,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,
},
@@ -1445,12 +1704,51 @@ 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,
},
+ [AV_PIX_FMT_GBRAP] = {
+ .name = "gbrap",
+ .nb_components = 4,
+ .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 */
+ { 3, 0, 1, 0, 7 }, /* A */
+ },
+ .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA,
+ },
+ [AV_PIX_FMT_GBRAP16LE] = {
+ .name = "gbrap16le",
+ .nb_components = 4,
+ .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 */
+ { 3, 1, 1, 0, 15 }, /* A */
+ },
+ .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA,
+ },
+ [AV_PIX_FMT_GBRAP16BE] = {
+ .name = "gbrap16be",
+ .nb_components = 4,
+ .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 */
+ { 3, 1, 1, 0, 15 }, /* A */
+ },
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA,
+ },
[AV_PIX_FMT_VDPAU] = {
.name = "vdpau",
.log2_chroma_w = 1,
@@ -1481,6 +1779,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,
@@ -1608,6 +1987,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)
{
@@ -1634,8 +2033,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;
}
@@ -1676,56 +2078,258 @@ 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);
+ }
+ }
+}
+
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);
}
-#undef PIX_FMT_SWAP_ENDIANNESS
+
+ *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;
+ }
+ 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)
@@ -1758,3 +2362,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 23dc009..a4376b2 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];
@@ -127,7 +130,7 @@ typedef struct AVPixFmtDescriptor {
*/
#define AV_PIX_FMT_FLAG_RGB (1 << 5)
/**
- * The pixel format is "pseudo-paletted". This means that Libav treats it as
+ * The pixel format is "pseudo-paletted". This means that FFmpeg treats it as
* paletted internally, but the palette is generated by the decoder and is not
* stored in the file.
*/
@@ -205,7 +208,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 +222,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 +245,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 +275,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
*/
@@ -281,6 +295,8 @@ int av_pix_fmt_get_chroma_sub_sample(enum AVPixelFormat pix_fmt,
*/
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt);
+void ff_check_pixfmt_descriptors(void);
+
/**
* Utility function to swap the endianness of a pixel format.
*
@@ -291,6 +307,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 0000000..8f04024
--- /dev/null
+++ b/libavutil/pixelutils.c
@@ -0,0 +1,219 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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"
+
+#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;
+ }
+
+#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 0000000..a8dbc15
--- /dev/null
+++ b/libavutil/pixelutils.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_PIXELUTILS_H
+#define AVUTIL_PIXELUTILS_H
+
+#include <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 6af6596..756a1a7 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,21 +30,24 @@
#include "libavutil/avconfig.h"
#include "version.h"
+#define AVPALETTE_SIZE 1024
+#define AVPALETTE_COUNT 256
+
/**
* Pixel format.
*
* @note
- * PIX_FMT_RGB32 is handled in an endian-specific manner. An RGBA
+ * AV_PIX_FMT_RGB32 is handled in an endian-specific manner. An RGBA
* color is put together as:
* (A << 24) | (R << 16) | (G << 8) | B
* This is stored as BGRA on little-endian CPU architectures and ARGB on
* big-endian CPUs.
*
* @par
- * When the pixel format is palettized RGB (PIX_FMT_PAL8), the palettized
+ * When the pixel format is palettized RGB (AV_PIX_FMT_PAL8), the palettized
* image data is stored in AVFrame.data[0]. The palette is transported in
* AVFrame.data[1], is 1024 bytes long (256 4-byte entries) and is
- * formatted the same as in PIX_FMT_RGB32 described above (i.e., it is
+ * formatted the same as in AV_PIX_FMT_RGB32 described above (i.e., it is
* also endian-specific). Note also that the individual RGB palette
* components stored in AVFrame.data[1] should be in the range 0..255.
* This is important as many custom PAL8 video codecs that were designed
@@ -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
@@ -144,9 +148,16 @@ enum AVPixelFormat {
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,6 +239,57 @@ enum AVPixelFormat {
AV_PIX_FMT_YA16BE, ///< 16bit gray, 16bit alpha (big-endian)
AV_PIX_FMT_YA16LE, ///< 16bit gray, 16bit alpha (little-endian)
+
+#ifndef AV_PIX_FMT_ABI_GIT_MASTER
+ AV_PIX_FMT_RGBA64BE=0x123, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
+ AV_PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
+ AV_PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
+ AV_PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
+#endif
+ AV_PIX_FMT_0RGB=0x123+4, ///< packed RGB 8:8:8, 32bpp, 0RGB0RGB...
+ AV_PIX_FMT_RGB0, ///< packed RGB 8:8:8, 32bpp, RGB0RGB0...
+ AV_PIX_FMT_0BGR, ///< packed BGR 8:8:8, 32bpp, 0BGR0BGR...
+ AV_PIX_FMT_BGR0, ///< packed BGR 8:8:8, 32bpp, BGR0BGR0...
+ AV_PIX_FMT_YUVA444P, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
+ AV_PIX_FMT_YUVA422P, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
+
+ AV_PIX_FMT_YUV420P12BE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian
+ AV_PIX_FMT_YUV420P12LE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
+ AV_PIX_FMT_YUV420P14BE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian
+ AV_PIX_FMT_YUV420P14LE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
+ AV_PIX_FMT_YUV422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian
+ AV_PIX_FMT_YUV422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
+ AV_PIX_FMT_YUV422P14BE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian
+ AV_PIX_FMT_YUV422P14LE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
+ AV_PIX_FMT_YUV444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian
+ AV_PIX_FMT_YUV444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
+ AV_PIX_FMT_YUV444P14BE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian
+ AV_PIX_FMT_YUV444P14LE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
+ AV_PIX_FMT_GBRP12BE, ///< planar GBR 4:4:4 36bpp, big-endian
+ AV_PIX_FMT_GBRP12LE, ///< planar GBR 4:4:4 36bpp, little-endian
+ AV_PIX_FMT_GBRP14BE, ///< planar GBR 4:4:4 42bpp, big-endian
+ AV_PIX_FMT_GBRP14LE, ///< planar GBR 4:4:4 42bpp, little-endian
+ AV_PIX_FMT_GBRAP, ///< planar GBRA 4:4:4:4 32bpp
+ AV_PIX_FMT_GBRAP16BE, ///< planar GBRA 4:4:4:4 64bpp, big-endian
+ AV_PIX_FMT_GBRAP16LE, ///< planar GBRA 4:4:4:4 64bpp, little-endian
+ AV_PIX_FMT_YUVJ411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor of PIX_FMT_YUV411P and setting color_range
+
+ AV_PIX_FMT_BAYER_BGGR8, ///< bayer, BGBG..(odd line), GRGR..(even line), 8-bit samples */
+ AV_PIX_FMT_BAYER_RGGB8, ///< bayer, RGRG..(odd line), GBGB..(even line), 8-bit samples */
+ AV_PIX_FMT_BAYER_GBRG8, ///< bayer, GBGB..(odd line), RGRG..(even line), 8-bit samples */
+ AV_PIX_FMT_BAYER_GRBG8, ///< bayer, GRGR..(odd line), BGBG..(even line), 8-bit samples */
+ AV_PIX_FMT_BAYER_BGGR16LE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, little-endian */
+ AV_PIX_FMT_BAYER_BGGR16BE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, big-endian */
+ AV_PIX_FMT_BAYER_RGGB16LE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, little-endian */
+ AV_PIX_FMT_BAYER_RGGB16BE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, big-endian */
+ AV_PIX_FMT_BAYER_GBRG16LE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, little-endian */
+ AV_PIX_FMT_BAYER_GBRG16BE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, big-endian */
+ AV_PIX_FMT_BAYER_GRBG16LE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, little-endian */
+ AV_PIX_FMT_BAYER_GRBG16BE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, big-endian */
+#if !FF_API_XVMC
+ AV_PIX_FMT_XVMC,///< XVideo Motion Acceleration via common packet passing
+#endif /* !FF_API_XVMC */
+
AV_PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
#if FF_API_PIX_FMT
@@ -213,6 +297,19 @@ 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
+#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
@@ -223,6 +320,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)
@@ -243,13 +342,28 @@ enum AVPixelFormat {
#define AV_PIX_FMT_YUV420P10 AV_PIX_FMT_NE(YUV420P10BE, YUV420P10LE)
#define AV_PIX_FMT_YUV422P10 AV_PIX_FMT_NE(YUV422P10BE, YUV422P10LE)
#define AV_PIX_FMT_YUV444P10 AV_PIX_FMT_NE(YUV444P10BE, YUV444P10LE)
+#define AV_PIX_FMT_YUV420P12 AV_PIX_FMT_NE(YUV420P12BE, YUV420P12LE)
+#define AV_PIX_FMT_YUV422P12 AV_PIX_FMT_NE(YUV422P12BE, YUV422P12LE)
+#define AV_PIX_FMT_YUV444P12 AV_PIX_FMT_NE(YUV444P12BE, YUV444P12LE)
+#define AV_PIX_FMT_YUV420P14 AV_PIX_FMT_NE(YUV420P14BE, YUV420P14LE)
+#define AV_PIX_FMT_YUV422P14 AV_PIX_FMT_NE(YUV422P14BE, YUV422P14LE)
+#define AV_PIX_FMT_YUV444P14 AV_PIX_FMT_NE(YUV444P14BE, YUV444P14LE)
#define AV_PIX_FMT_YUV420P16 AV_PIX_FMT_NE(YUV420P16BE, YUV420P16LE)
#define AV_PIX_FMT_YUV422P16 AV_PIX_FMT_NE(YUV422P16BE, YUV422P16LE)
#define AV_PIX_FMT_YUV444P16 AV_PIX_FMT_NE(YUV444P16BE, YUV444P16LE)
#define AV_PIX_FMT_GBRP9 AV_PIX_FMT_NE(GBRP9BE , GBRP9LE)
#define AV_PIX_FMT_GBRP10 AV_PIX_FMT_NE(GBRP10BE, GBRP10LE)
+#define AV_PIX_FMT_GBRP12 AV_PIX_FMT_NE(GBRP12BE, GBRP12LE)
+#define AV_PIX_FMT_GBRP14 AV_PIX_FMT_NE(GBRP14BE, GBRP14LE)
#define AV_PIX_FMT_GBRP16 AV_PIX_FMT_NE(GBRP16BE, GBRP16LE)
+#define AV_PIX_FMT_GBRAP16 AV_PIX_FMT_NE(GBRAP16BE, GBRAP16LE)
+
+#define AV_PIX_FMT_BAYER_BGGR16 AV_PIX_FMT_NE(BAYER_BGGR16BE, BAYER_BGGR16LE)
+#define AV_PIX_FMT_BAYER_RGGB16 AV_PIX_FMT_NE(BAYER_RGGB16BE, BAYER_RGGB16LE)
+#define AV_PIX_FMT_BAYER_GBRG16 AV_PIX_FMT_NE(BAYER_GBRG16BE, BAYER_GBRG16LE)
+#define AV_PIX_FMT_BAYER_GRBG16 AV_PIX_FMT_NE(BAYER_GRBG16BE, BAYER_GRBG16LE)
+
#define AV_PIX_FMT_YUVA420P9 AV_PIX_FMT_NE(YUVA420P9BE , YUVA420P9LE)
#define AV_PIX_FMT_YUVA422P9 AV_PIX_FMT_NE(YUVA422P9BE , YUVA422P9LE)
@@ -268,12 +382,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
@@ -291,12 +410,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
@@ -358,6 +487,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.
diff --git a/libavutil/ppc/cpu.c b/libavutil/ppc/cpu.c
index 50107e1..d51e3fa 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 f8fae58..0a212f3 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 fee4e7c..49af9f9 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 87d50a8..e1d530a 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 60d0f19..9dd2072 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 4471c6a..1ec349e 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
*/
diff --git a/libavutil/ppc/timer.h b/libavutil/ppc/timer.h
index 8d08d28..b28e624 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 0a4eaf8..69d8957 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 5624ac5..2f0c6eb 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
*/
@@ -85,29 +85,56 @@ 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);
}
+#else
+#define unaligned_load(a,b) VEC_LD(a,b)
+#endif
+
/**
* 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);
}
-#define vec_unaligned_load(b) \
- vec_perm(vec_ld(0, b), vec_ld(15, b), vec_lvsl(0, b));
+#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
+
#endif /* HAVE_ALTIVEC */
diff --git a/libavutil/qsort.h b/libavutil/qsort.h
new file mode 100644
index 0000000..30edcc8
--- /dev/null
+++ b/libavutil/qsort.h
@@ -0,0 +1,117 @@
+/*
+ * copyright (c) 2012 Michael Niedermayer <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 26884cb..8aa8c38 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 b1fad13..0462a04 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 4053936..55a8dd5 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
*/
@@ -110,11 +110,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 +146,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 5d7dab7..7439701 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 3bf710f..4e52ba5 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 ec3b47c..9362fd8 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 7871d2c..5c03e19 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 0000000..1ceb24b
--- /dev/null
+++ b/libavutil/ripemd.c
@@ -0,0 +1,515 @@
+/*
+ * 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
+ uint8_t ext; ///< extension (0 for 128 and 160, 1 for 256 and 320)
+ /** function used to update hash for 512-bit input block */
+ void (*transform)(uint32_t *state, const uint8_t buffer[64], int ext);
+} 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 SWAP(a,b) if (ext) { t = a; a = b; b = t; }
+
+#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++
+
+static void ripemd128_transform(uint32_t *state, const uint8_t buffer[64], int ext)
+{
+ uint32_t a, b, c, d, e, f, g, h, t;
+ uint32_t block[16];
+ int n;
+
+ if (ext) {
+ a = state[0]; b = state[1]; c = state[2]; d = state[3];
+ e = state[4]; f = state[5]; g = state[6]; h = state[7];
+ } else {
+ 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;
+ }
+ SWAP(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;
+ }
+ SWAP(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;
+ }
+ SWAP(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;
+ }
+ SWAP(d,h)
+#else
+
+#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)
+
+ R128_0; R128_0; R128_0; R128_0;
+ SWAP(a,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)
+
+ R128_16; R128_16; R128_16; R128_16;
+ SWAP(b,f)
+
+#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)
+
+ R128_32; R128_32; R128_32; R128_32;
+ SWAP(c,g)
+
+#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)
+
+ R128_48; R128_48; R128_48; R128_48;
+ SWAP(d,h)
+#endif
+
+ if (ext) {
+ state[0] += a; state[1] += b; state[2] += c; state[3] += d;
+ state[4] += e; state[5] += f; state[6] += g; state[7] += h;
+ } else {
+ 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;
+ }
+}
+
+#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)
+
+static void ripemd160_transform(uint32_t *state, const uint8_t buffer[64], int ext)
+{
+ uint32_t a, b, c, d, e, f, g, h, i, j, t;
+ uint32_t block[16];
+ int n;
+
+ if (ext) {
+ 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];
+ } else {
+ 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;
+ }
+ SWAP(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;
+ }
+ SWAP(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;
+ }
+ SWAP(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;
+ }
+ SWAP(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;
+ }
+ SWAP(e,j)
+#else
+
+#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)
+
+ R160_0; R160_0; R160_0;
+ ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j);
+ SWAP(a,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)
+
+ R160_16; R160_16; R160_16;
+ ROUND160_16_TO_31(e,a,b,c,d,j,f,g,h,i);
+ SWAP(b,g)
+
+#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)
+
+ R160_32; R160_32; R160_32;
+ ROUND160_32_TO_47(d,e,a,b,c,i,j,f,g,h);
+ SWAP(c,h)
+
+#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)
+
+ R160_48; R160_48; R160_48;
+ ROUND160_48_TO_63(c,d,e,a,b,h,i,j,f,g);
+ SWAP(d,i)
+
+#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)
+
+ R160_64; R160_64; R160_64;
+ ROUND160_64_TO_79(b,c,d,e,a,g,h,i,j,f);
+ SWAP(e,j)
+#endif
+
+ if (ext) {
+ 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;
+ } else {
+ 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;
+ }
+}
+
+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;
+ ctx->ext = 0;
+ 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;
+ ctx->ext = 0;
+ 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 = ripemd128_transform;
+ ctx->ext = 1;
+ 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 = ripemd160_transform;
+ ctx->ext = 1;
+ 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, ctx->ext);
+ j = 0;
+ }
+ }
+#else
+ if ((j + len) > 63) {
+ memcpy(&ctx->buffer[j], data, (i = 64 - j));
+ ctx->transform(ctx->state, ctx->buffer, ctx->ext);
+ for (; i + 63 < len; i += 64)
+ ctx->transform(ctx->state, &data[i], ctx->ext);
+ 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 0000000..7b0c8bc
--- /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 bff6004..c605b5e 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 8347fac..6a8a031 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 1ff1bfd..48dd27f 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 2d9b58c..0cf9424 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)
{
@@ -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 4c9a0c9..bf4377e 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 0000000..66a864f
--- /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 0000000..7b08701
--- /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 0000000..bf9cfda
--- /dev/null
+++ b/libavutil/softfloat.c
@@ -0,0 +1,71 @@
+/*
+ * 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
+
+int main(void){
+ SoftFloat one= av_int2sf(1, 0);
+ SoftFloat sf1, sf2;
+ double d1, d2;
+ 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);
+ return 0;
+}
diff --git a/libavutil/softfloat.h b/libavutil/softfloat.h
new file mode 100644
index 0000000..8647e6a
--- /dev/null
+++ b/libavutil/softfloat.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2006 Michael Niedermayer <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"
+
+#define MIN_EXP -126
+#define MAX_EXP 126
+#define ONE_BITS 29
+
+typedef struct SoftFloat{
+ int32_t exp;
+ int32_t mant;
+}SoftFloat;
+
+static av_const SoftFloat av_normalize_sf(SoftFloat a){
+ if(a.mant){
+#if 1
+ while((a.mant + 0x20000000U)<0x40000000U){
+ a.mant += a.mant;
+ a.exp -= 1;
+ }
+#else
+ int s=ONE_BITS + 1 - av_log2(a.mant ^ (a.mant<<1));
+ a.exp -= s;
+ a.mant <<= s;
+#endif
+ if(a.exp < MIN_EXP){
+ a.exp = MIN_EXP;
+ a.mant= 0;
+ }
+ }else{
+ a.exp= MIN_EXP;
+ }
+ return a;
+}
+
+static inline av_const SoftFloat av_normalize1_sf(SoftFloat a){
+#if 1
+ if((int32_t)(a.mant + 0x40000000U) < 0){
+ a.exp++;
+ a.mant>>=1;
+ }
+ av_assert2(a.mant < 0x40000000 && a.mant > -0x40000000);
+ return a;
+#elif 1
+ int t= a.mant + 0x40000000 < 0;
+ return (SoftFloat){a.exp+t, a.mant>>t};
+#else
+ int t= (a.mant + 0x40000000U)>>31;
+ return (SoftFloat){a.exp+t, a.mant>>t};
+#endif
+}
+
+/**
+ * @return Will not be more denormalized than a+b. So if either input is
+ * normalized, then the output will not be worse then the other input.
+ * If both are normalized, then the output will be normalized.
+ */
+static inline av_const SoftFloat av_mul_sf(SoftFloat a, SoftFloat b){
+ a.exp += b.exp;
+ av_assert2((int32_t)((a.mant * (int64_t)b.mant) >> ONE_BITS) == (a.mant * (int64_t)b.mant) >> ONE_BITS);
+ a.mant = (a.mant * (int64_t)b.mant) >> ONE_BITS;
+ return av_normalize1_sf(a);
+}
+
+/**
+ * b has to be normalized and not zero.
+ * @return Will not be more denormalized than a.
+ */
+static av_const SoftFloat av_div_sf(SoftFloat a, SoftFloat b){
+ a.exp -= b.exp+1;
+ a.mant = ((int64_t)a.mant<<(ONE_BITS+1)) / b.mant;
+ return av_normalize1_sf(a);
+}
+
+static inline av_const int av_cmp_sf(SoftFloat a, SoftFloat b){
+ int t= a.exp - b.exp;
+ if(t<0) return (a.mant >> (-t)) - b.mant ;
+ else return a.mant - (b.mant >> t);
+}
+
+static inline av_const SoftFloat av_add_sf(SoftFloat a, SoftFloat b){
+ int t= a.exp - b.exp;
+ if (t <-31) return b;
+ else if (t < 0) return av_normalize1_sf((SoftFloat){b.exp, b.mant + (a.mant >> (-t))});
+ else if (t < 32) return av_normalize1_sf((SoftFloat){a.exp, a.mant + (b.mant >> t )});
+ else return a;
+}
+
+static inline av_const SoftFloat av_sub_sf(SoftFloat a, SoftFloat b){
+ return av_add_sf(a, (SoftFloat){b.exp, -b.mant});
+}
+
+//FIXME sqrt, log, exp, pow, sin, cos
+
+static inline av_const SoftFloat av_int2sf(int v, int frac_bits){
+ return av_normalize_sf((SoftFloat){ONE_BITS-frac_bits, v});
+}
+
+/**
+ * Rounding is to -inf.
+ */
+static inline av_const int av_sf2int(SoftFloat v, int frac_bits){
+ v.exp += frac_bits - ONE_BITS;
+ if(v.exp >= 0) return v.mant << v.exp ;
+ else return v.mant >>(-v.exp);
+}
+
+#endif /* AVUTIL_SOFTFLOAT_H */
diff --git a/libavutil/stereo3d.c b/libavutil/stereo3d.c
index 2dcfddf..50cd928 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 b1910b1..1135dc9 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/threadmessage.c b/libavutil/threadmessage.c
new file mode 100644
index 0000000..b7fcbe2
--- /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 0000000..a8481d8
--- /dev/null
+++ b/libavutil/threadmessage.h
@@ -0,0 +1,91 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_THREADMESSAGE_H
+#define AVUTIL_THREADMESSAGE_H
+
+typedef struct AVThreadMessageQueue AVThreadMessageQueue;
+
+typedef enum AVThreadMessageFlags {
+
+ /**
+ * Perform non-blocking operation.
+ * If this flag is set, send and recv operations are non-blocking and
+ * return AVERROR(EAGAIN) immediately if they can not proceed.
+ */
+ AV_THREAD_MESSAGE_NONBLOCK = 1,
+
+} AVThreadMessageFlags;
+
+/**
+ * Allocate a new message queue.
+ *
+ * @param mq pointer to the message queue
+ * @param nelem maximum number of elements in the queue
+ * @param elsize size of each element in the queue
+ * @return >=0 for success; <0 for error, in particular AVERROR(ENOSYS) if
+ * lavu was built without thread support
+ */
+int av_thread_message_queue_alloc(AVThreadMessageQueue **mq,
+ unsigned nelem,
+ unsigned elsize);
+
+/**
+ * Free a message queue.
+ *
+ * The message queue must no longer be in use by another thread.
+ */
+void av_thread_message_queue_free(AVThreadMessageQueue **mq);
+
+/**
+ * Send a message on the queue.
+ */
+int av_thread_message_queue_send(AVThreadMessageQueue *mq,
+ void *msg,
+ unsigned flags);
+
+/**
+ * Receive a message from the queue.
+ */
+int av_thread_message_queue_recv(AVThreadMessageQueue *mq,
+ void *msg,
+ unsigned flags);
+
+/**
+ * Set the sending error code.
+ *
+ * If the error code is set to non-zero, av_thread_message_queue_recv() will
+ * return it immediately when there are no longer available messages.
+ * Conventional values, such as AVERROR_EOF or AVERROR(EAGAIN), can be used
+ * to cause the receiving thread to stop or suspend its operation.
+ */
+void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq,
+ int err);
+
+/**
+ * Set the receiving error code.
+ *
+ * If the error code is set to non-zero, av_thread_message_queue_send() will
+ * return it immediately. Conventional values, such as AVERROR_EOF or
+ * AVERROR(EAGAIN), can be used to cause the sending thread to stop or
+ * suspend its operation.
+ */
+void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq,
+ int err);
+
+#endif /* AVUTIL_THREADMESSAGE_H */
diff --git a/libavutil/time.c b/libavutil/time.c
index 7a3604e..dbaee02 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 463bcfc..dc169b0 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 829fefb..612a75a 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 0000000..1dfd040
--- /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 0000000..56e3975
--- /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 0d93d7c..13a3c8c 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; \
@@ -76,7 +78,7 @@
tskip_count++; \
if (((tcount + tskip_count) & (tcount + tskip_count - 1)) == 0) { \
av_log(NULL, AV_LOG_ERROR, \
- "%"PRIu64" UNITS in %s, %d runs, %d skips\n", \
+ "%"PRIu64" " FF_TIMER_UNITS " in %s, %d runs, %d skips\n", \
tsum * 10 / tcount, id, tcount, tskip_count); \
} \
}
diff --git a/libavutil/timestamp.h b/libavutil/timestamp.h
new file mode 100644
index 0000000..f010a7e
--- /dev/null
+++ b/libavutil/timestamp.h
@@ -0,0 +1,78 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * timestamp utils, mostly useful for debugging/logging purposes
+ */
+
+#ifndef AVUTIL_TIMESTAMP_H
+#define AVUTIL_TIMESTAMP_H
+
+#include "common.h"
+
+#if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS) && !defined(PRId64)
+#error missing -D__STDC_FORMAT_MACROS / #define __STDC_FORMAT_MACROS
+#endif
+
+#define AV_TS_MAX_STRING_SIZE 32
+
+/**
+ * Fill the provided buffer with a string containing a timestamp
+ * representation.
+ *
+ * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE
+ * @param ts the timestamp to represent
+ * @return the buffer in input
+ */
+static inline char *av_ts_make_string(char *buf, int64_t ts)
+{
+ if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS");
+ else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%"PRId64, ts);
+ return buf;
+}
+
+/**
+ * Convenience macro, the return value should be used only directly in
+ * function arguments but never stand-alone.
+ */
+#define av_ts2str(ts) av_ts_make_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts)
+
+/**
+ * Fill the provided buffer with a string containing a timestamp time
+ * representation.
+ *
+ * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE
+ * @param ts the timestamp to represent
+ * @param tb the timebase of the timestamp
+ * @return the buffer in input
+ */
+static inline char *av_ts_make_time_string(char *buf, int64_t ts, AVRational *tb)
+{
+ if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS");
+ else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%.6g", av_q2d(*tb) * ts);
+ return buf;
+}
+
+/**
+ * Convenience macro, the return value should be used only directly in
+ * function arguments but never stand-alone.
+ */
+#define av_ts2timestr(ts, tb) av_ts_make_time_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts, tb)
+
+#endif /* AVUTIL_TIMESTAMP_H */
diff --git a/libavutil/tomi/intreadwrite.h b/libavutil/tomi/intreadwrite.h
index baf592a..7dec415 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 d48d01a..d0b67ef 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 424656e..a14fa91 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/utf8.c b/libavutil/utf8.c
new file mode 100644
index 0000000..3447a51
--- /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 c8c161d..aafd3b9 100644
--- a/libavutil/utils.c
+++ b/libavutil/utils.c
@@ -1,23 +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
*/
#include "config.h"
#include "avutil.h"
+#include "avassert.h"
+#include "samplefmt.h"
+#include "pixdesc.h"
/**
* @file
@@ -26,18 +29,56 @@
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");
+ }
+
+#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 0
+ ff_check_pixfmt_descriptors();
+#endif
+ 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 b40009e..a682c80 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.
@@ -53,9 +55,9 @@
* @{
*/
-#define LIBAVUTIL_VERSION_MAJOR 54
-#define LIBAVUTIL_VERSION_MINOR 5
-#define LIBAVUTIL_VERSION_MICRO 0
+#define LIBAVUTIL_VERSION_MAJOR 54
+#define LIBAVUTIL_VERSION_MINOR 11
+#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
@@ -113,8 +121,17 @@
#endif
+#ifndef FF_CONST_AVUTIL53
+#if LIBAVUTIL_VERSION_MAJOR >= 53
+#define FF_CONST_AVUTIL53 const
+#else
+#define FF_CONST_AVUTIL53
+#endif
+#endif
+
/**
* @}
*/
#endif /* AVUTIL_VERSION_H */
+
diff --git a/libavutil/x86/Makefile b/libavutil/x86/Makefile
index 1e19082..ad3bdfc 100644
--- a/libavutil/x86/Makefile
+++ b/libavutil/x86/Makefile
@@ -2,7 +2,11 @@ OBJS += x86/cpu.o \
x86/float_dsp_init.o \
x86/lls_init.o \
+OBJS-$(CONFIG_PIXELUTILS) += x86/pixelutils_init.o \
+
YASM-OBJS += x86/cpuid.o \
x86/emms.o \
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 e30f5db..616ad6c 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 c73be9a..08e2a62 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 8be6d94..2b62e92 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 50da30e..bc64b1b 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 1cb8e94..c3f7866 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 a6851ac..0aad34a 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 2ed9e5d..a529b6b 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 d962499..ec3d22b 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 a04d91c..64b3a4d 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/intreadwrite.h b/libavutil/x86/intreadwrite.h
index 635096e..4061d19 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 eab85ed..769befb 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 888bc54..f531904 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 0000000..7522f24
--- /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 0000000..876cf46
--- /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 0000000..d600510
--- /dev/null
+++ b/libavutil/x86/pixelutils_init.c
@@ -0,0 +1,58 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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;
+ }
+
+ 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 cdd67dd..5b24b51 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 b4ce7d3..9df499f 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 e3ed381..8a13064 100644
--- a/libavutil/x86/x86inc.asm
+++ b/libavutil/x86/x86inc.asm
@@ -856,6 +856,14 @@ SECTION .note.GNU-stack noalloc noexec nowrite progbits
INIT_CPUFLAGS %1
%endmacro
+; FIXME: INIT_AVX can be replaced by INIT_XMM avx
+%macro INIT_AVX 0
+ INIT_XMM
+ %assign avx_enabled 1
+ %define PALIGNR PALIGNR_SSSE3
+ %define RESET_MM_PERMUTATION INIT_AVX
+%endmacro
+
%macro INIT_YMM 0-1+
%assign avx_enabled 1
%define RESET_MM_PERMUTATION INIT_YMM %1
@@ -1402,21 +1410,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 11779cf..0d0ef07 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
@@ -273,6 +282,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 +349,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 +607,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)
@@ -666,6 +723,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)
@@ -678,3 +754,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 0000000..bec1c77
--- /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 0000000..3aed314
--- /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 0000000..5e40f54
--- /dev/null
+++ b/libavutil/xga_font_data.h
@@ -0,0 +1,35 @@
+/*
+ * CGA/EGA/VGA ROM font data
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * CGA/EGA/VGA ROM font data
+ */
+
+#ifndef AVUTIL_XGA_FONT_DATA_H
+#define AVUTIL_XGA_FONT_DATA_H
+
+#include <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 53c0bfe..1750cbc 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 0fc3810..6f1e71e 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 0000000..b9bb4be
--- /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 0000000..e65d76f
--- /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 0000000..f8fb356
--- /dev/null
+++ b/libpostproc/postprocess.c
@@ -0,0 +1,1067 @@
+/*
+ * 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"
+
+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
+};
+
+
+#if ARCH_X86 && HAVE_INLINE_ASM
+static inline void prefetchnta(const void *p)
+{
+ __asm__ volatile( "prefetchnta (%0)\n\t"
+ : : "r" (p)
+ );
+}
+
+static inline void prefetcht0(const void *p)
+{
+ __asm__ volatile( "prefetcht0 (%0)\n\t"
+ : : "r" (p)
+ );
+}
+
+static inline void prefetcht1(const void *p)
+{
+ __asm__ volatile( "prefetcht1 (%0)\n\t"
+ : : "r" (p)
+ );
+}
+
+static inline void prefetcht2(const void *p)
+{
+ __asm__ volatile( "prefetcht2 (%0)\n\t"
+ : : "r" (p)
+ );
+}
+#endif
+
+/* 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));
+
+ 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)){
+ int 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 };
+
+pp_context *pp_get_context(int width, int height, int cpuCaps){
+ PPContext *c= av_malloc(sizeof(PPContext));
+ int stride= FFALIGN(width, 16); //assumed / will realloc if needed
+ int qpStride= (width+15)/16 + 2; //assumed / will realloc if needed
+
+ memset(c, 0, sizeof(PPContext));
+ 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;
+}
+
+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 0000000..e00ed96
--- /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 0000000..fa6ebe2
--- /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 0000000..1ebd974
--- /dev/null
+++ b/libpostproc/postprocess_internal.h
@@ -0,0 +1,178 @@
+/*
+ * 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(8, uint64_t, mmxDcOffset)[64];
+ DECLARE_ALIGNED(8, 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;
+
+ 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 0000000..6722f96
--- /dev/null
+++ b/libpostproc/postprocess_template.c
@@ -0,0 +1,3727 @@
+/*
+ * 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
+}
+
+/**
+ * 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){
+
+#if TEMPLATE_PP_MMXEXT && HAVE_6REGS
+/*
+ prefetchnta(srcBlock + (((x>>2)&6) + 5)*srcStride + 32);
+ prefetchnta(srcBlock + (((x>>2)&6) + 6)*srcStride + 32);
+ prefetcht0(dstBlock + (((x>>2)&6) + 5)*dstStride + 32);
+ prefetcht0(dstBlock + (((x>>2)&6) + 6)*dstStride + 32);
+*/
+
+ __asm__(
+ "mov %4, %%"REG_a" \n\t"
+ "shr $2, %%"REG_a" \n\t"
+ "and $6, %%"REG_a" \n\t"
+ "add %5, %%"REG_a" \n\t"
+ "mov %%"REG_a", %%"REG_d" \n\t"
+ "imul %1, %%"REG_a" \n\t"
+ "imul %3, %%"REG_d" \n\t"
+ "prefetchnta 32(%%"REG_a", %0) \n\t"
+ "prefetcht0 32(%%"REG_d", %2) \n\t"
+ "add %1, %%"REG_a" \n\t"
+ "add %3, %%"REG_d" \n\t"
+ "prefetchnta 32(%%"REG_a", %0) \n\t"
+ "prefetcht0 32(%%"REG_d", %2) \n\t"
+ :: "r" (srcBlock), "r" ((x86_reg)srcStride), "r" (dstBlock), "r" ((x86_reg)dstStride),
+ "g" ((x86_reg)x), "g" ((x86_reg)copyAhead)
+ : "%"REG_a, "%"REG_d
+ );
+
+#elif TEMPLATE_PP_3DNOW
+//FIXME check if this is faster on an 3dnow chip or if it is faster without the prefetch or ...
+/* prefetch(srcBlock + (((x>>3)&3) + 5)*srcStride + 32);
+ prefetch(srcBlock + (((x>>3)&3) + 9)*srcStride + 32);
+ prefetchw(dstBlock + (((x>>3)&3) + 5)*dstStride + 32);
+ prefetchw(dstBlock + (((x>>3)&3) + 9)*dstStride + 32);
+*/
+#endif
+
+ 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;
+ /* 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; x+=BLOCK_SIZE){
+ const int stride= dstStride;
+#if TEMPLATE_PP_MMX
+ uint8_t *tmpXchg;
+#endif
+ if(isColor){
+ QP= QPptr[x>>qpHShift];
+ c.nonBQP= nonBQPptr[x>>qpHShift];
+ }else{
+ QP= QPptr[x>>4];
+ QP= (QP* QPCorrecture + 256*128)>>16;
+ c.nonBQP= nonBQPptr[x>>4];
+ c.nonBQP= (c.nonBQP* QPCorrecture + 256*128)>>16;
+ yHistogram[ srcBlock[srcStride*12 + 4] ]++;
+ }
+ c.QP= QP;
+#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)
+ : "r" (QP)
+ );
+#endif
+
+
+#if TEMPLATE_PP_MMXEXT && HAVE_6REGS
+/*
+ prefetchnta(srcBlock + (((x>>2)&6) + 5)*srcStride + 32);
+ prefetchnta(srcBlock + (((x>>2)&6) + 6)*srcStride + 32);
+ prefetcht0(dstBlock + (((x>>2)&6) + 5)*dstStride + 32);
+ prefetcht0(dstBlock + (((x>>2)&6) + 6)*dstStride + 32);
+*/
+
+ __asm__(
+ "mov %4, %%"REG_a" \n\t"
+ "shr $2, %%"REG_a" \n\t"
+ "and $6, %%"REG_a" \n\t"
+ "add %5, %%"REG_a" \n\t"
+ "mov %%"REG_a", %%"REG_d" \n\t"
+ "imul %1, %%"REG_a" \n\t"
+ "imul %3, %%"REG_d" \n\t"
+ "prefetchnta 32(%%"REG_a", %0) \n\t"
+ "prefetcht0 32(%%"REG_d", %2) \n\t"
+ "add %1, %%"REG_a" \n\t"
+ "add %3, %%"REG_d" \n\t"
+ "prefetchnta 32(%%"REG_a", %0) \n\t"
+ "prefetcht0 32(%%"REG_d", %2) \n\t"
+ :: "r" (srcBlock), "r" ((x86_reg)srcStride), "r" (dstBlock), "r" ((x86_reg)dstStride),
+ "g" ((x86_reg)x), "g" ((x86_reg)copyAhead)
+ : "%"REG_a, "%"REG_d
+ );
+
+#elif TEMPLATE_PP_3DNOW
+//FIXME check if this is faster on an 3dnow chip or if it is faster without the prefetch or ...
+/* prefetch(srcBlock + (((x>>3)&3) + 5)*srcStride + 32);
+ prefetch(srcBlock + (((x>>3)&3) + 9)*srcStride + 32);
+ prefetchw(dstBlock + (((x>>3)&3) + 5)*dstStride + 32);
+ prefetchw(dstBlock + (((x>>3)&3) + 9)*dstStride + 32);
+*/
+#endif
+
+ 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);
+*/
+
+ /* 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);
+ }
+ }
+
+#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){
+//START_TIMER
+ const int t= RENAME(vertClassify)(tempBlock1, 16, &c);
+//STOP_TIMER("dc & minmax")
+ 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, 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);
+ }
+ }
+ }
+/*
+ for(x=0; x<width; x+=32){
+ volatile int i;
+ i+= dstBlock[x + 7*dstStride] + dstBlock[x + 8*dstStride]
+ + dstBlock[x + 9*dstStride] + dstBlock[x +10*dstStride]
+ + dstBlock[x +11*dstStride] + dstBlock[x +12*dstStride];
+ + dstBlock[x +13*dstStride]
+ + dstBlock[x +14*dstStride] + dstBlock[x +15*dstStride];
+ }*/
+ }
+#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 0000000..e6104ac
--- /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 0000000..59c2466
--- /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 3da14b6..72e5574 100644
--- a/library.mak
+++ b/library.mak
@@ -25,10 +25,10 @@ $(SUBDIR)%-test.i: $(SUBDIR)%.c
$(SUBDIR)x86/%.o: $(SUBDIR)x86/%.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 +51,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 +70,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 +85,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 +93,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 0000000..120ee33
--- /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 0000000..320ed67
--- /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 0000000..60e24ad
--- /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 0000000..74feff4
--- /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 0000000..85c71bf
--- /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 0000000..60f3f6d
--- /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 0000000..ec9e62e
--- /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 0000000..1f88316
--- /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 0000000..2abbbc2
--- /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 0000000..58b0bf3
--- /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 0000000..2e983df
--- /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 0000000..b8b592a
--- /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);
+}
+
+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/(1L<<31);
+ if(out_fmt == AV_SAMPLE_FMT_S16) scale = 1.0/(1L<<15);
+ if(out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1.0/(1L<< 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 = 1L<<16;
+ if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<24;
+ if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<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 0000000..4af7312
--- /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)
+
+#elif defined(TEMPLATE_DITHER_FLT)
+# define RENAME(N) N ## _float
+# define DELEM float
+# define CLIP(v)
+
+#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 0000000..0d5efe4
--- /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 0000000..47a1df0
--- /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 0000000..77e0f2e
--- /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 0000000..01cdb1e
--- /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( in.ch_count ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_CH_MAX, PARAM},
+{"in_channel_count" , "set input channel count" , OFFSET( in.ch_count ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_CH_MAX, PARAM},
+{"och" , "set output channel count" , OFFSET(out.ch_count ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_CH_MAX, PARAM},
+{"out_channel_count" , "set output channel count" , OFFSET(out.ch_count ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_CH_MAX, PARAM},
+{"uch" , "set used channel count" , OFFSET(used_ch_count ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_CH_MAX, PARAM},
+{"used_channel_count" , "set used channel count" , OFFSET(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( in_ch_layout ), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"},
+{"in_channel_layout" , "set input channel layout" , OFFSET( in_ch_layout ), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"},
+{"ocl" , "set output channel layout" , OFFSET(out_ch_layout ), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"},
+{"out_channel_layout" , "set output channel layout" , OFFSET(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 0000000..6552a2f
--- /dev/null
+++ b/libswresample/rematrix.c
@@ -0,0 +1,509 @@
+/*
+ * 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->in_ch_layout);
+ nb_out = av_get_channel_layout_nb_channels(s->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) 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 0000000..95a3b9a
--- /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 0000000..d0f6e20
--- /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 <<= 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 0000000..99a89b7
--- /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 0000000..a811b8b
--- /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 0000000..069b19c
--- /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 = (uint64_t)(v + 0x80000000) > 0xFFFFFFFF ? (v>>63) ^ 0x7FFFFFFF : 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 = (unsigned)(v + 32768) > 65535 ? (v>>31) ^ 32767 : 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 0000000..064451d
--- /dev/null
+++ b/libswresample/soxr_resample.c
@@ -0,0 +1,100 @@
+/*
+ * 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));
+ error = soxr_process((soxr_t)c, src->ch, (size_t)src_size,
+ &idone, dst->ch, (size_t)dst_size, &odone);
+ *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 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 0000000..c0162cd
--- /dev/null
+++ b/libswresample/swresample-test.c
@@ -0,0 +1,416 @@
+/*
+ * 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(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 0000000..b0bd697
--- /dev/null
+++ b/libswresample/swresample.c
@@ -0,0 +1,853 @@
+/*
+ * 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 <float.h>
+
+#define ALIGN 32
+
+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-> in_ch_layout), 0) < 0)
+ goto fail;
+
+ if (av_opt_set_int(s, "och", av_get_channel_layout_nb_channels(s->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;
+
+ 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);
+ }
+
+ 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
+ extern struct Resampler const soxr_resampler;
+ case SWR_ENGINE_SOXR: s->resampler = &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;
+ }
+
+ if ((!s->out_ch_layout || !s->in_ch_layout) && s->used_ch_count != s->out.ch_count && !s->rematrix_custom) {
+ char l1[1024], l2[1024];
+ 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);
+ 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(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 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 0000000..37656a6
--- /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 0000000..71d3ed7
--- /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 0000000..3761843
--- /dev/null
+++ b/libswresample/swresample_internal.h
@@ -0,0 +1,203 @@
+/*
+ * 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 {
+ enum SwrDitherType 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
+};
+
+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
+ enum AVMatrixEncoding 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)
+ enum SwrEngine engine;
+
+ 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 */
+ enum SwrFilterType 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 */
+};
+
+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;
+
+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);
+void 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 0000000..1320f78
--- /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 0000000..61c76fa
--- /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 0000000..be44df5
--- /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 0000000..57d3a89
--- /dev/null
+++ b/libswresample/x86/audio_convert.asm
@@ -0,0 +1,482 @@
+;******************************************************************************
+;* 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 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
+.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]
+ %7 x,x,x,x,m7,x
+%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 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
+
+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
+
+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
+
+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
+
+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 0000000..90bed51
--- /dev/null
+++ b/libswresample/x86/audio_convert_init.c
@@ -0,0 +1,146 @@
+/*
+ * 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(_unpack_2ch_)
+
+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(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(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(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 0000000..f0ae959
--- /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 0000000..e2ee291
--- /dev/null
+++ b/libswresample/x86/rematrix_init.c
@@ -0,0 +1,83 @@
+/*
+ * 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 void 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(2 * num * sizeof(int16_t));
+ s->native_simd_one = av_mallocz(2 * sizeof(int16_t));
+ 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(num * sizeof(float));
+ memcpy(s->native_simd_matrix, s->native_matrix, num * sizeof(float));
+ s->native_simd_one = av_mallocz(sizeof(float));
+ memcpy(s->native_simd_one, s->native_one, sizeof(float));
+ }
+#endif
+}
diff --git a/libswresample/x86/resample.asm b/libswresample/x86/resample.asm
new file mode 100644
index 0000000..a57ff37
--- /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 0000000..99f5e14
--- /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);
+
+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 0000000..9cddb4a
--- /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 3e8614d..a60b057 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 0000000..8b5a97b
--- /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 0000000..601bc9a
--- /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 0000000..f51a5f1
--- /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 0000000..30bcecd
--- /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 0000000..04be762
--- /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 0000000..67ab2ae
--- /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 fbf595d..42a915b 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 0000000..82d6177
--- /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 f583b3f..6716f0d 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,127 @@ 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++)
- dst[i] = src[4 * 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 rgbaToA_c(uint8_t *dst, const uint8_t *src, int width,
- uint32_t *unused)
+static void rgba64ToA_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];
}
-static void palToY_c(uint8_t *dst, const uint8_t *src, int width, uint32_t *pal)
+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 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 +520,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 +528,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 +539,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 +552,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 +565,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 +573,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 +581,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 +589,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 +599,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 +607,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 +615,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 +629,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,218 +644,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_uv(uint8_t *dstU, uint8_t *dstV, 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] << 6;
+}
+
+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)
{
@@ -745,6 +886,13 @@ 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;
break;
@@ -754,9 +902,17 @@ 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;
break;
+ case AV_PIX_FMT_GBRAP:
case AV_PIX_FMT_GBRP:
c->readChrPlanar = planar_rgb_to_uv;
break;
@@ -767,14 +923,21 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_YUV422P10LE:
case AV_PIX_FMT_YUV444P10LE:
case AV_PIX_FMT_YUV420P10LE:
+ case AV_PIX_FMT_YUV422P12LE:
+ 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:
@@ -788,14 +951,21 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_YUV444P10BE:
case AV_PIX_FMT_YUV422P10BE:
case AV_PIX_FMT_YUV420P10BE:
+ 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:
@@ -806,6 +976,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;
@@ -839,6 +1021,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;
@@ -875,6 +1061,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;
@@ -953,6 +1151,13 @@ 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;
break;
@@ -962,9 +1167,18 @@ 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;
break;
+ case AV_PIX_FMT_GBRAP:
+ c->readAlpPlanar = planar_rgb_to_a;
case AV_PIX_FMT_GBRP:
c->readLumPlanar = planar_rgb_to_y;
break;
@@ -975,9 +1189,16 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_YUV444P10LE:
case AV_PIX_FMT_YUV422P10LE:
case AV_PIX_FMT_YUV420P10LE:
+ case AV_PIX_FMT_YUV444P12LE:
+ 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;
@@ -1000,9 +1221,16 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_YUV444P10BE:
case AV_PIX_FMT_YUV422P10BE:
case AV_PIX_FMT_YUV420P10BE:
+ 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_GRAY16BE:
c->lumToYV12 = bswap16Y_c;
break;
@@ -1114,9 +1342,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_BGRA64BE:
+ case AV_PIX_FMT_RGBA64LE:
+ case AV_PIX_FMT_RGBA64BE: c->alpToYV12 = rgba64ToA_c; break;
case AV_PIX_FMT_BGRA:
case AV_PIX_FMT_RGBA:
c->alpToYV12 = rgbaToA_c;
@@ -1128,6 +1375,9 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_YA8:
c->alpToYV12 = uyvyToY_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 0000000..47a1df0
--- /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 e7765d6..4d49c3e 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,28 @@ 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" },
+
{ 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 125d998..eee6b48 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(r, 0, 7);
+ g = av_clip(g, 0, 7);
+ b = av_clip(b, 0, 3);
+ } 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(r, 0, 1);
+ g = av_clip(g, 0, 3);
+ b = av_clip(b, 0, 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(r, 0, 7);
+ g = av_clip(g, 0, 7);
+ b = av_clip(b, 0, 3);
+ } 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(r, 0, 1);
+ g = av_clip(g, 0, 3);
+ b = av_clip(b, 0, 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)) << 2;
+ int V = (vbuf0[i] - (128<<7)) << 2;
+
+ 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,
@@ -1277,16 +1780,17 @@ yuv2gbrp_full_X_c(SwsContext *c, const int16_t *lumFilter,
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->dstFormat);
int i;
- int hasAlpha = 0;
+ 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];
@@ -1329,10 +1833,14 @@ yuv2gbrp_full_X_c(SwsContext *c, const int16_t *lumFilter,
dest16[0][i] = G >> SH;
dest16[1][i] = B >> SH;
dest16[2][i] = R >> SH;
+ if (hasAlpha)
+ dest16[3][i] = A;
} else {
dest[0][i] = G >> 22;
dest[1][i] = B >> 22;
dest[2][i] = R >> 22;
+ if (hasAlpha)
+ dest[3][i] = A;
}
}
if (SH != 22 && (!isBE(c->dstFormat)) != (!HAVE_BIGENDIAN)) {
@@ -1340,6 +1848,8 @@ yuv2gbrp_full_X_c(SwsContext *c, const int16_t *lumFilter,
dest16[0][i] = av_bswap16(dest16[0][i]);
dest16[1][i] = av_bswap16(dest16[1][i]);
dest16[2][i] = av_bswap16(dest16[2][i]);
+ if (hasAlpha)
+ dest16[3][i] = av_bswap16(dest16[3][i]);
}
}
}
@@ -1363,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;
@@ -1379,77 +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 7e00488..a1548a7 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,22 +29,62 @@
#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;\
+ }
+#define GET_VF(a, b, c,d) {\
+ a = vec_mergeh(c, d);\
+ b = vec_mergel(c, d);\
+ }
+#else
+#define GET_LS(a,b,c,s) {\
+ ls = a;\
+ a = vec_vsx_ld(((b) << 1) + 16, s);\
+ }
+#define GET_VF(a, b, c, d) {\
+ a = vec_mergel(d, c);\
+ b = vec_mergeh(d, c);\
+ }
+#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;\
+ GET_VF(vf1, vf2, 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)
@@ -66,14 +106,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 +124,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,6 +158,58 @@ 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)
@@ -140,57 +232,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 +269,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 +341,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 74b0f18..25282bf 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 2c5e7ed..aa52a47 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 08545b3..2b1c5dd 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 3fb3921..5b1fcf7 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 f47b04e..5df5dea 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 693c7f2..f9a98a8 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 8063519..661ff5b 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 7756e1b..16a31ce 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,6 +45,7 @@ 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] = {
@@ -61,28 +63,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 +74,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 +99,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 +209,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 +219,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,16 +232,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, NULL);
src = formatConvBuffer;
}
@@ -282,21 +259,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],
@@ -309,14 +271,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;
}
@@ -356,8 +318,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;
@@ -381,8 +341,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;
@@ -394,6 +354,10 @@ static int swscale(SwsContext *c, const uint8_t *src[],
int lastInLumBuf = c->lastInLumBuf;
int lastInChrBuf = c->lastInChrBuf;
+ if (!usePal(c->srcFormat)) {
+ pal = c->input_rgb2yuv_table;
+ }
+
if (isPacked(c->srcFormat)) {
src[0] =
src[1] =
@@ -417,8 +381,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,
@@ -428,6 +392,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. */
@@ -452,6 +429,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]);
@@ -470,8 +448,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",
@@ -481,7 +459,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;
@@ -499,9 +477,9 @@ 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);
hyscale(c, lumPixBuf[lumBufIndex], dstW, src1, srcW, lumXInc,
hLumFilter, hLumFilterPos, hLumFilterSize,
formatConvBuffer, pal, 0);
@@ -521,9 +499,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)
@@ -556,103 +534,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];
@@ -678,6 +634,7 @@ 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,
@@ -686,18 +643,15 @@ static int swscale(SwsContext *c, const uint8_t *src[],
}
}
}
-
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);
}
@@ -718,6 +672,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;
@@ -728,40 +707,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))
@@ -779,3 +741,361 @@ SwsFunc ff_getSwsFunc(SwsContext *c)
return swscale;
}
+
+static void reset_ptr(const uint8_t *src[], int 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(r, 0, 4095);
+ g = av_clip(g, 0, 4095);
+ b = av_clip(b, 0, 4095);
+
+ // 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(x, 0, 4095);
+ y = av_clip(y, 0, 4095);
+ z = av_clip(z, 0, 4095);
+
+ // 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->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 8abbac4..903e120 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 a0daa07..63b4eca 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 128
+
+#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,14 @@ 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[2];
+ int cascaded_tmpStride[4];
+ uint8_t *cascaded_tmp[4];
+
uint32_t pal_yuv[256];
uint32_t pal_rgb[256];
@@ -351,10 +376,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 +402,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 +429,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 +467,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 +485,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,24 +507,25 @@ 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);
/**
* Functions to read planar input, such as planar RGB, and convert
- * internally to Y/UV.
+ * 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);
+ int width, int32_t *rgb2yuv);
+ void (*readAlpPlanar)(uint8_t *dst, const uint8_t *src[4], int width, int32_t *rgb2yuv);
/** @} */
/**
@@ -539,6 +601,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)
@@ -552,11 +616,11 @@ void ff_yuv2rgb_init_tables_ppc(SwsContext *c, const int inv_table[4],
void 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);
@@ -568,9 +632,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);
@@ -601,8 +667,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 || \
@@ -613,8 +679,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 || \
@@ -631,10 +698,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 || \
@@ -651,19 +719,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);
@@ -672,6 +794,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);
@@ -698,18 +821,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];
@@ -721,6 +845,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
@@ -740,4 +865,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 ffc813e..da457df 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)
@@ -488,6 +878,22 @@ static int planarRgbToRgbWrapper(SwsContext *c, const uint8_t *src[],
return srcSliceH;
}
+static int planarRgbToplanarRgbWrapper(SwsContext *c, const uint8_t *src[],
+ int srcStride[], int srcSliceY, int srcSliceH,
+ uint8_t *dst[], int dstStride[])
+{
+ copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW,
+ dst[0], dstStride[0]);
+ copyPlane(src[1], srcStride[1], srcSliceY, srcSliceH, c->srcW,
+ dst[1], dstStride[1]);
+ copyPlane(src[2], srcStride[2], srcSliceY, srcSliceH, c->srcW,
+ dst[2], dstStride[2]);
+ if (dst[3])
+ fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
+
+ return srcSliceH;
+}
+
static void packedtogbr24p(const uint8_t *src, int srcStride,
uint8_t *dst[], int dstStride[], int srcSliceH,
int alpha_first, int inc_size, int width)
@@ -562,6 +968,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 \
@@ -569,6 +1129,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)
@@ -578,17 +1152,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)) {
@@ -604,6 +1172,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)) ||
@@ -645,6 +1239,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;
}
@@ -656,34 +1253,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];
}
@@ -696,13 +1311,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;
@@ -741,7 +1357,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);
@@ -752,25 +1368,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[],
@@ -781,174 +1397,129 @@ 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);
if (!dst[plane])
continue;
// 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) \
- 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) \
- 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)) {
@@ -1010,11 +1581,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;
@@ -1031,6 +1602,10 @@ void ff_get_unscaled_swscale(SwsContext *c)
&& (!needsDither || (c->flags&(SWS_FAST_BILINEAR|SWS_POINT))))
c->swscale = rgbToRgbWrapper;
+ if ((srcFormat == AV_PIX_FMT_GBRP && dstFormat == AV_PIX_FMT_GBRAP) ||
+ (srcFormat == AV_PIX_FMT_GBRAP && dstFormat == AV_PIX_FMT_GBRP))
+ c->swscale = planarRgbToplanarRgbWrapper;
+
#define isByteRGB(f) ( \
f == AV_PIX_FMT_RGB32 || \
f == AV_PIX_FMT_RGB32_1 || \
@@ -1042,33 +1617,89 @@ 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_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_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) {
@@ -1099,13 +1730,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 &&
@@ -1120,177 +1752,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[], int 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 0000000..5cb8ee7
--- /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 32e304c..ab494ed 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,6 +111,10 @@ 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 },
@@ -134,8 +142,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,29 +167,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_XYZ12BE] = { 0, 0, 1 },
- [AV_PIX_FMT_XYZ12LE] = { 0, 0, 1 },
+ [AV_PIX_FMT_XYZ12BE] = { 1, 1, 1 },
+ [AV_PIX_FMT_XYZ12LE] = { 1, 1, 1 },
+ [AV_PIX_FMT_GBRAP] = { 1, 1 },
+ [AV_PIX_FMT_GBRAP16LE] = { 1, 0 },
+ [AV_PIX_FMT_GBRAP16BE] = { 1, 0 },
+ [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 },
};
int sws_isSupportedInput(enum AVPixelFormat pix_fmt)
@@ -202,15 +241,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)
{
@@ -224,12 +254,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;
@@ -237,19 +296,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;
@@ -257,12 +316,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;
@@ -273,12 +332,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;
@@ -286,8 +345,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;
@@ -297,28 +355,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
@@ -328,10 +375,10 @@ 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;
@@ -365,7 +412,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) {
@@ -416,8 +463,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;
@@ -430,14 +476,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;
@@ -512,19 +558,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)
@@ -548,36 +598,34 @@ 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] + 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;
- }
- (*filterPos)[i] = srcW - filterSize;
+ 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;
}
+ (*filterPos)[i]= srcW - filterSize;
}
}
// 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++) {
@@ -589,6 +637,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);
@@ -611,211 +663,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;
}
@@ -823,7 +857,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;
@@ -843,6 +877,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;
@@ -852,15 +889,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,7 +945,7 @@ SwsContext *sws_alloc_context(void)
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 };
@@ -880,13 +953,13 @@ 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;
cpu_flags = av_get_cpu_flags();
flags = c->flags;
@@ -896,16 +969,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);
}
}
@@ -925,19 +1015,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",
@@ -965,9 +1055,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,
@@ -988,10 +1125,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;
}
@@ -1011,30 +1153,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);
-
- /* unscaled special cases */
- if (unscaled && !usesHFilter && !usesVFilter &&
- (c->srcRange == c->dstRange || isAnyRGB(dstFormat))) {
- ff_get_unscaled_swscale(c);
+ // 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);
- 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_ALLOC_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)
@@ -1042,21 +1174,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;
@@ -1077,12 +1211,37 @@ 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;
}
}
+ 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 */
@@ -1090,9 +1249,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
@@ -1118,21 +1277,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 */
@@ -1140,19 +1310,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
@@ -1162,18 +1336,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
@@ -1215,6 +1394,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);
@@ -1230,9 +1412,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);
@@ -1249,38 +1431,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 ||
@@ -1289,18 +1463,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,
@@ -1312,9 +1488,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;
}
@@ -1333,8 +1549,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;
@@ -1342,9 +1556,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);
@@ -1418,7 +1629,12 @@ SwsFilter *sws_getDefaultFilter(float lumaGBlur, float chromaGBlur,
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;
@@ -1433,7 +1649,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;
@@ -1600,14 +1821,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;
}
@@ -1652,14 +1871,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);
}
@@ -1688,6 +1903,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);
@@ -1722,7 +1940,12 @@ 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]);
+ memset(c->cascaded_context, 0, sizeof(c->cascaded_context));
+ av_freep(&c->cascaded_tmp[0]);
av_free(c);
}
@@ -1760,19 +1983,13 @@ 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);
if (sws_init_context(context, srcFilter, dstFilter) < 0) {
sws_freeContext(context);
return NULL;
diff --git a/libswscale/version.h b/libswscale/version.h
index fdde657..228c577 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 b94b14a..6901207 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 0000000..103793d
--- /dev/null
+++ b/libswscale/x86/hscale_fast_bilinear_simd.c
@@ -0,0 +1,374 @@
+/*
+ * 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"
+ // "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 = 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 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;
+}
+
+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 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 //HAVE_INLINE_ASM
diff --git a/libswscale/x86/input.asm b/libswscale/x86/input.asm
index 6f5677e..af9afca 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 e1ceded..9ea4af9 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 9cfe831..b80e869 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 5d34c21..3899d0a 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,10 +1623,15 @@ 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;
for (y=0; y<height-2; y+=2) {
@@ -1640,7 +1639,7 @@ static inline void RENAME(rgb24toyv12)(const uint8_t *src, uint8_t *ydst, uint8_
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 +1658,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 +1681,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 +1699,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 +1710,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 +1759,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 +1819,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 +1848,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 +1862,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
@@ -1945,9 +1939,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 +1954,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 +1966,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 +2186,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 +2434,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 +2460,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 +2484,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 +2510,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 +2566,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 +2577,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 440a27b..7af92f7 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 f310a75..fe5c4ea 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
@@ -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(((int)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 1e42ec5..36a606c 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 dd9a2a4..88143d9 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 bacc87f..5e2f77c 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 0b97516..acb78f5 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 480fbe3..8e92e6d 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
@@ -532,7 +573,7 @@ CLOSEYUV2RGBFUNC(8)
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 +611,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 +622,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 +651,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(i-YUVRGB_TABLE_HEADROOM, 0, 255)*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(i-YUVRGB_TABLE_HEADROOM, 0, 255)*inc;
table[i] = elemsize * (off + (cb >> 16));
- cb += inc;
}
}
@@ -684,7 +719,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 +764,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);
switch (bpp) {
case 1:
@@ -847,6 +882,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);
@@ -872,7 +908,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-720p.avpreset b/presets/libvpx-1080p.ffpreset
index 3c7e396..cf25932 100644
--- a/presets/libvpx-720p.avpreset
+++ b/presets/libvpx-1080p.ffpreset
@@ -1,8 +1,10 @@
+vcodec=libvpx
+
g=120
lag-in-frames=16
deadline=good
cpu-used=0
-profile=0
+vprofile=1
qmax=51
qmin=11
slices=4
diff --git a/presets/libvpx-1080p50_60.avpreset b/presets/libvpx-1080p50_60.ffpreset
index f85d3d6..4a88040 100644
--- a/presets/libvpx-1080p50_60.avpreset
+++ b/presets/libvpx-1080p50_60.ffpreset
@@ -1,8 +1,10 @@
+vcodec=libvpx
+
g=120
lag-in-frames=25
deadline=good
cpu-used=0
-profile=1
+vprofile=1
qmax=51
qmin=11
slices=4
diff --git a/presets/libvpx-360p.avpreset b/presets/libvpx-360p.ffpreset
index 2cb9e38..f9729ba 100644
--- a/presets/libvpx-360p.avpreset
+++ b/presets/libvpx-360p.ffpreset
@@ -1,8 +1,10 @@
+vcodec=libvpx
+
g=120
lag-in-frames=16
deadline=good
cpu-used=0
-profile=0
+vprofile=0
qmax=63
qmin=0
b=768k
diff --git a/presets/libvpx-1080p.avpreset b/presets/libvpx-720p.ffpreset
index 5c7da6f..e84cc15 100644
--- a/presets/libvpx-1080p.avpreset
+++ b/presets/libvpx-720p.ffpreset
@@ -1,8 +1,10 @@
+vcodec=libvpx
+
g=120
lag-in-frames=16
deadline=good
cpu-used=0
-profile=1
+vprofile=0
qmax=51
qmin=11
slices=4
diff --git a/presets/libvpx-720p50_60.avpreset b/presets/libvpx-720p50_60.ffpreset
index 6139300..8fce2bf 100644
--- a/presets/libvpx-720p50_60.avpreset
+++ b/presets/libvpx-720p50_60.ffpreset
@@ -1,8 +1,10 @@
+vcodec=libvpx
+
g=120
lag-in-frames=25
deadline=good
cpu-used=0
-profile=0
+vprofile=0
qmax=51
qmin=11
slices=4
diff --git a/presets/libx264-baseline.avpreset b/presets/libx264-baseline.avpreset
deleted file mode 100644
index 0626e28..0000000
--- 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 a8c526e..0000000
--- 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 d9cf5af..0000000
--- 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 e311989..0000000
--- 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 48a2d44..0000000
--- 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 6323191..0000000
--- 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 c2c3e1a..0000000
--- 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 1658d56..0000000
--- 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 c25ff32..0000000
--- 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 f7b1d81..0000000
--- 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 a15ff4c..0000000
--- 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 bd71f03..0000000
--- 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 4d71eb7..0000000
--- 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 336c69b..0000000
--- 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 261d584..0000000
--- 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 06c8f9f..0000000
--- 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 93d721d..0000000
--- 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 c8099e5..0000000
--- 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 85778ec..0000000
--- 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 9998bc9..0000000
--- 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 87d6989..0000000
--- 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 c798b82..0000000
--- 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 1c117ec..0000000
--- 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 fc70e09..0000000
--- 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 9103301..0000000
--- 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 e3aaa17..0000000
--- 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 fa49629..0000000
--- 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 4909030..0000000
--- 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 7e01c8f..0000000
--- 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 daf5a8f..0000000
--- 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 a2ee79b..7ef8132 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
@@ -17,9 +31,25 @@ tests/data/vsynth1.yuv: tests/videogen$(HOSTEXESUF) | tests/data
$(M)$< $@
tests/data/vsynth2.yuv: tests/rotozoom$(HOSTEXESUF) | tests/data
- $(M)$< $(SRC_PATH)/tests/lena.pnm $@
+ $(M)$< $(SAMPLES)/lena.pnm $@
+
+tests/data/vsynth3.yuv: tests/videogen$(HOSTEXESUF) | tests/data
+ $(M)$< $@ $(FATEW) $(FATEH)
-tests/data/asynth% tests/data/vsynth%.yuv tests/vsynth%/00.pgm: TAG = GEN
+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) ./$< \
+ -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 +107,14 @@ 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/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 +124,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
@@ -105,6 +140,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 +151,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)'
+ $(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)'
fate-list:
@printf '%s\n' $(sort $(FATE))
@@ -152,7 +200,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 +214,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 7f9caed..8d596b5 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 6462d9a..5035ad9 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 0000000..4b5811d
--- /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 91de177..f78e4fc 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
@@ -71,38 +71,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="-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(){
@@ -114,8 +129,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"
@@ -136,20 +151,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(){
@@ -158,33 +179,46 @@ 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 $* -f nut md5:
}
pixfmts(){
filter=${test#filter-pixfmts-}
+ filter=${filter%_*}
filter_args=$1
+ prefilter_chain=$2
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
+
+ $showfiltfmts $filter | awk -F '[ \r]' '/^INPUT/{ fmt=substr($3, 5); print fmt }' | sort >$in_fmts
+ pix_fmts=$(comm -12 $scale_exclude_fmts $in_fmts)
- pix_fmts=$($showfiltfmts $filter | awk -F '[ \r]' '/^INPUT/{ print $3 }' | sort | comm -12 - $out_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
+ video_filter "${prefilter_chain}format=$pix_fmt,$filter=$filter_args" -pix_fmt $pix_fmt
done
- rm $exclude_fmts $out_fmts
+ rm $in_fmts $scale_in_fmts $scale_out_fmts $scale_exclude_fmts
+ test=$outertest
}
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=$?
@@ -197,6 +231,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 ;;
@@ -218,5 +253,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 0000000..db72c54
--- /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 af0f6c0..5a78018 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"} \
${cross_prefix:+--cross-prefix="$cross_prefix"} \
@@ -81,8 +83,10 @@ 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
+ echo "fate:0:${date}:${slot}:${version}:$1:$2:${comment}" >report
+# echo "fate:1:${date}:${slot}:${version}:$1:$2:${branch}:${comment}" >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
}
@@ -111,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 b3f07cb..bc52cad 100644
--- a/tests/fate/aac.mak
+++ b/tests/fate/aac.mak
@@ -81,6 +81,23 @@ 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 = 1862
+fate-aac-aref-encode: SIZE_TOLERANCE = 2464
+
+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
@@ -98,7 +115,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 3841240..f00c3c4 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 3431754..325bbd9 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,82 @@ 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, 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: FMT = flac
fate-acodec-flac: CODEC = flac -compression_level 2
+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 += $(FATE_ACODEC-yes)
$(FATE_ACODEC): tests/data/asynth-44100-2.wav
diff --git a/tests/fate/adpcm.mak b/tests/fate/adpcm.mak
index 7ee6245..b64920d 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/audio.mak b/tests/fate/audio.mak
index d6ca58e..b7e5362 100644
--- a/tests/fate/audio.mak
+++ b/tests/fate/audio.mak
@@ -10,41 +10,60 @@ 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_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, MPEGTS, DCA) += fate-dts
+FATE_SAMPLES_AUDIO-$(call DEMDEC, MPEGTS, DCA) += fate-dts
fate-dts: CMD = pcm -i $(TARGET_SAMPLES)/dts/dts.ts
fate-dts: CMP = oneoff
fate-dts: REF = $(SAMPLES)/dts/dts.pcm
-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 458ae7c..1040afa 100644
--- a/tests/fate/avformat.mak
+++ b/tests/fate/avformat.mak
@@ -1,18 +1,23 @@
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
@@ -30,6 +35,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 +45,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 54dc0ba..721c650 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 2446b90..0eccc9b 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 2bffd47..9de671c 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 0000000..da5dae8
--- /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 0000000..a6cb159
--- /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/vsynth2.yuv
+fate-force_key_frames: CMD = enc_dec \
+ "rawvideo -s 352x288 -pix_fmt yuv420p" tests/data/vsynth2.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/vsynth2.yuv
+fate-sub2video: CMD = framecrc \
+ -f rawvideo -r 5 -s 352x288 -pix_fmt yuv420p -i $(TARGET_PATH)/tests/data/vsynth2.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 0000000..cf20185
--- /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 d2a3904..9fdca2b 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 363ae2e..210b89e 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 42fb063..601a0d8 100644
--- a/tests/fate/filter-video.mak
+++ b/tests/fate/filter-video.mak
@@ -1,25 +1,55 @@
-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_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
@@ -41,13 +71,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 +122,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 +143,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 +206,98 @@ 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"
+
+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"
+
+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"
+
+FATE_FILTER_VSYNTH-$(CONFIG_IDET_FILTER) += fate-filter-idet
+fate-filter-idet: CMD = video_filter "idet"
+
+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_VSYNTH-$(CONFIG_PP_FILTER) += fate-filter-pp
+fate-filter-pp: CMD = video_filter "pp=be/hb/vb/tn/l5/al"
+
+FATE_FILTER_VSYNTH-$(CONFIG_PP_FILTER) += fate-filter-pp1
+fate-filter-pp1: CMD = video_filter "pp=fq|4/be/hb/vb/tn/l5/al"
+
+FATE_FILTER_VSYNTH-$(CONFIG_PP_FILTER) += fate-filter-pp2
+fate-filter-pp2: CMD = video_filter "pp=be/fq|16/h1/v1/lb"
+
+FATE_FILTER_VSYNTH-$(CONFIG_PP_FILTER) += fate-filter-pp3
+fate-filter-pp3: CMD = video_filter "pp=be/fq|8/ha|128|7/va/li"
+
+FATE_FILTER_VSYNTH-$(CONFIG_PP_FILTER) += fate-filter-pp4
+fate-filter-pp4: CMD = video_filter "pp=be/ci"
+
+FATE_FILTER_VSYNTH-$(CONFIG_PP_FILTER) += fate-filter-pp5
+fate-filter-pp5: CMD = video_filter "pp=md"
+
+FATE_FILTER_VSYNTH-$(CONFIG_PP_FILTER) += fate-filter-pp6
+fate-filter-pp6: CMD = video_filter "pp=be/fd"
+
+FATE_FILTER_VSYNTH-$(CONFIG_SELECT_FILTER) += fate-filter-select
+fate-filter-select: CMD = video_filter "select=not(eq(mod(n\,2)\,0)+eq(mod(n\,3)\,0))"
+
+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 +319,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,"
+
+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,"
+
+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 e28f45f..4a13404 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/gif.mak b/tests/fate/gif.mak
new file mode 100644
index 0000000..3dc50b3
--- /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 34d03bf..46178cd 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 9afe717..bd852cc 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,24 +152,75 @@ 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-$(call DEMDEC, HEVC, HEVC) += $(FATE_HEVC)
diff --git a/tests/fate/image.mak b/tests/fate/image.mak
index f91ee69..89b91aa 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,13 +24,13 @@ 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_EXR += fate-exr-slice-raw
@@ -50,53 +50,53 @@ 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, PICTOR) += fate-pictor
+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
@@ -129,7 +129,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 \
@@ -148,7 +148,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
@@ -172,9 +172,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
@@ -182,5 +185,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/libavresample.mak b/tests/fate/libavresample.mak
index 4a48c9c..c854a47 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 7f3329b..eadebdb 100644
--- a/tests/fate/libavutil.mak
+++ b/tests/fate/libavutil.mak
@@ -8,6 +8,11 @@ fate-aes: libavutil/aes-test$(EXESUF)
fate-aes: CMD = run libavutil/aes-test
fate-aes: 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 +30,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
@@ -49,7 +58,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,14 +70,34 @@ 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
@@ -78,5 +107,10 @@ 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 0000000..24b7d66
--- /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 3638f17..0736a01 100644
--- a/tests/fate/lossless-audio.mak
+++ b/tests/fate/lossless-audio.mak
@@ -1,22 +1,29 @@
-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_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 bf1a971..11eba30 100644
--- a/tests/fate/lossless-video.mak
+++ b/tests/fate/lossless-video.mak
@@ -7,7 +7,7 @@ fate-cllc-rgb: CMD = framecrc -i $(TARGET_SAMPLES)/cllc/sample-cllc-rgb.avi
FATE_CLLC += fate-cllc-yuy2-noblock
fate-cllc-yuy2-noblock: CMD = framecrc -i $(TARGET_SAMPLES)/cllc/sample-cllc-yuy2-noblock.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, CLLC) += $(FATE_CLLC)
+FATE_LOSSLESS_VIDEO-$(call DEMDEC, AVI, CLLC) += $(FATE_CLLC)
fate-cllc: $(FATE_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 10bbb30..4e8ae51 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 fe6a0e1..57ee084 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 f9b94e6..eefdec9 100644
--- a/tests/fate/mpeg4.mak
+++ b/tests/fate/mpeg4.mak
@@ -1,7 +1,7 @@
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))
diff --git a/tests/fate/opus.mak b/tests/fate/opus.mak
index 161a94f..b13d86c 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 116b50f..9ba4be5 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 376dfdd..9f9dd4a 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 8d4b6ac..e88df5f 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 ac95d64..6d78822 100644
--- a/tests/fate/qt.mak
+++ b/tests/fate/qt.mak
@@ -1,50 +1,55 @@
-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 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 f119ce9..c123e44 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 bd6ace6..72e9b4c 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_TSCC += fate-tscc-15bit
@@ -35,7 +35,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_SAMPLES_AVCONV-$(call DEMDEC, AVI, TSCC2) += fate-tscc2
@@ -47,7 +47,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
@@ -62,5 +62,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 be06f0f..e511387 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
@@ -89,6 +99,8 @@ 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, SNOW, AVI) += snow
+FATE_SEEK_VSYNTH2-$(call ENCDEC, SNOW, AVI) += snow-ll
FATE_SEEK_VSYNTH2-$(call ENCDEC, SVQ1, MOV) += svq1
FATE_SEEK_VSYNTH2-$(call ENCDEC, WMV1, AVI) += wmv1
FATE_SEEK_VSYNTH2-$(call ENCDEC, WMV2, AVI) += wmv2
@@ -125,6 +137,7 @@ 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-nsse: SRC = fate/vsynth2-mpeg4-nsse.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
@@ -135,12 +148,14 @@ 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-snow: SRC = fate/vsynth2-snow.avi
+fate-seek-vsynth2-snow-ll: SRC = fate/vsynth2-snow-ll.avi
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_SAMPLES_SEEK += $(FATE_SEEK_VSYNTH2-yes:%=fate-seek-vsynth2-%)
# 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
@@ -178,6 +194,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 +204,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
@@ -214,14 +232,16 @@ 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-%
+$(FATE_SEEK) $(FATE_SAMPLES_SEEK): 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: $(FATE_SEEK) $(FATE_SAMPLES_SEEK)
diff --git a/tests/fate/subtitles.mak b/tests/fate/subtitles.mak
new file mode 100644
index 0000000..53cd4cb
--- /dev/null
+++ b/tests/fate/subtitles.mak
@@ -0,0 +1,69 @@
+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-sub-movtextenc
+fate-sub-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_SAMPLES_FFMPEG += $(FATE_SUBTITLES)
+fate-subtitles: CMP = rawdiff
+fate-subtitles: $(FATE_SUBTITLES)
diff --git a/tests/fate/utvideo.mak b/tests/fate/utvideo.mak
index e1ef7ec..1e4755e 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 ed9fa2e..c715071 100644
--- a/tests/fate/vcodec.mak
+++ b/tests/fate/vcodec.mak
@@ -1,11 +1,16 @@
fate-vsynth1-%: SRC = tests/data/vsynth1.yuv
fate-vsynth2-%: SRC = tests/data/vsynth2.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
@@ -13,26 +18,27 @@ FATE_VCODEC-$(call ENCDEC, ASV2, AVI) += asv2
fate-vsynth%-asv2: ENCOPTS = -qscale 10
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-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_VCODEC-$(call ENCDEC, DVVIDEO, DV) += dv dv-411 dv-50
@@ -52,41 +58,64 @@ 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
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_VCODEC-$(call ENCDEC, MPEG1VIDEO, MPEG1VIDEO MPEGVIDEO) += mpeg1 mpeg1b
fate-vsynth%-mpeg1: FMT = mpeg1video
@@ -142,7 +171,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 +194,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 +218,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 +243,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 +254,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 +294,34 @@ fate-vsynth%-wmv2: ENCOPTS = -qscale 10
FATE_VCODEC-$(call ENCDEC, RAWVIDEO, AVI) += yuv
fate-vsynth%-yuv: CODEC = rawvideo
+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-%)
+# 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 = 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_VSYNTH3): tests/data/vsynth3.yuv
-FATE_AVCONV += $(FATE_VSYNTH1) $(FATE_VSYNTH2)
+FATE_AVCONV += $(FATE_VSYNTH1) $(FATE_VSYNTH3)
+FATE_SAMPLES_AVCONV += $(FATE_VSYNTH2)
fate-vsynth1: $(FATE_VSYNTH1)
fate-vsynth2: $(FATE_VSYNTH2)
-fate-vcodec: fate-vsynth1 fate-vsynth2
+fate-vsynth3: $(FATE_VSYNTH3)
+fate-vcodec: fate-vsynth1 fate-vsynth2 fate-vsynth3
diff --git a/tests/fate/video.mak b/tests/fate/video.mak
index 5a48e10..7e5416c 100644
--- a/tests/fate/video.mak
+++ b/tests/fate/video.mak
@@ -4,37 +4,43 @@ 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, MM, MMVIDEO) += fate-alg-mm
+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, 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
@@ -46,25 +52,24 @@ 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_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
@@ -76,31 +81,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
@@ -109,14 +117,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
@@ -124,17 +132,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
@@ -145,54 +153,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
@@ -200,49 +211,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
@@ -251,42 +259,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 975936c..44b5b93 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 f8c25e5..03f571b 100644
--- a/tests/fate/vpx.mak
+++ b/tests/fate/vpx.mak
@@ -19,9 +19,27 @@ 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_SAMPLES_AVCONV += $(FATE_VP6-yes)
fate-vp6: $(FATE_VP6-yes)
@@ -40,17 +58,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)
@@ -80,6 +98,7 @@ $(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)))
+$(eval $(call FATE_VP9_SUITE,trac3849,$(1),$(2)))
endef
$(eval $(call FATE_VP9_FULL))
diff --git a/tests/fate/vqf.mak b/tests/fate/vqf.mak
index 355bab0..ac18ebd 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 3432cc6..240f5ea 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 0000000..11e4a54
--- /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 0000000..ae35d7f
--- /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 0000000..9fc7497
--- /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 0000000..1aa302d
--- /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 0000000..ef3ea14
--- /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 0000000..26bca14
--- /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 0000000..d93dcaf
--- /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 0000000..7591822
--- /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 d646463..f648274 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 0000000..b060c01
--- /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 0000000..9ed1b2a
--- /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 0000000..e5df859
--- /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 0000000..bda0fd6
--- /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 0000000..17b69de
--- /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 3c18b2f..7e6ad06 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,26 +64,26 @@ do_audio_only()
}
if [ -n "$do_avi" ] ; then
-do_lavf avi "" "-acodec mp2 -ar 44100"
+do_lavf avi "" "-acodec mp2 -ar 44100 -ab 64k"
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"
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"
fi
if [ -n "$do_mxf_d10" ]; then
@@ -71,35 +91,73 @@ do_lavf mxf_d10 "-ar 48000 -ac 2" "-r 25 -vf scale=720:576,pad=720:608:0:32 -vco
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"
fi
if [ -n "$do_swf" ] ; then
do_lavf swf "" "-an"
fi
+if [ -n "$do_ffm" ] ; then
+do_lavf ffm "" "-ar 44100"
+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"
+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"
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_timecode_nodrop gxf "-ar 48000 -r 25 -s pal -ac 1"
+do_lavf_timecode_drop gxf "-ar 48000 -s ntsc -ac 1"
do_lavf gxf "-ar 48000" "-r 25 -s pal -ac 1"
fi
if [ -n "$do_nut" ] ; then
-do_lavf nut "" "-acodec mp2 -ar 44100"
+do_lavf nut "" "-acodec mp2 -ab 64k -ar 44100"
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"
+do_lavf mkv "" "-acodec mp2 -ab 64k -vcodec mpeg4 -ar 44100"
+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"
fi
@@ -145,6 +203,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 +228,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 +274,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 +304,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 +319,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/lena.pnm b/tests/lena.pnm
deleted file mode 100644
index 700508c..0000000
--- a/tests/lena.pnm
+++ /dev/null
@@ -1,109 +0,0 @@
-P6
-# CREATOR: The GIMP's PNM Filter Version 1.0
-256 256
-255
-â‰}߈‚â†väˆ|â{â†|à†r̃„uƯ„ñvß‚k̃„jÜ„pà€gƯ‚t̃sà‚jà„râværèrè’ẃ—zè—yî•vê”xévè†tàwfØvvÊZa´P_¨@Tœ>\œ=Y¤EX¦GXªJZ®IZ²J\²NW±JV¯LV°OZ²LX²LX´NX²LV²NZ°NZ®JS´JT´OV¸SY¼TZÂXZÂTXÂZYÄ^ZÄ[\Ê`\Ê^\Ë\Z̀f_Îb^Îeb̀abËbbËkhÍffÎd`̀b]Îb`Ê`^Êg_Ëd^Ëd`Ëa^ÎhaÎhjÑb^ĐebĐfaĐgf̉ebÔe`̉dd̉fb̉gdÎheÎf`Ïd^ĐffĐjf̀feÎfbÎjfĐgbÓidÑibĐicÎhj̉heÊghÊknÎhl̀ffËe_Çdd̀f^Îe]ÍcbÊcbÈjhÍibÍdaÎddÎdb̉b\Đe`Ñhb̉f`Đg`ĐjdÑd\ÏfdÎ``Îjj̉plÍgc̀d_Èbb̉e`Êd`Îfg̀b^Çb`Îe`È`eÎieÈbcÈc^Êb`̀cbÈccÎabËadÈbbÇbdÈ^^ÉbcÄbaÀ\`Â[dÀZ`»Za´X_°T[±PX¨HV¶LP¾V\È`]ÑlbÔqlÖzlÙtÜ„p̃ˆñrÚvƯ‚nÜzgÜ~jÚ€jÜl̃€nÜ€r̃‚rƯ€p̃†x̃‚n߀h̃€jÜ~j߀ẽ€l̃fà}fƯ‚j̃hÜ€ẽ„hÜ„m܆nƯ‚j̃†qƯˆqƯ„pÜ‚hØ„nä”nï¹…ôÈøΖøĐúÔ£üÔœúÔŸôÈ⪀Ärj§M\¥HX¨PZ®OZµX\¹Z\¶Za¼^`ºac¼X\¼^^¾ZZ½^b»dhº[cº\aĂZ[À[^ĂZZĂZ^¾^^Ă]`Â_^Á`cÄ`bÀ^_Å^]¼V\Á`cÂ`bÄbhÁ``Æ[[ÂbbÄa`¿[]¼V\¼V\ºVZ¾\bÚ{væ’€è”z̉rdâ‰}߈‚â†väˆ|â{â†|à†r̃„uƯ„ñvß‚k̃„jÜ„pà€gƯ‚t̃sà‚jà„râværèrè’ẃ—zè—yî•vê”xévè†tàwfØvvÊZa´P_¨@Tœ>\œ=Y¤EX¦GXªJZ®IZ²J\²NW±JV¯LV°OZ²LX²LX´NX²LV²NZ°NZ®JS´JT´OV¸SY¼TZÂXZÂTXÂZYÄ^ZÄ[\Ê`\Ê^\Ë\Z̀f_Îb^Îeb̀abËbbËkhÍffÎd`̀b]Îb`Ê`^Êg_Ëd^Ëd`Ëa^ÎhaÎhjÑb^ĐebĐfaĐgf̉ebÔe`̉dd̉fb̉gdÎheÎf`Ïd^ĐffĐjf̀feÎfbÎjfĐgbÓidÑibĐicÎhj̉heÊghÊknÎhl̀ffËe_Çdd̀f^Îe]ÍcbÊcbÈjhÍibÍdaÎddÎdb̉b\Đe`Ñhb̉f`Đg`ĐjdÑd\ÏfdÎ``Îjj̉plÍgc̀d_Èbb̉e`Êd`Îfg̀b^Çb`Îe`È`eÎieÈbcÈc^Êb`̀cbÈccÎabËadÈbbÇbdÈ^^ÉbcÄbaÀ\`Â[dÀZ`»Za´X_°T[±PX¨HV¶LP¾V\È`]ÑlbÔqlÖzlÙtÜ„p̃ˆñrÚvƯ‚nÜzgÜ~jÚ€jÜl̃€nÜ€r̃‚rƯ€p̃†x̃‚n߀h̃€jÜ~j߀ẽ€l̃fà}fƯ‚j̃hÜ€ẽ„hÜ„m܆nƯ‚j̃†qƯˆqƯ„pÜ‚hØ„nä”nï¹…ôÈøΖøĐúÔ£üÔœúÔŸôÈ⪀Ärj§M\¥HX¨PZ®OZµX\¹Z\¶Za¼^`ºac¼X\¼^^¾ZZ½^b»dhº[cº\aĂZ[À[^ĂZZĂZ^¾^^Ă]`Â_^Á`cÄ`bÀ^_Å^]¼V\Á`cÂ`bÄbhÁ``Æ[[ÂbbÄa`¿[]¼V\¼V\ºVZ¾\bÚ{væ’€è”z̉rdâ|à†yâ†vä†xâˆvâ„vàƒnà‚oß„m߆p߀hàh̃„oà€gƯ€t̃‚nß‚l̃náˆtæ‹qçrè“yë—zë—yî–v́”vêuç„oßwh×omÈX_´O^§AW>Y<V¤BV¦FZªFY®JZ°JZ²KV±JT®JT°LX³IS²JV³LW±JT²LX²LW¯JR³KU²PW¸QX¼U[ÂWYĂVZÂZXÄ\ZÆ\]Ê][Ê^^Ë[[Êa^Ïc^ÎdbËddËa^̀heËccÎfbÍc^Ía`Ëa`Êfc̀d`Íb`̀b_ÏieÎgjĐd_ĐgdĐhd̉idÓfaÔeaÓfb̉fb̉fbÏidĐd`Ïc_ĐecĐgbÎdbÏfcĐhbĐgảhaÑfbÏhdÎhf̉gaËgjÍhiÍjjËeb̀b`Ébàe^Đd]Îcàb`ÈfdÍjaÊb_̀ddÍc_Ña\ÍfbĐfaĐfaÏf^ĐgbĐe^Đd`Îb_̀hh̉jiÎhd̀daÇbaĐd_̀c_̀ccÍd_Éa`ÍdaÉacËhiÈ^`Èa^ÉccÊdeÉa`ÎbcËceÈ`bÇbdÈ``Ë`aÄ`aÁ\_Â[bÀ\`ºY`µW^³TZ°OY¨JVµJP½TXÇ_^ÏjbÔpl×ylÙ}rƯ‚r̃‡ußrÛsƯƒmÜ|jƯhÜ~kÜmÜ}kÜ~õ‚pÜ€mƯ‚p̃ƒoà€h߀hƯj̃~f̃~l̃€hß~ĩ€h̃„iÜd̃ƒh̃‚i܆o܃jƯ„q̃†ñ„pÜiÙlâ‘oôÅ÷ΘùĐœúÔ¡üÔúÖö˔求Êzm¨NX¥HXªLV®Q\³X]¸Y\¹Y\½\^½``¼Z]»]]¾\[¼^b¼`eº]a¸[`¿[\¿Y\ĂZYÄ\]¿_`Ä^]Ä^^À_aÄa`Á`_Ä^\½WZÂ_aÁ^aÅbdÄ_`Ç]ZÂbbÄ`^À\\¾U\¾V\¼Z\À_bØtl̃…vÚ}l¶WZâ†xà†qâ†vä‚nâ‡vâ†tâ€eà}lànà€ià€há~g̃‚kà€fß|j̃‚kß„ñ€gä„næŒrév́’t́–|́–xí–ý’sënæ„g̃xiÔfbÈZ\µL[¨<UŸ7S›;T¢<S§>T¬@T°KZ°LY°FS±FQ²EP±IV®FR°GS±JV²HOµFN²IT°GO³KV¶LRºOR¼VXÀTXÄWYÆ\\È_ZÊ\VÉ^ZÊZÙZXÍ_\Đb\Îa[̀ecÏ`\Îb_ËcbĐa^Ë`aÏbbÑf`Đd_Íc]̀c`Ïb]̉c`Ïb\̉c\ĐfgĐfdÑfb̉f`̉b^ƠebÔe`Ód^Ôa[Ñf^̉b^ĐabÎcdÎc_Ñc^ÑfcÎfdÎdaÏedÎfdĐc^Ïb`̀dhËkǹdfËmjÊbbÍgbÊb`Îd`Î`ZËc`Ëjf̀ieËbbÊe`Í^XÎd\Îd^ÎgdÓd^Îh`Íb`Đe`Ïa]ĐfbĐd^ĐffÍedĐd`Îa\Ë_\Ç`c̀`^Éfh̀^]Ëb`Éa`Êa_Ê_^ÅbeÎa\ÎabËcàbàabÉ`^Êbd̀_\È^^Æ^`Æ[]ÁZ^¼\f¼W^¹T[¶RZ²LT«KX¬EPºUXÄ\^Èe`ÓlgÔvnØ{nÛrÛ†p̃ˆt߈t̃„m̃‚õ~g̃}gÜoÜ|g̃€nÜ€nÜiƯ‚nß‚là€fßißfßẽ~cà€ià‚hƯ€j߀f̃}d̃ẽ‚gƯ‚iÜ‚lƯ„mÜ„r̃‚kƯ‚jÚiÛhè¢xñ¾÷ÊøĐú̉›ûÔüÖû̉•̣Éßs¸d_£HX¦JW«P]²V]¸V[¼[]½TWº[^»Z]½ZZ¼`^ÀZ^¾`a¿\^º^bº_d½]^¾^\Âa[Á__Æ_[À`_Á^]Ă]\Â\^Å\ZÀ^^¿[`Ä^^Æ``Ç]bÇ\[ÄbdÇ`\Ä_`Á[\Å[]Å`cÅb`¹VZœET~,KfEà‚ià…páƒrâ‚nâ…tâƒrà„kă€lâ€kà„nà‚jâĩnß~mƯ~hà‚l̃~iâƒjå‰mçré“ŕ“ẃ”ś–rî•ní‘pêŒlå€d̃tfÔjaÉWZ¸NX¨=R:Q¢8N¤:O¦@R­DT®DR²DPµHSµFP²DN³LW¯GR²KR²HR²GO²HN²HR°JT³LU³PY´OX»QY»VZĂUWÅZ]ĂYWÅ]]Ê^YÈ^]Ê]XÈa^̀]]Í`^Ê_[Đd]̀c_̀b`Íb^Íd_Íd`Îa^Îb]Îb^̀d^Íb\Đb^Îf_ĐbaÏc`ÏfaĐgb̉faÓh^̉haÓd^Ñb_̉gbÏhảdbÎb`ĐkhÑedÏdaĐfbĐdbÍa`ÑefÏcaĐd`Ïbf̀`_Ë`b̉dbÎb^Ëgf̀baË`\Í^\Í`]Éfb̀gdËhcÎedÎ^VÎ_[̀b\Ëe_ÎdcĐb^Óa]Đc`Đb[Ïb_̉b\ÎcaĐd^Đfb̀ecÏ`\Đa^Êb`Í`\ËbbÊ]]Ëb]Ë`^̀`]Ê\\È^`Í^^É]^ÈbaÎa_Ê_\̀`[Ëb`Ç[[É^]Ç]]È_^Æ\^¼Y_¼Ya¹TX¸PX·QS³LU¬HT±JU¼SYÂ]^ÎffÑql×xpÚ{nÜ‚q̃„tßuß…rß‚nƯ‚p̃€jƯ~j̃ƒká„lß‚iàj̃„mßiàjá„kàƒgâ‚eßjßg߀jà‚jß}ẽjß‚j̃ƒjÜ‚lÜlƯnÛmÜlÜkÚhÚ~m̃‰ń®€ơÂŒö̀™øĐûÓúÓ›üÔ™øÍ’ë·~Đ„l¬U[¨LY¬NU¯S\¸SZ¹XZºZ]¼\^¼Z_»Z\º]^¾[^¼]a¾\aÀ\]¾X[ÀZ`Á\^Â^^Â`^Ä[XÄ_^ÁZ\Ă_[Ă\_Ä^ZÆ]\Ä]^Ä`\Æ`cÆ``Å`]Ă`_Æa]ÈbbÆbdÉ_^Ä_\°NTŒ/Id@\B\Aàƒlà†nä‚iázká…oâƒká‚lâƒkä‚nàná„kâiß~hàhâ‚làbà‚hâ„jæjènê’oë“q́–ś•oî”ńhèmå}ẽo^Ơf]É\[µKT¨;OŸ8Q8P¥<P©@S¬BR®@P°HS´CN³GQ´FP±GT±IO´IR´DM±GP³IQ°DO°JR´KS¶OV¸OS½QT»VZÀW[Â[_Ä]`Æ\^È[VÊ^ZÎ[Ẁb\Ï^ZËb_Í_Z̀a^Î`\Ïa^Í_ZÊfdĐd^Ïd`Đe_Î`]Ïc\ÎaZĐ`]Đe]Đ`[Đdb̉fbĐfbÓb^Ôb[̉daÓd`̉ebÔd^ĐcaĐ_\ÑbbĐfbÓb^̉d`Ôd_Ñ`]Îc^ĐfaÎbbÑc\Ïc`ËcbĐa^ĐfdÍdbÎb`̀b`ÍcbÏ`\Îa^̀a^Ï`^ÈfcÏb^̀cZ̀c]ÍbaÎb\ÍdaÏcaĐhdÏc]Íd`Ïa]Îa_Î`_Î`[Ïb_Íd_Đd_̀c^̀bbÑaZ̀`]̀`]Êa^Êbf̀b]Í``Èa_̀_^ÊaaÊ^]̀`d̀d`̀`_̀a]Èa`ÈbaÈ`]Ä^_À\`¼V\¿YbºTZ·U`´NV²NX¯LY®HV±NX¾X^ÈegĐjfÖsoÚzrÜ~tß„vàˆuà†rá„oßl̃‚pßjßläƒiá†lá„mâ†oájâƒlá„jáƒlßj߀ià‚jà€hà†jàkà~fà€gßlÚ}aƯnÚlÚƒlÚhÛ€fÚ‚gÚ|iØkä—tđ¹„öÆ’ùΘúĐœûÔ₫ÖœûÓ˜ơÆŒä¤uÀlc¬JR¬IU«LU²RX³SZ¼VXÀ\]½ZZºY^»^a¾ZZ¾]^½Y\º\]¼Y_½ZZ½XZ¾\\¿\\Ă^^½]b¿]^Ä^\Ä\\Á^\Æ\\Â^^Ä^_È^\Í_\É\\Æ^`ÈdcÎfbËhbĂ_]®HO…,Fe@\@ZAZBäƒnâ‚pâ‚kâƒná„nâƒjâ€hâƒlâ‚jà‚qâ…lâkà€j߀iájáhăƒjä‹qèŒnè’rç”pé“tê’të“kínêhç‹hâ~gƯp\Ôh]ÉVT²JRª?Qœ7N :O¢=O¨<N¬BR°DQ±IV±GR³LX±KV°MV±NV³FN°DO±IP²CL±FO±DOµJR¸RVºNW¾RRÁWVĂVZÁVYÄZ^ÄX[È\ZË\YÍ\X̀]YĐ]VÎ[XÍ^XÑb`̀``Đb_Îd_ĐebÑd`̉c`Îb^ÏbaÎb`Ía\Ñc\Îd`Ï`\ÏbcÏgcĐb\Ôb^Ód^ÓgdÔg]Öc^Ôb\Đb\ĐfcÑddĐd`Óc`Ób]Ô_]Ñd_Î`aĐdcÎ`c̉c_̉b_Ñeảe`ÑdaÎdcĐd`Îb^Ï`^Îb_Đ_\Íb^ÏcaÍc`̉c`̀_[Î`ZÎebĐb]Đhd̉hd̉haÑddÏfbÎb`ÎebÏb^Îb]Îd`Íb_Îb^Đfb̀dfÎa\Èb`Î_ZÍcàb`ÉbaË^]̀b`̀__Ëc`Æ^\È]^̀`^Ê`_É_^Ë`^̀ddÈ__Ă]bÅ\`À\`ÀZ^¹V`µPZ´PX±SZ²PZ®IT©HW·S\Â_hÏkiÔqnÚvlÛ}tàmá‡vâˆsâ‡sà„má„mß…l̃‚oă†ná‡lâˆmåˆoä‰kä†pâ„pâ…jă‚fà‚là‚jà…gà‚ká‚f̃€hàh̃~dÜ‚jÜ€jÜ~jÜ‚oÜ€fÚ€jÚ‚mØ|hÖ~kÜ„lê©|óÀ‹øÊ’ùĐ›ûÔüƠœüÖúјđ»ˆÖr´WY¨LX¨M[¯T\±TZºTX¼X]¼Y_¼X\¼\_½\]ÂZZ¾\^¾[]ÀZ\ÁX[¼^c½[[¿^aÀ[ZĂ]\ÂZYÄ\]Ă\\Â\\Ă[\Æa^Ê`[Ç\[Æ`aÇ^`È^^̀hcÏgcÇ]Y²OV†,Gb$HY@X=Z@\>ä„pâ„nâ‚jă‚eß„nâƒhâ‚lâjă‚mâ‚jâ€gá€jà€g̃€jáiâ„iåˆpåpçqè“rç“vé“rê’nênêmæŒoç„fä~hƯr^×bVÊX\¶NW¦>Rœ<Q<R£<M§?O­FT±CN³FSµIRµJU±KT²JU´JR³HO²CP°IP²KP±BK°DM´JQ¶MV¹OV¾PQ¾TWÁTZÆVUÄ[aÅ^\Ê^\É\YÉ]YÍb[̀^XÎ^Ỳb^Î^ZÍ^\Îb]Îd`̀c`Đa^Đd\Ïb^Đa`Đa^Ï_\Óc\Îd`Đc]Ñc_Đb^̉b^̉aZÓheÖb`Ôc]̉b`Ñb[Đcb̉d`Ñdb̉feÖc^̉`\Ñ``ÏfdÏdẻfdĐcbĐec̉a`Ïc_ÏddÏdaĐc`Ñc\Îd_Đb^̉b\Îc`Ïd]Ídàb`Ïc`Ï_ZÎc]Îe_Ïb[Đd^ÓhaÓd_̉gfÎddÏb]ĐgdÏb]Î`^ÎddÎd`Îb_ÎaàcbÎc`ÉbcÍa^Í`\Ê`\Ë_]̀`^Ê_`Î`bÊbcÊ`à`_Îb^̀a`Ë``̀e_ËadÈ^cÄ^bÆ^`Â\aÁX^¼WY¶R]·T]±Vc±N[­KY«JX²NZ¼VaÊehÖpkØvrÜ|qƯs̃…tâpâˆrávăˆnàˆtá…rä‡täˆnåpæ‰påŒoè‡jă…ká„kâƒgá€lâ‚hà‚hàhâ~fâ‚fá‚fà‚hƯ~hÜ|jÜ|hÙ€kÙ€pÜ€lÚ€oØ‚pØ~jØyhä“qñ¶€øÄú͘ú̉œüƠŸüÖüƠŸ÷Ê“ç°€È{i¬MX­MY­MU´NW¶OUºZ[¸T\·VZ¼\^½Y[¾ZYÂ`]À[[¿YX½\]¾Z\À\`¿\b¿Z^Ă\\Á]`Ă^]Ä_`Æ_^Â]^Æ^^Å^^Å`ZÊcdÍdc̀ecÎk`ÄZ\¨EQ&Ea?\HZBZ<\B\Bă‚pà‚máƒmágâƒlä‚gâ‚oâ‚hâ€gă‚kâ‚jăjà~f̃~mâ€jătænætè’påqç‘pêpêlêmênç‰mæ„gà|gƯo\Ôf\ÈWY¶HR¦<LŸ7L 6J¢=O¨:J­FR²GQ°@L·KR´HO´HRµMV±HT²GT°FQ´JT²DM´DN±DKµEN·MP¼NQÀQUÁRSÅTSÇXVÈZ[Æ\bÇ]ZË\YË]ZÎ^ZÏ`\Ï_\Í_[̀eà`\Đa[Đd\Îb^Óa[̉b^̉c^Ñb^Îfảa^Đ`ZĐc_Óc`̉f_ĐfdÑd^̉c^ÑgẻfbÔe`Ókh̉eg̉fcÔa]̉d^Ôf\ÔefÑd^Ơa_̉``̉fcĐecÑcb̀a_ĐedÑgdÑffĐhd̉ec̉b^̉ffÑebÑ`\Í_\Ï`ZÎf]Ñd_Ïc`̀bà`]Đb]Đc^Óf]̉if̉fcƠjfÓe^ĐcaĐd`Îb\ÎebÎc^Đc`̉a_Đd\Íc`Î_\̀`\ÏbaÎ`[̀`_Ê`]Î^Z̀[^Î_^̀_^ÎbbÎaaÉbcÎ``ËbdÎ`^ÎbcËb`Æ_`À`bĂY\ĂZ]¾TX¿QV¹T[¶Zc´MX²OWªJ\®HW¹S^Á^hĐooÖvpØwpÜ}qÜ„wà…pá‰tâsâsâ†tă†lå†påpäŒuă‰lăqä‰qä†mâ„nâ…oânâ†jáƒnà‚láfâgá}bàh̃„rƯ|eÚjÚ|lÛ€mÚ}lØ~mÚ~hØ}i×{ĩ~hé¥{ô¿ˆúÊ‘úÑûÓœüÖ¢üÖ û̉œóĂávºb`¦JX­LV¬NZ¶PWºX\»TZ¼V[½Z_ÀY\¾[[Ä[ZÀZ[¾[]À_\½[\¿_a¾]_¿^^ÂabÂ_bÂ\\ÀceÅa^Ê`[Éb^̀b`Îb\Đd`̉hbÏfeĂ\[¦@Ly!B^>W>X<ZBY>[9_@âlà‚là„sâhâ„jâiä„hä†kä†kâ†mâiàƒpà€màlá…pä‰påråoænè‘qæ‘pèpèsç‰jèuèˆoä‚dâ{jƯreÖjeÆ^a¶Q\¦@Sœ8MŸ9L¤?P©@M®DM²CN±BN¶FP´GR´LT±IW´FP³HT°JT´FO±DN¯JS±DL¶KS¹NR»QW¼UZÁSWÀY_ÅXXÂY\ÈWZÆ^[Ê\\ÊYV̀`]Í`\Ï^`Đ`[Đa_Ñ^\Đa\̉d\ÎdbĐc_Đc]Ïfd̉d`ÑfcĐa^Ïb_Îdảa]Ñb`̉c`Ô`[ÑaaÑdb̉fbÔd_̉d_̉f`̉c_Ôb^̉b^̉daÔc\̉b\Ócả^[ĐbcÓjỉdbÔb^ĐdbÑcbÑabÎaaÎdbÑdaÓgeÏa`Îdf̀beÎ`b̀fb̀gbÍf`̀_]Í_^Đb]Đd]ĐgaÑgfĐig̉jfĐgdÑdcĐfbÎdàfcĐd`Đb_ÎgfÓfb̀`^̀a^Î\[Ía`Îcd̀cbÎdeÍ_Z̀`^̀^bÍ_`̀`\ÎbbĐcaÍad̀abÊ\ZÏ__ÊaaĂ^dÀbgÂ^d¿Z`¾VZ¾TY»S\¶P[³NX³NX®HV­FX³Q^¼[gËfgÓol×xqÛ~uÜ‚uâ…tă‰râŒxăˆväwăoă†oäqă‹räuæˆmåŒmå‹qă…jă„má…jă†oä†ná‚pâ‚hàkà€dá‚jƯlƯ~lÜ~jÚlƯ}jÙ€pØlÙnØ~iØzeØxf߉jđ°øÅúΕûÓ ûÔüÖŸưÖø̀“íµ„Đ…l«NXªISªM\°NVµTZ·V^ºTZ¼X_¾Z\Ä\ZÀ_`¾\`Ä_[À``¾\]À]`¼^`¾bbÀ]^Â__Â^^Äb^Æbd̀^]̀b`ĐfbĐg^̉gd̉iaÄZ[¤>Lu$CZ<V@YBZC^D\?\>`;â‚jà‚oâ‚nâláƒlæ‚jâ…mä„kä…lăƒlà~nâ‚nànà‚ná†oăŒqætæ‘oèŒpæ‘ränæoåpåkæ‰lç‰oç‚dä|f̃qbƠhbÈ^^´V\¤BR=O9N¥=J¨>J®BPµFP²FO³OWµIRµFN´KQ°HP°IQ®CO°DL±KP°EL³EK³FR·OX¼OV¼RU¿QPÄUUĂVVÆWVÆZYË\YÈZẀ\VÈ\\̀\XÍ_^̀a[Í`^Ïa`Ña[Îcb̀`_Đ_]ÎefĐ_[Đc`Ñb`Îdảb`ÍdcĐbZÏabÑc`Ñd\Đa`Ña]̉c`Ôd`Ôc^Đ`ZÑaZÔc`̉`_Đbảbảd_ĐcbĐaaÑeeÔc`̉`]̉`]Ô_\̉ecÓfgÎbbÏa`ÎacÏbbÎb`̀jf̀bbÎe`Îc`̀caÍbbÎ^\Í`Z̀b`Îa]̀caÑed̉ghĐkmÑooÑefÎdeÎb^ÏfdĐb_̀b`ÍbaÑfc̀`Z̀a`̀]_Đb[̀_`Ë`]Î``Đ`\Ê\]̀Z[Ê``Ë`^Î^\Ï`^̀``Í_^̀_\Ï_^Ê^ZÊ^`Â\`À]h¿\dÀelÂV\ºPX¶T\³LZ²JX°NY®FT´OY¸V^̀ecÑok×ztÜznÜsß„pàvâŒyävåvä‰pä†oá‰täxä‰rănäˆrä‰pâˆoäƒlà„nâ‚pâ„oâ„râ€fá‚sà‚j̃ƒpƯ}kÜ~nÜ~lÛjÜ€jÚoÙlØ}oÚ|kØ}lÚ{kÙyeæœtó»‡øÉ’úÏúÓ ûÖ üؤüÓ˜ơÆŒä¦w»jbªLT°R[®NU¸T[µPW¹X^»X\»X\¾Z\¼\`À`aÀZ^½[]¼\_¼`e¼Z^¿^`¾aeÂhjÄabÈabÊb_ÊfeÍedÑhg̉ig̉lfÆ\]£?Nx#D[AR@ZFXFX@\CZB]?aAâƒqà‚lâ~iâ‚lâ„mä‚iäƒnä„mă†râƒlâƒnà„màjâ€iă„mætç‘nå“tçtä‹nålæpäŒpälå†jä‰ræ‚hâ{hÚwhÖheÉ`d´OZ¥@Rœ8N;N¥?O«AK°AL±DN°GP²QX³DM´FO²DN²EL²HN²GN±HN±EL±IP²GN¶HPµLQ¹PT½NQ¿UU¿SVÄZYÂWXÅWVÉZX̀ZVÎ\WÈ\\Ë`\Đ_]Î`[Îc^Ñb[Đ`YÎc_Î`\ÎccÎc_Đc`Î`\Î`bÍb[Đ`^Íb`̉`Z̉c_ĐdbĐb]Îb]̉c]̉dbÓa^ÑcfĐ`]̉c]Ñ`[Îb_Ï^ZÔc^Ñ_ZÑb^̉ecĐ^^Ób^̉d`̉\X̉_[Đb`Ñ^]Í]]Î`\Ïb^̀a^Đ``Đ\[Ïb^Đc]Íb^̀``Ëc`Í^\̀`\Î_YÍbbÑfdÑbbÏedÏfdÎffÍbbĐc`ËbcÍa`Îb`ËdbĐb`Đb]̀e`Ëaàa_Î`[̀dd̀[YÊ\_Ë]\Ë\]Í^Z̀`^̀^Z̀`ZÍ\]Đ^\ÎZ\Ï\ZÏa_Ê`\Ë]]Â\`Â[`À[b¿Y]¾X`¾RV¶QZ°PZ²S\¯JW«JZ®O[¶P[Æ`dĐjiÖxpÚzvÜ€xƯ„tàˆyâ‰văwăxä‡näră‡máˆpá‡sátä‡näˆkâoá‰qàƒgà€mâ‚jâ‚jâ€hàmƯhƯlƯ~jÛ€lÜ|kÛ€jÚ}jÛ~lÛ|iØ{kØ~k×~lØveÔvfÜ„j́¬|ơÉø̀’ù̉›ûÔüƠû×¢ú̉—f֌i³TW¬JS°PU´PZ´RV¹V[»Y\ºVX¼V\¾UXÀ\\À_]¾[^¾\]ÀWZ¾\`ÀZ\ÁadÂbcĂfiÆdhÇdd̀edÎgd̉hiÓldÊ\[ >OnA_IV@XEZA\ LZ?]>\>b<c@â‚hßlànâƒtä†qä…jå…mä„lă‡mălàƒrâ„oà‚qâ†päsçtçvæsæ’oåră‹qåsä‹rá„kåˆlæ‡læ„jă}d̃tcÖh\ÊZZ¸LT¦@N6I5H¥>Mª<I°=J¯BN¯JR¶JR´HP²HR³CO±JR³JP±FL´FK°EL²EM´HN¸LP¹MP¸PU¾LR¾QSĂWXÅZYÆZWÈWUÈZXÈYT̀`\Ë_\Ï_[Đ`^ÍZV̀^\̀c]Ïc_̉`[Îc_Đ^_Đ_ZĐb^̉b_̀]^Î``Đ`^Î`^Ñ_\Ñ`YÎb`̉`ZĐ^YÓd_ÔfdÖe`Ô_\̉a\Ó`Ỷ`ZĐ``Đ`\̉b`ĐfhÑgfÓdảa_̉a\Ó^\Ơ^W̉_ZÑ]X̉ZVĐ^[Ï^[ĐZW̉]WÍ]^̀\^Î^]Î]YÎ^ZÍ`Z̀^[Î^Z̀`]Đ\Ẁ][ĐaaÍ`_Ïb`ÍdiÎdb̉cb̉b`ÎcaÍbaÑc_ÏcbĐd_Ï_\Î`\Î^\Î\ZÎ^ZÎb^Î`XÍ\[Í_\Í\Ỳ\[̀^^Ê_\Î_\Î^[Î\Z̀[\Í\XÎ``Î`_É\[Æ\aÂ^dÂZbÂ_fÀV]ºQ\µNW²N[°NW®JV®L\±T`·YhÆafÎjlÔtrÛ{tÜ~xß…yà‰|â‹vâ‹xâ‰xăŒtäuâ†pá†ràˆrâ‰nâ‡lâˆnáˆkâˆoă…ißjàlà„jájá‚ißoà‚l̃~hÜl̃~mÚ€kÛ}kÜ}jÛlÚ}lÙ|jØ|i×zmÖxkÖydă–q̣º†øÇ’úĐúÔûÖ¢ûØ¡üÖ÷Êç°~Çw`¨JU­KS°OX±TW¶X^¼]]¿ZYÁ\]½Z]Á\ZÄ^ZÀ[]À\Y¿Z]¿ZZ½Y\¼]cÄbfĂ]_ÅcbÉdfĐdh̉if̉jgÈ\_¤<Nr#Gf4XWDV>W=X<Z=X:`;_?f?f@â€fß‚pâ‚oäjä„næ…mæ…iäƒiä…mâ†râ‚nâ„má„nåpærètérç‘sçræoå‰iä‡pâˆnàˆqä‡jæˆpæ‡nă~gàt^Ùg[ÉTQ´FL¨7FŸ8L0G6I¨<L¯BM°DN°HN¶EN´GPµHQ²LV°JT°IT°DN¯FP²FQ´DL¶GN¸KO¸LP¹JN¼QW¿STÁX\ÆYXÄUUÈZ\ÊZVÇ^\̀XYÈabÍ^[Îb_Í^\Ë]à^YÏ^_Đ`ZÍbcÍ^aÏ^ZÎ`^Đ``Î`eÏbcÑb_ÎcbĐaaĐc_Ñ`\̉^XÏ\ZĐaZÏ_`Ó`_Ó`]Ôb^̉^ZÑ]ZÑ`\̉dbÑcdĐdlƠhf̉gf̉eb̉`aƠ^Z̉XXÑYVÑ[WÎZZÏZZÎZWÎ]WÎ\XÎ`\̀`bĐ^[Í`[̀\_Ê\ZÍ_\Ê`]É^]Ê^[ÈbàZXÎ`b̀]^̀bbÏfeÏcdĐcbĐaaÏdb̉ddÎcb̀fc̀_Z̀_]Í^Z̀^\̀^[̀__̀^`Ê][ËabË^_Î]WË_`Î`^Ë^]Î`XÍ\\Î]ZÎb`Í^_É^]È^`Ä]^ÀY`Ă\_Ă^a¾^dÀR\¶MX¸NW´LS±JQ±JY¶P^¹WbĂ[fÑfjÖolÖutÜ€xà†xâ…{â‡zâuâ‰uáwäˆtâ‡sá†mà†qá‡pâ…mà†lá‡hăˆhâ‡k̃ƒlâƒlß„ná‚jâƒk̃„mßj̃€lÜ~lƯmÛmÜl̃hØ€mÛ|jÙ}mÚ~kÖwhÖzlƠvhÜ€dê«zö‹ù͘ú̉™ûƠŸúØ¥üÛ üÔ™̣‰ڜw´\Z¬JP²NT³RW´V[¶ST¾ac¼^cÀ`aÄY^Â]^Â^^¿Z]¿\\¿V\Àab½^cĂ\\Á_bÆbbÎd`̉heĐhhÊ^X¢=MsAYA\FYDS:U7Z<\8_=c9h=j>c9äƒpă„oä„mă„jä„hæ„nå…lå„hå…oă†oä…jă†răˆuçoètç”rç”tä‘ræpåŒsă‡hă‡kâ„oà†qåhænç†låcàsZØgZÊXR·JN§<K6Hœ3H£;I¨CN®?M¯DO²HS±DNµHP³IR²HN²LV²FN¬KV°FN±HP°EP´HM·KT¸KO¸KR½SVÀSRÂTWÆXUÄZ\ÆYXÈYXÈ\[É]ZÊ`ZÊ`Z̀^Ẁ]ZÍ]Z̀a\̀^[Î_[Î_[Î\]̀b]ÍabÎa_Ña`̀chÎ]]ÎbbĐbaĐacÑab̉c]ÎacĐ`]Đ`]̉ddƠ^^Ô`ả\]Đ^^Ï__Ô^ZÔ^^ÑedÓfẻhh̉gảadÑ[\ÎZXÑ\ZÍ[XÊZWËVUÎWRÍZZÎVWÎ]\̀bdÎ^[ÍZYÈ\`Ë\X̀Z[ÊYỲ^\̀^^̀\ZÎa^Đa_̀b`̀^^ÎbdĐ`^ÎbèbfĐb^ĐdcÏhfĐbbÍb^Ê\\Đ_]Ê^\̀_bÍa^Ê`aË`à^[Î\ZÍ_]̀\XÉ]\̀\ZÏ]\ÍZ]ÈZ]Îa`̀^aÎ_\Ë]\Æ\_Ä^bĂU]ÄX^¾V^ÀYb¸OW¹QX¸NVµLU²LX¶Pa½XcÆaiÎfjÔprØwtÚ~w̃ƒyß„và†xăˆ{âtâxâˆtà‰vá‡tá‡o߇tâ‰oà‚mâˆjä†kâ…jă†jâ„iàmâƒmâ‚qá‚nâ€l̃ƒrß‚oƯ‚sÜ„r̃€nÜ~lÜ~nÚ~hÚ~qÙ{h×xkØxi×xdÖvgâlô¸€øÇ‘úÑ›úÔŸúÖ üؤüØ¢øДÉl°IN¬MU²OU´TY½UW¼VX½ZZ¾[^¾^]Â\ZÀ[]¾]]ÂZZ¾[`½]]Á^aÆb`Ä^^Éfd̀fdÏjdÂZ_¢9Kt>W=V:ZCXA[BW;^?^<b=d=g@a>f'Lä„jă…qä„pâ…må†mç„kåˆpä‡iä‡qä†näˆqåŒnåvèrçwé“rè’tèrçrçlä†jâ†nà‚rá†tçˆkènèmè€f̃s^ØgXÊXU¶KP¦=KŸ:N4K¦<Kª@M¯BR°BL²FR¶LV²LVµNV±DN±LU²GM°EP²FO²IR±DP²IQ¶IR·JO¸KQ½NR¾TUÅTVÇWVÂ\_Æ[ZÊ[XÆ\ZÉ\ZËZV̀_[̀\YÍ`^̀_]Ë`_̀`\Î`^̀]ZÎ^^̀\\Ï`\Î_aÍ``ËbfÍadÏ``Î_cÓd_Đ_^Ñb]̉c`Đ`\Î``ÏcbÓ^`̉a^Đ`]̉`_Đ_^Î^^ÏbfÑebĐdẻa`Ñbb̉dcÎ`cÎ_\ÎYV̀ZZËUUÍXV̀ZVÊYẀ\[̀Z\Î\ZÍ`]̀^^̀]`Î\\Î\XÈ]^È[\Î\[Ê]\Ñ[XÏcàdg̀acÎ`^Íb`̀bd̀efÍfh̀a`̀dhÎ^[Ëa`Ç]`̀bbË\[É\_̀b^Ë``Ë_^̀b^Î]\ÎZXÊ^à_^Ê[ZË^^Î]`Í\`ËbaĐ^\Ï``Ë`aÊbdÇX]ÀT_ÁV^ÀV\¼V`¿TYºLWºNX´NZ°KZ´Oaº[jÆclÎilÓkjƠwxÛ|t̃€và„xá‚tâ†sâ‹xá‡wâ†tß…và‚qá‡và„oăˆpă†iâ†gä„hâ„mä„jáƒlà€eánàqá„rá€há~k̃ƒpƯƒr̃„pß‚ñ‚lƯ~lÜ€oÚzlÛjÚyjÖwgÖxjÔtf×|ǵ¥xöÀ‰úÊ”û̉œùƠ¡úÙ§üÙ¤ü×÷Ë’ă§v¹d]®JP²OT´PXºUV¹VV¾XX¾V[Á^`À]`¾Y\¿ZZ¿\^À^]¿`bÅ[]Å``ÈcdËgbÍgcÄZV¢=Ks<X9W@[@\@\BZ=]?^>b=e<e<b:bAcEä‚gä„pä„näiå…lä…hä†jä‡lå‡pä‰væ†pçŒrèsé”té”ré”rè’ræ‘tèpæeä‡fâ‡lâ…pă…iæˆoèˆièˆjåcâv^ÜhV̀[VºHN§<JŸ9J¡9K¦?Q¥?P¬AN°BN²DN³GQ´HS´KT²KT°NV²FO´CL°CL²EP®ENµHO·GP¶JSºNU½PVÂPQÂTUÆUVÆYZÄZ]É\\ÆVVÊ[[É\\Ë_\Í^ZÎb]ÊZ]Đ`\Î^\Ía`Ê_à^ZÊ]`Đ]ZÎ`à`^Î`aÑ`^Đ`aÔ``̉`_ĐaaĐb]Ñbb̉b]ÓbcÏ_`Ï_^ĐaeÓehÑ`^Ñ^]̉_\Ñ``̉``̉cdÏbbÓddÑ\ZÔ\YÓ`_Đ[XÎXVÍZXÉZVÈXYÈVẀ[XÈVD̀[YÍ]ZÉ]^ÊZ[̀^[Í\\̀\X̀ZZÉ\YÆ\YÊ[^Ë_]Íab̀_`Îbè`à]`ËabÍheÎbeÍcbÎ_`Í__Ê^]Í__Ë^^̀aJÎabÍ^`É^^Ëa_Ï^\ÎZX̀`\É`cÊ\`Í]\̀[^̀^]Í[]Í`]Ê``Ç]`É^_É[_ÆW_ÅX_ÄT`¼RX¸QH¶L]¸N[´HX¶JX¶LY¼Y]Ç^bÏel̉jjÔqnÙwsƯ|r̃€r̃ƒvá†xá†wâ‡tâ‰vß„w̃†t߆s߆sá‰rá‰mà…râ‡oá…là„Vâ„oà‚pâƒkà„qăƒoà€jß„ñ‚p߆nà‚n߃T̃ƒr̃€mƯnÛoÛ~qÙ~oØ|nØvmƠrỎqe܃iï®löÄdùÎúÓ‚úØ—úÚüÛ¡üÖ ơƘڳ\~«Nw®Ni´PZ¼VV½WU¼UZ¿XZ¾[YÀ_[Á^[¿^\ÀaaÂ^^Â_`Èd`ÇgeÍg]Â[]¨CUw#R[NXNTG_DZ2]B\:`Hb?eBe;b<`<d@d >ä‡sâ…lá…nâƒkä…mä‰länæˆpå‡rätåŒrèqè’uêré’qèrêoèpèkå‡jä†mă†mâ„lă†lèˆiæ‹lè†gä~eàr[ØfVÉVP´HM¨>K6L;M¥;K¨BP®BR°@M´IR´GP´HP²HQ²JQ¯FM²FN°IS²EK°CM²BM´CMµEO¸LTºOW½OUÂRRÄSVÄSUÆXXÉWTË[ZÈZVÈ]YÆ\\Ê[Z̀\YÍ`]Đ__Í^]Đ][̉`]Ï_]Í_XÏ`^ĐZZÑ]\ÎYZÎ^`Óa_ÎceƠb^̉^`Ñ^\̉ZX̉``ÎbdÏ`bÎa`Ñ`^Î^eĐ`eĐ``Đ^^Đ`_Đ^]Đ`aƠcgÓdả``Ñ^`Î][Ñ[XÏZYÏWUÍXYÉ[\ÈXZÆX[ÊXVÊX[ËZ[È\^Ê^^̀b`ÈXVÄ[ZÉWẀYWÉYXÈ]\Ê[XÎ_^̀abÊafË_aÍef̀bcËbfÍejËgfÊfj̀aaÎ^\ËbdÍ`_̀`aËbaÏa_Ë\`Đ][Î^^É]\Í]ZË]`Î]\̀]\Ê\XÍ[]Î`]Í]]Î^]Ê_`Æ`dË]^Æ[_ÉW^ÅW^ÁRY¿T^µP[·P[¹RZ´JX¹LYºQ^½VaÈYcÏbfƠhkƠqnÙwqƯ}tÜ}tßuà‚t̃†vá…tâˆũ„vá„qà†oß„ná†kà†mà„náƒnáƒnà‚iá†mƯ…pà€ná„pà„pá†lßoàn߃m̃€pàƒmà‚rßpÜ~oÚpƯ~pÜ~pØxjØzjƠtcÔtcÖveçsô¿úË—ù̉ úרúÚ«ûÛ¦ưÚ¥úΘ賆ÂvfªLU«JS±NX¶PW»QTºVY¿VX¾\]À^^ÄZX¿[\Â^aÄdhÇbbÍdbÏhgÅ]\¤?Pu>Z9W;V=Z=Z@a"LaBfFdCf;iAd<b@d@f>e<ä„wä†mä„oăˆlâ‹värå‰nä‰næ‹yæpæsè’tè’oêrépê‘péjènçfç†jäiâ…mâ†nă†kå†jç‡lè†læ|ẽp[ÙdT̀[R¶HP¤<H5H4I¢9Hª@P®@O±CN¯DQ´FN°DO®FL°FN­HP®HN°EQ®EQ°CO²JU²IS·FP·LTºNTºQX¼PU¿X[ÂRVÇY[ÆVTÄVXÇXXÈ^YÅZ\ÉVXË^X̀_`Î^YÎ][Ï\ZÎcdÎ_\Ñ\WĐ\ZÏYỲ^^ÉX\Í^\Đ\\Î``Ñ\]Đ[ZÔ`_Ñ\VĐ^\̀\_Ê^bÎ`_Đ_aĐckÏgk̉bdÑ`^̉`]Đ^^̉\\Ñ_^̉`^̉^]Ï]^ÍZ\Ñ\ZÑ[[ÍZXÎ[WÎ[WËYVÇYZÉ^`ËXTÊ_aÊ]X̀]X̀]VÆXTÈXUÂ\XĂXZÉVWÈ]ZÈZZÊ]]̀`b̀`cÎab̀`aÍdc̀aeËfj̀ccÊej̀abÍ``Ê]`Ê^`Í^^Ï`_Ï`^Ë`^Í]^̀^`̀][ĐZX̀ZXËZZĐ^_Ï_aĐ[XÎ][Í\ZĐ\\Ê]_Î_cËXZÉWZËY]ÄV\ĂQZÂY`¼T]¹T\ºPV¸JT´JZ¶M[¾UcÆ[f̀blÓklÔmpÔtrÙzqÛ~ũ€uß‚tÜ€t߃sá„tà„t̃†r̃m̃…oá„là‡rá†lß‚p߃oàoá‡q߃l̃€oá…ráƒnâ‚làƒoàkàƒoß‚j̃€p̃p߃qß~lÚ{pÛ{nÜ{oØzlÙ{kÖviƠtfÖrcƯfî­~øÆùĐ˜ùÖ¤úئùÚ©üÛ«üÖ£öÅÜy·^Y¨DO¯FQ´OT¸RX½SX½TYÀZ\À^^Â]_ÂbbÂ_c̀ecÊfdÏfeÀVWœ:Js?X:W>V<Y>YC^D`FdDdCe>d@d?^>d=cAa<^;äˆvăˆnäˆoă‡gä‡råˆjå‡qåpæŒsæuê‘rêrèoêséoéjèŒfè‹kè‰eæ‡nâ„kä„jă‰rä‡oçˆlç‰næ„gä}gƯq]Öi]ÊXQ¶FK£6F0C›3G 8J§?N©BN°CP²DJµGM±KT°CK¯GN°FN°DL®GP°HN¯HQ²GP®BNµEPµKR¸NS¼QTÀSUÂSUĂSXÅZ\ÄVXÄVXĂVYÅW]Ç^^È]YÈ\]É\\Ë_ZÈ[WË]\Ï_]Ê^^Î\YÈ\Z̀VV̀]]É`cÎ`^Đ^_Ï`_ÑabÑ^^ĐabĐ^ZËZYÍ`^Î`b̀_aÑ^]̉`cĐ`b̉_aÏ`cĐ`^Ï\\Ó^\ĐbcÏ\[̉]]Ô\[̉Z[̉[YÏZZ̀ZZÍ\]ÈYZ̀TT̀\^ÊXYËVVÊXXÊ[XËZZÇTSÉVTÉTXÆVVÅTWÂZ[ÅY[È\^Ê\ZÊ\\̀`bË]`Ë_dÈbhÊbeÎehÎacËabĐ``Ë^^Ê^^̀^_Ë^`Ï^aÑ``Ï`^ÏZ\Î^à`_Í\ZÊ]_Ë^\Ê[^̀Z\Đ]XÍ_`Î[XÏ[\Î]\̀]b̀Y^ÉZcÇV\ÄUXÀV_¼Wa¿Wd¸U`¹NVµJX¶HY¹KY¾R`Å]f̀ch̉hk×pnÔwsØzsÚzqÜ~oƯ€uÜ€uƯ„tà„vß…x̃†sß‚o܆tàƒjà‚oáƒhàƒpà‚pß‚láƒmá‚oà~jà~kâ‚jă†rá„oà„là€õƒsà€nßñ~m̃~lÚzkÛzjÜzlÙyiÚwf×ufÖqbƠpaƠrbæ–pô¼„øË”úÔùÙªúÚªüÛ¬üÜ©û̉™ñ¾ƒÎƒhªJR¦DO¯OX³PV·PT»RYÀUZºW`¾Y[À_dĂacÈdf̀he¾W[>Nn@Y<X@U>Y?V=\Cb"Od'Pe#Kj%Ld$GdDb>d@b>_?^<`Cåwâpånä†päˆjæ‹päˆqæŒvètè’uè“véoèpé‰oèˆièŒkçŒfçˆkçˆjæ†lä†næ†må‡qçˆjéˆhè‰lç‚gä}fàp[ÖbVÈUP¸AJ¦:I™0Fœ2G£<N¦:K«BP±HR²JT²FP±AP³BL´EP°EP®DN¯EQ²EO°DN¯EN°GPµEMºFN¼NT¾PTÂQSÄVWÁX\ĂVVÅZ\ÄYXÆ\YÁ\^ÄWZÉ][ÉVTÆYZÎ]ZÍ]YÈ]^È\`È^`̀[ZËZZÎZWÍZ^ÏYZÍ[]Ñ^`Đ\ZÔ^`Ñ^^Ñ_ả^ZĐ\ZĐbaÎ`bĐ^]Îa_Đ\]Đ`dĐ\^Đa`Ñ^\Đ\`Ñ^aÔ^^Ñ^ả\^Ó^bĐ\\Đ\\Đ^^Đ[[Í]aÊ\[̀XYÎ[WÏZÙYTÈTPÇTTÆWVÈWSÆWYÅYUÆVVÉVQĂXZÄVVÈXXÉWWË^\É``Ê]aËabÊefÍaf̀bdÊbf̀_^Ë]`Í_eÎ^]̀Z[È^cË^`Î_`Í_^Î^`Î][̀YXÎ^`Î_`̀^^Ë^bË^ZÎ]X̀\ZÍ][̉^^Î]\Ê\^È[`ÈY_ÇUZÂTZ½R[¿S\¾S\¼R\¼PZ»OZ¹L\»NYÄT_ÆZdÎbdĐflƠopƠrnÙwsÚwoÚ|tƯvƯ€uÜx̃‚vƯ‚t̃†sß…s̃‚oà…káƒlß‚oá€ĩ‚tà€ià‚làjà}iß~i߀lá‚pá…nâ‚rál߀jàl̃~mÜ}nƯ~jÛzjÛziÛ{iÚvjÚubØtbÖtbƠp_Ön_Üdî­y÷ÈùÑ—øÖ¥ùÚªûÛ©û̃ªüפøÈå©z¾f[§EP®LR¯OX·MS¸QYºRZ¶T\¼Z_À\`ÅddÊd_Ă\\¥?Lt?Z=V=X@X>\>Z@^@d@fAdAa>b<`@`<a:_>_9Z>\>å†mäˆpå‰oæˆpä†käˆpäˆpçsé’yè”réxçˆjç‡lç†hèƒfè†cç„få‚eç‡jèˆnå‡räƒhæ‡oæ†oè†jçˆkç†låzfÜp\ØgXÇYU´EM¤7Kœ1H4I£:N¥<O«DT®DO²EP²DJ±HS¶HO±HS¯GO´LR°AL±JP®DO¯DM²IO¶FJ¹IP¼MR¼NQ¼RXÄUXÈXTÇYWÆTTÆTTÅZ_Æ\[Æ\[̀]Z̀YXÉXX̀ZYÎZZ̀\bÎ`_ÉYZÍZZÍ\\ĐYX̉_^Ñ^bÎ`aÑ^bĐ^b̉][Î\_Ñ\YĐ\bÎZỶ`^Ó[ZĐ`]Ñ_`Đ^^Đ_b̉`^̉``̉]^Ñ^]Đ__Ñ``Đ]\Ï\^̉^^ĐZZÑ\ZÔcả^\ÓZXĐ[WĐZXÏ[UÊWV̀ZV̀XTĂXVÈURÆXUÄUVÄWTĂSRÅXRÂTR¾XWÆVUÈVWÉ\[Ç\]Ë^_Ê\`Í_bË_dÈadÎbeÍ^aÍ\^É\aË_`Ë^_Ê`èZ\Î`gÍbdÍehÎ[^Î\_ÏbfÍ^b̀][Ê_bÍ\XĐ\YÎZZÏ]YĐ^]Ë_aÉYZÄY[ÈZ\ÈXZÄRWÂX]¾RV½S]ºQ\¸R]¶NY¶KX¸MZ¿R]ÄXdÎ\`Ñjj̉lj×qnÖtrØxpÙypÜzpÛ~sÜ€w̃~pÜ„w߃tà…tßjß‚lá€jànàƒnƯ€r̃‚lÜ€qß~gá€kà‚lß~lâ€nà~jâ‚nâ€qßmà~l̃|j̃zfÛwfÛxkØvfÚtgØvjÙtbØsbÔqdÖq^×o\Ös_ä“ọº‡ù̀”ùƠ¢øئúÚ¬úÛ§üܧüÔ›đ¾…Ñl®MRªGP®LU±MV±OV´RY¸SYºZ]À]bÉheÁYY¤>Hw"A^>V<V=X>Y>]A_BaHg"If&KdCb@_DaD`B]?^<^:]>\;ä‰pä…käläˆlăˆläˆrä‹qè’uê–ué’vèmæ„hæ€eæ‚gæ€hæ‚bå€eä‚iç†gè‹dç‡må‡hă…nä†lænçˆlè…nå|f̃ub×bWÉVS±DM£=L˜/E3F£=M§=N®AM­CP°DQ´EN´EO±GR²EQ²BN²HR²HO°FL®FP±FO²FPµHPºLR»IR¾PTÁU\ÅRVÆVVÆVXÈVXÆXYË\ZÈ^[ÈZYÊ\YÊ][̀[ZÎ\X̀\YÊ^`ËZYË\[ÎZ[Ê\^Î^\Ï^bÑ]]Đ`bÑblĐ[^̉^^Î\_Ë[]ÍZXÎ_bĐc`Ô^^Đ`_Ó^_Ñbc̉\_̉abÑ[ZÓ^`ĐZ_̉[YĐbbÑbb̉ZZ̉^ZĐXYÏZỶ[\̉_\Î[\ÎZ^ÎX[ËZ^ÈXcÆdqÄhrȇÇuzņ‘Ày~Àv~¾jp¾kr¼[`½X^ÁWVÅWVÆXWÉ[XĂXZÈWZÇ^^Ç\_ÇZ_Ë[_ÈX\Í^aÍ^^É^`Ï^`̀^cÍ]`Đ^àaeÎbcÍ`dÎ\\Ñ]]Ï]^Í\`̀`cÎb^Ñ[UĐ^Z̀]ZÎ]`Î]^Ç\^ÊZ^É]\ÈY_ĂS\¾T^½Q\»R\¸VaºPX¶JT·JZºLY¼P\ÅT`Ê^cĐhgÔlkƠnfÖvqÙtiØwpÚzrÚ}sÚ|vƯ|nƯ€ũ‚t̃‚r̃ƒqßõ€l߀mà€mÜq̃lß‚pßjá€jâ‚kâ€iâià~hàoáià}hßzlƯzgÜzjÚwjƠuj×qdØwhØqeÚrcØtbÖrcØsbØp_ÖrdÜ{d́©xöÅŒùΘùÖ¤úÚ¨úÚ©ûܪưÙ£÷̀æ­}ÀhZ¨FR­JT°KS²PX¸U\¹RZ¼^bÁb`¼X\£@Nv@[>X?W=X@X>\A_AdCa FeFg"IgFaEa@dAb>^9^<`;_>]<æ‹xä‰qåså†nä…låtçŒnê’úréˆhæ†hå€hä|cæ}cäz_ăz[ç|bä€cçˆlèjçŒpç‰lä†qå‹uèˆlé‰pêƒbå~lát_Ùj^È\[²GS¥;K™3Jœ2H <R¦=N­>O®CL²FQµFN³HSµKT´LU°GN²FR²GQ²FM¯EN°FP³HN¹GN¸PW¹NU¾RY¾QYÄUT̀XUÅWXÈZYËVXËZXÉZVËYUÍ[ZÊ[YË\ZĐ]\Í[\̀\`̀^cË[\ÑZXÎ]aÏ^]̉a\Đ\\Ñ[^Đ`b̉^bÔ`b̉]]ÎZ]Đ\]Ï\^̉lj̉_aĐ``̉bb̉dmÏ]`Ô\`Đ]_̉YYÑ_`Ñ[[Ó^\̉hfÍ_ẻY\Ï\`̀Z\ÎbnÈ_fÍz‚ÈpuÅuÂs{¿x…Å„‰ÊÏ”‰Î Ôœ•Î¡¡Đ’Ѩ£Ô¤”ͤ¢É œÀ€†Áu}¾[]ÁVYÂRTÅTTÂVVÁVZÆXZÈ\àZZ̀Z_ÍZ]Í\^ÎY]Ê_bË]aÏbfÎbfÎ`hÎacÍ_dÍ_cÉY_Í[]Ë]aË\\ÑZZĐYZ̀__Î\^Í[Z̀Z]̀Y_ÇYYÅV\ÂT_ÀR[¼Q\½S[ºR^¼LV¹KT¸HT¹NY¸UaÆU_̀`ẻgdƠklÔqnÖsmƠup×toÚulÙxrÚ{uÛzrÛxƯ€t̃€oƯƒrßl̃‚p̃~j̃~mÜnƯ}õ€l̃€náiâgâ€lâ€ià|hà~ià|iß|h̃yh̃vfÚxfÚvhØwlØvdØvjØrc×tg×udƠpaƠvdÖsdƠqaØqbăpó¶øÈ’ùÓœúצúÛªûܪưÛ©üÔœóĈזt°RW­W_®OX³SZ¹U]¼Y^¼_a¼VV˜8Jq B\:V?ZBZAY<Z@]@^BbDgGh"Fe#IcDfAcE`=]<]>]=\<^?\<æuäˆnå‰kæˆlä…nèmè’yê”sê–pé‰læ‚eå}eäw]âw^âu\ßxdâw]âjènæ‰hæˆnå‡mä†pä†réŒrçpé„hæ}dàs_Üe\Í]Z¶HO¦<Mœ6Lœ2J 9K¨<L¬=O°@L°BQ²FR²FUµFQ±JX®FP³EM´HO´FM³CN²DL´FL¿FL¹PS¿PVÀNQÂLPÄQVÈUSÇYYÇVWÇYXÊYZ̀\[̀ZYÊ^[̀[V̀\YÏ^Z̀]^̀^^Đ\^Î^]ĐZZ̉\\Ñ^\Ó\\Đ^`Ñcd̉\aÏ]^Đ^_Ï[_Đ^`Ó]_Ï^^Ë]_Đ]\ĐabĐb`̉`b̉\^̉^\̉^]Ơ_[̉X[̉ZZĐ]^Î\bĐirÍivÇr€Æq}Æ~‰Â}Ă}‚¾|ˆÀ~ȉŒÊ––Í’ˆÏ”ϥΡ›Î£›ÎŸœÓ­Ñ¥˜Ö´¦Ù¨˜Ö°§Ú³¢Ó¤Ê§¥È˜™Àv|¿`h¿WZ¾UX¾VY¿X^ÄV]Ê\_ÈZ`ÈZZÊ\^È]_Ê`dÉehÈdlÉag̀dìcd̀`b̀\^ÏaeÏZXÍ^^Đ]^Ï[^Î`_É[^Í\^Î^`̀Z\ÇY^ÉUVĂX^ÁV\ÁNV¼OZ½NZ¼P[¶LX·IV·LX¸P]ÂX`̀\cĐed×kjÖqjØsnÖqmƠtlÖxpØtl×{xÛzrÜ~pÜ~ṽ€p̃p̃qàqÜ{m̃~ñ~ná~kà}m̃jà€lâjägâ€gß{eá|hßzj̃}fƯzhƯxdØwfÙtfÖvj×tdØvh×rb×paÙr`ÖscÖrbÖsdƠobÖubÚxeë¡wöÀŒø͘úÔ¤úبûÚ¨üÜ©ưÚ§üÏ—́´Êxa¯NU«KT¶UZ¹U\Â_\¼TVŸ@Nq@X :V<V>X:W>Z:`@`Ae!Ga@f$Id$Jb"Gd"FbE^>[:Z:\;a<^;`<`=æˆqæˆræ…nä†näˆtçq́”ś”uë‘qè†häbăt]ßt\̃p^ßn\ßqcáv`ä‚jç‹oèmå‹næ‰lçˆqæˆqèlè‹nê„iæh̃scÜgXÎZV´FL£:G™2Hœ6F£9I¨:G«>N¯?L°BR·FP²ER±IQ²DN¯DM¯EN³GP´HP¶HO´EN¸FK¾JO¾MNÁNVÁOTÂQVÇTVÈY]ÈWVÊXZÊVR̀WT̀\ỲZTÎ`_ÍZT̀\XÍ\YÊ[ZÊ_\̀\ZÎ[\Đ\[ÑegĐ`bÑ_`̉__̉^`Ô^bÔ^^Ôac̉\\̉]aÑY^Î]`Đ^]̉_`Ôa\Óf_Ô]\Ô\\Ó^\Ô\YÑZXÏZ\̀[f̀ivÄw†Ç{„É‚ˆÇ}€Æƒ‡Çƒ†ÀƒÂ‹ʓ̉ —ÍŒ̀˜”͘‘ϘƠ¦Ô­¨Ñ¨›Í£̉¦›̉©ŸĐ§–Ѧ”̉£˜Ö¯¢Û¶§Ú´£Ø³£Ï¥Ä”—¼pz¼]f»U[¼NWÄWYÇUXÈZ[ÆY[ÆX^È^b̀`dÈdjËah̀_eĐ^bÎ`c̀\_Ï^^ÍZ^ÎZYÎ\_Í\ZÏ\[Ñ[^Ë\^ÎXYËVWÅT_ÆVZÅS[¾W`½SX¾MW¼OZ¼MWµLY°J\·KV¸P\ÄV\Í_f̉faÓmlÔrlÙtjØsjÖsj×umƠuqÙvlÜzmÚzrÜ{ñ€sÜñ€q߀nÜ~nà€l߀p߀màk̃|hà~oâ|gâ~gá€iàzfß|hàzhƯvf̃ubÜwgÚudØrd×qg×sb×pfÖpfÖpaØpb×p^ÖpfÖn^Ön_×pbÖveß„nđ°‚øÆ‘úĐøÖ§úÚªüÜ­üàª₫ئøÉâ¡v¾c[²PXºX\¿]]ºXXœ=Lq>[;S:U<Y=Z<Z>Z?^?bDcCcBfCdBdEbA`EZ>X9Z:^8a8]7_=^;æ‡tæ„læ‡kçˆræmëṕ’pê’lêmçhäx`àr\ƯlWÜiZÜm]ƯkYàw^ä‚gèlèŒhæoæ‡på‰lèoésé‰iê†hå|dár\ÚfWÏWR¸EM¦8G2E˜3F 6K§<L©8L²BO°DN³GT´FQ±FL±IR­DR²KO³DM¶CLµGQ´GP·JP¾HN¼HPÁMTĂPRÅRVÉTSËVVÍXWÍZVÆUVÊWTÍZXĐZX̉]YĐ]ZÏ\VĐYV̀YUÎZZÎ\]Î^\Đ_^̉_\Đ]]Ô`]̉ZZÑ`aÖ__Ô^^Ơ_\̉`_Đ^aĐ]^Ñ^^Ï\[Đ]^̉[ZÓ^XÓ]YÑ\`̉Z\Đ[]Đ[àfrÆt‚Ăv€Æ~‚Æ}€Ê†Ăz‚¾s|Â|‚ÄzĂ|ƒỂ–Ὶ›‘Θ’Ηϣ ÔªƠ§›Ô§˜Đ¥œÑ¬Í‘Ê”̀Ÿ–ĐªŸƠ¨”Ó©Ö³¢×­œƯº©̃¸¥Ø³¢Đ¥˜Â„ºdoºPWÀRXÂSZĂY_ÆX^È[^É\aÈ`dÉ\à[`Ï]`Đ^`Ê\eÊ]cË]`É[]Î^_̀W[ÎYYËZ^Î^^ÇX`ÆT[ÄVaÉUWÂSX¾T`ÀRX¾OX¸P^·QZ´JX²IV»IV¼MZ¿X`ÎbcÔgeÖnjØoiØxuØsnƠtqƠroØupÚwoÚwrÚxqÛ|wÜzsƯ‚r̃}q̃~ñqß{l̃{g̃|là~jß{lß{ià|h̃zhá|h̃xjƯzf̃sdƯweƯscÜreÚtdØpeÖn`ØqeÖo`Öod×ocØp^ÔrdÔsc×scØn\ƠpcÔqdÖudç–qô»†úË’ùÓ¢úاûܬûß®₫à®₫ÖóÂÖrºYZ¾YZ½XY£GQuA\<R=U >X>V>X=[>Z>`@dDfDbCb>d@`>`@\@\@[>^<`9b:\8Z9]8è„hæˆoç†iêŒsèŕó’rênè‡håeàsX̃lYÛ`RÚ^RÚeZÛl]äu^ä…gèjê‹iç‹mènè‰pé‰ĺkèpê†eæ€jărZÜjZÎVP¶FL¤6F—.C6I£5J§:K¨<L°?J¬AP±CPµFN²AM±BP¯FL±FN¯FP³EM¹IQ³CL¶EPºJN¼MT¿RZÄVZĂRUÊTẀVT̀SUÍWVÉZX̀YYÍYXĐZ]Đ[\Đ\YÎ^ZÑZWÎZXÎZ[̉^ZÏbaÑa`Đ`]Ñ\\Ñ\\Ñ\b̉]\Ö^`ÔYYÔ\\ÑXYÓ^ZÏUVÑ\\Đ^^Đ^]Ñ^\Ô\\ĐY]Î[cÊanÉ_pÀfxÆy‚È}†¾qÀz„ƆɄÀz„½u~¾tyÇ‚…Æ‚ƒÈ‚„̀ŒŒĐ“ÉŒ†̀””Đ˜ŒĐœ™Ô¢•Đ£Ñ®¦Đ¦ Î¤ŸÎ¡̀¢Đ ’Đ£™Ô° ̉¦“Ó¬ŸÖ±Ú³¤Ù°¤Ư¼ªß· à¸¢̉ª¢Á|‚ºU^¿PVĂUZÂUZÈRWÅ\_Æ\bÈ^h̀ZbÍ^d̀\bËbjÊ[^Ë\cÈZ\Í^b̀[aÆY`ÊZ\ÊW[ÉY`ÉSYÅX]ÅTYÀR^¿PX½R]ºO[¹QXºPX³JX¯IY·P\»NZÂZ`Ï``̉hfÙlgÚshÛshÚtk×rlØsnØsnÚvnÜvnÙxtÚzsÛ~xÜ~ũ~s̃q߀nà|lÛyl̃{nß}mÛ{lÜzfÜvfƯvfƯzf̃vdàxc̃ubÜtcÜrbÜp`ÜvhÚsd×ndÖnbÙod×lbØn`ÖocÔse×od×pd×o`ÖnbÔrcÓkbØv`íªzøÄŒúĐ˜ùبûÛ«ûܯ₫à¯₫̃¬ử˜î·ˆÉuf¼\Z§DOz"D\@T?T>XAXD\D`@`DbCcFdEd Eb@b>d@^>W?X>\FbHb=`:_?^9\9`<é„mæ…lçˆpêŒqë“pí–q́‘lêhè€eäxZÜmUØcSÖXOÔ[RƠ`YÛo`â{bæƒfê‹léjèkê‹nç‹lêuëpëŒpé‡læ‚iâubÚfXÍZTµBI 6J–-F–.D¡4E£5Hª;H°?K¬>M®@L¯AM±DO²@L²DL²FO±ER°BN´FP´IRµIQ¸FO¼IS½MTÂTZÅOQÈTVÊSRËUVÈWVËYVÎUTÎ\\̀XZ̉\]ĐWWÎZXÑYUÏ[YÎZYÍ`^ÎYZ̉[Z̉ZZ̉^^ÑZ\Ï_`̉]\̉`cÏ\^Ó\[ÑXZĐYXĐXZÎ]]Ï^`ÊbnÍeoÍp̀pyÅjw¾`k¶dvĂtxË€Äv~¾zƒÅx~Å|~Év{ÇzxÆzzÅ‚È‚Æx~Ç‚‡É…Ȇ…ƖʇƒÎ’ŒÍ“̀•‘Ó ̉¤ŸÔ¨ Ñ¢™̉¦–Ï¢̉©™Ởª¡Ô¯×§–Ó« ÚµƯ´¤Ø´¥Ûº®âÀªá»¦̃¶¦̀œ¹jr¼PYÀPU¾T\ÀX`Æ]gÉ[bÆ`iÉ`hÇ^f̀\bÈZ_ÉZb̀\`Ï\^ÈY`ÈZ^̀VZÊX^ÆXZÆUXÂS[ÂRW¾NV½QZ½R\¼NU»R]¸JS´O[³HV·Q^»NVÆY_Đ^_Ôji×poÚndÚshÜvmÙukÙriØtmÙuoÛwoÚyqÙwqØ}xÙ{vÜ|uƯ|m̃|q̃}iÛylƯvj̃zgÜxhÜweÜvcÜubƯxcÛwfÜt`ÜthÛraÜrbÚtcÜp`ÙpeÙqcØk`ÖndØm`ÚkXØpbÖo]ÙpbÚp`Øo^Øo^ÖpbƠl^Ôl`á‰fó¶„ú̀•ùÖ®üÚ®ûܬưß®ÿà­ÿƯ©ǜ“áy²MR~#CX<W@S>U=W;Z?Z@_CdBgCe?cEcAb@cAaBZ@Z?`F`B`B]:\>Z9Z;_<`:æˆoçmèṕoí–ź“mê‹mèƒlæzbàrXÚdTĐVKÍSOÎRN×dZƯvhâ~lä†gèŒĺŒléiêlè‹lélêŒnéné„hè}`ăvdÜh[̀VPµCL¡4F—*B”/Fœ2EŸAX¨>M®@O©>M­>L°AN°BK°FS±@I¯CM²DL±?L³@JµJS´JPºFO¹JR¼OT¿NSÄQRĂTWÆTTÇTT̀VTÉXXÉX\ÊVWÊZ\ËZXÅZ\̀XUÊW\ÇXTÍ]X̀]^̀\YÑ^\Î^^ĐZ\Ñ\_Ñ]^̉]^̉[ZÑZZ̉X]ÍU]̀alÉZkÍkxÎ~ŒÍ~ˆË~„¾rz¾fm¸Xe¼Ydºix¼hrÄnsÀpxÄrvÄx|ÅrwÈqwÅvzÈ‚ƒÊ}€É„‚ÉxzȂʆ†ÈŒÇˆÊ”Θ–̀™‘Ï”‘Í–̉¤—̉œÏ—ѨœÖ§”Ïœ̉¬œÙ¨–Ó«¢Ú¸§Ø®Ö²¦Üº¦Ư¶Ü¶¢Ü¼®̃¼­à¼¦à¹¥Öµ¨¾~ˆ·T_¹NV¿V_½[dĂV_ÄY`Å^eÉ\dÇV\ÇV[ÆXcÉ[`ÉY^ÇX]ÍZ\̀X\ÇW\ĂTZÀRX¿R\ÅQWÁNW¾MXÀOUºLV¶MYµGT²FT²IW¸MZ½OVÅR\Î]`ÓfdÖmlØrkÜvnÚulØulØtjØsmÚsmƯtpÙvpØzw×wuÙxsƯ|p̃}rƯ}nß|ñzhƯugƯwfÛtbƯxhÜxfÚsbÜr_ÜveÜtẽudÛucÚqdÛp^ÙrfÚpcØpbØpeØn`ØpfÖl\Ùm`Øl^Öl`ÚoaØo^Ùo`ƠsbÔmaÔl\Ùq\́ŸsùÄúÏŸûתûÜ­ữ±ÿß®ÿà¬ÿÚ ñ¼ˆ©HP\>RAV@U?XAZAZ?X>bAeDf>d@bBd@eBdD_C^D[@^>aD`>]=\A]?\:_:b9æ‡rèmë’x́”ní•vípê†jæ€făzf̃iZĐXPÆJJ¾EJÇOLØ`X̃rbă|dæ†iêmê‘pêŒḱoèmémëˆkíŒjê†jèƒgät[̃k\Đ[PµDM¡6H–3G“.G˜5M;N 7J¦=L¨CSªFP­GT¬AL¬AK±AJ®DM­AL²DK±EM´FQ³IS³HR¸KSÁJUÀMSÂLQÆTZÅSTÇUUÆRUÆXZÈZ\̀UTÉW[ËTXÎWÙ\_ÎYWÊZZ̀VUÍ\[Î[^ÏZX̉]`ĐZ[̉]^Đ^\Î[^ĐUX̉X\ÑTZƠelß›Đy€Ñ„Ê}|Ăv{¾ow¾biÀbiÂ\c¾\i¹_n¸dlÀlwÀlvÀnsºfm¿kp¾jrËzxÇqwÅutÈ„È|{Ê…ˆË€~È„…ˆ‚Í“”̉…Ï’’Íћʔ̀˜—̉¢‘Ô¤—̉«¡Ơ£‘Ó×´¥Ü®—Ö¬™Ø¸¨Ü±–Ü°ŸÚ·¨ßº¢âº¡Ư´¦Û»°ßÀ«ä¾¦ƯºªÇµguµR_¸Xc¼PXÂS[ÂR\ÀWZÂX_ÉYZÂV^ÅX^ÆX^ÇV\ÆV]ÆX^ÆX]ÄV]ÂT[ÂPTÁPXÂPVÀQWºNX´L\·LW³KU²DR°EQ´KX¼OXÉRWÎ`hÖedØpiÚriÜtnÜvnÚul×tiÙrjÚqjÚwjÜwmÛvnØsmÚvrÜ}qÜ|r̃zk̃|nß~r̃zlÜtdÚqcÛtdÜqeÚpbÜrbƯr`ÜueƯtcÚvgÜqbÜr`ÜpbÙqeÙpb×pgÙo`Øl`ØpaÚp_Ûn_Øo_×pfÙrcÛo`Ørd×o_Ơm^Ơk^à}ḍ±‚ûÅ‘ú̉ üبưƯ°₫á³ÿä³ÿ̃£̣¾€‘.CM 8P>R=W?V@\@Z=\>dBhCc@bBbBdE`=]?Z=\B_@g#I_@^BW<^B`?_6d=f:çrèrë“pí˜v́’qêjç‚håx`ßp]Ơ^OÄKM°@J´@JÈUPÖdX̃ugä~fæ†dêt́lëmêjêmêĺŒmê‹oë†iè~hăvaƯf[ÎXS¶FO 6J”,D0F™2J›8LŸ6H£:L§=L¬=N©@Nª@Nª?K­AN¬AM¬BI²FM²CL°CL³FO¶EL¸JQ¹LV¼NXÁPVÄQVÄTVÄPRÅTYÆWYĂZ^ÆXZÅTSÍXXÊVÙZZÏXVÉYZÎZVĐXXÎ[\Ñ[YĐZYĐZ\ĐXZĐXXÎY\ĐXXÎw‚Ïb`Í`dÇaeÈmqÆllÀgj½cj»^jÀbh½\g¼[j¼\h´`r¿gnÁnzÂlp¾nvºfr¹erÂhpÅw¼htÅrxÆy|Ê~}ʈˆÈ„ň̀Đ–Í†Í‡Đ˜É“Í ›Đœ—Ц Ö¬Ñ–̉²¤×²£Ơ¬œÖ± Û¯”Ö¥–ײ¢Ư¸Ú®™×±¥Ü¼­̃¹£Ư¸ª̃¼°àÁ±âÁª̃º¥Ơ°¨½‚ˆ¯Xf¶NZ»NXÀPXÀV]ÄT\ĂSZÄT[Å[`ÆV]ÇW[ÆUXÇU_ÆWYÂV[ÀUZ¿TZĂOW¾MS¾PZ¶KW³JY´LW²FS²GU²@J·KW¾KUÇT^Ö^`ÖhfÜlbÜqh̃wjßvnÛtmÚthÙslÚsjÜtnØwrÚvoÚwrÚunÛvnÛ{uƯxkàyl̃}oß}qÜwhÚuiÛrbÚn`ÚnbƯraƯsbÜsbÛvfÚtcÜqaÛsgÚp`ÚrbÚufÚpeÙpcØodÙpbØpbØo^Úp_ØsbÚqaØthØqfÙl_×oaƠpfØsfè–sø¼ưĐüت₫̃°₫â¶ÿâ¬ưÔÑ|_Z8P>Q=T>W>Z?\@_?bBfBeDdAdCeA`<[<Y>Z>`@d!Db?]<\=X;\9`;b:hAf=émê”ví›sî—rëvê„då€dăw^ÚiX̀QK¶BF¤3C²9EÈRNƠbVƯsbä€fç‡h́nêhêmèléjëŒníŒńmênè}hăv\ƯfZÏWO¶CI4G+B-C–2F›0E¢4G¤:I¦?N¦?L¦@O¨=J¬CN¬AK¯DJ®CM­BL¯FS±FT·FN´HSµHN¸MV»FK»OVÁRYÇQRÄTWÄS[ĂVYÉSRÈUVÇRUÊZ[ÊWZÇ[]ÈZ\ËXWÊW[Í^_ËZ\ÑZZÎWYÎ[^ÏWUĐXYÎV\Ög_́rÊNMÀV[¾_d¿\d¼_c»`e¼X]»]g¼\e¹\f¾`n½^cºbl¾ms¼nvÁlp»ip¸doºhpÄptÀsxÂprÄpwÆtwÆ|~Â~…Át|Ë…†Ë„~Î’‹É…‚ĉ̀–’͌ӧ—Ó›ŒĐ–Ơ¦˜Ù®ŸÙ± Ö²¥Ú°œÖ¥–Ô¯£Ú²˜Û²ŸÛµ¦Ú¶̃°–Ú­¢Ú¸®à»¦àº¨Ü¸¬Ú»±Ü¾«â¾ªÛ·¢Ă–™´cm²LX³NX¸NW½NX¾T\ÁYd¼T]ÅU\ÄSXĂTYÅS[ÇSXÂTZ¾S]ÀTY¾Q\½NVÀOV»MX´P_·GT´LX±FS®FT¶FR¼LZÁS\Ï_aÖffÚnhÜtiàvj̃yoÜujƯtgÛsjÛsjÜqiØtnØrjØtnØsnÚupÙtnÚuñ|k̃|q̃yiÜxoÚpdÚpbØnaÚnd̃o`Ûo^Üpb̃qaÜvf̃p`ÜoaÙqdÚscÛrdÚpeÚo`Øk`ÛpbÙn^Øl_ØpaÚueÙrfÚse×tjÚrdÖpc̉qe×n`Üykï¤|ưÊ•₫צÿß²ÿà­₫Ơ•ê¥p‚)AL :Q>Q 9U=X>YB^@dCgGfCcBdBhBb@[:Y<X<]@a@c@`BY=Y:\:]:c<g>c9\8́’pë™xîœrî”ḿ‹kéƒiåxbßq`Ơ`W¿JI¢:J–+B¯>FÇQOÖe\àtaæ~eèŒkéńkêlëjçqè‰j́‰kênê…hçzbărỸf[ĐVN¸FNœ2E-F)C“.G™4HŸ8M¢>N¥;L«:Gª>L¨@K¯>K¬@M­CO«BQ¬EP®DO®EN²HT´BN¸GM·FR¸DNºNTÀNVÁPSĂQUÀRXÂVVĂQTÅPSÅTXÊ`cÊZ[ÈXX̀\[ÉZ[ËZ^ÎZYÏVVÑZX̀ZZ̀Z[̀XX̀QWÏXZåœ}Îo\ :T¶NY¼\cÀZbº`i¼X[À^e¸X`º`jº[eº\e¸Wb¾biÂjpÁflĂko¼eg¹fp¼jr¾lvÀnuÁkoÆs{Ànw¾x€ÄrtÅz‚Ɔ„ŃƒÄƒˆÈŒˆË‰‰̉¥˜Ô”Đ›•Î£Ô¤™Ô¦Ö°£Ø®Ơ£–Ø´¢Ú´£Ù¨”ر¤Û¸¤̃®—תص¤à¹ Ư¶£Üº­̃¿°̃¼¦à»­Ú»¬Ú¼®Úº¨Ưº¡Ô®¡¸t{­N[¯FT´IV´OZ¸U`ºPW¿NS¾RY¼RXĂR[ÁTZÂRXÀT\¾PYÁLV¼OY¸JU¹LY´LZ³KX¸HQ®FR°AQ³FVºNZÅW^Ñ_aÙjfƯmg̃tlâwlàxnàyl̃xl̃tfØuqÙrmÖspØtlØqlØrm×pmÖpi×upÙuñxp̃{k̃{nÚrbØphÚlbØn`ƯnaÜneÜp`̃sd̃tbÛteÚpdØoaÚrfÚodØqaØpeÚo`ÚpbØohÙoaÚqeÙsgÙteÙp`ÚtdÙugÖrf×ufÖteØshâƒmù¾ˆÿ̉ÿÛ¥ÿ̉–ï«xŸBHT=N>Q>T@T@V<\Bb?gCf Fd@f EgAhC`BX>Y=]?cBbA^@X:Z?[>`;d>k?d>T2I2́“rî–wî•ẃré…jæ}fâtdÚdVÊTR«<F—*B–*B¨;IÅRMÔbZƯo\ä|`èŒlêŒḱ’jëqêlêjèḿlêlêƒiè|bâmYƯcUÏUQ¶CK4D)B)B˜2F›6H :K =L¤@N¬<L©BPªCR«@N¬AO©DO«BP«DP¯GT°CL®DP´FN´HPµKT½LS»NU¾PUÁPSÄNP¿OUÅRTÄRRÄVZÄTVÆWYÇV[ÄVZËUWËZYÎZ^̀VYÉ]_ĐZXÎZZĐZXĐXXÏ\\ĐXVâuXÂRT²IZ½PX¿V_ÄVYĂ^c»V`½Xb¾_iÁei½[h·Yd¸\dºdp¼dnĂilÀkr¸fq·fq½go¾jsÂouÆrvÁjnÄknÅpuÅxvĂx}ÄvyÆ€|ˆ‡̀‰†Đ’†Đ“‹̉¤ Ó¢Ó ›Ơ¤˜Ö¤Ô¦Ô¬ Ø¬˜ØªØ¯ Ø°̃°ŸÙª¢Ü¹§à´ŸÜ¯œÜ´§ß¸¡áº¢̃¸¬Û¼²ß²Ư¼¬Ú¶¦Ú½³Ü¾µâÁ¬Û¾¨Á–¬Wc±DT´MX±JU¶GP¹JS·LW½QX¾OWÀQZ¾PXÀOXÂOU¼N[ºLU¶OZ´O]²HX¶JW´JV±HR­ET´GU¹NZÄP[̉`eØjdßpĩvnâzqâ{m̃zmßxq̃wlÚtjÙtnØrjÖro×mhÔtmÖnkÔokÔmfÚnhÛrlƯ{m̃zpƯsdÛtjÛpeÙndÜo`̃r`̃raàsd̃ugÜteÛpdÛr`ÛpfÜoaÜqaÛpd×nbØqhÚpgÙpdÚrjÛqhƯtfÚnbÛseÜtdÚukÚugƯxlÛxnßxjó¢~ÿÈ’ÿ̀Œï§q£HNY?Q;T>V@U>V<[=\=dAa>d@cBfBgA`AZ@\A]@`BdA_AV=Z@[>\=bBi"Cg!DW9F3D3î•~î”pî“óŒkç„hçx^ßlỶZT¸FN.>*C–0F¬?LÈRN̉c\̃p\ăyaç‰ǵĺ’jêrê‰nêŒíq́Œné‹mæƒkæ{`álXÜfXÍVQ³EK›/D(C(B“2J›8L¢4G¢;R¢@RªFW«HVªGY­HX©BP­GR¬COªAQ­EP¬DR¬IU³DR´KV·JT¸IT¼NRÁRXÄTY½JPÁMQĂSVÁSXÂUXÂUZÅVZÇUYÆUVÊUZËX[ÊXX̀\[̀[\ĐYXÎWZÑZ\̉XYÏZVĐpg»NR»MU½RZ½KVÂV]ÂW_¿V]½V_½Za¾Z^¿_h¾\e¼\g¼\eÀdmÅlpĂnqÀks¾en¾ku¾jsÄovÆorÄirĂacºktÀt{¼krºjtÈ{Êyz̀‡…Đ…Í’Ó—‰ÔÓ¤—Ø¢Ñ̉­ Ø¥‘Ï –Ó©£Û¯˜Ö£”Ԧظ«̃¶£Ü±ŸÛ¸©ßº¥ß±Ûµª̃¾¯á¾¥àº§Ư»¬ÛÀ²Ư¾¦̃»ªÜ¼®ßĂºâĂ³áÁ©Ë¡ªYg¦CUªBP¬HS¯HQ²JS¶JR¼MT¼PWÀRX»NX»PY¹NX¸NZ¶MV³K^´IVµJU³LX¯IY®AN²FTºJXÅR\ÑZ]Ùihßnfßwnâzräznăzjâynß|qÜyrÜwnÚrlØmiÔjlƠlkÔjhÓkl̉gd×lhØoiÛwkƯylƯvhƯthÜpbÜpb̃p_̃rẽofÜsf̃t`ƯtiÜpaÛo`ÙpiÚqbØpfÚpdØoeÛsiÜrcÛrgÜteÚpeßsdƯtgÛtjÜtjÜwiÚuj̃znß}pà{nî’uù´}æi›<FX<W?WBW>V=X<Z>]>`<d<`@d@cCd?a@Y@ZBcFeDg@bB^EX<]A\@d>n(Jp,ObAI
-3?0R9î”zï”tïĺ…eèfâr\×cWÄTS¨;H”.D(A3E°BJĂQSƠbXßp[ä|hé‡jêń’pë’têtêrê‹në‰lê†gé„jç{bàoZÙg\ÎTP²BI™-BŒ,BŒ(@”1E6JŸ:K¢>P¨?O©DV©DU§AR¨L^§DT®CNª>M­BN°@M¬EQ¬?N°EO²GR´KU·LXºKR¼PX¾NXÂTZ¾TZÀRUĂQYÂTWÆRTÈXYÆUXÄTTÍUVÊWẀTX̀ZZĐXXÑYXÍUVÎV[ÏSW×ppƠdWºMU»Q[ÂSVÀVX¾RW¼PW¶MVºSaÁU\¸Vb¿^dÁ\gĂbiÁ^bÀ`iĂjmÀ^a¾gn¿mpÁjrÆlj̀moÈnmÀeo¼enÁrzÈnrÉ|yÇrpÈ{€È~|Àw͆Ά‚Î–Ó˜Đ‘ˆÔ£•Ơ™ÓœÖ­¡Ø°Úª–Ơ¨ ×´¦ß¸ŸÜ±¢Ú¶¨Ư¹¦Üµ¢Ûµ©ß»ªà¸¢à¹©Ü»®Ư¿®ß»¥Úº©Ù¹®ÚÀ´ƯÀ²àÁ³à·áõăÄ­Î¥«bo>MŸBN¤>J¬BN®DNµIR³LW¸R[¹KR¹PW¸LX´JX°HW¶JV³L^¹PVµIU²ET±BR¯FV¸IXÁS\Đ^e×jj̃qnàvhă}nă|kă|mä~pàylßzõtlÚsjÙmfÔhdÑfdÍfiÎcfĐb_̉baÔieØpiÜxp̃ym̃vĩrb̃obßp`̃peƯqẽtg̃uĩsd̃q_ÜpẽpdÚp`ÛoeƯobÙrfƯqfÛshÛrcÛsgÜrd̃vf̃qbÜvhßxj̃yiƯxj̃wjănålç„lÖo\’2C_AU?ZBVAV=Z@[?a?`=b@f>e>f@f;b>[<U;^Bg$JdC`>ZEV@Z>bEbCq)Ls.QfBT;D6K;E]ï•xî’ŕ‰nèƒlæxdÜl^ÏVS·DH1B“-D–*Bœ4F®BOÄVXƠdYƯn\æ€hè‰h́lî‘nèq́sêsê‹mî‹oêiè„iæxaâr\ÛbWÊVU°CK›,B*D*@—2G6H¡:M¤@P¦=M¨BTªAO«DR¬GS¬CQ®GSªBR°DQ¬BQ«BO®DP±ER·HR´HR¶MV¸KT¼QY¾PWÂPVÂPZÁNTÀPUÂSWÆVÙVZÈTVÇUVÊVUÈX[ËX\ÈZZÏXYĐYVÎWWÍW[Ơf`é§~ÇPQ½MX¼SWÂPS¼OU¹MV¶KW»PW¼S]¾V]¼Y[¾ahÄfk¾[a¼`gÆhe¿_d¼]bÂgjÇlpÄjlÄopÆnp»jwĂkoÆuxÁmsÉppÄlsÂwzĂqxÀ{…˃„Åz|ȇʇɖ‘ÏÎŒĐŸ×¬™Ø ”Ö¨¡×°ŸÜ¨—Ú­¢Û³¤Ư¹¡Ư´£Û²§Üºªß¶¢Ưµ¨̃¼±âÁ¯à·¢̃¼¨Ü¼®Ûº¤̃»©ß¼«Ü¾²Ü¾±̃¶¢Ú´¨Ư¾µßƺ̉²´¬~Œ©t¢Sb<K¤@O«DQ´GR´O[·KV¸OX·JS¶JU²JX·HS³ETµJZ´DU¬DU¬BT¬CX¸KWÁN^Ñ^d×npßwsáznä|lå|lå‚sç€ră~õxpàwjÜxn×ohƠebÏbdÉ\`Å]dÈZ[Î\`̉bg×njƯrk̃zk̃vlßsẽpẽn`ßrcâucâudàxjßwb̃l_ÜnbÜpbÜn^ÚodÜqfÛpfÜseÜtdÚshÜreÜtjƯzoƯtd̃vh̃xhàweàxjâzlă€pè€hØkb™7J`@X>V=V<Y=V:V9Y?aAg Ch!Cf?d<`=_:Z=X:^>dAgBdF\GZAYD]BfDh$Gr+Ng"EV:J5O;„:SËurîv́Œpê‡læ~fäq\Ù`TĂLN¦5G˜9M•2J“,D˜4H®CNÇUSÔdXƯq]æ{bèhëíój́‘pënérë‰kë‡iê„fæ|cát`ÚbUÉVR±@I›,D*D*D˜1Fœ4F 3I¦@R§?L«GY¨@M¬>P¬@R¬@MªDR«CR­CO­DO®ER¯DO°FNµHPµJQ´LT³OTºMT¿NSÄSRÄT\ÀQTÁQVĂRVÆZ[ÄUVÆSVÄXZÈSXÊX\ÍVXËSVËWX̉\\̀YXĐTZßwpÜmUÁNUÂQP¾NSºIP¸JS·IP¸P]¿QV¾X`¾Y]¾T\Â]a¾X_¾ciÉbeÂ\aÀ_cÂflÂlnÂei¼hrÆch̀nnÍquÅpqÈprĂjl¿lxĂsz¾ekÇxz̀zÈ||Í~zÇ€|Í‘ˆË‚~Ë’Ô¤”Ô™’Ơ¦Ù­–تŸÚ©ŸÙ³ªÜ²œÚ¨Ú±¢Û¸¤á´œÛ°Ü·¬ß¸§àºª̃¸«Ư»°à¼§̃¸¢Ö¶§Ø»¬Ú¸¥Ó¬¢Ñ°¯̉½¼ØÅÇàÎÈæÔÍëÙĐæÛĐà×Ëξ¸«`hœ5H¦;M¬DQ±MZ¸IR±KW³LW³HP®DT±HTµGU±IV°FX«FXªBY³EV¸K\ÀS^̉bdÖnmßsmá{på~nä€månæ€nâ~sá{nà|sƯxlØodÓd`̀\_ÂV^¿PZÀTXÅT\Î`_ÖedÚpiƯulàxkßufßpdàrdßsgàrbâxgßvjßtd̃n^̃neƯpcƯp`ÛpdÜpcƯrl̃rgƯrdƯqf̃rẽukÜqeÜrhƯuiàwiáxjâ{häoæõwh¸KPk@XAU@V?W=W<V:\>bDc?fBc@h@f<d:\>Y=^AeCe DfG]BXC\A\@`Dh!Fr2Sh$HS;J<N<y0Nºioà‰{êŒvê‡mèiäwdÜj\̀VR´?G™.D˜3G›6I™1E/F¬AMÈTSƠbZßqbæ|cé…hëńś’pîpí‘úńhê†jè…dæ~dár]ÚfYÊTP°ENœ2F(D/F–2FŸ:L 5J¥?M§FT«H[¬BQ«@O«EQ«FQªBQ¬DT¬AP®FT°CO°DO°GR´GU·IPºNY»PX½TYÀU]ÁTWÂNTÀPRÂPV¿UXÀQXÊXYÈTUÆV]ÈV\ÉYZÎVZÊVX̀VX̉XX̉VX̉\Väx^ÅUWÀSS¼LR¸JT·FO·LX¸KS»U_ÁW]¼X]½SX¼U\»PXĂbfÂZ\Âdl¾XbÀbgÅhm¾dlĂdh¿afÂgmËlnÁilÄnsÆln¾jrÉrpÂrxÂsxÇz|̀zzÍywÍ€̀|zË‹ˆÎ–̉”̉—“׬–Ư©Ø¦›Ø´©Ư¶ Ü¬›×§œÛ·¢Ü±Û¨Û·§Üºªá·¦Ú®¤Ü¿³à¼¦̃³¡Ú·©Ú·¨Ö­̉­©̉¸¼ÚľäÎĂèÎÂêĐẮÓǺÓÇïÖÆ̣ƯỊ̈àṆ̃àÉ̉´­ŸDV›4LŸ8J¨ER®FT®LV°HP®EP®CQ±CO°FU±GV¬FX¨FX©>T²GX³K\¼O`Đ_cØlh̃ukâwlå{næ€pä~lç€pä|năzkæ{lß|rÛriƠgb̀X^ĂPX´DN³JV¹IVÄTZĐ]^ØkjÛoiàwnàxñtißr`ƯrhàrcârdàteàsdƯpfƯn`Ưrh̃pcÜreÜpdÜod̃qfƯqeƯpdàobßtgßrbßvlàwkàwlăznâ~qæ€nä|gÂVVz'HXCU@X>X@V 8[AX<`@`>d@h@c=c<`8[:Z<]<d?jEb?_HVDX@^D^Bf$Kq.Py7Yf FO9Q@m'N¡YiÓ~täxë…fè†næycßn`Ô^W¿MO :K™.A˜2G˜3Hœ5G3H¬FRÉWTÖd^àtdå|fé‡gë‹ílê‘ńńpëḿŒjèmæ„læ|bàq]ÚaVÍRL°@K›5F*D&B”2H4J¤8M¤<L§?Sª>Nª?P¬@O«?N­FR¬ER«@N®ER¯FR®DQ¯CO³ET³JPµLV¸MVºLSºNU¾QXÁRW¼PVÄPUÄV[ÄX\È[\ÊX_ÊVWÇ\bÊVZÆ\ZÈX^ÈTTËTWĐZ\ĐZ]ÔgbĐ[VÄQR¼KR¼HPºMXµKT¹NW½O[ÀT]À^^ºRX¼RX¼X_Æ]cĂ^dĂ\c½\d¿]bÂ^b¿em¼dl¼cjÀ[bÀjlÅdoÂlrÆhlÊqoÅjiÁisĂhlÂrv΂ÈllË|xÏ€}ËÎŒ‡É~‚ÓŸØ¡Ö ”Ú°¢̃²Ü©Ø¦œÛ¶¨Û«Ø§œÙ²¨Ư¸¤̃°Ư´¤Û¸¬à¹¦̃² Ù¯Ù±£Øª›Ó°²Ô¿½àËÂåÏĂæ̀Äè̀¾èÔÆæÎÅèÎÀçÑÆêÓÄîÖÆï̃̉ôáÎïÚ¾»|’1H4K¡>M©CR¬GT®DQ®HV®CT¬FT¬FW­BS¬DT¥DV¤@V­DXµN\¾Q^Ï`cØgb̃sláwiå}nä~lä}kæ€kä}nå|nâ}qà|õrfÚg`̀ZY¼JP¬?J¤;M§;M³IXÅU^Óca×km̃tpâxlàujàsdƯoaàpbào`àtcârdßpbƯpd̃ncßqd̃od̃qh̃uiƯqgÜtiÜreƯrd̃rfàsbásháwháthâzlå€næzkĐ_Z.JZ>VET=X?X<\>^>`>c?f Da>e@f>b@]AX=Z=cBjBhC\AVAXBX=^B`Go-R|:[t5XdHW=o)K XhÅxzÛƒuä’wéˆvèhâtcÛdVÊQP­@K™.F0H4H™4G0H5H®CNÄTUÖd\àq`å|bê…f́Œḱ’kêńq́‘rêjêtè‡pèƒkæz`̃m[ØaZ̀OP³>Kœ0F+C+F2F 6I¤;L¨>Rª>L¬<O®GT­DT«DP­DP©CP«BP¬BN¬AO®DT®HQ²HS²ITµJRºNT¸OZÀOTÀNV¾RTÀRVÀPTĂRVÅSUÄXYÉVXÆTXÄZ`ÍWZÈWXÈTYÎYX̀XWĐ[\̉\]Ñ]VÈQT»IN»LQ»NTºLU½NU¼T_¼U`ÀZbÀWa½RY¼[cÂ]`ÀX^¿[fÀ[^½Z`¾Z`¾_d¸T]Àcf¿`dÀhnÂckÆru¾bkÂlqĂbdÄnrÉhkÄlpÊrqÇprÉopÇimĐ~zÉzw͈„Ô•ˆÔ…Ó˜Ú«—Ü® Ö¢œØ±ß³œÚª ×¬¢̃¹«̃­Ö§Úµ¨Ưº¢Û®™Ö§›̉ ˜̉¨¡̉´´ØÀ¼ä̀ÂçÏÂèÏÄæɸå̀Àæ̀¿æ̀ºçĐÂçʼèͼé̉ĂêĐĂîÙÉï̃Đđ̃ÈØĸ¤^l0I7J¢>N¨FS«BQ¬ES°ES­DP¦BS¨FVªDS¨BV£=U§BV´KZ»P\Î`dØjhƯrlâuhäzjåmä{iæ~lå|mâznä|oàzrÜskØljÏ_`¾NW¢8J•1H–2J¡6MºJXÊ[_̉hiÜnjƯtkàvpßseƯrfàobâreàufár`ƯpbÛoaƯofÜrjƯpbƯnd̃pfßqh̃vjÜrgÜshßshßsiâulâviăviåtæ€pÛmc¢<O`@T>T?U 8Z8Z8[;b>c>d@d@d@f=b>`@W<Y<b<i>i?`BU?ZBYB\AcFi(Or-Ts0Tn+P`?p&J›SdÀpr̉~wÙ‡vß‹uè|dăybßm^ÑZQ·EO 5J”.Dœ4K4I5H6J¢8H±DOÆTT̉bVßq_å|dè„fëń‘ĺ’ĺ‘ṕnênëŒoéˆmédåz_àn[Ø`TÈMQ®ML5J+E,F˜2HŸ6H¥8J¦?N§@N¬?QªBP¯@N¬BO¬CT¬@P®L[®HW«DR®FS®AN³HU²BO¶JRºNV¸OWÂQT¾TX¿QTĂQXÁRZĂVYÄSVÆX[ÊTXÊWVÆW]̀VVÊZ[ÊVỲ]X̀YYÏ[\ÖaXÉPRºHP¸MT¹IQ½KRºLT¼OTÂX`¿V`¾V`¹T`À]bÂ\cÀVZ¿Zb¿Zc¾]b·T^¿^]ºXb¼al¾`gÄfgÁgnÊjmÈlǹroÈipÊvvÄcfÂprÇklĂqvÇrsÄjnËz|ÎvwÍ€̉‹†Ï†…Ơ™×›×œÜ¯£ß®˜Ü©Ú¬¡̃µ¦àº¥Ư°¤Ù²¦Ú´œÜ¦Ô¤–ΜϤ¨Ñ²¶̃Ä¿å̀ÀæÎÂèʹæ̀Àå˽äɾäÉ¿äÍÂäɼæ̀ºæÍÀäÅ»æʵéĐĂéÓÈîÛĐïÛÍđßÄĐ´­—BT”2F˜7LŸ<M¨>P¦>MªDR­@O¬@Q©DV©@Q¨AU¨?R­>T³KZ¿PYÍ]d×efƯnjàxläpä€mâ|kä{măznă~pä|páxpƯqjÙleÍ_\¼NW™:J„%C€"AŒ(D¨@RĂTZÎceƠhiÛrl̃vjàujàtkàn`ârfàveàtĩrgÛpdßqd̃rh̃n`ƯndƯrfàthàobÜpd̃qf̃sjàtjäxiâvmåylénßvi¹LPmCU=U9T :V 7[:]@b?d@f@fBc>f@c@`<X>W=_@d>iBbAZ=W@\?^B`Bg"Mq1Wv6[l)Pg%Jz1R˜Nc»mrÎxÏ}tÖ~uƠ†yèvaâr^ØaRĂLL¤7G›.Bœ6L¢5H¡:L9J1D¢;N®BLÅTVÔdXßo[ä{hçˆnëhîṕĺrërëŒnênêmè‚däzbàn[×bUÉTR°FMŸ6J‘-E2L˜3G:L¤8L¤:L¦<N©@Q®@M®CP®BN«BP¯FQ®JX°DQ°BQªAR®DQ²DN²HT¶JRµKR¼LS¾NUÀQTÁPQÆPOÅPUÇRTĂRVÄVZËVWÊUUÊVVËVWÊZ^̀YX̀\[̀Z\Đ]YÇW\ºLT¸FP¶HR¸HNºPZ½RV¾T^¿X`¸MX½XaÂ`hÂY_¼X_¾[bÀZaºU\ºZa¼U]¸V^½^fÄbfÅghÄkoÄbbÆntÎttÆhǹolËlnÇooÈilÄrvÉzyÇos̀wuÉkqÏ€|Ö†€̉€€ÔŒƒÔ‘‹Ö˜‘Û£–Ưª™Ø”Ù®›Ưª“ܨگ ̃·¢Ú­Ï‡Ï–”Π¥Ơ¸¹áÉÄä̀ĂêÓÈèË»æÈ»åĂ®äƵäɺå˾å̀½ăǺäÈ»äƹè̀ºæÏÂâƹèʶéÓÇëÔÆîÛÎ́Ú̀êØ¿º”—”:N”-Fœ2F¡;L¢>O¥CU£@T§AS¦F[¢@R£?T¦:O©@T´IXÁPXÏ[_ÖfcƯokàznä~pä~mázmä|kä|lâ}oâ|q̃zsßqkÚlfÑbdºQW7M~=q@x=4I·LWÊX\̉fhØlm̃umàvm̃vgßriàoc̃ofáreßsiÜndÜmdßtlƯoẽphÜpgàrhàpf̃nb̃odàpfäneæpfäxoê~lè|mÈc`†%@[:R 9U8X 6Y :Z:^=eBgCgChCdBgCaBY@T ;\Bd?hBa>\@Y@\B_Cf1Vh2Zm'Rr6Zp1Xn*Rx2T™Lc·lsÉ|xĐẁzuÍzsÖ}râq^ÜfVÊTP°>Jœ2I2Eœ7K 8I¢8G¡4C2D7K®EOĂTVÖe[Ưscä{bæ†péŒńlëóqëŒlêqêqèkèeăy_Ưo\ÖbXÈRO°CM5I‘,F’(C–2G3G¥:O¤;N§@P«;Q¬>M¬?R°FT«FR¯FS°HU­FU¯EO­CT°DO®ES¶KS¹KT¸LT¸KS»OVÁPVÀSUÄRUÁT[ÄQWÅVXÅW\ÈVV̀VXÊXXÍXXÈYYÈXXÍ\^̉`\ÉRR»OXºJQ»JO¶LXºHP¼PUºS]ºNV½PXºU^ÆZ\ÁY_¹UZºQXÂ`g¼TX¼V`¶U_ºU`ÀW\ĂcgÅ^bÆgjÂ^gÂlpÊkmÊorËjiÇdj̀qsÊfjËnpĐtxÆmrÏrrËtvÎzÑwtÎ}w̉†Ñ~|ד†Ø”†Ơ“Ø£˜̃©–Ù¡˜Ö¡”Ú³£Û¦̉•Ï”’Ê•—Ơ´´áÀ·æÍÄéÍÂè̀Áêʸåȼăƺà¼áÅ´åʼăžăÈ»âÈ¿âÄ·âɼåǺèɹæμâƺå˹åÍÂêĐẮß̉íÚÈäÓ»¸ˆ‹2G“0H›0FŸ9N <P£BS¢?T¢AT£@S BV¤>RªAS·GTÂPZÎZ\ØgdÜqnáznä~qå|lå~mç~kä{là|pâxnÜytßvkÚlj̀af¾V[ @R‚"Dh=p>$@¦;LÀQXÊ\aÖhgÜpiàuoàzoátjßpfàpfápd̃thÛqgÜogßpb̃qf̃pg̃qĩrdàshƯn_àreàqfäqfæuiç{qé}jÜl_5FbAT8V?Y>Z;Z<`@dBjBgDdBfAf@`@\AU@Y>h Dj"Bd?\=X?YB^Aa#Je&Oh)Sl-Vt8az/Z~3Y–Pi³iuÈzxÍ~Đ‚zÈwsÇrqËulàfRÔ^N¼FJ¡7G˜2Hœ6HŸ8J¢6G¡:GŸ7E 6HŸ4E­EMĂQRÔ`ZÜq_äybèfêrëoëńnêpêŒĺnèŒlèƒbäycànZ×`UÊPL´DN2G‘(B,E˜4Jœ;N¢<P¤?P¨ATª>Pª@S¬DV®GU©CN®HV±FPªDN­ER«CP­CR²HQ´IRºJP·JR¹LT»PUÀPSÀSUÂTXĂPTÄTXÇWVÈZ`ÈZZÉXZÈQT̀Z\ÈWZÉXYĐ^YÉXU¼JQ¶NX¸GN¼KQ¸OXµKWºQ[¾RY¶MZ¾[`Å\aÀRW»X_¸T_¼Z[¼W\²QZµQ^½Z`À^dÁ[\ÄdjÄc`¼X_ÇfjÆkoÇvsÆgfÂnpÍtrËlmÏrnÏqq̀uxÎvtÏrs̉|xÏzz̀|}̀yvÏ|ÔŒ‰Ó†ˆÑ‰Ù¤–ܪ™ÚÙ¥–۬ס•̀„~ƔϦ¯Ư¹±èȺæȼê˶åËÀăĵßļâ¼âȾäʸ̃À¶æÈ´äÊÁâÈ¿ăǽáǺăµäȸàżăǹåÎÆăĐÇä̉̀èÔËíƯÑîßÔíØÂÜƹ¡[k/E“1I—6F8Mœ7M>NCU¡?R¢@R <P¦?R®FU¼Q]Î]_×ddÛnláxoå~tå€tä€sæoå|jă{măznà|sßxqÜolÓefÂV_¦AP„%Bd8^9y:˜1G³FSĂR[Ñ__Úkh̃um̃uláwkàrcßpdàrf̃peÜqfÛmc̃pg̃nh̃rjÜnf̃qnàrg̃pf̃uhàvpăwnçxnç~r̃scµBNk@VAb8\`0S^IZ<\=eCfAgAe@gBfBcB^@X@X>b@jBfB]AY>[@\?`=d$Lh%Nm+Vt4_u0\‚:`–Kh­fwÅvxÍ|zĐxÓƒwÂqn¾nl΂zØZNÈQN¬=H›1I›6I¡8L ?N8J¢:M5G9JŸ6G«>LÇTSƠ^X̃r`ă{gæ„hèrêŒpëó’têŒnêĺŒnêgè…dåz`àlZÖ^SÈRR°@H6I,G+F•8L›8L£<N¨?Q¨AQªAP©;N¬?L«DO¨@P­AM¯DQ«@P­@N¬BN®FS³HS´HN¶FQ¸IQ¸QY½PT¿PVÀSVĂRUÄRUÇTTÈUWÇUVÊTWÇ[\ÆVXÈWXÉYỲZ^Î[S»MR¸JQºJO¹KR½MWÀRZ¼QZ¼PZ¼NX¾W_ĂW\¾V^½W`½V\¾U\·V^µN\¬M\µTb¿]eÆbcÂehÂaf¾ekÂhmÄhmËwt̀mǹsr̀vrÆptĐwsËnpÎxxÔvuÏwvĐtkÈruÊsrÎqsÎvvÏ{vÓÖ’†ÛŒÙ™‹Ú¡”Ü©—Ơ–ŒÏƒÈƒ„Ǧܾ¸âĸăĹæÀ±çŴ俵â´̃ÆÁä̀ĂæĐÄäȺâĺâIJ῰åĂ¯áĹâ¶àÁ·ßÄ»ßÆÂâÏÇäÎÄé̉ÂèĐÊéÓÄêÔÈ́Ü̉ïàỐÜ̉́ÛÀͳ­—AS-C1G“0F˜6J–9L™8M;P;P¡<P¥@S®GXĂQ]Î]_×ih̃qlázmç~mæ€qä|lå}oå|lă}mă|qà|vàskÚppÑglÂZc¨BT‚$Ab9W;fB†,H¢DUµKVÈX`ƠgbƯojàtláwpàth̃pgàsj̃pgƯnd̃qf̃ocßncàrjƯohàrcàrjàqeâpdâulæukê}pærÍZV€ @Y@V@V;Z>Y;\>a<c>h>hAd>gBfA_>Z>X?a?n Bm$E]=Z@]D^D_@^Ab"Gh*Xl.Yv7b:_”Jg«at¼t|ÊywË~{ĐxÎ|xÀon΀wÔ‹̀RP³DHŸ2F›2F7H¤>N¢>L£:I¢8H:H2D4H®AMĂQQÔc^Ưq\âxbæ€fåfëŒń’sêqêsêuínêˆlçƒjä|dÜn`Ơ`TÇOMµ@HŸ3G+FŒ1J4O˜<P¢BR©AR§BP¯FS«AUªBN®BN¬AS¯DM®DSªCR±FR­CO®BQ³JT²HN·GN¸JP»MP¾QYÂPT¾RYÂUWÄRQÆTSÄUXÁTYÆVXÆV^ÈZ`ÎZ[ÍZZË]_¿TX¼TT¶KR·HQ¾NSÁSZºPZ·LW¼T`½R_¾W^»T^¼V]ÂTV¶JT´S\°HY³P\¹Ta¼Zc¼V_ÊehÂblÁfnÆabÇgh̀lhËij̀rqÍgjÈtwÎvs̉rsÑwr̉{zÎzvÍnlÀhoÎwtÈlmÍyyÓyvÏ{zׄ׈֒‡Ú©Ö”„рŀ}½Đ¤¨âÁ²åǼæƶåȹâĂ·á»­âĸáÆ¿æ˼æ̀ÁæŵăǽâÀ²̃Á¶Ư»²Ú¶¬̃¼®àƾàĂ¹äʽè̉ÆéÔÄçÎÂèɹå̀Àäɼå̀¾è̉ĂêÔÅîƯÍîÚÆïÚÁ¸…†“@M†0F…,D3G3H˜7K8L7K6O¦?O¬HXĂRXÑ^[Øif̃phâxnå}pæ~pă}lä~täziâ~sâ€vá|r̃vnÚph̉b`ÀVZ¥<J‡%B_ 6P8`@v$F˜<U®GWÄV^Ñc`Újg̃pkávlávmàujàpẽph̃ld̃qf̃lb̃pißphßnd̃qhàpjàqhâseåthèxiê|mÛmb£7F^;R:R :W?X<]@bAh@fAg@g?j!De@`:X<R 9^;fBpBfBV<[@^>aC_AaBfLi&Tr5b~8b•Pn¨bwÀv}É~|È̀zwÎ|sÂqrÊ{qÔ‹|Ø{¹CK¤9I™3F5N 6G¢:L¡:K¤;K¦9L6Fœ1DŸ8J¯=IĂPTÔbYƯnZâw`æƒièˆjéŒvêpësêuêŒrê‹nê‹uè‚lă~ĩn^Ôe`ÆRR²LT 2F)E4I–5K;O¤<M¨BQ¦?M«DP¬ET¨?O®AP¯AM¬@L®CQ®DP°BN¬HQ­FN²FS¯FM¶ER¸JRºPT¾OTÂQRÆX]ÂUWÀRTĂSVÉQVÆVXÈVXÈVZÈW\ÆZaÍbaÆYZ¼X_¼Q\¶PZ½U]¸IU¼RZ½NZºNX¼R\¾S\ÁX\¾U^¾SU¼OZ¹RV¶Xd¶V\¸Zg¿X\¼\iÂ`b¿\dÅklÁ_f¿hlÈeaÅotÊlhÄbdÊrsÎol̀trÓtn̉yvÓzvÉloÄrxÊssÊos̀rrĐtwÏyyÖ‚{̉€ƒÔ”ˆÚŒƠ‘€ÈxzÀt|•ŸÙ¬£âøă¶ä´âµăĂ·ă¸àĂ»äĂ´æɻིåıßÀ¸à¸«Ư¼³̃¼²áÈÀƯ¸áĂºçʹäĸä°åƱâÁ²à²ƯÅÀßƺàÊÂàÉ¿âÎÀäĐÆåĐÅèÔÈîÚÈÜÎŶŸª™`t>O‰,B‹.B0B™2F:G›4K¤:N®DQ¿RZÏ]^Øhbßoiâxkå}så~mä}qå~räylâ{pă~ràynßwñphÓdaÄY_¥<K†">c9UBWFg Gˆ3M¢BTºIUÊ\\ÖbbÚmhßtnâtnáufârbßnbÜndƯmbÜmf̃meƯoĩrlßqjărhásjäxjèylêzläti¾NPq>Z?Q
-9V 8W;W=`BfDjEj"DfAe@dBb;^<Z<[?iBnBiA[=X=aE`BbDd Fj*Qf&Qg"Nu3]IjªdtºryÊ{|Ë~{Î{ÂxvÂutÊ~uĐˆyÖ}×’¨;L2F›6J›6J¡7H¤;K¢>P¤:G¢;N 9L 4H4G°DPÁOSÔ^UÚmZâyhæ‚féˆhë‹mêpéŒrétéŒrëˆlé†lç„käydÜj[Ö^VÄTS²DL7K*C+B”+Eœ9L¡;Q¥@P©?R«BR©CRªBQ­DUª@O¬CNª@O¬BO°DO±AO³FPµFR±JO´JQµJS¹MU¾OZÅRVÄTYÀSUĂSVÄNQÆT[ÇVWÍXXÊV]ÊWỲ_aÔe^ÂQV½NT¼LVÀQW¾TZ¼PV¸OWºLT¸RX½QW¾T[¸V^ĂT\ºOV¼Yc¾Xc½\d¾X`¼WdºZbÀYaÆeiÆfhÁbhĂjnÅ`fÀlrÎtrÇkòtr̀fmÂns̉urÊjjÑvmÎnnÇsrÍnlÉinÎrrĐpmÎ|zĐxtÎvwÓƒÙ–‰Ô|Ăpp·o~̀¥¨ß²¢à»±å¹¦âÄ·àÀ¹ß¹«ăƺæɼåȾ᾵⺬ßĻܾ»Û´¬Ú¿¼à¸¦ßøæʺăŶིྶ̃¼±ÜÁº̃ĂºàĂºà¸äÊ»ằÄäËÂåÎÂăÎÀæÎÀæÎÄè̉ǺÖÉđÚËî̃ËÖÎÀ¬„“…4F‡-F‰)A’0F•3H–3H£:L®BOÁOZĐ\^ÖicƯol̃wkäpå~pă|lætä~lâ|năzrß}vßztÜqlÔdaĂVX¥>M‡&Af:X=X@`<p82Hª?LÀTZÏ[]Ögẽoiâvlătgâseàqd̃qd̃mcÜmf̃kaßnfßphàriárjátkæxlêzlèxhÑ^Z‰*FZ;S:T ;V ;W:\@gAl"HjDhAhBg>f?]<Z:W>d>qCjC`@W@[BbB`CcD`Ie"Jh$Rl(Sƒ;_¦[n¾rzÅzzÊ{z΀|΀vÁvxÅ|zÓŒ}Ơ”€Ơ}ד:N—4H7J <J¢8J£9J¢7H¢8J¤<N8NŸ5GŸ6H¬?MÂPOĐ^XÛpbâu`ç„jè†nëŒpèjéŒvèzèŒśŒtèrè…mäzb̃paƠbYÉRSµBM5F’+C,D—0C7H¢9J¦=N¨@Q¨@R¬GS­CP«BN©DP¯EO­@M¬FP®AO°HV®IQ°DP²HN¹HO¸MS¼JS½MSÀPWÀTVÁRUÁSVÆV\ÆTVÆTZÇX[ÈTUÉW\×i`Í_\¼HT¼IR¼HR¼KTÁTZÂPT¸N\¸NU·NX¼NV¼QZ¼TZÁV\ºNX¿Xb¿W\ÄXZ¹XbÀX\»_hĂdmÆbcÁfnÆba¾`jÉnuÉfkÍorĐppÉfkÊnpĐpoÊt{ÏrpÍpt̀ll̀nmÀirÇlkÄlsÈrt̀oqÊxyĐ~{ÓŒˆĐ€{ÄimĂ‚Œ×±§á½®Ưµ¬â´ Ûº¶ß¶¨äƶ࿴弧æĵå´àÀ¶Üº´à¼¯â¹Ư¼´ăǶܶ¬Ư¼²Ư»±à¿­ßÄÀàļàļăŹæÈ»äƼâǼâȾäʾäËÄäʽäÍÂå̀ÂçÍÂç̉ÆèÔÈêƠÉñÚẸ̀̃ÈàÖıŒ•¢FP$@‹)D/F”2G6K®BO¾MTÎX\×hd̃rkàznă~på~pă|nå~să{mäykâ~sâu߃Ülg̉dfÁRX¨@L‹'Dj<Z>U:W 9f9~;™4J²FVÈV]Óa`Úgeàthâtgàteârfán_ƯlbÛlb̃qgàpgàndáqiătläulçxmê{kƯj`¦8Ib5T 8T 8T9Y<\<^<h@i@jDl HgBfBfA\?V;`?kDlA`>^?\D\=fFbCc I`Lb!Nm$R{9^Ri¼nxÆwxÆy|ÈxvÎyÈzxÄxzщ~×~Ö“€Ö‘€Ø‘~˜<N7K9L£<I¤<K¤:K¢<M£=K :L¡9Jœ6K 9L¬ANÁNMĐb\Úpbâvdæ‚jèˆpêrèxèté‘zéwêŒrèˆsèƒiäzdÜo`Ơ_XÇTV´FN <O‘*D(B–0FŸ2F£:K¦=M§<K®BP©@N®@N¬BS¬CQ­FR¬BO«DP­FQ±EO­@I±FR´EJ¸JN»LRÀLQÀNSÂTVÂTWÀVXÂWXÈTVÂVXÂUXÅUXÆWZÎd^ÔcYÁRU¸LT·PW²EQ·LW¿OTĂRW¼OXºRXºNV¾QU¶R\¼NW¸PY»TZ»U`¼RZÁWZ¿Yb½^fÈfgËhlÈgjĂ^dÅlsÍpòmpĐwwĐsrÈhqÏzwÏjl̀nǹonÈkrÏpoÈfhÆlpÊhjÂbm̀rs̀pr̀tnÇnnÀkqÄrp¿nxÉ’‘ܱ¨âº©â½®ß¼¬Ú¶²ă¼£Û½´à² á¸§Üº°ß·©̃¹¬̃»´̃¼°̃À¶äÁ®ß¼µßµ«Ü¾ºàÄ´âÈÁß¼±æÄ®å̀ĂåǸáȾäÆ»ăȾäʼăÊÁâȼäʺăÊÀä̀»è̀½åÅ°çϾèÏÀçÏÀêμíÔĂđàÊâÖ³}†}%A"=ˆ'@.Cœ6L¨?O½MV̀`aƠfdÜocàxsä€ră}sä|oæ~pâzpâ|räzrå€p̃xr̃ldÔb_ÀRWª@LŒ'Dl:^=W:W 4`;m:)C¨<LºGS̀`aØdc̃ohàuiâtgàtfƯqeÜm`Ülãkbàndßriâtjátkäyné|räsd¾PTr;Z>T:V<V<Z>`Af@j Bh@i@h=fBeDa<[@_AgAjBf H\>\>c"Gb@cBaD`I]Hb Nv3\˜Vn´lxÅyÇwxĂw|ÊzwÆxxÁxzÎ…~Ó}Ö”‚Ö”€×’Ơ}4Jœ8H¡:L£<M£<N¤<K¢<K¡?JŸ<J;P6J >P¬BNÁUYƠaZÜo`âuaç‚næ†oè‰pèréŒuêŒvêrèpé‡oè‚jæzẽpbØbXÅRT¯BM <R’*D,H–/F8K <M¤?N¥?L¦AM¨>Q«>M®FU®IV´BL¯@M®BP¬BO®EM­DQ²DQ³EL·IPºLS·JQ½NV¿PVÂRXÂTWÄVZÆXYÁVY½RXÄPUÅ\_ƯuÊSTºHM±BP°EP®EP¶EPºNRÂRX¾V[¿RX¹KT¿SU¾OX¾TX¾U^»PV¹R\¼X_¸Vb¾X`Ă`_ÆhkÈadÁfrÈrrÎijÏuv̉wuÎnoÇrv̀lj̀npÏvẁqyÅntÎurÉflÉmrÇlrÈlmÉhhÆmrËrlÆkn¼em½js¿|ˆÑ”ܦ–ᶡඦ࿴࿰ྰ߯¢ß¸¥Ü¸²Û±¦̃¶£Ü¸°Ú´²àº®àº­̃´§Ư¶²àÀµâžçƷᾶèƱäɾ߽¹èƲäÈÁåÊ¿ăȾăƺâȼåʾáøăŸăÊ»ä̀¾ăʾâȼæξæ̉ÈäÏÄåÑĂæÎÁê×ÊđؼÜξ›Vjv:~"@Œ)A˜4H§>K»NVÎZYÓd`Ûngàyoăzlä~på|oäzmæ}päzră|oă~uăwñnk̉dcÄTZªBNŒ-Hj<\8[9X6X5b 5v6+E°>JÆWZ̉][Úfc̃nfàriàtẽndƯk_Ük`ÜjbßjaàtjárhătlæznèygÑc\Œ(F^;V<V;\=Z>^<d=i>i>h@f@eBh"DcA^@[?dAh Fc<\;V:^?`Bc?h$IZB]H\Mp(T”NjµlxÇ{|Ê|ÆxvĂxyÂquÀsvÇ~x̉Ö”Ö”‚Ơ“‚Ơ’Ô~›6Kœ4J¡:K¢>P¢<L£;K>N¢@N¤=K :L:N ;L¬GSÀQW̉c\ÛlZávbä‚må†nè‹pæpæˆrètésè†hçrç„jå{fßp_×f`ÄRS°DOœ6L‘,G,F–/F5K¤:N¥<Nª>K¨<O«?L¬?L­CR¬FU®CPªDT¬@L¬@M¬BN®DO±FN´FN¶HPºKR»MT½PW¿MVÁPVÀV[ÂQVÄQU¿QUÀNVÂNW̃„pèmÆNR´AMµDP·IU´DO·JQºNZ½MR½QY¾PT¼MT¼OU»QX¼QVºMW¶P\¹PZ¼W`Ä[^¿^hÄZ\Ă\fÄmùjmÇ`jËsr̉ssÍsùrnÆ\`ÄnsÎqnĐpt̀yzÏnqĐqsÊrrÂenÂioÀ^hºbnÅllº`j¾blºdrÍ•’Û²§Ú¨™Ú¢˜̃­œá»°æ¼¤à¼¯̃´¤̃º©Ư±¥ß¸¦Ø´²Ù°¨àº¦Ü³§Ú¦Ú²ªÚ·²âÀ±âļåÄ·äĺáƼἴçÆ·ăÉÁ̃À»æƲâõăÇ¿áÄ·ăʼå;ăȺæȸåʼăÊ»äɼàÈÂáƸç̉ÅçĐÅèÑĂèƠÆéÚ̉é̉Äîظɮ¨~*D~ ?‡#B”/D¤;H¹HR̀[ZÔd]Üofàvlå{næ}nä}lä~oä~tä{rá}rá|wàvpÜomÓbdÄXY¨FR,En=]<^<]>Z7[ 7f5~>›2F²DNËUSÖ`ZÚh`Üob̃viÜrãk^Ưj\Ük`àlbßreärhåwpæzmÜma¥>Ib:X>X<X=Z<X>`;iAj>hAgBi!EhAdC`@Z?^>gBfD`CY>^@dAfB`>_AVA_Kj%R…?a¬cwÇy}Î}È{|Ărt»nv¿psÉ€̉Œ}̉€Ô’Ơ‘~Ơ”‚Ö“~Ö‘ <J8I¡:L£?L¢;L£>L¢9J 7I¢:JŸ9J7L 4F«CPÂSXÑ`WÜnbâzeå‚mä‡pç‹oêoèsè‹qè‰té‹tçræˆoå|iƯpcÔcbÆRS³EP<SŒ,I,G•3J5J¡8K£<L¢<LªAN¨DR«BO¬BP­CR«CN®FP¬CP®AO°BN®EM²DP¸FMµGO¶KR¹NSÀSYĂQTÄSX½RXÀPNÂTVÂORºPVÀTZê©„æƒbÂEL±=JºDN·KT³HV´NZºRZµLT»R[ºLVÁOT¾NWÀPXºMX¾T^¼U]ÄX^ÂV`Ă`fÆ^d¼YcÈbb̀]cËjq̀jpÑot̉ztÍgh¿ajÂlrÏleÅioÔur̀jsÍorÍloĂchĂmn¾`j¾`fÁ`bº`j´\f¿t~Ó–Ư ‹â¸§Ư¬¢̃®ß°¤å´›à²¤ß¶ŸÜ±¦ß¶¨̃º«Ù­¬̃¸ŸÛ²¨Ú¨›×°®Ù´¯à½±à¿µà½¶ä³âÄ»äĹäƺáÇÀăÀ±åÎÁàĂÀ⽫áÉĂåɹáƽäȺäʼáǺáÈÀâȽßÄ·àĸ̃ĺ̃ĶàÊÂäÏÂæÔÈçÑÅéÚÎ́ÚÏë̃ÊăÑ¿£ft˜;J„ B*B8HµFOÊUVÔbZƯnfàvjä|lä~oă|mä€qä~qăztä~tàznßxoÜlgÓcdÇTV«CR+Er>^;\>^9\7[
-6^ 4m5‡"=Ÿ8F»IOÊVỦ`XƠj`ÚqbÛpbÚj[Üj\Üh[ßn`̃qdâtjåwlàvkĂRTt=V<V9U<Y=[=`Ed<j?f>h<gBfAf@cCZ>^BcBiDcBZA^DaCjBiF`@X@R=`Iƒ<d§`wÄy€Đ€€̀}|ÈxzÁrqºnsÇ~|͆}ÔŒ{ƠÔ|Ö|Ô~Ô“‚Ö‘}Ÿ>P¡<J¡:H¤<J¡<M 8L ;L¢>M¡<J6Hœ7Kœ7K§APÀOT̉aZÜpeâweå‚lç†nénæŒqèoêoéˆpéˆsé‹xçˆuä|ĩrdÔe`ÈVT²EQœ5M,HŒ-K–1J˜7M4F¥;L¥<Lª?MªAO«AL¬BO¬FSªDS®FT°FS¬DQ®DO­DV²FR´LX¸NV¹NU¼KR¾PTÂMU½OVÀSX¼T\ºPX¸JU´K\Îmdô»ÚuY¸BK¯BL·EO´HU¯KW¶KV·JV¼LT¼NXºKU½PU¾RW¾PWÅZ\ÂZ^ÄVZÄY_ĂZ^ÀZbÅdeÇ^d¿alÇhlÍop̉ppÓwnÈbcĂhpÆjiÈilĂhsÎtmÎjoÎqrĐmjÅflÆehÂahÄde¹Q`®Pd³ViÁ„ÖƯ™†Ü¯¤â°›àÀµà°¢á³¢Ü¦̃®—ܯ§ß¹£Ü¹¬̃´¢Ư¯œƠ Ú¶¬Ü¸µá»ªß¾·Ü¶¯à½­ăÀ³ß»°ăÁ±áżáżăÆ´ßÀ»ä°ăÊÁ̃Á»äIJáŽáŸßżâĵàµàÀ¹̃µÜÊÄƯÇÀáÊÀàǺå̀»äÎÆæ̉ÆçÓÈèÔÄëÜ̉îßÏëáÊÑĺXft='C2H¯HRÈZ^Ôd`Úmfßugăzlä|näzmä~rå}nâ~wä|rá|t̃xpÜniÔb`ÄSZ©DT.Jr?b>`<_:`:\ 5\ 5] 5l5‡$> :G³HNÂVX̀vỷ“ÖŸ Ö£¤ĐÙi`ÛndÜ„}ăzjäwfĐcZ'D[=YAW;[@Z;`Bb@h?j$Ig?f=iEhDdB_C^Bd>fDeE\?\BbBhBi!Cb>X=P 9T@r*S›Ut¿t|Ñ}~Î}~Äx{Ápw¿prÈzuшÓŒ}ƠŒÖ‘|Ô‚Ô|Ô€Ơ|ƠŒ|¢<L¢@P ;L¢:H <N>O¢=J =O:M:L0Fœ4G§>P¿MP̉d_Üpdáxcähç‡nëmêŒrê‹oé‹sésêoévçtä}ĩr`Ôc\ÇSV²FT4N.J+G”2Lœ6L¡7K¦>N¨>N¨:L©>K¬<J¬BP¬AO±FR°IV«BQ­DQ®ET¯GX²MZ²LY¶GQºLS¸PW½KRÁQZÂRVÀRV½LR¼LT¹IX¹Q]èªơ¯Íb`°?R²IU®HY²FSµFV¹GOºNWºHU¼PWºNTÀPTÂOR¾PUÅSVÄV]ÅYaÂR[¿[b̀aaÆ^gÄblÉioÊin̉sqĐhgÄfnÊkl̀ihÄhrÉnkÍlhÆlvÍruÍpuÅmrÈbg¶^lÂce²P`ªOd´`p̀˜”Ư¦™Ü¨Ûª á¯•â¯£ă·œ̃±¨̃¦œÛ¯¡Û¨œß¶Ư°¤̃¬™Ô ™Ó££Ü´¨à¾´ä¿²̃¸²á¾®̃¾¶Û·°à¶¦ß¿¸̃À¸äĶăǾâÇ»âöƯÀ¸âƹâÆ»àÄ»åƶàƺ̃Á¶Øµ¯ÚÀ·ßĽàƼä̀»äÎÁàÊĂâǸàɾâÍÄåÎÁäĐÅåĐÇêÖÆéÜÓîàĐîßÄË°¬}"B~ C’0IªFTÈXXĐccÚldßxoäyhâxläyjâ}pà|qă{qä~tă}sà~wÜplÓ``ÄX[¨FUˆ+FpD`;]>a:_:[7\6X 5Z
-0g7+D¤UkÉ ¤àÀ¶æÏÄëÔÄî̉ºàĴԠܯ²ăĂ·â”ŒÖmd¢8Hb?V>U<Z>ZC]@^>fBh@g@gBdBg!Fi"Jf I^DcCf@b@^>ZAaDhEgAd?`=Y@T@h"LIj·n|̀~|ĐzÈvvÄpt¼pxÄvv̀„~ÔŒ„ÔŒyƠ~Ô„ÓŒ}ÖzÔzÔ~ÖŒ{<NAQ 9K:JŸ:Kœ8Mœ5G 9Jœ4Gœ4F3D3G§>M½OTÓ_ZÚnaàygæjç†oè‹nèsèˆpç‹sèˆoéˆqè‰tèˆräzcßpdØe`Æ\\²KV8L,I-H˜0H2E¡:J¢<M¨<K§;K§>L°@L«BN¬CP¨@P«BP©BQ©>NªEV¯GX°N\³IT¸KS¸IP¸LS½JR¾OW¼NT¿NTÀLP¼KT¶FVÈ_^úÅ‘ïwÏYW®>R²GT³HV±ER´GR¸HRºMX¹NXÀPX¾PX¾LSºJUµGV¹NZÄX^¾T_Å[_È\aÄ_cÍfaÊafËhlËfhÄejÉnnÍvsĐpoÉlkÎjeÇdkÅlpÏljÑqnÆ`c·P[º`j¿\b´Ve¯Pc¼u„Ô‘ÛƯ«¢̃²¦àµ¢ß¤–⬔ڣœß«•Ư³©Ư³©Ü¹­Ù¡–וŒÖ—د¨ß² ßµ¬â·¦âº°à¾²̃º¶â»¬ßÁºÛ¸±â¼®âÁ¸ă¼¯ăƸà»ß¼̃À¸ßÄ¿àÀ´à·̃¼´Ü½·̃ƹƯÇÁà¶áõáǼàÈ¿ăÈ»âÏĂàÊÂà²ầ¿ầÅå̀¾å̉ÆæÓÇêƯĐ́àÑïßÆäÓ»CZy>‘2H­AQÄWXÔf`ƯndƯvpâyjâyjá{jä|nă|qä|mä}näxmá|t̃okÔcaÂZ_ªBP0Jp?a<Z<_=\8Z:T
-2O 4N 8\Bœj~ؾºèĐÁîØẮѹâÀª̃»¯̃ºåÍÂíÑÂîƠÂæÖÀÄ–lBVARAVAX?\F[>cBi!DfAgBe?hBeDf$HbB^@fDdE^?_?^Ad@h Eb@\<V:\Fk$P‹Af²gzÈz~Ï~zÎzxÆvxÀpvĂxz΂̉‰€Ơ‚Ô~Ô}Ó~ÔŒ|Ó~̉ỷ‰zÖ‹{˜8J™<L:Jœ<L:Kœ;L9JŸ<J =Mœ9I›2F4F£>LºMPÏ\TØnháwhå€jçˆpéŒtèrçqé‹uç‹vç‰wç‰ré†mäzeào]×dXÈSS²CQ™9Nˆ$B‰(F–.G˜2H 7JŸ6K 8I¦;M§<L¨>Oª<M¨?O¦AM¤@R§>L¨DW©BS«DR¯HR°DP´HR¶GT¸LT¸LT½NU¼LT¼OTºJP¶BP°BXÛ“€ûÈ’é‹cÀPV¯>P²HX´ER´BRµJT¸JV¼LVÁRVÈTX»KVÁNVÀPX»MX¼R\¿X\ÂS\¿P_ÉaeÊajÈclÍhhĐnrÎknËgiÊdkÑss̀jiÇZ^ĂfnÎjhĐopÎkfÄ[^°Ub´\f»W]²Sc±\nÆz‚Ù›Ú¡–Ø™–à­•ăºªá°œÛ¨Ú‹ØØ¢˜̃±£̃¸«Üª˜̉Ÿ×¨ Ü´¬à­™Ü²ªß²¢Ưº°à¸ªà»°âÀ³̃µ­á¼©ß½´àº®à¼«Ư¼´̃º¯âĂ·àļܽµ̃¼°Ù¹²Ø¼·àǽáǾăĂ³æÊÀßȽ̃½´áøàȼàÉÀâʾáÍẴÈÂáÊ¿äÍÂáËÄäÎÂåĐÄçÓÈ́̃ỐÜÎêÛÀ²ˆx@Œ*C¥?NÂRVÑcaÚlißwnâzmâ{lå~lå~nă~lä~nä~qá|rà{sƯpnÑcb¾VZ¬ITŒ/Jn>\?\<\<W8U 8P 6L?XEŸ|ƯɼíÔẤ̉ºæÀ¨Û²¥×¼¸àÊĂåÎǼÖÈ́ØÏíÙ̀îÓ¹Üijj,LLARDTBVB\C]AfAi"EfDbBh&Lg F`BbBbBcDfDdE_B]?`Dj"Fl(JaAW<P<^B~5Z¦_xÅxÏ€Ï~yÆv|ÂtzĂtv΂€̉‰~Ô‘‚Ô•€Ơ‹}ƠŒ~Ô}ÔŒ~Ó‰~̉‰{Ô‰{Ô{œCV›:Kœ:L;L8I6I¢6G 9H¤8F6H2Dœ4H¦:I½JỎ`XÙh`âxfælæˆné‹ténê‹nè‹pæ‰xé‰mætè‡näzdàp`Öe\ĂTV®CR/H†&B)E“/H–3Jœ2J8J¢;L¦<O§<N¬AN§@N¨>L¨@L¨?N¦<Lª@P¬CO«DN¯HV±GV²HW´IR´HS·HQ¼NX¸KR»NR»FN°CV¸NYñ¼—ù¸~ă}eÄRV²BT¯@P´BO¸HR¸HU½KT¶M[½LQ½RXÂPTÀPYÆRVÀS\ÀU[ÂX^½YdÂZ\Æ]eËdc̀egÊ`dÏnmĐghÇclÇmkÉ\`Â]dÈjkÎljĐolÍhe¾[cµ]e¹X\­GXªI^¹j|ÏŒ‹Ø‘‹Ø–̃¬Ÿ̃¬ß¡Œà±£ÚœÙ¡”ؤ֠™Ú¤’Ù¢‘טפ¡Ư³¥ß²§ß®™Û®¦Ü¨˜̃³¥ß¹¬àº°̃¶¨à¸ªƯ»²̃³ªâ¾¬Ú¸³Ü¸®à»°Ü¾¶̃¼´ßº¬Ö´¯Øº¶Ư¾¹àÁ¸ăƺâȺáÄ»ä´âʾàǽ̃À»áÄ´àȾßÊĂáȽâËÂàËĂßÈ¿ăÊ»á̀Ää;äĐÄêÖẾß̉êßÊμ·…4N‡(C 9L¾OTĐ`\ÚjaƯtmßxlá|nå|læ~nå{jă{oåqâ|rß{rÛqjÔdb½RV§BNˆ(Dm=\;W9X8R 4M8J<f4Y°™¨à̀½íÙÄèÈ°Û®˜Ö·±àÉÂåÑÈ́ÚÎï̃Đ̣ßÎơâÑôäƠđàĐèƯÂi‚HBNBSAYBXAbBg"Hi@c?dAi Ff EbCbDaBb?f@a@[BaBbBh@dCaAV@V>p#NœQm¼t€Ï€„Ï}}ÊwyÇtwÄtxÈ~€Óˆ~Ơ„Ö‘Ô’ƠŒ}Ñ€̉~Ô‹~ÓzÓˆ{ÔŒ|Ô‰xœ6I™:OŸ8I:L =M¤=L¢<L£>N¦=J ;M9KŸ1Fª<L½PTÎ`Z×j_àubäjè†méŒtêpëŒrêqêsê‰rèrç„læ|fÜqb̉_XÇVU°BJ—.J‡&DŒ&E+E’0G4I :L¢:M¨=L¨BP­?J®@L®?M®BNª@RªAN¬CR¬@P­AP±FT°GS¶FR¸HRµJR¿KR¿NU»PUºJP¸KU²?UÈf^ûÎô©vænÊXY°DT®BR±HU²FV¸LU¾NV¶FS¶PWÂSZÄLPÂR\ÀQXÄWY¼SaÄ[_ÂR\ÄaiË`bÉ^dÎhiÎa]Æ\bÄhlÈc^¶O]¹`lÏmiÎiiĐkhÊbcÂZ_Æhg¿S\²L\®M^ÂnwØ“‡Ù›–Û•̃¤ă¯œÜ—ˆØ‰Üآ֘ؤ٫œÖ’‰Ñ“‘ל—̃®›Ü¬¢à°Ùª Ư°Ü´©Ú®¤ß¸¬à¸ªÜ´©Ư¼µà¸¬Üº±Ư²«ßº¬Ú´°Ü·¬Ú²£Ù°«×´²Ư¿¸âÅ¿âÁ¹à¹â¸ăÆ»âźßÀ¸á¾¯âǵßÆ»Ư¼²àÄ´àǼ̃ÈÀáȺßȼßƼƯĂºßŸàÇ¿âËÄäÓ̀êÜ̉ë̃Đáת‚‹‚&C4G½NQ̉^XØnhÚ|qßznâ~lä|hănăpă~lä|mâ}q̃|rÛskÑc_¾RT¤CM,Eg:V:R9O8I9K?{Mm¬²æÏ¿ë־⼥ћ‘̉º¹åÏÂëƠÈ́ÙÉïÜÊïÛÊïÙẸ́Ú̀ôßÍøæ̉óæ̀Ŭ­LFNDP@U@Y?^?bBfDgCiBh>`@^>^>b@c@bAX>[AcBh DfAfD[@ZAj$ODeµj|̀ƒÓ€yÍ||ÅuzÂvxÈ||І€Ơ‹~ÔÖ€ƠÓ€Ơ|Ô‹‚̉Œ€̉‹~̉Œ|̉ˆ{̉‰{Ÿ:Lœ:KŸ;K ;J£;G¢<L£<K¨>Q©?L¤8G ;K¡5F§?JÀOPÑ\XÚiXáveäfèˆrépêuêtérépéqèˆpç„mæ~gƯpcØbYÊQQ­=I—2E‡&D‡'C(B’,C3G¡;L¦AL¦:Jª@M®@M«BP­BM­DR­BP°@M²@L®CQ¯@M°EO±HP´IS¹DN¼FNÀLPÀOS¾NU¹NW´GS´BXÓˆ|úÍ—ö©xáuaÄKR¯ER®?Q«BTµDP¶LVºDOµJVÀRVÆX`¼KTÀPUÂNZ½V\¿TZ·P`½`iË]bÎffĐhgÄXZ»VbÄda½PZªN]Àdh̉ig̉kiËghÉccÄadÄ]Y½QU´MZ¹P`È{}؋و̃¦–Ư¦œ̃¢–Ư›Ø‘…Ơ‹†×ˆ×”Û´¨Û¡”Ô•’צ Ü¥—Û©œÜ‹Ù¨“ܪܳ¤Û¶®̃­›Û·®ß³£̃¸ªÚ­ªáµ¦̃º¸̃º¯̃¹®Û²«Ü²¡Ö¬¦×®¥Ư¼·äÁ¶á¾¸äÁ³áÀ¶àÁ¶âÄ»âĻᾱàÀ´ÜÀ¶̃»¯àÀ¯Û¾´̃¾°ßǼâȾ̃ļ̃ĽàÈÀƯÈÂÜÈÂáÎÅáÉÂâËÁçƠÍé̃ƠèÜËÖǼQf˜.F¹HJÏ\X×jfÜnlà…zâ~uå~qç€jæ€oå~nä{nâzoßxnÜohÍcc½UY¤=K|=]5N8I 4I<RF“j†̉¼èĐÀé̀²Ö©•̀•“ÚĂ¾å̉Ä́ÖÇíƠÅëÔÁ́ÓĂëÓÄë̉ÅîØÈïÙËôàÎöè̀Ø̀Á`(LLEOAV@^C`CcBeChCgDa?dA[@cAf@bC\>Z@\@dBf>fC_DZBdL„8\¬cxÆw€Đ€~Î~~ÇwzÁqvÆ{|І€Ô€Ö‹€Ö~Ö‹~Ơ~Ơ~ÓŒ~Ó‰zÓ~Ó~̉‰{Ô|Óˆz >R:M¢=L <L¦:G¦<N¨;IªAN¨=N¦:H¢7H¤4E¬<J¸MSÎZUÚj_ávcåfèˆlëqêŕnévêrërêpé„iå|f̃qaƠbXÆPO¯@L—.EŒ0H-D.E‘*B›5L:L¨>M¨@P¯BO°DOªBP®@J°DN°?J²BN²@M±DN®@N³DNµEP´GP·JS¸HO¿KQÀPU¼U[¸V_¶FQ´GXüÆŒñŸzÜo]¾HT¬=P¨BS¯FV³GS²FRºHO½LUÀOSÀVY¹FN¹LWĂ[`ÀJR¼VbÊ^_ËccÍfkÇaaÁXc¾`jÂY_¸Pc¸\gÅcgĐhkÏhbÊ`^À\fÆc`¾RT´PW³LX®I`È‚Û•ˆÜœ‘ږߧ˜̃Ÿ’Ø”ÚØ“Ô’’Ơ—–Ú¦”Ö…Ơ’Ú¦›á¯œÜ«ŸÛ¤’ל“ٔߵ¨̃²¬ß¹«Ø°«Ư¬˜Û°¤Ü¬£Ư¶¬Û¬«â¶¡Ú»³̃´¤Ø¦¢×«¨̃½µ̃º´äº¨á½³á¿±̃»´à¹§á¼°ä¶à¹̃¼µàÁ´à·̃¿´Ü¾¶ÜĂ·ÜÀ¼àźáÈ¿áÊÁßƾß̀Äá̀ÁàËÅâ˾áÈÀàÉÁåĐÇçƠÍèÙ̀åÙÄÀ¢¦˜6L²CNÍ[VØiaÛtjàtă€ränçƒmæoæ‚oä~oá€r̃zpØlfÎc^¹NRœ<Jv:W 6H 6C<[(N¦‰ ÚƼé̉¿äÄ­ĐœÆ›¡×¼éÓÅí×Ǻ̉ÁêĐ¿ç;çÏÁéÓĂêÍ¿èÆ·ëĐẠ̈ÛÈ÷æÑăÔÀxC`JDRCYA]B_@a@c>e@b@cA`<`<d<^:W:V=`Da@iGiDcC`I\Dv&PŸRnÂt̉ƒ†ÑyÊzxÇvzÆwv̀‚ƠÔ}ƠŒ€Ö‹y׆{ÖŒ{Ô‹|ƠŒzÓ‹}Ô€Ô‰x̉‹{ÓyÖ‡x =P¢:N¢>L¤;K¥=L¨<L©?K¨>Iª>L©?K¦=L¤6Hª@L¼KRÎ]YÜiXăv`åfèlê’sêqêrê‘uëŕnêsè‚jæ{dÜqdÖbYÄTT®EM—0F‹'@)B‘,D•0FŸ5H¢;N¤>N¬@L¬CP¯@M¬@M®CL²EN³BL±DM²BL°DJµDK²EP³EL·HP¼KTºOWÁLPÁNR¼NT¹Q]µHY¹OXô¾™ú¼…ókÙoc¹AMª:L«@M¯FS®DS´JT¹JU¾PX¼PU´@L¬@P¿W[»MZ¿X^̀\_ÊafÈ^`̀b`À[bÀZ_¿OY¸VeÂ^fÑjmÍrpË^`ÂTZĂ`aÎfbÂU[¸PX¸LX´ViÎ~‚ÚŒƒÜ•̃ŸÜ§œÚ˜ˆØ…Ö†×Ơ–”Ü£Ú–Ô’Ú¥ŸÜ§̃‘ܤ—ܦ’ئ›Ø£Ú®¨à§•̃¼´Ü®¡̃¹«Ø®©Üª¢Ư§ Ú®£ß·¦Ù©©Ú¢–Ö£¤Û²ªâ¿¶ă¿µăÀµà¹²â¹¨̃¼¶á½°Û´®Ư®£â»ªâøà´̃¾µà¶àĂºƯļÜÄ»ßÅ»ßÆÀăËÀàǼàÅ»ßƶ̃ŸÜĂ¼̃Å¿ƯÇÁßÉ¿àÉÂâÍÆäĐÅèØÅƯμªev®BKÊYUÔhaÚulà|lă€mä~jç€oæ€jæ~læ€hß}õtcÖojÆZZ¶HJ—:Gg6J8F>o>a¶Ÿ¬ăĐÄ́̉¼̃º£Ê…Ê¢¨ÜÈÂéÓǼƠĂëÓÀèϽçË»å̀¾è̀¾åɸáŶáƽèÑÇïØÊöä̀çÛÅ„McKDP@ZAZB^Ab@b?fBbB`<`=`;b<\>V9]Ab?c>iAbB]EYCgH@d¶j}Đ‚„Ô‚~ÏzzËxxÆx{Ë~|ш׌‚Ö|؇zÖˆyÔ‡|Ô{Ơ}ƠˆzÓ‰~̉†|Ô‰xÑ~̉z×y¤<J¤=L¥?N¨AN¦=LªAV¨BO¨?L¬@P¨?K¬BO¨=M¬@MÀQPÓ^VƯfYáu`ä‚hèˆkêpê’qêqê“xêrëqéŒnéˆiåmàt`Öe\ĂSS®EN˜4K*B.G‘-F›1F 8J¥:L£>N®>Mª>N®@O¯CO®CR²EM´AL²@L³@J²DP´ISµHS¸GP¹IO¼JQ¹JR¿MSÀOUÀPTµFR²@RÅ[YüĐœø¹†î•qà|aµHT¬:M­GT±DR´HW¸MW¸GS´HR¨>Q®GUÂNUÁU\ÄY`ÄX`Ê\_Í]`ÀT]Ä^fĂY`µN`»ZkÉ_cÈ`gÏhgÈdfÂ]gÈbfÏjdÂ`dºRWµGTºYeÔ‹‚̃…Ú‹†àܜٔˆÖ“ŒÖ‚̉„†Ù›’Û£˜×Œ†Ø—˜Ư¦ß§œ̃ªÛ¡”Û›ÙŸ—Ưªœß²ªß°œÚª¤̃§˜×±¬Û©œƯ´­Û®¤Û´¨Ú¦Ú ˜ÙƠ­¨̃¸ªƯ³¬á¸¨â¾µà½´âÀ·à´¯à¶¦á¿´á¾®Üº´Ư²ªá¾®à¶ß¸߽°à¿µá³àÊĂàľ࿰̃¿±Ú¹«Ø¾·ÛľÜƼƯǾàŸ̃ÉÀàȾßÉÁàÊÂáÍÅä̉ÉâÖÈ̀¶¶±htÇXXÖcXƯtfàyhă}hå~iæ‚læhä€jå~lâxeÛscÔhbÁRQªBIŒ-D]:]#Jfʸ¸èÓĂè̀´Û´¡È––ΰ´ßÈÁé̉ÂêĐ¾êĐ¾èλèλäǹƯ»­âŸáÄ·ăȺéÎÂêÔÈïÚ̀ơăÈèÜÄ‚K`JDR@\C\D`GdDdC`8\:\9]:d@`;[@]A_>eBfBd>Y<U>[F|*Rª\t̀|‚Ñ„ˆ̉|Êz~Èt|Ê~шÔŒ‚׉׉|ÖŒ~Ö‡|Ô‹|Óˆ~̉‹̉ˆyÔ~ч|Ô‡xÔ‡}Ó~Ö‰y¨>M¨@N¦>Lª@K§BO«@J­DN®AK¯@L¬?K«>Kª=J­@L¼NRÑZXÚncát`å€jænênê’xêqê‘wépëlèlèˆpè‚gâveÙfYÆSW±FO4G0F’+E—0F4J¢8I¡>O§?L¬BO¯DN°AL­DP±BP±AL´CN´DN´BL±@L´EMºIPºFPºHM¹MS»MRÀMPÀPR¾MP¸JR³BUÑrhüÎøº‰ê’gÑ`V¼KS°@N²GR°@L´JT²GS²EN¤8Q­JXÀTb¾VZÄNYÆY\̀abËTXÄZbÉ\]ÁR^»_jÀ^dÄR]Ä\fÎhgËdlÊrtĐnǹghÆ`aºKR­DT¼ajÑxyÛ…wܛےڂڈzÔ†Ô‰„ؘ’Ö؇zÔ‡ƒØ–à«œƯ¦à¤•̃£œÙ£œƠ™ÛªœÜªœß² Û¨£̃¬œØ«¤Ú¤—دªƯ¦›Û²¦Ú£˜Ö˜‘̉Ú¤Ÿ̃¸¨̃­¢ß±Ư¶«ä»¬â¾¶â¼°̃»°Üµ°à´¨ß¼²à¼¬̃¼²Ư¶°â¿«âĂ·ƯÁµÜ¼¬Ư³¢̃º©Ö§˜Ơ¶´Ú¾´Ûº´à´àÄ»áĹßÆ»ƯÁ·àȼ̃žàÈ»ßÉẪÈÁäÎÄẳÏå̉Æ̉À¾Éˆ‘ÖbỸp\âzdå{bæ|aç€gæ~dä€já}fßwbÚug̉aW»PP 5D~&F†Ig¶œ§ÜÊÁể¿â¾£Ôª™Î¢ØÀ½äÍẤÔĂéĐÀè̀½ç˼äÊ»äƶßÁ¶ƯºáÄ·áĶäË¿êĐẤ×ỆÚÊơßÇåÙÁ€D]HBPB[C]EbHf"EfEa<_;`:`8]6Z8\=`>gBf<c<^:O 9M
-:fL–DcĂu‚̉‚‚̉€~Îx|Êw|ÈyxцÔŒØ|֌։|Ö‰~ƠˆxÓ|Óˆ|̉̉‹ÓˆzІÓ„yÑ|̉ˆ|Ô†|©@N§DO¬BL«>K¯@L°EP¯AL°?I°?G«<K®>Iª9G¯BJÂJỎ`[ÜjXáufä€gçˆpêxëŒpêréxë’qëwípêŒtècâxhØh[ÆRRµCN¡3F’+E•.E™.D5G¤=K¦?L¨?N®CN¬CP´?J¶GN´EP³BMµDP·JO¶EO³AJ³DM¶HPºKS¾KR¹LR¾LRÀRTĂOT¾PV·FR³>Wà‘yûÊ÷½ˆâz`Ñ\T»IV«=L¨>L®@P¯DO²CR®@R·KWÀO]ÈVZÁMRÅ[^ÀOR¿TYÇa]ÆR[´HXÁZaÈW`ÅZeÄ_gÎ`bÍgǹceÄZbÆ]`Ç`_¸HT¨<R¸eq؉|ØŒ„×€|ߌzÜœÔ}€Óxv̉}ƠÚ “Ô„}̉ˆØ˜Ü•̃Œ̃¬›Ü¡œÜœ’Ü­ Ư®¦ÙŸ“Ú ™Ü¦œ̃°¤Û¨£Ú¦–ש¤Ü£Ú°¥Ö˜’̉”“Óߦ–ß´§Ü¶ªÜ®£Ü§ ̃¬›ß¶¬àµ¤̃º¯à¼´à»²Ưº²ßº¯Ưº³à¼¯̃¾¸Ư·¬á¹âÅ·Û¹­Ñ–Ë“Ô´´ß·Ư¶ƯÀ·Ư¿¹àÅ»ƯÁ¶ƯĂºƯ¼ƯÁ¶Ưļ̃ļ̃øÜĂ¾̃ÆÂáÏÊăÏÊçÔÆ̃ÎÂÔŒƯjVâw^äydä{aå{eå}fă|eâydƯvbƠm^Ë[S°JUœD^¬y‰̉¼»éÔÂæĮ۶¢̉¨ Ïª¦Û¾æÑÄèÏÂèξæɹæɶæȹâĸ̃ĸ̃¿´à¶âĶäȼèÏÂểǼÔẸ̈ÛÎỗÅâƠ¿u9RLBTDZB\DbCgBe F_=d>`<b:`>]<bEcCjBhAc=T 8H8S@„5]³fxÏ{~ÓƒÎ}€Ëv|Èw{ÎƠƒ×‹~ØŒ€Ö‹~ƠˆÖ‡xÔ‡zÔ‡}Óˆ{Ó‡{Ô…xÔˆ{̉zÔ†zφ{ІyÔ‡zªBPªAK®BP®DM®BL­BN­EP¬EOªBL°@L«<G¬>J°@HÄHK̉\TÜjZáxiä€hæ‡tèrêqêsê‘tênísí‘ṕlê€iâvdƠhcÆVT´CJ£2F‘*B”0E˜0Gœ5I 5F¤>Oª=K®@L­BN±BO³BL±BN¶CMµHR²HN´CN±AL³AH¶DM¸OV¹JM¾LP½OP¿LMÂPR¾QT¸ET¶CVꬖüÊ”ô²~̃q[ÊSO¹OT¬@M§=K©>O¬EN±GT¿LQÂNZ½IQ¾KVÂPV¹AJ±LY½][¿NW·IYÅ^bÎ\fÆXeÉ_dÎ]dÈ_cÈ[^¼R]»Y`Ä`^´MZ©F]¾fqÓ|wØ‚zÜŒ†Ù€̉vtÔyoÓƒƒÑxyш֒Í|ƒỖ ˜Ü–Ú˜‘Ư˜“ܒܨګ§Ü¤˜Ư²¦Ø ˜Ø•ÚŸ’Ø£ Ú¬Ø¤¤Û§›Ú¦œ×“Ï×¢Ûª¢Û¦Ü¤“Ư´¥Û²«Ú°¦Ø§¢̃²¢Ư´®à´§̃º¬ß»²Ư²«á¾°̃Ă¹Ü¼²à¼®̃À¸àÀ´̃·§Ô”Ë’–̉©¦Ư¶§̃¼°ßÀ³ƯÁ»̃¹ßƺÜÀº̃ºàĂ¹̃ĂºƯÀµÚ¾³Ø¼¶ÜÀ¶Üľ̃ÆÀà̀ÄâÏÊç̉Á̃¸Ü}năv^äfädå|`ăyfâybßxbÚo[̉e]Ä^d¸sƒÎ¬°äÏÀèӻརƠ´¦×³¤Ơ´²ƯÈÁåĐÂç;çͽæʹâŶàÄ´äÆ»ßÀµßÁ³á¸âÅ·äÇ»åȽæÎÄíÓḈÖËñÙỊ́ÛẴͼf$DOET<ZB\@_?bB` Gd!He@b>_>^;^?eBb>h>f>_<P 4L
-:lL¤TrÄu~̉„†̉‚…Í|€Èv̀€€Ô‡|׋‚Ö‹ÖŒ|Ô‹‚Ô‡xÖ~Óˆ}І{Ó…|̉ˆ}Ó†zÔ…|ц|Ô„z̉„|Đ…{Đ…~«FRªDP©CM¬DM®FP±@J°BL­CN°BL®>G­@Q®;I´ALÅNOÖ\TÜk\ávdä€gè†lê‹rèrêpë”wê’ḿt́ńŒkè‚jâydØi`ÊVTºIK 2F’)A”,E˜/C6J¢4H¥<Lª@N±EP­FR¯DR²DO²DO³EL²?L±HP´CK°?H¯@H¸BL¹HN¸GLºJP¸NT¾LO»PVºIQ°@Q±AQó¿“ưÉŒđrÚfUÅSVÂRU¯ES¦<P±DQ°FUºHR»IP½HT²BP½LR¶BO³KUÄVYÁTZ¾V_ÆX^ÇT`ÈXbÎ]_Ëbd̀afÊYZ»U^¿^c¿VZµNZ®M]ÄivØ|uÚ„×…Ù†|×…€ÓurÎpwÏusÖ”ÊzwÆlvƠŒ‚Ư˜àœ‘Ü›–Üœ“ß –ڦ؜–ܣ֟ܙڦ–Ø¡ŸÙ”Ú¨™Ú¡ŸƯ°¢Ø¦ Ó†ÍŒ’Ø’̃²£Ü®¤ÛªŸÚ£Üª Ư³¤Û´¤Û¬¤̃¬¡ß¶§Ü²«ß°¢̃·ªÜ°ªß¸­àÀ¸àº̃ÀºàÀ²̃¸ªÎˆÎ”‘ر¦Ú¹ªÙµ®Ù¸³Ü¾´̃Á·ß¾¶̃Á¸ßÁ´àºß·ÜÀ·ƯÀºÛ¿·Ø¾ºÚ¹°Û¾´ÚÁ»ƯĂ¹̃ÈÂáÉÀäζܡău`æ~`å{bă{câu\ßyfÜveÖmd̉„Ô¬®ßɽë̉½æÁ¥Û² Ø´¤Öª ×»¶àÉÀçĐ¿æͼå˺äɹăķ߸ăŸáÁ´ƯÁµáĂ·âÄ·âĸäÊ¿æÎÂèÑÈểÇíỜđÙËđܾӸ¨QDNCVF^E^C^B`B^@b@c@^7^9Z<[<b@f=e>`>Z<O
-9]B9`ºfvĐ€Óƒ‚Ñ}|Éz}É|~ĐƒÖŒ€Ø~Ö‰|Ô‚ÔŒyƠˆ}ׇ|Ơˆ|Óˆ|Ô†zÑ‹|Ó‡~̉ƒ|Ó†{̉„zÑ…yÔ„ỷ„xªBTªCN°FQ°EO®CN­BO«CM¬AL°DO¬@N¯@N®BK¶GLËOLØ]S̃mXâwbâ{hæƒcèpéó‘t́–ś”rí’v́“rí“tègâxgØf[ÈWT·FL0D“.D˜-D›0F6H¤<L¥<K§>L°@M«AL±AN³FP²EM²EN¯@L³EL°DM°AN´@JµDK²DN¸HM½HLºJO¾MP¹KO³GQ®<R·LUö̀¦ù½ŒçfÖg^Ñb[ÀV[µFS®IU®AR´FRµIU¸>J®GX³AN¬<MºOSÄOSÀU`ĂTV»HU¾Q[Î^`Ë]fÍagÉXZ½KX¸TaĂZ^ÂS]¸T`´L\ÁkpÔpk×}Ü…xÙ€ÔspĐwvÔyxÓ…„Î|ÄgfËy|Öˆ‡Ú…Ư”…Ư˜Ú”Ü¢œÜ¢ÛŸ×˜‘Ô”•Ø”ˆÖ–Ø™˜̃±¢Û®®Ú–Ú¥’Û“ˆÔ’‘̉™›Ü§”Ú¥ Ü“ܬܮ¥Û¥Û©–Ú£›ÛƯ²¡Û­¤Û œƯ§—̃´¬Ü´°Ư¶²Ü¶°áÀ·â·áÀ¸Ù«¡̉›”Ѧ¤Ö¬¤Ú´¨Ø²©Ư¹¬Û¼´Ü¾´̃¼°Ü¼°Ü¼´Û¹­ß¿¸Ü½²̃¾¶Ü¾·Ư¾·Û¾º×½·Ø¶­Ù¼¶Ö¼¹Ø¾¹ƯÈÂâʹ߾³ăxbå|bæ}dăxZßu_ÜpaÛvqØ¢àĂºêѾæǮܱ–ض¦Ú´£Ô­¨ÚĂÀầ¿çξä˼ăȹâǶàõ߶à¶ßÀ²àĹàøâĸăÄ·âÊ¿æͽèĐÆêĐẮÔḈØ̀đØÉđÚ¼À˜’KFPATA^F]B`B\=]@dAc>_<\=\>\:b>g=e>`@]>hA€.U¬YtÊz~̉̉€€Ï{{̀wxÎ}Ö‡׋€ØŒ~ÖƠˆ~Ơ~Ôˆ|ƠˆwÔˆ~̉…z̉ˆ}Óˆ|ЇzĐˆ}̉†z̉…yσ{Ô…ỷ„x«CR¬FO¬BN¯?H®BL¯@L¬CP¬BL¬FT¬<J®BI±?G¼HJËNLÙ_Vßl^äxlá~lêˆfêpêlë“sî”rî–tí”tí”qípè†iăzgÛj\ÊXT´FL 3D•+@’*B™0Dœ9K¤?L¤9L¨@Q¬BOªDN­AN³EK°DN´@J²DO²EM²DP°BK²AI²EM´DM¸HNºIN»IN·GNºIO¯FRª<TÆb]ü̉ ø¿‚àƒp̃r`Đ]VÈYY¶FR¶GR³HV³JZ°BP³DQ°?P©@R¶NX±>Q¼NV¼IR®@T¸R^ÆX^ÂT`ÆY^ÆRZºJX¼W`Æ\a¾S_ºR`ºUèsv×yrƠwvÚ{oØv×|sÏuuĐvvÔ‚̉ˆ€ÀdiÈy~Ơ‰ˆÚ…ÙŒƠ€Ú˜‹Û¦¡Ú •×˜Ö’ؓהԒ•ÙܪœÛ¦ ß°œÙ¦£×‰…̉ƒ„Ö™•Ü¬¡Ü¡’Û’Ù¡›Ú’୘ܪ§Ü ”Û¤™Ø¤Ø’Ư¦“ج¨Ø˜Û¦–߸®àº­ß´§ßª–ß°œØ¦ Đ˜•Ö¬¢Û³¨̃¸©Ú² Ú²£Ø­œ×¯¦Û¸®Úµ¬ØºµÚ¼µÚ»¶Ư¶¨Ư¸°Û¶¬Ú´ªÛ¼´Ø¾¸Ø¼µƠµ³Ö²¤Ơº²Ô´¯Ø¹±Û»ƯźƯ„yâz]âzbăxfƯxkØܲ®âʼæͶᶜٳڵ¢ÙªœØ·´áʼæξæʸåǺáŹà´ßÁ¶̃À¶àÀ´áÁ´àĹâĸâƺâ¶âƺäÈ»ç̀¿èοêÏÂîƠÈîØ̀đÚÅïܼ§v|KCRJX"I^H^E`AbAa@b>\:\<Y9Z<`?d?fBfFeEmJ~$M›HhÁn|Ñ|€Ñ€Ñz|Ïy|Îzx̉„Ö‰~׋ÖÖŒ€Ö|Ö†Ôˆ}Ơ†zƠŒzÔ‡{Ơ‰yÓ†~̉„{ц~І€̉†}Ñ„zĐ…z̉€z¬EN­BP¯BN³@J®@L¬@N«BO®BP±FO­@I®>I°@K»GJËNKÖ_W̃lZâ{hä„nè‹qëŒś“ḿ–vî–rë”tî–}î–x́”vé‡jä{gÛiZÍXP²BL 2G’.F”.D—3I›;O¤<M¤<L«<K¯EO®@K¬@L¯DM¯BO±CN°CL²AL°;J±BI¯CN²FN²EK·JQ¼HO¹KO¶HN·FK®AO©7QÖ‚rüÑŸơ´~êkƯq\Ó_WÈ][´DN¸HP´HT²GU¹KX¼LW°HY¶ET´DU·LS¾PV´JYÀRYÈRXÉ[_ĂX_»O\¾Q\Ä^cÈ]dÅ\bÂU^¸Pc̀sv×€€Ôwt×€{×stƠsl̉rtÑvq̉ˆÈoj¿bkËx~Ø‚ƒÙ†~Ùˆ†ÚˆÙ”‘Ö’Ù™‰ÖœÚ—Œ×—Ö‘’Ù’‹Ù •×¢¤×†Üª™ÛÖ’‰Í€ˆÖ–Û¦™Û —Øœ—× Ù›”Ù¤ÛŸ̃¡Ø§¤Ú˜”Û­¢Ø£ ×˜’Ú©Ú¯ªÚªÜ´¥ÜŸ’֙ь֟›Ø¢œÚ¬£Ư´£Ø©–Ö¦Ơ¤œƠ¬¨Ô®­Ö³ªØº²Øµ±Úº°Ư¾¸Ư»´Ø²°Ú®¥Úµ¬Ø´®Ù³¯×¸°×·´Ôµ²̉¬¡Ô³­Đ²­Ó´®×¹²Ü²ۧ¦àqbßxdƯ†„Û°®à°èɴả̃·¡à¼¨á´¤Ü±©ÚÁºå̀¾èͽåƺâƸá´ÜÁ¶̃Àµß·ßµàµß·âÅ·äƸâĸâĶăĸáÄ·äȹæ̀ÁèĐÅî×ÊîÙÍñÙÄ́Ú¾‰RdOJRGXF^E`FbE`AaBb<Z<W 7^;`B`=eCc?dFp"Lz(P’8\±\tÎy‚̉||̉xyÎv{Đx|Ï€~Ôˆ‚ք׈~׈€Ơ~Ô‹‚Ơ~Ôˆ|Ôˆ{Ô†}Öˆ|Ö‰~̉ˆzІ|ц|уwÓ…xσ|Đ„zу{­BP¬FO¯BN³@J­CN¬DP®CN°AK¯EL±AI²@I²>J½CGÊPMÖ]VƯm]äzfå…lê‹nëmë’rï’pî–ś—wî•uî—~ï’rê‹pâ{fÜn^ÎUQµFL 6D‘+D“.C–3F?O¥@P¤8E©<K®@L¬DO«EP°BM¯@K±AJ±@L°BK±<I®@M­FR®BM²FN´FOºFOµFL¸GNµCJ¨;N¨:Oæœ~₫Η÷µémß~cÓh\Ê\X¾PU´BM²ES¬DS´IQ¶IX¸GRµFW¼R\µ@Q¹P\ÀLW¼ITÄY[ÄV\ºKX¿TbÈZbË_f̀]bÀOX´K]ËjrÖxtƠxvÔ}~Ù‚zÖqoÏhh̉tt̉„ˆÎpg¿aiÍt~Ù~uڄׄƒØ‚ƒØ“‹Ú™‹ÓƒƒÎ…Ø‚Ø”’Ø—Ú ”Ø™—Ø—Ư¦•Ô›–Ó„wÓˆш†Ù¤“Ü –ڌڠŒÙ£ Ú£™Ü¤Ú”ÜÚ܈٨ Ú–Û¨—ר©Ù¨¢̃³ªÜ®¥Ư³¥Ô›•̉™˜ØªŸÜ®£Û¬¥Û³§×¬¤ÏŸ Ö¤Ú´­ÙµªÛº²Ø²®Ü½¶Ù¸²Ú¶¯ß¸§Ú¶«Ø¬£×ª¢Ù°¨Ù´¬Ù³°Ö¯¤Ö´°̉±­Đ­«Ó®¦̉¶´Ó¯ªÔ°±Ö·«Û¾ºÜ’ۘ࿰èϹäªڪ‘ڳ߱߳ªăÀ·åǺæɸæɺäƸâŸàÄ·̃À·ß¶àÀ³ß¸àÁ¶áĂ¹âƼăǼăŹáĸâ¶߿±̃ÁµæÊ¿æÍÂéÏÄîÖ̀ïỤ́̀ÜÄäÖ¿v6QKDVH\D`BbD^@`FbG^?]=X:^=c?c<dBdGjJt%Pƒ1W£PnÄrÓ}Ó|Íy}Êv}Í~|Đ„‚ÖƠŒØ‹€×‰~Ó€Ô‚Ơˆ̉‡{Ôˆ~̉…|̉}Ô†|Ô„xĐ…}Ñ…z̉†x̉‡xĐ‚yц~Đ„{¯@N¬AL­CR³DN¯FP®AK«<I«CL®DP°?H±?J¶BHºHL̀QLƠ`UÜl\ä|dç‚fè‹ń‘q́•tî–oïtí™vï—wî–zî’xê‡gäzd̃k\̀WP¸HM¡4E‘,A+A–.Dœ5F¥6H§;H©?K®:H­AM®AN°FL°@J°BN²>I°?K¯>L¯DN®>L²AK³BL²DN¸FLµJP¸FL²BK©9O®<Pï¼™üΕö«v́˜jàxjÙhbÎZV¿LQ³HQ²ERºNS¶LSµFR­BR¶JVÀHQ½NXÅP[ÁT`¾S\ÇS\¿OYÁT\̀Y_̀_jÈY[¿MW¶K^ÈktÖz|ÔrsÖ|zØ~xÔvq̉pnĐqnÑvrÊnjÀafÍpyÖ}xÔ{}Öxx؇ؖ“ׄ̉…ƒ×…Ôˆ‹Ô‹‹ÚŒˆÚ¢›Û¨¢Û¨œÖ”—Ø‘ˆØ–ŒÏ{Ô––Ú¢˜Üœ’Ư¡‘Øœ—Ö•’ۜڨܡ”Ú›’Ø¡—ÜœŒÖ•–܋٨ל˜̃±£Üº³à²£Ü§™Ö¢Ø¥¡Ù§Ø¤›Ú¦›Ü«™Û´ªØ´­Ø³ªÖ¬©Ú°£Ø¶ªÚ·®Øµ®×²©Ú¸¯Ú±©Ú¦œØ¯¤Ơª¨Øª§×­¨Ø°¬Ö°§Ôª¨Ô°§Ó­¤Đ«¨Î£Ÿ̉¯«Đ¬¬Ô®©Ó±«Û¸¨Ư¹«ăÄ°çƭ⸡ڵ¢Ü¹¦Ü·ªÛ»²âöæɹçƶäÄ´ăÄ·âĶàÁµàÁ³̃À´̃¾®ß½²àÀ·àÀ¶ăŸáÆ»äŹäµâĹ̃¼¬Ưº­àöæ̀½èËÀềÀî×ÊïÙẸ́ƯÁÛŲ\AL@V@Y<]?^>`Ad#EdD]@Y;Z8`>d>a?dIk$Pq$P1\–Imºf{Ñ{}Ö~~̉x{̀wzÎy|Ï„‚̉‰„ÖŒ}ØŒ~Ø~ׂÖÖÖ‚̉‡‚Ó†~Óˆ€Ó†|Ô|̉†zцyÔ†x̉†|̉…{̀†}̉ˆz̉†}­FUªAM«BP­BN¬DPª:L«@M­BN­DP²AI³DK³BL·HMÅQRĐ^TÛl^äyaæ…gêĺ’rî–mî•xî›vđ˜rñ˜mî—rî’ŕˆiä{gÜkZËRO·IOŸ5G“,B+@—0B4D¦8Fª=L«:H®=J¬<L®@M¬GQ­CR±@M®>J¬BL®@L­AM¯CM±@I²@L´DM¹IO¶DN¶BH²AL«8N¸FRöÍ©üÇó®xêŸ|ăx_̃zcÏ\Ẁ]XÀLUÅVR·KT´DPµFV°CR»JVÀKP¾JRÂPVÍRQÆOTÈX_ÇbdÉV_̀]dÊ``¾P_²F[ÂhrÔuw×|wÔwwÔsq̉nn̉pnÔxv̉|rÂad½_j̀psƠxtÓuvÔ|Ô€ƒÓyÖ”ŒÎ|{Ơ}yÖ…‚Öْטؑڑܥ˜Ø“Ôƒ‚̉€Ö‹à›‰Üª›Ü ”Ø“‹Üœ“Û“Ú˜–Ú—‹Û¤–Úœ”Ü –Ø›‘Ö˜’הڗۨܦ¤Ư¨›Ø¤ŸØ¥Ú¨Ü©Üª—Ü«œÜ­Ö¤œÖ¦ŸÚ±©Ù²ªÚ¸²Ô¯©Ú²¥Ø¶¬Ù³¬Ø²®ÜªÚ«œØ¨¦×›”Ô¤Ö«¤Ö¯«Ơ°«Ô¤™̉®ªÓªŸÔ­¥Î¤Ê™ÈœÎªª̉ª¢×µ«à±俨߰’̃­̃½ªàºª̃¸°áöåÊ»é̀¼æÈ·â³⽫àÀ¶à³̃Á¶ßÀ´à¿°ß¿±ß¾°à·àĂ·âƸáøâÅ·äƸຮ۱£Ü¸®áĂºæɽæÊ¿êξïÖËñØÂïظ›L>O =X>[<_@]:cAb>[>\;Y<`Ab=f=gDdFbEn%R:c¬[vÊt}Ö~̉}|Đwz̀vzÑ~~̉‡Ơ‰€Ø×€ƠŒÖƠÖˆ~Ô†Óˆ€Ó†Ô‡}Ó‰€Ô†{ш€Ñ‡|̉†€Ñ†~̉†}̉…{̉‡{Ó…z°FW«AOª>N¬CPªDQ°AN¬>Hª@M¬>J¬=I¯@L³?G·ENÂQNÍ\VÙn`äxcæ‚hèsí”sî–mï™sî›sî–yï–rî™zï‘qê‰näydÜhZÎUR¶INŸ3E“'@’)C˜.E6F¢8H¥=LªAL°?I²@M°=J¯AK«@M°>K¯AL¯BN®@M­>I°@J´CL³BJ·EM¾IN´FN·BH®FR¨6NºLQøĐ£₫ʼnô¨qñ¡nä|c̃qcØj^̉`ZË\ÙVTÂNQ¼RX¸GR´HXºGR¸GV¼MU¼KV®>N¼QWÊTWÂTZÄ\cÈY\¼Va¶N[Ă`n̉qsÖvrÔz|ƠytÍlpËhl̉wwÔ‹„Ă_aÄhỏuvỞzỷzyÔ~|ƠˆÆsùpnƠ†}̉z~ØŒƒÙœÚœÜ’דԉֆ{Ö‡„Ô…ˆÚŸ™Ü¡”ÚˆƯ˜„ܜܖܙ̃œÜ¦˜Ú›”چܢ—Û˜Úœ‘ØŸ—Ö–’Øœ™Ú”Ú¢—Ơ œÙŸ˜̃®¡Û°¨Ùª¢Ø£Ø¦Ö¨¤×™×¦œÙ®¦Ø®¦Û¸°Ơ´°Ô®¨Ú°¤Ø²¬Ø© Øª¤Ơ¡£×œ’Ô  Ôœ™Ơ¨£Ö­©Ö­©Ô©¨Đ¡•Ï ¢Ñ¢™É–—ÊÇ™›Ô±¥ßĂ²äĂªƯ¬–×¥˜Ó¦Ûº¬à¼°Ư¼²âŹæʼè̀¸æǸäIJ۸¬Ü¼²àÀµ̃¿µàÀ±ßÁ¶ß»°̃¾´à¿³âø߸âÅ»ăĹåƸäÀ±Ù¨× “ܲ¥ß¾²äƼçȽêʽîÑÄîÔÀéƠº–^fKCR ;Z=[<]=^Db>dD\BX=Y=]<c<hAfB]<Z?u)TMj¿o}Ó|Ö}{Đy|Đux̀y|̉€~Ơ‚Ö‹ƒ×ÖŒ}Ô€Ö‹€Ơ‰|׋‚֌Ԇ€Ơ‡Ô‚Óˆ‚Ơ€Ô‡|̉‡Ô}̉†}Ó…~̉‰~ÔzÔ†{§AQª=Kª@NªDPªDQ¬CP«?M©AL¬@M¯AJ­?J¬=H²CLÀMLĐ\RÛn\âwaå…eêŒnëpî˜qî•rî˜uî”rđ—wï–vî’oê‰räv`ƯjZ̀[U·JM 4H”,C“+C™.FŸ3F¦;G¨?Iª@K®<K°AL´>J¯BN­?L°BJ²BN®@K­?L°CK°?J³@K²FN¶DN³CM´HN´DJ®BM¨7N¿TXùÔ­û¿…ô¬wét̃s\̃zc×h_ÖjbÈQS̀jbÆTSÂMN¶CN¼HP¶CP½P[¸FR°HZ¶J\ÁSXĂYdÀT\ÄPTºP`´L`Âck×rxÓjlÖwyƠzuÎlq̉np̀vwÑ€w¾Y^ºZfĐprÙ|tÖ|yØyvÔ‚~Ô†€̉ztÊgkĐpr̉prÔ‡‚ƠØÜ¥ Ù™˜Ø”ˆÖ‹†ÎptÖ†Ư¤—̃ —̃ ”ÜƠÛŒ{̃Ÿ‘Üœ”Ü̃¢•Ư§Ù›–Û–’Ü ‘Ú•×›˜Ø™’ׄטڗ•Ü›Ù§Ư¦Û¦˜Û£™ÚÖ¨¡Ü¬¢Ùª¦×Ÿ›Ú¨–Ø®¨Ùµ­Ú¶­×²¬×¨¢Ù¢™Ù¦¢Ø©¤Ö®ªÓ¢£Ô›”Ó£ Ö˜•Ö«£Ơ©¦Ơ¨£Ï–̀ ŸÉ…Å‘”Í¢ Ư¿³ä®̃³œƠ’Ơ£˜̃¹®̃º®à¾²àĹăǸçǶåƸăƶă²ܺ±Ü¼³̃À´àÀ¶àÁ´̃¿´ß¿´à¾´ßÀ³áĂ·àĂºáƼäĂ·åƶäƹץ˜̉–Œ̉•Û¥”Úµ«æƺäĶæƸîÑÁíѺáÉ´o,HQ@T<X:Z:\<`Ba>c$L_&LV;`>a;eDhDcDY@ZA„3\®cyÏ|~ÔƒÑz|̀v|Ïz|Đƒ‚Ñ‚ÖŒ€×|ÖŒƒ×~Ö‰€×‹ƒÖŒ×‹~ÖŒ€Ơ‚Ô‡}Óˆ‚Ô~Ô‹xÓ‰Ô‰|Ó‰|Ôˆ}̉†}ÔzƠŒ{Ô†z¬<J¬DQªFT«?M«=Jª@M®?N¬@M¬@L­DP©?Lª@L³DLÄQPÏ\TÜn[âw_è…ǵjî’ń—rî–uí™rí–uî–ví˜{́‘tê‡kåzaÜl^ËXW´JS 7J˜,D’.G˜4J <O£:H¦=K¨:I®=J°CM²BL±DN±@J¬>G°BN°CJ®>I°DJ²>H°?L´FO¶DJ³GNµIO´DN¯@I¨7PÅ\Tù׫ü€ô¨zí•jâ•zÜoØpeƯr`ÓaX×]VÑZS»HN»HQ´JV¶DO³ET¶IYÂRXºGVÀ[bË\Y¹GR«AWµHXÈlsÔxuÖhjÔtpÖurÑkjÓsuÑrpĐ€r²T_»\hĐnlÖyvÔtrÓzvƠ€Ơ|Đ„ÏopÍkt̉xzÔ~ƒÑxyØŒzц‹Ơ‡~Ùœ”̉‚€Ñ}‚Ԍۙ’ßƯ¡Úœ”Û”ˆÛ”ƠƯ‚Ưژܜ’̃œß¢“Ú˜”ØŒˆÖ‚€Ö”ˆÙ£–֕ֈܖ‰Û ”ڜܠ”̉֜ץ Ù¢˜ÜªÚ¯¨Ø­¤ÚŸ–Ú« Ú±¬Ø¯¦×«¡×¥ ØŸ× Ø¦¢Ø¤¡Ù­¨×§¤Ö˜Ô¡¢Ơ˜ŒÔ¦ÔŸ˜̀ÆÇ––Û»°æÄ®á¹Öª—׫ٶªÜ³«ßº±àÁ´æƶæƵäöä±ă±àÀ®̃½±Ư¼±̃¾±̃À¶̃À¶ß¿´ß½³ßÀµàÀ·à´ăĸáźâĹäƹăŶܰԔтӌˆØ›Ư¸©à¶¢̃°Ÿä¼®íʼêήƕŒT<P>U@Z@]>`@_?^;]AZ?\>_;`9_=`C_H_Hn!LœJjÀn}Ô€Ơ~}Ïy|Îv|Î̉ˆ„ÔŒ„ÖŒ~Ö‚Ö€Ù€Ö‹‚ÖˆׂԌ…Ô‹Ơ†yÔˆ|Ô‡|Ó‰|Ôˆ~Óˆ{̉‡|Ơ‡{ÓŒ{̉ˆ{Óˆ}Ô†}Ô†z¬@L¨AJ¨AJ¨BQª>NªANª>L¬@M¬=I¯@K¬>I¬?H´GPÄNOĐ`X̃o`ăzbæ…nëlî–ó—uí–ví˜zí˜x́“t́–vî‘xê‡iä|j̃jZÎXW°FP 2H”.F”*E˜3IŸ9H¥>N«?L¨?L®@L°?M¬HS®BN¯BO­@L²?K°BJ®@J®AN±>H°CN¯BL´DM³AJµEK¶BI±AM£5Q½VTùÔ®ù¶~ô¦uî™lî‰géhàwaàr^̃mXØj]̀Z[ÁQTÆPO»IP¨2F¬BS¼MSµDP¿UZÇXYÄRXµHT°FXÆdjƠtsÔsp̉mn̉fdÎnvÑmnÔ€tÆrr²P^»XfĐrpƠvuÙ{xÖz|ÑzwÓ‚|ÏvxƠ|{̉rỷ|×…‡Ô‚̀rx̀nsÖ’ˆÎƒÑtpÎ}„Ú‘Œß–Ư’Û“Ù‹ÚˆÚÙ•ŒÛ”×’‹Ø†Ü–ˆÚ –Ù–Ú‹€Ø‰×”Ö‰Óڀؘ؜•Ø˜ỞˆĐ“Ơ ™Ö™Øœ”ؤ؟™Û®£Ü®¦Úª¦Ö¡×§×§Ÿ×¡Ø¢˜ÖƠ–“Ù§¤×¨¦Ö§¨Ø¥›̉–ԑЉˆĐ–̀’”È“’Ôªä®æÀ¤Ú§Ù¬œÛ·¨Ư´¦Ưº¯à¸âĶä°å²âÀ²à¼®̃¸¦Üº«Ư¹ªÜ½³Ư½°à¼°áÀ´ß¿µ̃Àµ̃½²áõâ¸áÀ¶âŸăÆ»âȾä²âÀ±Ơ›Œ̉‹„͈ˆĐ‹‹Ö¤—Ø£–΀zؖḭêÄ®æϸ‹LWQ@T@]"J]C`A`@aB`A^@W=\8`<^9Z<^Cn&Vz0\Œ:_²cyĐy|Ó}̉zxÏwzÏy|Đ‚ƒ̉ˆ~Ö‹„׋،‚ØŒ‚Ơ׋|ØÔˆÔ†Ô‰}Ô‡~ÓŒ€Ñˆ}ÓŒ~ш~̉{Ôˆ|ÓŒ̉ŒÓ†|Ó‡t̉‰€Ơ†x¬@JªBNª>JªES¥<K§@O¦BN©@J©@Jª>K¬?L±BL³BN¿NSÏa\Ưoaä€lç†hëlí•rë”uí“v́™pë•sí’v́•ýléˆkæz`̃k\̀[V±GOœ6J’0F’.D˜.FŸ6H§>P¨>Oª>P®ER®DPª@Nª@N°BL°@L°@K®AL°@K¯@K°@L°EO°BJµBL´HP²@K²BL«?M¢7V¾`WúÔ¬úµp̣®{́fæ‰må€dÜ|jßpYØogÛdZØg]̉\VÆNS±@NªBR¯<L¬:M»NTĂRV¾OW¿MV³GXÄjn̉jnÖnjÔnmÔnl̀djÏjpĐwwÊzu¶R`¸VfÏjlÖpnÖyvÙxt×€{ÎwuËrrÍr{̉ttƠ„Ô…†Îrr̀x}ÍzÑtƠ~zƠ~xÏvÚˆzÜ”à˜̃›‘Ü•ŒØ؉܌‡Û˜Ü”ŒÛ™’ؖ׆„Ü€Ùœ‹Ø•Ù‹ƒÛ”‰Ù‹Ø•‰̉–‘؆ƠˆÑ‚‚̀…ˆÓÙ––ٜؖؓ–ؒژؘگ§Ù«¦Ô¥ Ó›ƠŸ˜Ö¢œÖ™Ơœ™̉–˜Ô”’×£ŸØ¬¢Ô Ï™™Ê…~ʈɋƠ¢”Ưº¨ă½¢Ü¨Øª—Û²ŸÛ´¥Ü¹°̃¾³âÇ·çÅ´ăÁ°á¾°á½¬̃»ªÛµ¬Úµ«Ú´ªÛ¸°Ü»°Üº°àÀ´̃¿³àÀµàÀ³̃¿²à·âÀµâĹâĂ¹äȼăƸäǺؤ”Đ‹„̓ђؤ—ؤ’ÀjhÆz€Ù—೤ææֵ¥^=TDR 8\C_"J` D`?b<_:Z:Z;b9d>\;\Bb Oy.Zˆ8d¦XrÈt€Ö|{Ó|}Đvz̀vyÍ€‚̉ˆ…̉‹„Ô‹€×Œ€ÔŒ€Ö€Ö„}֋׃֋‚ÖÓ‰̉€̉ˆ{̉‰‚̉ˆ̉ˆ̉Ô‰|̉‰€̉Œ|Ô‡|̉†yÔˆ}Ôˆ¬@L¨@K§;J¦>H£>L¨:L¥<I¥@J§>L§>Iª?L°@N°BOÅQRÓbZÜrbä{cè†fëṕ’rë”uê“ẃ”t锜“rê”v́ó†jæzcƯl\ÎXR±HPŸ8H”)D/H˜.F5J¥<K¦;Lª@N«?L«DQ®BN°@K¬@L¯BN¬>J®BM®AJ¬>H­@I±AH´DH´AJ³EN³AI°@Iª>MŸ4PÆl\ú̀œơ±|ó¥ĺ–qëgç†héẽobÛj\ØpfÛm_ÍXU¾FN³FS®@M¥8N²HQ¼LS»HP·EO²@TÇmrÔtq̉mjÎioÓifĐegÏlnĐppÊqo´P\¸ZjÈjnÓllÔllÖxt×€}ĐtsĐsrËloÑtrÔÎvpË~̀x~ÖˆÖ…‚Ơ{yÍjpÔ}{Û–Ö‚‰Ùˆ€Ü‰Ú‰‰Ư‡Ü˜‘Û–˜ÙŒÚ’†Ø–ŒÜ’‡Ø“Ø‹…Ö†‡Ø‚|ß ’Ø”’ÙŒ†Ư‘‚Ù—ƠƒÊ~‚Ï‹ˆÑ•”Ô“Ö™’Ö•‘Ø””ÛŸ”Üו”Ø—’Ô“”Ø¡–Û¬£Ø£œ×˜Ö“‘Ô™‘ƠÔӑӜԕ–Ơ££̉˜ÅŃΔ’Ù±¥åÀ«̃ªÖ¥–Ù­ŸÚª ̃²¨̃À¶âȼæÄ´æĂ²ăÀ°äÀ­Ư¹­Ü¯¤Ú¸­Ưº­Ü¶ªÚµ¬Ưº°à»²̃¾²àÁµàÁ¶áÁµßµàÀ¸âøâÀ¶ăȾäȽäǺäǵ⽭̀‡ˈˆÑ‰Ø£”Ø¥ÀkjÀnqÓ‹ŒÛ œß´¦èÑ´©v}P<P<U:X:]@d(K`$C^<[9X7^=h>c<\>_Fl#R~1\Ij¼o}Óz|Ô{Ôz{ÎvzËz}Đ„€×‰‚ÔŒƒƠƠŒ„̉€Đ‚Ö‡~ÔŒ€Ơ‡}Óˆ̉|Ô~̉ŒƠ‹̉†~ІÔˆz̉‡ỷˆ}Ó̉‹}ÔyІ{Ï~̉‡~«<G¬JT§=J¨@N¦>J¨BK©@L¨=J©>I©>L©@J­?L´DPĂSXÓ`[ßn^æ|dè†ièlëŕ–vë–rë–yë–t́–ví•x́’qêˆmæ|dßr`ÎYT¶FN 6H”*D“,F™0H¡8L¥>M¨=L¨BO©BP®BQ­AN¯@K­BN«;G¬>L®AJ¬@M®AN¯AJ°BJ±FQ°@I°AK¬@Jª?H¥8K2NÎziúÎú®jđ xîkçoæ‚_Ưrfæ{^Ùm`ÜfYÖpfÑ[R¼JO¸GT­CT¶JU½JPºLWºET®EYÆdlÖrqÑpqÔkjÏjiÊY`ÍinÏtuÁaa±ZhºXeÆ`iÓqqÔwuÑqr̉rpÓtoÎrtĐnqÔvqÉryÈqjÂgrĐ|xØ„…ׂ~Ö‚ÎosÏ{ƒÔzzÜÙ‘̉‡ŒÓ{ׂz؇ŒÜŒƒƯ£”ے؆ƒÙ„؆€Ø‚Ù‘†ÚÖ‹Û†€Ư˜†Ù–̉vq̀Ñ‹‡̉›–Ӌֈ֔׌ƒÛ–Ö—Ú”ŒÚœÚ”ŒÙŒØ”ؔۘכ•Ơ–˜ÖœÓ’•Ø˜ÔœÎ’̉”ËŒ‘ΈÎÈ”Ø¨ă¼¦â±‘ÚˆƠܯ™Ü°¢̃¾²áÁ²æȸæŲå¯ßÀ¯Üº¬Ü¶ªÙ¹«Ü¸¬Üº¬Û¸¬Ü·«Üº®Ư¼±à¾´ßÀ´â³ßµ߿¶à¸àĸßø̃ļâȼæÉ»æ˺äɸƠ˜‰Ë†ƒ̉’ŒÚ¢–× ÂpnÀw}ʆˆØ™”ÜŸă¶¤æ̉¼‚BTN <R<X;[<]AaA^A\=W<[<`@e@`<\AcLv.Z7a¯_wË{~Ö„ÔyyÍvyÎx{Í€|Ó‰‚Ổ‹€ÖƒÔƒƠ‹†Ơ€Ôˆ~Óˆ€̉ˆ̉‰„̉€Ó‹Đ‹„Ó‹}̉‰}̉ˆ~ш~̉ˆ|Ñ…}̉~Ôˆx̉†€Đˆ€Đ{Ô‰|¨>Kª@M¨?L¦=J¥>L¨>L¨>K§<I¦<J©>L®<Hª@Q³DPÆPR̉d\ân\æ|fç†jèĺ”që–v́–t́“yí”rï”oî”tí”pêˆjäzc̃n`̀]Y±GSŸ;P”-H“/I™2J¡7J¤:L¨=LªAN­@N¯>M®@K®@L®@K°<H°BN°@I®@M°BL³FN°DK²BK²@J°DK¬BK©<G¥8K¢1MÜ’súÄ‹óªzó©në™tëœmÜtjæˆdÚvoÜl\Î`\ÚpcÏ]YÊQUÂRW·MVµCR¸HQ¶BPºHWËilÔtvÔppÓnn̉hiÊfjÉeh̀mkÂgj³O^ĂajÉcnÓtuÔsrÖpmÔ~}ĐkkĐjmĐppĐytÈhmÅimÉrv̉~~ÑyzÓ~z̉poÎhoÔ}~Ú‰…׌Ø€Úƒ~؆„Ó†Ô€„Ú…~ƠŒÚنςˆ̉†”Ơˆ‹ØŒÚŒ‡Ư’…ܘل̉xÍyzÄw€Ôƒ×œ˜Ù‚Ú’‡Ø”Ø™Öׇ„Û˜‘Ù”–Üœ‘Ù“’Ø““؈֕‘Ö‹ÔˆˆÖ‘ŒÖœ˜Ó—˜̉‹Ô•̉“‘Ê€„ÉÇ‚ˆÔ”ᴢ䶟̃¤‹Ø Ü©“̃­Ÿà¹©äÀ­åÄ°çÂªă¿ªà½¨à¹¤Û¸ªÜ·¬Ú´¨Ú¹°Ü¸®̃º®Ü»°ß»­ß½¯ß¿µàÀ´à¸á¹áÁ¶à·âÄ·á·âÄ»âǼäÊÀçʼæʺඤ̀†ƒ̀†…Ô–ØÇwrÇ‚ÔŒƠ–‘̉Ü£œç̀³Ö¹§V@P@T?Z@\<^?_@^=^&MU<[<aAcB]@^Gj#Sy+Z NoÀo~̉‚„Ơ~}Đxz̀x}ÑyzĐ‚Ó‡ƒƠ‰Ö~׌|ÔŒ‚Ô‰~Ôˆ~Óˆ}̉†zÓ†{Ó†~̉ˆ€Ó‹{Ó‰€̉‡|̉ˆ~̉ˆ{Ї{̉Œ|̉‰{Ó‰|Ї|Óˆ}Іỷ‡zÓ‡z¦BUªBM¨DS©=L¦8F©=J¨?J©@L¥<Mª>K«<I²BN¼JR̀UTÚaXánYä|dç‡kéń”pé”sê–ní“x́”t́˜rí’tí’uëˆnæzg̃qbĐ[V´JR¢4H’,C.F1EŸ:K¤:L¨<Kª@O°AN«BL¬@O¬?M¬AM²@L¬AL­@J­<H«?L¬@G±@K¯@G°<I°BL®BL«:F¥5F/Lâ…ø¾…ø¶zñ¤{ô¯pëoéj̃v`éˆfÜtbßq\Ûj^Ûj\ÍUUĐZT¼LS¶JR°?O®DWÈegÊ`jƠjiÑlqÎfh̀glÊjpÎtt¿X^°TfÀUfÆ^d̉tpƠtrÔssÖuvÖwvÎnlÑmoÍvrÀ`gÁbǹkqÔzyƠ~xĐ„ÏpsÊgoÑ||Ù€؇€Ú„Ûˆ†Ô{~Ôx|ÚŒ‚Ø‘–Ñ~ƒÔ~ĐÎv‡Àsă™Ôˆ‘ؔؓƒÜƒØˆĐ€Å~‰Ñׇ׆ۑ„Ö’Ö‡†ÛŒ„Ø“Ú’Ø؈ؔŒ×‰×“ÙÖ”˜Ô†ˆƠˆÑ’̉‹̉̉”ĐˆĐ‹ŒËŒÅ‹̀Ú¬œâ¸¢à®‘ÙŸÚ¡ˆÛ¨—̃·¬ăÀ­ă¼©ă¼¦á¸Ÿá·ß²™Ù¬™Ø¬Ú¶¦Ü´¨Û¶¬̃»®ß»­̃¼®̃»­Ư¼¯ßÁ³à´âøâĂ·âĸá¸à·áĂ·âĺâǺäË¿åʽæ̀ºăŶ΃ȅ…̉–̉˜ÇuyʇԗӉ~Évẁ€†á´¥îÙ½¨tvLBO?V@XD^A^?_>]EU:^$KaBeBdB^E_Jk+X†8b³dtÏ}̉€€̉}|ÍuxÊvyĐ€щ„Ó‰‚ÔŒƒƠŒƠ‹€ÔˆÑ€̉†~Ó„|Óˆ‚Ôˆ~Ôˆ|̉‹„̉‰}ш̉‡}̉‹}Љ|ц}Ñyω|̉†|ч|щ~χ}̉‰Óˆx¨=K¦?J¨BR®BP­AN¬<J¨@N¨?M«@L¬@H³@M´@J¾GPÉTTÖbZàpaåzeæ…léṕ“ó–ú—ŕ˜xë™x́˜ṕ˜tínëˆpæ|f̃shĐ]\¶NT¤:N“)B‘.C˜-C6J :K¥>L§>L©<M­BL­=L®=J¬@N¯9G®?J°@L²AJ®BN¬AN®?H°>I°BN±AM«>I©:D£2G0Í°†ûÅö¸…ö¹yíœzđ©|èpæ“pâ‚jä~_ÜdTáycÙo]̉f^ÅLN¼HP´<L©<NÈgf×mkÑhjÇXaĐjhÈfrËdjÍrrÂ_b´WeÀZfÄ]lÓtuĐlq̉llÓutÖzvĐhiĐuẁipº[g½]l̀hqÓz}Ô€|Đss̉{uÈdmØyz׈ˆØˆ„Ö„Ú|ׄ‰Ö|Đ~ĐwӋΉ¢ÅŒ«¼…œ²¨v–¨j†¬by¯gx«Uh¹^aˆˆÔׄÚۈ،„Ø؈„Ø‘ˆÖˆ‡Ô†…ۆۖ؈ׅ֔“Ơˆ×’×Ổ„ŒÔ‘Ñ’—Í{΋ʄŒÅˆÊ…ˆÖ¤™̃³›ä¶ŸÛ˜†Ù “̃²̃¬¤ß¸¤çñå¬ỨܴœÛ± Ø­Ô­ŸƠ°£Ù±¨Üµ¨̃¸¬ƯºªÜº­̃»¬̃½°à¾³ßÀ´àĂ·àĸăøâĹâøá¸ß¸áŹáÅ»ăɽæÊÀå̀¿çĐºÖª¡Æ‚‚Ñ–Ñ’†ÇzzÎŒ‡Íˆw¾ed²Ud¿mvÙ˜é̀·å̉½t0HJ<R@WAZA`FaB`D`"LZEc!Hi,PgDc@aH`Gt&X›JjÆqyƠ€~Ö~|Ñy~ÎwyÎ|yÓ…̉ˆ~Ơ€×ˆ~Ơ‰|Ơˆ~Ó‰|Ó‡|Ôˆ}Ô†|ш{Ô…zÓ†|Óˆ~Ô~Ô‰}Ó‡~̉†{ш}чỷˆzĐ{̉‰~̉ˆ}̉̉ˆ|Ó†|̉…x¬>Kª@M¨@N¬BP¨AP©AM¦>P¨>J¯@J­BMµDL¸HRÄHNÏTTÚ`Xàm^åzcèˆiëŒŕ”t́˜t́•vî–ŕ—vî“t́•ṕmîˆlæ|fßqcÎa]°DKŸ5E‘*C'?–.Fœ4H ;L¤>O¨AQª<P«BO­BN«>M©>L¨<K«BO®BK®>J¬>J®CL°@I®@K¯>H°@H¬<H§:FŸ.E-Jé«úÆ’ü¾‚̣«xơ½†î”kí›pèiæißq\Ü~kánVâm̃hVÍb\¾DK¬3JÂSVÏbhÖjiĐhkÈenÄ[fÉjùom½\e³VfÁcjÄZfÓutƠqmÑkjĐll̉qr̉jgÎnrÉgi¿[lÅipÇfsËjrÔ€{Đ|ƒÎrpÀ_kĐkr×yxÛ‚€Ù„Ú‡…ÓyÈs~³^~´d}¯i‡®h„¸rÅx‡Æ‚È|ˆ°b~½zĂxz±v†•U|+VÍ~€Ú‚׈„Û€ÚŒ…Ö†ƒÖ†̉…‡Ó‹–ی،ֈ‰Ú‹ÖÔ„‚Ø…~̉‰‹Đ„ŒĐ‹Ó‹’ÔŒŒÏ„ˆÑŒÈ‚ŒÈyy˃̀‹̃¬–羦ߠ‡ÙŒØÛ­¥á¹§à¸­åº¢èÀ«á¼©Ü³ Ù²¤Ù³¤Ùµ¦Û²¢Úµ©Ü¸¬Ûº°̃»°Ưº°Ü½­̃¿²ß¾°àÀ´âÁ¶á¶âöâºâ¶ăĹáżàĂ¹ăƹâƼæ˽æ˾æ̀¾åƸɈ„̀“’Đ‹€Æ€Æ|r³TS¢MX>W°XfÅ{„ⶬîؼ̀¬T?K<P :X@ZDaDcD^A\DZ>bBl)LcDbFcNj!Q…2\²`vÏ}Ö‚~ÑxxĐyzÍz|Đ‚~Óˆ~Ó‹ØŒ~×Ô~Ôˆ€Ơ‰~ÓˆÔ†{Ô†}̉†|Đ…~ш€Ôˆ~Ô…{ч~Ó†{̉‡yшzÓ†uш}ЉzχzĐˆ~Đ…|φ~цzÎ…}¬DQª>N¬BO¨@N¨<J¬@KªEP©AM®AL±@M·HL¸FPÂHǸSUØbXào\åzaç†lêń–r픜—rí˜t́–xî”pí—nî’pîŒmå~g̃o^Ï[S´DL¢6H‘'A(C•0F™4J¢7K¡<M¨DR«BP©=L¬?K¯<Gª;J®<HªBM®>J®?L°AM±<J±=J°CL´@G¯BL®<H§8Eœ/G+Kꬂú̀™÷¹…÷Ạ̀¡wđª~êhè˜lè€\åjä‚[à|mèzVƯzkƠZQ¶ES¸HVÇ]d̀`aÇ^hË`f̀bfÇ`h̀qrÄag­N_¾\gÄ\fÏopØvrÔstÑkj̉nsĐloÑspÆfg¶VgÊdkËjmÍsỳntÑmoÎwrÈ\jÓ{ÔzÖvyØ{yÓw}¿dvDfŸP{¤\§Wv Ji—Eh”Ab¡Nm»gvÈm|¨QsÈ|…Ëx…Đ„·wƒ”Nzª^lËyÎƠچ؇֌‹½u€²uÂzÍz€Î~„Øֈ،̀yŒ¶i§ZxŒ7XÅ‚Đ†̀‡’Æv{Æ‹Är}̉–ഢ䰖Ư Ö—Ú©¢̃¶®á¹¬ä½­æ¾ªäº§ă¼©Ư¶¦Û±£Ú´¤Ú¸§Û·¬Ú·«Ú¸ªÛº°Ü¼±Ü¿µà¾³̃À±à´߾³à³â·á¸âƸâĺàÄ·ăŸâÄ·âĂ¹äǺäȽçÍÀèÏÁæʺנ–ΌΈ€È‚v²ZW”:G”1IAT¢H^Áv†Ö¢£́ϾíÚ»—_bM
-8J
-6Q
-7Y;\?_<\@\<\?]@f@lB_@`I`Mr&TLjÂny×|×|Đvỳv~Ï}Đ„Ó‰‚Ԍ։€Ø‹Ö‰|Ö~Ơ‰|̉†|̉†zш|̉‡|Ô…|ц}Ôˆ|̉†|ц|ц}̉‡{Đ„}ч~Đ…yÑ}Đˆ€Đ‰|Đ„}Đ…zĐ…uÍ…{¨BQªDR®?L¬CR¨>N«BP¨AS«AN¯BP¯BP¸CL½DNĂHPÊSV×d[àq^å{_è…f́ó”s딜˜ŕ—ś–sî˜tî˜nï‘sîŒnäƒpßpaÓ]T¶HL6D‘+@Œ$?–+@œ9K£8L¥=JªBN®AL­?L«BP¬AK­DN±?I¬>J°DJ®@K°?K±<H¯CN²AG±>J°:Dª>J©<F0Dœ,I檈øÉüÆŒøªyö”ïlæ˜tè‡`änæ~W̃vhèƒ^à{dê{XĐ_`ÆPUÊZ_ÄU^Ç[aÉ^bÅ^iÊ]dÊns¼]`¬N]¼XdÀ\hÏjlÔpt̉klÓpqĐhkĐehĐtr¾Z^¼XcÊhnÆamÊksÍrrĐ~‚ÇclĂ`lĐsvƠz~×€ƒÖ~…Đq|·To”Cmª\{Ä~Æn~ÅizºXp±[r§PnœKnˆ6^“>d–Oză”Ù’“ÛÔŒ¼wŒ›_”T‰’S…ŸZ~©Wx¶`sшڈӆŒÇ˜°z’V~»pˆ¹kˆÆx¸Œ±—^¢pw5pf O°mʆ’Âv̀xؤ–ă³à¦Ø€Ø–‰Û¦â¶¡æÆ´æ²æÀªâ¸¥à¶¢àº¨Ü¹ªÜ¹ªÚ¶¬Û¸¨Ú·©Ù¹«Ú»±Üº¬Ü½µàÁµàÀµßÁ¶áÀ´à·áÁ·âøăĹâŸâ¶áĺâĸâĺăÄ·åȺæÊÁèοêĐ¾Ü®̉•‰̀‡|¸h`œ;H‹3J–<Mœ<O¨L^¹anÖ›çÆ»ñÖ¸Ùº¢f:M :P8T 9[:a@^<]?Y?\;c>f>h D_G^Kh N€3\®_vÉz‚Ó}|Ô}zÎx|ĐwyÑ‚~Ó‹„̉‚Óˆ}Ô‰Ơ€̉ˆ~ƠŒ|Ô‡|̉‡Ôˆш‚ш€Ñ‡€Ñ†~ш~ц|Ї}Ñ„zĐˆ|цzшzЇ~Ï…yΆ}І}Đ„|Í‚zΈ|΃zªDN¨BP«>MªDQ©DQ©@O¨?M¬BM±BP­>N¶AJ»CHÆJPÑTQÜdXäpZæ{bé†ḱlí–vë–uï–qîpí—vî–ní—vï’pí‹lè€fáp^Ó\R¶HNŸ4D'>,E•0D˜0D8H¢<J©>LªAQ©@O¬=M±@L®AN±>K°AK³BK±=KµBP²@J²@L¶@F²=H´>F«<F¨4?-C+Iå{ù̉¢ö¶ˆøĂöªẓµ…đfç›uéƒ^Ûvdä}XÚpfè…bàp[ÜhYÊTWÀQYÂ\aÂT\¿P\Æ\fÈflĂ`d¬M`¶]h¼XdÎmr×rl̉nỉjhÎefÎnpËfj¼[b¸XdÄbjÊdiÈhnËjqÍnrÎmkÁ`lÎnrÔutÑzÓw~Ó{~Áh€«Rvºn‰Èo|Ín~¾]s¶Yu°Tq¢Ll›Ff—Df‹?ks&\N|À‰¤Ö” ÙŒ˜Ø–»l’¤h¦l f™œi™e™†J8^–Jh®a{°b·p‰¡Vv“Lq‹Cjl$Nw6]h$WFd„FpQIw4VÅ…•̀ˆ‘Û¦ă®›×€Ô‰€×’Ù§ Ü¶«á± ä¼¦ă¾¬â¼«̃¶¦Ư¸¬à¼¬Üº®Úº®Üº¬Úº­Ø¶ªÚ¹°Ü»°Ü½°̃À´ßÀµàÀ´ßÀ¶áÁ´á´á³á´ăǼăÆ·ăÁµâøăÅ·âøäźçÇ»éοæÇ°̃©Î‚Ànc©QR2E“:M—?NBS¤BVµ\kцⶬîѸéÔ¹LOO:N 9X?\=_>\;`<]9Y9Y:c?iCbA[B\In%R˜LjÁp~Ó}~Ñ~|Đx{Ív|̀|Ó†‚Ô‹‚ÖÔŒ‚Ơ‹Ôˆ€ƠŒ~Ơ‰~ÔŒÔ|Ô†|Ñ…|Óˆч~Đˆ‚Ñ…|ц~І~Đˆ~Đ„{Đ„xĐƒ|φ€Î…|Ï„{Ά}Đ…z̓xĐˆxÏw®@N«DP®BMªBQ¨@N¨JV§@P¬CR®FS°GP¶FL¾HOÈOQÔYVƯf\âq^æ~fè…h́kí•t́ví–qî˜vî—tî—vî˜uï“tîféiăo[Ñ\V³HQ7J*E$?–,Cœ2F¡6H§=K¥>Mª<Jª?M¬>I¯FQ²FM°=M°?L®FS°>J²@J±AM±?I²?K¸?E²@F¬<G§9D /Cœ,Pá~÷Ƙú̀ù°vơ¾‘ù¯u̣hå‹nátOÑaVáw[Ül`ë”bÖbT¹KX»KVÀSZÁ^bÀT`ÄcfÂ_a§FX²RbÁXeÊhmÓplÔllĐhkÎjlÍlmÊfj¼V`¼[fÈfl̀`fÊflËjoÈfkĂflÅ^hÍlt̉z}Đjn̉twÓz‚Áaw¬PrÂx‡Íz…Çlz¹\w›Fl›KnœMm‹<\0Sy(Ps&Qo"\Iz©¦̀ƒ–ш¼~§¢n¡¤r  \”R|V}@vr;tx=y†Wu9il.dn2`t0`n(Uq+W^NUHXLQAUDJH]"Q¾‡”ă¸ªÜ‘Ï‚{Ơ‹‚Ô˜œÜ´¤ă¿¬ç¿¬ä¹¦ă¼­â¼ª̃¶ªÛµ©Ư¹ªà½®̃½­Û·©Ü¸ªÙ¸¬Ù·©Û¹®Ư½®ßº¯ßÀ´àÀ³̃À·àÁ´áÀ³àÀ´âÀ²ăÅ·ăƹâĶäŹâŽăƽäĺåÈ»æư߯–Ïw¼po¬NQ˜;G“6G”7Hœ8Gœ<N¥FZ°TfȂ஥êƲêÓ·¾‚T:L 9T:X<_B_=]<^BX8[8`8c>h@^?TD^Hƒ<a­_rÏy|̉€Îx~Ëv|Ëvwу‚ÖÔ„Ô‹‚Ԁ׃Ơ‰~ÓŒ‚Ơ|ÖŒ€Ó‡~̉‡~̉…|̉†̉ˆ€̉ˆ}̉‡̉…~І~Ñ„zІ}ЇzІz̀…~Đ„|ĐˆxÏ…|·{Î…{Đ…z̉‚v°BQ¬BNªET®FPªEQ©BN¨DNªAN®BP´FPÀFJÄFNËKNÔTOƯh\äsYè~dé†í“lí˜qî–qí—qíwí–xñ—t́˜uï’ŕkæ~gâp`Ơ^VµLN4F.FŒ&A•.F™1E 7K¨?L¤>K«@M©?N«BN°BP°BL°?J®BO±FP°=H°=J²?L°?J³BJ¸<F³=G®?H±:C¦3Eœ*KƠy]øƠ¬û¹€ø¿‹÷°xô¼—ø³nî›q́ˆXÔlVÛeSËSPâ€`ƯhRºNY´JU¹LX¾R[Å\`Æ\`À[_¦BU®Nb½YgÈfq̉qnÎhjĐhhÏfẻkjÊmn¸ZgÂdnÊ`dÀhqÈdnÎll̀kpÄcm¾Zb̀jsĐptƠutĐnuÊlyÁ^q§Rp´i„Ên}̀q~¯\|˜Ah Nu¨UqœBe–Bg¤Pq P{ˆ;t„C†^–œb“²l©l•¤x¤h–P~v0gh*bd$Xh'et8td–€N~b Xp6kk+b^LZEYER?SGSGK>JH\"Vn‹Ö®£Ù–É}€Ï’•Ø°±ß¼²ä¾­å½¨ă»ªâ¸¦á½­̃¸§̃¸¬ß¸©̃¼©á¼ªƯ¹©ÜºªÚ´¦Ø¶ªÙ»°Üº­̃»®ßÀ°ß¾²áÀ²àÀ²à´ྰྮ⽭åǺåƸäŹæƽæÆ»åǺăÁ¬Úª’Çvd®XTDM—>L™@O˜9J™:G›9H¢@P BW±Xd̀ƒ‰Ư§è·¤î̀³ßìv/BY$IR=X=[Aa?a@\@\?V@a@h@g@aAX@O@bJ–IfÀoxÏ~Íz}ËvwÊsxĐ|{Óˆ„ÔŒ…Ô‚Ó…ÓƒÓŒ‚Ô‹€Ô~ÔÓŒ̉‹~Ô‚ÑЇ‚цω‚̉|̀ƒ|υΆ€Ï†~Ї~·}͆}Í„{̀„|Î…{І|φ|̉†z̉ƒvª?P¬EP¬EQ®HQ­FP¬AO©DP©AP²DN³@KºHOÅIOÉJN̉VRÛf\àr^é~`êf́“ṕ“pírï–rî•tï˜vî”tîuî“qílæ‚lârcÖ^R¹KQ0F&B‹)A”1F4H8N¢=N¥@P¦>L«CR¯AM¬>J®<J°BN°AP²BM²=J°BK³@L°@K´CMµAH²DK­>G­=E¥5C,IÀZNöΟúÉ–üµzô¾˜ü¾~ô³Œ̣¢jæ„eÛeVÊPLÑbT̉^QÍc^¾UW¹T`»R]¸NZ¿U]Ädg«FR®Rc¹Q^Â_kÔjnÏhmĐhmÏfj̀hkÊfh¸U`Â^dÍdjÊflÎjqÂeoÊdkÉjqÆ`hÄdpÓnr̉rr̉lv̉ntÆdt£Io±ZvËo|̀n|´`€˜Rv®ZyÀhz²Qh¦Jx´f¶j’¡^ƒ8m|1i~Bt„D}‚>ph—^…€9qv6kr4ke#Xh"`‡R†…X„k,Xi+bj,hm0dr5hWKRCN?K
-:RQONNQŒ`‘µ†ŒÛª“Ï}¿xĐ—̃¼µäĂ°æıåÀªä»ªà»®̃µ¦̃º¦Ü¶¨̃¶©ß·§̃¹¨Ü¹¬ß»«Ư¹¨Ù¶§Ú¸ªÛ¹©Ü¼¯Üº¯̃¾±ß¾²̃¾²âÀ°à½´àÁ´ß¸©â¿±çÉ»åÄ·æǸçÉ¼à¾¤Đ•{¯\VœEN™;J;I–<NCS˜<Lœ>K<M¢DR®Ta¸dqΉᩜ浢êÀ¥á¼“PTR;UBV:]@b@dC`=]B\DZ@^<hAf?\>SDQBr*S¨XnËwzÑ{xÍx{Èw~Ëx~̉ƒÔ‡Ö‘ˆÔ‹̉Œ€Ô„Ô‹~ÖƒÓŒƒƠŒ~ÔŒƒ̉‰̉ˆÓ‰~цω…Ï‡Đ†~Î…Í…€Ï…~΃~Ї~Ά{Ï…}ψ{І}Ï…|΂xÏ‚xÎ…xÑ„y¬CP®DN®ER¯HP°FN±BK¬BL¬=J®AM¶JR½HNÄFK̀LLƠWOƯcTàr`ç|`çń•ĺ–ŕ”tí”tí—vî˜qđ–pî—sî•sîlè€iăp^Ô`X¯GN 4F.D(B–2G›3F¡<J¦>L¥DQ­>J­?M«DK°BJ¯BJ®?I°DM²AL±@M­@K°BP¶?I²BK°<G±?L­<F­;E¨4B,F«9Kô˨ûÇøÅ“ü¾€÷·‹ưº{đ¦ví‘aÑ]ẀQR¿IǸqlÓk`ÄdlÄS[Ä[c¸S_»Z`°NX®MZ¾S_Æ[dÔlk̉kp̉hiĐgq̀hkÈdf¸Ze¼WaÆ\`ÉdnÎil̀jqËkqÄelÁXcÆ`k̉lm̉qtÏjoÑhoÉm{ªIl²a|ÂizÆewÀ[r¢Px¨Vy¿a¯V}¨W†œO€œXxƒ=h}7il"Vt*\u-\t+eƒFyXŒ†N†T~<y{2p€B‚V‹y<ir2hyAxm.cb$Uk>fn1h\!MVDM>C 9B
-:HD{Dlͤ›Ü ÈurĂv|ͤƯ¬œâ¼¬æ½¤â¾­áº«â»¬ßºªß¹¨Ư·©Üº©Ư¸¦Ư¶©ß»«à»©Ư¸¨Ư¹­Ú¸ªØ·©Ü¹«Ü¶«Üº¯ß¾¯Ưº°Ü¼±àÀ´àĂ·ăŵă°æƹéʺèÊ·äĂ©Æ‹r£MNBO“9L˜9L™9J–7Jœ<L AOœ=M¤BR¥I^®XjÄ|ً榖́ºœê¿ ¸s`s):V9V ;V9Z>bAb@c@_=^?[>_Dd=j?eCX@PBXEŒ?dºj|Đ}Ï|{ÍxzÉv|΀~Ó‰‚ׄؑ„Ö€×€Ó‹†ÔŒÔ…Ô‹ÔŒ‚Ô‹‚̉ŒÎрчƒÑ‡~Έ„ψш‚Đˆ€Ï‡‚΄~Đƒ{Ї}І|χ~΄{Î…~Ï…|΄|΄{уz°BR­DS°FR°GR®FQ®DP¬?K«>I®@M·FP¼DNÄFLÈMPÔXTÜeYàp`å~gèˆǵ“ĺ–tê˜ś–pî•qî™qđ–rí–víóŒnèƒgăoWĐ_ZµGN 3F)CŒ,B—0H›/Dª:G«<K¨=M«<H®@N°BM¬@M®BN¬=J°DP´BM°AN°>I¯DR´>J²@J²=H®>G®<Hª:B¤:E ,E¤/Gíµ€ù̀¢üÁöÀ”ü¼ö½’̣¥ræ‚dÚn[ÆKWÈY`Ư‰z̉lnÚ{fÆW`Ê^_ÀY[¬N`§DT·UeÀZdÎgfÏfjÔnmĐjpËlpĂfl¶Yc¿\iÈ^bÈbh̀dhÇhpÇhpÆdjÄ_dÆ^fÎjmĐmrƠjnĐjtÄ[l­Ji®[yÂhyÄhxÈfx´T|N|®f¤_˜T‚Ksv-Zk%RgNf RePhSlTx2m‹NŒ†O†’r£„EyR†Hz–i~;nZ‹X„]Lg(d\Vo@mwDyNCJ;OJD BMJ_|É¡™Ø–€º\d¾jvÓ¨¤á¼¨à°à°ß°Ưµ¢Ü¸«à»­Ư¹¬Ü¶¦ß·¥Ư¶£Û²£Ưµ¤Û´¨Û¸¬Ư¸¦Ü¶ªÛ·¥Ø·¨Ø¹«Úº­Úº¯Ü»¯Ü¼±̃À´â¾°â¸äÀ¯äÀ³æǶæƲܴ›³ji˜DT˜>NBR=N›>O9L—9I >M¥HW¬Vg±^o¿oỷ†…à簤뾣èħ°tmZ7V>W<\<\>_BcAa>`=^<]AX8b>f=j AbEXDUJl&S¢SnÅt~Ó}xĐ|zÇu|Êy~Đ„„ӄ׈ւƠØ€Ó‚̉‡ƒÔ‹‚ÓŒ„ÔŒ‚̉‹ƒ̉Œ‚Ñ‚̉Œ„̉ˆч·̉ˆ‚ІƒĐ†€Đ…|Ï„}Ά}І~Ï„xÊ…~̀†~Î…|Í„|χ€̀…~Î…~³JT°IR°GQ³FN®HQ®BN¯>J­AK¯?L´DN¼FLÂHNÈJJ̉WQÚdTás`äzbç†ièt́•nî”ŕ”ŕ–ŕsï”tî—oî“ŕŒlè‚gâp^ÖaX´FM¢6F1F,E–,F4E¢9J©=H§;K«=J¬>M°?I®@J®>J®BJ°@L¯DP°AL­;H°@H´BN±BI²;F¯<F¬<H°@H¦=Iœ6F™/MÚvúÉœøº‹û„ö¸‡üÆ~ñ§|ê…X×^XÔ`XÛwgØmjÖ|uĐ^^ĐspÄ^f²GV¬HXµM^¿T`ÍdhĐddÎlpĐhoĐhjÆfu¹P^¼]lÉ`mÆZ^ÊgnÍenÆhnÄgqÅ_hÅZf̉nrÓkmĐjlÓluÊap§Ffª\€»dzĂfỳjwÄa~¦P|’KzˆHtu1^s.`~3ly0hv.`lQdLh"TjSt,dŒT’ˆJ{•pŸ‚Bs|>uj"T:lˆAv†O†’Xx0ev<{v=xXRlAer@tF >C
-<@@d,fn„Ö®—Ô†v´[fµfuԢ⹠幜߮˜Ûª›Ù¬ Ø­ Ú¶¬Ư¸¨ÜµªÛ³¥Üµ¤̃·¦Ù«œ×±¤Û·¨Ü¶§Ù´¨Û¶¨Ø³¨Ù»«Ú¸«Úº°Ü¼¶Û»°Ü»°ß¾±Ü¿¶̃¿²à½²áÀ¯Ô«–º€x®p€§cx@V >L¤APœ:L˜<L<M ATªMb¹hsÊvwÙ‡̃‰|ă™‡è¨”é´–è¨͇g<VA]>[<_>`>eEd?fA^:^<X:]<dFj Cj'F`(PXL\N„;a·duÍz|̉|xÍ|zÇtxĐ|̉„Ơ”†×’†Ơ’†Ó„ÖÔ†ÔŒ~Ô„ÑŒ…̉Œ‚ӀόÑÑ‹€ÏˆĐ‰€Î…Љ‚͇πш}Έ‚щ|ц{φy͇~ψ€Î†}Ά̓~͆‚Í€x²HX²IVµKX³DP¯GW®<K¯BN°BN²BJ²AR¸BJ¼FPĂIM̉YUÜbUàr^æzcç†nêrë”uê™vê—té–ŕ”ŕ˜pë•sî“ṕŒnè‚găr]Ô]T¶HN 8JŒ*DŒ(B“-D™4H¢<N¤<Nª>K«=I©AL©?J¬BJ¯>I­@K±DP°BM®BL®AJ­@L®DL°?N²<I²@H®AL°BH¨<G¤4D'G¿_NøЬûĆơ¸ú»ö²…ơ®rä†jâ~\Ö\S̀dkÖwuÚvgÔ€{Đe_Â[g¦DU³PcºO_È_d̉jnÏfgÍbfÍloÆbf¾YbºZfÆ`iÈ]fÆ^hÊck̀jnÅdk¿ZgĂUaÎnsÑuxÍhnÎkmĐbjÅ`t™7`¾i€Èj|Éhx¾TnDo†7lp(^n&Zz3l…F}~;qq0^e MaHbJcNm Z‹L‚™b–X‹‰R€s2b]D`Sj(X‡Tt5h|6jIƒx=m^"RM EiDnb)ZB?< <YN©yˆÙ¡Đ~m·^n½v‚ר ă°–䶠߬“Ù¤”צ›Ö©ŸØ±¤ÛµªÛ³§Û³¢Ưµ§Ư´ŸÚ®ŸÚ²¡Û³¢Û²£Ü´©Ü´¨Ûµ§Ú¸«Ú·¬Ú¸¬Ù¹­Úº²Ư¼°Ư¼²à½²âÁ¶à¯ذ˜µ|u˜NhRm«v®k|¬Vg¤BP¨BS¡>T£J^´ao¾ksĐ‚|܉|ß‹zå”æ—æŸê¬”çÀ¤Ă“|m#>T <Z?^?^?`=fCeCiAb?^;[;Y=]8f?j"GbD`(T\%Tk(TŸRnÈt|̉}{Đ}{Èz|Éx}̉…€Ơ„Ö“†Ø‚ÔƒÔ„ÖƒÔ†ÔƒÔ‹‚Ô‚ƠŒ€̉Œ€Ñ|ÓŒĐŒ„ÎŒˆĐŒ‡Đ‹„Ή‚Ά€Î‡‚̉ˆ~Ï…|Ï…|Đ…~Έ}̀†χ{ІzΆ~Í{̀‚zÎ|±LZ´FPµJV°HU¯EP²FP³GS±BQ±BL±BN¸BI¼ELÆLN̉VQØf]àtaå|cç…dêpê”sê”mê”ú“së”o•qî’pílèeăs\ƠbX¸LSœ8I,D+F•0C2H 6D§:G¦<K§=J¨=L®?L¯?L®@M­<J®AK­@K°BK«@J¯CO®@K±FM¶>F¶BK®BK°BI¬>G¢:E›-E¨8Kñ‘ùƘú½€ó¯ˆø½ƒñ¬|̣¤mß}cÊmjÇ\ZÚ€uÓhẽyeÂhn¯HY®EVÀVbÆ_kÍnrĐfhÑhnÎjkÉen°O`´WhÄ\hÇboÄ^h̀]eÉ`fÇfnĂ`h¼ZiÍ_h̉jqĐgj̉km̉jlÏirÆhz>dÀh€Èfv©Mo‹>lv,`fRg!XJ‚‰Lzl'SdL_LbL\DfQ]L„;uj›œ]ˆ’Z~v2`]FX F`N‡[Fyl,eI|€LzXFJEHB|WŒqAƒHHg/Y®~†Ü‡Érl¼foɆŒƯ³®â·¢ăµ̃¯œØ©›Ö¦ŸØ©œÙ±¥Ù±¦Ú±¡Ú°¢Ù²¢Ù±¢Ú±ŸÙ¯Ú®Ù¯ Ø³¢Ü´©Û¸©Ú²£Û¶©Ø¶¬Üº¬Üº®Üº¬à¾°ßÀ³̃½¬̃º¢¿zFX‚B_”Xv˜Vv«u²x»ly´`o¾hoÉmj̉zà‹zâtæ‘wå“vá|æz蛄馒́À¤Æ‘~g6T>X<^<^=_<fCdAc@h@d?\C[<W8`7j@l!Bg!HZH^I€3Z²duÎx{Ï|xÎ{|ÊsuÏzxԀד„Ö‘€Ö“‚Ö‚Ó“…ד€Ô’…ÖƒÔ…Ó„̉ˆÓ€̉Œ‚ÑŒƒĐ‚·‚ÓƒĐŒÍ†‚φ€Í†ƒÑˆ|̀‡€̀ˆ€Î†~͈€Ï‰~Đˆ€Î‡‚Ά}̀ƒ΂{Ê‚|¶LX²GS±FU¯DQ°JU°DT²ER¯@L±BM°AM·CKÀAIÉKNĐTP×b\̃q`ä}hæ„lëq́’ré–së–qê”t́˜ṕ’sî•pî”ŕŒrçhâr`Ô`X¶JP8I*C)D‘.F™2H 4H¦<J¨<I¨@P¬?M­<K²AL®CM°BM±@K­BL¯AM®AK¬BN®>I¬<H®=J²@H²BL³DL¬BJ¥;H/Eœ,J̃lù̀¡ö»ûº}̣®‚ú¼ƒî vçœxà„ìqp×i[Ú€sÍ\XÄ\^³LUºPbÆTaÔhk̉ihĐilĐceÂ`j¸LY´L]Â]iÄ_jÉcgÉcmÊfj½ZhÅ]e¼Yd²UoÈnÈiuÊdrÑelÔhoƠr~Ên|§Fi»`v®Sl{0Zj$WdTw2i‹M|v6_^FXEZDdN`F\D`N\L‘Wˆ–W‡›Pt{2]^HdPbR‰W‘\o*`y;tz@q]IJ >RNI?€[f3g|<k½‡Ú–€Élh¶_j̀ß²¨ä¼«á¶¡̃®™Ø°£×¨Ô¦ Ơª Ø° Ø¬¡Ø¬›Ø«Ô©›Ø± Ú¬›ÙªŸÚ°£Ú±¢Ú°£̃´£Ư´¢Ûµ¥Ü¶¦Ú¸®Ü¹¬Ư½³̃¾´ăÀ®Ü¾¦Àv‚>H|<\‰Hk†=`•Uq”Nk¦j†´xĐ€„Ư€åˆuærèxæwæxå|è•‚â“‚è‹́ª”îĤԣŒj!<P;W;[;`>cAf Cj Db?dAe>_:aA]=a>d;j?a9W<VFdL—PmÀpzÑ|z̀zxÉ{€ÉsxÑ€|Ơ’Ù’„ƠƒÖ’†Ö”ƒ×”Ö”†Ơ’€Ô‚ƠƒÖ€ÓŒ„ӈςы‚Ñ„Ñ€Đ…Đ‰Đˆ‚ψ€Í…Ή~·‚Í…|χχ~̀|͇~Î…z͈˃z΂|Ë{µLX°MX±IT°FS°FQ²HU²HT­AM°CP³EK¸BI¾FKÁKMĐTQØ`Xâp\æzdéˆǵj́˜t́–pë•së”sê–ŕ–vî–nï”níŒpébáp\×`V¸LP8F)D)D•/Fœ7I¢6J¦:N¦?N§=L©?M©=K®@L®BN®BL±DN°BJ®DP®BM®@J¯AL¬AK°=I°CL²BL²CN±CM§<H¢3Gœ.MÊq[÷̉°úÀ€ö´úÁ‰ô®~ú¼‡ê˜p߇|å™t×rhâsÇ^]«AL¶P_Ă`gËdkÑknÎfmÔljÈen°JV«F\ÀWdÉ[cÈ`hÅ_jÆ[kÇ`iĂ_l¼Vd¼Wb»ly´dpœMhB_ªF]ÉasÖpxÊjv¤Dd’Bbv*Uh0^g$Zx8h„Ami"Pb$R[IWAh#Ph"OU :]FaPz;qlx.Z~4_dH\Gh X‰W‘”g“‡D|@{R‰TEO>i4vF @QJ„XŒƒKoÆ‹†ÚsÂdf¼hq̀’–̃­–廤⼨ܮ™ÙªœÖ¦›Ö¤Ô©¤Ö®¤Ø­¢×«Ơ¨̉§ÔªÔ§Ö¨×­œÖ¬¢Ù¯¤Ú±¤̃¶©̃¸§Ü´§̃¶¨Üº­Ư»°ß¼ªá¼¢̀¤ŒIG‚<YaI};X l‡”Sx—Tp˜Rvaz²|Ó‡†à„æwåxçtç‘vçvå{阃è¡î³•đÄ Ó£v(=R;V<V 8Z8b?b>d<jCdBdAfE`:^;]:^<e?g@^EVB^Os*T¬]qÎ{~Ñzx̀wzÉxzÎ{yÓ€×’Ø’„Ơ”Ö’€Ô‚Ö”ƒƠ“„Ö‚ÔƠ‚Ơ‚̉†Ó‚ЀЋ‚ĐЉÓ‹Đ‹‚ĐĐˆ‚ÍψΆ€̀ˆÎ‰‚̀‡Í†̀†€É„Î…~΄|Í„̀z²JW´JR´IR²IR²FQ³FP®EQ®EP³DK³EL³AJ¼BIÁILĐVTÚbWáo_æybç†lênë–pê–t́–ví–x́–rï•qî”pî”ṕˆlégâr_ÖbYºNR 8I(@+F’-Fœ7L¢;L¢<M¤?O¨=Jª=Qª>J¯@K¯@L«?K¯BM¬@K¬>K¬=I¬>J®BM¬AL±@G¶CH³DL·EK°FP«@I§9E/I´FKîÁ’öÆŸüÇö²ùÄ‹̣¢tă‡p袄ærߌuØmUÄ^\¬ATÂZcÊ\cÎ`fĐinĐkmÎce¿Xb°Rbº_lÄ[dÊ^gÈafÀZh¸ZhÁblÂ\g¾U`ÎhoƠlpÖjlÍhp¸[sJl<c¦Eb¸VkFeq(Tg%Xl-`{;ky0bm*[f"Xb ReLj%Su/^X<R ;\Fp)`†IvˆH{cGiMdOcP€FˆP€y4m]–^f&ZMGnF|nC{:>b6lª|¢Ë™”Ïzm¼_f¼cnÑ””߸­à²¢äº¥ß¹©Ö® Ö¦œÑ¤ Ø¨œØªÔª¢Ù¬œÖ©ÖªÔ¦—Ô§™Ó¨›̉Өױ¥×´¦Û´¦Ư²¢Û±¤Ü³¡Ư¸ªƯº¬̃¹£Ù¸ ¶‚jf;fD‘Mfˆ?jy,R­wƒ¢k†˜Tp¡d™Rr±t‡̀†’Ú‰†âˆ}è’{è”|ê“vê—|ê漣đ¿œÙ©v)BR9V?Y;^=^<a?f>c?e?c?c?d?`<[7_>`=g>d@]E^IdKA`¸juÍy}̀yyÊtxËvz̉‚|Ö„Ø’€×’…Ø•€Ö“„Ô‘€Ö”וƒƠ‘Ô‘Ơ‚ƠÓƒÔ‘ÓÓ‚ÎŒ„̉Œƒ̉щƒÎ†„̀ˆ€Î‰€Ïω~Έ|ψ€̀ˆ‚Ά̀†Ê„€Íˆ‚Í„{Í…|É‚´FP°JR³GS±IT°HU²DQ®DP¯BN´BO²AL°DMµFG¾FIÍOO×]Qân\æzcê‡hê’në•rëq́’sí–zë“qî”uî–rî•úsç‚nâr`Öe^¾KP6H&B$@’,F˜0HŸ:M¢8H¤;J¦>Lª?N¬;H¬=I­>Lª>L¯CL®CL­=L­>J¬>H¯@K¬>K°>K´EL¹EK¼FN¶DH±DN­>H¢9LŸ6NÎv[÷زùÂúÍ—ơ´|ê âˆĺ~å „äkÀ_]¨8H¶NYÏddÉdlÄ[f̀`bÊfm½R_­CV»boÅ`kÄ]fÉbfÀVbºYf¼UfÅ[f¾WeÊckÑflÖnqƠlsÇjt¦Hf-N˜Fb‰6_x,X{:ft8kn+^y3i„?|p1el*^f S^Lm'VNƒ^CQ
-<R >bR~>vx;bx4b^DbGbJh$R‰N~t*b€Cy‡No1gP Go>x‹xªQLEHiÆ“ŸÊ{s®ZeºftĐ˜á¸¦ç½§ä¸¥á³¡Ư´¥Ø¯¢Ôª¢Ó¦™Ô© Ö©œÓ¥›Ö«Ô©›Ñ¥•̉¡–̉£Ó¤˜Ñ¦œĐ¤˜Ö¯¡Ø´©Ø´«Ü¹­Ú¶§ß³¢à¶¥Ü¶Ÿ×©’´fY€.ElEf?FbWn8a’Ld­}“[x£m‚\{¦gz¾‚’Đ{àˆ{è“yê“x́˜ý„í¢ˆ̣²”ê½–»rXo&:U6S 5X7]:a:a=f?d@d@hDf Dc Ba?_@\=`8b=e;b?Z@_Jp(QŸPl¼pzÊwxÉx|Æpv̀yzÖˆ}ؔؔוƒƠ‘€×—‚Ö‚Ö‘‚ב€Ö“…Ơ’„ƠƒÓÔ‚̉ƒÑƒÔÑŒĐ‰ƒÑĐ‹Î͉†̉ƒÏ€Đ‰~І̀ƒÎˆ~Έ€̀‡|Ë„‚͈Ë}̀„{Ë‚~»NZ¶KT³KU³KZ³IU³HR®IT®BN±AL®AL­EN´AI¼DJ̀PQƠ]Ṽm[æzbémëpí–që”v́’wí•ś˜uï•xî˜mî”úˆhè‚jäp_ÚbY¿MN4FŒ(C&C‘/H›5H 6I¤:L¤>L¥>M«;I¬?K®<L®>H®<K¯<I¬:G°@HµBK®<H°?J°AJ±@J·FN·DK¸ELºIJ²FN²DJª>F¢3H¯BḾ¶„úÔ¯ú„öÆ“́§†à„mè˜źŸxä~Íe_®BTÇ^aĐgj̀dkËbhÆ^fĂ[d´N\¶TgÈ\eÊ^fÄ`lÀ\lÂYh½WjÂ[jÂZm̀\lÓltÍclÈ]fÀUe¬Nd”@bt'Vm"Pv"S{4dq6dm(Z?q|;ko0`e&Xb PTD\IŒR…<iS<S@UAl(Y‹Hzq1_cFX@cHs'Xs)Vv,^aLm-]‚P‚ZNSK«€bG Ej0lµˆ¡ª^r«\t¿lzƠ£ â´¨æº§ăº©à·¦Ư´¤Ú³¦×²¦Ö«ŸÔ¬ ÖªÓ¨£Ñ«£Ơ¬Ÿ̉£›Ô£”Ñœ’Đ£˜Ô¨Ô©œĐ¦×¯¢ÙµªØ·©Úµ©Ư´£Ü²¤Ư­Ú¦œƠ“Œ±Yf2OŒ8Vˆ<^}.OJd–SlDl_rªvœ\s¤iƒ˜Rq»|‰Ë€ˆ̃‚zæzë’|ë—‚î ̣ºç´TN\6W:V<T
-6Y:`9b;b<h<i Eg!Gh"Ci$Dc@`<^<\8_9e<e>aC\Fi"N‚4Xª^oÀrvÁnuÁpv¿ltĐ~|ׂ֓„Ø•†Ù”Ơ”‚×”€×”ƒÔ•ƒÔ‘‚Ô€ÔƒÔ‘‚Ơ’„Ó„ÓÔ€ÔŒÓĐ‹„̉‹€Ï€̉‰€Đ‹ƒÎ‡„΋€Ï~Έ~Έ€Í‰€Î‡ƒ̀…΃x̀…€Ëƒz̀‚|΄}²HS´JT´JW±NX²MVµIR±GR­ES­@L¯AI²>H±>H¸CIÉPNƠ^SƯm^å{dè…lëṕ•vê˜tí”yï–q́˜uíú—sï”qí‰lçiâubÖ`X¾JM4G+D(B”0H—5G 0F¤8J¦<J¥<Mª>M¬AP®AO­@K°@L®>J°=I°>J°?N®<I²>I®@L°AL¶EO·FM¸HOµHL¶HN´CK¯DJ¨;H 2JÄaPöÆ”øĐ¥úÆó®€ç¦‰ç˜{́¨‚è¥{Ăg`¼cfÎ`aËagÈdl̀doĂZg´Rb²TfÄ\f̀bgÍflÇalĂ`o¿Zq¾\r»UlÀ]xÎjxÍar¶Sp­Ss®Tr°Xr¨KlHn‘<fˆ9gp&Xk$Y}6j‚Aoe%RYITBSC\Sz3l˜f‘t2\R :S ?YDo+]Ixr0^]?`BjLdDgNaNYIt?k~IO IX U~®l6fˆKz–i˜Ro Oh§iŒƠ«ªå¸ä»¦â·¨̃¶¨Ư¸¬Ú°¢×¯¥Ơ¬¡Ó«Đ§›Ñ¤Ơª¡Ơ«Ô­ Ñ¤˜Î˜Î“Ó§Ö«¢Ó¨Ñ«¡Ô±¨×²§Ơ°¦Ø²¦ØªÚ¥å°§ê±¨è¢›Ø‚¬BUŒ-O9P•Pt„<^ŒDb‹GeCgªt„¡f€ b}›Lm°l„ËŒƯè•‚í ˆđ­”ñº’ᣉ8CX<W;Z;Y=[ 5_;c;i>f=c=jBfAk Dg=\<Z<Z<^=]:f>dD_Gj$Qt(S’Hd´hr¼ox¹ls¸jtÁptц‚Ø–‚×—…Ù’Ú”Ơ’‚Ö’„Ô~Ô‚Ö‚Ó€ƠÖƒÖ€Ô‘„Ơ†Ö€ÔÓ€̉̉Œ…ÑŒ†Ñ†ĐŒ…Đ‹‚Ñ‚ĐŒ~ЉЉ€Î~̀ˆ~ˈˆ‚Ά|̀„}È~Ë‚|´N\´MR³LV´KU±EO±FR®HR°EO²CL®CP¯>H°>H·@EÇLLÔ\S̃jZăzhè…jët́t́—x́–zî˜xî™vï˜v́—rî“rîoéhâs`ÖbXÀMQœ3HŒ)Cˆ(B.F™/Bœ5H¡:J£<M¦8I«BO©>OªBN®?L«?I®>L°BN°AN±?M®>J¯>N±BL¶DO¸DL·GL¸JP¹FL¹HL·FM±DN«?I£8L 5Rß•lú̉¦øÄ’̣²ƒö·„彩đ®~Ú}o´=FÙybË^[ÆVZÈaiÆbp¾[g·ViÀXeĂ_hÈdq¿]w¿n‡»gŒ¼_ˆ·a‘¶V†°\†¼^Æb~Èa}Æ^oĂUg¡B[•=X›<b4^~.^t.d‚:nIt|@mb QUFQCS C_O‚<q˜h’dGQ<YCaMn*\v.Zq.[bHcFr$QbEbHaOUGzFz{;zTLuI†Œl£›`º”œlœ„6[®b~»‘¦â± äµ¢á¶¥̃µ¥̃·§Û´ªÙ¬ Ö¬¡Ôªœ̉¤Ñ¨Ô¨˜Ô¨›Öª Ô¥˜Ï’Π™Đ¡œÑ«£Ô¯¦Ô¬¡Ñ«¢Ơ±©Ô®¤Ơª Û§â¦¢ç®ªé°ªé³¨æ«Ÿà‘É]e¥>Pˆ2]‚4Tb€–Rt“Lr–Sw `v¬z¥f~¤d‚¯k€Ç€ŒÜ‰‹î¤̣¶–đ¶‹Èv]€*>Z:X?X:X;^<a:e>i@h?f<d:gBe>h>f@^=]=`?^8b>e>dD`Hi$O4XŸWjºpu¼ns¯fr¯dpÄv|̉‚ו„Ø–†×—„Ö•‚Ó’„Ô‚Ô„Ơ‘~Ô‘€ÔƒÖƒØ‚×’Ơ‘‚ƠÓ‘‚Ó„ĐŒĐƒĐ‚Ï‚ĐˆƒĐ‹Ï„ÑƒĐŒ~Đˆщ€̀‰„Í‚Ë…̀‰€Î†~Ë…}ˇ€Î„~µKV´JT´LV²KW°FR²HT°EQ­CN®?N¯DM¬>G®<Jµ?FĂILÑ\UÜk\ät`èˆó’ṕ•wë–tî–zí–yî•rîtđœtđ”sïlè€hâtb×`T¿JR 6H*F‰(B’,D˜0D›4FŸ7J¤=L¨:L¨CR¨@N§?O¬>K¬<L¬?M°@L®<J®BK³CO®BO¬CO±EO¶EO·FL¼INÀHP¾LRºJP³JP²FJ¨8EŸ4N¼ONóÈ÷¾•ô·ˆó´‚ó°‚ñ¶Íf`ÇghÙoaÆU[ÂPWÁ\d¾WaµNb½`lÇ`qÊ`jÈev¹]v¼^qºXl²Rl´^|²e†³^†¥U‚ŸQ{¦_ˆªR~ Bl~1]r%V‰6f{,[ˆ:j†:hDu‰H|p,\aN\KZFTFbOˆN€U\CVCeH~Ev^A`HcHgRm!V€9m„>z€>z€>}p%c†Xw8sk)lƒR‰†P¡_ƒ©l•˜]Ÿ`†Ê¦Ëª̃°œâ°œÜ®¢Ư¯ Û´§Ơ°¤Ø¬Ô©Ó§›̉¦Ó§Ñ¥Ô§˜̉¢•̉ •̉¢–̉¢ÔŸ•̉¬¥Ơ¬¤Ơ¬¢Ñª¥Ơ¬§Úª¥æ®¤éª ê¯¨ë´ªë¹®ê¹¬æ®¢â “×qr¼HUœ:N7^ˆ<T¢l„“Kf†?`€:Z¬pƒ©rˆ«p®jƒÆ|̃•’꧉ߑq§JIi9];Z>Y>Z>]<[8f>j>f>j!Fh@eAf@f>k?b<\;Z:b=`:f<f?^Ec"Lo)U?^­dp¸qr´iq®dn´kxÊ€}Ô“ŒÖ–ˆØ˜„Ö˜‡Ô”„ÔÖ€Ô’Ô’‚Ô’„ÔƒÖ‘ƒÖ’‚ÔƠƒÓỔ€ĐƒĐ‚ÑŒ„Đ‚̉Œ‚̉ƒÑ‹‚Đ‹€ÏˆÏ‚Έ€Ê‹~ˈ€̀ˆ‚Ë…}̀ˆ̀„z̀„z̀|¶LR´LX´NW´KS¯FT´CP¶FL±GP°DP¬@Kª>M«;E°:H¿JMĐ]YƯl[âzgç‡nêŒoë–xê˜tî”ví—vëxï—vđ˜wđ–pđmè€hâvb×f[»LN 5FŒ&AŒ$?’+F—2E4F¡8H£9I¦;Lª>L©=J«?N¬@L¬<J®>J¯?I­BL­@M°>K°?L®@K¶EP¸EPºHQÀJRºLPºPT¼JP¶KO¸EK­BJ¤8K¤6Qè©„öز÷Á˜ôµ„ô´€̣»ÖxhÛu^̀\[ÅY`¾S_½V]°IY°L_½YeÆajÄcqÂ^n¶Oe´Rb°I`Â]rÍbrÏ`pË\sÊbvÂj~§Xq’Fop%Yp%V|/dr&X„0aƒ0`‚9gŒFt|;km.Zd"PdLXJVGj$X|7j€Ani"Tf Rn(Sp2^[?^>aB^@` EaCi"Lf$N^FbJ|Auj)Zn,dyAt}A€†L‡¤z¨^ŒÄ£Æœ̉¢ Ûª–ܦ”ؤ˜Ö¬ŸØ°¢Ô¬ Ô¤Ñ”̉̉Ÿ˜Ñ¥̉’Ñ“Ó¡“̉¤Ó¢̉¢™Ñ¡Ñ¤Ï¥ ̉¦¢Úª¤ä²¬è±ªê°¦ê±΅´©ë´­ï¶¯ï¼¯í¶¨ë°¡ăŒ„Ô^b²;J’7Ox-Xn,Hœa€„:[~8b€Aa®vŒªq‰¯p‰¾}Ö‰Đqn¶XX€)F[ :Z =X;ZAY>]>a>f9g=h>j@h>j@i Bj@h A^9Z9[;`=b=g>bA^Cf Ly/VOg¶jq¸ow°fs®hsºmtΈ€Ö–†Ö™…Ô”„Ơ—„Ô•†Ô”ƒƠƒÔ”†Ó‘€Ô€Ô“Ö’Ö‚Ô~Ó€Ó‚Ó’ƒ̉ƒ̉ƒ̉„̉„Ñ€Ó€ĐƒÏŒ„Î~Đ‹‚Đ‹|щ‚ω͈}΋€Í„~Ά{̀„zÊ}É…‚µHT¶MVµLV³GS³FR´HP±DP°CL¯BP¬@K¨>J§<H®;E»JMÎ[XÚjZà{hå‚fèrê’uë—v́qê—x́–yïwî˜zđ•sîqé‚kârbØcWÂOQ¢6FŒ&A‡%A‘+C•1D–2F :L¡6H¨?L­=L¯?K­>L«>N¬?L¬>L®:H¬>J­@N¯@K°@M²BL²BPºDM»HP½GN¾JR¾PV¼MVºJQ·HO²BI¥;N¤5Pá—zúÑ™ú̉¤öÀŒöº†ö´‹æ›rĐibÂXbÆ^dÂ^jµJ^¬DX¶Rh¿`pÈ^kÁ]l¹Wj·Sj¸QeÆfnÑfnÑboÄ[q®FgªH`̀gs¾\sDjw*So,Zo*]dPi!Un!Vz1d…Ap~7gq*\g!VZFXO`Pp-bl$Zx4k‚?v>rh#NZB]@^<]=^>_C_C\>Z=T=R@l-ar*ZˆFtz;nm/nzK„”]‹™l–±~¾‘Ô¡˜Ú¥œÖ•Ơ¥Ơ¨Ơ«̉¢—ΔΛ”Í–’̉¦Ñ —Ï ™̉¢›Ô£›Ó¡•̉ ™Ï¢Ï¤—̀“Ϥ¡á°¨ê¶©í·¬ë°¨ê²©́°ªíµ«́µ¬́´ªî¶­ï¶©î´èœƯnj¿FO£6K-LkOr0JNo‹@ct'R f}¬nˆ´x¼}É€„Âhm´QS(BY<X 9X>V;Z=^<gAh@h>jAl DjCg@jBe?a=^:Z8Z6`<l<f>_@`Hp'S‰=_«dr»qt·lp­an±doÁtw͈‚Ö”„וƒÔ”ƒƠ˜„Ơ”‚Ö“Ơ’ƒÑ˜ƒÑ‚Ô’€̉‘‚Ô’‚Ô“…Ó’€Ơ€Ô„Ô€Ô‚̉„̉ƒÓƒÓƒÔ€̉€Đ‹ƒÑ~Đˆ}Đ‰Đ‚ÏˆĐˆ|·~͆|ω{̀‚{ʃ΄z¶IV²JR´HU´HO±HW´FP®FR°BN°BK®BMª=I¦7F¨;J¸IMÎXSÚj[ávcæ€héó’uë–wí’tî”wê—xîví˜xî˜tđnèmătcÙbXÂNM4GŒ(B&@”0G“,Dœ1F£<N¢:N¨:K­BO°AL­AM¬BP®BO­BPª@P¯?M°AMª>K¯@O¶CK²DN·HP´DN¼MTÁQS¼NT¼KQ¸LO¼KJ´DL£:N¦2Nß–€ùÓ®üΖøÈø¼ôµzä†`ÆX\ÄZ]ÄZcÆ\d¸Td´RkÄ\g¿\e½Ta¶Tj·RgÉ`pĐlpØhj̉afË\hÆ\m«He¡Og²Sc£?Z•5X.Wt,dh#PcL[K^Ln+Z{4gx.dq(^y4hp)\d!U^Jw4m^Ot8pT†ŒM~k$UW:[=^BZ>]>^B^HZ@T<SATBx6hœQx Liˆ:gx9}o¦£~œ¸“£̀™“×›ŒØ£›Ö¤œÖ¦ Ö¯¤×­¡̉¦œĐ–̉™Í—”ÏŸ–Ñ¡̉£œÓ¦œÔ¦Ñ–Ï‘̉£Í¡›Ë—˜Ô Ÿç­΅°¥́µ«îº¯ë´΅¶­́µ©́¹®îµ®́¶¬î¸¨đº¦ï±¢́àvrÈMU°<JŒ.Kl!HTCu4RGe|.]ˆA`©pŒ³p‡¾‚’Ë…Êps²NVv>`>T;X :X:]=b<hAlCi@h<lEl An&Gl$Hf@`<^=Y;[7\7e;b<ZDcLv*S˜Nhµgtºpt²jq²bk¸ktÈ~}Љ‚Ó’Ơ”„Ö–‚Ö”„Ö“‚Ơ•‚Ô–…Ô‘‚ÓƒÔ‘ÓÔ‘€Ơ„Ô’Ơ“}Ó„̉‚̉‚Ó‘ƒ̉‰€̉Œ†ÑŒ‡Ô…Ñ…Ñ‹ƒĐ}ĐˆĐ~Ñ‹~Ñ~Đ‹~ωΈ}Ά|Ά|̀†~̀‚~²L\²HR°HW´HT°FS°JS±HP®>I±@I®?K©:E¥7F¦<N¸LQ̀ZVÛh]âvbă‚qèŒj́•xë˜v́–v́™xîzï˜xî˜yï˜xíoèläudØf^ÀPP¡4H(F%E’-H–4I7M¢>N¢8K§BQ«>N¬@P¬?N®DR­EP®AN¬AN®?M²?L¬<L¯<K¯@NµAN¸FRºHO¿LTĂMU¿MT½PV¼MP¼FK²DM¬=M©3Nà’zûÔ¢ừ›ûĐŸúÈñ¨sÊRNºFPÀX_Ä^i¸Vf»VfĂ\fÆ\d¶We¬E^¸NbÉanÔjqÔej̉dj̉cgÄap¸QdŸ;X’1L•7P|Ht"M‡Btq-[^EXBUBWFaKz7lu,\q/a{:f>qa QXHu3d^Kd$YR™g”|:kV<\@]>^BZ@V9XBS<M 7P@l'U”Np®_t/R˜Bg˜_¬ˆ¬·{Ơ¦Û¨˜Ú£–ب›Øª¢Ù°§Ù±¤ÖªŸ̉£˜Î˜Í‹Í˜”Î’̉œ—Ó¦ Ó§Ñ ”ÊÊ’‰Í›–ј–á¤ê®¤́¶§́µ§́º¯í¾¯́¶«ë¶ªë´΅·¯́·°đ»°î¶¨î¶«ï± ë‘å‡|̉X\´9G’,Ir C^AZ>Hb€4Z~5\§l„¯nˆ»u…΃Êtw¬HRl@\>X<\<Z>^=d;d;j Af@k!Ej>iAl#DiBd>_<`A[9\:b<g>_>ZAbJ‚=`©aq¼rv¼pv³kp¯fn¸tvȇ€ÑŒ€Ó€Ó‘‚Ö”€Ö“€Ö’Ơ}Ô“‚Ó‘Ơ“|Ó€̉|Ö~ÔÔ‘Ô~Ö“ƒÔ’€Ô~Ó€Ô€Ó‚Đ†Đ‚Ñ‹̉†̉ƒ̉€Ñ‚̉‹‚̉ˆ}Đш}χ€Í‡̀‚zÍzË€}¯KV²LV±ES±KX°JV´JS¯GQ­FS¬BL«BN¨;F£;G¨8H¶EMË[[Øhbău`ç‚mèŒtê’vê“wê˜v́—wívï—vî˜xđ–qîŒnè€låtfÙ`V¾MQ¤2F*D*E'B™4H7N£=P¦<MªAQ®BN®>N®AN°CQ®@N¯@O°CR¯@K±?M´AL³@M³BL¶FP·FQ¸HP¿MRÄRVÀSV¾PY½NS½LO¶JR¯<Mª4Nߌrû̉¨üĐ¢ưÊ÷̀›á}Z¶EN¹CMÂVZ¾V_ºT`¾YeÆ\d»\m²K^´NdÆ\k̉flĐdmÎelĐdhÁTfÂWdº^oƒ*Jd:mD\Bn.Yy4]dDWAZCWCYHYJx7f~>jl$Yv2b‚Bs^ NVJu4icRUKv=w’b“il'Z^G[@Y?Y=V;P :N 6L?h!M¨c|¥ZtKo›?b¼€µˆ¤ª‚¤¾£Ø¬¡Ù§–Û§›Ø¬Ú²§Ú³¨×°£Ô¨Đ—’ʒ͇̀”̀™”ÏŸÓ«£̉¤Ë——LjˆÏ’“̃›ç£™è©œê®¡́´¬́¶¨î¸¨ï¼¯ï¹¬́¹­íµ«í·¬đ¸«đ¼®ï½¯̣»­ï¸¨í¨œç‚̉ZZ¸;J2JtA]>YBn!F†9\y.W›\r¶x‘»‚•Ê‚‰Çy‚.IeA^E]B^>]>_;e;j?l?k!DlEj Gp,Mm#Hl&Hc@^<]9_:`;f:c;Y<[Hk!L“Id¶jrĂvu·qs°fp¹kpÅ|}͆̀…€Đ†|̉Ơ”€Ö”„Ö“‚Ơ“€Ö•„Ö”‚Ó’̉‘€Đ̉€Ó€Ô‚̉ƒÔ‚ÔÖ€Ô’̉̉‚ĐŒ„Ô‹‚̉‚̉„ЉĐ‚тщ€Đ‚ÑŒ€Ñˆ~·€̉†zЇw΄~Ê€®HX±JV°KU¯LZ®JV®EP­FT®CP®AN­AK§?H¤;Hª:H¸JOËZZÙi^áwfæiè‹vê“|́”t́—ẃ˜yí˜{î–yí”wî•yíŒpè„nâtcÙe[¾OP¡;I-H&@”*B—1E›5F¤@V¥<N«>N¬@N®CP°AQ°BR²DP°CR­@R°@L­>L°BN°BP±EQµHUºFN¹JR½JSÁLS¿NTÀNWÂNP¾JR»KN´@M¬8T̉r]úÖ³₫Ñ™ûÍ”ø¹‚ÉXN´DN¹FMºKS¼RX»P[»S^¾Te·J[ºRà]c̀\iÉZgÂOYËelÊVc¼Rf¾\n¶\n<^V@Z@hJ}=llI]@ZB[>X>\HXFd$R~9jx.ho%Xz9fr.bWIq:gh VQ B\RyCv¢wª‹Iƒ…Bx‚ExdQN
-8N:I
-8H ?^F¬lzĐ}z FfœJkÄ‚–ÙÀ…“kº¦Û°£Ö£–Ùª›Ù´§Ü¶«̃¸¤Ø¨̉›’ϔʑΉ̀“’Đ̉¨ Ôª̉”цۈæ•è˜ê¦ê¨é°¢́¶§́²¢́¶¨đ½®í»®îºªïº«đ¼°ñ¾±̣¿³ñ¿³ñÀ±ñ½®î°œê”Ùmj»ALŸ7JzBT=ZC^<…:Xx)TGf¼„˜Â‘Ï”Áuy&Fa@[>X@]:^>`?d:j<k>i@jAn%Fl"Dm#DkB^8^;]:]8b7d?_=\DbJ|2T£\m¼uvÀut·nq¶jpÁzyÉ‚|ʆzÉzÈ‚x͆Î̉~Ơ‘ƒÔ•Ơ•„Ô”„Ô”ƒÓ’„̉€̉’}Ó̉Ơ€ÔŒ‚Ô’Ö’‚Ơ’„Ô„Ôу̉‹~̉‹ÏЉ‚̉‹~Ñ~΋€Đ‰~Ï‹~Έ€Íˆ€Đˆz΄xĐ„{̀~z®DQ®HV²IU°FR®HR¬DO®DR°BN¯EN«ERª@K¨7F¨=HºIPÍ[X×i]àxhă‚pèx́’t́™wë–ví”sí›xî—xî˜wï”wívè‚jâ{nÚc\¼PY <M*E">—/E˜1F5G¢<O¦:Kª>O®?N«BN²BN²AK²@N´EO°BP®@O°BO°AO²BPµEN¶EP·EMºKQ¹IRÀLTÂSXÇTXĂMP¾LR¿JQ¸DL±>RÀOTöÈœ₫ÑüÔœè›s¼FM¸KRºKQ²KWµLV»U\¶R[ºVd¹XgÉ`ì\aÍaiÊbg©BX¶Rg¸Od¶Pc®G_£C\‚7V[A^D7b„@i]>X<X<aE`?_EZFYHf"L|9np)Zo*Zn,\d"Vs<ml'[^O^Xk._~¨o)VbDd FZ?O:G 6G:X@§n|Ôx¾Td²Tkƈ–ܦڇΌœm›ª‚¦Đ«¬Ơ£¡ØœƯ¶«Ú¯ŸÜ¬Ÿ̉¢›Đ˜–̀’“É‘‘ÉÊ—”Ч֮¡̉™Ơ„€àˆ„å’‹è–柕ꨛ́­¤́±¥́¶΅´©í¹ªï¾²í½±îºªđ¼°đ¿±̣À²ôṇ̀ǺôÅ´ôĶđ¶£î á{xÆKP¬8I&A^ :T?[Bu%H0^‚2Y»”‡–Đ–œ¼q}x D_<`>Y:b@_=b<e@f@i@h?j CiDp'Fo&Je=\:\8]7]8d9e>\=ZEj!PB\²iuÂxv¾qp·jq»ptÇ‚€Î‡~Ë…~Ê‚yÊỳ„{ǃ}͆€Ï‰~Ñ€̉‚Ô’Đ€̉€Ó€Ơ|Ö~Ó€̉€Ó~Ô~Ô€Ơ“€Ó€ÔŒ„Ñ‚ÑŒ€ÑŒƒÎŒ†ÑˆĐ‰Đ„Ñ~Đ‹~̉Œ{ψ~ψzЇ}Đ„y΃|̀y®EP®HT°FT°IU®HT²GS°FQ®EQ«@K©DP©@N¨:I¤<NµJRÊ[\Ùj]áwbäƒmé‹sêt́–v́–wí–{́˜zî›v́—yï™qî‘pæ„hăveÚf`ĂRV¢:O,H‹(B’.H˜.DŸ4G¢?M¤=L¨>N­BO¬DQ®CO®CP³DR²DR²AM°EN°DP¯CR²BU¶DNµCOµ?M¹GRÄmuÂRUÁPUÄRUÀNTÆPRÄLQºIM²>O¶>Q́¬₫Ö«üÓœ̃j»PZ½LPÂSX¿S[¹OZ¼PX²FU´L`Đhj̀bdÆXdÆT^¸T_’7Wƒ0QŒ9\‰0T}$L‚/Q‚3VkJ_G†Do{1^X<V=X>k!P_Aj"N\A\E\Bl)Ts/`h"Qg#Wm(^{<nj$Yf,^]Vc$V˜u›s.`V>S 8M 8K 5E5O>ZiÖxÀSa»SgΉ“߬۔ˆÚ†ƠŒ©v™¥„©¸›«Ä–£Ôœ›Û´©Ô¤™Ơ¨¢̉›—Ñ›Đœ•̀–“Í••Ïœ˜Ơ¦˜̉Ö{zăˆä„æ˜è覛ꨜ́²¦́²¥î»°́¶§́¼¯ï¼¬î¼¯í¼¬đ»­đ¾±óöơĂ´óÆ·ôdzơÇ´̣¾«ï¬æ…{ÏV[´<H˜*Ai9P ;X<hAz.Rt&T©fzÆ—Øœ™¿z†v"HbCh@_?h>n?j"EeAfCh?hDl Do)Jl%Dl @b>^9]>_<c>g=c@W>\Fr(PVh¼u{Æzt¼np´dpÂ{v̀ˆĐΆʆ€Èƒ|Í„~Æ‚~É~È‚€̀„€Î…~χ΋‚Ñ}ĐŒ€ĐŒ|Ô~̉ÓŒ€Ó€Ó~Ó’‚̉…Ó’†̉Œ‚ĐĐ‚ÔŒ‚ушĐ‹€Ñ‰€Đˆ~щ|̉ˆ|Ї{Ñ…{І|Ï‚|΂|Í|µBQ°IT°IT±CN°HT°GS°DN®DL­DN«ANª>L§<I¦=JµHǸXVÛjaávdä†qæ‹sê•t́–ú—ẃ˜t́™~í›v́˜zï—vđ’nè‚năvf×d\ÀPW¤<N-F*D’+B˜0F¢0E¡9I¢<Lª?Q«CQ¯FT²DR±ET±IX²DS±GR´AN±@R®CP°@N°@Lµ?P¶HXÈvp̃„hÄJO¿MTĂSXÆOPÆONÀLP¾JM·FS²DZÔu^üܶûÓ Ùn[ĂOR½NVĂXYÄW\¸Q^°@R´L`ÊgiÎahÈ]gÎgp·Ul™Fh—Bb€2Y€5S2Rh<u!Ez!F[D`FT„l$MVAU@^Jr*VaIgKYB_DfL\FbKi&UaQdSCw„C|‚J~aR]PVv„L}R;N 9L
-6I <M>Ng̉‰yÂaj³QeĐƒ’Ư¢–ÜØ”‹Ø‘‰Ó”•­{˜³¤̀¦¡¿— ̉©¨×¶¬×³¨Ö¦ŸĐ—”Đ˜˜̉œ–Îœ˜̉“Đ›”Ó…|Ùyzቆä‡æ’‡å˜‘蟕ê¬ê¦î²£í²¡î·©î¶§î»¬đº®í¼®î»®đ¿°ñÄ´óĸóõóǺơÅ´öɸôÀ¬ñ°ê“Ùbd¾AJ,Dr?V@T:] :jE}+\C`À„–̉•˜Ăƒ†7Y`HdDZ>`Af>h=fBi BkEl"Jl"Fp(In'HiAaAZ<\8b<d?iAbAU@XCy2V¨cqÄxvÄspºlp¼otÈ‚~Ô€̉Ή~̀„}Ê„{É„~Ê|Ê}È€~ÉzÈ‚~È€|Ê‚}Ë…|̀„~ÎŒ|̉‹}ĐŒ€ÓŒ̉Œ‚Đ‚̉}ÑĐƒÑ‚Đ…Đ‹ƒĐŒ‚Љ€ÑƒĐˆ~χ€̉‰|̉†zΈ{φц}̉†‚Ά~̓΀|²HP´MR±IS¯LS®FS¯EP®EP«FQªBO§EQª>J¥:I©;H¶JP̀YVÙj`âtfäƒkèsê•vê–ź–xí™zí˜yí˜ú™uí–wí’pæ„kàtbØd]·QX¤?S,I*F–.F™2F£6H¨<N¨AQ­DV®BR²CS°GS°IW´JTµDQ°FS²DN°@N°BN°@Q°BR¶@OÆZYƠo\ÂPTÄNRÄSXÀOTÄQWÆNQÂSXĂRX¼LQ·JW¾T`ñº‡ù×®Ù~nÄMPÄQSĂQVÅQS¾T`¸MZÆ]dÈX^Ë_cË^kÖetÑco¾R_³J`£Fb‘8ZkG^BbCX?V?eI‹P~dCU<ZCt0\j MbKdKYB`IhMYC^Fk&VaLbRt3f’R†—b’v2nbVl5\‘g”VCF4D
-9J?ˆE^ĐvÎgk½XgÎ}ˆƯ¨›Ư™Ư¨Øœ•Ö’‘Ô™°¹Œ¢ƠÑ —Ö¬¥Û¶«Ù¶«Ó¢Đ˜’Đ–Đœ’ΗБƠ}z̃zwâ~yæ‹„æˆæ’‹æœ•é¦ê°¢ê®£́¯¢í´­îº¬îº©î¸¬ï¾°ï½°î¼®đ¾¯̣ẉ̂ŹôÆ·ơŸơɸöÇ·ôÀ±ô¶¦íœ̃mmÆDLŸ.D:Z;M6V :aA€4`z-SĂŒ Đ“”Ä‚„‘@[bH`B^&M^@f@g@hBjCj#Eg Dm#Hq*Jn$Eh>c>Z9]:`:f;j=[=WAaFŒCa¸lqÅyvÀtx»hjÄzxω€̉•€ÏΌ͉z̀ˆ~̀†É…}ɆȃÈ…€È€zÈzÉ|ʆ€È‚|É„Ë„}Ë„yË„|ψĐŒ€ÑŒ{̉̉€Đ„Đ‚Ñ†Đ€Ïƒ̉‰Í„ψ|Љ{ψ~ІzÏ…|Ï…~Ï…z΂yĐÎ|t¶FR³HT±IS¯FR®EQ°>N°BL®BNªBL¨AP¦:H¤9K©BN¹HM̀XQØh[àtbäjèŒvë”vê”úvíývî—v́wî›wîræ‚nâu`Öh^»TZ¢>TŒ1P-L˜3O˜4NŸ7O¦?R¨AT²ET±CR°CQ³CP²FP²AQ²DP±BN²BN²@N±@L²DPµDN¸HQĂPSÁPWÂNV¿RYÄPWÈTVÅRVÅUZÂQVÄRTĂRV¼KT¶GZÜ|bùÜ®æ›ÇTSĂST¾OS¹FQÄV\Ñ\\Ê\aÅ_hÆV_ÍhrÊ^pÄU^®DX¨B]€!IkD`Ij$PeGP<VAZA…JtcHZDaJcH\Bj&S^C]FeHaLZFh#TdNVDj%U‚>x‚?zw3c„F€~:€‚C~¢°r2^D6E ;{5UÇ€x̀i`»WjÅs̃«á–‡à¢”̃¨—Ù¦¡Ù¡Ö¥¢±† ²ˆ Ï“ŒÔ’Û°¦̃¾µÚ¸ª̉–ј“Ñ̀ŒÎ‹Ø|zß{zâƒä†‚æ†å“‰æ’ˆèœ“ê¥™ë¬ í°¦î²΅²§íµ¨ï¹¨ï»­đ¾®đÀ¯đ¾¬ñ½­ñĂ²̣ŸôƵôƺöȶơȹơÅ´ôºªî£–âyqÅHP§4Fˆ!@`:J 8S ;YAz0Wu&T‰Г•Â€ˆ™AXl H`F^DbDl FeAhBl$Hl En#Fq$Iq(Hl%DfA]<^=]=b:d<b>V>YDt*TŸ\pÀvwÆxu½pr¿knÈ}}̉Ö”€Ô”‚Ó€ĐŒÎ}͈z̀„|ǃ|ȃ|Æ‚|È‚}Å~}Â|Æ€|Æ‚{ƃyÆzĂ~{Ă|yÆ‚}È‚}Ê„|ω€ÎŒƒĐ„ÎŒ„ΌΉ‚Έ‚ψ|Î~Έ}φ|φ}Í„|χ~΄|Ë‚{Đ~w̉€yÑ}t´HR²JS±HS²HR®DP­>N¯AO¯EP©?J¦=K¦<J¦:J¨<HµHNÆXYÖdYàtcâiéwê‘zê–x́˜źœyëœv́™yë˜uî—zî‘tæƒqâug×f^»RY¢<Q0M/N–4P<PŸ>P¤?P¦<OªAS­AN«FR¯DS°CR±DOµDN°DR±CO´DO²EQ³CQ´FT¹EPÂMRÂ\eÂMQ½NVÂQVÈXXÆTWÊSVÆTWÉRRÆR[ÄPQÂKTÉV\ñ½ˆ́¬ÎXTÆXWÂNN¿GRÎdbÍ\aÈ\cĐdh̀ctÉZdÅ\hª<R¡>R…(IdMaNq/`€<lU<P:RAWFw6ez8lr)Tj"TZDf$Pg"R\C`IfLaG`Hr0]dNU C^F‡K‰o._u-`n*^VH^F™|›m+`B:n&LÀvsÎqn»UbÀevס”ß—„ß—Œß£̃±¦Ü®£Ø¥¢Ơ§¤°ƒ ®|’Í“˜Ó–ܵ­Ư¼²Ó¦›Đ”ÏΓёŒÛ{zá€}á~ă†æˆæ”‰ç•è”éœë¦ëªœ́³¦î´¤́µ©í¶ªî¹­îºªđ¿°ï¾°ïÀ°̣Á±̣´̣ĶôÅ·ôȶơȹöɺöȶôÁ«ï¬ä€{ÏTX´<J–$?j:P;Q<UAfE|,Z°j~Đ–˜Æ…¢Ldp#JZA[@dBlCh DeEf!Fj$FiCq#Fq(Fj!DfC_>^<c=d@e>aAX@`EŒC_´l{È{zÂut¹nr¿qsË„{Ñ”„Ơ”ƒ̉’~̉“ƒÑ’Ï’‚ÏÍ}ɉlj~Ȇ|ʈ{Ç…€È„~È„|Å„}Ăƒ}€zĂ~}À~€}ÀzÂ|zÈ~{Æ„€Ê„~Ɇʇ„͂΃΄~Ά}ʃ|ˆ{Í…{͆z̀…z̀ˆĐƒzуzÑ{Đ}z¯EQ±IT±FQ¯FR«ES®CR°AL®CQª=J§<L¦;H¨6F¦3H´FKÆZ[Üf[àvfå‚lèvë”|êwê™v́xêœ|íwí™zî–óoæ„nàtgƠic½OT¤<P+L.J”.L›<R :O¤>Q§>P«@R¬BP°ES²BO±ES³CO¶FO´FT±FT±FR²FQ´BP´EP·GQºIR̀^\ĂMTĂUZÄPVËUXÉUXËUYÇWZÅYZÇTZÅPUÆQWÈT\à}`í¡vĐZRÅTX¼ERĐ_cÔb`ÔfkË`nÍbrÍhyÀex¶M_™6Qm@bI`Ra!P‚Jzw6gV ?T?ZDWDbH…Hrk NVD]Fz<ifL_DbEbIZEk*Zl&Sk$VZF`Jl.\YEz6j`JL =N
-@wQpRbF³nr̉vl¾U_ĂenÓ—›ÛŒ|Ư‡̃ŒÜ¢’ß²¤Ú­¤Ø°§Ï¨£®†œ¤l€ÍŸ×­¦Ü·­Öª Î–ÍŒ†Ê׆ß|zâ€ä†…ᆅäç“‘æ–阌èèꢔê¦í²¢́±¤î±¦ï¶©îºªí¸©đÁ®đ¾°đ¿¯̣¾­ñ´̣ŵóƸóĶô˽ö˼öË»öIJđ³¤æ‰‚×ac·<K /DvBXBRAT<aD…5c—Nc̉——Ó––K^n@\>`@bBhDgDh&Hj$IhBg!Dk#DmCg@c@^?]<`<g?d>X;XBiH™NhÀtwÇ{tÄtrºnpÂ{{΂֖€Ô–‚Đ’€̉’Ñ’‚̉|Đ‚̀~̀ƒÎ„ËŒ…̀‰€Ë‡ˇ€̀†|ˇ~ɇ~Ç‚{Ä{¼€}Á~~¾x¾‚zÀ~¾~Á}~Â~Ç€~É~z̀‚|Í„{̓|̀†€̀‚|Ë…{Í‚z͆Ï…{Đ‚wĐ‚wÑ€wĐ}t²CP®GR±FP­BP«EP®DR«BN¬>M­BK¨@L¥<J¨6D¤:H·HPÊYTÚj^àvfæ|oèŒwë”|ê—ú™x뛜™|î›tî˜wí–ríuå…pázmØg_ºOT¢8L/I*J–0Jœ8P :P§@Q¥>O©ET®DR±CO°BR³FS±ER²JS´ES´BS²DR³DQ¶BR¸FR¹IU½IRÀQ[ÀSX¿QWÆNPÇPTÆRRÆPQĂQSÄSQĂORÆRSÊ\YĐc_È[MÔq]ĂMPÄTTÊUYÖa_ÔkuÓftÂi‰µc‰±_¨Sp’8ZpE`Gr.cXBS ?xExh"SVBj-aZA^HU =bFz2d`J{:kz2^\B[=bG]FWAv8hbEx4d^GYEVEf YIz`OH 8F<XHU…¨c€Ơ‚m¾Yc¾ZgÎ’̃’zƯŒ€ÚÛ‘ƒÜ¦”ܲ¥Ø¬¦Ù°§Ô¬§À”¦k†ÊŸ¤Ú´§×¬ Đ™”ËÍ……Øzà€‚à€„ăƒ„â‡„âˆæ’è•æ“蘌ꙑè•ë –ꦘ́®¢í²¥íµªï¶ªđ»ªë¸®ï¸©ï¼«ï½­đ¾­ñÁ²̣Ă´ôƶ̣Æ·öɸöȸöÊ»öDzđº©ê–‹Ûji¾DO§:Iƒ'FZCTAS<Z@‚<b>\ΕœÖ˜˜œFZm!Ep$I]>cCh"Gi Al"Cl"Dn&Jl%Hk)Ii"Eb>`?`@b@e@f@`<V=aLƒ>_¨dwÂxrÅtoÄop½pwÈ}yĐ’‚Ô”€̉‘̉̉‚уϒ‚Đ΀Ж€Ó”Ñ~ЂЂ΀̀ŒƒÎ†{ˈ}ʉ|Å„}¾€€¾}~¾}y¼{ă}¾}|À~~½{~À|~Á|ÁztÇ|xÊxË~yÊ…‚ÊzÊ…|Ά|ψ{Ï„|Đ‚xÏ€xÑ€v²CM²GT°BO°IU®FN¬DO¬EN®=I­@J©DR¨=N¦7G¥;K³EOÉYYØh\̃vjăpèxê—{ê˜|́™zë›xë{îsívï˜uíqè„jäudØf\ºNP¤;L“,G,H—0H—4K6K¥=R£ARªFV¬BR±ET¬CS°HU²FT³HV¶GRµFQ³BP³BR·FS¶IRºGR¼KR¿NTÈRXÊRTÂSVÂPV¼PYÀNS¹LR·LV¶KTÀPTÔn\ÂVH8H±MPÁTV¿FLÔcbÑYdĐdz¾e«_Œ®g‡­^|›Ib†.RZBl2`o)\M @L <€R†m(Z`Mj,[T>aHXBVFi SƒJ~…FphI[>W9fMZB\AFxS@f Or/ddPaT[Ge‘h&TG5F6M=†De¸o{¸T`¸Taʓ܈چ|Û×ÔÖ›’Û°¤Ø±¬×­¦Ø®¤Î£¤º†’Ч¤Ô¨¡̉”‘Đ”’ч„Ư~€á†…⌌ↆᅆâ‹äŒç’è–è–阒êꠔ꜔́£˜ë­ í¯ î´©î·ªđµ¤́´§î¶£í·¨î»¬đ¼®ïÀ°đ¾®ó´óŵơƶöȼöȸóÁ´đ¼ªî¥–ßtpÂHQ­9H&D^?P 9R>Z@|.U‰2UÉ‹”×›˜§Ziw&LgF_>aDjBfDhFh"Gn(Ip(Hn%Fh F]>]:b?b<e?e>\?XDdN’Ni²kyÀxwÀqp½nrÆsp΃{Ô‘Ö‘~Ô’ƒÓ̉€̉€Î΀Î~Ï‘€̉”‚Ó“‚̉‘„Ó“…̉”„Ï~Î|·͉~Ȇ„€Á€|Àz¿‚yÁƒ}Á~|¾}}¼~z¾}~Àzy¿y{Àyz¿zxÀ}zĂ|zÆ}zÊ„̀‡~É{Ë|ĐxÍxÏ€y°DR°HQ¯EO³EN¬CS®@P­CL«=J¬?L©BN¨>L¤6F¤:I²DMÈYYÚibƯzqâ†qæxè”|é”zë™|ëœx́zí›~́{í—uî’rè„màtbÚb[ÀKN¥;M’.K(E–.G›6MŸ5N¤<R¨?Q­BPªFT®FV®@P°FU±CQ´ERµEQ³DO´GS´DQ¸DQ´HR¸KR¾LQ¿KPÆQRÊQPËTÙVWËST̀WXÊRS̀VT̀SWĐ\XÊwt9R¶V^΄ỏ„ĂLWËVdÂ^ƒ°`³m²]t¾T`Æ]b¨F[wL^R…S„d RI
-@NB‚Wz9ldQV@\O]En)^o$\ˆM}=fs*ZbEU :X?hPVD`A|@nT C_N…JƒfTZGo>nk0TR>RGH <t2V¶rx K\FaÉ€‡Û¡’ÛŒ€Ú‡Ø“„Ö‰ÓŒ‡ÓœÜ²§Ø´«Ơ¬¢×±ªÓ§£Î¢̉ª£Đ —ϔԄ~Ü~‚ᆆăăŒäâ‹äŒææ”꜓虒ꘒéœê›‘ë˜ë–́¨î«í°¤í·¦î¶©ë´¥î³£î·¨îº®đ¼ªî½¬đ¿²̣Á²óijôƶơȺ÷ǸöÆ´ô¯đ©•ázvÈKQ¬8I$Ca<S :S>XCt*O€.VÀ|Ùœ¯dv~,Pk&JeFi$Kp*Nh"Fm&Ji!Fl'Jn(Ik&Hf@]@_BbBa>e@a<Y@ZEr+SŸ[p¾uwÂtvºmn¸hnÆ{vщ~ÔzÔ~Ơ’€Ñ’€̉‘„Đ‚ÏƒĐ|Đ‘|̉€Ó“‚Ó•„Ó–„Ó“„̉–Đ”†Đ„ÏŒ€ÎŒ~ʈ}Ç„~Â}À„}Ä€x‚~À~|¿|v¼}¼z|¼||¾{{½{|Â{~½xyÀ{{Á{yÄ}}È~zÇ€~Í~yĐv΂|̀„}®?N±HQ°BK®AL©CS¯@L®CK°?J¬<I¬@L©<L¥8J¢:N²FRÊVYØlf̃wmălçzé“xë–v́—x́zí›x́œ{îœzï›xí’ræ„iáwdÚfYÁNO¢:K‘0LŒ)H•-H™3J :L£=P§?R¬ER­BR®BP­EU°IX°EV²DT°BP°DN´FR±BN·@N²HPºHPĂLQÂOUÄNSÄTTÆORÊTÙTSÊUTÈWXËUSÍZb̉[Vâ–rÀ\NÍZOàjRíœhĐff»Wuª^Œµg…Æbs¾TaÈ\d»Udz"G\Lk,f…XˆZ@K BSFX†ƒJ~V?R:[DZHr,\†Ft‚<gt0\g"JZ>V>Z@dL[Ig(Mp2[S >\F†U‡`LY>|FvWF]VRLaE¶rxÅ_a¥;S¿w€Ư«Ü‘~Ư˜ˆÜ Ø™Ô†ÔƒÖ˜Û±¥×³ªÖ±©Ø²¬̉ª¨Ó© Ñ¤˜Å|kÀTZÍ`iÔqwÛxyß~€á†‰â‹â‰æ敕癒Ꙓ꜔ê”ëœê›‘ëœ́¢”́£•î¨˜́®î´¥î´¥ë´¤î³¦ï³¡ï¶¦ï¸¦đ¼ªñ¾«ó¾«ñÀ°ôŲöȸôƸơÁ²ó¿«đ¬—â‚|ÆNV,F}Bc9U :R:V?kGw"P¶xˆÙ£ ºq{…+N{,LdHn,Nm*Ne Ef Hk$Eo%Ho*GjCb>^>bBa@d?f!E^?TBe K†@d«bsÂrwÁrsºlqºnsÈ€|̉Œ€̉~Ó‘€̉̉‘̉~̉‘€Đ~Đ€ÎĐ‘zÑ’€̉’‚Ó’Ó˜†̉•†̉‘‚̉‘ÏÏ̀‹~ËŒ}Ȉ~Æ|ƒÀ„yÀ}½~¿}{¾||¿~|¾{}Áy{¾{|Â{{¾y}ºwy¼z|Á{~ÂyxÆwrÉ|wÊ{x̀}v±GR¯CO¯FR¯DO«@M«BN®@L®@M±>L¬AM©=J¨;I¤8H¯EPÊUTÖjf̃qfäƒoæŒxç”|ê˜ý™|́|́œzî›zî›v́—v́qè†qâvdÚdY¿NR¤:L’.L‹*H–0K›6PŸ8N <O¤@S«BQ°FR±FR°FT°DR¬>R°ER²CP¯DP®BQ³BNµGT¸HQºJRÀLSÂQTÇPPÇTWÉTRÈSZËUTÊSWÈR\Ơ†‡ă®‰Ö„dÀbPb:n6t:(=¼Zn²j•³d„ÇcmÅV]»LUÂRV9TdJm.lu;g|KxL
-=NHb"XŒcv8iP :Y@`Dk"Pp&OdDaDeJZ;V ;X@]A^DaHf'N_GT Bh.`‚Oƒ^Kg&Zw7id$YQCQ>¢\hÍ}n¨DY¸]lƯ°¢à„Ư“‚ܢܪ—Ô—‰Đ„~̉Ơ›—Û³«Ú¶²Ü¹´Ü´¬×³¡̀Ÿ„¦PJ•*>¢:PµJ^ºQ`Å_lÍhsĐjp×ruƯ€âŒå“’藒뜕렕ë’ꙑé똌ë́¡‘́ªî´£î¶¦ë´¢î°¡í®¢́´¦ï¶¤ïº¥đ»¨đºªñ¾©ôĂ°ôĂ´ôĂ°̣¾­đ³—ꛉÚvqºDL…@p=a<W 7T ;T?lFw'W¤f{Û¦Á|…2Rp Dk Im&Jf"Jh)Pi$Jl*Ns1Rr0Ph!@d?]=a@`@e?fCY@XFk"Q•Nk¹ntÀtu¿ps·hpÀrr̀…|Ô{Ó‚̉~Ó}Ñ~ÑÑ‹}Ñ}ÏxÎ~Đ‹|Đ}Đ€Ñ‚Đ’‚Đ’€̉“ƒĐ‘‚΋͉Í{̀~ʈ€ÉƆ}ąÆ~¾ƒ}À|¿€ƒÄ€~Á€À€~À}~¾{z¼yy¹z|º{¿{|ºy{¿xxÀuuÁuxĂvv¯@P²CN®BN®BP­DP­CQ±AN°BN°DN¬@M¬<J¥;I¦<J²DLÉXVØf_̃woæ‚nèsê‘yí™xî‚́œ{îœ|ï|îœxí–ś”pæ…láxfÙdXÀQS¤:M0L‹-K”2M˜6OŸ3J :M£?R«AR¬@R°FU²GV­HU±HU°ES°DT°DQ®CT´FUµCN¶FN¹HRÀJQÂORÆSVÈSTÆSXÉVXÉVVËT[ÎY_ơ¾›̃‰i¦<A|;Q 9Q <S Ar&Q¼x”Đ °×§©ÍVZ¶BQ«FT4LkEeR~?s{N‚g%UOFPKu7n–rn0^Q 6`EZ<_DaF`G`Hf"OYAX?bJZD\Ah$Vt._k#VbOp.jy<ldRl0`XEL >H 9…D[Í}q¯LZ¯N^Ôœ“ࠆߖƒƯ¡ß®–̃´ ̉†Î…€ÎˆØ¨§Ü³ªÜº²̃º±Ú¸§Ê€¬HP¨BW«K^°KZ¯EW©@NªBV›6I¦?U³K_ĂVf̉mrÛ‚ƒăè“ꢘ뜔ëê‘́’ê•ë‰́£’́¨—î° í²Ÿê²£ëªœí­ë°î²£íµ£đ»ª̣ºªđ¾©ô®ôÀ¬đ»¦î®˜ă’Övn¾RX3Jx@j:a8X 6S;V ?iD{.^’JeƯª¦Æ€…LedIhCv,Qj$Ii"HiEm'Hr-Jm%De=_>]>b?dCb@fGXBZFx/W Wq¾ptÁvx¹pv¸gpÆz{Đ|Ơ~Ơ|Ñ}ÓŒ|Đ}Đ‹x̉Œ~Ñ{Ï‹z΋|ÎŒ{ÏŒz̀~Đ~̉Ï‚Ñ~Ñ’̉‘~Ízˆzʇ~ÍŒ|̀‰{Ê~ljlj{LJ~Â…~ă€Â††Ä€À‚‡¿~|¸z}¼{|½zy¾x{¼wz»w|ºx¸x|¶sz»rr¯BO®FR­ET®BR®EP®CQ°ES°@L®BL®AOª<L¢=N¢6J²BLÈWZÙj_̃yjå‚oè‹të’x́˜xï™~í́œxïxíœ~đ~îsç‡mă|gÙh[¾NS¢6K-KŒ+L’0M—6N4M¥BT§<O«@R­ES°HV°DR«BS±CQ°IT²GT²DPµEOµCL´ANµGP¸FQ¼KRÁUWĂPUÇQVÊRWÈW]É[_ÈZ`Ñccđ¤~̉†r’6KtBe>T =gE Lk¾™́•uâ‹fÂRX•+Hˆ-Mƒ+NhSj*c{Bm‡^‘RCQJb#^€D~pq6`M7W?R<g"Um3]b*R\Fl/Yc LV>dGX=V@XAr,\†H€dKt<vd(Ti%[f)_OAJ@n*LÂyp¾`d¤G[̀Œ’̃œƒÜ™„̃¢̃ª˜àº¦Û®œĐ‡Ï…‚̉•™Ú®¨Ù´®Úº°Ú¶¤̀ƒxÈ[bÎdjØtyØrv×rẁhsÂ]j´Q^œ<S‡">‚$@†$>4H±FXÍjoƯ‚æ–‹ê˜é™é•é™ç–‰ê—Œ́›́ª›í¯î²¢ê²£í¨œ́«Ÿë­ î¯î² ̣º¡ñ¸¤đ¸¢đ¸Ÿê­”߀̀rm¸X]®JX£<L(D~=w:d 4[ 8T<TBdEr$U„=ZÚ¥¢̀‰‹«YkgH`Bj"Fu(Ho*Kj#Eo(Il#FeB` EaE]?_?e<g"CeA\C^C„:\¬dsÄts¾px¸kq¶lù|Ô~Ù’~ÖxÓ‰|ÓŒ{Đ~Đ|Ñ~Đ‹}̉ˆyĐŒz͈}Ή€Î~ÎŒ}Ë‹‚̀€Î‚ĐÍ̀ˆ}Ɇ}ɇ|ʇ~Êzʈ|Ȉ~ȆzɉƇ‚Džņ„Ĉ„‚„ă¾}}¼|}½{|¾{z¸~¸wz»w|µrx²py¶pt¶GQ¯HV²DS°DQ±HP®DO®CN¬EQ²DO®@Jª>J¦<M¥9J°ANÉTT×g^àujălèý–xë™vî•vî›}î™{í}ïœ~î™ví‘xè„mâvcÛi\ÂRT¡9L-H0O–1N™8P9N¤:J¬=Pª@P¬DR²JV²ER±EQ°AN®@N¯@N®BP²@N´EP²ALµEN¼IR½IP½MSÁRV¿QVÉRTÈTYÊ`cÑnhØibÙlbß„m³XRvB`:N ;RF˜LoÆovÆ\a£:I¤CV€ GŒ8T*SgTz?w|BugOVL\PyB|:{xMp|GtM ;QAXKr8cl%U\"Kh6_m.Xt0^Z@`BS 8T;Q
-:VBt6f|>s~Q‰U<y9t[HJ?TBªcl̉x°KZćஙܑ~ƯŒà¨›ß·¦̃¼«̉›ŒË€ĐŒÓ¦¢×¶®Û¼±Ö²¡ÉqhÊT\ÔfjÛsuà{xƯuzÛpnâ‚€à~€ØlpÇXcµJY6L“-E†$>‚ ;)A«CỦpră€æ‘†ç‘‡é‡è’é˜ëœí§•î­î® í®Ÿ́©œíª í´¢î°¡í¬›đ²í¦ä˜Đvg¶UT¥EN”4K1M˜8S¦FX¨BVª?L¡1Dt:f;W=U>^?p%S~<Xؤ¦Î…´eto&KeIaBu1Rs-Kt&Gs+Ln$Cd?Y;`?^>_?d@h"GdD^DfL’Fb´p|Ătv¸lu·hrÁtt΄|Ö|×|Ö|Ô‹~Ô‹|Ñ|щ|Đ€Ï‹|ĐzÎ|ψvψ|̀ˆ~΋~̀Œ~ÍŒ‚ÎŒ€Î|Î}͈|̀€Ëˆyˆ~Ɉ|ˉ}Ȉ|Ê‹zȈ‚ʈ~˃ʋ…lj†Å‡„Ä„ƒ¿‚€À‚‚»|€¼|~¼{·x|ºu}³ry³tz³nt²BM­BR°GP¯CS¬JV±KV­FQ®FP±BL¯@JªAP£5H¡8J°BMÈTWØbYàwhă{méˆś”yî›xî”sî›|́™xï›|đœzđœzî”xç…läxeØh\ÁQR¢:N‘,I1N˜1M8NŸ:P¤BQ¨>Q¬AR°JX±GS²BQ²DQ²BP³CO¯AP­:I°BO²?I´GR³DM¶DM¹JRºGN¿JPÀOUÂO[ĐfiÚ{vátÜojƯneÚ}j§VemE‚:Vp0SJB’Pv¿cqÂbo›1QŒ6RŒ7Ty"IhMp-b„M„t7p]R\Uv@w„Mƒ^Qh3Z”hV@TDV@p)XcHSBWGn1`ˆKxk#OV8T 6X8X:Z?_"Qm7VˆY‡YDh*UL7G6†>V΄vÊb`¿lxÜ« ̃—Ü—†Ü¤’Ư² ß¾­Ù³£ĐŒ„·†ÔŸœÚµ®Ü½®Ö¬”¾^YÄRWĐ\cÏ]`×kk×ijÑjqºH\×vtăƒ|ƯuuÍZbÎaa³?P®?P¦8J›2H•/I2KµGYÔhnă„æ†çŒ†ê†éˆ́–‹́£˜í©œí°Ÿî°¡í«¢î©Ÿí¬í¨™ë¢’ê¡Ö{t¹TV 8M=T¦Jb¦I\±UiºVcÍdjÂLN¸CJ¢4Bv=o=Y;T?[<t&V}/RÖˇŒ°ar}.OdBbCu2PgDo"Jr(Kp(IeB\@`A`=dAfAfDdFdIp#PRn¾rx¿ts¶kp¹jnÇ}{Ô|Ơ{Ö~Ô‹~Ô‹|ƠŒ|̉‰|ш~ÓˆzĐzĐ{ψ~ІzΉ{·{φxÎ|Ï~Đ‹ĐŒ{Ï{ΉxΈẁˆxȇ}ʆyˉ~ˇ{Ê‹zˀLj‚ȉ€É†È†…ȇ„Ç„‚Ă…„Ä„}¾‚…»€º~~¸x~¸uy²r{²qz°nz®AO­FT¯FT°FT°JV®FV®HR®BK°CM¬>G§:J¤6E¢4C¯CMÉVXØg\àv`ă€pêt́–x́zï˜}ï˜ẃyïwđzñ~í”tæ‡oâ|iØl`ÂTY§;L‘,H‹)G•2Kœ4J 8M¥>P¨AS°DS°DR±DQ®BQ²ER±AN³EO²BO²>K´FP²AK²AJ²CN¸DK¾JN¹GQ¸KU½LUÇTZÚxñũ€ỹzpßvlæ…lØ …¯nqÅ|~¿lz–Fd¦bƒ¾U`Ôjf¢=Rp(Il"D[Kk$_{7o`™x0hp&fp0h‡X†n1fK@ZH‹[ƒe%TVEYD}=n\BP=RCh(VŒR}t-[T:U 6Z 5`>\:V:Z?` Fr4fN
-8J:f!BÂ~y¾[`¶ZfÚ¦ Ư ‰Ü–‚̃¡ß²âºªà¾­Ù¦̉“ŒÓ–”Ú®¤ƯÀ­Îˆ­JL¸BHÂJN¾FPºHM¾OPÁPNµKQ†<¬CKÔthÂP[¬=L¯BRµDYÂXi¸DT¼LZ¸AT¸EV¼DVÏ[b̃tvà~‚æz剃牂둉́£—î¬đ²¢ï³¦ï¯ î«Ÿî®¡́¥™æ“‡Ø~|ÂZd´Wf²N`¶U]¶R\ 8IŸ9G²HN±AI™0B–/C(Bz =y'HZAU>[Cw,Xv,Pќΰ_jB[a<b@r/Ph Dm(Hp)Gl"Bb?]>b?d>b@f?a@_Af J‚3YªbvÁsw¼ru¹gm¼km̀€zÔ‹|Ô|Ơ~Ơ‰~Ôˆ{Ô†yÓz̉†|̉ˆzшx̉ˆv·χxЇxχ{ΉzΈ|ÏŒxĐŒ}ÑŒzÏwΉẁˆỳˆ|̀†wˆ{ˆzʆ~Æ„~Ȉ€È~̀Œ€Í‹É…ÉŒ‰Å†‚Ä‚~ƃ€Ä†Â…ƒ¿¸}~¸vzµu}³u~°oy°@T¬FR­ER®HW¯FR¯DS®BM¬AM®DNª<I¤<I 3G¢2D°?LÈXUØe`áugå€kèŒrí–xîœuîœxđ™tđ›zïœuîœv́{́vçˆvă~gÚndÅQU§<K’,E(H–0G›3H 3I£@P¦?S­AN­BR²BR´EQ²BL±?K²BL°BK³@J´?H®;I³?J´BL³@K¶ET²N_¶Zt¾o{ÎpuÛtjÜ€r̃‚x̃€x̃|pæhî–păgá}à‰€¿Wa‡/Mƒ$D} @`A^2[]#Qh)f~;t^‘}>sdT|7vv3j‰[ˆg&XG>RCs<bv:lY@ZH€BrZ>R=R ?[L{AkˆP~YBV<Y=\8a:]<Y<S:V<XLL
-5¢YcÏxr®JXĐ⩌ږ…̃›ˆà©˜âº¨äÁ³Ưº®ÖªÖœ•Ú© ̃¾­É‘}œ7B¤6E§7B 3B¤;H‰$=†"=„#:~6o5z6”/:w9m6w;4G¾Va²AVĐ\eËU\ÍQ\̀R^ÑYaÙfm̃twâ|æ‚~ç}êˆîŸ“ï°¢ñ¯œïµ¥đ²¤î®¡ï¬ë§–߆‚Ñno½`h·X\›5B…(=z8r7r:}>{@~"@‹'?‡ =ƒ,Dk8\;R :\B|1Yw&N̉—˜Ë–¬Xh•G]hCaBt3Ol"Gp(Ll"Ef?a<`?`=`>`>d@^?U=eJ’Ib¸pw¿wzºquµhoÀvvÎ…zƠ~ƠzƠŒ~Ơz̉ỷ…zЇ}ц{ÓzÓ‰vÓ‡wІyĐ„yĐ„yЇ|Đˆ|ĐˆzÎzЉwÎzÎxІzˆyÎ…v̀…zʆx̀ˆ}Ê{dž€̀‰|ȉɈ€Í‰È‰‚Ȇ„Å‚€Â€}Â~|ÀÁ€¾~º}¾z€¸v~¶w{±r~®@N«HR°DN¬DQ¯AP®DQ­@M¬DN®>H§AO¤8E¡8G›0E°>ÌVT×f^̃uhä|jéŒrê”ẃ™tïwîœvîŸyïœxí|í˜ź’tè†nâxdÚhZÆRS¦;J3L*D–*B2F 3I§9J¢=K±@O´DN²BL·DMµBJ´AJ´BL´<G°>L²?H²BL®<H²;G®=P´QdÂ{ŒÊÔ‹zÔqjÜwfàzhàrß|sâ{mâpÙxk·N^ÀT`Ămu”<^^:T<K ;QHk8kt8s|:|R‡–jp&ak$]„G‰x4hŒ`d#VNDWDr4fq2a^MXB‚N~X?S ;P ;RH`R_…M„`MS:X9b:_8V 5P 6G>L9w3Qˇ€¾Yc¿lṽ³¦Ư—‚Ư‹̃£’â³£ăÀ±ß¾®Û²§Ú® Ûª™ß¼¦Ă…o+<”*B’&<ˆ <r:v:o:o:l:j8j8l<h8f<a5]
-3k7€;»UbÔjuÔ\fÖ[aƠXaƠ]dÙhpƯnpâvuä}zæ‚}́Œ‡í “đ®¡đ²¥đ¶¬ñº©đ·¥́®™ä–†Êkf;H'Br<m7p8l8k8j8l=n?p<v?$Ay"A`6]=Q <X<2ZsIĐ“’Ó˜¬^n–F[z/NbAq,Nn(Jn#Gl%Df@`:`>c@^@d>fCYBR <bGTi¿txÂtq¹mp¿klÇzuĐˆ|Ô|ÔŒx̉}̉‹|Ó‰vÓ‡vĐˆzІ{Ñ‚vшwÓˆxч|̉†x̉ˆvχ{Їyω}ΉxĐ|Đ‹yĐ‹xÎ…x̀†vË…{ˈ|Ê„{ʇzɆ}Ç…{Ȇ~LJ€É†‚ʈ„ƈƒÇ…€Ă…€¾€À€¾|{¼z»}€»|€·z~¶wzµuz±s|¨>N¬DNªBN§>O¥DQ¨@Q«<K¨<M§<J¤=K4E™0F˜0G©8FÄOPÖdZ̃tfäkèŕ’uíyđvïýxđ|î›|đ™x́uèƒiäwdÚnaĂRR¤<L/J‹&A“-D2Hœ6E¤6H¢4F«@N¬>L²HQ¶BM´@H²>J®>J°@L­>K®@L®;I¬5Hª4N¯F^Å‚–ØöLjáz^×l_̃vfàvfá{pâ~rá|rÙzwÀfr“B\lF‡<X€.PR <G @RMzG‚Xz3kz:pb—t1_€B€t1i~@~|By“oc"UMCUCu3fXAq/h[I‰W†[@TAR :O
-;R Dj,Z_Zm,_P
-5Y 5`9\;J9F <U=³opÅnf¹VdÚ© à ƒß”€Ü †̃¨™á´¨â¶ƯºªƯ²©̃³¢Ư¶ŸÆw*=† =†<w6n:n<k:l=i:g5c9d=k&KCY„9Rm?Z7Y9_ 6ƒ>¾KXÓfkƠ`eÔZbÖ\dÛdiƯklàrxăxuåë†í¢˜đ°Ÿó»­ó¼¯ó¿­đº¥á ‹»[Z†(BjDd@eCk>~(F|(Do=h<j=oAl Bp>z<l8d8_7U:Y?v)SqF̀Ơ˜­[n”H`v,Lo#Lp*Ln&Jl$DkAb<[<`=c<b?eAbCZATBr$Jª^lÄy{ÀspºntÅstΆ~ƠÔŒ|ÓŒx̉ˆỷˆz̉†yÏ‚yчxĐ„zÏ„zÏ„vц{уvчỷ‰y΄ỷƒzІyψzЇ|·|ψsÎ…{̀‡xÉ…ỳ†{̀ˆzÊ„zȆ~È„~Ƀ|Ȇ†È…€È…€Ä„~Á~Á~}Á|¾||½~|¼{~½z|ºy}¶x{¸x}µv{´s{¨>L§=L¨AN¦<J¥>J¨@N¦:H¦;K¦:HŸ8Iœ6D•,B’+E¤5H½PTƠbWàrcä~féś˜wí›xîtîrîvï›~îœtîv́nè„häxbÙe\ÅRT§8J(CŒ&C—(B2F¡6J¤:J¦:J¨?J«=J°>H±BN¯<I¯<I°>L­;H¯>Jª9G¥8G¦0H¡.NÏ„~í¸̣µˆøºt̉ZQÙnb̃raàveâlälÈadÁox°^o‚-Mz-Sm@X@J DLEU‹^l'X^I†YŒd)SXOx<pBwz5v_”l”XJJ <XFn0`TFd$Ti&W‰^ˆf!KXE[>T:T=TCm4_V†Gty:pgOZ6U
-5J ;H
-:H]Í‚z«HWÎŒă²™Ư–‚à›ˆÜ¢“̃ª–ྰàÀ´ß»®̃³§Ü¼¦È{*@”)B‡!>u7g9f;i7k:h:i;]=hCtJFf¿– Á–§ Xpt$E[ 7Z 6a:*GÊXXƠbdÔYbÙZ\Übj̃ejánoâuwç}zê„î¡’đ²©ơÀ­ơµôŭ篖®PVj=aD\C^Lp!K2dœWv®k~—?Vk<^ 5f8m>p?n>c7h:a=V;^@{.WpFȆ١­`rAYt'Jo Hv.Ps-Km"Eg@a<^<`>b<b=cC^>[E_Gˆ;Y¹jsËxvÄvu¾orÈ{{Î|ƠyÔˆz̉Œ{Љ}̉†x̉‡z̉„wÏ„yĐƒvÏ‚zцyĐ‚yÏ„vĐƒuщĐƒzσyĐˆzĐ|Ά|΄|ΆzÏ…zÎ…yÍ„tΈ~Ά|̀„|É…{Ç…|‚|Ń€Ä„Æ…€~À~Á||½||»z|ºy|´u}¶u{¹vz¸w|²t|µt|²qx§>M©EP¨BQ¦<L¨;J¦?O£:M¥:J¡:H5F˜0D“1E”)B£5DÀMNÖe[̃sbä€iéví™sî›{ï™xïxîœ|ïœ|đ|ïvëtæ„lâvcÚfZÆSP§:H*D‘(D˜,F¡4H¦5J¤<N¬>K­AN¯?K°?K²?M³=H°CL°<J°BK«;I¬8F¨5D¦3J¢0Oáv誘ơ¹…à€h̀^\×lc̃teâzfähØrk¢C_Êjpº]l|+Ox$KO >RIXNp>pˆVzk#VVF{Izs9aJ BNHv6l_—‡F}‰YƒDpVHP>WG`FT>XHWF{Onx<h\D\AW:\>[AZ?bBW>b)Ls7abHT
-:K=a@Áxw¼]`³\n೥ܘ€̃̃¦“Û¤—Ù¯§ăĸ࿳໧àÀ©È‚˜7E4D”*B|9g8a 7k?†2IvAs"BpDT 8d@0W…8TÖ®¯á¼ÀѨ®²~ƒ+Ns=˜;Z‘(GÀOTĐXbÎR[ÔV[Ü`gƯejànrßplå~{éƒđ–ô¹ª÷Ǻö̀µđèÂoc|AbB`CZF\Jx*NªxŸŸ[sÈ¡¶fv‰*Id9b7j8n9jAd;d;_<T 6`@~-TgDÇ‚…Ø™°^t–BY‚8]q(My4Rp%Ho&EfBa;`<`;d @bB^>\@WBl"OPfÁryÊztÂtt¿pqË{Ó|Ô‹zƠ‰|ÓˆzÓ‰zшyщw΂wЇz̉…|уtÏ„zĐ‚tĐƒxÏ…zΆ~Đ„wĐ„wΆ~Ï‚x΄yІuΆ|ˆ~͆vÍ„v̀„xˆ|Í„{ɃzÅ‚}Æ|Ä‚}Æ…€Â‚€»}€»|y¼zy¼yx¸vzµtz´w{µpv²t|¯t|®q{¬s|«px¬DNªBN©AO¥?P¦?L¨@O¦=N¥;K¢6Kœ4E™2E’,B‘'@¡8IÄPQÖf^̃r`ă‚kérî›rîxíxí™yîvđŸxî wï€éä„nâxbÚdZÆRP¥:L‘(C“)Aœ0E 2E¨;J©BP«>L°@K²BJ°BL¬@M­>L­BN²EL¯BK®?L­9H¨9D£4G!F¶[]à¡”Ư¦{̃¨”ׂÖvpƯtlâxjàxiĐkmº[hÜ{hœ8Rc@dALE^TFzDr\FXGo2hp0Yd"XPKYRx:n”d™|;s†[ˆ~>o^KUBV@U>V=ZCSEk1S‹Y‡e"M`DT 9X>Z=^E\=U7YAVFR@^Rr(g–NfËvm¬EW֤㬒ܖ…Ư¢ŒƯ¬™Ù¯¤à¾²â·àÀ±âÀªƠ¬”¢FN¬AM 6F‰"?s;g8k:#B¡IY‹1P|/N‹>`lEt(HCeo(P̉®½ä¿Ä潾ܰ°¿n~•&H¸LU¶@T¹@IÊRXÆLV̀T^×ZcÚdk̃ghájpç{v́đ§›ơ½®úĐ»ôĐ²Û˜†¢>K‚(HgDz0NbCdCx+O?d™TrÔ›¥Ë|…¢9Jv>a8g<g6i<b;b:bDX@d@~3\gDÀ„Öœ¶n’4N‹Dfs*L;Wl"Fj!Dc>b:`>a>a;`=Z>Y@]I}0Rª^pÆvvÈttÁssÂstÏ„zÔŒ̉‰~Ó‰x̉‡{Ôˆ|Ô‰yΆ€Í„|Í‚x̉‚vÑ‚vσxĐ…vσyĐ€v̉‚sÑ‚yĐ„yÏ‚vÍ‚w΂xÏ„|Ï€vÎ…{̀„z̀„wË„~̀„zÈ€{ÆzÁ~Á~|Ä|Â{À~~¼}€¼z|¼y}¶z~¶v|±s{²ov²rx¯oxªovªlxªo{°vz°ANªAQªGT©=L¨CP«>J¦?M¡<K 8K›;K˜2B•,D&?¢4F¾OQƠbXßrcănêtî˜v́›|́zí|í yđ¤đ {ïœ|́”vè†rău^ÙfYÈTR©>K–+B”*C›1G 2Fª>K®AN®AK¶DL¶CK³BLµFN±DN³GN°EP²@L±FP®@Lª<G(BiB—MRÆ•›2O«^Tê°’ç­œâ|à€qÛzk´Q\‹,D‰/E^BP=RGWP~Gz‡HtfQSCm2ip-a`Pt8nZNaYzEz’^˜|9t•v |=mXCSBZD[BZCW<PAcL’dp(U[?Y?X:Z;`D\8X 5W9R7L@L >j(N¤^{™@Z¸l€Ú¥˜̉‡‚É€ƒÍ’“צ¢Üº®á¶ƯÀ´Ü¼©×±°Z^°GWÂR^³HV¤8L•2H{<l6‘&F¨HS«Xlz'J‚6V‹;V‡7WwJbÜÇÏçÇÆêÅ¿éÀ·Û”®AZ¨6IÉR\¸:HÄHTÄJXÉP_ÓT`Ö^`Üdmßqt惀́’‹đªöĂ³øθîŬÊpn£<P§Rj|&KE`=]‰6RA^{$N°r•Ú–̉zƒ«AN~ <h3`3b 2f8^:`9^9W=fB~3ZcFÀ|…×¢œÀx‚„2QGbz.Q„@\hDm$F`>\8a<bAeBc?^@ZBbEŒ?[´joĂxvÅtp¾npĂyzÍ„|ÏŒЉ|Ózщ|Ї~̉y΃zĐ„xÍ„v΄vÏ„uË‚wÏ€ù‚|уvÑ„z̉„yІzσx̀„vψzÏ„zĐƒtĐ‚v̀„xÍ€yÊ€vĂ~xÊ{Æ„|Ă~{Â|Ă~zÀ~{¾zz½{}»vxºx~¸uv´ps®nv°os®jrªmv¯py²z~»‚„ÆŒƒ¯FQ©CP©BQª@JªBN«@P¥BR¢8JŸ=Mœ8G”0B‘*BŒ%@4F¼MRÔb[̃sdămèŕ—xîvïyîœwñ¢zî đzí—xç‰oăv`ØdZÈSQ­?J–2H˜+E4F¢6Iª:J°@K°BL¸DL»FL³DK¸EK³JW³?M¸FSºJQ»YU—1B}9q:^?l@Ƭc{˜穔úÉ¢ở¾ê®°TTbGR>TCSAO BXKx<n~:hi Pe"\cWq0fi*bd!Up/am+gs0nˆ\”b™‚=y™z€H~RDVA_H[Bd#MXBSA^D}BghF\=bEZ<X:a>^<W9P 6Q<PHVFœZnªUb˜H`À¦ÆƒÍ”’Ô ’Ü°¢à»­ßÀ³̃¼±Ü¼©Ø²²\_µN\ÂT\Í_dÈ\hÇYdºQX <Ov8=®EZ¹V^¡Rl}.RrHy*X^ŒË±ÅçÁÄíÁÀî½¹́²¦áˆ~Í_kÂBTĐWVÆKVÈKSÎV`ËNZÑTcØ^fÙgnàppå‚€́”Œđ¶©ö̀¾÷̉ºè¼ª½S`´M^Àlv¦Wyƒ4RB\‹B`€.X›Y…Π±Ü”̉q~ª;L€=m5j6j4h6\7^7Z;Y?o)Jz2ZeJ¹u„Ù ¾{ˆ€0T‡@b‚6Uƒ<ZhCfA`<bBb@`>i$Fc=\:Z>dC—Nd¼ryÅytÂut¾tyÊvÑỷŒ|Ñ{Đˆx̉†yІ{Έ|̀‚wÏ…v̀€xÎ…z̓vÍ„{΄|΃wÏyĐ„w΀yĐ…xĐ…xÎx̓zÏ‚yÏ„xÏ‚v̀‚w΄uÈ€zÅ}xÄ€zÆxĂ}yÁ€¾{{À~z¾x|¹sw¹t|´tx´r|±mt®oz­lt°rw²y}À„{È‚Đ”…؇®@N¬FQªCP­BNª@LªBN§@N¢9J¢;J›:K–2F‘*C$@6F»LSÔ`Yàubă~nèŒrî–yívïŸzđ xđŸ{̣Ÿ~đ~îŸî•zè‡oâxfÚdZÊRP²>M›0G1H 4I¥8I¯>JµCL²EM¶GN¶JP½HO»IP»HNµEL±?F3<„)<l<2[z$P‡<_§_|Đ˜”˂甈ùïÑôƯ¯´r`h!Lm0jM>R@M?TJs4nK„|;tq5nh(aZKl0jv7ny<s|:r€Dys/hb•ˆU’s0h–tˆX_L_K[BV=cFZ<X;_=f#H]DbEfFY=\:\<`>Q8N :J 8RL„D\Âwx¢BVÀ†Ú¨Ơ‚zÜŸÚ¨•̃·¬ß¼²Ü¿´Û»¨Ôª’¶ZV¾R_ÉVaËR\ĐVdÔhmÖjoÑcj¼Tf6R—2N³@TÀQgÂez´a¨Z„³u’Χ¯á¸ºå¿½îļæÜmp̃soÓ\g̀NW̉_cÎPVÍNX̉U[Ó[dÖ[dÙ_hƯinä~똒̣¾´÷ÔÅở»â®¼P\¬<Pµ\hÂp‚¦`•Hv•M~¦lœÊ¢¶Ø «×’˜Îgp¦:L€>m9n;n6o=c>Y<`C_Br,Lu+RdL­cvÚ£Ÿ¿„‹‡8\†>`‚>^€;Vl&G`>`>_>];^=k>f>\>Z?n(M£Zf¾uxÂssÀqrÂtt˃̉~Љzщz̉‡wЇzцv΄|Î…w΄vË‚wĐ‚x΂wÍ„z΃̀…|ʃsÏ…x̀ƒ|Ï…x·{·wÊ…z̓y΃zÎxÊ‚z̀‚sÉ€wÅ{Ç€xÆ|wÂ|y¼yy¼yzºxw¼wvºyx¶qv±qx²nv®lw¯tz»~{Ň|Ê€Ô–ƒØ„Û¢ˆà«‹¯DQ«EP®FPªAN¨BN©BN©@M¤8L¤8K:J•6G)@&A 2GÁPQƠcYàsbä€lêŒsë–uíœ|î uî¢yï¤|đ ñ ~́—vê‰qă{jÚg[ÊWT°@N4I™5J¢3D¨8I­<J³AMºEN¿HP¾LT¼IRÀJR¿MP³]bp8^7b;tHSl²k‹ÇØ~„ä”ß«­áŸ’óɤʔk|<CXKYKH€SMVQh)l„P’o¥ŒZ†{ApP>OCPDuB_L‚Byw6mr2lt8x‹j˜’g¦k(dœƒ°b|>rh"Ke$VR=[>T
-4V 8]A^@^Ag GdB`A^=^#C\>R6J 7K <e C¼ru´MX²]q̃·¯Û‰Ú•ˆÜ¥—Ü°¡̃¿´̃Á¶Û¾ªÑª”¬OQ½LVÊX^ÍZdÏ`ẻ[bÙkmÚrxØnsƠhlÅ^k·HX¯B[²D^ËSdĐdnÑt€Ø€‰Û‹‡Üœ›ă¤¡é¤Ÿæœà¥Ú…–Úq€Đ_r̉_hÖ_bÔV\ÎQ\ÏQZÖZbÔ]eÙXb̃ovå~€́•̣¹­øƠÇó̉ÄડÅj|´Nm°LoÄXp̀s‡ĂtÉz”щבцÎpr¾HP‘*@n4{#@{">t<r?d?[Bc"K`Fw2Ks*RcK©dzܗĘ—Gb†;[ŒHcs$Fm"JcDZ:^AZ8b;h>b>Z8dC†8V®gtÀxwÀsuºnrÆ{x̀ˆĐŒ‚χ|Άỷx͆x̓tÎ…ỳ„v̓xÆ~z̀ƒz΃vΆ|ÏŒ‚Γˆ̀ƒzÑ…w΂xĐ„zΆzˆ{̀ỳƒẁ€v̀€vÉ€wÊ~tÅ~yĂ|vÄyvÂ|x¿zx¼yz¸t{ºvy¼xxµst¶qx²nt´tx¼}}Æ{Đ“Ö˜Û¤ˆƯ§‰àª„䮇粌°JV®IQ®DR­DR­IT¬FN¨>K¢9H 8Jœ1F˜0D”-D$>2D¿MPÔb\àsbä‚mètê–wî™zđ{ï yñ¡€ñ¢|̣¢ñ {đwê‹pä{hÜk\ÈUR¯@M2F›1F£7H¬<I±>I´FP¶GQ»NR¾LR½OY¿KSË^P«XY\8\ 8ƒ*P¡JfÆ…ŒÍ‚ˆĂwŒÏyˆ̀r‚ÎÛ¥¡¬ifb CY RTNVP{G|‡PˆPˆW„}Erl/Y|Gx_MJ @MC[N„X’UJ|H}v6pl,kv8x‡Y‹v«…G‰¡‡¯‡R~~Bwn1ar9hSAY@S:U<Y=]@^?a@]=`<`A[?Y 9O
-4J
-8N
-6—O]Érl¨>UË•–ଛړ„ÛŸƯ®̃¹¬àöƯ¿«̉®¯LN·DNÊP\Ï_ỉ^hÔdmƠcnÙjqÜnuƯosÙpvÖkqÊ\hÊcrÎ[fºGXÆRd²>QÅ[l̉gpÈfiÊnlÄdk̉~ˆØ‘œÛ—£Ü›œ̃ˆØnq̉W`̉V_ÎVb̉ZhÖXbØ\dÚ\fÜkqăzzé—’đ¶¯öƠÊôÖÊæ°ª̃˜Ö΀Œ̀p~ÖvÍdpÈ]g̀nrÆpr¬JTŸ4F“&>€<t<—8J-Av<t@eB\=e"HdEv0Mq#J^K¤\uØ•‘̀“—Vn}3TD`u,Jp$F\>\>`?\<e<l#G`BbBy<X˜LcµjtÀux¾mnÁopÇ|wÑ{ĐχxшzчzΆ{Í‚yÍ„z΃xÊ€xÄz΂zÍ‚zΆzÏŒ„Ê’‹È„{̓ỳƒ}Í„z̀…{̀‡zφz̀ƒù‚zÊ~tÄ}xÇ~uÇ|s¾wv½utÁyv¿xv¹tx¸pw´uz¶uy³tzµrw¹{|ȆwÓ“~×Ü¥„⨆⬅䯈它氆贉´CP®DP°HW®HU«BN¬DQ¥<N¢9I¤4Gœ4F–.B’(@$?œ0B½HLƠc\às_äqèoê˜x́›}ï}î¢|ï¦|̣¨|ó£~ñ¥}đ—yêtå~mÜhỲXT±BL™/Fœ0F¡6F©>K°DL´DN»EKÀLR»KVÁKOÂFPÊXJ´hciA+K¶bvÊlyÚˆ̀nƒ²j†®jŒ®cÀ~}ŸS`j&Vn-`e QZF\RaRf–^–n,d`\„V}IyRFRDTJ]I‚R‰`$ZwCtJTSn2nˆY]“‘[–™sŸDˆVrŸZCR<\AW?ZBX;\<_@^>[9_C`>V5T 4J
-5H <p)IÂwv¹JSµXcÚ®¢×‚Úœ‹Û¨—೥ྰƯÁ¯Ơ²¨IN¯<LÅJXĐZdÔblƠdtÚnrÙhpØnsÛpzÛptÛnvÚqzÙqvÚquÓcmÄTb̀ZfµF^È`nËjvÀcyºYl¸\xÉ|‡̉xÜ‚„̃ƒƒÚvx̉fs̀VdĐT`Ñ\jÔ`mÖX^ÖYfØXeÚjrăvyêï°ª÷ÓÈôØÊ涰̃‘‘̃~×tvØlnÑjm½Uh³Rj´Tl²Qa˜8X‰*H†&E—6N™3G4F”)?x7v:e:]7eBdD7Tp)O`P¤VrÖ””Đœœ«d{~/TH`x+Ig>`@^>_?Z9h@hA]?dB„8S©]m¾tx¾rr¾mqÁvwË„|ÑÔŒ{ω~ΆyÏ…{ІyÏ„t΄{ʆ{΃xÆ„€ÈxÍsÍ‚wË„yË‚ỳ‚vÍ…zÈ€zË€x˃v̀…|Ë‚{Ê‚zÊ€yÈ~xÂ{vÅ|tÄzvÀxr¼xzºts¹rs·sx´tt²q{¸rwºz}Ɉ~Ï’€Ö~Ü¥„à«â¬‡æ³†æ²†ç³ˆæ±†æ±Œç±ˆ³DR¯HR®GP®CN¤CQ©BP¢;L9L1E5G•0D)B%>˜+@¼JNÓaX̃rdä€lépë•{́œ|đŸxï xñ¤|ñ¤ñ¤ó¤€ñ|ëxå|hßjZÎWP²CJœ.Dœ.E¡2D¥9F°>K´CM¸FL¼KQÀPS¿JPÀFP¾JWÊypªap´pÊr†¾d‰»tÂŒª^k‡8Xp,Sy4^…Gmv2^_JW>PAWLONh5g—{©•l­‰X˜s§‡K~KŒd"W^ TO FxCsg'bn2e†Xj,lh6l‚Nˆ„Pˆ–l¥™n©”k¢•|£d*NP>\H^JV<]AaBZ:`B`@]>_D^>X8N
-6D4S>¬foÉqk®FTË‚†Ö™„Ú•Ú£•Ú¨Ư»°àĂ²×¶§NM¢0B¿ANÊPYÔ\dÔbmÙguÜrzÜoxÚs|ßtzßx~ÛquÜlpÜppƯwwÚkrÖjqÚhkÑ_jÓcnÔjrÓkx̀jxÔx„Ø~†Ü‹Ú|‡ÚvØz‚Ôw}ÎYhÓVfÖ`j×bkÖ\dÖZcØVcÚ_năx€êí²¬ôÏÅöÙËé¾´̃œ›ÚˆˆØ}€ÖoxÓdpĐ^jÏcpÈ\iÊ^i¾Qa¤>K¢4K¥>L©@J¢=I˜/?|8y8_ 6`8c<fBy-Ln(P_LVrƠŒÖ¤£³m€€2V‡?\r$F^<d@\9[:\8q(Dd<Y<a>‹>[²jtÁrs½mn¸hpÇyu΋|Ñ̉‰zω|Í„yφz̓zÏ„zË€x̓ẁxȅʃyË„|̀„x̀€s̀‚x̀‚vÈ‚|É„vÊ‚{É‚|É‚vȃzÉ€uÇxÇxÀzvÂ~x¾yy»vu¼xy¸vw·ss¶tw¹ptµpy¾~}Î~րܦ‚஄氄洂贅鵇泆贇賅氄粂®CQ©GTªDP¨CT¤@O¢>O9I5I2E–6F‘.C‹%A„:™.C¼FJÓ^WÜqfâ€rçẃ–zí~îyï¢xñ¢|ô¢‚ñ¥€ózñœ}́nä~jƯm^ÏZS´AJ,D™,B 4H¦<H®=H²CJºFL¾HM¿HLÀGLÀFN¼DTÔ`U΀‡×w€̃‘ÚÉpyªRm‚4^l3_j+X}8d„@dj'TRDRB^#YZJYN^Wn6h›}®v°”hhS€d!Q\NMFh+[u6nf&aO…ŒS”{E}p4ir3k‹X’‹W…›{¬„R}|>tm-]h#RX<\<[<]>\:\;cB\?\;X<P6P <I :}8OÍ~r¾RW¿\bÛª›Ø”†Ü‹Û¬ Ü¶ªáıÛÀ¨¦TN/G¸:JÅJVÏS[̉[gØfoÛoỹu|àz}ßz}̃wxáz}à{~ß|~̃yz̃ttÚnrÜrxÜouÜlpÚoxÛq{Üz~Ư}†à‚‹àˆà‰̃…Ư†̃‰Öov̉_iÖ_l×dnÙdmØ\gØWeØXdÛZhâr|èî°²óɼô×̀ëĺત̃›œß‰̃€„ÙszÙlsÙhn̉^gÏ[cÇV^ºHT¹FT¯HTµIO­BL 2@~8{ =_9b<f>hFs*Fn$N`PRkÔƠ¡¤¶p„2T}2Rp$DeBg@`F[@_;o(A`;V;c@–I_ºpuÁqrºnp¼lmÉ~{щ~шxĐz·~Ë‚zχ~Їy˃|Ë€x̀€z˃ỳ†z̀‚w΀vËzÊyÇxÊ‚vÉ‚yÉx̀‚xɃ|È„|È~zÇ{xÉ~uÇ{tÂyvÀxv¾zt½z|¾ttºrs¶rt²mx¸tz‚‚Ó—„Û¦„ᮈ䲅趈귃뵆궆洆泉貇賅籄鲇°DRªBP¦@N§<J =M8Iœ6F–4F2E’0CŒ)A„;w8%<µEK̉`ZÜqdă~nçtê’v́xí yđ¢yđ¢~ñ¤ñ¤‚̣¤„ñyêŒpä~f̃mZĐZP²>Gœ.D/B¢6G¦8Fª<H´BL·DL¾HMÂJNÁGLÂGM¾ISÁNZƠkg׋ˆÏyƒºXo¯Xo–Iik'Tf"R}:iJxp/\^NNETKq8pdTn-fq2n‚I„„NvGxuCr‚Pk/^XDTBPDb Vp1fh&d^"YˆZ’a£ƒP‹U“‚I…yDv…W„j0[M~`F`BZ@X>X;Y9[;Z<aB[BZCWDP>J @Z@¶opÉe^°FS̀~†̃¡̃¥”Ü«ßµªâĂ³̃Å®­hX“&>°:GÀHRÈLVĐTYÔbl×blÚlsàv|àz|à|€̃}ƒâ„ˆä…ˆå„‚ă„ˆâ…ßy„̃|€̃ß|€̃ƒˆá‡ˆàâă‘”áŒâ–á†àƯ„‡×ktƠ]kØckÛjrÜchÚXb×ZhÙYbÛYjáqxåŒè¨ªñÉÂôØ̀ëĺ⮧⤡ßß„†Ü‚Ûx|ÚqwƠ`lÓ^fÏ^hÎVZÅPZ¼R^¾PY´JS¤8G„<|=c9h:f>p"Dv,Jn&N\M–NiӒק¨´w„„7]~6Sr(Jb>f=Z<Y7c;f:Z9ZAl C¢We½tvÀqs¼nt¼qrÊ€zÏ~Ñ{φ~Έ{Љ{Í‚z̀„x̀‚zÍ‚xÊ‚yË„{ʃ{̓v̀‚zʃx̀„yÊyÉ€wÊ‚xÈ‚{ÉzÆyÄ‚}ÆxÆ|xÄ|tÄ{xÀxtÂyv¾wx¸yz·rv´nr³mpµqtƈ„Öœ‚á«æ¶ˆé¸ˆê¹Œë¹‚븄鶄궂鵂貅貄è³è´†è³ƒªDT©=K¦9J£8J<N›6L™2F–-G–1F”/C&<†;€:$>®AKÑ_ZƯqdâ}hçŒvè•|뜀îŸ|đ¢ƒđ¢|̣£€̣£~đ¤đ›wêsä}fàkZÎYP¯@I4Eœ*A¤2D¨9G²=G´@K¹HN½LT¼LP¼KP¿KT¾JX¾Vf¾]w¸^z¨Op®Ri¡Efy-bz?{ˆKQr1_\H_NUJ^MzBzq+f„J‰[–a~@u\Wq5i‡R…f#TI ?ND^Tb[w@q|Aw\ \W V•r¥†²Œan,dt@zyAx—Œºn9_QBX@_B\>]AZ?Y:Z@\D^HZHUGNFPEŒEVÎzk²ETµXfÖœ•̃ ̃¬Ÿß²¢â¾¬àÊ°´o‚!>§.Bº?LÆMSÍQ\ÓV^Ö^dÖfsÛiràuxâw{á~‚ä…懇åŒæ‡†å‹‰ç”䔑⌋äˆâŒăŒŒä–“â—“ă”ă‘⌌ä’âáˆ̃||ØjrÙflÜopÛkpÙchÙ\dØ[aÚZfÚYgßovå騪̣Ç»óÖ̀íÊÀ䱧á¥ß˜—̃‰Ü€Ü|€ÚxyÖjsÖdlÔ^h̉Y`ÊRbĂRa½L[´HU¦<M†:x>g:h>h>s#Dx&DkEXF’FdÑ—̃¤ Á‚„3Yv/Jp"Fb<g>X<Y9f:b:X8[:|+M­`h½qr½nl¹nsÄww͈~΋φ|Đˆ{̉ˆzÎ…{Í„z̀ƒx΂v̀‚zÈ{Ë‚{Æ€ỳ†xÈ„}˃yÉ‚xÇ~uÈx̀‚yÈ€xÈ~xÄ~vÀ|Ă}yÇ}|Ä{wÀyvÁ{u¾zv»xt¶ss´pr°ovµrtƌؠ‚⫇èµê¼Œ́»ˆîº†ë¹‡ë¶ƒé´ƒêµê³‚沅贆贂粅괇¦<N¤;K¢:M 8Jœ5L4H–5I”.F”.F‘.E"<„;:+C°?G̉^XÜl`ă|kç‹tê’x́|ï~đyđ |ó¥x̣¢~đ¢‚đ˜vêŒpçeƯm\ÎZT±CK0D—-A 1A¦:H®<F²@L·DL¼HMºKT¾JR¼NZÀN_ÀVm¬P|¤L}¼n˜¾w  d¤w´¨ˆ¸¡v¢„Jye$Ud S_QcXn*_TŒv2jeœŒXŒŒSˆz7wt5r“g™{@pN>J@QFZKe&_ƒJ„•dz@{l2nl4jwDvd Hb¡¹fƒf$Rh&Mh!G`D^B^@]AX=X;ZDWFXHRDNGeD¾xsĂ_Z²JZË‹‘ܟਕߴ¢à¸ªßÁªÄ‡w=&B¬5E¿FRÈLSÑV]̉W`ÔZbØhsÜgqßprâx~ä}}åæ…„æ‘懆æ‰è”Œè˜‘ä”äæŒåæ”ç”ă‘æ“䔓â“âàƒ̃yvÚltÛhoÜntÙfnÚ`bÙYdÖ\fÚY`ÙU^̃fr倅訨đÁ»óÖËđÍÄ汪à¤à™ß܃†ƯzzƯtxÚknØdhØbh̉]f̉W_ÈVcÆS[ºNU¨<L‰#=t<b=h<p Br>z-HoCW FŒ?`̉”Ü¥œÇˆˆ<]r&Fm A[6jB[A\:d=_<[<c@’?X·fk¾vt¾npºntÈ|xĐ„ĐvĐzφ|ψx΄x΃~Ë€v̀€y˃{Ê„{É‚~ȃzʃzÊ‚zÊx̀€xÇ€wȃyË~sÈ€{Æ~vÆ~xĂ|w¾|wÂxxÄyuÀyv¼uq¼us¶tr¶st±puµtvÆ‹|Ù‚ă®‡éµ‰́¼‰́¾î¼Œí»‡ë¸†ê¶궂ê´è±„簀鲅鴂絆赌¢:I¢=L¡DQ:L™7J˜6L–5J’3F.C,C…#<:{>(?­>JĐYVÙncâ€oèó•|ëœzîwïđ ̣£zñ¡x̣ ~ñ™úŒoæ€iÜlZÊTP¯@H0C™,B¡3E¢;J¬;G³>F²>KºCT¿HX¼Qq¾\Œ¹n »x«°}´º‰ºĂ‰­»’¯y˜Œ^~ƒVvz?ki)Yd!Rf%Tl-`e Ux;n„M„u6n‹_‘‹W€A{ŒX”’b„Fu[HL?R@O:ZJUN_T{Dt‡NŒ‰X’Œ\˜€MŒ~>x˜|¥œ°ˆ\‡n.X\}™Hc‹9Pƒ3TR<WB_BY;WAX@VDRCLBNF”RbĐ}p­EW¸XcØ¥£ÜŸ’ß´¢Ü´¨âÄ®̉µ›t/B{:˜(B°:IÁKXÉO[ĐS\ÔYaÖ[b×alÜipßouăy~äxwåƒç„†çˆè‘Œç„è–ꙓ甋蜖Ꙕ旒甑å呑處晓æ—âŒà€€àxyƯruÛkq̃nuÚksÚcj×ZeÚ`iÚU]ÚV`ßbkä}‚袠ïÀ¼ôỜđĐÅ鸭ࡘà‘á˜̃‡†ÛxỹptØjqÚfiÖen×_lÔXdÏXb̀U\ÂQR«DOˆ#BvAb?f@nBt!B~-Hh?U
-Bˆ:W̉Ü—È‹’Fan!?e9V 2o#CV8_<h<_;\=f? Pa¼qwÂrsºnnÂnǹ†|̉Œ|Đ‹}Đˆz͇{ˈ~̀ƒ|ΆyÍ„z̀…€Î„Ê‚xÇ‚}̀‡zɃ}̀‚zʆzǃ{Æ‚xÄxĂ€|€|Ä|wÄ~|Ä}zÀ|yÀywÂwr¼vw½wsºrt¸rw´rv´rxƈÖœă­è¶‡í¼‹đ¾Œî½†đ¼‹î¹ˆë¸…́·…ê´ê³‚鲄糅궈괅趉鸌7Lœ:MBU™7I•4H˜0H”0E”/F,D'?†$>}<w8Œ'>²HRĐ\XÚpbßjçoê”|ê›xîyđŸ|đ ẓ¢|̣¢€̣ |đ{ê‰næ~iÜkZ̀YU°@L,Cœ*@ 1B 7Gª7H³?N°Dc¸Nt¿h’È„œÊzźpÁpÈu´p‚|:V^!Sb'Zv=ph)X` Rh&Yi&Zh$Wm&Z~G€€B|x;sˆ^—z@zfŸ™n„Ith*VWGYHT?P?XASEUKd*Yr3ot8l’_“˜k•k•l6\NARJx2V´u€±huœPc„4UWFYE[>X?VBWDSBSFNF_ J¾}z½ba°P`Ç|†Ü¨“ட߷¨áÁ¬ÜǬ„GL]8<.B¶<HÉMUÍOT̉T^ƠX^Ø[bÙdnÛilàptâwtâvxä~€ç„„挄è“é”è•‘ê•ç—è‘霕ç”è–曒痑阒ç“æ•Œäâ…ƒàxyƯsvƯv|̃puÜlrÜdoÜ^eÛ^fÜY^Û[dÜbnăw|ç˜ï¼ôÔÉđÎÆë»°á¡à’Œá‹‰à‰†ß‚‚áutÜirÚbhÙ_n×ZiƠ\ỉ\h̀TZÄRY­?O‚DuBa>l Bt$Ds"C€0Hd>YG|-RĐÛœ̀ˆ¢\sm"AcCY8k>\;b<d<\8^;x)G¬[d¿vuÂqp¾mnÄvtц{Đ~Đ‹~ψ}ΈyÊ„|̀†y͈zÊ‚zÊ~È‚zÈ‚~Ê„zÇ€{È€{ɈȃyÊuÄ|xÆ~xÄ~xÁ}wÀ~xÆ~{À|xÄzuÁzxºvw»tt¹sv·pp´qvµptĂ‚{Ö~à¬‚èµˆê¹ˆî¼‹î¼„í»‰íº†í¹„́¹†́·ƒé¶ƒê´‡è³èµ„ë·ê·é¸è»“™6K˜5N˜:P–6L“0G”,D•6N-F*C‰&?„'D{=x<‹'C­CMÍ\ZÙthß~lçŕ•xë}îœ{ïŸyđœzđ zđ¦€đ¢~đ–zêŒqä€iÜn`ËXQª>Hœ/C˜,A0B¤6G«9L¶ET·atÂhtÇ\bÄQ^ÁXkµdˆ¬a°eLx†6hk$\m)a|:nv7hg#Ug'Yb Rf']j)b|?xu<ru7p‹Z—ŒX”–u«–l–’f‘aQXG]J\DZCWBYCVBUFYNl/Xx?v_Jh-H„CWT<D >[D‹<\¶ot·nu P_v*N\DTAY>Y@V@V@SBNDRIM`̀zpµT]¸\dÓŸ̃¢â´¢àº¤ầ²¥zhO9g9‚<¢:J»DLÆQVĐUX̉V\ÔY`×^`Û_gÜfnàpxâorâyvä~~胂挈é蔌ê–꜔ꜘé’éé›”è˜çç›êœ’è–Œç†æ‡„ă€|â~|ßux̃qs̃ns̃lrÜglÚ^aØ^dÙ[dØXbÛ`iăwæ™™ïÀ¶ổÊïÔÊëÀ´ä¢™̃“̃Œ‡ß‡„á‚‚ßwyÛkrÚepÚ`kÙZhÖZj̉ZdÍX[ÄRW¬@M|?v@^Ao?nCu'Fƒ3Nd?VDy*NΆŒÔ”™̀„„´sl=`8Z 4`6^7e:b<Y7[=…5Q¶djÄsrÂsqÀnpÈzvĐ̉Љ~Љ}ψ}͇}̀‡~ψz̀„zȃ|Ë„ˆ~ÉzÈ‚|Ë‚zÊ‚xÈzÉvÆ€|ÄxĂ}xĂ}wÂwÀ|{ÀzyÀ}z¾||¾xt·tv¶tx®nt²qu½xvÔ”âª€ç³…ë¸†í¹ƒíº‡îº„́»…î¼…́¹́»ˆ́¸ê¸êµ€ç¶‡è·ëºê½–êÀ–êÁœ–4J”3I’0H’0H0F)C”.E‘/G‹*F†(D‚"=x;t?‡ @¯@HÎ^XÜndâ~mæpê–yîœ|î›zî}đŸ{đ¥~î }đ|ï˜}êŒræzdßl_ËTS°DI/D–*@6G¥5H«=J±GV´MY¹HU¼MV¾N\ĂVeÂd|©Po•Fh>mˆH|‚>uƒAt~?rr1]s)ZiN_Vp-g‚H…WŒ_ \r6n—k¦™v¢‘bk)Xi1]n1f\I_HZ@Y@XDXCXB[HXIWEr.Rv:ncCˆ6IX<H <T<–E\´ep¼qwRf”Lf^AUAT=T>R;XCN=J @j&JÀ}|¾ef¹TdÉ€ˆâ²¥á°Ÿß°œà¿§Â¡ŒX<Z<p<„!@¦8IÀGRÉRXĐR[̉W^ÔV]ƠWZÚ_eƯik̃ksătsâyzăzyä~}凂针é–阉́œ“ꛓê™ê¡èœ’è’ç•Œè‹ê•ç”ˆç‡åˆâ„}àywàtvàtvßtt̃pqÜjnÚbgÙ`dÚVaØ^bÜ`găwzçí¾¶ôÖÎñØÎëøâ ̃’‹̃ˆˆß††ß„€ßxyÜqvÚkqÜ`lÚ^m×ZfÖ\aÑY[ÆMR¦8Iu?tA[=p?hBv$@9Nc@Y At IȈ֔˜Àox¼…Œp?\:W 7^:n"Be<`8]<d:–EV¾mmÈynÅtpÀpqÍ„{Ñ~Ó~Íxψx̀„ẁ‡zˈ̀ˆzÊ„zË€xÊ‚~É‚zÉ€zÉ€zÊyËzÇ~yÅ|€|Ç€xÈ|xÄ}xÅ|yĂ€~¾||Àzv¼z|ºuv¶rq³puµlr¹rt̀€̃¤€è±ƒë¸†î¸ƒí¸~́¹„í¸„́¹‚íº„́ºƒ́·„빆깆è·êºê»́¿–ëÀ–́œꠔ2J0I1J‘.H.F,D*D‰*Bˆ+D†)B~#@x Aw@ˆ#@²?HÍ\XÙmdă{kæpè’vê}îœý ~î |ïŸ~đŸ|̣€ï—}épæxfßl^ËZU¯@J0F”.D4F¢8K¨@P¬@N°LW·KV¹LU¿N]ÆS]Ä_n=`<jx4my6o…I‚ˆMˆy0`“Lz}1bdVr-h‡N„†^c*\\^zC~±†Q†‚Vd*cl8go2\`JV?Z@[A^J^FZE]FZFX@d&HZD_@ˆ8Mb:F9T?“CY±bq¸eu´€‚R^\BQ7P<R;O 6U>K ;K 8˜M]Étj·P]º\fÚ°®â°˜â¶§Ư´ ÖÀ§r9FM>Z@l>'B©<J¿KRÊNVÏRYÔXbØ[`×\cÙ`iÜ_c̃fkáqpârrârrä{yå…ƒé†è…ê”́˜éœ–́œ”ê¡’é¡•è–ç“ç–Œè“蔅戀äƒ|â}zàxvßqràoqßtsÜlmÛfjÚ`cÖY]ØY`Ù_gÛblàpwå’’í¸®óĐËñÖẾȽ࢘̃àŒ‹ß‰‡ß~̃yxÛrtÜkrƯ`pÚ`qÖ[dÔ]bÏZ\ÀJP2Fx@n@]<oAdBz#D‹9N`:X <sFÆ€Ö“—ÂqzÊŒ†z&HZ8^=\:r&Dc:`<^6o>£PZÀnjÅspÂqnÇxvĐˆ{̉€ÓŒ{Έzχu˃y·{̀…|̀…yˆ~Í‚zÊ€xÈv̀xÈ‚xÆzÄ~|Æ~zÈwÁ}yÇ€vÆ~uÂ}zÄzvÅ~w¾{{¼x{¼xx¼ut·rq±mp²hnÅ€yØœ{æ¯́¸„î¼…đºƒí·„í·‚î¶„́¹€íº‚́¹„́¹†í¹‰êºë»‹́¿”ëÀ’íÅœ́ÄéÅ ëÄ¢’2J2JŒ,F‹*C(B‹*Eˆ'D†(C„'E„$@}>w?u:ˆ%C¯:DÏ\WÙojà~låˆxë”{ê–v́›{êŸ{ë›xïœ|îœ|ïxđ•zê‰oç~hàk\Í\X²AJ,A”.D›2DŸ8L¤9J¬ET²FRºFP¾GNÂMSÄMV¿P`*Z‚=|™dœ˜n¤‘av/cŒ<l¡Rz4iz4jX„P}^(UVP][j.g‰j™a¢€Lzx?xc'Pe'U]HUDZ@dJ\E]FZ@ZFZEZEZ F^IX@y,Bj=J
-;t FœDY¬^pJlȉÀwv‚7TL6N<L ;L
-5N :K9fBÀxj»^^·TbÆw}ß´¥à³¤â¼¬ÜȲpmODSCdCo?ˆ#?ª:H¾GP̀TWÍRXÑSZØ\dÚ`fÚ^dÜafßioănrânpâtuäzxå{vè€x艂ꌃ́“ê꜒ê“é¡é˜é•è—ç’ˆæ‚åˆ|æ„uá{wßmpƯmpÜhl̃ppÛhkÛfeØ]cÔUTÔ\aÙ\cÚdm̃t{䉌́­¨óÎÆñ×ÍîËÀá£̃‘†àˆ̃„‚̃‚Ưz~ÚrwÛmqÚdmØ^jØZgÓZb̀V]½LT‘+EzBa=a=i;d>{"B‰8Nb8Z
-=jEÄ‚†ÙœÄv}̀…?ZT:X
-6Z:t*Dd>]>b@€*F²adÅtkÆtnÂppʈ„Ơ™ŒÓ“‚ÓŒyωzΈ|χy·zˉ|̀ƒxÊ„}Ëx̀‚xÇ‚yÇ€wÅ~zÉ}|Å|zĂ{Ä€}Á|vÄ}wÂ~vÀyuÁ|xÀyw¼zw¼xuºtw¶op¶np´ko»tuÔ‘{⪂괂ﺂ́¹î·‚́º€́¹ƒ́ºƒ́¹‡í¼‰ëÀ́Á‘íÄ™́ÅœîÆœ́Æ›êÆêÅ¢-G‹,H‡.L‡,G†/Hˆ.H‡.I†(G~%D€&Cx>t:q:">¯:FÍ[[Ùroà|lå†té‘xê”|́›x́yë˜xí›|îœzíœxí•ué‹wç|dàlZÎZS¬?M˜*B’,I›3J¢>T©Hi¨?N°CN´FO¹JQÁJSÁK`°M{’J¥‡¶ŸyX|w1f;oU…ˆGzs-_]“‚Nzc%Y^&\e&^d&bXWqBt’v¨|Cv†U\Pf'RgO]J`Dj$MYBXAY@V=ZBWC\#F€PvX;^5o =R>\=—CZ¢Zv>a®PQÖ—ºxyx2QO>H 8J9N 7Y=DPËre¶JR¾ZaÖ¤¤à±£å¾®äʶƫ”XBJ :UBlCr:‰#D¤8I»FRËNUĐUXÔX^×Y^Ú]cÜ_ãgkághânpâtvåtwåzxäzv䀀戂猄êê—é–ê™ëŒê—’èˆê’†êƒçŒ„æ‡{ä|âxtàsqƯknÚgnƯhjÜijÙbdÙZYÔVa×VYØ\cÚ`làruă‚ˆêœñÈẠ́ØÎđÍÀᥠ̃ƒàˆƒ̃†ƒÛ||̃uxÜzÚmtØfpØ_lƠ^ỉZ]ÈV\·DN&Bp>X=e@i<iCx)Bˆ8L]8V
-?a>»x€Ø˜Æw‚Ë„‚ Vl^ER 9V:n$@eD[@h>“8N¼ihÂsjĂqnÀopÍ„~Ơ†Ô•‚̉ˆx̉ˆ{Їz͇y͆}̀„ỳ†xÍ‚xˆ}Ê€tÉyÉ€|Ä~{Å~zÆxÄ{Ä}zĂ|wÁ{tÁyvÂ|xÅ{xÂ|x½{y¼xx¸sp¶pt´mp´op̀‡x̃¢é°†í¸ƒï»ƒïº‚ï¶î¸îµ}íµ́¸…í¸ƒ́ºˆ́¼́À‘ëÄ—́Æ›́ḈÆîÆíǺÄêĂŸ-Hˆ/J†-L†,J‡*H‡.L†1O„'G~(H|'Hv Bo>l=„ =­>KÍYVÚpjá~mç†oé”tê|́yê˜{é—ź›|́œxđxïnê…næxdàm]ĐYP«?L–,B'C–.L¦Jb¶i¬@S®>N·GT¸F\ºTyÀq µ‡¨¦w’ƒLfn*XdUƒ>s¨qT†s2dg˜€JqZOZQzH…l,fq0p_ a‚Yz°‰P‡”qh(Z`!Nd"Pb"RcGl(QXBWDT<T>YET >^"Hr5LhCkAn<`@vKHc­r‚¸`d)G°QỦŒv¼|}`?J;P:R =^;¶ji½a_´LXĂntâ¿µă¾³æIJàʳCJI 9M <^>{%Ds='B¤5F¹AOÆJS̀PVÔX^Ø[`Ù[`Ư_`Übdàjnágoârtäxzåxxä~~æ}{悀狄́…ê˜ë”ë–ꕌ閌é‰é’‰éŒ†èå†zä|táxtßkiÚbhÙcgØbeØhjØ`dƠX^ƠX[ƠT[ØY^Ûckàjsá€éœñļóÖÊñ̉Äăª§Ư‡‚à†‚Ư„‚Ü~ƯsxÜszÛhrÛfmÖ`hƠ^hÑ\dÈTZ®@N‚ AdBX@h@jDnA|*D:NY6T:a <´lvÖ’‘Èt}Ă~«^nj"FP :\<k>`BXBj< P`ÂohÆtlĂrnÅxpĐ~ÔzÓ{̉wЉxÏuÏ…{̀…zʈz̀„xÊ‚}É{Ê€vÊ€wÈ€wÄ€|Ä}tÆ}vĂ|xÅ~zĂ{vÁ{uÀ|ÀzvÀxwÀ|w¼wyºuu¹tu´no°opÀ{sÖ–u䬂́·‚ﺀï¹}ï¸î¶}í¸î¶î·í¸‚́ºƒë½íÀ”îÄ–íÇ›îÊ¥íÊ£íÈ îǼĂêÄë 5Jˆ-Jˆ.Jˆ.Lˆ0L„0L,J€+J|'G{$Ev@l;l8„&D°CK̀ZXØnhß|läˆrèyê–́˜yê˜xé–źŸî|đwïqêˆnåyf̃k]ÎVV®@M–(B‘*G“'H«Pb°h‹ =X¬:Z¶Qx¿u£Å§»y¹l€Œ:bTBaUw2m¢e•º Evˆ\yBj]SXVZ$]…^˜l<qi,th4n˜†»”qŸ‘\™„Z€€E|_JeOf.Vc Lj"NX@Q;O<O<SBX?r$C9Qˆ.Cˆ1Kf=€.Q4]œW~Í͆–7Rw"F½`\̀ƒj{(LF4J
-9H<~8NÆxo¶U^´VaÔæÀ¯æųâȱ¯ƒnO:N :N
-;c@‚*Fs;‹<¦2E·@LÂJRËNV̉T\×]`×[`Ú`dÛ`dàcfàlnânoässäxxă~~å|惂ç‚}éˆçꔋꋄ蒉ê”鑇蒉é‚舀æ‡|â€yàxrƯhfÙabØbhØbfÙ`cØ^`Ö\`ÔRVƠRXƠX\Ù\fÜcoà‚‰éœ đ·óÓẸ́ÖÉè·´̃‹ƒßŒ‰ß€}à{~ársÜpyÙjrØbjÖ`hÖ_h̉X\ÆSU¤5JxBZ=VAfDt$DmA€)A;R^ 8T >_Bª_lÑ“’Às~Æ„‡°gxn(HK
-7b>e@^=X>w*J­YaÄujÇrkÄpoÈ|uÑzÔzÔxƠ}̉ˆv̉yψz̀ˆwΆz̀†|΄{Ë„zÈ‚|Ç€}Æ‚|Æ~yÆxÄ~xÀ~|Ä}xĂzu¿zwÂ}wÀxu¿vu¾zw»uw»vx´su¶knºpr΋uà§{è¶íº‚đ»€îºđ·|ï¶zî·~î·|́·z뼃î¾íÂîÆ–îÇœïË î̀¡îË¢́É ́Ƙë–éÂêÂ0JŒ1L‰/K†0N†5P…/N„1P‚(Hz"Fy#FsBl<h:€$B¬9F̀ZZØofàziæ‡tê’yë–|ê˜zê–yë–ý™vîœ|ïœsî‘pèˆoçyeÜn^ÍXS­9H•)?‘*C”&F©>QÀw«P³TwƆ¢År®Sx®d±f{&XbTz,e a¤l–BjŒS‚z>ie#Z`"`\ Zt@€{H„eq6u|T’‘qª‡Y•o¬u>l˜r¦d#Pd$Rd)P`Ff NV=P 8M8H 7V>jH=N«Zg:K‚&@b@7[’Hw¸qƒâ£˜ß¥‘®WdYD’7F¬jpkBC4@4S:²ii¾ib²Xd¾dhƯ¯¨åÁ°ăƮģZ4K
-6P 8N
-6i!A†0Hx:Œ!;¡1D¹DNÇFǸOỶX_ÖZbØ]`Û[cÜ]`àdjàdjàlqârxæwzå|~æ{vç~憃æ}熀æ‡æˆè„ê‚èˆè„èˆè†å‚wä{tßvvÜihÚdd×^dØ_dÙadÔ[cƠY]ÓTZ̉SZÔVZ×X`Üjmá~„蘒ﴮ̣ÑÆôÛÎ́źۂ{ß„Ư|Ưzz̃ttÚpvÚmtØbo×]jÖ^fĐZ\¾HR›/Iq@T@Y@`Av"Cs'Gƒ-G<L]6P :^@£Ndё‚ȅˆ´pwm%HH3`:]=[<Z:5P¸fhÇvoÈqlÂpnÍ„{ÔŒ{̉Œx̉xшwчvÎ…xÏ„vÏ…x·yΆxÊ‚xÈ„zʃ{È‚xÆ‚zÄzÄ€zÁ€}ÄzÄ~x¿}yÁ|vÂ|v¿yv½vs»vt¹ww¸qr±pq¶lpÇ|tÚ˜|æ°~́¸‚í¼ƒđ¹‚î¸|í¶î¶}í¶„í¸íº…́¿î—îƘîÈ™đÊ îË¢îË î̀¢́ÇŸíÆ¡êĂœêẮĂ 1J‹1J2J„-H„.L‚+K‚+H€(Fz&Dz @s=l;c7<ª<H̀]ZØlbà~læ‰ré“ê”|́—}ë˜|ë–wí˜vîœzî›xï”sênèzfƯl\ÍWO¬<G’+@’(B’'B1L¹R_Æx„ºk‹´Z€§Lt§Rz¶_}°Zw‰/ep \Aj¨hOp9k€Kzv<l|T`!Yn4sIˆv@vhj(eƒaœ‡^‰\’ˆº{<q‘rf#PYCZDb!Kc HX>S 8T>O:n FfP|*E©QY >PwB2`Fi¬^r³FUØ᪽nr^<s:…8JO5D2D6v*CÄugºTXºXcË„äÁ´æÆ°Ơ¾©p1BJ:R 9O
-9P =j<’9Rz:$> .B¶?KÈHLÊNVÔ\`ÖT\×Z_Ú\bÛbd̃dißdmàjmärväpqăzzävwå}ç…|æ€}æ|èƒ~æ†|挄è‰çŒ„刀èæå‚|âyvßpoÚhf×b`Ö^cÖ]dÖ]`Ơ[bÔV\ĐSỶRXÔTZÖXcÛflày~æŒ́ª¨ó̉Éö̃̉đÍÀÛ‰†̃‡„Ú~|Ü{z̃srÜrwÜhpØen×_kÔ\aËTW³FP-I^AV@`G_<v#Ev$Dƒ.E‡6K` 3R5]@™DZÑ‹̀‹’É~€¶v{s+KI 6b@T:[?c@˜EV¿nlÈtmÈpjÄtpÑ„yƠz̉Œx̉w̉{цtĐ{pφt·vΆt̀„yË…{Ê‚ẁ„yÉ…{ÉzÄ~xÆ€xÄ‚}ÀxÆ|xĂ~zÂ|vÂyv½wuºvu¾zx½tt¶st²nrºrr̉xá§~ê´}đºƒîºđ¸‚î·î¸~́¹†́¼ˆîĂ“ïÈ™ïÉ́ÊîÊœîËîÉ¢îË ́È¡́È¡íÆëÄŸíÆ¥’0J2L4Jˆ,Lƒ0N‚(H„+H,J|'Dt=m;i9c9~7«9EËXZÙlaâ}måˆxç‘zé”yí™}íxíœ}îyîœyñwï•sé‰lè~bßm[ĐTK­;H–*@“(@“+B˜1F¢?N®E\µPj®Y‡¥c“§c–¶g¹d„‡6fdR|9p’T…>qF€>x~F„c!Yt:xzB‚r3ph¢O‚p4t~Z—zC€f¢·x4prJrg*\N<RAV@`E]?X>U?TA`El4d€>b6R‘8S†*Q²w~¶a`µSX+GŒ9B­h_’JW^:W4dDN 5K9R 8 S[Æl^ºWb¿cl̃µ®èÆ®̃Ĥ][K 7P<S9S
-:R 9n(F–AT€;Œ(@§2C³<IÂGL̀PUĐSZÔZ`Ú]`Ü\aÜ_d̃ahàeiàjnälqăqvâutäwwäwuäzwæ~yå~{å|{åƒæˆçæ…å…€è†~ä€{â|uàrrÜmnØdd̉Z\ÑY]ÔVZ×^bØdjÖU^ÖT\ÓV[ÑNV×ZbÚclàx}æŒ́¢̣ĐÆöàÔñÏ¿̃’Ư‚~Ú̃y|̃xyÚqyÙgoÖfnÔ^gÓ]cĂUZ§>L~AT<SB_>cCw(Gx'D„+Aƒ/Dd:Q4Y ;“9T̀†‡ÍÈ||¼xx€8UV;\>R9Z<v&I¢S\ĂtoÉtlÆqmÊvl̉~̉z̉uĐ‹xЇz͈x΂sÎ…t˃t΄v̀‚x̀‡|Ljzʆ€Ç‚wÇ€xÇ‚vÄxÆ‚xÂzÆ|tÂ~y¾}xÂ}x¾{v¼usºzvºss¸mo´mrÅ~vÛŸ|氄ñ¼ïºđ¸|ï¶î¶~︃́¸„í¾ŒíĂîÆœđÊî̀îÊîÈ›îÉíÈœ́È¢́É¡íɤ́ɦíÆ£íÇ¡’2O2K‹0IŒ0J.J‡0J‡0I‚.K| Bw@r<g:` 5y8¨8DÊXSÙj\à{måˆxêzê•í˜zí›|í™î›zđŸỵ~đ•wëkç~bânZĐVP°@K”,D&B’,Eœ2G¤;T©Hj¶\|´Tt§Ot¸`}·f¦Xr'Yt*^‚@q}4j|:nW‚Ho0et:u|D}n.rn2iq¢c%[e'_~X˜p3s‹g£‘·€>~d0T‚P†N?SA[FU>^FdF\ET?Y =e"F7as&H…/TŸG\Æwt¾HO3Fy H‹Oi†C_aEP5W;]@F2Z<ŒBU»d_¶QV»ZaÍ‚„äÀ¨̉~¼†{Y9J5K 5V 8U8T 9s*EJ^:”%<£/B²;HÀENÊOS̀RZÔW]×[\Ú]`Û`bÜdfƯ^fàekâlqäqvăsråxyăxxâxväxză{zå€æ‚|僂艂æ„~戅èƒ}â€zàxt̃ssÛpn×`bĐRYÍNVØY`Ù`fÜdfÙ]`ØX_ÔW\ÓTZÖ^cÛdlàrwçê™̣ËÄöáỌ̈Ó¾̃—’ÜvrÜvũxx̃zzÛnpÖhnÖbj̉[cÎZ^»T\›:Nd>Q>UB`A]@v"C}*Eƒ.G~(>j<U4\ <…-NÁ|†Î•Æ|€Å€˜Qf\<T:L:U9…2M³_bËxm̀wkÆsmÊ{v̉|̉zÑ|ψzΆx̀†{Άx̀‚tË„t̀‚ỳ~tÊtÊ‚{É‚{Ê‚uÉyÆ‚yÂ~ÆxÅvÅxÈ}rÂ}xÁzvÂxw¿vs½us¸pq¸mq·suĐxâ©ë·‚ñ¼„ñº‚đ¹~đº€î¸|đĂđÆ—đË đÊïÊïÊ™îƘíƘ́Èœ́È¢́É¢́Ê¢́É¢íÉ¥́Ȩ“4I1J2K.L‰0H/Jˆ,E‚&B~=w;t:f6`
-2{7¨6BÊWTÙi]à}oèpê‘xë–yî~́˜~îzîyđ~ñ |̣•víŒtæ~fßl[ĐWR¯AJ*AŒ"?–-L¥@^²\„¾d†¶Tm³G^ªMmµRq¹Ri™<ht%]-b†Asv,fƒI}–fz7js6nt6ln-nc"a„]‘†XˆURh-nl¤q1s…_™ˆ¬U^ NŒf•WDQAZLb!Sl/X_CT9J 7^Bn&I~7a—O_™Slœ<TÆnYÈ„s¯dlBX‡=Po'FV:N 7X>K
-;Q>œh¼u|·fm¦P\ŸPfÀ|wʈ|À‹Œ°xn%JS 8O 6Z8W6W@u*BK]%<&=0C­:FÄKQÊORÑTZÔY]ÖYZÙX\Ú_b̃`eággáhnánqämnáoqåxsăxväuuåzvă{zæ}~å~xä‚~ç|æ„~æ„~惀â|{àvs̃mlØmlÑSYÈFRĐQYÚ_eÜgiÜelƯgmÜhnØ`g×X]ÖY_Ùbl̃lpèî¡ôÈ»ùáÓóÓ¿ß•ØtsÜuq̃vw̃tw×lr×djÔ^fÑ]cÈW^³N]…&CY@V@Z?aB\A{%B.H€+E€+Bf;T3[ ;r>»v~Í“•Ê…‡̀„}¤\mg=R;K 9X<•GZ¼ikÏ{qËzpÊtlÏ€t̉zщw͈zÎ…xÍ…{Í…t̀‚vÊvÈx̀†wÊ€sÉùƒwÊ‚wÈ‚{ȇ|Æ‚xÄ‚~Ç€vÇwÄzÁ~vÀ…~Ă|v¾wv½vr¼rq³ll¶npÄzwÙ˜z鲂̣¾‚đº€đ¸đ¸|đ¹€î¸‚(ïÀđÄ•đÈîÊîÊ îÈ™îÈ–îÅ”́Æ›́ḈÈ êÈ¥́̀§ëʨêÈ¥́Ȩ”6N’9O’2L1H‹0H‹.F‡,F†(@‚%@};v;f8` 4|9¦<HÍXVÚjaázmæ‹vê’|ë–~́˜|ë›}í€ï{î|̣zñ–t́ŒpædàmZĐVR²<J“,K”-V¦Fq»f‹Áe{´KZ°EZ¶IV®Pq¸Sr¹Pk‹8hz,`i'T†Ay‚;y”b“Z‰z2hx;nh,^o3pZ Ut¥t;nPQe*bp£x8€vH{ ®“b–\Q|Y€j'^[Ll+[g%PX<^<l$IN
-4U=iH…6Nªj_ KMf=q%K’@T¥Sin"DT:P 3K
-2R 4T 9D:‚LfΔ‹Ø‡Ï‰Ä†‚·w„¸~ˆ̀§̉œ…KP[
-4O5R9\7T 7U <u.H Na’0CŒ!< 2E¶>HĂJS̀PWÑX^ƠSZÖ]bÚY^Ü\b̃`càacàhlâlnâmpàmpăppäwvăwtäxuä€|ä~{ä€zä€yæzå…ă‚å‚~â~|̃võrwØpoĐV]ÉDMÔR[Üch̃jk̃ejßjj̃kj̃jmØZ\ÔQXØWXßlo熀î¤ó¿°÷Ô»̣ζۇÚtqÜwuÛuxƯnrØipØdiÓ\eÑY`ÆX]¤BPfDR<T>X<_?a?u$A{)G~+D~&Be:Z 6^=f?´mx̉”“Í…Ç}~¨bln$CS:H 8Z<ŸPbÄrkÓyhÏyhÇsỏ‡z̉ŒxÎŒ}Έ}ψzψ|Άẁ‚vË‚yÊ‚uÈ‚wÊvÊ‚sÇxÈ€xÅ~yÆuă€Å~zÇ€vÆ‚xÄ~vĂ|tÂ|uÀ|xÀzyºss»sq´kq¼otΈxߢ|́¶đ»„̣»~đ»‚đ¹zđ¸…﹂ï½ïĂ‘đÈ—đÉïÈîÉ›íÈîǼÆ™ëÈ́ÇíÊ¢ëÊ¥ëɧ́Ë¥êʦëƧ–=N’4K1H7L‹0F‹3H‡*B‡(A‚$?€ ;z ?k7e 6†"@©?JÍZVØj_àzlæré‘zê–zë–zꘀë–{ï™zî|̣Ÿyđ—x́yäm̃j[ÏZY´FX¢?a§Ol«Pj®HW¦?R©>P°AS¶DX°Tu¼Xt­Pv†6gq&Zf&[C|‹N†\ŒŒM}8ll-cXNh(f~T‘Œen.eXXUTˆb˜€C‡p3qœ¤¢°`ZvPsb‘SD`EZBY@g=‚4PN
-9L<WAl-TcFX8R<^FCf—Rh0LV8N8N5X:G8D3®„Đ”’،וڜघߨ“Ö ¦[al:P
-6P
-4T6_5Y=X
-:x.JœL\’.D’#:¨4C¸<DÆKRÊOVÓWVÖY^ØZ_ÚW_Ü[d̃^hàbfáklâflânrâkpärtävvăuwäuvâtwäz{ä~xă{}ä|æ~å‚|ä€zá~{ßvrƯrtÚmlÑT_ËFP×W`̃ccƯa^Ù^WÔVN×abÚ`]×\bÓP[ØOTÜagävś˜ï¸¨ô®́½¬Ö€vÚuuÜuuÜruÜprØmtÓir̉_aÊ[[»QX‚&FX?V@RAXE`Ff@v@‚/Hv"?&Ab5b;\:Z >¦_pĐ“”Î’“Ăxz¨dpt$FU<H 9gA¨W`ÊzpĐ|fÍunÈztÓ‹~Ñ|΋|͈}̀†vÍ„z̀†xË„xÊ€vʆù„zȃzÈ‚xdžyÆ„zÄ„~Æ€yÂvÈ„xÈwÆ€wĂ~wÁ~xÂ|w¾wx¼wv¾tp¸pr´mr¿tqÖ•€äª„î·|đ¼‡ñºđ¸~đ¶~đ¶đº‚đ¾ˆïĂïÄ”đƘïÆ™íÈœîÇ îÆœ́ÉŸ́ÈŸëÈŸ́ȤëȤë̀ªë˧ë˦êɨëȧ’2J’5L’/G‘0J/H,C-Eˆ*B„"?~!?{?t<n8&A°ENÏ\]Úoià{læuéxê’|ë˜{ê˜~́˜}î~đ~óœ~̣˜x́pç|d̃nbĐ\_´Jb<\*L“,H3K¤9J«=P°DU¶DV´Mj¸UxŸPwˆ5a„*`v,b‡D}„D|›l”˜V†}6hi(`J
-Ej6l ¶†Hj)]l/qVVW…N~>—v ² Âv3uh5]~§ZGXGZDu-Tj"@€4NN 4M;N<Z@g#Od![^M h‚¨w–c;P
-6Q8R<V9M 7E<\DȤ–Ö¡˜Ư¯Û¦›̃®¤Ú¬œË”UVb9S4Q1T
-4X5b=Z 8[ ;t+EœK]”5Nœ)>®8D´=HÅJLÊPQÓSTÖRT×WYÚZ\ÛZXƯ^aàfhàdhâfjâlpâlnæwsäqråvxäxuâ{xăyuäz|ä}zä€~ä€{ä‚zä€{â‚€àysàsrÛljÓblĐPYÜ^^ßbXÏWQˆ6t6%9½>BÄCEĐRRÖTW×VZ̃bdè‡î¬¡ï»­à˜‰Ú}zÛvxÜuvÜttÜnrÙhoƠ^h̉\`ÆZ^¦APe?T?WBT@ZGcFi>}%C…0Dt>(De8f8\ :X
-<œVpÓŒŒÎ’”Ânqµnvz0MS>VB|,J¸dg̀~ỏ|ǹyjÊvÓŒ|̉‹|Ήz͇|̀‡|̀ˆ{̀„yÈwÈ‚xÈ‚{̀€v̀€vÉ‚xÈ€zÈ‚xÆ}wÄ{zĂ~z‚|Ç~tÂ|tÂzrĂ{sÂ}t»yx¾yx¼rpµpt²kpÈ}tÜ™~é¯ñ·ñ¼̣»~đ¹~ﻀñ¹đ½…đÂđÆ•ïǘđÇ—îÅ™́ÆîÇœ́ÈíË ́Ê¡́ʤ́̀¤́̀§ê˧ëÍ©ë˦́É¥êÈ©“0J’0I‘/G-G.F‘.G’1G)B†#>€"?€$>y:{;—/DºNV̉baƯtlà~tæˆvévé–€ê˜|́˜zí~î™yï|̣}ï”{́qç~h̃n`Đ]d¶FT—.G%A•.E5E¢:J«>M´BM¸DS¶Md§Qy˜?h…1\•6gz0d„Bx†H{±p‰”Iwv1hVHLM\’•m”l&`j2f|@‚Z'\vH}„Q~B’j ª¶ŒOŒ`%S›„¬\KTDW?y5Nt$Du(Da?L
-7J 8L <T@n-^z1j¬wŒ®dldDV<YB^@R9E
-;F9ˆRi˄ז‹à¯˜ß®Ÿá·©Ú¶¨¨hnV2R
-4T4S 5V7]:c:_;Z
-9w*H¢Wd9P¤+=°=JºAHÅFLÎMNÎSVÖRUØVXÛZ]Ü[`Ü\`àbdàdhájnápsăopåpoâxvävtåtvâuyäwwä~{ä€|æ€|ä{å€yä€}ă‚€àytâvq̃spÛflÓQZÖWZÜ\ZÉQV¨7P™.K°BT¶CR°7J¯6DÈHKÑRWÛ\\ávt袘謟à̃‰ƒÜuwÜsvÚpuÙknÖin̉cj̉`bĂVZ…(H\BVCYCTC`C`@mA‚(B‚(Du'A‚)Af8f7d:T;@ZĐ†Ï”’µgnºz€€2NQ:o F“;PÂniĐ}oÔykËvgÎvÔ‰|Đ{ΈzË…yÉ„wÊ„|É‚yË‚vÈ‚zÆ€zÊ€xÈ€xÉ„|Ç}È€vÆ€zÈwĂ~vÂ}xÆ{sĂ{tÆ}vÄsÀ{wÁxt¾xw¸ru¸pr¸psÑ„wá¢}í³|ñº‚đ¼̣»}ñ»ïº„ñ¼†đ¿ïÆ”ñǘïÇœïÉ›îḈÈ¢îȤíʤ́Ë¢íͧí̀¦í̀¦́̀΅ͨíͪ́ˤëÈ£́É¥/F‘5K’.F“-F’,D“.D‘*BŒ'A†&A†(B„&A‚$>‡#@¡7IÀSZĐhhÜyoá€rç‹uè‘zê•ë˜|ê”ź™ïœ}đ€̣ñ˜{́uèkák[̉[Wµ@H.F’&B—2I9K¦<M¯BL³DPºJZ¸Mn°X~Ÿ>f=f3c{6g€>pw1g…Cnv1bj'`M Jq@{™w „P„i$`uF||G\ZxJ}‹`™yG|aœ›~¡Ÿv­l,dœ†¢j*YF
-8K 8^>aAYg®e`f>LAH<J>O@†T‘b€jFR :f Hf@j Ha Fl%F‚6Z©^d¿qtĐ„z؀ߙ„ߦŒ½yr)BP
-8W :Z<Y=]<_5c:[:\B|.J£Zh¡:Oœ*=´?JÂCH̀NQÎKPÔTY×UYÙTXÙZ\Û[`Ü]_àbhàbjâiiâmpâpráooătsâuráooäxxăw{äzxä{xåzwæ€|äƒ|ăyäƒ~á}váus̃vtƯpsÔ]gÓRZÙUZØYZÚ[\Ø[^Ø^dÛ\[ĐPWĂKWĂFQ̀R`ÖYhÜ|ˆæ©¢äŸ‘â„̃„}Û{|ÛtyØnrÙipÓfpÔ^fË`d®FUiBZBYDWEQBbEbBo B…,Dƒ.Hv&B‚,Be5i8h<S=|-Nʈ‰̉”‘¹px¾~~ˆ@WT?n#E§OZÊwmÑ|iÑ|iÊ{tÏ„z̉Œ|΋|Îy͇v͆wʃẁ‚wÍ‚x̀‚tÈ‚}È‚zÆ…}È„|ÈwĂ‚zÄ€xÈ€xÄzÄ~uĂvÀ|vÅ}rÁytÂytÀyt¼vt¸tt¶mq½tpÖwå¥{î·|ñ»đ»€ñºƒñº‚đº‚ñ¿ñẶÉ—̣ÇïÉœïÉœîÉ£́Ê îÉŸîÈí̀§ïΨî̀§î̀¦î̀¨í̀£îʤíÈ£ëȤ́È©”,E4G,D”0D+B(A+F*E…!;‚"?†)Cˆ)C/Gª<OĂW^̉lnƯwqâ‚tçvèxé’zé’{ê”{́–zî˜|ị̈¡‚̣œyëvè}g̃qeĐ^V¶EM.I&A–0F8J¤:Fª@P±BQºI^º[x¸Sjœ@d2YjNv/_„Bwt1bw4`d"RN Gh,d˜l™†N{l*_y=wu:rq4mj(ltFx‹`•t5w‡^œ^ª’¼„Hƒ–x‚K}G9K;hG^>¼ijÜ‹t˜HVX6? 9E @WN^„€@h\LH :€<\‡:\ PiOf¥Yp±q€§NR³[^½\`¶fnÏ­ªÈ°¥f$<P8P 9Z<d.Qj>^e&J`6b6[6^Hw-Jª`m£EY.@²:GÂHP̀JOÎPSÔRXƠVZØV[ÚYUÙ^ẽZ\ß_ẽbgßdjălnánoâmnátràptâqsávuättä}~âuxå{xå€}å€|å€~ä€|äyâyvàxvàtpƯlnØfjÙ`k×UỸX[àYZƯ^^̃``×QXÔQ^ÔfxƠ…—ܨ嫤æ¬æ™â‹…Ü€Ư{{Úuy×nvƠhp̉bkÑcfÄX\ˆ/L\@XCZEVEVE`CdDnFŒ9L„2N|(B€*Df8k9`7V
->qHŃˆ̉˜¼ls¿{~”G]^Dl$B·`fÑxỉ{pÓwhÊ{ỏz̉‹zÎzцtφzΆz̀„{ɃwɃwËvÈ€yË€vÆ‚zÆ‚{ÈzÉ€yÆyÅvÀ||ÁxÂ{¿|sÁys¾{wÀzt¾|x»tq¸po¹nnÂztÚ”{讀ï¸~̣ºï»}ñº€ñ»‚đ¾‡ñĂñÄ–ñÊ›̣ÉŸđÈđÈîÉ íÈŸîÈœîÊ îΣđͦíÍ©íË£íÍ£í̀ îÈ¡́É¥ëÈ¥́Ë­‘,FŒ3H.D’,B&>‘0C”.D*E‡#B‚&B†)B+B”5MªBRÅ\aÔopÜ|tà„yä‹vè’zèwê’xê’vë–zî~đzđ {đ{ëvçf̃p`̉[T¸BJ™1F“'A–1F5I¢:I«?M¯?P¸K]ºRfÄQcªRyjNRDj$X?sv4bn']`U\ Vf–„Ho` O`Uu:os2pn4m{G„|Qˆ†V|Bl¢B€œ~§”[”™y¤”i”RCN9fD^B­ZfØŒnÄ|f]:@
-:E 9uJql#Gr&Et*Sz3V”D[¢Ph¬Zr¼€Ë¡™¶mbªNR¦DU°ZeÅ‹‘äĐ²›[ZN>R?S:^:c@g$DbDf;b:Z9Z<{2K«ao BQ-C³:FÅHNËMQĐPV̉TW×TU×VZÙYXØZbÚXZƯ^dß`dàadâhjäklânoàmmàosâqrătvärqåz|ăzxæ|{âzză€zæ€yä‚å}xä}}á~|̃zxßtvànpƯlqÚajÛ`lÜag̃kmß{xÚtyØozăŒë²©è¸­èµ¥å«Ÿæ—‘⌇Ü{|ÜyxÙtx×pvÔhnÏejÍ_b²LXdBXDX>ZFVETCdGh Hp$F’?N.E4J€%@n9t$@^:\ >hA¼v}Ó™ºjt¸u}‘CYlE€.IÂllÎ{oĐykÓ|p̀€pÑŒxЉz·x͈z͈|Ë„z̀ẁƒwË„yÈ‚zÆ‚{Ê€vÄ€{Â|Æ‚xƃzÅyÈ~vÄ€vÅ€uÁ|vÁ~yĂ~wÀzx¾xt¿vr·sr´rqµpmÈ}r̃›zë²€̣º€ñ¸}đº„̣»~ñ¼†ñẠ́Å”đÇ›ñÊœđÈîÇœîÉ¢îÈŸ́È›ïÉŸîÊ¡ï̀¢îˤí̀¦́̀¤íÏ¥́Ê¥́Ê£́ʧêˬ́̀®‘.H4K.H.E4K”0F‘0H+A†)Bƒ&E‚$?Œ,F˜;R¬HZÆ^eƠrrß~vá„xæ‹zè{æ‘të“xë–{́˜zđ—~ï~̣œ~ñ|îtè‚jápeÔ`Z·DO–1H,F”1IŸ5G¢:K¨<K±AQ´CV»Mf̀h€Åqˆy$WUHe&U~=up&Zo,jh#bf›^‚f'VSL[Tt2lq1oh1j~K„‡a—„QˆZ‰ar3vf‘œn¤™y¢œzu8kUEgHfD‘D\¼hrªAJmFLC_,S`$LNGw0T›\v¡Um¥\{¯f€À†•Ơ¦ŸÄ€DV¢LZ°\r¼v‚ܼ¬¼•€ZEVG[HZH`AbFg$EhAfBd>\A^Dz1O¨`q¡GZŸ0F°>KÀHQÊLVÎTXÔT[ÖUX×XZÙSVÚYZÛ]b̃`b̃bhàfiàhlâlmâljàloàpsàlpâosäwuäyzä{zä}|å€僂æ€~ă€}ă€|ă}zá|áyvàvṽvtƯqtßklƯimßnpâ|zæœä™à}}ç‹ê´¤é¶ªè³¦ä®¡æà†Ü}|Úuz×ptƠkpÑbl̀blÄ^e9SZH[IXBXET@WIaFr&Jo E˜FSz&A…:O{$@o<x(B`<\ <\ >¬ivÔ™¸kr¸u~>S(K˜ATÄrm̉zl̉xẻwi΄q̉Œxшv͆ỳ†|̀‡z̀ˆzË‚ẁ„zÍ„ỳxÈ€uÈzÉwÄ€xÆ€zÅ|ÅxÅ|wÈ}uÆ|xÆ€v¾|yÀ|v¿|uÀzt»xyµpn¶pp¹pnΆvâ|í±~̣º~̣ºđ¹~ñº~đ¼ˆđẬÆ”đÊ›ñÊñÊœîÊ đÆ›ïÆíÉîÊđÊî̀ïͤí̀¤íÍ¥î̀¥́̀¦î̀¦́ͪíήîͲ3AŒ0Fˆ(@Œ*C.E‘.D‹*F)?†&@~;~=‹)?˜@T²JXÇ`iÓqs̃{tá„våxèxé‘vê”x́”vî˜|đœ}đŸ‚ó đuêvékßs`Ñ`Z¶FN˜0D*D/H™8N¤>O¨@P­DV¶J`Æe„ÑyµWpz,`]Pj&]~Bzo*d€B‚\’•lj.Z]RTOZSl,`q3hf+ep9pQ‰y?tXe˜{D}S~œw«‡Y‰œ{¢Yn-ap*Yƒ5aƒ:]›F]’;\n'Sl(Pj&LG>TL{;d¶t„¶n†½~Í”™̉¢˜̉«HPDR9W¼hlÓ¬¢Ë¯—l.EVDZF_!N`"JbHd$Jh%Iq'Hj"HfA`B\Gw0O¢Zl¢M`¤8L´@N¾ITÊPXÎW^ÔV\ÔW_×[^Ø\^Ú]`Û]`̃ahágkàglâikâhgâfißlnßkrânrâsväyxäyzăzzăz|ä{ză~z倀ä€{ă~~ázxàyvß{zƯxxßur̃utƯpp̃poâ|wèˆê²¤ç´¨âç˜ê´¦è·®è´¦ç±¦ä—à…Üv~ÛqwÚsw×jvÔgk̀fl¸U`fBYEWHVGYHXFYFk*Kt&Mt%D˜@Pw&Bƒ1F{"Cp >u#DgD\?ZD Vẻ˜Œ¼w~¾x~‹>UŒ8R­W^Êvl̉|jÏuh̀|nĐ‚t̉Œ|φzΉ~͇zˇzʃvÊ‚yÆ‚{Ê‚z̀‚vÄvÈ‚xÈ€zÈ‚zÆzÄ{wÄ~yÆ~xÆ€yÄ{ÄxÂ~vÀ~u¾wrÀvq½xs¶rsµnm»qp̉wä¤wïµ€̣»}ñ¹|đ¹‚ñ½‚ñÁŒïÆ’̣Ê›ñÊœñËđÈïȘđÆ—đǘîÈ›đÉœïÊ ïÊîË¢́̀¤îΨî̀§́Ϩí̀¨íαëÍ­î̀®*Bˆ.B&@+BŒ(B'@+CŒ*B„!={8=‰(B–8O°N^ÉdlÔrvƯ~tâ†{æyè‘|ê’yê”t́“}í•wđ~đ ~̣{đ˜ź‘rèjßq^Ï]W·DL˜3H*B”0F2F¤6J¬<P°<R¿ZtĐv‘·Zw P|{/_h&Yo)av2j„H›oœ†Ptl)Ta(UWFYRZNp0en0bm0ck.ft<un/f…V‹€R…}Iq6p“lœ„P„¢„¯˜cw4ju2c“KxŒ@m†<`„7Z]>Z@g HMCp*X³Ä‰’Æ„ŒÍ•–Đ¡¢Ơ°§º€w™=M?P@XµjnÔ»£v9@U9Y=[>]>b:d<c:h=w(Bn%Bb?`8\?mB¡Yj¢N`¨:N±@IĂIOÈKTÑTVƠSVÖYYØXYÚX[ÚWYÛ]`Ư_^̃efßegàkkàlnàhm̃fißikăgjállårrävvăvwäxxâxxàvsäzyăyzâ~yà{zƯut̃xwƯwuÜts̃tt̃upßywâ€|çî¿®́º¯æŸ˜ç—́¸®ë»®ê¸¨è³¡ă“ˆß‚€Ùx}×ouÚsvØgrÔflÊaf’7NYCZHXHWAXCUBXDq(Ho#I|,F“:N{$?…1G~"Bx >w;d6V 8X <‘AỲ’‰À‚‡»v|Œ;QNaµ]^ĐxgƠ{h̉r\Î~qщwÑwχx̀†yʇỳ„|˃yÈ‚{È‚xÇ‚zÈ€zÇ‚xÇvÄ€xĂ~yÂ|tÂ|yÂ|tÀ}Â~xÂ~uÂ|xĂ€v¾|tÀxs¾zv¾xq¹sp¶onÀtnÖwè¦{î¸~ñº€ñ»|đ»€ñ¿‰ñÄđẸ̀Ê™̣̀ŸñÉ™ñÈđɘïÇ›đÈ—îÉ›đËŸîÊœîÊœî̀¦́̀¨îάîͨ́ΨîͪîίîÍ®íÍ°,Dˆ,CŒ&@*B†)@ˆ(@+@ˆ$>†;€=>‹'B—=Q®N\Ébj̉ptƯ|vá†xæŒvëwé”xê’uë’x́˜|îyñ ̣ đ›ź’tæ„làr\Ñ`Y¸FJ˜1EŒ&?*?œ4G£5I¨<R¸PjÊy“·Xr²Ui¥Rtq Rp"Zr,d‚;vŸl“YƒVAZFkBf[Na"X\Np/id(Wv1lh(\w:vp.i|Bn‹a—g*at:|ˆb‘—fœŸ€ª™iƒ@vm$O©nˆŒ=Zh Gm@Z;O 6p E‡5VPk¼zÆ€ˆÉˆ‘̉ Ø¸«̉®˜¤IK§IRœ;P¥P\ɤœ’]TO>U;Z=j>]<a9f6c7i;}-Fo?_;f<Y
-8o ?œQeK^¥GY®<JÀFLÈKQÏPUÔRVØVZÙXZÚ_^Ù\\ÜWZàacádeàccâhmâeeăhlàhkàloáiißlnâljăqqâtrâtuâvvâsuäytáy{ä€zàzvÜur̃stÜxvÚ{zƯwỹzuá||刄飖îŶêÀ´æ§¢æ™́»¬́¿³ê¶¦ç­Ÿă•‹̃ƒ‚ÖrwØrx×pvÔioĐhn¸ZdiCWBYD\EZC]CU@_Fu)Gp%I…/F’7J&A‚/E|=}'@o7f8Y 6V >ˆ=Zʇ~½}ƒ¹mt>T¨Vf½c^ÔveÔ{gÔvaÏ~lЉxцwΆv̀ˆzʇ|È„~É‚xÊuÇxÉ€vÆzÄ~zÇ€wŃyÄ|ÄxÂztÂ|vÂvÁxtĂ~wÂ}x¿}zÁ~v¾zpÀxq½wl¹rq¶lnÂsmØ’vè­xđ¸ẓº̣º~̣¼„̣ÂŒñÈ–đ̣̀Ëœ̣Ê›ñÉ›đÇ—đÉđÉœđÊîÉđËîÈíÊ í˦́Í­íΪ́ͨí̀ªîΪí̀ª́̀±îΰ‰+B‡(Bˆ(@‡(Bˆ%?†!<‰%<…&@‚"@}"A€$?Œ.F’4J«JYĂ]hÏpqÛ|và‚xæ‹séxç“wê•v́–t́}́˜~ïœyñẓœzísè…kàtd̉\T»CH™.FŒ%>”.D4J£0MªB^ÀmŒ¶\v°JbÀap¢NznUr"Z…>y“Uˆ—l”x;kTGbRd,Wp5li+_c(Wm.f]L}Brn,[h.bo.kq/d‹^c#`n3q‰]œl›b”bœdFeÊt8aFV 7p#Dz+T<ZMb¡I`¬dxƒŒ̀˜Ó¬¤Ö¹©°b^DQ:O BW¼ˆŒ®lVAR<`>e?n?fC`:l;c8n @~,Cz(Ed<c:\<j>˜L_HZ¦Qe¢1E¹GTÆJPÎPVƠTZÙV[Ú[`ÜYYÚ\aÜZ^à^`ßehàagâfjällădhàfiàkkácdàjhâhjâikáppâssàstáqqârqàtqâ|xàrpƯxvƯrvƯvuÛxxÛ~}̃~yâ‚~äˆé¦œđǺ́´æ§æ”́¯¥íÀ¶ê¸¬ç®›ä”ŒÛz|×ntØqvÔkwÑktÊek›?XYDYBXCZDXAZAYEbFs&Lj$I4I4J€*E‚/Fr8y%Bq=e=Z9S ?ˆ@]Æ€zĈ´js’=VµcjÉj_ÓueÓwbÏznÎwΉx̀„xÎ|ʇ|̀‚yʇ|̀…x̀†uÉxÉ€vÉ„~Æ~xÆ€|ÄzÅ€zÄ}xÂ~yÆ}vÂ~yĂ}vÁ€wÂ~yÄ}vÂxnÂzp»tp³pr´ml´moĂwmÚ—xë®vñ¹‚̣»}̣»ñ¿‰̣Æ‘̣È”ñ̀œóÊ—̣Ê™̣É™ñÈ›đÊœđÊ¡đÊîÈœđÊíÉœ́Ê£́̀ª́Đ­íÏ­ïͬî̀¨îͪíί́Í­îα†*D„&C…&A…$B†$@‡%?„%?%A€>z <ƒ&>Œ+E‘7L¥G\À\jÎmtÙ|yàƒyæzèvé“{ë“uê—}í™zîœ}́„ñ }̣yî“pé„làtcƠ^S¸GI”,A#>’-D™1M¥;V¼g½h«H^¸FV¿dr›Hvk V5o„<p‡N€‹\†j'X^M`Qa#Vp2ff(\l2jh+^h.bt8fx7gd*Zh-bj.b}Ju{C|[V`$^Œ\Œx«[›t°x‘²\\R0U@X ?|1O®at¦`zœLf Pe¶p~ȘΜœÖ»¬¾„tœDQœ:LŸ@WµkoÄ X8N:R;o#@€*GdAb=]8n9f>n<{-F~,Fp?c:\ 7h:›O`›DS¤Lb0Dµ<FÄJRÏJNÔVYÙTWØX[ÚZXÛ[_Û]`ß`_àdeàdháhlâlkăgfăiiàehàdeàfhàflßjnàioàkĩosàpp̃qr̃mñts̃nlÜprƯqrÜrsÛtt̃zz̃||á‚€æ騛íÁ±́ÇÁ毳騫îĽîÀ®́¸¨è°£ä–“ÙtyÖjqÖjủjvÓkqÂ`jlEU@Y>XDb&JYFXDXAe"En$Gx)H…1I2L€%?.Fs >v"?v!<b9Y 9U
->~7U¾wzËŒ·kn—E_¶`gËmaÑsbÑwd̀}qΆrÎyΆvІu͈xΈz̀‚v̀†xÉ€yÇsÆwÇwĂ€{Æ~zÅ‚}Å~zÆ~yÈ€xÅ}xÄ}xÁ~|À}xÂ|yÄ|uÄ{pÀxtºup»rm²or³ljÆzp̃˜vê°xñº€óº‚ô½‰̣Ä‘óÈ”óẸ̈ËóËñÉđʘñʘđËđËđÊœîɘîÈ́ÊíΧíΩíĐ­íΫîÏ­íΫîήîέîϯîΰƒ,B| @{ >€ <#?‚)D…'B$D‚!B~ >„#Aˆ&@‘5M¦DWÂ]lÏntÚ~z߃xåŒ{è‘xè”yê–|́—|îî{î¡~ñ¢|đœ{́–vè‚iàs`Ó^VºJO”*D%B’(G™/O´ZsÀn†¥CZ²ASºHV¹]t”>mp&Yr*_]H‰Y„Hy_Lc"T_Nn5fc&X_&Xn9rh,b{Fxw:p~@st5kh.do6kp7m|Ftz@~YWh,d”l’”c—–r¢„¤p0[@@IB}0V¶`rËsË–£¿•ª¸–È•£Û³¤Ø¸¨Ë‹œ>H¥JU CW²^gƤŸx?KPDO@R?„3F•:Pd@a@Z8l>e=l=x(E‡8Nr"@b6`<h:”G]™>P¢L^œ5J²8FÁEP̀JPƠOSÖVZÚY\ÜZZÚ][Ü[[ß\_̃ggâcãfjáffáhjáhẽek̃cd̃ehàih̃lnƯlhƯefÜjlÜnl̃hjÚglÜonÛroÚprƯkrƯoqÜzzàxá…zä‚zæƒtå„tê“虇́³˜îµ¡ë›è‹‹êˆˆæâ’̉fnÏ_lÑdsÔlsĐjq¡DYZHVAV>[Ea&LXBZA_BbAu)Hz)H†4K8P~&Bˆ0F€-Fx">€(>e7T
-5X>n)L»w|Đ“’²dj£Pc¼ieÎqaÔu_̉x`Ëzh΄sÏwĐˆv͈{̀‡z̀…yÊ‚ẁ„zÊ„{Æ‚yÇ}xÆ€wƃzÈ…wÄ€}Ä€wÆ€xÄ€zÂysÆ}vÂ}xÅ}yĂ|uÂzsĂypÀwr¼wq»tr´nk³kpÈ{l̃œx́­|đº̣¾óẬÅ’̣Êœ̣Ị̂Ëœó̀™̣ÉñɘñËđË đ̀ đËíÊ¡ïÊŸí˦́ͦîͬí̉°îĐ­ïϯíάïͪîϬîΪîά€(Ex?x>{:~"@‚#=‚&C‚$A‚$B~=„ ?‹,C’2I¦FWĂ`lĐpqÚ~{à‰xä‹zè’}ê•{ê–}́•~ë˜zî›~đ¢đ €ñ{́”wé…hàueƠZRºCK•-E‰&H‘*L¥B\Âs‰¨Ic§:M¯>S¸J]¼l„?ifO[L_#W‰Z„“a’d"Mb$T^ Qf*[f$XZSd+cg(dq;k‰T’€Au†J~z>wu<rp4li*aˆZ‡w;q]Sh0c|B~d™˜s›‘h—TTMA§Td¥Bd¬^~Đ˜¦â¾´ß¾¾ç°⼩̉¤’ FI¦JRœ8P«OXÈ“¢qfO 9Q=S:V;„+B˜AJ^:b:Y6n<m:p>-D|,Fx"?`@b :l<–J^8IœIU•/D©3B¼?KÉKQÓTTØT[ÛZXƯ\ZÚ^[ÛYṼ^\à^^̃`_àbdáeeâjmàjnàfeàfgßffâjiƯccÚ`^Ú\ZÚ[ZÚ_\ÚdfÚgcÙopÚifÚomÜkgÜol̃jbßhf̃efÜ`aÜ^eÜ[băjpâhpävxæz}ăoxăeuăhr̃tuĐjh¿L[Æ[f̉kv̉otÆenrCYFWCXA^D\D^D]FcBdDy-Jo(F‚0J‰6J„,B‰4L'Bv>}(Bg9T 5Y <hFºv̀¬Za®ZhÆkb̉udÖzfÔvcÍznφ{ÎyφyΉyˇzË„wÊvÈxÈzÄ}vÈ€tÄ|yÄ€xÇ„xĂ~|ÄyÄ‚z€xÀ}|Â}z¾~~¿||ĂzqÄzrÂxq¾wt¼to¹rq´lm²hkÊ~qßzí±€đº‚ñÁóÅ‘ñÈ™̣̀Ỵ̈̀ŸñËœñÊœñÈđÊóËđÊ ñ̀¡đ̀ îÊ¢ï̀¦îÍ£́Ï«îΫíЬîĐ­îĐ®íĐ¯îάîĐ­íÏ­ïÏ«s?r>v=t<v<z=&A‚$A~ :}<‚ <*A’4H¢DVÁ_jÓqsÚ€yß‹|åzꔀê˜}門뜀ï}đ~đ €ñ€đ~́’qèƒjàraÔ[Q¶DK)F‰!E›6X¹i„±Xq 6Oª8O±H^ÂbzĂs‰4a^L[Ir4lb!M|Gsl)[b&Xa&Vj-]f*[^!TTT`!^s@v’k£‚E|‹Qƒ†Ny?rp4kh+hl1d‹\z;|j5m~PŒL€g †N‚‹V—_˜Öˆ¬k–¡h̀¢ª̃¶´êɾèűִ¤©ST©LT¤CR¢DY»{}Ħ˜Z<P?R;\=V<l8ˆ4F_;]9a:f;j<v%Ax%C|(A…+E^6^:g:Rd3H˜D[’,C¡1Fº<HÆGLÏNPÖRYÚ\\Û^_ÚXVÚXYƯYXƯ[Yß`]ß^_àcbâhlâloâliájiâldßrgØ[T·9@®6>ÀGHÊSMÑYSƠ]Z×`YƠ\YÔ[VƠWXƠQQ̉OOÓPOÑPMĐKMĐLNÎHRƯRVßWXßf`ÙbaÀ>D´3@ÆDMÂNSµ>L¸FUÍadÙrtÏov¦J\]CVDXA[@dDXB\BZ>fAf@‚3JlBˆ2Fƒ,D€*@8K{%>k8z&@p=U 5\ 8cD°hvÍŒ¬Yj¹jsËodÔzg×xaÔ|iÊvnφxΈvΉv̀ˆzÊ‚ù„zË…xÇ‚xÈ‚vǃzÇ€wĂ~zƃv€{Ä‚|€yÆ‚vÂzÄ{¾}wÀ~yÀ|uĂ|rÄ{rĂ|uÀzu½usµrq±kn´hhÍ‚uá tï°|̣½…ôÅóÈ•̣̀Ỵ̈΢̣ËŸñ̀ ̣̀đ̀¢đ̀ñÊ›đÈđ̀ đÊïË¡îͤïͨíЬîĐª́Đ®îÑ°îĐ¯îÏ­îÏ®îϯîĐ­î̉­pAp>s>vAv"?}#A‚&@€=}>=†%A.F”:S¨K\Âbl̉vwÛ~|à†yåxê˜~ë|ëœ}íœ~î€đ~ï {îŸđœú“vè„mào_ÑZR´DM”-K&O¹m‹½g~¡:T£0Lª:TĂe~Ñy¿l‚ƒ0`bQo)\|<iVE\HbPg*Zb(Xl1cm-`d&[YZ]^wJ—{¦‘a“TŒ‚J€ŒVŒ}@xs=va'`o6j^‘gNƒf)^xM{n3jy0]µj‚³pˆ¯^uÉܲº̃»½ê˼̃Á®´xxœ=L«KT¢AX³clе¨…JPP =ZB^@cAT8c<.>kA] 5d9b8h:r @q ?|+Dˆ3Jc 3Z 6f8”H\ƒ(F•ER‘3H–*@´<FÂFM̀RRÓQRÔ][Ù_[ÙZWØ[[ÚXTÚ\^Ư^_âd`àgeăfhájiâlläojânhßneÑTR±:N®;K¨.>¥*=®0<³6>¼:@Á:BÄ@HÉHLÂ>F»;D·8C¬4A°/=¸4BÄ?HƠGO×LRÖRXÈER·?T²6TºDXÇWfÆQ^É\bÖlpÖuxÇinv$FW@UDY>`BeCZ>Z@bBfAt*Gz*Jm C8L€*B‚0E‹6Hz">e 5€0Az)D[8]@^D£ZlÊŒ´htÄvzĐoaÔ|hØxbÖ|j̀}qĐỳ‡yÍ’€̀†vÊ…wË…uʆwÊ„wʃvȃ{ÇxÄ€{Å€u‚|¿{À}xÄ~yĂwĂ~zÀ}w¾{xĂ|sÀ~yĂ|uÅ{s¼xu¸tpµnm®jl¸kh̉„qă¦xï³|̣¾ôÆôËœñΤóÍ ̣Í ñ̀œṇ̃̀ËœđÊ›ñÉ›ïÊœđË¡ï̀ î̀¢đ̀¦ïͧíάíάíÏ­î̉¯îÓ­íĐ®ïĐ®ïÑ°ïĐ®ïάl@l?p>q?v?|>€&A~!A~=€ B„$@8O•:U¯L]Ä`jÑvvÜ~uâˆxåý˜~뙟›~îœ{ññ¢zđ¢|ïœ{́qæ‚l̃nbÏ[Z³BU˜/T°\€Är†£BW.J£2L²LhÎrŒÈm„¯_z~,\bKu2ch#O[HR?d&Rh-Zc,Wl5ff$Yj0bh*j^ bwH€˜v¦–k„L…€H…†K‡‡O„ŒT€Dv;y…L}Ÿ|„I~e'\j3n]"\ƒ>n·h{ÎmkÚb`̃bf伶́ØÑæ̀¾Ó¬›¢LR¦ESœ8Q´\hΩŸª~oSAXA`<b<^9T;`6s$>s >]=b<j<k=o ?n@v(Cƒ5Jj=a=d<’G\„*E‘=O6K“.C°6D¼@IÊNS̉RRÔUSƠ\Y×VTÙUUØXVÙ\]Ü]bàbẽdbàadàejáspâppâqmànhÙ\^ÔV]ÖW^ÏR[ÈFVÅ>LÄ<LÊ@OĐDỎLWƠN\ÔNXĐO]ĐP^̀K_ÊN\̀Ob̉LbÚUmß`vÚe|̃jƒÚb}ƠVr̉]nÔjq̉fhÙilÜrqÔnn¤DRZDVBRC\@aB^DU@W@f?gA|.HpBr?Œ6Jƒ0I‚+DŒ8Hz"Ah;{.F€1K[9\<\BLaĐˆ„¹muÍ~|Ôq_Ơ~rØxaÑ~mÍ}rщxЉxĐˆw·xÊ„wË…yÊ„zÈ…|ʃxÈ‚yȆ{€zÄ€v‚Â~yÁzÁƒ~‚|ÁyÀ{¾|xÄ}tÂ~vÂ}xÁ|u¼vs¸uq´on°kn¹nlƠ‹pæ§~ñ¸‚ôÄôʘôỊ́Ρ̣Πñ̀ ñÍỴ̈̀ñÊđ̀ đÊœđ̀ ñÍ£đΤîÍ¡đΦî̀¦îÏ©ïÏ®îЬïÑ«đ̉°îĐ«đϬđЬïϬđάh@kAp?q>v>y?} =|>|=z"B†,E>U•AZ­QeÂeoÓsr̃}sâˆxævé™zê›~í›}́œ}î{đ¢|đ£đ¡ïzêqælƯqgÍVb³C`µgˆÇ|Œ¦B\“,E.L¨<X¿bÈq¶Yv§Rp‚7bj(Wj&Rs/^^K^MXA]NVJn7ig%]d(Ws8xY^uQ„¦–¼˜g™n0jzE€Lˆ~K…P‚‰P‚‚Gw‚Hxn2a{Do~D~l:vL„¥`Ü}{ån[Ưa_ÓVaÛƒïÚËÛ¼«´pq GT¨FX²WeĐ“ŒÉ¦’`$FQE^DdAd@Z>U=`:p"Br <^9a;j?r"Ao!BpBr"@€2Hm?^@e>‹CYz)F6J6L’1H§7I¶@JÇMQÏOOÎSUÔYUƠTRÖTWÖXXÖZ\ØZZ̃_aÜab̃ff̃ghßpoàsnàqnáonánñfd̃ZZÚVWÛVXßU[̃RbàNWáKVäSZäZiă_pæZpèm…åw”æ{儜脡듬́ µë¤±́«èw̃_{Úbv̉rsÚtvÜnnÖpoÂ__mAV?XCVBb@fB[AXAZAgAh Dy%CjBw&C‹:L-E†.G5K}(Gh>z*@„6O_=_<\B’B[ÊŒÀw|Đ}yƠs`×qØwd̉ǹ€rÑ‹tʉyˈẁ„wʃwʆ{ʇzÉ„wɆzʃx̀„{ÅxĂ€wĂyÁ~vÂ~vÀ€x€vĂ€wÀ|xÁzÄ~vÁzyÂ~vÂzv¾vr¹vu³no°gi»mf׋vçª~̣¼‰óÅ’ôÎóÎñĐ£̣Π̣̀Ÿđ̀ ñÍ đΡđÍ đËïΠíÍ£ïΧîÏ©îĐªîÑ©íĐ®đĐ­îѯîЬïϬíΪîΪđΩïϨñͤj>iBp@r@u@z!A#B"@z={?‰*F8L™@V«K\ÁalĐsq̃}vá…væ‹tê˜~ëźź{î î¡yđ¤î¢}îœvèzäƒzÚpwÉWrÂh‡Æ|Œ¢EZ)D—,E0N®KhÊuµVtµOh¦Jl9fm)\f"P‰S‰k(U_ LN>XKSHvBzp*^b!S~J‡V\xX‡®œ¼“e’d+cd(d{I€†W’]•D€z<p|Cq[%_i-\VŒ‚PŒ’f¥h•Ơy‰äocÚb\ËP`Îyầ„x¤FQ¬NVÁgiÚ€Ö®˜„FPSGZM]EbAb@Z<X;\8g:n6k=^8c<p >k:t!Bt">~+Ht@]<g?„:O|$A8Kˆ6I‡&@˜.A¬:HÀIMÉLP̀KRĐTVĐPRÔRVÓWZÔXYÖZ`ÚY[Ü\`Ü`aÜglánláppánnänlåtláhh̃``Û\_ÙVUÜWZ̃TWàVZàLWâNZæP\åZmçetêy„éŒíœ˜îœ˜ë˜đŸ˜ï©¦ï°«í ænÜ`wƠhwƠvyÜxwØllÈjl5JX@WAT@ZDd>g?X<V:_;j=l=f<j@~-D‘@Sƒ(@‹0D/Lv=o:~)A‰<Ob>`<]D>\ˌƆĐ|uÔxb×r×xdÑ€r̀ƒs̀z̀z̀‰{ÎwÆ…yɉ|Ê…x̀„ẁ…vʆ{È„xƃxÅ„wĂƒzăwÄ€vƒxÂyÄ~x½}zÂzÄvÁ|vÂ~v½zwºzv¶qn²oq­fn¾ojØtë®|ôÀơËơÎôĐ£ñỊ̂Ị̂Πđ̀œ̣ÎñÍ¡đΤđÍ¥ïΧđϧđÎ¥ïÏ­ñШîЬïѬđĐ«îШîÏ©ïϦîΤđͤđͤđÍŸñÊœhCkAl>r<s>y>z<| =w<w>‡/J“:O@U¬HXÁ^h̉rp̃}t߇xäŒwé“{êź}́ }́{ï¡zî¢đŸ}î˜|é€â”Í|¡ÁlĂpˆ B[$B‹$B‘+Kœ:[¹`Äx¬If±Ib–Dkw,V|2ks2`zp*WT<S@UI^%X‚N‡m+^f!YwFzf"ff”¬¼•f–n1p] Zv=vt=w|Mf„P‰z?wn6hg-b€@rJ‚x¬ªp˜É|˜âkiÔU`ÊhsÔ¯²Ï°¦˜?P°W`Æjfä˜{Ø•~]TVCXJXB_DbDcB_<Z<^7^:k<k<_=`:j>p@r At#B},Dx(D`<c={+Cz"@8Nˆ6L"?3J®<H»BKÄHKÉMPÎQUÊPVÎPRĐVXĐTYÖTYØYXØ\bÙY\ÚadÚlhàjjâmiätpäplánfßhfƯbdØY[×W\ØRUÚVZßU^âYaæR\çP\ê\ńjxên|îu‚í|…́xƒîn€íṕ{ŒçxÜ`vØk{ÖrvÜxyÜtt̉np¹W\d>U=V<V@Y>h?d<Y;W8`8g8w(Ba:h=€,A–BV„,F‘8J5Jz$Bw$Bx$@‹@Rg:_>\F>^É‹É„‡ÏzwØ~hÖ†yØzaÑ€rËrÍv̀‹w΋x̀xÊz̀ŒzʈyȇzÊ…xÈ„wȆxɈyÄ‚wĂ„{ăzÆ…yÄ€xÂ|wÀ~tÁ~yÂzÂ|wÁzwÂ~v¾ztºvt¹rn²kl­hk½mlÛ’x́²„ơÄờö̉¤ôĐỴ̈Đ£̣ÎœóΠñË¢̣Π̣΢ñ΢ñШđЦđϨñϦđЦñѬđѨđШđϦïϤïËŸđËîÍ¡ïÉđÉ™îɘñÈ—m Dg?l>n>v:x9v9v:s:w<†,G“8L™?S¨DTÁ\c̉ppÜ~vă†væxè•yé™}́ }í}í |î¢}î¢|́ˆç‘匉à”Înx°NW'D…>$F”/Q¬RtɘµRl­C`°OiŒ=dfOl&Z„U~”ff KZFZHRJd/`L…g"WA‚l8mt6u˜ƒ²¡„¬]Œ‘b` \q9nzF…_%_xNw•j¥‡TS~LZ–†Pˆ§‚°Ä„¢¼w–×t…ÉJ]Ơå˸´pw®SaĐtkå‘r躓¬ihZHYKZG[F`Ed!Fg CbBZ>^<aBe@f>f@b@f>t)BlAn"By*Fw(Ec>cC}6Q„.JŒ9Kƒ0Hz!=‡*D 6I³BL»HRÂKOÇLPÉMMÊMRĐQTÏTVÓZZÖXYÔ_dØZaØ_fÛfg̃hĩjhàloâpmâmlàieÜcbÛ`fÛ^[ØWVÖTWƠVZÚXZàYZâVYäT`è^pébxêbyëk‚êídzébzçcxâ`vØfzÔt|ÛvtÙ|x̉lnÈfh4KXBXBVCSAZCdA^@`>]>h>f8r"Ad<k<‰.B’9T~&DŒ8M‰1J(C}'Ds>DWe<b=^F‡>_ʈΉ‡Ơ~tØ~n؆x×{fÍ‚tˆỳ‰zÊw͉xˈxÈ…xȆxʉ{Ɇỳ†wÊ…xɇxÆ„zĆxÄzÄ‚wĆ{Äz€xÀ}yÂ{¾|½~y¿~{Á|tÂ}uºvt²rr°nn¬dn¼njÜ’w÷Ê”öĐ ö̉£öѤóĐ óÏŸóΠñÍ ̣Π̣Ш̣Ñ©̣Шï̉¬ñĐ©ñÑ©đ̉¯ñÓ¬ñѨđΡđ̀î̀ŸîÊ›îÈ™îÈ”ïÇ”đÆ’îÆ–đÇ”e>d:j:m9l:s<v:q:r=x;‹/F˜8K˜EZ¥@PÁZ`̉nlÜypàƒrä‰sè’{́~ë |îî¡|đ¡{ï }đ¤€í›‚葃â‚|ÚtqËY[¬@J(@ˆ"E(M;\Âz“¿g¥Da°H^®Xx„:`cR`O•t˜’]€X?XDZMSOwF|xDwXPv:qv8xv<r§Æ–h{D}”zªEˆ|D€‹c–n3ne+duFo˜n¨ŒN‚’x­™p‘T˜eΪÁ€Çp“ÄJaÍ~ƒÖ¼»»iqÏwvärí¸—À{fn,NVL]"LXI[G^Gg"IdDb*L\D_FbEcH_Be!DhDe!Dj Du&En#Cw,Fz+Hh Ed>v-H‚0L3F2Hy"@…,D˜-A¬;H¸BJ»DLÂDIÇLOÈOTÊRỲTUÏX\ÓXXÖabÖadÚbdÜddÜfkÚfj̃hlàijâkfàmjÜddÜbdÜ^_Ú_`ØYZÖ[`ÔXYØQTØQWÜQZáXZáZcá]hådvä]gă\jáWfÜVbØdsØuvÙxwÛsrÖtt̀jj¦DMx#DT<XCVBX?_Cb?`Ah@`Bh=j@p"@e=m:ˆ4F‹8M'FŒ8H‡/E…0Gy >x:’FVi;d@`G‚;_Ȇ„ωĐ}m×€p؆tÔjÍ„sʉvËvÈ‹z̀ˆu͉xȇzɆzˉ|Ë‹ỳˆwÈ…yÇ…zÇ„wÅ„xÄ…{ĂƒxÀƒzÄ‚v¿z½€x¾~x¼~yº|x¼yw¼vs¾zrµtt²qm°lm¨co¾liƯ•{îºơÊ”ở¦öÓ¨ö̉¢̣Ñ¢óỊ̂Ф̣Ï¡̣Đ¢ñϦñ̉¬ôÓ«ñÓ®ñ̉ª̣̉¨đѧñĐ¢đΠđÊ™ïȘîÈ–ïÆ”îÆ—́Å–îÇ—íÈ–îÆ–îÆf&Lc<f<g<j:r=p;n;o>w;3FAM˜8L£=NÀV]̉jfÚvõtä‡uè•xëœ}í¢~́Ÿ}îŸđ}ï¢|đ¡~ïœé’|ä€oÜqfÍ[T®@K’)D"H†$N©TnÄ€—¥Fi¨C\°Lb Nil"NcUo&Y~™‹TyQ =^HSHRKP‚j1^XP\!Vx=‚~F±¯Îœv§o1n|R„–q¨ˆV’lœw=tg,bb$czP€–€³“r£ŒMv§o|?k­xœ²_~¶z¥ÁUoÅœ̃½܂ṕ—x́¥Ø¦{v*KXNXJ\H\ L` LdDhAj!Ca@Z?`Bg!B`?_@`Bq!Cp$DhBt(Bn"@t(Bx&Ek?a@o$C3P|,C‡6Ls >|(DŒ'@¡1A°<F¸GO¾DN¾BFÂKSÇLQÉRVÍQXÏTXƠ[\Ø\]Ø\`ÚdfÚaeÚflƯfk̃joßkmßgĩimÜdfÜ`eÛ`_Û\\Ü^aÖZWƠXZÎTXĐQTÑMS̉NRÓQT̉OZÑLTĐP\̉T`ÔhsƯ~Úz|ÜptÚrqÏqm¶MP…)AiBVBT>R<W>^?]>hBeDn"Cc<i;h;j;n<”DS‹2J0H‹5H‡3D….Cw=x"@<Jq:d?`F€8[É̉Ñ{lÙrØ‚v̉}mʃwʉxÊxȈuȈẁˆzɆ|ʈ}ʇ|Ɇx̀ˆzɇzɆz̀xɈzÄ…yÁƒ}À…|ƒyÀ„zÂxÁy¼}z½}v¼{xº|y¼xqµvt±on«ik§agºjiÙ–xöÍöÔ¨öÔ«ö̉¤ôĐ£̣Đ£̣Đ¢ñĐ¢̣Ц̣̉¨̣Ô¯ôÔ­ñÔ®̣Ó«̣Цđͤñ̀œíɘîÈ–îÈ•íÈ—îÇ–îÈœíÉîÈîÊŸïË¡đÊ`?b>f>k@h;h8j8f6k;z"@”<OBP>O¦>N¾V^ĐhbÚrnÜ|râƒté’|ëœ́{́ {đ{đ¡{ñ¢~đ¤{đ{èwå„pàqdÍ[Y±BL*E‚DŒ'P®Xrºu’ @^ªF`£Rj{7]\L^Ty2ct”€=bXAXFOJ\'X€I~g&X\TNPa&df²¨È€ª‚Gˆg5n™‚´b›‘nŸG‚q<zr6w~Z™mœ™x¥–c–Ms}7j˜f”–Mx©d¾QgÔ©ªÛ­¬Úzræ›å®~ƒ8GVFVG[J\F[C^BeCj Al BdAW?]<k@]@bAa!GfCm BqBj@l @o?s#@l?dAjB|-Kv$C†:Rt#Cv#B‹,E,@¤6D±<Eº@F¹CH¾GL¿ELÈNS̀OTĐUXÔXZÖ\^Ø\_Ø_fØaiÚhmƯfjÜjlƯllÜhlÚgnÙbhÛdiÚ`dÙ^dÙ`dØ\cØbf×dgÖ^cÏ[b̀W`ÎZfÑ^jÔbgØirÛu|ß{zƯ|}Úp{ØhrÖpnÄlm€ >…*Cc@V>UBT?Z>aBcDdCl+Im$Cd @e>j>i>k>•GW3K‹.IŒ8H<P€)Ex<z%B<Ls=o"EgHz4WăˆƠ—Ó}nÚ…zƠ€pÎ{ǹ†vʈx̀{ËŒyȇ|̀Œ|ɇzˉ~ˈ{Ȉ̀ˆ~ʈ{Ê~̀{È‹LJ~ņzÀ†€Âƒ{À‚{¾z¾€w»~x½~wº{x»zv¼ztµro°onªhj£_e³hhÜ•vđ¾÷ÏơÖ«öÔ¨ö̉¤óĐ¢ó̉£óÑ¢̣Ñ£óѨ̣Ó¬̣Ó¬ôÓ­óÓªóЧñΤï̀›đÊœíÉ–îɘïÊ›îËœïËđ̀ îË¡đË¢đÍ£đÍ£̣Ë¥bD`=f>h>f=i<h9f<j:„,FŸL\§GR¢FR­J\ÂX[ĐedÖqjÜznâ…tè’vê|́œ{î~ízđ|đ €đ¢‚î~ê’xæ„pàtb̉_X´CL)D‚EŒ#N®Xt¶p”¤<Z¥Bc:`y2Zi(WcUt4]b†h L\HUFGC`-\y@p^Kf)\WUR[˜¬«—½–{«™p¢t<„f“{°–p ‰T‚SŒlLtBvl Ÿj–Dlh-b–mœ˜e˜—`–§V„Ö ¢Û¸½î¦ñ¿¡QTVIWJXEZF[BZD^Ah!FgAl Be BZB_Ah"EbDgD^DbDf"Fk BlDl Bp!@t"Br'Ch@d=x%CpB€3Jt'Cl?‚,B“+A5C¥6D®<G¸CI»EN¾IOÆJTËRWÏU]Ơ[cƠY^Ö\aØajÙ`cÚdjÛikÛflÛfk̃fnÚfiÙgiÚcjÚejÙglÙbjÙef̃mñqp̃rpßtyƯx|ßx|ăvxâw{ăzyá|Û|̃x|ÙhvÙqsÑol«JUc8€,E^DXAR>UBX@`B`BhBg Bj#D`?f;d8g=j<˜DT4J1H7FŒ7L‚)Az"<{">:Fw%Dk8fGt,N„†Ô“Ö~oØyÔ|ò|nË‹yÉ…xÍxÊ‹|ʉwʈ|ƇzȆzÉzɈ{ʈÊ„z̀‡|ȇ}Ƈ|Ć|ÁƒÁ…zÁ‚|À‚|½€|¼x¼~{¹|v¸}zºzv¸xw´sq®kl¨gj¥bi²gjÛ—vđÀö̉¡ơÖªöÖªöÖ¥ổ£ôÑ£óѤ̣ÔªôÔ¬̣̉ªôÓ¨ổ©ñФñÏ¢đ̀ đËîËœî̀¡đ̀¡ñ̀ ïËđÍ¡đË¢đͦđÍ£̣Σ̣̀£̣̀¡bBb@d<e<c;e:d6a:i<5F©ITªLU¨FR²JWÅ[`ÎhfÖpkƯvkă‚tévë˜}́œýœ~́|î~ï‚đ ~î}èzå‡r̃tcĐ`Z¹CH’+G… D$K¤Ff´h«HgHmŒCf5\l&U~8gu3X}Ck^H\EPHLEh4ay=nWKi*[] ZY!_lª“¶‘q§ƒO‚—m¢|M€¡’½–q¢ˆWa[h1guFƒ‡b”¨n–§Dbo&WbQw¡g”·e~྾ïÊ¿ö¾“Ât_m#HSETEYF\I\B\A]@hBlChBg@U>\@h Da=c@c@\@aChAm"Cl@p @t#Aq$@h<`<n <r?t$Ax+DhAv$@ˆ&@%;¢4C§6D²AH¹DL¿FLÄIPÈKTÍU[ƠZ[ØVWƠ]aØbf×cfØikÚdkÚfjÛgmÜimÚimÚjp̃jmÜhpÜpqÜnrÜpsàvwà{}â€ç…‡çŒ†æˆ„æzå|å~{à‚ß|zÜu}ØrwØspÈnhy=a<„.FXCR=UAZBXB^B^Bm'Fh@o&G`<k>a9d@n>›LX5Jˆ-DŒ7J7E/C€(A„.D6F|'Bf<pLp"JăƒØ‹×†sØ~ĐxfÉq̀xËvÊŒzÊŒzÉyË|Ĉ~Ć€Æ€Ä†ȇ{Å„zǃzƇ}ć€Æˆ|¿„{Á…Á‚zÀ…€¾€y¾|»z¹||·|z¶xxµwt°qr¨jp¦inŸbl¬djÛ~ñĂ‘öĐ¢ơÖ¬ơתöרôÔ¥ôÓ¤ổ¦óÓªôѤ̣Đ¥óĐ¡ôĐ£ñЧñΤđÍ¡ï̀£đ΢đϦđÏ¥̣΢ñ̀¡̣ÍỴ̈̀ đ̣̀Ë ̣Ëœ̣ÊœóÉb<^>^=d>c@c>a>b@rC˜;KªFP§HT©FS´JSÅ^eÑdbÖqhÛwjä„pê’xë˜|́›î́›zîœ|đ}đ‚î—{́wåqàsb̉^V¸DO˜1Jˆ"Dˆ&L”;Z¨\€¬Qt¡Nl†3`v.\s-]ŒKt€>ev8b`JVELDNHr:fx;lQH`Pf"^Z[}W€œy£‚Z€T_–‰Srœ}°Œ\ŒŒ^’€N‡v;wp:tsBuœpœÀPv¾Eh k–r:d’Y„¤JiÓ–„êȱÀjh$G\IUGZI[J`!J^ H]G`De?l Dm Dd?W@`Aj"@_@f<l@^>\<`;j Bi>n<t!>t&Ai=b;l>v$Dn ?{,Bh=q;†+@€:!8˜0>¦<G®<D´CO¾FNÅJP̀NSÓWZƠ\_Ơ]e×`b×cfØhfÚfnØgnÚglÛkkÚmpÛnpßoqßtwá|}ây{̃vxăvv䃃拉猆蒋é‘å‚æƒ~â~}ß‚€Ư|~Üu~ØuvÔyq®RZ\ 7b:v#BVBVBVBVDVDbEi$Il"Bt,JfAf:j<a>gAo? S_‘7L0F‘>Q1F…-G&@‡.F8N{(Ep>mKp H„†ÖÖ‡zÚ̀uiʆxʆyÊỳ‹|ÉŒzÉ~ÉŒ€ÄȈ~ÇĂ…Æ„dž~Â…}ņ}Äƈ|‚yÁƒ|Ă„|¾‚º~z¸€¸}v¸{w¸|y´zx´wv±rr©lp¤ek£`l®im̃¢đÄ•öÓ§ơ׬ơƠ§öÖ¦ôÔ£ôĐ£ôĐ¢ôĐ¢ôĐ¥̣΢̣΢ôΠ̣΢ñΤ̣ΤñϤ̣΢̣Σ̣ϧñ̀¥ñÊŸñỆÊñɘ̣Èœ̣È›ñÆ–ôÆ^:`;b:a<c@b@`>`Ft>•6H¨JT¬JS¦DR´LVÉ^_Ñd`×neƯ|tâ…qèvêœ{êyê€ëzíyîœ}đƒîœzêxæ„õraĐ[U·CJ—.F†B*H7R¡LhHl¢Ji‡8fw/Zu5a€;aˆGmr2\`"OXJNFMFu@mx6gPIZNf"Vj)j~Pv˜qœQuB}„Yd‰]–•t¢’h¡’m Œ_˜†Tn9vl6n¡y¡°R~̉Ld±p˜r7bKx™Pv¶u†Đ¹¶t:RXJf FUDZB[E\A\CZC_;i$Eo'Fn<`AX<bAn"@`?b?l=c>]<`<f=n>l=n;r ?lAf<g<t"?o@s"=k=m>‡.A€";r6ƒ7-=¡2>®:B¶@HºBIÅJǸRVÔVWØ`d×`cØacÖbfÙfjÛfkÚinÜorÚmtÜnpßtxàxxää…„á‚âƒæ„„å‰è”Œè‘‰ç…èŒå‡†äˆßˆ†̃}~Üv|Ú||Ïun‹/IX>kAw$CTAUAXDTBbHb!Dm$FhAo%Ca;q$Bo!@b:l;x A O\“8P‹3I’@V:M€'C€'?ˆ.DŒ3Hv$B~&GkEr$LÂ…‰Ô•ÖˆtØ‚ÊtiÆ‚tLJxÍ‘|̀ŒxÉzȆ|ÊŒ~Ň|ȉ€Å‡|Ć{È„{Ć~Ń}Ȉ|Çzˆ~Ă…{‡}¾†|½‚~»€|·||¶}z·|vµ{y³xx´uv®tt©lp¤hp`j²prଋ̣ËöÖ§öجöת÷Ö¦ở¢ôÑ¢óĐ¡̣Ρ̣Ϥ̣Π̣Ï£ôЦ̣̉¨óШóФ̣Ï£̣Ị̂Í ñËœ̣ÊđË ̣ÉœñÈœđÈñÈœóÇœñÆœóĂ”_:]>]>`>_>]@]A\@t @—;L¦IQ­JR¨GT°GRÆ\^ÑhdØnẽxoă‡xé{꜂êv́›|́wîî›|ï}îxëtè…q̃s_Ï\T´CL”+G‚B,H–4Q¢Nf–GhKiw&Rj)So*]h#R\ƒm0YZLa OUIOHr<ft2fQF]"T\Ts2r„M€d‚X`#Xb&`i3eˆa–h¨™{­—t°j‘fQ’p8yz¡£b–ÁHjÆ€ˆBfn5a•Ut£X`Ǭ¤i)Pw:U_LUIZH\H^G[D^H`@p-Lp$DnBb?X9d?m"B]?\<f>f@Y>`=`?f;k<p>k?r<j=h@q!Al>t%?t"Ah9€-Dƒ,Ao6p4€6&:0>¦<C²=B¼BHÇMPÍUZÔZ[ÓYdÖ^cÖbhÙdjØejÚlqƯsxÜsxÜqvàzyá}€ă†ƒåŒäŒæ‰ˆæ†ç‹ˆèˆæˆäˆ‡èäç‹̃ˆ„ÜxÜvxÖ}xÅgfj9W?v'BgBSBZFZEUF^F`Fn'Fk#@m @^<s*Ee<e>jAy$FŸVb•?P2L’DW6G„(B…0G….Cˆ*Bv$@….JbBlI‰Œ×™Ö†~Ö‹€ÉykÈ„~ʇxË~ÊŒ|ÈŒzÇzÆ…ă~ƆĆ~Ă„|„À„}Àƒ~Ă„|Æ{Ɔ{Áƒ{„zÁ{¿‚}¼|x¸}z¶{z¶zy´{x³vt³ss®qp©np hjŸ_m¹wvç´̣̀ŸöצơÙ®öק÷Ô¢ôÏóÎœóΠ̣ΟóϤ̣Φ̣̉¦ôѧóѤổ¥ôÏ¢̣Π̣Ẹ̈É™đÉñǘñÇñÆ™ñÇœđụ̈́Ạ̊Æ̣Ä–ñÀ‘^=^<aBb@\<[<`B`Dt#D‘5H›<K BQ£CP¶HPÉ\[̉h`×lẽ|lă†qè“ý™ë›vëœwëzîyîxï¡~ï›|ëpè†nár^̉^X´EL’+D†"C,J“7R G]¢Pp€0Vk"Nh#Rb!Tb&R—kŒj*XY!N`#OWLTNk4^t2cRJ^!RWQj,i^”j˜…X‹f&^Z S] \l5p„Z–u¨–s§†Z•”s¦’s«„X˜”h•ªnœºf“Âx–¯G`Fv…I`…@[l1Lh)Nz6QTLWI]Gl$F^D[D[F`Dq#Dr"Dr"CaBZ?dBq&D^>_E`>n>_;^<d=`>k @m?n>l:k?k@p$Bl<s"?t(Ch>z(Bƒ,Ar<d7g5u3†";.<©0<°8DÁEJÊOTÎT\ĐZbÓ^ảaiØcjÙfnÜhnƯmpÚrvØstßvzâyyä~}æä’ååŒè‹æåçˆè‘‘ç˜å”̃†„Ùv}ØzzÑzx´JQa?\>v%D^FWK^!JVJXJ_ J^Gn$Cr(Ef:`=j!<e<b>l=x#AT_•=R5O’GZˆ2G…*D‹9H†0Fˆ.Hv&@‡/Kp"HjHƉٜ’؈|Ö†ÈxoÆ€wɉxÊ‹xÊ‹ÉŒ~È{Ljz‚zÁ‚~Ć}Ć¿‡Á‡À…€¿ƒ}¾†~¿„Â…{Á…|½„}º‚€¶{º|z¶|{µzxµxx³zy¯vtªqq§nq¢ckŸcn½€xê¸ôĐ¡öÚ©ơÛ°öÖ¥÷̉óΙôÍ™ôΛ̣ÎóФ̣Đ¢ôÑ¥ổ¨ñѦóѧôῸ̣˜̣Ê™̣Æ–ñÅ–̣È–đÅ•đÄ’̣Ă“ñĂ”ôÁŒđ¼‘í¶ˆêª‚^B\>`D`C[B\AY@[>mA‚.E˜:L¡BPªGRºPX̀abÔiaÙngß|nå†tç“xè™zêœ|ë€́zízî|î |î›|́’té†nâr`Đ^X²@K‘*F€ D‡(H’4N G^¤PbcG^GbLYRe.Z•_~€<dVJd$Pi)XVJo2`l*]RGZNSOTU]’œt¤’st2hZPl*jl8p{I„ˆY‹d™’j£—z®–x­†Z“Œ_›c–´tŸ´~“Lv–Dk‡Ia’N`^%No+N[#JX!KUE\FaD\EYBXDa@r @t@u$B^@V>eAx(C_@`B`Ai$FaA[@d@]:b>k Bn!Bh<l!>d=lAn#Ep =t'Df@r#?~+D„+Bh<a:a5s5‚9’(>¡0A²>HÂJLÈRV̀SZÎTZĐ\aƠ`i×bf×cmÛkkÜrtÛqvÜvt̃v|àvy䂂≄扈ææ’ç’‘æ‹åŒˆçä‹â‹‡Ư€…Ørz×yvÆmlª@IY;[<s#HZHW"M^$LX$OX L]J_!Jo%At.Id;f?e>i@i<l@„,E¡Wb“>L/G”CT„.Fƒ)@6J‰/D0Gx"@ˆ3LjFgHȆ„֖؇wׄÆ|tÅyÄ„uĆzÈyŇ|ň}Â…€Â‚}Á‡Ä„€Å…~†ƒÀ‡½…~ƒ|†~À…¾„|¿‚z¸~}»~y·|z´||²yw³xw¶xv±xt­rv¨nq§jk bl£dkÉzî¾ó̉¢öÛ­ơÛ®öƠ¦÷ĐôÍ›ồ˜ôÏœ̣ĐôĐ¡ổ£ổ¨ổ©ñЦôΡóẸ̈ÉñÆ™̣Æ“̣Ç™óĂ”đĂ’ï¾í¹ˆ́µ„ê«|äœz؇eĂgOa?\?]=\=[<Y=Z<\Bf@y$B“5FDPªHTºTZËcd̉d^Úqià{ræ†tè’zê˜ë—xë–{ëœ|î›|đ~đ›~î’tç†ràuaĐ^Y¬ALˆ)Ex D{&G3N¦[t€3Ub F\DWIj)[v>j€<]4^YKd&Sl(Vd"Rp.\h,ZSHUKUQJPR‚ ƒ²’s‡P…_Vs9ro5q{D|‡W€K†f a”œ†¶˜‚¶˜}°^– s¢¸‚¦¾¨x4cyAfMeIdZ"LRKT"LTJZJ\J\H\JYHd Jr&Hw+H~,HcAWBc>v(D]@^Dd CgBe D[@b@bA`?f?l!@j Bn%Ck%Dh>nBn!Co#DgBo"D‚.F†+By"Aj<e9f9n:|:Œ,Bœ.@«8@­<I²@KÀJMÅV\ÇU]È\fÉ\hÓbiƠgkÜjkÜprƯrxßvzâ}€à|~åˆ‰æŒˆæŒ‰è’Œä‡„ă†‚ä†‚à…„ß„„Ûz|Ör{ĐsrÆgd©@NZD\Ej$LY%OZ$N[&PW$O\$L_"L_ Is+Hr*HbDm'Ga@fBgChA„.JQ]’?S‘;NAR5I†0F;NŒ8M3H~,H8NmJl#LĈŒØ’…Ø‚x̉ˆ}Äxp¼tp¸ur»|tÂ}sÀzĂ~wĂx‚{†‚¿~À†‚À„€Â„~Á„|Á€¿‚|„|Àƒ~¼|½€|µ}~¸}zµzw°yz´zx²uv³vw®ux¨no¦hlŸcl¤foÔ˜zïĂ’öÓ¢öÚ©öجơƠ¤÷ĐŸôÍœôÍôĐ óĐôÏŸơÑôѤöĐ¢ôÎôÍôÉœñẸ̀Æ—ôÅ•óĂ’̣¿”ﻋꯆäœpÙ†cÄfP¢FF€-@h;X<[@ZB^@^?X=W;YC`?p@1FŸDP¦FR²IRÇ\_ÑfbÙukàvăxéxè˜|ê–{è˜~ꘀízî|î{ï˜ź‘rè„pßq^Î[T®AK„&DiEƒ/T¬f„¦^„ˆ9a“V~WHNIp-ZŒJro,Tv0Xf"Mg%Se&Tk(Sl,Wc$RTFTHYRKRlDt¢Œ»˜w£^g(\n4er6pf*d€Dx`‘h{F‡^ˆ™{«„T’nª›t¨¯¸¾‡ª›gŸ£x¦¤iˆ¨n„h1VLHNFSFXJZF\H^F\DmB{&B.Fz&DX=X=g!Bx,E_A]A_>hAjA^@_=c>[<a?f>h@o"An BjCq(Fs&Er(FiDl D~+G‚+Dˆ,E|!>u>q>n:x<{7";† :„":‹&<–0@¡;I¨@KªMX¶TbÀZaË\cÏdjƠjnÔnwÚwz̃xỹtzá~|㇆䉆å„Ⴢ̃{zßzx̃|xÜ|zƠpuĐppÊkhÉ^S—0BX@ZB_FXJ\"MZLX$N`#Na!L]Jn,Jl!DcCiBbBa<gBo$H„.J O_“CZ’>R=S‹8M„/F=P‘:N7I&@‹6Lo Kt)OÈׂֈ~΂x¹roµhf°ff¸lk¼rl»vn»uwÀzw¾z¾|{¼~¾„‚À„~„ˆƒÂ„~À…~¿‚~¾‚}½€|¾€y¶¶~~¸||´}|°yx°ux¯vw­su§nq¡dp `k­oũ¨ƒñÇ—ơÔ¤÷Ù©öÖ¦öÓ£öÏồ™ơÎœơÎôÎôÏŸöÎôΠơËŸờ›ôȘơẸ̀Ç“̣Â’đ¼î´ˆëªât̉~h³ULˆ0?i8^<X@U>Y@[>`A]>Z<X:X>V>];q B†-DBPœAO¤ANÁTVÑe_Úpc߀ră†rè’yé–|è˜~é—|́˜x́|ëœzđŸ„đ˜~êŒtă„lÚn_ÈTP¤<Iz H†7`ºÓ°°¥Lm Ut±t‡UEOGc M~8`q0YfJl'Ph#Qa Np/Z]H\LWFSHWLMPa4e Œ¹~©Ÿ­ƒJ†€L‚z?ub$`p6m”h˜’w¢J„q;o…c–}S“o¢Ÿƒ³®’¶¢y¤ q¢­†¦·™·±«•fX)SQNRKUKXJ[JZG[Il E‡2L0Ix)EZAT>e<{-D_?`A\A_?hA^?`?d>]>c=dBf@n!Aq%Bo"Cp$Dr%Ds%Bo!Bh=p!@‚&A”6G‹-D~"=z@~#?/J.M6O”5OŸ>[§H^®H`¯Lc²Kb³Qc¾UlÄ\l̀XhÑ_jÖdtÔdzÚuÜu~Ư|…ßz‚á‡â‹âà‚à~†à}‰Ư|ƒÖp|ÈhrÆipËlb½VUˆ4KYF\F[L\#NY'OY(SY La%M^"L^Go,Nj$Ff Dd@a@_@d=r$D€,HœN`“BV‘<P‘CR‰<R„4Lˆ4L8L6H}&D0Kw*Px*P̀‹×{؉Èyr¯ff®`b«Z\¬\`´c`µjn´nn»ml·tu¼rr¶tx¸wx»~z¾~~¿|zÂ~z½‚¿…‚¼‚¸€‚¼€|º€}·|x´zz±yz¯uw®tvªuvªlp¤jqcj `l¹xt䲋̣ʘơÖ§÷×£ö̉¢öÏœö̀›ồôÎơÍôÍồ›ờœôÊ™öÊơÉ›ôÇ’óÂ’î¼î·‰æ¨~̃’nÎvZªMJ€-Bc;Z<T 7U:Y;^>^@`=`A^>X>V<X9T<Z;q;‡-A—=G˜;O9J¼IRÎa\Ùqeß~oä‡yæxè–|ë{é–véwë™wê}î™zî—{ê‹päjÚlbĂRP¢7S˜AgĂ˜ªÜ¾¬–JT|$XRmŸc~TGMCUG~>gv4]aKj$Pj(Rf#Pm*S\H`JTFSETHNOb0`™|¨–n¢¥ˆ¨—jœt8dy9kf&b`!]~Hs—w›zC|n6t‹o¥o®t>x˜{§§Œµ ~¥‰Tˆq2[“Nm§†®‘´“ah0YNBM@RDVBZGZDlC0H…4Hu(GT<R=h Cu$B^B_@]?^Be@c?\?b>c?_=e@`?g?m$Cj#Ei?o!Al!Am Ag=j<€'=‰,A‘-B0E˜1H¤?NµLZ·OZ¾Q`Æ\g̀aj̉bkĐen̉ptĐpvÏjm̀inÊlnÎpz̉nr×uyØuz܇܃̃‰‚̃„}ß„~̃‰‚ß„̃‹à“á•ß”ˆÛ”ו–ƠØœĂ–£av{A_e.MW#HY'PZ(NZ#NY$L[!H^"N^Gl#Dh"Fe D`>^BaA`=t%D|*F›LZ–HY8M“FV:T…2L‰8N‘:N0I}(B‚,H{+S~5WĐ–‘ׇtƠˆÁmh¦X[¬bb¦RX¨V^¯ZX¯`f³ae°bb®fi¶on±hl²nt¶st¶tuµwx¹vu¾~xĂ|¾‚~»‚€º~yº}z¸}|´yx°x|®xv­svªqp¨mp hp`i¡_kƉ{ê¼ơÏöƠ§øƠöÏ™öË’ö̀–ó̀˜đ˘ồœóÊöÊơÊ–ôÈ”öÇ‘ơÇ“óÁí¸ç¬†á~Ñ…o¶ZQ‹/@e;X;T:O:R<`<n<p>eCf DfBfA\=W=T:R<X;o<‚)=3CŒ0D’1E¶OTËdcØob̃|să…wæ“|è—|ê˜}ê˜|ê˜|ê–xé˜|î™}î™zèră{eÖh`½Qb±UxĐ ¯â¿¢GLˆNmr%TftŒLaX KT MPD|<d{8an*Vi&Tl&Tt2`_H^Iq1]VIXIXJVQu>s™v¨’fŸ’hŸ€¬„N„u8fj.d[Ob%XwFswAƒZ˜·“qv>|R‹ˆ³¨’ºw£x@xb"Tu6`´”¨¾¢»¦ƒ¨f1aGCNFSFUE`Dn@.H8Ks @T>T=o*Fy(B^@]@`>^>cCh?\>a>b>\<aAb>d Dg An"Bj<u&?j>f<f8c8t$=†,D’3D“6I¦AO¶KX»O^ÄZfÊ]`Đ`dĐ_fÓ``ÔcfÔlhÔihÓheÑjkÍljÔpn×jk×mrÜtwÜzwƯ}yÛ|̃|{Ü{zÚ€€Û€xÚ‚~Û‚|Ư„‚Ưˆà“‰ä›‘槜è²é¸£á·¥Đ­¤²˜‡\{j9]R#IW$MUJY$M[E^EfBf BaAX@XCi!F`?s(F{(G—KY”G\‰7O‘FX:S…2LŒ5J;P’8L‡-F†,Hy&N‡:WÓ•Ơ€jÖ†}¸ff¨QX´\\­Y\¨O\ªSW¨U]¯Z_®Z^­^c¬_hª[c¬bi©bg®fk¯jn®ln²ps·ss¸zzºzwºwv¶yz´z{´z{°xz±y}®ts¨or¥jq¢gnœaj¤dlÔ—ïÀ”öĐŸøÔ¢÷̉ơÊ”öÈ’öÊ—ôÊ•̣˘ôÎœ̣Ê›ôÉ™̣È”ôÈ”ơÄ”̣Âí¼ç®ß›|̉u´e_8Hf:W>S@P:Z>e8w"=ƒ.F€*Di>i"Dl$Fd!Ed@^?Z>U:V 8l=z!=†/A…/F/E¯KQ̀cb×lbÜ{må…vèzè–{ê–ê•~é˜|ê—|́́~î—{èrâzjƠklÊj€Û«®Ü°Œ’BH}0Ru&Pc K[xj*PL?MDNFw8^„Bhp,VdNl)Rn)R` M`Q~Dmd!Q] M[LXPp4j“k™•m Z’xœœ~©|Fv^&UNK]#]‚WfŸ“x§Ÿ´€PwD|RˆŒe’¦”T|”iƒFzd P–_vĂ“ µ–«¢‚¬a0`MKSFVFbEs#Gƒ-G:KmBXDXBt.Hx-I]C]CbF]B_@fB`@_=`>_>_@bBbBjBo#CkAl?r#Ce?d;f@m>‰-C”2GŸ:JµFSÀQXÊV^Đ`fĐ_dĐ^g̀Y^Ë_cÏ`aĐbc̉feÑed̀glÏihÓjoØmpØpqÛvuÜvtÚzyÙ|zÛwwÙyvØvtÙut×xtÙzwÛÛˆ‚ß”‡âŸŒâ¨–絡跥́º¤í½¦́¾¨à¼¬À¢¥“k†n?aX,QW(PYH^HeEc E^BVBXB^DdEv.N‚1L—GU–Ja†2K;PŒAZ†3M„0L:O6N‹1H/Mw,U‹>[×™”Ö€n΀y¸bc©Zb°]e¶cd¬Zb¬V\ªYa¬R]®\bªX`¬V`ªYc¬Z`£Yd¨\b¦\g§ah©di¯hl­jp¯mp±pr¯pw°tv±uy¬sv°ux¬rs©or¤ktfrœ`m¨dnØ€̣Ä“öÏö̉ø͘ôÆöÈ‘÷Ç̣Ç–ôËœôÊôÉöÉ™ơÈ—ôĂóÀ굌⦋ה|¿rj—DLoB\BS:W;a>k @})DŒ1G4H‡/Hx,Hu*Jp(Hm%IhCfA`CV@W@f>{#?‚)A‚%=ˆ,B¦BLÄWXÔf^Üthå‚sæxè”}ê”|è–zè’|ê•|ê–}í™ẃ‘wè‰tâ~vÚ~ß­¬Ó’u4Hx$H‡8[f"T|<_¯xˆVDLELCLDn*VˆDjv*TdLg&Ri'S^NeT|Ej~<he"S\M[Nf&`q>n‘j˜r£†S…“m——w¨p7w`*fq9tƒP†˜w¤¡’¸k’h1jwJzF‚|Ff”—p¤~Dn}@lt8v„Ii¬ˆ ¢jƒ¨Œ ¡‚¬T"MODVFf Es)P,H‘:LhEWCXDj%Fy/NfH\Fb D\CZ?cCh"G`B`>bCbDfD`@eAm#Fm&FjBl Ce@i Af<m>‰2G–7K¢:K·J\ÂT^Ê[`Đ]`Í_dÎZà[`Ê]cË`gÎfj̉bcÏejĐhlÓknÖilÖgmÙnsÜqqÛvtÛvwØsrÚrtÔqqÔtuÖqxØrtØvuƯ{̃Œ‡â™‹âŸŒăª˜æ´çº¤èº£é¼¤ê¾¨íÀ¬î«⿭Ȫ¨œu‰sDg[,NV!G]G[H` HUCTCZCdFp(GŒ>W•IW˜Ob†5Pˆ=Sˆ<U/L†2I’=N4N„+G…8Wx,V”H^Ø”×iËvr´be²bfºmoºhf·jj²[_°ag¯[^°Y]¬V\©U`¨T^¨T^¥P]¢T`ŸS^ V`¡W^¥T\¦^f¨^e§^g¤bm¨bi¬hm¨joªlo¨kp¤ip£fmfnœ^j§dqÚ ~̣ÂöΘöĐöÊơÅôÄơÈ‘ôÉ—ơËœôÈ™óÊ›öʘôɘđÀí¸‹ê°‡ä¨†Ư–Èzj LTr=]9Z:_>gCr B+C0G’8M5J†3I™NdBZ‚5L{,Ft%Dj>f>_@a?q>}$>{$>t<~"<–4F¾NRĐ`XÚtjăƒtèwé–zè”xê’{ê“|ê•ẃ“xí›yí“|ç…äŒè´ÙŒr£EP€#Dx$I~0^t+V´‡WaMBJ>J@K
->\ H€;dy.YW@d%N_H^J`P~GkNys*[l)Zf%Sb$YUQm8fœx¦’a˜|Axm˜fŸ”o«˜t²˜w­¤”¶†¨l3du>}s<x†Z€Jˆ~N‚”q—‹Vm.kh›£r¸”¯£f‰w6]«ªh”RKTBcGnB~(E0HaBRCUCr,H~1J`B\@bD[A\>^>i DaA_@bB_Ad=aB`>l"?l#Bk Cp@hChAf>k:*C’8N¨=K¾LVÂP[ËYZËX^Î\_ĐZ]ËZ^ÊZbÎZ_Đ^cÑbhÓdkÑjlÖhn×ijØklÚknÛpnÙrsÚqpÖkjÖrpƠllÖpp×rrØroÛ{x̃€zà’„á–‰â¢ă¬•æ´æ¹£é»¢ê¾¦ë¾¤ë¾¥êÀ΅¿¨ïÀ¨è¿ªÏ²©¤|u@\Z BR?Z>O:N>P;`=p!D‰=U‰8LPb‚/J‡:T†8O‚/Kƒ.K’=P4K~&E~3Pr#JQbÙÔ~lÈtmµfi´lkÀqmºljÂql½ni¸ed¶fd³bh±^c°\`«U`¦Vb£PY£P[¥OW¢OWœLWL[¡Q[¢Ua£X\ [hX`œX` [b \d \i\e]j—Xc˜Uf§agÛ¡„̣ÀöË–ö̀’öÅôĂ‹óÄöÇ–ôɘôÊôÊ›̣É™ơÊóÈ›đÀ’ë´ä§„Ú“v¾fX–=Fq<Z7[5f=n>t"B€*E‹1G”8H’7L‘5J”?N¢kz cv›RdCW†5M}.Gv$Dj@jAz"@x:t<n6p8‰(@­BK̀WRÚoeâ‚pèxè“zè“yê–ë’tê”x薀ꗈê¡ê°¢æœ„à€lÆ[Z¤APˆ'I€,R˜Ko§r¯nsi$ILBRBO?NBXCg$S:bn)Ux;fM :SB^Lr0[’R{|6fs1dj%Pr>lKENLˆd…qœ`Œs8ja)UtAiƒM|‘l’Ÿ®uFqo7vxF~‚P†x?x‰b—ˆ^–†Y[†P‰”f˜²ŒŸÅ–¢•Tn|7hvB^ª”¤o8cVAgBmB€)D5K`@RBVCx-C‚1L_?^BbA\>\@Z<jCf>`>a@]?^?a?dGl$Hp&Ci Bs BkBj?g>f:~(DŒ5J¢<K¼MVÄY`ÁX_ÆV\ÏZ]ÎZ]̀\^Í\aÏ[d̀[fĐ`jÔjlÑhhÔfkÖgjØglÜjmÙlsØln×jr×moÙklÔnsÖpmØpoÚtqÚ|w̃„}ᒃ☌ä§æ®›è²œç¸¢é¸¡ê¼¤ê½¢ê¾΅À§íÀ«î¾¦ïÁªñĪîÄ­̀²¨ wf5TQ<L8K<M 6`:n@‡1Jˆ:O˜P`€(F‡;Pˆ8Qƒ1J‚,H9H‡*D€*Dz%Er$N¦XgÙ’̉}pÈtrºlnºsn¾trºqnÁrlÄvrºke½jh¶hh³eh³dk®^e«Xb©Xb¦S^¢MW¢KUJT IZœJU˜DTJVOY•KX•LY–N^LX U_X^—R]GXDYUbØ•yﻆöÉöÉ’öňơ‹öÅơȘóǘơÈ›ôɘôɘöÈ•óÆ–ï¾å¬ˆÚ–t¹f\„,A`<^<c>m>z&Ax&B~(D†*B‘8J”4G‘4J“9L–<N¦q€¦q€§k{ _n“I]Œ=P‚4Lv'Dv$B„,Fy<s9j8n9…&?¨>GÉTTÚncâ~næŒ{ê’zê’~́”}ê˜zë–z蔂ç đ§Œ́|æˆtÛtg̀^YªBT,PMwª`lĐ©£w(DT?M>L>L=O=VARFr-WŒPw‚ItG7L=[Nm&W“`ˆ†Drw2ew8exCrJ @J C^"TbŒx§•g›|JzCvv:pƒW‘p™^#Z€UŒƒVL††T‹ƒLg˜fŸ^’‹Y•a–f}°’­„Cj~:ct/e|De|Ÿe"MiChB€'D…/I`?T?U=y+C~-Ca>`@a@Z@\BY>iBg Bd@_B[A\?bBh BfAm$Dl"B{0Ip!Bl@g=b<q!>‰0F¤?JµHPÀPUĂRX̀XỲY]ÊY\ÊV\̀\dĐ[`Ñ_eÏ]dĐhkÑfgÚddØdiÙhjÚjlÙlnØinØouÖkn×km×om×rnØvvÛxũ}àˆ~ß•ˆâ ä«æ¯—ç²–æ´œè·é¶œê»í¼¥ë¾¦í¿¦îÁ¨í¿¨đ¬̣Ă«óƯéȱÀ©ªWvR#CH<J <[<q&D€-I<O–Ob},L†7L3L}.I~(D5H‚,Eƒ,Hy)Kr$O¬^k؃̉zqĂvxÀvzÀzu½xt¾vpÀunÁzt¼rl¼qr·ooºlo¸jj´hn³fi°bkªYa¨Vc§U_£P\ LYHT›FT˜DR–JVHUAV‘HXJW§W[§XZRU?Q„0J–DVÑ‹töÈ’öÈöÄŒơĂôÇ”ơËœôÊôǘôÈ–̣Æ”̣•걈̃—|Àuf5D]6`;pA€*D~,Bƒ+F€,E…0G3F“8I‘7J–8J•8L“7L©|„§u„¨t‡¦r} bpTf’AZˆ7N‚1Lˆ4K~(Dr=f>h;€(D¦>HÉTRÚncâ‚qç‹tè{é’wê’ź”ý”|ë|́~í•zë’rè…rßtbÊ\]¨C[˜Dd³gˆ»w}Æ‚W?RCNAQAQ?TDR?WNi(V‡QuƒHpE 9H<PFh%Tp–‡Fsv2b†R}w@iTIOETHo4b[ƒa‡›v¨ˆTRˆ˜|¤„Th.mc-e‡b’ˆ[”ˆ[Y“v@nœ‡¶‘j¢’hw¡£b‚¢iz¨ˆªu-X^JR„ vƒWbCgD‚(Ax(D^@R;Q;|5Ix-GbC`Cd!E[?\CW>f!IdDj'Ib!F`B]B`BgBdCi Eq%H|,Hz(Fo BjBc@r B‡4KŸDV²HR»NW¿NUÅQZÇY_̀X\Î[_Î]dÓ`dĐ^`Æ_hÎaf×fgÚehÚkhÙjjÜnkÙjlØlmØmnÖjj×mnÙrrØppÛvtƯ}ỹ„yà‚á—‡ă‰ä§å®•å°–æ²ç¯–ç²–è·ê¸Ÿê¹›́½¤ï¾£đ¿¦đÀ¥̣Á¦ñƬôỴ̄ɮ׿®œ~”\-PJ:V<n"Br@†:K—NZx$F‚0J4N{*F~*D1G„(D‚0Ju Ep#M¶lwÖĐyq¿pnÀ|zÀ~zÁ~|¿xuÀzwÅyr¾wvºsr¸su¶rtºqr·noºmn´jl¯fk¯ah®^e¨Zb§Wb¡P\ŸL[˜FZ”JXBR?S“FV¤T^´ca±`XªWZ“CQ0L’>PÓsđ½ŒöÈ’ơÈöÆŒôÆöÊ™ờ ôÉôǘơÈ–̣ŕç¦zÜ’jÀhY8Gg<b;s$B‚,F‹4J†2J…/H†6J4L”7I”<L˜<K”6H”>P”9M¨zˆ¨v‡¨}‰¦y‡¦s¥hvŸWj—L\@U@N…3F{#@d8e4€(@¤>HÈRR×ncâ‚qæ‹{èzç’yê’xë”ẃ”{ë–zë•|́—{êwè„l̃rfÆZ^¹dºuŒ¯^u¿zzŒH]RFP?QBR<N>Q?ODv;r•U”Y†DsSIGDXU‰UˆŸvu0`y7hHra%PXKQHi,`‡N|u2cd"XzJy^–yŸ~Kpd(]k2iq6xh2fŒff–_“ˆH„”o¤Œ¸”hœ›tœY‚”Lb™oyœ|¦ZN^ MLp¬†m,UeD|&EnCYBS?W@‚1G~.Gd?cF_BbD^BXC\CfFh&Gh,L_A^C^BcAhDi"Do"E|,H‰4Jn"DfBbAo Bˆ6J•BU®HUÀRXÄQXÆRXÆVZÍY\Î\bÏ[`Đ^dĂZaÊahƠdhØhkÜikÚnpÚlnÜlnØkmØhhÙjnØde×mrÙstØttÜxṽỹ‡~à’„á‹ă ‹ä¦’ä«”ç²æ°•æ®™è±™è¸œé¶ éµœë»¤́¾¤ï¾¤đ£̣©đỊ̆Æ®̣È°̣˳åʱ°¤m:ZQAfBeBx1M‘K\u(J}2N4Ny(F„0G9L'D,GlDs%MÀ{€Ö†zÎwjÀqtÊ~yÈtÄ|wÁ~|Á~uÁzvÀxt»vu¼uvºtvºtw¹sv»rv¹or´jm°go®bj¬elª_f¨Ze¢R_¢T]›Tb”HV‘@TŸOY®XZ¾k`¿eYµSN”DR‚+I›FTÚ–wñ½öÊ–öÊ•öÈ•ơÉ”öÎ÷Îö̀›öÉôÈ•đđ窀؄e´UQ|$>_7a:u$Bˆ0E6LŒ0F‰1I‹3H:O–;Lœ?P@N˜AM’7I•2G–7N¦x†¥t„¨}ª‚’¬„ªy‡¦lw \l™K[–EU7H}&@f8e9z=§<HÉVUØplá€tçŒ}ê{ë”xê•zè”ź–x́˜zî™~ï”zêqä€lƯmdÈ_ẻ‡–Ü¥¢C]¨^tv.RPBPBQ?R>L9N 8H
-<VF‡Ip›d’p¢b W’›liŒ|8`r.fn,^k.Zs:rPLf+c’a‹€Ald!Th(`ƒ^hr;bn5l^$[h2ft?up;uq@ra–”jŸ–e£…²~«­–rvœm'RaLˆg{ˆ`MLm/a¡m{˜l_Ew"Fj!KXJUFTF6O|.JfFfHaHbE^BWD] He Hh$If$Ha"GaD^Ba>r%Fi%Hx%Gw$A‹5Hy%Df?hDmA‹9L?S­LYÂRTĂRZÊTYÈT[Ï[aĐ\aÍ[`ÆZ\ÆajÔad×diÛikÚnqÙpoÜmmÚlm×nmÚddÙfk×fgØoqÛrmÜvlƯx̃ƒyà~à‚ᔃ☉䣑䨒宓嫖æ®æ²˜è²–é²–é´—ë¸›í» ï¾¤ïÀ¦ñÀ¤ñħ̣ƬñÆ®óÈ°ôʶ́̀®½¦¦t@^\>WAl$D‹BTp"Ft(Dy,Ht"B~(A‹4J(C„(DfAr#JÄ…†ÖnÊunÀuò†xÈzÆ}vÂ~xÄ~zÄ}vÀ|w¾xy¾yz¼wxºxwºux¸qu¸tv¹op´op³kp±in®cfª_h¨`i¤Zb WeSa™GW¢OV·\YÈjTÄk\µXP›BN‘2N¶^Zà£~̣Ä‘öʘö̀˜÷˘ờ›öΙøÎœô˘öÈ•ôÆ•ï¿Ư›r´\Wz$>\@Z9t!B;K”:H‘7F‹0FŒ0G1H–;M?O CRŸDQ>L‘8K”2D˜8N¢n‚¤v†¨‹¬ˆ“°’®„¬|‡§m|¢`h›P^;K‚(@j=^ 7w @¤=IÈYV×njâ‚tè‘zê–}ëyê–{ê–|ê•uë˜víœ{í˜vênä€nÛkjÔ{ˆéƸԕ„=]‘@Z1Yd"RTBP>V>P7T?P@VCk)Ta!Jc%J|;`VvLlu1\n.[v8hc!Vb([k0fx@|”fTu^HTHo2b”y¢m-X^"Vf.ba$[]"\r>r€N†r<t€R†Œb’—n¢x¤w©z¨Ÿ€­£«ƒDuH JvB_¶¢°|H{\Jƒ?f·›ªl(OlD`CRBRBRDz0G~,IhDfA`Cd H^FSD^Dh Cl)Jj&F`EbD^E`Dt&Hl!Fz&H},H˜:K’6FiAe=h>Œ8P–9N²P[ĂPSÆQWÍWZÍ^`ĐZ\ËZ^ÄTXÊZbÔgk×ik×gkÛdfÛikÙnlÙllÚlnÚlmØffÙhlØjmÚljÜtñzvß{à…{à€á€á‘†ă–†â ‹ä¢å©’娓檒谓殑貔ç´ê¸œ́º́¸đ¿ ñÀ¢đħóÄ«̣È°óɱơʳồµîδŭ¦DdT?j Dˆ:NjBo!?t%Bn C.Dˆ/H+By#D_?t#F̀„„ÖuÇvq½toʃxÆxÆ‚xÂ}yÂ~xÂ|v¾{tÀzy¿|x»z|¼|z¹vvºsu¶su·su¶rr²ln°ko¯gm­ho§clªal¤`k¢_kŸR`¥X\ºbVÆkXÈjUµXQ¤DQ <PÎxeè³…ôÆ–öÎöÎœöÍœöÍôÎ÷ÏŸöÊóẠ̈Áé±Î‚jœBP^=Z<p!D9Mœ>L–>N–8L“8K2I•9NŸDQ¤FR¨JUCP?N“:L’6H@O l~¢t‡©~Œ¬„”­™®‰•¯ˆ“«|‰§nz¢`j”HV.Fl @\8y#B¤<HÄTW×nfăƒuçyé™|́˜yê|ê—}ë˜ź˜yíyî–zèrå~l̃nnæ“”öĐ¾¸nzTr;\`FdJ_J[EbJXCWF\Ei$Rv8_XGLEh'Rw5_n(Rk&Sb!N^Kf$Ss4gzDozChx;]e#PN BUP‹]‹™{¤XR\$Vd(\n6me)dd*c}L€‚PˆxA{zD|‹[v¦œv¦˜r ¥“¼‚Ÿ{¢SQSJ´†º£½m*X‡F{vPwh@Z@Q?TDSFv-Lw,HeDhB]E`E`GXG^GcDl(Ir(H^B`A`E]Gv.Jr*Hv Aˆ1K£?I©BKt#C`;_;†0H’4H¶S^ÄQVÉPWÎVXÏa]ÇU]ºO]ÆW_ÖadØfkØmlÙhjØdgÚflÚjkØihÛmjÚjhÙklÜjmØouÜqrƯwsƯ}xá€xà…~à€â‹â‚ă•…ăœŒäŒä£æ£æ§’ç¬æ¬—鯔貒굘́¶—́·đ¼¢ñ¾¢đ¤óèóÅ®óÆ®ôÊ´ô˶ơιñϲĪ¥s;ZeE€4Ll#Fm"Fm#Fu'G…6M‡2H-Iy*J\G|.QÔ‡Ơ|mÄxr»wxÇ€yÅ‚zƃÀ}z¿~|À}z½|w¿‚}¾zx¿}z¾yw»wx¼x|¹ww·tx¼vy¹ss±nr±lr°orªjt©jp¦hr¤ai¢\e«_Z¹gZÂhVÄjS¹[O«NR²NTÙqﺉöÈ•öΛöΘ÷Í™öΛöΛøÍôÈ”đÂë¶á¡s¿n^ƒ*C\;k@ˆ0H›;L˜=L—?Q—:J”7M˜6JCS¨JR«LR«HRAM˜<N–=P˜<P£FXœl€h|£r„¬‚¬‹–¬˜®Œ–ª‚¬x‚©tz XaŒ<Ls ?a7z#@¢7FÆVX×ohâƒrçvé|íœ~êú˜|́—x́yí{́•vèŒpänßqs蜒îʬXr¼o}±xJ :S@P8\Bf Hh"KfJh$Nn(Sx3Xf#QPDr/Vx6\j#L^Hf$Qh(Tf&S`!JXDVCVI`!PRNXRV~gm2jPH`(`p:kn6lj0jk7j‡ZK~xAuK›pœŸ«œs¢œ bŒwˆVŒm-n–Vr̀”¡r”€Et@V°Œ¥c JXHTFVJWL|4Qv.Ok!Hh#Lc Jb$L^$KZ L^!Jd%Km(Lt.M_"Ib"M`$Nc!J€5Sy/Ls"J‰6R©FW­HU…0MbF]B~-J’9P¸ZfÈW\ÈT[ÊSZÅW^¶N\ĂW]ÔfmØafØceÚjnØfjØgmÚimÛmlÛnmÛhiÙhjÛifÛlhÛrõvqƯxt̃~váƒ{á|߈|á€á‘‚â”†â‘ƒăœ‡å‡ä¤ä å¤‹æ¯è®é®é´—́³•́·˜î¼đ½ đÀ¤̣Ħ̣ƪñÇ°ôɶóɵóλơѺîĐ³¿ p-Nl!<n=c>l;p!@-Dx"D„/H},LYE†4NÖ”‡̉ufÄwrÂwrÆ~xÅ‚{Æ‚s€xÀ€x¿}v½xrÀ~zÂzs¿zx¿{x¼y{½vv»wxºuw¸vv¹sv´rx±nr°mp¯lpªitªjq¥dl¥cj¬``µdYĂjVÇiUÄdP¶TPÂ_SáŸyđ‘ờ›öΙơĐøÍœøÎøÎœøÎóÈ’í¼‡æªxƠ‰e¯XSwAf@~(D>P=L<NAQœ@Q;K<N«LV¯TW°V]¨JVDR–=N•4J›@O¢AQ‰JdSjŸl~¦yˆª‚’°–°’°Œ˜´•°‚‡¥fm@Rr >b8| ; @LÅWZØneá€rè‘xê›zï~í́œ{́{́zî }́yêpè„nàph̃€zᵪ˜Ah˜HT¤fjJ=M>S@T;ZA[CX?^Ao2Xl%Ko+R]D]BZ!LXDZKw:h}>lf(P_ IS@PBQCp5^^"NPFZ SuBoˆV…b&[VLh*`d)\p6nk/ltBtŒ^–€F‚z<t—n›¡~«œt™s¡`”“j” x¡Mz–Y‰“Rl¦„r8l]J¸£­v4ZRESHQERC€5Nt(Ij%Fl&HaA^@]DUDaBb"Hj#Fx,K^HbDa@`@s#Bz*Ew$F’6N´MR¹LP8Hh;^<|(F‘6K´YdËXYÊPV¿M[¸T]É`cÖ^aØadØbiÚhkƯhiÙhiØlkÛjfÜijÜojÜhgÙnlÚllÛllÛqlßvr̃ytá}râƒxâ‰}à‡zà‹€áŒ}ă‚ă–†âœă„ää‰å¦æ£Œé¦è§‹ê®‘́µ•ë¸îºœđ¼ đ¿ óẹ̀ị̀Æ®ôɳôʶôͺơνổ¼î̉²²ˆ•c?j;^5e:t;‚-Dt!B}%@r"D\C”@RÖ“„ÑrdÂtpÄ|tÆ‚{È„uÄxÀ€x¾~xÀ}u½ztÀ{wÀxt¾zvÀ{v¾xt½zx¼xx¹wz¹txµqt²rx·qs°nt±ot¨jr§mt©flªgl®fd½h^Är\ÇlSÅcO¿[RĐw_ꯂóÅöĐöÎœöÏøÏ÷Đœ÷ĐœøÍ™đÅ“éµ…à›tÉrXDPx Dz(H9N CRœ>Q™8L>Nœ=O?R§HT´PY´TY°MT¢HTœCR˜=Nœ@Q¥GU¤JYm*L~:\—\rŸp…¦}Œ­˜¶™¢¶˜˜¼–˜µ…‰©pu—P^u!@`9v=£;GÆVXÚsjä„qè{́œzîœ}́œ~ë}ë{î~ï¢|î˜yétékârhÚ‡Ê~‚¢Xx{/Qf AL=Q>V@Q;T>]@UA^Dr3\\@e#HeHTCUBQC\K…JxˆK}d!Mk-W\KKCQFr<_v8gLDNKf1c‡T‚GvYQ^$Tl2jo3fh,fn5s|Q‚ˆYy>v–k˜¡¨n—˜p|¯˜n›¦†ªEodƒq%Ux|ª…ª\O¾”“e‚L<N<OCR=€3Fr%Dn@p"Ad@`A^@TCb@aCq&Ht.K_D_=Z>\;r#@{*Dz$E™>P¾QUÂSV§EPr<b<r"D“9M²PbÊTVºER¾O[̀bf×fdÖ^_×\\ÚfhÚhfÛhgÛilØheÙljÛghÚhiÜikÚghÛmpÜqpÜnlßtñxq̃zqâ~rá‡{â‡zâ…}à~ă~ă‘ä†â‡â„ăœˆæä§ç¦‹æ§è¬’́´–ë¶˜í¸›ï¼›ï¾ñÁ§̣Ħ̣ŬôÈ°ôȲôÍ·ơĐ¼ơÑÀơÔ¾çͶ—dwi@Z8a8n8{'@n>r%Ch=[A¢J[ד†Îq`ÂvmÇ~vÅ€vĂ€tÅrÁ~uÀ€uÂ~w¿|uĂ}zÂxt¾xvÁ|v¼xz¼||¼wv¼yy¾ut·tt²rvµqt´rv¯mq«luªjt¬il®in´hfÄmZ̀sX̀qUÆhSÄ`SØ„f﹄óÉ™÷Ñ öĐöÎœ÷Đ÷Θ÷Í›ơÊđÄ讀ւd¸XP1J{(H4MœAN¡CQ™:M=NŸ@NBU¢FV¬PX²QY¯RX«LS£DT@Oœ:P¡AQ HX¥KYZ<n'KˆKff|¤wˆ­˜·œ¢»½˜´‹¬xz\dz.G] :t>Ÿ9HÆXYÜphäƒrèý~đœî|ëœ~́|î {ï|홀ëwæ€jàvtâwÍ¥ª_p‚2Tk"LO>O=R>R>T;\AUCu<bh%LUD\#J^A^GTBSHf%UŒS~…EyXBx=dj$QOBNCd)RTWOPH_(Zz>tt;f}Cy_"Zh-bw:ps6ni4ih2f‚[‘€D|“i–Zƒ[b’Ÿ‚²x§² ¾¬yª[r[Ie*J¿¨¯:p°€„º›L>N 8M:Q>{,Bn$Fm Ar%Ff?eB_@V@aCcCl$Fo$Ea"HbH]@Z:q#>x(B|$Bª@LĂUXÄRT°EJ|!:`:q$B’6G§L_¾GTÁMZ̉[aÚcbØcdÖ^aÖ^`ÛcfØefÛfmÚliÙkkÚlkÛgcÛkk̃hfÛjmƯnlÜllƯrñpñxr̃zsàzràuáˆxâ†yà‰|áŒ|ää“‚ă„ăˆă‡æ¤æŸè¥ç®è¬ê±–ê²“í¶™í¸–îº ñÀ¤ñÀ¨̣ìôÆ°̣ǵó̀¶ờºôÑ¿öÔÂô׺Ơº²†<TX;_:m9u=h:r @iAaB´\eÖˆz̀l^¾wpÄxpÆ€vÄ~tÄ€vÆtÂ~qĂ|u¾|rÄ€uÁ~w½|vÀ{u¾{x¾{v½xwºxz¸xzºvy´rtµxy®ru®ns®kt¬ip®os®gj·jcÈpXÍpS̀rVÈpSÇjWà”ṃ½‡öÎœøÔ¤öÑöÎöĐœöΙ÷Đ˜ơȒâ¢zÉnX =K†,K‡/M”<N DS™>Rœ?R EV¡BR¦FW®OZ¶U\´W\­LV@P@Pœ@R BT¥L\£J^ L\P 8\?z9[Zqs…²”·˜ ½¡¿œ·®{ fm€1I[ 6n<˜7LÉXXÚvlå„té’|ë~î|îŸ}î|훀í|î {ízésè„fâsgât`Ü¥Wy‡@`v8]K;M<UBR<VAXAZEƒFl\DUFSDZ*Q]F\EVIm(X—aŒ…FuUBl2Vi#NQ7O @RD‚Jnt4iQJUK}J~h$Yw@l~Bf$^~L}~Gxq:t`(an<qI€h™|@t”_˜k›d”{©´¹¬«LtN@HC‚Q`–^£tɬ´M=J 8H 6R :x(An&Dk@z)Dd=d>\>V>]A_Gt3Ts+J`B`Be(L^9p>t<†$@²DNÅTVÈUTµJK‚%>` 7j=‰0J£H[ĂTZÎUUÖY[ÙacØedƠadÖchÚ]`ÙdhÜegÜfiÚljÜlfÛmlÜlhƯmhÛjjÚllÜmkƯmlßvt̃xs̃|uà}và‚và„}à‡zà‰~âyă~â”ƒă”ƒă˜„ä™ˆäŸ‰ä¢‹ç¦åªŒè«ê±•ê²–́¶–î¹Ÿí¼ ̣¾¤ñÀ¦đª̣Æ°ñụ̊ʶö͸ơϼöÔĂơØĂïÖ¶½‘”\<X:d:r1Kb6q!?]>b@¾kk̀‚vÆmbÁwqÄ}tÄ‚{Ä€tÄ}tÄ}uĂ}vÂ|r¾uĂ€vÀ{t½xrÀ|x½wt½xu¼yyºvu½vv¹ux¸tu¶uy³qs²ps®lt¯no¯ls°ge¹eaÅlZÍoXÎvXĐv[Đw[ä¤ụÁơĐ›øÓ¡ơÎœøÏ›øĐö͘öË•ơÈ“́¼~Û”r´TN.D‹.H”6L›=N@Q”:N FT£FU¥DS­JU¶TYµRZ®JTBP<O>NBR¨GU¨JW¦M`ŸJ_N 5V8fGBak‚®œ¹£¾¢£Á¢¡º”–±†ˆ£ot6P[4d7“2FÄV[Úulå‚rè’ý›́~́€́›|í |́ €í{î™yítè†jàxfÔdb·Y\Ä“ ‘JYw0MG <R?VCSAXAZDo3[l)LWATAXFYJVBXB\Im)Y–g‹…K{PCg,Vp*RV?S@L @`LƒAns.fQDwDug#Zd*[†M€z>yw@s†Q‰…W‰Lˆj2lq=r‰\‘z>v™oœs£‰Xz¬°›¸§ˆ£ŒRz_"UD Cd&U£z®¨yˆØĂÂY@MEF?P<w*Cv&Cp>~/I`>b=_=Z=bB^Cq(Gx/L\BcF_C^:n?s=•2H¸LUÁRUÇSR±DJ"<^ 8d@4N¨K^ÊPTĐRT×][Úbb×^\ÖaeØahÛcgÚb`ÛdbƯgcÛjeÛmkÛigÜkh̃lhƯmiÚmlÜpr̃rl̃rqàvnàuqáyqà}ràuàˆ{à†zà€ââ}ă’„â˜„â›†äŸŒå è§ä¤æ¬ç³˜é²‘뵘́¸™î» đ¾¤ñª̣ị̀ůñÅ°ñ˸ó˸ôͺ÷̉ÀöÖÄơ×»äÊ´ˆE]X>b8j9a7n<W
-8f;ÅrpĐ€uĂk_ÄvpɃyÈtÆ~sÇ€sĂ}sÅ}rĂzo¿zpĂt¼zt¼wu½wv¼xvºwvºxv·uw»vuºvw¸ss¶tt´sv®os®ps®jm°gl±ed²a]Ăi\Ñ}fÚˆb̃–là t곈̣ÄöĐ ö̉öĐœøÑøĐœö̀–öÊ•ơƉé²|Đ}^¦DL‹/J•6Jœ;L >P˜9N™@T¦GR¦KZ®OW²RW²SX¬FR BP˜:N›8L =L£JY©IW¦J\ H\œLeJ5K 4^Bx6Y˜mƒ®Œ—ºŸ¤¼ £ÀŸ¼–¶ˆ¤ov8NU
-4\ 3,@Ă[XØrdâƒrè}ë{íŸýŸxê™{́™xîđ ~ñ{í’vë‡käxfƠdZ·P\̀“z2R^CLAVDT@R<[!N^!Jj&O]EU?WBZGVBT>TA[Go,W›m”~BrQCf'Pz8^^EN 9M <QF_K„Dq|;qt?qn.dZOq2dz@yw<w‚R‡\ŒŒ^~Ji0fzDyt:te’£y¨Ÿ‚µœuª‘ª’d…bCh)VRFr&Z³°¾‘¡ÖÄÂ` GI?G>P9€0Et!>w!>ƒ2GaAb@\BXA^D^ Gr)Ep"E\A_?_A_:l<p<:H´CJ¾INÀRS³AHŒ)?`>i=–:P­FRÊTWĐRT×\YØ``ÖXXØ^`ÚfeÚcbØ__Ư`^ßgfÛdfÛlkÜlfÜmjƯlhÜlfƯlh̃ts̃uqàyvƯxt̃unàztàuß~tâ„xà†yá‰{àâ㔅㗆♇äœä¢å£å¤åª’讔箘괕́º ́ºœï¾¤đ¿©đĂ®̣ƱñÈ´̣ȵô˸ôνö̉¿ơÔÂơÖ¾óØ·Ă•™[8\9f8^ 3a7R
-<t>Îzq̉ˆÁmgÄxmʃrÈ‚wÅ~rÈ|pÄ}pÆrÀ|qÀ{sĂ~s¾|x¼yw¼zw¾xwºyx¼us¶st·svºxu¶st´ss³ru«np«jn«hk°hg²_a¸hf̀xhÜqäuê«x́´̣ÁơÉ—÷Đœö̉ ø̉øĐ›øΖø̀–ôÆŒñ¿†álÄgP›:H—5L9N¢BP@R8O¦BQªHU­KW²QX·TW´NV§DN=O”8K›;M¡?N§JX¨KY¢LaJbL`L 6M<[Dq-T–ay®‹–¼Ÿ£¾£§À££À˜·Œ¦rtt(BP 4\9.@ÇWTÜtfâ„nçvê€í¢źŸź{́œ|í zđŸđ€í•têiæ{fƠc[ªKd¢Ub¨s‡TAM@YFUAR=ZCf(N_D^AYAYDUBUGYESCUK|<j ¢w;hQA]C|=^\CM:R?[LVJd&Vz>i‚Ftv:nYJr5mf-\Hƒ}Fx\Œ‚R‚~J}r9pvC{s6q…T…¦‡®¨´£~­¨Œ©¢„¨^KRCz8meR­†¦È¨¶̀µ¸T:I ;B ;N <.DnBw&BAT\?c>[@[>`@b@q&Ai!B[A]@c#FfBp@~(D¤AN¾NN½JL¶>G²DH–0Ag7o;—<N¬HTËTXÑVYÚ]\×`]×XZ×[^ÚbdÚecÚedƯgdÜhdÜfdÛjkÛibÛigƯldÛlhÜnkƯsr̃vqàsmßph̃xràwq̃zqáuà€x̃„wàˆ|áˆ{áŒâ’ƒä˜ä˜‡äœ‰äŸå‰ä©’æ©æ°–毕貕꺠́»Ÿî¾¥đªïÄ®̣ƱñDẓÍ·̣˹̣̀ºôĐÁöÔĂôÖÄöØÀäʵ„<UY 8`9W
-4_4K4?Ñ€tÖ†s¿lhÇ|rÊ„rƃtÆrÉ€vÅ}sÄtÂzvÄ~uÂ}w¾}u¾xs¿xv¼vrºwtºro¹rr¹rs¸st±tx´pt²ru®lo¬fj¬hk²b^ºb`Ísh̃tê¢zí³„đ¸†ñ½óÅ÷̀™÷̉øÓŸø̉œ÷ÑœùΘơÈ•ôÆë³~×a³ML›:Kœ=L¢>M¦BP=P¡AN­GU¬IR²MT´SX´OTªJQœCT–=N˜>N?O§EO¨LW¥JWF]™K`NbH
-6R@XBl(RYtª‡“º› Â£¤Â¤£½œ˜·Ÿipo+HN :]9“2DÄWWÚteà‚së‘x́|đ¡€́ |́Ÿ{îŸ}î¡zđ ‚îŸv́–uë‹kå|hØha¸e~¬_p«hjPHWLZHRDUE`&N`"IXE_EXBX@VCZH[BRKXRW„¤¢x8cNAQ>}8\j(NN 9bKaMUA`(P\K[Eb%SVIu;mf&\{H}‚E~ƒR„~J|xE|n4kwB{r:uˆV£|¤¥²w¡£‚¡¨Ÿx>qK?_J^P¦~™Æ³½¶•ŸJ?K=KDTA‰8Jv&Fu$C’CU_EgA\D^HaAcDt(FfEY<Z<_>i;r=1H°FL»HK­?HºHN¾PS›0@f:l>>O¨CRÊPVƠ[[ØaaØ_[Ù]^×\`ÛcdÜhbÚgd̃hd̃idÛfbÜf`ÜhaÜjdÜkeÜmgÛolÜliƯpñtnƯpl̃soßyrà~sà‚tà€x߃xá„zà†{á€â€â–‡â–‚âŒâă¡å«“媓媒殕籖궛뻠ᆭđÁ«ñĂ­̣Ç°đŲñ̀º̣ʸđ̀»óϽởÂơÔÆøÖẠ́×·¼…Z
-4\ 4S.\
-3O6ˆ.EĐ{lׄrÁqnÅ~vÈ‚sÈ‚tÆ„uÆ„uÄ|rÅ~pÈ€tÂ~rĂ{tÂ|r¾|x¾|r»utºyv¸ts¶ts¶tt¸tr²tr°np²nj¬lm®gi°ffµd^ÆofÜqé§̣µ‡ô¼‡ơ½‡öÁ’øÈ“ùĐœøÓ¢ù̉Ÿø̉øÑ›ùÍ–öÈŒñ½‚ä¢oÊjR§@J8M >M¡?LŸ<M AM©ER­LV°LU¶RVºUV²LU¦DN™>P™;M>P¢DT¨GR¨M[¡HVCZ›NbœPdI2L
-5V@j,WVo«‚¶”À ¥Ä£¢¼œœ°‡ kpt-HL5[
-4’+@ĂXUØr_å„qê“ú|ízêzë}îœ{í¡xï¤}ñ €í–yêˆlåyhÛg^Ø”“¯epz?]NEa GR?Q@a#Od%QZDX:`BU>T>[F\DUBRIa%Zsœu˜v2XL>O=l+Mm(OR<i)Qf#KUDb.XWLO?ZO\Ph.[r4jj8j‚N†R‚‹^’|L~s?um4rg2nˆZ‘¢~¥y©^‘¬²Ÿt–_†YGNFZNŸw¿°»†VhREI
-;I<]>:Hr Bz'C†5I`<j D^A`<a@e>p*Hf(K[B\<b:n?u:–:H­>F²@J¼GPÈZZÅST6Fg<o;™BU¬HVÊRTØ]^Ø`_×\\Ú]\Ú``ÜhdÜfdÜdbàhdƯheÛhdÛb^ÜfaÛhbƯibÚieƯjgÜmjÜtpßqkƯrõtl̃xrß{qà}tà~wà‚zà‚wâ‹}àˆâá“à—„ă—…ăœŒå¡‹ä¢ä¨–殗宗泖鵜깢Eđ¾ªï«̣Å®đIJđɸñ̀¹đ̀¼ñͼ̣ĐÀóÓÂ÷ÖĂöØ»àÀ®u @X:P2X 4N8”?OÏzgÑ|lÄysÅsŃuÅrÄpƃxÄqÄ€pÄ~pÅ~pÀyoÀxt¹|x¼xt»xv¸tr³no¶pq·roµqs¯ru¯np®lqªhj¬ef®ef¹baÔ€q殃̣¾öÅ•ôÄ“ö¾‹÷ÂöÈø̉ŸöƠ¤÷̉ ø̉úÑ›úÍ”öǺ±sÚ‹a¼VN¡<N¢<J >K£;IŸ:K§DN®JW°MV´RV¹UX¸UW«HS?N—@Sœ:MœAR¥JS¨IR¦JXH\I_SgQeI1K3O
-7bJRmª‚³¼¤Á¢¡¾Ÿœ±ˆŸmqv0JQ2^7)>ÁTTÚrbå„lé‘vëœ{́¢xí|́ {êxí ï£|đŸzî—t́hæzcƯf]؈¤^jn9ZN?bJTC]Gh)O^DWAV@Z?XBT<_IM 9L @NIyJ‡p–œju.ZNCQBYDa$LT>r4\cJYJZJ[$PTCXKWHZLt3ji0bw=v„Q„c’~H{l6ik4n`%f‡Sƒª³—n•j›¦²’m”|¤“_’j)hd TªŒ¬««v;`’s¡J=H <b@Œ7It$F|,H~*DaAg>c=d?b>bBg?bG^$J_De>t"@"<™5GÀFNÄNQÊWZ̀WVÇSR 8He 8w"BŸ?N´JÙOPØ]\Ø`dÚ`cÛaaÛ`]ÜgdƯdeÜc`ƯhdƯedƯfeßd_ÜeeÛeb̃fcÚfd̃lfÛsqÛrjƯrmÜtnƯrjƯwõ{rß|tƯ}vß‚xáƒwá‡}â{ăà‚à“†â˜‡âœˆåŒä ä¤æ­•å­˜æ±—ê·ê¸ î»¦îÀ­đÄ®̣űđɲđÈ·ñȶîͼđ;̣ÑÁôĐÁöƠÄ÷Ö¾îƠµ¥fpP 6N5U3P5§LX̉wdĐvnÈ{qÄpÆ‚uÇ€tÄtÁxÄtÁ~tÄpÄ|p¿|vÀ|qºtq½zr¼wr¸tn¶tr¸qn´rp±or­ln­kp®moªln°kl°`bĂjbá}ñ¾’÷̀œøÏ ÷̀öÄ“öÄ‹ơÉ”øĐöÔ ùÔù̉Ÿ÷Ϙ÷Ệ½€çŸjÏsX¬JI¡<I¢>J¡=L >M¡?O®DN°GPºSV¹TW¼TX·TZ¥ES=P˜:N>N ER©NX¦MX L[J`HZ™Mb•H^G0I 2L6^D„Jl¦{³‘¼ ¢Å£¤ÂŸœ¸Œ¤rvx1KP0\ 6†&?¾VWÛr\å†ṕ”v́{ï {ë}́ {́~î¤xï¦ẓwî’q́‰dçyaÛh\Î}u’HdR>PAdH\Id"N]BZAV:W<X?W@ZBXAJ =J D`*`œz§›f‡—f„q0XL>NAR=` H\Dr-S^AbJS=ZJVCa"QWHTHl,\b)Wj4ju@o˜pˆZˆ^ R^![a&e…X‹¤ˆ®z©¦„©¨­B|€Ll¢~¥I~™k¤¶¤Â¡w« |¥À±»\GK?d>„,Dk?x(Cr"Dj Bg@j"Di@`?c>h@b@^DdGhAu?’0E±GTÊRS̀XZÍY\ÎZWÆTR¢:Hg9~,G›<L³LTĐRTÖ`]Ø`_Ø`bÛhfÙdaØgĩe_Üfdàe`̃d`ÛcbÜhfÛhfÜf`Ûf_Üh`ÛnhÜomÜpjÜqm̃phƯtñslàym̃{tà}uƯ€vàƒ{à‹}áˆ{áà€á€ä™…â‰ăœˆâ¢ä¥‘æ­‘æ¬—å±–êµœé¶ í¼¥î«đªđűđÉ´đȵñʶđͼ̣ͽñÎÀóοơÓĂø×Ăôض̀œ”T
-2D-M2R 3´Y\ÎreĐ{jÄzpÆ|ÈsÆ‚uÄ~vÂ~tÁ~tÁztĂtÄ{u¾{q¿yu½vq¾wo¹xtºxr¹sp¶qn´rt´qr®kn®jm­mu«ik¬ei´aeÊp`ê°ˆ̣Éœø̉¥øÔ¦ùĐøÈ•öÈ”÷̀™ú̉œøƠ¦ùÔ¢ùÓœøĐ–öÆí²tß`Â\O«BIªAJ¦;F :H 8H¥<L¬EP´KS·PU¼QSºRW­JTŸCS›<O˜9O AO¦JV¥KZ¨O]J^›Lb™Mb˜PcDZG 4I3N7[B‚@b¢t‡´”¾¡£Å¤¢ÁŸ¶¥tx9MT 2[ 3Œ"<ÀVXÜoYä†të’uî ~î¡{́Ÿź|î¢~î¡{ï¤zđ xî˜q́hå|eÚh^ÊrlF_VF\Je"Lf$N`HR :YBS;[<X>XAYBO@MEd&X_’Z‚‚Fg…IlbINAM?QD[Fj)Pp,TU9b HO 8O=VEh*T`"PP>k/^d&V]&\`$[‹d’g”g(df.htE‡‹c– z¦Ÿ{¦§‰²®’³ z¦ˆDq¦r—x5h¦ˆ²®•±lˆ’qz†_jQ@V>n"@}(Da?r!Bm!As'DeBf!Bl!Bd@h"Dd<c=`?f@z&F(F¡:HÄTRËSXÏZZÍZ\ÎWVÅTV›-Dk;†6LŸ@O¶LVÑTV×WR×][Ú]`ÜdcÚhdÛgaƯefƯic̃fb̃f`Üd^̃d\ÜecÜgbÜhdÜidƯhd̃ljÜlh̃njÜrkƯrp̃xt̃võzsà€xà‚{á…zàƒx̃‹}àˆ߀â„ă˜‡ăœä—‰ä¡ä¦äªå­˜æ¯ç´œç¶¡ë¹¥î¾ªí¾¬đƳïIJđǵđȶđ̀¼ñ̀½đÎÀñÏĂöÑÀ÷ÔÄöÙºăÄ°r)EE9H4X 6¼_[ÍndÎwkĂxs̀{Ä}pÆ‚y€sĂrÂzpĂ|pĂ{sÁ}u¼xtÁzr¾wp¼zs¼vp¹xs´ql²on¶sn´pn­mo¬kn­gh«de¯bd¶^_Ñ}iôÍ øÖ¨øÔ¦ùÎùÊ”ö̀™÷ΛøÓŸ÷Ô¤ùÔùÑø̀ơ¿‚è nÖvU¼NI­DL°?F¤=H¡:H 7F§AN«DO´NV¶TWºTU²MT¦BP @R›>Nœ>R¡FQ¥NZ¥L\¡L\Ma˜Pf˜K_“J\‡:RH.J4M
-:\CDc t„´’›Á¢¤Æ¨¤Â¡œµ‘¥xy‡BTU 4\
-4†#;¾QRÜp_älë”vî›yí{íŸ|îœ~îŸ|î¡î¡xđ ~́˜nëjå}iÙjfĂbbŒCdbOh%Rj&RZEXGS>X>X@Z<[>Y@VDRH^L’d‹|Fj^LƒNz~Bdg.XTEPCSF\!Kv4]k&LR8`GR<Q:[De(P`#RK
-=a)Rl.`a [j:p‡cœŒZ[’~L†T‘f–¡x¢¢|¡¤z‚Knœw ¤z¦¨²²´Ç®¶¡}[BG9K6f&Kk"@y(Bs @]@u"Bj>n$Bb?f Bf?a?l$Ad@b@bAoA€(B-F­DKÎWS̉ZX̉[Z̀XZ̀TTÀLO&>g:‹<P >M¸KTÓXVÖXVØ\]Ú`_Úb[ÚebÜgd̃j`ßf^àgd̃h^ÜgcÜf_ÚheÚjgƯjdƯjhÜhcƯnl̃phßpjƯrlÜpjÜvpÜxñvmà~rà~uàwß…à„|á‰~âŒâŒ€â‘„ăŒä‹ă¡Œă¤å¦‘䮘æ²æµ˜è¸£ëº¦ë½©íÀ®ïƱîÄ´ïÆ´đÇ·ïʺđÉ»ï̀¼ñÏÀôοởÂöƠ¿ïĐ²YhA1H5a:ÀlgÎl]ËzjÄytÈ|ÄrÂ|rÂ~rÀ~vÀ~sÀ~t¿|tÀ{r¸xu»xvºxt»yrºzv¹us·wr²rs±rr²qq¯mm¬jm¬fg®fe²`a»b`ÖŒrñ¾ŒơÎ÷Ơ¦ù̉öÍ’öÈ“÷É‘øÏ÷Ô¢÷Ô¥øÑøΗöÇ‹ï²zá_̀iT¹NP´IM°HO­BN¦@J¨?Jª@K°GP»RR½XT´MR®IU¢CR=N<O CS§KZ¦O]¤N\L_˜IZ–DZ”E[ˆ<Qˆ=XF0J6H5[A|Ddvˆ°˜¼Ÿ¢Â¥¥ÀŸ¶¦yy‰JY]8\ 3…$?¸PTÜqdæ„pê“v́Ÿx́œ{́œzëxêsèwëxîwè‘vä‡rà~rÖplºZm”Lsl'Xg%Ne"PTAS?T>Y@W<X=Z>WGZLi*Zn2[j.PQHYJ”b†~<bn2XVBTARB`!Lw7[h#JT@XAU@P@YDf&Rf(WL A_(QAq_OTIf/`n4f‰]”k•s©–jœrŸ¦‡¨—i|6p‚Krm›v¢²‘´º•«¦€¨†YŒ^&Z`'IBXX<x,BjBdBz&DfAn$Dk"Dk$BeCd<o"B`=c<e<}!@‡)@–4G¹GMÍXSÑ\ZÏZXÎXZÍ[[ÂPN…!<h8;N¢@QºKSÓZXØ_`Ú`\ÚbbÚ^\ÚdgÜgf̃faßlfàkfßebÜdcßf`ÜfcÛe`ÜffÜhcÜieƯidÜjf̃jbÛliÚpm̃upÜumƯtlß|tß~và‚zßy߆~áˆ~àŒ€â‘„á”„ä•ˆä›âä å¦”䭘江ç²ç¶êº¥ëº¨ëÀ¬îIJî²îÅ´đƶđʹñ˽đ̀ºñÍẠ̀ϽôÑĂöÓ¾ô×µÇG0D5g9ĂigĐn^ÊwkÅ|vÈ„wƃv¾|vÀ~tÄ~p¾~t¾{p¼{s¾xm¼yv¾znºwp½zs¹xt·xr¶tq´st²st±pp¬ovªjl®lo¯fe´c`¾jhÛ’wñÀ÷Đœ÷̉ øÍ“öÆŒ÷Æö˘øĐŸúƠ¦øÔ¢ù̉øÍ’óÁê¢nØy[ÄaT¼RR·KL³EJ®GOªAIªCL«BM°HP»PQ¼RU¶QU­IR¢DRœ>O@P BR¥JX¥LZ¡L]J^–JZ•CV‘@Tˆ9R„5RH3F0L4W?w@b tˆ¯¼¡Â¤¢¾  ¸”§z|Uac:^2„ =·NPÛodæ‚në’ví›|뜀痂æ˜~ä˜|ß”}â—‚åä’{à…uƯ|r̉ki¸fy§kk(UXFYJTCVDW@X>W@`HZFWHm3\€Fp]EUFTGbM…Ai~<d~>bVCWHTDc*Pd"Kf(QXCU>VFTC]Jj1ZXFZQi+V}Bpe%VTFUJZXm:njœœ®p”d“Ÿ~¦–l—ŒU~}>hs:_zQp’s•’b°Ÿ¾˜«£x¡ªv “Rz>nGfo&Hf Cj Bk F}0L‚9Pm>e@hAi>d;`<f<†(AŒ)@Ÿ5DÀIK̀ZXÏZ[ĐYYĐW\ÏZX¾NR?j<•<N¨GTĂRRÖWR×[WÙb^Ùb]Ú_\ÚefÚjiàidßojájbƯhd̃e`̃jcÛbYÜ`]Üb]ÜfbƯg`ÜjbÛlf̃ndÜpgÛmh̃qj̃ulßvr̃yp̃}uàxàƒx̃ˆ~à†ỹ†zâ~áâ•„à”‡á–⢌䪒䫓峘沘糟꺤꽫êÀ­í³î²îųđƸđÉ·đ̀º̣˺̣Ï¿̣;óÏĂö̉ÀöÔ¸Û¸©`<D6w:Æh^Îs`ÇzpÂ|sÆ„vĉ{¿|t½ztÁ|pÀ|t¼yo¿yr»zpºzt¸vt½xn¼wr¹wp¸zs¶ur´ts³ut¯lqªoq¬kp®gg°fe¹c_Æmcà–ẓĂöĐ÷Óœ÷Ê–ơÄöÄ÷Ê”ùÑ›ùÔ¦øÔ ùĐ˜öƈđ¶yâŒ^ÎhUÂZTÄXTºLN²GOª=G¬AI§CMªIT¬FL¶PV·QR±PT¨DO>Nœ;K>NŸHV¨MY¡I[¢Pc™EZ”JZ’BZŒ<T‰>Y…6RF/D2J:U>v9^j}²—À¡Ă¤¤À¡º•¬~~U]]7[ 0‚#<·JNÚl]çƒlí’wîœ{ï~êœ|æ›~曀ă堆蜀è“qè†nâygƠlmÆr„®bl&Rd&MRBVBX?W@X>T<`B]DXBe*Ma#GUA]HZKYH‚Bk}?dv2W^HRD_#Lc&OWC`$J^EYHZEZHZGd*S^R^P|Bk}@qYJTHF BQNi5nf˜£„¬“f•™r§˜q˜pœ†Fl†JuM
-7O :i0Kp1XX:h#A†?QŒG[†Rp o“¦l\Œ¢sŸ˜_‰”Y{†>Vj@n @c>c;k>a;e>o>†(B™4I¨@NÇOQĐ\ZÏWỶ[\̉]b̉XV¶HM%FtA›?P«HTÆTZ×[V×]^Úc`Úd`Ûa`ÛabÜfẽic̃ljàjeƯhbƯidßgcÛdaÛc_Üb\Úc]ßf_̃jeÛhẽohƯneÜmf̃njßwr̃zsàym̃~yà~và}xß„y߇{߆~⌀⒂┇ăˆà˜ˆá¡ă¨ä©”å­˜æ°æ³ é¸¦è»¨ê¼«́À¯íĂ²î±đÄ´đƶñÊ·đ˼ñνđÍ¿ñĐÀơÑ¿ö̉ºè̀¯‡=WF:*DÇh]̀tgÄ|sÀ{sÄ€rÄ|Ä~sÀ~v¾|r»{x½~t¿}tºws½xo¸wr½xs½xr»yr»zr·xt²sr¶ts®mn¬jnªgh­ge´hdºgdËnbå¡|ơÄ“öϘøÑ÷ÈöÉöÄöÊ“ø̉øƠ¦ú̉¢ùÎ’ôˆé¥jÙyYÇ]TÄTPÅXV¹KN²JP¯BL¬CM§?K±DN³JNµPS²NR¬DL >O<K9HBQ¢KY¤N\ L^FY˜DX˜F[‘<S>WD[‰AXJ 4H2G6R>n1U–dx°•»Ă¥¥Ä¢Ÿ¿œ™®„„ŒS`c8\9‚"@¹NQÛk]æ…kê’ý{ï›ýý{럀́|í¡|îœzë•tèŒkäzfƠwuÆm~˜Fjd"ObFXG[DW@] FX>ZA^BY>U@YBVD] Jc#LXEXFw7\r5^j)PbFYGg*S[HUC`$Gc"H[BY>S@Q@d&R^ RXH†Ott8fL<e,eLE\ Zo4s‡Z‡–lœ}Jvœ‚ª…P‡bœlœY~r0cN =`=|FmP>W<x1DI 8N;w/Ir/Jl%Kcf–[o‘JaOsy/Qk Bd=f!FhA^=f=}'C.E6E´CLÎUTÏXZĐZ^Đ`bÎ_cÑ\^­;ItB~(E@R¯ESÎX\Øa`Ù]\Ûb\ØdfÚcbÚgfÜjf̃ig̃kdßggßgb̃d`̃jfÜfcÚbZÛc^Ûc]Üe`ÚgbÛgfƯkeÜohÛplƯohßsñtnƯzrÜzṽzwà‚yà„vß‚xß„yáˆ{à€à“‚ă‘…á™à â¢Œă¤äª˜ç²›æ´¢è¶ èº¨é»«́¿¯í³î¶đĶđÆ´ñȹđɼï̀¾ñÍ¿̣̀¾óĐ¿ơĐ»ñ̉®´pzF5‘8JÉi\ÍvbĂ|r¾|rĂƒqÆ‚s„xÀ|pÀ~rÂ{u½|u»zt¹xnºwrºzo¸xr¼xo»yt¸xt¶wt¶vrµur³rqªloªnm®lm²ki¼hb̀n`䤂ôÁ‹÷͘ø̉öÈöÁ†öÄöÊ—øÖ£úÖ¤ùÑ™øÈñ¹|ä•bÔlUÆVSÀPRÀVX¸KP°HN¯HM£=HªCM±GL¶HJ¶KN­FP¥BL8I˜8Fœ9J¤FS¦LZ¤N^O_–>T”CX”FY=RAYA[B]I5H2I
-8R?f%L’_uªˆ“¹Â¤£Ă¤Ÿ»œ”«…†Ubf<_4‚%BºLPØl`ănë’ẃ˜zî|í́v́ |́¡zí¢}íŸxë–qç‹oâzbÓoqÀsƒ—EhbH[A[@d"LZ=V@W=X>\HZCUBYH^"Le(PZFTFc Nq2Yj.Uc!KYD^"L\FXGXGg+Nh-TX@S;N=T>g%SOD\NƒPvr9kMJX$Pv@k,dt@zƒLh‡[”dl …Q‹˜n›t–f“\E];„TvR7g>b;H?]@w,HfCYDp1Ja"Ht$GŒ?Mœ]fo&Hh>b;`<_>o@†*A–5F¢<J¼IMÍVX̀XYÎ\`Đ^aĐ`bÎ^[ <In?4M¥FU´MUÔ``Ùb]Ú`[ÚbcÛcbÜggÜggÛlhßhd̃gb̃hdßlh̃jdƯifÜcaÛdbÜdaÜd`ÜfdÛkeÛieÛlhÛigÜlißmjƯrkÜupÜtqƯxsß|t̃„{̃„{Ư„zƯ‡{̃‹}à~á‘„â“á†à™ˆâˆä¦’嬓粕ä³ç¶Ÿè¸¦èºªê¾®́À³ïÆ·ïÅ´îÆ·ïȶđɺđ̀½ñ̀»ñ̀¿̣̀¼ơĐ¾ó̉²Đ M 6>LÇbWÍxgÄ|uÁ€vÄ‚w‚sÁƒ{¼zwÂ|t¿zvÂ~tÀzsºxo»xrºzrºwq¹ytºwu¹xt·xu´vr²rr°oo­no­kl±lm¸lgÀeX̀obà˜ṣ¹„öÈ’øÍ÷ÇöÀ…øÉ÷̀—ùÔ¢ûÔ ùÏ•ơĈî²x܆bĐ\NÅWVÀTQ¼RS¸OU¶HN¬DN¢>J¦:G¬EP®EM°IP¤?L—6J8L˜<J¢CP©HU¨OZ¢M`›J^–BV˜I_”DW@XAXF^“H`P9L9L ;T>f$K[sª„‘µ’˜À ¤À¢œ¶”¬†ƒ”Ydf<^:…'F¶LQØk`ăhê’tësëzë ýŸý|́ xíŸzî ý™tê‹sàxeÖy|Äv†¦KkgHbEZAdHU=WBS@V@^HUAVFd$Pq/Vg)PVCXKXGj*Wd(Lf(Ng&M^ LR?UDTD]Hu<aUAQ=RB]Fa"NMBl2gt:jk5^s>yTPs@q|Bu?kL|}JvŒg”‰`”„X}Iz‡Zœt¦€¢„Hy[>‡Y|T9d=P<Q>p&Bp<e%H[>u)Dh@m ?a?|-@r&D^@^;[9b:z$AŒ2Cœ6F¯BNÂJOÍVVĐ[ZĐ\^ÎbdÏ_]ÄTV”/DjB“:L¨LZ¼RXÖ_^Ø`aØ`^ÛggÜhf̃hfƯheƯfd̃leßlfàlhàngßmd̃hfÛfcÛdZÛfdÚc^ÛgdƯhbÜjbƯh_ÜmbÜndƯpf̃pmÜsnƯvr̃xoß}ũ~w̃€xà‚ỹ‡̃‹à}áâ‘‚à“€ß‡âä¦ä¨‘å­’äµè´¢è·¥é»ª́¼­ê¾­î´îĂ²íŵđÆ´ïȺïÊ¿̣ͼ̣Í¿đ̀ÀôξóжßÀ¬o E BLÉfZ̀xiÆxÀ€vÂ…|¿‚yÀ€t¾}wÀ|pÀ|t½|vÂ~vºzr½{t½{v»xt»zv¼zx¸xqµwu²tr³sq®nm«mp°pp¶rn»leÄl]Êl`Ú†dê¨xñ¾ƒöÀ‚ö¿„ơ¿€öĂŒøÎúÖ¤úÔöΕóˆë¨mÚ|XÊWSÂTRÂQT½NR´JN³LV§DM @M¤>J¬DL®JP <H•2E‘.B9M¡IW©KX¦L^ GXJ\•BV”BZ—F\”E[•C\@Y‘Ea“H_L
-4L
-5K 8Q >b L‹Ul§Œµ”˜¾£ ½¡¹˜•¬‡†–_jm$Cd<„#B¶HNØj^âiéuê˜x́Ÿyëx́œź{ê|́Ÿzíœý—rè‰gàtfÛ€}Đz„´`ufEo&PV>`FQ>R>P ;VG]HUIu7b…@ek'L^CTBTDZIh*Sb#Md$Kb#G[F^JZFVJSGd)O`PO<UA^I^$TPF~Huj+``&V}Myn2jQFyT„NyM‡zH‰‹lœ–u¢ˆb“u<nd&]{Fq˜j }§}8bKp\ CdHL <T?r$@j @`;`;o$Dr(Dg>^>d>i#C_?]<^8j:€$=‘3G¤8H»HNÀJRÉW]ÍVVÍ^_Î^`Î]\¹NS#CnD™:N©IVÄUWÖ`]Øc`ÚbãjgÜkh̃ifÜjiƯgißkeƯjgákfßkg̃hb̃iiÚecÜfbÜgfÙedÛfbƯkẽg\̃f`ƯibÜlb̃lg̃tõtl̃upÛuoàwqà€tßtà‚ũƒzà‰~ß‚à~â€ß‚à–†â›†â¥ä¦ä­”æ°æ¶¢æµ¢æ¼ªê½¬é½­́Á®î³îÆ´ïŲđȸîɼñ̀¼ïʾđ̀¾̣̀½̣Ϻ́̀®VjªGOÍj]ÊzfÀ|t¾xmÀ„x¾z¼|x¼~t¿}w¿~t¼}y¾zuÀ€s¾~w¼|u¼|t½{u»zvºyt¶zv³vu³vt²rr®np´rl¶nm¿peÉo`Ëm\ĐsZ܇`è¤nê­rí®vî¶xơĂøÏúÖ¢ù̉÷Ê‹ôÀ‚è i×rUÆTR¾PR¿LO»LO´FO®DK¦<I¢<J¥AN«HPªAJ˜6H&@1FŸBR§LYªLY£HUŸJX™BT@S“BV–BW”BX”D[‘Ha‘JaCXR<R>N:M 9[F„Jf¥}ˆ´”½¡¤À¢¼—®……dlx0Jj>ˆ)DµFN×i_ă|dëú}íźœzí~é|êŸ{́ }î|́”qê‰káxhØvvÚ‡„±WmkFˆ>d\BZAL>NBN@_Im&R~=ey:]c!CX>TAPDTGb(Tk(Qf*S^FYFVHh&R_$LZ#PRJZ$It8hRBbLXG`(\e.\m2[b%Wd$Zs:b‚R‚LLII‡pœœ–Èb’—|±‡d’ˆ^ˆL~i.gd+dŒd’f”˜n “_zFp˜}¤N <[Dn AeD\Dh Bj Ap"B`>b@`>c>_>Z8a:p >‹1B–5D¨;E¿LPÅPTÊVX̀[^Đ\ZÏZXÊVW®DNnC~,JBTªLX̀\^Ø^]ØffÚgfßhf̃kĩjgƯhfƯmĩqpßifág`ßgb̃f^ßgaßf^ÜhdÜc`ÛibÚfaÙe`̃e]Ưf\Ưjd̃ld̃nhƯpj̃up̃vp̃{ußzs̃}r̃|tà‚xàƒxƯ†zàˆ|à‹~ጀâ’ᘄ☄âă¢ä¬’䫖洠泠纩黨輮ëÀ±ïĂ³îÄ·đĵđʸđɼ̣˺đ̀½đË»̣̀¿ñλđΰ̀Œ‘¸LNĐpcÊxf¹tj¬he¸rp¼wn¼wr¼zu¾{u¾~z¾w‚tÀ~x¼zº|x¼|t½|w»{vº|v´yw´wt´us°op±sqºrm¼tpÄthÈtf̀r\Ît_Ît\ÖZ̃bà“fê­zöÆ÷ÑùØ¢úĐ—÷Ẹ́»}è—`̉iVÆRP¾MN¸KQ´EM¯DM§>L9L£ALªHT¦@N>M’1G.H”9N¤GTªT\¨LXŸHVGY”?S;T‘AS”F[”H\”BZ”H[H^†8OR:M 7M 9J
-9WB~Dduƒ°’˜ºŸ¾¢¼›–®‰‰nu~:Pn?†&C²FLÖi\â€hé{ë˜tîœízê›}ézé{́~îx́”pçˆnßxfÖprÜ‚²Zrs&MŒBb^JXCO?OD^ Nw8^{;^h$K[HSBSBTARDVHj-Zd Om-X^I\I`$Nk)Tm,Uc)RWIPCk,W`$N\HQJd*V‚R‚^GUD]Mc$R‚Zm4fOMS IoBdq?oˆbˆh–‹e“p8d\R]TxK|g£©Œµ¡v­¤±ŒfN:^@k@^=T<n?c=d=]8b<`=[8]=_:f:z >,D¢>H¶FPÄORÉTVÎVẀ^^ÎYX̀Y\ÄTZ—3Gh?Œ4J¤BQ½U\Ô]\ØadÙedÚfeÛgiƯnj̃mh̃jkßleàqmâmhàld̃haƯjf̃iẽh_ÚhdÜc^ÙfdÚd\̃daƯf_Üd[ƯmeÜpj̃lk̃pkƯsl̃siÜwñxlƯ|sß}tà}sßũ„{̃„vß‹|߉zß‚ß–‚àœˆá‰â¨ă©ä¬”è°ç´¤è¸¦é»¨è¼®ê¾±î±îÅ·đƸđɺđ̀¿ñʼđ̀¼ïʼ̣̀¼ñ̀¿̣ϸ䶫ÂWX̉w^Åxa°e`¢Z[©cf«ff®ij´nj¹pk¸snÀxs¿~t¾~wÀy¿€w¹}wºxº~uº~v¸|y´{u·zt´tr¶ztÀsnÅxoÈxnÎykÏvfĐt\Éq^ÊiRÎsZÙ„dë®xøÈúÖ¢ûןû̉“øƉđ³qâ\ÎaRÁPPºNPµJO°>H¦BP¡9LŸ<N§BP©@L¢=L•4GŒ,D6J?R¨LX¨PX¥HZCV”AV>R>V@T•EX“F]’DY“Nb‰@R0JN:M 6L
-5NAR@zA`x†°¸œœµ·™–¬ˆ†lr€;Pn>†&>µBJÖfYâ{bè‹të–v́zë›vêœwêẃ{́Ÿxíœ~ë–xèsâ{jÓfeÚ†z´ats'K‰?`b I[CUBUC\C`E_CWEWEXEV@ZHTF\ Jd"Nk+Xj+P_ LYIh,Ue#P_Ic"Ld!La!Ij*N]APCLDk6]}Fq\FPEYNl0c‡`Bzi/bUKWKVKWNtHr–}¡„X„[K\Rn0lrBs˜o—¶¥¼¨˜§_$JY<d<j?V>X;r!>e!C`>]<b<]8Z9`;e8j:ƒ(A‘.C§>J¿LPÂOTÊPRÍXXÎ^`ËYYÍXVºIM}@lD˜=R¨EQËZZØ_XÜdbÚbbÛgh̃hgÜgf̃jfßkhàidápkàsnálfàhh̃hdâkbßldßlaÜhbÛfcÜdãgc̃kbƯfaÜlhÛmfÜllÜphÜsõwq̃wm̃xpƯys̃{oß|rßuƯ‚wƯ…{Ư‡~ß|àƒâ“€à›„áˆâ¢‰â¦ă¨ä°œæ´ å¸¤è¸¦è½ªê¿­îÀ±îĶđȸđȺđȼđÉ»đ̀½đ;ñ̀¾đ̀¾̣ϺïÊ·̉spÓv^¾iX¢OR–DQŸTZOU¡Y^¢\_ªfj®gf´nl¶qt»xu¾zv½|s¾{»z»€x¸|y¸}z¶|tµyu¸vs¼wpÄ|uÉ~r̀oĐ}hĐwfĐt^ÊtdÅk\ËviÖ†ḱ·„ø̀–úÙ£ûÖûÏöǼ¦gÜ|ZÉ[NÄNL¹MP²HN«DP¤<L7L¤@NªFR£AO•1F1F1G˜<M CT¨LZ£IX H\™FV“A[<R‘@W”CZ–H[’DXDYCW„9Nv'?P:N6J5L;TA‚Fd¡x‡­•¶˜¸œ£º™—®ˆns€<Ps#@†&@±BJƠdXß{iè‹pê–v́›zêx́œzëx́yíŸ{îœyë•t́nå|bÔd_Đtr®_vx,N5Xl%PZCS@R=X@]B[CZDVDT?TD[JXEk,X_Jl)S[L\!P`'Pz>ag*PRCYE\@c#I]AS@OAP?wBjb J`IUJXNx@ui˜g—i0^o6jZHX HLFSO‚`z•mœ[P\"RJ~€Gxr4^˜wˆVuO 9a=j>e>R7]8h<a:^8^;]5X8Y8e9g;o>‰*?˜6D±FKÂKNÅPTÊRRÊUX̀\^ËY[ÉXX£9LiIx&F<L¼PVÓ`\Øa[ÚgcØfaÚigÜgfƯiiƯif̃hdßmhàniáncàpjájdàjbâlbàldàkbßjd̃e\Üg`ÜhbÜg^ƯldƯhaÛoĩojƯoj̃qjßxmÜvrßvjßypß{qà~uƯ|q̃‚wà‡zàˆ}àŒzá}ߔᘄᘇâ‡â¤äª’æ®å²æ¶¡è¸¦è¼¬êÀ®́Á±́´ïÅ·đȼîÈ»̣ʼñÊ»đͼñ̀¼ñ˽óϾóÑ´Ư—ÊlX§LN”@J†4H˜HS‘;F–DI˜KROT¤Y]©`d«ef®jh²ll·vv³trºyv·xs¶xt¶zx·~z¸|wºzrÁvmÆ{o΄t̉„jÔ}gÑx_ĐvYËq[Éo\Đt]Ưmñ¾øÎúØ¢üƠ™û̀‰ó¼|ç˜^ÖmTÅRL½KMµEN¨>Hœ:J6I<J©BL¦CN—8MŒ,B-F–9MŸFX¤L]¢JY CT›DT–CW:P’@W–EW›Lb˜J]‘DVF\†:R},Em>N 5L 2M
-8M :WB|<]k|®Œ–¼ ¡Å¦¢Á¢µ– qt€:Or$@ˆ(@´?G̉e\ß|fçrê˜zê–x́œzêœx́œ{ë~́¡zï ý–wëmè~bÖf]Èbd¤Vn~4V„>^p(PT>N?SA]Fa"IYDYGXCTBTC]Ja&Qe&Lb&Pj(SVIWLd,Ur5Xl+PVDT@S<ZF[CTAR@XDr9bTA^ Kj+^\Tj+`Œd•’g’‘h–\"Ki)TZNJ>VLf1To<Z_#WYM†V†[††G~Œ\y}BbU 7g9l@^9U>b<^8^9^@^6T 4X 6]7i=u&C~(C‘,@¦>HºNOÂORÇSSÈSTÊZX̀]]ÎZT¾PO‡&@c>ˆ/I¢ANÊZ\×fdÚd`Úb[ÙcdÚfdÜhf̃kf̃kf̃njàlfánlßmj̃pnàlhàjfàjcßngßgdàhbƯd\ÛhfÜhbÜcbÚgbÛicÚjbƯkfÜrk̃rhÜul̃xpßumà{pß|qß~r̃|t̃x̃ˆxƯ‰|ßzâ|ß’~à•‡à•„á˜‚ă¡ˆâ§ä°—䯜沢綢带龯́Á´íŵđÆ·đÈ·ïɼđ;đ˽ñÎẠ́ÎÀñÎÂôÏ¿ôԺ亩·ZV‘6FŒ2D€'?6C„,=‹8E7G“DN˜DR›FPOUŸR\¤^_§ad§bf¯jj°nn®pq°pr³ut¸ywº~{Ä‚w΂oчtщkÎz`ÈtXÇiQÈiTËnWÔ~bå¥zôÅú̉œüØ¡û̉’øÆ‚í²râXÏbSÀQM³FJ¤=I–1G“0F–5J¢>L¨DM>K.F‡(B2H•:N¤N[¤IXœDTDV™FZ”CT>X•BWN`œOb•EZEZ‰>T€6Mt%@j @L 4L7J 2L
-6Y@o,P•f}¸˜œÂ¤¤Â§¥Á¥¡¸—–¦z|‹G[n!?~ ?®>GÓaŨveä‡nç”sè—vèœ~êý|ê}́ |đ |î˜úkçcÛk^Æ`eŸPn€4Z„;^{3[N>N@ZAj%LZ@WAT@RDVGXHj(Qj*RVDd+Tb&PUKWJg(Oh&Jr.V]EXCXAT>R8]DQ>ZFYBWHa,ii0a…X–„NƒN„˜pŸ†©m;p[Lj0\l0hVCe#L`!N\Jd%U‰b•r/Z‰Jt—b‹d CX;b<f8R :Z<c>Y<Y:Z7Y8U4Z6b:l;+D,B˜6G´FNÄQQÇRPÇRSÈPT̀VTÉVSÇVT¤9Dd;r$G’:N®ITÔ`ZÖa^Øb\ÙebØffÚfdÜhg̃nlàmh̃ohànjátiƯkgàgeàjeàndándàlb̃lgàiãe^ÜdYÜhbÛd\Üf`Üh_ÜlcÛiẽpdƯpf̃rh̃rgßvp̃yp̃yñ|s̃ṽũ„v߆x߉vázà’á”‚à–‚à†âœâ¤å¯˜ä®—ä²æ³¢æ·©é¾¬ëÁ±ëĵïŶíƸïʹñ̀¼đʼ̣˼ó̀»ñĐÁôĐ¿öÓ¼ëʶ±UZ…,D4F…0J‹:L€)B‚+B„,@‹0@8J9F“@M“CN–DP˜MU˜JZœR\Ÿ[`Ÿ^d¤`j¨gj¯rs¹tpÄ|t͈v̉zÓŒpÎjĂv]¼eXÂjYÈlW؈eöË•üƠ¡ư× ûÎó¿~ébÚuVÈYR´FL¥:F˜4E,C2G˜8H¤BP¤@L—6H…&@Œ0F™>N¡HV£NcBT—BV˜CW”CY“AV’BX”D\›PbOc”F]EY‚8Pz-Fl<n;L3H2H
-6L 8Q=h#O–j|µ”˜À Äª¤Ä¦¡»›‘¨~~”Wcn<&@­=FÑ`W̃viå†pé“wê˜xê˜xê{ë|́›zï{ïvî—x́Œnç~ãodĂX^¤Uu†6[ƒ<^|6ZP>O>`FdAV@V@VBUCTFZHo0V\HSHl,V^MQJXNk,Vj(Mj)OaF`DY?R@WF\B_G\FSF_'LnErFDpBlˆZŒ|E|‘h¡‘j¡¸x>ua&Vf(Sj(br2az8fv2fEl „ZBf#Br4KbB`=d9]6R 5b@]:W8Z>\=W;W9]5i @q;ˆ0C‘1D£<H¾MNÆRRÊXUÆTRÈSUÉTTÇVT¸LPx;Z=„0NCQÀVXÖ`]Ùd`Ú_ZÜhbÛa_ÙcdÜf_Üjg̃jhàlfàleáoiàlfâgb̃jcàofájbßf_ßjeßgb̃e^̃h`̃g]Úe\Üf[ÜfaÜg[ÜleÜof̃mgßof̃rjßrjßvlƯvjß{l̃|t̃€tà‚ũ†xà‡yàŒà‘€á”€ß˜†ä—†â˜†ä¢ä¬’ă¬˜å±æ´¢æ¹ªè¾¯ê¾®́´íĸíƺîÈ»đʺïÊ¿đ;ó̀ÀñÏÂôĐÁö̉»ñ̉¸¸rwˆ/G’;HŒ8H’>N‹2IŒ5J†3I†2H†6J„/E‰1D†5D†2E‡4D‰:H>K‹COETIX–P]\f«fjºrlÆ~pĐpÓlÎ|bÍ‚hч]Đ`Í|_Ûjđº†øĐ›üÖ¤üÔ˜úÈ…í°và…XĐdN¸JK£<G–1D*A‹,B’4FANŸ>M›9H.C‡,E”:N¡IY¤J] K]˜BT–AX•FV“@T’?S–GVLbRg–I`“H^AW}0Lt*Cg=l:O:J7G 6F1L 9g"Ol|´’À ¢Æ§ È§¢½œ—ªˆ…œblu">€&@¨>HÏ]WÜvdăˆpæ’tè—zêvêœ{́Ÿzê|í¢|đ¡{í{ëŒpè‚cÙk^¨?P¦b}‹:`Bcx3ZK <Q>bFX;RAV@R?RB\Km.Vi'OTFUGo0U\KRGXHi(Ri(On,Sc!Lh(ObFP=U@[D\D`K\JZCZHF ARHxF{v:vˆ[‹aŸ©_–] Rn5h…K€”^‡•[ƒj%Do#>U?X<X=f?h#CcBV6X;`;X:X9X9Y8W8Z=`8o;w <3E4DµDJĂRUÆVUÈWVÈRWÈYXÈTTÂPM*@Y:e=”;LªO\Í^ZÛbZÚd`Úd]Úb`Údb̃egƯegƯjfƯlfàjdàieápiàjd̃hh̃jhßniànhàjb̃jaáhdßf`Ưg\ÜhaÚdZÛaXÛfaÚd\ƯkdÜmcÜkc̃rh̃mdßqgƯwk̃wlßynßzm̃|nßtƯ†z̃†wß‹zàyâ’à”á”â—„ă ă¨ăª–å®å²¤æ¸©è»«ê¾¯êÁ²́Å·́ĸîȺđɸïÊ»đ˼ñË¿̣̀¿ơÑÀơĐ¼ôÔ´Đ–”†,F9J–>M–BN˜DS“>N’6I6HŒ:L…0F„*A€,Av&By(Ax+Dz)Ay,Cv.Fx.Fz.FAP”NV©``¼l^Ær^Î|fÔŒgƯœpƯ–f؃^Ơ„câ¢uôĂú̉ưÖüĐ•öÀxèdØuWÀSJ¦:B.B‚;};Œ'?–2F8F•2G3FŒ.H3IFV¤N\¢JX“<P•>T”BV–EW’>T“>T˜DWLb˜Nd‘D[‘F[‡?V~2Hm!>k=k@W9R7P
-4R5R :f"K—hv²’™ÂŸÇª¤Èª¤¾˜±‡jtv&?|$>¦<HÎ_UÜwlä‰pæ’wé—vëyë›yê{êœ{́¢}đ¡í|́’oæ„j̀[WŒ1N¥bxŒ>`„:[t-WN?\G\AS=V>S=R@YGv6`b!G` LTCTFr4]\LSH[Ln+Tf"Km-Tf'Qf'QaG[ET=d LVA^"K^!HVDN@OFXMQFzJ†€L†’g‘q¨•oŸ‚¨‹SŒg‰IxƒBpSu€Ft`FO<V;Z?e=h@\9S8\=]9T7U 6X6V5Z8X:d9r @‚'=;D©=G»GJÄRQÇPLÉTPÇSRÆUSÆUN¦5<a6Z:,F¢CRÂV[ØbXÛb\Ûg]Üg`Ưb^ÚfdÜhdÜij̃igßjeßieàhfàkeàjbàljáofânẽnĩjdàk_âf^áic̃jbƯgcÜf^ƯdZÛhbÚib̃j`Ük`ÜhbÜqlƯrl̃phƯsl̃xpßwl̃yjà{oà~s̃ṽ„ṽ†zߌ|â~à“„à“…âœ‡âŸă¤ä«—䮘ä¯æ¶£è¾«ê¼­é¿°́ŵ́Ă´́Ç»îƹîÊ»ï̀¿̣ʾñ̀ÁôĐÁơÏÂơԹ⺭“6M9JBM˜GTœFSDN™BQ˜BO–:J8J8J….D-Ew%An Am=h;d6`7c8j <w,B?JŸOR´VT̉„nä®|çµ|áªp׉dÚdê­zøÆú̉˜ưÔ–úˈđ¸qă`ÊaP«?E”/D}"@v>| <‘2J”6I’2F‹,D0H’:ODS¤Qc¤P_›FY“AT’=S’=S’?V’@T“@THZ›Lb—Ob”I^DW„7Rs$?n ?i:h;`<^;b;hAhCp(Lft²’–¿¡¢È«ªÉ¬¤Ä£·˜”Ÿkpy+E}'A¦@KÎ`[Ûwhăˆsæ’xè™xèzéxèœzéx́¥}ï£zï~î’pæ„fÀWY’9T¨i~…6Xp&LeKL>\ IT@R=XBS@[Hf$Lh&KXEb$OYDUDe*P[IQD_$Lo0Tc"Je%Mb#Kc"L\De$Jb"HXBP>R@^$Ib"KVG[HUENBUNxG|ˆV™}¢›„¹‰[v‘\‰…Fz}Axp0^Sxt5bT;R:^<e?]8Z<X@aFXFU<]:T7T 6Z8Z6h9{&@‹-BŸ;I´DHÁKOÇPRÆPQÈUSÉTRÈVO¶AFt6V :k?–;N¶RXÓ^YÖ`YÙd_Ûg_ÚgaƯd`ÛfbÛhf̃hhƯkc̃hb̃hdßfbßjĩjeßnlàkhàqkáicànhànfàj_ßk`ßi]ƯgcÜgb̃g^Ûd]Ûh`Ưj]Üh\Üg]ÜkdÜng̃ocÜukÜ{ñyõ{n߀pà€r̃€rà„r̃‡ỹˆ|à|á}à”âƒâ ăŸâ¦‘⪓ä­å³¤ç¹§è»¦ê¾®́Á²ëö́ĸíƺîȸï̀¾đ˾đ̀Ạ̀ÏĂơĐ¾ơĐ·îͲª]h6H–DQ›IS¡NY¢LTKTGSAM•?O•<L‹4G‡,D(Cu'Bo@d<^<X9X:U7]<k ?:Q»ldá¦}î½„íº€æ®rƯ”cƯ’jïµ€øÉüĐ•üĐøÆ‚́ªfØzS²KH•/@†(@s<} B…(A0D’5H2F†*D6L›AQHZ¤Sb P^™FV“>P“>R8PŒ=R’>T•BXœJZœPh•LbH[ˆ<Ry2Il"=p <h8g:i8~,C.B~,Dy(F|4Q˜]p³ŒÄ¤¡È¬§Ë°ªÈ«¢º›’in~4I(D¨BLÍ\SÜviă„qæ“xê˜xéŸvêvævè|î£vđ¢zîœzípă„h´MZ™@W¶t„=^j$KbJR>dHR?TEYDf$OdFWAYCWCc#LW>SEZHh&TTBh(Ti+Qc%Mc"Nc Ic"Lb"NZD]ER=SAN <R<l-P_EXAe&QVEXCRJp<o`”£±˜³‘q“lœu8p†Nˆ˜`ˆ¡n‹~:fP<T;e>a<S7W7Y4X7U7U8T6P6X8Y9d=}$@‡*@•3Dª@J¼HKÈNNÆONÊSRËPNËXT¼LL:W;]<ˆ0H®JRÎ\ZÖ_VÖ`^Ûf_Ûf_ÛgbƯe`ÛhcÛeeƯfaÜhd̃ifƯhcƯgẽllßleàrlßlhâpjànháldàjaáifàj^àjdƯgaÜe]ßh_Üd]ÜhaÛngÛg`ƯjbÜjbÚnh̃jc̃peÛujƯthÜxlß|nà|p̃vàƒq̃‚x߆ṽzß|á“€ăœ„äŒâŸâ¨”â«–å®ä´¤æ¹¤ç¹«è¼ªêÁ°ëṍÆ·íǺ́ƺïʺđ̀½đ̀½̣ÎÀôξôĐº̣Đ±Äˆ‰9J”BQKT R\¢NV£OU¢MVKU˜GW–@P>P8J‡2F~1Ht <h@`<Z?R:L 5N:Y?<RƠŒṕ»‡ôĆïÄ‚æ¤dÛ„[à™pô¾†úÍ’ử’ừˆô¼ză•^À[M˜5C€!?u@vA…&BŒ/F5F2H‚&D„(G”:QH\¦Rb¢N^—FY‘=SŒ8R‹8Q<Tˆ5LAW˜H]ŸSfSh—MbDY…8Pu(Es'Bj<f=n;6I>N:Lˆ6N†9RˆB]—^r­„ˆÂŸœË®¤Ï²¤ÊªŸº™•¤rv…@R-C¨@Ì\PÚteă‡ræ”úœzèxéŸwê|è|́¦yï§~í™vê”pß|b¹L]¡D[·p‚’Ffj"LZBWB]DVF^Jq2Zh%IY@VBT?XDa!I[IUHYFd$N^Il,V^ Kb'Mj(Sd&Pf(Nd LVBUESBS?YBR=T:f"P[Bv6`c JVBPDMFq9f”n“q ›²˜|±†Rˆ‹Xˆ„>q—Rh›_R?W?c?W:X<V:V7S8V7U9S;V>\8^:p<Œ0D.D<I¶FJÄQRÆTSÇPRÆWXÈVN¿OO(;a7W9u>¤@NÉVUÔ`^Ö]S×e`Üe_Úc[Úc^Ưf_ÚmhƯgeÜjh̃hc̃jgàhaßjdàjfáicâohálfàplàngàojàldápf̃mdßh]Ưg_Ưiãi`ÜhbÜh`ƯicÜi^ƯjbƯj`Ưi^ÚkdÜpfÜrh̃tj̃rfßxjà€nƯs߃vƯ€x̃ƒyàˆzàŒ|á‘~â—ƒă˜ä‰ä¤‘ă¤ä«˜å³¢èµ¦ç¹©ç¼®è¾­ëÀ´ëṍźíɽîǹîɼđË¿ñÎÀó̀¿ôÏ¿ơÓ¶Ú®¤”=M’>O˜JTŸJS¤P]¥PX¥RX¡PXLVœFS”FV>PŒ=P8O~.Fq"Ai D^8X<N=I :Q;<Là›nóÀ‰÷ȃóÂz̃—[܆^çªxô†üËŒü΋ùÄ€é¨nÎoP’0>€!:q>p>z#@…*DŒ/F0D„,Hƒ+I6O™DV¦N_¦Vf˜JZŒ:Q‰6N‡9R‰8O8O8M’>U›NbŸXmVk•J`ˆ@W‚8Q|2Jx,Gp%Dj>l!A’BR‘DV‘?P?QE\‘I`dw¬„Œ¾›Ê¬¤̀°¨È¬ºŸª|yIW„4I¥CÒ\VÚvdâ†rå’uêxèŸ|ê{ëœwéŸyđ¦|̣§}́uê“rÜzf¸U_ Lb®ezCct,TQ>SAXBd#J`Ca DYBW@XBZA[DXB\DWE[G]H`%Li)OZFh+Um,Xi*Te&Lf$MR@UDR@P>ZG^GL>b"Gn+Uh*Rd K\KVHXLf,^p:eŒa“ ~¤«—³—t¦|D~€G{’j•_X?^@[<V8V7V9U<T9U5R5Q 1Y6^6h6(>.A“.@¨>G¾LMÅRPÅTSÉRPÈWQÂOK%;[ 7Z=v%D9JÂPQĐ]VÖ^UØ^ZÙg_Úd[ÙdbÜd`̃haƯlaƯlẽidÜg`̃haßkháhcàieƯhgàpjàlẽlhßmgànhàmfàng̃j`àh_àjãnfƯh^Ưf^̃e\ÜiaÜi\ÜmbÜjaÚg_ÜkcÛpkÛpjßugÜsĩxl̃|pƯ~õ‚t߀tà‚z̃ˆzàxâ“€à•ƒâ“‚â™…äă¥å®æ°æ´¤çºªçºªç¾°ê³êĶ́ƵëÅ·́È»îȽï˾ñ̀¾̣̀¿óϾöѶèDZ£LX8N•CRœOW¢T\¢PX§RW¤PV MUFR™GV=NAR‰9Pƒ2J|1Kq&Ah"@]<T;O<X?<J̃’iđº|øÄ~đ¾xâ›fă˜j́²zơÁƒùÆ…öÀ~í­qÑzV¢:Cv9t<l>y#B‚&@‹0F„&?'?‚)BŒ3MœCT¡Na¥Sa›L\>Tˆ:N†6N„1Jˆ5N8N@V—G^ Ui¡]pœNd‘K_Œ@Vƒ6Q€5Pz)Fn#?k!@s'DŒ:PBP?PCX”K`—Vj¡n~®Œ½Ÿ¡Åª¦É°«Ê®¢Â¢•ª‚€’Ta†0D«DNÊXQÛtcă†qç”xëœyê|́¡zëzê|ï¥~đ§ví pè—nÚzc¦L^¦Nh¬`s†@`u*SXB[GX=XCX?ZB[DX?VAX?]Ja%L` HXFWEV@XAZDYGi-Tm.X^!JZIf&Od)STBVBRDVBh&Na#NP=e$Lj,Ud&P\Mb"Rm/^b$Np0\j.\m8]Z‚—x’f˜af3O[A\@_AYAT<Y@T;V<V8O 4N 5X7`@d8t =†+@”4G4C¸HJÁMOÉ[WÆTTÈQP½KE#7T 3T
-4p >9I¼JPÏ\W̉\YÖ]ZØ_[×b\Úf]ÚfeƯb[ßhbÜhhÚjf̃hfƯjãheƯlgàjcàhẽhfßngßnfàlißkfàlcàohàpiàh]àkaàmf̃hb̃g^̃edÛd]ƯjdÜiaƯmdÜndÙkdÜibÜmcÛsfßrg̃rgßziÜ|pƯ{ñ|qß‚t̃†ỹ|̃zà~à‹xß’€ă˜…✌â¨ä§•ä«æ²¢æ´£æ¹§è¿­é¾´ê¶́Ĺ́Æ»íǺđÇ»đ˾̣̀¾̣Ƕó˼öϼđβºtx3D“BP›JTŸR\¤SY¨RW¥SZ¢OUŸKU˜DS–GU”CR8L‹9M…5Jx,Bt'Bf>`:^@jE˜:LÖ‚bí²zơÀ„ó¿î¶yí±xđ¶uö¼~̣¸zê¥iÔ{T@Cx;j<g<o<|$B‚*Aˆ,D$Aƒ(C1J”<P KY¤Pb›JW’AX†4N€0J‚2L…2K†2KŒ8R”FZMd XmXr”OgG^‡;T…:T‚8Os*Go"Bk$Ar)Fˆ;R@V“DW—K^—Sg_p¦v„®‹¼¢£Ă¬¦É¯§Ê¬£Ä£–­„ƒ–Zd‡3F¨CLËZOÙrbá‰zç’téyêzêŸźŸvë¢|î§yñ¤zïx́–mÚn—7O®\qªYl„@`d FR>_GT?YDYDX@ZD[@ZCX@ZCb%JbIWGZGYEUCTDc%Pd%Le'QVJVHp4\|>fVBZHVFL@g&Q|@j`LTDf%Js5f\LXLs>gu;raQw@svAp€Oq<l’f„©v@gZ?\<[>U>T>\@T;V8U=N=R 7[:`5n9†,@ˆ,@—3B®BJ¶FOÅQPÈWRÇOK¶DHv9S
-7W<v#@Ÿ6F·FLÊVV̉YT̉ZZƠ^XØa\×^YÚf_Úf_Ưd[ßjhƯgd̃lbßh`ÜhaÛebÜmf̃gfßhb̃gdßlgàqhàohàkd̃kf̃olàpkßmfálcàlgßneßiaàg_ÛfbÜlfÛibÜngÜjbÛohƯj`ÜleƯrfƯrjÜrjÜtf̃vj̃xpß|nßr̃‚wá‰xà~àà‰{àă—ƒäâ ˆâ£ä¨–䱠峥浦绫農ê²ëÄ·́Ä·íɹîʾîʾđ̀¾đȹ̣̀¾ơιóĐ´Ơ¡–’7G<H”BPœKT¢QV§V[¤TXŸPWŸNX™EM™HT–ET?R?R†7J~1H}2Kv,Et"?v$C{'C“6LĐweê²€ôˆôĂơ†̣º{î®jê¤jä’_ÎsY¤JM‚)Dl<g>k>u"A€)B*A"?~$B‰3K—?QJY¢L]L`“BXŒ>R‚6L2L…/H„6L‰6O’@Y˜Lb Uj \qPg’E`ŒH\†=U€4Nx.Jm$Cp"Dt0Lu.Kx-J>P–L\œXhœ\m dv§t€¯†‹À¡¡Æ¨¤Ç«¥Å§¾ ˜­„€—\dˆ6G¢FPÉZWØsgà‡tårè€êxézêŸzí¤~î§đ¦víœzë”sß‚i–6R°bv¥Un†;_ZBQB`HRAXGW@\FXAaJbJVB]Df$J_FS@VDTFUF`'Su5bj/Zj1]TD^!Ox>d|Ad[FSAZHKAf(Y~Ei|>g^L]LzBmZH`&\a0X}Jyf'`v>o—l˜”ld&Pp1]p@X‚Jud?Z@U?T>W;\<X:R9P7O 4V8b@c<z)HŒ0F4I¯CH·FK¶GIÀOJ´FF&7]6N7`6‰-B¨>HµHNÅONÍXUĐZXÔ^Z×^XÙ`\Ùa[Ûe`Úh^Ûd^áj`Üj`̃ibƯh_Ưjcßjc̃hb̃iẽjd̃kgßldâniâkbâjb̃lg̃ngáohßoeàlbàldàkdàmd̃haÛjj̃k_ÚifƯndÚh^Üh`ÜfZÚl`ÜpfƯphÜreÜuj̃wjƯvhƯ~q̃r̃~ũˆzàxà‹|à}à’‚â”‚á’„àœ†â㦖ă­ä±£ä²§åº§æ¼®è¿²ë´ëƸíƺïÇ»îʼï̀¼ïÊ»đËÀơμôĐ¶ä¾¬CR:K“CRJUKQ£PX£PT¡PX¢LVHV•FQ—MX”DT”FS;P„8O…8J2J‚3J†6I3N£GUÏ|lè´‚öÇ”ø̀–÷È’̣¸zæ iÙ|TÂbQ¢BJ‚*Du"@n;n@v&E‚.F„,B)B|"B†/F‘8OFX Qb¢O_˜MZ?U„2M2M€.J…2L†4MŒ>VNbŸTh£[nœRh–MeBZŒHZ‡=R~4Mt*Hr&Et,Gq*Jm Ak">„?W’J[Znœ^oœ^oœj{«„¼ ¿¥¥Å©¨Ä§ ½Ÿ”¬„€˜^iŒ<L£GPÇXRØrdà…oå–xèyèzê|ëŸ{́ zî¦zî§{îý“o߃h:T£Wl YpˆBfR>N?YCTB`"N]Cd&NT?f&N_IWC^Db%Hg'NWEQ=SCTFb'P}8duAnk6`SJe&UvAf~Djr4\N@R@VG] I|Cnk,Sj,V_#Te+MwAu[ Jj+\`!Rw:nl0i‰T~¥‡©€Mzv4jTAwAhn'OU>Q;S<Y=\?S8P 4Q:M 3U 4^3n:ˆ1A–1?£=E²AH¯BGœ6@„6b6R:Z:x$B 9GµBL»JPÆQQÉSUÎ\WÓXRÔ]VØ`ZØaXØc^ÜdZÙfaÙf]Üg`ÚicƯf\̃hd̃ljànaƯlẽießifàjfâldàngßnfánbßtlàngàrjßpkàmhámfßofàofƯndÜlhƯliÜj`ßmc̃j`Üi_Ưk_Üi^ÜmẽndÜqg̃wiƯuiÜvm̃yl̃|t̃oà‡{̃‡zßzá‹~â’â‘â’‡à›Œââ¢—ăª˜ă® â²¢æ¶§æ¹¬è¾²êÀ³ê¶́ŶîȾîʾïËÀî˽ï;óÏÀôϸêʯ¬^i‰7F’AO–HQMYMUNVŸNS¡T[›JU™IQ™JV’GZ–HV>P‹<Qˆ;TŒAR@P”=P–8K­KTÓ€pé°„÷È•ù̀‘ơÂ…è¤pÑyS±PK‘4D(@|">r<t@{&B|*C‚.E€&B'A‡,H’=RœGZ Q`ŸNa˜J]EW‡5L|-Iy*H~,G„5P<Q“BZœPb¢Zl£ZkœNf–QdG]FZ€6Ly1Jl @t%Fz0Kv1Ml$Bb<€4LŒG]—Vf–Vi‘Si”^t¢y…µ–¿¤¡Äª¤Åª ¼ ¬‚˜Zf>L¦GRÅVP×rdá„mă“wèzë|êŸ|í }́¡€ï¤ï£|ëxî’kàˆn >X˜If˜Tny2TN@N>XCTD]"KX@b!JZBk'O`FT@XG]Fq2\b&OSAXFVDl.Yv0^yLuv7cTHb$Tu@j‚Lt~Aj`LRA]JV@€Fli)TQ>WJ]%Oh‘b%Vd&Y^Rq:it9u|Ax¡¡aq5d\Ih.Vj.YR<N8WA[<T9R9R8Z=U:\5j4)?1<”1?‰,=|<h6V@W9`:$@œ0A­@IµBG½KNÆSTËWXÎTTĐYỶ\VĐecÖ`\Ö_\Öa\Ûh]Ùe^Ûd\Üg_Ûh`Üb^̃f`àleßkb̃heƯidàgc̃piámdâlbàngápcàqdßtjàtfßrjáqißrjàphánd̃mbßleÜljÛjd̃jb̃iaÜj^ƯlbƯi`Ưj]ƯpfƯpdƯugƯvhÛxl̃xlƯ~qÜ€ũt̃…x߈|áˆ|á’┃◈âˆâ›Œâ£ă¦–ä«ă²¤äµ§å¹­ç¼°è¾¯êĹëŸíÇ»́Ë¿îËÂđʽïË¿̣ÎÂñνïί‡„†3E:G“HR•JT›LWLTœPVŸNU™NW™HTOZ”K]—MX“ETCVEV•FX˜HV™CQ—>Q«HỦxf樄ñ¿Œđ¿ˆèª{Ö^¨HJ4Gˆ4K~.F|(Fw!A€,Dƒ.E‡2H„.D‚*D….H”:QK^¤Tc¤WjN\‘CU†:L€2Hx(Fu(Gz&B‡4M‘BW—F\¢Vh YlŸVgQg“MaH]„>Vy.Gl"Bq&Bz,Hx-Ht,Gh!BZ6o'C~9PˆDZ‰F[Ke“\t u„°“–À¤¢Ç«¦Èª¡¿¢™°ˆ„Ÿdn>I¢ENÅXQØp`ß‚nă’wêœv́œ́ |î£|í£xï¦zî§vë́”lä‰m±P`Œ7XD`n(OQ@TAU>YE] I[H_GT>m+Vf"JZBZHX@v<gTBVCYFVDj*Sn)TvLoq3\KAd&Vz:hŒZ„Lu€@n[JWFQGh,Q„KtK>THc&ZsHa`•b#QY Td(_uBx‰W––d«—´‘_Œ\E^Fd+SS;P8U9Y>T=ZAX8[8^8f3i8i8e8^>S7W9[>j!D‚,Fœ;OªBPµDN¼HLÀNSÉTUÍUTÎ]^ÎXTĐXX̉ZV̉^ZÖ_YÖa\Ö^ZÚcaÚgaÙfeÜhaÛebÜjfàg^̃jãjcÜfbÛfdƯkhßmfßlh̃ld̃ngàpd̃pj̃tràphásfàtlàsm̃nhßlhƯnfƯphßodÚjeÜhbƯld̃pf̃nbÜnfÛlb̃odÛphÜrg̃tfÜxlƯynƯzr̃~sàũ„w߇{á†}á€â“ƒá–†ââ‰â¡“⤔䬘䮜䳦䵥漯龰éÀ´ëÄ·́Ⱦ́ļîËÀíÊÀî̀¾ñÎẠ̀̀¹̣ήܮ¢9GŒ;H@O’FO•JU˜LVOXŸSZR\›LW™R\›PZ–MZ’FZ“JY™M^ P\¤P`¤NX¢GU¨GTÈc\Ûuâp̃ǹyZ§JJŒ8N‰8Nˆ:K†0Iƒ,D†0Fˆ/DŒ2Jˆ/F„*E…/J‘8P™FZŸRa¢[jMY“AQ‰9L‚2J~5Pz(Ct'F|-F;O™M`Qf¥^m Zo\n˜Pg•NcŒFZ€7Mr(Dp&Fr,Fw*Ft(Fj!CgAW:f >p*H€<T‡D[‰HdVpo°•¼¤ŸÄ¨£Æ¨ Á ˜±‡ kr–FS¦FRÄVRÙnaß‚mävê™x́œzí ~đ¤zî¢~ñ¦đ¨~ïŸzî•sæn¼\fv'K}6\]BUDSBR>U>X?YE\J^Jk'Pg K\I\H\F|GsVEVDZHWId!Nd#PzNxk*XMG`$S‚E€Œ_Y†ŒT€j'TV"QTL^LUz`(VLHSEb$W‹a‚t7fn2f_!Ut>pb”^™r‘¤z ‚Ft`L`&NR<P:V9S:T8\>]?\8^5[2U 5T6^<d:t(B†(@“/B6C¬9D¯<JºGNÂPTÊTVÎVZÎ^[ĐZWÑ\\Ñ_^̉`_̉]YÓ^ZÔ\V×`XÔb]Ød[ÖdbØ`ZÚjcÙgbÜf\àj`̃h`̃f]̃faƯjb̃iãif̃jeàidßlcàsißmgánfàqjßrlárißsoßojßnf̃nbànẽmbƯodÜhbÜjcƯj_àp`̃nbÜm`̃ndÛogƯrgÜtkƯvjƯzqß{nÜsà„w̃†|߆~àˆxáŒ€â‘€à”…â†â á¡‘⧗äªâ¬œă²¢ä´¦æº¨è¼¬èÀ²éĂ´íŶíɾí˾îÊ¿í̀ÀđÎÀñξñĐ·å¬œHX†7H<L@N’IV•KX–MRRXŸR^S\ V^›Q\˜K\–P]˜R^ Ra¨W]¬V\ªRZªLU®LV¼VWËl`Êp^ÀeZ¨JS’:L4K‡2F‹.E4H’4G”:K‘4F1B,Dƒ,G‰8N•DYL^QbT`“ET‰<J€,C{(Bx(Ft!@v(F†4PK] ReYj¤]n¤^pZn•MeNd†?X|0Hr)Dr(Cn"@r#@q$BhB_;Y@e>j @u1L€;T‚A\ˆJg›gx¬¸œĂ¦ Â¦Ÿ½ ³‰„¢lqRW£KTÁXS×kZá€læ’xê™zê€í ~î¡|î¡€ñ¢ñ§́€ëtç‰rÆddr!Ev5ZT@XFRCV@\)M\ATAZDb"Lh*Tb!L` Pd"O`K}Mub LVBYFZKd*Wn,Y~Nvc MOCZL|@v‡Tƒ_Z†j0]PGKBt<rƒHi[…L@G <j+`k.Z‹X„g*Xn.nd(X“i™_‡yDt}KqZ‚zAm\EOBSDWJV IYHW:S3U4X4a3m:v"=…$9‘);›4@§4@«;E®;G»HQÀLRÆTTÊWXÏWSÎTUÑVUĐWVÓZỶ^WÓ\UÓ^Z̉\\Ö^VÔ_XÖ[T×c]Øe^Ø`ZÜc[ÚfcƯh^Üe_Üf`̃e]ÜgbßlgßkdàlfájeálcàmfàmfƯqlßrlàtpàtjátl̃njßnh̃tm̃ndƯsißnb̃rfÜld̃kbÜpfàlaƯod̃l`̃ncÚqhÜngƯshƯyh̃{ñxlƯ|qßuàƒu߃wà„xà‚â‹~áà˜ˆăâ¢ă§’䫘䮛ä°ä³£å¶¨åº«è¿²é¿²́¶́Ä·î˽î̀¾íÊ¿î̀½đ̀Ạ̀θ́̀¯´muƒ4E†9JBPŒDR“KY•KQNZ¡U^¡TZ W_œXfP_RaTa¥[f«^a¯ZZ²VW±SX´RX²OT´TV²TZ¦NW›CR’:O’=O“<N”:LBR<K—:I–6GŒ-A†*C‰.I“<R™H\œPb˜R_DVˆ=Qƒ0F.D},Cu$Bs#D|0K’ATŸQ` Vl Vh£`r¡^qœXo•UiIc„9T{0Is(Ep"Bm"An$Ck @c<aC^ Ad"Ae?m(Hz6T~=[‚Ab•by«†»Ÿ Æª¡Æ¬¥Ă¤²‘‡¦stW_¤LY¿WV×jZà€kåuê™zí}́¡€ï¡‚ñ¤€ñ¤~́}é’tă‰p»[_t"Iu1W[H^HVFV>[F\FR=YAb Kk*Te%Qb%Qb"N_Mn:Zq5fTDQBVHc M{BdzCkXFPGSGv<h„Pˆ|Ht”j’zBrPCF Cb%WˆNx•jŒn-YC <MFr2ey@\ƒL}^$Nh,fS‚ŒX‡’c˜j4j†S|~Di]"KP?P<V"BT8P4R4W6`7k=t;…'@’/B›8H¢6E©CL¶HL¸FIÂMNÆPPÈTXÉVỲVWÎWUÏXVĐZYĐZX̉ZZÓ][Ôb\Ô`YĐ\WÖ^UÖYSÖ^ZØ^\Ød\Úd\ÚhaÜd^̃fZÜc\Üb_ƯfbÛoh̃ofàj`ài`âldànfßib̃khÜlĩqjßrl̃qjàpf̃rnƯnfàsjàpiƯqgßpd̃vj̃ndßneÜocßl^̃leƯldßrlÛohƯqd̃thÜviƯvĩvlßznàq̃ƒs̃t̃‡y߉~à€à‘ƒá’†á›‰àœá£â¥‘ăªă°œă°¢ä´¤ç¸©æ¹®è¿°ë·êÅ·îÊ»îʼ́ʼî˼ï̀¾đκïαɔƒ4K‚3H‡@OŒBS‘JT’KV˜OZS]ŸV^ \bWcœV`¡Xa§[f«^b°\]µVV²TX¶TW¼TW´NS¬LUªJR¢FSœAQ™>Q@R¡HV£FR¦HTŸ>O–:M5I‹2G‹6J7P—BVœPe™J^H[ˆ8L„6N‚6Mƒ2H{*Fw,Fv&Fˆ;T˜J^¢Xl¢Zm¥bw£fxœYj–Tf‘Nb‡CZ|/Kv+Fo$Ck @l"Do"?gAb <bA\@f%Dh*Li%Cn,Mt3T{:Z’]t¯ˆ‘Á¦¤Đ´¬Ô¸®Î´¬Á¤–®} \e¥JSÀYX×l^â‚kæ’v́yí ~́ î£~đ¨̣¦í¡|ç•tĐ|a”<PlIp.Ta.PY#MSAWDZ@ZDV@_"MaHh'R] J` Ne$Nb$T\ I}FxZGQARF]NyDjt4aQBQFQJv:k‹Y–g'X“j’’f’\MNERL„Hz•g‡„HmVF><XF‚Bpaˆh(\SJo8jˆV‰’a„T€p7cg+Ka"KM;R>U?T:W=]9h9l3t58•*: 5B©:F²BH¾OLÄNNÄOKÄPOÆNNÈTSÊXVÎYWĐZX̉^\̉ZXÔ^\Ô][Ơ^UÖ\VƠ\WÓ_W×]WÖ[YÖ`XÚgbÚb\Úd`̃hhÜfZ̃d^ÜdaƯf]̃f_Üjeßibàgbàh`àkeànfßjh̃nfßleßmhárißpjáskápiàpiàsj̃tlàpkßqlßwq̃rf̃pfßod̃rẽriÜncßphÛtlƯvkßvhÜxh̃vj̃|rƯzpß}s̃€rà‚ũ…zß{âŒâ€á‘„╆â™á¢ă ’⣔⫝̸ᮛⰣ乨巪绮èÁ´ê¶íȸ́Ê»ëÉ»́ǹî̀½đ̀¸ñͱװ¡Œ3H€0D†=L‹CS’IT•MWQZU]Y`Xb [d£]e§^hª_d¬]a¸`^»XV·TU¸VVºQT´NR¬IT¬KT¨HT¥FP¤DR¦GU¯NR°NX¯IR£BO—:L2HŒ3J8O˜@TF\•JZˆ7N„6L~2G}+B‚0C‚.C}2L|.H2K‘@TN`¦\l£`l¨ap£`s˜Tf–TeŒFZ‚6Ox+El Bj @n>f>e:d:b8f6^=b BdBbAj(Jj)Nn-S”Yp´“ж°ÜµßĂ³ƯÀ®Ö¹¦»•£_f§T[ÀZXØn\á„lçríœ{î|îŸ~đ¤‚ñ§ô§€đŸâŒpªS^z,QdDh%N^C_JV@\ I[DUBVE_Hc%Pf%N\Jb Md$Mf(TXIoAao3cP@VH]K‹aŒ|@mTLUNTLzApŒ^“hY‚R}w}GxZ"PPEqGoVz„Oyr/^H?J>v0`zC_”h•VNPEr3e}Ju‘bl.dR>b$MP?T;ZAV@\>c8k8q0€!6”0?¥9A²?IºCG½NOÅMJÊPKÊRPÇNKÉQPÊSRÎWUĐ[VĐZUÑZYÓ\XƠ^XÖ_W̉ZTÔa\×\SÖ^TÙaX×^XÖ^ZÚd\Ø`YÚf_Úc[Üe\ÜdZÜh`̃fZ̃g`Üi`̃iaßg]àf\ámdàj`àlcßlf̃mdàqkáphàpiàniàrqßrkàul̃ql̃skàqhßulßrhàrlßrdànc̃riƯpf̃wlƯrfƯthàvhàxgßxjßwkƯzp̃zñp̃…ṽ…zߌ{àŒ~ă‘€á“ƒá–†àá ”â¤à¦âªâ­à® äµ¦æº¯ç½¯è¿±èÁ³ëÄ·ëƺêɺëȽêǼ́̀¼ñ͵âĂ®KZ|.G…;K‡BVDOQYœR\RYXbVb [f¤`fªaf¬af´`^·YZºUU¹VU¸VV¸UX·QT´QV°JT«JR©DT¬FRµQV¼TV¸QU®HR£@N:N“6N˜=R•DV˜I`–I\ŒAZ†:L~,Dz*A|,D~.G~)>~6N4N;NœPd¥\h§aq§s¤^nZo–PeŒEY†?Uy1Hn)Gh$Ah @i>h"@f>f;f<v:Z>d"@bA_@h"Eg%Jo.W”av½•—Û¾¯áĂ³âijß°̃¾¤Î©“­po§RZÁZVØjZà‚næṕx́Ÿ{ïœ~đ¢€î¢€đ¤đ¤~́|â“y¼lpOlx'Pc KVCbFf&NZAZDQBYB`#PbHfKb"Ld"Nj(Qi-UZL\&IzGvL@TGb'T˜uz8bVEWOVH~Etbo'_w8hŸ}¢•j”b#LOBRFy@h‡T€_"J`#SI @j'Ou/^ˆXs€FxOBq0dn1c[‰yJum6po4\T=P:V 7S6_6l6s2‚!7—0;¤7>°<@¹EG¾GGÀMHĂPNÊQJÊTLÈTNËRNÉSMĐWS̉XS̉]UĐZV̉XPÓ^YƠZR̉XVÖ^XƠ^ZƠ`YÚcZØ`Y×^YÚ^XØaZÛaTƯd[ÜaXƯhaÜh`̃h`̃f]ƯdaƯh`̃fZ̃jgàhcáießkdàjãhgáogßqjàleápnárkàrsătiàtkàpjàtf̃xoápjàvpßsjßrẽxq̃vlßtñtiƯtk̃zñxjàylà|qß~k̃zpß}mà„và„táxâ|à‘‚à—…à“…á™‹à â¤“á¡á©œâ¬œá®Ÿä´¦æ¼¬æº¬é¾²èÀ´ëõêĶêÈ»ëÈ»ëʽ́ͺñ͹êʱ¯ox{.J„8H‰>JŒGUŒGPŒHT˜T]˜Tb›T`ŸZb¨bi­bf°ae´``¸ZYº[Y¼VQ¼TT¹UV¸RT·OU¸JP³LT²NV¸VYÁWXÀVV¶RY­LT¦AR@Q—=T™DZ˜F\—H^’K_„>Vƒ6J~.C}-F‚.I}0F}/H0I‹=SœM^£Wd«bn«du¨bp\p˜VjJ`BU4Lr)Fh#Cd>h">k%Cf:h;i<r >Œ2HY<`=`@`>d&GcHk*P˜bz̀¤œÛ½±ß³ăijàĂ²Ư¼§Ó°’»ƒw¨PWÀ\\Ơm`á€jäŕœv́œx́xï¡|î{î£~ñ£|îŸ~é‘sÈnn³do‚3VcJYE\D`DXD_KPA_"Jb-Sf&PfMd Pi"Nn)Um+Tf"RTFzJpb PVLg-W˜r—s2^[JVJ\NˆQ|e•eR}4q„Uv ¦s4dPBSJh*W\‚g,ac&Pe"TZA€:dn.T†NucTi)[p,`„T€G€†V„_‹ZDL 6N 2X 1c3u4ƒ#;’.<¥5=¬9?·DI¹HJÀGGĂNKÂJJÊPNÊTÒSPÍVQËRPĐVOÑZUÔ`Ỷ\UĐ\XĐ]VÔYRÑ[VÖ]V×a^Ø`XÚ_XÚb\Ø`[Ú^RØ_YÜ_VÜd\ÛaZ̃d[Ưf^Ưf_Üb[Ûg_̃mfáj^̃hdàh`àkdàg^àlbàlhßplànjàniásnàoeàqiâulßriâtkàthàqkávjàwm̃thâujßxmßsjàsl̃tf̃tg̃wl̃zlâyná~sà|sà{pßzoáƒzâ‡{á‹yâà‘€ß‘à’á†â áˆà¢’䨖⭜à¯ä²¡ä¶¨äº­ç¾°çÀ´êĶêÄ·êȺ́Ⱥ́ʼ́Ê»ñ˹îαʓ’}/J{4Lˆ>LHR’R[–MY—P\”NZ›Vc¡\b«^c¯ad²]`¶\^º][À[WÂXV¼UV¼UVºOQ¸OU½RS¼QS¿WYÈ[VÊ_XÂXWºOQ¬GR ?Pœ@U›DXœNb”F]ˆBZˆ@Y‚<Xˆ;Qƒ8Rƒ4J‚;P€-G†2H‹:P˜H\§Vh­cq¬hs¬fv¤cp›Uf•RiˆD]€;Rt*Fh @c;`6f9i<j)Fl<}+Fˆ0C™8IZ>[=b?`@d"EaEj'P˜\rΦœÚ¼¯ÜÀ°àñßÁ®̃»¦Ơ²˜Áˆ~¥R\¾ZXÖnbà‚kåúœv́wê xí¢|î {ï£|ñ¥€íxß“xºYbNbv-QbF^DWAX>ZAc JUH^H`#LdLk%Rh"Nr*Vz6\z5]r2\[Jd$Ms0`\OsDnŒ\‚q,XcJ[Nj"W„Fq`TB~?ut0dz˜–d‘[KRIk/b_„‹X†XJe&Pf&Tr0T}<gf*Oh+XVGn/`~@k€I}s9q”f^‰^!KT 4\ 4o3€7&9œ+;¨6>¯9B¸FHºDEÁGFÆPQÈPǸOLÊWTÍUQÎUP̀WTĐXQĐXỎ_W̉]VĐZWĐ\XÔ^TÓ`[×`UØbXÖ]ZÙ`XÙb\ØbYÜ\TÛ^TÚh_Üd[ƯjdƯf`̃eXƯc]Ư`XÜf`̃jh̃jbƯgẽmk̃kfßgdàicàngánjâpdârgâtjárgàsjàkiàrfásháqjßrhârfázpàwnâxiátg̃xlávh̃rfßuh̃xoƯzjà{lâ~lá}oà€rà~rà„wă…và‹}áŒ~à‹|Ưá’‚á–‡ààá£’ă©—ă¬á®ă²æµ¨å¹§ç¼±è¾±êÁ´ë·éÆ·́ƸíʽíʺđʺïͲڲ¦‹:N4I„<K?IBN”FO’NZ”O[R\[b¨\`®^a´[\¸^^ÄaXĂa^Ă\VÀTRÀTS¿SPÁYWÇXTËUTĐ`WĐ`X̀_XĂVS¸KR£GT?O@V™DT–E\<X‚<V6Pƒ9O<U„:P†:P†5K„2GŒ<Q˜H]£Xj¬bl¯mx¬kx«ht\m—Uh‹EZ€<Tt)Ei<f!A^8a>e>g=p&By(CŒ5HŸ?J¢<KU<\<^>^:c D^Fc&O‰OmË¢Ú»²̃¾²̃À³Ư¿²Ú¸¦̉®—À‡y§NXÀ\XØn_ß„nåt́wë{́ î |́¢€î£ñ¤}íŸṽ‘w¤JWA^j"Gf$NdHR@P<_Bh%LP?g*V[Hh)Rn(Rg#Pp-Vs*Tx5Zx6b\JbMp0fj.^o’†HpbLg!T` QiR†Lub‹P@w8fv3fu<h“j€FzXMf'U˜p—‹XzXDRCTDl(Q<^s0\f(SWIWFaL~Kym,b}?g—f…X|j$Ki<‚$<–->œ4B¢1?©7@®?F½GHÁHIÆMJÊQNÊSRÊPPÎTTÎXSÏXSĐWUÑ\SÓZRĐZXÑZXĐ^[̉]TÖ]TÓ]TƠ^X×_TØ\UØ\XØaZ×`ZÛ^XÚ^VÛcXÜa\Üe[àe[̃i`̃f_à^W̃dZƯc[̃d\̃hhàh_àhd̃lfàjc̃nhàrgárfâpfßphßrjßrj̃kfàrlâsjàtoßsmârgáwlàxlàuhàtlàvhßyoßymàtgßxjÜ{pàwkßyoá€rá€tá€pá‚sâ…yáˆ|á€à„àá~ß“†á˜àŒàŒâ¤•âª•â¯Ÿä± å´¦å¸¨å¸¬ç¿°ê¿°êÁ´éĶíƼíÈÀ́Ç»ïʼđηæÄ®¥Vl„>Z‡?PˆDS‘HN@JBM”JV™W`œW_¦Y`«X[´^_Âe_̀g\É`VÆ[VÅ\WÆZTÆXTÄZWÎb[Ñh[ÖkXÑdYË]UÀTR±IR¡>NBQ—>O’:P‡7Q{4Q4R‚6SŒBY>X@Tˆ:Q†:P…4M”DUK^©Zk²gp¯n|¬ktªguœ]kH^:Qv/Hg >a<_6`:`8c;j?u+F†4J@R¬FRªANR9^>`=\=` C[>`H†Hfęڼ®̃¾±Ü¾°Ü¾®Øº¦Ñ¬·zq¡S^Â`\Øl\á„mæŒnë–x́„́¢z́¢|đ¤‚́€á–{¢JWFdh&Nj%LY>Q>P:d"Gi*PH8g(RV@r0Yr2[k"Mq*Vm&Nt-Xx4^f%ObS|@t|;h ˆ«r4Y`Fq.`VBd R‚Gm^ˆTHi(Tt4`p+d|Fk˜nœs2l\!N x|EhN=YFSJZDo*Xy:`e-Se"PTD_L}Lso.a`F‚Lzz7NR€z8’/D—1A›2>¨:D¨8@²@DºDF¾HKĂJJÆLNÈQRÏSRËWT̀VQÎXQÑZPĐXQ̉ZTÑbZÑa[ĐZW̉]TƠ\TÔ\VÔ]WÖ\T×`\×b^Ùb\Öd]Û`TÛ^XÜ^Wß`Ỹe^̃ib̃e_Üe]ß`X̃c\Ưd\ßb^̃fdâhfàhd̃nháihàhbàojândârl̃nf̃pf̃nnâmcàrkárhàqhßrjàrhàvjàxiáypàwlßvhßxl̃xqáyißxl̃{õztà{pà„rà„tà‚xâ€tà„tàˆ~ጂà†ßŒ„ß€à”ˆá”☌àœâ¦”᪘ᬘ峢䳤䷤䶨溰辰èÀ´ê´́Ź́ÇÀîļđÊ»đ˵êÈ·Ân‚R€’IhˆEZDRBPHT“HRPWœRZœPY°bf½f^Çj]Ñh\Ïc\̀`VÈ\XÎ]TÊ[TÈ`\Đj^×l[ØkZÑfZÊXP¸RS¨BK˜<J˜<L6Lƒ/H1Lx2P|2P‰>Z@]AXBZ†<V‡6QŒ<R—DV¤P_¬cn²fp®mvªjx¥dr–Vg†D[v+Fh#@f"D_<Z2_7`:k>v,N~8P–BV¨GT²DN·HQ \ No newline at end of file
diff --git a/tests/md5.sh b/tests/md5.sh
index 0b382b1..5e2528c 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 2bc49ab..b96d99a 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
297720 tests/data/fate/acodec-adpcm-adx.adx
-2dbc601ed5259f4d74dc48ccd8da7eaf *tests/data/fate/acodec-adpcm-adx.out.wav
+7260139001fcac62384dad50a1023e75 *tests/data/fate/acodec-adpcm-adx.out.wav
stddev: 6989.46 PSNR: 19.44 MAXDIFF:65398 bytes: 1058400/ 1058432
diff --git a/tests/ref/acodec/adpcm-adx-trellis b/tests/ref/acodec/adpcm-adx-trellis
new file mode 100644
index 0000000..fff0291
--- /dev/null
+++ b/tests/ref/acodec/adpcm-adx-trellis
@@ -0,0 +1,4 @@
+0a30509d9296b857e134b762b76dbc31 *tests/data/fate/acodec-adpcm-adx-trellis.adx
+297720 tests/data/fate/acodec-adpcm-adx-trellis.adx
+7260139001fcac62384dad50a1023e75 *tests/data/fate/acodec-adpcm-adx-trellis.out.wav
+stddev: 6989.46 PSNR: 19.44 MAXDIFF:65398 bytes: 1058400/ 1058432
diff --git a/tests/ref/acodec/adpcm-ima_qt b/tests/ref/acodec/adpcm-ima_qt
index 8001527..364dfa1 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 0000000..0a09965
--- /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 6d83fd5..bd3306d 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 0000000..10d78c7
--- /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 eb8515d..c760b78 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 0000000..8587e70
--- /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 fddb771..2cb9e90 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 0000000..a2bb565
--- /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 da60f44..2741058 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 0000000..a099ec5
--- /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 0000000..a50c30a
--- /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 dde0e36..7d6ebe8 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 3ef32c2..c2e7f20 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/g723_1 b/tests/ref/acodec/g723_1
new file mode 100644
index 0000000..e33fe3d
--- /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 42381b4..57b83ac 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 0000000..bf8cc7f
--- /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 28ce960..00555e3 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 5b0f498..b98c0b7 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 681f083..c0fdd70 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 dd882d3..e0e0307 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 c6cb027..5c90e7b 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 bd2a1e8..f5c117d 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 61e5664..a9b4593 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 0000000..3d7d7b1
--- /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 51366ad..5fa80bd 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 0000000..c635c72
--- /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 f673040..916aceb 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 a7e77e2..cf5ae1a 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 0000000..67393d9
--- /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 1b6dec9..5a48bb2 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 1c3e412..47c736b 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 0000000..643659f
--- /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 c947729..14f4c85 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 0000000..301e715
--- /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 0000000..3fd831d
--- /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 0000000..ea724bb
--- /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 0000000..3c19637
--- /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 0000000..b82d6bc
--- /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 0000000..909a130
--- /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 0000000..16a183f
--- /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 80e70ea..c9bf04a 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 0000000..61cb27a
--- /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/fate/4xm-1 b/tests/ref/fate/4xm-1
index d38a47a..37371aa 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 35b0797..cf71357 100644
--- a/tests/ref/fate/4xm-2
+++ b/tests/ref/fate/4xm-2
@@ -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 869d38c..9db9430 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/aasc b/tests/ref/fate/aasc
index 57d59a9..83f83b9 100644
--- a/tests/ref/fate/aasc
+++ b/tests/ref/fate/aasc
@@ -22,3 +22,4 @@
0, 20, 20, 1, 168000, 0x7a2b1006
0, 21, 21, 1, 168000, 0xc7ca1345
0, 22, 22, 1, 168000, 0x8841c413
+0, 23, 23, 1, 168000, 0xbaed0290
diff --git a/tests/ref/fate/acodec-aref b/tests/ref/fate/acodec-aref
new file mode 100644
index 0000000..d70876d
--- /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 0000000..eb5cfe6
--- /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 0000000..d1a1c36
--- /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 0000000..3640e1c
--- /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 6c2fa32..4bd22af 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 0000000..c6f1ee1
--- /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 0000000..c5de1a6
--- /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 45cb97b..3a746b6 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 0000000..90692f1
--- /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/aliaspix-bgr b/tests/ref/fate/aliaspix-bgr
index 235a5ac..8671d3e 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 74cf6a2..0433a36 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 0000000..94acd45
--- /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 c686327..83614c2 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 0000000..5b89c2b
--- /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 0000000..599683a
--- /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/bethsoft-vid b/tests/ref/fate/bethsoft-vid
index 535888b..9f96da1 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/bmpparser b/tests/ref/fate/bmpparser
index e7022b1..3cdd986 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 0000000..b33c1ae
--- /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 0000000..d183b3f
--- /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 c96468a..87cf9ca 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 dccb2b5..a782059 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 e4071a9..8060f06 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: 12/601
+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 25886b2..6426d45 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 356ad1b..269f1f3 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: 3/158
+0, 0, 0, 1, 67584, 0xce0cade5
diff --git a/tests/ref/fate/cdxl-pal8 b/tests/ref/fate/cdxl-pal8
index f5c319a..82d4d63 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: 12/601
+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 d285e9a..f7a1a46 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 0000000..bb7ac70
--- /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 f73c8c0..5842541 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/cllc-argb b/tests/ref/fate/cllc-argb
index 0283863..4a5dce5 100644
--- a/tests/ref/fate/cllc-argb
+++ b/tests/ref/fate/cllc-argb
@@ -3,3 +3,4 @@
0, 1, 1, 1, 3686400, 0x66a45032
0, 2, 2, 1, 3686400, 0xdf0c861f
0, 3, 3, 1, 3686400, 0xa4a68cdb
+0, 4, 4, 1, 3686400, 0xb5f9526e
diff --git a/tests/ref/fate/cllc-rgb b/tests/ref/fate/cllc-rgb
index 06d54da..b4ca055 100644
--- a/tests/ref/fate/cllc-rgb
+++ b/tests/ref/fate/cllc-rgb
@@ -13,3 +13,4 @@
0, 11, 11, 1, 921600, 0x4d7488fa
0, 12, 12, 1, 921600, 0x16b9c9c9
0, 13, 13, 1, 921600, 0xa0a4f77f
+0, 14, 14, 1, 921600, 0xf61a5501
diff --git a/tests/ref/fate/cllc-yuy2-noblock b/tests/ref/fate/cllc-yuy2-noblock
index 2cb9e78..6ad59d5 100644
--- a/tests/ref/fate/cllc-yuy2-noblock
+++ b/tests/ref/fate/cllc-yuy2-noblock
@@ -14,3 +14,4 @@
0, 12, 12, 1, 614400, 0x2d8fd7cc
0, 13, 13, 1, 614400, 0xd9dfc2ef
0, 14, 14, 1, 614400, 0xaf95cef0
+0, 15, 15, 1, 614400, 0x6dcf5ed6
diff --git a/tests/ref/fate/crc b/tests/ref/fate/crc
index 80bb0ea..8aa0dd2 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 979baf6..4c721d8 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 87ca600..1b586b3 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 5fcbc51..49de1c1 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 71596b4..bb368a1 100644
--- a/tests/ref/fate/cvid-partial
+++ b/tests/ref/fate/cvid-partial
@@ -1,79 +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, 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 f663040..2f28e46 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 92a7cce..7bc5bf1 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 a140e5c..a799f03 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 3990d24..30b4b71 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 a050c97..cc4b454 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 8c91faa..9b170ec 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 67b5722..0e0dc02 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 b9f7727..3be3c52 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 92ed259..535f98b 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 7dd40f2..28122c5 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 39dde05..866260a 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 cf24e3e..99eb3f6 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/dirac b/tests/ref/fate/dirac
new file mode 100644
index 0000000..7781b4e
--- /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/ea-cmv b/tests/ref/fate/ea-cmv
index 18f2b3a..8f9049e 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 b01e5a5..914b13c 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 0000000..d0fad03
--- /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 0000000..7b303cd
--- /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 0000000..2b10529
--- /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 0000000..88e3c82
--- /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 0000000..54d318d
--- /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 0000000..54d318d
--- /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 0000000..b7526f4
--- /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|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|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|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|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 0000000..78060da
--- /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,0,1:1,4:3,rgb24,-99,N/A,unknown,unknown,unknown,unspecified,N/A,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,0,1:1,1:1,rgb24,-99,N/A,unknown,unknown,unknown,unspecified,N/A,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 0000000..dcf4e25
--- /dev/null
+++ b/tests/ref/fate/ffprobe_default
@@ -0,0 +1,663 @@
+[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
+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
+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
+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
+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 0000000..c1e6b1a
--- /dev/null
+++ b/tests/ref/fate/ffprobe_flat
@@ -0,0 +1,599 @@
+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.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.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.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.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 0000000..b2ae271
--- /dev/null
+++ b/tests/ref/fate/ffprobe_ini
@@ -0,0 +1,678 @@
+# 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
+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
+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
+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
+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 0000000..29e8fe0
--- /dev/null
+++ b/tests/ref/fate/ffprobe_json
@@ -0,0 +1,641 @@
+{
+ "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,
+ "has_b_frames": 0,
+ "sample_aspect_ratio": "1:1",
+ "display_aspect_ratio": "4:3",
+ "pix_fmt": "rgb24",
+ "level": -99,
+ "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,
+ "has_b_frames": 0,
+ "sample_aspect_ratio": "1:1",
+ "display_aspect_ratio": "1:1",
+ "pix_fmt": "rgb24",
+ "level": -99,
+ "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 0000000..90353c4
--- /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" has_b_frames="0" sample_aspect_ratio="1:1" display_aspect_ratio="4:3" pix_fmt="rgb24" level="-99" 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" has_b_frames="0" sample_aspect_ratio="1:1" display_aspect_ratio="1:1" pix_fmt="rgb24" level="-99" 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/fic-avi b/tests/ref/fate/fic-avi
index e2b26a3..cc4ea5d 100644
--- a/tests/ref/fate/fic-avi
+++ b/tests/ref/fate/fic-avi
@@ -119,3 +119,4 @@
0, 117, 117, 1, 1566720, 0xfe83b964
0, 118, 118, 1, 1566720, 0x25dc30a6
0, 119, 119, 1, 1566720, 0x25dc30a6
+0, 120, 120, 1, 1566720, 0x25dc30a6
diff --git a/tests/ref/fate/film-cvid b/tests/ref/fate/film-cvid
index 12b1f1c..3ca7b59 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 0000000..91e1d4c
--- /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 0000000..013f6a3
--- /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 0000000..92b70d9
--- /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 0000000..ac1c584
--- /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 0000000..1b1a48d
--- /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 0000000..37c3486
--- /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 0000000..82b571f
--- /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, 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, 0x23c418ae
+0, 40, 40, 1, 276480, 0x70ac4c76
+0, 41, 41, 1, 276480, 0x166ef020
+0, 42, 42, 1, 276480, 0xaa0614ab
+0, 43, 43, 1, 276480, 0x8bc2fa2b
+0, 44, 44, 1, 276480, 0x07956a97
+0, 45, 45, 1, 276480, 0x6fcb808b
+0, 46, 46, 1, 276480, 0x841cf493
+0, 47, 47, 1, 276480, 0xe7834514
+0, 48, 48, 1, 276480, 0xb805fcb1
+0, 49, 49, 1, 276480, 0xe29bacc8
+0, 50, 50, 1, 276480, 0x6b79c3d3
+0, 51, 51, 1, 276480, 0x798c35c6
+0, 52, 52, 1, 276480, 0x1b31d2ed
+0, 53, 53, 1, 276480, 0x6ceebf3e
+0, 54, 54, 1, 276480, 0x7ac8de3c
+0, 55, 55, 1, 276480, 0x14d6768c
+0, 56, 56, 1, 276480, 0xcb08af08
+0, 57, 57, 1, 276480, 0xed3053ea
+0, 58, 58, 1, 276480, 0x015782fb
+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 0000000..4e9e9d3
--- /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 0000000..265f956
--- /dev/null
+++ b/tests/ref/fate/filter-colormatrix1
@@ -0,0 +1 @@
+colormatrix1 a5a26833c0feec3220af855ed36987b0
diff --git a/tests/ref/fate/filter-colormatrix2 b/tests/ref/fate/filter-colormatrix2
new file mode 100644
index 0000000..4e96587
--- /dev/null
+++ b/tests/ref/fate/filter-colormatrix2
@@ -0,0 +1 @@
+colormatrix2 2c81a2a1bfcba0768e00f0fc5ab7bf5a
diff --git a/tests/ref/fate/filter-concat b/tests/ref/fate/filter-concat
new file mode 100644
index 0000000..73e4185
--- /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 32041c2..0295d8d 100644
--- a/tests/ref/fate/filter-crop
+++ b/tests/ref/fate/filter-crop
@@ -1 +1 @@
-crop 3d163f156eaddf41d2be20736f973539
+crop 75217686e926f7541a200ecf88aa2c12
diff --git a/tests/ref/fate/filter-crop_scale b/tests/ref/fate/filter-crop_scale
index 82e5394..4658df4 100644
--- a/tests/ref/fate/filter-crop_scale
+++ b/tests/ref/fate/filter-crop_scale
@@ -1 +1 @@
-crop_scale 0a3d45d58b805b8c47416b9239535f94
+crop_scale 3aac5217ef443c41ad850959d9c5da6c
diff --git a/tests/ref/fate/filter-crop_scale_vflip b/tests/ref/fate/filter-crop_scale_vflip
index 29574f7..2afa7b6 100644
--- a/tests/ref/fate/filter-crop_scale_vflip
+++ b/tests/ref/fate/filter-crop_scale_vflip
@@ -1 +1 @@
-crop_scale_vflip 3e2c7694d37733ca52e1723d5262af36
+crop_scale_vflip 368e9ce823b95ab344bd90fc4d0288b8
diff --git a/tests/ref/fate/filter-crop_vflip b/tests/ref/fate/filter-crop_vflip
index a3f8200..e13ed4b 100644
--- a/tests/ref/fate/filter-crop_vflip
+++ b/tests/ref/fate/filter-crop_vflip
@@ -1 +1 @@
-crop_vflip 628542e17b6900ee79b1429183ae01b0
+crop_vflip 23f6190695a24f9d98ba6143623cccd6
diff --git a/tests/ref/fate/filter-curves b/tests/ref/fate/filter-curves
new file mode 100644
index 0000000..a96f0ee
--- /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 1a1f497..80342ee 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 869b9f3..c63d2fc 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 0000000..fb2a917
--- /dev/null
+++ b/tests/ref/fate/filter-edgedetect
@@ -0,0 +1 @@
+edgedetect bcbaea799d3585c4235fc342ecd3591d
diff --git a/tests/ref/fate/filter-edgedetect-colormix b/tests/ref/fate/filter-edgedetect-colormix
new file mode 100644
index 0000000..f6f9b87
--- /dev/null
+++ b/tests/ref/fate/filter-edgedetect-colormix
@@ -0,0 +1 @@
+edgedetect-colormix 7a25ca606e18344ab4d82382b787e4da
diff --git a/tests/ref/fate/filter-fade b/tests/ref/fate/filter-fade
index 131b614..9d691ce 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-framepack-frameseq b/tests/ref/fate/filter-framepack-frameseq
index 83c08a0..c3d2a15 100644
--- a/tests/ref/fate/filter-framepack-frameseq
+++ b/tests/ref/fate/filter-framepack-frameseq
@@ -1,16 +1,16 @@
-#tb 0: 1/50
+#tb 0: 1/25
0, 0, 0, 1, 152064, 0x05b789ef
0, 1, 1, 1, 152064, 0x05b789ef
0, 2, 2, 1, 152064, 0x4bb46551
-0, 3, 3, 1, 152064, 0x4bb46551
-0, 4, 4, 1, 152064, 0x9dddf64a
-0, 5, 5, 1, 152064, 0x9dddf64a
-0, 6, 6, 1, 152064, 0x2a8380b0
-0, 7, 7, 1, 152064, 0x2a8380b0
-0, 8, 8, 1, 152064, 0x4de3b652
-0, 9, 9, 1, 152064, 0x4de3b652
-0, 10, 10, 1, 152064, 0xedb5a8e6
-0, 11, 11, 1, 152064, 0xedb5a8e6
-0, 12, 12, 1, 152064, 0xe20f7c23
-0, 13, 13, 1, 152064, 0xe20f7c23
-0, 14, 14, 1, 152064, 0x5ab58bac
+0, 3, 3, 1, 152064, 0x9dddf64a
+0, 4, 4, 1, 152064, 0x2a8380b0
+0, 5, 5, 1, 152064, 0x4de3b652
+0, 6, 6, 1, 152064, 0xedb5a8e6
+0, 7, 7, 1, 152064, 0xe20f7c23
+0, 8, 8, 1, 152064, 0x5ab58bac
+0, 9, 9, 1, 152064, 0x1f1b8026
+0, 10, 10, 1, 152064, 0x91373915
+0, 11, 11, 1, 152064, 0x02344760
+0, 12, 12, 1, 152064, 0x30f5fcd5
+0, 13, 13, 1, 152064, 0xc711ad61
+0, 14, 14, 1, 152064, 0x24eca223
diff --git a/tests/ref/fate/filter-gradfun-sample b/tests/ref/fate/filter-gradfun-sample
new file mode 100644
index 0000000..595f82a
--- /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 0000000..df9f6b2
--- /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 0000000..da6bbc4
--- /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 0000000..dcf2a29
--- /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 0000000..8215388
--- /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 0000000..c1d6fd8
--- /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 0000000..97718f9
--- /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 0000000..527b202
--- /dev/null
+++ b/tests/ref/fate/filter-hue
@@ -0,0 +1 @@
+hue 2c8a14eff52333355f59f81fab43aedf
diff --git a/tests/ref/fate/filter-idet b/tests/ref/fate/filter-idet
new file mode 100644
index 0000000..2f9f11c
--- /dev/null
+++ b/tests/ref/fate/filter-idet
@@ -0,0 +1 @@
+idet 005e6ddc8a5daf11cf866a1ec76c2572
diff --git a/tests/ref/fate/filter-lavd-life b/tests/ref/fate/filter-lavd-life
new file mode 100644
index 0000000..565f88a
--- /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 0000000..c946b5c
--- /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 0000000..0ea5a49
--- /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 0000000..000d43b
--- /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 0000000..80ba484
--- /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, 0xc69368eb
+0, 11, 11, 1, 622080, 0x76bdde33
+0, 12, 12, 1, 622080, 0x5a04d7a6
+0, 13, 13, 1, 622080, 0x68eacaec
+0, 14, 14, 1, 622080, 0x1e888865
+0, 15, 15, 1, 622080, 0x188ad805
+0, 16, 16, 1, 622080, 0x268e94ce
+0, 17, 17, 1, 622080, 0x89da806c
+0, 18, 18, 1, 622080, 0x507ec6c9
+0, 19, 19, 1, 622080, 0xf20ba69b
+0, 20, 20, 1, 622080, 0x5786a96e
+0, 21, 21, 1, 622080, 0xf9d2fd6e
+0, 22, 22, 1, 622080, 0x4b69ef51
+0, 23, 23, 1, 622080, 0x19a22b06
+0, 24, 24, 1, 622080, 0x13a30e94
+0, 25, 25, 1, 622080, 0x02435f86
+0, 26, 26, 1, 622080, 0x06794a00
+0, 27, 27, 1, 622080, 0x289e8aea
+0, 28, 28, 1, 622080, 0x494ab1a4
+0, 29, 29, 1, 622080, 0xc1c6f5da
+0, 30, 30, 1, 622080, 0x1f6d6764
+0, 31, 31, 1, 622080, 0xaa898832
+0, 32, 32, 1, 622080, 0x6935c412
+0, 33, 33, 1, 622080, 0x825e2a67
+0, 34, 34, 1, 622080, 0xd8ee113a
+0, 35, 35, 1, 622080, 0x9ffc7f17
+0, 36, 36, 1, 622080, 0xa7819ac8
+0, 37, 37, 1, 622080, 0xa412377d
+0, 38, 38, 1, 622080, 0x538376bc
diff --git a/tests/ref/fate/filter-metadata-ebur128 b/tests/ref/fate/filter-metadata-ebur128
new file mode 100644
index 0000000..7a060bd
--- /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 0000000..d04054a
--- /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 0000000..4161287
--- /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 3c3b7b7..b59e1c1 100644
--- a/tests/ref/fate/filter-null
+++ b/tests/ref/fate/filter-null
@@ -1 +1 @@
-null eba2f135a08829387e2f698ff72a2939
+null 005e6ddc8a5daf11cf866a1ec76c2572
diff --git a/tests/ref/fate/filter-overlay b/tests/ref/fate/filter-overlay
index d988a2e..f0f03d6 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 0000000..cb94aa5
--- /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 0000000..a1f6787
--- /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 0000000..982386b
--- /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 0000000..0b2d9f7
--- /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 0000000..07d2a07
--- /dev/null
+++ b/tests/ref/fate/filter-pad
@@ -0,0 +1 @@
+pad 91fb048d7b2b4b4b5b6b3a46e6240adf
diff --git a/tests/ref/fate/filter-phase b/tests/ref/fate/filter-phase
new file mode 100644
index 0000000..e0ec8d6
--- /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 0000000..fff82e7
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-0bgr
@@ -0,0 +1 @@
+pixdesc-0bgr 567bba091d0c8148a892b826c52d1e73
diff --git a/tests/ref/fate/filter-pixdesc-0rgb b/tests/ref/fate/filter-pixdesc-0rgb
new file mode 100644
index 0000000..fe8e22a
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-0rgb
@@ -0,0 +1 @@
+pixdesc-0rgb 81f013e1d0da78e347aac45e57007187
diff --git a/tests/ref/fate/filter-pixdesc-abgr b/tests/ref/fate/filter-pixdesc-abgr
index ac8513e..ebf8413 100644
--- a/tests/ref/fate/filter-pixdesc-abgr
+++ b/tests/ref/fate/filter-pixdesc-abgr
@@ -1 +1 @@
-pixdesc-abgr 037bf9df6a765520ad6d490066bf4b89
+pixdesc-abgr 0d93666da1532ca69c1a3e2ee0248430
diff --git a/tests/ref/fate/filter-pixdesc-argb b/tests/ref/fate/filter-pixdesc-argb
index 3b81bfe..367b86d 100644
--- a/tests/ref/fate/filter-pixdesc-argb
+++ b/tests/ref/fate/filter-pixdesc-argb
@@ -1 +1 @@
-pixdesc-argb c442a8261c2265a07212ef0f72e35f5a
+pixdesc-argb 86f5041b9245930bc6977d4f2babf74d
diff --git a/tests/ref/fate/filter-pixdesc-bgr0 b/tests/ref/fate/filter-pixdesc-bgr0
new file mode 100644
index 0000000..78c7191
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-bgr0
@@ -0,0 +1 @@
+pixdesc-bgr0 5f7fdabb606edcd0db80684da021f6c9
diff --git a/tests/ref/fate/filter-pixdesc-bgr24 b/tests/ref/fate/filter-pixdesc-bgr24
index 76b6dfc..852ed8f 100644
--- a/tests/ref/fate/filter-pixdesc-bgr24
+++ b/tests/ref/fate/filter-pixdesc-bgr24
@@ -1 +1 @@
-pixdesc-bgr24 0d0cb38ab3fa0b2ec0865c14f78b217b
+pixdesc-bgr24 fd0c957cabb399b3dda29e1190e6cfac
diff --git a/tests/ref/fate/filter-pixdesc-bgr444be b/tests/ref/fate/filter-pixdesc-bgr444be
index e5a8819..937d8ba 100644
--- a/tests/ref/fate/filter-pixdesc-bgr444be
+++ b/tests/ref/fate/filter-pixdesc-bgr444be
@@ -1 +1 @@
-pixdesc-bgr444be d9ea9307d21b162225b8b2c524cf9477
+pixdesc-bgr444be 96d828ff1ea24858100e0afcef6f6201
diff --git a/tests/ref/fate/filter-pixdesc-bgr444le b/tests/ref/fate/filter-pixdesc-bgr444le
index 8bda95c..b785ae4 100644
--- a/tests/ref/fate/filter-pixdesc-bgr444le
+++ b/tests/ref/fate/filter-pixdesc-bgr444le
@@ -1 +1 @@
-pixdesc-bgr444le 88035350e9da3a8f67387890b956f0bc
+pixdesc-bgr444le 5a43d10a7890378368073be08141f967
diff --git a/tests/ref/fate/filter-pixdesc-bgr48be b/tests/ref/fate/filter-pixdesc-bgr48be
index f87f3fa..b7933e3 100644
--- a/tests/ref/fate/filter-pixdesc-bgr48be
+++ b/tests/ref/fate/filter-pixdesc-bgr48be
@@ -1 +1 @@
-pixdesc-bgr48be 00624e6c7ec7ab19897ba2f0a3257fe8
+pixdesc-bgr48be 65986a0555423c910db4820732565a5e
diff --git a/tests/ref/fate/filter-pixdesc-bgr48le b/tests/ref/fate/filter-pixdesc-bgr48le
index 738a4a9..a7fe428 100644
--- a/tests/ref/fate/filter-pixdesc-bgr48le
+++ b/tests/ref/fate/filter-pixdesc-bgr48le
@@ -1 +1 @@
-pixdesc-bgr48le d02c235ebba7167881ca2d576497ff84
+pixdesc-bgr48le 3050e56ee66fa61d8dd88b12f4b2f956
diff --git a/tests/ref/fate/filter-pixdesc-bgr4_byte b/tests/ref/fate/filter-pixdesc-bgr4_byte
index fa465d2..68d8343 100644
--- a/tests/ref/fate/filter-pixdesc-bgr4_byte
+++ b/tests/ref/fate/filter-pixdesc-bgr4_byte
@@ -1 +1 @@
-pixdesc-bgr4_byte 50d23cc82d9dcef2fd12adb81fb9b806
+pixdesc-bgr4_byte 6d8ea0cb6b4cadace60222063a847630
diff --git a/tests/ref/fate/filter-pixdesc-bgr555be b/tests/ref/fate/filter-pixdesc-bgr555be
index 0e137bb..02367a1 100644
--- a/tests/ref/fate/filter-pixdesc-bgr555be
+++ b/tests/ref/fate/filter-pixdesc-bgr555be
@@ -1 +1 @@
-pixdesc-bgr555be 49f01b1f1f0c84fd9e776dd34cc3c280
+pixdesc-bgr555be 90ffbd6a7850f25253977aecf84e229e
diff --git a/tests/ref/fate/filter-pixdesc-bgr555le b/tests/ref/fate/filter-pixdesc-bgr555le
index 9c7ca5b..796b0a9 100644
--- a/tests/ref/fate/filter-pixdesc-bgr555le
+++ b/tests/ref/fate/filter-pixdesc-bgr555le
@@ -1 +1 @@
-pixdesc-bgr555le 378d6ac4223651a1adcbf94a3d0d807b
+pixdesc-bgr555le 9f800958e9c238c9441fef9799ab2a8d
diff --git a/tests/ref/fate/filter-pixdesc-bgr565be b/tests/ref/fate/filter-pixdesc-bgr565be
index 1d71f7e..8e549a0 100644
--- a/tests/ref/fate/filter-pixdesc-bgr565be
+++ b/tests/ref/fate/filter-pixdesc-bgr565be
@@ -1 +1 @@
-pixdesc-bgr565be 257cf78afa35dc31e9696f139c916715
+pixdesc-bgr565be 0e7c46857a3bebc2e3bb77ae68cc0bad
diff --git a/tests/ref/fate/filter-pixdesc-bgr565le b/tests/ref/fate/filter-pixdesc-bgr565le
index bfe2b9d..f993392 100644
--- a/tests/ref/fate/filter-pixdesc-bgr565le
+++ b/tests/ref/fate/filter-pixdesc-bgr565le
@@ -1 +1 @@
-pixdesc-bgr565le 1dfdd03995c287e3c754b164bf26a355
+pixdesc-bgr565le 31c0b9b6bc009a4bfa4421c3bbb2ff39
diff --git a/tests/ref/fate/filter-pixdesc-bgr8 b/tests/ref/fate/filter-pixdesc-bgr8
index 2aa9b9a..013ba83 100644
--- a/tests/ref/fate/filter-pixdesc-bgr8
+++ b/tests/ref/fate/filter-pixdesc-bgr8
@@ -1 +1 @@
-pixdesc-bgr8 24bd566170343d06fec6fccfff5abc54
+pixdesc-bgr8 775803c35cf19b2fc84f537ce5a7e262
diff --git a/tests/ref/fate/filter-pixdesc-bgra b/tests/ref/fate/filter-pixdesc-bgra
index 6896fbd..f368323 100644
--- a/tests/ref/fate/filter-pixdesc-bgra
+++ b/tests/ref/fate/filter-pixdesc-bgra
@@ -1 +1 @@
-pixdesc-bgra 76a18a5151242fa137133f604cd624d2
+pixdesc-bgra 020a3623e3ad6ea398d6adfcba9e510c
diff --git a/tests/ref/fate/filter-pixdesc-bgra64be b/tests/ref/fate/filter-pixdesc-bgra64be
new file mode 100644
index 0000000..9e88c5a
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-bgra64be
@@ -0,0 +1 @@
+pixdesc-bgra64be ce8e864307b8f11d1bc4a92f3384416b
diff --git a/tests/ref/fate/filter-pixdesc-bgra64le b/tests/ref/fate/filter-pixdesc-bgra64le
new file mode 100644
index 0000000..87847fb
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-bgra64le
@@ -0,0 +1 @@
+pixdesc-bgra64le fa2e6435c1f7f498d5714898e120dd89
diff --git a/tests/ref/fate/filter-pixdesc-gbrap b/tests/ref/fate/filter-pixdesc-gbrap
new file mode 100644
index 0000000..13dae79
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-gbrap
@@ -0,0 +1 @@
+pixdesc-gbrap dcf43e62881e69a873382c12d3afe0a4
diff --git a/tests/ref/fate/filter-pixdesc-gbrp b/tests/ref/fate/filter-pixdesc-gbrp
index cbcaac8..cd9b3e1 100644
--- a/tests/ref/fate/filter-pixdesc-gbrp
+++ b/tests/ref/fate/filter-pixdesc-gbrp
@@ -1 +1 @@
-pixdesc-gbrp 76204621e200a3cc633012f6720c7005
+pixdesc-gbrp 78a26e285e0f6ee73f37d70621e659fe
diff --git a/tests/ref/fate/filter-pixdesc-gbrp10be b/tests/ref/fate/filter-pixdesc-gbrp10be
index b7e4976..8a0a8e3 100644
--- a/tests/ref/fate/filter-pixdesc-gbrp10be
+++ b/tests/ref/fate/filter-pixdesc-gbrp10be
@@ -1 +1 @@
-pixdesc-gbrp10be 2ca4a4a589a7dc461ff186913c7a69e5
+pixdesc-gbrp10be d325f4f209bf460f8ff7d37bc51978dd
diff --git a/tests/ref/fate/filter-pixdesc-gbrp10le b/tests/ref/fate/filter-pixdesc-gbrp10le
index a9750f7..5a575e1 100644
--- a/tests/ref/fate/filter-pixdesc-gbrp10le
+++ b/tests/ref/fate/filter-pixdesc-gbrp10le
@@ -1 +1 @@
-pixdesc-gbrp10le 46176f1fcc6e67f9862115fe373f73d3
+pixdesc-gbrp10le c2328ae0384eeb34b1ac83726b385f46
diff --git a/tests/ref/fate/filter-pixdesc-gbrp12be b/tests/ref/fate/filter-pixdesc-gbrp12be
new file mode 100644
index 0000000..252d647
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-gbrp12be
@@ -0,0 +1 @@
+pixdesc-gbrp12be 8aa22995644b2796ecafc10dec5f3bd8
diff --git a/tests/ref/fate/filter-pixdesc-gbrp12le b/tests/ref/fate/filter-pixdesc-gbrp12le
new file mode 100644
index 0000000..481e807
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-gbrp12le
@@ -0,0 +1 @@
+pixdesc-gbrp12le df4badcfdf6701e03809ef5a278297b8
diff --git a/tests/ref/fate/filter-pixdesc-gbrp14be b/tests/ref/fate/filter-pixdesc-gbrp14be
new file mode 100644
index 0000000..1cb037f
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-gbrp14be
@@ -0,0 +1 @@
+pixdesc-gbrp14be a02a13caee9af458c5039c697ab896a6
diff --git a/tests/ref/fate/filter-pixdesc-gbrp14le b/tests/ref/fate/filter-pixdesc-gbrp14le
new file mode 100644
index 0000000..5b60a09
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-gbrp14le
@@ -0,0 +1 @@
+pixdesc-gbrp14le 4f521b6e69078bd0eca8dfcfde0f6ef6
diff --git a/tests/ref/fate/filter-pixdesc-gbrp9be b/tests/ref/fate/filter-pixdesc-gbrp9be
index 50261c4..8593f71 100644
--- a/tests/ref/fate/filter-pixdesc-gbrp9be
+++ b/tests/ref/fate/filter-pixdesc-gbrp9be
@@ -1 +1 @@
-pixdesc-gbrp9be 981c2c1b0ef1791824b4c7518331bc2e
+pixdesc-gbrp9be 397280799d9e78f48670664491e62524
diff --git a/tests/ref/fate/filter-pixdesc-gbrp9le b/tests/ref/fate/filter-pixdesc-gbrp9le
index 9a59a9b..1cf277e 100644
--- a/tests/ref/fate/filter-pixdesc-gbrp9le
+++ b/tests/ref/fate/filter-pixdesc-gbrp9le
@@ -1 +1 @@
-pixdesc-gbrp9le 25fb915ed11d07d631e0e7b78d54bebf
+pixdesc-gbrp9le dbf020fa8423e170f2624ddba9f2c945
diff --git a/tests/ref/fate/filter-pixdesc-gray b/tests/ref/fate/filter-pixdesc-gray
index 6900fe2..b710439 100644
--- a/tests/ref/fate/filter-pixdesc-gray
+++ b/tests/ref/fate/filter-pixdesc-gray
@@ -1 +1 @@
-pixdesc-gray db08f7f0751900347e6b8649e4164d21
+pixdesc-gray 19ae78946e6acc3b552daa61b44a8ca1
diff --git a/tests/ref/fate/filter-pixdesc-gray16be b/tests/ref/fate/filter-pixdesc-gray16be
index dcf6713..30153f2 100644
--- a/tests/ref/fate/filter-pixdesc-gray16be
+++ b/tests/ref/fate/filter-pixdesc-gray16be
@@ -1 +1 @@
-pixdesc-gray16be 7becf34ae825a3df3969bf4c6bfeb5e2
+pixdesc-gray16be 2665aebcabc71b30a2252308b1335a81
diff --git a/tests/ref/fate/filter-pixdesc-gray16le b/tests/ref/fate/filter-pixdesc-gray16le
index 9ac4dd3..1ad6a12 100644
--- a/tests/ref/fate/filter-pixdesc-gray16le
+++ b/tests/ref/fate/filter-pixdesc-gray16le
@@ -1 +1 @@
-pixdesc-gray16le 10bd87059b5c189f3caef2837f4f2b5c
+pixdesc-gray16le f35d7d9b8cac96c5ac25c2cd4b42443b
diff --git a/tests/ref/fate/filter-pixdesc-monob b/tests/ref/fate/filter-pixdesc-monob
index 6405cb4..ed626a9 100644
--- a/tests/ref/fate/filter-pixdesc-monob
+++ b/tests/ref/fate/filter-pixdesc-monob
@@ -1 +1 @@
-pixdesc-monob 668ebe8b8103b9046b251b2fa8a1d88f
+pixdesc-monob d2b84b01179f38ce59a7050064d42289
diff --git a/tests/ref/fate/filter-pixdesc-monow b/tests/ref/fate/filter-pixdesc-monow
index 657f98f..bafc96e 100644
--- a/tests/ref/fate/filter-pixdesc-monow
+++ b/tests/ref/fate/filter-pixdesc-monow
@@ -1 +1 @@
-pixdesc-monow 9251497f3b0634f1165d12d5a289d943
+pixdesc-monow 550a446b7900a42990d76befca7f08a0
diff --git a/tests/ref/fate/filter-pixdesc-nv12 b/tests/ref/fate/filter-pixdesc-nv12
index f42f406..37893a2 100644
--- a/tests/ref/fate/filter-pixdesc-nv12
+++ b/tests/ref/fate/filter-pixdesc-nv12
@@ -1 +1 @@
-pixdesc-nv12 e0af357888584d36eec5aa0f673793ef
+pixdesc-nv12 18aaac3efcb2e389bfa2ade34b917634
diff --git a/tests/ref/fate/filter-pixdesc-nv21 b/tests/ref/fate/filter-pixdesc-nv21
index 65e7e7b..f4e7cb9 100644
--- a/tests/ref/fate/filter-pixdesc-nv21
+++ b/tests/ref/fate/filter-pixdesc-nv21
@@ -1 +1 @@
-pixdesc-nv21 9a3297f3b34baa038b1f37cb202b512f
+pixdesc-nv21 cb3b54dcc21c72943d496e6368b0c00b
diff --git a/tests/ref/fate/filter-pixdesc-rgb0 b/tests/ref/fate/filter-pixdesc-rgb0
new file mode 100644
index 0000000..fa8d0af
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-rgb0
@@ -0,0 +1 @@
+pixdesc-rgb0 62028885ff1adc3368c378748a80be71
diff --git a/tests/ref/fate/filter-pixdesc-rgb24 b/tests/ref/fate/filter-pixdesc-rgb24
index dcbf91f..424ad81 100644
--- a/tests/ref/fate/filter-pixdesc-rgb24
+++ b/tests/ref/fate/filter-pixdesc-rgb24
@@ -1 +1 @@
-pixdesc-rgb24 b41eba9651e1b5fe386289b506188105
+pixdesc-rgb24 273cfae99e5951d567f230beec3e3eeb
diff --git a/tests/ref/fate/filter-pixdesc-rgb444be b/tests/ref/fate/filter-pixdesc-rgb444be
index cd87cc2..4fa6f6f 100644
--- a/tests/ref/fate/filter-pixdesc-rgb444be
+++ b/tests/ref/fate/filter-pixdesc-rgb444be
@@ -1 +1 @@
-pixdesc-rgb444be 9e89db334568c6b2e3d5d0540f4ba960
+pixdesc-rgb444be d90556c864a78c45ca9e2c27130067cd
diff --git a/tests/ref/fate/filter-pixdesc-rgb444le b/tests/ref/fate/filter-pixdesc-rgb444le
index d193db3..603c060 100644
--- a/tests/ref/fate/filter-pixdesc-rgb444le
+++ b/tests/ref/fate/filter-pixdesc-rgb444le
@@ -1 +1 @@
-pixdesc-rgb444le 0a68cb6de8bf530aa30c5c1205c25155
+pixdesc-rgb444le fe271368f267be87eb8f5b46335ba6dc
diff --git a/tests/ref/fate/filter-pixdesc-rgb48be b/tests/ref/fate/filter-pixdesc-rgb48be
index fe4c50e..9df990b 100644
--- a/tests/ref/fate/filter-pixdesc-rgb48be
+++ b/tests/ref/fate/filter-pixdesc-rgb48be
@@ -1 +1 @@
-pixdesc-rgb48be cc139ec1dd9451f0e049c0cb3a0c8aa2
+pixdesc-rgb48be 434c2ce989de629050e53e820b6929b6
diff --git a/tests/ref/fate/filter-pixdesc-rgb48le b/tests/ref/fate/filter-pixdesc-rgb48le
index b340208..74737f7 100644
--- a/tests/ref/fate/filter-pixdesc-rgb48le
+++ b/tests/ref/fate/filter-pixdesc-rgb48le
@@ -1 +1 @@
-pixdesc-rgb48le 86c5608904f75360d492dbc5c9589969
+pixdesc-rgb48le e04c4a36ea9f9c5624ebd56463b593fe
diff --git a/tests/ref/fate/filter-pixdesc-rgb4_byte b/tests/ref/fate/filter-pixdesc-rgb4_byte
index d44d559..d422ee7 100644
--- a/tests/ref/fate/filter-pixdesc-rgb4_byte
+++ b/tests/ref/fate/filter-pixdesc-rgb4_byte
@@ -1 +1 @@
-pixdesc-rgb4_byte c93ba89b74c504e7f5ae9d9ab1546c73
+pixdesc-rgb4_byte 77c49fda8c97ffc25678d8a51f7056ca
diff --git a/tests/ref/fate/filter-pixdesc-rgb555be b/tests/ref/fate/filter-pixdesc-rgb555be
index a15e67f..76705e9 100644
--- a/tests/ref/fate/filter-pixdesc-rgb555be
+++ b/tests/ref/fate/filter-pixdesc-rgb555be
@@ -1 +1 @@
-pixdesc-rgb555be 912a62c5e53bfcbac2a0340e10973cf2
+pixdesc-rgb555be cb820a51149ba9944480bad7e1260abc
diff --git a/tests/ref/fate/filter-pixdesc-rgb555le b/tests/ref/fate/filter-pixdesc-rgb555le
index 4a7e709..6d0e61b 100644
--- a/tests/ref/fate/filter-pixdesc-rgb555le
+++ b/tests/ref/fate/filter-pixdesc-rgb555le
@@ -1 +1 @@
-pixdesc-rgb555le a937a0fc764fb57dc1b3af87cba0273c
+pixdesc-rgb555le dc18e2fec8f39ebfd5b479fa6c5fe717
diff --git a/tests/ref/fate/filter-pixdesc-rgb565be b/tests/ref/fate/filter-pixdesc-rgb565be
index 7ed206b..62cbb3b 100644
--- a/tests/ref/fate/filter-pixdesc-rgb565be
+++ b/tests/ref/fate/filter-pixdesc-rgb565be
@@ -1 +1 @@
-pixdesc-rgb565be 9cadf742e05ddc23a3b5b270f89aad3c
+pixdesc-rgb565be 0a7a10645295397cd6cbd6eadce71c8e
diff --git a/tests/ref/fate/filter-pixdesc-rgb565le b/tests/ref/fate/filter-pixdesc-rgb565le
index b4648dd..46c5935 100644
--- a/tests/ref/fate/filter-pixdesc-rgb565le
+++ b/tests/ref/fate/filter-pixdesc-rgb565le
@@ -1 +1 @@
-pixdesc-rgb565le d39aa298bb525e9be8860351c6f62dab
+pixdesc-rgb565le 7454e27a0e2c2c37c67e5361a82dd445
diff --git a/tests/ref/fate/filter-pixdesc-rgb8 b/tests/ref/fate/filter-pixdesc-rgb8
index ccc0940..da3f48f 100644
--- a/tests/ref/fate/filter-pixdesc-rgb8
+++ b/tests/ref/fate/filter-pixdesc-rgb8
@@ -1 +1 @@
-pixdesc-rgb8 4a9d8e4f2f154e83a7e1735be6300700
+pixdesc-rgb8 7b602ac8a68dd95ad639f741be805a0d
diff --git a/tests/ref/fate/filter-pixdesc-rgba b/tests/ref/fate/filter-pixdesc-rgba
index a5b64a5..b1d0b5e 100644
--- a/tests/ref/fate/filter-pixdesc-rgba
+++ b/tests/ref/fate/filter-pixdesc-rgba
@@ -1 +1 @@
-pixdesc-rgba 93a5b3712e6eb8c5b9a09ffc7b9fbc12
+pixdesc-rgba 283a6115965814470d50f11bf197c5fe
diff --git a/tests/ref/fate/filter-pixdesc-rgba64be b/tests/ref/fate/filter-pixdesc-rgba64be
new file mode 100644
index 0000000..1d7cbd0
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-rgba64be
@@ -0,0 +1 @@
+pixdesc-rgba64be a00ce626e8c94dcc2ebd7b95d7a7d43b
diff --git a/tests/ref/fate/filter-pixdesc-rgba64le b/tests/ref/fate/filter-pixdesc-rgba64le
new file mode 100644
index 0000000..1f8fecc
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-rgba64le
@@ -0,0 +1 @@
+pixdesc-rgba64le 50932da874a5063a595a9428edb187fe
diff --git a/tests/ref/fate/filter-pixdesc-uyvy422 b/tests/ref/fate/filter-pixdesc-uyvy422
index a5b3703..6967b7e 100644
--- a/tests/ref/fate/filter-pixdesc-uyvy422
+++ b/tests/ref/fate/filter-pixdesc-uyvy422
@@ -1 +1 @@
-pixdesc-uyvy422 adcf64516a19fce44df77082bdb16291
+pixdesc-uyvy422 2d479ff414d1c94bf506e48c86f66a02
diff --git a/tests/ref/fate/filter-pixdesc-xyz12be b/tests/ref/fate/filter-pixdesc-xyz12be
new file mode 100644
index 0000000..8a1eb68
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-xyz12be
@@ -0,0 +1 @@
+pixdesc-xyz12be ff515a5c7277e411c0bf3c8f26d02de8
diff --git a/tests/ref/fate/filter-pixdesc-xyz12le b/tests/ref/fate/filter-pixdesc-xyz12le
new file mode 100644
index 0000000..ea1bcd1
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-xyz12le
@@ -0,0 +1 @@
+pixdesc-xyz12le 63f383905675fd3306a329eb89d6d0f8
diff --git a/tests/ref/fate/filter-pixdesc-yuv410p b/tests/ref/fate/filter-pixdesc-yuv410p
index 237603a..1af3abd 100644
--- a/tests/ref/fate/filter-pixdesc-yuv410p
+++ b/tests/ref/fate/filter-pixdesc-yuv410p
@@ -1 +1 @@
-pixdesc-yuv410p 2d9225153c83ee1132397d619d94d1b3
+pixdesc-yuv410p 242e22aa812c1db8bff7f8132fb1f6da
diff --git a/tests/ref/fate/filter-pixdesc-yuv411p b/tests/ref/fate/filter-pixdesc-yuv411p
index a1ab6e4..253805f 100644
--- a/tests/ref/fate/filter-pixdesc-yuv411p
+++ b/tests/ref/fate/filter-pixdesc-yuv411p
@@ -1 +1 @@
-pixdesc-yuv411p 8b298af3e43348ca1b11eb8a3252ac6c
+pixdesc-yuv411p 9305f8baa6ab955566fbee34391734b3
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p b/tests/ref/fate/filter-pixdesc-yuv420p
index 7b0cfd2..0722984 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p
+++ b/tests/ref/fate/filter-pixdesc-yuv420p
@@ -1 +1 @@
-pixdesc-yuv420p eba2f135a08829387e2f698ff72a2939
+pixdesc-yuv420p 005e6ddc8a5daf11cf866a1ec76c2572
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p10be b/tests/ref/fate/filter-pixdesc-yuv420p10be
index 4fe0371..f9ac99a 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p10be
+++ b/tests/ref/fate/filter-pixdesc-yuv420p10be
@@ -1 +1 @@
-pixdesc-yuv420p10be 299fe1d785a3d3dd5e70778700d7fb06
+pixdesc-yuv420p10be ac1b6e1050f39464703e78a2ffc1913a
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p10le b/tests/ref/fate/filter-pixdesc-yuv420p10le
index f1aaedf..2535e52 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p10le
+++ b/tests/ref/fate/filter-pixdesc-yuv420p10le
@@ -1 +1 @@
-pixdesc-yuv420p10le 8aee004e765a5383be0954f5e916b72f
+pixdesc-yuv420p10le 5c158075ae335e6bbf4cd3be29bbb62a
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p12be b/tests/ref/fate/filter-pixdesc-yuv420p12be
new file mode 100644
index 0000000..ad0d32d
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv420p12be
@@ -0,0 +1 @@
+pixdesc-yuv420p12be 6a53755f72b37b2a264387dd5604b431
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p12le b/tests/ref/fate/filter-pixdesc-yuv420p12le
new file mode 100644
index 0000000..d26cfae
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv420p12le
@@ -0,0 +1 @@
+pixdesc-yuv420p12le 174eb0b1aa668d517c13d6e397577cf9
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p14be b/tests/ref/fate/filter-pixdesc-yuv420p14be
new file mode 100644
index 0000000..6748f14
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv420p14be
@@ -0,0 +1 @@
+pixdesc-yuv420p14be ea8399e9ef8b6aa033ad2f5d6dca0473
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p14le b/tests/ref/fate/filter-pixdesc-yuv420p14le
new file mode 100644
index 0000000..90f0c51
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv420p14le
@@ -0,0 +1 @@
+pixdesc-yuv420p14le a63fb4dfb6a7db44a5fd7f35d39d9032
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p16be b/tests/ref/fate/filter-pixdesc-yuv420p16be
index 9f7221f..3f9d722 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p16be
+++ b/tests/ref/fate/filter-pixdesc-yuv420p16be
@@ -1 +1 @@
-pixdesc-yuv420p16be 16c009a235cd52b74791a895423152a3
+pixdesc-yuv420p16be fa7a59892b9d15f6e41c24e5f348f303
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p16le b/tests/ref/fate/filter-pixdesc-yuv420p16le
index 2bd8c94..2826983 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p16le
+++ b/tests/ref/fate/filter-pixdesc-yuv420p16le
@@ -1 +1 @@
-pixdesc-yuv420p16le 2d59c4f1d0314a5a957a7cfc4b6fabcc
+pixdesc-yuv420p16le 5b75c822b20189bb0859b05bcf241aec
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p9be b/tests/ref/fate/filter-pixdesc-yuv420p9be
index cd2e847..7a10497 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p9be
+++ b/tests/ref/fate/filter-pixdesc-yuv420p9be
@@ -1 +1 @@
-pixdesc-yuv420p9be ce880fa07830e5297c22acf6e20555ce
+pixdesc-yuv420p9be d5dabd911d09c9e8fa01fe284dcfd4d6
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p9le b/tests/ref/fate/filter-pixdesc-yuv420p9le
index c887495..28eeac3 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p9le
+++ b/tests/ref/fate/filter-pixdesc-yuv420p9le
@@ -1 +1 @@
-pixdesc-yuv420p9le 16543fda8f87d94a6cf857d2e8d4461a
+pixdesc-yuv420p9le eb1f57241a76ae5d65228adb3aede871
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p b/tests/ref/fate/filter-pixdesc-yuv422p
index e533230..8544034 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p
+++ b/tests/ref/fate/filter-pixdesc-yuv422p
@@ -1 +1 @@
-pixdesc-yuv422p c9bba4529821d796a6ab09f6a5fd355a
+pixdesc-yuv422p 5afc9b0f6c5cef4a7d0543c03d0fc8a4
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p10be b/tests/ref/fate/filter-pixdesc-yuv422p10be
index 2e68731..61eb787 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p10be
+++ b/tests/ref/fate/filter-pixdesc-yuv422p10be
@@ -1 +1 @@
-pixdesc-yuv422p10be 11af7dfafe8bc025c7e3bd82b830fe8a
+pixdesc-yuv422p10be b83a73824cf37922faa84227ca151b83
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p10le b/tests/ref/fate/filter-pixdesc-yuv422p10le
index 3b173bc..f160a43 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p10le
+++ b/tests/ref/fate/filter-pixdesc-yuv422p10le
@@ -1 +1 @@
-pixdesc-yuv422p10le ec04efb76efa79bf0d02b21572371a56
+pixdesc-yuv422p10le 64e51f718442560814e74dd1e01d6c94
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p12be b/tests/ref/fate/filter-pixdesc-yuv422p12be
new file mode 100644
index 0000000..57ecfb5
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv422p12be
@@ -0,0 +1 @@
+pixdesc-yuv422p12be 460ce0ef46387d0ee667664e72dfe6d0
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p12le b/tests/ref/fate/filter-pixdesc-yuv422p12le
new file mode 100644
index 0000000..416659a
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv422p12le
@@ -0,0 +1 @@
+pixdesc-yuv422p12le 687856619666bc8f8bc6a8e91f7c4e95
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p14be b/tests/ref/fate/filter-pixdesc-yuv422p14be
new file mode 100644
index 0000000..6b9d590
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv422p14be
@@ -0,0 +1 @@
+pixdesc-yuv422p14be 461184df05416126fec7c5d2fbad3876
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p14le b/tests/ref/fate/filter-pixdesc-yuv422p14le
new file mode 100644
index 0000000..ec6cbc4
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv422p14le
@@ -0,0 +1 @@
+pixdesc-yuv422p14le e180b189ef2f8448c681d02b478e56cd
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p16be b/tests/ref/fate/filter-pixdesc-yuv422p16be
index 9e69199..a45e01a 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p16be
+++ b/tests/ref/fate/filter-pixdesc-yuv422p16be
@@ -1 +1 @@
-pixdesc-yuv422p16be 5499502e1c29534a158a1fe60e889f60
+pixdesc-yuv422p16be 332fba636d33aea23514392d80602a96
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p16le b/tests/ref/fate/filter-pixdesc-yuv422p16le
index 5a865b0..56d62cf 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p16le
+++ b/tests/ref/fate/filter-pixdesc-yuv422p16le
@@ -1 +1 @@
-pixdesc-yuv422p16le e3d61fde6978591596bc36b914386623
+pixdesc-yuv422p16le 5d8e26fbbc8f25576065106c8820d56a
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p9be b/tests/ref/fate/filter-pixdesc-yuv422p9be
index 7b244db..4d72964 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p9be
+++ b/tests/ref/fate/filter-pixdesc-yuv422p9be
@@ -1 +1 @@
-pixdesc-yuv422p9be 29b71579946940a8c00fa844c9dff507
+pixdesc-yuv422p9be e3b364350da35d2ffd431665ed9d3592
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p9le b/tests/ref/fate/filter-pixdesc-yuv422p9le
index a6dbb93..df40e54 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p9le
+++ b/tests/ref/fate/filter-pixdesc-yuv422p9le
@@ -1 +1 @@
-pixdesc-yuv422p9le 062b7f9cbb972bf36b5bdb1a7623701a
+pixdesc-yuv422p9le 0f21976b77781cada504f690d7dc6c15
diff --git a/tests/ref/fate/filter-pixdesc-yuv440p b/tests/ref/fate/filter-pixdesc-yuv440p
index b6b6e14..0a8271f 100644
--- a/tests/ref/fate/filter-pixdesc-yuv440p
+++ b/tests/ref/fate/filter-pixdesc-yuv440p
@@ -1 +1 @@
-pixdesc-yuv440p 5a064afe2b453bb52cdb3f176b1aa1cf
+pixdesc-yuv440p e6754959dfd9631f2dc1682fa71aa4e0
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p b/tests/ref/fate/filter-pixdesc-yuv444p
index 628f0e4..1df19f2 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p
+++ b/tests/ref/fate/filter-pixdesc-yuv444p
@@ -1 +1 @@
-pixdesc-yuv444p 0a98447b78fd476aa39686da6a74fa2e
+pixdesc-yuv444p db3ad634aea336663a2f5c2475b95410
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p10be b/tests/ref/fate/filter-pixdesc-yuv444p10be
index b1c57fa..cb253ca 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p10be
+++ b/tests/ref/fate/filter-pixdesc-yuv444p10be
@@ -1 +1 @@
-pixdesc-yuv444p10be 71be185a2fb7a353eb024df9bc63212d
+pixdesc-yuv444p10be e341efd871b34308831113f4b2ff29f9
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p10le b/tests/ref/fate/filter-pixdesc-yuv444p10le
index 16be63f..6c3e701 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p10le
+++ b/tests/ref/fate/filter-pixdesc-yuv444p10le
@@ -1 +1 @@
-pixdesc-yuv444p10le c1c6b30a12065c7901c0a267e4861a0f
+pixdesc-yuv444p10le f9666d63623e0d7dceda1a17202579cf
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p12be b/tests/ref/fate/filter-pixdesc-yuv444p12be
new file mode 100644
index 0000000..ffb3234
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv444p12be
@@ -0,0 +1 @@
+pixdesc-yuv444p12be 151c0e12d45ddf475a293cf9eee4c224
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p12le b/tests/ref/fate/filter-pixdesc-yuv444p12le
new file mode 100644
index 0000000..57fdd58
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv444p12le
@@ -0,0 +1 @@
+pixdesc-yuv444p12le e0da5848e54c3ba0dbfa0414ff4a47f3
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p14be b/tests/ref/fate/filter-pixdesc-yuv444p14be
new file mode 100644
index 0000000..42050c2
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv444p14be
@@ -0,0 +1 @@
+pixdesc-yuv444p14be 83d2420dc82158274425c6ea5e396dbf
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p14le b/tests/ref/fate/filter-pixdesc-yuv444p14le
new file mode 100644
index 0000000..4c626cd
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv444p14le
@@ -0,0 +1 @@
+pixdesc-yuv444p14le 155753892ad8a8957df50033fd21fecb
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p16be b/tests/ref/fate/filter-pixdesc-yuv444p16be
index 1ed4d0b..5f36584 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p16be
+++ b/tests/ref/fate/filter-pixdesc-yuv444p16be
@@ -1 +1 @@
-pixdesc-yuv444p16be 1c6ea2c2f5e539006112ceec3d4e7d90
+pixdesc-yuv444p16be 6bb40952bd87aaaf2938cfadd1017a79
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p16le b/tests/ref/fate/filter-pixdesc-yuv444p16le
index c685b8c..530b284 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p16le
+++ b/tests/ref/fate/filter-pixdesc-yuv444p16le
@@ -1 +1 @@
-pixdesc-yuv444p16le 20f86bc2f68d2b3f1f2b48b97b2189f4
+pixdesc-yuv444p16le 9be8c3ca67cb8a778d39c087f008d8c0
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p9be b/tests/ref/fate/filter-pixdesc-yuv444p9be
index 6f87a9a..562e876 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p9be
+++ b/tests/ref/fate/filter-pixdesc-yuv444p9be
@@ -1 +1 @@
-pixdesc-yuv444p9be 6ab31f4c12b533ce318ecdff83cdd054
+pixdesc-yuv444p9be 5a54227a9e1e12fd297e36e1e9361c52
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p9le b/tests/ref/fate/filter-pixdesc-yuv444p9le
index 83d83f6..855c2a5 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p9le
+++ b/tests/ref/fate/filter-pixdesc-yuv444p9le
@@ -1 +1 @@
-pixdesc-yuv444p9le f0606604a5c08becab6ba500124c4b7c
+pixdesc-yuv444p9le faeeb7f3ff5efc51975d48d49f4ced5d
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p b/tests/ref/fate/filter-pixdesc-yuva420p
index 7194758..91b818d 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p
+++ b/tests/ref/fate/filter-pixdesc-yuva420p
@@ -1 +1 @@
-pixdesc-yuva420p a29884f3f3dfe1e00b961bc17bef3d47
+pixdesc-yuva420p 7b609ede889454d2b89b184c290e9e32
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p10be b/tests/ref/fate/filter-pixdesc-yuva420p10be
index 6d3723f..ccf6097 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p10be
+++ b/tests/ref/fate/filter-pixdesc-yuva420p10be
@@ -1 +1 @@
-pixdesc-yuva420p10be145366ff1632de3e300d947f49844284
+pixdesc-yuva420p10be4a0ab3165ccc5cde5f4ef9c27e8ccf82
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p10le b/tests/ref/fate/filter-pixdesc-yuva420p10le
index 5b7f692..a7dbf52 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p10le
+++ b/tests/ref/fate/filter-pixdesc-yuva420p10le
@@ -1 +1 @@
-pixdesc-yuva420p10led797038552d7f698e4d1db4dfa18ceb0
+pixdesc-yuva420p10le8fbcc6200060e0710e5a824b86c9c219
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p16be b/tests/ref/fate/filter-pixdesc-yuva420p16be
index 6e82b70..ff7182b 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p16be
+++ b/tests/ref/fate/filter-pixdesc-yuva420p16be
@@ -1 +1 @@
-pixdesc-yuva420p16be25a335f66a0670911ced818aa42fb670
+pixdesc-yuva420p16bed149e664c8fce03192d78279472ae2c3
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p16le b/tests/ref/fate/filter-pixdesc-yuva420p16le
index 2bedb68..fb7e8c4 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p16le
+++ b/tests/ref/fate/filter-pixdesc-yuva420p16le
@@ -1 +1 @@
-pixdesc-yuva420p16le97bf252e6c030f0f0412d3826c2ea259
+pixdesc-yuva420p16le11b9f6b757f98fd4a442983bca8945b1
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p9be b/tests/ref/fate/filter-pixdesc-yuva420p9be
index 3a621bd..29c85a7 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p9be
+++ b/tests/ref/fate/filter-pixdesc-yuva420p9be
@@ -1 +1 @@
-pixdesc-yuva420p9be 06b764d85bd3c22e9b7ca4babed84d4f
+pixdesc-yuva420p9be 0aae288a080fb0acfac23610b2d30111
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p9le b/tests/ref/fate/filter-pixdesc-yuva420p9le
index 5edc34d..80fd895 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p9le
+++ b/tests/ref/fate/filter-pixdesc-yuva420p9le
@@ -1 +1 @@
-pixdesc-yuva420p9le 1f01cdd4fc46f98d4c11b2947307a0e3
+pixdesc-yuva420p9le fb67be28488cb722d4aea6fe3fdaaa16
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p b/tests/ref/fate/filter-pixdesc-yuva422p
index b50c2a3..9285d99 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p
+++ b/tests/ref/fate/filter-pixdesc-yuva422p
@@ -1 +1 @@
-pixdesc-yuva422p 92b6815f465297284cdb843711682cee
+pixdesc-yuva422p 88c582f7c6d7c123198fb707aad2d5b0
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p10be b/tests/ref/fate/filter-pixdesc-yuva422p10be
index c012d70..fd9a24c 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p10be
+++ b/tests/ref/fate/filter-pixdesc-yuva422p10be
@@ -1 +1 @@
-pixdesc-yuva422p10befb240ff9ac49b45b1b3d40df2c89e39d
+pixdesc-yuva422p10be465ec369d7e47a71976821fdc31c289c
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p10le b/tests/ref/fate/filter-pixdesc-yuva422p10le
index 632cb6f..6b2397c 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p10le
+++ b/tests/ref/fate/filter-pixdesc-yuva422p10le
@@ -1 +1 @@
-pixdesc-yuva422p10lef767ede9ba1d427faadc963cf41d2412
+pixdesc-yuva422p10le07df8a8fcb3081e89d84359b178d5260
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p16be b/tests/ref/fate/filter-pixdesc-yuva422p16be
index b9d5bde..e6f0dab 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p16be
+++ b/tests/ref/fate/filter-pixdesc-yuva422p16be
@@ -1 +1 @@
-pixdesc-yuva422p16beef442b11b26e5e61f3c958fa309576dd
+pixdesc-yuva422p16be0144a6783d7728a0e66d2b6d1134ecec
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p16le b/tests/ref/fate/filter-pixdesc-yuva422p16le
index 22ad86e..d281764 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p16le
+++ b/tests/ref/fate/filter-pixdesc-yuva422p16le
@@ -1 +1 @@
-pixdesc-yuva422p16le5789009759d7a44dacc6da2194e402b1
+pixdesc-yuva422p16le5b49f7e660c77bafcb03869ea2e1ce02
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p9be b/tests/ref/fate/filter-pixdesc-yuva422p9be
index 967b324..55cd6be 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p9be
+++ b/tests/ref/fate/filter-pixdesc-yuva422p9be
@@ -1 +1 @@
-pixdesc-yuva422p9be e0d2f45f7f5541eee988137c7ebb3495
+pixdesc-yuva422p9be 923a2d718c2dcf62c4c9b573a56f15ad
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p9le b/tests/ref/fate/filter-pixdesc-yuva422p9le
index 2ce6d76..0ba0fde 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p9le
+++ b/tests/ref/fate/filter-pixdesc-yuva422p9le
@@ -1 +1 @@
-pixdesc-yuva422p9le a4ec81f328efd3856dec430fb27f2f56
+pixdesc-yuva422p9le 9188e6cef21e89d034d37da1b1702a7d
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p b/tests/ref/fate/filter-pixdesc-yuva444p
index 43083b1..bf5ff9c 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p
+++ b/tests/ref/fate/filter-pixdesc-yuva444p
@@ -1 +1 @@
-pixdesc-yuva444p c523716e4900cfe515eaab1d7124fdd9
+pixdesc-yuva444p f89cdb4fea764921004e149358d7028a
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p10be b/tests/ref/fate/filter-pixdesc-yuva444p10be
index 2b79d4e..b45da7b 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p10be
+++ b/tests/ref/fate/filter-pixdesc-yuva444p10be
@@ -1 +1 @@
-pixdesc-yuva444p10bef5791a75fdb86da0c243511ef9ab8fbd
+pixdesc-yuva444p10be87b0f4d461c40bde0cc85b109103d016
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p10le b/tests/ref/fate/filter-pixdesc-yuva444p10le
index 80a1ed8..be941fc 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p10le
+++ b/tests/ref/fate/filter-pixdesc-yuva444p10le
@@ -1 +1 @@
-pixdesc-yuva444p10le578e88dfbe4ab07f280fcc7554f3a5c4
+pixdesc-yuva444p10le5aed7ca68d5645a3a9acbe14b8eca54f
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p16be b/tests/ref/fate/filter-pixdesc-yuva444p16be
index 400010b..31ccde2 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p16be
+++ b/tests/ref/fate/filter-pixdesc-yuva444p16be
@@ -1 +1 @@
-pixdesc-yuva444p16beee7b9dd854e36b165d5b7cffb646ba6c
+pixdesc-yuva444p16be5701a24fa4153d45be9533d7ec00b660
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p16le b/tests/ref/fate/filter-pixdesc-yuva444p16le
index 1564007..11554e0 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p16le
+++ b/tests/ref/fate/filter-pixdesc-yuva444p16le
@@ -1 +1 @@
-pixdesc-yuva444p16leec93b2907923d5655e9fb085479260ef
+pixdesc-yuva444p16lec3092fc38248cf96e30dce70208ed360
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p9be b/tests/ref/fate/filter-pixdesc-yuva444p9be
index 4d781bc..4377c0e 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p9be
+++ b/tests/ref/fate/filter-pixdesc-yuva444p9be
@@ -1 +1 @@
-pixdesc-yuva444p9be 03414257d78e72c28d03e3c247319b7c
+pixdesc-yuva444p9be 8ab557ee81eae76cd176d998078d671d
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p9le b/tests/ref/fate/filter-pixdesc-yuva444p9le
index 646a2a2..30bba91 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p9le
+++ b/tests/ref/fate/filter-pixdesc-yuva444p9le
@@ -1 +1 @@
-pixdesc-yuva444p9le e421d753257e36a79c2c0ec1607ac9e6
+pixdesc-yuva444p9le b599165331bd7fa6b05dbf7b80044856
diff --git a/tests/ref/fate/filter-pixdesc-yuvj411p b/tests/ref/fate/filter-pixdesc-yuvj411p
new file mode 100644
index 0000000..0ea341a
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuvj411p
@@ -0,0 +1 @@
+pixdesc-yuvj411p ffb1370ebb9e1bb3b7dd4a532fe8eaeb
diff --git a/tests/ref/fate/filter-pixdesc-yuvj420p b/tests/ref/fate/filter-pixdesc-yuvj420p
index 3187f9d..960d402 100644
--- a/tests/ref/fate/filter-pixdesc-yuvj420p
+++ b/tests/ref/fate/filter-pixdesc-yuvj420p
@@ -1 +1 @@
-pixdesc-yuvj420p 32eec78ba51857b16ce9b813a49b7189
+pixdesc-yuvj420p aaddf557fa39c3b9521bc6afabbc18e6
diff --git a/tests/ref/fate/filter-pixdesc-yuvj422p b/tests/ref/fate/filter-pixdesc-yuvj422p
index f5f2af4..07a087d 100644
--- a/tests/ref/fate/filter-pixdesc-yuvj422p
+++ b/tests/ref/fate/filter-pixdesc-yuvj422p
@@ -1 +1 @@
-pixdesc-yuvj422p 0dfa0ed434f73be51428758c69e082cb
+pixdesc-yuvj422p 4f46f78ace9176a534aea861ac316441
diff --git a/tests/ref/fate/filter-pixdesc-yuvj440p b/tests/ref/fate/filter-pixdesc-yuvj440p
index 9fc39cf..8a335ef 100644
--- a/tests/ref/fate/filter-pixdesc-yuvj440p
+++ b/tests/ref/fate/filter-pixdesc-yuvj440p
@@ -1 +1 @@
-pixdesc-yuvj440p 657501a28004e27a592757a7509f5189
+pixdesc-yuvj440p d8083286cf699e81113fc8ea04ba3c35
diff --git a/tests/ref/fate/filter-pixdesc-yuvj444p b/tests/ref/fate/filter-pixdesc-yuvj444p
index c2bf052..5115fa1 100644
--- a/tests/ref/fate/filter-pixdesc-yuvj444p
+++ b/tests/ref/fate/filter-pixdesc-yuvj444p
@@ -1 +1 @@
-pixdesc-yuvj444p 98d3d054f2ec09a75eeed5d328dc75b7
+pixdesc-yuvj444p cad8f07876e62d33caf6c420d0f67a56
diff --git a/tests/ref/fate/filter-pixdesc-yuyv422 b/tests/ref/fate/filter-pixdesc-yuyv422
index 2a4980d..42d0cb0 100644
--- a/tests/ref/fate/filter-pixdesc-yuyv422
+++ b/tests/ref/fate/filter-pixdesc-yuyv422
@@ -1 +1 @@
-pixdesc-yuyv422 f2569f2b5069a0ee0cecae33de0455e3
+pixdesc-yuyv422 ad9bf7f09f4f8263131649407a778e7b
diff --git a/tests/ref/fate/filter-pixdesc-yvyu422 b/tests/ref/fate/filter-pixdesc-yvyu422
index 934df9b..788a456 100644
--- a/tests/ref/fate/filter-pixdesc-yvyu422
+++ b/tests/ref/fate/filter-pixdesc-yvyu422
@@ -1 +1 @@
-pixdesc-yvyu422 17aef3e345d23edd3c660a91dcfc5a19
+pixdesc-yvyu422 59f91e478f573d8a305e11da12a87be3
diff --git a/tests/ref/fate/filter-pixfmts-copy b/tests/ref/fate/filter-pixfmts-copy
index f99e8ea..a421734 100644
--- a/tests/ref/fate/filter-pixfmts-copy
+++ b/tests/ref/fate/filter-pixfmts-copy
@@ -1,90 +1,119 @@
-abgr 037bf9df6a765520ad6d490066bf4b89
-argb c442a8261c2265a07212ef0f72e35f5a
-bgr24 0d0cb38ab3fa0b2ec0865c14f78b217b
-bgr444be d9ea9307d21b162225b8b2c524cf9477
-bgr444le 88035350e9da3a8f67387890b956f0bc
-bgr48be 00624e6c7ec7ab19897ba2f0a3257fe8
-bgr48le d02c235ebba7167881ca2d576497ff84
-bgr4_byte 50d23cc82d9dcef2fd12adb81fb9b806
-bgr555be 49f01b1f1f0c84fd9e776dd34cc3c280
-bgr555le 378d6ac4223651a1adcbf94a3d0d807b
-bgr565be 257cf78afa35dc31e9696f139c916715
-bgr565le 1dfdd03995c287e3c754b164bf26a355
-bgr8 24bd566170343d06fec6fccfff5abc54
-bgra 76a18a5151242fa137133f604cd624d2
-gbrp 76204621e200a3cc633012f6720c7005
-gbrp10be 2ca4a4a589a7dc461ff186913c7a69e5
-gbrp10le 46176f1fcc6e67f9862115fe373f73d3
-gbrp9be 981c2c1b0ef1791824b4c7518331bc2e
-gbrp9le 25fb915ed11d07d631e0e7b78d54bebf
-gray db08f7f0751900347e6b8649e4164d21
-gray16be 7becf34ae825a3df3969bf4c6bfeb5e2
-gray16le 10bd87059b5c189f3caef2837f4f2b5c
-monob 668ebe8b8103b9046b251b2fa8a1d88f
-monow 9251497f3b0634f1165d12d5a289d943
-nv12 e0af357888584d36eec5aa0f673793ef
-nv21 9a3297f3b34baa038b1f37cb202b512f
-rgb24 b41eba9651e1b5fe386289b506188105
-rgb444be 9e89db334568c6b2e3d5d0540f4ba960
-rgb444le 0a68cb6de8bf530aa30c5c1205c25155
-rgb48be cc139ec1dd9451f0e049c0cb3a0c8aa2
-rgb48le 86c5608904f75360d492dbc5c9589969
-rgb4_byte c93ba89b74c504e7f5ae9d9ab1546c73
-rgb555be 912a62c5e53bfcbac2a0340e10973cf2
-rgb555le a937a0fc764fb57dc1b3af87cba0273c
-rgb565be 9cadf742e05ddc23a3b5b270f89aad3c
-rgb565le d39aa298bb525e9be8860351c6f62dab
-rgb8 4a9d8e4f2f154e83a7e1735be6300700
-rgba 93a5b3712e6eb8c5b9a09ffc7b9fbc12
-uyvy422 adcf64516a19fce44df77082bdb16291
-yuv410p 2d9225153c83ee1132397d619d94d1b3
-yuv411p 8b298af3e43348ca1b11eb8a3252ac6c
-yuv420p eba2f135a08829387e2f698ff72a2939
-yuv420p10be 299fe1d785a3d3dd5e70778700d7fb06
-yuv420p10le 8aee004e765a5383be0954f5e916b72f
-yuv420p16be 16c009a235cd52b74791a895423152a3
-yuv420p16le 2d59c4f1d0314a5a957a7cfc4b6fabcc
-yuv420p9be ce880fa07830e5297c22acf6e20555ce
-yuv420p9le 16543fda8f87d94a6cf857d2e8d4461a
-yuv422p c9bba4529821d796a6ab09f6a5fd355a
-yuv422p10be 11af7dfafe8bc025c7e3bd82b830fe8a
-yuv422p10le ec04efb76efa79bf0d02b21572371a56
-yuv422p16be 5499502e1c29534a158a1fe60e889f60
-yuv422p16le e3d61fde6978591596bc36b914386623
-yuv422p9be 29b71579946940a8c00fa844c9dff507
-yuv422p9le 062b7f9cbb972bf36b5bdb1a7623701a
-yuv440p 5a064afe2b453bb52cdb3f176b1aa1cf
-yuv444p 0a98447b78fd476aa39686da6a74fa2e
-yuv444p10be 71be185a2fb7a353eb024df9bc63212d
-yuv444p10le c1c6b30a12065c7901c0a267e4861a0f
-yuv444p16be 1c6ea2c2f5e539006112ceec3d4e7d90
-yuv444p16le 20f86bc2f68d2b3f1f2b48b97b2189f4
-yuv444p9be 6ab31f4c12b533ce318ecdff83cdd054
-yuv444p9le f0606604a5c08becab6ba500124c4b7c
-yuva420p a29884f3f3dfe1e00b961bc17bef3d47
-yuva420p10be 145366ff1632de3e300d947f49844284
-yuva420p10le d797038552d7f698e4d1db4dfa18ceb0
-yuva420p16be 25a335f66a0670911ced818aa42fb670
-yuva420p16le 97bf252e6c030f0f0412d3826c2ea259
-yuva420p9be 06b764d85bd3c22e9b7ca4babed84d4f
-yuva420p9le 1f01cdd4fc46f98d4c11b2947307a0e3
-yuva422p 92b6815f465297284cdb843711682cee
-yuva422p10be fb240ff9ac49b45b1b3d40df2c89e39d
-yuva422p10le f767ede9ba1d427faadc963cf41d2412
-yuva422p16be ef442b11b26e5e61f3c958fa309576dd
-yuva422p16le 5789009759d7a44dacc6da2194e402b1
-yuva422p9be e0d2f45f7f5541eee988137c7ebb3495
-yuva422p9le a4ec81f328efd3856dec430fb27f2f56
-yuva444p c523716e4900cfe515eaab1d7124fdd9
-yuva444p10be f5791a75fdb86da0c243511ef9ab8fbd
-yuva444p10le 578e88dfbe4ab07f280fcc7554f3a5c4
-yuva444p16be ee7b9dd854e36b165d5b7cffb646ba6c
-yuva444p16le ec93b2907923d5655e9fb085479260ef
-yuva444p9be 03414257d78e72c28d03e3c247319b7c
-yuva444p9le e421d753257e36a79c2c0ec1607ac9e6
-yuvj420p 32eec78ba51857b16ce9b813a49b7189
-yuvj422p 0dfa0ed434f73be51428758c69e082cb
-yuvj440p 657501a28004e27a592757a7509f5189
-yuvj444p 98d3d054f2ec09a75eeed5d328dc75b7
-yuyv422 f2569f2b5069a0ee0cecae33de0455e3
-yvyu422 17aef3e345d23edd3c660a91dcfc5a19
+0bgr 7211d3bdeafda12a27b6c586f56369e8
+0rgb dc534ffbcf7b02007a245e6af5bc0bf7
+abgr 0d93666da1532ca69c1a3e2ee0248430
+argb 86f5041b9245930bc6977d4f2babf74d
+bgr0 914c5750b13f79908c23d2621bc5d171
+bgr24 fd0c957cabb399b3dda29e1190e6cfac
+bgr444be 96d828ff1ea24858100e0afcef6f6201
+bgr444le 5a43d10a7890378368073be08141f967
+bgr48be 65986a0555423c910db4820732565a5e
+bgr48le 3050e56ee66fa61d8dd88b12f4b2f956
+bgr4_byte 6d8ea0cb6b4cadace60222063a847630
+bgr555be 90ffbd6a7850f25253977aecf84e229e
+bgr555le 9f800958e9c238c9441fef9799ab2a8d
+bgr565be 0e7c46857a3bebc2e3bb77ae68cc0bad
+bgr565le 31c0b9b6bc009a4bfa4421c3bbb2ff39
+bgr8 775803c35cf19b2fc84f537ce5a7e262
+bgra 020a3623e3ad6ea398d6adfcba9e510c
+bgra64be ce8e864307b8f11d1bc4a92f3384416b
+bgra64le fa2e6435c1f7f498d5714898e120dd89
+gbrap dcf43e62881e69a873382c12d3afe0a4
+gbrp 78a26e285e0f6ee73f37d70621e659fe
+gbrp10be d325f4f209bf460f8ff7d37bc51978dd
+gbrp10le c2328ae0384eeb34b1ac83726b385f46
+gbrp12be 8aa22995644b2796ecafc10dec5f3bd8
+gbrp12le df4badcfdf6701e03809ef5a278297b8
+gbrp14be a02a13caee9af458c5039c697ab896a6
+gbrp14le 4f521b6e69078bd0eca8dfcfde0f6ef6
+gbrp9be 397280799d9e78f48670664491e62524
+gbrp9le dbf020fa8423e170f2624ddba9f2c945
+gray 19ae78946e6acc3b552daa61b44a8ca1
+gray16be 2665aebcabc71b30a2252308b1335a81
+gray16le f35d7d9b8cac96c5ac25c2cd4b42443b
+monob d2b84b01179f38ce59a7050064d42289
+monow 550a446b7900a42990d76befca7f08a0
+nv12 18aaac3efcb2e389bfa2ade34b917634
+nv21 cb3b54dcc21c72943d496e6368b0c00b
+pal8 5ad4084b953f16007faf99f366b2ecae
+rgb0 1cb89a77512524197ae6495dc7206a7b
+rgb24 273cfae99e5951d567f230beec3e3eeb
+rgb444be d90556c864a78c45ca9e2c27130067cd
+rgb444le fe271368f267be87eb8f5b46335ba6dc
+rgb48be 434c2ce989de629050e53e820b6929b6
+rgb48le e04c4a36ea9f9c5624ebd56463b593fe
+rgb4_byte 77c49fda8c97ffc25678d8a51f7056ca
+rgb555be cb820a51149ba9944480bad7e1260abc
+rgb555le dc18e2fec8f39ebfd5b479fa6c5fe717
+rgb565be 0a7a10645295397cd6cbd6eadce71c8e
+rgb565le 7454e27a0e2c2c37c67e5361a82dd445
+rgb8 7b602ac8a68dd95ad639f741be805a0d
+rgba 283a6115965814470d50f11bf197c5fe
+rgba64be a00ce626e8c94dcc2ebd7b95d7a7d43b
+rgba64le 50932da874a5063a595a9428edb187fe
+uyvy422 2d479ff414d1c94bf506e48c86f66a02
+xyz12be ff515a5c7277e411c0bf3c8f26d02de8
+xyz12le 63f383905675fd3306a329eb89d6d0f8
+yuv410p 242e22aa812c1db8bff7f8132fb1f6da
+yuv411p 9305f8baa6ab955566fbee34391734b3
+yuv420p 005e6ddc8a5daf11cf866a1ec76c2572
+yuv420p10be ac1b6e1050f39464703e78a2ffc1913a
+yuv420p10le 5c158075ae335e6bbf4cd3be29bbb62a
+yuv420p12be 6a53755f72b37b2a264387dd5604b431
+yuv420p12le 174eb0b1aa668d517c13d6e397577cf9
+yuv420p14be ea8399e9ef8b6aa033ad2f5d6dca0473
+yuv420p14le a63fb4dfb6a7db44a5fd7f35d39d9032
+yuv420p16be fa7a59892b9d15f6e41c24e5f348f303
+yuv420p16le 5b75c822b20189bb0859b05bcf241aec
+yuv420p9be d5dabd911d09c9e8fa01fe284dcfd4d6
+yuv420p9le eb1f57241a76ae5d65228adb3aede871
+yuv422p 5afc9b0f6c5cef4a7d0543c03d0fc8a4
+yuv422p10be b83a73824cf37922faa84227ca151b83
+yuv422p10le 64e51f718442560814e74dd1e01d6c94
+yuv422p12be 460ce0ef46387d0ee667664e72dfe6d0
+yuv422p12le 687856619666bc8f8bc6a8e91f7c4e95
+yuv422p14be 461184df05416126fec7c5d2fbad3876
+yuv422p14le e180b189ef2f8448c681d02b478e56cd
+yuv422p16be 332fba636d33aea23514392d80602a96
+yuv422p16le 5d8e26fbbc8f25576065106c8820d56a
+yuv422p9be e3b364350da35d2ffd431665ed9d3592
+yuv422p9le 0f21976b77781cada504f690d7dc6c15
+yuv440p e6754959dfd9631f2dc1682fa71aa4e0
+yuv444p db3ad634aea336663a2f5c2475b95410
+yuv444p10be e341efd871b34308831113f4b2ff29f9
+yuv444p10le f9666d63623e0d7dceda1a17202579cf
+yuv444p12be 151c0e12d45ddf475a293cf9eee4c224
+yuv444p12le e0da5848e54c3ba0dbfa0414ff4a47f3
+yuv444p14be 83d2420dc82158274425c6ea5e396dbf
+yuv444p14le 155753892ad8a8957df50033fd21fecb
+yuv444p16be 6bb40952bd87aaaf2938cfadd1017a79
+yuv444p16le 9be8c3ca67cb8a778d39c087f008d8c0
+yuv444p9be 5a54227a9e1e12fd297e36e1e9361c52
+yuv444p9le faeeb7f3ff5efc51975d48d49f4ced5d
+yuva420p 7b609ede889454d2b89b184c290e9e32
+yuva420p10be 4a0ab3165ccc5cde5f4ef9c27e8ccf82
+yuva420p10le 8fbcc6200060e0710e5a824b86c9c219
+yuva420p16be d149e664c8fce03192d78279472ae2c3
+yuva420p16le 11b9f6b757f98fd4a442983bca8945b1
+yuva420p9be 0aae288a080fb0acfac23610b2d30111
+yuva420p9le fb67be28488cb722d4aea6fe3fdaaa16
+yuva422p 88c582f7c6d7c123198fb707aad2d5b0
+yuva422p10be 465ec369d7e47a71976821fdc31c289c
+yuva422p10le 07df8a8fcb3081e89d84359b178d5260
+yuva422p16be 0144a6783d7728a0e66d2b6d1134ecec
+yuva422p16le 5b49f7e660c77bafcb03869ea2e1ce02
+yuva422p9be 923a2d718c2dcf62c4c9b573a56f15ad
+yuva422p9le 9188e6cef21e89d034d37da1b1702a7d
+yuva444p f89cdb4fea764921004e149358d7028a
+yuva444p10be 87b0f4d461c40bde0cc85b109103d016
+yuva444p10le 5aed7ca68d5645a3a9acbe14b8eca54f
+yuva444p16be 5701a24fa4153d45be9533d7ec00b660
+yuva444p16le c3092fc38248cf96e30dce70208ed360
+yuva444p9be 8ab557ee81eae76cd176d998078d671d
+yuva444p9le b599165331bd7fa6b05dbf7b80044856
+yuvj411p ffb1370ebb9e1bb3b7dd4a532fe8eaeb
+yuvj420p aaddf557fa39c3b9521bc6afabbc18e6
+yuvj422p 4f46f78ace9176a534aea861ac316441
+yuvj440p d8083286cf699e81113fc8ea04ba3c35
+yuvj444p cad8f07876e62d33caf6c420d0f67a56
+yuyv422 ad9bf7f09f4f8263131649407a778e7b
+yvyu422 59f91e478f573d8a305e11da12a87be3
diff --git a/tests/ref/fate/filter-pixfmts-crop b/tests/ref/fate/filter-pixfmts-crop
index cbbcf90..f091a0a 100644
--- a/tests/ref/fate/filter-pixfmts-crop
+++ b/tests/ref/fate/filter-pixfmts-crop
@@ -1,42 +1,114 @@
-abgr cd761690872843d1b7ab0c695393c751
-argb 2ec6ef18769bcd651c2e8904d5a3ee67
-bgr24 3450fd00cf1493d1ded75544d82ba3ec
-bgr48be 18ca4002732f278cc9f525215c2fca41
-bgr48le 395a4c187c4e95217d089bd3df9f3654
-bgr4_byte 2f6ac3cdd4676ab4e2982bdf0664945b
-bgr555be d3a7c273604723adeb7e5f5dd1c4272b
-bgr555le d22442fc13b464f9ba455b08df4e981f
-bgr565be fadceef4a64ad6873fcb43ddee0deb3c
-bgr565le 891664e5a54ae5968901347da92bc5e9
-bgr8 4b7159e05765bd4703180072d86423c8
-bgra 395c9f706fccda721471acaa5c96c16c
-gray 8c4850e66562a587a292dc728a65ea4a
-gray16be daa5a6b98fb4a280c57c57bff1a2ab5a
-gray16le 84f5ea7259073edcb893113b42213c8e
-rgb24 3b90ed64b687d3dc186c6ef521dc71a8
-rgb48be e6fd353c0eb9bea889423954414bea35
-rgb48le 68a1723da11ce08b502d42e204376503
-rgb4_byte 6958029f73c6cdfed4f71020d816f027
-rgb555be 41a7d1836837bc90f2cae19a9c9df3b3
-rgb555le eeb78f8ce6186fba55c941469e60ba67
-rgb565be b2d1cb525f3a0cfe27753c0d479b2fa9
-rgb565le 6a49700680be9a0d434411825a769556
-rgb8 88b0398c265d1ed7a837dc084fa0917c
-rgba fd00b24c7597268c32759a84a1de2de4
-yuv410p a9f2eaa747bf988b7bebe4f442b9c67a
-yuv411p 3334d3aef8dba238658090ac172375d1
-yuv420p bfea0188ddd4889787c403caae119cc7
-yuv420p16be 8365eff38b8c329aeb95fc605fa229bb
-yuv420p16le 5e8dd38d973d5854abe1ad4efad20cc1
-yuv422p f2f930a91fe00d4252c4720b5ecd8961
-yuv422p16be 167e4338811a7d272925a4c6417d60da
-yuv422p16le 3359395d5875d581fa1e975013d30114
-yuv440p 2472417d980e395ad6843cbb8b633b29
-yuv444p 1f151980486848c96bc5585ced99003e
-yuv444p16be 1ce8fcd4712d525af983e6179d6a4f9e
-yuv444p16le 5f1441e18345aadb3f881dac99c6c08a
-yuva420p 7536753dfbc7932560fb50c921369a0e
-yuvj420p 21f891093006d42d7683b0e1d773a657
-yuvj422p 9a43d474c407590ad8f213880586b45e
-yuvj440p 977351350450ebdbf7a9d20020c6b5a5
-yuvj444p 4a50ba26859dad91dcf7000de0d0efa1
+0bgr 2dbfe85133679ec33860be0c6209660f
+0rgb ca0c4e07d1d385c56ea72382f2ee9540
+abgr d614480ee1b09b22b0b4f64909d95187
+argb 79132bf1dbdbc2b25be4c28b8828c97d
+bgr0 29f32318c36b40445e98954c53ad5fb0
+bgr24 f6f04b3110f2cecd06719fb38965e0dc
+bgr444be 95bd8c3e75963f49c447b7273484bc73
+bgr444le 2c9cd030b8865bdf7d402ffc70e2a72b
+bgr48be 19aae8f9550d354d718d107a44ac837e
+bgr48le 338b82f7b4aac5d517a8a8b2396d78d0
+bgr4_byte 6ef669512505c87d9155848cde78094b
+bgr555be 2328e1ebdcc5a675d16409ad94e670f1
+bgr555le b7cbc03dd251298e07fd436ce26271a0
+bgr565be 282650e0b2dc125776a1f6ee8df80cea
+bgr565le 3414ba2c28368f39c6e3e52933d51994
+bgr8 ea3c3e7390bff85f70d8e3a59ddced70
+bgra b8bd94fa3040d24cba2c42f94475dbde
+bgra64be ec9acb7200a2fcc36d0068585b5e44ca
+bgra64le 367049173354f78f9198567d672fbad8
+gbrap 0f62b82e45c6a41e16e15b1f220edacf
+gbrp cf6e1617315229a93d4775dcecc3060b
+gbrp10be 66e216886535254f85f95d958da447b1
+gbrp10le c4184848c40d8ac1b35efdc438629038
+gbrp12be b74a3b1085ceb7297df79d83e9f0620c
+gbrp12le 7a18358bd4b1b2cd2462252022e689da
+gbrp14be 09139a87b1bbf3a6aea23e60af322de1
+gbrp14le 885c5014c6314d5689974f45e3761db4
+gbrp9be aa505e48a02e7ca696aafa383311e73f
+gbrp9le 3ca0021fbcf8f64605d75c93bd25c9e8
+gray fcdefb797cd029045b14087dd32864df
+gray16be 98923eb3c74084b4e5df109c7ed7d5bd
+gray16le 5c90c5415f66b8515a1dff86cd57968c
+nv12 d92caeeb7a3957ed03db73cbe1238269
+nv21 88575d9d13287e3e494aca95d7658316
+pal8 d8fd9dc03d11c2359422520eaba5c3f8
+rgb0 5ce99f382ae88184b9420b3d12d3b61b
+rgb24 2927da0677191eb732927e2ae7a6de49
+rgb444be b4b2edd542bc206ffdc37e43df6dc230
+rgb444le 03df3d8eb5007993d6c532e69a13d978
+rgb48be 511ca3199940d39e3c71640922c2e34c
+rgb48le 5026a5cd5c377ed7a39c1a7711a93b80
+rgb4_byte 1aa5e401fbfc91898908bf5524680085
+rgb555be 3f2940a75e77ed606025832c44e0364e
+rgb555le 7727c0b88bad1275560816345a41a458
+rgb565be ea41d5778aaa9d771aa3ed732d508ea1
+rgb565le a0ff4142dd837bbfc9ca8ebf0f817028
+rgb8 0c68336442a457e0ecc01af4fe283592
+rgba 1a7347d049f523fdb377d24c209110d1
+rgba64be f0e885fd18aaf45220bdde36df95a172
+rgba64le 7f043d06074c8ac573936df9ea497bf8
+xyz12be 4cb9f4b47d02089b824c7471b24589a6
+xyz12le 1000d2cd841586430c844e3b254a4b7f
+yuv410p 27b126789bb0fa0171d67e4bff86057a
+yuv411p 0d0d234e2f4417554bfa5c62c2aeee7b
+yuv420p 5683e1fe2c3125f140d9dfb025ff4a3a
+yuv420p10be 82459e6203ec39c21dfef93ccdb03f97
+yuv420p10le ea104a93f1798a8b7d48a7583077dc46
+yuv420p12be ca90b12e6a67f5470dc7272a6c5af2ba
+yuv420p12le 72786a5c34eac7ebd26baa75ff764573
+yuv420p14be 5e085866453f846ac5b41d0045c46371
+yuv420p14le 6825f0f1876303de8576e5203930f49d
+yuv420p16be caada8eed18c9b1a3765789412261fea
+yuv420p16le 04c49d9a9c6c6d8388a80a037ee124b9
+yuv420p9be 512093cac681bc30a4fe832d149b195e
+yuv420p9le 3b77b2c993d19a81a529b5feb661ab04
+yuv422p b0c57e1847ccefade6214359dbba389a
+yuv422p10be 36fa87316dc861d0ca28faeb83595a92
+yuv422p10le fa668d15ddfd94d46f4db8a68ee8eb2c
+yuv422p12be 1abe2eea053f807702e22c1b2f75a233
+yuv422p12le 44ee5fac430c99cb9f931af7b09e3419
+yuv422p14be 0ee2568ece15da65d2ce21783f2ef9f2
+yuv422p14le 1f04c8f882ad9051fb6464c14f61e78c
+yuv422p16be 6350e88697371cb3ba550bfc3d8a4d05
+yuv422p16le 5420bd643996c2fc10709ca58a0323e9
+yuv422p9be 0cf0d2f092b01b86cb8883e5b9ee70fd
+yuv422p9le caa7eabbc6cc12b91314d5a03857c3d9
+yuv440p 54ee388cdaf8b1fe88b78348913b18b0
+yuv444p 434403ed452af56f5bc6e96863eaca97
+yuv444p10be d7ef21572858c0071b5c74281ed8cb1b
+yuv444p10le 3c293e9a0aacd45fbcf9b6568cddcb4f
+yuv444p12be 143a391a1a5722bfb476724c8cb2dd5c
+yuv444p12le 570ff3794e15763dd53f54d2eaaee05f
+yuv444p14be b3ac16add13002a5cca2668d19a3aebd
+yuv444p14le 44eaf3ba7020d3cfb4ab7251dd0343b6
+yuv444p16be 795c309ec568cd4eb9b9cd97fb928dd1
+yuv444p16le 0ff751ac170c039e5c2cea00e9065df2
+yuv444p9be 7e90f7c4008d785c25f5e9379aa20541
+yuv444p9le 1bf226c716813e713f247eb39fdbac31
+yuva420p b805f9fad9e670fb87c2fa254db8a776
+yuva420p10be 9e5118ff02c71aee492948bdaf2ef116
+yuva420p10le 682b1220ef7495e6a70c2c69923416be
+yuva420p16be bed3c6cac6f188f7f0b388beeba144f8
+yuva420p16le ac2dbb6a9e3ef79782eca4d7885e5e70
+yuva420p9be ddc6a2ba66a42b2e2d8e9a75e0426073
+yuva420p9le 15d9d336ea76798159309eaf8a81f71b
+yuva422p 1f5e5be0a81413ff624e2da3c9b5ff0b
+yuva422p10be 27a3bc7e422483ccc84f4ce7afe7fa36
+yuva422p10le 6a5185cf6f174f33577ca44d69f42a39
+yuva422p16be 9f77ac57d045130d4402e52cb5c6fa5f
+yuva422p16le efd4b506ad2851c5d11f403f5f79b833
+yuva422p9be a0013b146490bd943c5f989a138c5e2d
+yuva422p9le 5440db83cee16f6f1b49130fee76b65a
+yuva444p 79c57d621f664142101bf88c3d947776
+yuva444p10be 784547c017774839255831836c3f41cc
+yuva444p10le c528063241ed798bbbb1ce9001691519
+yuva444p16be a8d8b0620b92c4dee0385f52d34d401e
+yuva444p16le e1f9622ba10c0cf1ca8d8aefe80ad272
+yuva444p9be 1df34b1a5b7ac4d6fb087728a7d2eb0b
+yuva444p9le 8471a740d2d7af99802539fdda5297c2
+yuvj411p 71449a14b9528bae023a46f1b23e4cf9
+yuvj420p 1d0b465815230b10ebbf6a7de4475230
+yuvj422p 58815ae40359ca3f0023e724eecf4896
+yuvj440p 4dcc9e6e899b17c5d910ec4d4f265828
+yuvj444p 1387fffb3b61d6dcb6e845fd50ecc667
diff --git a/tests/ref/fate/filter-pixfmts-field b/tests/ref/fate/filter-pixfmts-field
new file mode 100644
index 0000000..4023d18
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-field
@@ -0,0 +1,119 @@
+0bgr da40e8ccfd148cf8eaebf7586132d045
+0rgb e247794e532df9e2c70938acc7159812
+abgr 778f96e971a11a4d33db88d9359cf835
+argb 51cef8b83532ff5803413d8264312426
+bgr0 e22ddfc7d7f420955315dbccc19c6f88
+bgr24 bb505cc8b02aabe37ee68e2391fce435
+bgr444be 259ced749e1d94eadf1401d4d1cd92cf
+bgr444le 77346fad55a531016553ab6a41203c23
+bgr48be 562116f5ad37cf9a57dc3077276a5c52
+bgr48le 803718e260ff84c8961e2322b0aa77c4
+bgr4_byte c2363d641e39a3b3529c3ff9e625b58d
+bgr555be b070a363d939b19ed5e2f8d10935e6df
+bgr555le 3c51c7ba5110786bda62b30e94c28d45
+bgr565be b2a3f742b2f4e6d46ec10256537b9f74
+bgr565le 910e1d53030dcb2216e64e63e1683d09
+bgr8 5ae2b998f1ae54a9f1aee8df508fcc16
+bgra 8ec6e2a10c06dea5c83c92316efad900
+bgra64be 5feb3132af84db36b7a2dd99f9185fd2
+bgra64le 77cb5875f094bab68d701d0ebf3902f3
+gbrap a145cc653f0e30df7646c6310a22a270
+gbrp e43a0e1eb1360124f1ef7dc13270767e
+gbrp10be 2b94a60221a200c8a017fb13b142306a
+gbrp10le b40a0d25fe6695c216e11ffd53f1ef6e
+gbrp12be 633ced5d9290577573b3da4b5266dfd7
+gbrp12le d18226724a83b979b41347061ccf8d0c
+gbrp14be 3053d53652f6b35a32c53f2d7858215d
+gbrp14le 40611b24e43b4f41a14a86501040717c
+gbrp9be 50d9e81ff97bfe6dfe21c703d4ec85ba
+gbrp9le 33d8622fc0e4244b1c95f14a898e9183
+gray 0ff5c743f41244240c010e39b25a509c
+gray16be a35ecebecdb0e4209e38519adad52429
+gray16le 8cf6a024f9bd2034a2ec6ba10eb34ce8
+monob 205fa455f3dbbb46326bc8b93ac1b8b6
+monow 673df03c4dd7371e4e8ddee4fde72691
+nv12 c8bd4d74563cfbe12cea49907d0bbe93
+nv21 75838b092b464f61a1224dba16b6bd28
+pal8 10f7b4ca6b02425dc26809dc1c882b17
+rgb0 90e8bb1e5da4b51d99f28a4573737c0c
+rgb24 6073589b0f8498b69955adb2cff5c962
+rgb444be a5020766d8e2b4b02e4f6fb0e4df17eb
+rgb444le 812898e56d6a0d939241f9f070a3d05e
+rgb48be d66d9652de4104c563e162f5710f551e
+rgb48le 5ae3bc8d675d113a85ca4fd8b440e6bc
+rgb4_byte aacb867629a017c97269a8739474f5b3
+rgb555be 5fdb26f93e0ccb1bc8d3adcafca53929
+rgb555le 941e33a73b9575ee5a4d037da5d36e86
+rgb565be b43a972ce8b63cee54a398f0b823b310
+rgb565le db624d8125bbbf2711c62b93dbd4cc97
+rgb8 8074e19f6cf4b79e93ba0a5e76e16a21
+rgba 2e855e00c7415f8698f7d332d3ef07c7
+rgba64be 6ca359313c4819215c58137584be9d5c
+rgba64le 61586310c6b20e985fda58527c07625e
+uyvy422 5091022709f8e2f90d20afada267056b
+xyz12be 88f8ba489f0d5d74061508f8b8e5a1e8
+xyz12le b39ce3f7e10f3b8f9c56eb71e48de667
+yuv410p fc15f344ce228b16b6d35ad6668dd6c6
+yuv411p 4763ecedee2d6d951f84e5c84602b64e
+yuv420p 8234e4e976b7867eb8fea90d54b08d6d
+yuv420p10be b6bae85f66170adffb4939812820c6c9
+yuv420p10le cf714c34cd18d13ab1b348a366d627f2
+yuv420p12be 987c004cf05e500d70823133e30b4101
+yuv420p12le 0c840d9c2456863653332bcf4b764068
+yuv420p14be d3d9d84a772082735940eae6106f1df2
+yuv420p14le 04bcfdcf9ec4d851d4ef7bdd4eae7ec0
+yuv420p16be d84d447fa91aba9368fefab32facb670
+yuv420p16le 9a967ce79ef2b65c05128ca8ce442c3b
+yuv420p9be 9f8b1f03b43691e9c9f0f0e6a6cbec94
+yuv420p9le 61897b91251f360c026cf5e1e7de8273
+yuv422p 4ecb3e22f22ce0b7b348ec97ccd4c95f
+yuv422p10be a9f828e6c59bb44ea848392e601e74ed
+yuv422p10le b90a0531c38a5b3e3cf7f7dccdc3e7ee
+yuv422p12be bfc36b487709b2b9964e9ab77c4108e7
+yuv422p12le 2aed4636fbb852272ef4ee62d646b95b
+yuv422p14be a8ad6ac7d2b0548f5588cdc90d269893
+yuv422p14le 74abbffdb88ae77b6718987a23cc945a
+yuv422p16be 009484dcc7faa2656a3d5049ee1c28ff
+yuv422p16le b35565fe10f9a15b71d3706877118d8e
+yuv422p9be 41605ec9fb967cc3da4ac88d8c4ca6ba
+yuv422p9le 10bf2ae59bb45f5d632afe2fa0788f17
+yuv440p 4558340790744ccad447adcd3c8f041c
+yuv444p 018c531ab9b4427f6b3ae863306f7bdf
+yuv444p10be d45e1d588191d1e038e88ca3406bfe14
+yuv444p10le 991363b633a740ae2fc48d8cc8bde0b3
+yuv444p12be 106ee7c13eb39c1cf6fac07f0c129e55
+yuv444p12le 964b5dc1055c6faaaff1033791a82859
+yuv444p14be 8d0b2a6c08fb8b62f5ae1745671ef466
+yuv444p14le ba9706bfce142cebf861baa42c609691
+yuv444p16be e894084b5173960f66cdf0be179f8828
+yuv444p16le 34ca4cd51f22eadbb379b116b30e66f8
+yuv444p9be b3715905e1a2b46fa776e2dc6845eae0
+yuv444p9le 0474a78522158eaa049870a84aee9aa3
+yuva420p b3dede844de94db4622f700d8bd43ab3
+yuva420p10be c49dc6be444fda3f719be75125c1af65
+yuva420p10le 8c4cea6082c1566d5240d51eb21b9c21
+yuva420p16be 08347d7eff7b9c0e2e140f7e1ff98392
+yuva420p16le 3d6332129ca396b62fe7013ae60c0ad2
+yuva420p9be 066e66cac039be9c7ea7c4b8e3aeae88
+yuva420p9le c792a6e6ce331f9f2b10c0c6ad944b5d
+yuva422p 000da58b14a2a73f2d47267f87581898
+yuva422p10be 782d92de7de5322ff4e950712ec992b2
+yuva422p10le 5c2e0802bb2bfc9e32963d785c3d760f
+yuva422p16be c0b197bba30c9a04ebbe09529f996c63
+yuva422p16le f64595d50dc66ce4ef2f8376097561d8
+yuva422p9be 8026e04dcbf11fde5b4236f182dbcaa7
+yuva422p9le 6897400d7317f318f6d14f5488dba413
+yuva444p 152be56f7c6ea8c9ed2c595a84ef9fea
+yuva444p10be 6af6c6e15d213c71392bb9871e9eb4b9
+yuva444p10le 3aa47775cc47b2054eb3264a847294f6
+yuva444p16be d7d17d7165a5c8e9bb55f81e3a204d48
+yuva444p16le ee067aaac4fcbb2c2ab728bbeafd6b6f
+yuva444p9be 4daf3aeda37b259c63fdea951557786f
+yuva444p9le 80fc6a6dacd5b1991b500a9e9c9df7bb
+yuvj411p c3b81c898d51924b8864e56ba557e632
+yuvj420p b6d76f36d0014bd00e4a833be0cdfcbe
+yuvj422p ba411e3632a9d565b7721233d2c4302c
+yuvj440p 7e8f985279ed6e38fee52f06d6648d54
+yuvj444p 4ead7294ec3a6d6a84a208248280acc1
+yuyv422 adfd70357cf0abe7fe6b3139621c9b97
+yvyu422 802a6d0fd0561e872f56d2e25a9a7eca
diff --git a/tests/ref/fate/filter-pixfmts-fieldmatch b/tests/ref/fate/filter-pixfmts-fieldmatch
new file mode 100644
index 0000000..22d5549
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-fieldmatch
@@ -0,0 +1,5 @@
+yuv410p 08518d1ceaf740696b26eb89325987c1
+yuv411p ca4b3b96c4f487fc293ad8d631f37660
+yuv420p 2069df6ae54ce80f82d591ac753e66cc
+yuv422p 7b4fe261becce67a0eeeea0b6886d9f6
+yuv444p 5a0ca602480a00e662017c2ecdfc4e1c
diff --git a/tests/ref/fate/filter-pixfmts-fieldorder b/tests/ref/fate/filter-pixfmts-fieldorder
new file mode 100644
index 0000000..2f9e298
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-fieldorder
@@ -0,0 +1,92 @@
+0bgr 87e4c14d6e3377bae54cb08ee3b527a4
+0rgb 67835d4d5c75f773cf316bf82317f7a9
+abgr 2c35d478cac0fa76e840cd455203f8e8
+argb 7d833ab271baeca42ae82c425d5583a1
+bgr0 3a00a32a238af8b2bfe9ceea3ce5e3a6
+bgr24 f4a6c11d6b49f530f0dfa26196e8cd1b
+bgr444be 4c8a1ef65209044402e3fc0a706ab0e7
+bgr444le d62aff0548bd7715c229f37c8f5e2077
+bgr48be 857859896ad2885ce012b1437ee3311e
+bgr48le 1a2a9a56bbeaa36493da520e61c9140d
+bgr4_byte 47665ea920c2468c250e24579eaec01d
+bgr555be 99205a9ce3678daaf552372dcf03678e
+bgr555le 05a98219aec9178fdf023578f68597a6
+bgr565be 1cccb7efe4ceb6e15b01d6e091572694
+bgr565le b48ee4ff1d25835c529812b5ce081d2c
+bgr8 2e3dec1c1478f205bd263f1d35dbd301
+bgra 736a847ee15006866720df4e8d7cffd0
+bgra64be b1ac6b0ae9fbc1e7485d78d758ae7855
+bgra64le 82017083411b9c78b9de682f95e001a6
+gbrap f5dd667bc2438cb74eb709a4d8c504b4
+gbrp aa6512b64079355b3d6069e8ce257115
+gbrp10be 83f7eb6db542508ab2aa8e4045363498
+gbrp10le d081d44402d3e84a7731a9509e4842d7
+gbrp12be 07549ce0bbfa9d7ebf807925e32cb52c
+gbrp12le 723a946919a3a35e6b4a5a6b81affa64
+gbrp14be 904f38b9994d711dabf59edaa3704bd8
+gbrp14le 87935220dedf260e2f26d91304aaeb67
+gbrp9be 0719eee49ac14369e5decccc965d364d
+gbrp9le 1663f26a123bfd93a53b83a72853f8fd
+gray ca1ae72fd165cb0e793dbf44cd17cb74
+gray16be 5cc58221802f9566613bec7ee27f05be
+gray16le ef44719f4375b74a3e562ea0cddc5067
+rgb0 209ccbaf7e193c0d6843fc9c086e0db4
+rgb24 2a9189f9baf29d81371dd73e792fcc1a
+rgb444be 3b10f406d79321d77884305cd4026739
+rgb444le ac1b4501e8d5b19e1d51f6948bb109ce
+rgb48be 2d443f167878bdd1a93f34d7b01ea766
+rgb48le a2f86eabf14d3b292dd45a060ecdb41c
+rgb4_byte 76a55b794d4c652a10a7dba4be89ae33
+rgb555be 983a31785d83f99f32ee6292846cdd9a
+rgb555le 9e02ef746849c955ce0dc5c66bf0f77b
+rgb565be a47bcfd2efcf1ab824506d0d7952c6ec
+rgb565le 18b176356affe3bfec67ec8bf8a63095
+rgb8 6b8a7bb3aa5bbed22b6e7c6b6e566a33
+rgba f216a9c593319dd89d78cdcd97b111a6
+rgba64be a657ad856d26f894ef909f3ac6774079
+rgba64le 700fa5ce375b69fb177da41582e78f60
+uyvy422 a8d8f7f2e799725dad9ab945711bbc84
+xyz12be ccefb77b2fa15dcb925b494a7872cd83
+xyz12le e33e4809336203709b87999ff53a5f1b
+yuv411p 63d3858b1ce40c97fe8be19a21886557
+yuv422p 828d0499b48aadfc3d0787eaeec178ae
+yuv422p10be 8364845c98449f49feded2c907c26c11
+yuv422p10le 7d64b97a71d6276a44f0a2c0ccb396e4
+yuv422p12be 1f619504129f53a87050443dfd220f29
+yuv422p12le c4597c632fb4dd91af6b3183a569b63d
+yuv422p14be 674ee482c19ff53105f9c7ee333a4948
+yuv422p14le b98d87cbdab7456f4e0962c3e7b9a2f1
+yuv422p16be c3e4c5671aae6cbe572995a2a537099f
+yuv422p16le 25608d9d2882c24652f4c7277c74b1cf
+yuv422p9be 7a3752f28c6e6cc4d3d72a35c57b6da3
+yuv422p9le 377557cf7c12d15d0b0cc4dfaea4d748
+yuv444p a75c960a41e1987fa2b85456411d971f
+yuv444p10be a2f74aef9316b56dde187c383cd70273
+yuv444p10le 6ce92cf2129498e049cd41461ad8fc72
+yuv444p12be de3ba0096885b72a50611606265322aa
+yuv444p12le 8f6ec998e360298759ec5c4f5788608b
+yuv444p14be 6a93535d841807b7f804239a30883e04
+yuv444p14le 4cd381fc8bc7d41debda5ac7aac96117
+yuv444p16be d2bcde1e26bdd53edd9fb6f80418c92c
+yuv444p16le db108fcc80db08bf6a3852477c320f39
+yuv444p9be f14a9b7d6265c5bb03e4c908454dc61d
+yuv444p9le 7f0fa36975c3935ba83e33cd1076ea55
+yuva422p 0efaf456ea8a75321fb87a7adcf586bc
+yuva422p10be a94b98c1cea8c0215c0b27fdc2f66348
+yuva422p10le 2130fd0b256888ea6d235851eba9212f
+yuva422p16be d60b712e6ff309606a0a0ba721a93362
+yuva422p16le acdfb43cae949e9cc597f594cbf56170
+yuva422p9be 86f77fe1a26cd223745b86ecd7d3a499
+yuva422p9le ebd5681fc413c2e1cb5612f8a6883aab
+yuva444p cf62854472ae46951e74db8b75e760f3
+yuva444p10be 4bc8c4012d17b0821600d90d3d2c1bba
+yuva444p10le 8c4347ea6eb51866035b9307bfe552a3
+yuva444p16be b81b586bdddb311933a0c0ab4c468e34
+yuva444p16le 758266b13c9419cf21d704647c44bf07
+yuva444p9be 76cb30498de990bd1f6016ae653033c4
+yuva444p9le 490abec545bbfc8669e24e76412c23d0
+yuvj411p eabc1185ec235305fdbee60d5f9de13e
+yuvj422p f290bae9a4a91e42d8c1ad5e4013fca4
+yuvj444p 390ed32d78a59c2fe7303954e198c45c
+yuyv422 846de2f21f1433fcd884a210713286ad
+yvyu422 75757dbf4a28debe42f44f07f7bbe06c
diff --git a/tests/ref/fate/filter-pixfmts-hflip b/tests/ref/fate/filter-pixfmts-hflip
index 3741713..97b4165 100644
--- a/tests/ref/fate/filter-pixfmts-hflip
+++ b/tests/ref/fate/filter-pixfmts-hflip
@@ -1,42 +1,114 @@
-abgr 49468c6c9ceee5d52b08b1270a909323
-argb 50ba9f16c6475530602f2983278b82d0
-bgr24 cc53d2011d097972db0d22756c3699e3
-bgr48be 815192d3757c66de97b0d51818acbe0f
-bgr48le 8e4184ac6eae251b4bace51dba7d790c
-bgr4_byte aac987e7d1a6a96477cfc0b48a4285de
-bgr555be bc07265898440116772200390d70c092
-bgr555le ccee08679bac84a1f960c6c9070c5538
-bgr565be e088789ce46224b87c6e46610ef19add
-bgr565le 3703466e19e1b52e03a34fd244a8e8e4
-bgr8 50b505a889f0428242305acb642da107
-bgra 01ca21e7e6a8d1281b4553bde8e8a404
-gray 03efcb4ab52a24c0af0e03cfd26c9377
-gray16be 9bcbca979601ddc4869f846f08f3d1dd
-gray16le c1b8965adcc7f847ee343149ff507073
-rgb24 754f1722fc738590cc407ac65749bfe8
-rgb48be d690412ca5fada031b5da47b87096248
-rgb48le c901feb564232f5d0bc0eabd66dae3e7
-rgb4_byte c8a3f995fcf3e0919239ea2c413ddc29
-rgb555be 045ce8607d3910586f4d97481dda8632
-rgb555le 8778ee0cf58ce9ad1d99a1eca9f95e87
-rgb565be c8022a1b2470e72f124e4389fad4c372
-rgb565le 2cb690eb3fcb72da3771ad6a48931158
-rgb8 9e462b811b9b6173397b9cfc1f6b2f17
-rgba d3d0dc1ecef3ed72f26a2986d0efc204
-yuv410p acb543ebbbf63eefe533e6faffc006da
-yuv411p c626cf6d191139b4ca7efc0155f957f1
-yuv420p 2d5c80f9ba2ddd85b2aeda3564cc7d64
-yuv420p16be 758b0c1e2113b15e7afde48da4e4d024
-yuv420p16le 480ccd951dcb806bc875d307e02e50a0
-yuv422p 6e728f4eb9eae287c224f396d84be6ea
-yuv422p16be a05d43cd62b790087bd37083174557de
-yuv422p16le 6954abebcbc62d81068d58d0c62bdd5b
-yuv440p a99e2b57ed601f39852715c9d675d0d3
-yuv444p 947e47f7bb5fdccc659d19b7df2b6fc3
-yuv444p16be 58c012e5ab73b066ef3c2b6411a395f1
-yuv444p16le 32c12794e184042a59738ab2de608c8d
-yuva420p d83ec0c01498189f179ec574918185f1
-yuvj420p df3aaaec3bb157c3bde5f0365af30f4f
-yuvj422p d113871528d510a192797af59df9c05c
-yuvj440p 07f5ff12ced85aba1b5cf51692fff4bb
-yuvj444p 8d95f6b4d4c9b4b0389d36df686bfa46
+0bgr 62c0dc8407c8bfedc4f7030d90f961fa
+0rgb c589d3f9f8ffab05582b3b700d5d11cf
+abgr fad9ac424ee86f3fcbf6652565caa006
+argb 7f5454d8a5b4c1b292d055653f44e838
+bgr0 ba29a864dc098b75ab154766463f60f0
+bgr24 fb66bbb185312b51477f0dcec23f9243
+bgr444be a1da1347c242d95e3f491ca2ebced5b6
+bgr444le 8781877c57b87461339e9fab76502e5b
+bgr48be 5948b1b36e82c8d39306a331ffaf9b59
+bgr48le fb9a9ecf8e5878c55bc47e50f8ec7472
+bgr4_byte 7a2a195a99a8a64e55b750b66c117523
+bgr555be f869793742746ada03de17e85cba7400
+bgr555le cfffac5557d65e7450240089c628397d
+bgr565be 88a7d3ea7cef00c0b992d9894aced78a
+bgr565le 520f41f1f6889e2b9ac115810b2fc32a
+bgr8 a0a58190f00f9b3cd664df5e5a12a368
+bgra 587390de9dd066995cd7a24cc01411c2
+bgra64be ccd2b9941a8eb6a8578df7ea8d301c55
+bgra64le 2dbc6f9b03c2d2ea385423c97d837aa2
+gbrap 7469feefe6c5e859494bb15be073a4e4
+gbrp 00534ee5f27ac7ccfbf178e19e992dd3
+gbrp10be 4be5e92dd91c9f021c71969119eba6bb
+gbrp10le 11f1210504144efa505990975e7b735d
+gbrp12be 007145b9703f6890a27fd0ed1384fd2a
+gbrp12le 78392fe0d6bea1b64b08ecf00fbc0580
+gbrp14be cf7a394be8a51a42266b092bfe550123
+gbrp14le 23fba36e3b2703ff487d636dcab07629
+gbrp9be a70297de1c2da7d9a1721fbd809d69c5
+gbrp9le c67297e85c1707317f04258bf3a7cc17
+gray 460d0f736a63b70ac1d4331f9ff3380d
+gray16be a3c2f891649aa6337682d423a33b3f15
+gray16le ef9f8e6f2bc20a6dda884205d0d3f076
+nv12 b83a552443aa43efde11e7bad47393f5
+nv21 671c206b03ac9d2f56e323ad702689c3
+pal8 b15f61c785b5dd347e126f5316b4b554
+rgb0 88b4288b4dbace449e39675f02948ad4
+rgb24 62afbb93549d4912e800ef8dafa34ed0
+rgb444be 3084118ef48129c38baee4adc3686cd0
+rgb444le 7d6e5e6742761ab4aed0652baa236213
+rgb48be 591737c3d532d721915e43bcc94e9fc6
+rgb48le a5cba08bd5b049738155aff294c5e864
+rgb4_byte 636865fcebe6e87564087ad44e481085
+rgb555be b4d023fb9a5bdcbfd88bb6d0e889128c
+rgb555le f81be3135c6186a977cd7a9c37948fdd
+rgb565be e1ee3f91358f51841559caff850d7b09
+rgb565le 992aea678a434e5aa46bb6bc6ecad205
+rgb8 618e1f474797a4008fb45e1fecd31571
+rgba 94c432b19055081b0f2c4ef4df83c7c9
+rgba64be 0106f21ee49b5658ca51037a8358b851
+rgba64le 8d634d18a2d6255ee37c9937f9b776c2
+xyz12be 3218766b866b1a958799f2231a1760af
+xyz12le d616708c5b8ffbfb960fa112df2c7c02
+yuv410p 3cf18ea881884223e798063d7a6227b4
+yuv411p ba99a290df25bbc99c8da014876c7f8c
+yuv420p f4718aad178ced96ff16466fb0454490
+yuv420p10be 9ef247d488ecd4ad9cce0cafb2bd4c03
+yuv420p10le b3b4d183aff923c8992a1076d51f6a14
+yuv420p12be b25dc59d848f87f229767ae041b7836f
+yuv420p12le 94fa01559df13f10ac426a410ce7422b
+yuv420p14be 984b4d286b5322be557f135fe5902f85
+yuv420p14le 9fc1cfbebf9e7419abd19a323282196e
+yuv420p16be cb58423896d429f6b1378e83a9dc35d7
+yuv420p16le c4bdbc33ccfc668e3979d18982d0fd12
+yuv420p9be f14fdf5b9f5ff296fc750d6b9ba6f991
+yuv420p9le 07d07c395c4a17666a69cbe6ddef7fc2
+yuv422p 1855d103d1995a2daa95252226eea394
+yuv422p10be bf32d8d1a96708703ee45942f7770db2
+yuv422p10le 61df19909db569953d4a6efc96e0ad61
+yuv422p12be 4d5428ff5df7eede5fe49891b4271695
+yuv422p12le d8dc60b5d05ccc5419051402462e7c1d
+yuv422p14be 5f41c1c701a1fa1d6fc3e08bae35c9cb
+yuv422p14le e1ba0c61696b09838d3aa47f3e18223d
+yuv422p16be ed22d602c9e6f6a8627d0694a7fdc4ca
+yuv422p16le 02975f7af27c35e68684235d185a4828
+yuv422p9be d4fdec159cb4c106a81e407fe1b441be
+yuv422p9le 7a19175e5e38a028029cf6c14f5485d8
+yuv440p 18b37e71484029063d41c5716cd0f785
+yuv444p e666141ffbbc8ed5ecfd65bf27b07c72
+yuv444p10be 39437baaba84ff78b152769202566acd
+yuv444p10le a8c9900e3593919c029373cc7781e64d
+yuv444p12be 323a0510d12d3d473a9751a727aa9da0
+yuv444p12le aea9acf0d37b3c8603c02be733239e79
+yuv444p14be a2d31ca75e52a26a1feeb7b1477b2315
+yuv444p14le f41c19e54da37587a4b6f3ef09e3ccc6
+yuv444p16be 6467f6e5b939afef13353a76b9ae6b4a
+yuv444p16le 41f0561edd3c81fd853763cf70d0ea69
+yuv444p9be b049fafb30796f808fb921846b713158
+yuv444p9le 7442e01cde0fd3f477d08ab557acf9e7
+yuva420p 7eca570c9d353f82df64cbb0428bf912
+yuva420p10be 318988d51adb8df54f2db35e30efc01f
+yuva420p10le 5a8013321ba7a86097fae24ff898a94a
+yuva420p16be 033329cf69ff22f15394645c0bf132a0
+yuva420p16le 744fd628f72cb1c0c9c7493d7cd6def9
+yuva420p9be b2abe1fc6dae3ac013ee1c9da8e77dd5
+yuva420p9le 48f859b2184cae6bef8a820d49d1de6d
+yuva422p 7a9753f866cf59a63fefc3b3a6b71a88
+yuva422p10be a7f4c5add41ad5d62e539bd0f30631e1
+yuva422p10le b17312f0335ef77cd96d5097ab6bbef8
+yuva422p16be 95083847b4cee02aabd9ccb6b9b5c5e8
+yuva422p16le a12d042ae5ee2fa4ac6390cca87d8c7c
+yuva422p9be c364ee7d2e394de73e139474da5a7642
+yuva422p9le a090cd6be95928567fb0edc9d9438f8f
+yuva444p 6a4f6d23d820af40b831bca12ec7e153
+yuva444p10be 8ce49bc46add1d63bc2a0561b11fe36d
+yuva444p10le a9247f4c96d3241858d482f4b52e2b3f
+yuva444p16be 3b879425868f36b83008b265eeb425f7
+yuva444p16le 6771f76ac929369825b7e9cafa4b7264
+yuva444p9be a240dc0a0fa02177fdeb51571397ba78
+yuva444p9le ff34f13a8fa1c49c24af005d89edcf93
+yuvj411p 242d4306ee7b76e8a8cabae17c6392f1
+yuvj420p 7e74c8ea515cc80b5aacf6d98940840e
+yuvj422p 58f001ed095aae9952e885669bc6f0a9
+yuvj440p 13ea331ee29d87af155aa87dec4baa1b
+yuvj444p 0560df72ac64519b6c29e5df4c3d4ed2
diff --git a/tests/ref/fate/filter-pixfmts-histeq b/tests/ref/fate/filter-pixfmts-histeq
new file mode 100644
index 0000000..a250902
--- /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 0000000..e3992eb
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-il
@@ -0,0 +1,118 @@
+0bgr 9eded8f32c68f7ac1a9b193a99ce09ba
+0rgb b4dc02b3db8e378029202d8de0c7e2cd
+abgr e66274a79478a72e2e6bd14be05950b9
+argb 1fdb247f982a305a5dc95fd662cf583b
+bgr0 a0c8efd0fd721d05a87ca41f1156be7c
+bgr24 2fee903a9a4c4411656bfe43e845eae4
+bgr444be 4035d08aa7eb0bb9b1165f21db43bf49
+bgr444le 067af68192af9c8b80d529e50ce8c7cc
+bgr48be 9712780cef8aa67417a997fb01259f45
+bgr48le 4945f4513ac7aa7da7199f0cb7114ebd
+bgr4_byte 1eb031ef7470e7f12f425adc8da54eb1
+bgr555be 77590a767858f467987ce85526164998
+bgr555le 42eef867a53bf544bfb163c3905da40b
+bgr565be ddfcb8711b76b548e36f84f847a985a4
+bgr565le 6df28910dfa046a80e2661c13bae393b
+bgr8 d560799e113ebf3fac2d006485394c52
+bgra d4755c172ca15a4cb3d26f226c17ef97
+bgra64be 3b38a8f5257e515706b424bf33915a65
+bgra64le df508adc2fd31a1d754c9faf3e9044e3
+gbrap 1b41767ca1de932c654275849a38769f
+gbrp 0a1790e275dd089b7ed35eb4917d65ac
+gbrp10be f4b749ca22458fcff8c4afe06e8fdd32
+gbrp10le 341a84cdbe06d876c15ec76a75df5c5d
+gbrp12be 693a8a9fc7099d6baa716a20ad28feaa
+gbrp12le 12e7f0d8eaf54c6e50c1088cfcf7131d
+gbrp14be 3cf8e3be290b0558d3d17dc654968fb0
+gbrp14le 122601e60d3298f2720e37fd9ba92d4b
+gbrp9be 6e495a6ff70f1008102fe787ec076ba2
+gbrp9le 35cd5c8a66fabe16047251d4384f0ea1
+gray 1ecdbe783136ccecd51ee105efc2a4a9
+gray16be 8bea3fb5ba687fdfcc4340aae268bec9
+gray16le cf250abe6fe20d402f4d672a76c29e39
+monob 08ec835d9c5a90578e05b82a85b4f3b0
+monow 2808420bc8ff291e27daf16dc87990f4
+nv12 13b8f8e86c93e6fc53346884983d1e59
+nv21 b75609c49d74f51f7552a2b3c3e79632
+rgb0 5587b57404a8646071e55e915faade5a
+rgb24 1dafaa9b67687772ea55461dc034b28a
+rgb444be 39eb5acc4da2829b8c30452b09623f43
+rgb444le f0b41a1162dc303ee441ad28a13c1570
+rgb48be dd92d2605758f944d075819c3d991589
+rgb48le 5b473d5ce25126949412721d0a55ad7d
+rgb4_byte 637911d85ed773e6374e4c1cb249ddc4
+rgb555be ca555c54f844dd69c6563af5429ea7bd
+rgb555le 6ed06b8d9774e17bee60a625d6f4d937
+rgb565be 06b421fa3e499b3e9d4013574ddeb654
+rgb565le ebcef31d12af8f17bec5a36c379e50b2
+rgb8 c90695c74cb20df324f43e426834aa8e
+rgba 38b2c628e167e150e0094038bfb6548b
+rgba64be e239083765579fc97e01d1b6caf54dbf
+rgba64le 266364e7212cd2fa0882999cd502c7ba
+uyvy422 c372c0e3574f92d1fc923da006ca074d
+xyz12be 4523aa53eae97de4b5415d3a155e6ee6
+xyz12le e97355f5c22045c4d6aa31e74d2bc411
+yuv410p 55e672ea60e9f0e982bc2f99d4964dff
+yuv411p 4e5d919cbbb5c4034824ee777c34e46a
+yuv420p e24aa0234e84f6f53caa5d3d10bbc49b
+yuv420p10be f858ef2a1ed40ec071d9d794a39401ce
+yuv420p10le c4970eb75151077040be61fe8c9572f6
+yuv420p12be 5adc2cd69721f7cd3d436c8e297a483a
+yuv420p12le aea48d6faea1f58d559f1dce4e989f6e
+yuv420p14be 4b1014dc7f58b17a123b2e21141bb7cb
+yuv420p14le 259021fa7ad8e968638b6ade9dcceb9c
+yuv420p16be 280439052fa7ba9da4271cbc8e85671d
+yuv420p16le a101ec2b87ce10ecc5a622ef7dbd160c
+yuv420p9be 8e660afb3e04469c3765c2a719c56099
+yuv420p9le 23b5c65e767e4de3dfbb0f9b6a6c6972
+yuv422p 3a73dd428e915cb01c55ce3913658939
+yuv422p10be e499378daeec408a7ce2c15f869be54a
+yuv422p10le 4cb3417eac19ff7e0129c5c915f1046e
+yuv422p12be 508c1bcefe3bd1d1de0b44d8ae447474
+yuv422p12le d103d620dbe6ba000044f2c6294bd13a
+yuv422p14be 7a39893b1fe54e9e88fae741e6951df7
+yuv422p14le 65d4c2c327a903f6d4b0a435524a7999
+yuv422p16be 850e0d0b4feb48c8c14e172de7e567c1
+yuv422p16le a1dbef3752c0c578e0285980a5859864
+yuv422p9be f3e1b7196d3e17ad5d31d9d200a2457e
+yuv422p9le a21cb4b38bbdee136f70c15abecd5f8b
+yuv440p f0cfcb6a845fc7f33ab54f04e5f61099
+yuv444p 8bf605570d90a638980e1c11526d99e7
+yuv444p10be 755f929aff54eda092127fca283cf333
+yuv444p10le fe216173a6b4eff5c029d468861b3da6
+yuv444p12be b4378896cdc5d11c0f861384b053c66b
+yuv444p12le 18c2b0c8b2782733fd81cf1aecb51ea5
+yuv444p14be 6af38d0fbbed53040c7935665e9f728b
+yuv444p14le ccc3ac62e2c7ab69107bd79b132c53a6
+yuv444p16be c392cd118a1813d3d6eb85d37bfe0a75
+yuv444p16le 71aefbed6ddf5c85ec421a7be04c1d36
+yuv444p9be ed5f899b0e9055b87896b2747bfeb3db
+yuv444p9le b53e702b8b5506901e09fc150ff96510
+yuva420p 1de168e7f9d7185bcb2724e3c017c75d
+yuva420p10be 0d9d69c9689892925b3b9aaa617160cc
+yuva420p10le 1abdcbcb7e1e6f5ad5110d6d32223a52
+yuva420p16be af08ba92e1e1622f6bf2b4ec933b916b
+yuva420p16le 04f1b058d84b18087307d7f3cca35c33
+yuva420p9be a4e26083fc89e73f2f51e90c414ab44c
+yuva420p9le da57847a85dd93a9875c3e03929b7fa8
+yuva422p 9845c629815148c54583343240506f6a
+yuva422p10be 80b8a7a7e22632f9a77e24c7e8a6f409
+yuva422p10le 157c25fde7c088e54efadf6e3108f6a0
+yuva422p16be a85e3226731777c94726dbf92b50755c
+yuva422p16le 9fd8eda7aba4922c42cf67eb1ad2b6c7
+yuva422p9be 9c0408751c14dd7474ef53faa5d94049
+yuva422p9le bbc2511d505364744014c5df307c8354
+yuva444p df5585dcd8c3ac78789b7ba384528cca
+yuva444p10be 2c41bb8c29f917271c14d335440b60d4
+yuva444p10le 79dfa39d248f4845ee8894e3b37ef782
+yuva444p16be 2918483ac55e52492cf7aadc09ea7b9b
+yuva444p16le ff3c3b4d415a601140d8eb39c4ce2e91
+yuva444p9be 0d5eedd3cf06dc399ecf1c7d879095fe
+yuva444p9le f58eb05ff7d50d732d33cbd78a80c42a
+yuvj411p f9cf651e623210cbcd5c0b4ad0ed159f
+yuvj420p 048ba7f77ab4bdd1ec3664f7f9cad978
+yuvj422p 209c34ab49969ea811ef915d6141a1ca
+yuvj440p bd6510ff3385d4c72ed27cee49565310
+yuvj444p 345d97deced4a2b3b527bcfe178c0a95
+yuyv422 aa7f6cb7b5de1f35269c60c13b9dc415
+yvyu422 da9e97e6bb74f95639069a635738b0cd
diff --git a/tests/ref/fate/filter-pixfmts-kerndeint b/tests/ref/fate/filter-pixfmts-kerndeint
new file mode 100644
index 0000000..376d8f4
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-kerndeint
@@ -0,0 +1,10 @@
+0bgr bdff73f3a0b22f29d2fcae461db92efc
+0rgb 6d19d706cc405fc7e0d0e941d34ddc5f
+abgr 6eb205786c9eb1419334f7725fc799ee
+argb 180b920be1f3b03234e327725a00abed
+bgr0 661a99840c4cb6d9bb755ab6fec9548b
+bgra c5e9622e15ad7ad276f50d8ebb7e994f
+rgb0 58d8a93cf254c8a7affef326a2e88367
+rgba 403329386173553df13d94c7230ec734
+yuv420p c1d71b5c7f1f65d7e27070355fc7c74a
+yuyv422 ce701473de3deefd9a8a1184e505ffe5
diff --git a/tests/ref/fate/filter-pixfmts-lut b/tests/ref/fate/filter-pixfmts-lut
new file mode 100644
index 0000000..f52b90a
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-lut
@@ -0,0 +1,19 @@
+abgr ba621149cf836e3040b31f417faae4f5
+argb 38a10f547a116087f4afb161f09f87df
+bgr24 0e14a84f8a498ecc61d65f6d7b2f6905
+bgra edc092372e78c03968e247e930687b1a
+rgb24 439d60a3995d71d227129f20c8077083
+rgba 2c5eb9b91888657a7ea033b70ed8b7ef
+yuv410p 9f25ea872cdc078cd795e5d243fa6956
+yuv411p 726aa70c7c10368e3358f83a274e27bc
+yuv420p 026f7be12e833017a7893f2a443adb31
+yuv422p 3a83fd6a45b44460fa53b2131d2b052f
+yuv440p e25b242fdf1683b0af3858ce3aa5f74b
+yuv444p c73795970622f64ba618f4ff773777dc
+yuva420p 144eac0b2d74f93f8a2e6da620282e22
+yuva422p 6831b3672beb871f5158f39f2bb2bcd5
+yuva444p 62fc47a98c133aa3f475f92b02505e06
+yuvj420p 23e02eddd976caa8c9d1840d56b5d6d1
+yuvj422p d536cbaac3a322156103768de3072e69
+yuvj440p 68e4837233bc868bf4f115e5f3b0a459
+yuvj444p fd69499b44f0a118e0f30f46340dda61
diff --git a/tests/ref/fate/filter-pixfmts-null b/tests/ref/fate/filter-pixfmts-null
index f99e8ea..a421734 100644
--- a/tests/ref/fate/filter-pixfmts-null
+++ b/tests/ref/fate/filter-pixfmts-null
@@ -1,90 +1,119 @@
-abgr 037bf9df6a765520ad6d490066bf4b89
-argb c442a8261c2265a07212ef0f72e35f5a
-bgr24 0d0cb38ab3fa0b2ec0865c14f78b217b
-bgr444be d9ea9307d21b162225b8b2c524cf9477
-bgr444le 88035350e9da3a8f67387890b956f0bc
-bgr48be 00624e6c7ec7ab19897ba2f0a3257fe8
-bgr48le d02c235ebba7167881ca2d576497ff84
-bgr4_byte 50d23cc82d9dcef2fd12adb81fb9b806
-bgr555be 49f01b1f1f0c84fd9e776dd34cc3c280
-bgr555le 378d6ac4223651a1adcbf94a3d0d807b
-bgr565be 257cf78afa35dc31e9696f139c916715
-bgr565le 1dfdd03995c287e3c754b164bf26a355
-bgr8 24bd566170343d06fec6fccfff5abc54
-bgra 76a18a5151242fa137133f604cd624d2
-gbrp 76204621e200a3cc633012f6720c7005
-gbrp10be 2ca4a4a589a7dc461ff186913c7a69e5
-gbrp10le 46176f1fcc6e67f9862115fe373f73d3
-gbrp9be 981c2c1b0ef1791824b4c7518331bc2e
-gbrp9le 25fb915ed11d07d631e0e7b78d54bebf
-gray db08f7f0751900347e6b8649e4164d21
-gray16be 7becf34ae825a3df3969bf4c6bfeb5e2
-gray16le 10bd87059b5c189f3caef2837f4f2b5c
-monob 668ebe8b8103b9046b251b2fa8a1d88f
-monow 9251497f3b0634f1165d12d5a289d943
-nv12 e0af357888584d36eec5aa0f673793ef
-nv21 9a3297f3b34baa038b1f37cb202b512f
-rgb24 b41eba9651e1b5fe386289b506188105
-rgb444be 9e89db334568c6b2e3d5d0540f4ba960
-rgb444le 0a68cb6de8bf530aa30c5c1205c25155
-rgb48be cc139ec1dd9451f0e049c0cb3a0c8aa2
-rgb48le 86c5608904f75360d492dbc5c9589969
-rgb4_byte c93ba89b74c504e7f5ae9d9ab1546c73
-rgb555be 912a62c5e53bfcbac2a0340e10973cf2
-rgb555le a937a0fc764fb57dc1b3af87cba0273c
-rgb565be 9cadf742e05ddc23a3b5b270f89aad3c
-rgb565le d39aa298bb525e9be8860351c6f62dab
-rgb8 4a9d8e4f2f154e83a7e1735be6300700
-rgba 93a5b3712e6eb8c5b9a09ffc7b9fbc12
-uyvy422 adcf64516a19fce44df77082bdb16291
-yuv410p 2d9225153c83ee1132397d619d94d1b3
-yuv411p 8b298af3e43348ca1b11eb8a3252ac6c
-yuv420p eba2f135a08829387e2f698ff72a2939
-yuv420p10be 299fe1d785a3d3dd5e70778700d7fb06
-yuv420p10le 8aee004e765a5383be0954f5e916b72f
-yuv420p16be 16c009a235cd52b74791a895423152a3
-yuv420p16le 2d59c4f1d0314a5a957a7cfc4b6fabcc
-yuv420p9be ce880fa07830e5297c22acf6e20555ce
-yuv420p9le 16543fda8f87d94a6cf857d2e8d4461a
-yuv422p c9bba4529821d796a6ab09f6a5fd355a
-yuv422p10be 11af7dfafe8bc025c7e3bd82b830fe8a
-yuv422p10le ec04efb76efa79bf0d02b21572371a56
-yuv422p16be 5499502e1c29534a158a1fe60e889f60
-yuv422p16le e3d61fde6978591596bc36b914386623
-yuv422p9be 29b71579946940a8c00fa844c9dff507
-yuv422p9le 062b7f9cbb972bf36b5bdb1a7623701a
-yuv440p 5a064afe2b453bb52cdb3f176b1aa1cf
-yuv444p 0a98447b78fd476aa39686da6a74fa2e
-yuv444p10be 71be185a2fb7a353eb024df9bc63212d
-yuv444p10le c1c6b30a12065c7901c0a267e4861a0f
-yuv444p16be 1c6ea2c2f5e539006112ceec3d4e7d90
-yuv444p16le 20f86bc2f68d2b3f1f2b48b97b2189f4
-yuv444p9be 6ab31f4c12b533ce318ecdff83cdd054
-yuv444p9le f0606604a5c08becab6ba500124c4b7c
-yuva420p a29884f3f3dfe1e00b961bc17bef3d47
-yuva420p10be 145366ff1632de3e300d947f49844284
-yuva420p10le d797038552d7f698e4d1db4dfa18ceb0
-yuva420p16be 25a335f66a0670911ced818aa42fb670
-yuva420p16le 97bf252e6c030f0f0412d3826c2ea259
-yuva420p9be 06b764d85bd3c22e9b7ca4babed84d4f
-yuva420p9le 1f01cdd4fc46f98d4c11b2947307a0e3
-yuva422p 92b6815f465297284cdb843711682cee
-yuva422p10be fb240ff9ac49b45b1b3d40df2c89e39d
-yuva422p10le f767ede9ba1d427faadc963cf41d2412
-yuva422p16be ef442b11b26e5e61f3c958fa309576dd
-yuva422p16le 5789009759d7a44dacc6da2194e402b1
-yuva422p9be e0d2f45f7f5541eee988137c7ebb3495
-yuva422p9le a4ec81f328efd3856dec430fb27f2f56
-yuva444p c523716e4900cfe515eaab1d7124fdd9
-yuva444p10be f5791a75fdb86da0c243511ef9ab8fbd
-yuva444p10le 578e88dfbe4ab07f280fcc7554f3a5c4
-yuva444p16be ee7b9dd854e36b165d5b7cffb646ba6c
-yuva444p16le ec93b2907923d5655e9fb085479260ef
-yuva444p9be 03414257d78e72c28d03e3c247319b7c
-yuva444p9le e421d753257e36a79c2c0ec1607ac9e6
-yuvj420p 32eec78ba51857b16ce9b813a49b7189
-yuvj422p 0dfa0ed434f73be51428758c69e082cb
-yuvj440p 657501a28004e27a592757a7509f5189
-yuvj444p 98d3d054f2ec09a75eeed5d328dc75b7
-yuyv422 f2569f2b5069a0ee0cecae33de0455e3
-yvyu422 17aef3e345d23edd3c660a91dcfc5a19
+0bgr 7211d3bdeafda12a27b6c586f56369e8
+0rgb dc534ffbcf7b02007a245e6af5bc0bf7
+abgr 0d93666da1532ca69c1a3e2ee0248430
+argb 86f5041b9245930bc6977d4f2babf74d
+bgr0 914c5750b13f79908c23d2621bc5d171
+bgr24 fd0c957cabb399b3dda29e1190e6cfac
+bgr444be 96d828ff1ea24858100e0afcef6f6201
+bgr444le 5a43d10a7890378368073be08141f967
+bgr48be 65986a0555423c910db4820732565a5e
+bgr48le 3050e56ee66fa61d8dd88b12f4b2f956
+bgr4_byte 6d8ea0cb6b4cadace60222063a847630
+bgr555be 90ffbd6a7850f25253977aecf84e229e
+bgr555le 9f800958e9c238c9441fef9799ab2a8d
+bgr565be 0e7c46857a3bebc2e3bb77ae68cc0bad
+bgr565le 31c0b9b6bc009a4bfa4421c3bbb2ff39
+bgr8 775803c35cf19b2fc84f537ce5a7e262
+bgra 020a3623e3ad6ea398d6adfcba9e510c
+bgra64be ce8e864307b8f11d1bc4a92f3384416b
+bgra64le fa2e6435c1f7f498d5714898e120dd89
+gbrap dcf43e62881e69a873382c12d3afe0a4
+gbrp 78a26e285e0f6ee73f37d70621e659fe
+gbrp10be d325f4f209bf460f8ff7d37bc51978dd
+gbrp10le c2328ae0384eeb34b1ac83726b385f46
+gbrp12be 8aa22995644b2796ecafc10dec5f3bd8
+gbrp12le df4badcfdf6701e03809ef5a278297b8
+gbrp14be a02a13caee9af458c5039c697ab896a6
+gbrp14le 4f521b6e69078bd0eca8dfcfde0f6ef6
+gbrp9be 397280799d9e78f48670664491e62524
+gbrp9le dbf020fa8423e170f2624ddba9f2c945
+gray 19ae78946e6acc3b552daa61b44a8ca1
+gray16be 2665aebcabc71b30a2252308b1335a81
+gray16le f35d7d9b8cac96c5ac25c2cd4b42443b
+monob d2b84b01179f38ce59a7050064d42289
+monow 550a446b7900a42990d76befca7f08a0
+nv12 18aaac3efcb2e389bfa2ade34b917634
+nv21 cb3b54dcc21c72943d496e6368b0c00b
+pal8 5ad4084b953f16007faf99f366b2ecae
+rgb0 1cb89a77512524197ae6495dc7206a7b
+rgb24 273cfae99e5951d567f230beec3e3eeb
+rgb444be d90556c864a78c45ca9e2c27130067cd
+rgb444le fe271368f267be87eb8f5b46335ba6dc
+rgb48be 434c2ce989de629050e53e820b6929b6
+rgb48le e04c4a36ea9f9c5624ebd56463b593fe
+rgb4_byte 77c49fda8c97ffc25678d8a51f7056ca
+rgb555be cb820a51149ba9944480bad7e1260abc
+rgb555le dc18e2fec8f39ebfd5b479fa6c5fe717
+rgb565be 0a7a10645295397cd6cbd6eadce71c8e
+rgb565le 7454e27a0e2c2c37c67e5361a82dd445
+rgb8 7b602ac8a68dd95ad639f741be805a0d
+rgba 283a6115965814470d50f11bf197c5fe
+rgba64be a00ce626e8c94dcc2ebd7b95d7a7d43b
+rgba64le 50932da874a5063a595a9428edb187fe
+uyvy422 2d479ff414d1c94bf506e48c86f66a02
+xyz12be ff515a5c7277e411c0bf3c8f26d02de8
+xyz12le 63f383905675fd3306a329eb89d6d0f8
+yuv410p 242e22aa812c1db8bff7f8132fb1f6da
+yuv411p 9305f8baa6ab955566fbee34391734b3
+yuv420p 005e6ddc8a5daf11cf866a1ec76c2572
+yuv420p10be ac1b6e1050f39464703e78a2ffc1913a
+yuv420p10le 5c158075ae335e6bbf4cd3be29bbb62a
+yuv420p12be 6a53755f72b37b2a264387dd5604b431
+yuv420p12le 174eb0b1aa668d517c13d6e397577cf9
+yuv420p14be ea8399e9ef8b6aa033ad2f5d6dca0473
+yuv420p14le a63fb4dfb6a7db44a5fd7f35d39d9032
+yuv420p16be fa7a59892b9d15f6e41c24e5f348f303
+yuv420p16le 5b75c822b20189bb0859b05bcf241aec
+yuv420p9be d5dabd911d09c9e8fa01fe284dcfd4d6
+yuv420p9le eb1f57241a76ae5d65228adb3aede871
+yuv422p 5afc9b0f6c5cef4a7d0543c03d0fc8a4
+yuv422p10be b83a73824cf37922faa84227ca151b83
+yuv422p10le 64e51f718442560814e74dd1e01d6c94
+yuv422p12be 460ce0ef46387d0ee667664e72dfe6d0
+yuv422p12le 687856619666bc8f8bc6a8e91f7c4e95
+yuv422p14be 461184df05416126fec7c5d2fbad3876
+yuv422p14le e180b189ef2f8448c681d02b478e56cd
+yuv422p16be 332fba636d33aea23514392d80602a96
+yuv422p16le 5d8e26fbbc8f25576065106c8820d56a
+yuv422p9be e3b364350da35d2ffd431665ed9d3592
+yuv422p9le 0f21976b77781cada504f690d7dc6c15
+yuv440p e6754959dfd9631f2dc1682fa71aa4e0
+yuv444p db3ad634aea336663a2f5c2475b95410
+yuv444p10be e341efd871b34308831113f4b2ff29f9
+yuv444p10le f9666d63623e0d7dceda1a17202579cf
+yuv444p12be 151c0e12d45ddf475a293cf9eee4c224
+yuv444p12le e0da5848e54c3ba0dbfa0414ff4a47f3
+yuv444p14be 83d2420dc82158274425c6ea5e396dbf
+yuv444p14le 155753892ad8a8957df50033fd21fecb
+yuv444p16be 6bb40952bd87aaaf2938cfadd1017a79
+yuv444p16le 9be8c3ca67cb8a778d39c087f008d8c0
+yuv444p9be 5a54227a9e1e12fd297e36e1e9361c52
+yuv444p9le faeeb7f3ff5efc51975d48d49f4ced5d
+yuva420p 7b609ede889454d2b89b184c290e9e32
+yuva420p10be 4a0ab3165ccc5cde5f4ef9c27e8ccf82
+yuva420p10le 8fbcc6200060e0710e5a824b86c9c219
+yuva420p16be d149e664c8fce03192d78279472ae2c3
+yuva420p16le 11b9f6b757f98fd4a442983bca8945b1
+yuva420p9be 0aae288a080fb0acfac23610b2d30111
+yuva420p9le fb67be28488cb722d4aea6fe3fdaaa16
+yuva422p 88c582f7c6d7c123198fb707aad2d5b0
+yuva422p10be 465ec369d7e47a71976821fdc31c289c
+yuva422p10le 07df8a8fcb3081e89d84359b178d5260
+yuva422p16be 0144a6783d7728a0e66d2b6d1134ecec
+yuva422p16le 5b49f7e660c77bafcb03869ea2e1ce02
+yuva422p9be 923a2d718c2dcf62c4c9b573a56f15ad
+yuva422p9le 9188e6cef21e89d034d37da1b1702a7d
+yuva444p f89cdb4fea764921004e149358d7028a
+yuva444p10be 87b0f4d461c40bde0cc85b109103d016
+yuva444p10le 5aed7ca68d5645a3a9acbe14b8eca54f
+yuva444p16be 5701a24fa4153d45be9533d7ec00b660
+yuva444p16le c3092fc38248cf96e30dce70208ed360
+yuva444p9be 8ab557ee81eae76cd176d998078d671d
+yuva444p9le b599165331bd7fa6b05dbf7b80044856
+yuvj411p ffb1370ebb9e1bb3b7dd4a532fe8eaeb
+yuvj420p aaddf557fa39c3b9521bc6afabbc18e6
+yuvj422p 4f46f78ace9176a534aea861ac316441
+yuvj440p d8083286cf699e81113fc8ea04ba3c35
+yuvj444p cad8f07876e62d33caf6c420d0f67a56
+yuyv422 ad9bf7f09f4f8263131649407a778e7b
+yvyu422 59f91e478f573d8a305e11da12a87be3
diff --git a/tests/ref/fate/filter-pixfmts-pad b/tests/ref/fate/filter-pixfmts-pad
index 03db5a7..98ac29c 100644
--- a/tests/ref/fate/filter-pixfmts-pad
+++ b/tests/ref/fate/filter-pixfmts-pad
@@ -1,17 +1,27 @@
-abgr e8e5e350c856c051d502cd435a2aa0bd
-argb a98e0a1213824ee4566d4891468bb614
-bgr24 ac7417cea8d6e799a31a3c9a39b8f202
-bgra 6113a09a023cb2b08e9cad78eb1eb37a
-rgb24 65eed443acc66c4f02bab6df4ebed515
-rgba 74d4158ad0c626e9a7c6923b9ca73294
-yuv410p a5210eb6a9b10c3269899b935df9a2d6
-yuv411p a23380c9698e2d80c9fa8a8b6d4f6854
-yuv420p f8733600369adaea28aa445dbdf2ed4c
-yuv422p 3e0d822c11c716e7636387b1bf27c5ff
-yuv440p 225dd7fbc8cceb24c26b765187d43a9e
-yuv444p 45484f0411d336ce94636da0395f4692
-yuva420p 919722724765dc3a716c38fa53b20580
-yuvj420p 4f20e2799966c21a9d9e0788b0956925
-yuvj422p e4d84b0683f77a76f1c17d976eff127c
-yuvj440p 33511c43339aa32533ab832861c150c3
-yuvj444p 82f0badd9d0c062bbfa0d9d73d7240a3
+0bgr 22bc089fc08499837ea10d21a529dd00
+0rgb 1c50d2473acac4b679b2e3fa8e8e7690
+abgr 6220c7c4bbf648671bf626f5f9150ec5
+argb 56b15eb7545a145b2a24046fd0ed4026
+bgr0 3be8817aa08b9da594cd13e568512131
+bgr24 e5de0be1dac9dd4b460734aa4f375e58
+bgra 1053d254d9a0771f73873d87562d39d8
+gbrap a064334f3ca45fcff9e1a8830ddae250
+gbrp 8ed451b460562df4af1264d29b237dbe
+gray 830e079c84012915564c4058db1f9324
+rgb0 d98f4dcad3fd8d1ef60a17aa2bbdbe2f
+rgb24 2b2f83ba2729eaba0644086591545997
+rgba 8526a8dee19622d7326cb67049e766f3
+yuv410p 0d76230039ba638acca0316ea1f409b8
+yuv411p 30a738023914476182fee34a00f0f6e5
+yuv420p dd819efe6a446392172856c363df4cd5
+yuv422p 93cade68bf90cb752895a05ef9dd5ffc
+yuv440p bc947633890872500ea44b29ea5f65e5
+yuv444p 1e9d6e3d58784d515de973cd7d787ec4
+yuva420p e2b891af8868283c7c20b7dd1aa9ffee
+yuva422p aba3ab7266a9c9a8fc765674d763ecc7
+yuva444p 552862b03e94f00d742655d0f9945ada
+yuvj411p 30b23cf51aba5af35b1215b72fa79dec
+yuvj420p 425fd8861231be032bbb624340d426c9
+yuvj422p e57b3ea1e368b3c2655db36a33a5507a
+yuvj440p 925b099022d40904533660adcb369f18
+yuvj444p 8ba8860166b0c8150bdd9c6646b957a4
diff --git a/tests/ref/fate/filter-pixfmts-pullup b/tests/ref/fate/filter-pixfmts-pullup
new file mode 100644
index 0000000..c406d1c
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-pullup
@@ -0,0 +1,12 @@
+gray d39e18e32032ff22653df6b166e63d28
+yuv410p 7bf504443a542a45b104c80e84ba71fc
+yuv411p 984dc2dd858c112890ec392d67955edc
+yuv420p db8bdc0191dd669419fcb28a26bf9acb
+yuv422p b255751a646eb12087b1766de0650b52
+yuv440p 421228103ae192db87c05677c8a5c58f
+yuv444p b94e5c0a63aedac7efcc8bc5e7800fe7
+yuvj411p 36bf69556c95ec4ff2e6b3d524b7d34b
+yuvj420p 2dc343b7d5353b2f769aa41b59885abf
+yuvj422p c5bdb2ea53ae3db4c6859d514f6a473c
+yuvj440p 9babeadd76a194e37d082ebe7ed11553
+yuvj444p d0170299a3cbc649956e9f31d0898cec
diff --git a/tests/ref/fate/filter-pixfmts-rotate b/tests/ref/fate/filter-pixfmts-rotate
new file mode 100644
index 0000000..d67bbbf
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-rotate
@@ -0,0 +1,20 @@
+0bgr 7951d539e3ad4a08fed97124e0210f43
+0rgb e8f60a93eacd8238100518df19b740b5
+abgr ae2f3005122aad5563cf7ff12783e3eb
+argb b7ae033b85032661be80d8ba01200eec
+bgr0 70c6098cbf680a08ff3b29cfab58ffc5
+bgr24 83fc4e817b1fa89944e245f43367802d
+bgra bc1461220ce53ae40930332a20e8a8f4
+gbrap db83fee7e30c89e280ce0c7ddafdc649
+gbrp d485c1b9d18b56085a17294c633b32a1
+gray dcef928e5befed02d28107afecd9e904
+rgb0 bf15cfb2c478c50e7a6875db550aedcd
+rgb24 77d5f147a56fc9b17a53c7d0abfbe210
+rgba 43b3acb79b05a83964f8fc4542ff3520
+yuv410p 0a5d25ea1feb6a169f1af87089e75dcb
+yuv420p 39c2f18ae4a1313b680d281ba7de0b9e
+yuv444p 7d6fb967e0da2730c2d6dce701802add
+yuva420p 2c2d9b20293a8eba4a98434528e9c10b
+yuva444p d4de3db71ebeb0d3266c17391e6f99b3
+yuvj420p cac522bf5672812deaf6716e75388ff6
+yuvj444p ee0bff6744f737012a01343d9df12180
diff --git a/tests/ref/fate/filter-pixfmts-scale b/tests/ref/fate/filter-pixfmts-scale
index dcd73bd..b691b98 100644
--- a/tests/ref/fate/filter-pixfmts-scale
+++ b/tests/ref/fate/filter-pixfmts-scale
@@ -1,90 +1,119 @@
-abgr d894cb97f6c80eb21bdbe8a4eea62d86
-argb 54346f2b2eef10919e0f247241df3b24
-bgr24 570f8d6b51a838aed022ef67535f6bdc
-bgr444be 25fe04f73a3bad4140d1c4f96ca5b670
-bgr444le 2fde227e6cea6dca5decdd0b7c0866f7
-bgr48be 390d3058a12a99c2b153ed7922508bea
-bgr48le 39fe06feb4ec1d9730dccc04a0cfac4c
-bgr4_byte ee1d35a7baf8e9016891929a2f565c0b
-bgr555be de8901c1358834fddea060fcb3a67beb
-bgr555le 36b745067197f9ca8c1731cac51329c9
-bgr565be 922a2503767036ae9536f4f7823c04ee
-bgr565le 3a514a298c6161a071ddf9963c06509d
-bgr8 7f007fa6c153a16e808a9c51605a4016
-bgra a5e7040f9a80cccd65e5acf2ca09ace5
-gbrp 205c50f8359cb4ba2827a7711dea2cc6
-gbrp10be 30b7f9d5ef5da474fb794743146236aa
-gbrp10le 2e9949a01fe4c38774728e34795165cc
-gbrp9be 6bac01a7f64a381521b2149fc46f4178
-gbrp9le 4b6cba7acf7886c13db122e590ec6b1f
-gray d7786a7d9d99ac74230cc045cab5632c
-gray16be b554d6c1cc8da23967445be4dd3e4a86
-gray16le 715a33aa1c19cb26b14f5cc000e7a3d1
-monob 88c4c050758e64d120f50c7eff694381
-monow d31772ebaa877fc2a78565937f7f9673
-nv12 4676d59db43d657dc12841f6bc3ab452
-nv21 69c699510ff1fb777b118ebee1002f14
-rgb24 514692e28e8ff6860e415ce4fcf6eb8c
-rgb444be 12254053ae93373869fca18b2afcba31
-rgb444le badbd68b59c87df6ae73248309637634
-rgb48be 8fac63787a711886030f8e056872b488
-rgb48le ab92f2763a2eb264c3870cc758f97149
-rgb4_byte d81ffd3add95842a618eec81024f0b5c
-rgb555be 4607309f9f217d51cbb53d13b84b4537
-rgb555le a350ef1dc2c9688ed49e7ba018843795
-rgb565be 678ce231c4ea13629c1353b1df4ffbef
-rgb565le 6f4bb711238baa762d73305213f8d035
-rgb8 091d0170b354ef0e97312b95feb5483f
-rgba a3d362f222098a00e63867f612018659
-uyvy422 314bd486277111a95d9369b944fa0400
-yuv410p 7df8f6d69b56a8dcb6c7ee908e5018b5
-yuv411p 1143e7c5cc28fe0922b051b17733bc4c
-yuv420p fdad2d8df8985e3d17e73c71f713cb14
-yuv420p10be 27f28a6e09b1c04d0f755035a5db1f43
-yuv420p10le a5a1692e026590ba2eddb46b9b827529
-yuv420p16be d7270efce54eb59c7b01c14157a1b890
-yuv420p16le e85abf00bad940a922b623c91c9026d7
-yuv420p9be bb87fddca65d1742412c8d2b1caf96c6
-yuv420p9le 828eec50014a41258a5423c1fe56ac97
-yuv422p 918e37701ee7377d16a8a6c119c56a40
-yuv422p10be 315654908d50718e175aae018c484732
-yuv422p10le 91bbc78a9a56f659b55abc17722dcc09
-yuv422p16be e7e34fe9264784763ab6cb406524c0f3
-yuv422p16le c435b76b08204dda6908640fb5fd4621
-yuv422p9be 82494823944912f73cebc58ad2979bbd
-yuv422p9le fc69c8a21f473916a4b4225636b97e06
-yuv440p 461503fdb9b90451020aa3b25ddf041c
-yuv444p 81b2eba962d12e8d64f003ac56f6faf2
-yuv444p10be fb304d77c6d2e18df5938662a22176f0
-yuv444p10le b17136913eb066dca6be6af645b9f7e8
-yuv444p16be 0da9bed80f5542682ab286f3261cf24c
-yuv444p16le a0c5d3c7bf3f181db503cf8e450d1335
-yuv444p9be 9ac2643ce7f7e5c4e17c8c9fd8494d4a
-yuv444p9le 896a1cc9cccca1ba410dd53942d33cc4
-yuva420p 8673a9131fb47de69788863f93a50eb7
-yuva420p10be d92a95061809f251175f5d5e3074930e
-yuva420p10le bad90ba2d4c260e379a7aa6dc7760853
-yuva420p16be a61d8ddb646e2d26020fc7ed2a48c1a9
-yuva420p16le 90ef774f86ad3177ec57eca8744b4e09
-yuva420p9be f7655546446bfdc875243d7cdeb13b30
-yuva420p9le ada2b719827059d70ebc57e2a3f9da92
-yuva422p 3c76ebeca0a7d3aa5f8e31ef80a86ffe
-yuva422p10be 01dd539e4a62762a3c97e965c76bb6f7
-yuva422p10le 76355d9d8fdcd085a24d48832b72e40b
-yuva422p16be c21afa31ac18bd92e8e596b81552b52b
-yuva422p16le 0bc3720dba6076dcce3b74b1d3c6c4b7
-yuva422p9be a60ac5b8026e9621724c033fbf79dbda
-yuva422p9le c3eda8831e9b9c94a3eb487d33114103
-yuva444p 3268c6abe5e3cdbd16552a1eddced816
-yuva444p10be 856b37c1ee53459f46b9359d329ac9b5
-yuva444p10le 22790592361c007406d4ca9a9e0954a5
-yuva444p16be ed5b07fe4d5b1137604568786777af1d
-yuva444p16le 3a3df23feb60d8832b566fd9765983d0
-yuva444p9be 4fc479c5b1044ad37b4e6fc6488b4f7f
-yuva444p9le c41849b0134670d6f6253c337defbb04
-yuvj420p 30427bd6caf5bda93a173dbebe759e09
-yuvj422p fc8288f64fd149573f73cf8da05d8e6d
-yuvj440p 508ac7a9ddeb6d1794a1100ba7a1664c
-yuvj444p 73aebe144085b22d1189caf6ca07e18c
-yuyv422 169e19ac91b257bd84ace0fdf56559ad
-yvyu422 d0d3dbd1ae665ff0cf8b0a5d64878622
+0bgr bfd7734cc0e7183828cbc27a87a74fd1
+0rgb b4048f9039c7d19d4cf629512eab6e49
+abgr 0e21453cd0f400abc65f5c8c5f9a2407
+argb f5f38bf456c4540ddcd6143920b152d7
+bgr0 0d259e56d57f3c345a5a33d2288ddc25
+bgr24 b588ba9ac44e37192d15011289ed9e66
+bgr444be 36ad62c82d433d8a6e67527329cafc8e
+bgr444le 267fc56e6ee33cc02b1a19b77a77ec74
+bgr48be 6628a75fc4e34a7dd49f27f91afb0851
+bgr48le 6c75a39868247db041e26147d2e7b53c
+bgr4_byte 7fa21e4a5a8c675d013a1e3dc51243ec
+bgr555be f2fd3215c29a54eebf522ebf12b4da4b
+bgr555le c113e39b478334bf4327abfb75fdbd2d
+bgr565be a4aae2855bb89d43174377ff93da3075
+bgr565le 59e98d1560e7368fe2b5b83ebdf44f72
+bgr8 a5e7429398bcb06e65886108236e8be0
+bgra 2cc6f245d3f97c14d8348c26eb864968
+bgra64be 71bcd0f8c5e00a78a5fea6d933a9cdfd
+bgra64le 477b5ceda81e963b77af1c347b43a6e8
+gbrap 81d1062009b10394fa2375212d6fa4db
+gbrp eda47ef0d0df311e7a7469c7f844c8d3
+gbrp10be a37c7e545f725e0662ba85fddbc854c5
+gbrp10le 4116fd82b3a7e2f6d7c98de6bb9b712f
+gbrp12be 9e41ce94896ac589ba4080356cb0a64a
+gbrp12le 4efabb781c595c5511c4c64aab121727
+gbrp14be 4340d7cf3beeafded76f4ddfe31072a0
+gbrp14le aaaaee74d2f397ce5cd2d32833926f7c
+gbrp9be 7b888a93129d17969b5d7f84d69d8697
+gbrp9le f777b972045bdb016a528468e88e6f28
+gray 056173fc49e4f006a833812d9e32d70f
+gray16be e45056dddc12d35477133243494cc8ed
+gray16le 292c098ac003086d66a3f22fe0bc6fda
+monob 24f12215824e19b3040b5019b2d7df8d
+monow 72dda82d40e73d494ba14313b2c6287a
+nv12 a44b33111b0d1280abc870151f65388c
+nv21 b9c69651861e44a837713f0d5be426da
+pal8 58a550701a23eddc83d2a73346c12a72
+rgb0 5e1c18e999682ae5a4389b4e37384138
+rgb24 e4d86fc5656b70ff4935fe2a90cc08cb
+rgb444be 006a4118a03c2b71db3921de2ba96893
+rgb444le 455102c8041447df22b5b262ac8d41e5
+rgb48be 18b205f29cec6e90a7e957bff8c6f458
+rgb48le 6801bf7aedb9ec5b8d6e90ac59cc02c1
+rgb4_byte 7ce98c9c289e718169173019a7daa902
+rgb555be 23a2240967bbae4f7073762614288afc
+rgb555le 2d16b7cf6948ec88d2d290344b8e7020
+rgb565be 0a2e18eaf3eeb041ad19ca0a0a4983aa
+rgb565le 55a54972f5f4e1045b980ecb05765768
+rgb8 15452aa88fafe2e99761f9ef47f498ef
+rgba 0914498509b7d34a1f2a788e1f6e5b3c
+rgba64be d82f2688636e49920e5a03425aaa8ef3
+rgba64le 63841e2644b9cf4ca1ad2f3b7facb83b
+uyvy422 c8fc0f5e8931a2c798b69a02ec715a26
+xyz12be 25f6ba007126c7348050446af457ffdb
+xyz12le 6a7a9d76fc51d6c8e433d77421f89157
+yuv410p d189beeef028bfed7a0a376a6d3dda40
+yuv411p f00f59254b3d461804db2d701a2a030b
+yuv420p 470647070fc66cda538ac268ec242bcb
+yuv420p10be df8f8abee664033b8d1f180996460291
+yuv420p10le 92cb7f81920cbc2a2d6cdbb4bcf3511d
+yuv420p12be af2dc0234ca535cf86cbf8ce69589638
+yuv420p12le 6777b6a682ba411c8477463966fb983e
+yuv420p14be 3e243028bb2fad0c9297ef1c2bd92734
+yuv420p14le f520370cd5b78d9cd7a06c56cb94d172
+yuv420p16be b99f75e99404c7885d4ccc18fbfce4a6
+yuv420p16le 66c47ba1b3dce2b39ec78d48d9eae792
+yuv420p9be 901c2489ac1ee42d4f59a2272fdb9b0b
+yuv420p9le 3191db22046c5dc83cdf163ffa554688
+yuv422p 06acfd062b924ddbf596d693b1d3e162
+yuv422p10be 70f5d4293068457e721fa7f08ec825cc
+yuv422p10le 75dc1a6818161c7cf12ef5c3e4136ebe
+yuv422p12be a1d5c0b193fbe6afbd4f4df3791c73ff
+yuv422p12le e1ec329c42de5a0ec64f1f02f38507e4
+yuv422p14be 2ee37076fddae430fd4b1b60abb28c27
+yuv422p14le 9ce7e04b030801746083b7c14fcc907c
+yuv422p16be 3bf45caed6ce686b43095dccfff5f198
+yuv422p16le 7200f2405f7b979bc29f5446653d1fbe
+yuv422p9be 4c44d041f51b499fe419c51be0831c12
+yuv422p9le b48e78a8a6a3f88269b4f5f810b75603
+yuv440p a9dd3fab4320c3c9b0eb01d2bf75acb9
+yuv444p 77387910c01eacca94793a9be37c1aa1
+yuv444p10be b4e8cef69cb2ad2c24e795325a1d883c
+yuv444p10le 83855dd296a1859c085193c1edbb35e2
+yuv444p12be 9c2bdcb8cf18fadb4123e7e95a4a688e
+yuv444p12le 7ebc00148fa0697a62a57954397f80db
+yuv444p14be 964671f6fb832031719109404dc24334
+yuv444p14le 938e67a1e1d1d9c24b0b2e31ac8af277
+yuv444p16be f5d62af6faff3ccf7050984449e050fa
+yuv444p16le 6a164dc492c5fd3a432bb35bea6e758a
+yuv444p9be 33b3de3ce657818af720ca4c68ec1dbf
+yuv444p9le 48d58e5f12cc52ac1056819496280cf5
+yuva420p 2d257eab9850cb69ddf0d8038c0c63d7
+yuva420p10be 4728f2b6d43136926602bc0135c2d68c
+yuva420p10le 47a7f657d8c011086b19f768a7466811
+yuva420p16be f52db29abe686228ca68283eaf4570d5
+yuva420p16le f04b89a3811e5b0c40963a2428f21890
+yuva420p9be 587f574431d740f7da5a2b2361478e67
+yuva420p9le e1f7165579b963f9f0b4b724f00af4ef
+yuva422p dd7818dd6a875ec3d0e38f87a0900850
+yuva422p10be 8a0b5a8e1ac23b3806cd677b4ef5c7ad
+yuva422p10le 15c8c0573dc98d2e570d5a395298245a
+yuva422p16be 5469c6ea7ff27ee727909724216b10ac
+yuva422p16le 11cca9765696bc43617baa0c5fedd28f
+yuva422p9be 535ff206a1bfc4dee17d846dba21a6a4
+yuva422p9le 08e3e8819decb2eba909cfb2ac2ebec2
+yuva444p 9bf08cf5f2f711145a78503a68563f41
+yuva444p10be db3d5d341b61bad86f60aaf07e7b2f47
+yuva444p10le d8b4aa64fbb4c6ea51d2d96e8be38884
+yuva444p16be ebfc666db6de2d932e232b4e09fd1c1a
+yuva444p16le 0ae0b32da3d398c5ee800727e9b4bdaf
+yuva444p9be 7a1fa645240d60ff933bdc2c856ae80a
+yuva444p9le af34e0e6168c12cba3e63194c6a8e0b4
+yuvj411p bd702b35d0db2b316d5c9a54ba2fa866
+yuvj420p d5e8943616d2dc0ddf9f64ccf0ec088e
+yuvj422p 78314d864e3edd4162db5eabb347503b
+yuvj440p 4b6168487de8434d45ecec0c2e9c2278
+yuvj444p 3a8958f4cc6352b6486b25f05db3a982
+yuyv422 8c926b0916e4ae27df8f0d0450712f72
+yvyu422 b4edcd5179382a595efe8286e6dad579
diff --git a/tests/ref/fate/filter-pixfmts-super2xsai b/tests/ref/fate/filter-pixfmts-super2xsai
new file mode 100644
index 0000000..a3d7fed
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-super2xsai
@@ -0,0 +1,14 @@
+abgr 2ef66d92ea295954daec5e60f3c624ed
+argb 247bb72c65d9cfb5779b8741dbc332b9
+bgr24 f40a64ec89f99d3ee0fe73437ccd800a
+bgr555be e068bb0bc5e18d6072d8acbac1d310c0
+bgr555le bb18c256e2257bedd5e5dca8a121e834
+bgr565be a1eb921b9b4eacd31b616c3e04fccb7a
+bgr565le 22a9884160a681efb67d5535a5beb423
+bgra 3a2be01be675daca7cf14e5b3f0e4728
+rgb24 b82659f61dbc5d097c32a2916ba7df8e
+rgb555be c05c613110ee7fc595fb2f13a27baa7e
+rgb555le 781f83ee441babd51e545e313737b9b2
+rgb565be 4c01aaa3a3622a558b38116f1c5bb31f
+rgb565le d40bdd5c32032f9a219e77180795fb8c
+rgba f90c2f745598be6d9a6e82cbf264a4ad
diff --git a/tests/ref/fate/filter-pixfmts-swapuv b/tests/ref/fate/filter-pixfmts-swapuv
new file mode 100644
index 0000000..a37384e
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-swapuv
@@ -0,0 +1,62 @@
+yuv410p 029701cd3d50df12570653d3b77bf9c8
+yuv411p d5e669b8a135a410296550159eab2bd9
+yuv420p 3c1682586b331a417c62e2632976c6a5
+yuv420p10be 474a2392e5deda2782a6d14f66e28322
+yuv420p10le d6bf2a10e76799c53e342dc95eb2b2fa
+yuv420p12be ccc4d59eb775a435210d5144cf213bbb
+yuv420p12le 1d46c041c178f7c3ba721c9f0300e5c7
+yuv420p14be d6d90762c9bf75b93a8d0f01bf88e67c
+yuv420p14le d382dcc2a618dac825bd42e876e10ef2
+yuv420p16be 837daa01ca24e468ada8f424dcba0baf
+yuv420p16le 83ebf761e5ba7c459daf2b3a8044a1d1
+yuv420p9be 009f38d02a5ed45a73eab6ee50cf7ddd
+yuv420p9le f4247ce765b00e604198fdda072151f6
+yuv422p 9001a9e63f6f13b8d7e62fd3c7cc76be
+yuv422p10be 40c4629543181e284db0c27f79608b5b
+yuv422p10le 4e8b6b36ce914fa566f9baea1e191698
+yuv422p12be 1ec959d0dc26928c6fb93925353a7c81
+yuv422p12le 3ef47dc70087949daf4355b62c1adecd
+yuv422p14be 5462e9b00c0782893967c3ed2da317a6
+yuv422p14le 8cef92b54ca51982386becad2f2edc0e
+yuv422p16be a9021704027340b1f21e62348568657e
+yuv422p16le fb8e5aff474eca0b9b4bba0ab5765158
+yuv422p9be 2d27809e85655e5ce9db5f194d617069
+yuv422p9le 13f42a98d4c6c57883d6817329ec3ea7
+yuv440p 44c7ad06592e46b42143756210798d7d
+yuv444p 49587b263a4c8da66ddc267f746b7041
+yuv444p10be 6589db276e865800614153e43bad3da8
+yuv444p10le 8e17f00cbc47188e007b59e568bf13aa
+yuv444p12be a1b9df9b367da1abaf20058e0946f70d
+yuv444p12le 5b0fee31978851ee4b15adda9d09f59d
+yuv444p14be eea4f1fd5d04b16b323b2797b6fc5496
+yuv444p14le 824f6014212cd804d7495cdac8accaa2
+yuv444p16be 2c3a255d9260d93b56c3df1a7793b05f
+yuv444p16le 51a7e2cbf1c331317fb0768902d8eed2
+yuv444p9be 873e54e3b96b5de22eb55a7e0de8d16e
+yuv444p9le 2e0347745b5352669c743df386cf7e8e
+yuva420p 382e6ba313b1e5ec8140ba85b67739d9
+yuva420p10be 7fd81a2920475845956f906079bb858c
+yuva420p10le 0a443a68ae124617ad8b429285f55707
+yuva420p16be 4bc4032b56eb8c671d3896d743cf9230
+yuva420p16le 8789993f7975cb397b4135c68d2eac47
+yuva420p9be 511a9f068d44504aeafdd024425e27e1
+yuva420p9le 71aedf72c65d0e7d8adf23d4cec0be9a
+yuva422p 812466f48c19e6c75eae9f77c7d37146
+yuva422p10be c303a9890caa41a28809a81b96ee9be0
+yuva422p10le 889b8ffc52c49a71452d217cd426e82d
+yuva422p16be fabad5519e983469396bf39cbdfdc8e3
+yuva422p16le 7a48c3b8e75b6a9e0817c9c5026795ea
+yuva422p9be ea95ab08a41a0f5028293d01b7633099
+yuva422p9le a374569c2cfb4cc29bf699d8a58fab03
+yuva444p 980451d431db7a978ed145b07877a4fb
+yuva444p10be b2eb903bfa5aaf4d7ef1a760f5bda4a9
+yuva444p10le 7f08e6e6f9be8bbb685ec073a1c26c0b
+yuva444p16be 25853e6375b3b284596db23489e03fac
+yuva444p16le 771c8bda1d8d52d4c26e88513b7aa85a
+yuva444p9be bb61d7a428671b51f1a3ca2789cc09af
+yuva444p9le 901b1d1fd58173437690e371ba5a78e4
+yuvj411p 08f897f81c4532e39415d6b1a473cbb2
+yuvj420p 0abdb9835e118c368a12c7c1b0d9b3e2
+yuvj422p b3e33fd45ddeab175e9719ca10586113
+yuvj440p 128a7ab2aba6f84809a3f36ea671b4dd
+yuvj444p 02092a8f68e0e202bb94869d828e32fc
diff --git a/tests/ref/fate/filter-pixfmts-tinterlace_merge b/tests/ref/fate/filter-pixfmts-tinterlace_merge
new file mode 100644
index 0000000..4f1f75e
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-tinterlace_merge
@@ -0,0 +1,14 @@
+gray 5bfdd4a77ce5bef266f2e0ce9f4f971b
+yuv410p 2327b4c01e6a16acf18229f3faa4f29f
+yuv411p 486a0448fd543b54eefd599eee613ba4
+yuv420p 36c640c73bdbc62d047a923d2abbc559
+yuv422p 2434b401a62eb3799e441d8b1c2e18f2
+yuv440p 6951eb4455ea2979f65ece3b1132eb5c
+yuv444p d36e193a9bfc1b21ca16b563d3802d9c
+yuva420p 54139ae3544a9c2695ade817342bd1d6
+yuva422p 0ec7ea9e289365c357ba0a0926d684f3
+yuva444p bb9cfc136d4a5a2e8c25b5885ff51a38
+yuvj420p ead0073708f677df3ea594d326954415
+yuvj422p b76079bba6818dac80d71795403585d8
+yuvj440p e3d34f02bf946af9d7973701097b3391
+yuvj444p c1757fcbb3f04d78cf082afe6537a540
diff --git a/tests/ref/fate/filter-pixfmts-tinterlace_pad b/tests/ref/fate/filter-pixfmts-tinterlace_pad
new file mode 100644
index 0000000..da0eae6
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-tinterlace_pad
@@ -0,0 +1,14 @@
+gray 7f0b876b010cc2211e0ae44f88c8eb14
+yuv410p 7412fe273dc17de5cf23dc14465b0a99
+yuv411p d41ad065ed5c07a33da876c3ac16fc65
+yuv420p 2d3a4843548f89f2d8855a4f2de76827
+yuv422p 3c0ec17893996a99520a1226a7ea0105
+yuv440p e0474bb9e49906d44c7b2d62d23edc85
+yuv444p f7dc9731dd13fc2de16878444efc52d9
+yuva420p 6b3cd0f2231af767a83090a34f3996fc
+yuva422p 7369cf26a49b7711d92f418d10d0dbc4
+yuva444p 33c742fc331cd3bb0599a866a38595da
+yuvj420p 287eb3cc6982e43839098fcafe5347b8
+yuvj422p 1d442127a0bc27c8d4c1ed0173d58102
+yuvj440p 1c5dcc66f8bc75104fb7e00078ec85bc
+yuvj444p 833430eaf6cca94d98170eb289f4bd28
diff --git a/tests/ref/fate/filter-pixfmts-vflip b/tests/ref/fate/filter-pixfmts-vflip
index 073322d..847cc55 100644
--- a/tests/ref/fate/filter-pixfmts-vflip
+++ b/tests/ref/fate/filter-pixfmts-vflip
@@ -1,90 +1,119 @@
-abgr 25e72e9dbd01ab00727c976d577f7be5
-argb 19869bf1a5ac0b6af4d8bbe2c104533c
-bgr24 89108a4ba00201f79b75b9305c42352d
-bgr444be 9ef12c42fb791948ca4423c452dc6b9a
-bgr444le 3650ecfc163abd1596c0cd29d130c4b0
-bgr48be 2f23931844f57641f3737348182d118c
-bgr48le 4242a026012b6c135a6aa138a6d67031
-bgr4_byte 407fcf564ed764c38e1d748f700ab921
-bgr555be f739d2519f7e9d494359bf67a3821537
-bgr555le bd7b3ec4d684dfad075d89a606cb8b74
-bgr565be f19e9a4786395e1ddcd51399c98c9f6c
-bgr565le fdb617533e1e7ff512ea5b6b6233e738
-bgr8 c60f93fd152c6903391d1fe9decd3547
-bgra 7f9b799fb48544e49ce93e91d7f9fca8
-gbrp 25c1bce192daefab910d51a56b52199e
-gbrp10be 6fe980f9ca94cbcdb9e01f4e906fdf19
-gbrp10le f793a1d96d3524c6a17e53356c415c4e
-gbrp9be e10dc3a2566b065260a45356ef08c1cd
-gbrp9le f25105a33f18d6bcca3205c67ec106be
-gray 30d9014a9d43b5f37e7aa64be3a3ecfc
-gray16be 6b84b85d3326182fa1217e138249edc5
-gray16le 66bb8faa09dc149734aca3c768a6d4e1
-monob d0cf8732677a5360b6160133043590d8
-monow ff9869d067ecb94eb9d90c9750c31fea
-nv12 046f00f598ce14d9854a3534a5c99114
-nv21 01ea369dd2d0d3ed7451dc5c8d61497f
-rgb24 eaefabc168d0b14576bab45bc1e56e1e
-rgb444be 06722e03f8404e7d2226665ed2444a32
-rgb444le 185c9a5d9c2877484310d4196ef4cd6f
-rgb48be 62dd185862ed142283bd300eb6dbd216
-rgb48le dcb76353268bc5862194d131762220da
-rgb4_byte 8c6ff02df0b06dd2d574836c3741b2a2
-rgb555be 40dc33cfb5cf56aac1c5a290ac486c36
-rgb555le 4f8eaad29a17e0f8e9d8ab743e76b999
-rgb565be b57623ad9df74648339311a0edcebc7b
-rgb565le 73f247a3315dceaea3022ac7c197c5ef
-rgb8 13a8d89ef78d8127297d899005456ff0
-rgba 1fc6e920a42ec812aaa3b2aa02f37987
-uyvy422 ffbd36720c77398d9a0d03ce2625928f
-yuv410p 7bfb39d7afb49d6a6173e6b23ae321eb
-yuv411p 4a90048cc3a65fac150e53289700efe1
-yuv420p 2e6d6062e8cad37fb3ab2c433b55f382
-yuv420p10be fb0772f5e2b9da20ff826e64c3893137
-yuv420p10le e95879e14c4a6805f39643964baf41f7
-yuv420p16be 539076782902664a8acf381bf4f713e8
-yuv420p16le 0f609e588e5a258644ef85170d70e030
-yuv420p9be be40ec975fb2873891643cbbbddbc3b0
-yuv420p9le 7e606310d3f5ff12badf911e8f333471
-yuv422p d7f5cb44d9b0210d66d6a8762640ab34
-yuv422p10be 0be8378c3773e1c0b394315ef4994351
-yuv422p10le 6518094fe8de6bee95af21af1e5dc1e1
-yuv422p16be 9bd8f8c961822b586fa4cf992be54acc
-yuv422p16le 9c4a1239605c7952b736ac3130163f14
-yuv422p9be 7c6f1e140b3999ee7d923854e507752a
-yuv422p9le 51f10d79c07989060dd06e767e6d7d60
-yuv440p 876385e96165acf51271b20e5d85a416
-yuv444p 9c3c667d1613b72d15bc6d851c5eb8f7
-yuv444p10be ee069cc6db48975eb029d72f889a7fe6
-yuv444p10le 645b3335248113cafe3c29edb1d7f3be
-yuv444p16be de2dedfc6f12073ffead113f86e07ecf
-yuv444p16le 8e83323cf102d6c823a03ae8a7b7e033
-yuv444p9be 6ac92b7dc9ab2fc59bee99204886899a
-yuv444p9le 85aef13a654953d3455d89770b0d74bd
-yuva420p c705d1cf061d8c6580ac690b55f92276
-yuva420p10be baa5e3b0ff6d0ebbb0958560cd763c6e
-yuva420p10le a36dc59ad55b406e5fee475236e9753c
-yuva420p16be bf3b134eb70878df9afba61d03e930b8
-yuva420p16le 105d375154329a381aa58379a0a6ec46
-yuva420p9be 8273d591e055f48990c29dd905a6cdfd
-yuva420p9le 95ced0bb07e422d98db61a35cdb3fb8f
-yuva422p 6aed0ea657ed51cc047a4fbdd981aec8
-yuva422p10be d69a3404984c5fd30c0fc548532bcb6b
-yuva422p10le a40c8e6f50e12d94bf7484107ec98559
-yuva422p16be 39552c259ca242f2417e913ffc602fde
-yuva422p16le 16faa558a34291ca32f6d94dce211ee2
-yuva422p9be a951eafb62c092c63f7566b6803f60df
-yuva422p9le 00b39cfca78666e057ee527f5e174a04
-yuva444p da5d64f2b2bd2013c186456f595fad65
-yuva444p10be 00e74a9c0c7818a9bbd9fee95b961ee8
-yuva444p10le cbe30f44b63cf7ed27fc2dde40315b5e
-yuva444p16be 7e9b799b057e1446dabbf0f738480cfb
-yuva444p16le 556d58b91a617fe4a83af99a4aea1c2e
-yuva444p9be b5a31de4fac408eeecaf3aff11f40e55
-yuva444p9le 67467f1e1d9edbd59d3984ebbfe24be6
-yuvj420p 41fd02b204da0ab62452cd14b595e2e4
-yuvj422p 7f6ca9bc1812cde02036d7d29a7cce43
-yuvj440p 25711c3c0fd15ec19c59a10784fcfb96
-yuvj444p e45dee2ac02276dfab92e8ebfbe52e00
-yuyv422 e944ff7316cd03c42c091717ce74f602
-yvyu422 02c8cd287744c94b48da7cf111e3eea0
+0bgr d7f264cac771432a25fa943aff095c5a
+0rgb 00b65b68edef9ba563f0738453e342da
+abgr 97b62a09a7e19e2f1d8a056303ea9b20
+argb c84d9d20e9a88adb2eb1d5c1ff640f5c
+bgr0 258027340baeee1dfff2c7cda1a96e01
+bgr24 101889812392a4ed72fd4c49bbe49571
+bgr444be 9de20b03634f0f4755e17a4f5f4d5779
+bgr444le 1034410821ac7ce05f7c4825ae7c436a
+bgr48be 9aa28ad8f52b7b4cfd5bec421aac3597
+bgr48le ea833f8f7be21b907d733c1b6cce6f69
+bgr4_byte 18bd6511f1e9699888114b47899bede9
+bgr555be 62c978a01dc9c38d68db62e3e6d50a15
+bgr555le bd86a6180de15d421cad1f3748c0c432
+bgr565be 21f35c3720bac8be76557378af6b4982
+bgr565le 12d65b77a0d88f39fb8e2d410c96a52a
+bgr8 0fbbb8598ad9ec69944c7b8c0714eecc
+bgra 4e61f5f149d19c964c34fda94958b6ab
+bgra64be cbc87591652d5be459cc4afb75cb6ccb
+bgra64le 1111426757016491bd790e8fe341418b
+gbrap d69032f319b8c5c6427070f4f964fdbe
+gbrp 6a1825f47d5301c4756d61bc368f4260
+gbrp10be fe6c50f04325ac990b0e85be64135363
+gbrp10le 7ff6825b3df868263caae7035892dbe9
+gbrp12be 0d9612a71854b2777b2e8549f07bf9d2
+gbrp12le f00801ff735ef409fd9826bb65d56ce6
+gbrp14be 0db0c750faa92da731ed088ee8c046d1
+gbrp14le 8e7f0ac52b130228b43df3eec8ab2c1d
+gbrp9be 0cf496a35e029b6c4a547661f3ce6dc8
+gbrp9le d45b29752301b6ddbdcbcf896c7475d8
+gray 49e378255356b1b642cb76ba9c006e0e
+gray16be e0e2c9dde127ea410e7d930fd329ef6a
+gray16le 877c610baca60a8f64848a94e3b975a4
+monob 1b1830c7283af9696a576c59fb40836e
+monow 4ccd9f821466493d918e9834783cb13e
+nv12 97d95f7055cdee9f69cee1abe6c8241b
+nv21 c9d640860ea278486d0a0fc1c9e10d52
+pal8 b7c18ad02487ab7f8ce8bf14491ff450
+rgb0 acf4913303d81b03ddf7a3c9749922ee
+rgb24 a5c724922dc2d431e50a323cfd0246cc
+rgb444be 5236f07cbc576b8abd502994cf273493
+rgb444le 75b0f34a04a98857bb0b275d40fbba22
+rgb48be 93dda593c25905b7ddd5532580ffe4e9
+rgb48le e37363ee038eec9fe3c0f87f9bd52871
+rgb4_byte 0d16108350a75b0a530e40058676e269
+rgb555be 0fb532a86368f85a669c5d3d8e63ad38
+rgb555le b135d8d18d276a8c06def67c47ef72df
+rgb565be 3c6570ae71c4a43b28a8462eb33e428f
+rgb565le 95c7bd6ac8bacad78a2252ac79a15470
+rgb8 2bb00e664b00fbe94d4b589ddb9c74ab
+rgba 1484910f0ca35cc686e6ac1fc271c70a
+rgba64be ce4e73b7dc6f67693f06ac6baa1d28dc
+rgba64le 34f23188309117e0619a16c2535edc98
+uyvy422 8cc384aa6d5eeef990034363337b1639
+xyz12be ca70be1c52a0435b83f815c2d95b0c1b
+xyz12le 9a95c4551d3f99f5cf0a54231bc32d33
+yuv410p 4adc2e0d8637002378cd2fe96aaa74cf
+yuv411p 5af542946ce00b7e741bbdd3dfd957e4
+yuv420p d5b8595bc10291e6230185904d77ebf9
+yuv420p10be 09a4fa9d5f7b34058045e3707db49717
+yuv420p10le 507501aad32169107ab56dd28bf1d4ce
+yuv420p12be dd737564b938565450a717f87d4617f2
+yuv420p12le a8c63f8e6ccf9c216b7b707c41acddeb
+yuv420p14be c9f5a477855fd651fb2458b85f7d8abe
+yuv420p14le 8a559dd6ec6a27ee736bccdf2cc042ad
+yuv420p16be 5780b999dbcee5fdf8d7aaac46e30624
+yuv420p16le b34fa2d224560dc6dcc67f6ee73204a3
+yuv420p9be d97241dbe6747b17377734506090ccd6
+yuv420p9le ce70f75be8a3b8ac128062aa95abd65e
+yuv422p ec52f5e684eb3f2304dab75894ef742a
+yuv422p10be ee8d61f272aa8700213b504b0e34f16c
+yuv422p10le dc7fbc426d2e30ddd21ec4fd7b7f43aa
+yuv422p12be 2d8075d3b4ae74f9a9860b170c07d26b
+yuv422p12le 2e441892e37e1d3e9b94488723766492
+yuv422p14be b163fa01d688c6bcbb6b77bd6e8a1cb6
+yuv422p14le 06c9cc5e79c1d99ef4d58652c6acc1d5
+yuv422p16be 92e966a93d68ea591cd54730978d7f48
+yuv422p16le d3d1ff9c78b6d1dda8e5529aa881e254
+yuv422p9be b910bf8de09521e2935749fa68fbcf8e
+yuv422p9le 98d13d3db47da9be9f666ce773f2eed9
+yuv440p aba0a5eda16ce1050175bb1151900a4c
+yuv444p 81a72d37cdfba65c7a2dfccaf21cd0d8
+yuv444p10be a10191d92e5a08983bec906d8fbb505a
+yuv444p10le 6367be8bb534416105e450a54ae2efbf
+yuv444p12be 54bcddf538435a8cb9873710d5f3f629
+yuv444p12le 6e8be3148d3e9faf993fed042d063f60
+yuv444p14be a960d66036cc20be0f35dfaf69054f17
+yuv444p14le a607ca2fcb3f662cc2059b5f70c8bb03
+yuv444p16be aee08d16e3efdaa7f0bfe73126a11a23
+yuv444p16le 25be0fc8a7081440b1bef9b4398f4364
+yuv444p9be 3ea6ead34f243fb2d776caeda1571b7a
+yuv444p9le c6fe7f4a77396035be00add0c4ae0eb7
+yuva420p b5b6c3691ecb4cde7e8fb0db0fa58436
+yuva420p10be 9cec28d706cfa9e4cf687adf38fcb437
+yuva420p10le d865d58d6ec7c385be8939e0fb06dcc5
+yuva420p16be 17e321712b97997551cee0d6c93883b0
+yuva420p16le 587f054f353f3c37c2a6554a546d3e6c
+yuva420p9be 2e7fc142cc1c10d5c49db628b745dc6f
+yuva420p9le ab44ecd3051398545b492de1b9c6781a
+yuva422p 2fa2fbe8e495ef0123d5ae5005c1bb3a
+yuva422p10be 8a8553eef2fbbf5ba0a9472f4aaac397
+yuva422p10le 8c84582c47e333d4406b4638a1e9ca28
+yuva422p16be 4b21870437fd45811b42436ec24c22f0
+yuva422p16le c10435c3cae6631c4d5200bb6d4fd427
+yuva422p9be 30fa3a052a24b6eddded347656a820c7
+yuva422p9le 948e60c4e9d5aca07fc2675520da4e1f
+yuva444p 9808d67ac9d32ae98aaa7c0e99894a87
+yuva444p10be 9315b16190771ba62ce09f59b6c0424b
+yuva444p10le 418ec9aea69613173aadac19097924a3
+yuva444p16be 6cac8b62ee44176f71397b8f42691447
+yuva444p16le 1c5acdf9a2d18e8e5cca7b3ab0393985
+yuva444p9be e72f6776db5d1a9f46df3acb3069f88d
+yuva444p9le 09503c3d5f66c5b2d4dede3976121ff9
+yuvj411p 544fb79d4a831b22424fba46e51b6ecc
+yuvj420p d55b1e0d10d3cb467488cce54d9adbe9
+yuvj422p d85777d10b281236f6e83a0362f1f69a
+yuvj440p 29dc5524ee438c06066905165ba0e1a0
+yuvj444p 847c2ae3a37309b3d88f757dded973f1
+yuyv422 c1cf8865677f66e1b2592229754f4595
+yvyu422 a9df408e5f1963a4187c113ca0416d87
diff --git a/tests/ref/fate/filter-pp b/tests/ref/fate/filter-pp
new file mode 100644
index 0000000..fa37774
--- /dev/null
+++ b/tests/ref/fate/filter-pp
@@ -0,0 +1 @@
+pp 3730f1ed7bf244ce059d110e21f39bbd
diff --git a/tests/ref/fate/filter-pp1 b/tests/ref/fate/filter-pp1
new file mode 100644
index 0000000..b129ea3
--- /dev/null
+++ b/tests/ref/fate/filter-pp1
@@ -0,0 +1 @@
+pp1 cb9f884e27a5be11f72afc9b517efd10
diff --git a/tests/ref/fate/filter-pp2 b/tests/ref/fate/filter-pp2
new file mode 100644
index 0000000..257f0a7
--- /dev/null
+++ b/tests/ref/fate/filter-pp2
@@ -0,0 +1 @@
+pp2 975d4c1d489e42ddbd4a27464e8355af
diff --git a/tests/ref/fate/filter-pp3 b/tests/ref/fate/filter-pp3
new file mode 100644
index 0000000..c2f2b4c
--- /dev/null
+++ b/tests/ref/fate/filter-pp3
@@ -0,0 +1 @@
+pp3 ef0f10f1859af2f75717e8c9d64ee38a
diff --git a/tests/ref/fate/filter-pp4 b/tests/ref/fate/filter-pp4
new file mode 100644
index 0000000..61d2fc8
--- /dev/null
+++ b/tests/ref/fate/filter-pp4
@@ -0,0 +1 @@
+pp4 0a2895c619ab9c6c22fd7cffb25070a8
diff --git a/tests/ref/fate/filter-pp5 b/tests/ref/fate/filter-pp5
new file mode 100644
index 0000000..d528c09
--- /dev/null
+++ b/tests/ref/fate/filter-pp5
@@ -0,0 +1 @@
+pp5 5fc6703d42bd98942e5dd104ce220291
diff --git a/tests/ref/fate/filter-pp6 b/tests/ref/fate/filter-pp6
new file mode 100644
index 0000000..46474da
--- /dev/null
+++ b/tests/ref/fate/filter-pp6
@@ -0,0 +1 @@
+pp6 93b508d07bfcf4703aa7dff2d2ef5c03
diff --git a/tests/ref/fate/filter-scale200 b/tests/ref/fate/filter-scale200
index 17103a2..45d0a04 100644
--- a/tests/ref/fate/filter-scale200
+++ b/tests/ref/fate/filter-scale200
@@ -1 +1 @@
-scale200 aebdc1c3e08da2a925ba7212b1fadee0
+scale200 27f58ed67924a4dabf16d9c15cdf9a77
diff --git a/tests/ref/fate/filter-scale500 b/tests/ref/fate/filter-scale500
index 93ba4f2..a885dd4 100644
--- a/tests/ref/fate/filter-scale500
+++ b/tests/ref/fate/filter-scale500
@@ -1 +1 @@
-scale500 ef865c51156e55ce1ce38c8f90a709e6
+scale500 fd3a84a8832f7e1f34b714837986de7d
diff --git a/tests/ref/fate/filter-select b/tests/ref/fate/filter-select
new file mode 100644
index 0000000..b5913fe
--- /dev/null
+++ b/tests/ref/fate/filter-select
@@ -0,0 +1 @@
+select 01a2ff59ce9f6601b05b853b0d3128c1
diff --git a/tests/ref/fate/filter-separatefields b/tests/ref/fate/filter-separatefields
new file mode 100644
index 0000000..46cb470
--- /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 0000000..e9ef835
--- /dev/null
+++ b/tests/ref/fate/filter-setdar
@@ -0,0 +1 @@
+setdar 0f778c1cc72a8d03598d7de535fcb4b5
diff --git a/tests/ref/fate/filter-setpts b/tests/ref/fate/filter-setpts
index 14aa613..c1ce1d3 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, 0x02344760
+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, 0xb15d38c8
+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, 0xce09f9d6
+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, 0xe295c51e
+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, 0x0b07594c
+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 0000000..189cf81
--- /dev/null
+++ b/tests/ref/fate/filter-setsar
@@ -0,0 +1 @@
+setsar 0f778c1cc72a8d03598d7de535fcb4b5
diff --git a/tests/ref/fate/filter-stereo3d-abr-ml b/tests/ref/fate/filter-stereo3d-abr-ml
new file mode 100644
index 0000000..d0597a7
--- /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 0000000..44a8091
--- /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 0000000..b19cbb8
--- /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 0000000..0358199
--- /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 0000000..273e520
--- /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 0000000..c827e3c
--- /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 0000000..5c8a429
--- /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 0000000..b417ae4
--- /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 0000000..b8a13a9
--- /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 0000000..36f11f2
--- /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 0000000..8319d5b
--- /dev/null
+++ b/tests/ref/fate/filter-tile
@@ -0,0 +1 @@
+tile c9f419f3b0813d50c85186b776d0bd85
diff --git a/tests/ref/fate/filter-unsharp b/tests/ref/fate/filter-unsharp
index 5dcf40f..613163b 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 66b8732..f21976a 100644
--- a/tests/ref/fate/filter-vflip
+++ b/tests/ref/fate/filter-vflip
@@ -1 +1 @@
-vflip 2e6d6062e8cad37fb3ab2c433b55f382
+vflip d5b8595bc10291e6230185904d77ebf9
diff --git a/tests/ref/fate/filter-vflip_crop b/tests/ref/fate/filter-vflip_crop
index 6bb832f..0e201d6 100644
--- a/tests/ref/fate/filter-vflip_crop
+++ b/tests/ref/fate/filter-vflip_crop
@@ -1 +1 @@
-vflip_crop 72ee0d0dfc8af0cd94a466760313654d
+vflip_crop 4458d2c260df9748524ac0d74d18fdde
diff --git a/tests/ref/fate/filter-vflip_vflip b/tests/ref/fate/filter-vflip_vflip
index b719745..6fe2aa0 100644
--- a/tests/ref/fate/filter-vflip_vflip
+++ b/tests/ref/fate/filter-vflip_vflip
@@ -1 +1 @@
-vflip_vflip eba2f135a08829387e2f698ff72a2939
+vflip_vflip 005e6ddc8a5daf11cf866a1ec76c2572
diff --git a/tests/ref/fate/filter-yadif-mode0 b/tests/ref/fate/filter-yadif-mode0
index d2c14d3..4d42890 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 ca5f290..08cd518 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 0000000..aa27bfc
--- /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 0000000..65427a2
--- /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 61e6c1d..cd702b6 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 f0faf1d..23a9342 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 0000000..863e746
--- /dev/null
+++ b/tests/ref/fate/force_key_frames
@@ -0,0 +1,4 @@
+74daf0c27174418b74191fd855a631e8 *tests/data/fate/force_key_frames.avi
+113308 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 1ebfb7c..06e0024 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 ac8b701..139ee7e 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 0000000..36c6634
--- /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 0000000..6bf05c5
--- /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/gif-color b/tests/ref/fate/gif-color
new file mode 100644
index 0000000..5559186
--- /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 0000000..547b9ce
--- /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 0000000..838745b
--- /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 0000000..c5ebfcb
--- /dev/null
+++ b/tests/ref/fate/gif-disposal-restore
@@ -0,0 +1,3 @@
+#tb 0: 1/1
+0, 0, 0, 1, 112320, 0xb8afe429
+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 0000000..5a133bd
--- /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 0000000..c0d39bd
--- /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 0000000..9f4a593
--- /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, 2281, 0x68464d30, 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, 1558, 0x7a13e53b, S=1, 1024, 0xf351799f
+0, 41, 41, 1, 940, 0xb1b6cba2, 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, 0xe7af807c, 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, 4289, 0xb415f717, 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 0000000..c11e132
--- /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 0000000..203a154
--- /dev/null
+++ b/tests/ref/fate/gifenc-pal8
@@ -0,0 +1,174 @@
+#tb 0: 1/10
+0, 0, 0, 1, 1320, 0x95d1a9e9, S=1, 1024, 0xec907a9e
+0, 1, 1, 1, 1463, 0xa697fe95, S=1, 1024, 0xec907a9e
+0, 2, 2, 1, 1638, 0x7ea154fa, S=1, 1024, 0xec907a9e
+0, 3, 3, 1, 1755, 0x7e0b9c4d, S=1, 1024, 0xec907a9e
+0, 4, 4, 1, 1896, 0x4aacc768, S=1, 1024, 0xec907a9e
+0, 5, 5, 1, 2038, 0x209d1490, S=1, 1024, 0xec907a9e
+0, 6, 6, 1, 2168, 0x0c405606, S=1, 1024, 0xec907a9e
+0, 7, 7, 1, 2258, 0xc2fa9229, S=1, 1024, 0xec907a9e
+0, 8, 8, 1, 2442, 0x0d4bec48, S=1, 1024, 0xec907a9e
+0, 9, 9, 1, 2565, 0x15742730, S=1, 1024, 0xec907a9e
+0, 10, 10, 1, 2733, 0x2eb57d95, S=1, 1024, 0xec907a9e
+0, 11, 11, 1, 2849, 0x9f16ad46, S=1, 1024, 0xec907a9e
+0, 12, 12, 1, 2981, 0xf139f908, S=1, 1024, 0xec907a9e
+0, 13, 13, 1, 3082, 0x57144aec, S=1, 1024, 0xec907a9e
+0, 14, 14, 1, 3200, 0x35227f42, S=1, 1024, 0xec907a9e
+0, 15, 15, 1, 3316, 0xf6d7c002, S=1, 1024, 0xec907a9e
+0, 16, 16, 1, 3462, 0x27a20d23, S=1, 1024, 0xec907a9e
+0, 17, 17, 1, 3600, 0xaecb2b02, S=1, 1024, 0xec907a9e
+0, 18, 18, 1, 3712, 0x947d49d1, S=1, 1024, 0xec907a9e
+0, 19, 19, 1, 3838, 0xf87eb223, S=1, 1024, 0xec907a9e
+0, 20, 20, 1, 3949, 0x4152eedf, S=1, 1024, 0xec907a9e
+0, 21, 21, 1, 4084, 0x512c1e34, S=1, 1024, 0xec907a9e
+0, 22, 22, 1, 4187, 0xc5715a14, S=1, 1024, 0xec907a9e
+0, 23, 23, 1, 4323, 0x6326a0f5, S=1, 1024, 0xec907a9e
+0, 24, 24, 1, 4426, 0x5f6bd655, S=1, 1024, 0xec907a9e
+0, 25, 25, 1, 4564, 0xc62005fd, S=1, 1024, 0xec907a9e
+0, 26, 26, 1, 4664, 0x43e97006, S=1, 1024, 0xec907a9e
+0, 27, 27, 1, 4808, 0xf6e08d4f, S=1, 1024, 0xec907a9e
+0, 28, 28, 1, 4932, 0x2d51e0b5, S=1, 1024, 0xec907a9e
+0, 29, 29, 1, 5072, 0x577430c8, S=1, 1024, 0xec907a9e
+0, 30, 30, 1, 5247, 0xd9fe945d, S=1, 1024, 0xec907a9e
+0, 31, 31, 1, 5353, 0x27eec140, S=1, 1024, 0xec907a9e
+0, 32, 32, 1, 5536, 0xde59038d, S=1, 1024, 0xec907a9e
+0, 33, 33, 1, 5691, 0x358970e4, S=1, 1024, 0xec907a9e
+0, 34, 34, 1, 5835, 0xd89201d8, S=1, 1024, 0xec907a9e
+0, 35, 35, 1, 5967, 0x1c2e1fee, S=1, 1024, 0xec907a9e
+0, 36, 36, 1, 6082, 0xd4b88e90, S=1, 1024, 0xec907a9e
+0, 37, 37, 1, 6277, 0x020fe685, S=1, 1024, 0xec907a9e
+0, 38, 38, 1, 6382, 0xc1db2297, S=1, 1024, 0xec907a9e
+0, 39, 39, 1, 6509, 0xc65473a6, S=1, 1024, 0xec907a9e
+0, 40, 40, 1, 6621, 0xca917a35, S=1, 1024, 0xec907a9e
+0, 41, 41, 1, 6714, 0x70f29b1d, S=1, 1024, 0xec907a9e
+0, 42, 42, 1, 6822, 0x6f02e7ec, S=1, 1024, 0xec907a9e
+0, 43, 43, 1, 6880, 0x95440d97, S=1, 1024, 0xec907a9e
+0, 44, 44, 1, 6983, 0xab7a43fb, S=1, 1024, 0xec907a9e
+0, 45, 45, 1, 7085, 0xc3427580, S=1, 1024, 0xec907a9e
+0, 46, 46, 1, 7242, 0x3d00c5f0, S=1, 1024, 0xec907a9e
+0, 47, 47, 1, 7349, 0x453fad59, S=1, 1024, 0xec907a9e
+0, 48, 48, 1, 7514, 0xbd862667, S=1, 1024, 0xec907a9e
+0, 49, 49, 1, 7575, 0xf8cb3c77, S=1, 1024, 0xec907a9e
+0, 50, 50, 1, 7759, 0x1fe6ab40, S=1, 1024, 0xec907a9e
+0, 51, 51, 1, 7846, 0x3853fd0f, S=1, 1024, 0xec907a9e
+0, 52, 52, 1, 7975, 0x88d02c47, S=1, 1024, 0xec907a9e
+0, 53, 53, 1, 8092, 0xe28a3368, S=1, 1024, 0xec907a9e
+0, 54, 54, 1, 8188, 0x159a5d3b, S=1, 1024, 0xec907a9e
+0, 55, 55, 1, 8307, 0x598cae50, S=1, 1024, 0xec907a9e
+0, 56, 56, 1, 8436, 0xd104ee50, S=1, 1024, 0xec907a9e
+0, 57, 57, 1, 8498, 0x0b1527ed, S=1, 1024, 0xec907a9e
+0, 58, 58, 1, 8559, 0x0f722288, S=1, 1024, 0xec907a9e
+0, 59, 59, 1, 8661, 0x3efb2500, S=1, 1024, 0xec907a9e
+0, 60, 60, 1, 8774, 0x1e188a8b, S=1, 1024, 0xec907a9e
+0, 61, 61, 1, 8848, 0x5b438dbb, S=1, 1024, 0xec907a9e
+0, 62, 62, 1, 8968, 0x4b47ecb3, S=1, 1024, 0xec907a9e
+0, 63, 63, 1, 9036, 0x7a8e0791, S=1, 1024, 0xec907a9e
+0, 64, 64, 1, 9114, 0x7379131a, S=1, 1024, 0xec907a9e
+0, 65, 65, 1, 9258, 0x06099246, S=1, 1024, 0xec907a9e
+0, 66, 66, 1, 9423, 0x721ac9ab, S=1, 1024, 0xec907a9e
+0, 67, 67, 1, 9529, 0xbb1c0d18, S=1, 1024, 0xec907a9e
+0, 68, 68, 1, 9608, 0xc29a05f0, S=1, 1024, 0xec907a9e
+0, 69, 69, 1, 9668, 0xf35221ff, S=1, 1024, 0xec907a9e
+0, 70, 70, 1, 9709, 0x8c6d33f0, S=1, 1024, 0xec907a9e
+0, 71, 71, 1, 9810, 0x2d5b59f4, S=1, 1024, 0xec907a9e
+0, 72, 72, 1, 9879, 0x110ea6e5, S=1, 1024, 0xec907a9e
+0, 73, 73, 1, 10038, 0x5945f5f4, S=1, 1024, 0xec907a9e
+0, 74, 74, 1, 10120, 0xab24f519, S=1, 1024, 0xec907a9e
+0, 75, 75, 1, 10218, 0x090d305a, S=1, 1024, 0xec907a9e
+0, 76, 76, 1, 10231, 0xa77e6a66, S=1, 1024, 0xec907a9e
+0, 77, 77, 1, 10313, 0x192254b7, S=1, 1024, 0xec907a9e
+0, 78, 78, 1, 10444, 0x36609934, S=1, 1024, 0xec907a9e
+0, 79, 79, 1, 10670, 0xfa971206, S=1, 1024, 0xec907a9e
+0, 80, 80, 1, 10902, 0x01b59fd5, S=1, 1024, 0xec907a9e
+0, 81, 81, 1, 10992, 0x1f2ab0bc, S=1, 1024, 0xec907a9e
+0, 82, 82, 1, 11044, 0x7f5b1dc2, S=1, 1024, 0xec907a9e
+0, 83, 83, 1, 11170, 0x0beaee49, S=1, 1024, 0xec907a9e
+0, 84, 84, 1, 11267, 0xb1ae3808, S=1, 1024, 0xec907a9e
+0, 85, 85, 1, 11427, 0x2cc9aa3f, S=1, 1024, 0xec907a9e
+0, 86, 86, 1, 11529, 0x654de4f3, S=1, 1024, 0xec907a9e
+0, 87, 87, 1, 11632, 0xf4972bdf, S=1, 1024, 0xec907a9e
+0, 88, 88, 1, 11825, 0x0cd2548c, S=1, 1024, 0xec907a9e
+0, 89, 89, 1, 11864, 0x80758637, S=1, 1024, 0xec907a9e
+0, 90, 90, 1, 11950, 0xf8246fba, S=1, 1024, 0xec907a9e
+0, 91, 91, 1, 12088, 0x1b99c82b, S=1, 1024, 0xec907a9e
+0, 92, 92, 1, 12161, 0x682cf4ad, S=1, 1024, 0xec907a9e
+0, 93, 93, 1, 12305, 0x9f62069a, S=1, 1024, 0xec907a9e
+0, 94, 94, 1, 12296, 0xe08dd96c, S=1, 1024, 0xec907a9e
+0, 95, 95, 1, 12497, 0x9a20b2d0, S=1, 1024, 0xec907a9e
+0, 96, 96, 1, 12660, 0x4d1d05ea, S=1, 1024, 0xec907a9e
+0, 97, 97, 1, 12763, 0x12542531, S=1, 1024, 0xec907a9e
+0, 98, 98, 1, 12917, 0x7d0944dc, S=1, 1024, 0xec907a9e
+0, 99, 99, 1, 13021, 0xa1c89f22, S=1, 1024, 0xec907a9e
+0, 100, 100, 1, 13184, 0xe13ad0be, S=1, 1024, 0xec907a9e
+0, 101, 101, 1, 13315, 0x11b93a5d, S=1, 1024, 0xec907a9e
+0, 102, 102, 1, 13337, 0x677e54ef, S=1, 1024, 0xec907a9e
+0, 103, 103, 1, 13536, 0x48b7b5de, S=1, 1024, 0xec907a9e
+0, 104, 104, 1, 13728, 0x03f4d302, S=1, 1024, 0xec907a9e
+0, 105, 105, 1, 13822, 0x973b97ec, S=1, 1024, 0xec907a9e
+0, 106, 106, 1, 14002, 0x0de77dfc, S=1, 1024, 0xec907a9e
+0, 107, 107, 1, 14156, 0xf1b1d4e1, S=1, 1024, 0xec907a9e
+0, 108, 108, 1, 14256, 0x355320cc, S=1, 1024, 0xec907a9e
+0, 109, 109, 1, 14451, 0x306cb131, S=1, 1024, 0xec907a9e
+0, 110, 110, 1, 14508, 0xca729c8e, S=1, 1024, 0xec907a9e
+0, 111, 111, 1, 14683, 0x7abec197, S=1, 1024, 0xec907a9e
+0, 112, 112, 1, 14852, 0xa5b90496, S=1, 1024, 0xec907a9e
+0, 113, 113, 1, 15090, 0xcd29839d, S=1, 1024, 0xec907a9e
+0, 114, 114, 1, 15225, 0xfd85f899, S=1, 1024, 0xec907a9e
+0, 115, 115, 1, 15340, 0x07411310, S=1, 1024, 0xec907a9e
+0, 116, 116, 1, 15473, 0xe90086c1, S=1, 1024, 0xec907a9e
+0, 117, 117, 1, 15583, 0x524da1f3, S=1, 1024, 0xec907a9e
+0, 118, 118, 1, 15683, 0x404cbd62, S=1, 1024, 0xec907a9e
+0, 119, 119, 1, 15779, 0x3ec01717, S=1, 1024, 0xec907a9e
+0, 120, 120, 1, 15934, 0xac8b4c03, S=1, 1024, 0xec907a9e
+0, 121, 121, 1, 16116, 0xb4fa83c9, S=1, 1024, 0xec907a9e
+0, 122, 122, 1, 16153, 0x18f669c1, S=1, 1024, 0xec907a9e
+0, 123, 123, 1, 16303, 0x765b10e4, S=1, 1024, 0xec907a9e
+0, 124, 124, 1, 16460, 0xc4a8149a, S=1, 1024, 0xec907a9e
+0, 125, 125, 1, 16475, 0x48664e2d, S=1, 1024, 0xec907a9e
+0, 126, 126, 1, 16710, 0x8a599742, S=1, 1024, 0xec907a9e
+0, 127, 127, 1, 16848, 0x8634a3d5, S=1, 1024, 0xec907a9e
+0, 128, 128, 1, 16955, 0x01f1ebda, S=1, 1024, 0xec907a9e
+0, 129, 129, 1, 17044, 0xd57b47df, S=1, 1024, 0xec907a9e
+0, 130, 130, 1, 17153, 0xc5cf7bc7, S=1, 1024, 0xec907a9e
+0, 131, 131, 1, 17375, 0xbbeea767, S=1, 1024, 0xec907a9e
+0, 132, 132, 1, 17476, 0xd7a25686, S=1, 1024, 0xec907a9e
+0, 133, 133, 1, 17602, 0x1c99b228, S=1, 1024, 0xec907a9e
+0, 134, 134, 1, 17676, 0xd860d1d2, S=1, 1024, 0xec907a9e
+0, 135, 135, 1, 17799, 0xe4ccb3ae, S=1, 1024, 0xec907a9e
+0, 136, 136, 1, 17930, 0xf322e416, S=1, 1024, 0xec907a9e
+0, 137, 137, 1, 18201, 0xc6f1cfa7, S=1, 1024, 0xec907a9e
+0, 138, 138, 1, 18409, 0x7cdfe609, S=1, 1024, 0xec907a9e
+0, 139, 139, 1, 18686, 0xf65e5519, S=1, 1024, 0xec907a9e
+0, 140, 140, 1, 18790, 0x6d5c8a90, S=1, 1024, 0xec907a9e
+0, 141, 141, 1, 18891, 0x4702a6cf, S=1, 1024, 0xec907a9e
+0, 142, 142, 1, 18995, 0x69e5e02d, S=1, 1024, 0xec907a9e
+0, 143, 143, 1, 19058, 0xc56f0272, S=1, 1024, 0xec907a9e
+0, 144, 144, 1, 19223, 0xe89733f6, S=1, 1024, 0xec907a9e
+0, 145, 145, 1, 19501, 0xdb80f9e9, S=1, 1024, 0xec907a9e
+0, 146, 146, 1, 19566, 0xa3952da8, S=1, 1024, 0xec907a9e
+0, 147, 147, 1, 19692, 0x65925150, S=1, 1024, 0xec907a9e
+0, 148, 148, 1, 19730, 0x1352599a, S=1, 1024, 0xec907a9e
+0, 149, 149, 1, 19916, 0xd246bf9b, S=1, 1024, 0xec907a9e
+0, 150, 150, 1, 20136, 0x1c462eea, S=1, 1024, 0xec907a9e
+0, 151, 151, 1, 20210, 0xdec93f63, S=1, 1024, 0xec907a9e
+0, 152, 152, 1, 20311, 0xdff7836e, S=1, 1024, 0xec907a9e
+0, 153, 153, 1, 20377, 0x753d813f, S=1, 1024, 0xec907a9e
+0, 154, 154, 1, 20478, 0x7592b1a8, S=1, 1024, 0xec907a9e
+0, 155, 155, 1, 20597, 0x58313994, S=1, 1024, 0xec907a9e
+0, 156, 156, 1, 20717, 0xcdd9c665, S=1, 1024, 0xec907a9e
+0, 157, 157, 1, 20816, 0x803b4b03, S=1, 1024, 0xec907a9e
+0, 158, 158, 1, 20912, 0xce36ce22, S=1, 1024, 0xec907a9e
+0, 159, 159, 1, 20975, 0x1d08e543, S=1, 1024, 0xec907a9e
+0, 160, 160, 1, 21130, 0xc966e24c, S=1, 1024, 0xec907a9e
+0, 161, 161, 1, 21343, 0x735e614e, S=1, 1024, 0xec907a9e
+0, 162, 162, 1, 21455, 0x78d7afd1, S=1, 1024, 0xec907a9e
+0, 163, 163, 1, 21533, 0x62a10f46, S=1, 1024, 0xec907a9e
+0, 164, 164, 1, 21645, 0x8e53a12f, S=1, 1024, 0xec907a9e
+0, 165, 165, 1, 21931, 0x3b2f7226, S=1, 1024, 0xec907a9e
+0, 166, 166, 1, 22009, 0xf06bc58a, S=1, 1024, 0xec907a9e
+0, 167, 167, 1, 22115, 0xeeb1c5d7, S=1, 1024, 0xec907a9e
+0, 168, 168, 1, 22211, 0xcbab1084, S=1, 1024, 0xec907a9e
+0, 169, 169, 1, 22380, 0xf07d5cb7, S=1, 1024, 0xec907a9e
+0, 170, 170, 1, 22443, 0xcb79441c, S=1, 1024, 0xec907a9e
+0, 171, 171, 1, 22588, 0xcad49814, S=1, 1024, 0xec907a9e
+0, 172, 172, 1, 22706, 0x34924e43, S=1, 1024, 0xec907a9e
diff --git a/tests/ref/fate/gifenc-rgb4_byte b/tests/ref/fate/gifenc-rgb4_byte
new file mode 100644
index 0000000..9b00103
--- /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 0000000..a894173
--- /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, 2281, 0x6a414aa1, 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, 1558, 0x2c14e4b2, S=1, 1024, 0xcfc8799f
+0, 41, 41, 1, 940, 0x4927cd90, 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, 0x6d338044, 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, 4289, 0x7b3afbc0, 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 0000000..244e546
--- /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 0000000..016abbc
--- /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 0000000..93a3aa4
--- /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 0000000..4141eee
--- /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 0000000..0957654
--- /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 0000000..79e69eb
--- /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 0000000..fc4cc50
--- /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 0000000..0aae9fe
--- /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 0000000..c74483c
--- /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 0000000..26d41d4
--- /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 0000000..3f9bfed
--- /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 5dfa441..4932bdd 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 c61fd0c..4d233b5 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 db85e99..96c2bf4 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 11cc4d0..44cb13b 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 0000000..f73569f
--- /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 0000000..7693050
--- /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 0000000..fd99c82
--- /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 0000000..5ed71e2
--- /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 0000000..2638729
--- /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 0000000..3cd7a26
--- /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 50be4f1..50be4f1 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 0750bb3..589cbf3 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 83f9b4a..077b38e 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 1087148..823988d 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 3d9e43b..0000000
--- 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 c3ebaf2..0000000
--- 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 59f51ef..0000000
--- 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 4b9793b..0000000
--- 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 0000000..d2ab0f5
--- /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 a8427d1..3ba3bb5 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 8037e9c..d616bac 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 5697619..0000000
--- 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 0000000..4454bfa
--- /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 0251f30..0000000
--- 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 0000000..547b590
--- /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 3c0946e..0000000
--- 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 0000000..2c21f35
--- /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 0000000..809b4cd
--- /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 0000000..d887df2
--- /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 0000000..7446ae8
--- /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 0000000..e99e389
--- /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 0000000..e00c29f
--- /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 0000000..d05de74
--- /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 0000000..a01c3b5
--- /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 bff448b..0000000
--- 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 0000000..72a12e8
--- /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 0000000..6c43693
--- /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 0000000..2267a09
--- /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 0000000..48ca5ad
--- /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 0000000..872c5c2
--- /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 0000000..74849eb
--- /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 0000000..55e4be0
--- /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 0000000..e45005f
--- /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 0000000..4e49caa
--- /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 bcfa7fa..885d0e4 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 0000000..63baa95
--- /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 4bea997..56f5b44 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 1a58c0d..2851704 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 0000000..b6ed211
--- /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 0000000..4cb1f78
--- /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 0000000..a1884dd
--- /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 0000000..bbb3cfe
--- /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 0000000..811c790
--- /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 0000000..bbb3cfe
--- /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 f302764..7dbc72b 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 23f03f8..332c7df 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/hmac b/tests/ref/fate/hmac
index 7d2a437..27b95ba 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 badb06d..bdb6fed 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 e294f70..0f55649 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 3f0adfb..7b91238 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 2469aaa..b20e998 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 abd86eb..b37bd6e 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 56a54a1..02b6314 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 0d5102d..b0a6008 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 0000000..51638df
--- /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 6f35893..4f475bb 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 0000000..b5fb96b
--- /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/lmlm4-demux b/tests/ref/fate/lmlm4-demux
index 0546135..95df3e6 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 0000000..9e9ba47
--- /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 0000000..39aec95
--- /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 0000000..435cbec
--- /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 0000000..a47c85c
--- /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 0000000..f720c31
--- /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 e4887f4..ef8a00b 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 0000000..84608fd
--- /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, 0, 63501, 0x139d4c99
+0, 0, 84, 0, 5368, 0xd964b678, F=0x0
+1, 8, 8, 21, 528, 0x3c990ddf
+1, 29, 29, 21, 510, 0xc16e0719
+0, 42, 42, 0, 1840, 0x097b6726, F=0x0
+1, 50, 50, 21, 500, 0x6248f603
+1, 71, 71, 22, 491, 0xe767f705
+0, 84, 167, 0, 7168, 0xaa5913ed, F=0x0
+1, 93, 93, 21, 506, 0x4340f3f3
+1, 114, 114, 21, 492, 0xf11c0210
+0, 125, 125, 0, 2129, 0x6ab0db3e, F=0x0
+1, 135, 135, 21, 502, 0x314b007e
+1, 156, 156, 22, 507, 0x76de0162
+0, 167, 250, 0, 7230, 0x3fd63940, F=0x0
+1, 179, 179, 21, 501, 0x0538fa45
+1, 200, 200, 21, 521, 0xc89f06d2
+0, 209, 209, 0, 2114, 0xfceafb26, F=0x0
+1, 221, 221, 21, 646, 0x8d8d3599
+1, 242, 242, 22, 661, 0x222242de
+0, 250, 334, 0, 63420, 0x5ca6250f, F=0x0
+1, 264, 264, 21, 609, 0xc0dc255c
+1, 285, 285, 21, 619, 0x9ac52dd1
+0, 292, 292, 0, 16751, 0xf293ab46, F=0x0
+0, 292, 417, 0, 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, 0, 5044, 0xa0344ae6, F=0x0
+1, 392, 392, 21, 486, 0x7946e28c
+1, 413, 413, 22, 499, 0xa770f22a
+0, 417, 500, 0, 25289, 0x46f9a219, F=0x0
+1, 435, 435, 21, 506, 0x355ef81d
+1, 456, 456, 21, 474, 0x6d24e2c5
+0, 459, 459, 0, 12871, 0x23e570c4, F=0x0
+1, 477, 477, 21, 494, 0x7d77e90f
+1, 498, 498, 22, 524, 0x6c82fdd2
+0, 500, 584, 0, 29580, 0xd051ad0c, F=0x0
+1, 520, 520, 21, 482, 0xe625f255
+1, 541, 541, 21, 533, 0xed00fd16
+0, 542, 542, 0, 9221, 0xfa1bdf6c, F=0x0
+1, 562, 562, 21, 524, 0x65cdf879
+1, 583, 583, 22, 533, 0xee26f570
+0, 584, 667, 0, 22238, 0x4e0daf3e, F=0x0
+1, 605, 605, 21, 621, 0xed9f23cc
+0, 625, 625, 0, 7627, 0xc566337e, F=0x0
+1, 626, 626, 21, 400, 0xe4fdb43a
+1, 647, 647, 21, 428, 0xd7eacd61
+0, 667, 750, 0, 23124, 0x3bad1f16, F=0x0
+1, 668, 668, 22, 442, 0xef1fda0b
+1, 691, 691, 21, 450, 0x1c58e44b
+0, 709, 709, 0, 7093, 0x3ab77cce, F=0x0
+1, 712, 712, 21, 487, 0x0e5feab7
+1, 733, 733, 21, 465, 0x984adca9
+0, 750, 834, 0, 23210, 0xa7851bbf, F=0x0
+1, 754, 754, 22, 479, 0x0960e535
+1, 776, 776, 21, 489, 0x2f3ffc02
+0, 792, 792, 0, 16045, 0x33039eb5, F=0x0
+1, 797, 797, 21, 505, 0x541aff95
+1, 818, 818, 21, 485, 0xb7a5e7f8
+0, 834, 917, 0, 24859, 0x317ea0f2, F=0x0
+1, 839, 839, 22, 537, 0xb0dd1072
+1, 862, 862, 21, 485, 0x6e9eee58
+0, 875, 875, 0, 7589, 0x02a8e5d5, F=0x0
+1, 883, 883, 21, 480, 0x0a6fec0b
+1, 904, 904, 21, 496, 0x6ff8ee65
+0, 917, 959, 0, 19208, 0xdfb1a109, F=0x0
+1, 925, 925, 21, 505, 0x75a308b8
+1, 946, 946, 21, 512, 0x9628f3da
+0, 959, 2000, 0, 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, 0, 23528, 0xc1dd888a, F=0x0
+1, 2014, 2014, 21, 481, 0x2cd7e611
+1, 2035, 2035, 21, 473, 0x14f2d777
+0, 2042, 2042, 0, 9206, 0x8f8cb89b, F=0x0
+1, 2056, 2056, 21, 543, 0x0f6dfccf
+1, 2077, 2077, 22, 489, 0x8049f5df
+0, 2084, 2167, 0, 34864, 0x3a343fe0, F=0x0
+1, 2099, 2099, 21, 480, 0xaa82edfc
+1, 2120, 2120, 21, 505, 0xea87f3e9
+0, 2125, 2125, 0, 12516, 0x885c8e4d, F=0x0
+1, 2141, 2141, 21, 474, 0x0760e6a1
+1, 2162, 2162, 22, 547, 0xcde40a72
+0, 2167, 2250, 0, 21215, 0x4428040b, F=0x0
+1, 2184, 2184, 21, 606, 0x4e401ec6
+1, 2205, 2205, 21, 611, 0xd13e18b6
+0, 2209, 2209, 0, 11811, 0xfe46f6c7, F=0x0
+1, 2226, 2226, 21, 492, 0xe2a3ea95
+1, 2247, 2247, 22, 582, 0x15fe1df5
+0, 2250, 2334, 0, 18643, 0xdcd87177, F=0x0
+1, 2269, 2269, 21, 455, 0x3753cfd3
+1, 2290, 2290, 21, 467, 0x9342cfed
+0, 2292, 2292, 0, 4578, 0x0bacbdaf, F=0x0
+1, 2311, 2311, 21, 422, 0x080ec43e
+1, 2332, 2332, 22, 466, 0xefb8e9aa
+0, 2334, 2417, 0, 25403, 0x49348e8b, F=0x0
+1, 2355, 2355, 21, 482, 0x2455e264
+0, 2375, 2375, 0, 7254, 0xe5c672b9, F=0x0
+1, 2376, 2376, 21, 471, 0xb370df1e
+1, 2397, 2397, 21, 461, 0x01addfe6
+0, 2417, 2500, 0, 25215, 0x1149c259, F=0x0
+1, 2418, 2418, 22, 566, 0x93760a5d
+1, 2440, 2440, 21, 618, 0x4e8e2f95
+0, 2459, 2459, 0, 14257, 0x38956a4d, F=0x0
+1, 2461, 2461, 21, 612, 0xc79128bc
+1, 2482, 2482, 21, 594, 0x169d1975
+0, 2500, 2584, 0, 36619, 0xca6497c5, F=0x0
+1, 2503, 2503, 22, 488, 0xb218e907
+1, 2526, 2526, 21, 437, 0xb180c83f
+0, 2542, 2542, 0, 13152, 0x4ea52247, F=0x0
+1, 2547, 2547, 21, 432, 0x85f8cf2b
+1, 2568, 2568, 21, 469, 0x65d0e38e
+0, 2584, 2667, 0, 31751, 0xb0140e79, F=0x0
+1, 2589, 2589, 22, 473, 0xb4dee328
+1, 2611, 2611, 21, 462, 0xd95cd547
+0, 2625, 2625, 0, 13619, 0x97308292, F=0x0
+1, 2632, 2632, 21, 470, 0x3638f48d
+1, 2653, 2653, 21, 558, 0x93c3121b
+0, 2667, 2750, 0, 32851, 0x014d2abc, F=0x0
+1, 2674, 2674, 22, 486, 0x5983ed52
+1, 2696, 2696, 21, 507, 0x572af3c3
+0, 2709, 2709, 0, 16915, 0x3597bc67, F=0x0
+1, 2717, 2717, 21, 480, 0xe3b3e16c
+1, 2738, 2738, 21, 492, 0x9443f00e
+0, 2750, 2834, 0, 35380, 0x728cd77a, F=0x0
+1, 2759, 2759, 22, 480, 0x7845ea30
+1, 2781, 2781, 21, 480, 0x7d01e1a2
+0, 2792, 2792, 0, 12780, 0x84c38c29, F=0x0
+1, 2802, 2802, 21, 505, 0x17d6f18b
+1, 2823, 2823, 21, 506, 0xca09ee14
+0, 2834, 2917, 0, 26049, 0x3788982a, F=0x0
+1, 2844, 2844, 22, 479, 0x0383f05a
+1, 2867, 2867, 21, 499, 0xa3b5e804
+0, 2875, 2875, 0, 11796, 0x0cbff503, F=0x0
+1, 2888, 2888, 21, 494, 0x0970e72e
+1, 2909, 2909, 21, 484, 0x6f34da96
+0, 2917, 2959, 0, 16638, 0x097c9345, F=0x0
+1, 2930, 2930, 21, 492, 0x5282e9aa
+1, 2951, 2951, 21, 487, 0x6f19e15e
+0, 2959, 3000, 0, 64129, 0xc13b91ac
+1, 2972, 2972, 22, 500, 0x17aef81a
+1, 2995, 2995, 21, 510, 0xa323f6e6
+0, 3000, 3084, 0, 19338, 0xfe901382, F=0x0
+1, 3016, 3016, 21, 492, 0x49d7e74f
+1, 3038, 3038, 21, 483, 0xa78deadb
+0, 3042, 3042, 0, 4643, 0x5a05768b, F=0x0
+1, 3059, 3059, 21, 639, 0xf2c237e9
+1, 3080, 3080, 21, 661, 0xcd604711
+0, 3084, 3167, 0, 25932, 0x395e1d01, F=0x0
+1, 3101, 3101, 22, 647, 0xb8ee3acf
+1, 3123, 3123, 21, 575, 0x3303118e
+0, 3125, 3125, 0, 5301, 0x2aacb15c, F=0x0
+1, 3144, 3144, 21, 506, 0x2063eef7
+1, 3165, 3165, 21, 518, 0x7661f08e
+0, 3167, 3250, 0, 24089, 0x5cf78354, F=0x0
+1, 3186, 3186, 22, 534, 0x2858f90e
+1, 3208, 3208, 21, 520, 0xd596f460
+0, 3209, 3209, 0, 5837, 0x1c16cfad, F=0x0
+1, 3229, 3229, 21, 496, 0xc2a6efed
+0, 3250, 3334, 0, 26754, 0x4cf1ad04, F=0x0
+1, 3250, 3250, 21, 470, 0xcff5e778
+1, 3271, 3271, 22, 476, 0xcb63e48a
+0, 3292, 3292, 0, 11067, 0x8b0b776f, F=0x0
+1, 3293, 3293, 21, 516, 0xaea8f74b
+1, 3314, 3314, 21, 503, 0x5998f00d
+0, 3334, 3417, 0, 28780, 0xc610f024, F=0x0
+1, 3335, 3335, 21, 488, 0xd818dd28
+1, 3356, 3356, 22, 495, 0x2662f5b5
+0, 3375, 3375, 0, 14863, 0xd58ed8f0, F=0x0
+1, 3379, 3379, 21, 499, 0x6884ec30
+1, 3400, 3400, 21, 496, 0x556bdc0e
+0, 3417, 3500, 0, 24790, 0x71e32bae, F=0x0
+1, 3421, 3421, 21, 524, 0xa756f115
+1, 3442, 3442, 22, 505, 0xd332f37b
+0, 3459, 3459, 0, 9123, 0x6c72b7a3, F=0x0
+1, 3464, 3464, 21, 494, 0xa380e41e
+1, 3485, 3485, 21, 513, 0xf26bf0a9
+0, 3500, 3584, 0, 24706, 0x9bdd9247, F=0x0
+1, 3506, 3506, 21, 515, 0x28fffe2a
+1, 3527, 3527, 22, 506, 0xc5a2f83c
+0, 3542, 3542, 0, 8105, 0x85b8ff64, F=0x0
+1, 3550, 3550, 21, 510, 0xa10bf9c7
+1, 3571, 3571, 21, 507, 0x93d1e650
+0, 3584, 3667, 0, 25402, 0xe4622ee0, F=0x0
+1, 3592, 3592, 21, 506, 0x1a36f285
+1, 3613, 3613, 22, 522, 0xd7a1f5e4
+0, 3625, 3625, 0, 9693, 0x910910bc, F=0x0
+1, 3635, 3635, 21, 511, 0x2e79fa62
+1, 3656, 3656, 21, 516, 0xfda2ef86
+0, 3667, 3750, 0, 31403, 0xff9934ee, F=0x0
+1, 3677, 3677, 21, 497, 0xd65cf156
+1, 3698, 3698, 22, 480, 0xde3be560
+0, 3709, 3709, 0, 13936, 0x9b6aec9e, F=0x0
+1, 3720, 3720, 21, 514, 0x7d8cf49f
+1, 3741, 3741, 21, 667, 0x7a483dec
+0, 3750, 3834, 0, 28639, 0x620b80de, F=0x0
+1, 3762, 3762, 21, 640, 0x7cd92998
+1, 3783, 3783, 22, 504, 0xe3bbf106
+0, 3792, 3792, 0, 18769, 0xf51353c4, F=0x0
+1, 3805, 3805, 21, 498, 0xe8c6f489
+1, 3826, 3826, 21, 489, 0x620df125
+0, 3834, 3917, 0, 30240, 0x48151fb3, F=0x0
+1, 3847, 3847, 21, 505, 0x7d73e570
+1, 3868, 3868, 22, 496, 0xc211f6c6
+0, 3875, 3875, 0, 13391, 0x4f3f112d, F=0x0
+1, 3891, 3891, 21, 483, 0x126fe774
+1, 3912, 3912, 21, 479, 0xac88db91
+0, 3917, 3959, 0, 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 0000000..8c59012
--- /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 97d8edf..c875275 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 e302536..bf8a01a 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-resolution-change-down-down b/tests/ref/fate/mpeg4-resolution-change-down-down
index 137575a..02fcda5 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 31332c3..37e56d8 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 81911f7..36110c3 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 9aac9c8..8d1bbcd 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 d539c71..c54cff6 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 fffdea2..f5c0e647 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 4f8f616..9e898ff 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 0000000..cd5c0e8
--- /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 426afae..3d9a2dc 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/mxpeg b/tests/ref/fate/mxpeg
new file mode 100644
index 0000000..90af90f
--- /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 1d00f8e..98318ac 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 0000000..bb4874f
--- /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 0f09446..0ad08b1 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 a5c9c4a..96ead33 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 71e6bf9..b2e04cb 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 0000000..96beb8c
--- /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 0000000..6523390
--- /dev/null
+++ b/tests/ref/fate/opt
@@ -0,0 +1,90 @@
+Testing default values
+num=0
+toggle=1
+string=default
+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
+
+Testing av_set_options_string()
+OK ''
+Error ':'
+Error '='
+Error 'foo=:'
+Error ':=foo'
+Error '=foo'
+Error 'foo='
+Error 'foo'
+Error 'foo=val'
+Error 'foo==val'
+Error 'toggle=:'
+OK 'string=:'
+Error 'toggle=1 : foo'
+Error 'toggle=100'
+Error 'toggle==1'
+OK 'flags=+mu-lame : num=42: toggle=0'
+OK 'num=42 : string=blahblah'
+Error 'rational=0 : rational=1/2 : rational=1/-1'
+Error 'rational=-1/0'
+OK 'size=1024x768'
+OK 'size=pal'
+Error 'size=bogus'
+OK 'pix_fmt=yuv420p'
+OK 'pix_fmt=2'
+Error 'pix_fmt=bogus'
+OK 'sample_fmt=s16'
+OK 'sample_fmt=2'
+Error 'sample_fmt=bogus'
+OK 'video_rate=pal'
+OK 'video_rate=25'
+OK 'video_rate=30000/1001'
+OK 'video_rate=30/1.001'
+Error 'video_rate=bogus'
+Error 'duration=bogus'
+OK 'duration=123.45'
+OK 'duration=1\:23\:45.67'
+OK 'color=blue'
+OK 'color=0x223300'
+OK 'color=0x42FF07AA'
+OK 'cl=stereo+downmix'
+Error 'cl=foo'
+Error 'bin=boguss'
+Error 'bin=111'
+OK 'bin=ffff'
+Error 'num64=bogus'
+OK 'num64=44'
+OK 'num64=44.4'
+Error 'num64=-1'
+Error 'num64=101'
+Error 'flt=bogus'
+OK 'flt=2'
+OK 'flt=2.2'
+Error 'flt=-1'
+Error 'flt=101'
+Error 'dbl=bogus'
+OK 'dbl=2'
+OK 'dbl=2.2'
+Error 'dbl=-1'
+Error 'dbl=101'
+
+Testing av_opt_set_from_string()
+OK ''
+OK '5'
+OK '5:hello'
+OK '5:hello:size=pal'
+Error '5:size=pal:hello'
+Error ':'
+Error '='
+OK ' 5 : hello : size = pal '
+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 0000000..857fb54
--- /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 01f6e08..1482452 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 3dc4344..c89b608 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 0000000..493497f
--- /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 0000000..b481db7
--- /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 7bd73d8..66fc601 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 5b30968..9d30db6 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 ed819ce..c383836 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 8bd0445..b1159f1 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 eb473ce..f20fe0c 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 b932700..07906c4 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, 0x93ce1cd5
diff --git a/tests/ref/fate/png-ya8 b/tests/ref/fate/png-ya8
index 9ce98f6..3a5c99d 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, 0xed73bf03
diff --git a/tests/ref/fate/pngparser b/tests/ref/fate/pngparser
index b481dcd..93005cf 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 379739f..f402511 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 dc93c33..61a5014 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 1c50840..3113c8a 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 3763b00..5562dce 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 97be6cf..d64cfd5 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 0000000..559ec2b
--- /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 0000000..745e966
--- /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 0000000..5fd8d0b
--- /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 fad2a50..7edbbdd 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 69b1d40..67d4844 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 d0d71b5..2021f2a 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 a424e47..f191169 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 7a162b8..a21b099 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 5866db5..95c0f7c 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 bbdd464..ed6dc03 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 cc09e78..74eb4ab 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 bef2358..5b30fbb 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 9a55ad5..eccb477 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 0000000..2b5b3af
--- /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 34a2924..a7e2838 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 0000000..fadfe93
--- /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 0000000..947412d
--- /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 a1c5333..a9ae3bb 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 0000000..3aa2573
--- /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 89a9d8c..70db647 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 d5cb265..6159859 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 078d1c2..a882118 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 b0e0606..4d4d349 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 3218edc..f56e53e 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 30aca1c..7a6e855 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 8f3ca50..b0521b7 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 058f5f9..9b3d4cb 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 f4e939e..94e35af 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 0000000..6009115
--- /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 5b9dde1..668faee 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 cdfc3d5..1635b37 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 0000000..7aac52f
--- /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 4fcd614..637f28c 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 0000000..1a012cd
--- /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 0000000..87253c9
--- /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 0000000..ed5cdbe
--- /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 0000000..a30fe4a
--- /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 0000000..f0eb331
--- /dev/null
+++ b/tests/ref/fate/sub-microdvd
@@ -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,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:00.00,0:00:40.00,Default,,0,0,0,,25.000 FPS
+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 0000000..7cbab62
--- /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 0000000..6a90e96
--- /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-movtextenc b/tests/ref/fate/sub-movtextenc
new file mode 100644
index 0000000..e74b8f2
--- /dev/null
+++ b/tests/ref/fate/sub-movtextenc
@@ -0,0 +1 @@
+bb762c178bd8c437a9101c748c1ccb4d
diff --git a/tests/ref/fate/sub-mpl2 b/tests/ref/fate/sub-mpl2
new file mode 100644
index 0000000..72fc0fc
--- /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 0000000..890ceb0
--- /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 0000000..64528ec
--- /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 0000000..799c62b
--- /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 0000000..cd9aa5a
--- /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 0000000..caa85a2
--- /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 5a14664..4439857 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,,{\an1}{\move(0,50,0,100)}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 0000000..cde33cd
--- /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 0000000..1f1e031
--- /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 0000000..19944f6
--- /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 0000000..a75406b
--- /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 0000000..6e804f6
--- /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 0000000..8c63a90
--- /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 0000000..dbeadb0
--- /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 0000000..1c6cdaf
--- /dev/null
+++ b/tests/ref/fate/sub2video
@@ -0,0 +1,96 @@
+#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
+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 3b26d1f..3bcf715 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/svq3 b/tests/ref/fate/svq3
index 141300a..073d10b 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/theora-coeff-level64 b/tests/ref/fate/theora-coeff-level64
index d6abb62..4bfafaf 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 57c1209..2fa88c9 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 6b5281d..af4a320 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/truemotion1-24 b/tests/ref/fate/truemotion1-24
index f097ed0..73bb9e7 100644
--- a/tests/ref/fate/truemotion1-24
+++ b/tests/ref/fate/truemotion1-24
@@ -14,3 +14,4 @@
0, 12, 12, 1, 69120, 0xf55d74c7
0, 13, 13, 1, 69120, 0xb5082ca7
0, 14, 14, 1, 69120, 0x5876d758
+0, 15, 15, 1, 69120, 0x45e7dd5c
diff --git a/tests/ref/fate/tscc-15bit b/tests/ref/fate/tscc-15bit
index 372b165..a2871ef 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 0000000..d332efc
--- /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 0000000..73c6a2d
--- /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 99d1182..f6adabe 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 5983ddf..3d4c22b 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 d6c6962..839766b 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 757febe..83e3cb4 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 1198a33..1588b6d 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 555409f..b8e0b41 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 cec5a28..ae79eff 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 ddd074b..21e15b5 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 555eee2..7f9b58d 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 d9afc2c..9da47a4 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 e1c8fcd..8241aae 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 ca77177..bb97e21 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/v210 b/tests/ref/fate/v210
index 2847564..7ad9dcf 100644
--- a/tests/ref/fate/v210
+++ b/tests/ref/fate/v210
@@ -1,2 +1,2 @@
#tb 0: 1/50
-0, 0, 0, 1, 3686400, 0x75ee1dde
+0, 0, 0, 1, 3686400, 0x8d5c3847
diff --git a/tests/ref/fate/v410enc b/tests/ref/fate/v410enc
index ab219bb..b2c728e 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 a60cb8a..7d3b0ab 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 dca5fa9..1b4d55f 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 0000000..521e55f
--- /dev/null
+++ b/tests/ref/fate/vcr2
@@ -0,0 +1,158 @@
+#tb 0: 16701/250000
+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 2a1848e..064b7fa 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/vp5 b/tests/ref/fate/vp5
index 791fe60..0e601ba 100644
--- a/tests/ref/fate/vp5
+++ b/tests/ref/fate/vp5
@@ -245,3 +245,4 @@
0, 243, 243, 1, 233472, 0x6f530ac6
0, 244, 244, 1, 233472, 0x94f7466c
0, 245, 245, 1, 233472, 0xa8c1d365
+0, 246, 246, 1, 233472, 0xedcff050
diff --git a/tests/ref/fate/vp60 b/tests/ref/fate/vp60
index 5e4b62c..c1da72b 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 6ce8486..1f2ddd9 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 0000000..91a099c
--- /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 8795042..edb555d 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 0000000..e974bbc
--- /dev/null
+++ b/tests/ref/fate/vp8-alpha
@@ -0,0 +1,121 @@
+#tb 0: 1/1000
+0, 0, 0, 0, 2108, 0x59b92a34, S=2, 1900, 0x8fb3adc5, 8, 0x00000000
+0, 32, 32, 0, 142, 0x2f2a3fed, F=0x0, S=1, 160, 0xa13346af
+0, 65, 65, 0, 157, 0x17804767, F=0x0, S=1, 209, 0x64115f15
+0, 99, 99, 0, 206, 0x537262ca, F=0x0, S=1, 317, 0x44a09dd0
+0, 132, 132, 0, 259, 0x73ff74b6, F=0x0, S=1, 384, 0x2ee2c588
+0, 165, 165, 0, 320, 0x0fcf8ce4, F=0x0, S=1, 415, 0xff68c953
+0, 199, 199, 0, 377, 0x8fffb5f5, F=0x0, S=1, 475, 0x4166f3eb
+0, 232, 232, 0, 407, 0xe476c19e, F=0x0, S=1, 193, 0x3ff75489
+0, 265, 265, 0, 539, 0x90202334, F=0x0, S=1, 681, 0x776656b0
+0, 299, 299, 0, 560, 0xc6e2168d, F=0x0, S=1, 585, 0xddc81b8a
+0, 332, 332, 0, 597, 0x201a32a7, F=0x0, S=1, 574, 0x8baa1d65
+0, 365, 365, 0, 770, 0xab2b8891, F=0x0, S=1, 666, 0xcd8e51eb
+0, 399, 399, 0, 708, 0xc2386711, F=0x0, S=1, 706, 0x046b6444
+0, 432, 432, 0, 905, 0x7211c52d, F=0x0, S=1, 814, 0x5e288def
+0, 465, 465, 0, 770, 0xda4f8574, F=0x0, S=1, 829, 0xa0e8a949
+0, 499, 499, 0, 955, 0xf9a1d77a, F=0x0, S=1, 857, 0x9b63b955
+0, 532, 532, 0, 970, 0xff4de39a, F=0x0, S=1, 153, 0x3b00416c
+0, 565, 565, 0, 978, 0x12bcf81f, F=0x0, S=1, 1181, 0xce175555
+0, 599, 599, 0, 1233, 0x2903744a, F=0x0, S=1, 860, 0x737eb566
+0, 632, 632, 0, 1118, 0x7f274f50, F=0x0, S=1, 933, 0xb669c6b6
+0, 665, 665, 0, 941, 0x6bffd4b1, F=0x0, S=1, 1058, 0x07581cee
+0, 699, 699, 0, 1598, 0xc007219f, F=0x0, S=1, 939, 0x2c0bdc45
+0, 732, 732, 0, 1218, 0x25d962b6, F=0x0, S=1, 1090, 0x96482341
+0, 765, 765, 0, 1200, 0x86b85be3, F=0x0, S=1, 189, 0x3f085309
+0, 799, 799, 0, 1329, 0x298a848a, F=0x0, S=1, 1426, 0x6ea3df12
+0, 832, 832, 0, 1500, 0xe437edec, F=0x0, S=1, 1244, 0x32836b8d
+0, 865, 865, 0, 1288, 0xc4447dd5, F=0x0, S=1, 1289, 0x06a57b0f
+0, 899, 899, 0, 1281, 0xb5bf7e9f, F=0x0, S=1, 1227, 0xd96d5697
+0, 932, 932, 0, 1372, 0x09be9014, F=0x0, S=1, 1556, 0x2630fbff
+0, 965, 965, 0, 1238, 0x42ce6316, F=0x0, S=1, 1287, 0x1d3084f6
+0, 999, 999, 0, 1655, 0xb94b45c2, F=0x0, S=1, 1494, 0x34dbd1a4
+0, 1032, 1032, 0, 1164, 0xf6b93ad0, F=0x0, S=1, 1337, 0xba6d9673
+0, 1065, 1065, 0, 1084, 0x58c50fb5, F=0x0, S=1, 1384, 0x3fabb82b
+0, 1099, 1099, 0, 1151, 0x0b3f3359, F=0x0, S=1, 1353, 0x08e2a1d7
+0, 1132, 1132, 0, 1277, 0xa3ae77e1, F=0x0, S=1, 1409, 0xf65cb9f7
+0, 1165, 1165, 0, 782, 0xdcf671ff, F=0x0, S=1, 1408, 0x01e2ac53
+0, 1199, 1199, 0, 926, 0xe913c286, F=0x0, S=1, 1320, 0x32e38e42
+0, 1232, 1232, 0, 970, 0x3d86e5ae, F=0x0, S=1, 1608, 0x40b52618
+0, 1265, 1265, 0, 1353, 0xe4f197b2, F=0x0, S=1, 1272, 0xf1d272a5
+0, 1299, 1299, 0, 685, 0x629b4ce4, F=0x0, S=1, 1257, 0x14845de9
+0, 1332, 1332, 0, 743, 0x6f1172a3, F=0x0, S=1, 1260, 0xa6c66fda
+0, 1365, 1365, 0, 789, 0x94fc84cd, F=0x0, S=1, 1009, 0x7daaf2b0
+0, 1399, 1399, 0, 1460, 0x668adb82, F=0x0, S=1, 944, 0x44b6ccf5
+0, 1432, 1432, 0, 766, 0x49c884ef, F=0x0, S=1, 996, 0x8646e6dd
+0, 1465, 1465, 0, 1037, 0x24831498, F=0x0, S=1, 983, 0x14a9e7a6
+0, 1499, 1499, 0, 943, 0x1f53d180, F=0x0, S=1, 1107, 0x02f72acb
+0, 1532, 1532, 0, 1152, 0xbf6a35ae, F=0x0, S=1, 1026, 0xd57afda0
+0, 1565, 1565, 0, 730, 0x42806abf, F=0x0, S=1, 1029, 0xfb0402d5
+0, 1599, 1599, 0, 975, 0xa5ffec57, F=0x0, S=1, 1081, 0xe2890cea
+0, 1632, 1632, 0, 970, 0xbe8ee224, F=0x0, S=1, 1151, 0x7b0d3b20
+0, 1665, 1665, 0, 1012, 0x20c6f0d8, F=0x0, S=1, 979, 0xc25cd69c
+0, 1699, 1699, 0, 874, 0x1a2fb4da, F=0x0, S=1, 943, 0xdb2dc9f8
+0, 1732, 1732, 0, 869, 0xab0caf3d, F=0x0, S=1, 934, 0x48b9bfcc
+0, 1765, 1765, 0, 863, 0xd8caa2e5, F=0x0, S=1, 874, 0x0b34b026
+0, 1799, 1799, 0, 1246, 0x47866cdc, F=0x0, S=1, 818, 0x0c908eeb
+0, 1832, 1832, 0, 742, 0xa6296ac1, F=0x0, S=1, 921, 0x97b6b053
+0, 1865, 1865, 0, 828, 0x0b568d7a, F=0x0, S=1, 969, 0x3314dbfa
+0, 1899, 1899, 0, 825, 0x6d329394, F=0x0, S=1, 982, 0x5f66e68c
+0, 1932, 1932, 0, 836, 0x8ace8dfb, F=0x0, S=1, 929, 0x9ffdc2fd
+0, 1965, 1965, 0, 1774, 0xd4686726, F=0x0, S=1, 909, 0x11a9c07a
+0, 1999, 1999, 0, 1803, 0x08c879ce, F=0x0, S=1, 1525, 0x1e11f02f
+0, 2032, 2032, 0, 518, 0x7c32fc72, F=0x0, S=1, 785, 0xfc1f792a
+0, 2065, 2065, 0, 790, 0x3dac8aa0, F=0x0, S=1, 876, 0x0918c88d
+0, 2099, 2099, 0, 927, 0x4feccb24, F=0x0, S=1, 1059, 0xbcaa05c7
+0, 2132, 2132, 0, 835, 0x29d39266, F=0x0, S=1, 980, 0x4913e409
+0, 2165, 2165, 0, 951, 0xc1dddd12, F=0x0, S=1, 1041, 0x0541047e
+0, 2199, 2199, 0, 876, 0x2f6eb89d, F=0x0, S=1, 949, 0x2d56c53b
+0, 2232, 2232, 0, 959, 0xf0dedabd, F=0x0, S=1, 1022, 0x8d33f5fa
+0, 2265, 2265, 0, 860, 0x9274ab39, F=0x0, S=1, 1061, 0x289c0132
+0, 2299, 2299, 0, 863, 0x7058ba30, F=0x0, S=1, 940, 0x1f32d4a3
+0, 2332, 2332, 0, 1021, 0xcabdf84f, F=0x0, S=1, 887, 0xda8ab95e
+0, 2365, 2365, 0, 897, 0x9867c8e8, F=0x0, S=1, 840, 0xd93eaaf5
+0, 2399, 2399, 0, 897, 0x6a16b5db, F=0x0, S=1, 977, 0x7b77dc9b
+0, 2432, 2432, 0, 953, 0xe9b4cf1f, F=0x0, S=1, 921, 0x75a8ca45
+0, 2465, 2465, 0, 847, 0x0335ad37, F=0x0, S=1, 1000, 0x2691f3bd
+0, 2499, 2499, 0, 902, 0x3360b315, F=0x0, S=1, 1008, 0xd5e1deb6
+0, 2532, 2532, 0, 881, 0xf5309d59, F=0x0, S=1, 1113, 0xdbef3065
+0, 2565, 2565, 0, 974, 0x7c2de3ce, F=0x0, S=1, 1086, 0x365626bb
+0, 2599, 2599, 0, 974, 0xf42bd9f5, F=0x0, S=1, 1039, 0xa7e9060d
+0, 2632, 2632, 0, 1029, 0x7c33f4d0, F=0x0, S=1, 1041, 0xf4affa59
+0, 2665, 2665, 0, 881, 0x9021a565, F=0x0, S=1, 1039, 0xc1e00521
+0, 2699, 2699, 0, 1157, 0xe1c136f7, F=0x0, S=1, 917, 0x357ac7d3
+0, 2732, 2732, 0, 649, 0xdffb3cb7, F=0x0, S=1, 976, 0xa386e05e
+0, 2765, 2765, 0, 758, 0xb67875f3, F=0x0, S=1, 1041, 0xae4e0a63
+0, 2799, 2799, 0, 1105, 0x8ffb1a26, F=0x0, S=1, 962, 0x211ddc5e
+0, 2832, 2832, 0, 866, 0xa60eb2d9, F=0x0, S=1, 929, 0xe9e4c84b
+0, 2865, 2865, 0, 912, 0xcd34bf9b, F=0x0, S=1, 946, 0xfce9d359
+0, 2899, 2899, 0, 868, 0x5651a343, F=0x0, S=1, 809, 0x624a8ef9
+0, 2932, 2932, 0, 997, 0xfa66eaeb, F=0x0, S=1, 992, 0xc913e5e2
+0, 2965, 2965, 0, 1111, 0x3f272497, F=0x0, S=1, 1007, 0xf78ee6a7
+0, 2999, 2999, 0, 842, 0xe442999f, F=0x0, S=1, 972, 0x25a0d25c
+0, 3032, 3032, 0, 1030, 0x6f97ffad, F=0x0, S=1, 993, 0x4059fd6b
+0, 3065, 3065, 0, 1176, 0x66e64926, F=0x0, S=1, 951, 0x2762cdf1
+0, 3099, 3099, 0, 803, 0xfd1699cb, F=0x0, S=1, 959, 0x5cf9d56c
+0, 3132, 3132, 0, 972, 0x1cdff00e, F=0x0, S=1, 1023, 0xeaf20900
+0, 3165, 3165, 0, 907, 0x17f8acca, F=0x0, S=1, 1054, 0xeb010c4d
+0, 3199, 3199, 0, 915, 0x3569b545, F=0x0, S=1, 987, 0x73b2e159
+0, 3232, 3232, 0, 1021, 0x14c5076a, F=0x0, S=1, 1007, 0x6c4bf7f0
+0, 3265, 3265, 0, 837, 0xbf86b0ef, F=0x0, S=1, 963, 0xf472d31a
+0, 3299, 3299, 0, 885, 0x1caac123, F=0x0, S=1, 1052, 0x2b7bfd20
+0, 3332, 3332, 0, 1355, 0x299e8d3c, F=0x0, S=1, 858, 0x2bbca3f0
+0, 3365, 3365, 0, 784, 0xb0bd7e9d, F=0x0, S=1, 969, 0xc865dc00
+0, 3399, 3399, 0, 991, 0xbc7ddda9, F=0x0, S=1, 1028, 0x801b00a6
+0, 3432, 3432, 0, 986, 0xb356f6b1, F=0x0, S=1, 1056, 0x8b840add
+0, 3465, 3465, 0, 978, 0x94a3e87e, F=0x0, S=1, 1018, 0xe766fa52
+0, 3499, 3499, 0, 976, 0x55ddd14a, F=0x0, S=1, 992, 0x58a9ddfe
+0, 3532, 3532, 0, 1241, 0x1ec867f7, F=0x0, S=1, 966, 0xa329e84f
+0, 3565, 3565, 0, 975, 0xecf5dbb3, F=0x0, S=1, 899, 0xa7539f4d
+0, 3599, 3599, 0, 1129, 0xb7243037, F=0x0, S=1, 1057, 0xbd0d10bd
+0, 3632, 3632, 0, 913, 0xe5f1d03d, F=0x0, S=1, 1092, 0xeb9621f8
+0, 3665, 3665, 0, 943, 0x87d0ed78, F=0x0, S=1, 1057, 0x079c1054
+0, 3699, 3699, 0, 917, 0x536cc3fd, F=0x0, S=1, 946, 0xd2b9d0e2
+0, 3732, 3732, 0, 892, 0x4dffb1e2, F=0x0, S=1, 930, 0x70c9cc40
+0, 3765, 3765, 0, 957, 0x1a98e71c, F=0x0, S=1, 719, 0x6fec614a
+0, 3799, 3799, 0, 893, 0xf405b2c3, F=0x0, S=1, 821, 0x63529cab
+0, 3832, 3832, 0, 978, 0xa0a8d5f6, F=0x0, S=1, 745, 0x3c616219
+0, 3865, 3865, 0, 887, 0xfa7cb65d, F=0x0, S=1, 768, 0xb8f07885
+0, 3899, 3899, 0, 867, 0xd808ade7, F=0x0, S=1, 783, 0xf82b6b9a
+0, 3932, 3932, 0, 1068, 0x6f8b135a, F=0x0, S=1, 807, 0x52028d50
+0, 3965, 3965, 0, 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 77b69ed..b503de8 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 d87c563..f581c99 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 64accc4..ef38aa8 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 d42674a..55149b0 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 504766f..ffe3896 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 f402372..f7f5313 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 3569dee..3368c70 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 38b92c4..28c249c 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 8d9b912..a0cb441 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 9be8d73..0503c4e 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 fae204d..f41f014 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 b250ad9..2feeb63 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 d591ec7..adf7235 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 4d5adcb..3de64b6 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 de7c0b3..e31e6e6 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 4341e59..689e24b 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 b32f233..766c931 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 291e7fe..4da7ff3 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 a8ccda8..0d3fbea 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 a6e701e..e2afb9c 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 0d22d2b..4d9b081 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 023caf8..09e6299 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 5abb9ee..0c22157 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 1be91be..730a012 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 9e359b3..0f2dd7a 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 e984311..c6c1282 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 b1e6b54..cdc6ec5 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 6bb9687..f405cef 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 32055ca..bc5e86a 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 9f738a3..93e46a9 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 3449ea9..0924f54 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 1494fd9..9213e9d 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 1a75e63..80d1a6c 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 b614bd7..e7ab21d 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 e092a9a..842ab6e 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 159debc..7478558 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 bc89173..3a5b1c1 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 a05d563..baf3bc3 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 43c1c55..2ba95e1 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 95e5216..8119688 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 4ddd9fb..0e94992 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 bb9d945..90533aa 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 968dfc1..d16d198 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 8f087c5..eccdfd6 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 a14840b..70a76b3 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 0ccb749..d9308dc 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 f8c5df7..d2efd69 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 588ef1c..85919fc 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 583cfa0..cc6eae7 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 45b2c69..4f26b58 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 22c5749..4c9bf96 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 8103d96..ef49c4e 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 ab7c061..374c44e 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 d5719ec..aa9c833 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 623d62c..820725b 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 e6cde45..4a39a13 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 b4c0134..96e526f 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 89e45f9..9f61d33 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 ed5add1..396a1a3 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 8ac2b91..dc77394 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 ccd735d..667549c 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 3955ebf..c7fbfbc 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 e458266..090ce6f 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 178c224..130b5fa 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 4ab45e2..5cb7105 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 df6c212..cb51f72 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 7e6476e..0bf90b4 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 22a3ce2..2604a53 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 34f74a6..3403d1d 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 e9d40af..f2cdc8e 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 3a86326..87ab57e 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 6d976d8..f3a14d1 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 5f2ab99..784925d 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 38c2496..daa6f5d 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 c50fdd4..0a48cf9 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 80bff69..f1f6069 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 38783aa..499b57e 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 80ead0f..2a10350 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 dbc6a5d..8ae9bd3 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 c71532e..a409462 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 b453341..92aa67f 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 1efa26f..d17d3d6 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 f473884..d7765be 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 406bd61..02e6e16 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 78d7e91..51238c1 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 541c7e9..e1af6f6 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 df41b70..977095f 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 b183d6b..c0cf715 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 e0189a2..2e52d32 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 3fad7dc..b2b5fda 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 51a27b3..403a131 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 3829cfb..01d8818 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 c2e0a68..d72aafc 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 8b7470d..8615d7b 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 7d3841f..55ab620 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 affba37..bdcedbf 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 506f39f..3226dfa 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 6ef07a0..7aaa369 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 f9ea55b..5708cd3 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 cff03c2..a60e36b 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 9f9f5fe..659d491 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 3f1e9f1..d4069c9 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 5ca7bee..f5ec31c 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 e61e65d..950b04e 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 9a9401f..04a5e7e 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 ef9fa1b..f26965a 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 aac95a3..84e9b17 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 bea7010..8490e4e 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 b013952..fb6f0c8 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 1795bd9..fadce55 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 663a456..02a2676 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 54d9aaa..97e527f 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 0e19d9a..63dbf24 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 2d75fc8..f7d0102 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 49129ce..08aabcc 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 3fcf5ca..9323a14 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 6b2a43a..a3a91b9 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 d7103ae..b90faf3 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 450facc..b7bd74b 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 ef6042a..0f46da7 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 038b21b..172422c 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 6d3021b..c400956 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 ae376d3..2df5adc 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 bc816e9..f5f45fb 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 ebb465e..4aac211 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 6afccbb..2b30219 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 fb3fb87..e9de2ed 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 4e000a5..e1e00fd 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 d2b9c99..c39c88d 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 65c87da..d036df1 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 d6ccbbb..5869186 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 adcb22e..a2ce10e 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 db88976..0c8dc67 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 d877088..8c92b2d 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 ce29241..a9f804e 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 fc5b90c..4bed149 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 e31ad98..ac61f27 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 2182c29..2bc9eb6 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 b15296a..e1e01ee 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 e499cc9..046e7ee 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 4810a6e..16cb5dd 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 1f8fdf3..427acca 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 ed1c9a5..a0f033e 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 c90f7e3..a852272 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 743732b..418febe 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 7f2a052..d358bd6 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 76ec31e..426f91b 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 63c775b..8e0133a 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 97d67c8..4bdc1ba 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 03928de..3b395dd 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 0901a7b..14b9cb0 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 a999573..79bc91c 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 3a3d6c8..a89e10f 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 5c4e1ac..73aa4e7 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 c8ed23f..293abad 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 39efcba..1c4156b 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 b328ab4..294c7de 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 0aed802..d0882e5 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 9f8c3f2..20f46ea 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 2e68802..b1ffd8f 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 7d24b47..7248874 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 152de0d..fb49188 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 974ab53..0ef318a 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 595299e..2d02a49 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 890dd9c..f458f53 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 2535ceb..176b9d9 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 ba4d425..371a874 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 49fea91..95b2e06 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 899fd50..1e2790a 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 b972f6a..7cccf9b 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 4f622cd..81136e6 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 b0b7ee2..670d115 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 f7c7c3f..fd37506 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 6f45370..d5806a1 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 3657e80..3f6ee8b 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 cd47b57..ea1cb0c 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 91eaa80..7c459d2 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 14f52f6..19a786c 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 97e600c..dd7967d 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 c224ef0..1af7c58 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 96a3a1f..d51ee96 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 a8d42a7..f75e192 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 9867cc7..af7cb9a 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 a2a98f6..cc85d27 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 b9fb7c2..d51fcc6 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 9a6b9da..0a36bd3 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 38d2e60..6bc31f9 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 a541f14..b06557f 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 2236687..84da7dd 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 5f924a3..0943abf 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 b5373d5..b181224 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 aa5bc3c..7bcbfdc 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 0477efa..7dbccf6 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 18ed456..70d64ea 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 a7a1981..7d9020c 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 0db3b00..a6813b4 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 3949dbd..c14d20c 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 9c4245c..873525b 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 253bb1d..91e229e 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 39752a9..a77ac5f 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 efbc81c..fa9f158 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 cfa3758..1e1d225 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 046f733..5563363 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 b94c04d..1275e9e 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 dfcc091..39e0825 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 f7cf72c..8fbc5b1 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 e957344..3e212ac 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 b2efc65..a925e1a 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 0996abd..3c59459 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 fba94fc..610578b 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 2bf1225..874e595 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 9cb72d3..43d55b9 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 f70b330..fe2c477 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 62cea7f..b16c531 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 d13634a..818038d 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 9e88108..cda6f99 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 0ff9dfc..fa83e1d 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 37b39a8..50d81cb 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 01c05dc..88b3c43 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-2pass-akiyo b/tests/ref/fate/vp9-2pass-akiyo
index 5061a76..2f32092 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 0978807..9668c54 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 2be837a..5c931b6 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 bfef222..0fdb3f2 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 23c760e..2915323 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 0000000..4d129b3
--- /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/vqa-cc b/tests/ref/fate/vqa-cc
index d3c5e6a..8950f94 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 3acae60..3c1dd35 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 0000000..f5fc912
--- /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-representations b/tests/ref/fate/webm-dash-manifest-representations
new file mode 100644
index 0000000..8556ece
--- /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 0000000..6e9de21
--- /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 0000000..ce20563
--- /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 7f4b523..12d8fbb 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 d6bf15e..279c8b6 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 0000000..1f75ce2
--- /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 bdd6c20..904d78b 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 778e8ab..77192b3 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 0000000..7f1f1e6
--- /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 20c6ac1..d13270a 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 0361389..c00a24b 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 c3cafa3..2fc93ee 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 1a56660..1920281 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 f054a9d..384bb65 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 b0c3df5..cb39014 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/fate/zmbv-8bit b/tests/ref/fate/zmbv-8bit
index 64dacae..9f02ae3 100644
--- a/tests/ref/fate/zmbv-8bit
+++ b/tests/ref/fate/zmbv-8bit
@@ -274,3 +274,4 @@
0, 272, 272, 1, 192000, 0xd08e49d1
0, 273, 273, 1, 192000, 0xd08e49d1
0, 274, 274, 1, 192000, 0xd08e49d1
+0, 275, 275, 1, 192000, 0x1f34135f
diff --git a/tests/ref/lavf-fate/latm b/tests/ref/lavf-fate/latm
new file mode 100644
index 0000000..8c4f541
--- /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 0000000..b559538
--- /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 0000000..9e9cc7e
--- /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 c713d02..c504c18 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 2178435..400278c 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 0000000..513c612
--- /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 71cfdcb..ede4926 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 08ae042..4068fad 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
+cec38e42ff83343f6a5c300aa3009e7f *./tests/data/lavf/lavf.avi
+330806 ./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 b79ee4d..8958855 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 0000000..7b2a67d
--- /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 a9f1169..591ef1b 100644
--- a/tests/ref/lavf/dpx
+++ b/tests/ref/lavf/dpx
@@ -1,3 +1,18 @@
-808ea110635774252439722a48329d61 *./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 c2b7335..b152c84 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 0000000..c11350a
--- /dev/null
+++ b/tests/ref/lavf/ffm
@@ -0,0 +1,3 @@
+16cc0ee04b036c210b2fc85182d748e1 *./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 0000000..59aac92
--- /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 019204d..f014bec 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 4a4ebfb..d2e2f11 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 8dfd63d..d356f20 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 0000000..47e0709
--- /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 0000000..ab2975f0
--- /dev/null
+++ b/tests/ref/lavf/ismv
@@ -0,0 +1,9 @@
+b1106bfcdbd1bb12be9161320351dd00 *./tests/data/lavf/lavf.ismv
+312542 ./tests/data/lavf/lavf.ismv
+./tests/data/lavf/lavf.ismv CRC=0xb7d29d29
+c8bea6c84b6274f14042381045b0f532 *./tests/data/lavf/lavf.ismv
+321448 ./tests/data/lavf/lavf.ismv
+./tests/data/lavf/lavf.ismv CRC=0x33834815
+b1106bfcdbd1bb12be9161320351dd00 *./tests/data/lavf/lavf.ismv
+312542 ./tests/data/lavf/lavf.ismv
+./tests/data/lavf/lavf.ismv CRC=0xb7d29d29
diff --git a/tests/ref/lavf/jpg b/tests/ref/lavf/jpg
index 584a97a..1309d74 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 a871ea9..edbfe60 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 947abc7..fae95ca 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 f34a006..72d962a 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 e4c8ae0..7aab14f 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 09e3c36..236661c 100644
--- a/tests/ref/lavf/mxf
+++ b/tests/ref/lavf/mxf
@@ -1,3 +1,9 @@
-051b982c1b5799eb107339735a090c70 *./tests/data/lavf/lavf.mxf
-525881 ./tests/data/lavf/lavf.mxf
-./tests/data/lavf/lavf.mxf CRC=0x773f059a
+dbc4ced82ef1c2fa4df3571b4f994a22 *./tests/data/lavf/lavf.mxf
+525369 ./tests/data/lavf/lavf.mxf
+./tests/data/lavf/lavf.mxf CRC=0xdbfff6f1
+fe4294023cd990938f042c7855405f63 *./tests/data/lavf/lavf.mxf
+560697 ./tests/data/lavf/lavf.mxf
+./tests/data/lavf/lavf.mxf CRC=0x11a6178e
+ef0c741e17bf7963fc51adcb6bab8ec8 *./tests/data/lavf/lavf.mxf
+525369 ./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 5864e8e..ff7d876 100644
--- a/tests/ref/lavf/mxf_d10
+++ b/tests/ref/lavf/mxf_d10
@@ -1,3 +1,3 @@
-8cf467a910c84dd05db24848becba42e *./tests/data/lavf/lavf.mxf_d10
+87e0903ef7ea55b1a032b9d878588683 *./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/nut b/tests/ref/lavf/nut
index d7a8ab1..1c3d710 100644
--- a/tests/ref/lavf/nut
+++ b/tests/ref/lavf/nut
@@ -1,3 +1,3 @@
-8c9d5193a672ad0dee90f0712acc3a31 *./tests/data/lavf/lavf.nut
-319680 ./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 ea827ac..a08fb5e 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 636a419..abb2974 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 e60ea78..6568b60 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 419fdaa..816579f 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 28ad60e..da6f9a6 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 186dde5..8803087 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 f216e7e..9cf677b 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 33275e2..97093aa 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 993310d..62e0a31 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 b0cd303..a43c1f4 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 0000000..a2eeb97
--- /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 097235b..4db0505 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 1e07793..7ce0fa4 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 ce6b646..7efaf97 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 b636bd9..4b0b985 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 8512d26..1381f09 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 3131960..ded8af7 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 deb7999..d026090 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 0000000..26c6868
--- /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 fa8a859..da3bfc2 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 0000000..aa7e5fc
--- /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 0000000..dccd0e7
--- /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 0000000..b0ae7d1
--- /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 0000000..4cc4be6
--- /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 3fd20c8..5e593b5 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 0000000..bdaf1f0
--- /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 0000000..b6517c5
--- /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 0000000..579be7f
--- /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 0000000..2f90913
--- /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 0000000..5cbfaed
--- /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 15ab0d2..f6add9a 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-mp2 b/tests/ref/seek/acodec-mp2
index 8de3676..62abab4 100644
--- a/tests/ref/seek/acodec-mp2
+++ b/tests/ref/seek/acodec-mp2
@@ -1,6 +1,6 @@
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 417
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 417
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 440
ret: 0 st:-1 flags:1 ts: 1.894167
ret: 0 st: 0 flags:1 dts: 1.880816 pts: 1.880816 pos: 30093 size: 418
ret: 0 st: 0 flags:0 ts: 0.788334
@@ -18,7 +18,7 @@ ret: 0 st: 0 flags:1 dts: 2.168163 pts: 2.168163 pos: 34690 size: 418
ret: 0 st:-1 flags:1 ts: 1.047503
ret: 0 st: 0 flags:1 dts: 1.044898 pts: 1.044898 pos: 16718 size: 418
ret: 0 st: 0 flags:0 ts:-0.058330
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 417
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 440
ret: 0 st: 0 flags:1 ts: 2.835837
ret: 0 st: 0 flags:1 dts: 2.821224 pts: 2.821224 pos: 45139 size: 418
ret: 0 st:-1 flags:0 ts: 1.730004
@@ -26,7 +26,7 @@ ret: 0 st: 0 flags:1 dts: 1.750204 pts: 1.750204 pos: 28003 size: 418
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.600816 pts: 0.600816 pos: 9613 size: 418
ret: 0 st: 0 flags:0 ts:-0.481662
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 417
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 440
ret: 0 st: 0 flags:1 ts: 2.412505
ret: 0 st: 0 flags:1 dts: 2.403265 pts: 2.403265 pos: 38452 size: 418
ret: 0 st:-1 flags:0 ts: 1.306672
@@ -34,7 +34,7 @@ ret: 0 st: 0 flags:1 dts: 1.332245 pts: 1.332245 pos: 21315 size: 418
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.182857 pts: 0.182857 pos: 2925 size: 418
ret: 0 st: 0 flags:0 ts:-0.904994
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 417
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 440
ret: 0 st: 0 flags:1 ts: 1.989173
ret: 0 st: 0 flags:1 dts: 1.985306 pts: 1.985306 pos: 31764 size: 418
ret: 0 st:-1 flags:0 ts: 0.883340
diff --git a/tests/ref/seek/acodec-pcm-f32be b/tests/ref/seek/acodec-pcm-f32be
index 886356a..b838262 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 9be3b4e..8222351 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 4f1ffc5..41acc98 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 8348916..afa3351 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/lavf-aiff b/tests/ref/seek/lavf-aiff
index 784b144..eb9ada0 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 2eade27..b64bec3 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 a2c57eb..d5a70b2 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 0cabe12..7725134 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: 9926 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: 9926 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: 301474 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: 301474 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: 301474 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: 155956 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: 301474 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: 9926 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: 301474 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: 155956 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: 9926 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: 301474 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: 9926 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: 9926 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: 301474 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: 301474 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: 301474 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: 155956 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 d60729b..0f0b152 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 3c49749..0000ff5 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 0000000..eceed1a
--- /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 77a1066..c12da84 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 883f187..9ce8308 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 c8f11c8..7162462 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 88964ca..4f3a14c 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 fd4fcf1..11275d6 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 196d263..0bc98fa 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 0091915..27ea7c7 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 6e27064..e804b84 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 c65e868..9b23466 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: 6144 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: 6144 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: 460288 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: 460288 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: 6144 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: 460288 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: 211456 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: 6144 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: 460288 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: 6144 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: 460288 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: 211456 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: 6144 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: 460288 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: 6144 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: 6144 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: 460288 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: 460288 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: 6144 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: 460288 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: 460288 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: 6144 size: 24801
diff --git a/tests/ref/seek/lavf-nut b/tests/ref/seek/lavf-nut
index fc3ef63..b2da526 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: 279 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: 279 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: 146329 size: 27925
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146329 size: 27925
-ret: 0 st: 0 flags:1 ts:-0.320000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 279 size: 27837
-ret: 0 st: 1 flags:0 ts: 2.586122
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146329 size: 27925
-ret: 0 st: 1 flags:1 ts: 1.462857
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146329 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: 279 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: 279 size: 27837
-ret: 0 st: 0 flags:0 ts: 2.160000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146329 size: 27925
-ret: 0 st: 0 flags:1 ts: 1.040000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146329 size: 27925
-ret: 0 st: 1 flags:0 ts:-0.052245
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 279 size: 27837
-ret: 0 st: 1 flags:1 ts: 2.847347
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146329 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: 146329 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: 146329 size: 27925
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 279 size: 27837
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146329 size: 27925
-ret: 0 st: 1 flags:0 ts: 1.306122
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146329 size: 27925
-ret: 0 st: 1 flags:1 ts: 0.208980
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 279 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: 279 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: 146329 size: 27925
-ret: 0 st: 0 flags:0 ts: 0.880000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146329 size: 27925
-ret: 0 st: 0 flags:1 ts:-0.240000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 279 size: 27837
-ret: 0 st: 1 flags:0 ts: 2.664490
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146329 size: 27925
-ret: 0 st: 1 flags:1 ts: 1.567347
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146329 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: 146329 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: 279 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 109ae32..caf4879 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 2858934..25bb68f 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 418674f..ba21627 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 2836367..ceac008 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 8ba5180..57b4e4a 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 6376b5e..6d53ce0 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 46c535a..7087494 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 adce9e0..4b19173 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 b2f605a..b07132a 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 8f90753..ee7552a 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 1b49f2f..0d9fb04 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 b31fab0..e57651e 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 387aef6..833d763 100644
--- a/tests/ref/seek/lavf-voc
+++ b/tests/ref/seek/lavf-voc
@@ -1,27 +1,27 @@
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:-1 st: 0 flags:0 ts: 0.788330
+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:-1 st: 0 flags:0 ts: 0.365012
+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:-1 st: 0 flags:0 ts:-0.058328
+ret:-1 st: 0 flags:1 ts: 2.835848
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:-1 st: 0 flags:0 ts:-0.481669
+ret:-1 st: 0 flags:1 ts: 2.412507
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: 0 flags:0 ts:-0.904986
+ret:-1 st: 0 flags:1 ts: 1.989167
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.671668
-ret:-1 st: 0 flags:1 ts: 1.565847
+ret:-1 st: 0 flags:0 ts: 2.671673
+ret:-1 st: 0 flags:1 ts: 1.565849
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-wav b/tests/ref/seek/lavf-wav
index 1a9cfc5..ed2f8d6 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 0000000..355ab98
--- /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
index 5873bb1..e2556a7 100644
--- a/tests/ref/seek/vsynth2-asv1
+++ b/tests/ref/seek/vsynth2-asv1
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 14316
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 12152
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 14316
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 12152
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: 776840 size: 18256
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: 643344 size: 15064
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: 305352 size: 16180
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: 255232 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: 595448 size: 17980
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos: 493584 size: 14796
ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 135516 size: 14868
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 114852 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: 404100 size: 16856
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos: 336180 size: 13824
ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 14316
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 12152
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 813396 size: 18296
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 673504 size: 15104
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: 704136 size: 18140
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: 583312 size: 14956
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: 241764 size: 15736
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: 202872 size: 12944
ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 14316
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 12152
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 813396 size: 18296
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 673504 size: 15104
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: 524488 size: 17548
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: 435128 size: 14488
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 77020 size: 14496
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 65864 size: 12144
ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 14316
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 12152
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 813396 size: 18296
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 673504 size: 15104
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: 337808 size: 16388
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: 281884 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: 631584 size: 18188
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos: 523324 size: 14972
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 180212 size: 15168
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 152056 size: 12540
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-asv2 b/tests/ref/seek/vsynth2-asv2
index 7d37b7a..cd99c45 100644
--- a/tests/ref/seek/vsynth2-asv2
+++ b/tests/ref/seek/vsynth2-asv2
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 13732
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 12072
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 13732
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 12072
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: 736152 size: 17340
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: 630028 size: 14892
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: 289708 size: 15300
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: 248836 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: 564140 size: 17016
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos: 482700 size: 14532
ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 128564 size: 14052
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 111600 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: 383244 size: 15896
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos: 328252 size: 13532
ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 13732
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 12072
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 770852 size: 17400
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 659848 size: 14928
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: 667016 size: 17172
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: 570784 size: 14712
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: 229388 size: 14956
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: 197536 size: 12724
ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 13732
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 12072
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 770852 size: 17400
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 659848 size: 14928
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: 496932 size: 16564
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: 425316 size: 14116
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 73176 size: 13664
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 64104 size: 11780
ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 13732
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 12072
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 770852 size: 17400
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 659848 size: 14928
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: 320444 size: 15592
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: 274964 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: 598288 size: 17180
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos: 511944 size: 14668
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 171012 size: 14392
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 147820 size: 12240
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
index 6c41d67..a5f0ce9 100644
--- a/tests/ref/seek/vsynth2-dnxhd-1080i
+++ b/tests/ref/seek/vsynth2-dnxhd-1080i
@@ -3,41 +3,41 @@ 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:-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.360000
-ret: 0 st: 0 flags:1 ts:-0.760000
+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.040000
+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.840000
+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.480000
+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.400000
+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.920000
+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: 2.000000
+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.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
+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
diff --git a/tests/ref/seek/vsynth2-dnxhd-720p b/tests/ref/seek/vsynth2-dnxhd-720p
index b6398b6..b57f07d 100644
--- a/tests/ref/seek/vsynth2-dnxhd-720p
+++ b/tests/ref/seek/vsynth2-dnxhd-720p
@@ -3,38 +3,38 @@ 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: 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.360000
-ret:-1 st: 0 flags:1 ts:-0.760000
+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.040000
+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.840000
+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.480000
+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.400000
+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.920000
+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: 2.000000
+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.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
+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/vsynth2-dnxhd-720p-rd b/tests/ref/seek/vsynth2-dnxhd-720p-rd
index b6398b6..b57f07d 100644
--- a/tests/ref/seek/vsynth2-dnxhd-720p-rd
+++ b/tests/ref/seek/vsynth2-dnxhd-720p-rd
@@ -3,38 +3,38 @@ 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: 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.360000
-ret:-1 st: 0 flags:1 ts:-0.760000
+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.040000
+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.840000
+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.480000
+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.400000
+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.920000
+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: 2.000000
+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.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
+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/vsynth2-dv b/tests/ref/seek/vsynth2-dv
index baaeefb..d318794 100644
--- a/tests/ref/seek/vsynth2-dv
+++ b/tests/ref/seek/vsynth2-dv
@@ -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: 1.880000 pts: 1.880000 pos: -1 size:144000
+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: -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.576668
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
+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: -1 size:144000
+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: -1 size:144000
+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: -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.153336
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
+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: -1 size:144000
+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: -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.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
+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: -1 size:144000
+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: -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: 1.960000 pts: 1.960000 pos: -1 size:144000
+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: -1 size:144000
+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: -1 size:144000
+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: -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.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
+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: -1 size:144000
+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: -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.680000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
+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: -1 size:144000
+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: -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/vsynth2-dv-411 b/tests/ref/seek/vsynth2-dv-411
index baaeefb..d318794 100644
--- a/tests/ref/seek/vsynth2-dv-411
+++ b/tests/ref/seek/vsynth2-dv-411
@@ -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: 1.880000 pts: 1.880000 pos: -1 size:144000
+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: -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.576668
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
+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: -1 size:144000
+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: -1 size:144000
+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: -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.153336
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
+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: -1 size:144000
+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: -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.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
+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: -1 size:144000
+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: -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: 1.960000 pts: 1.960000 pos: -1 size:144000
+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: -1 size:144000
+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: -1 size:144000
+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: -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.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
+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: -1 size:144000
+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: -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.680000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
+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: -1 size:144000
+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: -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/vsynth2-dv-50 b/tests/ref/seek/vsynth2-dv-50
index 1f07e5b..fae6d1b 100644
--- a/tests/ref/seek/vsynth2-dv-50
+++ b/tests/ref/seek/vsynth2-dv-50
@@ -1,53 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+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: -1 size:288000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:288000
diff --git a/tests/ref/seek/vsynth2-ffv1 b/tests/ref/seek/vsynth2-ffv1
index 715a272..84e7436 100644
--- a/tests/ref/seek/vsynth2-ffv1
+++ b/tests/ref/seek/vsynth2-ffv1
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5688 size: 71679
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5690 size: 71707
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5688 size: 71679
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5690 size: 71707
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2498334 size: 75937
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2499438 size: 75965
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1630830 size: 72682
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1631570 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:2498334 size: 75937
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2499438 size: 75965
ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 801262 size: 69457
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 801634 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:1630830 size: 72682
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1631570 size: 72710
ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5688 size: 71679
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5690 size: 71707
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3392418 size: 77461
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3393890 size: 77489
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3392418 size: 77461
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3393890 size: 77489
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 801262 size: 69457
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 801634 size: 69485
ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5688 size: 71679
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5690 size: 71707
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3392418 size: 77461
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3393890 size: 77489
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2498334 size: 75937
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2499438 size: 75965
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5688 size: 71679
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5690 size: 71707
ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5688 size: 71679
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5690 size: 71707
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3392418 size: 77461
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3393890 size: 77489
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1630830 size: 72682
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1631570 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:2498334 size: 75937
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2499438 size: 75965
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 801262 size: 69457
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 801634 size: 69485
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-flashsv b/tests/ref/seek/vsynth2-flashsv
index 5c3dfbd..8bfb2fc 100644
--- a/tests/ref/seek/vsynth2-flashsv
+++ b/tests/ref/seek/vsynth2-flashsv
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size:240757
+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: 179 size:240757
+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:11605742 size:254053
+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:4820497 size:245503
+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:8811891 size:253041
+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:2387432 size:241101
+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:6302814 size:248927
+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: 179 size:240757
+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:12114692 size:254237
+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:10843556 size:253913
+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:3598785 size:243372
+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: 179 size:240757
+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:12114692 size:254237
+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:8053696 size:252195
+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:1187801 size:238567
+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: 179 size:240757
+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:12114692 size:254237
+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:5559218 size:247341
+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:9572227 size:254219
+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:2870233 size:242377
+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/vsynth2-flv b/tests/ref/seek/vsynth2-flv
index 9542a31..d4aecda 100644
--- a/tests/ref/seek/vsynth2-flv
+++ b/tests/ref/seek/vsynth2-flv
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size: 10380
+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: 179 size: 10380
+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: 83220 size: 12295
+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: 52565 size: 11127
+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: 83220 size: 12295
+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: 25940 size: 10089
+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: 52565 size: 11127
+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: 179 size: 10380
+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: 117138 size: 12730
+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: 117138 size: 12730
+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: 25940 size: 10089
+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: 179 size: 10380
+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: 117138 size: 12730
+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: 83220 size: 12295
+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: 179 size: 10380
+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: 179 size: 10380
+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: 117138 size: 12730
+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: 52565 size: 11127
+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: 83220 size: 12295
+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: 25940 size: 10089
+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/vsynth2-h261 b/tests/ref/seek/vsynth2-h261
index 1789adc..48ee00f 100644
--- a/tests/ref/seek/vsynth2-h261
+++ b/tests/ref/seek/vsynth2-h261
@@ -2,45 +2,45 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9645
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9645
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 126502 size: 11377
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 126494 size: 11377
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 82060 size: 10322
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 82052 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: 126502 size: 11377
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 126494 size: 11377
ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 44666 size: 9404
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 44664 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: 82060 size: 10322
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 82052 size: 10322
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9645
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 175870 size: 11707
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 175856 size: 11707
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 175870 size: 11707
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 175856 size: 11707
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 44666 size: 9404
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 44664 size: 9404
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9645
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 175870 size: 11707
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 175856 size: 11707
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 126502 size: 11377
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 126494 size: 11377
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9645
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9645
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 175870 size: 11707
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 175856 size: 11707
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 82060 size: 10322
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 82052 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: 126502 size: 11377
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 126494 size: 11377
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 44666 size: 9404
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 44664 size: 9404
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-h263 b/tests/ref/seek/vsynth2-h263
index b92074f..6b7df48 100644
--- a/tests/ref/seek/vsynth2-h263
+++ b/tests/ref/seek/vsynth2-h263
@@ -18,15 +18,15 @@ ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 66792 size: 11128
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10381
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 144546 size: 12731
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 144552 size: 12731
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 144546 size: 12731
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 144552 size: 12731
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 36438 size: 10090
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10381
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 144546 size: 12731
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 144552 size: 12731
ret: 0 st:-1 flags:0 ts: 1.306672
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 103702 size: 12296
ret: 0 st:-1 flags:1 ts: 0.200839
@@ -34,7 +34,7 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10381
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10381
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 144546 size: 12731
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 144552 size: 12731
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 66792 size: 11128
ret:-1 st:-1 flags:1 ts:-0.222493
diff --git a/tests/ref/seek/vsynth2-h263p b/tests/ref/seek/vsynth2-h263p
index 9d842a6..7dd4852 100644
--- a/tests/ref/seek/vsynth2-h263p
+++ b/tests/ref/seek/vsynth2-h263p
@@ -2,45 +2,45 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 36208
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 36208
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 569926 size: 45151
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 569918 size: 45151
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 355976 size: 40907
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 355968 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: 569926 size: 45151
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 569918 size: 45151
ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 171042 size: 36515
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 171042 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: 355976 size: 40907
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 355968 size: 40907
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 36208
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 804366 size: 46411
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 804358 size: 46411
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 804366 size: 46411
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 804358 size: 46411
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 171042 size: 36515
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 171042 size: 36514
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 36208
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 804366 size: 46411
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 804358 size: 46411
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 569926 size: 45151
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 569918 size: 45151
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 36208
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 36208
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 804366 size: 46411
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 804358 size: 46411
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 355976 size: 40907
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 355968 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: 569926 size: 45151
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 569918 size: 45151
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 171042 size: 36515
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 171042 size: 36514
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-huffyuv b/tests/ref/seek/vsynth2-huffyuv
index 69a37f5..ad01899 100644
--- a/tests/ref/seek/vsynth2-huffyuv
+++ b/tests/ref/seek/vsynth2-huffyuv
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5724 size:129760
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5754 size:123508
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5724 size:129760
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5754 size:123508
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:6069172 size:128520
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:5744998 size:121152
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:2579612 size:129192
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:2437994 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:4778228 size:129424
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:4523454 size:122784
ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1160248 size:128504
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1093870 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:3355284 size:129424
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:3173590 size:122784
ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5724 size:129760
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5754 size:123508
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:6326124 size:128288
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:5987030 size:120672
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:5553996 size:129016
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:5258650 size:121992
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:2062492 size:129204
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:1947350 size:122568
ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5724 size:129760
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5754 size:123508
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:6326124 size:128288
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:5987030 size:120672
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:4260860 size:129280
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:4032694 size:122544
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 646908 size:128204
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 609906 size:120724
ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5724 size:129760
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5754 size:123508
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:6326124 size:128288
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:5987030 size:120672
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:2838068 size:129268
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:2683062 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:5037024 size:129284
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:4768978 size:122556
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1546172 size:128860
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1458406 size:121888
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-ljpeg b/tests/ref/seek/vsynth2-ljpeg
index 92264c9..1ca1441 100644
--- a/tests/ref/seek/vsynth2-ljpeg
+++ b/tests/ref/seek/vsynth2-ljpeg
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 96069
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 96000
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 96069
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 96000
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:4481864 size: 94870
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:4478624 size: 94801
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:1902318 size: 95465
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:1900940 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:3527724 size: 95724
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:3525172 size: 95655
ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 854944 size: 94635
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 854322 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:2475566 size: 95649
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:2473776 size: 95580
ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 96069
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 96000
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:4671498 size: 94595
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:4668120 size: 94526
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:4101338 size: 95353
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:4098374 size: 95284
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:1520284 size: 95410
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:1519182 size: 95341
ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 96069
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 96000
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:4671498 size: 94595
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:4668120 size: 94526
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:3145114 size: 95587
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:3142838 size: 95518
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 477226 size: 94261
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 476880 size: 94192
ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 96069
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 96000
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:4671498 size: 94595
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:4668120 size: 94526
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:2093302 size: 95528
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:2091786 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:3719126 size: 95615
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:3716438 size: 95546
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1139238 size: 95032
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1138408 size: 94963
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mjpeg b/tests/ref/seek/vsynth2-mjpeg
index 59db09a..c1395a9 100644
--- a/tests/ref/seek/vsynth2-mjpeg
+++ b/tests/ref/seek/vsynth2-mjpeg
@@ -2,45 +2,45 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 12096
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 12096
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: 627854 size: 14811
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: 627814 size: 14806
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: 247488 size: 12959
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: 247498 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: 480758 size: 14528
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos: 480736 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: 11927
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 110996 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: 326672 size: 13489
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos: 326680 size: 13491
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 12096
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 657522 size: 14881
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 657468 size: 14897
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: 568652 size: 14746
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: 568606 size: 14751
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: 196416 size: 12719
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: 196420 size: 12720
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 12096
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 657522 size: 14881
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 657468 size: 14897
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: 423482 size: 14119
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: 423470 size: 14114
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 63860 size: 11714
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 63862 size: 11715
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 12096
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 657522 size: 14881
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 657468 size: 14897
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: 273508 size: 13131
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: 273512 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: 509926 size: 14597
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos: 509892 size: 14594
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146958 size: 12168
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146950 size: 12173
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg1 b/tests/ref/seek/vsynth2-mpeg1
index a85055a..0ec751a 100644
--- a/tests/ref/seek/vsynth2-mpeg1
+++ b/tests/ref/seek/vsynth2-mpeg1
@@ -2,45 +2,45 @@ 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: 124245 size: 11796
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 76694 size: 10792
-ret:-1 st: 0 flags:1 ts:-0.320000
+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: 124245 size: 11796
-ret: 0 st: 0 flags:0 ts: 0.360000
+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.760000
+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: 76694 size: 10792
-ret: 0 st: 0 flags:0 ts:-0.040000
+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.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 177089 size: 12057
+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: 177089 size: 12057
+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.480000
+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.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 177089 size: 12057
+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: 124245 size: 11796
+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.920000
+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: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 177089 size: 12057
+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: 76694 size: 10792
+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.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 124245 size: 11796
+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/vsynth2-mpeg1b b/tests/ref/seek/vsynth2-mpeg1b
index 3b0b084..e079e34 100644
--- a/tests/ref/seek/vsynth2-mpeg1b
+++ b/tests/ref/seek/vsynth2-mpeg1b
@@ -2,44 +2,44 @@ 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: 194420 size: 14837
-ret: 0 st: 0 flags:0 ts: 0.800000
+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.320000
+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.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: NOPTS pos: 34797 size: 12009
-ret:-1 st: 0 flags:1 ts:-0.760000
+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.040000
+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.840000
-ret: 0 st: 0 flags:1 dts: 1.800000 pts: NOPTS pos: 194420 size: 14837
+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: 194420 size: 14837
+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.480000
+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.400000
-ret: 0 st: 0 flags:1 dts: 1.800000 pts: NOPTS pos: 194420 size: 14837
+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.920000
+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: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.800000 pts: NOPTS pos: 194420 size: 14837
+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.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
+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
diff --git a/tests/ref/seek/vsynth2-mpeg2-422 b/tests/ref/seek/vsynth2-mpeg2-422
index f07a93c..06d8f7a 100644
--- a/tests/ref/seek/vsynth2-mpeg2-422
+++ b/tests/ref/seek/vsynth2-mpeg2-422
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17509
+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: 17509
+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: 325187 size: 19948
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 200760 size: 22587
-ret:-1 st: 0 flags:1 ts:-0.320000
+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: 265500 size: 21341
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 104466 size: 28996
-ret:-1 st: 0 flags:1 ts:-0.760000
+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: 200760 size: 22587
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17509
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 325187 size: 19948
+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: 325187 size: 19948
+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: 104466 size: 28996
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17509
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 325187 size: 19948
+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: 265500 size: 21341
+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: 17509
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17509
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 325187 size: 19948
+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: 0.880000 pts: NOPTS pos: 200760 size: 22587
+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.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 265500 size: 21341
+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: 200760 size: 22587
+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/vsynth2-mpeg2-idct-int b/tests/ref/seek/vsynth2-mpeg2-idct-int
index 8086c9c..b096f6f 100644
--- a/tests/ref/seek/vsynth2-mpeg2-idct-int
+++ b/tests/ref/seek/vsynth2-mpeg2-idct-int
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9923
+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: 9923
+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: 127961 size: 11930
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 79127 size: 10921
-ret:-1 st: 0 flags:1 ts:-0.320000
+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: 127961 size: 11930
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 39004 size: 9997
-ret:-1 st: 0 flags:1 ts:-0.760000
+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: 79127 size: 10921
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9923
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 182186 size: 12195
+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: 182186 size: 12195
+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: 39004 size: 9997
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9923
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 182186 size: 12195
+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: 127961 size: 11930
+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: 9923
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9923
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 182186 size: 12195
+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: 79127 size: 10921
+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.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 127961 size: 11930
+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: 39004 size: 9997
+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/vsynth2-mpeg2-ilace b/tests/ref/seek/vsynth2-mpeg2-ilace
index 824f8ad..d2a7838 100644
--- a/tests/ref/seek/vsynth2-mpeg2-ilace
+++ b/tests/ref/seek/vsynth2-mpeg2-ilace
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9973
+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: 9973
+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: 132643 size: 11982
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 82176 size: 10977
-ret:-1 st: 0 flags:1 ts:-0.320000
+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: 132643 size: 11982
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 40558 size: 10057
-ret:-1 st: 0 flags:1 ts:-0.760000
+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: 82176 size: 10977
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9973
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 188477 size: 12244
+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: 188477 size: 12244
+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: 40558 size: 10057
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9973
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 188477 size: 12244
+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: 132643 size: 11982
+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: 9973
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9973
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 188477 size: 12244
+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: 82176 size: 10977
+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.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 132643 size: 11982
+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: 40558 size: 10057
+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/vsynth2-mpeg2-ivlc-qprd b/tests/ref/seek/vsynth2-mpeg2-ivlc-qprd
index a65dee8..330dc16 100644
--- a/tests/ref/seek/vsynth2-mpeg2-ivlc-qprd
+++ b/tests/ref/seek/vsynth2-mpeg2-ivlc-qprd
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 16251
+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: 16251
+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: 227553 size: 12737
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 164191 size: 13933
-ret:-1 st: 0 flags:1 ts:-0.320000
+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: 196718 size: 13170
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 98760 size: 29177
-ret:-1 st: 0 flags:1 ts:-0.760000
+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: 164191 size: 13933
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 16251
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 227553 size: 12737
+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: 227553 size: 12737
+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: 98760 size: 29177
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 16251
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 227553 size: 12737
+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: 196718 size: 13170
+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: 16251
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 16251
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 227553 size: 12737
+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: 0.880000 pts: NOPTS pos: 164191 size: 13933
+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.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 196718 size: 13170
+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: 164191 size: 13933
+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/vsynth2-mpeg2-thread b/tests/ref/seek/vsynth2-mpeg2-thread
index d66fd87..8e16f43 100644
--- a/tests/ref/seek/vsynth2-mpeg2-thread
+++ b/tests/ref/seek/vsynth2-mpeg2-thread
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9973
+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: 9973
+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: 158273 size: 12244
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 67814 size: 10977
-ret:-1 st: 0 flags:1 ts:-0.320000
+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: 110366 size: 11982
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 30759 size: 10057
-ret:-1 st: 0 flags:1 ts:-0.760000
+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: 67814 size: 10977
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9973
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 158273 size: 12244
+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: 158273 size: 12244
+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: 30759 size: 10057
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9973
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 158273 size: 12244
+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: 110366 size: 11982
+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: 9973
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9973
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 158273 size: 12244
+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: 0.880000 pts: NOPTS pos: 67814 size: 10977
+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.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 110366 size: 11982
+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: 67814 size: 10977
+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/vsynth2-mpeg2-thread-ivlc b/tests/ref/seek/vsynth2-mpeg2-thread-ivlc
index 6f6ff7a..49ec819 100644
--- a/tests/ref/seek/vsynth2-mpeg2-thread-ivlc
+++ b/tests/ref/seek/vsynth2-mpeg2-thread-ivlc
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9966
+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: 9966
+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: 157726 size: 11942
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 67747 size: 10803
-ret:-1 st: 0 flags:1 ts:-0.320000
+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: 110116 size: 11709
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 30756 size: 9992
-ret:-1 st: 0 flags:1 ts:-0.760000
+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: 67747 size: 10803
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9966
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 157726 size: 11942
+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: 157726 size: 11942
+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: 30756 size: 9992
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9966
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 157726 size: 11942
+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: 110116 size: 11709
+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: 9966
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9966
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 157726 size: 11942
+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: 0.880000 pts: NOPTS pos: 67747 size: 10803
+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.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 110116 size: 11709
+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: 67747 size: 10803
+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/vsynth2-mpeg4 b/tests/ref/seek/vsynth2-mpeg4
index 0600ed0..b1c8a19 100644
--- a/tests/ref/seek/vsynth2-mpeg4
+++ b/tests/ref/seek/vsynth2-mpeg4
@@ -3,46 +3,46 @@ 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.800000
+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.320000
+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.360000
+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.760000
+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.040000
+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.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 106167 size: 11182
+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: 106167 size: 11182
+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.480000
+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.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 106167 size: 11182
+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.920000
+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: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 106167 size: 11182
+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.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
+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
diff --git a/tests/ref/seek/vsynth2-mpeg4-adap b/tests/ref/seek/vsynth2-mpeg4-adap
index 87b80cc..cb6beee 100644
--- a/tests/ref/seek/vsynth2-mpeg4-adap
+++ b/tests/ref/seek/vsynth2-mpeg4-adap
@@ -2,13 +2,13 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 6855
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 6855
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174444 size: 16883
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174442 size: 16883
ret: 0 st: 0 flags:0 ts: 0.800000
ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 98216 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: 135586 size: 17525
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 135578 size: 17525
ret: 0 st: 0 flags:0 ts: 0.360000
ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 59442 size: 17261
ret:-1 st: 0 flags:1 ts:-0.760000
@@ -18,29 +18,29 @@ ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 98216 size: 17063
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 6855
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174444 size: 16883
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174442 size: 16883
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174444 size: 16883
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174442 size: 16883
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 59442 size: 17261
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 6855
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174444 size: 16883
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174442 size: 16883
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 135586 size: 17525
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 135578 size: 17525
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 6855
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 6855
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174444 size: 16883
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174442 size: 16883
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 98216 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: 135586 size: 17525
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 135578 size: 17525
ret: 0 st:-1 flags:0 ts: 0.460008
ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 98216 size: 17063
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
index 322bcab..e31df5d 100644
--- a/tests/ref/seek/vsynth2-mpeg4-error
+++ b/tests/ref/seek/vsynth2-mpeg4-error
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9564
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9729
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9564
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9729
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 113130 size: 12795
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 113182 size: 15063
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 71648 size: 11680
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 73142 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: 113130 size: 12795
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 113182 size: 15063
ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 36770 size: 10310
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 38228 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: 71648 size: 11680
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 73142 size: 10235
ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9564
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9729
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 159358 size: 13895
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 163064 size: 13980
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 159358 size: 13895
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 163064 size: 13980
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 36770 size: 10310
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 38228 size: 10303
ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9564
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9729
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 159358 size: 13895
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 163064 size: 13980
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 113130 size: 12795
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 113182 size: 15063
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9564
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9729
ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9564
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9729
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 159358 size: 13895
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 163064 size: 13980
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 71648 size: 11680
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 73142 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: 113130 size: 12795
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 113182 size: 15063
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 36770 size: 10310
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 38228 size: 10303
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
index 5273ae1..3d6b5ce 100644
--- a/tests/ref/seek/vsynth2-mpeg4-nr
+++ b/tests/ref/seek/vsynth2-mpeg4-nr
@@ -2,45 +2,45 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10673
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10673
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 100628 size: 12464
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 100652 size: 12464
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 65468 size: 11181
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 65488 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: 100628 size: 12464
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 100652 size: 12464
ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35300 size: 9987
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35310 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: 65468 size: 11181
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 65488 size: 11180
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10673
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139412 size: 12911
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139372 size: 12911
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139412 size: 12911
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139372 size: 12911
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35300 size: 9987
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35310 size: 9987
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10673
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139412 size: 12911
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139372 size: 12911
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 100628 size: 12464
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 100652 size: 12464
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10673
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10673
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139412 size: 12911
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139372 size: 12911
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 65468 size: 11181
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 65488 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: 100628 size: 12464
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 100652 size: 12464
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35300 size: 9987
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35310 size: 9987
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg4-nsse b/tests/ref/seek/vsynth2-mpeg4-nsse
new file mode 100644
index 0000000..8e2a95f
--- /dev/null
+++ b/tests/ref/seek/vsynth2-mpeg4-nsse
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11937
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11937
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 127872 size: 15054
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 81652 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: 127872 size: 15054
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 42638 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: 81652 size: 13376
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11937
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 179512 size: 15553
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 179512 size: 15553
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 42638 size: 11805
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11937
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 179512 size: 15553
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 127872 size: 15054
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11937
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11937
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 179512 size: 15553
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 81652 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: 127872 size: 15054
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 42638 size: 11805
+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
index 195fb30..cd6eaf0 100644
--- a/tests/ref/seek/vsynth2-mpeg4-qpel
+++ b/tests/ref/seek/vsynth2-mpeg4-qpel
@@ -1,46 +1,46 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 11942
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 11938
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 11942
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 11938
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141518 size: 15562
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141526 size: 15554
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 64104 size: 13382
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 64110 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: 100356 size: 15057
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 100336 size: 15055
ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 32806 size: 11813
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 32836 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: 64104 size: 13382
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 64110 size: 13377
ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 11942
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 11938
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141518 size: 15562
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141526 size: 15554
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141518 size: 15562
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141526 size: 15554
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 32806 size: 11813
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 32836 size: 11806
ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 11942
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 11938
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141518 size: 15562
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141526 size: 15554
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 100356 size: 15057
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 100336 size: 15055
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 11942
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 11938
ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 11942
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 11938
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141518 size: 15562
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141526 size: 15554
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 64104 size: 13382
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 64110 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: 100356 size: 15057
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 100336 size: 15055
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 64104 size: 13382
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 64110 size: 13377
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
index 4c3c7f5..74aee79 100644
--- a/tests/ref/seek/vsynth2-mpeg4-qprd
+++ b/tests/ref/seek/vsynth2-mpeg4-qprd
@@ -2,13 +2,13 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 14873
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 14873
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211020 size: 14638
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211030 size: 14638
ret: 0 st: 0 flags:0 ts: 0.800000
ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 150654 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: 180770 size: 14371
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180778 size: 14371
ret: 0 st: 0 flags:0 ts: 0.360000
ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 93024 size: 29366
ret:-1 st: 0 flags:1 ts:-0.760000
@@ -18,29 +18,29 @@ ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 150654 size: 14502
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 14873
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211020 size: 14638
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211030 size: 14638
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211020 size: 14638
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211030 size: 14638
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 93024 size: 29366
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 14873
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211020 size: 14638
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211030 size: 14638
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180770 size: 14371
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180778 size: 14371
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 14873
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 14873
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211020 size: 14638
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211030 size: 14638
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 150654 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: 180770 size: 14371
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180778 size: 14371
ret: 0 st:-1 flags:0 ts: 0.460008
ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 150654 size: 14502
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
index 5c96c78..6bcfd48 100644
--- a/tests/ref/seek/vsynth2-mpeg4-rc
+++ b/tests/ref/seek/vsynth2-mpeg4-rc
@@ -2,45 +2,45 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 15766
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 15766
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207956 size: 13826
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207950 size: 13826
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 153800 size: 13382
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 153784 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: 180948 size: 13326
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180946 size: 13326
ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 94582 size: 32807
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 94574 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: 153800 size: 13382
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 153784 size: 13377
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 15766
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207956 size: 13826
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207950 size: 13826
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207956 size: 13826
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207950 size: 13826
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 94582 size: 32807
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 94574 size: 32807
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 15766
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207956 size: 13826
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207950 size: 13826
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180948 size: 13326
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180946 size: 13326
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 15766
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 15766
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207956 size: 13826
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207950 size: 13826
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 153800 size: 13382
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 153784 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: 180948 size: 13326
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180946 size: 13326
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 153800 size: 13382
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 153784 size: 13377
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
index 8c4f663..ca849f3 100644
--- a/tests/ref/seek/vsynth2-mpeg4-thread
+++ b/tests/ref/seek/vsynth2-mpeg4-thread
@@ -2,45 +2,45 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 14874
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 14874
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228210 size: 16324
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228186 size: 16323
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 162150 size: 16475
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 162156 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: 195320 size: 16136
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 195330 size: 16153
ret: 0 st: 0 flags:0 ts: 0.360000
ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 97832 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: 162150 size: 16475
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 162156 size: 16462
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 14874
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228210 size: 16324
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228186 size: 16323
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228210 size: 16324
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228186 size: 16323
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 97832 size: 33332
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 14874
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228210 size: 16324
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228186 size: 16323
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 195320 size: 16136
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 195330 size: 16153
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 14874
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 14874
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228210 size: 16324
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228186 size: 16323
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 162150 size: 16475
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 162156 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: 195320 size: 16136
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 195330 size: 16153
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 162150 size: 16475
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 162156 size: 16462
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-msmpeg4 b/tests/ref/seek/vsynth2-msmpeg4
index 323f96a..e096f76 100644
--- a/tests/ref/seek/vsynth2-msmpeg4
+++ b/tests/ref/seek/vsynth2-msmpeg4
@@ -18,15 +18,15 @@ ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 53846 size: 9624
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 8637
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 114264 size: 11180
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 114256 size: 11180
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 114264 size: 11180
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 114256 size: 11180
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29388 size: 8502
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 8637
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 114264 size: 11180
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 114256 size: 11180
ret: 0 st:-1 flags:0 ts: 1.306672
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 82508 size: 10783
ret: 0 st:-1 flags:1 ts: 0.200839
@@ -34,7 +34,7 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 8637
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 8637
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 114264 size: 11180
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 114256 size: 11180
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 53846 size: 9624
ret:-1 st:-1 flags:1 ts:-0.222493
diff --git a/tests/ref/seek/vsynth2-msmpeg4v2 b/tests/ref/seek/vsynth2-msmpeg4v2
index 177898e..00a175d 100644
--- a/tests/ref/seek/vsynth2-msmpeg4v2
+++ b/tests/ref/seek/vsynth2-msmpeg4v2
@@ -18,15 +18,15 @@ ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54778 size: 10010
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9003
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116100 size: 11578
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116112 size: 11578
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116100 size: 11578
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116112 size: 11578
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29770 size: 8869
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9003
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116100 size: 11578
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116112 size: 11578
ret: 0 st:-1 flags:0 ts: 1.306672
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83870 size: 11165
ret: 0 st:-1 flags:1 ts: 0.200839
@@ -34,7 +34,7 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9003
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 9003
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116100 size: 11578
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116112 size: 11578
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54778 size: 10010
ret:-1 st:-1 flags:1 ts:-0.222493
diff --git a/tests/ref/seek/vsynth2-roqvideo b/tests/ref/seek/vsynth2-roqvideo
index d003a37..50a0a33 100644
--- a/tests/ref/seek/vsynth2-roqvideo
+++ b/tests/ref/seek/vsynth2-roqvideo
@@ -1,4 +1,4 @@
-ret: 0 st: 0 flags:0 dts: 0.000000 pts: 0.000000 pos: 24 size: 26082
+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
diff --git a/tests/ref/seek/vsynth2-rv10 b/tests/ref/seek/vsynth2-rv10
index 123b03c..818040d 100644
--- a/tests/ref/seek/vsynth2-rv10
+++ b/tests/ref/seek/vsynth2-rv10
@@ -1,14 +1,13 @@
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: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 98608 size: 12303
+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: 139556 size: 12738
+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
@@ -16,21 +15,21 @@ 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: 139556 size: 12738
+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: 139556 size: 12738
+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: 139556 size: 12738
+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: 139556 size: 12738
+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
@@ -38,13 +37,13 @@ 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: 139556 size: 12738
+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: 139556 size: 12738
+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
diff --git a/tests/ref/seek/vsynth2-rv20 b/tests/ref/seek/vsynth2-rv20
index f2b24e3..7f1ad39 100644
--- a/tests/ref/seek/vsynth2-rv20
+++ b/tests/ref/seek/vsynth2-rv20
@@ -8,7 +8,7 @@ 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: 139145 size: 11803
+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
@@ -16,21 +16,21 @@ 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: 139145 size: 11803
+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: 139145 size: 11803
+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: 139145 size: 11803
+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: 139145 size: 11803
+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
@@ -38,13 +38,13 @@ 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: 139145 size: 11803
+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: 139145 size: 11803
+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
diff --git a/tests/ref/seek/vsynth2-snow b/tests/ref/seek/vsynth2-snow
new file mode 100644
index 0000000..d8f5aae
--- /dev/null
+++ b/tests/ref/seek/vsynth2-snow
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39714 size: 3640
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 27434 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: 39714 size: 3640
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 16124 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: 27434 size: 3494
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52604 size: 3582
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52604 size: 3582
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 16124 size: 3244
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52604 size: 3582
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39714 size: 3640
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52604 size: 3582
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 27434 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: 39714 size: 3640
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 16124 size: 3244
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-snow-ll b/tests/ref/seek/vsynth2-snow-ll
new file mode 100644
index 0000000..95a4a79
--- /dev/null
+++ b/tests/ref/seek/vsynth2-snow-ll
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902788 size: 78837
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1239090 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:1902788 size: 78837
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 605628 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:1239090 size: 74994
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585614 size: 79731
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585614 size: 79731
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 605628 size: 71059
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585614 size: 79731
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902788 size: 78837
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585614 size: 79731
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1239090 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:1902788 size: 78837
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 605628 size: 71059
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-svq1 b/tests/ref/seek/vsynth2-svq1
index 17bb99e..33fe33e 100644
--- a/tests/ref/seek/vsynth2-svq1
+++ b/tests/ref/seek/vsynth2-svq1
@@ -3,46 +3,46 @@ 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.800000
+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.320000
+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.360000
+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.760000
+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.040000
+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.840000
+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.480000
+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.400000
+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.920000
+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: 2.000000
+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.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
+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
diff --git a/tests/ref/seek/vsynth2-wmv1 b/tests/ref/seek/vsynth2-wmv1
index 85465b3..0f073b2 100644
--- a/tests/ref/seek/vsynth2-wmv1
+++ b/tests/ref/seek/vsynth2-wmv1
@@ -18,15 +18,15 @@ ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54758 size: 9931
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 8990
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115812 size: 11487
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115806 size: 11486
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115812 size: 11487
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115806 size: 11486
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29794 size: 8796
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 8990
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115812 size: 11487
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115806 size: 11486
ret: 0 st:-1 flags:0 ts: 1.306672
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83742 size: 11099
ret: 0 st:-1 flags:1 ts: 0.200839
@@ -34,7 +34,7 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 8990
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 8990
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115812 size: 11487
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115806 size: 11486
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54758 size: 9931
ret:-1 st:-1 flags:1 ts:-0.222493
diff --git a/tests/ref/seek/vsynth2-wmv2 b/tests/ref/seek/vsynth2-wmv2
index 53680d0..a29f0d4 100644
--- a/tests/ref/seek/vsynth2-wmv2
+++ b/tests/ref/seek/vsynth2-wmv2
@@ -2,13 +2,13 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8917
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8917
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11170
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11169
ret: 0 st: 0 flags:0 ts: 0.800000
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54534 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: 83764 size: 11170
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11169
ret: 0 st: 0 flags:0 ts: 0.360000
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29588 size: 8839
ret:-1 st: 0 flags:1 ts:-0.760000
@@ -18,29 +18,29 @@ ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54534 size: 9989
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8917
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116062 size: 11554
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116066 size: 11554
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116062 size: 11554
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116066 size: 11554
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29588 size: 8839
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8917
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116062 size: 11554
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116066 size: 11554
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11170
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11169
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8917
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8917
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116062 size: 11554
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116066 size: 11554
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54534 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: 83764 size: 11170
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11169
ret: 0 st:-1 flags:0 ts: 0.460008
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29588 size: 8839
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 0000000..38a34b2
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-amv
@@ -0,0 +1,4 @@
+e3e6dcf69be5c598b4eae901034a80e2 *tests/data/fate/vsynth1-amv.avi
+1365496 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 e640f1c..445197a 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
+f446db5dfd6bcc14378bca9406e39adb *tests/data/fate/vsynth1-asv1.avi
+1298616 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 6282ad4..225712e 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
+06b7b65686a1eb03d43f25e179c03872 *tests/data/fate/vsynth1-asv2.avi
+1434408 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 0000000..53591e1
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-avui
@@ -0,0 +1,4 @@
+87ef06cbd15934c282d4aa83e2a5cf0a *tests/data/fate/vsynth1-avui.mov
+42624917 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-cljr b/tests/ref/vsynth/vsynth1-cljr
index cdd6ca2..58191a6 100644
--- a/tests/ref/vsynth/vsynth1-cljr
+++ b/tests/ref/vsynth/vsynth1-cljr
@@ -1,4 +1,4 @@
-41fc45d5e8bca3cf2be35457b188cdb3 *tests/data/fate/vsynth1-cljr.avi
+d04d90410c1936ec545e049cb7f0d1e9 *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
+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 8d396e8..f9b7e0e 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
+14f1ea20bbd3024ccbfd84c681888d07 *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-720p b/tests/ref/vsynth/vsynth1-dnxhd-720p
index 94c28ed..fd77e86 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 a667b9d..8a8f639 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 1de576a..0422776 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 0000000..f8f6df0
--- /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 f5a37ad..6237b07 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 a1f07da..48e01a1 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 18ee398..d5da88d 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 0000000..c45b593
--- /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 a162a77..dd11996 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
+7563e82e673db8ca60e79e7e725e174f *tests/data/fate/vsynth1-ffv1.avi
+2691264 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 0000000..346bde8
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffv1.0
@@ -0,0 +1,4 @@
+b9ce2f9781613d3380f7036d619af87b *tests/data/fate/vsynth1-ffv1.0.avi
+2655364 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 cf86f57..a8b9e41 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
+936c7cb29dc7b12a5db8a0217b3486b9 *tests/data/fate/vsynth1-ffvhuff.avi
+6809210 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 0000000..334c846
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffvhuff420p12
@@ -0,0 +1,4 @@
+571a999f4f0e5895be97d9240e036695 *tests/data/fate/vsynth1-ffvhuff420p12.avi
+14205352 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 0000000..0d88cdd
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffvhuff422p10left
@@ -0,0 +1,4 @@
+43705266ad32d9b98feb54d59c05b83e *tests/data/fate/vsynth1-ffvhuff422p10left.avi
+13860680 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 0000000..7c518f4
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffvhuff444
@@ -0,0 +1,4 @@
+962b03019d92658356eb7cdfad857d08 *tests/data/fate/vsynth1-ffvhuff444.avi
+11712338 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 0000000..76acffd
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffvhuff444p16
@@ -0,0 +1,4 @@
+9d7ab6d77fb4004512246c2f93f93c29 *tests/data/fate/vsynth1-ffvhuff444p16.avi
+24706272 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 a4f22ce..8b27830 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 0000000..a01ccbe
--- /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 a92658b..3a21e6a 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 b350e6f..52372d8 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
+364cc6703e90df30631dad52d1d9c909 *tests/data/fate/vsynth1-h261.avi
+707546 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 0000000..23fa231
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-h261-trellis
@@ -0,0 +1,4 @@
+a61e040bbbfc6875e6842ac066a5285b *tests/data/fate/vsynth1-h261-trellis.avi
+655412 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 d5916fa..a07c597 100644
--- a/tests/ref/vsynth/vsynth1-h263
+++ b/tests/ref/vsynth/vsynth1-h263
@@ -1,4 +1,4 @@
-130ae384b6f12fd7d18979aa5371523a *tests/data/fate/vsynth1-h263.avi
+3975fd5e232267fab6a5f8a5e095e3f9 *tests/data/fate/vsynth1-h263.avi
659674 tests/data/fate/vsynth1-h263.avi
-1a1ba9a3a63ec1a1a9585fded0a7c954 *tests/data/fate/vsynth1-h263.out.rawvideo
+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 ca3d4bf..ecb7a9a 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
+d66bfd3b2cd4bc59d8ec218391294266 *tests/data/fate/vsynth1-h263-obmc.avi
+657316 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 9e1765f..b96913d 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
+15a47620dcf88daaa71d4c679f620b47 *tests/data/fate/vsynth1-h263p.avi
+2328362 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 246da19..f747d9d 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
+b48b81b3bdd4e24834f9ada6f567b94e *tests/data/fate/vsynth1-huffyuv.avi
+8876470 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 0000000..c40ad0f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-huffyuvbgr24
@@ -0,0 +1,4 @@
+62748f420e76a0b26886f432074f89a1 *tests/data/fate/vsynth1-huffyuvbgr24.avi
+13196986 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 0000000..8578b81
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-huffyuvbgra
@@ -0,0 +1,4 @@
+0a441061598152cd44ddc308076671c3 *tests/data/fate/vsynth1-huffyuvbgra.avi
+14464166 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 0000000..a6a3e10
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-jpeg2000
@@ -0,0 +1,4 @@
+b526a22fcc4f710da181617ad06ec523 *tests/data/fate/vsynth1-jpeg2000.avi
+2306902 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 0000000..cd56149
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-jpeg2000-97
@@ -0,0 +1,4 @@
+397690bc9f6202c77ce3810640762ca3 *tests/data/fate/vsynth1-jpeg2000-97.avi
+2243132 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 b54bd5d..2e44308 100644
--- a/tests/ref/vsynth/vsynth1-jpegls
+++ b/tests/ref/vsynth/vsynth1-jpegls
@@ -1,4 +1,4 @@
-f8acf917e24ea6c9200f2cdf99744ca9 *tests/data/fate/vsynth1-jpegls.avi
+424107c7919713b422b8e982ae3e4319 *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
+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 702de39..99bfade 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
+24d72a5b4c0d3a49a30098369d56b1cc *tests/data/fate/vsynth1-ljpeg.avi
+6309478 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 3c6fb4b..63ad240 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
+c14acfb3472919caa50ed90125ab33a9 *tests/data/fate/vsynth1-mjpeg.avi
+1515902 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 0000000..3356dd3
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-mjpeg-422
@@ -0,0 +1,4 @@
+bcd2370d76f32b9eed7842685a04f29f *tests/data/fate/vsynth1-mjpeg-422.avi
+1756300 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 0000000..5ebf895
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-mjpeg-444
@@ -0,0 +1,4 @@
+f611f316df9b6890d6dcd3379691c36e *tests/data/fate/vsynth1-mjpeg-444.avi
+1989780 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-mpeg1 b/tests/ref/vsynth/vsynth1-mpeg1
index 5f3d703..902b201 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 ddd9bef..6d7afa4 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 d0baa0a..0f06f38 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 1209e88..e936ba4 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 cc789bb..89356d0 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 81e43c5..b9144b6 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 647525d..392f9bb 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 1a479bc..5f750b9 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 b211c94..618125c 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 38a7294..4e9b4bd 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 840eb47..a9d11b7 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
+82726c84fc7a0b464818bf6e83e0d2db *tests/data/fate/vsynth1-mpeg4-adap.avi
+403432 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 8ca1f2f..d1d921f 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
+8f6e6b9a8242a2342edab58c00900841 *tests/data/fate/vsynth1-mpeg4-adv.avi
589704 tests/data/fate/vsynth1-mpeg4-adv.avi
-f8b226876b1b2c0b98fd6928fd9adbd8 *tests/data/fate/vsynth1-mpeg4-adv.out.rawvideo
+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 9180911..3aafd4e 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
+6ea634d8b179098a3ec7f05af1e4a98d *tests/data/fate/vsynth1-mpeg4-error.avi
+752346 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 28f8c6a..a18eabc 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
+953407e0e1fd1c99e4b320065f69ad81 *tests/data/fate/vsynth1-mpeg4-nr.avi
+675452 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 0000000..a6065f9
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-mpeg4-nsse
@@ -0,0 +1,4 @@
+10fa4b9d835349220908b5ebde9a0e70 *tests/data/fate/vsynth1-mpeg4-nsse.avi
+886842 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 1ff1dce..ed53fed 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
+b49ff3a036fdb479404f80f1490c6330 *tests/data/fate/vsynth1-mpeg4-qpel.avi
+858680 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 0b2892d..307ff32 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
+1bcc031a67149a9650d7efb56952c5fa *tests/data/fate/vsynth1-mpeg4-qprd.avi
+710672 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 0c2abf3..f41b458 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
+e9ff13628bd5bd138a44f4d4815d8d09 *tests/data/fate/vsynth1-mpeg4-rc.avi
+830494 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 b0bf7d8..581897c 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
+fa47e87b4fac7ee7da58cf677d816567 *tests/data/fate/vsynth1-mpeg4-thread.avi
+774750 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 0000000..7c6b872
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-mpng
@@ -0,0 +1,4 @@
+a32e70b1079dff3af0fe1fc339fafce2 *tests/data/fate/vsynth1-mpng.avi
+12158276 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 cd1b6db..e0f3c2a 100644
--- a/tests/ref/vsynth/vsynth1-msmpeg4
+++ b/tests/ref/vsynth/vsynth1-msmpeg4
@@ -1,4 +1,4 @@
-c1d04df31764c0ca281dc6fe023287fb *tests/data/fate/vsynth1-msmpeg4.avi
-624706 tests/data/fate/vsynth1-msmpeg4.avi
-5ca72c39e3fc5df8e62f223c869589f5 *tests/data/fate/vsynth1-msmpeg4.out.rawvideo
+391863936d129fef45d855dd0fcf5b8a *tests/data/fate/vsynth1-msmpeg4.avi
+624702 tests/data/fate/vsynth1-msmpeg4.avi
+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 fb9862c..150bf30 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
+a1f1ad51642bd8394ea9ad7646d91b85 *tests/data/fate/vsynth1-msmpeg4v2.avi
+623766 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 0000000..dd87a21
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-msvideo1
@@ -0,0 +1,4 @@
+e017b7844d81f70cdd6aaad479d9462b *tests/data/fate/vsynth1-msvideo1.avi
+2051892 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 12aa758..14de8b9 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 0000000..6e5ed17
--- /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 4ddd1d8..4b92081 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 0000000..c3d571d
--- /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 0000000..477f1a5
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-r210
@@ -0,0 +1,4 @@
+7b674ea381bacc9abe3e3579f9df0e98 *tests/data/fate/vsynth1-r210.avi
+22125248 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 f72b737..5f43618 100644
--- a/tests/ref/vsynth/vsynth1-rgb
+++ b/tests/ref/vsynth/vsynth1-rgb
@@ -1,4 +1,4 @@
-d78bcd5828862c3342388ec8a2c34fef *tests/data/fate/vsynth1-rgb.avi
+a955310c1ad92f967fc4e3d38dc0ef91 *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
+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 5adba69..2cca942 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 234015f..d414bd6 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 abcc4a1..5b3310a 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 0000000..a3d7028
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-snow
@@ -0,0 +1,4 @@
+40c38c87f15a76745fcc1e1c59f80054 *tests/data/fate/vsynth1-snow.avi
+136076 tests/data/fate/vsynth1-snow.avi
+91021b7d6d7908648fe78cc1975af8c4 *tests/data/fate/vsynth1-snow.out.rawvideo
+stddev: 22.77 PSNR: 20.98 MAXDIFF: 172 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-snow-hpel b/tests/ref/vsynth/vsynth1-snow-hpel
new file mode 100644
index 0000000..5ef7de0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-snow-hpel
@@ -0,0 +1,4 @@
+6a91c3b8d05cbcc664e357539bd13269 *tests/data/fate/vsynth1-snow-hpel.avi
+138700 tests/data/fate/vsynth1-snow-hpel.avi
+d6845c8f1310e041afdcebc6bbfc449b *tests/data/fate/vsynth1-snow-hpel.out.rawvideo
+stddev: 22.74 PSNR: 20.99 MAXDIFF: 171 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-snow-ll b/tests/ref/vsynth/vsynth1-snow-ll
new file mode 100644
index 0000000..7cb8643
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-snow-ll
@@ -0,0 +1,4 @@
+ef9af2fa50b412301aeeaa1aeca09526 *tests/data/fate/vsynth1-snow-ll.avi
+3419968 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 f610fdc..9c1b6ff 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 defd2f6..dbafe42 100644
--- a/tests/ref/vsynth/vsynth1-v210
+++ b/tests/ref/vsynth/vsynth1-v210
@@ -1,4 +1,4 @@
-054d7e903fb4d9e68700c56b93d45916 *tests/data/fate/vsynth1-v210.avi
+895d30660eb4da017568141a8d1df4e8 *tests/data/fate/vsynth1-v210.avi
14752448 tests/data/fate/vsynth1-v210.avi
50973792d3f1abe04a51ee0121f077f2 *tests/data/fate/vsynth1-v210.out.rawvideo
stddev: 1.85 PSNR: 42.78 MAXDIFF: 29 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-v308 b/tests/ref/vsynth/vsynth1-v308
new file mode 100644
index 0000000..45b20ed
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-v308
@@ -0,0 +1,4 @@
+b1d7f4300e69fc8995188f73b7680481 *tests/data/fate/vsynth1-v308.avi
+15213248 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 0000000..e5970e1
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-v408
@@ -0,0 +1,4 @@
+c14aa9857a0ff73130a9fb11cf738c73 *tests/data/fate/vsynth1-v408.avi
+20282048 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 78bd0f0..1759ec1 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
+76024303a316ffe69b4357b220eafc4a *tests/data/fate/vsynth1-wmv1.avi
+626870 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 6a3cd3b..75d3e22 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
+818ade4e037d5db8c10f6bce727faec6 *tests/data/fate/vsynth1-wmv2.avi
+659138 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-y41p b/tests/ref/vsynth/vsynth1-y41p
new file mode 100644
index 0000000..6b5b08c
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-y41p
@@ -0,0 +1,4 @@
+1441e4ca15d9fb1d6b2901cac7938e7f *tests/data/fate/vsynth1-y41p.avi
+7610048 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 3db5ab0..3648e69 100644
--- a/tests/ref/vsynth/vsynth1-yuv
+++ b/tests/ref/vsynth/vsynth1-yuv
@@ -1,4 +1,4 @@
-a9c708ba20f5c562fb1c89f6aa841c8c *tests/data/fate/vsynth1-yuv.avi
+79738c86c951f7b2f061b3cb238989b0 *tests/data/fate/vsynth1-yuv.avi
7610048 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 0000000..dc79810
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-yuv4
@@ -0,0 +1,4 @@
+7fe85091535c7f7db31f9aaa00388d9a *tests/data/fate/vsynth1-yuv4.avi
+7610048 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 0000000..9ed0aed
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-zlib
@@ -0,0 +1,4 @@
+18a22e378a1a5961663fe76925fee271 *tests/data/fate/vsynth1-zlib.avi
+12108632 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 0000000..c608c4b
--- /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 0000000..daa5894
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-amv
@@ -0,0 +1,4 @@
+e0d0da8cf786616eff2e88c45644c902 *tests/data/fate/vsynth2-amv.avi
+761976 tests/data/fate/vsynth2-amv.avi
+f256ad9feefb499c6569d06d868eb496 *tests/data/fate/vsynth2-amv.out.rawvideo
+stddev: 4.30 PSNR: 35.46 MAXDIFF: 65 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-asv1 b/tests/ref/vsynth/vsynth2-asv1
index 282435b..7811888 100644
--- a/tests/ref/vsynth/vsynth2-asv1
+++ b/tests/ref/vsynth/vsynth2-asv1
@@ -1,4 +1,4 @@
-ae8d79e0e421138a9a67a148a42c26c5 *tests/data/fate/vsynth2-asv1.avi
-832500 tests/data/fate/vsynth2-asv1.avi
-c96ff7fd17c52f99ddb7922a4cb9168f *tests/data/fate/vsynth2-asv1.out.rawvideo
-stddev: 10.47 PSNR: 27.73 MAXDIFF: 98 bytes: 7603200/ 7603200
+bffe7188b4b5c3ff76c75561d0bebd77 *tests/data/fate/vsynth2-asv1.avi
+689416 tests/data/fate/vsynth2-asv1.avi
+a7cdefad200f48ab308c746461a8792e *tests/data/fate/vsynth2-asv1.out.rawvideo
+stddev: 5.07 PSNR: 34.03 MAXDIFF: 70 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-asv2 b/tests/ref/vsynth/vsynth2-asv2
index 8942862..617a77f 100644
--- a/tests/ref/vsynth/vsynth2-asv2
+++ b/tests/ref/vsynth/vsynth2-asv2
@@ -1,4 +1,4 @@
-ccf6762758395eee9a29ef7a4ef3cd58 *tests/data/fate/vsynth2-asv2.avi
-789060 tests/data/fate/vsynth2-asv2.avi
-74a78015b64b2cf8cb9da2e44f508a69 *tests/data/fate/vsynth2-asv2.out.rawvideo
-stddev: 10.28 PSNR: 27.89 MAXDIFF: 95 bytes: 7603200/ 7603200
+f8c3b9899bbd9545757fac0c7ecf4e34 *tests/data/fate/vsynth2-asv2.avi
+675584 tests/data/fate/vsynth2-asv2.avi
+5990db66c7ac0bbe2f98ec2770c1bf3b *tests/data/fate/vsynth2-asv2.out.rawvideo
+stddev: 4.57 PSNR: 34.93 MAXDIFF: 47 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-avui b/tests/ref/vsynth/vsynth2-avui
new file mode 100644
index 0000000..7976a36
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-avui
@@ -0,0 +1,4 @@
+df5efcfd2170df82e466be4deb7ce4a9 *tests/data/fate/vsynth2-avui.mov
+42624917 tests/data/fate/vsynth2-avui.mov
+dde5895817ad9d219f79a52d0bdfb001 *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-cljr b/tests/ref/vsynth/vsynth2-cljr
index 39c74c3..0b61365 100644
--- a/tests/ref/vsynth/vsynth2-cljr
+++ b/tests/ref/vsynth/vsynth2-cljr
@@ -1,4 +1,4 @@
-5745ff1d80a6f454ae448dcf0bce50e0 *tests/data/fate/vsynth2-cljr.avi
+7bfd989038611212a80b5b050bb78ea7 *tests/data/fate/vsynth2-cljr.avi
5075648 tests/data/fate/vsynth2-cljr.avi
-cfe7802bf34aafed7df5dcaa5126ef23 *tests/data/fate/vsynth2-cljr.out.rawvideo
-stddev: 3.69 PSNR: 36.78 MAXDIFF: 22 bytes: 7603200/ 7603200
+965c4a134144b30b24d6d138b03ddb8c *tests/data/fate/vsynth2-cljr.out.rawvideo
+stddev: 3.29 PSNR: 37.76 MAXDIFF: 23 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-dnxhd-1080i b/tests/ref/vsynth/vsynth2-dnxhd-1080i
index 35db6d2..d3cf503 100644
--- a/tests/ref/vsynth/vsynth2-dnxhd-1080i
+++ b/tests/ref/vsynth/vsynth2-dnxhd-1080i
@@ -1,4 +1,4 @@
-c456f2a7ac9435ea5bfea86bc69c1c41 *tests/data/fate/vsynth2-dnxhd-1080i.mov
-3031875 tests/data/fate/vsynth2-dnxhd-1080i.mov
-42262a2325441b38b3b3c8a42d888e7d *tests/data/fate/vsynth2-dnxhd-1080i.out.rawvideo
+d680a5eed77c5b8dc6b5ef3bcf6e87e8 *tests/data/fate/vsynth2-dnxhd-1080i.mov
+3031911 tests/data/fate/vsynth2-dnxhd-1080i.mov
+744ba46da5d4c19a28562ea31061d170 *tests/data/fate/vsynth2-dnxhd-1080i.out.rawvideo
stddev: 1.31 PSNR: 45.77 MAXDIFF: 23 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth2-dnxhd-720p b/tests/ref/vsynth/vsynth2-dnxhd-720p
index afc6fde..0a8441b 100644
--- a/tests/ref/vsynth/vsynth2-dnxhd-720p
+++ b/tests/ref/vsynth/vsynth2-dnxhd-720p
@@ -1,4 +1,4 @@
-58e07cc6ae0a2d36787044d0e82708a6 *tests/data/fate/vsynth2-dnxhd-720p.dnxhd
+4ca9473a8d106bdfe36e9bf7c516b648 *tests/data/fate/vsynth2-dnxhd-720p.dnxhd
2293760 tests/data/fate/vsynth2-dnxhd-720p.dnxhd
-ab601eaafef74d80d3d20b780dddd836 *tests/data/fate/vsynth2-dnxhd-720p.out.rawvideo
-stddev: 1.36 PSNR: 45.45 MAXDIFF: 127 bytes: 7603200/ 760320
+d44c4b08cda8a8042ae345124fdfffcc *tests/data/fate/vsynth2-dnxhd-720p.out.rawvideo
+stddev: 1.32 PSNR: 45.68 MAXDIFF: 22 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth2-dnxhd-720p-10bit b/tests/ref/vsynth/vsynth2-dnxhd-720p-10bit
index f087c13..7a32d8c 100644
--- a/tests/ref/vsynth/vsynth2-dnxhd-720p-10bit
+++ b/tests/ref/vsynth/vsynth2-dnxhd-720p-10bit
@@ -1,4 +1,4 @@
-4b57da2c0c1280469ff3579f7151c227 *tests/data/fate/vsynth2-dnxhd-720p-10bit.dnxhd
+e96fc4a7d994b9369c50da32fd325822 *tests/data/fate/vsynth2-dnxhd-720p-10bit.dnxhd
2293760 tests/data/fate/vsynth2-dnxhd-720p-10bit.dnxhd
-31a6aa8b8702e85fa3b48e73f035c4e4 *tests/data/fate/vsynth2-dnxhd-720p-10bit.out.rawvideo
-stddev: 1.35 PSNR: 45.46 MAXDIFF: 23 bytes: 7603200/ 760320
+0449440eb3e8416840a27deb1a8f80b0 *tests/data/fate/vsynth2-dnxhd-720p-10bit.out.rawvideo
+stddev: 1.35 PSNR: 45.47 MAXDIFF: 22 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth2-dnxhd-720p-rd b/tests/ref/vsynth/vsynth2-dnxhd-720p-rd
index c1b8f96..5387ce5 100644
--- a/tests/ref/vsynth/vsynth2-dnxhd-720p-rd
+++ b/tests/ref/vsynth/vsynth2-dnxhd-720p-rd
@@ -1,4 +1,4 @@
-092ffb7b8cf3c11556bb05dbb8b476ac *tests/data/fate/vsynth2-dnxhd-720p-rd.dnxhd
+b305b03708e905717b42fc0b304367d4 *tests/data/fate/vsynth2-dnxhd-720p-rd.dnxhd
2293760 tests/data/fate/vsynth2-dnxhd-720p-rd.dnxhd
-33547ca318acff9448cba719cb99296d *tests/data/fate/vsynth2-dnxhd-720p-rd.out.rawvideo
+13de1c5ed025abb5120450e134aa623d *tests/data/fate/vsynth2-dnxhd-720p-rd.out.rawvideo
stddev: 1.32 PSNR: 45.66 MAXDIFF: 22 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth2-dnxhd_1080i b/tests/ref/vsynth/vsynth2-dnxhd_1080i
new file mode 100644
index 0000000..81ecc5e
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-dnxhd_1080i
@@ -0,0 +1,4 @@
+204e80f2e406ada90fca596ab2810b3e *./tests/data/vsynth2/dnxhd-1080i.mov
+3031911 ./tests/data/vsynth2/dnxhd-1080i.mov
+3c559af629ae0a8fb1a9a0e4b4da7733 *./tests/data/dnxhd_1080i.vsynth2.out.yuv
+stddev: 1.31 PSNR: 45.77 MAXDIFF: 23 bytes: 760320/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-dv b/tests/ref/vsynth/vsynth2-dv
index 2aac5ff..7bcc5ad 100644
--- a/tests/ref/vsynth/vsynth2-dv
+++ b/tests/ref/vsynth/vsynth2-dv
@@ -1,4 +1,4 @@
-bfa766f89bfeabc0ae1044f3954bed52 *tests/data/fate/vsynth2-dv.dv
+85b8d55b0b68bb3fc2e90babb580f9b7 *tests/data/fate/vsynth2-dv.dv
7200000 tests/data/fate/vsynth2-dv.dv
-7ec62bd3350a6848364669e6e1e4b9cc *tests/data/fate/vsynth2-dv.out.rawvideo
-stddev: 1.71 PSNR: 43.47 MAXDIFF: 33 bytes: 7603200/ 7603200
+7dac420637360b031ccae7c5a69c5e0c *tests/data/fate/vsynth2-dv.out.rawvideo
+stddev: 1.70 PSNR: 43.47 MAXDIFF: 33 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-dv-411 b/tests/ref/vsynth/vsynth2-dv-411
index 00ecace..541673a 100644
--- a/tests/ref/vsynth/vsynth2-dv-411
+++ b/tests/ref/vsynth/vsynth2-dv-411
@@ -1,4 +1,4 @@
-00a9d8683ac6826af41bcf7223fb0389 *tests/data/fate/vsynth2-dv-411.dv
+e428508f400327aeb96969c08fb9e1b5 *tests/data/fate/vsynth2-dv-411.dv
7200000 tests/data/fate/vsynth2-dv-411.dv
-3cd4b85065d67bfb7fbab3bea4039711 *tests/data/fate/vsynth2-dv-411.out.rawvideo
+713ed907fde448c603d6e9aee5efedd1 *tests/data/fate/vsynth2-dv-411.out.rawvideo
stddev: 2.89 PSNR: 38.91 MAXDIFF: 45 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-dv-50 b/tests/ref/vsynth/vsynth2-dv-50
index e7e5dc1..4aecdb0 100644
--- a/tests/ref/vsynth/vsynth2-dv-50
+++ b/tests/ref/vsynth/vsynth2-dv-50
@@ -1,4 +1,4 @@
-61e31c79e8949b25c849753a0785b0d7 *tests/data/fate/vsynth2-dv-50.dv
+0032a07167199e6f49e07fa7ed4d5f62 *tests/data/fate/vsynth2-dv-50.dv
14400000 tests/data/fate/vsynth2-dv-50.dv
-af3f2dd5ab62c1a1d98b07d4aeb6852f *tests/data/fate/vsynth2-dv-50.out.rawvideo
+56c77e537291536b242857d1056de30c *tests/data/fate/vsynth2-dv-50.out.rawvideo
stddev: 0.82 PSNR: 49.82 MAXDIFF: 12 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-dv_411 b/tests/ref/vsynth/vsynth2-dv_411
new file mode 100644
index 0000000..708ac88
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-dv_411
@@ -0,0 +1,4 @@
+e428508f400327aeb96969c08fb9e1b5 *./tests/data/vsynth2/dv411.dv
+7200000 ./tests/data/vsynth2/dv411.dv
+7f9fa421028aabb11eaf4c6513a5a843 *./tests/data/dv_411.vsynth2.out.yuv
+stddev: 10.09 PSNR: 28.05 MAXDIFF: 60 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-ffv1 b/tests/ref/vsynth/vsynth2-ffv1
index 8263b01..d0035e4 100644
--- a/tests/ref/vsynth/vsynth2-ffv1
+++ b/tests/ref/vsynth/vsynth2-ffv1
@@ -1,4 +1,4 @@
-9d8486fc8a260204d8ee3212d95915b5 *tests/data/fate/vsynth2-ffv1.avi
-3546258 tests/data/fate/vsynth2-ffv1.avi
+9e091bee097632ef7106d3bade12b81b *tests/data/fate/vsynth2-ffv1.avi
+3547788 tests/data/fate/vsynth2-ffv1.avi
dde5895817ad9d219f79a52d0bdfb001 *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 0000000..f3877d1
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffv1.0
@@ -0,0 +1,4 @@
+114950628c091cd830d9e66e74f6bca2 *tests/data/fate/vsynth2-ffv1.0.avi
+3525792 tests/data/fate/vsynth2-ffv1.0.avi
+dde5895817ad9d219f79a52d0bdfb001 *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 8daed2b..921d5bf 100644
--- a/tests/ref/vsynth/vsynth2-ffvhuff
+++ b/tests/ref/vsynth/vsynth2-ffvhuff
@@ -1,4 +1,4 @@
-f6a213ef136012a3d189d09468d80dd3 *tests/data/fate/vsynth2-ffvhuff.avi
-4988044 tests/data/fate/vsynth2-ffvhuff.avi
+7cb61df06d2cb4659ceb8d73c4822aaf *tests/data/fate/vsynth2-ffvhuff.avi
+4845022 tests/data/fate/vsynth2-ffvhuff.avi
dde5895817ad9d219f79a52d0bdfb001 *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 0000000..1f1279f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffvhuff420p12
@@ -0,0 +1,4 @@
+e5873a19c7be1cdf25600eb033738b9e *tests/data/fate/vsynth2-ffvhuff420p12.avi
+10925576 tests/data/fate/vsynth2-ffvhuff420p12.avi
+08b3c6c70eba608bae926608ff253f2a *tests/data/fate/vsynth2-ffvhuff420p12.out.rawvideo
+stddev: 0.68 PSNR: 51.38 MAXDIFF: 1 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-ffvhuff422p10left b/tests/ref/vsynth/vsynth2-ffvhuff422p10left
new file mode 100644
index 0000000..bb16978
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffvhuff422p10left
@@ -0,0 +1,4 @@
+d7d321c3b1ed3378e03b2f618f248d86 *tests/data/fate/vsynth2-ffvhuff422p10left.avi
+10041832 tests/data/fate/vsynth2-ffvhuff422p10left.avi
+a627fb50c8276200fd71383977d87ca3 *tests/data/fate/vsynth2-ffvhuff422p10left.out.rawvideo
+stddev: 0.34 PSNR: 57.43 MAXDIFF: 6 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-ffvhuff444 b/tests/ref/vsynth/vsynth2-ffvhuff444
new file mode 100644
index 0000000..c4ea9cd
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffvhuff444
@@ -0,0 +1,4 @@
+68e78dc89bb596f93a14e7f4a7a24365 *tests/data/fate/vsynth2-ffvhuff444.avi
+7530714 tests/data/fate/vsynth2-ffvhuff444.avi
+d43cb310c130c69214332d74f6ee5f9a *tests/data/fate/vsynth2-ffvhuff444.out.rawvideo
+stddev: 0.41 PSNR: 55.80 MAXDIFF: 7 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-ffvhuff444p16 b/tests/ref/vsynth/vsynth2-ffvhuff444p16
new file mode 100644
index 0000000..1f03a03
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffvhuff444p16
@@ -0,0 +1,4 @@
+db17747292df97d6c62b15b041c378da *tests/data/fate/vsynth2-ffvhuff444p16.avi
+26360716 tests/data/fate/vsynth2-ffvhuff444p16.avi
+05ccd9a38f9726030b3099c0c99d3a13 *tests/data/fate/vsynth2-ffvhuff444p16.out.rawvideo
+stddev: 0.45 PSNR: 55.06 MAXDIFF: 7 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-flashsv b/tests/ref/vsynth/vsynth2-flashsv
index b05e746..e44fa8f 100644
--- a/tests/ref/vsynth/vsynth2-flashsv
+++ b/tests/ref/vsynth/vsynth2-flashsv
@@ -1,4 +1,4 @@
-cd771e2b159450e63e38e26b872e548e *tests/data/fate/vsynth2-flashsv.flv
-12368933 tests/data/fate/vsynth2-flashsv.flv
-592b3321994e26a990deb3a0a1415de9 *tests/data/fate/vsynth2-flashsv.out.rawvideo
-stddev: 0.65 PSNR: 51.84 MAXDIFF: 14 bytes: 7603200/ 7603200
+0667077971e0cb63b5f49c580006e90e *tests/data/fate/vsynth2-flashsv.flv
+12368953 tests/data/fate/vsynth2-flashsv.flv
+3a984506f1ebfc9fb73b6814cab201cc *tests/data/fate/vsynth2-flashsv.out.rawvideo
+stddev: 0.66 PSNR: 51.73 MAXDIFF: 14 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-flashsv2 b/tests/ref/vsynth/vsynth2-flashsv2
new file mode 100644
index 0000000..d207a8b
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-flashsv2
@@ -0,0 +1,4 @@
+01e0aa4da9ccc8e12fd03df63625eea4 *tests/data/fate/vsynth2-flashsv2.flv
+9291162 tests/data/fate/vsynth2-flashsv2.flv
+8f63e24049ba1789a7f8353c695a3d99 *tests/data/fate/vsynth2-flashsv2.out.rawvideo
+stddev: 2.39 PSNR: 40.55 MAXDIFF: 21 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-flv b/tests/ref/vsynth/vsynth2-flv
index 3047fb7..ab31755 100644
--- a/tests/ref/vsynth/vsynth2-flv
+++ b/tests/ref/vsynth/vsynth2-flv
@@ -1,4 +1,4 @@
-747633a169bbfe4622c6c1a7990deafd *tests/data/fate/vsynth2-flv.flv
-131340 tests/data/fate/vsynth2-flv.flv
-8999c8264fb0941561f64c4a736e9d88 *tests/data/fate/vsynth2-flv.out.rawvideo
-stddev: 5.33 PSNR: 33.59 MAXDIFF: 80 bytes: 7603200/ 7603200
+dee04bdab18c2eed81373faec89fd5a7 *tests/data/fate/vsynth2-flv.flv
+131380 tests/data/fate/vsynth2-flv.flv
+184034553ceb801bb1d1521d2d998a67 *tests/data/fate/vsynth2-flv.out.rawvideo
+stddev: 5.33 PSNR: 33.59 MAXDIFF: 79 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-h261 b/tests/ref/vsynth/vsynth2-h261
index 71ea191..67a8f0b 100644
--- a/tests/ref/vsynth/vsynth2-h261
+++ b/tests/ref/vsynth/vsynth2-h261
@@ -1,4 +1,4 @@
-921e06dffd04667d336449c7cd1c6589 *tests/data/fate/vsynth2-h261.avi
-191074 tests/data/fate/vsynth2-h261.avi
-db7ceff174823b98834faa2320ca89ac *tests/data/fate/vsynth2-h261.out.rawvideo
+6399cb1044e5433c844c21790fc17128 *tests/data/fate/vsynth2-h261.avi
+191060 tests/data/fate/vsynth2-h261.avi
+08f65e9aeeeaf189548c2bb417d5114f *tests/data/fate/vsynth2-h261.out.rawvideo
stddev: 6.37 PSNR: 32.03 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-h261-trellis b/tests/ref/vsynth/vsynth2-h261-trellis
new file mode 100644
index 0000000..8a7cf78
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-h261-trellis
@@ -0,0 +1,4 @@
+616cb40cf84704d177e207ee85a24531 *tests/data/fate/vsynth2-h261-trellis.avi
+184582 tests/data/fate/vsynth2-h261-trellis.avi
+f9df8cd110a2f3d9706dd2f29a1d0a89 *tests/data/fate/vsynth2-h261-trellis.out.rawvideo
+stddev: 6.32 PSNR: 32.11 MAXDIFF: 89 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-h263 b/tests/ref/vsynth/vsynth2-h263
index b2ce370..8feabfe 100644
--- a/tests/ref/vsynth/vsynth2-h263
+++ b/tests/ref/vsynth/vsynth2-h263
@@ -1,4 +1,4 @@
-329c0318b8727d66946ec729c6e960fc *tests/data/fate/vsynth2-h263.avi
-160094 tests/data/fate/vsynth2-h263.avi
-61213b91b359697ebcefb9e0a53ac54a *tests/data/fate/vsynth2-h263.out.rawvideo
+b5ea141b794ad88019507375ec092ad7 *tests/data/fate/vsynth2-h263.avi
+160102 tests/data/fate/vsynth2-h263.avi
+b7d733ebedbaa04f49bf7493a907e223 *tests/data/fate/vsynth2-h263.out.rawvideo
stddev: 5.43 PSNR: 33.42 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-h263-obmc b/tests/ref/vsynth/vsynth2-h263-obmc
index 67fd2fd..aa9a60a 100644
--- a/tests/ref/vsynth/vsynth2-h263-obmc
+++ b/tests/ref/vsynth/vsynth2-h263-obmc
@@ -1,4 +1,4 @@
-3abbe86e18ef9d407cc3817dd31ebeba *tests/data/fate/vsynth2-h263-obmc.avi
-154716 tests/data/fate/vsynth2-h263-obmc.avi
-6f326547cf1cbd95a8c0a5ddce9eb71a *tests/data/fate/vsynth2-h263-obmc.out.rawvideo
+d242b7948697014abcaaff50551400ac *tests/data/fate/vsynth2-h263-obmc.avi
+154726 tests/data/fate/vsynth2-h263-obmc.avi
+588d992d9d8096da8bdc5027268da914 *tests/data/fate/vsynth2-h263-obmc.out.rawvideo
stddev: 5.39 PSNR: 33.49 MAXDIFF: 82 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-h263p b/tests/ref/vsynth/vsynth2-h263p
index 826dcd1..182e096 100644
--- a/tests/ref/vsynth/vsynth2-h263p
+++ b/tests/ref/vsynth/vsynth2-h263p
@@ -1,4 +1,4 @@
-865ca965ab4fdfe225db7de3d23b4ad8 *tests/data/fate/vsynth2-h263p.avi
-868006 tests/data/fate/vsynth2-h263p.avi
-4b0ee791f280029dc03c528f76f195d4 *tests/data/fate/vsynth2-h263p.out.rawvideo
+000157a2e05709df95e40bd5e2185141 *tests/data/fate/vsynth2-h263p.avi
+867998 tests/data/fate/vsynth2-h263p.avi
+dca18571c05c13dd691d7b0b232e43fc *tests/data/fate/vsynth2-h263p.out.rawvideo
stddev: 1.91 PSNR: 42.50 MAXDIFF: 19 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-huffyuv b/tests/ref/vsynth/vsynth2-huffyuv
index 7d062dd..a2d2ae3 100644
--- a/tests/ref/vsynth/vsynth2-huffyuv
+++ b/tests/ref/vsynth/vsynth2-huffyuv
@@ -1,4 +1,4 @@
-30d509aca4a7298cf7667581a5e37671 *tests/data/fate/vsynth2-huffyuv.avi
-6455220 tests/data/fate/vsynth2-huffyuv.avi
+c639e4044a66dc5dffb46d5d82516ef8 *tests/data/fate/vsynth2-huffyuv.avi
+6108510 tests/data/fate/vsynth2-huffyuv.avi
dde5895817ad9d219f79a52d0bdfb001 *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 0000000..939eb2f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-huffyuvbgr24
@@ -0,0 +1,4 @@
+d72d98a2847811499028f8997320a38b *tests/data/fate/vsynth2-huffyuvbgr24.avi
+8872410 tests/data/fate/vsynth2-huffyuvbgr24.avi
+0a8b7ddfec03622e37c869c5b552f9fc *tests/data/fate/vsynth2-huffyuvbgr24.out.rawvideo
+stddev: 1.24 PSNR: 46.26 MAXDIFF: 17 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-huffyuvbgra b/tests/ref/vsynth/vsynth2-huffyuvbgra
new file mode 100644
index 0000000..b37b49f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-huffyuvbgra
@@ -0,0 +1,4 @@
+e8c2dbe6ad5d273af2bdb2dc3a2a524d *tests/data/fate/vsynth2-huffyuvbgra.avi
+10139598 tests/data/fate/vsynth2-huffyuvbgra.avi
+0a8b7ddfec03622e37c869c5b552f9fc *tests/data/fate/vsynth2-huffyuvbgra.out.rawvideo
+stddev: 1.24 PSNR: 46.26 MAXDIFF: 17 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-jpeg2000 b/tests/ref/vsynth/vsynth2-jpeg2000
new file mode 100644
index 0000000..84e90d4
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-jpeg2000
@@ -0,0 +1,4 @@
+6cf1985f29a7febbb79edf1d5268e203 *tests/data/fate/vsynth2-jpeg2000.avi
+1151144 tests/data/fate/vsynth2-jpeg2000.avi
+e7d79c9e11d0fe97f03e38be66c34e4f *tests/data/fate/vsynth2-jpeg2000.out.rawvideo
+stddev: 4.41 PSNR: 35.23 MAXDIFF: 63 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-jpeg2000-97 b/tests/ref/vsynth/vsynth2-jpeg2000-97
new file mode 100644
index 0000000..c053a5d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-jpeg2000-97
@@ -0,0 +1,4 @@
+7cdaa014398f52869704dc537983db54 *tests/data/fate/vsynth2-jpeg2000-97.avi
+1118952 tests/data/fate/vsynth2-jpeg2000-97.avi
+8ac8b9ee81fa73c873668e9f6b78764d *tests/data/fate/vsynth2-jpeg2000-97.out.rawvideo
+stddev: 4.95 PSNR: 34.23 MAXDIFF: 60 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-jpegls b/tests/ref/vsynth/vsynth2-jpegls
index 75ad403..e256dea 100644
--- a/tests/ref/vsynth/vsynth2-jpegls
+++ b/tests/ref/vsynth/vsynth2-jpegls
@@ -1,4 +1,4 @@
-f34315ed0e30cf4d94dd21ff1d4cea1b *tests/data/fate/vsynth2-jpegls.avi
+9840b70886b4fc86512de729e41de979 *tests/data/fate/vsynth2-jpegls.avi
8334618 tests/data/fate/vsynth2-jpegls.avi
-592b3321994e26a990deb3a0a1415de9 *tests/data/fate/vsynth2-jpegls.out.rawvideo
-stddev: 0.65 PSNR: 51.84 MAXDIFF: 14 bytes: 7603200/ 7603200
+3a984506f1ebfc9fb73b6814cab201cc *tests/data/fate/vsynth2-jpegls.out.rawvideo
+stddev: 0.66 PSNR: 51.73 MAXDIFF: 14 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-ljpeg b/tests/ref/vsynth/vsynth2-ljpeg
index a7b8a2d..b59923e 100644
--- a/tests/ref/vsynth/vsynth2-ljpeg
+++ b/tests/ref/vsynth/vsynth2-ljpeg
@@ -1,4 +1,4 @@
-5d603cecd59db0f255a53bda837a6bae *tests/data/fate/vsynth2-ljpeg.avi
-4766902 tests/data/fate/vsynth2-ljpeg.avi
+234a0e54d00829513bdc92fc580b2598 *tests/data/fate/vsynth2-ljpeg.avi
+4763454 tests/data/fate/vsynth2-ljpeg.avi
dde5895817ad9d219f79a52d0bdfb001 *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 981d01b..eaabc73 100644
--- a/tests/ref/vsynth/vsynth2-mjpeg
+++ b/tests/ref/vsynth/vsynth2-mjpeg
@@ -1,4 +1,4 @@
-ba05f4fad7f34a96c77964e8cdf9d5c0 *tests/data/fate/vsynth2-mjpeg.avi
-673212 tests/data/fate/vsynth2-mjpeg.avi
-a96a4e15ffcb13e44360df642d049496 *tests/data/fate/vsynth2-mjpeg.out.rawvideo
+a3c1f9f7887b726bab17dbafa5debdca *tests/data/fate/vsynth2-mjpeg.avi
+673174 tests/data/fate/vsynth2-mjpeg.avi
+9d4bd90e9abfa18192383b4adc23c8d4 *tests/data/fate/vsynth2-mjpeg.out.rawvideo
stddev: 4.32 PSNR: 35.40 MAXDIFF: 49 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mjpeg-422 b/tests/ref/vsynth/vsynth2-mjpeg-422
new file mode 100644
index 0000000..61d2997
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-mjpeg-422
@@ -0,0 +1,4 @@
+ebf2e0f17a75119ff86b15e721d16a76 *tests/data/fate/vsynth2-mjpeg-422.avi
+746530 tests/data/fate/vsynth2-mjpeg-422.avi
+451ac80989c4e14445cf951fd7f83b6d *tests/data/fate/vsynth2-mjpeg-422.out.rawvideo
+stddev: 4.18 PSNR: 35.70 MAXDIFF: 49 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mjpeg-444 b/tests/ref/vsynth/vsynth2-mjpeg-444
new file mode 100644
index 0000000..ae01a35
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-mjpeg-444
@@ -0,0 +1,4 @@
+7674eb1aedaad0976c60329f556440d1 *tests/data/fate/vsynth2-mjpeg-444.avi
+851442 tests/data/fate/vsynth2-mjpeg-444.avi
+34edcb9c87ff7aac456a4fb07f43504b *tests/data/fate/vsynth2-mjpeg-444.out.rawvideo
+stddev: 4.05 PSNR: 35.96 MAXDIFF: 49 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg1 b/tests/ref/vsynth/vsynth2-mpeg1
index a975973..9e3e999 100644
--- a/tests/ref/vsynth/vsynth2-mpeg1
+++ b/tests/ref/vsynth/vsynth2-mpeg1
@@ -1,4 +1,4 @@
-73ca6f1deab02d1d67a0e8495c026a9e *tests/data/fate/vsynth2-mpeg1.mpeg1video
-192783 tests/data/fate/vsynth2-mpeg1.mpeg1video
-56147e94b12f08df7213e610e177823d *tests/data/fate/vsynth2-mpeg1.out.rawvideo
+a77a8eb6e2ad32a5b20b41abda16f4c1 *tests/data/fate/vsynth2-mpeg1.mpeg1video
+192794 tests/data/fate/vsynth2-mpeg1.mpeg1video
+b3584042c60385e0fb988b8ec5b36409 *tests/data/fate/vsynth2-mpeg1.out.rawvideo
stddev: 4.95 PSNR: 34.22 MAXDIFF: 57 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg1b b/tests/ref/vsynth/vsynth2-mpeg1b
index 4b92ac5..c2fb217 100644
--- a/tests/ref/vsynth/vsynth2-mpeg1b
+++ b/tests/ref/vsynth/vsynth2-mpeg1b
@@ -1,4 +1,4 @@
-e026a2fef80c9679776d2b5c8be09338 *tests/data/fate/vsynth2-mpeg1b.mpeg1video
-225198 tests/data/fate/vsynth2-mpeg1b.mpeg1video
-1150495f4bd487486ee53326c42d0bb8 *tests/data/fate/vsynth2-mpeg1b.out.rawvideo
+333395b113b8045bac4e3fd90839ca6a *tests/data/fate/vsynth2-mpeg1b.mpeg1video
+225201 tests/data/fate/vsynth2-mpeg1b.mpeg1video
+f17fb3eef4ed3d03eeaaee45b217f7a5 *tests/data/fate/vsynth2-mpeg1b.out.rawvideo
stddev: 4.10 PSNR: 35.86 MAXDIFF: 59 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2 b/tests/ref/vsynth/vsynth2-mpeg2
index c346fc4..bceb954 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2
+++ b/tests/ref/vsynth/vsynth2-mpeg2
@@ -1,4 +1,4 @@
-bc0dfd0449235fc82c4e08e639c60738 *tests/data/fate/vsynth2-mpeg2.mpeg2video
-198727 tests/data/fate/vsynth2-mpeg2.mpeg2video
-b7cae8a1f751b821cddcbe4d5dbc518c *tests/data/fate/vsynth2-mpeg2.out.rawvideo
+6071414a26d41ae9c4cc5477d8ca19eb *tests/data/fate/vsynth2-mpeg2.mpeg2video
+198673 tests/data/fate/vsynth2-mpeg2.mpeg2video
+9efe4846a75d9b7387d1e3bb1e5db29a *tests/data/fate/vsynth2-mpeg2.out.rawvideo
stddev: 4.96 PSNR: 34.20 MAXDIFF: 59 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2-422 b/tests/ref/vsynth/vsynth2-mpeg2-422
index d898c6f..b4a896c 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-422
+++ b/tests/ref/vsynth/vsynth2-mpeg2-422
@@ -1,4 +1,4 @@
-15424b60d15080836cf868657968cb3d *tests/data/fate/vsynth2-mpeg2-422.mpeg2video
-356161 tests/data/fate/vsynth2-mpeg2-422.mpeg2video
-9fbde6cc707068edf15de2050adb8da7 *tests/data/fate/vsynth2-mpeg2-422.out.rawvideo
-stddev: 3.16 PSNR: 38.13 MAXDIFF: 49 bytes: 7603200/ 7603200
+521ec92c0b8672011a43dd13db98c400 *tests/data/fate/vsynth2-mpeg2-422.mpeg2video
+356431 tests/data/fate/vsynth2-mpeg2-422.mpeg2video
+51ca353620f85db8b5b1c56f1a275add *tests/data/fate/vsynth2-mpeg2-422.out.rawvideo
+stddev: 3.15 PSNR: 38.14 MAXDIFF: 49 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2-idct-int b/tests/ref/vsynth/vsynth2-mpeg2-idct-int
index bb8c1c6..69d5c86 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-idct-int
+++ b/tests/ref/vsynth/vsynth2-mpeg2-idct-int
@@ -1,4 +1,4 @@
-46aa32897fe88df6db156731332e3667 *tests/data/fate/vsynth2-mpeg2-idct-int.mpeg2video
-198101 tests/data/fate/vsynth2-mpeg2-idct-int.mpeg2video
+505371e1b10f5af01b63b3f57606b26e *tests/data/fate/vsynth2-mpeg2-idct-int.mpeg2video
+198041 tests/data/fate/vsynth2-mpeg2-idct-int.mpeg2video
92794e70e4a19a494f10efe353d9895d *tests/data/fate/vsynth2-mpeg2-idct-int.out.rawvideo
stddev: 4.97 PSNR: 34.19 MAXDIFF: 58 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2-ilace b/tests/ref/vsynth/vsynth2-mpeg2-ilace
index 4492c8d..5c37c34 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-ilace
+++ b/tests/ref/vsynth/vsynth2-mpeg2-ilace
@@ -1,4 +1,4 @@
-f2f0aa5808066cc6b4e79c78b2fd2223 *tests/data/fate/vsynth2-mpeg2-ilace.mpeg2video
-204639 tests/data/fate/vsynth2-mpeg2-ilace.mpeg2video
-ea5057b60146c06d40449cdfc686bf13 *tests/data/fate/vsynth2-mpeg2-ilace.out.rawvideo
+dbc7dd0272f3711f50722f4753e3bfb0 *tests/data/fate/vsynth2-mpeg2-ilace.mpeg2video
+204576 tests/data/fate/vsynth2-mpeg2-ilace.mpeg2video
+d69be0d4ba1cb9c1fef9fb0d94a912ba *tests/data/fate/vsynth2-mpeg2-ilace.out.rawvideo
stddev: 4.98 PSNR: 34.18 MAXDIFF: 65 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd b/tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd
index 1b1554f..dea3f94 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd
+++ b/tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd
@@ -1,4 +1,4 @@
-d5513b33636854d4956078d6f40f9758 *tests/data/fate/vsynth2-mpeg2-ivlc-qprd.mpeg2video
-244761 tests/data/fate/vsynth2-mpeg2-ivlc-qprd.mpeg2video
-e38edc0ae8e422bcd9346b15da41a438 *tests/data/fate/vsynth2-mpeg2-ivlc-qprd.out.rawvideo
+5731a196498d4e8097c0ebe57e383ef6 *tests/data/fate/vsynth2-mpeg2-ivlc-qprd.mpeg2video
+244694 tests/data/fate/vsynth2-mpeg2-ivlc-qprd.mpeg2video
+b26e21599dee48a174bdbc40b2817e55 *tests/data/fate/vsynth2-mpeg2-ivlc-qprd.out.rawvideo
stddev: 4.15 PSNR: 35.76 MAXDIFF: 74 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2-thread b/tests/ref/vsynth/vsynth2-mpeg2-thread
index 7293a33..335d1c6 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-thread
+++ b/tests/ref/vsynth/vsynth2-mpeg2-thread
@@ -1,4 +1,4 @@
-33dc9ed754788b68d27e694b20f29fe9 *tests/data/fate/vsynth2-mpeg2-thread.mpeg2video
-179710 tests/data/fate/vsynth2-mpeg2-thread.mpeg2video
-8c6a7ed2eb73bd18fd2bb9829464100d *tests/data/fate/vsynth2-mpeg2-thread.out.rawvideo
+9e734d384b4234d075203dffffa5174c *tests/data/fate/vsynth2-mpeg2-thread.mpeg2video
+179656 tests/data/fate/vsynth2-mpeg2-thread.mpeg2video
+f8f084b7f51fbe4f82d57b8aeec17edf *tests/data/fate/vsynth2-mpeg2-thread.out.rawvideo
stddev: 4.72 PSNR: 34.65 MAXDIFF: 72 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2-thread-ivlc b/tests/ref/vsynth/vsynth2-mpeg2-thread-ivlc
index 2cacf32..67a380a 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-thread-ivlc
+++ b/tests/ref/vsynth/vsynth2-mpeg2-thread-ivlc
@@ -1,4 +1,4 @@
-31b7429e67bbeec0bb9b86d8f2e596de *tests/data/fate/vsynth2-mpeg2-thread-ivlc.mpeg2video
-178861 tests/data/fate/vsynth2-mpeg2-thread-ivlc.mpeg2video
-8c6a7ed2eb73bd18fd2bb9829464100d *tests/data/fate/vsynth2-mpeg2-thread-ivlc.out.rawvideo
+39ae4e15e3da14218ebf250180badd92 *tests/data/fate/vsynth2-mpeg2-thread-ivlc.mpeg2video
+178807 tests/data/fate/vsynth2-mpeg2-thread-ivlc.mpeg2video
+f8f084b7f51fbe4f82d57b8aeec17edf *tests/data/fate/vsynth2-mpeg2-thread-ivlc.out.rawvideo
stddev: 4.72 PSNR: 34.65 MAXDIFF: 72 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4 b/tests/ref/vsynth/vsynth2-mpeg4
index a654c13..ac5ee39 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4
+++ b/tests/ref/vsynth/vsynth2-mpeg4
@@ -1,4 +1,4 @@
-0282105e98166fac06f7ba9e857cfbfe *tests/data/fate/vsynth2-mpeg4.mp4
-119833 tests/data/fate/vsynth2-mpeg4.mp4
-90a3577850239083a9042bef33c50e85 *tests/data/fate/vsynth2-mpeg4.out.rawvideo
+4a029747434d24d128b078a5e6aa1e88 *tests/data/fate/vsynth2-mpeg4.mp4
+119722 tests/data/fate/vsynth2-mpeg4.mp4
+9a1e085d9e488c5ead0c940c9612a37a *tests/data/fate/vsynth2-mpeg4.out.rawvideo
stddev: 5.34 PSNR: 33.57 MAXDIFF: 83 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-adap b/tests/ref/vsynth/vsynth2-mpeg4-adap
index fb4c206..7a40c4b 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-adap
+++ b/tests/ref/vsynth/vsynth2-mpeg4-adap
@@ -1,4 +1,4 @@
-76c8962b06b7a0d748bd7eb3f6fc0e18 *tests/data/fate/vsynth2-mpeg4-adap.avi
-198498 tests/data/fate/vsynth2-mpeg4-adap.avi
-4affb83f6adc94f31024b4f9e0168945 *tests/data/fate/vsynth2-mpeg4-adap.out.rawvideo
+bbb12e077f858242c1387d23d2ccdae8 *tests/data/fate/vsynth2-mpeg4-adap.avi
+198496 tests/data/fate/vsynth2-mpeg4-adap.avi
+87b6dbe98d276137fceaae2fa672eced *tests/data/fate/vsynth2-mpeg4-adap.out.rawvideo
stddev: 3.75 PSNR: 36.65 MAXDIFF: 71 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-adv b/tests/ref/vsynth/vsynth2-mpeg4-adv
index b3bf264..c1385ca 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-adv
+++ b/tests/ref/vsynth/vsynth2-mpeg4-adv
@@ -1,4 +1,4 @@
-1875ae5a45936c08778c4430a22e87eb *tests/data/fate/vsynth2-mpeg4-adv.avi
+9fa1b5a68a6128a7160cfc8443a696e1 *tests/data/fate/vsynth2-mpeg4-adv.avi
141534 tests/data/fate/vsynth2-mpeg4-adv.avi
3f3a21e9db85a9c0f7022f557a5374c1 *tests/data/fate/vsynth2-mpeg4-adv.out.rawvideo
stddev: 4.94 PSNR: 34.25 MAXDIFF: 69 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-error b/tests/ref/vsynth/vsynth2-mpeg4-error
index 35dd03d..a8d93bc 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-error
+++ b/tests/ref/vsynth/vsynth2-mpeg4-error
@@ -1,4 +1,4 @@
-d3025e5f784efeb2ab9b84f8924eda19 *tests/data/fate/vsynth2-mpeg4-error.avi
-176576 tests/data/fate/vsynth2-mpeg4-error.avi
-96baa9e4c24c837a3ba5abd8dd2cdd30 *tests/data/fate/vsynth2-mpeg4-error.out.rawvideo
-stddev: 8.98 PSNR: 29.06 MAXDIFF: 184 bytes: 7603200/ 7603200
+82510449a3200b58dbcfbf0a643eb624 *tests/data/fate/vsynth2-mpeg4-error.avi
+180364 tests/data/fate/vsynth2-mpeg4-error.avi
+4537ba5320f1ae0971cc6e329c366776 *tests/data/fate/vsynth2-mpeg4-error.out.rawvideo
+stddev: 7.65 PSNR: 30.45 MAXDIFF: 158 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-nr b/tests/ref/vsynth/vsynth2-mpeg4-nr
index 7fdce67..05dcc54 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-nr
+++ b/tests/ref/vsynth/vsynth2-mpeg4-nr
@@ -1,4 +1,4 @@
-75725f3c2a08efa145a2692a20373a21 *tests/data/fate/vsynth2-mpeg4-nr.avi
-155032 tests/data/fate/vsynth2-mpeg4-nr.avi
-f7fc191308679f709405e62271f5c65f *tests/data/fate/vsynth2-mpeg4-nr.out.rawvideo
+cf0cde80515f8bfbd89d33aa51f1c5e1 *tests/data/fate/vsynth2-mpeg4-nr.avi
+154994 tests/data/fate/vsynth2-mpeg4-nr.avi
+d89cd5d0b1707f48fa9c4747c66d2d56 *tests/data/fate/vsynth2-mpeg4-nr.out.rawvideo
stddev: 4.73 PSNR: 34.63 MAXDIFF: 64 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-nsse b/tests/ref/vsynth/vsynth2-mpeg4-nsse
new file mode 100644
index 0000000..0833519
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-mpeg4-nsse
@@ -0,0 +1,4 @@
+b60bb3d8b942795272f0f0d89cd6351e *tests/data/fate/vsynth2-mpeg4-nsse.avi
+198434 tests/data/fate/vsynth2-mpeg4-nsse.avi
+59864a1050e641eaed8b0ee077bc780b *tests/data/fate/vsynth2-mpeg4-nsse.out.rawvideo
+stddev: 4.32 PSNR: 35.40 MAXDIFF: 60 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-qpel b/tests/ref/vsynth/vsynth2-mpeg4-qpel
index cab264a..2822580 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-qpel
+++ b/tests/ref/vsynth/vsynth2-mpeg4-qpel
@@ -1,4 +1,4 @@
-c45101c6c3b681f5d420a938c0689a37 *tests/data/fate/vsynth2-mpeg4-qpel.avi
-163676 tests/data/fate/vsynth2-mpeg4-qpel.avi
-26dc7c78955fa678fbf150e236eb5627 *tests/data/fate/vsynth2-mpeg4-qpel.out.rawvideo
+ab94d9e56635e100d95e74fc8dc845e5 *tests/data/fate/vsynth2-mpeg4-qpel.avi
+163662 tests/data/fate/vsynth2-mpeg4-qpel.avi
+e2ce994dbb66da51c2e1ad26617d7c2f *tests/data/fate/vsynth2-mpeg4-qpel.out.rawvideo
stddev: 3.97 PSNR: 36.14 MAXDIFF: 54 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-qprd b/tests/ref/vsynth/vsynth2-mpeg4-qprd
index 1779dd7..287fff22 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-qprd
+++ b/tests/ref/vsynth/vsynth2-mpeg4-qprd
@@ -1,4 +1,4 @@
-81afd85c3ab00b685588e1b61cc3e4b3 *tests/data/fate/vsynth2-mpeg4-qprd.avi
-231446 tests/data/fate/vsynth2-mpeg4-qprd.avi
-de8a883865e2dff7a51f66da6c48df48 *tests/data/fate/vsynth2-mpeg4-qprd.out.rawvideo
+a576ecbf48c33916f2d17cf1bf37f3fe *tests/data/fate/vsynth2-mpeg4-qprd.avi
+231450 tests/data/fate/vsynth2-mpeg4-qprd.avi
+3071250e0864546c2455c9f9c9b8604e *tests/data/fate/vsynth2-mpeg4-qprd.out.rawvideo
stddev: 3.71 PSNR: 36.72 MAXDIFF: 61 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-rc b/tests/ref/vsynth/vsynth2-mpeg4-rc
index 74e7962..ccf4400 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-rc
+++ b/tests/ref/vsynth/vsynth2-mpeg4-rc
@@ -1,4 +1,4 @@
-e3621649079539ec118e8581c54bc2ef *tests/data/fate/vsynth2-mpeg4-rc.avi
-226320 tests/data/fate/vsynth2-mpeg4-rc.avi
-2b34e606af895b62a250de98749a19b0 *tests/data/fate/vsynth2-mpeg4-rc.out.rawvideo
+ea96539a0bebf70c3c09de0199a53a30 *tests/data/fate/vsynth2-mpeg4-rc.avi
+226310 tests/data/fate/vsynth2-mpeg4-rc.avi
+6e8b62e8c3bcbfdcc58afb69a0b1c4e3 *tests/data/fate/vsynth2-mpeg4-rc.out.rawvideo
stddev: 4.23 PSNR: 35.60 MAXDIFF: 85 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-thread b/tests/ref/vsynth/vsynth2-mpeg4-thread
index 61478a0..f8475df 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-thread
+++ b/tests/ref/vsynth/vsynth2-mpeg4-thread
@@ -1,4 +1,4 @@
-69b716c9f99c5acb86a744521c32cf72 *tests/data/fate/vsynth2-mpeg4-thread.avi
-250128 tests/data/fate/vsynth2-mpeg4-thread.avi
-5355deb8c7609a3f1ff2173aab1dee70 *tests/data/fate/vsynth2-mpeg4-thread.out.rawvideo
+8d7903d55221035c67866b8c1314c499 *tests/data/fate/vsynth2-mpeg4-thread.avi
+250092 tests/data/fate/vsynth2-mpeg4-thread.avi
+045fe9f226bbcc3d41644bffaed03b31 *tests/data/fate/vsynth2-mpeg4-thread.out.rawvideo
stddev: 3.69 PSNR: 36.78 MAXDIFF: 65 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpng b/tests/ref/vsynth/vsynth2-mpng
new file mode 100644
index 0000000..31fbdcc
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-mpng
@@ -0,0 +1,4 @@
+aaee9d1ff7dccfc045603c45f0160000 *tests/data/fate/vsynth2-mpng.avi
+12558330 tests/data/fate/vsynth2-mpng.avi
+98d0e2854731472c5bf13d8638502d0a *tests/data/fate/vsynth2-mpng.out.rawvideo
+stddev: 1.26 PSNR: 46.10 MAXDIFF: 13 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-msmpeg4 b/tests/ref/vsynth/vsynth2-msmpeg4
index a7cc94e..439bb4e 100644
--- a/tests/ref/vsynth/vsynth2-msmpeg4
+++ b/tests/ref/vsynth/vsynth2-msmpeg4
@@ -1,4 +1,4 @@
-f602d25096c83f166bdab01fa07a34c1 *tests/data/fate/vsynth2-msmpeg4.avi
-127668 tests/data/fate/vsynth2-msmpeg4.avi
-0e1c6e25c71c6a8fa8e506e3d97ca4c9 *tests/data/fate/vsynth2-msmpeg4.out.rawvideo
-stddev: 5.33 PSNR: 33.59 MAXDIFF: 78 bytes: 7603200/ 7603200
+50b91fe78559c0f5f1e5873cdcc0e6a8 *tests/data/fate/vsynth2-msmpeg4.avi
+127660 tests/data/fate/vsynth2-msmpeg4.avi
+bb14902d5850d6b0ab70fdb017855775 *tests/data/fate/vsynth2-msmpeg4.out.rawvideo
+stddev: 5.33 PSNR: 33.58 MAXDIFF: 78 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-msmpeg4v2 b/tests/ref/vsynth/vsynth2-msmpeg4v2
index 542dfe5..985089a 100644
--- a/tests/ref/vsynth/vsynth2-msmpeg4v2
+++ b/tests/ref/vsynth/vsynth2-msmpeg4v2
@@ -1,4 +1,4 @@
-43d6ca9b63993b4603d4f08fa6aaeab3 *tests/data/fate/vsynth2-msmpeg4v2.avi
-129906 tests/data/fate/vsynth2-msmpeg4v2.avi
-8920194f8bf8f9cdd6c65b3df9e1a292 *tests/data/fate/vsynth2-msmpeg4v2.out.rawvideo
-stddev: 5.33 PSNR: 33.59 MAXDIFF: 80 bytes: 7603200/ 7603200
+4770bd848f1937a861bf1a72295c6094 *tests/data/fate/vsynth2-msmpeg4v2.avi
+129918 tests/data/fate/vsynth2-msmpeg4v2.avi
+537c114e1d47c54a4bccd31f4073e9bd *tests/data/fate/vsynth2-msmpeg4v2.out.rawvideo
+stddev: 5.33 PSNR: 33.59 MAXDIFF: 79 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-msvideo1 b/tests/ref/vsynth/vsynth2-msvideo1
new file mode 100644
index 0000000..421ad87
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-msvideo1
@@ -0,0 +1,4 @@
+e554e31a4a635c924391228b7194d21b *tests/data/fate/vsynth2-msvideo1.avi
+914560 tests/data/fate/vsynth2-msvideo1.avi
+9a6ac7c0171286f009d159b59fdc1154 *tests/data/fate/vsynth2-msvideo1.out.rawvideo
+stddev: 7.97 PSNR: 30.10 MAXDIFF: 123 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-prores b/tests/ref/vsynth/vsynth2-prores
index 9d56b95..a46fa48 100644
--- a/tests/ref/vsynth/vsynth2-prores
+++ b/tests/ref/vsynth/vsynth2-prores
@@ -1,4 +1,4 @@
-7d167fee27e8c34968bbecec282f927a *tests/data/fate/vsynth2-prores.mov
-3884722 tests/data/fate/vsynth2-prores.mov
-ca2f6c1162635dedfa468c90f1fdc0ef *tests/data/fate/vsynth2-prores.out.rawvideo
-stddev: 0.92 PSNR: 48.77 MAXDIFF: 10 bytes: 7603200/ 7603200
+637f34b5fd81f072f76a967595fa6af7 *tests/data/fate/vsynth2-prores.mov
+2844076 tests/data/fate/vsynth2-prores.mov
+03fd29e3963716a09d232b6f817ecb57 *tests/data/fate/vsynth2-prores.out.rawvideo
+stddev: 1.31 PSNR: 45.77 MAXDIFF: 11 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-prores_ks b/tests/ref/vsynth/vsynth2-prores_ks
new file mode 100644
index 0000000..ff815e5
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-prores_ks
@@ -0,0 +1,4 @@
+b03741c69037cbdcd2809278c00c0350 *tests/data/fate/vsynth2-prores_ks.mov
+3884596 tests/data/fate/vsynth2-prores_ks.mov
+6cfe987de99cf8ac9d43bdc5cd150838 *tests/data/fate/vsynth2-prores_ks.out.rawvideo
+stddev: 0.92 PSNR: 48.78 MAXDIFF: 10 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-qtrle b/tests/ref/vsynth/vsynth2-qtrle
index ac2b557..c9bf1e3 100644
--- a/tests/ref/vsynth/vsynth2-qtrle
+++ b/tests/ref/vsynth/vsynth2-qtrle
@@ -1,4 +1,4 @@
-fe3db3dd385b8e5dc43cccc17b50f7f0 *tests/data/fate/vsynth2-qtrle.mov
-14798419 tests/data/fate/vsynth2-qtrle.mov
-b2418e0e3a9a8619b31219cbcf24dc82 *tests/data/fate/vsynth2-qtrle.out.rawvideo
-stddev: 1.26 PSNR: 46.06 MAXDIFF: 13 bytes: 7603200/ 7603200
+4863978263d966d704ffaaa6d23123bb *tests/data/fate/vsynth2-qtrle.mov
+14798345 tests/data/fate/vsynth2-qtrle.mov
+98d0e2854731472c5bf13d8638502d0a *tests/data/fate/vsynth2-qtrle.out.rawvideo
+stddev: 1.26 PSNR: 46.10 MAXDIFF: 13 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-qtrlegray b/tests/ref/vsynth/vsynth2-qtrlegray
new file mode 100644
index 0000000..8b83a5a
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-qtrlegray
@@ -0,0 +1,4 @@
+2c4e69b59d8e8e19903c843575806d5f *tests/data/fate/vsynth2-qtrlegray.mov
+5111283 tests/data/fate/vsynth2-qtrlegray.mov
+d7bfbe259af9ae323bb94b09c33570a5 *tests/data/fate/vsynth2-qtrlegray.out.rawvideo
+stddev: 18.65 PSNR: 22.72 MAXDIFF: 72 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-r210 b/tests/ref/vsynth/vsynth2-r210
new file mode 100644
index 0000000..e42d797
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-r210
@@ -0,0 +1,4 @@
+16717c6cee907554cbeaefbbc116cd66 *tests/data/fate/vsynth2-r210.avi
+22125248 tests/data/fate/vsynth2-r210.avi
+6ea4fcd93fc83defc8770e85b64b60bb *tests/data/fate/vsynth2-r210.out.rawvideo
+stddev: 0.70 PSNR: 51.12 MAXDIFF: 12 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-rgb b/tests/ref/vsynth/vsynth2-rgb
index 5c9a98e..f86c37c 100644
--- a/tests/ref/vsynth/vsynth2-rgb
+++ b/tests/ref/vsynth/vsynth2-rgb
@@ -1,4 +1,4 @@
-01199075994e44f282fbb6a8e3ccc668 *tests/data/fate/vsynth2-rgb.avi
+188bce319523a1c7d24103aab1ed1bda *tests/data/fate/vsynth2-rgb.avi
15213248 tests/data/fate/vsynth2-rgb.avi
-b2418e0e3a9a8619b31219cbcf24dc82 *tests/data/fate/vsynth2-rgb.out.rawvideo
-stddev: 1.26 PSNR: 46.06 MAXDIFF: 13 bytes: 7603200/ 7603200
+98d0e2854731472c5bf13d8638502d0a *tests/data/fate/vsynth2-rgb.out.rawvideo
+stddev: 1.26 PSNR: 46.10 MAXDIFF: 13 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-roqvideo b/tests/ref/vsynth/vsynth2-roqvideo
index d4c075a..c8b02e7 100644
--- a/tests/ref/vsynth/vsynth2-roqvideo
+++ b/tests/ref/vsynth/vsynth2-roqvideo
@@ -1,4 +1,4 @@
-b46f899b2363065c60f3782ba1f8b7bd *tests/data/fate/vsynth2-roqvideo.roq
-92786 tests/data/fate/vsynth2-roqvideo.roq
-e69fca960dd0911e9b8d589c13e11dc1 *tests/data/fate/vsynth2-roqvideo.out.rawvideo
-stddev: 3.81 PSNR: 36.49 MAXDIFF: 54 bytes: 7603200/ 760320
+1a43cd71c91f2ef42d11a81419bff3bd *tests/data/fate/vsynth2-roqvideo.roq
+94810 tests/data/fate/vsynth2-roqvideo.roq
+97cda6096430c0ab7a43a0e120cd3e91 *tests/data/fate/vsynth2-roqvideo.out.rawvideo
+stddev: 3.81 PSNR: 36.50 MAXDIFF: 49 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth2-rv10 b/tests/ref/vsynth/vsynth2-rv10
index 7afe4fc..3fc93d9 100644
--- a/tests/ref/vsynth/vsynth2-rv10
+++ b/tests/ref/vsynth/vsynth2-rv10
@@ -1,4 +1,4 @@
-b1467b0e8d8cad730e36d1e8ab49d573 *tests/data/fate/vsynth2-rv10.rm
-154310 tests/data/fate/vsynth2-rv10.rm
-61213b91b359697ebcefb9e0a53ac54a *tests/data/fate/vsynth2-rv10.out.rawvideo
+33a2aae3351b0b2121f823057c0e226f *tests/data/fate/vsynth2-rv10.rm
+154321 tests/data/fate/vsynth2-rv10.rm
+b7d733ebedbaa04f49bf7493a907e223 *tests/data/fate/vsynth2-rv10.out.rawvideo
stddev: 5.43 PSNR: 33.42 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-rv20 b/tests/ref/vsynth/vsynth2-rv20
index a3440fa..1251e49 100644
--- a/tests/ref/vsynth/vsynth2-rv20
+++ b/tests/ref/vsynth/vsynth2-rv20
@@ -1,4 +1,4 @@
-96acb098850b9bf309f89e48b08fe96f *tests/data/fate/vsynth2-rv20.rm
-153302 tests/data/fate/vsynth2-rv20.rm
-46f314e70d9bac2e7d82cfc230534977 *tests/data/fate/vsynth2-rv20.out.rawvideo
+4d23a72fe7e29f98f38888804eacd111 *tests/data/fate/vsynth2-rv20.rm
+153304 tests/data/fate/vsynth2-rv20.rm
+6fa5dc1c2f00f858fc4895ad640891a2 *tests/data/fate/vsynth2-rv20.out.rawvideo
stddev: 5.48 PSNR: 33.35 MAXDIFF: 81 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-snow b/tests/ref/vsynth/vsynth2-snow
new file mode 100644
index 0000000..74b6068
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-snow
@@ -0,0 +1,4 @@
+a7bc7eba6ac50f0b417cb9f829feb7a1 *tests/data/fate/vsynth2-snow.avi
+57688 tests/data/fate/vsynth2-snow.avi
+8890189af71a0dd3447c4e8424c9a76b *tests/data/fate/vsynth2-snow.out.rawvideo
+stddev: 10.47 PSNR: 27.72 MAXDIFF: 119 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-snow-hpel b/tests/ref/vsynth/vsynth2-snow-hpel
new file mode 100644
index 0000000..f43263e
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-snow-hpel
@@ -0,0 +1,4 @@
+fa6986c9ebaa087b037d099acefa0ade *tests/data/fate/vsynth2-snow-hpel.avi
+61760 tests/data/fate/vsynth2-snow-hpel.avi
+8680d40905f423999d65b996c4dcb984 *tests/data/fate/vsynth2-snow-hpel.out.rawvideo
+stddev: 10.45 PSNR: 27.74 MAXDIFF: 123 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-snow-ll b/tests/ref/vsynth/vsynth2-snow-ll
new file mode 100644
index 0000000..db2ffa9
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-snow-ll
@@ -0,0 +1,4 @@
+ed109f21012f92ad5ea19451844ae721 *tests/data/fate/vsynth2-snow-ll.avi
+2721746 tests/data/fate/vsynth2-snow-ll.avi
+dde5895817ad9d219f79a52d0bdfb001 *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 e2af545..afad59c 100644
--- a/tests/ref/vsynth/vsynth2-svq1
+++ b/tests/ref/vsynth/vsynth2-svq1
@@ -1,4 +1,4 @@
-c15de1e0b0439981dc94b927b1933889 *tests/data/fate/vsynth2-svq1.mov
-766851 tests/data/fate/vsynth2-svq1.mov
+6e9678439ab7460db1fcc8e41ca1a1e0 *tests/data/fate/vsynth2-svq1.mov
+766701 tests/data/fate/vsynth2-svq1.mov
aa03471dac3f49455a33a2b19fda1098 *tests/data/fate/vsynth2-svq1.out.rawvideo
stddev: 3.23 PSNR: 37.93 MAXDIFF: 61 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-v210 b/tests/ref/vsynth/vsynth2-v210
index eb80b34..1320c38 100644
--- a/tests/ref/vsynth/vsynth2-v210
+++ b/tests/ref/vsynth/vsynth2-v210
@@ -1,4 +1,4 @@
-ddc80f41b9e92c26adbe09567a4c7a1d *tests/data/fate/vsynth2-v210.avi
+6fbbcfee1832fe4c62aacb70454cff62 *tests/data/fate/vsynth2-v210.avi
14752448 tests/data/fate/vsynth2-v210.avi
a627fb50c8276200fd71383977d87ca3 *tests/data/fate/vsynth2-v210.out.rawvideo
stddev: 0.34 PSNR: 57.43 MAXDIFF: 6 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-v308 b/tests/ref/vsynth/vsynth2-v308
new file mode 100644
index 0000000..f32dc5d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-v308
@@ -0,0 +1,4 @@
+1ea64cd6ad32dae72963b8fdf89e96d1 *tests/data/fate/vsynth2-v308.avi
+15213248 tests/data/fate/vsynth2-v308.avi
+d43cb310c130c69214332d74f6ee5f9a *tests/data/fate/vsynth2-v308.out.rawvideo
+stddev: 0.41 PSNR: 55.80 MAXDIFF: 7 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-v408 b/tests/ref/vsynth/vsynth2-v408
new file mode 100644
index 0000000..333a4e3
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-v408
@@ -0,0 +1,4 @@
+b4cdf2351f908fc308d8693d0cee69e1 *tests/data/fate/vsynth2-v408.avi
+20282048 tests/data/fate/vsynth2-v408.avi
+dde5895817ad9d219f79a52d0bdfb001 *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 188b518..6e325ba 100644
--- a/tests/ref/vsynth/vsynth2-wmv1
+++ b/tests/ref/vsynth/vsynth2-wmv1
@@ -1,4 +1,4 @@
-73f3b72208ed1e61be60f1412dbf35e2 *tests/data/fate/vsynth2-wmv1.avi
-129518 tests/data/fate/vsynth2-wmv1.avi
-81eee429b665254d19a06607463c0b5e *tests/data/fate/vsynth2-wmv1.out.rawvideo
+3099f5514693a609180ab5761dc8d4ca *tests/data/fate/vsynth2-wmv1.avi
+129510 tests/data/fate/vsynth2-wmv1.avi
+dec44e3c04db4fef49a7728f164d9159 *tests/data/fate/vsynth2-wmv1.out.rawvideo
stddev: 5.33 PSNR: 33.60 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-wmv2 b/tests/ref/vsynth/vsynth2-wmv2
index 25c0dee..72fe406 100644
--- a/tests/ref/vsynth/vsynth2-wmv2
+++ b/tests/ref/vsynth/vsynth2-wmv2
@@ -1,4 +1,4 @@
-c7db61ce6fc07e8fb9a7204992c2e4c4 *tests/data/fate/vsynth2-wmv2.avi
-129848 tests/data/fate/vsynth2-wmv2.avi
-288bdf1b411b814a067ceb00ac6b9d16 *tests/data/fate/vsynth2-wmv2.out.rawvideo
+c8d1d1371bd09add388c32f3259ef555 *tests/data/fate/vsynth2-wmv2.avi
+129852 tests/data/fate/vsynth2-wmv2.avi
+b4de16a0d302c52702f7a4362da989bc *tests/data/fate/vsynth2-wmv2.out.rawvideo
stddev: 5.33 PSNR: 33.59 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-y41p b/tests/ref/vsynth/vsynth2-y41p
new file mode 100644
index 0000000..9c782f8
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-y41p
@@ -0,0 +1,4 @@
+522ebf5fbf98aeec5ee6b39de1c1afc0 *tests/data/fate/vsynth2-y41p.avi
+7610048 tests/data/fate/vsynth2-y41p.avi
+d27a84ccdac09055724d122e03fea82a *tests/data/fate/vsynth2-y41p.out.rawvideo
+stddev: 1.07 PSNR: 47.54 MAXDIFF: 21 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-yuv b/tests/ref/vsynth/vsynth2-yuv
index d79e986..066cfec 100644
--- a/tests/ref/vsynth/vsynth2-yuv
+++ b/tests/ref/vsynth/vsynth2-yuv
@@ -1,4 +1,4 @@
-d08219372af7a764c1afbc99a1002fe0 *tests/data/fate/vsynth2-yuv.avi
+f48f08c67097b3c35b1105f24ef68a0c *tests/data/fate/vsynth2-yuv.avi
7610048 tests/data/fate/vsynth2-yuv.avi
dde5895817ad9d219f79a52d0bdfb001 *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 0000000..b76cee4
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-yuv4
@@ -0,0 +1,4 @@
+1dcf2c21fe3ff1b57f9280a4fd550d14 *tests/data/fate/vsynth2-yuv4.avi
+7610048 tests/data/fate/vsynth2-yuv4.avi
+dde5895817ad9d219f79a52d0bdfb001 *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 0000000..d956a04
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-zlib
@@ -0,0 +1,4 @@
+f2c6b3c88f07f0ed08dd25ca654854fb *tests/data/fate/vsynth2-zlib.avi
+12517176 tests/data/fate/vsynth2-zlib.avi
+98d0e2854731472c5bf13d8638502d0a *tests/data/fate/vsynth2-zlib.out.rawvideo
+stddev: 1.26 PSNR: 46.10 MAXDIFF: 13 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-zmbv b/tests/ref/vsynth/vsynth2-zmbv
new file mode 100644
index 0000000..93e0b6a
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-zmbv
@@ -0,0 +1,4 @@
+e9cc761eb3fedc36ce5f97744196ed8b *tests/data/fate/vsynth2-zmbv.avi
+1808720 tests/data/fate/vsynth2-zmbv.avi
+ee68a5292fd0745834246b4ec0d85e9b *tests/data/fate/vsynth2-zmbv.out.rawvideo
+stddev: 8.12 PSNR: 29.94 MAXDIFF: 32 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth3-amv b/tests/ref/vsynth/vsynth3-amv
new file mode 100644
index 0000000..bbfba3e
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-amv
@@ -0,0 +1,4 @@
+4d0844cd148bd9fa8155b72cc4a6e991 *tests/data/fate/vsynth3-amv.avi
+33928 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 0000000..8486b04
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-asv1
@@ -0,0 +1,4 @@
+642c88813798d857d236f21bb36d8783 *tests/data/fate/vsynth3-asv1.avi
+34700 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 0000000..2a5d23b
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-asv2
@@ -0,0 +1,4 @@
+45f865e3d1cac1ef59ae4689f41dead5 *tests/data/fate/vsynth3-asv2.avi
+36204 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 0000000..9a2daa4
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-cljr
@@ -0,0 +1,4 @@
+c05ee9983a4f8fe62d7270507a87655b *tests/data/fate/vsynth3-cljr.avi
+68048 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-ffv1 b/tests/ref/vsynth/vsynth3-ffv1
new file mode 100644
index 0000000..cdd011a
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffv1
@@ -0,0 +1,4 @@
+b781c01d152c5a040ee71b2421b6d8e6 *tests/data/fate/vsynth3-ffv1.avi
+62190 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 0000000..6e2c4e0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffv1.0
@@ -0,0 +1,4 @@
+aa9187b44d9d8ff4d0ac7b9c5301830c *tests/data/fate/vsynth3-ffv1.0.avi
+52252 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 0000000..c89611f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffvhuff
@@ -0,0 +1,4 @@
+bc18700e9ce7947fe4c5ffc71457f3c1 *tests/data/fate/vsynth3-ffvhuff.avi
+90206 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 0000000..2d775d9
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffvhuff420p12
@@ -0,0 +1,4 @@
+9b3e44ccdd28614f588804a0682db312 *tests/data/fate/vsynth3-ffvhuff420p12.avi
+175256 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 0000000..d62ee0f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffvhuff422p10left
@@ -0,0 +1,4 @@
+5afec2536440c892919a1569c7109858 *tests/data/fate/vsynth3-ffvhuff422p10left.avi
+173548 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 0000000..8446a7f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffvhuff444
@@ -0,0 +1,4 @@
+134851e6f9702e83c4c9aa6e5ff1eaa4 *tests/data/fate/vsynth3-ffvhuff444.avi
+151362 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 0000000..842104f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffvhuff444p16
@@ -0,0 +1,4 @@
+1a6e53646d0988bd67ced92923439e51 *tests/data/fate/vsynth3-ffvhuff444p16.avi
+320084 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 0000000..38a34bd
--- /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 0000000..31d0d3f
--- /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 0000000..7abe2b5
--- /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 0000000..0a16b65
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-huffyuv
@@ -0,0 +1,4 @@
+27cd1ec1151b7456117f98a8cdf281cd *tests/data/fate/vsynth3-huffyuv.avi
+116346 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 0000000..95f4422
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-huffyuvbgr24
@@ -0,0 +1,4 @@
+a7bf0c82277d59d425ebe4af93f75e27 *tests/data/fate/vsynth3-huffyuvbgr24.avi
+165154 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 0000000..32eecd4
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-huffyuvbgra
@@ -0,0 +1,4 @@
+9d360ce029b5ec86f0f6c80c44edf9bd *tests/data/fate/vsynth3-huffyuvbgra.avi
+179598 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 0000000..6b5f110
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-jpeg2000
@@ -0,0 +1,4 @@
+1c49dca7b2d828b9a551bf66f3324f3d *tests/data/fate/vsynth3-jpeg2000.avi
+63768 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 0000000..1087241
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-jpeg2000-97
@@ -0,0 +1,4 @@
+9ce2c4690cbc85aae9e9e5227e74eb94 *tests/data/fate/vsynth3-jpeg2000-97.avi
+65360 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 0000000..b035373
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-jpegls
@@ -0,0 +1,4 @@
+13bf416e04554609ddc2830912ff1d89 *tests/data/fate/vsynth3-jpegls.avi
+133164 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 0000000..47db0c1
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ljpeg
@@ -0,0 +1,4 @@
+39cd774ffe47c804f2f58d5bbcf7b0a5 *tests/data/fate/vsynth3-ljpeg.avi
+105840 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 0000000..25036c8
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mjpeg
@@ -0,0 +1,4 @@
+cf68ecc19e6c07d2a0c211e6ad1e3d9f *tests/data/fate/vsynth3-mjpeg.avi
+64804 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 0000000..23c58bb
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mjpeg-422
@@ -0,0 +1,4 @@
+c1f42031676078a7cfc38a7eb53c89e8 *tests/data/fate/vsynth3-mjpeg-422.avi
+69458 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 0000000..d17df66
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mjpeg-444
@@ -0,0 +1,4 @@
+893c830a9635aaf686f53372cbe5e0ed *tests/data/fate/vsynth3-mjpeg-444.avi
+70584 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-mpeg1 b/tests/ref/vsynth/vsynth3-mpeg1
new file mode 100644
index 0000000..7a3b484
--- /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 0000000..adfa418
--- /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 0000000..d2e5b9f
--- /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 0000000..2247f28
--- /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 0000000..3b2f714
--- /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 0000000..fe2720e
--- /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 0000000..d732912
--- /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 0000000..faf1071
--- /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 0000000..8ac72f1
--- /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 0000000..02cf68d
--- /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 0000000..ec5b9e2
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-adap
@@ -0,0 +1,4 @@
+40a36d85d24df09ba8695ab4a16e0843 *tests/data/fate/vsynth3-mpeg4-adap.avi
+43702 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 0000000..7274207
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-adv
@@ -0,0 +1,4 @@
+c3b4a5d4d642b6fea981b4f762a8081b *tests/data/fate/vsynth3-mpeg4-adv.avi
+32292 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 0000000..4f54a60
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-error
@@ -0,0 +1,4 @@
+cee34cadd91b861d424f493acb9289ab *tests/data/fate/vsynth3-mpeg4-error.avi
+38208 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 0000000..8cb1032
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-nr
@@ -0,0 +1,4 @@
+b0f9c0997901e00ca2582ebe20f120e5 *tests/data/fate/vsynth3-mpeg4-nr.avi
+36496 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 0000000..f96b1c6
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-nsse
@@ -0,0 +1,4 @@
+4b2c5176f1fc2134612f3b512e8f936a *tests/data/fate/vsynth3-mpeg4-nsse.avi
+41976 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 0000000..f17474f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-qpel
@@ -0,0 +1,4 @@
+5e4bb1c9bd845896891ca5fe418948a3 *tests/data/fate/vsynth3-mpeg4-qpel.avi
+42618 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 0000000..1691e1f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-qprd
@@ -0,0 +1,4 @@
+af2517de1718262000b76c1da0bd100d *tests/data/fate/vsynth3-mpeg4-qprd.avi
+61826 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 0000000..36c771c
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-rc
@@ -0,0 +1,4 @@
+ddc944ea93e7e87bfae36bb85ee36c91 *tests/data/fate/vsynth3-mpeg4-rc.avi
+81088 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 0000000..2b59322
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-thread
@@ -0,0 +1,4 @@
+601ac957b2a8cc4d9f5812824b7d1e0d *tests/data/fate/vsynth3-mpeg4-thread.avi
+74578 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 0000000..2a112a7
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpng
@@ -0,0 +1,4 @@
+f1a9b596c743645e5518a41e4fe2b043 *tests/data/fate/vsynth3-mpng.avi
+179800 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 0000000..dc653fc
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-msmpeg4
@@ -0,0 +1,4 @@
+68d0838cf0e66a3092acaf347061cea8 *tests/data/fate/vsynth3-msmpeg4.avi
+32440 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 0000000..58d6e4f2
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-msmpeg4v2
@@ -0,0 +1,4 @@
+dfba0b605760d087cb6f5c0ce45f671a *tests/data/fate/vsynth3-msmpeg4v2.avi
+32626 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 0000000..f63a7a7
--- /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 0000000..99cfc13
--- /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 0000000..6f93232
--- /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 0000000..8362ee5
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-r210
@@ -0,0 +1,4 @@
+5f6e0ba5fc9a1b1440e80aebcb41d57a *tests/data/fate/vsynth3-r210.avi
+442048 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 0000000..f407523
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-rgb
@@ -0,0 +1,4 @@
+7b20b20734352d33b18b802513f5fc47 *tests/data/fate/vsynth3-rgb.avi
+180248 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 0000000..b51fa03
--- /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 0000000..d3275f0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-v210
@@ -0,0 +1,4 @@
+d2f5e07f0c0e917d80d63f39d683919e *tests/data/fate/vsynth3-v210.avi
+224448 tests/data/fate/vsynth3-v210.avi
+0cf7cf68724fa5146b1667e4fa08b0e1 *tests/data/fate/vsynth3-v210.out.rawvideo
+stddev: 2.12 PSNR: 41.58 MAXDIFF: 26 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-v308 b/tests/ref/vsynth/vsynth3-v308
new file mode 100644
index 0000000..c70678c
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-v308
@@ -0,0 +1,4 @@
+53dacfdcf280d58b465da71583f4af26 *tests/data/fate/vsynth3-v308.avi
+180248 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 0000000..da87e81
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-v408
@@ -0,0 +1,4 @@
+ac8ea8d8f38b5c6b76c2fef9667a172d *tests/data/fate/vsynth3-v408.avi
+238048 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 0000000..568d3cf
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-wmv1
@@ -0,0 +1,4 @@
+b13831403f2dfdf3e5e6d33b03dbc687 *tests/data/fate/vsynth3-wmv1.avi
+32654 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 0000000..9d20b7b
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-wmv2
@@ -0,0 +1,4 @@
+1a8a90c91240f84d0ceca4f20ae4be27 *tests/data/fate/vsynth3-wmv2.avi
+33976 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-yuv b/tests/ref/vsynth/vsynth3-yuv
new file mode 100644
index 0000000..29abb30
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-yuv
@@ -0,0 +1,4 @@
+d0a6f0188d9cc70919865ebc59cc0179 *tests/data/fate/vsynth3-yuv.avi
+93548 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 0000000..70f8274
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-yuv4
@@ -0,0 +1,4 @@
+4b5196292069c5301446b546d0148783 *tests/data/fate/vsynth3-yuv4.avi
+93548 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 0000000..e69e289
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-zlib
@@ -0,0 +1,4 @@
+278541a159accf11fec8914cad41e85c *tests/data/fate/vsynth3-zlib.avi
+174878 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/vsynth1/cljr b/tests/ref/vsynth1/cljr
new file mode 100644
index 0000000..6002bbb
--- /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 0000000..6d8b143
--- /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/vsynth2/cljr b/tests/ref/vsynth2/cljr
new file mode 100644
index 0000000..f4cf7d1
--- /dev/null
+++ b/tests/ref/vsynth2/cljr
@@ -0,0 +1,4 @@
+fdc1926e0a599de94513f0a3472b598f *./tests/data/vsynth2/cljr.avi
+5075660 ./tests/data/vsynth2/cljr.avi
+7df03229ee6361ea11a0d83d4926cb10 *./tests/data/cljr.vsynth2.out.yuv
+stddev: 10.30 PSNR: 27.87 MAXDIFF: 65 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth2/huffyuv b/tests/ref/vsynth2/huffyuv
new file mode 100644
index 0000000..e59b53c
--- /dev/null
+++ b/tests/ref/vsynth2/huffyuv
@@ -0,0 +1,4 @@
+ed66182be0d515e8b6cb970ad63162da *./tests/data/vsynth2/huffyuv.avi
+6455232 ./tests/data/vsynth2/huffyuv.avi
+dde5895817ad9d219f79a52d0bdfb001 *./tests/data/huffyuv.vsynth2.out.yuv
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth2/yuv b/tests/ref/vsynth2/yuv
new file mode 100644
index 0000000..699ebc9
--- /dev/null
+++ b/tests/ref/vsynth2/yuv
@@ -0,0 +1,4 @@
+3d5ee6d2023bc15bba898819e4977e46 *./tests/data/vsynth2/yuv.avi
+7610060 ./tests/data/vsynth2/yuv.avi
+dde5895817ad9d219f79a52d0bdfb001 *./tests/data/yuv.vsynth2.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 3728d44..86bc446 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"
@@ -47,8 +50,8 @@ ENC_OPTS="$COMMON_OPTS -threads 1 -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 69c88c2..cfa7f81 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 0000000..ad37b02
--- /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 66eaf82..b35ed81 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;
- }
+ noseek = fseek(f[0], 0, SEEK_SET) ||
+ fseek(f[1], 0, SEEK_SET);
- 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]);
+ if (!noseek) {
+ for (i = 0; i < 2; i++) {
+ uint8_t *p = buf[i];
+ if (fread(p, 1, 12, f[i]) != 12)
return 1;
- }
- }
- }
-
- max = (1LL << (8 * len)) - 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 (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 (!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 (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,63 @@ 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 (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 (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 0000000..9f355a3
--- /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 2fdc491..dde6e03 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
*/
@@ -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 0b7f67e..91da8b5 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 59244a8..3bd62b7 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 0000000..fc60e86
--- /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 0000000..9800ab5
--- /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 0000000..22bb712
--- /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 0000000..4600702
--- /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/crypto_bench.c b/tools/crypto_bench.c
new file mode 100644
index 0000000..6037ead
--- /dev/null
+++ b/tools/crypto_bench.c
@@ -0,0 +1,407 @@
+/*
+ * 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/cast5.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_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);
+}
+
+/***************************************************************************
+ * 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/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_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_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);
+}
+
+#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_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);
+}
+
+#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("CAST-128", cast128, "crc:456aa584")
+};
+
+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 74588c1..84feda9 100644
--- a/tools/cws2fws.c
+++ b/tools/cws2fws.c
@@ -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 0000000..02371e0
--- /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 0000000..c2a295c
--- /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 0000000..0530d28
--- /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 0000000..944f374
--- /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 0000000..6942527
--- /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 0000000..625f531
--- /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 0000000..d9ca37e
--- /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 12f1066..964322d 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");
}
}
}
diff --git a/tools/ismindex.c b/tools/ismindex.c
index 387b185..3e53046 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"
@@ -336,7 +338,7 @@ 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) {
ret = AVERROR(ENOMEM);
goto fail;
diff --git a/tools/make_chlayout_test b/tools/make_chlayout_test
new file mode 100755
index 0000000..fcdbda3
--- /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 0000000..e1d3d60
--- /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 0000000..7d87c5e
--- /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 e681d6d..cbdbf8d 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 c6398fe..61cb5cc 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 0000000..f379723
--- /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 678f4dd..78327de 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,10 +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;
+#ifndef AV_READ_TIME
+#define AV_READ_TIME(x) 0
+#endif
+
static void probe(AVProbeData *pd, int type, int p, int size)
{
int i = 0;
@@ -36,7 +43,10 @@ static void probe(AVProbeData *pd, int type, int p, int size)
if (fmt->flags & AVFMT_NOFILE)
continue;
if (fmt->read_probe) {
- int score = fmt->read_probe(pd);
+ 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 +59,45 @@ 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++;
+ }
+}
+
+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;
+
+ if(argc >= 2)
+ retry_count = atoi(argv[1]);
+ if(argc >= 3)
+ max_size = atoi(argv[2]);
+
+ 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 +105,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 +172,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 0db5ca2..97be019 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 0000000..c42b28d
--- /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/trasher.c b/tools/trasher.c
index 35625e9..aaa09f4 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
*/
@@ -56,7 +56,10 @@ int main(int argc, char **argv)
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);
+ if (fseek(f, pos, SEEK_SET) < 0) {
+ fprintf(stderr, "seek failed\n");
+ return 1;
+ }
if (maxburst < 0)
burst = -maxburst;
diff --git a/tools/uncoded_frame.c b/tools/uncoded_frame.c
new file mode 100644
index 0000000..53e71ea
--- /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_close(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 0000000..ccea99b
--- /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 0000000..65b1794
--- /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 0000000..d47bf21
--- /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 0000000..a7d1126
--- /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 6f72b2c..f9754eb 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
OpenPOWER on IntegriCloud