summaryrefslogtreecommitdiff
Diffstat
-rw-r--r--.gitignore32
-rw-r--r--CREDITS59
-rw-r--r--Changelog487
-rw-r--r--INSTALL9
-rw-r--r--LICENSE69
-rw-r--r--MAINTAINERS544
-rw-r--r--Makefile108
-rw-r--r--README12
-rw-r--r--RELEASE2
-rw-r--r--arch.mak5
-rw-r--r--avconv.c2393
-rw-r--r--avconv.h374
-rw-r--r--avconv_filter.c655
-rw-r--r--avconv_opt.c2341
-rw-r--r--avplay.c2976
-rw-r--r--avprobe.c969
-rw-r--r--avserver.c4685
-rw-r--r--cmdutils.c684
-rw-r--r--cmdutils.h111
-rw-r--r--cmdutils_common_opts.h13
-rw-r--r--common.mak76
-rw-r--r--compat/aix/math.h14
-rw-r--r--compat/avisynth/avisynth_c.h879
-rw-r--r--compat/avisynth/avisynth_c_25.h68
-rw-r--r--compat/avisynth/avxsynth_c.h727
-rw-r--r--compat/avisynth/windowsPorts/basicDataTypeConversions.h85
-rw-r--r--compat/avisynth/windowsPorts/windows2linux.h77
-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.h162
-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.h26
-rw-r--r--compat/w32pthreads.h15
-rwxr-xr-xconfigure978
-rw-r--r--doc/APIchanges902
-rw-r--r--doc/Doxyfile19
-rw-r--r--doc/Makefile105
-rw-r--r--doc/RELEASE_NOTES101
-rw-r--r--doc/authors.texi11
-rw-r--r--doc/avconv.texi1112
-rw-r--r--doc/avplay.texi182
-rw-r--r--doc/avprobe.texi141
-rw-r--r--doc/avserver.conf372
-rw-r--r--doc/avserver.texi276
-rw-r--r--doc/avtools-common-opts.texi184
-rw-r--r--doc/bitstream_filters.texi65
-rw-r--r--doc/build_system.txt25
-rw-r--r--doc/codecs.texi1093
-rw-r--r--doc/decoders.texi202
-rw-r--r--doc/default.css165
-rw-r--r--doc/demuxers.texi372
-rw-r--r--doc/developer.texi419
-rw-r--r--doc/devices.texi21
-rw-r--r--doc/encoders.texi1241
-rw-r--r--doc/errno.txt174
-rw-r--r--doc/eval.texi156
-rw-r--r--doc/examples/Makefile38
-rw-r--r--doc/examples/README18
-rw-r--r--doc/examples/decoding_encoding.c650
-rw-r--r--doc/examples/demuxing.c341
-rw-r--r--doc/examples/filtering_audio.c265
-rw-r--r--doc/examples/filtering_video.c251
-rw-r--r--doc/examples/metadata.c56
-rw-r--r--doc/examples/muxing.c564
-rw-r--r--doc/examples/resampling_audio.c211
-rw-r--r--doc/examples/scaling_video.c141
-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.texi1454
-rw-r--r--doc/ffmpeg.txt47
-rw-r--r--doc/ffplay.texi277
-rw-r--r--doc/ffprobe.texi637
-rw-r--r--doc/ffprobe.xsd245
-rw-r--r--doc/ffserver.conf371
-rw-r--r--doc/ffserver.texi320
-rw-r--r--doc/fftools-common-opts.texi292
-rw-r--r--doc/filter_design.txt270
-rw-r--r--doc/filters.texi8910
-rw-r--r--doc/formats.texi188
-rw-r--r--doc/general.texi277
-rw-r--r--doc/git-howto.texi91
-rw-r--r--doc/git-howto.txt19
-rw-r--r--doc/indevs.texi629
-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.texi44
-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.texi741
-rw-r--r--doc/nut.texi5
-rw-r--r--doc/optimization.txt8
-rw-r--r--doc/outdevs.texi262
-rw-r--r--doc/platform.texi65
-rw-r--r--doc/print_options.c10
-rw-r--r--doc/protocols.texi489
-rw-r--r--doc/resampler.texi232
-rw-r--r--doc/scaler.texi119
-rw-r--r--doc/snow.txt638
-rw-r--r--doc/soc.txt6
-rw-r--r--doc/swresample.txt46
-rw-r--r--doc/t2h.init151
-rwxr-xr-xdoc/texi2pod.pl77
-rw-r--r--doc/utils.texi1064
-rw-r--r--ffmpeg.c3457
-rw-r--r--ffmpeg.h453
-rw-r--r--ffmpeg_filter.c925
-rw-r--r--ffmpeg_opt.c2885
-rw-r--r--ffplay.c3628
-rw-r--r--ffprobe.c2714
-rw-r--r--ffserver.c4744
-rw-r--r--libavcodec/012v.c159
-rw-r--r--libavcodec/4xm.c168
-rw-r--r--libavcodec/8bps.c31
-rw-r--r--libavcodec/8svx.c121
-rw-r--r--libavcodec/Makefile204
-rw-r--r--libavcodec/a64colors.h8
-rw-r--r--libavcodec/a64enc.h58
-rw-r--r--libavcodec/a64multienc.c45
-rw-r--r--libavcodec/a64tables.h8
-rw-r--r--libavcodec/aac.h35
-rw-r--r--libavcodec/aac_ac3_parser.c8
-rw-r--r--libavcodec/aac_ac3_parser.h8
-rw-r--r--libavcodec/aac_adtstoasc_bsf.c14
-rw-r--r--libavcodec/aac_parser.c8
-rw-r--r--libavcodec/aac_tablegen.c8
-rw-r--r--libavcodec/aac_tablegen.h8
-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.c22
-rw-r--r--libavcodec/aacdec.c264
-rw-r--r--libavcodec/aacdectab.h8
-rw-r--r--libavcodec/aacenc.c38
-rw-r--r--libavcodec/aacenc.h20
-rw-r--r--libavcodec/aacps.c31
-rw-r--r--libavcodec/aacps.h8
-rw-r--r--libavcodec/aacps_tablegen.c8
-rw-r--r--libavcodec/aacps_tablegen.h8
-rw-r--r--libavcodec/aacpsdata.c8
-rw-r--r--libavcodec/aacpsdsp.c10
-rw-r--r--libavcodec/aacpsdsp.h9
-rw-r--r--libavcodec/aacpsy.c113
-rw-r--r--libavcodec/aacsbr.c101
-rw-r--r--libavcodec/aacsbr.h10
-rw-r--r--libavcodec/aacsbrdata.h14
-rw-r--r--libavcodec/aactab.c8
-rw-r--r--libavcodec/aactab.h8
-rw-r--r--libavcodec/aandcttab.c8
-rw-r--r--libavcodec/aandcttab.h8
-rw-r--r--libavcodec/aasc.c66
-rw-r--r--libavcodec/ac3.c8
-rw-r--r--libavcodec/ac3.h10
-rw-r--r--libavcodec/ac3_parser.c8
-rw-r--r--libavcodec/ac3_parser.h8
-rw-r--r--libavcodec/ac3dec.c44
-rw-r--r--libavcodec/ac3dec.h14
-rw-r--r--libavcodec/ac3dec_data.c8
-rw-r--r--libavcodec/ac3dec_data.h8
-rw-r--r--libavcodec/ac3dsp.c55
-rw-r--r--libavcodec/ac3dsp.h15
-rw-r--r--libavcodec/ac3enc.c22
-rw-r--r--libavcodec/ac3enc.h8
-rw-r--r--libavcodec/ac3enc_fixed.c23
-rw-r--r--libavcodec/ac3enc_float.c22
-rw-r--r--libavcodec/ac3enc_opts_template.c8
-rw-r--r--libavcodec/ac3enc_template.c39
-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.c356
-rw-r--r--libavcodec/adpcm.h12
-rw-r--r--libavcodec/adpcm_data.c44
-rw-r--r--libavcodec/adpcm_data.h14
-rw-r--r--libavcodec/adpcmenc.c60
-rw-r--r--libavcodec/adx.c13
-rw-r--r--libavcodec/adx.h8
-rw-r--r--libavcodec/adx_parser.c8
-rw-r--r--libavcodec/adxdec.c15
-rw-r--r--libavcodec/adxenc.c12
-rw-r--r--libavcodec/aic.c17
-rw-r--r--libavcodec/alac.c104
-rw-r--r--libavcodec/alac_data.c8
-rw-r--r--libavcodec/alac_data.h8
-rw-r--r--libavcodec/alacenc.c21
-rw-r--r--libavcodec/allcodecs.c134
-rw-r--r--libavcodec/alpha/asm.h8
-rw-r--r--libavcodec/alpha/dsputil_alpha.c12
-rw-r--r--libavcodec/alpha/dsputil_alpha.h8
-rw-r--r--libavcodec/alpha/dsputil_alpha_asm.S8
-rw-r--r--libavcodec/alpha/hpeldsp_alpha.c8
-rw-r--r--libavcodec/alpha/hpeldsp_alpha.h8
-rw-r--r--libavcodec/alpha/hpeldsp_alpha_asm.S9
-rw-r--r--libavcodec/alpha/motion_est_alpha.c8
-rw-r--r--libavcodec/alpha/motion_est_mvi_asm.S8
-rw-r--r--libavcodec/alpha/mpegvideo_alpha.c8
-rw-r--r--libavcodec/alpha/regdef.h8
-rw-r--r--libavcodec/alpha/simple_idct_alpha.c8
-rw-r--r--libavcodec/alsdec.c98
-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.c85
-rw-r--r--libavcodec/apedec.c31
-rw-r--r--libavcodec/api-example.c596
-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/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/dsputil_arm.S8
-rw-r--r--libavcodec/arm/dsputil_arm.h8
-rw-r--r--libavcodec/arm/dsputil_armv6.S8
-rw-r--r--libavcodec/arm/dsputil_init_arm.c10
-rw-r--r--libavcodec/arm/dsputil_init_armv5te.c10
-rw-r--r--libavcodec/arm/dsputil_init_armv6.c10
-rw-r--r--libavcodec/arm/dsputil_init_neon.c10
-rw-r--r--libavcodec/arm/dsputil_neon.S8
-rw-r--r--libavcodec/arm/fft_fixed_init_arm.c10
-rw-r--r--libavcodec/arm/fft_fixed_neon.S10
-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.c8
-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_armv6.S8
-rw-r--r--libavcodec/arm/h264dsp_init_arm.c12
-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.c9
-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/int_neon.S10
-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/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/neon.S8
-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/synth_filter_neon.S8
-rw-r--r--libavcodec/arm/synth_filter_vfp.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.S173
-rw-r--r--libavcodec/ass.c111
-rw-r--r--libavcodec/ass.h45
-rw-r--r--libavcodec/ass_split.c476
-rw-r--r--libavcodec/ass_split.h172
-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.c18
-rw-r--r--libavcodec/atrac.c11
-rw-r--r--libavcodec/atrac.h11
-rw-r--r--libavcodec/atrac1.c19
-rw-r--r--libavcodec/atrac1data.h8
-rw-r--r--libavcodec/atrac3.c51
-rw-r--r--libavcodec/atrac3data.h8
-rw-r--r--libavcodec/audio_frame_queue.c151
-rw-r--r--libavcodec/audio_frame_queue.h14
-rw-r--r--libavcodec/audioconvert.c116
-rw-r--r--libavcodec/audioconvert.h79
-rw-r--r--libavcodec/aura.c12
-rw-r--r--libavcodec/avcodec.h994
-rw-r--r--libavcodec/avfft.c10
-rw-r--r--libavcodec/avfft.h8
-rw-r--r--libavcodec/avpacket.c192
-rw-r--r--libavcodec/avpicture.c73
-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.c112
-rw-r--r--libavcodec/bethsoftvideo.c17
-rw-r--r--libavcodec/bethsoftvideo.h8
-rw-r--r--libavcodec/bfi.c20
-rw-r--r--libavcodec/bfin/config_bfin.h8
-rw-r--r--libavcodec/bfin/dsputil_bfin.c8
-rw-r--r--libavcodec/bfin/dsputil_bfin.h8
-rw-r--r--libavcodec/bfin/fdct_bfin.S16
-rw-r--r--libavcodec/bfin/hpel_pixels_bfin.S9
-rw-r--r--libavcodec/bfin/hpeldsp_bfin.c8
-rw-r--r--libavcodec/bfin/hpeldsp_bfin.h11
-rw-r--r--libavcodec/bfin/idct_bfin.S14
-rw-r--r--libavcodec/bfin/mathops.h8
-rw-r--r--libavcodec/bfin/mpegvideo_bfin.c17
-rw-r--r--libavcodec/bfin/pixels_bfin.S10
-rw-r--r--libavcodec/bfin/vp3_bfin.c8
-rw-r--r--libavcodec/bfin/vp3_bfin.h8
-rw-r--r--libavcodec/bfin/vp3_idct_bfin.S8
-rw-r--r--libavcodec/bgmc.c18
-rw-r--r--libavcodec/bgmc.h12
-rw-r--r--libavcodec/bink.c88
-rw-r--r--libavcodec/binkaudio.c20
-rw-r--r--libavcodec/binkdata.h8
-rw-r--r--libavcodec/binkdsp.c8
-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.c79
-rw-r--r--libavcodec/bitstream_filter.c16
-rw-r--r--libavcodec/bmp.c75
-rw-r--r--libavcodec/bmp.h12
-rw-r--r--libavcodec/bmp_parser.c91
-rw-r--r--libavcodec/bmpenc.c39
-rw-r--r--libavcodec/bmv.c29
-rw-r--r--libavcodec/brender_pix.c219
-rw-r--r--libavcodec/bytestream.h21
-rw-r--r--libavcodec/c93.c25
-rw-r--r--libavcodec/cabac.c157
-rw-r--r--libavcodec/cabac.h8
-rw-r--r--libavcodec/cabac_functions.h34
-rw-r--r--libavcodec/cavs.c18
-rw-r--r--libavcodec/cavs.h10
-rw-r--r--libavcodec/cavs_parser.c8
-rw-r--r--libavcodec/cavsdata.c8
-rw-r--r--libavcodec/cavsdec.c62
-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.h10
-rw-r--r--libavcodec/cdgraphics.c34
-rw-r--r--libavcodec/cdxl.c30
-rw-r--r--libavcodec/celp_filters.c22
-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.c267
-rw-r--r--libavcodec/cljr.c70
-rw-r--r--libavcodec/cllc.c23
-rw-r--r--libavcodec/cngdec.c12
-rw-r--r--libavcodec/cngenc.c8
-rw-r--r--libavcodec/codec_desc.c412
-rw-r--r--libavcodec/cook.c66
-rw-r--r--libavcodec/cook_parser.c8
-rw-r--r--libavcodec/cookdata.h8
-rw-r--r--libavcodec/copy_block.h41
-rw-r--r--libavcodec/cos_tablegen.c10
-rw-r--r--libavcodec/cpia.c233
-rw-r--r--libavcodec/crystalhd.c1223
-rw-r--r--libavcodec/cscd.c142
-rw-r--r--libavcodec/cyuv.c30
-rw-r--r--libavcodec/dca.c12
-rw-r--r--libavcodec/dca.h8
-rw-r--r--libavcodec/dca_parser.c18
-rw-r--r--libavcodec/dcadata.h42
-rw-r--r--libavcodec/dcadec.c670
-rw-r--r--libavcodec/dcadsp.c8
-rw-r--r--libavcodec/dcadsp.h8
-rw-r--r--libavcodec/dcaenc.c974
-rw-r--r--libavcodec/dcaenc.h113
-rw-r--r--libavcodec/dcahuff.h8
-rw-r--r--libavcodec/dct-test.c87
-rw-r--r--libavcodec/dct.c8
-rw-r--r--libavcodec/dct.h11
-rw-r--r--libavcodec/dct32.c8
-rw-r--r--libavcodec/dct32.h8
-rw-r--r--libavcodec/dct32_fixed.c8
-rw-r--r--libavcodec/dct32_float.c8
-rw-r--r--libavcodec/dctref.c8
-rw-r--r--libavcodec/dctref.h8
-rw-r--r--libavcodec/dfa.c42
-rw-r--r--libavcodec/dirac.c48
-rw-r--r--libavcodec/dirac.h11
-rw-r--r--libavcodec/dirac_arith.c116
-rw-r--r--libavcodec/dirac_arith.h190
-rw-r--r--libavcodec/dirac_dwt.c571
-rw-r--r--libavcodec/dirac_dwt.h123
-rw-r--r--libavcodec/dirac_parser.c12
-rw-r--r--libavcodec/diracdec.c1939
-rw-r--r--libavcodec/diracdsp.c201
-rw-r--r--libavcodec/diracdsp.h67
-rw-r--r--libavcodec/dnxhd_parser.c50
-rw-r--r--libavcodec/dnxhddata.c707
-rw-r--r--libavcodec/dnxhddata.h18
-rw-r--r--libavcodec/dnxhddec.c78
-rw-r--r--libavcodec/dnxhdenc.c102
-rw-r--r--libavcodec/dnxhdenc.h10
-rw-r--r--libavcodec/dpcm.c19
-rw-r--r--libavcodec/dpx.c296
-rw-r--r--libavcodec/dpx_parser.c108
-rw-r--r--libavcodec/dpxenc.c155
-rw-r--r--libavcodec/dsicinav.c71
-rw-r--r--libavcodec/dsputil.c247
-rw-r--r--libavcodec/dsputil.h19
-rw-r--r--libavcodec/dsputil_template.c16
-rw-r--r--libavcodec/dump_extradata_bsf.c13
-rw-r--r--libavcodec/dv.c46
-rw-r--r--libavcodec/dv_profile.c46
-rw-r--r--libavcodec/dv_profile.h14
-rw-r--r--libavcodec/dv_tablegen.c8
-rw-r--r--libavcodec/dv_tablegen.h8
-rw-r--r--libavcodec/dv_vlc_data.h8
-rw-r--r--libavcodec/dvbsub.c114
-rw-r--r--libavcodec/dvbsub_parser.c10
-rw-r--r--libavcodec/dvbsubdec.c213
-rw-r--r--libavcodec/dvd_nav_parser.c116
-rw-r--r--libavcodec/dvdata.c8
-rw-r--r--libavcodec/dvdata.h12
-rw-r--r--libavcodec/dvdec.c49
-rw-r--r--libavcodec/dvdsub_parser.c8
-rw-r--r--libavcodec/dvdsubdec.c239
-rw-r--r--libavcodec/dvdsubenc.c393
-rw-r--r--libavcodec/dxa.c103
-rw-r--r--libavcodec/dxtory.c10
-rw-r--r--libavcodec/dxva2.c8
-rw-r--r--libavcodec/dxva2.h19
-rw-r--r--libavcodec/dxva2_h264.c18
-rw-r--r--libavcodec/dxva2_internal.h9
-rw-r--r--libavcodec/dxva2_mpeg2.c18
-rw-r--r--libavcodec/dxva2_vc1.c17
-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.c25
-rw-r--r--libavcodec/eaidct.c8
-rw-r--r--libavcodec/eaidct.h8
-rw-r--r--libavcodec/eamad.c57
-rw-r--r--libavcodec/eatgq.c24
-rw-r--r--libavcodec/eatgv.c38
-rw-r--r--libavcodec/eatqi.c15
-rw-r--r--libavcodec/elbg.c13
-rw-r--r--libavcodec/elbg.h8
-rw-r--r--libavcodec/error_resilience.c217
-rw-r--r--libavcodec/error_resilience.h8
-rw-r--r--libavcodec/escape124.c40
-rw-r--r--libavcodec/escape130.c18
-rw-r--r--libavcodec/evrcdata.h1499
-rw-r--r--libavcodec/evrcdec.c917
-rw-r--r--libavcodec/exif.c130
-rw-r--r--libavcodec/exif.h170
-rw-r--r--libavcodec/exr.c1281
-rw-r--r--libavcodec/faandct.h8
-rw-r--r--libavcodec/faanidct.c8
-rw-r--r--libavcodec/faanidct.h8
-rw-r--r--libavcodec/faxcompr.c30
-rw-r--r--libavcodec/faxcompr.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.c36
-rw-r--r--libavcodec/fft.c192
-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/ffv1.c157
-rw-r--r--libavcodec/ffv1.h60
-rw-r--r--libavcodec/ffv1dec.c676
-rw-r--r--libavcodec/ffv1enc.c540
-rw-r--r--libavcodec/ffwavesynth.c484
-rw-r--r--libavcodec/flac.c11
-rw-r--r--libavcodec/flac.h8
-rw-r--r--libavcodec/flac_parser.c90
-rw-r--r--libavcodec/flacdata.c10
-rw-r--r--libavcodec/flacdata.h10
-rw-r--r--libavcodec/flacdec.c59
-rw-r--r--libavcodec/flacdsp.c8
-rw-r--r--libavcodec/flacdsp.h8
-rw-r--r--libavcodec/flacdsp_lpc_template.c8
-rw-r--r--libavcodec/flacdsp_template.c8
-rw-r--r--libavcodec/flacenc.c73
-rw-r--r--libavcodec/flashsv.c37
-rw-r--r--libavcodec/flashsv2enc.c931
-rw-r--r--libavcodec/flashsvenc.c14
-rw-r--r--libavcodec/flicvideo.c140
-rw-r--r--libavcodec/flv.h8
-rw-r--r--libavcodec/flvdec.c18
-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.c270
-rw-r--r--libavcodec/frame_thread_encoder.h26
-rw-r--r--libavcodec/fraps.c223
-rw-r--r--libavcodec/frwu.c43
-rw-r--r--libavcodec/g2meet.c29
-rw-r--r--libavcodec/g722.c8
-rw-r--r--libavcodec/g722.h8
-rw-r--r--libavcodec/g722dec.c12
-rw-r--r--libavcodec/g722enc.c15
-rw-r--r--libavcodec/g723_1.c1297
-rw-r--r--libavcodec/g723_1_data.h171
-rw-r--r--libavcodec/g726.c49
-rw-r--r--libavcodec/g729.h29
-rw-r--r--libavcodec/g729data.h382
-rw-r--r--libavcodec/g729dec.c726
-rw-r--r--libavcodec/g729postfilter.c610
-rw-r--r--libavcodec/g729postfilter.h116
-rw-r--r--libavcodec/get_bits.h98
-rw-r--r--libavcodec/gif.c271
-rw-r--r--libavcodec/gif.h49
-rw-r--r--libavcodec/gifdec.c452
-rw-r--r--libavcodec/golomb-test.c10
-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.c28
-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.h8
-rw-r--r--libavcodec/h261_parser.c22
-rw-r--r--libavcodec/h261data.c8
-rw-r--r--libavcodec/h261dec.c21
-rw-r--r--libavcodec/h261enc.c17
-rw-r--r--libavcodec/h263.c8
-rw-r--r--libavcodec/h263.h14
-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.c168
-rw-r--r--libavcodec/h264.c986
-rw-r--r--libavcodec/h264.h95
-rw-r--r--libavcodec/h264_cabac.c76
-rw-r--r--libavcodec/h264_cavlc.c130
-rw-r--r--libavcodec/h264_direct.c17
-rw-r--r--libavcodec/h264_loopfilter.c20
-rw-r--r--libavcodec/h264_mb_template.c25
-rw-r--r--libavcodec/h264_mc_template.c14
-rw-r--r--libavcodec/h264_mp4toannexb_bsf.c57
-rw-r--r--libavcodec/h264_mvpred.h18
-rw-r--r--libavcodec/h264_parser.c108
-rw-r--r--libavcodec/h264_ps.c153
-rw-r--r--libavcodec/h264_refs.c74
-rw-r--r--libavcodec/h264_sei.c194
-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.c50
-rw-r--r--libavcodec/h264data.h10
-rw-r--r--libavcodec/h264dsp.c32
-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.c30
-rw-r--r--libavcodec/h264pred.h8
-rw-r--r--libavcodec/h264pred_template.c97
-rw-r--r--libavcodec/h264qpel.c26
-rw-r--r--libavcodec/h264qpel.h8
-rw-r--r--libavcodec/h264qpel_template.c116
-rw-r--r--libavcodec/hevc.c2909
-rw-r--r--libavcodec/hevc.h986
-rw-r--r--libavcodec/hevc_cabac.c1424
-rw-r--r--libavcodec/hevc_filter.c693
-rw-r--r--libavcodec/hevc_mvs.c814
-rw-r--r--libavcodec/hevc_parser.c345
-rw-r--r--libavcodec/hevc_ps.c1313
-rw-r--r--libavcodec/hevc_refs.c484
-rw-r--r--libavcodec/hevc_sei.c129
-rw-r--r--libavcodec/hevcdsp.c192
-rw-r--r--libavcodec/hevcdsp.h77
-rw-r--r--libavcodec/hevcdsp_template.c1338
-rw-r--r--libavcodec/hevcpred.c66
-rw-r--r--libavcodec/hevcpred.h43
-rw-r--r--libavcodec/hevcpred_template.c555
-rw-r--r--libavcodec/hpel_template.c8
-rw-r--r--libavcodec/hpeldsp.c8
-rw-r--r--libavcodec/hpeldsp.h12
-rw-r--r--libavcodec/hpeldsp_template.c10
-rw-r--r--libavcodec/huffman.c37
-rw-r--r--libavcodec/huffman.h11
-rw-r--r--libavcodec/huffyuv.c13
-rw-r--r--libavcodec/huffyuv.h8
-rw-r--r--libavcodec/huffyuvdec.c105
-rw-r--r--libavcodec/huffyuvenc.c47
-rw-r--r--libavcodec/idcinvideo.c23
-rw-r--r--libavcodec/iff.c698
-rw-r--r--libavcodec/iirfilter.c15
-rw-r--r--libavcodec/iirfilter.h31
-rw-r--r--libavcodec/imc.c43
-rw-r--r--libavcodec/imcdata.h8
-rw-r--r--libavcodec/imgconvert.c324
-rw-r--r--libavcodec/imgconvert.h8
-rw-r--r--libavcodec/imx_dump_header_bsf.c13
-rw-r--r--libavcodec/indeo2.c37
-rw-r--r--libavcodec/indeo2data.h8
-rw-r--r--libavcodec/indeo3.c96
-rw-r--r--libavcodec/indeo3data.h8
-rw-r--r--libavcodec/indeo4.c65
-rw-r--r--libavcodec/indeo4data.h8
-rw-r--r--libavcodec/indeo5.c53
-rw-r--r--libavcodec/indeo5data.h8
-rw-r--r--libavcodec/intelh263dec.c14
-rw-r--r--libavcodec/internal.h71
-rw-r--r--libavcodec/interplayvideo.c37
-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.c53
-rw-r--r--libavcodec/ituh263enc.c20
-rw-r--r--libavcodec/ivi_common.c76
-rw-r--r--libavcodec/ivi_common.h10
-rw-r--r--libavcodec/ivi_dsp.c30
-rw-r--r--libavcodec/ivi_dsp.h12
-rw-r--r--libavcodec/j2kenc.c1056
-rw-r--r--libavcodec/jacosub.h45
-rw-r--r--libavcodec/jacosubdec.c205
-rw-r--r--libavcodec/jfdctint.c8
-rw-r--r--libavcodec/jpeg2000.c125
-rw-r--r--libavcodec/jpeg2000.h22
-rw-r--r--libavcodec/jpeg2000dec.c466
-rw-r--r--libavcodec/jpeg2000dwt.c231
-rw-r--r--libavcodec/jpeg2000dwt.h9
-rw-r--r--libavcodec/jpegls.c14
-rw-r--r--libavcodec/jpegls.h12
-rw-r--r--libavcodec/jpeglsdec.c105
-rw-r--r--libavcodec/jpeglsdec.h8
-rw-r--r--libavcodec/jpeglsenc.c25
-rw-r--r--libavcodec/jrevdct.c213
-rw-r--r--libavcodec/jvdec.c62
-rw-r--r--libavcodec/kbdwin.c12
-rw-r--r--libavcodec/kbdwin.h8
-rw-r--r--libavcodec/kgv1dec.c60
-rw-r--r--libavcodec/kmvc.c37
-rw-r--r--libavcodec/lagarith.c144
-rw-r--r--libavcodec/lagarithrac.c12
-rw-r--r--libavcodec/lagarithrac.h8
-rw-r--r--libavcodec/latm_parser.c9
-rw-r--r--libavcodec/lcl.h8
-rw-r--r--libavcodec/lcldec.c42
-rw-r--r--libavcodec/lclenc.c37
-rw-r--r--libavcodec/libaacplus.c141
-rw-r--r--libavcodec/libavcodec.v27
-rw-r--r--libavcodec/libcelt_dec.c140
-rw-r--r--libavcodec/libfaac.c30
-rw-r--r--libavcodec/libfdk-aacdec.c8
-rw-r--r--libavcodec/libfdk-aacenc.c12
-rw-r--r--libavcodec/libgsm.c46
-rw-r--r--libavcodec/libilbc.c26
-rw-r--r--libavcodec/libmp3lame.c25
-rw-r--r--libavcodec/libopencore-amr.c35
-rw-r--r--libavcodec/libopenjpegdec.c156
-rw-r--r--libavcodec/libopenjpegenc.c461
-rw-r--r--libavcodec/libopus.c8
-rw-r--r--libavcodec/libopus.h8
-rw-r--r--libavcodec/libopusdec.c49
-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.c19
-rw-r--r--libavcodec/libshine.c149
-rw-r--r--libavcodec/libspeexdec.c28
-rw-r--r--libavcodec/libspeexenc.c17
-rw-r--r--libavcodec/libstagefright.cpp590
-rw-r--r--libavcodec/libtheoraenc.c79
-rw-r--r--libavcodec/libtwolame.c198
-rw-r--r--libavcodec/libutvideo.h70
-rw-r--r--libavcodec/libutvideodec.cpp212
-rw-r--r--libavcodec/libutvideoenc.cpp240
-rw-r--r--libavcodec/libvo-aacenc.c20
-rw-r--r--libavcodec/libvo-amrwbenc.c18
-rw-r--r--libavcodec/libvorbis.c352
-rw-r--r--libavcodec/libvorbisdec.c199
-rw-r--r--libavcodec/libvorbisenc.c378
-rw-r--r--libavcodec/libvpxdec.c10
-rw-r--r--libavcodec/libvpxenc.c265
-rw-r--r--libavcodec/libwavpackenc.c8
-rw-r--r--libavcodec/libx264.c189
-rw-r--r--libavcodec/libxavs.c22
-rw-r--r--libavcodec/libxvid.c200
-rw-r--r--libavcodec/libxvid.h8
-rw-r--r--libavcodec/libxvid_rc.c59
-rw-r--r--libavcodec/libzvbi-teletextdec.c469
-rw-r--r--libavcodec/ljpegenc.c35
-rw-r--r--libavcodec/loco.c93
-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.c17
-rw-r--r--libavcodec/lzw.h9
-rw-r--r--libavcodec/lzwenc.c17
-rw-r--r--libavcodec/mace.c12
-rw-r--r--libavcodec/mathops.h8
-rw-r--r--libavcodec/mathtables.c10
-rw-r--r--libavcodec/mdct.c12
-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/mdec.c17
-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.c377
-rw-r--r--libavcodec/mimic.c20
-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.h185
-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.c16
-rw-r--r--libavcodec/mjpegdec.c902
-rw-r--r--libavcodec/mjpegdec.h17
-rw-r--r--libavcodec/mjpegenc.c139
-rw-r--r--libavcodec/mjpegenc.h10
-rw-r--r--libavcodec/mlp.c8
-rw-r--r--libavcodec/mlp.h8
-rw-r--r--libavcodec/mlp_parser.c55
-rw-r--r--libavcodec/mlp_parser.h12
-rw-r--r--libavcodec/mlpdec.c60
-rw-r--r--libavcodec/mlpdsp.c8
-rw-r--r--libavcodec/mlpdsp.h8
-rw-r--r--libavcodec/mmvideo.c25
-rw-r--r--libavcodec/motion-test.c151
-rw-r--r--libavcodec/motion_est.c95
-rw-r--r--libavcodec/motion_est_template.c58
-rw-r--r--libavcodec/motionpixels.c50
-rw-r--r--libavcodec/motionpixels_tablegen.c8
-rw-r--r--libavcodec/motionpixels_tablegen.h10
-rw-r--r--libavcodec/movsub_bsf.c18
-rw-r--r--libavcodec/movtextdec.c116
-rw-r--r--libavcodec/movtextenc.c165
-rw-r--r--libavcodec/mp3_header_compress_bsf.c13
-rw-r--r--libavcodec/mp3_header_decompress_bsf.c13
-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.c17
-rw-r--r--libavcodec/mpeg12.h8
-rw-r--r--libavcodec/mpeg12data.c76
-rw-r--r--libavcodec/mpeg12data.h11
-rw-r--r--libavcodec/mpeg12dec.c409
-rw-r--r--libavcodec/mpeg12enc.c118
-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.h11
-rw-r--r--libavcodec/mpeg4video_parser.c21
-rw-r--r--libavcodec/mpeg4video_parser.h8
-rw-r--r--libavcodec/mpeg4videodec.c275
-rw-r--r--libavcodec/mpeg4videoenc.c75
-rw-r--r--libavcodec/mpegaudio.c8
-rw-r--r--libavcodec/mpegaudio.h10
-rw-r--r--libavcodec/mpegaudio_parser.c9
-rw-r--r--libavcodec/mpegaudio_tablegen.c8
-rw-r--r--libavcodec/mpegaudio_tablegen.h15
-rw-r--r--libavcodec/mpegaudiodata.c18
-rw-r--r--libavcodec/mpegaudiodata.h8
-rw-r--r--libavcodec/mpegaudiodec.c80
-rw-r--r--libavcodec/mpegaudiodec_float.c8
-rw-r--r--libavcodec/mpegaudiodecheader.c8
-rw-r--r--libavcodec/mpegaudiodecheader.h8
-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.c8
-rw-r--r--libavcodec/mpegaudiodsp_float.c8
-rw-r--r--libavcodec/mpegaudiodsp_template.c11
-rw-r--r--libavcodec/mpegaudioenc.c26
-rw-r--r--libavcodec/mpegaudiotab.h8
-rw-r--r--libavcodec/mpegvideo.c1186
-rw-r--r--libavcodec/mpegvideo.h66
-rw-r--r--libavcodec/mpegvideo_enc.c414
-rw-r--r--libavcodec/mpegvideo_motion.c74
-rw-r--r--libavcodec/mpegvideo_parser.c34
-rw-r--r--libavcodec/mpegvideo_xvmc.c8
-rw-r--r--libavcodec/mpl2dec.c96
-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.h8
-rw-r--r--libavcodec/msmpeg4data.c8
-rw-r--r--libavcodec/msmpeg4data.h8
-rw-r--r--libavcodec/msmpeg4dec.c33
-rw-r--r--libavcodec/msmpeg4enc.c20
-rw-r--r--libavcodec/msrle.c25
-rw-r--r--libavcodec/msrledec.c81
-rw-r--r--libavcodec/msrledec.h8
-rw-r--r--libavcodec/mss1.c17
-rw-r--r--libavcodec/mss12.c17
-rw-r--r--libavcodec/mss12.h8
-rw-r--r--libavcodec/mss2.c41
-rw-r--r--libavcodec/mss2dsp.c11
-rw-r--r--libavcodec/mss2dsp.h8
-rw-r--r--libavcodec/mss3.c50
-rw-r--r--libavcodec/mss34dsp.c8
-rw-r--r--libavcodec/mss34dsp.h8
-rw-r--r--libavcodec/mss4.c51
-rw-r--r--libavcodec/msvideo1.c12
-rw-r--r--libavcodec/msvideo1enc.c311
-rw-r--r--libavcodec/mvcdec.c286
-rw-r--r--libavcodec/mxpegdec.c26
-rw-r--r--libavcodec/nellymoserdec.c9
-rw-r--r--libavcodec/nellymoserenc.c24
-rw-r--r--libavcodec/noise_bsf.c19
-rw-r--r--libavcodec/nuv.c66
-rw-r--r--libavcodec/old_codec_ids.h397
-rw-r--r--libavcodec/options.c116
-rw-r--r--libavcodec/options_table.h98
-rw-r--r--libavcodec/paf.c451
-rw-r--r--libavcodec/paf.h28
-rw-r--r--libavcodec/pamenc.c80
-rw-r--r--libavcodec/parser.c55
-rw-r--r--libavcodec/parser.h8
-rw-r--r--libavcodec/pcm-bluray.c19
-rw-r--r--libavcodec/pcm-dvd.c22
-rw-r--r--libavcodec/pcm.c183
-rw-r--r--libavcodec/pcm_tablegen.c8
-rw-r--r--libavcodec/pcm_tablegen.h8
-rw-r--r--libavcodec/pcx.c131
-rw-r--r--libavcodec/pcxenc.c50
-rw-r--r--libavcodec/pgssubdec.c240
-rw-r--r--libavcodec/pictordec.c52
-rw-r--r--libavcodec/png.c17
-rw-r--r--libavcodec/png.h15
-rw-r--r--libavcodec/png_parser.c120
-rw-r--r--libavcodec/pngdec.c556
-rw-r--r--libavcodec/pngdsp.c10
-rw-r--r--libavcodec/pngdsp.h8
-rw-r--r--libavcodec/pngenc.c145
-rw-r--r--libavcodec/pnm.c76
-rw-r--r--libavcodec/pnm.h10
-rw-r--r--libavcodec/pnm_parser.c8
-rw-r--r--libavcodec/pnmdec.c113
-rw-r--r--libavcodec/pnmenc.c30
-rw-r--r--libavcodec/ppc/asm.S8
-rw-r--r--libavcodec/ppc/dsputil_altivec.c8
-rw-r--r--libavcodec/ppc/dsputil_altivec.h8
-rw-r--r--libavcodec/ppc/dsputil_ppc.c13
-rw-r--r--libavcodec/ppc/fdct_altivec.c8
-rw-r--r--libavcodec/ppc/fft_altivec.c8
-rw-r--r--libavcodec/ppc/fft_altivec_s.S8
-rw-r--r--libavcodec/ppc/fmtconvert_altivec.c8
-rw-r--r--libavcodec/ppc/gmc_altivec.c12
-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.c8
-rw-r--r--libavcodec/ppc/idct_altivec.c12
-rw-r--r--libavcodec/ppc/int_altivec.c8
-rw-r--r--libavcodec/ppc/mathops.h8
-rw-r--r--libavcodec/ppc/mpegaudiodsp_altivec.c8
-rw-r--r--libavcodec/ppc/mpegvideo_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.c57
-rw-r--r--libavcodec/proresdata.c8
-rw-r--r--libavcodec/proresdata.h8
-rw-r--r--libavcodec/proresdec.c781
-rw-r--r--libavcodec/proresdec.h55
-rw-r--r--libavcodec/proresdec2.c688
-rw-r--r--libavcodec/proresdec_lgpl.c783
-rw-r--r--libavcodec/proresdsp.c20
-rw-r--r--libavcodec/proresdsp.h13
-rw-r--r--libavcodec/proresenc.c1278
-rw-r--r--libavcodec/proresenc_anatoliy.c626
-rw-r--r--libavcodec/proresenc_kostya.c1276
-rw-r--r--libavcodec/psymodel.c24
-rw-r--r--libavcodec/psymodel.h10
-rw-r--r--libavcodec/pthread.c220
-rw-r--r--libavcodec/ptx.c20
-rw-r--r--libavcodec/put_bits.h19
-rw-r--r--libavcodec/qcelpdata.h12
-rw-r--r--libavcodec/qcelpdec.c24
-rw-r--r--libavcodec/qdm2.c123
-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.c59
-rw-r--r--libavcodec/qtrle.c116
-rw-r--r--libavcodec/qtrleenc.c156
-rw-r--r--libavcodec/r210dec.c29
-rw-r--r--libavcodec/r210enc.c123
-rw-r--r--libavcodec/ra144.c25
-rw-r--r--libavcodec/ra144.h14
-rw-r--r--libavcodec/ra144dec.c22
-rw-r--r--libavcodec/ra144enc.c23
-rw-r--r--libavcodec/ra288.c27
-rw-r--r--libavcodec/ra288.h8
-rw-r--r--libavcodec/ralf.c12
-rw-r--r--libavcodec/ralfdata.h8
-rw-r--r--libavcodec/rangecoder.c15
-rw-r--r--libavcodec/rangecoder.h16
-rw-r--r--libavcodec/ratecontrol.c52
-rw-r--r--libavcodec/ratecontrol.h8
-rw-r--r--libavcodec/raw.c51
-rw-r--r--libavcodec/raw.h15
-rw-r--r--libavcodec/rawdec.c154
-rw-r--r--libavcodec/rawenc.c12
-rw-r--r--libavcodec/rdft.c8
-rw-r--r--libavcodec/rdft.h8
-rw-r--r--libavcodec/realtextdec.c83
-rw-r--r--libavcodec/rectangle.h21
-rw-r--r--libavcodec/remove_extradata_bsf.c13
-rw-r--r--libavcodec/resample.c435
-rw-r--r--libavcodec/resample2.c319
-rw-r--r--libavcodec/rl.h8
-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.h8
-rw-r--r--libavcodec/roqvideodec.c33
-rw-r--r--libavcodec/roqvideoenc.c22
-rw-r--r--libavcodec/rpza.c20
-rw-r--r--libavcodec/rtjpeg.c8
-rw-r--r--libavcodec/rtjpeg.h8
-rw-r--r--libavcodec/rv10.c66
-rw-r--r--libavcodec/rv10enc.c8
-rw-r--r--libavcodec/rv20enc.c20
-rw-r--r--libavcodec/rv30.c16
-rw-r--r--libavcodec/rv30data.h8
-rw-r--r--libavcodec/rv30dsp.c8
-rw-r--r--libavcodec/rv34.c56
-rw-r--r--libavcodec/rv34.h8
-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.c177
-rw-r--r--libavcodec/s3tc.c8
-rw-r--r--libavcodec/s3tc.h8
-rw-r--r--libavcodec/samidec.c158
-rw-r--r--libavcodec/sanm.c1307
-rw-r--r--libavcodec/sanm_data.h248
-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.c74
-rw-r--r--libavcodec/sgienc.c82
-rw-r--r--libavcodec/sgirledec.c151
-rw-r--r--libavcodec/sh4/dsputil_sh4.c8
-rw-r--r--libavcodec/sh4/dsputil_sh4.h9
-rw-r--r--libavcodec/sh4/idct_sh4.c8
-rw-r--r--libavcodec/sh4/sh4.h8
-rw-r--r--libavcodec/shorten.c80
-rw-r--r--libavcodec/simple_idct.c12
-rw-r--r--libavcodec/simple_idct.h13
-rw-r--r--libavcodec/simple_idct_template.c24
-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.c12
-rw-r--r--libavcodec/sipr.h8
-rw-r--r--libavcodec/sipr16k.c9
-rw-r--r--libavcodec/sipr16kdata.h8
-rw-r--r--libavcodec/siprdata.h8
-rw-r--r--libavcodec/smacker.c196
-rw-r--r--libavcodec/smc.c14
-rw-r--r--libavcodec/smvjpegdec.c205
-rw-r--r--libavcodec/snow.c708
-rw-r--r--libavcodec/snow.h704
-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.c598
-rw-r--r--libavcodec/snowenc.c2018
-rw-r--r--libavcodec/sonic.c989
-rw-r--r--libavcodec/sp5x.h8
-rw-r--r--libavcodec/sp5xdec.c18
-rw-r--r--libavcodec/sparc/dsputil_vis.c8
-rw-r--r--libavcodec/sparc/dsputil_vis.h8
-rw-r--r--libavcodec/sparc/hpeldsp_vis.c8
-rw-r--r--libavcodec/sparc/simple_idct_vis.c8
-rw-r--r--libavcodec/sparc/vis.h8
-rw-r--r--libavcodec/srtdec.c91
-rw-r--r--libavcodec/srtenc.c324
-rw-r--r--libavcodec/subviewerdec.c83
-rw-r--r--libavcodec/sunrast.c63
-rw-r--r--libavcodec/sunrast.h8
-rw-r--r--libavcodec/sunrastenc.c33
-rw-r--r--libavcodec/svq1.c8
-rw-r--r--libavcodec/svq1.h8
-rw-r--r--libavcodec/svq13.c8
-rw-r--r--libavcodec/svq1_cb.h8
-rw-r--r--libavcodec/svq1_vlc.h8
-rw-r--r--libavcodec/svq1dec.c62
-rw-r--r--libavcodec/svq1enc.c54
-rw-r--r--libavcodec/svq1enc_cb.h8
-rw-r--r--libavcodec/svq3.c84
-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.h8
-rw-r--r--libavcodec/tak.c58
-rw-r--r--libavcodec/tak.h13
-rw-r--r--libavcodec/tak_parser.c32
-rw-r--r--libavcodec/takdec.c347
-rw-r--r--libavcodec/targa.c163
-rw-r--r--libavcodec/targa.h15
-rw-r--r--libavcodec/targa_y216dec.c83
-rw-r--r--libavcodec/targaenc.c66
-rw-r--r--libavcodec/textdec.c188
-rw-r--r--libavcodec/thread.h23
-rw-r--r--libavcodec/tiertexseqv.c14
-rw-r--r--libavcodec/tiff.c754
-rw-r--r--libavcodec/tiff.h111
-rw-r--r--libavcodec/tiff_common.c317
-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.c238
-rw-r--r--libavcodec/timecode.c150
-rw-r--r--libavcodec/timecode.h106
-rw-r--r--libavcodec/tmv.c16
-rw-r--r--libavcodec/truemotion1.c36
-rw-r--r--libavcodec/truemotion1data.h8
-rw-r--r--libavcodec/truemotion2.c118
-rw-r--r--libavcodec/truespeech.c12
-rw-r--r--libavcodec/truespeech_data.h8
-rw-r--r--libavcodec/tscc.c24
-rw-r--r--libavcodec/tscc2.c9
-rw-r--r--libavcodec/tscc2data.h8
-rw-r--r--libavcodec/tta.c369
-rw-r--r--libavcodec/ttadata.c52
-rw-r--r--libavcodec/ttadata.h50
-rw-r--r--libavcodec/ttaenc.c232
-rw-r--r--libavcodec/twinvq.c14
-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.c13
-rw-r--r--libavcodec/ulti_cb.h8
-rw-r--r--libavcodec/unary.h8
-rw-r--r--libavcodec/utils.c1647
-rw-r--r--libavcodec/utvideo.c8
-rw-r--r--libavcodec/utvideo.h8
-rw-r--r--libavcodec/utvideodec.c16
-rw-r--r--libavcodec/utvideoenc.c20
-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.c23
-rw-r--r--libavcodec/vaapi_internal.h8
-rw-r--r--libavcodec/vaapi_mpeg.c48
-rw-r--r--libavcodec/vaapi_mpeg2.c8
-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.c107
-rw-r--r--libavcodec/vc1.c52
-rw-r--r--libavcodec/vc1.h14
-rw-r--r--libavcodec/vc1_parser.c17
-rw-r--r--libavcodec/vc1acdata.h8
-rw-r--r--libavcodec/vc1data.c22
-rw-r--r--libavcodec/vc1data.h26
-rw-r--r--libavcodec/vc1dec.c318
-rw-r--r--libavcodec/vc1dsp.c60
-rw-r--r--libavcodec/vc1dsp.h14
-rw-r--r--libavcodec/vcr1.c45
-rw-r--r--libavcodec/vda.h34
-rw-r--r--libavcodec/vda_h264.c70
-rw-r--r--libavcodec/vda_h264_dec.c228
-rw-r--r--libavcodec/vdpau.c358
-rw-r--r--libavcodec/vdpau.h51
-rw-r--r--libavcodec/vdpau_h264.c15
-rw-r--r--libavcodec/vdpau_internal.h31
-rw-r--r--libavcodec/vdpau_mpeg12.c8
-rw-r--r--libavcodec/vdpau_mpeg4.c8
-rw-r--r--libavcodec/vdpau_vc1.c12
-rw-r--r--libavcodec/version.h39
-rw-r--r--libavcodec/videodsp.c9
-rw-r--r--libavcodec/videodsp.h30
-rw-r--r--libavcodec/videodsp_template.c48
-rw-r--r--libavcodec/vima.c239
-rw-r--r--libavcodec/vmdav.c86
-rw-r--r--libavcodec/vmnc.c65
-rw-r--r--libavcodec/vorbis.c14
-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.c18
-rw-r--r--libavcodec/vorbis_parser.h8
-rw-r--r--libavcodec/vorbisdec.c138
-rw-r--r--libavcodec/vorbisdsp.c8
-rw-r--r--libavcodec/vorbisdsp.h8
-rw-r--r--libavcodec/vorbisenc.c33
-rw-r--r--libavcodec/vp3.c103
-rw-r--r--libavcodec/vp3_parser.c8
-rw-r--r--libavcodec/vp3data.h8
-rw-r--r--libavcodec/vp3dsp.c8
-rw-r--r--libavcodec/vp3dsp.h8
-rw-r--r--libavcodec/vp5.c11
-rw-r--r--libavcodec/vp56.c301
-rw-r--r--libavcodec/vp56.h42
-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.c60
-rw-r--r--libavcodec/vp6data.h8
-rw-r--r--libavcodec/vp6dsp.c8
-rw-r--r--libavcodec/vp8.c122
-rw-r--r--libavcodec/vp8.h12
-rw-r--r--libavcodec/vp8_parser.c8
-rw-r--r--libavcodec/vp8data.h8
-rw-r--r--libavcodec/vp8dsp.c28
-rw-r--r--libavcodec/vp8dsp.h8
-rw-r--r--libavcodec/vp9.c3578
-rw-r--r--libavcodec/vp9.h72
-rw-r--r--libavcodec/vp9data.h2155
-rw-r--r--libavcodec/vp9dsp.c2049
-rw-r--r--libavcodec/vp9dsp.h118
-rw-r--r--libavcodec/vqavideo.c94
-rw-r--r--libavcodec/wavpack.c195
-rw-r--r--libavcodec/wavpack.h194
-rw-r--r--libavcodec/wavpackenc.c2989
-rw-r--r--libavcodec/wavpackenc.h664
-rw-r--r--libavcodec/webp.c8
-rw-r--r--libavcodec/webvttdec.c100
-rw-r--r--libavcodec/wma.c14
-rw-r--r--libavcodec/wma.h10
-rw-r--r--libavcodec/wma_common.c8
-rw-r--r--libavcodec/wma_common.h8
-rw-r--r--libavcodec/wmadata.h10
-rw-r--r--libavcodec/wmadec.c44
-rw-r--r--libavcodec/wmaenc.c86
-rw-r--r--libavcodec/wmalosslessdec.c53
-rw-r--r--libavcodec/wmaprodata.h8
-rw-r--r--libavcodec/wmaprodec.c54
-rw-r--r--libavcodec/wmavoice.c32
-rw-r--r--libavcodec/wmavoice_data.h8
-rw-r--r--libavcodec/wmv2.c32
-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.c14
-rw-r--r--libavcodec/wnv1.c17
-rw-r--r--libavcodec/ws-snd1.c14
-rw-r--r--libavcodec/x86/Makefile13
-rw-r--r--libavcodec/x86/ac3dsp.asm8
-rw-r--r--libavcodec/x86/ac3dsp_init.c13
-rw-r--r--libavcodec/x86/cabac.h35
-rw-r--r--libavcodec/x86/cavsdsp.c8
-rw-r--r--libavcodec/x86/constants.c8
-rw-r--r--libavcodec/x86/constants.h8
-rw-r--r--libavcodec/x86/dct32.asm10
-rw-r--r--libavcodec/x86/dct_init.c8
-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.c104
-rw-r--r--libavcodec/x86/diracdsp_mmx.h47
-rw-r--r--libavcodec/x86/diracdsp_yasm.asm264
-rw-r--r--libavcodec/x86/dnxhdenc.c8
-rw-r--r--libavcodec/x86/dsputil.asm11
-rw-r--r--libavcodec/x86/dsputil_init.c60
-rw-r--r--libavcodec/x86/dsputil_mmx.c167
-rw-r--r--libavcodec/x86/dsputil_qns_template.c10
-rw-r--r--libavcodec/x86/dsputil_x86.c8
-rw-r--r--libavcodec/x86/dsputil_x86.h17
-rw-r--r--libavcodec/x86/dsputilenc.asm8
-rw-r--r--libavcodec/x86/dsputilenc_mmx.c31
-rw-r--r--libavcodec/x86/dwt_yasm.asm306
-rw-r--r--libavcodec/x86/fdct.c12
-rw-r--r--libavcodec/x86/fft.asm23
-rw-r--r--libavcodec/x86/fft.h8
-rw-r--r--libavcodec/x86/fft_init.c8
-rw-r--r--libavcodec/x86/fmtconvert.asm8
-rw-r--r--libavcodec/x86/fmtconvert_init.c8
-rw-r--r--libavcodec/x86/fpel.asm8
-rw-r--r--libavcodec/x86/fpel_mmx.c8
-rw-r--r--libavcodec/x86/h263_loopfilter.asm10
-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.h8
-rw-r--r--libavcodec/x86/h264_idct.asm8
-rw-r--r--libavcodec/x86/h264_idct_10bit.asm24
-rw-r--r--libavcodec/x86/h264_intrapred.asm8
-rw-r--r--libavcodec/x86/h264_intrapred_10bit.asm34
-rw-r--r--libavcodec/x86/h264_intrapred_init.c8
-rw-r--r--libavcodec/x86/h264_qpel.c16
-rw-r--r--libavcodec/x86/h264_qpel_10bit.asm8
-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/hpeldsp.asm15
-rw-r--r--libavcodec/x86/hpeldsp_init.c8
-rw-r--r--libavcodec/x86/hpeldsp_mmx.c8
-rw-r--r--libavcodec/x86/hpeldsp_rnd_template.c8
-rw-r--r--libavcodec/x86/idct_mmx_xvid.c8
-rw-r--r--libavcodec/x86/idct_sse2_xvid.c9
-rw-r--r--libavcodec/x86/idct_xvid.h8
-rw-r--r--libavcodec/x86/imdct36.asm12
-rw-r--r--libavcodec/x86/lpc.c11
-rw-r--r--libavcodec/x86/mathops.h8
-rw-r--r--libavcodec/x86/mlpdsp.c9
-rw-r--r--libavcodec/x86/motion_est.c26
-rw-r--r--libavcodec/x86/mpeg4qpel.asm10
-rw-r--r--libavcodec/x86/mpegaudiodsp.c27
-rw-r--r--libavcodec/x86/mpegvideo.c28
-rw-r--r--libavcodec/x86/mpegvideoenc.c10
-rw-r--r--libavcodec/x86/mpegvideoenc_template.c21
-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.c13
-rw-r--r--libavcodec/x86/qpel.asm8
-rw-r--r--libavcodec/x86/rnd_mmx.c8
-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.c8
-rw-r--r--libavcodec/x86/sbrdsp.asm192
-rw-r--r--libavcodec/x86/sbrdsp_init.c27
-rw-r--r--libavcodec/x86/simple_idct.c11
-rw-r--r--libavcodec/x86/snowdsp.c902
-rw-r--r--libavcodec/x86/v210-init.c48
-rw-r--r--libavcodec/x86/v210.asm88
-rw-r--r--libavcodec/x86/vc1dsp.asm8
-rw-r--r--libavcodec/x86/vc1dsp.h8
-rw-r--r--libavcodec/x86/vc1dsp_mmx.c1
-rw-r--r--libavcodec/x86/videodsp.asm860
-rw-r--r--libavcodec/x86/videodsp_init.c217
-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.c69
-rw-r--r--libavcodec/x86/vp56_arith.h8
-rw-r--r--libavcodec/x86/vp6dsp.asm8
-rw-r--r--libavcodec/x86/vp6dsp_init.c8
-rw-r--r--libavcodec/x86/vp8dsp.asm8
-rw-r--r--libavcodec/x86/vp8dsp_init.c10
-rw-r--r--libavcodec/x86/vp9dsp.asm278
-rw-r--r--libavcodec/x86/vp9dsp_init.c214
-rw-r--r--libavcodec/x86/w64xmmtest.c15
-rw-r--r--libavcodec/xan.c112
-rw-r--r--libavcodec/xbmdec.c119
-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.c10
-rw-r--r--libavcodec/xiph.h10
-rw-r--r--libavcodec/xl.c15
-rw-r--r--libavcodec/xsubdec.c17
-rw-r--r--libavcodec/xsubenc.c12
-rw-r--r--libavcodec/xvmc.h8
-rw-r--r--libavcodec/xvmc_internal.h8
-rw-r--r--libavcodec/xwd.h8
-rw-r--r--libavcodec/xwddec.c21
-rw-r--r--libavcodec/xwdenc.c45
-rw-r--r--libavcodec/xxan.c83
-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.c117
-rw-r--r--libavcodec/zmbvenc.c19
-rw-r--r--libavdevice/Makefile32
-rw-r--r--libavdevice/alldevices.c23
-rw-r--r--libavdevice/alsa-audio-common.c85
-rw-r--r--libavdevice/alsa-audio-dec.c62
-rw-r--r--libavdevice/alsa-audio-enc.c25
-rw-r--r--libavdevice/alsa-audio.h21
-rw-r--r--libavdevice/avdevice.c14
-rw-r--r--libavdevice/avdevice.h10
-rw-r--r--libavdevice/bktr.c29
-rw-r--r--libavdevice/caca.c240
-rw-r--r--libavdevice/dshow.c1095
-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.c12
-rw-r--r--libavdevice/dv1394.h8
-rw-r--r--libavdevice/fbdev.c268
-rw-r--r--libavdevice/fbdev_common.c57
-rw-r--r--libavdevice/fbdev_common.h32
-rw-r--r--libavdevice/fbdev_dec.c231
-rw-r--r--libavdevice/fbdev_enc.c206
-rw-r--r--libavdevice/iec61883.c497
-rw-r--r--libavdevice/jack_audio.c14
-rw-r--r--libavdevice/lavfi.c435
-rw-r--r--libavdevice/libcdio.c10
-rw-r--r--libavdevice/libdc1394.c8
-rw-r--r--libavdevice/openal-dec.c252
-rw-r--r--libavdevice/oss_audio.c17
-rw-r--r--libavdevice/pulse.c190
-rw-r--r--libavdevice/pulse_audio_common.c42
-rw-r--r--libavdevice/pulse_audio_common.h29
-rw-r--r--libavdevice/pulse_audio_dec.c173
-rw-r--r--libavdevice/pulse_audio_enc.c167
-rw-r--r--libavdevice/sdl.c236
-rw-r--r--libavdevice/sndio_common.c10
-rw-r--r--libavdevice/sndio_common.h10
-rw-r--r--libavdevice/sndio_dec.c8
-rw-r--r--libavdevice/sndio_enc.c11
-rw-r--r--libavdevice/timefilter.c52
-rw-r--r--libavdevice/timefilter.h27
-rw-r--r--libavdevice/v4l.c362
-rw-r--r--libavdevice/v4l2-common.c96
-rw-r--r--libavdevice/v4l2-common.h62
-rw-r--r--libavdevice/v4l2.c801
-rw-r--r--libavdevice/v4l2enc.c110
-rw-r--r--libavdevice/version.h16
-rw-r--r--libavdevice/vfwcap.c53
-rw-r--r--libavdevice/x11grab.c105
-rw-r--r--libavdevice/xv.c217
-rw-r--r--libavfilter/Makefile187
-rw-r--r--libavfilter/af_aconvert.c196
-rw-r--r--libavfilter/af_adelay.c283
-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.c350
-rw-r--r--libavfilter/af_amix.c50
-rw-r--r--libavfilter/af_anull.c27
-rw-r--r--libavfilter/af_apad.c156
-rw-r--r--libavfilter/af_aphaser.c358
-rw-r--r--libavfilter/af_aresample.c309
-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.c1196
-rw-r--r--libavfilter/af_biquads.c620
-rw-r--r--libavfilter/af_channelmap.c28
-rw-r--r--libavfilter/af_channelsplit.c40
-rw-r--r--libavfilter/af_compand.c518
-rw-r--r--libavfilter/af_earwax.c172
-rw-r--r--libavfilter/af_join.c53
-rw-r--r--libavfilter/af_ladspa.c703
-rw-r--r--libavfilter/af_pan.c422
-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_volume.c50
-rw-r--r--libavfilter/af_volume.h8
-rw-r--r--libavfilter/af_volumedetect.c159
-rw-r--r--libavfilter/all_channel_layouts.inc68
-rw-r--r--libavfilter/allfilters.c136
-rw-r--r--libavfilter/asink_anullsink.c10
-rw-r--r--libavfilter/asrc_abuffer.h91
-rw-r--r--libavfilter/asrc_aevalsrc.c242
-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.c54
-rw-r--r--libavfilter/audio.h50
-rw-r--r--libavfilter/avcodec.c157
-rw-r--r--libavfilter/avcodec.h110
-rw-r--r--libavfilter/avf_avectorscope.c273
-rw-r--r--libavfilter/avf_concat.c426
-rw-r--r--libavfilter/avf_showspectrum.c502
-rw-r--r--libavfilter/avf_showwaves.c256
-rw-r--r--libavfilter/avfilter.c607
-rw-r--r--libavfilter/avfilter.h452
-rw-r--r--libavfilter/avfiltergraph.c592
-rw-r--r--libavfilter/avfiltergraph.h9
-rw-r--r--libavfilter/bbox.c75
-rw-r--r--libavfilter/bbox.h44
-rw-r--r--libavfilter/buffer.c102
-rw-r--r--libavfilter/bufferqueue.h121
-rw-r--r--libavfilter/buffersink.c427
-rw-r--r--libavfilter/buffersink.h102
-rw-r--r--libavfilter/buffersrc.c188
-rw-r--r--libavfilter/buffersrc.h83
-rw-r--r--libavfilter/deshake.h104
-rw-r--r--libavfilter/deshake_opencl.c176
-rw-r--r--libavfilter/deshake_opencl.h38
-rw-r--r--libavfilter/deshake_opencl_kernel.h217
-rw-r--r--libavfilter/drawutils.c489
-rw-r--r--libavfilter/drawutils.h120
-rw-r--r--libavfilter/dualinput.c83
-rw-r--r--libavfilter/dualinput.h46
-rw-r--r--libavfilter/f_ebur128.c799
-rw-r--r--libavfilter/f_interleave.c259
-rw-r--r--libavfilter/f_perms.c178
-rw-r--r--libavfilter/f_select.c533
-rw-r--r--libavfilter/f_sendcmd.c576
-rw-r--r--libavfilter/f_settb.c187
-rw-r--r--libavfilter/f_zmq.c275
-rw-r--r--libavfilter/fifo.c12
-rw-r--r--libavfilter/filtfmts.c76
-rw-r--r--libavfilter/formats.c319
-rw-r--r--libavfilter/formats.h65
-rw-r--r--libavfilter/framesync.c329
-rw-r--r--libavfilter/framesync.h296
-rw-r--r--libavfilter/gradfun.h16
-rw-r--r--libavfilter/graphdump.c164
-rw-r--r--libavfilter/graphparser.c132
-rw-r--r--libavfilter/internal.h160
-rw-r--r--libavfilter/lavfutils.c98
-rw-r--r--libavfilter/lavfutils.h43
-rw-r--r--libavfilter/libavfilter.v1
-rw-r--r--libavfilter/libmpcodecs/av_helpers.h27
-rw-r--r--libavfilter/libmpcodecs/cpudetect.h60
-rw-r--r--libavfilter/libmpcodecs/img_format.c233
-rw-r--r--libavfilter/libmpcodecs/img_format.h300
-rw-r--r--libavfilter/libmpcodecs/libvo/fastmemcpy.h99
-rw-r--r--libavfilter/libmpcodecs/libvo/video_out.h281
-rw-r--r--libavfilter/libmpcodecs/mp_image.c253
-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.c2118
-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.c393
-rw-r--r--libavfilter/libmpcodecs/vfcap.h56
-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.c11
-rw-r--r--libavfilter/setpts.c163
-rw-r--r--libavfilter/split.c88
-rw-r--r--libavfilter/src_movie.c603
-rw-r--r--libavfilter/thread.h8
-rw-r--r--libavfilter/transform.c201
-rw-r--r--libavfilter/transform.h127
-rw-r--r--libavfilter/trim.c121
-rw-r--r--libavfilter/unsharp.h75
-rw-r--r--libavfilter/unsharp_opencl.c283
-rw-r--r--libavfilter/unsharp_opencl.h34
-rw-r--r--libavfilter/unsharp_opencl_kernel.h137
-rw-r--r--libavfilter/version.h29
-rw-r--r--libavfilter/vf_alphamerge.c207
-rw-r--r--libavfilter/vf_aspect.c166
-rw-r--r--libavfilter/vf_bbox.c134
-rw-r--r--libavfilter/vf_blackdetect.c204
-rw-r--r--libavfilter/vf_blackframe.c59
-rw-r--r--libavfilter/vf_blend.c465
-rw-r--r--libavfilter/vf_boxblur.c99
-rw-r--r--libavfilter/vf_colorbalance.c213
-rw-r--r--libavfilter/vf_colorchannelmixer.c360
-rw-r--r--libavfilter/vf_colormatrix.c388
-rw-r--r--libavfilter/vf_copy.c24
-rw-r--r--libavfilter/vf_crop.c160
-rw-r--r--libavfilter/vf_cropdetect.c74
-rw-r--r--libavfilter/vf_curves.c552
-rw-r--r--libavfilter/vf_dctdnoiz.c433
-rw-r--r--libavfilter/vf_decimate.c397
-rw-r--r--libavfilter/vf_delogo.c125
-rw-r--r--libavfilter/vf_deshake.c580
-rw-r--r--libavfilter/vf_drawbox.c333
-rw-r--r--libavfilter/vf_drawtext.c1112
-rw-r--r--libavfilter/vf_edgedetect.c331
-rw-r--r--libavfilter/vf_extractplanes.c335
-rw-r--r--libavfilter/vf_fade.c244
-rw-r--r--libavfilter/vf_field.c111
-rw-r--r--libavfilter/vf_fieldmatch.c984
-rw-r--r--libavfilter/vf_fieldorder.c106
-rw-r--r--libavfilter/vf_format.c71
-rw-r--r--libavfilter/vf_fps.c74
-rw-r--r--libavfilter/vf_framestep.c101
-rw-r--r--libavfilter/vf_frei0r.c168
-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.c70
-rw-r--r--libavfilter/vf_hqdn3d.h12
-rw-r--r--libavfilter/vf_hue.c449
-rw-r--r--libavfilter/vf_idet.c308
-rw-r--r--libavfilter/vf_il.c212
-rw-r--r--libavfilter/vf_interlace.c58
-rw-r--r--libavfilter/vf_kerndeint.c318
-rw-r--r--libavfilter/vf_libopencv.c62
-rw-r--r--libavfilter/vf_lut.c220
-rw-r--r--libavfilter/vf_lut3d.c796
-rw-r--r--libavfilter/vf_mcdeint.c315
-rw-r--r--libavfilter/vf_mergeplanes.c313
-rw-r--r--libavfilter/vf_mp.c791
-rw-r--r--libavfilter/vf_mpdecimate.c257
-rw-r--r--libavfilter/vf_noise.c488
-rw-r--r--libavfilter/vf_null.c23
-rw-r--r--libavfilter/vf_overlay.c656
-rw-r--r--libavfilter/vf_owdenoise.c342
-rw-r--r--libavfilter/vf_pad.c207
-rw-r--r--libavfilter/vf_perspective.c403
-rw-r--r--libavfilter/vf_phase.c320
-rw-r--r--libavfilter/vf_pixdesctest.c36
-rw-r--r--libavfilter/vf_pp.c186
-rw-r--r--libavfilter/vf_psnr.c386
-rw-r--r--libavfilter/vf_pullup.c768
-rw-r--r--libavfilter/vf_pullup.h71
-rw-r--r--libavfilter/vf_removelogo.c581
-rw-r--r--libavfilter/vf_rotate.c489
-rw-r--r--libavfilter/vf_sab.c339
-rw-r--r--libavfilter/vf_scale.c364
-rw-r--r--libavfilter/vf_select.c362
-rw-r--r--libavfilter/vf_separatefields.c146
-rw-r--r--libavfilter/vf_setfield.c94
-rw-r--r--libavfilter/vf_settb.c161
-rw-r--r--libavfilter/vf_showinfo.c53
-rw-r--r--libavfilter/vf_smartblur.c304
-rw-r--r--libavfilter/vf_spp.c437
-rw-r--r--libavfilter/vf_spp.h59
-rw-r--r--libavfilter/vf_stereo3d.c664
-rw-r--r--libavfilter/vf_subtitles.c366
-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.c384
-rw-r--r--libavfilter/vf_transpose.c238
-rw-r--r--libavfilter/vf_unsharp.c224
-rw-r--r--libavfilter/vf_vflip.c24
-rw-r--r--libavfilter/vf_vidstabdetect.c217
-rw-r--r--libavfilter/vf_vidstabtransform.c291
-rw-r--r--libavfilter/vf_vignette.c339
-rw-r--r--libavfilter/vf_w3fdif.c394
-rw-r--r--libavfilter/vf_yadif.c241
-rw-r--r--libavfilter/video.c17
-rw-r--r--libavfilter/video.h10
-rw-r--r--libavfilter/vidstabutils.c85
-rw-r--r--libavfilter/vidstabutils.h36
-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.c285
-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/Makefile5
-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.c27
-rw-r--r--libavfilter/x86/vf_hqdn3d.asm8
-rw-r--r--libavfilter/x86/vf_hqdn3d_init.c10
-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.asm38
-rw-r--r--libavfilter/x86/vf_yadif_init.c68
-rw-r--r--libavfilter/x86/yadif-10.asm282
-rw-r--r--libavfilter/x86/yadif-16.asm347
-rw-r--r--libavfilter/yadif.h50
-rw-r--r--libavformat/4xm.c25
-rw-r--r--libavformat/Makefile116
-rw-r--r--libavformat/a64.c9
-rw-r--r--libavformat/aacdec.c27
-rw-r--r--libavformat/ac3dec.c68
-rw-r--r--libavformat/act.c207
-rw-r--r--libavformat/adp.c91
-rw-r--r--libavformat/adtsenc.c38
-rw-r--r--libavformat/adxdec.c11
-rw-r--r--libavformat/aea.c8
-rw-r--r--libavformat/afc.c79
-rw-r--r--libavformat/aiff.h14
-rw-r--r--libavformat/aiffdec.c96
-rw-r--r--libavformat/aiffenc.c198
-rw-r--r--libavformat/allformats.c79
-rw-r--r--libavformat/amr.c13
-rw-r--r--libavformat/anm.c10
-rw-r--r--libavformat/apc.c15
-rw-r--r--libavformat/ape.c32
-rw-r--r--libavformat/apetag.c89
-rw-r--r--libavformat/apetag.h12
-rw-r--r--libavformat/aqtitledec.c148
-rw-r--r--libavformat/asf.c9
-rw-r--r--libavformat/asf.h20
-rw-r--r--libavformat/asfcrypt.c8
-rw-r--r--libavformat/asfcrypt.h8
-rw-r--r--libavformat/asfdec.c281
-rw-r--r--libavformat/asfenc.c184
-rw-r--r--libavformat/assdec.c225
-rw-r--r--libavformat/assenc.c44
-rw-r--r--libavformat/ast.c29
-rw-r--r--libavformat/ast.h30
-rw-r--r--libavformat/astdec.c119
-rw-r--r--libavformat/astenc.c214
-rw-r--r--libavformat/au.c103
-rw-r--r--libavformat/audiointerleave.c30
-rw-r--r--libavformat/audiointerleave.h8
-rw-r--r--libavformat/avc.c8
-rw-r--r--libavformat/avc.h8
-rw-r--r--libavformat/avformat.h562
-rw-r--r--libavformat/avi.h8
-rw-r--r--libavformat/avidec.c406
-rw-r--r--libavformat/avienc.c71
-rw-r--r--libavformat/avio.c89
-rw-r--r--libavformat/avio.h78
-rw-r--r--libavformat/avio_internal.h25
-rw-r--r--libavformat/aviobuf.c166
-rw-r--r--libavformat/avisynth.c798
-rw-r--r--libavformat/avlanguage.c8
-rw-r--r--libavformat/avlanguage.h8
-rw-r--r--libavformat/avr.c93
-rw-r--r--libavformat/avs.c13
-rw-r--r--libavformat/bethsoftvid.c15
-rw-r--r--libavformat/bfi.c18
-rw-r--r--libavformat/bink.c18
-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.c52
-rw-r--r--libavformat/cafenc.c280
-rw-r--r--libavformat/cavsvideodec.c8
-rw-r--r--libavformat/cdg.c15
-rw-r--r--libavformat/cdxl.c53
-rw-r--r--libavformat/concat.c13
-rw-r--r--libavformat/concatdec.c408
-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/daud.c12
-rw-r--r--libavformat/dfa.c18
-rw-r--r--libavformat/diracdec.c8
-rw-r--r--libavformat/dnxhddec.c10
-rw-r--r--libavformat/dsicin.c13
-rw-r--r--libavformat/dtsdec.c15
-rw-r--r--libavformat/dtshddec.c139
-rw-r--r--libavformat/dv.c95
-rw-r--r--libavformat/dv.h10
-rw-r--r--libavformat/dvenc.c58
-rw-r--r--libavformat/dxa.c26
-rw-r--r--libavformat/eacdata.c17
-rw-r--r--libavformat/electronicarts.c94
-rw-r--r--libavformat/epafdec.c104
-rw-r--r--libavformat/ffm.h11
-rw-r--r--libavformat/ffmdec.c188
-rw-r--r--libavformat/ffmenc.c68
-rw-r--r--libavformat/ffmeta.h8
-rw-r--r--libavformat/ffmetadec.c16
-rw-r--r--libavformat/ffmetaenc.c8
-rw-r--r--libavformat/file.c61
-rw-r--r--libavformat/filmstripdec.c12
-rw-r--r--libavformat/filmstripenc.c10
-rw-r--r--libavformat/flac_picture.c23
-rw-r--r--libavformat/flac_picture.h11
-rw-r--r--libavformat/flacdec.c37
-rw-r--r--libavformat/flacenc.c25
-rw-r--r--libavformat/flacenc.h8
-rw-r--r--libavformat/flacenc_header.c8
-rw-r--r--libavformat/flic.c23
-rw-r--r--libavformat/flv.h32
-rw-r--r--libavformat/flvdec.c253
-rw-r--r--libavformat/flvenc.c101
-rw-r--r--libavformat/format.c27
-rw-r--r--libavformat/framecrcenc.c35
-rw-r--r--libavformat/framehash.c11
-rw-r--r--libavformat/frmdec.c110
-rw-r--r--libavformat/ftp.c721
-rw-r--r--libavformat/g722.c11
-rw-r--r--libavformat/g723_1.c10
-rw-r--r--libavformat/g729dec.c103
-rw-r--r--libavformat/gif.c374
-rw-r--r--libavformat/gifdec.c334
-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.c182
-rw-r--r--libavformat/h261dec.c10
-rw-r--r--libavformat/h263dec.c8
-rw-r--r--libavformat/h264dec.c8
-rw-r--r--libavformat/hevcdec.c66
-rw-r--r--libavformat/hls.c89
-rw-r--r--libavformat/hlsenc.c27
-rw-r--r--libavformat/hlsproto.c10
-rw-r--r--libavformat/http.c255
-rw-r--r--libavformat/http.h10
-rw-r--r--libavformat/httpauth.c8
-rw-r--r--libavformat/httpauth.h8
-rw-r--r--libavformat/icodec.c182
-rw-r--r--libavformat/icoenc.c202
-rw-r--r--libavformat/id3v1.c11
-rw-r--r--libavformat/id3v1.h8
-rw-r--r--libavformat/id3v2.c187
-rw-r--r--libavformat/id3v2.h8
-rw-r--r--libavformat/id3v2enc.c148
-rw-r--r--libavformat/idcin.c34
-rw-r--r--libavformat/idroqdec.c13
-rw-r--r--libavformat/idroqenc.c8
-rw-r--r--libavformat/iff.c294
-rw-r--r--libavformat/ilbc.c8
-rw-r--r--libavformat/img2.c19
-rw-r--r--libavformat/img2dec.c263
-rw-r--r--libavformat/img2enc.c97
-rw-r--r--libavformat/ingenientdec.c21
-rw-r--r--libavformat/internal.h49
-rw-r--r--libavformat/ipmovie.c35
-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.h25
-rw-r--r--libavformat/iss.c13
-rw-r--r--libavformat/iv8.c8
-rw-r--r--libavformat/ivfdec.c8
-rw-r--r--libavformat/ivfenc.c8
-rw-r--r--libavformat/jacosubdec.c270
-rw-r--r--libavformat/jacosubenc.c42
-rw-r--r--libavformat/jvdec.c34
-rw-r--r--libavformat/latmenc.c91
-rw-r--r--libavformat/libavformat.v33
-rw-r--r--libavformat/libgme.c201
-rw-r--r--libavformat/libmodplug.c381
-rw-r--r--libavformat/libnut.c324
-rw-r--r--libavformat/libquvi.c146
-rw-r--r--libavformat/librtmp.c8
-rw-r--r--libavformat/libssh.c229
-rw-r--r--libavformat/lmlm4.c14
-rw-r--r--libavformat/loasdec.c87
-rw-r--r--libavformat/lvfdec.c148
-rw-r--r--libavformat/lxfdec.c16
-rw-r--r--libavformat/m4vdec.c10
-rw-r--r--libavformat/matroska.c53
-rw-r--r--libavformat/matroska.h44
-rw-r--r--libavformat/matroskadec.c700
-rw-r--r--libavformat/matroskaenc.c522
-rw-r--r--libavformat/md5enc.c85
-rw-r--r--libavformat/md5proto.c8
-rw-r--r--libavformat/metadata-example.c56
-rw-r--r--libavformat/metadata.c8
-rw-r--r--libavformat/metadata.h8
-rw-r--r--libavformat/mgsts.c106
-rw-r--r--libavformat/microdvddec.c167
-rw-r--r--libavformat/microdvdenc.c67
-rw-r--r--libavformat/mkvtimestamp_v2.c50
-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.c73
-rw-r--r--libavformat/mmst.c10
-rw-r--r--libavformat/mov.c840
-rw-r--r--libavformat/mov_chan.c11
-rw-r--r--libavformat/mov_chan.h8
-rw-r--r--libavformat/movenc.c924
-rw-r--r--libavformat/movenc.h26
-rw-r--r--libavformat/movenchint.c17
-rw-r--r--libavformat/mp3dec.c198
-rw-r--r--libavformat/mp3enc.c158
-rw-r--r--libavformat/mpc.c16
-rw-r--r--libavformat/mpc8.c26
-rw-r--r--libavformat/mpeg.c538
-rw-r--r--libavformat/mpeg.h10
-rw-r--r--libavformat/mpegenc.c61
-rw-r--r--libavformat/mpegts.c481
-rw-r--r--libavformat/mpegts.h8
-rw-r--r--libavformat/mpegtsenc.c211
-rw-r--r--libavformat/mpegvideodec.c34
-rw-r--r--libavformat/mpjpeg.c19
-rw-r--r--libavformat/mpl2dec.c146
-rw-r--r--libavformat/mpsubdec.c144
-rw-r--r--libavformat/msnwc_tcp.c14
-rw-r--r--libavformat/mtv.c26
-rw-r--r--libavformat/mux.c346
-rw-r--r--libavformat/mvdec.c441
-rw-r--r--libavformat/mvi.c12
-rw-r--r--libavformat/mxf.c41
-rw-r--r--libavformat/mxf.h25
-rw-r--r--libavformat/mxfdec.c697
-rw-r--r--libavformat/mxfenc.c458
-rw-r--r--libavformat/mxg.c24
-rw-r--r--libavformat/ncdec.c10
-rw-r--r--libavformat/network.c47
-rw-r--r--libavformat/network.h23
-rw-r--r--libavformat/nistspheredec.c128
-rw-r--r--libavformat/noproxy-test.c8
-rw-r--r--libavformat/nsvdec.c65
-rw-r--r--libavformat/nullenc.c8
-rw-r--r--libavformat/nut.c180
-rw-r--r--libavformat/nut.h12
-rw-r--r--libavformat/nutdec.c126
-rw-r--r--libavformat/nutenc.c280
-rw-r--r--libavformat/nuv.c100
-rw-r--r--libavformat/oggdec.c361
-rw-r--r--libavformat/oggdec.h6
-rw-r--r--libavformat/oggenc.c48
-rw-r--r--libavformat/oggparsecelt.c29
-rw-r--r--libavformat/oggparsedirac.c8
-rw-r--r--libavformat/oggparseflac.c38
-rw-r--r--libavformat/oggparseogm.c22
-rw-r--r--libavformat/oggparseopus.c30
-rw-r--r--libavformat/oggparseskeleton.c25
-rw-r--r--libavformat/oggparsespeex.c10
-rw-r--r--libavformat/oggparsetheora.c39
-rw-r--r--libavformat/oggparsevorbis.c44
-rw-r--r--libavformat/oma.c8
-rw-r--r--libavformat/oma.h8
-rw-r--r--libavformat/omadec.c33
-rw-r--r--libavformat/omaenc.c13
-rw-r--r--libavformat/options.c22
-rw-r--r--libavformat/options_table.h29
-rw-r--r--libavformat/os_support.c8
-rw-r--r--libavformat/os_support.h19
-rw-r--r--libavformat/output-example.c527
-rw-r--r--libavformat/paf.c262
-rw-r--r--libavformat/pcm.c28
-rw-r--r--libavformat/pcm.h9
-rw-r--r--libavformat/pcmdec.c38
-rw-r--r--libavformat/pcmenc.c8
-rw-r--r--libavformat/pjsdec.c137
-rw-r--r--libavformat/pmpdec.c91
-rw-r--r--libavformat/psxstr.c68
-rw-r--r--libavformat/pva.c27
-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.c54
-rw-r--r--libavformat/rawdec.h10
-rw-r--r--libavformat/rawenc.c54
-rw-r--r--libavformat/rawenc.h8
-rw-r--r--libavformat/rawvideodec.c40
-rw-r--r--libavformat/rdt.c12
-rw-r--r--libavformat/rdt.h8
-rw-r--r--libavformat/realtextdec.c153
-rw-r--r--libavformat/redspark.c170
-rw-r--r--libavformat/riff.c66
-rw-r--r--libavformat/riff.h17
-rw-r--r--libavformat/riffdec.c55
-rw-r--r--libavformat/riffenc.c35
-rw-r--r--libavformat/rl2.c23
-rw-r--r--libavformat/rm.c8
-rw-r--r--libavformat/rm.h10
-rw-r--r--libavformat/rmdec.c170
-rw-r--r--libavformat/rmenc.c17
-rw-r--r--libavformat/rmsipr.c8
-rw-r--r--libavformat/rmsipr.h8
-rw-r--r--libavformat/rpl.c28
-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.c8
-rw-r--r--libavformat/rtmppkt.h8
-rw-r--r--libavformat/rtmpproto.c37
-rw-r--r--libavformat/rtp.c11
-rw-r--r--libavformat/rtp.h8
-rw-r--r--libavformat/rtpdec.c10
-rw-r--r--libavformat/rtpdec.h8
-rw-r--r--libavformat/rtpdec_amr.c8
-rw-r--r--libavformat/rtpdec_asf.c8
-rw-r--r--libavformat/rtpdec_formats.h8
-rw-r--r--libavformat/rtpdec_g726.c8
-rw-r--r--libavformat/rtpdec_h263.c8
-rw-r--r--libavformat/rtpdec_h263_rfc2190.c8
-rw-r--r--libavformat/rtpdec_h264.c8
-rw-r--r--libavformat/rtpdec_ilbc.c8
-rw-r--r--libavformat/rtpdec_jpeg.c8
-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.c8
-rw-r--r--libavformat/rtpdec_qcelp.c8
-rw-r--r--libavformat/rtpdec_qdm2.c16
-rw-r--r--libavformat/rtpdec_qt.c8
-rw-r--r--libavformat/rtpdec_svq3.c13
-rw-r--r--libavformat/rtpdec_vp8.c8
-rw-r--r--libavformat/rtpdec_xiph.c18
-rw-r--r--libavformat/rtpenc.c19
-rw-r--r--libavformat/rtpenc.h12
-rw-r--r--libavformat/rtpenc_aac.c8
-rw-r--r--libavformat/rtpenc_amr.c8
-rw-r--r--libavformat/rtpenc_chain.c12
-rw-r--r--libavformat/rtpenc_chain.h8
-rw-r--r--libavformat/rtpenc_h263.c12
-rw-r--r--libavformat/rtpenc_h263_rfc2190.c8
-rw-r--r--libavformat/rtpenc_h264.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.c23
-rw-r--r--libavformat/rtsp.h20
-rw-r--r--libavformat/rtspcodes.h8
-rw-r--r--libavformat/rtspdec.c10
-rw-r--r--libavformat/rtspenc.c8
-rw-r--r--libavformat/samidec.c137
-rw-r--r--libavformat/sapdec.c8
-rw-r--r--libavformat/sapenc.c8
-rw-r--r--libavformat/sauce.c10
-rw-r--r--libavformat/sauce.h8
-rw-r--r--libavformat/sbgdec.c1511
-rw-r--r--libavformat/sctp.c16
-rw-r--r--libavformat/sdp.c24
-rw-r--r--libavformat/seek-test.c43
-rw-r--r--libavformat/seek.c8
-rw-r--r--libavformat/seek.h8
-rw-r--r--libavformat/segafilm.c72
-rw-r--r--libavformat/segment.c716
-rw-r--r--libavformat/sierravmd.c82
-rw-r--r--libavformat/siff.c59
-rw-r--r--libavformat/smacker.c56
-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.c238
-rw-r--r--libavformat/sol.c15
-rw-r--r--libavformat/sox.h8
-rw-r--r--libavformat/soxdec.c38
-rw-r--r--libavformat/soxenc.c23
-rw-r--r--libavformat/spdif.c8
-rw-r--r--libavformat/spdif.h11
-rw-r--r--libavformat/spdifdec.c33
-rw-r--r--libavformat/spdifenc.c30
-rw-r--r--libavformat/srtdec.c147
-rw-r--r--libavformat/srtenc.c115
-rw-r--r--libavformat/srtp.c8
-rw-r--r--libavformat/srtp.h8
-rw-r--r--libavformat/srtpproto.c8
-rw-r--r--libavformat/subtitles.c283
-rw-r--r--libavformat/subtitles.h124
-rw-r--r--libavformat/subviewer1dec.c124
-rw-r--r--libavformat/subviewerdec.c194
-rw-r--r--libavformat/swf.c8
-rw-r--r--libavformat/swf.h105
-rw-r--r--libavformat/swfdec.c299
-rw-r--r--libavformat/swfenc.c25
-rw-r--r--libavformat/takdec.c49
-rw-r--r--libavformat/tcp.c62
-rw-r--r--libavformat/tedcaptionsdec.c366
-rw-r--r--libavformat/tee.c498
-rw-r--r--libavformat/thp.c21
-rw-r--r--libavformat/tiertexseq.c8
-rw-r--r--libavformat/tls.c57
-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.c257
-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.c1844
-rw-r--r--libavformat/vc1test.c14
-rw-r--r--libavformat/vc1testenc.c11
-rw-r--r--libavformat/version.h36
-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.c18
-rw-r--r--libavformat/w64.c50
-rw-r--r--libavformat/w64.h31
-rw-r--r--libavformat/wavdec.c357
-rw-r--r--libavformat/wavenc.c199
-rw-r--r--libavformat/wc3movie.c12
-rw-r--r--libavformat/webvttdec.c223
-rw-r--r--libavformat/webvttenc.c99
-rw-r--r--libavformat/westwood_aud.c10
-rw-r--r--libavformat/westwood_vqa.c47
-rw-r--r--libavformat/wtv.c1115
-rw-r--r--libavformat/wtv.h58
-rw-r--r--libavformat/wtv_common.c82
-rw-r--r--libavformat/wtvdec.c1095
-rw-r--r--libavformat/wtvenc.c805
-rw-r--r--libavformat/wv.c8
-rw-r--r--libavformat/wv.h8
-rw-r--r--libavformat/wvdec.c20
-rw-r--r--libavformat/wvenc.c12
-rw-r--r--libavformat/xa.c11
-rw-r--r--libavformat/xmv.c192
-rw-r--r--libavformat/xwma.c8
-rw-r--r--libavformat/yop.c26
-rw-r--r--libavformat/yuv4mpeg.c294
-rw-r--r--libavresample/arm/audio_convert_init.c8
-rw-r--r--libavresample/arm/audio_convert_neon.S8
-rw-r--r--libavresample/audio_convert.c8
-rw-r--r--libavresample/audio_convert.h8
-rw-r--r--libavresample/audio_data.c8
-rw-r--r--libavresample/audio_data.h8
-rw-r--r--libavresample/audio_mix.c8
-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/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--libavutil/Makefile37
-rw-r--r--libavutil/adler32.c46
-rw-r--r--libavutil/adler32.h17
-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.c8
-rw-r--r--libavutil/arm/cpu.h8
-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/timer.h8
-rw-r--r--libavutil/atomic.c14
-rw-r--r--libavutil/atomic.h8
-rw-r--r--libavutil/atomic_gcc.h8
-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.c8
-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.c91
-rw-r--r--libavutil/avstring.h86
-rw-r--r--libavutil/avutil.h116
-rw-r--r--libavutil/base64.c171
-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.h8
-rw-r--r--libavutil/buffer.c41
-rw-r--r--libavutil/buffer.h19
-rw-r--r--libavutil/buffer_internal.h10
-rw-r--r--libavutil/channel_layout.c198
-rw-r--r--libavutil/channel_layout.h51
-rw-r--r--libavutil/colorspace.h8
-rw-r--r--libavutil/common.h75
-rw-r--r--libavutil/cpu.c96
-rw-r--r--libavutil/cpu.h42
-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.c27
-rw-r--r--libavutil/dict.h14
-rw-r--r--libavutil/error.c95
-rw-r--r--libavutil/error.h74
-rw-r--r--libavutil/eval.c226
-rw-r--r--libavutil/eval.h12
-rw-r--r--libavutil/fifo.c47
-rw-r--r--libavutil/fifo.h21
-rw-r--r--libavutil/file.c74
-rw-r--r--libavutil/file.h20
-rw-r--r--libavutil/file_open.c16
-rw-r--r--libavutil/float_dsp.c15
-rw-r--r--libavutil/float_dsp.h11
-rw-r--r--libavutil/frame.c151
-rw-r--r--libavutil/frame.h179
-rw-r--r--libavutil/hash.c204
-rw-r--r--libavutil/hash.h90
-rw-r--r--libavutil/hmac.c128
-rw-r--r--libavutil/hmac.h12
-rw-r--r--libavutil/imgutils.c145
-rw-r--r--libavutil/imgutils.h70
-rw-r--r--libavutil/integer.c196
-rw-r--r--libavutil/integer.h86
-rw-r--r--libavutil/internal.h25
-rw-r--r--libavutil/intfloat.h8
-rw-r--r--libavutil/intfloat_readwrite.c11
-rw-r--r--libavutil/intfloat_readwrite.h8
-rw-r--r--libavutil/intmath.c8
-rw-r--r--libavutil/intmath.h12
-rw-r--r--libavutil/intreadwrite.h94
-rw-r--r--libavutil/lfg.c12
-rw-r--r--libavutil/lfg.h8
-rw-r--r--libavutil/libavutil.v2
-rw-r--r--libavutil/libm.h19
-rw-r--r--libavutil/lls.c8
-rw-r--r--libavutil/lls.h8
-rw-r--r--libavutil/log.c189
-rw-r--r--libavutil/log.h64
-rw-r--r--libavutil/log2_tab.c10
-rw-r--r--libavutil/lzo.c60
-rw-r--r--libavutil/lzo.h8
-rw-r--r--libavutil/mathematics.c50
-rw-r--r--libavutil/mathematics.h46
-rw-r--r--libavutil/md5.c103
-rw-r--r--libavutil/md5.h46
-rw-r--r--libavutil/mem.c181
-rw-r--r--libavutil/mem.h110
-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/murmur3.c192
-rw-r--r--libavutil/murmur3.h32
-rw-r--r--libavutil/old_pix_fmts.h55
-rw-r--r--libavutil/opencl.c812
-rw-r--r--libavutil/opencl.h287
-rw-r--r--libavutil/opencl_internal.c59
-rw-r--r--libavutil/opencl_internal.h33
-rw-r--r--libavutil/opt.c961
-rw-r--r--libavutil/opt.h263
-rw-r--r--libavutil/parseutils.c294
-rw-r--r--libavutil/parseutils.h77
-rw-r--r--libavutil/pca.c248
-rw-r--r--libavutil/pca.h35
-rw-r--r--libavutil/pixdesc.c643
-rw-r--r--libavutil/pixdesc.h39
-rw-r--r--libavutil/pixfmt.h140
-rw-r--r--libavutil/ppc/cpu.c10
-rw-r--r--libavutil/ppc/cpu.h8
-rw-r--r--libavutil/ppc/float_dsp_altivec.c8
-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.h8
-rw-r--r--libavutil/qsort.h117
-rw-r--r--libavutil/random_seed.c94
-rw-r--r--libavutil/random_seed.h19
-rw-r--r--libavutil/rational.c43
-rw-r--r--libavutil/rational.h10
-rw-r--r--libavutil/rc4.c8
-rw-r--r--libavutil/rc4.h8
-rw-r--r--libavutil/ripemd.c515
-rw-r--r--libavutil/ripemd.h75
-rw-r--r--libavutil/samplefmt.c61
-rw-r--r--libavutil/samplefmt.h60
-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.h126
-rw-r--r--libavutil/time.c10
-rw-r--r--libavutil/time.h10
-rw-r--r--libavutil/timecode.c218
-rw-r--r--libavutil/timecode.h140
-rw-r--r--libavutil/timer.h8
-rw-r--r--libavutil/timestamp.h74
-rw-r--r--libavutil/tomi/intreadwrite.h8
-rw-r--r--libavutil/tree.c46
-rw-r--r--libavutil/tree.h20
-rw-r--r--libavutil/utils.c70
-rw-r--r--libavutil/version.h70
-rw-r--r--libavutil/x86/asm.h8
-rw-r--r--libavutil/x86/bswap.h8
-rw-r--r--libavutil/x86/cpu.c8
-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.asm22
-rw-r--r--libavutil/x86/float_dsp_init.c8
-rw-r--r--libavutil/x86/intreadwrite.h8
-rw-r--r--libavutil/x86/lls.asm11
-rw-r--r--libavutil/x86/lls_init.c8
-rw-r--r--libavutil/x86/timer.h8
-rw-r--r--libavutil/x86/w64xmmtest.h8
-rw-r--r--libavutil/x86/x86inc.asm8
-rw-r--r--libavutil/x86/x86util.asm8
-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/Makefile9
-rw-r--r--libpostproc/libpostproc.v4
-rw-r--r--libpostproc/postprocess.c1045
-rw-r--r--libpostproc/postprocess.h106
-rw-r--r--libpostproc/postprocess_altivec_template.c1210
-rw-r--r--libpostproc/postprocess_internal.h179
-rw-r--r--libpostproc/postprocess_template.c3714
-rw-r--r--libpostproc/version.h45
-rw-r--r--library.mak21
-rw-r--r--libswresample/Makefile18
-rw-r--r--libswresample/arm/Makefile2
-rw-r--r--libswresample/arm/audio_convert_init.c67
-rw-r--r--libswresample/arm/audio_convert_neon.S363
-rw-r--r--libswresample/audioconvert.c224
-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/rematrix.c500
-rw-r--r--libswresample/rematrix_template.c106
-rw-r--r--libswresample/resample.c372
-rw-r--r--libswresample/resample_template.c211
-rw-r--r--libswresample/soxr_resample.c93
-rw-r--r--libswresample/swresample-test.c414
-rw-r--r--libswresample/swresample.c934
-rw-r--r--libswresample/swresample.h311
-rw-r--r--libswresample/swresample_internal.h199
-rw-r--r--libswresample/version.h45
-rw-r--r--libswresample/x86/Makefile3
-rw-r--r--libswresample/x86/audio_convert.asm465
-rw-r--r--libswresample/x86/rematrix.asm250
-rw-r--r--libswresample/x86/resample_mmx.h70
-rw-r--r--libswresample/x86/swresample_x86.c200
-rw-r--r--libswscale/Makefile2
-rw-r--r--libswscale/bfin/internal_bfin.S8
-rw-r--r--libswscale/bfin/swscale_bfin.c8
-rw-r--r--libswscale/bfin/yuv2rgb_bfin.c11
-rw-r--r--libswscale/colorspace-test.c18
-rw-r--r--libswscale/input.c625
-rw-r--r--libswscale/options.c29
-rw-r--r--libswscale/output.c944
-rw-r--r--libswscale/ppc/swscale_altivec.c10
-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.c105
-rw-r--r--libswscale/sparc/yuv2rgb_vis.c8
-rw-r--r--libswscale/swscale-test.c70
-rw-r--r--libswscale/swscale.c577
-rw-r--r--libswscale/swscale.h32
-rw-r--r--libswscale/swscale_internal.h197
-rw-r--r--libswscale/swscale_unscaled.c987
-rw-r--r--libswscale/utils.c628
-rw-r--r--libswscale/version.h15
-rw-r--r--libswscale/x86/Makefile2
-rw-r--r--libswscale/x86/input.asm206
-rw-r--r--libswscale/x86/output.asm12
-rw-r--r--libswscale/x86/rgb2rgb.c12
-rw-r--r--libswscale/x86/rgb2rgb_template.c151
-rw-r--r--libswscale/x86/scale.asm12
-rw-r--r--libswscale/x86/swscale.c137
-rw-r--r--libswscale/x86/swscale_template.c130
-rw-r--r--libswscale/x86/w64xmmtest.c8
-rw-r--r--libswscale/x86/yuv2rgb.c13
-rw-r--r--libswscale/x86/yuv2rgb_template.c35
-rw-r--r--libswscale/yuv2rgb.c125
-rw-r--r--presets/libvpx-1080p.avpreset17
-rw-r--r--presets/libvpx-1080p.ffpreset19
-rw-r--r--presets/libvpx-1080p50_60.avpreset17
-rw-r--r--presets/libvpx-1080p50_60.ffpreset19
-rw-r--r--presets/libvpx-360p.avpreset16
-rw-r--r--presets/libvpx-360p.ffpreset18
-rw-r--r--presets/libvpx-720p.avpreset17
-rw-r--r--presets/libvpx-720p.ffpreset19
-rw-r--r--presets/libvpx-720p50_60.avpreset17
-rw-r--r--presets/libvpx-720p50_60.ffpreset19
-rw-r--r--presets/libx264-baseline.avpreset1
-rw-r--r--presets/libx264-fast.avpreset1
-rw-r--r--presets/libx264-fast_firstpass.avpreset2
-rw-r--r--presets/libx264-faster.avpreset1
-rw-r--r--presets/libx264-faster_firstpass.avpreset2
-rw-r--r--presets/libx264-ipod320.avpreset4
-rw-r--r--presets/libx264-ipod320.ffpreset6
-rw-r--r--presets/libx264-ipod640.avpreset4
-rw-r--r--presets/libx264-ipod640.ffpreset6
-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/Makefile68
-rw-r--r--tests/audiogen.c8
-rw-r--r--tests/base64.c8
-rwxr-xr-xtests/copycooker.sh30
-rwxr-xr-xtests/fate-run.sh79
-rwxr-xr-xtests/fate-update.sh55
-rw-r--r--tests/fate-valgrind.supp31
-rwxr-xr-xtests/fate.sh6
-rw-r--r--tests/fate/aac.mak23
-rw-r--r--tests/fate/ac3.mak3
-rw-r--r--tests/fate/acodec.mak54
-rw-r--r--tests/fate/adpcm.mak15
-rw-r--r--tests/fate/audio.mak38
-rw-r--r--tests/fate/avformat.mak23
-rw-r--r--tests/fate/cover-art.mak23
-rw-r--r--tests/fate/demux.mak87
-rw-r--r--tests/fate/ea.mak15
-rw-r--r--tests/fate/exif.mak14
-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.mak27
-rw-r--r--tests/fate/filter-video.mak233
-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.mak156
-rw-r--r--tests/fate/image.mak40
-rw-r--r--tests/fate/libavcodec.mak2
-rw-r--r--tests/fate/libavresample.mak8
-rw-r--r--tests/fate/libavutil.mak20
-rw-r--r--tests/fate/libswresample.mak276
-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/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.mak17
-rw-r--r--tests/fate/screen.mak17
-rw-r--r--tests/fate/seek.mak6
-rw-r--r--tests/fate/subtitles.mak62
-rw-r--r--tests/fate/utvideo.mak2
-rw-r--r--tests/fate/vcodec.mak81
-rw-r--r--tests/fate/video.mak168
-rw-r--r--tests/fate/voice.mak24
-rw-r--r--tests/fate/vpx.mak45
-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.conf307
-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_yuv4444
-rw-r--r--tests/filtergraphs/scalenorm4
-rwxr-xr-xtests/lavf-regression.sh131
-rw-r--r--tests/md5.sh2
-rw-r--r--tests/ref/acodec/adpcm-ima_qt2
-rw-r--r--tests/ref/acodec/adpcm_ima_qt4
-rw-r--r--tests/ref/acodec/alac4
-rw-r--r--tests/ref/acodec/flac4
-rw-r--r--tests/ref/acodec/g723_14
-rw-r--r--tests/ref/acodec/pcm-f32be4
-rw-r--r--tests/ref/acodec/pcm-f64be4
-rw-r--r--tests/ref/acodec/pcm-s16be4
-rw-r--r--tests/ref/acodec/pcm-s16be_planar4
-rw-r--r--tests/ref/acodec/pcm-s16le_planar4
-rw-r--r--tests/ref/acodec/pcm-s24be4
-rw-r--r--tests/ref/acodec/pcm-s24le_planar4
-rw-r--r--tests/ref/acodec/pcm-s32be4
-rw-r--r--tests/ref/acodec/pcm-s32le_planar4
-rw-r--r--tests/ref/acodec/pcm-s84
-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/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/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/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/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/ea-mad194
-rw-r--r--tests/ref/fate/ea-tgq558
-rw-r--r--tests/ref/fate/ea-tqi54
-rw-r--r--tests/ref/fate/eval78
-rw-r--r--tests/ref/fate/exif-image-embedded360
-rw-r--r--tests/ref/fate/exif-image-jpg224
-rw-r--r--tests/ref/fate/exif-image-tiff25
-rw-r--r--tests/ref/fate/exr-slice-pxr242
-rw-r--r--tests/ref/fate/exr-slice-raw2
-rw-r--r--tests/ref/fate/exr-slice-rle2
-rw-r--r--tests/ref/fate/exr-slice-zip12
-rw-r--r--tests/ref/fate/exr-slice-zip162
-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_default616
-rw-r--r--tests/ref/fate/ffprobe_flat552
-rw-r--r--tests/ref/fate/ffprobe_ini629
-rw-r--r--tests/ref/fate/ffprobe_json600
-rw-r--r--tests/ref/fate/ffprobe_xml54
-rw-r--r--tests/ref/fate/film-cvid220
-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-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-fade98
-rw-r--r--tests/ref/fate/filter-gradfun-sample21
-rw-r--r--tests/ref/fate/filter-histogram-levels51
-rw-r--r--tests/ref/fate/filter-histogram-waveform51
-rw-r--r--tests/ref/fate/filter-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_yuv44451
-rw-r--r--tests/ref/fate/filter-pad1
-rw-r--r--tests/ref/fate/filter-phase51
-rw-r--r--tests/ref/fate/filter-pixdesc204
-rw-r--r--tests/ref/fate/filter-pixfmts-copy205
-rw-r--r--tests/ref/fate/filter-pixfmts-crop154
-rw-r--r--tests/ref/fate/filter-pixfmts-field116
-rw-r--r--tests/ref/fate/filter-pixfmts-fieldorder89
-rw-r--r--tests/ref/fate/filter-pixfmts-hflip154
-rw-r--r--tests/ref/fate/filter-pixfmts-histeq6
-rw-r--r--tests/ref/fate/filter-pixfmts-il115
-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-null205
-rw-r--r--tests/ref/fate/filter-pixfmts-pad44
-rw-r--r--tests/ref/fate/filter-pixfmts-rotate20
-rw-r--r--tests/ref/fate/filter-pixfmts-scale205
-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-vflip205
-rw-r--r--tests/ref/fate/filter-pp1
-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/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-restore4
-rw-r--r--tests/ref/fate/gif-gray37
-rw-r--r--tests/ref/fate/gifenc-bgr4_byte174
-rw-r--r--tests/ref/fate/gifenc-bgr8174
-rw-r--r--tests/ref/fate/gifenc-gray174
-rw-r--r--tests/ref/fate/gifenc-pal8174
-rw-r--r--tests/ref/fate/gifenc-rgb4_byte174
-rw-r--r--tests/ref/fate/gifenc-rgb8174
-rw-r--r--tests/ref/fate/h264-conformance-frext-hi422fr10_sony_b6
-rw-r--r--tests/ref/fate/h264-conformance-frext-hi422fr13_sony_b6
-rw-r--r--tests/ref/fate/h264-conformance-frext-hi422fr1_sony_a6
-rw-r--r--tests/ref/fate/h264-conformance-frext-hi422fr6_sony_a6
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i1_panasonic_a11
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i2_panasonic_a11
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i3_panasonic_a11
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i4_panasonic_a11
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i5_panasonic_a11
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i6_panasonic_a11
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i7_panasonic_a11
-rw-r--r--tests/ref/fate/h264-crop-to-container8
-rw-r--r--tests/ref/fate/h264-extreme-plane-pred4
-rw-r--r--tests/ref/fate/h264-lossless20
-rw-r--r--tests/ref/fate/hevc-conformance-AMP_A_Samsung_461
-rw-r--r--tests/ref/fate/hevc-conformance-AMP_B_Samsung_461
-rw-r--r--tests/ref/fate/hevc-conformance-AMP_D_Hisilicon101
-rw-r--r--tests/ref/fate/hevc-conformance-AMP_E_Hisilicon101
-rw-r--r--tests/ref/fate/hevc-conformance-AMP_F_Hisilicon_3101
-rw-r--r--tests/ref/fate/hevc-conformance-AMVP_A_MTK_431
-rw-r--r--tests/ref/fate/hevc-conformance-AMVP_B_MTK_442
-rw-r--r--tests/ref/fate/hevc-conformance-AMVP_C_Samsung_461
-rw-r--r--tests/ref/fate/hevc-conformance-CAINIT_A_SHARP_451
-rw-r--r--tests/ref/fate/hevc-conformance-CAINIT_B_SHARP_451
-rw-r--r--tests/ref/fate/hevc-conformance-CAINIT_C_SHARP_351
-rw-r--r--tests/ref/fate/hevc-conformance-CAINIT_D_SHARP_351
-rw-r--r--tests/ref/fate/hevc-conformance-CAINIT_E_SHARP_351
-rw-r--r--tests/ref/fate/hevc-conformance-CAINIT_F_SHARP_351
-rw-r--r--tests/ref/fate/hevc-conformance-CAINIT_G_SHARP_351
-rw-r--r--tests/ref/fate/hevc-conformance-CAINIT_H_SHARP_351
-rw-r--r--tests/ref/fate/hevc-conformance-CIP_A_Panasonic_33
-rw-r--r--tests/ref/fate/hevc-conformance-CIP_C_Panasonic_23
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_A_MAIN10_VIXS_29
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_A_SONY_331
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_B_SONY_331
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_C_SONY_331
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_D_VIXS_19
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_D_VIXS_29
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_E_VIXS_19
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_E_VIXS_29
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_F_VIXS_19
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_F_VIXS_29
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_G_VIXS_19
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_G_VIXS_29
-rw-r--r--tests/ref/fate/hevc-conformance-DELTAQP_B_SONY_331
-rw-r--r--tests/ref/fate/hevc-conformance-DELTAQP_C_SONY_331
-rw-r--r--tests/ref/fate/hevc-conformance-DSLICE_A_HHI_551
-rw-r--r--tests/ref/fate/hevc-conformance-DSLICE_B_HHI_551
-rw-r--r--tests/ref/fate/hevc-conformance-DSLICE_C_HHI_551
-rw-r--r--tests/ref/fate/hevc-conformance-ENTP_A_LG_251
-rw-r--r--tests/ref/fate/hevc-conformance-ENTP_B_LG_251
-rw-r--r--tests/ref/fate/hevc-conformance-ENTP_C_LG_351
-rw-r--r--tests/ref/fate/hevc-conformance-EXT_A_ericsson_34
-rw-r--r--tests/ref/fate/hevc-conformance-IPRED_A_docomo_221
-rw-r--r--tests/ref/fate/hevc-conformance-IPRED_B_Nokia_32
-rw-r--r--tests/ref/fate/hevc-conformance-IPRED_C_Mitsubishi_25
-rw-r--r--tests/ref/fate/hevc-conformance-LS_A_Orange_210
-rw-r--r--tests/ref/fate/hevc-conformance-LS_B_ORANGE_326
-rw-r--r--tests/ref/fate/hevc-conformance-MAXBINS_A_TI_43
-rw-r--r--tests/ref/fate/hevc-conformance-MAXBINS_B_TI_44
-rw-r--r--tests/ref/fate/hevc-conformance-MAXBINS_C_TI_44
-rw-r--r--tests/ref/fate/hevc-conformance-MERGE_A_TI_39
-rw-r--r--tests/ref/fate/hevc-conformance-MERGE_B_TI_39
-rw-r--r--tests/ref/fate/hevc-conformance-MERGE_C_TI_39
-rw-r--r--tests/ref/fate/hevc-conformance-MERGE_D_TI_39
-rw-r--r--tests/ref/fate/hevc-conformance-MERGE_E_TI_39
-rw-r--r--tests/ref/fate/hevc-conformance-MERGE_F_MTK_442
-rw-r--r--tests/ref/fate/hevc-conformance-MERGE_G_HHI_43
-rw-r--r--tests/ref/fate/hevc-conformance-MVCLIP_A_qualcomm_36
-rw-r--r--tests/ref/fate/hevc-conformance-MVDL1ZERO_A_docomo_3501
-rw-r--r--tests/ref/fate/hevc-conformance-MVEDGE_A_qualcomm_318
-rw-r--r--tests/ref/fate/hevc-conformance-NUT_A_ericsson_435
-rw-r--r--tests/ref/fate/hevc-conformance-PICSIZE_A_Bossen_111
-rw-r--r--tests/ref/fate/hevc-conformance-PICSIZE_B_Bossen_111
-rw-r--r--tests/ref/fate/hevc-conformance-PICSIZE_C_Bossen_111
-rw-r--r--tests/ref/fate/hevc-conformance-PICSIZE_D_Bossen_111
-rw-r--r--tests/ref/fate/hevc-conformance-PMERGE_A_TI_39
-rw-r--r--tests/ref/fate/hevc-conformance-PMERGE_B_TI_39
-rw-r--r--tests/ref/fate/hevc-conformance-PMERGE_C_TI_39
-rw-r--r--tests/ref/fate/hevc-conformance-PMERGE_D_TI_39
-rw-r--r--tests/ref/fate/hevc-conformance-PMERGE_E_TI_39
-rw-r--r--tests/ref/fate/hevc-conformance-POC_A_Bossen_36
-rw-r--r--tests/ref/fate/hevc-conformance-PPS_A_qualcomm_782
-rw-r--r--tests/ref/fate/hevc-conformance-PS_A_VIDYO_326
-rw-r--r--tests/ref/fate/hevc-conformance-PS_B_VIDYO_326
-rw-r--r--tests/ref/fate/hevc-conformance-RAP_A_docomo_487
-rw-r--r--tests/ref/fate/hevc-conformance-RAP_B_Bossen_184
-rw-r--r--tests/ref/fate/hevc-conformance-RPLM_A_qualcomm_4301
-rw-r--r--tests/ref/fate/hevc-conformance-RPLM_B_qualcomm_4301
-rw-r--r--tests/ref/fate/hevc-conformance-RPS_A_docomo_445
-rw-r--r--tests/ref/fate/hevc-conformance-RPS_B_qualcomm_5301
-rw-r--r--tests/ref/fate/hevc-conformance-RPS_C_ericsson_441
-rw-r--r--tests/ref/fate/hevc-conformance-RPS_D_ericsson_569
-rw-r--r--tests/ref/fate/hevc-conformance-RPS_E_qualcomm_5301
-rw-r--r--tests/ref/fate/hevc-conformance-RQT_A_HHI_43
-rw-r--r--tests/ref/fate/hevc-conformance-RQT_B_HHI_43
-rw-r--r--tests/ref/fate/hevc-conformance-RQT_C_HHI_43
-rw-r--r--tests/ref/fate/hevc-conformance-RQT_D_HHI_43
-rw-r--r--tests/ref/fate/hevc-conformance-RQT_E_HHI_43
-rw-r--r--tests/ref/fate/hevc-conformance-RQT_F_HHI_43
-rw-r--r--tests/ref/fate/hevc-conformance-RQT_G_HHI_43
-rw-r--r--tests/ref/fate/hevc-conformance-SAO_A_MediaTek_461
-rw-r--r--tests/ref/fate/hevc-conformance-SAO_B_MediaTek_561
-rw-r--r--tests/ref/fate/hevc-conformance-SAO_C_Samsung_461
-rw-r--r--tests/ref/fate/hevc-conformance-SAO_D_Samsung_461
-rw-r--r--tests/ref/fate/hevc-conformance-SAO_E_Canon_417
-rw-r--r--tests/ref/fate/hevc-conformance-SAO_F_Canon_317
-rw-r--r--tests/ref/fate/hevc-conformance-SAO_G_Canon_317
-rw-r--r--tests/ref/fate/hevc-conformance-SDH_A_Orange_33
-rw-r--r--tests/ref/fate/hevc-conformance-SLICES_A_Rovi_310
-rw-r--r--tests/ref/fate/hevc-conformance-SLIST_A_Sony_466
-rw-r--r--tests/ref/fate/hevc-conformance-SLIST_B_Sony_866
-rw-r--r--tests/ref/fate/hevc-conformance-SLIST_C_Sony_366
-rw-r--r--tests/ref/fate/hevc-conformance-SLIST_D_Sony_966
-rw-r--r--tests/ref/fate/hevc-conformance-STRUCT_A_Samsung_561
-rw-r--r--tests/ref/fate/hevc-conformance-STRUCT_B_Samsung_461
-rw-r--r--tests/ref/fate/hevc-conformance-TILES_A_Cisco_2101
-rw-r--r--tests/ref/fate/hevc-conformance-TILES_B_Cisco_1101
-rw-r--r--tests/ref/fate/hevc-conformance-TMVP_A_MS_218
-rw-r--r--tests/ref/fate/hevc-conformance-TSCL_A_VIDYO_574
-rw-r--r--tests/ref/fate/hevc-conformance-TSCL_B_VIDYO_474
-rw-r--r--tests/ref/fate/hevc-conformance-TSKIP_A_MS_218
-rw-r--r--tests/ref/fate/hevc-conformance-WPP_A_ericsson_MAIN10_249
-rw-r--r--tests/ref/fate/hevc-conformance-WPP_A_ericsson_MAIN_249
-rw-r--r--tests/ref/fate/hevc-conformance-WPP_B_ericsson_MAIN10_249
-rw-r--r--tests/ref/fate/hevc-conformance-WPP_B_ericsson_MAIN_249
-rw-r--r--tests/ref/fate/hevc-conformance-WPP_C_ericsson_MAIN10_249
-rw-r--r--tests/ref/fate/hevc-conformance-WPP_C_ericsson_MAIN_249
-rw-r--r--tests/ref/fate/hevc-conformance-WPP_D_ericsson_MAIN10_249
-rw-r--r--tests/ref/fate/hevc-conformance-WPP_D_ericsson_MAIN_249
-rw-r--r--tests/ref/fate/hevc-conformance-WPP_E_ericsson_MAIN10_249
-rw-r--r--tests/ref/fate/hevc-conformance-WPP_E_ericsson_MAIN_249
-rw-r--r--tests/ref/fate/hevc-conformance-WPP_F_ericsson_MAIN10_249
-rw-r--r--tests/ref/fate/hevc-conformance-WPP_F_ericsson_MAIN_249
-rw-r--r--tests/ref/fate/hevc-conformance-WP_A_MAIN10_Toshiba_3257
-rw-r--r--tests/ref/fate/hevc-conformance-WP_A_Toshiba_3257
-rw-r--r--tests/ref/fate/hevc-conformance-WP_B_Toshiba_3257
-rw-r--r--tests/ref/fate/hevc-conformance-WP_MAIN10_B_Toshiba_3257
-rw-r--r--tests/ref/fate/hevc-conformance-cip_B_NEC_26
-rw-r--r--tests/ref/fate/hevc-conformance-ipcm_A_NEC_22
-rw-r--r--tests/ref/fate/hevc-conformance-ipcm_B_NEC_22
-rw-r--r--tests/ref/fate/hevc-conformance-ipcm_C_NEC_22
-rw-r--r--tests/ref/fate/hevc-conformance-ipcm_D_NEC_22
-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-demux10
-rw-r--r--tests/ref/fate/jv8
-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-demux168
-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/mkv217
-rw-r--r--tests/ref/fate/motionpixels220
-rw-r--r--tests/ref/fate/mpeg2-field-enc62
-rw-r--r--tests/ref/fate/msvideo1-16bit60
-rw-r--r--tests/ref/fate/mtv2
-rw-r--r--tests/ref/fate/murmur31
-rw-r--r--tests/ref/fate/mxf-demux170
-rw-r--r--tests/ref/fate/mxpeg31
-rw-r--r--tests/ref/fate/nc-demux176
-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/paf-audio7
-rw-r--r--tests/ref/fate/paf-demux160
-rw-r--r--tests/ref/fate/paf-video153
-rw-r--r--tests/ref/fate/parseutils43
-rw-r--r--tests/ref/fate/pictor2
-rw-r--r--tests/ref/fate/pmp-demux106
-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/sanm16
-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-aqtitle1
-rw-r--r--tests/ref/fate/sub-charenc1
-rw-r--r--tests/ref/fate/sub-jacosub1
-rw-r--r--tests/ref/fate/sub-microdvd1
-rw-r--r--tests/ref/fate/sub-microdvd-remux1
-rw-r--r--tests/ref/fate/sub-movtext1
-rw-r--r--tests/ref/fate/sub-movtextenc1
-rw-r--r--tests/ref/fate/sub-mpl21
-rw-r--r--tests/ref/fate/sub-mpsub1
-rw-r--r--tests/ref/fate/sub-mpsub-frames1
-rw-r--r--tests/ref/fate/sub-pjs1
-rw-r--r--tests/ref/fate/sub-realtext1
-rw-r--r--tests/ref/fate/sub-sami1
-rw-r--r--tests/ref/fate/sub-srt2
-rw-r--r--tests/ref/fate/sub-subripenc1
-rw-r--r--tests/ref/fate/sub-subviewer1
-rw-r--r--tests/ref/fate/sub-subviewer11
-rw-r--r--tests/ref/fate/sub-vplayer1
-rw-r--r--tests/ref/fate/sub-webvtt1
-rw-r--r--tests/ref/fate/sub2video95
-rw-r--r--tests/ref/fate/svq1300
-rw-r--r--tests/ref/fate/svq3360
-rw-r--r--tests/ref/fate/targa-conformance-CCM82
-rw-r--r--tests/ref/fate/targa-conformance-UCM82
-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/txd-16bpp24
-rw-r--r--tests/ref/fate/txd-pal84
-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_left4
-rw-r--r--tests/ref/fate/utvideoenc_rgb_median4
-rw-r--r--tests/ref/fate/utvideoenc_rgb_none4
-rw-r--r--tests/ref/fate/utvideoenc_rgba_left4
-rw-r--r--tests/ref/fate/utvideoenc_rgba_median4
-rw-r--r--tests/ref/fate/utvideoenc_rgba_none4
-rw-r--r--tests/ref/fate/utvideoenc_yuv420_left4
-rw-r--r--tests/ref/fate/utvideoenc_yuv420_median4
-rw-r--r--tests/ref/fate/utvideoenc_yuv420_none4
-rw-r--r--tests/ref/fate/utvideoenc_yuv422_left4
-rw-r--r--tests/ref/fate/utvideoenc_yuv422_median4
-rw-r--r--tests/ref/fate/utvideoenc_yuv422_none4
-rw-r--r--tests/ref/fate/v2102
-rw-r--r--tests/ref/fate/vc1-ism242
-rw-r--r--tests/ref/fate/vima17
-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-007
-rw-r--r--tests/ref/fate/vp9-00-quantizer-017
-rw-r--r--tests/ref/fate/vp9-00-quantizer-027
-rw-r--r--tests/ref/fate/vp9-00-quantizer-037
-rw-r--r--tests/ref/fate/vp9-00-quantizer-047
-rw-r--r--tests/ref/fate/vp9-00-quantizer-057
-rw-r--r--tests/ref/fate/vp9-00-quantizer-067
-rw-r--r--tests/ref/fate/vp9-00-quantizer-077
-rw-r--r--tests/ref/fate/vp9-00-quantizer-087
-rw-r--r--tests/ref/fate/vp9-00-quantizer-097
-rw-r--r--tests/ref/fate/vp9-00-quantizer-107
-rw-r--r--tests/ref/fate/vp9-00-quantizer-117
-rw-r--r--tests/ref/fate/vp9-00-quantizer-127
-rw-r--r--tests/ref/fate/vp9-00-quantizer-137
-rw-r--r--tests/ref/fate/vp9-00-quantizer-147
-rw-r--r--tests/ref/fate/vp9-00-quantizer-157
-rw-r--r--tests/ref/fate/vp9-00-quantizer-167
-rw-r--r--tests/ref/fate/vp9-00-quantizer-177
-rw-r--r--tests/ref/fate/vp9-00-quantizer-187
-rw-r--r--tests/ref/fate/vp9-00-quantizer-197
-rw-r--r--tests/ref/fate/vp9-00-quantizer-207
-rw-r--r--tests/ref/fate/vp9-00-quantizer-217
-rw-r--r--tests/ref/fate/vp9-00-quantizer-227
-rw-r--r--tests/ref/fate/vp9-00-quantizer-237
-rw-r--r--tests/ref/fate/vp9-00-quantizer-247
-rw-r--r--tests/ref/fate/vp9-00-quantizer-257
-rw-r--r--tests/ref/fate/vp9-00-quantizer-267
-rw-r--r--tests/ref/fate/vp9-00-quantizer-277
-rw-r--r--tests/ref/fate/vp9-00-quantizer-287
-rw-r--r--tests/ref/fate/vp9-00-quantizer-297
-rw-r--r--tests/ref/fate/vp9-00-quantizer-307
-rw-r--r--tests/ref/fate/vp9-00-quantizer-317
-rw-r--r--tests/ref/fate/vp9-00-quantizer-327
-rw-r--r--tests/ref/fate/vp9-00-quantizer-337
-rw-r--r--tests/ref/fate/vp9-00-quantizer-347
-rw-r--r--tests/ref/fate/vp9-00-quantizer-357
-rw-r--r--tests/ref/fate/vp9-00-quantizer-367
-rw-r--r--tests/ref/fate/vp9-00-quantizer-377
-rw-r--r--tests/ref/fate/vp9-00-quantizer-387
-rw-r--r--tests/ref/fate/vp9-00-quantizer-397
-rw-r--r--tests/ref/fate/vp9-00-quantizer-407
-rw-r--r--tests/ref/fate/vp9-00-quantizer-417
-rw-r--r--tests/ref/fate/vp9-00-quantizer-427
-rw-r--r--tests/ref/fate/vp9-00-quantizer-437
-rw-r--r--tests/ref/fate/vp9-00-quantizer-447
-rw-r--r--tests/ref/fate/vp9-00-quantizer-457
-rw-r--r--tests/ref/fate/vp9-00-quantizer-467
-rw-r--r--tests/ref/fate/vp9-00-quantizer-477
-rw-r--r--tests/ref/fate/vp9-00-quantizer-487
-rw-r--r--tests/ref/fate/vp9-00-quantizer-497
-rw-r--r--tests/ref/fate/vp9-00-quantizer-507
-rw-r--r--tests/ref/fate/vp9-00-quantizer-517
-rw-r--r--tests/ref/fate/vp9-00-quantizer-527
-rw-r--r--tests/ref/fate/vp9-00-quantizer-537
-rw-r--r--tests/ref/fate/vp9-00-quantizer-547
-rw-r--r--tests/ref/fate/vp9-00-quantizer-557
-rw-r--r--tests/ref/fate/vp9-00-quantizer-567
-rw-r--r--tests/ref/fate/vp9-00-quantizer-577
-rw-r--r--tests/ref/fate/vp9-00-quantizer-587
-rw-r--r--tests/ref/fate/vp9-00-quantizer-597
-rw-r--r--tests/ref/fate/vp9-00-quantizer-607
-rw-r--r--tests/ref/fate/vp9-00-quantizer-617
-rw-r--r--tests/ref/fate/vp9-00-quantizer-627
-rw-r--r--tests/ref/fate/vp9-00-quantizer-637
-rw-r--r--tests/ref/fate/vp9-01-sharpness-115
-rw-r--r--tests/ref/fate/vp9-01-sharpness-215
-rw-r--r--tests/ref/fate/vp9-01-sharpness-315
-rw-r--r--tests/ref/fate/vp9-01-sharpness-415
-rw-r--r--tests/ref/fate/vp9-01-sharpness-515
-rw-r--r--tests/ref/fate/vp9-01-sharpness-615
-rw-r--r--tests/ref/fate/vp9-01-sharpness-715
-rw-r--r--tests/ref/fate/vp9-02-size-08x0815
-rw-r--r--tests/ref/fate/vp9-02-size-08x1015
-rw-r--r--tests/ref/fate/vp9-02-size-08x1615
-rw-r--r--tests/ref/fate/vp9-02-size-08x1815
-rw-r--r--tests/ref/fate/vp9-02-size-08x3215
-rw-r--r--tests/ref/fate/vp9-02-size-08x3415
-rw-r--r--tests/ref/fate/vp9-02-size-08x6415
-rw-r--r--tests/ref/fate/vp9-02-size-08x6615
-rw-r--r--tests/ref/fate/vp9-02-size-10x0815
-rw-r--r--tests/ref/fate/vp9-02-size-10x1015
-rw-r--r--tests/ref/fate/vp9-02-size-10x1615
-rw-r--r--tests/ref/fate/vp9-02-size-10x1815
-rw-r--r--tests/ref/fate/vp9-02-size-10x3215
-rw-r--r--tests/ref/fate/vp9-02-size-10x3415
-rw-r--r--tests/ref/fate/vp9-02-size-10x6415
-rw-r--r--tests/ref/fate/vp9-02-size-10x6615
-rw-r--r--tests/ref/fate/vp9-02-size-16x0815
-rw-r--r--tests/ref/fate/vp9-02-size-16x1015
-rw-r--r--tests/ref/fate/vp9-02-size-16x1615
-rw-r--r--tests/ref/fate/vp9-02-size-16x1815
-rw-r--r--tests/ref/fate/vp9-02-size-16x3215
-rw-r--r--tests/ref/fate/vp9-02-size-16x3415
-rw-r--r--tests/ref/fate/vp9-02-size-16x6415
-rw-r--r--tests/ref/fate/vp9-02-size-16x6615
-rw-r--r--tests/ref/fate/vp9-02-size-18x0815
-rw-r--r--tests/ref/fate/vp9-02-size-18x1015
-rw-r--r--tests/ref/fate/vp9-02-size-18x1615
-rw-r--r--tests/ref/fate/vp9-02-size-18x1815
-rw-r--r--tests/ref/fate/vp9-02-size-18x3215
-rw-r--r--tests/ref/fate/vp9-02-size-18x3415
-rw-r--r--tests/ref/fate/vp9-02-size-18x6415
-rw-r--r--tests/ref/fate/vp9-02-size-18x6615
-rw-r--r--tests/ref/fate/vp9-02-size-32x0815
-rw-r--r--tests/ref/fate/vp9-02-size-32x1015
-rw-r--r--tests/ref/fate/vp9-02-size-32x1615
-rw-r--r--tests/ref/fate/vp9-02-size-32x1815
-rw-r--r--tests/ref/fate/vp9-02-size-32x3215
-rw-r--r--tests/ref/fate/vp9-02-size-32x3415
-rw-r--r--tests/ref/fate/vp9-02-size-32x6415
-rw-r--r--tests/ref/fate/vp9-02-size-32x6615
-rw-r--r--tests/ref/fate/vp9-02-size-34x0815
-rw-r--r--tests/ref/fate/vp9-02-size-34x1015
-rw-r--r--tests/ref/fate/vp9-02-size-34x1615
-rw-r--r--tests/ref/fate/vp9-02-size-34x1815
-rw-r--r--tests/ref/fate/vp9-02-size-34x3215
-rw-r--r--tests/ref/fate/vp9-02-size-34x3415
-rw-r--r--tests/ref/fate/vp9-02-size-34x6415
-rw-r--r--tests/ref/fate/vp9-02-size-34x6615
-rw-r--r--tests/ref/fate/vp9-02-size-64x0815
-rw-r--r--tests/ref/fate/vp9-02-size-64x1015
-rw-r--r--tests/ref/fate/vp9-02-size-64x1615
-rw-r--r--tests/ref/fate/vp9-02-size-64x1815
-rw-r--r--tests/ref/fate/vp9-02-size-64x3215
-rw-r--r--tests/ref/fate/vp9-02-size-64x3415
-rw-r--r--tests/ref/fate/vp9-02-size-64x6415
-rw-r--r--tests/ref/fate/vp9-02-size-64x6615
-rw-r--r--tests/ref/fate/vp9-02-size-66x0815
-rw-r--r--tests/ref/fate/vp9-02-size-66x1015
-rw-r--r--tests/ref/fate/vp9-02-size-66x1615
-rw-r--r--tests/ref/fate/vp9-02-size-66x1815
-rw-r--r--tests/ref/fate/vp9-02-size-66x3215
-rw-r--r--tests/ref/fate/vp9-02-size-66x3415
-rw-r--r--tests/ref/fate/vp9-02-size-66x6415
-rw-r--r--tests/ref/fate/vp9-02-size-66x6615
-rw-r--r--tests/ref/fate/vp9-03-deltaq7
-rw-r--r--tests/ref/fate/vp9-03-size-196x19615
-rw-r--r--tests/ref/fate/vp9-03-size-196x19815
-rw-r--r--tests/ref/fate/vp9-03-size-196x20015
-rw-r--r--tests/ref/fate/vp9-03-size-196x20215
-rw-r--r--tests/ref/fate/vp9-03-size-196x20815
-rw-r--r--tests/ref/fate/vp9-03-size-196x21015
-rw-r--r--tests/ref/fate/vp9-03-size-196x22415
-rw-r--r--tests/ref/fate/vp9-03-size-196x22615
-rw-r--r--tests/ref/fate/vp9-03-size-198x19615
-rw-r--r--tests/ref/fate/vp9-03-size-198x19815
-rw-r--r--tests/ref/fate/vp9-03-size-198x20015
-rw-r--r--tests/ref/fate/vp9-03-size-198x20215
-rw-r--r--tests/ref/fate/vp9-03-size-198x20815
-rw-r--r--tests/ref/fate/vp9-03-size-198x21015
-rw-r--r--tests/ref/fate/vp9-03-size-198x22415
-rw-r--r--tests/ref/fate/vp9-03-size-198x22615
-rw-r--r--tests/ref/fate/vp9-03-size-200x19615
-rw-r--r--tests/ref/fate/vp9-03-size-200x19815
-rw-r--r--tests/ref/fate/vp9-03-size-200x20015
-rw-r--r--tests/ref/fate/vp9-03-size-200x20215
-rw-r--r--tests/ref/fate/vp9-03-size-200x20815
-rw-r--r--tests/ref/fate/vp9-03-size-200x21015
-rw-r--r--tests/ref/fate/vp9-03-size-200x22415
-rw-r--r--tests/ref/fate/vp9-03-size-200x22615
-rw-r--r--tests/ref/fate/vp9-03-size-202x19615
-rw-r--r--tests/ref/fate/vp9-03-size-202x19815
-rw-r--r--tests/ref/fate/vp9-03-size-202x20015
-rw-r--r--tests/ref/fate/vp9-03-size-202x20215
-rw-r--r--tests/ref/fate/vp9-03-size-202x20815
-rw-r--r--tests/ref/fate/vp9-03-size-202x21015
-rw-r--r--tests/ref/fate/vp9-03-size-202x22415
-rw-r--r--tests/ref/fate/vp9-03-size-202x22615
-rw-r--r--tests/ref/fate/vp9-03-size-208x19615
-rw-r--r--tests/ref/fate/vp9-03-size-208x19815
-rw-r--r--tests/ref/fate/vp9-03-size-208x20015
-rw-r--r--tests/ref/fate/vp9-03-size-208x20215
-rw-r--r--tests/ref/fate/vp9-03-size-208x20815
-rw-r--r--tests/ref/fate/vp9-03-size-208x21015
-rw-r--r--tests/ref/fate/vp9-03-size-208x22415
-rw-r--r--tests/ref/fate/vp9-03-size-208x22615
-rw-r--r--tests/ref/fate/vp9-03-size-210x19615
-rw-r--r--tests/ref/fate/vp9-03-size-210x19815
-rw-r--r--tests/ref/fate/vp9-03-size-210x20015
-rw-r--r--tests/ref/fate/vp9-03-size-210x20215
-rw-r--r--tests/ref/fate/vp9-03-size-210x20815
-rw-r--r--tests/ref/fate/vp9-03-size-210x21015
-rw-r--r--tests/ref/fate/vp9-03-size-210x22415
-rw-r--r--tests/ref/fate/vp9-03-size-210x22615
-rw-r--r--tests/ref/fate/vp9-03-size-224x19615
-rw-r--r--tests/ref/fate/vp9-03-size-224x19815
-rw-r--r--tests/ref/fate/vp9-03-size-224x20015
-rw-r--r--tests/ref/fate/vp9-03-size-224x20215
-rw-r--r--tests/ref/fate/vp9-03-size-224x20815
-rw-r--r--tests/ref/fate/vp9-03-size-224x21015
-rw-r--r--tests/ref/fate/vp9-03-size-224x22415
-rw-r--r--tests/ref/fate/vp9-03-size-224x22615
-rw-r--r--tests/ref/fate/vp9-03-size-226x19615
-rw-r--r--tests/ref/fate/vp9-03-size-226x19815
-rw-r--r--tests/ref/fate/vp9-03-size-226x20015
-rw-r--r--tests/ref/fate/vp9-03-size-226x20215
-rw-r--r--tests/ref/fate/vp9-03-size-226x20815
-rw-r--r--tests/ref/fate/vp9-03-size-226x21015
-rw-r--r--tests/ref/fate/vp9-03-size-226x22415
-rw-r--r--tests/ref/fate/vp9-03-size-226x22615
-rw-r--r--tests/ref/fate/vp9-2pass-akiyo55
-rw-r--r--tests/ref/fate/vp9-segmentation-akiyo55
-rw-r--r--tests/ref/fate/vp9-tiling-pedestrian7
-rw-r--r--tests/ref/fate/vqa-cc68
-rw-r--r--tests/ref/fate/wmv8-drm262
-rw-r--r--tests/ref/fate/wmv8-drm-nodec256
-rw-r--r--tests/ref/fate/wmv8-x8intra474
-rw-r--r--tests/ref/fate/wtv-demux86
-rw-r--r--tests/ref/fate/xface2
-rw-r--r--tests/ref/fate/xmv-demux176
-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-8bit3
-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_fmt8
-rw-r--r--tests/ref/lavf/ffm4
-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/wtv3
-rw-r--r--tests/ref/lavf/xbm3
-rw-r--r--tests/ref/lavf/xwd23
-rw-r--r--tests/ref/seek/acodec-flac46
-rw-r--r--tests/ref/seek/acodec-pcm-f32be54
-rw-r--r--tests/ref/seek/acodec-pcm-f64be54
-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-ffm26
-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-mxf26
-rw-r--r--tests/ref/seek/lavf-mxf_d102
-rw-r--r--tests/ref/seek/lavf-nut86
-rw-r--r--tests/ref/seek/lavf-ogg63
-rw-r--r--tests/ref/seek/lavf-pcx9
-rw-r--r--tests/ref/seek/lavf-pgm9
-rw-r--r--tests/ref/seek/lavf-ppm9
-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-ts42
-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-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-flv8
-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-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-42248
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-idct-int24
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-ilace40
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-ivlc-qprd26
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-thread48
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-thread-ivlc48
-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-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-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-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-dv2
-rw-r--r--tests/ref/vsynth/vsynth1-dv-4112
-rw-r--r--tests/ref/vsynth/vsynth1-dv-502
-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-ffvhuff2
-rw-r--r--tests/ref/vsynth/vsynth1-flashsv4
-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-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-huffyuv2
-rw-r--r--tests/ref/vsynth/vsynth1-jpeg20004
-rw-r--r--tests/ref/vsynth/vsynth1-jpeg2000-974
-rw-r--r--tests/ref/vsynth/vsynth1-jpegls4
-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-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-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-rgb4
-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-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-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-dv2
-rw-r--r--tests/ref/vsynth/vsynth2-dv-4112
-rw-r--r--tests/ref/vsynth/vsynth2-dv-502
-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-ffvhuff2
-rw-r--r--tests/ref/vsynth/vsynth2-flashsv4
-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-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-huffyuv2
-rw-r--r--tests/ref/vsynth/vsynth2-jpeg20004
-rw-r--r--tests/ref/vsynth/vsynth2-jpeg2000-974
-rw-r--r--tests/ref/vsynth/vsynth2-jpegls4
-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-ilace6
-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-error8
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg4-nr6
-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-rgb4
-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-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/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.c165
-rw-r--r--tests/tiny_ssim.c216
-rw-r--r--tests/utils.c10
-rw-r--r--tests/videogen.c8
-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.c358
-rw-r--r--tools/cws2fws.c14
-rw-r--r--tools/enum_options.c143
-rw-r--r--tools/ffescape.c180
-rw-r--r--tools/ffeval.c139
-rw-r--r--tools/ffhash.c149
-rw-r--r--tools/fourcc2pixfmt.c123
-rw-r--r--tools/graph2dot.c38
-rw-r--r--tools/ismindex.c22
-rwxr-xr-xtools/make_chlayout_test114
-rwxr-xr-xtools/missing_codec_desc37
-rwxr-xr-xtools/normalize.py33
-rwxr-xr-xtools/patcheck12
-rw-r--r--tools/pktdumper.c8
-rwxr-xr-xtools/plotframes164
-rw-r--r--tools/probetest.c33
-rw-r--r--tools/qt-faststart.c63
-rw-r--r--tools/seek_print.c105
-rw-r--r--tools/trasher.c13
-rwxr-xr-xtools/unwrap-diff2
-rw-r--r--tools/yuvcmp.c182
-rw-r--r--tools/zmqsend.c167
-rwxr-xr-xtools/zmqshell.py26
-rwxr-xr-xversion.sh26
3541 files changed, 317548 insertions, 67202 deletions
diff --git a/.gitignore b/.gitignore
index 000f149..1f13ec4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
*.d
*.def
*.dll
+*.dylib
*.exe
*.exp
*.gcda
@@ -17,20 +18,33 @@
*.ver
*-example
*-test
+*_g
/.config
/.version
-/avconv
-/avplay
-/avprobe
-/avserver
+/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/examples/decoding_encoding
+/doc/examples/demuxing
+/doc/examples/filtering_audio
+/doc/examples/filtering_video
+/doc/examples/metadata
+/doc/examples/muxing
+/doc/examples/pc-uninstalled
+/doc/examples/resampling_audio
+/doc/examples/scaling_video
+/doc/fate.txt
/doc/doxy/html/
/doc/print_options
/lcov/
@@ -43,13 +57,23 @@
/tests/data/
/tests/rotozoom
/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/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 4032d07..72f79d3 100644
--- a/Changelog
+++ b/Changelog
@@ -1,96 +1,222 @@
Entries are sorted chronologically from oldest to youngest within each release,
releases are sorted from youngest to oldest.
-version 10:
-- av_strnstr
-- support ID3v2 tags in ASF files
+version <next>
+
+
+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 demuxer, HEVC demuxing in TS, Matroska and MP4
+- 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
-- new 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
+- new 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
- new interlace filter
-- JPEG 2000 decoder
-- new asetpts filter (same as setpts, but for audio)
-- new trim and atrim filters
-- avconv -t and -ss (output-only) options are now sample-accurate when
+- 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
+- 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
-- incomplete 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
+- 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 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
@@ -103,44 +229,143 @@ 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 playback support
+- 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
-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
@@ -210,23 +435,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
@@ -236,44 +478,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
@@ -281,6 +506,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
@@ -292,6 +518,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
@@ -338,7 +565,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
@@ -351,11 +578,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:
@@ -596,6 +858,7 @@ version 0.5:
- Gopher client support
- MXF D-10 muxer
- generic metadata API
+- flash ScreenVideo2 encoder
version 0.4.9-pre1:
@@ -798,7 +1061,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
index ac5dc5d..9549346 100644
--- a/INSTALL
+++ b/INSTALL
@@ -2,17 +2,14 @@
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
+'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. '/libavdir/libav/configure'.
+path when launching 'configure', e.g. '/ffmpegdir/ffmpeg/configure'.
-2) Then type 'make' to build Libav. GNU Make 3.81 or later is required.
+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.
-
- - 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/LICENSE b/LICENSE
index 1074989..1840d69 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,27 +1,54 @@
-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/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_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_yadif.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 +68,36 @@ 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, 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
+ - 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..a9a55df
--- a/dev/null
+++ b/MAINTAINERS
@@ -0,0 +1,544 @@
+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, ffserver.h Baptiste Coudurier
+
+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 Döffinger, Alexander Strasser
+presets Robert Swain
+metadata subsystem Aurelien Jacobs
+release management Michael Niedermayer
+
+
+Communication
+=============
+
+website Robert Swain, Lou Logan
+mailinglists 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
+ 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
+
+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
+ 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
+ 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
+ dxa.c Kostya Shishkov
+ eacmv*, eaidct*, eat* Peter Ross
+ exif.c, exif.h Thilo Borgmann
+ ffv1.c Michael Niedermayer
+ ffwavesynth.c Nicolas George
+ 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.c Michael Niedermayer
+ 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
+ libx264.c Mans Rullgard, Jason Garrett-Glaser
+ libxavs.c Stefan Gehrer
+ 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
+ s3tc* Ivo van Poorten
+ smacker.c Kostya Shishkov
+ smc.c Mike Melanson
+ smvjpegdec.c Ash Hughes
+ snow.c 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
+ vcr1.c Michael Niedermayer
+ vda_h264_dec.c Xidorn Quan
+ vima.c Paul B Mahol
+ vmnc.c Kostya Shishkov
+ vorbis_dec.c Denes Balatoni, David Conrad
+ vorbis_enc.c Oded Shimon
+ vp3* Mike Melanson
+ vp5 Aurelien Jacobs
+ vp6 Aurelien Jacobs
+ vp8 David Conrad, Jason Garrett-Glaser, Ronald Bultje
+ 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
+
+
+ dshow.c Roger Pack
+ fbdev_enc.c Lukasz Marek
+ iec61883.c Georg Lippitsch
+ lavfi Stefano Sabatini
+ libdc1394.c Roman Shaposhnik
+ pulse_audio_enc.c Lukasz Marek
+ sdl Stefano Sabatini
+ v4l2.c Luca Abeni
+ vfwcap.c Ramiro Polla
+
+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
+ avf_avectorscope.c Paul B Mahol
+ vf_blend.c Paul B Mahol
+ vf_colorbalance.c Paul B Mahol
+ 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_il.c Paul B Mahol
+ 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
+ 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
+ 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* 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.c 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_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
+ siff.c Kostya Shishkov
+ smacker.c Kostya Shishkov
+ smjpeg* Paul B Mahol
+ 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
+ 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
+
+
+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
+ADI/Blackfin DSP Marc Hoffman
+Sparc Roman Shaposhnik
+x86 Michael Niedermayer
+
+
+Releases
+========
+
+2.1 Michael Niedermayer
+2.0 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
+BÅ“sch ClĂ©ment 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 Döffinger 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
+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 783971f..46d4d52 100644
--- a/Makefile
+++ b/Makefile
@@ -1,88 +1,47 @@
+MAIN_MAKEFILE=1
include config.mak
vpath %.c $(SRC_PATH)
+vpath %.cpp $(SRC_PATH)
vpath %.h $(SRC_PATH)
vpath %.S $(SRC_PATH)
vpath %.asm $(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
-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)
-
-%.o: %.c
- $(COMPILE_C)
+PROGS-$(CONFIG_FFMPEG) += ffmpeg
+PROGS-$(CONFIG_FFPLAY) += ffplay
+PROGS-$(CONFIG_FFPROBE) += ffprobe
+PROGS-$(CONFIG_FFSERVER) += ffserver
-%.o: %.S
- $(COMPILE_S)
+PROGS := $(PROGS-yes:%=%$(PROGSSUF)$(EXESUF))
+INSTPROGS = $(PROGS-yes:%=%$(PROGSSUF)$(EXESUF))
-%.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
-
-PROGS-$(CONFIG_AVCONV) += avconv
-PROGS-$(CONFIG_AVPLAY) += avplay
-PROGS-$(CONFIG_AVPROBE) += avprobe
-PROGS-$(CONFIG_AVSERVER) += avserver
-
-PROGS := $(PROGS-yes:%=%$(EXESUF))
OBJS = cmdutils.o $(EXEOBJS)
-OBJS-avconv = avconv_opt.o avconv_filter.o
-TESTTOOLS = audiogen videogen rotozoom tiny_psnr base64
+OBJS-ffmpeg = ffmpeg_opt.o ffmpeg_filter.o
+TESTTOOLS = audiogen videogen rotozoom tiny_psnr tiny_ssim base64
HOSTPROGS := $(TESTTOOLS:%=tests/%) doc/print_options
TOOLS = qt-faststart trasher
TOOLS-$(CONFIG_ZLIB) += cws2fws
-BASENAMES = avconv avplay avprobe avserver
-ALLPROGS = $(BASENAMES:%=%$(EXESUF))
-ALLMANPAGES = $(BASENAMES:%=%.1)
+BASENAMES = ffmpeg ffplay ffprobe ffserver
+ALLPROGS = $(BASENAMES:%=%$(PROGSSUF)$(EXESUF))
+ALLPROGS_G = $(BASENAMES:%=%$(PROGSSUF)_g$(EXESUF))
FFLIBS-$(CONFIG_AVDEVICE) += avdevice
FFLIBS-$(CONFIG_AVFILTER) += avfilter
FFLIBS-$(CONFIG_AVFORMAT) += avformat
FFLIBS-$(CONFIG_AVRESAMPLE) += avresample
FFLIBS-$(CONFIG_AVCODEC) += avcodec
+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
@@ -93,6 +52,10 @@ FF_DEP_LIBS := $(DEP_LIBS)
all: $(PROGS)
+$(PROGS): %$(EXESUF): %_g$(EXESUF)
+ $(CP) $< $@
+ $(STRIP) $@
+
$(TOOLS): %$(EXESUF): %.o $(EXEOBJS)
$(LD) $(LDFLAGS) $(LD_O) $^ $(ELIBS)
@@ -109,6 +72,7 @@ SUBDIR_VARS := CLEANFILES EXAMPLES FFLIBS HOSTPROGS TESTPROGS TOOLS \
ARMV5TE-OBJS ARMV6-OBJS VFP-OBJS NEON-OBJS \
ALTIVEC-OBJS VIS-OBJS \
MMX-OBJS YASM-OBJS \
+ MIPSFPU-OBJS MIPSDSPR2-OBJS MIPSDSPR1-OBJS MIPS32R2-OBJS \
OBJS HOSTOBJS TESTOBJS
define RESET
@@ -128,16 +92,16 @@ $(foreach D,$(FFLIBS),$(eval $(call DOSUBDIR,lib$(D))))
define DOPROG
OBJS-$(1) += $(1).o cmdutils.o $(EXEOBJS)
-$(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-yes),$(eval $(call DOPROG,$(P))))
-$(PROGS): %$(EXESUF): %.o $(FF_DEP_LIBS)
+%$(PROGSSUF)_g$(EXESUF): %.o $(FF_DEP_LIBS)
$(LD) $(LDFLAGS) $(LD_O) $(OBJS-$*) $(FF_EXTRALIBS)
OBJDIRS += tools
@@ -170,11 +134,12 @@ install-progs-$(CONFIG_SHARED): install-libs
install-progs: install-progs-yes $(PROGS)
$(Q)mkdir -p "$(BINDIR)"
- $(INSTALL) -c -m 755 $(PROGS) "$(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
@@ -185,19 +150,20 @@ uninstall-data:
$(RM) -r "$(DATADIR)"
clean::
- $(RM) $(ALLPROGS)
+ $(RM) $(ALLPROGS) $(ALLPROGS_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 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)/doc/Makefile
include $(SRC_PATH)/tests/Makefile
@@ -213,5 +179,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
index afef671..ae007bc 100644
--- a/README
+++ b/README
@@ -1,12 +1,18 @@
-Libav README
-------------
+FFmpeg README
+-------------
1) Documentation
----------------
-* Read the documentation in the doc/ directory.
+* Read the documentation in the doc/ directory in git.
+ You can also view it online at http://ffmpeg.org/documentation.html
2) Licensing
------------
* See the LICENSE file.
+
+3) Build and Install
+--------------------
+
+* See the INSTALL file.
diff --git a/RELEASE b/RELEASE
index ae33bab..cd5ac03 100644
--- a/RELEASE
+++ b/RELEASE
@@ -1 +1 @@
-10_alpha1
+2.0
diff --git a/arch.mak b/arch.mak
index 09d24af..b71c8e5 100644
--- a/arch.mak
+++ b/arch.mak
@@ -3,6 +3,11 @@ OBJS-$(HAVE_ARMV6) += $(ARMV6-OBJS) $(ARMV6-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_VIS) += $(VIS-OBJS) $(VIS-OBJS-yes)
diff --git a/avconv.c b/avconv.c
deleted file mode 100644
index be47da0..0000000
--- a/avconv.c
+++ b/dev/null
@@ -1,2393 +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 "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 int64_t video_size = 0;
-static int64_t audio_size = 0;
-static int64_t extra_size = 0;
-static int nb_frames_dup = 0;
-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++) {
- avfilter_graph_free(&filtergraphs[i]->graph);
- for (j = 0; j < filtergraphs[i]->nb_inputs; j++) {
- av_freep(&filtergraphs[i]->inputs[j]->name);
- av_freep(&filtergraphs[i]->inputs[j]);
- }
- av_freep(&filtergraphs[i]->inputs);
- for (j = 0; j < filtergraphs[i]->nb_outputs; j++) {
- av_freep(&filtergraphs[i]->outputs[j]->name);
- av_freep(&filtergraphs[i]->outputs[j]);
- }
- av_freep(&filtergraphs[i]->outputs);
- av_freep(&filtergraphs[i]->graph_desc);
- av_freep(&filtergraphs[i]);
- }
- av_freep(&filtergraphs);
-
- /* close files */
- for (i = 0; i < nb_output_files; i++) {
- AVFormatContext *s = output_files[i]->ctx;
- if (s && s->oformat && !(s->oformat->flags & AVFMT_NOFILE) && s->pb)
- avio_close(s->pb);
- avformat_free_context(s);
- av_dict_free(&output_files[i]->opts);
- av_freep(&output_files[i]);
- }
- for (i = 0; i < nb_output_streams; i++) {
- AVBitStreamFilterContext *bsfc = output_streams[i]->bitstream_filters;
- while (bsfc) {
- AVBitStreamFilterContext *next = bsfc->next;
- av_bitstream_filter_close(bsfc);
- bsfc = next;
- }
- output_streams[i]->bitstream_filters = NULL;
- avcodec_free_frame(&output_streams[i]->filtered_frame);
-
- av_parser_close(output_streams[i]->parser);
-
- av_freep(&output_streams[i]->forced_keyframes);
- av_freep(&output_streams[i]->avfilter);
- av_freep(&output_streams[i]->logfile_prefix);
- 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++) {
- av_frame_free(&input_streams[i]->decoded_frame);
- av_frame_free(&input_streams[i]->filter_frame);
- av_dict_free(&input_streams[i]->opts);
- av_freep(&input_streams[i]->filters);
- 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->st->codec;
- int ret;
-
- /*
- * Audio encoders may split the packets -- #frames in != #packets out.
- * But there is no reordering, so we can limit the number of output packets
- * by simply dropping them here.
- * Counting encoded video frames needs to be done separately because of
- * reordering, see do_video_out()
- */
- if (!(avctx->codec_type == AVMEDIA_TYPE_VIDEO && avctx->codec)) {
- if (ost->frame_number >= ost->max_frames) {
- av_free_packet(pkt);
- return;
- }
- ost->frame_number++;
- }
-
- while (bsfc) {
- AVPacket new_pkt = *pkt;
- int a = av_bitstream_filter_filter(bsfc, avctx, NULL,
- &new_pkt.data, &new_pkt.size,
- pkt->data, pkt->size,
- pkt->flags & AV_PKT_FLAG_KEY);
- if (a > 0) {
- av_free_packet(pkt);
- new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size,
- av_buffer_default_free, NULL, 0);
- if (!new_pkt.buf)
- exit_program(1);
- } else if (a < 0) {
- av_log(NULL, AV_LOG_ERROR, "%s failed for stream %d, codec %s",
- bsfc->filter->name, pkt->stream_index,
- avctx->codec ? avctx->codec->name : "copy");
- print_error("", a);
- if (exit_on_error)
- exit_program(1);
- }
- *pkt = new_pkt;
-
- bsfc = bsfc->next;
- }
-
- if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS) &&
- ost->last_mux_dts != AV_NOPTS_VALUE &&
- pkt->dts < ost->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT)) {
- av_log(NULL, AV_LOG_WARNING, "Non-monotonous DTS in output stream "
- "%d:%d; previous: %"PRId64", current: %"PRId64"; ",
- ost->file_index, ost->st->index, ost->last_mux_dts, pkt->dts);
- if (exit_on_error) {
- av_log(NULL, AV_LOG_FATAL, "aborting.\n");
- exit_program(1);
- }
- av_log(NULL, AV_LOG_WARNING, "changing to %"PRId64". This may result "
- "in incorrect timestamps in the output file.\n",
- ost->last_mux_dts + 1);
- pkt->dts = ost->last_mux_dts + 1;
- if (pkt->pts != AV_NOPTS_VALUE)
- pkt->pts = FFMAX(pkt->pts, pkt->dts);
- }
- ost->last_mux_dts = pkt->dts;
-
- 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->st->codec->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->st->codec;
- 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;
-
- 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) {
- if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
- if (pkt.dts != AV_NOPTS_VALUE)
- pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base);
- if (pkt.duration > 0)
- pkt.duration = av_rescale_q(pkt.duration, enc->time_base, ost->st->time_base);
-
- write_frame(s, &pkt, ost);
-
- audio_size += pkt.size;
- }
-}
-
-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->st->codec;
-
- 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;
- 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->st->codec;
-
- *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_VERBOSE, "*** drop!\n");
- 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 (ost->st->codec->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 = ost->st->codec->global_quality;
- if (!enc->me_threshold)
- 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++;
- }
- 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) {
- if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
- if (pkt.dts != AV_NOPTS_VALUE)
- pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base);
-
- write_frame(s, &pkt, ost);
- *frame_size = pkt.size;
- video_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->st->codec;
- 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)(video_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)video_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 = avcodec_alloc_frame())) {
- return AVERROR(ENOMEM);
- } else
- avcodec_get_frame_defaults(ost->filtered_frame);
- 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->st->codec->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->st->codec->time_base) -
- av_rescale_q(start_time,
- AV_TIME_BASE_Q,
- ost->st->codec->time_base);
- }
-
- switch (ost->filter->filter->inputs[0]->type) {
- case AVMEDIA_TYPE_VIDEO:
- if (!ost->frame_aspect_ratio)
- ost->st->codec->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;
-}
-
-/*
- * 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, j, 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]->st->codec->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) {
- OutputFile *of = output_files[ost->file_index];
-
- ost->finished = 1;
-
- if (of->shortest) {
- for (j = 0; j < of->ctx->nb_streams; j++)
- output_streams[of->ost_index + j]->finished = 1;
- }
-
- ret = 0;
- } else if (ret == AVERROR(EAGAIN))
- return 0;
- }
-
- return ret;
-}
-
-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();
- 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->st->codec;
- 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() - 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->st->pts.val * 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_dup || nb_frames_drop)
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " dup=%d drop=%d",
- nb_frames_dup, nb_frames_drop);
-
- av_log(NULL, AV_LOG_INFO, "%s \r", buf);
-
- fflush(stderr);
-
- if (is_last_report) {
- int64_t raw= audio_size + video_size + extra_size;
- av_log(NULL, AV_LOG_INFO, "\n");
- av_log(NULL, AV_LOG_INFO, "video:%1.0fkB audio:%1.0fkB global headers:%1.0fkB muxing overhead %f%%\n",
- video_size / 1024.0,
- audio_size / 1024.0,
- extra_size / 1024.0,
- 100.0 * (total_size - raw) / raw
- );
- }
-}
-
-static void flush_encoders(void)
-{
- int i, ret;
-
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
- AVCodecContext *enc = ost->st->codec;
- AVFormatContext *os = output_files[ost->file_index]->ctx;
- int stop_encoding = 0;
-
- if (!ost->encoding_needed)
- continue;
-
- if (ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1)
- continue;
- if (ost->st->codec->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;
- int64_t *size;
-
- switch (ost->st->codec->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- encode = avcodec_encode_audio2;
- desc = "Audio";
- size = &audio_size;
- break;
- case AVMEDIA_TYPE_VIDEO:
- encode = avcodec_encode_video2;
- desc = "Video";
- size = &video_size;
- 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);
- }
- *size += ret;
- if (ost->logfile && enc->stats_out) {
- fprintf(ost->logfile, "%s", enc->stats_out);
- }
- if (!got_packet) {
- stop_encoding = 1;
- break;
- }
- if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
- if (pkt.dts != AV_NOPTS_VALUE)
- pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base);
- if (pkt.duration > 0)
- pkt.duration = av_rescale_q(pkt.duration, 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->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
- audio_size += pkt->size;
- else if (ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
- video_size += pkt->size;
- 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->st->codec->codec_id != AV_CODEC_ID_H264
- && ost->st->codec->codec_id != AV_CODEC_ID_MPEG1VIDEO
- && ost->st->codec->codec_id != AV_CODEC_ID_MPEG2VIDEO
- && ost->st->codec->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);
- ost->st->codec->frame_number++;
-}
-
-int guess_input_channel_layout(InputStream *ist)
-{
- AVCodecContext *dec = ist->st->codec;
-
- 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->st->codec;
- int i, ret, err = 0, resample_changed;
-
- if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame()))
- 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;
- }
-
- /* 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, ist->st->codec->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->st->codec,
- 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;
- }
-
- 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;
- }
-
- 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->st->codec,
- &subtitle, got_output, pkt);
- if (ret < 0)
- return ret;
- if (!*got_output)
- return ret;
-
- 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 output_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 == NULL) {
- /* 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) {
- 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->st->codec->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->st->codec->time_base.num != 0) {
- int ticks = ist->st->parser ? ist->st->parser->repeat_pict + 1 :
- ist->st->codec->ticks_per_frame;
- ist->next_dts += av_rescale_q(ticks, ist->st->codec->time_base, 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->st->codec->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- ist->next_dts += ((int64_t)AV_TIME_BASE * ist->st->codec->frame_size) /
- ist->st->codec->sample_rate;
- break;
- case AVMEDIA_TYPE_VIDEO:
- if (ist->st->codec->time_base.num != 0) {
- int ticks = ist->st->parser ? ist->st->parser->repeat_pict + 1 : ist->st->codec->ticks_per_frame;
- ist->next_dts += ((int64_t)AV_TIME_BASE *
- ist->st->codec->time_base.num * ticks) /
- ist->st->codec->time_base.den;
- }
- 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 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->st->codec->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->st->codec, codec, ost->st->codec);
- break;
- }
- }
-
- av_opt_set_int(ist->st->codec, "refcounted_frames", 1, 0);
-
- if (!av_dict_get(ist->opts, "threads", NULL, 0))
- av_dict_set(&ist->opts, "threads", "auto", 0);
- if ((ret = avcodec_open2(ist->st->codec, codec, &ist->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->opts);
- }
-
- ist->last_dts = ist->st->avg_frame_rate.num ? - ist->st->codec->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);
- ist->is_start = 1;
-
- 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->st->codec->codec_type == ost->st->codec->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 int transcode_init(void)
-{
- int ret = 0, i, j, k;
- AVFormatContext *oc;
- AVCodecContext *codec;
- 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();
- }
-
- /* 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 *icodec = NULL;
- ost = output_streams[i];
- oc = output_files[ost->file_index]->ctx;
- ist = get_input_stream(ost);
-
- if (ost->attachment_filename)
- continue;
-
- codec = ost->st->codec;
-
- if (ist) {
- icodec = ist->st->codec;
-
- ost->st->disposition = ist->st->disposition;
- codec->bits_per_raw_sample = icodec->bits_per_raw_sample;
- codec->chroma_sample_location = icodec->chroma_sample_location;
- }
-
- if (ost->stream_copy) {
- AVRational sar;
- uint64_t extra_size;
-
- av_assert0(ist && !ost->filter);
-
- extra_size = (uint64_t)icodec->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 */
- codec->codec_id = icodec->codec_id;
- codec->codec_type = icodec->codec_type;
-
- if (!codec->codec_tag) {
- if (!oc->oformat->codec_tag ||
- av_codec_get_id (oc->oformat->codec_tag, icodec->codec_tag) == codec->codec_id ||
- av_codec_get_tag(oc->oformat->codec_tag, icodec->codec_id) <= 0)
- codec->codec_tag = icodec->codec_tag;
- }
-
- codec->bit_rate = icodec->bit_rate;
- codec->rc_max_rate = icodec->rc_max_rate;
- codec->rc_buffer_size = icodec->rc_buffer_size;
- codec->field_order = icodec->field_order;
- codec->extradata = av_mallocz(extra_size);
- if (!codec->extradata) {
- return AVERROR(ENOMEM);
- }
- memcpy(codec->extradata, icodec->extradata, icodec->extradata_size);
- codec->extradata_size = icodec->extradata_size;
- if (!copy_tb) {
- codec->time_base = icodec->time_base;
- codec->time_base.num *= icodec->ticks_per_frame;
- av_reduce(&codec->time_base.num, &codec->time_base.den,
- codec->time_base.num, codec->time_base.den, INT_MAX);
- } else
- codec->time_base = ist->st->time_base;
-
- ost->parser = av_parser_init(codec->codec_id);
-
- switch (codec->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);
- }
- codec->channel_layout = icodec->channel_layout;
- codec->sample_rate = icodec->sample_rate;
- codec->channels = icodec->channels;
- codec->frame_size = icodec->frame_size;
- codec->audio_service_type = icodec->audio_service_type;
- codec->block_align = icodec->block_align;
- break;
- case AVMEDIA_TYPE_VIDEO:
- codec->pix_fmt = icodec->pix_fmt;
- codec->width = icodec->width;
- codec->height = icodec->height;
- codec->has_b_frames = icodec->has_b_frames;
- if (ost->frame_aspect_ratio)
- sar = av_d2q(ost->frame_aspect_ratio * codec->height / codec->width, 255);
- else if (ist->st->sample_aspect_ratio.num)
- sar = ist->st->sample_aspect_ratio;
- else
- sar = icodec->sample_aspect_ratio;
- ost->st->sample_aspect_ratio = codec->sample_aspect_ratio = sar;
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- codec->width = icodec->width;
- codec->height = icodec->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;
-
- /*
- * 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 (codec->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))))) {
- ost->frame_rate = ist->framerate.num ? ist->framerate :
- 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 (!ost->filter &&
- (codec->codec_type == AVMEDIA_TYPE_VIDEO ||
- codec->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 (codec->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- codec->sample_fmt = ost->filter->filter->inputs[0]->format;
- codec->sample_rate = ost->filter->filter->inputs[0]->sample_rate;
- codec->channel_layout = ost->filter->filter->inputs[0]->channel_layout;
- codec->channels = av_get_channel_layout_nb_channels(codec->channel_layout);
- codec->time_base = (AVRational){ 1, codec->sample_rate };
- break;
- case AVMEDIA_TYPE_VIDEO:
- codec->time_base = ost->filter->filter->inputs[0]->time_base;
-
- codec->width = ost->filter->filter->inputs[0]->w;
- codec->height = ost->filter->filter->inputs[0]->h;
- codec->sample_aspect_ratio = ost->st->sample_aspect_ratio =
- ost->frame_aspect_ratio ? // overridden by the -aspect cli option
- av_d2q(ost->frame_aspect_ratio * codec->height/codec->width, 255) :
- ost->filter->filter->inputs[0]->sample_aspect_ratio;
- codec->pix_fmt = ost->filter->filter->inputs[0]->format;
-
- if (icodec &&
- (codec->width != icodec->width ||
- codec->height != icodec->height ||
- codec->pix_fmt != icodec->pix_fmt)) {
- codec->bits_per_raw_sample = 0;
- }
-
- if (ost->forced_keyframes)
- parse_forced_key_frames(ost->forced_keyframes, ost,
- ost->st->codec);
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- codec->time_base = (AVRational){1, 1000};
- break;
- default:
- abort();
- break;
- }
- /* two pass mode */
- if ((codec->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->opts, "stats", logfilename, AV_DICT_DONT_OVERWRITE);
- } else {
- if (codec->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);
- }
- codec->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->st->codec;
- if (dec && dec->subtitle_header) {
- ost->st->codec->subtitle_header = av_malloc(dec->subtitle_header_size);
- if (!ost->st->codec->subtitle_header) {
- ret = AVERROR(ENOMEM);
- goto dump_format;
- }
- memcpy(ost->st->codec->subtitle_header, dec->subtitle_header, dec->subtitle_header_size);
- ost->st->codec->subtitle_header_size = dec->subtitle_header_size;
- }
- if (!av_dict_get(ost->opts, "threads", NULL, 0))
- av_dict_set(&ost->opts, "threads", "auto", 0);
- if ((ret = avcodec_open2(ost->st->codec, codec, &ost->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->opts);
- if (ost->st->codec->bit_rate && ost->st->codec->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");
- extra_size += ost->st->codec->extradata_size;
-
- if (ost->st->codec->me_threshold)
- input_streams[ost->source_index]->st->codec->debug |= FF_DEBUG_MV;
- } else {
- av_opt_set_dict(ost->st->codec, &ost->opts);
- }
- }
-
- /* 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
- av_log(NULL, AV_LOG_INFO, " (%s -> %s)", input_streams[ost->source_index]->dec ?
- input_streams[ost->source_index]->dec->name : "?",
- ost->enc ? ost->enc->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() - 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)
- output_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))
- ost->finished= 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)
- goto discard_packet;
-
- ist = input_streams[ifile->ist_index + pkt.stream_index];
- if (ist->discard)
- goto discard_packet;
-
- 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 (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 = output_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();
-
-#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) {
- output_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->st->codec->stats_in);
- avcodec_close(ost->st->codec);
- }
- }
-
- /* close each decoder */
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
- if (ist->decoding_needed) {
- avcodec_close(ist->st->codec);
- }
- }
-
- /* 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->stream_copy)
- av_freep(&ost->st->codec->extradata);
- if (ost->logfile) {
- fclose(ost->logfile);
- ost->logfile = NULL;
- }
- av_freep(&ost->st->codec->subtitle_header);
- av_free(ost->forced_kf_pts);
- av_dict_free(&ost->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();
-#endif
-}
-
-static int64_t getmaxrss(void)
-{
-#if HAVE_GETRUSAGE && HAVE_STRUCT_RUSAGE_RU_MAXRSS
- struct rusage rusage;
- getrusage(RUSAGE_SELF, &rusage);
- return (int64_t)rusage.ru_maxrss * 1024;
-#elif HAVE_GETPROCESSMEMORYINFO
- HANDLE proc;
- PROCESS_MEMORY_COUNTERS memcounters;
- proc = GetCurrentProcess();
- memcounters.cb = sizeof(memcounters);
- GetProcessMemoryInfo(proc, &memcounters, sizeof(memcounters));
- return memcounters.PeakPagefileUsage;
-#else
- return 0;
-#endif
-}
-
-int main(int argc, char **argv)
-{
- int ret;
- int64_t ti;
-
- register_exit(avconv_cleanup);
-
- av_log_set_flags(AV_LOG_SKIP_REPEATED);
- parse_loglevel(argc, argv, options);
-
- avcodec_register_all();
-#if CONFIG_AVDEVICE
- avdevice_register_all();
-#endif
- avfilter_register_all();
- av_register_all();
- avformat_network_init();
-
- show_banner();
-
- /* parse options and open all input/output files */
- ret = avconv_parse_options(argc, argv);
- if (ret < 0)
- exit_program(1);
-
- if (nb_output_files <= 0 && nb_input_files == 0) {
- show_usage();
- av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
- exit_program(1);
- }
-
- /* file converter / grab */
- if (nb_output_files <= 0) {
- fprintf(stderr, "At least one output file must be specified\n");
- exit_program(1);
- }
-
- ti = getutime();
- if (transcode() < 0)
- exit_program(1);
- ti = getutime() - ti;
- if (do_benchmark) {
- int maxrss = getmaxrss() / 1024;
- printf("bench: utime=%0.3fs maxrss=%ikB\n", ti / 1000000.0, maxrss);
- }
-
- exit_program(0);
- return 0;
-}
diff --git a/avconv.h b/avconv.h
deleted file mode 100644
index cb3005d..0000000
--- a/avconv.h
+++ b/dev/null
@@ -1,374 +0,0 @@
-/*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVCONV_H
-#define AVCONV_H
-
-#include "config.h"
-
-#include <stdint.h>
-#include <stdio.h>
-
-#if HAVE_PTHREADS
-#include <pthread.h>
-#endif
-
-#include "cmdutils.h"
-
-#include "libavformat/avformat.h"
-#include "libavformat/avio.h"
-
-#include "libavcodec/avcodec.h"
-
-#include "libavfilter/avfilter.h"
-
-#include "libavutil/avutil.h"
-#include "libavutil/dict.h"
-#include "libavutil/fifo.h"
-#include "libavutil/pixfmt.h"
-#include "libavutil/rational.h"
-
-#define VSYNC_AUTO -1
-#define VSYNC_PASSTHROUGH 0
-#define VSYNC_CFR 1
-#define VSYNC_VFR 2
-
-/* select an input stream for an output stream */
-typedef struct StreamMap {
- int disabled; /* 1 is this mapping is disabled by a negative map */
- int file_index;
- int stream_index;
- int sync_file_index;
- int sync_stream_index;
- char *linklabel; /* name of an output link, for mapping lavfi outputs */
-} StreamMap;
-
-/* select an input file for an output file */
-typedef struct MetadataMap {
- int file; // file index
- char type; // type of metadata to copy -- (g)lobal, (s)tream, (c)hapter or (p)rogram
- int index; // stream/chapter/program number
-} MetadataMap;
-
-typedef struct OptionsContext {
- OptionGroup *g;
-
- /* input/output options */
- int64_t start_time;
- const char *format;
-
- SpecifierOpt *codec_names;
- int nb_codec_names;
- SpecifierOpt *audio_channels;
- int nb_audio_channels;
- SpecifierOpt *audio_sample_rate;
- int nb_audio_sample_rate;
- SpecifierOpt *frame_rates;
- int nb_frame_rates;
- SpecifierOpt *frame_sizes;
- int nb_frame_sizes;
- SpecifierOpt *frame_pix_fmts;
- int nb_frame_pix_fmts;
-
- /* input options */
- int64_t input_ts_offset;
- int rate_emu;
- int accurate_seek;
-
- SpecifierOpt *ts_scale;
- int nb_ts_scale;
- SpecifierOpt *dump_attachment;
- int nb_dump_attachment;
-
- /* output options */
- StreamMap *stream_maps;
- int nb_stream_maps;
- /* first item specifies output metadata, second is input */
- MetadataMap (*meta_data_maps)[2];
- int nb_meta_data_maps;
- int metadata_global_manual;
- int metadata_streams_manual;
- int metadata_chapters_manual;
- const char **attachments;
- int nb_attachments;
-
- int chapters_input_file;
-
- int64_t recording_time;
- uint64_t limit_filesize;
- float mux_preload;
- float mux_max_delay;
- int shortest;
-
- int video_disable;
- int audio_disable;
- int subtitle_disable;
- int data_disable;
-
- /* indexed by output file stream index */
- int *streamid_map;
- int nb_streamid_map;
-
- SpecifierOpt *metadata;
- int nb_metadata;
- SpecifierOpt *max_frames;
- int nb_max_frames;
- SpecifierOpt *bitstream_filters;
- int nb_bitstream_filters;
- SpecifierOpt *codec_tags;
- int nb_codec_tags;
- SpecifierOpt *sample_fmts;
- int nb_sample_fmts;
- SpecifierOpt *qscale;
- int nb_qscale;
- SpecifierOpt *forced_key_frames;
- int nb_forced_key_frames;
- SpecifierOpt *force_fps;
- int nb_force_fps;
- SpecifierOpt *frame_aspect_ratios;
- int nb_frame_aspect_ratios;
- SpecifierOpt *rc_overrides;
- int nb_rc_overrides;
- SpecifierOpt *intra_matrices;
- int nb_intra_matrices;
- SpecifierOpt *inter_matrices;
- int nb_inter_matrices;
- SpecifierOpt *top_field_first;
- int nb_top_field_first;
- SpecifierOpt *metadata_map;
- int nb_metadata_map;
- SpecifierOpt *presets;
- int nb_presets;
- SpecifierOpt *copy_initial_nonkeyframes;
- int nb_copy_initial_nonkeyframes;
- SpecifierOpt *filters;
- int nb_filters;
- SpecifierOpt *filter_scripts;
- int nb_filter_scripts;
- SpecifierOpt *pass;
- int nb_pass;
- SpecifierOpt *passlogfiles;
- int nb_passlogfiles;
-} OptionsContext;
-
-typedef struct InputFilter {
- AVFilterContext *filter;
- struct InputStream *ist;
- struct FilterGraph *graph;
- uint8_t *name;
-} InputFilter;
-
-typedef struct OutputFilter {
- AVFilterContext *filter;
- struct OutputStream *ost;
- struct FilterGraph *graph;
- uint8_t *name;
-
- /* temporary storage until stream maps are processed */
- AVFilterInOut *out_tmp;
-} OutputFilter;
-
-typedef struct FilterGraph {
- int index;
- const char *graph_desc;
-
- AVFilterGraph *graph;
-
- InputFilter **inputs;
- int nb_inputs;
- OutputFilter **outputs;
- int nb_outputs;
-} FilterGraph;
-
-typedef struct InputStream {
- int file_index;
- AVStream *st;
- int discard; /* true if stream data should be discarded */
- int decoding_needed; /* true if the packets must be decoded in 'raw_fifo' */
- AVCodec *dec;
- AVFrame *decoded_frame;
- AVFrame *filter_frame; /* a ref of decoded_frame, to be sent to filters */
-
- int64_t start; /* time when read started */
- /* predicted dts of the next packet read for this stream or (when there are
- * several frames in a packet) of the next frame in current packet */
- int64_t next_dts;
- /* dts of the last packet read for this stream */
- int64_t last_dts;
- PtsCorrectionContext pts_ctx;
- double ts_scale;
- int is_start; /* is 1 at the start and after a discontinuity */
- int showed_multi_packet_warning;
- AVDictionary *opts;
- AVRational framerate; /* framerate forced with -r */
-
- int resample_height;
- int resample_width;
- int resample_pix_fmt;
-
- int resample_sample_fmt;
- int resample_sample_rate;
- int resample_channels;
- uint64_t resample_channel_layout;
-
- /* decoded data from this stream goes into all those filters
- * currently video and audio only */
- InputFilter **filters;
- int nb_filters;
-} InputStream;
-
-typedef struct InputFile {
- AVFormatContext *ctx;
- int eof_reached; /* true if eof reached */
- int eagain; /* true if last read attempt returned EAGAIN */
- int ist_index; /* index of first stream in ist_table */
- int64_t ts_offset;
- int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */
- int64_t recording_time;
- int nb_streams; /* number of stream that avconv is aware of; may be different
- from ctx.nb_streams if new streams appear during av_read_frame() */
- int rate_emu;
- int accurate_seek;
-
-#if HAVE_PTHREADS
- pthread_t thread; /* thread reading from this file */
- int finished; /* the thread has exited */
- int joined; /* the thread has been joined */
- pthread_mutex_t fifo_lock; /* lock for access to fifo */
- pthread_cond_t fifo_cond; /* the main thread will signal on this cond after reading from fifo */
- AVFifoBuffer *fifo; /* demuxed packets are stored here; freed by the main thread */
-#endif
-} InputFile;
-
-typedef struct OutputStream {
- int file_index; /* file index */
- int index; /* stream index in the output file */
- int source_index; /* InputStream index */
- AVStream *st; /* stream in the output file */
- int encoding_needed; /* true if encoding needed for this stream */
- int frame_number;
- /* input pts and corresponding output pts
- for A/V sync */
- // double sync_ipts; /* dts from the AVPacket of the demuxer in second units */
- struct InputStream *sync_ist; /* input stream to sync against */
- int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ // FIXME look at frame_number
- /* pts of the first frame encoded for this stream, used for limiting
- * recording time */
- int64_t first_pts;
- /* dts of the last packet sent to the muxer */
- int64_t last_mux_dts;
- AVBitStreamFilterContext *bitstream_filters;
- AVCodec *enc;
- int64_t max_frames;
- AVFrame *filtered_frame;
-
- /* video only */
- AVRational frame_rate;
- int force_fps;
- int top_field_first;
-
- float frame_aspect_ratio;
-
- /* forced key frames */
- int64_t *forced_kf_pts;
- int forced_kf_count;
- int forced_kf_index;
- char *forced_keyframes;
-
- char *logfile_prefix;
- FILE *logfile;
-
- OutputFilter *filter;
- char *avfilter;
-
- int64_t sws_flags;
- AVDictionary *opts;
- AVDictionary *resample_opts;
- int finished; /* no more packets should be written for this stream */
- int stream_copy;
- const char *attachment_filename;
- int copy_initial_nonkeyframes;
-
- enum AVPixelFormat pix_fmts[2];
-
- AVCodecParserContext *parser;
-} OutputStream;
-
-typedef struct OutputFile {
- AVFormatContext *ctx;
- AVDictionary *opts;
- int ost_index; /* index of the first stream in output_streams */
- int64_t recording_time; /* desired length of the resulting file in microseconds */
- int64_t start_time; /* start time in microseconds */
- uint64_t limit_filesize;
-
- int shortest;
-} OutputFile;
-
-extern InputStream **input_streams;
-extern int nb_input_streams;
-extern InputFile **input_files;
-extern int nb_input_files;
-
-extern OutputStream **output_streams;
-extern int nb_output_streams;
-extern OutputFile **output_files;
-extern int nb_output_files;
-
-extern FilterGraph **filtergraphs;
-extern int nb_filtergraphs;
-
-extern char *vstats_filename;
-
-extern float audio_drift_threshold;
-extern float dts_delta_threshold;
-
-extern int audio_volume;
-extern int audio_sync_method;
-extern int video_sync_method;
-extern int do_benchmark;
-extern int do_deinterlace;
-extern int do_hex_dump;
-extern int do_pkt_dump;
-extern int copy_ts;
-extern int copy_tb;
-extern int exit_on_error;
-extern int print_stats;
-extern int qp_hist;
-
-extern const AVIOInterruptCB int_cb;
-
-extern const OptionDef options[];
-
-void reset_options(OptionsContext *o);
-void show_usage(void);
-
-void opt_output_file(void *optctx, const char *filename);
-
-void assert_avoptions(AVDictionary *m);
-
-int guess_input_channel_layout(InputStream *ist);
-
-int configure_filtergraph(FilterGraph *fg);
-int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out);
-int ist_in_filtergraph(FilterGraph *fg, InputStream *ist);
-FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost);
-
-int avconv_parse_options(int argc, char **argv);
-
-#endif /* AVCONV_H */
diff --git a/avconv_filter.c b/avconv_filter.c
deleted file mode 100644
index 348196f..0000000
--- a/avconv_filter.c
+++ b/dev/null
@@ -1,655 +0,0 @@
-/*
- * avconv filter configuration
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "avconv.h"
-
-#include "libavfilter/avfilter.h"
-
-#include "libavresample/avresample.h"
-
-#include "libavutil/avassert.h"
-#include "libavutil/avstring.h"
-#include "libavutil/channel_layout.h"
-#include "libavutil/opt.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/pixfmt.h"
-#include "libavutil/samplefmt.h"
-
-/* Define a function for building a string containing a list of
- * allowed formats. */
-#define DEF_CHOOSE_FORMAT(type, var, supported_list, none, get_name) \
-static char *choose_ ## var ## s(OutputStream *ost) \
-{ \
- if (ost->st->codec->var != none) { \
- get_name(ost->st->codec->var); \
- return av_strdup(name); \
- } else if (ost->enc && ost->enc->supported_list) { \
- const type *p; \
- AVIOContext *s = NULL; \
- uint8_t *ret; \
- int len; \
- \
- if (avio_open_dyn_buf(&s) < 0) \
- exit(1); \
- \
- for (p = ost->enc->supported_list; *p != none; p++) { \
- get_name(*p); \
- avio_printf(s, "%s|", name); \
- } \
- len = avio_close_dyn_buf(s, &ret); \
- ret[len - 1] = 0; \
- return ret; \
- } else \
- return NULL; \
-}
-
-DEF_CHOOSE_FORMAT(enum AVPixelFormat, pix_fmt, pix_fmts, AV_PIX_FMT_NONE,
- GET_PIX_FMT_NAME)
-
-DEF_CHOOSE_FORMAT(enum AVSampleFormat, sample_fmt, sample_fmts,
- AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME)
-
-DEF_CHOOSE_FORMAT(int, sample_rate, supported_samplerates, 0,
- GET_SAMPLE_RATE_NAME)
-
-DEF_CHOOSE_FORMAT(uint64_t, channel_layout, channel_layouts, 0,
- GET_CH_LAYOUT_NAME)
-
-FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
-{
- FilterGraph *fg = av_mallocz(sizeof(*fg));
-
- if (!fg)
- exit(1);
- fg->index = nb_filtergraphs;
-
- GROW_ARRAY(fg->outputs, fg->nb_outputs);
- if (!(fg->outputs[0] = av_mallocz(sizeof(*fg->outputs[0]))))
- exit(1);
- fg->outputs[0]->ost = ost;
- fg->outputs[0]->graph = fg;
-
- ost->filter = fg->outputs[0];
-
- GROW_ARRAY(fg->inputs, fg->nb_inputs);
- if (!(fg->inputs[0] = av_mallocz(sizeof(*fg->inputs[0]))))
- exit(1);
- fg->inputs[0]->ist = ist;
- fg->inputs[0]->graph = fg;
-
- GROW_ARRAY(ist->filters, ist->nb_filters);
- ist->filters[ist->nb_filters - 1] = fg->inputs[0];
-
- GROW_ARRAY(filtergraphs, nb_filtergraphs);
- filtergraphs[nb_filtergraphs - 1] = fg;
-
- return fg;
-}
-
-static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
-{
- InputStream *ist = NULL;
- enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
- int i;
-
- // TODO: support other filter types
- if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
- av_log(NULL, AV_LOG_FATAL, "Only video and audio filters supported "
- "currently.\n");
- exit(1);
- }
-
- if (in->name) {
- AVFormatContext *s;
- AVStream *st = NULL;
- char *p;
- int file_idx = strtol(in->name, &p, 0);
-
- if (file_idx < 0 || file_idx >= nb_input_files) {
- av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtegraph description %s.\n",
- file_idx, fg->graph_desc);
- exit(1);
- }
- s = input_files[file_idx]->ctx;
-
- for (i = 0; i < s->nb_streams; i++) {
- if (s->streams[i]->codec->codec_type != type)
- continue;
- if (check_stream_specifier(s, s->streams[i], *p == ':' ? p + 1 : p) == 1) {
- st = s->streams[i];
- break;
- }
- }
- if (!st) {
- av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s "
- "matches no streams.\n", p, fg->graph_desc);
- exit(1);
- }
- ist = input_streams[input_files[file_idx]->ist_index + st->index];
- } else {
- /* find the first unused stream of corresponding type */
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
- if (ist->st->codec->codec_type == type && ist->discard)
- break;
- }
- if (i == nb_input_streams) {
- av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for "
- "unlabeled input pad %d on filter %s", in->pad_idx,
- in->filter_ctx->name);
- exit(1);
- }
- }
- av_assert0(ist);
-
- ist->discard = 0;
- ist->decoding_needed = 1;
- ist->st->discard = AVDISCARD_NONE;
-
- GROW_ARRAY(fg->inputs, fg->nb_inputs);
- if (!(fg->inputs[fg->nb_inputs - 1] = av_mallocz(sizeof(*fg->inputs[0]))))
- exit(1);
- fg->inputs[fg->nb_inputs - 1]->ist = ist;
- fg->inputs[fg->nb_inputs - 1]->graph = fg;
-
- GROW_ARRAY(ist->filters, ist->nb_filters);
- ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1];
-}
-
-static int insert_trim(int64_t start_time, int64_t duration,
- AVFilterContext **last_filter, int *pad_idx,
- const char *filter_name)
-{
- AVFilterGraph *graph = (*last_filter)->graph;
- AVFilterContext *ctx;
- const AVFilter *trim;
- enum AVMediaType type = avfilter_pad_get_type((*last_filter)->output_pads, *pad_idx);
- const char *name = (type == AVMEDIA_TYPE_VIDEO) ? "trim" : "atrim";
- int ret = 0;
-
- if (duration == INT64_MAX && start_time == AV_NOPTS_VALUE)
- return 0;
-
- trim = avfilter_get_by_name(name);
- if (!trim) {
- av_log(NULL, AV_LOG_ERROR, "%s filter not present, cannot limit "
- "recording time.\n", name);
- return AVERROR_FILTER_NOT_FOUND;
- }
-
- ctx = avfilter_graph_alloc_filter(graph, trim, filter_name);
- if (!ctx)
- return AVERROR(ENOMEM);
-
- if (duration != INT64_MAX) {
- ret = av_opt_set_double(ctx, "duration", (double)duration / 1e6,
- AV_OPT_SEARCH_CHILDREN);
- }
- if (ret >= 0 && start_time != AV_NOPTS_VALUE) {
- ret = av_opt_set_double(ctx, "start", (double)start_time / 1e6,
- AV_OPT_SEARCH_CHILDREN);
- }
- if (ret < 0) {
- av_log(ctx, AV_LOG_ERROR, "Error configuring the %s filter", name);
- return ret;
- }
-
- ret = avfilter_init_str(ctx, NULL);
- if (ret < 0)
- return ret;
-
- ret = avfilter_link(*last_filter, *pad_idx, ctx, 0);
- if (ret < 0)
- return ret;
-
- *last_filter = ctx;
- *pad_idx = 0;
- return 0;
-}
-
-static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
-{
- char *pix_fmts;
- OutputStream *ost = ofilter->ost;
- OutputFile *of = output_files[ost->file_index];
- AVCodecContext *codec = ost->st->codec;
- AVFilterContext *last_filter = out->filter_ctx;
- int pad_idx = out->pad_idx;
- int ret;
- char name[255];
-
- snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
- ret = avfilter_graph_create_filter(&ofilter->filter,
- avfilter_get_by_name("buffersink"),
- name, NULL, NULL, fg->graph);
- if (ret < 0)
- return ret;
-
- if (codec->width || codec->height) {
- char args[255];
- AVFilterContext *filter;
-
- snprintf(args, sizeof(args), "%d:%d:0x%X",
- codec->width,
- codec->height,
- (unsigned)ost->sws_flags);
- snprintf(name, sizeof(name), "scaler for output stream %d:%d",
- ost->file_index, ost->index);
- if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
- name, args, NULL, fg->graph)) < 0)
- return ret;
- if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
- return ret;
-
- last_filter = filter;
- pad_idx = 0;
- }
-
- if ((pix_fmts = choose_pix_fmts(ost))) {
- AVFilterContext *filter;
- snprintf(name, sizeof(name), "pixel format for output stream %d:%d",
- ost->file_index, ost->index);
- if ((ret = avfilter_graph_create_filter(&filter,
- avfilter_get_by_name("format"),
- "format", pix_fmts, NULL,
- fg->graph)) < 0)
- return ret;
- if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
- return ret;
-
- last_filter = filter;
- pad_idx = 0;
- av_freep(&pix_fmts);
- }
-
- if (ost->frame_rate.num) {
- AVFilterContext *fps;
- char args[255];
-
- snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num,
- ost->frame_rate.den);
- snprintf(name, sizeof(name), "fps for output stream %d:%d",
- ost->file_index, ost->index);
- ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"),
- name, args, NULL, fg->graph);
- if (ret < 0)
- return ret;
-
- ret = avfilter_link(last_filter, pad_idx, fps, 0);
- if (ret < 0)
- return ret;
- last_filter = fps;
- pad_idx = 0;
- }
-
- snprintf(name, sizeof(name), "trim for output stream %d:%d",
- ost->file_index, ost->index);
- ret = insert_trim(of->start_time, of->recording_time,
- &last_filter, &pad_idx, name);
- if (ret < 0)
- return ret;
-
-
- if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
- return ret;
-
- return 0;
-}
-
-static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
-{
- OutputStream *ost = ofilter->ost;
- OutputFile *of = output_files[ost->file_index];
- AVCodecContext *codec = ost->st->codec;
- AVFilterContext *last_filter = out->filter_ctx;
- int pad_idx = out->pad_idx;
- char *sample_fmts, *sample_rates, *channel_layouts;
- char name[255];
- int ret;
-
-
- snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
- ret = avfilter_graph_create_filter(&ofilter->filter,
- avfilter_get_by_name("abuffersink"),
- name, NULL, NULL, fg->graph);
- if (ret < 0)
- return ret;
-
- if (codec->channels && !codec->channel_layout)
- codec->channel_layout = av_get_default_channel_layout(codec->channels);
-
- sample_fmts = choose_sample_fmts(ost);
- sample_rates = choose_sample_rates(ost);
- channel_layouts = choose_channel_layouts(ost);
- if (sample_fmts || sample_rates || channel_layouts) {
- AVFilterContext *format;
- char args[256];
- int len = 0;
-
- if (sample_fmts)
- len += snprintf(args + len, sizeof(args) - len, "sample_fmts=%s:",
- sample_fmts);
- if (sample_rates)
- len += snprintf(args + len, sizeof(args) - len, "sample_rates=%s:",
- sample_rates);
- if (channel_layouts)
- len += snprintf(args + len, sizeof(args) - len, "channel_layouts=%s:",
- channel_layouts);
- args[len - 1] = 0;
-
- av_freep(&sample_fmts);
- av_freep(&sample_rates);
- av_freep(&channel_layouts);
-
- snprintf(name, sizeof(name), "audio format for output stream %d:%d",
- ost->file_index, ost->index);
- ret = avfilter_graph_create_filter(&format,
- avfilter_get_by_name("aformat"),
- name, args, NULL, fg->graph);
- if (ret < 0)
- return ret;
-
- ret = avfilter_link(last_filter, pad_idx, format, 0);
- if (ret < 0)
- return ret;
-
- last_filter = format;
- pad_idx = 0;
- }
-
- snprintf(name, sizeof(name), "trim for output stream %d:%d",
- ost->file_index, ost->index);
- ret = insert_trim(of->start_time, of->recording_time,
- &last_filter, &pad_idx, name);
- if (ret < 0)
- return ret;
-
- if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
- return ret;
-
- return 0;
-}
-
-#define DESCRIBE_FILTER_LINK(f, inout, in) \
-{ \
- AVFilterContext *ctx = inout->filter_ctx; \
- AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads; \
- int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs; \
- AVIOContext *pb; \
- \
- if (avio_open_dyn_buf(&pb) < 0) \
- exit(1); \
- \
- avio_printf(pb, "%s", ctx->filter->name); \
- if (nb_pads > 1) \
- avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));\
- avio_w8(pb, 0); \
- avio_close_dyn_buf(pb, &f->name); \
-}
-
-int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
-{
- av_freep(&ofilter->name);
- DESCRIBE_FILTER_LINK(ofilter, out, 0);
-
- switch (avfilter_pad_get_type(out->filter_ctx->output_pads, out->pad_idx)) {
- case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, ofilter, out);
- case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, ofilter, out);
- default: av_assert0(0);
- }
-}
-
-static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
- AVFilterInOut *in)
-{
- AVFilterContext *last_filter;
- const AVFilter *buffer_filt = avfilter_get_by_name("buffer");
- InputStream *ist = ifilter->ist;
- InputFile *f = input_files[ist->file_index];
- AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) :
- ist->st->time_base;
- AVRational sar;
- char args[255], name[255];
- int ret, pad_idx = 0;
-
- sar = ist->st->sample_aspect_ratio.num ?
- ist->st->sample_aspect_ratio :
- ist->st->codec->sample_aspect_ratio;
- snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d", ist->st->codec->width,
- ist->st->codec->height, ist->st->codec->pix_fmt,
- tb.num, tb.den, sar.num, sar.den);
- snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
- ist->file_index, ist->st->index);
-
- if ((ret = avfilter_graph_create_filter(&ifilter->filter, buffer_filt, name,
- args, NULL, fg->graph)) < 0)
- return ret;
- last_filter = ifilter->filter;
-
- if (ist->framerate.num) {
- AVFilterContext *setpts;
-
- snprintf(name, sizeof(name), "force CFR for input from stream %d:%d",
- ist->file_index, ist->st->index);
- if ((ret = avfilter_graph_create_filter(&setpts,
- avfilter_get_by_name("setpts"),
- name, "N", NULL,
- fg->graph)) < 0)
- return ret;
-
- if ((ret = avfilter_link(last_filter, 0, setpts, 0)) < 0)
- return ret;
-
- last_filter = setpts;
- }
-
- snprintf(name, sizeof(name), "trim for input stream %d:%d",
- ist->file_index, ist->st->index);
- ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
- AV_NOPTS_VALUE : 0, f->recording_time, &last_filter, &pad_idx, name);
- if (ret < 0)
- return ret;
-
- if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
- return ret;
- return 0;
-}
-
-static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
- AVFilterInOut *in)
-{
- AVFilterContext *last_filter;
- const AVFilter *abuffer_filt = avfilter_get_by_name("abuffer");
- InputStream *ist = ifilter->ist;
- InputFile *f = input_files[ist->file_index];
- char args[255], name[255];
- int ret, pad_idx = 0;
-
- snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s"
- ":channel_layout=0x%"PRIx64,
- 1, ist->st->codec->sample_rate,
- ist->st->codec->sample_rate,
- av_get_sample_fmt_name(ist->st->codec->sample_fmt),
- ist->st->codec->channel_layout);
- snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
- ist->file_index, ist->st->index);
-
- if ((ret = avfilter_graph_create_filter(&ifilter->filter, abuffer_filt,
- name, args, NULL,
- fg->graph)) < 0)
- return ret;
- last_filter = ifilter->filter;
-
- if (audio_sync_method > 0) {
- AVFilterContext *async;
- int len = 0;
-
- av_log(NULL, AV_LOG_WARNING, "-async has been deprecated. Used the "
- "asyncts audio filter instead.\n");
-
- if (audio_sync_method > 1)
- len += snprintf(args + len, sizeof(args) - len, "compensate=1:"
- "max_comp=%d:", audio_sync_method);
- snprintf(args + len, sizeof(args) - len, "min_delta=%f",
- audio_drift_threshold);
-
- snprintf(name, sizeof(name), "graph %d audio sync for input stream %d:%d",
- fg->index, ist->file_index, ist->st->index);
- ret = avfilter_graph_create_filter(&async,
- avfilter_get_by_name("asyncts"),
- name, args, NULL, fg->graph);
- if (ret < 0)
- return ret;
-
- ret = avfilter_link(last_filter, 0, async, 0);
- if (ret < 0)
- return ret;
-
- last_filter = async;
- }
- if (audio_volume != 256) {
- AVFilterContext *volume;
-
- av_log(NULL, AV_LOG_WARNING, "-vol has been deprecated. Use the volume "
- "audio filter instead.\n");
-
- snprintf(args, sizeof(args), "volume=%f", audio_volume / 256.0);
-
- snprintf(name, sizeof(name), "graph %d volume for input stream %d:%d",
- fg->index, ist->file_index, ist->st->index);
- ret = avfilter_graph_create_filter(&volume,
- avfilter_get_by_name("volume"),
- name, args, NULL, fg->graph);
- if (ret < 0)
- return ret;
-
- ret = avfilter_link(last_filter, 0, volume, 0);
- if (ret < 0)
- return ret;
-
- last_filter = volume;
- }
-
- snprintf(name, sizeof(name), "trim for input stream %d:%d",
- ist->file_index, ist->st->index);
- ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
- AV_NOPTS_VALUE : 0, f->recording_time, &last_filter, &pad_idx, name);
- if (ret < 0)
- return ret;
-
- if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
- return ret;
-
- return 0;
-}
-
-static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
- AVFilterInOut *in)
-{
- av_freep(&ifilter->name);
- DESCRIBE_FILTER_LINK(ifilter, in, 1);
-
- switch (avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx)) {
- case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in);
- case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in);
- default: av_assert0(0);
- }
-}
-
-int configure_filtergraph(FilterGraph *fg)
-{
- AVFilterInOut *inputs, *outputs, *cur;
- int ret, i, init = !fg->graph, simple = !fg->graph_desc;
- const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter :
- fg->graph_desc;
-
- avfilter_graph_free(&fg->graph);
- if (!(fg->graph = avfilter_graph_alloc()))
- return AVERROR(ENOMEM);
-
- if (simple) {
- OutputStream *ost = fg->outputs[0]->ost;
- char args[512];
- AVDictionaryEntry *e = NULL;
-
- snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags);
- fg->graph->scale_sws_opts = av_strdup(args);
-
- args[0] = '\0';
- while ((e = av_dict_get(fg->outputs[0]->ost->resample_opts, "", e,
- AV_DICT_IGNORE_SUFFIX))) {
- av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
- }
- if (strlen(args))
- args[strlen(args) - 1] = '\0';
- fg->graph->resample_lavr_opts = av_strdup(args);
- }
-
- if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0)
- return ret;
-
- if (simple && (!inputs || inputs->next || !outputs || outputs->next)) {
- av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' does not have "
- "exactly one input and output.\n", graph_desc);
- return AVERROR(EINVAL);
- }
-
- for (cur = inputs; !simple && init && cur; cur = cur->next)
- init_input_filter(fg, cur);
-
- for (cur = inputs, i = 0; cur; cur = cur->next, i++)
- if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0)
- return ret;
- avfilter_inout_free(&inputs);
-
- if (!init || simple) {
- /* we already know the mappings between lavfi outputs and output streams,
- * so we can finish the setup */
- for (cur = outputs, i = 0; cur; cur = cur->next, i++)
- configure_output_filter(fg, fg->outputs[i], cur);
- avfilter_inout_free(&outputs);
-
- if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)
- return ret;
- } else {
- /* wait until output mappings are processed */
- for (cur = outputs; cur;) {
- GROW_ARRAY(fg->outputs, fg->nb_outputs);
- if (!(fg->outputs[fg->nb_outputs - 1] = av_mallocz(sizeof(*fg->outputs[0]))))
- exit(1);
- fg->outputs[fg->nb_outputs - 1]->graph = fg;
- fg->outputs[fg->nb_outputs - 1]->out_tmp = cur;
- cur = cur->next;
- fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL;
- }
- }
-
- return 0;
-}
-
-int ist_in_filtergraph(FilterGraph *fg, InputStream *ist)
-{
- int i;
- for (i = 0; i < fg->nb_inputs; i++)
- if (fg->inputs[i]->ist == ist)
- return 1;
- return 0;
-}
-
diff --git a/avconv_opt.c b/avconv_opt.c
deleted file mode 100644
index 70cbd71..0000000
--- a/avconv_opt.c
+++ b/dev/null
@@ -1,2341 +0,0 @@
-/*
- * avconv option parsing
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdint.h>
-
-#include "avconv.h"
-#include "cmdutils.h"
-
-#include "libavformat/avformat.h"
-
-#include "libavcodec/avcodec.h"
-
-#include "libavfilter/avfilter.h"
-
-#include "libavutil/avassert.h"
-#include "libavutil/avstring.h"
-#include "libavutil/avutil.h"
-#include "libavutil/channel_layout.h"
-#include "libavutil/intreadwrite.h"
-#include "libavutil/fifo.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/opt.h"
-#include "libavutil/parseutils.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/pixfmt.h"
-
-#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
-{\
- int i, ret;\
- for (i = 0; i < o->nb_ ## name; i++) {\
- char *spec = o->name[i].specifier;\
- if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0)\
- outvar = o->name[i].u.type;\
- else if (ret < 0)\
- exit_program(1);\
- }\
-}
-
-char *vstats_filename;
-
-float audio_drift_threshold = 0.1;
-float dts_delta_threshold = 10;
-
-int audio_volume = 256;
-int audio_sync_method = 0;
-int video_sync_method = VSYNC_AUTO;
-int do_benchmark = 0;
-int do_hex_dump = 0;
-int do_pkt_dump = 0;
-int copy_ts = 0;
-int copy_tb = 1;
-int exit_on_error = 0;
-int print_stats = 1;
-int qp_hist = 0;
-
-static int file_overwrite = 0;
-static int file_skip = 0;
-static int video_discard = 0;
-static int intra_dc_precision = 8;
-static int using_stdin = 0;
-static int input_sync;
-
-static void uninit_options(OptionsContext *o)
-{
- const OptionDef *po = options;
- int i;
-
- /* all OPT_SPEC and OPT_STRING can be freed in generic way */
- while (po->name) {
- void *dst = (uint8_t*)o + po->u.off;
-
- if (po->flags & OPT_SPEC) {
- SpecifierOpt **so = dst;
- int i, *count = (int*)(so + 1);
- for (i = 0; i < *count; i++) {
- av_freep(&(*so)[i].specifier);
- if (po->flags & OPT_STRING)
- av_freep(&(*so)[i].u.str);
- }
- av_freep(so);
- *count = 0;
- } else if (po->flags & OPT_OFFSET && po->flags & OPT_STRING)
- av_freep(dst);
- po++;
- }
-
- for (i = 0; i < o->nb_stream_maps; i++)
- av_freep(&o->stream_maps[i].linklabel);
- av_freep(&o->stream_maps);
- av_freep(&o->meta_data_maps);
- av_freep(&o->streamid_map);
-}
-
-static void init_options(OptionsContext *o)
-{
- memset(o, 0, sizeof(*o));
-
- o->mux_max_delay = 0.7;
- o->start_time = AV_NOPTS_VALUE;
- o->recording_time = INT64_MAX;
- o->limit_filesize = UINT64_MAX;
- o->chapters_input_file = INT_MAX;
- o->accurate_seek = 1;
-}
-
-/* return a copy of the input with the stream specifiers removed from the keys */
-static AVDictionary *strip_specifiers(AVDictionary *dict)
-{
- AVDictionaryEntry *e = NULL;
- AVDictionary *ret = NULL;
-
- while ((e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))) {
- char *p = strchr(e->key, ':');
-
- if (p)
- *p = 0;
- av_dict_set(&ret, e->key, e->value, 0);
- if (p)
- *p = ':';
- }
- return ret;
-}
-
-static double parse_frame_aspect_ratio(const char *arg)
-{
- int x = 0, y = 0;
- double ar = 0;
- const char *p;
- char *end;
-
- p = strchr(arg, ':');
- if (p) {
- x = strtol(arg, &end, 10);
- if (end == p)
- y = strtol(end + 1, &end, 10);
- if (x > 0 && y > 0)
- ar = (double)x / (double)y;
- } else
- ar = strtod(arg, NULL);
-
- if (!ar) {
- av_log(NULL, AV_LOG_FATAL, "Incorrect aspect ratio specification.\n");
- exit_program(1);
- }
- return ar;
-}
-
-static int opt_audio_codec(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "codec:a", arg, options);
-}
-
-static int opt_video_codec(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "codec:v", arg, options);
-}
-
-static int opt_subtitle_codec(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "codec:s", arg, options);
-}
-
-static int opt_data_codec(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "codec:d", arg, options);
-}
-
-static int opt_map(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- StreamMap *m = NULL;
- int i, negative = 0, file_idx;
- int sync_file_idx = -1, sync_stream_idx;
- char *p, *sync;
- char *map;
-
- if (*arg == '-') {
- negative = 1;
- arg++;
- }
- map = av_strdup(arg);
-
- /* parse sync stream first, just pick first matching stream */
- if (sync = strchr(map, ',')) {
- *sync = 0;
- sync_file_idx = strtol(sync + 1, &sync, 0);
- if (sync_file_idx >= nb_input_files || sync_file_idx < 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid sync file index: %d.\n", sync_file_idx);
- exit_program(1);
- }
- if (*sync)
- sync++;
- for (i = 0; i < input_files[sync_file_idx]->nb_streams; i++)
- if (check_stream_specifier(input_files[sync_file_idx]->ctx,
- input_files[sync_file_idx]->ctx->streams[i], sync) == 1) {
- sync_stream_idx = i;
- break;
- }
- if (i == input_files[sync_file_idx]->nb_streams) {
- av_log(NULL, AV_LOG_FATAL, "Sync stream specification in map %s does not "
- "match any streams.\n", arg);
- exit_program(1);
- }
- }
-
-
- if (map[0] == '[') {
- /* this mapping refers to lavfi output */
- const char *c = map + 1;
- GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
- m = &o->stream_maps[o->nb_stream_maps - 1];
- m->linklabel = av_get_token(&c, "]");
- if (!m->linklabel) {
- av_log(NULL, AV_LOG_ERROR, "Invalid output link label: %s.\n", map);
- exit_program(1);
- }
- } else {
- file_idx = strtol(map, &p, 0);
- if (file_idx >= nb_input_files || file_idx < 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid input file index: %d.\n", file_idx);
- exit_program(1);
- }
- if (negative)
- /* disable some already defined maps */
- for (i = 0; i < o->nb_stream_maps; i++) {
- m = &o->stream_maps[i];
- if (file_idx == m->file_index &&
- check_stream_specifier(input_files[m->file_index]->ctx,
- input_files[m->file_index]->ctx->streams[m->stream_index],
- *p == ':' ? p + 1 : p) > 0)
- m->disabled = 1;
- }
- else
- for (i = 0; i < input_files[file_idx]->nb_streams; i++) {
- if (check_stream_specifier(input_files[file_idx]->ctx, input_files[file_idx]->ctx->streams[i],
- *p == ':' ? p + 1 : p) <= 0)
- continue;
- GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
- m = &o->stream_maps[o->nb_stream_maps - 1];
-
- m->file_index = file_idx;
- m->stream_index = i;
-
- if (sync_file_idx >= 0) {
- m->sync_file_index = sync_file_idx;
- m->sync_stream_index = sync_stream_idx;
- } else {
- m->sync_file_index = file_idx;
- m->sync_stream_index = i;
- }
- }
- }
-
- if (!m) {
- av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches no streams.\n", arg);
- exit_program(1);
- }
-
- av_freep(&map);
- return 0;
-}
-
-static int opt_attach(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- GROW_ARRAY(o->attachments, o->nb_attachments);
- o->attachments[o->nb_attachments - 1] = arg;
- return 0;
-}
-
-/**
- * Parse a metadata specifier passed as 'arg' parameter.
- * @param arg metadata string to parse
- * @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram)
- * @param index for type c/p, chapter/program index is written here
- * @param stream_spec for type s, the stream specifier is written here
- */
-static void parse_meta_type(char *arg, char *type, int *index, const char **stream_spec)
-{
- if (*arg) {
- *type = *arg;
- switch (*arg) {
- case 'g':
- break;
- case 's':
- if (*(++arg) && *arg != ':') {
- av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg);
- exit_program(1);
- }
- *stream_spec = *arg == ':' ? arg + 1 : "";
- break;
- case 'c':
- case 'p':
- if (*(++arg) == ':')
- *index = strtol(++arg, NULL, 0);
- break;
- default:
- av_log(NULL, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
- exit_program(1);
- }
- } else
- *type = 'g';
-}
-
-static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
-{
- AVDictionary **meta_in = NULL;
- AVDictionary **meta_out;
- int i, ret = 0;
- char type_in, type_out;
- const char *istream_spec = NULL, *ostream_spec = NULL;
- int idx_in = 0, idx_out = 0;
-
- parse_meta_type(inspec, &type_in, &idx_in, &istream_spec);
- parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);
-
- if (type_in == 'g' || type_out == 'g')
- o->metadata_global_manual = 1;
- if (type_in == 's' || type_out == 's')
- o->metadata_streams_manual = 1;
- if (type_in == 'c' || type_out == 'c')
- o->metadata_chapters_manual = 1;
-
- /* ic is NULL when just disabling automatic mappings */
- if (!ic)
- return 0;
-
-#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
- if ((index) < 0 || (index) >= (nb_elems)) {\
- av_log(NULL, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\
- (desc), (index));\
- exit_program(1);\
- }
-
-#define SET_DICT(type, meta, context, index)\
- switch (type) {\
- case 'g':\
- meta = &context->metadata;\
- break;\
- case 'c':\
- METADATA_CHECK_INDEX(index, context->nb_chapters, "chapter")\
- meta = &context->chapters[index]->metadata;\
- break;\
- case 'p':\
- METADATA_CHECK_INDEX(index, context->nb_programs, "program")\
- meta = &context->programs[index]->metadata;\
- break;\
- case 's':\
- break; /* handled separately below */ \
- default: av_assert0(0);\
- }\
-
- SET_DICT(type_in, meta_in, ic, idx_in);
- SET_DICT(type_out, meta_out, oc, idx_out);
-
- /* for input streams choose first matching stream */
- if (type_in == 's') {
- for (i = 0; i < ic->nb_streams; i++) {
- if ((ret = check_stream_specifier(ic, ic->streams[i], istream_spec)) > 0) {
- meta_in = &ic->streams[i]->metadata;
- break;
- } else if (ret < 0)
- exit_program(1);
- }
- if (!meta_in) {
- av_log(NULL, AV_LOG_FATAL, "Stream specifier %s does not match any streams.\n", istream_spec);
- exit_program(1);
- }
- }
-
- if (type_out == 's') {
- for (i = 0; i < oc->nb_streams; i++) {
- if ((ret = check_stream_specifier(oc, oc->streams[i], ostream_spec)) > 0) {
- meta_out = &oc->streams[i]->metadata;
- av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
- } else if (ret < 0)
- exit_program(1);
- }
- } else
- av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
-
- return 0;
-}
-
-static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
-{
- const AVCodecDescriptor *desc;
- const char *codec_string = encoder ? "encoder" : "decoder";
- AVCodec *codec;
-
- codec = encoder ?
- avcodec_find_encoder_by_name(name) :
- avcodec_find_decoder_by_name(name);
-
- if (!codec && (desc = avcodec_descriptor_get_by_name(name))) {
- codec = encoder ? avcodec_find_encoder(desc->id) :
- avcodec_find_decoder(desc->id);
- if (codec)
- av_log(NULL, AV_LOG_VERBOSE, "Matched %s '%s' for codec '%s'.\n",
- codec_string, codec->name, desc->name);
- }
-
- if (!codec) {
- av_log(NULL, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name);
- exit_program(1);
- }
- if (codec->type != type) {
- av_log(NULL, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name);
- exit_program(1);
- }
- return codec;
-}
-
-static AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st)
-{
- char *codec_name = NULL;
-
- MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
- if (codec_name) {
- AVCodec *codec = find_codec_or_die(codec_name, st->codec->codec_type, 0);
- st->codec->codec_id = codec->id;
- return codec;
- } else
- return avcodec_find_decoder(st->codec->codec_id);
-}
-
-/* Add all the streams from the given input file to the global
- * list of input streams. */
-static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
-{
- int i;
-
- for (i = 0; i < ic->nb_streams; i++) {
- AVStream *st = ic->streams[i];
- AVCodecContext *dec = st->codec;
- InputStream *ist = av_mallocz(sizeof(*ist));
- char *framerate = NULL;
-
- if (!ist)
- exit_program(1);
-
- GROW_ARRAY(input_streams, nb_input_streams);
- input_streams[nb_input_streams - 1] = ist;
-
- ist->st = st;
- ist->file_index = nb_input_files;
- ist->discard = 1;
- st->discard = AVDISCARD_ALL;
-
- ist->ts_scale = 1.0;
- MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
-
- ist->dec = choose_decoder(o, ic, st);
- ist->opts = filter_codec_opts(o->g->codec_opts, ist->st->codec->codec_id, ic, st, ist->dec);
-
- switch (dec->codec_type) {
- case AVMEDIA_TYPE_VIDEO:
- ist->resample_height = dec->height;
- ist->resample_width = dec->width;
- ist->resample_pix_fmt = dec->pix_fmt;
-
- MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
- if (framerate && av_parse_video_rate(&ist->framerate,
- framerate) < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error parsing framerate %s.\n",
- framerate);
- exit_program(1);
- }
-
- break;
- case AVMEDIA_TYPE_AUDIO:
- guess_input_channel_layout(ist);
-
- ist->resample_sample_fmt = dec->sample_fmt;
- ist->resample_sample_rate = dec->sample_rate;
- ist->resample_channels = dec->channels;
- ist->resample_channel_layout = dec->channel_layout;
-
- break;
- case AVMEDIA_TYPE_DATA:
- case AVMEDIA_TYPE_SUBTITLE:
- case AVMEDIA_TYPE_ATTACHMENT:
- case AVMEDIA_TYPE_UNKNOWN:
- break;
- default:
- abort();
- }
- }
-}
-
-static void assert_file_overwrite(const char *filename)
-{
- if (file_overwrite && file_skip) {
- fprintf(stderr, "Error, both -y and -n supplied. Exiting.\n");
- exit_program(1);
- }
-
- if (!file_overwrite &&
- (strchr(filename, ':') == NULL || filename[1] == ':' ||
- av_strstart(filename, "file:", NULL))) {
- if (avio_check(filename, 0) == 0) {
- if (!using_stdin && !file_skip) {
- fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
- fflush(stderr);
- if (!read_yesno()) {
- fprintf(stderr, "Not overwriting - exiting\n");
- exit_program(1);
- }
- }
- else {
- fprintf(stderr,"File '%s' already exists. Exiting.\n", filename);
- exit_program(1);
- }
- }
- }
-}
-
-static void dump_attachment(AVStream *st, const char *filename)
-{
- int ret;
- AVIOContext *out = NULL;
- AVDictionaryEntry *e;
-
- if (!st->codec->extradata_size) {
- av_log(NULL, AV_LOG_WARNING, "No extradata to dump in stream #%d:%d.\n",
- nb_input_files - 1, st->index);
- return;
- }
- if (!*filename && (e = av_dict_get(st->metadata, "filename", NULL, 0)))
- filename = e->value;
- if (!*filename) {
- av_log(NULL, AV_LOG_FATAL, "No filename specified and no 'filename' tag"
- "in stream #%d:%d.\n", nb_input_files - 1, st->index);
- exit_program(1);
- }
-
- assert_file_overwrite(filename);
-
- if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n",
- filename);
- exit_program(1);
- }
-
- avio_write(out, st->codec->extradata, st->codec->extradata_size);
- avio_flush(out);
- avio_close(out);
-}
-
-static int open_input_file(OptionsContext *o, const char *filename)
-{
- InputFile *f;
- AVFormatContext *ic;
- AVInputFormat *file_iformat = NULL;
- int err, i, ret;
- int64_t timestamp;
- uint8_t buf[128];
- AVDictionary **opts;
- AVDictionary *unused_opts = NULL;
- AVDictionaryEntry *e = NULL;
- int orig_nb_streams; // number of streams before avformat_find_stream_info
-
- if (o->format) {
- if (!(file_iformat = av_find_input_format(o->format))) {
- av_log(NULL, AV_LOG_FATAL, "Unknown input format: '%s'\n", o->format);
- exit_program(1);
- }
- }
-
- if (!strcmp(filename, "-"))
- filename = "pipe:";
-
- using_stdin |= !strncmp(filename, "pipe:", 5) ||
- !strcmp(filename, "/dev/stdin");
-
- /* get default parameters from command line */
- ic = avformat_alloc_context();
- if (!ic) {
- print_error(filename, AVERROR(ENOMEM));
- exit_program(1);
- }
- if (o->nb_audio_sample_rate) {
- snprintf(buf, sizeof(buf), "%d", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i);
- av_dict_set(&o->g->format_opts, "sample_rate", buf, 0);
- }
- if (o->nb_audio_channels) {
- /* because we set audio_channels based on both the "ac" and
- * "channel_layout" options, we need to check that the specified
- * demuxer actually has the "channels" option before setting it */
- if (file_iformat && file_iformat->priv_class &&
- av_opt_find(&file_iformat->priv_class, "channels", NULL, 0,
- AV_OPT_SEARCH_FAKE_OBJ)) {
- snprintf(buf, sizeof(buf), "%d",
- o->audio_channels[o->nb_audio_channels - 1].u.i);
- av_dict_set(&o->g->format_opts, "channels", buf, 0);
- }
- }
- if (o->nb_frame_rates) {
- /* set the format-level framerate option;
- * this is important for video grabbers, e.g. x11 */
- if (file_iformat && file_iformat->priv_class &&
- av_opt_find(&file_iformat->priv_class, "framerate", NULL, 0,
- AV_OPT_SEARCH_FAKE_OBJ)) {
- av_dict_set(&o->g->format_opts, "framerate",
- o->frame_rates[o->nb_frame_rates - 1].u.str, 0);
- }
- }
- if (o->nb_frame_sizes) {
- av_dict_set(&o->g->format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0);
- }
- if (o->nb_frame_pix_fmts)
- av_dict_set(&o->g->format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0);
-
- ic->flags |= AVFMT_FLAG_NONBLOCK;
- ic->interrupt_callback = int_cb;
-
- /* open the input file with generic libav function */
- err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts);
- if (err < 0) {
- print_error(filename, err);
- exit_program(1);
- }
- assert_avoptions(o->g->format_opts);
-
- /* apply forced codec ids */
- for (i = 0; i < ic->nb_streams; i++)
- choose_decoder(o, ic, ic->streams[i]);
-
- /* Set AVCodecContext options for avformat_find_stream_info */
- opts = setup_find_stream_info_opts(ic, o->g->codec_opts);
- orig_nb_streams = ic->nb_streams;
-
- /* If not enough info to get the stream parameters, we decode the
- first frames to get it. (used in mpeg case for example) */
- ret = avformat_find_stream_info(ic, opts);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "%s: could not find codec parameters\n", filename);
- avformat_close_input(&ic);
- exit_program(1);
- }
-
- timestamp = (o->start_time == AV_NOPTS_VALUE) ? 0 : o->start_time;
- /* add the stream start time */
- if (ic->start_time != AV_NOPTS_VALUE)
- timestamp += ic->start_time;
-
- /* if seeking requested, we execute it */
- if (o->start_time != AV_NOPTS_VALUE) {
- ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
- if (ret < 0) {
- av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
- filename, (double)timestamp / AV_TIME_BASE);
- }
- }
-
- /* update the current parameters so that they match the one of the input stream */
- add_input_streams(o, ic);
-
- /* dump the file content */
- av_dump_format(ic, nb_input_files, filename, 0);
-
- GROW_ARRAY(input_files, nb_input_files);
- f = av_mallocz(sizeof(*f));
- if (!f)
- exit_program(1);
- input_files[nb_input_files - 1] = f;
-
- f->ctx = ic;
- f->ist_index = nb_input_streams - ic->nb_streams;
- f->start_time = o->start_time;
- f->recording_time = o->recording_time;
- f->ts_offset = o->input_ts_offset - (copy_ts ? 0 : timestamp);
- f->nb_streams = ic->nb_streams;
- f->rate_emu = o->rate_emu;
- f->accurate_seek = o->accurate_seek;
-
- /* check if all codec options have been used */
- unused_opts = strip_specifiers(o->g->codec_opts);
- for (i = f->ist_index; i < nb_input_streams; i++) {
- e = NULL;
- while ((e = av_dict_get(input_streams[i]->opts, "", e,
- AV_DICT_IGNORE_SUFFIX)))
- av_dict_set(&unused_opts, e->key, NULL, 0);
- }
-
- e = NULL;
- while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
- const AVClass *class = avcodec_get_class();
- const AVOption *option = av_opt_find(&class, e->key, NULL, 0,
- AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
- if (!option)
- continue;
- if (!(option->flags & AV_OPT_FLAG_DECODING_PARAM)) {
- av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
- "input file #%d (%s) is not a decoding option.\n", e->key,
- option->help ? option->help : "", nb_input_files - 1,
- filename);
- exit_program(1);
- }
-
- av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
- "input file #%d (%s) has not been used for any stream. The most "
- "likely reason is either wrong type (e.g. a video option with "
- "no video streams) or that it is a private option of some decoder "
- "which was not actually used for any stream.\n", e->key,
- option->help ? option->help : "", nb_input_files - 1, filename);
- }
- av_dict_free(&unused_opts);
-
- for (i = 0; i < o->nb_dump_attachment; i++) {
- int j;
-
- for (j = 0; j < ic->nb_streams; j++) {
- AVStream *st = ic->streams[j];
-
- if (check_stream_specifier(ic, st, o->dump_attachment[i].specifier) == 1)
- dump_attachment(st, o->dump_attachment[i].u.str);
- }
- }
-
- for (i = 0; i < orig_nb_streams; i++)
- av_dict_free(&opts[i]);
- av_freep(&opts);
-
- return 0;
-}
-
-static uint8_t *get_line(AVIOContext *s)
-{
- AVIOContext *line;
- uint8_t *buf;
- char c;
-
- if (avio_open_dyn_buf(&line) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Could not alloc buffer for reading preset.\n");
- exit_program(1);
- }
-
- while ((c = avio_r8(s)) && c != '\n')
- avio_w8(line, c);
- avio_w8(line, 0);
- avio_close_dyn_buf(line, &buf);
-
- return buf;
-}
-
-static int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s)
-{
- int i, ret = 1;
- char filename[1000];
- const char *base[3] = { getenv("AVCONV_DATADIR"),
- getenv("HOME"),
- AVCONV_DATADIR,
- };
-
- for (i = 0; i < FF_ARRAY_ELEMS(base) && ret; i++) {
- if (!base[i])
- continue;
- if (codec_name) {
- snprintf(filename, sizeof(filename), "%s%s/%s-%s.avpreset", base[i],
- i != 1 ? "" : "/.avconv", codec_name, preset_name);
- ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
- }
- if (ret) {
- snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i],
- i != 1 ? "" : "/.avconv", preset_name);
- ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
- }
- }
- return ret;
-}
-
-static void choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *ost)
-{
- char *codec_name = NULL;
-
- MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st);
- if (!codec_name) {
- ost->st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename,
- NULL, ost->st->codec->codec_type);
- ost->enc = avcodec_find_encoder(ost->st->codec->codec_id);
- } else if (!strcmp(codec_name, "copy"))
- ost->stream_copy = 1;
- else {
- ost->enc = find_codec_or_die(codec_name, ost->st->codec->codec_type, 1);
- ost->st->codec->codec_id = ost->enc->id;
- }
-}
-
-static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type)
-{
- OutputStream *ost;
- AVStream *st = avformat_new_stream(oc, NULL);
- int idx = oc->nb_streams - 1, ret = 0;
- char *bsf = NULL, *next, *codec_tag = NULL;
- AVBitStreamFilterContext *bsfc, *bsfc_prev = NULL;
- double qscale = -1;
-
- if (!st) {
- av_log(NULL, AV_LOG_FATAL, "Could not alloc stream.\n");
- exit_program(1);
- }
-
- if (oc->nb_streams - 1 < o->nb_streamid_map)
- st->id = o->streamid_map[oc->nb_streams - 1];
-
- GROW_ARRAY(output_streams, nb_output_streams);
- if (!(ost = av_mallocz(sizeof(*ost))))
- exit_program(1);
- output_streams[nb_output_streams - 1] = ost;
-
- ost->file_index = nb_output_files - 1;
- ost->index = idx;
- ost->st = st;
- st->codec->codec_type = type;
- choose_encoder(o, oc, ost);
- if (ost->enc) {
- AVIOContext *s = NULL;
- char *buf = NULL, *arg = NULL, *preset = NULL;
-
- ost->opts = filter_codec_opts(o->g->codec_opts, ost->enc->id, oc, st, ost->enc);
-
- MATCH_PER_STREAM_OPT(presets, str, preset, oc, st);
- if (preset && (!(ret = get_preset_file_2(preset, ost->enc->name, &s)))) {
- do {
- buf = get_line(s);
- if (!buf[0] || buf[0] == '#') {
- av_free(buf);
- continue;
- }
- if (!(arg = strchr(buf, '='))) {
- av_log(NULL, AV_LOG_FATAL, "Invalid line found in the preset file.\n");
- exit_program(1);
- }
- *arg++ = 0;
- av_dict_set(&ost->opts, buf, arg, AV_DICT_DONT_OVERWRITE);
- av_free(buf);
- } while (!s->eof_reached);
- avio_close(s);
- }
- if (ret) {
- av_log(NULL, AV_LOG_FATAL,
- "Preset %s specified for stream %d:%d, but could not be opened.\n",
- preset, ost->file_index, ost->index);
- exit_program(1);
- }
- } else {
- ost->opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL);
- }
-
- avcodec_get_context_defaults3(st->codec, ost->enc);
- st->codec->codec_type = type; // XXX hack, avcodec_get_context_defaults2() sets type to unknown for stream copy
-
- ost->max_frames = INT64_MAX;
- MATCH_PER_STREAM_OPT(max_frames, i64, ost->max_frames, oc, st);
-
- MATCH_PER_STREAM_OPT(bitstream_filters, str, bsf, oc, st);
- while (bsf) {
- if (next = strchr(bsf, ','))
- *next++ = 0;
- if (!(bsfc = av_bitstream_filter_init(bsf))) {
- av_log(NULL, AV_LOG_FATAL, "Unknown bitstream filter %s\n", bsf);
- exit_program(1);
- }
- if (bsfc_prev)
- bsfc_prev->next = bsfc;
- else
- ost->bitstream_filters = bsfc;
-
- bsfc_prev = bsfc;
- bsf = next;
- }
-
- MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st);
- if (codec_tag) {
- uint32_t tag = strtol(codec_tag, &next, 0);
- if (*next)
- tag = AV_RL32(codec_tag);
- st->codec->codec_tag = tag;
- }
-
- MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st);
- if (qscale >= 0) {
- st->codec->flags |= CODEC_FLAG_QSCALE;
- st->codec->global_quality = FF_QP2LAMBDA * qscale;
- }
-
- if (oc->oformat->flags & AVFMT_GLOBALHEADER)
- st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
- av_opt_get_int(o->g->sws_opts, "sws_flags", 0, &ost->sws_flags);
-
- av_dict_copy(&ost->resample_opts, o->g->resample_opts, 0);
-
- ost->pix_fmts[0] = ost->pix_fmts[1] = AV_PIX_FMT_NONE;
- ost->last_mux_dts = AV_NOPTS_VALUE;
-
- return ost;
-}
-
-static void parse_matrix_coeffs(uint16_t *dest, const char *str)
-{
- int i;
- const char *p = str;
- for (i = 0;; i++) {
- dest[i] = atoi(p);
- if (i == 63)
- break;
- p = strchr(p, ',');
- if (!p) {
- av_log(NULL, AV_LOG_FATAL, "Syntax error in matrix \"%s\" at coeff %d\n", str, i);
- exit_program(1);
- }
- p++;
- }
-}
-
-/* read file contents into a string */
-static uint8_t *read_file(const char *filename)
-{
- AVIOContext *pb = NULL;
- AVIOContext *dyn_buf = NULL;
- int ret = avio_open(&pb, filename, AVIO_FLAG_READ);
- uint8_t buf[1024], *str;
-
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error opening file %s.\n", filename);
- return NULL;
- }
-
- ret = avio_open_dyn_buf(&dyn_buf);
- if (ret < 0) {
- avio_closep(&pb);
- return NULL;
- }
- while ((ret = avio_read(pb, buf, sizeof(buf))) > 0)
- avio_write(dyn_buf, buf, ret);
- avio_w8(dyn_buf, 0);
- avio_closep(&pb);
-
- ret = avio_close_dyn_buf(dyn_buf, &str);
- if (ret < 0)
- return NULL;
- return str;
-}
-
-static char *get_ost_filters(OptionsContext *o, AVFormatContext *oc,
- OutputStream *ost)
-{
- AVStream *st = ost->st;
- char *filter = NULL, *filter_script = NULL;
-
- MATCH_PER_STREAM_OPT(filter_scripts, str, filter_script, oc, st);
- MATCH_PER_STREAM_OPT(filters, str, filter, oc, st);
-
- if (filter_script && filter) {
- av_log(NULL, AV_LOG_ERROR, "Both -filter and -filter_script set for "
- "output stream #%d:%d.\n", nb_output_files, st->index);
- exit_program(1);
- }
-
- if (filter_script)
- return read_file(filter_script);
- else if (filter)
- return av_strdup(filter);
-
- return av_strdup(st->codec->codec_type == AVMEDIA_TYPE_VIDEO ?
- "null" : "anull");
-}
-
-static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
-{
- AVStream *st;
- OutputStream *ost;
- AVCodecContext *video_enc;
- char *frame_aspect_ratio = NULL;
-
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO);
- st = ost->st;
- video_enc = st->codec;
-
- MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);
- if (frame_aspect_ratio)
- ost->frame_aspect_ratio = parse_frame_aspect_ratio(frame_aspect_ratio);
-
- if (!ost->stream_copy) {
- const char *p = NULL;
- char *frame_rate = NULL, *frame_size = NULL;
- char *frame_pix_fmt = NULL;
- char *intra_matrix = NULL, *inter_matrix = NULL;
- int do_pass = 0;
- int i;
-
- MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);
- if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate);
- exit_program(1);
- }
-
- MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
- if (frame_size && av_parse_video_size(&video_enc->width, &video_enc->height, frame_size) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
- exit_program(1);
- }
-
- MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st);
- if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == AV_PIX_FMT_NONE) {
- av_log(NULL, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", frame_pix_fmt);
- exit_program(1);
- }
- st->sample_aspect_ratio = video_enc->sample_aspect_ratio;
-
- MATCH_PER_STREAM_OPT(intra_matrices, str, intra_matrix, oc, st);
- if (intra_matrix) {
- if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64))) {
- av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for intra matrix.\n");
- exit_program(1);
- }
- parse_matrix_coeffs(video_enc->intra_matrix, intra_matrix);
- }
- MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st);
- if (inter_matrix) {
- if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64))) {
- av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for inter matrix.\n");
- exit_program(1);
- }
- parse_matrix_coeffs(video_enc->inter_matrix, inter_matrix);
- }
-
- MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st);
- for (i = 0; p; i++) {
- int start, end, q;
- int e = sscanf(p, "%d,%d,%d", &start, &end, &q);
- if (e != 3) {
- av_log(NULL, AV_LOG_FATAL, "error parsing rc_override\n");
- exit_program(1);
- }
- video_enc->rc_override =
- av_realloc(video_enc->rc_override,
- sizeof(RcOverride) * (i + 1));
- video_enc->rc_override[i].start_frame = start;
- video_enc->rc_override[i].end_frame = end;
- if (q > 0) {
- video_enc->rc_override[i].qscale = q;
- video_enc->rc_override[i].quality_factor = 1.0;
- }
- else {
- video_enc->rc_override[i].qscale = 0;
- video_enc->rc_override[i].quality_factor = -q/100.0;
- }
- p = strchr(p, '/');
- if (p) p++;
- }
- video_enc->rc_override_count = i;
- video_enc->intra_dc_precision = intra_dc_precision - 8;
-
- /* two pass mode */
- MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
- if (do_pass) {
- if (do_pass == 1) {
- video_enc->flags |= CODEC_FLAG_PASS1;
- } else {
- video_enc->flags |= CODEC_FLAG_PASS2;
- }
- }
-
- MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st);
- if (ost->logfile_prefix &&
- !(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
- exit_program(1);
-
- MATCH_PER_STREAM_OPT(forced_key_frames, str, ost->forced_keyframes, oc, st);
- if (ost->forced_keyframes)
- ost->forced_keyframes = av_strdup(ost->forced_keyframes);
-
- MATCH_PER_STREAM_OPT(force_fps, i, ost->force_fps, oc, st);
-
- ost->top_field_first = -1;
- MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
-
-
- ost->avfilter = get_ost_filters(o, oc, ost);
- if (!ost->avfilter)
- exit_program(1);
- } else {
- MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st);
- }
-
- return ost;
-}
-
-static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
-{
- AVStream *st;
- OutputStream *ost;
- AVCodecContext *audio_enc;
-
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO);
- st = ost->st;
-
- audio_enc = st->codec;
- audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
-
- if (!ost->stream_copy) {
- char *sample_fmt = NULL;
-
- MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st);
-
- MATCH_PER_STREAM_OPT(sample_fmts, str, sample_fmt, oc, st);
- if (sample_fmt &&
- (audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) {
- av_log(NULL, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt);
- exit_program(1);
- }
-
- MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
-
- ost->avfilter = get_ost_filters(o, oc, ost);
- if (!ost->avfilter)
- exit_program(1);
- }
-
- return ost;
-}
-
-static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc)
-{
- OutputStream *ost;
-
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA);
- if (!ost->stream_copy) {
- av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
- exit_program(1);
- }
-
- return ost;
-}
-
-static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc)
-{
- OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT);
- ost->stream_copy = 1;
- ost->finished = 1;
- return ost;
-}
-
-static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc)
-{
- AVStream *st;
- OutputStream *ost;
- AVCodecContext *subtitle_enc;
-
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE);
- st = ost->st;
- subtitle_enc = st->codec;
-
- subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
-
- return ost;
-}
-
-/* arg format is "output-stream-index:streamid-value". */
-static int opt_streamid(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- int idx;
- char *p;
- char idx_str[16];
-
- av_strlcpy(idx_str, arg, sizeof(idx_str));
- p = strchr(idx_str, ':');
- if (!p) {
- av_log(NULL, AV_LOG_FATAL,
- "Invalid value '%s' for option '%s', required syntax is 'index:value'\n",
- arg, opt);
- exit_program(1);
- }
- *p++ = '\0';
- idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, INT_MAX);
- o->streamid_map = grow_array(o->streamid_map, sizeof(*o->streamid_map), &o->nb_streamid_map, idx+1);
- o->streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX);
- return 0;
-}
-
-static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata)
-{
- AVFormatContext *is = ifile->ctx;
- AVFormatContext *os = ofile->ctx;
- AVChapter **tmp;
- int i;
-
- tmp = av_realloc(os->chapters, sizeof(*os->chapters) * (is->nb_chapters + os->nb_chapters));
- if (!tmp)
- return AVERROR(ENOMEM);
- os->chapters = tmp;
-
- for (i = 0; i < is->nb_chapters; i++) {
- AVChapter *in_ch = is->chapters[i], *out_ch;
- int64_t start_time = (ofile->start_time == AV_NOPTS_VALUE) ? 0 : ofile->start_time;
- int64_t ts_off = av_rescale_q(start_time - ifile->ts_offset,
- AV_TIME_BASE_Q, in_ch->time_base);
- int64_t rt = (ofile->recording_time == INT64_MAX) ? INT64_MAX :
- av_rescale_q(ofile->recording_time, AV_TIME_BASE_Q, in_ch->time_base);
-
-
- if (in_ch->end < ts_off)
- continue;
- if (rt != INT64_MAX && in_ch->start > rt + ts_off)
- break;
-
- out_ch = av_mallocz(sizeof(AVChapter));
- if (!out_ch)
- return AVERROR(ENOMEM);
-
- out_ch->id = in_ch->id;
- out_ch->time_base = in_ch->time_base;
- out_ch->start = FFMAX(0, in_ch->start - ts_off);
- out_ch->end = FFMIN(rt, in_ch->end - ts_off);
-
- if (copy_metadata)
- av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
-
- os->chapters[os->nb_chapters++] = out_ch;
- }
- return 0;
-}
-
-static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
- AVFormatContext *oc)
-{
- OutputStream *ost;
-
- switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
- ofilter->out_tmp->pad_idx)) {
- case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc); break;
- case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc); break;
- default:
- av_log(NULL, AV_LOG_FATAL, "Only video and audio filters are supported "
- "currently.\n");
- exit_program(1);
- }
-
- ost->source_index = -1;
- ost->filter = ofilter;
-
- ofilter->ost = ost;
-
- if (ost->stream_copy) {
- av_log(NULL, AV_LOG_ERROR, "Streamcopy requested for output stream %d:%d, "
- "which is fed from a complex filtergraph. Filtering and streamcopy "
- "cannot be used together.\n", ost->file_index, ost->index);
- exit_program(1);
- }
-
- if (configure_output_filter(ofilter->graph, ofilter, ofilter->out_tmp) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error configuring filter.\n");
- exit_program(1);
- }
- avfilter_inout_free(&ofilter->out_tmp);
-}
-
-static int configure_complex_filters(void)
-{
- int i, ret = 0;
-
- for (i = 0; i < nb_filtergraphs; i++)
- if (!filtergraphs[i]->graph &&
- (ret = configure_filtergraph(filtergraphs[i])) < 0)
- return ret;
- return 0;
-}
-
-static int open_output_file(OptionsContext *o, const char *filename)
-{
- AVFormatContext *oc;
- int i, j, err;
- AVOutputFormat *file_oformat;
- OutputFile *of;
- OutputStream *ost;
- InputStream *ist;
- AVDictionary *unused_opts = NULL;
- AVDictionaryEntry *e = NULL;
-
- if (configure_complex_filters() < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error configuring filters.\n");
- exit_program(1);
- }
-
- GROW_ARRAY(output_files, nb_output_files);
- of = av_mallocz(sizeof(*of));
- if (!of)
- exit_program(1);
- output_files[nb_output_files - 1] = of;
-
- of->ost_index = nb_output_streams;
- of->recording_time = o->recording_time;
- of->start_time = o->start_time;
- of->limit_filesize = o->limit_filesize;
- of->shortest = o->shortest;
- av_dict_copy(&of->opts, o->g->format_opts, 0);
-
- if (!strcmp(filename, "-"))
- filename = "pipe:";
-
- oc = avformat_alloc_context();
- if (!oc) {
- print_error(filename, AVERROR(ENOMEM));
- exit_program(1);
- }
- of->ctx = oc;
- if (o->recording_time != INT64_MAX)
- oc->duration = o->recording_time;
-
- if (o->format) {
- file_oformat = av_guess_format(o->format, NULL, NULL);
- if (!file_oformat) {
- av_log(NULL, AV_LOG_FATAL, "Requested output format '%s' is not a suitable output format\n", o->format);
- exit_program(1);
- }
- } else {
- file_oformat = av_guess_format(NULL, filename, NULL);
- if (!file_oformat) {
- av_log(NULL, AV_LOG_FATAL, "Unable to find a suitable output format for '%s'\n",
- filename);
- exit_program(1);
- }
- }
-
- oc->oformat = file_oformat;
- oc->interrupt_callback = int_cb;
- av_strlcpy(oc->filename, filename, sizeof(oc->filename));
-
- /* create streams for all unlabeled output pads */
- for (i = 0; i < nb_filtergraphs; i++) {
- FilterGraph *fg = filtergraphs[i];
- for (j = 0; j < fg->nb_outputs; j++) {
- OutputFilter *ofilter = fg->outputs[j];
-
- if (!ofilter->out_tmp || ofilter->out_tmp->name)
- continue;
-
- switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
- ofilter->out_tmp->pad_idx)) {
- case AVMEDIA_TYPE_VIDEO: o->video_disable = 1; break;
- case AVMEDIA_TYPE_AUDIO: o->audio_disable = 1; break;
- case AVMEDIA_TYPE_SUBTITLE: o->subtitle_disable = 1; break;
- }
- init_output_filter(ofilter, o, oc);
- }
- }
-
- if (!o->nb_stream_maps) {
- /* pick the "best" stream of each type */
-#define NEW_STREAM(type, index)\
- if (index >= 0) {\
- ost = new_ ## type ## _stream(o, oc);\
- ost->source_index = index;\
- ost->sync_ist = input_streams[index];\
- input_streams[index]->discard = 0;\
- input_streams[index]->st->discard = AVDISCARD_NONE;\
- }
-
- /* video: highest resolution */
- if (!o->video_disable && oc->oformat->video_codec != AV_CODEC_ID_NONE) {
- int area = 0, idx = -1;
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
- if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
- ist->st->codec->width * ist->st->codec->height > area) {
- area = ist->st->codec->width * ist->st->codec->height;
- idx = i;
- }
- }
- NEW_STREAM(video, idx);
- }
-
- /* audio: most channels */
- if (!o->audio_disable && oc->oformat->audio_codec != AV_CODEC_ID_NONE) {
- int channels = 0, idx = -1;
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
- if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
- ist->st->codec->channels > channels) {
- channels = ist->st->codec->channels;
- idx = i;
- }
- }
- NEW_STREAM(audio, idx);
- }
-
- /* subtitles: pick first */
- if (!o->subtitle_disable && oc->oformat->subtitle_codec != AV_CODEC_ID_NONE) {
- for (i = 0; i < nb_input_streams; i++)
- if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
- NEW_STREAM(subtitle, i);
- break;
- }
- }
- /* do something with data? */
- } else {
- for (i = 0; i < o->nb_stream_maps; i++) {
- StreamMap *map = &o->stream_maps[i];
-
- if (map->disabled)
- continue;
-
- if (map->linklabel) {
- FilterGraph *fg;
- OutputFilter *ofilter = NULL;
- int j, k;
-
- for (j = 0; j < nb_filtergraphs; j++) {
- fg = filtergraphs[j];
- for (k = 0; k < fg->nb_outputs; k++) {
- AVFilterInOut *out = fg->outputs[k]->out_tmp;
- if (out && !strcmp(out->name, map->linklabel)) {
- ofilter = fg->outputs[k];
- goto loop_end;
- }
- }
- }
-loop_end:
- if (!ofilter) {
- av_log(NULL, AV_LOG_FATAL, "Output with label '%s' does not exist "
- "in any defined filter graph.\n", map->linklabel);
- exit_program(1);
- }
- init_output_filter(ofilter, o, oc);
- } else {
- ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index];
- switch (ist->st->codec->codec_type) {
- case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc); break;
- case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc); break;
- case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(o, oc); break;
- case AVMEDIA_TYPE_DATA: ost = new_data_stream(o, oc); break;
- case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc); break;
- default:
- av_log(NULL, AV_LOG_FATAL, "Cannot map stream #%d:%d - unsupported type.\n",
- map->file_index, map->stream_index);
- exit_program(1);
- }
-
- ost->source_index = input_files[map->file_index]->ist_index + map->stream_index;
- ost->sync_ist = input_streams[input_files[map->sync_file_index]->ist_index +
- map->sync_stream_index];
- ist->discard = 0;
- ist->st->discard = AVDISCARD_NONE;
- }
- }
- }
-
- /* handle attached files */
- for (i = 0; i < o->nb_attachments; i++) {
- AVIOContext *pb;
- uint8_t *attachment;
- const char *p;
- int64_t len;
-
- if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n",
- o->attachments[i]);
- exit_program(1);
- }
- if ((len = avio_size(pb)) <= 0) {
- av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
- o->attachments[i]);
- exit_program(1);
- }
- if (!(attachment = av_malloc(len))) {
- av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n",
- o->attachments[i]);
- exit_program(1);
- }
- avio_read(pb, attachment, len);
-
- ost = new_attachment_stream(o, oc);
- ost->stream_copy = 0;
- ost->source_index = -1;
- ost->attachment_filename = o->attachments[i];
- ost->st->codec->extradata = attachment;
- ost->st->codec->extradata_size = len;
-
- p = strrchr(o->attachments[i], '/');
- av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE);
- avio_close(pb);
- }
-
- /* check if all codec options have been used */
- unused_opts = strip_specifiers(o->g->codec_opts);
- for (i = of->ost_index; i < nb_output_streams; i++) {
- e = NULL;
- while ((e = av_dict_get(output_streams[i]->opts, "", e,
- AV_DICT_IGNORE_SUFFIX)))
- av_dict_set(&unused_opts, e->key, NULL, 0);
- }
-
- e = NULL;
- while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
- const AVClass *class = avcodec_get_class();
- const AVOption *option = av_opt_find(&class, e->key, NULL, 0,
- AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
- if (!option)
- continue;
- if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) {
- av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
- "output file #%d (%s) is not an encoding option.\n", e->key,
- option->help ? option->help : "", nb_output_files - 1,
- filename);
- exit_program(1);
- }
-
- av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
- "output file #%d (%s) has not been used for any stream. The most "
- "likely reason is either wrong type (e.g. a video option with "
- "no video streams) or that it is a private option of some encoder "
- "which was not actually used for any stream.\n", e->key,
- option->help ? option->help : "", nb_output_files - 1, filename);
- }
- av_dict_free(&unused_opts);
-
- /* check filename in case of an image number is expected */
- if (oc->oformat->flags & AVFMT_NEEDNUMBER) {
- if (!av_filename_number_test(oc->filename)) {
- print_error(oc->filename, AVERROR(EINVAL));
- exit_program(1);
- }
- }
-
- if (!(oc->oformat->flags & AVFMT_NOFILE)) {
- /* test if it already exists to avoid losing precious files */
- assert_file_overwrite(filename);
-
- /* open the file */
- if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,
- &oc->interrupt_callback,
- &of->opts)) < 0) {
- print_error(filename, err);
- exit_program(1);
- }
- }
-
- if (o->mux_preload) {
- uint8_t buf[64];
- snprintf(buf, sizeof(buf), "%d", (int)(o->mux_preload*AV_TIME_BASE));
- av_dict_set(&of->opts, "preload", buf, 0);
- }
- oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
- oc->flags |= AVFMT_FLAG_NONBLOCK;
-
- /* copy metadata */
- for (i = 0; i < o->nb_metadata_map; i++) {
- char *p;
- int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
-
- if (in_file_index >= nb_input_files) {
- av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
- exit_program(1);
- }
- copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc,
- in_file_index >= 0 ?
- input_files[in_file_index]->ctx : NULL, o);
- }
-
- /* copy chapters */
- if (o->chapters_input_file >= nb_input_files) {
- if (o->chapters_input_file == INT_MAX) {
- /* copy chapters from the first input file that has them*/
- o->chapters_input_file = -1;
- for (i = 0; i < nb_input_files; i++)
- if (input_files[i]->ctx->nb_chapters) {
- o->chapters_input_file = i;
- break;
- }
- } else {
- av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n",
- o->chapters_input_file);
- exit_program(1);
- }
- }
- if (o->chapters_input_file >= 0)
- copy_chapters(input_files[o->chapters_input_file], of,
- !o->metadata_chapters_manual);
-
- /* copy global metadata by default */
- if (!o->metadata_global_manual && nb_input_files)
- av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata,
- AV_DICT_DONT_OVERWRITE);
- if (!o->metadata_streams_manual)
- for (i = of->ost_index; i < nb_output_streams; i++) {
- InputStream *ist;
- if (output_streams[i]->source_index < 0) /* this is true e.g. for attached files */
- continue;
- ist = input_streams[output_streams[i]->source_index];
- av_dict_copy(&output_streams[i]->st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
- }
-
- /* process manually set metadata */
- for (i = 0; i < o->nb_metadata; i++) {
- AVDictionary **m;
- char type, *val;
- const char *stream_spec;
- int index = 0, j, ret;
-
- val = strchr(o->metadata[i].u.str, '=');
- if (!val) {
- av_log(NULL, AV_LOG_FATAL, "No '=' character in metadata string %s.\n",
- o->metadata[i].u.str);
- exit_program(1);
- }
- *val++ = 0;
-
- parse_meta_type(o->metadata[i].specifier, &type, &index, &stream_spec);
- if (type == 's') {
- for (j = 0; j < oc->nb_streams; j++) {
- if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {
- av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);
- } else if (ret < 0)
- exit_program(1);
- }
- }
- else {
- switch (type) {
- case 'g':
- m = &oc->metadata;
- break;
- case 'c':
- if (index < 0 || index >= oc->nb_chapters) {
- av_log(NULL, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
- exit_program(1);
- }
- m = &oc->chapters[index]->metadata;
- break;
- default:
- av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
- exit_program(1);
- }
- av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
- }
- }
-
- return 0;
-}
-
-static int opt_target(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- enum { PAL, NTSC, FILM, UNKNOWN } norm = UNKNOWN;
- static const char *const frame_rates[] = { "25", "30000/1001", "24000/1001" };
-
- if (!strncmp(arg, "pal-", 4)) {
- norm = PAL;
- arg += 4;
- } else if (!strncmp(arg, "ntsc-", 5)) {
- norm = NTSC;
- arg += 5;
- } else if (!strncmp(arg, "film-", 5)) {
- norm = FILM;
- arg += 5;
- } else {
- /* Try to determine PAL/NTSC by peeking in the input files */
- if (nb_input_files) {
- int i, j, fr;
- for (j = 0; j < nb_input_files; j++) {
- for (i = 0; i < input_files[j]->nb_streams; i++) {
- AVCodecContext *c = input_files[j]->ctx->streams[i]->codec;
- if (c->codec_type != AVMEDIA_TYPE_VIDEO)
- continue;
- fr = c->time_base.den * 1000 / c->time_base.num;
- if (fr == 25000) {
- norm = PAL;
- break;
- } else if ((fr == 29970) || (fr == 23976)) {
- norm = NTSC;
- break;
- }
- }
- if (norm != UNKNOWN)
- break;
- }
- }
- if (norm != UNKNOWN)
- av_log(NULL, AV_LOG_INFO, "Assuming %s for target.\n", norm == PAL ? "PAL" : "NTSC");
- }
-
- if (norm == UNKNOWN) {
- av_log(NULL, AV_LOG_FATAL, "Could not determine norm (PAL/NTSC/NTSC-Film) for target.\n");
- av_log(NULL, AV_LOG_FATAL, "Please prefix target with \"pal-\", \"ntsc-\" or \"film-\",\n");
- av_log(NULL, AV_LOG_FATAL, "or set a framerate with \"-r xxx\".\n");
- exit_program(1);
- }
-
- if (!strcmp(arg, "vcd")) {
- opt_video_codec(o, "c:v", "mpeg1video");
- opt_audio_codec(o, "c:a", "mp2");
- parse_option(o, "f", "vcd", options);
-
- parse_option(o, "s", norm == PAL ? "352x288" : "352x240", options);
- parse_option(o, "r", frame_rates[norm], options);
- opt_default(NULL, "g", norm == PAL ? "15" : "18");
-
- opt_default(NULL, "b", "1150000");
- opt_default(NULL, "maxrate", "1150000");
- opt_default(NULL, "minrate", "1150000");
- opt_default(NULL, "bufsize", "327680"); // 40*1024*8;
-
- opt_default(NULL, "b:a", "224000");
- parse_option(o, "ar", "44100", options);
- parse_option(o, "ac", "2", options);
-
- opt_default(NULL, "packetsize", "2324");
- opt_default(NULL, "muxrate", "1411200"); // 2352 * 75 * 8;
-
- /* We have to offset the PTS, so that it is consistent with the SCR.
- SCR starts at 36000, but the first two packs contain only padding
- and the first pack from the other stream, respectively, may also have
- been written before.
- So the real data starts at SCR 36000+3*1200. */
- o->mux_preload = (36000 + 3 * 1200) / 90000.0; // 0.44
- } else if (!strcmp(arg, "svcd")) {
-
- opt_video_codec(o, "c:v", "mpeg2video");
- opt_audio_codec(o, "c:a", "mp2");
- parse_option(o, "f", "svcd", options);
-
- parse_option(o, "s", norm == PAL ? "480x576" : "480x480", options);
- parse_option(o, "r", frame_rates[norm], options);
- opt_default(NULL, "g", norm == PAL ? "15" : "18");
-
- opt_default(NULL, "b", "2040000");
- opt_default(NULL, "maxrate", "2516000");
- opt_default(NULL, "minrate", "0"); // 1145000;
- opt_default(NULL, "bufsize", "1835008"); // 224*1024*8;
- opt_default(NULL, "flags", "+scan_offset");
-
-
- opt_default(NULL, "b:a", "224000");
- parse_option(o, "ar", "44100", options);
-
- opt_default(NULL, "packetsize", "2324");
-
- } else if (!strcmp(arg, "dvd")) {
-
- opt_video_codec(o, "c:v", "mpeg2video");
- opt_audio_codec(o, "c:a", "ac3");
- parse_option(o, "f", "dvd", options);
-
- parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
- parse_option(o, "r", frame_rates[norm], options);
- opt_default(NULL, "g", norm == PAL ? "15" : "18");
-
- opt_default(NULL, "b", "6000000");
- opt_default(NULL, "maxrate", "9000000");
- opt_default(NULL, "minrate", "0"); // 1500000;
- opt_default(NULL, "bufsize", "1835008"); // 224*1024*8;
-
- opt_default(NULL, "packetsize", "2048"); // from www.mpucoder.com: DVD sectors contain 2048 bytes of data, this is also the size of one pack.
- opt_default(NULL, "muxrate", "10080000"); // from mplex project: data_rate = 1260000. mux_rate = data_rate * 8
-
- opt_default(NULL, "b:a", "448000");
- parse_option(o, "ar", "48000", options);
-
- } else if (!strncmp(arg, "dv", 2)) {
-
- parse_option(o, "f", "dv", options);
-
- parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
- parse_option(o, "pix_fmt", !strncmp(arg, "dv50", 4) ? "yuv422p" :
- norm == PAL ? "yuv420p" : "yuv411p", options);
- parse_option(o, "r", frame_rates[norm], options);
-
- parse_option(o, "ar", "48000", options);
- parse_option(o, "ac", "2", options);
-
- } else {
- av_log(NULL, AV_LOG_ERROR, "Unknown target: %s\n", arg);
- return AVERROR(EINVAL);
- }
- return 0;
-}
-
-static int opt_vstats_file(void *optctx, const char *opt, const char *arg)
-{
- av_free (vstats_filename);
- vstats_filename = av_strdup (arg);
- return 0;
-}
-
-static int opt_vstats(void *optctx, const char *opt, const char *arg)
-{
- char filename[40];
- time_t today2 = time(NULL);
- struct tm *today = localtime(&today2);
-
- snprintf(filename, sizeof(filename), "vstats_%02d%02d%02d.log", today->tm_hour, today->tm_min,
- today->tm_sec);
- return opt_vstats_file(NULL, opt, filename);
-}
-
-static int opt_video_frames(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "frames:v", arg, options);
-}
-
-static int opt_audio_frames(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "frames:a", arg, options);
-}
-
-static int opt_data_frames(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "frames:d", arg, options);
-}
-
-static int opt_video_tag(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "tag:v", arg, options);
-}
-
-static int opt_audio_tag(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "tag:a", arg, options);
-}
-
-static int opt_subtitle_tag(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "tag:s", arg, options);
-}
-
-static int opt_video_filters(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "filter:v", arg, options);
-}
-
-static int opt_audio_filters(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "filter:a", arg, options);
-}
-
-static int opt_vsync(void *optctx, const char *opt, const char *arg)
-{
- if (!av_strcasecmp(arg, "cfr")) video_sync_method = VSYNC_CFR;
- else if (!av_strcasecmp(arg, "vfr")) video_sync_method = VSYNC_VFR;
- else if (!av_strcasecmp(arg, "passthrough")) video_sync_method = VSYNC_PASSTHROUGH;
-
- if (video_sync_method == VSYNC_AUTO)
- video_sync_method = parse_number_or_die("vsync", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);
- return 0;
-}
-
-static int opt_channel_layout(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- char layout_str[32];
- char *stream_str;
- char *ac_str;
- int ret, channels, ac_str_size;
- uint64_t layout;
-
- layout = av_get_channel_layout(arg);
- if (!layout) {
- av_log(NULL, AV_LOG_ERROR, "Unknown channel layout: %s\n", arg);
- return AVERROR(EINVAL);
- }
- snprintf(layout_str, sizeof(layout_str), "%"PRIu64, layout);
- ret = opt_default(NULL, opt, layout_str);
- if (ret < 0)
- return ret;
-
- /* set 'ac' option based on channel layout */
- channels = av_get_channel_layout_nb_channels(layout);
- snprintf(layout_str, sizeof(layout_str), "%d", channels);
- stream_str = strchr(opt, ':');
- ac_str_size = 3 + (stream_str ? strlen(stream_str) : 0);
- ac_str = av_mallocz(ac_str_size);
- if (!ac_str)
- return AVERROR(ENOMEM);
- av_strlcpy(ac_str, "ac", 3);
- if (stream_str)
- av_strlcat(ac_str, stream_str, ac_str_size);
- ret = parse_option(o, ac_str, layout_str, options);
- av_free(ac_str);
-
- return ret;
-}
-
-static int opt_audio_qscale(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "q:a", arg, options);
-}
-
-static int opt_filter_complex(void *optctx, const char *opt, const char *arg)
-{
- GROW_ARRAY(filtergraphs, nb_filtergraphs);
- if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
- return AVERROR(ENOMEM);
- filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
- filtergraphs[nb_filtergraphs - 1]->graph_desc = av_strdup(arg);
- if (!filtergraphs[nb_filtergraphs - 1]->graph_desc)
- return AVERROR(ENOMEM);
- return 0;
-}
-
-static int opt_filter_complex_script(void *optctx, const char *opt, const char *arg)
-{
- uint8_t *graph_desc = read_file(arg);
- if (!graph_desc)
- return AVERROR(EINVAL);
-
- GROW_ARRAY(filtergraphs, nb_filtergraphs);
- if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
- return AVERROR(ENOMEM);
- filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
- filtergraphs[nb_filtergraphs - 1]->graph_desc = graph_desc;
- return 0;
-}
-
-void show_help_default(const char *opt, const char *arg)
-{
- /* per-file options have at least one of those set */
- const int per_file = OPT_SPEC | OPT_OFFSET | OPT_PERFILE;
- int show_advanced = 0, show_avoptions = 0;
-
- if (opt && *opt) {
- if (!strcmp(opt, "long"))
- show_advanced = 1;
- else if (!strcmp(opt, "full"))
- show_advanced = show_avoptions = 1;
- else
- av_log(NULL, AV_LOG_ERROR, "Unknown help option '%s'.\n", opt);
- }
-
- show_usage();
-
- printf("Getting help:\n"
- " -h -- print basic options\n"
- " -h long -- print more options\n"
- " -h full -- print all options (including all format and codec specific options, very long)\n"
- " See man %s for detailed description of the options.\n"
- "\n", program_name);
-
- show_help_options(options, "Print help / information / capabilities:",
- OPT_EXIT, 0, 0);
-
- show_help_options(options, "Global options (affect whole program "
- "instead of just one file:",
- 0, per_file | OPT_EXIT | OPT_EXPERT, 0);
- if (show_advanced)
- show_help_options(options, "Advanced global options:", OPT_EXPERT,
- per_file | OPT_EXIT, 0);
-
- show_help_options(options, "Per-file main options:", 0,
- OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE |
- OPT_EXIT, per_file);
- if (show_advanced)
- show_help_options(options, "Advanced per-file options:",
- OPT_EXPERT, OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE, per_file);
-
- show_help_options(options, "Video options:",
- OPT_VIDEO, OPT_EXPERT | OPT_AUDIO, 0);
- if (show_advanced)
- show_help_options(options, "Advanced Video options:",
- OPT_EXPERT | OPT_VIDEO, OPT_AUDIO, 0);
-
- show_help_options(options, "Audio options:",
- OPT_AUDIO, OPT_EXPERT | OPT_VIDEO, 0);
- if (show_advanced)
- show_help_options(options, "Advanced Audio options:",
- OPT_EXPERT | OPT_AUDIO, OPT_VIDEO, 0);
- show_help_options(options, "Subtitle options:",
- OPT_SUBTITLE, 0, 0);
- printf("\n");
-
- if (show_avoptions) {
- int flags = AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM;
- show_help_children(avcodec_get_class(), flags);
- show_help_children(avformat_get_class(), flags);
- show_help_children(sws_get_class(), flags);
- show_help_children(avfilter_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM);
- }
-}
-
-void show_usage(void)
-{
- printf("Hyper fast Audio and Video encoder\n");
- printf("usage: %s [options] [[infile options] -i infile]... {[outfile options] outfile}...\n", program_name);
- printf("\n");
-}
-
-enum OptGroup {
- GROUP_OUTFILE,
- GROUP_INFILE,
-};
-
-static const OptionGroupDef groups[] = {
- [GROUP_OUTFILE] = { "output file", NULL, OPT_OUTPUT },
- [GROUP_INFILE] = { "input file", "i", OPT_INPUT },
-};
-
-static int open_files(OptionGroupList *l, const char *inout,
- int (*open_file)(OptionsContext*, const char*))
-{
- int i, ret;
-
- for (i = 0; i < l->nb_groups; i++) {
- OptionGroup *g = &l->groups[i];
- OptionsContext o;
-
- init_options(&o);
- o.g = g;
-
- ret = parse_optgroup(&o, g);
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error parsing options for %s file "
- "%s.\n", inout, g->arg);
- return ret;
- }
-
- av_log(NULL, AV_LOG_DEBUG, "Opening an %s file: %s.\n", inout, g->arg);
- ret = open_file(&o, g->arg);
- uninit_options(&o);
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error opening %s file %s.\n",
- inout, g->arg);
- return ret;
- }
- av_log(NULL, AV_LOG_DEBUG, "Successfully opened the file.\n");
- }
-
- return 0;
-}
-
-int avconv_parse_options(int argc, char **argv)
-{
- OptionParseContext octx;
- uint8_t error[128];
- int ret;
-
- memset(&octx, 0, sizeof(octx));
-
- /* split the commandline into an internal representation */
- ret = split_commandline(&octx, argc, argv, options, groups,
- FF_ARRAY_ELEMS(groups));
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error splitting the argument list: ");
- goto fail;
- }
-
- /* apply global options */
- ret = parse_optgroup(NULL, &octx.global_opts);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error parsing global options: ");
- goto fail;
- }
-
- /* open input files */
- ret = open_files(&octx.groups[GROUP_INFILE], "input", open_input_file);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error opening input files: ");
- goto fail;
- }
-
- /* open output files */
- ret = open_files(&octx.groups[GROUP_OUTFILE], "output", open_output_file);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error opening output files: ");
- goto fail;
- }
-
-fail:
- uninit_parse_context(&octx);
- if (ret < 0) {
- av_strerror(ret, error, sizeof(error));
- av_log(NULL, AV_LOG_FATAL, "%s\n", error);
- }
- return ret;
-}
-
-#define OFFSET(x) offsetof(OptionsContext, x)
-const OptionDef options[] = {
- /* main options */
-#include "cmdutils_common_opts.h"
- { "f", HAS_ARG | OPT_STRING | OPT_OFFSET |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(format) },
- "force format", "fmt" },
- { "y", OPT_BOOL, { &file_overwrite },
- "overwrite output files" },
- { "n", OPT_BOOL, { &file_skip },
- "never overwrite output files" },
- { "c", HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(codec_names) },
- "codec name", "codec" },
- { "codec", HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(codec_names) },
- "codec name", "codec" },
- { "pre", HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(presets) },
- "preset name", "preset" },
- { "map", HAS_ARG | OPT_EXPERT | OPT_PERFILE |
- OPT_OUTPUT, { .func_arg = opt_map },
- "set input stream mapping",
- "[-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]]" },
- { "map_metadata", HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(metadata_map) },
- "set metadata information of outfile from infile",
- "outfile[,metadata]:infile[,metadata]" },
- { "map_chapters", HAS_ARG | OPT_INT | OPT_EXPERT | OPT_OFFSET |
- OPT_OUTPUT, { .off = OFFSET(chapters_input_file) },
- "set chapters mapping", "input_file_index" },
- { "t", HAS_ARG | OPT_TIME | OPT_OFFSET |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(recording_time) },
- "record or transcode \"duration\" seconds of audio/video",
- "duration" },
- { "fs", HAS_ARG | OPT_INT64 | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(limit_filesize) },
- "set the limit file size in bytes", "limit_size" },
- { "ss", HAS_ARG | OPT_TIME | OPT_OFFSET |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(start_time) },
- "set the start time offset", "time_off" },
- { "accurate_seek", OPT_BOOL | OPT_OFFSET | OPT_EXPERT |
- OPT_INPUT, { .off = OFFSET(accurate_seek) },
- "enable/disable accurate seeking with -ss" },
- { "itsoffset", HAS_ARG | OPT_TIME | OPT_OFFSET |
- OPT_EXPERT | OPT_INPUT, { .off = OFFSET(input_ts_offset) },
- "set the input ts offset", "time_off" },
- { "itsscale", HAS_ARG | OPT_DOUBLE | OPT_SPEC |
- OPT_EXPERT | OPT_INPUT, { .off = OFFSET(ts_scale) },
- "set the input ts scale", "scale" },
- { "metadata", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(metadata) },
- "add metadata", "string=string" },
- { "dframes", HAS_ARG | OPT_PERFILE | OPT_EXPERT |
- OPT_OUTPUT, { .func_arg = opt_data_frames },
- "set the number of data frames to record", "number" },
- { "benchmark", OPT_BOOL | OPT_EXPERT, { &do_benchmark },
- "add timings for benchmarking" },
- { "timelimit", HAS_ARG | OPT_EXPERT, { .func_arg = opt_timelimit },
- "set max runtime in seconds", "limit" },
- { "dump", OPT_BOOL | OPT_EXPERT, { &do_pkt_dump },
- "dump each input packet" },
- { "hex", OPT_BOOL | OPT_EXPERT, { &do_hex_dump },
- "when dumping packets, also dump the payload" },
- { "re", OPT_BOOL | OPT_EXPERT | OPT_OFFSET |
- OPT_INPUT, { .off = OFFSET(rate_emu) },
- "read input at native frame rate", "" },
- { "target", HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_target },
- "specify target file type (\"vcd\", \"svcd\", \"dvd\","
- " \"dv\", \"dv50\", \"pal-vcd\", \"ntsc-svcd\", ...)", "type" },
- { "vsync", HAS_ARG | OPT_EXPERT, { opt_vsync },
- "video sync method", "" },
- { "async", HAS_ARG | OPT_INT | OPT_EXPERT, { &audio_sync_method },
- "audio sync method", "" },
- { "adrift_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &audio_drift_threshold },
- "audio drift threshold", "threshold" },
- { "copyts", OPT_BOOL | OPT_EXPERT, { &copy_ts },
- "copy timestamps" },
- { "copytb", OPT_BOOL | OPT_EXPERT, { &copy_tb },
- "copy input stream time base when stream copying" },
- { "shortest", OPT_BOOL | OPT_EXPERT | OPT_OFFSET |
- OPT_OUTPUT, { .off = OFFSET(shortest) },
- "finish encoding within shortest input" },
- { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &dts_delta_threshold },
- "timestamp discontinuity delta threshold", "threshold" },
- { "xerror", OPT_BOOL | OPT_EXPERT, { &exit_on_error },
- "exit on error", "error" },
- { "copyinkf", OPT_BOOL | OPT_EXPERT | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(copy_initial_nonkeyframes) },
- "copy initial non-keyframes" },
- { "frames", OPT_INT64 | HAS_ARG | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(max_frames) },
- "set the number of frames to record", "number" },
- { "tag", OPT_STRING | HAS_ARG | OPT_SPEC |
- OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(codec_tags) },
- "force codec tag/fourcc", "fourcc/tag" },
- { "q", HAS_ARG | OPT_EXPERT | OPT_DOUBLE |
- OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(qscale) },
- "use fixed quality scale (VBR)", "q" },
- { "qscale", HAS_ARG | OPT_EXPERT | OPT_DOUBLE |
- OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(qscale) },
- "use fixed quality scale (VBR)", "q" },
- { "filter", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filters) },
- "set stream filterchain", "filter_list" },
- { "filter_script", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filter_scripts) },
- "read stream filtergraph description from a file", "filename" },
- { "filter_complex", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex },
- "create a complex filtergraph", "graph_description" },
- { "filter_complex_script", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex_script },
- "read complex filtergraph description from a file", "filename" },
- { "stats", OPT_BOOL, { &print_stats },
- "print progress report during encoding", },
- { "attach", HAS_ARG | OPT_PERFILE | OPT_EXPERT |
- OPT_OUTPUT, { .func_arg = opt_attach },
- "add an attachment to the output file", "filename" },
- { "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_EXPERT | OPT_INPUT, { .off = OFFSET(dump_attachment) },
- "extract an attachment into a file", "filename" },
-
- /* video options */
- { "vframes", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_frames },
- "set the number of video frames to record", "number" },
- { "r", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_rates) },
- "set frame rate (Hz value, fraction or abbreviation)", "rate" },
- { "s", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_sizes) },
- "set frame size (WxH or abbreviation)", "size" },
- { "aspect", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(frame_aspect_ratios) },
- "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" },
- { "pix_fmt", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_pix_fmts) },
- "set pixel format", "format" },
- { "vn", OPT_VIDEO | OPT_BOOL | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(video_disable) },
- "disable video" },
- { "vdt", OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT , { &video_discard },
- "discard threshold", "n" },
- { "rc_override", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(rc_overrides) },
- "rate control override for specific intervals", "override" },
- { "vcodec", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_INPUT |
- OPT_OUTPUT, { .func_arg = opt_video_codec },
- "force video codec ('copy' to copy stream)", "codec" },
- { "pass", OPT_VIDEO | HAS_ARG | OPT_SPEC | OPT_INT | OPT_OUTPUT, { .off = OFFSET(pass) },
- "select the pass number (1 or 2)", "n" },
- { "passlogfile", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(passlogfiles) },
- "select two pass log file name prefix", "prefix" },
- { "vstats", OPT_VIDEO | OPT_EXPERT , { &opt_vstats },
- "dump video coding statistics to file" },
- { "vstats_file", OPT_VIDEO | HAS_ARG | OPT_EXPERT , { opt_vstats_file },
- "dump video coding statistics to file", "file" },
- { "vf", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_filters },
- "video filters", "filter list" },
- { "intra_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(intra_matrices) },
- "specify intra matrix coeffs", "matrix" },
- { "inter_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(inter_matrices) },
- "specify inter matrix coeffs", "matrix" },
- { "top", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_INT| OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(top_field_first) },
- "top=1/bottom=0/auto=-1 field first", "" },
- { "dc", OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT , { &intra_dc_precision },
- "intra_dc_precision", "precision" },
- { "vtag", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
- OPT_OUTPUT, { .func_arg = opt_video_tag },
- "force video tag/fourcc", "fourcc/tag" },
- { "qphist", OPT_VIDEO | OPT_BOOL | OPT_EXPERT , { &qp_hist },
- "show QP histogram" },
- { "force_fps", OPT_VIDEO | OPT_BOOL | OPT_EXPERT | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(force_fps) },
- "force the selected framerate, disable the best supported framerate selection" },
- { "streamid", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
- OPT_OUTPUT, { .func_arg = opt_streamid },
- "set the value of an outfile streamid", "streamIndex:value" },
- { "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
- OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(forced_key_frames) },
- "force key frames at specified timestamps", "timestamps" },
-
- /* audio options */
- { "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_frames },
- "set the number of audio frames to record", "number" },
- { "aq", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_qscale },
- "set audio quality (codec-specific)", "quality", },
- { "ar", OPT_AUDIO | HAS_ARG | OPT_INT | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(audio_sample_rate) },
- "set audio sampling rate (in Hz)", "rate" },
- { "ac", OPT_AUDIO | HAS_ARG | OPT_INT | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(audio_channels) },
- "set number of audio channels", "channels" },
- { "an", OPT_AUDIO | OPT_BOOL | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(audio_disable) },
- "disable audio" },
- { "acodec", OPT_AUDIO | HAS_ARG | OPT_PERFILE |
- OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_audio_codec },
- "force audio codec ('copy' to copy stream)", "codec" },
- { "atag", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
- OPT_OUTPUT, { .func_arg = opt_audio_tag },
- "force audio tag/fourcc", "fourcc/tag" },
- { "vol", OPT_AUDIO | HAS_ARG | OPT_INT, { &audio_volume },
- "change audio volume (256=normal)" , "volume" },
- { "sample_fmt", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_SPEC |
- OPT_STRING | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(sample_fmts) },
- "set sample format", "format" },
- { "channel_layout", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
- OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_channel_layout },
- "set channel layout", "layout" },
- { "af", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_filters },
- "audio filters", "filter list" },
-
- /* subtitle options */
- { "sn", OPT_SUBTITLE | OPT_BOOL | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(subtitle_disable) },
- "disable subtitle" },
- { "scodec", OPT_SUBTITLE | HAS_ARG | OPT_PERFILE | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_subtitle_codec },
- "force subtitle codec ('copy' to copy stream)", "codec" },
- { "stag", OPT_SUBTITLE | HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_subtitle_tag }
- , "force subtitle tag/fourcc", "fourcc/tag" },
-
- /* grab options */
- { "isync", OPT_BOOL | OPT_EXPERT, { &input_sync }, "this option is deprecated and does nothing", "" },
-
- /* muxer options */
- { "muxdelay", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_max_delay) },
- "set the maximum demux-decode delay", "seconds" },
- { "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_preload) },
- "set the initial demux-decode delay", "seconds" },
-
- { "bsf", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(bitstream_filters) },
- "A comma-separated list of bitstream filters", "bitstream_filters" },
-
- /* data codec support */
- { "dcodec", HAS_ARG | OPT_DATA | OPT_PERFILE | OPT_EXPERT | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_data_codec },
- "force data codec ('copy' to copy stream)", "codec" },
-
- { NULL, },
-};
diff --git a/avplay.c b/avplay.c
deleted file mode 100644
index 00becbe..0000000
--- a/avplay.c
+++ b/dev/null
@@ -1,2976 +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 "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() 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) 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 debug_mv = 0;
-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 autoexit;
-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() - 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() / 1000000.0;
- }
-}
-
-/* get the current external clock value */
-static double get_external_clock(VideoState *is)
-{
- int64_t ti;
- ti = av_gettime();
- 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() / 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() / 1000000.0;
- }
- is->video_current_pts_drift = is->video_current_pts - av_gettime() / 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() / 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();
- 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];
-
- /* 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 == NULL) {
- 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() / 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 = avcodec_alloc_frame()))
- return AVERROR(ENOMEM);
- } else
- avcodec_get_frame_defaults(is->frame);
-
- 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();
-
- 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;
-
- 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->debug_mv = debug_mv;
- 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 ||
- avcodec_open2(avctx, codec, &opts) < 0)
- return -1;
- if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
- av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
- return AVERROR_OPTION_NOT_FOUND;
- }
-
- /* 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");
- return -1;
- }
- 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());
- return -1;
- }
- 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;
- }
- return 0;
-}
-
-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;
- avcodec_free_frame(&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);
- if (err < 0) {
- fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
- ret = -1;
- goto fail;
- }
- for (i = 0; i < orig_nb_streams; i++)
- av_dict_free(&opts[i]);
- av_freep(&opts);
-
- 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 (autoexit) {
- 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);
- }
-}
-
-/* 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_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 int opt_vismv(void *optctx, const char *opt, const char *arg)
-{
- debug_mv = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX);
- 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", "" },
- { "vismv", HAS_ARG | OPT_EXPERT, { .func_arg = opt_vismv }, "visualize motion vectors", "" },
- { "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" },
- { "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_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 c7b3d39..0000000
--- a/avprobe.c
+++ b/dev/null
@@ -1,969 +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 && 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);
- 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/avserver.c b/avserver.c
deleted file mode 100644
index 56bcda9..0000000
--- a/avserver.c
+++ b/dev/null
@@ -1,4685 +0,0 @@
-/*
- * Multiple format streaming server
- * Copyright (c) 2000, 2001, 2002 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"
-#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, avserver _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/avio_internal.h"
-#include "libavformat/internal.h"
-#include "libavformat/url.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>
-#include <unistd.h>
-#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"
-
-const char program_name[] = "avserver";
-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 *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 MAX_STREAMS 20
-
-#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 FFStream *stream;
- /* -1 is invalid stream */
- int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
- int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
- int switch_pending;
- AVFormatContext fmt_ctx; /* instance of FFStream 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[MAX_STREAMS];
-
- /* RTP/UDP specific */
- URLContext *rtp_handles[MAX_STREAMS];
-
- /* RTP/TCP specific */
- struct HTTPContext *rtsp_c;
- uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
-} HTTPContext;
-
-/* each generated stream is described here */
-enum StreamType {
- STREAM_TYPE_LIVE,
- STREAM_TYPE_STATUS,
- STREAM_TYPE_REDIRECT,
-};
-
-enum IPAddressAction {
- IP_ALLOW = 1,
- IP_DENY,
-};
-
-typedef struct IPAddressACL {
- struct IPAddressACL *next;
- enum IPAddressAction action;
- /* These are in host order */
- struct in_addr first;
- struct in_addr last;
-} IPAddressACL;
-
-/* description of each stream of the avserver.conf file */
-typedef struct FFStream {
- enum StreamType stream_type;
- char filename[1024]; /* stream filename */
- struct FFStream *feed; /* feed we are using (can be null if
- coming from file) */
- AVDictionary *in_opts; /* input parameters */
- AVInputFormat *ifmt; /* if non NULL, force input format */
- AVOutputFormat *fmt;
- IPAddressACL *acl;
- char dynamic_acl[1024];
- int nb_streams;
- int prebuffer; /* Number of millseconds early to start */
- int64_t max_time; /* Number of milliseconds to run */
- int send_on_key;
- AVStream *streams[MAX_STREAMS];
- int feed_streams[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 */
- char author[512];
- char title[512];
- char copyright[512];
- char comment[512];
- pid_t pid; /* of avconv process */
- time_t pid_start; /* of avconv process */
- char **child_argv;
- struct FFStream *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 FFStream *next_feed;
-} FFStream;
-
-typedef struct FeedData {
- long long data_count;
- float avg_frame_size; /* frame size averaged over last frames with exponential mean */
-} FeedData;
-
-static struct sockaddr_in my_http_addr;
-static struct sockaddr_in my_rtsp_addr;
-
-static char logfilename[1024];
-static HTTPContext *first_http_ctx;
-static FFStream *first_feed; /* contains only feeds */
-static FFStream *first_stream; /* contains all streams, including feeds */
-
-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_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
-static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
-
-/* SDP handling */
-static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
- struct in_addr my_ip);
-
-/* RTP handling */
-static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
- FFStream *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 const char *config_filename;
-
-static int avserver_debug;
-static int no_launch;
-static int need_to_start_children;
-
-/* maximum number of simultaneous HTTP connections */
-static unsigned int nb_max_http_connections = 2000;
-static unsigned int nb_max_connections = 5;
-static unsigned int nb_connections;
-
-static uint64_t max_bandwidth = 1000;
-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 int64_t ffm_read_write_index(int fd)
-{
- uint8_t buf[8];
-
- lseek(fd, 8, SEEK_SET);
- 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;
- lseek(fd, 8, SEEK_SET);
- 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;
-}
-
-/* FIXME: make avserver 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;
-}
-
-static char *ctime1(char *buf2)
-{
- time_t ti;
- char *p;
-
- ti = time(NULL);
- p = ctime(&ti);
- strcpy(buf2, p);
- 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);
- 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(FFStream *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;
-
- av_strlcpy(pathname, my_program_name, sizeof(pathname));
-
- slash = strrchr(pathname, '/');
- if (!slash)
- slash = pathname;
- else
- slash++;
- strcpy(slash, "avconv");
-
- 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 (!avserver_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;
- setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
-
- 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;
- }
- ff_socket_nonblock(server_fd, 1);
-
- return server_fd;
-}
-
-/* start all multicast streams */
-static void start_multicast(void)
-{
- FFStream *stream;
- char session_id[32];
- HTTPContext *rtp_c;
- struct sockaddr_in dest_addr;
- int default_port, stream_index;
-
- default_port = 6000;
- for(stream = first_stream; stream != NULL; stream = stream->next) {
- if (stream->is_multicast) {
- /* open the RTP connection */
- snprintf(session_id, sizeof(session_id), "%08x%08x",
- av_lfg_get(&random_state), av_lfg_get(&random_state));
-
- /* 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);
- }
- }
-
- /* change state to send data */
- 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, delay1;
- struct pollfd *poll_table, *poll_entry;
- HTTPContext *c, *c_next;
-
- if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
- http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
- return -1;
- }
-
- if (my_http_addr.sin_port) {
- server_fd = socket_open_listen(&my_http_addr);
- if (server_fd < 0)
- return -1;
- }
-
- if (my_rtsp_addr.sin_port) {
- rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
- if (rtsp_server_fd < 0)
- return -1;
- }
-
- if (!rtsp_server_fd && !server_fd) {
- http_log("HTTP and RTSP disabled.\n");
- return -1;
- }
-
- http_log("AVserver started.\n");
-
- start_children(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 != NULL) {
- 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 avserver is doing the timing, we work by
- looking at which packet need to be sent every
- 10 ms */
- delay1 = 10; /* one tick wait XXX: 10 ms assumed */
- if (delay1 < delay)
- delay = delay1;
- }
- 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))
- return -1;
- } while (ret < 0);
-
- cur_time = av_gettime() / 1000;
-
- if (need_to_start_children) {
- need_to_start_children = 0;
- start_children(first_feed);
- }
-
- /* now handle the events */
- for(c = first_http_ctx; c != NULL; c = c_next) {
- c_next = c->next;
- if (handle_connection(c) < 0) {
- /* close and free the connection */
- log_connection(c);
- 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[300];
- 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 %d, and this exceeds the limit of %d.</p>\r\n"
- "</body></html>\r\n",
- nb_connections, nb_max_connections);
- send(fd, buffer, len, 0);
-}
-
-
-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;
- }
- ff_socket_nonblock(fd, 1);
-
- if (nb_connections >= 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_free(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) != NULL) {
- 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 != NULL; 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_free(ctx->streams[0]);
- av_free(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_free(ctx->streams[i]);
-
- 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_free(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)) {
- /* error : close connection */
- av_freep(&c->pb_buffer);
- return -1;
- }
- } 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 sets 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)) {
- av_freep(&c->pb_buffer);
- 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)) {
- /* error : close connection */
- av_freep(&c->pb_buffer);
- return -1;
- }
- } 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;
-}
-
-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(FFStream *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;
- FFStream *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;
-}
-
-/* XXX: factorize in utils.c ? */
-/* XXX: take care with different space meaning */
-static void skip_spaces(const char **pp)
-{
- const char *p;
- p = *pp;
- while (*p == ' ' || *p == '\t')
- p++;
- *pp = p;
-}
-
-static void get_word(char *buf, int buf_size, const char **pp)
-{
- const char *p;
- char *q;
-
- p = *pp;
- skip_spaces(&p);
- 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 void 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;
-}
-
-static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
- const char *p, const char *filename, int line_num)
-{
- char arg[1024];
- IPAddressACL acl;
- int errors = 0;
-
- 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++;
- }
-
- get_arg(arg, sizeof(arg), &p);
-
- if (resolve_host(&acl.first, arg) != 0) {
- fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
- filename, line_num, arg);
- errors++;
- } else
- acl.last = acl.first;
-
- get_arg(arg, sizeof(arg), &p);
-
- if (arg[0]) {
- if (resolve_host(&acl.last, arg) != 0) {
- fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
- filename, line_num, arg);
- errors++;
- }
- }
-
- if (!errors) {
- IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
- IPAddressACL **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;
- }
- }
-}
-
-
-static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
-{
- FILE* f;
- char line[1024];
- char cmd[1024];
- IPAddressACL *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(IPAddressACL));
-
- /* 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;
- get_arg(cmd, sizeof(cmd), &p);
-
- if (!av_strcasecmp(cmd, "ACL"))
- parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
- }
- fclose(f);
- return acl;
-}
-
-
-static void free_acl_list(IPAddressACL *in_acl)
-{
- IPAddressACL *pacl,*pacl2;
-
- pacl = in_acl;
- while(pacl) {
- pacl2 = pacl;
- pacl = pacl->next;
- av_freep(pacl2);
- }
-}
-
-static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
-{
- enum IPAddressAction last_action = IP_DENY;
- IPAddressACL *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(FFStream *stream, HTTPContext *c)
-{
- int ret = 0;
- IPAddressACL *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 filenames */
-static void compute_real_filename(char *filename, int max_size)
-{
- char file1[1024];
- char file2[1024];
- char *p;
- FFStream *stream;
-
- /* compute filename by matching without the file extensions */
- av_strlcpy(file1, filename, sizeof(file1));
- p = strrchr(file1, '.');
- if (p)
- *p = '\0';
- for(stream = first_stream; stream != NULL; 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;
- FFStream *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 (avserver_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 = first_stream;
- while (stream != NULL) {
- if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
- break;
- stream = stream->next;
- }
- if (stream == NULL) {
- 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;
- q += 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);
- /* 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 && max_bandwidth < current_bandwidth) {
- c->http_error = 503;
- q = c->buffer;
- q += 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, max_bandwidth);
- /* 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:
- q += 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 avserver -->\r\n"
- "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
- "</ASX>\r\n", hostbuf, filename, info);
- break;
- case REDIR_RAM:
- q += 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 avserver\r\n"
- "http://%s/%s%s\r\n", hostbuf, filename, info);
- break;
- case REDIR_ASF:
- q += 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);
- break;
- case REDIR_RTSP:
- {
- char hostname[256], *p;
- /* extract only hostname */
- av_strlcpy(hostname, hostbuf, sizeof(hostname));
- p = strrchr(hostname, ':');
- if (p)
- *p = '\0';
- q += 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(my_rtsp_addr.sin_port), filename);
- }
- break;
- case REDIR_SDP:
- {
- uint8_t *sdp_data;
- int sdp_data_size;
- socklen_t len;
- struct sockaddr_in my_addr;
-
- q += snprintf(q, c->buffer_size,
- "HTTP/1.0 200 OK\r\n"
- "Content-type: application/sdp\r\n"
- "\r\n");
-
- len = sizeof(my_addr);
- getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
-
- /* 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 in 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 */
- q = c->buffer;
- q += snprintf(q, q - (char *) 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";
- q += snprintf(q, q - (char *) 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);
-
- q += snprintf(q, q - (char *) 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);
- }
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
-
- /* 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;
- q += 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);
- /* 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;
- FFStream *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: %s\r\n", "text/html");
- 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 = first_stream;
- while (stream != NULL) {
- 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 = first_stream;
- while (stream != NULL) {
- 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) && !defined(CONFIG_NOCUTILS)
- {
- 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, "%10s %64s", 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, nb_max_connections);
-
- avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
- current_bandwidth, 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 != NULL) {
- 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 i, ret;
- int64_t stream_pos;
-
- /* find file name */
- if (c->stream->feed) {
- strcpy(input_filename, c->stream->feed->feed_filename);
- /* compute position (absolute time) */
- if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
- if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
- 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);
- /* compute position (relative time) */
- if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
- if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
- return ret;
- } else
- stream_pos = 0;
- }
- if (input_filename[0] == '\0')
- return -1;
-
- /* open stream */
- if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
- http_log("could not open %s: %d\n", input_filename, ret);
- return -1;
- }
- s->flags |= AVFMT_FLAG_GENPTS;
- c->fmt_in = s;
- if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
- http_log("Could not find stream info '%s'\n", input_filename);
- avformat_close_input(&s);
- return -1;
- }
-
- /* choose stream as clock source (we favorize 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:
- memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
- av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
- av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
- av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
- av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
-
- c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
-
- 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 FFStream 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;
- c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
- AVStream, not in codec */
- }
- /* 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 Libav
- * Try to set it use configuration option
- */
- c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
-
- if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
- http_log("Error writing output header\n");
- return -1;
- }
- 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 stream (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 (av_write_frame(ctx, &pkt) < 0) {
- http_log("Error writing frame to output\n");
- 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 connection) */
-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;
-
- if (c->stream->feed_opened)
- return -1;
-
- /* Don't permit writing to this one */
- if (c->stream->readonly)
- return -1;
-
- /* open feed */
- fd = open(c->stream->feed_filename, O_RDWR);
- if (fd < 0) {
- http_log("Error opening feeder file: %s\n", strerror(errno));
- return -1;
- }
- 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) {
- http_log("Error truncating feed file: %s\n", strerror(errno));
- return -1;
- }
- } else {
- if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
- http_log("Error reading write index from feed file: %s\n", strerror(errno));
- return -1;
- }
- }
-
- 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) {
- FFStream *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 */
- lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
- 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 != NULL; 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_free(pb);
- goto fail;
- }
-
- /* Now we have the actual streams */
- if (s->nb_streams != feed->nb_streams) {
- avformat_close_input(&s);
- av_free(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_free(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 != NULL; 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];
-
- switch(error_number) {
- case RTSP_STATUS_OK:
- str = "OK";
- break;
- case RTSP_STATUS_METHOD:
- str = "Method Not Allowed";
- break;
- case RTSP_STATUS_BANDWIDTH:
- str = "Not Enough Bandwidth";
- break;
- case RTSP_STATUS_SESSION:
- str = "Session Not Found";
- break;
- case RTSP_STATUS_STATE:
- str = "Method Not Valid in This State";
- break;
- case RTSP_STATUS_AGGREGATE:
- str = "Aggregate operation not allowed";
- break;
- case RTSP_STATUS_ONLY_AGGREGATE:
- str = "Only aggregate operation allowed";
- break;
- case RTSP_STATUS_TRANSPORT:
- str = "Unsupported transport";
- break;
- case RTSP_STATUS_INTERNAL:
- str = "Internal Server Error";
- break;
- case RTSP_STATUS_SERVICE:
- str = "Service Unavailable";
- break;
- case RTSP_STATUS_VERSION:
- str = "RTSP Version not supported";
- break;
- default:
- str = "Unknown Error";
- break;
- }
-
- 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_pause(c, url, header);
- else if (!strcmp(cmd, "TEARDOWN"))
- rtsp_cmd_teardown(c, url, header);
- 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(FFStream *stream, uint8_t **pbuffer,
- struct in_addr my_ip)
-{
- AVFormatContext *avc;
- AVStream *avs = NULL;
- int i;
-
- avc = avformat_alloc_context();
- if (avc == NULL) {
- return -1;
- }
- av_dict_set(&avc->metadata, "title",
- stream->title[0] ? stream->title : "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_free(avc->streams);
- av_dict_free(&avc->metadata);
- av_free(avc);
- av_free(avs);
-
- return strlen(*pbuffer);
-}
-
-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)
-{
- FFStream *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 = first_stream; stream != NULL; 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_SERVICE); /* XXX: right error ? */
- 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 != NULL; 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)
-{
- FFStream *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 = first_stream; stream != NULL; 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')
- snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
- av_lfg_get(&random_state), av_lfg_get(&random_state));
-
- /* 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_pause(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) {
- 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");
-}
-
-static void rtsp_cmd_teardown(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;
- }
-
- /* 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");
-
- /* abort the session */
- close_connection(rtp_c);
-}
-
-
-/********************************************************************/
-/* RTP handling */
-
-static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
- FFStream *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 >= 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_free(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(sizeof(AVStream *) * ctx->nb_streams);
- 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(ctx);
- return -1;
- }
- avio_close_dyn_buf(ctx->pb, &dummy_buf);
- av_free(dummy_buf);
-
- c->rtp_ctx[stream_index] = ctx;
- return 0;
-}
-
-/********************************************************************/
-/* avserver initialization */
-
-static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
-{
- AVStream *fst;
-
- 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_malloc(codec->extradata_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 the streams.
- */
- 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(FFStream *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(FFStream *stream)
-{
- FFStream **ps;
- ps = &first_stream;
- while (*ps != NULL) {
- 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_malloc(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)
-{
- FFStream *stream, *stream_next;
- int i, ret;
-
- /* gather all streams */
- for(stream = first_stream; stream != NULL; 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);
- }
-
- http_log("Opening file '%s'\n", stream->feed_filename);
- if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
- http_log("Could not open '%s': %d\n", stream->feed_filename, 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)
-{
- FFStream *stream, *feed;
- int i;
-
- /* gather all streams */
- for(stream = first_stream; stream != NULL; 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 = first_feed; feed != NULL; 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) {
- /* 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 s1 = {0}, *s = &s1;
-
- 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 supports the required parameters\n");
- exit(1);
- }
- /* XXX: need better api */
- av_freep(&s->priv_data);
- avio_close(s->pb);
- }
- /* 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;
- FFStream *stream;
-
- for(stream = first_stream; stream != NULL; 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;
- }
-}
-
-/* add a codec and set the default parameters */
-static void add_codec(FFStream *stream, AVCodecContext *av)
-{
- AVStream *st;
-
- /* 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;
- av->rc_buffer_aggressivity = 1.0;
-
- if (!av->rc_eq)
- av->rc_eq = "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 = avcodec_alloc_context3(NULL);
- stream->streams[stream->nb_streams++] = st;
- memcpy(st->codec, av, sizeof(AVCodecContext));
-}
-
-static enum AVCodecID opt_audio_codec(const char *arg)
-{
- AVCodec *p= avcodec_find_encoder_by_name(arg);
-
- if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
- return AV_CODEC_ID_NONE;
-
- return p->id;
-}
-
-static enum AVCodecID opt_video_codec(const char *arg)
-{
- AVCodec *p= avcodec_find_encoder_by_name(arg);
-
- if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
- return AV_CODEC_ID_NONE;
-
- return p->id;
-}
-
-static int avserver_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 avserver_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 = 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 1;
- }
-
- 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 = 1;
- break;
- }
- if(!strcmp(tmp, "acodec")){
- *audio_id = opt_audio_codec(tmp2);
- }else if(!strcmp(tmp, "vcodec")){
- *video_id = opt_video_codec(tmp2);
- }else if(!strcmp(tmp, "scodec")){
- /* opt_subtitle_codec(tmp2); */
- }else if(avserver_opt_default(tmp, tmp2, avctx, type) < 0){
- fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
- ret = 1;
- break;
- }
- }
-
- fclose(f);
-
- return ret;
-}
-
-static AVOutputFormat *avserver_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 report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
-{
- va_list vl;
- va_start(vl, fmt);
- fprintf(stderr, "%s:%d: ", filename, line_num);
- vfprintf(stderr, fmt, vl);
- va_end(vl);
-
- (*errors)++;
-}
-
-static int parse_ffconfig(const char *filename)
-{
- FILE *f;
- char line[1024];
- char cmd[64];
- char arg[1024];
- const char *p;
- int val, errors, line_num;
- FFStream **last_stream, *stream, *redirect;
- FFStream **last_feed, *feed, *s;
- AVCodecContext audio_enc, video_enc;
- enum AVCodecID audio_id, video_id;
-
- f = fopen(filename, "r");
- if (!f) {
- perror(filename);
- return -1;
- }
-
- errors = 0;
- line_num = 0;
- first_stream = NULL;
- last_stream = &first_stream;
- first_feed = NULL;
- last_feed = &first_feed;
- stream = NULL;
- feed = NULL;
- redirect = NULL;
- audio_id = AV_CODEC_ID_NONE;
- video_id = AV_CODEC_ID_NONE;
-
-#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
- for(;;) {
- if (fgets(line, sizeof(line), f) == NULL)
- break;
- line_num++;
- p = line;
- while (av_isspace(*p))
- p++;
- if (*p == '\0' || *p == '#')
- continue;
-
- get_arg(cmd, sizeof(cmd), &p);
-
- if (!av_strcasecmp(cmd, "Port")) {
- get_arg(arg, sizeof(arg), &p);
- val = atoi(arg);
- if (val < 1 || val > 65536) {
- ERROR("Invalid_port: %s\n", arg);
- }
- my_http_addr.sin_port = htons(val);
- } else if (!av_strcasecmp(cmd, "BindAddress")) {
- get_arg(arg, sizeof(arg), &p);
- if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
- ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
- }
- } else if (!av_strcasecmp(cmd, "RTSPPort")) {
- get_arg(arg, sizeof(arg), &p);
- val = atoi(arg);
- if (val < 1 || val > 65536) {
- ERROR("%s:%d: Invalid port: %s\n", arg);
- }
- my_rtsp_addr.sin_port = htons(atoi(arg));
- } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
- get_arg(arg, sizeof(arg), &p);
- if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
- ERROR("Invalid host/IP address: %s\n", arg);
- }
- } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
- get_arg(arg, sizeof(arg), &p);
- val = atoi(arg);
- if (val < 1 || val > 65536) {
- ERROR("Invalid MaxHTTPConnections: %s\n", arg);
- }
- nb_max_http_connections = val;
- } else if (!av_strcasecmp(cmd, "MaxClients")) {
- get_arg(arg, sizeof(arg), &p);
- val = atoi(arg);
- if (val < 1 || val > nb_max_http_connections) {
- ERROR("Invalid MaxClients: %s\n", arg);
- } else {
- nb_max_connections = val;
- }
- } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
- int64_t llval;
- get_arg(arg, sizeof(arg), &p);
- llval = atoll(arg);
- if (llval < 10 || llval > 10000000) {
- ERROR("Invalid MaxBandwidth: %s\n", arg);
- } else
- max_bandwidth = llval;
- } else if (!av_strcasecmp(cmd, "CustomLog")) {
- if (!avserver_debug)
- get_arg(logfilename, sizeof(logfilename), &p);
- } else if (!av_strcasecmp(cmd, "<Feed")) {
- /*********************************************/
- /* Feed related options */
- char *q;
- if (stream || feed) {
- ERROR("Already in a tag\n");
- } else {
- feed = av_mallocz(sizeof(FFStream));
- get_arg(feed->filename, sizeof(feed->filename), &p);
- q = strrchr(feed->filename, '>');
- if (*q)
- *q = '\0';
-
- for (s = 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);
- /* defaut 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 :-) */
-
- /* 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 (!av_strcasecmp(cmd, "Launch")) {
- if (feed) {
- int i;
-
- feed->child_argv = av_mallocz(64 * sizeof(char *));
-
- for (i = 0; i < 62; i++) {
- get_arg(arg, sizeof(arg), &p);
- if (!arg[0])
- break;
-
- feed->child_argv[i] = av_strdup(arg);
- }
-
- feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
-
- snprintf(feed->child_argv[i], 30+strlen(feed->filename),
- "http://%s:%d/%s",
- (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
- inet_ntoa(my_http_addr.sin_addr),
- ntohs(my_http_addr.sin_port), feed->filename);
- }
- } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
- if (feed) {
- get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
- feed->readonly = 1;
- } else if (stream) {
- get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
- }
- } else if (!av_strcasecmp(cmd, "File")) {
- if (feed) {
- get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
- } else if (stream)
- get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
- } else if (!av_strcasecmp(cmd, "Truncate")) {
- if (feed) {
- get_arg(arg, sizeof(arg), &p);
- feed->truncate = strtod(arg, NULL);
- }
- } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
- if (feed) {
- char *p1;
- double fsize;
-
- 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;
- }
- 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>")) {
- if (!feed) {
- ERROR("No corresponding <Feed> for </Feed>\n");
- }
- feed = NULL;
- } else if (!av_strcasecmp(cmd, "<Stream")) {
- /*********************************************/
- /* Stream related options */
- char *q;
- if (stream || feed) {
- ERROR("Already in a tag\n");
- } else {
- FFStream *s;
- stream = av_mallocz(sizeof(FFStream));
- get_arg(stream->filename, sizeof(stream->filename), &p);
- q = strrchr(stream->filename, '>');
- if (*q)
- *q = '\0';
-
- for (s = first_stream; s; s = s->next) {
- if (!strcmp(stream->filename, s->filename)) {
- ERROR("Stream '%s' already registered\n", s->filename);
- }
- }
-
- stream->fmt = avserver_guess_format(NULL, stream->filename, NULL);
- avcodec_get_context_defaults3(&video_enc, NULL);
- avcodec_get_context_defaults3(&audio_enc, NULL);
- audio_id = AV_CODEC_ID_NONE;
- video_id = AV_CODEC_ID_NONE;
- if (stream->fmt) {
- audio_id = stream->fmt->audio_codec;
- video_id = stream->fmt->video_codec;
- }
-
- *last_stream = stream;
- last_stream = &stream->next;
- }
- } else if (!av_strcasecmp(cmd, "Feed")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream) {
- FFStream *sfeed;
-
- sfeed = first_feed;
- while (sfeed != NULL) {
- if (!strcmp(sfeed->filename, arg))
- break;
- sfeed = sfeed->next_feed;
- }
- if (!sfeed)
- ERROR("feed '%s' not defined\n", arg);
- else
- stream->feed = sfeed;
- }
- } else if (!av_strcasecmp(cmd, "Format")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream) {
- 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 jpeg */
- if (!strcmp(arg, "jpeg"))
- strcpy(arg, "mjpeg");
- stream->fmt = avserver_guess_format(arg, NULL, NULL);
- if (!stream->fmt) {
- ERROR("Unknown Format: %s\n", arg);
- }
- }
- if (stream->fmt) {
- audio_id = stream->fmt->audio_codec;
- video_id = stream->fmt->video_codec;
- }
- }
- } else if (!av_strcasecmp(cmd, "InputFormat")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream) {
- 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->stream_type == STREAM_TYPE_STATUS) {
- 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")) {
- if (stream)
- get_arg(stream->author, sizeof(stream->author), &p);
- } else if (!av_strcasecmp(cmd, "Comment")) {
- if (stream)
- get_arg(stream->comment, sizeof(stream->comment), &p);
- } else if (!av_strcasecmp(cmd, "Copyright")) {
- if (stream)
- get_arg(stream->copyright, sizeof(stream->copyright), &p);
- } else if (!av_strcasecmp(cmd, "Title")) {
- if (stream)
- get_arg(stream->title, sizeof(stream->title), &p);
- } else if (!av_strcasecmp(cmd, "Preroll")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream)
- stream->prebuffer = atof(arg) * 1000;
- } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
- if (stream)
- stream->send_on_key = 1;
- } else if (!av_strcasecmp(cmd, "AudioCodec")) {
- get_arg(arg, sizeof(arg), &p);
- audio_id = opt_audio_codec(arg);
- if (audio_id == AV_CODEC_ID_NONE) {
- ERROR("Unknown AudioCodec: %s\n", arg);
- }
- } else if (!av_strcasecmp(cmd, "VideoCodec")) {
- get_arg(arg, sizeof(arg), &p);
- video_id = opt_video_codec(arg);
- if (video_id == AV_CODEC_ID_NONE) {
- ERROR("Unknown VideoCodec: %s\n", arg);
- }
- } else if (!av_strcasecmp(cmd, "MaxTime")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream)
- stream->max_time = atof(arg) * 1000;
- } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream)
- audio_enc.bit_rate = lrintf(atof(arg) * 1000);
- } else if (!av_strcasecmp(cmd, "AudioChannels")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream)
- audio_enc.channels = atoi(arg);
- } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream)
- audio_enc.sample_rate = atoi(arg);
- } else if (!av_strcasecmp(cmd, "AudioQuality")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream) {
-// audio_enc.quality = atof(arg) * 1000;
- }
- } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
- if (stream) {
- int minrate, maxrate;
-
- get_arg(arg, sizeof(arg), &p);
-
- if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
- video_enc.rc_min_rate = minrate * 1000;
- video_enc.rc_max_rate = maxrate * 1000;
- } else {
- ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
- }
- }
- } else if (!av_strcasecmp(cmd, "Debug")) {
- if (stream) {
- get_arg(arg, sizeof(arg), &p);
- video_enc.debug = strtol(arg,0,0);
- }
- } else if (!av_strcasecmp(cmd, "Strict")) {
- if (stream) {
- get_arg(arg, sizeof(arg), &p);
- video_enc.strict_std_compliance = atoi(arg);
- }
- } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
- if (stream) {
- get_arg(arg, sizeof(arg), &p);
- video_enc.rc_buffer_size = atoi(arg) * 8*1024;
- }
- } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
- if (stream) {
- get_arg(arg, sizeof(arg), &p);
- video_enc.bit_rate_tolerance = atoi(arg) * 1000;
- }
- } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream) {
- video_enc.bit_rate = atoi(arg) * 1000;
- }
- } else if (!av_strcasecmp(cmd, "VideoSize")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream) {
- av_parse_video_size(&video_enc.width, &video_enc.height, arg);
- if ((video_enc.width % 16) != 0 ||
- (video_enc.height % 16) != 0) {
- ERROR("Image size must be a multiple of 16\n");
- }
- }
- } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream) {
- AVRational frame_rate;
- if (av_parse_video_rate(&frame_rate, arg) < 0) {
- ERROR("Incorrect frame rate: %s\n", arg);
- } else {
- video_enc.time_base.num = frame_rate.den;
- video_enc.time_base.den = frame_rate.num;
- }
- }
- } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream)
- video_enc.gop_size = atoi(arg);
- } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
- if (stream)
- video_enc.gop_size = 1;
- } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
- if (stream)
- video_enc.mb_decision = FF_MB_DECISION_BITS;
- } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
- if (stream) {
- video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
- video_enc.flags |= CODEC_FLAG_4MV;
- }
- } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
- !av_strcasecmp(cmd, "AVOptionAudio")) {
- char arg2[1024];
- AVCodecContext *avctx;
- int type;
- get_arg(arg, sizeof(arg), &p);
- get_arg(arg2, sizeof(arg2), &p);
- if (!av_strcasecmp(cmd, "AVOptionVideo")) {
- avctx = &video_enc;
- type = AV_OPT_FLAG_VIDEO_PARAM;
- } else {
- avctx = &audio_enc;
- type = AV_OPT_FLAG_AUDIO_PARAM;
- }
- if (avserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
- ERROR("AVOption error: %s %s\n", arg, arg2);
- }
- } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
- !av_strcasecmp(cmd, "AVPresetAudio")) {
- AVCodecContext *avctx;
- int type;
- get_arg(arg, sizeof(arg), &p);
- if (!av_strcasecmp(cmd, "AVPresetVideo")) {
- avctx = &video_enc;
- video_enc.codec_id = video_id;
- type = AV_OPT_FLAG_VIDEO_PARAM;
- } else {
- avctx = &audio_enc;
- audio_enc.codec_id = audio_id;
- type = AV_OPT_FLAG_AUDIO_PARAM;
- }
- if (avserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
- ERROR("AVPreset error: %s\n", arg);
- }
- } else if (!av_strcasecmp(cmd, "VideoTag")) {
- get_arg(arg, sizeof(arg), &p);
- if ((strlen(arg) == 4) && stream)
- video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
- } else if (!av_strcasecmp(cmd, "BitExact")) {
- if (stream)
- video_enc.flags |= CODEC_FLAG_BITEXACT;
- } else if (!av_strcasecmp(cmd, "DctFastint")) {
- if (stream)
- video_enc.dct_algo = FF_DCT_FASTINT;
- } else if (!av_strcasecmp(cmd, "IdctSimple")) {
- if (stream)
- video_enc.idct_algo = FF_IDCT_SIMPLE;
- } else if (!av_strcasecmp(cmd, "Qscale")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream) {
- video_enc.flags |= CODEC_FLAG_QSCALE;
- video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
- }
- } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream) {
- video_enc.max_qdiff = atoi(arg);
- if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
- ERROR("VideoQDiff out of range\n");
- }
- }
- } else if (!av_strcasecmp(cmd, "VideoQMax")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream) {
- video_enc.qmax = atoi(arg);
- if (video_enc.qmax < 1 || video_enc.qmax > 31) {
- ERROR("VideoQMax out of range\n");
- }
- }
- } else if (!av_strcasecmp(cmd, "VideoQMin")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream) {
- video_enc.qmin = atoi(arg);
- if (video_enc.qmin < 1 || video_enc.qmin > 31) {
- ERROR("VideoQMin out of range\n");
- }
- }
- } else if (!av_strcasecmp(cmd, "LumiMask")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream)
- video_enc.lumi_masking = atof(arg);
- } else if (!av_strcasecmp(cmd, "DarkMask")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream)
- video_enc.dark_masking = atof(arg);
- } else if (!av_strcasecmp(cmd, "NoVideo")) {
- video_id = AV_CODEC_ID_NONE;
- } else if (!av_strcasecmp(cmd, "NoAudio")) {
- audio_id = AV_CODEC_ID_NONE;
- } else if (!av_strcasecmp(cmd, "ACL")) {
- parse_acl_row(stream, feed, NULL, p, filename, line_num);
- } else if (!av_strcasecmp(cmd, "DynamicACL")) {
- if (stream) {
- get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
- }
- } else if (!av_strcasecmp(cmd, "RTSPOption")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream) {
- av_freep(&stream->rtsp_option);
- stream->rtsp_option = av_strdup(arg);
- }
- } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream) {
- if (resolve_host(&stream->multicast_ip, arg) != 0) {
- ERROR("Invalid host/IP address: %s\n", arg);
- }
- stream->is_multicast = 1;
- stream->loop = 1; /* default is looping */
- }
- } else if (!av_strcasecmp(cmd, "MulticastPort")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream)
- stream->multicast_port = atoi(arg);
- } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream)
- stream->multicast_ttl = atoi(arg);
- } else if (!av_strcasecmp(cmd, "NoLoop")) {
- if (stream)
- stream->loop = 0;
- } else if (!av_strcasecmp(cmd, "</Stream>")) {
- if (!stream) {
- ERROR("No corresponding <Stream> for </Stream>\n");
- } else {
- if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
- if (audio_id != AV_CODEC_ID_NONE) {
- audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
- audio_enc.codec_id = audio_id;
- add_codec(stream, &audio_enc);
- }
- if (video_id != AV_CODEC_ID_NONE) {
- video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
- video_enc.codec_id = video_id;
- add_codec(stream, &video_enc);
- }
- }
- stream = NULL;
- }
- } else if (!av_strcasecmp(cmd, "<Redirect")) {
- /*********************************************/
- char *q;
- if (stream || feed || redirect) {
- ERROR("Already in a tag\n");
- } else {
- redirect = av_mallocz(sizeof(FFStream));
- *last_stream = redirect;
- last_stream = &redirect->next;
-
- get_arg(redirect->filename, sizeof(redirect->filename), &p);
- q = strrchr(redirect->filename, '>');
- if (*q)
- *q = '\0';
- redirect->stream_type = STREAM_TYPE_REDIRECT;
- }
- } else if (!av_strcasecmp(cmd, "URL")) {
- if (redirect)
- get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
- } else if (!av_strcasecmp(cmd, "</Redirect>")) {
- if (!redirect) {
- ERROR("No corresponding <Redirect> for </Redirect>\n");
- } else {
- if (!redirect->feed_filename[0]) {
- ERROR("No URL found for <Redirect>\n");
- }
- redirect = NULL;
- }
- } else if (!av_strcasecmp(cmd, "LoadModule")) {
- ERROR("Loadable modules no longer supported\n");
- } else {
- ERROR("Incorrect keyword: '%s'\n", cmd);
- }
- }
-#undef ERROR
-
- fclose(f);
- if (errors)
- return -1;
- else
- return 0;
-}
-
-static void handle_child_exit(int sig)
-{
- pid_t pid;
- int status;
-
- while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
- FFStream *feed;
-
- for (feed = 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)
-{
- avserver_debug = 1;
- logfilename[0] = '-';
-}
-
-void show_help_default(const char *opt, const char *arg)
-{
- printf("usage: avserver [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/avserver.conf", "configfile" },
- { NULL },
-};
-
-int main(int argc, char **argv)
-{
- struct sigaction sigact = { { 0 } };
-
- config_filename = av_strdup("/etc/avserver.conf");
-
- parse_loglevel(argc, argv, options);
- av_register_all();
- avformat_network_init();
-
- show_banner();
-
- 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 (parse_ffconfig(config_filename) < 0) {
- fprintf(stderr, "Incorrect config file - exiting.\n");
- exit(1);
- }
-
- /* open log file if needed */
- if (logfilename[0] != '\0') {
- if (!strcmp(logfilename, "-"))
- logfile = stdout;
- else
- logfile = fopen(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/cmdutils.c b/cmdutils.c
index d6eb981..b10a552 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
*/
@@ -29,13 +29,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"
@@ -53,18 +57,27 @@
#include <sys/time.h>
#include <sys/resource.h>
#endif
+#if CONFIG_OPENCL
+#include "libavutil/opencl.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 = 2013;
+const int this_year = 2013;
+
+static FILE *report_file;
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)
@@ -73,6 +86,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);
@@ -83,6 +98,20 @@ 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);
+ fputs(line, report_file);
+ fflush(report_file);
+}
+
static void (*program_exit)(int ret);
void register_exit(void (*cb)(int ret))
@@ -163,8 +192,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);
@@ -286,7 +317,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;
}
}
@@ -413,65 +445,139 @@ int locate_option(int argc, char **argv, const OptionDef *options,
(po->name && !strcmp(optname, po->name)))
return i;
- if (!po || po->flags & HAS_ARG)
+ if (po->flags & HAS_ARG)
i++;
}
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);
+ }
+ }
+}
+
+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;
+ }
+#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;
}
@@ -516,6 +622,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;
@@ -526,6 +633,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));
@@ -583,6 +691,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);
}
@@ -599,6 +708,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);
@@ -613,8 +723,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;
@@ -697,12 +811,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;
}
@@ -722,6 +837,13 @@ int opt_loglevel(void *optctx, const char *opt, const char *arg)
int level;
int i;
+ tail = strstr(arg, "repeat");
+ av_log_set_flags(tail ? 0 : AV_LOG_SKIP_REPEATED);
+ 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);
@@ -741,6 +863,116 @@ 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 {
+ 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) {
+ av_log(NULL, AV_LOG_ERROR, "Failed to open report \"%s\": %s\n",
+ filename.str, strerror(errno));
+ return AVERROR(errno);
+ }
+ 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
@@ -754,6 +986,26 @@ int opt_timelimit(void *optctx, const char *opt, const char *arg)
return 0;
}
+#if CONFIG_OPENCL
+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;
+}
+#endif
+
void print_error(const char *filename, int err)
{
char errbuf[128];
@@ -769,6 +1021,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) { \
@@ -776,7 +1029,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, \
@@ -785,7 +1038,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", \
@@ -807,24 +1060,40 @@ 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, 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);
+}
+
+void show_banner(int argc, char **argv, const OptionDef *options)
+{
+ int idx = locate_option(argc, argv, options, "version");
+ if (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 (0 , AV_LOG_INFO);
print_all_libs_info(SHOW_VERSION, AV_LOG_INFO);
return 0;
@@ -832,12 +1101,13 @@ int show_version(void *optctx, const char *opt, const char *arg)
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"
@@ -850,8 +1120,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"
@@ -865,8 +1136,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"
@@ -879,8 +1151,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"
@@ -894,9 +1167,8 @@ 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;
}
@@ -951,7 +1223,7 @@ int show_formats(void *optctx, const char *opt, const char *arg)
#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) { \
@@ -969,7 +1241,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)) {
@@ -1013,7 +1286,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 '?';
}
}
@@ -1029,6 +1304,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;
@@ -1043,7 +1348,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"
@@ -1055,9 +1361,11 @@ 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;
+ printf(" ");
printf(avcodec_find_decoder(desc->id) ? "D" : ".");
printf(avcodec_find_encoder(desc->id) ? "E" : ".");
@@ -1086,30 +1394,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))
@@ -1118,6 +1433,7 @@ static void print_codecs(int encoder)
printf("\n");
}
}
+ av_free(codecs);
}
int show_decoders(void *optctx, const char *opt, const char *arg)
@@ -1161,15 +1477,61 @@ int show_protocols(void *optctx, const char *opt, const char *arg)
int show_filters(void *optctx, const char *opt, const char *arg)
{
const AVFilter av_unused(*filter) = NULL;
-
- printf("Filters:\n");
+ 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");
#if CONFIG_AVFILTER
- while ((filter = avfilter_next(filter)))
- printf("%-16s %s\n", filter->name, filter->description);
+ 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);
+ }
#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;
@@ -1203,6 +1565,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("%-12s%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("%-12s", 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;
@@ -1236,13 +1627,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);
}
}
@@ -1301,6 +1692,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;
@@ -1312,7 +1704,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");
@@ -1320,24 +1714,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
@@ -1397,6 +1801,11 @@ int cmdutils_read_file(const char *filename, char **bufptr, size_t *size)
fseek(f, 0, SEEK_END);
*size = ftell(f);
fseek(f, 0, SEEK_SET);
+ if (*size == (size_t)-1) {
+ av_log(NULL, AV_LOG_ERROR, "IO error: %s\n", strerror(errno));
+ fclose(f);
+ return AVERROR(errno);
+ }
*bufptr = av_malloc(*size + 1);
if (!*bufptr) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate file buffer\n");
@@ -1421,58 +1830,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");
}
@@ -1484,56 +1882,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) /* 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,
@@ -1630,15 +1982,3 @@ void *grow_array(void *array, int elem_size, int *size, int new_size)
}
return array;
}
-
-const char *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 "unknown";
- }
-}
diff --git a/cmdutils.h b/cmdutils.h
index f1b69f9..2d2afc8 100644
--- a/cmdutils.h
+++ b/cmdutils.h
@@ -2,25 +2,25 @@
* 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>
@@ -29,6 +29,10 @@
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
+#ifdef __MINGW32__
+#undef main /* We don't want SDL to override our main() */
+#endif
+
/**
* program name, defined by the program for show_version().
*/
@@ -39,9 +43,15 @@ extern const char program_name[];
*/
extern const int program_birth_year;
+/**
+ * this year, defined by the program for show_banner()
+ */
+extern const int this_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;
/**
@@ -67,12 +77,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 +97,14 @@ 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);
+
+int opt_opencl(void *optctx, const char *opt, const char *arg);
+
/**
* Limit the execution time.
*/
@@ -120,7 +138,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 +169,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 +207,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 +256,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 +277,7 @@ typedef struct OptionGroup {
AVDictionary *format_opts;
AVDictionary *resample_opts;
struct SwsContext *sws_opts;
+ AVDictionary *swr_opts;
} OptionGroup;
/**
@@ -385,30 +404,34 @@ 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 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.
+ * 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 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 +450,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 +507,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 +545,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 +568,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..6966303 100644
--- a/cmdutils_common_opts.h
+++ b/cmdutils_common_opts.h
@@ -12,7 +12,14 @@
{ "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" },
+#if CONFIG_OPENCL
+ { "opencl_options", HAS_ARG, {.func_arg = opt_opencl}, "set OpenCL environment options" },
+#endif
diff --git a/common.mak b/common.mak
index 41ef235..6479b08 100644
--- a/common.mak
+++ b/common.mak
@@ -5,6 +5,80 @@
# 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
+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)
+
+%.o: %.c
+ $(COMPILE_C)
+
+%.o: %.cpp
+ $(COMPILE_CXX)
+
+%.s: %.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -S -o $@ $<
+
+%.o: %.S
+ $(COMPILE_S)
+
+%.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)
@@ -52,7 +126,7 @@ $(TOOLOBJS): | tools
OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(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
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..84b6e13
--- a/dev/null
+++ b/compat/avisynth/avisynth_c.h
@@ -0,0 +1,879 @@
+// Avisynth C Interface Version 0.20
+// Copyright 2003 Kevin Atkinson
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
+// http://www.gnu.org/copyleft/gpl.html .
+//
+// As a special exception, I give you permission to link to the
+// Avisynth C interface with independent modules that communicate with
+// the Avisynth C interface solely through the interfaces defined in
+// avisynth_c.h, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting combined work
+// under terms of your choice, provided that every copy of the
+// combined work is accompanied by a complete copy of the source code
+// of the Avisynth C interface and Avisynth itself (with the version
+// used to produce the combined work), being distributed under the
+// terms of the GNU General Public License plus this exception. An
+// independent module is a module which is not derived from or based
+// on Avisynth C Interface, such as 3rd-party filters, import and
+// export plugins, or graphical user interfaces.
+
+// 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 == NULL)
+ return NULL;
+ library->handle = LoadLibrary("avisynth");
+ if (library->handle == NULL)
+ goto fail;
+
+#define __AVSC_STRINGIFY(x) #x
+#define AVSC_STRINGIFY(x) __AVSC_STRINGIFY(x)
+#define AVSC_LOAD_FUNC(name) {\
+ library->name = (name##_func) GetProcAddress(library->handle, AVSC_STRINGIFY(name));\
+ if (library->name == NULL)\
+ goto fail;\
+}
+
+ AVSC_LOAD_FUNC(avs_add_function);
+ AVSC_LOAD_FUNC(avs_at_exit);
+ AVSC_LOAD_FUNC(avs_bit_blt);
+ AVSC_LOAD_FUNC(avs_check_version);
+ AVSC_LOAD_FUNC(avs_clip_get_error);
+ AVSC_LOAD_FUNC(avs_copy_clip);
+ AVSC_LOAD_FUNC(avs_copy_value);
+ AVSC_LOAD_FUNC(avs_copy_video_frame);
+ AVSC_LOAD_FUNC(avs_create_script_environment);
+ AVSC_LOAD_FUNC(avs_delete_script_environment);
+ AVSC_LOAD_FUNC(avs_function_exists);
+ AVSC_LOAD_FUNC(avs_get_audio);
+ AVSC_LOAD_FUNC(avs_get_cpu_flags);
+ AVSC_LOAD_FUNC(avs_get_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 == NULL)
+ 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
--- a/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..7a81e21
--- a/dev/null
+++ b/compat/avisynth/avxsynth_c.h
@@ -0,0 +1,727 @@
+// Avisynth C Interface Version 0.20
+// Copyright 2003 Kevin Atkinson
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
+// http://www.gnu.org/copyleft/gpl.html .
+//
+// As a special exception, I give you permission to link to the
+// Avisynth C interface with independent modules that communicate with
+// the Avisynth C interface solely through the interfaces defined in
+// avisynth_c.h, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting combined work
+// under terms of your choice, provided that every copy of the
+// combined work is accompanied by a complete copy of the source code
+// of the Avisynth C interface and Avisynth itself (with the version
+// used to produce the combined work), being distributed under the
+// terms of the GNU General Public License plus this exception. An
+// independent module is a module which is not derived from or based
+// on Avisynth C Interface, such as 3rd-party filters, import and
+// export plugins, or graphical user interfaces.
+
+#ifndef __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
--- a/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
--- a/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/getopt.c b/compat/getopt.c
index 3e7d3e2..dd082ea 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
*/
@@ -46,7 +46,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;
@@ -54,6 +54,7 @@ static int getopt(int argc, char *argv[], char *opts)
optind++;
return EOF;
}
+ }
optopt = c = argv[optind][sp];
if (c == ':' || (cp = strchr(opts, c)) == NULL) {
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
--- a/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..b816bff
--- a/dev/null
+++ b/compat/os2threads.h
@@ -0,0 +1,162 @@
+/*
+ * 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>
+
+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..f894771
--- a/dev/null
+++ b/compat/va_copy.h
@@ -0,0 +1,26 @@
+/*
+ * 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
diff --git a/compat/w32pthreads.h b/compat/w32pthreads.h
index be275ed..7b51c25 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
@@ -39,6 +39,7 @@
#include <windows.h>
#include <process.h>
+#include "libavutil/common.h"
#include "libavutil/internal.h"
#include "libavutil/mem.h"
@@ -278,4 +279,4 @@ static void w32thread_init(void)
}
-#endif /* LIBAV_COMPAT_W32PTHREADS_H */
+#endif /* FFMPEG_COMPAT_W32PTHREADS_H */
diff --git a/configure b/configure
index ebd21b2..af322f5 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,10 +78,11 @@ 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]
@@ -98,31 +99,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-incompatible-fork-abi enable incompatible Libav fork ABI (deprecated) [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 disable avserver build
+ --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,10 +144,10 @@ Component options:
--disable-fft disable FFT code
Hardware accelerators:
- --enable-dxva2 enable DXVA2 code
- --enable-vaapi enable VAAPI code
+ --disable-dxva2 disable DXVA2 code [autodetect]
+ --disable-vaapi disable VAAPI code [autodetect]
--enable-vda enable VDA code
- --enable-vdpau enable VDPAU code
+ --disable-vdpau disable VDPAU code [autodetect]
Individual component options:
--disable-everything disable all components listed below
@@ -175,40 +188,68 @@ 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-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-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 decoding 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-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-libx264 enable H.264 encoding via x264 [no]
--enable-libxavs enable AVS encoding via xavs [no]
--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]
+ --enable-openal enable OpenAL 1.1 capture support [no]
+ --enable-opencl enable OpenCL code
--enable-openssl enable openssl [no]
--enable-x11grab enable X11 grabbing [no]
- --enable-zlib enable zlib [autodetect]
+ --disable-zlib disable zlib [autodetect]
Advanced options (experts only):
--cross-prefix=PREFIX use PREFIX for compilation tools [$cross_prefix]
@@ -219,13 +260,16 @@ Advanced options (experts only):
--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]
+ --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]
--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
@@ -234,12 +278,14 @@ Advanced options (experts only):
--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-libs=ELIBS add ELIBS [$ELIBS]
--extra-version=STRING version string suffix []
--optflags=OPTFLAGS override optimization-related compiler flags
--build-suffix=SUFFIX library name suffix []
--malloc-prefix=PREFIX prefix malloc and related names with PREFIX
+ --progs-suffix=SUFFIX program name suffix []
--arch=ARCH select architecture [$arch]
--cpu=CPU select the minimum required CPU (affects
instruction selection, may crash on older CPUs)
@@ -278,14 +324,27 @@ Optimization options (experts only):
--disable-vis disable VIS optimizations
--disable-inline-asm disable use of inline assembler
--disable-yasm disable use of yasm assembler
+ --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-xmm-clobber-test check XMM registers for clobbering (Win64-only;
should be used only for debugging purposes)
--enable-random randomly enable/disable components
@@ -330,7 +389,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
@@ -366,7 +425,7 @@ sh_quote(){
}
cleanws(){
- echo "$@" | sed 's/^ *//;s/ */ /g;s/ *$//'
+ echo "$@" | sed 's/^ *//;s/ */ /g;s/ *$//;s/\r//g'
}
filter(){
@@ -618,6 +677,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;
}
}
}"
@@ -651,6 +716,10 @@ add_cflags(){
append CFLAGS $($cflags_filter "$@")
}
+add_cxxflags(){
+ append CXXFLAGS $($cflags_filter "$@")
+}
+
add_asflags(){
append ASFLAGS $($asflags_filter "$@")
}
@@ -701,6 +770,13 @@ 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_cpp(){
log check_cpp "$@"
cat > $TMPC
@@ -741,7 +817,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(){
@@ -750,9 +826,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
@@ -787,9 +865,17 @@ int x;
EOF
}
+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
}
@@ -815,7 +901,7 @@ 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
@@ -828,10 +914,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
}
@@ -848,7 +934,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(){
@@ -880,6 +985,14 @@ 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"
@@ -895,7 +1008,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(){
@@ -955,7 +1068,7 @@ check_builtin(){
builtin=$3
shift 3
disable "$name"
- check_code ld "$headers" "$builtin" "$@" && enable "$name"
+ check_code ld "$headers" "$builtin" "cc" "$@" && enable "$name"
}
require(){
@@ -974,6 +1087,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"
@@ -1039,26 +1160,49 @@ COMPONENT_LIST="
EXTERNAL_LIBRARY_LIST="
avisynth
bzlib
+ crystalhd
+ fontconfig
frei0r
gnutls
+ iconv
+ ladspa
+ libaacplus
+ libass
+ libbluray
+ libcaca
libcdio
+ libcelt
libdc1394
libfaac
libfdk_aac
+ libflite
libfreetype
+ libgme
libgsm
+ libiec61883
libilbc
+ libmodplug
libmp3lame
+ libnut
libopencore_amrnb
libopencore_amrwb
libopencv
libopenjpeg
libopus
libpulse
+ libquvi
librtmp
libschroedinger
+ libshine
+ libsoxr
libspeex
+ libssh
+ libstagefright_h264
libtheora
+ libtwolame
+ libutvideo
+ libv4l2
+ libvidstab
libvo_aacenc
libvo_amrwbenc
libvorbis
@@ -1067,17 +1211,30 @@ EXTERNAL_LIBRARY_LIST="
libx264
libxavs
libxvid
+ libzmq
+ libzvbi
+ openal
+ opencl
openssl
x11grab
zlib
"
+DOCUMENT_LIST="
+ doc
+ htmlpages
+ manpages
+ podpages
+ txtpages
+"
+
HWACCEL_LIST="
dxva2
vaapi
vda
vdpau
"
+
LIBRARY_LIST="
avcodec
avdevice
@@ -1085,33 +1242,41 @@ LIBRARY_LIST="
avformat
avresample
avutil
+ postproc
+ swresample
swscale
"
PROGRAM_LIST="
- avconv
- avplay
- avprobe
- avserver
+ ffplay
+ ffprobe
+ ffserver
+ ffmpeg
"
CONFIG_LIST="
$COMPONENT_LIST
+ $DOCUMENT_LIST
$EXTERNAL_LIBRARY_LIST
$HWACCEL_LIST
$LIBRARY_LIST
$PROGRAM_LIST
dct
- doc
+ dwt
error_resilience
+ fast_unaligned
fft
+ ftrapv
gpl
gray
hardcoded_tables
+ incompatible_libav_abi
+ incompatible_fork_abi
lsp
lzo
mdct
memalign_hack
+ memory_poisoning
network
nonfree
pic
@@ -1131,6 +1296,7 @@ CONFIG_LIST="
THREADS_LIST='
pthreads
w32threads
+ os2threads
'
ATOMICS_LIST='
@@ -1198,6 +1364,10 @@ ARCH_EXT_LIST="
altivec
ppc4xx
vis
+ mipsfpu
+ mips32r2
+ mipsdspr1
+ mipsdspr2
"
HAVE_LIST_CMDLINE='
@@ -1209,11 +1379,14 @@ HAVE_LIST_CMDLINE='
HAVE_LIST_PUB='
bigendian
fast_unaligned
+ incompatible_libav_abi
+ incompatible_fork_abi
'
MATH_FUNCS="
atanf
atan2f
+ cbrt
cbrtf
cosf
exp2
@@ -1247,6 +1420,7 @@ HAVE_LIST="
$THREADS_LIST
$ATOMICS_LIST
$MATH_FUNCS
+ access
aligned_malloc
aligned_stack
alsa_asoundlib_h
@@ -1254,12 +1428,15 @@ HAVE_LIST="
arpa_inet_h
asm_mod_q
asm_mod_y
+ asm_types_h
atomic_cas_ptr
atomics_native
attribute_may_alias
attribute_packed
cdio_paranoia_h
cdio_paranoia_paranoia_h
+ CL_cl_h
+ clock_gettime
closesocket
CommandLineToArgvW
cpunop
@@ -1292,6 +1469,7 @@ HAVE_LIST="
getrusage
getservbyport
gettimeofday
+ glob
gnu_as
gsm_h
ibm_asm
@@ -1300,6 +1478,7 @@ HAVE_LIST="
inline_asm_labels
isatty
jack_port_get_latency_range
+ kbhit
ldbrx
libdc1394_1
libdc1394_2
@@ -1307,9 +1486,11 @@ HAVE_LIST="
local_aligned_8
localtime_r
loongson
+ lzo1x_999_compress
machine_ioctl_bt848_h
machine_ioctl_meteor_h
machine_rw_barrier
+ makeinfo
malloc_h
MapViewOfFile
memalign
@@ -1320,10 +1501,17 @@ HAVE_LIST="
mprotect
msvcrt
nanosleep
+ openjpeg_1_5_openjpeg_h
+ PeekNamedPipe
+ perl
+ pod2man
poll_h
posix_memalign
pragma_deprecated
+ pthread_cancel
rdtsc
+ rsync_contimeout
+ sarestart
sched_getaffinity
sdl
SetConsoleTextAttribute
@@ -1334,17 +1522,17 @@ HAVE_LIST="
socklen_t
soundcard_h
strerror_r
- strptime
- strtok_r
struct_addrinfo
struct_group_source_req
struct_ip_mreq_source
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
symver_asm_label
symver_gnu_asm
@@ -1359,6 +1547,8 @@ HAVE_LIST="
sys_time_h
sys_un_h
sys_videoio_h
+ termios_h
+ texi2html
threads
unistd_h
usleep
@@ -1376,6 +1566,8 @@ CONFIG_EXTRA="
ac3dsp
audio_frame_queue
dsputil
+ exif
+ frame_thread_encoder
gcrypt
golomb
gplv3
@@ -1414,6 +1606,7 @@ CMDLINE_SELECT="
logging
lto
optimizations
+ stripping
"
PATHS_LIST='
@@ -1432,10 +1625,12 @@ CMDLINE_SET="
ar
arch
as
+ assert_level
build_suffix
cc
cpu
cross_prefix
+ cxx
dep_cc
extra_version
host_cc
@@ -1444,25 +1639,32 @@ CMDLINE_SET="
host_ldflags
host_libs
host_os
+ install
ld
logfile
malloc_prefix
nm
optflags
pkg_config
+ progs_suffix
random_seed
samples
+ strip
sysinclude
sysroot
target_exec
target_os
target_path
target_samples
+ tempprefix
toolchain
+ valgrind
+ yasmexe
"
CMDLINE_APPEND="
extra_cflags
+ extra_cxxflags
host_cppflags
"
@@ -1479,6 +1681,11 @@ vfpv3_deps="vfp"
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"
@@ -1528,12 +1735,13 @@ log2_deps="!msvcrt"
# subsystems
dct_select="rdft"
error_resilience_select="dsputil"
+frame_thread_encoder_deps="encoders threads"
lpc_select="dsputil"
mdct_select="fft"
rdft_select="fft"
mpegaudio_select="mpegaudiodsp"
mpegaudiodsp_select="dct"
-mpegvideo_select="dsputil hpeldsp videodsp"
+mpegvideo_select="dsputil h264chroma hpeldsp videodsp"
mpegvideoenc_select="mpegvideo"
# decoders / encoders
@@ -1548,7 +1756,8 @@ alac_encoder_select="lpc"
als_decoder_select="dsputil"
amrnb_decoder_select="lsp"
amrwb_decoder_select="lsp"
-amv_decoder_select="dsputil hpeldsp"
+amv_decoder_select="dsputil hpeldsp exif"
+amv_encoder_select="aandcttables"
ape_decoder_select="dsputil"
asv1_decoder_select="dsputil"
asv1_encoder_select="dsputil"
@@ -1556,6 +1765,7 @@ asv2_decoder_select="dsputil"
asv2_encoder_select="dsputil"
atrac1_decoder_select="mdct sinewin"
atrac3_decoder_select="mdct"
+avrn_decoder_select="exif"
bink_decoder_select="dsputil hpeldsp"
binkaudio_dct_decoder_select="mdct rdft dct sinewin"
binkaudio_rdft_decoder_select="mdct rdft sinewin"
@@ -1566,31 +1776,34 @@ cook_decoder_select="dsputil mdct sinewin"
cscd_decoder_select="lzo"
cscd_decoder_suggest="zlib"
dca_decoder_select="mdct"
+dirac_decoder_select="dsputil dwt golomb videodsp"
dnxhd_decoder_select="dsputil"
dnxhd_encoder_select="aandcttables dsputil mpegvideoenc"
dvvideo_decoder_select="dsputil"
dvvideo_encoder_select="dsputil"
-dxa_decoder_deps="zlib"
+dxa_decoder_select="zlib"
eac3_decoder_select="ac3_decoder"
eac3_encoder_select="ac3_encoder"
eamad_decoder_select="aandcttables dsputil mpegvideo"
-eatgq_decoder_select="aandcttables dsputil"
+eatgq_decoder_select="aandcttables"
eatqi_decoder_select="aandcttables error_resilience mpegvideo"
+exr_decoder_select="zlib"
ffv1_decoder_select="dsputil golomb rangecoder"
ffv1_encoder_select="dsputil rangecoder"
ffvhuff_decoder_select="dsputil"
ffvhuff_encoder_select="dsputil huffman"
flac_decoder_select="golomb"
flac_encoder_select="dsputil 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="dsputil"
fraps_decoder_select="dsputil huffman"
-g2m_decoder_deps="zlib"
-g2m_decoder_select="dsputil"
+g2m_decoder_select="dsputil zlib"
+g729_decoder_select="dsputil"
h261_decoder_select="error_resilience mpegvideo"
h261_encoder_select="aandcttables mpegvideoenc"
h263_decoder_select="error_resilience h263_parser mpegvideo"
@@ -1599,13 +1812,14 @@ h263i_decoder_select="h263_decoder"
h263p_encoder_select="h263_encoder"
h264_decoder_select="golomb h264chroma h264dsp h264pred h264qpel videodsp"
h264_decoder_suggest="error_resilience"
+hevc_decoder_select="dsputil golomb videodsp"
huffyuv_decoder_select="dsputil"
huffyuv_encoder_select="dsputil huffman"
iac_decoder_select="dsputil fft mdct sinewin"
imc_decoder_select="dsputil fft mdct sinewin"
indeo3_decoder_select="hpeldsp"
interplay_video_decoder_select="hpeldsp"
-jpegls_decoder_select="dsputil golomb hpeldsp"
+jpegls_decoder_select="dsputil golomb hpeldsp exif"
jpegls_encoder_select="golomb"
jv_decoder_select="dsputil"
lagarith_decoder_select="dsputil"
@@ -1614,8 +1828,8 @@ loco_decoder_select="golomb"
mdec_decoder_select="dsputil error_resilience mpegvideo"
metasound_decoder_select="lsp mdct sinewin"
mimic_decoder_select="dsputil hpeldsp"
-mjpeg_decoder_select="dsputil hpeldsp"
-mjpegb_decoder_select="dsputil hpeldsp"
+mjpeg_decoder_select="dsputil hpeldsp exif"
+mjpegb_decoder_select="dsputil hpeldsp exif"
mjpeg_encoder_select="aandcttables dsputil mpegvideoenc"
mlp_decoder_select="dsputil mlp_parser"
motionpixels_decoder_select="dsputil"
@@ -1645,20 +1859,19 @@ msmpeg4v2_encoder_select="h263_encoder"
msmpeg4v3_decoder_select="h263_decoder"
msmpeg4v3_encoder_select="h263_encoder"
mss2_decoder_select="error_resilience vc1_decoder"
-mxpeg_decoder_select="dsputil hpeldsp"
+mxpeg_decoder_select="dsputil hpeldsp exif"
nellymoser_decoder_select="mdct sinewin"
nellymoser_encoder_select="audio_frame_queue mdct sinewin"
nuv_decoder_select="dsputil lzo"
-png_decoder_deps="zlib"
-png_decoder_select="dsputil"
-png_encoder_deps="zlib"
-png_encoder_select="dsputil"
+png_decoder_select="zlib"
+png_encoder_select="dsputil zlib"
prores_decoder_select="dsputil"
prores_encoder_select="dsputil"
qcelp_decoder_select="lsp"
qdm2_decoder_select="mdct rdft mpegaudiodsp"
ra_144_encoder_select="audio_frame_queue lpc"
ralf_decoder_select="golomb"
+rtjpeg_decoder_select="dsputil"
rv10_decoder_select="error_resilience h263_decoder"
rv10_encoder_select="h263_encoder"
rv20_decoder_select="error_resilience h263_decoder"
@@ -1667,7 +1880,12 @@ rv30_decoder_select="error_resilience golomb h264chroma h264pred h264qpel mpegvi
rv40_decoder_select="error_resilience golomb h264chroma h264pred h264qpel mpegvideo videodsp"
shorten_decoder_select="golomb"
sipr_decoder_select="lsp"
-sp5x_decoder_select="dsputil hpeldsp"
+snow_decoder_select="dsputil dwt h264qpel hpeldsp rangecoder"
+snow_encoder_select="aandcttables dsputil dwt h264qpel hpeldsp mpegvideoenc rangecoder"
+sonic_decoder_select="golomb"
+sonic_encoder_select="golomb"
+sonic_ls_encoder_select="golomb"
+sp5x_decoder_select="dsputil hpeldsp exif"
svq1_decoder_select="hpeldsp"
svq1_encoder_select="aandcttables dsputil hpeldsp mpegvideoenc"
svq3_decoder_select="golomb h264chroma h264dsp h264pred h264qpel hpeldsp mpegvideo videodsp"
@@ -1676,11 +1894,11 @@ tak_decoder_select="dsputil"
theora_decoder_select="vp3_decoder"
tiff_decoder_suggest="zlib"
tiff_encoder_suggest="zlib"
-thp_decoder_select="dsputil hpeldsp"
-truehd_decoder_select="mlp_decoder"
+thp_decoder_select="dsputil hpeldsp exif"
+truehd_decoder_select="mlp_parser"
truemotion2_decoder_select="dsputil"
truespeech_decoder_select="dsputil"
-tscc_decoder_deps="zlib"
+tscc_decoder_select="zlib"
twinvq_decoder_select="mdct lsp sinewin"
utvideo_decoder_select="dsputil"
utvideo_encoder_select="dsputil huffman"
@@ -1695,6 +1913,7 @@ vp6_decoder_select="h264chroma hpeldsp huffman videodsp vp3dsp"
vp6a_decoder_select="vp6_decoder"
vp6f_decoder_select="vp6_decoder"
vp8_decoder_select="h264pred videodsp"
+vp9_decoder_select="videodsp"
webp_decoder_select="vp8_decoder"
wmapro_decoder_select="mdct sinewin"
wmav1_decoder_select="mdct sinewin"
@@ -1708,13 +1927,14 @@ wmv2_decoder_select="h263_decoder 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"
@@ -1725,34 +1945,53 @@ 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_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"
+mpeg1_vdpau_decoder_deps="vdpau"
+mpeg1_vdpau_decoder_select="mpeg1video_decoder"
mpeg1_vdpau_hwaccel_deps="vdpau"
mpeg1_vdpau_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"
+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
@@ -1762,17 +2001,21 @@ mpegvideo_parser_select="error_resilience mpegvideo"
vc1_parser_select="mpegvideo"
# 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"
@@ -1784,15 +2027,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"
@@ -1801,8 +2050,12 @@ libvpx_vp9_decoder_deps="libvpx"
libvpx_vp9_encoder_deps="libvpx"
libwavpack_encoder_deps="libwavpack"
libx264_encoder_deps="libx264"
+libx264rgb_encoder_deps="libx264"
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"
@@ -1815,6 +2068,8 @@ 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"
dxa_demuxer_select="riffdec"
eac3_demuxer_select="ac3_parser"
f4v_muxer_select="mov_muxer"
@@ -1822,6 +2077,8 @@ flac_demuxer_select="flac_parser"
hls_muxer_select="mpegts_muxer"
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"
@@ -1851,7 +2108,9 @@ spdif_muxer_select="aac_parser"
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"
@@ -1863,28 +2122,44 @@ xwma_demuxer_select="riffdec"
alsa_indev_deps="alsa_asoundlib_h snd_pcm_htimestamp"
alsa_outdev_deps="alsa_asoundlib_h"
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"
+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"
+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"
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"
+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"
-x11grab_indev_deps="x11grab XShmCreateImage"
+xv_outdev_deps="X11_extensions_Xvlib_h XvGetPortAttribute"
+xv_outdev_extralibs="-lXv -lX11 -lXext"
+x11grab_indev_deps="x11grab"
# 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"
httpproxy_protocol_select="tcp_protocol"
http_protocol_select="tcp_protocol"
@@ -1894,6 +2169,7 @@ librtmpe_protocol_deps="librtmp"
librtmps_protocol_deps="librtmp"
librtmpt_protocol_deps="librtmp"
librtmpte_protocol_deps="librtmp"
+libssh_protocol_deps="libssh"
mmsh_protocol_select="http_protocol"
mmst_protocol_select="network"
rtmp_protocol_deps="!librtmp_protocol"
@@ -1916,21 +2192,69 @@ unix_protocol_deps="sys_un_h"
unix_protocol_select="network"
# filters
+aconvert_filter_deps="swresample"
+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"
+colormatrix_filter_deps="gpl"
cropdetect_filter_deps="gpl"
+dctdnoiz_filter_deps="avcodec"
+dctdnoiz_filter_select="fft"
delogo_filter_deps="gpl"
+deshake_filter_deps="avcodec"
+deshake_filter_select="dsputil"
drawtext_filter_deps="libfreetype"
-frei0r_filter_deps="frei0r dlopen strtok_r"
+ebur128_filter_deps="gpl"
+flite_filter_deps="libflite"
+frei0r_filter_deps="frei0r dlopen"
frei0r_filter_extralibs='$ldl'
-frei0r_src_filter_deps="frei0r dlopen strtok_r"
+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"
+mcdeint_filter_deps="avcodec gpl"
+movie_filter_deps="avcodec avformat"
+mp_filter_deps="gpl avcodec swscale inline_asm"
+mpdecimate_filter_deps="gpl avcodec"
+mptestsrc_filter_deps="gpl"
+negate_filter_deps="lut_filter"
+perspective_filter_deps="gpl"
resample_filter_deps="avresample"
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"
+sab_filter_deps="gpl swscale"
scale_filter_deps="swscale"
+smartblur_filter_deps="gpl swscale"
+showspectrum_filter_deps="avcodec"
+showspectrum_filter_select="rdft"
+spp_filter_deps="gpl avcodec"
+spp_filter_select="fft"
+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"
yadif_filter_deps="gpl"
+pixfmts_super2xsai_test_deps="super2xsai_filter"
+tinterlace_merge_test_deps="tinterlace_filter"
+tinterlace_pad_test_deps="tinterlace_filter"
+zmq_filter_deps="libzmq"
# libraries
avcodec_deps="avutil"
@@ -1938,21 +2262,27 @@ avdevice_deps="avutil avcodec avformat"
avfilter_deps="avutil"
avformat_deps="avutil avcodec"
avresample_deps="avutil"
+postproc_deps="avutil gpl"
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_select="rdft"
-avprobe_deps="avcodec avformat"
-avserver_deps="avformat fork !shared"
-avserver_select="ffm_muxer rtp_protocol rtsp_demuxer"
-avserver_extralibs='$ldl'
-
-doc_deps="texi2html"
+ffplay_deps="avcodec avformat swscale swresample sdl"
+ffplay_select="rdft crop_filter"
+ffprobe_deps="avcodec avformat"
+ffserver_deps="avformat fork sarestart"
+ffserver_select="ffm_muxer rtp_protocol rtsp_demuxer"
+ffserver_extralibs='$ldl'
+
+# documentation
+podpages_deps="perl"
+manpages_deps="perl pod2man"
+htmlpages_deps="texi2html"
+txtpages_deps="makeinfo"
+doc_deps_any="manpages htmlpages podpages txtpages"
# default parameters
@@ -1961,8 +2291,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'
@@ -1971,15 +2301,17 @@ shlibdir_default="$libdir_default"
# toolchain
ar_default="ar"
cc_default="gcc"
+cxx_default="g++"
host_cc_default="gcc"
cp_f="cp -f"
+install="install"
ln_s="ln -s -f"
nm_default="nm -g"
objformat="elf"
pkg_config_default=pkg-config
ranlib="ranlib"
-strip="strip"
-yasmexe="yasm"
+strip_default="strip"
+yasmexe_default="yasm"
nogas=":"
@@ -1992,18 +2324,22 @@ target_os_default=$(tolower $(uname -s))
host_os=$target_os_default
# configurable options
-enable $LIBRARY_LIST $PROGRAM_LIST
+enable $PROGRAM_LIST
+enable $DOCUMENT_LIST
+enable $(filter_out avresample $LIBRARY_LIST)
+enable stripping
enable asm
enable debug
enable doc
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
+# Enable hwaccels by default.
+enable dxva2 vaapi vdpau
# build settings
SHFLAGS='-shared -Wl,-soname,$$(@F)'
@@ -2029,6 +2365,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'
@@ -2064,7 +2402,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(){
@@ -2184,7 +2522,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)
+ 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')
@@ -2205,6 +2545,8 @@ for opt do
;;
--help|-h) show_help
;;
+ --fatal-warnings) enable fatal_warnings
+ ;;
*)
optname="${opt%%=*}"
optname="${optname#--}"
@@ -2222,7 +2564,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
@@ -2234,13 +2576,16 @@ 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}"
+strip_default="${cross_prefix}${strip_default}"
sysinclude_default="${sysroot}/usr/include"
+test -n "$valgrind" && toolchain="valgrind-memcheck"
+
case "$toolchain" in
clang-asan)
cc_default="clang"
@@ -2263,12 +2608,12 @@ case "$toolchain" in
add_ldflags -fsanitize=thread -pie -fPIC
;;
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)
cc_default="c99wrap cl"
@@ -2297,7 +2642,7 @@ case "$toolchain" in
;;
esac
-set_default arch cc pkg_config sysinclude target_exec target_os
+set_default arch cc cxx pkg_config strip sysinclude target_exec target_os yasmexe
enabled cross_compile || host_cc_default=$cc
set_default host_cc
@@ -2320,7 +2665,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(){
@@ -2340,6 +2689,7 @@ trap 'rm -f -- $TMPFILES' EXIT
tmpfile TMPASM .asm
tmpfile TMPC .c
+tmpfile TMPCPP .cpp
tmpfile TMPE $EXESUF
tmpfile TMPH .h
tmpfile TMPO .o
@@ -2427,6 +2777,7 @@ msvc_flags(){
-Wall) echo -W4 -wd4244 -wd4127 -wd4018 -wd4389 \
-wd4146 -wd4057 -wd4204 -wd4706 -wd4305 \
-wd4152 -wd4324 -we4013 -wd4100 -wd4214 \
+ -wd4554 \
-wd4273 ;;
esac
done
@@ -2474,7 +2825,8 @@ suncc_flags(){
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 ;;
+ amdfam10|barcelona) echo -xtarget=barcelona ;;
+ bdver*) echo -xarch=avx ;;
athlon-4|athlon-[mx]p) echo -xarch=ssea ;;
k8|opteron|athlon64|athlon-fx)
echo -xarch=sse2a ;;
@@ -2629,7 +2981,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; then
_type=msvc
@@ -2655,6 +3007,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)
@@ -2773,6 +3126,7 @@ else
fi
add_cflags $extra_cflags
+add_cxxflags $extra_cxxflags
add_asflags $extra_cflags
if test -n "$sysroot"; then
@@ -2815,7 +3169,7 @@ case "$arch" in
aarch64|arm64)
arch="aarch64"
;;
- arm*)
+ arm*|iPad*|iPhone*)
arch="arm"
;;
mips*|IP*)
@@ -2839,7 +3193,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
@@ -2949,6 +3303,28 @@ 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
case $(tolower $cpu) in
@@ -3057,6 +3433,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>
@@ -3102,6 +3479,11 @@ case "$arch" in
spic=$shared
fi
;;
+ ppc)
+ check_cc <<EOF && subarch="ppc64"
+ int test[(int)sizeof(char*) - 7];
+EOF
+ ;;
esac
enable $subarch
@@ -3138,6 +3520,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
@@ -3154,12 +3537,14 @@ case $target_os in
;;
bsd/os)
add_extralibs -lpoll -lgnugetopt
+ strip="strip -d"
;;
darwin)
gas="gas-preprocessor.pl $cc"
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)'
@@ -3188,14 +3573,21 @@ case $target_os in
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
;;
@@ -3250,6 +3642,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
@@ -3270,6 +3663,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
@@ -3306,7 +3700,7 @@ case $target_os in
add_compat strtod.o strtod=avpriv_strtod
network_extralibs='-lbsd'
exeobjs=compat/plan9/main.o
- disable avserver
+ disable ffserver
cp_f='cp'
;;
none)
@@ -3336,6 +3730,13 @@ elif check_header _mingw.h; then
(__MINGW32_MAJOR_VERSION == 3 && __MINGW32_MINOR_VERSION >= 15)" ||
die "ERROR: MinGW runtime version must be >= 3.15."
add_cppflags -U__STRICT_ANSI__
+ if check_cpp_condition _mingw.h "defined(__MINGW64_VERSION_MAJOR) && \
+ __MINGW64_VERSION_MAJOR < 3"; then
+ add_compat msvcrt/snprintf.o
+ add_cflags "-include $source_path/compat/msvcrt/snprintf.h"
+ else
+ add_cppflags -D__USE_MINGW_ANSI_STDIO=1
+ fi
elif check_func_headers stdlib.h _get_doserrno; then
libc_type=msvcrt
add_compat strtod.o strtod=avpriv_strtod
@@ -3376,7 +3777,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
@@ -3394,19 +3795,32 @@ EOF
exit 1;
fi
+# backward compatibility layer for incompatible_libav/fork_abi
+enabled incompatible_fork_abi && enable incompatible_libav_abi
+enabled incompatible_libav_abi && enable incompatible_fork_abi
+
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 libutvideo
+die_license_disabled gpl libvidstab
die_license_disabled gpl libx264
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
@@ -3475,7 +3889,10 @@ if 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
nogas=die
@@ -3484,7 +3901,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
@@ -3511,6 +3928,14 @@ 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
@@ -3531,7 +3956,9 @@ elif enabled ppc; then
# AltiVec flags: The FSF version of GCC differs from the Apple version
if enabled altivec; then
- nogas=warn
+ if ! enabled_any pic ppc64; then
+ nogas=warn
+ fi
check_cflags -maltivec -mabi=altivec &&
{ check_header altivec.h && inc_altivec_h="#include <altivec.h>" ; } ||
check_cflags -faltivec
@@ -3601,6 +4028,7 @@ 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 "vextractf128 xmm0, ymm0, 0" || disable avx_external avresample
check_yasm "vfmaddps ymm0, ymm1, ymm2, ymm3" || disable fma4_external
check_yasm "CPU amdnop" && enable cpunop
fi
@@ -3671,6 +4099,8 @@ fi
# Solaris has nanosleep in -lrt, OpenSolaris no longer needs that
check_func nanosleep || { check_func nanosleep -lrt && add_extralibs -lrt; }
+check_func access
+check_func clock_gettime || { check_func clock_gettime -lrt && add_extralibs -lrt; }
check_func fcntl
check_func fork
check_func_headers stdlib.h getenv
@@ -3689,18 +4119,21 @@ check_func mprotect
check_func ${malloc_prefix}posix_memalign && enable posix_memalign
check_func_headers malloc.h _aligned_malloc && enable aligned_malloc
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 strtok_r
check_func sched_getaffinity
check_builtin sync_val_compare_and_swap "" "int *ptr; int oldval, newval; __sync_val_compare_and_swap(ptr, oldval, newval)"
check_builtin machine_rw_barrier mbarrier.h "__machine_rw_barrier()"
check_builtin atomic_cas_ptr atomic.h "void **ptr; void *oldval, *newval; atomic_cas_ptr(ptr, oldval, newval)"
check_builtin MemoryBarrier windows.h "MemoryBarrier()"
+check_builtin sarestart signal.h "SA_RESTART"
check_func sysconf
check_func sysctl
check_func usleep
+check_func_headers conio.h kbhit
+check_func_headers windows.h PeekNamedPipe
check_func_headers io.h setmode
+check_func_headers lzo/lzo1x.h lzo1x_999_compress
check_lib2 "windows.h shellapi.h" CommandLineToArgvW -lshell32
check_lib2 "windows.h wincrypt.h" CryptGenRandom -ladvapi32
check_lib2 "windows.h psapi.h" GetProcessMemoryInfo -lpsapi
@@ -3711,12 +4144,16 @@ check_func_headers windows.h MapViewOfFile
check_func_headers windows.h SetConsoleTextAttribute
check_func_headers windows.h Sleep
check_func_headers windows.h VirtualAlloc
+check_func_headers glob.h glob
+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 malloc.h
check_header poll.h
check_header sys/mman.h
@@ -3725,12 +4162,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
disabled zlib || check_lib zlib.h zlibVersion -lz || disable zlib
disabled bzlib || check_lib2 bzlib.h BZ2_bzlibVersion -lbz2 || disable bzlib
@@ -3741,7 +4180,7 @@ 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_create; then
:
@@ -3766,12 +4205,16 @@ for thread in $THREADS_LIST; do
fi
done
+if enabled pthreads; then
+ check_func pthread_cancel
+fi
+
enabled sync_val_compare_and_swap && enable atomics_gcc
enabled_all atomic_cas_ptr machine_rw_barrier && enable atomics_suncc
enabled MemoryBarrier && enable atomics_win32
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
@@ -3782,43 +4225,90 @@ for func in $MATH_FUNCS; do
done
# these are off by default, so fail if requested and not available
-enabled avisynth && require2 vfw32 "windows.h vfw.h" AVIFileInit -lavifil32
+enabled avisynth && { { check_lib2 "windows.h" LoadLibrary; } ||
+ { check_lib2 "dlfcn.h" dlopen -ldl; } ||
+ die "ERROR: LoadLibrary/dlopen not found for avisynth"; }
+enabled fontconfig && require_pkg_config fontconfig "fontconfig/fontconfig.h" FcInit
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 libbluray libbluray/bluray.h bd_open -lbluray
+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 libfreetype && require_pkg_config freetype2 "ft2build.h freetype/freetype.h" FT_Init_FreeType
+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 libmodplug libmodplug/modplug.h ModPlug_Load -lmodplug
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 && require libopenjpeg openjpeg.h opj_version -lopenjpeg
+enabled libopencv && require_pkg_config opencv opencv/cxcore.h cvCreateImageHeader
+enabled libopenjpeg && { check_lib openjpeg-1.5/openjpeg.h opj_version -lopenjpeg ||
+ check_lib openjpeg.h opj_version -lopenjpeg ||
+ 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 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 libsoxr && require libsoxr soxr.h soxr_create -lsoxr
+enabled libssh && require_pkg_config libssh libssh/sftp.h sftp_init
enabled libspeex && require libspeex 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 &&
+ { 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 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 libwavpack && require libwavpack wavpack/wavpack.h WavpackOpenFileOutput -lwavpack
enabled libx264 && require libx264 x264.h x264_encoder_encode -lx264 &&
{ 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 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"; } &&
+ { ! enabled_any w32threads os2threads ||
+ die "opencl currently needs --enable-pthreads or --disable-w32threads"; } &&
+ { 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 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 ||
@@ -3838,17 +4328,33 @@ if enabled libdc1394; then
die "ERROR: No version of libdc1394 found "
fi
+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
+ fi
fi
+enabled sdl && add_cflags $sdl_cflags && add_extralibs $sdl_libs
-texi2html -version > /dev/null 2>&1 && enable texi2html || disable texi2html
+texi2html --help 2> /dev/null | grep -q 'init-file' && enable texi2html || disable texi2html
+makeinfo --version > /dev/null 2>&1 && enable makeinfo || disable makeinfo
+perl --version > /dev/null 2>&1 && enable perl || disable perl
+pod2man --help > /dev/null 2>&1 && enable pod2man || disable pod2man
+rsync --help 2> /dev/null | grep -q 'contimeout' && enable rsync_contimeout || disable rsync_contimeout
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
@@ -3857,6 +4363,8 @@ check_func_headers "windows.h vfw.h" capCreateCaptureWindow "$vfwcap_indev_extra
# 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; } ||
@@ -3867,20 +4375,28 @@ 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
enabled x11grab &&
@@ -3888,10 +4404,17 @@ require X11 X11/Xlib.h XOpenDisplay -lX11 &&
require Xext X11/extensions/XShm.h XShmCreateImage -lXext &&
require Xfixes X11/extensions/Xfixes.h XFixesGetCursorImage -lXfixes
+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
+# 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
@@ -3904,17 +4427,17 @@ check_cflags -Wdisabled-optimization
check_cflags -Wpointer-arith
check_cflags -Wredundant-decls
check_cflags -Wno-pointer-sign
-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
enabled extra_warnings && check_cflags -Winline
# 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
test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic
enabled xmm_clobber_test &&
@@ -3923,6 +4446,7 @@ 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,sws_scale ||
@@ -3967,17 +4491,25 @@ 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
@@ -4000,7 +4532,6 @@ elif enabled gcc; then
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
enabled extra_warnings || check_cflags -Wno-maybe-uninitialized
elif enabled llvm_gcc; then
@@ -4038,6 +4569,7 @@ elif enabled_any msvc icl; then
add_cflags -Qansi-alias
# icl will pass the inline asm tests but inline asm is currently
# not supported (build will fail)
+ disabled inline_asm || warn "inline asm disabled due to issues with it in ICL"
disable inline_asm
fi
fi
@@ -4051,9 +4583,12 @@ case $target_os in
;;
esac
+enable frame_thread_encoder
enabled_any $THREADS_LIST && enable threads
enabled_any $ATOMICS_LIST && enable atomics_native
+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"
+
enabled asm || { arch=c; disable $ARCH_LIST $ARCH_EXT_LIST; }
check_deps $CONFIG_LIST \
@@ -4061,9 +4596,42 @@ check_deps $CONFIG_LIST \
$HAVE_LIST \
$ALL_COMPONENTS \
+
+if test $target_os = "haiku"; then
+ disable memalign
+ disable posix_memalign
+fi
+
! enabled_any memalign posix_memalign aligned_malloc &&
enabled_any $need_memalign && 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
+
echo "install prefix $prefix"
echo "source path $source_path"
echo "C compiler $cc"
@@ -4071,6 +4639,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
@@ -4097,6 +4668,13 @@ 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}"
@@ -4107,15 +4685,23 @@ if enabled sparc; then
echo "VIS enabled ${vis-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 "libzvbi enabled ${libzvbi-no}"
+echo "texi2html enabled ${texi2html-no}"
+echo "perl enabled ${perl-no}"
+echo "pod2man enabled ${pod2man-no}"
+echo "makeinfo enabled ${makeinfo-no}"
test -n "$random_seed" &&
echo "random seed ${random_seed}"
echo
@@ -4144,15 +4730,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 || $ln_s "$source_path/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
@@ -4162,9 +4752,13 @@ 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
CC=$cc
+CXX=$cxx
AS=$as
LD=$ld
DEPCC=$dep_cc
@@ -4178,15 +4772,19 @@ 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
@@ -4195,6 +4793,7 @@ LDFLAGS=$LDFLAGS
SHFLAGS=$(echo $($ldflags_filter $SHFLAGS))
YASMFLAGS=$YASMFLAGS
BUILDSUF=$build_suffix
+PROGSSUF=$progs_suffix
FULLNAME=$FULLNAME
LIBPREF=$LIBPREF
LIBSUF=$LIBSUF
@@ -4204,6 +4803,7 @@ SLIBSUF=$SLIBSUF
EXESUF=$EXESUF
EXTRA_VERSION=$extra_version
CCDEP=$CCDEP
+CXXDEP=$CXXDEP
CCDEP_FLAGS=$CCDEP_FLAGS
ASDEP=$ASDEP
ASDEP_FLAGS=$ASDEP_FLAGS
@@ -4227,14 +4827,14 @@ HOSTLD_O=$HOSTLD_O
TARGET_EXEC=$target_exec $target_exec_args
TARGET_PATH=$target_path
TARGET_SAMPLES=${target_samples:-\$(SAMPLES)}
-LIBS-avplay=$sdl_libs
-CFLAGS-avplay=$sdl_cflags
+LIBS-ffplay=$sdl_libs
+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}
@@ -4245,7 +4845,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(){
@@ -4263,18 +4864,23 @@ map 'get_version $v' $LIBRARY_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 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 SLIBSUF "$SLIBSUF"
+#define HAVE_MMX2 HAVE_MMXEXT
EOF
+test -n "$assert_level" &&
+ echo "#define ASSERT_LEVEL $assert_level" >>$TMPH
+
test -n "$malloc_prefix" &&
echo "#define MALLOC_PREFIX $malloc_prefix" >>$TMPH
@@ -4285,13 +4891,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
@@ -4311,7 +4922,10 @@ 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
@@ -4324,7 +4938,7 @@ pkgconfig_generate(){
requires=$5
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
@@ -4340,31 +4954,67 @@ Libs: -L\${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
}
-lavfi_libs="libavutil = $LIBAVUTIL_VERSION"
-enabled movie_filter && prepend lavfi_libs "libavformat >= $LIBAVFORMAT_VERSION, libavcodec >= $LIBAVCODEC_VERSION,"
-enabled resample_filter && prepend lavfi_libs "libavresample >= $LIBAVRESAMPLE_VERSION,"
-enabled scale_filter && prepend lavfi_libs "libswscale >= $LIBSWSCALE_VERSION,"
+lavfi_libs="libavutil${build_suffix} = $LIBAVUTIL_VERSION"
+enabled libavfilter_deps_avcodec && prepend lavfi_libs "libavcodec${build_suffix} = $LIBAVCODEC_VERSION,"
+enabled libavfilter_deps_avformat && prepend lavfi_libs "libavformat${build_suffix} = $LIBAVFORMAT_VERSION,"
+enabled libavfilter_deps_avresample && prepend lavfi_libs "libavresample${build_suffix} = $LIBAVRESAMPLE_VERSION,"
+enabled libavfilter_deps_swscale && prepend lavfi_libs "libswscale${build_suffix} = $LIBSWSCALE_VERSION,"
+enabled libavfilter_deps_swresample && prepend lavfi_libs "libswresample${build_suffix} = $LIBSWRESAMPLE_VERSION,"
+enabled libavfilter_deps_postproc && prepend lavfi_libs "libpostproc${build_suffix} = $LIBPOSTPROC_VERSION,"
+lavfi_libs=${lavfi_libs%, }
+
+lavd_libs="libavformat${build_suffix} = $LIBAVFORMAT_VERSION"
+enabled lavfi_indev && prepend lavd_libs "libavfilter${build_suffix} = $LIBAVFILTER_VERSION,"
+
+pkgconfig_generate libavutil "FFmpeg utility library" "$LIBAVUTIL_VERSION" "$LIBM"
+pkgconfig_generate libavcodec "FFmpeg codec library" "$LIBAVCODEC_VERSION" "$extralibs" "libavutil${build_suffix} = $LIBAVUTIL_VERSION"
+pkgconfig_generate libavformat "FFmpeg container format library" "$LIBAVFORMAT_VERSION" "$extralibs" "libavcodec${build_suffix} = $LIBAVCODEC_VERSION"
+pkgconfig_generate libavdevice "FFmpeg device handling library" "$LIBAVDEVICE_VERSION" "$extralibs" "$lavd_libs"
+pkgconfig_generate libavfilter "FFmpeg audio/video filtering library" "$LIBAVFILTER_VERSION" "$extralibs" "$lavfi_libs"
+pkgconfig_generate libpostproc "FFmpeg postprocessing library" "$LIBPOSTPROC_VERSION" "" "libavutil${build_suffix} = $LIBAVUTIL_VERSION"
+pkgconfig_generate libavresample "Libav audio resampling library" "$LIBAVRESAMPLE_VERSION" "$extralibs" "libavutil${build_suffix} = $LIBAVUTIL_VERSION"
+pkgconfig_generate libswscale "FFmpeg image rescaling library" "$LIBSWSCALE_VERSION" "$LIBM" "libavutil${build_suffix} = $LIBAVUTIL_VERSION"
+pkgconfig_generate libswresample "FFmpeg audio resampling library" "$LIBSWRESAMPLE_VERSION" "$LIBM" "libavutil${build_suffix} = $LIBAVUTIL_VERSION"
+
+fix_ffmpeg_remote(){
+ git_remote_from=$1
+ git_remote_to=$2
+ fixme_remote=$(git --git-dir=$source_path/.git --work-tree=$source_path remote -v | grep $git_remote_from | cut -f 1 | sort | uniq)
+ if [ "$fixme_remote" != "" ]; then
+ echolog "
+Outdated domain in git config, the official domain for ffmpeg git is since
+November 2011, source.ffmpeg.org, both the old and the new point to the same
+repository and server. To update it enter the following commands:
+"
+ for remote in $fixme_remote; do
+ echolog "git remote set-url $remote $git_remote_to"
+ done
+ fi
+}
-pkgconfig_generate libavutil "Libav utility library" "$LIBAVUTIL_VERSION" "$LIBM"
-pkgconfig_generate libavcodec "Libav codec library" "$LIBAVCODEC_VERSION" "$extralibs" "libavutil = $LIBAVUTIL_VERSION"
-pkgconfig_generate libavformat "Libav container format library" "$LIBAVFORMAT_VERSION" "$extralibs" "libavcodec = $LIBAVCODEC_VERSION"
-pkgconfig_generate libavdevice "Libav device handling library" "$LIBAVDEVICE_VERSION" "$extralibs" "libavformat = $LIBAVFORMAT_VERSION"
-pkgconfig_generate libavfilter "Libav video filtering library" "$LIBAVFILTER_VERSION" "$extralibs" "$lavfi_libs"
-pkgconfig_generate libavresample "Libav audio resampling library" "$LIBAVRESAMPLE_VERSION" "$extralibs" "libavutil = $LIBAVUTIL_VERSION"
-pkgconfig_generate libswscale "Libav image rescaling library" "$LIBSWSCALE_VERSION" "$LIBM" "libavutil = $LIBAVUTIL_VERSION"
+if test -f "$source_path/.git/config"; then
+ remote_from=git.videolan.org
+ remote_to=source.ffmpeg.org
+ fix_ffmpeg_remote git@$remote_from:ffmpeg git@$remote_to:ffmpeg
+ fix_ffmpeg_remote git://$remote_from/ffmpeg git://$remote_to/ffmpeg
+fi
diff --git a/doc/APIchanges b/doc/APIchanges
index 20fb16e..456b35c 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: 2013-03-xx
@@ -7,12 +7,34 @@ libavdevice: 2013-03-xx
libavfilter: 2012-06-22
libavformat: 2013-03-xx
libavresample: 2012-10-05
+libpostproc: 2011-04-18
+libswresample: 2011-09-19
libswscale: 2011-06-20
libavutil: 2012-10-22
API changes, most recent first:
+2013-10-27 - xxxxxxx - lavc 55.39.100 - avcodec.h
+ Add CODEC_CAP_DELAY support to avcodec_decode_subtitle2.
+
+2013-10-27 - xxxxxxx - lavu 52.48.100 - parseutils.h
+ Add av_get_known_color_name().
+
+2013-10-17 - xxxxxxx - 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-xx - xxxxxxx -libswscale 2.5.101 - options.c
+ Change default scaler to bicubic
+
+2013-10-03 - xxxxxxx - lavc 55.34.100 - avcodec.h
+ Add av_codec_get_max_lowres()
+
+2013-10-02 - xxxxxxx - lavf 55.19.100 - avformat.h
+ Add audio/video/subtitle AVCodec fields to AVFormatContext to force specific
+ decoders
+
2013-08-xx - xxxxxxx - lavfi 3.11.0 - avfilter.h
Add AVFilterGraph.execute and AVFilterGraph.opaque for custom slice threading
implementations.
@@ -21,92 +43,297 @@ API changes, most recent first:
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 - 36cd017 - 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-xx - xxxxxxx - lavc 55.27.100 - vdpau.h
+ Add a render2 alternative to the render callback function.
+
+2013-08-xx - xxxxxxx - 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.
-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()
+
+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.
+
+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.
+
+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.
+
+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()
@@ -124,64 +351,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.
-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.
@@ -189,23 +415,23 @@ 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-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.
@@ -213,101 +439,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()
@@ -319,137 +534,155 @@ 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-02-09 - c28e7af - lavu 51.39.100
+ Add a new installed header libavutil/timestamp.h with timestamp
+ utilities.
-2012-03-20 - 3c90cc2 - lavfo 54.2.0
+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
+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-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-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:
@@ -457,220 +690,364 @@ 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().
-------------------------------8<-------------------------------------
- 0.7 branch was cut here
------------------------------>8--------------------------------------
+2011-06-28 - 5129336 - lavu 51.11.0 - avutil.h
+ Define the AV_PICTURE_TYPE_NONE value in AVPictureType enum.
+
+2011-06-19 - fd2c0a5 - lavfi 2.23.0 - avfilter.h
+ Add layout negotiation fields and helper functions.
-2011-06-16 - 05e84c9, 25de595 - lavf 53.2.0 - avformat.h
+ 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
@@ -691,9 +1068,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
@@ -726,11 +1106,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.
@@ -760,6 +1140,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.
diff --git a/doc/Doxyfile b/doc/Doxyfile
index ae65478..6488aad 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,15 +639,14 @@ EXCLUDE_SYMBOLS =
# directories that contain example code fragments that are included (see
# the \include command).
-EXAMPLE_PATH = libavcodec/ \
- libavformat/
+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
@@ -710,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
@@ -794,13 +793,13 @@ HTML_FILE_EXTENSION = .html
# each generated HTML page. If it is left blank doxygen will generate a
# standard header.
-HTML_HEADER = doc/doxy/header.html
+#HTML_HEADER = doc/doxy/header.html
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
# each generated HTML page. If it is left blank doxygen will generate a
# standard footer.
-HTML_FOOTER = doc/doxy/footer.html
+#HTML_FOOTER = doc/doxy/footer.html
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
# style sheet that is used by each HTML page. It can be used to
@@ -809,7 +808,7 @@ HTML_FOOTER = doc/doxy/footer.html
# the style sheet file to the HTML output directory, so don't put your own
# stylesheet in the HTML output directory as well, or it will be erased!
-HTML_STYLESHEET = doc/doxy/doxy_stylesheet.css
+#HTML_STYLESHEET = doc/doxy/doxy_stylesheet.css
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
# Doxygen will adjust the colors in the stylesheet and background images
@@ -819,7 +818,7 @@ HTML_STYLESHEET = doc/doxy/doxy_stylesheet.css
# 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
diff --git a/doc/Makefile b/doc/Makefile
index 81f098e..50a68b4 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -1,72 +1,137 @@
-MANPAGES = $(PROGS-yes:%=doc/%.1)
-PODPAGES = $(PROGS-yes:%=doc/%.pod)
-HTMLPAGES = $(PROGS-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 = $(PROGS-yes:%=doc/%.1) $(PROGS-yes:%=doc/%-all.1) $(COMPONENTS-yes:%=doc/%.1)
+MANPAGES3 = $(LIBRARIES-yes:%=doc/%.3)
+MANPAGES = $(MANPAGES1) $(MANPAGES3)
+PODPAGES = $(PROGS-yes:%=doc/%.pod) $(PROGS-yes:%=doc/%-all.pod) $(COMPONENTS-yes:%=doc/%.pod) $(LIBRARIES-yes:%=doc/%.pod)
+HTMLPAGES = $(PROGS-yes:%=doc/%.html) $(PROGS-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 = $(HTMLPAGES) $(MANPAGES) $(PODPAGES)
+TXTPAGES = doc/fate.txt \
-all-$(CONFIG_DOC): documentation
+
+DOCS-$(CONFIG_HTMLPAGES) += $(HTMLPAGES)
+DOCS-$(CONFIG_PODPAGES) += $(PODPAGES)
+DOCS-$(CONFIG_MANPAGES) += $(MANPAGES)
+DOCS-$(CONFIG_TXTPAGES) += $(TXTPAGES)
+DOCS = $(DOCS-yes)
+
+all-$(CONFIG_DOC): doc
+
+doc: documentation
apidoc: doc/doxy/html
documentation: $(DOCS)
-TEXIDEP = awk '/^@include/ { printf "$@: $(@D)/%s\n", $$2 }' <$< >$(@:%=%.d)
+TEXIDEP = awk '/^@(verbatim)?include/ { printf "$@: $(@D)/%s\n", $$2 }' <$< >$(@:%=%.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)
$(GENTEXI): TAG = GENTEXI
-$(GENTEXI): doc/avoptions_%.texi: doc/print_options
+$(GENTEXI): doc/avoptions_%.texi: doc/print_options$(HOSTEXESUF)
$(M)doc/print_options $* > $@
doc/%.html: TAG = HTML
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: TAG = HTML
+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 $@ $<
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/%-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: TAG = MAN
+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/doxy/html: $(SRC_PATH)/doc/Doxyfile $(INSTHEADERS)
$(M)$(SRC_PATH)/doc/doxy-wrapper.sh $(SRC_PATH) $^
-install-progs-$(CONFIG_DOC): install-doc install-man
+install-doc: install-html install-man
+
+install-html:
+
+install-man:
+
+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/",$(PROGS-yes:%=%.1) $(PROGS-yes:%=%-all.1) $(COMPONENTS-yes:%=%.1))
+ $(RM) $(addprefix "$(MANDIR)/man3/",$(LIBRARIES-yes:%=%.3))
+
+clean:: docclean
+
+distclean:: docclean
+ $(RM) doc/config.texi
-clean::
- $(RM) doc/*.html doc/*.pod doc/*.1 $(CLEANSUFFIXES:%=doc/%) doc/avoptions_*.texi
+docclean:
+ $(RM) $(TXTPAGES) doc/*.html doc/*.pod doc/*.1 doc/*.3 $(CLEANSUFFIXES:%=doc/%) 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
index 62207c6..fae3a2b 100644
--- a/doc/RELEASE_NOTES
+++ b/doc/RELEASE_NOTES
@@ -1,101 +1,16 @@
Release Notes
=============
-* 9 "Plain Nine"
+* 2.1 "Fourier" October, 2013
+
General notes
-------------
+See the Changelog file for a list of significant changes. Note, there
+are many more new features and bugfixes than whats listed there.
-From this release onwards, we have decided to drop the leading zero from our
-release numbers. There were no plans of ever changing it, so it carried no
-information. Thus this release is just a plain 9, the next will be 10 etc.
-
-A new library arrived in Libav during this development cycle -- its name is
-libavresample and it handles audio conversion and mixing. All users are
-encouraged to use it instead of the old, now deprecated, audio conversion
-API in libavcodec.
-
-The libpostproc library now resides in a separate tree. It was fully independent
-of the other Libav libraries, not used by any of the tools and saw very little
-development. For these reasons we decided that it has no place in Libav. A
-standalone Git tree is available at http://git.videolan.org/?p=libpostproc.git
-for people wishing to use libpostproc.
-
-The major versions of the libavcodec, libavformat and libavfilter libraries have
-been bumped, so they are not API or ABI compatible with the 0.8 release. The
-ffmpeg transcoding tool, kept for compatibility in 0.8, has also been dropped.
-
-This release brings a number of significant changes in the libavfilter library.
-Firstly, all the API dealing with filter internals is no longer public. The
-result is that creating user-side filters will not be supported until
-libavfilter is more mature.
-Secondly, full audio filtering support is now available along with a set of
-basic audio filters. We hope that their number will soon grow significantly.
-The avconv transcoding tool has of course been extended to handle audio
-filtering as well.
-There were a number of other API changes, most importantly the addition of
-the buffer sink public API.
-
-In the libavcodec library, one of the most notable changes is added support for
-planar audio (i.e. not interleaved). Many decoders and encoders, that previously
-did inefficient (de)interleaving internally, now only work with planar audio
-formats. Libavresample can be used for optimized conversion between interleaved
-and planar formats.
-
-Of big interest to our Windows users, Libav now supports building with the MSVC
-compiler. Since MSVC does not support C99 features used extensively by Libav,
-this has been accomplished using a converter that turns C99 code to C89. See the
-platform-specific documentation for more detailed documentation on building
-Libav with MSVC.
-
-As usual, this release also contains support for some new formats, many smaller
-new features and countless bug fixes. We can highlight Opus decoding / encoding
-through libopus, encoders for Apple ProRes and Ut Video, WMA Lossless and
-RealAudio Lossless decoders, fragmented MOV/MP4 and ISMV (Smooth Streaming)
-muxers, 24-bit FLAC encoding, a large number of RTMP improvements and support
-for cover art in ID3v2, WMA, MP4 and FLAC.
-
-See the Changelog file for a list of significant changes.
-
-Please note that our policy on bug reports has not changed. We still only accept
-bug reports against HEAD of the Libav trunk repository. If you are experiencing
-issues with any formally released version of Libav, please try a current version
-of the development code to check if the issue still exists. If it does, make
-your report against the development code following the usual bug reporting
+Bugreports against FFmpeg git master or the most recent FFmpeg release are
+accepted. If you are experiencing issues with any formally released version of
+FFmpeg, please try git master to check if the issue still exists. If it does,
+make your report against the development code following the usual bug reporting
guidelines.
-
-
-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]:
-* New video encoding API, similar to the previously introduced audio encoding
- API, which encodes from an AVFrame to an AVPacket, thus allowing it to
- properly output timing information and side data.
-
-* All CODEC_ID_* symbols now carry AV_ prefixes. Non-prefixed codec IDs are
- deprecated.
-
-* New codec descriptor API, which allows getting the properties of a given codec
- (identified by its ID), without referring to a specific decoder or encoder.
-
-* An AVFrame must now be freed with a dedicated function, avcodec_free_frame().
-
-[libavutil]:
-* New audio FIFO API, which simplifies managing/merging/splitting audio buffers.
-
-* new int/float type punning API
-
-[libavfilter]:
-* All filter internals were hidden.
-
-* audio filtering.
-
-* new buffer sink API for getting frames out of libavfilter.
-
-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
--- a/dev/null
+++ b/doc/authors.texi
@@ -0,0 +1,11 @@
+@chapter Authors
+
+The FFmpeg developers.
+
+For details about the authorship, see the Git history of the project
+(git://source.ffmpeg.org/ffmpeg), e.g. by typing the command
+@command{git log} in the FFmpeg source directory, or browsing the
+online repository at @url{http://source.ffmpeg.org}.
+
+Maintainers for the specific components are listed in the file
+@file{MAINTAINERS} in the source code tree.
diff --git a/doc/avconv.texi b/doc/avconv.texi
deleted file mode 100644
index 714b0e7..0000000
--- a/doc/avconv.texi
+++ b/dev/null
@@ -1,1112 +0,0 @@
-\input texinfo @c -*- texinfo -*-
-
-@settitle avconv Documentation
-@titlepage
-@center @titlefont{avconv Documentation}
-@end titlepage
-
-@top
-
-@contents
-
-@chapter Synopsis
-
-The generic syntax is:
-
-@example
-@c man begin SYNOPSIS
-avconv [global options] [[infile options][@option{-i} @var{infile}]]... @{[outfile options] @var{outfile}@}...
-@c man end
-@end example
-
-@chapter Description
-@c man begin DESCRIPTION
-
-avconv is a very fast video and audio converter that can also grab from
-a live audio/video source. It can also convert between arbitrary sample
-rates and resize video on the fly with a high quality polyphase filter.
-
-avconv reads from an arbitrary number of input "files" (which can be regular
-files, pipes, network streams, grabbing devices, etc.), specified by the
-@code{-i} option, and writes to an arbitrary number of output "files", which are
-specified by a plain output filename. Anything found on the command line which
-cannot be interpreted as an option is considered to be an output filename.
-
-Each input or output file can in principle contain any number of streams of
-different types (video/audio/subtitle/attachment/data). Allowed number and/or
-types of streams can be limited by the container format. Selecting, which
-streams from which inputs go into output, is done either automatically or with
-the @code{-map} option (see the Stream selection chapter).
-
-To refer to input files in options, you must use their indices (0-based). E.g.
-the first input file is @code{0}, the second is @code{1} etc. Similarly, streams
-within a file are referred to by their indices. E.g. @code{2:3} refers to the
-fourth stream in the third input file. See also the Stream specifiers chapter.
-
-As a general rule, options are applied to the next specified
-file. Therefore, order is important, and you can have the same
-option on the command line multiple times. Each occurrence is
-then applied to the next input or output file.
-Exceptions from this rule are the global options (e.g. verbosity level),
-which should be specified first.
-
-Do not mix input and output files -- first specify all input files, then all
-output files. Also do not mix options which belong to different files. All
-options apply ONLY to the next input or output file and are reset between files.
-
-@itemize
-@item
-To set the video bitrate of the output file to 64kbit/s:
-@example
-avconv -i input.avi -b 64k output.avi
-@end example
-
-@item
-To force the frame rate of the output file to 24 fps:
-@example
-avconv -i input.avi -r 24 output.avi
-@end example
-
-@item
-To force the frame rate of the input file (valid for raw formats only)
-to 1 fps and the frame rate of the output file to 24 fps:
-@example
-avconv -r 1 -i input.m2v -r 24 output.avi
-@end example
-@end itemize
-
-The format option may be needed for raw input files.
-
-@c man end DESCRIPTION
-
-@chapter Detailed description
-@c man begin DETAILED DESCRIPTION
-
-The transcoding process in @command{avconv} for each output can be described by
-the following diagram:
-
-@example
- _______ ______________ _________ ______________ ________
-| | | | | | | | | |
-| input | demuxer | encoded data | decoder | decoded | encoder | encoded data | muxer | output |
-| file | ---------> | packets | ---------> | frames | ---------> | packets | -------> | file |
-|_______| |______________| |_________| |______________| |________|
-
-@end example
-
-@command{avconv} calls the libavformat library (containing demuxers) to read
-input files and get packets containing encoded data from them. When there are
-multiple input files, @command{avconv} tries to keep them synchronized by
-tracking lowest timestamp on any active input stream.
-
-Encoded packets are then passed to the decoder (unless streamcopy is selected
-for the stream, see further for a description). The decoder produces
-uncompressed frames (raw video/PCM audio/...) which can be processed further by
-filtering (see next section). After filtering the frames are passed to the
-encoder, which encodes them and outputs encoded packets again. Finally those are
-passed to the muxer, which writes the encoded packets to the output file.
-
-@section Filtering
-Before encoding, @command{avconv} can process raw audio and video frames using
-filters from the libavfilter library. Several chained filters form a filter
-graph. @command{avconv} distinguishes between two types of filtergraphs -
-simple and complex.
-
-@subsection Simple filtergraphs
-Simple filtergraphs are those that have exactly one input and output, both of
-the same type. In the above diagram they can be represented by simply inserting
-an additional step between decoding and encoding:
-
-@example
- _________ __________ ______________
-| | | | | |
-| decoded | simple filtergraph | filtered | encoder | encoded data |
-| frames | -------------------> | frames | ---------> | packets |
-|_________| |__________| |______________|
-
-@end example
-
-Simple filtergraphs are configured with the per-stream @option{-filter} option
-(with @option{-vf} and @option{-af} aliases for video and audio respectively).
-A simple filtergraph for video can look for example like this:
-
-@example
- _______ _____________ _______ _____ ________
-| | | | | | | | | |
-| input | ---> | deinterlace | ---> | scale | ---> | fps | ---> | output |
-|_______| |_____________| |_______| |_____| |________|
-
-@end example
-
-Note that some filters change frame properties but not frame contents. E.g. the
-@code{fps} filter in the example above changes number of frames, but does not
-touch the frame contents. Another example is the @code{setpts} filter, which
-only sets timestamps and otherwise passes the frames unchanged.
-
-@subsection Complex filtergraphs
-Complex filtergraphs are those which cannot be described as simply a linear
-processing chain applied to one stream. This is the case e.g. when the graph has
-more than one input and/or output, or when output stream type is different from
-input. They can be represented with the following diagram:
-
-@example
- _________
-| |
-| input 0 |\ __________
-|_________| \ | |
- \ _________ /| output 0 |
- \ | | / |__________|
- _________ \| complex | /
-| | | |/
-| input 1 |---->| filter |\
-|_________| | | \ __________
- /| graph | \ | |
- / | | \| output 1 |
- _________ / |_________| |__________|
-| | /
-| input 2 |/
-|_________|
-
-@end example
-
-Complex filtergraphs are configured with the @option{-filter_complex} option.
-Note that this option is global, since a complex filtergraph by its nature
-cannot be unambiguously associated with a single stream or file.
-
-A trivial example of a complex filtergraph is the @code{overlay} filter, which
-has two video inputs and one video output, containing one video overlaid on top
-of the other. Its audio counterpart is the @code{amix} filter.
-
-@section Stream copy
-Stream copy is a mode selected by supplying the @code{copy} parameter to the
-@option{-codec} option. It makes @command{avconv} omit the decoding and encoding
-step for the specified stream, so it does only demuxing and muxing. It is useful
-for changing the container format or modifying container-level metadata. The
-diagram above will in this case simplify to this:
-
-@example
- _______ ______________ ________
-| | | | | |
-| input | demuxer | encoded data | muxer | output |
-| file | ---------> | packets | -------> | file |
-|_______| |______________| |________|
-
-@end example
-
-Since there is no decoding or encoding, it is very fast and there is no quality
-loss. However it might not work in some cases because of many factors. Applying
-filters is obviously also impossible, since filters work on uncompressed data.
-
-@c man end DETAILED DESCRIPTION
-
-@chapter Stream selection
-@c man begin STREAM SELECTION
-
-By default avconv tries to pick the "best" stream of each type present in input
-files and add them to each output file. For video, this means the highest
-resolution, for audio the highest channel count. For subtitle it's simply the
-first subtitle stream.
-
-You can disable some of those defaults by using @code{-vn/-an/-sn} options. For
-full manual control, use the @code{-map} option, which disables the defaults just
-described.
-
-@c man end STREAM SELECTION
-
-@chapter Options
-@c man begin OPTIONS
-
-@include avtools-common-opts.texi
-
-@section Main options
-
-@table @option
-
-@item -f @var{fmt} (@emph{input/output})
-Force input or output file format. The format is normally autodetected for input
-files and guessed from file extension for output files, so this option is not
-needed in most cases.
-
-@item -i @var{filename} (@emph{input})
-input file name
-
-@item -y (@emph{global})
-Overwrite output files without asking.
-
-@item -n (@emph{global})
-Immediately exit when output files already exist.
-
-@item -c[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream})
-@itemx -codec[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream})
-Select an encoder (when used before an output file) or a decoder (when used
-before an input file) for one or more streams. @var{codec} is the name of a
-decoder/encoder or a special value @code{copy} (output only) to indicate that
-the stream is not to be reencoded.
-
-For example
-@example
-avconv -i INPUT -map 0 -c:v libx264 -c:a copy OUTPUT
-@end example
-encodes all video streams with libx264 and copies all audio streams.
-
-For each stream, the last matching @code{c} option is applied, so
-@example
-avconv -i INPUT -map 0 -c copy -c:v:1 libx264 -c:a:137 libvorbis OUTPUT
-@end example
-will copy all the streams except the second video, which will be encoded with
-libx264, and the 138th audio, which will be encoded with libvorbis.
-
-@item -t @var{duration} (@emph{output})
-Stop writing the output after its duration reaches @var{duration}.
-@var{duration} may be a number in seconds, or in @code{hh:mm:ss[.xxx]} form.
-
-@item -fs @var{limit_size} (@emph{output})
-Set the file size limit.
-
-@item -ss @var{position} (@emph{input/output})
-When used as an input option (before @code{-i}), seeks in this input file to
-@var{position}. Note the in most formats it is not possible to seek exactly, so
-@command{avconv} will seek to the closest seek point before @var{position}.
-When transcoding and @option{-accurate_seek} is enabled (the default), this
-extra segment between the seek point and @var{position} will be decoded and
-discarded. When doing stream copy or when @option{-noaccurate_seek} is used, it
-will be preserved.
-
-When used as an output option (before an output filename), decodes but discards
-input until the timestamps reach @var{position}.
-
-@var{position} may be either in seconds or in @code{hh:mm:ss[.xxx]} form.
-
-@item -itsoffset @var{offset} (@emph{input})
-Set the input time offset in seconds.
-@code{[-]hh:mm:ss[.xxx]} syntax is also supported.
-The offset is added to the timestamps of the input files.
-Specifying a positive offset means that the corresponding
-streams are delayed by @var{offset} seconds.
-
-@item -metadata[:metadata_specifier] @var{key}=@var{value} (@emph{output,per-metadata})
-Set a metadata key/value pair.
-
-An optional @var{metadata_specifier} may be given to set metadata
-on streams or chapters. See @code{-map_metadata} documentation for
-details.
-
-This option overrides metadata set with @code{-map_metadata}. It is
-also possible to delete metadata by using an empty value.
-
-For example, for setting the title in the output file:
-@example
-avconv -i in.avi -metadata title="my title" out.flv
-@end example
-
-To set the language of the first audio stream:
-@example
-avconv -i INPUT -metadata:s:a:0 language=eng OUTPUT
-@end example
-
-@item -target @var{type} (@emph{output})
-Specify target file type (@code{vcd}, @code{svcd}, @code{dvd}, @code{dv},
-@code{dv50}). @var{type} may be prefixed with @code{pal-}, @code{ntsc-} or
-@code{film-} to use the corresponding standard. All the format options
-(bitrate, codecs, buffer sizes) are then set automatically. You can just type:
-
-@example
-avconv -i myfile.avi -target vcd /tmp/vcd.mpg
-@end example
-
-Nevertheless you can specify additional options as long as you know
-they do not conflict with the standard, as in:
-
-@example
-avconv -i myfile.avi -target vcd -bf 2 /tmp/vcd.mpg
-@end example
-
-@item -dframes @var{number} (@emph{output})
-Set the number of data frames to record. This is an alias for @code{-frames:d}.
-
-@item -frames[:@var{stream_specifier}] @var{framecount} (@emph{output,per-stream})
-Stop writing to the stream after @var{framecount} frames.
-
-@item -q[:@var{stream_specifier}] @var{q} (@emph{output,per-stream})
-@itemx -qscale[:@var{stream_specifier}] @var{q} (@emph{output,per-stream})
-Use fixed quality scale (VBR). The meaning of @var{q} is
-codec-dependent.
-
-@item -filter[:@var{stream_specifier}] @var{filter_graph} (@emph{output,per-stream})
-@var{filter_graph} is a description of the filter graph to apply to
-the stream. Use @code{-filters} to show all the available filters
-(including also sources and sinks).
-
-See also the @option{-filter_complex} option if you want to create filter graphs
-with multiple inputs and/or outputs.
-
-@item -filter_script[:@var{stream_specifier}] @var{filename} (@emph{output,per-stream})
-This option is similar to @option{-filter}, the only difference is that its
-argument is the name of the file from which a filtergraph description is to be
-read.
-
-@item -pre[:@var{stream_specifier}] @var{preset_name} (@emph{output,per-stream})
-Specify the preset for matching stream(s).
-
-@item -stats (@emph{global})
-Print encoding progress/statistics. On by default.
-
-@item -attach @var{filename} (@emph{output})
-Add an attachment to the output file. This is supported by a few formats
-like Matroska for e.g. fonts used in rendering subtitles. Attachments
-are implemented as a specific type of stream, so this option will add
-a new stream to the file. It is then possible to use per-stream options
-on this stream in the usual way. Attachment streams created with this
-option will be created after all the other streams (i.e. those created
-with @code{-map} or automatic mappings).
-
-Note that for Matroska you also have to set the mimetype metadata tag:
-@example
-avconv -i INPUT -attach DejaVuSans.ttf -metadata:s:2 mimetype=application/x-truetype-font out.mkv
-@end example
-(assuming that the attachment stream will be third in the output file).
-
-@item -dump_attachment[:@var{stream_specifier}] @var{filename} (@emph{input,per-stream})
-Extract the matching attachment stream into a file named @var{filename}. If
-@var{filename} is empty, then the value of the @code{filename} metadata tag
-will be used.
-
-E.g. to extract the first attachment to a file named 'out.ttf':
-@example
-avconv -dump_attachment:t:0 out.ttf INPUT
-@end example
-To extract all attachments to files determined by the @code{filename} tag:
-@example
-avconv -dump_attachment:t "" INPUT
-@end example
-
-Technical note -- attachments are implemented as codec extradata, so this
-option can actually be used to extract extradata from any stream, not just
-attachments.
-
-@end table
-
-@section Video Options
-
-@table @option
-@item -vframes @var{number} (@emph{output})
-Set the number of video frames to record. This is an alias for @code{-frames:v}.
-@item -r[:@var{stream_specifier}] @var{fps} (@emph{input/output,per-stream})
-Set frame rate (Hz value, fraction or abbreviation).
-
-As an input option, ignore any timestamps stored in the file and instead
-generate timestamps assuming constant frame rate @var{fps}.
-
-As an output option, duplicate or drop input frames to achieve constant output
-frame rate @var{fps} (note that this actually causes the @code{fps} filter to be
-inserted to the end of the corresponding filtergraph).
-
-@item -s[:@var{stream_specifier}] @var{size} (@emph{input/output,per-stream})
-Set frame size.
-
-As an input option, this is a shortcut for the @option{video_size} private
-option, recognized by some demuxers for which the frame size is either not
-stored in the file or is configurable -- e.g. raw video or video grabbers.
-
-As an output option, this inserts the @code{scale} video filter to the
-@emph{end} of the corresponding filtergraph. Please use the @code{scale} filter
-directly to insert it at the beginning or some other place.
-
-The format is @samp{wxh} (default - same as source). The following
-abbreviations are recognized:
-@table @samp
-@item sqcif
-128x96
-@item qcif
-176x144
-@item cif
-352x288
-@item 4cif
-704x576
-@item 16cif
-1408x1152
-@item qqvga
-160x120
-@item qvga
-320x240
-@item vga
-640x480
-@item svga
-800x600
-@item xga
-1024x768
-@item uxga
-1600x1200
-@item qxga
-2048x1536
-@item sxga
-1280x1024
-@item qsxga
-2560x2048
-@item hsxga
-5120x4096
-@item wvga
-852x480
-@item wxga
-1366x768
-@item wsxga
-1600x1024
-@item wuxga
-1920x1200
-@item woxga
-2560x1600
-@item wqsxga
-3200x2048
-@item wquxga
-3840x2400
-@item whsxga
-6400x4096
-@item whuxga
-7680x4800
-@item cga
-320x200
-@item ega
-640x350
-@item hd480
-852x480
-@item hd720
-1280x720
-@item hd1080
-1920x1080
-@end table
-
-@item -aspect[:@var{stream_specifier}] @var{aspect} (@emph{output,per-stream})
-Set the video display aspect ratio specified by @var{aspect}.
-
-@var{aspect} can be a floating point number string, or a string of the
-form @var{num}:@var{den}, where @var{num} and @var{den} are the
-numerator and denominator of the aspect ratio. For example "4:3",
-"16:9", "1.3333", and "1.7777" are valid argument values.
-
-@item -vn (@emph{output})
-Disable video recording.
-
-@item -vcodec @var{codec} (@emph{output})
-Set the video codec. This is an alias for @code{-codec:v}.
-
-@item -pass[:@var{stream_specifier}] @var{n} (@emph{output,per-stream})
-Select the pass number (1 or 2). It is used to do two-pass
-video encoding. The statistics of the video are recorded in the first
-pass into a log file (see also the option -passlogfile),
-and in the second pass that log file is used to generate the video
-at the exact requested bitrate.
-On pass 1, you may just deactivate audio and set output to null,
-examples for Windows and Unix:
-@example
-avconv -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y NUL
-avconv -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y /dev/null
-@end example
-
-@item -passlogfile[:@var{stream_specifier}] @var{prefix} (@emph{output,per-stream})
-Set two-pass log file name prefix to @var{prefix}, the default file name
-prefix is ``av2pass''. The complete file name will be
-@file{PREFIX-N.log}, where N is a number specific to the output
-stream.
-
-@item -vf @var{filter_graph} (@emph{output})
-@var{filter_graph} is a description of the filter graph to apply to
-the input video.
-Use the option "-filters" to show all the available filters (including
-also sources and sinks). This is an alias for @code{-filter:v}.
-
-@end table
-
-@section Advanced Video Options
-
-@table @option
-@item -pix_fmt[:@var{stream_specifier}] @var{format} (@emph{input/output,per-stream})
-Set pixel format. Use @code{-pix_fmts} to show all the supported
-pixel formats.
-@item -sws_flags @var{flags} (@emph{input/output})
-Set SwScaler flags.
-@item -vdt @var{n}
-Discard threshold.
-
-@item -rc_override[:@var{stream_specifier}] @var{override} (@emph{output,per-stream})
-rate control override for specific intervals
-
-@item -vstats
-Dump video coding statistics to @file{vstats_HHMMSS.log}.
-@item -vstats_file @var{file}
-Dump video coding statistics to @var{file}.
-@item -top[:@var{stream_specifier}] @var{n} (@emph{output,per-stream})
-top=1/bottom=0/auto=-1 field first
-@item -dc @var{precision}
-Intra_dc_precision.
-@item -vtag @var{fourcc/tag} (@emph{output})
-Force video tag/fourcc. This is an alias for @code{-tag:v}.
-@item -qphist (@emph{global})
-Show QP histogram.
-@item -force_key_frames[:@var{stream_specifier}] @var{time}[,@var{time}...] (@emph{output,per-stream})
-Force key frames at the specified timestamps, more precisely at the first
-frames after each specified time.
-This option can be useful to ensure that a seek point is present at a
-chapter mark or any other designated place in the output file.
-The timestamps must be specified in ascending order.
-
-@item -copyinkf[:@var{stream_specifier}] (@emph{output,per-stream})
-When doing stream copy, copy also non-key frames found at the
-beginning.
-@end table
-
-@section Audio Options
-
-@table @option
-@item -aframes @var{number} (@emph{output})
-Set the number of audio frames to record. This is an alias for @code{-frames:a}.
-@item -ar[:@var{stream_specifier}] @var{freq} (@emph{input/output,per-stream})
-Set the audio sampling frequency. For output streams it is set by
-default to the frequency of the corresponding input stream. For input
-streams this option only makes sense for audio grabbing devices and raw
-demuxers and is mapped to the corresponding demuxer options.
-@item -aq @var{q} (@emph{output})
-Set the audio quality (codec-specific, VBR). This is an alias for -q:a.
-@item -ac[:@var{stream_specifier}] @var{channels} (@emph{input/output,per-stream})
-Set the number of audio channels. For output streams it is set by
-default to the number of input audio channels. For input streams
-this option only makes sense for audio grabbing devices and raw demuxers
-and is mapped to the corresponding demuxer options.
-@item -an (@emph{output})
-Disable audio recording.
-@item -acodec @var{codec} (@emph{input/output})
-Set the audio codec. This is an alias for @code{-codec:a}.
-@item -sample_fmt[:@var{stream_specifier}] @var{sample_fmt} (@emph{output,per-stream})
-Set the audio sample format. Use @code{-sample_fmts} to get a list
-of supported sample formats.
-@item -af @var{filter_graph} (@emph{output})
-@var{filter_graph} is a description of the filter graph to apply to
-the input audio.
-Use the option "-filters" to show all the available filters (including
-also sources and sinks). This is an alias for @code{-filter:a}.
-@end table
-
-@section Advanced Audio options:
-
-@table @option
-@item -atag @var{fourcc/tag} (@emph{output})
-Force audio tag/fourcc. This is an alias for @code{-tag:a}.
-@end table
-
-@section Subtitle options:
-
-@table @option
-@item -scodec @var{codec} (@emph{input/output})
-Set the subtitle codec. This is an alias for @code{-codec:s}.
-@item -sn (@emph{output})
-Disable subtitle recording.
-@end table
-
-@section Advanced options
-
-@table @option
-@item -map [-]@var{input_file_id}[:@var{stream_specifier}][,@var{sync_file_id}[:@var{stream_specifier}]] | @var{[linklabel]} (@emph{output})
-
-Designate one or more input streams as a source for the output file. Each input
-stream is identified by the input file index @var{input_file_id} and
-the input stream index @var{input_stream_id} within the input
-file. Both indices start at 0. If specified,
-@var{sync_file_id}:@var{stream_specifier} sets which input stream
-is used as a presentation sync reference.
-
-The first @code{-map} option on the command line specifies the
-source for output stream 0, the second @code{-map} option specifies
-the source for output stream 1, etc.
-
-A @code{-} character before the stream identifier creates a "negative" mapping.
-It disables matching streams from already created mappings.
-
-An alternative @var{[linklabel]} form will map outputs from complex filter
-graphs (see the @option{-filter_complex} option) to the output file.
-@var{linklabel} must correspond to a defined output link label in the graph.
-
-For example, to map ALL streams from the first input file to output
-@example
-avconv -i INPUT -map 0 output
-@end example
-
-For example, if you have two audio streams in the first input file,
-these streams are identified by "0:0" and "0:1". You can use
-@code{-map} to select which streams to place in an output file. For
-example:
-@example
-avconv -i INPUT -map 0:1 out.wav
-@end example
-will map the input stream in @file{INPUT} identified by "0:1" to
-the (single) output stream in @file{out.wav}.
-
-For example, to select the stream with index 2 from input file
-@file{a.mov} (specified by the identifier "0:2"), and stream with
-index 6 from input @file{b.mov} (specified by the identifier "1:6"),
-and copy them to the output file @file{out.mov}:
-@example
-avconv -i a.mov -i b.mov -c copy -map 0:2 -map 1:6 out.mov
-@end example
-
-To select all video and the third audio stream from an input file:
-@example
-avconv -i INPUT -map 0:v -map 0:a:2 OUTPUT
-@end example
-
-To map all the streams except the second audio, use negative mappings
-@example
-avconv -i INPUT -map 0 -map -0:a:1 OUTPUT
-@end example
-
-Note that using this option disables the default mappings for this output file.
-
-@item -map_metadata[:@var{metadata_spec_out}] @var{infile}[:@var{metadata_spec_in}] (@emph{output,per-metadata})
-Set metadata information of the next output file from @var{infile}. Note that
-those are file indices (zero-based), not filenames.
-Optional @var{metadata_spec_in/out} parameters specify, which metadata to copy.
-A metadata specifier can have the following forms:
-@table @option
-@item @var{g}
-global metadata, i.e. metadata that applies to the whole file
-
-@item @var{s}[:@var{stream_spec}]
-per-stream metadata. @var{stream_spec} is a stream specifier as described
-in the @ref{Stream specifiers} chapter. In an input metadata specifier, the first
-matching stream is copied from. In an output metadata specifier, all matching
-streams are copied to.
-
-@item @var{c}:@var{chapter_index}
-per-chapter metadata. @var{chapter_index} is the zero-based chapter index.
-
-@item @var{p}:@var{program_index}
-per-program metadata. @var{program_index} is the zero-based program index.
-@end table
-If metadata specifier is omitted, it defaults to global.
-
-By default, global metadata is copied from the first input file,
-per-stream and per-chapter metadata is copied along with streams/chapters. These
-default mappings are disabled by creating any mapping of the relevant type. A negative
-file index can be used to create a dummy mapping that just disables automatic copying.
-
-For example to copy metadata from the first stream of the input file to global metadata
-of the output file:
-@example
-avconv -i in.ogg -map_metadata 0:s:0 out.mp3
-@end example
-
-To do the reverse, i.e. copy global metadata to all audio streams:
-@example
-avconv -i in.mkv -map_metadata:s:a 0:g out.mkv
-@end example
-Note that simple @code{0} would work as well in this example, since global
-metadata is assumed by default.
-
-@item -map_chapters @var{input_file_index} (@emph{output})
-Copy chapters from input file with index @var{input_file_index} to the next
-output file. If no chapter mapping is specified, then chapters are copied from
-the first input file with at least one chapter. Use a negative file index to
-disable any chapter copying.
-@item -debug
-Print specific debug info.
-@item -benchmark (@emph{global})
-Show benchmarking information at the end of an encode.
-Shows CPU time used and maximum memory consumption.
-Maximum memory consumption is not supported on all systems,
-it will usually display as 0 if not supported.
-@item -timelimit @var{duration} (@emph{global})
-Exit after avconv has been running for @var{duration} seconds.
-@item -dump (@emph{global})
-Dump each input packet to stderr.
-@item -hex (@emph{global})
-When dumping packets, also dump the payload.
-@item -re (@emph{input})
-Read input at native frame rate. Mainly used to simulate a grab device
-or live input stream (e.g. when reading from a file). Should not be used
-with actual grab devices or live input streams (where it can cause packet
-loss).
-@item -vsync @var{parameter}
-Video sync method.
-
-@table @option
-@item passthrough
-Each frame is passed with its timestamp from the demuxer to the muxer.
-@item cfr
-Frames will be duplicated and dropped to achieve exactly the requested
-constant framerate.
-@item vfr
-Frames are passed through with their timestamp or dropped so as to
-prevent 2 frames from having the same timestamp.
-@item auto
-Chooses between 1 and 2 depending on muxer capabilities. This is the
-default method.
-@end table
-
-With -map you can select from which stream the timestamps should be
-taken. You can leave either video or audio unchanged and sync the
-remaining stream(s) to the unchanged one.
-
-@item -async @var{samples_per_second}
-Audio sync method. "Stretches/squeezes" the audio stream to match the timestamps,
-the parameter is the maximum samples per second by which the audio is changed.
--async 1 is a special case where only the start of the audio stream is corrected
-without any later correction.
-This option has been deprecated. Use the @code{asyncts} audio filter instead.
-@item -copyts
-Copy timestamps from input to output.
-@item -copytb
-Copy input stream time base from input to output when stream copying.
-@item -shortest (@emph{output})
-Finish encoding when the shortest input stream ends.
-@item -dts_delta_threshold
-Timestamp discontinuity delta threshold.
-@item -muxdelay @var{seconds} (@emph{input})
-Set the maximum demux-decode delay.
-@item -muxpreload @var{seconds} (@emph{input})
-Set the initial demux-decode delay.
-@item -streamid @var{output-stream-index}:@var{new-value} (@emph{output})
-Assign a new stream-id value to an output stream. This option should be
-specified prior to the output filename to which it applies.
-For the situation where multiple output files exist, a streamid
-may be reassigned to a different value.
-
-For example, to set the stream 0 PID to 33 and the stream 1 PID to 36 for
-an output mpegts file:
-@example
-avconv -i infile -streamid 0:33 -streamid 1:36 out.ts
-@end example
-
-@item -bsf[:@var{stream_specifier}] @var{bitstream_filters} (@emph{output,per-stream})
-Set bitstream filters for matching streams. @var{bistream_filters} is
-a comma-separated list of bitstream filters. Use the @code{-bsfs} option
-to get the list of bitstream filters.
-@example
-avconv -i h264.mp4 -c:v copy -bsf:v h264_mp4toannexb -an out.h264
-@end example
-@example
-avconv -i file.mov -an -vn -bsf:s mov2textsub -c:s copy -f rawvideo sub.txt
-@end example
-
-@item -tag[:@var{stream_specifier}] @var{codec_tag} (@emph{output,per-stream})
-Force a tag/fourcc for matching streams.
-
-@item -filter_complex @var{filtergraph} (@emph{global})
-Define a complex filter graph, i.e. one with arbitrary number of inputs and/or
-outputs. For simple graphs -- those with one input and one output of the same
-type -- see the @option{-filter} options. @var{filtergraph} is a description of
-the filter graph, as described in @ref{Filtergraph syntax}.
-
-Input link labels must refer to input streams using the
-@code{[file_index:stream_specifier]} syntax (i.e. the same as @option{-map}
-uses). If @var{stream_specifier} matches multiple streams, the first one will be
-used. An unlabeled input will be connected to the first unused input stream of
-the matching type.
-
-Output link labels are referred to with @option{-map}. Unlabeled outputs are
-added to the first output file.
-
-Note that with this option it is possible to use only lavfi sources without
-normal input files.
-
-For example, to overlay an image over video
-@example
-avconv -i video.mkv -i image.png -filter_complex '[0:v][1:v]overlay[out]' -map
-'[out]' out.mkv
-@end example
-Here @code{[0:v]} refers to the first video stream in the first input file,
-which is linked to the first (main) input of the overlay filter. Similarly the
-first video stream in the second input is linked to the second (overlay) input
-of overlay.
-
-Assuming there is only one video stream in each input file, we can omit input
-labels, so the above is equivalent to
-@example
-avconv -i video.mkv -i image.png -filter_complex 'overlay[out]' -map
-'[out]' out.mkv
-@end example
-
-Furthermore we can omit the output label and the single output from the filter
-graph will be added to the output file automatically, so we can simply write
-@example
-avconv -i video.mkv -i image.png -filter_complex 'overlay' out.mkv
-@end example
-
-To generate 5 seconds of pure red video using lavfi @code{color} source:
-@example
-avconv -filter_complex 'color=red' -t 5 out.mkv
-@end example
-
-@item -filter_complex_script @var{filename} (@emph{global})
-This option is similar to @option{-filter_complex}, the only difference is that
-its argument is the name of the file from which a complex filtergraph
-description is to be read.
-
-@item -accurate_seek (@emph{input})
-This option enables or disables accurate seeking in input files with the
-@option{-ss} option. It is enabled by default, so seeking is accurate when
-transcoding. Use @option{-noaccurate_seek} to disable it, which may be useful
-e.g. when copying some streams and transcoding the others.
-
-@end table
-@c man end OPTIONS
-
-@chapter Tips
-@c man begin TIPS
-
-@itemize
-@item
-For streaming at very low bitrate application, use a low frame rate
-and a small GOP size. This is especially true for RealVideo where
-the Linux player does not seem to be very fast, so it can miss
-frames. An example is:
-
-@example
-avconv -g 3 -r 3 -t 10 -b 50k -s qcif -f rv10 /tmp/b.rm
-@end example
-
-@item
-The parameter 'q' which is displayed while encoding is the current
-quantizer. The value 1 indicates that a very good quality could
-be achieved. The value 31 indicates the worst quality. If q=31 appears
-too often, it means that the encoder cannot compress enough to meet
-your bitrate. You must either increase the bitrate, decrease the
-frame rate or decrease the frame size.
-
-@item
-If your computer is not fast enough, you can speed up the
-compression at the expense of the compression ratio. You can use
-'-me zero' to speed up motion estimation, and '-g 0' to disable
-motion estimation completely (you have only I-frames, which means it
-is about as good as JPEG compression).
-
-@item
-To have very low audio bitrates, reduce the sampling frequency
-(down to 22050 Hz for MPEG audio, 22050 or 11025 for AC-3).
-
-@item
-To have a constant quality (but a variable bitrate), use the option
-'-qscale n' when 'n' is between 1 (excellent quality) and 31 (worst
-quality).
-
-@end itemize
-@c man end TIPS
-
-@chapter Examples
-@c man begin EXAMPLES
-
-@section Preset files
-
-A preset file contains a sequence of @var{option=value} pairs, one for
-each line, specifying a sequence of options which can be specified also on
-the command line. Lines starting with the hash ('#') character are ignored and
-are used to provide comments. Empty lines are also ignored. Check the
-@file{presets} directory in the Libav source tree for examples.
-
-Preset files are specified with the @code{pre} option, this option takes a
-preset name as input. Avconv searches for a file named @var{preset_name}.avpreset in
-the directories @file{$AVCONV_DATADIR} (if set), and @file{$HOME/.avconv}, and in
-the data directory defined at configuration time (usually @file{$PREFIX/share/avconv})
-in that order. For example, if the argument is @code{libx264-max}, it will
-search for the file @file{libx264-max.avpreset}.
-
-@section Video and Audio grabbing
-
-If you specify the input format and device then avconv can grab video
-and audio directly.
-
-@example
-avconv -f oss -i /dev/dsp -f video4linux2 -i /dev/video0 /tmp/out.mpg
-@end example
-
-Note that you must activate the right video source and channel before
-launching avconv with any TV viewer such as
-@uref{http://linux.bytesex.org/xawtv/, xawtv} by Gerd Knorr. You also
-have to set the audio recording levels correctly with a
-standard mixer.
-
-@section X11 grabbing
-
-Grab the X11 display with avconv via
-
-@example
-avconv -f x11grab -s cif -r 25 -i :0.0 /tmp/out.mpg
-@end example
-
-0.0 is display.screen number of your X11 server, same as
-the DISPLAY environment variable.
-
-@example
-avconv -f x11grab -s cif -r 25 -i :0.0+10,20 /tmp/out.mpg
-@end example
-
-0.0 is display.screen number of your X11 server, same as the DISPLAY environment
-variable. 10 is the x-offset and 20 the y-offset for the grabbing.
-
-@section Video and Audio file format conversion
-
-Any supported file format and protocol can serve as input to avconv:
-
-Examples:
-@itemize
-@item
-You can use YUV files as input:
-
-@example
-avconv -i /tmp/test%d.Y /tmp/out.mpg
-@end example
-
-It will use the files:
-@example
-/tmp/test0.Y, /tmp/test0.U, /tmp/test0.V,
-/tmp/test1.Y, /tmp/test1.U, /tmp/test1.V, etc...
-@end example
-
-The Y files use twice the resolution of the U and V files. They are
-raw files, without header. They can be generated by all decent video
-decoders. You must specify the size of the image with the @option{-s} option
-if avconv cannot guess it.
-
-@item
-You can input from a raw YUV420P file:
-
-@example
-avconv -i /tmp/test.yuv /tmp/out.avi
-@end example
-
-test.yuv is a file containing raw YUV planar data. Each frame is composed
-of the Y plane followed by the U and V planes at half vertical and
-horizontal resolution.
-
-@item
-You can output to a raw YUV420P file:
-
-@example
-avconv -i mydivx.avi hugefile.yuv
-@end example
-
-@item
-You can set several input files and output files:
-
-@example
-avconv -i /tmp/a.wav -s 640x480 -i /tmp/a.yuv /tmp/a.mpg
-@end example
-
-Converts the audio file a.wav and the raw YUV video file a.yuv
-to MPEG file a.mpg.
-
-@item
-You can also do audio and video conversions at the same time:
-
-@example
-avconv -i /tmp/a.wav -ar 22050 /tmp/a.mp2
-@end example
-
-Converts a.wav to MPEG audio at 22050 Hz sample rate.
-
-@item
-You can encode to several formats at the same time and define a
-mapping from input stream to output streams:
-
-@example
-avconv -i /tmp/a.wav -map 0:a -b 64k /tmp/a.mp2 -map 0:a -b 128k /tmp/b.mp2
-@end example
-
-Converts a.wav to a.mp2 at 64 kbits and to b.mp2 at 128 kbits. '-map
-file:index' specifies which input stream is used for each output
-stream, in the order of the definition of output streams.
-
-@item
-You can transcode decrypted VOBs:
-
-@example
-avconv -i snatch_1.vob -f avi -c:v mpeg4 -b:v 800k -g 300 -bf 2 -c:a libmp3lame -b:a 128k snatch.avi
-@end example
-
-This is a typical DVD ripping example; the input is a VOB file, the
-output an AVI file with MPEG-4 video and MP3 audio. Note that in this
-command we use B-frames so the MPEG-4 stream is DivX5 compatible, and
-GOP size is 300 which means one intra frame every 10 seconds for 29.97fps
-input video. Furthermore, the audio stream is MP3-encoded so you need
-to enable LAME support by passing @code{--enable-libmp3lame} to configure.
-The mapping is particularly useful for DVD transcoding
-to get the desired audio language.
-
-NOTE: To see the supported input formats, use @code{avconv -formats}.
-
-@item
-You can extract images from a video, or create a video from many images:
-
-For extracting images from a video:
-@example
-avconv -i foo.avi -r 1 -s WxH -f image2 foo-%03d.jpeg
-@end example
-
-This will extract one video frame per second from the video and will
-output them in files named @file{foo-001.jpeg}, @file{foo-002.jpeg},
-etc. Images will be rescaled to fit the new WxH values.
-
-If you want to extract just a limited number of frames, you can use the
-above command in combination with the -vframes or -t option, or in
-combination with -ss to start extracting from a certain point in time.
-
-For creating a video from many images:
-@example
-avconv -f image2 -i foo-%03d.jpeg -r 12 -s WxH foo.avi
-@end example
-
-The syntax @code{foo-%03d.jpeg} specifies to use a decimal number
-composed of three digits padded with zeroes to express the sequence
-number. It is the same syntax supported by the C printf function, but
-only formats accepting a normal integer are suitable.
-
-@item
-You can put many streams of the same type in the output:
-
-@example
-avconv -i test1.avi -i test2.avi -map 0.3 -map 0.2 -map 0.1 -map 0.0 -c copy test12.nut
-@end example
-
-The resulting output file @file{test12.avi} will contain first four streams from
-the input file in reverse order.
-
-@item
-To force CBR video output:
-@example
-avconv -i myfile.avi -b 4000k -minrate 4000k -maxrate 4000k -bufsize 1835k out.m2v
-@end example
-
-@item
-The four options lmin, lmax, mblmin and mblmax use 'lambda' units,
-but you may use the QP2LAMBDA constant to easily convert from 'q' units:
-@example
-avconv -i src.ext -lmax 21*QP2LAMBDA dst.ext
-@end example
-
-@end itemize
-@c man end EXAMPLES
-
-@include eval.texi
-@include encoders.texi
-@include demuxers.texi
-@include muxers.texi
-@include indevs.texi
-@include outdevs.texi
-@include protocols.texi
-@include bitstream_filters.texi
-@include filters.texi
-@include metadata.texi
-
-@ignore
-
-@setfilename avconv
-@settitle avconv video converter
-
-@c man begin SEEALSO
-avplay(1), avprobe(1) and the Libav HTML documentation
-@c man end
-
-@c man begin AUTHORS
-The Libav developers
-@c man end
-
-@end ignore
-
-@bye
diff --git a/doc/avplay.texi b/doc/avplay.texi
deleted file mode 100644
index b856f9b..0000000
--- a/doc/avplay.texi
+++ b/dev/null
@@ -1,182 +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 -vismv
-Visualize motion vectors.
-@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 -autoexit
-Exit when video is done playing.
-@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 mouse click
-Seek to percentage in file corresponding to fraction of width.
-
-@end table
-
-@c man end
-
-@include eval.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
+++ b/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/avserver.conf b/doc/avserver.conf
deleted file mode 100644
index e1cd9fb..0000000
--- a/doc/avserver.conf
+++ b/dev/null
@@ -1,372 +0,0 @@
-# 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.
-Port 8090
-
-# Address on which the server is bound. Only useful if you have
-# several network interfaces.
-BindAddress 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 AVServer
-# 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 avconv encoder or another
-# avserver. This sequence may be encoded simultaneously with several
-# codecs at several resolutions.
-
-<Feed feed1.ffm>
-
-# You must use 'avconv' to send a live feed to avserver. In this
-# example, you can type:
-#
-# avconv http://localhost:8090/feed1.ffm
-
-# avserver 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 avconv automatically.
-# First avconv must be defined with an appropriate path if needed,
-# after that options can follow, but avoid adding the http:// field
-#Launch avconv
-
-# 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'). AVServer 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
-#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
-#Author "Me"
-#Copyright "Super MegaCorp"
-#Title "Test stream from disk"
-#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 avserver 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.libav.org/
-</Redirect>
diff --git a/doc/avserver.texi b/doc/avserver.texi
deleted file mode 100644
index 88e6221..0000000
--- a/doc/avserver.texi
+++ b/dev/null
@@ -1,276 +0,0 @@
-\input texinfo @c -*- texinfo -*-
-
-@settitle avserver Documentation
-@titlepage
-@center @titlefont{avserver Documentation}
-@end titlepage
-
-@top
-
-@contents
-
-@chapter Synopsys
-
-The generic syntax is:
-
-@example
-@c man begin SYNOPSIS
-avserver [options]
-@c man end
-@end example
-
-@chapter Description
-@c man begin DESCRIPTION
-
-WARNING: avserver is unmaintained, largely broken and in need of a
-complete rewrite. It probably won't work for you. Use at your own
-risk.
-
-avserver 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 in avserver.conf).
-
-This documentation covers only the streaming aspects of avserver /
-avconv. All questions about parameters for avconv, codec questions,
-etc. are not covered here. Read @file{avconv.html} for more
-information.
-
-@section How does it work?
-
-avserver receives prerecorded files or FFM streams from some avconv
-instance as input, then streams them over RTP/RTSP/HTTP.
-
-An avserver instance will listen on some port as specified in the
-configuration file. You can launch one or more instances of avconv and
-send one or more FFM streams to the port where avserver is expecting
-to receive them. Alternately, you can make avserver launch such avconv
-instances at startup.
-
-Input streams are called feeds, and each one is specified by a <Feed>
-section in the configuration file.
-
-For each feed you can have different output streams in various
-formats, each one specified by a <Stream> section in the configuration
-file.
-
-@section Status stream
-
-avserver 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 What can this do?
-
-When properly configured and running, you can capture video and audio in real
-time from a suitable capture card, and stream it out over the Internet to
-either Windows Media Player or RealAudio player (with some restrictions).
-
-It can also stream from files, though that is currently broken. Very often, a
-web server can be used to serve up the files just as well.
-
-It can stream prerecorded video from .ffm files, though it is somewhat tricky
-to make it work correctly.
-
-@section What do I need?
-
-I use Linux on a 900 MHz Duron with a cheapo Bt848 based TV capture card. I'm
-using stock Linux 2.4.17 with the stock drivers. [Actually that isn't true,
-I needed some special drivers for my motherboard-based sound card.]
-
-I understand that FreeBSD systems work just fine as well.
-
-@section How do I make it work?
-
-First, build the kit. It *really* helps to have installed LAME first. Then when
-you run the avserver ./configure, make sure that you have the
-@code{--enable-libmp3lame} flag turned on.
-
-LAME is important as it allows for streaming audio to Windows Media Player.
-Don't ask why the other audio types do not work.
-
-As a simple test, just run the following two command lines where INPUTFILE
-is some file which you can decode with avconv:
-
-@example
-./avserver -f doc/avserver.conf &
-./avconv -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.
-
-@section What happens next?
-
-You should edit the avserver.conf file to suit your needs (in terms of
-frame rates etc). Then install avserver and avconv, write a script to start
-them up, and off you go.
-
-@section Troubleshooting
-
-@subsection I don't hear any audio, but video is fine.
-
-Maybe you didn't install LAME, or got your ./configure statement wrong. Check
-the avconv output to see if a line referring to MP3 is present. If not, then
-your configuration was incorrect. If it is, then maybe your wiring is not
-set up correctly. Maybe the sound card is not getting data from the right
-input source. Maybe you have a really awful audio interface (like I do)
-that only captures in stereo and also requires that one channel be flipped.
-If you are one of these people, then export 'AUDIO_FLIP_LEFT=1' before
-starting avconv.
-
-@subsection The audio and video lose sync after a while.
-
-Yes, they do.
-
-@subsection After a long while, the video update rate goes way down in WMP.
-
-Yes, it does. Who knows why?
-
-@subsection WMP 6.4 behaves differently to WMP 7.
-
-Yes, it does. Any thoughts on this would be gratefully received. These
-differences extend to embedding WMP into a web page. [There are two
-object IDs that you can use: The old one, which does not play well, and
-the new one, which does (both tested on the same system). However,
-I suspect that the new one is not available unless you have installed WMP 7].
-
-@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
-avserver parameters must match the original parameters used to record the
-file. If they do not, then avserver 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
-avserver.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, avserver (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 avserver.conf that will
-add the 15 second prebuffering on all requests that do not otherwise
-specify a time. In addition, avserver will skip frames until a key_frame
-is found. This further reduces the startup delay by not transferring data
-that will be discarded.
-
-* You may want to adjust the MaxBandwidth in the avserver.conf to limit
-the amount of bandwidth consumed by live streams.
-
-@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 avserver, 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 avtools-common-opts.texi
-
-@section Main options
-
-@table @option
-@item -f @var{configfile}
-Use @file{configfile} instead of @file{/etc/avserver.conf}.
-@item -n
-Enable no-launch mode. This option disables all the Launch directives
-within the various <Stream> sections. Since avserver will not launch
-any avconv instances, you will have to launch them manually.
-@item -d
-Enable debug mode. This option increases log verbosity, directs log
-messages to stdout.
-@end table
-@c man end
-
-@ignore
-
-@setfilename avserver
-@settitle avserver video server
-
-@c man begin SEEALSO
-
-avconv(1), avplay(1), avprobe(1), the @file{avserver.conf}
-example 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 156319e..0000000
--- a/doc/avtools-common-opts.texi
+++ b/dev/null
@@ -1,184 +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.
-@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/bitstream_filters.texi b/doc/bitstream_filters.texi
index 6e7f878..315fe33 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,19 +10,70 @@ 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
+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 imx_dump_header
@section mjpeg2jpeg
@@ -34,7 +85,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,9 +108,9 @@ 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
@@ -72,6 +123,6 @@ avconv -i frame_%d.jpg -c:v copy rotated.avi
@section noise
-@section remove_extradata
+@section remove_extra
@c man end BITSTREAM FILTERS
diff --git a/doc/build_system.txt b/doc/build_system.txt
index c3dede7..36c141e 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,13 +9,19 @@ 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.
@@ -27,3 +33,18 @@ libavcodec/api-example
libswscale/swscale-test
Build the swscale self-test (useful also as example).
+
+
+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..1606f6c
--- a/dev/null
+++ b/doc/codecs.texi
@@ -0,0 +1,1093 @@
+@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
+Use only bitexact stuff (except (I)DCT).
+@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 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 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
+@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).
+
+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.
+@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.
+
+@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 multithreading type.
+
+Possible values:
+@table @samp
+@item slice
+
+@item frame
+
+@end table
+@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.
+@end table
+
+@c man end CODEC OPTIONS
+
+@include decoders.texi
+@include encoders.texi
diff --git a/doc/decoders.texi b/doc/decoders.texi
new file mode 100644
index 0000000..9d9f298
--- a/dev/null
+++ b/doc/decoders.texi
@@ -0,0 +1,202 @@
+@chapter Decoders
+@c man begin DECODERS
+
+Decoders are configured elements in FFmpeg which allow the decoding of
+multimedia streams.
+
+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}.
+
+You can disable all the decoders with the configure option
+@code{--disable-decoders} and selectively enable / disable single decoders
+with the options @code{--enable-decoder=@var{DECODER}} /
+@code{--disable-decoder=@var{DECODER}}.
+
+The option @code{-codecs} 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
+
+@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}.
+
+@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}.
+@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..e6c6cfe
--- a/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 {
+ padding-bottom: 1px;
+ padding-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..bfc0bdc 100644
--- a/doc/demuxers.texi
+++ b/doc/demuxers.texi
@@ -1,30 +1,185 @@
@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 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.
+
+@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.
+
+@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 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 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.
-The pattern may contain the string "%d" or "%0@var{N}d", which
+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 +187,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 +199,177 @@ filenames of the form @file{img-001.bmp}, @file{img-002.bmp}, ...,
sequence of filenames of the form @file{i%m%g-1.jpg},
@file{i%m%g-2.jpg}, ..., @file{i%m%g-10.jpg}, etc.
-The size, the pixel format, and the format of each image must be the
-same for all the files in the sequence.
+Note that the pattern must not necessarily contain "%d" or
+"%0@var{N}d", for example to convert a single image file
+@file{img.jpeg} you can employ the command:
+@example
+ffmpeg -i img.jpeg img.png
+@end example
+
+@item glob
+Select a glob wildcard pattern type.
+
+The pattern is interpreted like a @code{glob()} pattern. This is only
+selectable if libavformat was compiled with globbing support.
+
+@item glob_sequence @emph{(deprecated, will be removed)}
+Select a mixed glob wildcard/sequence pattern.
+
+If your version of libavformat was compiled with globbing support, and
+the provided pattern contains at least one glob meta character among
+@code{%*?[]@{@}} that is preceded by an unescaped "%", the pattern is
+interpreted like a @code{glob()} pattern, otherwise it is interpreted
+like a sequence pattern.
+
+All glob special characters @code{%*?[]@{@}} must be prefixed
+with "%". To escape a literal "%" you shall use "%%".
+
+For example the pattern @code{foo-%*.jpeg} will match all the
+filenames prefixed by "foo-" and terminating with ".jpeg", and
+@code{foo-%?%?%?.jpeg} will match all the filenames prefixed with
+"foo-", followed by a sequence of three characters, and terminating
+with ".jpeg".
+
+This pattern type is deprecated in favor of @var{glob} and
+@var{sequence}.
+@end table
-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:
+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.
+@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 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 832e21e..9c72c44 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 declarations 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,87 @@ depend on B, then A can and should be committed first and separate from B.
Keeping changes well split into self-contained parts makes reviewing and
understanding them on the commit log mailing list easier. This also helps
in case of debugging later on.
+Also if you have doubts about splitting or not splitting, do not hesitate to
+ask/discuss it on the developer mailing list.
@item
-Patches that change behavior of the programs (renaming options etc) or
-public API or ABI should be discussed in depth and possible few days should
-pass between discussion and commit.
-Changes to the build system (Makefiles, configure script) which alter
-the expected behavior should be considered in the same regard.
+Do not change behavior of the programs (renaming options etc) or public
+API or ABI without first discussing it on the ffmpeg-devel mailing list.
+Do not remove functionality from the code. Just improve!
+
+Note: Redundant code can be removed.
+
+@item
+Do not commit changes to the build system (Makefiles, configure script)
+which change behavior, defaults etc, without asking first. The same
+applies to compiler warning fixes, trivial looking fixes and to code
+maintained by other developers. We usually have a reason for doing things
+the way we do. Send your changes as patches to the ffmpeg-devel mailing
+list, and if the code maintainers say OK, you may commit. This does not
+apply to files you wrote and/or maintain.
+
+@item
+We refuse source indentation and other cosmetic changes if they are mixed
+with functional changes, such commits will be rejected and removed. Every
+developer has his own indentation style, you should not change it. Of course
+if you (re)write something, you can use your own style, even though we would
+prefer if the indentation throughout FFmpeg was consistent (Many projects
+force a given indentation style - we do not.). If you really need to make
+indentation changes (try to avoid this), separate them strictly from real
+changes.
+
+NOTE: If you had to put if()@{ .. @} over a large (> 5 lines) chunk of code,
+then either do NOT change the indentation of the inner part within (do not
+move it to the right)! or do so in a separate commit
+
+@item
+Always fill out the commit log message. Describe in a few lines what you
+changed and why. You can refer to mailing list postings if you fix a
+particular bug. Comments such as "fixed!" or "Changed it." are unacceptable.
+Recommended format:
+area changed: Short 1 line description
+
+details describing what and why and giving references.
+
+@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 +374,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 +435,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 +470,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 +498,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
-Is the patch against latest Libav git master branch?
+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
-Are you subscribed to the
-@uref{https://lists.libav.org/mailman/listinfo/libav-devel, libav-devel}
-mailing list? (Only list subscribers are allowed to post.)
+Did you provide a clear git commit log message?
+
+@item
+Is the patch against latest FFmpeg git master branch?
+
+@item
+Are you subscribed to ffmpeg-devel?
+(the list is subscribers only due to spam)
@item
Have you checked that the changes are minimal, so that the same cannot be
@@ -553,7 +559,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 +577,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 +588,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 +619,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 +667,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 +696,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 +715,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 +723,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 +737,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 +749,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 +760,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..8f8b22a
--- a/dev/null
+++ b/doc/devices.texi
@@ -0,0 +1,21 @@
+@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
+
+@include indevs.texi
+@include outdevs.texi
diff --git a/doc/encoders.texi b/doc/encoders.texi
index d6f4bce..67f2a39 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{-codecs} of the av* tools will display the list of
+The option @code{-codecs} 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 Comment this out until somebody writes the respective documentation.
+@c See also @ref{libfaac}, @ref{libaacplus}, and @ref{libfdk-aac-enc}.
+
+@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
+descibed 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,6 +494,375 @@ Selected by Encoder (default)
@end table
+@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. 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 overriden 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.
+
+@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 modeled 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 of FFmpeg is 10ms, but is 20ms in @command{opusenc}.
+
+@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
+
@section libwavpack
A wrapper providing WavPack encoding through libwavpack.
@@ -446,191 +897,699 @@ 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
+
+Theora format supported through libtheora.
+
+Requires the presence of the libtheora headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libtheora}.
+
+@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, only works if the @code{qscale} flag in
+@option{flags} is not enabled.
+
+@item flags
+Used to enable constant quality mode 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 in lambda units, only works if the
+@code{qscale} flag in @option{flags} is enabled. The value is clipped
+in the [0 - 10*@code{FF_QP2LAMBDA}] range, and then multiplied for 6.3
+to get a value in the native libtheora range [0-63]. A higher value
+corresponds to a higher quality.
+
+For example, to set maximum constant quality encoding with
+@command{ffmpeg}:
+@example
+ffmpeg -i INPUT -flags:v qscale -global_quality:v "10*QP2LAMBDA" -codec:v libtheora OUTPUT.ogg
+@end example
+@end table
+
+@section libvpx
+
+VP8 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
+
+@end table
+
+For more information about libvpx see:
+@url{http://www.webmproject.org/}
+
@section libx264
-x264 H.264/MPEG-4 AVC encoder wrapper
+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).
+This encoder requires the presence of the libx264 headers and library
+during configuration. You need to explicitly configure the build with
+@code{--enable-libx264}.
-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.
+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).
-@subsection Option Mapping
+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 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}.
+
+@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 qmax (@emph{qpmax})
+
+@item qmin (@emph{qpmin})
+
+@item qdiff (@emph{qpstep})
+
+@item qblur (@emph{qblur})
+
+@item qcomp (@emph{qcomp})
+
+@item refs (@emph{ref})
+
+@item sc_threshold (@emph{scenecut})
-The following options are supported by the x264 wrapper, the x264-equivalent
-options follow the Libav ones.
-
-@multitable @columnfractions .2 .2
-@item b @tab bitrate
-Libav @code{b} option is expressed in bits/s, x264 @code{bitrate} in kilobits/s.
-@item bf @tab bframes
-Maximum number of B-frames.
-@item g @tab keyint
-Maximum GOP size.
-@item qmin @tab qpmin
-@item qmax @tab qpmax
-@item qdiff @tab qpstep
-@item qblur @tab qblur
-@item qcomp @tab qcomp
-@item refs @tab ref
-@item sc_threshold @tab scenecut
-@item trellis @tab trellis
-@item nr @tab nr
-Noise reduction.
-@item me_range @tab merange
-@item me_method @tab me
-@item subq @tab subme
-@item b_strategy @tab b-adapt
-@item keyint_min @tab keyint-min
-@item coder @tab cabac
-Set coder to @code{ac} to use CABAC.
-@item cmp @tab chroma-me
-Set to @code{chroma} to use chroma motion estimation.
-@item threads @tab threads
-@item thread_type @tab sliced_threads
-Set to @code{slice} to use sliced threading instead of frame threading.
-@item flags -cgop @tab open-gop
-Set @code{-cgop} to use recovery points to close GOPs.
-@item rc_init_occupancy @tab vbv-init
-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}
+@item trellis (@emph{trellis})
+
+@item nr (@emph{nr})
+
+@item me_range (@emph{merange})
+
+@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})
+
+@item b_strategy (@emph{b-adapt})
+
+@item keyint_min (@emph{min-keyint})
+
+@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})
+
+@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 @var{integer}
-Constant quantization parameter rate control method.
-@item -aq-mode @var{integer}
-AQ method
-Possible values:
+@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
+@item none (@emph{0})
+Disabled.
-@item variance
+@item variance (@emph{1})
Variance AQ (complexity mask).
-@item autovariance
+
+@item autovariance (@emph{2})
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 aq-strength (@emph{aq-strength})
+Set AQ strength, reduce blocking and blurring in flat and textured areas.
-@item simple
+@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 smart
+@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 @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}
+
+@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 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 @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
+@item b-bias (@emph{b-bias})
+Set the influence on how often B-frames are used.
-@item strict
+@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
+@item normal (@emph{normal})
Non-strict (not Blu-ray compatible).
@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
+@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
+@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 spatial
+@item x264opts (N.A.)
+Set any x264 option, see @command{x264 --fullhelp} for a list.
-@item temporal
+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.
-@item auto
+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 compability 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
-@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:
+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 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 none
-@item vbr
+@item mv4
+Use four motion vector by macroblock.
+
+@item aic
+Enable high quality AC prediction.
+
+@item gray
+Only encode grayscale.
-@item cbr
+@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 -x264-params @var{string}
-Override the x264 configuration using a :-separated list of key=value parameters.
+
+@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).
+
+@item variance_aq
+Enable variance adaptive quantization when set to 1. Default is 0
+(disabled).
+
+When combined with @option{lumi_aq}, the resulting quality will not
+be better than any of the two specified individually. In other
+words, the resulting quality will be the worse one of the two
+effects.
+
+@item ssim
+Set structural similarity (SSIM) displaying method. Possible values:
+
+@table @samp
+@item off
+Disable displaying of SSIM information.
+
+@item avg
+Output average SSIM at the end of encoding to stdout. The format of
+showing the average SSIM is:
+
+@example
+Average SSIM: %f
+@end example
+
+For users who are not familiar with C, %f means a float number, or
+a decimal (e.g. 0.939232).
+
+@item frame
+Output both per-frame SSIM data during encoding and average SSIM at
+the end of encoding to stdout. The format of per-frame information
+is:
+
@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
+ SSIM: avg: %1.3f min: %1.3f max: %1.3f
@end example
+
+For users who are not familiar with C, %1.3f means a float number
+rounded to 3 digits after the dot (e.g. 0.932).
+
+@end table
+
+@item ssim_acc
+Set SSIM accuracy. Valid options are integers within the range of
+0-4, while 0 gives the most accurate result and 4 computes the
+fastest.
+
@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 png
+
+PNG image encoder.
+
+@subsection Private options
+
+@table @option
+@item dpi @var{integer}
+Set physical density of pixels, in dots per inch, unset by default
+@item dpm @var{integer}
+Set physical density of pixels, in dots per meter, unset by default
+@end table
@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 choosen with the @code{-vcodec} option.
+
+@subsection Private Options for prores-ks
@table @option
@item profile @var{integer}
diff --git a/doc/errno.txt b/doc/errno.txt
new file mode 100644
index 0000000..31cab26
--- a/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
+++ b/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..3d698cc
--- a/dev/null
+++ b/doc/examples/Makefile
@@ -0,0 +1,38 @@
+# 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= decoding_encoding \
+ demuxing \
+ filtering_video \
+ filtering_audio \
+ metadata \
+ muxing \
+ resampling_audio \
+ scaling_video \
+
+OBJS=$(addsuffix .o,$(EXAMPLES))
+
+# the following examples make explicit use of the math library
+decoding_encoding: LDLIBS += -lm
+muxing: LDLIBS += -lm
+resampling_audio: LDLIBS += -lm
+
+.phony: all clean-test clean
+
+all: $(OBJS) $(EXAMPLES)
+
+clean-test:
+ $(RM) test*.pgm test.h264 test.mp2 test.sw test.mpg
+
+clean: clean-test
+ $(RM) $(EXAMPLES) $(OBJS)
diff --git a/doc/examples/README b/doc/examples/README
new file mode 100644
index 0000000..cb40881
--- a/dev/null
+++ b/doc/examples/README
@@ -0,0 +1,18 @@
+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.
+
+
+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.
+
+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 you can go into
+doc/examples and run a command such as PKG_CONFIG_PATH=pc-uninstalled make.
diff --git a/doc/examples/decoding_encoding.c b/doc/examples/decoding_encoding.c
new file mode 100644
index 0000000..976b611
--- a/dev/null
+++ b/doc/examples/decoding_encoding.c
@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 2001 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * libavcodec API use example.
+ *
+ * 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
+ * @example doc/examples/decoding_encoding.c
+ */
+
+#include <math.h>
+
+#include <libavutil/opt.h>
+#include <libavcodec/avcodec.h>
+#include <libavutil/channel_layout.h>
+#include <libavutil/common.h>
+#include <libavutil/imgutils.h>
+#include <libavutil/mathematics.h>
+#include <libavutil/samplefmt.h>
+
+#define INBUF_SIZE 4096
+#define AUDIO_INBUF_SIZE 20480
+#define AUDIO_REFILL_THRESH 4096
+
+/* check that a given sample format is supported by the encoder */
+static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt)
+{
+ const enum AVSampleFormat *p = codec->sample_fmts;
+
+ while (*p != AV_SAMPLE_FMT_NONE) {
+ if (*p == sample_fmt)
+ return 1;
+ p++;
+ }
+ return 0;
+}
+
+/* just pick the highest supported samplerate */
+static int select_sample_rate(AVCodec *codec)
+{
+ const int *p;
+ int best_samplerate = 0;
+
+ if (!codec->supported_samplerates)
+ return 44100;
+
+ p = codec->supported_samplerates;
+ while (*p) {
+ best_samplerate = FFMAX(*p, best_samplerate);
+ p++;
+ }
+ return best_samplerate;
+}
+
+/* select layout with the highest channel count */
+static int select_channel_layout(AVCodec *codec)
+{
+ const uint64_t *p;
+ uint64_t best_ch_layout = 0;
+ int best_nb_channels = 0;
+
+ if (!codec->channel_layouts)
+ return AV_CH_LAYOUT_STEREO;
+
+ p = codec->channel_layouts;
+ while (*p) {
+ int nb_channels = av_get_channel_layout_nb_channels(*p);
+
+ if (nb_channels > best_nb_channels) {
+ best_ch_layout = *p;
+ best_nb_channels = nb_channels;
+ }
+ p++;
+ }
+ return best_ch_layout;
+}
+
+/*
+ * Audio encoding example
+ */
+static void audio_encode_example(const char *filename)
+{
+ AVCodec *codec;
+ AVCodecContext *c= NULL;
+ AVFrame *frame;
+ AVPacket pkt;
+ int i, j, k, ret, got_output;
+ int buffer_size;
+ FILE *f;
+ uint16_t *samples;
+ float t, tincr;
+
+ printf("Encode audio file %s\n", filename);
+
+ /* find the MP2 encoder */
+ codec = avcodec_find_encoder(AV_CODEC_ID_MP2);
+ if (!codec) {
+ fprintf(stderr, "Codec not found\n");
+ exit(1);
+ }
+
+ c = avcodec_alloc_context3(codec);
+ if (!c) {
+ fprintf(stderr, "Could not allocate audio codec context\n");
+ exit(1);
+ }
+
+ /* put sample parameters */
+ c->bit_rate = 64000;
+
+ /* check that the encoder supports s16 pcm input */
+ c->sample_fmt = AV_SAMPLE_FMT_S16;
+ if (!check_sample_fmt(codec, c->sample_fmt)) {
+ fprintf(stderr, "Encoder does not support sample format %s",
+ av_get_sample_fmt_name(c->sample_fmt));
+ exit(1);
+ }
+
+ /* select other audio parameters supported by the encoder */
+ c->sample_rate = select_sample_rate(codec);
+ c->channel_layout = select_channel_layout(codec);
+ c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
+
+ /* open it */
+ if (avcodec_open2(c, codec, NULL) < 0) {
+ fprintf(stderr, "Could not open codec\n");
+ exit(1);
+ }
+
+ f = fopen(filename, "wb");
+ if (!f) {
+ fprintf(stderr, "Could not open %s\n", filename);
+ exit(1);
+ }
+
+ /* frame containing input raw audio */
+ frame = avcodec_alloc_frame();
+ if (!frame) {
+ fprintf(stderr, "Could not allocate audio frame\n");
+ exit(1);
+ }
+
+ frame->nb_samples = c->frame_size;
+ frame->format = c->sample_fmt;
+ frame->channel_layout = c->channel_layout;
+
+ /* the codec gives us the frame size, in samples,
+ * we calculate the size of the samples buffer in bytes */
+ buffer_size = av_samples_get_buffer_size(NULL, c->channels, c->frame_size,
+ c->sample_fmt, 0);
+ samples = av_malloc(buffer_size);
+ if (!samples) {
+ fprintf(stderr, "Could not allocate %d bytes for samples buffer\n",
+ buffer_size);
+ exit(1);
+ }
+ /* setup the data pointers in the AVFrame */
+ ret = avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,
+ (const uint8_t*)samples, buffer_size, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Could not setup audio frame\n");
+ exit(1);
+ }
+
+ /* encode a single tone sound */
+ t = 0;
+ tincr = 2 * M_PI * 440.0 / c->sample_rate;
+ for(i=0;i<200;i++) {
+ av_init_packet(&pkt);
+ pkt.data = NULL; // packet data will be allocated by the encoder
+ pkt.size = 0;
+
+ for (j = 0; j < c->frame_size; j++) {
+ samples[2*j] = (int)(sin(t) * 10000);
+
+ for (k = 1; k < c->channels; k++)
+ samples[2*j + k] = samples[2*j];
+ t += tincr;
+ }
+ /* encode the samples */
+ ret = avcodec_encode_audio2(c, &pkt, frame, &got_output);
+ if (ret < 0) {
+ fprintf(stderr, "Error encoding audio frame\n");
+ exit(1);
+ }
+ if (got_output) {
+ fwrite(pkt.data, 1, pkt.size, f);
+ av_free_packet(&pkt);
+ }
+ }
+
+ /* get the delayed frames */
+ for (got_output = 1; got_output; i++) {
+ ret = avcodec_encode_audio2(c, &pkt, NULL, &got_output);
+ if (ret < 0) {
+ fprintf(stderr, "Error encoding frame\n");
+ exit(1);
+ }
+
+ if (got_output) {
+ fwrite(pkt.data, 1, pkt.size, f);
+ av_free_packet(&pkt);
+ }
+ }
+ fclose(f);
+
+ av_freep(&samples);
+ avcodec_free_frame(&frame);
+ avcodec_close(c);
+ av_free(c);
+}
+
+/*
+ * Audio decoding.
+ */
+static void audio_decode_example(const char *outfilename, const char *filename)
+{
+ AVCodec *codec;
+ AVCodecContext *c= NULL;
+ int len;
+ FILE *f, *outfile;
+ uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
+ AVPacket avpkt;
+ AVFrame *decoded_frame = NULL;
+
+ av_init_packet(&avpkt);
+
+ printf("Decode audio file %s to %s\n", filename, outfilename);
+
+ /* find the mpeg audio decoder */
+ codec = avcodec_find_decoder(AV_CODEC_ID_MP2);
+ if (!codec) {
+ fprintf(stderr, "Codec not found\n");
+ exit(1);
+ }
+
+ c = avcodec_alloc_context3(codec);
+ if (!c) {
+ fprintf(stderr, "Could not allocate audio codec context\n");
+ exit(1);
+ }
+
+ /* open it */
+ if (avcodec_open2(c, codec, NULL) < 0) {
+ fprintf(stderr, "Could not open codec\n");
+ exit(1);
+ }
+
+ f = fopen(filename, "rb");
+ if (!f) {
+ fprintf(stderr, "Could not open %s\n", filename);
+ exit(1);
+ }
+ outfile = fopen(outfilename, "wb");
+ if (!outfile) {
+ av_free(c);
+ exit(1);
+ }
+
+ /* decode until eof */
+ avpkt.data = inbuf;
+ avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
+
+ while (avpkt.size > 0) {
+ int got_frame = 0;
+
+ if (!decoded_frame) {
+ if (!(decoded_frame = avcodec_alloc_frame())) {
+ fprintf(stderr, "Could not allocate audio frame\n");
+ exit(1);
+ }
+ } else
+ avcodec_get_frame_defaults(decoded_frame);
+
+ len = avcodec_decode_audio4(c, decoded_frame, &got_frame, &avpkt);
+ if (len < 0) {
+ fprintf(stderr, "Error while decoding\n");
+ exit(1);
+ }
+ if (got_frame) {
+ /* if a frame has been decoded, output it */
+ int data_size = av_samples_get_buffer_size(NULL, c->channels,
+ decoded_frame->nb_samples,
+ c->sample_fmt, 1);
+ fwrite(decoded_frame->data[0], 1, data_size, outfile);
+ }
+ avpkt.size -= len;
+ avpkt.data += len;
+ avpkt.dts =
+ avpkt.pts = AV_NOPTS_VALUE;
+ if (avpkt.size < AUDIO_REFILL_THRESH) {
+ /* Refill the input buffer, to avoid trying to decode
+ * incomplete frames. Instead of this, one could also use
+ * a parser, or use a proper container format through
+ * libavformat. */
+ memmove(inbuf, avpkt.data, avpkt.size);
+ avpkt.data = inbuf;
+ len = fread(avpkt.data + avpkt.size, 1,
+ AUDIO_INBUF_SIZE - avpkt.size, f);
+ if (len > 0)
+ avpkt.size += len;
+ }
+ }
+
+ fclose(outfile);
+ fclose(f);
+
+ avcodec_close(c);
+ av_free(c);
+ avcodec_free_frame(&decoded_frame);
+}
+
+/*
+ * Video encoding example
+ */
+static void video_encode_example(const char *filename, int codec_id)
+{
+ AVCodec *codec;
+ AVCodecContext *c= NULL;
+ int i, ret, x, y, got_output;
+ FILE *f;
+ AVFrame *frame;
+ AVPacket pkt;
+ uint8_t endcode[] = { 0, 0, 1, 0xb7 };
+
+ printf("Encode video file %s\n", filename);
+
+ /* find the mpeg1 video encoder */
+ codec = avcodec_find_encoder(codec_id);
+ if (!codec) {
+ fprintf(stderr, "Codec not found\n");
+ exit(1);
+ }
+
+ c = avcodec_alloc_context3(codec);
+ if (!c) {
+ fprintf(stderr, "Could not allocate video codec context\n");
+ exit(1);
+ }
+
+ /* put sample parameters */
+ c->bit_rate = 400000;
+ /* resolution must be a multiple of two */
+ c->width = 352;
+ c->height = 288;
+ /* frames per second */
+ c->time_base= (AVRational){1,25};
+ c->gop_size = 10; /* emit one intra frame every ten frames */
+ c->max_b_frames=1;
+ c->pix_fmt = AV_PIX_FMT_YUV420P;
+
+ if(codec_id == AV_CODEC_ID_H264)
+ av_opt_set(c->priv_data, "preset", "slow", 0);
+
+ /* open it */
+ if (avcodec_open2(c, codec, NULL) < 0) {
+ fprintf(stderr, "Could not open codec\n");
+ exit(1);
+ }
+
+ f = fopen(filename, "wb");
+ if (!f) {
+ fprintf(stderr, "Could not open %s\n", filename);
+ exit(1);
+ }
+
+ frame = avcodec_alloc_frame();
+ if (!frame) {
+ fprintf(stderr, "Could not allocate video frame\n");
+ exit(1);
+ }
+ frame->format = c->pix_fmt;
+ frame->width = c->width;
+ frame->height = c->height;
+
+ /* the image can be allocated by any means and av_image_alloc() is
+ * just the most convenient way if av_malloc() is to be used */
+ ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height,
+ c->pix_fmt, 32);
+ if (ret < 0) {
+ fprintf(stderr, "Could not allocate raw picture buffer\n");
+ exit(1);
+ }
+
+ /* encode 1 second of video */
+ for(i=0;i<25;i++) {
+ av_init_packet(&pkt);
+ pkt.data = NULL; // packet data will be allocated by the encoder
+ pkt.size = 0;
+
+ fflush(stdout);
+ /* prepare a dummy image */
+ /* Y */
+ for(y=0;y<c->height;y++) {
+ for(x=0;x<c->width;x++) {
+ frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
+ }
+ }
+
+ /* Cb and Cr */
+ for(y=0;y<c->height/2;y++) {
+ for(x=0;x<c->width/2;x++) {
+ frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
+ frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
+ }
+ }
+
+ frame->pts = i;
+
+ /* encode the image */
+ ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
+ if (ret < 0) {
+ fprintf(stderr, "Error encoding frame\n");
+ exit(1);
+ }
+
+ if (got_output) {
+ printf("Write frame %3d (size=%5d)\n", i, pkt.size);
+ fwrite(pkt.data, 1, pkt.size, f);
+ av_free_packet(&pkt);
+ }
+ }
+
+ /* get the delayed frames */
+ for (got_output = 1; got_output; i++) {
+ fflush(stdout);
+
+ ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
+ if (ret < 0) {
+ fprintf(stderr, "Error encoding frame\n");
+ exit(1);
+ }
+
+ if (got_output) {
+ printf("Write frame %3d (size=%5d)\n", i, pkt.size);
+ fwrite(pkt.data, 1, pkt.size, f);
+ av_free_packet(&pkt);
+ }
+ }
+
+ /* add sequence end code to have a real mpeg file */
+ fwrite(endcode, 1, sizeof(endcode), f);
+ fclose(f);
+
+ avcodec_close(c);
+ av_free(c);
+ av_freep(&frame->data[0]);
+ avcodec_free_frame(&frame);
+ printf("\n");
+}
+
+/*
+ * Video decoding example
+ */
+
+static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
+ char *filename)
+{
+ FILE *f;
+ int i;
+
+ f=fopen(filename,"w");
+ fprintf(f,"P5\n%d %d\n%d\n",xsize,ysize,255);
+ for(i=0;i<ysize;i++)
+ fwrite(buf + i * wrap,1,xsize,f);
+ fclose(f);
+}
+
+static int decode_write_frame(const char *outfilename, AVCodecContext *avctx,
+ AVFrame *frame, int *frame_count, AVPacket *pkt, int last)
+{
+ int len, got_frame;
+ char buf[1024];
+
+ len = avcodec_decode_video2(avctx, frame, &got_frame, pkt);
+ if (len < 0) {
+ fprintf(stderr, "Error while decoding frame %d\n", *frame_count);
+ return len;
+ }
+ if (got_frame) {
+ printf("Saving %sframe %3d\n", last ? "last " : "", *frame_count);
+ fflush(stdout);
+
+ /* the picture is allocated by the decoder, no need to free it */
+ snprintf(buf, sizeof(buf), outfilename, *frame_count);
+ pgm_save(frame->data[0], frame->linesize[0],
+ avctx->width, avctx->height, buf);
+ (*frame_count)++;
+ }
+ if (pkt->data) {
+ pkt->size -= len;
+ pkt->data += len;
+ }
+ return 0;
+}
+
+static void video_decode_example(const char *outfilename, const char *filename)
+{
+ AVCodec *codec;
+ AVCodecContext *c= NULL;
+ int frame_count;
+ FILE *f;
+ AVFrame *frame;
+ uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
+ AVPacket avpkt;
+
+ av_init_packet(&avpkt);
+
+ /* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */
+ memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+
+ printf("Decode video file %s to %s\n", filename, outfilename);
+
+ /* find the mpeg1 video decoder */
+ codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO);
+ if (!codec) {
+ fprintf(stderr, "Codec not found\n");
+ exit(1);
+ }
+
+ c = avcodec_alloc_context3(codec);
+ if (!c) {
+ fprintf(stderr, "Could not allocate video codec context\n");
+ exit(1);
+ }
+
+ if(codec->capabilities&CODEC_CAP_TRUNCATED)
+ c->flags|= CODEC_FLAG_TRUNCATED; /* we do not send complete frames */
+
+ /* For some codecs, such as msmpeg4 and mpeg4, width and height
+ MUST be initialized there because this information is not
+ available in the bitstream. */
+
+ /* open it */
+ if (avcodec_open2(c, codec, NULL) < 0) {
+ fprintf(stderr, "Could not open codec\n");
+ exit(1);
+ }
+
+ f = fopen(filename, "rb");
+ if (!f) {
+ fprintf(stderr, "Could not open %s\n", filename);
+ exit(1);
+ }
+
+ frame = avcodec_alloc_frame();
+ if (!frame) {
+ fprintf(stderr, "Could not allocate video frame\n");
+ exit(1);
+ }
+
+ frame_count = 0;
+ for(;;) {
+ avpkt.size = fread(inbuf, 1, INBUF_SIZE, f);
+ if (avpkt.size == 0)
+ break;
+
+ /* NOTE1: some codecs are stream based (mpegvideo, mpegaudio)
+ and this is the only method to use them because you cannot
+ know the compressed data size before analysing it.
+
+ BUT some other codecs (msmpeg4, mpeg4) are inherently frame
+ based, so you must call them with all the data for one
+ frame exactly. You must also initialize 'width' and
+ 'height' before initializing them. */
+
+ /* NOTE2: some codecs allow the raw parameters (frame size,
+ sample rate) to be changed at any frame. We handle this, so
+ you should also take care of it */
+
+ /* here, we use a stream based decoder (mpeg1video), so we
+ feed decoder and see if it could decode a frame */
+ avpkt.data = inbuf;
+ while (avpkt.size > 0)
+ if (decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 0) < 0)
+ exit(1);
+ }
+
+ /* some codecs, such as MPEG, transmit the I and P frame with a
+ latency of one frame. You must do the following to have a
+ chance to get the last frame of the video */
+ avpkt.data = NULL;
+ avpkt.size = 0;
+ decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 1);
+
+ fclose(f);
+
+ avcodec_close(c);
+ av_free(c);
+ avcodec_free_frame(&frame);
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ const char *output_type;
+
+ /* register all the codecs */
+ avcodec_register_all();
+
+ if (argc < 2) {
+ printf("usage: %s output_type\n"
+ "API example program to decode/encode a media stream with libavcodec.\n"
+ "This program generates a synthetic stream and encodes it to a file\n"
+ "named test.h264, test.mp2 or test.mpg depending on output_type.\n"
+ "The encoded stream is then decoded and written to a raw data output.\n"
+ "output_type must be choosen 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 {
+ fprintf(stderr, "Invalid output type '%s', choose between 'h264', 'mp2', or 'mpg'\n",
+ output_type);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/doc/examples/demuxing.c b/doc/examples/demuxing.c
new file mode 100644
index 0000000..e459cf0
--- a/dev/null
+++ b/doc/examples/demuxing.c
@@ -0,0 +1,341 @@
+/*
+ * 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
+ * libavformat demuxing API use example.
+ *
+ * Show how to use the libavformat and libavcodec API to demux and
+ * decode audio and video data.
+ * @example doc/examples/demuxing.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;
+
+static int decode_packet(int *got_frame, int cached)
+{
+ int ret = 0;
+ int decoded = pkt.size;
+
+ 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\n");
+ 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\n");
+ 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);
+ }
+ }
+
+ 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;
+
+ 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 ret;
+ }
+
+ if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 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) {
+ fprintf(stderr, "usage: %s 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", argv[0]);
+ exit(1);
+ }
+ 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", video_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;
+ }
+
+ frame = avcodec_alloc_frame();
+ 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:
+ if (video_dec_ctx)
+ avcodec_close(video_dec_ctx);
+ if (audio_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);
+ av_free(frame);
+ av_free(video_dst_data[0]);
+
+ return ret < 0;
+}
diff --git a/doc/examples/filtering_audio.c b/doc/examples/filtering_audio.c
new file mode 100644
index 0000000..35dd4e7
--- a/dev/null
+++ b/doc/examples/filtering_audio.c
@@ -0,0 +1,265 @@
+/*
+ * 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 doc/examples/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;
+ 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();
+
+ /* 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");
+ return ret;
+ }
+
+ /* 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");
+ return ret;
+ }
+
+ 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");
+ return ret;
+ }
+
+ 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");
+ return ret;
+ }
+
+ 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");
+ return ret;
+ }
+
+ /* 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)
+ return ret;
+
+ if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
+ return ret;
+
+ /* 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);
+
+ return 0;
+}
+
+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 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);
+ }
+
+ avcodec_register_all();
+ 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 == audio_stream_index) {
+ avcodec_get_frame_defaults(frame);
+ 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;
+ }
+
+ 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);
+ }
+ }
+ }
+ av_free_packet(&packet);
+ }
+end:
+ avfilter_graph_free(&filter_graph);
+ if (dec_ctx)
+ avcodec_close(dec_ctx);
+ avformat_close_input(&fmt_ctx);
+ av_frame_free(&frame);
+ av_frame_free(&filt_frame);
+
+ if (ret < 0 && ret != AVERROR_EOF) {
+ char buf[1024];
+ av_strerror(ret, buf, sizeof(buf));
+ fprintf(stderr, "Error occurred: %s\n", buf);
+ exit(1);
+ }
+
+ exit(0);
+}
diff --git a/doc/examples/filtering_video.c b/doc/examples/filtering_video.c
new file mode 100644
index 0000000..d3c33df
--- a/dev/null
+++ b/doc/examples/filtering_video.c
@@ -0,0 +1,251 @@
+/*
+ * 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 doc/examples/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>
+
+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;
+
+ /* 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;
+ 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 };
+ AVBufferSinkParams *buffersink_params;
+
+ filter_graph = avfilter_graph_alloc();
+
+ /* 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");
+ return ret;
+ }
+
+ /* buffer video sink: to terminate the filter chain. */
+ buffersink_params = av_buffersink_params_alloc();
+ buffersink_params->pixel_fmts = pix_fmts;
+ ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
+ NULL, buffersink_params, filter_graph);
+ av_free(buffersink_params);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
+ return ret;
+ }
+
+ /* 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)
+ return ret;
+
+ if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
+ return ret;
+ return 0;
+}
+
+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);
+ }
+
+ avcodec_register_all();
+ 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) {
+ avcodec_get_frame_defaults(frame);
+ 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_free_packet(&packet);
+ }
+end:
+ avfilter_graph_free(&filter_graph);
+ if (dec_ctx)
+ avcodec_close(dec_ctx);
+ avformat_close_input(&fmt_ctx);
+ av_frame_free(&frame);
+ av_frame_free(&filt_frame);
+
+ if (ret < 0 && ret != AVERROR_EOF) {
+ char buf[1024];
+ av_strerror(ret, buf, sizeof(buf));
+ fprintf(stderr, "Error occurred: %s\n", buf);
+ exit(1);
+ }
+
+ exit(0);
+}
diff --git a/doc/examples/metadata.c b/doc/examples/metadata.c
new file mode 100644
index 0000000..9c1bcd7
--- a/dev/null
+++ b/doc/examples/metadata.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011 Reinhard Tartler
+ *
+ * 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
+ * Shows how the metadata API can be used in application programs.
+ * @example doc/examples/metadata.c
+ */
+
+#include <stdio.h>
+
+#include <libavformat/avformat.h>
+#include <libavutil/dict.h>
+
+int main (int argc, char **argv)
+{
+ AVFormatContext *fmt_ctx = NULL;
+ AVDictionaryEntry *tag = NULL;
+ int ret;
+
+ if (argc != 2) {
+ printf("usage: %s <input_file>\n"
+ "example program to demonstrate the use of the libavformat metadata API.\n"
+ "\n", argv[0]);
+ return 1;
+ }
+
+ av_register_all();
+ if ((ret = avformat_open_input(&fmt_ctx, argv[1], NULL, NULL)))
+ return ret;
+
+ while ((tag = av_dict_get(fmt_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
+ printf("%s=%s\n", tag->key, tag->value);
+
+ avformat_close_input(&fmt_ctx);
+ return 0;
+}
diff --git a/doc/examples/muxing.c b/doc/examples/muxing.c
new file mode 100644
index 0000000..a8f979f
--- a/dev/null
+++ b/doc/examples/muxing.c
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * libavformat API example.
+ *
+ * Output a media file in any supported libavformat format.
+ * The default codecs are used.
+ * @example doc/examples/muxing.c
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include <libavutil/opt.h>
+#include <libavutil/mathematics.h>
+#include <libavformat/avformat.h>
+#include <libswscale/swscale.h>
+#include <libswresample/swresample.h>
+
+/* 5 seconds stream duration */
+#define STREAM_DURATION 200.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 */
+
+static int sws_flags = SWS_BICUBIC;
+
+/* Add an output stream. */
+static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec,
+ enum AVCodecID codec_id)
+{
+ AVCodecContext *c;
+ AVStream *st;
+
+ /* 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);
+ }
+
+ st = avformat_new_stream(oc, *codec);
+ if (!st) {
+ fprintf(stderr, "Could not allocate stream\n");
+ exit(1);
+ }
+ st->id = oc->nb_streams-1;
+ c = st->codec;
+
+ switch ((*codec)->type) {
+ case AVMEDIA_TYPE_AUDIO:
+ c->sample_fmt = AV_SAMPLE_FMT_FLTP;
+ c->bit_rate = 64000;
+ c->sample_rate = 44100;
+ c->channels = 2;
+ 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. */
+ c->time_base.den = STREAM_FRAME_RATE;
+ c->time_base.num = 1;
+ c->gop_size = 12; /* emit one intra frame every twelve frames at most */
+ c->pix_fmt = STREAM_PIX_FMT;
+ if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
+ /* just for testing, we also add B frames */
+ c->max_b_frames = 2;
+ }
+ if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
+ /* Needed to avoid using macroblocks in which some coeffs overflow.
+ * This does not happen with normal video, it just happens here as
+ * the motion of the chroma plane does not match the luma plane. */
+ c->mb_decision = 2;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* Some formats want stream headers to be separate. */
+ if (oc->oformat->flags & AVFMT_GLOBALHEADER)
+ c->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+ return st;
+}
+
+/**************************************************************/
+/* audio output */
+
+static float t, tincr, tincr2;
+
+static uint8_t **src_samples_data;
+static int src_samples_linesize;
+static int src_nb_samples;
+
+static int max_dst_nb_samples;
+uint8_t **dst_samples_data;
+int dst_samples_linesize;
+int dst_samples_size;
+
+struct SwrContext *swr_ctx = NULL;
+
+static void open_audio(AVFormatContext *oc, AVCodec *codec, AVStream *st)
+{
+ AVCodecContext *c;
+ int ret;
+
+ c = st->codec;
+
+ /* open it */
+ ret = avcodec_open2(c, codec, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open audio codec: %s\n", av_err2str(ret));
+ exit(1);
+ }
+
+ /* init signal generator */
+ t = 0;
+ tincr = 2 * M_PI * 110.0 / c->sample_rate;
+ /* increment frequency by 110 Hz per second */
+ tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;
+
+ src_nb_samples = c->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE ?
+ 10000 : c->frame_size;
+
+ ret = av_samples_alloc_array_and_samples(&src_samples_data, &src_samples_linesize, c->channels,
+ src_nb_samples, c->sample_fmt, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Could not allocate source samples\n");
+ exit(1);
+ }
+
+ /* create resampler context */
+ if (c->sample_fmt != AV_SAMPLE_FMT_S16) {
+ swr_ctx = swr_alloc();
+ if (!swr_ctx) {
+ fprintf(stderr, "Could not allocate resampler context\n");
+ exit(1);
+ }
+
+ /* set options */
+ av_opt_set_int (swr_ctx, "in_channel_count", c->channels, 0);
+ av_opt_set_int (swr_ctx, "in_sample_rate", c->sample_rate, 0);
+ av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
+ av_opt_set_int (swr_ctx, "out_channel_count", c->channels, 0);
+ av_opt_set_int (swr_ctx, "out_sample_rate", c->sample_rate, 0);
+ av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", c->sample_fmt, 0);
+
+ /* initialize the resampling context */
+ if ((ret = swr_init(swr_ctx)) < 0) {
+ fprintf(stderr, "Failed to initialize the resampling context\n");
+ exit(1);
+ }
+ }
+
+ /* 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 = src_nb_samples;
+ ret = av_samples_alloc_array_and_samples(&dst_samples_data, &dst_samples_linesize, c->channels,
+ max_dst_nb_samples, c->sample_fmt, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Could not allocate destination samples\n");
+ exit(1);
+ }
+ dst_samples_size = av_samples_get_buffer_size(NULL, c->channels, max_dst_nb_samples,
+ c->sample_fmt, 0);
+}
+
+/* Prepare a 16 bit dummy audio frame of 'frame_size' samples and
+ * 'nb_channels' channels. */
+static void get_audio_frame(int16_t *samples, int frame_size, int nb_channels)
+{
+ int j, i, v;
+ int16_t *q;
+
+ q = samples;
+ for (j = 0; j < frame_size; j++) {
+ v = (int)(sin(t) * 10000);
+ for (i = 0; i < nb_channels; i++)
+ *q++ = v;
+ t += tincr;
+ tincr += tincr2;
+ }
+}
+
+static void write_audio_frame(AVFormatContext *oc, AVStream *st)
+{
+ AVCodecContext *c;
+ AVPacket pkt = { 0 }; // data and size must be 0;
+ AVFrame *frame = avcodec_alloc_frame();
+ int got_packet, ret, dst_nb_samples;
+
+ av_init_packet(&pkt);
+ c = st->codec;
+
+ get_audio_frame((int16_t *)src_samples_data[0], src_nb_samples, c->channels);
+
+ /* convert samples from native format to destination codec format, using the resampler */
+ if (swr_ctx) {
+ /* compute destination number of samples */
+ dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, c->sample_rate) + src_nb_samples,
+ c->sample_rate, c->sample_rate, AV_ROUND_UP);
+ if (dst_nb_samples > max_dst_nb_samples) {
+ av_free(dst_samples_data[0]);
+ ret = av_samples_alloc(dst_samples_data, &dst_samples_linesize, c->channels,
+ dst_nb_samples, c->sample_fmt, 0);
+ if (ret < 0)
+ exit(1);
+ max_dst_nb_samples = dst_nb_samples;
+ dst_samples_size = av_samples_get_buffer_size(NULL, c->channels, dst_nb_samples,
+ c->sample_fmt, 0);
+ }
+
+ /* convert to destination format */
+ ret = swr_convert(swr_ctx,
+ dst_samples_data, dst_nb_samples,
+ (const uint8_t **)src_samples_data, src_nb_samples);
+ if (ret < 0) {
+ fprintf(stderr, "Error while converting\n");
+ exit(1);
+ }
+ } else {
+ dst_samples_data[0] = src_samples_data[0];
+ dst_nb_samples = src_nb_samples;
+ }
+
+ frame->nb_samples = dst_nb_samples;
+ avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,
+ dst_samples_data[0], dst_samples_size, 0);
+
+ 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)
+ return;
+
+ pkt.stream_index = st->index;
+
+ /* Write the compressed frame to the media file. */
+ ret = av_interleaved_write_frame(oc, &pkt);
+ if (ret != 0) {
+ fprintf(stderr, "Error while writing audio frame: %s\n",
+ av_err2str(ret));
+ exit(1);
+ }
+ avcodec_free_frame(&frame);
+}
+
+static void close_audio(AVFormatContext *oc, AVStream *st)
+{
+ avcodec_close(st->codec);
+ av_free(src_samples_data[0]);
+ av_free(dst_samples_data[0]);
+}
+
+/**************************************************************/
+/* video output */
+
+static AVFrame *frame;
+static AVPicture src_picture, dst_picture;
+static int frame_count;
+
+static void open_video(AVFormatContext *oc, AVCodec *codec, AVStream *st)
+{
+ int ret;
+ AVCodecContext *c = st->codec;
+
+ /* open the codec */
+ ret = avcodec_open2(c, codec, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open video codec: %s\n", av_err2str(ret));
+ exit(1);
+ }
+
+ /* allocate and init a re-usable frame */
+ frame = avcodec_alloc_frame();
+ if (!frame) {
+ fprintf(stderr, "Could not allocate video frame\n");
+ exit(1);
+ }
+
+ /* Allocate the encoded raw picture. */
+ ret = avpicture_alloc(&dst_picture, c->pix_fmt, c->width, c->height);
+ if (ret < 0) {
+ fprintf(stderr, "Could not allocate picture: %s\n", av_err2str(ret));
+ exit(1);
+ }
+
+ /* If the output format is not YUV420P, then a temporary YUV420P
+ * picture is needed too. It is then converted to the required
+ * output format. */
+ if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
+ ret = avpicture_alloc(&src_picture, AV_PIX_FMT_YUV420P, c->width, c->height);
+ if (ret < 0) {
+ fprintf(stderr, "Could not allocate temporary picture: %s\n",
+ av_err2str(ret));
+ exit(1);
+ }
+ }
+
+ /* copy data and linesize picture pointers to frame */
+ *((AVPicture *)frame) = dst_picture;
+}
+
+/* Prepare a dummy image. */
+static void fill_yuv_image(AVPicture *pict, int frame_index,
+ int width, int height)
+{
+ int x, y, i;
+
+ i = frame_index;
+
+ /* Y */
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
+
+ /* Cb and Cr */
+ for (y = 0; y < height / 2; y++) {
+ for (x = 0; x < width / 2; x++) {
+ pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
+ pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
+ }
+ }
+}
+
+static void write_video_frame(AVFormatContext *oc, AVStream *st)
+{
+ int ret;
+ static struct SwsContext *sws_ctx;
+ AVCodecContext *c = st->codec;
+
+ if (frame_count >= STREAM_NB_FRAMES) {
+ /* No more frames to compress. The codec has a latency of a few
+ * frames if using B-frames, so we get the last frames by
+ * passing the same picture again. */
+ } else {
+ if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
+ /* as we only generate a YUV420P picture, we must convert it
+ * to the codec pixel format if needed */
+ if (!sws_ctx) {
+ sws_ctx = sws_getContext(c->width, c->height, AV_PIX_FMT_YUV420P,
+ c->width, c->height, c->pix_fmt,
+ sws_flags, NULL, NULL, NULL);
+ if (!sws_ctx) {
+ fprintf(stderr,
+ "Could not initialize the conversion context\n");
+ exit(1);
+ }
+ }
+ fill_yuv_image(&src_picture, frame_count, c->width, c->height);
+ sws_scale(sws_ctx,
+ (const uint8_t * const *)src_picture.data, src_picture.linesize,
+ 0, c->height, dst_picture.data, dst_picture.linesize);
+ } else {
+ fill_yuv_image(&dst_picture, frame_count, c->width, c->height);
+ }
+ }
+
+ if (oc->oformat->flags & AVFMT_RAWPICTURE) {
+ /* Raw video case - directly store the picture in the packet */
+ AVPacket pkt;
+ av_init_packet(&pkt);
+
+ pkt.flags |= AV_PKT_FLAG_KEY;
+ pkt.stream_index = st->index;
+ pkt.data = dst_picture.data[0];
+ pkt.size = sizeof(AVPicture);
+
+ ret = av_interleaved_write_frame(oc, &pkt);
+ } else {
+ AVPacket pkt = { 0 };
+ int got_packet;
+ av_init_packet(&pkt);
+
+ /* encode the image */
+ ret = avcodec_encode_video2(c, &pkt, frame, &got_packet);
+ if (ret < 0) {
+ fprintf(stderr, "Error encoding video frame: %s\n", av_err2str(ret));
+ exit(1);
+ }
+ /* If size is zero, it means the image was buffered. */
+
+ if (!ret && got_packet && pkt.size) {
+ pkt.stream_index = st->index;
+
+ /* Write the compressed frame to the media file. */
+ ret = av_interleaved_write_frame(oc, &pkt);
+ } else {
+ ret = 0;
+ }
+ }
+ if (ret != 0) {
+ fprintf(stderr, "Error while writing video frame: %s\n", av_err2str(ret));
+ exit(1);
+ }
+ frame_count++;
+}
+
+static void close_video(AVFormatContext *oc, AVStream *st)
+{
+ avcodec_close(st->codec);
+ av_free(src_picture.data[0]);
+ av_free(dst_picture.data[0]);
+ av_free(frame);
+}
+
+/**************************************************************/
+/* media file output */
+
+int main(int argc, char **argv)
+{
+ const char *filename;
+ AVOutputFormat *fmt;
+ AVFormatContext *oc;
+ AVStream *audio_st, *video_st;
+ AVCodec *audio_codec, *video_codec;
+ double audio_time, video_time;
+ int ret;
+
+ /* Initialize libavcodec, and register all codecs and formats. */
+ av_register_all();
+
+ if (argc != 2) {
+ printf("usage: %s output_file\n"
+ "API example program to output a media file with libavformat.\n"
+ "This program generates a synthetic audio and video stream, encodes and\n"
+ "muxes them into a file named output_file.\n"
+ "The output format is automatically guessed according to the file extension.\n"
+ "Raw images can also be output by using '%%d' in the filename.\n"
+ "\n", argv[0]);
+ return 1;
+ }
+
+ filename = argv[1];
+
+ /* allocate the output media context */
+ avformat_alloc_output_context2(&oc, NULL, NULL, filename);
+ if (!oc) {
+ printf("Could not deduce output format from file extension: using MPEG.\n");
+ avformat_alloc_output_context2(&oc, NULL, "mpeg", filename);
+ }
+ if (!oc) {
+ return 1;
+ }
+ fmt = oc->oformat;
+
+ /* Add the audio and video streams using the default format codecs
+ * and initialize the codecs. */
+ video_st = NULL;
+ audio_st = NULL;
+
+ if (fmt->video_codec != AV_CODEC_ID_NONE) {
+ video_st = add_stream(oc, &video_codec, fmt->video_codec);
+ }
+ if (fmt->audio_codec != AV_CODEC_ID_NONE) {
+ audio_st = add_stream(oc, &audio_codec, fmt->audio_codec);
+ }
+
+ /* Now that all the parameters are set, we can open the audio and
+ * video codecs and allocate the necessary encode buffers. */
+ if (video_st)
+ open_video(oc, video_codec, video_st);
+ if (audio_st)
+ open_audio(oc, audio_codec, audio_st);
+
+ av_dump_format(oc, 0, filename, 1);
+
+ /* open the output file, if needed */
+ if (!(fmt->flags & AVFMT_NOFILE)) {
+ ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open '%s': %s\n", filename,
+ av_err2str(ret));
+ return 1;
+ }
+ }
+
+ /* Write the stream header, if any. */
+ ret = avformat_write_header(oc, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Error occurred when opening output file: %s\n",
+ av_err2str(ret));
+ return 1;
+ }
+
+ if (frame)
+ frame->pts = 0;
+ for (;;) {
+ /* Compute current audio and video time. */
+ audio_time = audio_st ? audio_st->pts.val * av_q2d(audio_st->time_base) : 0.0;
+ video_time = video_st ? video_st->pts.val * av_q2d(video_st->time_base) : 0.0;
+
+ if ((!audio_st || audio_time >= STREAM_DURATION) &&
+ (!video_st || video_time >= STREAM_DURATION))
+ break;
+
+ /* write interleaved audio and video frames */
+ if (!video_st || (video_st && audio_st && audio_time < video_time)) {
+ write_audio_frame(oc, audio_st);
+ } else {
+ write_video_frame(oc, video_st);
+ frame->pts += av_rescale_q(1, video_st->codec->time_base, video_st->time_base);
+ }
+ }
+
+ /* Write the trailer, if any. The trailer must be written before you
+ * close the CodecContexts open when you wrote the header; otherwise
+ * av_write_trailer() may try to use memory that was freed on
+ * av_codec_close(). */
+ av_write_trailer(oc);
+
+ /* Close each codec. */
+ if (video_st)
+ close_video(oc, video_st);
+ if (audio_st)
+ close_audio(oc, audio_st);
+
+ if (!(fmt->flags & AVFMT_NOFILE))
+ /* Close the output file. */
+ avio_close(oc->pb);
+
+ /* free the stream */
+ avformat_free_context(oc);
+
+ return 0;
+}
diff --git a/doc/examples/resampling_audio.c b/doc/examples/resampling_audio.c
new file mode 100644
index 0000000..70db9ef
--- a/dev/null
+++ b/doc/examples/resampling_audio.c
@@ -0,0 +1,211 @@
+/*
+ * 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 doc/examples/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.
+ */
+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_free(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);
+ 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:
+ if (dst_file)
+ 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..be2c510
--- a/dev/null
+++ b/doc/examples/scaling_video.c
@@ -0,0 +1,141 @@
+/*
+ * 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 doc/examples/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:
+ if (dst_file)
+ fclose(dst_file);
+ av_freep(&src_data[0]);
+ av_freep(&dst_data[0]);
+ sws_freeContext(sws_ctx);
+ return ret < 0;
+}
diff --git a/doc/faq.texi b/doc/faq.texi
index b400124..c47d9d9 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
+
+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.
+
+@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
-Notice that you should set a reasonably high bitrate for your intermediate and
-output files, if you want to preserve video quality.
+Note that you may need to escape the character "|" which is special for many
+shells.
-Also notice that you may avoid the huge intermediate files by taking advantage
-of named pipes, should your platform support it:
+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,13 +356,13 @@ 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]
@@ -267,7 +370,7 @@ rm temp[12].[av] all.[av]
@section -profile option fails when encoding H.264 video with AAC audio
-@command{avconv} prints an error like
+@command{ffmpeg} prints an error like
@example
Undefined constant or missing '(' in 'baseline'
@@ -282,16 +385,71 @@ video and audio. Specifically the AAC encoder also defines some profiles, none
of which are named @var{baseline}.
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}.
+by using @url{http://ffmpeg.org/ffmpeg.html#Stream-specifiers-1, Stream specifiers}.
Appending @code{:v} to it will do exactly that.
+@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.
+
+Then insert the correct @code{aformat} explicitly in the filtergraph,
+specifying the exact format.
+
+@example
+aformat=sample_fmts=s16:channel_layouts=stereo
+@end example
+
+@section Why does FFmpeg not see the subtitles in my VOB file?
+
+VOB and a few other formats do not have a global header that describes
+everything present in the file. Instead, applications are supposed to scan
+the file to see what it contains. Since VOB files are frequently large, only
+the beginning is scanned. If the subtitles happen only later in the file,
+they will not be initally detected.
+
+Some applications, including the @code{ffmpeg} command-line tool, can only
+work with streams that were detected during the initial scan; streams that
+are detected later are ignored.
+
+The size of the initial scan is controlled by two options: @code{probesize}
+(default ~5 Mo) and @code{analyzeduration} (default 5,000,000 µs = 5 s). For
+the subtitle stream to be detected, both values must be large enough.
+
+@section Why was the @command{ffmpeg} @option{-sameq} option removed? What to use instead?
+
+The @option{-sameq} option meant "same quantizer", and made sense only in a
+very limited set of cases. Unfortunately, a lot of people mistook it for
+"same quality" and used it in places where it did not make sense: it had
+roughly the expected visible effect, but achieved it in a very inefficient
+way.
+
+Each encoder has its own set of options to set the quality-vs-size balance,
+use the options for the encoder you are using to set the quality level to a
+point acceptable for your tastes. The most common options to do that are
+@option{-qscale} and @option{-qmax}, but you should peruse the documentation
+of the encoder you chose.
+
@chapter Development
-@section Are there examples illustrating how to use the Libav libraries, particularly libavcodec and libavformat?
+@section Are there examples illustrating how to use the FFmpeg libraries, particularly libavcodec and libavformat?
+
+Yes. Check the @file{doc/examples} directory in the source
+repository, also available online at:
+@url{https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples}.
-Yes. Read the Developers Guide of the Libav documentation. Alternatively,
+Examples are also installed by default, usually in
+@code{$PREFIX/share/ffmpeg/examples}.
+
+Also you may read the Developers Guide of the FFmpeg documentation. Alternatively,
examine the source code for one of the many open source projects that
-already incorporate Libav at (@url{projects.html}).
+already incorporate FFmpeg at (@url{projects.html}).
@section Can you support my C compiler XXX?
@@ -302,42 +460,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.
+
+@section I'm using FFmpeg from within my C++ application but the linker complains about missing symbols which seem to be available.
-Libav is a pure C project, so to use the libraries within your C++ application
+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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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..69767a2
--- a/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 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..1eb8cd6
--- a/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 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
--- a/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/ffmpeg.texi b/doc/ffmpeg.texi
new file mode 100644
index 0000000..2bb65d5
--- a/dev/null
+++ b/doc/ffmpeg.texi
@@ -0,0 +1,1454 @@
+\input texinfo @c -*- texinfo -*-
+
+@settitle ffmpeg Documentation
+@titlepage
+@center @titlefont{ffmpeg Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Synopsis
+
+ffmpeg [@var{global_options}] @{[@var{input_file_options}] -i @file{input_file}@} ... @{[@var{output_file_options}] @file{output_file}@} ...
+
+@chapter Description
+@c man begin DESCRIPTION
+
+@command{ffmpeg} is a very fast video and audio converter that can also grab from
+a live audio/video source. It can also convert between arbitrary sample
+rates and resize video on the fly with a high quality polyphase filter.
+
+@command{ffmpeg} reads from an arbitrary number of input "files" (which can be regular
+files, pipes, network streams, grabbing devices, etc.), specified by the
+@code{-i} option, and writes to an arbitrary number of output "files", which are
+specified by a plain output filename. Anything found on the command line which
+cannot be interpreted as an option is considered to be an output filename.
+
+Each input or output file can, in principle, contain any number of streams of
+different types (video/audio/subtitle/attachment/data). The allowed number and/or
+types of streams may be limited by the container format. Selecting which
+streams from which inputs will go into which output is either done automatically
+or with the @code{-map} option (see the Stream selection chapter).
+
+To refer to input files in options, you must use their indices (0-based). E.g.
+the first input file is @code{0}, the second is @code{1}, etc. Similarly, streams
+within a file are referred to by their indices. E.g. @code{2:3} refers to the
+fourth stream in the third input file. Also see the Stream specifiers chapter.
+
+As a general rule, options are applied to the next specified
+file. Therefore, order is important, and you can have the same
+option on the command line multiple times. Each occurrence is
+then applied to the next input or output file.
+Exceptions from this rule are the global options (e.g. verbosity level),
+which should be specified first.
+
+Do not mix input and output files -- first specify all input files, then all
+output files. Also do not mix options which belong to different files. All
+options apply ONLY to the next input or output file and are reset between files.
+
+@itemize
+@item
+To set the video bitrate of the output file to 64 kbit/s:
+@example
+ffmpeg -i input.avi -b:v 64k -bufsize 64k output.avi
+@end example
+
+@item
+To force the frame rate of the output file to 24 fps:
+@example
+ffmpeg -i input.avi -r 24 output.avi
+@end example
+
+@item
+To force the frame rate of the input file (valid for raw formats only)
+to 1 fps and the frame rate of the output file to 24 fps:
+@example
+ffmpeg -r 1 -i input.m2v -r 24 output.avi
+@end example
+@end itemize
+
+The format option may be needed for raw input files.
+
+@c man end DESCRIPTION
+
+@chapter Detailed description
+@c man begin DETAILED DESCRIPTION
+
+The transcoding process in @command{ffmpeg} for each output can be described by
+the following diagram:
+
+@example
+ _______ ______________ _________ ______________ ________
+| | | | | | | | | |
+| input | demuxer | encoded data | decoder | decoded | encoder | encoded data | muxer | output |
+| file | ---------> | packets | ---------> | frames | ---------> | packets | -------> | file |
+|_______| |______________| |_________| |______________| |________|
+
+@end example
+
+@command{ffmpeg} calls the libavformat library (containing demuxers) to read
+input files and get packets containing encoded data from them. When there are
+multiple input files, @command{ffmpeg} tries to keep them synchronized by
+tracking lowest timestamp on any active input stream.
+
+Encoded packets are then passed to the decoder (unless streamcopy is selected
+for the stream, see further for a description). The decoder produces
+uncompressed frames (raw video/PCM audio/...) which can be processed further by
+filtering (see next section). After filtering, the frames are passed to the
+encoder, which encodes them and outputs encoded packets. Finally those are
+passed to the muxer, which writes the encoded packets to the output file.
+
+@section Filtering
+Before encoding, @command{ffmpeg} can process raw audio and video frames using
+filters from the libavfilter library. Several chained filters form a filter
+graph. @command{ffmpeg} distinguishes between two types of filtergraphs:
+simple and complex.
+
+@subsection Simple filtergraphs
+Simple filtergraphs are those that have exactly one input and output, both of
+the same type. In the above diagram they can be represented by simply inserting
+an additional step between decoding and encoding:
+
+@example
+ _________ __________ ______________
+| | | | | |
+| decoded | simple filtergraph | filtered | encoder | encoded data |
+| frames | -------------------> | frames | ---------> | packets |
+|_________| |__________| |______________|
+
+@end example
+
+Simple filtergraphs are configured with the per-stream @option{-filter} option
+(with @option{-vf} and @option{-af} aliases for video and audio respectively).
+A simple filtergraph for video can look for example like this:
+
+@example
+ _______ _____________ _______ _____ ________
+| | | | | | | | | |
+| input | ---> | deinterlace | ---> | scale | ---> | fps | ---> | output |
+|_______| |_____________| |_______| |_____| |________|
+
+@end example
+
+Note that some filters change frame properties but not frame contents. E.g. the
+@code{fps} filter in the example above changes number of frames, but does not
+touch the frame contents. Another example is the @code{setpts} filter, which
+only sets timestamps and otherwise passes the frames unchanged.
+
+@subsection Complex filtergraphs
+Complex filtergraphs are those which cannot be described as simply a linear
+processing chain applied to one stream. This is the case, 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:
+
+@example
+ _________
+| |
+| input 0 |\ __________
+|_________| \ | |
+ \ _________ /| output 0 |
+ \ | | / |__________|
+ _________ \| complex | /
+| | | |/
+| input 1 |---->| filter |\
+|_________| | | \ __________
+ /| graph | \ | |
+ / | | \| output 1 |
+ _________ / |_________| |__________|
+| | /
+| input 2 |/
+|_________|
+
+@end example
+
+Complex filtergraphs are configured with the @option{-filter_complex} option.
+Note that this option is global, since a complex filtergraph, by its nature,
+cannot be unambiguously associated with a single stream or file.
+
+The @option{-lavfi} option is equivalent to @option{-filter_complex}.
+
+A trivial example of a complex filtergraph is the @code{overlay} filter, which
+has two video inputs and one video output, containing one video overlaid on top
+of the other. Its audio counterpart is the @code{amix} filter.
+
+@section Stream copy
+Stream copy is a mode selected by supplying the @code{copy} parameter to the
+@option{-codec} option. It makes @command{ffmpeg} omit the decoding and encoding
+step for the specified stream, so it does only demuxing and muxing. It is useful
+for changing the container format or modifying container-level metadata. The
+diagram above will, in this case, simplify to this:
+
+@example
+ _______ ______________ ________
+| | | | | |
+| input | demuxer | encoded data | muxer | output |
+| file | ---------> | packets | -------> | file |
+|_______| |______________| |________|
+
+@end example
+
+Since there is no decoding or encoding, it is very fast and there is no quality
+loss. However, it might not work in some cases because of many factors. Applying
+filters is obviously also impossible, since filters work on uncompressed data.
+
+@c man end DETAILED DESCRIPTION
+
+@chapter Stream selection
+@c man begin STREAM SELECTION
+
+By default, @command{ffmpeg} includes only one stream of each type (video, audio, subtitle)
+present in the input files and adds them to each output file. It picks the
+"best" of each based upon the following criteria: for video, it is the stream
+with the highest resolution, for audio, it is the stream with the most channels, for
+subtitles, it is the first subtitle stream. In the case where several streams of
+the same type rate equally, the stream with the lowest index is chosen.
+
+You can disable some of those defaults by using the @code{-vn/-an/-sn} options. For
+full manual control, use the @code{-map} option, which disables the defaults just
+described.
+
+@c man end STREAM SELECTION
+
+@chapter Options
+@c man begin OPTIONS
+
+@include fftools-common-opts.texi
+
+@section Main options
+
+@table @option
+
+@item -f @var{fmt} (@emph{input/output})
+Force input or output file format. The format is normally auto detected for input
+files and guessed from the file extension for output files, so this option is not
+needed in most cases.
+
+@item -i @var{filename} (@emph{input})
+input file name
+
+@item -y (@emph{global})
+Overwrite output files without asking.
+
+@item -n (@emph{global})
+Do not overwrite output files, and exit immediately if a specified
+output file already exists.
+
+@item -c[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream})
+@itemx -codec[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream})
+Select an encoder (when used before an output file) or a decoder (when used
+before an input file) for one or more streams. @var{codec} is the name of a
+decoder/encoder or a special value @code{copy} (output only) to indicate that
+the stream is not to be re-encoded.
+
+For example
+@example
+ffmpeg -i INPUT -map 0 -c:v libx264 -c:a copy OUTPUT
+@end example
+encodes all video streams with libx264 and copies all audio streams.
+
+For each stream, the last matching @code{c} option is applied, so
+@example
+ffmpeg -i INPUT -map 0 -c copy -c:v:1 libx264 -c:a:137 libvorbis OUTPUT
+@end example
+will copy all the streams except the second video, which will be encoded with
+libx264, and the 138th audio, which will be encoded with libvorbis.
+
+@item -t @var{duration} (@emph{output})
+Stop writing the output after its duration reaches @var{duration}.
+@var{duration} may be a number in seconds, or in @code{hh:mm:ss[.xxx]} form.
+
+-to and -t are mutually exclusive and -t has priority.
+
+@item -to @var{position} (@emph{output})
+Stop writing the output at @var{position}.
+@var{position} may be a number in seconds, or in @code{hh:mm:ss[.xxx]} form.
+
+-to and -t are mutually exclusive and -t has priority.
+
+@item -fs @var{limit_size} (@emph{output})
+Set the file size limit, expressed in bytes.
+
+@item -ss @var{position} (@emph{input/output})
+When used as an input option (before @code{-i}), seeks in this input file to
+@var{position}. Note the in most formats it is not possible to seek exactly, so
+@command{ffmpeg} will seek to the closest seek point before @var{position}.
+When transcoding and @option{-accurate_seek} is enabled (the default), this
+extra segment between the seek point and @var{position} will be decoded and
+discarded. When doing stream copy or when @option{-noaccurate_seek} is used, it
+will be preserved.
+
+When used as an output option (before an output filename), decodes but discards
+input until the timestamps reach @var{position}.
+
+@var{position} may be either in seconds or in @code{hh:mm:ss[.xxx]} form.
+
+@item -itsoffset @var{offset} (@emph{input})
+Set the input time offset in seconds.
+@code{[-]hh:mm:ss[.xxx]} syntax is also supported.
+The offset is added to the timestamps of the input files.
+Specifying a positive offset means that the corresponding
+streams are delayed by @var{offset} seconds.
+
+@item -timestamp @var{time} (@emph{output})
+Set the recording timestamp in the container.
+The syntax for @var{time} is:
+@example
+now|([(YYYY-MM-DD|YYYYMMDD)[T|t| ]]((HH:MM:SS[.m...])|(HHMMSS[.m...]))[Z|z])
+@end example
+If the value is "now" it takes the current time.
+Time is local time unless 'Z' or '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.
+
+@item -metadata[:metadata_specifier] @var{key}=@var{value} (@emph{output,per-metadata})
+Set a metadata key/value pair.
+
+An optional @var{metadata_specifier} may be given to set metadata
+on streams or chapters. See @code{-map_metadata} documentation for
+details.
+
+This option overrides metadata set with @code{-map_metadata}. It is
+also possible to delete metadata by using an empty value.
+
+For example, for setting the title in the output file:
+@example
+ffmpeg -i in.avi -metadata title="my title" out.flv
+@end example
+
+To set the language of the first audio stream:
+@example
+ffmpeg -i INPUT -metadata:s:a:1 language=eng OUTPUT
+@end example
+
+@item -target @var{type} (@emph{output})
+Specify target file type (@code{vcd}, @code{svcd}, @code{dvd}, @code{dv},
+@code{dv50}). @var{type} may be prefixed with @code{pal-}, @code{ntsc-} or
+@code{film-} to use the corresponding standard. All the format options
+(bitrate, codecs, buffer sizes) are then set automatically. You can just type:
+
+@example
+ffmpeg -i myfile.avi -target vcd /tmp/vcd.mpg
+@end example
+
+Nevertheless you can specify additional options as long as you know
+they do not conflict with the standard, as in:
+
+@example
+ffmpeg -i myfile.avi -target vcd -bf 2 /tmp/vcd.mpg
+@end example
+
+@item -dframes @var{number} (@emph{output})
+Set the number of data frames to record. This is an alias for @code{-frames:d}.
+
+@item -frames[:@var{stream_specifier}] @var{framecount} (@emph{output,per-stream})
+Stop writing to the stream after @var{framecount} frames.
+
+@item -q[:@var{stream_specifier}] @var{q} (@emph{output,per-stream})
+@itemx -qscale[:@var{stream_specifier}] @var{q} (@emph{output,per-stream})
+Use fixed quality scale (VBR). The meaning of @var{q} is
+codec-dependent.
+
+@anchor{filter_option}
+@item -filter[:@var{stream_specifier}] @var{filtergraph} (@emph{output,per-stream})
+Create the filtergraph specified by @var{filtergraph} and use it to
+filter the stream.
+
+@var{filtergraph} is a description of the filtergraph to apply to
+the stream, and must have a single input and a single output of the
+same type of the stream. In the filtergraph, the input is associated
+to the label @code{in}, and the output to the label @code{out}. See
+the ffmpeg-filters manual for more information about the filtergraph
+syntax.
+
+See the @ref{filter_complex_option,,-filter_complex option} if you
+want to create filtergraphs with multiple inputs and/or outputs.
+
+@item -filter_script[:@var{stream_specifier}] @var{filename} (@emph{output,per-stream})
+This option is similar to @option{-filter}, the only difference is that its
+argument is the name of the file from which a filtergraph description is to be
+read.
+
+@item -pre[:@var{stream_specifier}] @var{preset_name} (@emph{output,per-stream})
+Specify the preset for matching stream(s).
+
+@item -stats (@emph{global})
+Print encoding progress/statistics. It is on by default, to explicitly
+disable it you need to specify @code{-nostats}.
+
+@item -progress @var{url} (@emph{global})
+Send program-friendly progress information to @var{url}.
+
+Progress information is written approximately every second and at the end of
+the encoding process. It is made of "@var{key}=@var{value}" lines. @var{key}
+consists of only alphanumeric characters. The last key of a sequence of
+progress information is always "progress".
+
+@item -stdin
+Enable interaction on standard input. On by default unless standard input is
+used as an input. To explicitly disable interaction you need to specify
+@code{-nostdin}.
+
+Disabling interaction on standard input is useful, for example, if
+ffmpeg is in the background process group. Roughly the same result can
+be achieved with @code{ffmpeg ... < /dev/null} but it requires a
+shell.
+
+@item -debug_ts (@emph{global})
+Print timestamp information. It is off by default. This option is
+mostly useful for testing and debugging purposes, and the output
+format may change from one version to another, so it should not be
+employed by portable scripts.
+
+See also the option @code{-fdebug ts}.
+
+@item -attach @var{filename} (@emph{output})
+Add an attachment to the output file. This is supported by a few formats
+like Matroska for e.g. fonts used in rendering subtitles. Attachments
+are implemented as a specific type of stream, so this option will add
+a new stream to the file. It is then possible to use per-stream options
+on this stream in the usual way. Attachment streams created with this
+option will be created after all the other streams (i.e. those created
+with @code{-map} or automatic mappings).
+
+Note that for Matroska you also have to set the mimetype metadata tag:
+@example
+ffmpeg -i INPUT -attach DejaVuSans.ttf -metadata:s:2 mimetype=application/x-truetype-font out.mkv
+@end example
+(assuming that the attachment stream will be third in the output file).
+
+@item -dump_attachment[:@var{stream_specifier}] @var{filename} (@emph{input,per-stream})
+Extract the matching attachment stream into a file named @var{filename}. If
+@var{filename} is empty, then the value of the @code{filename} metadata tag
+will be used.
+
+E.g. to extract the first attachment to a file named 'out.ttf':
+@example
+ffmpeg -dump_attachment:t:0 out.ttf -i INPUT
+@end example
+To extract all attachments to files determined by the @code{filename} tag:
+@example
+ffmpeg -dump_attachment:t "" -i INPUT
+@end example
+
+Technical note -- attachments are implemented as codec extradata, so this
+option can actually be used to extract extradata from any stream, not just
+attachments.
+
+@end table
+
+@section Video Options
+
+@table @option
+@item -vframes @var{number} (@emph{output})
+Set the number of video frames to record. This is an alias for @code{-frames:v}.
+@item -r[:@var{stream_specifier}] @var{fps} (@emph{input/output,per-stream})
+Set frame rate (Hz value, fraction or abbreviation).
+
+As an input option, ignore any timestamps stored in the file and instead
+generate timestamps assuming constant frame rate @var{fps}.
+
+As an output option, duplicate or drop input frames to achieve constant output
+frame rate @var{fps}.
+
+@item -s[:@var{stream_specifier}] @var{size} (@emph{input/output,per-stream})
+Set frame size.
+
+As an input option, this is a shortcut for the @option{video_size} private
+option, recognized by some demuxers for which the frame size is either not
+stored in the file or is configurable -- e.g. raw video or video grabbers.
+
+As an output option, this inserts the @code{scale} video filter to the
+@emph{end} of the corresponding filtergraph. Please use the @code{scale} filter
+directly to insert it at the beginning or some other place.
+
+The format is @samp{wxh} (default - same as source).
+
+@item -aspect[:@var{stream_specifier}] @var{aspect} (@emph{output,per-stream})
+Set the video display aspect ratio specified by @var{aspect}.
+
+@var{aspect} can be a floating point number string, or a string of the
+form @var{num}:@var{den}, where @var{num} and @var{den} are the
+numerator and denominator of the aspect ratio. For example "4:3",
+"16:9", "1.3333", and "1.7777" are valid argument values.
+
+If used together with @option{-vcodec copy}, it will affect the aspect ratio
+stored at container level, but not the aspect ratio stored in encoded
+frames, if it exists.
+
+@item -vn (@emph{output})
+Disable video recording.
+
+@item -vcodec @var{codec} (@emph{output})
+Set the video codec. This is an alias for @code{-codec:v}.
+
+@item -pass[:@var{stream_specifier}] @var{n} (@emph{output,per-stream})
+Select the pass number (1 or 2). It is used to do two-pass
+video encoding. The statistics of the video are recorded in the first
+pass into a log file (see also the option -passlogfile),
+and in the second pass that log file is used to generate the video
+at the exact requested bitrate.
+On pass 1, you may just deactivate audio and set output to null,
+examples for Windows and Unix:
+@example
+ffmpeg -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y NUL
+ffmpeg -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y /dev/null
+@end example
+
+@item -passlogfile[:@var{stream_specifier}] @var{prefix} (@emph{output,per-stream})
+Set two-pass log file name prefix to @var{prefix}, the default file name
+prefix is ``ffmpeg2pass''. The complete file name will be
+@file{PREFIX-N.log}, where N is a number specific to the output
+stream
+
+@item -vlang @var{code}
+Set the ISO 639 language code (3 letters) of the current video stream.
+
+@item -vf @var{filtergraph} (@emph{output})
+Create the filtergraph specified by @var{filtergraph} and use it to
+filter the stream.
+
+This is an alias for @code{-filter:v}, see the @ref{filter_option,,-filter option}.
+@end table
+
+@section Advanced Video Options
+
+@table @option
+@item -pix_fmt[:@var{stream_specifier}] @var{format} (@emph{input/output,per-stream})
+Set pixel format. Use @code{-pix_fmts} to show all the supported
+pixel formats.
+If the selected pixel format can not be selected, ffmpeg will print a
+warning and select the best pixel format supported by the encoder.
+If @var{pix_fmt} is prefixed by a @code{+}, ffmpeg will exit with an error
+if the requested pixel format can not be selected, and automatic conversions
+inside filtergraphs are disabled.
+If @var{pix_fmt} is a single @code{+}, ffmpeg selects the same pixel format
+as the input (or graph output) and automatic conversions are disabled.
+
+@item -sws_flags @var{flags} (@emph{input/output})
+Set SwScaler flags.
+@item -vdt @var{n}
+Discard threshold.
+
+@item -rc_override[:@var{stream_specifier}] @var{override} (@emph{output,per-stream})
+Rate control override for specific intervals, formatted as "int,int,int"
+list separated with slashes. Two first values are the beginning and
+end frame numbers, last one is quantizer to use if positive, or quality
+factor if negative.
+
+@item -ilme
+Force interlacing support in encoder (MPEG-2 and MPEG-4 only).
+Use this option if your input file is interlaced and you want
+to keep the interlaced format for minimum losses.
+The alternative is to deinterlace the input stream with
+@option{-deinterlace}, but deinterlacing introduces losses.
+@item -psnr
+Calculate PSNR of compressed frames.
+@item -vstats
+Dump video coding statistics to @file{vstats_HHMMSS.log}.
+@item -vstats_file @var{file}
+Dump video coding statistics to @var{file}.
+@item -top[:@var{stream_specifier}] @var{n} (@emph{output,per-stream})
+top=1/bottom=0/auto=-1 field first
+@item -dc @var{precision}
+Intra_dc_precision.
+@item -vtag @var{fourcc/tag} (@emph{output})
+Force video tag/fourcc. This is an alias for @code{-tag:v}.
+@item -qphist (@emph{global})
+Show QP histogram
+@item -vbsf @var{bitstream_filter}
+Deprecated see -bsf
+
+@item -force_key_frames[:@var{stream_specifier}] @var{time}[,@var{time}...] (@emph{output,per-stream})
+@item -force_key_frames[:@var{stream_specifier}] expr:@var{expr} (@emph{output,per-stream})
+Force key frames at the specified timestamps, more precisely at the first
+frames after each specified time.
+
+If the argument is prefixed with @code{expr:}, the string @var{expr}
+is interpreted like an expression and is evaluated for each frame. A
+key frame is forced in case the evaluation is non-zero.
+
+If one of the times is "@code{chapters}[@var{delta}]", it is expanded into
+the time of the beginning of all chapters in the file, shifted by
+@var{delta}, expressed as a time in seconds.
+This option can be useful to ensure that a seek point is present at a
+chapter mark or any other designated place in the output file.
+
+For example, to insert a key frame at 5 minutes, plus key frames 0.1 second
+before the beginning of every chapter:
+@example
+-force_key_frames 0:05:00,chapters-0.1
+@end example
+
+The expression in @var{expr} can contain the following constants:
+@table @option
+@item n
+the number of current processed frame, starting from 0
+@item n_forced
+the number of forced frames
+@item prev_forced_n
+the number of the previous forced frame, it is @code{NAN} when no
+keyframe was forced yet
+@item prev_forced_t
+the time of the previous forced frame, it is @code{NAN} when no
+keyframe was forced yet
+@item t
+the time of the current processed frame
+@end table
+
+For example to force a key frame every 5 seconds, you can specify:
+@example
+-force_key_frames expr:gte(t,n_forced*5)
+@end example
+
+To force a key frame 5 seconds after the time of the last forced one,
+starting from second 13:
+@example
+-force_key_frames expr:if(isnan(prev_forced_t),gte(t,13),gte(t,prev_forced_t+5))
+@end example
+
+Note that forcing too many keyframes is very harmful for the lookahead
+algorithms of certain encoders: using fixed-GOP options or similar
+would be more efficient.
+
+@item -copyinkf[:@var{stream_specifier}] (@emph{output,per-stream})
+When doing stream copy, copy also non-key frames found at the
+beginning.
+@end table
+
+@section Audio Options
+
+@table @option
+@item -aframes @var{number} (@emph{output})
+Set the number of audio frames to record. This is an alias for @code{-frames:a}.
+@item -ar[:@var{stream_specifier}] @var{freq} (@emph{input/output,per-stream})
+Set the audio sampling frequency. For output streams it is set by
+default to the frequency of the corresponding input stream. For input
+streams this option only makes sense for audio grabbing devices and raw
+demuxers and is mapped to the corresponding demuxer options.
+@item -aq @var{q} (@emph{output})
+Set the audio quality (codec-specific, VBR). This is an alias for -q:a.
+@item -ac[:@var{stream_specifier}] @var{channels} (@emph{input/output,per-stream})
+Set the number of audio channels. For output streams it is set by
+default to the number of input audio channels. For input streams
+this option only makes sense for audio grabbing devices and raw demuxers
+and is mapped to the corresponding demuxer options.
+@item -an (@emph{output})
+Disable audio recording.
+@item -acodec @var{codec} (@emph{input/output})
+Set the audio codec. This is an alias for @code{-codec:a}.
+@item -sample_fmt[:@var{stream_specifier}] @var{sample_fmt} (@emph{output,per-stream})
+Set the audio sample format. Use @code{-sample_fmts} to get a list
+of supported sample formats.
+
+@item -af @var{filtergraph} (@emph{output})
+Create the filtergraph specified by @var{filtergraph} and use it to
+filter the stream.
+
+This is an alias for @code{-filter:a}, see the @ref{filter_option,,-filter option}.
+@end table
+
+@section Advanced Audio options:
+
+@table @option
+@item -atag @var{fourcc/tag} (@emph{output})
+Force audio tag/fourcc. This is an alias for @code{-tag:a}.
+@item -absf @var{bitstream_filter}
+Deprecated, see -bsf
+@item -guess_layout_max @var{channels} (@emph{input,per-stream})
+If some input channel layout is not known, try to guess only if it
+corresponds to at most the specified number of channels. For example, 2
+tells to @command{ffmpeg} to recognize 1 channel as mono and 2 channels as
+stereo but not 6 channels as 5.1. The default is to always try to guess. Use
+0 to disable all guessing.
+@end table
+
+@section Subtitle options:
+
+@table @option
+@item -slang @var{code}
+Set the ISO 639 language code (3 letters) of the current subtitle stream.
+@item -scodec @var{codec} (@emph{input/output})
+Set the subtitle codec. This is an alias for @code{-codec:s}.
+@item -sn (@emph{output})
+Disable subtitle recording.
+@item -sbsf @var{bitstream_filter}
+Deprecated, see -bsf
+@end table
+
+@section Advanced Subtitle options:
+
+@table @option
+
+@item -fix_sub_duration
+Fix subtitles durations. For each subtitle, wait for the next packet in the
+same stream and adjust the duration of the first to avoid overlap. This is
+necessary with some subtitles codecs, especially DVB subtitles, because the
+duration in the original packet is only a rough estimate and the end is
+actually marked by an empty subtitle frame. Failing to use this option when
+necessary can result in exaggerated durations or muxing failures due to
+non-monotonic timestamps.
+
+Note that this option will delay the output of all data until the next
+subtitle packet is decoded: it may increase memory consumption and latency a
+lot.
+
+@item -canvas_size @var{size}
+Set the size of the canvas used to render subtitles.
+
+@end table
+
+@section Advanced options
+
+@table @option
+@item -map [-]@var{input_file_id}[:@var{stream_specifier}][,@var{sync_file_id}[:@var{stream_specifier}]] | @var{[linklabel]} (@emph{output})
+
+Designate one or more input streams as a source for the output file. Each input
+stream is identified by the input file index @var{input_file_id} and
+the input stream index @var{input_stream_id} within the input
+file. Both indices start at 0. If specified,
+@var{sync_file_id}:@var{stream_specifier} sets which input stream
+is used as a presentation sync reference.
+
+The first @code{-map} option on the command line specifies the
+source for output stream 0, the second @code{-map} option specifies
+the source for output stream 1, etc.
+
+A @code{-} character before the stream identifier creates a "negative" mapping.
+It disables matching streams from already created mappings.
+
+An alternative @var{[linklabel]} form will map outputs from complex filter
+graphs (see the @option{-filter_complex} option) to the output file.
+@var{linklabel} must correspond to a defined output link label in the graph.
+
+For example, to map ALL streams from the first input file to output
+@example
+ffmpeg -i INPUT -map 0 output
+@end example
+
+For example, if you have two audio streams in the first input file,
+these streams are identified by "0:0" and "0:1". You can use
+@code{-map} to select which streams to place in an output file. For
+example:
+@example
+ffmpeg -i INPUT -map 0:1 out.wav
+@end example
+will map the input stream in @file{INPUT} identified by "0:1" to
+the (single) output stream in @file{out.wav}.
+
+For example, to select the stream with index 2 from input file
+@file{a.mov} (specified by the identifier "0:2"), and stream with
+index 6 from input @file{b.mov} (specified by the identifier "1:6"),
+and copy them to the output file @file{out.mov}:
+@example
+ffmpeg -i a.mov -i b.mov -c copy -map 0:2 -map 1:6 out.mov
+@end example
+
+To select all video and the third audio stream from an input file:
+@example
+ffmpeg -i INPUT -map 0:v -map 0:a:2 OUTPUT
+@end example
+
+To map all the streams except the second audio, use negative mappings
+@example
+ffmpeg -i INPUT -map 0 -map -0:a:1 OUTPUT
+@end example
+
+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.
+Optional @var{metadata_spec_in/out} parameters specify, which metadata to copy.
+A metadata specifier can have the following forms:
+@table @option
+@item @var{g}
+global metadata, i.e. metadata that applies to the whole file
+
+@item @var{s}[:@var{stream_spec}]
+per-stream metadata. @var{stream_spec} is a stream specifier as described
+in the @ref{Stream specifiers} chapter. In an input metadata specifier, the first
+matching stream is copied from. In an output metadata specifier, all matching
+streams are copied to.
+
+@item @var{c}:@var{chapter_index}
+per-chapter metadata. @var{chapter_index} is the zero-based chapter index.
+
+@item @var{p}:@var{program_index}
+per-program metadata. @var{program_index} is the zero-based program index.
+@end table
+If metadata specifier is omitted, it defaults to global.
+
+By default, global metadata is copied from the first input file,
+per-stream and per-chapter metadata is copied along with streams/chapters. These
+default mappings are disabled by creating any mapping of the relevant type. A negative
+file index can be used to create a dummy mapping that just disables automatic copying.
+
+For example to copy metadata from the first stream of the input file to global metadata
+of the output file:
+@example
+ffmpeg -i in.ogg -map_metadata 0:s:0 out.mp3
+@end example
+
+To do the reverse, i.e. copy global metadata to all audio streams:
+@example
+ffmpeg -i in.mkv -map_metadata:s:a 0:g out.mkv
+@end example
+Note that simple @code{0} would work as well in this example, since global
+metadata is assumed by default.
+
+@item -map_chapters @var{input_file_index} (@emph{output})
+Copy chapters from input file with index @var{input_file_index} to the next
+output file. If no chapter mapping is specified, then chapters are copied from
+the first input file with at least one chapter. Use a negative file index to
+disable any chapter copying.
+
+@item -benchmark (@emph{global})
+Show benchmarking information at the end of an encode.
+Shows CPU time used and maximum memory consumption.
+Maximum memory consumption is not supported on all systems,
+it will usually display as 0 if not supported.
+@item -benchmark_all (@emph{global})
+Show benchmarking information during the encode.
+Shows CPU time used in various steps (audio/video encode/decode).
+@item -timelimit @var{duration} (@emph{global})
+Exit after ffmpeg has been running for @var{duration} seconds.
+@item -dump (@emph{global})
+Dump each input packet to stderr.
+@item -hex (@emph{global})
+When dumping packets, also dump the payload.
+@item -re (@emph{input})
+Read input at native frame rate. Mainly used to simulate a grab device.
+or live input stream (e.g. when reading from a file). Should not be used
+with actual grab devices or live input streams (where it can cause packet
+loss).
+By default @command{ffmpeg} attempts to read the input(s) as fast as possible.
+This option will slow down the reading of the input(s) to the native frame rate
+of the input(s). It is useful for real-time output (e.g. live streaming).
+@item -loop_input
+Loop over the input stream. Currently it works only for image
+streams. This option is used for automatic FFserver testing.
+This option is deprecated, use -loop 1.
+@item -loop_output @var{number_of_times}
+Repeatedly loop output for formats that support looping such as animated GIF
+(0 will loop the output infinitely).
+This option is deprecated, use -loop.
+@item -vsync @var{parameter}
+Video sync method.
+For compatibility reasons old values can be specified as numbers.
+Newly added values will have to be specified as strings always.
+
+@table @option
+@item 0, passthrough
+Each frame is passed with its timestamp from the demuxer to the muxer.
+@item 1, cfr
+Frames will be duplicated and dropped to achieve exactly the requested
+constant frame rate.
+@item 2, vfr
+Frames are passed through with their timestamp or dropped so as to
+prevent 2 frames from having the same timestamp.
+@item drop
+As passthrough but destroys all timestamps, making the muxer generate
+fresh timestamps based on frame-rate.
+@item -1, auto
+Chooses between 1 and 2 depending on muxer capabilities. This is the
+default method.
+@end table
+
+Note that the timestamps may be further modified by the muxer, after this.
+For example, in the case that the format option @option{avoid_negative_ts}
+is enabled.
+
+With -map you can select from which stream the timestamps should be
+taken. You can leave either video or audio unchanged and sync the
+remaining stream(s) to the unchanged one.
+
+@item -async @var{samples_per_second}
+Audio sync method. "Stretches/squeezes" the audio stream to match the timestamps,
+the parameter is the maximum samples per second by which the audio is changed.
+-async 1 is a special case where only the start of the audio stream is corrected
+without any later correction.
+
+Note that the timestamps may be further modified by the muxer, after this.
+For example, in the case that the format option @option{avoid_negative_ts}
+is enabled.
+
+This option has been deprecated. Use the @code{aresample} audio filter instead.
+
+@item -copyts
+Do not process input timestamps, but keep their values without trying
+to sanitize them. In particular, do not remove the initial start time
+offset value.
+
+Note that, depending on the @option{vsync} option or on specific muxer
+processing (e.g. in case the format option @option{avoid_negative_ts}
+is enabled) the output timestamps may mismatch with the input
+timestamps even when this option is selected.
+
+@item -copytb @var{mode}
+Specify how to set the encoder timebase when stream copying. @var{mode} is an
+integer numeric value, and can assume one of the following values:
+
+@table @option
+@item 1
+Use the demuxer timebase.
+
+The time base is copied to the output encoder from the corresponding input
+demuxer. This is sometimes required to avoid non monotonically increasing
+timestamps when copying video streams with variable frame rate.
+
+@item 0
+Use the decoder timebase.
+
+The time base is copied to the output encoder from the corresponding input
+decoder.
+
+@item -1
+Try to make the choice automatically, in order to generate a sane output.
+@end table
+
+Default value is -1.
+
+@item -shortest (@emph{output})
+Finish encoding when the shortest input stream ends.
+@item -dts_delta_threshold
+Timestamp discontinuity delta threshold.
+@item -muxdelay @var{seconds} (@emph{input})
+Set the maximum demux-decode delay.
+@item -muxpreload @var{seconds} (@emph{input})
+Set the initial demux-decode delay.
+@item -streamid @var{output-stream-index}:@var{new-value} (@emph{output})
+Assign a new stream-id value to an output stream. This option should be
+specified prior to the output filename to which it applies.
+For the situation where multiple output files exist, a streamid
+may be reassigned to a different value.
+
+For example, to set the stream 0 PID to 33 and the stream 1 PID to 36 for
+an output mpegts file:
+@example
+ffmpeg -i infile -streamid 0:33 -streamid 1:36 out.ts
+@end example
+
+@item -bsf[:@var{stream_specifier}] @var{bitstream_filters} (@emph{output,per-stream})
+Set bitstream filters for matching streams. @var{bitstream_filters} is
+a comma-separated list of bitstream filters. Use the @code{-bsfs} option
+to get the list of bitstream filters.
+@example
+ffmpeg -i h264.mp4 -c:v copy -bsf:v h264_mp4toannexb -an out.h264
+@end example
+@example
+ffmpeg -i file.mov -an -vn -bsf:s mov2textsub -c:s copy -f rawvideo sub.txt
+@end example
+
+@item -tag[:@var{stream_specifier}] @var{codec_tag} (@emph{per-stream})
+Force a tag/fourcc for matching streams.
+
+@item -timecode @var{hh}:@var{mm}:@var{ss}SEP@var{ff}
+Specify Timecode for writing. @var{SEP} is ':' for non drop timecode and ';'
+(or '.') for drop.
+@example
+ffmpeg -i input.mpg -timecode 01:02:03.04 -r 30000/1001 -s ntsc output.mpg
+@end example
+
+@anchor{filter_complex_option}
+@item -filter_complex @var{filtergraph} (@emph{global})
+Define a complex filtergraph, i.e. one with arbitrary number of inputs and/or
+outputs. For simple graphs -- those with one input and one output of the same
+type -- see the @option{-filter} options. @var{filtergraph} is a description of
+the filtergraph, as described in the ``Filtergraph syntax'' section of the
+ffmpeg-filters manual.
+
+Input link labels must refer to input streams using the
+@code{[file_index:stream_specifier]} syntax (i.e. the same as @option{-map}
+uses). If @var{stream_specifier} matches multiple streams, the first one will be
+used. An unlabeled input will be connected to the first unused input stream of
+the matching type.
+
+Output link labels are referred to with @option{-map}. Unlabeled outputs are
+added to the first output file.
+
+Note that with this option it is possible to use only lavfi sources without
+normal input files.
+
+For example, to overlay an image over video
+@example
+ffmpeg -i video.mkv -i image.png -filter_complex '[0:v][1:v]overlay[out]' -map
+'[out]' out.mkv
+@end example
+Here @code{[0:v]} refers to the first video stream in the first input file,
+which is linked to the first (main) input of the overlay filter. Similarly the
+first video stream in the second input is linked to the second (overlay) input
+of overlay.
+
+Assuming there is only one video stream in each input file, we can omit input
+labels, so the above is equivalent to
+@example
+ffmpeg -i video.mkv -i image.png -filter_complex 'overlay[out]' -map
+'[out]' out.mkv
+@end example
+
+Furthermore we can omit the output label and the single output from the filter
+graph will be added to the output file automatically, so we can simply write
+@example
+ffmpeg -i video.mkv -i image.png -filter_complex 'overlay' out.mkv
+@end example
+
+To generate 5 seconds of pure red video using lavfi @code{color} source:
+@example
+ffmpeg -filter_complex 'color=c=red' -t 5 out.mkv
+@end example
+
+@item -lavfi @var{filtergraph} (@emph{global})
+Define a complex filtergraph, i.e. one with arbitrary number of inputs and/or
+outputs. Equivalent to @option{-filter_complex}.
+
+@item -filter_complex_script @var{filename} (@emph{global})
+This option is similar to @option{-filter_complex}, the only difference is that
+its argument is the name of the file from which a complex filtergraph
+description is to be read.
+
+@item -accurate_seek (@emph{input})
+This option enables or disables accurate seeking in input files with the
+@option{-ss} option. It is enabled by default, so seeking is accurate when
+transcoding. Use @option{-noaccurate_seek} to disable it, which may be useful
+e.g. when copying some streams and transcoding the others.
+
+@item -override_ffserver (@emph{global})
+Overrides the input specifications from ffserver. Using this option you can
+map any input stream to ffserver and control many aspects of the encoding from
+ffmpeg. Without this option ffmpeg will transmit to ffserver what is requested by
+ffserver.
+The option is intended for cases where features are needed that cannot be
+specified to ffserver but can be to ffmpeg.
+
+@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
+@c man begin TIPS
+
+@itemize
+@item
+For streaming at very low bitrates, use a low frame rate
+and a small GOP size. This is especially true for RealVideo where
+the Linux player does not seem to be very fast, so it can miss
+frames. An example is:
+
+@example
+ffmpeg -g 3 -r 3 -t 10 -b:v 50k -s qcif -f rv10 /tmp/b.rm
+@end example
+
+@item
+The parameter 'q' which is displayed while encoding is the current
+quantizer. The value 1 indicates that a very good quality could
+be achieved. The value 31 indicates the worst quality. If q=31 appears
+too often, it means that the encoder cannot compress enough to meet
+your bitrate. You must either increase the bitrate, decrease the
+frame rate or decrease the frame size.
+
+@item
+If your computer is not fast enough, you can speed up the
+compression at the expense of the compression ratio. You can use
+'-me zero' to speed up motion estimation, and '-g 0' to disable
+motion estimation completely (you have only I-frames, which means it
+is about as good as JPEG compression).
+
+@item
+To have very low audio bitrates, reduce the sampling frequency
+(down to 22050 Hz for MPEG audio, 22050 or 11025 for AC-3).
+
+@item
+To have a constant quality (but a variable bitrate), use the option
+'-qscale n' when 'n' is between 1 (excellent quality) and 31 (worst
+quality).
+
+@end itemize
+@c man end TIPS
+
+@chapter Examples
+@c man begin EXAMPLES
+
+@section Preset files
+
+A preset file contains a sequence of @var{option=value} pairs, one for
+each line, specifying a sequence of options which can be specified also on
+the command line. Lines starting with the hash ('#') character are ignored and
+are used to provide comments. Empty lines are also ignored. Check the
+@file{presets} directory in the FFmpeg source tree for examples.
+
+Preset files are specified with the @code{pre} option, this option takes a
+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 ffmpeg can grab video
+and audio directly.
+
+@example
+ffmpeg -f oss -i /dev/dsp -f video4linux2 -i /dev/video0 /tmp/out.mpg
+@end example
+
+Or with an ALSA audio source (mono input, card id 1) instead of OSS:
+@example
+ffmpeg -f alsa -ac 1 -i hw:1 -f video4linux2 -i /dev/video0 /tmp/out.mpg
+@end example
+
+Note that you must activate the right video source and channel before
+launching ffmpeg with any TV viewer such as
+@uref{http://linux.bytesex.org/xawtv/, xawtv} by Gerd Knorr. You also
+have to set the audio recording levels correctly with a
+standard mixer.
+
+@section X11 grabbing
+
+Grab the X11 display with ffmpeg via
+
+@example
+ffmpeg -f x11grab -video_size cif -framerate 25 -i :0.0 /tmp/out.mpg
+@end example
+
+0.0 is display.screen number of your X11 server, same as
+the DISPLAY environment variable.
+
+@example
+ffmpeg -f x11grab -video_size cif -framerate 25 -i :0.0+10,20 /tmp/out.mpg
+@end example
+
+0.0 is display.screen number of your X11 server, same as the DISPLAY environment
+variable. 10 is the x-offset and 20 the y-offset for the grabbing.
+
+@section Video and Audio file format conversion
+
+Any supported file format and protocol can serve as input to ffmpeg:
+
+Examples:
+@itemize
+@item
+You can use YUV files as input:
+
+@example
+ffmpeg -i /tmp/test%d.Y /tmp/out.mpg
+@end example
+
+It will use the files:
+@example
+/tmp/test0.Y, /tmp/test0.U, /tmp/test0.V,
+/tmp/test1.Y, /tmp/test1.U, /tmp/test1.V, etc...
+@end example
+
+The Y files use twice the resolution of the U and V files. They are
+raw files, without header. They can be generated by all decent video
+decoders. You must specify the size of the image with the @option{-s} option
+if ffmpeg cannot guess it.
+
+@item
+You can input from a raw YUV420P file:
+
+@example
+ffmpeg -i /tmp/test.yuv /tmp/out.avi
+@end example
+
+test.yuv is a file containing raw YUV planar data. Each frame is composed
+of the Y plane followed by the U and V planes at half vertical and
+horizontal resolution.
+
+@item
+You can output to a raw YUV420P file:
+
+@example
+ffmpeg -i mydivx.avi hugefile.yuv
+@end example
+
+@item
+You can set several input files and output files:
+
+@example
+ffmpeg -i /tmp/a.wav -s 640x480 -i /tmp/a.yuv /tmp/a.mpg
+@end example
+
+Converts the audio file a.wav and the raw YUV video file a.yuv
+to MPEG file a.mpg.
+
+@item
+You can also do audio and video conversions at the same time:
+
+@example
+ffmpeg -i /tmp/a.wav -ar 22050 /tmp/a.mp2
+@end example
+
+Converts a.wav to MPEG audio at 22050 Hz sample rate.
+
+@item
+You can encode to several formats at the same time and define a
+mapping from input stream to output streams:
+
+@example
+ffmpeg -i /tmp/a.wav -map 0:a -b:a 64k /tmp/a.mp2 -map 0:a -b:a 128k /tmp/b.mp2
+@end example
+
+Converts a.wav to a.mp2 at 64 kbits and to b.mp2 at 128 kbits. '-map
+file:index' specifies which input stream is used for each output
+stream, in the order of the definition of output streams.
+
+@item
+You can transcode decrypted VOBs:
+
+@example
+ffmpeg -i snatch_1.vob -f avi -c:v mpeg4 -b:v 800k -g 300 -bf 2 -c:a libmp3lame -b:a 128k snatch.avi
+@end example
+
+This is a typical DVD ripping example; the input is a VOB file, the
+output an AVI file with MPEG-4 video and MP3 audio. Note that in this
+command we use B-frames so the MPEG-4 stream is DivX5 compatible, and
+GOP size is 300 which means one intra frame every 10 seconds for 29.97fps
+input video. Furthermore, the audio stream is MP3-encoded so you need
+to enable LAME support by passing @code{--enable-libmp3lame} to configure.
+The mapping is particularly useful for DVD transcoding
+to get the desired audio language.
+
+NOTE: To see the supported input formats, use @code{ffmpeg -formats}.
+
+@item
+You can extract images from a video, or create a video from many images:
+
+For extracting images from a video:
+@example
+ffmpeg -i foo.avi -r 1 -s WxH -f image2 foo-%03d.jpeg
+@end example
+
+This will extract one video frame per second from the video and will
+output them in files named @file{foo-001.jpeg}, @file{foo-002.jpeg},
+etc. Images will be rescaled to fit the new WxH values.
+
+If you want to extract just a limited number of frames, you can use the
+above command in combination with the -vframes or -t option, or in
+combination with -ss to start extracting from a certain point in time.
+
+For creating a video from many images:
+@example
+ffmpeg -f image2 -i foo-%03d.jpeg -r 12 -s WxH foo.avi
+@end example
+
+The syntax @code{foo-%03d.jpeg} specifies to use a decimal number
+composed of three digits padded with zeroes to express the sequence
+number. It is the same syntax supported by the C printf function, but
+only formats accepting a normal integer are suitable.
+
+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
+ffmpeg -i test1.avi -i test2.avi -map 0:3 -map 0:2 -map 0:1 -map 0:0 -c copy test12.nut
+@end example
+
+The resulting output file @file{test12.avi} will contain first four streams from
+the input file in reverse order.
+
+@item
+To force CBR video output:
+@example
+ffmpeg -i myfile.avi -b 4000k -minrate 4000k -maxrate 4000k -bufsize 1835k out.m2v
+@end example
+
+@item
+The four options lmin, lmax, mblmin and mblmax use 'lambda' units,
+but you may use the QP2LAMBDA constant to easily convert from 'q' units:
+@example
+ffmpeg -i src.ext -lmax 21*QP2LAMBDA dst.ext
+@end example
+
+@end itemize
+@c man end EXAMPLES
+
+@include config.texi
+@ifset config-all
+@ifset config-avutil
+@include utils.texi
+@end ifset
+@ifset config-avcodec
+@include codecs.texi
+@include bitstream_filters.texi
+@end ifset
+@ifset config-avformat
+@include formats.texi
+@include protocols.texi
+@end ifset
+@ifset config-avdevice
+@include devices.texi
+@end ifset
+@ifset config-swresample
+@include resampler.texi
+@end ifset
+@ifset config-swscale
+@include scaler.texi
+@end ifset
+@ifset config-avfilter
+@include filters.texi
+@end ifset
+@end ifset
+
+@chapter See Also
+
+@ifhtml
+@ifset config-all
+@url{ffmpeg.html,ffmpeg}
+@end ifset
+@ifset config-not-all
+@url{ffmpeg-all.html,ffmpeg-all},
+@end ifset
+@url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-utils.html,ffmpeg-utils},
+@url{ffmpeg-scaler.html,ffmpeg-scaler},
+@url{ffmpeg-resampler.html,ffmpeg-resampler},
+@url{ffmpeg-codecs.html,ffmpeg-codecs},
+@url{ffmpeg-bitstream-filters.html,ffmpeg-bitstream-filters},
+@url{ffmpeg-formats.html,ffmpeg-formats},
+@url{ffmpeg-devices.html,ffmpeg-devices},
+@url{ffmpeg-protocols.html,ffmpeg-protocols},
+@url{ffmpeg-filters.html,ffmpeg-filters}
+@end ifhtml
+
+@ifnothtml
+@ifset config-all
+ffmpeg(1),
+@end ifset
+@ifset config-not-all
+ffmpeg-all(1),
+@end ifset
+ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1),
+ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1),
+ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg
+@settitle ffmpeg video converter
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg.txt b/doc/ffmpeg.txt
new file mode 100644
index 0000000..a028ca2
--- a/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..54b6f19
--- a/dev/null
+++ b/doc/ffplay.texi
@@ -0,0 +1,277 @@
+\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 -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 -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.
+
+@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 -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 -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.
+@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 curret program.
+
+@item v
+Cycle video channel.
+
+@item t
+Cycle subtitle channel in the current program.
+
+@item c
+Cycle program.
+
+@item w
+Show audio waves.
+
+@item left/right
+Seek backward/forward 10 seconds.
+
+@item down/up
+Seek backward/forward 1 minute.
+
+@item page down/page up
+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
+@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..777dbe7
--- a/dev/null
+++ b/doc/ffprobe.texi
@@ -0,0 +1,637 @@
+\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_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
+format_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 contained in the input multimedia
+stream.
+
+The information for each single frame is printed within a dedicated
+section with name "FRAME".
+
+@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 -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 ":".
+
+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
+@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..6a48ff4
--- a/dev/null
+++ b/doc/ffprobe.xsd
@@ -0,0 +1,245 @@
+<?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="packets" type="ffprobe:packetsType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="frames" type="ffprobe:framesType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="streams" type="ffprobe:streamsType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="programs" type="ffprobe:programsType" 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:element name="program_version" type="ffprobe:programVersionType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="library_versions" type="ffprobe:libraryVersionsType" 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:element name="frame" type="ffprobe:frameType" minOccurs="0" maxOccurs="unbounded"/>
+ </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:complexType>
+
+ <xsd:complexType name="frameType">
+ <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="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="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" />
+
+ <!-- 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="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="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_type" type="xsd:string" use="required"/>
+ <xsd:attribute name="compiler_version" 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:schema>
diff --git a/doc/ffserver.conf b/doc/ffserver.conf
new file mode 100644
index 0000000..0f5922c
--- a/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.
+Port 8090
+
+# Address on which the server is bound. Only useful if you have
+# several network interfaces.
+BindAddress 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
+#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
+#Author "Me"
+#Copyright "Super MegaCorp"
+#Title "Test stream from disk"
+#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..14443e6
--- a/dev/null
+++ b/doc/ffserver.texi
@@ -0,0 +1,320 @@
+\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 in
+@file{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.
+
+@section Status stream
+
+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 What can this do?
+
+When properly configured and running, you can capture video and audio in real
+time from a suitable capture card, and stream it out over the Internet to
+either Windows Media Player or RealAudio player (with some restrictions).
+
+It can also stream from files, though that is currently broken. Very often, a
+web server can be used to serve up the files just as well.
+
+It can stream prerecorded video from .ffm files, though it is somewhat tricky
+to make it work correctly.
+
+@section How do I make it work?
+
+First, build the kit. It *really* helps to have installed LAME first. Then when
+you run the ffserver ./configure, make sure that you have the
+@code{--enable-libmp3lame} flag turned on.
+
+LAME is important as it allows for streaming audio to Windows Media Player.
+Don't ask why the other audio types do not 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.
+
+@section What happens next?
+
+You should edit the ffserver.conf file to suit your needs (in terms of
+frame rates etc). Then install ffserver and ffmpeg, write a script to start
+them up, and off you go.
+
+@section Troubleshooting
+
+@subsection I don't hear any audio, but video is fine.
+
+Maybe you didn't install LAME, or got your ./configure statement wrong. Check
+the ffmpeg output to see if a line referring to MP3 is present. If not, then
+your configuration was incorrect. If it is, then maybe your wiring is not
+set up correctly. Maybe the sound card is not getting data from the right
+input source. Maybe you have a really awful audio interface (like I do)
+that only captures in stereo and also requires that one channel be flipped.
+If you are one of these people, then export 'AUDIO_FLIP_LEFT=1' before
+starting ffmpeg.
+
+@subsection The audio and video lose sync after a while.
+
+Yes, they do.
+
+@subsection After a long while, the video update rate goes way down in WMP.
+
+Yes, it does. Who knows why?
+
+@subsection WMP 6.4 behaves differently to WMP 7.
+
+Yes, it does. Any thoughts on this would be gratefully received. These
+differences extend to embedding WMP into a web page. [There are two
+object IDs that you can use: The old one, which does not play well, and
+the new one, which does (both tested on the same system). However,
+I suspect that the new one is not available unless you have installed WMP 7].
+
+@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.
+
+* You may want to adjust the MaxBandwidth in the ffserver.conf to limit
+the amount of bandwidth consumed by live streams.
+
+@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
+
+@section What is FFM, FFM2
+
+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.
+
+@chapter Options
+@c man begin OPTIONS
+
+@include fftools-common-opts.texi
+
+@section Main options
+
+@table @option
+@item -f @var{configfile}
+Use @file{configfile} instead of @file{/etc/ffserver.conf}.
+@item -n
+Enable no-launch mode. This option disables all the Launch directives
+within the various <Stream> sections. Since ffserver will not launch
+any ffmpeg instances, you will have to launch them manually.
+@item -d
+Enable debug mode. This option increases log verbosity, directs log
+messages to stdout.
+@end table
+@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..617af2f
--- a/dev/null
+++ b/doc/fftools-common-opts.texi
@@ -0,0 +1,292 @@
+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 multiplies, 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}
+Matches the stream by a format-specific ID.
+@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.
+
+@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 -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{%}
+@end table
+
+Errors in parsing the environment variable are not fatal, and will not
+appear in the report.
+
+@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_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
--- a/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 e4fb57e..14692a2 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, 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 in output the top half of the video is mirrored
+onto the bottom half.
+
+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 can be represented using 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()} function defined in
@file{libavfilter/avfilter.h}.
@@ -41,7 +138,7 @@ The name of the filter class is optionally followed by a string
"=@var{arguments}".
@var{arguments} is a string which contains the parameters used to
-initialize the filter instance. It may have one of the two allowed forms:
+initialize the filter instance. It may have one of the following forms:
@itemize
@item
@@ -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
@@ -112,21 +215,318 @@ Follows a BNF description for the filtergraph syntax:
@var{FILTERGRAPH} ::= [sws_flags=@var{flags};] @var{FILTERCHAIN} [;@var{FILTERGRAPH}]
@end example
+@section Notes on filtergraph escaping
+
+Some filter arguments require the use of special characters, typically
+@code{:} to separate key=value pairs in a named options list. In this
+case the user should perform a first level escaping when specifying
+the filter arguments. For example, consider the following literal
+string to be embedded in the @ref{drawtext} filter arguments:
+@example
+this is a 'string': may contain one, or more, special characters
+@end example
+
+Since @code{:} is special for the filter arguments syntax, it needs to
+be escaped, so you get:
+@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
+arguments 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
+
+Finally an additional level of escaping may be 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
+
+Sometimes, it might be more convenient to employ quoting in place of
+escaping. For example the string:
+@example
+Caesar: tu quoque, Brute, fili mi
+@end example
+
+Can be quoted in the filter arguments as:
+@example
+text='Caesar: tu quoque, Brute, fili mi'
+@end example
+
+And finally inserted in a filtergraph like:
+@example
+drawtext=text=\'Caesar: tu quoque\, Brute\, fili mi\'
+@end example
+
+See the ``Quoting and escaping'' section in the ffmpeg-utils manual
+for more information about the escaping and quoting rules adopted by
+FFmpeg.
+
+@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
+@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 aconvert
+
+Convert the input audio format to the specified formats.
+
+@emph{This filter is deprecated. Use @ref{aformat} instead.}
+
+The filter accepts a string of the form:
+"@var{sample_format}:@var{channel_layout}".
+
+@var{sample_format} specifies the sample format, and can be a string or the
+corresponding numeric value defined in @file{libavutil/samplefmt.h}. Use 'p'
+suffix for a planar sample format.
+
+@var{channel_layout} specifies the channel layout, and can be a string
+or the corresponding number value defined in @file{libavutil/channel_layout.h}.
+
+The special parameter "auto", signifies that the filter will
+automatically select the output format depending on the output filter.
+
+@subsection Examples
+
+@itemize
+@item
+Convert input to float, planar, stereo:
+@example
+aconvert=fltp:stereo
+@end example
+
+@item
+Convert input to unsigned 8-bit, automatically select out channel layout:
+@example
+aconvert=u8:auto
+@end example
+@end itemize
+
+@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 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 time for starting to apply the fade effect. Default is 0.
+The accepted syntax is:
+@example
+[-]HH[:MM[:SS[.m...]]]
+[-]S+[.m...]
+@end example
+See also the function @code{av_parse_time()}.
+If set this option is used instead of @var{start_sample} one.
+
+@item duration, d
+Specify the duration for which the fade effect has to last. Default is 0.
+The accepted syntax is:
+@example
+[-]HH[:MM[:SS[.m...]]]
+[-]S+[.m...]
+@end example
+See also the function @code{av_parse_time()}.
+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.
+If set this option is used instead of @var{nb_samples} one.
+
+@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.
The filter accepts the following named parameters:
@@ -141,6 +541,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 +552,94 @@ For example to 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.
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,74 +675,119 @@ 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 a audio stream with silence, this can be used together with
+-shortest to extend audio streams to the same length as the video stream.
-This filter accepts the following options:
+@section aphaser
+Add a phasing effect to the input audio.
+
+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.
+
+A description of the accepted parameters follows.
@table @option
+@item in_gain
+Set input gain. Default is 0.4.
-@item expr
-The expression which is evaluated for each frame to construct its timestamp.
+@item out_gain
+Set output gain. Default is 0.74
+
+@item delay
+Set delay in milliseconds. Default is 3.0.
+
+@item decay
+Set decay. Default is 0.4.
+
+@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
-The expression is evaluated through the eval API and can contain the following
-constants:
+@anchor{aresample}
+@section aresample
-@table @option
-@item PTS
-the presentation timestamp in input
+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.
-@item PI
-Greek PI
+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.
-@item PHI
-golden ratio
+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.
-@item E
-Euler number
+@subsection Examples
-@item N
-Number of the audio samples pass through the filter so far, starting at 0.
+@itemize
+@item
+Resample the input audio to 44100Hz:
+@example
+aresample=44100
+@end example
-@item S
-Number of the audio samples in the current frame.
+@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
-@item SR
-Audio sample rate.
+@section asetnsamples
-@item STARTPTS
-the PTS of the first frame
+Set the number of samples per each output audio frame.
-@item PREV_INPTS
-previous input PTS
+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.
-@item PREV_OUTPTS
-previous output PTS
+The filter accepts the following options:
-@item RTCTIME
-wallclock (RTC) time in microseconds
+@table @option
-@item RTCSTART
-wallclock (RTC) time at the start of the movie in microseconds
+@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
-Some examples follow:
-
+For example, to set the number of per-frame samples to 1234 and
+disable padding for the last frame, use:
@example
-# start counting PTS from zero
-asetpts=expr=PTS-STARTPTS
+asetnsamples=n=1234:p=0
+@end example
-#generate timestamps by counting samples
-asetpts=expr=N/SR/TB
+@section asetrate
-# generate timestamps from a "live source" and rebase onto the current timebase
-asetpts='(RTCTIME - RTCSTART) / (TB * 1000000)"
-@end example
+Set the sample rate without altering the PCM data.
+This will result in a change of speed and pitch.
+
+The filter accepts the following options:
+@table @option
+@item sample_rate, r
+Set the output sample rate. Default is 44100 Hz.
+@end table
@section ashowinfo
@@ -282,6 +810,10 @@ depends on the filter input pad, and is usually 1/@var{sample_rate}.
@item pts_time
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
sample format
@@ -302,23 +834,94 @@ 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.
-The filter accepts a single parameter which specifies the number of outputs. If
-unspecified, it defaults to 2.
+The filter 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
-For example
+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.
+
+@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.
+
The filter accepts the following named parameters:
@table @option
@@ -345,17 +948,42 @@ 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.
This filter accepts the following options:
@table @option
@item start
-Timestamp (in seconds) of the start of the kept section. I.e. the audio sample
+Specify time of the start of the kept section, 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.
@@ -368,7 +996,7 @@ Same as @var{end}, except this option sets the end timestamp in samples instead
of seconds.
@item duration
-Maximum duration of the output in seconds.
+Specify maximum duration of the output.
@item start_sample
Number of the first sample that should be passed to output.
@@ -377,6 +1005,10 @@ Number of the first sample that should be passed to output.
Number of the first sample that should be dropped.
@end table
+@option{start}, @option{end}, @option{duration} are expressed as time
+duration specifications, check the "Time duration" section in the
+ffmpeg-utils manual.
+
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
@@ -398,43 +1030,124 @@ 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 channelsplit
-Split each channel in input audio stream into a separate output stream.
+@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:
-This filter accepts the following named parameters:
@table @option
-@item channel_layout
-Channel layout of the input stream. Default is "stereo".
+@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
-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.
+@item width, w
+Specify the band-width of a filter in width_type units.
+@end table
-To 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 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 channelmap
+
Remap input channels to new locations.
This filter accepts the following named parameters:
@@ -457,17 +1170,203 @@ output channels preserving index.
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 in input audio stream into a separate output stream.
+
+This filter accepts the following named parameters:
+@table @option
+@item channel_layout
+Channel layout of the input stream. 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.
+
+To 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
+
+Compress or expand audio dynamic range.
+
+A description of the accepted options follows.
+
+@table @option
+@item attacks
+@item decays
+Set list of times in seconds for each channel over which the instantaneous
+level of the input signal is averaged to determine its volume.
+@option{attacks} refers to increase of volume and @option{decays} refers
+to decrease of volume.
+For most situations, the attack time (response to the audio getting louder)
+should be shorter than the decay time because the human ear is more sensitive
+to sudden loud audio than sudden soft audio.
+Typical value for attack is @code{0.3} seconds and for decay @code{0.8}
+seconds.
+
+@item points
+Set list of points for transfer function, specified in dB relative to maximum
+possible signal amplitude.
+Each key points list need to be defined using the following syntax:
+@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 may be overridden (by @code{0/out-dBn}).
+Typical values for the transfer function are @code{-70/-70 -60/-20}.
+
+@item soft-knee
+Set amount for which the points at where adjacent line segments on the
+transfer function meet will be rounded. Defaults is @code{0.01}.
+
+@item gain
+Set additional gain in dB to be applied at all points on the transfer function
+and allows easy adjustment of the overall gain.
+Default is @code{0}.
+
+@item volume
+Set initial volume in dB to be assumed for each channel when filtering starts.
+This permits the user to supply a nominal level initially, so that,
+for example, a very large gain is not applied to initial signal levels before
+the companding has begun to operate. A typical value for audio which is
+initially quiet is -90 dB. Default is @code{0}.
+
+@item delay
+Set delay in seconds. Default is @code{0}. The input audio
+is analysed immediately, but audio is delayed before being fed to the
+volume adjuster. Specifying a delay approximately equal to the attack/decay
+times allows the filter to effectively operate in predictive rather than
+reactive mode.
+@end table
+
+@subsection Examples
+@itemize
+@item
+Make music with both quiet and loud passages suitable for listening
+in a noisy environment:
+@example
+compand=.3 .3:1 1:-90/-60 -60/-40 -40/-30 -20/-20:6:0:-90:0.2
+@end example
+
+@item
+Noise-gate for when the noise is at a lower level than the signal:
+@example
+compand=.1 .1:.2 .2:-900/-900 -50.1/-900 -50/-50:.01:0:-90:.1
+@end example
+
+@item
+Here is another noise-gate, this time for when the noise is at a higher level
+than the signal (making it, in some ways, similar to squelch):
+@example
+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
+
+@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.
The filter accepts the following named parameters:
@@ -494,27 +1393,342 @@ and if that fails it picks the first unused input channel.
E.g. to 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
To 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 the function
+@code{av_parse_time()} for the accepted format, also check the "Time duration"
+section in the ffmpeg-utils manual.
+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. This filter 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 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
Adjust the input audio volume.
-The filter accepts the following named parameters:
+The filter accepts the following options:
+
@table @option
@item volume
@@ -530,7 +1744,7 @@ The output audio volume is given by the relation:
Default value for @var{volume} is 1.0.
@item precision
-Mathematical precision.
+Set the mathematical precision.
This determines which input sample formats will be allowed, which affects the
precision of the volume scaling.
@@ -556,6 +1770,12 @@ 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
@@ -563,48 +1783,64 @@ volume=volume=6dB:precision=fixed
@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).
-Null audio source, never return audio frames. It is mainly useful as a
-template and to be employed in analysis / debugging tools.
+All volumes are in decibels relative to the maximum PCM value.
-It accepts as optional parameter a string of the form
-@var{sample_rate}:@var{channel_layout}.
+@subsection Examples
-@var{sample_rate} specify the sample rate, and defaults to 44100.
+Here is an excerpt of the output:
+@example
+[Parsed_volumedetect_0 @ 0xa23120] mean_volume: -27 dB
+[Parsed_volumedetect_0 @ 0xa23120] max_volume: -4 dB
+[Parsed_volumedetect_0 @ 0xa23120] histogram_4db: 6
+[Parsed_volumedetect_0 @ 0xa23120] histogram_5db: 62
+[Parsed_volumedetect_0 @ 0xa23120] histogram_6db: 286
+[Parsed_volumedetect_0 @ 0xa23120] histogram_7db: 1042
+[Parsed_volumedetect_0 @ 0xa23120] histogram_8db: 2551
+[Parsed_volumedetect_0 @ 0xa23120] histogram_9db: 4609
+[Parsed_volumedetect_0 @ 0xa23120] histogram_10db: 8409
+@end example
-@var{channel_layout} specify the channel layout, and can be either an
-integer or a string representing a channel layout. The default value
-of @var{channel_layout} is 3, which corresponds to CH_LAYOUT_STEREO.
+It means that:
+@itemize
+@item
+The mean square energy is approximately -27 dB, or 10^-2.7.
+@item
+The largest sample is at -4 dB, or more precisely between -4 dB and -5 dB.
+@item
+There are 6 samples at -4 dB, 62 at -5 dB, 286 at -6 dB, etc.
+@end itemize
-Check the channel_layout_map definition in
-@file{libavutil/channel_layout.c} for the mapping between strings and
-channel layout values.
+In other words, raising the volume by +4 dB does not cause any clipping,
+raising it by +5 dB causes clipping for 6 samples, etc.
-Follow some examples:
-@example
-# set the sample rate to 48000 Hz and the channel layout to CH_LAYOUT_MONO.
-anullsrc=48000:4
+@c man end AUDIO FILTERS
-# same as
-anullsrc=48000:mono
-@end example
+@chapter Audio Sources
+@c man begin AUDIO SOURCES
+
+Below is a description of the currently available audio sources.
@section abuffer
+
Buffer audio frames, and make them available to the filter chain.
-This source is not intended to be part of user-supplied graph descriptions but
-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 named parameters:
+
@table @option
@item time_base
@@ -612,18 +1848,293 @@ 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
-Audio sample rate.
+The sample rate of the incoming audio buffers.
@item sample_fmt
-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
-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.
+
+@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 the function
+@code{av_parse_time()} for the accepted format.
+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
+
+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
+
+Specify 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
+Specify 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
@@ -631,31 +2142,136 @@ 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 to be employed 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}.
-
-This filter accepts no 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.
+
+@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
@@ -671,84 +2287,354 @@ The filter accepts the following options:
@table @option
@item amount
-The percentage of the pixels that have to be below the threshold, defaults to
-98.
+Set the percentage of the pixels that have to be below the threshold, defaults
+to @code{98}.
+
+@item threshold, thresh
+Set the threshold below which a pixel value is considered black, defaults to
+@code{32}.
-@item threshold
-Threshold below which a pixel value is considered black, defaults to 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 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
+@end itemize
+
@section boxblur
Apply boxblur algorithm to the input video.
-This filter accepts the following options:
+The filter accepts the following options:
@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
-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
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 follow:
+A value of 0 will disable the effect.
+@end table
-@itemize
+@subsection Examples
+@itemize
@item
Apply a boxblur filter with luma, chroma, and alpha radius
set to 2:
@example
boxblur=luma_radius=2:luma_power=1
+boxblur=2:1
@end example
@item
-Set luma radius to 2, alpha and chroma radius to 0
+Set luma radius to 2, alpha and chroma radius to 0:
@example
-boxblur=2:1:0:0:0:0
+boxblur=2:1:cr=0:ar=0
@end example
@item
-Set luma and chroma radius to a fraction of the video dimension
+Set luma and chroma radius 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 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. Mainly useful for
@@ -758,62 +2644,85 @@ testing purposes.
Crop the input video to given dimensions.
-This filter accepts the following options:
+The filter accepts the following options:
@table @option
+@item w, out_w
+Width of the output video. It defaults to @code{iw}.
+This expression is evaluated only once during the filter
+configuration.
-@item out_w
-Width of the output video.
-
-@item out_h
-Height of the output video.
+@item h, out_h
+Height of the output video. It defaults to @code{ih}.
+This expression is evaluated only once during the filter
+configuration.
@item x
Horizontal position, in the input video, of the left edge of the output video.
+It defaults to @code{(in_w-out_w)/2}.
+This expression is evaluated per-frame.
@item y
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
-the corresponding mathematical approximated values for e
-(euler number), pi (greek PI), PHI (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
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
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 input frame, starting from 0
+@item pos
+the position in the file of the input frame, NAN if unknown
+
@item t
timestamp expressed in seconds, 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
-evaluated just at 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
@@ -824,48 +2733,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}.
-Follow 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
+
+@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
-# crop the input video central square
+@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
@@ -875,30 +2823,238 @@ Calculate necessary cropping parameters and prints the recommended
parameters through the logging system. The detected dimensions
correspond to the non-black area of the input video.
-This filter accepts the following options:
+The filter accepts the following options:
@table @option
@item limit
-Threshold, which can be optionally specified from nothing (0) to
-everything (255), 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. Default value is 24.
@item round
-Value which the width/height should be divisible by, defaults to
-16. The offset is automatically adjusted to center the video. Use 2 to
-get only even dimensions (needed for 4:2:2 video). 16 is best when
-encoding to most video codecs.
+Set the value for which the width/height should be divisible by. The
+offset is automatically adjusted to center the video. Use 2 to get
+only even dimensions (needed for 4:2:2 video). 16 is best when
+encoding to most video codecs. Default value is 16.
-@item reset
-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. 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 return 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 and can be extremely slow.
+
+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. Each block is of size
+@code{16x16}. 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 @code{15}.
+
+@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.
+@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
+
+@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 delogo
Suppress a TV station logo by a simple interpolation of the surrounding
@@ -908,11 +3064,13 @@ pixels. Just set a rectangle covering the logo and watch it disappear
This filter accepts the following options:
@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.
@@ -922,15 +3080,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
-Some examples follow.
+@subsection Examples
@itemize
-
@item
Set a rectangle covering the area with top left corner coordinates 0,0
and size 100x77, setting a band of size 10:
@@ -940,6 +3102,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.
@@ -947,125 +3189,223 @@ Draw a colored box on the input image.
This filter accepts the following options:
@table @option
+@item x
+@item y
+The expressions which specify the top left corner coordinates of the box. Default to 0.
-@item x, y
-Specify the top left corner coordinates of the box. Default 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. Default 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
+
+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
-Follow some examples:
+@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 text string or text from specified file on top of 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}.
+@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
-The description of the accepted parameters follows.
+Draw a grid on the input image.
+
+This filter accepts the following options:
@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 fontfile
-The font file to be used for drawing text. Path must be included.
-This parameter is mandatory.
+@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.
-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
-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
-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
-rendered text width and height
+@item sar
+The input sample aspect ratio.
-@item w, h
-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
-timestamp expressed in seconds, 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.
-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.
-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 text string or text from specified file on top of video using the
+libfreetype library.
+
+To enable compilation of this filter you need to configure FFmpeg with
+@code{--enable-libfreetype}.
+
+@subsection Syntax
+
+The description of the accepted parameters follows.
+
+@table @option
@item box
Used to draw a box around text using background color.
Value should 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. 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 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 fontfile
+The font file to be used for drawing text. Path must be included.
+This parameter is mandatory.
+
+@item fontsize
+The font size to be used for drawing text.
+The default value of @var{fontsize} is 16.
@item ft_load_flags
Flags to be used for loading the fonts.
@@ -1088,7 +3428,6 @@ a combination of the following values:
@item monochrome
@item linear_design
@item no_autohint
-@item end table
@end table
Default value is "render".
@@ -1096,39 +3435,343 @@ Default value is "render".
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. 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
+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:
+If libavfilter was built with @code{--enable-fontconfig}, then
+@option{fontfile} can be a fontconfig pattern or omitted.
+
+@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 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, in seconds, with microsecond accuracy.
+
+@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
+
+@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}.
+
+@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 choosen 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}.
+@end table
+
+Example:
+@example
+edgedetect=low=0.1:high=0.4
+@end example
+
+@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 fade
Apply fade-in/out effect to input video.
@@ -1136,34 +3779,419 @@ Apply fade-in/out effect to input video.
This filter accepts the following options:
@table @option
-
-@item type
+@item type, t
The effect type -- can be either "in" for fade-in, or "out" for a fade-out
effect.
+Default is @code{in}.
-@item start_frame
-The number of the start frame for starting to apply the fade effect.
+@item start_frame, s
+Specify the number of the start frame for starting to apply the fade
+effect. Default is 0.
-@item nb_frames
+@item nb_frames, n
The number of frames 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 completely black.
+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 completely black.
+If both duration and nb_frames are specified, duration is used. Default is 0.
@end table
-A few usage examples follow, usable too as test scenarios.
+@subsection Examples
+
+@itemize
+@item
+Fade in first 30 frames of video:
@example
-# fade in first 30 frames of video
-fade=type=in:nb_frames=30
+fade=in:0:30
+@end example
+
+The command above is equivalent to:
+@example
+fade=t=in:s=0:n=30
+@end example
-# fade out last 45 frames of a 200-frame video
+@item
+Fade out last 45 frames of a 200-frame video:
+@example
+fade=out:155:45
fade=type=out:start_frame=155:nb_frames=45
+@end example
+
+@item
+Fade in first 25 frames and fade out last 25 frames of a 1000-frame video:
+@example
+fade=in:0:25, fade=out:975:25
+@end example
+
+@item
+Make first 5 frames black, then fade in from frame 5-24:
+@example
+fade=in:5:20
+@end example
+
+@item
+Fade in alpha over first 25 frames of video:
+@example
+fade=in:0:25:alpha=1
+@end example
+
+@item
+Make 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 filter accepts the following options:
+
+@table @option
+@item order
+Specify the assumed field order of the input stream. Available values are:
+
+@table @samp
+@item auto
+Auto detect parity (use FFmpeg's internal parity value).
+@item bff
+Assume bottom field first.
+@item tff
+Assume top field first.
+@end table
+
+Note that it is sometimes recommended not to trust the parity announced by the
+stream.
+
+Default value is @var{auto}.
+
+@item mode
+Set the matching mode or strategy to use. @option{pc} mode is the safest in the
+sense that it won't risk creating jerkiness due to duplicate frames when
+possible, but if there are bad edits or blended fields it will end up
+outputting combed frames when a good match might actually exist. On the other
+hand, @option{pcn_ub} mode is the most risky in terms of creating jerkiness,
+but will almost always find a good frame if there is one. The other values are
+all somewhere in between @option{pc} and @option{pcn_ub} in terms of risking
+jerkiness and creating duplicate frames versus finding good matches in sections
+with bad edits, orphaned fields, blended fields, etc.
+
+More details about p/c/n/u/b are available in @ref{p/c/n/u/b meaning} section.
+
+Available values are:
+
+@table @samp
+@item pc
+2-way matching (p/c)
+@item pc_n
+2-way matching, and trying 3rd match if still combed (p/c + n)
+@item pc_u
+2-way matching, and trying 3rd match (same order) if still combed (p/c + u)
+@item pc_n_ub
+2-way matching, trying 3rd match if still combed, and trying 4th/5th matches if
+still combed (p/c + n + u/b)
+@item pcn
+3-way matching (p/c/n)
+@item pcn_ub
+3-way matching, and trying 4th/5th matches if all 3 of the original matches are
+detected as combed (p/c/n + u/b)
+@end table
+
+The parenthesis at the end indicate the matches that would be used for that
+mode assuming @option{order}=@var{tff} (and @option{field} on @var{auto} or
+@var{top}).
+
+In terms of speed @option{pc} mode is by far the fastest and @option{pcn_ub} is
+the slowest.
+
+Default value is @var{pc_n}.
+
+@item ppsrc
+Mark the main input stream as a pre-processed input, and enable the secondary
+input stream as the clean source to pick the fields from. See the filter
+introduction for more details. It is similar to the @option{clip2} feature from
+VFM/TFM.
+
+Default value is @code{0} (disabled).
+
+@item field
+Set the field to match from. It is recommended to set this to the same value as
+@option{order} unless you experience matching failures with that setting. In
+certain circumstances changing the field that is used to match from can have a
+large impact on matching performance. Available values are:
+
+@table @samp
+@item auto
+Automatic (same value as @option{order}).
+@item bottom
+Match from the bottom field.
+@item top
+Match from the top field.
+@end table
-# fade in first 25 frames and fade out last 25 frames of a 1000-frame video
-fade=type=in:start_frame=0:nb_frames=25, fade=type=out:start_frame=975:nb_frames=25
+Default value is @var{auto}.
+
+@item mchroma
+Set whether or not chroma is included during the match comparisons. In most
+cases it is recommended to leave this enabled. You should set this to @code{0}
+only if your clip has bad chroma problems such as heavy rainbowing or other
+artifacts. Setting this to @code{0} could also be used to speed things up at
+the cost of some accuracy.
+
+Default value is @code{1}.
+
+@item y0
+@item y1
+These define an exclusion band which excludes the lines between @option{y0} and
+@option{y1} from being included in the field matching decision. An exclusion
+band can be used to ignore subtitles, a logo, or other things that may
+interfere with the matching. @option{y0} sets the starting scan line and
+@option{y1} sets the ending line; all lines in between @option{y0} and
+@option{y1} (including @option{y0} and @option{y1}) will be ignored. Setting
+@option{y0} and @option{y1} to the same value will disable the feature.
+@option{y0} and @option{y1} defaults to @code{0}.
+
+@item scthresh
+Set the scene change detection threshold as a percentage of maximum change on
+the luma plane. Good values are in the @code{[8.0, 14.0]} range. Scene change
+detection is only relevant in case @option{combmatch}=@var{sc}. The range for
+@option{scthresh} is @code{[0.0, 100.0]}.
+
+Default value is @code{12.0}.
+
+@item combmatch
+When @option{combatch} is not @var{none}, @code{fieldmatch} will take into
+account the combed scores of matches when deciding what match to use as the
+final match. Available values are:
-# make first 5 frames black, then fade in from frame 5-24
-fade=type=in:start_frame=5:nb_frames=20
+@table @samp
+@item none
+No final matching based on combed scores.
+@item sc
+Combed scores are only used when a scene change is detected.
+@item full
+Use combed scores all the time.
+@end table
+
+Default is @var{sc}.
+
+@item combdbg
+Force @code{fieldmatch} to calculate the combed metrics for certain matches and
+print them. This setting is known as @option{micout} in TFM/VFM vocabulary.
+Available values are:
+
+@table @samp
+@item none
+No forced calculation.
+@item pcn
+Force p/c/n calculations.
+@item pcnub
+Force p/c/n/u/b calculations.
+@end table
+
+Default value is @var{none}.
+
+@item cthresh
+This is the area combing threshold used for combed frame detection. This
+essentially controls how "strong" or "visible" combing must be to be detected.
+Larger values mean combing must be more visible and smaller values mean combing
+can be less visible or strong and still be detected. Valid settings are from
+@code{-1} (every pixel will be detected as combed) to @code{255} (no pixel will
+be detected as combed). This is basically a pixel difference value. A good
+range is @code{[8, 12]}.
+
+Default value is @code{9}.
+
+@item chroma
+Sets whether or not chroma is considered in the combed frame decision. Only
+disable this if your source has chroma problems (rainbowing, etc.) that are
+causing problems for the combed frame detection with chroma enabled. Actually,
+using @option{chroma}=@var{0} is usually more reliable, except for the case
+where there is chroma only combing in the source.
+
+Default value is @code{0}.
+
+@item blockx
+@item blocky
+Respectively set the x-axis and y-axis size of the window used during combed
+frame detection. This has to do with the size of the area in which
+@option{combpel} pixels are required to be detected as combed for a frame to be
+declared combed. See the @option{combpel} parameter description for more info.
+Possible values are any number that is a power of 2 starting at 4 and going up
+to 512.
+
+Default value is @code{16}.
+
+@item combpel
+The number of combed pixels inside any of the @option{blocky} by
+@option{blockx} size blocks on the frame for the frame to be detected as
+combed. While @option{cthresh} controls how "visible" the combing must be, this
+setting controls "how much" combing there must be in any localized area (a
+window defined by the @option{blockx} and @option{blocky} settings) on the
+frame. Minimum value is @code{0} and maximum is @code{blocky x blockx} (at
+which point no frames will ever be detected as combed). This setting is known
+as @option{MI} in TFM/VFM vocabulary.
+
+Default value is @code{80}.
+@end table
+
+@anchor{p/c/n/u/b meaning}
+@subsection p/c/n/u/b meaning
+
+@subsubsection p/c/n
+
+We assume the following telecined stream:
+
+@example
+Top fields: 1 2 2 3 4
+Bottom fields: 1 2 3 4 4
+@end example
+
+The numbers correspond to the progressive frame the fields relate to. Here, the
+first two frames are progressive, the 3rd and 4th are combed, and so on.
+
+When @code{fieldmatch} is configured to run a matching from bottom
+(@option{field}=@var{bottom}) this is how this input stream get transformed:
+
+@example
+Input stream:
+ T 1 2 2 3 4
+ B 1 2 3 4 4 <-- matching reference
+
+Matches: c c n n c
+
+Output stream:
+ T 1 2 3 4 4
+ B 1 2 3 4 4
+@end example
+
+As a result of the field matching, we can see that some frames get duplicated.
+To perform a complete inverse telecine, you need to rely on a decimation filter
+after this operation. See for instance the @ref{decimate} filter.
+
+The same operation now matching from top fields (@option{field}=@var{top})
+looks like this:
+
+@example
+Input stream:
+ T 1 2 2 3 4 <-- matching reference
+ B 1 2 3 4 4
+
+Matches: c c p p c
+
+Output stream:
+ T 1 2 2 3 4
+ B 1 2 2 3 4
+@end example
+
+In these examples, we can see what @var{p}, @var{c} and @var{n} mean;
+basically, they refer to the frame and field of the opposite parity:
+
+@itemize
+@item @var{p} matches the field of the opposite parity in the previous frame
+@item @var{c} matches the field of the opposite parity in the current frame
+@item @var{n} matches the field of the opposite parity in the next frame
+@end itemize
+
+@subsubsection u/b
+
+The @var{u} and @var{b} matching are a bit special in the sense that they match
+from the opposite parity flag. In the following examples, we assume that we are
+currently matching the 2nd frame (Top:2, bottom:2). According to the match, a
+'x' is placed above and below each matched fields.
+
+With bottom matching (@option{field}=@var{bottom}):
+@example
+Match: c p n b u
+
+ x x x x x
+ Top 1 2 2 1 2 2 1 2 2 1 2 2 1 2 2
+ Bottom 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
+ x x x x x
+
+Output frames:
+ 2 1 2 2 2
+ 2 2 2 1 3
+@end example
+
+With top matching (@option{field}=@var{top}):
+@example
+Match: c p n b u
+
+ x x x x x
+ Top 1 2 2 1 2 2 1 2 2 1 2 2 1 2 2
+ Bottom 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
+ x x x x x
+
+Output frames:
+ 2 2 2 1 2
+ 2 1 3 2 2
+@end example
+
+@subsection Examples
+
+Simple IVTC of a top field first telecined stream:
+@example
+fieldmatch=order=tff:combmatch=none, decimate
+@end example
+
+Advanced IVTC, with fallback on @ref{yadif} for still combed frames:
+@example
+fieldmatch=order=tff:combmatch=full, yadif=deint=interlaced, decimate
@end example
@section fieldorder
@@ -1179,7 +4207,7 @@ Output field order. Valid values are @var{tff} for top field first or @var{bff}
for bottom field first.
@end table
-Default value is "tff".
+Default value is @samp{tff}.
Transformation is achieved by shifting the picture content up or down
by one line, and filling the remaining line with appropriate picture content.
@@ -1194,7 +4222,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
@@ -1206,6 +4234,7 @@ framework.
The filter does not take parameters.
+@anchor{format}
@section format
Convert the input video to one of the specified pixel formats.
@@ -1221,25 +4250,49 @@ A '|'-separated list of pixel format names, for example
@end table
-Some examples follow:
+@subsection Examples
+
+@itemize
+@item
+Convert the input video to the format @var{yuv420p}
@example
-# convert the input video to the format "yuv420p"
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
@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.
This filter accepts the following named parameters:
@table @option
@item fps
-Desired output framerate.
+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
@@ -1251,13 +4304,45 @@ 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 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 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 filter accepts the following options:
@@ -1278,36 +4363,168 @@ A '|'-separated list of parameters to pass to the frei0r effect.
A frei0r effect parameter can be a boolean (whose values are specified
with "y" and "n"), a double, a color (specified by the syntax
-@var{R}/@var{G}/@var{B}, @var{R}, @var{G}, and @var{B} being float
-numbers from 0.0 to 1.0) or by an @code{av_parse_color()} color
-description), a position (specified by the syntax @var{X}/@var{Y},
+@var{R}/@var{G}/@var{B}, (@var{R}, @var{G}, and @var{B} being float
+numbers from 0.0 to 1.0) or by a color description specified in the "Color"
+section in the ffmpeg-utils manual), a position (specified by the syntax @var{X}/@var{Y},
@var{X} and @var{Y} being float numbers) and a string.
The number and kind of parameters depend on the loaded effect. If an
effect parameter is not specified the default value is set.
-Some examples follow:
+@subsection Examples
+
+@itemize
+@item
+Apply the distort0r effect, set the first two double parameters:
@example
-# apply the distort0r effect, set the first two double parameters
frei0r=filter_name=distort0r:filter_params=0.5|0.01
+@end example
-# apply the colordistance effect, takes a color as first parameter
+@item
+Apply the colordistance effect, take a color as first parameter:
+@example
frei0r=colordistance:0.2/0.3/0.4
frei0r=colordistance:violet
frei0r=colordistance:0x112233
+@end example
-# apply the perspective effect, specify the top left and top right
-# image positions
+@item
+Apply the perspective effect, specify 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
+@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.
@@ -1333,23 +4550,268 @@ 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
-# default parameters
-gradfun=strength=1.2:radius=16
+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
-# omitting radius
-gradfun=1.2
+A Hald CLUT is supposed to be a squared image of @code{Level*Level*Level} by
+@code{Level*Level*Level} pixels. For a given Hald CLUT, FFmpeg will select the
+biggest possible square starting at the top left of the picture. The remaining
+padding pixels (bottom or right) will be ignored. This area can be used to add
+a preview of the Hald CLUT.
+
+Typically, the following generated Hald CLUT will be supported by the
+@code{haldclut} filter:
+
+@example
+ffmpeg -f lavfi -i @ref{haldclutsrc}=8 -vf "
+ pad=iw+320 [padded_clut];
+ smptebars=s=320x256, split [a][b];
+ [padded_clut][a] overlay=W-320:h, curves=color_negative [main];
+ [main][b] overlay=W-320" -frames:v 1 clut.png
+@end example
+
+It contains the original and a preview of the effect of the CLUT: SMPTE color
+bars are displayed on the right-top, and below the same color bars processed by
+the color changes.
+
+Then, the effect of this Hald CLUT can be visualized with:
+@example
+ffplay input.mkv -vf "movie=clut.png, [in] haldclut"
@end example
@section hflip
Flip the input video horizontally.
-For example to horizontally flip the input video with @command{avconv}:
+For example to horizontally flip the input video with @command{ffmpeg}:
+@example
+ffmpeg -i in.avi -vf "hflip" out.avi
+@end example
+
+@section histeq
+This filter applies a global color histogram equalization on a
+per-frame basis.
+
+It can be used to correct video that has a compressed range of pixel
+intensities. The filter redistributes the pixel intensities to
+equalize their distribution across the intensity range. It may be
+viewed as an "automatically adjusting contrast filter". This filter is
+useful only for correcting degraded or poorly captured source
+video.
+
+The filter accepts the following options:
+
+@table @option
+@item strength
+Determine the amount of equalization to be applied. As the strength
+is reduced, the distribution of pixel intensities more-and-more
+approaches that of the input frame. The value must be a float number
+in the range [0,1] and defaults to 0.200.
+
+@item intensity
+Set the maximum intensity that can generated and scale the output
+values appropriately. The strength should be set as desired and then
+the intensity can be limited if needed to avoid washing-out. The value
+must be a float number in the range [0,1] and defaults to 0.210.
+
+@item antibanding
+Set the antibanding level. If enabled the filter will randomly vary
+the luminance of output pixels by a small amount to avoid banding of
+the histogram. Possible values are @code{none}, @code{weak} or
+@code{strong}. It defaults to @code{none}.
+@end table
+
+@section histogram
+
+Compute and draw a color distribution histogram for the input video.
+
+The computed histogram is a representation of distribution of color components
+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 display 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 current frame. Bellow each graph is color component scale meter.
+
+@item color
+chroma values in vectorscope, if brighter more such chroma values are
+distributed in an image.
+Displays chroma values (U/V color placement) in two dimensional graph
+(which is called a vectorscope). It can be used to read of the hue and
+saturation of the current frame. At a same time it is a histogram.
+The whiter a pixel in the vectorscope, the more pixels of the input frame
+correspond to that pixel (that is the 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. So the graph can be used to read of 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 you increase the amount of a specific color, while leaving
+the other colors unchanged, the saturation increases, and you move 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 graph in the left side represents
+color component value 0 and right side represents value = 255. In column mode 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 much
+of same luminance values across input rows/columns are distributed.
+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 other in @code{column} waveform mode
+for @code{waveform} histogram mode. For @code{levels} histogram mode
+per color component graphs are placed one bellow other.
+
+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 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 make by making adjustments to level the
+three waveforms.
+
+@item overlay
+Presents information that's 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 can make it easier to spot
+the 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
High precision/quality 3d denoise filter. This filter aims to reduce
@@ -1376,6 +4838,167 @@ a float number which specifies chroma temporal strength, defaults to
@var{luma_tmp}*@var{chroma_spatial}/@var{luma_spatial}
@end table
+@section hue
+
+Modify the hue and/or the saturation of the input.
+
+This filter accepts the following options:
+
+@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 is interlaced or progressive,
+top or bottom field first.
+
+The filter accepts the following options:
+
+@table @option
+@item intl_thres
+Set interlacing threshold.
+@item prog_thres
+Set progressive threshold.
+@end table
+
+@section il
+
+Deinterleave or interleave fields.
+
+This filter allows 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
@@ -1406,6 +5029,95 @@ 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
+
+@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
@@ -1416,19 +5128,30 @@ to an RGB input video.
These filters accept the following options:
@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
@@ -1443,11 +5166,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
-the corresponding mathematical approximated values for e
-(euler number), pi (greek PI), PHI (golden ratio)
-
-@item w, h
+@item w
+@item h
the input width and height
@item val
@@ -1481,35 +5201,253 @@ expression
All expressions default to "val".
-Some examples follow:
+@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, turns the video into a graytone image
+@item
+Remove chroma components, turns 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 0.5 factor
+@item
+Correct luminance gamma by a 0.5 factor:
+@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.
@@ -1531,15 +5469,71 @@ A '|'-separated list of pixel format names, for example
@end table
-Some examples follow:
+@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
@@ -1550,7 +5544,7 @@ Pass the video source unchanged to the output.
Apply video transform using libopencv.
To enable this filter install libopencv library and headers and
-configure Libav with --enable-libopencv.
+configure FFmpeg with @code{--enable-libopencv}.
This filter accepts the following parameters:
@@ -1658,83 +5652,252 @@ video on which the second input is overlayed.
This filter 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.
+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 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 yuv444
+force YUV444 output
+@item rgb
+force RGB output
@end table
-The parameters are expressions containing the following parameters:
+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, main_h
+@item main_w, W
+@item main_h, H
main input width and height
-@item W, H
-same as @var{main_w} and @var{main_h}
-
-@item overlay_w, overlay_h
+@item overlay_w, w
+@item overlay_h, h
overlay input width and height
-@item w, h
-same as @var{overlay_w} and @var{overlay_h}
+@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
+timestamp expressed in seconds, 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 it does the example for
the @var{movie} filter.
-Follow 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
+
+@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
+
+@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
-# 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
+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
-# 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
+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
-# 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]
+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
-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
-Add paddings to the input image, and places the original input at the
+Add paddings to the input image, and place the original input at the
given coordinates @var{x}, @var{y}.
This filter 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
-
-Specify the offsets where to place the input image in the padded area
-with respect to the top/left border of the output image.
+@item x
+@item y
+Specify an expression for the offsets where to place the input image
+in the padded area with respect to the top/left border of the output
+image.
The @var{x} expression can reference the value set by the @var{y}
expression, and vice versa.
@@ -1742,71 +5905,210 @@ 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 a 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
-the corresponding mathematical approximated values for e
-(euler number), pi (greek PI), phi (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
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, that is the size of the padded area as
specified by the @var{width} and @var{height} expressions
-@item ow, oh
+@item ow
+@item oh
same as @var{out_w} and @var{out_h}
-@item x, y
+@item x
+@item y
x and y offsets as specified by the @var{x} and @var{y}
expressions, or NAN if not yet specified
@item a
-input display aspect ratio, same as @var{iw} / @var{ih}
+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, vsub
+@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.
@end table
-Some examples follow:
+@subsection Examples
+@itemize
+@item
+Add paddings with color "violet" to the input video. Output video
+size is 640x480, 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 color "violet" to the input video. Output video
-# size is 640x480, 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 bt 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
-# double output size and put the input video in the bottom-right
-# corner of the output padded area
+@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
+
+@item
+Double 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.
+
+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}.
+@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
@@ -1820,390 +6122,894 @@ format=monow, pixdesctest
can be used to test the monowhite pixel format descriptor definition.
-@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.
-This filter accepts the following options:
+The filters accept the following options:
@table @option
+@item subfilters
+Set postprocessing subfilters string.
+@end table
-@item w
-Output video width.
+All subfilters share common options to determine their scope:
-@item h
-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
-the corresponding mathematical approximated values for e
-(euler number), pi (greek PI), phi (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
-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
-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 dar, a
-input display aspect ratio, 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 hsub, vsub
-horizontal and vertical chroma subsample values. For example for the
-pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
+@item dr/dering
+Deringing filter
+
+@item tn/tmpnoise[|threshold1[|threshold2[|threshold3]]], temporal noise reducer
+@table @option
+@item threshold1
+larger -> stronger filtering
+@item threshold2
+larger -> stronger filtering
+@item threshold3
+larger -> stronger filtering
@end table
-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 follow:
-@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 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 for 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, but make 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, keep the same input aspect ratio
-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
-This filter accepts the following options:
+@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 PI
-Greek PI
+@item stats_file, f
+If specified the filter will use the named file to save the PSNR of
+each individual frame.
+@end table
-@item PHI
-golden ratio
+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.
-@item E
-Euler number
+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, 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
-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, 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 (Presentation TimeStamp) of the filtered video frame,
-expressed in seconds, 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, NAN if undefined
+@section pullup
-@item prev_selected_pts
-the PTS of the last previously filtered video frame, 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, 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, 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, NAN if undefined
+The filter accepts the following options:
-@item pict_type
-the type of the filtered frame, 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, can assume one of the following values:
-@table @option
-@item PROGRESSIVE
-the frame is progressive (not interlaced)
-@item TOPFIRST
-the frame is top-field-first
-@item BOTTOMFIRST
-the frame is bottom-field-first
+This option may be set to use chroma plane instead of the default luma plane
+for doing filter's computations. This may improve accuracy on very clean
+source material, but more likely will decrease accuracy, especially if there
+is chroma noise (rainbow effect) or any grayscale video.
+The main purpose of setting @option{mp} to a chroma plane is to reduce CPU
+load and make pullup usable in realtime on slow machines.
@end table
-@item key
-1 if the filtered frame is a key-frame, 0 otherwise
+For example to inverse telecined NTSC input:
+@example
+pullup,fps=24000/1001
+@end example
-@end table
+@section removelogo
-The default value of the select expression is "1".
+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.
-Some examples follow:
+The filter accepts the following options:
-@example
-# select all frames in input
-select
+@table @option
+@item filename, f
+Set the filter bitmap file, which can be any image format supported by
+libavformat. The width and height of the image file must match those of the
+video stream being processed.
+@end table
-# the above is the same as:
-select=expr=1
+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.
-# skip all frames:
-select=expr=0
+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.
-# select only I-frames
-select='expr=eq(pict_type\,I)'
+@section rotate
-# select one frame every 100
-select='not(mod(n\,100))'
+Rotate video by an arbitrary angle expressed in radians.
-# select only frames contained in the 10-20 time interval
-select='gte(t\,10)*lte(t\,20)'
+The filter accepts the following options:
-# select only I frames contained in the 10-20 time interval
-select='gte(t\,10)*lte(t\,20)*eq(pict_type\,I)'
+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".
-# select frames with a minimum distance of 10 seconds
-select='isnan(prev_selected_t)+gte(t-prev_selected_t\,10)'
-@end example
+This expression is evaluated for each frame.
-@anchor{setdar}
-@section setdar
+@item out_w, ow
+Set the output width expression, default value is "iw".
+This expression is evaluated just once during configuration.
-Set the Display Aspect Ratio for the filter output video.
+@item out_h, oh
+Set the output height expression, default value is "ih".
+This expression is evaluated just once during configuration.
-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 bilinear
+Enable bilinear interpolation if set to 1, a value of 0 disables
+it. Default value is 1.
-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 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).
-This filter accepts the following options:
+Default value is "black".
+@end table
+
+The expressions for the angle and the output size can contain the
+following constants and functions:
@table @option
+@item n
+sequential number of the input frame, starting from 0. It is always NAN
+before the first frame is filtered.
-@item dar
-Output display aspect ratio, as a rational or a decimal number.
+@item t
+time in seconds of the input frame, it is set to 0 when the filter is
+configured. It is always NAN before the first frame is filtered.
+
+@item 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_w, iw
+@item in_h, ih
+the input video width and heigth
+@item out_w, ow
+@item out_h, oh
+the output width and heigth, that is the size of the padded area as
+specified by the @var{width} and @var{height} expressions
+
+@item rotw(a)
+@item roth(a)
+the minimal width/height required for completely containing the input
+video rotated by @var{a} radians.
+
+These are only available when computing the @option{out_w} and
+@option{out_h} expressions.
@end table
-For example to change the display aspect ratio to 16:9, specify:
+@subsection Examples
+
+@itemize
+@item
+Rotate the input by PI/6 radians clockwise:
@example
-setdar=dar=16/9
-# the above is equivalent to
-setdar=dar=1.77777
+rotate=PI/6
@end example
-See also the @ref{setsar} filter documentation.
+@item
+Rotate the input by PI/6 radians counter-clockwise:
+@example
+rotate=-PI/6
+@end example
-@section setpts
+@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
-Change the PTS (presentation timestamp) of the input video frames.
+@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
-This filter accepts the following options:
+@item
+Rotate the video, output size is choosen so that the whole rotating
+input video is always completely contained in the output:
+@example
+rotate='2*PI*t:ow=hypot(iw,ih):oh=ow'
+@end example
+
+@item
+Rotate the video, reduce the output size so that no background is ever
+shown:
+@example
+rotate=2*PI*t:ow='min(iw,ih)/sqrt(2)':oh=ow:c=none
+@end example
+@end itemize
+
+@subsection Commands
+
+The filter supports the following commands:
@table @option
+@item a, angle
+Set the angle expression.
+The command accepts the same syntax of the corresponding option.
-@item expr
-The expression which is evaluated for each frame to construct its timestamp.
+If the specified expression is not valid, it is kept at its current
+value.
+@end table
+
+@section sab
+
+Apply Shape Adaptive Blur.
+
+The filter accepts the following options:
+@table @option
+@item luma_radius, lr
+Set luma blur filter strength, must be a value in range 0.1-4.0, default
+value is 1.0. A greater value will result in a more blurred image, and
+in slower processing.
+
+@item luma_pre_filter_radius, lpfr
+Set luma pre-filter radius, must be a value in the 0.1-2.0 range, default
+value is 1.0.
+
+@item luma_strength, ls
+Set luma maximum difference between pixels to still be considered, must
+be a value in the 0.1-100.0 range, default value is 1.0.
+
+@item chroma_radius, cr
+Set chroma blur filter strength, must be a value in range 0.1-4.0. A
+greater value will result in a more blurred image, and in slower
+processing.
+
+@item chroma_pre_filter_radius, cpfr
+Set chroma pre-filter radius, must be a value in the 0.1-2.0 range.
+
+@item chroma_strength, cs
+Set chroma maximum difference between pixels to still be considered,
+must be a value in the 0.1-100.0 range.
@end table
-The expression is evaluated through the eval API and can contain the following
-constants:
+Each chroma option value, if not explicitly specified, is set to the
+corresponding luma option value.
+
+@section scale
+
+Scale (resize) the input video, using the libswscale library.
+
+The scale filter forces the output display aspect ratio to be the same
+of the input, by changing the output sample aspect ratio.
+
+If the input image format is different from the format requested by
+the next filter, the scale filter will convert the input to the
+requested format.
+
+@subsection Options
+The filter accepts the following options, or any of the options
+supported by the libswscale scaler.
+
+See @ref{scaler_options,,the ffmpeg-scaler manual,ffmpeg-scaler} for
+the complete list of scaler options.
@table @option
-@item PTS
-the presentation timestamp in input
+@item width, w
+@item height, h
+Set the output video dimension expression. Default value is the input
+dimension.
-@item PI
-Greek PI
+If the value is 0, the input width is used for the output.
-@item PHI
-golden ratio
+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 E
-Euler number
+See below for the list of accepted constants for use in the dimension
+expression.
-@item N
-the count of the input frame, starting from 0.
+@item interl
+Set the interlacing mode. It accepts the following values:
-@item STARTPTS
-the PTS of the first video frame
+@table @samp
+@item 1
+Force interlaced aware scaling.
-@item INTERLACED
-tell if the current frame is interlaced
+@item 0
+Do not apply interlaced scaling.
-@item PREV_INPTS
-previous input PTS
+@item -1
+Select interlaced aware scaling depending on whether the source frames
+are flagged as interlaced or not.
+@end table
-@item PREV_OUTPTS
-previous output PTS
+Default value is @samp{0}.
-@item RTCTIME
-wallclock (RTC) time in microseconds
+@item flags
+Set libswscale scaling flags. See
+@ref{sws_flags,,the ffmpeg-scaler manual,ffmpeg-scaler} for the
+complete list of values. If not explictly specified the filter applies
+the default flags.
-@item RTCSTART
-wallclock (RTC) time at the start of the movie in microseconds
+@item size, s
+Set the video size. For the syntax of this option, check the "Video size"
+section in the ffmpeg-utils manual.
-@item TB
-timebase of the input timestamps
+@item in_color_matrix
+@item out_color_matrix
+Set in/output YCbCr color space type.
+
+This allows the autodetected value to be overridden as well as allows forcing
+a specific value used for the output and encoder.
+
+If not specified, the color space type depends on the pixel format.
+
+Possible values:
+
+@table @samp
+@item auto
+Choose automatically.
+
+@item bt709
+Format conforming to International Telecommunication Union (ITU)
+Recommendation BT.709.
+
+@item fcc
+Set color space conforming to the United States Federal Communications
+Commission (FCC) Code of Federal Regulations (CFR) Title 47 (2003) 73.682 (a).
+
+@item bt601
+Set color space conforming to:
+@itemize
+@item
+ITU Radiocommunication Sector (ITU-R) Recommendation BT.601
+
+@item
+ITU-R Rec. BT.470-6 (1998) Systems B, B1, and G
+
+@item
+Society of Motion Picture and Television Engineers (SMPTE) ST 170:2004
+
+@end itemize
+
+@item smpte240m
+Set color space conforming to SMPTE ST 240:1999.
@end table
-Some examples follow:
+@item in_range
+@item out_range
+Set in/output YCbCr sample range.
-@example
-# start counting PTS from zero
-setpts=expr=PTS-STARTPTS
+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:
-# fast motion
-setpts=expr=0.5*PTS
+@table @samp
+@item auto
+Choose automatically.
-# slow motion
-setpts=2.0*PTS
+@item jpeg/full/pc
+Set full range (0-255 in case of 8-bit luma).
-# fixed rate 25 fps
-setpts=N/(25*TB)
+@item mpeg/tv
+Set "MPEG" range (16-235 in case of 8-bit luma).
+@end table
-# fixed rate 25 fps with some jitter
-setpts='1/(25*TB) * (N + 0.05 * sin(N*2*PI/25))'
+@item force_original_aspect_ratio
+Enable decreasing or increasing output video width or height if necessary to
+keep the original aspect ratio. Possible values:
-# generate timestamps from a "live source" and rebase onto the current timebase
-setpts='(RTCTIME - RTCSTART) / (TB * 1000000)"
-@end example
+@table @samp
+@item disable
+Scale the video as specified and disable this feature.
-@anchor{setsar}
-@section setsar
+@item decrease
+The output video dimensions will automatically be decreased if needed.
-Set the Sample (aka Pixel) Aspect Ratio for the filter output video.
+@item increase
+The output video dimensions will automatically be increased if needed.
-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}
+@end table
-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.
+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.
-This filter accepts the following options:
+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.
-@table @option
+@end table
+
+The values of the @option{w} and @option{h} options are expressions
+containing the following constants:
+
+@table @var
+@item in_w
+@item in_h
+the input width and height
+
+@item iw
+@item ih
+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
+same as @var{out_w} and @var{out_h}
+
+@item a
+same as @var{iw} / @var{ih}
@item sar
-Output sample aspect ratio, as a rational or decimal number.
+input sample aspect ratio
+@item dar
+input display aspect ratio. Calculated from @code{(iw / ih) * 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.
@end table
-For example to change the sample aspect ratio to 10:11, specify:
+@subsection Examples
+
+@itemize
+@item
+Scale the input video to a size of 200x100:
@example
-setsar=sar=10/11
+scale=w=200:h=100
@end example
-@section settb
+This is equivalent to:
+@example
+scale=200:100
+@end example
-Set the timebase to use for the output frames timestamps.
-It is mainly useful for testing timebase configuration.
+or:
+@example
+scale=200x100
+@end example
-This filter accepts the following options:
+@item
+Specify a size abbreviation for the output size:
+@example
+scale=qcif
+@end example
+
+which can also be written as:
+@example
+scale=size=qcif
+@end example
+
+@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
+
+@item
+Seek for Greek harmony:
+@example
+scale=iw:1/PHI*iw
+scale=ih*PHI:ih
+@end example
+
+@item
+Increase the height, and set the width to 3/2 of the height:
+@example
+scale=w=3/2*oh:h=3/5*ih
+@end example
+
+@item
+Increase the size, but make 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, keep the same input
+aspect ratio:
+@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 equation
+above.
+
+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.
+
+The filters accept the following options:
@table @option
+@item r, ratio, dar (@code{setdar} only), sar (@code{setsar} only)
+Set the aspect ratio used by the filter.
-@item expr
-The expression which is evaluated into the output timebase.
+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
-The expression can contain the constants "PI", "E", "PHI", "AVTB" (the
-default timebase), and "intb" (the input timebase).
+@subsection Examples
-The default value for the input is "intb".
+@itemize
-Follow some examples.
+@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
-# set the timebase to 1/25
-settb=expr=1/25
+setsar=sar=10/11
+@end example
-# set the timebase to 1/10
-settb=expr=0.1
+@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
-#set the timebase to 1001/1000
-settb=1+0.001
+@end itemize
-#set the timebase to 2*intb
-settb=2*intb
+@anchor{setfield}
+@section setfield
-#set the default timebase value
-settb=AVTB
-@end example
+Force field for the output video frame.
+
+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 filter accepts the following options:
+
+@table @option
+
+@item mode
+Available values are:
+
+@table @samp
+@item auto
+Keep the same field property.
+
+@item bff
+Mark the frame as bottom-field-first.
+
+@item tff
+Mark the frame as top-field-first.
+
+@item prog
+Mark the frame as progressive.
+@end table
+@end table
@section showinfo
@@ -2239,8 +7045,8 @@ sample aspect ratio of the input frame, expressed in the form
@var{num}/@var{den}
@item s
-size of the input frame, expressed in the form
-@var{width}x@var{height}
+size of the input frame. For the syntax of this option, check the "Video size"
+section in the ffmpeg-utils manual.
@item i
interlaced mode ("P" for "progressive", "T" for top field first, "B"
@@ -2257,43 +7063,501 @@ the @code{av_get_picture_type_char} function defined in
@file{libavutil/avutil.h}.
@item checksum
-Adler-32 checksum of all the planes of the input frame
+Adler-32 checksum (printed in hexadecimal) of all the planes of the input frame
@item plane_checksum
-Adler-32 checksum of each plane of the input frame, expressed in the form
-"[@var{c0} @var{c1} @var{c2} @var{c3}]"
+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 split
+@anchor{smartblur}
+@section smartblur
-Split input video into several identical outputs.
+Blur the input video without impacting the outlines.
-The filter accepts a single parameter which specifies the number of outputs. If
-unspecified, it defaults to 2.
+The filter accepts the following options:
-For example
+@table @option
+@item luma_radius, lr
+Set the luma radius. The option value must be a float number in
+the range [0.1,5.0] that specifies the variance of the gaussian filter
+used to blur the image (slower if larger). Default value is 1.0.
+
+@item luma_strength, ls
+Set the luma strength. The option value must be a float number
+in the range [-1.0,1.0] that configures the blurring. A value included
+in [0.0,1.0] will blur the image whereas a value included in
+[-1.0,0.0] will sharpen the image. Default value is 1.0.
+
+@item luma_threshold, lt
+Set the luma threshold used as a coefficient to determine
+whether a pixel should be blurred or not. The option value must be an
+integer in the range [-30,30]. A value of 0 will filter all the image,
+a value included in [0,30] will filter flat areas and a value included
+in [-30,0] will filter edges. Default value is 0.
+
+@item chroma_radius, cr
+Set the chroma radius. The option value must be a float number in
+the range [0.1,5.0] that specifies the variance of the gaussian filter
+used to blur the image (slower if larger). Default value is 1.0.
+
+@item chroma_strength, cs
+Set the chroma strength. The option value must be a float number
+in the range [-1.0,1.0] that configures the blurring. A value included
+in [0.0,1.0] will blur the image whereas a value included in
+[-1.0,0.0] will sharpen the image. Default value is 1.0.
+
+@item chroma_threshold, ct
+Set the chroma threshold used as a coefficient to determine
+whether a pixel should be blurred or not. The option value must be an
+integer in the range [-30,30]. A value of 0 will filter all the image,
+a value included in [0,30] will filter flat areas and a value included
+in [-30,0] will filter edges. Default value is 0.
+@end table
+
+If a chroma option is not explicitly set, the corresponding luma value
+is set.
+
+@section stereo3d
+
+Convert between different stereoscopic image formats.
+
+The filters accept the following options:
+
+@table @option
+@item in
+Set stereoscopic image format of input.
+
+Available values for input image formats are:
+@table @samp
+@item sbsl
+side by side parallel (left eye left, right eye right)
+
+@item sbsr
+side by side crosseye (right eye left, left eye right)
+
+@item sbs2l
+side by side parallel with half width resolution
+(left eye left, right eye right)
+
+@item sbs2r
+side by side crosseye with half width resolution
+(right eye left, left eye right)
+
+@item abl
+above-below (left eye above, right eye below)
+
+@item abr
+above-below (right eye above, left eye below)
+
+@item ab2l
+above-below with half height resolution
+(left eye above, right eye below)
+
+@item ab2r
+above-below with half height resolution
+(right eye above, left eye below)
+
+@item al
+alternating frames (left eye first, right eye second)
+
+@item ar
+alternating frames (right eye first, left eye second)
+
+Default value is @samp{sbsl}.
+@end table
+
+@item out
+Set stereoscopic image format of output.
+
+Available values for output image formats are all the input formats as well as:
+@table @samp
+@item arbg
+anaglyph red/blue gray
+(red filter on left eye, blue filter on right eye)
+
+@item argg
+anaglyph red/green gray
+(red filter on left eye, green filter on right eye)
+
+@item arcg
+anaglyph red/cyan gray
+(red filter on left eye, cyan filter on right eye)
+
+@item arch
+anaglyph red/cyan half colored
+(red filter on left eye, cyan filter on right eye)
+
+@item arcc
+anaglyph red/cyan color
+(red filter on left eye, cyan filter on right eye)
+
+@item arcd
+anaglyph red/cyan color optimized with the least squares projection of dubois
+(red filter on left eye, cyan filter on right eye)
+
+@item agmg
+anaglyph green/magenta gray
+(green filter on left eye, magenta filter on right eye)
+
+@item agmh
+anaglyph green/magenta half colored
+(green filter on left eye, magenta filter on right eye)
+
+@item agmc
+anaglyph green/magenta colored
+(green filter on left eye, magenta filter on right eye)
+
+@item agmd
+anaglyph green/magenta color optimized with the least squares projection of dubois
+(green filter on left eye, magenta filter on right eye)
+
+@item aybg
+anaglyph yellow/blue gray
+(yellow filter on left eye, blue filter on right eye)
+
+@item aybh
+anaglyph yellow/blue half colored
+(yellow filter on left eye, blue filter on right eye)
+
+@item aybc
+anaglyph yellow/blue colored
+(yellow filter on left eye, blue filter on right eye)
+
+@item aybd
+anaglyph yellow/blue color optimized with the least squares projection of dubois
+(yellow filter on left eye, blue filter on right eye)
+
+@item irl
+interleaved rows (left eye has top row, right eye starts on next row)
+
+@item irr
+interleaved rows (right eye has top row, left eye starts on next row)
+
+@item ml
+mono output (left eye only)
+
+@item mr
+mono output (right eye only)
+@end table
+
+Default value is @samp{arcd}.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Convert input video from side by side parallel to anaglyph yellow/blue dubois:
@example
-avconv -i INPUT -filter_complex split=5 OUTPUT
+stereo3d=sbsl:aybd
@end example
-will create 5 copies of the input video.
-@section transpose
+@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
-Transpose rows with columns in the input video and optionally flip it.
+@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.
+@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
+
+@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 dir
-The direction of the transpose.
+@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 accomodate 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
-The direction can assume the following values:
+Transpose rows with columns in the input video and optionally flip it.
+This filter accepts the following options:
+
+@table @option
+
+@item dir
+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
@@ -2301,7 +7565,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
@@ -2309,7 +7573,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
@@ -2317,7 +7581,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
@@ -2326,17 +7590,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.
This filter accepts the following options:
@table @option
@item start
-Timestamp (in seconds) of the start of the kept section. I.e. the frame with the
+Specify 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
-Timestamp (in seconds) of the first frame that will be dropped. I.e. the frame
+Specify 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.
@@ -2349,7 +7646,7 @@ Same as @var{end}, except this option sets the end timestamp in timebase units
instead of seconds.
@item duration
-Maximum duration of the output in seconds.
+Specify maximum duration of the output.
@item start_frame
Number of the first frame that should be passed to output.
@@ -2358,6 +7655,10 @@ Number of the first frame that should be passed to output.
Number of the first frame that should be dropped.
@end table
+@option{start}, @option{end}, @option{duration} are expressed as time
+duration specifications, check the "Time duration" section in the
+ffmpeg-utils manual.
+
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
@@ -2377,16 +7678,18 @@ 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
+
+
@section unsharp
Sharpen or blur the input video.
@@ -2394,56 +7697,447 @@ 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, 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, default value is 5.
+
+@item luma_amount, la
+Set the luma effect strength. It can be a float 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.
-@item luma_msize_x
-Set the luma matrix horizontal size. It can be an integer between 3
-and 13, default value is 5.
+Default value is 1.0.
-@item luma_msize_y
-Set the luma matrix vertical size. It can be an integer between 3
-and 13, 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, default value is 5.
-@item luma_amount
-Set the luma effect strength. It can be a float number between -2.0
-and 5.0, default value is 1.0.
+@item chroma_msize_y, cy
+Set the chroma matrix vertical size. It must be an odd integer
+between 3 and 63, default value is 5.
-@item chroma_msize_x
-Set the chroma matrix horizontal size. It can be an integer between 3
-and 13, default value is 5.
+@item chroma_amount, ca
+Set the chroma effect strength. It can be a float number, reasonable
+values lay between -1.5 and 1.5.
-@item chroma_msize_y
-Set the chroma matrix vertical size. It can be an integer between 3
-and 13, 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 chroma_amount
-Set the chroma effect strength. It can be a float number between -2.0
-and 5.0, default value is 0.0.
+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
-# Strong blur of both luma and chroma parameters
+@item
+Apply 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 9.
+
+@item stepsize
+Set stepsize of the search process. The region around minimum is
+scanned with 1 pixel resolution. Default value is 6.
+
+@item mincontrast
+Set minimum contrast. Below this value a local measurement field is
+discarded. Must be a floating point value in the range 0-1. Default
+value is 0.3.
+
+@item tripod
+Set reference frame number for tripod mode.
+
+If enabled, the motion of the frames is compared to a reference frame
+in the filtered stream, identified by the specified number. The idea
+is to compensate all movements in a more-or-less static scene and keep
+the camera view absolutely still.
+
+If set to 0, it is disabled. The frames are counted starting from 1.
+
+@item show
+Show fields and transforms in the resulting frames. It accepts an
+integer in the range 0-2. Default value is 0, which disables any
+visualization.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Use default values:
+@example
+vidstabdetect
+@end example
+
+@item
+Analyze strongly shaky movie and put the results in file
+@file{mytransforms.trf}:
+@example
+vidstabdetect=shakiness=10:accuracy=15:result="mytransforms.trf"
+@end example
+
+@item
+Visualize the result of internal transformations in the resulting
+video:
+@example
+vidstabdetect=show=1
+@end example
+
+@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 unsharp filter, see below.
+
+To enable compilation of this filter you need to configure FFmpeg with
+@code{--enable-libvidstab}.
+
+This filter accepts the following options:
+
+@table @option
+
+@item input
+path to the file used to read the transforms (default: @file{transforms.trf})
+
+@item smoothing
+number of frames (value*2 + 1) used for lowpass filtering the camera movements
+(default: 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 values leads to a smoother video, but limits the
+acceleration of the camera (pan/tilt movements).
+
+@item maxshift
+maximal number of pixels to translate frames (default: -1 no limit)
+
+@item maxangle
+maximal angle in radians (degree*PI/180) to rotate frames (default: -1
+no limit)
+
+@item crop
+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
+@table @samp
+@item 0
+keep transforms normal (default)
+@item 1
+invert transforms
+@end table
+
+@item relative
+consider transforms as
+@table @samp
+@item 0
+absolute
+@item 1
+relative to previous frame (default)
+@end table
+
+@item zoom
+percentage to zoom (default: 0)
+@table @samp
+@item >0
+zoom in
+@item <0
+zoom out
+@end table
+
+@item optzoom
+set optimal zooming to avoid borders
+@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)
+@end table
+Note that the value given at zoom is added to the one calculated
+here.
+
+@item interpol
+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
+virtual tripod mode means that the video is stabilized such that the
+camera stays stationary. Use also @code{tripod} option of
+@ref{vidstabdetect}.
+@table @samp
+@item 0
+off (default)
+@item 1
+virtual tripod mode: equivalent to @code{relative=0:smoothing=0}
+@end table
+
+@end table
-# Use the default values with @command{avconv}
-./avconv -i in.avi -vf "unsharp" out.mp4
+@subsection Examples
+
+@itemize
+@item
+typical call with default default values:
+ (note the unsharp filter which is always recommended)
+@example
+ffmpeg -i inp.mpeg -vf vidstabtransform,unsharp=5:5:0.8:3:3:0.4 inp_stabilized.mpeg
+@end example
+
+@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
+ffmpeg -i in.avi -vf "vflip" out.avi
+@end example
+
+@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 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
-./avconv -i in.avi -vf "vflip" out.avi
+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
+
+@anchor{yadif}
@section yadif
Deinterlace the input video ("yadif" means "yet another deinterlacing
@@ -2451,54 +8145,54 @@ filter").
This filter accepts the following options:
+
@table @option
@item mode
The interlacing mode to adopt, accepts one of the following values:
@table @option
-@item 0
+@item 0, send_frame
output 1 frame for each frame
-@item 1
+@item 1, send_field
output 1 frame for each field
-@item 2
-like 0 but skips spatial interlacing check
-@item 3
-like 1 but skips spatial interlacing check
+@item 2, send_frame_nospatial
+like @code{send_frame} but skip spatial interlacing check
+@item 3, send_field_nospatial
+like @code{send_field} but skip spatial interlacing check
@end table
-Default value is 0.
+Default value is @code{send_frame}.
@item parity
The picture field parity assumed for the input interlaced video, accepts one of
the following values:
@table @option
-@item 0
+@item 0, tff
assume top field first
-@item 1
+@item 1, bff
assume bottom field first
-@item -1
+@item -1, auto
enable automatic detection
@end table
-Default value is -1.
+Default value is @code{auto}.
If interlacing is unknown or decoder does not export this information,
top field first will be assumed.
-@item auto
-Whether 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
-Default value is 0.
-
+Default value is @code{all}.
@end table
@c man end VIDEO FILTERS
@@ -2515,10 +8209,15 @@ Buffer video frames, and make them available to the filter chain.
This source is mainly intended for a programmatic use, in particular
through the interface defined in @file{libavfilter/vsrc_buffer.h}.
-This filter accepts the following parameters:
+This source accepts the following options:
@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
Input video width.
@@ -2526,14 +8225,23 @@ Input video width.
Input video height.
@item pix_fmt
-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
-Sample (pixel) aspect ratio of the input video.
+@item frame_rate
+Specify the frame rate expected for the video stream.
+@item pixel_aspect, sar
+Specify the sample aspect ratio assumed by the video frames.
+
+@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:
@@ -2544,131 +8252,274 @@ 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 float
-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
-For example the following graph description will generate a red source
-with an opacity of 0.2, with size "qcif" and a frame rate of 10
-frames per second, which will be overlayed over the source connected
-to the pad with identifier "in".
+@subsection Examples
+@itemize
+@item
+Read the initial state from @file{pattern}, and specify an output of
+size 200x400.
@example
-"color=red@@0.2:qcif:10 [color]; [in][color] overlay [out]"
+cellauto=f=pattern:s=200x400
@end example
-@section movie
+@item
+Generate a random initial row with a width of 200 cells, with a fill
+ratio of 2/3:
+@example
+cellauto=ratio=2/3:s=200x200
+@end example
-Read a video stream from a movie container.
+@item
+Create a pattern generated by rule 18 starting by a single alive cell
+centered on an initial row with width 100:
+@example
+cellauto=p=@@:s=100x400:full=0:rule=18
+@end example
-Note that this source is a hack that bypasses the standard input path. It can be
-useful in applications that do not support arbitrary filter graphs, but its use
-is discouraged in those that do. Specifically in @command{avconv} this filter
-should never be used, the @option{-filter_complex} option fully replaces it.
+@item
+Specify a more elaborated initial pattern:
+@example
+cellauto=p='@@@@ @@ @@@@':s=100x400:full=0:rule=18
+@end example
-This filter accepts the following options:
+@end itemize
+
+@section mandelbrot
+
+Generate a Mandelbrot set fractal, and progressively zoom towards the
+point specified with @var{start_x} and @var{start_y}.
+
+This source accepts the following options:
@table @option
-@item filename
-The name of the resource to read (not necessarily a file but also 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. 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 best suited video stream will be automatically selected. 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}.
-This filter allows to overlay a second video on top of 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 follow:
-@example
-# skip 3.2 seconds from the start of the avi file in.avi, and overlay it
-# on top of the input labelled as "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".
+
+@item start_scale
+Set the initial scale value. Default value is 3.0.
+
+@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.
-# read from a video4linux2 device, and overlay it on top of the input
-# labelled as "in"
-movie=/dev/video0:f=video4linux2, scale=180:-1, setpts=PTS-STARTPTS [movie];
-[in] setpts=PTS-STARTPTS, [movie] overlay=16:16 [out]
+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 float
+number or a valid video frame rate abbreviation. The default value is
+"25".
+
+@item duration, d
+Set the video duration of the sourced video. The accepted syntax is:
+@example
+[-]HH:MM:SS[.m...]
+[-]S+[.m...]
@end example
+See also the function @code{av_parse_time()}.
-@section nullsrc
+If not specified, or the expressed duration is negative, the video is
+supposed to be generated forever.
-Null video source, never return images. It is mainly useful as a
-template and to be employed in analysis / debugging tools.
+@item test, t
-It accepts as optional parameter a string of the form
-@var{width}:@var{height}:@var{timebase}.
+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
-@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).
+Default value is "all", which will cycle through the list of all tests.
+@end table
+
+For example the following:
+@example
+testsrc=t=dc_luma
+@end example
-@var{timebase} specifies an arithmetic expression representing a
-timebase. The expression can contain the constants "PI", "E", "PHI",
-"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 options:
@table @option
@item size
-The size of the video to generate, 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
Framerate of the generated video, may be a string of the form
@@ -2684,19 +8535,169 @@ A '|'-separated list of parameters to pass to the frei0r source.
@end table
-Some examples follow:
+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 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.
@@ -2705,10 +8706,23 @@ The sources accept the following options:
@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
@@ -2720,7 +8734,7 @@ 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
+@item duration, d
Set the video duration of the sourced video. The accepted syntax is:
@example
[-]HH[:MM[:SS[.m...]]]
@@ -2730,6 +8744,14 @@ See also the function @code{av_parse_time()}.
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:
@@ -2738,7 +8760,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
@@ -2752,8 +8798,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 a programmatic use through the interface defined in
-@file{libavfilter/buffersink.h}.
+This sink is mainly intended for a 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
@@ -2762,3 +8813,1164 @@ mainly useful as a template and to be employed 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 video
+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}.
+@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, NAN if undefined
+
+@item TB
+timebase of the input timestamps
+
+@item pts
+the PTS (Presentation TimeStamp) of the filtered video frame,
+expressed in @var{TB} units, NAN if undefined
+
+@item t
+the PTS (Presentation TimeStamp) of the filtered video frame,
+expressed in seconds, NAN if undefined
+
+@item prev_pts
+the PTS of the previously filtered video frame, NAN if undefined
+
+@item prev_selected_pts
+the PTS of the last previously filtered video frame, NAN if undefined
+
+@item prev_selected_t
+the PTS of the last previously selected video frame, NAN if undefined
+
+@item start_pts
+the PTS of the first video frame in the video, NAN if undefined
+
+@item start_t
+the time of the first video frame in the video, NAN if undefined
+
+@item pict_type @emph{(video only)}
+the type of the filtered frame, 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, 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
+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
+audio sample rate
+
+@item STARTPTS
+the PTS of the first frame
+
+@item STARTT
+the time in seconds of the first frame
+
+@item INTERLACED
+tell if 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
+previous input PTS
+
+@item PREV_INT
+previous input time in seconds
+
+@item PREV_OUTPTS
+previous output PTS
+
+@item PREV_OUTT
+previous output time in seconds
+
+@item RTCTIME
+wallclock (RTC) time in microseconds. This is deprecated, use time(0)
+instead.
+
+@item RTCSTART
+wallclock (RTC) time at the start of the movie in microseconds
+
+@item TB
+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.
+
+This filter accepts the following options:
+
+@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 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 if the spectrum should slide along the window. Default value is
+@code{0}.
+
+@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}.
+@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.
+@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".
+
+@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.
+
+This filter accepts the following options:
+
+@table @option
+@item filename
+The name of the resource to read (not necessarily a file but also 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. 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 best suited video stream will be automatically selected. 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
+
+This filter allows to overlay a second video on top of 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 as "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 as "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..b535a5f
--- a/dev/null
+++ b/doc/formats.texi
@@ -0,0 +1,188 @@
+@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
+@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})
+Shift timestamps to make them non-negative. A value of 1 enables shifting,
+a value of 0 disables it, the default value of -1 enables shifting
+when required by the target format.
+
+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.
+
+Also note that this affects only leading negative timestamps, and not
+non-monotonic negative timestamps.
+
+@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.
+@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.
+
+@include demuxers.texi
+@include muxers.texi
+@include metadata.texi
diff --git a/doc/general.texi b/doc/general.texi
index c2dc272..647c5e2 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,15 +78,23 @@ 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.
Then pass @code{--enable-libmp3lame} to configure to enable it.
+@section TwoLAME
+
+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.
+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
@@ -81,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
@@ -89,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
@@ -98,29 +119,43 @@ 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 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
-@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
@@ -128,27 +163,43 @@ 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
@tab Multimedia format used in games like Mad Dog McCree.
@item 3GPP AMR @tab X @tab X
+@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.
@@ -161,7 +212,7 @@ library:
@tab Video format used by CD+G karaoke disks
@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
@@ -179,7 +230,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 FFM (AVserver live feed) @tab X @tab X
+@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.
@@ -190,13 +242,19 @@ 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 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
@@ -207,9 +265,13 @@ 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 LVF @tab @tab X
@item LXF @tab @tab X
@tab VR native stream format, used by Leitch/Harris' video servers.
@item Matroska @tab X @tab X
@@ -219,6 +281,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
@@ -246,6 +311,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
@@ -254,6 +320,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
@@ -264,6 +331,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
@@ -283,7 +351,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
@@ -309,19 +377,23 @@ 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.
+@item Silicon Graphics Movie @tab @tab X
@item Sierra SOL @tab @tab X
@tab .sol files used in Sierra Online games.
@item Sierra VMD @tab @tab X
@@ -330,10 +402,12 @@ library:
@tab Multimedia format used by many games.
@item SMJPEG @tab X @tab X
@tab Used in certain Loki game ports.
+@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 Text files @tab @tab X
@@ -343,10 +417,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
@@ -357,16 +432,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
@@ -374,15 +449,17 @@ following image formats are supported:
@item .Y.U.V @tab X @tab X
@tab one raw file per component
@item animated GIF @tab X @tab X
- @tab Only uncompressed GIFs are generated.
@item BMP @tab X @tab X
@tab Microsoft BMP image
+@item PIX @tab @tab X
+ @tab PIX is an image format used in the Argonaut BRender engine.
@item DPX @tab X @tab X
@tab Digital Picture Exchange
+@item EXR @tab @tab X
+ @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
@@ -399,7 +476,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
@@ -414,8 +490,10 @@ following image formats are supported:
@tab Targa (.TGA) image format
@item WebP @tab @tab X
@tab WebP image format
-@item XBM @tab X @tab
+@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
@@ -431,13 +509,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
@@ -458,13 +535,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
@@ -484,10 +566,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
@@ -509,10 +592,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
@@ -545,6 +628,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
@@ -553,6 +637,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 Smush @tab @tab X
+ @tab Used in LucasArts games.
@item lossless MJPEG @tab X @tab X
@item Microsoft ATC Screen @tab @tab X
@tab Also known as Microsoft Screen 3.
@@ -590,8 +676,12 @@ following image formats are supported:
@tab fourcc: VP60,VP61,VP62
@item VP8 @tab E @tab X
@tab fourcc: VP80, encoding supported through external library libvpx
-@item planar RGB @tab @tab X
- @tab fourcc: 8BPS
+@item VP9 @tab E @tab X
+ @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
@@ -601,8 +691,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
@@ -613,11 +703,16 @@ following image formats are supported:
@tab Texture dictionaries used by the Renderware Engine.
@item RL2 video @tab @tab X
@tab used in some games by Entertainment Software Partners
+@item SGI RLE 8-bit @tab @tab X
@item Sierra VMD video @tab @tab X
@tab Used in Sierra VMD files.
+@item Silicon Graphics Motion Video Compressor 1 (MVC1) @tab @tab X
+@item Silicon Graphics Motion Video Compressor 2 (MVC2) @tab @tab X
@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
@@ -635,6 +730,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
@@ -653,6 +750,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
@@ -667,7 +767,10 @@ 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
@@ -696,19 +799,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
@@ -719,20 +824,23 @@ following image formats are supported:
@tab encoding supported through external library libopencore-amrnb
@item AMR-WB @tab E @tab X
@tab encoding supported through external library libvo-amrwbenc
+@item Amazing Studio PAF Audio @tab @tab X
@item Apple lossless audio @tab X @tab X
@tab QuickTime fourcc 'alac'
@item ATRAC1 @tab @tab X
@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
@@ -743,8 +851,10 @@ following image formats are supported:
@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
@@ -758,9 +868,9 @@ 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 IX @tab IX
+ @tab libtwolame can be used alternatively for encoding.
@item MP3 (MPEG audio layer 3) @tab E @tab IX
@tab encoding supported through external library LAME, ADU MP3 and MP3onMP4 also supported
@item MPEG-4 Audio Lossless Coding (ALS) @tab @tab X
@@ -771,9 +881,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
@@ -810,20 +922,25 @@ 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
@tab imperfect and incomplete support
-@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
@@ -843,16 +960,34 @@ 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 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 @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
@@ -889,18 +1024,34 @@ 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 Lavfi virtual device @tab X @tab
@item Linux framebuffer @tab X @tab
@item JACK @tab X @tab
@item LIBCDIO @tab X
@item LIBDC1394 @tab X @tab
+@item OpenAL @tab X
@item OSS @tab X @tab X
@item Pulseaudio @tab X @tab
-@item Video4Linux2 @tab X @tab
+@item SDL @tab @tab X
+@item Video4Linux2 @tab X @tab X
@item VfW capture @tab X @tab
@item X11 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..44e1cc6 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
@@ -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
index 036b567..5ba72ee 100644
--- a/doc/git-howto.txt
+++ b/doc/git-howto.txt
@@ -28,9 +28,9 @@ 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
+What follows now is a basic introduction to Git and some FFmpeg-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.
+FFmpeg project you are expected to be familiar with these rules.
@@ -39,18 +39,19 @@ I. BASICS:
0. Get GIT:
+ Most distributions have a git package, if not
You can get git from http://git-scm.com/
1. Cloning the source tree:
- git clone git://git.libav.org/libav.git <target>
+ git clone git://source.ffmpeg.org/ffmpeg <target>
- This will put the Libav sources into the directory <target>.
+ This will put the FFmpeg sources into the directory <target>.
- git clone git@git.libav.org:libav.git <target>
+ git clone git@source.ffmpeg.org:ffmpeg <target>
- This will put the Libav sources into the directory <target> and let
+ This will put the FFmpeg sources into the directory <target> and let
you push back your changes to the remote repository.
@@ -72,7 +73,7 @@ I. BASICS:
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.
3. Adding/removing files/directories:
@@ -97,7 +98,7 @@ I. BASICS:
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/
+ interface available at http://source.ffmpeg.org
6. Checking source tree status:
@@ -268,5 +269,5 @@ I. BASICS:
where $SHA1 is the commit SHA1 from the 'git log' output.
-Contact the project admins <git at libav dot org> if you have technical
+Contact the project admins <root at ffmpeg dot org> if you have technical
problems with the GIT server.
diff --git a/doc/indevs.texi b/doc/indevs.texi
index 8ff64a7..72b1493 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,7 +13,7 @@ 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
+The option "-formats" of the ff* tools will display the list of
supported input devices (amongst the demuxers).
A description of the currently available input devices follows.
@@ -42,10 +42,10 @@ 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:
@@ -55,6 +55,114 @@ For more information see:
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 +180,78 @@ 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 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 +263,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,119 +291,245 @@ 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 libdc1394
+@section lavfi
-IIDC1394 input device, based on libdc1394 and libraw1394.
+Libavfilter input virtual device.
-@section oss
+This input device reads data from the open output pads of a libavfilter
+filtergraph.
-Open Sound System input device.
+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}.
-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}.
+@subsection Options
-For example to grab from @file{/dev/dsp} using @command{avconv} use the
-command:
-@example
-avconv -f oss -i /dev/dsp /tmp/oss.wav
-@end example
+@table @option
-For more information about OSS see:
-@url{http://manuals.opensound.com/usersguide/dsp.html}
+@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.
-@section pulse
+If not specified defaults to the filename specified for the input
+device.
-pulseaudio 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}.
-To enable this input device during configuration you need libpulse-simple
-installed in your system.
+@end table
-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}.
+@subsection Examples
+@itemize
+@item
+Create a color video stream and play it back with @command{ffplay}:
@example
-avconv -f pulse -i default /tmp/pulse.wav
+ffplay -f lavfi -graph "color=c=pink [out0]" dummy
@end example
-@subsection @var{server} AVOption
-
-The syntax is:
+@item
+As the previous example, but use filename for specifying the graph
+description, and omit the "out0" label:
@example
--server @var{server name}
+ffplay -f lavfi color=c=pink
@end example
-Connects to a specific server.
+@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
-@subsection @var{name} AVOption
+@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
-The syntax is:
+@item
+Read an audio stream and a video stream and play it back with
+@command{ffplay}:
@example
--name @var{application name}
+ffplay -f lavfi "movie=test.avi[out0];amovie=test.wav[out1]"
@end example
-Specify the application name pulse will use when showing active clients,
-by default it is "libav"
+@end itemize
-@subsection @var{stream_name} AVOption
+@section libdc1394
-The syntax is:
-@example
--stream_name @var{stream name}
-@end example
+IIDC1394 input device, based on libdc1394 and libraw1394.
-Specify the stream name pulse will use when showing active streams,
-by default it is "record"
+@section openal
-@subsection @var{sample_rate} AVOption
+The OpenAL input device provides audio capture on all systems with a
+working OpenAL 1.1 implementation.
-The syntax is:
-@example
--sample_rate @var{samplerate}
-@end example
+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}.
-Specify the samplerate in Hz, by default 48kHz is used.
+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 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}.
-@subsection @var{channels} AVOption
+@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}.
-The syntax is:
+@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
--channels @var{N}
+$ ffmpeg -list_devices true -f openal -i dummy out.ogg
@end example
-Specify the channels in use, by default 2 (stereo) is set.
+Capture from the OpenAL device @file{DR-BT101 via PulseAudio}:
+@example
+$ ffmpeg -f openal -i 'DR-BT101 via PulseAudio' out.ogg
+@end example
-@subsection @var{frame_size} AVOption
+Capture from the default device (note the empty string '' as filename):
+@example
+$ ffmpeg -f openal -i '' out.ogg
+@end example
-The syntax is:
+Capture from two devices simultaneously, writing to two different files,
+within the same @command{ffmpeg} command:
@example
--frame_size @var{bytes}
+$ 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
-Specify the number of byte per frame, by default it is set to 1024.
+Open Sound System input device.
-@subsection @var{fragment_size} AVOption
+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}.
-The syntax is:
+For example to grab from @file{/dev/dsp} using @command{ffmpeg} use the
+command:
@example
--fragment_size @var{bytes}
+ffmpeg -f oss -i /dev/dsp /tmp/oss.wav
@end example
-Specify the minimal buffering fragment in pulseaudio, it will affect the
+For more information about OSS see:
+@url{http://manuals.opensound.com/usersguide/dsp.html}
+
+@section pulse
+
+PulseAudio input device.
+
+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 PulseAudio source devices and their properties you can invoke
+the command @command{pactl list sources}.
+
+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 "record".
+
+@item sample_rate
+Specify the samplerate in Hz, by default 48kHz is used.
+
+@item channels
+Specify the channels in use, by default 2 (stereo) is set.
+
+@item frame_size
+Specify the number of bytes per frame, by default it is set to 1024.
+
+@item fragment_size
+Specify the minimal buffering fragment in PulseAudio, it will affect the
audio latency. By default it is unset.
+@end table
+
+@subsection Examples
+Record a stream from default device:
+@example
+ffmpeg -f pulse -i default /tmp/pulse.wav
+@end example
@section sndio
@@ -248,16 +542,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 +565,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 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
@@ -309,24 +696,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 +727,37 @@ zero) to the edge of region.
For example:
@example
-avconv -f x11grab -follow_mouse centered -r 25 -s cif -i :0.0 out.mpg
-
-# Follows only when the mouse pointer reaches within 100 pixels to edge
-avconv -f x11grab -follow_mouse 100 -r 25 -s cif -i :0.0 out.mpg
+ffmpeg -f x11grab -follow_mouse centered -framerate 25 -video_size cif -i :0.0 out.mpg
@end example
-@subsection @var{show_region} AVOption
-
-The syntax is:
+To follow only when the mouse pointer reaches within 100 pixels to edge:
@example
--show_region 1
+ffmpeg -f x11grab -follow_mouse 100 -framerate 25 -video_size cif -i :0.0 out.mpg
@end example
-If @var{show_region} AVOption is specified with @var{1}, then the grabbing
-region will be indicated on screen. With this option, it's easy to know what is
-being grabbed if only a portion of the screen is grabbed.
+@item framerate
+Set the grabbing frame rate. Default value is @code{ntsc},
+corresponding to a frame rate of @code{30000/1001}.
+
+@item show_region
+Show grabbed region on screen.
+
+If @var{show_region} is specified with @code{1}, then the grabbing
+region will be indicated on screen. With this option, it is easy to
+know what is being grabbed if only a portion of the screen is grabbed.
For example:
@example
-avconv -f x11grab -show_region 1 -r 25 -s cif -i :0.0+10,20 out.mpg
+ffmpeg -f x11grab -show_region 1 -framerate 25 -video_size cif -i :0.0+10,20 out.mpg
+@end example
-# With follow_mouse
-avconv -f x11grab -follow_mouse centered -show_region 1 -r 25 -s cif -i :0.0 out.mpg
+With @var{follow_mouse}:
+@example
+ffmpeg -f x11grab -follow_mouse centered -show_region 1 -framerate 25 -video_size cif -i :0.0 out.mpg
@end example
+@item video_size
+Set the video frame size. Default value is @code{vga}.
+@end table
+
@c man end INPUT DEVICES
diff --git a/doc/issue_tracker.txt b/doc/issue_tracker.txt
new file mode 100644
index 0000000..33b3535
--- a/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)://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
--- a/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
--- a/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 b452294..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 is the substitute of the
-now deprecated '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.
-But 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, 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 in output the top half of the video is mirrored
-onto the bottom half.
+@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, fifo, overlay} are in one linear
-chain, and @var{fifo, crop, vflip} are in another. The points where
-the linear chains join are labeled by names enclosed in square
-brackets. In our example, that is @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 in input a list of parameters: they are specified
-after the filter name and an equal sign, and are separated each other
-by a semicolon.
-
-There exist so-called @var{source filters} that do not have a video
-input, and we expect in the future some @var{sink filters} that will
-not have video output.
-
-@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
--- a/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..50b0d0e
--- a/dev/null
+++ b/doc/libavutil.texi
@@ -0,0 +1,44 @@
+\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).
+
+@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
--- a/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
--- a/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
--- a/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 6e06e46..ae5301c 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,28 @@ 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.
+
+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
@@ -35,20 +52,20 @@ CRC=0x@var{CRC}, where @var{CRC} is a hexadecimal number 0-padded to
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.
@@ -56,40 +73,79 @@ See also the @ref{framecrc} muxer.
@anchor{framecrc}
@section framecrc
-Per-frame CRC (Cyclic Redundancy Check) testing format.
+Per-packet CRC (Cyclic Redundancy Check) testing format.
-This muxer computes and prints the Adler-32 CRC for each decoded audio
-and video frame. By default audio frames are converted to signed
+This muxer computes and prints the Adler-32 CRC for each audio
+and video packet. By default audio frames are converted to signed
16-bit raw audio and video frames to raw video before computing the
CRC.
The output of the muxer consists of a line for each audio and video
-frame of the form: @var{stream_index}, @var{frame_dts},
-@var{frame_size}, 0x@var{CRC}, where @var{CRC} is a hexadecimal
-number 0-padded to 8 digits containing the CRC of the decoded frame.
+packet of the form:
+@example
+@var{stream_index}, @var{packet_dts}, @var{packet_pts}, @var{packet_duration}, @var{packet_size}, 0x@var{CRC}
+@end example
+
+@var{CRC} is a hexadecimal number 0-padded to 8 digits containing the
+CRC of the packet.
-For example to compute the CRC of each decoded frame in the input, and
-store it in the file @file{out.crc}:
+For example to compute the CRC of the audio and video frames in
+@file{INPUT}, converted to raw audio and video packets, and store it
+in the file @file{out.crc}:
@example
-avconv -i INPUT -f framecrc out.crc
+ffmpeg -i INPUT -f framecrc out.crc
@end example
-You can print the CRC of each decoded frame to stdout with the command:
+To print the information to stdout, use the command:
@example
-avconv -i INPUT -f framecrc -
+ffmpeg -i INPUT -f framecrc -
@end example
-You can select the output format of each frame with @command{avconv} by
-specifying the audio and video codec and format. For example, to
+With @command{ffmpeg}, you can select the output format to which the
+audio and video frames are encoded before computing the CRC for each
+packet by specifying the audio and video codec. For example, to
compute the CRC of each decoded input audio frame converted to PCM
unsigned 8-bit and of each decoded input video frame converted to
MPEG-2 video, use the command:
@example
-avconv -i INPUT -c:a pcm_u8 -c:v mpeg2video -f framecrc -
+ffmpeg -i INPUT -c:a pcm_u8 -c:v mpeg2video -f framecrc -
@end example
See also the @ref{crc} muxer.
+@anchor{framemd5}
+@section framemd5
+
+Per-packet MD5 testing format.
+
+This muxer computes and prints the MD5 hash for each audio
+and video packet. By default audio frames are converted to signed
+16-bit raw audio and video frames to raw video before computing the
+hash.
+
+The output of the muxer consists of a line for each audio and video
+packet of the form:
+@example
+@var{stream_index}, @var{packet_dts}, @var{packet_pts}, @var{packet_duration}, @var{packet_size}, @var{MD5}
+@end example
+
+@var{MD5} is a hexadecimal number representing the computed MD5 hash
+for the packet.
+
+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{hls}
@section hls
@@ -102,7 +158,7 @@ receive the same basename as the playlist, a sequential number and
a .ts extension.
@example
-avconv -i in.nut out.m3u8
+ffmpeg -i in.nut out.m3u8
@end example
@table @option
@@ -116,6 +172,39 @@ Set the number after which index wraps.
Start the sequence from @var{number}.
@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
@@ -146,31 +235,32 @@ 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
+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}.
+@item start_number @var{number}
+Start the sequence from @var{number}. Default value is 1. Must be a
+non-negative number.
@item -update @var{number}
If @var{number} is nonzero, the filename will always be interpreted as just a
@@ -179,12 +269,132 @@ images.
@end table
-@section MOV/MP4/ISMV
+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.
+
+The recognized metadata settings in this muxer are:
+
+@table @option
+
+@item title=@var{title name}
+Name provided to a single track
+@end table
+
+@table @option
+
+@item language=@var{language name}
+Specifies the language of the track in the Matroska languages form
+@end table
+
+@table @option
+
+@item stereo_mode=@var{mode}
+Stereo 3D video layout of two views in a single video track
+@table @option
+@item mono
+video is not stereo
+@item left_right
+Both views are arranged side by side, Left-eye view is on the left
+@item bottom_top
+Both views are arranged in top-bottom orientation, Left-eye view is at bottom
+@item top_bottom
+Both views are arranged in top-bottom orientation, Left-eye view is on top
+@item checkerboard_rl
+Each view is arranged in a checkerboard interleaved pattern, Left-eye view being first
+@item checkerboard_lr
+Each view is arranged in a checkerboard interleaved pattern, Right-eye view being first
+@item row_interleaved_rl
+Each view is constituted by a row based interleaving, Right-eye view is first row
+@item row_interleaved_lr
+Each view is constituted by a row based interleaving, Left-eye view is first row
+@item col_interleaved_rl
+Both views are arranged in a column based interleaving manner, Right-eye view is first column
+@item col_interleaved_lr
+Both views are arranged in a column based interleaving manner, Left-eye view is first column
+@item anaglyph_cyan_red
+All frames are in anaglyph format viewable through red-cyan filters
+@item right_left
+Both views are arranged side by side, Right-eye view is on the left
+@item anaglyph_green_magenta
+All frames are in anaglyph format viewable through green-magenta filters
+@item block_lr
+Both eyes laced in one Block, Left-eye view is first
+@item block_rl
+Both eyes laced in one Block, Right-eye view is first
+@end table
+@end table
+
+For example a 3D WebM clip can be created using the following command line:
+@example
+ffmpeg -i sample_left_right_clip.mpg -an -c:v libvpx -metadata stereo_mode=left_right -y stereo_clip.webm
+@end example
+
+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
+to leave for the index at the beginning of the file. However for some use cases
+-- e.g. streaming where seeking is possible but slow -- it is useful to put the
+index at the beginning of the file.
+
+If this option is set to a non-zero value, the muxer will reserve a given amount
+of space in the file header and then try to write the cues there when the muxing
+finishes. If the available space does not suffice, muxing will fail. A safe size
+for most use cases should be about 50kB per hour of video.
+
+Note that cues are only written if the output is seekable and this option will
+have no effect if it is not.
+
+@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
@@ -198,6 +408,9 @@ 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}
@@ -208,7 +421,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
@@ -243,12 +456,50 @@ 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.
@end table
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
+
+The MP3 muxer writes a raw MP3 stream with an ID3v2 header at the beginning and
+optionally an ID3v1 tag at the end. ID3v2.3 and ID3v2.4 are supported, the
+@code{id3v2_version} option controls which one is used. The legacy ID3v1 tag is
+not written by default, but may be enabled with the @code{write_id3v1} option.
+
+For seekable output the muxer also writes a Xing frame at the beginning, which
+contains the number of frames in the file. It is useful for computing duration
+of VBR files.
+
+The muxer supports writing ID3v2 attached pictures (APIC frames). The pictures
+are supplied to the muxer in form of a video stream with a single packet. There
+can be any number of those streams, each will correspond to a single APIC frame.
+The stream metadata tags @var{title} and @var{comment} map to APIC
+@var{description} and @var{picture type} respectively. See
+@url{http://id3.org/id3v2.4.0-frames} for allowed picture types.
+
+Note that the APIC frames must be written at the beginning, so the muxer will
+buffer the audio frames until it gets all the pictures. It is therefore advised
+to provide the pictures as soon as possible to avoid excessive buffering.
+
+Examples:
+
+Write an mp3 with an ID3v2.3 header and an ID3v1 footer:
+@example
+ffmpeg -i INPUT -id3v2_version 3 -write_id3v1 1 out.mp3
+@end example
+
+To attach a picture to an mp3 file select both the audio and the picture stream
+with @code{map}:
+@example
+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
@section mpegts
@@ -273,15 +524,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 muxrate.
+@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
+
+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
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_provider} is "FFmpeg" and the default for
@code{service_name} is "Service01".
@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 \
@@ -299,185 +584,327 @@ 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 matroska
+@section ogg
-Matroska container muxer.
+Ogg container muxer.
-This muxer implements the matroska and webm container specs.
+@table @option
+@item -page_duration @var{duration}
+Preferred page duration, in microseconds. The muxer will attempt to create
+pages that are approximately @var{duration} microseconds long. This allows the
+user to compromise between seek granularity and container overhead. The default
+is 1 second. A value of 0 will fill all segments, making pages as large as
+possible. A value of 1 will effectively use 1 packet-per-page in most
+situations, giving a small seek granularity at the cost of additional container
+overhead.
+@end table
-The recognized metadata settings in this muxer are:
+@section segment, stream_segment, ssegment
-@table @option
+Basic stream segmenter.
-@item title=@var{title name}
-Name provided to a single track
-@end table
+The segmenter muxer outputs streams to a number of separate files of nearly
+fixed duration. Output filename pattern can be set in a fashion similar to
+@ref{image2}.
-@table @option
+@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}.
-@item language=@var{language name}
-Specifies the language of the track in the Matroska languages form
-@end table
+Every segment starts with a keyframe of the selected reference stream,
+which is set through the @option{reference_stream} option.
-@table @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 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 segment muxer supports the following options:
-@item STEREO_MODE=@var{mode}
-Stereo 3D video layout of two views in a single video track
@table @option
-@item mono
-video is not stereo
-@item left_right
-Both views are arranged side by side, Left-eye view is on the left
-@item bottom_top
-Both views are arranged in top-bottom orientation, Left-eye view is at bottom
-@item top_bottom
-Both views are arranged in top-bottom orientation, Left-eye view is on top
-@item checkerboard_rl
-Each view is arranged in a checkerboard interleaved pattern, Left-eye view being first
-@item checkerboard_lr
-Each view is arranged in a checkerboard interleaved pattern, Right-eye view being first
-@item row_interleaved_rl
-Each view is constituted by a row based interleaving, Right-eye view is first row
-@item row_interleaved_lr
-Each view is constituted by a row based interleaving, Left-eye view is first row
-@item col_interleaved_rl
-Both views are arranged in a column based interleaving manner, Right-eye view is first column
-@item col_interleaved_lr
-Both views are arranged in a column based interleaving manner, Left-eye view is first column
-@item anaglyph_cyan_red
-All frames are in anaglyph format viewable through red-cyan filters
-@item right_left
-Both views are arranged side by side, Right-eye view is on the left
-@item anaglyph_green_magenta
-All frames are in anaglyph format viewable through green-magenta filters
-@item block_lr
-Both eyes laced in one Block, Left-eye view is first
-@item block_rl
-Both eyes laced in one Block, Right-eye view is first
-@end table
+@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 choosen
+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_list @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
-For example a 3D WebM clip can be created using the following command line:
+Default value is @code{samp}.
+
+@item segment_list_size @var{size}
+Update the list file so that it contains at most the last @var{size}
+segments. If 0 the list file will contain all the segments. Default
+value is 0.
+
+@item segment_list_type @var{type}
+Specify the format for the segment list file.
+
+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
-avconv -i sample_left_right_clip.mpg -an -c:v libvpx -metadata STEREO_MODE=left_right -y stereo_clip.webm
+@var{segment_filename},@var{segment_start_time},@var{segment_end_time}
@end example
-This muxer supports the following options:
+@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.
-@table @option
+@var{segment_start_time} and @var{segment_end_time} specify
+the segment start and end time expressed in seconds.
-@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
-to leave for the index at the beginning of the file. However for some use cases
--- e.g. streaming where seeking is possible but slow -- it is useful to put the
-index at the beginning of the file.
+A list file with the suffix @code{".csv"} or @code{".ext"} will
+auto-select this format.
-If this option is set to a non-zero value, the muxer will reserve a given amount
-of space in the file header and then try to write the cues there when the muxing
-finishes. If the available space does not suffice, muxing will fail. A safe size
-for most use cases should be about 50kB per hour of video.
+@samp{ext} is deprecated in favor or @samp{csv}.
-Note that cues are only written if the output is seekable and this option will
-have no effect if it is not.
+@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
-@section segment
+If not specified the type is guessed from the list file name suffix.
-Basic stream segmenter.
+@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.
-The segmenter muxer outputs streams to a number of separate files of nearly
-fixed duration. Output filename pattern can be set in a fashion similar to
-@ref{image2}.
+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.
-Every segment starts with a video keyframe, if a video stream is present.
-The segment muxer works best with a single constant frame rate video.
+@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".
-Optionally it can generate a flat list of the created segments, one segment
-per line.
+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.
-@table @option
-@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_list @var{name}
-Generate also a listfile named @var{name}.
-@item segment_list_size @var{size}
-Overwrite the listfile once it reaches @var{size} entries.
@item segment_wrap @var{limit}
Wrap around segment index once it reaches @var{limit}.
-@end table
-@example
-avconv -i in.mkv -c copy -map 0 -f segment -list out.list out%03d.nut
-@end example
+@item segment_start_number @var{number}
+Set the sequence number of the first segment. Defaults to @code{0}.
-@section mp3
+@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.
-The MP3 muxer writes a raw MP3 stream with an ID3v2 header at the beginning and
-optionally an ID3v1 tag at the end. ID3v2.3 and ID3v2.4 are supported, the
-@code{id3v2_version} option controls which one is used. The legacy ID3v1 tag is
-not written by default, but may be enabled with the @code{write_id3v1} option.
+@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
-For seekable output the muxer also writes a Xing frame at the beginning, which
-contains the number of frames in the file. It is useful for computing duration
-of VBR files.
+@subsection Examples
-The muxer supports writing ID3v2 attached pictures (APIC frames). The pictures
-are supplied to the muxer in form of a video stream with a single packet. There
-can be any number of those streams, each will correspond to a single APIC frame.
-The stream metadata tags @var{title} and @var{comment} map to APIC
-@var{description} and @var{picture type} respectively. See
-@url{http://id3.org/id3v2.4.0-frames} for allowed picture types.
+@itemize
+@item
+To 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
-Note that the APIC frames must be written at the beginning, so the muxer will
-buffer the audio frames until it gets all the pictures. It is therefore advised
-to provide the pictures as soon as possible to avoid excessive buffering.
+@item
+As the example above, but 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
-Examples:
+@item
+As the example above, but 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.
-Write an mp3 with an ID3v2.3 header and an ID3v1 footer:
+@item
+Segment the input file by splitting the input file according to the
+frame numbers sequence specified with the @option{segment_frames} option:
@example
-avconv -i INPUT -id3v2_version 3 -write_id3v1 1 out.mp3
+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
-Attach a picture to an mp3:
+@item
+To convert the @file{in.mkv} to TS segments using the @code{libx264}
+and @code{libfaac} encoders:
@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 in.mkv -map 0 -codec:v libx264 -codec:a libfaac -f ssegment -segment_list out.list out%03d.ts
@end example
-@section ogg
+@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
-Ogg container muxer.
+@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 the ``Quoting and escaping'' section in the ffmpeg-utils
+manual).
+
+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 -page_duration @var{duration}
-Preferred page duration, in microseconds. The muxer will attempt to create
-pages that are approximately @var{duration} microseconds long. This allows the
-user to compromise between seek granularity and container overhead. The default
-is 1 second. A value of 0 will fill all segments, making pages as large as
-possible. A value of 1 will effectively use 1 packet-per-page in most
-situations, giving a small seek granularity at the cost of additional container
-overhead.
+@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{/}. If the stream specifier is not specified, the
+bistream 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
+Some examples follow.
+@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
+@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.
+
@c man end MUXERS
diff --git a/doc/nut.texi b/doc/nut.texi
index 39a22ff..0026a12 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 Container-specific codec tags
@section Generic raw YUVA formats
@@ -109,6 +113,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 2b8c51b..5a66d6b 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?
@@ -201,7 +201,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..c737225 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,7 +13,7 @@ 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
+The option "-formats" of the ff* tools will display the list of
enabled output devices (amongst the muxers).
A description of the currently available output devices follows.
@@ -22,12 +22,268 @@ A description of the currently available output devices follows.
ALSA (Advanced Linux Sound Architecture) output device.
+@section caca
+
+CACA output device.
+
+This output device allows 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 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 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}.
+
+@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 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.
+Zero is a default.
+@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 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_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.
+
+@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.
+
+@item window_title
+Set the window title, if not specified default to the filename
+specified for the output device.
+@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 2a7dd45..6d01e0e 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,12 +26,12 @@ to configure.
@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
@@ -45,20 +45,21 @@ 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
+Mac OS X on PowerPC or ARM (iPhone) requires a preprocessor from
@url{http://github.com/yuvi/gas-preprocessor} to build the optimized
assembler functions. Just download the Perl script and put it 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 assembler 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 assembler functions. @uref{http://www.finkproject.org/, Fink},
+@uref{http://www.gentoo.org/proj/en/gentoo-alt/prefix/bootstrap-macos.xml, Gentoo Prefix},
+@uref{http://mxcl.github.com/homebrew/, Homebrew}
+or @uref{http://www.macports.org, MacPorts} can easily provide it.
@chapter DOS
@@ -69,15 +70,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
@@ -93,23 +97,24 @@ 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 or ICL using a C99-to-C89 conversion utility and
+FFmpeg can be built with MSVC or ICL using a C99-to-C89 conversion utility and
wrapper. For ICL, only the wrapper is used, since ICL supports C99.
You will need the following prerequisites:
@itemize
-@item @uref{https://github.com/libav/c99-to-c89/, C99-to-C89 Converter & Wrapper}
+@item @uref{http://download.videolan.org/pub/contrib/c99-to-c89/, C99-to-C89 Converter & Wrapper}
@item @uref{http://code.google.com/p/msinttypes/, msinttypes}
@item @uref{http://www.mingw.org/, MSYS}
@item @uref{http://yasm.tortall.net/, YASM}
@@ -165,15 +170,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
@@ -183,7 +188,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
@@ -235,14 +240,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
@@ -260,7 +265,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
@@ -270,7 +275,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
@@ -302,7 +307,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.
@@ -318,7 +323,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.
@@ -356,7 +361,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 1a9f575..3f3844d 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,31 +76,107 @@ 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.
-For example to read from a file @file{input.mpeg} with @command{avconv}
+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
+The ff* 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 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
Gopher protocol.
@@ -89,6 +205,77 @@ m3u8 files.
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.
+
+@item headers
+Set custom HTTP headers, can override built in default headers. The
+value must be a string encoding the headers.
+
+@item content_type
+Force a content type.
+
+@item user-agent
+Override User-Agent header. If not specified the protocol will use a
+string describing the libavformat build.
+
+@item multiple_requests
+Use persistent connections if set to 1. By default it is 0.
+
+@item post_data
+Set custom HTTP post data.
+
+@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 mime_type
+Set MIME type.
+
+@item icy
+If set to 1 request ICY (SHOUTcast) metadata from the server. If the server
+supports this, the metadata has to be retrieved by the application by reading
+the @option{icy_metadata_headers} and @option{icy_metadata_packet} options.
+The default is 0.
+
+@item icy_metadata_headers
+If the server supports ICY metadata, this contains the ICY specific HTTP reply
+headers, separated with newline characters.
+
+@item icy_metadata_packet
+If the server supports ICY metadata, and @option{icy} was set to 1, this
+contains the last non-empty metadata packet sent by the server.
+
+@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.
+@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 mmst
MMS (Microsoft Media Server) protocol over TCP.
@@ -113,10 +300,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
@@ -138,20 +325,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.
@@ -271,16 +468,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
@@ -323,6 +520,38 @@ The Real-Time Messaging Protocol tunneled through HTTPS (RTMPTS) is used
for streaming multimedia content within HTTPS requests to traverse
firewalls.
+@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.
+
+@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
@@ -353,19 +582,82 @@ 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
@@ -383,7 +675,7 @@ The required syntax for a RTSP url is:
rtsp://@var{hostname}[:@var{port}]/@var{path}
@end example
-The following options (set on the @command{avconv}/@command{avplay} command
+The following options (set on the @command{ffmpeg}/@command{ffplay} command
line, or set in code via @code{AVOption}s or in @code{avformat_open_input}),
are supported:
@@ -424,7 +716,7 @@ 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}.
@@ -434,27 +726,32 @@ Example command lines:
To 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:
@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:
@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:
@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
+@table @option
+@item stimeout
+Socket IO timeout in micro seconds.
+@end table
+
@section sap
Session Announcement Protocol (RFC 2974). This is not technically a
@@ -504,19 +801,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
@@ -538,15 +835,59 @@ 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 tcp
Trasmission Control Protocol.
@@ -561,9 +902,14 @@ tcp://@var{hostname}:@var{port}[?@var{options}]
@item listen
Listen for an incoming connection
+@item timeout=@var{microseconds}
+In read mode: if no data arrived in more than this time interval, raise error.
+In write mode: if socket cannot be written in more than this time interval, raise error.
+This also sets timeout on TCP connection establishing.
+
@example
-avconv -i @var{input} -f @var{format} tcp://@var{hostname}:@var{port}?listen
-avplay tcp://@var{hostname}:@var{port}
+ffmpeg -i @var{input} -f @var{format} tcp://@var{hostname}:@var{port}?listen
+ffplay tcp://@var{hostname}:@var{port}
@end example
@end table
@@ -572,9 +918,9 @@ avplay tcp://@var{hostname}:@var{port}
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
@@ -582,11 +928,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.
@@ -599,13 +946,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}
@@ -614,6 +961,20 @@ 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.
@@ -624,15 +985,22 @@ 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.
+
+In case threading is enabled on the system, a circular buffer is used
+to store the incoming data, which allows 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 socket buffer size in bytes. This is used both for the
+receiving and the sending buffer 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
@@ -640,13 +1008,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
@@ -666,23 +1034,34 @@ 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}
+In read mode: if no data arrived in more than this time interval, raise error.
@end table
-Some usage examples of the udp protocol with @command{avconv} follow.
+Some usage examples of the UDP protocol with @command{ffmpeg} follow.
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:
@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:
@example
-avconv -i udp://[@var{multicast-address}]:@var{port}
+ffmpeg -i udp://[@var{multicast-address}]:@var{port}
@end example
@section unix
diff --git a/doc/resampler.texi b/doc/resampler.texi
new file mode 100644
index 0000000..f9eef03
--- a/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..08d90bc
--- a/dev/null
+++ b/doc/scaler.texi
@@ -0,0 +1,119 @@
+@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 bicubiclin
+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
+@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..080a33b
--- a/dev/null
+++ b/doc/snow.txt
@@ -0,0 +1,638 @@
+=============================================
+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?
+the MV median predictor is patented IIRC
+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
index 89728b5..2504dba 100644
--- a/doc/soc.txt
+++ b/doc/soc.txt
@@ -8,9 +8,9 @@ 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
+that is to improve FFmpeg, to reach this goal, code must
* conform to the development policy and patch submission guidelines
-* must improve Libav somehow (faster, smaller, "better",
+* must improve FFmpeg somehow (faster, smaller, "better",
more codecs supported, fewer bugs, cleaner, ...)
for mentors and other developers to help students to reach that goal it is
@@ -20,5 +20,5 @@ easy reviewable that again leads us to:
* 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).
+ FFmpeg, individual changes were generally not reviewable due to cosmetics).
* frequent commits, so that comments can be provided early
diff --git a/doc/swresample.txt b/doc/swresample.txt
new file mode 100644
index 0000000..2d192a3
--- a/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..e7760f4 100644
--- a/doc/t2h.init
+++ b/doc/t2h.init
@@ -1,6 +1,6 @@
# no horiz rules between sections
-$end_section = \&Libav_end_section;
-sub Libav_end_section($$)
+$end_section = \&FFmpeg_end_section;
+sub FFmpeg_end_section($$)
{
}
@@ -8,132 +8,16 @@ $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;
-}
-
-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;
-}
-
-.alert-danger,
-.alert-error {
- background-color: #f2dede;
- border-color: #eed3d7;
- color: #b94a48;
-}
-.alert-info {
- background-color: #d9edf7;
- border-color: #bce8f1;
- color: #3a87ad;
-}
-
-ul.toc {
- list-style-type: none;
-}
--->
-</style>
+$CSS_LINES = $ENV{"FFMPEG_CSS"} || <<EOT;
+<link rel="stylesheet" type="text/css" href="default.css" />
EOT
-my $TEMPLATE_HEADER = $ENV{"LIBAV_HEADER"} || <<EOT;
+my $TEMPLATE_HEADER = $ENV{"FFMPEG_HEADER"} || <<EOT;
<link rel="icon" href="favicon.png" type="image/png" />
</head>
<body>
-<div class="container">
+<div id="container">
+<div id="body">
EOT
$PRE_BODY_CLOSE = '</div></div>';
@@ -141,20 +25,20 @@ $PRE_BODY_CLOSE = '</div></div>';
$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 +65,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,7 +79,7 @@ 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>
@@ -209,8 +93,6 @@ $Texi2HTML::THISDOC{program_authors}
$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
@@ -218,6 +100,9 @@ $TEMPLATE_HEADER
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/texi2pod.pl b/doc/texi2pod.pl
index 96d967b..610f349 100755
--- a/doc/texi2pod.pl
+++ b/doc/texi2pod.pl
@@ -1,4 +1,4 @@
-#! /usr/bin/perl -w
+#! /usr/bin/perl
# Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
@@ -23,11 +23,13 @@
# markup to Perl POD format. It's intended to be used to extract
# something suitable for a manpage from a Texinfo document.
+use warnings;
+
$output = 0;
$skipping = 0;
-%sects = ();
-@sects_sequence = ();
-$section = "";
+%chapters = ();
+@chapters_sequence = ();
+$chapter = "";
@icstack = ();
@endwstack = ();
@skstack = ();
@@ -114,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;
@@ -148,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)$/) {
@@ -188,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;
};
@@ -209,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())
@@ -267,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/;
@@ -294,7 +301,7 @@ INF: while(<$inf>) {
$columns =~ s/\@tab/ : /;
$_ = " : ". $columns;
- $section =~ s/\n+\s+$//;
+ $chapter =~ s/\n+\s+$//;
};
/^\@itemx?\s*(.+)?$/ and do {
@@ -308,7 +315,7 @@ INF: while(<$inf>) {
}
};
- $section .= $shift.$_."\n";
+ $chapter .= $shift.$_."\n";
}
# End of current file.
close($inf);
@@ -317,16 +324,15 @@ $inf = pop @instack;
die "No filename or title\n" unless defined $fn && defined $tl;
-$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";
}
}
@@ -371,6 +377,7 @@ sub postprocess
s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g;
s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g;
s/;\s+\@pxref\{(?:[^\}]*)\}//g;
+ s/\@ref\{(?:[^,\}]*,)(?:[^,\}]*,)([^,\}]*).*\}/$1/g;
s/\@ref\{([^\}]*)\}/$1/g;
s/\@noindent\s*//g;
s/\@refill//g;
@@ -380,7 +387,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;
@@ -424,13 +431,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/utils.texi b/doc/utils.texi
new file mode 100644
index 0000000..9377139
--- a/dev/null
+++ b/doc/utils.texi
@@ -0,0 +1,1064 @@
+@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 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
+
+@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{av_opencl_get_device_list()}.
+
+@item device_idx
+Select the index of the device used to run OpenCL code.
+
+The specifed index must be one of the indexes in the device list which
+can be obtained with @code{av_opencl_get_device_list()}.
+
+@end table
+
+@c man end OPENCL OPTIONS
diff --git a/ffmpeg.c b/ffmpeg.c
new file mode 100644
index 0000000..24b6bec
--- a/dev/null
+++ b/ffmpeg.c
@@ -0,0 +1,3457 @@
+/*
+ * 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>
+#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 "libswscale/swscale.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 "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 int64_t video_size = 0;
+static int64_t audio_size = 0;
+static int64_t subtitle_size = 0;
+static int64_t extra_size = 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;
+
+#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 "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 * 1000,
+ AV_TIME_BASE_Q, ist->st->time_base);
+ end_pts = av_rescale_q(sub->pts + sub->end_display_time * 1000,
+ 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->st->codec, 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, substracting 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;
+
+ for (i = 0; i < ist->nb_filters; i++)
+ av_buffersrc_add_ref(ist->filters[i]->filter, NULL, 0);
+}
+
+/* end of sub2video hack */
+
+void term_exit(void)
+{
+ av_log(NULL, AV_LOG_QUIET, "%s", "");
+#if HAVE_TERMIOS_H
+ if(restore_tty)
+ tcsetattr (0, TCSANOW, &oldtty);
+#endif
+}
+
+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();
+ if(received_nb_signals > 3)
+ exit_program(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 > 1;
+}
+
+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++) {
+ avfilter_graph_free(&filtergraphs[i]->graph);
+ for (j = 0; j < filtergraphs[i]->nb_inputs; j++) {
+ av_freep(&filtergraphs[i]->inputs[j]->name);
+ av_freep(&filtergraphs[i]->inputs[j]);
+ }
+ av_freep(&filtergraphs[i]->inputs);
+ for (j = 0; j < filtergraphs[i]->nb_outputs; j++) {
+ av_freep(&filtergraphs[i]->outputs[j]->name);
+ av_freep(&filtergraphs[i]->outputs[j]);
+ }
+ av_freep(&filtergraphs[i]->outputs);
+ av_freep(&filtergraphs[i]->graph_desc);
+ av_freep(&filtergraphs[i]);
+ }
+ av_freep(&filtergraphs);
+
+ av_freep(&subtitle_out);
+
+ /* close files */
+ for (i = 0; i < nb_output_files; i++) {
+ AVFormatContext *s = output_files[i]->ctx;
+ if (s && s->oformat && !(s->oformat->flags & AVFMT_NOFILE) && s->pb)
+ avio_close(s->pb);
+ avformat_free_context(s);
+ av_dict_free(&output_files[i]->opts);
+ av_freep(&output_files[i]);
+ }
+ for (i = 0; i < nb_output_streams; i++) {
+ AVBitStreamFilterContext *bsfc = output_streams[i]->bitstream_filters;
+ while (bsfc) {
+ AVBitStreamFilterContext *next = bsfc->next;
+ av_bitstream_filter_close(bsfc);
+ bsfc = next;
+ }
+ output_streams[i]->bitstream_filters = NULL;
+ avcodec_free_frame(&output_streams[i]->filtered_frame);
+
+ av_parser_close(output_streams[i]->parser);
+
+ av_freep(&output_streams[i]->forced_keyframes);
+ av_expr_free(output_streams[i]->forced_keyframes_pexpr);
+ av_freep(&output_streams[i]->avfilter);
+ av_freep(&output_streams[i]->logfile_prefix);
+ 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++) {
+ av_frame_free(&input_streams[i]->decoded_frame);
+ av_frame_free(&input_streams[i]->filter_frame);
+ av_dict_free(&input_streams[i]->opts);
+ avsubtitle_free(&input_streams[i]->prev_sub.subtitle);
+ av_frame_free(&input_streams[i]->sub2video.frame);
+ av_freep(&input_streams[i]->filters);
+ 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);
+ }
+ term_exit();
+}
+
+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 write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
+{
+ AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
+ AVCodecContext *avctx = ost->st->codec;
+ int ret;
+
+ 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++;
+ }
+
+ 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) {
+ 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) &&
+ (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;
+
+ 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->st->codec->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);
+ exit_program(1);
+ }
+}
+
+static void close_output_stream(OutputStream *ost)
+{
+ OutputFile *of = output_files[ost->file_index];
+
+ ost->finished = 1;
+ if (of->shortest) {
+ int64_t end = av_rescale_q(ost->sync_opts - ost->first_pts, ost->st->codec->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->st->codec->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->st->codec;
+ 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;
+
+ av_assert0(pkt.size || !pkt.data);
+ update_benchmark(NULL);
+ 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) {
+ if (pkt.pts != AV_NOPTS_VALUE)
+ pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
+ if (pkt.dts != AV_NOPTS_VALUE)
+ pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base);
+ if (pkt.duration > 0)
+ pkt.duration = av_rescale_q(pkt.duration, 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));
+ }
+
+ audio_size += pkt.size;
+ write_frame(s, &pkt, ost);
+
+ av_free_packet(&pkt);
+ }
+}
+
+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->st->codec;
+
+ 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++) {
+ 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;
+ 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);
+ 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;
+ }
+ subtitle_size += pkt.size;
+ 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->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)
+ format_video_sync = (s->oformat->flags & AVFMT_VARIABLE_FPS) ? ((s->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH : VSYNC_VFR) : VSYNC_CFR;
+
+ switch (format_video_sync) {
+ 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, "*** drop!\n");
+ 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. */
+ enc->coded_frame->interlaced_frame = in_picture->interlaced_frame;
+ enc->coded_frame->top_field_first = in_picture->top_field_first;
+ if (enc->coded_frame->interlaced_frame)
+ enc->field_order = enc->coded_frame->top_field_first ? AV_FIELD_TB:AV_FIELD_BT;
+ else
+ 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;
+
+ video_size += pkt.size;
+ write_frame(s, &pkt, ost);
+ } else {
+ int got_packet, forced_keyframe = 0;
+ double pts_time;
+
+ if (ost->st->codec->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)
+ enc->field_order = in_picture->top_field_first ? AV_FIELD_TT:AV_FIELD_BB;
+ else
+ enc->field_order = in_picture->top_field_first ? AV_FIELD_TB:AV_FIELD_BT;
+ } else
+ enc->field_order = AV_FIELD_PROGRESSIVE;
+
+ in_picture->quality = ost->st->codec->global_quality;
+ if (!enc->me_threshold)
+ 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);
+ 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 (pkt.pts == AV_NOPTS_VALUE && !(enc->codec->capabilities & CODEC_CAP_DELAY))
+ pkt.pts = ost->sync_opts;
+
+ if (pkt.pts != AV_NOPTS_VALUE)
+ pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
+ if (pkt.dts != AV_NOPTS_VALUE)
+ pkt.dts = av_rescale_q(pkt.dts, 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;
+ video_size += pkt.size;
+ write_frame(s, &pkt, ost);
+ av_free_packet(&pkt);
+
+ /* 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->st->codec;
+ 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 = ost->st->pts.val * 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)(video_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)video_size / 1024, ti1, bitrate, avg_bitrate);
+ fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(enc->coded_frame->pict_type));
+ }
+}
+
+/**
+ * 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];
+ int ret = 0;
+
+ if (!ost->filter)
+ continue;
+
+ if (!ost->filtered_frame && !(ost->filtered_frame = avcodec_alloc_frame())) {
+ return AVERROR(ENOMEM);
+ } else
+ avcodec_get_frame_defaults(ost->filtered_frame);
+ filtered_frame = ost->filtered_frame;
+
+ while (1) {
+ ret = av_buffersink_get_frame_flags(ost->filter->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;
+ }
+ 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,
+ ost->filter->filter->inputs[0]->time_base,
+ ost->st->codec->time_base) -
+ av_rescale_q(start_time,
+ AV_TIME_BASE_Q,
+ ost->st->codec->time_base);
+ }
+ //if (ost->source_index >= 0)
+ // *filtered_frame= *input_streams[ost->source_index]->decoded_frame; //for me_threshold
+
+
+ switch (ost->filter->filter->inputs[0]->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ filtered_frame->pts = frame_pts;
+ if (!ost->frame_aspect_ratio.num)
+ ost->st->codec->sample_aspect_ratio = filtered_frame->sample_aspect_ratio;
+
+ do_video_out(of->ctx, ost, filtered_frame);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ filtered_frame->pts = frame_pts;
+ if (!(ost->st->codec->codec->capabilities & CODEC_CAP_PARAM_CHANGE) &&
+ ost->st->codec->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_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->st->codec;
+ 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 ((is_last_report || !ost->finished) && ost->st->pts.val != AV_NOPTS_VALUE)
+ pts = FFMAX(pts, av_rescale_q(ost->st->pts.val,
+ 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) {
+ int64_t raw= audio_size + video_size + subtitle_size + extra_size;
+ av_log(NULL, AV_LOG_INFO, "\n");
+ av_log(NULL, AV_LOG_INFO, "video:%1.0fkB audio:%1.0fkB subtitle:%1.0f global headers:%1.0fkB muxing overhead %f%%\n",
+ video_size / 1024.0,
+ audio_size / 1024.0,
+ subtitle_size / 1024.0,
+ extra_size / 1024.0,
+ 100.0 * (total_size - raw) / raw
+ );
+ if(video_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 flush_encoders(void)
+{
+ int i, ret;
+
+ for (i = 0; i < nb_output_streams; i++) {
+ OutputStream *ost = output_streams[i];
+ AVCodecContext *enc = ost->st->codec;
+ AVFormatContext *os = output_files[ost->file_index]->ctx;
+ int stop_encoding = 0;
+
+ if (!ost->encoding_needed)
+ continue;
+
+ if (ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1)
+ continue;
+ if (ost->st->codec->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;
+ int64_t *size;
+
+ switch (ost->st->codec->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ encode = avcodec_encode_audio2;
+ desc = "Audio";
+ size = &audio_size;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ encode = avcodec_encode_video2;
+ desc = "Video";
+ size = &video_size;
+ break;
+ default:
+ stop_encoding = 1;
+ }
+
+ if (encode) {
+ AVPacket pkt;
+ 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);
+ }
+ *size += pkt.size;
+ if (ost->logfile && enc->stats_out) {
+ fprintf(ost->logfile, "%s", enc->stats_out);
+ }
+ if (!got_packet) {
+ stop_encoding = 1;
+ break;
+ }
+ if (pkt.pts != AV_NOPTS_VALUE)
+ pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
+ if (pkt.dts != AV_NOPTS_VALUE)
+ pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base);
+ if (pkt.duration > 0)
+ pkt.duration = av_rescale_q(pkt.duration, enc->time_base, ost->st->time_base);
+ write_frame(os, &pkt, ost);
+ if (ost->st->codec->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 (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->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ audio_size += pkt->size;
+ else if (ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ video_size += pkt->size;
+ ost->sync_opts++;
+ } else if (ost->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+ subtitle_size += pkt->size;
+ }
+
+ 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->st->codec, pkt->size);
+ if(!duration)
+ duration = ist->st->codec->frame_size;
+ opkt.dts = opkt.pts = av_rescale_delta(ist->st->time_base, pkt->dts,
+ (AVRational){1, ist->st->codec->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->st->codec->codec_id != AV_CODEC_ID_H264
+ && ost->st->codec->codec_id != AV_CODEC_ID_MPEG1VIDEO
+ && ost->st->codec->codec_id != AV_CODEC_ID_MPEG2VIDEO
+ && ost->st->codec->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;
+ }
+
+ 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);
+ ost->st->codec->frame_number++;
+}
+
+int guess_input_channel_layout(InputStream *ist)
+{
+ AVCodecContext *dec = ist->st->codec;
+
+ 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->st->codec;
+ int i, ret, err = 0, resample_changed;
+ AVRational decoded_frame_tb;
+
+ if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame()))
+ 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;
+ }
+
+#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];
+ int j;
+ if (configure_filtergraph(fg) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
+ exit_program(1);
+ }
+ for (j = 0; j < fg->nb_outputs; j++) {
+ OutputStream *ost = fg->outputs[j]->ost;
+ if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
+ !(ost->enc->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE))
+ av_buffersink_set_frame_size(ost->filter->filter,
+ ost->st->codec->frame_size);
+ }
+ }
+ }
+
+ /* 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;
+ pkt->pts = AV_NOPTS_VALUE;
+ decoded_frame_tb = ist->st->time_base;
+ } else if (pkt->pts != AV_NOPTS_VALUE) {
+ decoded_frame->pts = pkt->pts;
+ pkt->pts = AV_NOPTS_VALUE;
+ decoded_frame_tb = ist->st->time_base;
+ }else {
+ decoded_frame->pts = ist->dts;
+ decoded_frame_tb = AV_TIME_BASE_Q;
+ }
+ if (decoded_frame->pts != AV_NOPTS_VALUE)
+ decoded_frame->pts = av_rescale_delta(decoded_frame_tb, decoded_frame->pts,
+ (AVRational){1, ist->st->codec->sample_rate}, decoded_frame->nb_samples, &ist->filter_in_rescale_delta_last,
+ (AVRational){1, ist->st->codec->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->st->codec,
+ decoded_frame, got_output, pkt);
+ update_benchmark("decode_video %d.%d", ist->file_index, ist->st->index);
+
+ 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;
+
+ 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 \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);
+ }
+
+ 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);
+ }
+ }
+
+ 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->st->codec,
+ &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) {
+ if (ist->prev_sub.got_output) {
+ int 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->st->codec, AV_LOG_DEBUG,
+ "Subtitle duration reduced from %d to %d\n",
+ ist->prev_sub.subtitle.end_display_time, end);
+ 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);
+ }
+
+ sub2video_update(ist, &subtitle);
+
+ if (!*got_output || !subtitle.num_rects)
+ return ret;
+
+ 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);
+ }
+
+ avsubtitle_free(&subtitle);
+ return ret;
+}
+
+/* pkt = NULL means EOF (needed to flush decoder buffers) */
+static int output_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->st->codec->has_b_frames * AV_TIME_BASE / av_q2d(ist->st->avg_frame_rate) : 0;
+ ist->pts = 0;
+ if (pkt != NULL && 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 == NULL) {
+ /* 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->st->codec->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) {
+ 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->st->codec->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->st->codec->time_base.num != 0 && ist->st->codec->time_base.den != 0) {
+ int ticks= ist->st->parser ? ist->st->parser->repeat_pict+1 : ist->st->codec->ticks_per_frame;
+ duration = ((int64_t)AV_TIME_BASE *
+ ist->st->codec->time_base.num * ticks) /
+ ist->st->codec->time_base.den;
+ } 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->st->codec->codec_type != AVMEDIA_TYPE_AUDIO)
+ ret = avpkt.size;
+ avpkt.data += ret;
+ avpkt.size -= ret;
+ }
+ if (!got_output) {
+ continue;
+ }
+ }
+
+ /* handle stream copy */
+ if (!ist->decoding_needed) {
+ ist->dts = ist->next_dts;
+ switch (ist->st->codec->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ ist->next_dts += ((int64_t)AV_TIME_BASE * ist->st->codec->frame_size) /
+ ist->st->codec->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->st->codec->time_base.num != 0) {
+ int ticks= ist->st->parser ? ist->st->parser->repeat_pict + 1 : ist->st->codec->ticks_per_frame;
+ ist->next_dts += ((int64_t)AV_TIME_BASE *
+ ist->st->codec->time_base.num * ticks) /
+ ist->st->codec->time_base.den;
+ }
+ 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 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 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->st->codec->codec_id), ist->file_index, ist->st->index);
+ return AVERROR(EINVAL);
+ }
+
+ av_opt_set_int(ist->st->codec, "refcounted_frames", 1, 0);
+
+ if (!av_dict_get(ist->opts, "threads", NULL, 0))
+ av_dict_set(&ist->opts, "threads", "auto", 0);
+ if ((ret = avcodec_open2(ist->st->codec, codec, &ist->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->opts);
+ }
+
+ ist->next_pts = AV_NOPTS_VALUE;
+ ist->next_dts = AV_NOPTS_VALUE;
+ ist->is_start = 1;
+
+ 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(sizeof(*pts) * size);
+ 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 int transcode_init(void)
+{
+ int ret = 0, i, j, k;
+ AVFormatContext *oc;
+ AVCodecContext *codec;
+ 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();
+ }
+
+ /* 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 *icodec = NULL;
+ ost = output_streams[i];
+ oc = output_files[ost->file_index]->ctx;
+ ist = get_input_stream(ost);
+
+ if (ost->attachment_filename)
+ continue;
+
+ codec = ost->st->codec;
+
+ if (ist) {
+ icodec = ist->st->codec;
+
+ ost->st->disposition = ist->st->disposition;
+ codec->bits_per_raw_sample = icodec->bits_per_raw_sample;
+ codec->chroma_sample_location = icodec->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 == codec->codec_type)
+ break;
+ }
+ if (j == oc->nb_streams)
+ if (codec->codec_type == AVMEDIA_TYPE_AUDIO || codec->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)icodec->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 */
+ codec->codec_id = icodec->codec_id;
+ codec->codec_type = icodec->codec_type;
+
+ if (!codec->codec_tag) {
+ unsigned int codec_tag;
+ if (!oc->oformat->codec_tag ||
+ av_codec_get_id (oc->oformat->codec_tag, icodec->codec_tag) == codec->codec_id ||
+ !av_codec_get_tag2(oc->oformat->codec_tag, icodec->codec_id, &codec_tag))
+ codec->codec_tag = icodec->codec_tag;
+ }
+
+ codec->bit_rate = icodec->bit_rate;
+ codec->rc_max_rate = icodec->rc_max_rate;
+ codec->rc_buffer_size = icodec->rc_buffer_size;
+ codec->field_order = icodec->field_order;
+ codec->extradata = av_mallocz(extra_size);
+ if (!codec->extradata) {
+ return AVERROR(ENOMEM);
+ }
+ memcpy(codec->extradata, icodec->extradata, icodec->extradata_size);
+ codec->extradata_size= icodec->extradata_size;
+ codec->bits_per_coded_sample = icodec->bits_per_coded_sample;
+
+ codec->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(icodec->time_base)
+ && av_q2d(ist->st->time_base) < 1.0/500 && av_q2d(icodec->time_base) < 1.0/500
+ || copy_tb==2){
+ codec->time_base.num = ist->st->r_frame_rate.den;
+ codec->time_base.den = 2*ist->st->r_frame_rate.num;
+ codec->ticks_per_frame = 2;
+ } else if ( copy_tb<0 && av_q2d(icodec->time_base)*icodec->ticks_per_frame > 2*av_q2d(ist->st->time_base)
+ && av_q2d(ist->st->time_base) < 1.0/500
+ || copy_tb==0){
+ codec->time_base = icodec->time_base;
+ codec->time_base.num *= icodec->ticks_per_frame;
+ codec->time_base.den *= 2;
+ codec->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 && icodec->time_base.den
+ && av_q2d(icodec->time_base)*icodec->ticks_per_frame > av_q2d(ist->st->time_base)
+ && av_q2d(ist->st->time_base) < 1.0/500
+ || copy_tb==0){
+ codec->time_base = icodec->time_base;
+ codec->time_base.num *= icodec->ticks_per_frame;
+ }
+ }
+ if ( codec->codec_tag == AV_RL32("tmcd")
+ && icodec->time_base.num < icodec->time_base.den
+ && icodec->time_base.num > 0
+ && 121LL*icodec->time_base.num > icodec->time_base.den) {
+ codec->time_base = icodec->time_base;
+ }
+
+ if (ist && !ost->frame_rate.num)
+ ost->frame_rate = ist->framerate;
+ if(ost->frame_rate.num)
+ codec->time_base = av_inv_q(ost->frame_rate);
+
+ av_reduce(&codec->time_base.num, &codec->time_base.den,
+ codec->time_base.num, codec->time_base.den, INT_MAX);
+
+ ost->parser = av_parser_init(codec->codec_id);
+
+ switch (codec->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);
+ }
+ codec->channel_layout = icodec->channel_layout;
+ codec->sample_rate = icodec->sample_rate;
+ codec->channels = icodec->channels;
+ codec->frame_size = icodec->frame_size;
+ codec->audio_service_type = icodec->audio_service_type;
+ codec->block_align = icodec->block_align;
+ if((codec->block_align == 1 || codec->block_align == 1152 || codec->block_align == 576) && codec->codec_id == AV_CODEC_ID_MP3)
+ codec->block_align= 0;
+ if(codec->codec_id == AV_CODEC_ID_AC3)
+ codec->block_align= 0;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ codec->pix_fmt = icodec->pix_fmt;
+ codec->width = icodec->width;
+ codec->height = icodec->height;
+ codec->has_b_frames = icodec->has_b_frames;
+ if (ost->frame_aspect_ratio.num) { // overridden by the -aspect cli option
+ sar =
+ av_mul_q(ost->frame_aspect_ratio,
+ (AVRational){ codec->height, codec->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 = icodec->sample_aspect_ratio;
+ ost->st->sample_aspect_ratio = codec->sample_aspect_ratio = sar;
+ ost->st->avg_frame_rate = ist->st->avg_frame_rate;
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ codec->width = icodec->width;
+ codec->height = icodec->height;
+ break;
+ case AVMEDIA_TYPE_DATA:
+ case AVMEDIA_TYPE_ATTACHMENT:
+ break;
+ default:
+ abort();
+ }
+ } else {
+ if (!ost->enc)
+ ost->enc = avcodec_find_encoder(codec->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++;
+ ost->encoding_needed = 1;
+
+ if (!ost->filter &&
+ (codec->codec_type == AVMEDIA_TYPE_VIDEO ||
+ codec->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 (codec->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.num ? ist->st->r_frame_rate : (AVRational){25, 1};
+// 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];
+ }
+ }
+
+ switch (codec->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ codec->sample_fmt = ost->filter->filter->inputs[0]->format;
+ codec->sample_rate = ost->filter->filter->inputs[0]->sample_rate;
+ codec->channel_layout = ost->filter->filter->inputs[0]->channel_layout;
+ codec->channels = avfilter_link_get_channels(ost->filter->filter->inputs[0]);
+ codec->time_base = (AVRational){ 1, codec->sample_rate };
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ codec->time_base = av_inv_q(ost->frame_rate);
+ if (ost->filter && !(codec->time_base.num && codec->time_base.den))
+ codec->time_base = ost->filter->filter->inputs[0]->time_base;
+ if ( av_q2d(codec->time_base) < 0.001 && video_sync_method != VSYNC_PASSTHROUGH
+ && (video_sync_method == VSYNC_CFR || (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,
+ codec->time_base);
+
+ codec->width = ost->filter->filter->inputs[0]->w;
+ codec->height = ost->filter->filter->inputs[0]->h;
+ codec->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){ codec->height, codec->width }) :
+ ost->filter->filter->inputs[0]->sample_aspect_ratio;
+ if (!strncmp(ost->enc->name, "libx264", 7) &&
+ codec->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) &&
+ codec->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));
+ codec->pix_fmt = ost->filter->filter->inputs[0]->format;
+
+ if (!icodec ||
+ codec->width != icodec->width ||
+ codec->height != icodec->height ||
+ codec->pix_fmt != icodec->pix_fmt) {
+ codec->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->st->codec);
+ }
+ }
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ codec->time_base = (AVRational){1, 1000};
+ if (!codec->width) {
+ codec->width = input_streams[ost->source_index]->st->codec->width;
+ codec->height = input_streams[ost->source_index]->st->codec->height;
+ }
+ break;
+ default:
+ abort();
+ break;
+ }
+ /* two pass mode */
+ if (codec->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->opts, "stats", logfilename, AV_DICT_DONT_OVERWRITE);
+ } else {
+ if (codec->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);
+ }
+ codec->stats_in = logbuffer;
+ }
+ if (codec->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;
+ }
+ }
+ }
+ }
+ }
+
+ /* 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->st->codec;
+ if (dec && dec->subtitle_header) {
+ /* ASS code assumes this buffer is null terminated so add extra byte. */
+ ost->st->codec->subtitle_header = av_mallocz(dec->subtitle_header_size + 1);
+ if (!ost->st->codec->subtitle_header) {
+ ret = AVERROR(ENOMEM);
+ goto dump_format;
+ }
+ memcpy(ost->st->codec->subtitle_header, dec->subtitle_header, dec->subtitle_header_size);
+ ost->st->codec->subtitle_header_size = dec->subtitle_header_size;
+ }
+ if (!av_dict_get(ost->opts, "threads", NULL, 0))
+ av_dict_set(&ost->opts, "threads", "auto", 0);
+ if ((ret = avcodec_open2(ost->st->codec, codec, &ost->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->st->codec->frame_size);
+ assert_avoptions(ost->opts);
+ if (ost->st->codec->bit_rate && ost->st->codec->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");
+ extra_size += ost->st->codec->extradata_size;
+
+ if (ost->st->codec->me_threshold)
+ input_streams[ost->source_index]->st->codec->debug |= FF_DEBUG_MV;
+ } else {
+ av_opt_set_dict(ost->st->codec, &ost->opts);
+ }
+ }
+
+ /* 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->st->codec);
+ }
+ 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
+ av_log(NULL, AV_LOG_INFO, " (%s -> %s)", input_streams[ost->source_index]->dec ?
+ input_streams[ost->source_index]->dec->name : "?",
+ ost->enc ? ost->enc->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++)
+ 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->unavailable && !ost->finished && opts < opts_min) {
+ opts_min = opts;
+ ost_min = 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->st->codec->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 (!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->dts, 1000000, AV_TIME_BASE);
+ int64_t now = av_gettime() - 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);
+ }
+ ifile->eof_reached = 1;
+
+ for (i = 0; i < ifile->nb_streams; i++) {
+ ist = input_streams[ifile->ist_index + i];
+ if (ist->decoding_needed)
+ output_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))
+ close_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) {
+ report_new_stream(file_index, &pkt);
+ goto discard_packet;
+ }
+
+ ist = input_streams[ifile->ist_index + pkt.stream_index];
+ 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->st->codec->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;
+ }
+ }
+
+ 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 (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 &&
+ ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE)){
+ 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 (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 &&
+ ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||
+ pkt_dts + AV_TIME_BASE/10 < ist->pts){
+ 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 && ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE)
+ ) {
+ 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 && ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE)
+ ) {
+ 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->st->codec->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 = output_packet(ist, &pkt);
+ if (ret < 0) {
+ char buf[128];
+ av_strerror(ret, buf, sizeof(buf));
+ av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
+ ist->file_index, ist->st->index, buf);
+ 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();
+
+#if HAVE_PTHREADS
+ if ((ret = init_input_threads()) < 0)
+ goto fail;
+#endif
+
+ while (!received_sigterm) {
+ int64_t cur_time= av_gettime();
+
+ /* 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) {
+ output_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());
+
+ /* close each encoder */
+ for (i = 0; i < nb_output_streams; i++) {
+ ost = output_streams[i];
+ if (ost->encoding_needed) {
+ av_freep(&ost->st->codec->stats_in);
+ avcodec_close(ost->st->codec);
+ }
+ }
+
+ /* close each decoder */
+ for (i = 0; i < nb_input_streams; i++) {
+ ist = input_streams[i];
+ if (ist->decoding_needed) {
+ avcodec_close(ist->st->codec);
+ }
+ }
+
+ /* 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->stream_copy)
+ av_freep(&ost->st->codec->extradata);
+ if (ost->logfile) {
+ fclose(ost->logfile);
+ ost->logfile = NULL;
+ }
+ av_freep(&ost->st->codec->subtitle_header);
+ av_freep(&ost->forced_kf_pts);
+ av_freep(&ost->apad);
+ av_dict_free(&ost->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();
+#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 : 0);
+ return 0;
+}
diff --git a/ffmpeg.h b/ffmpeg.h
new file mode 100644
index 0000000..c001d2c
--- a/dev/null
+++ b/ffmpeg.h
@@ -0,0 +1,453 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FFMPEG_H
+#define FFMPEG_H
+
+#include "config.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <signal.h>
+
+#if HAVE_PTHREADS
+#include <pthread.h>
+#endif
+
+#include "cmdutils.h"
+
+#include "libavformat/avformat.h"
+#include "libavformat/avio.h"
+
+#include "libavcodec/avcodec.h"
+
+#include "libavfilter/avfilter.h"
+
+#include "libavutil/avutil.h"
+#include "libavutil/dict.h"
+#include "libavutil/eval.h"
+#include "libavutil/fifo.h"
+#include "libavutil/pixfmt.h"
+#include "libavutil/rational.h"
+
+#include "libswresample/swresample.h"
+
+#define VSYNC_AUTO -1
+#define VSYNC_PASSTHROUGH 0
+#define VSYNC_CFR 1
+#define VSYNC_VFR 2
+#define VSYNC_DROP 0xff
+
+#define MAX_STREAMS 1024 /* arbitrary sanity check value */
+
+/* select an input stream for an output stream */
+typedef struct StreamMap {
+ int disabled; /* 1 is this mapping is disabled by a negative map */
+ int file_index;
+ int stream_index;
+ int sync_file_index;
+ int sync_stream_index;
+ char *linklabel; /* name of an output link, for mapping lavfi outputs */
+} StreamMap;
+
+typedef struct {
+ int file_idx, stream_idx, channel_idx; // input
+ int ofile_idx, ostream_idx; // output
+} AudioChannelMap;
+
+typedef struct OptionsContext {
+ OptionGroup *g;
+
+ /* input/output options */
+ int64_t start_time;
+ const char *format;
+
+ SpecifierOpt *codec_names;
+ int nb_codec_names;
+ SpecifierOpt *audio_channels;
+ int nb_audio_channels;
+ SpecifierOpt *audio_sample_rate;
+ int nb_audio_sample_rate;
+ SpecifierOpt *frame_rates;
+ int nb_frame_rates;
+ SpecifierOpt *frame_sizes;
+ int nb_frame_sizes;
+ SpecifierOpt *frame_pix_fmts;
+ int nb_frame_pix_fmts;
+
+ /* input options */
+ int64_t input_ts_offset;
+ int rate_emu;
+ int accurate_seek;
+
+ SpecifierOpt *ts_scale;
+ int nb_ts_scale;
+ SpecifierOpt *dump_attachment;
+ int nb_dump_attachment;
+
+ /* output options */
+ StreamMap *stream_maps;
+ int nb_stream_maps;
+ AudioChannelMap *audio_channel_maps; /* one info entry per -map_channel */
+ int nb_audio_channel_maps; /* number of (valid) -map_channel settings */
+ int metadata_global_manual;
+ int metadata_streams_manual;
+ int metadata_chapters_manual;
+ const char **attachments;
+ int nb_attachments;
+
+ int chapters_input_file;
+
+ int64_t recording_time;
+ int64_t stop_time;
+ uint64_t limit_filesize;
+ float mux_preload;
+ float mux_max_delay;
+ int shortest;
+
+ int video_disable;
+ int audio_disable;
+ int subtitle_disable;
+ int data_disable;
+
+ /* indexed by output file stream index */
+ int *streamid_map;
+ int nb_streamid_map;
+
+ SpecifierOpt *metadata;
+ int nb_metadata;
+ SpecifierOpt *max_frames;
+ int nb_max_frames;
+ SpecifierOpt *bitstream_filters;
+ int nb_bitstream_filters;
+ SpecifierOpt *codec_tags;
+ int nb_codec_tags;
+ SpecifierOpt *sample_fmts;
+ int nb_sample_fmts;
+ SpecifierOpt *qscale;
+ int nb_qscale;
+ SpecifierOpt *forced_key_frames;
+ int nb_forced_key_frames;
+ SpecifierOpt *force_fps;
+ int nb_force_fps;
+ SpecifierOpt *frame_aspect_ratios;
+ int nb_frame_aspect_ratios;
+ SpecifierOpt *rc_overrides;
+ int nb_rc_overrides;
+ SpecifierOpt *intra_matrices;
+ int nb_intra_matrices;
+ SpecifierOpt *inter_matrices;
+ int nb_inter_matrices;
+ SpecifierOpt *top_field_first;
+ int nb_top_field_first;
+ SpecifierOpt *metadata_map;
+ int nb_metadata_map;
+ SpecifierOpt *presets;
+ int nb_presets;
+ SpecifierOpt *copy_initial_nonkeyframes;
+ int nb_copy_initial_nonkeyframes;
+ SpecifierOpt *copy_prior_start;
+ int nb_copy_prior_start;
+ SpecifierOpt *filters;
+ int nb_filters;
+ SpecifierOpt *filter_scripts;
+ int nb_filter_scripts;
+ SpecifierOpt *reinit_filters;
+ int nb_reinit_filters;
+ SpecifierOpt *fix_sub_duration;
+ int nb_fix_sub_duration;
+ SpecifierOpt *canvas_sizes;
+ int nb_canvas_sizes;
+ SpecifierOpt *pass;
+ int nb_pass;
+ SpecifierOpt *passlogfiles;
+ int nb_passlogfiles;
+ SpecifierOpt *guess_layout_max;
+ int nb_guess_layout_max;
+ SpecifierOpt *apad;
+ int nb_apad;
+} OptionsContext;
+
+typedef struct InputFilter {
+ AVFilterContext *filter;
+ struct InputStream *ist;
+ struct FilterGraph *graph;
+ uint8_t *name;
+} InputFilter;
+
+typedef struct OutputFilter {
+ AVFilterContext *filter;
+ struct OutputStream *ost;
+ struct FilterGraph *graph;
+ uint8_t *name;
+
+ /* temporary storage until stream maps are processed */
+ AVFilterInOut *out_tmp;
+} OutputFilter;
+
+typedef struct FilterGraph {
+ int index;
+ const char *graph_desc;
+
+ AVFilterGraph *graph;
+ int reconfiguration;
+
+ InputFilter **inputs;
+ int nb_inputs;
+ OutputFilter **outputs;
+ int nb_outputs;
+} FilterGraph;
+
+typedef struct InputStream {
+ int file_index;
+ AVStream *st;
+ int discard; /* true if stream data should be discarded */
+ int decoding_needed; /* true if the packets must be decoded in 'raw_fifo' */
+ AVCodec *dec;
+ AVFrame *decoded_frame;
+ AVFrame *filter_frame; /* a ref of decoded_frame, to be sent to filters */
+
+ int64_t start; /* time when read started */
+ /* predicted dts of the next packet read for this stream or (when there are
+ * several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */
+ int64_t next_dts;
+ int64_t dts; ///< dts of the last packet read for this stream (in AV_TIME_BASE units)
+
+ int64_t next_pts; ///< synthetic pts for the next decode frame (in AV_TIME_BASE units)
+ int64_t pts; ///< current pts of the decoded frame (in AV_TIME_BASE units)
+ int wrap_correction_done;
+
+ int64_t filter_in_rescale_delta_last;
+
+ double ts_scale;
+ int is_start; /* is 1 at the start and after a discontinuity */
+ int saw_first_ts;
+ int showed_multi_packet_warning;
+ AVDictionary *opts;
+ AVRational framerate; /* framerate forced with -r */
+ int top_field_first;
+ int guess_layout_max;
+
+ int resample_height;
+ int resample_width;
+ int resample_pix_fmt;
+
+ int resample_sample_fmt;
+ int resample_sample_rate;
+ int resample_channels;
+ uint64_t resample_channel_layout;
+
+ int fix_sub_duration;
+ struct { /* previous decoded subtitle and related variables */
+ int got_output;
+ int ret;
+ AVSubtitle subtitle;
+ } prev_sub;
+
+ struct sub2video {
+ int64_t last_pts;
+ int64_t end_pts;
+ AVFrame *frame;
+ int w, h;
+ } sub2video;
+
+ int dr1;
+
+ /* decoded data from this stream goes into all those filters
+ * currently video and audio only */
+ InputFilter **filters;
+ int nb_filters;
+
+ int reinit_filters;
+} InputStream;
+
+typedef struct InputFile {
+ AVFormatContext *ctx;
+ int eof_reached; /* true if eof reached */
+ int eagain; /* true if last read attempt returned EAGAIN */
+ int ist_index; /* index of first stream in input_streams */
+ int64_t 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 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
+ pthread_t thread; /* thread reading from this file */
+ int finished; /* the thread has exited */
+ int joined; /* the thread has been joined */
+ pthread_mutex_t fifo_lock; /* lock for access to fifo */
+ pthread_cond_t fifo_cond; /* the main thread will signal on this cond after reading from fifo */
+ AVFifoBuffer *fifo; /* demuxed packets are stored here; freed by the main thread */
+#endif
+} InputFile;
+
+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 struct OutputStream {
+ int file_index; /* file index */
+ int index; /* stream index in the output file */
+ int source_index; /* InputStream index */
+ AVStream *st; /* stream in the output file */
+ int encoding_needed; /* true if encoding needed for this stream */
+ int frame_number;
+ /* input pts and corresponding output pts
+ for A/V sync */
+ struct InputStream *sync_ist; /* input stream to sync against */
+ int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ // FIXME look at frame_number
+ /* pts of the first frame encoded for this stream, used for limiting
+ * recording time */
+ int64_t first_pts;
+ /* dts of the last packet sent to the muxer */
+ int64_t last_mux_dts;
+ AVBitStreamFilterContext *bitstream_filters;
+ AVCodec *enc;
+ int64_t max_frames;
+ AVFrame *filtered_frame;
+
+ /* video only */
+ AVRational frame_rate;
+ int force_fps;
+ int top_field_first;
+
+ 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[SWR_CH_MAX]; /* 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;
+
+ int64_t sws_flags;
+ AVDictionary *opts;
+ AVDictionary *swr_opts;
+ AVDictionary *resample_opts;
+ char *apad;
+ int 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;
+
+ int keep_pix_fmt;
+
+ AVCodecParserContext *parser;
+} OutputStream;
+
+typedef struct OutputFile {
+ AVFormatContext *ctx;
+ AVDictionary *opts;
+ int ost_index; /* index of the first stream in output_streams */
+ int64_t recording_time; ///< desired length of the resulting file in microseconds == AV_TIME_BASE units
+ int64_t start_time; ///< start time in microseconds == AV_TIME_BASE units
+ uint64_t limit_filesize; /* filesize limit expressed in bytes */
+
+ int shortest;
+} OutputFile;
+
+extern InputStream **input_streams;
+extern int nb_input_streams;
+extern InputFile **input_files;
+extern int nb_input_files;
+
+extern OutputStream **output_streams;
+extern int nb_output_streams;
+extern OutputFile **output_files;
+extern int nb_output_files;
+
+extern FilterGraph **filtergraphs;
+extern int nb_filtergraphs;
+
+extern char *vstats_filename;
+
+extern 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 const AVIOInterruptCB int_cb;
+
+extern const OptionDef options[];
+
+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 assert_avoptions(AVDictionary *m);
+
+int guess_input_channel_layout(InputStream *ist);
+
+enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodec *codec, enum AVPixelFormat target);
+void choose_sample_fmt(AVStream *st, AVCodec *codec);
+
+int configure_filtergraph(FilterGraph *fg);
+int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out);
+int ist_in_filtergraph(FilterGraph *fg, InputStream *ist);
+FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost);
+
+int ffmpeg_parse_options(int argc, char **argv);
+
+#endif /* FFMPEG_H */
diff --git a/ffmpeg_filter.c b/ffmpeg_filter.c
new file mode 100644
index 0000000..461cc90
--- a/dev/null
+++ b/ffmpeg_filter.c
@@ -0,0 +1,925 @@
+/*
+ * ffmpeg filter configuration
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "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, 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;
+ if (st->codec->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
+ if (st->codec->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 (st->codec->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++) {
+ 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->opts, "strict", NULL, 0);
+ if (strict_dict)
+ // used by choose_pixel_fmt() and below
+ av_opt_set(ost->st->codec, "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->st->codec->pix_fmt == AV_PIX_FMT_NONE)
+ return NULL;
+ return av_strdup(av_get_pix_fmt_name(ost->st->codec->pix_fmt));
+ }
+ if (ost->st->codec->pix_fmt != AV_PIX_FMT_NONE) {
+ return av_strdup(av_get_pix_fmt_name(choose_pixel_fmt(ost->st, ost->enc, ost->st->codec->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->st->codec->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
+ if (ost->st->codec->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->st->codec->codec_id == AV_CODEC_ID_LJPEG) {
+ p = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE };
+ }
+ }
+
+ for (; *p != AV_PIX_FMT_NONE; p++) {
+ const char *name = av_get_pix_fmt_name(*p);
+ avio_printf(s, "%s|", name);
+ }
+ len = avio_close_dyn_buf(s, &ret);
+ ret[len - 1] = 0;
+ return ret;
+ } else
+ return NULL;
+}
+
+/* Define a function for building a string containing a list of
+ * allowed formats. */
+#define DEF_CHOOSE_FORMAT(type, var, supported_list, none, get_name) \
+static char *choose_ ## var ## s(OutputStream *ost) \
+{ \
+ if (ost->st->codec->var != none) { \
+ get_name(ost->st->codec->var); \
+ return av_strdup(name); \
+ } else if (ost->enc && ost->enc->supported_list) { \
+ const type *p; \
+ AVIOContext *s = NULL; \
+ uint8_t *ret; \
+ int len; \
+ \
+ if (avio_open_dyn_buf(&s) < 0) \
+ exit_program(1); \
+ \
+ for (p = ost->enc->supported_list; *p != none; p++) { \
+ get_name(*p); \
+ avio_printf(s, "%s|", name); \
+ } \
+ len = avio_close_dyn_buf(s, &ret); \
+ ret[len - 1] = 0; \
+ return ret; \
+ } else \
+ return NULL; \
+}
+
+// DEF_CHOOSE_FORMAT(enum AVPixelFormat, pix_fmt, pix_fmts, AV_PIX_FMT_NONE,
+// GET_PIX_FMT_NAME)
+
+DEF_CHOOSE_FORMAT(enum AVSampleFormat, sample_fmt, sample_fmts,
+ AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME)
+
+DEF_CHOOSE_FORMAT(int, sample_rate, supported_samplerates, 0,
+ GET_SAMPLE_RATE_NAME)
+
+DEF_CHOOSE_FORMAT(uint64_t, channel_layout, channel_layouts, 0,
+ GET_CH_LAYOUT_NAME)
+
+FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
+{
+ FilterGraph *fg = av_mallocz(sizeof(*fg));
+
+ if (!fg)
+ exit_program(1);
+ fg->index = nb_filtergraphs;
+
+ GROW_ARRAY(fg->outputs, fg->nb_outputs);
+ if (!(fg->outputs[0] = av_mallocz(sizeof(*fg->outputs[0]))))
+ exit_program(1);
+ fg->outputs[0]->ost = ost;
+ fg->outputs[0]->graph = fg;
+
+ ost->filter = fg->outputs[0];
+
+ GROW_ARRAY(fg->inputs, fg->nb_inputs);
+ if (!(fg->inputs[0] = av_mallocz(sizeof(*fg->inputs[0]))))
+ exit_program(1);
+ fg->inputs[0]->ist = ist;
+ fg->inputs[0]->graph = fg;
+
+ GROW_ARRAY(ist->filters, ist->nb_filters);
+ ist->filters[ist->nb_filters - 1] = fg->inputs[0];
+
+ GROW_ARRAY(filtergraphs, nb_filtergraphs);
+ filtergraphs[nb_filtergraphs - 1] = fg;
+
+ return fg;
+}
+
+static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
+{
+ InputStream *ist = NULL;
+ enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
+ int i;
+
+ // TODO: support other filter types
+ if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
+ av_log(NULL, AV_LOG_FATAL, "Only video and audio filters supported "
+ "currently.\n");
+ exit_program(1);
+ }
+
+ if (in->name) {
+ AVFormatContext *s;
+ AVStream *st = NULL;
+ char *p;
+ int file_idx = strtol(in->name, &p, 0);
+
+ if (file_idx < 0 || file_idx >= nb_input_files) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtergraph description %s.\n",
+ file_idx, fg->graph_desc);
+ exit_program(1);
+ }
+ s = input_files[file_idx]->ctx;
+
+ for (i = 0; i < s->nb_streams; i++) {
+ enum AVMediaType stream_type = s->streams[i]->codec->codec_type;
+ if (stream_type != type &&
+ !(stream_type == AVMEDIA_TYPE_SUBTITLE &&
+ type == AVMEDIA_TYPE_VIDEO /* sub2video hack */))
+ continue;
+ if (check_stream_specifier(s, s->streams[i], *p == ':' ? p + 1 : p) == 1) {
+ st = s->streams[i];
+ break;
+ }
+ }
+ if (!st) {
+ av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s "
+ "matches no streams.\n", p, fg->graph_desc);
+ exit_program(1);
+ }
+ ist = input_streams[input_files[file_idx]->ist_index + st->index];
+ } else {
+ /* find the first unused stream of corresponding type */
+ for (i = 0; i < nb_input_streams; i++) {
+ ist = input_streams[i];
+ if (ist->st->codec->codec_type == type && ist->discard)
+ break;
+ }
+ if (i == nb_input_streams) {
+ av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for "
+ "unlabeled input pad %d on filter %s\n", in->pad_idx,
+ in->filter_ctx->name);
+ exit_program(1);
+ }
+ }
+ av_assert0(ist);
+
+ ist->discard = 0;
+ ist->decoding_needed++;
+ ist->st->discard = AVDISCARD_NONE;
+
+ GROW_ARRAY(fg->inputs, fg->nb_inputs);
+ if (!(fg->inputs[fg->nb_inputs - 1] = av_mallocz(sizeof(*fg->inputs[0]))))
+ exit_program(1);
+ fg->inputs[fg->nb_inputs - 1]->ist = ist;
+ fg->inputs[fg->nb_inputs - 1]->graph = fg;
+
+ GROW_ARRAY(ist->filters, ist->nb_filters);
+ ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1];
+}
+
+static int insert_trim(int64_t start_time, int64_t duration,
+ AVFilterContext **last_filter, int *pad_idx,
+ const char *filter_name)
+{
+ AVFilterGraph *graph = (*last_filter)->graph;
+ AVFilterContext *ctx;
+ const AVFilter *trim;
+ enum AVMediaType type = avfilter_pad_get_type((*last_filter)->output_pads, *pad_idx);
+ const char *name = (type == AVMEDIA_TYPE_VIDEO) ? "trim" : "atrim";
+ int ret = 0;
+
+ if (duration == INT64_MAX && start_time == AV_NOPTS_VALUE)
+ return 0;
+
+ trim = avfilter_get_by_name(name);
+ if (!trim) {
+ av_log(NULL, AV_LOG_ERROR, "%s filter not present, cannot limit "
+ "recording time.\n", name);
+ return AVERROR_FILTER_NOT_FOUND;
+ }
+
+ ctx = avfilter_graph_alloc_filter(graph, trim, filter_name);
+ if (!ctx)
+ return AVERROR(ENOMEM);
+
+ if (duration != INT64_MAX) {
+ ret = av_opt_set_int(ctx, "durationi", duration,
+ AV_OPT_SEARCH_CHILDREN);
+ }
+ if (ret >= 0 && start_time != AV_NOPTS_VALUE) {
+ ret = av_opt_set_int(ctx, "starti", start_time,
+ AV_OPT_SEARCH_CHILDREN);
+ }
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Error configuring the %s filter", name);
+ return ret;
+ }
+
+ ret = avfilter_init_str(ctx, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = avfilter_link(*last_filter, *pad_idx, ctx, 0);
+ if (ret < 0)
+ return ret;
+
+ *last_filter = ctx;
+ *pad_idx = 0;
+ return 0;
+}
+
+static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
+{
+ char *pix_fmts;
+ OutputStream *ost = ofilter->ost;
+ OutputFile *of = output_files[ost->file_index];
+ AVCodecContext *codec = ost->st->codec;
+ AVFilterContext *last_filter = out->filter_ctx;
+ int pad_idx = out->pad_idx;
+ int ret;
+ char name[255];
+
+ snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
+ ret = avfilter_graph_create_filter(&ofilter->filter,
+ avfilter_get_by_name("buffersink"),
+ name, NULL, NULL, fg->graph);
+
+ if (ret < 0)
+ return ret;
+
+ if (codec->width || codec->height) {
+ char args[255];
+ AVFilterContext *filter;
+
+ snprintf(args, sizeof(args), "%d:%d:0x%X",
+ codec->width,
+ codec->height,
+ (unsigned)ost->sws_flags);
+ snprintf(name, sizeof(name), "scaler for output stream %d:%d",
+ ost->file_index, ost->index);
+ if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
+ name, args, NULL, fg->graph)) < 0)
+ return ret;
+ if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
+ return ret;
+
+ last_filter = filter;
+ pad_idx = 0;
+ }
+
+ if ((pix_fmts = choose_pix_fmts(ost))) {
+ AVFilterContext *filter;
+ snprintf(name, sizeof(name), "pixel format for output stream %d:%d",
+ ost->file_index, ost->index);
+ ret = avfilter_graph_create_filter(&filter,
+ avfilter_get_by_name("format"),
+ "format", pix_fmts, NULL,
+ fg->graph);
+ av_freep(&pix_fmts);
+ if (ret < 0)
+ return ret;
+ if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
+ return ret;
+
+ last_filter = filter;
+ pad_idx = 0;
+ }
+
+ if (ost->frame_rate.num && 0) {
+ AVFilterContext *fps;
+ char args[255];
+
+ snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num,
+ ost->frame_rate.den);
+ snprintf(name, sizeof(name), "fps for output stream %d:%d",
+ ost->file_index, ost->index);
+ ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"),
+ name, args, NULL, fg->graph);
+ if (ret < 0)
+ return ret;
+
+ ret = avfilter_link(last_filter, pad_idx, fps, 0);
+ if (ret < 0)
+ return ret;
+ last_filter = fps;
+ pad_idx = 0;
+ }
+
+ snprintf(name, sizeof(name), "trim for output stream %d:%d",
+ ost->file_index, ost->index);
+ ret = insert_trim(of->start_time, of->recording_time,
+ &last_filter, &pad_idx, name);
+ if (ret < 0)
+ return ret;
+
+
+ if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
+{
+ OutputStream *ost = ofilter->ost;
+ OutputFile *of = output_files[ost->file_index];
+ AVCodecContext *codec = ost->st->codec;
+ AVFilterContext *last_filter = out->filter_ctx;
+ int pad_idx = out->pad_idx;
+ char *sample_fmts, *sample_rates, *channel_layouts;
+ char name[255];
+ int ret;
+
+ snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
+ ret = avfilter_graph_create_filter(&ofilter->filter,
+ avfilter_get_by_name("abuffersink"),
+ name, NULL, NULL, fg->graph);
+ if (ret < 0)
+ return ret;
+ if ((ret = av_opt_set_int(ofilter->filter, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0)
+ return ret;
+
+#define AUTO_INSERT_FILTER(opt_name, filter_name, arg) do { \
+ AVFilterContext *filt_ctx; \
+ \
+ av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi " \
+ "similarly to -af " filter_name "=%s.\n", arg); \
+ \
+ ret = avfilter_graph_create_filter(&filt_ctx, \
+ avfilter_get_by_name(filter_name), \
+ filter_name, arg, NULL, fg->graph); \
+ if (ret < 0) \
+ return ret; \
+ \
+ ret = avfilter_link(last_filter, pad_idx, filt_ctx, 0); \
+ if (ret < 0) \
+ return ret; \
+ \
+ last_filter = filt_ctx; \
+ pad_idx = 0; \
+} while (0)
+ if (ost->audio_channels_mapped) {
+ int i;
+ AVBPrint pan_buf;
+ av_bprint_init(&pan_buf, 256, 8192);
+ av_bprintf(&pan_buf, "0x%"PRIx64,
+ av_get_default_channel_layout(ost->audio_channels_mapped));
+ for (i = 0; i < ost->audio_channels_mapped; i++)
+ if (ost->audio_channels_map[i] != -1)
+ av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
+
+ AUTO_INSERT_FILTER("-map_channel", "pan", pan_buf.str);
+ av_bprint_finalize(&pan_buf, NULL);
+ }
+
+ if (codec->channels && !codec->channel_layout)
+ codec->channel_layout = av_get_default_channel_layout(codec->channels);
+
+ sample_fmts = choose_sample_fmts(ost);
+ sample_rates = choose_sample_rates(ost);
+ channel_layouts = choose_channel_layouts(ost);
+ if (sample_fmts || sample_rates || channel_layouts) {
+ AVFilterContext *format;
+ char args[256];
+ args[0] = 0;
+
+ if (sample_fmts)
+ av_strlcatf(args, sizeof(args), "sample_fmts=%s:",
+ sample_fmts);
+ if (sample_rates)
+ av_strlcatf(args, sizeof(args), "sample_rates=%s:",
+ sample_rates);
+ if (channel_layouts)
+ av_strlcatf(args, sizeof(args), "channel_layouts=%s:",
+ channel_layouts);
+
+ av_freep(&sample_fmts);
+ av_freep(&sample_rates);
+ av_freep(&channel_layouts);
+
+ snprintf(name, sizeof(name), "audio format for output stream %d:%d",
+ ost->file_index, ost->index);
+ ret = avfilter_graph_create_filter(&format,
+ avfilter_get_by_name("aformat"),
+ name, args, NULL, fg->graph);
+ if (ret < 0)
+ return ret;
+
+ ret = avfilter_link(last_filter, pad_idx, format, 0);
+ if (ret < 0)
+ return ret;
+
+ last_filter = format;
+ pad_idx = 0;
+ }
+
+ if (audio_volume != 256 && 0) {
+ char args[256];
+
+ snprintf(args, sizeof(args), "%f", audio_volume / 256.);
+ AUTO_INSERT_FILTER("-vol", "volume", args);
+ }
+
+ if (ost->apad && of->shortest) {
+ char args[256];
+ int i;
+
+ for (i=0; i<of->ctx->nb_streams; i++)
+ if (of->ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ break;
+
+ if (i<of->ctx->nb_streams) {
+ snprintf(args, sizeof(args), "%s", ost->apad);
+ AUTO_INSERT_FILTER("-apad", "apad", args);
+ }
+ }
+
+ snprintf(name, sizeof(name), "trim for output stream %d:%d",
+ ost->file_index, ost->index);
+ ret = insert_trim(of->start_time, of->recording_time,
+ &last_filter, &pad_idx, name);
+ if (ret < 0)
+ return ret;
+
+ if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
+ return ret;
+
+ return 0;
+}
+
+#define DESCRIBE_FILTER_LINK(f, inout, in) \
+{ \
+ AVFilterContext *ctx = inout->filter_ctx; \
+ AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads; \
+ int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs; \
+ AVIOContext *pb; \
+ \
+ if (avio_open_dyn_buf(&pb) < 0) \
+ exit_program(1); \
+ \
+ avio_printf(pb, "%s", ctx->filter->name); \
+ if (nb_pads > 1) \
+ avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));\
+ avio_w8(pb, 0); \
+ avio_close_dyn_buf(pb, &f->name); \
+}
+
+int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
+{
+ av_freep(&ofilter->name);
+ DESCRIBE_FILTER_LINK(ofilter, out, 0);
+
+ switch (avfilter_pad_get_type(out->filter_ctx->output_pads, out->pad_idx)) {
+ case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, ofilter, out);
+ case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, ofilter, out);
+ default: av_assert0(0);
+ }
+}
+
+static int sub2video_prepare(InputStream *ist)
+{
+ AVFormatContext *avf = input_files[ist->file_index]->ctx;
+ int i, w, h;
+
+ /* Compute the size of the canvas for the subtitles stream.
+ If the subtitles codec has set a size, use it. Otherwise use the
+ maximum dimensions of the video streams in the same file. */
+ w = ist->st->codec->width;
+ h = ist->st->codec->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->st->codec->width = ist->resample_width = w;
+ ist->sub2video.h = ist->st->codec->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->st->codec->pix_fmt = AV_PIX_FMT_RGB32;
+
+ ist->sub2video.frame = av_frame_alloc();
+ if (!ist->sub2video.frame)
+ return AVERROR(ENOMEM);
+ return 0;
+}
+
+static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
+ AVFilterInOut *in)
+{
+ AVFilterContext *last_filter;
+ const AVFilter *buffer_filt = avfilter_get_by_name("buffer");
+ InputStream *ist = ifilter->ist;
+ InputFile *f = input_files[ist->file_index];
+ AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) :
+ ist->st->time_base;
+ AVRational fr = ist->framerate;
+ AVRational sar;
+ AVBPrint args;
+ char name[255];
+ int ret, pad_idx = 0;
+
+ if (ist->st->codec->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->st->codec->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->st->codec->sample_aspect_ratio;
+ if(!sar.den)
+ sar = (AVRational){0,1};
+ av_bprint_init(&args, 0, 1);
+ av_bprintf(&args,
+ "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:"
+ "pixel_aspect=%d/%d:sws_param=flags=%d", ist->resample_width,
+ ist->resample_height, ist->resample_pix_fmt,
+ tb.num, tb.den, sar.num, sar.den,
+ SWS_BILINEAR + ((ist->st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
+ if (fr.num && fr.den)
+ av_bprintf(&args, ":frame_rate=%d/%d", fr.num, fr.den);
+ snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
+ ist->file_index, ist->st->index);
+
+ if ((ret = avfilter_graph_create_filter(&ifilter->filter, buffer_filt, name,
+ args.str, NULL, fg->graph)) < 0)
+ return ret;
+ last_filter = ifilter->filter;
+
+ if (ist->framerate.num) {
+ AVFilterContext *setpts;
+
+ snprintf(name, sizeof(name), "force CFR for input from stream %d:%d",
+ ist->file_index, ist->st->index);
+ if ((ret = avfilter_graph_create_filter(&setpts,
+ avfilter_get_by_name("setpts"),
+ name, "N", NULL,
+ fg->graph)) < 0)
+ return ret;
+
+ if ((ret = avfilter_link(last_filter, 0, setpts, 0)) < 0)
+ return ret;
+
+ last_filter = setpts;
+ }
+
+ if (do_deinterlace) {
+ AVFilterContext *yadif;
+
+ snprintf(name, sizeof(name), "deinterlace input from stream %d:%d",
+ ist->file_index, ist->st->index);
+ if ((ret = avfilter_graph_create_filter(&yadif,
+ avfilter_get_by_name("yadif"),
+ name, "", NULL,
+ fg->graph)) < 0)
+ return ret;
+
+ if ((ret = avfilter_link(last_filter, 0, yadif, 0)) < 0)
+ return ret;
+
+ last_filter = yadif;
+ }
+
+ snprintf(name, sizeof(name), "trim for input stream %d:%d",
+ ist->file_index, ist->st->index);
+ ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
+ AV_NOPTS_VALUE : 0, f->recording_time, &last_filter, &pad_idx, name);
+ if (ret < 0)
+ return ret;
+
+ if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
+ return ret;
+ return 0;
+}
+
+static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
+ AVFilterInOut *in)
+{
+ AVFilterContext *last_filter;
+ const AVFilter *abuffer_filt = avfilter_get_by_name("abuffer");
+ InputStream *ist = ifilter->ist;
+ InputFile *f = input_files[ist->file_index];
+ AVBPrint args;
+ char name[255];
+ int ret, pad_idx = 0;
+
+ if (ist->st->codec->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->st->codec->sample_rate,
+ ist->st->codec->sample_rate,
+ av_get_sample_fmt_name(ist->st->codec->sample_fmt));
+ if (ist->st->codec->channel_layout)
+ av_bprintf(&args, ":channel_layout=0x%"PRIx64,
+ ist->st->codec->channel_layout);
+ else
+ av_bprintf(&args, ":channels=%d", ist->st->codec->channels);
+ snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
+ ist->file_index, ist->st->index);
+
+ if ((ret = avfilter_graph_create_filter(&ifilter->filter, abuffer_filt,
+ name, args.str, NULL,
+ fg->graph)) < 0)
+ return ret;
+ last_filter = ifilter->filter;
+
+#define AUTO_INSERT_FILTER_INPUT(opt_name, filter_name, arg) do { \
+ AVFilterContext *filt_ctx; \
+ \
+ av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi " \
+ "similarly to -af " filter_name "=%s.\n", arg); \
+ \
+ snprintf(name, sizeof(name), "graph %d %s for input stream %d:%d", \
+ fg->index, filter_name, ist->file_index, ist->st->index); \
+ ret = avfilter_graph_create_filter(&filt_ctx, \
+ avfilter_get_by_name(filter_name), \
+ name, arg, NULL, fg->graph); \
+ if (ret < 0) \
+ return ret; \
+ \
+ ret = avfilter_link(last_filter, 0, filt_ctx, 0); \
+ if (ret < 0) \
+ return ret; \
+ \
+ last_filter = filt_ctx; \
+} while (0)
+
+ if (audio_sync_method > 0) {
+ char args[256] = {0};
+
+ av_strlcatf(args, sizeof(args), "async=%d", audio_sync_method);
+ if (audio_drift_threshold != 0.1)
+ av_strlcatf(args, sizeof(args), ":min_hard_comp=%f", audio_drift_threshold);
+ if (!fg->reconfiguration)
+ av_strlcatf(args, sizeof(args), ":first_pts=0");
+ AUTO_INSERT_FILTER_INPUT("-async", "aresample", args);
+ }
+
+// if (ost->audio_channels_mapped) {
+// int i;
+// AVBPrint pan_buf;
+// av_bprint_init(&pan_buf, 256, 8192);
+// av_bprintf(&pan_buf, "0x%"PRIx64,
+// av_get_default_channel_layout(ost->audio_channels_mapped));
+// for (i = 0; i < ost->audio_channels_mapped; i++)
+// if (ost->audio_channels_map[i] != -1)
+// av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
+// AUTO_INSERT_FILTER_INPUT("-map_channel", "pan", pan_buf.str);
+// av_bprint_finalize(&pan_buf, NULL);
+// }
+
+ if (audio_volume != 256) {
+ char args[256];
+
+ av_log(NULL, AV_LOG_WARNING, "-vol has been deprecated. Use the volume "
+ "audio filter instead.\n");
+
+ snprintf(args, sizeof(args), "%f", audio_volume / 256.);
+ AUTO_INSERT_FILTER_INPUT("-vol", "volume", args);
+ }
+
+ snprintf(name, sizeof(name), "trim for input stream %d:%d",
+ ist->file_index, ist->st->index);
+ ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
+ AV_NOPTS_VALUE : 0, f->recording_time, &last_filter, &pad_idx, name);
+ if (ret < 0)
+ return ret;
+
+ if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
+ AVFilterInOut *in)
+{
+ av_freep(&ifilter->name);
+ DESCRIBE_FILTER_LINK(ifilter, in, 1);
+
+ switch (avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx)) {
+ case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in);
+ case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in);
+ default: av_assert0(0);
+ }
+}
+
+int configure_filtergraph(FilterGraph *fg)
+{
+ AVFilterInOut *inputs, *outputs, *cur;
+ int ret, i, init = !fg->graph, simple = !fg->graph_desc;
+ const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter :
+ fg->graph_desc;
+
+ avfilter_graph_free(&fg->graph);
+ if (!(fg->graph = avfilter_graph_alloc()))
+ return AVERROR(ENOMEM);
+
+ if (simple) {
+ OutputStream *ost = fg->outputs[0]->ost;
+ char args[512];
+ AVDictionaryEntry *e = NULL;
+
+ snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags);
+ fg->graph->scale_sws_opts = av_strdup(args);
+
+ args[0] = 0;
+ while ((e = av_dict_get(ost->swr_opts, "", e,
+ AV_DICT_IGNORE_SUFFIX))) {
+ av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
+ }
+ if (strlen(args))
+ args[strlen(args)-1] = 0;
+ av_opt_set(fg->graph, "aresample_swr_opts", args, 0);
+
+ args[0] = '\0';
+ while ((e = av_dict_get(fg->outputs[0]->ost->resample_opts, "", e,
+ AV_DICT_IGNORE_SUFFIX))) {
+ av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
+ }
+ if (strlen(args))
+ args[strlen(args) - 1] = '\0';
+ fg->graph->resample_lavr_opts = av_strdup(args);
+
+ e = av_dict_get(ost->opts, "threads", NULL, 0);
+ if (e)
+ av_opt_set(fg->graph, "threads", e->value, 0);
+ }
+
+ if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0)
+ return ret;
+
+ if (simple && (!inputs || inputs->next || !outputs || outputs->next)) {
+ av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' does not have "
+ "exactly one input and output.\n", graph_desc);
+ return AVERROR(EINVAL);
+ }
+
+ for (cur = inputs; !simple && init && cur; cur = cur->next)
+ init_input_filter(fg, cur);
+
+ for (cur = inputs, i = 0; cur; cur = cur->next, i++)
+ if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0)
+ return ret;
+ avfilter_inout_free(&inputs);
+
+ if (!init || simple) {
+ /* we already know the mappings between lavfi outputs and output streams,
+ * so we can finish the setup */
+ for (cur = outputs, i = 0; cur; cur = cur->next, i++)
+ configure_output_filter(fg, fg->outputs[i], cur);
+ avfilter_inout_free(&outputs);
+
+ if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)
+ return ret;
+ } else {
+ /* wait until output mappings are processed */
+ for (cur = outputs; cur;) {
+ GROW_ARRAY(fg->outputs, fg->nb_outputs);
+ if (!(fg->outputs[fg->nb_outputs - 1] = av_mallocz(sizeof(*fg->outputs[0]))))
+ exit_program(1);
+ fg->outputs[fg->nb_outputs - 1]->graph = fg;
+ fg->outputs[fg->nb_outputs - 1]->out_tmp = cur;
+ cur = cur->next;
+ fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL;
+ }
+ }
+
+ fg->reconfiguration = 1;
+ return 0;
+}
+
+int ist_in_filtergraph(FilterGraph *fg, InputStream *ist)
+{
+ int i;
+ for (i = 0; i < fg->nb_inputs; i++)
+ if (fg->inputs[i]->ist == ist)
+ return 1;
+ return 0;
+}
+
diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c
new file mode 100644
index 0000000..c9283d6
--- a/dev/null
+++ b/ffmpeg_opt.c
@@ -0,0 +1,2885 @@
+/*
+ * ffmpeg option parsing
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+
+#include "ffmpeg.h"
+#include "cmdutils.h"
+
+#include "libavformat/avformat.h"
+
+#include "libavcodec/avcodec.h"
+
+#include "libavfilter/avfilter.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/avutil.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/fifo.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/pixfmt.h"
+
+#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
+{\
+ int i, ret;\
+ for (i = 0; i < o->nb_ ## name; i++) {\
+ char *spec = o->name[i].specifier;\
+ if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0)\
+ outvar = o->name[i].u.type;\
+ else if (ret < 0)\
+ exit_program(1);\
+ }\
+}
+
+#define MATCH_PER_TYPE_OPT(name, type, outvar, fmtctx, mediatype)\
+{\
+ int i;\
+ for (i = 0; i < o->nb_ ## name; i++) {\
+ char *spec = o->name[i].specifier;\
+ if (!strcmp(spec, mediatype))\
+ outvar = o->name[i].u.type;\
+ }\
+}
+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 debug_ts = 0;
+int exit_on_error = 0;
+int print_stats = -1;
+int qp_hist = 0;
+int stdin_interaction = 1;
+int frame_bits_per_raw_sample = 0;
+float max_error_rate = 2.0/3;
+
+
+static int intra_only = 0;
+static int file_overwrite = 0;
+static int no_file_overwrite = 0;
+static int video_discard = 0;
+static int intra_dc_precision = 8;
+static int do_psnr = 0;
+static int input_sync;
+static int override_ffserver = 0;
+
+static void uninit_options(OptionsContext *o)
+{
+ const OptionDef *po = options;
+ int i;
+
+ /* all OPT_SPEC and OPT_STRING can be freed in generic way */
+ while (po->name) {
+ void *dst = (uint8_t*)o + po->u.off;
+
+ if (po->flags & OPT_SPEC) {
+ SpecifierOpt **so = dst;
+ int i, *count = (int*)(so + 1);
+ for (i = 0; i < *count; i++) {
+ av_freep(&(*so)[i].specifier);
+ if (po->flags & OPT_STRING)
+ av_freep(&(*so)[i].u.str);
+ }
+ av_freep(so);
+ *count = 0;
+ } else if (po->flags & OPT_OFFSET && po->flags & OPT_STRING)
+ av_freep(dst);
+ po++;
+ }
+
+ for (i = 0; i < o->nb_stream_maps; i++)
+ av_freep(&o->stream_maps[i].linklabel);
+ av_freep(&o->stream_maps);
+ av_freep(&o->audio_channel_maps);
+ av_freep(&o->streamid_map);
+ av_freep(&o->attachments);
+}
+
+static void init_options(OptionsContext *o)
+{
+ memset(o, 0, sizeof(*o));
+
+ o->stop_time = INT64_MAX;
+ o->mux_max_delay = 0.7;
+ o->start_time = AV_NOPTS_VALUE;
+ o->recording_time = INT64_MAX;
+ o->limit_filesize = UINT64_MAX;
+ o->chapters_input_file = INT_MAX;
+ o->accurate_seek = 1;
+}
+
+/* return a copy of the input with the stream specifiers removed from the keys */
+static AVDictionary *strip_specifiers(AVDictionary *dict)
+{
+ AVDictionaryEntry *e = NULL;
+ AVDictionary *ret = NULL;
+
+ while ((e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))) {
+ char *p = strchr(e->key, ':');
+
+ if (p)
+ *p = 0;
+ av_dict_set(&ret, e->key, e->value, 0);
+ if (p)
+ *p = ':';
+ }
+ return ret;
+}
+
+static int opt_sameq(void *optctx, const char *opt, const char *arg)
+{
+ av_log(NULL, AV_LOG_ERROR, "Option '%s' was removed. "
+ "If you are looking for an option to preserve the quality (which is not "
+ "what -%s was for), use -qscale 0 or an equivalent quality factor option.\n",
+ opt, opt);
+ return AVERROR(EINVAL);
+}
+
+static int opt_video_channel(void *optctx, const char *opt, const char *arg)
+{
+ av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -channel.\n");
+ return opt_default(optctx, "channel", arg);
+}
+
+static int opt_video_standard(void *optctx, const char *opt, const char *arg)
+{
+ av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -standard.\n");
+ return opt_default(optctx, "standard", arg);
+}
+
+static int opt_audio_codec(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "codec:a", arg, options);
+}
+
+static int opt_video_codec(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "codec:v", arg, options);
+}
+
+static int opt_subtitle_codec(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "codec:s", arg, options);
+}
+
+static int opt_data_codec(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "codec:d", arg, options);
+}
+
+static int opt_map(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ StreamMap *m = NULL;
+ int i, negative = 0, file_idx;
+ int sync_file_idx = -1, sync_stream_idx = 0;
+ char *p, *sync;
+ char *map;
+
+ if (*arg == '-') {
+ negative = 1;
+ arg++;
+ }
+ map = av_strdup(arg);
+
+ /* parse sync stream first, just pick first matching stream */
+ if (sync = strchr(map, ',')) {
+ *sync = 0;
+ sync_file_idx = strtol(sync + 1, &sync, 0);
+ if (sync_file_idx >= nb_input_files || sync_file_idx < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid sync file index: %d.\n", sync_file_idx);
+ exit_program(1);
+ }
+ if (*sync)
+ sync++;
+ for (i = 0; i < input_files[sync_file_idx]->nb_streams; i++)
+ if (check_stream_specifier(input_files[sync_file_idx]->ctx,
+ input_files[sync_file_idx]->ctx->streams[i], sync) == 1) {
+ sync_stream_idx = i;
+ break;
+ }
+ if (i == input_files[sync_file_idx]->nb_streams) {
+ av_log(NULL, AV_LOG_FATAL, "Sync stream specification in map %s does not "
+ "match any streams.\n", arg);
+ exit_program(1);
+ }
+ }
+
+
+ if (map[0] == '[') {
+ /* this mapping refers to lavfi output */
+ const char *c = map + 1;
+ GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
+ m = &o->stream_maps[o->nb_stream_maps - 1];
+ m->linklabel = av_get_token(&c, "]");
+ if (!m->linklabel) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid output link label: %s.\n", map);
+ exit_program(1);
+ }
+ } else {
+ file_idx = strtol(map, &p, 0);
+ if (file_idx >= nb_input_files || file_idx < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid input file index: %d.\n", file_idx);
+ exit_program(1);
+ }
+ if (negative)
+ /* disable some already defined maps */
+ for (i = 0; i < o->nb_stream_maps; i++) {
+ m = &o->stream_maps[i];
+ if (file_idx == m->file_index &&
+ check_stream_specifier(input_files[m->file_index]->ctx,
+ input_files[m->file_index]->ctx->streams[m->stream_index],
+ *p == ':' ? p + 1 : p) > 0)
+ m->disabled = 1;
+ }
+ else
+ for (i = 0; i < input_files[file_idx]->nb_streams; i++) {
+ if (check_stream_specifier(input_files[file_idx]->ctx, input_files[file_idx]->ctx->streams[i],
+ *p == ':' ? p + 1 : p) <= 0)
+ continue;
+ GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
+ m = &o->stream_maps[o->nb_stream_maps - 1];
+
+ m->file_index = file_idx;
+ m->stream_index = i;
+
+ if (sync_file_idx >= 0) {
+ m->sync_file_index = sync_file_idx;
+ m->sync_stream_index = sync_stream_idx;
+ } else {
+ m->sync_file_index = file_idx;
+ m->sync_stream_index = i;
+ }
+ }
+ }
+
+ if (!m) {
+ av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches no streams.\n", arg);
+ exit_program(1);
+ }
+
+ av_freep(&map);
+ return 0;
+}
+
+static int opt_attach(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ GROW_ARRAY(o->attachments, o->nb_attachments);
+ o->attachments[o->nb_attachments - 1] = arg;
+ return 0;
+}
+
+static int opt_map_channel(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ int n;
+ AVStream *st;
+ AudioChannelMap *m;
+
+ GROW_ARRAY(o->audio_channel_maps, o->nb_audio_channel_maps);
+ m = &o->audio_channel_maps[o->nb_audio_channel_maps - 1];
+
+ /* muted channel syntax */
+ n = sscanf(arg, "%d:%d.%d", &m->channel_idx, &m->ofile_idx, &m->ostream_idx);
+ if ((n == 1 || n == 3) && m->channel_idx == -1) {
+ m->file_idx = m->stream_idx = -1;
+ if (n == 1)
+ m->ofile_idx = m->ostream_idx = -1;
+ return 0;
+ }
+
+ /* normal syntax */
+ n = sscanf(arg, "%d.%d.%d:%d.%d",
+ &m->file_idx, &m->stream_idx, &m->channel_idx,
+ &m->ofile_idx, &m->ostream_idx);
+
+ if (n != 3 && n != 5) {
+ av_log(NULL, AV_LOG_FATAL, "Syntax error, mapchan usage: "
+ "[file.stream.channel|-1][:syncfile:syncstream]\n");
+ exit_program(1);
+ }
+
+ if (n != 5) // only file.stream.channel specified
+ m->ofile_idx = m->ostream_idx = -1;
+
+ /* check input */
+ if (m->file_idx < 0 || m->file_idx >= nb_input_files) {
+ av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file index: %d\n",
+ m->file_idx);
+ exit_program(1);
+ }
+ if (m->stream_idx < 0 ||
+ m->stream_idx >= input_files[m->file_idx]->nb_streams) {
+ av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file stream index #%d.%d\n",
+ m->file_idx, m->stream_idx);
+ exit_program(1);
+ }
+ st = input_files[m->file_idx]->ctx->streams[m->stream_idx];
+ if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
+ av_log(NULL, AV_LOG_FATAL, "mapchan: stream #%d.%d is not an audio stream.\n",
+ m->file_idx, m->stream_idx);
+ exit_program(1);
+ }
+ if (m->channel_idx < 0 || m->channel_idx >= st->codec->channels) {
+ av_log(NULL, AV_LOG_FATAL, "mapchan: invalid audio channel #%d.%d.%d\n",
+ m->file_idx, m->stream_idx, m->channel_idx);
+ exit_program(1);
+ }
+ return 0;
+}
+
+/**
+ * Parse a metadata specifier passed as 'arg' parameter.
+ * @param arg metadata string to parse
+ * @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram)
+ * @param index for type c/p, chapter/program index is written here
+ * @param stream_spec for type s, the stream specifier is written here
+ */
+static void parse_meta_type(char *arg, char *type, int *index, const char **stream_spec)
+{
+ if (*arg) {
+ *type = *arg;
+ switch (*arg) {
+ case 'g':
+ break;
+ case 's':
+ if (*(++arg) && *arg != ':') {
+ av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg);
+ exit_program(1);
+ }
+ *stream_spec = *arg == ':' ? arg + 1 : "";
+ break;
+ case 'c':
+ case 'p':
+ if (*(++arg) == ':')
+ *index = strtol(++arg, NULL, 0);
+ break;
+ default:
+ av_log(NULL, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
+ exit_program(1);
+ }
+ } else
+ *type = 'g';
+}
+
+static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
+{
+ AVDictionary **meta_in = NULL;
+ AVDictionary **meta_out = NULL;
+ int i, ret = 0;
+ char type_in, type_out;
+ const char *istream_spec = NULL, *ostream_spec = NULL;
+ int idx_in = 0, idx_out = 0;
+
+ parse_meta_type(inspec, &type_in, &idx_in, &istream_spec);
+ parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);
+
+ if (!ic) {
+ if (type_out == 'g' || !*outspec)
+ o->metadata_global_manual = 1;
+ if (type_out == 's' || !*outspec)
+ o->metadata_streams_manual = 1;
+ if (type_out == 'c' || !*outspec)
+ o->metadata_chapters_manual = 1;
+ return 0;
+ }
+
+ if (type_in == 'g' || type_out == 'g')
+ o->metadata_global_manual = 1;
+ if (type_in == 's' || type_out == 's')
+ o->metadata_streams_manual = 1;
+ if (type_in == 'c' || type_out == 'c')
+ o->metadata_chapters_manual = 1;
+
+ /* ic is NULL when just disabling automatic mappings */
+ if (!ic)
+ return 0;
+
+#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
+ if ((index) < 0 || (index) >= (nb_elems)) {\
+ av_log(NULL, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\
+ (desc), (index));\
+ exit_program(1);\
+ }
+
+#define SET_DICT(type, meta, context, index)\
+ switch (type) {\
+ case 'g':\
+ meta = &context->metadata;\
+ break;\
+ case 'c':\
+ METADATA_CHECK_INDEX(index, context->nb_chapters, "chapter")\
+ meta = &context->chapters[index]->metadata;\
+ break;\
+ case 'p':\
+ METADATA_CHECK_INDEX(index, context->nb_programs, "program")\
+ meta = &context->programs[index]->metadata;\
+ break;\
+ case 's':\
+ break; /* handled separately below */ \
+ default: av_assert0(0);\
+ }\
+
+ SET_DICT(type_in, meta_in, ic, idx_in);
+ SET_DICT(type_out, meta_out, oc, idx_out);
+
+ /* for input streams choose first matching stream */
+ if (type_in == 's') {
+ for (i = 0; i < ic->nb_streams; i++) {
+ if ((ret = check_stream_specifier(ic, ic->streams[i], istream_spec)) > 0) {
+ meta_in = &ic->streams[i]->metadata;
+ break;
+ } else if (ret < 0)
+ exit_program(1);
+ }
+ if (!meta_in) {
+ av_log(NULL, AV_LOG_FATAL, "Stream specifier %s does not match any streams.\n", istream_spec);
+ exit_program(1);
+ }
+ }
+
+ if (type_out == 's') {
+ for (i = 0; i < oc->nb_streams; i++) {
+ if ((ret = check_stream_specifier(oc, oc->streams[i], ostream_spec)) > 0) {
+ meta_out = &oc->streams[i]->metadata;
+ av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
+ } else if (ret < 0)
+ exit_program(1);
+ }
+ } else
+ av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
+
+ return 0;
+}
+
+static int opt_recording_timestamp(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ char buf[128];
+ int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;
+ struct tm time = *gmtime((time_t*)&recording_timestamp);
+ strftime(buf, sizeof(buf), "creation_time=%FT%T%z", &time);
+ parse_option(o, "metadata", buf, options);
+
+ av_log(NULL, AV_LOG_WARNING, "%s is deprecated, set the 'creation_time' metadata "
+ "tag instead.\n", opt);
+ return 0;
+}
+
+static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
+{
+ const AVCodecDescriptor *desc;
+ const char *codec_string = encoder ? "encoder" : "decoder";
+ AVCodec *codec;
+
+ codec = encoder ?
+ avcodec_find_encoder_by_name(name) :
+ avcodec_find_decoder_by_name(name);
+
+ if (!codec && (desc = avcodec_descriptor_get_by_name(name))) {
+ codec = encoder ? avcodec_find_encoder(desc->id) :
+ avcodec_find_decoder(desc->id);
+ if (codec)
+ av_log(NULL, AV_LOG_VERBOSE, "Matched %s '%s' for codec '%s'.\n",
+ codec_string, codec->name, desc->name);
+ }
+
+ if (!codec) {
+ av_log(NULL, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name);
+ exit_program(1);
+ }
+ if (codec->type != type) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name);
+ exit_program(1);
+ }
+ return codec;
+}
+
+static AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st)
+{
+ char *codec_name = NULL;
+
+ MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
+ if (codec_name) {
+ AVCodec *codec = find_codec_or_die(codec_name, st->codec->codec_type, 0);
+ st->codec->codec_id = codec->id;
+ return codec;
+ } else
+ return avcodec_find_decoder(st->codec->codec_id);
+}
+
+/* Add all the streams from the given input file to the global
+ * list of input streams. */
+static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
+{
+ int i;
+ char *next, *codec_tag = NULL;
+
+ for (i = 0; i < ic->nb_streams; i++) {
+ AVStream *st = ic->streams[i];
+ AVCodecContext *dec = st->codec;
+ InputStream *ist = av_mallocz(sizeof(*ist));
+ char *framerate = NULL;
+
+ if (!ist)
+ exit_program(1);
+
+ GROW_ARRAY(input_streams, nb_input_streams);
+ input_streams[nb_input_streams - 1] = ist;
+
+ ist->st = st;
+ ist->file_index = nb_input_files;
+ ist->discard = 1;
+ st->discard = AVDISCARD_ALL;
+
+ ist->ts_scale = 1.0;
+ MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
+
+ MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
+ if (codec_tag) {
+ uint32_t tag = strtol(codec_tag, &next, 0);
+ if (*next)
+ tag = AV_RL32(codec_tag);
+ st->codec->codec_tag = tag;
+ }
+
+ ist->dec = choose_decoder(o, ic, st);
+ ist->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);
+
+ ist->filter_in_rescale_delta_last = AV_NOPTS_VALUE;
+
+ 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 = dec->height;
+ ist->resample_width = dec->width;
+ ist->resample_pix_fmt = dec->pix_fmt;
+
+ MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
+ if (framerate && av_parse_video_rate(&ist->framerate,
+ framerate) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error parsing framerate %s.\n",
+ framerate);
+ exit_program(1);
+ }
+
+ ist->top_field_first = -1;
+ MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st);
+
+ 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 = dec->sample_fmt;
+ ist->resample_sample_rate = dec->sample_rate;
+ ist->resample_channels = dec->channels;
+ ist->resample_channel_layout = dec->channel_layout;
+
+ break;
+ case AVMEDIA_TYPE_DATA:
+ case AVMEDIA_TYPE_SUBTITLE: {
+ char *canvas_size = NULL;
+ if(!ist->dec)
+ ist->dec = avcodec_find_decoder(dec->codec_id);
+ MATCH_PER_STREAM_OPT(fix_sub_duration, i, ist->fix_sub_duration, ic, st);
+ MATCH_PER_STREAM_OPT(canvas_sizes, str, canvas_size, ic, st);
+ if (canvas_size &&
+ av_parse_video_size(&dec->width, &dec->height, canvas_size) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid canvas size: %s.\n", canvas_size);
+ exit_program(1);
+ }
+ break;
+ }
+ case AVMEDIA_TYPE_ATTACHMENT:
+ case AVMEDIA_TYPE_UNKNOWN:
+ break;
+ default:
+ abort();
+ }
+ }
+}
+
+static void assert_file_overwrite(const char *filename)
+{
+ if (file_overwrite && no_file_overwrite) {
+ fprintf(stderr, "Error, both -y and -n supplied. Exiting.\n");
+ exit_program(1);
+ }
+
+ if (!file_overwrite &&
+ (strchr(filename, ':') == NULL || filename[1] == ':' ||
+ av_strstart(filename, "file:", NULL))) {
+ if (avio_check(filename, 0) == 0) {
+ if (stdin_interaction && !no_file_overwrite) {
+ fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
+ fflush(stderr);
+ term_exit();
+ signal(SIGINT, SIG_DFL);
+ if (!read_yesno()) {
+ av_log(NULL, AV_LOG_FATAL, "Not overwriting - exiting\n");
+ exit_program(1);
+ }
+ term_init();
+ }
+ else {
+ av_log(NULL, AV_LOG_FATAL, "File '%s' already exists. Exiting.\n", filename);
+ exit_program(1);
+ }
+ }
+ }
+}
+
+static void dump_attachment(AVStream *st, const char *filename)
+{
+ int ret;
+ AVIOContext *out = NULL;
+ AVDictionaryEntry *e;
+
+ if (!st->codec->extradata_size) {
+ av_log(NULL, AV_LOG_WARNING, "No extradata to dump in stream #%d:%d.\n",
+ nb_input_files - 1, st->index);
+ return;
+ }
+ if (!*filename && (e = av_dict_get(st->metadata, "filename", NULL, 0)))
+ filename = e->value;
+ if (!*filename) {
+ av_log(NULL, AV_LOG_FATAL, "No filename specified and no 'filename' tag"
+ "in stream #%d:%d.\n", nb_input_files - 1, st->index);
+ exit_program(1);
+ }
+
+ assert_file_overwrite(filename);
+
+ if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n",
+ filename);
+ exit_program(1);
+ }
+
+ avio_write(out, st->codec->extradata, st->codec->extradata_size);
+ avio_flush(out);
+ avio_close(out);
+}
+
+static int open_input_file(OptionsContext *o, const char *filename)
+{
+ InputFile *f;
+ AVFormatContext *ic;
+ AVInputFormat *file_iformat = NULL;
+ int err, i, ret;
+ int64_t timestamp;
+ 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;
+
+ if (o->format) {
+ if (!(file_iformat = av_find_input_format(o->format))) {
+ av_log(NULL, AV_LOG_FATAL, "Unknown input format: '%s'\n", o->format);
+ exit_program(1);
+ }
+ }
+
+ if (!strcmp(filename, "-"))
+ filename = "pipe:";
+
+ stdin_interaction &= strncmp(filename, "pipe:", 5) &&
+ strcmp(filename, "/dev/stdin");
+
+ /* get default parameters from command line */
+ ic = avformat_alloc_context();
+ if (!ic) {
+ print_error(filename, AVERROR(ENOMEM));
+ exit_program(1);
+ }
+ if (o->nb_audio_sample_rate) {
+ snprintf(buf, sizeof(buf), "%d", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i);
+ av_dict_set(&o->g->format_opts, "sample_rate", buf, 0);
+ }
+ if (o->nb_audio_channels) {
+ /* because we set audio_channels based on both the "ac" and
+ * "channel_layout" options, we need to check that the specified
+ * demuxer actually has the "channels" option before setting it */
+ if (file_iformat && file_iformat->priv_class &&
+ av_opt_find(&file_iformat->priv_class, "channels", NULL, 0,
+ AV_OPT_SEARCH_FAKE_OBJ)) {
+ snprintf(buf, sizeof(buf), "%d",
+ o->audio_channels[o->nb_audio_channels - 1].u.i);
+ av_dict_set(&o->g->format_opts, "channels", buf, 0);
+ }
+ }
+ if (o->nb_frame_rates) {
+ /* set the format-level framerate option;
+ * this is important for video grabbers, e.g. x11 */
+ if (file_iformat && file_iformat->priv_class &&
+ av_opt_find(&file_iformat->priv_class, "framerate", NULL, 0,
+ AV_OPT_SEARCH_FAKE_OBJ)) {
+ av_dict_set(&o->g->format_opts, "framerate",
+ o->frame_rates[o->nb_frame_rates - 1].u.str, 0);
+ }
+ }
+ if (o->nb_frame_sizes) {
+ av_dict_set(&o->g->format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0);
+ }
+ if (o->nb_frame_pix_fmts)
+ av_dict_set(&o->g->format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0);
+
+ 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 avformat function */
+ err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts);
+ if (err < 0) {
+ print_error(filename, err);
+ exit_program(1);
+ }
+ assert_avoptions(o->g->format_opts);
+
+ /* apply forced codec ids */
+ for (i = 0; i < ic->nb_streams; i++)
+ choose_decoder(o, ic, ic->streams[i]);
+
+ /* Set AVCodecContext options for avformat_find_stream_info */
+ opts = setup_find_stream_info_opts(ic, o->g->codec_opts);
+ orig_nb_streams = ic->nb_streams;
+
+ /* If not enough info to get the stream parameters, we decode the
+ first frames to get it. (used in mpeg case for example) */
+ ret = avformat_find_stream_info(ic, opts);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "%s: could not find codec parameters\n", filename);
+ avformat_close_input(&ic);
+ exit_program(1);
+ }
+
+ timestamp = (o->start_time == AV_NOPTS_VALUE) ? 0 : o->start_time;
+ /* add the stream start time */
+ if (ic->start_time != AV_NOPTS_VALUE)
+ timestamp += ic->start_time;
+
+ /* if seeking requested, we execute it */
+ if (o->start_time != AV_NOPTS_VALUE) {
+ ret = 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);
+ }
+ }
+
+ /* update the current parameters so that they match the one of the input stream */
+ add_input_streams(o, ic);
+
+ /* dump the file content */
+ av_dump_format(ic, nb_input_files, filename, 0);
+
+ GROW_ARRAY(input_files, nb_input_files);
+ f = av_mallocz(sizeof(*f));
+ if (!f)
+ exit_program(1);
+ input_files[nb_input_files - 1] = f;
+
+ f->ctx = ic;
+ f->ist_index = nb_input_streams - ic->nb_streams;
+ f->start_time = o->start_time;
+ f->recording_time = o->recording_time;
+ f->ts_offset = o->input_ts_offset - (copy_ts ? 0 : timestamp);
+ f->nb_streams = ic->nb_streams;
+ f->rate_emu = o->rate_emu;
+ f->accurate_seek = o->accurate_seek;
+
+ /* check if all codec options have been used */
+ unused_opts = strip_specifiers(o->g->codec_opts);
+ for (i = f->ist_index; i < nb_input_streams; i++) {
+ e = NULL;
+ while ((e = av_dict_get(input_streams[i]->opts, "", e,
+ AV_DICT_IGNORE_SUFFIX)))
+ av_dict_set(&unused_opts, e->key, NULL, 0);
+ }
+
+ e = NULL;
+ while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
+ const AVClass *class = avcodec_get_class();
+ const AVOption *option = av_opt_find(&class, e->key, NULL, 0,
+ AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
+ if (!option)
+ continue;
+ if (!(option->flags & AV_OPT_FLAG_DECODING_PARAM)) {
+ av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
+ "input file #%d (%s) is not a decoding option.\n", e->key,
+ option->help ? option->help : "", nb_input_files - 1,
+ filename);
+ exit_program(1);
+ }
+
+ av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
+ "input file #%d (%s) has not been used for any stream. The most "
+ "likely reason is either wrong type (e.g. a video option with "
+ "no video streams) or that it is a private option of some decoder "
+ "which was not actually used for any stream.\n", e->key,
+ option->help ? option->help : "", nb_input_files - 1, filename);
+ }
+ av_dict_free(&unused_opts);
+
+ for (i = 0; i < o->nb_dump_attachment; i++) {
+ int j;
+
+ for (j = 0; j < ic->nb_streams; j++) {
+ AVStream *st = ic->streams[j];
+
+ if (check_stream_specifier(ic, st, o->dump_attachment[i].specifier) == 1)
+ dump_attachment(st, o->dump_attachment[i].u.str);
+ }
+ }
+
+ for (i = 0; i < orig_nb_streams; i++)
+ av_dict_free(&opts[i]);
+ av_freep(&opts);
+
+ return 0;
+}
+
+static uint8_t *get_line(AVIOContext *s)
+{
+ AVIOContext *line;
+ uint8_t *buf;
+ char c;
+
+ if (avio_open_dyn_buf(&line) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Could not alloc buffer for reading preset.\n");
+ exit_program(1);
+ }
+
+ while ((c = avio_r8(s)) && c != '\n')
+ avio_w8(line, c);
+ avio_w8(line, 0);
+ avio_close_dyn_buf(line, &buf);
+
+ return buf;
+}
+
+static int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s)
+{
+ int i, ret = 1;
+ char filename[1000];
+ const char *base[3] = { getenv("AVCONV_DATADIR"),
+ getenv("HOME"),
+ AVCONV_DATADIR,
+ };
+
+ for (i = 0; i < FF_ARRAY_ELEMS(base) && ret; i++) {
+ if (!base[i])
+ continue;
+ if (codec_name) {
+ snprintf(filename, sizeof(filename), "%s%s/%s-%s.avpreset", base[i],
+ i != 1 ? "" : "/.avconv", codec_name, preset_name);
+ ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
+ }
+ if (ret) {
+ snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i],
+ i != 1 ? "" : "/.avconv", preset_name);
+ ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
+ }
+ }
+ return ret;
+}
+
+static void choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *ost)
+{
+ char *codec_name = NULL;
+
+ MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st);
+ if (!codec_name) {
+ ost->st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename,
+ NULL, ost->st->codec->codec_type);
+ ost->enc = avcodec_find_encoder(ost->st->codec->codec_id);
+ } else if (!strcmp(codec_name, "copy"))
+ ost->stream_copy = 1;
+ else {
+ ost->enc = find_codec_or_die(codec_name, ost->st->codec->codec_type, 1);
+ ost->st->codec->codec_id = ost->enc->id;
+ }
+}
+
+static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type, int source_index)
+{
+ OutputStream *ost;
+ AVStream *st = avformat_new_stream(oc, NULL);
+ int idx = oc->nb_streams - 1, ret = 0;
+ char *bsf = NULL, *next, *codec_tag = NULL;
+ AVBitStreamFilterContext *bsfc, *bsfc_prev = NULL;
+ double qscale = -1;
+ int i;
+
+ if (!st) {
+ av_log(NULL, AV_LOG_FATAL, "Could not alloc stream.\n");
+ exit_program(1);
+ }
+
+ if (oc->nb_streams - 1 < o->nb_streamid_map)
+ st->id = o->streamid_map[oc->nb_streams - 1];
+
+ GROW_ARRAY(output_streams, nb_output_streams);
+ if (!(ost = av_mallocz(sizeof(*ost))))
+ exit_program(1);
+ output_streams[nb_output_streams - 1] = ost;
+
+ ost->file_index = nb_output_files - 1;
+ ost->index = idx;
+ ost->st = st;
+ st->codec->codec_type = type;
+ choose_encoder(o, oc, ost);
+ if (ost->enc) {
+ AVIOContext *s = NULL;
+ char *buf = NULL, *arg = NULL, *preset = NULL;
+
+ ost->opts = filter_codec_opts(o->g->codec_opts, ost->enc->id, oc, st, ost->enc);
+
+ MATCH_PER_STREAM_OPT(presets, str, preset, oc, st);
+ if (preset && (!(ret = get_preset_file_2(preset, ost->enc->name, &s)))) {
+ do {
+ buf = get_line(s);
+ if (!buf[0] || buf[0] == '#') {
+ av_free(buf);
+ continue;
+ }
+ if (!(arg = strchr(buf, '='))) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid line found in the preset file.\n");
+ exit_program(1);
+ }
+ *arg++ = 0;
+ av_dict_set(&ost->opts, buf, arg, AV_DICT_DONT_OVERWRITE);
+ av_free(buf);
+ } while (!s->eof_reached);
+ avio_close(s);
+ }
+ if (ret) {
+ av_log(NULL, AV_LOG_FATAL,
+ "Preset %s specified for stream %d:%d, but could not be opened.\n",
+ preset, ost->file_index, ost->index);
+ exit_program(1);
+ }
+ } else {
+ ost->opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL);
+ }
+
+ avcodec_get_context_defaults3(st->codec, ost->enc);
+ st->codec->codec_type = type; // XXX hack, avcodec_get_context_defaults2() sets type to unknown for stream copy
+
+ 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) {
+ if (next = strchr(bsf, ','))
+ *next++ = 0;
+ if (!(bsfc = av_bitstream_filter_init(bsf))) {
+ av_log(NULL, AV_LOG_FATAL, "Unknown bitstream filter %s\n", bsf);
+ exit_program(1);
+ }
+ if (bsfc_prev)
+ bsfc_prev->next = bsfc;
+ else
+ ost->bitstream_filters = bsfc;
+
+ bsfc_prev = bsfc;
+ bsf = next;
+ }
+
+ MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st);
+ if (codec_tag) {
+ uint32_t tag = strtol(codec_tag, &next, 0);
+ if (*next)
+ tag = AV_RL32(codec_tag);
+ st->codec->codec_tag = tag;
+ }
+
+ MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st);
+ if (qscale >= 0) {
+ st->codec->flags |= CODEC_FLAG_QSCALE;
+ st->codec->global_quality = FF_QP2LAMBDA * qscale;
+ }
+
+ if (oc->oformat->flags & AVFMT_GLOBALHEADER)
+ st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+ av_opt_get_int(o->g->sws_opts, "sws_flags", 0, &ost->sws_flags);
+
+ av_dict_copy(&ost->swr_opts, o->g->swr_opts, 0);
+ if (ost->enc && av_get_exact_bits_per_sample(ost->enc->id) == 24)
+ av_dict_set(&ost->swr_opts, "output_sample_bits", "24", 0);
+
+ av_dict_copy(&ost->resample_opts, o->g->resample_opts, 0);
+
+ ost->source_index = source_index;
+ if (source_index >= 0) {
+ ost->sync_ist = input_streams[source_index];
+ input_streams[source_index]->discard = 0;
+ input_streams[source_index]->st->discard = AVDISCARD_NONE;
+ }
+ ost->last_mux_dts = AV_NOPTS_VALUE;
+
+ return ost;
+}
+
+static void parse_matrix_coeffs(uint16_t *dest, const char *str)
+{
+ int i;
+ const char *p = str;
+ for (i = 0;; i++) {
+ dest[i] = atoi(p);
+ if (i == 63)
+ break;
+ p = strchr(p, ',');
+ if (!p) {
+ av_log(NULL, AV_LOG_FATAL, "Syntax error in matrix \"%s\" at coeff %d\n", str, i);
+ exit_program(1);
+ }
+ p++;
+ }
+}
+
+/* read file contents into a string */
+static uint8_t *read_file(const char *filename)
+{
+ AVIOContext *pb = NULL;
+ AVIOContext *dyn_buf = NULL;
+ int ret = avio_open(&pb, filename, AVIO_FLAG_READ);
+ uint8_t buf[1024], *str;
+
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error opening file %s.\n", filename);
+ return NULL;
+ }
+
+ ret = avio_open_dyn_buf(&dyn_buf);
+ if (ret < 0) {
+ avio_closep(&pb);
+ return NULL;
+ }
+ while ((ret = avio_read(pb, buf, sizeof(buf))) > 0)
+ avio_write(dyn_buf, buf, ret);
+ avio_w8(dyn_buf, 0);
+ avio_closep(&pb);
+
+ ret = avio_close_dyn_buf(dyn_buf, &str);
+ if (ret < 0)
+ return NULL;
+ return str;
+}
+
+static char *get_ost_filters(OptionsContext *o, AVFormatContext *oc,
+ OutputStream *ost)
+{
+ AVStream *st = ost->st;
+ char *filter = NULL, *filter_script = NULL;
+
+ MATCH_PER_STREAM_OPT(filter_scripts, str, filter_script, oc, st);
+ MATCH_PER_STREAM_OPT(filters, str, filter, oc, st);
+
+ if (filter_script && filter) {
+ av_log(NULL, AV_LOG_ERROR, "Both -filter and -filter_script set for "
+ "output stream #%d:%d.\n", nb_output_files, st->index);
+ exit_program(1);
+ }
+
+ if (filter_script)
+ return read_file(filter_script);
+ else if (filter)
+ return av_strdup(filter);
+
+ return av_strdup(st->codec->codec_type == AVMEDIA_TYPE_VIDEO ?
+ "null" : "anull");
+}
+
+static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
+{
+ AVStream *st;
+ OutputStream *ost;
+ AVCodecContext *video_enc;
+ char *frame_rate = NULL, *frame_aspect_ratio = NULL;
+
+ ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO, source_index);
+ st = ost->st;
+ video_enc = st->codec;
+
+ 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_aspect_ratios, str, frame_aspect_ratio, oc, st);
+ if (frame_aspect_ratio) {
+ AVRational q;
+ if (av_parse_ratio(&q, frame_aspect_ratio, 255, 0, NULL) < 0 ||
+ q.num <= 0 || q.den <= 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid aspect ratio: %s\n", frame_aspect_ratio);
+ exit_program(1);
+ }
+ ost->frame_aspect_ratio = q;
+ }
+
+ if (!ost->stream_copy) {
+ const char *p = NULL;
+ char *frame_size = NULL;
+ char *frame_pix_fmt = NULL;
+ char *intra_matrix = NULL, *inter_matrix = NULL;
+ int do_pass = 0;
+ int i;
+
+ MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
+ if (frame_size && av_parse_video_size(&video_enc->width, &video_enc->height, frame_size) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
+ exit_program(1);
+ }
+
+ video_enc->bits_per_raw_sample = frame_bits_per_raw_sample;
+ MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st);
+ if (frame_pix_fmt && *frame_pix_fmt == '+') {
+ ost->keep_pix_fmt = 1;
+ if (!*++frame_pix_fmt)
+ frame_pix_fmt = NULL;
+ }
+ if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == AV_PIX_FMT_NONE) {
+ av_log(NULL, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", frame_pix_fmt);
+ exit_program(1);
+ }
+ st->sample_aspect_ratio = video_enc->sample_aspect_ratio;
+
+ if (intra_only)
+ video_enc->gop_size = 0;
+ MATCH_PER_STREAM_OPT(intra_matrices, str, intra_matrix, oc, st);
+ if (intra_matrix) {
+ if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64))) {
+ av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for intra matrix.\n");
+ exit_program(1);
+ }
+ parse_matrix_coeffs(video_enc->intra_matrix, intra_matrix);
+ }
+ MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st);
+ if (inter_matrix) {
+ if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64))) {
+ av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for inter matrix.\n");
+ exit_program(1);
+ }
+ parse_matrix_coeffs(video_enc->inter_matrix, inter_matrix);
+ }
+
+ MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st);
+ for (i = 0; p; i++) {
+ int start, end, q;
+ int e = sscanf(p, "%d,%d,%d", &start, &end, &q);
+ if (e != 3) {
+ av_log(NULL, AV_LOG_FATAL, "error parsing rc_override\n");
+ exit_program(1);
+ }
+ /* FIXME realloc failure */
+ video_enc->rc_override =
+ av_realloc(video_enc->rc_override,
+ sizeof(RcOverride) * (i + 1));
+ video_enc->rc_override[i].start_frame = start;
+ video_enc->rc_override[i].end_frame = end;
+ if (q > 0) {
+ video_enc->rc_override[i].qscale = q;
+ video_enc->rc_override[i].quality_factor = 1.0;
+ }
+ else {
+ video_enc->rc_override[i].qscale = 0;
+ video_enc->rc_override[i].quality_factor = -q/100.0;
+ }
+ p = strchr(p, '/');
+ if (p) p++;
+ }
+ video_enc->rc_override_count = i;
+ video_enc->intra_dc_precision = intra_dc_precision - 8;
+
+ if (do_psnr)
+ video_enc->flags|= CODEC_FLAG_PSNR;
+
+ /* two pass mode */
+ MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
+ if (do_pass) {
+ if (do_pass & 1) {
+ video_enc->flags |= CODEC_FLAG_PASS1;
+ av_dict_set(&ost->opts, "flags", "+pass1", AV_DICT_APPEND);
+ }
+ if (do_pass & 2) {
+ video_enc->flags |= CODEC_FLAG_PASS2;
+ av_dict_set(&ost->opts, "flags", "+pass2", AV_DICT_APPEND);
+ }
+ }
+
+ MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st);
+ if (ost->logfile_prefix &&
+ !(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
+ exit_program(1);
+
+ MATCH_PER_STREAM_OPT(forced_key_frames, str, ost->forced_keyframes, oc, st);
+ if (ost->forced_keyframes)
+ ost->forced_keyframes = av_strdup(ost->forced_keyframes);
+
+ MATCH_PER_STREAM_OPT(force_fps, i, ost->force_fps, oc, st);
+
+ ost->top_field_first = -1;
+ MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
+
+
+ ost->avfilter = get_ost_filters(o, oc, ost);
+ if (!ost->avfilter)
+ exit_program(1);
+ } else {
+ MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st);
+ }
+
+ return ost;
+}
+
+static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
+{
+ int n;
+ AVStream *st;
+ OutputStream *ost;
+ AVCodecContext *audio_enc;
+
+ ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO, source_index);
+ st = ost->st;
+
+ audio_enc = st->codec;
+ audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
+
+ if (!ost->stream_copy) {
+ char *sample_fmt = NULL;
+
+ MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st);
+
+ MATCH_PER_STREAM_OPT(sample_fmts, str, sample_fmt, oc, st);
+ if (sample_fmt &&
+ (audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt);
+ exit_program(1);
+ }
+
+ MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
+
+ 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];
+ InputStream *ist = input_streams[ost->source_index];
+ if ((map->channel_idx == -1 || (ist->file_index == map->file_idx && ist->st->index == map->stream_idx)) &&
+ (map->ofile_idx == -1 || ost->file_index == map->ofile_idx) &&
+ (map->ostream_idx == -1 || ost->st->index == map->ostream_idx)) {
+ if (ost->audio_channels_mapped < FF_ARRAY_ELEMS(ost->audio_channels_map))
+ ost->audio_channels_map[ost->audio_channels_mapped++] = map->channel_idx;
+ else
+ av_log(NULL, AV_LOG_FATAL, "Max channel mapping for output %d.%d reached\n",
+ ost->file_index, ost->st->index);
+ }
+ }
+ }
+
+ return ost;
+}
+
+static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
+{
+ OutputStream *ost;
+
+ ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA, source_index);
+ if (!ost->stream_copy) {
+ av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
+ exit_program(1);
+ }
+
+ return ost;
+}
+
+static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
+{
+ OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT, source_index);
+ ost->stream_copy = 1;
+ ost->finished = 1;
+ return ost;
+}
+
+static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
+{
+ AVStream *st;
+ OutputStream *ost;
+ AVCodecContext *subtitle_enc;
+
+ ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE, source_index);
+ st = ost->st;
+ subtitle_enc = st->codec;
+
+ subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
+
+ MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc, st);
+
+ if (!ost->stream_copy) {
+ char *frame_size = NULL;
+
+ MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
+ if (frame_size && av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
+ exit_program(1);
+ }
+ }
+
+ return ost;
+}
+
+/* arg format is "output-stream-index:streamid-value". */
+static int opt_streamid(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ int idx;
+ char *p;
+ char idx_str[16];
+
+ av_strlcpy(idx_str, arg, sizeof(idx_str));
+ p = strchr(idx_str, ':');
+ if (!p) {
+ av_log(NULL, AV_LOG_FATAL,
+ "Invalid value '%s' for option '%s', required syntax is 'index:value'\n",
+ arg, opt);
+ exit_program(1);
+ }
+ *p++ = '\0';
+ idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, MAX_STREAMS-1);
+ o->streamid_map = grow_array(o->streamid_map, sizeof(*o->streamid_map), &o->nb_streamid_map, idx+1);
+ o->streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX);
+ return 0;
+}
+
+static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata)
+{
+ AVFormatContext *is = ifile->ctx;
+ AVFormatContext *os = ofile->ctx;
+ AVChapter **tmp;
+ int i;
+
+ tmp = av_realloc_f(os->chapters, is->nb_chapters + os->nb_chapters, sizeof(*os->chapters));
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ os->chapters = tmp;
+
+ for (i = 0; i < is->nb_chapters; i++) {
+ AVChapter *in_ch = is->chapters[i], *out_ch;
+ int64_t start_time = (ofile->start_time == AV_NOPTS_VALUE) ? 0 : ofile->start_time;
+ int64_t ts_off = av_rescale_q(start_time - ifile->ts_offset,
+ AV_TIME_BASE_Q, in_ch->time_base);
+ int64_t rt = (ofile->recording_time == INT64_MAX) ? INT64_MAX :
+ av_rescale_q(ofile->recording_time, AV_TIME_BASE_Q, in_ch->time_base);
+
+
+ if (in_ch->end < ts_off)
+ continue;
+ if (rt != INT64_MAX && in_ch->start > rt + ts_off)
+ break;
+
+ out_ch = av_mallocz(sizeof(AVChapter));
+ if (!out_ch)
+ return AVERROR(ENOMEM);
+
+ out_ch->id = in_ch->id;
+ out_ch->time_base = in_ch->time_base;
+ out_ch->start = FFMAX(0, in_ch->start - ts_off);
+ out_ch->end = FFMIN(rt, in_ch->end - ts_off);
+
+ if (copy_metadata)
+ av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
+
+ os->chapters[os->nb_chapters++] = out_ch;
+ }
+ return 0;
+}
+
+static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename)
+{
+ int i, err;
+ AVFormatContext *ic = avformat_alloc_context();
+
+ ic->interrupt_callback = int_cb;
+ err = avformat_open_input(&ic, filename, NULL, NULL);
+ if (err < 0)
+ return err;
+ /* copy stream format */
+ for(i=0;i<ic->nb_streams;i++) {
+ AVStream *st;
+ OutputStream *ost;
+ AVCodec *codec;
+ AVCodecContext *avctx;
+
+ codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
+ 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, codec, st->codec->pix_fmt);
+ }
+
+ avformat_close_input(&ic);
+ return err;
+}
+
+static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
+ AVFormatContext *oc)
+{
+ OutputStream *ost;
+
+ switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
+ ofilter->out_tmp->pad_idx)) {
+ case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc, -1); break;
+ case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc, -1); break;
+ default:
+ av_log(NULL, AV_LOG_FATAL, "Only video and audio filters are supported "
+ "currently.\n");
+ exit_program(1);
+ }
+
+ ost->source_index = -1;
+ ost->filter = ofilter;
+
+ ofilter->ost = ost;
+
+ if (ost->stream_copy) {
+ av_log(NULL, AV_LOG_ERROR, "Streamcopy requested for output stream %d:%d, "
+ "which is fed from a complex filtergraph. Filtering and streamcopy "
+ "cannot be used together.\n", ost->file_index, ost->index);
+ exit_program(1);
+ }
+
+ if (configure_output_filter(ofilter->graph, ofilter, ofilter->out_tmp) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error configuring filter.\n");
+ exit_program(1);
+ }
+ avfilter_inout_free(&ofilter->out_tmp);
+}
+
+static int configure_complex_filters(void)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < nb_filtergraphs; i++)
+ if (!filtergraphs[i]->graph &&
+ (ret = configure_filtergraph(filtergraphs[i])) < 0)
+ return ret;
+ return 0;
+}
+
+static int open_output_file(OptionsContext *o, const char *filename)
+{
+ AVFormatContext *oc;
+ int i, j, err;
+ AVOutputFormat *file_oformat;
+ OutputFile *of;
+ OutputStream *ost;
+ InputStream *ist;
+ AVDictionary *unused_opts = NULL;
+ AVDictionaryEntry *e = NULL;
+
+ if (configure_complex_filters() < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error configuring filters.\n");
+ exit_program(1);
+ }
+
+ if (o->stop_time != INT64_MAX && o->recording_time != INT64_MAX) {
+ o->stop_time = INT64_MAX;
+ av_log(NULL, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n");
+ }
+
+ if (o->stop_time != INT64_MAX && o->recording_time == INT64_MAX) {
+ int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time;
+ if (o->stop_time <= start_time) {
+ av_log(NULL, AV_LOG_WARNING, "-to value smaller than -ss; ignoring -to.\n");
+ o->stop_time = INT64_MAX;
+ } else {
+ o->recording_time = o->stop_time - start_time;
+ }
+ }
+
+ GROW_ARRAY(output_files, nb_output_files);
+ of = av_mallocz(sizeof(*of));
+ if (!of)
+ exit_program(1);
+ output_files[nb_output_files - 1] = of;
+
+ of->ost_index = nb_output_streams;
+ of->recording_time = o->recording_time;
+ of->start_time = o->start_time;
+ of->limit_filesize = o->limit_filesize;
+ of->shortest = o->shortest;
+ av_dict_copy(&of->opts, o->g->format_opts, 0);
+
+ if (!strcmp(filename, "-"))
+ filename = "pipe:";
+
+ err = avformat_alloc_output_context2(&oc, NULL, o->format, filename);
+ if (!oc) {
+ print_error(filename, err);
+ exit_program(1);
+ }
+
+ of->ctx = oc;
+ if (o->recording_time != INT64_MAX)
+ oc->duration = o->recording_time;
+
+ file_oformat= oc->oformat;
+ oc->interrupt_callback = int_cb;
+
+ /* create streams for all unlabeled output pads */
+ for (i = 0; i < nb_filtergraphs; i++) {
+ FilterGraph *fg = filtergraphs[i];
+ for (j = 0; j < fg->nb_outputs; j++) {
+ OutputFilter *ofilter = fg->outputs[j];
+
+ if (!ofilter->out_tmp || ofilter->out_tmp->name)
+ continue;
+
+ switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
+ ofilter->out_tmp->pad_idx)) {
+ case AVMEDIA_TYPE_VIDEO: o->video_disable = 1; break;
+ case AVMEDIA_TYPE_AUDIO: o->audio_disable = 1; break;
+ case AVMEDIA_TYPE_SUBTITLE: o->subtitle_disable = 1; break;
+ }
+ init_output_filter(ofilter, o, oc);
+ }
+ }
+
+ /* ffserver seeking with date=... needs a date reference */
+ if (!strcmp(file_oformat->name, "ffm") &&
+ av_strstart(filename, "http:", NULL)) {
+ int err = parse_option(o, "metadata", "creation_time=now", options);
+ if (err < 0) {
+ print_error(filename, err);
+ exit_program(1);
+ }
+ }
+
+ if (!strcmp(file_oformat->name, "ffm") && !override_ffserver &&
+ av_strstart(filename, "http:", NULL)) {
+ int j;
+ /* special case for files sent to ffserver: we get the stream
+ parameters from ffserver */
+ int err = read_ffserver_streams(o, oc, filename);
+ if (err < 0) {
+ print_error(filename, err);
+ exit_program(1);
+ }
+ for(j = nb_output_streams - oc->nb_streams; j < nb_output_streams; j++) {
+ ost = output_streams[j];
+ for (i = 0; i < nb_input_streams; i++) {
+ ist = input_streams[i];
+ if(ist->st->codec->codec_type == ost->st->codec->codec_type){
+ ost->sync_ist= ist;
+ ost->source_index= i;
+ if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) ost->avfilter = av_strdup("anull");
+ if(ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) ost->avfilter = av_strdup("null");
+ ist->discard = 0;
+ ist->st->discard = AVDISCARD_NONE;
+ 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) {
+ int area = 0, idx = -1;
+ int qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0);
+ for (i = 0; i < nb_input_streams; i++) {
+ int new_area;
+ ist = input_streams[i];
+ new_area = ist->st->codec->width * ist->st->codec->height;
+ if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ new_area = 1;
+ if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
+ new_area > area) {
+ if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ continue;
+ area = new_area;
+ idx = i;
+ }
+ }
+ if (idx >= 0)
+ new_video_stream(o, oc, idx);
+ }
+
+ /* audio: most channels */
+ if (!o->audio_disable && oc->oformat->audio_codec != AV_CODEC_ID_NONE) {
+ int channels = 0, idx = -1;
+ for (i = 0; i < nb_input_streams; i++) {
+ ist = input_streams[i];
+ if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
+ ist->st->codec->channels > channels) {
+ channels = ist->st->codec->channels;
+ idx = i;
+ }
+ }
+ if (idx >= 0)
+ new_audio_stream(o, oc, idx);
+ }
+
+ /* subtitles: pick first */
+ MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, oc, "s");
+ if (!o->subtitle_disable && (oc->oformat->subtitle_codec != AV_CODEC_ID_NONE || subtitle_codec_name)) {
+ for (i = 0; i < nb_input_streams; i++)
+ if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+ new_subtitle_stream(o, oc, i);
+ break;
+ }
+ }
+ /* do something with data? */
+ } else {
+ for (i = 0; i < o->nb_stream_maps; i++) {
+ StreamMap *map = &o->stream_maps[i];
+
+ if (map->disabled)
+ continue;
+
+ if (map->linklabel) {
+ FilterGraph *fg;
+ OutputFilter *ofilter = NULL;
+ int j, k;
+
+ for (j = 0; j < nb_filtergraphs; j++) {
+ fg = filtergraphs[j];
+ for (k = 0; k < fg->nb_outputs; k++) {
+ AVFilterInOut *out = fg->outputs[k]->out_tmp;
+ if (out && !strcmp(out->name, map->linklabel)) {
+ ofilter = fg->outputs[k];
+ goto loop_end;
+ }
+ }
+ }
+loop_end:
+ if (!ofilter) {
+ av_log(NULL, AV_LOG_FATAL, "Output with label '%s' does not exist "
+ "in any defined filter graph, or was already used elsewhere.\n", map->linklabel);
+ exit_program(1);
+ }
+ init_output_filter(ofilter, o, oc);
+ } else {
+ int src_idx = input_files[map->file_index]->ist_index + map->stream_index;
+
+ ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index];
+ if(o->subtitle_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
+ continue;
+ if(o-> audio_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ continue;
+ if(o-> video_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ continue;
+ if(o-> data_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_DATA)
+ continue;
+
+ switch (ist->st->codec->codec_type) {
+ case AVMEDIA_TYPE_VIDEO: ost = new_video_stream (o, oc, src_idx); break;
+ case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream (o, oc, src_idx); break;
+ case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream (o, oc, src_idx); break;
+ case AVMEDIA_TYPE_DATA: ost = new_data_stream (o, oc, src_idx); break;
+ case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc, src_idx); break;
+ default:
+ av_log(NULL, AV_LOG_FATAL, "Cannot map stream #%d:%d - unsupported type.\n",
+ map->file_index, map->stream_index);
+ exit_program(1);
+ }
+ }
+ }
+ }
+
+ /* handle attached files */
+ for (i = 0; i < o->nb_attachments; i++) {
+ AVIOContext *pb;
+ uint8_t *attachment;
+ const char *p;
+ int64_t len;
+
+ if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n",
+ o->attachments[i]);
+ exit_program(1);
+ }
+ if ((len = avio_size(pb)) <= 0) {
+ av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
+ o->attachments[i]);
+ exit_program(1);
+ }
+ if (!(attachment = av_malloc(len))) {
+ av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n",
+ o->attachments[i]);
+ exit_program(1);
+ }
+ avio_read(pb, attachment, len);
+
+ ost = new_attachment_stream(o, oc, -1);
+ ost->stream_copy = 0;
+ ost->attachment_filename = o->attachments[i];
+ ost->finished = 1;
+ ost->st->codec->extradata = attachment;
+ ost->st->codec->extradata_size = len;
+
+ p = strrchr(o->attachments[i], '/');
+ av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE);
+ avio_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++) {
+ e = NULL;
+ while ((e = av_dict_get(output_streams[i]->opts, "", e,
+ AV_DICT_IGNORE_SUFFIX)))
+ av_dict_set(&unused_opts, e->key, NULL, 0);
+ }
+
+ e = NULL;
+ while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
+ const AVClass *class = avcodec_get_class();
+ const AVOption *option = av_opt_find(&class, e->key, NULL, 0,
+ AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
+ if (!option)
+ continue;
+ if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) {
+ av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
+ "output file #%d (%s) is not an encoding option.\n", e->key,
+ option->help ? option->help : "", nb_output_files - 1,
+ filename);
+ exit_program(1);
+ }
+
+ // gop_timecode is injected by generic code but not always used
+ if (!strcmp(e->key, "gop_timecode"))
+ continue;
+
+ av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
+ "output file #%d (%s) has not been used for any stream. The most "
+ "likely reason is either wrong type (e.g. a video option with "
+ "no video streams) or that it is a private option of some encoder "
+ "which was not actually used for any stream.\n", e->key,
+ option->help ? option->help : "", nb_output_files - 1, filename);
+ }
+ av_dict_free(&unused_opts);
+
+ /* check filename in case of an image number is expected */
+ if (oc->oformat->flags & AVFMT_NEEDNUMBER) {
+ if (!av_filename_number_test(oc->filename)) {
+ print_error(oc->filename, AVERROR(EINVAL));
+ exit_program(1);
+ }
+ }
+
+ if (!(oc->oformat->flags & AVFMT_NOFILE)) {
+ /* test if it already exists to avoid losing precious files */
+ assert_file_overwrite(filename);
+
+ /* open the file */
+ if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,
+ &oc->interrupt_callback,
+ &of->opts)) < 0) {
+ print_error(filename, err);
+ exit_program(1);
+ }
+ } else if (strcmp(oc->oformat->name, "image2")==0 && !av_filename_number_test(filename))
+ assert_file_overwrite(filename);
+
+ if (o->mux_preload) {
+ uint8_t buf[64];
+ snprintf(buf, sizeof(buf), "%d", (int)(o->mux_preload*AV_TIME_BASE));
+ av_dict_set(&of->opts, "preload", buf, 0);
+ }
+ oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
+
+ /* copy metadata */
+ for (i = 0; i < o->nb_metadata_map; i++) {
+ char *p;
+ int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
+
+ if (in_file_index >= nb_input_files) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
+ exit_program(1);
+ }
+ copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc,
+ in_file_index >= 0 ?
+ input_files[in_file_index]->ctx : NULL, o);
+ }
+
+ /* copy chapters */
+ if (o->chapters_input_file >= nb_input_files) {
+ if (o->chapters_input_file == INT_MAX) {
+ /* copy chapters from the first input file that has them*/
+ o->chapters_input_file = -1;
+ for (i = 0; i < nb_input_files; i++)
+ if (input_files[i]->ctx->nb_chapters) {
+ o->chapters_input_file = i;
+ break;
+ }
+ } else {
+ av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n",
+ o->chapters_input_file);
+ exit_program(1);
+ }
+ }
+ if (o->chapters_input_file >= 0)
+ copy_chapters(input_files[o->chapters_input_file], of,
+ !o->metadata_chapters_manual);
+
+ /* copy global metadata by default */
+ if (!o->metadata_global_manual && nb_input_files){
+ av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata,
+ AV_DICT_DONT_OVERWRITE);
+ if(o->recording_time != INT64_MAX)
+ av_dict_set(&oc->metadata, "duration", NULL, 0);
+ av_dict_set(&oc->metadata, "creation_time", NULL, 0);
+ }
+ if (!o->metadata_streams_manual)
+ for (i = of->ost_index; i < nb_output_streams; i++) {
+ InputStream *ist;
+ if (output_streams[i]->source_index < 0) /* this is true e.g. for attached files */
+ continue;
+ ist = input_streams[output_streams[i]->source_index];
+ av_dict_copy(&output_streams[i]->st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
+ }
+
+ /* process manually set metadata */
+ for (i = 0; i < o->nb_metadata; i++) {
+ AVDictionary **m;
+ char type, *val;
+ const char *stream_spec;
+ int index = 0, j, ret = 0;
+
+ val = strchr(o->metadata[i].u.str, '=');
+ if (!val) {
+ av_log(NULL, AV_LOG_FATAL, "No '=' character in metadata string %s.\n",
+ o->metadata[i].u.str);
+ exit_program(1);
+ }
+ *val++ = 0;
+
+ parse_meta_type(o->metadata[i].specifier, &type, &index, &stream_spec);
+ if (type == 's') {
+ for (j = 0; j < oc->nb_streams; j++) {
+ if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {
+ av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);
+ } else if (ret < 0)
+ exit_program(1);
+ }
+ }
+ else {
+ switch (type) {
+ case 'g':
+ m = &oc->metadata;
+ break;
+ case 'c':
+ if (index < 0 || index >= oc->nb_chapters) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
+ exit_program(1);
+ }
+ m = &oc->chapters[index]->metadata;
+ break;
+ default:
+ av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
+ exit_program(1);
+ }
+ av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
+ }
+ }
+
+ return 0;
+}
+
+static int opt_target(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ enum { PAL, NTSC, FILM, UNKNOWN } norm = UNKNOWN;
+ static const char *const frame_rates[] = { "25", "30000/1001", "24000/1001" };
+
+ if (!strncmp(arg, "pal-", 4)) {
+ norm = PAL;
+ arg += 4;
+ } else if (!strncmp(arg, "ntsc-", 5)) {
+ norm = NTSC;
+ arg += 5;
+ } else if (!strncmp(arg, "film-", 5)) {
+ norm = FILM;
+ arg += 5;
+ } else {
+ /* Try to determine PAL/NTSC by peeking in the input files */
+ if (nb_input_files) {
+ int i, j, fr;
+ for (j = 0; j < nb_input_files; j++) {
+ for (i = 0; i < input_files[j]->nb_streams; i++) {
+ AVCodecContext *c = input_files[j]->ctx->streams[i]->codec;
+ if (c->codec_type != AVMEDIA_TYPE_VIDEO)
+ continue;
+ fr = c->time_base.den * 1000 / c->time_base.num;
+ if (fr == 25000) {
+ norm = PAL;
+ break;
+ } else if ((fr == 29970) || (fr == 23976)) {
+ norm = NTSC;
+ break;
+ }
+ }
+ if (norm != UNKNOWN)
+ break;
+ }
+ }
+ if (norm != UNKNOWN)
+ av_log(NULL, AV_LOG_INFO, "Assuming %s for target.\n", norm == PAL ? "PAL" : "NTSC");
+ }
+
+ if (norm == UNKNOWN) {
+ av_log(NULL, AV_LOG_FATAL, "Could not determine norm (PAL/NTSC/NTSC-Film) for target.\n");
+ av_log(NULL, AV_LOG_FATAL, "Please prefix target with \"pal-\", \"ntsc-\" or \"film-\",\n");
+ av_log(NULL, AV_LOG_FATAL, "or set a framerate with \"-r xxx\".\n");
+ exit_program(1);
+ }
+
+ if (!strcmp(arg, "vcd")) {
+ opt_video_codec(o, "c:v", "mpeg1video");
+ opt_audio_codec(o, "c:a", "mp2");
+ parse_option(o, "f", "vcd", options);
+ av_dict_set(&o->g->codec_opts, "b:v", arg, 0);
+
+ parse_option(o, "s", norm == PAL ? "352x288" : "352x240", options);
+ parse_option(o, "r", frame_rates[norm], options);
+ av_dict_set(&o->g->codec_opts, "g", norm == PAL ? "15" : "18", 0);
+
+ av_dict_set(&o->g->codec_opts, "b:v", "1150000", 0);
+ av_dict_set(&o->g->codec_opts, "maxrate", "1150000", 0);
+ av_dict_set(&o->g->codec_opts, "minrate", "1150000", 0);
+ av_dict_set(&o->g->codec_opts, "bufsize", "327680", 0); // 40*1024*8;
+
+ av_dict_set(&o->g->codec_opts, "b:a", "224000", 0);
+ parse_option(o, "ar", "44100", options);
+ parse_option(o, "ac", "2", options);
+
+ av_dict_set(&o->g->format_opts, "packetsize", "2324", 0);
+ av_dict_set(&o->g->format_opts, "muxrate", "1411200", 0); // 2352 * 75 * 8;
+
+ /* We have to offset the PTS, so that it is consistent with the SCR.
+ SCR starts at 36000, but the first two packs contain only padding
+ and the first pack from the other stream, respectively, may also have
+ been written before.
+ So the real data starts at SCR 36000+3*1200. */
+ o->mux_preload = (36000 + 3 * 1200) / 90000.0; // 0.44
+ } else if (!strcmp(arg, "svcd")) {
+
+ opt_video_codec(o, "c:v", "mpeg2video");
+ opt_audio_codec(o, "c:a", "mp2");
+ parse_option(o, "f", "svcd", options);
+
+ parse_option(o, "s", norm == PAL ? "480x576" : "480x480", options);
+ parse_option(o, "r", frame_rates[norm], options);
+ parse_option(o, "pix_fmt", "yuv420p", options);
+ av_dict_set(&o->g->codec_opts, "g", norm == PAL ? "15" : "18", 0);
+
+ av_dict_set(&o->g->codec_opts, "b:v", "2040000", 0);
+ av_dict_set(&o->g->codec_opts, "maxrate", "2516000", 0);
+ av_dict_set(&o->g->codec_opts, "minrate", "0", 0); // 1145000;
+ av_dict_set(&o->g->codec_opts, "bufsize", "1835008", 0); // 224*1024*8;
+ av_dict_set(&o->g->codec_opts, "scan_offset", "1", 0);
+
+ av_dict_set(&o->g->codec_opts, "b:a", "224000", 0);
+ parse_option(o, "ar", "44100", options);
+
+ av_dict_set(&o->g->format_opts, "packetsize", "2324", 0);
+
+ } else if (!strcmp(arg, "dvd")) {
+
+ opt_video_codec(o, "c:v", "mpeg2video");
+ opt_audio_codec(o, "c:a", "ac3");
+ parse_option(o, "f", "dvd", options);
+
+ parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
+ parse_option(o, "r", frame_rates[norm], options);
+ parse_option(o, "pix_fmt", "yuv420p", options);
+ av_dict_set(&o->g->codec_opts, "g", norm == PAL ? "15" : "18", 0);
+
+ av_dict_set(&o->g->codec_opts, "b:v", "6000000", 0);
+ av_dict_set(&o->g->codec_opts, "maxrate", "9000000", 0);
+ av_dict_set(&o->g->codec_opts, "minrate", "0", 0); // 1500000;
+ av_dict_set(&o->g->codec_opts, "bufsize", "1835008", 0); // 224*1024*8;
+
+ av_dict_set(&o->g->format_opts, "packetsize", "2048", 0); // from www.mpucoder.com: DVD sectors contain 2048 bytes of data, this is also the size of one pack.
+ av_dict_set(&o->g->format_opts, "muxrate", "10080000", 0); // from mplex project: data_rate = 1260000. mux_rate = data_rate * 8
+
+ av_dict_set(&o->g->codec_opts, "b:a", "448000", 0);
+ parse_option(o, "ar", "48000", options);
+
+ } else if (!strncmp(arg, "dv", 2)) {
+
+ parse_option(o, "f", "dv", options);
+
+ parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
+ parse_option(o, "pix_fmt", !strncmp(arg, "dv50", 4) ? "yuv422p" :
+ norm == PAL ? "yuv420p" : "yuv411p", options);
+ parse_option(o, "r", frame_rates[norm], options);
+
+ parse_option(o, "ar", "48000", options);
+ parse_option(o, "ac", "2", options);
+
+ } else {
+ av_log(NULL, AV_LOG_ERROR, "Unknown target: %s\n", arg);
+ return AVERROR(EINVAL);
+ }
+ return 0;
+}
+
+static int opt_vstats_file(void *optctx, const char *opt, const char *arg)
+{
+ av_free (vstats_filename);
+ vstats_filename = av_strdup (arg);
+ return 0;
+}
+
+static int opt_vstats(void *optctx, const char *opt, const char *arg)
+{
+ char filename[40];
+ time_t today2 = time(NULL);
+ struct tm *today = localtime(&today2);
+
+ snprintf(filename, sizeof(filename), "vstats_%02d%02d%02d.log", today->tm_hour, today->tm_min,
+ today->tm_sec);
+ return opt_vstats_file(NULL, opt, filename);
+}
+
+static int opt_video_frames(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "frames:v", arg, options);
+}
+
+static int opt_audio_frames(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "frames:a", arg, options);
+}
+
+static int opt_data_frames(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "frames:d", arg, options);
+}
+
+static int opt_default_new(OptionsContext *o, const char *opt, const char *arg)
+{
+ int ret;
+ AVDictionary *cbak = codec_opts;
+ AVDictionary *fbak = format_opts;
+ codec_opts = NULL;
+ format_opts = NULL;
+
+ ret = opt_default(NULL, opt, arg);
+
+ av_dict_copy(&o->g->codec_opts , codec_opts, 0);
+ av_dict_copy(&o->g->format_opts, format_opts, 0);
+ av_dict_free(&codec_opts);
+ av_dict_free(&format_opts);
+ codec_opts = cbak;
+ format_opts = fbak;
+
+ return ret;
+}
+
+static int opt_preset(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ FILE *f=NULL;
+ char filename[1000], line[1000], tmp_line[1000];
+ const char *codec_name = NULL;
+
+ tmp_line[0] = *opt;
+ tmp_line[1] = 0;
+ MATCH_PER_TYPE_OPT(codec_names, str, codec_name, NULL, tmp_line);
+
+ if (!(f = get_preset_file(filename, sizeof(filename), arg, *opt == 'f', codec_name))) {
+ if(!strncmp(arg, "libx264-lossless", strlen("libx264-lossless"))){
+ av_log(NULL, AV_LOG_FATAL, "Please use -preset <speed> -qp 0\n");
+ }else
+ av_log(NULL, AV_LOG_FATAL, "File for preset '%s' not found\n", arg);
+ exit_program(1);
+ }
+
+ while (fgets(line, sizeof(line), f)) {
+ char *key = tmp_line, *value, *endptr;
+
+ if (strcspn(line, "#\n\r") == 0)
+ continue;
+ av_strlcpy(tmp_line, line, sizeof(tmp_line));
+ if (!av_strtok(key, "=", &value) ||
+ !av_strtok(value, "\r\n", &endptr)) {
+ av_log(NULL, AV_LOG_FATAL, "%s: Invalid syntax: '%s'\n", filename, line);
+ exit_program(1);
+ }
+ av_log(NULL, AV_LOG_DEBUG, "ffpreset[%s]: set '%s' = '%s'\n", filename, key, value);
+
+ if (!strcmp(key, "acodec")) opt_audio_codec (o, key, value);
+ else if (!strcmp(key, "vcodec")) opt_video_codec (o, key, value);
+ else if (!strcmp(key, "scodec")) opt_subtitle_codec(o, key, value);
+ else if (!strcmp(key, "dcodec")) opt_data_codec (o, key, value);
+ else if (opt_default_new(o, key, value) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n",
+ filename, line, key, value);
+ exit_program(1);
+ }
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+static int opt_old2new(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ char *s = av_asprintf("%s:%c", opt + 1, *opt);
+ int ret = parse_option(o, s, arg, options);
+ av_free(s);
+ return ret;
+}
+
+static int opt_bitrate(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ if(!strcmp(opt, "b")){
+ av_log(NULL, AV_LOG_WARNING, "Please use -b:a or -b:v, -b is ambiguous\n");
+ av_dict_set(&o->g->codec_opts, "b:v", arg, 0);
+ return 0;
+ }
+ av_dict_set(&o->g->codec_opts, opt, arg, 0);
+ return 0;
+}
+
+static int opt_qscale(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ char *s;
+ int ret;
+ if(!strcmp(opt, "qscale")){
+ av_log(NULL, AV_LOG_WARNING, "Please use -q:a or -q:v, -qscale is ambiguous\n");
+ return parse_option(o, "q:v", arg, options);
+ }
+ s = av_asprintf("q%s", opt + 6);
+ ret = parse_option(o, s, arg, options);
+ av_free(s);
+ return ret;
+}
+
+static int opt_profile(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ if(!strcmp(opt, "profile")){
+ av_log(NULL, AV_LOG_WARNING, "Please use -profile:a or -profile:v, -profile is ambiguous\n");
+ av_dict_set(&o->g->codec_opts, "profile:v", arg, 0);
+ return 0;
+ }
+ av_dict_set(&o->g->codec_opts, opt, arg, 0);
+ return 0;
+}
+
+static int opt_video_filters(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "filter:v", arg, options);
+}
+
+static int opt_audio_filters(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "filter:a", arg, options);
+}
+
+static int opt_vsync(void *optctx, const char *opt, const char *arg)
+{
+ if (!av_strcasecmp(arg, "cfr")) video_sync_method = VSYNC_CFR;
+ else if (!av_strcasecmp(arg, "vfr")) video_sync_method = VSYNC_VFR;
+ else if (!av_strcasecmp(arg, "passthrough")) video_sync_method = VSYNC_PASSTHROUGH;
+ else if (!av_strcasecmp(arg, "drop")) video_sync_method = VSYNC_DROP;
+
+ if (video_sync_method == VSYNC_AUTO)
+ video_sync_method = parse_number_or_die("vsync", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);
+ return 0;
+}
+
+static int opt_timecode(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ char *tcr = av_asprintf("timecode=%s", arg);
+ int ret = parse_option(o, "metadata:g", tcr, options);
+ if (ret >= 0)
+ ret = av_dict_set(&o->g->codec_opts, "gop_timecode", arg, 0);
+ av_free(tcr);
+ return 0;
+}
+
+static int opt_channel_layout(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ char layout_str[32];
+ char *stream_str;
+ char *ac_str;
+ int ret, channels, ac_str_size;
+ uint64_t layout;
+
+ layout = av_get_channel_layout(arg);
+ if (!layout) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown channel layout: %s\n", arg);
+ return AVERROR(EINVAL);
+ }
+ snprintf(layout_str, sizeof(layout_str), "%"PRIu64, layout);
+ ret = opt_default_new(o, opt, layout_str);
+ if (ret < 0)
+ return ret;
+
+ /* set 'ac' option based on channel layout */
+ channels = av_get_channel_layout_nb_channels(layout);
+ snprintf(layout_str, sizeof(layout_str), "%d", channels);
+ stream_str = strchr(opt, ':');
+ ac_str_size = 3 + (stream_str ? strlen(stream_str) : 0);
+ ac_str = av_mallocz(ac_str_size);
+ if (!ac_str)
+ return AVERROR(ENOMEM);
+ av_strlcpy(ac_str, "ac", 3);
+ if (stream_str)
+ av_strlcat(ac_str, stream_str, ac_str_size);
+ ret = parse_option(o, ac_str, layout_str, options);
+ av_free(ac_str);
+
+ return ret;
+}
+
+static int opt_audio_qscale(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "q:a", arg, options);
+}
+
+static int opt_filter_complex(void *optctx, const char *opt, const char *arg)
+{
+ GROW_ARRAY(filtergraphs, nb_filtergraphs);
+ if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
+ return AVERROR(ENOMEM);
+ filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
+ filtergraphs[nb_filtergraphs - 1]->graph_desc = av_strdup(arg);
+ if (!filtergraphs[nb_filtergraphs - 1]->graph_desc)
+ return AVERROR(ENOMEM);
+ return 0;
+}
+
+static int opt_filter_complex_script(void *optctx, const char *opt, const char *arg)
+{
+ uint8_t *graph_desc = read_file(arg);
+ if (!graph_desc)
+ return AVERROR(EINVAL);
+
+ GROW_ARRAY(filtergraphs, nb_filtergraphs);
+ if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
+ return AVERROR(ENOMEM);
+ filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
+ filtergraphs[nb_filtergraphs - 1]->graph_desc = graph_desc;
+ return 0;
+}
+
+void show_help_default(const char *opt, const char *arg)
+{
+ /* per-file options have at least one of those set */
+ const int per_file = OPT_SPEC | OPT_OFFSET | OPT_PERFILE;
+ int show_advanced = 0, show_avoptions = 0;
+
+ if (opt && *opt) {
+ if (!strcmp(opt, "long"))
+ show_advanced = 1;
+ else if (!strcmp(opt, "full"))
+ show_advanced = show_avoptions = 1;
+ else
+ av_log(NULL, AV_LOG_ERROR, "Unknown help option '%s'.\n", opt);
+ }
+
+ show_usage();
+
+ printf("Getting help:\n"
+ " -h -- print basic options\n"
+ " -h long -- print more options\n"
+ " -h full -- print all options (including all format and codec specific options, very long)\n"
+ " See man %s for detailed description of the options.\n"
+ "\n", program_name);
+
+ show_help_options(options, "Print help / information / capabilities:",
+ OPT_EXIT, 0, 0);
+
+ show_help_options(options, "Global options (affect whole program "
+ "instead of just one file:",
+ 0, per_file | OPT_EXIT | OPT_EXPERT, 0);
+ if (show_advanced)
+ show_help_options(options, "Advanced global options:", OPT_EXPERT,
+ per_file | OPT_EXIT, 0);
+
+ show_help_options(options, "Per-file main options:", 0,
+ OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE |
+ OPT_EXIT, per_file);
+ if (show_advanced)
+ show_help_options(options, "Advanced per-file options:",
+ OPT_EXPERT, OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE, per_file);
+
+ show_help_options(options, "Video options:",
+ OPT_VIDEO, OPT_EXPERT | OPT_AUDIO, 0);
+ if (show_advanced)
+ show_help_options(options, "Advanced Video options:",
+ OPT_EXPERT | OPT_VIDEO, OPT_AUDIO, 0);
+
+ show_help_options(options, "Audio options:",
+ OPT_AUDIO, OPT_EXPERT | OPT_VIDEO, 0);
+ if (show_advanced)
+ show_help_options(options, "Advanced Audio options:",
+ OPT_EXPERT | OPT_AUDIO, OPT_VIDEO, 0);
+ show_help_options(options, "Subtitle options:",
+ OPT_SUBTITLE, 0, 0);
+ printf("\n");
+
+ if (show_avoptions) {
+ int flags = AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM;
+ show_help_children(avcodec_get_class(), flags);
+ show_help_children(avformat_get_class(), flags);
+#if CONFIG_SWSCALE
+ show_help_children(sws_get_class(), flags);
+#endif
+ show_help_children(swr_get_class(), AV_OPT_FLAG_AUDIO_PARAM);
+ show_help_children(avfilter_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM);
+ }
+}
+
+void show_usage(void)
+{
+ av_log(NULL, AV_LOG_INFO, "Hyper fast Audio and Video encoder\n");
+ av_log(NULL, AV_LOG_INFO, "usage: %s [options] [[infile options] -i infile]... {[outfile options] outfile}...\n", program_name);
+ av_log(NULL, AV_LOG_INFO, "\n");
+}
+
+enum OptGroup {
+ GROUP_OUTFILE,
+ GROUP_INFILE,
+};
+
+static const OptionGroupDef groups[] = {
+ [GROUP_OUTFILE] = { "output file", NULL, OPT_OUTPUT },
+ [GROUP_INFILE] = { "input file", "i", OPT_INPUT },
+};
+
+static int open_files(OptionGroupList *l, const char *inout,
+ int (*open_file)(OptionsContext*, const char*))
+{
+ int i, ret;
+
+ for (i = 0; i < l->nb_groups; i++) {
+ OptionGroup *g = &l->groups[i];
+ OptionsContext o;
+
+ init_options(&o);
+ o.g = g;
+
+ ret = parse_optgroup(&o, g);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error parsing options for %s file "
+ "%s.\n", inout, g->arg);
+ return ret;
+ }
+
+ av_log(NULL, AV_LOG_DEBUG, "Opening an %s file: %s.\n", inout, g->arg);
+ ret = open_file(&o, g->arg);
+ uninit_options(&o);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error opening %s file %s.\n",
+ inout, g->arg);
+ return ret;
+ }
+ av_log(NULL, AV_LOG_DEBUG, "Successfully opened the file.\n");
+ }
+
+ return 0;
+}
+
+int ffmpeg_parse_options(int argc, char **argv)
+{
+ OptionParseContext octx;
+ uint8_t error[128];
+ int ret;
+
+ memset(&octx, 0, sizeof(octx));
+
+ /* split the commandline into an internal representation */
+ ret = split_commandline(&octx, argc, argv, options, groups,
+ FF_ARRAY_ELEMS(groups));
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error splitting the argument list: ");
+ goto fail;
+ }
+
+ /* apply global options */
+ ret = parse_optgroup(NULL, &octx.global_opts);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error parsing global options: ");
+ goto fail;
+ }
+
+ /* open input files */
+ ret = open_files(&octx.groups[GROUP_INFILE], "input", open_input_file);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error opening input files: ");
+ goto fail;
+ }
+
+ /* open output files */
+ ret = open_files(&octx.groups[GROUP_OUTFILE], "output", open_output_file);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error opening output files: ");
+ goto fail;
+ }
+
+fail:
+ uninit_parse_context(&octx);
+ if (ret < 0) {
+ av_strerror(ret, error, sizeof(error));
+ av_log(NULL, AV_LOG_FATAL, "%s\n", error);
+ }
+ return ret;
+}
+
+static int opt_progress(void *optctx, const char *opt, const char *arg)
+{
+ AVIOContext *avio = NULL;
+ int ret;
+
+ if (!strcmp(arg, "-"))
+ arg = "pipe:";
+ ret = avio_open2(&avio, arg, AVIO_FLAG_WRITE, &int_cb, NULL);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Failed to open progress URL \"%s\": %s\n",
+ arg, av_err2str(ret));
+ return ret;
+ }
+ progress_avio = avio;
+ return 0;
+}
+
+#define OFFSET(x) offsetof(OptionsContext, x)
+const OptionDef options[] = {
+ /* main options */
+#include "cmdutils_common_opts.h"
+ { "f", HAS_ARG | OPT_STRING | OPT_OFFSET |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(format) },
+ "force format", "fmt" },
+ { "y", OPT_BOOL, { &file_overwrite },
+ "overwrite output files" },
+ { "n", OPT_BOOL, { &no_file_overwrite },
+ "never overwrite output files" },
+ { "c", HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(codec_names) },
+ "codec name", "codec" },
+ { "codec", HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(codec_names) },
+ "codec name", "codec" },
+ { "pre", HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(presets) },
+ "preset name", "preset" },
+ { "map", HAS_ARG | OPT_EXPERT | OPT_PERFILE |
+ OPT_OUTPUT, { .func_arg = opt_map },
+ "set input stream mapping",
+ "[-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]]" },
+ { "map_channel", HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_map_channel },
+ "map an audio channel from one stream to another", "file.stream.channel[:syncfile.syncstream]" },
+ { "map_metadata", HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(metadata_map) },
+ "set metadata information of outfile from infile",
+ "outfile[,metadata]:infile[,metadata]" },
+ { "map_chapters", HAS_ARG | OPT_INT | OPT_EXPERT | OPT_OFFSET |
+ OPT_OUTPUT, { .off = OFFSET(chapters_input_file) },
+ "set chapters mapping", "input_file_index" },
+ { "t", HAS_ARG | OPT_TIME | OPT_OFFSET |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(recording_time) },
+ "record or transcode \"duration\" seconds of audio/video",
+ "duration" },
+ { "to", HAS_ARG | OPT_TIME | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(stop_time) },
+ "record or transcode stop time", "time_stop" },
+ { "fs", HAS_ARG | OPT_INT64 | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(limit_filesize) },
+ "set the limit file size in bytes", "limit_size" },
+ { "ss", HAS_ARG | OPT_TIME | OPT_OFFSET |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(start_time) },
+ "set the start time offset", "time_off" },
+ { "accurate_seek", OPT_BOOL | OPT_OFFSET | OPT_EXPERT |
+ OPT_INPUT, { .off = OFFSET(accurate_seek) },
+ "enable/disable accurate seeking with -ss" },
+ { "itsoffset", HAS_ARG | OPT_TIME | OPT_OFFSET |
+ OPT_EXPERT | OPT_INPUT, { .off = OFFSET(input_ts_offset) },
+ "set the input ts offset", "time_off" },
+ { "itsscale", HAS_ARG | OPT_DOUBLE | OPT_SPEC |
+ OPT_EXPERT | OPT_INPUT, { .off = OFFSET(ts_scale) },
+ "set the input ts scale", "scale" },
+ { "timestamp", HAS_ARG | OPT_PERFILE, { .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" },
+ { "benchmark", OPT_BOOL | OPT_EXPERT, { &do_benchmark },
+ "add timings for benchmarking" },
+ { "benchmark_all", OPT_BOOL | OPT_EXPERT, { &do_benchmark_all },
+ "add timings for each task" },
+ { "progress", HAS_ARG | OPT_EXPERT, { .func_arg = opt_progress },
+ "write program-readable progress information", "url" },
+ { "stdin", OPT_BOOL | OPT_EXPERT, { &stdin_interaction },
+ "enable or disable interaction on standard input" },
+ { "timelimit", HAS_ARG | OPT_EXPERT, { .func_arg = opt_timelimit },
+ "set max runtime in seconds", "limit" },
+ { "dump", OPT_BOOL | OPT_EXPERT, { &do_pkt_dump },
+ "dump each input packet" },
+ { "hex", OPT_BOOL | OPT_EXPERT, { &do_hex_dump },
+ "when dumping packets, also dump the payload" },
+ { "re", OPT_BOOL | OPT_EXPERT | OPT_OFFSET |
+ OPT_INPUT, { .off = OFFSET(rate_emu) },
+ "read input at native frame rate", "" },
+ { "target", HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_target },
+ "specify target file type (\"vcd\", \"svcd\", \"dvd\","
+ " \"dv\", \"dv50\", \"pal-vcd\", \"ntsc-svcd\", ...)", "type" },
+ { "vsync", HAS_ARG | OPT_EXPERT, { opt_vsync },
+ "video sync method", "" },
+ { "async", HAS_ARG | OPT_INT | OPT_EXPERT, { &audio_sync_method },
+ "audio sync method", "" },
+ { "adrift_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &audio_drift_threshold },
+ "audio drift threshold", "threshold" },
+ { "copyts", OPT_BOOL | OPT_EXPERT, { &copy_ts },
+ "copy timestamps" },
+ { "copytb", 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" },
+ { "tag", OPT_STRING | HAS_ARG | OPT_SPEC |
+ OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(codec_tags) },
+ "force codec tag/fourcc", "fourcc/tag" },
+ { "q", HAS_ARG | OPT_EXPERT | OPT_DOUBLE |
+ OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(qscale) },
+ "use fixed quality scale (VBR)", "q" },
+ { "qscale", HAS_ARG | OPT_EXPERT | OPT_PERFILE |
+ OPT_OUTPUT, { .func_arg = opt_qscale },
+ "use fixed quality scale (VBR)", "q" },
+ { "profile", HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_profile },
+ "set profile", "profile" },
+ { "filter", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filters) },
+ "set stream filtergraph", "filter_graph" },
+ { "filter_script", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filter_scripts) },
+ "read stream filtergraph description from a file", "filename" },
+ { "reinit_filter", HAS_ARG | OPT_INT | OPT_SPEC | OPT_INPUT, { .off = OFFSET(reinit_filters) },
+ "reinit filtergraph on input parameter changes", "" },
+ { "filter_complex", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex },
+ "create a complex filtergraph", "graph_description" },
+ { "lavfi", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex },
+ "create a complex filtergraph", "graph_description" },
+ { "filter_complex_script", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex_script },
+ "read complex filtergraph description from a file", "filename" },
+ { "stats", OPT_BOOL, { &print_stats },
+ "print progress report during encoding", },
+ { "attach", HAS_ARG | OPT_PERFILE | OPT_EXPERT |
+ OPT_OUTPUT, { .func_arg = opt_attach },
+ "add an attachment to the output file", "filename" },
+ { "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_EXPERT | OPT_INPUT, { .off = OFFSET(dump_attachment) },
+ "extract an attachment into a file", "filename" },
+ { "debug_ts", OPT_BOOL | OPT_EXPERT, { &debug_ts },
+ "print timestamp debugging info" },
+ { "max_error_rate", HAS_ARG | OPT_FLOAT, { &max_error_rate },
+ "maximum error rate", "ratio of errors (0.0: no errors, 1.0: 100% errors) above which ffmpeg returns an error instead of success." },
+
+ /* video options */
+ { "vframes", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_frames },
+ "set the number of video frames to record", "number" },
+ { "r", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_rates) },
+ "set frame rate (Hz value, fraction or abbreviation)", "rate" },
+ { "s", OPT_VIDEO | HAS_ARG | OPT_SUBTITLE | OPT_STRING | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_sizes) },
+ "set frame size (WxH or abbreviation)", "size" },
+ { "aspect", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(frame_aspect_ratios) },
+ "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" },
+ { "pix_fmt", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_pix_fmts) },
+ "set pixel format", "format" },
+ { "bits_per_raw_sample", OPT_VIDEO | OPT_INT | HAS_ARG, { &frame_bits_per_raw_sample },
+ "set the number of bits per raw sample", "number" },
+ { "intra", OPT_VIDEO | OPT_BOOL | OPT_EXPERT, { &intra_only },
+ "deprecated use -g 1" },
+ { "vn", OPT_VIDEO | OPT_BOOL | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,{ .off = OFFSET(video_disable) },
+ "disable video" },
+ { "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 to 3)", "n" },
+ { "passlogfile", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(passlogfiles) },
+ "select two pass log file name prefix", "prefix" },
+ { "deinterlace", OPT_VIDEO | OPT_BOOL | OPT_EXPERT, { &do_deinterlace },
+ "this option is deprecated, use the yadif filter instead" },
+ { "psnr", OPT_VIDEO | OPT_BOOL | OPT_EXPERT, { &do_psnr },
+ "calculate PSNR of compressed frames" },
+ { "vstats", OPT_VIDEO | OPT_EXPERT , { &opt_vstats },
+ "dump video coding statistics to file" },
+ { "vstats_file", OPT_VIDEO | HAS_ARG | OPT_EXPERT , { opt_vstats_file },
+ "dump video coding statistics to file", "file" },
+ { "vf", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_filters },
+ "set video filters", "filter_graph" },
+ { "intra_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(intra_matrices) },
+ "specify intra matrix coeffs", "matrix" },
+ { "inter_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(inter_matrices) },
+ "specify inter matrix coeffs", "matrix" },
+ { "top", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_INT| OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(top_field_first) },
+ "top=1/bottom=0/auto=-1 field first", "" },
+ { "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_old2new },
+ "force video tag/fourcc", "fourcc/tag" },
+ { "qphist", OPT_VIDEO | OPT_BOOL | OPT_EXPERT , { &qp_hist },
+ "show QP histogram" },
+ { "force_fps", OPT_VIDEO | OPT_BOOL | OPT_EXPERT | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(force_fps) },
+ "force the selected framerate, disable the best supported framerate selection" },
+ { "streamid", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
+ OPT_OUTPUT, { .func_arg = opt_streamid },
+ "set the value of an outfile streamid", "streamIndex:value" },
+ { "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
+ OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(forced_key_frames) },
+ "force key frames at specified timestamps", "timestamps" },
+ { "b", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_bitrate },
+ "video bitrate (please use -b:v)", "bitrate" },
+
+ /* audio options */
+ { "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_frames },
+ "set the number of audio frames to record", "number" },
+ { "aq", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_qscale },
+ "set audio quality (codec-specific)", "quality", },
+ { "ar", OPT_AUDIO | HAS_ARG | OPT_INT | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(audio_sample_rate) },
+ "set audio sampling rate (in Hz)", "rate" },
+ { "ac", OPT_AUDIO | HAS_ARG | OPT_INT | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(audio_channels) },
+ "set number of audio channels", "channels" },
+ { "an", OPT_AUDIO | OPT_BOOL | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,{ .off = OFFSET(audio_disable) },
+ "disable audio" },
+ { "acodec", OPT_AUDIO | HAS_ARG | OPT_PERFILE |
+ OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_audio_codec },
+ "force audio codec ('copy' to copy stream)", "codec" },
+ { "atag", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
+ OPT_OUTPUT, { .func_arg = opt_old2new },
+ "force audio tag/fourcc", "fourcc/tag" },
+ { "vol", OPT_AUDIO | HAS_ARG | OPT_INT, { &audio_volume },
+ "change audio volume (256=normal)" , "volume" },
+ { "sample_fmt", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_SPEC |
+ OPT_STRING | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(sample_fmts) },
+ "set sample format", "format" },
+ { "channel_layout", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
+ OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_channel_layout },
+ "set channel layout", "layout" },
+ { "af", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_filters },
+ "set audio filters", "filter_graph" },
+ { "guess_layout_max", OPT_AUDIO | HAS_ARG | OPT_INT | OPT_SPEC | OPT_EXPERT | OPT_INPUT, { .off = OFFSET(guess_layout_max) },
+ "set the maximum number of channels to try to guess the channel layout" },
+
+ /* subtitle options */
+ { "sn", OPT_SUBTITLE | OPT_BOOL | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(subtitle_disable) },
+ "disable subtitle" },
+ { "scodec", OPT_SUBTITLE | HAS_ARG | OPT_PERFILE | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_subtitle_codec },
+ "force subtitle codec ('copy' to copy stream)", "codec" },
+ { "stag", OPT_SUBTITLE | HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_old2new }
+ , "force subtitle tag/fourcc", "fourcc/tag" },
+ { "fix_sub_duration", OPT_BOOL | OPT_EXPERT | OPT_SUBTITLE | OPT_SPEC | OPT_INPUT, { .off = OFFSET(fix_sub_duration) },
+ "fix subtitles duration" },
+ { "canvas_size", OPT_SUBTITLE | HAS_ARG | OPT_STRING | OPT_SPEC | OPT_INPUT, { .off = OFFSET(canvas_sizes) },
+ "set canvas size (WxH or abbreviation)", "size" },
+
+ /* grab options */
+ { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_channel },
+ "deprecated, use -channel", "channel" },
+ { "tvstd", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_standard },
+ "deprecated, use -standard", "standard" },
+ { "isync", OPT_BOOL | OPT_EXPERT, { &input_sync }, "this option is deprecated and does nothing", "" },
+
+ /* muxer options */
+ { "muxdelay", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_max_delay) },
+ "set the maximum demux-decode delay", "seconds" },
+ { "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_preload) },
+ "set the initial demux-decode delay", "seconds" },
+ { "override_ffserver", OPT_BOOL | OPT_EXPERT | OPT_OUTPUT, { &override_ffserver },
+ "override the options from ffserver", "" },
+
+ { "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/ffplay.c b/ffplay.c
new file mode 100644
index 0000000..5d3d189
--- a/dev/null
+++ b/ffplay.c
@@ -0,0 +1,3628 @@
+/*
+ * 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 "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
+
+/* 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 minimum AV sync threshold */
+#define AV_SYNC_THRESHOLD_MIN 0.01
+/* 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 4
+
+typedef struct VideoPicture {
+ double pts; // presentation timestamp for this picture
+ int64_t pos; // byte position in file
+ SDL_Overlay *bmp;
+ int width, height; /* source height & width */
+ int allocated;
+ int reallocate;
+ int serial;
+
+ AVRational sar;
+} VideoPicture;
+
+typedef struct SubPicture {
+ double pts; /* presentation time stamp for this picture */
+ AVSubtitle sub;
+ int serial;
+} SubPicture;
+
+typedef struct AudioParams {
+ int freq;
+ int channels;
+ int64_t channel_layout;
+ enum AVSampleFormat fmt;
+} 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;
+
+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 *read_tid;
+ SDL_Thread *video_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;
+ int audio_finished;
+ int video_finished;
+
+ Clock audclk;
+ Clock vidclk;
+ Clock extclk;
+
+ 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_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;
+ int audio_buf_frames_pending;
+ AVPacket audio_pkt_temp;
+ AVPacket audio_pkt;
+ int audio_pkt_temp_serial;
+ int audio_last_serial;
+ 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;
+ AVFrame *frame;
+ int64_t audio_frame_next_pts;
+
+ 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;
+ 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_duration;
+ double frame_last_dropped_pts;
+ double frame_last_returned_time;
+ double frame_last_filter_delay;
+ int64_t frame_last_dropped_pos;
+ int frame_last_dropped_serial;
+ int video_stream;
+ AVStream *video_st;
+ PacketQueue videoq;
+ int64_t video_current_pos; // current displayed file pos
+ double max_frame_duration; // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity
+ 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
+ SDL_Rect last_display_rect;
+
+ char filename[1024];
+ int width, height, xleft, ytop;
+ int step;
+
+#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
+ 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 workaround_bugs = 1;
+static int fast = 0;
+static int genpts = 0;
+static int lowres = 0;
+static int error_concealment = 3;
+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 char *vfilters = NULL;
+static char *afilters = NULL;
+#endif
+
+/* 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;
+
+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 int packet_queue_put(PacketQueue *q, AVPacket *pkt);
+
+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 != 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_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 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(VideoPicture *vp)
+{
+ if (vp->bmp) {
+ SDL_FreeYUVOverlay(vp->bmp);
+ vp->bmp = NULL;
+ }
+}
+
+static void free_subpicture(SubPicture *sp)
+{
+ avsubtitle_free(&sp->sub);
+}
+
+static void calculate_display_rect(SDL_Rect *rect, int scr_xleft, int scr_ytop, int scr_width, int scr_height, VideoPicture *vp)
+{
+ float aspect_ratio;
+ int width, height, x, y;
+
+ if (vp->sar.num == 0)
+ aspect_ratio = 0;
+ else
+ aspect_ratio = av_q2d(vp->sar);
+
+ if (aspect_ratio <= 0.0)
+ aspect_ratio = 1.0;
+ aspect_ratio *= (float)vp->width / (float)vp->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)
+{
+ VideoPicture *vp;
+ SubPicture *sp;
+ AVPicture pict;
+ SDL_Rect rect;
+ int i;
+
+ vp = &is->pictq[is->pictq_rindex];
+ if (vp->bmp) {
+ 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);
+ }
+ }
+ }
+
+ calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp);
+
+ 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() - 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(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, 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)
+{
+ int i;
+ /* 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 */
+ for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
+ free_picture(&is->pictq[i]);
+ for (i = 0; i < SUBPICTURE_QUEUE_SIZE; i++)
+ free_subpicture(&is->subpq[i]);
+ SDL_DestroyMutex(is->pictq_mutex);
+ SDL_DestroyCond(is->pictq_cond);
+ SDL_DestroyMutex(is->subpq_mutex);
+ SDL_DestroyCond(is->subpq_cond);
+ 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);
+#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 int video_open(VideoState *is, int force_set_video_mode, VideoPicture *vp)
+{
+ int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
+ int w,h;
+ SDL_Rect rect;
+
+ if (is_full_screen) flags |= SDL_FULLSCREEN;
+ else flags |= SDL_RESIZABLE;
+
+ if (vp && vp->width) {
+ calculate_display_rect(&rect, 0, 0, INT_MAX, vp->height, vp);
+ default_width = rect.w;
+ default_height = rect.h;
+ }
+
+ 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() / 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() / 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() / 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 void pictq_next_picture(VideoState *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);
+}
+
+static int pictq_prev_picture(VideoState *is) {
+ VideoPicture *prevvp;
+ int ret = 0;
+ /* update queue size and signal for the previous picture */
+ prevvp = &is->pictq[(is->pictq_rindex + VIDEO_PICTURE_QUEUE_SIZE - 1) % VIDEO_PICTURE_QUEUE_SIZE];
+ if (prevvp->allocated && prevvp->serial == is->videoq.serial) {
+ SDL_LockMutex(is->pictq_mutex);
+ if (is->pictq_size < VIDEO_PICTURE_QUEUE_SIZE) {
+ if (--is->pictq_rindex == -1)
+ is->pictq_rindex = VIDEO_PICTURE_QUEUE_SIZE - 1;
+ is->pictq_size++;
+ ret = 1;
+ }
+ SDL_CondSignal(is->pictq_cond);
+ SDL_UnlockMutex(is->pictq_mutex);
+ }
+ return ret;
+}
+
+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);
+ is->video_current_pos = pos;
+ is->frame_last_pts = pts;
+}
+
+/* called to display each frame */
+static void video_refresh(void *opaque, double *remaining_time)
+{
+ VideoState *is = opaque;
+ VideoPicture *vp;
+ double time;
+
+ SubPicture *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() / 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 = pictq_prev_picture(is);
+retry:
+ if (is->pictq_size == 0) {
+ SDL_LockMutex(is->pictq_mutex);
+ if (is->frame_last_dropped_pts != AV_NOPTS_VALUE && is->frame_last_dropped_pts > is->frame_last_pts) {
+ update_video_pts(is, is->frame_last_dropped_pts, is->frame_last_dropped_pos, is->frame_last_dropped_serial);
+ is->frame_last_dropped_pts = AV_NOPTS_VALUE;
+ }
+ SDL_UnlockMutex(is->pictq_mutex);
+ // nothing to do, no picture to display in the queue
+ } else {
+ double last_duration, duration, delay;
+ /* dequeue the picture */
+ vp = &is->pictq[is->pictq_rindex];
+
+ if (vp->serial != is->videoq.serial) {
+ pictq_next_picture(is);
+ redisplay = 0;
+ goto retry;
+ }
+
+ if (is->paused)
+ goto display;
+
+ /* compute nominal last_duration */
+ last_duration = vp->pts - is->frame_last_pts;
+ if (!isnan(last_duration) && last_duration > 0 && last_duration < is->max_frame_duration) {
+ /* if duration of the last frame was sane, update last_duration in video state */
+ is->frame_last_duration = last_duration;
+ }
+ if (redisplay)
+ delay = 0.0;
+ else
+ delay = compute_target_delay(is->frame_last_duration, is);
+
+ time= av_gettime()/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 (is->pictq_size > 1) {
+ VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + 1) % VIDEO_PICTURE_QUEUE_SIZE];
+ duration = nextvp->pts - vp->pts;
+ 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++;
+ pictq_next_picture(is);
+ redisplay = 0;
+ goto retry;
+ }
+ }
+
+ if (is->subtitle_st) {
+ while (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 (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))))
+ {
+ 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);
+ } else {
+ break;
+ }
+ }
+ }
+
+display:
+ /* display picture */
+ if (!display_disable && is->show_mode == SHOW_MODE_VIDEO)
+ video_display(is);
+
+ pictq_next_picture(is);
+
+ 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();
+ 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)
+{
+ VideoPicture *vp;
+ int64_t bufferdiff;
+
+ vp = &is->pictq[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, int64_t pos, int serial)
+{
+ VideoPicture *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
+
+ /* wait until we have space to put a new picture */
+ SDL_LockMutex(is->pictq_mutex);
+
+ /* keep the last already displayed picture in the queue */
+ while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE - 1 &&
+ !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 || !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) {
+ 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 == NULL) {
+ 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->pos = pos;
+ vp->serial = serial;
+
+ /* now we can update the picture count */
+ if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE)
+ is->pictq_windex = 0;
+ SDL_LockMutex(is->pictq_mutex);
+ is->pictq_size++;
+ SDL_UnlockMutex(is->pictq_mutex);
+ }
+ return 0;
+}
+
+static int get_video_frame(VideoState *is, AVFrame *frame, AVPacket *pkt, int *serial)
+{
+ int got_picture;
+
+ if (packet_queue_get(&is->videoq, pkt, 1, serial) < 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 queue but that's harder)
+ while (is->pictq_size && !is->videoq.abort_request) {
+ SDL_CondWait(is->pictq_cond, is->pictq_mutex);
+ }
+ is->video_current_pos = -1;
+ is->frame_last_pts = AV_NOPTS_VALUE;
+ is->frame_last_duration = 0;
+ is->frame_timer = (double)av_gettime() / 1000000.0;
+ is->frame_last_dropped_pts = AV_NOPTS_VALUE;
+ SDL_UnlockMutex(is->pictq_mutex);
+ return 0;
+ }
+
+ if(avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt) < 0)
+ return 0;
+
+ if (!got_picture && !pkt->data)
+ is->video_finished = *serial;
+
+ if (got_picture) {
+ int ret = 1;
+ double dpts = NAN;
+
+ 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;
+ }
+
+ 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)) {
+ SDL_LockMutex(is->pictq_mutex);
+ if (is->frame_last_pts != AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE) {
+ double clockdiff = get_clock(&is->vidclk) - get_master_clock(is);
+ double ptsdiff = dpts - is->frame_last_pts;
+ if (!isnan(clockdiff) && fabs(clockdiff) < AV_NOSYNC_THRESHOLD &&
+ !isnan(ptsdiff) && ptsdiff > 0 && ptsdiff < AV_NOSYNC_THRESHOLD &&
+ clockdiff + ptsdiff - is->frame_last_filter_delay < 0 &&
+ is->videoq.nb_packets) {
+ is->frame_last_dropped_pos = av_frame_get_pkt_pos(frame);
+ is->frame_last_dropped_pts = dpts;
+ is->frame_last_dropped_serial = *serial;
+ is->frame_drops_early++;
+ av_frame_unref(frame);
+ ret = 0;
+ }
+ }
+ SDL_UnlockMutex(is->pictq_mutex);
+ }
+
+ return ret;
+ }
+ return 0;
+}
+
+#if CONFIG_AVFILTER
+static int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph,
+ AVFilterContext *source_ctx, AVFilterContext *sink_ctx)
+{
+ int ret;
+ 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;
+ }
+
+ 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, *filt_crop;
+ 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;
+
+ /* SDL YUV code is not handling odd width/height for some driver
+ * combinations, therefore we crop the picture to an even width/height. */
+ if ((ret = avfilter_graph_create_filter(&filt_crop,
+ avfilter_get_by_name("crop"),
+ "ffplay_crop", "floor(in_w/2)*2:floor(in_h/2)*2", NULL, graph)) < 0)
+ goto fail;
+ if ((ret = avfilter_link(filt_crop, 0, filt_out, 0)) < 0)
+ goto fail;
+
+ if ((ret = configure_filtergraph(graph, vfilters, filt_src, filt_crop)) < 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 video_thread(void *arg)
+{
+ AVPacket pkt = { 0 };
+ VideoState *is = arg;
+ AVFrame *frame = av_frame_alloc();
+ double pts;
+ int ret;
+ int serial = 0;
+
+#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;
+#endif
+
+ for (;;) {
+ while (is->paused && !is->videoq.abort_request)
+ SDL_Delay(10);
+
+ avcodec_get_frame_defaults(frame);
+ av_free_packet(&pkt);
+
+ ret = get_video_frame(is, frame, &pkt, &serial);
+ 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 != serial) {
+ 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"), serial);
+ avfilter_graph_free(&graph);
+ graph = avfilter_graph_alloc();
+ if ((ret = configure_video_filters(graph, is, vfilters, frame)) < 0) {
+ SDL_Event event;
+ event.type = FF_QUIT_EVENT;
+ event.user.data1 = is;
+ SDL_PushEvent(&event);
+ av_free_packet(&pkt);
+ 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 = serial;
+ }
+
+ ret = av_buffersrc_add_frame(filt_in, frame);
+ if (ret < 0)
+ goto the_end;
+ av_frame_unref(frame);
+ avcodec_get_frame_defaults(frame);
+ av_free_packet(&pkt);
+
+ while (ret >= 0) {
+ is->frame_last_returned_time = av_gettime() / 1000000.0;
+
+ ret = av_buffersink_get_frame_flags(filt_out, frame, 0);
+ if (ret < 0) {
+ if (ret == AVERROR_EOF)
+ is->video_finished = serial;
+ ret = 0;
+ break;
+ }
+
+ is->frame_last_filter_delay = av_gettime() / 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;
+
+ pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(filt_out->inputs[0]->time_base);
+ ret = queue_picture(is, frame, pts, av_frame_get_pkt_pos(frame), serial);
+ av_frame_unref(frame);
+ }
+#else
+ pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(is->video_st->time_base);
+ ret = queue_picture(is, frame, pts, av_frame_get_pkt_pos(frame), serial);
+ av_frame_unref(frame);
+#endif
+
+ if (ret < 0)
+ goto the_end;
+ }
+ the_end:
+ avcodec_flush_buffers(is->video_st->codec);
+#if CONFIG_AVFILTER
+ 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;
+ int serial;
+ 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, &serial) < 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) {
+ if (sp->sub.pts != AV_NOPTS_VALUE)
+ pts = sp->sub.pts / (double)AV_TIME_BASE;
+ sp->pts = pts;
+ sp->serial = 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 */
+ if (++is->subpq_windex == SUBPICTURE_QUEUE_SIZE)
+ is->subpq_windex = 0;
+ SDL_LockMutex(is->subpq_mutex);
+ is->subpq_size++;
+ SDL_UnlockMutex(is->subpq_mutex);
+ } else if (got_subtitle) {
+ avsubtitle_free(&sp->sub);
+ }
+ 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 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)
+{
+ AVPacket *pkt_temp = &is->audio_pkt_temp;
+ AVPacket *pkt = &is->audio_pkt;
+ AVCodecContext *dec = is->audio_st->codec;
+ int len1, data_size, resampled_data_size;
+ int64_t dec_channel_layout;
+ int got_frame;
+ av_unused double audio_clock0;
+ int wanted_nb_samples;
+ AVRational tb;
+ int ret;
+ int reconfigure;
+
+ for (;;) {
+ /* NOTE: the audio packet can contain several frames */
+ while (pkt_temp->stream_index != -1 || is->audio_buf_frames_pending) {
+ if (!is->frame) {
+ if (!(is->frame = avcodec_alloc_frame()))
+ return AVERROR(ENOMEM);
+ } else {
+ av_frame_unref(is->frame);
+ avcodec_get_frame_defaults(is->frame);
+ }
+
+ if (is->audioq.serial != is->audio_pkt_temp_serial)
+ break;
+
+ if (is->paused)
+ return -1;
+
+ if (!is->audio_buf_frames_pending) {
+ 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->dts =
+ pkt_temp->pts = AV_NOPTS_VALUE;
+ pkt_temp->data += len1;
+ pkt_temp->size -= len1;
+ if (pkt_temp->data && pkt_temp->size <= 0 || !pkt_temp->data && !got_frame)
+ pkt_temp->stream_index = -1;
+ if (!pkt_temp->data && !got_frame)
+ is->audio_finished = is->audio_pkt_temp_serial;
+
+ if (!got_frame)
+ continue;
+
+ tb = (AVRational){1, is->frame->sample_rate};
+ if (is->frame->pts != AV_NOPTS_VALUE)
+ is->frame->pts = av_rescale_q(is->frame->pts, dec->time_base, tb);
+ else if (is->frame->pkt_pts != AV_NOPTS_VALUE)
+ is->frame->pts = av_rescale_q(is->frame->pkt_pts, is->audio_st->time_base, tb);
+ else if (is->audio_frame_next_pts != AV_NOPTS_VALUE)
+#if CONFIG_AVFILTER
+ is->frame->pts = av_rescale_q(is->audio_frame_next_pts, (AVRational){1, is->audio_filter_src.freq}, tb);
+#else
+ is->frame->pts = av_rescale_q(is->audio_frame_next_pts, (AVRational){1, is->audio_src.freq}, tb);
+#endif
+
+ if (is->frame->pts != AV_NOPTS_VALUE)
+ is->audio_frame_next_pts = is->frame->pts + is->frame->nb_samples;
+
+#if CONFIG_AVFILTER
+ dec_channel_layout = get_valid_channel_layout(is->frame->channel_layout, av_frame_get_channels(is->frame));
+
+ reconfigure =
+ cmp_audio_fmts(is->audio_filter_src.fmt, is->audio_filter_src.channels,
+ is->frame->format, av_frame_get_channels(is->frame)) ||
+ is->audio_filter_src.channel_layout != dec_channel_layout ||
+ is->audio_filter_src.freq != is->frame->sample_rate ||
+ is->audio_pkt_temp_serial != is->audio_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, is->audio_last_serial,
+ is->frame->sample_rate, av_frame_get_channels(is->frame), av_get_sample_fmt_name(is->frame->format), buf2, is->audio_pkt_temp_serial);
+
+ is->audio_filter_src.fmt = is->frame->format;
+ is->audio_filter_src.channels = av_frame_get_channels(is->frame);
+ is->audio_filter_src.channel_layout = dec_channel_layout;
+ is->audio_filter_src.freq = is->frame->sample_rate;
+ is->audio_last_serial = is->audio_pkt_temp_serial;
+
+ if ((ret = configure_audio_filters(is, afilters, 1)) < 0)
+ return ret;
+ }
+
+ if ((ret = av_buffersrc_add_frame(is->in_audio_filter, is->frame)) < 0)
+ return ret;
+ av_frame_unref(is->frame);
+#endif
+ }
+#if CONFIG_AVFILTER
+ if ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, is->frame, 0)) < 0) {
+ if (ret == AVERROR(EAGAIN)) {
+ is->audio_buf_frames_pending = 0;
+ continue;
+ }
+ if (ret == AVERROR_EOF)
+ is->audio_finished = is->audio_pkt_temp_serial;
+ return ret;
+ }
+ is->audio_buf_frames_pending = 1;
+ tb = is->out_audio_filter->inputs[0]->time_base;
+#endif
+
+ data_size = av_samples_get_buffer_size(NULL, av_frame_get_channels(is->frame),
+ is->frame->nb_samples,
+ is->frame->format, 1);
+
+ dec_channel_layout =
+ (is->frame->channel_layout && av_frame_get_channels(is->frame) == av_get_channel_layout_nb_channels(is->frame->channel_layout)) ?
+ is->frame->channel_layout : av_get_default_channel_layout(av_frame_get_channels(is->frame));
+ wanted_nb_samples = synchronize_audio(is, is->frame->nb_samples);
+
+ if (is->frame->format != is->audio_src.fmt ||
+ dec_channel_layout != is->audio_src.channel_layout ||
+ is->frame->sample_rate != is->audio_src.freq ||
+ (wanted_nb_samples != is->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, is->frame->format, is->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",
+ is->frame->sample_rate, av_get_sample_fmt_name(is->frame->format), av_frame_get_channels(is->frame),
+ is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);
+ break;
+ }
+ is->audio_src.channel_layout = dec_channel_layout;
+ is->audio_src.channels = av_frame_get_channels(is->frame);
+ is->audio_src.freq = is->frame->sample_rate;
+ is->audio_src.fmt = is->frame->format;
+ }
+
+ if (is->swr_ctx) {
+ const uint8_t **in = (const uint8_t **)is->frame->extended_data;
+ uint8_t **out = &is->audio_buf1;
+ int out_count = (int64_t)wanted_nb_samples * is->audio_tgt.freq / is->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");
+ break;
+ }
+ if (wanted_nb_samples != is->frame->nb_samples) {
+ if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - is->frame->nb_samples) * is->audio_tgt.freq / is->frame->sample_rate,
+ wanted_nb_samples * is->audio_tgt.freq / is->frame->sample_rate) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "swr_set_compensation() failed\n");
+ break;
+ }
+ }
+ 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, is->frame->nb_samples);
+ if (len2 < 0) {
+ av_log(NULL, AV_LOG_ERROR, "swr_convert() failed\n");
+ break;
+ }
+ if (len2 == out_count) {
+ av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too small\n");
+ swr_init(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 = is->frame->data[0];
+ resampled_data_size = data_size;
+ }
+
+ audio_clock0 = is->audio_clock;
+ /* update the audio clock with the pts */
+ if (is->frame->pts != AV_NOPTS_VALUE)
+ is->audio_clock = is->frame->pts * av_q2d(tb) + (double) is->frame->nb_samples / is->frame->sample_rate;
+ else
+ is->audio_clock = NAN;
+ is->audio_clock_serial = is->audio_pkt_temp_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;
+ }
+
+ /* free the current packet */
+ if (pkt->data)
+ av_free_packet(pkt);
+ memset(pkt_temp, 0, sizeof(*pkt_temp));
+ pkt_temp->stream_index = -1;
+
+ if (is->audioq.abort_request) {
+ return -1;
+ }
+
+ if (is->audioq.nb_packets == 0)
+ SDL_CondSignal(is->continue_read_thread);
+
+ /* read next packet */
+ if ((packet_queue_get(&is->audioq, pkt, 1, &is->audio_pkt_temp_serial)) < 0)
+ return -1;
+
+ if (pkt->data == flush_pkt.data) {
+ avcodec_flush_buffers(dec);
+ is->audio_buf_frames_pending = 0;
+ is->audio_frame_next_pts = AV_NOPTS_VALUE;
+ if ((is->ic->iformat->flags & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) && !is->ic->iformat->read_seek)
+ is->audio_frame_next_pts = is->audio_st->start_time;
+ }
+
+ *pkt_temp = *pkt;
+ }
+}
+
+/* prepare a new audio buffer */
+static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
+{
+ VideoState *is = opaque;
+ int audio_size, len1;
+ int bytes_per_sec;
+ int frame_size = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, 1, is->audio_tgt.fmt, 1);
+
+ audio_callback_time = av_gettime();
+
+ 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) / frame_size * 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;
+ }
+ bytes_per_sec = is->audio_tgt.freq * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
+ 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) / 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};
+
+ 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_spec.channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
+ 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;
+ }
+ wanted_spec.format = AUDIO_S16SYS;
+ wanted_spec.silence = 0;
+ wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
+ 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): %s\n", wanted_spec.channels, SDL_GetError());
+ wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];
+ if (!wanted_spec.channels) {
+ av_log(NULL, AV_LOG_ERROR,
+ "No more channel 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;
+ 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;
+ 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;
+ avctx->workaround_bugs = workaround_bugs;
+ 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);
+ avctx->error_concealment = error_concealment;
+
+ 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(&opts, "lowres", av_asprintf("%d", stream_lowres), AV_DICT_DONT_STRDUP_VAL);
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO)
+ av_dict_set(&opts, "refcounted_frames", "1", 0);
+ if (avcodec_open2(avctx, codec, &opts) < 0)
+ return -1;
+ if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
+ av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
+ return AVERROR_OPTION_NOT_FOUND;
+ }
+
+ 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)
+ return ret;
+ 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)
+ return ret;
+ 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 = 2.0 * is->audio_hw_buf_size / av_samples_get_buffer_size(NULL, is->audio_tgt.channels, is->audio_tgt.freq, is->audio_tgt.fmt, 1);
+
+ memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
+ memset(&is->audio_pkt_temp, 0, sizeof(is->audio_pkt_temp));
+ is->audio_pkt_temp.stream_index = -1;
+
+ is->audio_stream = stream_index;
+ is->audio_st = ic->streams[stream_index];
+
+ packet_queue_start(&is->audioq);
+ 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);
+ 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);
+
+ is->subtitle_tid = SDL_CreateThread(subtitle_thread, is);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+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_flush(&is->audioq);
+ av_free_packet(&is->audio_pkt);
+ swr_free(&is->swr_ctx);
+ av_freep(&is->audio_buf1);
+ is->audio_buf1_size = 0;
+ 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;
+ }
+#if CONFIG_AVFILTER
+ avfilter_graph_free(&is->agraph);
+#endif
+ 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_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 */
+ SDL_LockMutex(is->subpq_mutex);
+ SDL_CondSignal(is->subpq_cond);
+ SDL_UnlockMutex(is->subpq_mutex);
+
+ SDL_WaitThread(is->subtitle_tid, NULL);
+
+ 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();
+
+ 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;
+ 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);
+ if (err < 0) {
+ av_log(NULL, AV_LOG_WARNING,
+ "%s: could not find codec parameters\n", is->filename);
+ ret = -1;
+ goto fail;
+ }
+ for (i = 0; i < orig_nb_streams; i++)
+ av_dict_free(&opts[i]);
+ av_freep(&opts);
+
+ if (ic->pb)
+ ic->pb->eof_reached = 0; // FIXME hack, ffplay 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) && 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;
+
+ /* 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->audio_finished == is->audioq.serial) &&
+ (!is->video_st || (is->video_finished == is->videoq.serial && is->pictq_size == 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;
+ }
+ }
+ if (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);
+ SDL_Delay(10);
+ eof=0;
+ continue;
+ }
+ ret = av_read_frame(ic, pkt);
+ if (ret < 0) {
+ if (ret == AVERROR_EOF || url_feof(ic->pb))
+ 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;
+ }
+ /* 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 */
+ is->pictq_mutex = SDL_CreateMutex();
+ is->pictq_cond = SDL_CreateCond();
+
+ is->subpq_mutex = SDL_CreateMutex();
+ is->subpq_cond = SDL_CreateCond();
+
+ 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->audio_last_serial = -1;
+ is->av_sync_type = av_sync_type;
+ is->read_tid = SDL_CreateThread(read_thread, is);
+ if (!is->read_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;
+ 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];
+ 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[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() - 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();
+ }
+}
+
+/* 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:
+ toggle_audio_display(cur_stream);
+ break;
+ case SDLK_PAGEUP:
+ incr = 600.0;
+ goto do_seek;
+ case SDLK_PAGEDOWN:
+ incr = -600.0;
+ goto do_seek;
+ 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) {
+ 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);
+ 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();
+ 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|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", "" },
+ { "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", ""},
+ { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, { &lowres }, "", "" },
+ { "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" },
+ { "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_STRING | HAS_ARG, { &vfilters }, "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" },
+ { 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 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"
+ "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 */
+ 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();
+
+ 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(__MINGW32__) && !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..80a286b
--- a/dev/null
+++ b/ffprobe.c
@@ -0,0 +1,2714 @@
+/*
+ * 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 "version.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/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 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;
+
+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_LIBRARY_VERSION,
+ SECTION_ID_LIBRARY_VERSIONS,
+ SECTION_ID_PACKET,
+ SECTION_ID_PACKETS,
+ SECTION_ID_PACKETS_AND_FRAMES,
+ 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,
+} 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, -1 } },
+ [SECTION_ID_FRAME] = { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, -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_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_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, -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" },
+};
+
+static const OptionDef *options;
+
+/* FFprobe 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 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];
+ }
+ }
+
+ 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 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
+};
+
+static const char *writer_get_name(void *p)
+{
+ WriterContext *wctx = p;
+ return wctx->writer->name;
+}
+
+static const AVClass writer_class = {
+ "Writer",
+ writer_get_name,
+ NULL,
+ LIBAVUTIL_VERSION_INT,
+};
+
+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_freep(wctx);
+}
+
+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;
+
+ if (writer->priv_class) {
+ void *priv_ctx = (*wctx)->priv;
+ *((const AVClass **)priv_ctx) = writer->priv_class;
+ av_opt_set_defaults(priv_ctx);
+
+ if (args &&
+ (ret = av_set_options_string(priv_ctx, args, "=", ":")) < 0)
+ goto fail;
+ }
+
+ 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 void writer_print_string(WriterContext *wctx,
+ const char *key, const char *val, int opt)
+{
+ const struct section *section = wctx->section[wctx->level];
+
+ if (opt && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))
+ return;
+
+ if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
+ wctx->writer->print_string(wctx, key, val);
+ wctx->nb_item[wctx->level]++;
+ }
+}
+
+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", 1);
+ } 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", 1);
+ } 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);
+}
+
+#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 = { \
+ #name, \
+ name##_get_name, \
+ name##_options \
+}
+
+/* Default output */
+
+typedef struct DefaultContext {
+ const AVClass *class;
+ int nokey;
+ int noprint_wrappers;
+ int nested_section[SECTION_MAX_NB_LEVELS];
+} DefaultContext;
+
+#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, 1)
+#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)
+
+static inline void show_tags(WriterContext *wctx, AVDictionary *tags, int section_id)
+{
+ AVDictionaryEntry *tag = NULL;
+
+ if (!tags)
+ return;
+ writer_print_section_header(wctx, section_id);
+ while ((tag = av_dict_get(tags, "", tag, AV_DICT_IGNORE_SUFFIX)))
+ writer_print_string(wctx, tag->key, tag->value, 0);
+ writer_print_section_footer(wctx);
+}
+
+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_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;
+
+ 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_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;
+ }
+ show_tags(w, av_frame_get_metadata(frame), SECTION_ID_FRAME_TAGS);
+
+ 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;
+ int ret = 0, got_frame = 0;
+
+ avcodec_get_frame_defaults(frame);
+ 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;
+ }
+ }
+
+ if (ret < 0)
+ return ret;
+ ret = FFMIN(ret, pkt->size); /* guard against bogus return values */
+ pkt->data += ret;
+ pkt->size -= ret;
+ if (got_frame) {
+ nb_streams_frames[pkt->stream_index]++;
+ if (do_show_frames)
+ show_frame(w, frame, fmt_ctx->streams[pkt->stream_index], fmt_ctx);
+ }
+ 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;
+ 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;
+ }
+ }
+
+ while (!av_read_frame(fmt_ctx, &pkt)) {
+ 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:
+ 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 void 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;
+ }
+ }
+}
+
+static void 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;
+
+ 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 {
+ 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->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 (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);
+
+ /* 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);
+ }
+
+ 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);
+}
+
+static void show_streams(WriterContext *w, AVFormatContext *fmt_ctx)
+{
+ int i;
+ writer_print_section_header(w, SECTION_ID_STREAMS);
+ for (i = 0; i < fmt_ctx->nb_streams; i++)
+ if (selected_streams[i])
+ show_stream(w, fmt_ctx, i, 0);
+ writer_print_section_footer(w);
+}
+
+static void show_program(WriterContext *w, AVFormatContext *fmt_ctx, AVProgram *program)
+{
+ int i;
+
+ 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);
+ show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS);
+
+ 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]])
+ show_stream(w, fmt_ctx, program->stream_index[i], 1);
+ }
+ writer_print_section_footer(w);
+
+ writer_print_section_footer(w);
+}
+
+static void show_programs(WriterContext *w, AVFormatContext *fmt_ctx)
+{
+ int i;
+
+ 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;
+ show_program(w, fmt_ctx, program);
+ }
+ writer_print_section_footer(w);
+}
+
+static void show_chapters(WriterContext *w, AVFormatContext *fmt_ctx)
+{
+ int i;
+
+ 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);
+ show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS);
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+}
+
+static void show_format(WriterContext *w, AVFormatContext *fmt_ctx)
+{
+ char val_str[128];
+ int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;
+
+ writer_print_section_header(w, SECTION_ID_FORMAT);
+ print_str("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));
+ show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS);
+
+ writer_print_section_footer(w);
+ fflush(stdout);
+}
+
+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;
+
+ 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 */
+ 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;
+
+ nb_streams_frames = av_calloc(fmt_ctx->nb_streams, sizeof(*nb_streams_frames));
+ nb_streams_packets = av_calloc(fmt_ctx->nb_streams, sizeof(*nb_streams_packets));
+ selected_streams = av_calloc(fmt_ctx->nb_streams, sizeof(*selected_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);
+ if (ret < 0)
+ goto 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);
+ read_packets(wctx, fmt_ctx);
+ if (do_show_frames || do_show_packets)
+ writer_print_section_footer(wctx);
+ }
+ if (do_show_programs)
+ show_programs(wctx, fmt_ctx);
+ if (do_show_streams)
+ show_streams(wctx, fmt_ctx);
+ if (do_show_chapters)
+ show_chapters(wctx, fmt_ctx);
+ if (do_show_format)
+ show_format(wctx, fmt_ctx);
+
+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, 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);
+}
+
+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(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(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_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_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(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);
+
+ 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;
+
+ 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) {
+ 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 (!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))) {
+ 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);
+
+ 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..5ecdb08
--- a/dev/null
+++ b/ffserver.c
@@ -0,0 +1,4744 @@
+/*
+ * 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/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/pixdesc.h"
+#include "libavutil/random_seed.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+
+#include <stdarg.h>
+#include <unistd.h>
+#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"
+
+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 *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 MAX_STREAMS 20
+
+#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 FFStream *stream;
+ /* -1 is invalid stream */
+ int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
+ int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
+ int switch_pending;
+ AVFormatContext fmt_ctx; /* instance of FFStream 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[MAX_STREAMS];
+
+ /* RTP/UDP specific */
+ URLContext *rtp_handles[MAX_STREAMS];
+
+ /* RTP/TCP specific */
+ struct HTTPContext *rtsp_c;
+ uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
+} HTTPContext;
+
+/* each generated stream is described here */
+enum StreamType {
+ STREAM_TYPE_LIVE,
+ STREAM_TYPE_STATUS,
+ STREAM_TYPE_REDIRECT,
+};
+
+enum IPAddressAction {
+ IP_ALLOW = 1,
+ IP_DENY,
+};
+
+typedef struct IPAddressACL {
+ struct IPAddressACL *next;
+ enum IPAddressAction action;
+ /* These are in host order */
+ struct in_addr first;
+ struct in_addr last;
+} IPAddressACL;
+
+/* description of each stream of the ffserver.conf file */
+typedef struct FFStream {
+ enum StreamType stream_type;
+ char filename[1024]; /* stream filename */
+ struct FFStream *feed; /* feed we are using (can be null if
+ coming from file) */
+ AVDictionary *in_opts; /* input parameters */
+ AVInputFormat *ifmt; /* if non NULL, force input format */
+ AVOutputFormat *fmt;
+ IPAddressACL *acl;
+ char dynamic_acl[1024];
+ int nb_streams;
+ int prebuffer; /* Number of millseconds early to start */
+ int64_t max_time; /* Number of milliseconds to run */
+ int send_on_key;
+ AVStream *streams[MAX_STREAMS];
+ int feed_streams[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 */
+ char author[512];
+ char title[512];
+ char copyright[512];
+ char comment[512];
+ pid_t pid; /* Of ffmpeg process */
+ time_t pid_start; /* Of ffmpeg process */
+ char **child_argv;
+ struct FFStream *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 FFStream *next_feed;
+} FFStream;
+
+typedef struct FeedData {
+ long long data_count;
+ float avg_frame_size; /* frame size averaged over last frames with exponential mean */
+} FeedData;
+
+static struct sockaddr_in my_http_addr;
+static struct sockaddr_in my_rtsp_addr;
+
+static char logfilename[1024];
+static HTTPContext *first_http_ctx;
+static FFStream *first_feed; /* contains only feeds */
+static FFStream *first_stream; /* contains all streams, including feeds */
+
+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_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
+static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
+
+/* SDP handling */
+static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
+ struct in_addr my_ip);
+
+/* RTP handling */
+static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
+ FFStream *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 const char *config_filename;
+
+static int ffserver_debug;
+static int no_launch;
+static int need_to_start_children;
+
+/* maximum number of simultaneous HTTP connections */
+static unsigned int nb_max_http_connections = 2000;
+static unsigned int nb_max_connections = 5;
+static unsigned int nb_connections;
+
+static uint64_t max_bandwidth = 1000;
+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;
+}
+
+/* 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;
+}
+
+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(FFStream *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;
+
+ 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 (!ffserver_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;
+ setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
+
+ 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;
+ }
+ ff_socket_nonblock(server_fd, 1);
+
+ return server_fd;
+}
+
+/* start all multicast streams */
+static void start_multicast(void)
+{
+ FFStream *stream;
+ char session_id[32];
+ HTTPContext *rtp_c;
+ struct sockaddr_in dest_addr = {0};
+ int default_port, stream_index;
+
+ default_port = 6000;
+ for(stream = first_stream; stream != NULL; 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);
+ }
+ }
+
+ /* change state to send data */
+ 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, delay1;
+ struct pollfd *poll_table, *poll_entry;
+ HTTPContext *c, *c_next;
+
+ if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
+ http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
+ return -1;
+ }
+
+ if (my_http_addr.sin_port) {
+ server_fd = socket_open_listen(&my_http_addr);
+ if (server_fd < 0)
+ return -1;
+ }
+
+ if (my_rtsp_addr.sin_port) {
+ rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
+ if (rtsp_server_fd < 0)
+ return -1;
+ }
+
+ if (!rtsp_server_fd && !server_fd) {
+ http_log("HTTP and RTSP disabled.\n");
+ return -1;
+ }
+
+ http_log("FFserver started.\n");
+
+ start_children(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 != NULL) {
+ 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 need to be sent every
+ 10 ms */
+ delay1 = 10; /* one tick wait XXX: 10 ms assumed */
+ if (delay1 < delay)
+ delay = delay1;
+ }
+ 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))
+ return -1;
+ } while (ret < 0);
+
+ cur_time = av_gettime() / 1000;
+
+ if (need_to_start_children) {
+ need_to_start_children = 0;
+ start_children(first_feed);
+ }
+
+ /* now handle the events */
+ for(c = first_http_ctx; c != NULL; c = c_next) {
+ c_next = c->next;
+ if (handle_connection(c) < 0) {
+ /* close and free the connection */
+ log_connection(c);
+ 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, nb_max_connections);
+ av_assert0(len < sizeof(buffer));
+ send(fd, buffer, len, 0);
+}
+
+
+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;
+ }
+ ff_socket_nonblock(fd, 1);
+
+ if (nb_connections >= 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_free(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) != NULL) {
+ 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 != NULL; 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_free(ctx->streams[0]);
+ av_free(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_free(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_free(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)) {
+ /* error : close connection */
+ av_freep(&c->pb_buffer);
+ return -1;
+ }
+ } 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 sets 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)) {
+ av_freep(&c->pb_buffer);
+ 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)) {
+ /* error : close connection */
+ av_freep(&c->pb_buffer);
+ return -1;
+ }
+ } 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;
+}
+
+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(FFStream *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;
+ FFStream *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;
+}
+
+/* XXX: factorize in utils.c ? */
+/* XXX: take care with different space meaning */
+static void skip_spaces(const char **pp)
+{
+ const char *p;
+ p = *pp;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *pp = p;
+}
+
+static void get_word(char *buf, int buf_size, const char **pp)
+{
+ const char *p;
+ char *q;
+
+ p = *pp;
+ skip_spaces(&p);
+ 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 void 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;
+}
+
+static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
+ const char *p, const char *filename, int line_num)
+{
+ char arg[1024];
+ IPAddressACL acl;
+ int errors = 0;
+
+ 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++;
+ }
+
+ get_arg(arg, sizeof(arg), &p);
+
+ if (resolve_host(&acl.first, arg) != 0) {
+ fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
+ filename, line_num, arg);
+ errors++;
+ } else
+ acl.last = acl.first;
+
+ get_arg(arg, sizeof(arg), &p);
+
+ if (arg[0]) {
+ if (resolve_host(&acl.last, arg) != 0) {
+ fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
+ filename, line_num, arg);
+ errors++;
+ }
+ }
+
+ if (!errors) {
+ IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
+ IPAddressACL **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;
+ }
+ }
+}
+
+
+static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
+{
+ FILE* f;
+ char line[1024];
+ char cmd[1024];
+ IPAddressACL *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(IPAddressACL));
+
+ /* 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;
+ get_arg(cmd, sizeof(cmd), &p);
+
+ if (!av_strcasecmp(cmd, "ACL"))
+ parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
+ }
+ fclose(f);
+ return acl;
+}
+
+
+static void free_acl_list(IPAddressACL *in_acl)
+{
+ IPAddressACL *pacl,*pacl2;
+
+ pacl = in_acl;
+ while(pacl) {
+ pacl2 = pacl;
+ pacl = pacl->next;
+ av_freep(pacl2);
+ }
+}
+
+static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
+{
+ enum IPAddressAction last_action = IP_DENY;
+ IPAddressACL *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(FFStream *stream, HTTPContext *c)
+{
+ int ret = 0;
+ IPAddressACL *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 filenames */
+static void compute_real_filename(char *filename, int max_size)
+{
+ char file1[1024];
+ char file2[1024];
+ char *p;
+ FFStream *stream;
+
+ /* compute filename by matching without the file extensions */
+ av_strlcpy(file1, filename, sizeof(file1));
+ p = strrchr(file1, '.');
+ if (p)
+ *p = '\0';
+ for(stream = first_stream; stream != NULL; 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;
+ FFStream *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 (ffserver_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 = first_stream;
+ while (stream != NULL) {
+ if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
+ break;
+ stream = stream->next;
+ }
+ if (stream == NULL) {
+ 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 && 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, 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(my_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);
+ getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
+
+ /* 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 in 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;
+ FFStream *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: %s\r\n", "text/html");
+ 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 = first_stream;
+ while (stream != NULL) {
+ 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 = first_stream;
+ while (stream != NULL) {
+ 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, nb_max_connections);
+
+ avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
+ current_bandwidth, 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 != NULL) {
+ 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)
+ 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)
+ return ret;
+ } else
+ stream_pos = 0;
+ }
+ if (input_filename[0] == '\0')
+ return -1;
+
+ /* open stream */
+ if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
+ http_log("could not open %s: %d\n", input_filename, ret);
+ return -1;
+ }
+
+ /* 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") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
+ http_log("Could not find stream info '%s'\n", input_filename);
+ avformat_close_input(&s);
+ return -1;
+ }
+
+ /* choose stream as clock source (we favorize 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:
+ memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
+ av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
+ av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
+ av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
+ av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
+
+ c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
+
+ 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 FFStream 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;
+ c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
+ AVStream, not in codec */
+ }
+ /* 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 use configuration option
+ */
+ c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
+
+ if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
+ http_log("Error writing output header\n");
+ return -1;
+ }
+ 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 stream (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 (av_write_frame(ctx, &pkt) < 0) {
+ http_log("Error writing frame to output\n");
+ 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 connection) */
+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;
+
+ if (c->stream->feed_opened)
+ return -1;
+
+ /* Don't permit writing to this one */
+ if (c->stream->readonly)
+ return -1;
+
+ /* open feed */
+ fd = open(c->stream->feed_filename, O_RDWR);
+ if (fd < 0) {
+ http_log("Error opening feeder file: %s\n", strerror(errno));
+ return -1;
+ }
+ 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) {
+ http_log("Error truncating feed file: %s\n", strerror(errno));
+ return -1;
+ }
+ } else {
+ if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
+ http_log("Error reading write index from feed file: %s\n", strerror(errno));
+ return -1;
+ }
+ }
+
+ 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) {
+ FFStream *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 */
+ lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
+ 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 != NULL; 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_free(pb);
+ goto fail;
+ }
+
+ /* Now we have the actual streams */
+ if (s->nb_streams != feed->nb_streams) {
+ avformat_close_input(&s);
+ av_free(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_free(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 != NULL; 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];
+
+ switch(error_number) {
+ case RTSP_STATUS_OK:
+ str = "OK";
+ break;
+ case RTSP_STATUS_METHOD:
+ str = "Method Not Allowed";
+ break;
+ case RTSP_STATUS_BANDWIDTH:
+ str = "Not Enough Bandwidth";
+ break;
+ case RTSP_STATUS_SESSION:
+ str = "Session Not Found";
+ break;
+ case RTSP_STATUS_STATE:
+ str = "Method Not Valid in This State";
+ break;
+ case RTSP_STATUS_AGGREGATE:
+ str = "Aggregate operation not allowed";
+ break;
+ case RTSP_STATUS_ONLY_AGGREGATE:
+ str = "Only aggregate operation allowed";
+ break;
+ case RTSP_STATUS_TRANSPORT:
+ str = "Unsupported transport";
+ break;
+ case RTSP_STATUS_INTERNAL:
+ str = "Internal Server Error";
+ break;
+ case RTSP_STATUS_SERVICE:
+ str = "Service Unavailable";
+ break;
+ case RTSP_STATUS_VERSION:
+ str = "RTSP Version not supported";
+ break;
+ default:
+ str = "Unknown Error";
+ break;
+ }
+
+ 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_pause(c, url, header);
+ else if (!strcmp(cmd, "TEARDOWN"))
+ rtsp_cmd_teardown(c, url, header);
+ 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(FFStream *stream, uint8_t **pbuffer,
+ struct in_addr my_ip)
+{
+ AVFormatContext *avc;
+ AVStream *avs = NULL;
+ AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
+ int i;
+
+ avc = avformat_alloc_context();
+ if (avc == NULL || !rtp_format) {
+ return -1;
+ }
+ avc->oformat = rtp_format;
+ av_dict_set(&avc->metadata, "title",
+ stream->title[0] ? stream->title : "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_free(avc->streams);
+ av_dict_free(&avc->metadata);
+ av_free(avc);
+ av_free(avs);
+
+ return strlen(*pbuffer);
+}
+
+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)
+{
+ FFStream *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 = first_stream; stream != NULL; 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_SERVICE); /* XXX: right error ? */
+ 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 != NULL; 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)
+{
+ FFStream *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 = first_stream; stream != NULL; 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_pause(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) {
+ 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");
+}
+
+static void rtsp_cmd_teardown(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;
+ }
+
+ /* 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");
+
+ /* abort the session */
+ close_connection(rtp_c);
+}
+
+
+/********************************************************************/
+/* RTP handling */
+
+static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
+ FFStream *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 >= 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_free(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(sizeof(AVStream *) * ctx->nb_streams);
+ 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(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(FFStream *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 the streams.
+ */
+ 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(FFStream *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(FFStream *stream)
+{
+ FFStream **ps;
+ ps = &first_stream;
+ while (*ps != NULL) {
+ 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)
+{
+ FFStream *stream, *stream_next;
+ int i, ret;
+
+ /* gather all streams */
+ for(stream = first_stream; stream != NULL; 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);
+ }
+
+ http_log("Opening file '%s'\n", stream->feed_filename);
+ if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
+ http_log("Could not open '%s': %d\n", stream->feed_filename, 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)
+{
+ FFStream *stream, *feed;
+ int i;
+
+ /* gather all streams */
+ for(stream = first_stream; stream != NULL; 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 = first_feed; feed != NULL; 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 s1 = {0}, *s = &s1;
+
+ 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);
+ }
+ /* 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;
+ FFStream *stream;
+
+ for(stream = first_stream; stream != NULL; 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;
+ }
+}
+
+/* add a codec and set the default parameters */
+static void add_codec(FFStream *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;
+ 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 = avcodec_alloc_context3(NULL);
+ stream->streams[stream->nb_streams++] = st;
+ memcpy(st->codec, av, sizeof(AVCodecContext));
+}
+
+static enum AVCodecID opt_audio_codec(const char *arg)
+{
+ AVCodec *p= avcodec_find_encoder_by_name(arg);
+
+ if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
+ return AV_CODEC_ID_NONE;
+
+ return p->id;
+}
+
+static enum AVCodecID opt_video_codec(const char *arg)
+{
+ AVCodec *p= avcodec_find_encoder_by_name(arg);
+
+ if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
+ return AV_CODEC_ID_NONE;
+
+ return p->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 = 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 1;
+ }
+
+ 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 = 1;
+ break;
+ }
+ if(!strcmp(tmp, "acodec")){
+ *audio_id = opt_audio_codec(tmp2);
+ }else if(!strcmp(tmp, "vcodec")){
+ *video_id = opt_video_codec(tmp2);
+ }else if(!strcmp(tmp, "scodec")){
+ /* opt_subtitle_codec(tmp2); */
+ }else if(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);
+ ret = 1;
+ 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 report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
+{
+ va_list vl;
+ va_start(vl, fmt);
+ fprintf(stderr, "%s:%d: ", filename, line_num);
+ vfprintf(stderr, fmt, vl);
+ va_end(vl);
+
+ (*errors)++;
+}
+
+static int parse_ffconfig(const char *filename)
+{
+ FILE *f;
+ char line[1024];
+ char cmd[64];
+ char arg[1024];
+ const char *p;
+ int val, errors, line_num;
+ FFStream **last_stream, *stream, *redirect;
+ FFStream **last_feed, *feed, *s;
+ AVCodecContext audio_enc, video_enc;
+ enum AVCodecID audio_id, video_id;
+
+ f = fopen(filename, "r");
+ if (!f) {
+ perror(filename);
+ return -1;
+ }
+
+ errors = 0;
+ line_num = 0;
+ first_stream = NULL;
+ last_stream = &first_stream;
+ first_feed = NULL;
+ last_feed = &first_feed;
+ stream = NULL;
+ feed = NULL;
+ redirect = NULL;
+ audio_id = AV_CODEC_ID_NONE;
+ video_id = AV_CODEC_ID_NONE;
+
+#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
+ for(;;) {
+ if (fgets(line, sizeof(line), f) == NULL)
+ break;
+ line_num++;
+ p = line;
+ while (av_isspace(*p))
+ p++;
+ if (*p == '\0' || *p == '#')
+ continue;
+
+ get_arg(cmd, sizeof(cmd), &p);
+
+ if (!av_strcasecmp(cmd, "Port")) {
+ get_arg(arg, sizeof(arg), &p);
+ val = atoi(arg);
+ if (val < 1 || val > 65536) {
+ ERROR("Invalid_port: %s\n", arg);
+ }
+ my_http_addr.sin_port = htons(val);
+ } else if (!av_strcasecmp(cmd, "BindAddress")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
+ ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
+ }
+ } else if (!av_strcasecmp(cmd, "NoDaemon")) {
+ // do nothing here, its the default now
+ } else if (!av_strcasecmp(cmd, "RTSPPort")) {
+ get_arg(arg, sizeof(arg), &p);
+ val = atoi(arg);
+ if (val < 1 || val > 65536) {
+ ERROR("%s:%d: Invalid port: %s\n", arg);
+ }
+ my_rtsp_addr.sin_port = htons(atoi(arg));
+ } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
+ ERROR("Invalid host/IP address: %s\n", arg);
+ }
+ } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
+ get_arg(arg, sizeof(arg), &p);
+ val = atoi(arg);
+ if (val < 1 || val > 65536) {
+ ERROR("Invalid MaxHTTPConnections: %s\n", arg);
+ }
+ nb_max_http_connections = val;
+ } else if (!av_strcasecmp(cmd, "MaxClients")) {
+ get_arg(arg, sizeof(arg), &p);
+ val = atoi(arg);
+ if (val < 1 || val > nb_max_http_connections) {
+ ERROR("Invalid MaxClients: %s\n", arg);
+ } else {
+ nb_max_connections = val;
+ }
+ } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
+ int64_t llval;
+ get_arg(arg, sizeof(arg), &p);
+ llval = strtoll(arg, NULL, 10);
+ if (llval < 10 || llval > 10000000) {
+ ERROR("Invalid MaxBandwidth: %s\n", arg);
+ } else
+ max_bandwidth = llval;
+ } else if (!av_strcasecmp(cmd, "CustomLog")) {
+ if (!ffserver_debug)
+ get_arg(logfilename, sizeof(logfilename), &p);
+ } else if (!av_strcasecmp(cmd, "<Feed")) {
+ /*********************************************/
+ /* Feed related options */
+ char *q;
+ if (stream || feed) {
+ ERROR("Already in a tag\n");
+ } else {
+ feed = av_mallocz(sizeof(FFStream));
+ get_arg(feed->filename, sizeof(feed->filename), &p);
+ q = strrchr(feed->filename, '>');
+ if (*q)
+ *q = '\0';
+
+ for (s = 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);
+ /* defaut 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 :-) */
+
+ /* 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 (!av_strcasecmp(cmd, "Launch")) {
+ if (feed) {
+ int i;
+
+ feed->child_argv = av_mallocz(64 * sizeof(char *));
+
+ for (i = 0; i < 62; i++) {
+ get_arg(arg, sizeof(arg), &p);
+ if (!arg[0])
+ break;
+
+ feed->child_argv[i] = av_strdup(arg);
+ }
+
+ feed->child_argv[i] = av_asprintf("http://%s:%d/%s",
+ (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
+ inet_ntoa(my_http_addr.sin_addr),
+ ntohs(my_http_addr.sin_port), feed->filename);
+ }
+ } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
+ if (feed) {
+ get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
+ feed->readonly = 1;
+ } else if (stream) {
+ get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
+ }
+ } else if (!av_strcasecmp(cmd, "File")) {
+ if (feed) {
+ get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
+ } else if (stream)
+ get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
+ } else if (!av_strcasecmp(cmd, "Truncate")) {
+ if (feed) {
+ get_arg(arg, sizeof(arg), &p);
+ feed->truncate = strtod(arg, NULL);
+ }
+ } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
+ if (feed) {
+ char *p1;
+ double fsize;
+
+ 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;
+ }
+ 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>")) {
+ if (!feed) {
+ ERROR("No corresponding <Feed> for </Feed>\n");
+ }
+ feed = NULL;
+ } else if (!av_strcasecmp(cmd, "<Stream")) {
+ /*********************************************/
+ /* Stream related options */
+ char *q;
+ if (stream || feed) {
+ ERROR("Already in a tag\n");
+ } else {
+ FFStream *s;
+ stream = av_mallocz(sizeof(FFStream));
+ get_arg(stream->filename, sizeof(stream->filename), &p);
+ q = strrchr(stream->filename, '>');
+ if (q)
+ *q = '\0';
+
+ for (s = 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);
+ avcodec_get_context_defaults3(&video_enc, NULL);
+ avcodec_get_context_defaults3(&audio_enc, NULL);
+
+ audio_id = AV_CODEC_ID_NONE;
+ video_id = AV_CODEC_ID_NONE;
+ if (stream->fmt) {
+ audio_id = stream->fmt->audio_codec;
+ video_id = stream->fmt->video_codec;
+ }
+
+ *last_stream = stream;
+ last_stream = &stream->next;
+ }
+ } else if (!av_strcasecmp(cmd, "Feed")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ FFStream *sfeed;
+
+ sfeed = first_feed;
+ while (sfeed != NULL) {
+ if (!strcmp(sfeed->filename, arg))
+ break;
+ sfeed = sfeed->next_feed;
+ }
+ if (!sfeed)
+ ERROR("feed '%s' not defined\n", arg);
+ else
+ stream->feed = sfeed;
+ }
+ } else if (!av_strcasecmp(cmd, "Format")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ 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 jpeg */
+ 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) {
+ audio_id = stream->fmt->audio_codec;
+ video_id = stream->fmt->video_codec;
+ }
+ }
+ } else if (!av_strcasecmp(cmd, "InputFormat")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ 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->stream_type == STREAM_TYPE_STATUS) {
+ 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")) {
+ if (stream)
+ get_arg(stream->author, sizeof(stream->author), &p);
+ } else if (!av_strcasecmp(cmd, "Comment")) {
+ if (stream)
+ get_arg(stream->comment, sizeof(stream->comment), &p);
+ } else if (!av_strcasecmp(cmd, "Copyright")) {
+ if (stream)
+ get_arg(stream->copyright, sizeof(stream->copyright), &p);
+ } else if (!av_strcasecmp(cmd, "Title")) {
+ if (stream)
+ get_arg(stream->title, sizeof(stream->title), &p);
+ } else if (!av_strcasecmp(cmd, "Preroll")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream)
+ stream->prebuffer = atof(arg) * 1000;
+ } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
+ if (stream)
+ stream->send_on_key = 1;
+ } else if (!av_strcasecmp(cmd, "AudioCodec")) {
+ get_arg(arg, sizeof(arg), &p);
+ audio_id = opt_audio_codec(arg);
+ if (audio_id == AV_CODEC_ID_NONE) {
+ ERROR("Unknown AudioCodec: %s\n", arg);
+ }
+ } else if (!av_strcasecmp(cmd, "VideoCodec")) {
+ get_arg(arg, sizeof(arg), &p);
+ video_id = opt_video_codec(arg);
+ if (video_id == AV_CODEC_ID_NONE) {
+ ERROR("Unknown VideoCodec: %s\n", arg);
+ }
+ } else if (!av_strcasecmp(cmd, "MaxTime")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream)
+ stream->max_time = atof(arg) * 1000;
+ } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream)
+ audio_enc.bit_rate = lrintf(atof(arg) * 1000);
+ } else if (!av_strcasecmp(cmd, "AudioChannels")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream)
+ audio_enc.channels = atoi(arg);
+ } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream)
+ audio_enc.sample_rate = atoi(arg);
+ } else if (!av_strcasecmp(cmd, "AudioQuality")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+// audio_enc.quality = atof(arg) * 1000;
+ }
+ } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
+ if (stream) {
+ int minrate, maxrate;
+
+ get_arg(arg, sizeof(arg), &p);
+
+ if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
+ video_enc.rc_min_rate = minrate * 1000;
+ video_enc.rc_max_rate = maxrate * 1000;
+ } else {
+ ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
+ }
+ }
+ } else if (!av_strcasecmp(cmd, "Debug")) {
+ if (stream) {
+ get_arg(arg, sizeof(arg), &p);
+ video_enc.debug = strtol(arg,0,0);
+ }
+ } else if (!av_strcasecmp(cmd, "Strict")) {
+ if (stream) {
+ get_arg(arg, sizeof(arg), &p);
+ video_enc.strict_std_compliance = atoi(arg);
+ }
+ } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
+ if (stream) {
+ get_arg(arg, sizeof(arg), &p);
+ video_enc.rc_buffer_size = atoi(arg) * 8*1024;
+ }
+ } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
+ if (stream) {
+ get_arg(arg, sizeof(arg), &p);
+ video_enc.bit_rate_tolerance = atoi(arg) * 1000;
+ }
+ } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ video_enc.bit_rate = atoi(arg) * 1000;
+ }
+ } else if (!av_strcasecmp(cmd, "VideoSize")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ av_parse_video_size(&video_enc.width, &video_enc.height, arg);
+ if ((video_enc.width % 16) != 0 ||
+ (video_enc.height % 16) != 0) {
+ ERROR("Image size must be a multiple of 16\n");
+ }
+ }
+ } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ AVRational frame_rate;
+ if (av_parse_video_rate(&frame_rate, arg) < 0) {
+ ERROR("Incorrect frame rate: %s\n", arg);
+ } else {
+ video_enc.time_base.num = frame_rate.den;
+ video_enc.time_base.den = frame_rate.num;
+ }
+ }
+ } else if (!av_strcasecmp(cmd, "PixelFormat")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ video_enc.pix_fmt = av_get_pix_fmt(arg);
+ if (video_enc.pix_fmt == AV_PIX_FMT_NONE) {
+ ERROR("Unknown pixel format: %s\n", arg);
+ }
+ }
+ } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream)
+ video_enc.gop_size = atoi(arg);
+ } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
+ if (stream)
+ video_enc.gop_size = 1;
+ } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
+ if (stream)
+ video_enc.mb_decision = FF_MB_DECISION_BITS;
+ } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
+ if (stream) {
+ video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
+ video_enc.flags |= CODEC_FLAG_4MV;
+ }
+ } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
+ !av_strcasecmp(cmd, "AVOptionAudio")) {
+ char arg2[1024];
+ AVCodecContext *avctx;
+ int type;
+ get_arg(arg, sizeof(arg), &p);
+ get_arg(arg2, sizeof(arg2), &p);
+ if (!av_strcasecmp(cmd, "AVOptionVideo")) {
+ avctx = &video_enc;
+ type = AV_OPT_FLAG_VIDEO_PARAM;
+ } else {
+ avctx = &audio_enc;
+ type = AV_OPT_FLAG_AUDIO_PARAM;
+ }
+ if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
+ ERROR("AVOption error: %s %s\n", arg, arg2);
+ }
+ } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
+ !av_strcasecmp(cmd, "AVPresetAudio")) {
+ AVCodecContext *avctx;
+ int type;
+ get_arg(arg, sizeof(arg), &p);
+ if (!av_strcasecmp(cmd, "AVPresetVideo")) {
+ avctx = &video_enc;
+ video_enc.codec_id = video_id;
+ type = AV_OPT_FLAG_VIDEO_PARAM;
+ } else {
+ avctx = &audio_enc;
+ audio_enc.codec_id = audio_id;
+ type = AV_OPT_FLAG_AUDIO_PARAM;
+ }
+ if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
+ ERROR("AVPreset error: %s\n", arg);
+ }
+ } else if (!av_strcasecmp(cmd, "VideoTag")) {
+ get_arg(arg, sizeof(arg), &p);
+ if ((strlen(arg) == 4) && stream)
+ video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
+ } else if (!av_strcasecmp(cmd, "BitExact")) {
+ if (stream)
+ video_enc.flags |= CODEC_FLAG_BITEXACT;
+ } else if (!av_strcasecmp(cmd, "DctFastint")) {
+ if (stream)
+ video_enc.dct_algo = FF_DCT_FASTINT;
+ } else if (!av_strcasecmp(cmd, "IdctSimple")) {
+ if (stream)
+ video_enc.idct_algo = FF_IDCT_SIMPLE;
+ } else if (!av_strcasecmp(cmd, "Qscale")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ video_enc.flags |= CODEC_FLAG_QSCALE;
+ video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
+ }
+ } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ video_enc.max_qdiff = atoi(arg);
+ if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
+ ERROR("VideoQDiff out of range\n");
+ }
+ }
+ } else if (!av_strcasecmp(cmd, "VideoQMax")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ video_enc.qmax = atoi(arg);
+ if (video_enc.qmax < 1 || video_enc.qmax > 31) {
+ ERROR("VideoQMax out of range\n");
+ }
+ }
+ } else if (!av_strcasecmp(cmd, "VideoQMin")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ video_enc.qmin = atoi(arg);
+ if (video_enc.qmin < 1 || video_enc.qmin > 31) {
+ ERROR("VideoQMin out of range\n");
+ }
+ }
+ } else if (!av_strcasecmp(cmd, "LumiMask")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream)
+ video_enc.lumi_masking = atof(arg);
+ } else if (!av_strcasecmp(cmd, "DarkMask")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream)
+ video_enc.dark_masking = atof(arg);
+ } else if (!av_strcasecmp(cmd, "NoVideo")) {
+ video_id = AV_CODEC_ID_NONE;
+ } else if (!av_strcasecmp(cmd, "NoAudio")) {
+ audio_id = AV_CODEC_ID_NONE;
+ } else if (!av_strcasecmp(cmd, "ACL")) {
+ parse_acl_row(stream, feed, NULL, p, filename, line_num);
+ } else if (!av_strcasecmp(cmd, "DynamicACL")) {
+ if (stream) {
+ get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
+ }
+ } else if (!av_strcasecmp(cmd, "RTSPOption")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ av_freep(&stream->rtsp_option);
+ stream->rtsp_option = av_strdup(arg);
+ }
+ } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ if (resolve_host(&stream->multicast_ip, arg) != 0) {
+ ERROR("Invalid host/IP address: %s\n", arg);
+ }
+ stream->is_multicast = 1;
+ stream->loop = 1; /* default is looping */
+ }
+ } else if (!av_strcasecmp(cmd, "MulticastPort")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream)
+ stream->multicast_port = atoi(arg);
+ } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream)
+ stream->multicast_ttl = atoi(arg);
+ } else if (!av_strcasecmp(cmd, "NoLoop")) {
+ if (stream)
+ stream->loop = 0;
+ } else if (!av_strcasecmp(cmd, "</Stream>")) {
+ if (!stream) {
+ ERROR("No corresponding <Stream> for </Stream>\n");
+ } else {
+ if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
+ if (audio_id != AV_CODEC_ID_NONE) {
+ audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
+ audio_enc.codec_id = audio_id;
+ add_codec(stream, &audio_enc);
+ }
+ if (video_id != AV_CODEC_ID_NONE) {
+ video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
+ video_enc.codec_id = video_id;
+ add_codec(stream, &video_enc);
+ }
+ }
+ stream = NULL;
+ }
+ } else if (!av_strcasecmp(cmd, "<Redirect")) {
+ /*********************************************/
+ char *q;
+ if (stream || feed || redirect) {
+ ERROR("Already in a tag\n");
+ } else {
+ redirect = av_mallocz(sizeof(FFStream));
+ *last_stream = redirect;
+ last_stream = &redirect->next;
+
+ get_arg(redirect->filename, sizeof(redirect->filename), &p);
+ q = strrchr(redirect->filename, '>');
+ if (*q)
+ *q = '\0';
+ redirect->stream_type = STREAM_TYPE_REDIRECT;
+ }
+ } else if (!av_strcasecmp(cmd, "URL")) {
+ if (redirect)
+ get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
+ } else if (!av_strcasecmp(cmd, "</Redirect>")) {
+ if (!redirect) {
+ ERROR("No corresponding <Redirect> for </Redirect>\n");
+ } else {
+ if (!redirect->feed_filename[0]) {
+ ERROR("No URL found for <Redirect>\n");
+ }
+ redirect = NULL;
+ }
+ } else if (!av_strcasecmp(cmd, "LoadModule")) {
+ ERROR("Loadable modules no longer supported\n");
+ } else {
+ ERROR("Incorrect keyword: '%s'\n", cmd);
+ }
+ }
+#undef ERROR
+
+ fclose(f);
+ if (errors)
+ return -1;
+ else
+ return 0;
+}
+
+static void handle_child_exit(int sig)
+{
+ pid_t pid;
+ int status;
+
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ FFStream *feed;
+
+ for (feed = 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)
+{
+ ffserver_debug = 1;
+ logfilename[0] = '-';
+}
+
+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 } };
+
+ 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 (parse_ffconfig(config_filename) < 0) {
+ fprintf(stderr, "Incorrect config file - exiting.\n");
+ exit(1);
+ }
+ av_freep(&config_filename);
+
+ /* open log file if needed */
+ if (logfilename[0] != '\0') {
+ if (!strcmp(logfilename, "-"))
+ logfile = stdout;
+ else
+ logfile = fopen(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/libavcodec/012v.c b/libavcodec/012v.c
new file mode 100644
index 0000000..c2b6a35
--- a/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 09336b0..a73f8d5 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
*/
@@ -24,6 +24,7 @@
* 4XM codec.
*/
+#include "libavutil/avassert.h"
#include "libavutil/frame.h"
#include "libavutil/intreadwrite.h"
#include "avcodec.h"
@@ -32,6 +33,7 @@
#include "get_bits.h"
#include "internal.h"
+
#define BLOCK_TYPE_VLC_BITS 5
#define ACDC_VLC_BITS 9
@@ -129,7 +131,7 @@ typedef struct CFrameBuffer {
typedef struct FourXContext {
AVCodecContext *avctx;
DSPContext dsp;
- AVFrame *last_picture;
+ AVFrame *current_picture, *last_picture;
GetBitContext pre_gb; ///< ac/dc prefix
GetBitContext gb;
GetByteContext g;
@@ -283,7 +285,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;
@@ -327,7 +329,7 @@ static inline void mcdc(uint16_t *dst, uint16_t *src, int log2w,
}
break;
default:
- break;
+ av_assert0(0);
}
}
@@ -345,8 +347,7 @@ static int decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src,
int scale = 1;
unsigned dc = 0;
- if (code < 0 || code > 6 || log2w < 0)
- return AVERROR_INVALIDDATA;
+ av_assert0(code >= 0 && code <= 6 && log2w >= 0);
if (code == 1) {
log2h--;
@@ -363,24 +364,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);
}
@@ -411,19 +430,18 @@ static int decode_p_frame(FourXContext *f, AVFrame *frame,
if (!f->last_picture->data[0]) {
if ((ret = ff_get_buffer(f->avctx, f->last_picture,
AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(f->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return ret;
}
- memset(f->last_picture->data[0], 0,
- f->avctx->height * FFABS(f->last_picture->linesize[0]));
+ for (y=0; y<f->avctx->height; y++)
+ memset(f->last_picture->data[0] + y*f->last_picture->linesize[0], 0, 2*f->avctx->width);
}
src = (uint16_t *)f->last_picture->data[0];
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);
@@ -434,13 +452,12 @@ static int decode_p_frame(FourXContext *f, AVFrame *frame,
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;
}
@@ -482,10 +499,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);
@@ -503,7 +527,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);
@@ -583,7 +612,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];
@@ -592,6 +621,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));
@@ -601,10 +631,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++;
@@ -612,9 +642,6 @@ static const uint8_t *read_huffman_tables(FourXContext *f,
if (start == 0)
break;
- if (--len < 0)
- return NULL;
-
end = *ptr++;
}
frequency[256] = 1;
@@ -622,6 +649,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 +723,7 @@ static int decode_i2_frame(FourXContext *f, AVFrame *frame, const uint8_t *buf,
const int mbs = (FFALIGN(width, 16) >> 4) * (FFALIGN(height, 16) >> 4);
uint16_t *dst = (uint16_t*)frame->data[0];
const int stride = frame->linesize[0]>>1;
+ const uint8_t *buf_end = buf + length;
GetByteContext g3;
if (length < mbs * 8) {
@@ -702,6 +735,8 @@ static int decode_i2_frame(FourXContext *f, AVFrame *frame, const uint8_t *buf,
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 +770,6 @@ static int decode_i_frame(FourXContext *f, AVFrame *frame, const uint8_t *buf, i
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 +781,6 @@ static int decode_i_frame(FourXContext *f, AVFrame *frame, const uint8_t *buf, i
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,6 +797,8 @@ static int decode_i_frame(FourXContext *f, AVFrame *frame, const uint8_t *buf, i
return AVERROR_INVALIDDATA;
}
+ av_assert0(prestream <= buf + length);
+
init_get_bits(&f->gb, buf + 4, 8 * bitstream_size);
prestream_size = length + buf - prestream;
@@ -807,11 +842,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 %d\n",
@@ -827,12 +858,19 @@ static int decode_frame(AVCodecContext *avctx, void *data,
const int data_size = buf_size - 20;
CFrameBuffer *cfrm;
- if (data_size < 0)
+ 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",
@@ -851,11 +889,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);
}
@@ -882,26 +923,32 @@ static int decode_frame(AVCodecContext *avctx, void *data,
frame_size = buf_size - 12;
}
+ FFSWAP(AVFrame*, f->current_picture, f->last_picture);
+
// alternatively we would have to use our own buffer management
avctx->flags |= CODEC_FLAG_EMU_EDGE;
- if ((ret = ff_get_buffer(avctx, picture, AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, f->current_picture)) < 0)
return ret;
- }
if (frame_4cc == AV_RL32("ifr2")) {
- picture->pict_type = AV_PICTURE_TYPE_I;
- if ((ret = decode_i2_frame(f, picture, buf - 4, frame_size + 4)) < 0)
+ f->current_picture->pict_type = AV_PICTURE_TYPE_I;
+ if ((ret = decode_i2_frame(f, f->current_picture, 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, picture, buf, frame_size)) < 0)
+ f->current_picture->pict_type = AV_PICTURE_TYPE_I;
+ if ((ret = decode_i_frame(f, f->current_picture, 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, picture, buf, frame_size)) < 0)
+ f->current_picture->pict_type = AV_PICTURE_TYPE_P;
+ if ((ret = decode_p_frame(f, f->current_picture, 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);
@@ -910,10 +957,9 @@ static int decode_frame(AVCodecContext *avctx, void *data,
buf_size);
}
- picture->key_frame = picture->pict_type == AV_PICTURE_TYPE_I;
+ f->current_picture->key_frame = f->current_picture->pict_type == AV_PICTURE_TYPE_I;
- av_frame_unref(f->last_picture);
- if ((ret = av_frame_ref(f->last_picture, picture)) < 0)
+ if ((ret = av_frame_ref(picture, f->current_picture)) < 0)
return ret;
*got_frame = 1;
@@ -928,7 +974,11 @@ static av_cold int decode_init(AVCodecContext *avctx)
if (avctx->extradata_size != 4 || !avctx->extradata) {
av_log(avctx, AV_LOG_ERROR, "extradata wrong or missing\n");
- return 1;
+ return AVERROR_INVALIDDATA;
+ }
+ if((avctx->width % 16) || (avctx->height % 16)) {
+ av_log(avctx, AV_LOG_ERROR, "unsupported width/height\n");
+ return AVERROR_INVALIDDATA;
}
f->version = AV_RL32(avctx->extradata) >> 16;
@@ -941,8 +991,9 @@ static av_cold int decode_init(AVCodecContext *avctx)
else
avctx->pix_fmt = AV_PIX_FMT_BGR555;
- f->last_picture = av_frame_alloc();
- if (!f->last_picture)
+ f->current_picture = av_frame_alloc();
+ f->last_picture = av_frame_alloc();
+ if (!f->current_picture || !f->last_picture)
return AVERROR(ENOMEM);
return 0;
@@ -961,6 +1012,7 @@ static av_cold int decode_end(AVCodecContext *avctx)
f->cfrm[i].allocated_size = 0;
}
ff_free_vlc(&f->pre_vlc);
+ av_frame_free(&f->current_picture);
av_frame_free(&f->last_picture);
return 0;
diff --git a/libavcodec/8bps.c b/libavcodec/8bps.c
index cfeb486..d01ef92 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 11fbf19..eff525c 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(EINVAL);
+ 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(EINVAL);
}
- 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,50 +135,37 @@ 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;
if (avctx->channels < 1 || avctx->channels > 2) {
av_log(avctx, AV_LOG_ERROR, "8SVX does not support more than 2 channels\n");
- return AVERROR(EINVAL);
+ 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 -1;
+ 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 6f80a9e..d46c546 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1,9 +1,12 @@
+include $(SUBDIR)../config.mak
+
NAME = avcodec
FFLIBS = avutil
HEADERS = avcodec.h \
avfft.h \
dxva2.h \
+ old_codec_ids.h \
vaapi.h \
vda.h \
vdpau.h \
@@ -11,6 +14,7 @@ HEADERS = avcodec.h \
xvmc.h \
OBJS = allcodecs.o \
+ audioconvert.o \
avpacket.o \
avpicture.o \
bitstream.o \
@@ -18,11 +22,13 @@ OBJS = allcodecs.o \
codec_desc.o \
fmtconvert.o \
imgconvert.o \
- log2_tab.o \
mathtables.o \
options.o \
parser.o \
raw.o \
+ rawdec.o \
+ resample.o \
+ resample2.o \
utils.o \
OBJS-$(HAVE_MSVCRT) += file_open.o
@@ -31,14 +37,17 @@ OBJS-$(HAVE_MSVCRT) += file_open.o
OBJS-$(CONFIG_AANDCTTABLES) += aandcttab.o
OBJS-$(CONFIG_AC3DSP) += ac3dsp.o
OBJS-$(CONFIG_AUDIO_FRAME_QUEUE) += audio_frame_queue.o
+OBJS-$(CONFIG_CRYSTALHD) += crystalhd.o
OBJS-$(CONFIG_DCT) += dct.o dct32_fixed.o dct32_float.o
OBJS-$(CONFIG_DXVA2) += dxva2.o
OBJS-$(CONFIG_DSPUTIL) += dsputil.o faanidct.o \
simple_idct.o jrevdct.o
OBJS-$(CONFIG_ENCODERS) += faandct.o jfdctfst.o jfdctint.o
OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o
+OBJS-$(CONFIG_EXIF) += exif.o tiff_common.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_H264CHROMA) += h264chroma.o
@@ -50,7 +59,7 @@ OBJS-$(CONFIG_HUFFMAN) += huffman.o
OBJS-$(CONFIG_LIBXVID) += libxvid_rc.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_MPEGAUDIO) += mpegaudio.o mpegaudiodata.o \
mpegaudiodecheader.o
OBJS-$(CONFIG_MPEGAUDIODSP) += mpegaudiodsp.o \
@@ -63,6 +72,7 @@ OBJS-$(CONFIG_MPEGVIDEOENC) += mpegvideo_enc.o mpeg12data.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_VAAPI) += vaapi.o
OBJS-$(CONFIG_VDPAU) += vdpau.o
@@ -70,6 +80,7 @@ OBJS-$(CONFIG_VIDEODSP) += videodsp.o
OBJS-$(CONFIG_VP3DSP) += vp3dsp.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,10 +108,16 @@ OBJS-$(CONFIG_AMRWB_DECODER) += amrwbdec.o celp_filters.o \
acelp_vectors.o \
acelp_pitch_delay.o
OBJS-$(CONFIG_AMV_DECODER) += sp5xdec.o mjpegdec.o mjpeg.o
+OBJS-$(CONFIG_AMV_ENCODER) += mjpegenc.o mjpeg.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
@@ -110,16 +127,25 @@ OBJS-$(CONFIG_ATRAC1_DECODER) += atrac1.o atrac.o
OBJS-$(CONFIG_ATRAC3_DECODER) += atrac3.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 wma.o wma_common.o
OBJS-$(CONFIG_BINKAUDIO_RDFT_DECODER) += binkaudio.o wma.o wma_common.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_VIDEO_DECODER) += bmv.o
OBJS-$(CONFIG_BMV_AUDIO_DECODER) += bmv.o
+OBJS-$(CONFIG_BRENDER_PIX_DECODER) += brender_pix.o
OBJS-$(CONFIG_C93_DECODER) += c93.o
OBJS-$(CONFIG_CAVS_DECODER) += cavs.o cavsdec.o cavsdsp.o \
cavsdata.o mpeg12data.o
@@ -132,10 +158,14 @@ 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
@@ -165,14 +195,18 @@ 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_FFVHUFF_DECODER) += huffyuv.o huffyuvdec.o
OBJS-$(CONFIG_FFVHUFF_ENCODER) += huffyuv.o huffyuvenc.o
+OBJS-$(CONFIG_FFWAVESYNTH_DECODER) += ffwavesynth.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
@@ -180,7 +214,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
@@ -196,10 +232,16 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o \
h264_loopfilter.o h264_direct.o \
cabac.o h264_sei.o h264_ps.o \
h264_refs.o h264_cavlc.o h264_cabac.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 cabac.o
+
OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o huffyuvdec.o
OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o huffyuvenc.o
OBJS-$(CONFIG_IAC_DECODER) += imc.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
@@ -209,6 +251,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 \
jpeg2000dwt.o mqcdec.o mqc.o
OBJS-$(CONFIG_JPEGLS_DECODER) += jpeglsdec.o jpegls.o \
@@ -225,6 +270,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
@@ -232,6 +278,8 @@ OBJS-$(CONFIG_MJPEGB_DECODER) += mjpegbdec.o mjpegdec.o mjpeg.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.o
OBJS-$(CONFIG_MP1FLOAT_DECODER) += mpegaudiodec_float.o
OBJS-$(CONFIG_MP2_DECODER) += mpegaudiodec.o
@@ -246,11 +294,15 @@ OBJS-$(CONFIG_MP3ON4_DECODER) += mpegaudiodec.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_MPEGVIDEO_DECODER) += mpeg12.o mpeg12data.o \
+ mpegvideo.o error_resilience.o
OBJS-$(CONFIG_MPEG_XVMC_DECODER) += mpegvideo_xvmc.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_MPEG2VIDEO_ENCODER) += mpeg12enc.o mpeg12.o \
+ timecode.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 \
h263dec.o h263.o ituh263dec.o \
@@ -267,12 +319,17 @@ 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
+OBJS-$(CONFIG_MVC2_DECODER) += mvcdec.o
OBJS-$(CONFIG_MXPEG_DECODER) += mxpegdec.o mjpegdec.o mjpeg.o
OBJS-$(CONFIG_NELLYMOSER_DECODER) += nellymoserdec.o nellymoser.o
OBJS-$(CONFIG_NELLYMOSER_ENCODER) += nellymoserenc.o nellymoser.o
OBJS-$(CONFIG_NUV_DECODER) += nuv.o rtjpeg.o
+OBJS-$(CONFIG_PAF_VIDEO_DECODER) += paf.o
+OBJS-$(CONFIG_PAF_AUDIO_DECODER) += paf.o
OBJS-$(CONFIG_PAM_DECODER) += pnmdec.o pnm.o
OBJS-$(CONFIG_PAM_ENCODER) += pamenc.o pnm.o
OBJS-$(CONFIG_PBM_DECODER) += pnmdec.o pnm.o
@@ -285,12 +342,16 @@ OBJS-$(CONFIG_PGMYUV_DECODER) += pnmdec.o pnm.o
OBJS-$(CONFIG_PGMYUV_ENCODER) += pnmenc.o pnm.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 pnm.o
-OBJS-$(CONFIG_PRORES_DECODER) += proresdec.o proresdata.o proresdsp.o
-OBJS-$(CONFIG_PRORES_ENCODER) += proresenc.o proresdata.o proresdsp.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 proresdsp.o
OBJS-$(CONFIG_PTX_DECODER) += ptx.o
OBJS-$(CONFIG_QCELP_DECODER) += qcelpdec.o \
celp_filters.o acelp_vectors.o \
@@ -301,13 +362,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
@@ -320,9 +384,13 @@ 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
+OBJS-$(CONFIG_SGIRLE_DECODER) += sgirledec.o
OBJS-$(CONFIG_SHORTEN_DECODER) += shorten.o
OBJS-$(CONFIG_SIPR_DECODER) += sipr.o acelp_pitch_delay.o \
celp_math.o acelp_vectors.o \
@@ -331,9 +399,21 @@ 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 mjpegdec.o mjpeg.o
OBJS-$(CONFIG_SRT_DECODER) += srtdec.o ass.o
+OBJS-$(CONFIG_SRT_ENCODER) += srtenc.o ass_split.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
@@ -343,21 +423,25 @@ OBJS-$(CONFIG_SVQ3_DECODER) += svq3.o svq13.o h263.o h264.o \
h264_loopfilter.o h264_direct.o \
h264_sei.o h264_ps.o h264_refs.o \
h264_cavlc.o h264_cabac.o cabac.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_THEORA_DECODER) += xiph.o
OBJS-$(CONFIG_THP_DECODER) += mjpegdec.o mjpeg.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
+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
@@ -365,6 +449,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
@@ -372,7 +460,7 @@ OBJS-$(CONFIG_VB_DECODER) += vb.o
OBJS-$(CONFIG_VBLE_DECODER) += vble.o
OBJS-$(CONFIG_VC1_DECODER) += vc1dec.o vc1.o vc1data.o vc1dsp.o \
msmpeg4dec.o msmpeg4.o msmpeg4data.o \
- intrax8.o intrax8dsp.o
+ intrax8.o intrax8dsp.o wmv2dsp.o
OBJS-$(CONFIG_VCR1_DECODER) += vcr1.o
OBJS-$(CONFIG_VMDAUDIO_DECODER) += vmdav.o
OBJS-$(CONFIG_VMDVIDEO_DECODER) += vmdav.o
@@ -387,9 +475,14 @@ OBJS-$(CONFIG_VP5_DECODER) += vp5.o vp56.o vp56data.o vp56dsp.o \
OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o vp56dsp.o \
vp6dsp.o vp56rac.o
OBJS-$(CONFIG_VP8_DECODER) += vp8.o vp8dsp.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_WAVPACK_ENCODER) += wavpackenc.o
+OBJS-$(CONFIG_WEBP_DECODER) += vp8.o vp8dsp.o vp56rac.o
OBJS-$(CONFIG_WEBP_DECODER) += webp.o
+OBJS-$(CONFIG_WEBVTT_DECODER) += webvttdec.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
@@ -410,13 +503,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
@@ -441,12 +542,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
@@ -454,11 +559,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
@@ -478,7 +585,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
@@ -496,8 +605,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
@@ -513,9 +624,10 @@ OBJS-$(CONFIG_ADPCM_THP_DECODER) += adpcm.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_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
@@ -523,12 +635,12 @@ 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_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_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
@@ -537,41 +649,46 @@ OBJS-$(CONFIG_ADX_DEMUXER) += adx.o
OBJS-$(CONFIG_CAF_DEMUXER) += mpeg4audio.o mpegaudiodata.o \
ac3tab.o
OBJS-$(CONFIG_DV_DEMUXER) += dv_profile.o
-OBJS-$(CONFIG_DV_MUXER) += dv_profile.o
-OBJS-$(CONFIG_FLAC_DEMUXER) += flac.o flacdata.o \
+OBJS-$(CONFIG_DV_MUXER) += dv_profile.o timecode.o
+OBJS-$(CONFIG_FLAC_DEMUXER) += flac.o flacdata.o vorbis_data.o \
vorbis_parser.o xiph.o
-OBJS-$(CONFIG_FLAC_MUXER) += flac.o flacdata.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) += xiph.o mpeg4audio.o \
+OBJS-$(CONFIG_MATROSKA_AUDIO_MUXER) += xiph.o 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 xiph.o
+ flac.o flacdata.o vorbis_data.o xiph.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_DEMUXER) += mpeg4audio.o mpegaudiodata.o ac3tab.o timecode.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) += timecode.o dnxhddata.o
OBJS-$(CONFIG_NUT_MUXER) += mpegaudiodata.o
OBJS-$(CONFIG_OGG_DEMUXER) += xiph.o flac.o flacdata.o \
mpeg12data.o vorbis_parser.o \
- dirac.o
-OBJS-$(CONFIG_OGG_MUXER) += xiph.o flac.o flacdata.o
+ dirac.o vorbis_data.o
+OBJS-$(CONFIG_OGG_MUXER) += xiph.o flac.o flacdata.o \
+ vorbis_data.o
OBJS-$(CONFIG_RTP_MUXER) += mpeg4audio.o xiph.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 \
- xiph.o flac.o flacdata.o
+ xiph.o flac.o flacdata.o \
+ vorbis_data.o
OBJS-$(CONFIG_WTV_DEMUXER) += mpeg4audio.o mpegaudiodata.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
@@ -595,13 +712,19 @@ 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 \
- vorbis_data.o vorbis_parser.o
+OBJS-$(CONFIG_LIBVORBIS_DECODER) += libvorbisdec.o
+OBJS-$(CONFIG_LIBVORBIS_ENCODER) += libvorbisenc.o \
+ vorbis_data.o vorbis_parser.o xiph.o
OBJS-$(CONFIG_LIBVPX_VP8_DECODER) += libvpxdec.o
OBJS-$(CONFIG_LIBVPX_VP8_ENCODER) += libvpxenc.o
OBJS-$(CONFIG_LIBVPX_VP9_DECODER) += libvpxdec.o
@@ -610,6 +733,7 @@ OBJS-$(CONFIG_LIBWAVPACK_ENCODER) += libwavpackenc.o
OBJS-$(CONFIG_LIBX264_ENCODER) += libx264.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 \
@@ -618,14 +742,18 @@ OBJS-$(CONFIG_AAC_LATM_PARSER) += latm_parser.o
OBJS-$(CONFIG_AC3_PARSER) += ac3_parser.o ac3tab.o \
aac_ac3_parser.o
OBJS-$(CONFIG_ADX_PARSER) += adx_parser.o adx.o
+OBJS-$(CONFIG_BMP_PARSER) += bmp_parser.o
OBJS-$(CONFIG_CAVSVIDEO_PARSER) += cavs_parser.o
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
@@ -634,11 +762,13 @@ OBJS-$(CONFIG_H264_PARSER) += h264_parser.o h264.o \
h264_refs.o h264_sei.o h264_direct.o \
h264_loopfilter.o h264_cabac.o \
h264_cavlc.o h264_ps.o
+OBJS-$(CONFIG_HEVC_PARSER) += hevc_parser.o
OBJS-$(CONFIG_MJPEG_PARSER) += mjpeg_parser.o
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 \
@@ -674,32 +804,42 @@ OBJS-$(CONFIG_TEXT2MOVSUB_BSF) += movsub_bsf.o
# thread libraries
OBJS-$(HAVE_PTHREADS) += pthread.o
OBJS-$(HAVE_W32THREADS) += pthread.o
+OBJS-$(HAVE_OS2THREADS) += pthread.o
+
+OBJS-$(CONFIG_FRAME_THREAD_ENCODER) += frame_thread_encoder.o
SKIPHEADERS += %_tablegen.h \
%_tables.h \
aac_tablegen_decl.h \
fft-internal.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_LIBUTVIDEO) += libutvideo.h
SKIPHEADERS-$(CONFIG_MPEG_XVMC_DECODER) += xvmc.h
SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_internal.h
SKIPHEADERS-$(CONFIG_VDA) += vda.h
SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h vdpau_internal.h
-EXAMPLES = api
-
-TESTPROGS = dct \
+TESTPROGS = cabac \
fft \
fft-fixed \
+ fft-fixed32 \
golomb \
iirfilter \
+ imgconvert \
rangecoder \
+ snowenc \
+TESTPROGS-$(CONFIG_DCT) += dct
+TESTPROGS-$(HAVE_MMX) += motion
TESTOBJS = dctref.o
+TOOLS = fourcc2pixfmt
+
HOSTPROGS = aac_tablegen \
aacps_tablegen \
cbrt_tablegen \
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 d5f8e9a..0000000
--- a/libavcodec/a64enc.h
+++ b/dev/null
@@ -1,58 +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 {
- /* general variables */
- AVFrame picture;
-
- /* 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 f2c6c4a..e5c0fa7 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,31 @@
#define INTERLACED 1
#define CROP_SCREENS 1
+#define C64XRES 320
+#define C64YRES 200
+
+typedef struct A64Context {
+ /* general variables */
+ AVFrame picture;
+
+ /* 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};
@@ -255,7 +279,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;
@@ -309,10 +333,8 @@ 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 */
@@ -371,6 +393,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"),
@@ -383,7 +406,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)"),
@@ -396,3 +420,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..89f463e 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
*/
@@ -259,7 +259,8 @@ typedef struct ChannelElement {
/**
* main AAC context
*/
-typedef struct AACContext {
+struct AACContext {
+ AVClass *class;
AVCodecContext *avctx;
AVFrame *frame;
@@ -303,9 +304,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 b17cd4d..6f1e188 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 bec6e7f..c8f9e0a 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
*/
@@ -112,7 +112,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..ab6ca4e 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
*/
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..1c19a15 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
*/
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 30f92e0..c9718c4 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..50a246f 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
*/
@@ -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;
@@ -875,7 +875,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];
@@ -1112,26 +1112,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 ae22e67..eb6ee5e 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
*/
@@ -81,6 +81,7 @@
*/
#include "libavutil/float_dsp.h"
+#include "libavutil/opt.h"
#include "avcodec.h"
#include "internal.h"
#include "get_bits.h"
@@ -107,12 +108,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)
{
@@ -129,7 +136,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
@@ -151,6 +158,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,10 +195,8 @@ static int frame_configure_elements(AVCodecContext *avctx)
/* get output buffer */
av_frame_unref(ac->frame);
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++) {
@@ -426,6 +435,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);
}
}
@@ -471,7 +482,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;
@@ -483,6 +495,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.
@@ -520,6 +549,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;
@@ -537,6 +568,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;
@@ -623,6 +656,8 @@ static void decode_channel_map(uint8_t layout_map[][3],
case AAC_CHANNEL_LFE:
syn_ele = TYPE_LFE;
break;
+ default:
+ av_assert0(0);
}
layout_map[0][0] = syn_ele;
layout_map[0][1] = get_bits(gb, 4);
@@ -668,6 +703,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);
@@ -687,7 +726,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);
@@ -861,9 +900,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)
@@ -927,7 +966,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;
@@ -981,6 +1020,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;
@@ -989,6 +1030,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) {
@@ -1027,6 +1070,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);
@@ -1088,7 +1136,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);
@@ -1191,13 +1239,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,
@@ -1215,10 +1263,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;
}
/**
@@ -1249,7 +1300,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) {
@@ -1421,7 +1472,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);
}
}
@@ -2155,6 +2206,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.
*
@@ -2196,6 +2273,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:
@@ -2218,7 +2297,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;
@@ -2310,10 +2389,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])
@@ -2600,7 +2679,7 @@ 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++) {
@@ -2611,25 +2690,25 @@ static void spectral_to_sample(AACContext *ac)
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);
@@ -2651,10 +2730,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) {
@@ -2670,6 +2751,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;
@@ -2747,13 +2843,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;
@@ -2792,6 +2889,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:
@@ -2824,9 +2922,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;
@@ -2836,7 +2935,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;
}
@@ -2867,17 +2966,35 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data,
multiplier = (ac->oc[1].m4ac.sbr == 1) ? ac->oc[1].m4ac.ext_sample_rate > ac->oc[1].m4ac.sample_rate : 0;
samples <<= multiplier;
+ /* 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 (samples)
ac->frame->nb_samples = samples;
+ else
+ av_frame_unref(ac->frame);
*got_frame_ptr = !!samples;
+ 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];
+ }
+
if (ac->oc[1].status && audio_found) {
avctx->sample_rate = ac->oc[1].m4ac.sample_rate << multiplier;
avctx->frame_size = samples;
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));
+ }
return 0;
fail:
pop_output_configuration(ac);
@@ -2898,8 +3015,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);
@@ -2916,6 +3037,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;
@@ -2927,7 +3057,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;
@@ -2965,7 +3095,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
@@ -3010,10 +3140,15 @@ static int latm_decode_audio_specific_config(struct LATMContext *latmctx,
if (bits_consumed < 0)
return AVERROR_INVALIDDATA;
- if (ac->oc[1].m4ac.sample_rate != m4ac.sample_rate ||
+ if (!latmctx->initialized ||
+ 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;
@@ -3056,9 +3191,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;
@@ -3171,7 +3306,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
@@ -3179,7 +3314,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;
@@ -3209,7 +3344,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;
@@ -3226,6 +3361,40 @@ 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,
+};
AVCodec ff_aac_decoder = {
.name = "aac",
@@ -3241,6 +3410,8 @@ AVCodec ff_aac_decoder = {
},
.capabilities = CODEC_CAP_CHANNEL_CONF | CODEC_CAP_DR1,
.channel_layouts = aac_channel_layout,
+ .flush = flush,
+ .priv_class = &aac_decoder_class,
};
/*
@@ -3262,4 +3433,5 @@ AVCodec ff_aac_latm_decoder = {
},
.capabilities = CODEC_CAP_CHANNEL_CONF | CODEC_CAP_DR1,
.channel_layouts = aac_channel_layout,
+ .flush = flush,
};
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 55aa2f1..5596b4b 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)
{
@@ -571,11 +570,8 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
}
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;
@@ -768,7 +764,10 @@ 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];
+
+ if (HAVE_MIPSDSPR1)
+ ff_aac_coder_init_mips(s);
s->lambda = avctx->global_quality ? avctx->global_quality : 120;
@@ -792,6 +791,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 +806,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 +822,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 1abafe2..9abc296 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;
}
@@ -603,7 +620,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)
@@ -807,7 +823,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 && 2*b <= NR_PAR_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 635737d..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
*/
diff --git a/libavcodec/aacps_tablegen.h b/libavcodec/aacps_tablegen.h
index 701812b..05a2af6 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
*/
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 e90c50b..9f62844 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 93737d2..74a8af6 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..d2a782e 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;
@@ -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 650f7aa..0b6779c 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
*/
@@ -35,13 +35,19 @@
#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,6 +91,8 @@ 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;
@@ -140,6 +148,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 +161,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 +345,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 +370,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 +399,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,
@@ -549,7 +562,7 @@ static int sbr_hf_calc_npatches(AACContext *ac, SpectralBandReplication *sbr)
k = sbr->n_master;
} while (sb != sbr->kx[1] + sbr->m[1]);
- if (sbr->patch_num_subbands[sbr->num_patches-1] < 3 && sbr->num_patches > 1)
+ if (sbr->num_patches > 1 && sbr->patch_num_subbands[sbr->num_patches-1] < 3)
sbr->num_patches--;
return 0;
@@ -743,7 +756,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;
@@ -927,7 +940,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;
@@ -1116,7 +1131,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;
}
@@ -1125,7 +1145,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;
}
@@ -1134,9 +1159,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] =
@@ -1151,6 +1182,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)
@@ -1168,11 +1200,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],
@@ -1218,6 +1252,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)
@@ -1571,10 +1606,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;
@@ -1598,7 +1629,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;
@@ -1628,13 +1658,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;
@@ -1667,10 +1701,10 @@ 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, sbr->data[ch].W, sbr->data[ch].Ypos);
+ sbr->c.sbr_lf_gen(ac, sbr, sbr->X_low, 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, sbr->X_low, sbr->k[0]);
+ sbr->c.sbr_hf_inverse_filter(&sbr->dsp, sbr->alpha0, sbr->alpha1, sbr->X_low, sbr->k[0]);
sbr_chirp(sbr, &sbr->data[ch]);
sbr_hf_gen(ac, sbr, sbr->X_high, sbr->X_low, sbr->alpha0, sbr->alpha1,
sbr->data[ch].bw_array, sbr->data[ch].t_env,
@@ -1681,14 +1715,14 @@ 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],
sbr->X_high, sbr, &sbr->data[ch],
sbr->data[ch].e_a);
}
}
/* synthesis */
- sbr_x_gen(sbr, sbr->X[ch],
+ sbr->c.sbr_x_gen(sbr, sbr->X[ch],
sbr->data[ch].Y[1-sbr->data[ch].Ypos],
sbr->data[ch].Y[ sbr->data[ch].Ypos],
sbr->X_low, ch);
@@ -1715,3 +1749,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/aacsbrdata.h b/libavcodec/aacsbrdata.h
index f309059..12575ee 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
*/
@@ -352,7 +352,7 @@ static DECLARE_ALIGNED(32, float, sbr_qmf_window_us)[640] = {
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 +610,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 77cbc2d..7ec8374 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 a2dc46b..699d99d 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..87c50b3 100644
--- a/libavcodec/aandcttab.c
+++ b/libavcodec/aandcttab.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/aandcttab.h b/libavcodec/aandcttab.h
index daccb7b..d774828 100644
--- a/libavcodec/aandcttab.h
+++ b/libavcodec/aandcttab.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/aasc.c b/libavcodec/aasc.c
index 468e394..38658f8 100644
--- a/libavcodec/aasc.c
+++ b/libavcodec/aasc.c
@@ -2,20 +2,20 @@
* Autodesk RLE Decoder
* 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 647432f..e609bb5 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 */
diff --git a/libavcodec/ac3_parser.c b/libavcodec/ac3_parser.c
index 4abcf16..8dc4c0d 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
*/
diff --git a/libavcodec/ac3_parser.h b/libavcodec/ac3_parser.h
index 9322550..b5022de 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
*/
diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c
index 3edb3af..1603f4f 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
*/
@@ -441,7 +441,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;
@@ -1325,7 +1325,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)) {
@@ -1358,6 +1358,10 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
avctx->channels = s->out_channels;
avctx->channel_layout = s->channel_layout;
+ 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)) {
@@ -1376,19 +1380,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];
}
for (blk = 0; blk < s->num_blocks; blk++) {
if (!err && decode_audio_block(s, blk)) {
@@ -1397,13 +1400,17 @@ 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(((float*)frame->data[ch]) + AC3_BLOCK_SIZE*blk, output[ch], sizeof(**output) * AC3_BLOCK_SIZE);
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);
@@ -1429,6 +1436,13 @@ static av_cold int ac3_decode_end(AVCodecContext *avctx)
#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, 1.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},
};
diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h
index 06b8544..ae72d80 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
*/
@@ -89,6 +89,12 @@ typedef struct AC3DecodeContext {
int eac3; ///< indicates if current frame is E-AC-3
///@}
+ int preferred_stereo_downmix;
+ float ltrt_center_mix_level;
+ float ltrt_surround_mix_level;
+ float loro_center_mix_level;
+ float loro_surround_mix_level;
+
///@name Frame syntax parameters
int snr_offset_strategy; ///< SNR offset strategy (snroffststr)
int block_switch_syntax; ///< block switch syntax enabled (blkswe)
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/ac3dsp.c b/libavcodec/ac3dsp.c
index ef19f6a..6df3a68 100644
--- a/libavcodec/ac3dsp.c
+++ b/libavcodec/ac3dsp.c
@@ -2,20 +2,20 @@
* AC-3 DSP utils
* 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
*/
@@ -23,6 +23,7 @@
#include "avcodec.h"
#include "ac3.h"
#include "ac3dsp.h"
+#include "mathops.h"
static void ac3_exponent_min_c(uint8_t *exp, int num_reuse_blocks, int nb_coefs)
{
@@ -171,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)
{
@@ -207,10 +250,14 @@ 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;
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 882eb76..bafbc89 100644
--- a/libavcodec/ac3dsp.h
+++ b/libavcodec/ac3dsp.h
@@ -2,20 +2,20 @@
* AC-3 DSP utils
* 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,6 +126,12 @@ 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);
} AC3DSPContext;
@@ -133,5 +139,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 ce6c1a6..37c496c 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
*/
@@ -271,7 +271,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;
@@ -1208,14 +1208,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) {
@@ -1284,7 +1281,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;
@@ -2020,6 +2017,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);
diff --git a/libavcodec/ac3enc.h b/libavcodec/ac3enc.h
index be9dcf2..a04e704 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 6e25189..b1f9c21 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
*/
@@ -34,8 +34,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"
@@ -107,6 +112,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 86a5cff..532c56c 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 @@
#if CONFIG_AC3_ENCODER
#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,
+};
#endif
#include "ac3enc_template.c"
@@ -117,6 +121,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 339a08f..a252be9 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 ae9100c..354be53 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
*/
@@ -44,6 +44,9 @@ static void clip_coefficients(DSPContext *dsp, CoefType *coef, unsigned int len)
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)
{
@@ -67,7 +70,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)
{
@@ -130,7 +133,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;
@@ -333,8 +336,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;
@@ -358,20 +361,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]))
@@ -440,10 +435,8 @@ 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)
diff --git a/libavcodec/ac3tab.c b/libavcodec/ac3tab.c
index ebcfb0b..1ae7ddf 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
*/
@@ -114,7 +114,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 c2b3feb..c41a93e 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 ab09bdb..c005c4b 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"
@@ -106,9 +107,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(dsp->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 e5410bb..72977f1 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..8e20de2 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -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];
@@ -440,6 +483,9 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
*coded_samples = 0;
+ if(ch <= 0)
+ return 0;
+
switch (avctx->codec->id) {
/* constant, only check buf_size */
case AV_CODEC_ID_ADPCM_EA_XAS:
@@ -456,6 +502,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 +517,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;
@@ -525,11 +572,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 +622,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 */
@@ -609,10 +675,8 @@ 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;
@@ -681,6 +745,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 +773,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 +852,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);
@@ -871,6 +953,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 +1060,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 +1248,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 +1258,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:
@@ -1223,22 +1344,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 +1447,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);
@@ -1304,7 +1544,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 +1560,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..f43a28c 100644
--- a/libavcodec/adpcm.h
+++ b/libavcodec/adpcm.h
@@ -1,20 +1,20 @@
/*
* 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..1d3e579 100644
--- a/libavcodec/adpcm_data.c
+++ b/libavcodec/adpcm_data.c
@@ -1,20 +1,20 @@
/*
* 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..a14d520 100644
--- a/libavcodec/adpcm_data.h
+++ b/libavcodec/adpcm_data.h
@@ -1,20 +1,20 @@
/*
* 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 fb3ce0d..5391570 100644
--- a/libavcodec/adpcmenc.c
+++ b/libavcodec/adpcmenc.c
@@ -5,25 +5,24 @@
* 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;
@@ -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) {
diff --git a/libavcodec/adx.c b/libavcodec/adx.c
index 6335865..94bc386 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
*/
@@ -47,6 +47,11 @@ int avpriv_adx_decode_header(AVCodecContext *avctx, const uint8_t *buf,
return AVERROR_INVALIDDATA;
offset = AV_RB16(buf + 2) + 4;
+ if (offset < 6) {
+ av_log(avctx, AV_LOG_ERROR, "offset is prior data\n");
+ return AVERROR_INVALIDDATA;
+ }
+
/* if copyright string is within the provided data, validate it */
if (bufsize >= offset && memcmp(buf + offset - 6, "(c)CRI", 6))
return AVERROR_INVALIDDATA;
diff --git a/libavcodec/adx.h b/libavcodec/adx.h
index ff4c2d6..b28d09a 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 17d5bec..e59cc92 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;
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 5981dd8..a7e3691 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
*/
@@ -201,7 +201,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);
@@ -215,14 +216,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);
@@ -232,7 +233,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;
}
diff --git a/libavcodec/alac.c b/libavcodec/alac.c
index f972531..3f37f61 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)
@@ -50,6 +50,7 @@
#include "get_bits.h"
#include "bytestream.h"
#include "internal.h"
+#include "thread.h"
#include "unary.h"
#include "mathops.h"
#include "alac_data.h"
@@ -73,6 +74,8 @@ 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;
} ALACContext;
static inline unsigned int decode_scalar(GetBitContext *gb, int k, int bps)
@@ -97,7 +100,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;
@@ -108,6 +111,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);
@@ -148,6 +154,7 @@ static void rice_decompress(ALACContext *alac, int32_t *output_buffer,
history = 0;
}
}
+ return 0;
}
static inline int sign_only(int v)
@@ -184,7 +191,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. */
@@ -263,7 +270,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;
}
@@ -281,19 +288,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: %u != %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];
}
@@ -324,14 +330,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) {
@@ -356,6 +366,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);
@@ -376,6 +388,7 @@ static int decode_element(AVCodecContext *avctx, AVFrame *frame, int ch_index,
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++) {
@@ -391,6 +404,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;
}
@@ -404,7 +448,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;
@@ -416,7 +461,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;
}
@@ -457,7 +502,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]);
}
@@ -474,7 +519,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);
}
@@ -521,24 +567,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;
@@ -554,7 +602,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;
@@ -569,6 +617,13 @@ 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);
+}
+
AVCodec ff_alac_decoder = {
.name = "alac",
.long_name = NULL_IF_CONFIG_SMALL("ALAC (Apple Lossless Audio Codec)"),
@@ -578,5 +633,6 @@ 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,
};
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 5fbcbfc..bc68a06 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
*/
@@ -274,7 +274,7 @@ static void alac_linear_predictor(AlacEncodeContext *s, int ch)
// 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++) {
@@ -483,7 +483,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 +578,6 @@ static av_cold int alac_encode_init(AVCodecContext *avctx)
goto error;
}
- avctx->coded_frame = avcodec_alloc_frame();
- 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 +606,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/allcodecs.c b/libavcodec/allcodecs.c
index 55d7957..696a79f 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
*/
@@ -97,19 +97,24 @@ void avcodec_register_all(void)
REGISTER_ENCODER(A64MULTI5, a64multi5);
REGISTER_DECODER(AASC, aasc);
REGISTER_DECODER(AIC, aic);
- 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);
REGISTER_ENCDEC (BMP, bmp);
REGISTER_DECODER(BMV_VIDEO, bmv_video);
+ REGISTER_DECODER(BRENDER_PIX, brender_pix);
REGISTER_DECODER(C93, c93);
REGISTER_DECODER(CAVS, cavs);
REGISTER_DECODER(CDGRAPHICS, cdgraphics);
@@ -118,9 +123,11 @@ void avcodec_register_all(void)
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);
@@ -137,10 +144,11 @@ void avcodec_register_all(void)
REGISTER_DECODER(EIGHTSVX_FIB, eightsvx_fib);
REGISTER_DECODER(ESCAPE124, escape124);
REGISTER_DECODER(ESCAPE130, escape130);
+ REGISTER_DECODER(EXR, exr);
REGISTER_ENCDEC (FFV1, ffv1);
REGISTER_ENCDEC (FFVHUFF, ffvhuff);
REGISTER_ENCDEC (FLASHSV, flashsv);
- REGISTER_DECODER(FLASHSV2, flashsv2);
+ REGISTER_ENCDEC (FLASHSV2, flashsv2);
REGISTER_DECODER(FLIC, flic);
REGISTER_ENCDEC (FLV, flv);
REGISTER_DECODER(FOURXM, fourxm);
@@ -151,8 +159,12 @@ 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_ENCDEC (HUFFYUV, huffyuv);
REGISTER_DECODER(IDCIN, idcin);
REGISTER_DECODER(IFF_BYTERUN1, iff_byterun1);
@@ -162,7 +174,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);
@@ -180,18 +192,28 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (MPEG1VIDEO, mpeg1video);
REGISTER_ENCDEC (MPEG2VIDEO, mpeg2video);
REGISTER_ENCDEC (MPEG4, mpeg4);
+ REGISTER_DECODER(MPEG4_CRYSTALHD, mpeg4_crystalhd);
+ REGISTER_DECODER(MPEG4_VDPAU, mpeg4_vdpau);
+ REGISTER_DECODER(MPEGVIDEO, mpegvideo);
+ REGISTER_DECODER(MPEG_VDPAU, mpeg_vdpau);
+ REGISTER_DECODER(MPEG1_VDPAU, mpeg1_vdpau);
+ REGISTER_DECODER(MPEG2_CRYSTALHD, mpeg2_crystalhd);
REGISTER_DECODER(MSA1, msa1);
+ REGISTER_DECODER(MSMPEG4_CRYSTALHD, msmpeg4_crystalhd);
REGISTER_DECODER(MSMPEG4V1, msmpeg4v1);
REGISTER_ENCDEC (MSMPEG4V2, msmpeg4v2);
REGISTER_ENCDEC (MSMPEG4V3, msmpeg4v3);
REGISTER_DECODER(MSRLE, msrle);
REGISTER_DECODER(MSS1, mss1);
REGISTER_DECODER(MSS2, mss2);
- REGISTER_DECODER(MSVIDEO1, msvideo1);
+ REGISTER_ENCDEC (MSVIDEO1, msvideo1);
REGISTER_DECODER(MSZH, mszh);
REGISTER_DECODER(MTS2, mts2);
+ REGISTER_DECODER(MVC1, mvc1);
+ REGISTER_DECODER(MVC2, mvc2);
REGISTER_DECODER(MXPEG, mxpeg);
REGISTER_DECODER(NUV, nuv);
+ REGISTER_DECODER(PAF_VIDEO, paf_video);
REGISTER_ENCDEC (PAM, pam);
REGISTER_ENCDEC (PBM, pbm);
REGISTER_ENCDEC (PCX, pcx);
@@ -201,12 +223,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);
@@ -215,15 +240,20 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (RV20, rv20);
REGISTER_DECODER(RV30, rv30);
REGISTER_DECODER(RV40, rv40);
- REGISTER_DECODER(S302M, s302m);
+ REGISTER_ENCDEC (S302M, s302m);
+ REGISTER_DECODER(SANM, sanm);
REGISTER_ENCDEC (SGI, sgi);
+ REGISTER_DECODER(SGIRLE, sgirle);
REGISTER_DECODER(SMACKER, smacker);
REGISTER_DECODER(SMC, smc);
+ REGISTER_DECODER(SMVJPEG, smvjpeg);
+ REGISTER_ENCDEC (SNOW, snow);
REGISTER_DECODER(SP5X, sp5x);
REGISTER_ENCDEC (SUNRAST, sunrast);
REGISTER_ENCDEC (SVQ1, svq1);
REGISTER_DECODER(SVQ3, svq3);
REGISTER_ENCDEC (TARGA, targa);
+ REGISTER_DECODER(TARGA_Y216, targa_y216);
REGISTER_DECODER(THEORA, theora);
REGISTER_DECODER(THP, thp);
REGISTER_DECODER(TIERTEXSEQVIDEO, tiertexseqvideo);
@@ -238,10 +268,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);
@@ -252,19 +286,26 @@ void avcodec_register_all(void)
REGISTER_DECODER(VP6A, vp6a);
REGISTER_DECODER(VP6F, vp6f);
REGISTER_DECODER(VP8, vp8);
+ REGISTER_DECODER(VP9, vp9);
REGISTER_DECODER(VQA, vqa);
REGISTER_DECODER(WEBP, webp);
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_ENCODER(XBM, xbm);
+ 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);
@@ -285,11 +326,14 @@ 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(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);
@@ -311,6 +355,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(MPC7, mpc7);
REGISTER_DECODER(MPC8, mpc8);
REGISTER_ENCDEC (NELLYMOSER, nellymoser);
+ REGISTER_DECODER(PAF_AUDIO, paf_audio);
REGISTER_DECODER(QCELP, qcelp);
REGISTER_DECODER(QDM2, qdm2);
REGISTER_ENCDEC (RA_144, ra_144);
@@ -319,14 +364,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);
@@ -345,17 +392,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);
@@ -363,7 +411,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);
@@ -374,7 +422,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);
@@ -383,6 +433,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);
@@ -390,7 +441,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);
@@ -402,16 +455,32 @@ void avcodec_register_all(void)
REGISTER_DECODER(ADPCM_THP, adpcm_thp);
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_ENCDEC (SUBRIP, subrip);
+ REGISTER_DECODER(SUBVIEWER, subviewer);
+ REGISTER_DECODER(SUBVIEWER1, subviewer1);
+ REGISTER_DECODER(TEXT, text);
+ REGISTER_DECODER(VPLAYER, vplayer);
+ REGISTER_DECODER(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);
@@ -423,40 +492,57 @@ 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(LIBX264, libx264);
+ REGISTER_ENCODER(LIBX264RGB, libx264rgb);
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);
REGISTER_PARSER(AAC_LATM, aac_latm);
REGISTER_PARSER(AC3, ac3);
REGISTER_PARSER(ADX, adx);
+ REGISTER_PARSER(BMP, bmp);
REGISTER_PARSER(CAVSVIDEO, cavsvideo);
REGISTER_PARSER(COOK, cook);
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);
REGISTER_PARSER(H263, h263);
REGISTER_PARSER(H264, h264);
+ REGISTER_PARSER(HEVC, hevc);
REGISTER_PARSER(MJPEG, mjpeg);
REGISTER_PARSER(MLP, mlp);
REGISTER_PARSER(MPEG4VIDEO, mpeg4video);
REGISTER_PARSER(MPEGAUDIO, mpegaudio);
REGISTER_PARSER(MPEGVIDEO, mpegvideo);
+ REGISTER_PARSER(PNG, png);
REGISTER_PARSER(PNM, pnm);
REGISTER_PARSER(RV30, rv30);
REGISTER_PARSER(RV40, rv40);
diff --git a/libavcodec/alpha/asm.h b/libavcodec/alpha/asm.h
index ab4cfcc..827721e 100644
--- a/libavcodec/alpha/asm.h
+++ b/libavcodec/alpha/asm.h
@@ -2,20 +2,20 @@
* Alpha optimized DSP utils
* Copyright (c) 2002 Falk Hueffner <falk@debian.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/alpha/dsputil_alpha.c b/libavcodec/alpha/dsputil_alpha.c
index 7a41cb8..03ba0a8 100644
--- a/libavcodec/alpha/dsputil_alpha.c
+++ b/libavcodec/alpha/dsputil_alpha.c
@@ -2,20 +2,20 @@
* Alpha optimized DSP utils
* Copyright (c) 2002 Falk Hueffner <falk@debian.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
*/
@@ -124,7 +124,7 @@ av_cold void ff_dsputil_init_alpha(DSPContext *c, AVCodecContext *avctx)
const int high_bit_depth = avctx->bits_per_raw_sample > 8;
if (!high_bit_depth) {
- c->clear_blocks = clear_blocks_axp;
+ c->clear_blocks = clear_blocks_axp;
}
/* amask clears all bits that correspond to present features. */
@@ -147,7 +147,7 @@ av_cold void ff_dsputil_init_alpha(DSPContext *c, AVCodecContext *avctx)
put_pixels_clamped_axp_p = c->put_pixels_clamped;
add_pixels_clamped_axp_p = c->add_pixels_clamped;
- if (avctx->bits_per_raw_sample <= 8 &&
+ if (!avctx->lowres && avctx->bits_per_raw_sample <= 8 &&
(avctx->idct_algo == FF_IDCT_AUTO ||
avctx->idct_algo == FF_IDCT_SIMPLEALPHA)) {
c->idct_put = ff_simple_idct_put_axp;
diff --git a/libavcodec/alpha/dsputil_alpha.h b/libavcodec/alpha/dsputil_alpha.h
index d976c18..828cd16 100644
--- a/libavcodec/alpha/dsputil_alpha.h
+++ b/libavcodec/alpha/dsputil_alpha.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/alpha/dsputil_alpha_asm.S b/libavcodec/alpha/dsputil_alpha_asm.S
index afe02cc..d801bcf 100644
--- a/libavcodec/alpha/dsputil_alpha_asm.S
+++ b/libavcodec/alpha/dsputil_alpha_asm.S
@@ -2,20 +2,20 @@
* Alpha optimized DSP utils
* Copyright (c) 2002 Falk Hueffner <falk@debian.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/alpha/hpeldsp_alpha.c b/libavcodec/alpha/hpeldsp_alpha.c
index 144fa22..8d54807 100644
--- a/libavcodec/alpha/hpeldsp_alpha.c
+++ b/libavcodec/alpha/hpeldsp_alpha.c
@@ -2,20 +2,20 @@
* Alpha optimized DSP utils
* Copyright (c) 2002 Falk Hueffner <falk@debian.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/alpha/hpeldsp_alpha.h b/libavcodec/alpha/hpeldsp_alpha.h
index e44ff50..985182c 100644
--- a/libavcodec/alpha/hpeldsp_alpha.h
+++ b/libavcodec/alpha/hpeldsp_alpha.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/alpha/hpeldsp_alpha_asm.S b/libavcodec/alpha/hpeldsp_alpha_asm.S
index b23d24f..df386c4 100644
--- a/libavcodec/alpha/hpeldsp_alpha_asm.S
+++ b/libavcodec/alpha/hpeldsp_alpha_asm.S
@@ -2,20 +2,20 @@
* Alpha optimized DSP utils
* Copyright (c) 2002 Falk Hueffner <falk@debian.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,6 +26,7 @@
#include "regdef.h"
+
.set noat
.set noreorder
.arch pca56
diff --git a/libavcodec/alpha/motion_est_alpha.c b/libavcodec/alpha/motion_est_alpha.c
index e062e90..a7c33e4 100644
--- a/libavcodec/alpha/motion_est_alpha.c
+++ b/libavcodec/alpha/motion_est_alpha.c
@@ -2,20 +2,20 @@
* Alpha optimized DSP utils
* Copyright (c) 2002 Falk Hueffner <falk@debian.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/alpha/motion_est_mvi_asm.S b/libavcodec/alpha/motion_est_mvi_asm.S
index 7fe4e16..2399085 100644
--- a/libavcodec/alpha/motion_est_mvi_asm.S
+++ b/libavcodec/alpha/motion_est_mvi_asm.S
@@ -2,20 +2,20 @@
* Alpha optimized DSP utils
* Copyright (c) 2002 Falk Hueffner <falk@debian.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/alpha/mpegvideo_alpha.c b/libavcodec/alpha/mpegvideo_alpha.c
index 5557159..7ba0f2e 100644
--- a/libavcodec/alpha/mpegvideo_alpha.c
+++ b/libavcodec/alpha/mpegvideo_alpha.c
@@ -2,20 +2,20 @@
* Alpha optimized DSP utils
* Copyright (c) 2002 Falk Hueffner <falk@debian.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/alpha/regdef.h b/libavcodec/alpha/regdef.h
index 1005943..f05577a 100644
--- a/libavcodec/alpha/regdef.h
+++ b/libavcodec/alpha/regdef.h
@@ -2,20 +2,20 @@
* Alpha optimized DSP utils
* copyright (c) 2002 Falk Hueffner <falk@debian.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/alpha/simple_idct_alpha.c b/libavcodec/alpha/simple_idct_alpha.c
index 262ad71..3bd1b33 100644
--- a/libavcodec/alpha/simple_idct_alpha.c
+++ b/libavcodec/alpha/simple_idct_alpha.c
@@ -9,20 +9,20 @@
* Alpha optimizations by MĂ¥ns RullgĂ¥rd <mans@mansr.com>
* and Falk Hueffner <falk@debian.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/alsdec.c b/libavcodec/alsdec.c
index 782a1b8..825949f 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 "avcodec.h"
@@ -197,6 +197,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
@@ -283,8 +284,10 @@ static av_cold int read_specific_config(ALSDecContext *ctx)
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);
@@ -303,7 +306,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);
@@ -350,13 +353,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;
}
@@ -390,7 +401,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);
@@ -426,7 +437,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;
}
@@ -549,12 +559,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);
@@ -569,6 +582,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;
}
@@ -667,7 +682,7 @@ 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 {
@@ -703,7 +718,7 @@ static int read_var_block_data(ALSDecContext *ctx, ALSBlockData *bd)
int offset = parcor_rice_table[sconf->coef_table][k][0];
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 %d is out of range\n", quant_cof[k]);
+ av_log(avctx, AV_LOG_ERROR, "quant_cof %d is out of range.\n", quant_cof[k]);
return AVERROR_INVALIDDATA;
}
}
@@ -960,7 +975,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;
@@ -968,7 +983,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;
@@ -1022,8 +1037,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);
@@ -1128,7 +1143,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];
@@ -1176,7 +1191,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;
}
@@ -1201,7 +1216,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;
}
@@ -1233,7 +1248,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;
}
@@ -1363,7 +1378,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;
}
@@ -1413,6 +1428,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;
}
@@ -1472,19 +1488,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) {
@@ -1494,7 +1514,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) {
@@ -1734,7 +1754,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 ae67f3c..8dce61a 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;
@@ -94,12 +96,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;
}
@@ -152,7 +169,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);
}
@@ -188,21 +205,23 @@ static int execute_code(AVCodecContext * avctx, int c)
case 'l': //reset screen mode
if (s->nb_args < 2)
s->args[0] = DEFAULT_SCREEN_MODE;
+ width = avctx->width;
+ height = avctx->height;
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;
@@ -210,13 +229,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;
@@ -224,17 +243,17 @@ static int execute_code(AVCodecContext * avctx, int c)
default:
avpriv_request_sample(avctx, "Unsupported screen mode");
}
+ 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);
avcodec_set_dimensions(avctx, width, height);
- 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);
@@ -282,12 +301,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 {
@@ -311,6 +338,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;
}
@@ -324,19 +353,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) {
@@ -375,7 +406,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);
@@ -387,7 +418,7 @@ static int decode_frame(AVCodecContext *avctx,
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';
+ s->args[s->nb_args] = FFMAX(s->args[s->nb_args], 0) * 10 + buf[0] - '0';
break;
case ';':
s->nb_args++;
@@ -403,7 +434,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 8669db8..ea71ea0 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
*/
@@ -248,6 +248,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);
@@ -488,9 +489,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--;
@@ -517,9 +521,13 @@ static inline int ape_decode_value_3900(APEContext *ctx, APERice *rice)
} else
tmpk = (rice->k < 1) ? 0 : rice->k - 1;
- if (tmpk <= 16 || ctx->fileversion < 3910)
+ if (tmpk <= 16 || ctx->fileversion < 3910) {
+ if (tmpk > 23) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "Too many bits: %d\n", tmpk);
+ return AVERROR_INVALIDDATA;
+ }
x = range_decode_bits(ctx, tmpk);
- else if (tmpk <= 32) {
+ } else if (tmpk <= 32) {
x = range_decode_bits(ctx, 16);
x |= (range_decode_bits(ctx, tmpk - 16) << 16);
} else {
@@ -1466,7 +1474,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) {
@@ -1491,10 +1498,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;
@@ -1538,7 +1543,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/api-example.c b/libavcodec/api-example.c
deleted file mode 100644
index 25b7cfe..0000000
--- a/libavcodec/api-example.c
+++ b/dev/null
@@ -1,596 +0,0 @@
-/*
- * copyright (c) 2001 Fabrice Bellard
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * libavcodec API use example.
- *
- * @example libavcodec/api-example.c
- * Note that this library only handles codecs (mpeg, mpeg4, etc...),
- * not file formats (avi, vob, etc...). See library 'libavformat' for the
- * format handling
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#ifdef HAVE_AV_CONFIG_H
-#undef HAVE_AV_CONFIG_H
-#endif
-
-#include "libavcodec/avcodec.h"
-#include "libavutil/channel_layout.h"
-#include "libavutil/common.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/samplefmt.h"
-
-#define INBUF_SIZE 4096
-#define AUDIO_INBUF_SIZE 20480
-#define AUDIO_REFILL_THRESH 4096
-
-/* check that a given sample format is supported by the encoder */
-static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt)
-{
- const enum AVSampleFormat *p = codec->sample_fmts;
-
- while (*p != AV_SAMPLE_FMT_NONE) {
- if (*p == sample_fmt)
- return 1;
- p++;
- }
- return 0;
-}
-
-/* just pick the highest supported samplerate */
-static int select_sample_rate(AVCodec *codec)
-{
- const int *p;
- int best_samplerate = 0;
-
- if (!codec->supported_samplerates)
- return 44100;
-
- p = codec->supported_samplerates;
- while (*p) {
- best_samplerate = FFMAX(*p, best_samplerate);
- p++;
- }
- return best_samplerate;
-}
-
-/* select layout with the highest channel count */
-static int select_channel_layout(AVCodec *codec)
-{
- const uint64_t *p;
- uint64_t best_ch_layout = 0;
- int best_nb_channels = 0;
-
- if (!codec->channel_layouts)
- return AV_CH_LAYOUT_STEREO;
-
- p = codec->channel_layouts;
- while (*p) {
- int nb_channels = av_get_channel_layout_nb_channels(*p);
-
- if (nb_channels > best_nb_channels) {
- best_ch_layout = *p;
- best_nb_channels = nb_channels;
- }
- p++;
- }
- return best_ch_layout;
-}
-
-/*
- * Audio encoding example
- */
-static void audio_encode_example(const char *filename)
-{
- AVCodec *codec;
- AVCodecContext *c= NULL;
- AVFrame *frame;
- AVPacket pkt;
- int i, j, k, ret, got_output;
- int buffer_size;
- FILE *f;
- uint16_t *samples;
- float t, tincr;
-
- printf("Audio encoding\n");
-
- /* find the MP2 encoder */
- codec = avcodec_find_encoder(AV_CODEC_ID_MP2);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- c = avcodec_alloc_context3(codec);
-
- /* put sample parameters */
- c->bit_rate = 64000;
-
- /* check that the encoder supports s16 pcm input */
- c->sample_fmt = AV_SAMPLE_FMT_S16;
- if (!check_sample_fmt(codec, c->sample_fmt)) {
- fprintf(stderr, "encoder does not support %s",
- av_get_sample_fmt_name(c->sample_fmt));
- exit(1);
- }
-
- /* select other audio parameters supported by the encoder */
- c->sample_rate = select_sample_rate(codec);
- c->channel_layout = select_channel_layout(codec);
- c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
-
- /* open it */
- if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
- }
-
- f = fopen(filename, "wb");
- if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
- exit(1);
- }
-
- /* frame containing input raw audio */
- frame = avcodec_alloc_frame();
- if (!frame) {
- fprintf(stderr, "could not allocate audio frame\n");
- exit(1);
- }
-
- frame->nb_samples = c->frame_size;
- frame->format = c->sample_fmt;
- frame->channel_layout = c->channel_layout;
-
- /* the codec gives us the frame size, in samples,
- * we calculate the size of the samples buffer in bytes */
- buffer_size = av_samples_get_buffer_size(NULL, c->channels, c->frame_size,
- c->sample_fmt, 0);
- samples = av_malloc(buffer_size);
- if (!samples) {
- fprintf(stderr, "could not allocate %d bytes for samples buffer\n",
- buffer_size);
- exit(1);
- }
- /* setup the data pointers in the AVFrame */
- ret = avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,
- (const uint8_t*)samples, buffer_size, 0);
- if (ret < 0) {
- fprintf(stderr, "could not setup audio frame\n");
- exit(1);
- }
-
- /* encode a single tone sound */
- t = 0;
- tincr = 2 * M_PI * 440.0 / c->sample_rate;
- for(i=0;i<200;i++) {
- av_init_packet(&pkt);
- pkt.data = NULL; // packet data will be allocated by the encoder
- pkt.size = 0;
-
- for (j = 0; j < c->frame_size; j++) {
- samples[2*j] = (int)(sin(t) * 10000);
-
- for (k = 1; k < c->channels; k++)
- samples[2*j + k] = samples[2*j];
- t += tincr;
- }
- /* encode the samples */
- ret = avcodec_encode_audio2(c, &pkt, frame, &got_output);
- if (ret < 0) {
- fprintf(stderr, "error encoding audio frame\n");
- exit(1);
- }
- if (got_output) {
- fwrite(pkt.data, 1, pkt.size, f);
- av_free_packet(&pkt);
- }
- }
- fclose(f);
-
- av_freep(&samples);
- avcodec_free_frame(&frame);
- avcodec_close(c);
- av_free(c);
-}
-
-/*
- * Audio decoding.
- */
-static void audio_decode_example(const char *outfilename, const char *filename)
-{
- AVCodec *codec;
- AVCodecContext *c= NULL;
- int len;
- FILE *f, *outfile;
- uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
- AVPacket avpkt;
- AVFrame *decoded_frame = NULL;
-
- av_init_packet(&avpkt);
-
- printf("Audio decoding\n");
-
- /* find the mpeg audio decoder */
- codec = avcodec_find_decoder(AV_CODEC_ID_MP2);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- c = avcodec_alloc_context3(codec);
-
- /* open it */
- if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
- }
-
- f = fopen(filename, "rb");
- if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
- exit(1);
- }
- outfile = fopen(outfilename, "wb");
- if (!outfile) {
- av_free(c);
- exit(1);
- }
-
- /* decode until eof */
- avpkt.data = inbuf;
- avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
-
- while (avpkt.size > 0) {
- int got_frame = 0;
-
- if (!decoded_frame) {
- if (!(decoded_frame = avcodec_alloc_frame())) {
- fprintf(stderr, "out of memory\n");
- exit(1);
- }
- } else
- avcodec_get_frame_defaults(decoded_frame);
-
- len = avcodec_decode_audio4(c, decoded_frame, &got_frame, &avpkt);
- if (len < 0) {
- fprintf(stderr, "Error while decoding\n");
- exit(1);
- }
- if (got_frame) {
- /* if a frame has been decoded, output it */
- int data_size = av_samples_get_buffer_size(NULL, c->channels,
- decoded_frame->nb_samples,
- c->sample_fmt, 1);
- fwrite(decoded_frame->data[0], 1, data_size, outfile);
- }
- avpkt.size -= len;
- avpkt.data += len;
- if (avpkt.size < AUDIO_REFILL_THRESH) {
- /* Refill the input buffer, to avoid trying to decode
- * incomplete frames. Instead of this, one could also use
- * a parser, or use a proper container format through
- * libavformat. */
- memmove(inbuf, avpkt.data, avpkt.size);
- avpkt.data = inbuf;
- len = fread(avpkt.data + avpkt.size, 1,
- AUDIO_INBUF_SIZE - avpkt.size, f);
- if (len > 0)
- avpkt.size += len;
- }
- }
-
- fclose(outfile);
- fclose(f);
-
- avcodec_close(c);
- av_free(c);
- avcodec_free_frame(&decoded_frame);
-}
-
-/*
- * Video encoding example
- */
-static void video_encode_example(const char *filename)
-{
- AVCodec *codec;
- AVCodecContext *c= NULL;
- int i, ret, x, y, got_output;
- FILE *f;
- AVFrame *picture;
- AVPacket pkt;
- uint8_t endcode[] = { 0, 0, 1, 0xb7 };
-
- printf("Video encoding\n");
-
- /* find the mpeg1 video encoder */
- codec = avcodec_find_encoder(AV_CODEC_ID_MPEG1VIDEO);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- c = avcodec_alloc_context3(codec);
- picture= avcodec_alloc_frame();
-
- /* put sample parameters */
- c->bit_rate = 400000;
- /* resolution must be a multiple of two */
- c->width = 352;
- c->height = 288;
- /* frames per second */
- c->time_base= (AVRational){1,25};
- c->gop_size = 10; /* emit one intra frame every ten frames */
- c->max_b_frames=1;
- c->pix_fmt = AV_PIX_FMT_YUV420P;
-
- /* open it */
- if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
- }
-
- f = fopen(filename, "wb");
- if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
- exit(1);
- }
-
- ret = av_image_alloc(picture->data, picture->linesize, c->width, c->height,
- c->pix_fmt, 32);
- if (ret < 0) {
- fprintf(stderr, "could not alloc raw picture buffer\n");
- exit(1);
- }
- picture->format = c->pix_fmt;
- picture->width = c->width;
- picture->height = c->height;
-
- /* encode 1 second of video */
- for(i=0;i<25;i++) {
- av_init_packet(&pkt);
- pkt.data = NULL; // packet data will be allocated by the encoder
- pkt.size = 0;
-
- fflush(stdout);
- /* prepare a dummy image */
- /* Y */
- for(y=0;y<c->height;y++) {
- for(x=0;x<c->width;x++) {
- picture->data[0][y * picture->linesize[0] + x] = x + y + i * 3;
- }
- }
-
- /* Cb and Cr */
- for(y=0;y<c->height/2;y++) {
- for(x=0;x<c->width/2;x++) {
- picture->data[1][y * picture->linesize[1] + x] = 128 + y + i * 2;
- picture->data[2][y * picture->linesize[2] + x] = 64 + x + i * 5;
- }
- }
-
- picture->pts = i;
-
- /* encode the image */
- ret = avcodec_encode_video2(c, &pkt, picture, &got_output);
- if (ret < 0) {
- fprintf(stderr, "error encoding frame\n");
- exit(1);
- }
-
- if (got_output) {
- printf("encoding frame %3d (size=%5d)\n", i, pkt.size);
- fwrite(pkt.data, 1, pkt.size, f);
- av_free_packet(&pkt);
- }
- }
-
- /* get the delayed frames */
- for (got_output = 1; got_output; i++) {
- fflush(stdout);
-
- ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
- if (ret < 0) {
- fprintf(stderr, "error encoding frame\n");
- exit(1);
- }
-
- if (got_output) {
- printf("encoding frame %3d (size=%5d)\n", i, pkt.size);
- fwrite(pkt.data, 1, pkt.size, f);
- av_free_packet(&pkt);
- }
- }
-
- /* add sequence end code to have a real mpeg file */
- fwrite(endcode, 1, sizeof(endcode), f);
- fclose(f);
-
- avcodec_close(c);
- av_free(c);
- av_freep(&picture->data[0]);
- avcodec_free_frame(&picture);
- printf("\n");
-}
-
-/*
- * Video decoding example
- */
-
-static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
- char *filename)
-{
- FILE *f;
- int i;
-
- f=fopen(filename,"w");
- fprintf(f,"P5\n%d %d\n%d\n",xsize,ysize,255);
- for(i=0;i<ysize;i++)
- fwrite(buf + i * wrap,1,xsize,f);
- fclose(f);
-}
-
-static void video_decode_example(const char *outfilename, const char *filename)
-{
- AVCodec *codec;
- AVCodecContext *c= NULL;
- int frame, got_picture, len;
- FILE *f;
- AVFrame *picture;
- uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
- char buf[1024];
- AVPacket avpkt;
-
- av_init_packet(&avpkt);
-
- /* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */
- memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
-
- printf("Video decoding\n");
-
- /* find the mpeg1 video decoder */
- codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- c = avcodec_alloc_context3(codec);
- picture= avcodec_alloc_frame();
-
- if(codec->capabilities&CODEC_CAP_TRUNCATED)
- c->flags|= CODEC_FLAG_TRUNCATED; /* we do not send complete frames */
-
- /* For some codecs, such as msmpeg4 and mpeg4, width and height
- MUST be initialized there because this information is not
- available in the bitstream. */
-
- /* open it */
- if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
- }
-
- /* the codec gives us the frame size, in samples */
-
- f = fopen(filename, "rb");
- if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
- exit(1);
- }
-
- frame = 0;
- for(;;) {
- avpkt.size = fread(inbuf, 1, INBUF_SIZE, f);
- if (avpkt.size == 0)
- break;
-
- /* NOTE1: some codecs are stream based (mpegvideo, mpegaudio)
- and this is the only method to use them because you cannot
- know the compressed data size before analysing it.
-
- BUT some other codecs (msmpeg4, mpeg4) are inherently frame
- based, so you must call them with all the data for one
- frame exactly. You must also initialize 'width' and
- 'height' before initializing them. */
-
- /* NOTE2: some codecs allow the raw parameters (frame size,
- sample rate) to be changed at any frame. We handle this, so
- you should also take care of it */
-
- /* here, we use a stream based decoder (mpeg1video), so we
- feed decoder and see if it could decode a frame */
- avpkt.data = inbuf;
- while (avpkt.size > 0) {
- len = avcodec_decode_video2(c, picture, &got_picture, &avpkt);
- if (len < 0) {
- fprintf(stderr, "Error while decoding frame %d\n", frame);
- exit(1);
- }
- if (got_picture) {
- printf("saving frame %3d\n", frame);
- fflush(stdout);
-
- /* the picture is allocated by the decoder. no need to
- free it */
- snprintf(buf, sizeof(buf), outfilename, frame);
- pgm_save(picture->data[0], picture->linesize[0],
- c->width, c->height, buf);
- frame++;
- }
- avpkt.size -= len;
- avpkt.data += len;
- }
- }
-
- /* some codecs, such as MPEG, transmit the I and P frame with a
- latency of one frame. You must do the following to have a
- chance to get the last frame of the video */
- avpkt.data = NULL;
- avpkt.size = 0;
- len = avcodec_decode_video2(c, picture, &got_picture, &avpkt);
- if (got_picture) {
- printf("saving last frame %3d\n", frame);
- fflush(stdout);
-
- /* the picture is allocated by the decoder. no need to
- free it */
- snprintf(buf, sizeof(buf), outfilename, frame);
- pgm_save(picture->data[0], picture->linesize[0],
- c->width, c->height, buf);
- frame++;
- }
-
- fclose(f);
-
- avcodec_close(c);
- av_free(c);
- avcodec_free_frame(&picture);
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- const char *filename;
-
- /* register all the codecs */
- avcodec_register_all();
-
- if (argc <= 1) {
- audio_encode_example("/tmp/test.mp2");
- audio_decode_example("/tmp/test.sw", "/tmp/test.mp2");
-
- video_encode_example("/tmp/test.mpg");
- filename = "/tmp/test.mpg";
- } else {
- filename = argv[1];
- }
-
- // audio_decode_example("/tmp/test.sw", filename);
- video_decode_example("/tmp/test%d.pgm", filename);
-
- return 0;
-}
diff --git a/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 d7cb95b..ffe0747 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
*/
@@ -31,6 +31,14 @@ void ff_ac3_lshift_int16_neon(int16_t *src, unsigned len, unsigned shift);
void ff_ac3_rshift_int32_neon(int32_t *src, unsigned len, unsigned shift);
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_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,
@@ -56,5 +64,7 @@ av_cold void ff_ac3dsp_init_arm(AC3DSPContext *c, int bit_exact)
c->ac3_rshift_int32 = ff_ac3_rshift_int32_neon;
c->float_to_fixed24 = ff_float_to_fixed24_neon;
c->extract_exponents = ff_ac3_extract_exponents_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 82ff8af..381f158 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
*/
@@ -108,3 +108,47 @@ function ff_ac3_extract_exponents_neon, export=1
bgt 1b
bx lr
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 8999456..5cfc5cb 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/dca.h b/libavcodec/arm/dca.h
index 39ec2b6..35971a8 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
*/
@@ -26,7 +26,7 @@
#include "config.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,
@@ -34,46 +34,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 d49a176..8893f48 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 fe3aae8..6a6c77a 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 5892a84..b23ce4a 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/dsputil_arm.S b/libavcodec/arm/dsputil_arm.S
index 1692a58..586a833 100644
--- a/libavcodec/arm/dsputil_arm.S
+++ b/libavcodec/arm/dsputil_arm.S
@@ -2,20 +2,20 @@
@ ARMv4 optimized DSP utils
@ 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/dsputil_arm.h b/libavcodec/arm/dsputil_arm.h
index 36d5d56..b7b5bdc 100644
--- a/libavcodec/arm/dsputil_arm.h
+++ b/libavcodec/arm/dsputil_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/dsputil_armv6.S b/libavcodec/arm/dsputil_armv6.S
index e667a47..6ec238b 100644
--- a/libavcodec/arm/dsputil_armv6.S
+++ b/libavcodec/arm/dsputil_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/dsputil_init_arm.c b/libavcodec/arm/dsputil_init_arm.c
index bb68eb6..68991fa 100644
--- a/libavcodec/arm/dsputil_init_arm.c
+++ b/libavcodec/arm/dsputil_init_arm.c
@@ -2,20 +2,20 @@
* ARM optimized DSP utils
* 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
*/
@@ -63,7 +63,7 @@ av_cold void ff_dsputil_init_arm(DSPContext *c, AVCodecContext *avctx)
ff_put_pixels_clamped = c->put_pixels_clamped;
ff_add_pixels_clamped = c->add_pixels_clamped;
- if (avctx->bits_per_raw_sample <= 8) {
+ if (!avctx->lowres && avctx->bits_per_raw_sample <= 8) {
if(avctx->idct_algo == FF_IDCT_AUTO ||
avctx->idct_algo == FF_IDCT_ARM){
c->idct_put = j_rev_dct_arm_put;
diff --git a/libavcodec/arm/dsputil_init_armv5te.c b/libavcodec/arm/dsputil_init_armv5te.c
index 302a655..841fbfa 100644
--- a/libavcodec/arm/dsputil_init_armv5te.c
+++ b/libavcodec/arm/dsputil_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
*/
@@ -26,7 +26,7 @@ void ff_simple_idct_add_armv5te(uint8_t *dest, int line_size, int16_t *data);
av_cold void ff_dsputil_init_armv5te(DSPContext *c, AVCodecContext *avctx)
{
- if (avctx->bits_per_raw_sample <= 8 &&
+ if (!avctx->lowres && avctx->bits_per_raw_sample <= 8 &&
(avctx->idct_algo == FF_IDCT_AUTO ||
avctx->idct_algo == FF_IDCT_SIMPLEARMV5TE)) {
c->idct_put = ff_simple_idct_put_armv5te;
diff --git a/libavcodec/arm/dsputil_init_armv6.c b/libavcodec/arm/dsputil_init_armv6.c
index 4c8ba47..8f38302 100644
--- a/libavcodec/arm/dsputil_init_armv6.c
+++ b/libavcodec/arm/dsputil_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
*/
@@ -55,7 +55,7 @@ av_cold void ff_dsputil_init_armv6(DSPContext *c, AVCodecContext *avctx)
{
const int high_bit_depth = avctx->bits_per_raw_sample > 8;
- if (avctx->bits_per_raw_sample <= 8 &&
+ if (!avctx->lowres && avctx->bits_per_raw_sample <= 8 &&
(avctx->idct_algo == FF_IDCT_AUTO ||
avctx->idct_algo == FF_IDCT_SIMPLEARMV6)) {
c->idct_put = ff_simple_idct_put_armv6;
diff --git a/libavcodec/arm/dsputil_init_neon.c b/libavcodec/arm/dsputil_init_neon.c
index 793fab1..6d19af7 100644
--- a/libavcodec/arm/dsputil_init_neon.c
+++ b/libavcodec/arm/dsputil_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
*/
@@ -52,7 +52,7 @@ av_cold void ff_dsputil_init_neon(DSPContext *c, AVCodecContext *avctx)
{
const int high_bit_depth = avctx->bits_per_raw_sample > 8;
- if (avctx->bits_per_raw_sample <= 8) {
+ if (!avctx->lowres && avctx->bits_per_raw_sample <= 8) {
if (avctx->idct_algo == FF_IDCT_AUTO ||
avctx->idct_algo == FF_IDCT_SIMPLENEON) {
c->idct_put = ff_simple_idct_put_neon;
diff --git a/libavcodec/arm/dsputil_neon.S b/libavcodec/arm/dsputil_neon.S
index 81662c0..307e122 100644
--- a/libavcodec/arm/dsputil_neon.S
+++ b/libavcodec/arm/dsputil_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/fft_fixed_init_arm.c b/libavcodec/arm/fft_fixed_init_arm.c
index 50532f2..ef098f4 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..d4a38a2 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
*/
@@ -122,7 +122,7 @@ endfunc
function fft_pass_neon
push {r4,lr}
- movrel lr, coefs + 24
+ movrel lr, coefs+24
vld1.16 {d30}, [lr,:64]
lsl r12, r2, #3
vmov d31, d30
diff --git a/libavcodec/arm/fft_init_arm.c b/libavcodec/arm/fft_init_arm.c
index 3a3d1a7..7e49b9c 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
*/
@@ -46,8 +46,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 7845ebb..f1ab37c 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..9b93942 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
*/
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 41a095a..55d070e 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 15301f8..112d5d6 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_armv6.S b/libavcodec/arm/h264dsp_armv6.S
index c4f12a6..93dc69b 100644
--- a/libavcodec/arm/h264dsp_armv6.S
+++ b/libavcodec/arm/h264dsp_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/h264dsp_init_arm.c b/libavcodec/arm/h264dsp_init_arm.c
index b206a1b..2cafbaf 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
*/
@@ -73,11 +73,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;
@@ -97,6 +100,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,
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 3e5321c..2edeca2 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 2e25c2a..1562f0b 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_VP8)
@@ -68,6 +69,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;
@@ -77,6 +79,7 @@ static av_cold void h264_pred_init_neon(H264PredContext *h, int codec_id,
h->pred16x16[DC_128_PRED8x8 ] = ff_pred16x16_128_dc_neon;
if (codec_id != AV_CODEC_ID_SVQ3 && codec_id != AV_CODEC_ID_RV40 && 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 a232689..eaa1324 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 d4f97e3..2f3d311 100644
--- a/libavcodec/arm/hpeldsp_arm.S
+++ b/libavcodec/arm/hpeldsp_arm.S
@@ -2,20 +2,20 @@
@ ARMv4 optimized DSP utils
@ 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 6b5c1ce..3f18c62 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 a030d42..cd50150 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 8176afe..2cc2b78 100644
--- a/libavcodec/arm/hpeldsp_init_arm.c
+++ b/libavcodec/arm/hpeldsp_init_arm.c
@@ -2,25 +2,26 @@
* ARM optimized DSP utils
* 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
*/
#include "libavutil/arm/cpu.h"
#include "libavutil/attributes.h"
+#include "libavcodec/bit_depth_template.c" // for CALL_2X_PIXELS
#include "libavcodec/rnd_avg.h"
#include "hpeldsp_arm.h"
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/int_neon.S b/libavcodec/arm/int_neon.S
index 04208c2..dea1ad5 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
*/
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 9f7cb46..e481cd1 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 94db24f..ee3984c 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/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 0c04688..6566798 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 d69fa2f..4ff93b7 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 2066cbc..a572290 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 0c6c428..e05df8e 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/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/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 6ad60fa..3bf9ac7 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 8227898..50d20c9 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/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 e6e6408..0bf3ef1 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/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 120069d..48a6c3b 100644
--- a/libavcodec/arm/videodsp_armv5te.S
+++ b/libavcodec/arm/videodsp_armv5te.S
@@ -2,20 +2,20 @@
@ ARMv5te optimized DSP utils
@ 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 dfd6078..5af795b 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 e5ecfc3..f133905 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 cd3428b..ddaa120 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 ce00e4a..6041ef1 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 5207758..a14b188 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 b7897cd..d360ae3 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 e15e191..563268e 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 0468181..ae045a6 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 0cd2efa..436b340 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
*/
@@ -1576,18 +1576,19 @@ endconst
/* Bilinear MC */
function ff_put_vp8_bilin16_h_neon, export=1
- ldr r3, [sp, #4] @ mx
- rsb r12, r3, #8
- vdup.8 d0, r3
+ push {lr}
+ ldr lr, [sp, #8] @ mx
+ rsb r12, lr, #8
+ vdup.8 d0, lr
vdup.8 d1, r12
- ldr r12, [sp] @ h
+ ldr r12, [sp, #4] @ h
1:
subs r12, r12, #2
- vld1.8 {d2-d4}, [r2], r1
+ vld1.8 {d2-d4}, [r2], r3
vext.8 q2, q1, q2, #1
vmull.u8 q8, d2, d1
vmlal.u8 q8, d4, d0
- vld1.8 {d18-d20},[r2], r1
+ vld1.8 {d18-d20},[r2], r3
vmull.u8 q3, d3, d1
vmlal.u8 q3, d5, d0
vext.8 q10, q9, q10, #1
@@ -1603,24 +1604,25 @@ function ff_put_vp8_bilin16_h_neon, export=1
vst1.8 {q3}, [r0,:128], r1
bgt 1b
- bx lr
+ pop {pc}
endfunc
function ff_put_vp8_bilin16_v_neon, export=1
- ldr r3, [sp, #8] @ my
- rsb r12, r3, #8
- vdup.8 d0, r3
+ push {lr}
+ ldr lr, [sp, #12] @ my
+ rsb r12, lr, #8
+ vdup.8 d0, lr
vdup.8 d1, r12
- ldr r12, [sp] @ h
- vld1.8 {q1}, [r2], r1
+ ldr r12, [sp, #4] @ h
+ vld1.8 {q1}, [r2], r3
1:
subs r12, r12, #2
- vld1.8 {q2}, [r2], r1
+ vld1.8 {q2}, [r2], r3
vmull.u8 q3, d2, d1
vmlal.u8 q3, d4, d0
vmull.u8 q8, d3, d1
vmlal.u8 q8, d5, d0
- vld1.8 {q1}, [r2], r1
+ vld1.8 {q1}, [r2], r3
vmull.u8 q9, d4, d1
vmlal.u8 q9, d2, d0
vmull.u8 q10, d5, d1
@@ -1633,21 +1635,22 @@ function ff_put_vp8_bilin16_v_neon, export=1
vst1.8 {q3}, [r0,:128], r1
bgt 1b
- bx lr
+ pop {pc}
endfunc
function ff_put_vp8_bilin16_hv_neon, export=1
- ldr r3, [sp, #4] @ mx
- rsb r12, r3, #8
- vdup.8 d0, r3
+ push {lr}
+ ldr lr, [sp, #8] @ mx
+ rsb r12, lr, #8
+ vdup.8 d0, lr
vdup.8 d1, r12
- ldr r3, [sp, #8] @ my
- rsb r12, r3, #8
- vdup.8 d2, r3
+ ldr lr, [sp, #12] @ my
+ rsb r12, lr, #8
+ vdup.8 d2, lr
vdup.8 d3, r12
- ldr r12, [sp] @ h
+ ldr r12, [sp, #4] @ h
- vld1.8 {d4-d6}, [r2], r1
+ vld1.8 {d4-d6}, [r2], r3
vext.8 q3, q2, q3, #1
vmull.u8 q8, d4, d1
vmlal.u8 q8, d6, d0
@@ -1657,11 +1660,11 @@ function ff_put_vp8_bilin16_hv_neon, export=1
vrshrn.u16 d5, q9, #3
1:
subs r12, r12, #2
- vld1.8 {d18-d20},[r2], r1
+ vld1.8 {d18-d20},[r2], r3
vext.8 q10, q9, q10, #1
vmull.u8 q11, d18, d1
vmlal.u8 q11, d20, d0
- vld1.8 {d26-d28},[r2], r1
+ vld1.8 {d26-d28},[r2], r3
vmull.u8 q12, d19, d1
vmlal.u8 q12, d21, d0
vext.8 q14, q13, q14, #1
@@ -1689,22 +1692,23 @@ function ff_put_vp8_bilin16_hv_neon, export=1
vst1.8 {q10}, [r0,:128], r1
bgt 1b
- bx lr
+ pop {pc}
endfunc
function ff_put_vp8_bilin8_h_neon, export=1
- ldr r3, [sp, #4] @ mx
- rsb r12, r3, #8
- vdup.8 d0, r3
+ push {lr}
+ ldr lr, [sp, #8] @ mx
+ rsb r12, lr, #8
+ vdup.8 d0, lr
vdup.8 d1, r12
- ldr r12, [sp] @ h
+ ldr r12, [sp, #4] @ h
1:
subs r12, r12, #2
- vld1.8 {q1}, [r2], r1
+ vld1.8 {q1}, [r2], r3
vext.8 d3, d2, d3, #1
vmull.u8 q2, d2, d1
vmlal.u8 q2, d3, d0
- vld1.8 {q3}, [r2], r1
+ vld1.8 {q3}, [r2], r3
vext.8 d7, d6, d7, #1
vmull.u8 q8, d6, d1
vmlal.u8 q8, d7, d0
@@ -1714,22 +1718,23 @@ function ff_put_vp8_bilin8_h_neon, export=1
vst1.8 {d16}, [r0,:64], r1
bgt 1b
- bx lr
+ pop {pc}
endfunc
function ff_put_vp8_bilin8_v_neon, export=1
- ldr r3, [sp, #8] @ my
- rsb r12, r3, #8
- vdup.8 d0, r3
+ push {lr}
+ ldr lr, [sp, #12] @ my
+ rsb r12, lr, #8
+ vdup.8 d0, lr
vdup.8 d1, r12
- ldr r12, [sp] @ h
- vld1.8 {d2}, [r2], r1
+ ldr r12, [sp, #4] @ h
+ vld1.8 {d2}, [r2], r3
1:
subs r12, r12, #2
- vld1.8 {d3}, [r2], r1
+ vld1.8 {d3}, [r2], r3
vmull.u8 q2, d2, d1
vmlal.u8 q2, d3, d0
- vld1.8 {d2}, [r2], r1
+ vld1.8 {d2}, [r2], r3
vmull.u8 q3, d3, d1
vmlal.u8 q3, d2, d0
vrshrn.u16 d4, q2, #3
@@ -1738,32 +1743,33 @@ function ff_put_vp8_bilin8_v_neon, export=1
vst1.8 {d6}, [r0,:64], r1
bgt 1b
- bx lr
+ pop {pc}
endfunc
function ff_put_vp8_bilin8_hv_neon, export=1
- ldr r3, [sp, #4] @ mx
- rsb r12, r3, #8
- vdup.8 d0, r3
+ push {lr}
+ ldr lr, [sp, #8] @ mx
+ rsb r12, lr, #8
+ vdup.8 d0, lr
vdup.8 d1, r12
- ldr r3, [sp, #8] @ my
- rsb r12, r3, #8
- vdup.8 d2, r3
+ ldr lr, [sp, #12] @ my
+ rsb r12, lr, #8
+ vdup.8 d2, lr
vdup.8 d3, r12
- ldr r12, [sp] @ h
+ ldr r12, [sp, #4] @ h
- vld1.8 {q2}, [r2], r1
+ vld1.8 {q2}, [r2], r3
vext.8 d5, d4, d5, #1
vmull.u8 q9, d4, d1
vmlal.u8 q9, d5, d0
vrshrn.u16 d22, q9, #3
1:
subs r12, r12, #2
- vld1.8 {q3}, [r2], r1
+ vld1.8 {q3}, [r2], r3
vext.8 d7, d6, d7, #1
vmull.u8 q8, d6, d1
vmlal.u8 q8, d7, d0
- vld1.8 {q2}, [r2], r1
+ vld1.8 {q2}, [r2], r3
vext.8 d5, d4, d5, #1
vmull.u8 q9, d4, d1
vmlal.u8 q9, d5, d0
@@ -1779,20 +1785,21 @@ function ff_put_vp8_bilin8_hv_neon, export=1
vst1.8 {d23}, [r0,:64], r1
bgt 1b
- bx lr
+ pop {pc}
endfunc
function ff_put_vp8_bilin4_h_neon, export=1
- ldr r3, [sp, #4] @ mx
- rsb r12, r3, #8
- vdup.8 d0, r3
+ push {lr}
+ ldr lr, [sp, #8] @ mx
+ rsb r12, lr, #8
+ vdup.8 d0, lr
vdup.8 d1, r12
- ldr r12, [sp] @ h
+ ldr r12, [sp, #4] @ h
1:
subs r12, r12, #2
- vld1.8 {d2}, [r2], r1
+ vld1.8 {d2}, [r2], r3
vext.8 d3, d2, d3, #1
- vld1.8 {d6}, [r2], r1
+ vld1.8 {d6}, [r2], r3
vext.8 d7, d6, d7, #1
vtrn.32 q1, q3
vmull.u8 q2, d2, d1
@@ -1802,20 +1809,21 @@ function ff_put_vp8_bilin4_h_neon, export=1
vst1.32 {d4[1]}, [r0,:32], r1
bgt 1b
- bx lr
+ pop {pc}
endfunc
function ff_put_vp8_bilin4_v_neon, export=1
- ldr r3, [sp, #8] @ my
- rsb r12, r3, #8
- vdup.8 d0, r3
+ push {lr}
+ ldr lr, [sp, #12] @ my
+ rsb r12, lr, #8
+ vdup.8 d0, lr
vdup.8 d1, r12
- ldr r12, [sp] @ h
- vld1.32 {d2[]}, [r2], r1
+ ldr r12, [sp, #4] @ h
+ vld1.32 {d2[]}, [r2], r3
1:
vld1.32 {d3[]}, [r2]
- vld1.32 {d2[1]}, [r2], r1
- vld1.32 {d3[1]}, [r2], r1
+ vld1.32 {d2[1]}, [r2], r3
+ vld1.32 {d3[1]}, [r2], r3
vmull.u8 q2, d2, d1
vmlal.u8 q2, d3, d0
vtrn.32 d3, d2
@@ -1825,30 +1833,31 @@ function ff_put_vp8_bilin4_v_neon, export=1
subs r12, r12, #2
bgt 1b
- bx lr
+ pop {pc}
endfunc
function ff_put_vp8_bilin4_hv_neon, export=1
- ldr r3, [sp, #4] @ mx
- rsb r12, r3, #8
- vdup.8 d0, r3
+ push {lr}
+ ldr lr, [sp, #8] @ mx
+ rsb r12, lr, #8
+ vdup.8 d0, lr
vdup.8 d1, r12
- ldr r3, [sp, #8] @ my
- rsb r12, r3, #8
- vdup.8 d2, r3
+ ldr lr, [sp, #12] @ my
+ rsb r12, lr, #8
+ vdup.8 d2, lr
vdup.8 d3, r12
- ldr r12, [sp] @ h
+ ldr r12, [sp, #4] @ h
- vld1.8 {d4}, [r2], r1
+ vld1.8 {d4}, [r2], r3
vext.8 d5, d4, d4, #1
vmull.u8 q9, d4, d1
vmlal.u8 q9, d5, d0
vrshrn.u16 d22, q9, #3
1:
subs r12, r12, #2
- vld1.8 {d6}, [r2], r1
+ vld1.8 {d6}, [r2], r3
vext.8 d7, d6, d6, #1
- vld1.8 {d4}, [r2], r1
+ vld1.8 {d4}, [r2], r3
vext.8 d5, d4, d4, #1
vtrn.32 q3, q2
vmull.u8 q8, d6, d1
@@ -1863,5 +1872,5 @@ function ff_put_vp8_bilin4_hv_neon, export=1
vst1.32 {d20[1]}, [r0,:32], r1
bgt 1b
- bx lr
+ pop {pc}
endfunc
diff --git a/libavcodec/ass.c b/libavcodec/ass.c
index 098050a..6fe18f5 100644
--- a/libavcodec/ass.c
+++ b/libavcodec/ass.c
@@ -1,53 +1,38 @@
/*
- * 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"
"ScriptType: v4.00+\r\n"
"\r\n"
@@ -56,11 +41,10 @@ static int ass_subtitle_header(AVCodecContext *avctx,
"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"
"\r\n"
"[Events]\r\n"
- "Format: Layer, Start, End, Text\r\n",
+ "Format: Layer, Start, End, Style, Text\r\n",
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 +53,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,37 +63,60 @@ 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 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};
+ AVBPrint buf;
+ int ret, dlen;
AVSubtitleRect **rects;
- 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);
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+ if (!raw || raw == 2) {
+ long int layer = 0;
+
+ if (raw == 2) {
+ /* skip ReadOrder */
+ dialog = strchr(dialog, ',');
+ if (!dialog)
+ return AVERROR_INVALIDDATA;
+ dialog++;
+
+ /* 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,");
}
dlen = strcspn(dialog, "\n");
dlen += dialog[dlen] == '\n';
+ av_bprintf(&buf, "%.*s", dlen, dialog);
+ if (raw == 2)
+ av_bprintf(&buf, "\r\n");
+ if (!av_bprint_is_complete(&buf))
+ return AVERROR(ENOMEM);
+
rects = av_realloc(sub->rects, (sub->num_rects+1) * sizeof(*sub->rects));
if (!rects)
return AVERROR(ENOMEM);
@@ -117,9 +124,9 @@ int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
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)
+ return ret;
sub->num_rects++;
return dlen;
}
diff --git a/libavcodec/ass.h b/libavcodec/ass.h
index 594b5f3..ef99b58 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
*/
@@ -39,20 +39,34 @@
/** @} */
/**
- * Generate a suitable AVCodecContext.subtitle_header for SUBTITLE_ASS
- * with default style.
+ * 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_default(AVCodecContext *avctx);
+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);
/**
- * Initialize an AVSubtitle structure for use with ff_ass_add_rect().
+ * Generate a suitable AVCodecContext.subtitle_header for SUBTITLE_ASS
+ * with default style.
*
- * @param sub pointer to the AVSubtitle
+ * @param avctx pointer to the AVCodecContext
+ * @return >= 0 on success otherwise an error code <0
*/
-void ff_ass_init(AVSubtitle *sub);
+int ff_ass_subtitle_header_default(AVCodecContext *avctx);
/**
* Add an ASS dialog line to an AVSubtitle as a new AVSubtitleRect.
@@ -60,8 +74,11 @@ void ff_ass_init(AVSubtitle *sub);
* @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 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
@@ -71,6 +88,6 @@ void ff_ass_init(AVSubtitle *sub);
* 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 ts_start, int duration, int raw);
#endif /* AVCODEC_ASS_H */
diff --git a/libavcodec/ass_split.c b/libavcodec/ass_split.c
new file mode 100644
index 0000000..413e9c8
--- a/dev/null
+++ b/libavcodec/ass_split.c
@@ -0,0 +1,476 @@
+/*
+ * 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[10];
+} 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)},
+ {"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) },
+ {"Alignment", ASS_INT, offsetof(ASSStyle, alignment) },
+ {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)},
+ {"BackColour", ASS_COLOR,offsetof(ASSStyle, back_color) },
+ {"Bold", ASS_INT, offsetof(ASSStyle, bold) },
+ {"Italic", ASS_INT, offsetof(ASSStyle, italic) },
+ {"Alignment", ASS_ALGN, offsetof(ASSStyle, alignment) },
+ {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) },
+ {"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 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] != ':')
+ return NULL;
+ 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;
+ 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;
+ }
+ }
+ }
+ 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..06c1ce3
--- a/dev/null
+++ b/libavcodec/ass_split.h
@@ -0,0 +1,172 @@
+/*
+ * 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 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 alignment; /**< position of the text (left, center, top...),
+ defined after the layout of the numpad
+ (1-3 sub, 4-6 mid, 7-9 top) */
+} 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 *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 f6788c9..21f179b 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 228bd18..ca67c67 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 f160434..038b461 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
*/
@@ -28,7 +28,6 @@
#include "asv.h"
#include "avcodec.h"
-#include "put_bits.h"
#include "internal.h"
#include "mathops.h"
#include "mpeg12data.h"
@@ -210,10 +209,8 @@ static int decode_frame(AVCodecContext *avctx,
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;
@@ -275,8 +272,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);
@@ -284,8 +280,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
ff_init_scantable(a->dsp.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;
@@ -312,6 +307,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"),
@@ -323,7 +319,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"),
@@ -335,4 +333,5 @@ AVCodec ff_asv2_decoder = {
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
};
+#endif
diff --git a/libavcodec/asvenc.c b/libavcodec/asvenc.c
index 9dd5e08..38d971a 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
*/
@@ -28,6 +28,7 @@
#include "asv.h"
#include "avcodec.h"
+#include "internal.h"
#include "mathops.h"
#include "mpeg12data.h"
@@ -114,7 +115,7 @@ static inline void asv2_encode_block(ASV1Context *a, int16_t block[64]){
if( (block[index + 1] = (block[index + 1]*a->q_intra_matrix[index + 1] + (1<<15))>>16) ) ccp |= 2;
if( (block[index + 9] = (block[index + 9]*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 put_bits(&a->pb, ff_asv_dc_ccp_tab[ccp][1], ff_asv_dc_ccp_tab[ccp][0]);
@@ -179,12 +180,9 @@ 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 ((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);
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..08f8357 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
*/
diff --git a/libavcodec/atrac3.c b/libavcodec/atrac3.c
index 76fd0d1..fc3b2fd 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;
@@ -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",
@@ -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/audio_frame_queue.c b/libavcodec/audio_frame_queue.c
index 0a8b25c..1220345 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->delay;
afq->remaining_samples = avctx->delay;
- 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..5d8a348
--- a/dev/null
+++ b/libavcodec/audioconvert.c
@@ -0,0 +1,116 @@
+/*
+ * 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"
+
+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;
+}
diff --git a/libavcodec/audioconvert.h b/libavcodec/audioconvert.h
new file mode 100644
index 0000000..7e7a1bc
--- a/dev/null
+++ b/libavcodec/audioconvert.h
@@ -0,0 +1,79 @@
+/*
+ * 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
+ */
+
+
+#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 /* AVCODEC_AUDIOCONVERT_H */
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 ad45d97..f7be037 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"
@@ -92,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.
@@ -271,9 +273,37 @@ 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_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
/* various PCM "codecs" */
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
@@ -305,8 +335,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,
@@ -339,6 +372,12 @@ enum AVCodecID {
AV_CODEC_ID_ADPCM_IMA_ISS,
AV_CODEC_ID_ADPCM_G722,
AV_CODEC_ID_ADPCM_IMA_APC,
+ 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,
@@ -418,10 +457,18 @@ 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_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'),
/* subtitle codecs */
AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs.
@@ -434,10 +481,30 @@ 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_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_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it
@@ -446,6 +513,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
};
/**
@@ -487,6 +558,16 @@ typedef struct AVCodecDescriptor {
* Codec supports lossless compression. Audio and video codecs only.
*/
#define AV_CODEC_PROP_LOSSLESS (1 << 2)
+/**
+ * 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
@@ -496,7 +577,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 16
/**
* @ingroup lavc_encoding
@@ -520,6 +601,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
};
/**
@@ -556,25 +638,6 @@ enum AVColorTransferCharacteristic{
AVCOL_TRC_NB , ///< Not part of ABI
};
-enum AVColorSpace{
- AVCOL_SPC_RGB = 0,
- AVCOL_SPC_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B
- AVCOL_SPC_UNSPECIFIED = 2,
- AVCOL_SPC_FCC = 4,
- AVCOL_SPC_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601
- AVCOL_SPC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC / functionally identical to above
- AVCOL_SPC_SMPTE240M = 7,
- AVCOL_SPC_YCOCG = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16
- AVCOL_SPC_NB , ///< Not part of ABI
-};
-
-enum AVColorRange{
- AVCOL_RANGE_UNSPECIFIED = 0,
- AVCOL_RANGE_MPEG = 1, ///< the normal 219*2^(n-8) "MPEG" YUV ranges
- AVCOL_RANGE_JPEG = 2, ///< the normal 2^n-1 "JPEG" YUV ranges
- AVCOL_RANGE_NB , ///< Not part of ABI
-};
-
/**
* X X 3 4 X X are luma samples,
* 1 2 1-6 are possible chroma positions
@@ -657,9 +720,11 @@ 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
/* Unsupported options :
* Syntax Arithmetic coding (SAC)
@@ -734,10 +799,12 @@ typedef struct RcOverride{
* Codec should fill in channel configuration and samplerate instead of container
*/
#define CODEC_CAP_CHANNEL_CONF 0x0400
+
/**
* Codec is able to deal with negative linesizes
*/
#define CODEC_CAP_NEG_LINESIZES 0x0800
+
/**
* Codec supports frame-level multithreading.
*/
@@ -758,6 +825,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
//The following defines may change, don't expect compatibility if you use them.
#define MB_TYPE_INTRA4x4 0x0001
@@ -881,6 +956,63 @@ enum AVPacketSideDataType {
* @endcode
*/
AV_PKT_DATA_H263_MB_INFO,
+
+ /**
+ * 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,
};
/**
@@ -891,7 +1023,7 @@ enum AVPacketSideDataType {
* 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.
*
@@ -1007,6 +1139,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 {
@@ -1112,7 +1246,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.
@@ -1142,6 +1276,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.
@@ -1176,7 +1315,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
@@ -1196,7 +1335,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
*/
@@ -1205,7 +1344,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
*/
@@ -1412,6 +1551,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
@@ -1724,7 +1865,7 @@ typedef struct AVCodecContext {
/** Field order
* - encoding: set by libavcodec
- * - decoding: Set by libavcodec
+ * - decoding: Set by user.
*/
enum AVFieldOrder field_order;
@@ -1788,7 +1929,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;
@@ -1807,9 +1948,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;
@@ -2188,9 +2330,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;
@@ -2340,9 +2482,14 @@ 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_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 compliancies 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
@@ -2364,8 +2511,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
@@ -2434,10 +2581,10 @@ typedef struct AVCodecContext {
* low resolution decoding, 1-> 1/2 size, 2->1/4 size
* - encoding: unused
* - decoding: Set by user.
- *
- * @deprecated use decoder private options instead
+ * Code outside libavcodec should access this field using:
+ * av_codec_{get,set}_lowres(avctx)
*/
- attribute_deprecated int lowres;
+ int lowres;
#endif
/**
@@ -2617,21 +2764,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.
*/
@@ -2671,8 +2818,99 @@ typedef struct AVCodecContext {
* - decoding: unused.
*/
uint64_t vbv_delay;
+
+ /**
+ * 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;
} 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);
+
/**
* AVProfile.
*/
@@ -2714,7 +2952,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}
@@ -2782,6 +3020,8 @@ typedef struct AVCodec {
void (*flush)(AVCodecContext *);
} AVCodec;
+int av_codec_get_max_lowres(const AVCodec *codec);
+
/**
* AVHWAccel.
*/
@@ -2880,11 +3120,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;
@@ -2892,9 +3134,6 @@ typedef struct AVPicture {
* @}
*/
-#define AVPALETTE_SIZE 1024
-#define AVPALETTE_COUNT 256
-
enum AVSubtitleType {
SUBTITLE_NONE,
@@ -2933,10 +3172,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;
@@ -2993,6 +3233,40 @@ void avcodec_register(AVCodec *codec);
*/
void avcodec_register_all(void);
+
+#if FF_API_ALLOC_CONTEXT
+/**
+ * Allocate an AVCodecContext and set its fields to default values. The
+ * resulting struct can be deallocated by simply calling av_free().
+ *
+ * @return An AVCodecContext filled with default values or NULL on failure.
+ * @see avcodec_get_context_defaults
+ *
+ * @deprecated use avcodec_alloc_context3()
+ */
+attribute_deprecated
+AVCodecContext *avcodec_alloc_context(void);
+
+/** THIS FUNCTION IS NOT YET PART OF THE PUBLIC API!
+ * we WILL change its arguments and name a few times! */
+attribute_deprecated
+AVCodecContext *avcodec_alloc_context2(enum AVMediaType);
+
+/**
+ * Set the fields of the given AVCodecContext to default values.
+ *
+ * @param s The AVCodecContext of which the fields should be set to default values.
+ * @deprecated use avcodec_get_context_defaults3
+ */
+attribute_deprecated
+void avcodec_get_context_defaults(AVCodecContext *s);
+
+/** THIS FUNCTION IS NOT YET PART OF THE PUBLIC API!
+ * we WILL change its arguments and name a few times! */
+attribute_deprecated
+void avcodec_get_context_defaults2(AVCodecContext *s, enum AVMediaType);
+#endif
+
/**
* Allocate an AVCodecContext and set its fields to default values. The
* resulting struct can be deallocated by calling avcodec_close() on it followed
@@ -3030,13 +3304,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
*/
@@ -3070,6 +3360,40 @@ void avcodec_get_frame_defaults(AVFrame *frame);
*/
void avcodec_free_frame(AVFrame **frame);
+#if FF_API_AVCODEC_OPEN
+/**
+ * Initialize the AVCodecContext to use the given AVCodec. Prior to using this
+ * function the context has to be allocated.
+ *
+ * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(),
+ * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for
+ * retrieving a codec.
+ *
+ * @warning This function is not thread safe!
+ *
+ * @code
+ * avcodec_register_all();
+ * codec = avcodec_find_decoder(AV_CODEC_ID_H264);
+ * if (!codec)
+ * exit(1);
+ *
+ * context = avcodec_alloc_context3(codec);
+ *
+ * if (avcodec_open(context, codec) < 0)
+ * exit(1);
+ * @endcode
+ *
+ * @param avctx The context which will be set up to use the given codec.
+ * @param codec The codec to use within the context.
+ * @return zero on success, a negative value on error
+ * @see avcodec_alloc_context3, avcodec_find_decoder, avcodec_find_encoder, avcodec_close
+ *
+ * @deprecated use avcodec_open2
+ */
+attribute_deprecated
+int avcodec_open(AVCodecContext *avctx, AVCodec *codec);
+#endif
+
/**
* Initialize the AVCodecContext to use the given AVCodec. Prior to using this
* function the context has to be allocated with avcodec_alloc_context3().
@@ -3202,6 +3526,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, AVPacket *src);
+
+/**
+ * Copy packet side data
+ *
+ * @return 0 on success, negative AVERROR on fail
+ */
+int av_copy_packet_side_data(AVPacket *dst, AVPacket *src);
+
+/**
* Free a packet.
*
* @param pkt packet to free
@@ -3241,6 +3579,11 @@ 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);
+
+
/**
* Convenience function to free all the side data stored.
* All the other fields stay untouched.
@@ -3372,6 +3715,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
@@ -3420,7 +3845,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.
@@ -3453,7 +3878,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
@@ -3464,7 +3889,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.
@@ -3476,6 +3901,14 @@ 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.
@@ -3536,6 +3969,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];
@@ -3708,7 +4142,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,
@@ -3742,6 +4176,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.
*
@@ -3755,11 +4219,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
@@ -3783,6 +4248,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.
*
@@ -3828,21 +4313,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);
@@ -3856,58 +4441,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 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
*
- * @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.
+ * @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);
@@ -3922,7 +4513,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);
@@ -3960,10 +4551,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
@@ -3994,7 +4596,8 @@ unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat pix_fmt);
* @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.
+ * @return Combination of flags informing you what kind of losses will occur
+ * (maximum loss for an invalid dst_pix_fmt).
*/
int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, enum AVPixelFormat src_pix_fmt,
int has_alpha);
@@ -4004,7 +4607,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.
@@ -4016,9 +4619,53 @@ 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);
+
+/**
+ * Find the best pixel format to convert to given a certain source pixel
+ * format and a selection of two destination pixel formats. 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_fmt_of_2() selects which of
+ * the given pixel formats should be used to suffer the least amount of loss.
+ *
+ * If one of the destination formats is AV_PIX_FMT_NONE the other pixel format (if valid) will be
+ * returned.
+ *
+ * @code
+ * src_pix_fmt = AV_PIX_FMT_YUV420P;
+ * dst_pix_fmt1= AV_PIX_FMT_RGB24;
+ * dst_pix_fmt2= AV_PIX_FMT_GRAY8;
+ * dst_pix_fmt3= AV_PIX_FMT_RGB8;
+ * loss= FF_LOSS_CHROMA; // don't care about chroma loss, so chroma loss will be ignored.
+ * dst_pix_fmt = avcodec_find_best_pix_fmt_of_2(dst_pix_fmt1, dst_pix_fmt2, src_pix_fmt, alpha, &loss);
+ * dst_pix_fmt = avcodec_find_best_pix_fmt_of_2(dst_pix_fmt, dst_pix_fmt3, src_pix_fmt, alpha, &loss);
+ * @endcode
+ *
+ * @param[in] dst_pix_fmt1 One of the two destination pixel formats to choose from
+ * @param[in] dst_pix_fmt2 The other of the two destination pixel formats to choose from
+ * @param[in] src_pix_fmt Source pixel format
+ * @param[in] has_alpha Whether the source pixel format alpha channel is used.
+ * @param[in, out] loss_ptr Combination of loss flags. In: selects which of the losses to ignore, i.e.
+ * NULL or value of zero means we care about all losses. Out: the loss
+ * that occurs when converting from src to selected dst pixel format.
+ * @return The best pixel format to convert to or -1 if none was found.
+ */
+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);
@@ -4053,7 +4700,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.
*
@@ -4066,7 +4718,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,
@@ -4092,6 +4746,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.
@@ -4131,14 +4793,78 @@ 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 availble 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(AVBitStreamFilter *f);
/* memory */
@@ -4165,15 +4891,21 @@ void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size);
void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size);
/**
- * 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
@@ -4185,7 +4917,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
@@ -4201,7 +4933,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
@@ -4241,7 +4973,7 @@ enum AVLockOp {
* lockmgr should store/get a pointer to a user allocated mutex. It's
* NULL upon AV_LOCK_CREATE and != NULL for all other ops.
*
- * @param cb User defined callback. Note: Libav may invoke calls to this
+ * @param cb User defined callback. Note: FFmpeg may invoke calls to this
* callback during the call to av_lockmgr_register().
* Thus, the application must be prepared to handle that.
* If cb is set to NULL the lockmgr will be unregistered.
@@ -4256,6 +4988,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/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 b896182..2d20a45 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 c0a0f8c..d9cfb38 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
*/
@@ -26,6 +26,9 @@
#include "libavutil/internal.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)
@@ -186,41 +189,52 @@ 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, 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, 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;
}
}
return 0;
@@ -230,6 +244,29 @@ 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, AVPacket *src)
+{
+ *dst = *src;
+ return copy_packet_data(dst, src, 0);
+}
+
void av_packet_free_side_data(AVPacket *pkt)
{
int i;
@@ -273,7 +310,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;
@@ -298,6 +335,97 @@ 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, orig_pktsize = pkt->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(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;
+ /* 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(pkt->data + pkt->size, 0,
+ FFMIN(orig_pktsize - pkt->size, FF_INPUT_BUFFER_PADDING_SIZE));
+ pkt->side_data_elems = i+1;
+ return 1;
+ }
+ return 0;
+}
+
int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
int size)
{
diff --git a/libavcodec/avpicture.c b/libavcodec/avpicture.c
index a50bbc4..a6f89ef 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,
@@ -119,7 +72,7 @@ void avpicture_free(AVPicture *picture)
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
--- a/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 6ff6d26..065345b 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
--- a/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..9276935
--- a/dev/null
+++ b/libavcodec/avuienc.c
@@ -0,0 +1,112 @@
+/*
+ * 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 = avcodec_alloc_frame();
+
+ 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, *src = pic->data[0];
+ 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++) {
+ 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 1914d6b..71d111f 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
*/
@@ -41,8 +41,8 @@ typedef struct BethsoftvidContext {
static av_cold int bethsoftvid_decode_init(AVCodecContext *avctx)
{
BethsoftvidContext *vid = avctx->priv_data;
- avctx->pix_fmt = AV_PIX_FMT_PAL8;
avcodec_get_frame_defaults(&vid->frame);
+ avctx->pix_fmt = AV_PIX_FMT_PAL8;
return 0;
}
@@ -55,7 +55,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;
@@ -74,10 +75,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..c7ac378 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.
diff --git a/libavcodec/bfin/config_bfin.h b/libavcodec/bfin/config_bfin.h
index e714070..3643953 100644
--- a/libavcodec/bfin/config_bfin.h
+++ b/libavcodec/bfin/config_bfin.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 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
*/
/*
diff --git a/libavcodec/bfin/dsputil_bfin.c b/libavcodec/bfin/dsputil_bfin.c
index 3ce2941..a95fd6b 100644
--- a/libavcodec/bfin/dsputil_bfin.c
+++ b/libavcodec/bfin/dsputil_bfin.c
@@ -4,20 +4,20 @@
* Copyright (C) 2007 Marc Hoffman <marc.hoffman@analog.com>
* Copyright (c) 2006 Michael Benjamin <michael.benjamin@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
*/
diff --git a/libavcodec/bfin/dsputil_bfin.h b/libavcodec/bfin/dsputil_bfin.h
index a082cd7..079ebdd 100644
--- a/libavcodec/bfin/dsputil_bfin.h
+++ b/libavcodec/bfin/dsputil_bfin.h
@@ -3,20 +3,20 @@
*
* Copyright (C) 2007 Marc Hoffman <mmh@pleasantst.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/bfin/fdct_bfin.S b/libavcodec/bfin/fdct_bfin.S
index c923d76..9169574 100644
--- a/libavcodec/bfin/fdct_bfin.S
+++ b/libavcodec/bfin/fdct_bfin.S
@@ -3,20 +3,20 @@
*
* Copyright (C) 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
*/
/*
@@ -104,14 +104,14 @@ short dct_coef[]
S3,C3,
-----------------------------------------------------------
-Libav conformance testing results
+FFMPEG conformance testing results
-----------------------------------------------------------
dct-test: modified with the following
dct_error("BFINfdct", 0, ff_bfin_fdct, fdct, test);
produces the following output:
-libavcodec> ./dct-test
-Libav DCT/IDCT test
+root:/u/ffmpeg/bhead/libavcodec> ./dct-test
+ffmpeg DCT/IDCT test
2 -131 -6 -48 -36 33 -83 24
34 52 -24 -15 5 92 57 143
@@ -123,6 +123,8 @@ Libav DCT/IDCT test
-17 -63 -15 73 50 -91 159 -14
DCT BFINfdct: err_inf=2 err2=0.16425938 syserr=0.00795000 maxout=2098 blockSumErr=27
DCT BFINfdct: 92.1 kdct/s
+root:/u/ffmpeg/bhead/libavcodec>
+
*/
#include "config.h"
diff --git a/libavcodec/bfin/hpel_pixels_bfin.S b/libavcodec/bfin/hpel_pixels_bfin.S
index 9b927b0..c0cbf1f 100644
--- a/libavcodec/bfin/hpel_pixels_bfin.S
+++ b/libavcodec/bfin/hpel_pixels_bfin.S
@@ -2,23 +2,22 @@
* Blackfin Pixel Operations
* Copyright (C) 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
*/
-
#include "config_bfin.h"
/*
diff --git a/libavcodec/bfin/hpeldsp_bfin.c b/libavcodec/bfin/hpeldsp_bfin.c
index cecb1db..2df551b 100644
--- a/libavcodec/bfin/hpeldsp_bfin.c
+++ b/libavcodec/bfin/hpeldsp_bfin.c
@@ -4,20 +4,20 @@
* Copyright (C) 2007 Marc Hoffman <marc.hoffman@analog.com>
* Copyright (c) 2006 Michael Benjamin <michael.benjamin@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
*/
diff --git a/libavcodec/bfin/hpeldsp_bfin.h b/libavcodec/bfin/hpeldsp_bfin.h
index 2de16f7..36f3872 100644
--- a/libavcodec/bfin/hpeldsp_bfin.h
+++ b/libavcodec/bfin/hpeldsp_bfin.h
@@ -1,23 +1,26 @@
/*
+ * BlackFin DSPUTILS COMMON OPTIMIZATIONS HEADER
+ *
* Copyright (C) 2007 Marc Hoffman <mmh@pleasantst.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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_BFIN_HPELDSP_BFIN_H
#define AVCODEC_BFIN_HPELDSP_BFIN_H
diff --git a/libavcodec/bfin/idct_bfin.S b/libavcodec/bfin/idct_bfin.S
index 0eeffc2..bd80447 100644
--- a/libavcodec/bfin/idct_bfin.S
+++ b/libavcodec/bfin/idct_bfin.S
@@ -3,20 +3,20 @@
*
* Copyright (C) 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
*/
/*
@@ -32,15 +32,15 @@ Performance :
-----------------------------------------------------------
-Libav conformance testing results
+FFMPEG conformance testing results
-----------------------------------------------------------
dct-test: modified with the following
dct_error("BFINidct", 1, ff_bfin_idct, idct, test);
produces the following output
-libavcodec> ./dct-test -i
-Libav DCT/IDCT test
+root:/u/ffmpeg/bhead/libavcodec> ./dct-test -i
+ffmpeg DCT/IDCT test
8 15 -2 21 24 17 0 10
2 -10 -5 -5 -3 7 -14 -3
diff --git a/libavcodec/bfin/mathops.h b/libavcodec/bfin/mathops.h
index bbee493..50c0316 100644
--- a/libavcodec/bfin/mathops.h
+++ b/libavcodec/bfin/mathops.h
@@ -3,20 +3,20 @@
*
* Copyright (C) 2007 Marc Hoffman <mmhoffm@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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_BFIN_MATHOPS_H
diff --git a/libavcodec/bfin/mpegvideo_bfin.c b/libavcodec/bfin/mpegvideo_bfin.c
index d03d3c0..458e7dc 100644
--- a/libavcodec/bfin/mpegvideo_bfin.c
+++ b/libavcodec/bfin/mpegvideo_bfin.c
@@ -3,20 +3,20 @@
*
* Copyright (C) 2007 Marc Hoffman <mmh@pleasantst.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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,13 @@ static int dct_quantize_bfin (MpegEncContext *s,
dc = block[0] = (block[0] + (q >> 1)) / q;
start_i = 1;
last_non_zero = 0;
- bias = s->q_intra_matrix16[qscale][1];
- qmat = s->q_intra_matrix16[qscale][0];
+ if(n<4){
+ bias = s->q_intra_matrix16[qscale][1];
+ qmat = s->q_intra_matrix16[qscale][0];
+ }else{
+ bias = s->q_chroma_intra_matrix16[qscale][1];
+ qmat = s->q_chroma_intra_matrix16[qscale][0];
+ }
} else {
start_i = 0;
diff --git a/libavcodec/bfin/pixels_bfin.S b/libavcodec/bfin/pixels_bfin.S
index 70d9de5..2c84deb 100644
--- a/libavcodec/bfin/pixels_bfin.S
+++ b/libavcodec/bfin/pixels_bfin.S
@@ -2,20 +2,20 @@
* Blackfin Pixel Operations
* Copyright (C) 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
*/
#include "config_bfin.h"
@@ -160,7 +160,7 @@ DEFUN_END(pix_sum)
DEFUN(get_pixels,mL1,
- (int16_t *restrict block, const uint8_t *pixels, int line_size)):
+ (int16_t *av_restrict block, const uint8_t *pixels, int line_size)):
[--sp] = (r7:4);
i3=r0; // dest
i0=r1; // src0
diff --git a/libavcodec/bfin/vp3_bfin.c b/libavcodec/bfin/vp3_bfin.c
index a8cdcb6..868c431 100644
--- a/libavcodec/bfin/vp3_bfin.c
+++ b/libavcodec/bfin/vp3_bfin.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 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
*/
diff --git a/libavcodec/bfin/vp3_bfin.h b/libavcodec/bfin/vp3_bfin.h
index 5a2c5a4..e832de7 100644
--- a/libavcodec/bfin/vp3_bfin.h
+++ b/libavcodec/bfin/vp3_bfin.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/bfin/vp3_idct_bfin.S b/libavcodec/bfin/vp3_idct_bfin.S
index 05ec96a..4e20045 100644
--- a/libavcodec/bfin/vp3_idct_bfin.S
+++ b/libavcodec/bfin/vp3_idct_bfin.S
@@ -3,20 +3,20 @@
*
* Copyright (C) 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
*/
/*
diff --git a/libavcodec/bgmc.c b/libavcodec/bgmc.c
index c7f732e..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"
@@ -460,8 +460,8 @@ static uint8_t *bgmc_lut_getp(uint8_t *lut, int *lut_status, int delta)
av_cold int ff_bgmc_init(AVCodecContext *avctx,
uint8_t **cf_lut, int **cf_lut_status)
{
- *cf_lut = av_malloc(sizeof(*cf_lut) * LUT_BUFF * 16 * LUT_SIZE);
- *cf_lut_status = av_malloc(sizeof(*cf_lut_status) * LUT_BUFF);
+ *cf_lut = av_malloc(sizeof(**cf_lut) * LUT_BUFF * 16 * LUT_SIZE);
+ *cf_lut_status = av_malloc(sizeof(**cf_lut_status) * LUT_BUFF);
if (!*cf_lut || !*cf_lut_status) {
ff_bgmc_end(cf_lut, cf_lut_status);
@@ -469,7 +469,7 @@ av_cold int ff_bgmc_init(AVCodecContext *avctx,
return AVERROR(ENOMEM);
} else {
// initialize lut_status buffer to a value never used to compare against
- memset(*cf_lut_status, -1, sizeof(*cf_lut_status) * LUT_BUFF);
+ memset(*cf_lut_status, -1, sizeof(**cf_lut_status) * LUT_BUFF);
}
return 0;
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 0057542..8878694 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
*/
@@ -143,7 +143,7 @@ enum BlockTypes {
};
/**
- * Initialize length length in all bundles.
+ * Initialize length in all bundles.
*
* @param c decoder context
* @param width plane width
@@ -174,7 +174,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;
@@ -185,8 +185,12 @@ static av_cold void init_bundles(BinkContext *c)
for (i = 0; i < BINKB_NB_SRC; i++) {
c->bundle[i].data = av_malloc(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 +683,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 +871,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->bdsp.idct_put(dst, stride, dctblock);
break;
case 3:
@@ -899,7 +904,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->bdsp.idct_add(dst, stride, dctblock);
break;
case 5:
@@ -1136,6 +1141,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 +1187,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;
}
@@ -1234,41 +1240,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 +1307,10 @@ static av_cold int decode_init(AVCodecContext *avctx)
ff_hpeldsp_init(&c->hdsp, avctx->flags);
ff_binkdsp_init(&c->bdsp);
- init_bundles(c);
+ if ((ret = init_bundles(c)) < 0) {
+ free_bundles(c);
+ return ret;
+ }
if (c->version == 'b') {
if (!binkb_initialised) {
diff --git a/libavcodec/binkaudio.c b/libavcodec/binkaudio.c
index ddaa613..b7ad418 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
@@ -317,10 +317,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 a0ac2a8..a23f9c7 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
*/
diff --git a/libavcodec/binkdsp.h b/libavcodec/binkdsp.h
index 4c1f73f..6b84e01 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
--- a/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
--- a/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 37d02ad..96f5ede 100644
--- a/libavcodec/bit_depth_template.c
+++ b/libavcodec/bit_depth_template.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
*/
#include "rnd_avg.h"
+#include "libavutil/intreadwrite.h"
#ifndef BIT_DEPTH
#define BIT_DEPTH 8
@@ -70,7 +71,7 @@
# define pixel4 uint32_t
# define dctcoef int16_t
-# define INIT_CLIP const uint8_t *cm = ff_cropTbl + 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
@@ -82,7 +83,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 e7c476b..299ee23 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"
@@ -107,9 +109,9 @@ static int alloc_table(VLC *vlc, int size, int use_static)
vlc->table_size += size;
if (vlc->table_size > vlc->table_allocated) {
if (use_static)
- return AVERROR_BUG;
+ abort(); // cannot do anything, init_vlc() is used with too little memory
vlc->table_allocated += (1 << vlc->bits);
- vlc->table = av_realloc(vlc->table, sizeof(VLC_TYPE) * 2 * vlc->table_allocated);
+ vlc->table = av_realloc_f(vlc->table, vlc->table_allocated, sizeof(VLC_TYPE) * 2);
if (!vlc->table)
return AVERROR(ENOMEM);
}
@@ -160,6 +162,8 @@ static int build_table(VLC *vlc, int table_nb_bits, int nb_codes,
VLC_TYPE (*table)[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)
@@ -266,42 +270,59 @@ 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
+ void *state;
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;
+ while (state = avpriv_atomic_ptr_cas(&vlc->init_state, NULL, vlc)) {
+ if (state == vlc + 1) {
+ av_assert0(vlc->table_size && vlc->table_size == vlc->table_allocated);
+ return 0;
+ }
}
+ av_assert0(!vlc->table_size);
+ av_assert0(nb_codes + 1 <= FF_ARRAY_ELEMS(localbuf));
+ buf = localbuf;
} 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((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);
@@ -312,15 +333,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);
+ state = avpriv_atomic_ptr_cas(&vlc->init_state, vlc, vlc+1);
+ av_assert0(state == vlc);
+ av_assert0(ret >= 0);
+ } 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 8960b19..3ee582f 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,8 +36,9 @@ AVBitStreamFilter *av_bitstream_filter_next(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)
@@ -59,6 +61,8 @@ AVBitStreamFilterContext *av_bitstream_filter_init(const char *name)
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/bmp.c b/libavcodec/bmp.c
index e5f7ebb..404c47d 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
*/
@@ -38,7 +38,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;
@@ -83,7 +84,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
@@ -107,7 +109,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;
@@ -123,6 +125,7 @@ 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);
+ alpha = bytestream_get_le32(&buf);
}
avctx->width = width;
@@ -133,21 +136,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;
@@ -193,10 +196,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;
@@ -204,7 +205,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",
@@ -242,16 +243,20 @@ static int bmp_decode_frame(AVCodecContext *avctx,
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];
}
@@ -282,6 +287,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;
@@ -311,23 +317,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 ab11523..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
*/
@@ -24,10 +24,6 @@
#include "avcodec.h"
-typedef struct BMPContext {
- AVFrame picture;
-} BMPContext;
-
typedef enum {
BMP_RGB =0,
BMP_RLE8 =1,
diff --git a/libavcodec/bmp_parser.c b/libavcodec/bmp_parser.c
new file mode 100644
index 0000000..06ed367
--- a/dev/null
+++ b/libavcodec/bmp_parser.c
@@ -0,0 +1,91 @@
+/*
+ * BMP parser
+ * 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
+ */
+
+/**
+ * @file
+ * BMP parser
+ */
+
+#include "libavutil/bswap.h"
+#include "parser.h"
+
+typedef struct BMPParseContext {
+ ParseContext pc;
+ uint32_t fsize;
+ uint32_t remaining_size;
+} BMPParseContext;
+
+static int bmp_parse(AVCodecParserContext *s, AVCodecContext *avctx,
+ const uint8_t **poutbuf, int *poutbuf_size,
+ const uint8_t *buf, int buf_size)
+{
+ BMPParseContext *bpc = s->priv_data;
+ uint64_t state = bpc->pc.state64;
+ 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 (!bpc->pc.frame_start_found) {
+ 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;
+ }
+ }
+ bpc->pc.state64 = state;
+ } else {
+ if (bpc->remaining_size) {
+ i = FFMIN(bpc->remaining_size, buf_size);
+ bpc->remaining_size -= i;
+ if (bpc->remaining_size)
+ goto flush;
+ next = i;
+ }
+ }
+
+flush:
+ if (ff_combine_frame(&bpc->pc, next, &buf, &buf_size) < 0)
+ return buf_size;
+
+ bpc->pc.frame_start_found = 0;
+
+ *poutbuf = buf;
+ *poutbuf_size = buf_size;
+ return next;
+}
+
+AVCodecParser ff_bmp_parser = {
+ .codec_ids = { AV_CODEC_ID_BMP },
+ .priv_data_size = sizeof(BMPParseContext),
+ .parser_parse = bmp_parse,
+ .parser_close = ff_parse_close,
+};
diff --git a/libavcodec/bmpenc.c b/libavcodec/bmpenc.c
index 44e18cc..ad02a6b 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"
@@ -31,12 +32,10 @@ static const uint32_t rgb565_masks[] = { 0xF800, 0x07E0, 0x001F };
static const uint32_t rgb444_masks[] = { 0x0F00, 0x00F0, 0x000F };
static av_cold int bmp_encode_init(AVCodecContext *avctx){
- BMPContext *s = avctx->priv_data;
-
- avcodec_get_frame_defaults(&s->picture);
- avctx->coded_frame = &s->picture;
-
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;
@@ -58,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);
}
return 0;
@@ -67,14 +66,14 @@ static av_cold int bmp_encode_init(AVCodecContext *avctx){
static int bmp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *pict, int *got_packet)
{
- BMPContext *s = avctx->priv_data;
- AVFrame * const p = &s->picture;
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;
- *p = *pict;
+ AVFrame * const p = (AVFrame *)pict;
+
p->pict_type= AV_PICTURE_TYPE_I;
p->key_frame= 1;
switch (avctx->pix_fmt) {
@@ -93,7 +92,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;
@@ -112,10 +114,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.
@@ -164,12 +164,11 @@ AVCodec ff_bmp_encoder = {
.long_name = NULL_IF_CONFIG_SMALL("BMP (Windows and OS/2 bitmap)"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_BMP,
- .priv_data_size = sizeof(BMPContext),
.init = bmp_encode_init,
.encode2 = bmp_encode_frame,
.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/bmv.c b/libavcodec/bmv.c
index 3c017d0..baa1c8b 100644
--- a/libavcodec/bmv.c
+++ b/libavcodec/bmv.c
@@ -2,23 +2,24 @@
* Discworld II BMV video and 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
*/
+#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "avcodec.h"
#include "bytestream.h"
@@ -99,6 +100,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;
@@ -132,6 +135,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;
@@ -184,8 +188,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;
@@ -226,7 +228,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) {
@@ -240,10 +242,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");
@@ -275,6 +275,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;
@@ -313,10 +318,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/brender_pix.c b/libavcodec/brender_pix.c
new file mode 100644
index 0000000..e1f5d48
--- a/dev/null
+++ b/libavcodec/brender_pix.c
@@ -0,0 +1,219 @@
+/*
+ * BRender PIX (.pix) image decoder
+ * Copyright (c) 2012 Aleksi Nurmi
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * Tested against samples from I-War / Independence War and Defiance.
+ * If the PIX file does not contain a palette, the
+ * palette_has_changed property of the AVFrame is set to 0.
+ */
+
+#include "libavutil/imgutils.h"
+#include "avcodec.h"
+#include "bytestream.h"
+#include "internal.h"
+
+typedef struct BRPixHeader {
+ int format;
+ unsigned int width, height;
+} BRPixHeader;
+
+static int brpix_decode_header(BRPixHeader *out, GetByteContext *pgb)
+{
+ unsigned int header_len = bytestream2_get_be32(pgb);
+
+ out->format = bytestream2_get_byte(pgb);
+ bytestream2_skip(pgb, 2);
+ out->width = bytestream2_get_be16(pgb);
+ out->height = bytestream2_get_be16(pgb);
+
+ // the header is at least 11 bytes long; we read the first 7
+ if (header_len < 11) {
+ return 0;
+ }
+
+ // skip the rest of the header
+ bytestream2_skip(pgb, header_len-7);
+
+ return 1;
+}
+
+static int brpix_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ AVFrame *frame = data;
+
+ int ret;
+ GetByteContext gb;
+
+ unsigned int bytes_pp;
+
+ unsigned int magic[4];
+ unsigned int chunk_type;
+ unsigned int data_len;
+ BRPixHeader hdr;
+
+ bytestream2_init(&gb, avpkt->data, avpkt->size);
+
+ magic[0] = bytestream2_get_be32(&gb);
+ magic[1] = bytestream2_get_be32(&gb);
+ magic[2] = bytestream2_get_be32(&gb);
+ magic[3] = bytestream2_get_be32(&gb);
+
+ if (magic[0] != 0x12 ||
+ magic[1] != 0x8 ||
+ magic[2] != 0x2 ||
+ magic[3] != 0x2) {
+ av_log(avctx, AV_LOG_ERROR, "Not a BRender PIX file\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ chunk_type = bytestream2_get_be32(&gb);
+ if (chunk_type != 0x3 && chunk_type != 0x3d) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid chunk type %d\n", chunk_type);
+ return AVERROR_INVALIDDATA;
+ }
+
+ ret = brpix_decode_header(&hdr, &gb);
+ if (!ret) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid header length\n");
+ return AVERROR_INVALIDDATA;
+ }
+ switch (hdr.format) {
+ case 3:
+ avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ bytes_pp = 1;
+ break;
+ case 4:
+ avctx->pix_fmt = AV_PIX_FMT_RGB555BE;
+ bytes_pp = 2;
+ break;
+ case 5:
+ avctx->pix_fmt = AV_PIX_FMT_RGB565BE;
+ bytes_pp = 2;
+ break;
+ case 6:
+ avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ bytes_pp = 3;
+ break;
+ case 7:
+ avctx->pix_fmt = AV_PIX_FMT_0RGB;
+ bytes_pp = 4;
+ break;
+ case 18:
+ avctx->pix_fmt = AV_PIX_FMT_GRAY8A;
+ bytes_pp = 2;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Format %d is not supported\n",
+ hdr.format);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ if (av_image_check_size(hdr.width, hdr.height, 0, avctx) < 0)
+ return AVERROR_INVALIDDATA;
+
+ if (hdr.width != avctx->width || hdr.height != avctx->height)
+ avcodec_set_dimensions(avctx, hdr.width, hdr.height);
+
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+
+ chunk_type = bytestream2_get_be32(&gb);
+
+ if (avctx->pix_fmt == AV_PIX_FMT_PAL8 &&
+ (chunk_type == 0x3 || chunk_type == 0x3d)) {
+ BRPixHeader palhdr;
+ uint32_t *pal_out = (uint32_t *)frame->data[1];
+ int i;
+
+ ret = brpix_decode_header(&palhdr, &gb);
+ if (!ret) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid palette header length\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (palhdr.format != 7) {
+ av_log(avctx, AV_LOG_ERROR, "Palette is not in 0RGB format\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ chunk_type = bytestream2_get_be32(&gb);
+ data_len = bytestream2_get_be32(&gb);
+ bytestream2_skip(&gb, 8);
+ if (chunk_type != 0x21 || data_len != 1032 ||
+ bytestream2_get_bytes_left(&gb) < 1032) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid palette data\n");
+ return AVERROR_INVALIDDATA;
+ }
+ // convert 0RGB to machine endian format (ARGB32)
+ for (i = 0; i < 256; ++i) {
+ bytestream2_skipu(&gb, 1);
+ *pal_out++ = (0xFFU << 24) | bytestream2_get_be24u(&gb);
+ }
+ bytestream2_skip(&gb, 8);
+
+ frame->palette_has_changed = 1;
+
+ chunk_type = bytestream2_get_be32(&gb);
+ } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
+ uint32_t *pal_out = (uint32_t *)frame->data[1];
+ int i;
+
+ for (i = 0; i < 256; ++i) {
+ *pal_out++ = (0xFFU << 24) | (i * 0x010101);
+ }
+ frame->palette_has_changed = 1;
+ }
+
+ data_len = bytestream2_get_be32(&gb);
+ bytestream2_skip(&gb, 8);
+
+ // read the image data to the buffer
+ {
+ unsigned int bytes_per_scanline = bytes_pp * hdr.width;
+ unsigned int bytes_left = bytestream2_get_bytes_left(&gb);
+
+ if (chunk_type != 0x21 || data_len != bytes_left ||
+ bytes_left / bytes_per_scanline < hdr.height)
+ {
+ av_log(avctx, AV_LOG_ERROR, "Invalid image data\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ av_image_copy_plane(frame->data[0], frame->linesize[0],
+ avpkt->data + bytestream2_tell(&gb),
+ bytes_per_scanline,
+ bytes_per_scanline, hdr.height);
+ }
+
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+AVCodec ff_brender_pix_decoder = {
+ .name = "brender_pix",
+ .long_name = NULL_IF_CONFIG_SMALL("BRender PIX image"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_BRENDER_PIX,
+ .decode = brpix_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/bytestream.h b/libavcodec/bytestream.h
index 0f89558..f245859 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;
@@ -190,6 +193,16 @@ static av_always_inline int bytestream2_tell_p(PutByteContext *p)
return (int)(p->buffer - p->buffer_start);
}
+static av_always_inline int bytestream2_size(GetByteContext *g)
+{
+ return (int)(g->buffer_end - g->buffer_start);
+}
+
+static av_always_inline int bytestream2_size_p(PutByteContext *p)
+{
+ return (int)(p->buffer_end - p->buffer_start);
+}
+
static av_always_inline int bytestream2_seek(GetByteContext *g,
int offset,
int whence)
diff --git a/libavcodec/c93.c b/libavcodec/c93.c
index d1f8629..f25368b 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
*/
@@ -127,12 +127,12 @@ static int decode_frame(AVCodecContext *avctx, void *data,
uint8_t *out;
int stride, ret, i, x, y, b, bt = 0;
+ avcodec_set_dimensions(avctx, WIDTH, HEIGHT);
+
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];
@@ -170,7 +170,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;
@@ -230,7 +237,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 e1cd811..29b188b 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
*/
@@ -147,7 +147,6 @@ void ff_init_cabac_states(void)
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;
@@ -165,3 +164,151 @@ void ff_init_cabac_states(void)
initialized = 1;
}
+
+#ifdef TEST
+#define SIZE 10240
+
+#include "libavutil/lfg.h"
+#include "avcodec.h"
+
+static inline void put_cabac_bit(CABACContext *c, int b){
+ put_bits(&c->pb, 1, b);
+ for(;c->outstanding_count; c->outstanding_count--){
+ put_bits(&c->pb, 1, 1-b);
+ }
+}
+
+static inline void renorm_cabac_encoder(CABACContext *c){
+ while(c->range < 0x100){
+ //FIXME optimize
+ if(c->low<0x100){
+ put_cabac_bit(c, 0);
+ }else if(c->low<0x200){
+ c->outstanding_count++;
+ c->low -= 0x100;
+ }else{
+ put_cabac_bit(c, 1);
+ c->low -= 0x200;
+ }
+
+ c->range+= c->range;
+ c->low += c->low;
+ }
+}
+
+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];
+ }
+
+ 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(&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 04495a6..d4bafe0 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
*/
diff --git a/libavcodec/cabac_functions.h b/libavcodec/cabac_functions.h
index afc7c98..b84258b 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
*/
@@ -49,8 +49,7 @@ static void refill(CABACContext *c){
c->low+= c->bytestream[0]<<1;
#endif
c->low -= CABAC_MASK;
- if (c->bytestream < c->bytestream_end)
- c->bytestream += CABAC_BITS / 8;
+ c->bytestream += CABAC_BITS / 8;
}
static inline void renorm_cabac_decoder_once(CABACContext *c){
@@ -77,8 +76,7 @@ static void refill2(CABACContext *c){
#endif
c->low += x<<i;
- if (c->bytestream < c->bytestream_end)
- c->bytestream += CABAC_BITS/8;
+ c->bytestream += CABAC_BITS/8;
}
static av_always_inline int get_cabac_inline(CABACContext *c, uint8_t * const state){
@@ -162,4 +160,24 @@ static int av_unused get_cabac_terminate(CABACContext *c){
}
}
+/**
+ * Skip @p n bytes and reset the decoder.
+ * @return the address of the first skipped byte or NULL if there's less than @p n bytes left
+ */
+static av_unused const uint8_t* skip_bytes(CABACContext *c, int n) {
+ const uint8_t *ptr = c->bytestream;
+
+ if (c->low & 0x1)
+ ptr--;
+#if CABAC_BITS == 16
+ if (c->low & 0x1FF)
+ ptr--;
+#endif
+ if ((int) (c->bytestream_end - ptr) < n)
+ return NULL;
+ ff_init_cabac_decoder(c, ptr + n, c->bytestream_end - ptr - n);
+
+ return ptr;
+}
+
#endif /* AVCODEC_CABAC_FUNCTIONS_H */
diff --git a/libavcodec/cavs.c b/libavcodec/cavs.c
index 19b9929..42b82e4 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
*/
@@ -407,7 +407,7 @@ static inline void mc_dir_part(AVSContext *h, AVFrame *pic, int chroma_height,
full_my < 0 - extra_height ||
full_mx + 16 /* FIXME */ > pic_width + extra_width ||
full_my + 16 /* FIXME */ > pic_height + extra_height) {
- h->vdsp.emulated_edge_mc(h->edge_emu_buffer,
+ h->vdsp.emulated_edge_mc(h->edge_emu_buffer, h->l_stride,
src_y - 2 - 2 * h->l_stride, h->l_stride,
16 + 5, 16 + 5 /* FIXME */,
full_mx - 2, full_my - 2,
@@ -420,7 +420,7 @@ static inline void mc_dir_part(AVSContext *h, AVFrame *pic, int chroma_height,
qpix_op[luma_xy](dest_y, src_y, h->l_stride);
if (emu) {
- h->vdsp.emulated_edge_mc(h->edge_emu_buffer, src_cb,
+ h->vdsp.emulated_edge_mc(h->edge_emu_buffer, h->c_stride, src_cb,
h->c_stride,
9, 9 /* FIXME */,
mx >> 3, my >> 3,
@@ -430,7 +430,7 @@ static inline void mc_dir_part(AVSContext *h, AVFrame *pic, int chroma_height,
chroma_op(dest_cb, src_cb, h->c_stride, chroma_height, mx & 7, my & 7);
if (emu) {
- h->vdsp.emulated_edge_mc(h->edge_emu_buffer, src_cr,
+ h->vdsp.emulated_edge_mc(h->edge_emu_buffer, h->c_stride, src_cr,
h->c_stride,
9, 9 /* FIXME */,
mx >> 3, my >> 3,
@@ -701,7 +701,7 @@ int ff_cavs_next_mb(AVSContext *h)
*
****************************************************************************/
-void ff_cavs_init_pic(AVSContext *h)
+int ff_cavs_init_pic(AVSContext *h)
{
int i;
@@ -722,6 +722,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;
}
/*****************************************************************************
diff --git a/libavcodec/cavs.h b/libavcodec/cavs.h
index 7d9b94e..f3c05dc 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
*/
@@ -267,7 +267,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..905a306 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
*/
diff --git a/libavcodec/cavsdec.c b/libavcodec/cavsdec.c
index 142b844..74983a7 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"
@@ -509,11 +510,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 +555,30 @@ 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)
+ return -1;
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;
@@ -602,7 +608,7 @@ static inline int decode_residual_inter(AVSContext *h)
/* get coded block pattern */
int cbp = get_ue_golomb(&h->gb);
- if (cbp > 63 || cbp < 0) {
+ if (cbp > 63U) {
av_log(h->avctx, AV_LOG_ERROR, "illegal inter cbp %d\n", cbp);
return AVERROR_INVALIDDATA;
}
@@ -673,7 +679,7 @@ static int decode_mb_i(AVSContext *h, int cbp_code)
/* get coded block pattern */
if (h->cur.f->pict_type == AV_PICTURE_TYPE_I)
cbp_code = get_ue_golomb(gb);
- if (cbp_code > 63 || cbp_code < 0) {
+ if (cbp_code > 63U) {
av_log(h->avctx, AV_LOG_ERROR, "illegal intra cbp\n");
return AVERROR_INVALIDDATA;
}
@@ -760,7 +766,7 @@ static void decode_mb_p(AVSContext *h, enum cavs_mb mb_type)
h->col_type_base[h->mbidx] = mb_type;
}
-static void decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
+static int decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
{
int block;
enum cavs_sub_mb sub_type[4];
@@ -832,7 +838,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 +877,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,6 +891,10 @@ 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)
+ return -1;
+
h->mby = h->stc;
h->mbidx = h->mby * h->mb_width;
@@ -929,6 +945,7 @@ static inline int check_for_slice(AVSContext *h)
static int decode_pic(AVSContext *h)
{
int skip_count = -1;
+ int ret;
enum cavs_mb mb_type;
if (!h->top_qp) {
@@ -964,8 +981,10 @@ static int decode_pic(AVSContext *h)
skip_bits(&h->gb, 1); //marker_bit
}
- ff_get_buffer(h->avctx, h->cur.f, h->cur.f->pict_type == AV_PICTURE_TYPE_B ?
- 0 : AV_GET_BUFFER_FLAG_REF);
+ if ((ret = ff_get_buffer(h->avctx, h->cur.f,
+ h->cur.f->pict_type == AV_PICTURE_TYPE_B ?
+ 0 : AV_GET_BUFFER_FLAG_REF)) < 0)
+ return ret;
if (!h->edge_emu_buffer) {
int alloc_size = FFALIGN(FFABS(h->cur.f->linesize[0]) + 32, 32);
@@ -974,7 +993,8 @@ 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 */
@@ -1090,6 +1110,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;
diff --git a/libavcodec/cavsdsp.c b/libavcodec/cavsdsp.c
index 2716e33..61283c2 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 333bd10..4598c7d 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..0db64fc 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
*/
@@ -42,7 +42,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 b8a6fb8..b7a8fa7 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,7 +265,7 @@ 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;
@@ -273,20 +273,25 @@ static int cdg_decode_frame(AVCodecContext *avctx,
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);
+ }
- 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 = bytestream_get_byte(&buf);
inst = bytestream_get_byte(&buf);
inst &= CDG_MASK;
buf += 2; /// skipping 2 unneeded bytes
- bytestream_get_buffer(&buf, cdg_data, buf_size - CDG_HEADER_SIZE);
+
+ if (buf_size > CDG_HEADER_SIZE)
+ bytestream_get_buffer(&buf, cdg_data, buf_size - CDG_HEADER_SIZE);
if ((command & CDG_MASK) == CDG_COMMAND) {
switch (inst) {
@@ -327,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 b198c4c..93a5537 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,14 +34,13 @@
#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
typedef struct {
AVCodecContext *avctx;
- AVFrame frame;
int bpp;
int format;
int padded_bits;
@@ -64,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);
}
}
@@ -116,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]);
}
@@ -258,10 +266,8 @@ static int cdxl_decode_frame(AVCodecContext *avctx, void *data,
return AVERROR_PATCHWELCOME;
}
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
p->pict_type = AV_PICTURE_TYPE_I;
if (encoding) {
@@ -285,7 +291,7 @@ static av_cold int cdxl_decode_end(AVCodecContext *avctx)
{
CDXLVideoContext *c = avctx->priv_data;
- av_free(c->new_video);
+ av_freep(&c->new_video);
return 0;
}
diff --git a/libavcodec/celp_filters.c b/libavcodec/celp_filters.c
index 381ffa4..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];
@@ -133,7 +136,7 @@ void ff_celp_lp_synthesis_filterf(float *out, const float *filter_coeffs,
out2 -= val * old_out2;
out3 -= val * old_out3;
- for (i = 5; i <= filter_length; i += 2) {
+ for (i = 5; i < filter_length; i += 2) {
old_out3 = out[-i];
val = filter_coeffs[i-1];
@@ -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 3167a23..082d0b2 100644
--- a/libavcodec/cinepak.c
+++ b/libavcodec/cinepak.c
@@ -2,20 +2,20 @@
* Cinepak Video Decoder
* 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
@@ -58,7 +58,7 @@ typedef struct {
typedef struct CinepakContext {
AVCodecContext *avctx;
- AVFrame frame;
+ AVFrame *frame;
const unsigned char *data;
int size;
@@ -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;
+ uint8_t *cb0, *cb1, *cb2, *cb3;
unsigned int x, y;
- uint32_t iy[4];
- uint32_t iu[2];
- uint32_t iv[2];
+ 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,18 +409,21 @@ 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;
}
- avcodec_get_frame_defaults(&s->frame);
+ s->frame = av_frame_alloc();
+ if (!s->frame)
+ return AVERROR(ENOMEM);
return 0;
}
@@ -430,25 +439,25 @@ 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);
if (pal) {
- s->frame.palette_has_changed = 1;
+ s->frame->palette_has_changed = 1;
memcpy(s->pal, pal, AVPALETTE_SIZE);
}
}
- 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);
+ memcpy (s->frame->data[1], s->pal, AVPALETTE_SIZE);
- if ((ret = av_frame_ref(data, &s->frame)) < 0)
+ if ((ret = av_frame_ref(data, s->frame)) < 0)
return ret;
*got_frame = 1;
@@ -461,7 +470,7 @@ static av_cold int cinepak_decode_end(AVCodecContext *avctx)
{
CinepakContext *s = avctx->priv_data;
- av_frame_unref(&s->frame);
+ av_frame_free(&s->frame);
return 0;
}
diff --git a/libavcodec/cljr.c b/libavcodec/cljr.c
index f6dbb76..51ac106 100644
--- a/libavcodec/cljr.c
+++ b/libavcodec/cljr.c
@@ -2,20 +2,20 @@
* Cirrus Logic AccuPak (CLJR) codec
* 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,6 +25,7 @@
*/
#include "avcodec.h"
+#include "libavutil/opt.h"
#include "get_bits.h"
#include "internal.h"
#include "put_bits.h"
@@ -45,16 +46,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;
@@ -65,10 +64,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;
@@ -99,7 +98,9 @@ AVCodec ff_cljr_decoder = {
#if CONFIG_CLJR_ENCODER
typedef struct CLJRContext {
+ AVClass *avclass;
AVFrame picture;
+ int dither_type;
} CLJRContext;
static av_cold int encode_init(AVCodecContext *avctx)
@@ -114,13 +115,18 @@ static av_cold int encode_init(AVCodecContext *avctx)
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;
-
- if ((ret = ff_alloc_packet(pkt, 32*avctx->height*avctx->width/4)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+ uint32_t dither= avctx->frame_number;
+ static const uint32_t ordered_dither[2][2] =
+ {
+ { 0x10400000, 0x104F0000 },
+ { 0xCB2A0000, 0xCB250000 },
+ };
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, 32*avctx->height*avctx->width/4)) < 0)
return ret;
- }
avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
avctx->coded_frame->key_frame = 1;
@@ -132,13 +138,18 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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) {
- 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;
+ }
+ 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);
}
}
@@ -150,6 +161,20 @@ 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"),
@@ -160,5 +185,6 @@ AVCodec ff_cljr_encoder = {
.encode2 = encode_frame,
.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV411P,
AV_PIX_FMT_NONE },
+ .priv_class = &cljr_class,
};
#endif
diff --git a/libavcodec/cllc.c b/libavcodec/cllc.c
index 6818f9f..ee77381 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
*/
@@ -410,11 +410,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)
@@ -426,11 +423,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)
@@ -441,11 +435,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..12241c3 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
*/
@@ -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..5ab6e36 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
*/
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index f486cb2..3c4793d 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
*/
@@ -36,7 +39,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.id = AV_CODEC_ID_MPEG2VIDEO,
.type = AVMEDIA_TYPE_VIDEO,
.name = "mpeg2video",
- .long_name = NULL_IF_CONFIG_SMALL("MPEG-1 video"),
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 video"),
.props = AV_CODEC_PROP_LOSSY,
},
{
@@ -71,7 +74,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.id = AV_CODEC_ID_RV20,
.type = AVMEDIA_TYPE_VIDEO,
.name = "rv20",
- .long_name = NULL_IF_CONFIG_SMALL("RealVideo 1.0"),
+ .long_name = NULL_IF_CONFIG_SMALL("RealVideo 2.0"),
.props = AV_CODEC_PROP_LOSSY,
},
{
@@ -223,6 +226,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS,
},
{
+ .id = AV_CODEC_ID_HEVC,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "hevc",
+ .long_name = NULL_IF_CONFIG_SMALL("H.265 / HEVC"),
+ .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS,
+ },
+ {
.id = AV_CODEC_ID_INDEO3,
.type = AVMEDIA_TYPE_VIDEO,
.name = "indeo3",
@@ -419,6 +429,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",
@@ -739,7 +756,14 @@ static const AVCodecDescriptor codec_descriptors[] = {
.type = AVMEDIA_TYPE_VIDEO,
.name = "sgi",
.long_name = NULL_IF_CONFIG_SMALL("SGI image"),
- .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ },
+ {
+ .id = AV_CODEC_ID_SGIRLE,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "sgirle",
+ .long_name = NULL_IF_CONFIG_SMALL("SGI RLE 8-bit"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
},
{
.id = AV_CODEC_ID_C93,
@@ -912,6 +936,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.id = AV_CODEC_ID_TMV,
.type = AVMEDIA_TYPE_VIDEO,
.name = "tmv",
+ .long_name = NULL_IF_CONFIG_SMALL("8088flex TMV"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
},
{
@@ -925,8 +950,8 @@ static const AVCodecDescriptor codec_descriptors[] = {
.id = AV_CODEC_ID_DPX,
.type = AVMEDIA_TYPE_VIDEO,
.name = "dpx",
- .long_name = NULL_IF_CONFIG_SMALL("DPX image"),
- .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+ .long_name = NULL_IF_CONFIG_SMALL("DPX (Digital Picture Exchange) image"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
},
{
.id = AV_CODEC_ID_MAD,
@@ -1055,6 +1080,20 @@ static const AVCodecDescriptor codec_descriptors[] = {
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
},
{
+ .id = AV_CODEC_ID_MVC1,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "mvc1",
+ .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_MVC2,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "mvc2",
+ .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+ },
+ {
.id = AV_CODEC_ID_MXPEG,
.type = AVMEDIA_TYPE_VIDEO,
.name = "mxpeg",
@@ -1150,12 +1189,13 @@ 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_XBM,
.type = AVMEDIA_TYPE_VIDEO,
.name = "xbm",
+ .long_name = NULL_IF_CONFIG_SMALL("XBM (X BitMap) image"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
},
{
@@ -1215,6 +1255,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",
@@ -1222,6 +1269,117 @@ static const AVCodecDescriptor codec_descriptors[] = {
.props = AV_CODEC_PROP_LOSSY,
},
{
+ .id = AV_CODEC_ID_EXR,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "exr",
+ .long_name = NULL_IF_CONFIG_SMALL("OpenEXR image"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY |
+ AV_CODEC_PROP_LOSSLESS,
+ },
+ {
+ .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_SANM,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "sanm",
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts SMUSH video"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_PAF_VIDEO,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "paf_video",
+ .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File Video"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .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_BRENDER_PIX,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "brender_pix",
+ .long_name = NULL_IF_CONFIG_SMALL("BRender PIX image"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ },
+ {
+ .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",
@@ -1284,13 +1442,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,
@@ -1363,10 +1523,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,
},
{
@@ -1437,7 +1604,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,
@@ -1658,6 +1825,41 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA CRYO APC"),
.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,
+ },
/* AMR */
{
@@ -2151,6 +2353,38 @@ static const AVCodecDescriptor codec_descriptors[] = {
.props = AV_CODEC_PROP_LOSSY,
},
{
+ .id = AV_CODEC_ID_VIMA,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "vima",
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts VIMA audio"),
+ .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_PAF_AUDIO,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "paf_audio",
+ .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File Audio"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
.id = AV_CODEC_ID_OPUS,
.type = AVMEDIA_TYPE_AUDIO,
.name = "opus",
@@ -2178,6 +2412,20 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("Voxware MetaSound"),
.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,
+ },
/* subtitle codecs */
{
@@ -2185,42 +2433,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,
@@ -2232,8 +2494,126 @@ 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_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,
+ },
+ {
+ .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_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"),
+ },
+
};
const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id)
diff --git a/libavcodec/cook.c b/libavcodec/cook.c
index 190d28c..5b9f34a 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
*/
@@ -228,7 +228,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",
@@ -302,8 +302,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);
@@ -396,7 +396,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;
@@ -629,13 +629,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;
@@ -735,7 +739,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);
@@ -744,7 +748,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++)
@@ -752,11 +756,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
@@ -804,10 +815,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++) {
@@ -926,7 +937,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,
@@ -935,6 +946,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;
}
@@ -958,10 +970,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;
}
@@ -1045,7 +1055,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;
@@ -1079,6 +1089,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;
}
@@ -1186,11 +1201,20 @@ 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) {
diff --git a/libavcodec/cook_parser.c b/libavcodec/cook_parser.c
index f140e90..f17f56e 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
*/
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 ec465db..a73910d 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,28 @@
#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;
+ for(i=0; i<h; i++)
+ {
+ AV_COPY32U(dst, src);
+ dst+=dstStride;
+ src+=srcStride;
+ }
+}
+
static inline void copy_block8(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride, int h)
{
int i;
@@ -34,6 +56,17 @@ static inline void copy_block8(uint8_t *dst, const uint8_t *src, int dstStride,
}
}
+static inline void copy_block16(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride, int h)
+{
+ int i;
+ for(i=0; i<h; i++)
+ {
+ AV_COPY128U(dst, src);
+ dst+=dstStride;
+ src+=srcStride;
+ }
+}
+
static inline void copy_block9(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 9cf9cef..48b7b90 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..44226fb
--- a/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) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported subsample!\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ if (header[18] == YUVORDER_UYVY) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported YUV byte order!\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ if (header[29] == DECIMATION_ENAB) {
+ av_log(avctx, AV_LOG_ERROR, "Decimation unsupported!\n");
+ 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 enexpectedly!\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..94f8c85
--- a/dev/null
+++ b/libavcodec/crystalhd.c
@@ -0,0 +1,1223 @@
+/*
+ * - 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 <unistd.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"
+
+/** 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_free(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);
+ 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->pkt->pts,
+ avctx->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->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..c686123 100644
--- a/libavcodec/cyuv.c
+++ b/libavcodec/cyuv.c
@@ -6,20 +6,20 @@
*
* 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 308211f..1c1c080 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
*/
diff --git a/libavcodec/dca.h b/libavcodec/dca.h
index 0037de2..d60b282 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
*/
diff --git a/libavcodec/dca_parser.c b/libavcodec/dca_parser.c
index e233f50..9b73371 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;
diff --git a/libavcodec/dcadata.h b/libavcodec/dcadata.h
index 324e40f..15df49e 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
*/
@@ -7522,6 +7522,40 @@ static const float dca_downmix_coeffs[65] = {
0.001412537544623, 0.001000000000000, 0.000501187233627, 0.000251188643151, 0.000000000000000,
};
+static const float dca_downmix_scale_factors[241] = {
+ 0.001000, 0.001059, 0.001122, 0.001189, 0.001259, 0.001334, 0.001413, 0.001496,
+ 0.001585, 0.001679, 0.001778, 0.001884, 0.001995, 0.002113, 0.002239, 0.002371,
+ 0.002512, 0.002661, 0.002818, 0.002985, 0.003162, 0.003350, 0.003548, 0.003758,
+ 0.003981, 0.004217, 0.004467, 0.004732, 0.005012, 0.005309, 0.005623, 0.005957,
+ 0.006310, 0.006683, 0.007079, 0.007499, 0.007943, 0.008414, 0.008913, 0.009441,
+ 0.010000, 0.010593, 0.011220, 0.011885, 0.012589, 0.013335, 0.014125, 0.014962,
+ 0.015849, 0.016788, 0.017783, 0.018836, 0.019953, 0.021135, 0.022387, 0.023714,
+ 0.025119, 0.026607, 0.028184, 0.029854, 0.031623, 0.032546, 0.033497, 0.034475,
+ 0.035481, 0.036517, 0.037584, 0.038681, 0.039811, 0.040973, 0.042170, 0.043401,
+ 0.044668, 0.045973, 0.047315, 0.048697, 0.050119, 0.051582, 0.053088, 0.054639,
+ 0.056234, 0.057876, 0.059566, 0.061306, 0.063096, 0.064938, 0.066834, 0.068786,
+ 0.070795, 0.072862, 0.074989, 0.077179, 0.079433, 0.081752, 0.084140, 0.086596,
+ 0.089125, 0.091728, 0.094406, 0.097163, 0.100000, 0.102920, 0.105925, 0.109018,
+ 0.112202, 0.115478, 0.118850, 0.122321, 0.125893, 0.129569, 0.133352, 0.137246,
+ 0.141254, 0.145378, 0.149624, 0.153993, 0.158489, 0.163117, 0.167880, 0.172783,
+ 0.177828, 0.180406, 0.183021, 0.185674, 0.188365, 0.191095, 0.193865, 0.196675,
+ 0.199526, 0.202418, 0.205353, 0.208329, 0.211349, 0.214412, 0.217520, 0.220673,
+ 0.223872, 0.227117, 0.230409, 0.233749, 0.237137, 0.240575, 0.244062, 0.247600,
+ 0.251189, 0.254830, 0.258523, 0.262271, 0.266073, 0.269929, 0.273842, 0.277811,
+ 0.281838, 0.285924, 0.290068, 0.294273, 0.298538, 0.302866, 0.307256, 0.311709,
+ 0.316228, 0.320812, 0.325462, 0.330179, 0.334965, 0.339821, 0.344747, 0.349744,
+ 0.354813, 0.359956, 0.365174, 0.370467, 0.375837, 0.381285, 0.386812, 0.392419,
+ 0.398107, 0.403878, 0.409732, 0.415671, 0.421697, 0.427809, 0.434010, 0.440301,
+ 0.446684, 0.453158, 0.459727, 0.466391, 0.473151, 0.480010, 0.486968, 0.494026,
+ 0.501187, 0.508452, 0.515822, 0.523299, 0.530884, 0.538580, 0.546387, 0.554307,
+ 0.562341, 0.570493, 0.578762, 0.587151, 0.595662, 0.604296, 0.613056, 0.621942,
+ 0.630957, 0.640103, 0.649382, 0.658795, 0.668344, 0.678032, 0.687860, 0.697831,
+ 0.707107, 0.718208, 0.728618, 0.739180, 0.749894, 0.760764, 0.771792, 0.782979,
+ 0.794328, 0.805842, 0.817523, 0.829373, 0.841395, 0.853591, 0.865964, 0.878517,
+ 0.891251, 0.904170, 0.917276, 0.930572, 0.944061, 0.957745, 0.971628, 0.985712,
+ 1.000000
+};
+
static const uint8_t dca_default_coeffs[10][5][2] = {
{ { 13, 13 }, },
{ { 0, 64 }, { 64, 0 }, },
diff --git a/libavcodec/dcadec.c b/libavcodec/dcadec.c
index c80bd81..613e60b 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
*/
@@ -36,7 +36,6 @@
#include "avcodec.h"
#include "fft.h"
#include "get_bits.h"
-#include "put_bits.h"
#include "dcadata.h"
#include "dcahuff.h"
#include "dca.h"
@@ -53,12 +52,14 @@
//#define TRACE
#define DCA_PRIM_CHANNELS_MAX (7)
-#define DCA_SUBBANDS (32)
+#define DCA_SUBBANDS (64)
#define DCA_ABITS_MAX (32) /* Should be 28 */
#define DCA_SUBSUBFRAMES_MAX (4)
#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,
@@ -94,6 +95,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
@@ -375,6 +438,20 @@ typedef struct {
int xch_present; ///< XCh extension present and valid
int xch_base_channel; ///< index of first (only) channel containing XCH data
+ /* 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
@@ -461,16 +538,87 @@ 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 sign, mag, 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);
+ scale_factor =
+ 1.0f / dca_downmix_scale_factors[(get_bits(&s->gb, 6) - 1) << 2];
+
+ 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);
+ sign = (coeff & 64) ? 1.0 : -1.0;
+ mag = dca_downmix_scale_factors[((coeff & 63) - 1) << 2];
+ ichan = dca_xxch2index(s, 1 << i);
+ s->xxch_dmix_coeff[j][ichan] = sign * mag;
+ }
+ }
+ }
+ }
+ }
+
if (s->prim_channels > DCA_PRIM_CHANNELS_MAX)
s->prim_channels = DCA_PRIM_CHANNELS_MAX;
@@ -507,9 +655,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;
@@ -569,7 +724,7 @@ static int dca_parse_frame_header(DCAContext *s)
if (!s->bit_rate)
return AVERROR_INVALIDDATA;
- s->downmix = get_bits(&s->gb, 1);
+ s->downmix = get_bits(&s->gb, 1); /* note: this is FixedBit == 0 */
s->dynrange = get_bits(&s->gb, 1);
s->timestamp = get_bits(&s->gb, 1);
s->aux_data = get_bits(&s->gb, 1);
@@ -581,6 +736,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;
}
@@ -643,7 +799,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);
}
@@ -846,6 +1002,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]);
@@ -857,8 +1014,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;
@@ -1043,7 +1204,7 @@ static void dca_downmix(float **samples, int srcfmt,
case DCA_STEREO_TOTAL:
case DCA_STEREO_SUMDIFF:
case DCA_4F2R:
- av_log(NULL, 0, "Not implemented!\n");
+ av_log(NULL, AV_LOG_ERROR, "Not implemented!\n");
break;
case DCA_STEREO:
break;
@@ -1296,7 +1457,7 @@ static int dca_filter_channels(DCAContext *s, int block_index)
if (s->output & DCA_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],
1.0 / (256.0 * 32768.0));
/* Outputs 20bits pcm samples */
}
@@ -1421,11 +1582,11 @@ static int dca_exss_parse_asset_header(DCAContext *s)
{
int header_pos = get_bits_count(&s->gb);
int header_size;
- int channels;
+ int channels = 0;
int embedded_stereo = 0;
int embedded_6ch = 0;
int drc_code_present;
- int extensions_mask;
+ int av_uninit(extensions_mask);
int i, j;
if (get_bits_left(&s->gb) < 16)
@@ -1565,26 +1726,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);
@@ -1637,7 +2018,7 @@ static void dca_exss_parse_header(DCAContext *s)
}
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))
@@ -1646,6 +2027,33 @@ static void dca_exss_parse_header(DCAContext *s)
/* not parsed further, we were only interested in the extensions mask
* from the asset header */
+
+ if (num_assets > 0) {
+ 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);
+ }
+ }
}
/**
@@ -1658,15 +2066,25 @@ 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;
@@ -1707,7 +2125,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 */
@@ -1744,8 +2162,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))) {
@@ -1761,6 +2184,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: {
@@ -1800,49 +2224,136 @@ 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->xch_present && (!avctx->request_channels ||
- avctx->request_channels > num_core_channels + !!s->lfe)) {
- 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];
+ /* 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->xch_present && (!avctx->request_channels ||
+ avctx->request_channels
+ > num_core_channels + !!s->lfe)) {
+ 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 (avctx->request_channels == 2 && s->prim_channels > 2) {
+ channels = 2;
+ s->output = 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 {
+ av_log(avctx, AV_LOG_ERROR,
+ "Non standard configuration %d !\n", s->amode);
+ 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;
- 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];
+ 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];
+ }
+ }
+
+ /* 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];
+ }
}
- if (channels > !!s->lfe &&
- s->channel_order_tab[channels - 1 - !!s->lfe] < 0)
+ /* make sure that we have managed to get equivelant 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: Inconsistant 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;
+ }
+ }
+ }
- if (avctx->request_channels == 2 && s->prim_channels > 2) {
- channels = 2;
- s->output = DCA_STEREO;
- avctx->channel_layout = AV_CH_LAYOUT_STEREO;
+ 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 */
@@ -1886,6 +2397,53 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data,
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 */
diff --git a/libavcodec/dcadsp.c b/libavcodec/dcadsp.c
index 57d716e..abeba24 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 ec88be7..d86c1f3 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
*/
diff --git a/libavcodec/dcaenc.c b/libavcodec/dcaenc.c
new file mode 100644
index 0000000..cb73f42
--- a/dev/null
+++ b/libavcodec/dcaenc.c
@@ -0,0 +1,974 @@
+/*
+ * DCA encoder
+ * Copyright (C) 2008-2012 Alexander E. Patrakov
+ * 2010 Benjamin Larsson
+ * 2011 Xiang Wang
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/common.h"
+#include "avcodec.h"
+#include "dca.h"
+#include "dcadata.h"
+#include "dcaenc.h"
+#include "internal.h"
+#include "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 addres: 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..20f557b
--- a/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 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 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 254fc76..cbc8429 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 b7a27f0..be00c4b 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
*/
@@ -69,7 +69,7 @@ struct algo {
const char *name;
void (*func)(int16_t *block);
enum formattag { NO_PERM, MMX_PERM, MMX_SIMPLE_PERM, SCALE_PERM,
- SSE2_PERM, PARTTRANS_PERM } format;
+ SSE2_PERM, PARTTRANS_PERM, TRANSPOSE_PERM } format;
int mm_support;
int nonspec;
};
@@ -103,6 +103,23 @@ static const struct algo fdct_tab[] = {
{ 0 }
};
+#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);
+}
+#endif
+
static const struct algo idct_tab[] = {
{ "FAANI", ff_faanidct, NO_PERM },
{ "REF-DBL", ff_ref_idct, NO_PERM },
@@ -118,6 +135,9 @@ static const struct algo idct_tab[] = {
#endif
#if HAVE_SSE2_INLINE
{ "XVID-SSE2", ff_idct_xvid_sse2, SSE2_PERM, AV_CPU_FLAG_SSE2, 1 },
+#if ARCH_X86_64 && HAVE_YASM
+ { "PR-SSE2", ff_prores_idct_put_10_sse2_wrap, TRANSPOSE_PERM, AV_CPU_FLAG_SSE2, 1 },
+#endif
#endif
#if ARCH_BFIN
@@ -178,7 +198,7 @@ static void idct_mmx_init(void)
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;
@@ -187,7 +207,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++)
@@ -196,11 +216,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;
}
@@ -222,13 +244,16 @@ static void permute(int16_t dst[64], const int16_t src[64], int perm)
} else if (perm == PARTTRANS_PERM) {
for (i = 0; i < 64; i++)
dst[(i & 0x24) | ((i & 3) << 3) | ((i >> 3) & 3)] = src[i];
+ } else if (perm == TRANSPOSE_PERM) {
+ for (i = 0; i < 64; i++)
+ dst[(i>>3) | ((i<<3)&0x38)] = src[i];
} else {
for (i = 0; i < 64; i++)
dst[i] = src[i];
}
}
-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;
@@ -238,6 +263,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;
@@ -248,7 +274,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->format);
dct->func(block);
@@ -294,7 +320,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);
@@ -306,7 +332,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->format);
ti = av_gettime();
@@ -316,10 +343,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() - 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);
@@ -444,6 +471,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);
@@ -458,10 +504,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() - ti;
} while (ti1 < 1000000);
- emms_c();
printf("%s %s: %0.1f kdct/s\n", 1 ? "IDCT248" : "DCT248", name,
(double) it1 * 1000.0 / (double) ti1);
@@ -469,10 +515,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");
@@ -489,6 +536,7 @@ int main(int argc, char **argv)
int test = 1;
int speed = 0;
int err = 0;
+ int bits=8;
cpu_flags = av_get_cpu_flags();
@@ -518,8 +566,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);
@@ -527,7 +576,7 @@ int main(int argc, char **argv)
const struct algo *algos = test_idct ? idct_tab : fdct_tab;
for (i = 0; algos[i].name; i++)
if (!(~cpu_flags & algos[i].mm_support)) {
- err |= dct_error(&algos[i], test, test_idct, speed);
+ err |= dct_error(&algos[i], test, test_idct, speed, bits);
}
}
diff --git a/libavcodec/dct.c b/libavcodec/dct.c
index 4dbbff8..b1ee06a 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
*/
diff --git a/libavcodec/dct.h b/libavcodec/dct.h
index 3de10b9..a500521 100644
--- a/libavcodec/dct.h
+++ b/libavcodec/dct.h
@@ -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
*/
@@ -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_fdct_mmx(int16_t *block);
void ff_fdct_mmxext(int16_t *block);
diff --git a/libavcodec/dct32.c b/libavcodec/dct32.c
index 272e0db..fb53d53 100644
--- a/libavcodec/dct32.c
+++ b/libavcodec/dct32.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/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 7eb9dc1..1a5528d 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 727ec3c..70168f5 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/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 ab65fdc..b1be475 100644
--- a/libavcodec/dfa.c
+++ b/libavcodec/dfa.c
@@ -3,23 +3,24 @@
* 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
*/
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "bytestream.h"
#include "internal.h"
@@ -35,12 +36,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)
@@ -68,6 +70,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;
@@ -250,6 +254,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);
@@ -287,7 +294,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--) {
@@ -336,11 +343,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) {
@@ -353,7 +359,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) {
@@ -372,9 +378,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 e11fea7..e132acc 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"
@@ -31,7 +32,7 @@
#include "golomb.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 },
@@ -42,7 +43,6 @@ static const dirac_source_params dirac_source_parameters_defaults[] = {
{ 704, 576, 2, 0, 1, 10, 3, 704, 576, 0, 0, 1, 2 },
{ 720, 480, 1, 1, 0, 4, 2, 704, 480, 8, 0, 3, 1 },
{ 720, 576, 1, 1, 1, 3, 3, 704, 576, 8, 0, 3, 2 },
-
{ 1280, 720, 1, 0, 1, 7, 1, 1280, 720, 0, 0, 3, 3 },
{ 1280, 720, 1, 0, 1, 6, 1, 1280, 720, 0, 0, 3, 3 },
{ 1920, 1080, 1, 1, 1, 4, 1, 1920, 1080, 0, 0, 3, 3 },
@@ -51,7 +51,6 @@ static const dirac_source_params dirac_source_parameters_defaults[] = {
{ 1920, 1080, 1, 0, 1, 6, 1, 1920, 1080, 0, 0, 3, 3 },
{ 2048, 1080, 0, 0, 1, 2, 1, 2048, 1080, 0, 0, 4, 4 },
{ 4096, 2160, 0, 0, 1, 2, 1, 4096, 2160, 0, 0, 4, 4 },
-
{ 3840, 2160, 1, 0, 1, 7, 1, 3840, 2160, 0, 0, 3, 3 },
{ 3840, 2160, 1, 0, 1, 6, 1, 3840, 2160, 0, 0, 3, 3 },
{ 7680, 4320, 1, 0, 1, 7, 1, 3840, 2160, 0, 0, 3, 3 },
@@ -120,6 +119,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 */
@@ -134,7 +134,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;
@@ -145,14 +145,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) {
@@ -179,7 +179,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) {
@@ -191,7 +191,7 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
* aspect ratio values */
if (source->aspect_ratio_index > 0)
avctx->sample_aspect_ratio =
- dirac_preset_aspect_ratios[source->aspect_ratio_index-1];
+ dirac_preset_aspect_ratios[source->aspect_ratio_index-1];
/* [DIRAC_STD] 10.3.7 Clean area. clean_area(video_params) */
if (get_bits1(gb)) { /* [DIRAC_STD] custom_clean_area_flag */
@@ -212,10 +212,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;
@@ -233,16 +233,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 a integer multiply 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;
@@ -253,7 +259,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 */
@@ -300,10 +306,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
@@ -320,7 +326,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
--- a/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..f9a8bba
--- a/dev/null
+++ b/libavcodec/dirac_arith.h
@@ -0,0 +1,190 @@
+/*
+ * 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 "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
+ 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)) {
+ 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..bbd8ec7
--- a/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 "dsputil.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;
+ 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..25c13d1
--- a/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 optimiztions
+#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 46f5430..a2a22ee 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
*/
@@ -161,7 +161,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;
diff --git a/libavcodec/diracdec.c b/libavcodec/diracdec.c
new file mode 100644
index 0000000..15baf75
--- a/dev/null
+++ b/libavcodec/diracdec.c
@@ -0,0 +1,1939 @@
+/*
+ * 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 "dsputil.h"
+#include "get_bits.h"
+#include "bytestream.h"
+#include "internal.h"
+#include "golomb.h"
+#include "dirac_arith.h"
+#include "mpeg12data.h"
+#include "dirac_dwt.h"
+#include "dirac.h"
+#include "diracdsp.h"
+#include "videodsp.h" // for ff_emulated_edge_mc_8
+
+/**
+ * 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 ff_emulated_edge_mc ff_emulated_edge_mc_8 /* Fix: change the calls to this function regarding bit depth */
+
+#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;
+ DSPContext dsp;
+ 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 multipled by OBMC weights */
+ uint8_t *mcscratch;
+
+ 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
+};
+
+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((w+max_xblen)*h * sizeof(IDWTELEM));
+ s->plane[i].idwt_tmp = av_malloc((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);
+ }
+
+ w = s->source.width;
+ h = s->source.height;
+
+ /* fixme: allocate using real stride here */
+ s->sbsplit = av_malloc(sbwidth * sbheight);
+ s->blmotion = av_malloc(sbwidth * sbheight * 16 * sizeof(*s->blmotion));
+ s->edge_emu_buffer_base = av_malloc((w+64)*MAX_BLOCKSIZE);
+
+ s->mctmp = av_malloc((w+64+MAX_BLOCKSIZE) * (h+MAX_BLOCKSIZE) * sizeof(*s->mctmp));
+ s->mcscratch = av_malloc((w+64)*MAX_BLOCKSIZE);
+
+ if (!s->sbsplit || !s->blmotion || !s->mctmp || !s->mcscratch)
+ return AVERROR(ENOMEM);
+ 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);
+ }
+
+ 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;
+ s->avctx = avctx;
+ s->frame_number = -1;
+
+ if (avctx->flags&CODEC_FLAG_EMU_EDGE) {
+ av_log(avctx, AV_LOG_ERROR, "Edge emulation not supported!\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ ff_dsputil_init(&s->dsp, avctx);
+ ff_diracdsp_init(&s->diracdsp);
+
+ 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)
+{
+ dirac_decode_flush(avctx);
+ 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+1)) / cb_height;
+ left = 0;
+ for (cb_x = 0; cb_x < cb_width; cb_x++) {
+ right = (b->width * (cb_x+1)) / 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 explictly
+ 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(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, "codeblock width invalid\n")
+ CHECKEDREAD(s->codeblock[i].height, tmp < 1, "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 & ~(-1 << s->mv_precision);
+ my = motion_y & ~(-1 << 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++) {
+ ff_emulated_edge_mc(s->edge_emu_buffer[i], p->stride,
+ src[i], 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->dsp.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->dsp.draw_edges(ref->hpel[plane][1], ref->avframe.linesize[plane], width, height, edge, edge, EDGE_TOP | EDGE_BOTTOM);
+ s->dsp.draw_edges(ref->hpel[plane][2], ref->avframe.linesize[plane], width, height, edge, edge, EDGE_TOP | EDGE_BOTTOM);
+ s->dsp.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;
+}
+
+/**
+ * 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];
+ ff_get_buffer(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;
+ }
+
+ avcodec_get_frame_defaults(&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 = ff_get_buffer(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];
+
+ /* [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;
+ DiracFrame *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");
+ delayed_frame = s->delay_frames[0];
+
+ 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->avframe.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..429241d
--- a/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 "dsputil.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
--- a/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 d981079..6e030e4 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 96895da..669b806 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[] = {
@@ -285,63 +287,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] = {
@@ -434,63 +416,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] = {
@@ -583,63 +545,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] = {
@@ -710,61 +652,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,
@@ -854,63 +777,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] = {
@@ -1003,136 +906,126 @@ 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 } },
+ { 36, 36, 45, 75, 90 },
+ { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } },
};
int ff_dnxhd_get_cid_table(int cid)
@@ -1144,6 +1037,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;
@@ -1155,7 +1056,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;
}
@@ -1163,3 +1064,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..b8bcb21 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
+ AVRational frame_rates[5];
} CIDEntry;
-extern const CIDEntry ff_dnxhd_cid_table[];
+extern av_export 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 f7b8a22..15e6c67 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
*/
@@ -28,11 +28,12 @@
#include "dnxhddata.h"
#include "dsputil.h"
#include "internal.h"
+#include "thread.h"
typedef struct DNXHDContext {
AVCodecContext *avctx;
GetBitContext gb;
- int cid; ///< compression id
+ int64_t cid; ///< compression id
unsigned int width, height;
unsigned int mb_width, mb_height;
uint32_t mb_scan_index[68]; /* max for 1080p */
@@ -46,6 +47,9 @@ typedef struct DNXHDContext {
int bit_depth; // 8, 10 or 0 if not initialized at all.
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
@@ -59,10 +63,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;
@@ -71,6 +76,10 @@ static int dnxhd_init_vlc(DNXHDContext *ctx, int cid)
av_log(ctx->avctx, AV_LOG_ERROR, "unsupported cid %d\n", cid);
return -1;
}
+ 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);
@@ -164,7 +173,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 -1;
}
@@ -180,16 +189,22 @@ 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 (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;
}
@@ -204,41 +219,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);
@@ -268,6 +289,14 @@ static int dnxhd_decode_macroblock(DNXHDContext *ctx, AVFrame *frame, int x, int
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->dsp.clear_block(ctx->blocks[i]);
ctx->decode_dct_block(ctx, ctx->blocks[i], i, qscale);
@@ -330,6 +359,7 @@ static int dnxhd_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
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;
@@ -352,10 +382,8 @@ static int dnxhd_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
avcodec_set_dimensions(avctx, ctx->width, ctx->height);
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;
}
@@ -370,7 +398,7 @@ static int dnxhd_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
}
*got_frame = 1;
- return buf_size;
+ return avpkt->size;
}
static av_cold int dnxhd_decode_close(AVCodecContext *avctx)
@@ -392,5 +420,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 d71186d..5cf6d8b 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
*/
@@ -41,11 +41,17 @@ static const AVOption options[]={
{"nitris_compat", "encode with Avid Nitris compatibility", offsetof(DNXHDEncContext, nitris_compat), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, VE},
{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,
+};
#define LAMBDA_FRAC_BITS 10
-static void dnxhd_8bit_get_pixels_8x4_sym(int16_t *restrict block, const uint8_t *pixels, int line_size)
+static void dnxhd_8bit_get_pixels_8x4_sym(int16_t *av_restrict block, const uint8_t *pixels, int line_size)
{
int i;
for (i = 0; i < 4; i++) {
@@ -62,23 +68,31 @@ static void dnxhd_8bit_get_pixels_8x4_sym(int16_t *restrict block, const uint8_t
memcpy(block + 24, block - 32, sizeof(*block) * 8);
}
-static av_always_inline void dnxhd_10bit_get_pixels_8x4_sym(int16_t *restrict block, const uint8_t *pixels, int line_size)
+static av_always_inline void dnxhd_10bit_get_pixels_8x4_sym(int16_t *av_restrict block, const uint8_t *pixels, int 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;
@@ -123,10 +137,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);
ctx->vlc_bits [index] = ctx->cid_table->ac_bits[j]+1;
@@ -137,7 +151,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;
ctx->vlc_bits [index]+= ctx->cid_table->index_bits;
@@ -146,7 +160,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];
}
@@ -209,6 +223,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 -1;
@@ -247,12 +266,14 @@ 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");
+ av_log(avctx, AV_LOG_ERROR, "video parameters incompatible with DNxHD. Valid DNxHD profiles:\n");
+ ff_dnxhd_print_profiles(avctx, AV_LOG_ERROR);
return -1;
}
av_log(avctx, AV_LOG_DEBUG, "cid %d\n", ctx->cid);
index = ff_dnxhd_get_cid_table(ctx->cid);
+ av_assert0(index >= 0);
ctx->cid_table = &ff_dnxhd_cid_table[index];
ctx->m.avctx = avctx;
@@ -261,8 +282,9 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx)
avctx->bits_per_raw_sample = ctx->cid_table->bit_depth;
- ff_dsputil_init(&ctx->m.dsp, avctx);
ff_dct_common_init(&ctx->m);
+ ff_dct_encode_init(&ctx->m);
+
if (!ctx->m.dct_quantize)
ctx->m.dct_quantize = ff_dct_quantize_c;
@@ -330,7 +352,7 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx)
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);
@@ -497,15 +519,8 @@ static av_always_inline void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, in
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, int jobnr, int threadnr)
@@ -535,14 +550,14 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, int jobnr, i
int n = dnxhd_switch_matrix(ctx, i);
memcpy(block, src_block, 64*sizeof(*block));
- last_index = ctx->m.dct_quantize(&ctx->m, block, i, qscale, &overflow);
+ last_index = ctx->m.dct_quantize(&ctx->m, block, 4&(2*i), qscale, &overflow);
ac_bits += dnxhd_calc_ac_bits(ctx, block, last_index);
diff = block[0] - ctx->m.last_dc[n];
if (diff < 0) nbits = av_log2_16bit(-2*diff);
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];
@@ -581,8 +596,7 @@ static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg, int jobnr, int
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,
- qscale, &overflow);
+ 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);
//STOP_TIMER("encode_block");
@@ -832,13 +846,13 @@ static void radix_count(const RCCMPEntry *data, int size, int buckets[RADIX_PASS
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]);
}
}
@@ -932,10 +946,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);
@@ -965,12 +977,12 @@ static int dnxhd_encode_picture(AVCodecContext *avctx, AVPacket *pkt,
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);
AV_WB32(buf + ctx->cid_table->coding_unit_size - 4, 0x600DC0DE); // EOF
@@ -1018,6 +1030,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"),
@@ -1031,5 +1048,6 @@ AVCodec ff_dnxhd_encoder = {
.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV422P,
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 fed17be..9b59b96 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..0c0bcca 100644
--- a/libavcodec/dpcm.c
+++ b/libavcodec/dpcm.c
@@ -2,20 +2,20 @@
* Assorted DPCM codecs
* 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 da7457d..8468720 100644
--- a/libavcodec/dpx.c
+++ b/libavcodec/dpx.c
@@ -2,20 +2,20 @@
* 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
*/
@@ -25,6 +25,18 @@
#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 +49,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 +70,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, i, ret;
+ int w, h, bits_per_color, descriptor, elements, packing, total_size;
+ int encoding;
- 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");
@@ -91,6 +111,11 @@ static int decode_frame(AVCodecContext *avctx,
buf = avpkt->data + 0x304;
w = read32(&buf, endian);
h = read32(&buf, endian);
+ if ((ret = av_image_check_size(w, h, 0, avctx)) < 0)
+ return ret;
+
+ if (w != avctx->width || h != avctx->height)
+ avcodec_set_dimensions(avctx, w, h);
// Need to end in 0x320 to read the descriptor
buf += 20;
@@ -100,107 +125,190 @@ static int decode_frame(AVCodecContext *avctx,
buf += 3;
avctx->bits_per_raw_sample =
bits_per_color = buf[0];
+ buf++;
+ packing = read16(&buf, endian);
+ encoding = read16(&buf, endian);
+
+ if (packing > 1) {
+ avpriv_report_missing_feature(avctx, "Packing %d", packing);
+ return AVERROR_PATCHWELCOME;
+ }
+ if (encoding) {
+ avpriv_report_missing_feature(avctx, "Encoding %d", encoding);
+ return AVERROR_PATCHWELCOME;
+ }
- buf += 825;
+ buf += 820;
avctx->sample_aspect_ratio.num = read32(&buf, endian);
avctx->sample_aspect_ratio.den = read32(&buf, endian);
+ if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0)
+ av_reduce(&avctx->sample_aspect_ratio.num, &avctx->sample_aspect_ratio.den,
+ avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den,
+ 0x10000);
+ else
+ avctx->sample_aspect_ratio = (AVRational){ 0, 1 };
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);
- return AVERROR_INVALIDDATA;
+ case 8:
+ total_size = avctx->width * avctx->height * elements;
+ break;
+ case 10:
+ if (!packing) {
+ av_log(avctx, AV_LOG_ERROR, "Packing to 32bit required\n");
+ return -1;
+ }
+ total_size = (avctx->width * elements + 2) / 3 * 4 * avctx->height;
+ break;
+ case 12:
+ if (!packing) {
+ av_log(avctx, AV_LOG_ERROR, "Packing to 16bit required\n");
+ return -1;
+ }
+ total_size = 2 * avctx->width * avctx->height * elements;
+ break;
+ case 16:
+ total_size = 2 * avctx->width * avctx->height * 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;
}
- if ((ret = av_image_check_size(w, h, 0, avctx)) < 0)
- return ret;
- if (w != avctx->width || h != avctx->height)
- avcodec_set_dimensions(avctx, w, h);
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- 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;
}
+ 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) {
+ if (total_size + (int64_t)offset > avpkt->size) {
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;
}
- 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, elements * avctx->width,
+ elements * avctx->width, avctx->height);
+ break;
}
*got_frame = 1;
@@ -210,7 +318,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..70baaf4
--- a/dev/null
+++ b/libavcodec/dpx_parser.c
@@ -0,0 +1,108 @@
+/*
+ * 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)
+ return 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');
+ 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;
+ next = i;
+ }
+ }
+
+ for (;d->pc.frame_start_found && i < buf_size; i++) {
+ d->pc.state = (d->pc.state << 8) | buf[i];
+ if (d->index == 16) {
+ d->fsize = d->is_be ? d->pc.state : av_bswap32(d->pc.state);
+ if (d->fsize <= 1664) {
+ d->index = d->pc.frame_start_found = 0;
+ goto flush;
+ }
+ d->index = 0;
+ if (d->fsize > buf_size - i + 19)
+ d->remaining_size = d->fsize - buf_size + i - 19;
+ else
+ next = d->fsize + i - 19;
+ break;
+ }
+ d->index++;
+ }
+
+flush:
+ if (ff_combine_frame(&d->pc, next, &buf, &buf_size) < 0)
+ return buf_size;
+
+ d->index = 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 83a70a6..0eb1297 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
*/
@@ -26,34 +26,44 @@
#include "internal.h"
typedef struct DPXContext {
- AVFrame picture;
int big_endian;
int bits_per_component;
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 = &s->picture;
- 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->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;
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");
@@ -75,8 +85,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];
@@ -85,14 +94,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;
@@ -101,6 +110,59 @@ 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;
+ 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 < 3; i++)
+ src[i] += pic->linesize[i]/2;
+ }
+}
+
static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *frame, int *got_packet)
{
@@ -113,10 +175,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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");
+ if ((ret = ff_alloc_packet2(avctx, pkt, size + HEADER_SIZE)) < 0)
return ret;
- }
buf = pkt->data;
memset(buf, 0, HEADER_SIZE);
@@ -140,13 +200,15 @@ 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,
@@ -156,7 +218,13 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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);
@@ -174,17 +242,20 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
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,
- .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/dsicinav.c b/libavcodec/dsicinav.c
index 4d157b4..14bba55 100644
--- a/libavcodec/dsicinav.c
+++ b/libavcodec/dsicinav.c
@@ -2,20 +2,20 @@
* Delphine Software International CIN Audio/Video Decoders
* 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
*/
@@ -87,11 +87,33 @@ static const int16_t cinaudio_delta16_table[256] = {
0, 0, 0, 0, 0, 0, 0, 0
};
+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;
@@ -99,11 +121,8 @@ static av_cold int cinvideo_decode_init(AVCodecContext *avctx)
avcodec_get_frame_defaults(&cin->frame);
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;
}
@@ -185,27 +204,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,
@@ -232,19 +254,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) {
@@ -259,7 +279,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);
@@ -295,11 +315,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;
@@ -322,12 +339,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_unref(&cin->frame);
- for (i = 0; i < 3; ++i)
- av_free(cin->bitmap_table[i]);
+ destroy_buffers(cin);
return 0;
}
@@ -357,10 +372,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/dsputil.c b/libavcodec/dsputil.c
index 6d93706..17de1d4 100644
--- a/libavcodec/dsputil.c
+++ b/libavcodec/dsputil.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
*/
@@ -41,6 +41,7 @@
#include "mathops.h"
#include "mpegvideo.h"
#include "config.h"
+#include "diracdsp.h"
uint32_t ff_squareTbl[512] = {0, };
@@ -327,7 +328,7 @@ static int sse16_c(void *v, uint8_t *pix1, uint8_t *pix2, int line_size, int h)
return s;
}
-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;
@@ -347,8 +348,7 @@ static void diff_pixels_c(int16_t *restrict block, const uint8_t *s1,
}
}
-
-static void put_pixels_clamped_c(const int16_t *block, uint8_t *restrict pixels,
+static void put_pixels_clamped_c(const int16_t *block, uint8_t *av_restrict pixels,
int line_size)
{
int i;
@@ -369,8 +369,40 @@ 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,
+ uint8_t *av_restrict pixels,
int line_size)
{
int i, j;
@@ -390,7 +422,7 @@ static void put_signed_pixels_clamped_c(const int16_t *block,
}
}
-static void add_pixels8_c(uint8_t *restrict pixels,
+static void add_pixels8_c(uint8_t *av_restrict pixels,
int16_t *block,
int line_size)
{
@@ -410,7 +442,7 @@ static void add_pixels8_c(uint8_t *restrict pixels,
}
}
-static void add_pixels_clamped_c(const int16_t *block, uint8_t *restrict pixels,
+static void add_pixels_clamped_c(const int16_t *block, uint8_t *av_restrict pixels,
int line_size)
{
int i;
@@ -430,6 +462,36 @@ 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 int sum_abs_dctelem_c(int16_t *block)
{
int sum=0, i;
@@ -1329,6 +1391,51 @@ void ff_avg_rv40_qpel8_mc33_c(uint8_t *dst, uint8_t *src, ptrdiff_t stride)
}
#endif /* CONFIG_RV40_DECODER */
+#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
+
static void wmv2_mspel8_v_lowpass(uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int w){
const uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
int i;
@@ -1743,7 +1850,7 @@ static int try_8x8basis_c(int16_t rem[64], int16_t weight[64], int16_t basis[64]
int b= rem[i] + ((basis[i]*scale + (1<<(BASIS_SHIFT - RECON_SHIFT-1)))>>(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;
}
@@ -1808,6 +1915,14 @@ void ff_set_cmp(DSPContext* 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");
}
@@ -1816,7 +1931,7 @@ void ff_set_cmp(DSPContext* c, me_cmp_func *cmp, int type){
static void add_bytes_c(uint8_t *dst, uint8_t *src, int w){
long i;
- for(i=0; i<=w-sizeof(long); i+=sizeof(long)){
+ for(i=0; i<=w-(int)sizeof(long); i+=sizeof(long)){
long a = *(long*)(src+i);
long b = *(long*)(dst+i);
*(long*)(dst+i) = ((a&pb_7f) + (b&pb_7f)) ^ ((a^b)&pb_80);
@@ -1825,7 +1940,7 @@ static void add_bytes_c(uint8_t *dst, uint8_t *src, int w){
dst[i+0] += src[i+0];
}
-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)){
@@ -1841,7 +1956,7 @@ static void diff_bytes_c(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w){
}
}else
#endif
- for(i=0; i<=w-sizeof(long); i+=sizeof(long)){
+ for(i=0; i<=w-(int)sizeof(long); i+=sizeof(long)){
long a = *(long*)(src1+i);
long b = *(long*)(src2+i);
*(long*)(dst+i) = ((a|pb_80) - (b&pb_7f)) ^ ((a^b^pb_80)&pb_80);
@@ -1965,7 +2080,7 @@ static int hadamard8_diff8x8_c(/*MpegEncContext*/ void *s, uint8_t *dst, uint8_t
int temp[64];
int sum=0;
- assert(h==8);
+ av_assert2(h==8);
for(i=0; i<8; i++){
//FIXME try pointer walks
@@ -2010,7 +2125,7 @@ static int hadamard8_intra8x8_c(/*MpegEncContext*/ void *s, uint8_t *src, uint8_
int temp[64];
int sum=0;
- assert(h==8);
+ av_assert2(h==8);
for(i=0; i<8; i++){
//FIXME try pointer walks
@@ -2057,7 +2172,7 @@ static int dct_sad8x8_c(/*MpegEncContext*/ void *c, uint8_t *src1, uint8_t *src2
MpegEncContext * const s= (MpegEncContext *)c;
LOCAL_ALIGNED_16(int16_t, temp, [64]);
- assert(h==8);
+ av_assert2(h==8);
s->dsp.diff_pixels(temp, src1, src2, stride);
s->dsp.fdct(temp);
@@ -2122,7 +2237,7 @@ static int dct_max8x8_c(/*MpegEncContext*/ void *c, uint8_t *src1, uint8_t *src2
LOCAL_ALIGNED_16(int16_t, temp, [64]);
int sum=0, i;
- assert(h==8);
+ av_assert2(h==8);
s->dsp.diff_pixels(temp, src1, src2, stride);
s->dsp.fdct(temp);
@@ -2139,7 +2254,7 @@ static int quant_psnr8x8_c(/*MpegEncContext*/ void *c, uint8_t *src1, uint8_t *s
int16_t * const bak = temp+64;
int sum=0, i;
- assert(h==8);
+ av_assert2(h==8);
s->mb_intra=0;
s->dsp.diff_pixels(temp, src1, src2, stride);
@@ -2167,7 +2282,7 @@ static int rd8x8_c(/*MpegEncContext*/ void *c, uint8_t *src1, uint8_t *src2, int
uint8_t * length;
uint8_t * last_length;
- assert(h==8);
+ av_assert2(h==8);
copy_block8(lsrc1, src1, 8, stride, 8);
copy_block8(lsrc2, src2, 8, stride, 8);
@@ -2209,7 +2324,7 @@ static int rd8x8_c(/*MpegEncContext*/ void *c, uint8_t *src1, uint8_t *src2, int
level= temp[i] + 64;
- assert(level - 64);
+ av_assert2(level - 64);
if((level&(~127)) == 0){
bits+= last_length[UNI_AC_ENC_INDEX(run, level)];
@@ -2241,7 +2356,7 @@ static int bit8x8_c(/*MpegEncContext*/ void *c, uint8_t *src1, uint8_t *src2, in
uint8_t * length;
uint8_t * last_length;
- assert(h==8);
+ av_assert2(h==8);
s->dsp.diff_pixels(temp, src1, src2, stride);
@@ -2280,7 +2395,7 @@ static int bit8x8_c(/*MpegEncContext*/ void *c, uint8_t *src1, uint8_t *src2, in
level= temp[i] + 64;
- assert(level - 64);
+ av_assert2(level - 64);
if((level&(~127)) == 0){
bits+= last_length[UNI_AC_ENC_INDEX(run, level)];
@@ -2497,6 +2612,37 @@ static void jref_idct_add(uint8_t *dest, int line_size, int16_t *block)
add_pixels_clamped_c(block, dest, line_size);
}
+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));
+}
+
/* init static data */
av_cold void ff_dsputil_static_init(void)
{
@@ -2520,7 +2666,7 @@ int ff_check_alignment(void){
"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 Libav developers.\n");
+ "Do not report crashes to FFmpeg developers.\n");
#endif
did_fail=1;
}
@@ -2553,12 +2699,33 @@ av_cold void ff_dsputil_init(DSPContext* c, AVCodecContext *avctx)
}
#endif //CONFIG_ENCODERS
- 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->idct_permutation_type = FF_NO_IDCT_PERM;
- } else {
+ 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->idct_permutation_type= FF_NO_IDCT_PERM;
+ }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->idct_permutation_type= FF_NO_IDCT_PERM;
+ }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->idct_permutation_type= FF_NO_IDCT_PERM;
+ }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->idct_permutation_type = FF_NO_IDCT_PERM;
+ } 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->idct_permutation_type = FF_NO_IDCT_PERM;
+ } else {
if(avctx->idct_algo==FF_IDCT_INT){
c->idct_put= jref_idct_put;
c->idct_add= jref_idct_add;
@@ -2575,6 +2742,7 @@ av_cold void ff_dsputil_init(DSPContext* c, AVCodecContext *avctx)
c->idct = ff_simple_idct_8;
c->idct_permutation_type= FF_NO_IDCT_PERM;
}
+ }
}
c->diff_pixels = diff_pixels_c;
@@ -2689,6 +2857,9 @@ av_cold void ff_dsputil_init(DSPContext* c, AVCodecContext *avctx)
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
c->ssd_int8_vs_int16 = ssd_int8_vs_int16_c;
@@ -2737,10 +2908,14 @@ av_cold void ff_dsputil_init(DSPContext* c, AVCodecContext *avctx)
switch (avctx->bits_per_raw_sample) {
case 9:
case 10:
+ case 12:
+ case 14:
BIT_DEPTH_FUNCS(16);
break;
default:
- BIT_DEPTH_FUNCS(8);
+ if(avctx->bits_per_raw_sample<=8 || avctx->codec_type != AVMEDIA_TYPE_VIDEO) {
+ BIT_DEPTH_FUNCS(8);
+ }
break;
}
@@ -2763,3 +2938,13 @@ av_cold void ff_dsputil_init(DSPContext* c, AVCodecContext *avctx)
ff_init_scantable_permutation(c->idct_permutation,
c->idct_permutation_type);
}
+
+av_cold void dsputil_init(DSPContext* c, AVCodecContext *avctx)
+{
+ ff_dsputil_init(c, avctx);
+}
+
+av_cold void avpriv_dsputil_init(DSPContext *c, AVCodecContext *avctx)
+{
+ ff_dsputil_init(c, avctx);
+}
diff --git a/libavcodec/dsputil.h b/libavcodec/dsputil.h
index c248b9f..b9f8bde 100644
--- a/libavcodec/dsputil.h
+++ b/libavcodec/dsputil.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
*/
@@ -64,7 +64,7 @@ void ff_gmc_c(uint8_t *dst, uint8_t *src, int stride, int h, int ox, int oy,
/* 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 libav-devel mailing list, ...
+to the ffmpeg-devel mailing list, ...
!warning These alignments might not match reality, (missing attribute((align))
stuff somewhere possible).
@@ -155,6 +155,8 @@ typedef struct DSPContext {
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];
@@ -190,7 +192,7 @@ typedef struct DSPContext {
/* huffyuv specific */
void (*add_bytes)(uint8_t *dst/*align 16*/, uint8_t *src/*align 16*/, int w);
- void (*diff_bytes)(uint8_t *dst/*align 16*/, uint8_t *src1/*align 16*/, uint8_t *src2/*align 1*/,int w);
+ void (*diff_bytes)(uint8_t *dst/*align 16*/, const uint8_t *src1/*align 16*/, const uint8_t *src2/*align 1*/,int w);
/**
* subtract huffyuv's variant of median prediction
* note, this might read from src1[-1], src2[-1]
@@ -199,6 +201,7 @@ typedef struct DSPContext {
void (*add_hfyu_median_prediction)(uint8_t *dst, const uint8_t *top, const uint8_t *diff, int w, int *left, int *left_top);
int (*add_hfyu_left_prediction)(uint8_t *dst, const uint8_t *src, int w, int left);
void (*add_hfyu_left_prediction_bgr32)(uint8_t *dst, const uint8_t *src, int w, int *red, int *green, int *blue, int *alpha);
+ /* this might write to dst[w] */
void (*bswap_buf)(uint32_t *dst, const uint32_t *src, int w);
void (*bswap16_buf)(uint16_t *dst, const uint16_t *src, int len);
@@ -309,6 +312,8 @@ typedef struct DSPContext {
void ff_dsputil_static_init(void);
void ff_dsputil_init(DSPContext* p, AVCodecContext *avctx);
+void avpriv_dsputil_init(DSPContext* p, AVCodecContext *avctx);
+attribute_deprecated void dsputil_init(DSPContext* c, AVCodecContext *avctx);
int ff_check_alignment(void);
@@ -322,4 +327,6 @@ void ff_dsputil_init_sh4(DSPContext* c, AVCodecContext *avctx);
void ff_dsputil_init_vis(DSPContext* c, AVCodecContext *avctx);
void ff_dsputil_init_x86(DSPContext* c, AVCodecContext *avctx);
+void ff_dsputil_init_dwt(DSPContext *c);
+
#endif /* AVCODEC_DSPUTIL_H */
diff --git a/libavcodec/dsputil_template.c b/libavcodec/dsputil_template.c
index 3a6d27f..96be7a6 100644
--- a/libavcodec/dsputil_template.c
+++ b/libavcodec/dsputil_template.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
*/
@@ -32,10 +32,10 @@
#if BIT_DEPTH == 8
/* draw the edges of width 'w' of an image of size width, height */
//FIXME check that this is ok for mpeg4 interlaced
-static void FUNCC(draw_edges)(uint8_t *_buf, int _wrap, int width, int height, int w, int h, int sides)
+static void FUNCC(draw_edges)(uint8_t *p_buf, int p_wrap, int width, int height, int w, int h, int sides)
{
- pixel *buf = (pixel*)_buf;
- int wrap = _wrap / sizeof(pixel);
+ pixel *buf = (pixel*)p_buf;
+ int wrap = p_wrap / sizeof(pixel);
pixel *ptr, *last_line;
int i;
@@ -59,7 +59,7 @@ static void FUNCC(draw_edges)(uint8_t *_buf, int _wrap, int width, int height, i
}
#endif
-static void FUNCC(get_pixels)(int16_t *restrict block,
+static void FUNCC(get_pixels)(int16_t *av_restrict block,
const uint8_t *_pixels,
int line_size)
{
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 0e76944..ba07c71 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
*/
@@ -275,7 +275,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 == 1184);
for (i = 0; i < dv_vlc.table_size; i++){
int code = dv_vlc.table[i][0];
@@ -297,6 +297,7 @@ av_cold int ff_dvvideo_init(AVCodecContext *avctx)
}
/* Generic DSP setup */
+ memset(&dsp,0, sizeof(dsp));
ff_dsputil_init(&dsp, avctx);
ff_set_cmp(&dsp, dsp.ildct_cmp, avctx->ildct_cmp);
s->get_pixels = dsp.get_pixels;
@@ -311,7 +312,13 @@ av_cold int ff_dvvideo_init(AVCodecContext *avctx)
/* 248DCT setup */
s->fdct[1] = dsp.fdct248;
s->idct_put[1] = ff_simple_idct248_put; // FIXME: need to add it to DSP
- memcpy(s->dv_zigzag[1], ff_zigzag248_direct, 64);
+ if (avctx->lowres){
+ for (i = 0; i < 64; i++){
+ int j = ff_zigzag248_direct[i];
+ s->dv_zigzag[1][i] = dsp.idct_permutation[(j & 7) + (j & 8) * 4 + (j & 48) / 2];
+ }
+ }else
+ memcpy(s->dv_zigzag[1], ff_zigzag248_direct, 64);
avcodec_get_frame_defaults(&s->picture);
avctx->coded_frame = &s->picture;
@@ -330,6 +337,10 @@ static av_cold int dvvideo_init_encoder(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;
+ }
dv_vlc_map_tableinit();
@@ -497,7 +508,7 @@ static av_always_inline int dv_init_enc_block(EncBlockInfo* bi, uint8_t *data, i
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
@@ -505,13 +516,13 @@ static av_always_inline int dv_init_enc_block(EncBlockInfo* bi, uint8_t *data, i
#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] = bi->area_q[2] = bi->area_q[3] = 0;
bi->partial_bit_count = 0;
@@ -540,7 +551,7 @@ static av_always_inline int dv_init_enc_block(EncBlockInfo* bi, uint8_t *data, i
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))) >> (dv_weight_bits+4);
@@ -602,7 +613,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]) {
@@ -612,11 +623,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];
@@ -803,6 +814,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->picture.top_field_first ? 0x00 : 0x40;
uint8_t aspect = 0;
if ((int)(av_q2d(c->avctx->sample_aspect_ratio) * c->avctx->width / c->avctx->height * 10) >= 17) /* 16:9 */
@@ -841,7 +853,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 */
@@ -948,10 +960,8 @@ static int dvvideo_encode_frame(AVCodecContext *c, AVPacket *pkt,
s->sys = avpriv_dv_codec_profile(c);
if (!s->sys || ff_dv_init_dynamic_tables(s->sys))
return -1;
- 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->picture = *frame;
diff --git a/libavcodec/dv_profile.c b/libavcodec/dv_profile.c
index be392bb..e73af29 100644
--- a/libavcodec/dv_profile.c
+++ b/libavcodec/dv_profile.c
@@ -1,24 +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 <stdint.h>
#include "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "libavutil/pixdesc.h"
#include "avcodec.h"
@@ -280,22 +281,30 @@ static const DVprofile dv_profiles[] = {
}
};
-const DVprofile* avpriv_dv_frame_profile(const DVprofile *sys,
+const DVprofile* avpriv_dv_frame_profile2(AVCodecContext* codec, const DVprofile *sys,
const uint8_t* frame, unsigned buf_size)
{
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];
@@ -304,17 +313,36 @@ const DVprofile* avpriv_dv_frame_profile(const DVprofile *sys,
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];
+
return NULL;
}
+const DVprofile* avpriv_dv_frame_profile(const DVprofile *sys,
+ const uint8_t* frame, unsigned buf_size)
+{
+ return avpriv_dv_frame_profile2(NULL, sys, frame, buf_size);
+}
+
const DVprofile* avpriv_dv_codec_profile(AVCodecContext* codec)
{
int i;
+ int w, h;
+
+ if (codec->coded_width || codec->coded_height) {
+ w = codec->coded_width;
+ h = codec->coded_height;
+ } else {
+ w = codec->width;
+ h = codec->height;
+ }
for (i=0; i<FF_ARRAY_ELEMS(dv_profiles); i++)
- if (codec->height == dv_profiles[i].height &&
+ if (h == dv_profiles[i].height &&
codec->pix_fmt == dv_profiles[i].pix_fmt &&
- codec->width == dv_profiles[i].width)
+ w == dv_profiles[i].width)
return &dv_profiles[i];
return NULL;
diff --git a/libavcodec/dv_profile.h b/libavcodec/dv_profile.h
index c6d2278..8f0faf3 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,10 @@
#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 */
+
typedef struct DVwork_chunk {
uint16_t buf_offset;
uint16_t mb_coordinates[5];
@@ -62,6 +66,8 @@ typedef struct DVprofile {
const DVprofile* avpriv_dv_frame_profile(const DVprofile *sys,
const uint8_t* frame, unsigned buf_size);
+const DVprofile* avpriv_dv_frame_profile2(AVCodecContext* codec, const DVprofile *sys,
+ const uint8_t* frame, unsigned buf_size);
const DVprofile* avpriv_dv_codec_profile(AVCodecContext* codec);
/**
diff --git a/libavcodec/dv_tablegen.c b/libavcodec/dv_tablegen.c
index f463550..5d3793e 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 05831ea..e8cdc21 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
*/
diff --git a/libavcodec/dv_vlc_data.h b/libavcodec/dv_vlc_data.h
index d62fd6b..be768e6 100644
--- a/libavcodec/dv_vlc_data.h
+++ b/libavcodec/dv_vlc_data.h
@@ -2,20 +2,20 @@
* VLC 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
*/
diff --git a/libavcodec/dvbsub.c b/libavcodec/dvbsub.c
index de0808f..f30b767 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,7 +258,7 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
page_id = 1;
- if (h->num_rects == 0 || h->rects == NULL)
+ if (h->num_rects && h->rects == NULL)
return -1;
*q++ = 0x00; /* subtitle_stream_id */
@@ -218,10 +271,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 +284,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 +295,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 +362,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 +405,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);
@@ -387,7 +440,6 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
*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 9eaedca..4ce40aa 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
*/
#include "avcodec.h"
@@ -154,6 +154,7 @@ static void png_save2(const char *filename, uint32_t *bitmap, int w, int h)
typedef struct DVBSubCLUT {
int id;
+ int version;
uint32_t clut4[4];
uint32_t clut16[16];
@@ -180,6 +181,7 @@ typedef struct DVBSubObjectDisplay {
typedef struct DVBSubObject {
int id;
+ int version;
int type;
@@ -199,6 +201,7 @@ typedef struct DVBSubRegionDisplay {
typedef struct DVBSubRegion {
int id;
+ int version;
int width;
int height;
@@ -209,6 +212,7 @@ typedef struct DVBSubRegion {
uint8_t *pbuf;
int buf_size;
+ int dirty;
DVBSubObjectDisplay *display_list;
@@ -228,6 +232,7 @@ typedef struct DVBSubContext {
int composition_id;
int ancillary_id;
+ int version;
int time_out;
DVBSubRegion *region_list;
DVBSubCLUT *clut_list;
@@ -318,21 +323,10 @@ static void delete_region_display_list(DVBSubContext *ctx, DVBSubRegion *region)
}
-static void delete_state(DVBSubContext *ctx)
+static void delete_cluts(DVBSubContext *ctx)
{
- DVBSubRegion *region;
DVBSubCLUT *clut;
- while (ctx->region_list) {
- region = ctx->region_list;
-
- ctx->region_list = region->next;
-
- delete_region_display_list(ctx, region);
- av_free(region->pbuf);
- av_free(region);
- }
-
while (ctx->clut_list) {
clut = ctx->clut_list;
@@ -340,12 +334,35 @@ static void delete_state(DVBSubContext *ctx)
av_free(clut);
}
+}
- av_freep(&ctx->display_definition);
+static void delete_objects(DVBSubContext *ctx)
+{
+ DVBSubObject *object;
- /* Should already be null */
- if (ctx->object_list)
- av_log(0, AV_LOG_ERROR, "Memory deallocation error!\n");
+ while (ctx->object_list) {
+ object = ctx->object_list;
+
+ ctx->object_list = object->next;
+
+ av_free(object);
+ }
+}
+
+static void delete_regions(DVBSubContext *ctx)
+{
+ DVBSubRegion *region;
+
+ while (ctx->region_list) {
+ region = ctx->region_list;
+
+ ctx->region_list = region->next;
+
+ delete_region_display_list(ctx, region);
+
+ av_free(region->pbuf);
+ av_free(region);
+ }
}
static av_cold int dvbsub_init_decoder(AVCodecContext *avctx)
@@ -362,6 +379,8 @@ static av_cold int dvbsub_init_decoder(AVCodecContext *avctx)
ctx->ancillary_id = AV_RB16(avctx->extradata + 2);
}
+ ctx->version = -1;
+
default_clut.id = -1;
default_clut.next = NULL;
@@ -430,7 +449,13 @@ 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;
@@ -444,16 +469,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);
@@ -514,14 +541,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;
@@ -549,16 +576,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);
@@ -638,14 +667,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)
@@ -670,12 +699,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)++;
@@ -744,6 +775,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");
@@ -758,21 +790,22 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis
if (i % 16)
av_dlog(avctx, "\n");
+#endif
if (region == 0)
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;
}
@@ -785,9 +818,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) {
@@ -800,9 +833,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) {
@@ -810,9 +843,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:
@@ -847,7 +880,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;
@@ -878,7 +910,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);
@@ -886,9 +919,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);
}
@@ -900,13 +933,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;
@@ -924,6 +958,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);
@@ -934,11 +969,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++;
@@ -946,7 +986,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;
@@ -972,14 +1012,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;
}
@@ -990,6 +1037,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;
@@ -1006,11 +1054,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);
@@ -1026,6 +1076,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);
@@ -1035,9 +1086,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)
@@ -1104,17 +1156,27 @@ 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) {
+
+ 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 (page_state == 1 || page_state == 2) {
+ delete_regions(ctx);
+ delete_objects(ctx);
+ delete_cluts(ctx);
}
tmp_display_list = ctx->display_list;
@@ -1159,6 +1221,7 @@ static void dvbsub_parse_page_segment(AVCodecContext *avctx,
av_free(display);
}
+ }
}
@@ -1286,6 +1349,10 @@ 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;
@@ -1312,10 +1379,7 @@ static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf,
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;
@@ -1328,22 +1392,24 @@ static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf,
sub->rects = av_mallocz(sizeof(*sub->rects) * sub->num_rects);
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);
- rect = sub->rects[i];
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 = 16;
+ rect->nb_colors = (1 << region->depth);
rect->type = SUBTITLE_BITMAP;
rect->pict.linesize[0] = region->width;
@@ -1375,7 +1441,7 @@ static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf,
}
sub->num_rects = i;
-
+ }
#ifdef DEBUG
save_display_set(ctx);
#endif
@@ -1396,6 +1462,8 @@ static int dvbsub_decode(AVCodecContext *avctx,
int page_id;
int segment_length;
int i;
+ int ret;
+ int got_segment = 0;
av_dlog(avctx, "DVB sub packet:\n");
@@ -1434,20 +1502,27 @@ static int dvbsub_decode(AVCodecContext *avctx,
switch (segment_type) {
case DVBSUB_PAGE_SEGMENT:
dvbsub_parse_page_segment(avctx, p, segment_length);
+ 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) return ret;
+ 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);
+ got_segment |= 16;
break;
default:
av_dlog(avctx, "Subtitling segment type 0x%x, page id %d, length %d\n",
@@ -1458,6 +1533,10 @@ 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 && sub)
+ *data_size = dvbsub_display_end_segment(avctx, p, 0, sub);
return p - buf;
}
diff --git a/libavcodec/dvd_nav_parser.c b/libavcodec/dvd_nav_parser.c
new file mode 100644
index 0000000..4b03e39
--- a/dev/null
+++ b/libavcodec/dvd_nav_parser.c
@@ -0,0 +1,116 @@
+/*
+ * 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 "dsputil.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 c779277..a7e3d59 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
*/
diff --git a/libavcodec/dvdata.h b/libavcodec/dvdata.h
index 1c5d199..97c20e3 100644
--- a/libavcodec/dvdata.h
+++ b/libavcodec/dvdata.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
*/
@@ -83,10 +83,6 @@ extern const int ff_dv_iweight_720_c[64];
#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)
*/
diff --git a/libavcodec/dvdec.c b/libavcodec/dvdec.c
index 4b7dfee..c46c2ff 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,6 +35,7 @@
* DV decoder
*/
+#include "libavutil/avassert.h"
#include "libavutil/internal.h"
#include "libavutil/pixdesc.h"
#include "avcodec.h"
@@ -145,11 +146,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, [5*80 + 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));
@@ -236,7 +237,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);
}
@@ -286,9 +287,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->picture.linesize[j], pixels += 8) {
- ptr1 = pixels + (1 << (log2_blocksize - 1));
+ ptr1 = pixels + ((1 << (log2_blocksize))>>1);
c_ptr1 = c_ptr + (s->picture.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];
}
@@ -318,9 +319,9 @@ static int dvvideo_decode_frame(AVCodecContext *avctx,
int buf_size = avpkt->size;
DVVideoContext *s = avctx->priv_data;
const uint8_t* vsc_pack;
- int apt, is16_9;
+ int ret, apt, is16_9;
- s->sys = avpriv_dv_frame_profile(s->sys, buf, buf_size);
+ s->sys = avpriv_dv_frame_profile2(avctx, s->sys, buf, buf_size);
if (!s->sys || buf_size < s->sys->frame_size || ff_dv_init_dynamic_tables(s->sys)) {
av_log(avctx, AV_LOG_ERROR, "could not find dv frame profile\n");
return -1; /* NOTE: we only accept several full frames */
@@ -331,13 +332,20 @@ static int dvvideo_decode_frame(AVCodecContext *avctx,
avctx->pix_fmt = s->sys->pix_fmt;
avctx->time_base = s->sys->time_base;
avcodec_set_dimensions(avctx, s->sys->width, s->sys->height);
- if (ff_get_buffer(avctx, &s->picture, 0) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return -1;
- }
+ if ((ret = ff_get_buffer(avctx, &s->picture, 0)) < 0)
+ return ret;
s->picture.interlaced_frame = 1;
s->picture.top_field_first = 0;
+ /* Determine the codec's sample_aspect ratio and field order from the packet */
+ vsc_pack = buf + 80*5 + 48 + 5;
+ if ( *vsc_pack == dv_video_control ) {
+ apt = buf[4] & 0x07;
+ is16_9 = (vsc_pack[2] & 0x07) == 0x02 || (!apt && (vsc_pack[2] & 0x07) == 0x07);
+ avctx->sample_aspect_ratio = s->sys->sar[is16_9];
+ s->picture.top_field_first = !(vsc_pack[3] & 0x40);
+ }
+
s->buf = buf;
avctx->execute(avctx, dv_decode_video_segment, s->sys->work_chunks, NULL,
dv_work_pool_size(s->sys), sizeof(DVwork_chunk));
@@ -348,14 +356,6 @@ static int dvvideo_decode_frame(AVCodecContext *avctx,
*got_frame = 1;
av_frame_move_ref(data, &s->picture);
- /* Determine the codec's sample_aspect ratio from the packet */
- 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)));
- avctx->sample_aspect_ratio = s->sys->sar[is16_9];
- }
-
return s->sys->frame_size;
}
@@ -378,4 +378,5 @@ AVCodec ff_dvvideo_decoder = {
.close = dvvideo_close,
.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..e50c339 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
*/
diff --git a/libavcodec/dvdsubdec.c b/libavcodec/dvdsubdec.c
index 3cc9022..f0dd289 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
*/
#include "avcodec.h"
@@ -23,12 +23,23 @@
#include "dsputil.h"
#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;
+#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)
@@ -123,17 +134,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;
}
@@ -151,18 +169,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);
@@ -171,6 +189,21 @@ static void guess_palette(DVDSubContext* ctx,
}
}
+static void reset_rects(AVSubtitle *sub_header)
+{
+ int i;
+
+ if (sub_header->rects != NULL) {
+ 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,
@@ -179,14 +212,13 @@ 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 };
+ 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;
@@ -200,6 +232,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);
@@ -312,15 +347,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
if (h < 0)
h = 0;
if (w > 0 && h > 0) {
- if (sub_header->rects != NULL) {
- 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));
@@ -339,9 +366,8 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
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;
@@ -349,8 +375,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;
@@ -358,15 +389,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 != NULL) {
- 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;
}
@@ -467,6 +490,25 @@ static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h,
}
#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)
@@ -477,7 +519,21 @@ 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:
@@ -489,55 +545,114 @@ static int dvdsub_decode(AVCodecContext *avctx,
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],
+ ppm_save(ppm_name, sub->rects[0]->pict.data[0],
sub->rects[0]->w, sub->rects[0]->h, 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 &&
av_image_check_size(w, h, 0, avctx) >= 0)
avcodec_set_dimensions(avctx, w, h);
}
- 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 VD 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, VD },
+ { 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"),
@@ -546,4 +661,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 db6749e..8130b74 100644
--- a/libavcodec/dvdsubenc.c
+++ b/libavcodec/dvdsubenc.c
@@ -2,27 +2,32 @@
* 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"
-#undef NDEBUG
-#include <assert.h>
+typedef struct {
+ uint32_t global_palette[16];
+} DVDSubtitleContext;
// ncnt is the nibble counter
#define PUTNIBBLE(val)\
@@ -53,7 +58,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,73 +91,252 @@ 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;
if (rects == 0 || h->rects == NULL)
- 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;
+ 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);
+ }
+ 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 (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;
+
+ 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 (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)
- 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;
+ 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);
// set data packet size
qq = outbuf + 2;
@@ -160,34 +344,33 @@ 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]);
- }
+ 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++ = 0x01; // start command
*q++ = 0xff; // terminating command
@@ -201,7 +384,41 @@ static int encode_dvd_subtitles(uint8_t *outbuf, int outbuf_size,
bytestream_put_be16(&qq, q - outbuf);
av_log(NULL, AV_LOG_DEBUG, "subtitle_packet size=%td\n", q - outbuf);
- return 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,7 +428,7 @@ 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;
}
@@ -220,5 +437,7 @@ AVCodec ff_dvdsub_encoder = {
.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_data_size = sizeof(DVDSubtitleContext),
};
diff --git a/libavcodec/dxa.c b/libavcodec/dxa.c
index f32be99..2704852 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"
@@ -38,7 +39,7 @@
* Decoder context
*/
typedef struct DxaDecContext {
- AVFrame prev;
+ AVFrame *prev;
int dsize;
uint8_t *decomp_buf;
@@ -70,6 +71,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 +133,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,59 +203,59 @@ 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;
outptr = frame->data[0];
srcptr = c->decomp_buf;
- tmpptr = c->prev.data[0];
+ 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;
+ }
}
+
+ 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;
frame->pict_type = AV_PICTURE_TYPE_P;
- if(c->prev.data[0])
- memcpy(frame->data[0], c->prev.data[0], frame->linesize[0] * avctx->height);
+ if (c->prev->data[0])
+ memcpy(frame->data[0], c->prev->data[0], frame->linesize[0] * avctx->height);
else{ // Should happen only when first frame is 'NULL'
memset(frame->data[0], 0, frame->linesize[0] * avctx->height);
frame->key_frame = 1;
@@ -265,14 +276,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,21 +296,25 @@ 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, 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;
}
- av_frame_unref(&c->prev);
- if ((ret = av_frame_ref(&c->prev, frame)) < 0)
+ av_frame_unref(c->prev);
+ if ((ret = av_frame_ref(c->prev, frame)) < 0)
return ret;
*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)
@@ -304,8 +323,14 @@ static av_cold int decode_init(AVCodecContext *avctx)
avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ c->prev = av_frame_alloc();
+ if (!c->prev)
+ return AVERROR(ENOMEM);
+
c->dsize = avctx->width * avctx->height * 2;
- if((c->decomp_buf = av_malloc(c->dsize)) == NULL) {
+ c->decomp_buf = av_malloc(c->dsize);
+ if (!c->decomp_buf) {
+ av_frame_free(&c->prev);
av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
return AVERROR(ENOMEM);
}
@@ -318,7 +343,7 @@ static av_cold int decode_end(AVCodecContext *avctx)
DxaDecContext * const c = avctx->priv_data;
av_freep(&c->decomp_buf);
- av_frame_unref(&c->prev);
+ av_frame_free(&c->prev);
return 0;
}
diff --git a/libavcodec/dxtory.c b/libavcodec/dxtory.c
index 6018ebb..21282b8 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
*/
@@ -66,7 +66,7 @@ static int dxtory_decode_v1(AVCodecContext *avctx, AVFrame *pic,
return 0;
}
-const uint8_t def_lru[8] = { 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xFF };
+static const uint8_t def_lru[8] = { 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xFF };
static inline uint8_t decode_sym(GetBitContext *gb, uint8_t lru[8])
{
diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c
index bc43cae..0997c73 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 d161eb9..ac39e06 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
*/
@@ -29,7 +29,14 @@
* Public libavcodec DXVA2 header.
*/
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
+#undef _WIN32_WINNT
+#endif
+
+#if !defined(_WIN32_WINNT)
#define _WIN32_WINNT 0x0600
+#endif
+
#include <stdint.h>
#include <d3d9.h>
#include <dxva2api.h>
@@ -45,7 +52,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.
*/
@@ -76,7 +83,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 6457824..1090502 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
*/
@@ -95,7 +95,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) |
@@ -149,8 +149,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)
@@ -257,7 +257,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)
@@ -290,7 +290,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx,
/* Create an annex B bitstream buffer with only slice NAL and finalize slice */
if (FAILED(IDirectXVideoDecoder_GetBuffer(ctx->decoder,
DXVA2_BitStreamDateBufferType,
- &dxva_data, &dxva_size)))
+ (void **)&dxva_data, &dxva_size)))
return -1;
current = dxva_data;
end = dxva_data + dxva_size;
diff --git a/libavcodec/dxva2_internal.h b/libavcodec/dxva2_internal.h
index a81cfbe..8a454c1 100644
--- a/libavcodec/dxva2_internal.h
+++ b/libavcodec/dxva2_internal.h
@@ -3,27 +3,26 @@
*
* 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
*/
#ifndef AVCODEC_DXVA_INTERNAL_H
#define AVCODEC_DXVA_INTERNAL_H
-#define _WIN32_WINNT 0x0600
#define COBJMACROS
#include "config.h"
diff --git a/libavcodec/dxva2_mpeg2.c b/libavcodec/dxva2_mpeg2.c
index 049fa48..542f17c 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
*/
@@ -109,10 +109,10 @@ static void fill_quantization_matrices(AVCodecContext *avctx,
qm->bNewQmatrix[i] = 1;
for (i = 0; i < 64; i++) {
int n = s->dsp.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];
}
}
@@ -160,7 +160,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx,
if (FAILED(IDirectXVideoDecoder_GetBuffer(ctx->decoder,
DXVA2_BitStreamDateBufferType,
- &dxva_data, &dxva_size)))
+ (void **)&dxva_data, &dxva_size)))
return -1;
current = dxva_data;
end = dxva_data + dxva_size;
diff --git a/libavcodec/dxva2_vc1.c b/libavcodec/dxva2_vc1.c
index 4af3ce8..92c78fd 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
*/
@@ -68,7 +68,7 @@ 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) |
@@ -178,13 +178,16 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx,
if (FAILED(IDirectXVideoDecoder_GetBuffer(ctx->decoder,
DXVA2_BitStreamDateBufferType,
- &dxva_data, &dxva_size)))
+ (void **)&dxva_data, &dxva_size)))
return -1;
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 baba454..b55ee2a 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 c238fc1..9944617 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 3b1256c..3f22c74 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;
@@ -140,8 +141,11 @@ static void cmv_process_header(CmvContext *s, const uint8_t *buf, const uint8_t
s->width = AV_RL16(&buf[4]);
s->height = AV_RL16(&buf[6]);
- if (s->avctx->width!=s->width || s->avctx->height!=s->height)
+ if (s->avctx->width!=s->width || s->avctx->height!=s->height) {
avcodec_set_dimensions(s->avctx, s->width, s->height);
+ av_frame_unref(s->last_frame);
+ av_frame_unref(s->last2_frame);
+ }
s->avctx->time_base.num = 1;
s->avctx->time_base.den = AV_RL16(&buf[10]);
@@ -151,7 +155,7 @@ static void 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;
}
}
@@ -174,17 +178,18 @@ 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);
cmv_process_header(s, buf+EA_PREAMBLE_SIZE, buf_end);
- 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 8d6aa62..6d8291e 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
*/
@@ -82,15 +82,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);
}
}
@@ -110,7 +116,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;
@@ -160,13 +166,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)
@@ -180,7 +187,7 @@ 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;
@@ -192,21 +199,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->dsp.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)
@@ -231,10 +239,10 @@ static int decode_frame(AVCodecContext *avctx,
int chunk_type;
int inter, ret;
- if (buf_size < 17) {
+ if (buf_size < 26) {
av_log(avctx, AV_LOG_ERROR, "Input buffer too small\n");
*got_frame = 0;
- return -1;
+ return AVERROR_INVALIDDATA;
}
chunk_type = AV_RL32(&buf[0]);
@@ -249,17 +257,22 @@ static int decode_frame(AVCodecContext *avctx,
calc_quant_matrix(s, buf[13]);
buf += 16;
+ 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) {
- if (av_image_check_size(width, height, 0, avctx) < 0)
- return -1;
+ if((width * height)/2048*7 > buf_end-buf)
+ return AVERROR_INVALIDDATA;
+ if ((ret = av_image_check_size(width, height, 0, avctx)) < 0)
+ return ret;
avcodec_set_dimensions(avctx, width, height);
av_frame_unref(&s->last_frame);
}
- 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");
@@ -279,11 +292,13 @@ static int decode_frame(AVCodecContext *avctx,
if (!s->bitstream_buf)
return AVERROR(ENOMEM);
s->dsp.bswap16_buf(s->bitstream_buf, (const uint16_t*)buf, (buf_end-buf)/2);
+ memset((uint8_t*)s->bitstream_buf + (buf_end-buf), 0, FF_INPUT_BUFFER_PADDING_SIZE);
init_get_bits(&s->gb, s->bitstream_buf, 8*(buf_end-buf));
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;
diff --git a/libavcodec/eatgq.c b/libavcodec/eatgq.c
index 0a3e0f6..a24550b 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);
@@ -222,16 +225,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 fabc516..bfdfb76 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
*/
@@ -57,6 +57,7 @@ static av_cold int tgv_decode_init(AVCodecContext *avctx)
s->avctx = avctx;
avctx->time_base = (AVRational){1, 15};
avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ avcodec_get_frame_defaults(&s->last_frame);
return 0;
}
@@ -76,7 +77,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;
@@ -151,7 +152,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]);
@@ -168,19 +169,25 @@ 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;
}
if (num_blocks_packed > s->num_blocks_packed) {
- s->block_codebook = av_realloc(s->block_codebook, num_blocks_packed*16);
+ if (av_reallocp_array(&s->block_codebook, num_blocks_packed, sizeof(*s->block_codebook))) {
+ s->num_blocks_packed = 0;
+ return AVERROR(ENOMEM);
+ }
s->num_blocks_packed = num_blocks_packed;
}
/* 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);
@@ -220,8 +227,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];
@@ -256,12 +265,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;
}
@@ -276,8 +288,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;
}
}
diff --git a/libavcodec/eatqi.c b/libavcodec/eatqi.c
index 9f7ec4d..262deb1 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
*/
@@ -114,10 +114,8 @@ static int tqi_decode_frame(AVCodecContext *avctx,
if (s->avctx->width!=s->width || s->avctx->height!=s->height)
avcodec_set_dimensions(s->avctx, s->width, s->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;
- }
av_fast_padded_malloc(&t->bitstream_buf, &t->bitstream_buf_size,
buf_end - buf);
@@ -131,9 +129,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;
diff --git a/libavcodec/elbg.c b/libavcodec/elbg.c
index 0aa8e16..2707599 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"
@@ -111,7 +112,7 @@ static int get_high_utility_cell(elbg_data *elbg)
while (elbg->utility_inc[i] < r)
i++;
- assert(elbg->cells[i]);
+ av_assert2(elbg->cells[i]);
return i;
}
@@ -189,7 +190,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
diff --git a/libavcodec/elbg.h b/libavcodec/elbg.h
index b8ea489..e6f577e 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
*/
diff --git a/libavcodec/error_resilience.c b/libavcodec/error_resilience.c
index 1769d2b..23180dc 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
*/
@@ -40,7 +40,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 {
@@ -133,11 +133,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(stride*h*sizeof( int16_t)*4);
+ uint32_t (*dist)[4] = av_malloc(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;
@@ -148,66 +210,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);
}
/**
@@ -377,6 +394,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)) ||
@@ -427,8 +452,8 @@ static void guess_mv(ERContext *s)
if (fixed[mb_xy] == MV_FROZEN)
continue;
- assert(!IS_INTRA(s->cur_pic->mb_type[mb_xy]));
- assert(s->last_pic && s->last_pic->f.data[0]);
+ av_assert1(!IS_INTRA(s->cur_pic->mb_type[mb_xy]));
+ av_assert1(s->last_pic && s->last_pic->f.data[0]);
j = 0;
if (mb_x > 0 && fixed[mb_xy - 1] == MV_FROZEN)
@@ -543,7 +568,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 {
@@ -710,6 +735,7 @@ static int is_intra_more_likely(ERContext *s)
}
is_intra_likely += s->dsp->sad[0](NULL, last_mb_ptr, mb_ptr,
linesize[0], 16);
+ // FIXME need await_progress() here
is_intra_likely -= s->dsp->sad[0](NULL, last_mb_ptr,
last_mb_ptr + linesize[0] * 16,
linesize[0], 16);
@@ -721,6 +747,7 @@ static int is_intra_more_likely(ERContext *s)
}
}
}
+// av_log(NULL, AV_LOG_ERROR, "is_intra_likely: %d type:%d\n", is_intra_likely, s->pict_type);
return is_intra_likely > 0;
}
@@ -800,13 +827,15 @@ 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 &&
+ if (start_xy > 0 && !(s->avctx->active_thread_type & FF_THREAD_SLICE) &&
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;
+ }
}
}
@@ -823,12 +852,45 @@ void ff_er_frame_end(ERContext *s)
/* 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->lowres ||
s->avctx->hwaccel ||
+ s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU ||
!s->cur_pic || s->cur_pic->field_picture ||
s->error_count == 3 * s->mb_width *
(s->avctx->skip_top + s->avctx->skip_bottom)) {
return;
- };
+ }
+ 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 ( 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) {
+ 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");
+ s->last_pic = NULL;
+ }
+ }
+ if (s->next_pic) {
+ 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");
+ s->next_pic = NULL;
+ }
+ }
if (s->cur_pic->motion_val[0] == NULL) {
av_log(s->avctx, AV_LOG_ERROR, "Warning MVs not available\n");
@@ -863,6 +925,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;
@@ -883,7 +946,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;
@@ -906,7 +970,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;
@@ -933,6 +997,7 @@ void ff_er_frame_end(ERContext *s)
}
}
+#if 1
/* backward mark errors */
distance = 9999999;
for (error_type = 1; error_type <= 3; error_type++) {
@@ -957,6 +1022,7 @@ void ff_er_frame_end(ERContext *s)
distance = 9999999;
}
}
+#endif
/* forward mark errors */
error = 0;
@@ -971,7 +1037,7 @@ 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++) {
@@ -982,6 +1048,7 @@ void ff_er_frame_end(ERContext *s)
s->error_status_table[mb_xy] = error;
}
}
+#endif
dc_error = ac_error = mv_error = 0;
for (i = 0; i < s->mb_num; i++) {
@@ -994,8 +1061,8 @@ 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);
@@ -1085,6 +1152,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;
@@ -1152,15 +1220,17 @@ void ff_er_frame_end(ERContext *s)
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++) {
@@ -1182,6 +1252,7 @@ void ff_er_frame_end(ERContext *s)
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 */
diff --git a/libavcodec/error_resilience.h b/libavcodec/error_resilience.h
index f979656..970fdc2 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
*/
diff --git a/libavcodec/escape124.c b/libavcodec/escape124.c
index 4e4b908..a050fcb 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
@@ -62,6 +58,7 @@ static av_cold int escape124_decode_init(AVCodecContext *avctx)
{
Escape124Context *s = avctx->priv_data;
+ avcodec_get_frame_defaults(&s->frame);
avctx->pix_fmt = AV_PIX_FMT_RGB555;
s->num_superblocks = ((unsigned)avctx->width / 8) *
@@ -89,7 +86,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))
@@ -120,7 +117,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)
@@ -199,7 +196,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;
@@ -214,13 +210,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);
@@ -232,7 +230,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)
@@ -269,10 +267,8 @@ static int escape124_decode_frame(AVCodecContext *avctx,
}
}
- 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;
@@ -298,7 +294,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);
@@ -310,7 +306,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)) {
@@ -322,15 +318,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));
}
@@ -352,7 +346,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..cde1f57
--- a/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 **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..51ae9e2
--- a/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 **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..9646426
--- a/dev/null
+++ b/libavcodec/exif.c
@@ -0,0 +1,130 @@
+/*
+ * 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 TIFF_DOUBLE : return ff_tadd_doubles_metadata(count, name, sep, gb, le, metadata);
+ case TIFF_SHORT : return ff_tadd_shorts_metadata(count, name, sep, gb, le, metadata);
+ case TIFF_BYTE :
+ case TIFF_UNDEFINED: return ff_tadd_bytes_metadata(count, name, sep, gb, le, 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);
+
+ // read count values and add it metadata
+ // store metadata or proceed with next IFD
+ ret = ff_tis_ifd(id);
+ if (ret) {
+ ret = ff_exif_decode_ifd(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 ff_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..71fe829
--- a/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 ff_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
new file mode 100644
index 0000000..ef4fc36
--- a/dev/null
+++ b/libavcodec/exr.c
@@ -0,0 +1,1281 @@
+/*
+ * OpenEXR (.exr) image decoder
+ * Copyright (c) 2009 Jimmy Christensen
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * OpenEXR decoder
+ * @author Jimmy Christensen
+ *
+ * For more information on the OpenEXR format, visit:
+ * http://openexr.com/
+ *
+ * exr_flt2uint() and exr_halflt2uint() is credited to Reimar Döffinger
+ */
+
+#include <zlib.h>
+
+#include "get_bits.h"
+#include "avcodec.h"
+#include "bytestream.h"
+#include "mathops.h"
+#include "thread.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/avassert.h"
+
+enum ExrCompr {
+ EXR_RAW = 0,
+ EXR_RLE = 1,
+ EXR_ZIP1 = 2,
+ EXR_ZIP16 = 3,
+ EXR_PIZ = 4,
+ EXR_PXR24 = 5,
+ EXR_B44 = 6,
+ EXR_B44A = 7,
+};
+
+enum ExrPixelType {
+ EXR_UINT,
+ EXR_HALF,
+ EXR_FLOAT
+};
+
+typedef struct EXRChannel {
+ int xsub, ysub;
+ enum ExrPixelType pixel_type;
+} EXRChannel;
+
+typedef struct EXRThreadData {
+ uint8_t *uncompressed_data;
+ int uncompressed_size;
+
+ uint8_t *tmp;
+ int tmp_size;
+
+ uint8_t *bitmap;
+ uint16_t *lut;
+} EXRThreadData;
+
+typedef struct EXRContext {
+ AVFrame *picture;
+ int compr;
+ enum ExrPixelType pixel_type;
+ int channel_offsets[4]; // 0 = red, 1 = green, 2 = blue and 3 = alpha
+ const AVPixFmtDescriptor *desc;
+
+ uint32_t xmax, xmin;
+ uint32_t ymax, ymin;
+ uint32_t xdelta, ydelta;
+
+ int ysize;
+
+ uint64_t scan_line_size;
+ int scan_lines_per_block;
+
+ const uint8_t *buf, *table;
+ int buf_size;
+
+ EXRChannel *channels;
+ int nb_channels;
+
+ EXRThreadData *thread_data;
+ int thread_data_size;
+} EXRContext;
+
+/**
+ * Converts from 32-bit float as uint32_t to uint16_t
+ *
+ * @param v 32-bit float
+ * @return normalized 16-bit unsigned int
+ */
+static inline uint16_t exr_flt2uint(uint32_t v)
+{
+ unsigned int exp = v >> 23;
+ // "HACK": negative values result in exp< 0, so clipping them to 0
+ // is also handled by this condition, avoids explicit check for sign bit.
+ if (exp<= 127 + 7 - 24) // we would shift out all bits anyway
+ return 0;
+ if (exp >= 127)
+ return 0xffff;
+ v &= 0x007fffff;
+ return (v + (1 << 23)) >> (127 + 7 - exp);
+}
+
+/**
+ * Converts from 16-bit float as uint16_t to uint16_t
+ *
+ * @param v 16-bit float
+ * @return normalized 16-bit unsigned int
+ */
+static inline uint16_t exr_halflt2uint(uint16_t v)
+{
+ unsigned exp = 14 - (v >> 10);
+ if (exp >= 14) {
+ if (exp == 14) return (v >> 9) & 1;
+ else return (v & 0x8000) ? 0 : 0xffff;
+ }
+ v <<= 6;
+ return (v + (1 << 16)) >> (exp + 1);
+}
+
+/**
+ * Gets the size of the header variable
+ *
+ * @param **buf the current pointer location in the header where
+ * the variable data starts
+ * @param *buf_end pointer location of the end of the buffer
+ * @return size of variable data
+ */
+static unsigned int get_header_variable_length(const uint8_t **buf,
+ const uint8_t *buf_end)
+{
+ unsigned int variable_buffer_data_size = bytestream_get_le32(buf);
+ if (variable_buffer_data_size >= buf_end - *buf)
+ return 0;
+ return variable_buffer_data_size;
+}
+
+/**
+ * Checks if the variable name corresponds with it's data type
+ *
+ * @param *avctx the AVCodecContext
+ * @param **buf the current pointer location in the header where
+ * the variable name starts
+ * @param *buf_end pointer location of the end of the buffer
+ * @param *value_name name of the varible to check
+ * @param *value_type type of the varible to check
+ * @param minimum_length minimum length of the variable data
+ * @param variable_buffer_data_size variable length read from the header
+ * after it's checked
+ * @return negative if variable is invalid
+ */
+static int check_header_variable(AVCodecContext *avctx,
+ const uint8_t **buf,
+ const uint8_t *buf_end,
+ const char *value_name,
+ const char *value_type,
+ unsigned int minimum_length,
+ unsigned int *variable_buffer_data_size)
+{
+ if (buf_end - *buf >= minimum_length && !strcmp(*buf, value_name)) {
+ *buf += strlen(value_name)+1;
+ if (!strcmp(*buf, value_type)) {
+ *buf += strlen(value_type)+1;
+ *variable_buffer_data_size = get_header_variable_length(buf, buf_end);
+ if (!*variable_buffer_data_size)
+ av_log(avctx, AV_LOG_ERROR, "Incomplete header\n");
+ return 1;
+ }
+ *buf -= strlen(value_name)+1;
+ av_log(avctx, AV_LOG_WARNING, "Unknown data type for header variable %s\n", value_name);
+ }
+ return -1;
+}
+
+static void predictor(uint8_t *src, int size)
+{
+ uint8_t *t = src + 1;
+ uint8_t *stop = src + size;
+
+ while (t < stop) {
+ int d = (int)t[-1] + (int)t[0] - 128;
+ t[0] = d;
+ ++t;
+ }
+}
+
+static void reorder_pixels(uint8_t *src, uint8_t *dst, int size)
+{
+ const int8_t *t1 = src;
+ const int8_t *t2 = src + (size + 1) / 2;
+ int8_t *s = dst;
+ int8_t *stop = s + size;
+
+ while (1) {
+ if (s < stop)
+ *(s++) = *(t1++);
+ else
+ break;
+
+ if (s < stop)
+ *(s++) = *(t2++);
+ else
+ break;
+ }
+}
+
+static int zip_uncompress(const uint8_t *src, int compressed_size,
+ int uncompressed_size, EXRThreadData *td)
+{
+ unsigned long dest_len = uncompressed_size;
+
+ if (uncompress(td->tmp, &dest_len, src, compressed_size) != Z_OK ||
+ dest_len != uncompressed_size)
+ return AVERROR(EINVAL);
+
+ predictor(td->tmp, uncompressed_size);
+ reorder_pixels(td->tmp, td->uncompressed_data, uncompressed_size);
+
+ return 0;
+}
+
+static int rle_uncompress(const uint8_t *src, int compressed_size,
+ int uncompressed_size, EXRThreadData *td)
+{
+ int8_t *d = (int8_t *)td->tmp;
+ const int8_t *s = (const int8_t *)src;
+ int ssize = compressed_size;
+ int dsize = uncompressed_size;
+ int8_t *dend = d + dsize;
+ int count;
+
+ while (ssize > 0) {
+ count = *s++;
+
+ if (count < 0) {
+ count = -count;
+
+ if ((dsize -= count ) < 0 ||
+ (ssize -= count + 1) < 0)
+ return -1;
+
+ while (count--)
+ *d++ = *s++;
+ } else {
+ count++;
+
+ if ((dsize -= count) < 0 ||
+ (ssize -= 2 ) < 0)
+ return -1;
+
+ while (count--)
+ *d++ = *s;
+
+ s++;
+ }
+ }
+
+ if (dend != d)
+ return AVERROR_INVALIDDATA;
+
+ predictor(td->tmp, uncompressed_size);
+ reorder_pixels(td->tmp, td->uncompressed_data, uncompressed_size);
+
+ return 0;
+}
+
+#define USHORT_RANGE (1 << 16)
+#define BITMAP_SIZE (1 << 13)
+
+static uint16_t reverse_lut(const uint8_t *bitmap, uint16_t *lut)
+{
+ int i, k = 0;
+
+ for (i = 0; i < USHORT_RANGE; i++) {
+ if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
+ lut[k++] = i;
+ }
+
+ i = k - 1;
+
+ memset(lut + k, 0, (USHORT_RANGE - k) * 2);
+
+ return i;
+}
+
+static void apply_lut(const uint16_t *lut, uint16_t *dst, int dsize)
+{
+ int i;
+
+ for (i = 0; i < dsize; ++i)
+ dst[i] = lut[dst[i]];
+}
+
+#define HUF_ENCBITS 16 // literal (value) bit length
+#define HUF_DECBITS 14 // decoding bit size (>= 8)
+
+#define HUF_ENCSIZE ((1 << HUF_ENCBITS) + 1) // encoding table size
+#define HUF_DECSIZE (1 << HUF_DECBITS) // decoding table size
+#define HUF_DECMASK (HUF_DECSIZE - 1)
+
+typedef struct HufDec {
+ int len;
+ int lit;
+ int *p;
+} HufDec;
+
+static void huf_canonical_code_table(uint64_t *hcode)
+{
+ uint64_t c, n[59] = { 0 };
+ int i;
+
+ for (i = 0; i < HUF_ENCSIZE; ++i)
+ n[hcode[i]] += 1;
+
+ c = 0;
+ for (i = 58; i > 0; --i) {
+ uint64_t nc = ((c + n[i]) >> 1);
+ n[i] = c;
+ c = nc;
+ }
+
+ for (i = 0; i < HUF_ENCSIZE; ++i) {
+ int l = hcode[i];
+
+ if (l > 0)
+ hcode[i] = l | (n[l]++ << 6);
+ }
+}
+
+#define SHORT_ZEROCODE_RUN 59
+#define LONG_ZEROCODE_RUN 63
+#define SHORTEST_LONG_RUN (2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN)
+#define LONGEST_LONG_RUN (255 + SHORTEST_LONG_RUN)
+
+static int huf_unpack_enc_table(GetByteContext *gb,
+ int32_t im, int32_t iM, uint64_t *hcode)
+{
+ GetBitContext gbit;
+
+ init_get_bits8(&gbit, gb->buffer, bytestream2_get_bytes_left(gb));
+
+ for (; im <= iM; im++) {
+ uint64_t l = hcode[im] = get_bits(&gbit, 6);
+
+ if (l == LONG_ZEROCODE_RUN) {
+ int zerun = get_bits(&gbit, 8) + SHORTEST_LONG_RUN;
+
+ if (im + zerun > iM + 1)
+ return AVERROR_INVALIDDATA;
+
+ while (zerun--)
+ hcode[im++] = 0;
+
+ im--;
+ } else if (l >= (uint64_t) SHORT_ZEROCODE_RUN) {
+ int zerun = l - SHORT_ZEROCODE_RUN + 2;
+
+ if (im + zerun > iM + 1)
+ return AVERROR_INVALIDDATA;
+
+ while (zerun--)
+ hcode[im++] = 0;
+
+ im--;
+ }
+ }
+
+ bytestream2_skip(gb, (get_bits_count(&gbit) + 7) / 8);
+ huf_canonical_code_table(hcode);
+
+ return 0;
+}
+
+static int huf_build_dec_table(const uint64_t *hcode, int im,
+ int iM, HufDec *hdecod)
+{
+ for (; im <= iM; im++) {
+ uint64_t c = hcode[im] >> 6;
+ int i, l = hcode[im] & 63;
+
+ if (c >> l)
+ return AVERROR_INVALIDDATA;
+
+ if (l > HUF_DECBITS) {
+ HufDec *pl = hdecod + (c >> (l - HUF_DECBITS));
+ if (pl->len)
+ return AVERROR_INVALIDDATA;
+
+ pl->lit++;
+
+ pl->p = av_realloc_f(pl->p, pl->lit, sizeof(int));
+ if (!pl->p)
+ return AVERROR(ENOMEM);
+
+ pl->p[pl->lit - 1] = im;
+ } else if (l) {
+ HufDec *pl = hdecod + (c << (HUF_DECBITS - l));
+
+ for (i = 1 << (HUF_DECBITS - l); i > 0; i--, pl++) {
+ if (pl->len || pl->p)
+ return AVERROR_INVALIDDATA;
+ pl->len = l;
+ pl->lit = im;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#define get_char(c, lc, gb) { \
+ c = (c << 8) | bytestream2_get_byte(gb); \
+ lc += 8; \
+}
+
+#define get_code(po, rlc, c, lc, gb, out, oe) { \
+ if (po == rlc) { \
+ if (lc < 8) \
+ get_char(c, lc, gb); \
+ lc -= 8; \
+ \
+ cs = c >> lc; \
+ \
+ if (out + cs > oe) \
+ return AVERROR_INVALIDDATA; \
+ \
+ s = out[-1]; \
+ \
+ while (cs-- > 0) \
+ *out++ = s; \
+ } else if (out < oe) { \
+ *out++ = po; \
+ } else { \
+ return AVERROR_INVALIDDATA; \
+ } \
+}
+
+static int huf_decode(const uint64_t *hcode, const HufDec *hdecod,
+ GetByteContext *gb, int nbits,
+ int rlc, int no, uint16_t *out)
+{
+ uint64_t c = 0;
+ uint16_t *outb = out;
+ uint16_t *oe = out + no;
+ const uint8_t *ie = gb->buffer + (nbits + 7) / 8; // input byte size
+ uint8_t cs, s;
+ int i, lc = 0;
+
+ while (gb->buffer < ie) {
+ get_char(c, lc, gb);
+
+ while (lc >= HUF_DECBITS) {
+ const HufDec pl = hdecod[(c >> (lc-HUF_DECBITS)) & HUF_DECMASK];
+
+ if (pl.len) {
+ lc -= pl.len;
+ get_code(pl.lit, rlc, c, lc, gb, out, oe);
+ } else {
+ int j;
+
+ if (!pl.p)
+ return AVERROR_INVALIDDATA;
+
+ for (j = 0; j < pl.lit; j++) {
+ int l = hcode[pl.p[j]] & 63;
+
+ while (lc < l && bytestream2_get_bytes_left(gb) > 0)
+ get_char(c, lc, gb);
+
+ if (lc >= l) {
+ if ((hcode[pl.p[j]] >> 6) ==
+ ((c >> (lc - l)) & ((1LL << l) - 1))) {
+ lc -= l;
+ get_code(pl.p[j], rlc, c, lc, gb, out, oe);
+ break;
+ }
+ }
+ }
+
+ if (j == pl.lit)
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ }
+
+ i = (8 - nbits) & 7;
+ c >>= i;
+ lc -= i;
+
+ while (lc > 0) {
+ const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];
+
+ if (pl.len) {
+ lc -= pl.len;
+ get_code(pl.lit, rlc, c, lc, gb, out, oe);
+ } else {
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ if (out - outb != no)
+ return AVERROR_INVALIDDATA;
+ return 0;
+}
+
+static int huf_uncompress(GetByteContext *gb,
+ uint16_t *dst, int dst_size)
+{
+ int32_t src_size, im, iM;
+ uint32_t nBits;
+ uint64_t *freq;
+ HufDec *hdec;
+ int ret, i;
+
+ src_size = bytestream2_get_le32(gb);
+ im = bytestream2_get_le32(gb);
+ iM = bytestream2_get_le32(gb);
+ bytestream2_skip(gb, 4);
+ nBits = bytestream2_get_le32(gb);
+ if (im < 0 || im >= HUF_ENCSIZE ||
+ iM < 0 || iM >= HUF_ENCSIZE ||
+ src_size < 0)
+ return AVERROR_INVALIDDATA;
+
+ bytestream2_skip(gb, 4);
+
+ freq = av_calloc(HUF_ENCSIZE, sizeof(*freq));
+ hdec = av_calloc(HUF_DECSIZE, sizeof(*hdec));
+ if (!freq || !hdec) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if ((ret = huf_unpack_enc_table(gb, im, iM, freq)) < 0)
+ goto fail;
+
+ if (nBits > 8 * bytestream2_get_bytes_left(gb)) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ if ((ret = huf_build_dec_table(freq, im, iM, hdec)) < 0)
+ goto fail;
+ ret = huf_decode(freq, hdec, gb, nBits, iM, dst_size, dst);
+
+fail:
+ for (i = 0; i < HUF_DECSIZE; i++) {
+ if (hdec)
+ av_freep(&hdec[i].p);
+ }
+
+ av_free(freq);
+ av_free(hdec);
+
+ return ret;
+}
+
+static inline void wdec14(uint16_t l, uint16_t h, uint16_t *a, uint16_t *b)
+{
+ int16_t ls = l;
+ int16_t hs = h;
+ int hi = hs;
+ int ai = ls + (hi & 1) + (hi >> 1);
+ int16_t as = ai;
+ int16_t bs = ai - hi;
+
+ *a = as;
+ *b = bs;
+}
+
+#define NBITS 16
+#define A_OFFSET (1 << (NBITS - 1))
+#define MOD_MASK ((1 << NBITS) - 1)
+
+static inline void wdec16(uint16_t l, uint16_t h, uint16_t *a, uint16_t *b)
+{
+ int m = l;
+ int d = h;
+ int bb = (m - (d >> 1)) & MOD_MASK;
+ int aa = (d + bb - A_OFFSET) & MOD_MASK;
+ *b = bb;
+ *a = aa;
+}
+
+static void wav_decode(uint16_t *in, int nx, int ox,
+ int ny, int oy, uint16_t mx)
+{
+ int w14 = (mx < (1 << 14));
+ int n = (nx > ny) ? ny: nx;
+ int p = 1;
+ int p2;
+
+ while (p <= n)
+ p <<= 1;
+
+ p >>= 1;
+ p2 = p;
+ p >>= 1;
+
+ while (p >= 1) {
+ uint16_t *py = in;
+ uint16_t *ey = in + oy * (ny - p2);
+ uint16_t i00, i01, i10, i11;
+ int oy1 = oy * p;
+ int oy2 = oy * p2;
+ int ox1 = ox * p;
+ int ox2 = ox * p2;
+
+ for (; py <= ey; py += oy2) {
+ uint16_t *px = py;
+ uint16_t *ex = py + ox * (nx - p2);
+
+ for (; px <= ex; px += ox2) {
+ uint16_t *p01 = px + ox1;
+ uint16_t *p10 = px + oy1;
+ uint16_t *p11 = p10 + ox1;
+
+ if (w14) {
+ wdec14(*px, *p10, &i00, &i10);
+ wdec14(*p01, *p11, &i01, &i11);
+ wdec14(i00, i01, px, p01);
+ wdec14(i10, i11, p10, p11);
+ } else {
+ wdec16(*px, *p10, &i00, &i10);
+ wdec16(*p01, *p11, &i01, &i11);
+ wdec16(i00, i01, px, p01);
+ wdec16(i10, i11, p10, p11);
+ }
+ }
+
+ if (nx & p) {
+ uint16_t *p10 = px + oy1;
+
+ if (w14)
+ wdec14(*px, *p10, &i00, p10);
+ else
+ wdec16(*px, *p10, &i00, p10);
+
+ *px = i00;
+ }
+ }
+
+ if (ny & p) {
+ uint16_t *px = py;
+ uint16_t *ex = py + ox * (nx - p2);
+
+ for (; px <= ex; px += ox2) {
+ uint16_t *p01 = px + ox1;
+
+ if (w14)
+ wdec14(*px, *p01, &i00, p01);
+ else
+ wdec16(*px, *p01, &i00, p01);
+
+ *px = i00;
+ }
+ }
+
+ p2 = p;
+ p >>= 1;
+ }
+}
+
+static int piz_uncompress(EXRContext *s, const uint8_t *src, int ssize, int dsize, EXRThreadData *td)
+{
+ GetByteContext gb;
+ uint16_t maxval, min_non_zero, max_non_zero;
+ uint16_t *ptr, *tmp = (uint16_t *)td->tmp;
+ int8_t *out;
+ int ret, i, j;
+
+ if (!td->bitmap)
+ td->bitmap = av_malloc(BITMAP_SIZE);
+ if (!td->lut)
+ td->lut = av_malloc(1 << 17);
+ if (!td->bitmap || !td->lut)
+ return AVERROR(ENOMEM);
+
+ bytestream2_init(&gb, src, ssize);
+ min_non_zero = bytestream2_get_le16(&gb);
+ max_non_zero = bytestream2_get_le16(&gb);
+
+ if (max_non_zero >= BITMAP_SIZE)
+ return AVERROR_INVALIDDATA;
+
+ memset(td->bitmap, 0, FFMIN(min_non_zero, BITMAP_SIZE));
+ if (min_non_zero <= max_non_zero)
+ bytestream2_get_buffer(&gb, td->bitmap + min_non_zero,
+ max_non_zero - min_non_zero + 1);
+ memset(td->bitmap + max_non_zero, 0, BITMAP_SIZE - max_non_zero);
+
+ maxval = reverse_lut(td->bitmap, td->lut);
+
+ ret = huf_uncompress(&gb, tmp, dsize / sizeof(int16_t));
+ if (ret)
+ return ret;
+
+ ptr = tmp;
+ for (i = 0; i < s->nb_channels; i++) {
+ EXRChannel *channel = &s->channels[i];
+ int size = channel->pixel_type;
+
+ for (j = 0; j < size; j++)
+ wav_decode(ptr + j, s->xdelta, size, s->ysize, s->xdelta * size, maxval);
+ ptr += s->xdelta * s->ysize * size;
+ }
+
+ apply_lut(td->lut, tmp, dsize / sizeof(int16_t));
+
+ out = td->uncompressed_data;
+ for (i = 0; i < s->ysize; i++) {
+ for (j = 0; j < s->nb_channels; j++) {
+ uint16_t *in = tmp + j * s->xdelta * s->ysize + i * s->xdelta;
+ memcpy(out, in, s->xdelta * 2);
+ out += s->xdelta * 2;
+ }
+ }
+
+ return 0;
+}
+
+static int pxr24_uncompress(EXRContext *s, const uint8_t *src,
+ int compressed_size, int uncompressed_size,
+ EXRThreadData *td)
+{
+ unsigned long dest_len = uncompressed_size;
+ const uint8_t *in = td->tmp;
+ uint8_t *out;
+ int c, i, j;
+
+ if (uncompress(td->tmp, &dest_len, src, compressed_size) != Z_OK ||
+ dest_len != uncompressed_size)
+ return AVERROR(EINVAL);
+
+ out = td->uncompressed_data;
+ for (i = 0; i < s->ysize; i++) {
+ for (c = 0; c < s->nb_channels; c++) {
+ EXRChannel *channel = &s->channels[c];
+ const uint8_t *ptr[4];
+ uint32_t pixel = 0;
+
+ switch (channel->pixel_type) {
+ case EXR_FLOAT:
+ ptr[0] = in;
+ ptr[1] = ptr[0] + s->xdelta;
+ ptr[2] = ptr[1] + s->xdelta;
+ in = ptr[2] + s->xdelta;
+
+ for (j = 0; j < s->xdelta; ++j) {
+ uint32_t diff = (*(ptr[0]++) << 24) |
+ (*(ptr[1]++) << 16) |
+ (*(ptr[2]++) << 8);
+ pixel += diff;
+ bytestream_put_le32(&out, pixel);
+ }
+ break;
+ case EXR_HALF:
+ ptr[0] = in;
+ ptr[1] = ptr[0] + s->xdelta;
+ in = ptr[1] + s->xdelta;
+ for (j = 0; j < s->xdelta; j++) {
+ uint32_t diff = (*(ptr[0]++) << 8) | *(ptr[1]++);
+
+ pixel += diff;
+ bytestream_put_le16(&out, pixel);
+ }
+ break;
+ default:
+ av_assert1(0);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int decode_block(AVCodecContext *avctx, void *tdata,
+ int jobnr, int threadnr)
+{
+ EXRContext *s = avctx->priv_data;
+ AVFrame *const p = s->picture;
+ EXRThreadData *td = &s->thread_data[threadnr];
+ const uint8_t *channel_buffer[4] = { 0 };
+ const uint8_t *buf = s->buf;
+ uint64_t line_offset, uncompressed_size;
+ uint32_t xdelta = s->xdelta;
+ uint16_t *ptr_x;
+ uint8_t *ptr;
+ int32_t data_size, line;
+ const uint8_t *src;
+ int axmax = (avctx->width - (s->xmax + 1)) * 2 * s->desc->nb_components;
+ int bxmin = s->xmin * 2 * s->desc->nb_components;
+ int i, x, buf_size = s->buf_size;
+ int av_unused ret;
+
+ line_offset = AV_RL64(s->table + jobnr * 8);
+ // Check if the buffer has the required bytes needed from the offset
+ if (line_offset > buf_size - 8)
+ return AVERROR_INVALIDDATA;
+
+ src = buf + line_offset + 8;
+ line = AV_RL32(src - 8);
+ if (line < s->ymin || line > s->ymax)
+ return AVERROR_INVALIDDATA;
+
+ data_size = AV_RL32(src - 4);
+ if (data_size <= 0 || data_size > buf_size)
+ return AVERROR_INVALIDDATA;
+
+ s->ysize = FFMIN(s->scan_lines_per_block, s->ymax - line + 1);
+ uncompressed_size = s->scan_line_size * s->ysize;
+ if ((s->compr == EXR_RAW && (data_size != uncompressed_size ||
+ line_offset > buf_size - uncompressed_size)) ||
+ (s->compr != EXR_RAW && (data_size > uncompressed_size ||
+ line_offset > buf_size - data_size))) {
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (data_size < uncompressed_size) {
+ av_fast_padded_malloc(&td->uncompressed_data, &td->uncompressed_size, uncompressed_size);
+ av_fast_padded_malloc(&td->tmp, &td->tmp_size, uncompressed_size);
+ if (!td->uncompressed_data || !td->tmp)
+ return AVERROR(ENOMEM);
+
+ switch (s->compr) {
+ case EXR_ZIP1:
+ case EXR_ZIP16:
+ ret = zip_uncompress(src, data_size, uncompressed_size, td);
+ break;
+ case EXR_PIZ:
+ ret = piz_uncompress(s, src, data_size, uncompressed_size, td);
+ break;
+ case EXR_PXR24:
+ ret = pxr24_uncompress(s, src, data_size, uncompressed_size, td);
+ break;
+ case EXR_RLE:
+ ret = rle_uncompress(src, data_size, uncompressed_size, td);
+ }
+
+ src = td->uncompressed_data;
+ }
+
+ channel_buffer[0] = src + xdelta * s->channel_offsets[0];
+ channel_buffer[1] = src + xdelta * s->channel_offsets[1];
+ channel_buffer[2] = src + xdelta * s->channel_offsets[2];
+ if (s->channel_offsets[3] >= 0)
+ channel_buffer[3] = src + xdelta * s->channel_offsets[3];
+
+ ptr = p->data[0] + line * p->linesize[0];
+ for (i = 0; i < s->scan_lines_per_block && line + i <= s->ymax; i++, ptr += p->linesize[0]) {
+ const uint8_t *r, *g, *b, *a;
+
+ r = channel_buffer[0];
+ g = channel_buffer[1];
+ b = channel_buffer[2];
+ if (channel_buffer[3])
+ a = channel_buffer[3];
+
+ ptr_x = (uint16_t *)ptr;
+
+ // Zero out the start if xmin is not 0
+ memset(ptr_x, 0, bxmin);
+ ptr_x += s->xmin * s->desc->nb_components;
+ 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));
+ 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));
+ if (channel_buffer[3])
+ *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&a));
+ }
+ }
+
+ // Zero out the end if xmax+1 is not w
+ memset(ptr_x, 0, axmax);
+
+ channel_buffer[0] += s->scan_line_size;
+ channel_buffer[1] += s->scan_line_size;
+ channel_buffer[2] += s->scan_line_size;
+ if (channel_buffer[3])
+ channel_buffer[3] += s->scan_line_size;
+ }
+
+ return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx,
+ void *data,
+ int *got_frame,
+ AVPacket *avpkt)
+{
+ const uint8_t *buf = avpkt->data;
+ unsigned int buf_size = avpkt->size;
+ const uint8_t *buf_end = buf + buf_size;
+
+ EXRContext *const s = avctx->priv_data;
+ ThreadFrame frame = { .f = data };
+ AVFrame *picture = data;
+ uint8_t *ptr;
+
+ int i, y, magic_number, version, flags, ret;
+ int w = 0;
+ int h = 0;
+
+ int out_line_size;
+ int scan_line_blocks;
+
+ unsigned int current_channel_offset = 0;
+
+ s->xmin = ~0;
+ s->xmax = ~0;
+ s->ymin = ~0;
+ s->ymax = ~0;
+ s->xdelta = ~0;
+ s->ydelta = ~0;
+ s->channel_offsets[0] = -1;
+ s->channel_offsets[1] = -1;
+ s->channel_offsets[2] = -1;
+ s->channel_offsets[3] = -1;
+ s->pixel_type = -1;
+ s->nb_channels = 0;
+ s->compr = -1;
+ s->buf = buf;
+ s->buf_size = buf_size;
+
+ if (buf_size < 10) {
+ av_log(avctx, AV_LOG_ERROR, "Too short header to parse\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ magic_number = bytestream_get_le32(&buf);
+ if (magic_number != 20000630) { // As per documentation of OpenEXR it's supposed to be int 20000630 little-endian
+ av_log(avctx, AV_LOG_ERROR, "Wrong magic number %d\n", magic_number);
+ return AVERROR_INVALIDDATA;
+ }
+
+ version = bytestream_get_byte(&buf);
+ if (version != 2) {
+ avpriv_report_missing_feature(avctx, "Version %d", version);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ flags = bytestream_get_le24(&buf);
+ if (flags & 0x2) {
+ avpriv_report_missing_feature(avctx, "Tile support");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ // Parse the header
+ while (buf < buf_end && buf[0]) {
+ unsigned int variable_buffer_data_size;
+ // Process the channel list
+ if (check_header_variable(avctx, &buf, buf_end, "channels", "chlist", 38, &variable_buffer_data_size) >= 0) {
+ const uint8_t *channel_list_end;
+ if (!variable_buffer_data_size)
+ return AVERROR_INVALIDDATA;
+
+ channel_list_end = buf + variable_buffer_data_size;
+ while (channel_list_end - buf >= 19) {
+ EXRChannel *channel;
+ enum ExrPixelType current_pixel_type;
+ int channel_index = -1;
+ int xsub, ysub;
+
+ if (!strcmp(buf, "R"))
+ channel_index = 0;
+ else if (!strcmp(buf, "G"))
+ channel_index = 1;
+ else if (!strcmp(buf, "B"))
+ channel_index = 2;
+ else if (!strcmp(buf, "A"))
+ channel_index = 3;
+ else
+ av_log(avctx, AV_LOG_WARNING, "Unsupported channel %.256s\n", buf);
+
+ while (bytestream_get_byte(&buf) && buf < channel_list_end)
+ continue; /* skip */
+
+ if (channel_list_end - * &buf < 4) {
+ av_log(avctx, AV_LOG_ERROR, "Incomplete header\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ current_pixel_type = bytestream_get_le32(&buf);
+ if (current_pixel_type > 2) {
+ av_log(avctx, AV_LOG_ERROR, "Unknown pixel type\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ buf += 4;
+ xsub = bytestream_get_le32(&buf);
+ ysub = bytestream_get_le32(&buf);
+ if (xsub != 1 || ysub != 1) {
+ avpriv_report_missing_feature(avctx, "Subsampling %dx%d", xsub, ysub);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ if (channel_index >= 0) {
+ if (s->pixel_type != -1 && s->pixel_type != current_pixel_type) {
+ av_log(avctx, AV_LOG_ERROR, "RGB channels not of the same depth\n");
+ return AVERROR_INVALIDDATA;
+ }
+ s->pixel_type = current_pixel_type;
+ s->channel_offsets[channel_index] = current_channel_offset;
+ }
+
+ s->channels = av_realloc_f(s->channels, ++s->nb_channels, sizeof(EXRChannel));
+ if (!s->channels)
+ return AVERROR(ENOMEM);
+ channel = &s->channels[s->nb_channels - 1];
+ channel->pixel_type = current_pixel_type;
+ channel->xsub = xsub;
+ channel->ysub = ysub;
+
+ current_channel_offset += 1 << current_pixel_type;
+ }
+
+ /* Check if all channels are set with an offset or if the channels
+ * are causing an overflow */
+
+ if (FFMIN3(s->channel_offsets[0],
+ s->channel_offsets[1],
+ s->channel_offsets[2]) < 0) {
+ if (s->channel_offsets[0] < 0)
+ av_log(avctx, AV_LOG_ERROR, "Missing red channel\n");
+ if (s->channel_offsets[1] < 0)
+ av_log(avctx, AV_LOG_ERROR, "Missing green channel\n");
+ if (s->channel_offsets[2] < 0)
+ av_log(avctx, AV_LOG_ERROR, "Missing blue channel\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ buf = channel_list_end;
+ continue;
+ } else if (check_header_variable(avctx, &buf, buf_end, "dataWindow", "box2i", 31, &variable_buffer_data_size) >= 0) {
+ if (!variable_buffer_data_size)
+ return AVERROR_INVALIDDATA;
+
+ s->xmin = AV_RL32(buf);
+ s->ymin = AV_RL32(buf + 4);
+ s->xmax = AV_RL32(buf + 8);
+ s->ymax = AV_RL32(buf + 12);
+ s->xdelta = (s->xmax - s->xmin) + 1;
+ s->ydelta = (s->ymax - s->ymin) + 1;
+
+ buf += variable_buffer_data_size;
+ continue;
+ } else if (check_header_variable(avctx, &buf, buf_end, "displayWindow", "box2i", 34, &variable_buffer_data_size) >= 0) {
+ if (!variable_buffer_data_size)
+ return AVERROR_INVALIDDATA;
+
+ w = AV_RL32(buf + 8) + 1;
+ h = AV_RL32(buf + 12) + 1;
+
+ buf += variable_buffer_data_size;
+ continue;
+ } else if (check_header_variable(avctx, &buf, buf_end, "lineOrder", "lineOrder", 25, &variable_buffer_data_size) >= 0) {
+ if (!variable_buffer_data_size)
+ return AVERROR_INVALIDDATA;
+
+ av_log(avctx, AV_LOG_DEBUG, "line order : %d\n", *buf);
+ if (*buf > 2) {
+ av_log(avctx, AV_LOG_ERROR, "Unknown line order\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ buf += variable_buffer_data_size;
+ continue;
+ } else if (check_header_variable(avctx, &buf, buf_end, "pixelAspectRatio", "float", 31, &variable_buffer_data_size) >= 0) {
+ if (!variable_buffer_data_size)
+ return AVERROR_INVALIDDATA;
+
+ avctx->sample_aspect_ratio = av_d2q(av_int2float(AV_RL32(buf)), 255);
+
+ buf += variable_buffer_data_size;
+ continue;
+ } else if (check_header_variable(avctx, &buf, buf_end, "compression", "compression", 29, &variable_buffer_data_size) >= 0) {
+ if (!variable_buffer_data_size)
+ return AVERROR_INVALIDDATA;
+
+ if (s->compr == -1)
+ s->compr = *buf;
+ else
+ av_log(avctx, AV_LOG_WARNING, "Found more than one compression attribute\n");
+
+ buf += variable_buffer_data_size;
+ continue;
+ }
+
+ // Check if there is enough bytes for a header
+ if (buf_end - buf <= 9) {
+ av_log(avctx, AV_LOG_ERROR, "Incomplete header\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ // Process unknown variables
+ for (i = 0; i < 2; i++) {
+ // Skip variable name/type
+ while (++buf < buf_end)
+ if (buf[0] == 0x0)
+ break;
+ }
+ buf++;
+ // Skip variable length
+ if (buf_end - buf >= 5) {
+ variable_buffer_data_size = get_header_variable_length(&buf, buf_end);
+ if (!variable_buffer_data_size) {
+ av_log(avctx, AV_LOG_ERROR, "Incomplete header\n");
+ return AVERROR_INVALIDDATA;
+ }
+ buf += variable_buffer_data_size;
+ }
+ }
+
+ if (s->compr == -1) {
+ av_log(avctx, AV_LOG_ERROR, "Missing compression attribute\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (buf >= buf_end) {
+ av_log(avctx, AV_LOG_ERROR, "Incomplete frame\n");
+ return AVERROR_INVALIDDATA;
+ }
+ buf++;
+
+ switch (s->pixel_type) {
+ case EXR_FLOAT:
+ case EXR_HALF:
+ if (s->channel_offsets[3] >= 0)
+ avctx->pix_fmt = AV_PIX_FMT_RGBA64;
+ else
+ avctx->pix_fmt = AV_PIX_FMT_RGB48;
+ break;
+ case EXR_UINT:
+ avpriv_request_sample(avctx, "32-bit unsigned int");
+ return AVERROR_PATCHWELCOME;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Missing channel list\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ switch (s->compr) {
+ case EXR_RAW:
+ case EXR_RLE:
+ case EXR_ZIP1:
+ s->scan_lines_per_block = 1;
+ break;
+ case EXR_PXR24:
+ case EXR_ZIP16:
+ s->scan_lines_per_block = 16;
+ break;
+ case EXR_PIZ:
+ s->scan_lines_per_block = 32;
+ break;
+ default:
+ avpriv_report_missing_feature(avctx, "Compression %d", s->compr);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ if (av_image_check_size(w, h, 0, avctx))
+ return AVERROR_INVALIDDATA;
+
+ // Verify the xmin, xmax, ymin, ymax and xdelta before setting the actual image size
+ if (s->xmin > s->xmax ||
+ s->ymin > s->ymax ||
+ s->xdelta != s->xmax - s->xmin + 1 ||
+ s->xmax >= w || s->ymax >= h) {
+ av_log(avctx, AV_LOG_ERROR, "Wrong sizing or missing size information\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (w != avctx->width || h != avctx->height) {
+ avcodec_set_dimensions(avctx, w, h);
+ }
+
+ s->desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+ out_line_size = avctx->width * 2 * s->desc->nb_components;
+ s->scan_line_size = s->xdelta * current_channel_offset;
+ scan_line_blocks = (s->ydelta + s->scan_lines_per_block - 1) / s->scan_lines_per_block;
+
+ if (s->compr != EXR_RAW) {
+ size_t thread_data_size, prev_size;
+ EXRThreadData *m;
+
+ prev_size = s->thread_data_size;
+ if (av_size_mult(avctx->thread_count, sizeof(EXRThreadData), &thread_data_size))
+ return AVERROR(EINVAL);
+
+ m = av_fast_realloc(s->thread_data, &s->thread_data_size, thread_data_size);
+ if (!m)
+ return AVERROR(ENOMEM);
+ s->thread_data = m;
+ memset(s->thread_data + prev_size, 0, s->thread_data_size - prev_size);
+ }
+
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
+ return ret;
+
+ if (buf_end - buf < scan_line_blocks * 8)
+ return AVERROR_INVALIDDATA;
+ s->table = buf;
+ ptr = picture->data[0];
+
+ // Zero out the start if ymin is not 0
+ for (y = 0; y < s->ymin; y++) {
+ memset(ptr, 0, out_line_size);
+ ptr += picture->linesize[0];
+ }
+
+ s->picture = picture;
+ avctx->execute2(avctx, decode_block, s->thread_data, NULL, scan_line_blocks);
+
+ // Zero out the end if ymax+1 is not h
+ for (y = s->ymax + 1; y < avctx->height; y++) {
+ memset(ptr, 0, out_line_size);
+ ptr += picture->linesize[0];
+ }
+
+ picture->pict_type = AV_PICTURE_TYPE_I;
+ *got_frame = 1;
+
+ return buf_size;
+}
+
+static av_cold int decode_end(AVCodecContext *avctx)
+{
+ EXRContext *s = avctx->priv_data;
+ int i;
+
+ for (i = 0; i < s->thread_data_size / sizeof(EXRThreadData); i++) {
+ EXRThreadData *td = &s->thread_data[i];
+ av_freep(&td->uncompressed_data);
+ av_freep(&td->tmp);
+ av_freep(&td->bitmap);
+ av_freep(&td->lut);
+ }
+
+ av_freep(&s->thread_data);
+ s->thread_data_size = 0;
+ av_freep(&s->channels);
+
+ return 0;
+}
+
+AVCodec ff_exr_decoder = {
+ .name = "exr",
+ .long_name = NULL_IF_CONFIG_SMALL("OpenEXR image"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_EXR,
+ .priv_data_size = sizeof(EXRContext),
+ .close = decode_end,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS | CODEC_CAP_SLICE_THREADS,
+};
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 5cacfdd..5f34fa5 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..900851b 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,6 +285,7 @@ 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]));
@@ -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/fft-fixed-test.c b/libavcodec/fft-fixed-test.c
index 63cd194..a1a6160 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..89cd47c
--- a/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 CONFIG_FFT_FLOAT 0
+#define CONFIG_FFT_FIXED_32 1
+#include "fft-test.c"
diff --git a/libavcodec/fft-internal.h b/libavcodec/fft-internal.h
index c312625..065eecc 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 CONFIG_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 /* CONFIG_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 /* CONFIG_FFT_FIXED_32 */
+
#endif /* CONFIG_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 7e923d5..d650a10 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
*/
@@ -55,6 +55,10 @@
# define RANGE 1.0
# define REF_SCALE(x, bits) (x)
# define FMT "%10.6f"
+#elif CONFIG_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)))
@@ -149,7 +153,7 @@ static void mdct_ref(FFTSample *output, FFTSample *input, int nbits)
}
#if CONFIG_FFT_FLOAT
-static void idct_ref(float *output, float *input, int nbits)
+static void idct_ref(FFTSample *output, FFTSample *input, int nbits)
{
int n = 1<<nbits;
int k, i;
@@ -165,7 +169,7 @@ static void idct_ref(float *output, float *input, int nbits)
output[i] = 2 * s / n;
}
}
-static void dct_ref(float *output, float *input, int nbits)
+static void dct_ref(FFTSample *output, FFTSample *input, int nbits)
{
int n = 1<<nbits;
int k, i;
@@ -206,7 +210,7 @@ static int check_diff(FFTSample *tab1, FFTSample *tab2, int n, double scale)
error+= e*e;
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;
}
@@ -289,10 +293,12 @@ int main(int argc, char **argv)
scale = atof(optarg);
break;
case 'c':
- cpuflags = av_parse_cpu_flags(optarg);
- if (cpuflags < 0)
+ 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;
}
}
@@ -329,6 +335,7 @@ int main(int argc, char **argv)
ff_rdft_init(r, fft_nbits, do_inverse ? IDFT_C2R : DFT_R2C);
fft_ref_init(fft_nbits, do_inverse);
break;
+# if CONFIG_DCT
case TRANSFORM_DCT:
if (do_inverse)
av_log(NULL, AV_LOG_INFO,"DCT_III");
@@ -336,6 +343,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
#endif
default:
av_log(NULL, AV_LOG_ERROR, "Requested transform not supported\n");
@@ -409,11 +417,11 @@ int main(int argc, char **argv)
break;
case TRANSFORM_DCT:
memcpy(tab, tab1, fft_size * sizeof(FFTComplex));
- d->dct_calc(d, tab);
+ d->dct_calc(d, (FFTSample *)tab);
if (do_inverse) {
- idct_ref(tab_ref, tab1, fft_nbits);
+ idct_ref((FFTSample*)tab_ref, (FFTSample *)tab1, fft_nbits);
} else {
- dct_ref(tab_ref, tab1, fft_nbits);
+ dct_ref((FFTSample*)tab_ref, (FFTSample *)tab1, fft_nbits);
}
err = check_diff((float *)tab_ref, (float *)tab, fft_size, 1.0);
break;
@@ -478,9 +486,11 @@ int main(int argc, char **argv)
case TRANSFORM_RDFT:
ff_rdft_end(r);
break;
+# if CONFIG_DCT
case TRANSFORM_DCT:
ff_dct_end(d);
break;
+# endif
#endif
}
diff --git a/libavcodec/fft.c b/libavcodec/fft.c
index 0b8140a..e0cf1f2 100644
--- a/libavcodec/fft.c
+++ b/libavcodec/fft.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 CONFIG_FFT_FIXED_32
+#include "fft_table.h"
+#else /* CONFIG_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 /* CONFIG_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) && (!CONFIG_FFT_FIXED_32)
int i;
int m = 1<<index;
double freq = 2*M_PI/m;
@@ -157,25 +163,33 @@ av_cold int ff_fft_init(FFTContext *s, int nbits, int inverse)
s->mdct_calc = ff_mdct_calc_c;
#endif
+#if CONFIG_FFT_FIXED_32
+ {
+ int n=0;
+ ff_fft_lut_init(fft_offsets_lut, 0, 1 << 16, &n);
+ }
+#else /* CONFIG_FFT_FIXED_32 */
#if CONFIG_FFT_FLOAT
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 /* CONFIG_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;
@@ -205,6 +219,169 @@ av_cold void ff_fft_end(FFTContext *s)
av_freep(&s->tmp_buf);
}
+#if CONFIG_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;
+ FFTSample w_re, w_im;
+ FFTSample *w_re_ptr, *w_im_ptr;
+ 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 = 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 = 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++){
+ offset = 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;
+
+ w_re_ptr = w_tab_sr + step;
+ w_im_ptr = w_tab_sr + MAX_FFT_SIZE/(4*16) - step;
+
+ for (i=1; i<n4; i++){
+ w_re = w_re_ptr[0];
+ 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 /* CONFIG_FFT_FIXED_32 */
+
#define BUTTERFLIES(a0,a1,a2,a3) {\
BF(t3, t5, t5, t1);\
BF(a2.re, a0.re, a0.re, t5);\
@@ -350,3 +527,4 @@ static void fft_calc_c(FFTContext *s, FFTComplex *z)
{
fft_dispatch[s->nbits-2](z);
}
+#endif /* CONFIG_FFT_FIXED_32 */
diff --git a/libavcodec/fft.h b/libavcodec/fft.h
index d1425ad..217090c 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 CONFIG_FFT_FLOAT 1
#endif
+#ifndef CONFIG_FFT_FIXED_32
+#define CONFIG_FFT_FIXED_32 0
+#endif
+
#include <stdint.h>
#include "config.h"
#include "libavutil/mem.h"
@@ -40,15 +44,26 @@ typedef float FFTDouble;
#else
+#if CONFIG_FFT_FIXED_32
+
+#define Q31(x) (int)((x)*2147483648.0 + 0.5)
+#define FFT_NAME(x) x ## _fixed_32
+
+typedef int32_t FFTSample;
+
+#else /* CONFIG_FFT_FIXED_32 */
+
#define FFT_NAME(x) x ## _fixed
typedef int16_t FFTSample;
-typedef int FFTDouble;
+
+#endif /* CONFIG_FFT_FIXED_32 */
typedef struct FFTComplex {
- int16_t re, im;
+ FFTSample re, im;
} FFTComplex;
+typedef int FFTDouble;
typedef struct FFTContext FFTContext;
#endif /* CONFIG_FFT_FLOAT */
@@ -135,6 +150,7 @@ int ff_fft_init(FFTContext *s, int nbits, int inverse);
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 b28091d..153b7d8 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 CONFIG_FFT_FLOAT 0
+#define CONFIG_FFT_FIXED_32 0
#include "fft.c"
diff --git a/libavcodec/fft_fixed_32.c b/libavcodec/fft_fixed_32.c
new file mode 100644
index 0000000..f2954d7
--- a/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 CONFIG_FFT_FLOAT 0
+#define CONFIG_FFT_FIXED_32 1
+#include "fft.c"
diff --git a/libavcodec/fft_float.c b/libavcodec/fft_float.c
index 24c9fdb..011dc45 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 CONFIG_FFT_FLOAT 1
+#define CONFIG_FFT_FIXED_32 0
#include "fft.c"
diff --git a/libavcodec/fft_init_table.c b/libavcodec/fft_init_table.c
new file mode 100644
index 0000000..7511dbe
--- a/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"
+
+int32_t 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 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..687e5b9
--- a/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 maxiumum allowed fft size
+#define MAX_FFT_SIZE (1 << MAX_LOG2_NFFT)
+
+extern int32_t w_tab_sr[];
+extern uint16_t 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/ffv1.c b/libavcodec/ffv1.c
index a31f278..9f3206f 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,122 +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;
- s->avctx = avctx;
- s->flags = avctx->flags;
-
if (!avctx->width || !avctx->height)
return AVERROR_INVALIDDATA;
- avcodec_get_frame_defaults(&s->picture);
+ s->avctx = avctx;
+ s->flags = avctx->flags;
+ s->picture.f = avcodec_alloc_frame();
+ s->last_picture.f = av_frame_alloc();
+ if (!s->picture.f || !s->last_picture.f)
+ return AVERROR(ENOMEM);
ff_dsputil_init(&s->dsp, avctx);
s->width = avctx->width;
@@ -155,7 +65,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;
@@ -181,7 +91,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];
}
}
@@ -189,15 +99,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));
@@ -207,6 +125,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));
@@ -266,12 +188,19 @@ void ffv1_clear_slice_state(FFV1Context *f, FFV1Context *fs)
}
}
+
av_cold int ffv1_close(AVCodecContext *avctx)
{
FFV1Context *s = avctx->priv_data;
int i, j;
- av_frame_unref(&s->last_picture);
+ 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];
diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h
index 43c9607..bdc7b86 100644
--- a/libavcodec/ffv1.h
+++ b/libavcodec/ffv1.h
@@ -3,33 +3,50 @@
*
* 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 "dsputil.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
@@ -39,12 +56,6 @@
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;
@@ -72,19 +83,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 picture, 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 +108,7 @@ typedef struct FFV1Context {
int16_t *sample_buffer;
int ec;
+ int intra;
int slice_damaged;
int key_frame_ok;
@@ -115,8 +128,18 @@ typedef struct FFV1Context {
int slice_height;
int slice_x;
int slice_y;
+ int slice_reset_contexts;
+ int slice_coding_mode;
} 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)
@@ -195,11 +218,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 f0a409f..0add4ff 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,14 +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"
@@ -76,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);
@@ -107,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;
@@ -194,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++) {
@@ -230,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];
@@ -248,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 + r) >> 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;
}
}
}
@@ -273,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));
@@ -326,21 +330,60 @@ static int decode_slice_header(FFV1Context *f, FFV1Context *fs)
}
f->cur->sample_aspect_ratio.num = get_symbol(c, state, 0);
f->cur->sample_aspect_ratio.den = get_symbol(c, state, 0);
-
+ if (fs->version > 3) {
+ fs->slice_reset_contexts = get_rac(c, state);
+ fs->slice_coding_mode = get_symbol(c, state, 0);
+ }
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(CONTEXT_SIZE * psrc->context_count);
+ memcpy(pdst->state, psrc->state, CONTEXT_SIZE * psrc->context_count);
+ } else {
+ pdst->vlc_state = av_malloc(sizeof(*pdst->vlc_state) * psrc->context_count);
+ memcpy(pdst->vlc_state, psrc->vlc_state, sizeof(*pdst->vlc_state) * psrc->context_count);
+ }
+ }
+ }
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;
@@ -348,44 +391,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],
@@ -395,16 +431,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;
}
@@ -420,7 +457,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;
@@ -444,7 +481,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;
@@ -464,12 +501,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];
@@ -481,19 +521,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) {
@@ -516,6 +558,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) {
@@ -528,138 +572,135 @@ 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) {
- 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);
+ int chroma_planes, chroma_h_shift, chroma_v_shift, transparency, colorspace, bits_per_raw_sample;
+ unsigned v= get_symbol(c, state, 0);
+ if (v >= 2) {
+ av_log(f->avctx, AV_LOG_ERROR, "invalid version %d in ver01 header\n", v);
return AVERROR_INVALIDDATA;
}
f->version = v;
-
- f->ac = 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];
}
- f->colorspace = get_symbol(c, state, 0); //YUV cs type
+ colorspace = get_symbol(c, state, 0); //YUV cs type
+ bits_per_raw_sample = f->version > 0 ? get_symbol(c, state, 0) : f->avctx->bits_per_raw_sample;
+ chroma_planes = get_rac(c, state);
+ chroma_h_shift = get_symbol(c, state, 0);
+ chroma_v_shift = get_symbol(c, state, 0);
+ transparency = get_rac(c, state);
+
+ if (f->plane_count) {
+ if ( colorspace != f->colorspace
+ || bits_per_raw_sample != f->avctx->bits_per_raw_sample
+ || chroma_planes != f->chroma_planes
+ || chroma_h_shift!= f->chroma_h_shift
+ || chroma_v_shift!= f->chroma_v_shift
+ || transparency != f->transparency) {
+ av_log(f->avctx, AV_LOG_ERROR, "Invalid change of global parameters\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
- if (f->version > 0)
- f->avctx->bits_per_raw_sample = get_symbol(c, state, 0);
+ f->colorspace = colorspace;
+ f->avctx->bits_per_raw_sample = bits_per_raw_sample;
+ f->chroma_planes = chroma_planes;
+ f->chroma_h_shift = chroma_h_shift;
+ f->chroma_v_shift = chroma_v_shift;
+ f->transparency = transparency;
- f->chroma_planes = get_rac(c, state);
- f->chroma_h_shift = get_symbol(c, state, 0);
- f->chroma_v_shift = get_symbol(c, state, 0);
- f->transparency = get_rac(c, state);
f->plane_count = 2 + f->transparency;
}
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) {
@@ -668,27 +709,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);
@@ -705,16 +744,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;
}
@@ -726,23 +764,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;
}
@@ -777,12 +812,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);
+ if ((ret = ffv1_common_init(avctx)) < 0)
+ return ret;
if (avctx->extradata && (ret = read_extra_header(f)) < 0)
return ret;
@@ -790,11 +826,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;
@@ -803,10 +840,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->picture.f;
- f->cur = p;
+ if (f->version < 3 && avctx->field_order > AV_FIELD_PROGRESSIVE) {
+ /* we have interlaced material flagged in container */
+ p->interlaced_frame = 1;
+ if (avctx->field_order == AV_FIELD_TT || avctx->field_order == AV_FIELD_TB)
+ p->top_field_first = 1;
+ }
+ f->avctx = avctx;
ff_init_range_decoder(c, buf, buf_size);
ff_build_rac_states(c, 0.05 * (1LL << 32), 256 - 8);
@@ -826,27 +875,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;
@@ -856,7 +901,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;
}
}
@@ -866,56 +919,157 @@ 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] *
- (fs->slice_y >> sv) + (fs->slice_x >> sh);
+ 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.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 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 *fsrc = src->priv_data;
+ FFV1Context *fdst = dst->priv_data;
+ int i, ret;
+
+ if (dst == src)
+ return 0;
+
+ {
+ 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;
+ }
+
+ fdst->fsrc = fsrc;
+
+ return 0;
+}
+
AVCodec ff_ffv1_decoder = {
.name = "ffv1",
.long_name = NULL_IF_CONFIG_SMALL("FFmpeg video codec #1"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_FFV1,
.priv_data_size = sizeof(FFV1Context),
- .init = ffv1_decode_init,
+ .init = decode_init,
.close = ffv1_close,
- .decode = ffv1_decode_frame,
+ .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 1aec37b..59d2869 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 = 0; 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, 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 + r) >> 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);
@@ -438,14 +550,16 @@ 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);
+ 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);
+ f->micro_version = 4;
+ put_symbol(c, state, f->micro_version, 0);
}
put_symbol(c, state, f->ac, 0);
@@ -485,12 +599,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 +628,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,32 +658,21 @@ 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) {
+ if (avctx->level == 3 || (avctx->level <= 0 && s->version == 2)) {
s->version = 3;
}
@@ -578,27 +680,29 @@ static av_cold int ffv1_encode_init(AVCodecContext *avctx)
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 +710,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 +723,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 +738,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 +760,54 @@ 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);
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;
@@ -721,13 +826,12 @@ static av_cold int ffv1_encode_init(AVCodecContext *avctx)
if ((ret = ffv1_allocate_initial_states(s)) < 0)
return ret;
- avctx->coded_frame = &s->picture;
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)) {
@@ -746,7 +850,7 @@ static av_cold int ffv1_encode_init(AVCodecContext *avctx)
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);
@@ -787,45 +891,60 @@ 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)];
}
+ }
}
}
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];
@@ -847,23 +966,26 @@ 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->picture.interlaced_frame)
+ if (!f->picture.f->interlaced_frame)
put_symbol(c, state, 3, 0);
else
- put_symbol(c, state, 1 + !f->picture.top_field_first, 0);
- put_symbol(c, state, f->picture.sample_aspect_ratio.num, 0);
- put_symbol(c, state, f->picture.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);
+ }
}
static int encode_slice(AVCodecContext *c, void *arg)
@@ -874,11 +996,14 @@ static int encode_slice(AVCodecContext *c, void *arg)
int height = fs->slice_height;
int x = fs->slice_x;
int y = fs->slice_y;
- AVFrame *const p = &f->picture;
- 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;
+ 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;
+
+ fs->slice_coding_mode = 0;
+retry:
if (p->key_frame)
ffv1_clear_slice_state(f, fs);
if (f->version > 2) {
@@ -887,62 +1012,74 @@ 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);
+ 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]};
+ 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 = &f->picture;
+ 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 (f->version > 3)
+ maxsize = FF_MIN_BUFFER_SIZE + avctx->width*avctx->height*3LL*4;
- 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");
+ 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);
- *p = *pict;
+ av_frame_unref(p);
+ if ((ret = av_frame_ref(p, pict)) < 0)
+ return ret;
p->pict_type = AV_PICTURE_TYPE_I;
if (avctx->gop_size == 0 || f->picture_number % avctx->gop_size == 0) {
@@ -965,9 +1102,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,
@@ -1057,12 +1193,11 @@ static int ffv1_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
#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,
@@ -1080,23 +1215,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,
+ .init = encode_init,
+ .encode2 = encode_frame,
.close = ffv1_close,
.capabilities = CODEC_CAP_SLICE_THREADS,
.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..a62746d
--- a/dev/null
+++ b/libavcodec/ffwavesynth.c
@@ -0,0 +1,484 @@
+/*
+ * 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;
+ AVFrame frame;
+ 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;
+ avcodec_get_frame_defaults(&ws->frame);
+ avc->coded_frame = &ws->frame;
+ 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;
+ 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);
+ ws->frame.nb_samples = duration;
+ r = ff_get_buffer(avc, &ws->frame, 0);
+ if (r < 0)
+ return r;
+ pcm = (int16_t *)ws->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;
+ *(AVFrame *)rframe = ws->frame;
+ 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/flac.c b/libavcodec/flac.c
index b3e3847..3874b6c 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
*/
@@ -227,8 +227,7 @@ void avpriv_flac_parse_streaminfo(AVCodecContext *avctx, struct FLACStreaminfo *
avctx->bits_per_raw_sample = s->bps;
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 63f41c2..13e863b 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..ba1f060 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;
@@ -470,6 +490,9 @@ static int get_best_header(FLACParseContext* fpc, const uint8_t **poutbuf,
&fpc->wrap_buf_allocated_size);
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 +512,11 @@ 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;
+ }
*poutbuf = buf;
*poutbuf_size = buf_size;
return buf_size;
@@ -546,14 +572,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 +596,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",
(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 +641,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;
}
@@ -624,9 +655,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;
@@ -661,6 +695,8 @@ static av_cold int flac_parse_init(AVCodecParserContext *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));
+ if (!fpc->fifo_buf)
+ return AVERROR(ENOMEM);
return 0;
}
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 0305d50..9bf950a 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,7 @@
#include <limits.h>
+#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "libavutil/crc.h"
#include "avcodec.h"
@@ -43,6 +44,7 @@
#include "flac.h"
#include "flacdata.h"
#include "flacdsp.h"
+#include "thread.h"
typedef struct FLACContext {
FLACSTREAMINFO
@@ -127,6 +129,8 @@ static int allocate_buffers(FLACContext *s)
{
int buf_size;
+ av_assert0(s->max_blocksize);
+
buf_size = av_samples_get_buffer_size(NULL, s->channels, s->max_blocksize,
AV_SAMPLE_FMT_S32P, 0);
if (buf_size < 0)
@@ -247,7 +251,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++) {
@@ -485,6 +490,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;
@@ -499,6 +505,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, "skiping 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, "skiping 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 */
@@ -515,19 +531,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);
@@ -546,6 +569,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;
@@ -564,10 +598,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..02eba3e 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
*/
diff --git a/libavcodec/flacdsp.h b/libavcodec/flacdsp.h
index 33184b5..5e66dc2 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
*/
diff --git a/libavcodec/flacdsp_lpc_template.c b/libavcodec/flacdsp_lpc_template.c
index 269e64b..0c453ae 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
*/
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 58e86be..1fc8c4c 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 "dsputil.h"
-#include "get_bits.h"
+#include "put_bits.h"
#include "golomb.h"
#include "internal.h"
#include "lpc.h"
@@ -153,7 +154,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++) {
@@ -247,8 +248,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 */
@@ -274,7 +278,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;
}
@@ -289,7 +294,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];
@@ -328,13 +333,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;
}
@@ -345,20 +350,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) {
@@ -366,7 +371,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);
@@ -394,6 +399,28 @@ 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);
@@ -616,9 +643,9 @@ 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;
@@ -1243,10 +1270,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);
@@ -1290,7 +1315,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" },
@@ -1325,7 +1350,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 e9749fe..3d185d5 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
*/
@@ -126,6 +126,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;
@@ -136,7 +139,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;
@@ -241,6 +245,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)
@@ -256,6 +262,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)) {
@@ -301,8 +311,7 @@ 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;
+ avcodec_set_dimensions(avctx, s->image_width, s->image_height);
}
/* check for changes of image width and image height */
@@ -319,19 +328,17 @@ static int flashsv_decode_frame(AVCodecContext *avctx, void *data,
if (s->is_keyframe) {
s->keyframedata = av_realloc(s->keyframedata, avpkt->size);
memcpy(s->keyframedata, avpkt->data, avpkt->size);
- s->blocks = av_realloc(s->blocks,
- (v_blocks + !!v_part) * (h_blocks + !!h_part)
- * sizeof(s->blocks[0]));
}
+ 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++) {
@@ -380,6 +387,10 @@ static int flashsv_decode_frame(AVCodecContext *avctx, void *data,
}
s->diff_start = get_bits(&gb, 8);
s->diff_height = get_bits(&gb, 8);
+ if (s->diff_start + s->diff_height > cur_blk_height) {
+ av_log(avctx, AV_LOG_ERROR, "Block parameters invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
av_log(avctx, AV_LOG_DEBUG,
"%dx%d diff start %d height %d\n",
i, j, s->diff_start, s->diff_height);
diff --git a/libavcodec/flashsv2enc.c b/libavcodec/flashsv2enc.c
new file mode 100644
index 0000000..2115a46
--- a/dev/null
+++ b/libavcodec/flashsv2enc.c
@@ -0,0 +1,931 @@
+/*
+ * 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;
+ AVFrame 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 4096x4096 !\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
+}
+
+static const double block_size_fraction = 1.0 / 300;
+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 const double use15_7_threshold = 8192;
+
+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 const double color15_7_factor = 100;
+
+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 *pict, int *got_packet)
+{
+ FlashSV2Context *const s = avctx->priv_data;
+ AVFrame *const p = &s->frame;
+ int res;
+ int keyframe = 0;
+
+ *p = *pict;
+
+ 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);
+ p->pict_type = AV_PICTURE_TYPE_I;
+ p->key_frame = 1;
+ 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);
+ } else {
+ p->pict_type = AV_PICTURE_TYPE_P;
+ p->key_frame = 0;
+ }
+
+ avctx->coded_frame = p;
+
+ 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 bbfb41c..ee67652 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
*/
@@ -228,12 +228,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 ff1d820..76a7976 100644
--- a/libavcodec/flicvideo.c
+++ b/libavcodec/flicvideo.c
@@ -2,20 +2,20 @@
* FLI/FLC Animation Video Decoder
* 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);
@@ -136,7 +154,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;
@@ -168,14 +185,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 */
@@ -183,15 +202,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
@@ -214,6 +240,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;
@@ -224,26 +253,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
@@ -262,6 +287,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;
@@ -278,6 +305,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);
}
@@ -300,16 +329,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);
}
@@ -346,6 +381,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");
@@ -365,6 +402,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--;
@@ -381,9 +420,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;
@@ -396,7 +435,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:
@@ -404,14 +442,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));
@@ -464,10 +504,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];
@@ -476,14 +514,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:
@@ -501,6 +551,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;
@@ -512,6 +564,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;
@@ -525,6 +579,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);
@@ -559,6 +615,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);
@@ -572,6 +630,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);
@@ -611,6 +671,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);
@@ -625,6 +687,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 3d9a2d5..16bc88b 100644
--- a/libavcodec/flv.h
+++ b/libavcodec/flv.h
@@ -1,19 +1,19 @@
/*
* 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
*/
diff --git a/libavcodec/flvdec.c b/libavcodec/flvdec.c
index 665208a..3e55aaf 100644
--- a/libavcodec/flvdec.c
+++ b/libavcodec/flvdec.c
@@ -1,19 +1,19 @@
/*
* 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
*/
@@ -40,12 +40,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 */
@@ -84,7 +84,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;
@@ -107,6 +107,9 @@ int ff_flv_decode_picture_header(MpegEncContext *s)
}
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,5 +132,6 @@ 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 = ff_pixfmt_list_420,
};
diff --git a/libavcodec/flvenc.c b/libavcodec/flvenc.c
index fbdb23d..9421955 100644
--- a/libavcodec/flvenc.c
+++ b/libavcodec/flvenc.c
@@ -1,19 +1,19 @@
/*
* 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..b9acefc
--- a/dev/null
+++ b/libavcodec/frame_thread_encoder.c
@@ -0,0 +1,270 @@
+/*
+ * 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->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(sizeof(Task) * BUFFER_SIZE);
+ 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_free(c->task_fifo); c->task_fifo = NULL;
+ 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
--- a/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 438c215..225da11 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,15 +37,16 @@
#include "bytestream.h"
#include "dsputil.h"
#include "internal.h"
+#include "thread.h"
#define FPS_TAG MKTAG('F', 'P', 'S', 'x')
+#define VLC_BITS 11
/**
* local variable storage
*/
typedef struct FrapsContext {
AVCodecContext *avctx;
- AVFrame frame;
uint8_t *tmpbuf;
int tmpbuf_size;
DSPContext dsp;
@@ -61,13 +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;
- avcodec_get_frame_defaults(&s->frame);
-
ff_dsputil_init(&s->dsp, avctx);
return 0;
@@ -98,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 */
@@ -109,7 +107,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
*/
@@ -135,17 +133,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");
@@ -155,7 +153,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,
@@ -164,87 +161,91 @@ 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;
- expected_size = header_size;
+ 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;
+
+ 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:
@@ -253,37 +254,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,
@@ -297,36 +269,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) {
@@ -334,18 +277,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;
@@ -361,8 +306,6 @@ static av_cold int decode_end(AVCodecContext *avctx)
{
FrapsContext *s = (FrapsContext*)avctx->priv_data;
- av_frame_unref(&s->frame);
-
av_freep(&s->tmpbuf);
return 0;
}
@@ -377,5 +320,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 e7743e7..1667149 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
*/
@@ -389,7 +389,7 @@ static int kempf_decode_tile(G2MContext *c, int tile_x, int tile_y,
return 0;
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);
@@ -411,6 +411,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;
}
@@ -441,8 +443,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)
@@ -451,7 +453,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);
@@ -488,7 +490,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, c->cursor_fmt==1 ? 32 : 1) * 4;
if (cursor_w < 1 || cursor_w > 256 ||
cursor_h < 1 || cursor_h > 256) {
@@ -540,7 +542,6 @@ static int g2m_load_cursor(AVCodecContext *avctx, G2MContext *c,
bits <<= 1;
}
}
- dst += c->cursor_stride - c->cursor_w * 4;
}
dst = c->cursor;
@@ -566,7 +567,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
@@ -580,7 +580,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:
@@ -802,11 +801,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..470fbbf 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
*/
@@ -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 e7b67da..c4d6c7b 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..09da766 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,1138 @@ 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);
+ }
+
+ 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 = (const int16_t *)frame->data[0];
+
+ HFParam hf[4];
+ int i, j;
+
+ 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;
+ }
+
+ 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/g729.h b/libavcodec/g729.h
new file mode 100644
index 0000000..6168313
--- a/dev/null
+++ b/libavcodec/g729.h
@@ -0,0 +1,29 @@
+/*
+ * G.729, G729 Annex D decoders
+ * Copyright (c) 2008 Vladimir Voroshilov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef AVCODEC_G729_H
+#define AVCODEC_G729_H
+
+/**
+ * subframe size
+ */
+#define SUBFRAME_SIZE 40
+
+#endif // AVCODEC_G729_H
diff --git a/libavcodec/g729data.h b/libavcodec/g729data.h
new file mode 100644
index 0000000..365ca47
--- a/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..d29ad1f
--- a/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 "dsputil.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 {
+ DSPContext dsp;
+
+ /// 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_dsputil_init(&ctx->dsp, avctx);
+ ctx->dsp.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->dsp, 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->dsp,
+ &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..fc90374
--- a/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(DSPContext *dsp, 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 = dsp->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 = dsp->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 = dsp->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 = dsp->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 = dsp->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 = dsp->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 = dsp->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(DSPContext *dsp, 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 = dsp->scalarproduct_int16(lp_gn + 10, lp_gn + 10, 20);
+ rh1 = dsp->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(DSPContext *dsp, 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(dsp, 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(dsp, 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..5239fc8
--- a/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 "dsputil.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(DSPContext *dsp, 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 5a0089a..4ddb088 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
@@ -65,6 +64,7 @@ typedef struct VLC {
int bits;
VLC_TYPE (*table)[2]; ///< code, bits
int table_size, table_allocated;
+ void * volatile init_state;
} VLC;
typedef struct RL_VLC_ELEM {
@@ -126,7 +126,7 @@ typedef struct RL_VLC_ELEM {
#if UNCHECKED_BITSTREAM_READER
#define OPEN_READER(name, gb) \
unsigned int name ## _index = (gb)->index; \
- unsigned int av_unused name ## _cache = 0
+ unsigned int av_unused name ## _cache
#define HAVE_BITS_REMAINING(name, gb) 1
#else
@@ -140,27 +140,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)
@@ -181,12 +188,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)
@@ -215,6 +228,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;
@@ -227,6 +241,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);
@@ -241,6 +256,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);
@@ -248,6 +264,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.
*/
@@ -255,6 +283,7 @@ static inline unsigned int show_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);
return tmp;
@@ -263,7 +292,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);
}
@@ -303,20 +331,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)
@@ -378,7 +408,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) {
buffer_size = bit_size = 0;
buffer = NULL;
ret = AVERROR_INVALIDDATA;
@@ -388,9 +418,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;
@@ -408,8 +436,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);
}
diff --git a/libavcodec/gif.c b/libavcodec/gif.c
index 4dc124f..8b9d95f 100644
--- a/libavcodec/gif.c
+++ b/libavcodec/gif.c
@@ -1,114 +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 {
- AVFrame picture;
+ 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);
@@ -123,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;
}
@@ -131,37 +211,59 @@ static av_cold int gif_encode_init(AVCodecContext *avctx)
{
GIFContext *s = avctx->priv_data;
- avctx->coded_frame = &s->picture;
+ if (avctx->width > 65535 || avctx->height > 65535) {
+ av_log(avctx, AV_LOG_ERROR, "GIF does not support resolutions above 65535x65535\n");
+ return AVERROR(EINVAL);
+ }
+
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;
- AVFrame *const p = &s->picture;
+ AVFrame *const p = (AVFrame *)pict;
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;
- *p = *pict;
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
- 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, p->data[1], AVPALETTE_SIZE);
+ palette = (uint32_t*)p->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;
@@ -176,9 +278,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)"),
@@ -192,4 +312,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
--- a/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 a233797..4151b88 100644
--- a/libavcodec/gifdec.c
+++ b/libavcodec/gifdec.c
@@ -2,120 +2,248 @@
* 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;
+
+ GetByteContext gb;
/* LZW compatible decoder */
- const uint8_t *bytestream;
- const uint8_t *bytestream_end;
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 = bytestream_get_le16(&s->bytestream);
- top = bytestream_get_le16(&s->bytestream);
- width = bytestream_get_le16(&s->bytestream);
- height = bytestream_get_le16(&s->bytestream);
- flags = bytestream_get_byte(&s->bytestream);
+ 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) {
- bytestream_get_buffer(&s->bytestream, 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)
- return AVERROR(EINVAL);
-
- /* 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;
+ return AVERROR_INVALIDDATA;
+ if (width <= 0 || height <= 0)
+ return AVERROR_INVALIDDATA;
+
+ /* 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 = width; s->gce_h = height;
+
+ 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, width, 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 = bytestream_get_byte(&s->bytestream);
- ff_lzw_decode_init(s->lzw, code_size, s->bytestream,
- s->bytestream_end - s->bytestream, 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);
+ if (ff_lzw_decode(s->lzw, s->idx_line, width) == 0)
+ goto decode_tail;
+
+ pr = ptr + width;
+
+ 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:
@@ -147,52 +275,76 @@ static int gif_read_image(GifState *s, AVFrame *frame)
ptr += linesize;
}
}
+
+ decode_tail:
/* read the garbage data until end marker is found */
ff_lzw_decode_tail(s->lzw);
- s->bytestream = ff_lzw_cur_ptr(s->lzw);
+
+ /* Graphic Control Extension's scope is single frame.
+ * Remove its influence. */
+ s->transparent_color_index = -1;
+ s->gce_disposal = GCE_DISPOSAL_NONE;
+
return 0;
}
static int gif_read_extension(GifState *s)
{
- int ext_code, ext_len, i, gce_flags, gce_transparent_index;
+ int ext_code, ext_len, gce_flags, gce_transparent_index;
+
+ /* There must be at least 2 bytes:
+ * 1 for extension label and 1 for extension length. */
+ if (bytestream2_get_bytes_left(&s->gb) < 2)
+ return AVERROR_INVALIDDATA;
- /* extension */
- ext_code = bytestream_get_byte(&s->bytestream);
- ext_len = bytestream_get_byte(&s->bytestream);
+ 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 = bytestream_get_byte(&s->bytestream);
- s->gce_delay = bytestream_get_le16(&s->bytestream);
- gce_transparent_index = bytestream_get_byte(&s->bytestream);
+
+ /* 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 = bytestream_get_byte(&s->bytestream);
+ 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++)
- bytestream_get_byte(&s->bytestream);
- ext_len = bytestream_get_byte(&s->bytestream);
+ 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;
- av_dlog(s->avctx, "gif: ext_len1=%d\n", ext_len);
+ bytestream2_skipu(&s->gb, ext_len);
+ ext_len = bytestream2_get_byteu(&s->gb);
+
+ av_dlog(s->avctx, "ext_len1=%d\n", ext_len);
}
return 0;
}
@@ -201,70 +353,75 @@ static int gif_read_header1(GifState *s)
{
uint8_t sig[6];
int v, n;
- int has_global_palette;
+ int background_color_index;
- if (s->bytestream_end < s->bytestream + 13)
+ if (bytestream2_get_bytes_left(&s->gb) < 13)
return AVERROR_INVALIDDATA;
/* read gif signature */
- bytestream_get_buffer(&s->bytestream, 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 = bytestream_get_le16(&s->bytestream);
- s->screen_height = bytestream_get_le16(&s->bytestream);
- 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 = bytestream_get_byte(&s->bytestream);
+ 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 = bytestream_get_byte(&s->bytestream);
- bytestream_get_byte(&s->bytestream); /* 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 (s->bytestream_end < s->bytestream + n * 3)
+ if (bytestream2_get_bytes_left(&s->gb) < n * 3)
return AVERROR_INVALIDDATA;
- bytestream_get_buffer(&s->bytestream, 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;
}
static int gif_parse_next_image(GifState *s, AVFrame *frame)
{
- while (s->bytestream < s->bytestream_end) {
- int code = bytestream_get_byte(&s->bytestream);
+ while (bytestream2_get_bytes_left(&s->gb)) {
+ 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)
@@ -273,40 +430,76 @@ 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;
- s->bytestream = buf;
- s->bytestream_end = 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;
- if ((ret = av_image_check_size(s->screen_width, s->screen_height, 0, avctx)) < 0)
- return ret;
- avcodec_set_dimensions(avctx, s->screen_width, s->screen_height);
+ 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_get_buffer(avctx, picture, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- 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;
}
- s->image_palette = (uint32_t *)picture->data[1];
- ret = gif_parse_next_image(s, picture);
+
+ 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 = av_image_check_size(s->screen_width, s->screen_height, 0, avctx)) < 0)
+ return ret;
+ avcodec_set_dimensions(avctx, s->screen_width, s->screen_height);
+
+ 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;
+ }
+
+ 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 s->bytestream - buf;
+
+ return avpkt->size;
}
static av_cold int gif_decode_close(AVCodecContext *avctx)
@@ -314,9 +507,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)"),
@@ -327,4 +540,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..8adcdf6 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
*/
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 efe5059..43875dc 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 (HAVE_BITS_REMAINING(re, gb));
+ } while (ret<0x8000000U && HAVE_BITS_REMAINING(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);
@@ -316,7 +324,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 && HAVE_BITS_REMAINING(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);
}
@@ -455,7 +465,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) {
@@ -476,8 +486,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);
@@ -514,7 +524,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)
@@ -531,7 +541,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 c7c3e22..e56f4cd 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 1d381fc..f76bbef 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
*/
@@ -54,7 +54,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 642f3b7..7ca9677 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
*/
@@ -34,9 +34,18 @@
static av_cold int gsm_init(AVCodecContext *avctx)
{
+ if (avctx->codec_tag == 0x0032 &&
+ avctx->bit_rate != 13000 &&
+ avctx->bit_rate != 17912 &&
+ avctx->bit_rate != 35824 &&
+ avctx->bit_rate != 71656) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported audio mode\n");
+ return AVERROR_PATCHWELCOME;
+ }
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;
switch (avctx->codec_id) {
@@ -69,10 +78,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) {
@@ -101,6 +108,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"),
@@ -112,7 +120,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"),
@@ -124,3 +133,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 8b75bb6..4324ea2 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 7a81da9..fd89ed6 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 b5222af..0f55953 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..597bf7e 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
*/
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 eb8e64a..0d1f305 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 479da77..5e45fc7 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 "mpegvideo.h"
#include "h263.h"
@@ -129,7 +130,7 @@ static int h261_decode_gob_header(H261Context *h)
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;
}
@@ -376,11 +377,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
@@ -637,12 +639,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 +670,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 4cff998..d7f40de 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,6 +26,7 @@
*/
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "mpegvideo.h"
#include "h263.h"
@@ -212,8 +213,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);
@@ -267,7 +268,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)
@@ -296,7 +297,7 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64],
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]);
diff --git a/libavcodec/h263.c b/libavcodec/h263.c
index 0a7ec87..eda61f6 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 4f58f92..0995494 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
@@ -63,8 +63,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];
@@ -116,7 +116,7 @@ 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);
+const uint8_t *ff_h263_find_resync_marker(MpegEncContext *s, 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 e3b83ad..e245e2f 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 8060d8f..40d2237 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"
@@ -36,6 +38,7 @@
#include "mpeg4video_parser.h"
#include "mpegvideo.h"
#include "msmpeg4.h"
+#include "vdpau_internal.h"
#include "thread.h"
av_cold int ff_h263_decode_init(AVCodecContext *avctx)
@@ -63,6 +66,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;
@@ -110,8 +114,12 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx)
s->codec_id = avctx->codec->id;
avctx->hwaccel = ff_find_hwaccel(avctx->codec->id, avctx->pix_fmt);
+ 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)
if ((ret = ff_MPV_common_init(s)) < 0)
return ret;
@@ -162,7 +170,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;
@@ -174,10 +182,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) {
@@ -277,7 +285,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) &&
@@ -290,7 +298,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->resync_marker &&
!s->data_partitioning) {
const int bits_count = get_bits_count(&s->gb);
@@ -332,7 +340,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;
@@ -367,6 +375,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;
@@ -393,6 +402,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");
@@ -404,13 +415,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;
@@ -437,11 +462,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(s, &gb);
+ if (init_get_bits8(&gb, s->avctx->extradata, s->avctx->extradata_size) >= 0 )
+ ff_mpeg4_decode_picture_header(s, &gb);
}
ret = ff_mpeg4_decode_picture_header(s, &s->gb);
} else if (CONFIG_H263I_DECODER && s->codec_id == AV_CODEC_ID_H263I) {
@@ -452,6 +474,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);
@@ -586,7 +616,7 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
(av_get_cpu_flags() & AV_CPU_FLAG_MMX)) {
avctx->idct_algo = FF_IDCT_XVIDMMX;
ff_dct_common_init(s);
- s->picture_number = 0;
+ goto retry;
}
#endif
@@ -647,6 +677,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(s, 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);
@@ -664,14 +699,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 ||
@@ -689,7 +724,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 &&
@@ -698,28 +733,36 @@ 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);
- /* divx 5.01+ bistream reorder stuff */
+ av_assert1(s->bitstream_buffer_size == 0);
+frame_end:
+ ff_er_frame_end(&s->er);
+
+ if (avctx->hwaccel) {
+ ret = avctx->hwaccel->end_frame(avctx);
+ if (ret < 0)
+ return ret;
+ }
+
+ ff_MPV_frame_end(s);
+
+ /* 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->codec_id == AV_CODEC_ID_MPEG4 && 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 &&
- s->xvid_build >= 0) { // xvid style
- startcode_found = 1;
- current_pos = 0;
- }
if (startcode_found) {
av_fast_malloc(&s->bitstream_buffer,
@@ -734,37 +777,43 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
}
}
-intrax8_decoded:
- ff_er_frame_end(&s->er);
-
- if (avctx->hwaccel) {
- ret = avctx->hwaccel->end_frame(avctx);
- if (ret < 0)
- return ret;
- }
-
- ff_MPV_frame_end(s);
-
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 != NULL) {
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);
@@ -793,5 +842,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/h264.c b/libavcodec/h264.c
index d093928..cd6fff8 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,8 +25,11 @@
* @author Michael Niedermayer <michaelni@gmx.at>
*/
+#define UNCHECKED_BITSTREAM_READER 1
+
#include "libavutil/avassert.h"
#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
#include "internal.h"
#include "cabac.h"
#include "cabac_functions.h"
@@ -43,31 +46,38 @@
#include "rectangle.h"
#include "svq3.h"
#include "thread.h"
+#include "vdpau_internal.h"
#include <assert.h>
+static void flush_change(H264Context *h);
+
const uint16_t ff_h264_mb_sizes[4] = { 256, 384, 512, 768 };
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,
@@ -86,7 +96,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,
@@ -106,7 +116,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,
@@ -181,6 +191,12 @@ static const enum AVPixelFormat h264_hwaccel_pixfmt_list_jpeg_420[] = {
AV_PIX_FMT_NONE
};
+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)
@@ -191,19 +207,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);
}
@@ -336,6 +361,10 @@ static int ref_picture(H264Context *h, Picture *dst, Picture *src)
dst->field_picture = src->field_picture;
dst->needs_realloc = src->needs_realloc;
dst->reference = src->reference;
+ dst->sync = src->sync;
+ dst->crop = src->crop;
+ dst->crop_left = src->crop_left;
+ dst->crop_top = src->crop_top;
return 0;
fail:
@@ -409,6 +438,9 @@ static int alloc_picture(H264Context *h, Picture *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;
@@ -532,10 +564,10 @@ int ff_h264_check_intra4x4_pred_mode(H264Context *h)
*/
int ff_h264_check_intra_pred_mode(H264Context *h, int mode, int is_chroma)
{
- static const int8_t top[7] = { LEFT_DC_PRED8x8, 1, -1, -1 };
- static const int8_t left[7] = { TOP_DC_PRED8x8, -1, 2, -1, DC_128_PRED8x8 };
+ static const int8_t top[4] = { LEFT_DC_PRED8x8, 1, -1, -1 };
+ static const int8_t left[5] = { TOP_DC_PRED8x8, -1, 2, -1, DC_128_PRED8x8 };
- if (mode > 6U) {
+ if (mode > 3U) {
av_log(h->avctx, AV_LOG_ERROR,
"out of range intra chroma pred mode at %d %d\n",
h->mb_x, h->mb_y);
@@ -632,21 +664,27 @@ 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);
+
+ si = h->rbsp_buffer_size[bufidx];
+ av_fast_padded_malloc(&h->rbsp_buffer[bufidx], &h->rbsp_buffer_size[bufidx], length+MAX_MBPAIR_SIZE);
dst = h->rbsp_buffer[bufidx];
if (dst == NULL)
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) {
@@ -702,13 +740,13 @@ static inline int get_lowest_part_list_y(H264Context *h, Picture *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,
@@ -780,7 +818,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];
@@ -812,7 +850,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,
@@ -896,7 +934,7 @@ static av_always_inline void mc_dir_part(H264Context *h, Picture *pic,
full_my < 0 - extra_height ||
full_mx + 16 /*FIXME*/ > pic_width + extra_width ||
full_my + 16 /*FIXME*/ > pic_height + extra_height) {
- h->vdsp.emulated_edge_mc(h->edge_emu_buffer,
+ h->vdsp.emulated_edge_mc(h->edge_emu_buffer, h->mb_linesize,
src_y - (2 << pixel_shift) - 2 * h->mb_linesize,
h->mb_linesize,
16 + 5, 16 + 5 /*FIXME*/, full_mx - 2,
@@ -915,7 +953,7 @@ static av_always_inline void mc_dir_part(H264Context *h, Picture *pic,
if (chroma_idc == 3 /* yuv444 */) {
src_cb = pic->f.data[1] + offset;
if (emu) {
- h->vdsp.emulated_edge_mc(h->edge_emu_buffer,
+ h->vdsp.emulated_edge_mc(h->edge_emu_buffer, h->mb_linesize,
src_cb - (2 << pixel_shift) - 2 * h->mb_linesize,
h->mb_linesize,
16 + 5, 16 + 5 /*FIXME*/,
@@ -929,7 +967,7 @@ static av_always_inline void mc_dir_part(H264Context *h, Picture *pic,
src_cr = pic->f.data[2] + offset;
if (emu) {
- h->vdsp.emulated_edge_mc(h->edge_emu_buffer,
+ h->vdsp.emulated_edge_mc(h->edge_emu_buffer, h->mb_linesize,
src_cr - (2 << pixel_shift) - 2 * h->mb_linesize,
h->mb_linesize,
16 + 5, 16 + 5 /*FIXME*/,
@@ -956,7 +994,7 @@ static av_always_inline void mc_dir_part(H264Context *h, Picture *pic,
(my >> ysh) * h->mb_uvlinesize;
if (emu) {
- h->vdsp.emulated_edge_mc(h->edge_emu_buffer, src_cb, h->mb_uvlinesize,
+ h->vdsp.emulated_edge_mc(h->edge_emu_buffer, h->mb_uvlinesize, src_cb, h->mb_uvlinesize,
9, 8 * chroma_idc + 1, (mx >> 3), (my >> ysh),
pic_width >> 1, pic_height >> (chroma_idc == 1 /* yuv420 */));
src_cb = h->edge_emu_buffer;
@@ -966,7 +1004,7 @@ static av_always_inline void mc_dir_part(H264Context *h, Picture *pic,
mx & 7, (my << (chroma_idc == 2 /* yuv422 */)) & 7);
if (emu) {
- h->vdsp.emulated_edge_mc(h->edge_emu_buffer, src_cr, h->mb_uvlinesize,
+ h->vdsp.emulated_edge_mc(h->edge_emu_buffer, h->mb_uvlinesize, src_cr, h->mb_uvlinesize,
9, 8 * chroma_idc + 1, (mx >> 3), (my >> ysh),
pic_width >> 1, pic_height >> (chroma_idc == 1 /* yuv420 */));
src_cr = h->edge_emu_buffer;
@@ -1147,9 +1185,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);
}
}
@@ -1174,6 +1210,9 @@ static void free_tables(H264Context *h, int free_rbsp)
av_freep(&h->mb2b_xy);
av_freep(&h->mb2br_xy);
+ for (i = 0; i < 3; i++)
+ av_freep(&h->visualization_buffer[i]);
+
av_buffer_pool_uninit(&h->qscale_table_pool);
av_buffer_pool_uninit(&h->mb_type_pool);
av_buffer_pool_uninit(&h->motion_val_pool);
@@ -1290,7 +1329,7 @@ static void init_dequant_tables(H264Context *h)
int ff_h264_alloc_tables(H264Context *h)
{
const int big_mb_num = h->mb_stride * (h->mb_height + 1);
- const int row_mb_num = h->mb_stride * 2 * h->avctx->thread_count;
+ const int row_mb_num = 2*h->mb_stride*FFMAX(h->avctx->thread_count, 1);
int x, y, i;
FF_ALLOCZ_OR_GOTO(h->avctx, h->intra4x4_pred_mode,
@@ -1450,18 +1489,21 @@ 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 too short\n");
return AVERROR_INVALIDDATA;
}
@@ -1473,7 +1515,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) {
@@ -1487,7 +1529,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) {
@@ -1498,14 +1540,14 @@ int ff_h264_decode_extradata(H264Context *h)
p += nalsize;
}
// Now 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)
@@ -1519,12 +1561,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)
@@ -1558,18 +1605,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);
if (avctx->codec_id == AV_CODEC_ID_H264) {
- if (avctx->ticks_per_frame == 1)
- h->avctx->time_base.den *= 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 &&
@@ -1580,6 +1635,8 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)
avctx->internal->allocate_progress = 1;
+ flush_change(h);
+
return 0;
}
@@ -1634,6 +1691,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;
@@ -1655,7 +1716,7 @@ static int decode_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 &&
@@ -1681,6 +1742,17 @@ static int decode_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");
@@ -1688,14 +1760,19 @@ static int decode_update_thread_context(AVCodecContext *dst,
}
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++)
@@ -1704,19 +1781,21 @@ static int decode_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->me, 0, sizeof(h->me));
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));
- avcodec_get_frame_defaults(&h->cur_pic.f);
- h->cur_pic.tf.f = &h->cur_pic.f;
h->avctx = dst;
h->DPB = NULL;
@@ -1724,6 +1803,17 @@ static int decode_update_thread_context(AVCodecContext *dst,
h->mb_type_pool = NULL;
h->ref_index_pool = NULL;
h->motion_val_pool = 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));
+ avcodec_get_frame_defaults(&h->cur_pic.f);
+ h->cur_pic.tf.f = &h->cur_pic.f;
ret = ff_h264_alloc_tables(h);
if (ret < 0) {
@@ -1735,17 +1825,13 @@ static int decode_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;
@@ -1760,7 +1846,7 @@ static int decode_update_thread_context(AVCodecContext *dst,
h->data_partitioning = h1->data_partitioning;
h->low_delay = h1->low_delay;
- for (i = 0; i < MAX_PICTURE_COUNT; i++) {
+ for (i = 0; h->DPB && i < MAX_PICTURE_COUNT; i++) {
unref_picture(h, &h->DPB[i]);
if (h1->DPB[i].f.data[0] &&
(ret = ref_picture(h, &h->DPB[i], &h1->DPB[i])) < 0)
@@ -1769,19 +1855,13 @@ static int decode_update_thread_context(AVCodecContext *dst,
h->cur_pic_ptr = REBASE_PICTURE(h1->cur_pic_ptr, h, h1);
unref_picture(h, &h->cur_pic);
- if ((ret = ref_picture(h, &h->cur_pic, &h1->cur_pic)) < 0)
+ if (h1->cur_pic.f.buf[0] && (ret = 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;
@@ -1822,7 +1902,7 @@ static int decode_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->sync = h1->sync;
if (context_reinitialized)
h264_set_parameter_from_sps(h);
@@ -1847,6 +1927,17 @@ static int h264_frame_start(H264Context *h)
Picture *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;
@@ -1861,24 +1952,32 @@ 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.
* See decode_nal_units().
*/
pic->f.key_frame = 0;
+ pic->sync = 0;
pic->mmco_reset = 0;
if ((ret = alloc_picture(h, pic)) < 0)
return ret;
+ if(!h->sync && !h->avctx->hwaccel &&
+ !(h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU))
+ avpriv_color_frame(&pic->f, c);
h->cur_pic_ptr = pic;
unref_picture(h, &h->cur_pic);
if ((ret = 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);
+ h->er.last_pic =
+ h->er.next_pic = NULL;
+ }
assert(h->linesize && h->uvlinesize);
@@ -1893,22 +1992,8 @@ 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));
-
- // s->decode = (s->flags & CODEC_FLAG_PSNR) || !s->encoding ||
- // s->current_picture.f.reference /* || h->contains_intra */ || 1;
+ // s->decode = (h->flags & CODEC_FLAG_PSNR) || !s->encoding ||
+ // h->cur_pic.reference /* || h->contains_intra */ || 1;
/* 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
@@ -1938,7 +2023,6 @@ static void decode_postinit(H264Context *h, int setup_finished)
Picture *out = h->cur_pic_ptr;
Picture *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;
@@ -2020,6 +2104,8 @@ static void decode_postinit(H264Context *h, int setup_finished)
}
}
+ cur->mmco_reset = h->mmco_reset;
+ h->mmco_reset = 0;
// FIXME do something with unavailable reference frames
/* Sort B-frames into display order */
@@ -2036,107 +2122,75 @@ 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 = 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 && h->next_output_pic->sync) {
+ h->sync |= 2;
}
if (setup_finished && !h->avctx->hwaccel)
@@ -2299,23 +2353,21 @@ 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_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);
- }
- XCHG(top_border + (16 << pixel_shift), src_cb + (1 << pixel_shift), xchg);
- XCHG(top_border + (24 << pixel_shift), src_cb + (9 << pixel_shift), 1);
- XCHG(top_border + (32 << pixel_shift), src_cr + (1 << pixel_shift), xchg);
- XCHG(top_border + (40 << pixel_shift), src_cr + (9 << pixel_shift), 1);
- if (h->mb_x + 1 < h->mb_width) {
- 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) {
+ 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);
+ }
+ XCHG(top_border + (16 << pixel_shift), src_cb + (1 << pixel_shift), xchg);
+ XCHG(top_border + (24 << pixel_shift), src_cb + (9 << pixel_shift), 1);
+ XCHG(top_border + (32 << pixel_shift), src_cr + (1 << pixel_shift), xchg);
+ XCHG(top_border + (40 << pixel_shift), src_cr + (9 << pixel_shift), 1);
+ if (h->mb_x + 1 < h->mb_width) {
+ 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_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);
@@ -2405,7 +2457,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;
@@ -2696,30 +2748,44 @@ static void implicit_weight_table(H264Context *h, int field)
*/
static void idr(H264Context *h)
{
+ int i;
ff_h264_remove_all_refs(h);
h->prev_frame_num = 0;
h->prev_frame_num_offset = 0;
- h->prev_poc_msb =
+ 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 */
static void 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]));
memset(h->default_ref_list[0], 0, sizeof(h->default_ref_list[0]));
memset(h->default_ref_list[1], 0, sizeof(h->default_ref_list[1]));
ff_h264_reset_sei(h);
+ h->recovery_frame= -1;
+ h->sync= 0;
+ h->list_count = 0;
+ h->current_slice = 0;
+ h->mmco_reset = 1;
}
/* forget old pics after a seek */
@@ -2728,7 +2794,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;
@@ -2851,19 +2917,19 @@ static void init_scan_tables(H264Context *h)
#undef T
}
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 ));
}
}
@@ -2873,9 +2939,9 @@ static int 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) {
@@ -2894,6 +2960,10 @@ static int 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);
+
/*
* FIXME: Error handling code does not seem to support interlaced
* when slices span multiple rows
@@ -2906,12 +2976,14 @@ static int 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 (CONFIG_ERROR_RESILIENCE && !FIELD_PICTURE(h)) {
+ if (CONFIG_ERROR_RESILIENCE &&
+ !FIELD_PICTURE(h) && h->current_slice && !h->sps.new) {
h->er.cur_pic = h->cur_pic_ptr;
- h->er.last_pic = h->ref_count[0] ? &h->ref_list[0][0] : NULL;
- h->er.next_pic = h->ref_count[1] ? &h->ref_list[1][0] : NULL;
ff_er_frame_end(&h->er);
}
+ 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;
@@ -2997,7 +3069,15 @@ static int 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;
@@ -3008,6 +3088,7 @@ static int 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_dsputil_init(&h->dsp, h->avctx);
ff_videodsp_init(&h->vdsp, h->sps.bit_depth_luma);
@@ -3020,7 +3101,7 @@ static int h264_set_parameter_from_sps(H264Context *h)
return 0;
}
-static enum AVPixelFormat get_pixel_format(H264Context *h)
+static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
{
switch (h->sps.bit_depth_luma) {
case 9:
@@ -3045,22 +3126,53 @@ static enum AVPixelFormat get_pixel_format(H264Context *h)
else
return AV_PIX_FMT_YUV420P10;
break;
- case 8:
+ case 12:
if (CHROMA444(h)) {
if (h->avctx->colorspace == AVCOL_SPC_RGB) {
- return AV_PIX_FMT_GBRP;
+ return AV_PIX_FMT_GBRP12;
} else
- return h->avctx->color_range == AVCOL_RANGE_JPEG ? AV_PIX_FMT_YUVJ444P
- : AV_PIX_FMT_YUV444P;
+ return AV_PIX_FMT_YUV444P12;
+ } else if (CHROMA422(h))
+ return AV_PIX_FMT_YUV422P12;
+ else
+ return AV_PIX_FMT_YUV420P12;
+ break;
+ case 14:
+ if (CHROMA444(h)) {
+ if (h->avctx->colorspace == AVCOL_SPC_RGB) {
+ return AV_PIX_FMT_GBRP14;
+ } else
+ return AV_PIX_FMT_YUV444P14;
+ } else if (CHROMA422(h))
+ return AV_PIX_FMT_YUV422P14;
+ else
+ return AV_PIX_FMT_YUV420P14;
+ break;
+ case 8:
+ if (CHROMA444(h)) {
+ if (h->avctx->colorspace == AVCOL_SPC_RGB) {
+ av_log(h->avctx, AV_LOG_DEBUG, "Detected GBR colorspace.\n");
+ return AV_PIX_FMT_GBR24P;
+ } else if (h->avctx->colorspace == AVCOL_SPC_YCGCO) {
+ av_log(h->avctx, AV_LOG_WARNING, "Detected unsupported YCgCo colorspace.\n");
+ }
+ return h->avctx->color_range == AVCOL_RANGE_JPEG ? AV_PIX_FMT_YUVJ444P
+ : AV_PIX_FMT_YUV444P;
} else if (CHROMA422(h)) {
return h->avctx->color_range == AVCOL_RANGE_JPEG ? AV_PIX_FMT_YUVJ422P
: AV_PIX_FMT_YUV422P;
} else {
- return h->avctx->get_format(h->avctx, h->avctx->codec->pix_fmts ?
+ int i;
+ const enum AVPixelFormat * fmt = h->avctx->codec->pix_fmts ?
h->avctx->codec->pix_fmts :
h->avctx->color_range == AVCOL_RANGE_JPEG ?
h264_hwaccel_pixfmt_list_jpeg_420 :
- h264_hwaccel_pixfmt_list_420);
+ h264_hwaccel_pixfmt_list_420;
+
+ for (i=0; fmt[i] != AV_PIX_FMT_NONE; i++)
+ if (fmt[i] == h->avctx->pix_fmt && !force_callback)
+ return fmt[i];
+ return ff_thread_get_format(h->avctx, fmt);
}
break;
default:
@@ -3075,6 +3187,8 @@ static int init_dimensions(H264Context *h)
{
int width = h->width - (h->sps.crop_right + h->sps.crop_left);
int height = h->height - (h->sps.crop_top + 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 (!h->sps.crop &&
@@ -3166,7 +3280,9 @@ static int h264_slice_header_init(H264Context *h, int reinit)
if (!c)
return AVERROR(ENOMEM);
c->avctx = h->avctx;
- c->dsp = h->dsp;
+ if (CONFIG_ERROR_RESILIENCE) {
+ c->dsp = h->dsp;
+ }
c->vdsp = h->vdsp;
c->h264dsp = h->h264dsp;
c->h264qpel = h->h264qpel;
@@ -3174,12 +3290,13 @@ 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;
c->uvlinesize = h->uvlinesize;
- c->chroma_x_shift = h->chroma_x_shift;
- c->chroma_y_shift = h->chroma_y_shift;
+ c->chroma_x_shift = h->chroma_x_shift;
+ c->chroma_y_shift = h->chroma_y_shift;
c->qscale = h->qscale;
c->droppable = h->droppable;
c->data_partitioning = h->data_partitioning;
@@ -3211,26 +3328,33 @@ static int h264_slice_header_init(H264Context *h, int reinit)
int ff_set_ref_count(H264Context *h)
{
- 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
h->ref_count[0] = h->pps.ref_count[0];
h->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) {
h->ref_count[0] = get_ue_golomb(&h->gb) + 1;
- if (h->ref_count[0] < 1)
- return AVERROR_INVALIDDATA;
if (h->slice_type_nos == AV_PICTURE_TYPE_B) {
h->ref_count[1] = get_ue_golomb(&h->gb) + 1;
- if (h->ref_count[1] < 1)
- return AVERROR_INVALIDDATA;
- }
+ } else
+ // full range is spec-ok in this case, even for frames
+ h->ref_count[1] = 1;
+ }
+
+ if (h->ref_count[0]-1 > max[0] || h->ref_count[1]-1 > max[1]){
+ av_log(h->avctx, AV_LOG_ERROR, "reference overflow %u > %u or %u > %u\n", h->ref_count[0]-1, max[0], h->ref_count[1]-1, max[1]);
+ h->ref_count[0] = h->ref_count[1] = 0;
+ return AVERROR_INVALIDDATA;
}
if (h->slice_type_nos == AV_PICTURE_TYPE_B)
@@ -3242,14 +3366,6 @@ int ff_set_ref_count(H264Context *h)
h->ref_count[0] = h->ref_count[1] = 0;
}
- max_refs = h->picture_structure == PICT_FRAME ? 16 : 32;
-
- if (h->ref_count[0] > max_refs || h->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;
- }
-
return 0;
}
@@ -3269,15 +3385,15 @@ static int 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->me.qpel_put = h->h264qpel.put_h264_qpel_pixels_tab;
h->me.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 && FIELD_PICTURE(h)) {
@@ -3298,7 +3414,7 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
if (slice_type > 9) {
av_log(h->avctx, AV_LOG_ERROR,
"slice type too large (%d) at %d %d\n",
- h->slice_type, h->mb_x, h->mb_y);
+ slice_type, h->mb_x, h->mb_y);
return AVERROR_INVALIDDATA;
}
if (slice_type > 4) {
@@ -3308,10 +3424,6 @@ static int 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;
@@ -3320,7 +3432,7 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
pps_id = get_ue_golomb(&h->gb);
if (pps_id >= MAX_PPS_COUNT) {
- av_log(h->avctx, AV_LOG_ERROR, "pps_id out of range\n");
+ av_log(h->avctx, AV_LOG_ERROR, "pps_id %d out of range\n", pps_id);
return AVERROR_INVALIDDATA;
}
if (!h0->pps_buffers[pps_id]) {
@@ -3345,6 +3457,13 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
h->current_sps_id = h->pps.sps_id;
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;
@@ -3359,9 +3478,17 @@ static int 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 (h0->avctx->pix_fmt != 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);
@@ -3380,8 +3507,8 @@ static int 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;
@@ -3394,6 +3521,7 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
if (h->context_initialized &&
(h->width != h->avctx->coded_width ||
h->height != h->avctx->coded_height ||
+ must_reinit ||
needs_reinit)) {
if (h != h0) {
av_log(h->avctx, AV_LOG_ERROR, "changing width/height on "
@@ -3403,12 +3531,12 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
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,
@@ -3423,7 +3551,7 @@ static int 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;
@@ -3449,6 +3577,10 @@ static int 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);
@@ -3478,7 +3610,7 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
} else {
/* Shorten frame num gaps so we don't have to allocate reference
* frames just to throw them away */
- if (h->frame_num != h->prev_frame_num) {
+ if (h->frame_num != h->prev_frame_num && h->prev_frame_num >= 0) {
int unwrap_prev_frame_num = h->prev_frame_num;
int max_frame_num = 1 << h->sps.log2_max_frame_num;
@@ -3498,17 +3630,23 @@ static int 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.data[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);
}
@@ -3518,7 +3656,7 @@ static int 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);
}
@@ -3545,11 +3683,14 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
}
}
- while (h->frame_num != h->prev_frame_num &&
+ while (h->frame_num != h->prev_frame_num && h->prev_frame_num >= 0 && !h0->first_field &&
h->frame_num != (h->prev_frame_num + 1) % (1 << h->sps.log2_max_frame_num)) {
Picture *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)
return ret;
@@ -3602,6 +3743,8 @@ static int 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. */
@@ -3625,13 +3768,32 @@ static int 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");
@@ -3642,7 +3804,7 @@ static int 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;
@@ -3678,8 +3840,13 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
if (ret < 0)
return ret;
- 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);
@@ -3818,10 +3985,16 @@ static int 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++) {
@@ -3857,6 +4030,10 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
(h->ref_list[j][i].reference & 3);
}
+ if (h->ref_count[0]) h->er.last_pic = &h->ref_list[0][0];
+ if (h->ref_count[1]) h->er.next_pic = &h->ref_list[1][0];
+ h->er.ref_count = h->ref_count[0];
+
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",
@@ -3913,7 +4090,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]];
@@ -3928,7 +4105,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]);
@@ -3961,7 +4138,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);
@@ -4234,7 +4411,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,
@@ -4244,12 +4421,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)
@@ -4259,10 +4435,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);
@@ -4303,7 +4491,9 @@ 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 %td\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",
h->mb_x, h->mb_y,
@@ -4374,7 +4564,8 @@ 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);
@@ -4382,7 +4573,7 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg)
return 0;
} else {
er_add_slice(h, h->resync_mb_x, h->resync_mb_y,
- h->mb_x - 1, h->mb_y,
+ h->mb_x, h->mb_y,
ER_MB_END);
return AVERROR_INVALIDDATA;
@@ -4425,14 +4616,19 @@ static int execute_decode_slices(H264Context *h, int context_count)
H264Context *hx;
int i;
- 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,
@@ -4444,13 +4640,17 @@ static int execute_decode_slices(H264Context *h, int 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;
}
+static const uint8_t start_code[] = { 0x00, 0x00, 0x01 };
+
static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size,
int parse_extradata)
{
@@ -4462,8 +4662,14 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size,
int pass = !(avctx->active_thread_type & FF_THREAD_FRAME);
int nals_needed = 0; ///< number of NALs that need decoding before the next frame thread starts
int nal_index;
+ int idr_cleared=0;
+ int first_slice = 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;
@@ -4472,6 +4678,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;
+ }
+
for (; pass <= 1; pass++) {
buf_index = 0;
context_count = 0;
@@ -4531,16 +4744,14 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size,
h->workaround_bugs |= FF_BUG_TRUNCATED;
if (!(h->workaround_bugs & FF_BUG_TRUNCATED))
- while (ptr[dst_length - 1] == 0 && dst_length > 0)
+ while(dst_length > 0 && ptr[dst_length - 1] == 0)
dst_length--;
bit_length = !dst_length ? 0
: (8 * dst_length -
decode_rbsp_trailing(h, ptr + dst_length - 1));
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);
+ av_log(h->avctx, AV_LOG_DEBUG, "NAL %d/%d at %d/%d length %d pass %d\n", hx->nal_unit_type, hx->nal_ref_idc, buf_index, buf_size, dst_length, pass);
if (h->is_avc && (nalsize != consumed) && nalsize)
av_log(h->avctx, AV_LOG_DEBUG,
@@ -4564,42 +4775,60 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size,
case NAL_IDR_SLICE:
case NAL_SLICE:
init_get_bits(&hx->gb, ptr, bit_length);
- if (!get_ue_golomb(&hx->gb))
+ if (!get_ue_golomb(&hx->gb) || !first_slice)
nals_needed = nal_index;
+ if (!first_slice)
+ first_slice = hx->nal_unit_type;
}
continue;
}
+ if (!first_slice)
+ switch (hx->nal_unit_type) {
+ case NAL_DPA:
+ case NAL_IDR_SLICE:
+ case NAL_SLICE:
+ first_slice = hx->nal_unit_type;
+ }
+
if (avctx->skip_frame >= AVDISCARD_NONREF &&
h->nal_ref_idc == 0 &&
h->nal_unit_type != NAL_SEI)
continue;
again:
- /* Ignore every NAL unit type except PPS and SPS during extradata
+ /* Ignore per frame NAL unit type during extradata
* parsing. Decoding slices is not possible in codec init
* with frame-mt */
- if (parse_extradata && HAVE_THREADS &&
- (h->avctx->active_thread_type & FF_THREAD_FRAME) &&
- (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 (h->nal_unit_type != NAL_IDR_SLICE) {
+ if (first_slice != 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;
case NAL_SLICE:
init_get_bits(&hx->gb, ptr, bit_length);
hx->intra_gb_ptr =
@@ -4609,9 +4838,30 @@ again:
if ((err = decode_slice_header(hx, h)))
break;
+ if (h->sei_recovery_frame_cnt >= 0 && (h->frame_num != h->sei_recovery_frame_cnt || hx->slice_type_nos != AV_PICTURE_TYPE_I))
+ h->valid_recovery_point = 1;
+
+ if ( h->sei_recovery_frame_cnt >= 0
+ && ( 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);
+
+ 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 (h->recovery_frame == h->frame_num) {
+ h->cur_pic_ptr->sync |= 1;
+ h->recovery_frame = -1;
+ }
+
+ h->sync |= !!h->cur_pic_ptr->f.key_frame;
+ h->sync |= 3*!!(avctx->flags2 & CODEC_FLAG2_SHOW_ALL);
+ h->cur_pic_ptr->sync |= h->sync;
if (h->current_slice == 1) {
if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS))
@@ -4620,6 +4870,9 @@ 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 &&
@@ -4636,6 +4889,14 @@ again:
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++;
}
@@ -4658,6 +4919,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 &&
@@ -4676,19 +4940,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 = h264_set_parameter_from_sps(h);
- if (ret < 0)
- goto end;
-
break;
case NAL_PPS:
init_get_bits(&h->gb, ptr, bit_length);
@@ -4753,21 +5016,24 @@ 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, Picture *srcp)
{
+ AVFrame *src = &srcp->f;
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->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];
+ int off = ((srcp->crop_left >> hshift) << h->pixel_shift) +
+ (srcp->crop_top >> vshift) * dst->linesize[i];
dst->data[i] += off;
}
return 0;
@@ -4781,17 +5047,18 @@ static int decode_frame(AVCodecContext *avctx, void *data,
H264Context *h = avctx->priv_data;
AVFrame *pict = data;
int buf_index = 0;
+ Picture *out;
+ int i, out_idx;
int ret;
h->flags = avctx->flags;
/* end of stream, output what is still in the buffers */
-out:
if (buf_size == 0) {
- Picture *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];
@@ -4810,7 +5077,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;
@@ -4818,19 +5086,42 @@ out:
return buf_index;
}
+ if(h->is_avc && buf_size >= 9 && buf[0]==1 && buf[2]==0 && (buf[4]&0xFC)==0xFC && (buf[5]&0x1F) && buf[8]==0x67){
+ 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)
+ goto not_extra;
+ p += nalsize;
+ }
+ cnt = *(p++);
+ if(!cnt)
+ goto not_extra;
+ while(cnt--){
+ int nalsize= AV_RB16(p) + 2;
+ if(nalsize > buf_size - (p-buf) || p[2]!=0x68)
+ goto not_extra;
+ p += nalsize;
+ }
+
+ return ff_h264_decode_extradata(h, buf, buf_size);
+ }
+not_extra:
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;
}
@@ -4842,14 +5133,18 @@ out:
field_end(h, 0);
- if (!h->next_output_pic) {
- /* Wait for second field. */
- *got_frame = 0;
- } else {
- ret = output_frame(h, pict, &h->next_output_pic->f);
+ /* Wait for second field. */
+ *got_frame = 0;
+ if (h->next_output_pic && (h->next_output_pic->sync || h->sync>1)) {
+ ret = output_frame(h, pict, h->next_output_pic);
if (ret < 0)
return ret;
*got_frame = 1;
+ if (CONFIG_MPEGVIDEO) {
+ ff_print_debug_info2(h->avctx, h->next_output_pic, pict, h->er.mbskip_table,
+ &h->low_delay,
+ h->mb_width, h->mb_height, h->mb_stride, 1);
+ }
}
}
@@ -4875,6 +5170,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);
unref_picture(h, &h->cur_pic);
@@ -4899,6 +5195,26 @@ 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,
+};
+
+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_decoder = {
.name = "h264",
.long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
@@ -4915,4 +5231,24 @@ AVCodec ff_h264_decoder = {
.init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),
.update_thread_context = ONLY_IF_THREADS_ENABLED(decode_update_thread_context),
.profiles = NULL_IF_CONFIG_SMALL(profiles),
+ .priv_class = &h264_class,
};
+
+#if CONFIG_H264_VDPAU_DECODER
+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 = 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 cb97067..ed7f04b 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
*/
@@ -46,6 +46,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
@@ -85,6 +87,7 @@
#define CABAC(h) h->pps.cabac
#endif
+#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)
@@ -95,7 +98,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 {
@@ -122,8 +125,10 @@ enum {
typedef enum {
SEI_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_RECOVERY_POINT = 6, ///< recovery point (frame # to decoder sync)
+ SEI_TYPE_FRAME_PACKING = 45, ///< frame packing arrangement
} SEI_Type;
/**
@@ -142,6 +147,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 {
@@ -224,11 +242,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 {
@@ -255,7 +285,6 @@ typedef struct MMCO {
*/
typedef struct H264Context {
AVCodecContext *avctx;
- DSPContext dsp;
VideoDSPContext vdsp;
H264DSPContext h264dsp;
H264ChromaContext h264chroma;
@@ -263,6 +292,7 @@ typedef struct H264Context {
MotionEstContext me;
ParseContext parse_context;
GetBitContext gb;
+ DSPContext dsp;
ERContext er;
Picture *DPB;
@@ -445,12 +475,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;
@@ -547,7 +577,7 @@ typedef struct H264Context {
struct H264Context *thread_context[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;
@@ -570,6 +600,7 @@ typedef struct H264Context {
enum AVPictureType pict_type;
int last_slice_type;
+ unsigned int last_ref_count[2];
/** @} */
/**
@@ -610,6 +641,20 @@ typedef struct H264Context {
* frames.
*/
int sei_recovery_frame_cnt;
+ /**
+ * recovery_frame is the frame_num at which the next frame should
+ * be fully constructed.
+ *
+ * Set to -1 when not expecting a recovery point.
+ */
+ int recovery_frame;
+
+ /**
+ * Are the SEI recovery points looking valid.
+ */
+ int valid_recovery_point;
+
+ FPA sei_fpa;
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
@@ -620,16 +665,26 @@ 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
+
+ int sync; ///< did we had a keyframe or recovery point
+
+ uint8_t parse_history[4];
+ int parse_history_count;
+ int parse_last_mb;
uint8_t *edge_emu_buffer;
int16_t *dc_val_base;
+ uint8_t *visualization_buffer[3]; ///< temporary buffer vor MV visualization
+
AVBufferPool *qscale_table_pool;
AVBufferPool *mb_type_pool;
AVBufferPool *motion_val_pool;
AVBufferPool *ref_index_pool;
} 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];
/**
@@ -712,7 +767,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);
@@ -748,6 +803,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
* / / /
diff --git a/libavcodec/h264_cabac.c b/libavcodec/h264_cabac.c
index 43ddf7d..7b1ee05 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,6 +26,7 @@
*/
#define CABAC(h) 1
+#define UNCHECKED_BITSTREAM_READER 1
#include "libavutil/attributes.h"
#include "config.h"
@@ -37,13 +38,12 @@
#include "h264data.h"
#include "h264_mvpred.h"
#include "golomb.h"
+#include "libavutil/avassert.h"
#if ARCH_X86
#include "x86/h264_i386.h"
#endif
-#include <assert.h>
-
/* Cabac pre state table */
static const int8_t cabac_context_init_I[1024][2] =
@@ -1619,7 +1619,6 @@ decode_cabac_residual_internal(H264Context *h, int16_t *block,
cc.range = h->cabac.range;
cc.low = h->cabac.low;
cc.bytestream= h->cabac.bytestream;
- cc.bytestream_end = h->cabac.bytestream_end;
#else
#define CC &h->cabac
#endif
@@ -1668,7 +1667,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 )
@@ -1680,11 +1679,12 @@ 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;
}
}
+
#define STORE_BLOCK(type) \
do { \
uint8_t *ctx = coeff_abs_level1_ctx[node_ctx] + abs_level_m1_ctx_base; \
@@ -1709,7 +1709,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++; \
} \
\
@@ -1728,11 +1728,11 @@ decode_cabac_residual_internal(H264Context *h, int16_t *block,
} \
} while ( coeff_count );
- if (h->pixel_shift) {
- STORE_BLOCK(int32_t)
- } else {
- STORE_BLOCK(int16_t)
- }
+ if (h->pixel_shift) {
+ STORE_BLOCK(int32_t)
+ } else {
+ STORE_BLOCK(int16_t)
+ }
#ifdef CABAC_ON_STACK
h->cabac.range = cc.range ;
h->cabac.low = cc.low ;
@@ -1883,6 +1883,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;
@@ -1925,7 +1926,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++;
@@ -1978,7 +1979,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;
@@ -2024,6 +2025,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 ) ) {
@@ -2092,11 +2096,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
@@ -2178,11 +2181,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
@@ -2206,11 +2209,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
@@ -2237,15 +2240,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
@@ -2283,6 +2286,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 5ed1d5d..8facf55 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 "h264data.h" // FIXME FIXME FIXME
#include "h264_mvpred.h"
#include "golomb.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:
@@ -776,6 +784,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);
@@ -842,7 +853,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){
@@ -855,7 +866,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)){
@@ -935,14 +946,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;
}
@@ -966,14 +976,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;
}
@@ -999,19 +1008,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;
}
@@ -1060,6 +1068,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)){
@@ -1112,12 +1125,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;
}
}
@@ -1126,34 +1142,12 @@ 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 (i4x4 = 0; i4x4 < 4; i4x4++) {
- const int index = 16 + 16*chroma_idx + 8*i8x8 + i4x4;
+ 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)
return -1;
- mb += 16 << pixel_shift;
- }
- }
- }
- }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 /* 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;
+ mb += 16<<pixel_shift;
}
}
}
diff --git a/libavcodec/h264_direct.c b/libavcodec/h264_direct.c
index 85fda31..477359c 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
*/
@@ -208,6 +208,7 @@ static void pred_spatial_direct_motion(H264Context * const h, int *mb_type){
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;
@@ -287,8 +288,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){
@@ -477,8 +478,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 b8bf555..475070a 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 "mathops.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) {
@@ -705,7 +707,7 @@ void ff_h264_filter_mb( H264Context *h, int mb_x, int mb_y, uint8_t *img_y, uint
const int mvy_limit = IS_INTERLACED(mb_type) ? 2 : 4;
int first_vertical_edge_done = 0;
av_unused int dir;
- 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 = h->slice_alpha_c0_offset - qp_bd_offset;
int b = h->slice_beta_offset - qp_bd_offset;
diff --git a/libavcodec/h264_mb_template.c b/libavcodec/h264_mb_template.c
index 9b63fef..15cb3c9 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
*/
@@ -98,8 +98,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,
@@ -114,13 +114,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++) {
@@ -140,9 +137,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 dee02f5..7aec43b 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
*/
@@ -70,7 +70,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);
@@ -102,7 +102,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];
@@ -140,7 +140,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 e86c3e1..58568a7 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
*/
@@ -68,17 +68,10 @@ 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);
-
/* 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 {
sps_seen = 1;
}
@@ -88,9 +81,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);
}
@@ -103,7 +102,7 @@ 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)
@@ -138,6 +137,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;
@@ -164,15 +164,12 @@ static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
*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;
@@ -182,14 +179,14 @@ static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
/* 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 ((ret=alloc_and_copy(poutbuf, poutbuf_size,
avctx->extradata, avctx->extradata_size,
- buf, nal_size) < 0)
+ 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;
@@ -204,11 +201,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 a7545f0..7015d8c 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
*/
@@ -31,8 +31,8 @@
#include "internal.h"
#include "avcodec.h"
#include "h264.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)
@@ -102,7 +102,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
@@ -481,7 +481,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;
@@ -606,7 +606,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;
@@ -663,7 +663,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 05a40c7..0c426dd 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,30 +25,48 @@
* @author Michael Niedermayer <michaelni@gmx.at>
*/
+#define UNCHECKED_BITSTREAM_READER 1
+
#include "libavutil/attributes.h"
#include "parser.h"
#include "h264data.h"
#include "golomb.h"
#include "internal.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.h264_find_start_code_candidate(buf + i, buf_size - i);
- if (i < buf_size)
+ i += h->h264dsp.h264_find_start_code_candidate(buf + i, next_avc - i);
+ if (i < next_avc)
state = 2;
} else if (state <= 2) {
if (buf[i] == 1)
@@ -65,26 +83,41 @@ static int h264_find_frame_end(H264Context *h, const uint8_t *buf,
goto found;
}
} else if (v == 1 || v == 2 || v == 5) {
+ state += 8;
+ continue;
+ }
+ state = 7;
+ } else {
+ h->parse_history[h->parse_history_count++]= buf[i];
+ if (h->parse_history_count>3) {
+ 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);
+ last_mb= h->parse_last_mb;
+ 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) - 3 * (state > 7);
}
static int scan_mmco_reset(AVCodecParserContext *s)
@@ -174,6 +207,7 @@ static inline int parse_nal_units(AVCodecParserContext *s,
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 */
@@ -183,17 +217,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;
for (;;) {
- int src_length, dst_length, consumed;
+ int src_length, dst_length, consumed, nalsize = 0;
+ if (h->is_avc) {
+ int i;
+ if (h->nal_length_size >= buf_end - buf) break;
+ nalsize = 0;
+ for (i = 0; i < h->nal_length_size; i++)
+ nalsize = (nalsize << 8) | *buf++;
+ if (nalsize <= 0 || nalsize > buf_end - buf) {
+ av_log(h->avctx, AV_LOG_ERROR, "AVC: nal size %d\n", nalsize);
+ break;
+ }
+ src_length = nalsize;
+ } else {
buf = avpriv_find_start_code(buf, buf_end, &state);
if (buf >= buf_end)
break;
--buf;
src_length = buf_end - buf;
+ }
switch (state & 0x1f) {
case NAL_SLICE:
case NAL_IDR_SLICE:
@@ -234,7 +282,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) {
@@ -261,6 +309,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;
@@ -385,10 +436,12 @@ static inline int parse_nal_units(AVCodecParserContext *s,
return 0; /* no need to evaluate the rest */
}
- buf += consumed;
+ buf += h->is_avc ? nalsize : 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;
}
@@ -405,14 +458,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);
}
}
@@ -428,7 +480,7 @@ 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
}
}
@@ -464,7 +516,7 @@ static int h264_split(AVCodecContext *avctx,
for (i = 0; i <= buf_size; i++) {
if ((state & 0xFFFFFF1F) == 0x107)
has_sps = 1;
- /* if((state&0xFFFFFF1F) == 0x101 ||
+ /* if ((state&0xFFFFFF1F) == 0x101 ||
* (state&0xFFFFFF1F) == 0x102 ||
* (state&0xFFFFFF1F) == 0x105) {
* }
diff --git a/libavcodec/h264_ps.c b/libavcodec/h264_ps.c
index 54b735d..a06e3dd 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
*/
@@ -68,13 +68,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] = {
@@ -180,6 +202,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);
@@ -205,7 +232,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 */
@@ -228,6 +256,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));
@@ -279,13 +308,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
}
}
@@ -304,7 +331,9 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
constraint_set_flags |= get_bits1(&h->gb) << 1; // constraint_set1_flag
constraint_set_flags |= get_bits1(&h->gb) << 2; // constraint_set2_flag
constraint_set_flags |= get_bits1(&h->gb) << 3; // constraint_set3_flag
- get_bits(&h->gb, 4); // reserved
+ constraint_set_flags |= get_bits1(&h->gb) << 4; // constraint_set4_flag
+ constraint_set_flags |= get_bits1(&h->gb) << 5; // constraint_set5_flag
+ get_bits(&h->gb, 2); // reserved
level_idc = get_bits(&h->gb, 8);
sps_id = get_ue_golomb_31(&h->gb);
@@ -320,10 +349,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 || sps->profile_idc == 110 ||
sps->profile_idc == 122 || sps->profile_idc == 244 ||
@@ -331,16 +362,25 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
sps->profile_idc == 86 || sps->profile_idc == 118 ||
sps->profile_idc == 128 || sps->profile_idc == 144) {
sps->chroma_format_idc = get_ue_golomb_31(&h->gb);
- if (sps->chroma_format_idc > 3) {
+ if (sps->chroma_format_idc > 3U) {
av_log(h->avctx, AV_LOG_ERROR,
- "chroma_format_idc (%u) out of range\n",
+ "chroma_format_idc %d is illegal\n",
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;
+ if (sps->bit_depth_luma > 14U || sps->bit_depth_chroma > 14U || sps->bit_depth_luma != sps->bit_depth_chroma) {
+ 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);
@@ -363,7 +403,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);
@@ -385,8 +430,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 > 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\n");
goto fail;
}
@@ -408,11 +455,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)
@@ -425,6 +467,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 "
@@ -451,6 +495,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;
@@ -467,7 +522,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;
}
@@ -477,7 +532,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:%d/%d/%d/%d %s %s %d/%d\n",
+ "sps:%u profile:%d/%d poc:%d ref:%d %dx%d %s %s crop:%d/%d/%d/%d %s %s %d/%d b%d reo:%d\n",
sps_id, sps->profile_idc, sps->level_idc,
sps->poc_type,
sps->ref_frame_count,
@@ -489,14 +544,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,
+ h->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;
- h->current_sps_id = sps_id;
return 0;
@@ -514,21 +570,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 (%d) 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));
@@ -540,6 +607,19 @@ int ff_h264_decode_picture_parameter_set(H264Context *h, int bit_length)
av_log(h->avctx, AV_LOG_ERROR, "sps_id out of range\n");
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);
@@ -604,8 +684,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);
@@ -615,10 +694,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 3721c2e..27ca8f8 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
*/
@@ -25,6 +25,7 @@
* @author Michael Niedermayer <michaelni@gmx.at>
*/
+#include "libavutil/avassert.h"
#include "internal.h"
#include "avcodec.h"
#include "h264.h"
@@ -129,10 +130,10 @@ 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], sorted, len, 0, h->picture_structure);
len += build_def_list(h->default_ref_list[list] + len, h->long_ref, 16, 1, h->picture_structure);
- assert(len <= 32);
+ av_assert0(len <= 32);
if (len < h->ref_count[list])
memset(&h->default_ref_list[list][len], 0, sizeof(Picture) * (h->ref_count[list] - len));
@@ -151,7 +152,7 @@ int ff_h264_fill_default_ref_list(H264Context *h)
} else {
len = build_def_list(h->default_ref_list[0], h->short_ref, h->short_ref_count, 0, h->picture_structure);
len += build_def_list(h->default_ref_list[0] + len, h-> long_ref, 16, 1, h->picture_structure);
- assert(len <= 32);
+ av_assert0(len <= 32);
if (len < h->ref_count[0])
memset(&h->default_ref_list[0][len], 0, sizeof(Picture) * (h->ref_count[0] - len));
}
@@ -303,13 +304,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.data[0]) {
- av_log(h->avctx, AV_LOG_ERROR, "Missing reference picture\n");
- if (h->default_ref_list[list][0].f.data[0])
+ if ( !h->ref_list[list][index].f.data[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.data[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);
}
}
@@ -319,7 +326,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++) {
Picture *frame = &h->ref_list[list][i];
Picture *field = &h->ref_list[list][16 + 2 * i];
@@ -466,6 +473,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));
}
/**
@@ -507,8 +517,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;
@@ -519,10 +532,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;
- 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;
@@ -541,8 +552,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;
@@ -571,7 +582,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;
@@ -614,7 +625,19 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count)
*/
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);
+ if (remove_short(h, h->cur_pic_ptr->frame_num, 0)) {
+ av_log(h->avctx, AV_LOG_ERROR, "mmco: cannot assign current picture to short and long at the same time\n");
+ }
h->long_ref[mmco[i].long_arg] = h->cur_pic_ptr;
h->long_ref[mmco[i].long_arg]->long_ref = 1;
@@ -641,6 +664,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);
}
@@ -679,8 +704,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
@@ -707,6 +731,13 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count)
print_short_term(h);
print_long_term(h);
+
+ if(err >= 0 && h->long_ref_count==0 && h->short_ref_count<=2 && h->pps.ref_count[0]<=2 + (h->picture_structure != PICT_FRAME) && h->cur_pic_ptr->f.pict_type == AV_PICTURE_TYPE_I){
+ h->cur_pic_ptr->sync |= 1;
+ if(!h->avctx->has_b_frames)
+ h->sync = 2;
+ }
+
return (h->avctx->err_recognition & AV_EF_EXPLODE) ? err : 0;
}
@@ -714,7 +745,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
@@ -780,6 +811,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 27a2c76..7d5558a 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,9 @@ 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);
+
return 0;
}
@@ -157,7 +205,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 +213,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);
}
@@ -175,26 +223,73 @@ static int decode_buffering_period(H264Context *h)
return 0;
}
+static int decode_frame_packing(H264Context *h, int size) {
+ int bits = get_bits_left(&h->gb);
+
+ h->sei_fpa.frame_packing_arrangement_id = get_ue_golomb(&h->gb);
+ h->sei_fpa.frame_packing_arrangement_cancel_flag = get_bits(&h->gb, 1);
+ if (!h->sei_fpa.frame_packing_arrangement_cancel_flag) {
+ h->sei_fpa.frame_packing_arrangement_type = get_bits(&h->gb, 7);
+ h->sei_fpa.quincunx_sampling_flag = get_bits(&h->gb, 1);
+ h->sei_fpa.content_interpretation_type = get_bits(&h->gb, 6);
+ skip_bits(&h->gb, 1); /* spatial_flipping_flag */
+ skip_bits(&h->gb, 1); /* frame0_flipped_flag */
+ skip_bits(&h->gb, 1); /* field_views_flag */
+ skip_bits(&h->gb, 1); /* current_frame_is_frame0_flag */
+ skip_bits(&h->gb, 1); /* frame0_self_contained_flag */
+ skip_bits(&h->gb, 1); /* frame1_self_contained_flag */
+ if (!h->sei_fpa.quincunx_sampling_flag && h->sei_fpa.frame_packing_arrangement_type != 5) {
+ skip_bits(&h->gb, 4); /* frame0_grid_position_x */
+ skip_bits(&h->gb, 4); /* frame0_grid_position_y */
+ skip_bits(&h->gb, 4); /* frame1_grid_position_x */
+ skip_bits(&h->gb, 4); /* frame1_grid_position_y */
+ }
+ skip_bits(&h->gb, 8); /* frame_packing_arrangement_reserved_byte */
+ h->sei_fpa.frame_packing_arrangement_repetition_period = get_ue_golomb(&h->gb) /* frame_packing_arrangement_repetition_period */;
+ }
+ skip_bits(&h->gb, 1); /* 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);
+ skip_bits_long(&h->gb, 8 * size - (bits - get_bits_left(&h->gb)));
+ return 0;
+}
+
int ff_h264_decode_sei(H264Context *h)
{
while (get_bits_left(&h->gb) > 16) {
- int size = 0;
int type = 0;
+ unsigned size = 0;
+ unsigned next;
int ret = 0;
- do
+ do {
+ if (get_bits_left(&h->gb) < 8)
+ return AVERROR_INVALIDDATA;
type += show_bits(&h->gb, 8);
- while (get_bits(&h->gb, 8) == 255);
+ } while (get_bits(&h->gb, 8) == 255);
- do
+ do {
+ if (get_bits_left(&h->gb) < 8)
+ return AVERROR_INVALIDDATA;
size += show_bits(&h->gb, 8);
- while (get_bits(&h->gb, 8) == 255);
+ } 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
@@ -202,6 +297,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)
@@ -217,10 +316,14 @@ int ff_h264_decode_sei(H264Context *h)
if (ret < 0)
return ret;
break;
+ case SEI_TYPE_FRAME_PACKING:
+ if (decode_frame_packing(h, size) < 0)
+ return -1;
+ 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);
@@ -228,3 +331,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/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 8aa5e93..5f8ed91 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 34d9630..45bbc7d 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 351d9d2..b64172a 100644
--- a/libavcodec/h264chroma_template.c
+++ b/libavcodec/h264chroma_template.c
@@ -2,28 +2,56 @@
* 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{\
+ 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;\
+ }\
+ }\
+}\
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 +60,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++){\
@@ -63,9 +91,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++){\
@@ -98,9 +126,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 f90a267..eb229f3 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
*/
@@ -52,7 +52,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 a901dbb..72f699f 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
*/
@@ -26,8 +26,9 @@
*/
#include <stdint.h>
-
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
+
#include "avcodec.h"
#include "h264dsp.h"
#include "h264idct.h"
@@ -45,6 +46,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
@@ -61,19 +70,19 @@ static int h264_find_start_code_candidate_c(const uint8_t *buf, int size)
* simpler and there must be FF_INPUT_BUFFER_PADDING_SIZE
* bytes at the end.
*/
-#if HAVE_FAST_64BIT
+# if HAVE_FAST_64BIT
while (i < size &&
!((~*(const uint64_t *)(buf + i) &
(*(const uint64_t *)(buf + i) - 0x0101010101010101ULL)) &
0x8080808080808080ULL))
i += 8;
-#else
+# else
while (i < size &&
!((~*(const uint32_t *)(buf + i) &
(*(const uint32_t *)(buf + i) - 0x01010101U)) &
0x80808080U))
i += 4;
-#endif
+# endif
#endif
for (; i < size; i++)
if (!buf[i])
@@ -157,7 +166,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 6249ba7..1be4804 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 aadafad..42c32d1 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
*/
@@ -34,7 +34,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;
@@ -69,7 +69,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 2c991fd..3a96654 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,8 +26,10 @@
*/
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "dsputil.h"
#include "h264pred.h"
+#include "avcodec.h" // for AV_CODEC_ID_*
#define BIT_DEPTH 8
#include "h264pred_template.c"
@@ -41,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)
{
@@ -400,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
@@ -558,6 +568,9 @@ av_cold void ff_h264_pred_init(H264PredContext *h, int codec_id,
h->pred16x16_add[VERT_PRED8x8]= FUNCC(pred16x16_vertical_add , depth);\
h->pred16x16_add[ HOR_PRED8x8]= FUNCC(pred16x16_horizontal_add , depth);\
+ if(!chroma_format_idc)
+ chroma_format_idc = 1;
+
switch (bit_depth) {
case 9:
H264_PRED(9)
@@ -565,7 +578,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 62e5b79..ed67d2e 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
*/
diff --git a/libavcodec/h264pred_template.c b/libavcodec/h264pred_template.c
index e15c76c..8d8d62e 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
*/
@@ -33,7 +33,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);
@@ -46,7 +46,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]));
@@ -57,7 +57,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);
@@ -72,7 +72,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);
@@ -86,7 +86,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);
@@ -100,7 +100,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);
@@ -113,7 +113,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);
@@ -126,7 +126,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);
@@ -164,7 +164,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
@@ -192,7 +192,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
@@ -220,7 +220,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
@@ -249,7 +249,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
@@ -275,7 +275,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;
@@ -301,7 +301,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
@@ -328,7 +328,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);
@@ -346,7 +346,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]);
@@ -372,7 +372,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];
@@ -391,7 +391,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];
@@ -406,7 +406,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];
@@ -421,7 +421,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));\
}
@@ -438,7 +438,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;
@@ -487,7 +487,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);
@@ -515,7 +515,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]);
@@ -542,7 +542,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);\
@@ -565,7 +565,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++){
@@ -597,7 +597,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++){
@@ -645,7 +645,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++){
@@ -711,6 +711,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);
@@ -769,7 +770,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;
@@ -883,7 +884,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)));
}
@@ -891,7 +892,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);
@@ -901,7 +902,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);
@@ -911,7 +912,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;
@@ -923,7 +924,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;
@@ -938,7 +939,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;
@@ -961,7 +962,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;
@@ -984,7 +985,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;
@@ -1008,7 +1009,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;
@@ -1039,7 +1040,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;
@@ -1070,7 +1071,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;
@@ -1100,7 +1101,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;
@@ -1137,7 +1138,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];
@@ -1158,7 +1159,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];
@@ -1178,7 +1179,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];
@@ -1203,7 +1204,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 24c9299..7c86d2a 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_ARM)
diff --git a/libavcodec/h264qpel.h b/libavcodec/h264qpel.h
index d761775..6abfac0 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 027edf5..48eb8c8 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
*/
@@ -72,14 +72,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, uint8_t *_src, int dstStride, int srcStride){\
+static av_unused void FUNC(OPNAME ## h264_qpel2_h_lowpass)(uint8_t *p_dst, uint8_t *p_src, int dstStride, int srcStride){\
const int h=2;\
INIT_CLIP\
int i;\
- pixel *dst = (pixel*)_dst;\
- pixel *src = (pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ pixel *dst = (pixel*)p_dst;\
+ pixel *src = (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]));\
@@ -89,14 +89,14 @@ static av_unused void FUNC(OPNAME ## h264_qpel2_h_lowpass)(uint8_t *_dst, uint8_
}\
}\
\
-static av_unused void FUNC(OPNAME ## h264_qpel2_v_lowpass)(uint8_t *_dst, uint8_t *_src, int dstStride, int srcStride){\
+static av_unused void FUNC(OPNAME ## h264_qpel2_v_lowpass)(uint8_t *p_dst, uint8_t *p_src, int dstStride, int srcStride){\
const int w=2;\
INIT_CLIP\
int i;\
- pixel *dst = (pixel*)_dst;\
- pixel *src = (pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ pixel *dst = (pixel*)p_dst;\
+ pixel *src = (pixel*)p_src;\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
for(i=0; i<w; i++)\
{\
const int srcB= src[-2*srcStride];\
@@ -113,16 +113,16 @@ static av_unused void FUNC(OPNAME ## h264_qpel2_v_lowpass)(uint8_t *_dst, uint8_
}\
}\
\
-static av_unused void FUNC(OPNAME ## h264_qpel2_hv_lowpass)(uint8_t *_dst, int16_t *tmp, uint8_t *_src, int dstStride, int tmpStride, int srcStride){\
+static av_unused void FUNC(OPNAME ## h264_qpel2_hv_lowpass)(uint8_t *p_dst, pixeltmp *tmp, uint8_t *p_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;\
- pixel *src = (pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ pixel *dst = (pixel*)p_dst;\
+ pixel *src = (pixel*)p_src;\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
src -= 2*srcStride;\
for(i=0; i<h+5; i++)\
{\
@@ -147,14 +147,14 @@ static av_unused void FUNC(OPNAME ## h264_qpel2_hv_lowpass)(uint8_t *_dst, int16
tmp++;\
}\
}\
-static void FUNC(OPNAME ## h264_qpel4_h_lowpass)(uint8_t *_dst, uint8_t *_src, int dstStride, int srcStride){\
+static void FUNC(OPNAME ## h264_qpel4_h_lowpass)(uint8_t *p_dst, uint8_t *p_src, int dstStride, int srcStride){\
const int h=4;\
INIT_CLIP\
int i;\
- pixel *dst = (pixel*)_dst;\
- pixel *src = (pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ pixel *dst = (pixel*)p_dst;\
+ pixel *src = (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]));\
@@ -166,14 +166,14 @@ static void FUNC(OPNAME ## h264_qpel4_h_lowpass)(uint8_t *_dst, uint8_t *_src, i
}\
}\
\
-static void FUNC(OPNAME ## h264_qpel4_v_lowpass)(uint8_t *_dst, uint8_t *_src, int dstStride, int srcStride){\
+static void FUNC(OPNAME ## h264_qpel4_v_lowpass)(uint8_t *p_dst, uint8_t *p_src, int dstStride, int srcStride){\
const int w=4;\
INIT_CLIP\
int i;\
- pixel *dst = (pixel*)_dst;\
- pixel *src = (pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ pixel *dst = (pixel*)p_dst;\
+ pixel *src = (pixel*)p_src;\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
for(i=0; i<w; i++)\
{\
const int srcB= src[-2*srcStride];\
@@ -194,16 +194,16 @@ static void FUNC(OPNAME ## h264_qpel4_v_lowpass)(uint8_t *_dst, uint8_t *_src, i
}\
}\
\
-static void FUNC(OPNAME ## h264_qpel4_hv_lowpass)(uint8_t *_dst, int16_t *tmp, uint8_t *_src, int dstStride, int tmpStride, int srcStride){\
+static void FUNC(OPNAME ## h264_qpel4_hv_lowpass)(uint8_t *p_dst, pixeltmp *tmp, uint8_t *p_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;\
- pixel *src = (pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ pixel *dst = (pixel*)p_dst;\
+ pixel *src = (pixel*)p_src;\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
src -= 2*srcStride;\
for(i=0; i<h+5; i++)\
{\
@@ -235,14 +235,14 @@ static void FUNC(OPNAME ## h264_qpel4_hv_lowpass)(uint8_t *_dst, int16_t *tmp, u
}\
}\
\
-static void FUNC(OPNAME ## h264_qpel8_h_lowpass)(uint8_t *_dst, uint8_t *_src, int dstStride, int srcStride){\
+static void FUNC(OPNAME ## h264_qpel8_h_lowpass)(uint8_t *p_dst, uint8_t *p_src, int dstStride, int srcStride){\
const int h=8;\
INIT_CLIP\
int i;\
- pixel *dst = (pixel*)_dst;\
- pixel *src = (pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ pixel *dst = (pixel*)p_dst;\
+ pixel *src = (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 ]));\
@@ -258,14 +258,14 @@ static void FUNC(OPNAME ## h264_qpel8_h_lowpass)(uint8_t *_dst, uint8_t *_src, i
}\
}\
\
-static void FUNC(OPNAME ## h264_qpel8_v_lowpass)(uint8_t *_dst, uint8_t *_src, int dstStride, int srcStride){\
+static void FUNC(OPNAME ## h264_qpel8_v_lowpass)(uint8_t *p_dst, uint8_t *p_src, int dstStride, int srcStride){\
const int w=8;\
INIT_CLIP\
int i;\
- pixel *dst = (pixel*)_dst;\
- pixel *src = (pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ pixel *dst = (pixel*)p_dst;\
+ pixel *src = (pixel*)p_src;\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
for(i=0; i<w; i++)\
{\
const int srcB= src[-2*srcStride];\
@@ -294,16 +294,16 @@ static void FUNC(OPNAME ## h264_qpel8_v_lowpass)(uint8_t *_dst, uint8_t *_src, i
}\
}\
\
-static void FUNC(OPNAME ## h264_qpel8_hv_lowpass)(uint8_t *_dst, int16_t *tmp, uint8_t *_src, int dstStride, int tmpStride, int srcStride){\
+static void FUNC(OPNAME ## h264_qpel8_hv_lowpass)(uint8_t *p_dst, pixeltmp *tmp, uint8_t *p_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;\
- pixel *src = (pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ pixel *dst = (pixel*)p_dst;\
+ pixel *src = (pixel*)p_src;\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
src -= 2*srcStride;\
for(i=0; i<h+5; i++)\
{\
@@ -365,7 +365,7 @@ static void FUNC(OPNAME ## h264_qpel16_h_lowpass)(uint8_t *dst, uint8_t *src, in
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, uint8_t *src, int dstStride, int tmpStride, int srcStride){\
+static void FUNC(OPNAME ## h264_qpel16_hv_lowpass)(uint8_t *dst, pixeltmp *tmp, 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;\
@@ -477,13 +477,13 @@ static void FUNCC(OPNAME ## h264_qpel ## SIZE ## _mc33)(uint8_t *dst, uint8_t *s
\
static void FUNCC(OPNAME ## h264_qpel ## SIZE ## _mc22)(uint8_t *dst, 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, 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);\
@@ -493,7 +493,7 @@ static void FUNCC(OPNAME ## h264_qpel ## SIZE ## _mc21)(uint8_t *dst, uint8_t *s
\
static void FUNCC(OPNAME ## h264_qpel ## SIZE ## _mc23)(uint8_t *dst, 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);\
@@ -505,7 +505,7 @@ static void FUNCC(OPNAME ## h264_qpel ## SIZE ## _mc12)(uint8_t *dst, uint8_t *s
{\
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);\
@@ -518,7 +518,7 @@ static void FUNCC(OPNAME ## h264_qpel ## SIZE ## _mc32)(uint8_t *dst, uint8_t *s
{\
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
new file mode 100644
index 0000000..aaf319f
--- a/dev/null
+++ b/libavcodec/hevc.c
@@ -0,0 +1,2909 @@
+/*
+ * 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 FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License 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/internal.h"
+#include "libavutil/md5.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+
+#include "bytestream.h"
+#include "cabac_functions.h"
+#include "dsputil.h"
+#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 };
+
+/**
+ * NOTE: Each function hls_foo correspond to the function foo in the
+ * specification (HLS stands for High Level Syntax).
+ */
+
+/**
+ * Section 5.7
+ */
+
+/* free everything allocated by pic_arrays_init() */
+static void pic_arrays_free(HEVCContext *s)
+{
+ av_freep(&s->sao);
+ av_freep(&s->deblock);
+ av_freep(&s->split_cu_flag);
+
+ av_freep(&s->skip_flag);
+ av_freep(&s->tab_ct_depth);
+
+ av_freep(&s->tab_ipm);
+ av_freep(&s->cbf_luma);
+ av_freep(&s->is_pcm);
+
+ av_freep(&s->qp_y_tab);
+ av_freep(&s->tab_slice_address);
+ av_freep(&s->filter_slice_edges);
+
+ 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);
+}
+
+/* allocate arrays that depend on frame dimensions */
+static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
+{
+ int log2_min_cb_size = sps->log2_min_cb_size;
+ int width = sps->width;
+ int height = sps->height;
+ int pic_size = width * height;
+ int pic_size_in_ctb = ((width >> log2_min_cb_size) + 1) *
+ ((height >> log2_min_cb_size) + 1);
+ 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->sao = av_mallocz_array(ctb_count, sizeof(*s->sao));
+ s->deblock = av_mallocz_array(ctb_count, sizeof(*s->deblock));
+ s->split_cu_flag = av_malloc(pic_size);
+ if (!s->sao || !s->deblock || !s->split_cu_flag)
+ 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);
+ if (!s->skip_flag || !s->tab_ct_depth)
+ goto fail;
+
+ s->cbf_luma = av_malloc(sps->min_tb_width * sps->min_tb_height);
+ s->tab_ipm = av_malloc(min_pu_size);
+ s->is_pcm = av_malloc(min_pu_size);
+ 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 * sizeof(*s->tab_slice_address));
+ s->qp_y_tab = av_malloc(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));
+ 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);
+ s->rpl_tab_pool = av_buffer_pool_init(ctb_count * sizeof(RefPicListTab),
+ av_buffer_allocz);
+ if (!s->tab_mvf_pool || !s->rpl_tab_pool)
+ goto fail;
+
+ return 0;
+fail:
+ pic_arrays_free(s);
+ return AVERROR(ENOMEM);
+}
+
+static void pred_weight_table(HEVCContext *s, GetBitContext *gb)
+{
+ int i = 0;
+ int j = 0;
+ uint8_t luma_weight_l0_flag[16];
+ uint8_t chroma_weight_l0_flag[16];
+ uint8_t luma_weight_l1_flag[16];
+ uint8_t chroma_weight_l1_flag[16];
+
+ 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);
+ }
+
+ for (i = 0; i < s->sh.nb_refs[L0]; i++) {
+ luma_weight_l0_flag[i] = get_bits1(gb);
+ if (!luma_weight_l0_flag[i]) {
+ s->sh.luma_weight_l0[i] = 1 << s->sh.luma_log2_weight_denom;
+ s->sh.luma_offset_l0[i] = 0;
+ }
+ }
+ if (s->sps->chroma_format_idc != 0) { // FIXME: invert "if" and "for"
+ for (i = 0; i < s->sh.nb_refs[L0]; i++)
+ chroma_weight_l0_flag[i] = get_bits1(gb);
+ } else {
+ for (i = 0; i < s->sh.nb_refs[L0]; i++)
+ chroma_weight_l0_flag[i] = 0;
+ }
+ for (i = 0; i < s->sh.nb_refs[L0]; i++) {
+ if (luma_weight_l0_flag[i]) {
+ int delta_luma_weight_l0 = get_se_golomb(gb);
+ s->sh.luma_weight_l0[i] = (1 << s->sh.luma_log2_weight_denom) + delta_luma_weight_l0;
+ s->sh.luma_offset_l0[i] = get_se_golomb(gb);
+ }
+ if (chroma_weight_l0_flag[i]) {
+ for (j = 0; j < 2; j++) {
+ 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_log2_weight_denom) + 128), -128, 127);
+ }
+ } else {
+ s->sh.chroma_weight_l0[i][0] = 1 << s->sh.chroma_log2_weight_denom;
+ s->sh.chroma_offset_l0[i][0] = 0;
+ s->sh.chroma_weight_l0[i][1] = 1 << s->sh.chroma_log2_weight_denom;
+ s->sh.chroma_offset_l0[i][1] = 0;
+ }
+ }
+ if (s->sh.slice_type == B_SLICE) {
+ for (i = 0; i < s->sh.nb_refs[L1]; i++) {
+ luma_weight_l1_flag[i] = get_bits1(gb);
+ if (!luma_weight_l1_flag[i]) {
+ s->sh.luma_weight_l1[i] = 1 << s->sh.luma_log2_weight_denom;
+ s->sh.luma_offset_l1[i] = 0;
+ }
+ }
+ if (s->sps->chroma_format_idc != 0) {
+ for (i = 0; i < s->sh.nb_refs[L1]; i++)
+ chroma_weight_l1_flag[i] = get_bits1(gb);
+ } else {
+ for (i = 0; i < s->sh.nb_refs[L1]; i++)
+ chroma_weight_l1_flag[i] = 0;
+ }
+ for (i = 0; i < s->sh.nb_refs[L1]; i++) {
+ if (luma_weight_l1_flag[i]) {
+ int delta_luma_weight_l1 = get_se_golomb(gb);
+ s->sh.luma_weight_l1[i] = (1 << s->sh.luma_log2_weight_denom) + delta_luma_weight_l1;
+ s->sh.luma_offset_l1[i] = get_se_golomb(gb);
+ }
+ if (chroma_weight_l1_flag[i]) {
+ for (j = 0; j < 2; j++) {
+ 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_log2_weight_denom) + 128), -128, 127);
+ }
+ } else {
+ s->sh.chroma_weight_l1[i][0] = 1 << s->sh.chroma_log2_weight_denom;
+ s->sh.chroma_offset_l1[i][0] = 0;
+ s->sh.chroma_weight_l1[i][1] = 1 << s->sh.chroma_log2_weight_denom;
+ s->sh.chroma_offset_l1[i][1] = 0;
+ }
+ }
+ }
+}
+
+static int decode_lt_rps(HEVCContext *s, LongTermRPS *rps, GetBitContext *gb)
+{
+ const HEVCSPS *sps = s->sps;
+ int max_poc_lsb = 1 << sps->log2_max_poc_lsb;
+ int prev_delta_msb = 0;
+ int nb_sps = 0, nb_sh;
+ int i;
+
+ rps->nb_refs = 0;
+ if (!sps->long_term_ref_pics_present_flag)
+ return 0;
+
+ if (sps->num_long_term_ref_pics_sps > 0)
+ nb_sps = get_ue_golomb_long(gb);
+ nb_sh = get_ue_golomb_long(gb);
+
+ if (nb_sh + nb_sps > FF_ARRAY_ELEMS(rps->poc))
+ return AVERROR_INVALIDDATA;
+
+ rps->nb_refs = nb_sh + nb_sps;
+
+ for (i = 0; i < rps->nb_refs; i++) {
+ uint8_t delta_poc_msb_present;
+
+ if (i < nb_sps) {
+ uint8_t lt_idx_sps = 0;
+
+ if (sps->num_long_term_ref_pics_sps > 1)
+ lt_idx_sps = get_bits(gb, av_ceil_log2(sps->num_long_term_ref_pics_sps));
+
+ rps->poc[i] = sps->lt_ref_pic_poc_lsb_sps[lt_idx_sps];
+ rps->used[i] = sps->used_by_curr_pic_lt_sps_flag[lt_idx_sps];
+ } else {
+ rps->poc[i] = get_bits(gb, sps->log2_max_poc_lsb);
+ rps->used[i] = get_bits1(gb);
+ }
+
+ delta_poc_msb_present = get_bits1(gb);
+ if (delta_poc_msb_present) {
+ int delta = get_ue_golomb_long(gb);
+
+ if (i && i != nb_sps)
+ delta += prev_delta_msb;
+
+ rps->poc[i] += s->poc - delta * max_poc_lsb - s->sh.pic_order_cnt_lsb;
+ prev_delta_msb = delta;
+ }
+ }
+
+ return 0;
+}
+
+static int set_sps(HEVCContext *s, const HEVCSPS *sps)
+{
+ int ret;
+
+ pic_arrays_free(s);
+ ret = pic_arrays_init(s, sps);
+ if (ret < 0)
+ goto fail;
+
+ s->avctx->coded_width = sps->width;
+ s->avctx->coded_height = sps->height;
+ s->avctx->width = sps->output_width;
+ s->avctx->height = sps->output_height;
+ s->avctx->pix_fmt = sps->pix_fmt;
+ s->avctx->sample_aspect_ratio = sps->vui.sar;
+ s->avctx->has_b_frames = sps->temporal_layer[sps->max_sub_layers - 1].num_reorder_pics;
+
+ ff_hevc_pred_init(&s->hpc, sps->bit_depth);
+ ff_hevc_dsp_init (&s->hevcdsp, sps->bit_depth);
+ ff_videodsp_init (&s->vdsp, sps->bit_depth);
+
+ 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;
+ }
+
+ s->sps = sps;
+ s->vps = s->vps_list[s->sps->vps_id];
+ return 0;
+fail:
+ pic_arrays_free(s);
+ s->sps = NULL;
+ return ret;
+}
+
+static int hls_slice_header(HEVCContext *s)
+{
+ GetBitContext *gb = &s->HEVClc->gb;
+ SliceHeader *sh = &s->sh;
+ int i, j, ret;
+
+ // Coded parameters
+ sh->first_slice_in_pic_flag = get_bits1(gb);
+ if ((IS_IDR(s) || IS_BLA(s)) && sh->first_slice_in_pic_flag) {
+ s->seq_decode = (s->seq_decode + 1) & 0xff;
+ s->max_ra = INT_MAX;
+ if (IS_IDR(s))
+ ff_hevc_clear_refs(s);
+ }
+ if (s->nal_unit_type >= 16 && s->nal_unit_type <= 23)
+ sh->no_output_of_prior_pics_flag = get_bits1(gb);
+
+ sh->pps_id = get_ue_golomb_long(gb);
+ if (sh->pps_id >= MAX_PPS_COUNT || !s->pps_list[sh->pps_id]) {
+ av_log(s->avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", sh->pps_id);
+ return AVERROR_INVALIDDATA;
+ }
+ if (!sh->first_slice_in_pic_flag &&
+ s->pps != (HEVCPPS*)s->pps_list[sh->pps_id]->data) {
+ av_log(s->avctx, AV_LOG_ERROR, "PPS changed between slices.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ s->pps = (HEVCPPS*)s->pps_list[sh->pps_id]->data;
+
+ if (s->sps != (HEVCSPS*)s->sps_list[s->pps->sps_id]->data) {
+ s->sps = (HEVCSPS*)s->sps_list[s->pps->sps_id]->data;
+
+ ff_hevc_clear_refs(s);
+ ret = set_sps(s, s->sps);
+ if (ret < 0)
+ return ret;
+
+ s->seq_decode = (s->seq_decode + 1) & 0xff;
+ s->max_ra = INT_MAX;
+ }
+
+ sh->dependent_slice_segment_flag = 0;
+ if (!sh->first_slice_in_pic_flag) {
+ int slice_address_length;
+
+ if (s->pps->dependent_slice_segments_enabled_flag)
+ sh->dependent_slice_segment_flag = get_bits1(gb);
+
+ slice_address_length = av_ceil_log2(s->sps->ctb_width *
+ s->sps->ctb_height);
+ sh->slice_segment_addr = get_bits(gb, slice_address_length);
+ if (sh->slice_segment_addr >= s->sps->ctb_width * s->sps->ctb_height) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid slice segment address: %u.\n",
+ sh->slice_segment_addr);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (!sh->dependent_slice_segment_flag) {
+ sh->slice_addr = sh->slice_segment_addr;
+ s->slice_idx++;
+ }
+ } else {
+ sh->slice_segment_addr = sh->slice_addr = 0;
+ s->slice_idx = 0;
+ s->slice_initialized = 0;
+ }
+
+ if (!sh->dependent_slice_segment_flag) {
+ s->slice_initialized = 0;
+
+ for (i = 0; i < s->pps->num_extra_slice_header_bits; i++)
+ skip_bits(gb, 1); // slice_reserved_undetermined_flag[]
+
+ sh->slice_type = get_ue_golomb_long(gb);
+ if (!(sh->slice_type == I_SLICE || sh->slice_type == P_SLICE ||
+ sh->slice_type == B_SLICE)) {
+ av_log(s->avctx, AV_LOG_ERROR, "Unknown slice type: %d.\n",
+ sh->slice_type);
+ return AVERROR_INVALIDDATA;
+ }
+ if (IS_IRAP(s) && sh->slice_type != I_SLICE) {
+ av_log(s->avctx, AV_LOG_ERROR, "Inter slices in an IRAP frame.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (s->pps->output_flag_present_flag)
+ sh->pic_output_flag = get_bits1(gb);
+
+ if (s->sps->separate_colour_plane_flag)
+ sh->colour_plane_id = get_bits(gb, 2);
+
+ if (!IS_IDR(s)) {
+ int short_term_ref_pic_set_sps_flag;
+ int poc;
+
+ sh->pic_order_cnt_lsb = get_bits(gb, s->sps->log2_max_poc_lsb);
+ poc = ff_hevc_compute_poc(s, sh->pic_order_cnt_lsb);
+ if (!sh->first_slice_in_pic_flag && poc != s->poc) {
+ av_log(s->avctx, AV_LOG_WARNING,
+ "Ignoring POC change between slices: %d -> %d\n", s->poc, poc);
+ if (s->avctx->err_recognition & AV_EF_EXPLODE)
+ return AVERROR_INVALIDDATA;
+ poc = s->poc;
+ }
+ s->poc = poc;
+
+ short_term_ref_pic_set_sps_flag = get_bits1(gb);
+ if (!short_term_ref_pic_set_sps_flag) {
+ ret = ff_hevc_decode_short_term_rps(s, &sh->slice_rps, s->sps, 1);
+ if (ret < 0)
+ return ret;
+
+ sh->short_term_rps = &sh->slice_rps;
+ } else {
+ int numbits, rps_idx;
+
+ if (!s->sps->nb_st_rps) {
+ av_log(s->avctx, AV_LOG_ERROR, "No ref lists in the SPS.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ numbits = av_ceil_log2(s->sps->nb_st_rps);
+ rps_idx = (numbits > 0) ? get_bits(gb, numbits) : 0;
+ sh->short_term_rps = &s->sps->st_rps[rps_idx];
+ }
+
+ ret = decode_lt_rps(s, &sh->long_term_rps, gb);
+ if (ret < 0) {
+ av_log(s->avctx, AV_LOG_WARNING, "Invalid long term RPS.\n");
+ if (s->avctx->err_recognition & AV_EF_EXPLODE)
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (s->sps->sps_temporal_mvp_enabled_flag)
+ sh->slice_temporal_mvp_enabled_flag = get_bits1(gb);
+ else
+ sh->slice_temporal_mvp_enabled_flag = 0;
+ } else {
+ s->sh.short_term_rps = NULL;
+ s->poc = 0;
+ }
+
+ /* 8.3.1 */
+ if (s->temporal_id == 0 &&
+ s->nal_unit_type != NAL_TRAIL_N &&
+ s->nal_unit_type != NAL_TSA_N &&
+ s->nal_unit_type != NAL_STSA_N &&
+ s->nal_unit_type != NAL_TRAIL_N &&
+ s->nal_unit_type != NAL_RADL_N &&
+ s->nal_unit_type != NAL_RADL_R &&
+ s->nal_unit_type != NAL_RASL_R)
+ s->pocTid0 = s->poc;
+
+ if (s->sps->sao_enabled) {
+ sh->slice_sample_adaptive_offset_flag[0] = get_bits1(gb);
+ sh->slice_sample_adaptive_offset_flag[1] =
+ sh->slice_sample_adaptive_offset_flag[2] = get_bits1(gb);
+ } else {
+ sh->slice_sample_adaptive_offset_flag[0] = 0;
+ sh->slice_sample_adaptive_offset_flag[1] = 0;
+ sh->slice_sample_adaptive_offset_flag[2] = 0;
+ }
+
+ sh->nb_refs[L0] = sh->nb_refs[L1] = 0;
+ if (sh->slice_type == P_SLICE || sh->slice_type == B_SLICE) {
+ int nb_refs;
+
+ sh->nb_refs[L0] = s->pps->num_ref_idx_l0_default_active;
+ if (sh->slice_type == B_SLICE)
+ sh->nb_refs[L1] = s->pps->num_ref_idx_l1_default_active;
+
+ if (get_bits1(gb)) { // num_ref_idx_active_override_flag
+ sh->nb_refs[L0] = get_ue_golomb_long(gb) + 1;
+ if (sh->slice_type == B_SLICE)
+ sh->nb_refs[L1] = get_ue_golomb_long(gb) + 1;
+ }
+ if (sh->nb_refs[L0] > MAX_REFS || sh->nb_refs[L1] > MAX_REFS) {
+ av_log(s->avctx, AV_LOG_ERROR, "Too many refs: %d/%d.\n",
+ sh->nb_refs[L0], sh->nb_refs[L1]);
+ return AVERROR_INVALIDDATA;
+ }
+
+ sh->rpl_modification_flag[0] = 0;
+ sh->rpl_modification_flag[1] = 0;
+ nb_refs = ff_hevc_frame_nb_refs(s);
+ if (!nb_refs) {
+ av_log(s->avctx, AV_LOG_ERROR, "Zero refs for a frame with P or B slices.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (s->pps->lists_modification_present_flag && nb_refs > 1) {
+ sh->rpl_modification_flag[0] = get_bits1(gb);
+ if (sh->rpl_modification_flag[0]) {
+ for (i = 0; i < sh->nb_refs[L0]; i++)
+ sh->list_entry_lx[0][i] = get_bits(gb, av_ceil_log2(nb_refs));
+ }
+
+ if (sh->slice_type == B_SLICE) {
+ sh->rpl_modification_flag[1] = get_bits1(gb);
+ if (sh->rpl_modification_flag[1] == 1)
+ for (i = 0; i < sh->nb_refs[L1]; i++)
+ sh->list_entry_lx[1][i] = get_bits(gb, av_ceil_log2(nb_refs));
+ }
+ }
+
+ if (sh->slice_type == B_SLICE)
+ sh->mvd_l1_zero_flag = get_bits1(gb);
+
+ if (s->pps->cabac_init_present_flag)
+ sh->cabac_init_flag = get_bits1(gb);
+ else
+ sh->cabac_init_flag = 0;
+
+ sh->collocated_ref_idx = 0;
+ if (sh->slice_temporal_mvp_enabled_flag) {
+ sh->collocated_list = L0;
+ if (sh->slice_type == B_SLICE)
+ sh->collocated_list = !get_bits1(gb);
+
+ if (sh->nb_refs[sh->collocated_list] > 1) {
+ sh->collocated_ref_idx = get_ue_golomb_long(gb);
+ if (sh->collocated_ref_idx >= sh->nb_refs[sh->collocated_list]) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Invalid collocated_ref_idx: %d.\n", sh->collocated_ref_idx);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ }
+
+ if ((s->pps->weighted_pred_flag && sh->slice_type == P_SLICE) ||
+ (s->pps->weighted_bipred_flag && sh->slice_type == B_SLICE)) {
+ pred_weight_table(s, gb);
+ }
+
+ sh->max_num_merge_cand = 5 - get_ue_golomb_long(gb);
+ if (sh->max_num_merge_cand < 1 || sh->max_num_merge_cand > 5) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Invalid number of merging MVP candidates: %d.\n",
+ sh->max_num_merge_cand);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ sh->slice_qp_delta = get_se_golomb(gb);
+ if (s->pps->pic_slice_level_chroma_qp_offsets_present_flag) {
+ sh->slice_cb_qp_offset = get_se_golomb(gb);
+ sh->slice_cr_qp_offset = get_se_golomb(gb);
+ } else {
+ sh->slice_cb_qp_offset = 0;
+ sh->slice_cr_qp_offset = 0;
+ }
+
+ if (s->pps->deblocking_filter_control_present_flag) {
+ int deblocking_filter_override_flag = 0;
+
+ if (s->pps->deblocking_filter_override_enabled_flag)
+ deblocking_filter_override_flag = get_bits1(gb);
+
+ if (deblocking_filter_override_flag) {
+ sh->disable_deblocking_filter_flag = get_bits1(gb);
+ if (!sh->disable_deblocking_filter_flag) {
+ sh->beta_offset = get_se_golomb(gb) * 2;
+ sh->tc_offset = get_se_golomb(gb) * 2;
+ }
+ } else {
+ sh->disable_deblocking_filter_flag = s->pps->disable_dbf;
+ sh->beta_offset = s->pps->beta_offset;
+ sh->tc_offset = s->pps->tc_offset;
+ }
+ } else {
+ sh->disable_deblocking_filter_flag = 0;
+ sh->beta_offset = 0;
+ sh->tc_offset = 0;
+ }
+
+ if (s->pps->seq_loop_filter_across_slices_enabled_flag &&
+ (sh->slice_sample_adaptive_offset_flag[0] ||
+ sh->slice_sample_adaptive_offset_flag[1] ||
+ !sh->disable_deblocking_filter_flag)) {
+ sh->slice_loop_filter_across_slices_enabled_flag = get_bits1(gb);
+ } else {
+ sh->slice_loop_filter_across_slices_enabled_flag = s->pps->seq_loop_filter_across_slices_enabled_flag;
+ }
+ } else if (!s->slice_initialized) {
+ av_log(s->avctx, AV_LOG_ERROR, "Independent slice segment missing.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ sh->num_entry_point_offsets = 0;
+ if (s->pps->tiles_enabled_flag || s->pps->entropy_coding_sync_enabled_flag) {
+ sh->num_entry_point_offsets = get_ue_golomb_long(gb);
+ if (sh->num_entry_point_offsets > 0) {
+ int offset_len = get_ue_golomb_long(gb) + 1;
+ 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(sh->num_entry_point_offsets * sizeof(int));
+ sh->offset = av_malloc(sh->num_entry_point_offsets * sizeof(int));
+ sh->size = av_malloc(sh->num_entry_point_offsets * sizeof(int));
+ 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) {
+ int length = get_ue_golomb_long(gb);
+ 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_ctb_addr_rs = sh->slice_segment_addr;
+
+ s->HEVClc->first_qp_group = !s->sh.dependent_slice_segment_flag;
+
+ if (!s->pps->cu_qp_delta_enabled_flag)
+ s->HEVClc->qp_y = ((s->sh.slice_qp + 52 + 2 * s->sps->qp_bd_offset) %
+ (52 + s->sps->qp_bd_offset)) - s->sps->qp_bd_offset;
+
+ s->slice_initialized = 1;
+
+ return 0;
+}
+
+#define CTB(tab, x, y) ((tab)[(y) * s->sps->ctb_width + (x)])
+
+#define SET_SAO(elem, value) \
+do { \
+ if (!sao_merge_up_flag && !sao_merge_left_flag) \
+ sao->elem = value; \
+ else if (sao_merge_left_flag) \
+ sao->elem = CTB(s->sao, rx-1, ry).elem; \
+ else if (sao_merge_up_flag) \
+ sao->elem = CTB(s->sao, rx, ry-1).elem; \
+ else \
+ sao->elem = 0; \
+} while (0)
+
+static void hls_sao_param(HEVCContext *s, int rx, int ry)
+{
+ 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;
+
+ if (s->sh.slice_sample_adaptive_offset_flag[0] ||
+ s->sh.slice_sample_adaptive_offset_flag[1]) {
+ if (rx > 0) {
+ if (lc->ctb_left_flag)
+ sao_merge_left_flag = ff_hevc_sao_merge_flag_decode(s);
+ }
+ if (ry > 0 && !sao_merge_left_flag) {
+ if (lc->ctb_up_flag)
+ sao_merge_up_flag = ff_hevc_sao_merge_flag_decode(s);
+ }
+ }
+
+ for (c_idx = 0; c_idx < 3; c_idx++) {
+ if (!s->sh.slice_sample_adaptive_offset_flag[c_idx]) {
+ sao->type_idx[c_idx] = SAO_NOT_APPLIED;
+ continue;
+ }
+
+ if (c_idx == 2) {
+ sao->type_idx[2] = sao->type_idx[1];
+ sao->eo_class[2] = sao->eo_class[1];
+ } else {
+ SET_SAO(type_idx[c_idx], ff_hevc_sao_type_idx_decode(s));
+ }
+
+ if (sao->type_idx[c_idx] == SAO_NOT_APPLIED)
+ continue;
+
+ for (i = 0; i < 4; i++)
+ SET_SAO(offset_abs[c_idx][i], ff_hevc_sao_offset_abs_decode(s));
+
+ if (sao->type_idx[c_idx] == SAO_BAND) {
+ for (i = 0; i < 4; i++) {
+ if (sao->offset_abs[c_idx][i]) {
+ SET_SAO(offset_sign[c_idx][i], ff_hevc_sao_offset_sign_decode(s));
+ } else {
+ sao->offset_sign[c_idx][i] = 0;
+ }
+ }
+ SET_SAO(band_position[c_idx], ff_hevc_sao_band_position_decode(s));
+ } else if (c_idx != 2) {
+ SET_SAO(eo_class[c_idx], ff_hevc_sao_eo_class_decode(s));
+ }
+
+ // 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;
+ 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];
+ }
+ }
+ }
+}
+
+#undef SET_SAO
+#undef CTB
+
+
+static void 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)
+{
+ HEVCLocalContext *lc = s->HEVClc;
+
+ 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(s, x0, y0, log2_trafo_size, 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(s, x0, y0, log2_trafo_size - 1, 1);
+ s->hpc.intra_pred(s, x0, y0, log2_trafo_size - 1, 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(s, xBase, yBase, log2_trafo_size, 1);
+ s->hpc.intra_pred(s, xBase, yBase, log2_trafo_size, 2);
+ }
+ }
+
+ if (lc->tt.cbf_luma ||
+ SAMPLE_CBF(lc->tt.cbf_cb[trafo_depth], x0, y0) ||
+ SAMPLE_CBF(lc->tt.cbf_cr[trafo_depth], x0, y0)) {
+ int scan_idx = SCAN_DIAG;
+ int scan_idx_c = SCAN_DIAG;
+
+ 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);
+ if (lc->tu.cu_qp_delta != 0)
+ if (ff_hevc_cu_qp_delta_sign_flag(s) == 1)
+ lc->tu.cu_qp_delta = -lc->tu.cu_qp_delta;
+ lc->tu.is_cu_qp_delta_coded = 1;
+ ff_hevc_set_qPy(s, x0, y0, cb_xBase, cb_yBase, log2_cb_size);
+ }
+
+ 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) {
+ scan_idx = SCAN_VERT;
+ } else if (lc->tu.cur_intra_pred_mode >= 22 &&
+ lc->tu.cur_intra_pred_mode <= 30) {
+ scan_idx = SCAN_HORIZ;
+ }
+
+ if (lc->pu.intra_pred_mode_c >= 6 &&
+ lc->pu.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) {
+ scan_idx_c = SCAN_HORIZ;
+ }
+ }
+
+ if (lc->tt.cbf_luma)
+ ff_hevc_hls_residual_coding(s, x0, y0, log2_trafo_size, scan_idx, 0);
+ if (log2_trafo_size > 2) {
+ if (SAMPLE_CBF(lc->tt.cbf_cb[trafo_depth], x0, y0))
+ ff_hevc_hls_residual_coding(s, x0, y0, log2_trafo_size - 1, scan_idx_c, 1);
+ if (SAMPLE_CBF(lc->tt.cbf_cr[trafo_depth], x0, y0))
+ ff_hevc_hls_residual_coding(s, x0, y0, log2_trafo_size - 1, scan_idx_c, 2);
+ } else if (blk_idx == 3) {
+ if (SAMPLE_CBF(lc->tt.cbf_cb[trafo_depth], xBase, yBase))
+ ff_hevc_hls_residual_coding(s, xBase, yBase, log2_trafo_size, scan_idx_c, 1);
+ if (SAMPLE_CBF(lc->tt.cbf_cr[trafo_depth], xBase, yBase))
+ ff_hevc_hls_residual_coding(s, xBase, yBase, log2_trafo_size, scan_idx_c, 2);
+ }
+ }
+}
+
+static void set_deblocking_bypass(HEVCContext *s, int x0, int y0, int log2_cb_size)
+{
+ int cb_size = 1 << log2_cb_size;
+ int log2_min_pu_size = s->sps->log2_min_pu_size;
+
+ int min_pu_width = s->sps->min_pu_width;
+ int x_end = FFMIN(x0 + cb_size, s->sps->width);
+ int y_end = FFMIN(y0 + cb_size, s->sps->height);
+ int i, j;
+
+ for (j = (y0 >> log2_min_pu_size); j < (y_end >> log2_min_pu_size); j++)
+ for (i = (x0 >> log2_min_pu_size); i < (x_end >> log2_min_pu_size); i++)
+ s->is_pcm[i + j * min_pu_width] = 2;
+}
+
+static void 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)
+{
+ HEVCLocalContext *lc = s->HEVClc;
+ uint8_t split_transform_flag;
+
+ if (trafo_depth > 0 && log2_trafo_size == 2) {
+ SAMPLE_CBF(lc->tt.cbf_cb[trafo_depth], x0, y0) =
+ SAMPLE_CBF(lc->tt.cbf_cb[trafo_depth - 1], xBase, yBase);
+ SAMPLE_CBF(lc->tt.cbf_cr[trafo_depth], x0, y0) =
+ SAMPLE_CBF(lc->tt.cbf_cr[trafo_depth - 1], xBase, yBase);
+ } else {
+ SAMPLE_CBF(lc->tt.cbf_cb[trafo_depth], x0, y0) =
+ SAMPLE_CBF(lc->tt.cbf_cr[trafo_depth], x0, y0) = 0;
+ }
+
+ if (lc->cu.intra_split_flag) {
+ if (trafo_depth == 1)
+ lc->tu.cur_intra_pred_mode = lc->pu.intra_pred_mode[blk_idx];
+ } else {
+ lc->tu.cur_intra_pred_mode = lc->pu.intra_pred_mode[0];
+ }
+
+ lc->tt.cbf_luma = 1;
+
+ lc->tt.inter_split_flag = (s->sps->max_transform_hierarchy_depth_inter == 0 &&
+ lc->cu.pred_mode == MODE_INTER &&
+ lc->cu.part_mode != PART_2Nx2N && trafo_depth == 0);
+
+ if (log2_trafo_size <= s->sps->log2_max_trafo_size &&
+ log2_trafo_size > s->sps->log2_min_tb_size &&
+ trafo_depth < lc->cu.max_trafo_depth &&
+ !(lc->cu.intra_split_flag && trafo_depth == 0)) {
+ split_transform_flag = ff_hevc_split_transform_flag_decode(s, log2_trafo_size);
+ } else {
+ split_transform_flag = (log2_trafo_size > s->sps->log2_max_trafo_size ||
+ (lc->cu.intra_split_flag && (trafo_depth == 0)) ||
+ lc->tt.inter_split_flag);
+ }
+
+ if (log2_trafo_size > 2) {
+ if (trafo_depth == 0 ||
+ SAMPLE_CBF(lc->tt.cbf_cb[trafo_depth - 1], xBase, yBase)) {
+ SAMPLE_CBF(lc->tt.cbf_cb[trafo_depth], x0, y0) =
+ ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
+ }
+
+ if (trafo_depth == 0 || SAMPLE_CBF(lc->tt.cbf_cr[trafo_depth - 1], xBase, yBase)) {
+ SAMPLE_CBF(lc->tt.cbf_cr[trafo_depth], x0, y0) =
+ ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
+ }
+ }
+
+ if (split_transform_flag) {
+ int x1 = x0 + ((1 << log2_trafo_size) >> 1);
+ int y1 = y0 + ((1 << log2_trafo_size) >> 1);
+
+ hls_transform_tree(s, x0, y0, x0, y0, cb_xBase, cb_yBase, log2_cb_size,
+ log2_trafo_size - 1, trafo_depth + 1, 0);
+ hls_transform_tree(s, x1, y0, x0, y0, cb_xBase, cb_yBase, log2_cb_size,
+ log2_trafo_size - 1, trafo_depth + 1, 1);
+ hls_transform_tree(s, x0, y1, x0, y0, cb_xBase, cb_yBase, log2_cb_size,
+ log2_trafo_size - 1, trafo_depth + 1, 2);
+ hls_transform_tree(s, x1, y1, x0, y0, cb_xBase, cb_yBase, log2_cb_size,
+ log2_trafo_size - 1, trafo_depth + 1, 3);
+ } else {
+ int min_tu_size = 1 << s->sps->log2_min_tb_size;
+ int log2_min_tu_size = s->sps->log2_min_tb_size;
+ int min_tu_width = s->sps->min_tb_width;
+
+ if (lc->cu.pred_mode == MODE_INTRA || trafo_depth != 0 ||
+ SAMPLE_CBF(lc->tt.cbf_cb[trafo_depth], x0, y0) ||
+ SAMPLE_CBF(lc->tt.cbf_cr[trafo_depth], x0, y0)) {
+ lc->tt.cbf_luma = ff_hevc_cbf_luma_decode(s, trafo_depth);
+ }
+
+ hls_transform_unit(s, x0, y0, xBase, yBase, cb_xBase, cb_yBase,
+ log2_cb_size, log2_trafo_size, trafo_depth, blk_idx);
+
+ // TODO: store cbf_luma somewhere else
+ if (lc->tt.cbf_luma) {
+ int i, j;
+ for (i = 0; i < (1 << log2_trafo_size); i += min_tu_size)
+ for (j = 0; j < (1 << log2_trafo_size); j += min_tu_size) {
+ int x_tu = (x0 + j) >> log2_min_tu_size;
+ int y_tu = (y0 + i) >> log2_min_tu_size;
+ s->cbf_luma[y_tu * min_tu_width + x_tu] = 1;
+ }
+ }
+ if (!s->sh.disable_deblocking_filter_flag) {
+ ff_hevc_deblocking_boundary_strengths(s, x0, y0, log2_trafo_size,
+ lc->slice_or_tiles_up_boundary,
+ lc->slice_or_tiles_left_boundary);
+ if (s->pps->transquant_bypass_enable_flag && lc->cu.cu_transquant_bypass_flag)
+ set_deblocking_bypass(s, x0, y0, log2_trafo_size);
+ }
+ }
+}
+
+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;
+ GetBitContext gb;
+ int cb_size = 1 << log2_cb_size;
+ int stride0 = s->frame->linesize[0];
+ uint8_t *dst0 = &s->frame->data[0][y0 * stride0 + (x0 << s->sps->pixel_shift)];
+ int stride1 = s->frame->linesize[1];
+ uint8_t *dst1 = &s->frame->data[1][(y0 >> s->sps->vshift[1]) * stride1 + ((x0 >> s->sps->hshift[1]) << s->sps->pixel_shift)];
+ 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;
+ const uint8_t *pcm = skip_bytes(&s->HEVClc->cc, (length + 7) >> 3);
+ int ret;
+
+ ff_hevc_deblocking_boundary_strengths(s, x0, y0, log2_cb_size,
+ lc->slice_or_tiles_up_boundary,
+ lc->slice_or_tiles_left_boundary);
+
+ ret = init_get_bits(&gb, pcm, length);
+ if (ret < 0)
+ return ret;
+
+ s->hevcdsp.put_pcm(dst0, stride0, cb_size, &gb, s->sps->pcm.bit_depth);
+ s->hevcdsp.put_pcm(dst1, stride1, cb_size / 2, &gb, s->sps->pcm.bit_depth_chroma);
+ s->hevcdsp.put_pcm(dst2, stride2, cb_size / 2, &gb, s->sps->pcm.bit_depth_chroma);
+ return 0;
+}
+
+/**
+ * 8.5.3.2.2.1 Luma sample 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 ref reference picture buffer at origin (0, 0)
+ * @param mv motion vector (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
+ */
+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)
+{
+ 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];
+
+ 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]) {
+ int offset = extra_top * srcstride + (extra_left << s->sps->pixel_shift);
+
+ s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, srcstride, src - offset, srcstride,
+ block_w + ff_hevc_qpel_extra[mx], block_h + ff_hevc_qpel_extra[my],
+ x_off - extra_left, y_off - extra_top,
+ pic_width, pic_height);
+ src = lc->edge_emu_buffer + offset;
+ }
+ s->hevcdsp.put_hevc_qpel[my][mx](dst, dststride, src, srcstride, block_w,
+ block_h, lc->mc_buffer);
+}
+
+/**
+ * 8.5.3.2.2.2 Chroma sample interpolation process
+ *
+ * @param s HEVC decoding context
+ * @param dst1 target buffer for block data at block position (U plane)
+ * @param dst2 target buffer for block data at block position (V plane)
+ * @param dststride stride of the dst1 and dst2 buffers
+ * @param ref reference picture buffer at origin (0, 0)
+ * @param mv motion vector (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
+ */
+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)
+{
+ 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);
+
+ 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) {
+ int offset1 = EPEL_EXTRA_BEFORE * (src1stride + (1 << s->sps->pixel_shift));
+ int offset2 = EPEL_EXTRA_BEFORE * (src2stride + (1 << s->sps->pixel_shift));
+
+ s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src1stride, src1 - offset1, src1stride,
+ block_w + EPEL_EXTRA, block_h + EPEL_EXTRA,
+ x_off - EPEL_EXTRA_BEFORE,
+ y_off - EPEL_EXTRA_BEFORE,
+ pic_width, pic_height);
+
+ src1 = lc->edge_emu_buffer + offset1;
+ s->hevcdsp.put_hevc_epel[!!my][!!mx](dst1, dststride, src1, src1stride,
+ block_w, block_h, mx, my, lc->mc_buffer);
+
+ s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src2stride, src2 - offset2, src2stride,
+ block_w + EPEL_EXTRA, block_h + EPEL_EXTRA,
+ x_off - EPEL_EXTRA_BEFORE,
+ y_off - EPEL_EXTRA_BEFORE,
+ pic_width, pic_height);
+ src2 = lc->edge_emu_buffer + offset2;
+ 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);
+ }
+}
+
+static void hevc_await_progress(HEVCContext *s, HEVCFrame *ref,
+ const Mv *mv, int y0, int height)
+{
+ int y = (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)
+{
+#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;
+ int merge_idx = 0;
+ struct MvField current_mv = {{{ 0 }}};
+
+ int min_pu_width = s->sps->min_pu_width;
+
+ 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);
+ int log2_min_cb_size = s->sps->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 ref_idx[2];
+ int mvp_flag[2];
+ int x_pu, y_pu;
+ int i, j;
+
+ if (SAMPLE_CTB(s->skip_flag, x_cb, y_cb)) {
+ if (s->sh.max_num_merge_cand > 1)
+ merge_idx = ff_hevc_merge_idx_decode(s);
+ else
+ merge_idx = 0;
+
+ ff_hevc_luma_mv_merge_mode(s, x0, y0, 1 << log2_cb_size, 1 << log2_cb_size,
+ log2_cb_size, partIdx, merge_idx, &current_mv);
+ x_pu = x0 >> s->sps->log2_min_pu_size;
+ y_pu = y0 >> s->sps->log2_min_pu_size;
+
+ for (i = 0; i < nPbW >> s->sps->log2_min_pu_size; i++)
+ for (j = 0; j < nPbH >> s->sps->log2_min_pu_size; j++)
+ tab_mvf[(y_pu + j) * min_pu_width + x_pu + i] = current_mv;
+ } else { /* MODE_INTER */
+ lc->pu.merge_flag = ff_hevc_merge_flag_decode(s);
+ if (lc->pu.merge_flag) {
+ if (s->sh.max_num_merge_cand > 1)
+ merge_idx = ff_hevc_merge_idx_decode(s);
+ else
+ merge_idx = 0;
+
+ ff_hevc_luma_mv_merge_mode(s, x0, y0, nPbW, nPbH, log2_cb_size,
+ partIdx, merge_idx, &current_mv);
+ x_pu = x0 >> s->sps->log2_min_pu_size;
+ y_pu = y0 >> s->sps->log2_min_pu_size;
+
+ for (i = 0; i < nPbW >> s->sps->log2_min_pu_size; i++)
+ for (j = 0; j < nPbH >> s->sps->log2_min_pu_size; j++)
+ tab_mvf[(y_pu + j) * min_pu_width + x_pu + i] = current_mv;
+ } else {
+ enum InterPredIdc inter_pred_idc = PRED_L0;
+ ff_hevc_set_neighbour_available(s, x0, y0, nPbW, nPbH);
+ if (s->sh.slice_type == B_SLICE)
+ inter_pred_idc = ff_hevc_inter_pred_idc_decode(s, nPbW, nPbH);
+
+ if (inter_pred_idc != PRED_L1) {
+ if (s->sh.nb_refs[L0]) {
+ 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;
+ 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, mvp_flag[0], 0);
+ current_mv.mv[0].x += lc->pu.mvd.x;
+ current_mv.mv[0].y += lc->pu.mvd.y;
+ }
+
+ if (inter_pred_idc != PRED_L0) {
+ if (s->sh.nb_refs[L1]) {
+ ref_idx[1] = ff_hevc_ref_idx_lx_decode(s, s->sh.nb_refs[L1]);
+ current_mv.ref_idx[1] = ref_idx[1];
+ }
+
+ if (s->sh.mvd_l1_zero_flag == 1 && inter_pred_idc == PRED_BI) {
+ lc->pu.mvd.x = 0;
+ lc->pu.mvd.y = 0;
+ } else {
+ ff_hevc_hls_mvd_coding(s, x0, y0, 1);
+ }
+
+ current_mv.pred_flag[1] = 1;
+ 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, mvp_flag[1], 1);
+ current_mv.mv[1].x += lc->pu.mvd.x;
+ current_mv.mv[1].y += lc->pu.mvd.y;
+ }
+
+ x_pu = x0 >> s->sps->log2_min_pu_size;
+ y_pu = y0 >> s->sps->log2_min_pu_size;
+
+ for (i = 0; i < nPbW >> s->sps->log2_min_pu_size; i++)
+ for(j = 0; j < nPbH >> s->sps->log2_min_pu_size; j++)
+ tab_mvf[(y_pu + j) * min_pu_width + x_pu + i] = current_mv;
+ }
+ }
+
+ if (current_mv.pred_flag[0]) {
+ 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]) {
+ 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);
+ }
+ }
+}
+
+/**
+ * 8.4.1
+ */
+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;
+ int x_pu = x0 >> s->sps->log2_min_pu_size;
+ int y_pu = y0 >> s->sps->log2_min_pu_size;
+ int min_pu_width = s->sps->min_pu_width;
+ int size_in_pus = pu_size >> s->sps->log2_min_pu_size;
+ int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
+ int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
+
+ int cand_up = (lc->ctb_up_flag || y0b) ?
+ s->tab_ipm[(y_pu - 1) * min_pu_width + x_pu] : INTRA_DC;
+ int cand_left = (lc->ctb_left_flag || x0b) ?
+ s->tab_ipm[y_pu * min_pu_width + x_pu - 1] : INTRA_DC;
+
+ int y_ctb = (y0 >> (s->sps->log2_ctb_size)) << (s->sps->log2_ctb_size);
+
+ MvField *tab_mvf = s->ref->tab_mvf;
+ int intra_pred_mode;
+ int candidate[3];
+ int i, j;
+
+ // intra_pred_mode prediction does not cross vertical CTB boundaries
+ if ((y0 - 1) < y_ctb)
+ cand_up = INTRA_DC;
+
+ if (cand_left == cand_up) {
+ if (cand_left < 2) {
+ candidate[0] = INTRA_PLANAR;
+ candidate[1] = INTRA_DC;
+ candidate[2] = INTRA_ANGULAR_26;
+ } else {
+ candidate[0] = cand_left;
+ candidate[1] = 2 + ((cand_left - 2 - 1 + 32) & 31);
+ candidate[2] = 2 + ((cand_left - 2 + 1) & 31);
+ }
+ } else {
+ candidate[0] = cand_left;
+ candidate[1] = cand_up;
+ if (candidate[0] != INTRA_PLANAR && candidate[1] != INTRA_PLANAR) {
+ candidate[2] = INTRA_PLANAR;
+ } else if (candidate[0] != INTRA_DC && candidate[1] != INTRA_DC) {
+ candidate[2] = INTRA_DC;
+ } else {
+ candidate[2] = INTRA_ANGULAR_26;
+ }
+ }
+
+ if (prev_intra_luma_pred_flag) {
+ intra_pred_mode = candidate[lc->pu.mpm_idx];
+ } else {
+ if (candidate[0] > candidate[1])
+ FFSWAP(uint8_t, candidate[0], candidate[1]);
+ if (candidate[0] > candidate[2])
+ FFSWAP(uint8_t, candidate[0], candidate[2]);
+ if (candidate[1] > candidate[2])
+ FFSWAP(uint8_t, candidate[1], candidate[2]);
+
+ intra_pred_mode = lc->pu.rem_intra_luma_pred_mode;
+ for (i = 0; i < 3; i++)
+ if (intra_pred_mode >= candidate[i])
+ intra_pred_mode++;
+ }
+
+ /* write the intra prediction units into the mv array */
+ if (!size_in_pus)
+ size_in_pus = 1;
+ for (i = 0; i < size_in_pus; i++) {
+ memset(&s->tab_ipm[(y_pu + i) * min_pu_width + x_pu],
+ 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;
+ }
+ }
+
+ return intra_pred_mode;
+}
+
+static av_always_inline void set_ct_depth(HEVCContext *s, int x0, int y0,
+ int log2_cb_size, int ct_depth)
+{
+ int length = (1 << log2_cb_size) >> s->sps->log2_min_cb_size;
+ int x_cb = x0 >> s->sps->log2_min_cb_size;
+ int y_cb = y0 >> s->sps->log2_min_cb_size;
+ int y;
+
+ for (y = 0; y < length; y++)
+ memset(&s->tab_ct_depth[(y_cb + y) * s->sps->min_cb_width + x_cb],
+ ct_depth, length);
+}
+
+static void intra_prediction_unit(HEVCContext *s, int x0, int y0,
+ int log2_cb_size)
+{
+ 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;
+ int pb_size = (1 << log2_cb_size) >> split;
+ int side = split + 1;
+ int chroma_mode;
+ int i, j;
+
+ for (i = 0; i < side; i++)
+ for (j = 0; j < side; j++)
+ prev_intra_luma_pred_flag[2 * i + j] = ff_hevc_prev_intra_luma_pred_flag_decode(s);
+
+ for (i = 0; i < side; i++) {
+ for (j = 0; j < side; j++) {
+ if (prev_intra_luma_pred_flag[2 * i + j])
+ lc->pu.mpm_idx = ff_hevc_mpm_idx_decode(s);
+ else
+ lc->pu.rem_intra_luma_pred_mode = ff_hevc_rem_intra_luma_pred_mode_decode(s);
+
+ lc->pu.intra_pred_mode[2 * i + j] =
+ luma_intra_pred_mode(s, x0 + pb_size * j, y0 + pb_size * i, pb_size,
+ prev_intra_luma_pred_flag[2 * i + j]);
+ }
+ }
+
+ 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];
+ }
+}
+
+static void intra_prediction_unit_default_value(HEVCContext *s,
+ int x0, int y0,
+ int log2_cb_size)
+{
+ 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;
+ MvField *tab_mvf = s->ref->tab_mvf;
+ int x_pu = x0 >> s->sps->log2_min_pu_size;
+ int y_pu = y0 >> s->sps->log2_min_pu_size;
+ int j, k;
+
+ if (size_in_pus == 0)
+ size_in_pus = 1;
+ for (j = 0; j < size_in_pus; j++) {
+ memset(&s->tab_ipm[(y_pu + j) * min_pu_width + x_pu], INTRA_DC, size_in_pus);
+ 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;
+ }
+}
+
+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;
+ 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 x, y;
+
+ lc->cu.x = x0;
+ lc->cu.y = y0;
+ lc->cu.rqt_root_cbf = 1;
+
+ lc->cu.pred_mode = MODE_INTRA;
+ lc->cu.part_mode = PART_2Nx2N;
+ lc->cu.intra_split_flag = 0;
+ lc->cu.pcm_flag = 0;
+ SAMPLE_CTB(s->skip_flag, x_cb, y_cb) = 0;
+ for (x = 0; x < 4; x++)
+ lc->pu.intra_pred_mode[x] = 1;
+ if (s->pps->transquant_bypass_enable_flag) {
+ lc->cu.cu_transquant_bypass_flag = ff_hevc_cu_transquant_bypass_flag_decode(s);
+ if (lc->cu.cu_transquant_bypass_flag)
+ set_deblocking_bypass(s, x0, y0, log2_cb_size);
+ } else
+ lc->cu.cu_transquant_bypass_flag = 0;
+
+ 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;
+ }
+
+ if (SAMPLE_CTB(s->skip_flag, x_cb, y_cb)) {
+ hls_prediction_unit(s, x0, y0, cb_size, cb_size, log2_cb_size, 0);
+ intra_prediction_unit_default_value(s, x0, y0, log2_cb_size);
+
+ if (!s->sh.disable_deblocking_filter_flag)
+ ff_hevc_deblocking_boundary_strengths(s, x0, y0, log2_cb_size,
+ lc->slice_or_tiles_up_boundary,
+ lc->slice_or_tiles_left_boundary);
+ } else {
+ if (s->sh.slice_type != I_SLICE)
+ lc->cu.pred_mode = ff_hevc_pred_mode_decode(s);
+ if (lc->cu.pred_mode != MODE_INTRA ||
+ log2_cb_size == s->sps->log2_min_cb_size) {
+ lc->cu.part_mode = ff_hevc_part_mode_decode(s, log2_cb_size);
+ lc->cu.intra_split_flag = lc->cu.part_mode == PART_NxN &&
+ lc->cu.pred_mode == MODE_INTRA;
+ }
+
+ if (lc->cu.pred_mode == MODE_INTRA) {
+ if (lc->cu.part_mode == PART_2Nx2N && s->sps->pcm_enabled_flag &&
+ log2_cb_size >= s->sps->pcm.log2_min_pcm_cb_size &&
+ log2_cb_size <= s->sps->pcm.log2_max_pcm_cb_size) {
+ lc->cu.pcm_flag = ff_hevc_pcm_flag_decode(s);
+ }
+ if (lc->cu.pcm_flag) {
+ int ret;
+ intra_prediction_unit_default_value(s, x0, y0, log2_cb_size);
+ ret = hls_pcm_sample(s, x0, y0, log2_cb_size);
+ if (s->sps->pcm.loop_filter_disable_flag)
+ set_deblocking_bypass(s, x0, y0, log2_cb_size);
+
+ if (ret < 0)
+ return ret;
+ } else {
+ intra_prediction_unit(s, x0, y0, log2_cb_size);
+ }
+ } else {
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ break;
+ }
+ }
+
+ if (!lc->cu.pcm_flag) {
+ if (lc->cu.pred_mode != MODE_INTRA &&
+ !(lc->cu.part_mode == PART_2Nx2N && lc->pu.merge_flag)) {
+ lc->cu.rqt_root_cbf = ff_hevc_no_residual_syntax_flag_decode(s);
+ }
+ if (lc->cu.rqt_root_cbf) {
+ 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;
+ hls_transform_tree(s, x0, y0, x0, y0, x0, y0, log2_cb_size,
+ log2_cb_size, 0, 0);
+ } else {
+ if (!s->sh.disable_deblocking_filter_flag)
+ ff_hevc_deblocking_boundary_strengths(s, x0, y0, log2_cb_size,
+ lc->slice_or_tiles_up_boundary,
+ lc->slice_or_tiles_left_boundary);
+ }
+ }
+ }
+
+ 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);
+
+ x = y_cb * min_cb_width + x_cb;
+ for (y = 0; y < length; y++) {
+ memset(&s->qp_y_tab[x], lc->qp_y, length);
+ x += min_cb_width;
+ }
+
+ set_ct_depth(s, x0, y0, log2_cb_size, lc->ct.depth);
+
+ return 0;
+}
+
+static int hls_coding_quadtree(HEVCContext *s, int x0, int y0,
+ int log2_cb_size, int cb_depth)
+{
+ HEVCLocalContext *lc = s->HEVClc;
+ const int cb_size = 1 << log2_cb_size;
+ int ret;
+
+ 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) {
+ SAMPLE(s->split_cu_flag, x0, y0) =
+ ff_hevc_split_coding_unit_flag_decode(s, cb_depth, x0, y0);
+ } else {
+ SAMPLE(s->split_cu_flag, x0, y0) =
+ (log2_cb_size > s->sps->log2_min_cb_size);
+ }
+ if (s->pps->cu_qp_delta_enabled_flag &&
+ log2_cb_size >= s->sps->log2_ctb_size - s->pps->diff_cu_qp_delta_depth) {
+ lc->tu.is_cu_qp_delta_coded = 0;
+ lc->tu.cu_qp_delta = 0;
+ }
+
+ if (SAMPLE(s->split_cu_flag, x0, y0)) {
+ const int cb_size_split = cb_size >> 1;
+ const int x1 = x0 + cb_size_split;
+ const int y1 = y0 + cb_size_split;
+ int more_data = 0;
+
+ more_data = hls_coding_quadtree(s, x0, y0, log2_cb_size - 1, cb_depth + 1);
+ if (more_data < 0)
+ return more_data;
+
+ if (more_data && x1 < s->sps->width)
+ more_data = hls_coding_quadtree(s, x1, y0, log2_cb_size - 1, cb_depth + 1);
+ if (more_data && y1 < s->sps->height)
+ more_data = hls_coding_quadtree(s, x0, y1, log2_cb_size - 1, cb_depth + 1);
+ if (more_data && x1 < s->sps->width &&
+ y1 < s->sps->height) {
+ return hls_coding_quadtree(s, x1, y1, log2_cb_size - 1, cb_depth + 1);
+ }
+ if (more_data)
+ return ((x1 + cb_size_split) < s->sps->width ||
+ (y1 + cb_size_split) < s->sps->height);
+ else
+ return 0;
+ } else {
+ 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;
+}
+
+static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb, int ctb_addr_ts)
+{
+ 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;
+
+ int tile_left_boundary;
+ int tile_up_boundary;
+ int slice_left_boundary;
+ int slice_up_boundary;
+
+ s->tab_slice_address[ctb_addr_rs] = s->sh.slice_addr;
+
+ if (s->pps->entropy_coding_sync_enabled_flag) {
+ if (x_ctb == 0 && (y_ctb & (ctb_size - 1)) == 0)
+ lc->first_qp_group = 1;
+ lc->end_of_tiles_x = s->sps->width;
+ } 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;
+ }
+ } else {
+ lc->end_of_tiles_x = s->sps->width;
+ }
+
+ lc->end_of_tiles_y = FFMIN(y_ctb + ctb_size, s->sps->height);
+
+ if (s->pps->tiles_enabled_flag) {
+ tile_left_boundary = ((x_ctb > 0) &&
+ (s->pps->tile_id[ctb_addr_ts] == s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs - 1]]));
+ slice_left_boundary = ((x_ctb > 0) &&
+ (s->tab_slice_address[ctb_addr_rs] == s->tab_slice_address[ctb_addr_rs - 1]));
+ tile_up_boundary = ((y_ctb > 0) &&
+ (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]]));
+ slice_up_boundary = ((y_ctb > 0) &&
+ (s->tab_slice_address[ctb_addr_rs] == s->tab_slice_address[ctb_addr_rs - s->sps->ctb_width]));
+ } else {
+ tile_left_boundary =
+ tile_up_boundary = 1;
+ slice_left_boundary = ctb_addr_in_slice > 0;
+ slice_up_boundary = ctb_addr_in_slice >= s->sps->ctb_width;
+ }
+ lc->slice_or_tiles_left_boundary = (!slice_left_boundary) + (!tile_left_boundary << 1);
+ lc->slice_or_tiles_up_boundary = (!slice_up_boundary + (!tile_up_boundary << 1));
+ lc->ctb_left_flag = ((x_ctb > 0) && (ctb_addr_in_slice > 0) && tile_left_boundary);
+ lc->ctb_up_flag = ((y_ctb > 0) && (ctb_addr_in_slice >= s->sps->ctb_width) && tile_up_boundary);
+ lc->ctb_up_right_flag = ((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]]));
+ 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_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];
+
+ while (more_data && ctb_addr_ts < s->sps->ctb_size) {
+ int ctb_addr_rs = s->pps->ctb_addr_ts_to_rs[ctb_addr_ts];
+
+ x_ctb = (ctb_addr_rs % ((s->sps->width + (ctb_size - 1)) >> s->sps->log2_ctb_size)) << s->sps->log2_ctb_size;
+ y_ctb = (ctb_addr_rs / ((s->sps->width + (ctb_size - 1)) >> s->sps->log2_ctb_size)) << s->sps->log2_ctb_size;
+ hls_decode_neighbour(s, x_ctb, y_ctb, ctb_addr_ts);
+
+ 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);
+
+ s->deblock[ctb_addr_rs].beta_offset = s->sh.beta_offset;
+ s->deblock[ctb_addr_rs].tc_offset = s->sh.tc_offset;
+ s->filter_slice_edges[ctb_addr_rs] = s->sh.slice_loop_filter_across_slices_enabled_flag;
+
+ more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->sps->log2_ctb_size, 0);
+ if (more_data < 0)
+ return more_data;
+
+ ctb_addr_ts++;
+ ff_hevc_save_states(s, ctb_addr_ts);
+ ff_hevc_hls_filters(s, x_ctb, y_ctb, ctb_size);
+ }
+
+ if (x_ctb + ctb_size >= s->sps->width &&
+ y_ctb + ctb_size >= s->sps->height)
+ ff_hevc_hls_filter(s, x_ctb, y_ctb);
+
+ 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)
+ 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);
+ 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((s->sh.num_entry_point_offsets + 1) * sizeof(int));
+ int *arg = av_malloc((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_malloc(sizeof(HEVCLocalContext));
+ s->HEVClcList[i]->edge_emu_buffer = av_malloc((MAX_PB_SIZE + 7) * s->frame->linesize[0]);
+ 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;
+ int nuh_layer_id;
+
+ if (get_bits1(gb) != 0)
+ return AVERROR_INVALIDDATA;
+
+ s->nal_unit_type = get_bits(gb, 6);
+
+ nuh_layer_id = get_bits(gb, 6);
+ s->temporal_id = get_bits(gb, 3) - 1;
+ if (s->temporal_id < 0)
+ return AVERROR_INVALIDDATA;
+
+ av_log(s->avctx, AV_LOG_DEBUG,
+ "nal_unit_type: %d, nuh_layer_id: %dtemporal_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 hevc_frame_start(HEVCContext *s)
+{
+ HEVCLocalContext *lc = s->HEVClc;
+ 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->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);
+
+ lc->start_of_tiles_x = 0;
+ s->is_decoded = 0;
+
+ 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);
+ if (ret < 0)
+ goto fail;
+
+ av_fast_malloc(&lc->edge_emu_buffer, &lc->edge_emu_buffer_size,
+ (MAX_PB_SIZE + 7) * s->ref->frame->linesize[0]);
+ if (!lc->edge_emu_buffer) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ ret = ff_hevc_frame_rps(s);
+ if (ret < 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "Error constructing the frame RPS.\n");
+ goto fail;
+ }
+
+ av_frame_unref(s->output_frame);
+ ret = ff_hevc_output_frame(s, s->output_frame, 0);
+ if (ret < 0)
+ goto fail;
+
+ ff_thread_finish_setup(s->avctx);
+
+ return 0;
+fail:
+ if (s->ref && s->threads_type == FF_THREAD_FRAME)
+ ff_thread_report_progress(&s->ref->tf, INT_MAX, 0);
+ s->ref = NULL;
+ return ret;
+}
+
+static int decode_nal_unit(HEVCContext *s, const uint8_t *nal, int length)
+{
+ HEVCLocalContext *lc = s->HEVClc;
+ GetBitContext *gb = &lc->gb;
+ int ctb_addr_ts;
+ int ret;
+
+ ret = init_get_bits8(gb, nal, length);
+ if (ret < 0)
+ return ret;
+
+ ret = hls_nal_unit(s);
+ if (ret < 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid NAL unit %d, skipping.\n",
+ s->nal_unit_type);
+ if (s->avctx->err_recognition & AV_EF_EXPLODE)
+ return ret;
+ return 0;
+ } else if (!ret)
+ return 0;
+
+ switch (s->nal_unit_type) {
+ case NAL_VPS:
+ ret = ff_hevc_decode_nal_vps(s);
+ if (ret < 0)
+ return ret;
+ break;
+ case NAL_SPS:
+ ret = ff_hevc_decode_nal_sps(s);
+ if (ret < 0)
+ return ret;
+ break;
+ case NAL_PPS:
+ ret = ff_hevc_decode_nal_pps(s);
+ if (ret < 0)
+ return ret;
+ break;
+ case NAL_SEI_PREFIX:
+ case NAL_SEI_SUFFIX:
+ ret = ff_hevc_decode_nal_sei(s);
+ if (ret < 0)
+ return ret;
+ break;
+ case NAL_TRAIL_R:
+ case NAL_TRAIL_N:
+ case NAL_TSA_N:
+ case NAL_TSA_R:
+ case NAL_STSA_N:
+ case NAL_STSA_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:
+ case NAL_RADL_N:
+ case NAL_RADL_R:
+ case NAL_RASL_N:
+ case NAL_RASL_R:
+ ret = hls_slice_header(s);
+ if (ret < 0)
+ return ret;
+
+ if (s->max_ra == INT_MAX) {
+ if (s->nal_unit_type == NAL_CRA_NUT || IS_BLA(s)) {
+ s->max_ra = s->poc;
+ } else {
+ if (IS_IDR(s))
+ s->max_ra = INT_MIN;
+ }
+ }
+
+ if ((s->nal_unit_type == NAL_RASL_R || s->nal_unit_type == NAL_RASL_N) &&
+ s->poc <= s->max_ra) {
+ s->is_decoded = 0;
+ break;
+ } else {
+ if (s->nal_unit_type == NAL_RASL_R && s->poc > s->max_ra)
+ s->max_ra = INT_MIN;
+ }
+
+ if (s->sh.first_slice_in_pic_flag) {
+ ret = hevc_frame_start(s);
+ if (ret < 0)
+ return ret;
+ } else if (!s->ref) {
+ av_log(s->avctx, AV_LOG_ERROR, "First slice in a frame missing.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (!s->sh.dependent_slice_segment_flag &&
+ s->sh.slice_type != I_SLICE) {
+ ret = ff_hevc_slice_rpl(s);
+ if (ret < 0) {
+ av_log(s->avctx, AV_LOG_WARNING,
+ "Error constructing the reference lists for the current slice.\n");
+ if (s->avctx->err_recognition & AV_EF_EXPLODE)
+ return ret;
+ }
+ }
+
+ 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)
+ return ctb_addr_ts;
+ break;
+ case NAL_EOS_NUT:
+ case NAL_EOB_NUT:
+ s->seq_decode = (s->seq_decode + 1) & 0xff;
+ s->max_ra = INT_MAX;
+ break;
+ case NAL_AUD:
+ case NAL_FD_NUT:
+ break;
+ default:
+ av_log(s->avctx, AV_LOG_INFO,
+ "Skipping NAL unit %d\n", s->nal_unit_type);
+ }
+
+ return 0;
+}
+
+/* FIXME: This is adapted from ff_h264_decode_nal, avoiding duplication
+ between these functions would be nice. */
+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) { \
+ /* startcode, so we must be past the end */ \
+ length = i; \
+ } \
+ break; \
+ }
+#if HAVE_FAST_UNALIGNED
+#define FIND_FIRST_ZERO \
+ if (i > 0 && !src[i]) \
+ i--; \
+ while (src[i]) \
+ i++
+#if HAVE_FAST_64BIT
+ for (i = 0; i + 1 < length; i += 9) {
+ if (!((~AV_RN64A(src + i) &
+ (AV_RN64A(src + i) - 0x0100010001000101ULL)) &
+ 0x8000800080008080ULL))
+ continue;
+ FIND_FIRST_ZERO;
+ STARTCODE_TEST;
+ i -= 7;
+ }
+#else
+ for (i = 0; i + 1 < length; i += 5) {
+ if (!((~AV_RN32A(src + i) &
+ (AV_RN32A(src + i) - 0x01000101U)) &
+ 0x80008080U))
+ continue;
+ FIND_FIRST_ZERO;
+ STARTCODE_TEST;
+ i -= 3;
+ }
+#endif
+#else
+ for (i = 0; i + 1 < length; i += 2) {
+ if (src[i])
+ continue;
+ if (i > 0 && src[i - 1] == 0)
+ i--;
+ STARTCODE_TEST;
+ }
+#endif
+
+ if (i >= length - 1) { // no escaped 0
+ nal->data = src;
+ nal->size = length;
+ return length;
+ }
+
+ av_fast_malloc(&nal->rbsp_buffer, &nal->rbsp_buffer_size,
+ length + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!nal->rbsp_buffer)
+ return AVERROR(ENOMEM);
+
+ dst = nal->rbsp_buffer;
+
+ memcpy(dst, src, i);
+ si = di = i;
+ while (si + 2 < length) {
+ // remove escapes (very rare 1:2^22)
+ if (src[si + 2] > 3) {
+ dst[di++] = src[si++];
+ dst[di++] = src[si++];
+ } else if (src[si] == 0 && src[si + 1] == 0) {
+ if (src[si + 2] == 3) { // escape
+ dst[di++] = 0;
+ 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;
+ }
+
+ dst[di++] = src[si++];
+ }
+ while (si < length)
+ dst[di++] = src[si++];
+nsc:
+
+ memset(dst + di, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+
+ nal->data = dst;
+ nal->size = di;
+ return si;
+}
+
+static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length)
+{
+ int i, consumed, ret = 0;
+
+ s->ref = NULL;
+ s->eos = 0;
+
+ /* split the input packet into NAL units, so we know the upper bound on the
+ * number of slices in the frame */
+ s->nb_nals = 0;
+ while (length >= 4) {
+ HEVCNAL *nal;
+ int extract_length = 0;
+
+ if (s->is_nalff) {
+ int i;
+ for (i = 0; i < s->nal_length_size; i++)
+ extract_length = (extract_length << 8) | buf[i];
+ buf += s->nal_length_size;
+ length -= s->nal_length_size;
+
+ if (extract_length > length) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid NAL unit size.\n");
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ } else {
+ /* 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;
+ }
+
+ 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));
+ if (!tmp) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ 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;
+ }
+ 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;
+
+
+ if (consumed < 0) {
+ ret = consumed;
+ goto fail;
+ }
+
+ ret = init_get_bits8(&s->HEVClc->gb, nal->data, nal->size);
+ if (ret < 0)
+ goto fail;
+ hls_nal_unit(s);
+
+ if (s->nal_unit_type == NAL_EOS_NUT ||
+ s->nal_unit_type == NAL_EOB_NUT)
+ s->eos = 1;
+
+ buf += consumed;
+ length -= consumed;
+ }
+
+ /* parse the NAL units */
+ for (i = 0; i < s->nb_nals; i++) {
+ 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);
+ if (s->avctx->err_recognition & AV_EF_EXPLODE)
+ goto fail;
+ }
+ }
+
+fail:
+ if (s->ref && s->threads_type == FF_THREAD_FRAME)
+ ff_thread_report_progress(&s->ref->tf, INT_MAX, 0);
+
+ return ret;
+}
+
+static void print_md5(void *log_ctx, int level, uint8_t md5[16])
+{
+ int i;
+ for (i = 0; i < 16; i++)
+ av_log(log_ctx, level, "%02"PRIx8, md5[i]);
+}
+
+static int verify_md5(HEVCContext *s, AVFrame *frame)
+{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
+ int pixel_shift;
+ int i, j;
+
+ if (!desc)
+ return AVERROR(EINVAL);
+
+ pixel_shift = desc->comp[0].depth_minus1 > 7;
+
+ av_log(s->avctx, AV_LOG_DEBUG, "Verifying checksum for frame with POC %d: ",
+ s->poc);
+
+ /* the checksums are LE, so we have to byteswap for >8bpp formats
+ * on BE arches */
+#if HAVE_BIGENDIAN
+ if (pixel_shift && !s->checksum_buf) {
+ av_fast_malloc(&s->checksum_buf, &s->checksum_buf_size,
+ FFMAX3(frame->linesize[0], frame->linesize[1],
+ frame->linesize[2]));
+ if (!s->checksum_buf)
+ return AVERROR(ENOMEM);
+ }
+#endif
+
+ for (i = 0; frame->data[i]; i++) {
+ int width = s->avctx->coded_width;
+ int height = s->avctx->coded_height;
+ int w = (i == 1 || i == 2) ? (width >> desc->log2_chroma_w) : width;
+ int h = (i == 1 || i == 2) ? (height >> desc->log2_chroma_h) : height;
+ uint8_t md5[16];
+
+ av_md5_init(s->md5_ctx);
+ for (j = 0; j < h; j++) {
+ const uint8_t *src = frame->data[i] + j * frame->linesize[i];
+#if HAVE_BIGENDIAN
+ if (pixel_shift) {
+ s->dsp.bswap16_buf((uint16_t*)s->checksum_buf,
+ (const uint16_t*)src, w);
+ src = s->checksum_buf;
+ }
+#endif
+ av_md5_update(s->md5_ctx, src, w << pixel_shift);
+ }
+ av_md5_final(s->md5_ctx, md5);
+
+ if (!memcmp(md5, s->md5[i], 16)) {
+ av_log (s->avctx, AV_LOG_DEBUG, "plane %d - correct ", i);
+ print_md5(s->avctx, AV_LOG_DEBUG, md5);
+ av_log (s->avctx, AV_LOG_DEBUG, "; ");
+ } else {
+ av_log (s->avctx, AV_LOG_ERROR, "mismatching checksum of plane %d - ", i);
+ print_md5(s->avctx, AV_LOG_ERROR, md5);
+ av_log (s->avctx, AV_LOG_ERROR, " != ");
+ print_md5(s->avctx, AV_LOG_ERROR, s->md5[i]);
+ av_log (s->avctx, AV_LOG_ERROR, "\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ av_log(s->avctx, AV_LOG_DEBUG, "\n");
+
+ return 0;
+}
+
+static int hevc_decode_frame(AVCodecContext *avctx, void *data, int *got_output,
+ AVPacket *avpkt)
+{
+ int ret;
+ HEVCContext *s = avctx->priv_data;
+
+ if (!avpkt->size) {
+ ret = ff_hevc_output_frame(s, data, 1);
+ if (ret < 0)
+ return ret;
+
+ *got_output = ret;
+ return 0;
+ }
+
+ s->ref = NULL;
+ ret = decode_nal_units(s, avpkt->data, avpkt->size);
+ if (ret < 0)
+ return ret;
+
+ /* verify the SEI checksum */
+ if (avctx->err_recognition & AV_EF_CRCCHECK && s->is_decoded &&
+ avctx->err_recognition & AV_EF_EXPLODE &&
+ s->is_md5) {
+ ret = verify_md5(s, s->ref->frame);
+ if (ret < 0) {
+ ff_hevc_unref_frame(s, s->ref, ~0);
+ return ret;
+ }
+ }
+ s->is_md5 = 0;
+
+ if (s->is_decoded) {
+ av_log(avctx, AV_LOG_DEBUG, "Decoded frame with POC %d.\n", s->poc);
+ s->is_decoded = 0;
+ }
+
+ if (s->output_frame->buf[0]) {
+ av_frame_move_ref(data, s->output_frame);
+ *got_output = 1;
+ }
+
+ return avpkt->size;
+}
+
+static int hevc_ref_frame(HEVCContext *s, HEVCFrame *dst, HEVCFrame *src)
+{
+ int ret;
+
+ ret = ff_thread_ref_frame(&dst->tf, &src->tf);
+ if (ret < 0)
+ return ret;
+
+ dst->tab_mvf_buf = av_buffer_ref(src->tab_mvf_buf);
+ if (!dst->tab_mvf_buf)
+ goto fail;
+ dst->tab_mvf = src->tab_mvf;
+
+ dst->rpl_tab_buf = av_buffer_ref(src->rpl_tab_buf);
+ if (!dst->rpl_tab_buf)
+ goto fail;
+ dst->rpl_tab = src->rpl_tab;
+
+ dst->rpl_buf = av_buffer_ref(src->rpl_buf);
+ if (!dst->rpl_buf)
+ goto fail;
+
+ dst->poc = src->poc;
+ dst->ctb_count = src->ctb_count;
+ dst->window = src->window;
+ dst->flags = src->flags;
+ dst->sequence = src->sequence;
+
+ return 0;
+fail:
+ ff_hevc_unref_frame(s, dst, ~0);
+ return AVERROR(ENOMEM);
+}
+
+static av_cold int hevc_decode_free(AVCodecContext *avctx)
+{
+ HEVCContext *s = avctx->priv_data;
+ HEVCLocalContext *lc = s->HEVClc;
+ int i;
+
+ pic_arrays_free(s);
+
+ av_freep(&lc->edge_emu_buffer);
+ 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);
+
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
+ ff_hevc_unref_frame(s, &s->DPB[i], ~0);
+ av_frame_free(&s->DPB[i].frame);
+ }
+
+ for (i = 0; i < FF_ARRAY_ELEMS(s->vps_list); i++)
+ av_freep(&s->vps_list[i]);
+ for (i = 0; i < FF_ARRAY_ELEMS(s->sps_list); i++)
+ 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]);
+
+ 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++) {
+ lc = s->HEVClcList[i];
+ if (lc) {
+ av_freep(&lc->edge_emu_buffer);
+
+ av_freep(&s->HEVClcList[i]);
+ av_freep(&s->sList[i]);
+ }
+ }
+ av_freep(&s->HEVClcList[0]);
+
+ for (i = 0; i < s->nals_allocated; i++)
+ av_freep(&s->nals[i].rbsp_buffer);
+ av_freep(&s->nals);
+ s->nals_allocated = 0;
+
+ return 0;
+}
+
+static av_cold int hevc_init_context(AVCodecContext *avctx)
+{
+ HEVCContext *s = avctx->priv_data;
+ int i;
+
+ s->avctx = avctx;
+
+ s->HEVClc = av_mallocz(sizeof(HEVCLocalContext));
+ 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;
+
+ s->output_frame = av_frame_alloc();
+ if (!s->output_frame)
+ goto fail;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
+ s->DPB[i].frame = av_frame_alloc();
+ if (!s->DPB[i].frame)
+ goto fail;
+ s->DPB[i].tf.f = s->DPB[i].frame;
+ }
+
+ s->max_ra = INT_MAX;
+
+ s->md5_ctx = av_md5_alloc();
+ if (!s->md5_ctx)
+ goto fail;
+
+ ff_dsputil_init(&s->dsp, avctx);
+
+ s->context_initialized = 1;
+
+ return 0;
+fail:
+ hevc_decode_free(avctx);
+ return AVERROR(ENOMEM);
+}
+
+static int hevc_update_thread_context(AVCodecContext *dst,
+ const AVCodecContext *src)
+{
+ HEVCContext *s = dst->priv_data;
+ HEVCContext *s0 = src->priv_data;
+ int i, ret;
+
+ if (!s->context_initialized) {
+ ret = hevc_init_context(dst);
+ if (ret < 0)
+ return ret;
+ }
+
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
+ ff_hevc_unref_frame(s, &s->DPB[i], ~0);
+ if (s0->DPB[i].frame->buf[0]) {
+ ret = hevc_ref_frame(s, &s->DPB[i], &s0->DPB[i]);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ for (i = 0; i < FF_ARRAY_ELEMS(s->sps_list); i++) {
+ av_buffer_unref(&s->sps_list[i]);
+ if (s0->sps_list[i]) {
+ s->sps_list[i] = av_buffer_ref(s0->sps_list[i]);
+ if (!s->sps_list[i])
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ for (i = 0; i < FF_ARRAY_ELEMS(s->pps_list); i++) {
+ av_buffer_unref(&s->pps_list[i]);
+ if (s0->pps_list[i]) {
+ s->pps_list[i] = av_buffer_ref(s0->pps_list[i]);
+ if (!s->pps_list[i])
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ if (s->sps != s0->sps)
+ ret = set_sps(s, s0->sps);
+
+ s->seq_decode = s0->seq_decode;
+ s->seq_output = s0->seq_output;
+ s->pocTid0 = s0->pocTid0;
+ s->max_ra = s0->max_ra;
+
+ 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;
+ }
+
+ return 0;
+}
+
+static int hevc_decode_extradata(HEVCContext *s)
+{
+ AVCodecContext *avctx = s->avctx;
+ GetByteContext gb;
+ int ret;
+
+ bytestream2_init(&gb, avctx->extradata, avctx->extradata_size);
+
+ if (avctx->extradata_size > 3 &&
+ (avctx->extradata[0] || avctx->extradata[1] ||
+ avctx->extradata[2] > 1)) {
+ /* It seems the extradata is encoded as hvcC format.
+ * Temporarily, we support configurationVersion==0 until 14496-15 3rd finalized.
+ * When finalized, configurationVersion will be 1 and we can recognize hvcC by
+ * checking if avctx->extradata[0]==1 or not. */
+ int i, j, num_arrays;
+ int nal_len_size;
+
+ s->is_nalff = 1;
+
+ bytestream2_skip(&gb, 21);
+ nal_len_size = (bytestream2_get_byte(&gb) & 3) + 1;
+ num_arrays = bytestream2_get_byte(&gb);
+
+ /* nal units in the hvcC always have length coded with 2 bytes,
+ * so put a fake nal_length_size = 2 while parsing them */
+ s->nal_length_size = 2;
+
+ /* Decode nal units from hvcC. */
+ for (i = 0; i < num_arrays; i++) {
+ int type = bytestream2_get_byte(&gb) & 0x3f;
+ int cnt = bytestream2_get_be16(&gb);
+
+ for (j = 0; j < cnt; j++) {
+ // +2 for the nal size field
+ int nalsize = bytestream2_peek_be16(&gb) + 2;
+ if (bytestream2_get_bytes_left(&gb) < nalsize) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Invalid NAL unit size in extradata.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ret = decode_nal_units(s, gb.buffer, nalsize);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Decoding nal unit %d %d from hvcC failed\n", type, i);
+ return ret;
+ }
+ bytestream2_skip(&gb, nalsize);
+ }
+ }
+
+ /* Now store right nal length size, that will be used to parse all other nals */
+ s->nal_length_size = nal_len_size;
+ } else {
+ s->is_nalff = 0;
+ ret = decode_nal_units(s, avctx->extradata, avctx->extradata_size);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static av_cold int hevc_decode_init(AVCodecContext *avctx)
+{
+ HEVCContext *s = avctx->priv_data;
+ int ret;
+
+ ff_init_cabac_states();
+
+ avctx->internal->allocate_progress = 1;
+
+ ret = hevc_init_context(avctx);
+ if (ret < 0)
+ return ret;
+
+ s->enable_parallel_tiles = 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) {
+ hevc_decode_free(avctx);
+ return ret;
+ }
+ }
+
+ 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;
+}
+
+static av_cold int hevc_init_thread_copy(AVCodecContext *avctx)
+{
+ HEVCContext *s = avctx->priv_data;
+ int ret;
+
+ memset(s, 0, sizeof(*s));
+
+ ret = hevc_init_context(avctx);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void hevc_decode_flush(AVCodecContext *avctx)
+{
+ HEVCContext *s = avctx->priv_data;
+ ff_hevc_flush_dpb(s);
+ s->max_ra = INT_MAX;
+}
+
+#define OFFSET(x) offsetof(HEVCContext, x)
+#define PAR (AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
+static const AVOption options[] = {
+ { "strict-displaywin", "stricly apply default display window size", OFFSET(strict_def_disp_win),
+ AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, PAR },
+ { NULL },
+};
+
+static const AVClass hevc_decoder_class = {
+ .class_name = "HEVC decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_hevc_decoder = {
+ .name = "hevc",
+ .long_name = NULL_IF_CONFIG_SMALL("HEVC (High Efficiency Video Coding)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_HEVC,
+ .priv_data_size = sizeof(HEVCContext),
+ .priv_class = &hevc_decoder_class,
+ .init = hevc_decode_init,
+ .close = hevc_decode_free,
+ .decode = hevc_decode_frame,
+ .flush = hevc_decode_flush,
+ .update_thread_context = hevc_update_thread_context,
+ .init_thread_copy = hevc_init_thread_copy,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY | CODEC_CAP_SLICE_THREADS | CODEC_CAP_FRAME_THREADS,
+};
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
new file mode 100644
index 0000000..4b45323
--- a/dev/null
+++ b/libavcodec/hevc.h
@@ -0,0 +1,986 @@
+/*
+ * 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_HEVC_H
+#define AVCODEC_HEVC_H
+
+#include "libavutil/buffer.h"
+#include "libavutil/md5.h"
+
+#include "avcodec.h"
+#include "cabac.h"
+#include "dsputil.h"
+#include "get_bits.h"
+#include "hevcpred.h"
+#include "hevcdsp.h"
+#include "internal.h"
+#include "thread.h"
+#include "videodsp.h"
+
+#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
+ */
+#define MAX_SUB_LAYERS 7
+#define MAX_VPS_COUNT 16
+#define MAX_SPS_COUNT 32
+#define MAX_PPS_COUNT 256
+#define MAX_SHORT_TERM_RPS_COUNT 64
+#define MAX_CU_SIZE 128
+
+//TODO: check if this is really the maximum
+#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 MRG_MAX_NUM_CANDS 5
+
+#define L0 0
+#define L1 1
+
+#define EPEL_EXTRA_BEFORE 1
+#define EPEL_EXTRA_AFTER 2
+#define EPEL_EXTRA 3
+
+/**
+ * Value of the luma sample at position (x, y) in the 2D array tab.
+ */
+#define SAMPLE(tab, x, y) ((tab)[(y) * s->sps->width + (x)])
+#define SAMPLE_CTB(tab, x, y) ((tab)[(y) * min_cb_width + (x)])
+#define SAMPLE_CBF(tab, x, y) ((tab)[((y) & ((1<<log2_trafo_size)-1)) * MAX_CU_SIZE + ((x) & ((1<<log2_trafo_size)-1))])
+
+#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
+ */
+enum NALUnitType {
+ NAL_TRAIL_N = 0,
+ NAL_TRAIL_R = 1,
+ NAL_TSA_N = 2,
+ NAL_TSA_R = 3,
+ NAL_STSA_N = 4,
+ NAL_STSA_R = 5,
+ NAL_RADL_N = 6,
+ NAL_RADL_R = 7,
+ NAL_RASL_N = 8,
+ NAL_RASL_R = 9,
+ NAL_BLA_W_LP = 16,
+ NAL_BLA_W_RADL = 17,
+ NAL_BLA_N_LP = 18,
+ NAL_IDR_W_RADL = 19,
+ NAL_IDR_N_LP = 20,
+ NAL_CRA_NUT = 21,
+ NAL_VPS = 32,
+ NAL_SPS = 33,
+ NAL_PPS = 34,
+ NAL_AUD = 35,
+ NAL_EOS_NUT = 36,
+ NAL_EOB_NUT = 37,
+ NAL_FD_NUT = 38,
+ NAL_SEI_PREFIX = 39,
+ NAL_SEI_SUFFIX = 40,
+};
+
+enum RPSType {
+ ST_CURR_BEF = 0,
+ ST_CURR_AFT,
+ ST_FOLL,
+ LT_CURR,
+ LT_FOLL,
+ NB_RPS_TYPE,
+};
+
+enum SliceType {
+ B_SLICE = 0,
+ P_SLICE = 1,
+ I_SLICE = 2,
+};
+
+enum SyntaxElement {
+ SAO_MERGE_FLAG = 0,
+ SAO_TYPE_IDX,
+ SAO_EO_CLASS,
+ SAO_BAND_POSITION,
+ SAO_OFFSET_ABS,
+ SAO_OFFSET_SIGN,
+ END_OF_SLICE_FLAG,
+ SPLIT_CODING_UNIT_FLAG,
+ CU_TRANSQUANT_BYPASS_FLAG,
+ SKIP_FLAG,
+ CU_QP_DELTA,
+ PRED_MODE_FLAG,
+ PART_MODE,
+ PCM_FLAG,
+ PREV_INTRA_LUMA_PRED_FLAG,
+ MPM_IDX,
+ REM_INTRA_LUMA_PRED_MODE,
+ INTRA_CHROMA_PRED_MODE,
+ MERGE_FLAG,
+ MERGE_IDX,
+ INTER_PRED_IDC,
+ REF_IDX_L0,
+ REF_IDX_L1,
+ ABS_MVD_GREATER0_FLAG,
+ ABS_MVD_GREATER1_FLAG,
+ ABS_MVD_MINUS2,
+ MVD_SIGN_FLAG,
+ MVP_LX_FLAG,
+ NO_RESIDUAL_DATA_FLAG,
+ SPLIT_TRANSFORM_FLAG,
+ CBF_LUMA,
+ CBF_CB_CR,
+ TRANSFORM_SKIP_FLAG,
+ LAST_SIGNIFICANT_COEFF_X_PREFIX,
+ LAST_SIGNIFICANT_COEFF_Y_PREFIX,
+ LAST_SIGNIFICANT_COEFF_X_SUFFIX,
+ LAST_SIGNIFICANT_COEFF_Y_SUFFIX,
+ SIGNIFICANT_COEFF_GROUP_FLAG,
+ SIGNIFICANT_COEFF_FLAG,
+ COEFF_ABS_LEVEL_GREATER1_FLAG,
+ COEFF_ABS_LEVEL_GREATER2_FLAG,
+ COEFF_ABS_LEVEL_REMAINING,
+ COEFF_SIGN_FLAG,
+};
+
+enum PartMode {
+ PART_2Nx2N = 0,
+ PART_2NxN = 1,
+ PART_Nx2N = 2,
+ PART_NxN = 3,
+ PART_2NxnU = 4,
+ PART_2NxnD = 5,
+ PART_nLx2N = 6,
+ PART_nRx2N = 7,
+};
+
+enum PredMode {
+ MODE_INTER = 0,
+ MODE_INTRA,
+ MODE_SKIP,
+};
+
+enum InterPredIdc {
+ PRED_L0 = 0,
+ PRED_L1,
+ PRED_BI,
+};
+
+enum IntraPredMode {
+ INTRA_PLANAR = 0,
+ INTRA_DC,
+ INTRA_ANGULAR_2,
+ INTRA_ANGULAR_3,
+ INTRA_ANGULAR_4,
+ INTRA_ANGULAR_5,
+ INTRA_ANGULAR_6,
+ INTRA_ANGULAR_7,
+ INTRA_ANGULAR_8,
+ INTRA_ANGULAR_9,
+ INTRA_ANGULAR_10,
+ INTRA_ANGULAR_11,
+ INTRA_ANGULAR_12,
+ INTRA_ANGULAR_13,
+ INTRA_ANGULAR_14,
+ INTRA_ANGULAR_15,
+ INTRA_ANGULAR_16,
+ INTRA_ANGULAR_17,
+ INTRA_ANGULAR_18,
+ INTRA_ANGULAR_19,
+ INTRA_ANGULAR_20,
+ INTRA_ANGULAR_21,
+ INTRA_ANGULAR_22,
+ INTRA_ANGULAR_23,
+ INTRA_ANGULAR_24,
+ INTRA_ANGULAR_25,
+ INTRA_ANGULAR_26,
+ INTRA_ANGULAR_27,
+ INTRA_ANGULAR_28,
+ INTRA_ANGULAR_29,
+ INTRA_ANGULAR_30,
+ INTRA_ANGULAR_31,
+ INTRA_ANGULAR_32,
+ INTRA_ANGULAR_33,
+ INTRA_ANGULAR_34,
+};
+
+enum SAOType {
+ SAO_NOT_APPLIED = 0,
+ SAO_BAND,
+ SAO_EDGE,
+};
+
+enum SAOEOClass {
+ SAO_EO_HORIZ = 0,
+ SAO_EO_VERT,
+ SAO_EO_135D,
+ SAO_EO_45D,
+};
+
+enum ScanType {
+ SCAN_DIAG = 0,
+ SCAN_HORIZ,
+ SCAN_VERT,
+};
+
+typedef struct ShortTermRPS {
+ int num_negative_pics;
+ int num_delta_pocs;
+ int32_t delta_poc[32];
+ uint8_t used[32];
+} ShortTermRPS;
+
+typedef struct LongTermRPS {
+ int poc[32];
+ uint8_t used[32];
+ uint8_t nb_refs;
+} LongTermRPS;
+
+typedef struct RefPicList {
+ struct HEVCFrame *ref[MAX_REFS];
+ int list[MAX_REFS];
+ int isLongTerm[MAX_REFS];
+ int nb_refs;
+} RefPicList;
+
+typedef struct RefPicListTab {
+ RefPicList refPicList[2];
+} RefPicListTab;
+
+typedef struct HEVCWindow {
+ int left_offset;
+ int right_offset;
+ int top_offset;
+ int bottom_offset;
+} HEVCWindow;
+
+typedef struct VUI {
+ AVRational sar;
+
+ int overscan_info_present_flag;
+ int overscan_appropriate_flag;
+
+ int video_signal_type_present_flag;
+ int video_format;
+ int video_full_range_flag;
+ int colour_description_present_flag;
+ uint8_t colour_primaries;
+ uint8_t transfer_characteristic;
+ uint8_t matrix_coeffs;
+
+ int chroma_loc_info_present_flag;
+ int chroma_sample_loc_type_top_field;
+ int chroma_sample_loc_type_bottom_field;
+ int neutra_chroma_indication_flag;
+
+ int field_seq_flag;
+ int frame_field_info_present_flag;
+
+ int default_display_window_flag;
+ HEVCWindow def_disp_win;
+
+ int vui_timing_info_present_flag;
+ uint32_t vui_num_units_in_tick;
+ uint32_t vui_time_scale;
+ int vui_poc_proportional_to_timing_flag;
+ int vui_num_ticks_poc_diff_one_minus1;
+ int vui_hrd_parameters_present_flag;
+
+ int bitstream_restriction_flag;
+ int tiles_fixed_structure_flag;
+ int motion_vectors_over_pic_boundaries_flag;
+ int restricted_ref_pic_lists_flag;
+ int min_spatial_segmentation_idc;
+ int max_bytes_per_pic_denom;
+ int max_bits_per_min_cu_denom;
+ int log2_max_mv_length_horizontal;
+ int log2_max_mv_length_vertical;
+} VUI;
+
+typedef struct PTL {
+ int general_profile_space;
+ uint8_t general_tier_flag;
+ int general_profile_idc;
+ int general_profile_compatibility_flag[32];
+ int general_level_idc;
+
+ uint8_t sub_layer_profile_present_flag[MAX_SUB_LAYERS];
+ uint8_t sub_layer_level_present_flag[MAX_SUB_LAYERS];
+
+ int sub_layer_profile_space[MAX_SUB_LAYERS];
+ uint8_t sub_layer_tier_flag[MAX_SUB_LAYERS];
+ int sub_layer_profile_idc[MAX_SUB_LAYERS];
+ uint8_t sub_layer_profile_compatibility_flags[MAX_SUB_LAYERS][32];
+ int sub_layer_level_idc[MAX_SUB_LAYERS];
+} PTL;
+
+typedef struct VPS {
+ uint8_t vps_temporal_id_nesting_flag;
+ int vps_max_layers;
+ int vps_max_sub_layers; ///< vps_max_temporal_layers_minus1 + 1
+
+ PTL ptl;
+ int vps_sub_layer_ordering_info_present_flag;
+ unsigned int vps_max_dec_pic_buffering[MAX_SUB_LAYERS];
+ unsigned int vps_num_reorder_pics[MAX_SUB_LAYERS];
+ unsigned int vps_max_latency_increase[MAX_SUB_LAYERS];
+ int vps_max_layer_id;
+ int vps_num_layer_sets; ///< vps_num_layer_sets_minus1 + 1
+ uint8_t vps_timing_info_present_flag;
+ uint32_t vps_num_units_in_tick;
+ uint32_t vps_time_scale;
+ uint8_t vps_poc_proportional_to_timing_flag;
+ int vps_num_ticks_poc_diff_one; ///< vps_num_ticks_poc_diff_one_minus1 + 1
+ int vps_num_hrd_parameters;
+} VPS;
+
+typedef struct ScalingList {
+ // This is a little wasteful, since sizeID 0 only needs 8 coeffs, and size ID 3 only has 2 arrays, not 6.
+ uint8_t sl[4][6][64];
+ uint8_t sl_dc[2][6];
+} ScalingList;
+
+typedef struct HEVCSPS {
+ int vps_id;
+ int chroma_format_idc;
+ uint8_t separate_colour_plane_flag;
+
+ ///< output (i.e. cropped) values
+ int output_width, output_height;
+ HEVCWindow output_window;
+
+ HEVCWindow pic_conf_win;
+
+ int bit_depth;
+ int pixel_shift;
+ enum AVPixelFormat pix_fmt;
+
+ unsigned int log2_max_poc_lsb;
+ int pcm_enabled_flag;
+
+ int max_sub_layers;
+ struct {
+ int max_dec_pic_buffering;
+ int num_reorder_pics;
+ int max_latency_increase;
+ } temporal_layer[MAX_SUB_LAYERS];
+
+ VUI vui;
+ PTL ptl;
+
+ uint8_t scaling_list_enable_flag;
+ ScalingList scaling_list;
+
+ unsigned int nb_st_rps;
+ ShortTermRPS st_rps[MAX_SHORT_TERM_RPS_COUNT];
+
+ uint8_t amp_enabled_flag;
+ uint8_t sao_enabled;
+
+ uint8_t long_term_ref_pics_present_flag;
+ uint16_t lt_ref_pic_poc_lsb_sps[32];
+ uint8_t used_by_curr_pic_lt_sps_flag[32];
+ uint8_t num_long_term_ref_pics_sps;
+
+ struct {
+ uint8_t bit_depth;
+ uint8_t bit_depth_chroma;
+ unsigned int log2_min_pcm_cb_size;
+ unsigned int log2_max_pcm_cb_size;
+ uint8_t loop_filter_disable_flag;
+ } pcm;
+ uint8_t sps_temporal_mvp_enabled_flag;
+ uint8_t sps_strong_intra_smoothing_enable_flag;
+
+ unsigned int log2_min_cb_size;
+ unsigned int log2_diff_max_min_coding_block_size;
+ unsigned int log2_min_tb_size;
+ unsigned int log2_max_trafo_size;
+ unsigned int log2_ctb_size;
+ unsigned int log2_min_pu_size;
+
+ int max_transform_hierarchy_depth_inter;
+ int max_transform_hierarchy_depth_intra;
+
+ ///< coded frame dimension in various units
+ int width;
+ int height;
+ int ctb_width;
+ int ctb_height;
+ int ctb_size;
+ int min_cb_width;
+ int min_cb_height;
+ int min_tb_width;
+ int min_tb_height;
+ int min_pu_width;
+ int min_pu_height;
+
+ int hshift[3];
+ int vshift[3];
+
+ int qp_bd_offset;
+} HEVCSPS;
+
+typedef struct HEVCPPS {
+ int sps_id; ///< seq_parameter_set_id
+
+ uint8_t sign_data_hiding_flag;
+
+ uint8_t cabac_init_present_flag;
+
+ int num_ref_idx_l0_default_active; ///< num_ref_idx_l0_default_active_minus1 + 1
+ int num_ref_idx_l1_default_active; ///< num_ref_idx_l1_default_active_minus1 + 1
+ int pic_init_qp_minus26;
+
+ uint8_t constrained_intra_pred_flag;
+ uint8_t transform_skip_enabled_flag;
+
+ uint8_t cu_qp_delta_enabled_flag;
+ int diff_cu_qp_delta_depth;
+
+ int cb_qp_offset;
+ int cr_qp_offset;
+ uint8_t pic_slice_level_chroma_qp_offsets_present_flag;
+ uint8_t weighted_pred_flag;
+ uint8_t weighted_bipred_flag;
+ uint8_t output_flag_present_flag;
+ uint8_t transquant_bypass_enable_flag;
+
+ uint8_t dependent_slice_segments_enabled_flag;
+ uint8_t tiles_enabled_flag;
+ uint8_t entropy_coding_sync_enabled_flag;
+
+ int num_tile_columns; ///< num_tile_columns_minus1 + 1
+ int num_tile_rows; ///< num_tile_rows_minus1 + 1
+ uint8_t uniform_spacing_flag;
+ uint8_t loop_filter_across_tiles_enabled_flag;
+
+ uint8_t seq_loop_filter_across_slices_enabled_flag;
+
+ uint8_t deblocking_filter_control_present_flag;
+ uint8_t deblocking_filter_override_enabled_flag;
+ uint8_t disable_dbf;
+ int beta_offset; ///< beta_offset_div2 * 2
+ int tc_offset; ///< tc_offset_div2 * 2
+
+ int pps_scaling_list_data_present_flag;
+ ScalingList scaling_list;
+
+ uint8_t lists_modification_present_flag;
+ 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 pps_extension_flag;
+ uint8_t pps_extension_data_flag;
+
+ // Inferred parameters
+ int *column_width; ///< ColumnWidth
+ int *row_height; ///< RowHeight
+ int *col_bd; ///< ColBd
+ int *row_bd; ///< RowBd
+ int *col_idxX;
+
+ int *ctb_addr_rs_to_ts; ///< CtbAddrRSToTS
+ int *ctb_addr_ts_to_rs; ///< CtbAddrTSToRS
+ int *tile_id; ///< TileId
+ int *tile_pos_rs; ///< TilePosRS
+ int *min_cb_addr_zs; ///< MinCbAddrZS
+ int *min_tb_addr_zs; ///< MinTbAddrZS
+} HEVCPPS;
+
+typedef struct SliceHeader {
+ int pps_id;
+
+ ///< address (in raster order) of the first block in the current slice segment
+ unsigned int slice_segment_addr;
+ ///< address (in raster order) of the first block in the current slice
+ unsigned int slice_addr;
+
+ enum SliceType slice_type;
+
+ int pic_order_cnt_lsb;
+
+ uint8_t first_slice_in_pic_flag;
+ uint8_t dependent_slice_segment_flag;
+ uint8_t pic_output_flag;
+ uint8_t colour_plane_id;
+
+ ///< RPS coded in the slice header itself is stored here
+ ShortTermRPS slice_rps;
+ const ShortTermRPS *short_term_rps;
+ LongTermRPS long_term_rps;
+ unsigned int list_entry_lx[2][32];
+
+ uint8_t rpl_modification_flag[2];
+ uint8_t no_output_of_prior_pics_flag;
+ uint8_t slice_temporal_mvp_enabled_flag;
+
+ unsigned int nb_refs[2];
+
+ uint8_t slice_sample_adaptive_offset_flag[3];
+ uint8_t mvd_l1_zero_flag;
+
+ uint8_t cabac_init_flag;
+ uint8_t disable_deblocking_filter_flag; ///< slice_header_disable_deblocking_filter_flag
+ uint8_t slice_loop_filter_across_slices_enabled_flag;
+ uint8_t collocated_list;
+
+ unsigned int collocated_ref_idx;
+
+ int slice_qp_delta;
+ int slice_cb_qp_offset;
+ int slice_cr_qp_offset;
+
+ int beta_offset; ///< beta_offset_div2 * 2
+ int tc_offset; ///< tc_offset_div2 * 2
+
+ 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;
+
+ uint8_t luma_log2_weight_denom;
+ int16_t chroma_log2_weight_denom;
+
+ int16_t luma_weight_l0[16];
+ int16_t chroma_weight_l0[16][2];
+ int16_t chroma_weight_l1[16][2];
+ int16_t luma_weight_l1[16];
+
+ int16_t luma_offset_l0[16];
+ int16_t chroma_offset_l0[16][2];
+
+ int16_t luma_offset_l1[16];
+ int16_t chroma_offset_l1[16][2];
+
+ int slice_ctb_addr_rs;
+} SliceHeader;
+
+typedef struct CodingTree {
+ int depth; ///< ctDepth
+} CodingTree;
+
+typedef struct CodingUnit {
+ int x;
+ int y;
+
+ enum PredMode pred_mode; ///< PredMode
+ enum PartMode part_mode; ///< PartMode
+
+ uint8_t rqt_root_cbf;
+
+ uint8_t pcm_flag;
+
+ // Inferred parameters
+ uint8_t intra_split_flag; ///< IntraSplitFlag
+ uint8_t max_trafo_depth; ///< MaxTrafoDepth
+ uint8_t cu_transquant_bypass_flag;
+} CodingUnit;
+
+typedef struct Mv {
+ int16_t x; ///< horizontal component of motion vector
+ int16_t y; ///< vertical component of motion vector
+} Mv;
+
+typedef struct MvField {
+ Mv mv[2];
+ int8_t ref_idx[2];
+ int8_t pred_flag[2];
+ uint8_t is_intra;
+} MvField;
+
+typedef struct NeighbourAvailable {
+ int cand_bottom_left;
+ int cand_left;
+ int cand_up;
+ int cand_up_left;
+ int cand_up_right;
+ int cand_up_right_sap;
+} NeighbourAvailable;
+
+typedef struct PredictionUnit {
+ int mpm_idx;
+ int rem_intra_luma_pred_mode;
+ uint8_t intra_pred_mode[4];
+ Mv mvd;
+ uint8_t merge_flag;
+ uint8_t intra_pred_mode_c;
+} PredictionUnit;
+
+typedef struct TransformTree {
+ uint8_t cbf_cb[MAX_TRANSFORM_DEPTH][MAX_CU_SIZE * MAX_CU_SIZE];
+ uint8_t cbf_cr[MAX_TRANSFORM_DEPTH][MAX_CU_SIZE * MAX_CU_SIZE];
+ uint8_t cbf_luma;
+
+ // Inferred parameters
+ uint8_t inter_split_flag;
+} TransformTree;
+
+typedef struct TransformUnit {
+ int cu_qp_delta;
+
+ // Inferred parameters;
+ int cur_intra_pred_mode;
+ uint8_t is_cu_qp_delta_coded;
+} TransformUnit;
+
+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
+
+ int eo_class[3]; ///< sao_eo_class
+
+ int offset_val[3][5]; ///<SaoOffsetVal
+
+ uint8_t type_idx[3]; ///< sao_type_idx
+} SAOParams;
+
+typedef struct DBParams {
+ int beta_offset;
+ int tc_offset;
+} DBParams;
+
+#define HEVC_FRAME_FLAG_OUTPUT (1 << 0)
+#define HEVC_FRAME_FLAG_SHORT_REF (1 << 1)
+#define HEVC_FRAME_FLAG_LONG_REF (1 << 2)
+
+typedef struct HEVCFrame {
+ AVFrame *frame;
+ ThreadFrame tf;
+ MvField *tab_mvf;
+ RefPicList *refPicList;
+ RefPicListTab **rpl_tab;
+ int ctb_count;
+ int poc;
+ struct HEVCFrame *collocated_ref;
+
+ HEVCWindow window;
+
+ AVBufferRef *tab_mvf_buf;
+ AVBufferRef *rpl_tab_buf;
+ AVBufferRef *rpl_buf;
+
+ /**
+ * A sequence counter, so that old frames are output first
+ * after a POC reset
+ */
+ uint16_t sequence;
+
+ /**
+ * A combination of HEVC_FRAME_FLAG_*
+ */
+ uint8_t flags;
+} HEVCFrame;
+
+typedef struct HEVCNAL {
+ uint8_t *rbsp_buffer;
+ int rbsp_buffer_size;
+
+ int size;
+ const uint8_t *data;
+} HEVCNAL;
+
+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 first_qp_group;
+
+ GetBitContext gb;
+ CABACContext cc;
+ TransformTree tt;
+
+ int8_t qp_y;
+ int8_t curr_qp_y;
+
+ 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;
+ uint8_t *edge_emu_buffer;
+ int edge_emu_buffer_size;
+ CodingTree ct;
+ CodingUnit cu;
+ PredictionUnit pu;
+ NeighbourAvailable na;
+
+ uint8_t slice_or_tiles_left_boundary;
+ uint8_t slice_or_tiles_up_boundary;
+} HEVCLocalContext;
+
+typedef struct HEVCContext {
+ const AVClass *c; // needed by private avoptions
+ AVCodecContext *avctx;
+
+ struct HEVCContext *sList[MAX_NB_THREADS];
+
+ HEVCLocalContext *HEVClcList[MAX_NB_THREADS];
+ HEVCLocalContext *HEVClc;
+
+ uint8_t threads_type;
+ uint8_t threads_number;
+
+ int width;
+ int height;
+
+ uint8_t *cabac_state;
+
+ /** 1 if the independent slice segment header was successfully parsed */
+ uint8_t slice_initialized;
+
+ AVFrame *frame;
+ AVFrame *sao_frame;
+ AVFrame *tmp_frame;
+ AVFrame *output_frame;
+ VPS *vps;
+ const HEVCSPS *sps;
+ HEVCPPS *pps;
+ VPS *vps_list[MAX_VPS_COUNT];
+ AVBufferRef *sps_list[MAX_SPS_COUNT];
+ AVBufferRef *pps_list[MAX_PPS_COUNT];
+
+ AVBufferPool *tab_mvf_pool;
+ AVBufferPool *rpl_tab_pool;
+
+ ///< candidate references for the current frame
+ RefPicList rps[5];
+
+ SliceHeader sh;
+ SAOParams *sao;
+ DBParams *deblock;
+ enum NALUnitType nal_unit_type;
+ int temporal_id; ///< temporal_id_plus1 - 1
+ HEVCFrame *ref;
+ HEVCFrame DPB[32];
+ int poc;
+ int pocTid0;
+ int slice_idx; ///< number of the slice being currently decoded
+ int eos; ///< current packet contains an EOS/EOB NAL
+ int max_ra;
+ int bs_width;
+ int bs_height;
+
+ int is_decoded;
+
+ HEVCPredContext hpc;
+ HEVCDSPContext hevcdsp;
+ VideoDSPContext vdsp;
+ DSPContext dsp;
+ int8_t *qp_y_tab;
+ uint8_t *split_cu_flag;
+ uint8_t *horizontal_bs;
+ uint8_t *vertical_bs;
+
+ int32_t *tab_slice_address;
+
+ // CU
+ uint8_t *skip_flag;
+ uint8_t *tab_ct_depth;
+ // PU
+ uint8_t *tab_ipm;
+
+
+ uint8_t *cbf_luma; // cbf_luma of colocated TU
+ uint8_t *is_pcm;
+
+ // CTB-level flags affecting loop filter operation
+ uint8_t *filter_slice_edges;
+
+ /** used on BE to byteswap the lines for checksumming */
+ uint8_t *checksum_buf;
+ int checksum_buf_size;
+
+ /**
+ * Sequence counters for decoded and output frames, so that old
+ * frames are output first after a POC reset
+ */
+ uint16_t seq_decode;
+ uint16_t seq_output;
+
+ 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;
+
+ uint8_t *data;
+
+ HEVCNAL *nals;
+ int nb_nals;
+ int nals_allocated;
+
+ // for checking the frame checksums
+ struct AVMD5 *md5_ctx;
+ uint8_t md5[3][16];
+ uint8_t is_md5;
+
+ int context_initialized;
+ int is_nalff; ///< this flag is != 0 if bitstream is encapsulated
+ ///< as a format defined in 14496-15
+ int strict_def_disp_win;
+
+ int nal_length_size; ///< Number of bytes used for nal length (1, 2 or 4)
+ int nuh_layer_id;
+
+} HEVCContext;
+
+int ff_hevc_decode_short_term_rps(HEVCContext *s, ShortTermRPS *rps,
+ const HEVCSPS *sps, int is_slice_header);
+int ff_hevc_decode_nal_vps(HEVCContext *s);
+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.
+ */
+void ff_hevc_clear_refs(HEVCContext *s);
+
+/**
+ * Drop all frames currently in DPB.
+ */
+void ff_hevc_flush_dpb(HEVCContext *s);
+
+/**
+ * Compute POC of the current frame and return it.
+ */
+int ff_hevc_compute_poc(HEVCContext *s, int poc_lsb);
+
+RefPicList* ff_hevc_get_ref_list(HEVCContext *s, HEVCFrame *frame, int x0, int y0);
+
+/**
+ * Construct the reference picture sets for the current frame.
+ */
+int ff_hevc_frame_rps(HEVCContext *s);
+
+/**
+ * Construct the reference picture list(s) for the current slice.
+ */
+int ff_hevc_slice_rpl(HEVCContext *s);
+
+void ff_hevc_save_states(HEVCContext *s, int ctb_addr_ts);
+void ff_hevc_cabac_init(HEVCContext *s, int ctb_addr_ts);
+int ff_hevc_sao_merge_flag_decode(HEVCContext *s);
+int ff_hevc_sao_type_idx_decode(HEVCContext *s);
+int ff_hevc_sao_band_position_decode(HEVCContext *s);
+int ff_hevc_sao_offset_abs_decode(HEVCContext *s);
+int ff_hevc_sao_offset_sign_decode(HEVCContext *s);
+int ff_hevc_sao_eo_class_decode(HEVCContext *s);
+int ff_hevc_end_of_slice_flag_decode(HEVCContext *s);
+int ff_hevc_cu_transquant_bypass_flag_decode(HEVCContext *s);
+int ff_hevc_skip_flag_decode(HEVCContext *s, int x0, int y0, int x_cb, int y_cb);
+int ff_hevc_pred_mode_decode(HEVCContext *s);
+int ff_hevc_split_coding_unit_flag_decode(HEVCContext *s, int ct_depth, int x0, int y0);
+int ff_hevc_part_mode_decode(HEVCContext *s, int log2_cb_size);
+int ff_hevc_pcm_flag_decode(HEVCContext *s);
+int ff_hevc_prev_intra_luma_pred_flag_decode(HEVCContext *s);
+int ff_hevc_mpm_idx_decode(HEVCContext *s);
+int ff_hevc_rem_intra_luma_pred_mode_decode(HEVCContext *s);
+int ff_hevc_intra_chroma_pred_mode_decode(HEVCContext *s);
+int ff_hevc_merge_idx_decode(HEVCContext *s);
+int ff_hevc_merge_flag_decode(HEVCContext *s);
+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_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);
+
+/**
+ * Get the number of candidate references for the current frame.
+ */
+int ff_hevc_frame_nb_refs(HEVCContext *s);
+
+int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, int poc);
+
+/**
+ * Find next frame in output order and put a reference to it in frame.
+ * @return 1 if a frame was output, 0 otherwise
+ */
+int ff_hevc_output_frame(HEVCContext *s, AVFrame *frame, int flush);
+
+void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags);
+
+void ff_hevc_set_neighbour_available(HEVCContext *s, int x0, int y0, int nPbW, int nPbH);
+void ff_hevc_luma_mv_merge_mode(HEVCContext *s, int x0, int y0, int nPbW, int nPbH, int log2_cb_size, int part_idx, int merge_idx, MvField *mv);
+void ff_hevc_luma_mv_mvp_mode(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, int log2_cb_size);
+void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0, int log2_trafo_size,
+ int slice_or_tiles_up_boundary, int slice_or_tiles_left_boundary);
+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);
+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_hls_mvd_coding(HEVCContext *s, int x0, int y0, int log2_cb_size);
+
+void ff_hevc_pps_free(HEVCPPS **ppps);
+
+extern const uint8_t ff_hevc_qpel_extra_before[4];
+extern const uint8_t ff_hevc_qpel_extra_after[4];
+extern const uint8_t ff_hevc_qpel_extra[4];
+
+extern const uint8_t ff_hevc_diag_scan4x4_x[16];
+extern const uint8_t ff_hevc_diag_scan4x4_y[16];
+extern const uint8_t ff_hevc_diag_scan8x8_x[64];
+extern const uint8_t ff_hevc_diag_scan8x8_y[64];
+
+#endif // AVCODEC_HEVC_H
diff --git a/libavcodec/hevc_cabac.c b/libavcodec/hevc_cabac.c
new file mode 100644
index 0000000..0fa7afa
--- a/dev/null
+++ b/libavcodec/hevc_cabac.c
@@ -0,0 +1,1424 @@
+/*
+ * HEVC CABAC decoding
+ *
+ * Copyright (C) 2012 - 2013 Guillaume Martres
+ * Copyright (C) 2012 - 2013 Gildas Cocherel
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/attributes.h"
+#include "libavutil/common.h"
+
+#include "cabac_functions.h"
+#include "hevc.h"
+
+#define CABAC_MAX_BIN 100
+
+/**
+ * number of bin by SyntaxElement.
+ */
+static const int8_t num_bins_in_se[] = {
+ 1, // sao_merge_flag
+ 1, // sao_type_idx
+ 0, // sao_eo_class
+ 0, // sao_band_position
+ 0, // sao_offset_abs
+ 0, // sao_offset_sign
+ 0, // end_of_slice_flag
+ 3, // split_coding_unit_flag
+ 1, // cu_transquant_bypass_flag
+ 3, // skip_flag
+ 3, // cu_qp_delta
+ 1, // pred_mode
+ 4, // part_mode
+ 0, // pcm_flag
+ 1, // prev_intra_luma_pred_mode
+ 0, // mpm_idx
+ 0, // rem_intra_luma_pred_mode
+ 2, // intra_chroma_pred_mode
+ 1, // merge_flag
+ 1, // merge_idx
+ 5, // inter_pred_idc
+ 2, // ref_idx_l0
+ 2, // ref_idx_l1
+ 2, // abs_mvd_greater0_flag
+ 2, // abs_mvd_greater1_flag
+ 0, // abs_mvd_minus2
+ 0, // mvd_sign_flag
+ 1, // mvp_lx_flag
+ 1, // no_residual_data_flag
+ 3, // split_transform_flag
+ 2, // cbf_luma
+ 4, // cbf_cb, cbf_cr
+ 2, // transform_skip_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
+ 24, // coeff_abs_level_greater1_flag
+ 6, // coeff_abs_level_greater2_flag
+ 0, // coeff_abs_level_remaining
+ 0, // coeff_sign_flag
+};
+
+/**
+ * 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,
+};
+
+#define CNU 154
+/**
+ * Indexed by init_type
+ */
+static const uint8_t init_values[3][HEVC_CONTEXTS] = {
+ {
+ // sao_merge_flag
+ 153,
+ // sao_type_idx
+ 200,
+ // split_coding_unit_flag
+ 139, 141, 157,
+ // cu_transquant_bypass_flag
+ 154,
+ // skip_flag
+ CNU, CNU, CNU,
+ // cu_qp_delta
+ 154, 154, 154,
+ // pred_mode
+ CNU,
+ // part_mode
+ 184, CNU, CNU, CNU,
+ // prev_intra_luma_pred_mode
+ 184,
+ // intra_chroma_pred_mode
+ 63, 139,
+ // merge_flag
+ CNU,
+ // merge_idx
+ CNU,
+ // inter_pred_idc
+ CNU, CNU, CNU, CNU, CNU,
+ // ref_idx_l0
+ CNU, CNU,
+ // ref_idx_l1
+ CNU, CNU,
+ // abs_mvd_greater1_flag
+ CNU, CNU,
+ // abs_mvd_greater1_flag
+ CNU, CNU,
+ // mvp_lx_flag
+ CNU,
+ // no_residual_data_flag
+ CNU,
+ // split_transform_flag
+ 153, 138, 138,
+ // cbf_luma
+ 111, 141,
+ // cbf_cb, cbf_cr
+ 94, 138, 182, 154,
+ // transform_skip_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,
+ // last_significant_coeff_y_prefix
+ 110, 110, 124, 125, 140, 153, 125, 127, 140, 109, 111, 143, 127, 111,
+ 79, 108, 123, 63,
+ // significant_coeff_group_flag
+ 91, 171, 134, 141,
+ // significant_coeff_flag
+ 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,
+ // 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,
+ },
+ {
+ // sao_merge_flag
+ 153,
+ // sao_type_idx
+ 185,
+ // split_coding_unit_flag
+ 107, 139, 126,
+ // cu_transquant_bypass_flag
+ 154,
+ // skip_flag
+ 197, 185, 201,
+ // cu_qp_delta
+ 154, 154, 154,
+ // pred_mode
+ 149,
+ // part_mode
+ 154, 139, 154, 154,
+ // prev_intra_luma_pred_mode
+ 154,
+ // intra_chroma_pred_mode
+ 152, 139,
+ // merge_flag
+ 110,
+ // merge_idx
+ 122,
+ // inter_pred_idc
+ 95, 79, 63, 31, 31,
+ // ref_idx_l0
+ 153, 153,
+ // ref_idx_l1
+ 153, 153,
+ // abs_mvd_greater1_flag
+ 140, 198,
+ // abs_mvd_greater1_flag
+ 140, 198,
+ // mvp_lx_flag
+ 168,
+ // no_residual_data_flag
+ 79,
+ // split_transform_flag
+ 124, 138, 94,
+ // cbf_luma
+ 153, 111,
+ // cbf_cb, cbf_cr
+ 149, 107, 167, 154,
+ // transform_skip_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,
+ // last_significant_coeff_y_prefix
+ 125, 110, 94, 110, 95, 79, 125, 111, 110, 78, 110, 111, 111, 95,
+ 94, 108, 123, 108,
+ // significant_coeff_group_flag
+ 121, 140, 61, 154,
+ // significant_coeff_flag
+ 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,
+ // 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,
+ },
+ {
+ // sao_merge_flag
+ 153,
+ // sao_type_idx
+ 160,
+ // split_coding_unit_flag
+ 107, 139, 126,
+ // cu_transquant_bypass_flag
+ 154,
+ // skip_flag
+ 197, 185, 201,
+ // cu_qp_delta
+ 154, 154, 154,
+ // pred_mode
+ 134,
+ // part_mode
+ 154, 139, 154, 154,
+ // prev_intra_luma_pred_mode
+ 183,
+ // intra_chroma_pred_mode
+ 152, 139,
+ // merge_flag
+ 154,
+ // merge_idx
+ 137,
+ // inter_pred_idc
+ 95, 79, 63, 31, 31,
+ // ref_idx_l0
+ 153, 153,
+ // ref_idx_l1
+ 153, 153,
+ // abs_mvd_greater1_flag
+ 169, 198,
+ // abs_mvd_greater1_flag
+ 169, 198,
+ // mvp_lx_flag
+ 168,
+ // no_residual_data_flag
+ 79,
+ // split_transform_flag
+ 224, 167, 122,
+ // cbf_luma
+ 153, 111,
+ // cbf_cb, cbf_cr
+ 149, 92, 167, 154,
+ // transform_skip_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,
+ // last_significant_coeff_y_prefix
+ 125, 110, 124, 110, 95, 94, 125, 111, 111, 79, 125, 126, 111, 111,
+ 79, 108, 123, 93,
+ // significant_coeff_group_flag
+ 121, 140, 61, 154,
+ // significant_coeff_flag
+ 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,
+ // 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,
+ },
+};
+
+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_scan4x1_x[4] = {
+ 0, 1, 2, 3,
+};
+
+static const uint8_t diag_scan1x4_y[4] = {
+ 0, 1, 2, 3,
+};
+
+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, },
+};
+
+static const uint8_t diag_scan8x2_x[16] = {
+ 0, 0, 1, 1,
+ 2, 2, 3, 3,
+ 4, 4, 5, 5,
+ 6, 6, 7, 7,
+};
+
+static const uint8_t diag_scan8x2_y[16] = {
+ 0, 1, 0, 1,
+ 0, 1, 0, 1,
+ 0, 1, 0, 1,
+ 0, 1, 0, 1,
+};
+
+static const uint8_t diag_scan8x2_inv[2][8] = {
+ { 0, 2, 4, 6, 8, 10, 12, 14, },
+ { 1, 3, 5, 7, 9, 11, 13, 15, },
+};
+
+static const uint8_t diag_scan2x8_x[16] = {
+ 0, 0, 1, 0,
+ 1, 0, 1, 0,
+ 1, 0, 1, 0,
+ 1, 0, 1, 1,
+};
+
+static const uint8_t diag_scan2x8_y[16] = {
+ 0, 1, 0, 2,
+ 1, 3, 2, 4,
+ 3, 5, 4, 6,
+ 5, 7, 6, 7,
+};
+
+static const uint8_t diag_scan2x8_inv[8][2] = {
+ { 0, 2, },
+ { 1, 4, },
+ { 3, 6, },
+ { 5, 8, },
+ { 7, 10, },
+ { 9, 12, },
+ { 11, 14, },
+ { 13, 15, },
+};
+
+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)
+{
+ if (s->pps->entropy_coding_sync_enabled_flag &&
+ ((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);
+ }
+}
+
+static void load_states(HEVCContext *s)
+{
+ memcpy(s->HEVClc->cabac_state, s->cabac_state, HEVC_CONTEXTS);
+}
+
+static void cabac_reinit(HEVCLocalContext *lc)
+{
+ skip_bytes(&lc->cc, 0);
+}
+
+static void cabac_init_decoder(HEVCContext *s)
+{
+ GetBitContext *gb = &s->HEVClc->gb;
+ skip_bits(gb, 1);
+ align_get_bits(gb);
+ ff_init_cabac_decoder(&s->HEVClc->cc,
+ gb->buffer + get_bits_count(gb) / 8,
+ (get_bits_left(gb) + 7) / 8);
+}
+
+static void cabac_init_state(HEVCContext *s)
+{
+ int init_type = 2 - s->sh.slice_type;
+ int i;
+
+ if (s->sh.cabac_init_flag && s->sh.slice_type != I_SLICE)
+ init_type ^= 3;
+
+ for (i = 0; i < HEVC_CONTEXTS; i++) {
+ 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;
+
+ pre ^= pre >> 31;
+ if (pre > 124)
+ pre = 124 + (pre & 1);
+ s->HEVClc->cabac_state[i] = pre;
+ }
+}
+
+void ff_hevc_cabac_init(HEVCContext *s, int ctb_addr_ts)
+{
+ if (ctb_addr_ts == s->pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs]) {
+ cabac_init_decoder(s);
+ if ((s->sh.dependent_slice_segment_flag == 0) ||
+ (s->pps->tiles_enabled_flag &&
+ (s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[ctb_addr_ts - 1])))
+ cabac_init_state(s);
+
+ if (!s->sh.first_slice_in_pic_flag && s->pps->entropy_coding_sync_enabled_flag) {
+ if ((ctb_addr_ts % s->sps->ctb_width) == 0) {
+ if (s->sps->ctb_width == 1)
+ cabac_init_state(s);
+ else if (s->sh.dependent_slice_segment_flag == 1)
+ load_states(s);
+ }
+ }
+ } else {
+ if (s->pps->tiles_enabled_flag &&
+ (s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[ctb_addr_ts - 1])) {
+ 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);
+ if (s->threads_number == 1)
+ cabac_reinit(s->HEVClc);
+ else
+ cabac_init_decoder(s);
+
+ if (s->sps->ctb_width == 1)
+ cabac_init_state(s);
+ else
+ load_states(s);
+ }
+ }
+ }
+}
+
+#define GET_CABAC(ctx) get_cabac(&s->HEVClc->cc, &s->HEVClc->cabac_state[ctx])
+
+int ff_hevc_sao_merge_flag_decode(HEVCContext *s)
+{
+ return GET_CABAC(elem_offset[SAO_MERGE_FLAG]);
+}
+
+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))
+ return SAO_BAND;
+ return SAO_EDGE;
+}
+
+int ff_hevc_sao_band_position_decode(HEVCContext *s)
+{
+ int i;
+ int value = get_cabac_bypass(&s->HEVClc->cc);
+
+ for (i = 0; i < 4; i++)
+ value = (value << 1) | get_cabac_bypass(&s->HEVClc->cc);
+ return value;
+}
+
+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))
+ i++;
+ return i;
+}
+
+int ff_hevc_sao_offset_sign_decode(HEVCContext *s)
+{
+ 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);
+ return ret;
+}
+
+int ff_hevc_end_of_slice_flag_decode(HEVCContext *s)
+{
+ return get_cabac_terminate(&s->HEVClc->cc);
+}
+
+int ff_hevc_cu_transquant_bypass_flag_decode(HEVCContext *s)
+{
+ return GET_CABAC(elem_offset[CU_TRANSQUANT_BYPASS_FLAG]);
+}
+
+int ff_hevc_skip_flag_decode(HEVCContext *s, int x0, int y0, int x_cb, int y_cb)
+{
+ int min_cb_width = s->sps->min_cb_width;
+ int inc = 0;
+ int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
+ int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
+
+ 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)
+ inc += !!SAMPLE_CTB(s->skip_flag, x_cb, y_cb-1);
+
+ return GET_CABAC(elem_offset[SKIP_FLAG] + inc);
+}
+
+int ff_hevc_cu_qp_delta_abs(HEVCContext *s)
+{
+ int prefix_val = 0;
+ int suffix_val = 0;
+ int inc = 0;
+
+ while (prefix_val < 5 && GET_CABAC(elem_offset[CU_QP_DELTA] + inc)) {
+ prefix_val++;
+ inc = 1;
+ }
+ if (prefix_val >= 5) {
+ int k = 0;
+ while (k < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc->cc)) {
+ suffix_val += 1 << k;
+ k++;
+ }
+ if (k == CABAC_MAX_BIN)
+ av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", k);
+
+ while (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);
+}
+
+int ff_hevc_pred_mode_decode(HEVCContext *s)
+{
+ return GET_CABAC(elem_offset[PRED_MODE_FLAG]);
+}
+
+int ff_hevc_split_coding_unit_flag_decode(HEVCContext *s, int ct_depth, int x0, int y0)
+{
+ int inc = 0, depth_left = 0, depth_top = 0;
+ int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
+ int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
+ int 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)
+ depth_left = s->tab_ct_depth[(y_cb)*s->sps->min_cb_width + x_cb-1];
+ 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);
+ inc += (depth_top > ct_depth);
+ return GET_CABAC(elem_offset[SPLIT_CODING_UNIT_FLAG] + inc);
+}
+
+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
+ return PART_NxN;
+ if (GET_CABAC(elem_offset[PART_MODE] + 1)) // 01
+ return PART_2NxN;
+ if (log2_cb_size == 3) // 00
+ return PART_Nx2N;
+ if (GET_CABAC(elem_offset[PART_MODE] + 2)) // 001
+ return PART_Nx2N;
+ return PART_NxN; // 000
+ }
+
+ if (!s->sps->amp_enabled_flag) {
+ if (GET_CABAC(elem_offset[PART_MODE] + 1)) // 01
+ return PART_2NxN;
+ return PART_Nx2N;
+ }
+
+ 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
+ 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
+ return PART_nRx2N;
+ return PART_nLx2N; // 0000
+}
+
+int ff_hevc_pcm_flag_decode(HEVCContext *s)
+{
+ return get_cabac_terminate(&s->HEVClc->cc);
+}
+
+int ff_hevc_prev_intra_luma_pred_flag_decode(HEVCContext *s)
+{
+ return GET_CABAC(elem_offset[PREV_INTRA_LUMA_PRED_FLAG]);
+}
+
+int ff_hevc_mpm_idx_decode(HEVCContext *s)
+{
+ int i = 0;
+ while (i < 2 && get_cabac_bypass(&s->HEVClc->cc))
+ i++;
+ return i;
+}
+
+int ff_hevc_rem_intra_luma_pred_mode_decode(HEVCContext *s)
+{
+ int i;
+ int value = get_cabac_bypass(&s->HEVClc->cc);
+
+ for (i = 0; i < 4; i++)
+ value = (value << 1) | get_cabac_bypass(&s->HEVClc->cc);
+ return value;
+}
+
+int ff_hevc_intra_chroma_pred_mode_decode(HEVCContext *s)
+{
+ int ret;
+ 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);
+ return ret;
+}
+
+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))
+ i++;
+ }
+ return i;
+}
+
+int ff_hevc_merge_flag_decode(HEVCContext *s)
+{
+ return GET_CABAC(elem_offset[MERGE_FLAG]);
+}
+
+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))
+ return PRED_BI;
+
+ return GET_CABAC(elem_offset[INTER_PRED_IDC] + 4);
+}
+
+int ff_hevc_ref_idx_lx_decode(HEVCContext *s, int num_ref_idx_lx)
+{
+ int i = 0;
+ int max = num_ref_idx_lx - 1;
+ int max_ctx = FFMIN(max, 2);
+
+ 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))
+ i++;
+ }
+
+ return i;
+}
+
+int ff_hevc_mvp_lx_flag_decode(HEVCContext *s)
+{
+ return GET_CABAC(elem_offset[MVP_LX_FLAG]);
+}
+
+int ff_hevc_no_residual_syntax_flag_decode(HEVCContext *s)
+{
+ return GET_CABAC(elem_offset[NO_RESIDUAL_DATA_FLAG]);
+}
+
+static av_always_inline int abs_mvd_greater0_flag_decode(HEVCContext *s)
+{
+ return GET_CABAC(elem_offset[ABS_MVD_GREATER0_FLAG]);
+}
+
+static av_always_inline int abs_mvd_greater1_flag_decode(HEVCContext *s)
+{
+ return GET_CABAC(elem_offset[ABS_MVD_GREATER1_FLAG] + 1);
+}
+
+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)) {
+ 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);
+}
+
+static av_always_inline int mvd_sign_flag_decode(HEVCContext *s)
+{
+ return get_cabac_bypass_sign(&s->HEVClc->cc, -1);
+}
+
+int ff_hevc_split_transform_flag_decode(HEVCContext *s, int log2_trafo_size)
+{
+ return GET_CABAC(elem_offset[SPLIT_TRANSFORM_FLAG] + 5 - log2_trafo_size);
+}
+
+int ff_hevc_cbf_cb_cr_decode(HEVCContext *s, int trafo_depth)
+{
+ return GET_CABAC(elem_offset[CBF_CB_CR] + trafo_depth);
+}
+
+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)
+{
+ 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 av_always_inline int last_significant_coeff_x_prefix_decode(HEVCContext *s, int c_idx,
+ int log2_size)
+{
+ LAST_SIG_COEFF(LAST_SIGNIFICANT_COEFF_X_PREFIX)
+}
+
+static av_always_inline int last_significant_coeff_y_prefix_decode(HEVCContext *s, int c_idx,
+ int log2_size)
+{
+ LAST_SIG_COEFF(LAST_SIGNIFICANT_COEFF_Y_PREFIX)
+}
+
+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);
+
+ for (i = 1; i < length; i++)
+ value = (value << 1) | get_cabac_bypass(&s->HEVClc->cc);
+ return value;
+}
+
+static av_always_inline int significant_coeff_group_flag_decode(HEVCContext *s, int c_idx, int ctx_cg)
+{
+ int inc;
+
+ inc = FFMIN(ctx_cg, 1) + (c_idx>0 ? 2 : 0);
+
+ return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_GROUP_FLAG] + inc);
+}
+
+static av_always_inline int 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 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;
+ int 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;
+ }
+
+ return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_FLAG] + inc);
+}
+
+static av_always_inline int coeff_abs_level_greater1_flag_decode(HEVCContext *s, int c_idx, int inc)
+{
+
+ if (c_idx > 0)
+ inc += 16;
+
+ return GET_CABAC(elem_offset[COEFF_ABS_LEVEL_GREATER1_FLAG] + 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;
+
+ return GET_CABAC(elem_offset[COEFF_ABS_LEVEL_GREATER2_FLAG] + inc);
+}
+
+static av_always_inline int coeff_abs_level_remaining_decode(HEVCContext *s, int base_level, 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))
+ 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);
+ 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);
+ last_coeff_abs_level_remaining = (((1 << prefix_minus3) + 3 - 1)
+ << rc_rice_param) + suffix;
+ }
+ return last_coeff_abs_level_remaining;
+}
+
+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);
+ 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 = (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;
+ int 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->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 =
+ last_significant_coeff_x_prefix_decode(s, c_idx, log2_trafo_size);
+ last_significant_coeff_y =
+ last_significant_coeff_y_prefix_decode(s, c_idx, log2_trafo_size);
+
+ 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;
+
+ 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);
+
+ 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 (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] =
+ 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] += 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);
+ 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 = coeff_abs_level_remaining_decode(s, trans_coeff_level, c_rice_param);
+
+ trans_coeff_level += last_coeff_abs_level_remaining;
+ if (trans_coeff_level > (3 << 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))
+ 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) {
+ 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);
+ }
+}
+
+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
new file mode 100644
index 0000000..0a6d7c9
--- a/dev/null
+++ b/libavcodec/hevc_filter.c
@@ -0,0 +1,693 @@
+/*
+ * HEVC video Decoder
+ *
+ * Copyright (C) 2012 - 2013 Guillaume Martres
+ * Copyright (C) 2013 Seppo Tomperi
+ * Copyright (C) 2013 Wassim Hamidouche
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License 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/internal.h"
+
+#include "cabac_functions.h"
+#include "golomb.h"
+#include "hevc.h"
+#include "bit_depth_template.c"
+
+#define LUMA 0
+#define CB 1
+#define CR 2
+
+static const uint8_t tctable[54] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // QP 0...18
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, // QP 19...37
+ 5, 5, 6, 6, 7, 8, 9,10,11,13,14,16,18,20,22,24 // QP 38...53
+};
+
+static const uint8_t betatable[52] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, // QP 0...18
+ 9,10,11,12,13,14,15,16,17,18,20,22,24,26,28,30,32,34,36, // QP 19...37
+ 38,40,42,44,46,48,50,52,54,56,58,60,62,64 // QP 38...51
+};
+
+static int chroma_tc(HEVCContext *s, int qp_y, int c_idx, int tc_offset)
+{
+ static const int qp_c[] = { 29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37 };
+ int qp_i, offset;
+ int qp;
+ int idxt;
+
+ // slice qp offset is not used for deblocking
+ if (c_idx == 1)
+ offset = s->pps->cb_qp_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];
+
+ idxt = av_clip_c(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)
+{
+ 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) && (xQgBase & ctb_size_mask);
+ int availableB = (yBase & ctb_size_mask) && (yQgBase & ctb_size_mask);
+ int qPy_pred;
+ int qPy_a;
+ int qPy_b;
+
+ // qPy_pred
+ if (lc->first_qp_group) {
+ 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_a
+ if (availableA == 0)
+ qPy_a = qPy_pred;
+ else
+ qPy_a = s->qp_y_tab[(x_cb - 1) + y_cb * min_cb_width];
+
+ // qPy_b
+ if (availableB == 0)
+ qPy_b = qPy_pred;
+ else
+ qPy_b = s->qp_y_tab[x_cb + (y_cb - 1) * min_cb_width];
+
+ 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)
+{
+ int qp_y = get_qPy_pred(s, xC, yC, xBase, yBase, log2_cb_size);
+
+ if (s->HEVClc->tu.cu_qp_delta != 0) {
+ int off = s->sps->qp_bd_offset;
+ s->HEVClc->qp_y = ((qp_y + s->HEVClc->tu.cu_qp_delta + 52 + 2 * off) % (52 + off)) - off;
+ } else
+ s->HEVClc->qp_y = qp_y;
+}
+
+static int get_qPy(HEVCContext *s, int xC, int yC)
+{
+ int log2_min_cb_size = s->sps->log2_min_cb_size;
+ int x = xC >> log2_min_cb_size;
+ int y = yC >> log2_min_cb_size;
+ return s->qp_y_tab[x + y * s->sps->min_cb_width];
+}
+
+static void copy_CTB(uint8_t *dst, uint8_t *src, int width, int height, int stride)
+{
+ int i;
+
+ for(i=0; i< height; i++){
+ memcpy(dst, src, width);
+ dst += stride;
+ src += stride;
+ }
+}
+
+#define CTB(tab, x, y) ((tab)[(y) * s->sps->ctb_width + (x)])
+
+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 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];
+
+ // 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;
+ uint8_t up_tile_edge = 0;
+
+ sao[0] = &CTB(s->sao, x_ctb, y_ctb);
+ 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 (!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];
+ }
+ }
+ }
+
+ 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;
+ }
+ }
+ }
+}
+
+static int get_pcm(HEVCContext *s, int x, int y)
+{
+ int log2_min_pu_size = s->sps->log2_min_pu_size;
+ int x_pu = x >> log2_min_pu_size;
+ int y_pu = y >> log2_min_pu_size;
+
+ if (x < 0 || x_pu >= s->sps->min_pu_width ||
+ y < 0 || y_pu >= s->sps->min_pu_height)
+ return 2;
+ return s->is_pcm[y_pu * s->sps->min_pu_width + x_pu];
+}
+
+#define TC_CALC(qp, bs) tctable[av_clip((qp) + DEFAULT_INTRA_TC_OFFSET * ((bs) - 1) + ((tc_offset >> 1) << 1), 0, MAX_QP + DEFAULT_INTRA_TC_OFFSET)]
+
+static void deblocking_filter_CTB(HEVCContext *s, int x0, int y0)
+{
+ uint8_t *src;
+ int x, y;
+ int chroma;
+ int c_tc[2];
+ int beta[2];
+ int 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, 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 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;
+
+ if (x0) {
+ left_tc_offset = s->deblock[ctb-1].tc_offset;
+ left_beta_offset = s->deblock[ctb-1].beta_offset;
+ }
+
+ x_end = x0+ctb_size;
+ if (x_end > s->sps->width)
+ x_end = s->sps->width;
+ y_end = y0+ctb_size;
+ if (y_end > s->sps->height)
+ y_end = s->sps->height;
+
+ tc_offset = cur_tc_offset;
+ beta_offset = cur_beta_offset;
+
+ // vertical filtering luma
+ for (y = y0; y < y_end; y += 8) {
+ 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];
+ if (bs0 || bs1) {
+ 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) + get_qPy(s, x, y + 4) + 1) >> 1;
+
+ beta[0] = betatable[av_clip(qp0 + ((beta_offset >> 1) << 1), 0, MAX_QP)];
+ beta[1] = betatable[av_clip(qp1 + ((beta_offset >> 1) << 1), 0, MAX_QP)];
+ tc[0] = bs0 ? TC_CALC(qp0, bs0) : 0;
+ tc[1] = bs1 ? TC_CALC(qp1, bs1) : 0;
+ src = &s->frame->data[LUMA][y * s->frame->linesize[LUMA] + (x << 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);
+ no_q[0] = get_pcm(s, x, y);
+ no_q[1] = get_pcm(s, x, y + 4);
+ s->hevcdsp.hevc_v_loop_filter_luma_c(src, s->frame->linesize[LUMA], beta, tc, no_p, no_q);
+ } else
+ s->hevcdsp.hevc_v_loop_filter_luma(src, s->frame->linesize[LUMA], 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);
+ }
+ }
+ }
+ }
+
+ // 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];
+ if (bs0 || bs1) {
+ const int qp0 = (get_qPy(s, x, y - 1) + get_qPy(s, x, y) + 1) >> 1;
+ const int qp1 = (get_qPy(s, x + 4, y - 1) + get_qPy(s, x + 4, y) + 1) >> 1;
+
+ tc_offset = x >= x0 ? cur_tc_offset : left_tc_offset;
+ beta_offset = x >= x0 ? cur_beta_offset : left_beta_offset;
+
+ beta[0] = betatable[av_clip(qp0 + ((beta_offset >> 1) << 1), 0, MAX_QP)];
+ beta[1] = betatable[av_clip(qp1 + ((beta_offset >> 1) << 1), 0, MAX_QP)];
+ tc[0] = bs0 ? TC_CALC(qp0, bs0) : 0;
+ tc[1] = bs1 ? TC_CALC(qp1, bs1) : 0;
+ src = &s->frame->data[LUMA][y * s->frame->linesize[LUMA] + (x << s->sps->pixel_shift)];
+ if (pcmf) {
+ no_p[0] = get_pcm(s, x, y - 1);
+ no_p[1] = get_pcm(s, x + 4, y - 1);
+ no_q[0] = get_pcm(s, x, y);
+ no_q[1] = get_pcm(s, x + 4, y);
+ s->hevcdsp.hevc_h_loop_filter_luma_c(src, s->frame->linesize[LUMA], beta, tc, no_p, no_q);
+ } else
+ s->hevcdsp.hevc_h_loop_filter_luma(src, s->frame->linesize[LUMA], beta, tc, no_p, no_q);
+ }
+ }
+ }
+
+ // horizontal filtering chroma
+ for (chroma = 1; chroma <= 2; chroma++) {
+ for (y = y0 ? y0 : 16; y < y_end; y += 16) {
+ for (x = x0 - 8; x < x_end; x += 16) {
+ int bs0, bs1;
+ // to make sure no memory access over boundary when x = -8
+ // TODO: simplify with row based deblocking
+ if (x < 0) {
+ bs0 = 0;
+ bs1 = s->horizontal_bs[(x + 8 + y * s->bs_width) >> 2];
+ } else if (x >= x_end - 8) {
+ bs0 = s->horizontal_bs[(x + y * s->bs_width) >> 2];
+ bs1 = 0;
+ } else {
+ bs0 = s->horizontal_bs[(x + y * s->bs_width) >> 2];
+ bs1 = s->horizontal_bs[(x + 8 + y * s->bs_width) >> 2];
+ }
+
+ if ((bs0 == 2) || (bs1 == 2)) {
+ const int qp0 = (bs0 == 2) ? ((get_qPy(s, x, y - 1) + get_qPy(s, x, y) + 1) >> 1) : 0;
+ const int qp1 = (bs1 == 2) ? ((get_qPy(s, x + 8, y - 1) + get_qPy(s, x + 8, y) + 1) >> 1) : 0;
+
+ tc_offset = x >= x0 ? cur_tc_offset : left_tc_offset;
+ c_tc[0] = (bs0 == 2) ? chroma_tc(s, qp0, chroma, tc_offset) : 0;
+ c_tc[1] = (bs1 == 2) ? chroma_tc(s, qp1, chroma, cur_tc_offset) : 0;
+ src = &s->frame->data[chroma][(y / 2) * s->frame->linesize[chroma] + ((x / 2) << s->sps->pixel_shift)];
+ if (pcmf) {
+ no_p[0] = get_pcm(s, x, y - 1);
+ no_p[1] = get_pcm(s, x + 8, y - 1);
+ no_q[0] = get_pcm(s, x, y);
+ no_q[1] = get_pcm(s, x + 8, y);
+ s->hevcdsp.hevc_h_loop_filter_chroma_c(src, s->frame->linesize[chroma], c_tc, no_p, no_q);
+ } else
+ s->hevcdsp.hevc_h_loop_filter_chroma(src, s->frame->linesize[chroma], c_tc, no_p, no_q);
+ }
+ }
+ }
+ }
+}
+
+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)
+{
+ 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 {
+ return 1;
+ }
+ } else { // 1 MV
+ Mv A, B;
+ int ref_A;
+ int 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]];
+ }
+
+ 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 (ref_A == ref_B) {
+ if (abs(A.x - B.x) >= 4 || abs(A.y - B.y) >= 4)
+ return 1;
+ else
+ return 0;
+ } else
+ return 1;
+ }
+ }
+
+ return 1;
+}
+
+void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0, int log2_trafo_size,
+ int slice_or_tiles_up_boundary, int slice_or_tiles_left_boundary)
+{
+ 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;
+
+ int i, j;
+ int bs;
+
+ if (y0 > 0 && (y0 & 7) == 0) {
+ 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];
+ RefPicList* top_refPicList = ff_hevc_get_ref_list(s, s->ref, x0 + i, y0 - 1);
+
+ bs = boundary_strength(s, curr, curr_cbf_luma, top, top_cbf_luma, top_refPicList, 1);
+ if (!s->sh.slice_loop_filter_across_slices_enabled_flag && (slice_or_tiles_up_boundary & 1) && (y0 % (1 << s->sps->log2_ctb_size)) == 0)
+ bs = 0;
+ else if (!s->pps->loop_filter_across_tiles_enabled_flag && (slice_or_tiles_up_boundary & 2) && (y0 % (1 << s->sps->log2_ctb_size)) == 0)
+ bs = 0;
+ if (y0 == 0 || s->sh.disable_deblocking_filter_flag == 1)
+ bs = 0;
+ 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)
+ 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;
+ 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];
+ RefPicList* top_refPicList = ff_hevc_get_ref_list(s, s->ref, x0 + i, y0 + j - 1);
+
+ bs = boundary_strength(s, curr, curr_cbf_luma, top, top_cbf_luma, top_refPicList, 0);
+ if (s->sh.disable_deblocking_filter_flag == 1)
+ bs = 0;
+ if (bs)
+ s->horizontal_bs[((x0 + i) + (y0 + j) * s->bs_width) >> 2] = bs;
+ }
+ }
+
+ // bs for vertical TU boundaries
+ if (x0 > 0 && (x0 & 7) == 0) {
+ 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];
+ RefPicList* left_refPicList = ff_hevc_get_ref_list(s, s->ref, x0 - 1, y0 + i);
+
+ bs = boundary_strength(s, curr, curr_cbf_luma, left, left_cbf_luma, left_refPicList, 1);
+ if (!s->sh.slice_loop_filter_across_slices_enabled_flag && (slice_or_tiles_left_boundary & 1) && (x0 % (1 << s->sps->log2_ctb_size)) == 0)
+ bs = 0;
+ else if (!s->pps->loop_filter_across_tiles_enabled_flag && (slice_or_tiles_left_boundary & 2) && (x0 % (1 << s->sps->log2_ctb_size)) == 0)
+ bs = 0;
+ if (x0 == 0 || s->sh.disable_deblocking_filter_flag == 1)
+ bs = 0;
+ if (bs)
+ s->vertical_bs[(x0 >> 3) + ((y0 + i) >> 2) * s->bs_width] = bs;
+ }
+ }
+
+ // bs for TU internal vertical PU boundaries
+ if (log2_trafo_size > log2_min_pu_size && !is_intra)
+ 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];
+ RefPicList* left_refPicList = ff_hevc_get_ref_list(s, s->ref, x0 + i - 1, y0 + j);
+
+ bs = boundary_strength(s, curr, curr_cbf_luma, left, left_cbf_luma, left_refPicList, 0);
+ if (s->sh.disable_deblocking_filter_flag == 1)
+ bs = 0;
+ if (bs)
+ s->vertical_bs[((x0 + i) >> 3) + ((y0 + j) >> 2) * s->bs_width] = bs;
+ }
+ }
+}
+#undef LUMA
+#undef CB
+#undef CR
+
+void ff_hevc_hls_filter(HEVCContext *s, int x, int y)
+{
+ deblocking_filter_CTB(s, x, y);
+ if (s->sps->sao_enabled)
+ sao_filter_CTB(s, x, y);
+}
+
+void ff_hevc_hls_filters(HEVCContext *s, int x_ctb, int y_ctb, int 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);
+ if (s->threads_type == FF_THREAD_FRAME )
+ 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);
+}
diff --git a/libavcodec/hevc_mvs.c b/libavcodec/hevc_mvs.c
new file mode 100644
index 0000000..d26de51
--- a/dev/null
+++ b/libavcodec/hevc_mvs.c
@@ -0,0 +1,814 @@
+/*
+ * HEVC video Decoder
+ *
+ * Copyright (C) 2012 - 2013 Guillaume Martres
+ * Copyright (C) 2013 Anand Meher Kotra
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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"
+
+static const uint8_t l0_l1_cand_idx[12][2] = {
+ { 0, 1, },
+ { 1, 0, },
+ { 0, 2, },
+ { 2, 0, },
+ { 1, 2, },
+ { 2, 1, },
+ { 0, 3, },
+ { 3, 0, },
+ { 1, 3, },
+ { 3, 1, },
+ { 2, 3, },
+ { 3, 2, },
+};
+
+void ff_hevc_set_neighbour_available(HEVCContext *s, int x0, int y0, int nPbW, int nPbH)
+{
+ HEVCLocalContext *lc = s->HEVClc;
+ int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
+ int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
+
+ lc->na.cand_up = (lc->ctb_up_flag || y0b);
+ lc->na.cand_left = (lc->ctb_left_flag || x0b);
+ lc->na.cand_up_left = (!x0b && !y0b) ? lc->ctb_up_left_flag : lc->na.cand_left && lc->na.cand_up;
+ lc->na.cand_up_right_sap =
+ ((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 )
+ && (x0 + nPbW) < lc->end_of_tiles_x;
+ lc->na.cand_bottom_left = ((y0 + nPbH) >= lc->end_of_tiles_y) ? 0 : lc->na.cand_left;
+}
+
+/*
+ * 6.4.1 Derivation process for z-scan order block availability
+ */
+static 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);
+}
+
+/*
+ * 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);
+}
+
+//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)
+{
+ uint8_t plevel = s->pps->log2_parallel_merge_level;
+
+ return xN >> plevel == xP >> plevel &&
+ yN >> plevel == yP >> plevel;
+}
+
+#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)
+{
+ if (A.pred_flag[0] && A.pred_flag[1] && B.pred_flag[0] && B.pred_flag[1])
+ return MATCH(ref_idx[0]) && MATCH(mv[0].x) && MATCH(mv[0].y) &&
+ MATCH(ref_idx[1]) && MATCH(mv[1].x) && MATCH(mv[1].y);
+
+ if (A.pred_flag[0] && !A.pred_flag[1] && B.pred_flag[0] && !B.pred_flag[1])
+ return MATCH(ref_idx[0]) && MATCH(mv[0].x) && MATCH(mv[0].y);
+
+ if (!A.pred_flag[0] && A.pred_flag[1] && !B.pred_flag[0] && B.pred_flag[1])
+ return MATCH(ref_idx[1]) && MATCH(mv[1].x) && MATCH(mv[1].y);
+
+ return 0;
+}
+
+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);
+ 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);
+}
+
+static int check_mvset(Mv *mvLXCol, Mv *mvCol,
+ int colPic, int poc,
+ RefPicList *refPicList, int X, int refIdxLx,
+ RefPicList *refPicList_col, int listCol, int refidxCol)
+{
+ int cur_lt = refPicList[X].isLongTerm[refIdxLx];
+ int col_lt = refPicList_col[listCol].isLongTerm[refidxCol];
+ int col_poc_diff, cur_poc_diff;
+
+ if (cur_lt != col_lt) {
+ mvLXCol->x = 0;
+ mvLXCol->y = 0;
+ return 0;
+ }
+
+ 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) {
+ mvLXCol->x = mvCol->x;
+ mvLXCol->y = mvCol->y;
+ } else {
+ mv_scale(mvLXCol, mvCol, col_poc_diff, cur_poc_diff);
+ }
+ return 1;
+}
+
+#define CHECK_MVSET(l) \
+ check_mvset(mvLXCol, temp_col.mv + l, \
+ colPic, s->poc, \
+ refPicList, X, refIdxLx, \
+ refPicList_col, L##l, temp_col.ref_idx[l])
+
+// derive the motion vectors section 8.5.3.1.8
+static int derive_temporal_colocated_mvs(HEVCContext *s, MvField temp_col,
+ int refIdxLx, Mv* mvLXCol, int X,
+ int colPic, RefPicList* refPicList_col)
+{
+ RefPicList *refPicList = s->ref->refPicList;
+
+ if (temp_col.is_intra) {
+ mvLXCol->x = 0;
+ mvLXCol->y = 0;
+ return 0;
+ }
+
+ if (temp_col.pred_flag[0] == 0)
+ return CHECK_MVSET(1);
+ else if (temp_col.pred_flag[0] == 1 && temp_col.pred_flag[1] == 0)
+ return CHECK_MVSET(0);
+ else if (temp_col.pred_flag[0] == 1 && temp_col.pred_flag[1] == 1) {
+ 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++;
+ }
+ if (check_diffpicount == 0 && X == 0)
+ return CHECK_MVSET(0);
+ else if (check_diffpicount == 0 && X == 1)
+ return CHECK_MVSET(1);
+ else {
+ if (s->sh.collocated_list == L1)
+ return CHECK_MVSET(0);
+ else
+ return CHECK_MVSET(1);
+ }
+ }
+
+ return 0;
+}
+
+#define TAB_MVF(x, y) \
+ tab_mvf[(y) * min_pu_width + x]
+
+#define TAB_MVF_PU(v) \
+ TAB_MVF(x##v##_pu, y##v##_pu)
+
+#define DERIVE_TEMPORAL_COLOCATED_MVS \
+ derive_temporal_colocated_mvs(s, temp_col, \
+ refIdxLx, mvLXCol, X, colPic, \
+ ff_hevc_get_ref_list(s, ref, x, y))
+
+/*
+ * 8.5.3.1.7 temporal luma motion vector prediction
+ */
+static int temporal_luma_motion_vector(HEVCContext *s, int x0, int y0,
+ int nPbW, int nPbH, int refIdxLx,
+ Mv* mvLXCol, int X)
+{
+ MvField *tab_mvf;
+ MvField temp_col;
+ int x, y;
+ int x_pu, y_pu;
+ int min_pu_width = s->sps->min_pu_width;
+ int availableFlagLXCol = 0;
+ int colPic;
+
+ HEVCFrame *ref = s->ref->collocated_ref;
+
+ if (!ref)
+ return 0;
+
+ tab_mvf = ref->tab_mvf;
+ colPic = ref->poc;
+
+ //bottom right collocated motion vector
+ x = x0 + nPbW;
+ y = y0 + nPbH;
+
+ if (s->threads_type == FF_THREAD_FRAME )
+ ff_thread_await_progress(&ref->tf, y, 0);
+ if (tab_mvf &&
+ (y0 >> s->sps->log2_ctb_size) == (y >> s->sps->log2_ctb_size) &&
+ y < s->sps->height &&
+ x < s->sps->width) {
+ x = ((x >> 4) << 4);
+ y = ((y >> 4) << 4);
+ 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);
+ availableFlagLXCol = DERIVE_TEMPORAL_COLOCATED_MVS;
+ }
+
+ // derive center collocated motion vector
+ if (tab_mvf && !availableFlagLXCol) {
+ x = x0 + (nPbW >> 1);
+ y = y0 + (nPbH >> 1);
+ x = ((x >> 4) << 4);
+ y = ((y >> 4) << 4);
+ 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);
+ availableFlagLXCol = DERIVE_TEMPORAL_COLOCATED_MVS;
+ }
+ return availableFlagLXCol;
+}
+
+#define AVAILABLE(cand, v) \
+ (cand && !TAB_MVF_PU(v).is_intra)
+
+#define PRED_BLOCK_AVAILABLE(v) \
+ check_prediction_block_available(s, log2_cb_size, \
+ x0, y0, nPbW, nPbH, \
+ x##v, y##v, part_idx)
+
+#define COMPARE_MV_REFIDX(a, b) \
+ compareMVrefidx(TAB_MVF_PU(a), TAB_MVF_PU(b))
+
+/*
+ * 8.5.3.1.2 Derivation process for spatial merging candidates
+ */
+static void derive_spatial_merge_candidates(HEVCContext *s, int x0, int y0,
+ int nPbW, int nPbH, int log2_cb_size,
+ int singleMCLFlag, int part_idx,
+ struct MvField mergecandlist[])
+{
+ HEVCLocalContext *lc = s->HEVClc;
+ RefPicList *refPicList = s->ref->refPicList;
+ MvField *tab_mvf = s->ref->tab_mvf;
+
+ const int min_pu_width = s->sps->min_pu_width;
+
+ 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;
+
+ 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;
+
+ int nb_merge_cand = 0;
+ int nb_orig_merge_cand = 0;
+
+ int is_available_a0;
+ int is_available_a1;
+ 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_available_a1 = 0;
+ }
+
+ if (is_available_a1)
+ mergecandlist[nb_merge_cand++] = TAB_MVF_PU(A1);
+
+ // 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_available_b1 = 0;
+ }
+
+ 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;
+
+ if (is_available_b1 && is_available_b0)
+ check_MER = !COMPARE_MV_REFIDX(B0, B1);
+
+ if (is_available_b0 && check_MER)
+ mergecandlist[nb_merge_cand++] = TAB_MVF_PU(B0);
+
+ // 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;
+
+ if (is_available_a1 && is_available_a0)
+ check_MER = !COMPARE_MV_REFIDX(A0, A1);
+
+ if (is_available_a0 && check_MER)
+ mergecandlist[nb_merge_cand++] = TAB_MVF_PU(A0);
+
+ // above left spatial merge candidate
+ check_MER = 1;
+
+ is_available_b2 = AVAILABLE(cand_up_left, B2);
+
+ if (isDiffMER(s, xB2, yB2, x0, y0))
+ is_available_b2 = 0;
+
+ if (is_available_a1 && is_available_b2)
+ check_MER = !COMPARE_MV_REFIDX(B2, A1);
+
+ if (is_available_b1 && is_available_b2)
+ check_MER_1 = !COMPARE_MV_REFIDX(B2, B1);
+
+ if (is_available_b2 && check_MER && check_MER_1 && nb_merge_cand != 4)
+ mergecandlist[nb_merge_cand++] = TAB_MVF_PU(B2);
+
+ // temporal motion vector candidate
+ if (s->sh.slice_temporal_mvp_enabled_flag &&
+ nb_merge_cand < s->sh.max_num_merge_cand) {
+ Mv mv_l0_col, mv_l1_col;
+ int available_l0 = temporal_luma_motion_vector(s, x0, y0, nPbW, nPbH,
+ 0, &mv_l0_col, 0);
+ int available_l1 = (s->sh.slice_type == B_SLICE) ?
+ temporal_luma_motion_vector(s, x0, y0, nPbW, nPbH,
+ 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;
+ if (available_l0) {
+ mergecandlist[nb_merge_cand].mv[0] = mv_l0_col;
+ mergecandlist[nb_merge_cand].ref_idx[0] = 0;
+ }
+ if (available_l1) {
+ mergecandlist[nb_merge_cand].mv[1] = mv_l1_col;
+ mergecandlist[nb_merge_cand].ref_idx[1] = 0;
+ }
+ nb_merge_cand++;
+ }
+ }
+
+ nb_orig_merge_cand = nb_merge_cand;
+
+ // 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 = 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++) {
+ int l0_cand_idx = l0_l1_cand_idx[comb_idx][0];
+ int l1_cand_idx = l0_l1_cand_idx[comb_idx][1];
+ 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] &&
+ (refPicList[0].list[l0_cand.ref_idx[0]] !=
+ refPicList[1].list[l1_cand.ref_idx[1]] ||
+ l0_cand.mv[0].x != l1_cand.mv[1].x ||
+ l0_cand.mv[0].y != l1_cand.mv[1].y)) {
+ 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].mv[0].x = l0_cand.mv[0].x;
+ mergecandlist[nb_merge_cand].mv[0].y = l0_cand.mv[0].y;
+ mergecandlist[nb_merge_cand].mv[1].x = l1_cand.mv[1].x;
+ mergecandlist[nb_merge_cand].mv[1].y = l1_cand.mv[1].y;
+ mergecandlist[nb_merge_cand].is_intra = 0;
+ nb_merge_cand++;
+ }
+ }
+ }
+
+ // 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].mv[0].x = 0;
+ mergecandlist[nb_merge_cand].mv[0].y = 0;
+ mergecandlist[nb_merge_cand].mv[1].x = 0;
+ mergecandlist[nb_merge_cand].mv[1].y = 0;
+ 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;
+
+ nb_merge_cand++;
+ zero_idx++;
+ }
+}
+
+/*
+ * 8.5.3.1.1 Derivation process of luma Mvs for merge mode
+ */
+void ff_hevc_luma_mv_merge_mode(HEVCContext *s, int x0, int y0, int nPbW,
+ int nPbH, int log2_cb_size, int part_idx,
+ int merge_idx, MvField *mv)
+{
+ int singleMCLFlag = 0;
+ int nCS = 1 << log2_cb_size;
+ struct MvField mergecand_list[MRG_MAX_NUM_CANDS] = { { { { 0 } } } };
+ int nPbW2 = nPbW;
+ int nPbH2 = nPbH;
+ HEVCLocalContext *lc = s->HEVClc;
+
+ if (s->pps->log2_parallel_merge_level > 2 && nCS == 8) {
+ singleMCLFlag = 1;
+ x0 = lc->cu.x;
+ y0 = lc->cu.y;
+ nPbW = nCS;
+ nPbH = nCS;
+ part_idx = 0;
+ }
+
+ ff_hevc_set_neighbour_available(s, x0, y0, nPbW, nPbH);
+ derive_spatial_merge_candidates(s, x0, y0, nPbW, nPbH, log2_cb_size,
+ singleMCLFlag, part_idx, mergecand_list);
+
+ if (mergecand_list[merge_idx].pred_flag[0] == 1 &&
+ mergecand_list[merge_idx].pred_flag[1] == 1 &&
+ (nPbW2 + nPbH2) == 12) {
+ mergecand_list[merge_idx].ref_idx[1] = -1;
+ mergecand_list[merge_idx].pred_flag[1] = 0;
+ }
+
+ *mv = mergecand_list[merge_idx];
+}
+
+static av_always_inline void dist_scale(HEVCContext *s, Mv * mv,
+ int min_pu_width, int x, int y,
+ int elist, int ref_idx_curr, int ref_idx)
+{
+ RefPicList *refPicList = s->ref->refPicList;
+ MvField *tab_mvf = s->ref->tab_mvf;
+ int ref_pic_elist = refPicList[elist].list[TAB_MVF(x, y).ref_idx[elist]];
+ int ref_pic_curr = refPicList[ref_idx_curr].list[ref_idx];
+
+ if (ref_pic_elist != ref_pic_curr)
+ mv_scale(mv, mv, s->poc - ref_pic_elist, s->poc - ref_pic_curr);
+}
+
+static int mv_mp_mode_mx(HEVCContext *s, int x, int y, int pred_flag_index,
+ Mv *mv, int ref_idx_curr, int ref_idx)
+{
+ MvField *tab_mvf = s->ref->tab_mvf;
+ int min_pu_width = s->sps->min_pu_width;
+
+ RefPicList *refPicList = s->ref->refPicList;
+
+ if (TAB_MVF(x, y).pred_flag[pred_flag_index] == 1 &&
+ 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;
+ }
+ return 0;
+}
+
+
+static int mv_mp_mode_mx_lt(HEVCContext *s, int x, int y, int pred_flag_index,
+ Mv *mv, int ref_idx_curr, int ref_idx)
+{
+ MvField *tab_mvf = s->ref->tab_mvf;
+ 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[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;
+ }
+ 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)
+
+#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)
+
+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;
+ MvField *tab_mvf = s->ref->tab_mvf;
+ int isScaledFlag_L0 = 0;
+ int availableFlagLXA0 = 0;
+ int availableFlagLXB0 = 0;
+ 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 xB2, yB2;
+ int xB2_pu = 0, yB2_pu = 0;
+ int is_available_b2 = 0;
+ Mv mvpcand_list[2] = { { 0 } };
+ Mv mxA = { 0 };
+ Mv mxB = { 0 };
+ int ref_idx_curr = 0;
+ 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;
+
+ ref_idx_curr = LX;
+ ref_idx = mv->ref_idx[LX];
+ pred_flag_index_l0 = LX;
+ pred_flag_index_l1 = !LX;
+
+ // 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);
+
+ //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 (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 && !availableFlagLXA0) {
+ availableFlagLXA0 = MP_MX_LT(A1, pred_flag_index_l0, mxA);
+ if (!availableFlagLXA0)
+ availableFlagLXA0 = MP_MX_LT(A1, pred_flag_index_l1, mxA);
+ }
+
+ // 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);
+
+ 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;
+
+ is_available_b1 = AVAILABLE(cand_up, B1);
+
+ if (is_available_b1) {
+ availableFlagLXB0 = MP_MX(B1, pred_flag_index_l0, mxB);
+ if (!availableFlagLXB0)
+ availableFlagLXB0 = MP_MX(B1, pred_flag_index_l1, mxB);
+ }
+ }
+
+ 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);
+
+ if (is_available_b2) {
+ availableFlagLXB0 = MP_MX(B2, pred_flag_index_l0, mxB);
+ if (!availableFlagLXB0)
+ availableFlagLXB0 = MP_MX(B2, pred_flag_index_l1, mxB);
+ }
+ }
+
+ if (isScaledFlag_L0 == 0) {
+ if (availableFlagLXB0) {
+ availableFlagLXA0 = 1;
+ mxA = mxB;
+ }
+ availableFlagLXB0 = 0;
+
+ // XB0 and L1
+ if (is_available_b0) {
+ availableFlagLXB0 = MP_MX_LT(B0, pred_flag_index_l0, mxB);
+ if (!availableFlagLXB0)
+ availableFlagLXB0 = MP_MX_LT(B0, pred_flag_index_l1, mxB);
+ }
+
+ if (is_available_b1 && !availableFlagLXB0) {
+ availableFlagLXB0 = MP_MX_LT(B1, pred_flag_index_l0, mxB);
+ if (!availableFlagLXB0)
+ availableFlagLXB0 = MP_MX_LT(B1, pred_flag_index_l1, mxB);
+ }
+
+ if (is_available_b2 && !availableFlagLXB0) {
+ availableFlagLXB0 = MP_MX_LT(B2, pred_flag_index_l0, mxB);
+ if (!availableFlagLXB0)
+ availableFlagLXB0 = MP_MX_LT(B2, pred_flag_index_l1, mxB);
+ }
+ }
+
+ if (availableFlagLXA0)
+ mvpcand_list[numMVPCandLX++] = mxA;
+
+ if (availableFlagLXB0 && (!availableFlagLXA0 || mxA.x != mxB.x || mxA.y != mxB.y))
+ mvpcand_list[numMVPCandLX++] = mxB;
+
+ //temporal motion vector prediction candidate
+ if (numMVPCandLX < 2 && s->sh.slice_temporal_mvp_enabled_flag) {
+ Mv mv_col;
+ int available_col = temporal_luma_motion_vector(s, x0, y0, nPbW,
+ nPbH, ref_idx, &mv_col, LX);
+ if (available_col)
+ 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;
+}
diff --git a/libavcodec/hevc_parser.c b/libavcodec/hevc_parser.c
new file mode 100644
index 0000000..642f975
--- a/dev/null
+++ b/libavcodec/hevc_parser.c
@@ -0,0 +1,345 @@
+/*
+ * HEVC Annex B format parser
+ *
+ * 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
+ */
+
+#include "libavutil/common.h"
+#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
+ */
+static int hevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf, int buf_size)
+{
+ int i;
+ ParseContext *pc = &((HEVCParseContext *)s->priv_data)->pc;
+
+ for (i = 0; i < buf_size; i++) {
+ int nut;
+
+ pc->state64 = (pc->state64 << 8) | buf[i];
+
+ if (((pc->state64 >> 3 * 8) & 0xFFFFFF) != START_CODE)
+ continue;
+
+ nut = (pc->state64 >> 2 * 8 + 1) & 0x3F;
+ // Beginning of access unit
+ if ((nut >= NAL_VPS && nut <= NAL_AUD) || nut == NAL_SEI_PREFIX ||
+ (nut >= 41 && nut <= 44) || (nut >= 48 && nut <= 55)) {
+ if (pc->frame_start_found) {
+ pc->frame_start_found = 0;
+ return i - 5;
+ }
+ } else if (nut <= NAL_RASL_R ||
+ (nut >= NAL_BLA_W_LP && nut <= NAL_CRA_NUT)) {
+ int first_slice_segment_in_pic_flag = buf[i] >> 7;
+ if (first_slice_segment_in_pic_flag) {
+ if (!pc->frame_start_found) {
+ pc->frame_start_found = 1;
+ } else { // First slice of next frame found
+ pc->frame_start_found = 0;
+ return i - 5;
+ }
+ }
+ }
+ }
+
+ return END_NOT_FOUND;
+}
+
+/**
+ * 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);
+
+ if (h->nal_unit_type >= 16 && h->nal_unit_type <= 23) {
+ 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 = h->vps_list[h->sps->vps_id];
+ }
+
+ 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 = &((HEVCParseContext *)s->priv_data)->pc;
+
+ if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
+ next = buf_size;
+ } else {
+ next = hevc_find_frame_end(s, buf, buf_size);
+ if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
+ *poutbuf = NULL;
+ *poutbuf_size = 0;
+ return buf_size;
+ }
+ }
+
+ parse_nal_units(s, avctx, buf, buf_size);
+
+ *poutbuf = buf;
+ *poutbuf_size = buf_size;
+ return next;
+}
+
+// Split after the parameter sets at the beginning of the stream if they exist.
+static int hevc_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
+{
+ int i;
+ uint32_t state = -1;
+ int has_ps = 0;
+
+ for (i = 0; i < buf_size; i++) {
+ state = (state << 8) | buf[i];
+ if (((state >> 8) & 0xFFFFFF) == START_CODE) {
+ int nut = (state >> 1) & 0x3F;
+ if (nut >= NAL_VPS && nut <= NAL_PPS) {
+ has_ps = 1;
+ } else if (has_ps) {
+ return i - 3;
+ } else { // no parameter set at the beginning of the stream
+ return 0;
+ }
+ }
+ }
+ 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_freep(&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]);
+
+ 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(HEVCParseContext),
+ .parser_init = hevc_init,
+ .parser_parse = hevc_parse,
+ .parser_close = hevc_close,
+ .split = hevc_split,
+};
diff --git a/libavcodec/hevc_ps.c b/libavcodec/hevc_ps.c
new file mode 100644
index 0000000..8fe6c8a
--- a/dev/null
+++ b/libavcodec/hevc_ps.c
@@ -0,0 +1,1313 @@
+/*
+ * HEVC Parameter Set Decoding
+ *
+ * Copyright (C) 2012 - 2103 Guillaume Martres
+ * Copyright (C) 2012 - 2103 Mickael Raulet
+ * Copyright (C) 2012 - 2013 Gildas Cocherel
+ * Copyright (C) 2013 Vittorio Giovara
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "golomb.h"
+#include "libavutil/imgutils.h"
+#include "hevc.h"
+
+static const uint8_t default_scaling_list_intra[] = {
+ 16, 16, 16, 16, 17, 18, 21, 24,
+ 16, 16, 16, 16, 17, 19, 22, 25,
+ 16, 16, 17, 18, 20, 22, 25, 29,
+ 16, 16, 18, 21, 24, 27, 31, 36,
+ 17, 17, 20, 24, 30, 35, 41, 47,
+ 18, 19, 22, 27, 35, 44, 54, 65,
+ 21, 22, 25, 31, 41, 54, 70, 88,
+ 24, 25, 29,36, 47, 65, 88, 115
+};
+
+static const uint8_t default_scaling_list_inter[] = {
+ 16, 16, 16, 16, 17, 18, 20, 24,
+ 16, 16, 16, 17, 18, 20, 24, 25,
+ 16, 16, 17, 18, 20, 24, 25, 28,
+ 16, 17, 18, 20, 24, 25, 28, 33,
+ 17, 18, 20, 24, 25, 28, 33, 41,
+ 18, 20, 24, 25, 28, 33, 41, 54,
+ 20, 24, 25, 28, 33, 41, 54, 71,
+ 24, 25, 28, 33, 41, 54, 71, 91
+};
+
+static const AVRational vui_sar[] = {
+ { 0, 1 },
+ { 1, 1 },
+ { 12, 11 },
+ { 10, 11 },
+ { 16, 11 },
+ { 40, 33 },
+ { 24, 11 },
+ { 20, 11 },
+ { 32, 11 },
+ { 80, 33 },
+ { 18, 11 },
+ { 15, 11 },
+ { 64, 33 },
+ { 160, 99 },
+ { 4, 3 },
+ { 3, 2 },
+ { 2, 1 },
+};
+
+int ff_hevc_decode_short_term_rps(HEVCContext *s, ShortTermRPS *rps,
+ const HEVCSPS *sps, int is_slice_header)
+{
+ HEVCLocalContext *lc = s->HEVClc;
+ uint8_t rps_predict = 0;
+ int delta_poc;
+ int k0 = 0;
+ int k1 = 0;
+ int k = 0;
+ int i;
+
+ GetBitContext *gb = &lc->gb;
+
+ if (rps != sps->st_rps && sps->nb_st_rps)
+ rps_predict = get_bits1(gb);
+
+ if (rps_predict) {
+ const ShortTermRPS *rps_ridx;
+ int delta_rps, abs_delta_rps;
+ uint8_t use_delta_flag = 0;
+ uint8_t delta_rps_sign;
+
+ if (is_slice_header) {
+ int delta_idx = get_ue_golomb_long(gb) + 1;
+ if (delta_idx > sps->nb_st_rps) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid value of delta_idx "
+ "in slice header RPS: %d > %d.\n", delta_idx,
+ sps->nb_st_rps);
+ return AVERROR_INVALIDDATA;
+ }
+ rps_ridx = &sps->st_rps[sps->nb_st_rps - delta_idx];
+ } else
+ rps_ridx = &sps->st_rps[rps - sps->st_rps - 1];
+
+ delta_rps_sign = get_bits1(gb);
+ abs_delta_rps = get_ue_golomb_long(gb) + 1;
+ 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);
+
+ if (!used)
+ use_delta_flag = get_bits1(gb);
+
+ if (used || use_delta_flag) {
+ if (i < rps_ridx->num_delta_pocs)
+ delta_poc = delta_rps + rps_ridx->delta_poc[i];
+ else
+ delta_poc = delta_rps;
+ rps->delta_poc[k] = delta_poc;
+ if (delta_poc < 0)
+ k0++;
+ else
+ k1++;
+ k++;
+ }
+ }
+
+ rps->num_delta_pocs = k;
+ rps->num_negative_pics = k0;
+ // sort in increasing order (smallest first)
+ if (rps->num_delta_pocs != 0) {
+ int used, tmp;
+ for (i = 1; i < rps->num_delta_pocs; i++) {
+ delta_poc = rps->delta_poc[i];
+ used = rps->used[i];
+ for (k = i-1 ; k >= 0; k--) {
+ tmp = rps->delta_poc[k];
+ if (delta_poc < tmp ) {
+ rps->delta_poc[k+1] = tmp;
+ rps->used[k+1] = rps->used[k];
+ rps->delta_poc[k] = delta_poc;
+ rps->used[k] = used;
+ }
+ }
+ }
+ }
+ if ((rps->num_negative_pics >> 1) != 0) {
+ int used;
+ k = rps->num_negative_pics - 1;
+ // flip the negative values to largest first
+ for (i = 0; i < rps->num_negative_pics>>1; i++) {
+ delta_poc = rps->delta_poc[i];
+ used = rps->used[i];
+ rps->delta_poc[i] = rps->delta_poc[k];
+ rps->used[i] = rps->used[k];
+ rps->delta_poc[k] = delta_poc;
+ rps->used[k] = used;
+ k--;
+ }
+ }
+ } else {
+ unsigned int prev, nb_positive_pics;
+ rps->num_negative_pics = get_ue_golomb_long(gb);
+ nb_positive_pics = get_ue_golomb_long(gb);
+
+ if (rps->num_negative_pics >= MAX_REFS ||
+ nb_positive_pics >= MAX_REFS) {
+ av_log(s->avctx, AV_LOG_ERROR, "Too many refs in a short term RPS.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ rps->num_delta_pocs = rps->num_negative_pics + nb_positive_pics;
+ if (rps->num_delta_pocs) {
+ prev = 0;
+ for (i = 0; i < rps->num_negative_pics; i++) {
+ delta_poc = get_ue_golomb_long(gb) + 1;
+ prev -= delta_poc;
+ rps->delta_poc[i] = prev;
+ rps->used[i] = get_bits1(gb);
+ }
+ prev = 0;
+ for (i = 0; i < nb_positive_pics; i++) {
+ delta_poc = get_ue_golomb_long(gb) + 1;
+ prev += delta_poc;
+ rps->delta_poc[rps->num_negative_pics + i] = prev;
+ rps->used[rps->num_negative_pics + i] = get_bits1(gb);
+ }
+ }
+ }
+ return 0;
+}
+
+static int decode_profile_tier_level(HEVCContext *s, PTL *ptl, int max_num_sub_layers)
+{
+ HEVCLocalContext *lc = s->HEVClc;
+ GetBitContext *gb = &lc->gb;
+ int i, j;
+
+ ptl->general_profile_space = get_bits(gb, 2);
+ ptl->general_tier_flag = get_bits1(gb);
+ ptl->general_profile_idc = get_bits(gb, 5);
+ if (ptl->general_profile_idc == 1)
+ av_log(s->avctx, AV_LOG_DEBUG, "Main profile bitstream\n");
+ else if (ptl->general_profile_idc == 2)
+ av_log(s->avctx, AV_LOG_DEBUG, "Main10 profile bitstream\n");
+ else
+ av_log(s->avctx, AV_LOG_WARNING, "No profile indication! (%d)\n", ptl->general_profile_idc);
+
+ for (i = 0; i < 32; i++)
+ ptl->general_profile_compatibility_flag[i] = get_bits1(gb);
+ skip_bits1(gb);// general_progressive_source_flag
+ skip_bits1(gb);// general_interlaced_source_flag
+ skip_bits1(gb);// general_non_packed_constraint_flag
+ skip_bits1(gb);// general_frame_only_constraint_flag
+ if (get_bits(gb, 16) != 0) // XXX_reserved_zero_44bits[0..15]
+ return -1;
+ if (get_bits(gb, 16) != 0) // XXX_reserved_zero_44bits[16..31]
+ return -1;
+ if (get_bits(gb, 12) != 0) // XXX_reserved_zero_44bits[32..43]
+ return -1;
+
+ ptl->general_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)
+ 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]) {
+ ptl->sub_layer_profile_space[i] = get_bits(gb, 2);
+ ptl->sub_layer_tier_flag[i] = get_bits(gb, 1);
+ ptl->sub_layer_profile_idc[i] = get_bits(gb, 5);
+ for (j = 0; j < 32; j++)
+ ptl->sub_layer_profile_compatibility_flags[i][j] = get_bits1(gb);
+ skip_bits1(gb);// sub_layer_progressive_source_flag
+ skip_bits1(gb);// sub_layer_interlaced_source_flag
+ skip_bits1(gb);// sub_layer_non_packed_constraint_flag
+ skip_bits1(gb);// sub_layer_frame_only_constraint_flag
+
+ if (get_bits(gb, 16) != 0) // sub_layer_reserved_zero_44bits[0..15]
+ return -1;
+ if (get_bits(gb, 16) != 0) // sub_layer_reserved_zero_44bits[16..31]
+ return -1;
+ if (get_bits(gb, 12) != 0) // sub_layer_reserved_zero_44bits[32..43]
+ return -1;
+ }
+ if (ptl->sub_layer_level_present_flag[i])
+ ptl->sub_layer_level_idc[i] = get_bits(gb, 8);
+ }
+ return 0;
+}
+
+static void decode_sublayer_hrd(HEVCContext *s, int nb_cpb, int subpic_params_present)
+{
+ GetBitContext *gb = &s->HEVClc->gb;
+ int i;
+
+ for (i = 0; i < nb_cpb; i++) {
+ get_ue_golomb_long(gb); // bit_rate_value_minus1
+ get_ue_golomb_long(gb); // cpb_size_value_minus1
+
+ if (subpic_params_present) {
+ get_ue_golomb_long(gb); // cpb_size_du_value_minus1
+ get_ue_golomb_long(gb); // bit_rate_du_value_minus1
+ }
+ skip_bits1(gb); // cbr_flag
+ }
+}
+
+static void decode_hrd(HEVCContext *s, int common_inf_present, int max_sublayers)
+{
+ GetBitContext *gb = &s->HEVClc->gb;
+ int nal_params_present = 0, vcl_params_present = 0;
+ int subpic_params_present = 0;
+ int i;
+
+ if (common_inf_present) {
+ nal_params_present = get_bits1(gb);
+ vcl_params_present = get_bits1(gb);
+
+ if (nal_params_present || vcl_params_present) {
+ subpic_params_present = get_bits1(gb);
+
+ if (subpic_params_present) {
+ skip_bits(gb, 8); // tick_divisor_minus2
+ skip_bits(gb, 5); // du_cpb_removal_delay_increment_length_minus1
+ skip_bits(gb, 1); // sub_pic_cpb_params_in_pic_timing_sei_flag
+ skip_bits(gb, 5); // dpb_output_delay_du_length_minus1
+ }
+
+ skip_bits(gb, 4); // bit_rate_scale
+ skip_bits(gb, 4); // cpb_size_scale
+
+ if (subpic_params_present)
+ skip_bits(gb, 4); // cpb_size_du_scale
+
+ skip_bits(gb, 5); // initial_cpb_removal_delay_length_minus1
+ skip_bits(gb, 5); // au_cpb_removal_delay_length_minus1
+ skip_bits(gb, 5); // dpb_output_delay_length_minus1
+ }
+ }
+
+ for (i = 0; i < max_sublayers; i++) {
+ int low_delay = 0;
+ int nb_cpb = 1;
+ int fixed_rate = get_bits1(gb);
+
+ if (!fixed_rate)
+ fixed_rate = get_bits1(gb);
+
+ if (fixed_rate)
+ get_ue_golomb_long(gb); // elemental_duration_in_tc_minus1
+ else
+ low_delay = get_bits1(gb);
+
+ if (!low_delay)
+ nb_cpb = get_ue_golomb_long(gb) + 1;
+
+ 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);
+ }
+}
+
+int ff_hevc_decode_nal_vps(HEVCContext *s)
+{
+ int i,j;
+ GetBitContext *gb = &s->HEVClc->gb;
+ int vps_id = 0;
+ VPS *vps;
+
+ av_log(s->avctx, AV_LOG_DEBUG, "Decoding VPS\n");
+
+ vps = av_mallocz(sizeof(*vps));
+ if (!vps)
+ return AVERROR(ENOMEM);
+
+ vps_id = get_bits(gb, 4);
+ if (vps_id >= MAX_VPS_COUNT) {
+ av_log(s->avctx, AV_LOG_ERROR, "VPS id out of range: %d\n", vps_id);
+ goto err;
+ }
+
+ if (get_bits(gb, 2) != 3) { // vps_reserved_three_2bits
+ av_log(s->avctx, AV_LOG_ERROR, "vps_reserved_three_2bits is not three\n");
+ goto err;
+ }
+
+ vps->vps_max_layers = get_bits(gb, 6) + 1;
+ vps->vps_max_sub_layers = get_bits(gb, 3) + 1;
+ vps->vps_temporal_id_nesting_flag = get_bits1(gb);
+
+ if (get_bits(gb, 16) != 0xffff) { // vps_reserved_ffff_16bits
+ av_log(s->avctx, AV_LOG_ERROR, "vps_reserved_ffff_16bits is not 0xffff\n");
+ goto err;
+ }
+
+ if (vps->vps_max_sub_layers > MAX_SUB_LAYERS) {
+ av_log(s->avctx, AV_LOG_ERROR, "vps_max_sub_layers out of range: %d\n",
+ vps->vps_max_sub_layers);
+ goto err;
+ }
+
+ if (decode_profile_tier_level(s, &vps->ptl, vps->vps_max_sub_layers) < 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "Error decoding profile tier level.\n");
+ goto err;
+ }
+ vps->vps_sub_layer_ordering_info_present_flag = get_bits1(gb);
+
+ i = vps->vps_sub_layer_ordering_info_present_flag ? 0 : vps->vps_max_sub_layers - 1;
+ for (; i < vps->vps_max_sub_layers; i++) {
+ vps->vps_max_dec_pic_buffering[i] = get_ue_golomb_long(gb) + 1;
+ 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) {
+ 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;
+ }
+ if (vps->vps_num_reorder_pics[i] > vps->vps_max_dec_pic_buffering[i] - 1) {
+ av_log(s->avctx, AV_LOG_ERROR, "vps_max_num_reorder_pics out of range: %d\n",
+ vps->vps_num_reorder_pics[i]);
+ goto err;
+ }
+ }
+
+ vps->vps_max_layer_id = get_bits(gb, 6);
+ vps->vps_num_layer_sets = get_ue_golomb_long(gb) + 1;
+ for (i = 1; i < vps->vps_num_layer_sets; i++)
+ for (j = 0; j <= vps->vps_max_layer_id; j++)
+ skip_bits(gb, 1); // layer_id_included_flag[i][j]
+
+ vps->vps_timing_info_present_flag = get_bits1(gb);
+ if (vps->vps_timing_info_present_flag) {
+ vps->vps_num_units_in_tick = get_bits_long(gb, 32);
+ vps->vps_time_scale = get_bits_long(gb, 32);
+ vps->vps_poc_proportional_to_timing_flag = get_bits1(gb);
+ if (vps->vps_poc_proportional_to_timing_flag)
+ vps->vps_num_ticks_poc_diff_one = get_ue_golomb_long(gb) + 1;
+ vps->vps_num_hrd_parameters = get_ue_golomb_long(gb);
+ for (i = 0; i < vps->vps_num_hrd_parameters; i++) {
+ int common_inf_present = 1;
+
+ get_ue_golomb_long(gb); // hrd_layer_set_idx
+ if (i)
+ common_inf_present = get_bits1(gb);
+ decode_hrd(s, common_inf_present, vps->vps_max_sub_layers);
+ }
+ }
+ get_bits1(gb); /* vps_extension_flag */
+
+ av_free(s->vps_list[vps_id]);
+ s->vps_list[vps_id] = vps;
+ return 0;
+
+err:
+ av_free(vps);
+ return AVERROR_INVALIDDATA;
+}
+
+static void decode_vui(HEVCContext *s, HEVCSPS *sps)
+{
+ VUI *vui = &sps->vui;
+ GetBitContext *gb = &s->HEVClc->gb;
+ int sar_present;
+
+ av_log(s->avctx, AV_LOG_DEBUG, "Decoding VUI\n");
+
+ sar_present = get_bits1(gb);
+ if (sar_present) {
+ uint8_t sar_idx = get_bits(gb, 8);
+ if (sar_idx < FF_ARRAY_ELEMS(vui_sar))
+ vui->sar = vui_sar[sar_idx];
+ else if (sar_idx == 255) {
+ vui->sar.num = get_bits(gb, 16);
+ vui->sar.den = get_bits(gb, 16);
+ } else
+ av_log(s->avctx, AV_LOG_WARNING, "Unknown SAR index: %u.\n",
+ sar_idx);
+ }
+
+ vui->overscan_info_present_flag = get_bits1(gb);
+ if (vui->overscan_info_present_flag)
+ vui->overscan_appropriate_flag = get_bits1(gb);
+
+ vui->video_signal_type_present_flag = get_bits1(gb);
+ if (vui->video_signal_type_present_flag) {
+ vui->video_format = get_bits(gb, 3);
+ vui->video_full_range_flag = get_bits1(gb);
+ vui->colour_description_present_flag = get_bits1(gb);
+ if (vui->colour_description_present_flag) {
+ vui->colour_primaries = get_bits(gb, 8);
+ vui->transfer_characteristic = get_bits(gb, 8);
+ vui->matrix_coeffs = get_bits(gb, 8);
+ }
+ }
+
+ vui->chroma_loc_info_present_flag = get_bits1(gb);
+ if (vui->chroma_loc_info_present_flag) {
+ vui->chroma_sample_loc_type_top_field = get_ue_golomb_long(gb);
+ vui->chroma_sample_loc_type_bottom_field = get_ue_golomb_long(gb);
+ }
+
+ vui->neutra_chroma_indication_flag = get_bits1(gb);
+ 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 (vui->default_display_window_flag) {
+ //TODO: * 2 is only valid for 420
+ vui->def_disp_win.left_offset = get_ue_golomb_long(gb) * 2;
+ vui->def_disp_win.right_offset = get_ue_golomb_long(gb) * 2;
+ vui->def_disp_win.top_offset = get_ue_golomb_long(gb) * 2;
+ vui->def_disp_win.bottom_offset = get_ue_golomb_long(gb) * 2;
+
+ if (s->strict_def_disp_win &&
+ s->avctx->flags2 & CODEC_FLAG2_IGNORE_CROP) {
+ av_log(s->avctx, AV_LOG_DEBUG,
+ "discarding vui default display window, "
+ "original values are l:%u r:%u t:%u b:%u\n",
+ vui->def_disp_win.left_offset,
+ vui->def_disp_win.right_offset,
+ vui->def_disp_win.top_offset,
+ vui->def_disp_win.bottom_offset);
+
+ vui->def_disp_win.left_offset =
+ vui->def_disp_win.right_offset =
+ vui->def_disp_win.top_offset =
+ vui->def_disp_win.bottom_offset = 0;
+ }
+ }
+
+ vui->vui_timing_info_present_flag = get_bits1(gb);
+ if (vui->vui_timing_info_present_flag) {
+ vui->vui_num_units_in_tick = get_bits(gb, 32);
+ vui->vui_time_scale = get_bits(gb, 32);
+ 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);
+ vui->vui_hrd_parameters_present_flag = get_bits1(gb);
+ if (vui->vui_hrd_parameters_present_flag)
+ decode_hrd(s, 1, sps->max_sub_layers);
+ }
+
+ vui->bitstream_restriction_flag = get_bits1(gb);
+ if (vui->bitstream_restriction_flag) {
+ vui->tiles_fixed_structure_flag = get_bits1(gb);
+ vui->motion_vectors_over_pic_boundaries_flag = get_bits1(gb);
+ vui->restricted_ref_pic_lists_flag = get_bits1(gb);
+ vui->min_spatial_segmentation_idc = get_ue_golomb_long(gb);
+ vui->max_bytes_per_pic_denom = get_ue_golomb_long(gb);
+ vui->max_bits_per_min_cu_denom = get_ue_golomb_long(gb);
+ vui->log2_max_mv_length_horizontal = get_ue_golomb_long(gb);
+ vui->log2_max_mv_length_vertical = get_ue_golomb_long(gb);
+ }
+}
+
+static void set_default_scaling_list_data(ScalingList *sl)
+{
+ int matrixId;
+
+ for (matrixId = 0; matrixId < 6; matrixId++) {
+ // 4x4 default is 16
+ memset(sl->sl[0][matrixId], 16, 16);
+ sl->sl_dc[0][matrixId] = 16; // default for 16x16
+ sl->sl_dc[1][matrixId] = 16; // default for 32x32
+ }
+ memcpy(sl->sl[1][0], default_scaling_list_intra, 64);
+ memcpy(sl->sl[1][1], default_scaling_list_intra, 64);
+ memcpy(sl->sl[1][2], default_scaling_list_intra, 64);
+ memcpy(sl->sl[1][3], default_scaling_list_inter, 64);
+ memcpy(sl->sl[1][4], default_scaling_list_inter, 64);
+ memcpy(sl->sl[1][5], default_scaling_list_inter, 64);
+ memcpy(sl->sl[2][0], default_scaling_list_intra, 64);
+ memcpy(sl->sl[2][1], default_scaling_list_intra, 64);
+ memcpy(sl->sl[2][2], default_scaling_list_intra, 64);
+ memcpy(sl->sl[2][3], default_scaling_list_inter, 64);
+ 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);
+}
+
+static int scaling_list_data(HEVCContext *s, ScalingList *sl)
+{
+ GetBitContext *gb = &s->HEVClc->gb;
+ uint8_t scaling_list_pred_mode_flag[4][6];
+ int32_t scaling_list_dc_coef[2][6];
+
+ int size_id, matrix_id, i, pos, delta;
+ 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]) {
+ delta = get_ue_golomb_long(gb);
+ // Only need to handle non-zero delta. Zero means default, which should already be in the arrays.
+ if (delta) {
+ // Copy from previous array.
+ if (matrix_id - delta < 0) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Invalid delta in scaling list data: %d.\n", delta);
+ return AVERROR_INVALIDDATA;
+ }
+
+ memcpy(sl->sl[size_id][matrix_id],
+ sl->sl[size_id][matrix_id - delta],
+ size_id > 0 ? 64 : 16);
+ if (size_id > 1)
+ sl->sl_dc[size_id - 2][matrix_id] = sl->sl_dc[size_id - 2][matrix_id - delta];
+ }
+ } else {
+ int next_coef;
+ int coef_num;
+ int32_t scaling_list_delta_coef;
+
+ next_coef = 8;
+ coef_num = FFMIN(64, (1 << (4 + (size_id << 1))));
+ if (size_id > 1) {
+ scaling_list_dc_coef[size_id - 2][matrix_id] = get_se_golomb(gb) + 8;
+ next_coef = scaling_list_dc_coef[size_id - 2][matrix_id];
+ sl->sl_dc[size_id - 2][matrix_id] = next_coef;
+ }
+ for (i = 0; i < coef_num; i++) {
+ if (size_id == 0)
+ pos = 4 * ff_hevc_diag_scan4x4_y[i] + ff_hevc_diag_scan4x4_x[i];
+ else
+ pos = 8 * ff_hevc_diag_scan8x8_y[i] + ff_hevc_diag_scan8x8_x[i];
+
+ scaling_list_delta_coef = get_se_golomb(gb);
+ next_coef = (next_coef + scaling_list_delta_coef + 256 ) % 256;
+ sl->sl[size_id][matrix_id][pos] = next_coef;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int ff_hevc_decode_nal_sps(HEVCContext *s)
+{
+ const AVPixFmtDescriptor *desc;
+ GetBitContext *gb = &s->HEVClc->gb;
+ int ret = 0;
+ int sps_id = 0;
+ int log2_diff_max_min_transform_block_size;
+ int bit_depth_chroma, start, vui_present, sublayer_ordering_info;
+ int i;
+
+ HEVCSPS *sps;
+ AVBufferRef *sps_buf = av_buffer_allocz(sizeof(*sps));
+
+ if (!sps_buf)
+ return AVERROR(ENOMEM);
+ sps = (HEVCSPS*)sps_buf->data;
+
+ av_log(s->avctx, AV_LOG_DEBUG, "Decoding SPS\n");
+
+ // Coded parameters
+
+ sps->vps_id = get_bits(gb, 4);
+ if (sps->vps_id >= MAX_VPS_COUNT) {
+ av_log(s->avctx, AV_LOG_ERROR, "VPS id out of range: %d\n", sps->vps_id);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+
+ sps->max_sub_layers = get_bits(gb, 3) + 1;
+ if (sps->max_sub_layers > MAX_SUB_LAYERS) {
+ av_log(s->avctx, AV_LOG_ERROR, "sps_max_sub_layers out of range: %d\n",
+ sps->max_sub_layers);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+
+ skip_bits1(gb); // temporal_id_nesting_flag
+ if (decode_profile_tier_level(s, &sps->ptl, sps->max_sub_layers) < 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "error decoding profile tier level\n");
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ sps_id = get_ue_golomb_long(gb);
+ if (sps_id >= MAX_SPS_COUNT) {
+ av_log(s->avctx, AV_LOG_ERROR, "SPS id out of range: %d\n", sps_id);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+
+ sps->chroma_format_idc = get_ue_golomb_long(gb);
+ if (sps->chroma_format_idc != 1) {
+ avpriv_report_missing_feature(s->avctx, "chroma_format_idc != 1\n");
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+
+ if (sps->chroma_format_idc == 3)
+ sps->separate_colour_plane_flag = get_bits1(gb);
+
+ sps->width = get_ue_golomb_long(gb);
+ sps->height = get_ue_golomb_long(gb);
+ if ((ret = av_image_check_size(sps->width,
+ sps->height, 0, s->avctx)) < 0)
+ goto err;
+
+ if (get_bits1(gb)) { // pic_conformance_flag
+ //TODO: * 2 is only valid for 420
+ sps->pic_conf_win.left_offset = get_ue_golomb_long(gb) * 2;
+ sps->pic_conf_win.right_offset = get_ue_golomb_long(gb) * 2;
+ sps->pic_conf_win.top_offset = get_ue_golomb_long(gb) * 2;
+ sps->pic_conf_win.bottom_offset = get_ue_golomb_long(gb) * 2;
+
+ if (s->avctx->flags2 & CODEC_FLAG2_IGNORE_CROP) {
+ av_log(s->avctx, AV_LOG_DEBUG,
+ "discarding sps conformance window, "
+ "original values are l:%u r:%u t:%u b:%u\n",
+ sps->pic_conf_win.left_offset,
+ sps->pic_conf_win.right_offset,
+ sps->pic_conf_win.top_offset,
+ sps->pic_conf_win.bottom_offset);
+
+ sps->pic_conf_win.left_offset =
+ sps->pic_conf_win.right_offset =
+ sps->pic_conf_win.top_offset =
+ sps->pic_conf_win.bottom_offset = 0;
+ }
+ sps->output_window = sps->pic_conf_win;
+ }
+
+ sps->bit_depth = get_ue_golomb_long(gb) + 8;
+ bit_depth_chroma = get_ue_golomb_long(gb) + 8;
+ if (bit_depth_chroma != sps->bit_depth) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Luma bit depth (%d) is different from chroma bit depth (%d), this is unsupported.\n",
+ sps->bit_depth, bit_depth_chroma);
+ ret = AVERROR_INVALIDDATA;
+ 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 {
+ av_log(s->avctx, AV_LOG_ERROR, "non-4:2:0 support is currently unspecified.\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ desc = av_pix_fmt_desc_get(sps->pix_fmt);
+ if (!desc) {
+ ret = AVERROR(EINVAL);
+ goto err;
+ }
+
+ sps->hshift[0] = sps->vshift[0] = 0;
+ sps->hshift[2] = sps->hshift[1] = desc->log2_chroma_w;
+ sps->vshift[2] = sps->vshift[1] = desc->log2_chroma_h;
+
+ sps->pixel_shift = sps->bit_depth > 8;
+
+ sps->log2_max_poc_lsb = get_ue_golomb_long(gb) + 4;
+ if (sps->log2_max_poc_lsb > 16) {
+ av_log(s->avctx, AV_LOG_ERROR, "log2_max_pic_order_cnt_lsb_minus4 out range: %d\n",
+ sps->log2_max_poc_lsb - 4);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+
+ sublayer_ordering_info = get_bits1(gb);
+ start = sublayer_ordering_info ? 0 : sps->max_sub_layers - 1;
+ for (i = start; i < sps->max_sub_layers; i++) {
+ sps->temporal_layer[i].max_dec_pic_buffering = get_ue_golomb_long(gb) + 1;
+ sps->temporal_layer[i].num_reorder_pics = get_ue_golomb_long(gb);
+ sps->temporal_layer[i].max_latency_increase = get_ue_golomb_long(gb) - 1;
+ if (sps->temporal_layer[i].max_dec_pic_buffering > MAX_DPB_SIZE) {
+ av_log(s->avctx, AV_LOG_ERROR, "sps_max_dec_pic_buffering_minus1 out of range: %d\n",
+ sps->temporal_layer[i].max_dec_pic_buffering - 1);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ if (sps->temporal_layer[i].num_reorder_pics > sps->temporal_layer[i].max_dec_pic_buffering - 1) {
+ av_log(s->avctx, AV_LOG_ERROR, "sps_max_num_reorder_pics out of range: %d\n",
+ sps->temporal_layer[i].num_reorder_pics);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ }
+
+ if (!sublayer_ordering_info) {
+ for (i = 0; i < start; i++){
+ sps->temporal_layer[i].max_dec_pic_buffering = sps->temporal_layer[start].max_dec_pic_buffering;
+ sps->temporal_layer[i].num_reorder_pics = sps->temporal_layer[start].num_reorder_pics;
+ sps->temporal_layer[i].max_latency_increase = sps->temporal_layer[start].max_latency_increase;
+ }
+ }
+
+ sps->log2_min_cb_size = get_ue_golomb_long(gb) + 3;
+ sps->log2_diff_max_min_coding_block_size = get_ue_golomb_long(gb);
+ sps->log2_min_tb_size = get_ue_golomb_long(gb) + 2;
+ log2_diff_max_min_transform_block_size = get_ue_golomb_long(gb);
+ sps->log2_max_trafo_size = log2_diff_max_min_transform_block_size + sps->log2_min_tb_size;
+
+ if (sps->log2_min_tb_size >= sps->log2_min_cb_size) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid value for log2_min_tb_size");
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ sps->max_transform_hierarchy_depth_inter = get_ue_golomb_long(gb);
+ sps->max_transform_hierarchy_depth_intra = get_ue_golomb_long(gb);
+
+ sps->scaling_list_enable_flag = get_bits1(gb);
+ if (sps->scaling_list_enable_flag) {
+ set_default_scaling_list_data(&sps->scaling_list);
+
+ if (get_bits1(gb)) {
+ ret = scaling_list_data(s, &sps->scaling_list);
+ if (ret < 0)
+ goto err;
+ }
+ }
+
+ sps->amp_enabled_flag = get_bits1(gb);
+ sps->sao_enabled = get_bits1(gb);
+
+ sps->pcm_enabled_flag = get_bits1(gb);
+ if (sps->pcm_enabled_flag) {
+ sps->pcm.bit_depth = get_bits(gb, 4) + 1;
+ sps->pcm.bit_depth_chroma = get_bits(gb, 4) + 1;
+ sps->pcm.log2_min_pcm_cb_size = get_ue_golomb_long(gb) + 3;
+ sps->pcm.log2_max_pcm_cb_size = sps->pcm.log2_min_pcm_cb_size +
+ get_ue_golomb_long(gb);
+ if (sps->pcm.bit_depth > sps->bit_depth) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "PCM bit depth (%d) is greater than normal bit depth (%d)\n",
+ sps->pcm.bit_depth, sps->bit_depth);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+
+ sps->pcm.loop_filter_disable_flag = get_bits1(gb);
+ }
+
+ sps->nb_st_rps = get_ue_golomb_long(gb);
+ if (sps->nb_st_rps > MAX_SHORT_TERM_RPS_COUNT) {
+ av_log(s->avctx, AV_LOG_ERROR, "Too many short term RPS: %d.\n",
+ sps->nb_st_rps);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ for (i = 0; i < sps->nb_st_rps; i++) {
+ if ((ret = ff_hevc_decode_short_term_rps(s, &sps->st_rps[i],
+ sps, 0)) < 0)
+ goto err;
+ }
+
+ sps->long_term_ref_pics_present_flag = get_bits1(gb);
+ if (sps->long_term_ref_pics_present_flag) {
+ sps->num_long_term_ref_pics_sps = get_ue_golomb_long(gb);
+ for (i = 0; i < sps->num_long_term_ref_pics_sps; i++) {
+ sps->lt_ref_pic_poc_lsb_sps[i] = get_bits(gb, sps->log2_max_poc_lsb);
+ sps->used_by_curr_pic_lt_sps_flag[i] = get_bits1(gb);
+ }
+ }
+
+ sps->sps_temporal_mvp_enabled_flag = get_bits1(gb);
+ sps->sps_strong_intra_smoothing_enable_flag = get_bits1(gb);
+ sps->vui.sar = (AVRational){0, 1};
+ vui_present = get_bits1(gb);
+ if (vui_present)
+ decode_vui(s, sps);
+ skip_bits1(gb); // sps_extension_flag
+
+ if (s->strict_def_disp_win) {
+ sps->output_window.left_offset += sps->vui.def_disp_win.left_offset;
+ sps->output_window.right_offset += sps->vui.def_disp_win.right_offset;
+ sps->output_window.top_offset += sps->vui.def_disp_win.top_offset;
+ sps->output_window.bottom_offset += sps->vui.def_disp_win.bottom_offset;
+ }
+ if (sps->output_window.left_offset & (0x1F >> (sps->pixel_shift)) &&
+ !(s->avctx->flags & CODEC_FLAG_UNALIGNED)) {
+ sps->output_window.left_offset &= ~(0x1F >> (sps->pixel_shift));
+ av_log(s->avctx, AV_LOG_WARNING, "Reducing left output window to %d "
+ "chroma samples to preserve alignment.\n",
+ sps->output_window.left_offset);
+ }
+ sps->output_width = sps->width -
+ (sps->output_window.left_offset + sps->output_window.right_offset);
+ sps->output_height = sps->height -
+ (sps->output_window.top_offset + sps->output_window.bottom_offset);
+ if (sps->output_width <= 0 || sps->output_height <= 0) {
+ av_log(s->avctx, AV_LOG_WARNING, "Invalid visible frame dimensions: %dx%d.\n",
+ sps->output_width, sps->output_height);
+ if (s->avctx->err_recognition & AV_EF_EXPLODE) {
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ av_log(s->avctx, AV_LOG_WARNING, "Displaying the whole video surface.\n");
+ sps->pic_conf_win.left_offset =
+ sps->pic_conf_win.right_offset =
+ sps->pic_conf_win.top_offset =
+ sps->pic_conf_win.bottom_offset = 0;
+ sps->output_width = sps->width;
+ sps->output_height = sps->height;
+ }
+
+ // Inferred parameters
+ sps->log2_ctb_size = sps->log2_min_cb_size
+ + sps->log2_diff_max_min_coding_block_size;
+ sps->log2_min_pu_size = sps->log2_min_cb_size - 1;
+
+ sps->ctb_width = (sps->width + (1 << sps->log2_ctb_size) - 1) >> sps->log2_ctb_size;
+ sps->ctb_height = (sps->height + (1 << sps->log2_ctb_size) - 1) >> sps->log2_ctb_size;
+ sps->ctb_size = sps->ctb_width * sps->ctb_height;
+
+ sps->min_cb_width = sps->width >> sps->log2_min_cb_size;
+ sps->min_cb_height = sps->height >> sps->log2_min_cb_size;
+ sps->min_tb_width = sps->width >> sps->log2_min_tb_size;
+ 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->qp_bd_offset = 6 * (sps->bit_depth - 8);
+
+ if (sps->width & ((1 << sps->log2_min_cb_size) - 1) ||
+ sps->height & ((1 << sps->log2_min_cb_size) - 1)) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid coded frame dimensions.\n");
+ goto err;
+ }
+
+ if (sps->log2_ctb_size > MAX_LOG2_CTB_SIZE) {
+ av_log(s->avctx, AV_LOG_ERROR, "CTB size out of range: 2^%d\n", sps->log2_ctb_size);
+ goto err;
+ }
+ if (sps->max_transform_hierarchy_depth_inter > sps->log2_ctb_size - sps->log2_min_tb_size) {
+ av_log(s->avctx, AV_LOG_ERROR, "max_transform_hierarchy_depth_inter out of range: %d\n",
+ sps->max_transform_hierarchy_depth_inter);
+ goto err;
+ }
+ if (sps->max_transform_hierarchy_depth_intra > sps->log2_ctb_size - sps->log2_min_tb_size) {
+ av_log(s->avctx, AV_LOG_ERROR, "max_transform_hierarchy_depth_intra out of range: %d\n",
+ sps->max_transform_hierarchy_depth_intra);
+ goto err;
+ }
+ if (sps->log2_max_trafo_size > FFMIN(sps->log2_ctb_size, 5)) {
+ av_log(s->avctx, AV_LOG_ERROR, "max transform block size out of range: %d\n",
+ sps->log2_max_trafo_size);
+ goto err;
+ }
+
+ if (s->avctx->debug & FF_DEBUG_BITSTREAM) {
+ av_log(s->avctx, AV_LOG_DEBUG, "Parsed SPS: id %d; coded wxh: %dx%d; "
+ "cropped wxh: %dx%d; pix_fmt: %s.\n",
+ sps_id, sps->width, sps->height,
+ sps->output_width, sps->output_height,
+ av_get_pix_fmt_name(sps->pix_fmt));
+ }
+
+ /* check if this is a repeat of an already parsed SPS, then keep the
+ * original one.
+ * otherwise drop all PPSes that depend on it */
+ if (s->sps_list[sps_id] &&
+ !memcmp(s->sps_list[sps_id]->data, sps_buf->data, sps_buf->size)) {
+ av_buffer_unref(&sps_buf);
+ } else {
+ for (i = 0; i < FF_ARRAY_ELEMS(s->pps_list); i++) {
+ if (s->pps_list[i] && ((HEVCPPS*)s->pps_list[i]->data)->sps_id == sps_id)
+ av_buffer_unref(&s->pps_list[i]);
+ }
+ av_buffer_unref(&s->sps_list[sps_id]);
+ s->sps_list[sps_id] = sps_buf;
+ }
+
+ return 0;
+err:
+
+ av_buffer_unref(&sps_buf);
+ return ret;
+}
+
+static void hevc_pps_free(void *opaque, uint8_t *data)
+{
+ HEVCPPS *pps = (HEVCPPS*)data;
+
+ av_freep(&pps->column_width);
+ av_freep(&pps->row_height);
+ av_freep(&pps->col_bd);
+ av_freep(&pps->row_bd);
+ av_freep(&pps->col_idxX);
+ av_freep(&pps->ctb_addr_rs_to_ts);
+ av_freep(&pps->ctb_addr_ts_to_rs);
+ av_freep(&pps->tile_pos_rs);
+ av_freep(&pps->tile_id);
+ av_freep(&pps->min_cb_addr_zs);
+ av_freep(&pps->min_tb_addr_zs);
+
+ av_freep(&pps);
+}
+
+int ff_hevc_decode_nal_pps(HEVCContext *s)
+{
+ GetBitContext *gb = &s->HEVClc->gb;
+ HEVCSPS *sps = NULL;
+ int pic_area_in_ctbs, pic_area_in_min_cbs, pic_area_in_min_tbs;
+ int log2_diff_ctb_min_tb_size;
+ int i, j, x, y, ctb_addr_rs, tile_id;
+ int ret = 0;
+ int pps_id = 0;
+
+ AVBufferRef *pps_buf;
+ HEVCPPS *pps = av_mallocz(sizeof(*pps));
+
+ if (!pps)
+ return AVERROR(ENOMEM);
+
+ pps_buf = av_buffer_create((uint8_t*)pps, sizeof(*pps), hevc_pps_free, NULL, 0);
+ if (!pps_buf) {
+ av_freep(&pps);
+ return AVERROR(ENOMEM);
+ }
+
+ av_log(s->avctx, AV_LOG_DEBUG, "Decoding PPS\n");
+
+ // Default values
+ pps->loop_filter_across_tiles_enabled_flag = 1;
+ pps->num_tile_columns = 1;
+ pps->num_tile_rows = 1;
+ pps->uniform_spacing_flag = 1;
+ pps->disable_dbf = 0;
+ pps->beta_offset = 0;
+ pps->tc_offset = 0;
+
+ // Coded parameters
+ pps_id = get_ue_golomb_long(gb);
+ if (pps_id >= MAX_PPS_COUNT) {
+ av_log(s->avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", pps_id);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ pps->sps_id = get_ue_golomb_long(gb);
+ if (pps->sps_id >= MAX_SPS_COUNT) {
+ av_log(s->avctx, AV_LOG_ERROR, "SPS id out of range: %d\n", pps->sps_id);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ if (!s->sps_list[pps->sps_id]) {
+ av_log(s->avctx, AV_LOG_ERROR, "SPS does not exist \n");
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ sps = (HEVCSPS*)s->sps_list[pps->sps_id]->data;
+
+ pps->dependent_slice_segments_enabled_flag = get_bits1(gb);
+ pps->output_flag_present_flag = get_bits1(gb);
+ pps->num_extra_slice_header_bits = get_bits(gb, 3);
+
+ pps->sign_data_hiding_flag = get_bits1(gb);
+
+ pps->cabac_init_present_flag = get_bits1(gb);
+
+ pps->num_ref_idx_l0_default_active = get_ue_golomb_long(gb) + 1;
+ pps->num_ref_idx_l1_default_active = get_ue_golomb_long(gb) + 1;
+
+ pps->pic_init_qp_minus26 = get_se_golomb(gb);
+
+ pps->constrained_intra_pred_flag = get_bits1(gb);
+ pps->transform_skip_enabled_flag = get_bits1(gb);
+
+ pps->cu_qp_delta_enabled_flag = get_bits1(gb);
+ pps->diff_cu_qp_delta_depth = 0;
+ if (pps->cu_qp_delta_enabled_flag)
+ pps->diff_cu_qp_delta_depth = get_ue_golomb_long(gb);
+
+ pps->cb_qp_offset = get_se_golomb(gb);
+ if (pps->cb_qp_offset < -12 || pps->cb_qp_offset > 12) {
+ av_log(s->avctx, AV_LOG_ERROR, "pps_cb_qp_offset out of range: %d\n",
+ pps->cb_qp_offset);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ pps->cr_qp_offset = get_se_golomb(gb);
+ if (pps->cr_qp_offset < -12 || pps->cr_qp_offset > 12) {
+ av_log(s->avctx, AV_LOG_ERROR, "pps_cr_qp_offset out of range: %d\n",
+ pps->cr_qp_offset);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ pps->pic_slice_level_chroma_qp_offsets_present_flag = get_bits1(gb);
+
+ pps->weighted_pred_flag = get_bits1(gb);
+ pps->weighted_bipred_flag = get_bits1(gb);
+
+ pps->transquant_bypass_enable_flag = get_bits1(gb);
+ pps->tiles_enabled_flag = get_bits1(gb);
+ pps->entropy_coding_sync_enabled_flag = get_bits1(gb);
+
+ if (pps->tiles_enabled_flag) {
+ pps->num_tile_columns = get_ue_golomb_long(gb) + 1;
+ pps->num_tile_rows = get_ue_golomb_long(gb) + 1;
+ if (pps->num_tile_columns == 0 ||
+ pps->num_tile_columns >= sps->width) {
+ av_log(s->avctx, AV_LOG_ERROR, "num_tile_columns_minus1 out of range: %d\n",
+ pps->num_tile_columns - 1);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ if (pps->num_tile_rows == 0 ||
+ pps->num_tile_rows >= sps->height) {
+ av_log(s->avctx, AV_LOG_ERROR, "num_tile_rows_minus1 out of range: %d\n",
+ pps->num_tile_rows - 1);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+
+ pps->column_width = av_malloc_array(pps->num_tile_columns, sizeof(*pps->column_width));
+ pps->row_height = av_malloc_array(pps->num_tile_rows, sizeof(*pps->row_height));
+ if (!pps->column_width || !pps->row_height) {
+ ret = AVERROR(ENOMEM);
+ goto err;
+ }
+
+ pps->uniform_spacing_flag = get_bits1(gb);
+ if (!pps->uniform_spacing_flag) {
+ int sum = 0;
+ for (i = 0; i < pps->num_tile_columns - 1; i++) {
+ pps->column_width[i] = get_ue_golomb_long(gb) + 1;
+ sum += pps->column_width[i];
+ }
+ if (sum >= sps->ctb_width) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid tile widths.\n");
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ pps->column_width[pps->num_tile_columns - 1] = sps->ctb_width - sum;
+
+ sum = 0;
+ for (i = 0; i < pps->num_tile_rows - 1; i++) {
+ pps->row_height[i] = get_ue_golomb_long(gb) + 1;
+ sum += pps->row_height[i];
+ }
+ if (sum >= sps->ctb_height) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid tile heights.\n");
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ pps->row_height[pps->num_tile_rows - 1] = sps->ctb_height - sum;
+ }
+ pps->loop_filter_across_tiles_enabled_flag = get_bits1(gb);
+ }
+
+ pps->seq_loop_filter_across_slices_enabled_flag = get_bits1(gb);
+
+ pps->deblocking_filter_control_present_flag = get_bits1(gb);
+ if (pps->deblocking_filter_control_present_flag) {
+ pps->deblocking_filter_override_enabled_flag = get_bits1(gb);
+ pps->disable_dbf = get_bits1(gb);
+ if (!pps->disable_dbf) {
+ pps->beta_offset = get_se_golomb(gb) * 2;
+ pps->tc_offset = get_se_golomb(gb) * 2;
+ if (pps->beta_offset/2 < -6 || pps->beta_offset/2 > 6) {
+ av_log(s->avctx, AV_LOG_ERROR, "pps_beta_offset_div2 out of range: %d\n",
+ pps->beta_offset/2);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ if (pps->tc_offset/2 < -6 || pps->tc_offset/2 > 6) {
+ av_log(s->avctx, AV_LOG_ERROR, "pps_tc_offset_div2 out of range: %d\n",
+ pps->tc_offset/2);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+ }
+ }
+
+ pps->pps_scaling_list_data_present_flag = get_bits1(gb);
+ if (pps->pps_scaling_list_data_present_flag) {
+ set_default_scaling_list_data(&pps->scaling_list);
+ ret = scaling_list_data(s, &pps->scaling_list);
+ if (ret < 0)
+ goto err;
+ }
+ pps->lists_modification_present_flag = get_bits1(gb);
+ pps->log2_parallel_merge_level = get_ue_golomb_long(gb) + 2;
+ if (pps->log2_parallel_merge_level > sps->log2_ctb_size) {
+ av_log(s->avctx, AV_LOG_ERROR, "log2_parallel_merge_level_minus2 out of range: %d\n",
+ pps->log2_parallel_merge_level - 2);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+
+ pps->slice_header_extension_present_flag = get_bits1(gb);
+ pps->pps_extension_flag = get_bits1(gb);
+
+ // Inferred parameters
+ pps->col_bd = av_malloc_array(pps->num_tile_columns + 1, sizeof(*pps->col_bd));
+ pps->row_bd = av_malloc_array(pps->num_tile_rows + 1, sizeof(*pps->row_bd));
+ pps->col_idxX = av_malloc_array(sps->ctb_width, sizeof(*pps->col_idxX));
+ if (!pps->col_bd || !pps->row_bd || !pps->col_idxX) {
+ ret = AVERROR(ENOMEM);
+ goto err;
+ }
+
+ if (pps->uniform_spacing_flag) {
+ if (!pps->column_width) {
+ pps->column_width = av_malloc_array(pps->num_tile_columns, sizeof(*pps->column_width));
+ pps->row_height = av_malloc_array(pps->num_tile_rows, sizeof(*pps->row_height));
+ }
+ if (!pps->column_width || !pps->row_height) {
+ ret = AVERROR(ENOMEM);
+ goto err;
+ }
+
+ for (i = 0; i < pps->num_tile_columns; i++) {
+ pps->column_width[i] = ((i + 1) * sps->ctb_width) / pps->num_tile_columns -
+ (i * sps->ctb_width) / pps->num_tile_columns;
+ }
+
+ for (i = 0; i < pps->num_tile_rows; i++) {
+ pps->row_height[i] = ((i + 1) * sps->ctb_height) / pps->num_tile_rows -
+ (i * sps->ctb_height) / pps->num_tile_rows;
+ }
+ }
+
+ pps->col_bd[0] = 0;
+ for (i = 0; i < pps->num_tile_columns; i++)
+ pps->col_bd[i + 1] = pps->col_bd[i] + pps->column_width[i];
+
+ pps->row_bd[0] = 0;
+ for (i = 0; i < pps->num_tile_rows; i++)
+ pps->row_bd[i + 1] = pps->row_bd[i] + pps->row_height[i];
+
+ for (i = 0, j = 0; i < sps->ctb_width; i++) {
+ if (i > pps->col_bd[j])
+ j++;
+ pps->col_idxX[i] = j;
+ }
+
+ /**
+ * 6.5
+ */
+ pic_area_in_ctbs = sps->ctb_width * sps->ctb_height;
+ pic_area_in_min_cbs = sps->min_cb_width * sps->min_cb_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_cb_addr_zs = av_malloc_array(pic_area_in_min_cbs, sizeof(*pps->min_cb_addr_zs));
+ pps->min_tb_addr_zs = av_malloc_array(pic_area_in_min_tbs, sizeof(*pps->min_tb_addr_zs));
+ if (!pps->ctb_addr_rs_to_ts || !pps->ctb_addr_ts_to_rs ||
+ !pps->tile_id || !pps->min_cb_addr_zs || !pps->min_tb_addr_zs) {
+ ret = AVERROR(ENOMEM);
+ goto err;
+ }
+
+ for (ctb_addr_rs = 0; ctb_addr_rs < pic_area_in_ctbs; ctb_addr_rs++) {
+ int tb_x = ctb_addr_rs % sps->ctb_width;
+ int tb_y = ctb_addr_rs / sps->ctb_width;
+ int tile_x = 0;
+ int tile_y = 0;
+ int val = 0;
+
+ for (i = 0; i < pps->num_tile_columns; i++) {
+ if (tb_x < pps->col_bd[i + 1]) {
+ tile_x = i;
+ break;
+ }
+ }
+
+ for (i = 0; i < pps->num_tile_rows; i++) {
+ if (tb_y < pps->row_bd[i + 1]) {
+ tile_y = i;
+ break;
+ }
+ }
+
+ for (i = 0; i < tile_x; i++ )
+ val += pps->row_height[tile_y] * pps->column_width[i];
+ for (i = 0; i < tile_y; i++ )
+ val += sps->ctb_width * pps->row_height[i];
+
+ val += (tb_y - pps->row_bd[tile_y]) * pps->column_width[tile_x] +
+ tb_x - pps->col_bd[tile_x];
+
+ pps->ctb_addr_rs_to_ts[ctb_addr_rs] = val;
+ pps->ctb_addr_ts_to_rs[val] = ctb_addr_rs;
+ }
+
+ for (j = 0, tile_id = 0; j < pps->num_tile_rows; j++)
+ for (i = 0; i < pps->num_tile_columns; i++, tile_id++)
+ for (y = pps->row_bd[j]; y < pps->row_bd[j + 1]; y++)
+ for (x = pps->col_bd[i]; x < pps->col_bd[i + 1]; x++)
+ pps->tile_id[pps->ctb_addr_rs_to_ts[y * sps->ctb_width + x]] = tile_id;
+
+ pps->tile_pos_rs = av_malloc_array(tile_id, sizeof(*pps->tile_pos_rs));
+ if (!pps->tile_pos_rs) {
+ ret = AVERROR(ENOMEM);
+ goto err;
+ }
+
+ for (j = 0; j < pps->num_tile_rows; j++)
+ for (i = 0; i < pps->num_tile_columns; i++)
+ pps->tile_pos_rs[j * pps->num_tile_columns + i] = pps->row_bd[j] * sps->ctb_width + pps->col_bd[i];
+
+ for (y = 0; y < sps->min_cb_height; y++) {
+ for (x = 0; x < sps->min_cb_width; x++) {
+ int tb_x = x >> sps->log2_diff_max_min_coding_block_size;
+ int tb_y = y >> sps->log2_diff_max_min_coding_block_size;
+ int ctb_addr_rs = sps->ctb_width * tb_y + tb_x;
+ int val = pps->ctb_addr_rs_to_ts[ctb_addr_rs] <<
+ (sps->log2_diff_max_min_coding_block_size * 2);
+ for (i = 0; i < sps->log2_diff_max_min_coding_block_size; i++) {
+ int m = 1 << i;
+ val += (m & x ? m * m : 0) + (m & y ? 2 * m * m : 0);
+ }
+ pps->min_cb_addr_zs[y * sps->min_cb_width + x] = val;
+ }
+ }
+
+ 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++) {
+ 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;
+ int val = pps->ctb_addr_rs_to_ts[ctb_addr_rs] <<
+ (log2_diff_ctb_min_tb_size * 2);
+ for (i = 0; i < log2_diff_ctb_min_tb_size; i++) {
+ 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;
+ }
+ }
+
+ av_buffer_unref(&s->pps_list[pps_id]);
+ s->pps_list[pps_id] = pps_buf;
+
+ return 0;
+
+err:
+ av_buffer_unref(&pps_buf);
+ return ret;
+}
diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c
new file mode 100644
index 0000000..6bdd37e
--- a/dev/null
+++ b/libavcodec/hevc_refs.c
@@ -0,0 +1,484 @@
+/*
+ * HEVC video Decoder
+ *
+ * Copyright (C) 2012 - 2013 Guillaume Martres
+ * Copyright (C) 2012 - 2013 Gildas Cocherel
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/pixdesc.h"
+
+#include "hevc.h"
+#include "internal.h"
+#include "thread.h"
+
+void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags)
+{
+ /* frame->frame can be NULL if context init failed */
+ if (!frame->frame || !frame->frame->buf[0])
+ return;
+
+ frame->flags &= ~flags;
+ if (!frame->flags) {
+ ff_thread_release_buffer(s->avctx, &frame->tf);
+
+ av_buffer_unref(&frame->tab_mvf_buf);
+ frame->tab_mvf = NULL;
+
+ av_buffer_unref(&frame->rpl_buf);
+ av_buffer_unref(&frame->rpl_tab_buf);
+ frame->rpl_tab = NULL;
+ frame->refPicList = NULL;
+
+ frame->collocated_ref = NULL;
+ }
+}
+
+RefPicList* ff_hevc_get_ref_list(HEVCContext *s, HEVCFrame *ref, int x0, int y0)
+{
+ if (x0 < 0 || y0 < 0) {
+ return s->ref->refPicList;
+ } else {
+ 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 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];
+ }
+}
+
+void ff_hevc_clear_refs(HEVCContext *s)
+{
+ int i;
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++)
+ ff_hevc_unref_frame(s, &s->DPB[i],
+ HEVC_FRAME_FLAG_SHORT_REF | HEVC_FRAME_FLAG_LONG_REF);
+}
+
+void ff_hevc_flush_dpb(HEVCContext *s)
+{
+ int i;
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++)
+ ff_hevc_unref_frame(s, &s->DPB[i], ~0);
+}
+
+static HEVCFrame *alloc_frame(HEVCContext *s)
+{
+ int i, j, ret;
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
+ HEVCFrame *frame = &s->DPB[i];
+ if (frame->frame->buf[0])
+ continue;
+
+ ret = ff_thread_get_buffer(s->avctx, &frame->tf, AV_GET_BUFFER_FLAG_REF);
+ if (ret < 0)
+ return NULL;
+
+ frame->rpl_buf = av_buffer_allocz(s->nb_nals * sizeof(RefPicListTab));
+ if (!frame->rpl_buf)
+ goto fail;
+
+ frame->tab_mvf_buf = av_buffer_pool_get(s->tab_mvf_pool);
+ if (!frame->tab_mvf_buf)
+ goto fail;
+ frame->tab_mvf = (MvField*)frame->tab_mvf_buf->data;
+
+ frame->rpl_tab_buf = av_buffer_pool_get(s->rpl_tab_pool);
+ if (!frame->rpl_tab_buf)
+ goto fail;
+ frame->rpl_tab = (RefPicListTab**)frame->rpl_tab_buf->data;
+ frame->ctb_count = s->sps->ctb_width * s->sps->ctb_height;
+ for (j = 0; j < frame->ctb_count; j++)
+ frame->rpl_tab[j] = (RefPicListTab*)frame->rpl_buf->data;
+
+ return frame;
+fail:
+ ff_hevc_unref_frame(s, frame, ~0);
+ return NULL;
+ }
+ av_log(s->avctx, AV_LOG_ERROR, "Error allocating frame, DPB full.\n");
+ return NULL;
+}
+
+int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, int poc)
+{
+ HEVCFrame *ref;
+ int i;
+
+ /* check that this POC doesn't already exist */
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
+ HEVCFrame *frame = &s->DPB[i];
+
+ if (frame->frame->buf[0] && frame->sequence == s->seq_decode &&
+ frame->poc == poc) {
+ av_log(s->avctx, AV_LOG_ERROR, "Duplicate POC in a sequence: %d.\n",
+ poc);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ ref = alloc_frame(s);
+ if (!ref)
+ return AVERROR(ENOMEM);
+
+ *frame = ref->frame;
+ s->ref = ref;
+ ref->poc = poc;
+
+ ref->flags = HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_SHORT_REF;
+ ref->sequence = s->seq_decode;
+ ref->window = s->sps->output_window;
+
+ return 0;
+}
+
+int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush)
+{
+ do {
+ int nb_output = 0;
+ int min_poc = INT_MAX;
+ int i, j, min_idx, ret;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
+ HEVCFrame *frame = &s->DPB[i];
+ if ((frame->flags & HEVC_FRAME_FLAG_OUTPUT) &&
+ frame->sequence == s->seq_output) {
+ nb_output++;
+ if (frame->poc < min_poc) {
+ min_poc = frame->poc;
+ min_idx = i;
+ }
+ }
+ }
+
+ /* wait for more frames before output */
+ if (!flush && s->seq_output == s->seq_decode && s->sps &&
+ nb_output <= s->sps->temporal_layer[s->sps->max_sub_layers - 1].num_reorder_pics)
+ return 0;
+
+ if (nb_output) {
+ HEVCFrame *frame = &s->DPB[min_idx];
+ 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);
+ ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT);
+ if (ret < 0)
+ return ret;
+
+ for (j = 0; j < 3; j++) {
+ int hshift = (j > 0) ? desc->log2_chroma_w : 0;
+ int vshift = (j > 0) ? desc->log2_chroma_h : 0;
+ int off = ((frame->window.left_offset >> hshift) << pixel_shift) +
+ (frame->window.top_offset >> vshift) * dst->linesize[j];
+ dst->data[j] += off;
+ }
+ av_log(s->avctx, AV_LOG_DEBUG, "Output frame with POC %d.\n", frame->poc);
+ return 1;
+ }
+
+ if (s->seq_output != s->seq_decode)
+ s->seq_output = (s->seq_output + 1) & 0xff;
+ else
+ break;
+ } while (1);
+
+ return 0;
+}
+
+static int init_slice_rpl(HEVCContext *s)
+{
+ HEVCFrame *frame = s->ref;
+ int ctb_count = frame->ctb_count;
+ int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[s->sh.slice_segment_addr];
+ int i;
+
+ if (s->slice_idx >= frame->rpl_buf->size / sizeof(RefPicListTab))
+ return AVERROR_INVALIDDATA;
+
+ for (i = ctb_addr_ts; i < ctb_count; i++)
+ frame->rpl_tab[i] = (RefPicListTab*)frame->rpl_buf->data + s->slice_idx;
+
+ frame->refPicList = (RefPicList*)frame->rpl_tab[ctb_addr_ts];
+
+ return 0;
+}
+
+int ff_hevc_slice_rpl(HEVCContext *s)
+{
+ SliceHeader *sh = &s->sh;
+
+ uint8_t nb_list = sh->slice_type == B_SLICE ? 2 : 1;
+ uint8_t list_idx;
+ int i, j, ret;
+
+ ret = init_slice_rpl(s);
+ if (ret < 0)
+ return ret;
+
+ if (!(s->rps[ST_CURR_BEF].nb_refs + s->rps[ST_CURR_AFT].nb_refs +
+ s->rps[LT_CURR].nb_refs)) {
+ av_log(s->avctx, AV_LOG_ERROR, "Zero refs in the frame RPS.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (list_idx = 0; list_idx < nb_list; list_idx++) {
+ RefPicList rpl_tmp = { { 0 } };
+ RefPicList *rpl = &s->ref->refPicList[list_idx];
+
+ /* The order of the elements is
+ * ST_CURR_BEF - ST_CURR_AFT - LT_CURR for the L0 and
+ * ST_CURR_AFT - ST_CURR_BEF - LT_CURR for the L1
+ */
+ int cand_lists[3] = { list_idx ? ST_CURR_AFT : ST_CURR_BEF,
+ list_idx ? ST_CURR_BEF : ST_CURR_AFT,
+ LT_CURR };
+
+ /* concatenate the candidate lists for the current frame */
+ while (rpl_tmp.nb_refs < sh->nb_refs[list_idx]) {
+ for (i = 0; i < FF_ARRAY_ELEMS(cand_lists); i++) {
+ RefPicList *rps = &s->rps[cand_lists[i]];
+ for (j = 0; j < rps->nb_refs && rpl_tmp.nb_refs < MAX_REFS; j++) {
+ rpl_tmp.list[rpl_tmp.nb_refs] = rps->list[j];
+ rpl_tmp.ref[rpl_tmp.nb_refs] = rps->ref[j];
+ rpl_tmp.isLongTerm[rpl_tmp.nb_refs] = (i == 2);
+ rpl_tmp.nb_refs++;
+ }
+ }
+ }
+
+ /* reorder the references if necessary */
+ if (sh->rpl_modification_flag[list_idx]) {
+ for (i = 0; i < sh->nb_refs[list_idx]; i++) {
+ int idx = sh->list_entry_lx[list_idx][i];
+
+ if (idx >= rpl_tmp.nb_refs) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid reference index.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ rpl->list[i] = rpl_tmp.list[idx];
+ rpl->ref[i] = rpl_tmp.ref[idx];
+ rpl->isLongTerm[i] = rpl_tmp.isLongTerm[idx];
+ rpl->nb_refs++;
+ }
+ } else {
+ memcpy(rpl, &rpl_tmp, sizeof(*rpl));
+ rpl->nb_refs = FFMIN(rpl->nb_refs, sh->nb_refs[list_idx]);
+ }
+
+ if (sh->collocated_list == list_idx &&
+ sh->collocated_ref_idx < rpl->nb_refs)
+ s->ref->collocated_ref = rpl->ref[sh->collocated_ref_idx];
+ }
+
+ return 0;
+}
+
+static HEVCFrame *find_ref_idx(HEVCContext *s, int poc)
+{
+ int i;
+ int LtMask = (1 << s->sps->log2_max_poc_lsb) - 1;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
+ HEVCFrame *ref = &s->DPB[i];
+ if (ref->frame->buf[0] && (ref->sequence == s->seq_decode)) {
+ if ((ref->poc & LtMask) == poc)
+ return ref;
+ }
+ }
+
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
+ HEVCFrame *ref = &s->DPB[i];
+ if (ref->frame->buf[0] && (ref->sequence == s->seq_decode)) {
+ if (ref->poc == poc || (ref->poc & LtMask) == poc)
+ return ref;
+ }
+ }
+
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Could not find ref with POC %d\n", poc);
+ return NULL;
+}
+
+static void mark_ref(HEVCFrame *frame, int flag)
+{
+ frame->flags &= ~(HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF);
+ frame->flags |= flag;
+}
+
+static HEVCFrame *generate_missing_ref(HEVCContext *s, int poc)
+{
+ HEVCFrame *frame;
+ int i, x, y;
+
+
+ frame = alloc_frame(s);
+ if (!frame)
+ return NULL;
+
+ if (!s->sps->pixel_shift) {
+ for (i = 0; frame->frame->buf[i]; i++)
+ memset(frame->frame->buf[i]->data, 1 << (s->sps->bit_depth - 1),
+ frame->frame->buf[i]->size);
+ } else {
+ for (i = 0; frame->frame->data[i]; i++)
+ for (y = 0; y < (s->sps->height >> s->sps->vshift[i]); y++)
+ for (x = 0; x < (s->sps->width >> s->sps->hshift[i]); x++) {
+ AV_WN16(frame->frame->data[i] + y * frame->frame->linesize[i] + 2 * x,
+ 1 << (s->sps->bit_depth - 1));
+ }
+ }
+
+ frame->poc = poc;
+ frame->sequence = s->seq_decode;
+ frame->flags = 0;
+
+ if (s->threads_type == FF_THREAD_FRAME)
+ ff_thread_report_progress(&frame->tf, INT_MAX, 0);
+
+ return frame;
+}
+
+/* add a reference with the given poc to the list and mark it as used in DPB */
+static int add_candidate_ref(HEVCContext *s, RefPicList *list,
+ int poc, int ref_flag)
+{
+ HEVCFrame *ref = find_ref_idx(s, poc);
+
+ if (ref == s->ref)
+ return AVERROR_INVALIDDATA;
+
+ if (!ref) {
+ ref = generate_missing_ref(s, poc);
+ if (!ref)
+ return AVERROR(ENOMEM);
+ }
+
+ list->list[list->nb_refs] = ref->poc;
+ list->ref[list->nb_refs] = ref;
+ list->nb_refs++;
+
+ mark_ref(ref, ref_flag);
+ return 0;
+}
+
+int ff_hevc_frame_rps(HEVCContext *s)
+{
+ const ShortTermRPS *short_rps = s->sh.short_term_rps;
+ const LongTermRPS *long_rps = &s->sh.long_term_rps;
+ RefPicList *rps = s->rps;
+ int i, ret;
+
+ if (!short_rps) {
+ rps[0].nb_refs = rps[1].nb_refs = 0;
+ return 0;
+ }
+
+ /* clear the reference flags on all frames except the current one */
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
+ HEVCFrame *frame = &s->DPB[i];
+
+ if (frame == s->ref)
+ continue;
+
+ mark_ref(frame, 0);
+ }
+
+ for (i = 0; i < NB_RPS_TYPE; i++)
+ rps[i].nb_refs = 0;
+
+ /* add the short refs */
+ for (i = 0; i < short_rps->num_delta_pocs; i++) {
+ int poc = s->poc + short_rps->delta_poc[i];
+ int list;
+
+ if (!short_rps->used[i])
+ list = ST_FOLL;
+ else if (i < short_rps->num_negative_pics)
+ list = ST_CURR_BEF;
+ else
+ list = ST_CURR_AFT;
+
+ ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_SHORT_REF);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* add the long refs */
+ for (i = 0; i < long_rps->nb_refs; i++) {
+ int poc = long_rps->poc[i];
+ int list = long_rps->used[i] ? LT_CURR : LT_FOLL;
+
+ ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_LONG_REF);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* release any frames that are now unused */
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++)
+ ff_hevc_unref_frame(s, &s->DPB[i], 0);
+
+ return 0;
+}
+
+int ff_hevc_compute_poc(HEVCContext *s, int poc_lsb)
+{
+ int max_poc_lsb = 1 << s->sps->log2_max_poc_lsb;
+ int prev_poc_lsb = s->pocTid0 % max_poc_lsb;
+ int prev_poc_msb = s->pocTid0 - prev_poc_lsb;
+ int poc_msb;
+
+ if ((poc_lsb < prev_poc_lsb) && ((prev_poc_lsb - poc_lsb) >= max_poc_lsb / 2))
+ poc_msb = prev_poc_msb + max_poc_lsb;
+ else if ((poc_lsb > prev_poc_lsb) && ((poc_lsb - prev_poc_lsb) > (max_poc_lsb / 2)))
+ poc_msb = prev_poc_msb - max_poc_lsb;
+ else
+ poc_msb = prev_poc_msb;
+
+ // For BLA picture types, POCmsb is set to 0.
+ if (s->nal_unit_type == NAL_BLA_W_LP ||
+ s->nal_unit_type == NAL_BLA_W_RADL ||
+ s->nal_unit_type == NAL_BLA_N_LP)
+ poc_msb = 0;
+
+ return poc_msb + poc_lsb;
+}
+
+int ff_hevc_frame_nb_refs(HEVCContext *s)
+{
+ int ret = 0;
+ int i;
+ const ShortTermRPS *rps = s->sh.short_term_rps;
+ LongTermRPS *long_rps = &s->sh.long_term_rps;
+
+ if (rps) {
+ for (i = 0; i < rps->num_negative_pics; i++)
+ ret += !!rps->used[i];
+ for (; i < rps->num_delta_pocs; i++)
+ ret += !!rps->used[i];
+ }
+
+ if (long_rps) {
+ for (i = 0; i < long_rps->nb_refs; i++)
+ ret += !!long_rps->used[i];
+ }
+ return ret;
+}
diff --git a/libavcodec/hevc_sei.c b/libavcodec/hevc_sei.c
new file mode 100644
index 0000000..1a96447
--- a/dev/null
+++ b/libavcodec/hevc_sei.c
@@ -0,0 +1,129 @@
+/*
+ * HEVC Supplementary Enhancement Information messages
+ *
+ * Copyright (C) 2012 - 2013 Guillaume Martres
+ * Copyright (C) 2012 - 2013 Gildas Cocherel
+ * Copyright (C) 2013 Vittorio Giovara
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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 "golomb.h"
+
+static void decode_nal_sei_decoded_picture_hash(HEVCContext *s, int payload_size)
+{
+ int cIdx, i;
+ 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/*((s->sps->chroma_format_idc == 0) ? 1 : 3)*/; cIdx++ ) {
+ if ( hash_type == 0 ) {
+ s->is_md5 = 1;
+ for( i = 0; i < 16; i++) {
+ s->md5[cIdx][i] = get_bits(gb, 8);
+ }
+ } else if( hash_type == 1 ) {
+ // picture_crc = get_bits(gb, 16);
+ skip_bits(gb, 16);
+ } else if( hash_type == 2 ) {
+ // picture_checksum = get_bits(gb, 32);
+ skip_bits(gb, 32);
+ }
+ }
+}
+
+static void decode_nal_sei_frame_packing_arrangement(HEVCLocalContext *lc)
+{
+ GetBitContext *gb = &lc->gb;
+ int cancel, type, quincunx;
+
+ get_ue_golomb(gb); // frame_packing_arrangement_id
+ cancel = get_bits1(gb); // frame_packing_cancel_flag
+ if ( cancel == 0 )
+ {
+ type = get_bits(gb, 7); // frame_packing_arrangement_type
+ quincunx = get_bits1(gb); // quincunx_sampling_flag
+ skip_bits(gb, 6); // content_interpretation_type
+
+ // the following skips spatial_flipping_flag frame0_flipped_flag
+ // field_views_flag current_frame_is_frame0_flag
+ // frame0_self_contained_flag frame1_self_contained_flag
+ skip_bits(gb, 6);
+
+ if ( quincunx == 0 && type != 5 )
+ skip_bits(gb, 16); // frame[01]_grid_position_[xy]
+ skip_bits(gb, 8); // frame_packing_arrangement_reserved_byte
+ skip_bits1(gb); // frame_packing_arrangement_persistance_flag
+ }
+ skip_bits1(gb); // upsampled_aspect_ratio_flag
+}
+
+static int decode_nal_sei_message(HEVCContext *s)
+{
+ GetBitContext *gb = &s->HEVClc->gb;
+
+ int payload_type = 0;
+ int payload_size = 0;
+ int byte = 0xFF;
+ av_log(s->avctx, AV_LOG_DEBUG, "Decoding SEI\n");
+
+ while (byte == 0xFF) {
+ byte = get_bits(gb, 8);
+ payload_type += byte;
+ }
+ byte = 0xFF;
+ while (byte == 0xFF) {
+ byte = get_bits(gb, 8);
+ payload_size += byte;
+ }
+ if (s->nal_unit_type == NAL_SEI_PREFIX) {
+ if (payload_type == 256 /*&& s->decode_checksum_sei*/)
+ decode_nal_sei_decoded_picture_hash(s, payload_size);
+ else if (payload_type == 45)
+ decode_nal_sei_frame_packing_arrangement(s->HEVClc);
+ 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 /* && s->decode_checksum_sei */)
+ decode_nal_sei_decoded_picture_hash(s, payload_size);
+ else {
+ av_log(s->avctx, AV_LOG_DEBUG, "Skipped SUFFIX SEI %d\n", payload_type);
+ skip_bits(gb, 8*payload_size);
+ }
+ }
+ return 0;
+}
+
+static int more_rbsp_data(GetBitContext *gb)
+{
+ return get_bits_left(gb) > 0 && show_bits(gb, 8) != 0x80;
+}
+
+int ff_hevc_decode_nal_sei(HEVCContext *s)
+{
+ do {
+ decode_nal_sei_message(s);
+ } while (more_rbsp_data(&s->HEVClc->gb));
+ return 0;
+}
diff --git a/libavcodec/hevcdsp.c b/libavcodec/hevcdsp.c
new file mode 100644
index 0000000..5ea774e
--- a/dev/null
+++ b/libavcodec/hevcdsp.c
@@ -0,0 +1,192 @@
+/*
+ * 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
+ */
+
+#include "hevc.h"
+#include "hevcdsp.h"
+
+static const int8_t transform[32][32] = {
+ { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 },
+ { 90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 46, 38, 31, 22, 13, 4,
+ -4, -13, -22, -31, -38, -46, -54, -61, -67, -73, -78, -82, -85, -88, -90, -90 },
+ { 90, 87, 80, 70, 57, 43, 25, 9, -9, -25, -43, -57, -70, -80, -87, -90,
+ -90, -87, -80, -70, -57, -43, -25, -9, 9, 25, 43, 57, 70, 80, 87, 90 },
+ { 90, 82, 67, 46, 22, -4, -31, -54, -73, -85, -90, -88, -78, -61, -38, -13,
+ 13, 38, 61, 78, 88, 90, 85, 73, 54, 31, 4, -22, -46, -67, -82, -90 },
+ { 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89,
+ 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89 },
+ { 88, 67, 31, -13, -54, -82, -90, -78, -46, -4, 38, 73, 90, 85, 61, 22,
+ -22, -61, -85, -90, -73, -38, 4, 46, 78, 90, 82, 54, 13, -31, -67, -88 },
+ { 87, 57, 9, -43, -80, -90, -70, -25, 25, 70, 90, 80, 43, -9, -57, -87,
+ -87, -57, -9, 43, 80, 90, 70, 25, -25, -70, -90, -80, -43, 9, 57, 87 },
+ { 85, 46, -13, -67, -90, -73, -22, 38, 82, 88, 54, -4, -61, -90, -78, -31,
+ 31, 78, 90, 61, 4, -54, -88, -82, -38, 22, 73, 90, 67, 13, -46, -85 },
+ { 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83,
+ 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83 },
+ { 82, 22, -54, -90, -61, 13, 78, 85, 31, -46, -90, -67, 4, 73, 88, 38,
+ -38, -88, -73, -4, 67, 90, 46, -31, -85, -78, -13, 61, 90, 54, -22, -82 },
+ { 80, 9, -70, -87, -25, 57, 90, 43, -43, -90, -57, 25, 87, 70, -9, -80,
+ -80, -9, 70, 87, 25, -57, -90, -43, 43, 90, 57, -25, -87, -70, 9, 80 },
+ { 78, -4, -82, -73, 13, 85, 67, -22, -88, -61, 31, 90, 54, -38, -90, -46,
+ 46, 90, 38, -54, -90, -31, 61, 88, 22, -67, -85, -13, 73, 82, 4, -78 },
+ { 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75,
+ 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75 },
+ { 73, -31, -90, -22, 78, 67, -38, -90, -13, 82, 61, -46, -88, -4, 85, 54,
+ -54, -85, 4, 88, 46, -61, -82, 13, 90, 38, -67, -78, 22, 90, 31, -73 },
+ { 70, -43, -87, 9, 90, 25, -80, -57, 57, 80, -25, -90, -9, 87, 43, -70,
+ -70, 43, 87, -9, -90, -25, 80, 57, -57, -80, 25, 90, 9, -87, -43, 70 },
+ { 67, -54, -78, 38, 85, -22, -90, 4, 90, 13, -88, -31, 82, 46, -73, -61,
+ 61, 73, -46, -82, 31, 88, -13, -90, -4, 90, 22, -85, -38, 78, 54, -67 },
+ { 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64,
+ 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64 },
+ { 61, -73, -46, 82, 31, -88, -13, 90, -4, -90, 22, 85, -38, -78, 54, 67,
+ -67, -54, 78, 38, -85, -22, 90, 4, -90, 13, 88, -31, -82, 46, 73, -61 },
+ { 57, -80, -25, 90, -9, -87, 43, 70, -70, -43, 87, 9, -90, 25, 80, -57,
+ -57, 80, 25, -90, 9, 87, -43, -70, 70, 43, -87, -9, 90, -25, -80, 57 },
+ { 54, -85, -4, 88, -46, -61, 82, 13, -90, 38, 67, -78, -22, 90, -31, -73,
+ 73, 31, -90, 22, 78, -67, -38, 90, -13, -82, 61, 46, -88, 4, 85, -54 },
+ { 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50,
+ 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50 },
+ { 46, -90, 38, 54, -90, 31, 61, -88, 22, 67, -85, 13, 73, -82, 4, 78,
+ -78, -4, 82, -73, -13, 85, -67, -22, 88, -61, -31, 90, -54, -38, 90, -46 },
+ { 43, -90, 57, 25, -87, 70, 9, -80, 80, -9, -70, 87, -25, -57, 90, -43,
+ -43, 90, -57, -25, 87, -70, -9, 80, -80, 9, 70, -87, 25, 57, -90, 43 },
+ { 38, -88, 73, -4, -67, 90, -46, -31, 85, -78, 13, 61, -90, 54, 22, -82,
+ 82, -22, -54, 90, -61, -13, 78, -85, 31, 46, -90, 67, 4, -73, 88, -38 },
+ { 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36,
+ 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36 },
+ { 31, -78, 90, -61, 4, 54, -88, 82, -38, -22, 73, -90, 67, -13, -46, 85,
+ -85, 46, 13, -67, 90, -73, 22, 38, -82, 88, -54, -4, 61, -90, 78, -31 },
+ { 25, -70, 90, -80, 43, 9, -57, 87, -87, 57, -9, -43, 80, -90, 70, -25,
+ -25, 70, -90, 80, -43, -9, 57, -87, 87, -57, 9, 43, -80, 90, -70, 25 },
+ { 22, -61, 85, -90, 73, -38, -4, 46, -78, 90, -82, 54, -13, -31, 67, -88,
+ 88, -67, 31, 13, -54, 82, -90, 78, -46, 4, 38, -73, 90, -85, 61, -22 },
+ { 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18,
+ 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18 },
+ { 13, -38, 61, -78, 88, -90, 85, -73, 54, -31, 4, 22, -46, 67, -82, 90,
+ -90, 82, -67, 46, -22, -4, 31, -54, 73, -85, 90, -88, 78, -61, 38, -13 },
+ { 9, -25, 43, -57, 70, -80, 87, -90, 90, -87, 80, -70, 57, -43, 25, -9,
+ -9, 25, -43, 57, -70, 80, -87, 90, -90, 87, -80, 70, -57, 43, -25, 9 },
+ { 4, -13, 22, -31, 38, -46, 54, -61, 67, -73, 78, -82, 85, -88, 90, -90,
+ 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 },
+};
+
+#define BIT_DEPTH 8
+#include "hevcdsp_template.c"
+#undef BIT_DEPTH
+
+#define BIT_DEPTH 9
+#include "hevcdsp_template.c"
+#undef BIT_DEPTH
+
+#define BIT_DEPTH 10
+#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
+
+#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_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->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->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); \
+ hevcdsp->hevc_v_loop_filter_chroma = FUNC(hevc_v_loop_filter_chroma, 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);
+
+
+ switch (bit_depth) {
+ case 9:
+ HEVC_DSP(9);
+ break;
+ case 10:
+ HEVC_DSP(10);
+ break;
+ default:
+ HEVC_DSP(8);
+ break;
+ }
+}
diff --git a/libavcodec/hevcdsp.h b/libavcodec/hevcdsp.h
new file mode 100644
index 0000000..c6511b0
--- a/dev/null
+++ b/libavcodec/hevcdsp.h
@@ -0,0 +1,77 @@
+/*
+ * 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_HEVCDSP_H
+#define AVCODEC_HEVCDSP_H
+
+#include "get_bits.h"
+
+struct 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 (*hevc_h_loop_filter_luma)(uint8_t *_pix, ptrdiff_t _stride, int *_beta, int *_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, 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);
+ void (*hevc_v_loop_filter_chroma)(uint8_t *_pix, ptrdiff_t _stride, int *_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, 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, 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, uint8_t *_no_q);
+ void (*hevc_v_loop_filter_chroma_c)(uint8_t *_pix, ptrdiff_t _stride, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
+} HEVCDSPContext;
+
+void ff_hevc_dsp_init(HEVCDSPContext *hpc, int bit_depth);
+
+extern const int8_t ff_hevc_epel_filters[7][16];
+
+#endif /* AVCODEC_HEVCDSP_H */
diff --git a/libavcodec/hevcdsp_template.c b/libavcodec/hevcdsp_template.c
new file mode 100644
index 0000000..bda1dee
--- a/dev/null
+++ b/libavcodec/hevcdsp_template.c
@@ -0,0 +1,1338 @@
+/*
+ * 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
+ */
+
+#include "get_bits.h"
+#include "bit_depth_template.c"
+#include "hevcdsp.h"
+#include "hevc.h"
+
+#define SET(dst, x) (dst) = (x)
+#define SCALE(dst, x) (dst) = av_clip_int16(((x) + add) >> shift)
+#define ADD_AND_SCALE(dst, x) (dst) = av_clip_pixel((dst) + av_clip_int16(((x) + add) >> shift))
+
+static void FUNC(put_pcm)(uint8_t *_dst, ptrdiff_t _stride, int size,
+ GetBitContext *gb, int pcm_bit_depth)
+{
+ int x, y;
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+
+ for (y = 0; y < size; y++) {
+ for (x = 0; x < size; 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, ptrdiff_t _stride)
+{
+ int x, y;
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+
+ for (y = 0; y < 4; y++) {
+ for (x = 0; x < 4; x++) {
+ dst[x] += *coeffs;
+ coeffs++;
+ }
+ dst += stride;
+ }
+
+}
+
+static void FUNC(transquant_bypass8x8)(uint8_t *_dst, int16_t *coeffs, ptrdiff_t _stride)
+{
+ int x, y;
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+
+ for (y = 0; y < 8; y++) {
+ for (x = 0; x < 8; x++) {
+ dst[x] += *coeffs;
+ coeffs++;
+ }
+ dst += stride;
+ }
+}
+
+static void FUNC(transquant_bypass16x16)(uint8_t *_dst, int16_t *coeffs, ptrdiff_t _stride)
+{
+ int x, y;
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+
+ for (y = 0; y < 16; y++) {
+ for (x = 0; x < 16; x++) {
+ dst[x] += *coeffs;
+ coeffs++;
+ }
+ dst += stride;
+ }
+
+}
+
+static void FUNC(transquant_bypass32x32)(uint8_t *_dst, int16_t *coeffs, ptrdiff_t _stride)
+{
+ int x, y;
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+
+ for (y = 0; y < 32; y++) {
+ for (x = 0; x < 32; x++) {
+ dst[x] += *coeffs;
+ coeffs++;
+ }
+ dst += stride;
+ }
+}
+
+static void FUNC(transform_skip)(uint8_t *_dst, int16_t *coeffs, ptrdiff_t _stride)
+{
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+ int shift = 13 - BIT_DEPTH;
+#if BIT_DEPTH <= 13
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+ int x, y;
+
+ 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;
+ }
+}
+
+static void FUNC(transform_4x4_luma_add)(uint8_t *_dst, int16_t *coeffs, ptrdiff_t _stride)
+{
+#define TR_4x4_LUMA(dst, src, step, assign) \
+ do { \
+ int c0 = src[0*step] + src[2*step]; \
+ int c1 = src[2*step] + src[3*step]; \
+ int c2 = src[0*step] - src[3*step]; \
+ int c3 = 74 * src[1*step]; \
+ \
+ assign(dst[2*step], 74 * (src[0*step] - src[2*step] + src[3*step])); \
+ assign(dst[0*step], 29 * c0 + 55 * c1 + c3); \
+ assign(dst[1*step], 55 * c2 - 29 * c1 + c3); \
+ assign(dst[3*step], 55 * c0 + 29 * c2 - c3); \
+ } while (0)
+
+ int i;
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+ int shift = 7;
+ int add = 1 << (shift - 1);
+ int16_t *src = coeffs;
+
+ for (i = 0; i < 4; i++) {
+ TR_4x4_LUMA(src, src, 4, SCALE);
+ src++;
+ }
+
+ shift = 20 - BIT_DEPTH;
+ add = 1 << (shift - 1);
+ for (i = 0; i < 4; i++) {
+ TR_4x4_LUMA(dst, coeffs, 1, ADD_AND_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); \
+ } while (0)
+#define TR_4_1(dst, src) TR_4(dst, src, 4, 4, SCALE)
+#define TR_4_2(dst, src) TR_4(dst, src, 1, 1, ADD_AND_SCALE)
+
+static void FUNC(transform_4x4_add)(uint8_t *_dst, int16_t *coeffs, ptrdiff_t _stride)
+{
+ int i;
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+ int shift = 7;
+ int add = 1 << (shift - 1);
+ int16_t *src = coeffs;
+
+ for (i = 0; i < 4; i++) {
+ TR_4_1(src, src);
+ src++;
+ }
+
+ shift = 20 - BIT_DEPTH;
+ add = 1 << (shift - 1);
+ for (i = 0; i < 4; i++) {
+ TR_4_2(dst, coeffs);
+ 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]); \
+ } \
+ } 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]); \
+ } \
+ } 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]); \
+ } \
+ } while (0)
+
+#define TR_8_1(dst, src) TR_8(dst, src, 8, 8, SCALE)
+#define TR_16_1(dst, src) TR_16(dst, src, 16, 16, SCALE)
+#define TR_32_1(dst, src) TR_32(dst, src, 32, 32, SCALE)
+
+#define TR_8_2(dst, src) TR_8(dst, src, 1, 1, ADD_AND_SCALE)
+#define TR_16_2(dst, src) TR_16(dst, src, 1, 1, ADD_AND_SCALE)
+#define TR_32_2(dst, src) TR_32(dst, src, 1, 1, ADD_AND_SCALE)
+
+static void FUNC(transform_8x8_add)(uint8_t *_dst, int16_t *coeffs, ptrdiff_t _stride)
+{
+ int i;
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+ int shift = 7;
+ int add = 1 << (shift - 1);
+ int16_t *src = coeffs;
+
+ for (i = 0; i < 8; i++) {
+ TR_8_1(src, src);
+ src++;
+ }
+
+ shift = 20 - BIT_DEPTH;
+ add = 1 << (shift - 1);
+ for (i = 0; i < 8; i++) {
+ TR_8_2(dst, coeffs);
+ coeffs += 8;
+ dst += stride;
+ }
+}
+
+static void FUNC(transform_16x16_add)(uint8_t *_dst, int16_t *coeffs, ptrdiff_t _stride)
+{
+ int i;
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+ int shift = 7;
+ int add = 1 << (shift - 1);
+ int16_t *src = coeffs;
+
+ for (i = 0; i < 16; i++) {
+ TR_16_1(src, src);
+ src++;
+ }
+
+ shift = 20 - BIT_DEPTH;
+ add = 1 << (shift - 1);
+ for (i = 0; i < 16; i++) {
+ TR_16_2(dst, coeffs);
+ coeffs += 16;
+ dst += stride;
+ }
+}
+
+static void FUNC(transform_32x32_add)(uint8_t *_dst, int16_t *coeffs, ptrdiff_t _stride)
+{
+#define IT32x32_even(i,w) ( src[ 0*w] * transform[ 0][i] ) + ( src[16*w] * transform[16][i] )
+#define IT32x32_odd(i,w) ( src[ 8*w] * transform[ 8][i] ) + ( src[24*w] * transform[24][i] )
+#define IT16x16(i,w) ( src[ 4*w] * transform[ 4][i] ) + ( src[12*w] * transform[12][i] ) + ( src[20*w] * transform[20][i] ) + ( src[28*w] * transform[28][i] )
+#define IT8x8(i,w) ( src[ 2*w] * transform[ 2][i] ) + ( src[ 6*w] * transform[ 6][i] ) + ( src[10*w] * transform[10][i] ) + ( src[14*w] * transform[14][i] ) + \
+ ( src[18*w] * transform[18][i] ) + ( src[22*w] * transform[22][i] ) + ( src[26*w] * transform[26][i] ) + ( src[30*w] * transform[30][i] )
+#define IT4x4(i,w) ( src[ 1*w] * transform[ 1][i] ) + ( src[ 3*w] * transform[ 3][i] ) + ( src[ 5*w] * transform[ 5][i] ) + ( src[ 7*w] * transform[ 7][i] ) + \
+ ( src[ 9*w] * transform[ 9][i] ) + ( src[11*w] * transform[11][i] ) + ( src[13*w] * transform[13][i] ) + ( src[15*w] * transform[15][i] ) + \
+ ( src[17*w] * transform[17][i] ) + ( src[19*w] * transform[19][i] ) + ( src[21*w] * transform[21][i] ) + ( src[23*w] * transform[23][i] ) + \
+ ( src[25*w] * transform[25][i] ) + ( src[27*w] * transform[27][i] ) + ( src[29*w] * transform[29][i] ) + ( src[31*w] * transform[31][i] )
+ int i;
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+ int shift = 7;
+ int add = 1 << (shift - 1);
+ int16_t *src = coeffs;
+
+ for (i = 0; i < 32; i++) {
+ TR_32_1(src, src);
+ src++;
+ }
+ src = coeffs;
+ shift = 20 - BIT_DEPTH;
+ add = 1 << (shift - 1);
+ for (i = 0; i < 32; i++) {
+ TR_32_2(dst, coeffs);
+ coeffs += 32;
+ dst += stride;
+ }
+#undef IT32x32_even
+#undef IT32x32_odd
+#undef IT16x16
+#undef IT8x8
+#undef IT4x4
+}
+
+static void FUNC(sao_band_filter)(uint8_t *_dst, uint8_t *_src,
+ ptrdiff_t _stride, SAOParams *sao,
+ int *borders, int width, int height,
+ int c_idx, int class)
+{
+ pixel *dst = (pixel*)_dst;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+ int offset_table[32] = { 0 };
+ int k, y, x;
+ int chroma = !!c_idx;
+ int shift = BIT_DEPTH - 5;
+ int *sao_offset_val = sao->offset_val[c_idx];
+ int sao_left_class = sao->band_position[c_idx];
+ int init_y = 0, init_x = 0;
+
+ 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;
+ }
+
+ 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[av_clip_pixel(src[x] >> shift)]);
+ dst += stride;
+ src += stride;
+ }
+}
+
+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);
+}
+
+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_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 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);
+}
+
+static void FUNC(sao_edge_filter_0)(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)
+{
+ int x, y;
+ pixel *dst = (pixel*)_dst;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+ int chroma = !!c_idx;
+ int *sao_offset_val = sao->offset_val[c_idx];
+ int sao_eo_class = sao->eo_class[c_idx];
+
+ 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 init_x = 0, init_y = 0, width = _width, height = _height;
+
+#define CMP(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1))
+
+ if (!borders[2])
+ width -= (8 >> chroma) + 2;
+ if (!borders[3])
+ height -= (4 >> chroma) + 2;
+
+ 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;
+ }
+ init_x = 1;
+ }
+ if (borders[2]) {
+ int offset_val = sao_offset_val[0];
+ int x_stride = width - 1;
+ for (x = 0; x < height; x++) {
+ dst[x_stride] = av_clip_pixel(src[x_stride] + offset_val);
+ x_stride += stride;
+ }
+ width --;
+ }
+
+ }
+ 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--;
+ }
+ }
+ {
+ int y_stride = init_y * stride;
+ int pos_0_0 = pos[sao_eo_class][0][0];
+ int pos_0_1 = pos[sao_eo_class][0][1];
+ int pos_1_0 = pos[sao_eo_class][1][0];
+ int pos_1_1 = pos[sao_eo_class][1][1];
+
+ int y_stride_0_1 = (init_y + pos_0_1) * stride;
+ int y_stride_1_1 = (init_y + pos_1_1) * stride;
+ for (y = init_y; y < height; y++) {
+ for (x = init_x; x < width; x++) {
+ int diff0 = CMP(src[x + y_stride], src[x + pos_0_0 + y_stride_0_1]);
+ int diff1 = CMP(src[x + y_stride], src[x + pos_1_0 + y_stride_1_1]);
+ int offset_val = edge_idx[2 + diff0 + diff1];
+ dst[x + y_stride] = av_clip_pixel(src[x + y_stride] + sao_offset_val[offset_val]);
+ }
+ y_stride += stride;
+ y_stride_0_1 += stride;
+ y_stride_1_1 += stride;
+ }
+ }
+
+ {
+ // Restore pixels that can't be modified
+ int save_upper_left = !diag_edge && sao_eo_class == SAO_EO_135D && !borders[0] && !borders[1];
+ if (vert_edge && sao_eo_class != SAO_EO_VERT)
+ for (y = init_y+save_upper_left; y< height; y++)
+ dst[y*stride] = src[y*stride];
+ if(horiz_edge && sao_eo_class != SAO_EO_HORIZ)
+ for(x = init_x+save_upper_left; x<width; x++)
+ dst[x] = src[x];
+ if(diag_edge && sao_eo_class == SAO_EO_135D)
+ dst[0] = src[0];
+ }
+
+#undef CMP
+}
+
+static void FUNC(sao_edge_filter_1)(uint8_t *_dst, uint8_t *_src,
+ ptrdiff_t _stride, SAOParams *sao,
+ int *borders, int _width, int _height,
+ 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;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+ int chroma = !!c_idx;
+ int *sao_offset_val = sao->offset_val[c_idx];
+ int sao_eo_class = sao->eo_class[c_idx];
+
+ 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 init_x = 0, init_y = 0, width = _width, height = _height;
+
+#define CMP(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1))
+
+ init_y = -(4 >> chroma) - 2;
+ if (!borders[2])
+ width -= (8 >> chroma) + 2;
+ height = (4 >> chroma) + 2;
+
+ 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;
+ }
+ init_x = 1;
+ }
+ if (borders[2]) {
+ int offset_val = sao_offset_val[0];
+ int x_stride = width - 1;
+ for (x = 0; x < height; x++) {
+ dst[x_stride] = av_clip_pixel(src[x_stride] + offset_val);
+ x_stride += stride;
+ }
+ 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;
+ }
+ }
+
+ {
+ // 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)];
+ }
+
+#undef CMP
+}
+
+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)
+{
+ int x, y;
+ pixel *dst = (pixel*)_dst;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+ int chroma = !!c_idx;
+ int *sao_offset_val = sao->offset_val[c_idx];
+ int sao_eo_class = sao->eo_class[c_idx];
+
+ 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 init_x = 0, init_y = 0, width = _width, height = _height;
+
+#define CMP(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1))
+
+ init_x = -(8 >> chroma) - 2;
+ width = (8 >> chroma) + 2;
+ if (!borders[3])
+ height -= (4 >> chroma) + 2;
+
+ 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--;
+ }
+ }
+ {
+ 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_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];
+ }
+#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)
+{
+ int x, y;
+ pixel *dst = (pixel*)_dst;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t stride = _stride / sizeof(pixel);
+ int chroma = !!c_idx;
+ int *sao_offset_val = sao->offset_val[c_idx];
+ int sao_eo_class = sao->eo_class[c_idx];
+
+ 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 init_x = 0, init_y = 0, width = _width, height = _height;
+
+#define CMP(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1))
+
+ init_y = -(4 >> chroma) - 2;
+ init_x = -(8 >> chroma) - 2;
+ width = (8 >> chroma) + 2;
+ height = (4 >> chroma) + 2;
+
+
+ dst = dst + (init_y * stride + init_x);
+ src = src + (init_y * stride + init_x);
+ init_y = init_x = 0;
+
+ {
+ 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_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];
+ }
+#undef CMP
+}
+
+#undef SET
+#undef SCALE
+#undef ADD_AND_SCALE
+#undef TR_4
+#undef TR_4_1
+#undef TR_4_2
+#undef TR_8
+#undef TR_8_1
+#undef TR_8_2
+#undef TR_16
+#undef TR_16_1
+#undef TR_16_2
+#undef TR_32
+#undef TR_32_1
+#undef TR_32_2
+
+static void FUNC(put_hevc_qpel_pixels)(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] = src[x] << (14 - BIT_DEPTH);
+ src += srcstride;
+ dst += dststride;
+ }
+}
+
+#define QPEL_FILTER_1(src, stride) \
+ (-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) \
+ (-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] - src[x+4*stride])
+#define QPEL_FILTER_3(src, stride) \
+ (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] - 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; \
+ } \
+}
+
+#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; \
+ } \
+}
+
+#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; \
+ } \
+}
+
+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)
+{
+ 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 += 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_epel_h)(int16_t *dst, ptrdiff_t dststride,
+ uint8_t *_src, ptrdiff_t _srcstride,
+ int width, int height, int mx, int my,
+ int16_t* mcbuffer)
+{
+ 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;
+ }
+}
+
+static void FUNC(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)
+{
+ 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;
+ }
+}
+
+static void FUNC(put_hevc_epel_hv)(int16_t *dst, ptrdiff_t dststride,
+ uint8_t *_src, ptrdiff_t _srcstride,
+ int width, int height, int mx, int my,
+ int16_t* mcbuffer)
+{
+ 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];
+ int16_t *tmp = tmp_array;
+
+ 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_0 = filter_v[0];
+ filter_1 = filter_v[1];
+ filter_2 = filter_v[2];
+ filter_3 = filter_v[3];
+ 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 += dststride;
+ }
+}
+
+static void FUNC(put_unweighted_pred)(uint8_t *_dst, ptrdiff_t _dststride,
+ int16_t *src, ptrdiff_t srcstride,
+ int width, int height)
+{
+ int x, y;
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+
+ 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;
+ src += srcstride;
+ }
+}
+
+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)
+{
+ int x, y;
+ 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);
+#else
+ int offset = 0;
+#endif
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ dst[x] = av_clip_pixel((src1[x] + src2[x] + offset) >> shift);
+ }
+ dst += dststride;
+ src1 += srcstride;
+ src2 += srcstride;
+ }
+}
+
+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)
+{
+ int shift;
+ int log2Wd;
+ int wx;
+ int ox;
+ int x , y;
+ int offset;
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+
+ shift = 14 - BIT_DEPTH;
+ log2Wd = denom + shift;
+ offset = 1 << (log2Wd - 1);
+ wx = wlxFlag;
+ ox = olxFlag * (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 += 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)
+{
+ int shift;
+ int log2Wd;
+ int w0;
+ int w1;
+ int o0;
+ int o1;
+ int x , y;
+ pixel *dst = (pixel*)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+
+ shift = 14 - BIT_DEPTH;
+ log2Wd = denom + shift;
+ w0 = wl0Flag;
+ w1 = wl1Flag;
+ o0 = (ol0Flag) * (1 << (BIT_DEPTH - 8));
+ o1 = (ol1Flag) * (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 += dststride;
+ src1 += srcstride;
+ src2 += srcstride;
+ }
+}
+
+// line zero
+#define P3 pix[-4*xstride]
+#define P2 pix[-3*xstride]
+#define P1 pix[-2*xstride]
+#define P0 pix[-xstride]
+#define Q0 pix[0]
+#define Q1 pix[xstride]
+#define Q2 pix[2*xstride]
+#define Q3 pix[3*xstride]
+
+// line three. used only for deblocking decision
+#define TP3 pix[-4*xstride+3*ystride]
+#define TP2 pix[-3*xstride+3*ystride]
+#define TP1 pix[-2*xstride+3*ystride]
+#define TP0 pix[-xstride+3*ystride]
+#define TQ0 pix[3*ystride]
+#define TQ1 pix[xstride+3*ystride]
+#define TQ2 pix[2*xstride+3*ystride]
+#define TQ3 pix[3*xstride+3*ystride]
+
+static void FUNC(hevc_loop_filter_luma)(uint8_t *_pix, ptrdiff_t _xstride,
+ ptrdiff_t _ystride, int *_beta, int *_tc,
+ uint8_t *_no_p, uint8_t *_no_q)
+{
+ int d, j;
+ pixel *pix = (pixel*)_pix;
+ ptrdiff_t xstride = _xstride / sizeof(pixel);
+ ptrdiff_t ystride = _ystride / sizeof(pixel);
+
+ for (j = 0; j < 2; j++) {
+ const int dp0 = abs(P2 - 2 * P1 + P0);
+ const int dq0 = abs(Q2 - 2 * Q1 + Q0);
+ const int dp3 = abs(TP2 - 2 * TP1 + TP0);
+ const int dq3 = abs(TQ2 - 2 * TQ1 + TQ0);
+ const int d0 = dp0 + dq0;
+ const int d3 = dp3 + dq3;
+ int beta = _beta[j] << (BIT_DEPTH - 8);
+ const int tc = _tc[j] << (BIT_DEPTH - 8);
+ const int no_p = _no_p[j];
+ const int no_q = _no_q[j];
+
+ if (d0 + d3 >= beta /*|| tc <= 0*/) {
+ pix += 4 * ystride;
+ continue;
+ } else {
+ const int beta_3 = beta >> 3;
+ const int beta_2 = beta >> 2;
+ const int tc25 = ((tc * 5 + 1) >> 1);
+
+ if (abs( P3 - P0) + abs( Q3 - Q0) < beta_3 && abs( P0 - Q0) < tc25 &&
+ abs(TP3 - TP0) + abs(TQ3 - TQ0) < beta_3 && abs(TP0 - TQ0) < tc25 &&
+ (d0 << 1) < beta_2 && (d3 << 1) < beta_2) {
+ // strong filtering
+ const int tc2 = tc << 1;
+ for (d = 0; d < 4; d++) {
+ const int p3 = P3;
+ const int p2 = P2;
+ const int p1 = P1;
+ const int p0 = P0;
+ const int q0 = Q0;
+ const int q1 = Q1;
+ const int q2 = Q2;
+ const int q3 = Q3;
+ if (!no_p) {
+ P0 = p0 + av_clip((( p2 + 2*p1 + 2*p0 + 2*q0 + q1 + 4 ) >> 3) - p0, -tc2, tc2);
+ P1 = p1 + av_clip((( p2 + p1 + p0 + q0 + 2 ) >> 2) - p1, -tc2, tc2);
+ P2 = p2 + av_clip((( 2*p3 + 3*p2 + p1 + p0 + q0 + 4 ) >> 3) - p2, -tc2, tc2);
+ }
+ if (!no_q) {
+ Q0 = q0 + av_clip((( p1 + 2*p0 + 2*q0 + 2*q1 + q2 + 4 ) >> 3) - q0, -tc2, tc2);
+ Q1 = q1 + av_clip((( p0 + q0 + q1 + q2 + 2 ) >> 2) - q1, -tc2, tc2);
+ Q2 = q2 + av_clip((( 2*q3 + 3*q2 + q1 + q0 + p0 + 4 ) >> 3) - q2, -tc2, tc2);
+ }
+ pix += ystride;
+ }
+ } else { // normal filtering
+ int nd_p = 1;
+ int nd_q = 1;
+ const int tc_2 = tc >> 1;
+ if (dp0 + dp3 < ((beta + (beta >> 1)) >> 3))
+ nd_p = 2;
+ if (dq0 + dq3 < ((beta + (beta >> 1)) >> 3))
+ nd_q = 2;
+
+ for (d = 0; d < 4; d++) {
+ const int p2 = P2;
+ const int p1 = P1;
+ const int p0 = P0;
+ const int q0 = Q0;
+ const int q1 = Q1;
+ const int q2 = Q2;
+ int delta0 = (9 * (q0 - p0) - 3 * (q1 - p1) + 8) >> 4;
+ if (abs(delta0) < 10 * tc) {
+ delta0 = av_clip(delta0, -tc, tc);
+ if (!no_p)
+ P0 = av_clip_pixel(p0 + delta0);
+ if (!no_q)
+ Q0 = av_clip_pixel(q0 - delta0);
+ if (!no_p && nd_p > 1) {
+ const int deltap1 = av_clip((((p2 + p0 + 1) >> 1) - p1 + delta0) >> 1, -tc_2, tc_2);
+ P1 = av_clip_pixel(p1 + deltap1);
+ }
+ if (!no_q && nd_q > 1) {
+ const int deltaq1 = av_clip((((q2 + q0 + 1) >> 1) - q1 - delta0) >> 1, -tc_2, tc_2);
+ Q1 = av_clip_pixel(q1 + deltaq1);
+ }
+ }
+ pix += ystride;
+ }
+ }
+ }
+ }
+}
+
+static void FUNC(hevc_loop_filter_chroma)(uint8_t *_pix, ptrdiff_t _xstride,
+ ptrdiff_t _ystride, int *_tc,
+ uint8_t *_no_p, uint8_t *_no_q)
+{
+ int d, j;
+ int no_p, no_q;
+ pixel *pix = (pixel*)_pix;
+ ptrdiff_t xstride = _xstride / sizeof(pixel);
+ ptrdiff_t ystride = _ystride / sizeof(pixel);
+
+ for (j = 0; j < 2; j++) {
+ const int tc = _tc[j] << (BIT_DEPTH - 8);
+ if (tc <= 0) {
+ pix += 4 * ystride;
+ continue;
+ }
+ no_p = _no_p[j];
+ no_q = _no_q[j];
+
+ for (d = 0; d < 4; d++) {
+ int delta0;
+ const int p1 = P1;
+ const int p0 = P0;
+ const int q0 = Q0;
+ const int q1 = Q1;
+ delta0 = av_clip((((q0 - p0) << 2) + p1 - q1 + 4) >> 3, -tc, tc);
+ if (!no_p)
+ P0 = av_clip_pixel(p0 + delta0);
+ if (!no_q)
+ Q0 = av_clip_pixel(q0 - delta0);
+ pix += ystride;
+ }
+ }
+}
+
+static void FUNC(hevc_h_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,
+ int *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, 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,
+ uint8_t *no_q)
+{
+ FUNC(hevc_loop_filter_luma)(pix, stride, sizeof(pixel), beta, tc, no_p, no_q);
+}
+
+static void FUNC(hevc_v_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,
+ int *beta, int *tc, uint8_t *no_p,
+ uint8_t *no_q)
+{
+ FUNC(hevc_loop_filter_luma)(pix, sizeof(pixel), stride, beta, tc, no_p, no_q);
+}
+
+#undef P3
+#undef P2
+#undef P1
+#undef P0
+#undef Q0
+#undef Q1
+#undef Q2
+#undef Q3
+
+#undef TP3
+#undef TP2
+#undef TP1
+#undef TP0
+#undef TQ0
+#undef TQ1
+#undef TQ2
+#undef TQ3
diff --git a/libavcodec/hevcpred.c b/libavcodec/hevcpred.c
new file mode 100644
index 0000000..b6b3906
--- a/dev/null
+++ b/libavcodec/hevcpred.c
@@ -0,0 +1,66 @@
+/*
+ * 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
+ */
+
+#include "hevc.h"
+#include "hevcpred.h"
+
+#define BIT_DEPTH 8
+#include "hevcpred_template.c"
+#undef BIT_DEPTH
+
+#define BIT_DEPTH 9
+#include "hevcpred_template.c"
+#undef BIT_DEPTH
+
+#define BIT_DEPTH 10
+#include "hevcpred_template.c"
+#undef BIT_DEPTH
+
+void ff_hevc_pred_init(HEVCPredContext *hpc, int bit_depth)
+{
+#undef FUNC
+#define FUNC(a, depth) a ## _ ## depth
+
+#define HEVC_PRED(depth) \
+ hpc->intra_pred = FUNC(intra_pred, depth); \
+ hpc->pred_planar[0] = FUNC(pred_planar_0, depth); \
+ hpc->pred_planar[1] = FUNC(pred_planar_1, depth); \
+ hpc->pred_planar[2] = FUNC(pred_planar_2, depth); \
+ hpc->pred_planar[3] = FUNC(pred_planar_3, depth); \
+ hpc->pred_dc = FUNC(pred_dc, depth); \
+ hpc->pred_angular[0] = FUNC(pred_angular_0, depth);\
+ hpc->pred_angular[1] = FUNC(pred_angular_1, depth);\
+ hpc->pred_angular[2] = FUNC(pred_angular_2, depth);\
+ hpc->pred_angular[3] = FUNC(pred_angular_3, depth);
+
+ switch (bit_depth) {
+ case 9:
+ HEVC_PRED(9);
+ break;
+ case 10:
+ HEVC_PRED(10);
+ break;
+ default:
+ HEVC_PRED(8);
+ break;
+ }
+}
diff --git a/libavcodec/hevcpred.h b/libavcodec/hevcpred.h
new file mode 100644
index 0000000..4dead2e
--- a/dev/null
+++ b/libavcodec/hevcpred.h
@@ -0,0 +1,43 @@
+/*
+ * 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)(struct HEVCContext *s, int x0, int y0, int log2_size, 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
new file mode 100644
index 0000000..8a33849
--- a/dev/null
+++ b/libavcodec/hevcpred_template.c
@@ -0,0 +1,555 @@
+/*
+ * 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
+ */
+
+#include "libavutil/pixdesc.h"
+#include "bit_depth_template.c"
+#include "hevcpred.h"
+
+#define POS(x, y) src[(x) + stride * (y)]
+
+static void FUNC(intra_pred)(HEVCContext *s, int x0, int y0, int log2_size, int c_idx)
+{
+#define PU(x) \
+ ((x) >> s->sps->log2_min_pu_size)
+#define MVF(x, y) \
+ (s->ref->tab_mvf[(x) + (y) * min_pu_width])
+#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
+#define MIN_TB_ADDR_ZS(x, y) \
+ s->pps->min_tb_addr_zs[(y) * s->sps->min_tb_width + (x)]
+#define EXTEND_LEFT(ptr, start, length) \
+ for (i = (start); i > (start) - (length); i--) \
+ ptr[i - 1] = ptr[i]
+#define EXTEND_RIGHT(ptr, start, length) \
+ for (i = (start); i < (start) + (length); i++) \
+ ptr[i] = ptr[i - 1]
+#define EXTEND_UP(ptr, start, length) EXTEND_LEFT(ptr, start, length)
+#define EXTEND_DOWN(ptr, start, length) EXTEND_RIGHT(ptr, start, length)
+#define EXTEND_LEFT_CIP(ptr, start, length) \
+ 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;
+ 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 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 cur_tb_addr = MIN_TB_ADDR_ZS(x_tb, y_tb);
+
+ ptrdiff_t stride = s->frame->linesize[c_idx] / sizeof(pixel);
+ pixel *src = (pixel*)s->frame->data[c_idx] + x + y * stride;
+
+ 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);
+ 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 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;
+
+ if (s->pps->constrained_intra_pred_flag == 1) {
+ int size_in_luma_pu = PU(size_in_luma);
+ int on_pu_edge_x = !(x0 & ((1 << s->sps->log2_min_pu_size) - 1));
+ int on_pu_edge_y = !(y0 & ((1 << s->sps->log2_min_pu_size) - 1));
+ if(!size_in_luma_pu)
+ size_in_luma_pu++;
+ 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);
+ cand_bottom_left = 0;
+ for (i = 0; i < max; i++)
+ cand_bottom_left |= MVF(x_left_pu, y_bottom_pu + i).is_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);
+ cand_left = 0;
+ for (i = 0; i < max; i++)
+ cand_left |= MVF(x_left_pu, y_left_pu + i).is_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;
+ }
+ 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);
+ cand_up = 0;
+ for (i = 0; i < max; i++)
+ cand_up |= MVF(x_top_pu + i, y_top_pu).is_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);
+ 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 < 2 * MAX_TB_SIZE; i++) {
+ left[i] = 128;
+ top[i] = 128;
+ }
+ }
+ if (cand_bottom_left) {
+ for (i = size + bottom_left_size; i < (size << 1); i++)
+ if (IS_INTRA(-1, size + bottom_left_size - 1) || !s->pps->constrained_intra_pred_flag)
+ left[i] = POS(-1, size + bottom_left_size - 1);
+ for (i = size + bottom_left_size - 1; i >= size; i--)
+ if (IS_INTRA(-1, i) || !s->pps->constrained_intra_pred_flag)
+ left[i] = POS(-1, i);
+ }
+ if (cand_left)
+ for (i = size - 1; i >= 0; i--)
+ if (IS_INTRA(-1, i) || !s->pps->constrained_intra_pred_flag)
+ left[i] = POS(-1, i);
+ if (cand_up_left)
+ if (IS_INTRA(-1, -1) || !s->pps->constrained_intra_pred_flag) {
+ left[-1] = POS(-1, -1);
+ top[-1] = left[-1];
+ }
+ if (cand_up)
+ for (i = size - 1; i >= 0; i--)
+ if (IS_INTRA(i, -1) || !s->pps->constrained_intra_pred_flag)
+ top[i] = POS(i, -1);
+ if (cand_up_right) {
+ for (i = size + top_right_size; i < (size << 1); i++)
+ if (IS_INTRA(size + top_right_size - 1, -1) || !s->pps->constrained_intra_pred_flag)
+ top[i] = POS(size + top_right_size - 1, -1);
+ for (i = size + top_right_size - 1; i >= size; i--)
+ if (IS_INTRA(i, -1) || !s->pps->constrained_intra_pred_flag)
+ top[i] = POS(i, -1);
+ }
+
+ if (s->pps->constrained_intra_pred_flag == 1) {
+ if (cand_bottom_left || cand_left || cand_up_left || cand_up || cand_up_right) {
+ int size_max_x = x0 + ((2 * size) << hshift) < s->sps->width ?
+ 2 * size : (s->sps->width - x0) >> hshift;
+ int size_max_y = y0 + ((2 * size) << vshift) < s->sps->height ?
+ 2 * size : (s->sps->height - y0) >> vshift;
+ int j = size + (cand_bottom_left? bottom_left_size: 0) -1;
+ if (!cand_up_right) {
+ size_max_x = x0 + ((size) << hshift) < s->sps->width ?
+ size : (s->sps->width - x0) >> hshift;
+ }
+ if (!cand_bottom_left) {
+ size_max_y = y0 + (( size) << vshift) < s->sps->height ?
+ size : (s->sps->height - y0) >> vshift;
+ }
+ if (cand_bottom_left || cand_left || cand_up_left) {
+ while (j>-1 && !IS_INTRA(-1, j)) j--;
+ if (!IS_INTRA(-1, j)) {
+ j = 0;
+ while(j < size_max_x && !IS_INTRA(j, -1)) j++;
+ EXTEND_LEFT_CIP(top, j, j+1);
+ left[-1] = top[-1];
+ j = 0;
+ }
+ } else {
+ j = 0;
+ while (j < size_max_x && !IS_INTRA(j, -1)) j++;
+ if (j > 0)
+ if (x0 > 0) {
+ EXTEND_LEFT_CIP(top, j, j+1);
+ } else {
+ EXTEND_LEFT_CIP(top, j, j);
+ top[-1] = top[0];
+ }
+ left[-1] = top[-1];
+ j = 0;
+ }
+ if (cand_bottom_left || cand_left) {
+ EXTEND_DOWN_CIP(left, j, size_max_y-j);
+ }
+ if (!cand_left) {
+ EXTEND_DOWN(left, 0, size);
+ }
+ if (!cand_bottom_left) {
+ EXTEND_DOWN(left, size, size);
+ }
+ if (x0 != 0 && y0 != 0) {
+ EXTEND_UP_CIP(left, size_max_y - 1, size_max_y);
+ } else if( x0 == 0) {
+ EXTEND_UP_CIP_0(left, size_max_y - 1, size_max_y);
+ } else{
+ EXTEND_UP_CIP(left, size_max_y - 1, size_max_y-1);
+ }
+ top[-1] = left[-1];
+ if (y0 != 0) {
+ EXTEND_RIGHT_CIP(top, 0, size_max_x);
+ }
+ }
+ }
+ // Infer the unavailable samples
+ if (!cand_bottom_left) {
+ if (cand_left) {
+ EXTEND_DOWN(left, size, size);
+ } else if (cand_up_left) {
+ EXTEND_DOWN(left, 0, 2 * size);
+ cand_left = 1;
+ } else if (cand_up) {
+ left[-1] = top[0];
+ EXTEND_DOWN(left, 0, 2 * size);
+ cand_up_left = 1;
+ cand_left = 1;
+ } else if (cand_up_right) {
+ EXTEND_LEFT(top, size, size);
+ left[-1] = top[0];
+ EXTEND_DOWN(left ,0 , 2 * size);
+ cand_up = 1;
+ cand_up_left = 1;
+ cand_left = 1;
+ } else { // No samples available
+ top[0] = left[-1] = (1 << (BIT_DEPTH - 1));
+ EXTEND_RIGHT(top, 1, 2 * size - 1);
+ EXTEND_DOWN(left, 0, 2 * size);
+ }
+ }
+
+ if (!cand_left) {
+ EXTEND_UP(left, size, size);
+ }
+ if (!cand_up_left) {
+ left[-1] = left[0];
+ }
+ if (!cand_up) {
+ top[0] = left[-1];
+ EXTEND_RIGHT(top, 1, size-1);
+ }
+ if (!cand_up_right) {
+ EXTEND_RIGHT(top, size, size);
+ }
+
+ top[-1] = left[-1];
+
+#undef EXTEND_LEFT_CIP
+#undef EXTEND_RIGHT_CIP
+#undef EXTEND_UP_CIP
+#undef EXTEND_DOWN_CIP
+#undef IS_INTRA
+#undef MVF_PU
+#undef MVF
+#undef PU
+#undef EXTEND_LEFT
+#undef EXTEND_RIGHT
+#undef EXTEND_UP
+#undef EXTEND_DOWN
+#undef MIN_TB_ADDR_ZS
+
+ // 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 - 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 &&
+ 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;
+ }
+ }
+ }
+
+ switch (mode) {
+ case INTRA_PLANAR:
+ s->hpc.pred_planar[log2_size - 2]((uint8_t*)src, (uint8_t*)top,
+ (uint8_t*)left, stride);
+ break;
+ case INTRA_DC:
+ s->hpc.pred_dc((uint8_t*)src, (uint8_t*)top,
+ (uint8_t*)left, stride, log2_size, c_idx);
+ break;
+ default:
+ s->hpc.pred_angular[log2_size - 2]((uint8_t*)src, (uint8_t*)top,
+ (uint8_t*)left, stride, c_idx, mode);
+ break;
+ }
+}
+
+static void FUNC(pred_planar_0)(uint8_t *_src, const uint8_t *_top,
+ const uint8_t *_left,
+ ptrdiff_t stride)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ const pixel *top = (const pixel*)_top;
+ const pixel *left = (const pixel*)_left;
+ for (y = 0; y < 4; y++)
+ for (x = 0; x < 4; x++)
+ POS(x, y) = ((3 - x) * left[y] + (x + 1) * top[4] +
+ (3 - y) * top[x] + (y + 1) * left[4] + 4) >> 3;
+}
+
+static void FUNC(pred_planar_1)(uint8_t *_src, const uint8_t *_top,
+ const uint8_t *_left, ptrdiff_t stride)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ const pixel *top = (const pixel*)_top;
+ const pixel *left = (const pixel*)_left;
+ for (y = 0; y < 8; y++)
+ for (x = 0; x < 8; x++)
+ POS(x, y) = ((7 - x) * left[y] + (x + 1) * top[8] +
+ (7 - y) * top[x] + (y + 1) * left[8] + 8) >> 4;
+}
+
+static void FUNC(pred_planar_2)(uint8_t *_src, const uint8_t *_top,
+ const uint8_t *_left, ptrdiff_t stride)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ const pixel *top = (const pixel*)_top;
+ const pixel *left = (const pixel*)_left;
+ for (y = 0; y < 16; y++)
+ for (x = 0; x < 16; x++)
+ POS(x, y) = ((15 - x) * left[y] + (x + 1) * top[16] +
+ (15 - y) * top[x] + (y + 1) * left[16] + 16) >> 5;
+}
+
+static void FUNC(pred_planar_3)(uint8_t *_src, const uint8_t *_top,
+ const uint8_t *_left, ptrdiff_t stride)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ const pixel *top = (const pixel*)_top;
+ const pixel *left = (const pixel*)_left;
+ for (y = 0; y < 32; y++)
+ for (x = 0; x < 32; x++)
+ POS(x, y) = ((31 - x) * left[y] + (x + 1) * top[32] +
+ (31 - y) * top[x] + (y + 1) * left[32] + 32) >> 6;
+}
+
+static void FUNC(pred_dc)(uint8_t *_src, const uint8_t *_top,
+ const uint8_t *_left,
+ ptrdiff_t stride, int log2_size, int c_idx)
+{
+ int i, j, x, y;
+ int size = (1 << log2_size);
+ pixel *src = (pixel*)_src;
+ const pixel *top = (const pixel*)_top;
+ const pixel *left = (const pixel*)_left;
+ int dc = size;
+ pixel4 a;
+ for (i = 0; i < size; i++)
+ dc += left[i] + top[i];
+
+ dc >>= log2_size + 1;
+
+ 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);
+
+ if (c_idx == 0 && size < 32) {
+ POS(0, 0) = (left[0] + 2 * dc + top[0] + 2) >> 2;
+ for (x = 1; x < size; x++)
+ POS(x, 0) = (top[x] + 3 * dc + 2) >> 2;
+ for (y = 1; y < size; y++)
+ POS(0, y) = (left[y] + 3 * dc + 2) >> 2;
+ }
+}
+
+static av_always_inline void FUNC(pred_angular)(uint8_t *_src,
+ const uint8_t *_top,
+ const uint8_t *_left,
+ ptrdiff_t stride, int c_idx,
+ int mode, int size)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ const pixel *top = (const pixel*)_top;
+ const pixel *left = (const pixel*)_left;
+
+ static const int intra_pred_angle[] = {
+ 32, 26, 21, 17, 13, 9, 5, 2, 0, -2, -5, -9, -13, -17, -21, -26, -32,
+ -26, -21, -17, -13, -9, -5, -2, 0, 2, 5, 9, 13, 17, 21, 26, 32
+ };
+ static const int inv_angle[] = {
+ -4096, -1638, -910, -630, -482, -390, -315, -256, -315, -390, -482,
+ -630, -910, -1638, -4096
+ };
+
+ int angle = intra_pred_angle[mode - 2];
+ pixel ref_array[3 * MAX_TB_SIZE + 1];
+ pixel *ref_tmp = ref_array + size;
+ const pixel *ref;
+ int last = (size * angle) >> 5;
+
+ 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 = last; x <= -1; x++)
+ ref_tmp[x] = left[-1 + ((x * inv_angle[mode-11] + 128) >> 8)];
+ ref = ref_tmp;
+ }
+
+ for (y = 0; y < size; y++) {
+ 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;
+ }
+ } else {
+ for (x = 0; x < size; x++) {
+ POS(x, y) = ref[x + idx + 1];
+ }
+ }
+ }
+ if (mode == 26 && c_idx == 0 && size < 32) {
+ for (y = 0; y < size; y++)
+ POS(0, y) = av_clip_pixel(top[0] + ((left[y] - left[-1]) >> 1));
+ }
+ } else {
+ ref = left - 1;
+ if (angle < 0 && last < -1) {
+ for (x = 0; x <= size; x++)
+ ref_tmp[x] = left[x - 1];
+ for (x = last; x <= -1; x++)
+ ref_tmp[x] = top[-1 + ((x * inv_angle[mode-11] + 128) >> 8)];
+ ref = ref_tmp;
+ }
+
+ for (x = 0; x < size; x++) {
+ int idx = ((x + 1) * angle) >> 5;
+ int fact = ((x + 1) * angle) & 31;
+ if (fact) {
+ for (y = 0; y < size; y++) {
+ POS(x, y) = ((32 - fact) * ref[y + idx + 1] +
+ fact * ref[y + idx + 2] + 16) >> 5;
+ }
+ } else {
+ for (y = 0; y < size; y++) {
+ POS(x, y) = ref[y + idx + 1];
+ }
+ }
+ }
+ 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));
+ }
+ }
+}
+
+static void FUNC(pred_angular_0)(uint8_t *src, const uint8_t *top,
+ const uint8_t *left,
+ ptrdiff_t stride, int c_idx, int mode)
+{
+ FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 2);
+}
+
+static void FUNC(pred_angular_1)(uint8_t *src, const uint8_t *top,
+ const uint8_t *left,
+ ptrdiff_t stride, int c_idx, int mode)
+{
+ FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 3);
+}
+
+static void FUNC(pred_angular_2)(uint8_t *src, const uint8_t *top,
+ const uint8_t *left,
+ ptrdiff_t stride, int c_idx, int mode)
+{
+ FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 4);
+}
+
+static void FUNC(pred_angular_3)(uint8_t *src, const uint8_t *top,
+ const uint8_t *left,
+ ptrdiff_t stride, int c_idx, int mode)
+{
+ FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 5);
+}
+#undef POS
diff --git a/libavcodec/hpel_template.c b/libavcodec/hpel_template.c
index 0c1f756..3b46999 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 852cb5a..473102d 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
*/
diff --git a/libavcodec/hpeldsp.h b/libavcodec/hpeldsp.h
index fc57103..ec9006c 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
*/
@@ -69,7 +69,7 @@ typedef struct HpelDSPContext {
/**
* Halfpel motion compensation with no rounding (a+b)>>1.
- * this is an array[2][4] of motion compensation functions for 2
+ * this is an array[4][4] of motion compensation functions for 2
* horizontal blocksizes (8,16) and the 4 halfpel positions<br>
* *pixels_tab[ 0->16xH 1->8xH ][ xhalfpel + 2*yhalfpel ]
* @param block destination where the result is stored
@@ -77,7 +77,7 @@ typedef struct HpelDSPContext {
* @param line_size number of bytes in a horizontal line of block
* @param h height
*/
- op_pixels_func put_no_rnd_pixels_tab[2][4];
+ op_pixels_func put_no_rnd_pixels_tab[4][4];
/**
* Halfpel motion compensation with no rounding (a+b)>>1.
diff --git a/libavcodec/hpeldsp_template.c b/libavcodec/hpeldsp_template.c
index 6518941..9c9fd2b 100644
--- a/libavcodec/hpeldsp_template.c
+++ b/libavcodec/hpeldsp_template.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
*/
@@ -83,7 +83,7 @@ static inline void FUNCC(OPNAME ## _pixels2_xy2)(uint8_t *_block, const uint8_t
int i, a0, b0, a1, b1;\
pixel *block = (pixel*)_block;\
const pixel *pixels = (const pixel*)_pixels;\
- line_size /= sizeof(pixel);\
+ line_size >>= sizeof(pixel)-1;\
a0= pixels[0];\
b0= pixels[1] + 2;\
a0 += b0;\
diff --git a/libavcodec/huffman.c b/libavcodec/huffman.c
index aef4929..2b64b3e 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
*/
@@ -112,7 +112,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];
@@ -122,7 +122,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);
}
@@ -130,7 +130,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;
@@ -153,21 +153,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..cec9537 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,9 +37,10 @@ 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);
diff --git a/libavcodec/huffyuv.c b/libavcodec/huffyuv.c
index d4cf6fa..b4ef76f 100644
--- a/libavcodec/huffyuv.c
+++ b/libavcodec/huffyuv.c
@@ -6,20 +6,20 @@
* 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
*/
@@ -83,10 +83,11 @@ av_cold void ff_huffyuv_common_init(AVCodecContext *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;
diff --git a/libavcodec/huffyuv.h b/libavcodec/huffyuv.h
index c464d83..e34b562 100644
--- a/libavcodec/huffyuv.h
+++ b/libavcodec/huffyuv.h
@@ -4,20 +4,20 @@
* 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
*/
diff --git a/libavcodec/huffyuvdec.c b/libavcodec/huffyuvdec.c
index ed490d4..9b904d4 100644
--- a/libavcodec/huffyuvdec.c
+++ b/libavcodec/huffyuvdec.c
@@ -6,20 +6,20 @@
* 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,14 +37,16 @@
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
+ 69,68, 0,
+ 0,0,0,0,0,0,0,0,
};
#define classic_shift_chroma_table_size 59
static const unsigned char classic_shift_chroma[classic_shift_chroma_table_size + FF_INPUT_BUFFER_PADDING_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
+ 214,245,116,83,82,49,80,79,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] = {
@@ -104,23 +106,26 @@ static int read_len_table(uint8_t *dst, GetBitContext *gb)
return 0;
}
-static void generate_joint_tables(HYuvContext *s)
+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;
+
if (s->bitstream_bpp < 24) {
int p, i, y, u;
for (p = 0; p < 3; p++) {
for (i = y = 0; y < 256; y++) {
int len0 = s->len[0][y];
int limit = VLC_BITS - len0;
- if(limit <= 0)
+ if(limit <= 0 || !len0)
continue;
for (u = 0; u < 256; u++) {
int len1 = s->len[p][u];
- if (len1 > limit)
+ if (len1 > limit || !len1)
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;
@@ -129,8 +134,9 @@ static void generate_joint_tables(HYuvContext *s)
}
}
ff_free_vlc(&s->vlc[3 + p]);
- ff_init_vlc_sparse(&s->vlc[3 + p], VLC_BITS, i, len, 1, 1,
- bits, 2, 2, symbols, 2, 2, 0);
+ if ((ret = ff_init_vlc_sparse(&s->vlc[3 + p], VLC_BITS, i, len, 1, 1,
+ bits, 2, 2, symbols, 2, 2, 0)) < 0)
+ return ret;
}
} else {
uint8_t (*map)[4] = (uint8_t(*)[4])s->pix_bgr_map;
@@ -143,18 +149,19 @@ static void 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) {
@@ -171,14 +178,17 @@ static void generate_joint_tables(HYuvContext *s)
}
}
ff_free_vlc(&s->vlc[3]);
- init_vlc(&s->vlc[3], VLC_BITS, i, len, 1, 1, bits, 2, 2, 0);
+ if ((ret = init_vlc(&s->vlc[3], VLC_BITS, i, len, 1, 1, bits, 2, 2, 0)) < 0)
+ return ret;
}
+ return 0;
}
static int read_huffman_tables(HYuvContext *s, const uint8_t *src, int length)
{
GetBitContext gb;
int i;
+ int ret;
init_get_bits(&gb, src, length * 8);
@@ -189,11 +199,13 @@ static int read_huffman_tables(HYuvContext *s, const uint8_t *src, int length)
return -1;
}
ff_free_vlc(&s->vlc[i]);
- init_vlc(&s->vlc[i], VLC_BITS, 256, s->len[i], 1, 1,
- s->bits[i], 4, 4, 0);
+ if ((ret = init_vlc(&s->vlc[i], VLC_BITS, 256, s->len[i], 1, 1,
+ s->bits[i], 4, 4, 0)) < 0)
+ return ret;
}
- generate_joint_tables(s);
+ if ((ret = generate_joint_tables(s)) < 0)
+ return ret;
return (get_bits_count(&gb) + 7) / 8;
}
@@ -202,6 +214,7 @@ static int read_old_huffman_tables(HYuvContext *s)
{
GetBitContext gb;
int i;
+ int ret;
init_get_bits(&gb, classic_shift_luma,
classic_shift_luma_table_size * 8);
@@ -225,11 +238,13 @@ static int read_old_huffman_tables(HYuvContext *s)
for (i = 0; i < 3; i++) {
ff_free_vlc(&s->vlc[i]);
- init_vlc(&s->vlc[i], VLC_BITS, 256, s->len[i], 1, 1,
- s->bits[i], 4, 4, 0);
+ if ((ret = init_vlc(&s->vlc[i], VLC_BITS, 256, s->len[i], 1, 1,
+ s->bits[i], 4, 4, 0)) < 0)
+ return ret;
}
- generate_joint_tables(s);
+ if ((ret = generate_joint_tables(s)) < 0)
+ return ret;
return 0;
}
@@ -241,6 +256,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
ff_huffyuv_common_init(avctx);
memset(s->vlc, 0, 3 * sizeof(VLC));
+ avcodec_get_frame_defaults(&s->picture);
s->interlaced = s->height > 288;
s->bgr32 = 1;
@@ -272,7 +288,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
if ( read_huffman_tables(s, ((uint8_t*)avctx->extradata) + 4,
avctx->extradata_size - 4) < 0)
- return -1;
+ return AVERROR_INVALIDDATA;
}else{
switch (avctx->bits_per_coded_sample & 7) {
case 1:
@@ -300,7 +316,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
s->context = 0;
if (read_old_huffman_tables(s) < 0)
- return -1;
+ return AVERROR_INVALIDDATA;
}
switch (s->bitstream_bpp) {
@@ -326,7 +342,18 @@ static av_cold int decode_init(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
}
- ff_huffyuv_alloc_temp(s);
+ 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 a multiple of 4 this colorspace and predictor\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (ff_huffyuv_alloc_temp(s)) {
+ ff_huffyuv_common_end(s);
+ return AVERROR(ENOMEM);
+ }
return 0;
}
@@ -336,7 +363,10 @@ static av_cold int decode_init_thread_copy(AVCodecContext *avctx)
HYuvContext *s = avctx->priv_data;
int i;
- ff_huffyuv_alloc_temp(s);
+ if (ff_huffyuv_alloc_temp(s)) {
+ ff_huffyuv_common_end(s);
+ return AVERROR(ENOMEM);
+ }
for (i = 0; i < 6; i++)
s->vlc[i].table = NULL;
@@ -344,10 +374,10 @@ static av_cold int decode_init_thread_copy(AVCodecContext *avctx)
if (s->version == 2) {
if (read_huffman_tables(s, ((uint8_t*)avctx->extradata) + 4,
avctx->extradata_size) < 0)
- return -1;
+ return AVERROR_INVALIDDATA;
} else {
if (read_old_huffman_tables(s) < 0)
- return -1;
+ return AVERROR_INVALIDDATA;
}
return 0;
@@ -482,31 +512,28 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
int fake_ystride, fake_ustride, fake_vstride;
ThreadFrame frame = { .f = data };
AVFrame * const p = data;
- int table_size = 0;
+ 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->dsp.bswap_buf((uint32_t*)s->bitstream_buffer,
(const uint32_t*)buf, buf_size / 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;
if (s->context) {
table_size = read_huffman_tables(s, s->bitstream_buffer, buf_size);
if (table_size < 0)
- return -1;
+ return AVERROR_INVALIDDATA;
}
if ((unsigned)(buf_size-table_size) >= INT_MAX / 8)
- return -1;
+ return AVERROR_INVALIDDATA;
init_get_bits(&s->gb, s->bitstream_buffer+table_size,
(buf_size-table_size) * 8);
@@ -530,7 +557,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
av_log(avctx, AV_LOG_ERROR,
"YUY2 output is not implemented yet\n");
- return -1;
+ return AVERROR_PATCHWELCOME;
} else {
leftv = p->data[2][0] = get_bits(&s->gb, 8);
@@ -712,7 +739,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
}else{
av_log(avctx, AV_LOG_ERROR,
"BGR24 output is not implemented yet\n");
- return -1;
+ return AVERROR_PATCHWELCOME;
}
}
emms_c();
diff --git a/libavcodec/huffyuvenc.c b/libavcodec/huffyuvenc.c
index 665d0a6..c56e281 100644
--- a/libavcodec/huffyuvenc.c
+++ b/libavcodec/huffyuvenc.c
@@ -4,20 +4,20 @@
* 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
*/
@@ -29,10 +29,11 @@
#include "avcodec.h"
#include "huffyuv.h"
#include "huffman.h"
+#include "internal.h"
#include "put_bits.h"
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) {
@@ -54,7 +55,7 @@ static inline int sub_left_prediction(HYuvContext *s, uint8_t *dst,
}
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)
{
@@ -128,8 +129,8 @@ static int store_table(HYuvContext *s, const uint8_t *len, uint8_t *buf)
for (; i < 256 && 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 {
@@ -149,6 +150,10 @@ static av_cold int encode_init(AVCodecContext *avctx)
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
+ if (!avctx->extradata || !avctx->stats_out) {
+ av_freep(&avctx->stats_out);
+ return AVERROR(ENOMEM);
+ }
s->version = 2;
avctx->coded_frame = &s->picture;
@@ -158,7 +163,7 @@ static av_cold int encode_init(AVCodecContext *avctx)
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;
@@ -170,7 +175,7 @@ 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);
}
avctx->bits_per_coded_sample = s->bitstream_bpp;
s->decorrelate = s->bitstream_bpp >= 24;
@@ -182,7 +187,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;
@@ -191,13 +196,13 @@ 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->interlaced != ( s->height > 288 ))
av_log(avctx, AV_LOG_INFO,
@@ -207,7 +212,7 @@ static av_cold int encode_init(AVCodecContext *avctx)
if (s->bitstream_bpp >= 24 && s->predictor == MEDIAN) {
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);
@@ -271,7 +276,10 @@ static av_cold int encode_init(AVCodecContext *avctx)
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;
@@ -389,8 +397,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 \
@@ -441,11 +449,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
AVFrame * const p = &s->picture;
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;
- }
*p = *pict;
p->pict_type = AV_PICTURE_TYPE_I;
diff --git a/libavcodec/idcinvideo.c b/libavcodec/idcinvideo.c
index 70c98d6..80c7d07 100644
--- a/libavcodec/idcinvideo.c
+++ b/libavcodec/idcinvideo.c
@@ -2,20 +2,20 @@
* id Quake II CIN Video Decoder
* 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/iff.c b/libavcodec/iff.c
index 1ee02bd..a4b90fa 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 "libavutil/imgutils.h"
@@ -31,11 +31,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;
+ 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) \
@@ -122,25 +141,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;
}
@@ -150,11 +324,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;
}
@@ -166,7 +358,13 @@ static av_cold int decode_init(AVCodecContext *avctx)
if (!s->planebuf)
return AVERROR(ENOMEM);
- avcodec_get_frame_defaults(&s->frame);
+ s->bpp = avctx->bits_per_coded_sample;
+ s->frame = av_frame_alloc();
+ if (!s->frame)
+ return AVERROR(ENOMEM);
+
+ if ((err = extract_header(avctx, NULL)) < 0)
+ return err;
return 0;
}
@@ -181,6 +379,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);
@@ -213,6 +415,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,113 +488,369 @@ static int decode_byterun(uint8_t *dst, int dst_size,
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;
- if ((res = ff_reget_buffer(avctx, &s->frame)) < 0)
+ if ((res = extract_header(avctx, avpkt)) < 0)
+ return res;
+ if ((res = ff_reget_buffer(avctx, s->frame)) < 0)
return res;
-
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)
+ 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++) {
- 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);
+ 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')) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+ 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]];
+ 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
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+ 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'))
+ 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'))
+ 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')) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+ 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)
+ if ((res = av_frame_ref(data, s->frame)) < 0)
return res;
*got_frame = 1;
@@ -362,31 +861,36 @@ static int decode_frame_byterun1(AVCodecContext *avctx,
static av_cold int decode_end(AVCodecContext *avctx)
{
IffContext *s = avctx->priv_data;
- av_frame_unref(&s->frame);
+ av_frame_free(&s->frame);
av_freep(&s->planebuf);
+ av_freep(&s->ham_buf);
+ av_freep(&s->ham_palbuf);
return 0;
}
+#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..a2d9d11 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
*/
@@ -313,6 +313,13 @@ av_cold void ff_iir_filter_free_coeffs(struct FFIIRFilterCoeffs *coeffs)
av_free(coeffs);
}
+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
#include <stdio.h>
diff --git a/libavcodec/iirfilter.h b/libavcodec/iirfilter.h
index bc65a96..4ea6642 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.
*
diff --git a/libavcodec/imc.c b/libavcodec/imc.c
index c1fbd76..cbd7041 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 "get_bits.h"
#include "dsputil.h"
@@ -356,7 +357,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 +451,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 +893,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;
@@ -1006,10 +1019,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 +1055,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 +1073,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 +1089,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 4eb049f..ee58cfb 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 "dsputil.h"
#include "imgconvert.h"
#include "internal.h"
+#include "libavutil/avassert.h"
#include "libavutil/colorspace.h"
#include "libavutil/common.h"
#include "libavutil/pixdesc.h"
@@ -43,6 +44,12 @@
#include "x86/dsputil_x86.h"
#endif
+#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 */
+
#if HAVE_MMX_EXTERNAL
#define deinterlace_line_inplace ff_deinterlace_line_inplace_mmx
#define deinterlace_line ff_deinterlace_line_mmx
@@ -51,124 +58,223 @@
#define deinterlace_line deinterlace_line_c
#endif
+#define pixdesc_has_alpha(pixdesc) \
+ ((pixdesc)->nb_components == 2 || (pixdesc)->nb_components == 4 || (pixdesc)->flags & AV_PIX_FMT_FLAG_PAL)
+
+
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)
+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)
{
- return desc->nb_components - (desc->flags & AV_PIX_FMT_FLAG_ALPHA) == 1;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
+ int i;
+
+ if (!desc || !desc->nb_components) {
+ *min = *max = 0;
+ return AVERROR(EINVAL);
+ }
+
+ *min = INT_MAX, *max = -INT_MAX;
+ for (i = 0; i < desc->nb_components; i++) {
+ *min = FFMIN(desc->comp[i].depth_minus1+1, *min);
+ *max = FFMAX(desc->comp[i].depth_minus1+1, *max);
+ }
+ return 0;
}
-int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt,
- enum AVPixelFormat src_pix_fmt,
- int has_alpha)
+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 loss, i, nb_components = FFMIN(src_desc->nb_components,
- dst_desc->nb_components);
+ 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 */
- loss = 0;
+ *lossp = loss = 0;
if (dst_pix_fmt == src_pix_fmt)
- return 0;
+ 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);
+ nb_components = FFMIN(src_desc->nb_components, dst_desc->nb_components);
for (i = 0; i < nb_components; i++)
- if (src_desc->comp[i].depth_minus1 > dst_desc->comp[i].depth_minus1)
+ if (src_desc->comp[i].depth_minus1 > dst_desc->comp[i].depth_minus1 && (consider & FF_LOSS_DEPTH)) {
loss |= FF_LOSS_DEPTH;
+ score -= 65536 >> dst_desc->comp[i].depth_minus1;
+ }
- 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 (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 ((src_desc->flags & AV_PIX_FMT_FLAG_RGB) != (dst_desc->flags & AV_PIX_FMT_FLAG_RGB))
- loss |= FF_LOSS_COLORSPACE;
+ 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 (has_alpha && !(dst_desc->flags & AV_PIX_FMT_FLAG_ALPHA) &&
- (dst_desc->flags & AV_PIX_FMT_FLAG_ALPHA))
+ 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;
+ }
- 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;
+ *lossp = loss;
+ return score;
+}
+int avcodec_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;
}
-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;
+ 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;
- /* 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;
- }
+ 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);
- 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;
- }
+ 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;
}
- i++;
+ } else {
+ dst_pix_fmt = score1 < score2 ? dst_pix_fmt2 : dst_pix_fmt1;
}
+
+ if (loss_ptr)
+ *loss_ptr = avcodec_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha);
return dst_pix_fmt;
}
-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 */
@@ -260,8 +366,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,
@@ -271,15 +391,23 @@ int av_picture_crop(AVPicture *dst, const AVPicture *src,
int y_shift;
int x_shift;
- if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB || !is_yuv_planar(desc))
+ if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB)
return -1;
y_shift = desc->log2_chroma_h;
x_shift = desc->log2_chroma_w;
+ if (is_yuv_planar(desc)) {
dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + left_band;
dst->data[1] = src->data[1] + ((top_band >> y_shift) * src->linesize[1]) + (left_band >> x_shift);
dst->data[2] = src->data[2] + ((top_band >> y_shift) * src->linesize[2]) + (left_band >> x_shift);
+ } else{
+ if(top_band % (1<<y_shift) || left_band % (1<<x_shift))
+ return -1;
+ if(left_band) //FIXME add support for this too
+ return -1;
+ dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + left_band;
+ }
dst->linesize[0] = src->linesize[0];
dst->linesize[1] = src->linesize[1];
@@ -510,3 +638,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 colortype:%d\n", desc->name, is_yuv_planar(desc), 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/libavcodec/imgconvert.h b/libavcodec/imgconvert.h
index 91e9f91..df8cee7 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 67c2fac..d3bbc6d 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
*/
@@ -34,7 +34,7 @@
typedef struct Ir2Context{
AVCodecContext *avctx;
- AVFrame picture;
+ AVFrame *picture;
GetBitContext gb;
int decode_delta;
} Ir2Context;
@@ -146,13 +146,11 @@ static int ir2_decode_frame(AVCodecContext *avctx,
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
AVFrame *picture = data;
- AVFrame * const p = &s->picture;
+ 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 */
@@ -173,36 +171,36 @@ static int ir2_decode_frame(AVCodecContext *avctx,
if (s->decode_delta) { /* intraframe */
if ((ret = ir2_decode_plane(s, avctx->width, avctx->height,
- s->picture.data[0], s->picture.linesize[0],
+ s->picture->data[0], s->picture->linesize[0],
ir2_luma_table)) < 0)
return ret;
/* swapped U and V */
if ((ret = ir2_decode_plane(s, avctx->width >> 2, avctx->height >> 2,
- s->picture.data[2], s->picture.linesize[2],
+ s->picture->data[2], s->picture->linesize[2],
ir2_luma_table)) < 0)
return ret;
if ((ret = ir2_decode_plane(s, avctx->width >> 2, avctx->height >> 2,
- s->picture.data[1], s->picture.linesize[1],
+ s->picture->data[1], s->picture->linesize[1],
ir2_luma_table)) < 0)
return ret;
} else { /* interframe */
if ((ret = ir2_decode_plane_inter(s, avctx->width, avctx->height,
- s->picture.data[0], s->picture.linesize[0],
+ s->picture->data[0], s->picture->linesize[0],
ir2_luma_table)) < 0)
return ret;
/* swapped U and V */
if ((ret = ir2_decode_plane_inter(s, avctx->width >> 2, avctx->height >> 2,
- s->picture.data[2], s->picture.linesize[2],
+ s->picture->data[2], s->picture->linesize[2],
ir2_luma_table)) < 0)
return ret;
if ((ret = ir2_decode_plane_inter(s, avctx->width >> 2, avctx->height >> 2,
- s->picture.data[1], s->picture.linesize[1],
+ s->picture->data[1], s->picture->linesize[1],
ir2_luma_table)) < 0)
return ret;
}
- if ((ret = av_frame_ref(picture, &s->picture)) < 0)
+ if ((ret = av_frame_ref(picture, s->picture)) < 0)
return ret;
*got_frame = 1;
@@ -219,7 +217,9 @@ static av_cold int ir2_decode_init(AVCodecContext *avctx)
avctx->pix_fmt= AV_PIX_FMT_YUV410P;
- avcodec_get_frame_defaults(&ic->picture);
+ ic->picture = av_frame_alloc();
+ if (!ic->picture)
+ return AVERROR(ENOMEM);
ir2_vlc.table = vlc_tables;
ir2_vlc.table_allocated = 1 << CODE_VLC_BITS;
@@ -239,9 +239,8 @@ static av_cold int ir2_decode_init(AVCodecContext *avctx)
static av_cold int ir2_decode_end(AVCodecContext *avctx)
{
Ir2Context * const ic = avctx->priv_data;
- AVFrame *pic = &ic->picture;
- av_frame_unref(pic);
+ av_frame_free(&ic->picture);
return 0;
}
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 7cc870d..b882763 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"
@@ -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;
avcodec_set_dimensions(avctx, width, height);
}
@@ -1039,17 +1051,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);
}
@@ -1085,6 +1093,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;
@@ -1096,11 +1107,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 6a19955..df878c5 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
*/
@@ -196,6 +196,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;
@@ -340,6 +341,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;
@@ -348,13 +353,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) {
@@ -362,12 +370,17 @@ 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)) {
@@ -393,6 +406,19 @@ static int decode_band_hdr(IVI45DecContext *ctx, IVIBandDesc *band,
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 */
if (!get_bits1(&ctx->gb))
@@ -435,6 +461,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;
}
@@ -453,7 +484,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;
@@ -468,6 +499,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;
@@ -505,8 +541,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 == FRAMETYPE_INTRA ||
ctx->frame_type == FRAMETYPE_INTRA1) {
@@ -554,6 +592,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 9b8945a..0ea4f40 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
*/
diff --git a/libavcodec/indeo5.c b/libavcodec/indeo5.c
index 83bbcbb..e48cb43 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
*/
@@ -59,7 +59,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;
@@ -81,8 +81,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;
@@ -120,6 +120,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 */
}
@@ -133,6 +134,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;
@@ -185,8 +191,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) {
@@ -196,6 +204,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];
@@ -232,6 +244,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 */
@@ -322,6 +335,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 scaleable stream\n");
+ ctx->frame_type = FRAMETYPE_INTER;
+ return AVERROR_INVALIDDATA;
+ }
+
if (ctx->frame_type != FRAMETYPE_NULL) {
ctx->frame_flags = get_bits(&ctx->gb, 8);
@@ -432,7 +451,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;
@@ -478,7 +497,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);
@@ -489,7 +508,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 */
@@ -515,7 +534,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);
@@ -538,6 +557,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++;
@@ -646,7 +674,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 78e3d52..e5462e7 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
*/
@@ -54,14 +54,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) {
@@ -77,7 +77,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))
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index f57bedc..96976e1 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
*/
@@ -77,6 +77,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.
@@ -86,6 +94,19 @@ typedef struct AVCodecInternal {
AVFrame to_free;
FramePool *pool;
+
+ /**
+ * 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;
} AVCodecInternal;
struct AVCodecDefault {
@@ -111,6 +132,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);
@@ -128,6 +161,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.
@@ -137,6 +171,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);
/**
@@ -145,6 +181,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);
}
@@ -162,8 +200,29 @@ 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);
+
+/**
+ * Call avcodec_close recursively, counterpart to avcodec_open2_recursive.
+ */
+int ff_codec_close_recursive(AVCodecContext *avctx);
+
+/**
+ * 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);
#endif /* AVCODEC_INTERNAL_H */
diff --git a/libavcodec/interplayvideo.c b/libavcodec/interplayvideo.c
index 7d785e3..7ac1456 100644
--- a/libavcodec/interplayvideo.c
+++ b/libavcodec/interplayvideo.c
@@ -2,20 +2,20 @@
* Interplay MVE Video Decoder
* 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;
@@ -528,7 +528,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 +917,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 +925,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 +970,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 0cad9da..ffdfb07 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"
@@ -126,13 +127,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){
@@ -143,8 +144,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);
}
@@ -266,15 +265,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);
@@ -327,7 +324,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;
@@ -344,8 +341,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;
@@ -440,7 +437,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->dsp.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:
@@ -537,7 +534,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->dsp.clear_block(s->block[0]);
if(chroma){
@@ -646,7 +643,7 @@ static int x8_decode_intra_mb(IntraX8Context* const w, const int chroma){
s->current_picture.f.linesize[!!chroma] );
}
if(!zeros_only)
- s->dsp.idct_add ( s->dest[chroma],
+ w->wdsp.idct_add (s->dest[chroma],
s->current_picture.f.linesize[!!chroma],
s->block[0] );
@@ -695,12 +692,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->dsp.idct_permutation, &w->scantable[0], ff_wmv1_scantable[0]);
- ff_init_scantable(s->dsp.idct_permutation, &w->scantable[1], ff_wmv1_scantable[2]);
- ff_init_scantable(s->dsp.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);
}
@@ -720,6 +721,7 @@ av_cold void ff_intrax8_common_end(IntraX8Context * w)
* The parent codec must call MPV_frame_start(), ff_er_frame_start() before calling this function.
* The parent codec must call ff_er_frame_end(), MPV_frame_end() after calling this function.
* This function does not use 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
@@ -727,7 +729,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 2ddc227..2cad21d 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"
@@ -100,11 +101,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);
@@ -127,6 +126,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;
}
}
@@ -205,16 +205,19 @@ static int h263_decode_gob_header(MpegEncContext *s)
* @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)
+const uint8_t *ff_h263_find_resync_marker(MpegEncContext *s, const uint8_t *av_restrict p, const uint8_t *av_restrict end)
{
- assert(p < end);
+ av_assert2(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;
+ if(s->resync_marker){
+ int prefix_len = ff_mpeg4_get_video_packet_prefix_length(s);
+ for(;p<end; p+=2){
+ if(!*p){
+ if (!p[-1] && ((p[1] >> (23-prefix_len)) == 1)) return p - 1;
+ else if (!p[ 1] && ((p[2] >> (23-prefix_len)) == 1)) return p;
+ }
}
}
return end+2;
@@ -344,7 +347,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)) {
@@ -481,7 +484,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)
@@ -562,11 +565,13 @@ static int h263_skip_b_part(MpegEncContext *s, int cbp)
{
LOCAL_ALIGNED_16(int16_t, dblock, [64]);
int i, mbi;
+ int bli[6];
/* we have to set s->mb_intra to zero to decode B-part of PB-frame correctly
* but real value should be restored in order to be used later (in OBMC condition)
*/
mbi = s->mb_intra;
+ memcpy(bli, s->block_last_index, sizeof(bli));
s->mb_intra = 0;
for (i = 0; i < 6; i++) {
if (h263_decode_block(s, dblock, i, cbp&32) < 0)
@@ -574,6 +579,7 @@ static int h263_skip_b_part(MpegEncContext *s, int cbp)
cbp+=cbp;
}
s->mb_intra = mbi;
+ memcpy(s->block_last_index, bli, sizeof(bli));
return 0;
}
@@ -603,7 +609,7 @@ int ff_h263_decode_mb(MpegEncContext *s,
const int xy= s->mb_x + s->mb_y * s->mb_stride;
int cbpb = 0, pb_mv_count = 0;
- assert(!s->h263_pred);
+ av_assert2(!s->h263_pred);
if (s->pict_type == AV_PICTURE_TYPE_P) {
do{
@@ -743,7 +749,7 @@ 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);
@@ -868,6 +874,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) {
@@ -957,6 +967,8 @@ int ff_h263_decode_picture_header(MpegEncContext *s)
s->h263_aic = get_bits1(&s->gb); /* Advanced Intra Coding (AIC) */
s->loop_filter= get_bits1(&s->gb);
s->unrestricted_mv = s->umvplus || s->obmc || s->loop_filter;
+ if(s->avctx->lowres)
+ s->loop_filter = 0;
s->h263_slice_structured= get_bits1(&s->gb);
if (get_bits1(&s->gb) != 0) {
@@ -1024,6 +1036,7 @@ int ff_h263_decode_picture_header(MpegEncContext *s)
height = ff_h263_format[format][1];
s->avctx->sample_aspect_ratio= (AVRational){12,11};
}
+ s->avctx->sample_aspect_ratio.den <<= s->ehc_mode;
if ((width == 0) || (height == 0))
return -1;
s->width = width;
@@ -1068,6 +1081,10 @@ int ff_h263_decode_picture_header(MpegEncContext *s)
s->qscale = get_bits(&s->gb, 5);
}
+ if (s->width == 0 || s->height == 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "dimensions 0\n");
+ return -1;
+ }
s->mb_width = (s->width + 15) / 16;
s->mb_height = (s->height + 15) / 16;
s->mb_num = s->mb_width * s->mb_height;
@@ -1124,7 +1141,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 0f59944..2db9581 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
*/
@@ -225,7 +225,7 @@ 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);
@@ -267,7 +267,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;
@@ -392,7 +392,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);
@@ -545,7 +545,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) {
@@ -726,8 +726,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;
diff --git a/libavcodec/ivi_common.c b/libavcodec/ivi_common.c
index 7ca53b7..4179852 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
*/
@@ -79,12 +79,9 @@ static int ivi_mc(IVIBandDesc *band, ivi_mc_func mc,
int min_size = band->pitch * (band->blk_size - 1) + band->blk_size;
int ref_size = (mc_type > 1) * band->pitch + (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);
mc(band->buf + offs, band->ref_buf + ref_offs, band->pitch, mc_type);
@@ -110,7 +107,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
@@ -224,7 +221,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)
@@ -259,6 +256,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]);
@@ -328,6 +326,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);
@@ -370,8 +369,10 @@ static int ivi_init_tiles(IVIBandDesc *band, IVITile *ref_tile,
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++;
}
@@ -396,6 +397,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];
@@ -453,10 +456,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;
@@ -547,6 +546,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);
@@ -734,6 +738,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++;
@@ -869,6 +889,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);
@@ -892,7 +916,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);
@@ -924,6 +949,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
@@ -980,6 +1009,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);
@@ -990,6 +1020,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;
@@ -999,6 +1030,8 @@ 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"); }
@@ -1015,11 +1048,12 @@ int ff_ivi_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
av_log(avctx, AV_LOG_ERROR, "Buffer contains IP frames!\n");
}
+ if (!ctx->is_nonnull_frame(ctx))
+ return buf_size;
+
avcodec_set_dimensions(avctx, ctx->planes[0].width, ctx->planes[0].height);
- 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 (avctx->codec_id == AV_CODEC_ID_INDEO4)
diff --git a/libavcodec/ivi_common.h b/libavcodec/ivi_common.h
index fb97c8d..72ab54f 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
*/
@@ -149,6 +149,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
@@ -247,6 +248,7 @@ typedef struct IVI45DecContext {
int (*is_nonnull_frame)(struct IVI45DecContext *ctx);
int gop_invalid;
+ int buf_invalid[3];
} IVI45DecContext;
/** compare some properties of two pictures */
diff --git a/libavcodec/ivi_dsp.c b/libavcodec/ivi_dsp.c
index bd1f523..f5e5e6b 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 */
diff --git a/libavcodec/ivi_dsp.h b/libavcodec/ivi_dsp.h
index 31d37e3..245f01d 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..d9f5eaf
--- a/dev/null
+++ b/libavcodec/j2kenc.c
@@ -0,0 +1,1056 @@
+/*
+ * 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;
+ 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(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(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;
+ avctx->coded_frame= &s->picture;
+
+ 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
--- a/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..b64fac8
--- a/dev/null
+++ b/libavcodec/jacosubdec.c
@@ -0,0 +1,205 @@
+/*
+ * 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"
+
+#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;
+
+#if HAVE_LOCALTIME_R
+ localtime_r(&now, &ltime);
+#else
+ ltime = *localtime(&now);
+#endif
+ 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++);
+ }
+ av_bprintf(dst, "\r\n");
+}
+
+static int jacosub_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_sub_ptr, AVPacket *avpkt)
+{
+ AVSubtitle *sub = data;
+ const char *ptr = avpkt->data;
+
+ if (avpkt->size <= 0)
+ goto end;
+
+ if (*ptr) {
+ AVBPrint buffer;
+ char *dec_sub;
+
+ // 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);
+ av_bprint_finalize(&buffer, &dec_sub);
+ ff_ass_add_rect(sub, dec_sub, avpkt->pts, avpkt->duration, 0);
+ av_free(dec_sub);
+ }
+
+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/jpeg2000.c b/libavcodec/jpeg2000.c
index bf46398..f3658c2 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
*/
@@ -25,6 +25,7 @@
* JPEG 2000 image encoder and decoder common functions
*/
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/mem.h"
#include "avcodec.h"
@@ -40,8 +41,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;
}
@@ -55,8 +55,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)
@@ -81,6 +79,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)
@@ -95,45 +103,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;
}
@@ -204,8 +200,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;
}
@@ -219,16 +215,16 @@ 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);
}
- comp->reslevel = av_malloc_array(codsty->nreslevels, sizeof(*comp->reslevel));
+ comp->reslevel = av_calloc(codsty->nreslevels, sizeof(*comp->reslevel));
if (!comp->reslevel)
return AVERROR(ENOMEM);
/* LOOP on resolution levels */
@@ -276,7 +272,7 @@ int ff_jpeg2000_init_component(Jpeg2000Component *comp,
reslevel->log2_prec_height) -
(reslevel->coord[1][0] >> reslevel->log2_prec_height);
- reslevel->band = av_malloc_array(reslevel->nbands, sizeof(*reslevel->band));
+ reslevel->band = av_calloc(reslevel->nbands, sizeof(*reslevel->band));
if (!reslevel->band)
return AVERROR(ENOMEM);
@@ -324,7 +320,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
@@ -372,8 +368,8 @@ 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);
- band->prec = av_malloc_array(reslevel->num_precincts_x *
- reslevel->num_precincts_y,
+ band->prec = av_calloc(reslevel->num_precincts_x *
+ (uint64_t)reslevel->num_precincts_y,
sizeof(*band->prec));
if (!band->prec)
return AVERROR(ENOMEM);
@@ -429,7 +425,7 @@ int ff_jpeg2000_init_component(Jpeg2000Component *comp,
return AVERROR(ENOMEM);
prec->cblk = av_mallocz_array(prec->nb_codeblocks_width *
- prec->nb_codeblocks_height,
+ (uint64_t)prec->nb_codeblocks_height,
sizeof(*prec->cblk));
if (!prec->cblk)
return AVERROR(ENOMEM);
@@ -481,6 +477,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;
@@ -490,15 +507,19 @@ void ff_jpeg2000_cleanup(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty)
Jpeg2000ResLevel *reslevel = comp->reslevel + reslevelno;
for (bandno = 0; bandno < reslevel->nbands; bandno++) {
- Jpeg2000Band *band = reslevel->band + bandno;
- for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++) {
- Jpeg2000Prec *prec = band->prec + precno;
- av_freep(&prec->zerobits);
- av_freep(&prec->cblkincl);
- av_freep(&prec->cblk);
- }
+ if (reslevel->band) {
+ Jpeg2000Band *band = reslevel->band + bandno;
+ for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++) {
+ if (band->prec) {
+ Jpeg2000Prec *prec = band->prec + precno;
+ av_freep(&prec->zerobits);
+ av_freep(&prec->cblkincl);
+ av_freep(&prec->cblk);
+ }
+ }
- av_freep(&band->prec);
+ av_freep(&band->prec);
+ }
}
av_freep(&reslevel->band);
}
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 cc154c3..b150bc1 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
*/
@@ -25,8 +25,10 @@
* JPEG 2000 image decoder
*/
+#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"
@@ -36,6 +38,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
@@ -53,14 +56,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;
@@ -71,6 +74,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;
@@ -80,7 +87,8 @@ typedef struct Jpeg2000DecoderContext {
int bit_index;
- int16_t curtileno;
+ int curtileno;
+
Jpeg2000Tile *tile;
/*options parameters*/
@@ -94,6 +102,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) {
@@ -151,12 +160,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;
@@ -172,13 +243,18 @@ 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);
return AVERROR_INVALIDDATA;
}
- if (ncomponents > 3) {
+ if (ncomponents > 4) {
avpriv_request_sample(s->avctx, "Support for %d components",
s->ncomponents);
return AVERROR_PATCHWELCOME;
@@ -186,8 +262,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;
@@ -203,21 +278,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;
@@ -238,36 +314,48 @@ 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;
+ }
+ }
+ 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;
}
- 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;
}
+ if (s->avctx->pix_fmt == AV_PIX_FMT_NONE) {
+ 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);
+ }
+ s->avctx->bits_per_raw_sample = s->precision;
return 0;
}
@@ -282,18 +370,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) {
@@ -301,10 +397,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 */
@@ -404,7 +504,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;
@@ -422,7 +522,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);
@@ -482,14 +582,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
@@ -703,25 +801,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 %d 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 %d > data size %zd\n",
- cblk->length, sizeof(cblk->data));
- return AVERROR_INVALIDDATA;
- }
}
}
return 0;
@@ -735,6 +826,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;
@@ -745,7 +839,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,
@@ -808,11 +902,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;
@@ -958,21 +1047,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),
@@ -1034,7 +1127,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;
}
}
@@ -1059,6 +1152,12 @@ static void mct_decode(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile)
int32_t *src[3], i0, i1, i2;
float *srcf[3], i0f, i1f, i2f;
+ 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)
srcf[i] = tile->comp[i].f_data;
@@ -1067,6 +1166,7 @@ static void mct_decode(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile)
for (i = 0; i < 2; i++)
csize *= tile->comp[0].coord[i][1] - tile->comp[0].coord[i][0];
+
switch (tile->codsty[0].transform) {
case FF_DWT97:
for (i = 0; i < csize; i++) {
@@ -1111,19 +1211,21 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
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] ||
@@ -1164,6 +1266,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;
@@ -1172,14 +1281,21 @@ 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 planar = !!picture->data[2];
+ int pixelsize = planar ? 1 : s->ncomponents;
+ 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]) {
@@ -1188,7 +1304,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]) {
@@ -1197,10 +1313,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 {
@@ -1212,13 +1328,20 @@ 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 planar = !!picture->data[2];
+ int pixelsize = planar ? 1 : s->ncomponents;
+ 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));
@@ -1227,7 +1350,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]) {
@@ -1237,10 +1360,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;
}
}
}
@@ -1252,15 +1375,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;
}
@@ -1287,17 +1414,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);
@@ -1306,13 +1437,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);
@@ -1328,6 +1461,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;
@@ -1379,26 +1513,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;
}
@@ -1412,7 +1621,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;
@@ -1434,6 +1644,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;
@@ -1443,15 +1656,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;
@@ -1460,6 +1672,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:
@@ -1491,7 +1706,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,
@@ -1507,6 +1722,7 @@ AVCodec ff_jpeg2000_decoder = {
.priv_data_size = sizeof(Jpeg2000DecoderContext),
.init_static_data = jpeg2000_init_static_data,
.decode = jpeg2000_decode_frame,
- .priv_class = &class,
+ .priv_class = &jpeg2000_class,
+ .max_lowres = 5,
.profiles = NULL_IF_CONFIG_SMALL(profiles)
};
diff --git a/libavcodec/jpeg2000dwt.c b/libavcodec/jpeg2000dwt.c
index 6642a53..266edec 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;
@@ -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 9aaa18b..b5be812 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
*/
@@ -57,6 +57,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 4bf9562..2dc3832 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
*/
@@ -41,7 +41,7 @@ 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];
@@ -99,6 +99,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..0e344f5 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
@@ -207,6 +207,9 @@ 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;
@@ -276,9 +279,9 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near,
JLSState *state;
int off = 0, stride = 1, width, shift, ret = 0;
- zero = av_mallocz(s->picture_ptr->linesize[0]);
+ zero = av_mallocz(s->picture.linesize[0]);
last = zero;
- cur = s->picture_ptr->data[0];
+ cur = s->picture.data[0];
state = av_mallocz(sizeof(JLSState));
/* initialize JPEG-LS state from JPEG parameters */
@@ -297,21 +300,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++) {
@@ -323,7 +328,7 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near,
t = *((uint16_t *)last);
}
last = cur;
- cur += s->picture_ptr->linesize[0];
+ cur += s->picture.linesize[0];
if (s->restart_interval && !--s->restart_count) {
align_get_bits(&s->gb);
@@ -333,12 +338,13 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near,
} else if (ilv == 1) { /* line interleaving */
int j;
int Rc[3] = { 0, 0, 0 };
- memset(cur, 0, s->picture_ptr->linesize[0]);
- width = s->width * 3;
+ stride = (s->nb_components > 1) ? 3 : 1;
+ memset(cur, 0, s->picture.linesize[0]);
+ 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) {
@@ -347,7 +353,7 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near,
}
}
last = cur;
- cur += s->picture_ptr->linesize[0];
+ cur += s->picture.linesize[0];
}
} else if (ilv == 2) { /* sample interleaving */
avpriv_report_missing_feature(s->avctx, "Sample interleaved images");
@@ -355,26 +361,73 @@ 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.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.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;
w = s->width * s->nb_components;
if (s->bits <= 8) {
- uint8_t *src = s->picture_ptr->data[0];
+ uint8_t *src = s->picture.data[0];
for (i = 0; i < s->height; i++) {
for (x = off; x < w; x += stride)
src[x] <<= shift;
- src += s->picture_ptr->linesize[0];
+ src += s->picture.linesize[0];
}
} else {
- uint16_t *src = (uint16_t *)s->picture_ptr->data[0];
+ uint16_t *src = (uint16_t *)s->picture.data[0];
for (i = 0; i < s->height; i++) {
for (x = 0; x < w; x++)
src[x] <<= shift;
- src += s->picture_ptr->linesize[0] / 2;
+ src += s->picture.linesize[0] / 2;
}
}
}
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 9f1fc1f..308d6d3 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"
@@ -268,11 +269,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);
@@ -313,7 +312,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) {
@@ -364,8 +367,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
diff --git a/libavcodec/jrevdct.c b/libavcodec/jrevdct.c
index e6846a1..91780b2 100644
--- a/libavcodec/jrevdct.c
+++ b/libavcodec/jrevdct.c
@@ -940,3 +940,216 @@ void ff_j_rev_dct(DCTBLOCK data)
dataptr++; /* advance pointer to next column */
}
}
+
+#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
diff --git a/libavcodec/jvdec.c b/libavcodec/jvdec.c
index 6b82c6a..740884a 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
*/
@@ -33,7 +33,7 @@
typedef struct JvContext {
DSPContext dsp;
- AVFrame frame;
+ AVFrame *frame;
uint32_t palette[AVPALETTE_COUNT];
int palette_has_changed;
} JvContext;
@@ -43,6 +43,9 @@ static av_cold int decode_init(AVCodecContext *avctx)
JvContext *s = avctx->priv_data;
avctx->pix_fmt = AV_PIX_FMT_PAL8;
ff_dsputil_init(&s->dsp, avctx);
+ s->frame = av_frame_alloc();
+ if (!s->frame)
+ return AVERROR(ENOMEM);
return 0;
}
@@ -134,71 +137,74 @@ static int decode_frame(AVCodecContext *avctx,
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)
- decode8x8(&gb, s->frame.data[0] + j*s->frame.linesize[0] + i,
- s->frame.linesize[0], &s->dsp);
+ decode8x8(&gb, s->frame->data[0] + j * s->frame->linesize[0] + i,
+ s->frame->linesize[0], &s->dsp);
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);
return AVERROR_INVALIDDATA;
}
}
- 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;
}
if (video_size) {
- s->frame.key_frame = 1;
- s->frame.pict_type = AV_PICTURE_TYPE_I;
- s->frame.palette_has_changed = s->palette_has_changed;
+ s->frame->key_frame = 1;
+ s->frame->pict_type = AV_PICTURE_TYPE_I;
+ s->frame->palette_has_changed = s->palette_has_changed;
s->palette_has_changed = 0;
- memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE);
+ memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE);
- if ((ret = av_frame_ref(data, &s->frame)) < 0)
+ if ((ret = av_frame_ref(data, s->frame)) < 0)
return ret;
*got_frame = 1;
}
- return buf_size;
+ return avpkt->size;
}
static av_cold int decode_close(AVCodecContext *avctx)
{
JvContext *s = avctx->priv_data;
- av_frame_unref(&s->frame);
+ av_frame_free(&s->frame);
return 0;
}
diff --git a/libavcodec/kbdwin.c b/libavcodec/kbdwin.c
index 1b7313d..5a62e9d 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;
diff --git a/libavcodec/kbdwin.h b/libavcodec/kbdwin.h
index 89b569a..4b93975 100644
--- a/libavcodec/kbdwin.h
+++ b/libavcodec/kbdwin.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/kgv1dec.c b/libavcodec/kgv1dec.c
index 1774f36..f793137 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,15 +31,14 @@
#include "internal.h"
typedef struct {
- AVCodecContext *avctx;
- AVFrame prev;
+ AVFrame *prev;
} KgvContext;
static void decode_flush(AVCodecContext *avctx)
{
KgvContext * const c = avctx->priv_data;
- av_frame_unref(&c->prev);
+ av_frame_unref(c->prev);
}
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
@@ -50,7 +49,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;
@@ -65,7 +64,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return res;
if (w != avctx->width || h != avctx->height) {
- av_frame_unref(&c->prev);
+ av_frame_unref(c->prev);
avcodec_set_dimensions(avctx, w, h);
}
@@ -73,9 +72,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if ((res = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
return res;
- out = (uint16_t *) frame->data[0];
- if (c->prev.data[0]) {
- prev = (uint16_t *) c->prev.data[0];
+ out = frame->data[0];
+ if (c->prev->data[0]) {
+ prev = c->prev->data[0];
} else {
prev = NULL;
}
@@ -83,16 +82,15 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
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
@@ -110,7 +108,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) {
@@ -119,8 +117,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;
@@ -135,27 +132,20 @@ 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;
}
}
if (outcnt - maxcnt)
av_log(avctx, AV_LOG_DEBUG, "frame finished with %d diff\n", outcnt - maxcnt);
- av_frame_unref(&c->prev);
- if ((res = av_frame_ref(&c->prev, frame)) < 0)
+ av_frame_unref(c->prev);
+ if ((res = av_frame_ref(c->prev, frame)) < 0)
return res;
*got_frame = 1;
@@ -167,16 +157,20 @@ static av_cold int decode_init(AVCodecContext *avctx)
{
KgvContext * const c = avctx->priv_data;
- c->avctx = avctx;
avctx->pix_fmt = AV_PIX_FMT_RGB555;
avctx->flags |= CODEC_FLAG_EMU_EDGE;
+ c->prev = av_frame_alloc();
+ if (!c->prev)
+ return AVERROR(ENOMEM);
+
return 0;
}
static av_cold int decode_end(AVCodecContext *avctx)
{
- decode_flush(avctx);
+ KgvContext * const c = avctx->priv_data;
+ av_frame_free(&c->prev);
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 ce2942a..0a4d23e 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
*/
@@ -157,8 +157,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;
}
@@ -174,7 +174,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];
}
@@ -249,8 +257,8 @@ static void lag_pred_line(LagarithContext *l, uint8_t *buf,
if (!line) {
/* Left prediction only for first line */
- L = l->dsp.add_hfyu_left_prediction(buf + 1, buf + 1,
- width - 1, buf[0]);
+ L = l->dsp.add_hfyu_left_prediction(buf, buf,
+ width, 0);
} else {
/* Left pixel is actually prev_row[width] */
L = buf[width - stride - 1];
@@ -276,11 +284,12 @@ static void lag_pred_line_yuy2(LagarithContext *l, uint8_t *buf,
int L, TL;
if (!line) {
- if (is_luma) {
- buf++;
- width--;
- }
- l->dsp.add_hfyu_left_prediction(buf + 1, buf + 1, width - 1, buf[0]);
+ L= buf[0];
+ if (is_luma)
+ buf[0] = 0;
+ l->dsp.add_hfyu_left_prediction(buf, buf, width, 0);
+ if (is_luma)
+ buf[0] = L;
return;
}
if (line == 1) {
@@ -293,14 +302,17 @@ static void lag_pred_line_yuy2(LagarithContext *l, uint8_t *buf,
L += buf[i];
buf[i] = L;
}
- buf += HEAD;
- width -= HEAD;
+ for (; i<width; i++) {
+ L = mid_pred(L&0xFF, buf[i-stride], (L + buf[i-stride] - TL)&0xFF) + buf[i];
+ TL = buf[i-stride];
+ buf[i]= L;
+ }
} else {
TL = buf[width - (2 * stride) - 1];
L = buf[width - stride - 1];
+ l->dsp.add_hfyu_median_prediction(buf, buf - stride, buf, width,
+ &L, &TL);
}
- l->dsp.add_hfyu_median_prediction(buf, buf - stride, buf, width,
- &L, &TL);
}
static int lag_decode_line(LagarithContext *l, lag_rac *rac,
@@ -374,7 +386,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));
@@ -394,7 +406,7 @@ output_zeros:
dst += i;
}
}
- return src_start - src;
+ return src - src_start;
}
@@ -407,7 +419,7 @@ 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;
@@ -415,8 +427,14 @@ static int lag_decode_arith_plane(LagarithContext *l, uint8_t *dst,
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;
@@ -499,7 +517,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;
@@ -508,6 +526,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;
@@ -519,18 +538,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;
@@ -542,10 +596,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;
@@ -553,7 +605,7 @@ static int lag_decode_frame(AVCodecContext *avctx,
if (!l->rgb_planes) {
l->rgb_stride = FFALIGN(avctx->width, 16);
- l->rgb_planes = av_malloc(l->rgb_stride * avctx->height * planes + 1);
+ l->rgb_planes = av_malloc(l->rgb_stride * avctx->height * 4 + 16);
if (!l->rgb_planes) {
av_log(avctx, AV_LOG_ERROR, "cannot allocate temporary buffer\n");
return AVERROR(ENOMEM);
@@ -561,14 +613,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,
@@ -602,10 +653,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 ||
@@ -628,9 +677,10 @@ static int lag_decode_frame(AVCodecContext *avctx,
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 ||
@@ -654,7 +704,7 @@ static int lag_decode_frame(AVCodecContext *avctx,
default:
av_log(avctx, AV_LOG_ERROR,
"Unsupported Lagarith frame type: %#x\n", frametype);
- return -1;
+ return AVERROR_PATCHWELCOME;
}
*got_frame = 1;
diff --git a/libavcodec/lagarithrac.c b/libavcodec/lagarithrac.c
index edfb18f..895acb0 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,11 +41,11 @@ 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 - 8, 0);
for (i = j = 0; i < 256; i++) {
unsigned r = i << l->hash_shift;
diff --git a/libavcodec/lagarithrac.h b/libavcodec/lagarithrac.h
index e4f066e..9892d11 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
*/
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 4d97948..57519ea 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;
@@ -175,10 +182,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
@@ -187,8 +192,14 @@ 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) {
+ ;
+ } else if (c->flags & FLAG_MULTITHREAD) {
mthread_inlen = AV_RL32(encoded);
+ 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(encoded+4);
mthread_outlen = FFMIN(mthread_outlen, c->decomp_size);
@@ -472,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");
@@ -497,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;
@@ -527,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 1f9f046..1dac307 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"
@@ -54,7 +56,6 @@
typedef struct LclEncContext {
AVCodecContext *avctx;
- AVFrame pic;
// Image type
int imgtype;
@@ -71,23 +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;
- AVFrame * const p = &c->pic;
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;
- }
-
- *p = *pict;
- p->pict_type= AV_PICTURE_TYPE_I;
- p->key_frame= 1;
+ 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");
@@ -136,13 +129,15 @@ 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->coded_frame= &c->pic;
+ avctx->extradata = av_mallocz(8 + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!avctx->extradata)
+ return AVERROR(ENOMEM);
- // 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;
diff --git a/libavcodec/libaacplus.c b/libavcodec/libaacplus.c
new file mode 100644
index 0000000..545e240
--- a/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..69e653c 100644
--- a/libavcodec/libavcodec.v
+++ b/libavcodec/libavcodec.v
@@ -1,4 +1,31 @@
LIBAVCODEC_$MAJOR {
global: av*;
+ #deprecated, remove after next bump
+ audio_resample;
+ audio_resample_close;
+ dsputil_init;
+ ff_dsputil_init;
+ ff_find_pix_fmt;
+ ff_framenum_to_drop_timecode;
+ ff_framenum_to_smtpe_timecode;
+ ff_raw_pix_fmt_tags;
+ ff_init_smtpe_timecode;
+ ff_fft*;
+ ff_mdct*;
+ ff_dct*;
+ ff_rdft*;
+ ff_prores_idct_put_10_sse2;
+ ff_simple_idct*;
+ ff_aanscales;
+ ff_faan*;
+ ff_mmx_idct;
+ ff_fdct*;
+ fdct_ifast;
+ j_rev_dct;
+ ff_mmxext_idct;
+ ff_idct_xvid*;
+ ff_jpeg_fdct*;
+ ff_dnxhd_get_cid_table;
+ ff_dnxhd_cid_table;
local: *;
};
diff --git a/libavcodec/libcelt_dec.c b/libavcodec/libcelt_dec.c
new file mode 100644
index 0000000..4e62fe5
--- a/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 9b5b11a..477669a 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->delay = 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 e459733..bc3802c 100644
--- a/libavcodec/libfdk-aacdec.c
+++ b/libavcodec/libfdk-aacdec.c
@@ -2,20 +2,20 @@
* AAC decoder wrapper
* 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/libavcodec/libfdk-aacenc.c b/libavcodec/libfdk-aacenc.c
index 4827169..755b76f 100644
--- a/libavcodec/libfdk-aacenc.c
+++ b/libavcodec/libfdk-aacenc.c
@@ -2,20 +2,20 @@
* AAC encoder wrapper
* 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
*/
@@ -330,10 +330,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/libgsm.c b/libavcodec/libgsm.c
index dfab005..5107bfe 100644
--- a/libavcodec/libgsm.c
+++ b/libavcodec/libgsm.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,6 +140,7 @@ AVCodec ff_libgsm_ms_encoder = {
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
};
+#endif
typedef struct LibGSMDecodeContext {
struct gsm_state *state;
@@ -145,7 +151,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();
@@ -191,10 +198,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++) {
@@ -219,6 +224,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"),
@@ -231,7 +237,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"),
@@ -244,3 +251,4 @@ AVCodec ff_libgsm_ms_decoder = {
.flush = libgsm_flush,
.capabilities = CODEC_CAP_DR1,
};
+#endif
diff --git a/libavcodec/libilbc.c b/libavcodec/libilbc.c
index af693bd..898fe83 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,10 +93,8 @@ 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);
@@ -127,7 +128,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,10 +167,8 @@ 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);
diff --git a/libavcodec/libmp3lame.c b/libavcodec/libmp3lame.c
index ce0e9c8..0fb9c6a 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;
@@ -48,6 +48,7 @@ typedef struct LAMEContext {
int buffer_index;
int buffer_size;
int reservoir;
+ int joint_stereo;
float *samples_flt[2];
AudioFrameQueue afq;
AVFloatDSPContext fdsp;
@@ -99,8 +100,9 @@ static av_cold int mp3lame_encode_init(AVCodecContext *avctx)
if ((s->gfp = lame_init()) == NULL)
return AVERROR(ENOMEM);
+
lame_set_num_channels(s->gfp, avctx->channels);
- lame_set_mode(s->gfp, avctx->channels > 1 ? JOINT_STEREO : MONO);
+ lame_set_mode(s->gfp, avctx->channels > 1 ? s->joint_stereo ? JOINT_STEREO : STEREO : MONO);
/* sample rate */
lame_set_in_samplerate (s->gfp, avctx->sample_rate);
@@ -113,11 +115,11 @@ static av_cold int mp3lame_encode_init(AVCodecContext *avctx)
lame_set_quality(s->gfp, avctx->compression_level);
/* rate control */
- if (avctx->flags & CODEC_FLAG_QSCALE) {
+ if (avctx->flags & CODEC_FLAG_QSCALE) { // VBR
lame_set_VBR(s->gfp, vbr_default);
lame_set_VBR_quality(s->gfp, avctx->global_quality / (float)FF_QP2LAMBDA);
} else {
- if (avctx->bit_rate)
+ if (avctx->bit_rate) // CBR
lame_set_brate(s->gfp, avctx->bit_rate / 1000);
}
@@ -242,10 +244,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);
@@ -263,7 +263,8 @@ 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 },
+ { "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 },
{ NULL },
};
diff --git a/libavcodec/libopencore-amr.c b/libavcodec/libopencore-amr.c
index 6b45959..75c467f 100644
--- a/libavcodec/libopencore-amr.c
+++ b/libavcodec/libopencore-amr.c
@@ -2,20 +2,20 @@
* AMR Audio decoder stub
* 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);
}
@@ -238,10 +237,8 @@ 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) {
@@ -270,7 +267,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 +291,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 +333,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 +344,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 ca824c6..734b54f 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/intreadwrite.h"
@@ -35,76 +34,69 @@
#include "avcodec.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
// pix_fmts with lower bpp have to be listed before
// similar pix_fmts with higher bpp.
-#define RGB_PIXEL_FORMATS AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, \
- AV_PIX_FMT_RGB48
-
-#define GRAY_PIXEL_FORMATS AV_PIX_FMT_GRAY8, AV_PIX_FMT_Y400A, \
- 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 RGB_PIXEL_FORMATS 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 any_pix_fmts[] = {RGB_PIXEL_FORMATS,
- GRAY_PIXEL_FORMATS,
- YUV_PIXEL_FORMATS,
- XYZ_PIXEL_FORMATS};
+static const enum AVPixelFormat libopenjpeg_rgb_pix_fmts[] = {RGB_PIXEL_FORMATS};
+static const enum AVPixelFormat libopenjpeg_gray_pix_fmts[] = {GRAY_PIXEL_FORMATS};
+static const enum AVPixelFormat libopenjpeg_yuv_pix_fmts[] = {YUV_PIXEL_FORMATS};
+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;
- 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;
- 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;
- case 1:
- match = match &&
- desc->comp[0].depth_minus1 + 1 >= img->comps[0].prec &&
- 1 == img->comps[0].dx &&
- 1 == img->comps[0].dy;
+ case 4: match = match && 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 >= 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 >= 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 >= image->comps[0].prec &&
+ 1 == image->comps[0].dx &&
+ 1 == image->comps[0].dy;
default:
break;
}
@@ -112,28 +104,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;
}
@@ -162,11 +153,9 @@ 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];
@@ -178,12 +167,10 @@ static void libopenjpeg_copy_to_packed8(AVFrame *picture, opj_image_t *image)
}
}
-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);
@@ -198,8 +185,7 @@ static void libopenjpeg_copy_to_packed16(AVFrame *picture, opj_image_t *image)
}
}
-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;
@@ -217,18 +203,20 @@ 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(16 - 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 = *comp_data << adjust[index];
img_ptr++;
comp_data++;
}
@@ -282,9 +270,7 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx,
return -1;
}
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);
@@ -310,11 +296,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;
- }
-
if (av_image_check_size(width, height, 0, avctx) < 0) {
av_log(avctx, AV_LOG_ERROR,
"%dx%d dimension invalid.\n", width, height);
@@ -332,20 +313,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 (ff_thread_get_buffer(avctx, &frame, 0) < 0) {
- av_log(avctx, AV_LOG_ERROR, "ff_thread_get_buffer() failed\n");
+ if (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);
@@ -415,11 +393,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,
@@ -435,5 +412,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 f2f98cd..c7769f7 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,36 +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_GRAY8A:
case AV_PIX_FMT_GRAY16:
- case AV_PIX_FMT_Y400A:
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:
@@ -105,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:
@@ -123,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;
}
@@ -151,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) {
@@ -168,120 +227,248 @@ static av_cold int libopenjpeg_encode_init(AVCodecContext *avctx)
return AVERROR(ENOMEM);
}
- avctx->coded_frame = avcodec_alloc_frame();
- 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 = avcodec_alloc_frame();
+ 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) {
+ 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;
+}
+
+// for XYZ 12 bit
+static int libopenjpeg_copy_packed12(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_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 void libopenjpeg_copy_packed16(AVCodecContext *avctx,
- const AVFrame *frame, opj_image_t *image)
+static int libopenjpeg_copy_packed16(AVCodecContext *avctx, const AVFrame *frame, opj_image_t *image)
{
int compno;
- int x, y;
- int image_index, frame_index;
+ int x;
+ int y;
+ int *image_line;
+ int frame_index;
const int numcomps = image->numcomps;
uint16_t *frame_ptr = (uint16_t*)frame->data[0];
for (compno = 0; compno < numcomps; ++compno) {
+ if (image->comps[compno].w > frame->linesize[0] / numcomps) {
+ av_log(avctx, AV_LOG_ERROR, "Error: frame's linesize is too small for the image\n");
+ return 0;
+ }
+ }
+
+ for (compno = 0; compno < numcomps; ++compno) {
for (y = 0; y < avctx->height; ++y) {
- image_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) {
- width = avctx->width / image->comps[compno].dx;
+ 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) {
- width = avctx->width / image->comps[compno].dx;
+ 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,
@@ -290,24 +477,42 @@ 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_Y400A:
- libopenjpeg_copy_packed8(avctx, frame, image);
+ case AV_PIX_FMT_GRAY8A:
+ 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:
- libopenjpeg_copy_packed16(avctx, frame, image);
+ case AV_PIX_FMT_RGBA64:
+ 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 = *frame;
+ 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);
+ }
break;
case AV_PIX_FMT_GRAY8:
case AV_PIX_FMT_YUV410P:
@@ -317,19 +522,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 +561,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 +588,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 +619,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,
@@ -422,15 +645,23 @@ AVCodec ff_libopenjpeg_encoder = {
.close = libopenjpeg_encode_close,
.capabilities = 0,
.pix_fmts = (const enum AVPixelFormat[]) {
- AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB48,
- AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16, AV_PIX_FMT_Y400A,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB48, AV_PIX_FMT_RGBA64,
+ AV_PIX_FMT_GBR24P,
+ AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, 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..2409de2 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,11 +93,22 @@ 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->internal->skip_samples = opus->pre_skip;
avc->delay = 3840; /* Decoder delay (in samples) at 48kHz */
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 592b8ca..97d3bba 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. */
@@ -306,6 +313,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) {
ff_af_queue_add(&opus->afq, frame);
@@ -324,10 +332,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,
@@ -349,12 +355,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 == NULL) {
+ 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 7e258e3..f20633a 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 e4789ee..43530e8 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
*/
@@ -27,14 +27,12 @@
* (http://dirac.sourceforge.net/specification.html).
*/
-#undef NDEBUG
-#include <assert.h>
-
#include <schroedinger/schro.h>
#include <schroedinger/schrodebug.h>
#include <schroedinger/schrovideoformat.h>
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "internal.h"
#include "libschroedinger.h"
@@ -302,8 +300,7 @@ static int libschroedinger_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
case SCHRO_STATE_HAVE_BUFFER:
case SCHRO_STATE_END_OF_STREAM:
enc_buf = schro_encoder_pull(encoder, &presentation_frame);
- assert(enc_buf->length > 0);
- assert(enc_buf->length <= buf_size);
+ av_assert0(enc_buf->length > 0);
parse_code = enc_buf->data[4];
/* All non-frame data is prepended to actual frame data to
@@ -377,10 +374,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
--- a/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..afe1176 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
*/
@@ -50,7 +50,18 @@ static av_cold int libspeex_decode_init(AVCodecContext *avctx)
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 +84,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 */
@@ -116,10 +128,8 @@ static int libspeex_decode_frame(AVCodecContext *avctx, void *data,
/* 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
diff --git a/libavcodec/libspeexenc.c b/libavcodec/libspeexenc.c
index 651d7ac..aba4618 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..bb49d8a
--- a/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 = (AVFrame*)av_mallocz(sizeof(AVFrame));
+ 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 == NULL) {
+ 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 b885664..9fa096f 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"
@@ -60,21 +60,26 @@ static int concatenate_packet(unsigned int* offset,
const char* message = NULL;
uint8_t* newdata = NULL;
int newsize = avc_context->extradata_size + 2 + packet->bytes;
+ int ret;
if (packet->bytes < 0) {
message = "ogg_packet has negative size";
+ ret = AVERROR_INVALIDDATA;
} else if (packet->bytes > 0xffff) {
message = "ogg_packet is larger than 65535 bytes";
+ ret = AVERROR_INVALIDDATA;
} else if (newsize < avc_context->extradata_size) {
message = "extradata_size would overflow";
+ ret = AVERROR_INVALIDDATA;
} else {
newdata = av_realloc(avc_context->extradata, newsize);
if (!newdata)
message = "av_realloc failed";
+ ret = AVERROR(ENOMEM);
}
if (message) {
av_log(avc_context, AV_LOG_ERROR, "concatenate_packet failed: %s\n", message);
- return -1;
+ return ret;
}
avc_context->extradata = newdata;
@@ -96,7 +101,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 +118,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 +132,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 +144,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 +153,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 +165,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 +202,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 +223,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 +233,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 +258,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 +281,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 +295,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 +314,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 +332,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
new file mode 100644
index 0000000..dc4efe5
--- a/dev/null
+++ b/libavcodec/libtwolame.c
@@ -0,0 +1,198 @@
+/*
+ * Interface to libtwolame for mp2 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
+ */
+
+/**
+ * @file
+ * Interface to libtwolame for mp2 encoding.
+ */
+
+#include <twolame.h>
+
+#include "libavutil/opt.h"
+#include "avcodec.h"
+#include "internal.h"
+#include "mpegaudio.h"
+
+typedef struct TWOLAMEContext {
+ AVClass *class;
+ int mode;
+ int psymodel;
+ int energy;
+ int error_protection;
+ int copyright;
+ int original;
+
+ twolame_options *glopts;
+ int64_t next_pts;
+} TWOLAMEContext;
+
+static av_cold int twolame_encode_close(AVCodecContext *avctx)
+{
+ TWOLAMEContext *s = avctx->priv_data;
+ twolame_close(&s->glopts);
+ return 0;
+}
+
+static av_cold int twolame_encode_init(AVCodecContext *avctx)
+{
+ TWOLAMEContext *s = avctx->priv_data;
+ int ret;
+
+ avctx->frame_size = TWOLAME_SAMPLES_PER_FRAME;
+
+ s->glopts = twolame_init();
+ if (!s->glopts)
+ return AVERROR(ENOMEM);
+
+ twolame_set_verbosity(s->glopts, 0);
+ twolame_set_mode(s->glopts, s->mode);
+ twolame_set_psymodel(s->glopts, s->psymodel);
+ twolame_set_energy_levels(s->glopts, s->energy);
+ twolame_set_error_protection(s->glopts, s->error_protection);
+ twolame_set_copyright(s->glopts, s->copyright);
+ twolame_set_original(s->glopts, s->original);
+
+ 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->flags & CODEC_FLAG_QSCALE || !avctx->bit_rate) {
+ twolame_set_VBR(s->glopts, TRUE);
+ twolame_set_VBR_level(s->glopts, avctx->global_quality);
+ av_log(avctx, AV_LOG_WARNING, "VBR mode is experimental!\n");
+ } else {
+ twolame_set_bitrate(s->glopts, avctx->bit_rate / 1000);
+ }
+
+ if ((ret = twolame_init_params(s->glopts)))
+ goto error;
+
+ return 0;
+error:
+ twolame_encode_close(avctx);
+ return ret;
+}
+
+static int twolame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
+ const AVFrame *frame, int *got_packet_ptr)
+{
+ TWOLAMEContext *s = avctx->priv_data;
+ int ret;
+
+ if ((ret = ff_alloc_packet2(avctx, avpkt, MPA_MAX_CODED_FRAME_SIZE)) < 0)
+ return ret;
+
+ if (frame) {
+ switch (avctx->sample_fmt) {
+ case AV_SAMPLE_FMT_FLT:
+ ret = twolame_encode_buffer_float32_interleaved(s->glopts,
+ frame->data[0],
+ frame->nb_samples,
+ avpkt->data, avpkt->size);
+ break;
+ case AV_SAMPLE_FMT_FLTP:
+ ret = twolame_encode_buffer_float32(s->glopts,
+ frame->data[0], frame->data[1],
+ frame->nb_samples,
+ avpkt->data, avpkt->size);
+ break;
+ case AV_SAMPLE_FMT_S16:
+ ret = twolame_encode_buffer_interleaved(s->glopts,
+ frame->data[0],
+ frame->nb_samples,
+ avpkt->data, avpkt->size);
+ break;
+ case AV_SAMPLE_FMT_S16P:
+ ret = twolame_encode_buffer(s->glopts,
+ frame->data[0], frame->data[1],
+ frame->nb_samples,
+ avpkt->data, avpkt->size);
+ break;
+ default:
+ return AVERROR_BUG;
+ }
+ } else {
+ ret = twolame_encode_flush(s->glopts, avpkt->data, avpkt->size);
+ }
+
+ if (ret > 0) {
+ avpkt->duration = ff_samples_to_time_base(avctx, avctx->frame_size);
+ if (frame) {
+ if (frame->pts != AV_NOPTS_VALUE)
+ avpkt->pts = frame->pts;
+ } else {
+ avpkt->pts = s->next_pts;
+ }
+ if (avpkt->pts != AV_NOPTS_VALUE)
+ s->next_pts = avpkt->pts + avpkt->duration;
+
+ avpkt->size = ret;
+ *got_packet_ptr = 1;
+ return 0;
+ }
+
+ return ret;
+}
+
+#define OFFSET(x) offsetof(TWOLAMEContext, x)
+#define AE AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "mode", "Mpeg Mode", OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = TWOLAME_AUTO_MODE }, TWOLAME_AUTO_MODE, TWOLAME_MONO, AE, "mode"},
+ { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_AUTO_MODE }, 0, 0, AE, "mode" },
+ { "stereo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_STEREO }, 0, 0, AE, "mode" },
+ { "joint_stereo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_JOINT_STEREO }, 0, 0, AE, "mode" },
+ { "dual_channel", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_DUAL_CHANNEL }, 0, 0, AE, "mode" },
+ { "mono", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_MONO }, 0, 0, AE, "mode" },
+ { "psymodel", "Psychoacoustic Model", OFFSET(psymodel), AV_OPT_TYPE_INT, { .i64 = 3 }, -1, 4, AE},
+ { "energy_levels","enable energy levels", OFFSET(energy), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE},
+ { "error_protection","enable CRC error protection", OFFSET(error_protection), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE},
+ { "copyright", "set MPEG Audio Copyright flag", OFFSET(copyright), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE},
+ { "original", "set MPEG Audio Original flag", OFFSET(original), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE},
+ { NULL },
+};
+
+static const AVClass libtwolame_class = {
+ .class_name = "libtwolame encoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_libtwolame_encoder = {
+ .name = "libtwolame",
+ .long_name = NULL_IF_CONFIG_SMALL("libtwolame MP2 (MPEG audio layer 2)"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_MP2,
+ .priv_data_size = sizeof(TWOLAMEContext),
+ .init = twolame_encode_init,
+ .encode2 = twolame_encode_frame,
+ .close = twolame_encode_close,
+ .capabilities = CODEC_CAP_DELAY,
+ .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT,
+ AV_SAMPLE_FMT_FLTP,
+ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_S16P,
+ AV_SAMPLE_FMT_NONE },
+ .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO,
+ AV_CH_LAYOUT_STEREO,
+ 0 },
+ .supported_samplerates = (const int[]){ 16000, 22050, 24000, 32000, 44100, 48000, 0 },
+ .priv_class = &libtwolame_class,
+};
diff --git a/libavcodec/libutvideo.h b/libavcodec/libutvideo.h
new file mode 100644
index 0000000..5fb1174
--- a/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..0fae9f7
--- a/dev/null
+++ b/libavcodec/libutvideodec.cpp
@@ -0,0 +1,212 @@
+/*
+ * 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 != 4*4) {
+ av_log(avctx, AV_LOG_ERROR, "Extradata size mismatch.\n");
+ 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;
+ 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);
+ 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 = avcodec_alloc_frame();
+
+ /* 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_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;
+ *(AVFrame *)data = *pic;
+
+ return avpkt->size;
+}
+
+static av_cold int utvideo_decode_close(AVCodecContext *avctx)
+{
+ UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
+
+ /* Free output */
+ av_freep(&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..44cd42f
--- a/dev/null
+++ b/libavcodec/libutvideoenc.cpp
@@ -0,0 +1,240 @@
+/*
+ * 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;
+ avctx->codec_tag = MKTAG('U', 'L', 'Y', '0');
+ break;
+ case AV_PIX_FMT_YUYV422:
+ in_format = UTVF_YUYV;
+ avctx->bits_per_coded_sample = 16;
+ 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 = avcodec_alloc_frame();
+
+ /* Alloc extradata buffer */
+ info = (UtVideoExtra *)av_malloc(sizeof(*info));
+
+ if (info == NULL) {
+ 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 9450792..04f9902 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 b255ba5..4216a41 100644
--- a/libavcodec/libvo-amrwbenc.c
+++ b/libavcodec/libvo-amrwbenc.c
@@ -2,20 +2,20 @@
* AMR Audio encoder stub
* Copyright (c) 2003 the ffmpeg project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,7 +45,7 @@ static const AVOption options[] = {
{ NULL }
};
-static const AVClass class = {
+static const AVClass amrwb_class = {
"libvo_amrwbenc", av_default_item_name, options, LIBAVUTIL_VERSION_INT
};
@@ -79,7 +79,7 @@ static av_cold int amr_wb_encode_init(AVCodecContext *avctx)
{
AMRWBContext *s = avctx->priv_data;
- if (avctx->sample_rate != 16000) {
+ if (avctx->sample_rate != 16000 && avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
av_log(avctx, AV_LOG_ERROR, "Only 16000Hz sample rate supported\n");
return AVERROR(ENOSYS);
}
@@ -115,10 +115,8 @@ static int amr_wb_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
const int16_t *samples = (const int16_t *)frame->data[0];
int size, ret;
- if ((ret = ff_alloc_packet(avpkt, MAX_PACKET_SIZE))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, MAX_PACKET_SIZE)) < 0)
return ret;
- }
if (s->last_bitrate != avctx->bit_rate) {
s->mode = get_wb_bitrate_mode(avctx->bit_rate, avctx);
@@ -150,5 +148,5 @@ AVCodec ff_libvo_amrwbenc_encoder = {
.close = amr_wb_encode_close,
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
- .priv_class = &class,
+ .priv_class = &amrwb_class,
};
diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbis.c
deleted file mode 100644
index a635db3..0000000
--- a/libavcodec/libvorbis.c
+++ b/dev/null
@@ -1,352 +0,0 @@
-/*
- * copyright (c) 2002 Mark Hills <mark@pogo.org.uk>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * Vorbis encoding support via libvorbisenc.
- * @author Mark Hills <mark@pogo.org.uk>
- */
-
-#include <vorbis/vorbisenc.h>
-
-#include "libavutil/fifo.h"
-#include "libavutil/opt.h"
-#include "avcodec.h"
-#include "audio_frame_queue.h"
-#include "bytestream.h"
-#include "internal.h"
-#include "vorbis.h"
-#include "vorbis_parser.h"
-
-#undef NDEBUG
-#include <assert.h>
-
-/* Number of samples the user should send in each call.
- * This value is used because it is the LCD of all possible frame sizes, so
- * an output packet will always start at the same point as one of the input
- * packets.
- */
-#define OGGVORBIS_FRAME_SIZE 64
-
-#define BUFFER_SIZE (1024 * 64)
-
-typedef struct OggVorbisContext {
- AVClass *av_class; /**< class for AVOptions */
- vorbis_info vi; /**< vorbis_info used during init */
- vorbis_dsp_state vd; /**< DSP state used for analysis */
- vorbis_block vb; /**< vorbis_block used for analysis */
- AVFifoBuffer *pkt_fifo; /**< output packet buffer */
- int eof; /**< end-of-file flag */
- int dsp_initialized; /**< vd has been initialized */
- vorbis_comment vc; /**< VorbisComment info */
- ogg_packet op; /**< ogg packet */
- double iblock; /**< impulse block bias option */
- VorbisParseContext vp; /**< parse context to get durations */
- AudioFrameQueue afq; /**< frame queue for timestamps */
-} OggVorbisContext;
-
-static const AVOption options[] = {
- { "iblock", "Sets the impulse block bias", offsetof(OggVorbisContext, iblock), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, -15, 0, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
- { NULL }
-};
-
-static const AVCodecDefault defaults[] = {
- { "b", "0" },
- { NULL },
-};
-
-static const AVClass class = { "libvorbis", av_default_item_name, options, LIBAVUTIL_VERSION_INT };
-
-
-static int vorbis_error_to_averror(int ov_err)
-{
- switch (ov_err) {
- case OV_EFAULT: return AVERROR_BUG;
- case OV_EINVAL: return AVERROR(EINVAL);
- case OV_EIMPL: return AVERROR(EINVAL);
- default: return AVERROR_UNKNOWN;
- }
-}
-
-static av_cold int oggvorbis_init_encoder(vorbis_info *vi,
- AVCodecContext *avctx)
-{
- OggVorbisContext *s = avctx->priv_data;
- double cfreq;
- int ret;
-
- if (avctx->flags & CODEC_FLAG_QSCALE || !avctx->bit_rate) {
- /* variable bitrate
- * NOTE: we use the oggenc range of -1 to 10 for global_quality for
- * user convenience, but libvorbis uses -0.1 to 1.0.
- */
- float q = avctx->global_quality / (float)FF_QP2LAMBDA;
- /* default to 3 if the user did not set quality or bitrate */
- if (!(avctx->flags & CODEC_FLAG_QSCALE))
- q = 3.0;
- if ((ret = vorbis_encode_setup_vbr(vi, avctx->channels,
- avctx->sample_rate,
- q / 10.0)))
- goto error;
- } else {
- int minrate = avctx->rc_min_rate > 0 ? avctx->rc_min_rate : -1;
- int maxrate = avctx->rc_max_rate > 0 ? avctx->rc_max_rate : -1;
-
- /* average bitrate */
- if ((ret = vorbis_encode_setup_managed(vi, avctx->channels,
- avctx->sample_rate, maxrate,
- avctx->bit_rate, minrate)))
- goto error;
-
- /* variable bitrate by estimate, disable slow rate management */
- if (minrate == -1 && maxrate == -1)
- if ((ret = vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE2_SET, NULL)))
- goto error;
- }
-
- /* cutoff frequency */
- if (avctx->cutoff > 0) {
- cfreq = avctx->cutoff / 1000.0;
- if ((ret = vorbis_encode_ctl(vi, OV_ECTL_LOWPASS_SET, &cfreq)))
- goto error;
- }
-
- /* impulse block bias */
- if (s->iblock) {
- if ((ret = vorbis_encode_ctl(vi, OV_ECTL_IBLOCK_SET, &s->iblock)))
- goto error;
- }
-
- if ((ret = vorbis_encode_setup_init(vi)))
- goto error;
-
- return 0;
-error:
- return vorbis_error_to_averror(ret);
-}
-
-/* How many bytes are needed for a buffer of length 'l' */
-static int xiph_len(int l)
-{
- return 1 + l / 255 + l;
-}
-
-static av_cold int oggvorbis_encode_close(AVCodecContext *avctx)
-{
- OggVorbisContext *s = avctx->priv_data;
-
- /* notify vorbisenc this is EOF */
- if (s->dsp_initialized)
- vorbis_analysis_wrote(&s->vd, 0);
-
- vorbis_block_clear(&s->vb);
- vorbis_dsp_clear(&s->vd);
- vorbis_info_clear(&s->vi);
-
- av_fifo_free(s->pkt_fifo);
- ff_af_queue_close(&s->afq);
- av_freep(&avctx->extradata);
-
- return 0;
-}
-
-static av_cold int oggvorbis_encode_init(AVCodecContext *avctx)
-{
- OggVorbisContext *s = avctx->priv_data;
- ogg_packet header, header_comm, header_code;
- uint8_t *p;
- unsigned int offset;
- int ret;
-
- vorbis_info_init(&s->vi);
- if ((ret = oggvorbis_init_encoder(&s->vi, avctx))) {
- av_log(avctx, AV_LOG_ERROR, "encoder setup failed\n");
- goto error;
- }
- if ((ret = vorbis_analysis_init(&s->vd, &s->vi))) {
- av_log(avctx, AV_LOG_ERROR, "analysis init failed\n");
- ret = vorbis_error_to_averror(ret);
- goto error;
- }
- s->dsp_initialized = 1;
- if ((ret = vorbis_block_init(&s->vd, &s->vb))) {
- av_log(avctx, AV_LOG_ERROR, "dsp init failed\n");
- ret = vorbis_error_to_averror(ret);
- goto error;
- }
-
- vorbis_comment_init(&s->vc);
- vorbis_comment_add_tag(&s->vc, "encoder", LIBAVCODEC_IDENT);
-
- if ((ret = vorbis_analysis_headerout(&s->vd, &s->vc, &header, &header_comm,
- &header_code))) {
- ret = vorbis_error_to_averror(ret);
- goto error;
- }
-
- avctx->extradata_size = 1 + xiph_len(header.bytes) +
- xiph_len(header_comm.bytes) +
- header_code.bytes;
- p = avctx->extradata = av_malloc(avctx->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (!p) {
- ret = AVERROR(ENOMEM);
- goto error;
- }
- p[0] = 2;
- offset = 1;
- offset += av_xiphlacing(&p[offset], header.bytes);
- offset += av_xiphlacing(&p[offset], header_comm.bytes);
- memcpy(&p[offset], header.packet, header.bytes);
- offset += header.bytes;
- memcpy(&p[offset], header_comm.packet, header_comm.bytes);
- offset += header_comm.bytes;
- memcpy(&p[offset], header_code.packet, header_code.bytes);
- offset += header_code.bytes;
- assert(offset == avctx->extradata_size);
-
- if ((ret = avpriv_vorbis_parse_extradata(avctx, &s->vp)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "invalid extradata\n");
- return ret;
- }
-
- vorbis_comment_clear(&s->vc);
-
- avctx->frame_size = OGGVORBIS_FRAME_SIZE;
- ff_af_queue_init(avctx, &s->afq);
-
- s->pkt_fifo = av_fifo_alloc(BUFFER_SIZE);
- if (!s->pkt_fifo) {
- ret = AVERROR(ENOMEM);
- goto error;
- }
-
- return 0;
-error:
- oggvorbis_encode_close(avctx);
- return ret;
-}
-
-static int oggvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
- const AVFrame *frame, int *got_packet_ptr)
-{
- OggVorbisContext *s = avctx->priv_data;
- ogg_packet op;
- int ret, duration;
-
- /* send samples to libvorbis */
- if (frame) {
- const int samples = frame->nb_samples;
- float **buffer;
- int c, channels = s->vi.channels;
-
- buffer = vorbis_analysis_buffer(&s->vd, samples);
- for (c = 0; c < channels; c++) {
- int co = (channels > 8) ? c :
- ff_vorbis_encoding_channel_layout_offsets[channels - 1][c];
- memcpy(buffer[c], frame->extended_data[co],
- samples * sizeof(*buffer[c]));
- }
- if ((ret = vorbis_analysis_wrote(&s->vd, samples)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "error in vorbis_analysis_wrote()\n");
- return vorbis_error_to_averror(ret);
- }
- if ((ret = ff_af_queue_add(&s->afq, frame)) < 0)
- return ret;
- } else {
- if (!s->eof)
- if ((ret = vorbis_analysis_wrote(&s->vd, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "error in vorbis_analysis_wrote()\n");
- return vorbis_error_to_averror(ret);
- }
- s->eof = 1;
- }
-
- /* retrieve available packets from libvorbis */
- while ((ret = vorbis_analysis_blockout(&s->vd, &s->vb)) == 1) {
- if ((ret = vorbis_analysis(&s->vb, NULL)) < 0)
- break;
- if ((ret = vorbis_bitrate_addblock(&s->vb)) < 0)
- break;
-
- /* add any available packets to the output packet buffer */
- while ((ret = vorbis_bitrate_flushpacket(&s->vd, &op)) == 1) {
- if (av_fifo_space(s->pkt_fifo) < sizeof(ogg_packet) + op.bytes) {
- av_log(avctx, AV_LOG_ERROR, "packet buffer is too small");
- return AVERROR_BUG;
- }
- av_fifo_generic_write(s->pkt_fifo, &op, sizeof(ogg_packet), NULL);
- av_fifo_generic_write(s->pkt_fifo, op.packet, op.bytes, NULL);
- }
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "error getting available packets\n");
- break;
- }
- }
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "error getting available packets\n");
- return vorbis_error_to_averror(ret);
- }
-
- /* check for available packets */
- if (av_fifo_size(s->pkt_fifo) < sizeof(ogg_packet))
- return 0;
-
- av_fifo_generic_read(s->pkt_fifo, &op, sizeof(ogg_packet), NULL);
-
- if ((ret = ff_alloc_packet(avpkt, op.bytes))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
- return ret;
- }
- av_fifo_generic_read(s->pkt_fifo, avpkt->data, op.bytes, NULL);
-
- avpkt->pts = ff_samples_to_time_base(avctx, op.granulepos);
-
- duration = avpriv_vorbis_parse_frame(&s->vp, avpkt->data, avpkt->size);
- if (duration > 0) {
- /* we do not know encoder delay until we get the first packet from
- * libvorbis, so we have to update the AudioFrameQueue counts */
- if (!avctx->delay) {
- avctx->delay = duration;
- s->afq.remaining_delay += duration;
- s->afq.remaining_samples += duration;
- }
- ff_af_queue_remove(&s->afq, duration, &avpkt->pts, &avpkt->duration);
- }
-
- *got_packet_ptr = 1;
- return 0;
-}
-
-AVCodec ff_libvorbis_encoder = {
- .name = "libvorbis",
- .long_name = NULL_IF_CONFIG_SMALL("libvorbis Vorbis"),
- .type = AVMEDIA_TYPE_AUDIO,
- .id = AV_CODEC_ID_VORBIS,
- .priv_data_size = sizeof(OggVorbisContext),
- .init = oggvorbis_encode_init,
- .encode2 = oggvorbis_encode_frame,
- .close = oggvorbis_encode_close,
- .capabilities = CODEC_CAP_DELAY,
- .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
- AV_SAMPLE_FMT_NONE },
- .priv_class = &class,
- .defaults = defaults,
-};
diff --git a/libavcodec/libvorbisdec.c b/libavcodec/libvorbisdec.c
new file mode 100644
index 0000000..b703b65
--- a/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/libvorbisenc.c b/libavcodec/libvorbisenc.c
new file mode 100644
index 0000000..a2faac7
--- a/dev/null
+++ b/libavcodec/libvorbisenc.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2002 Mark Hills <mark@pogo.org.uk>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <vorbis/vorbisenc.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/fifo.h"
+#include "libavutil/opt.h"
+#include "avcodec.h"
+#include "audio_frame_queue.h"
+#include "internal.h"
+#include "vorbis.h"
+#include "vorbis_parser.h"
+
+
+/* Number of samples the user should send in each call.
+ * This value is used because it is the LCD of all possible frame sizes, so
+ * an output packet will always start at the same point as one of the input
+ * packets.
+ */
+#define OGGVORBIS_FRAME_SIZE 64
+
+#define BUFFER_SIZE (1024 * 64)
+
+typedef struct OggVorbisEncContext {
+ AVClass *av_class; /**< class for AVOptions */
+ AVFrame frame;
+ vorbis_info vi; /**< vorbis_info used during init */
+ vorbis_dsp_state vd; /**< DSP state used for analysis */
+ vorbis_block vb; /**< vorbis_block used for analysis */
+ AVFifoBuffer *pkt_fifo; /**< output packet buffer */
+ int eof; /**< end-of-file flag */
+ int dsp_initialized; /**< vd has been initialized */
+ vorbis_comment vc; /**< VorbisComment info */
+ double iblock; /**< impulse block bias option */
+ VorbisParseContext vp; /**< parse context to get durations */
+ AudioFrameQueue afq; /**< frame queue for timestamps */
+} OggVorbisEncContext;
+
+static const AVOption options[] = {
+ { "iblock", "Sets the impulse block bias", offsetof(OggVorbisEncContext, iblock), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, -15, 0, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
+ { NULL }
+};
+
+static const AVCodecDefault defaults[] = {
+ { "b", "0" },
+ { NULL },
+};
+
+static const AVClass vorbis_class = {
+ .class_name = "libvorbis",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static int vorbis_error_to_averror(int ov_err)
+{
+ switch (ov_err) {
+ case OV_EFAULT: return AVERROR_BUG;
+ case OV_EINVAL: return AVERROR(EINVAL);
+ case OV_EIMPL: return AVERROR(EINVAL);
+ default: return AVERROR_UNKNOWN;
+ }
+}
+
+static av_cold int oggvorbis_init_encoder(vorbis_info *vi,
+ AVCodecContext *avctx)
+{
+ OggVorbisEncContext *s = avctx->priv_data;
+ double cfreq;
+ int ret;
+
+ if (avctx->flags & CODEC_FLAG_QSCALE || !avctx->bit_rate) {
+ /* variable bitrate
+ * NOTE: we use the oggenc range of -1 to 10 for global_quality for
+ * user convenience, but libvorbis uses -0.1 to 1.0.
+ */
+ float q = avctx->global_quality / (float)FF_QP2LAMBDA;
+ /* default to 3 if the user did not set quality or bitrate */
+ if (!(avctx->flags & CODEC_FLAG_QSCALE))
+ q = 3.0;
+ if ((ret = vorbis_encode_setup_vbr(vi, avctx->channels,
+ avctx->sample_rate,
+ q / 10.0)))
+ goto error;
+ } else {
+ int minrate = avctx->rc_min_rate > 0 ? avctx->rc_min_rate : -1;
+ int maxrate = avctx->rc_max_rate > 0 ? avctx->rc_max_rate : -1;
+
+ /* average bitrate */
+ if ((ret = vorbis_encode_setup_managed(vi, avctx->channels,
+ avctx->sample_rate, maxrate,
+ avctx->bit_rate, minrate)))
+ goto error;
+
+ /* variable bitrate by estimate, disable slow rate management */
+ if (minrate == -1 && maxrate == -1)
+ if ((ret = vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE2_SET, NULL)))
+ goto error; /* should not happen */
+ }
+
+ /* cutoff frequency */
+ if (avctx->cutoff > 0) {
+ cfreq = avctx->cutoff / 1000.0;
+ if ((ret = vorbis_encode_ctl(vi, OV_ECTL_LOWPASS_SET, &cfreq)))
+ goto error; /* should not happen */
+ }
+
+ /* impulse block bias */
+ if (s->iblock) {
+ if ((ret = vorbis_encode_ctl(vi, OV_ECTL_IBLOCK_SET, &s->iblock)))
+ goto error;
+ }
+
+ if (avctx->channels == 3 &&
+ avctx->channel_layout != (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) ||
+ avctx->channels == 4 &&
+ avctx->channel_layout != AV_CH_LAYOUT_2_2 &&
+ avctx->channel_layout != AV_CH_LAYOUT_QUAD ||
+ avctx->channels == 5 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT0 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT0_BACK ||
+ avctx->channels == 6 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT1 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT1_BACK ||
+ avctx->channels == 7 &&
+ avctx->channel_layout != (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER) ||
+ avctx->channels == 8 &&
+ avctx->channel_layout != AV_CH_LAYOUT_7POINT1) {
+ if (avctx->channel_layout) {
+ char name[32];
+ av_get_channel_layout_string(name, sizeof(name), avctx->channels,
+ avctx->channel_layout);
+ av_log(avctx, AV_LOG_ERROR, "%s not supported by Vorbis: "
+ "output stream will have incorrect "
+ "channel layout.\n", name);
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "No channel layout specified. The encoder "
+ "will use Vorbis channel layout for "
+ "%d channels.\n", avctx->channels);
+ }
+ }
+
+ if ((ret = vorbis_encode_setup_init(vi)))
+ goto error;
+
+ return 0;
+error:
+ return vorbis_error_to_averror(ret);
+}
+
+/* How many bytes are needed for a buffer of length 'l' */
+static int xiph_len(int l)
+{
+ return 1 + l / 255 + l;
+}
+
+static av_cold int oggvorbis_encode_close(AVCodecContext *avctx)
+{
+ OggVorbisEncContext *s = avctx->priv_data;
+
+ /* notify vorbisenc this is EOF */
+ if (s->dsp_initialized)
+ vorbis_analysis_wrote(&s->vd, 0);
+
+ vorbis_block_clear(&s->vb);
+ vorbis_dsp_clear(&s->vd);
+ vorbis_info_clear(&s->vi);
+
+ av_fifo_free(s->pkt_fifo);
+ ff_af_queue_close(&s->afq);
+ av_freep(&avctx->extradata);
+
+ return 0;
+}
+
+static av_cold int oggvorbis_encode_init(AVCodecContext *avctx)
+{
+ OggVorbisEncContext *s = avctx->priv_data;
+ ogg_packet header, header_comm, header_code;
+ uint8_t *p;
+ unsigned int offset;
+ int ret;
+
+ vorbis_info_init(&s->vi);
+ if ((ret = oggvorbis_init_encoder(&s->vi, avctx))) {
+ av_log(avctx, AV_LOG_ERROR, "encoder setup failed\n");
+ goto error;
+ }
+ if ((ret = vorbis_analysis_init(&s->vd, &s->vi))) {
+ av_log(avctx, AV_LOG_ERROR, "analysis init failed\n");
+ ret = vorbis_error_to_averror(ret);
+ goto error;
+ }
+ s->dsp_initialized = 1;
+ if ((ret = vorbis_block_init(&s->vd, &s->vb))) {
+ av_log(avctx, AV_LOG_ERROR, "dsp init failed\n");
+ ret = vorbis_error_to_averror(ret);
+ goto error;
+ }
+
+ vorbis_comment_init(&s->vc);
+ if (!(avctx->flags & CODEC_FLAG_BITEXACT))
+ vorbis_comment_add_tag(&s->vc, "encoder", LIBAVCODEC_IDENT);
+
+ if ((ret = vorbis_analysis_headerout(&s->vd, &s->vc, &header, &header_comm,
+ &header_code))) {
+ ret = vorbis_error_to_averror(ret);
+ goto error;
+ }
+
+ avctx->extradata_size = 1 + xiph_len(header.bytes) +
+ xiph_len(header_comm.bytes) +
+ header_code.bytes;
+ p = avctx->extradata = av_malloc(avctx->extradata_size +
+ FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!p) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+ p[0] = 2;
+ offset = 1;
+ offset += av_xiphlacing(&p[offset], header.bytes);
+ offset += av_xiphlacing(&p[offset], header_comm.bytes);
+ memcpy(&p[offset], header.packet, header.bytes);
+ offset += header.bytes;
+ memcpy(&p[offset], header_comm.packet, header_comm.bytes);
+ offset += header_comm.bytes;
+ memcpy(&p[offset], header_code.packet, header_code.bytes);
+ offset += header_code.bytes;
+ av_assert0(offset == avctx->extradata_size);
+
+ if ((ret = avpriv_vorbis_parse_extradata(avctx, &s->vp)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid extradata\n");
+ return ret;
+ }
+
+ vorbis_comment_clear(&s->vc);
+
+ avctx->frame_size = OGGVORBIS_FRAME_SIZE;
+ ff_af_queue_init(avctx, &s->afq);
+
+ s->pkt_fifo = av_fifo_alloc(BUFFER_SIZE);
+ if (!s->pkt_fifo) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+
+ return 0;
+error:
+ oggvorbis_encode_close(avctx);
+ return ret;
+}
+
+static int oggvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
+ const AVFrame *frame, int *got_packet_ptr)
+{
+ OggVorbisEncContext *s = avctx->priv_data;
+ ogg_packet op;
+ int ret, duration;
+
+ /* send samples to libvorbis */
+ if (frame) {
+ const int samples = frame->nb_samples;
+ float **buffer;
+ int c, channels = s->vi.channels;
+
+ buffer = vorbis_analysis_buffer(&s->vd, samples);
+ for (c = 0; c < channels; c++) {
+ int co = (channels > 8) ? c :
+ ff_vorbis_encoding_channel_layout_offsets[channels - 1][c];
+ memcpy(buffer[c], frame->extended_data[co],
+ samples * sizeof(*buffer[c]));
+ }
+ if ((ret = vorbis_analysis_wrote(&s->vd, samples)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error in vorbis_analysis_wrote()\n");
+ return vorbis_error_to_averror(ret);
+ }
+ if ((ret = ff_af_queue_add(&s->afq, frame)) < 0)
+ return ret;
+ } else {
+ if (!s->eof)
+ if ((ret = vorbis_analysis_wrote(&s->vd, 0)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error in vorbis_analysis_wrote()\n");
+ return vorbis_error_to_averror(ret);
+ }
+ s->eof = 1;
+ }
+
+ /* retrieve available packets from libvorbis */
+ while ((ret = vorbis_analysis_blockout(&s->vd, &s->vb)) == 1) {
+ if ((ret = vorbis_analysis(&s->vb, NULL)) < 0)
+ break;
+ if ((ret = vorbis_bitrate_addblock(&s->vb)) < 0)
+ break;
+
+ /* add any available packets to the output packet buffer */
+ while ((ret = vorbis_bitrate_flushpacket(&s->vd, &op)) == 1) {
+ if (av_fifo_space(s->pkt_fifo) < sizeof(ogg_packet) + op.bytes) {
+ av_log(avctx, AV_LOG_ERROR, "packet buffer is too small\n");
+ return AVERROR_BUG;
+ }
+ av_fifo_generic_write(s->pkt_fifo, &op, sizeof(ogg_packet), NULL);
+ av_fifo_generic_write(s->pkt_fifo, op.packet, op.bytes, NULL);
+ }
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error getting available packets\n");
+ break;
+ }
+ }
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error getting available packets\n");
+ return vorbis_error_to_averror(ret);
+ }
+
+ /* check for available packets */
+ if (av_fifo_size(s->pkt_fifo) < sizeof(ogg_packet))
+ return 0;
+
+ av_fifo_generic_read(s->pkt_fifo, &op, sizeof(ogg_packet), NULL);
+
+ if ((ret = ff_alloc_packet2(avctx, avpkt, op.bytes)) < 0)
+ return ret;
+ av_fifo_generic_read(s->pkt_fifo, avpkt->data, op.bytes, NULL);
+
+ avpkt->pts = ff_samples_to_time_base(avctx, op.granulepos);
+
+ duration = avpriv_vorbis_parse_frame(&s->vp, avpkt->data, avpkt->size);
+ if (duration > 0) {
+ /* we do not know encoder delay until we get the first packet from
+ * libvorbis, so we have to update the AudioFrameQueue counts */
+ if (!avctx->delay && s->afq.frames) {
+ avctx->delay = duration;
+ av_assert0(!s->afq.remaining_delay);
+ s->afq.frames->duration += duration;
+ s->afq.frames->pts -= duration;
+ s->afq.remaining_samples += duration;
+ }
+ ff_af_queue_remove(&s->afq, duration, &avpkt->pts, &avpkt->duration);
+ }
+
+ *got_packet_ptr = 1;
+ return 0;
+}
+
+AVCodec ff_libvorbis_encoder = {
+ .name = "libvorbis",
+ .long_name = NULL_IF_CONFIG_SMALL("libvorbis"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_VORBIS,
+ .priv_data_size = sizeof(OggVorbisEncContext),
+ .init = oggvorbis_encode_init,
+ .encode2 = oggvorbis_encode_frame,
+ .close = oggvorbis_encode_close,
+ .capabilities = CODEC_CAP_DELAY,
+ .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
+ AV_SAMPLE_FMT_NONE },
+ .priv_class = &vorbis_class,
+ .defaults = defaults,
+};
diff --git a/libavcodec/libvpxdec.c b/libavcodec/libvpxdec.c
index d19dd6f..de32f40 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
*/
@@ -96,7 +96,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;
}
diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c
index d5c4fe1..8ebf052 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,8 +30,10 @@
#include "avcodec.h"
#include "internal.h"
+#include "libavutil/avassert.h"
#include "libavutil/base64.h"
#include "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
@@ -42,11 +44,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;
};
@@ -54,17 +61,34 @@ 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 max_intra_rate;
} VP8Context;
/** String mappings for enum vp8e_enc_control_id */
@@ -86,6 +110,7 @@ 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",
};
static av_cold void log_encoder_error(AVCodecContext *avctx, const char *desc)
@@ -167,6 +192,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);
}
@@ -207,6 +234,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);
@@ -219,16 +248,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;
@@ -236,9 +277,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;
@@ -247,28 +286,47 @@ 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)
+ enccfg.rc_end_usage = VPX_CQ;
+
+ if (avctx->bit_rate) {
+ enccfg.rc_target_bitrate = av_rescale_rnd(avctx->bit_rate, 1, 1000,
+ AV_ROUND_NEAR_INF);
+ } 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)
+ if (avctx->qmin >= 0)
enccfg.rc_min_quantizer = avctx->qmin;
if (avctx->qmax > 0)
enccfg.rc_max_quantizer = avctx->qmax;
+
+ if (enccfg.rc_end_usage == VPX_CQ) {
+ if (ctx->crf < enccfg.rc_min_quantizer || ctx->crf > enccfg.rc_max_quantizer) {
+ av_log(avctx, AV_LOG_ERROR,
+ "CQ level must be between minimum and maximum quantizer value (%d-%d)\n",
+ 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;
@@ -280,6 +338,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)
@@ -322,20 +381,31 @@ 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);
+ 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)
@@ -348,11 +418,19 @@ static av_cold int vpx_init(AVCodecContext *avctx,
codecctl_int(avctx, VP8E_SET_TOKEN_PARTITIONS, av_log2(avctx->slices));
codecctl_int(avctx, VP8E_SET_STATIC_THRESHOLD, avctx->mb_threshold);
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);
+
+ 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 = avcodec_alloc_frame();
if (!avctx->coded_frame) {
av_log(avctx, AV_LOG_ERROR, "Error allocating coded frame\n");
@@ -363,13 +441,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;
+ }
}
/**
@@ -382,7 +486,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;
@@ -394,9 +499,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 == NULL) {
+ 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;
@@ -415,7 +543,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) {
@@ -430,7 +560,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) {
@@ -438,8 +570,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;
@@ -452,23 +584,35 @@ 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",
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 (%zu 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;
case VPX_CODEC_STATS_PKT: {
struct vpx_fixed_buf *stats = &ctx->twopass_stats;
- stats->buf = av_realloc(stats->buf,
- stats->sz + pkt->data.twopass_stats.sz);
+ stats->buf = av_realloc_f(stats->buf, 1,
+ stats->sz + pkt->data.twopass_stats.sz);
if (!stats->buf) {
av_log(avctx, AV_LOG_ERROR, "Stat buffer realloc failed\n");
return AVERROR(ENOMEM);
@@ -478,7 +622,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;
@@ -493,6 +644,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;
@@ -505,6 +657,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;
@@ -516,6 +682,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) {
@@ -531,6 +707,11 @@ static int vp8_encode(AVCodecContext *avctx, AVPacket *pkt,
ctx->twopass_stats.sz);
}
+ if (rawimg_alpha) {
+ av_free(rawimg_alpha->planes[VPX_PLANE_U]);
+ av_free(rawimg_alpha->planes[VPX_PLANE_V]);
+ }
+
*got_packet = !!coded_size;
return 0;
}
@@ -554,6 +735,7 @@ static const AVOption options[] = {
{ "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},
#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 "
@@ -561,6 +743,15 @@ static const AVOption options[] = {
"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"},
#endif
+{"speed", "", offsetof(VP8Context, cpu_used), AV_OPT_TYPE_INT, {.i64 = 3}, -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},
{ "crf", "Select the quality for constant quality mode", offsetof(VP8Context, crf), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 63, VE },
{ NULL }
};
@@ -580,7 +771,7 @@ 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,
.version = LIBAVUTIL_VERSION_INT,
@@ -596,7 +787,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,
};
@@ -609,7 +800,7 @@ static av_cold int vp9_init(AVCodecContext *avctx)
}
static const AVClass class_vp9 = {
- .class_name = "libvpx encoder",
+ .class_name = "libvpx-vp9 encoder",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
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/libx264.c b/libavcodec/libx264.c
index e842419..4093510 100644
--- a/libavcodec/libx264.c
+++ b/libavcodec/libx264.c
@@ -2,20 +2,20 @@
* 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
*/
@@ -48,7 +48,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;
@@ -108,16 +111,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,22 +136,41 @@ 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};
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];
}
@@ -154,7 +181,7 @@ 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->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);
}
@@ -213,6 +240,20 @@ static av_cold int X264_close(AVCodecContext *avctx)
return 0;
}
+#define OPT_STR(opt, param) \
+ do { \
+ int ret; \
+ if (param!=NULL && (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) {
@@ -221,10 +262,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;
@@ -241,14 +291,26 @@ 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;
x264_param_default(&x4->params);
x4->params.b_deblocking_filter = avctx->flags & CODEC_FLAG_LOOP_FILTER;
+ x4->params.rc.f_pb_factor = avctx->b_quant_factor;
+ x4->params.analyse.i_chroma_qp_offset = avctx->chromaoffset;
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);
}
@@ -260,6 +322,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;
@@ -288,10 +352,23 @@ static av_cold int X264_init(AVCodecContext *avctx)
(float)avctx->rc_initial_buffer_occupancy / avctx->rc_buffer_size;
}
+ OPT_STR("level", x4->level);
+
+ 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 (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->me_method == ME_EPZS)
x4->params.analyse.i_me_method = X264_ME_DIA;
@@ -385,23 +462,64 @@ 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;
+ 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_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;
@@ -417,7 +535,9 @@ 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;
+ 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;
if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER)
x4->params.b_repeat_headers = 0;
@@ -482,7 +602,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
@@ -499,6 +621,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)
{
@@ -517,6 +646,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 },
@@ -566,16 +699,24 @@ static const AVOption options[] = {
{ 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" },
{ "qmin", "-1" },
@@ -583,6 +724,7 @@ static const AVCodecDefault x264_defaults[] = {
{ "qdiff", "-1" },
{ "qblur", "-1" },
{ "qcomp", "-1" },
+// { "rc_lookahead", "-1" },
{ "refs", "-1" },
{ "sc_threshold", "-1" },
{ "trellis", "-1" },
@@ -611,7 +753,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/libxavs.c b/libavcodec/libxavs.c
index 1fc08a9..f7b99e0 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
*/
@@ -89,10 +89,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. */
@@ -146,7 +144,7 @@ static int XAVS_frame(AVCodecContext *ctx, AVPacket *pkt,
if (!ret) {
if (!frame && !(x4->end_of_stream)) {
- if ((ret = ff_alloc_packet(pkt, 4)) < 0)
+ if ((ret = ff_alloc_packet2(ctx, pkt, 4)) < 0)
return ret;
pkt->data[0] = 0x0;
@@ -390,10 +388,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" },
@@ -406,7 +404,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,
@@ -429,6 +427,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 9a07207..d4c7149 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
*/
@@ -28,6 +28,8 @@
#include <xvid.h>
#include <unistd.h>
#include "avcodec.h"
+#include "internal.h"
+#include "libavutil/file.h"
#include "libavutil/cpu.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
@@ -58,8 +60,13 @@ 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 */
+ int variance_aq; /**< Variance adaptive quantization */
+ int ssim; /**< SSIM information display mode */
+ int ssim_acc; /**< SSIM accuracy. 0: accurate. 4: fast. */
};
/**
@@ -70,6 +77,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
*
@@ -100,7 +109,7 @@ static int xvid_ff_2pass_create(xvid_plg_create_t * param,
/* 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),
@@ -347,43 +356,47 @@ 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_gbl_init_t xvid_gbl_init = { 0 };
- xvid_enc_create_t xvid_enc_create = { 0 };
- xvid_enc_plugin_t plugins[7];
+ 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 avconv command-line */
- x->vop_flags = XVID_VOP_HALFPEL; /* Bare minimum quality */
+ /* 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 */
- if( avctx->trellis
- )
- x->vop_flags |= XVID_VOP_TRELLISQUANT; /* Level 5 */
+ x->vop_flags |= XVID_VOP_INTER4V; /* Level 3 */
+ if( avctx->trellis)
+ 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;
switch( avctx->me_method ) {
case ME_FULL: /* Quality 6 */
- x->me_flags |= XVID_ME_EXTSEARCH16
- | XVID_ME_EXTSEARCH8;
+ x->me_flags |= XVID_ME_EXTSEARCH16
+ | XVID_ME_EXTSEARCH8;
case ME_EPZS: /* Quality 4 */
- x->me_flags |= XVID_ME_ADVANCEDDIAMOND8
- | XVID_ME_HALFPELREFINE8
- | XVID_ME_CHROMA_PVOP
- | XVID_ME_CHROMA_BVOP;
+ x->me_flags |= XVID_ME_ADVANCEDDIAMOND8
+ | XVID_ME_HALFPELREFINE8
+ | XVID_ME_CHROMA_PVOP
+ | XVID_ME_CHROMA_BVOP;
case ME_LOG: /* Quality 2 */
case ME_PHODS:
case ME_X1:
- x->me_flags |= XVID_ME_ADVANCEDDIAMOND16
- | XVID_ME_HALFPELREFINE16;
+ x->me_flags |= XVID_ME_ADVANCEDDIAMOND16
+ | XVID_ME_HALFPELREFINE16;
case ME_ZERO: /* Quality 0 */
default:
@@ -394,29 +407,29 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) {
switch( avctx->mb_decision ) {
case 2:
x->vop_flags |= XVID_VOP_MODEDECISION_RD;
- x->me_flags |= XVID_ME_HALFPELREFINE8_RD
- | XVID_ME_QUARTERPELREFINE8_RD
- | XVID_ME_EXTSEARCH_RD
- | XVID_ME_CHECKPREDICTION_RD;
+ x->me_flags |= XVID_ME_HALFPELREFINE8_RD
+ | XVID_ME_QUARTERPELREFINE8_RD
+ | XVID_ME_EXTSEARCH_RD
+ | XVID_ME_CHECKPREDICTION_RD;
case 1:
if( !(x->vop_flags & XVID_VOP_MODEDECISION_RD) )
x->vop_flags |= XVID_VOP_FAST_MODEDECISION_RD;
- x->me_flags |= XVID_ME_HALFPELREFINE16_RD
- | XVID_ME_QUARTERPELREFINE16_RD;
+ x->me_flags |= XVID_ME_HALFPELREFINE16_RD
+ | XVID_ME_QUARTERPELREFINE16_RD;
default:
break;
}
- /* Bring in VOL flags from avconv command-line */
+ /* Bring in VOL flags from ffmpeg command-line */
x->vol_flags = 0;
if( xvid_flags & CODEC_FLAG_GMC ) {
- x->vol_flags |= XVID_VOL_GMC;
- x->me_flags |= XVID_ME_GME_REFINE;
+ x->vol_flags |= XVID_VOL_GMC;
+ x->me_flags |= XVID_ME_GME_REFINE;
}
if( xvid_flags & CODEC_FLAG_QPEL ) {
- x->vol_flags |= XVID_VOL_QUARTERPEL;
- x->me_flags |= XVID_ME_QUARTERPELREFINE16;
+ x->vol_flags |= XVID_VOL_QUARTERPEL;
+ x->me_flags |= XVID_ME_QUARTERPELREFINE16;
if( x->vop_flags & XVID_VOP_INTER4V )
x->me_flags |= XVID_ME_QUARTERPELREFINE8;
}
@@ -472,7 +485,7 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) {
if( x->twopassbuffer == NULL || x->old_twopassbuffer == NULL ) {
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;
@@ -483,28 +496,27 @@ 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 == NULL ) {
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;
@@ -519,10 +531,41 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) {
xvid_enc_create.num_plugins++;
}
+ if ( avctx->lumi_masking != 0.0)
+ x->lumi_aq = 1;
+
/* Luminance Masking */
- if( 0.0 != avctx->lumi_masking ) {
+ if( x->lumi_aq ) {
+ masking_l.method = 0;
plugins[xvid_enc_create.num_plugins].func = xvid_plugin_lumimasking;
- plugins[xvid_enc_create.num_plugins].param = NULL;
+
+ /* The old behavior is that when avctx->lumi_masking is specified,
+ * plugins[...].param = NULL. Trying to keep the old behavior here. */
+ plugins[xvid_enc_create.num_plugins].param = avctx->lumi_masking ? NULL : &masking_l ;
+ xvid_enc_create.num_plugins++;
+ }
+
+ /* Variance AQ */
+ if( x->variance_aq ) {
+ masking_v.method = 1;
+ plugins[xvid_enc_create.num_plugins].func = xvid_plugin_lumimasking;
+ plugins[xvid_enc_create.num_plugins].param = &masking_v ;
+ 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;
+ ssim.b_printstat = ( x->ssim == 2 );
+ ssim.acc = x->ssim_acc;
+ ssim.cpu_flags = xvid_gbl_init.cpu_flags;
+ ssim.b_visualize = 0;
+ plugins[xvid_enc_create.num_plugins].param = &ssim;
xvid_enc_create.num_plugins++;
}
@@ -598,17 +641,22 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) {
xvid_enc_create.bquant_ratio = 100 * avctx->b_quant_factor;
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;
avctx->coded_frame = &x->encoded_picture;
return 0;
+fail:
+ xvid_encode_close(avctx);
+ return -1;
}
static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
@@ -624,11 +672,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;
@@ -663,11 +708,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;
@@ -734,20 +781,48 @@ static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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 != NULL ) {
- 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;
}
+#define OFFSET(x) offsetof(struct xvid_context, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "lumi_aq", "Luminance masking AQ", OFFSET(lumi_aq), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
+ { "variance_aq", "Variance AQ", OFFSET(variance_aq), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
+ { "ssim", "Show SSIM information to stdout", OFFSET(ssim), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, VE, "ssim" },
+ { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "ssim" },
+ { "avg", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "ssim" },
+ { "frame", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "ssim" },
+ { "ssim_acc", "SSIM accuracy", OFFSET(ssim_acc), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 4, VE },
+ { NULL },
+};
+
+static const AVClass xvid_class = {
+ .class_name = "libxvid",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_libxvid_encoder = {
.name = "libxvid",
.long_name = NULL_IF_CONFIG_SMALL("libxvidcore MPEG-4 part 2"),
@@ -758,4 +833,5 @@ AVCodec ff_libxvid_encoder = {
.encode2 = xvid_encode_frame,
.close = xvid_encode_close,
.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },
+ .priv_class = &xvid_class,
};
diff --git a/libavcodec/libxvid.h b/libavcodec/libxvid.h
index 413d353..90ecd6f 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 7f4a89d..5da435b 100644
--- a/libavcodec/libxvid_rc.c
+++ b/libavcodec/libxvid_rc.c
@@ -3,32 +3,28 @@
*
* 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"
#include <xvid.h>
#include <unistd.h>
-#if !HAVE_MKSTEMP
-#include <fcntl.h>
-#endif
-
#include "libavutil/attributes.h"
-#include "libavutil/internal.h"
+#include "libavutil/file.h"
#include "avcodec.h"
#include "libxvid.h"
#include "mpegvideo.h"
@@ -36,42 +32,6 @@
#undef NDEBUG
#include <assert.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 == NULL) {
- 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 +39,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;
@@ -96,7 +56,12 @@ av_cold int ff_xvid_rate_control_init(MpegEncContext *s)
frame_types[rce->pict_type], (int)lrintf(rce->qscale / FF_QP2LAMBDA), rce->i_count, s->mb_num - rce->i_count - rce->skip_count,
rce->skip_count, (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) {
+ av_log(NULL, AV_LOG_ERROR, "Error %s writing 2pass logfile\n", strerror(errno));
+ av_free(tmp_name);
+ close(fd);
+ return AVERROR(errno);
+ }
}
close(fd);
diff --git a/libavcodec/libzvbi-teletextdec.c b/libavcodec/libzvbi-teletextdec.c
new file mode 100644
index 0000000..8b504b5
--- a/dev/null
+++ b/libavcodec/libzvbi-teletextdec.c
@@ -0,0 +1,469 @@
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "avcodec.h"
+#include "libavutil/opt.h"
+#include "libavutil/intreadwrite.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)
+
+/* main data structure */
+typedef struct TeletextContext
+{
+ AVClass *class;
+ char *pgno;
+ int x_offset;
+ int y_offset;
+ char *format;
+ int format_id; /* 0 = bitmap, 1 = text */
+ int chop_top;
+ int sub_duration; /* in msec */
+ int transparent_bg;
+ int chop_spaces;
+
+ int lines_processed;
+ AVSubtitleRect *sub_rect;
+
+ vbi_decoder * vbi;
+ vbi_dvb_demux * dx;
+#ifdef DEBUG
+ vbi_export * ex;
+#endif
+ /* Don't even _think_ about making sliced stack-local! */
+ vbi_sliced sliced[64];
+} 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;
+}
+
+// draw a page as text
+static int
+gen_sub_text(TeletextContext *ctx, vbi_page *page, int chop_top)
+{
+ AVSubtitleRect *sub_rect = ctx->sub_rect;
+ char *text;
+ const char *in;
+ char *out;
+ 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;
+ out = text = av_malloc(TEXT_MAXSZ);
+ if (!text) {
+ av_free(vbi_text);
+ return AVERROR(ENOMEM);
+ }
+ 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);
+ memcpy(out, in, sz);
+ out += sz;
+ *out++ = '\n';
+ in += nl;
+ }
+ } else {
+ strcpy(text, vbi_text);
+ out += sz;
+ *out++ = '\n';
+ }
+ av_free(vbi_text);
+ *out = '\0';
+ if (out > text) {
+ sub_rect->type = SUBTITLE_TEXT;
+ sub_rect->text = text;
+ av_log(ctx, AV_LOG_DEBUG, "subtext:%s:txetbus\n", text);
+ } else {
+ sub_rect->type = SUBTITLE_NONE;
+ av_free(text);
+ }
+ return 0;
+}
+
+static void
+fix_transparency(TeletextContext *ctx, vbi_page *page, int chop_top, uint8_t transparent_color, int resx, int resy)
+{
+ AVSubtitleRect *sub_rect = ctx->sub_rect;
+ 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 / 10 + chop_top) * page->columns;
+ vbi_char *vcnext = vc + page->columns;
+ for (; vc < vcnext; vc++) {
+ uint8_t *pixelnext = pixel + 12;
+ switch (vc->opacity) {
+ case VBI_TRANSPARENT_SPACE:
+ memset(pixel, transparent_color, 12);
+ 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, vbi_page *page, int chop_top)
+{
+ AVSubtitleRect *sub_rect = ctx->sub_rect;
+ int resx = page->columns * 12;
+ int resy = (page->rows - chop_top) * 10;
+ 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, page, chop_top, cmax, resx, resy);
+ sub_rect->x = ctx->x_offset;
+ sub_rect->y = ctx->y_offset;
+ 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);
+#ifdef DEBUG
+ av_log(ctx, AV_LOG_DEBUG, "palette %0x\n",
+ ((uint32_t *)sub_rect->pict.data[1])[ci]);
+#endif
+ }
+ ((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;
+ 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;
+
+ /* Fetch the page. */
+ 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->sub_rect) {
+ ctx->sub_rect = av_mallocz(sizeof(*ctx->sub_rect));
+ if (ctx->sub_rect) {
+ res = (ctx->format_id == 0) ?
+ gen_sub_bitmap(ctx, &page, chop_top) :
+ gen_sub_text (ctx, &page, chop_top);
+ if (res)
+ av_freep(&ctx->sub_rect);
+ }
+ } else {
+ // FIXME: Multiple teletext pages in a single packet, some kind of buffering should be done instead of dropping the page...
+ av_log(ctx, AV_LOG_WARNING, "Missed page %s.%02x.\n", pgno_str, ev->ev.ttx_page.subno & 0xFF);
+ }
+
+ vbi_unref_page(&page);
+}
+
+static int
+teletext_decode_frame(AVCodecContext *avctx,
+ void *data, int *data_size,
+ AVPacket *pkt)
+{
+ TeletextContext *ctx = avctx->priv_data;
+ AVSubtitle *sub = data;
+ const uint8_t *buf = pkt->data;
+ unsigned int left = pkt->size;
+ uint8_t pesheader[45] = {0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x85, 0x80, 0x24, 0x21, 0x00, 0x01, 0x00, 0x01};
+ int pesheader_size = sizeof(pesheader);
+ const uint8_t *pesheader_buf = pesheader;
+
+ 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 (!ctx->dx && (!(ctx->dx = vbi_dvb_pes_demux_new (/* callback */ NULL, NULL))))
+ return AVERROR(ENOMEM);
+
+ // We allow unreasonably big packets, even if the standard only allows a max size of 1472
+ if ((pesheader_size + left) < 184 || (pesheader_size + left) > 65504 || (pesheader_size + left) % 184 != 0)
+ return AVERROR_INVALIDDATA;
+
+ memset(pesheader + 14, 0xff, pesheader_size - 14);
+ AV_WB16(pesheader + 4, left + pesheader_size - 6);
+
+ /* PTS is deliberately left as 0 in the PES header, otherwise libzvbi uses
+ * it to detect dropped frames. Unforunatey the guessed packet PTS values
+ * (see mpegts demuxer) are not accurate enough to pass that test. */
+ vbi_dvb_demux_cor(ctx->dx, ctx->sliced, 64, NULL, &pesheader_buf, &pesheader_size);
+
+ while (left > 0) {
+ int64_t pts = 0;
+ unsigned int lines = vbi_dvb_demux_cor(ctx->dx, ctx->sliced, 64, &pts, &buf, &left);
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_DEBUG,
+ "ctx=%p buf_size=%d left=%u lines=%u pts=%f pkt_pts=%f\n",
+ ctx, pkt->size, left, lines, (double)pts/90000.0, (double)pkt->pts/90000.0);
+#endif
+ if (lines > 0) {
+#ifdef DEBUGx
+ int i;
+ for(i=0; i<lines; ++i)
+ av_log(avctx, AV_LOG_DEBUG,
+ "lines=%d id=%x\n", i, ctx->sliced[i].id);
+#endif
+ vbi_decode(ctx->vbi, ctx->sliced, lines, (double)pts/90000.0);
+ ctx->lines_processed += lines;
+ }
+ }
+
+ // is there a subtitle to pass?
+ if (ctx->sub_rect) {
+ sub->format = (ctx->sub_rect->type == SUBTITLE_TEXT ? 1: 0);
+ sub->start_display_time = 0;
+ sub->end_display_time = ctx->sub_duration;
+ sub->num_rects = 0;
+
+ if (ctx->sub_rect->type != SUBTITLE_NONE) {
+ sub->rects = av_malloc(sizeof(*sub->rects) * 1);
+ if (sub->rects) {
+ sub->num_rects = 1;
+ sub->rects[0] = ctx->sub_rect;
+ }
+ } else {
+ av_log(avctx, AV_LOG_DEBUG, "sending empty sub\n");
+ sub->rects = NULL;
+ }
+ if (!sub->rects) // no rect was passed
+ av_free(ctx->sub_rect);
+ ctx->sub_rect = NULL;
+
+ *data_size = 1;
+ } else
+ *data_size = 0;
+
+ return pkt->size;
+}
+
+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;
+ }
+
+ ctx->dx = NULL;
+ ctx->vbi = NULL;
+ ctx->sub_rect = NULL;
+ if (!strcmp(ctx->format, "bitmap")) {
+ ctx->format_id = 0;
+ } else if (!strcmp(ctx->format, "text")) {
+ ctx->format_id = 1;
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "unkown format %s\n", ctx->format);
+ return AVERROR_OPTION_NOT_FOUND;
+ }
+
+#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 0;
+}
+
+static int teletext_close_decoder(AVCodecContext *avctx)
+{
+ TeletextContext *ctx = avctx->priv_data;
+
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_DEBUG, "lines_total=%u\n", ctx->lines_processed);
+#endif
+
+ vbi_dvb_demux_delete(ctx->dx);
+ vbi_decoder_delete(ctx->vbi);
+ ctx->dx = NULL;
+ ctx->vbi = NULL;
+ 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), AV_OPT_TYPE_STRING, {.str = "bitmap"}, 0, 0, SD},
+ {"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,
+ .flush = teletext_flush,
+ .priv_class= &teletext_class,
+};
diff --git a/libavcodec/ljpegenc.c b/libavcodec/ljpegenc.c
index 4b13239..af126aa 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
*/
@@ -56,11 +56,16 @@ static int encode_picture_lossless(AVCodecContext *avctx, AVPacket *pkt,
max_pkt_size += mb_width * mb_height * 3 * 4
* s->mjpeg_hsample[0] * s->mjpeg_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 (!s->edge_emu_buffer &&
+ (ret = ff_mpv_frame_size_alloc(s, pict->linesize[0])) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "failed to allocate context scratch buffers.\n");
return ret;
}
+ if ((ret = ff_alloc_packet2(avctx, pkt, max_pkt_size)) < 0)
+ return ret;
+
init_put_bits(&s->pb, pkt->data, pkt->size);
av_frame_unref(p);
@@ -74,7 +79,9 @@ static int encode_picture_lossless(AVCodecContext *avctx, AVPacket *pkt,
s->header_bits= put_bits_count(&s->pb);
- if(avctx->pix_fmt == AV_PIX_FMT_BGRA){
+ if(avctx->pix_fmt == AV_PIX_FMT_BGR0
+ || avctx->pix_fmt == AV_PIX_FMT_BGRA
+ || avctx->pix_fmt == AV_PIX_FMT_BGR24){
int x, y, i;
const int linesize= p->linesize[0];
uint16_t (*buffer)[4]= (void *) s->rd_scratchpad;
@@ -97,9 +104,15 @@ static int encode_picture_lossless(AVCodecContext *avctx, AVPacket *pkt,
top[i]= left[i]= topleft[i]= buffer[0][i];
}
for(x = 0; x < width; x++) {
+ 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;
@@ -191,7 +204,8 @@ static int encode_picture_lossless(AVCodecContext *avctx, AVPacket *pkt,
}
emms_c();
-
+ av_assert0(s->esc_pos == s->header_bits >> 3);
+ ff_mjpeg_encode_stuffing(s);
ff_mjpeg_encode_picture_trailer(s);
s->picture_number++;
@@ -214,4 +228,9 @@ AVCodec ff_ljpeg_encoder = { //FIXME avoid MPV_* lossless JPEG should not need t
.init = ff_MPV_encode_init,
.encode2 = encode_picture_lossless,
.close = ff_MPV_encode_end,
+ .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/lpc.c b/libavcodec/lpc.c
index fbd1bdf..1d52edf 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 c41a1f8..c323230 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;
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 2c99014..43e3e05 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
*/
@@ -92,11 +92,6 @@ static int lzw_get_code(struct LZWState * s)
return c & s->curmask;
}
-const uint8_t* ff_lzw_cur_ptr(LZWState *p)
-{
- return ((struct LZWState*)p)->pbuf;
-}
-
void ff_lzw_decode_tail(LZWState *p)
{
struct LZWState *s = (struct LZWState *)p;
@@ -191,6 +186,10 @@ int ff_lzw_decode(LZWState *p, uint8_t *buf, int len){
if ((--l) == 0)
goto the_end;
}
+ if (s->ebuf < s->pbuf) {
+ av_log(NULL, AV_LOG_ERROR, "lzw overread\n");
+ goto the_end;
+ }
c = lzw_get_code(s);
if (c == s->end_code) {
break;
diff --git a/libavcodec/lzw.h b/libavcodec/lzw.h
index ab782f5..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);
-const uint8_t* ff_lzw_cur_ptr(LZWState *lzw);
void ff_lzw_decode_tail(LZWState *lzw);
/** LZW encode state */
diff --git a/libavcodec/lzwenc.c b/libavcodec/lzwenc.c
index cb064e7..d5a07bc 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
*/
@@ -76,7 +76,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;
}
@@ -111,7 +111,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);
}
@@ -207,7 +207,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;
@@ -262,6 +262,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..fbd932e 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
*/
@@ -246,10 +246,8 @@ static int mace_decode_frame(AVCodecContext *avctx, void *data,
/* 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 6c216c2..bad25af 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
diff --git a/libavcodec/mathtables.c b/libavcodec/mathtables.c
index 8a3934b..ec5ba79 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.c b/libavcodec/mdct.c
index 6f64534..922d577 100644
--- a/libavcodec/mdct.c
+++ b/libavcodec/mdct.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 CONFIG_FFT_FLOAT
# define RSCALE(x) (x)
#else
+#if CONFIG_FFT_FIXED_32
+# define RSCALE(x) (((x) + 32) >> 6)
+#else /* CONFIG_FFT_FIXED_32 */
# define RSCALE(x) ((x) >> 1)
+#endif /* CONFIG_FFT_FIXED_32 */
#endif
/**
diff --git a/libavcodec/mdct_fixed.c b/libavcodec/mdct_fixed.c
index 94527f9..33a266d 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 CONFIG_FFT_FLOAT 0
+#define CONFIG_FFT_FIXED_32 0
#include "mdct.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..66226f3
--- a/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 CONFIG_FFT_FLOAT 0
+#define CONFIG_FFT_FIXED_32 1
+#include "mdct.c"
diff --git a/libavcodec/mdct_float.c b/libavcodec/mdct_float.c
index e4f5549..fec18ba 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 CONFIG_FFT_FLOAT 1
+#define CONFIG_FFT_FIXED_32 0
#include "mdct.c"
diff --git a/libavcodec/mdec.c b/libavcodec/mdec.c
index b9ffca6..ea47822 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
*/
@@ -121,7 +121,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->dsp.clear_blocks(block[0]);
@@ -165,10 +165,8 @@ static int decode_frame(AVCodecContext *avctx,
ThreadFrame frame = { .f = data };
int i, 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;
@@ -179,7 +177,8 @@ static int decode_frame(AVCodecContext *avctx,
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);
+ 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);
diff --git a/libavcodec/metasound.c b/libavcodec/metasound.c
index 88cbff6..5c65f03 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
*/
@@ -226,7 +226,7 @@ static int metasound_read_bitstream(AVCodecContext *avctx, TwinVQContext *tctx,
}
}
- 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 b159897..c6a8121 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
*/
@@ -3741,6 +3741,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 fcb44sl[] = {
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..f3c640f
--- a/dev/null
+++ b/libavcodec/microdvddec.c
@@ -0,0 +1,377 @@
+/*
+ * 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 c;
+ char *decoded_sub;
+ 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;
+
+ /* To be removed later */
+ if (sscanf(line, "{%*d}{%*[0123456789]}%c", &c) == 1 &&
+ line[avpkt->size - 1] == '\n') {
+ av_log(avctx, AV_LOG_ERROR, "AVPacket is not clean (contains timing "
+ "information and a trailing line break). You need to upgrade "
+ "your libavformat or sanitize your packet.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ 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) {
+ av_bprintf(&new_line, "\r\n");
+
+ av_bprint_finalize(&new_line, &decoded_sub);
+ if (*decoded_sub) {
+ 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;
+ ff_ass_add_rect(sub, decoded_sub, ts_start, ts_duration, 0);
+ }
+ av_free(decoded_sub);
+ }
+
+ *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 264c74a..a1cb5e7 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
*/
@@ -175,7 +175,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;
@@ -251,7 +251,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];
@@ -388,8 +388,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");
@@ -405,10 +405,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
--- a/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..d6210d1
--- a/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 *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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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..0f6f03f
--- a/dev/null
+++ b/libavcodec/mips/compute_antialias_float.h
@@ -0,0 +1,185 @@
+/*
+ * 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];
+ int n;
+ /* 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 */
+ n = 1;
+ ptr_end = ptr + 18;
+ } else {
+ n = 31;
+ 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..d240f1f
--- a/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 = 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 = 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 = 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(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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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 a69b519..96e1854 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
*/
@@ -127,6 +127,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 ec36589..f367288 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 a5f32a6..f061f0b 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
*/
@@ -52,6 +52,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 */
@@ -129,13 +130,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;
@@ -158,4 +163,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 fdf7c87..5c25a07 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,15 +30,18 @@
* MJPEG decoder.
*/
-#include <assert.h>
-
#include "libavutil/imgutils.h"
+#include "libavutil/avassert.h"
#include "libavutil/opt.h"
#include "avcodec.h"
+#include "copy_block.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,
@@ -50,7 +53,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);
@@ -86,6 +89,7 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx)
if (!s->picture_ptr)
s->picture_ptr = &s->picture;
+ avcodec_get_frame_defaults(&s->picture);
s->avctx = avctx;
ff_hpeldsp_init(&s->hdsp, avctx->flags);
@@ -95,24 +99,24 @@ 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;
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");
}
if (avctx->codec->id == AV_CODEC_ID_AMV)
s->flipped = 1;
@@ -129,10 +133,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)
@@ -141,7 +145,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
@@ -212,9 +216,15 @@ int ff_mjpeg_decode_dht(MJpegDecodeContext *s)
int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
{
int len, nb_components, i, width, height, pix_fmt_id;
+ 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->avctx->bits_per_raw_sample =
s->bits = get_bits(&s->gb, 8);
if (s->pegasus_rct)
@@ -222,8 +232,8 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
if (s->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;
}
@@ -258,28 +268,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]);
}
@@ -288,15 +302,18 @@ 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
+ || memcmp(s->h_count, h_count, sizeof(h_count))
+ || memcmp(s->v_count, v_count, sizeof(v_count))) {
+
s->width = width;
s->height = height;
+ 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 &&
@@ -314,7 +331,16 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
s->first_picture = 0;
}
- if (!(s->interlaced && (s->bottom_field == !s->interlace_polarity))) {
+ if (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) |
@@ -331,28 +357,115 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
switch (pix_fmt_id) {
case 0x11111100:
if (s->rgb)
- s->avctx->pix_fmt = AV_PIX_FMT_BGRA;
+ s->avctx->pix_fmt = s->bits <= 9 ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_BGR48;
+ else {
+ if (s->component_id[0] == 'Q' && s->component_id[1] == 'F' && s->component_id[2] == 'A') {
+ s->avctx->pix_fmt = s->bits <= 8 ? AV_PIX_FMT_GBRP : AV_PIX_FMT_GBRP16;
+ } else {
+ if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P;
+ else s->avctx->pix_fmt = AV_PIX_FMT_YUV444P16;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ }
+ }
+ av_assert0(s->nb_components == 3);
+ break;
+ case 0x11111111:
+ if (s->rgb)
+ s->avctx->pix_fmt = s->bits <= 9 ? AV_PIX_FMT_ABGR : AV_PIX_FMT_RGBA64;
+ else {
+ s->avctx->pix_fmt = s->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 0x12121100:
+ case 0x22122100:
+ 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;
+ s->upscale_v = 2;
+ s->upscale_h = (pix_fmt_id == 0x22122100);
+ s->chroma_height = s->height;
+ break;
+ case 0x21211100:
+ case 0x22211200:
+ if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P;
else
- s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P;
- assert(s->nb_components == 3);
+ goto unk_pixfmt;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ s->upscale_v = (pix_fmt_id == 0x22211200);
+ s->upscale_h = 2;
+ s->chroma_height = s->height;
+ break;
+ case 0x22221100:
+ 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;
+ s->upscale_v = 2;
+ s->upscale_h = 2;
+ s->chroma_height = s->height / 2;
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 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;
+ s->upscale_h = (pix_fmt_id == 0x22211100) * 2 + (pix_fmt_id == 0x22112100);
+ s->chroma_height = s->height / 2;
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;
+ s->upscale_v = (pix_fmt_id == 0x22121100) + 1;
break;
case 0x22111100:
- s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_YUVJ420P;
+ 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;
+ 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);
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->bits <= 8)
@@ -362,10 +475,8 @@ 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;
@@ -381,6 +492,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);
@@ -391,6 +507,8 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
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));
+ 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));
@@ -402,11 +520,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)
@@ -423,7 +541,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;
}
@@ -471,7 +589,7 @@ static int decode_dc_progressive(MJpegDecodeContext *s, int16_t *block,
int val;
s->dsp.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;
}
@@ -645,46 +763,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);
+ uint8_t *ptr = s->picture.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) {
@@ -692,24 +865,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];
+ }
+ }
}
}
}
@@ -719,48 +915,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.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.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++;
@@ -770,7 +1006,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];
@@ -779,16 +1016,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.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.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++;
@@ -805,6 +1056,37 @@ 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,
const AVFrame *reference)
@@ -814,23 +1096,23 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah,
const uint8_t *reference_data[MAX_COMPONENTS];
int linesize[MAX_COMPONENTS];
GetBitContext mb_bitmask_gb;
+ int bytes_per_pixel = 1 + (s->bits > 8);
if (mb_bitmask)
init_get_bits(&mb_bitmask_gb, mb_bitmask, s->mb_width * s->mb_height);
- if (s->flipped && s->avctx->flags & CODEC_FLAG_EMU_EDGE) {
- av_log(s->avctx, AV_LOG_ERROR,
- "Can not flip image with CODEC_FLAG_EMU_EDGE set!\n");
+ if (s->flipped && s->avctx->lowres) {
+ av_log(s->avctx, AV_LOG_ERROR, "Can not flip image with lowres\n");
s->flipped = 0;
}
-
+ s->restart_count = 0;
for (i = 0; i < nb_components; i++) {
int c = s->comp_index[i];
data[c] = s->picture_ptr->data[c];
reference_data[c] = reference ? reference->data[c] : NULL;
linesize[c] = s->linesize[c];
s->coefs_finished[c] |= 1;
- if (s->flipped) {
+ if (s->flipped && !(s->avctx->flags & CODEC_FLAG_EMU_EDGE)) {
// picture should be flipped upside-down for this codec
int offset = (linesize[c] * (s->v_scount[i] *
(8 * s->mb_height - ((s->height / s->v_max) & 7)) - 1));
@@ -863,27 +1145,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->dsp.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->dsp.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) +
@@ -891,9 +1175,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);
@@ -911,72 +1195,50 @@ 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;
+ uint8_t *data = s->picture.data[c];
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[c] |= (1LL << (se + 1)) - (1LL << 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);
@@ -988,18 +1250,15 @@ 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->dsp.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;
@@ -1013,6 +1272,13 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask,
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);
@@ -1042,27 +1308,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 */
@@ -1079,10 +1353,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 */
@@ -1091,9 +1365,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);
@@ -1103,8 +1378,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,
@@ -1115,11 +1389,10 @@ 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,
@@ -1135,7 +1408,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;
@@ -1174,16 +1447,15 @@ static int mjpeg_decode_app(MJpegDecodeContext *s)
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);
+ av_log(s->avctx, AV_LOG_DEBUG, "APPx %8X len=%d\n", 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
@@ -1191,12 +1463,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);
@@ -1208,7 +1477,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);
@@ -1236,7 +1505,7 @@ static int mjpeg_decode_app(MJpegDecodeContext *s)
goto out;
}
- if (id == AV_RL32("Adob") && (get_bits(&s->gb, 8) == 'e')) {
+ if (id == AV_RB32("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");
skip_bits(&s->gb, 16); /* version */
@@ -1247,15 +1516,15 @@ static int mjpeg_decode_app(MJpegDecodeContext *s)
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;
@@ -1265,19 +1534,69 @@ 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;
+ }
+
+ /* EXIF metadata */
+ if (s->start_code == APP1 && id == AV_RB32("Exif")) {
+ 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");
+ return ret;
+ }
+
+ bytestream2_seek(&gbytes, ifd_offset, SEEK_SET);
+
+ // read 0th IFD and store the metadata
+ // (return values > 0 indicate the presence of subimage metadata)
+ ret = ff_exif_decode_ifd(s->avctx, &gbytes, le, 0, &s->exif_metadata);
+ if (ret < 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "mjpeg: error decoding EXIF data\n");
+ return ret;
+ }
+
+ 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 */
@@ -1319,15 +1638,17 @@ 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")) {
+ if (!strncmp(cbuf, "AVID", 4)) {
s->buggy_avid = 1;
+ if (len > 14 && cbuf[12] == 1) /* 1 - NTSC, 2 - PAL */
+ s->interlace_polarity = 1;
} 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)) ||
+ (!strncmp(cbuf, "Metasoft MJPEG Codec", 20)))
s->flipped = 1;
av_free(cbuf);
@@ -1344,22 +1665,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);
@@ -1423,7 +1741,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;
}
}
@@ -1463,11 +1781,14 @@ 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;
- s->got_picture = 0; // picture from previous image can not be reused
+ av_dict_free(&s->exif_metadata);
+
buf_ptr = buf;
buf_end = buf + buf_size;
while (buf_ptr < buf_end) {
@@ -1484,14 +1805,15 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
start_code, unescaped_buf_size, buf_size);
return AVERROR_INVALIDDATA;
}
-
av_log(avctx, AV_LOG_DEBUG, "marker=%x avail_size_in_buf=%td\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)
@@ -1508,6 +1830,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");
@@ -1526,7 +1850,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:
@@ -1535,39 +1859,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");
@@ -1577,34 +1899,33 @@ 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(data, s->picture_ptr)) < 0)
return ret;
*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 &&
(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);
@@ -1624,7 +1945,6 @@ 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,
@@ -1637,8 +1957,70 @@ not_the_end:
}
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",
+ if (s->upscale_h) {
+ uint8_t *line = s->picture_ptr->data[s->upscale_h];
+ 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);
+ for (i = 0; i < s->chroma_height; i++) {
+ for (index = s->width - 1; index; index--)
+ line[index] = (line[index / 2] + line[(index + 1) / 2]) >> 1;
+ line += s->linesize[s->upscale_h];
+ }
+ }
+ if (s->upscale_v) {
+ uint8_t *dst = &((uint8_t *)s->picture_ptr->data[s->upscale_v])[(s->height - 1) * s->linesize[s->upscale_v]];
+ int w;
+ avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift);
+ w = s->width >> hshift;
+ 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);
+ for (i = s->height - 1; i; i--) {
+ uint8_t *src1 = &((uint8_t *)s->picture_ptr->data[s->upscale_v])[i / 2 * s->linesize[s->upscale_v]];
+ uint8_t *src2 = &((uint8_t *)s->picture_ptr->data[s->upscale_v])[(i + 1) / 2 * s->linesize[s->upscale_v]];
+ if (src1 == src2) {
+ memcpy(dst, src1, w);
+ } else {
+ for (index = 0; index < w; index++)
+ dst[index] = (src1[index] + src2[index]) >> 1;
+ }
+ dst -= s->linesize[s->upscale_v];
+ }
+ }
+ if (s->flipped && (s->avctx->flags & CODEC_FLAG_EMU_EDGE)) {
+ 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->width;
+ int h = s->height;
+ if(index && index<3){
+ w = FF_CEIL_RSHIFT(w, hshift);
+ h = FF_CEIL_RSHIFT(h, vshift);
+ }
+ if(dst){
+ uint8_t *dst2 = dst + s->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->linesize[index];
+ dst2 -= s->linesize[index];
+ }
+ }
+ }
+ }
+
+ 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 %td bytes\n",
buf_end - buf_ptr);
// return buf_end - buf_ptr;
return buf_ptr - buf;
@@ -1649,6 +2031,10 @@ 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_ptr)
av_frame_unref(s->picture_ptr);
@@ -1664,9 +2050,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[] = {
@@ -1691,10 +2085,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"),
@@ -1704,5 +2101,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 36598dd..fa69d50 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
*/
@@ -59,14 +59,19 @@ typedef struct MJpegDecodeContext {
int ls;
int progressive;
int rgb;
+ int upscale_h;
+ int chroma_height;
+ int upscale_v;
int rct; /* standard rct */
int pegasus_rct; /* pegasus reversible colorspace transform */
int bits; /* bits per component */
+ int colr;
+ int xfrm;
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;
@@ -81,6 +86,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 ?) */
@@ -113,6 +119,7 @@ typedef struct MJpegDecodeContext {
unsigned int ljpeg_buffer_size;
int extern_huff;
+ AVDictionary *exif_metadata;
} MJpegDecodeContext;
int ff_mjpeg_decode_init(AVCodecContext *avctx);
diff --git a/libavcodec/mjpegenc.c b/libavcodec/mjpegenc.c
index 0bf3dc1..74817ca 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 "avcodec.h"
#include "mpegvideo.h"
#include "mjpeg.h"
@@ -46,6 +44,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 -1;
+ }
+
m = av_malloc(sizeof(MJpegContext));
if (!m)
return -1;
@@ -108,6 +111,7 @@ static void jpeg_table_header(MpegEncContext *s)
int i, j, size;
uint8_t *ptr;
+ if (s->avctx->codec_id != AV_CODEC_ID_LJPEG) {
/* quant matrixes */
put_marker(p, DQT);
#ifdef TWOMATRIXES
@@ -129,6 +133,13 @@ static void jpeg_table_header(MpegEncContext *s)
put_bits(p, 8, s->chroma_intra_matrix[j]);
}
#endif
+ }
+
+ if(s->avctx->active_thread_type & FF_THREAD_SLICE){
+ put_marker(p, DRI);
+ put_bits(p, 16, 4);
+ put_bits(p, 16, (s->width-1)/(8*s->mjpeg_hsample[0]) + 1);
+ }
/* huffman table */
put_marker(p, DHT);
@@ -154,13 +165,13 @@ static void jpeg_put_comments(MpegEncContext *s)
int size;
uint8_t *ptr;
- if (s->aspect_ratio_info /* && !lossless */)
+ if (s->avctx->sample_aspect_ratio.num /* && !lossless */)
{
/* JFIF header */
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, s->avctx->sample_aspect_ratio.num);
put_bits(p, 16, s->avctx->sample_aspect_ratio.den);
@@ -195,9 +206,13 @@ static void jpeg_put_comments(MpegEncContext *s)
void ff_mjpeg_encode_picture_header(MpegEncContext *s)
{
const int lossless= s->avctx->codec_id != AV_CODEC_ID_MJPEG;
+ int i;
put_marker(&s->pb, SOI);
+ // hack for AMV mjpeg format
+ if(s->avctx->codec_id == AV_CODEC_ID_AMV) goto end;
+
jpeg_put_comments(s);
jpeg_table_header(s);
@@ -205,11 +220,13 @@ void ff_mjpeg_encode_picture_header(MpegEncContext *s)
switch(s->avctx->codec_id){
case AV_CODEC_ID_MJPEG: put_marker(&s->pb, SOF0 ); break;
case AV_CODEC_ID_LJPEG: put_marker(&s->pb, SOF3 ); break;
- default: assert(0);
+ default: av_assert0(0);
}
put_bits(&s->pb, 16, 17);
- if(lossless && s->avctx->pix_fmt == AV_PIX_FMT_BGRA)
+ if(lossless && (s->avctx->pix_fmt == AV_PIX_FMT_BGR0
+ || s->avctx->pix_fmt == AV_PIX_FMT_BGRA
+ || s->avctx->pix_fmt == AV_PIX_FMT_BGR24))
put_bits(&s->pb, 8, 9); /* 9 bits/component RCT */
else
put_bits(&s->pb, 8, 8); /* 8 bits/component */
@@ -268,10 +285,15 @@ void ff_mjpeg_encode_picture_header(MpegEncContext *s)
switch(s->avctx->codec_id){
case AV_CODEC_ID_MJPEG: put_bits(&s->pb, 8, 63); break; /* Se (not used) */
case AV_CODEC_ID_LJPEG: put_bits(&s->pb, 8, 0); break; /* not used */
- default: assert(0);
+ default: av_assert0(0);
}
put_bits(&s->pb, 8, 0); /* Ah/Al (not used) */
+
+end:
+ s->esc_pos = put_bits_count(&s->pb) >> 3;
+ for(i=1; i<s->slice_context_count; i++)
+ s->thread_context[i]->esc_pos = 0;
}
static void escape_FF(MpegEncContext *s, int start)
@@ -281,7 +303,7 @@ static void escape_FF(MpegEncContext *s, int start)
uint8_t *buf= s->pb.buf + start;
int align= (-(size_t)(buf))&3;
- assert((size&7) == 0);
+ av_assert1((size&7) == 0);
size >>= 3;
ff_count=0;
@@ -326,21 +348,30 @@ static void escape_FF(MpegEncContext *s, int start)
}
}
-void ff_mjpeg_encode_stuffing(PutBitContext * pbc)
+void ff_mjpeg_encode_stuffing(MpegEncContext *s)
{
- int length;
+ int length, i;
+ PutBitContext *pbc = &s->pb;
+ int mb_y = s->mb_y - !s->mb_x;
length= (-put_bits_count(pbc))&7;
if(length) put_bits(pbc, length, (1<<length)-1);
+
+ flush_put_bits(&s->pb);
+ escape_FF(s, 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(MpegEncContext *s)
{
- ff_mjpeg_encode_stuffing(&s->pb);
- flush_put_bits(&s->pb);
- assert((s->header_bits&7)==0);
+ av_assert1((s->header_bits&7)==0);
- escape_FF(s, s->header_bits>>3);
put_marker(&s->pb, EOI);
}
@@ -428,20 +459,61 @@ static void encode_block(MpegEncContext *s, int16_t *block, int n)
void ff_mjpeg_encode_mb(MpegEncContext *s, int16_t block[6][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 = *pic_arg;
+ int i;
+
+ //CODEC_FLAG_EMU_EDGE have to be cleared
+ if(s->avctx->flags & CODEC_FLAG_EMU_EDGE)
+ return -1;
+
+ //picture should be flipped upside-down
+ for(i=0; i < 3; i++) {
+ pic.data[i] += (pic.linesize[i] * (s->mjpeg_vsample[i] * (8 * s->mb_height -((s->height/V_MAX)&7)) - 1 ));
+ pic.linesize[i] *= -1;
+ }
+ return ff_MPV_encode_picture(avctx, pkt, &pic, got_packet);
+}
+
+#if CONFIG_MJPEG_ENCODER
AVCodec ff_mjpeg_encoder = {
.name = "mjpeg",
.long_name = NULL_IF_CONFIG_SMALL("MJPEG (Motion JPEG)"),
@@ -451,7 +523,24 @@ 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
+ },
+};
+#endif
+#if CONFIG_AMV_ENCODER
+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
},
};
+#endif
diff --git a/libavcodec/mjpegenc.h b/libavcodec/mjpegenc.h
index 11dd0b2..ce0c1cc 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
*/
@@ -53,7 +53,7 @@ int ff_mjpeg_encode_init(MpegEncContext *s);
void ff_mjpeg_encode_close(MpegEncContext *s);
void ff_mjpeg_encode_picture_header(MpegEncContext *s);
void ff_mjpeg_encode_picture_trailer(MpegEncContext *s);
-void ff_mjpeg_encode_stuffing(PutBitContext *pbc);
+void ff_mjpeg_encode_stuffing(MpegEncContext *s);
void ff_mjpeg_encode_dc(MpegEncContext *s, int val,
uint8_t *huff_size, uint16_t *huff_code);
void ff_mjpeg_encode_mb(MpegEncContext *s, int16_t block[6][64]);
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 d771112..d8d1292 100644
--- a/libavcodec/mlp.h
+++ b/libavcodec/mlp.h
@@ -2,20 +2,20 @@
* MLP codec common header file
* Copyright (c) 2007-2008 Ian Caulfield
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mlp_parser.c b/libavcodec/mlp_parser.c
index 1a68014..fcd1168 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;
@@ -130,7 +130,7 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
int ratebits, channel_arrangement;
uint16_t checksum;
- assert(get_bits_count(gb) == 0);
+ av_assert1(get_bits_count(gb) == 0);
if (gb->size_in_bits < 28 << 3) {
av_log(log, AV_LOG_ERROR, "packet too short, unable to read major sync\n");
@@ -158,9 +158,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;
@@ -171,15 +172,16 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
skip_bits(gb, 8);
+ 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);
skip_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;
@@ -246,7 +248,8 @@ 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;
}
@@ -264,13 +267,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;
}
@@ -321,6 +328,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
@@ -329,8 +337,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 == AV_CH_LAYOUT_STEREO &&
mh.num_substreams > 1) {
@@ -352,8 +360,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 == AV_CH_LAYOUT_STEREO &&
mh.num_substreams > 1) {
@@ -368,6 +376,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 e874426..9967abb 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
*/
@@ -39,6 +39,7 @@ 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 channels_mlp; ///< Channel count for MLP streams
int channels_thd_stream1; ///< Channel count for substream 1 of TrueHD streams ("6-channel presentation")
int channels_thd_stream2; ///< Channel count for substream 2 of TrueHD streams ("8-channel presentation")
@@ -57,5 +58,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 4339b9d..aab8293 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
*/
@@ -132,6 +132,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
@@ -372,8 +375,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;
+
return 0;
}
@@ -419,7 +431,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;
}
@@ -431,11 +443,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;
}
@@ -459,8 +471,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->max_decoded_substream > substr) {
@@ -499,7 +511,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
ch_assign = av_get_channel_layout_channel_index(s->ch_layout,
channel);
}
- if (ch_assign > s->max_matrix_channel) {
+ if ((unsigned)ch_assign > s->max_matrix_channel) {
avpriv_request_sample(m->avctx,
"Assignment of matrix channel %d to invalid output channel %d",
ch, ch_assign);
@@ -539,6 +551,20 @@ FF_ENABLE_DEPRECATION_WARNINGS
if (substr == m->max_decoded_substream) {
m->avctx->channels = s->max_matrix_channel + 1;
m->avctx->channel_layout = s->ch_layout;
+
+ 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;
@@ -557,7 +583,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");
@@ -612,7 +638,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;
}
}
@@ -731,6 +757,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;
}
@@ -757,7 +784,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;
}
@@ -1001,10 +1028,8 @@ static int output_data(MLPDecodeContext *m, unsigned int substr,
/* 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;
- }
data_32 = (int32_t *)frame->data[0];
data_16 = (int16_t *)frame->data[0];
@@ -1045,7 +1070,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;
@@ -1224,6 +1249,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)"),
@@ -1234,7 +1260,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 b96200e..b413e86 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 995f72a..84a8aa3 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 edf602b..ea182a0 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
*/
@@ -72,7 +72,7 @@ static int mm_decode_pal(MmContext *s)
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;
}
@@ -104,6 +104,9 @@ 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)
@@ -120,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)
*/
@@ -152,6 +155,8 @@ static int mm_decode_inter(MmContext * s, int half_horiz, int half_vert)
int replace_array = bytestream2_get_byte(&s->gb);
for(j=0; j<8; j++) {
int replace = (replace_array >> (7-j)) & 1;
+ if (x + half_horiz >= s->avctx->width)
+ return AVERROR_INVALIDDATA;
if (replace) {
int color = bytestream2_get_byte(&data_ptr);
s->frame.data[0][y*s->frame.linesize[0] + x] = color;
@@ -189,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 : res = 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;
@@ -216,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..53cfedb
--- a/dev/null
+++ b/libavcodec/motion-test.c
@@ -0,0 +1,151 @@
+/*
+ * (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 "dsputil.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();
+ 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() - 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;
+ DSPContext 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;
+ memset(&cctx, 0, sizeof(cctx));
+ ff_dsputil_init(&cctx, ctx);
+ for (c = 0; c < flags_size; c++) {
+ int x;
+ av_force_cpu_flags(flags[c]);
+ memset(&mmxctx, 0, sizeof(mmxctx));
+ ff_dsputil_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 04ae49e..f4d217b 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
*/
@@ -112,7 +112,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;
@@ -154,14 +154,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);
@@ -297,13 +297,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;
}
@@ -356,14 +355,16 @@ 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->dsp.me_cmp[2]*/){
- s->dsp.me_cmp[2]= zero_cmp;
- }
- if((c->avctx->me_sub_cmp&FF_CMP_CHROMA) && !s->dsp.me_sub_cmp[2]){
- s->dsp.me_sub_cmp[2]= zero_cmp;
+ if(s->codec_id != AV_CODEC_ID_SNOW){
+ if((c->avctx->me_cmp&FF_CMP_CHROMA)/* && !s->dsp.me_cmp[2]*/){
+ s->dsp.me_cmp[2]= zero_cmp;
+ }
+ if((c->avctx->me_sub_cmp&FF_CMP_CHROMA) && !s->dsp.me_sub_cmp[2]){
+ s->dsp.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;
}
- 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;
@@ -392,7 +393,7 @@ static int sad_hpel_motion_search(MpegEncContext * s,
const int flags= c->sub_flags;
LOAD_COMMON
- assert(flags == 0);
+ av_assert2(flags == 0);
if(c->skip){
*mx_ptr = 0;
@@ -516,6 +517,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;
@@ -523,8 +525,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;
@@ -537,6 +539,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);
@@ -563,10 +567,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);
@@ -578,6 +583,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];
@@ -605,6 +615,11 @@ 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=0; i<10; i++){
+ 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);
@@ -736,8 +751,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;
}
@@ -834,6 +849,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;
@@ -862,9 +881,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);
@@ -1061,7 +1080,7 @@ int ff_pre_estimate_p_frame_motion(MpegEncContext * s,
const int xy= mb_x + mb_y*s->mb_stride;
init_ref(c, s->new_picture.f.data, s->last_picture.f.data, NULL, 16*mb_x, 16*mb_y, 0);
- assert(s->quarter_sample==0 || s->quarter_sample==1);
+ av_assert0(s->quarter_sample==0 || s->quarter_sample==1);
c->pre_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_pre_cmp);
c->current_mv_penalty= c->mv_penalty[s->f_code] + MAX_MV;
@@ -1439,7 +1458,7 @@ static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y)
if(s->mv_type == MV_TYPE_16X16) break;
}
- assert(xmax <= 15 && ymax <= 15 && xmin >= -16 && ymin >= -16);
+ av_assert2(xmax <= 15 && ymax <= 15 && xmin >= -16 && ymin >= -16);
if(xmax < 0 || xmin >0 || ymax < 0 || ymin > 0){
s->b_direct_mv_table[mot_xy][0]= 0;
@@ -1655,12 +1674,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 7228744..3123edc 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
*/
@@ -89,19 +89,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){
@@ -141,7 +140,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;
@@ -180,9 +179,6 @@ static inline int get_mb_score(MpegEncContext *s, int mx, int my,
cmp_sub= s->dsp.mb_cmp[size];
chroma_cmp_sub= s->dsp.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))
@@ -309,11 +305,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++){
@@ -346,7 +342,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;
@@ -363,10 +359,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;\
@@ -404,10 +400,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;\
@@ -692,6 +688,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->dsp.me_cmp[size];
chroma_cmpf= s->dsp.me_cmp[size+1];
@@ -888,7 +886,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 6a7dd23..f8aa08b 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
*/
@@ -56,6 +56,11 @@ 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_dsputil_init(&mp->dsp, avctx);
@@ -63,6 +68,12 @@ static av_cold int mp_decode_init(AVCodecContext *avctx)
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));
+ 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;
avcodec_get_frame_defaults(&mp->frame);
return 0;
@@ -97,38 +108,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)
@@ -216,6 +237,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));
@@ -248,10 +271,8 @@ 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);
@@ -279,7 +300,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 ad8e0d9..31e5cdf 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 cbf56c8..b9802e5 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
*/
@@ -30,7 +30,7 @@ typedef struct YuvPixel {
} YuvPixel;
static int mp_yuv_to_rgb(int y, int v, int u, int clip_rgb) {
- static const uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
+ const uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
int r, g, b;
r = (1000 * y + 701 * v) / 1000;
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..05ff53a
--- a/dev/null
+++ b/libavcodec/movtextdec.c
@@ -0,0 +1,116 @@
+/*
+ * 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++;
+ }
+
+ av_bprintf(buf, "\r\n");
+ 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 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);
+
+ if (!av_bprint_is_complete(&buf))
+ return AVERROR(ENOMEM);
+
+ ff_ass_add_rect(sub, buf.str, ts_start, ts_end-ts_start, 0);
+ *got_sub_ptr = sub->num_rects > 0;
+ av_bprint_finalize(&buf, NULL);
+ 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..9b0a6c5
--- a/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 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);
+ 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_compress_bsf.c b/libavcodec/mp3_header_compress_bsf.c
index 06a7ebe..e479f6b 100644
--- a/libavcodec/mp3_header_compress_bsf.c
+++ b/libavcodec/mp3_header_compress_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
*/
@@ -82,7 +82,6 @@ output_unchanged:
}
AVBitStreamFilter ff_mp3_header_compress_bsf={
- "mp3comp",
- 0,
- mp3_header_compress,
+ .name = "mp3comp",
+ .filter = mp3_header_compress,
};
diff --git a/libavcodec/mp3_header_decompress_bsf.c b/libavcodec/mp3_header_decompress_bsf.c
index 8e086a1..df45532 100644
--- a/libavcodec/mp3_header_decompress_bsf.c
+++ b/libavcodec/mp3_header_decompress_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
*/
@@ -92,7 +92,6 @@ static int mp3_header_decompress(AVBitStreamFilterContext *bsfc, AVCodecContext
}
AVBitStreamFilter ff_mp3_header_decompress_bsf={
- "mp3decomp",
- 0,
- mp3_header_decompress,
+ .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 cbb121e..295b4c7 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 a38b0ea..86aca63 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
*/
@@ -37,10 +37,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] =
@@ -191,7 +187,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,
@@ -227,11 +223,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 b6e0cfd..2f58805 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
*/
@@ -128,6 +128,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");
@@ -137,7 +141,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");
@@ -249,10 +254,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;
@@ -269,8 +272,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 5724cc8..dad3d4c 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 "dsputil.h"
@@ -34,6 +39,7 @@
#include "mpeg12.h"
#include "mpeg12data.h"
#include "bytestream.h"
+#include "vdpau_internal.h"
#include "xvmc_internal.h"
#include "thread.h"
@@ -196,7 +202,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--;
@@ -237,3 +243,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 9d1696c..82b503d 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
*/
@@ -35,6 +35,7 @@
#include "mpeg12.h"
#include "mpeg12data.h"
#include "bytestream.h"
+#include "vdpau_internal.h"
#include "xvmc_internal.h"
#include "thread.h"
@@ -49,7 +50,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 extradata_decoded;
} Mpeg1Context;
@@ -266,6 +267,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)
{
int level, i, j, run;
@@ -417,6 +423,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)
{
@@ -557,6 +568,11 @@ static inline int mpeg2_decode_block_intra(MpegEncContext *s, int16_t *block, in
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)
{
int level, dc, diff, j, run;
@@ -668,7 +684,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) {
@@ -681,11 +697,12 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64])
mb_type = s->current_picture.mb_type[s->mb_x + s->mb_y * s->mb_stride - 1];
else
mb_type = s->current_picture.mb_type[s->mb_width + (s->mb_y - 1) * s->mb_stride - 1]; // FIXME not sure if this is allowed in MPEG at all
- 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;
@@ -783,11 +800,12 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64])
}
} 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 {
@@ -806,10 +824,10 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64])
s->mv[0][0][0] = 0;
s->mv[0][0][1] = 0;
} else {
- 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);
@@ -883,6 +901,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64])
}
}
} 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)) {
@@ -899,6 +918,10 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64])
}
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)) {
@@ -965,7 +988,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64])
s->dsp.clear_blocks(s->block[6]);
}
if (cbp <= 0) {
- av_log(s->avctx, AV_LOG_ERROR, "invalid cbp at %d %d\n", s->mb_x, s->mb_y);
+ av_log(s->avctx, AV_LOG_ERROR, "invalid cbp %d at %d %d\n", cbp, s->mb_x, s->mb_y);
return -1;
}
@@ -1098,40 +1121,71 @@ static void quant_matrix_rebuild(uint16_t *matrix, const uint8_t *old_perm,
}
}
-static const enum AVPixelFormat pixfmt_xvmc_mpg2_420[] = {
+static const enum AVPixelFormat mpeg1_hwaccel_pixfmt_list_420[] = {
+#if CONFIG_MPEG_XVMC_DECODER
AV_PIX_FMT_XVMC_MPEG2_IDCT,
AV_PIX_FMT_XVMC_MPEG2_MC,
- AV_PIX_FMT_NONE };
+#endif
+#if CONFIG_MPEG1_VDPAU_HWACCEL
+ AV_PIX_FMT_VDPAU_MPEG1,
+ AV_PIX_FMT_VDPAU,
+#endif
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_NONE
+};
-static const enum AVPixelFormat mpeg12_hwaccel_pixfmt_list_420[] = {
+static const enum AVPixelFormat mpeg2_hwaccel_pixfmt_list_420[] = {
+#if CONFIG_MPEG_XVMC_DECODER
+ AV_PIX_FMT_XVMC_MPEG2_IDCT,
+ AV_PIX_FMT_XVMC_MPEG2_MC,
+#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
};
+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;
- if (avctx->xvmc_acceleration)
- return avctx->get_format(avctx, pixfmt_xvmc_mpg2_420);
- else {
- if (s->chroma_format < 2)
- return avctx->get_format(avctx, mpeg12_hwaccel_pixfmt_list_420);
- else if (s->chroma_format == 2)
- return AV_PIX_FMT_YUV422P;
- else
- return AV_PIX_FMT_YUV444P;
+ if(s->chroma_format < 2) {
+ return ff_thread_get_format(avctx,
+ avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO ?
+ mpeg1_hwaccel_pixfmt_list_420 :
+ mpeg2_hwaccel_pixfmt_list_420);
+ } else if(s->chroma_format == 2)
+ return AV_PIX_FMT_YUV422P;
+ else
+ return AV_PIX_FMT_YUV444P;
+}
+
+static void setup_hwaccel_for_pixfmt(AVCodecContext *avctx)
+{
+ if (avctx->pix_fmt != AV_PIX_FMT_XVMC_MPEG2_IDCT && avctx->pix_fmt != AV_PIX_FMT_XVMC_MPEG2_MC) {
+ avctx->xvmc_acceleration = 0;
+ } else if (!avctx->xvmc_acceleration) {
+ avctx->xvmc_acceleration = 2;
}
+ avctx->hwaccel = ff_find_hwaccel(avctx->codec->id, avctx->pix_fmt);
+ // until then pix_fmt may be changed right after codec init
+ if (avctx->pix_fmt == AV_PIX_FMT_XVMC_MPEG2_IDCT ||
+ avctx->hwaccel || uses_vdpau(avctx))
+ if (avctx->idct_algo == FF_IDCT_AUTO)
+ avctx->idct_algo = FF_IDCT_SIMPLE;
}
/* Call this function when we know all parameters.
@@ -1148,7 +1202,7 @@ 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 && (s->height&31)) ||
0)
{
@@ -1157,13 +1211,19 @@ static int mpeg_decode_postinit(AVCodecContext *avctx)
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))
return -2;
avcodec_set_dimensions(avctx, s->width, s->height);
- 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;
@@ -1223,12 +1283,7 @@ static int mpeg_decode_postinit(AVCodecContext *avctx)
} // MPEG-2
avctx->pix_fmt = mpeg_get_pixelformat(avctx);
- avctx->hwaccel = ff_find_hwaccel(avctx->codec->id, avctx->pix_fmt);
- // until then pix_fmt may be changed right after codec init
- if (avctx->pix_fmt == AV_PIX_FMT_XVMC_MPEG2_IDCT ||
- avctx->hwaccel)
- if (avctx->idct_algo == FF_IDCT_AUTO)
- avctx->idct_algo = FF_IDCT_SIMPLE;
+ setup_hwaccel_for_pixfmt(avctx);
/* Quantization matrices may need reordering
* if DCT permutation is changed. */
@@ -1262,19 +1317,22 @@ static int mpeg1_decode_picture(AVCodecContext *avctx,
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;
}
@@ -1320,8 +1378,8 @@ static void mpeg_decode_sequence_extension(Mpeg1Context *s1)
s->codec_id = s->avctx->codec_id = AV_CODEC_ID_MPEG2VIDEO;
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, s->avctx->rc_buffer_size, s->bit_rate);
+ av_log(s->avctx, AV_LOG_DEBUG, "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);
}
@@ -1394,7 +1452,7 @@ static int load_matrix(MpegEncContext *s, uint16_t matrix0[64], uint16_t matrix1
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;
@@ -1435,6 +1493,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);
@@ -1447,28 +1510,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->dsp.idct_permutation, &s->inter_scantable, ff_alternate_vertical_scan);
@@ -1575,14 +1616,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;
@@ -1689,21 +1733,21 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y,
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);
@@ -1717,8 +1761,17 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y,
&& s->intra_dc_precision == 2 && s->q_scale_type == 1 && s->alternate_scan == 0
&& 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
@@ -1825,7 +1878,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)
@@ -1854,7 +1910,7 @@ static int slice_end(AVCodecContext *avctx, AVFrame *pict)
ff_xvmc_field_end(s);
/* 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 && !s->first_slice) {
/* end of image */
ff_er_frame_end(&s->er);
@@ -1865,7 +1921,8 @@ static int slice_end(AVCodecContext *avctx, AVFrame *pict)
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++;
@@ -1875,7 +1932,8 @@ static int slice_end(AVCodecContext *avctx, AVFrame *pict)
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);
}
}
@@ -1900,13 +1958,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);
@@ -1952,6 +2010,7 @@ 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;
@@ -1977,6 +2036,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;
@@ -1984,16 +2044,10 @@ static int vcr2_init_sequence(AVCodecContext *avctx)
s->low_delay = 1;
avctx->pix_fmt = mpeg_get_pixelformat(avctx);
- avctx->hwaccel = ff_find_hwaccel(avctx->codec->id, avctx->pix_fmt);
-
- if (avctx->pix_fmt == AV_PIX_FMT_XVMC_MPEG2_IDCT || avctx->hwaccel)
- if (avctx->idct_algo == FF_IDCT_AUTO)
- avctx->idct_algo = FF_IDCT_SIMPLE;
+ setup_hwaccel_for_pixfmt(avctx);
if (ff_MPV_common_init(s) < 0)
return -1;
- exchange_uv(s); // common init reset pblocks, so we swap them here
- s->swap_uv = 1; // in case of xvmc we need to swap uv for each MB
s1->mpeg_enc_ctx_allocated = 1;
for (i = 0; i < 64; i++) {
@@ -2010,9 +2064,16 @@ 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 {
+ exchange_uv(s); // common init reset pblocks, so we swap them here
+ 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;
@@ -2023,8 +2084,22 @@ static int vcr2_init_sequence(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;
+ 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') {
@@ -2047,31 +2122,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 */
+ tc = avctx->timecode_frame_start = get_bits(&s->gb, 25);
- 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);
-
- 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)
- 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);
+ 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 (%s) closed_gop=%d broken_link=%d\n",
+ tcbuf, s->closed_gop, broken_link);
+ }
}
static int decode_chunks(AVCodecContext *avctx,
@@ -2084,6 +2154,7 @@ static int decode_chunks(AVCodecContext *avctx,
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 */
@@ -2094,12 +2165,17 @@ static int decode_chunks(AVCodecContext *avctx,
if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_SLICE) &&
!avctx->hwaccel) {
int i;
+ av_assert0(avctx->thread_count > 1);
avctx->execute(avctx, slice_decode_thread, &s2->thread_context[0], NULL, s->slice_count, sizeof(void*));
for (i = 0; i < s->slice_count; i++)
s2->er.error_count += s2->thread_context[i]->er.error_count;
}
+ 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;
@@ -2123,7 +2199,8 @@ static int decode_chunks(AVCodecContext *avctx,
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);
if (avctx->err_recognition & AV_EF_EXPLODE)
@@ -2132,12 +2209,24 @@ static int decode_chunks(AVCodecContext *avctx,
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;
@@ -2216,14 +2305,48 @@ static int decode_chunks(AVCodecContext *avctx,
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);
return -1;
@@ -2232,13 +2355,13 @@ static int decode_chunks(AVCodecContext *avctx,
if (s2->last_picture_ptr == NULL) {
/* 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 == NULL) {
/* Skip P-frames if we do not have a reference frame or we have an invalid header. */
@@ -2280,11 +2403,17 @@ static int decode_chunks(AVCodecContext *avctx,
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];
@@ -2325,6 +2454,7 @@ static int mpeg_decode_frame(AVCodecContext *avctx,
AVPacket *avpkt)
{
const uint8_t *buf = avpkt->data;
+ int ret;
int buf_size = avpkt->size;
Mpeg1Context *s = avctx->priv_data;
AVFrame *picture = data;
@@ -2352,19 +2482,32 @@ static int mpeg_decode_frame(AVCodecContext *avctx,
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;
}
@@ -2373,7 +2516,6 @@ static void flush(AVCodecContext *avctx)
Mpeg1Context *s = avctx->priv_data;
s->sync=0;
- s->closed_gop = 0;
ff_mpeg_flush(avctx);
}
@@ -2413,6 +2555,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)
};
@@ -2429,9 +2572,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 CONFIG_MPEG_XVMC_DECODER
static av_cold int mpeg_mc_decode_init(AVCodecContext *avctx)
{
@@ -2465,3 +2624,35 @@ AVCodec ff_mpeg_xvmc_decoder = {
};
#endif
+
+#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 41eefe2..6882789 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
*/
@@ -26,8 +26,10 @@
*/
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
+#include "libavutil/timecode.h"
#include "avcodec.h"
#include "bytestream.h"
#include "mathops.h"
@@ -81,7 +83,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;
@@ -97,26 +99,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;
@@ -126,6 +139,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;
@@ -171,12 +187,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 multiplies 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;
}
@@ -205,8 +247,8 @@ 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;
@@ -280,8 +322,8 @@ 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
}
put_header(s, GOP_START_CODE);
@@ -293,15 +335,11 @@ 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);
@@ -325,7 +363,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);
@@ -334,7 +372,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);
@@ -402,7 +440,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 */
@@ -476,7 +514,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],
@@ -618,7 +656,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)
@@ -640,7 +678,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);
@@ -719,7 +757,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) {
@@ -806,8 +844,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)
@@ -988,6 +1026,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.", \
@@ -1045,7 +1085,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 628ca67..9b86997 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 214aa81..c4d23c9 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
*/
@@ -104,6 +104,7 @@ int ff_mpeg4_decode_partitions(MpegEncContext *s);
int ff_mpeg4_get_video_packet_prefix_length(MpegEncContext *s);
int ff_mpeg4_decode_video_packet_header(MpegEncContext *s);
void ff_mpeg4_init_direct_mv(MpegEncContext *s);
+void ff_mpeg4videodec_static_init(void);
/**
*
@@ -177,7 +178,7 @@ static inline int ff_mpeg4_pred_dc(MpegEncContext * s, int n, int level, int *di
}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);
return -1;
diff --git a/libavcodec/mpeg4video_parser.c b/libavcodec/mpeg4video_parser.c
index e291262..b3cbf91 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 "parser.h"
#include "mpegvideo.h"
#include "mpeg4video.h"
@@ -91,6 +93,13 @@ static int av_mpeg4_decode_header(AVCodecParserContext *s1,
if (s->width && (!avctx->width || !avctx->height || !avctx->coded_width || !avctx->coded_height)) {
avcodec_set_dimensions(avctx, s->width, s->height);
}
+ 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;
@@ -100,8 +109,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->enc.quant_precision=5;
pc->enc.slice_context_count = 1;
+ pc->enc.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 9a0b42b..6de1735 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 "internal.h"
#include "mpegvideo.h"
@@ -115,7 +118,7 @@ static inline int mpeg4_is_resync(MpegEncContext *s){
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 && !s->resync_marker){
return 0;
}
@@ -132,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);
@@ -145,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;
@@ -348,6 +356,17 @@ static int mpeg4_decode_sprite_trajectory(MpegEncContext *s, GetBitContext *gb)
return 0;
}
+static int decode_new_pred(MpegEncContext *s, GetBitContext *gb){
+ int len = FFMIN(s->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
@@ -379,17 +398,6 @@ int ff_mpeg4_decode_video_packet_header(MpegEncContext *s)
av_log(s->avctx, AV_LOG_ERROR, "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 which where already decoded
- }
s->mb_x= mb_num % s->mb_width;
s->mb_y= mb_num / s->mb_width;
@@ -441,7 +449,8 @@ int ff_mpeg4_decode_video_packet_header(MpegEncContext *s)
}
}
}
- //FIXME new-pred stuff
+ if (s->new_pred)
+ decode_new_pred(s, &s->gb);
return 0;
}
@@ -528,7 +537,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;
}
@@ -852,7 +861,7 @@ static inline int mpeg4_decode_block(MpegEncContext * s, int16_t * block,
int n, int coded, int intra, int rvlc)
{
int level, i, last, run;
- int dc_pred_dir;
+ int av_uninit(dc_pred_dir);
RLTable * rl;
RL_VLC_ELEM * rl_vlc;
const uint8_t * scan_table;
@@ -998,11 +1007,33 @@ static inline int mpeg4_decode_block(MpegEncContext * s, int16_t * block,
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", s->qscale);
return -1;
@@ -1162,7 +1193,7 @@ static int mpeg4_decode_mb(MpegEncContext *s,
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) {
do{
@@ -1474,16 +1505,21 @@ 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(s);
+ 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;
}
}
@@ -1494,35 +1530,36 @@ 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) {
- s->avctx->level = 0;
- }
+ // for Simple profile, level 0
+ if (s->avctx->profile == 0 && s->avctx->level == 8) {
+ s->avctx->level = 0;
+ }
- return 0;
+ return 0;
}
static int decode_vol_header(MpegEncContext *s, GetBitContext *gb){
@@ -1565,7 +1602,7 @@ static int decode_vol_header(MpegEncContext *s, GetBitContext *gb){
skip_bits1(gb); /* marker */
}
}else{
- // set low delay flag only once the smartest? low delay detection won't be overriden
+ // set low delay flag only once the smartest? low delay detection won't be overridden
if(s->picture_number==0)
s->low_delay=0;
}
@@ -1601,11 +1638,11 @@ static int decode_vol_header(MpegEncContext *s, GetBitContext *gb){
if (s->shape != BIN_ONLY_SHAPE) {
if (s->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 && !(s->width && s->codec_tag == AV_RL32("MP4S"))){ /* they should be non zero but who knows ... */
if (s->width && s->height &&
(s->width != width || s->height != height))
@@ -1654,6 +1691,9 @@ static int decode_vol_header(MpegEncContext *s, GetBitContext *gb){
s->quant_precision = get_bits(gb, 4); /* quant_precision */
if(get_bits(gb, 4)!=8) av_log(s->avctx, AV_LOG_ERROR, "N-bit not supported\n"); /* bits_per_pixel */
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;
}
@@ -1831,6 +1871,18 @@ no_cplx_est:
// bin shape stuff FIXME
}
}
+
+ if(s->avctx->debug&FF_DEBUG_PICT_INFO) {
+ av_log(s->avctx, AV_LOG_DEBUG, "tb %d/%d, tincrbits:%d, qp_prec:%d, ps:%d, %s%s%s%s\n",
+ s->avctx->time_base.num, s->avctx->time_base.den,
+ s->time_increment_bits,
+ s->quant_precision,
+ s->progressive_sequence,
+ s->scalability ? "scalability " :"" , s->quarter_sample ? "qpel " : "",
+ s->data_partitioning ? "partition " : "", s->rvlc ? "rvlc " : ""
+ );
+ }
+
return 0;
}
@@ -1860,7 +1912,9 @@ static int decode_user_data(MpegEncContext *s, GetBitContext *gb){
s->divx_build= build;
s->divx_packed= e==3 && last=='p';
if(s->divx_packed && !s->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");
s->showed_packed_warning=1;
}
}
@@ -1894,6 +1948,7 @@ static int decode_user_data(MpegEncContext *s, GetBitContext *gb){
static int decode_vop_header(MpegEncContext *s, GetBitContext *gb){
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 && s->vol_control_parameters==0 && !(s->flags & CODEC_FLAG_LOW_DELAY)){
@@ -1925,6 +1980,9 @@ static int decode_vop_header(MpegEncContext *s, GetBitContext *gb){
}
av_log(s->avctx, AV_LOG_ERROR, "my guess is %d bits ;)\n",s->time_increment_bits);
+ if (s->avctx->time_base.den && 4*s->avctx->time_base.den < 1<<s->time_increment_bits) {
+ s->avctx->time_base.den = 1<<s->time_increment_bits;
+ }
}
if(IS_3IV1) time_increment= get_bits1(gb); //FIXME investigate further
@@ -1965,6 +2023,14 @@ static int decode_vop_header(MpegEncContext *s, GetBitContext *gb){
}
}
+ if(s->avctx->time_base.num)
+ pts = ROUNDED_DIV(s->time, s->avctx->time_base.num);
+ 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 */
@@ -1973,6 +2039,9 @@ static int decode_vop_header(MpegEncContext *s, GetBitContext *gb){
av_log(s->avctx, AV_LOG_ERROR, "vop not coded\n");
return FRAME_SKIPPED;
}
+ if (s->new_pred)
+ decode_new_pred(s, gb);
+
if (s->shape != BIN_ONLY_SHAPE && ( s->pict_type == AV_PICTURE_TYPE_P
|| (s->pict_type == AV_PICTURE_TYPE_S && s->vol_sprite_usage==GMC_SPRITE))) {
/* rounding type for motion estimation */
@@ -2007,6 +2076,10 @@ static int decode_vop_header(MpegEncContext *s, GetBitContext *gb){
if(s->pict_type == AV_PICTURE_TYPE_B)
skip_bits_long(gb, s->cplx_estimation_trash_b);
+ if(get_bits_left(gb) < 3) {
+ av_log(s->avctx, AV_LOG_ERROR, "Header truncated\n");
+ return -1;
+ }
s->intra_dc_threshold= ff_mpeg4_dc_threshold[ get_bits(gb, 3) ];
if(!s->progressive_sequence){
s->top_field_first= get_bits1(gb);
@@ -2045,6 +2118,7 @@ static int decode_vop_header(MpegEncContext *s, GetBitContext *gb){
s->f_code = get_bits(gb, 3); /* fcode_for */
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 the MV decoding will break very quickly
}
}else
@@ -2052,16 +2126,25 @@ static int decode_vop_header(MpegEncContext *s, 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",
+ 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 time:%"PRId64" tincr:%d\n",
s->qscale, s->f_code, s->b_code,
s->pict_type == AV_PICTURE_TYPE_I ? "I" : (s->pict_type == AV_PICTURE_TYPE_P ? "P" : (s->pict_type == AV_PICTURE_TYPE_B ? "B" : "S")),
gb->size_in_bits,s->progressive_sequence, s->alternate_scan, s->top_field_first,
s->quarter_sample ? "q" : "h", s->data_partitioning, s->resync_marker, s->num_sprite_warping_points,
- s->sprite_warping_accuracy, 1-s->no_rounding, s->vo_type, s->vol_control_parameters ? " VOLC" : " ", s->intra_dc_threshold, s->cplx_estimation_trash_i, s->cplx_estimation_trash_p, s->cplx_estimation_trash_b);
+ s->sprite_warping_accuracy, 1-s->no_rounding, s->vo_type, s->vol_control_parameters ? " VOLC" : " ", s->intra_dc_threshold,
+ s->cplx_estimation_trash_i, s->cplx_estimation_trash_p, s->cplx_estimation_trash_b,
+ s->time,
+ time_increment
+ );
}
if(!s->scalability){
@@ -2119,8 +2202,8 @@ int ff_mpeg4_decode_picture_header(MpegEncContext * s, GetBitContext *gb)
startcode = 0xff;
for(;;) {
if(get_bits_count(gb) >= gb->size_in_bits){
- if(gb->size_in_bits==8 && (s->divx_version>=0 || s->xvid_build>=0)){
- av_log(s->avctx, AV_LOG_WARNING, "frame skip %d\n", gb->size_in_bits);
+ if(gb->size_in_bits==8 && (s->divx_version>=0 || s->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
@@ -2192,23 +2275,10 @@ end:
return decode_vop_header(s, gb);
}
-static av_cold int decode_init(AVCodecContext *avctx)
-{
- MpegEncContext *s = avctx->priv_data;
- int ret;
+av_cold void ff_mpeg4videodec_static_init(void) {
static int done = 0;
- s->divx_version=
- s->divx_build=
- s->xvid_build=
- s->lavc_build= -1;
-
- 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]);
@@ -2227,10 +2297,27 @@ static av_cold int decode_init(AVCodecContext *avctx)
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;
}
+}
+
+static av_cold int decode_init(AVCodecContext *avctx)
+{
+ MpegEncContext *s = avctx->priv_data;
+ int ret;
+
+ s->divx_version=
+ s->divx_build=
+ s->xvid_build=
+ s->lavc_build= -1;
+
+ if((ret=ff_h263_decode_init(avctx)) < 0)
+ return ret;
+
+ 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;
s->time_increment_bits = 4; /* default value for broken headers */
avctx->chroma_sample_location = AVCHROMA_LOC_LEFT;
@@ -2257,6 +2344,27 @@ 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,
+};
+
+static const AVClass mpeg4_vdpau_class = {
+ "MPEG4 Video VDPAU Decoder",
+ av_default_item_name,
+ mpeg4_options,
+ LIBAVUTIL_VERSION_INT,
};
AVCodec ff_mpeg4_decoder = {
@@ -2272,7 +2380,28 @@ 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(ff_mpeg_update_thread_context),
+ .priv_class = &mpeg4_class,
+};
+
+
+#if CONFIG_MPEG4_VDPAU_DECODER
+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(MpegEncContext),
+ .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 e145bac..db05b4b 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
*/
@@ -200,7 +200,7 @@ static inline int decide_ac_pred(MpegEncContext * s, int16_t block[6][64], const
}
/**
- * 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){
int i;
@@ -495,9 +495,9 @@ void ff_mpeg4_encode_mb(MpegEncContext * s,
}
}
- 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 & ...
@@ -517,7 +517,7 @@ void ff_mpeg4_encode_mb(MpegEncContext * s,
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 */
@@ -554,12 +554,12 @@ void ff_mpeg4_encode_mb(MpegEncContext * s,
}
if(mb_type == 0){
- 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, s->mv[0][0][0] - s->last_mv[0][0][0],
@@ -628,8 +628,6 @@ void ff_mpeg4_encode_mb(MpegEncContext * s,
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;
@@ -646,7 +644,21 @@ void ff_mpeg4_encode_mb(MpegEncContext * s,
b_pic = pic->f.data[0] + offset;
if (!pic->shared)
b_pic+= INPLACE_OFFSET;
- diff= s->dsp.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->dsp.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;
@@ -708,7 +720,7 @@ void ff_mpeg4_encode_mb(MpegEncContext * s,
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);
@@ -729,7 +741,7 @@ void ff_mpeg4_encode_mb(MpegEncContext * s,
ff_h263_encode_motion_vector(s, s->mv[0][1][0] - pred_x,
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]);
@@ -847,7 +859,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);
}
}
@@ -862,11 +874,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);
@@ -876,8 +889,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);
}
@@ -959,6 +970,8 @@ static void mpeg4_encode_vol_header(MpegEncContext * s, int vo_number, int vol_n
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);
}
@@ -1050,11 +1063,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);
@@ -1141,8 +1153,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) continue;
@@ -1225,6 +1237,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/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..b880b7a 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
*/
@@ -52,6 +52,8 @@
#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))
diff --git a/libavcodec/mpegaudio_parser.c b/libavcodec/mpegaudio_parser.c
index 58ea452..4081936 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;
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..f9557c9 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
*/
@@ -39,6 +39,7 @@ 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)
{
@@ -48,7 +49,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 +61,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.c b/libavcodec/mpegaudiodec.c
index 0c702b0..fc900d8 100644
--- a/libavcodec/mpegaudiodec.c
+++ b/libavcodec/mpegaudiodec.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"
@@ -209,6 +210,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 */
@@ -268,7 +271,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;
@@ -332,7 +338,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++) {
@@ -343,7 +349,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;
@@ -396,7 +402,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);
@@ -833,7 +839,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;
@@ -962,7 +968,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;
}
@@ -989,10 +995,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;
}
@@ -1172,6 +1178,17 @@ found2:
}
#if CONFIG_FLOAT
+#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 /* CONFIG_FLOAT */
+
+#ifndef compute_antialias
+#if CONFIG_FLOAT
#define AA(j) do { \
float tmp0 = ptr[-1-j]; \
float tmp1 = ptr[ j]; \
@@ -1217,6 +1234,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)
@@ -1386,9 +1404,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);
@@ -1397,7 +1414,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++) {
@@ -1579,9 +1596,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);
@@ -1596,7 +1610,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) {
@@ -1604,19 +1618,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);
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;
}
@@ -1652,10 +1667,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;
@@ -1676,6 +1700,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;
}
@@ -1722,6 +1747,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;
@@ -1909,10 +1935,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
@@ -1926,7 +1950,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");
diff --git a/libavcodec/mpegaudiodec_float.c b/libavcodec/mpegaudiodec_float.c
index b5c8223..61b332e 100644
--- a/libavcodec/mpegaudiodec_float.c
+++ b/libavcodec/mpegaudiodec_float.c
@@ -2,20 +2,20 @@
* 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
*/
diff --git a/libavcodec/mpegaudiodecheader.c b/libavcodec/mpegaudiodecheader.c
index 69dda45..1772c2a 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
*/
diff --git a/libavcodec/mpegaudiodecheader.h b/libavcodec/mpegaudiodecheader.h
index 764e8ab..c434d00 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
*/
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 342ed16..ddb7428 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
*/
@@ -44,4 +44,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 d6aa3f5..38c75c7 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,
@@ -57,6 +58,8 @@ void ff_mpa_synth_filter_float(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..8b69cc2 100644
--- a/libavcodec/mpegaudiodsp_fixed.c
+++ b/libavcodec/mpegaudiodsp_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/mpegaudiodsp_float.c b/libavcodec/mpegaudiodsp_float.c
index 2d8d53e..777cac8 100644
--- a/libavcodec/mpegaudiodsp_float.c
+++ b/libavcodec/mpegaudiodsp_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/mpegaudiodsp_template.c b/libavcodec/mpegaudiodsp_template.c
index 621bbd4..f79e068 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
*/
@@ -243,7 +243,7 @@ av_cold void RENAME(ff_init_mpadsp_tabs)(void)
else if (i < 18) d = 1;
}
//merge last stage of imdct into the window coefficients
- d *= 0.5 / cos(M_PI * (2 * i + 19) / 72);
+ d *= 0.5 * IMDCT_SCALAR / cos(M_PI * (2 * i + 19) / 72);
if (j == 2)
RENAME(ff_mdct_win)[j][i/3] = FIXHR((d / (1<<5)));
@@ -398,3 +398,4 @@ void RENAME(ff_imdct36_blocks)(INTFLOAT *out, INTFLOAT *buf, INTFLOAT *in,
out++;
}
}
+
diff --git a/libavcodec/mpegaudioenc.c b/libavcodec/mpegaudioenc.c
index 739eb64..63c8460 100644
--- a/libavcodec/mpegaudioenc.c
+++ b/libavcodec/mpegaudioenc.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
*/
@@ -148,16 +148,16 @@ 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;
scale_factor_table[i] = v;
#ifdef USE_FLOATS
- scale_factor_inv_table[i] = pow(2.0, -(3 - i) / 3.0) / (float)(1 << 20);
+ scale_factor_inv_table[i] = exp2(-(3 - i) / 3.0) / (float)(1 << 20);
#else
#define P 15
scale_factor_shift[i] = 21 - P - (i / 3);
- scale_factor_mult[i] = (1 << P) * pow(2.0, (i % 3) / 3.0);
+ scale_factor_mult[i] = (1 << P) * exp2((i % 3) / 3.0);
#endif
}
for(i=0;i<128;i++) {
@@ -401,7 +401,7 @@ static void compute_scale_factors(unsigned char scale_code[SBLIMIT],
av_dlog(NULL, "%2d:%d in=%x %x %d\n",
j, i, vmax, scale_factor_table[index], index);
/* store the scale factor */
- assert(index >=0 && index <= 63);
+ av_assert2(index >=0 && index <= 63);
sf[i] = index;
}
@@ -463,7 +463,7 @@ static void compute_scale_factors(unsigned char scale_code[SBLIMIT],
sf[1] = sf[2] = sf[0];
break;
default:
- assert(0); //cannot happen
+ av_assert2(0); //cannot happen
code = 0; /* kill warning */
}
@@ -583,7 +583,7 @@ static void compute_bit_allocation(MpegAudioContext *s,
}
}
*padding = max_frame_size - current_frame_size;
- assert(*padding >= 0);
+ av_assert0(*padding >= 0);
}
/*
@@ -698,7 +698,7 @@ static void encode_frame(MpegAudioContext *s,
#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) {
@@ -748,10 +748,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);
diff --git a/libavcodec/mpegaudiotab.h b/libavcodec/mpegaudiotab.h
index 45afe9b..35129e6 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/mpegvideo.c b/libavcodec/mpegvideo.c
index 718f946..32d6fa7 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
*/
@@ -32,6 +32,7 @@
#include "libavutil/imgutils.h"
#include "avcodec.h"
#include "dsputil.h"
+#include "h264chroma.h"
#include "internal.h"
#include "mathops.h"
#include "mpegvideo.h"
@@ -145,7 +146,8 @@ 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);
}
@@ -153,6 +155,7 @@ static void mpeg_er_decode_mb(void *opaque, int ref, int mv_dir, int mv_type,
av_cold int ff_dct_common_init(MpegEncContext *s)
{
ff_dsputil_init(&s->dsp, s->avctx);
+ ff_h264chroma_init(&s->h264chroma, 8); //for lowres
ff_hpeldsp_init(&s->hdsp, s->avctx->flags);
ff_videodsp_init(&s->vdsp, s->avctx->bits_per_raw_sample);
@@ -194,17 +197,17 @@ av_cold int ff_dct_common_init(MpegEncContext *s)
int ff_mpv_frame_size_alloc(MpegEncContext *s, int linesize)
{
- int alloc_size = FFALIGN(FFABS(linesize) + 32, 32);
+ int alloc_size = FFALIGN(FFABS(linesize) + 64, 32);
// 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,
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->edge_emu_buffer, alloc_size * 4 * 24,
fail);
- FF_ALLOCZ_OR_GOTO(s->avctx, s->me.scratchpad, alloc_size * 2 * 16 * 3,
+ FF_ALLOCZ_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;
@@ -285,6 +288,9 @@ static void 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);
@@ -334,6 +340,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;
}
@@ -370,11 +379,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)
+ free_picture_tables(pic);
+
if (shared) {
- assert(pic->f.data[0]);
+ av_assert0(pic->f.data[0]);
pic->shared = 1;
} else {
- assert(!pic->f.data[0]);
+ av_assert0(!pic->f.data[0]);
if (alloc_frame_buffer(s, pic) < 0)
return -1;
@@ -479,6 +493,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;
}
@@ -641,9 +658,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) {
@@ -653,16 +672,23 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst,
s->bitstream_buffer = NULL;
s->bitstream_buffer_size = s->allocated_bitstream_buffer_size = 0;
- ff_MPV_common_init(s);
+ if (s1->context_initialized){
+// s->picture_range_start += MAX_PICTURE_COUNT;
+// s->picture_range_end += MAX_PICTURE_COUNT;
+ if((ret = ff_MPV_common_init(s)) < 0){
+ memset(s, 0, sizeof(MpegEncContext));
+ s->avctx = dst;
+ return ret;
+ }
+ }
}
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;
@@ -674,6 +700,8 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst,
s->picture_number = s1->picture_number;
s->input_picture_number = s1->input_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.data[0] &&
@@ -703,6 +731,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->time_increment_bits, &s1->time_increment_bits,
@@ -740,7 +769,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
@@ -866,44 +894,32 @@ 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
+ 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);
@@ -926,15 +942,11 @@ 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) {
@@ -943,17 +955,14 @@ static int init_context_frame(MpegEncContext *s)
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;
@@ -1020,43 +1029,35 @@ 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);
+ avcodec_get_chroma_sub_sample(s->avctx->pix_fmt,
+ &s->chroma_x_shift,
+ &s->chroma_y_shift);
/* convert fourcc to upper case */
- s->codec_tag = avpriv_toupper4(s->avctx->codec_tag);
+ s->codec_tag = avpriv_toupper4(s->avctx->codec_tag);
+ s->stream_codec_tag = avpriv_toupper4(s->avctx->stream_codec_tag);
- s->stream_codec_tag = avpriv_toupper4(s->avctx->stream_codec_tag);
+ s->avctx->coded_frame = &s->current_picture.f;
- if (s->width && s->height) {
- s->avctx->coded_frame = &s->current_picture.f;
+ if (s->encoding) {
+ if (s->msmpeg4_version) {
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->ac_stats,
+ 2 * 2 * (MAX_LEVEL + 1) *
+ (MAX_RUN + 1) * 2 * sizeof(int), fail);
+ }
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->avctx->stats_out, 256, fail);
- if (s->encoding) {
- if (s->msmpeg4_version) {
- FF_ALLOCZ_OR_GOTO(s->avctx, s->ac_stats,
- 2 * 2 * (MAX_LEVEL + 1) *
- (MAX_RUN + 1) * 2 * sizeof(int), fail);
- }
- 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_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_inter_matrix16,
- 64 * 32 * 2 * sizeof(uint16_t), fail);
- FF_ALLOCZ_OR_GOTO(s->avctx, s->input_picture,
- MAX_PICTURE_COUNT * sizeof(Picture *), fail);
- FF_ALLOCZ_OR_GOTO(s->avctx, s->reordered_input_picture,
- MAX_PICTURE_COUNT * sizeof(Picture *), fail);
-
- if (s->avctx->noise_reduction) {
- FF_ALLOCZ_OR_GOTO(s->avctx, s->dct_offset,
- 2 * 64 * sizeof(uint16_t), 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)
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->reordered_input_picture, MAX_PICTURE_COUNT * sizeof(Picture *), fail)
+
+ if (s->avctx->noise_reduction) {
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->dct_offset, 2 * 64 * sizeof(uint16_t), fail);
}
}
@@ -1072,17 +1073,15 @@ av_cold int ff_MPV_common_init(MpegEncContext *s)
avcodec_get_frame_defaults(&s->last_picture.f);
avcodec_get_frame_defaults(&s->current_picture.f);
- 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));
@@ -1104,7 +1103,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:
@@ -1159,6 +1158,7 @@ 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);
@@ -1225,7 +1225,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;
@@ -1263,6 +1264,10 @@ void ff_MPV_common_end(MpegEncContext *s)
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);
@@ -1403,6 +1408,8 @@ void ff_release_unused_pictures(MpegEncContext*s, int remove_current)
static inline int pic_is_unused(MpegEncContext *s, Picture *pic)
{
+ if (pic == s->last_picture_ptr)
+ return 0;
if (pic->f.data[0] == NULL)
return 1;
if (pic->needs_realloc && !(pic->reference & DELAYED_PIC_REF))
@@ -1416,7 +1423,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.data[0] == NULL)
+ if (s->picture[i].f.data[0] == NULL && &s->picture[i] != s->last_picture_ptr)
return i;
}
} else {
@@ -1426,7 +1433,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)
@@ -1475,6 +1496,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 &&
@@ -1569,11 +1595,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.data[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 */
@@ -1583,12 +1612,13 @@ int ff_MPV_frame_start(MpegEncContext *s, AVCodecContext *avctx)
return i;
}
s->last_picture_ptr = &s->picture[i];
+ s->last_picture_ptr->f.key_frame = 0;
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,
+ memset(s->last_picture_ptr->f.data[0], 0x80,
avctx->height * s->last_picture_ptr->f.linesize[0]);
memset(s->last_picture_ptr->f.data[1], 0x80,
(avctx->height >> v_chroma_shift) *
@@ -1597,6 +1627,11 @@ int ff_MPV_frame_start(MpegEncContext *s, AVCodecContext *avctx)
(avctx->height >> v_chroma_shift) *
s->last_picture_ptr->f.linesize[2]);
+ 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);
}
@@ -1610,6 +1645,7 @@ int ff_MPV_frame_start(MpegEncContext *s, AVCodecContext *avctx)
return i;
}
s->next_picture_ptr = &s->picture[i];
+ s->next_picture_ptr->f.key_frame = 0;
if (ff_alloc_picture(s, s->next_picture_ptr, 0) < 0) {
s->next_picture_ptr = NULL;
return -1;
@@ -1618,6 +1654,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.data[0] &&
@@ -1633,12 +1673,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.data[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.data[0]));
if (s->picture_structure!= PICT_FRAME) {
int i;
@@ -1670,7 +1706,7 @@ int ff_MPV_frame_start(MpegEncContext *s, AVCodecContext *avctx)
}
if (s->dct_error_sum) {
- assert(s->avctx->noise_reduction && s->encoding);
+ av_assert2(s->avctx->noise_reduction && s->encoding);
update_noise_reduction(s);
}
@@ -1684,32 +1720,34 @@ int ff_MPV_frame_start(MpegEncContext *s, AVCodecContext *avctx)
* frame has been coded/decoded. */
void ff_MPV_frame_end(MpegEncContext *s)
{
- int i;
/* 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 if ((s->er.error_count || s->encoding) &&
+ } else if ((s->er.error_count || s->encoding || !(s->avctx->codec->capabilities&CODEC_CAP_DRAW_HORIZ_BAND)) &&
!s->avctx->hwaccel &&
+ !(s->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU) &&
s->unrestricted_mv &&
s->current_picture.reference &&
!s->intra_only &&
- !(s->flags & CODEC_FLAG_EMU_EDGE)) {
- 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->dsp.draw_edges(s->current_picture.f.data[0], s->linesize,
- s->h_edge_pos, s->v_edge_pos,
- EDGE_WIDTH, EDGE_WIDTH,
- EDGE_TOP | EDGE_BOTTOM);
- s->dsp.draw_edges(s->current_picture.f.data[1], s->uvlinesize,
- s->h_edge_pos >> hshift, s->v_edge_pos >> vshift,
- EDGE_WIDTH >> hshift, EDGE_WIDTH >> vshift,
- EDGE_TOP | EDGE_BOTTOM);
- s->dsp.draw_edges(s->current_picture.f.data[2], s->uvlinesize,
- s->h_edge_pos >> hshift, s->v_edge_pos >> vshift,
- EDGE_WIDTH >> hshift, EDGE_WIDTH >> vshift,
- EDGE_TOP | EDGE_BOTTOM);
+ !(s->flags & CODEC_FLAG_EMU_EDGE) &&
+ !s->avctx->lowres
+ ) {
+ 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->dsp.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->dsp.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->dsp.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, EDGE_WIDTH >> vshift,
+ EDGE_TOP | EDGE_BOTTOM);
}
emms_c();
@@ -1727,16 +1765,9 @@ void ff_MPV_frame_end(MpegEncContext *s)
break;
}
}
- assert(i < MAX_PICTURE_COUNT);
+ av_assert0(i < MAX_PICTURE_COUNT);
#endif
- 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]);
- }
- }
// clear copies, to avoid confusion
#if 0
memset(&s->last_picture, 0, sizeof(Picture));
@@ -1750,103 +1781,777 @@ void ff_MPV_frame_end(MpegEncContext *s)
}
/**
+ * 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;
+
+ 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 dx,dy;
+
+ 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);
+
+ 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);
+}
+
+/**
* Print debugging info for the given picture.
*/
-void ff_print_debug_info(MpegEncContext *s, Picture *p)
+void ff_print_debug_info2(AVCodecContext *avctx, Picture *p, AVFrame *pict, uint8_t *mbskip_table,
+ 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->hwaccel || !p || !p->mb_type
+ || (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",
+ p->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 = p->mb_type[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)) {
+ const int shift = 1 + quarter_sample;
+ int mb_y;
+ uint8_t *ptr;
+ int i;
+ int h_chroma_shift, v_chroma_shift, block_height;
+ const int width = avctx->width;
+ const int height = avctx->height;
+ 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;
+ ptr = pict->data[0];
+ 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 ((avctx->debug_mv) && p->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(p->mb_type[mb_index], direction))
+ continue;
+
+ if (IS_8X8(p->mb_type[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 = (p->motion_val[direction][xy][0] >> shift) + sx;
+ int my = (p->motion_val[direction][xy][1] >> shift) + sy;
+ draw_arrow(ptr, sx, sy, mx, my, width,
+ height, pict->linesize[0], 100);
+ }
+ } else if (IS_16X8(p->mb_type[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 = (p->motion_val[direction][xy][0] >> shift);
+ int my = (p->motion_val[direction][xy][1] >> shift);
+
+ if (IS_INTERLACED(p->mb_type[mb_index]))
+ my *= 2;
+
+ draw_arrow(ptr, sx, sy, mx + sx, my + sy, width,
+ height, pict->linesize[0], 100);
+ }
+ } else if (IS_8X16(p->mb_type[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 = p->motion_val[direction][xy][0] >> shift;
+ int my = p->motion_val[direction][xy][1] >> shift;
+
+ if (IS_INTERLACED(p->mb_type[mb_index]))
+ my *= 2;
+
+ draw_arrow(ptr, sx, sy, mx + sx, my + sy, width,
+ height, pict->linesize[0], 100);
+ }
+ } 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= (p->motion_val[direction][xy][0]>>shift) + sx;
+ int my= (p->motion_val[direction][xy][1]>>shift) + sy;
+ draw_arrow(ptr, sx, sy, mx, my, width, height, pict->linesize[0], 100);
+ }
+ }
+ }
+ if ((avctx->debug & FF_DEBUG_VIS_QP)) {
+ uint64_t c = (p->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) &&
+ p->motion_val[0]) {
+ int mb_type = p->mb_type[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 *) &p->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, p, pict, s->mbskip_table, &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, s->linesize,
+ src, 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;
}
- av_log(s->avctx, AV_LOG_DEBUG, "\n");
}
}
+
+ 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, linesize >> field_based, ptr_y,
+ 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 *uvbuf = s->edge_emu_buffer + 18 * s->linesize;
+ s->vdsp.emulated_edge_mc(uvbuf, uvlinesize >> field_based,
+ ptr_cb, 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(uvbuf + 16, uvlinesize >> field_based,
+ ptr_cr, uvlinesize >> field_based, 9,
+ 9 + field_based,
+ uvsrc_x, uvsrc_y << field_based,
+ h_edge_pos >> 1, v_edge_pos >> 1);
+ ptr_cb = uvbuf;
+ ptr_cr = uvbuf + 16;
+ }
+ }
+
+ // 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, s->uvlinesize, ptr, 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, s->uvlinesize,
+ ptr, 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;
+ }
+ }
+ }
+ break;
+ default:
+ av_assert2(0);
+ }
}
/**
@@ -1959,7 +2664,7 @@ 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(CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration){
@@ -2002,8 +2707,8 @@ void MPV_decode_mb_internal(MpegEncContext *s, int16_t block[12][64],
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 */
@@ -2012,7 +2717,7 @@ void MPV_decode_mb_internal(MpegEncContext *s, int16_t block[12][64],
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;
@@ -2052,19 +2757,31 @@ void MPV_decode_mb_internal(MpegEncContext *s, int16_t block[12][64],
}
}
- 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);
+ }
}
}
@@ -2110,17 +2827,17 @@ void MPV_decode_mb_internal(MpegEncContext *s, int16_t block[12][64],
}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
@@ -2162,17 +2879,17 @@ void MPV_decode_mb_internal(MpegEncContext *s, int16_t block[12][64],
}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->dsp.idct_put(dest_cb, dct_linesize, block[4]);
s->dsp.idct_put(dest_cr, dct_linesize, block[5]);
s->dsp.idct_put(dest_cb + dct_offset, dct_linesize, block[6]);
s->dsp.idct_put(dest_cr + dct_offset, dct_linesize, block[7]);
if(!s->chroma_x_shift){//Chroma444
- s->dsp.idct_put(dest_cb + 8, dct_linesize, block[8]);
- s->dsp.idct_put(dest_cr + 8, dct_linesize, block[9]);
- s->dsp.idct_put(dest_cb + 8 + dct_offset, dct_linesize, block[10]);
- s->dsp.idct_put(dest_cr + 8 + dct_offset, dct_linesize, block[11]);
+ s->dsp.idct_put(dest_cb + block_size, dct_linesize, block[8]);
+ s->dsp.idct_put(dest_cr + block_size, dct_linesize, block[9]);
+ s->dsp.idct_put(dest_cb + block_size + dct_offset, dct_linesize, block[10]);
+ s->dsp.idct_put(dest_cr + block_size + dct_offset, dct_linesize, block[11]);
}
}
}//gray
@@ -2190,10 +2907,12 @@ skip_idct:
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);
}
/**
@@ -2214,6 +2933,7 @@ void ff_draw_horiz_band(AVCodecContext *avctx, DSPContext *dsp, Picture *cur,
}
if (!avctx->hwaccel &&
+ !(avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU) &&
draw_edges &&
cur->reference &&
!(avctx->flags & CODEC_FLAG_EMU_EDGE)) {
@@ -2276,8 +2996,8 @@ void ff_draw_horiz_band(AVCodecContext *avctx, DSPContext *dsp, Picture *cur,
void ff_mpeg_draw_horiz_band(MpegEncContext *s, int y, int h)
{
int draw_edges = s->unrestricted_mv && !s->intra_only;
- ff_draw_horiz_band(s->avctx, &s->dsp, &s->current_picture,
- &s->last_picture, y, h, s->picture_structure,
+ ff_draw_horiz_band(s->avctx, &s->dsp, s->current_picture_ptr,
+ s->last_picture_ptr, y, h, s->picture_structure,
s->first_field, draw_edges, s->low_delay,
s->v_edge_pos, s->h_edge_pos);
}
@@ -2285,7 +3005,7 @@ void ff_mpeg_draw_horiz_band(MpegEncContext *s, int y, int h)
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;
@@ -2309,7 +3029,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));
}
}
}
@@ -2359,6 +3079,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;
@@ -2378,10 +3099,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++) {
@@ -2440,10 +3158,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];
@@ -2471,10 +3186,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];
@@ -2531,15 +3244,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;
@@ -2568,7 +3278,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;
diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h
index 9f222c5..2152af2 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
*/
@@ -32,6 +32,7 @@
#include "dsputil.h"
#include "error_resilience.h"
#include "get_bits.h"
+#include "h264chroma.h"
#include "hpeldsp.h"
#include "put_bits.h"
#include "ratecontrol.h"
@@ -42,6 +43,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
@@ -55,14 +57,13 @@ enum OutputFormat {
#define MPEG_BUF_SIZE (16 * 1024)
#define QMAT_SHIFT_MMX 16
-#define QMAT_SHIFT 22
+#define QMAT_SHIFT 21
#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 ME_MAP_SIZE 64
#define ME_MAP_SHIFT 3
@@ -118,6 +119,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
@@ -159,19 +163,24 @@ typedef struct Picture{
int pic_id; /**< h264 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]; ///< h264 POCs of the frames used as reference (FIXME need per slice)
+ int ref_poc[2][2][32]; ///< h264 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; ///< h264 1 -> MBAFF frame 0-> not MBAFF
int field_picture; ///< whether or not the picture was encoded in separate fields
+ int sync; ///< has been decoded after a keyframe
int mb_var_sum; ///< sum of MB variance for current frame
int 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;
+
+ int crop;
+ int crop_left;
+ int crop_top;
} Picture;
/**
@@ -349,7 +358,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) */
@@ -368,11 +377,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
@@ -381,6 +393,7 @@ typedef struct MpegEncContext {
int h263_long_vectors; ///< use horrible h263v1 long vector mode
DSPContext dsp; ///< pointers for accelerated dsp functions
+ H264ChromaContext h264chroma;
HpelDSPContext hdsp;
VideoDSPContext vdsp;
int f_code; ///< forward MV resolution
@@ -477,13 +490,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 */
@@ -496,6 +511,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
@@ -529,6 +545,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
@@ -613,6 +630,7 @@ typedef struct MpegEncContext {
struct MJpegContext *mjpeg_ctx;
int mjpeg_vsample[3]; ///< vertical sampling factors, default = {2, 1, 1}
int mjpeg_hsample[3]; ///< horizontal sampling factors, default = {2, 1, 1}
+ int esc_pos;
/* MSMPEG4 specific */
int mv_table_index;
@@ -677,12 +695,15 @@ 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
int16_t (*pblocks[12])[64];
int16_t (*block)[64]; ///< points to one of the following blocks
- int16_t (*blocks)[8][64]; // for HQ mode we need to keep the best block
+ int16_t (*blocks)[12][64]; // for HQ mode we need to keep the best block
int (*decode_mb)(struct MpegEncContext *s, int16_t block[6][64]); // used by some codecs to avoid a switch()
#define SLICE_OK 0
#define SLICE_ERROR -1
@@ -779,8 +800,8 @@ void ff_MPV_frame_end(MpegEncContext *s);
int ff_MPV_encode_init(AVCodecContext *avctx);
int ff_MPV_encode_end(AVCodecContext *avctx);
int ff_MPV_encode_picture(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *frame, int *got_packet);
-void ff_MPV_encode_init_x86(MpegEncContext *s);
+ AVFrame *frame, int *got_packet);
+void ff_dct_encode_init_x86(MpegEncContext *s);
void ff_MPV_common_init_x86(MpegEncContext *s);
void ff_MPV_common_init_axp(MpegEncContext *s);
void ff_MPV_common_init_arm(MpegEncContext *s);
@@ -793,7 +814,14 @@ void ff_draw_horiz_band(AVCodecContext *avctx, DSPContext *dsp, Picture *cur,
int v_edge_pos, int h_edge_pos);
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, Picture *p, AVFrame *pict, uint8_t *mbskip_table,
+ 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);
void ff_release_unused_pictures(MpegEncContext *s, int remove_current);
int ff_find_unused_picture(MpegEncContext *s, int shared);
@@ -807,6 +835,7 @@ void ff_set_qscale(MpegEncContext * s, int qscale);
void ff_mpeg_er_frame_start(MpegEncContext *s);
int ff_dct_common_init(MpegEncContext *s);
+int ff_dct_encode_init(MpegEncContext *s);
void ff_convert_matrix(DSPContext *dsp, 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);
@@ -835,7 +864,7 @@ extern const enum AVPixelFormat ff_pixfmt_list_420[];
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;
@@ -928,4 +957,5 @@ void ff_wmv2_encode_mb(MpegEncContext * s,
int ff_mpeg_ref_picture(MpegEncContext *s, Picture *dst, Picture *src);
void ff_mpeg_unref_picture(MpegEncContext *s, Picture *picture);
+
#endif /* AVCODEC_MPEGVIDEO_H */
diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c
index c245996..3f12e71 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
*/
@@ -50,6 +50,7 @@
#include "internal.h"
#include "bytestream.h"
#include <limits.h>
+#include "sp5x.h"
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);
@@ -99,8 +100,7 @@ void ff_convert_matrix(DSPContext *dsp, int (*qmat)[64],
* 3444240 >= (1 << 36) / (x) >= 275 */
qmat[qscale][i] = (int)((UINT64_C(1) << (QMAT_SHIFT + 14)) /
- (ff_aanscales[i] * qscale *
- quant_matrix[j]));
+ (ff_aanscales[i] * (int64_t)qscale * quant_matrix[j]));
}
} else {
for (i = 0; i < 64; i++) {
@@ -217,6 +217,21 @@ static void MPV_encode_defaults(MpegEncContext *s)
s->fcode_tab = default_fcode_tab;
}
+av_cold int ff_dct_encode_init(MpegEncContext *s) {
+ if (ARCH_X86)
+ ff_dct_encode_init_x86(s);
+
+ 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)
{
@@ -239,7 +254,9 @@ av_cold int ff_MPV_encode_init(AVCodecContext *avctx)
if (avctx->pix_fmt != AV_PIX_FMT_YUVJ420P &&
avctx->pix_fmt != AV_PIX_FMT_YUVJ422P &&
avctx->pix_fmt != AV_PIX_FMT_YUVJ444P &&
+ avctx->pix_fmt != AV_PIX_FMT_BGR0 &&
avctx->pix_fmt != AV_PIX_FMT_BGRA &&
+ avctx->pix_fmt != AV_PIX_FMT_BGR24 &&
((avctx->pix_fmt != AV_PIX_FMT_YUV420P &&
avctx->pix_fmt != AV_PIX_FMT_YUV422P &&
avctx->pix_fmt != AV_PIX_FMT_YUV444P) ||
@@ -249,10 +266,13 @@ av_cold int ff_MPV_encode_init(AVCodecContext *avctx)
}
break;
case AV_CODEC_ID_MJPEG:
+ case AV_CODEC_ID_AMV:
if (avctx->pix_fmt != AV_PIX_FMT_YUVJ420P &&
avctx->pix_fmt != AV_PIX_FMT_YUVJ422P &&
+ avctx->pix_fmt != AV_PIX_FMT_YUVJ444P &&
((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) ||
avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL)) {
av_log(avctx, AV_LOG_ERROR, "colorspace not supported in jpeg\n");
return -1;
@@ -266,6 +286,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;
@@ -282,8 +306,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;
@@ -323,10 +348,35 @@ 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");
- return -1;
+ 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");
+ if (avctx->rc_max_rate && !avctx->rc_buffer_size)
+ return -1;
}
if (avctx->rc_min_rate && avctx->rc_max_rate != avctx->rc_min_rate) {
@@ -340,7 +390,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;
}
@@ -402,18 +452,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");
@@ -421,7 +527,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;
@@ -471,6 +578,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");
@@ -479,14 +587,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;
@@ -513,8 +624,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;
@@ -524,13 +634,19 @@ 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_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &chroma_h_shift,
- &chroma_v_shift);
+ av_log(avctx, AV_LOG_DEBUG, "intra_quant_bias = %d inter_quant_bias = %d\n",s->intra_quant_bias,s->inter_quant_bias);
+
+ avcodec_get_chroma_sub_sample(avctx->pix_fmt, &chroma_h_shift, &chroma_v_shift);
if (avctx->codec_id == AV_CODEC_ID_MPEG4 &&
s->avctx->time_base.den > (1 << 16) - 1) {
@@ -557,13 +673,19 @@ av_cold int ff_MPV_encode_init(AVCodecContext *avctx)
break;
case AV_CODEC_ID_LJPEG:
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 (avctx->codec->id == AV_CODEC_ID_LJPEG &&
- avctx->pix_fmt == AV_PIX_FMT_BGRA) {
+ (avctx->pix_fmt == AV_PIX_FMT_BGR0
+ || s->avctx->pix_fmt == AV_PIX_FMT_BGRA
+ || s->avctx->pix_fmt == AV_PIX_FMT_BGR24)) {
s->mjpeg_vsample[0] = s->mjpeg_hsample[0] =
s->mjpeg_vsample[1] = s->mjpeg_hsample[1] =
s->mjpeg_vsample[2] = s->mjpeg_hsample[2] = 1;
+ } else if (avctx->pix_fmt == AV_PIX_FMT_YUV444P || avctx->pix_fmt == AV_PIX_FMT_YUVJ444P) {
+ s->mjpeg_vsample[0] = s->mjpeg_vsample[1] = s->mjpeg_vsample[2] = 2;
+ s->mjpeg_hsample[0] = s->mjpeg_hsample[1] = s->mjpeg_hsample[2] = 1;
} else {
s->mjpeg_vsample[0] = 2;
s->mjpeg_vsample[1] = 2 >> chroma_v_shift;
@@ -594,13 +716,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,16 +826,7 @@ 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);
-
- 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;
@@ -840,18 +953,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 {
@@ -868,7 +980,7 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg)
}
if (pic_arg) {
- if (!pic_arg->buf[0]);
+ if (!pic_arg->buf[0])
direct = 0;
if (pic_arg->linesize[0] != s->linesize)
direct = 0;
@@ -925,18 +1037,31 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg)
uint8_t *src = pic_arg->data[i];
uint8_t *dst = pic->f.data[i];
+ if (s->codec_id == AV_CODEC_ID_AMV && !(s->avctx->flags & CODEC_FLAG_EMU_EDGE)) {
+ h = ((s->height + 15)/16*16) >> v_shift;
+ }
+
if (!s->avctx->rc_buffer_size)
dst += INPLACE_OFFSET;
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 & 15)) {
+ s->dsp.draw_edges(dst, dst_stride,
+ w, h,
+ 16>>h_shift,
+ 16>>v_shift,
+ EDGE_BOTTOM);
+ }
}
}
}
@@ -1019,7 +1144,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;
@@ -1312,7 +1437,7 @@ no_output_pic:
}
int ff_MPV_encode_picture(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *pic_arg, int *got_packet)
+ AVFrame *pic_arg, int *got_packet)
{
MpegEncContext *s = avctx->priv_data;
int i, stuffing_count, ret;
@@ -1329,8 +1454,7 @@ 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)
+ if ((ret = ff_alloc_packet2(avctx, pkt, s->mb_width*s->mb_height*(MAX_MB_BYTES+100)+10000)) < 0)
return ret;
if (s->mb_info) {
s->mb_info_ptr = av_packet_new_side_data(pkt,
@@ -1351,7 +1475,8 @@ int ff_MPV_encode_picture(AVCodecContext *avctx, AVPacket *pkt,
s->pict_type = s->new_picture.f.pict_type;
//emms_c();
- ff_MPV_frame_start(s, avctx);
+ if (ff_MPV_frame_start(s, avctx) < 0)
+ return -1;
vbv_retry:
if (encode_picture(s, s->picture_number) < 0)
return -1;
@@ -1425,6 +1550,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) {
@@ -1479,7 +1605,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;
@@ -1492,12 +1618,12 @@ vbv_retry:
avctx->frame_bits = s->frame_bits;
pkt->pts = s->current_picture.f.pts;
- if (!s->low_delay) {
+ if (!s->low_delay && s->pict_type != AV_PICTURE_TYPE_B) {
if (!s->current_picture.f.coded_picture_number)
pkt->dts = pkt->pts - s->dts_delta;
else
pkt->dts = s->reordered_pts;
- s->reordered_pts = s->input_picture[0]->f.pts;
+ s->reordered_pts = pkt->pts;
} else
pkt->dts = pkt->pts;
if (s->current_picture.f.key_frame)
@@ -1507,6 +1633,13 @@ vbv_retry:
} else {
s->frame_bits = 0;
}
+
+ /* release non-reference frames */
+ for (i = 0; i < MAX_PICTURE_COUNT; i++) {
+ if (!s->picture[i].reference)
+ ff_mpeg_unref_picture(s, &s->picture[i]);
+ }
+
assert((s->frame_bits & 7) == 0);
pkt->size = s->frame_bits / 8;
@@ -1631,15 +1764,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;
@@ -1681,23 +1816,25 @@ 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) {
+ 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 + 32;
- s->vdsp.emulated_edge_mc(ebuf, ptr_y, wrap_y, 16, 16, mb_x * 16,
+ 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, wrap_y, ptr_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, wrap_c, 8,
- mb_block_height, mb_x * 8, mb_y * 8,
- s->width >> 1, s->height >> 1);
+ s->vdsp.emulated_edge_mc(ebuf + 18 * wrap_y, wrap_c, ptr_cb, wrap_c, mb_block_width,
+ mb_block_height, mb_x * mb_block_width, mb_y * mb_block_height,
+ cw, ch);
ptr_cb = ebuf + 18 * wrap_y;
- s->vdsp.emulated_edge_mc(ebuf + 18 * wrap_y + 8, ptr_cr, 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;
+ s->vdsp.emulated_edge_mc(ebuf + 18 * wrap_y + 16, wrap_c, ptr_cr, wrap_c, mb_block_width,
+ mb_block_height, mb_x * mb_block_width, mb_y * mb_block_height,
+ cw, ch);
+ ptr_cr = ebuf + 18 * wrap_y + 16;
}
if (s->mb_intra) {
@@ -1719,8 +1856,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;
}
}
@@ -1737,11 +1876,16 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s,
} else {
s->dsp.get_pixels(s->block[4], ptr_cb, wrap_c);
s->dsp.get_pixels(s->block[5], ptr_cr, wrap_c);
- if (!s->chroma_y_shift) { /* 422 */
- s->dsp.get_pixels(s->block[6],
- ptr_cb + (dct_offset >> 1), wrap_c);
- s->dsp.get_pixels(s->block[7],
- ptr_cr + (dct_offset >> 1), wrap_c);
+ if (!s->chroma_y_shift && s->chroma_x_shift) { /* 422 */
+ s->dsp.get_pixels(s->block[6], ptr_cb + uv_dct_offset, wrap_c);
+ s->dsp.get_pixels(s->block[7], ptr_cr + uv_dct_offset, wrap_c);
+ } else if (!s->chroma_y_shift && !s->chroma_x_shift) { /* 444 */
+ s->dsp.get_pixels(s->block[6], ptr_cb + 8, wrap_c);
+ s->dsp.get_pixels(s->block[7], ptr_cr + 8, wrap_c);
+ s->dsp.get_pixels(s->block[8], ptr_cb + uv_dct_offset, wrap_c);
+ s->dsp.get_pixels(s->block[9], ptr_cr + uv_dct_offset, wrap_c);
+ s->dsp.get_pixels(s->block[10], ptr_cb + uv_dct_offset + 8, wrap_c);
+ s->dsp.get_pixels(s->block[11], ptr_cr + uv_dct_offset + 8, wrap_c);
}
}
} else {
@@ -1800,6 +1944,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;
@@ -1821,10 +1966,10 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s,
s->dsp.diff_pixels(s->block[4], ptr_cb, dest_cb, wrap_c);
s->dsp.diff_pixels(s->block[5], ptr_cr, dest_cr, wrap_c);
if (!s->chroma_y_shift) { /* 422 */
- s->dsp.diff_pixels(s->block[6], ptr_cb + (dct_offset >> 1),
- dest_cb + (dct_offset >> 1), wrap_c);
- s->dsp.diff_pixels(s->block[7], ptr_cr + (dct_offset >> 1),
- dest_cr + (dct_offset >> 1), wrap_c);
+ s->dsp.diff_pixels(s->block[6], ptr_cb + uv_dct_offset,
+ dest_cb + uv_dct_offset, wrap_c);
+ s->dsp.diff_pixels(s->block[7], ptr_cr + uv_dct_offset,
+ dest_cr + uv_dct_offset, wrap_c);
}
}
/* pre quantization */
@@ -1851,12 +1996,12 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s,
wrap_c, 8) < 20 * s->qscale)
skip_dct[5] = 1;
if (!s->chroma_y_shift) { /* 422 */
- if (s->dsp.sad[1](NULL, ptr_cb + (dct_offset >> 1),
- dest_cb + (dct_offset >> 1),
+ if (s->dsp.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->dsp.sad[1](NULL, ptr_cr + (dct_offset >> 1),
- dest_cr + (dct_offset >> 1),
+ if (s->dsp.sad[1](NULL, ptr_cr + uv_dct_offset,
+ dest_cr + uv_dct_offset,
wrap_c, 8) < 20 * s->qscale)
skip_dct[7] = 1;
}
@@ -1878,17 +2023,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]) {
@@ -1934,6 +2079,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
@@ -1984,18 +2135,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){
@@ -2132,7 +2285,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;
}
@@ -2238,7 +2391,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);
@@ -2327,6 +2480,11 @@ static int encode_thread(AVCodecContext *c, void *arg){
s->current_picture.f.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));
@@ -2370,7 +2528,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;
}
}
@@ -2406,18 +2564,20 @@ 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){
if(s->start_mb_y != mb_y || mb_x!=0){
write_slice_end(s);
-
if(CONFIG_MPEG4_ENCODER && s->codec_id==AV_CODEC_ID_MPEG4 && s->partitioned_frame){
ff_mpeg4_init_partitions(s);
}
}
- 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->avctx->error_rate && s->resync_mb_x + s->resync_mb_y > 0){
@@ -2624,8 +2784,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;
@@ -2643,7 +2804,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);
@@ -2653,7 +2814,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);
@@ -3053,6 +3214,13 @@ static int encode_picture(MpegEncContext *s, int picture_number)
update_qscale(s);
}
+ if(s->codec_id != AV_CODEC_ID_AMV){
+ 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);
@@ -3095,6 +3263,8 @@ 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;
+ if(s->msmpeg4_version >= 3)
+ s->no_rounding=1;
av_dlog(s, "Scene change detected, encoding as I Frame %d %d\n",
s->current_picture.mb_var_sum, s->current_picture.mc_mb_var_sum);
}
@@ -3173,6 +3343,25 @@ static int encode_picture(MpegEncContext *s, int picture_number)
s->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->dsp.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->dsp, s->q_intra_matrix, s->q_intra_matrix16,
+ s->intra_matrix, s->intra_quant_bias, 8, 8, 1);
+ ff_convert_matrix(&s->dsp, s->q_chroma_intra_matrix, s->q_chroma_intra_matrix16,
+ s->chroma_intra_matrix, s->intra_quant_bias, 8, 8, 1);
+ s->qscale= 8;
+ }
//FIXME var duplication
s->current_picture_ptr->f.key_frame =
@@ -3183,6 +3372,7 @@ 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:
@@ -3214,7 +3404,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;
@@ -3305,7 +3495,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;
@@ -3351,7 +3541,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;
@@ -3385,7 +3575,7 @@ 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){
unquant_coeff= alevel*qmul + qadd;
@@ -3534,7 +3724,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;
@@ -3650,8 +3840,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);
@@ -3717,7 +3907,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;
@@ -3760,7 +3950,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){
@@ -3788,7 +3978,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] ];
@@ -3821,7 +4011,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;
@@ -3850,7 +4040,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->dsp.try_8x8basis(rem, weight, basis[j], unquant_change);
if(score<best_score){
@@ -3881,7 +4071,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
@@ -3909,7 +4099,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;
@@ -3972,7 +4162,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 df7ddf7..862ca25 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 "dsputil.h"
@@ -59,17 +60,15 @@ static void gmc1_motion(MpegEncContext *s,
ptr = ref_picture[0] + src_y * linesize + src_x;
- if (s->flags & CODEC_FLAG_EMU_EDGE) {
if ((unsigned)src_x >= FFMAX(s->h_edge_pos - 17, 0) ||
(unsigned)src_y >= FFMAX(s->v_edge_pos - 17, 0)) {
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr,
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, linesize, ptr,
linesize,
17, 17,
src_x, src_y,
s->h_edge_pos, s->v_edge_pos);
ptr = s->edge_emu_buffer;
}
- }
if ((motion_x | motion_y) & 7) {
s->dsp.gmc1(dest_y, ptr, linesize, 16,
@@ -105,25 +104,23 @@ static void gmc1_motion(MpegEncContext *s,
offset = (src_y * uvlinesize) + src_x;
ptr = ref_picture[1] + offset;
- if (s->flags & CODEC_FLAG_EMU_EDGE) {
if ((unsigned)src_x >= FFMAX((s->h_edge_pos >> 1) - 9, 0) ||
(unsigned)src_y >= FFMAX((s->v_edge_pos >> 1) - 9, 0)) {
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr,
- uvlinesize,
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, uvlinesize,
+ ptr, uvlinesize,
9, 9,
src_x, src_y,
s->h_edge_pos >> 1, s->v_edge_pos >> 1);
ptr = s->edge_emu_buffer;
emu = 1;
}
- }
s->dsp.gmc1(dest_cb, ptr, uvlinesize, 8,
motion_x & 15, motion_y & 15, 128 - s->no_rounding);
ptr = ref_picture[2] + offset;
if (emu) {
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr,
- uvlinesize,
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, uvlinesize,
+ ptr, uvlinesize,
9, 9,
src_x, src_y,
s->h_edge_pos >> 1, s->v_edge_pos >> 1);
@@ -215,11 +212,11 @@ static inline int hpel_motion(MpegEncContext *s,
if (s->unrestricted_mv && (s->flags & CODEC_FLAG_EMU_EDGE)) {
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->vdsp.emulated_edge_mc(s->edge_emu_buffer, s->linesize, src,
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;
}
@@ -311,7 +308,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) {
@@ -320,7 +317,7 @@ void mpeg_motion_internal(MpegEncContext *s,
src_y);
return;
}
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr_y,
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, s->linesize, ptr_y,
s->linesize,
17, 17 + field_based,
src_x, src_y << field_based,
@@ -328,12 +325,12 @@ void mpeg_motion_internal(MpegEncContext *s,
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,
+ s->vdsp.emulated_edge_mc(uvbuf, s->uvlinesize, ptr_cb,
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(uvbuf + 16, s->uvlinesize, ptr_cr,
s->uvlinesize,
9, 9 + field_based,
uvsrc_x, uvsrc_y << field_based,
@@ -397,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);
@@ -472,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]) {
@@ -540,21 +537,24 @@ 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)) {
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr_y,
+ (unsigned)src_y > FFMAX( v_edge_pos - (motion_y & 3) - h, 0)) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
s->linesize,
+ ptr_y, s->linesize,
17, 17 + field_based,
src_x, src_y << field_based,
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,
+ s->vdsp.emulated_edge_mc(uvbuf, s->uvlinesize,
+ ptr_cb,
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(uvbuf + 16, s->uvlinesize,
+ ptr_cr,
s->uvlinesize,
9, 9 + field_based,
uvsrc_x, uvsrc_y << field_based,
@@ -625,7 +625,7 @@ static void chroma_4mv_motion(MpegEncContext *s,
if (s->flags & CODEC_FLAG_EMU_EDGE) {
if ((unsigned)src_x > FFMAX((s->h_edge_pos >> 1) - (dxy & 1) - 8, 0) ||
(unsigned)src_y > FFMAX((s->v_edge_pos >> 1) - (dxy >> 1) - 8, 0)) {
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, s->uvlinesize,
ptr, s->uvlinesize,
9, 9, src_x, src_y,
s->h_edge_pos >> 1, s->v_edge_pos >> 1);
@@ -637,7 +637,7 @@ static void chroma_4mv_motion(MpegEncContext *s,
ptr = ref_picture[2] + offset;
if (emu) {
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, s->uvlinesize,
ptr, s->uvlinesize,
9, 9, src_x, src_y,
s->h_edge_pos >> 1, s->v_edge_pos >> 1);
@@ -676,7 +676,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]);
@@ -785,7 +785,8 @@ static inline void apply_8x8(MpegEncContext *s,
if (s->flags & CODEC_FLAG_EMU_EDGE) {
if ((unsigned)src_x > FFMAX(s->h_edge_pos - (motion_x & 3) - 8, 0) ||
(unsigned)src_y > FFMAX(s->v_edge_pos - (motion_y & 3) - 8, 0)) {
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr,
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
+ s->linesize, ptr,
s->linesize,
9, 9,
src_x, src_y,
@@ -905,8 +906,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;
}
@@ -920,8 +921,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;
@@ -950,6 +951,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,
@@ -968,7 +972,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 3219c10..f127218 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:
@@ -68,7 +72,7 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s,
frame_rate_index = buf[3] & 0xf;
pc->frame_rate.den = avctx->time_base.den = ff_mpeg12_frame_rate_tab[frame_rate_index].num;
pc->frame_rate.num = avctx->time_base.num = ff_mpeg12_frame_rate_tab[frame_rate_index].den;
- 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;
}
break;
@@ -88,7 +92,7 @@ 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)
avcodec_set_dimensions(avctx, pc->width, pc->height);
avctx->time_base.den = pc->frame_rate.den * (frame_rate_ext_n + 1) * 2;
@@ -139,6 +143,12 @@ 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;
+ } else if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && bit_rate &&
+ (bit_rate != 0x3FFFF || vbv_delay != 0xFFFF)) {
+ avctx->bit_rate = 400*bit_rate;
+ }
}
static int mpegvideo_parse(AVCodecParserContext *s,
@@ -179,18 +189,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 e95c91f..6b0c6ac 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
*/
diff --git a/libavcodec/mpl2dec.c b/libavcodec/mpl2dec.c
new file mode 100644
index 0000000..a777c7c
--- a/dev/null
+++ b/libavcodec/mpl2dec.c
@@ -0,0 +1,96 @@
+/*
+ * 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++;
+ }
+ }
+
+ av_bprintf(buf, "\r\n");
+ return 0;
+}
+
+static int mpl2_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_sub_ptr, AVPacket *avpkt)
+{
+ 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)) {
+ if (!av_bprint_is_complete(&buf)) {
+ av_bprint_finalize(&buf, NULL);
+ return AVERROR(ENOMEM);
+ }
+ ff_ass_add_rect(sub, buf.str, ts_start, ts_duration, 0);
+ }
+ *got_sub_ptr = sub->num_rects > 0;
+ av_bprint_finalize(&buf, NULL);
+ 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 60d87ba..f8294cd 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
--- a/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 52b0f5d..90e83ae 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 76c87f1..3bfd1fd 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 f844850..f2110e7 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])
@@ -278,17 +276,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..a723888 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
*/
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 9a12633..7c260fe 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 "dsputil.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->dsp.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){
@@ -646,7 +653,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 +838,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 +917,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 = ff_pixfmt_list_420,
};
@@ -923,6 +931,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 = ff_pixfmt_list_420,
};
@@ -936,6 +945,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 = ff_pixfmt_list_420,
};
@@ -949,5 +959,6 @@ 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 = ff_pixfmt_list_420,
};
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 a57040f..2b4ab1a 100644
--- a/libavcodec/msrle.c
+++ b/libavcodec/msrle.c
@@ -2,20 +2,20 @@
* Microsoft RLE video decoder
* 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
*/
@@ -50,10 +50,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;
@@ -68,6 +72,10 @@ static av_cold int msrle_decode_init(AVCodecContext *avctx)
avcodec_get_frame_defaults(&s->frame);
+ 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;
}
@@ -84,26 +92,23 @@ 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 = (avctx->width * avctx->bits_per_coded_sample + 7) / 8;
uint8_t *ptr = s->frame.data[0];
uint8_t *buf = avpkt->data + (avctx->height-1)*istride;
int i, j;
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 b5e016b..46ea2b5 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
*/
@@ -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;
@@ -151,10 +151,8 @@ static int mss1_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
init_get_bits(&gb, buf, buf_size * 8);
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];
@@ -193,7 +191,8 @@ static av_cold int mss1_decode_init(AVCodecContext *avctx)
int ret;
c->ctx.avctx = avctx;
- avctx->coded_frame = &c->pic;
+
+ avcodec_get_frame_defaults(&c->pic);
ret = ff_mss12_decode_init(&c->ctx, 0, &c->sc, NULL);
diff --git a/libavcodec/mss12.c b/libavcodec/mss12.c
index 3601978..b522e4a 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
*/
@@ -448,7 +448,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;
@@ -586,6 +586,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 %d.%d\n",
AV_RB32(avctx->extradata + 4), AV_RB32(avctx->extradata + 8));
@@ -645,7 +650,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..a3f9a7c 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
*/
diff --git a/libavcodec/mss2.c b/libavcodec/mss2.c
index d9c04be..fcb50e3 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
*/
@@ -34,7 +34,7 @@
typedef struct MSS2Context {
VC1Context v;
int split_position;
- AVFrame last_pic;
+ AVFrame *last_pic;
MSS12Context c;
MSS2DSPContext dsp;
SliceContext sc[2];
@@ -523,8 +523,8 @@ static int mss2_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
avctx->pix_fmt = is_555 ? AV_PIX_FMT_RGB555 : AV_PIX_FMT_RGB24;
- if (ctx->last_pic.format != avctx->pix_fmt)
- av_frame_unref(&ctx->last_pic);
+ if (ctx->last_pic->format != avctx->pix_fmt)
+ av_frame_unref(ctx->last_pic);
if (has_wmv9) {
bytestream2_init(&gB, buf, buf_size + ARITH2_PADDING);
@@ -598,25 +598,21 @@ 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]);
- c->last_rgb_pic = ctx->last_pic.data[0] +
- ctx->last_pic.linesize[0] * (avctx->height - 1);
+ if (ctx->last_pic->data[0]) {
+ av_assert0(frame->linesize[0] == ctx->last_pic->linesize[0]);
+ c->last_rgb_pic = ctx->last_pic->data[0] +
+ ctx->last_pic->linesize[0] * (avctx->height - 1);
} else {
av_log(avctx, AV_LOG_ERROR, "Missing keyframe\n");
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)
+ if ((ret = av_frame_ref(frame, ctx->last_pic)) < 0)
return ret;
c->last_rgb_pic = NULL;
@@ -730,8 +726,8 @@ static int mss2_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
av_log(avctx, AV_LOG_WARNING, "buffer not fully consumed\n");
if (c->mvX < 0 || c->mvY < 0) {
- av_frame_unref(&ctx->last_pic);
- ret = av_frame_ref(&ctx->last_pic, frame);
+ av_frame_unref(ctx->last_pic);
+ ret = av_frame_ref(ctx->last_pic, frame);
if (ret < 0)
return ret;
}
@@ -806,7 +802,7 @@ static av_cold int mss2_decode_end(AVCodecContext *avctx)
{
MSS2Context *const ctx = avctx->priv_data;
- av_frame_unref(&ctx->last_pic);
+ av_frame_free(&ctx->last_pic);
ff_mss12_decode_end(&ctx->c);
av_freep(&ctx->c.pal_pic);
@@ -824,10 +820,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);
}
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 020a43a..a3aec80 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
*/
@@ -108,7 +108,7 @@ typedef struct HaarBlockCoder {
typedef struct MSS3Context {
AVCodecContext *avctx;
- AVFrame pic;
+ AVFrame *pic;
int got_error;
RangeCoder coder;
@@ -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,14 +731,12 @@ 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;
+ c->pic->key_frame = keyframe;
+ c->pic->pict_type = keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
if (!bytestream2_get_bytes_left(&gb)) {
- if ((ret = av_frame_ref(data, &c->pic)) < 0)
+ if ((ret = av_frame_ref(data, c->pic)) < 0)
return ret;
*got_frame = 1;
@@ -751,9 +749,9 @@ static int mss3_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
mb_width = dec_width >> 4;
mb_height = dec_height >> 4;
- dst[0] = c->pic.data[0] + dec_x + dec_y * c->pic.linesize[0];
- dst[1] = c->pic.data[1] + dec_x / 2 + (dec_y / 2) * c->pic.linesize[1];
- dst[2] = c->pic.data[2] + dec_x / 2 + (dec_y / 2) * c->pic.linesize[2];
+ dst[0] = c->pic->data[0] + dec_x + dec_y * c->pic->linesize[0];
+ dst[1] = c->pic->data[1] + dec_x / 2 + (dec_y / 2) * c->pic->linesize[1];
+ dst[2] = c->pic->data[2] + dec_x / 2 + (dec_y / 2) * c->pic->linesize[2];
for (y = 0; y < mb_height; y++) {
for (x = 0; x < mb_width; x++) {
for (i = 0; i < 3; i++) {
@@ -764,23 +762,23 @@ static int mss3_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
case FILL_BLOCK:
decode_fill_block(acoder, c->fill_coder + i,
dst[i] + x * blk_size,
- c->pic.linesize[i], blk_size);
+ c->pic->linesize[i], blk_size);
break;
case IMAGE_BLOCK:
decode_image_block(acoder, c->image_coder + i,
dst[i] + x * blk_size,
- c->pic.linesize[i], blk_size);
+ c->pic->linesize[i], blk_size);
break;
case DCT_BLOCK:
decode_dct_block(acoder, c->dct_coder + i,
dst[i] + x * blk_size,
- c->pic.linesize[i], blk_size,
+ c->pic->linesize[i], blk_size,
c->dctblock, x, y);
break;
case HAAR_BLOCK:
decode_haar_block(acoder, c->haar_coder + i,
dst[i] + x * blk_size,
- c->pic.linesize[i], blk_size,
+ c->pic->linesize[i], blk_size,
c->hblock);
break;
}
@@ -792,12 +790,12 @@ static int mss3_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
}
}
}
- dst[0] += c->pic.linesize[0] * 16;
- dst[1] += c->pic.linesize[1] * 8;
- dst[2] += c->pic.linesize[2] * 8;
+ dst[0] += c->pic->linesize[0] * 16;
+ dst[1] += c->pic->linesize[1] * 8;
+ dst[2] += c->pic->linesize[2] * 8;
}
- if ((ret = av_frame_ref(data, &c->pic)) < 0)
+ if ((ret = av_frame_ref(data, c->pic)) < 0)
return ret;
*got_frame = 1;
@@ -811,6 +809,9 @@ static av_cold int mss3_decode_init(AVCodecContext *avctx)
int i;
c->avctx = avctx;
+ c->pic = av_frame_alloc();
+ if (!c->pic)
+ return AVERROR(ENOMEM);
if ((avctx->width & 0xF) || (avctx->height & 0xF)) {
av_log(avctx, AV_LOG_ERROR,
@@ -828,6 +829,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--;
@@ -848,7 +850,7 @@ static av_cold int mss3_decode_end(AVCodecContext *avctx)
MSS3Context * const c = avctx->priv_data;
int i;
- av_frame_unref(&c->pic);
+ av_frame_free(&c->pic);
for (i = 0; i < 3; i++)
av_freep(&c->dct_coder[i].prev_dc);
diff --git a/libavcodec/mss34dsp.c b/libavcodec/mss34dsp.c
index 11abb2d..e4d4299 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
*/
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 81de942..fd1f316 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
*/
@@ -126,7 +126,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];
@@ -297,10 +297,10 @@ static int mss4_decode_dct_block(MSS4Context *c, GetBitContext *gb,
return ret;
c->prev_dc[0][mb_x * 2 + i] = c->dc_cache[j][LEFT];
- ff_mss34_dct_put(out + xpos * 8, c->pic.linesize[0],
+ ff_mss34_dct_put(out + xpos * 8, c->pic->linesize[0],
c->block);
}
- out += 8 * c->pic.linesize[0];
+ out += 8 * c->pic->linesize[0];
}
for (i = 1; i < 3; i++) {
@@ -320,7 +320,7 @@ static int mss4_decode_dct_block(MSS4Context *c, GetBitContext *gb,
for (j = 0; j < 16; j++) {
for (k = 0; k < 8; k++)
AV_WN16A(out + k * 2, c->imgbuf[i][k + (j & ~1) * 4] * 0x101);
- out += c->pic.linesize[i];
+ out += c->pic->linesize[i];
}
}
@@ -481,7 +481,7 @@ static int mss4_decode_image_block(MSS4Context *ctx, GetBitContext *gb,
for (i = 0; i < 3; i++)
for (j = 0; j < 16; j++)
- memcpy(picdst[i] + mb_x * 16 + j * ctx->pic.linesize[i],
+ memcpy(picdst[i] + mb_x * 16 + j * ctx->pic->linesize[i],
ctx->imgbuf[i] + j * 16, 16);
return 0;
@@ -554,16 +554,14 @@ 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
+ c->pic->key_frame = (frame_type == INTRA_FRAME);
+ c->pic->pict_type = (frame_type == INTRA_FRAME) ? AV_PICTURE_TYPE_I
: AV_PICTURE_TYPE_P;
if (frame_type == SKIP_FRAME) {
*got_frame = 1;
- if ((ret = av_frame_ref(data, &c->pic)) < 0)
+ if ((ret = av_frame_ref(data, c->pic)) < 0)
return ret;
return buf_size;
@@ -575,13 +573,13 @@ 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;
- dst[0] = c->pic.data[0];
- dst[1] = c->pic.data[1];
- dst[2] = c->pic.data[2];
+ dst[0] = c->pic->data[0];
+ dst[1] = c->pic->data[1];
+ dst[2] = c->pic->data[2];
memset(c->prev_vec, 0, sizeof(c->prev_vec));
for (y = 0; y < mb_height; y++) {
@@ -615,12 +613,12 @@ static int mss4_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if (blk_type != DCT_BLOCK)
mss4_update_dc_cache(c, x);
}
- dst[0] += c->pic.linesize[0] * 16;
- dst[1] += c->pic.linesize[1] * 16;
- dst[2] += c->pic.linesize[2] * 16;
+ dst[0] += c->pic->linesize[0] * 16;
+ dst[1] += c->pic->linesize[1] * 16;
+ dst[2] += c->pic->linesize[2] * 16;
}
- if ((ret = av_frame_ref(data, &c->pic)) < 0)
+ if ((ret = av_frame_ref(data, c->pic)) < 0)
return ret;
*got_frame = 1;
@@ -633,6 +631,10 @@ static av_cold int mss4_decode_init(AVCodecContext *avctx)
MSS4Context * const c = avctx->priv_data;
int i;
+ c->pic = av_frame_alloc();
+ if (!c->pic)
+ return AVERROR(ENOMEM);
+
if (mss4_init_vlcs(c)) {
av_log(avctx, AV_LOG_ERROR, "Cannot initialise VLCs\n");
mss4_free_vlcs(c);
@@ -658,7 +660,8 @@ static av_cold int mss4_decode_end(AVCodecContext *avctx)
MSS4Context * const c = avctx->priv_data;
int i;
- av_frame_unref(&c->pic);
+ av_frame_free(&c->pic);
+
for (i = 0; i < 3; i++)
av_freep(&c->prev_dc[i]);
mss4_free_vlcs(c);
diff --git a/libavcodec/msvideo1.c b/libavcodec/msvideo1.c
index b41151c..83c50ac 100644
--- a/libavcodec/msvideo1.c
+++ b/libavcodec/msvideo1.c
@@ -2,20 +2,20 @@
* Microsoft Video-1 Decoder
* 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
*/
@@ -298,10 +298,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..1da302a
--- a/dev/null
+++ b/libavcodec/msvideo1enc.c
@@ -0,0 +1,311 @@
+/*
+ * 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;
+ AVFrame pic;
+ 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 0x0FFF
+#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;
+ AVFrame * const p = &c->pic;
+ 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;
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width*avctx->height*9 + FF_MIN_BUFFER_SIZE)) < 0)
+ return ret;
+ dst= buf= pkt->data;
+
+ *p = *pict;
+ 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;
+
+ p->quality = 24;
+
+ 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 /= p->quality;
+ }
+ // try to find optimal value to fill whole 4x4 block
+ score = 0;
+ ff_init_elbg(c->block, 3, 16, c->avg, 1, 1, c->output, &c->rnd);
+ ff_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 /= p->quality;
+ score += 2;
+ if(score < bestscore){
+ bestscore = score;
+ bestmode = MODE_FILL;
+ }
+ // search for optimal filling of 2-color block
+ score = 0;
+ ff_init_elbg(c->block, 3, 16, c->codebook, 2, 1, c->output, &c->rnd);
+ ff_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 /= p->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++){
+ ff_init_elbg(c->block2 + i*4*3, 3, 4, c->codebook2 + i*2*3, 2, 1, c->output2 + i*4, &c->rnd);
+ ff_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 /= p->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++;
+ p->pict_type= keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
+ p->key_frame= keyframe;
+ 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 multiplies of 4\n");
+ return -1;
+ }
+
+ avcodec_get_frame_defaults(&c->pic);
+ avctx->coded_frame = (AVFrame*)&c->pic;
+ 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
new file mode 100644
index 0000000..423c7c4
--- a/dev/null
+++ b/libavcodec/mvcdec.c
@@ -0,0 +1,286 @@
+/*
+ * Silicon Graphics Motion Video Compressor 1 & 2 decoder
+ * Copyright (c) 2012 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
+ * Silicon Graphics Motion Video Compressor 1 & 2 decoder
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avcodec.h"
+#include "bytestream.h"
+#include "internal.h"
+
+typedef struct MvcContext {
+ AVFrame *frame;
+ int vflip;
+} MvcContext;
+
+static av_cold int mvc_decode_init(AVCodecContext *avctx)
+{
+ MvcContext *s = avctx->priv_data;
+ int width = avctx->width;
+ int height = avctx->height;
+
+ if (avctx->codec_id == AV_CODEC_ID_MVC1) {
+ width += 3;
+ height += 3;
+ }
+ width &= ~3;
+ height &= ~3;
+ if (width != avctx->width || height != avctx->height)
+ avcodec_set_dimensions(avctx, width, height);
+
+ avctx->pix_fmt = (avctx->codec_id == AV_CODEC_ID_MVC1) ? AV_PIX_FMT_RGB555 : AV_PIX_FMT_BGRA;
+ s->frame = av_frame_alloc();
+ if (!s->frame)
+ return AVERROR(ENOMEM);
+
+ s->vflip = avctx->extradata_size >= 9 && !memcmp(avctx->extradata + avctx->extradata_size - 9, "BottomUp", 9);
+ return 0;
+}
+
+static int decode_mvc1(AVCodecContext *avctx, GetByteContext *gb, uint8_t *dst_start, int width, int height, int linesize)
+{
+ uint8_t *dst;
+ uint16_t v[8];
+ int mask, x, y, i;
+
+ x = y= 0;
+ while (bytestream2_get_bytes_left(gb) >= 6) {
+ mask = bytestream2_get_be16u(gb);
+ v[0] = bytestream2_get_be16u(gb);
+ v[1] = bytestream2_get_be16u(gb);
+ if ((v[0] & 0x8000)) {
+ if (bytestream2_get_bytes_left(gb) < 12) {
+ av_log(avctx, AV_LOG_WARNING, "buffer overflow\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (i = 2; i < 8; i++)
+ v[i] = bytestream2_get_be16u(gb);
+ } else {
+ v[2] = v[4] = v[6] = v[0];
+ v[3] = v[5] = v[7] = v[1];
+ }
+
+#define PIX16(target, true, false) \
+ i = (mask & target) ? true : false; \
+ AV_WN16A(dst, (v[i] & 0x7C00) | (v[i] & 0x3E0) | (v[i] & 0x1F)); \
+ dst += 2;
+
+#define ROW16(row, a1, a0, b1, b0) \
+ dst = dst_start + (y + row) * linesize + x * 2; \
+ PIX16(1 << (row * 4), a1, a0) \
+ PIX16(1 << (row * 4 + 1), a1, a0) \
+ PIX16(1 << (row * 4 + 2), b1, b0) \
+ PIX16(1 << (row * 4 + 3), b1, b0)
+
+ ROW16(0, 0, 1, 2, 3);
+ ROW16(1, 0, 1, 2, 3);
+ ROW16(2, 4, 5, 6, 7);
+ ROW16(3, 4, 5, 6, 7);
+
+ x += 4;
+ if (x >= width) {
+ y += 4;
+ if (y >= height) {
+ break;
+ }
+ x = 0;
+ }
+ }
+ return 0;
+}
+
+static void set_4x4_block(uint8_t *dst, int linesize, uint32_t pixel)
+{
+ int i, j;
+ for (j = 0; j < 4; j++)
+ for (i = 0; i < 4; i++)
+ AV_WN32A(dst + j * linesize + i * 4, pixel);
+}
+
+#define PIX32(target, true, false) \
+ AV_WN32A(dst, (mask & target) ? v[true] : v[false]); \
+ dst += 4;
+
+#define ROW32(row, a1, a0, b1, b0) \
+ dst = dst_start + (y + row) * linesize + x * 4; \
+ PIX32(1 << (row * 4), a1, a0) \
+ PIX32(1 << (row * 4 + 1), a1, a0) \
+ PIX32(1 << (row * 4 + 2), b1, b0) \
+ PIX32(1 << (row * 4 + 3), b1, b0)
+
+#define MVC2_BLOCK \
+ ROW32(0, 1, 0, 3, 2); \
+ ROW32(1, 1, 0, 3, 2); \
+ ROW32(2, 5, 4, 7, 6); \
+ ROW32(3, 5, 4, 7, 6);
+
+static int decode_mvc2(AVCodecContext *avctx, GetByteContext *gb, uint8_t *dst_start, int width, int height, int linesize, int vflip)
+{
+ uint8_t *dst;
+ uint32_t color[128], v[8];
+ int w, h, nb_colors, i, x, y, p0, p1, mask;
+
+ if (bytestream2_get_bytes_left(gb) < 6)
+ return AVERROR_INVALIDDATA;
+
+ w = bytestream2_get_be16u(gb);
+ h = bytestream2_get_be16u(gb);
+ if ((w & ~3) != width || (h & ~3) != height)
+ av_log(avctx, AV_LOG_WARNING, "dimension mismatch\n");
+
+ if (bytestream2_get_byteu(gb)) {
+ avpriv_request_sample(avctx, "bitmap feature");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ nb_colors = bytestream2_get_byteu(gb);
+ if (bytestream2_get_bytes_left(gb) < nb_colors * 3)
+ return AVERROR_INVALIDDATA;
+ for (i = 0; i < FFMIN(nb_colors, 128); i++)
+ color[i] = 0xFF000000 | bytestream2_get_be24u(gb);
+ if (nb_colors > 128)
+ bytestream2_skip(gb, (nb_colors - 128) * 3);
+
+ if (vflip) {
+ dst_start += (height - 1) * linesize;
+ linesize = -linesize;
+ }
+ x = y = 0;
+ while (bytestream2_get_bytes_left(gb) >= 1) {
+ p0 = bytestream2_get_byteu(gb);
+ if ((p0 & 0x80)) {
+ if ((p0 & 0x40)) {
+ p0 &= 0x3F;
+ p0 = (p0 << 2) | (p0 >> 4);
+ set_4x4_block(dst_start + y * linesize + x * 4, linesize, 0xFF000000 | (p0 << 16) | (p0 << 8) | p0);
+ } else {
+ int g, r;
+ p0 &= 0x3F;
+ p0 = (p0 << 2) | (p0 >> 4);
+ if (bytestream2_get_bytes_left(gb) < 2)
+ return AVERROR_INVALIDDATA;
+ g = bytestream2_get_byteu(gb);
+ r = bytestream2_get_byteu(gb);
+ set_4x4_block(dst_start + y * linesize + x * 4, linesize, 0xFF000000 | (r << 16) | (g << 8) | p0);
+ }
+ } else {
+ if (bytestream2_get_bytes_left(gb) < 1)
+ return AVERROR_INVALIDDATA;
+ p1 = bytestream2_get_byteu(gb);
+ if ((p1 & 0x80)) {
+ if ((p0 & 0x7F) == (p1 & 0x7F)) {
+ set_4x4_block(dst_start + y * linesize + x * 4, linesize, color[p0 & 0x7F]);
+ } else {
+ if (bytestream2_get_bytes_left(gb) < 2)
+ return AVERROR_INVALIDDATA;
+ v[0] = v[2] = v[4] = v[6] = color[p0 & 0x7F];
+ v[1] = v[3] = v[5] = v[7] = color[p1 & 0x7F];
+ mask = bytestream2_get_le16u(gb);
+ MVC2_BLOCK
+ }
+ } else {
+ if (bytestream2_get_bytes_left(gb) < 8)
+ return AVERROR_INVALIDDATA;
+ v[0] = color[p0 & 0x7F];
+ v[1] = color[p1 & 0x7F];
+ for (i = 2; i < 8; i++)
+ v[i] = color[bytestream2_get_byteu(gb) & 0x7F];
+ mask = bytestream2_get_le16u(gb);
+ MVC2_BLOCK
+ }
+ }
+
+ x += 4;
+ if (x >= width) {
+ y += 4;
+ if (y >= height)
+ break;
+ x = 0;
+ }
+ }
+ return 0;
+}
+
+static int mvc_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ MvcContext *s = avctx->priv_data;
+ GetByteContext gb;
+ int ret;
+
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
+ return ret;
+
+ bytestream2_init(&gb, avpkt->data, avpkt->size);
+ if (avctx->codec_id == AV_CODEC_ID_MVC1)
+ ret = decode_mvc1(avctx, &gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0]);
+ else
+ ret = decode_mvc2(avctx, &gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0], s->vflip);
+ if (ret < 0)
+ return ret;
+
+ *got_frame = 1;
+ if ((ret = av_frame_ref(data, s->frame)) < 0)
+ return ret;
+
+ return avpkt->size;
+}
+
+static av_cold int mvc_decode_end(AVCodecContext *avctx)
+{
+ MvcContext *s = avctx->priv_data;
+
+ av_frame_free(&s->frame);
+
+ return 0;
+}
+
+#if CONFIG_MVC1_DECODER
+AVCodec ff_mvc1_decoder = {
+ .name = "mvc1",
+ .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MVC1,
+ .priv_data_size = sizeof(MvcContext),
+ .init = mvc_decode_init,
+ .close = mvc_decode_end,
+ .decode = mvc_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
+#endif
+
+#if CONFIG_MVC2_DECODER
+AVCodec ff_mvc2_decoder = {
+ .name = "mvc2",
+ .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MVC2,
+ .priv_data_size = sizeof(MvcContext),
+ .init = mvc_decode_init,
+ .close = mvc_decode_end,
+ .decode = mvc_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
+#endif
diff --git a/libavcodec/mxpegdec.c b/libavcodec/mxpegdec.c
index 68c06c2..0069ca5 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
*/
@@ -80,6 +80,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) {
@@ -247,11 +248,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;
@@ -267,11 +266,9 @@ 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);
if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
@@ -339,4 +336,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 fc803a2..f9d1389 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:
@@ -60,8 +60,8 @@ typedef struct NellyMoserEncodeContext {
DECLARE_ALIGNED(32, float, mdct_out)[NELLY_SAMPLES];
DECLARE_ALIGNED(32, float, in_buff)[NELLY_SAMPLES];
DECLARE_ALIGNED(32, float, buf)[3 * NELLY_BUF_LEN]; ///< sample buffer
- float (*opt )[NELLY_BANDS];
- uint8_t (*path)[NELLY_BANDS];
+ float (*opt )[OPT_SIZE];
+ uint8_t (*path)[OPT_SIZE];
} NellyMoserEncodeContext;
static float pow_table[POW_TABLE_SIZE]; ///< -pow(2, -i / 2048.0 - 3.0);
@@ -171,7 +171,7 @@ 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);
@@ -226,8 +226,8 @@ static void get_exponent_dynamic(NellyMoserEncodeContext *s, float *cand, int *i
int i, j, band, best_idx;
float power_candidate, best_val;
- float (*opt )[NELLY_BANDS] = s->opt ;
- uint8_t(*path)[NELLY_BANDS] = s->path;
+ float (*opt )[OPT_SIZE] = s->opt ;
+ uint8_t(*path)[OPT_SIZE] = s->path;
for (i = 0; i < NELLY_BANDS * OPT_SIZE; i++) {
opt[0][i] = INFINITY;
@@ -390,10 +390,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/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 0e04254..bfbf802 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"
@@ -120,24 +121,27 @@ 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->dsp, 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->dsp, c->width, c->height,
c->lq, c->cq);
@@ -154,6 +158,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',
@@ -183,7 +188,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;
}
@@ -200,24 +205,31 @@ 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;
}
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]);
@@ -225,22 +237,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);
@@ -258,7 +271,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..d8a8f74
--- a/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
+
+#include "libavutil/common.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
+ CODEC_ID_MPEG2VIDEO_XVMC,
+ 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/options.c b/libavcodec/options.c
index 8d36c01..02fb89f 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
*/
@@ -67,6 +67,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,
@@ -75,17 +82,36 @@ 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,
};
+#if FF_API_ALLOC_CONTEXT
+void avcodec_get_context_defaults2(AVCodecContext *s, enum AVMediaType codec_type){
+ AVCodec c= {0};
+ c.type= codec_type;
+ avcodec_get_context_defaults3(s, &c);
+}
+#endif
+
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->get_buffer2 = avcodec_default_get_buffer2;
@@ -95,6 +121,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){
@@ -135,6 +162,26 @@ AVCodecContext *avcodec_alloc_context3(const AVCodec *codec)
return avctx;
}
+#if FF_API_ALLOC_CONTEXT
+AVCodecContext *avcodec_alloc_context2(enum AVMediaType codec_type){
+ AVCodecContext *avctx= av_malloc(sizeof(AVCodecContext));
+
+ if(avctx==NULL) return NULL;
+
+ avcodec_get_context_defaults2(avctx, codec_type);
+
+ return avctx;
+}
+
+void avcodec_get_context_defaults(AVCodecContext *s){
+ avcodec_get_context_defaults2(s, AVMEDIA_TYPE_UNKNOWN);
+}
+
+AVCodecContext *avcodec_alloc_context(void){
+ return avcodec_alloc_context2(AVMEDIA_TYPE_UNKNOWN);
+}
+#endif
+
int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
{
if (avcodec_is_open(dest)) { // check that the dest context is uninitialized
@@ -143,6 +190,10 @@ int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
src, dest);
return AVERROR(EINVAL);
}
+
+ av_opt_free(dest);
+ av_free(dest->priv_data);
+
memcpy(dest, src, sizeof(*dest));
/* set values specific to opened codecs back to their default state */
@@ -179,6 +230,7 @@ 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, 1);
#undef alloc_and_copy_or_fail
return 0;
@@ -196,3 +248,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 0706f9a..f57704e 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
*/
@@ -26,7 +28,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
@@ -40,12 +41,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"},
@@ -70,8 +72,10 @@ static const AVOption avcodec_options[] = {
{"cgop", "closed GOP", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_CLOSED_GOP }, INT_MIN, INT_MAX, V|E, "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"},
{"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" },
@@ -84,6 +88,7 @@ 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},
@@ -98,9 +103,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, FF_MAX_B_FRAMES, V|E},
+{"bf", "set maximum number of B frames between non-B-frames", OFFSET(max_b_frames), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, -1, FF_MAX_B_FRAMES, 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},
@@ -139,11 +144,14 @@ 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"},
+{"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},
@@ -219,7 +227,7 @@ static const AVOption avcodec_options[] = {
{"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"},
{"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"},
+{"thread_ops", "threading operations", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_THREADS }, INT_MIN, INT_MAX, V|A|D, "debug"},
{"vismv", "visualize motion vectors (MVs)", OFFSET(debug_mv), AV_OPT_TYPE_INT, {.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"},
@@ -243,6 +251,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},
@@ -261,7 +273,7 @@ static const AVOption avcodec_options[] = {
{"context", "context model", OFFSET(context_model), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
{"slice_flags", NULL, OFFSET(slice_flags), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX},
{"xvmc_acceleration", NULL, OFFSET(xvmc_acceleration), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX},
-{"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"},
@@ -273,7 +285,7 @@ static const AVOption avcodec_options[] = {
{"rc_init_occupancy", "number of bits which should be loaded into the rc buffer before decoding starts", OFFSET(rc_initial_buffer_occupancy), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
{"flags2", NULL, OFFSET(flags2), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT}, 0, UINT_MAX, V|A|E|D, "flags2"},
{"error", NULL, OFFSET(error_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
-{"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"},
{"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},
@@ -300,6 +312,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},
@@ -308,18 +321,18 @@ 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"},
+{"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},
@@ -336,7 +349,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", NULL, OFFSET(color_primaries), AV_OPT_TYPE_INT, {.i64 = AVCOL_PRI_UNSPECIFIED }, 1, AVCOL_PRI_NB-1, V|E|D},
@@ -346,7 +359,7 @@ static const AVOption avcodec_options[] = {
{"chroma_sample_location", NULL, OFFSET(chroma_sample_location), AV_OPT_TYPE_INT, {.i64 = AVCHROMA_LOC_UNSPECIFIED }, 0, AVCHROMA_LOC_NB-1, V|E|D},
{"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"},
@@ -359,18 +372,21 @@ 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, AV_SAMPLE_FMT_NB-1, 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 },
+{"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" },
{NULL},
};
diff --git a/libavcodec/paf.c b/libavcodec/paf.c
new file mode 100644
index 0000000..76c90c9
--- a/dev/null
+++ b/libavcodec/paf.c
@@ -0,0 +1,451 @@
+/*
+ * Packed Animation File video and audio 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 "libavutil/intreadwrite.h"
+#include "libavcodec/paf.h"
+#include "bytestream.h"
+#include "avcodec.h"
+#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 }
+};
+
+typedef struct PAFVideoDecContext {
+ AVFrame *pic;
+ GetByteContext gb;
+
+ int current_frame;
+ uint8_t *frame[4];
+ int frame_size;
+ int video_size;
+
+ uint8_t *opcodes;
+} PAFVideoDecContext;
+
+static av_cold int paf_vid_close(AVCodecContext *avctx)
+{
+ PAFVideoDecContext *c = avctx->priv_data;
+ int i;
+
+ av_frame_free(&c->pic);
+
+ for (i = 0; i < 4; i++)
+ av_freep(&c->frame[i]);
+
+ return 0;
+}
+
+static av_cold int paf_vid_init(AVCodecContext *avctx)
+{
+ PAFVideoDecContext *c = avctx->priv_data;
+ int i;
+
+ if (avctx->height & 3 || avctx->width & 3) {
+ av_log(avctx, AV_LOG_ERROR, "width and height must be multiplies of 4\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ avctx->pix_fmt = AV_PIX_FMT_PAL8;
+
+ c->pic = av_frame_alloc();
+ if (!c->pic)
+ return AVERROR(ENOMEM);
+
+ c->frame_size = FFALIGN(avctx->height, 256) * avctx->width;
+ c->video_size = avctx->height * avctx->width;
+ for (i = 0; i < 4; i++) {
+ c->frame[i] = av_mallocz(c->frame_size);
+ if (!c->frame[i]) {
+ paf_vid_close(avctx);
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ return 0;
+}
+
+static int get_video_page_offset(AVCodecContext *avctx, uint8_t a, uint8_t b)
+{
+ int x, y;
+
+ x = b & 0x7F;
+ y = ((a & 0x3F) << 1) | (b >> 7 & 1);
+
+ return y * 2 * avctx->width + x * 2;
+}
+
+static void copy4h(AVCodecContext *avctx, uint8_t *dst)
+{
+ PAFVideoDecContext *c = avctx->priv_data;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ bytestream2_get_buffer(&c->gb, dst, 4);
+ dst += avctx->width;
+ }
+}
+
+static void copy_color_mask(AVCodecContext *avctx, uint8_t mask, uint8_t *dst, uint8_t color)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if ((mask >> 4) & (1 << (3 - i)))
+ dst[i] = color;
+ if ((mask & 15) & (1 << (3 - i)))
+ dst[avctx->width + i] = color;
+ }
+}
+
+static void copy_src_mask(AVCodecContext *avctx, uint8_t mask, uint8_t *dst, const uint8_t *src)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if ((mask >> 4) & (1 << (3 - i)))
+ dst[i] = src[i];
+ if ((mask & 15) & (1 << (3 - i)))
+ dst[avctx->width + i] = src[avctx->width + i];
+ }
+}
+
+static int decode_0(AVCodecContext *avctx, uint8_t code, uint8_t *pkt)
+{
+ PAFVideoDecContext *c = avctx->priv_data;
+ uint32_t opcode_size, offset;
+ uint8_t *dst, *dend, mask = 0, color = 0, a, b, p;
+ const uint8_t *src, *send, *opcodes;
+ int i, j, x = 0;
+
+ i = bytestream2_get_byte(&c->gb);
+ if (i) {
+ if (code & 0x10) {
+ int align;
+
+ align = bytestream2_tell(&c->gb) & 3;
+ if (align)
+ bytestream2_skip(&c->gb, 4 - align);
+ }
+ do {
+ a = bytestream2_get_byte(&c->gb);
+ b = bytestream2_get_byte(&c->gb);
+ p = (a & 0xC0) >> 6;
+ dst = c->frame[p] + get_video_page_offset(avctx, a, b);
+ dend = c->frame[p] + c->frame_size;
+ offset = (b & 0x7F) * 2;
+ j = bytestream2_get_le16(&c->gb) + offset;
+
+ do {
+ offset++;
+ if (dst + 3 * avctx->width + 4 > dend)
+ return AVERROR_INVALIDDATA;
+ copy4h(avctx, dst);
+ if ((offset & 0x3F) == 0)
+ dst += avctx->width * 3;
+ dst += 4;
+ } while (offset < j);
+ } while (--i);
+ }
+
+ dst = c->frame[c->current_frame];
+ dend = c->frame[c->current_frame] + c->frame_size;
+ do {
+ a = bytestream2_get_byte(&c->gb);
+ b = bytestream2_get_byte(&c->gb);
+ p = (a & 0xC0) >> 6;
+ src = c->frame[p] + get_video_page_offset(avctx, a, b);
+ send = c->frame[p] + c->frame_size;
+ if ((src + 3 * avctx->width + 4 > send) ||
+ (dst + 3 * avctx->width + 4 > dend))
+ return AVERROR_INVALIDDATA;
+ copy_block4(dst, src, avctx->width, avctx->width, 4);
+ i++;
+ if ((i & 0x3F) == 0)
+ dst += avctx->width * 3;
+ dst += 4;
+ } while (i < c->video_size / 16);
+
+ opcode_size = bytestream2_get_le16(&c->gb);
+ bytestream2_skip(&c->gb, 2);
+
+ if (bytestream2_get_bytes_left(&c->gb) < opcode_size)
+ return AVERROR_INVALIDDATA;
+
+ opcodes = pkt + bytestream2_tell(&c->gb);
+ bytestream2_skipu(&c->gb, opcode_size);
+
+ dst = c->frame[c->current_frame];
+
+ for (i = 0; i < avctx->height; i += 4, dst += avctx->width * 3) {
+ for (j = 0; j < avctx->width; j += 4, dst += 4) {
+ int opcode, k = 0;
+
+ if (x > opcode_size)
+ return AVERROR_INVALIDDATA;
+ if (j & 4) {
+ opcode = opcodes[x] & 15;
+ x++;
+ } else {
+ opcode = opcodes[x] >> 4;
+ }
+
+ while (block_sequences[opcode][k]) {
+
+ offset = avctx->width * 2;
+ code = block_sequences[opcode][k++];
+
+ switch (code) {
+ case 2:
+ offset = 0;
+ case 3:
+ color = bytestream2_get_byte(&c->gb);
+ case 4:
+ mask = bytestream2_get_byte(&c->gb);
+ copy_color_mask(avctx, mask, dst + offset, color);
+ break;
+ case 5:
+ offset = 0;
+ case 6:
+ a = bytestream2_get_byte(&c->gb);
+ b = bytestream2_get_byte(&c->gb);
+ p = (a & 0xC0) >> 6;
+ src = c->frame[p] + get_video_page_offset(avctx, a, b);
+ send = c->frame[p] + c->frame_size;
+ case 7:
+ if (src + offset + avctx->width + 4 > send)
+ return AVERROR_INVALIDDATA;
+ mask = bytestream2_get_byte(&c->gb);
+ copy_src_mask(avctx, mask, dst + offset, src + offset);
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int paf_vid_decode(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *pkt)
+{
+ PAFVideoDecContext *c = avctx->priv_data;
+ uint8_t code, *dst, *src, *end;
+ int i, frame, ret;
+
+ if ((ret = ff_reget_buffer(avctx, c->pic)) < 0)
+ return ret;
+
+ bytestream2_init(&c->gb, pkt->data, pkt->size);
+
+ code = bytestream2_get_byte(&c->gb);
+ if (code & 0x20) {
+ for (i = 0; i < 4; i++)
+ memset(c->frame[i], 0, c->frame_size);
+
+ memset(c->pic->data[1], 0, AVPALETTE_SIZE);
+ c->current_frame = 0;
+ c->pic->key_frame = 1;
+ c->pic->pict_type = AV_PICTURE_TYPE_I;
+ } else {
+ c->pic->key_frame = 0;
+ c->pic->pict_type = AV_PICTURE_TYPE_P;
+ }
+
+ if (code & 0x40) {
+ uint32_t *out = (uint32_t *)c->pic->data[1];
+ int index, count;
+
+ index = bytestream2_get_byte(&c->gb);
+ count = bytestream2_get_byte(&c->gb) + 1;
+
+ if (index + count > 256)
+ return AVERROR_INVALIDDATA;
+ if (bytestream2_get_bytes_left(&c->gb) < 3*count)
+ return AVERROR_INVALIDDATA;
+
+ out += index;
+ for (i = 0; i < count; i++) {
+ unsigned r, g, b;
+
+ r = bytestream2_get_byteu(&c->gb);
+ r = r << 2 | r >> 4;
+ g = bytestream2_get_byteu(&c->gb);
+ g = g << 2 | g >> 4;
+ b = bytestream2_get_byteu(&c->gb);
+ b = b << 2 | b >> 4;
+ *out++ = 0xFFU << 24 | r << 16 | g << 8 | b;
+ }
+ c->pic->palette_has_changed = 1;
+ }
+
+ switch (code & 0x0F) {
+ case 0:
+ if ((ret = decode_0(avctx, code, pkt->data)) < 0)
+ return ret;
+ break;
+ case 1:
+ dst = c->frame[c->current_frame];
+ bytestream2_skip(&c->gb, 2);
+ if (bytestream2_get_bytes_left(&c->gb) < c->video_size)
+ return AVERROR_INVALIDDATA;
+ bytestream2_get_bufferu(&c->gb, dst, c->video_size);
+ break;
+ case 2:
+ frame = bytestream2_get_byte(&c->gb);
+ if (frame > 3)
+ return AVERROR_INVALIDDATA;
+ if (frame != c->current_frame)
+ memcpy(c->frame[c->current_frame], c->frame[frame], c->frame_size);
+ break;
+ case 4:
+ dst = c->frame[c->current_frame];
+ end = dst + c->video_size;
+
+ bytestream2_skip(&c->gb, 2);
+
+ while (dst < end) {
+ int8_t code;
+ int count;
+
+ if (bytestream2_get_bytes_left(&c->gb) < 2)
+ return AVERROR_INVALIDDATA;
+
+ code = bytestream2_get_byteu(&c->gb);
+ count = FFABS(code) + 1;
+
+ if (dst + count > end)
+ return AVERROR_INVALIDDATA;
+ if (code < 0)
+ memset(dst, bytestream2_get_byteu(&c->gb), count);
+ else
+ bytestream2_get_buffer(&c->gb, dst, count);
+ dst += count;
+ }
+ break;
+ default:
+ avpriv_request_sample(avctx, "unknown/invalid code");
+ return AVERROR_INVALIDDATA;
+ }
+
+ dst = c->pic->data[0];
+ src = c->frame[c->current_frame];
+ for (i = 0; i < avctx->height; i++) {
+ memcpy(dst, src, avctx->width);
+ dst += c->pic->linesize[0];
+ src += avctx->width;
+ }
+
+ c->current_frame = (c->current_frame + 1) & 3;
+ if ((ret = av_frame_ref(data, c->pic)) < 0)
+ return ret;
+
+ *got_frame = 1;
+
+ return pkt->size;
+}
+
+static av_cold int paf_aud_init(AVCodecContext *avctx)
+{
+ if (avctx->channels != 2) {
+ av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ avctx->channel_layout = AV_CH_LAYOUT_STEREO;
+ avctx->sample_fmt = AV_SAMPLE_FMT_S16;
+
+ return 0;
+}
+
+static int paf_aud_decode(AVCodecContext *avctx, void *data,
+ int *got_frame_ptr, AVPacket *pkt)
+{
+ AVFrame *frame = data;
+ uint8_t *buf = pkt->data;
+ int16_t *output_samples;
+ const uint8_t *t;
+ int frames, ret, i, j, k;
+
+ frames = pkt->size / PAF_SOUND_FRAME_SIZE;
+ if (frames < 1)
+ return AVERROR_INVALIDDATA;
+
+ frame->nb_samples = PAF_SOUND_SAMPLES * frames;
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+
+ output_samples = (int16_t *)frame->data[0];
+ for (i = 0; i < frames; i++) {
+ t = buf + 256 * sizeof(uint16_t);
+ for (j = 0; j < PAF_SOUND_SAMPLES; j++) {
+ for (k = 0; k < 2; k++) {
+ *output_samples++ = AV_RL16(buf + *t * 2);
+ t++;
+ }
+ }
+ buf += PAF_SOUND_FRAME_SIZE;
+ }
+
+ *got_frame_ptr = 1;
+
+ return pkt->size;
+}
+
+AVCodec ff_paf_video_decoder = {
+ .name = "paf_video",
+ .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File Video"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_PAF_VIDEO,
+ .priv_data_size = sizeof(PAFVideoDecContext),
+ .init = paf_vid_init,
+ .close = paf_vid_close,
+ .decode = paf_vid_decode,
+ .capabilities = CODEC_CAP_DR1,
+};
+
+AVCodec ff_paf_audio_decoder = {
+ .name = "paf_audio",
+ .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File Audio"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_PAF_AUDIO,
+ .init = paf_aud_init,
+ .decode = paf_aud_decode,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/paf.h b/libavcodec/paf.h
new file mode 100644
index 0000000..ce8245f
--- a/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/pamenc.c b/libavcodec/pamenc.c
index 29c923a..2421464 100644
--- a/libavcodec/pamenc.c
+++ b/libavcodec/pamenc.c
@@ -2,58 +2,41 @@
* 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"
#include "pnm.h"
static int pam_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *pict, int *got_packet)
+ const AVFrame *p, int *got_packet)
{
PNMContext *s = avctx->priv_data;
- AVFrame * const p = &s->picture;
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;
- }
-
- *p = *pict;
- p->pict_type = AV_PICTURE_TYPE_I;
- p->key_frame = 1;
-
- s->bytestream_start =
- s->bytestream = pkt->data;
- s->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";
@@ -64,21 +47,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;
+
+ s->bytestream_start =
+ s->bytestream = pkt->data;
+ s->bytestream_end = pkt->data + pkt->size;
+
snprintf(s->bytestream, s->bytestream_end - s->bytestream,
"P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLTYPE %s\nENDHDR\n",
w, h, depth, maxval, tuple_type);
@@ -87,16 +102,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(&s->bytestream, v);
- *s->bytestream++ = v >> 24;
- }
+ for (j = 0; j < w; j++)
+ *s->bytestream++ = ptr[j >> 3] >> (7 - j & 7) & 1;
ptr += linesize;
}
} else {
@@ -120,10 +130,8 @@ AVCodec ff_pam_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_PAM,
.priv_data_size = sizeof(PNMContext),
- .init = ff_pnm_init,
.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 6e755f6..8a82593 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 <string.h>
#include "parser.h"
+#include "libavutil/atomic.h"
#include "libavutil/mem.h"
static AVCodecParser *av_first_parser = NULL;
@@ -34,13 +35,14 @@ AVCodecParser* av_parser_next(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;
@@ -59,31 +61,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){
@@ -236,8 +237,10 @@ int ff_combine_frame(ParseContext *pc, int next, const uint8_t **buf, int *buf_s
if(next == END_NOT_FOUND){
void* new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, (*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;
@@ -250,9 +253,11 @@ int ff_combine_frame(ParseContext *pc, int next, const uint8_t **buf, int *buf_s
/* append to buffer */
if(pc->index){
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 172e93a..9696b09 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
@@ -85,7 +86,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
@@ -222,6 +225,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->block_size) {
+ av_log(avctx, AV_LOG_WARNING, "block_size has changed\n");
+ s->extra_sample_count = 0;
+ }
+ s->last_block_size = s->block_size;
src += 3;
buf_size -= 3;
@@ -229,10 +237,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 882c167..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 = avcodec_alloc_frame();
- 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,29 +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 av_unused 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) \
- { \
- int av_unused n2; \
- 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)
@@ -300,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;
}
@@ -314,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;
@@ -330,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;
@@ -348,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;
@@ -367,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)
@@ -375,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:
@@ -393,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:
@@ -401,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++;
@@ -458,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 }, \
@@ -498,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");
@@ -524,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 ad92d75..66b1a35 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 / 8 ||
- (!compressed && bytes_per_scanline > buf_size / h)) {
+ if (bytes_per_scanline < (w * bits_per_pixel * nplanes + 7) / 8 ||
+ (!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,30 +130,27 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
}
- buf += 128;
+ bytestream2_skipu(&gb, 60);
if ((ret = av_image_check_size(w, h, 0, avctx)) < 0)
return ret;
if (w != avctx->width || h != avctx->height)
avcodec_set_dimensions(avctx, w, h);
- 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];
@@ -167,39 +161,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);
@@ -209,8 +201,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;
@@ -224,16 +215,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 4c08fba..fa45888 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,24 +28,11 @@
#include "avcodec.h"
#include "bytestream.h"
+#include "libavutil/imgutils.h"
#include "internal.h"
-typedef struct PCXContext {
- AVFrame picture;
-} PCXContext;
-
static const uint32_t monoblack_pal[16] = { 0x000000, 0xFFFFFF };
-static av_cold int pcx_encode_init(AVCodecContext *avctx)
-{
- PCXContext *s = avctx->priv_data;
-
- avcodec_get_frame_defaults(&s->picture);
- avctx->coded_frame = &s->picture;
-
- return 0;
-}
-
/**
* PCX run-length encoder
* @param dst output buffer
@@ -99,16 +86,15 @@ static int pcx_rle_encode( uint8_t *dst, int dst_size,
static int pcx_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *frame, int *got_packet)
{
- PCXContext *s = avctx->priv_data;
- AVFrame *const pict = &s->picture;
+ AVFrame *const pict = (AVFrame *) frame;
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;
- *pict = *frame;
pict->pict_type = AV_PICTURE_TYPE_I;
pict->key_frame = 1;
@@ -127,6 +113,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;
@@ -146,13 +137,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
@@ -161,8 +155,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
@@ -207,8 +201,6 @@ AVCodec ff_pcx_encoder = {
.long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_PCX,
- .priv_data_size = sizeof(PCXContext),
- .init = pcx_encode_init,
.encode2 = pcx_encode_frame,
.pix_fmts = (const enum AVPixelFormat[]){
AV_PIX_FMT_RGB24,
diff --git a/libavcodec/pgssubdec.c b/libavcodec/pgssubdec.c
index 874493c..4de83f3 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
*/
@@ -29,6 +29,7 @@
#include "bytestream.h"
#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))
@@ -40,12 +41,17 @@ enum SegmentType {
DISPLAY_SEGMENT = 0x80,
};
-typedef struct PGSSubPresentation {
+typedef struct PGSSubPictureReference {
int x;
int y;
- int id_number;
- int object_number;
- uint8_t composition_flag;
+ int picture_id;
+ int composition;
+} PGSSubPictureReference;
+
+typedef struct PGSSubPresentation {
+ int id_number;
+ int object_count;
+ PGSSubPictureReference *objects;
int64_t pts;
} PGSSubPresentation;
@@ -58,24 +64,33 @@ typedef struct PGSSubPicture {
} PGSSubPicture;
typedef struct PGSSubContext {
+ AVClass *class;
PGSSubPresentation presentation;
uint32_t clut[256];
- PGSSubPicture picture;
+ PGSSubPicture pictures[UINT16_MAX];
+ int forced_subs_only;
} PGSSubContext;
static av_cold int init_decoder(AVCodecContext *avctx)
{
- avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ avctx->pix_fmt = AV_PIX_FMT_PAL8;
return 0;
}
static av_cold int close_decoder(AVCodecContext *avctx)
{
+ uint16_t picture;
+
PGSSubContext *ctx = avctx->priv_data;
- av_freep(&ctx->picture.rle);
- ctx->picture.rle_buffer_size = 0;
+ av_freep(&ctx->presentation.objects);
+ ctx->presentation.object_count = 0;
+
+ for (picture = 0; picture < UINT16_MAX; ++picture) {
+ av_freep(&ctx->pictures[picture].rle);
+ ctx->pictures[picture].rle_buffer_size = 0;
+ }
return 0;
}
@@ -83,14 +98,14 @@ 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
* @param buf pointer to the RLE data to process
* @param buf_size size of the RLE data to process
*/
-static int decode_rle(AVCodecContext *avctx, AVSubtitle *sub,
+static int decode_rle(AVCodecContext *avctx, AVSubtitle *sub, int rect,
const uint8_t *buf, unsigned int buf_size)
{
const uint8_t *rle_bitmap_end;
@@ -98,15 +113,15 @@ static int decode_rle(AVCodecContext *avctx, AVSubtitle *sub,
rle_bitmap_end = buf + buf_size;
- sub->rects[0]->pict.data[0] = av_malloc(sub->rects[0]->w * sub->rects[0]->h);
+ sub->rects[rect]->pict.data[0] = av_malloc(sub->rects[rect]->w * sub->rects[rect]->h);
- if (!sub->rects[0]->pict.data[0])
+ if (!sub->rects[rect]->pict.data[0])
return -1;
pixel_count = 0;
line_count = 0;
- while (buf < rle_bitmap_end && line_count < sub->rects[0]->h) {
+ while (buf < rle_bitmap_end && line_count < sub->rects[rect]->h) {
uint8_t flags, color;
int run;
@@ -121,27 +136,27 @@ static int decode_rle(AVCodecContext *avctx, AVSubtitle *sub,
color = flags & 0x80 ? bytestream_get_byte(&buf) : 0;
}
- if (run > 0 && pixel_count + run <= sub->rects[0]->w * sub->rects[0]->h) {
- memset(sub->rects[0]->pict.data[0] + pixel_count, color, run);
+ if (run > 0 && pixel_count + run <= sub->rects[rect]->w * sub->rects[rect]->h) {
+ memset(sub->rects[rect]->pict.data[0] + pixel_count, color, run);
pixel_count += run;
} else if (!run) {
/*
* New Line. Check if correct pixels decoded, if not display warning
* and adjust bitmap pointer to correct new line position.
*/
- if (pixel_count % sub->rects[0]->w > 0)
+ if (pixel_count % sub->rects[rect]->w > 0)
av_log(avctx, AV_LOG_ERROR, "Decoded %d pixels, when line should be %d pixels\n",
- pixel_count % sub->rects[0]->w, sub->rects[0]->w);
+ pixel_count % sub->rects[rect]->w, sub->rects[rect]->w);
line_count++;
}
}
- if (pixel_count < sub->rects[0]->w * sub->rects[0]->h) {
+ if (pixel_count < sub->rects[rect]->w * sub->rects[rect]->h) {
av_log(avctx, AV_LOG_ERROR, "Insufficient RLE data for subtitle\n");
return -1;
}
- av_dlog(avctx, "Pixel Count = %d, Area = %d\n", pixel_count, sub->rects[0]->w * sub->rects[0]->h);
+ av_dlog(avctx, "Pixel Count = %d, Area = %d\n", pixel_count, sub->rects[rect]->w * sub->rects[rect]->h);
return 0;
}
@@ -164,25 +179,28 @@ static int parse_picture_segment(AVCodecContext *avctx,
uint8_t sequence_desc;
unsigned int rle_bitmap_len, width, height;
+ uint16_t picture_id;
if (buf_size <= 4)
return -1;
buf_size -= 4;
- /* skip 3 unknown bytes: Object ID (2 bytes), Version Number */
- buf += 3;
+ picture_id = bytestream_get_be16(&buf);
+
+ /* skip 1 unknown byte: Version Number */
+ buf++;
/* Read the Sequence Description to determine if start of RLE data or appended to previous RLE */
sequence_desc = bytestream_get_byte(&buf);
if (!(sequence_desc & 0x80)) {
/* Additional RLE data */
- if (buf_size > ctx->picture.rle_remaining_len)
+ if (buf_size > ctx->pictures[picture_id].rle_remaining_len)
return -1;
- memcpy(ctx->picture.rle + ctx->picture.rle_data_len, buf, buf_size);
- ctx->picture.rle_data_len += buf_size;
- ctx->picture.rle_remaining_len -= buf_size;
+ memcpy(ctx->pictures[picture_id].rle + ctx->pictures[picture_id].rle_data_len, buf, buf_size);
+ ctx->pictures[picture_id].rle_data_len += buf_size;
+ ctx->pictures[picture_id].rle_remaining_len -= buf_size;
return 0;
}
@@ -204,17 +222,22 @@ static int parse_picture_segment(AVCodecContext *avctx,
return -1;
}
- ctx->picture.w = width;
- ctx->picture.h = height;
+ if (buf_size > rle_bitmap_len) {
+ av_log(avctx, AV_LOG_ERROR, "too much RLE data\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->pictures[picture_id].w = width;
+ ctx->pictures[picture_id].h = height;
- av_fast_malloc(&ctx->picture.rle, &ctx->picture.rle_buffer_size, rle_bitmap_len);
+ av_fast_malloc(&ctx->pictures[picture_id].rle, &ctx->pictures[picture_id].rle_buffer_size, rle_bitmap_len);
- if (!ctx->picture.rle)
+ if (!ctx->pictures[picture_id].rle)
return -1;
- memcpy(ctx->picture.rle, buf, buf_size);
- ctx->picture.rle_data_len = buf_size;
- ctx->picture.rle_remaining_len = rle_bitmap_len - buf_size;
+ memcpy(ctx->pictures[picture_id].rle, buf, buf_size);
+ ctx->pictures[picture_id].rle_data_len = buf_size;
+ ctx->pictures[picture_id].rle_remaining_len = rle_bitmap_len - buf_size;
return 0;
}
@@ -270,7 +293,6 @@ static void parse_palette_segment(AVCodecContext *avctx,
* @param buf pointer to the packet to process
* @param buf_size size of packet to process
* @todo TODO: Implement cropping
- * @todo TODO: Implement forcing of subtitles
*/
static void parse_presentation_segment(AVCodecContext *avctx,
const uint8_t *buf, int buf_size,
@@ -278,11 +300,11 @@ static void parse_presentation_segment(AVCodecContext *avctx,
{
PGSSubContext *ctx = avctx->priv_data;
- int x, y;
-
int w = bytestream_get_be16(&buf);
int h = bytestream_get_be16(&buf);
+ uint16_t object_index;
+
ctx->presentation.pts = pts;
av_dlog(avctx, "Video Dimensions %dx%d\n",
@@ -303,35 +325,46 @@ static void parse_presentation_segment(AVCodecContext *avctx,
*/
buf += 3;
- ctx->presentation.object_number = bytestream_get_byte(&buf);
- ctx->presentation.composition_flag = 0;
- if (!ctx->presentation.object_number)
+ ctx->presentation.object_count = bytestream_get_byte(&buf);
+ if (!ctx->presentation.object_count)
return;
- /*
- * Skip 3 bytes of unknown:
- * object_id_ref (2 bytes),
- * window_id_ref,
- */
- buf += 3;
- ctx->presentation.composition_flag = bytestream_get_byte(&buf);
+ /* Verify that enough bytes are remaining for all of the objects. */
+ buf_size -= 11;
+ if (buf_size < ctx->presentation.object_count * 8) {
+ ctx->presentation.object_count = 0;
+ return;
+ }
- x = bytestream_get_be16(&buf);
- y = bytestream_get_be16(&buf);
+ av_freep(&ctx->presentation.objects);
+ ctx->presentation.objects = av_malloc(sizeof(PGSSubPictureReference) * ctx->presentation.object_count);
+ if (!ctx->presentation.objects) {
+ ctx->presentation.object_count = 0;
+ return;
+ }
- /* TODO If cropping, cropping_x, cropping_y, cropping_width, cropping_height (all 2 bytes).*/
+ for (object_index = 0; object_index < ctx->presentation.object_count; ++object_index) {
+ PGSSubPictureReference *reference = &ctx->presentation.objects[object_index];
+ reference->picture_id = bytestream_get_be16(&buf);
- av_dlog(avctx, "Subtitle Placement x=%d, y=%d\n", x, y);
+ /* Skip window_id_ref */
+ buf++;
+ /* composition_flag (0x80 - object cropped, 0x40 - object forced) */
+ reference->composition = bytestream_get_byte(&buf);
- if (x > avctx->width || y > avctx->height) {
- av_log(avctx, AV_LOG_ERROR, "Subtitle out of video bounds. x = %d, y = %d, video width = %d, video height = %d.\n",
- x, y, avctx->width, avctx->height);
- x = 0; y = 0;
- }
+ reference->x = bytestream_get_be16(&buf);
+ reference->y = bytestream_get_be16(&buf);
+
+ /* TODO If cropping, cropping_x, cropping_y, cropping_width, cropping_height (all 2 bytes).*/
+ av_dlog(avctx, "Subtitle Placement ID=%d, x=%d, y=%d\n", reference->picture_id, reference->x, reference->y);
- /* Fill in dimensions */
- ctx->presentation.x = x;
- ctx->presentation.y = y;
+ if (reference->x > avctx->width || reference->y > avctx->height) {
+ av_log(avctx, AV_LOG_ERROR, "Subtitle out of video bounds. x = %d, y = %d, video width = %d, video height = %d.\n",
+ reference->x, reference->y, avctx->width, avctx->height);
+ reference->x = 0;
+ reference->y = 0;
+ }
+ }
}
/**
@@ -354,52 +387,61 @@ static int display_end_segment(AVCodecContext *avctx, void *data,
{
AVSubtitle *sub = data;
PGSSubContext *ctx = avctx->priv_data;
+ int64_t pts;
+
+ uint16_t rect;
/*
* The end display time is a timeout value and is only reached
- * if the next subtitle is later then timeout or subtitle has
+ * if the next subtitle is later than timeout or subtitle has
* not been cleared by a subsequent empty display command.
*/
+ 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;
- // Blank if last object_number was 0.
- // Note that this may be wrong for more complex subtitles.
- if (!ctx->presentation.object_number)
+ // Blank if last object_count was 0.
+ if (!ctx->presentation.object_count)
return 1;
+
sub->start_display_time = 0;
sub->end_display_time = 20000;
sub->format = 0;
- sub->rects = av_mallocz(sizeof(*sub->rects));
- sub->rects[0] = av_mallocz(sizeof(*sub->rects[0]));
- sub->num_rects = 1;
-
- if (ctx->presentation.composition_flag & 0x40)
- sub->rects[0]->flags |= AV_SUBTITLE_FLAG_FORCED;
+ sub->num_rects = ctx->presentation.object_count;
+ sub->rects = av_mallocz(sizeof(*sub->rects) * sub->num_rects);
+
+ for (rect = 0; rect < sub->num_rects; ++rect) {
+ uint16_t picture_id = ctx->presentation.objects[rect].picture_id;
+ sub->rects[rect] = av_mallocz(sizeof(*sub->rects[rect]));
+ sub->rects[rect]->x = ctx->presentation.objects[rect].x;
+ sub->rects[rect]->y = ctx->presentation.objects[rect].y;
+ sub->rects[rect]->w = ctx->pictures[picture_id].w;
+ sub->rects[rect]->h = ctx->pictures[picture_id].h;
+ sub->rects[rect]->type = SUBTITLE_BITMAP;
+
+ /* Process bitmap */
+ sub->rects[rect]->pict.linesize[0] = ctx->pictures[picture_id].w;
+ if (ctx->pictures[picture_id].rle) {
+ if (ctx->pictures[picture_id].rle_remaining_len)
+ av_log(avctx, AV_LOG_ERROR, "RLE data length %u is %u bytes shorter than expected\n",
+ ctx->pictures[picture_id].rle_data_len, ctx->pictures[picture_id].rle_remaining_len);
+ if (decode_rle(avctx, sub, rect, ctx->pictures[picture_id].rle, ctx->pictures[picture_id].rle_data_len) < 0)
+ return 0;
+ }
- sub->rects[0]->x = ctx->presentation.x;
- sub->rects[0]->y = ctx->presentation.y;
- sub->rects[0]->w = ctx->picture.w;
- sub->rects[0]->h = ctx->picture.h;
- sub->rects[0]->type = SUBTITLE_BITMAP;
+ /* Allocate memory for colors */
+ sub->rects[rect]->nb_colors = 256;
+ sub->rects[rect]->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
- /* Process bitmap */
- sub->rects[0]->pict.linesize[0] = ctx->picture.w;
+ /* Copy the forced flag */
+ sub->rects[rect]->flags = (ctx->presentation.objects[rect].composition & 0x40) != 0 ? AV_SUBTITLE_FLAG_FORCED : 0;
- if (ctx->picture.rle) {
- if (ctx->picture.rle_remaining_len)
- av_log(avctx, AV_LOG_ERROR, "RLE data length %u is %u bytes shorter than expected\n",
- ctx->picture.rle_data_len, ctx->picture.rle_remaining_len);
- if(decode_rle(avctx, sub, ctx->picture.rle, ctx->picture.rle_data_len) < 0)
- return 0;
+ if (!ctx->forced_subs_only || ctx->presentation.objects[rect].composition & 0x40)
+ memcpy(sub->rects[rect]->pict.data[1], ctx->clut, sub->rects[rect]->nb_colors * sizeof(uint32_t));
}
- /* Allocate memory for colors */
- sub->rects[0]->nb_colors = 256;
- sub->rects[0]->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
-
- memcpy(sub->rects[0]->pict.data[1], ctx->clut, sub->rects[0]->nb_colors * sizeof(uint32_t));
return 1;
}
@@ -409,6 +451,7 @@ static int decode(AVCodecContext *avctx, void *data, int *data_size,
{
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
+ AVSubtitle *sub = data;
const uint8_t *buf_end;
uint8_t segment_type;
@@ -452,7 +495,7 @@ static int decode(AVCodecContext *avctx, void *data, int *data_size,
parse_picture_segment(avctx, buf, segment_length);
break;
case PRESENTATION_SEGMENT:
- parse_presentation_segment(avctx, buf, segment_length, avpkt->pts);
+ parse_presentation_segment(avctx, buf, segment_length, sub->pts);
break;
case WINDOW_SEGMENT:
/*
@@ -479,6 +522,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"),
@@ -488,4 +545,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 2d72977..5b528f5 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,14 @@ 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) {
- if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
- return -1;
avcodec_set_dimensions(avctx, s->width, s->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;
- }
memset(frame->data[0], 0, s->height * frame->linesize[0]);
frame->pict_type = AV_PICTURE_TYPE_I;
frame->palette_has_changed = 1;
@@ -165,7 +163,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 +173,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 +196,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 +214,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 +233,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/png.c b/libavcodec/png.c
index 65d6964..b398d91 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
new file mode 100644
index 0000000..6f153d9
--- a/dev/null
+++ b/libavcodec/png_parser.c
@@ -0,0 +1,120 @@
+/*
+ * PNG parser
+ * Copyright (c) 2009 Peter Holik
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * PNG parser
+ */
+
+#include "parser.h"
+#include "png.h"
+
+typedef struct PNGParseContext
+{
+ ParseContext pc;
+ uint32_t index;
+ uint32_t chunk_length;
+ uint32_t remaining_size;
+} PNGParseContext;
+
+static int png_parse(AVCodecParserContext *s, AVCodecContext *avctx,
+ const uint8_t **poutbuf, int *poutbuf_size,
+ const uint8_t *buf, int buf_size)
+{
+ PNGParseContext *ppc = s->priv_data;
+ 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 == PNGSIG || state64 == MNGSIG) {
+ i++;
+ ppc->pc.frame_start_found = 1;
+ break;
+ }
+ }
+ ppc->pc.state64 = state64;
+ } else
+ if (ppc->remaining_size) {
+ i = FFMIN(ppc->remaining_size, buf_size);
+ ppc->remaining_size -= i;
+ if (ppc->remaining_size)
+ goto flush;
+ if (ppc->index == -1) {
+ next = i;
+ goto flush;
+ }
+ }
+
+ for (;ppc->pc.frame_start_found && i < buf_size; i++) {
+ ppc->pc.state = (ppc->pc.state<<8) | buf[i];
+ if (ppc->index == 3) {
+ ppc->chunk_length = ppc->pc.state;
+ if (ppc->chunk_length > 0x7fffffff) {
+ ppc->index = ppc->pc.frame_start_found = 0;
+ goto flush;
+ }
+ ppc->chunk_length += 4;
+ } else if (ppc->index == 7) {
+ if (ppc->chunk_length >= buf_size - i)
+ ppc->remaining_size = ppc->chunk_length - buf_size + i + 1;
+ if (ppc->pc.state == MKBETAG('I', 'E', 'N', 'D')) {
+ if (ppc->remaining_size)
+ ppc->index = -1;
+ else
+ next = ppc->chunk_length + i + 1;
+ break;
+ } else {
+ ppc->index = 0;
+ if (ppc->remaining_size)
+ break;
+ else
+ i += ppc->chunk_length;
+ continue;
+ }
+ }
+ ppc->index++;
+ }
+flush:
+ if (ff_combine_frame(&ppc->pc, next, &buf, &buf_size) < 0)
+ return buf_size;
+
+ ppc->index = ppc->pc.frame_start_found = 0;
+
+ *poutbuf = buf;
+ *poutbuf_size = buf_size;
+ return next;
+}
+
+AVCodecParser ff_png_parser = {
+ .codec_ids = { AV_CODEC_ID_PNG },
+ .priv_data_size = sizeof(PNGParseContext),
+ .parser_parse = png_parse,
+ .parser_close = ff_parse_close,
+};
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
index e646296..3d21e50 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,50 +95,64 @@ 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) {
memcpy(d, s, bpp);
}
d += bpp;
if ((mask << j) & 0x80)
s += bpp;
}
- }
break;
}
}
@@ -163,7 +189,7 @@ void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, int w
if(bpp >= 2) g = dst[1];\
if(bpp >= 3) 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;\
dst[i+1] = g = op(g, src[i+1], last[i+1]);\
@@ -179,13 +205,9 @@ void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, int w
else if(bpp == 2) UNROLL1(2, op)\
else if(bpp == 3) 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' */
static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type,
@@ -229,7 +251,7 @@ static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type,
p = last[i];
dst[i] = p + src[i];
}
- if (bpp > 1 && size > 4) {
+ if (bpp > 2 && size > 4) {
// would write off the end of the array if we let it process the last pixel with bpp=3
int w = bpp == 4 ? size : size - 3;
dsp->add_paeth_prediction(dst + i, src + i, last + i, w - i, bpp);
@@ -240,45 +262,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;
- }
+/* This used to be called "deloco" in FFmpeg
+ * and is actually an inverse reversible colorspace transformation */
+#define YUV2RGB(NAME, TYPE) \
+static void deloco_ ## NAME(TYPE *dst, int size, int alpha) \
+{ \
+ int i; \
+ for (i = 0; i < size; i += 3 + alpha) { \
+ int g = dst [i+1]; \
+ dst[i+0] += g; \
+ dst[i+2] += g; \
+ } \
}
-static void convert_to_rgb32(uint8_t *dst, const uint8_t *src, int width, int loco)
-{
- if (loco)
- convert_to_rgb32_loco(dst, src, width, 1);
- else
- convert_to_rgb32_loco(dst, src, width, 0);
-}
-
-static void deloco_rgb24(uint8_t *dst, int size)
-{
- int i;
- for (i = 0; i < size; i += 3) {
- int g = dst[i + 1];
- dst[i + 0] += g;
- dst[i + 2] += g;
- }
-}
+YUV2RGB(rgb8, uint8_t)
+YUV2RGB(rgb16, uint16_t)
/* process exactly one decompressed row */
static void png_handle_row(PNGDecContext *s)
@@ -288,14 +286,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
@@ -303,17 +293,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;
@@ -327,15 +328,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;
@@ -362,14 +364,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)) {
@@ -386,6 +389,122 @@ static int png_decode_idat(PNGDecContext *s, int length)
return 0;
}
+static int decode_zbuf(AVBPrint *bp, const uint8_t *data,
+ const uint8_t *data_end)
+{
+ z_stream zstream;
+ unsigned char *buf;
+ unsigned buf_size;
+ int ret;
+
+ zstream.zalloc = ff_png_zalloc;
+ zstream.zfree = ff_png_zfree;
+ zstream.opaque = NULL;
+ if (inflateInit(&zstream) != Z_OK)
+ return AVERROR_EXTERNAL;
+ zstream.next_in = (unsigned char *)data;
+ zstream.avail_in = data_end - data;
+ av_bprint_init(bp, 0, -1);
+
+ while (zstream.avail_in > 0) {
+ av_bprint_get_buffer(bp, 1, &buf, &buf_size);
+ if (!buf_size) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ zstream.next_out = buf;
+ zstream.avail_out = buf_size;
+ ret = inflate(&zstream, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END) {
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+ bp->len += zstream.next_out - buf;
+ if (ret == Z_STREAM_END)
+ break;
+ }
+ inflateEnd(&zstream);
+ bp->str[bp->len] = 0;
+ return 0;
+
+fail:
+ inflateEnd(&zstream);
+ av_bprint_finalize(bp, NULL);
+ return ret;
+}
+
+static uint8_t *iso88591_to_utf8(const uint8_t *in, size_t size_in)
+{
+ size_t extra = 0, i;
+ uint8_t *out, *q;
+
+ for (i = 0; i < size_in; i++)
+ extra += in[i] >= 0x80;
+ if (size_in == SIZE_MAX || extra > SIZE_MAX - size_in - 1)
+ return NULL;
+ q = out = av_malloc(size_in + extra + 1);
+ if (!out)
+ return NULL;
+ for (i = 0; i < size_in; i++) {
+ if (in[i] >= 0x80) {
+ *(q++) = 0xC0 | (in[i] >> 6);
+ *(q++) = 0x80 | (in[i] & 0x3F);
+ } else {
+ *(q++) = in[i];
+ }
+ }
+ *(q++) = 0;
+ return out;
+}
+
+static int decode_text_chunk(PNGDecContext *s, uint32_t length, int compressed,
+ AVDictionary **dict)
+{
+ int ret, method;
+ const uint8_t *data = s->gb.buffer;
+ const uint8_t *data_end = data + length;
+ const uint8_t *keyword = data;
+ const uint8_t *keyword_end = memchr(keyword, 0, data_end - keyword);
+ uint8_t *kw_utf8 = NULL, *text, *txt_utf8 = NULL;
+ unsigned text_len;
+ AVBPrint bp;
+
+ if (!keyword_end)
+ return AVERROR_INVALIDDATA;
+ data = keyword_end + 1;
+
+ if (compressed) {
+ if (data == data_end)
+ return AVERROR_INVALIDDATA;
+ method = *(data++);
+ if (method)
+ return AVERROR_INVALIDDATA;
+ if ((ret = decode_zbuf(&bp, data, data_end)) < 0)
+ return ret;
+ text_len = bp.len;
+ av_bprint_finalize(&bp, (char **)&text);
+ if (!text)
+ return AVERROR(ENOMEM);
+ } else {
+ text = (uint8_t *)data;
+ text_len = data_end - text;
+ }
+
+ 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_frame(AVCodecContext *avctx,
void *data, int *got_frame,
AVPacket *avpkt)
@@ -393,18 +512,26 @@ static int decode_frame(AVCodecContext *avctx,
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;
+ AVFrame *p;
+ AVDictionary *metadata = NULL;
uint32_t tag, length;
+ 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 */
- if (buf_size < 8 ||
- memcmp(buf, ff_pngsig, 8) != 0 &&
- memcmp(buf, ff_mngsig, 8) != 0)
- return -1;
+ sig = bytestream2_get_be64(&s->gb);
+ if (sig != PNGSIG &&
+ sig != MNGSIG) {
+ av_log(avctx, AV_LOG_ERROR, "Missing png signature\n");
+ return AVERROR_INVALIDDATA;
+ }
- bytestream2_init(&s->gb, buf + 8, buf_size - 8);
s->y = s->state = 0;
/* init the zlib */
@@ -412,16 +539,24 @@ static int decode_frame(AVCodecContext *avctx,
s->zstream.zfree = ff_png_zfree;
s->zstream.opaque = NULL;
ret = inflateInit(&s->zstream);
- if (ret != Z_OK)
- return -1;
+ if (ret != Z_OK) {
+ av_log(avctx, AV_LOG_ERROR, "inflateInit returned error %d\n", ret);
+ return AVERROR_EXTERNAL;
+ }
for (;;) {
- if (bytestream2_get_bytes_left(&s->gb) <= 0)
+ if (bytestream2_get_bytes_left(&s->gb) <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "No bytes left\n");
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),
@@ -434,6 +569,7 @@ static int decode_frame(AVCodecContext *avctx,
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");
goto fail;
}
s->bit_depth = bytestream2_get_byte(&s->gb);
@@ -443,14 +579,29 @@ static int decode_frame(AVCodecContext *avctx,
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 "
+ 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);
break;
+ case MKTAG('p', 'H', 'Y', 's'):
+ if (s->state & PNG_IDAT) {
+ av_log(avctx, AV_LOG_ERROR, "pHYs after IDAT\n");
+ goto fail;
+ }
+ 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 */
+ break;
case MKTAG('I', 'D', 'A', 'T'):
- if (!(s->state & PNG_IHDR))
+ if (!(s->state & PNG_IHDR)) {
+ av_log(avctx, AV_LOG_ERROR, "IDAT without IHDR\n");
goto fail;
+ }
if (!(s->state & PNG_IDAT)) {
/* init image info */
avctx->width = s->width;
@@ -461,13 +612,13 @@ static int decode_frame(AVCodecContext *avctx,
s->bpp = (s->bits_per_pixel + 7) >> 3;
s->row_size = (avctx->width * s->bits_per_pixel + 7) >> 3;
- if (s->bit_depth == 8 &&
+ 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 == 8 &&
+ } 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_RGB32;
- } else if (s->bit_depth == 8 &&
+ 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 &&
@@ -476,23 +627,28 @@ static int decode_frame(AVCodecContext *avctx,
} 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 &&
+ } 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) {
+ 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_Y400A;
} else {
+ av_log(avctx, AV_LOG_ERROR, "unsupported bit depth %d "
+ "and color type %d\n",
+ s->bit_depth, s->color_type);
goto fail;
}
- if (ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if (ff_thread_get_buffer(avctx, &s->picture, AV_GET_BUFFER_FLAG_REF) < 0)
goto fail;
- }
+ ff_thread_finish_setup(avctx);
+
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
p->interlaced_frame = !!s->interlace_type;
@@ -512,25 +668,25 @@ static int decode_frame(AVCodecContext *avctx,
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)
+ 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 */
- s->last_row = av_mallocz(s->row_size);
+ av_fast_padded_mallocz(&s->last_row, &s->last_row_size, 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);
+ av_fast_padded_malloc(&s->tmp_row, &s->tmp_row_size, s->row_size);
if (!s->tmp_row)
goto fail;
}
/* compressed row */
- crow_buf_base = av_malloc(s->row_size + 16);
- if (!crow_buf_base)
+ av_fast_padded_malloc(&s->buffer, &s->buffer_size, s->row_size + 16);
+ if (!s->buffer)
goto fail;
/* we want crow_buf+1 to be 16-byte aligned */
- s->crow_buf = crow_buf_base + 15;
+ s->crow_buf = s->buffer + 15;
s->zstream.avail_out = s->crow_size;
s->zstream.next_out = s->crow_buf;
}
@@ -551,10 +707,10 @@ static int decode_frame(AVCodecContext *avctx,
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;
+ s->palette[i] = (0xFFU << 24) | (r << 16) | (g << 8) | b;
}
for (; i < 256; i++) {
- s->palette[i] = (0xff << 24);
+ s->palette[i] = (0xFFU << 24);
}
s->state |= PNG_PLTE;
bytestream2_skip(&s->gb, 4); /* crc */
@@ -576,9 +732,22 @@ static int decode_frame(AVCodecContext *avctx,
bytestream2_skip(&s->gb, 4); /* crc */
}
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:
@@ -589,13 +758,91 @@ static int decode_frame(AVCodecContext *avctx,
}
}
exit_loop:
+
+ 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;
+ }
+ }
+ 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;
+ }
+ }
+ 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;
+ }
+ }
+
/* 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];
+ 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++) {
pd[i] += pd_last[i];
@@ -605,35 +852,57 @@ static int decode_frame(AVCodecContext *avctx,
}
}
}
+ ff_thread_report_progress(&s->picture, INT_MAX, 0);
+
+ av_frame_set_metadata(p, metadata);
+ metadata = NULL;
- av_frame_unref(s->prev);
- if ((ret = av_frame_ref(s->prev, p)) < 0)
- goto fail;
+ 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;
+ av_dict_free(&metadata);
+ ff_thread_report_progress(&s->picture, INT_MAX, 0);
+ ret = AVERROR_INVALIDDATA;
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;
}
@@ -642,7 +911,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;
}
@@ -656,5 +934,7 @@ AVCodec ff_png_decoder = {
.init = png_dec_init,
.close = png_dec_end,
.decode = decode_frame,
- .capabilities = CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
+ .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 afd9093..5ab1c35 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
*/
@@ -31,7 +31,7 @@
static void add_bytes_l2_c(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w)
{
long i;
- for (i = 0; i <= w - sizeof(long); i += sizeof(long)) {
+ for (i = 0; i <= w - (int)sizeof(long); i += sizeof(long)) {
long a = *(long *)(src1 + i);
long b = *(long *)(src2 + i);
*(long *)(dst + i) = ((a & pb_7f) + (b & pb_7f)) ^ ((a ^ b) & pb_80);
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 f39fadd..58acc3c 100644
--- a/libavcodec/pngenc.c
+++ b/libavcodec/pngenc.c
@@ -2,36 +2,37 @@
* 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 "dsputil.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;
DSPContext dsp;
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);
@@ -144,7 +148,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) {
@@ -170,23 +174,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)
{
@@ -233,12 +220,12 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
PNGEncContext *s = avctx->priv_data;
AVFrame * const p= &s->picture;
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;
uint8_t *crow_base = NULL, *crow_buf, *crow;
uint8_t *progressive_buf = NULL;
- uint8_t *rgba_buf = NULL;
uint8_t *top_buf = NULL;
*p = *pict;
@@ -247,7 +234,15 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
is_progressive = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT);
switch(avctx->pix_fmt) {
- case AV_PIX_FMT_RGB32:
+ case AV_PIX_FMT_RGBA64BE:
+ bit_depth = 16;
+ color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ break;
+ case AV_PIX_FMT_RGB48BE:
+ bit_depth = 16;
+ color_type = PNG_COLOR_TYPE_RGB;
+ break;
+ case AV_PIX_FMT_RGBA:
bit_depth = 8;
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
break;
@@ -263,6 +258,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;
@@ -289,15 +288,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;
@@ -312,19 +309,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);
@@ -337,6 +329,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;
@@ -351,7 +354,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);
@@ -378,10 +381,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);
@@ -396,11 +395,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);
top = ptr;
@@ -432,7 +426,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;
@@ -444,6 +437,23 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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;
+ }
+
avcodec_get_frame_defaults(&s->picture);
avctx->coded_frame= &s->picture;
ff_dsputil_init(&s->dsp, avctx);
@@ -452,9 +462,31 @@ 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;
}
+#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"),
@@ -463,9 +495,14 @@ AVCodec ff_png_encoder = {
.priv_data_size = sizeof(PNGEncContext),
.init = png_enc_init,
.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_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 eea30e8..63b77cd 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;
}
@@ -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 {
@@ -184,13 +192,3 @@ int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s)
}
return 0;
}
-
-av_cold int ff_pnm_init(AVCodecContext *avctx)
-{
- PNMContext *s = avctx->priv_data;
-
- avcodec_get_frame_defaults(&s->picture);
- avctx->coded_frame = &s->picture;
-
- return 0;
-}
diff --git a/libavcodec/pnm.h b/libavcodec/pnm.h
index ec5ebdb..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
*/
@@ -28,12 +28,10 @@ typedef struct PNMContext {
uint8_t *bytestream;
uint8_t *bytestream_start;
uint8_t *bytestream_end;
- AVFrame picture;
int maxval; ///< maximum value of a pixel
int type;
} PNMContext;
int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s);
-int ff_pnm_init(AVCodecContext *avctx);
#endif /* AVCODEC_PNM_H */
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 2e4983c..9b2824a 100644
--- a/libavcodec/pnmenc.c
+++ b/libavcodec/pnmenc.c
@@ -2,48 +2,40 @@
* 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"
#include "pnm.h"
static int pnm_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *pict, int *got_packet)
+ const AVFrame *p, int *got_packet)
{
PNMContext *s = avctx->priv_data;
- AVFrame * const p = &s->picture;
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;
- }
-
- *p = *pict;
- p->pict_type = AV_PICTURE_TYPE_I;
- p->key_frame = 1;
s->bytestream_start =
s->bytestream = pkt->data;
@@ -73,6 +65,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;
@@ -132,7 +128,6 @@ AVCodec ff_pgm_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_PGM,
.priv_data_size = sizeof(PNMContext),
- .init = ff_pnm_init,
.encode2 = pnm_encode_frame,
.pix_fmts = (const enum AVPixelFormat[]){
AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_NONE
@@ -147,7 +142,6 @@ AVCodec ff_pgmyuv_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_PGMYUV,
.priv_data_size = sizeof(PNMContext),
- .init = ff_pnm_init,
.encode2 = pnm_encode_frame,
.pix_fmts = (const enum AVPixelFormat[]){
AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_NONE
@@ -162,7 +156,6 @@ AVCodec ff_ppm_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_PPM,
.priv_data_size = sizeof(PNMContext),
- .init = ff_pnm_init,
.encode2 = pnm_encode_frame,
.pix_fmts = (const enum AVPixelFormat[]){
AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48BE, AV_PIX_FMT_NONE
@@ -177,7 +170,6 @@ AVCodec ff_pbm_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_PBM,
.priv_data_size = sizeof(PNMContext),
- .init = ff_pnm_init,
.encode2 = pnm_encode_frame,
.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_MONOWHITE,
AV_PIX_FMT_NONE },
diff --git a/libavcodec/ppc/asm.S b/libavcodec/ppc/asm.S
index 4d4285b..bbbf8a4 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/dsputil_altivec.c b/libavcodec/ppc/dsputil_altivec.c
index f90ec74..f36e394 100644
--- a/libavcodec/ppc/dsputil_altivec.c
+++ b/libavcodec/ppc/dsputil_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
*/
diff --git a/libavcodec/ppc/dsputil_altivec.h b/libavcodec/ppc/dsputil_altivec.h
index de5054b..0e769ab 100644
--- a/libavcodec/ppc/dsputil_altivec.h
+++ b/libavcodec/ppc/dsputil_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/dsputil_ppc.c b/libavcodec/ppc/dsputil_ppc.c
index 6ae6e3f..7454ea0 100644
--- a/libavcodec/ppc/dsputil_ppc.c
+++ b/libavcodec/ppc/dsputil_ppc.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
*/
@@ -141,6 +141,7 @@ static long check_dcbzl_effect(void)
av_cold void ff_dsputil_init_ppc(DSPContext *c, AVCodecContext *avctx)
{
const int high_bit_depth = avctx->bits_per_raw_sample > 8;
+ int mm_flags = av_get_cpu_flags();
// Common optimizations whether AltiVec is available or not
if (!high_bit_depth) {
@@ -156,7 +157,7 @@ av_cold void ff_dsputil_init_ppc(DSPContext *c, AVCodecContext *avctx)
}
}
- if (PPC_ALTIVEC(av_get_cpu_flags())) {
+ if (PPC_ALTIVEC(mm_flags)) {
ff_dsputil_init_altivec(c, avctx);
ff_int_init_altivec(c, avctx);
c->gmc1 = ff_gmc1_altivec;
@@ -169,7 +170,7 @@ av_cold void ff_dsputil_init_ppc(DSPContext *c, AVCodecContext *avctx)
}
#endif //CONFIG_ENCODERS
- if (avctx->bits_per_raw_sample <= 8) {
+ if (avctx->lowres == 0 && avctx->bits_per_raw_sample <= 8) {
if ((avctx->idct_algo == FF_IDCT_AUTO) ||
(avctx->idct_algo == FF_IDCT_ALTIVEC)) {
c->idct_put = ff_idct_put_altivec;
diff --git a/libavcodec/ppc/fdct_altivec.c b/libavcodec/ppc/fdct_altivec.c
index 355a697..ff816e2 100644
--- a/libavcodec/ppc/fdct_altivec.c
+++ b/libavcodec/ppc/fdct_altivec.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
*/
diff --git a/libavcodec/ppc/fft_altivec.c b/libavcodec/ppc/fft_altivec.c
index 2885d3f..2357198 100644
--- a/libavcodec/ppc/fft_altivec.c
+++ b/libavcodec/ppc/fft_altivec.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
*/
diff --git a/libavcodec/ppc/fft_altivec_s.S b/libavcodec/ppc/fft_altivec_s.S
index 958d7df..16ce838 100644
--- a/libavcodec/ppc/fft_altivec_s.S
+++ b/libavcodec/ppc/fft_altivec_s.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/fmtconvert_altivec.c b/libavcodec/ppc/fmtconvert_altivec.c
index 1359259..cd32e39 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/gmc_altivec.c b/libavcodec/ppc/gmc_altivec.c
index 38968dd..45d850a 100644
--- a/libavcodec/ppc/gmc_altivec.c
+++ b/libavcodec/ppc/gmc_altivec.c
@@ -3,20 +3,20 @@
* AltiVec-enabled
* 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 @@ void ff_gmc1_altivec(uint8_t *dst /* align 8 */, uint8_t *src /* align1 */, int
srcvA = vec_perm(src_0, src_1, 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 {
@@ -90,7 +90,7 @@ void ff_gmc1_altivec(uint8_t *dst /* align 8 */, uint8_t *src /* align1 */, int
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/h264chroma_init.c b/libavcodec/ppc/h264chroma_init.c
index 415a8df..921f2de 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 df298dd..9e749b5 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 f99c8f8..1f50ec9 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 4df1d09..cfc4560 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 d40c5d8..345ec39 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
*/
diff --git a/libavcodec/ppc/idct_altivec.c b/libavcodec/ppc/idct_altivec.c
index f68a61d..c6f2cd8 100644
--- a/libavcodec/ppc/idct_altivec.c
+++ b/libavcodec/ppc/idct_altivec.c
@@ -1,31 +1,31 @@
/*
* 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
diff --git a/libavcodec/ppc/int_altivec.c b/libavcodec/ppc/int_altivec.c
index 38ec99b..d4e0c85 100644
--- a/libavcodec/ppc/int_altivec.c
+++ b/libavcodec/ppc/int_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/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/mpegaudiodsp_altivec.c b/libavcodec/ppc/mpegaudiodsp_altivec.c
index 6855c0b..091f9a3 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 3d74029..cedc1c8 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/vc1dsp_altivec.c b/libavcodec/ppc/vc1dsp_altivec.c
index 4695b1c..1b73dd0 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 56a865d..d243bf6 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 bf50c02..56c2d0b 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 504139d..c858d8a 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
*/
@@ -241,15 +241,15 @@ void put_vp8_epel ## WIDTH ## _v ## TAPS ## _altivec(uint8_t *dst, ptrdiff_t dst
}
#define EPEL_HV(WIDTH, HTAPS, VTAPS) \
-static void put_vp8_epel ## WIDTH ## _h ## HTAPS ## v ## VTAPS ## _altivec(uint8_t *dst, ptrdiff_t stride, uint8_t *src, ptrdiff_t s, int h, int mx, int my) \
+static void put_vp8_epel ## WIDTH ## _h ## HTAPS ## v ## VTAPS ## _altivec(uint8_t *dst, ptrdiff_t dstride, uint8_t *src, ptrdiff_t sstride, int h, int mx, int my) \
{ \
DECLARE_ALIGNED(16, uint8_t, tmp)[(2*WIDTH+5)*16]; \
if (VTAPS == 6) { \
- put_vp8_epel ## WIDTH ## _h ## HTAPS ## _altivec(tmp, 16, src-2*stride, stride, h+5, mx, my); \
- put_vp8_epel ## WIDTH ## _v ## VTAPS ## _altivec(dst, stride, tmp+2*16, 16, h, mx, my); \
+ put_vp8_epel ## WIDTH ## _h ## HTAPS ## _altivec(tmp, 16, src-2*sstride, sstride, h+5, mx, my); \
+ put_vp8_epel ## WIDTH ## _v ## VTAPS ## _altivec(dst, dstride, tmp+2*16, 16, h, mx, my); \
} else { \
- put_vp8_epel ## WIDTH ## _h ## HTAPS ## _altivec(tmp, 16, src-stride, stride, h+4, mx, my); \
- put_vp8_epel ## WIDTH ## _v ## VTAPS ## _altivec(dst, stride, tmp+16, 16, h, mx, my); \
+ put_vp8_epel ## WIDTH ## _h ## HTAPS ## _altivec(tmp, 16, src-sstride, sstride, h+4, mx, my); \
+ put_vp8_epel ## WIDTH ## _v ## VTAPS ## _altivec(dst, dstride, tmp+16, 16, h, mx, my); \
} \
}
@@ -269,9 +269,44 @@ EPEL_HV(4, 4,6)
EPEL_HV(4, 6,4)
EPEL_HV(4, 4,4)
-static void put_vp8_pixels16_altivec(uint8_t *dst, ptrdiff_t stride, uint8_t *src, ptrdiff_t s, int h, int mx, int my)
+static void put_vp8_pixels16_altivec(uint8_t *dst, ptrdiff_t dstride, uint8_t *src, ptrdiff_t sstride, int h, int mx, int my)
{
- ff_put_pixels16_altivec(dst, src, stride, 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 perm = vec_lvsl(0, src);
+ int i;
+ register ptrdiff_t dstride2 = dstride << 1, sstride2 = sstride << 1;
+ register ptrdiff_t dstride3 = dstride2 + dstride, sstride3 = sstride + sstride2;
+ register ptrdiff_t dstride4 = dstride << 2, sstride4 = sstride << 2;
+
+// hand-unrolling the loop by 4 gains about 15%
+// mininum execution time goes from 74 to 60 cycles
+// it's faster than -funroll-loops, but using
+// -funroll-loops w/ this is bad - 74 cycles again.
+// all this is on a 7450, tuning for the 7450
+ for (i = 0; i < h; i += 4) {
+ pixelsv1 = vec_ld( 0, src);
+ pixelsv2 = vec_ld(15, src);
+ pixelsv1B = vec_ld(sstride, src);
+ pixelsv2B = vec_ld(15 + sstride, src);
+ pixelsv1C = vec_ld(sstride2, src);
+ pixelsv2C = vec_ld(15 + sstride2, src);
+ pixelsv1D = vec_ld(sstride3, src);
+ pixelsv2D = vec_ld(15 + sstride3, src);
+ vec_st(vec_perm(pixelsv1, pixelsv2, perm),
+ 0, (unsigned char*)dst);
+ vec_st(vec_perm(pixelsv1B, pixelsv2B, perm),
+ dstride, (unsigned char*)dst);
+ vec_st(vec_perm(pixelsv1C, pixelsv2C, perm),
+ dstride2, (unsigned char*)dst);
+ vec_st(vec_perm(pixelsv1D, pixelsv2D, perm),
+ dstride3, (unsigned char*)dst);
+ src += sstride4;
+ dst += dstride4;
+ }
}
#endif /* HAVE_ALTIVEC */
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.c b/libavcodec/proresdec.c
deleted file mode 100644
index 144fa26..0000000
--- a/libavcodec/proresdec.c
+++ b/dev/null
@@ -1,781 +0,0 @@
-/*
- * Apple ProRes compatible decoder
- *
- * Copyright (c) 2010-2011 Maxim Poliakovski
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * This is a decoder for Apple ProRes 422 SD/HQ/LT/Proxy and ProRes 4444.
- * It is used for storing and editing high definition video data in Apple's Final Cut Pro.
- *
- * @see http://wiki.multimedia.cx/index.php?title=Apple_ProRes
- */
-
-#define LONG_BITSTREAM_READER // some ProRes vlc codes require up to 28 bits to be read at once
-
-#include <stdint.h>
-
-#include "libavutil/intmath.h"
-#include "avcodec.h"
-#include "dsputil.h"
-#include "internal.h"
-#include "proresdata.h"
-#include "proresdsp.h"
-#include "get_bits.h"
-
-typedef struct {
- const uint8_t *index; ///< pointers to the data of this slice
- int slice_num;
- int x_pos, y_pos;
- int slice_width;
- int prev_slice_sf; ///< scalefactor of the previous decoded slice
- DECLARE_ALIGNED(16, int16_t, blocks)[8 * 4 * 64];
- DECLARE_ALIGNED(16, int16_t, qmat_luma_scaled)[64];
- DECLARE_ALIGNED(16, int16_t, qmat_chroma_scaled)[64];
-} ProresThreadData;
-
-typedef struct {
- ProresDSPContext dsp;
- AVFrame *frame;
- ScanTable scantable;
- int scantable_type; ///< -1 = uninitialized, 0 = progressive, 1/2 = interlaced
-
- int frame_type; ///< 0 = progressive, 1 = top-field first, 2 = bottom-field first
- int pic_format; ///< 2 = 422, 3 = 444
- uint8_t qmat_luma[64]; ///< dequantization matrix for luma
- uint8_t qmat_chroma[64]; ///< dequantization matrix for chroma
- int qmat_changed; ///< 1 - global quantization matrices changed
- int total_slices; ///< total number of slices in a picture
- ProresThreadData *slice_data;
- int pic_num;
- int chroma_factor;
- int mb_chroma_factor;
- int num_chroma_blocks; ///< number of chrominance blocks in a macroblock
- int num_x_slices;
- int num_y_slices;
- int slice_width_factor;
- int slice_height_factor;
- int num_x_mbs;
- int num_y_mbs;
- int alpha_info;
-} ProresContext;
-
-
-static av_cold int decode_init(AVCodecContext *avctx)
-{
- ProresContext *ctx = avctx->priv_data;
-
- ctx->total_slices = 0;
- ctx->slice_data = NULL;
-
- avctx->bits_per_raw_sample = PRORES_BITS_PER_SAMPLE;
- ff_proresdsp_init(&ctx->dsp);
-
- ctx->scantable_type = -1; // set scantable type to uninitialized
- memset(ctx->qmat_luma, 4, 64);
- memset(ctx->qmat_chroma, 4, 64);
-
- return 0;
-}
-
-
-static int decode_frame_header(ProresContext *ctx, const uint8_t *buf,
- const int data_size, AVCodecContext *avctx)
-{
- int hdr_size, version, width, height, flags;
- const uint8_t *ptr;
-
- hdr_size = AV_RB16(buf);
- if (hdr_size > data_size) {
- av_log(avctx, AV_LOG_ERROR, "frame data too small\n");
- return AVERROR_INVALIDDATA;
- }
-
- version = AV_RB16(buf + 2);
- if (version >= 2) {
- av_log(avctx, AV_LOG_ERROR,
- "unsupported header version: %d\n", version);
- return AVERROR_INVALIDDATA;
- }
-
- width = AV_RB16(buf + 8);
- height = AV_RB16(buf + 10);
- if (width != avctx->width || height != avctx->height) {
- av_log(avctx, AV_LOG_ERROR,
- "picture dimension changed: old: %d x %d, new: %d x %d\n",
- avctx->width, avctx->height, width, height);
- return AVERROR_INVALIDDATA;
- }
-
- ctx->frame_type = (buf[12] >> 2) & 3;
- if (ctx->frame_type > 2) {
- av_log(avctx, AV_LOG_ERROR,
- "unsupported frame type: %d\n", ctx->frame_type);
- return AVERROR_INVALIDDATA;
- }
-
- ctx->chroma_factor = (buf[12] >> 6) & 3;
- ctx->mb_chroma_factor = ctx->chroma_factor + 2;
- ctx->num_chroma_blocks = (1 << ctx->chroma_factor) >> 1;
- ctx->alpha_info = buf[17] & 0xf;
-
- if (ctx->alpha_info > 2) {
- av_log(avctx, AV_LOG_ERROR, "Invalid alpha mode %d\n", ctx->alpha_info);
- return AVERROR_INVALIDDATA;
- }
-
- switch (ctx->chroma_factor) {
- case 2:
- avctx->pix_fmt = ctx->alpha_info ? AV_PIX_FMT_YUVA422P10
- : AV_PIX_FMT_YUV422P10;
- break;
- case 3:
- avctx->pix_fmt = ctx->alpha_info ? AV_PIX_FMT_YUVA444P10
- : AV_PIX_FMT_YUV444P10;
- break;
- default:
- av_log(avctx, AV_LOG_ERROR,
- "unsupported picture format: %d\n", ctx->pic_format);
- return AVERROR_INVALIDDATA;
- }
-
- if (ctx->scantable_type != ctx->frame_type) {
- if (!ctx->frame_type)
- ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable,
- ff_prores_progressive_scan);
- else
- ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable,
- ff_prores_interlaced_scan);
- ctx->scantable_type = ctx->frame_type;
- }
-
- if (ctx->frame_type) { /* if interlaced */
- ctx->frame->interlaced_frame = 1;
- ctx->frame->top_field_first = ctx->frame_type & 1;
- } else {
- ctx->frame->interlaced_frame = 0;
- }
-
- avctx->color_primaries = buf[14];
- avctx->color_trc = buf[15];
- avctx->colorspace = buf[16];
-
- ctx->qmat_changed = 0;
- ptr = buf + 20;
- flags = buf[19];
- if (flags & 2) {
- if (ptr - buf > hdr_size - 64) {
- av_log(avctx, AV_LOG_ERROR, "header data too small\n");
- return AVERROR_INVALIDDATA;
- }
- if (memcmp(ctx->qmat_luma, ptr, 64)) {
- memcpy(ctx->qmat_luma, ptr, 64);
- ctx->qmat_changed = 1;
- }
- ptr += 64;
- } else {
- memset(ctx->qmat_luma, 4, 64);
- ctx->qmat_changed = 1;
- }
-
- if (flags & 1) {
- if (ptr - buf > hdr_size - 64) {
- av_log(avctx, AV_LOG_ERROR, "header data too small\n");
- return -1;
- }
- if (memcmp(ctx->qmat_chroma, ptr, 64)) {
- memcpy(ctx->qmat_chroma, ptr, 64);
- ctx->qmat_changed = 1;
- }
- } else {
- memset(ctx->qmat_chroma, 4, 64);
- ctx->qmat_changed = 1;
- }
-
- return hdr_size;
-}
-
-
-static int decode_picture_header(ProresContext *ctx, const uint8_t *buf,
- const int data_size, AVCodecContext *avctx)
-{
- int i, hdr_size, pic_data_size, num_slices;
- int slice_width_factor, slice_height_factor;
- int remainder, num_x_slices;
- const uint8_t *data_ptr, *index_ptr;
-
- hdr_size = data_size > 0 ? buf[0] >> 3 : 0;
- if (hdr_size < 8 || hdr_size > data_size) {
- av_log(avctx, AV_LOG_ERROR, "picture header too small\n");
- return AVERROR_INVALIDDATA;
- }
-
- pic_data_size = AV_RB32(buf + 1);
- if (pic_data_size > data_size) {
- av_log(avctx, AV_LOG_ERROR, "picture data too small\n");
- return AVERROR_INVALIDDATA;
- }
-
- slice_width_factor = buf[7] >> 4;
- slice_height_factor = buf[7] & 0xF;
- if (slice_width_factor > 3 || slice_height_factor) {
- av_log(avctx, AV_LOG_ERROR,
- "unsupported slice dimension: %d x %d\n",
- 1 << slice_width_factor, 1 << slice_height_factor);
- return AVERROR_INVALIDDATA;
- }
-
- ctx->slice_width_factor = slice_width_factor;
- ctx->slice_height_factor = slice_height_factor;
-
- ctx->num_x_mbs = (avctx->width + 15) >> 4;
- ctx->num_y_mbs = (avctx->height +
- (1 << (4 + ctx->frame->interlaced_frame)) - 1) >>
- (4 + ctx->frame->interlaced_frame);
-
- remainder = ctx->num_x_mbs & ((1 << slice_width_factor) - 1);
- num_x_slices = (ctx->num_x_mbs >> slice_width_factor) + (remainder & 1) +
- ((remainder >> 1) & 1) + ((remainder >> 2) & 1);
-
- num_slices = num_x_slices * ctx->num_y_mbs;
- if (num_slices != AV_RB16(buf + 5)) {
- av_log(avctx, AV_LOG_ERROR, "invalid number of slices\n");
- return AVERROR_INVALIDDATA;
- }
-
- if (ctx->total_slices != num_slices) {
- av_freep(&ctx->slice_data);
- ctx->slice_data = av_malloc((num_slices + 1) * sizeof(ctx->slice_data[0]));
- if (!ctx->slice_data)
- return AVERROR(ENOMEM);
- ctx->total_slices = num_slices;
- }
-
- if (hdr_size + num_slices * 2 > data_size) {
- av_log(avctx, AV_LOG_ERROR, "slice table too small\n");
- return AVERROR_INVALIDDATA;
- }
-
- /* parse slice table allowing quick access to the slice data */
- index_ptr = buf + hdr_size;
- data_ptr = index_ptr + num_slices * 2;
-
- for (i = 0; i < num_slices; i++) {
- ctx->slice_data[i].index = data_ptr;
- ctx->slice_data[i].prev_slice_sf = 0;
- data_ptr += AV_RB16(index_ptr + i * 2);
- }
- ctx->slice_data[i].index = data_ptr;
- ctx->slice_data[i].prev_slice_sf = 0;
-
- if (data_ptr > buf + data_size) {
- av_log(avctx, AV_LOG_ERROR, "out of slice data\n");
- return -1;
- }
-
- return pic_data_size;
-}
-
-
-/**
- * Read an unsigned rice/exp golomb codeword.
- */
-static inline int decode_vlc_codeword(GetBitContext *gb, unsigned codebook)
-{
- unsigned int rice_order, exp_order, switch_bits;
- unsigned int buf, code;
- int log, prefix_len, len;
-
- OPEN_READER(re, gb);
- UPDATE_CACHE(re, gb);
- buf = GET_CACHE(re, gb);
-
- /* number of prefix bits to switch between Rice and expGolomb */
- switch_bits = (codebook & 3) + 1;
- rice_order = codebook >> 5; /* rice code order */
- exp_order = (codebook >> 2) & 7; /* exp golomb code order */
-
- log = 31 - av_log2(buf); /* count prefix bits (zeroes) */
-
- if (log < switch_bits) { /* ok, we got a rice code */
- if (!rice_order) {
- /* shortcut for faster decoding of rice codes without remainder */
- code = log;
- LAST_SKIP_BITS(re, gb, log + 1);
- } else {
- prefix_len = log + 1;
- code = (log << rice_order) + NEG_USR32(buf << prefix_len, rice_order);
- LAST_SKIP_BITS(re, gb, prefix_len + rice_order);
- }
- } else { /* otherwise we got a exp golomb code */
- len = (log << 1) - switch_bits + exp_order + 1;
- code = NEG_USR32(buf, len) - (1 << exp_order) + (switch_bits << rice_order);
- LAST_SKIP_BITS(re, gb, len);
- }
-
- CLOSE_READER(re, gb);
-
- return code;
-}
-
-#define LSB2SIGN(x) (-((x) & 1))
-#define TOSIGNED(x) (((x) >> 1) ^ LSB2SIGN(x))
-
-/**
- * Decode DC coefficients for all blocks in a slice.
- */
-static inline void decode_dc_coeffs(GetBitContext *gb, int16_t *out,
- int nblocks)
-{
- int16_t prev_dc;
- int i, sign;
- int16_t delta;
- unsigned int code;
-
- code = decode_vlc_codeword(gb, FIRST_DC_CB);
- out[0] = prev_dc = TOSIGNED(code);
-
- out += 64; /* move to the DC coeff of the next block */
- delta = 3;
-
- for (i = 1; i < nblocks; i++, out += 64) {
- code = decode_vlc_codeword(gb, ff_prores_dc_codebook[FFMIN(FFABS(delta), 3)]);
-
- sign = -(((delta >> 15) & 1) ^ (code & 1));
- delta = (((code + 1) >> 1) ^ sign) - sign;
- prev_dc += delta;
- out[0] = prev_dc;
- }
-}
-
-
-/**
- * Decode AC coefficients for all blocks in a slice.
- */
-static inline int decode_ac_coeffs(GetBitContext *gb, int16_t *out,
- int blocks_per_slice,
- int plane_size_factor,
- const uint8_t *scan)
-{
- int pos, block_mask, run, level, sign, run_cb_index, lev_cb_index;
- int max_coeffs, bits_left;
-
- /* set initial prediction values */
- run = 4;
- level = 2;
-
- max_coeffs = blocks_per_slice << 6;
- block_mask = blocks_per_slice - 1;
-
- for (pos = blocks_per_slice - 1; pos < max_coeffs;) {
- run_cb_index = ff_prores_run_to_cb_index[FFMIN(run, 15)];
- lev_cb_index = ff_prores_lev_to_cb_index[FFMIN(level, 9)];
-
- bits_left = get_bits_left(gb);
- if (bits_left <= 0 || (bits_left <= 8 && !show_bits(gb, bits_left)))
- return 0;
-
- run = decode_vlc_codeword(gb, ff_prores_ac_codebook[run_cb_index]);
- if (run < 0)
- return AVERROR_INVALIDDATA;
-
- bits_left = get_bits_left(gb);
- if (bits_left <= 0 || (bits_left <= 8 && !show_bits(gb, bits_left)))
- return AVERROR_INVALIDDATA;
-
- level = decode_vlc_codeword(gb, ff_prores_ac_codebook[lev_cb_index]) + 1;
- if (level < 0)
- return AVERROR_INVALIDDATA;
-
- pos += run + 1;
- if (pos >= max_coeffs)
- break;
-
- sign = get_sbits(gb, 1);
- out[((pos & block_mask) << 6) + scan[pos >> plane_size_factor]] =
- (level ^ sign) - sign;
- }
-
- return 0;
-}
-
-
-/**
- * Decode a slice plane (luma or chroma).
- */
-static int decode_slice_plane(ProresContext *ctx, ProresThreadData *td,
- const uint8_t *buf,
- int data_size, uint16_t *out_ptr,
- int linesize, int mbs_per_slice,
- int blocks_per_mb, int plane_size_factor,
- const int16_t *qmat, int is_chroma)
-{
- GetBitContext gb;
- int16_t *block_ptr;
- int mb_num, blocks_per_slice, ret;
-
- blocks_per_slice = mbs_per_slice * blocks_per_mb;
-
- memset(td->blocks, 0, 8 * 4 * 64 * sizeof(*td->blocks));
-
- init_get_bits(&gb, buf, data_size << 3);
-
- decode_dc_coeffs(&gb, td->blocks, blocks_per_slice);
-
- ret = decode_ac_coeffs(&gb, td->blocks, blocks_per_slice,
- plane_size_factor, ctx->scantable.permutated);
- if (ret < 0)
- return ret;
-
- /* inverse quantization, inverse transform and output */
- block_ptr = td->blocks;
-
- if (!is_chroma) {
- for (mb_num = 0; mb_num < mbs_per_slice; mb_num++, out_ptr += blocks_per_mb * 4) {
- ctx->dsp.idct_put(out_ptr, linesize, block_ptr, qmat);
- block_ptr += 64;
- if (blocks_per_mb > 2) {
- ctx->dsp.idct_put(out_ptr + 8, linesize, block_ptr, qmat);
- block_ptr += 64;
- }
- ctx->dsp.idct_put(out_ptr + linesize * 4, linesize, block_ptr, qmat);
- block_ptr += 64;
- if (blocks_per_mb > 2) {
- ctx->dsp.idct_put(out_ptr + linesize * 4 + 8, linesize, block_ptr, qmat);
- block_ptr += 64;
- }
- }
- } else {
- for (mb_num = 0; mb_num < mbs_per_slice; mb_num++, out_ptr += blocks_per_mb * 4) {
- ctx->dsp.idct_put(out_ptr, linesize, block_ptr, qmat);
- block_ptr += 64;
- ctx->dsp.idct_put(out_ptr + linesize * 4, linesize, block_ptr, qmat);
- block_ptr += 64;
- if (blocks_per_mb > 2) {
- ctx->dsp.idct_put(out_ptr + 8, linesize, block_ptr, qmat);
- block_ptr += 64;
- ctx->dsp.idct_put(out_ptr + linesize * 4 + 8, linesize, block_ptr, qmat);
- block_ptr += 64;
- }
- }
- }
- return 0;
-}
-
-
-static void unpack_alpha(GetBitContext *gb, uint16_t *dst, int num_coeffs,
- const int num_bits)
-{
- const int mask = (1 << num_bits) - 1;
- int i, idx, val, alpha_val;
-
- idx = 0;
- alpha_val = mask;
- do {
- do {
- if (get_bits1(gb))
- val = get_bits(gb, num_bits);
- else {
- int sign;
- val = get_bits(gb, num_bits == 16 ? 7 : 4);
- sign = val & 1;
- val = (val + 2) >> 1;
- if (sign)
- val = -val;
- }
- alpha_val = (alpha_val + val) & mask;
- if (num_bits == 16)
- dst[idx++] = alpha_val >> 6;
- else
- dst[idx++] = (alpha_val << 2) | (alpha_val >> 6);
- if (idx >= num_coeffs - 1)
- break;
- } while (get_bits1(gb));
- val = get_bits(gb, 4);
- if (!val)
- val = get_bits(gb, 11);
- if (idx + val > num_coeffs)
- val = num_coeffs - idx;
- if (num_bits == 16)
- for (i = 0; i < val; i++)
- dst[idx++] = alpha_val >> 6;
- else
- for (i = 0; i < val; i++)
- dst[idx++] = (alpha_val << 2) | (alpha_val >> 6);
- } while (idx < num_coeffs);
-}
-
-/**
- * Decode alpha slice plane.
- */
-static void decode_alpha_plane(ProresContext *ctx, ProresThreadData *td,
- const uint8_t *buf, int data_size,
- uint16_t *out_ptr, int linesize,
- int mbs_per_slice)
-{
- GetBitContext gb;
- int i;
- uint16_t *block_ptr;
-
- memset(td->blocks, 0, 8 * 4 * 64 * sizeof(*td->blocks));
-
- init_get_bits(&gb, buf, data_size << 3);
-
- if (ctx->alpha_info == 2)
- unpack_alpha(&gb, td->blocks, mbs_per_slice * 4 * 64, 16);
- else
- unpack_alpha(&gb, td->blocks, mbs_per_slice * 4 * 64, 8);
-
- block_ptr = td->blocks;
-
- for (i = 0; i < 16; i++) {
- memcpy(out_ptr, block_ptr, 16 * mbs_per_slice * sizeof(*out_ptr));
- out_ptr += linesize >> 1;
- block_ptr += 16 * mbs_per_slice;
- }
-}
-
-static int decode_slice(AVCodecContext *avctx, void *tdata)
-{
- ProresThreadData *td = tdata;
- ProresContext *ctx = avctx->priv_data;
- int mb_x_pos = td->x_pos;
- int mb_y_pos = td->y_pos;
- int pic_num = ctx->pic_num;
- int slice_num = td->slice_num;
- int mbs_per_slice = td->slice_width;
- const uint8_t *buf;
- uint8_t *y_data, *u_data, *v_data, *a_data;
- AVFrame *pic = ctx->frame;
- int i, sf, slice_width_factor;
- int slice_data_size, hdr_size;
- int y_data_size, u_data_size, v_data_size, a_data_size;
- int y_linesize, u_linesize, v_linesize, a_linesize;
- int coff[4];
- int ret;
-
- buf = ctx->slice_data[slice_num].index;
- slice_data_size = ctx->slice_data[slice_num + 1].index - buf;
-
- slice_width_factor = av_log2(mbs_per_slice);
-
- y_data = pic->data[0];
- u_data = pic->data[1];
- v_data = pic->data[2];
- a_data = pic->data[3];
- y_linesize = pic->linesize[0];
- u_linesize = pic->linesize[1];
- v_linesize = pic->linesize[2];
- a_linesize = pic->linesize[3];
-
- if (pic->interlaced_frame) {
- if (!(pic_num ^ pic->top_field_first)) {
- y_data += y_linesize;
- u_data += u_linesize;
- v_data += v_linesize;
- if (a_data)
- a_data += a_linesize;
- }
- y_linesize <<= 1;
- u_linesize <<= 1;
- v_linesize <<= 1;
- a_linesize <<= 1;
- }
- y_data += (mb_y_pos << 4) * y_linesize + (mb_x_pos << 5);
- u_data += (mb_y_pos << 4) * u_linesize + (mb_x_pos << ctx->mb_chroma_factor);
- v_data += (mb_y_pos << 4) * v_linesize + (mb_x_pos << ctx->mb_chroma_factor);
- if (a_data)
- a_data += (mb_y_pos << 4) * a_linesize + (mb_x_pos << 5);
-
- if (slice_data_size < 6) {
- av_log(avctx, AV_LOG_ERROR, "slice data too small\n");
- return AVERROR_INVALIDDATA;
- }
-
- /* parse slice header */
- hdr_size = buf[0] >> 3;
- coff[0] = hdr_size;
- y_data_size = AV_RB16(buf + 2);
- coff[1] = coff[0] + y_data_size;
- u_data_size = AV_RB16(buf + 4);
- coff[2] = coff[1] + u_data_size;
- v_data_size = hdr_size > 7 ? AV_RB16(buf + 6) : slice_data_size - coff[2];
- coff[3] = coff[2] + v_data_size;
- a_data_size = slice_data_size - coff[3];
-
- /* if V or alpha component size is negative that means that previous
- component sizes are too large */
- if (v_data_size < 0 || a_data_size < 0 || hdr_size < 6) {
- av_log(avctx, AV_LOG_ERROR, "invalid data size\n");
- return AVERROR_INVALIDDATA;
- }
-
- sf = av_clip(buf[1], 1, 224);
- sf = sf > 128 ? (sf - 96) << 2 : sf;
-
- /* scale quantization matrixes according with slice's scale factor */
- /* TODO: this can be SIMD-optimized a lot */
- if (ctx->qmat_changed || sf != td->prev_slice_sf) {
- td->prev_slice_sf = sf;
- for (i = 0; i < 64; i++) {
- td->qmat_luma_scaled[ctx->dsp.idct_permutation[i]] = ctx->qmat_luma[i] * sf;
- td->qmat_chroma_scaled[ctx->dsp.idct_permutation[i]] = ctx->qmat_chroma[i] * sf;
- }
- }
-
- /* decode luma plane */
- ret = decode_slice_plane(ctx, td, buf + coff[0], y_data_size,
- (uint16_t*) y_data, y_linesize,
- mbs_per_slice, 4, slice_width_factor + 2,
- td->qmat_luma_scaled, 0);
-
- if (ret < 0)
- return ret;
-
- /* decode U chroma plane */
- ret = decode_slice_plane(ctx, td, buf + coff[1], u_data_size,
- (uint16_t*) u_data, u_linesize,
- mbs_per_slice, ctx->num_chroma_blocks,
- slice_width_factor + ctx->chroma_factor - 1,
- td->qmat_chroma_scaled, 1);
- if (ret < 0)
- return ret;
-
- /* decode V chroma plane */
- ret = decode_slice_plane(ctx, td, buf + coff[2], v_data_size,
- (uint16_t*) v_data, v_linesize,
- mbs_per_slice, ctx->num_chroma_blocks,
- slice_width_factor + ctx->chroma_factor - 1,
- td->qmat_chroma_scaled, 1);
- if (ret < 0)
- return ret;
-
- /* decode alpha plane if available */
- if (a_data && a_data_size)
- decode_alpha_plane(ctx, td, buf + coff[3], a_data_size,
- (uint16_t*) a_data, a_linesize,
- mbs_per_slice);
-
- return 0;
-}
-
-
-static int decode_picture(ProresContext *ctx, int pic_num,
- AVCodecContext *avctx)
-{
- int slice_num, slice_width, x_pos, y_pos;
-
- slice_num = 0;
-
- ctx->pic_num = pic_num;
- for (y_pos = 0; y_pos < ctx->num_y_mbs; y_pos++) {
- slice_width = 1 << ctx->slice_width_factor;
-
- for (x_pos = 0; x_pos < ctx->num_x_mbs && slice_width;
- x_pos += slice_width) {
- while (ctx->num_x_mbs - x_pos < slice_width)
- slice_width >>= 1;
-
- ctx->slice_data[slice_num].slice_num = slice_num;
- ctx->slice_data[slice_num].x_pos = x_pos;
- ctx->slice_data[slice_num].y_pos = y_pos;
- ctx->slice_data[slice_num].slice_width = slice_width;
-
- slice_num++;
- }
- }
-
- return avctx->execute(avctx, decode_slice,
- ctx->slice_data, NULL, slice_num,
- sizeof(ctx->slice_data[0]));
-}
-
-
-#define MOVE_DATA_PTR(nbytes) buf += (nbytes); buf_size -= (nbytes)
-
-static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
- AVPacket *avpkt)
-{
- ProresContext *ctx = avctx->priv_data;
- const uint8_t *buf = avpkt->data;
- int buf_size = avpkt->size;
- int frame_hdr_size, pic_num, pic_data_size;
-
- ctx->frame = data;
- ctx->frame->pict_type = AV_PICTURE_TYPE_I;
- ctx->frame->key_frame = 1;
-
- /* check frame atom container */
- if (buf_size < 28 || buf_size < AV_RB32(buf) ||
- AV_RB32(buf + 4) != FRAME_ID) {
- av_log(avctx, AV_LOG_ERROR, "invalid frame\n");
- return AVERROR_INVALIDDATA;
- }
-
- MOVE_DATA_PTR(8);
-
- frame_hdr_size = decode_frame_header(ctx, buf, buf_size, avctx);
- if (frame_hdr_size < 0)
- return AVERROR_INVALIDDATA;
-
- MOVE_DATA_PTR(frame_hdr_size);
-
- if (ff_get_buffer(avctx, ctx->frame, 0) < 0)
- return -1;
-
- for (pic_num = 0; ctx->frame->interlaced_frame - pic_num + 1; pic_num++) {
- pic_data_size = decode_picture_header(ctx, buf, buf_size, avctx);
- if (pic_data_size < 0)
- return AVERROR_INVALIDDATA;
-
- if (decode_picture(ctx, pic_num, avctx))
- return -1;
-
- MOVE_DATA_PTR(pic_data_size);
- }
-
- ctx->frame = NULL;
- *got_frame = 1;
-
- return avpkt->size;
-}
-
-
-static av_cold int decode_close(AVCodecContext *avctx)
-{
- ProresContext *ctx = avctx->priv_data;
-
- av_freep(&ctx->slice_data);
-
- return 0;
-}
-
-
-AVCodec ff_prores_decoder = {
- .name = "prores",
- .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"),
- .type = AVMEDIA_TYPE_VIDEO,
- .id = AV_CODEC_ID_PRORES,
- .priv_data_size = sizeof(ProresContext),
- .init = decode_init,
- .close = decode_close,
- .decode = decode_frame,
- .capabilities = CODEC_CAP_DR1 | CODEC_CAP_SLICE_THREADS,
-};
diff --git a/libavcodec/proresdec.h b/libavcodec/proresdec.h
new file mode 100644
index 0000000..de50dae
--- a/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 "dsputil.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 {
+ DSPContext dsp;
+ 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..b1affad
--- a/dev/null
+++ b/libavcodec/proresdec2.c
@@ -0,0 +1,688 @@
+/*
+ * 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 "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_dsputil_init(&ctx->dsp, 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(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->dsp.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->dsp.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->dsp.clear_block(blocks+(i<<6));
+
+ init_get_bits(&gb, buf, buf_size << 3);
+
+ if (ctx->alpha_info == 2) {
+ unpack_alpha(&gb, blocks, blocks_per_slice * 4 * 64, 16);
+ } else {
+ unpack_alpha(&gb, blocks, blocks_per_slice * 4 * 64, 8);
+ }
+
+ block = blocks;
+ for (i = 0; i < 16; i++) {
+ memcpy(dst, block, 16 * blocks_per_slice * sizeof(*dst));
+ dst += dst_stride >> 1;
+ block += 16 * blocks_per_slice;
+ }
+}
+
+static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int threadnr)
+{
+ ProresContext *ctx = avctx->priv_data;
+ SliceContext *slice = &ctx->slices[jobnr];
+ const uint8_t *buf = slice->data;
+ AVFrame *pic = ctx->frame;
+ int i, hdr_size, qscale, log2_chroma_blocks_per_mb;
+ int luma_stride, chroma_stride;
+ int y_data_size, u_data_size, v_data_size, a_data_size;
+ uint8_t *dest_y, *dest_u, *dest_v, *dest_a;
+ int16_t qmat_luma_scaled[64];
+ int16_t qmat_chroma_scaled[64];
+ int mb_x_shift;
+ int ret;
+
+ slice->ret = -1;
+ //av_log(avctx, AV_LOG_INFO, "slice %d mb width %d mb x %d y %d\n",
+ // jobnr, slice->mb_count, slice->mb_x, slice->mb_y);
+
+ // slice header
+ hdr_size = buf[0] >> 3;
+ qscale = av_clip(buf[1], 1, 224);
+ qscale = qscale > 128 ? qscale - 96 << 2: qscale;
+ y_data_size = AV_RB16(buf + 2);
+ u_data_size = AV_RB16(buf + 4);
+ v_data_size = slice->data_size - y_data_size - u_data_size - hdr_size;
+ if (hdr_size > 7) v_data_size = AV_RB16(buf + 6);
+ a_data_size = slice->data_size - y_data_size - u_data_size -
+ v_data_size - hdr_size;
+
+ if (y_data_size < 0 || u_data_size < 0 || v_data_size < 0
+ || hdr_size+y_data_size+u_data_size+v_data_size > slice->data_size){
+ av_log(avctx, AV_LOG_ERROR, "invalid plane data size\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ buf += hdr_size;
+
+ for (i = 0; i < 64; i++) {
+ qmat_luma_scaled [i] = ctx->qmat_luma [i] * qscale;
+ qmat_chroma_scaled[i] = ctx->qmat_chroma[i] * qscale;
+ }
+
+ if (ctx->frame_type == 0) {
+ luma_stride = pic->linesize[0];
+ chroma_stride = pic->linesize[1];
+ } else {
+ luma_stride = pic->linesize[0] << 1;
+ chroma_stride = pic->linesize[1] << 1;
+ }
+
+ if (avctx->pix_fmt == AV_PIX_FMT_YUV444P10 || avctx->pix_fmt == AV_PIX_FMT_YUVA444P10) {
+ mb_x_shift = 5;
+ log2_chroma_blocks_per_mb = 2;
+ } else {
+ mb_x_shift = 4;
+ log2_chroma_blocks_per_mb = 1;
+ }
+
+ dest_y = pic->data[0] + (slice->mb_y << 4) * luma_stride + (slice->mb_x << 5);
+ dest_u = pic->data[1] + (slice->mb_y << 4) * chroma_stride + (slice->mb_x << mb_x_shift);
+ dest_v = pic->data[2] + (slice->mb_y << 4) * chroma_stride + (slice->mb_x << mb_x_shift);
+ dest_a = pic->data[3] + (slice->mb_y << 4) * luma_stride + (slice->mb_x << 5);
+
+ if (ctx->frame_type && ctx->first_field ^ ctx->frame->top_field_first) {
+ dest_y += pic->linesize[0];
+ dest_u += pic->linesize[1];
+ dest_v += pic->linesize[2];
+ dest_a += pic->linesize[3];
+ }
+
+ ret = decode_slice_luma(avctx, slice, (uint16_t*)dest_y, luma_stride,
+ buf, y_data_size, qmat_luma_scaled);
+ if (ret < 0)
+ return ret;
+
+ if (!(avctx->flags & CODEC_FLAG_GRAY)) {
+ ret = decode_slice_chroma(avctx, slice, (uint16_t*)dest_u, chroma_stride,
+ buf + y_data_size, u_data_size,
+ qmat_chroma_scaled, log2_chroma_blocks_per_mb);
+ if (ret < 0)
+ return ret;
+
+ ret = decode_slice_chroma(avctx, slice, (uint16_t*)dest_v, chroma_stride,
+ buf + y_data_size + u_data_size, v_data_size,
+ qmat_chroma_scaled, log2_chroma_blocks_per_mb);
+ if (ret < 0)
+ return ret;
+ }
+ /* decode alpha plane if available */
+ if (ctx->alpha_info && pic->data[3] && a_data_size)
+ decode_slice_alpha(ctx, (uint16_t*)dest_a, luma_stride,
+ buf + y_data_size + u_data_size + v_data_size,
+ a_data_size, slice->mb_count);
+
+ slice->ret = 0;
+ return 0;
+}
+
+static int decode_picture(AVCodecContext *avctx)
+{
+ ProresContext *ctx = avctx->priv_data;
+ int i;
+
+ avctx->execute2(avctx, decode_slice_thread, NULL, NULL, ctx->slice_count);
+
+ for (i = 0; i < ctx->slice_count; i++)
+ if (ctx->slices[i].ret < 0)
+ return ctx->slices[i].ret;
+
+ return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ ProresContext *ctx = avctx->priv_data;
+ AVFrame *frame = data;
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ int frame_hdr_size, pic_size, ret;
+
+ if (buf_size < 28 || AV_RL32(buf + 4) != AV_RL32("icpf")) {
+ av_log(avctx, AV_LOG_ERROR, "invalid frame header\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->frame = frame;
+ ctx->frame->pict_type = AV_PICTURE_TYPE_I;
+ ctx->frame->key_frame = 1;
+ ctx->first_field = 1;
+
+ buf += 8;
+ buf_size -= 8;
+
+ frame_hdr_size = decode_frame_header(ctx, buf, buf_size, avctx);
+ if (frame_hdr_size < 0)
+ return frame_hdr_size;
+
+ buf += frame_hdr_size;
+ buf_size -= frame_hdr_size;
+
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+
+ decode_picture:
+ pic_size = decode_picture_header(avctx, buf, buf_size);
+ if (pic_size < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error decoding picture header\n");
+ return pic_size;
+ }
+
+ if ((ret = decode_picture(avctx)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error decoding picture\n");
+ return ret;
+ }
+
+ buf += pic_size;
+ buf_size -= pic_size;
+
+ if (ctx->frame_type && buf_size > 0 && ctx->first_field) {
+ ctx->first_field = 0;
+ goto decode_picture;
+ }
+
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+static av_cold int decode_close(AVCodecContext *avctx)
+{
+ ProresContext *ctx = avctx->priv_data;
+
+ av_freep(&ctx->slices);
+
+ return 0;
+}
+
+AVCodec ff_prores_decoder = {
+ .name = "prores",
+ .long_name = NULL_IF_CONFIG_SMALL("ProRes"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_PRORES,
+ .priv_data_size = sizeof(ProresContext),
+ .init = decode_init,
+ .close = decode_close,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_SLICE_THREADS,
+};
diff --git a/libavcodec/proresdec_lgpl.c b/libavcodec/proresdec_lgpl.c
new file mode 100644
index 0000000..a57429d
--- a/dev/null
+++ b/libavcodec/proresdec_lgpl.c
@@ -0,0 +1,783 @@
+/*
+ * Apple ProRes compatible decoder
+ *
+ * Copyright (c) 2010-2011 Maxim Poliakovski
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * This is a decoder for Apple ProRes 422 SD/HQ/LT/Proxy and ProRes 4444.
+ * It is used for storing and editing high definition video data in Apple's Final Cut Pro.
+ *
+ * @see http://wiki.multimedia.cx/index.php?title=Apple_ProRes
+ */
+
+#define LONG_BITSTREAM_READER // some ProRes vlc codes require up to 28 bits to be read at once
+
+#include <stdint.h>
+
+#include "libavutil/intmath.h"
+#include "avcodec.h"
+#include "dsputil.h"
+#include "internal.h"
+#include "proresdata.h"
+#include "proresdsp.h"
+#include "get_bits.h"
+
+typedef struct {
+ const uint8_t *index; ///< pointers to the data of this slice
+ int slice_num;
+ int x_pos, y_pos;
+ int slice_width;
+ int prev_slice_sf; ///< scalefactor of the previous decoded slice
+ DECLARE_ALIGNED(16, int16_t, blocks)[8 * 4 * 64];
+ DECLARE_ALIGNED(16, int16_t, qmat_luma_scaled)[64];
+ DECLARE_ALIGNED(16, int16_t, qmat_chroma_scaled)[64];
+} ProresThreadData;
+
+typedef struct {
+ ProresDSPContext dsp;
+ AVFrame *frame;
+ ScanTable scantable;
+ int scantable_type; ///< -1 = uninitialized, 0 = progressive, 1/2 = interlaced
+
+ int frame_type; ///< 0 = progressive, 1 = top-field first, 2 = bottom-field first
+ int pic_format; ///< 2 = 422, 3 = 444
+ uint8_t qmat_luma[64]; ///< dequantization matrix for luma
+ uint8_t qmat_chroma[64]; ///< dequantization matrix for chroma
+ int qmat_changed; ///< 1 - global quantization matrices changed
+ int total_slices; ///< total number of slices in a picture
+ ProresThreadData *slice_data;
+ int pic_num;
+ int chroma_factor;
+ int mb_chroma_factor;
+ int num_chroma_blocks; ///< number of chrominance blocks in a macroblock
+ int num_x_slices;
+ int num_y_slices;
+ int slice_width_factor;
+ int slice_height_factor;
+ int num_x_mbs;
+ int num_y_mbs;
+ int alpha_info;
+} ProresContext;
+
+
+static av_cold int decode_init(AVCodecContext *avctx)
+{
+ ProresContext *ctx = avctx->priv_data;
+
+ ctx->total_slices = 0;
+ ctx->slice_data = NULL;
+
+ avctx->bits_per_raw_sample = PRORES_BITS_PER_SAMPLE;
+ ff_proresdsp_init(&ctx->dsp, avctx);
+
+ ctx->scantable_type = -1; // set scantable type to uninitialized
+ memset(ctx->qmat_luma, 4, 64);
+ memset(ctx->qmat_chroma, 4, 64);
+
+ return 0;
+}
+
+
+static int decode_frame_header(ProresContext *ctx, const uint8_t *buf,
+ const int data_size, AVCodecContext *avctx)
+{
+ int hdr_size, version, width, height, flags;
+ const uint8_t *ptr;
+
+ hdr_size = AV_RB16(buf);
+ if (hdr_size > data_size) {
+ av_log(avctx, AV_LOG_ERROR, "frame data too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ version = AV_RB16(buf + 2);
+ if (version >= 2) {
+ av_log(avctx, AV_LOG_ERROR,
+ "unsupported header version: %d\n", version);
+ return AVERROR_INVALIDDATA;
+ }
+
+ width = AV_RB16(buf + 8);
+ height = AV_RB16(buf + 10);
+ if (width != avctx->width || height != avctx->height) {
+ av_log(avctx, AV_LOG_ERROR,
+ "picture dimension changed: old: %d x %d, new: %d x %d\n",
+ avctx->width, avctx->height, width, height);
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->frame_type = (buf[12] >> 2) & 3;
+ if (ctx->frame_type > 2) {
+ av_log(avctx, AV_LOG_ERROR,
+ "unsupported frame type: %d\n", ctx->frame_type);
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->chroma_factor = (buf[12] >> 6) & 3;
+ ctx->mb_chroma_factor = ctx->chroma_factor + 2;
+ ctx->num_chroma_blocks = (1 << ctx->chroma_factor) >> 1;
+ ctx->alpha_info = buf[17] & 0xf;
+
+ if (ctx->alpha_info > 2) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid alpha mode %d\n", ctx->alpha_info);
+ return AVERROR_INVALIDDATA;
+ }
+ if (avctx->skip_alpha) ctx->alpha_info = 0;
+
+ switch (ctx->chroma_factor) {
+ case 2:
+ avctx->pix_fmt = ctx->alpha_info ? AV_PIX_FMT_YUVA422P10
+ : AV_PIX_FMT_YUV422P10;
+ break;
+ case 3:
+ avctx->pix_fmt = ctx->alpha_info ? AV_PIX_FMT_YUVA444P10
+ : AV_PIX_FMT_YUV444P10;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR,
+ "unsupported picture format: %d\n", ctx->pic_format);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (ctx->scantable_type != ctx->frame_type) {
+ if (!ctx->frame_type)
+ ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable,
+ ff_prores_progressive_scan);
+ else
+ ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable,
+ ff_prores_interlaced_scan);
+ ctx->scantable_type = ctx->frame_type;
+ }
+
+ if (ctx->frame_type) { /* if interlaced */
+ ctx->frame->interlaced_frame = 1;
+ ctx->frame->top_field_first = ctx->frame_type & 1;
+ } else {
+ ctx->frame->interlaced_frame = 0;
+ }
+
+ avctx->color_primaries = buf[14];
+ avctx->color_trc = buf[15];
+ avctx->colorspace = buf[16];
+
+ ctx->qmat_changed = 0;
+ ptr = buf + 20;
+ flags = buf[19];
+ if (flags & 2) {
+ if (ptr - buf > hdr_size - 64) {
+ av_log(avctx, AV_LOG_ERROR, "header data too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (memcmp(ctx->qmat_luma, ptr, 64)) {
+ memcpy(ctx->qmat_luma, ptr, 64);
+ ctx->qmat_changed = 1;
+ }
+ ptr += 64;
+ } else {
+ memset(ctx->qmat_luma, 4, 64);
+ ctx->qmat_changed = 1;
+ }
+
+ if (flags & 1) {
+ if (ptr - buf > hdr_size - 64) {
+ av_log(avctx, AV_LOG_ERROR, "header data too small\n");
+ return -1;
+ }
+ if (memcmp(ctx->qmat_chroma, ptr, 64)) {
+ memcpy(ctx->qmat_chroma, ptr, 64);
+ ctx->qmat_changed = 1;
+ }
+ } else {
+ memset(ctx->qmat_chroma, 4, 64);
+ ctx->qmat_changed = 1;
+ }
+
+ return hdr_size;
+}
+
+
+static int decode_picture_header(ProresContext *ctx, const uint8_t *buf,
+ const int data_size, AVCodecContext *avctx)
+{
+ int i, hdr_size, pic_data_size, num_slices;
+ int slice_width_factor, slice_height_factor;
+ int remainder, num_x_slices;
+ const uint8_t *data_ptr, *index_ptr;
+
+ hdr_size = data_size > 0 ? buf[0] >> 3 : 0;
+ if (hdr_size < 8 || hdr_size > data_size) {
+ av_log(avctx, AV_LOG_ERROR, "picture header too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ pic_data_size = AV_RB32(buf + 1);
+ if (pic_data_size > data_size) {
+ av_log(avctx, AV_LOG_ERROR, "picture data too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ slice_width_factor = buf[7] >> 4;
+ slice_height_factor = buf[7] & 0xF;
+ if (slice_width_factor > 3 || slice_height_factor) {
+ av_log(avctx, AV_LOG_ERROR,
+ "unsupported slice dimension: %d x %d\n",
+ 1 << slice_width_factor, 1 << slice_height_factor);
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->slice_width_factor = slice_width_factor;
+ ctx->slice_height_factor = slice_height_factor;
+
+ ctx->num_x_mbs = (avctx->width + 15) >> 4;
+ ctx->num_y_mbs = (avctx->height +
+ (1 << (4 + ctx->frame->interlaced_frame)) - 1) >>
+ (4 + ctx->frame->interlaced_frame);
+
+ remainder = ctx->num_x_mbs & ((1 << slice_width_factor) - 1);
+ num_x_slices = (ctx->num_x_mbs >> slice_width_factor) + (remainder & 1) +
+ ((remainder >> 1) & 1) + ((remainder >> 2) & 1);
+
+ num_slices = num_x_slices * ctx->num_y_mbs;
+ if (num_slices != AV_RB16(buf + 5)) {
+ av_log(avctx, AV_LOG_ERROR, "invalid number of slices\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (ctx->total_slices != num_slices) {
+ av_freep(&ctx->slice_data);
+ ctx->slice_data = av_malloc((num_slices + 1) * sizeof(ctx->slice_data[0]));
+ if (!ctx->slice_data)
+ return AVERROR(ENOMEM);
+ ctx->total_slices = num_slices;
+ }
+
+ if (hdr_size + num_slices * 2 > data_size) {
+ av_log(avctx, AV_LOG_ERROR, "slice table too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* parse slice table allowing quick access to the slice data */
+ index_ptr = buf + hdr_size;
+ data_ptr = index_ptr + num_slices * 2;
+
+ for (i = 0; i < num_slices; i++) {
+ ctx->slice_data[i].index = data_ptr;
+ ctx->slice_data[i].prev_slice_sf = 0;
+ data_ptr += AV_RB16(index_ptr + i * 2);
+ }
+ ctx->slice_data[i].index = data_ptr;
+ ctx->slice_data[i].prev_slice_sf = 0;
+
+ if (data_ptr > buf + data_size) {
+ av_log(avctx, AV_LOG_ERROR, "out of slice data\n");
+ return -1;
+ }
+
+ return pic_data_size;
+}
+
+
+/**
+ * Read an unsigned rice/exp golomb codeword.
+ */
+static inline int decode_vlc_codeword(GetBitContext *gb, unsigned codebook)
+{
+ unsigned int rice_order, exp_order, switch_bits;
+ unsigned int buf, code;
+ int log, prefix_len, len;
+
+ OPEN_READER(re, gb);
+ UPDATE_CACHE(re, gb);
+ buf = GET_CACHE(re, gb);
+
+ /* number of prefix bits to switch between Rice and expGolomb */
+ switch_bits = (codebook & 3) + 1;
+ rice_order = codebook >> 5; /* rice code order */
+ exp_order = (codebook >> 2) & 7; /* exp golomb code order */
+
+ log = 31 - av_log2(buf); /* count prefix bits (zeroes) */
+
+ if (log < switch_bits) { /* ok, we got a rice code */
+ if (!rice_order) {
+ /* shortcut for faster decoding of rice codes without remainder */
+ code = log;
+ LAST_SKIP_BITS(re, gb, log + 1);
+ } else {
+ prefix_len = log + 1;
+ code = (log << rice_order) + NEG_USR32(buf << prefix_len, rice_order);
+ LAST_SKIP_BITS(re, gb, prefix_len + rice_order);
+ }
+ } else { /* otherwise we got a exp golomb code */
+ len = (log << 1) - switch_bits + exp_order + 1;
+ code = NEG_USR32(buf, len) - (1 << exp_order) + (switch_bits << rice_order);
+ LAST_SKIP_BITS(re, gb, len);
+ }
+
+ CLOSE_READER(re, gb);
+
+ return code;
+}
+
+#define LSB2SIGN(x) (-((x) & 1))
+#define TOSIGNED(x) (((x) >> 1) ^ LSB2SIGN(x))
+
+/**
+ * Decode DC coefficients for all blocks in a slice.
+ */
+static inline void decode_dc_coeffs(GetBitContext *gb, int16_t *out,
+ int nblocks)
+{
+ int16_t prev_dc;
+ int i, sign;
+ int16_t delta;
+ unsigned int code;
+
+ code = decode_vlc_codeword(gb, FIRST_DC_CB);
+ out[0] = prev_dc = TOSIGNED(code);
+
+ out += 64; /* move to the DC coeff of the next block */
+ delta = 3;
+
+ for (i = 1; i < nblocks; i++, out += 64) {
+ code = decode_vlc_codeword(gb, ff_prores_dc_codebook[FFMIN(FFABS(delta), 3)]);
+
+ sign = -(((delta >> 15) & 1) ^ (code & 1));
+ delta = (((code + 1) >> 1) ^ sign) - sign;
+ prev_dc += delta;
+ out[0] = prev_dc;
+ }
+}
+
+
+/**
+ * Decode AC coefficients for all blocks in a slice.
+ */
+static inline int decode_ac_coeffs(GetBitContext *gb, int16_t *out,
+ int blocks_per_slice,
+ int plane_size_factor,
+ const uint8_t *scan)
+{
+ int pos, block_mask, run, level, sign, run_cb_index, lev_cb_index;
+ int max_coeffs, bits_left;
+
+ /* set initial prediction values */
+ run = 4;
+ level = 2;
+
+ max_coeffs = blocks_per_slice << 6;
+ block_mask = blocks_per_slice - 1;
+
+ for (pos = blocks_per_slice - 1; pos < max_coeffs;) {
+ run_cb_index = ff_prores_run_to_cb_index[FFMIN(run, 15)];
+ lev_cb_index = ff_prores_lev_to_cb_index[FFMIN(level, 9)];
+
+ bits_left = get_bits_left(gb);
+ if (bits_left <= 0 || (bits_left <= 8 && !show_bits(gb, bits_left)))
+ return 0;
+
+ run = decode_vlc_codeword(gb, ff_prores_ac_codebook[run_cb_index]);
+ if (run < 0)
+ return AVERROR_INVALIDDATA;
+
+ bits_left = get_bits_left(gb);
+ if (bits_left <= 0 || (bits_left <= 8 && !show_bits(gb, bits_left)))
+ return AVERROR_INVALIDDATA;
+
+ level = decode_vlc_codeword(gb, ff_prores_ac_codebook[lev_cb_index]) + 1;
+ if (level < 0)
+ return AVERROR_INVALIDDATA;
+
+ pos += run + 1;
+ if (pos >= max_coeffs)
+ break;
+
+ sign = get_sbits(gb, 1);
+ out[((pos & block_mask) << 6) + scan[pos >> plane_size_factor]] =
+ (level ^ sign) - sign;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Decode a slice plane (luma or chroma).
+ */
+static int decode_slice_plane(ProresContext *ctx, ProresThreadData *td,
+ const uint8_t *buf,
+ int data_size, uint16_t *out_ptr,
+ int linesize, int mbs_per_slice,
+ int blocks_per_mb, int plane_size_factor,
+ const int16_t *qmat, int is_chroma)
+{
+ GetBitContext gb;
+ int16_t *block_ptr;
+ int mb_num, blocks_per_slice, ret;
+
+ blocks_per_slice = mbs_per_slice * blocks_per_mb;
+
+ memset(td->blocks, 0, 8 * 4 * 64 * sizeof(*td->blocks));
+
+ init_get_bits(&gb, buf, data_size << 3);
+
+ decode_dc_coeffs(&gb, td->blocks, blocks_per_slice);
+
+ ret = decode_ac_coeffs(&gb, td->blocks, blocks_per_slice,
+ plane_size_factor, ctx->scantable.permutated);
+ if (ret < 0)
+ return ret;
+
+ /* inverse quantization, inverse transform and output */
+ block_ptr = td->blocks;
+
+ if (!is_chroma) {
+ for (mb_num = 0; mb_num < mbs_per_slice; mb_num++, out_ptr += blocks_per_mb * 4) {
+ ctx->dsp.idct_put(out_ptr, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ if (blocks_per_mb > 2) {
+ ctx->dsp.idct_put(out_ptr + 8, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ }
+ ctx->dsp.idct_put(out_ptr + linesize * 4, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ if (blocks_per_mb > 2) {
+ ctx->dsp.idct_put(out_ptr + linesize * 4 + 8, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ }
+ }
+ } else {
+ for (mb_num = 0; mb_num < mbs_per_slice; mb_num++, out_ptr += blocks_per_mb * 4) {
+ ctx->dsp.idct_put(out_ptr, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ ctx->dsp.idct_put(out_ptr + linesize * 4, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ if (blocks_per_mb > 2) {
+ ctx->dsp.idct_put(out_ptr + 8, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ ctx->dsp.idct_put(out_ptr + linesize * 4 + 8, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ }
+ }
+ }
+ return 0;
+}
+
+
+static void unpack_alpha(GetBitContext *gb, uint16_t *dst, int num_coeffs,
+ const int num_bits)
+{
+ const int mask = (1 << num_bits) - 1;
+ int i, idx, val, alpha_val;
+
+ idx = 0;
+ alpha_val = mask;
+ do {
+ do {
+ if (get_bits1(gb))
+ val = get_bits(gb, num_bits);
+ else {
+ int sign;
+ val = get_bits(gb, num_bits == 16 ? 7 : 4);
+ sign = val & 1;
+ val = (val + 2) >> 1;
+ if (sign)
+ val = -val;
+ }
+ alpha_val = (alpha_val + val) & mask;
+ if (num_bits == 16)
+ dst[idx++] = alpha_val >> 6;
+ else
+ dst[idx++] = (alpha_val << 2) | (alpha_val >> 6);
+ if (idx >= num_coeffs) {
+ break;
+ }
+ } while (get_bits1(gb));
+ val = get_bits(gb, 4);
+ if (!val)
+ val = get_bits(gb, 11);
+ if (idx + val > num_coeffs)
+ val = num_coeffs - idx;
+ if (num_bits == 16)
+ for (i = 0; i < val; i++)
+ dst[idx++] = alpha_val >> 6;
+ else
+ for (i = 0; i < val; i++)
+ dst[idx++] = (alpha_val << 2) | (alpha_val >> 6);
+ } while (idx < num_coeffs);
+}
+
+/**
+ * Decode alpha slice plane.
+ */
+static void decode_alpha_plane(ProresContext *ctx, ProresThreadData *td,
+ const uint8_t *buf, int data_size,
+ uint16_t *out_ptr, int linesize,
+ int mbs_per_slice)
+{
+ GetBitContext gb;
+ int i;
+ uint16_t *block_ptr;
+
+ memset(td->blocks, 0, 8 * 4 * 64 * sizeof(*td->blocks));
+
+ init_get_bits(&gb, buf, data_size << 3);
+
+ if (ctx->alpha_info == 2)
+ unpack_alpha(&gb, td->blocks, mbs_per_slice * 4 * 64, 16);
+ else
+ unpack_alpha(&gb, td->blocks, mbs_per_slice * 4 * 64, 8);
+
+ block_ptr = td->blocks;
+
+ for (i = 0; i < 16; i++) {
+ memcpy(out_ptr, block_ptr, 16 * mbs_per_slice * sizeof(*out_ptr));
+ out_ptr += linesize >> 1;
+ block_ptr += 16 * mbs_per_slice;
+ }
+}
+
+static int decode_slice(AVCodecContext *avctx, void *tdata)
+{
+ ProresThreadData *td = tdata;
+ ProresContext *ctx = avctx->priv_data;
+ int mb_x_pos = td->x_pos;
+ int mb_y_pos = td->y_pos;
+ int pic_num = ctx->pic_num;
+ int slice_num = td->slice_num;
+ int mbs_per_slice = td->slice_width;
+ const uint8_t *buf;
+ uint8_t *y_data, *u_data, *v_data, *a_data;
+ AVFrame *pic = ctx->frame;
+ int i, sf, slice_width_factor;
+ int slice_data_size, hdr_size;
+ int y_data_size, u_data_size, v_data_size, a_data_size;
+ int y_linesize, u_linesize, v_linesize, a_linesize;
+ int coff[4];
+ int ret;
+
+ buf = ctx->slice_data[slice_num].index;
+ slice_data_size = ctx->slice_data[slice_num + 1].index - buf;
+
+ slice_width_factor = av_log2(mbs_per_slice);
+
+ y_data = pic->data[0];
+ u_data = pic->data[1];
+ v_data = pic->data[2];
+ a_data = pic->data[3];
+ y_linesize = pic->linesize[0];
+ u_linesize = pic->linesize[1];
+ v_linesize = pic->linesize[2];
+ a_linesize = pic->linesize[3];
+
+ if (pic->interlaced_frame) {
+ if (!(pic_num ^ pic->top_field_first)) {
+ y_data += y_linesize;
+ u_data += u_linesize;
+ v_data += v_linesize;
+ if (a_data)
+ a_data += a_linesize;
+ }
+ y_linesize <<= 1;
+ u_linesize <<= 1;
+ v_linesize <<= 1;
+ a_linesize <<= 1;
+ }
+ y_data += (mb_y_pos << 4) * y_linesize + (mb_x_pos << 5);
+ u_data += (mb_y_pos << 4) * u_linesize + (mb_x_pos << ctx->mb_chroma_factor);
+ v_data += (mb_y_pos << 4) * v_linesize + (mb_x_pos << ctx->mb_chroma_factor);
+ if (a_data)
+ a_data += (mb_y_pos << 4) * a_linesize + (mb_x_pos << 5);
+
+ if (slice_data_size < 6) {
+ av_log(avctx, AV_LOG_ERROR, "slice data too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* parse slice header */
+ hdr_size = buf[0] >> 3;
+ coff[0] = hdr_size;
+ y_data_size = AV_RB16(buf + 2);
+ coff[1] = coff[0] + y_data_size;
+ u_data_size = AV_RB16(buf + 4);
+ coff[2] = coff[1] + u_data_size;
+ v_data_size = hdr_size > 7 ? AV_RB16(buf + 6) : slice_data_size - coff[2];
+ coff[3] = coff[2] + v_data_size;
+ a_data_size = ctx->alpha_info ? slice_data_size - coff[3] : 0;
+
+ /* if V or alpha component size is negative that means that previous
+ component sizes are too large */
+ if (v_data_size < 0 || a_data_size < 0 || hdr_size < 6) {
+ av_log(avctx, AV_LOG_ERROR, "invalid data size\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ sf = av_clip(buf[1], 1, 224);
+ sf = sf > 128 ? (sf - 96) << 2 : sf;
+
+ /* scale quantization matrixes according with slice's scale factor */
+ /* TODO: this can be SIMD-optimized a lot */
+ if (ctx->qmat_changed || sf != td->prev_slice_sf) {
+ td->prev_slice_sf = sf;
+ for (i = 0; i < 64; i++) {
+ td->qmat_luma_scaled[ctx->dsp.idct_permutation[i]] = ctx->qmat_luma[i] * sf;
+ td->qmat_chroma_scaled[ctx->dsp.idct_permutation[i]] = ctx->qmat_chroma[i] * sf;
+ }
+ }
+
+ /* decode luma plane */
+ ret = decode_slice_plane(ctx, td, buf + coff[0], y_data_size,
+ (uint16_t*) y_data, y_linesize,
+ mbs_per_slice, 4, slice_width_factor + 2,
+ td->qmat_luma_scaled, 0);
+
+ if (ret < 0)
+ return ret;
+
+ /* decode U chroma plane */
+ ret = decode_slice_plane(ctx, td, buf + coff[1], u_data_size,
+ (uint16_t*) u_data, u_linesize,
+ mbs_per_slice, ctx->num_chroma_blocks,
+ slice_width_factor + ctx->chroma_factor - 1,
+ td->qmat_chroma_scaled, 1);
+ if (ret < 0)
+ return ret;
+
+ /* decode V chroma plane */
+ ret = decode_slice_plane(ctx, td, buf + coff[2], v_data_size,
+ (uint16_t*) v_data, v_linesize,
+ mbs_per_slice, ctx->num_chroma_blocks,
+ slice_width_factor + ctx->chroma_factor - 1,
+ td->qmat_chroma_scaled, 1);
+ if (ret < 0)
+ return ret;
+
+ /* decode alpha plane if available */
+ if (a_data && a_data_size)
+ decode_alpha_plane(ctx, td, buf + coff[3], a_data_size,
+ (uint16_t*) a_data, a_linesize,
+ mbs_per_slice);
+
+ return 0;
+}
+
+
+static int decode_picture(ProresContext *ctx, int pic_num,
+ AVCodecContext *avctx)
+{
+ int slice_num, slice_width, x_pos, y_pos;
+
+ slice_num = 0;
+
+ ctx->pic_num = pic_num;
+ for (y_pos = 0; y_pos < ctx->num_y_mbs; y_pos++) {
+ slice_width = 1 << ctx->slice_width_factor;
+
+ for (x_pos = 0; x_pos < ctx->num_x_mbs && slice_width;
+ x_pos += slice_width) {
+ while (ctx->num_x_mbs - x_pos < slice_width)
+ slice_width >>= 1;
+
+ ctx->slice_data[slice_num].slice_num = slice_num;
+ ctx->slice_data[slice_num].x_pos = x_pos;
+ ctx->slice_data[slice_num].y_pos = y_pos;
+ ctx->slice_data[slice_num].slice_width = slice_width;
+
+ slice_num++;
+ }
+ }
+
+ return avctx->execute(avctx, decode_slice,
+ ctx->slice_data, NULL, slice_num,
+ sizeof(ctx->slice_data[0]));
+}
+
+
+#define MOVE_DATA_PTR(nbytes) buf += (nbytes); buf_size -= (nbytes)
+
+static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ ProresContext *ctx = avctx->priv_data;
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ int frame_hdr_size, pic_num, pic_data_size;
+
+ ctx->frame = data;
+ ctx->frame->pict_type = AV_PICTURE_TYPE_I;
+ ctx->frame->key_frame = 1;
+
+ /* check frame atom container */
+ if (buf_size < 28 || buf_size < AV_RB32(buf) ||
+ AV_RB32(buf + 4) != FRAME_ID) {
+ av_log(avctx, AV_LOG_ERROR, "invalid frame\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ MOVE_DATA_PTR(8);
+
+ frame_hdr_size = decode_frame_header(ctx, buf, buf_size, avctx);
+ if (frame_hdr_size < 0)
+ return AVERROR_INVALIDDATA;
+
+ MOVE_DATA_PTR(frame_hdr_size);
+
+ if (ff_get_buffer(avctx, ctx->frame, 0) < 0)
+ return -1;
+
+ for (pic_num = 0; ctx->frame->interlaced_frame - pic_num + 1; pic_num++) {
+ pic_data_size = decode_picture_header(ctx, buf, buf_size, avctx);
+ if (pic_data_size < 0)
+ return AVERROR_INVALIDDATA;
+
+ if (decode_picture(ctx, pic_num, avctx))
+ return -1;
+
+ MOVE_DATA_PTR(pic_data_size);
+ }
+
+ ctx->frame = NULL;
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+
+static av_cold int decode_close(AVCodecContext *avctx)
+{
+ ProresContext *ctx = avctx->priv_data;
+
+ av_freep(&ctx->slice_data);
+
+ return 0;
+}
+
+
+AVCodec ff_prores_lgpl_decoder = {
+ .name = "prores_lgpl",
+ .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_PRORES,
+ .priv_data_size = sizeof(ProresContext),
+ .init = decode_init,
+ .close = decode_close,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_SLICE_THREADS,
+};
diff --git a/libavcodec/proresdsp.c b/libavcodec/proresdsp.c
index 1c0f391..4ff219e 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
*/
@@ -33,7 +33,7 @@
#define CLIP_AND_BIAS(x) (av_clip((x) + BIAS, CLIP_MIN, CLIP_MAX))
-#if CONFIG_PRORES_DECODER
+#if CONFIG_PRORES_DECODER | CONFIG_PRORES_LGPL_DECODER
/**
* Add bias value, clamp and output pixels of a slice
*/
@@ -57,7 +57,7 @@ static void prores_idct_put_c(uint16_t *out, int linesize, int16_t *block, const
}
#endif
-#if CONFIG_PRORES_ENCODER
+#if CONFIG_PRORES_KS_ENCODER
static void prores_fdct_c(const uint16_t *src, int linesize, int16_t *block)
{
int x, y;
@@ -72,18 +72,18 @@ static void prores_fdct_c(const uint16_t *src, int linesize, int16_t *block)
}
#endif
-av_cold void ff_proresdsp_init(ProresDSPContext *dsp)
+av_cold void ff_proresdsp_init(ProresDSPContext *dsp, AVCodecContext *avctx)
{
-#if CONFIG_PRORES_DECODER
+#if CONFIG_PRORES_DECODER | CONFIG_PRORES_LGPL_DECODER
dsp->idct_put = prores_idct_put_c;
dsp->idct_permutation_type = FF_NO_IDCT_PERM;
- if (ARCH_X86) ff_proresdsp_x86_init(dsp);
+ if (ARCH_X86) ff_proresdsp_x86_init(dsp, avctx);
ff_init_scantable_permutation(dsp->idct_permutation,
dsp->idct_permutation_type);
#endif
-#if CONFIG_PRORES_ENCODER
+#if CONFIG_PRORES_KS_ENCODER
dsp->fdct = prores_fdct_c;
dsp->dct_permutation_type = FF_NO_IDCT_PERM;
ff_init_scantable_permutation(dsp->dct_permutation,
diff --git a/libavcodec/proresdsp.h b/libavcodec/proresdsp.h
index 5e35140..706162a 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 "dsputil.h"
#define PRORES_BITS_PER_SAMPLE 10 ///< output precision of prores decoder
@@ -36,8 +37,8 @@ typedef struct ProresDSPContext {
void (* fdct) (const uint16_t *src, int linesize, int16_t *block);
} ProresDSPContext;
-void ff_proresdsp_init(ProresDSPContext *dsp);
+void ff_proresdsp_init(ProresDSPContext *dsp, AVCodecContext *avctx);
-void ff_proresdsp_x86_init(ProresDSPContext *dsp);
+void ff_proresdsp_x86_init(ProresDSPContext *dsp, AVCodecContext *avctx);
#endif /* AVCODEC_PRORESDSP_H */
diff --git a/libavcodec/proresenc.c b/libavcodec/proresenc.c
deleted file mode 100644
index 758b8e3..0000000
--- a/libavcodec/proresenc.c
+++ b/dev/null
@@ -1,1278 +0,0 @@
-/*
- * Apple ProRes encoder
- *
- * Copyright (c) 2012 Konstantin Shishkov
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "libavutil/opt.h"
-#include "libavutil/pixdesc.h"
-#include "avcodec.h"
-#include "dsputil.h"
-#include "put_bits.h"
-#include "bytestream.h"
-#include "internal.h"
-#include "proresdsp.h"
-#include "proresdata.h"
-
-#define CFACTOR_Y422 2
-#define CFACTOR_Y444 3
-
-#define MAX_MBS_PER_SLICE 8
-
-#define MAX_PLANES 4
-
-enum {
- PRORES_PROFILE_PROXY = 0,
- PRORES_PROFILE_LT,
- PRORES_PROFILE_STANDARD,
- PRORES_PROFILE_HQ,
- PRORES_PROFILE_4444,
-};
-
-enum {
- QUANT_MAT_PROXY = 0,
- QUANT_MAT_LT,
- QUANT_MAT_STANDARD,
- QUANT_MAT_HQ,
- QUANT_MAT_DEFAULT,
-};
-
-static const uint8_t prores_quant_matrices[][64] = {
- { // proxy
- 4, 7, 9, 11, 13, 14, 15, 63,
- 7, 7, 11, 12, 14, 15, 63, 63,
- 9, 11, 13, 14, 15, 63, 63, 63,
- 11, 11, 13, 14, 63, 63, 63, 63,
- 11, 13, 14, 63, 63, 63, 63, 63,
- 13, 14, 63, 63, 63, 63, 63, 63,
- 13, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- },
- { // LT
- 4, 5, 6, 7, 9, 11, 13, 15,
- 5, 5, 7, 8, 11, 13, 15, 17,
- 6, 7, 9, 11, 13, 15, 15, 17,
- 7, 7, 9, 11, 13, 15, 17, 19,
- 7, 9, 11, 13, 14, 16, 19, 23,
- 9, 11, 13, 14, 16, 19, 23, 29,
- 9, 11, 13, 15, 17, 21, 28, 35,
- 11, 13, 16, 17, 21, 28, 35, 41,
- },
- { // standard
- 4, 4, 5, 5, 6, 7, 7, 9,
- 4, 4, 5, 6, 7, 7, 9, 9,
- 5, 5, 6, 7, 7, 9, 9, 10,
- 5, 5, 6, 7, 7, 9, 9, 10,
- 5, 6, 7, 7, 8, 9, 10, 12,
- 6, 7, 7, 8, 9, 10, 12, 15,
- 6, 7, 7, 9, 10, 11, 14, 17,
- 7, 7, 9, 10, 11, 14, 17, 21,
- },
- { // high quality
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 5,
- 4, 4, 4, 4, 4, 4, 5, 5,
- 4, 4, 4, 4, 4, 5, 5, 6,
- 4, 4, 4, 4, 5, 5, 6, 7,
- 4, 4, 4, 4, 5, 6, 7, 7,
- },
- { // codec default
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- },
-};
-
-#define NUM_MB_LIMITS 4
-static const int prores_mb_limits[NUM_MB_LIMITS] = {
- 1620, // up to 720x576
- 2700, // up to 960x720
- 6075, // up to 1440x1080
- 9216, // up to 2048x1152
-};
-
-static const struct prores_profile {
- const char *full_name;
- uint32_t tag;
- int min_quant;
- int max_quant;
- int br_tab[NUM_MB_LIMITS];
- int quant;
-} prores_profile_info[5] = {
- {
- .full_name = "proxy",
- .tag = MKTAG('a', 'p', 'c', 'o'),
- .min_quant = 4,
- .max_quant = 8,
- .br_tab = { 300, 242, 220, 194 },
- .quant = QUANT_MAT_PROXY,
- },
- {
- .full_name = "LT",
- .tag = MKTAG('a', 'p', 'c', 's'),
- .min_quant = 1,
- .max_quant = 9,
- .br_tab = { 720, 560, 490, 440 },
- .quant = QUANT_MAT_LT,
- },
- {
- .full_name = "standard",
- .tag = MKTAG('a', 'p', 'c', 'n'),
- .min_quant = 1,
- .max_quant = 6,
- .br_tab = { 1050, 808, 710, 632 },
- .quant = QUANT_MAT_STANDARD,
- },
- {
- .full_name = "high quality",
- .tag = MKTAG('a', 'p', 'c', 'h'),
- .min_quant = 1,
- .max_quant = 6,
- .br_tab = { 1566, 1216, 1070, 950 },
- .quant = QUANT_MAT_HQ,
- },
- {
- .full_name = "4444",
- .tag = MKTAG('a', 'p', '4', 'h'),
- .min_quant = 1,
- .max_quant = 6,
- .br_tab = { 2350, 1828, 1600, 1425 },
- .quant = QUANT_MAT_HQ,
- }
-};
-
-#define TRELLIS_WIDTH 16
-#define SCORE_LIMIT INT_MAX / 2
-
-struct TrellisNode {
- int prev_node;
- int quant;
- int bits;
- int score;
-};
-
-#define MAX_STORED_Q 16
-
-typedef struct ProresThreadData {
- DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE];
- DECLARE_ALIGNED(16, uint16_t, emu_buf)[16 * 16];
- int16_t custom_q[64];
- struct TrellisNode *nodes;
-} ProresThreadData;
-
-typedef struct ProresContext {
- AVClass *class;
- DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE];
- DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16];
- int16_t quants[MAX_STORED_Q][64];
- int16_t custom_q[64];
- const uint8_t *quant_mat;
-
- ProresDSPContext dsp;
- ScanTable scantable;
-
- int mb_width, mb_height;
- int mbs_per_slice;
- int num_chroma_blocks, chroma_factor;
- int slices_width;
- int slices_per_picture;
- int pictures_per_frame; // 1 for progressive, 2 for interlaced
- int cur_picture_idx;
- int num_planes;
- int bits_per_mb;
- int force_quant;
- int alpha_bits;
-
- char *vendor;
- int quant_sel;
-
- int frame_size_upper_bound;
-
- int profile;
- const struct prores_profile *profile_info;
-
- int *slice_q;
-
- ProresThreadData *tdata;
-} ProresContext;
-
-static void get_slice_data(ProresContext *ctx, const uint16_t *src,
- int linesize, int x, int y, int w, int h,
- int16_t *blocks, uint16_t *emu_buf,
- int mbs_per_slice, int blocks_per_mb, int is_chroma)
-{
- const uint16_t *esrc;
- const int mb_width = 4 * blocks_per_mb;
- int elinesize;
- int i, j, k;
-
- for (i = 0; i < mbs_per_slice; i++, src += mb_width) {
- if (x >= w) {
- memset(blocks, 0, 64 * (mbs_per_slice - i) * blocks_per_mb
- * sizeof(*blocks));
- return;
- }
- if (x + mb_width <= w && y + 16 <= h) {
- esrc = src;
- elinesize = linesize;
- } else {
- int bw, bh, pix;
-
- esrc = emu_buf;
- elinesize = 16 * sizeof(*emu_buf);
-
- bw = FFMIN(w - x, mb_width);
- bh = FFMIN(h - y, 16);
-
- for (j = 0; j < bh; j++) {
- memcpy(emu_buf + j * 16,
- (const uint8_t*)src + j * linesize,
- bw * sizeof(*src));
- pix = emu_buf[j * 16 + bw - 1];
- for (k = bw; k < mb_width; k++)
- emu_buf[j * 16 + k] = pix;
- }
- for (; j < 16; j++)
- memcpy(emu_buf + j * 16,
- emu_buf + (bh - 1) * 16,
- mb_width * sizeof(*emu_buf));
- }
- if (!is_chroma) {
- ctx->dsp.fdct(esrc, elinesize, blocks);
- blocks += 64;
- if (blocks_per_mb > 2) {
- ctx->dsp.fdct(esrc + 8, elinesize, blocks);
- blocks += 64;
- }
- ctx->dsp.fdct(esrc + elinesize * 4, elinesize, blocks);
- blocks += 64;
- if (blocks_per_mb > 2) {
- ctx->dsp.fdct(esrc + elinesize * 4 + 8, elinesize, blocks);
- blocks += 64;
- }
- } else {
- ctx->dsp.fdct(esrc, elinesize, blocks);
- blocks += 64;
- ctx->dsp.fdct(esrc + elinesize * 4, elinesize, blocks);
- blocks += 64;
- if (blocks_per_mb > 2) {
- ctx->dsp.fdct(esrc + 8, elinesize, blocks);
- blocks += 64;
- ctx->dsp.fdct(esrc + elinesize * 4 + 8, elinesize, blocks);
- blocks += 64;
- }
- }
-
- x += mb_width;
- }
-}
-
-static void get_alpha_data(ProresContext *ctx, const uint16_t *src,
- int linesize, int x, int y, int w, int h,
- int16_t *blocks, int mbs_per_slice, int abits)
-{
- const int slice_width = 16 * mbs_per_slice;
- int i, j, copy_w, copy_h;
-
- copy_w = FFMIN(w - x, slice_width);
- copy_h = FFMIN(h - y, 16);
- for (i = 0; i < copy_h; i++) {
- memcpy(blocks, src, copy_w * sizeof(*src));
- if (abits == 8)
- for (j = 0; j < copy_w; j++)
- blocks[j] >>= 2;
- else
- for (j = 0; j < copy_w; j++)
- blocks[j] = (blocks[j] << 6) | (blocks[j] >> 4);
- for (j = copy_w; j < slice_width; j++)
- blocks[j] = blocks[copy_w - 1];
- blocks += slice_width;
- src += linesize >> 1;
- }
- for (; i < 16; i++) {
- memcpy(blocks, blocks - slice_width, slice_width * sizeof(*blocks));
- blocks += slice_width;
- }
-}
-
-/**
- * Write an unsigned rice/exp golomb codeword.
- */
-static inline void encode_vlc_codeword(PutBitContext *pb, unsigned codebook, int val)
-{
- unsigned int rice_order, exp_order, switch_bits, switch_val;
- int exponent;
-
- /* number of prefix bits to switch between Rice and expGolomb */
- switch_bits = (codebook & 3) + 1;
- rice_order = codebook >> 5; /* rice code order */
- exp_order = (codebook >> 2) & 7; /* exp golomb code order */
-
- switch_val = switch_bits << rice_order;
-
- if (val >= switch_val) {
- val -= switch_val - (1 << exp_order);
- exponent = av_log2(val);
-
- put_bits(pb, exponent - exp_order + switch_bits, 0);
- put_bits(pb, exponent + 1, val);
- } else {
- exponent = val >> rice_order;
-
- if (exponent)
- put_bits(pb, exponent, 0);
- put_bits(pb, 1, 1);
- if (rice_order)
- put_sbits(pb, rice_order, val);
- }
-}
-
-#define GET_SIGN(x) ((x) >> 31)
-#define MAKE_CODE(x) (((x) << 1) ^ GET_SIGN(x))
-
-static void encode_dcs(PutBitContext *pb, int16_t *blocks,
- int blocks_per_slice, int scale)
-{
- int i;
- int codebook = 3, code, dc, prev_dc, delta, sign, new_sign;
-
- prev_dc = (blocks[0] - 0x4000) / scale;
- encode_vlc_codeword(pb, FIRST_DC_CB, MAKE_CODE(prev_dc));
- sign = 0;
- codebook = 3;
- blocks += 64;
-
- for (i = 1; i < blocks_per_slice; i++, blocks += 64) {
- dc = (blocks[0] - 0x4000) / scale;
- delta = dc - prev_dc;
- new_sign = GET_SIGN(delta);
- delta = (delta ^ sign) - sign;
- code = MAKE_CODE(delta);
- encode_vlc_codeword(pb, ff_prores_dc_codebook[codebook], code);
- codebook = (code + (code & 1)) >> 1;
- codebook = FFMIN(codebook, 3);
- sign = new_sign;
- prev_dc = dc;
- }
-}
-
-static void encode_acs(PutBitContext *pb, int16_t *blocks,
- int blocks_per_slice,
- int plane_size_factor,
- const uint8_t *scan, const int16_t *qmat)
-{
- int idx, i;
- int run, level, run_cb, lev_cb;
- int max_coeffs, abs_level;
-
- max_coeffs = blocks_per_slice << 6;
- run_cb = ff_prores_run_to_cb_index[4];
- lev_cb = ff_prores_lev_to_cb_index[2];
- run = 0;
-
- for (i = 1; i < 64; i++) {
- for (idx = scan[i]; idx < max_coeffs; idx += 64) {
- level = blocks[idx] / qmat[scan[i]];
- if (level) {
- abs_level = FFABS(level);
- encode_vlc_codeword(pb, ff_prores_ac_codebook[run_cb], run);
- encode_vlc_codeword(pb, ff_prores_ac_codebook[lev_cb],
- abs_level - 1);
- put_sbits(pb, 1, GET_SIGN(level));
-
- run_cb = ff_prores_run_to_cb_index[FFMIN(run, 15)];
- lev_cb = ff_prores_lev_to_cb_index[FFMIN(abs_level, 9)];
- run = 0;
- } else {
- run++;
- }
- }
- }
-}
-
-static int encode_slice_plane(ProresContext *ctx, PutBitContext *pb,
- const uint16_t *src, int linesize,
- int mbs_per_slice, int16_t *blocks,
- int blocks_per_mb, int plane_size_factor,
- const int16_t *qmat)
-{
- int blocks_per_slice, saved_pos;
-
- saved_pos = put_bits_count(pb);
- blocks_per_slice = mbs_per_slice * blocks_per_mb;
-
- encode_dcs(pb, blocks, blocks_per_slice, qmat[0]);
- encode_acs(pb, blocks, blocks_per_slice, plane_size_factor,
- ctx->scantable.permutated, qmat);
- flush_put_bits(pb);
-
- return (put_bits_count(pb) - saved_pos) >> 3;
-}
-
-static void put_alpha_diff(PutBitContext *pb, int cur, int prev, int abits)
-{
- const int mask = (1 << abits) - 1;
- const int dbits = (abits == 8) ? 4 : 7;
- const int dsize = 1 << dbits - 1;
- int diff = cur - prev;
-
- diff &= mask;
- if (diff >= (1 << abits) - dsize)
- diff -= 1 << abits;
- if (diff < -dsize || diff > dsize || !diff) {
- put_bits(pb, 1, 1);
- put_bits(pb, abits, diff);
- } else {
- put_bits(pb, 1, 0);
- put_bits(pb, dbits - 1, FFABS(diff) - 1);
- put_bits(pb, 1, diff < 0);
- }
-}
-
-static void put_alpha_run(PutBitContext *pb, int run)
-{
- if (run) {
- put_bits(pb, 1, 0);
- if (run < 0x10)
- put_bits(pb, 4, run);
- else
- put_bits(pb, 15, run);
- } else {
- put_bits(pb, 1, 1);
- }
-}
-
-// todo alpha quantisation for high quants
-static int encode_alpha_plane(ProresContext *ctx, PutBitContext *pb,
- const uint16_t *src, int linesize,
- int mbs_per_slice, uint16_t *blocks,
- int quant)
-{
- const int abits = ctx->alpha_bits;
- const int mask = (1 << abits) - 1;
- const int num_coeffs = mbs_per_slice * 256;
- int saved_pos = put_bits_count(pb);
- int prev = mask, cur;
- int idx = 0;
- int run = 0;
-
- cur = blocks[idx++];
- put_alpha_diff(pb, cur, prev, abits);
- prev = cur;
- do {
- cur = blocks[idx++];
- if (cur != prev) {
- put_alpha_run (pb, run);
- put_alpha_diff(pb, cur, prev, abits);
- prev = cur;
- run = 0;
- } else {
- run++;
- }
- } while (idx < num_coeffs);
- if (run)
- put_alpha_run(pb, run);
- flush_put_bits(pb);
- return (put_bits_count(pb) - saved_pos) >> 3;
-}
-
-static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
- PutBitContext *pb,
- int sizes[4], int x, int y, int quant,
- int mbs_per_slice)
-{
- ProresContext *ctx = avctx->priv_data;
- int i, xp, yp;
- int total_size = 0;
- const uint16_t *src;
- int slice_width_factor = av_log2(mbs_per_slice);
- int num_cblocks, pwidth, linesize, line_add;
- int plane_factor, is_chroma;
- uint16_t *qmat;
-
- if (ctx->pictures_per_frame == 1)
- line_add = 0;
- else
- line_add = ctx->cur_picture_idx ^ !pic->top_field_first;
-
- if (ctx->force_quant) {
- qmat = ctx->quants[0];
- } else if (quant < MAX_STORED_Q) {
- qmat = ctx->quants[quant];
- } else {
- qmat = ctx->custom_q;
- for (i = 0; i < 64; i++)
- qmat[i] = ctx->quant_mat[i] * quant;
- }
-
- for (i = 0; i < ctx->num_planes; i++) {
- is_chroma = (i == 1 || i == 2);
- plane_factor = slice_width_factor + 2;
- if (is_chroma)
- plane_factor += ctx->chroma_factor - 3;
- if (!is_chroma || ctx->chroma_factor == CFACTOR_Y444) {
- xp = x << 4;
- yp = y << 4;
- num_cblocks = 4;
- pwidth = avctx->width;
- } else {
- xp = x << 3;
- yp = y << 4;
- num_cblocks = 2;
- pwidth = avctx->width >> 1;
- }
-
- linesize = pic->linesize[i] * ctx->pictures_per_frame;
- src = (const uint16_t*)(pic->data[i] + yp * linesize +
- line_add * pic->linesize[i]) + xp;
-
- if (i < 3) {
- get_slice_data(ctx, src, linesize, xp, yp,
- pwidth, avctx->height / ctx->pictures_per_frame,
- ctx->blocks[0], ctx->emu_buf,
- mbs_per_slice, num_cblocks, is_chroma);
- sizes[i] = encode_slice_plane(ctx, pb, src, linesize,
- mbs_per_slice, ctx->blocks[0],
- num_cblocks, plane_factor,
- qmat);
- } else {
- get_alpha_data(ctx, src, linesize, xp, yp,
- pwidth, avctx->height / ctx->pictures_per_frame,
- ctx->blocks[0], mbs_per_slice, ctx->alpha_bits);
- sizes[i] = encode_alpha_plane(ctx, pb, src, linesize,
- mbs_per_slice, ctx->blocks[0],
- quant);
- }
- total_size += sizes[i];
- }
- return total_size;
-}
-
-static inline int estimate_vlc(unsigned codebook, int val)
-{
- unsigned int rice_order, exp_order, switch_bits, switch_val;
- int exponent;
-
- /* number of prefix bits to switch between Rice and expGolomb */
- switch_bits = (codebook & 3) + 1;
- rice_order = codebook >> 5; /* rice code order */
- exp_order = (codebook >> 2) & 7; /* exp golomb code order */
-
- switch_val = switch_bits << rice_order;
-
- if (val >= switch_val) {
- val -= switch_val - (1 << exp_order);
- exponent = av_log2(val);
-
- return exponent * 2 - exp_order + switch_bits + 1;
- } else {
- return (val >> rice_order) + rice_order + 1;
- }
-}
-
-static int estimate_dcs(int *error, int16_t *blocks, int blocks_per_slice,
- int scale)
-{
- int i;
- int codebook = 3, code, dc, prev_dc, delta, sign, new_sign;
- int bits;
-
- prev_dc = (blocks[0] - 0x4000) / scale;
- bits = estimate_vlc(FIRST_DC_CB, MAKE_CODE(prev_dc));
- sign = 0;
- codebook = 3;
- blocks += 64;
- *error += FFABS(blocks[0] - 0x4000) % scale;
-
- for (i = 1; i < blocks_per_slice; i++, blocks += 64) {
- dc = (blocks[0] - 0x4000) / scale;
- *error += FFABS(blocks[0] - 0x4000) % scale;
- delta = dc - prev_dc;
- new_sign = GET_SIGN(delta);
- delta = (delta ^ sign) - sign;
- code = MAKE_CODE(delta);
- bits += estimate_vlc(ff_prores_dc_codebook[codebook], code);
- codebook = (code + (code & 1)) >> 1;
- codebook = FFMIN(codebook, 3);
- sign = new_sign;
- prev_dc = dc;
- }
-
- return bits;
-}
-
-static int estimate_acs(int *error, int16_t *blocks, int blocks_per_slice,
- int plane_size_factor,
- const uint8_t *scan, const int16_t *qmat)
-{
- int idx, i;
- int run, level, run_cb, lev_cb;
- int max_coeffs, abs_level;
- int bits = 0;
-
- max_coeffs = blocks_per_slice << 6;
- run_cb = ff_prores_run_to_cb_index[4];
- lev_cb = ff_prores_lev_to_cb_index[2];
- run = 0;
-
- for (i = 1; i < 64; i++) {
- for (idx = scan[i]; idx < max_coeffs; idx += 64) {
- level = blocks[idx] / qmat[scan[i]];
- *error += FFABS(blocks[idx]) % qmat[scan[i]];
- if (level) {
- abs_level = FFABS(level);
- bits += estimate_vlc(ff_prores_ac_codebook[run_cb], run);
- bits += estimate_vlc(ff_prores_ac_codebook[lev_cb],
- abs_level - 1) + 1;
-
- run_cb = ff_prores_run_to_cb_index[FFMIN(run, 15)];
- lev_cb = ff_prores_lev_to_cb_index[FFMIN(abs_level, 9)];
- run = 0;
- } else {
- run++;
- }
- }
- }
-
- return bits;
-}
-
-static int estimate_slice_plane(ProresContext *ctx, int *error, int plane,
- const uint16_t *src, int linesize,
- int mbs_per_slice,
- int blocks_per_mb, int plane_size_factor,
- const int16_t *qmat, ProresThreadData *td)
-{
- int blocks_per_slice;
- int bits;
-
- blocks_per_slice = mbs_per_slice * blocks_per_mb;
-
- bits = estimate_dcs(error, td->blocks[plane], blocks_per_slice, qmat[0]);
- bits += estimate_acs(error, td->blocks[plane], blocks_per_slice,
- plane_size_factor, ctx->scantable.permutated, qmat);
-
- return FFALIGN(bits, 8);
-}
-
-static int est_alpha_diff(int cur, int prev, int abits)
-{
- const int mask = (1 << abits) - 1;
- const int dbits = (abits == 8) ? 4 : 7;
- const int dsize = 1 << dbits - 1;
- int diff = cur - prev;
-
- diff &= mask;
- if (diff >= (1 << abits) - dsize)
- diff -= 1 << abits;
- if (diff < -dsize || diff > dsize || !diff)
- return abits + 1;
- else
- return dbits + 1;
-}
-
-static int estimate_alpha_plane(ProresContext *ctx, int *error,
- const uint16_t *src, int linesize,
- int mbs_per_slice, int quant,
- int16_t *blocks)
-{
- const int abits = ctx->alpha_bits;
- const int mask = (1 << abits) - 1;
- const int num_coeffs = mbs_per_slice * 256;
- int prev = mask, cur;
- int idx = 0;
- int run = 0;
- int bits;
-
- *error = 0;
- cur = blocks[idx++];
- bits = est_alpha_diff(cur, prev, abits);
- prev = cur;
- do {
- cur = blocks[idx++];
- if (cur != prev) {
- if (!run)
- bits++;
- else if (run < 0x10)
- bits += 4;
- else
- bits += 15;
- bits += est_alpha_diff(cur, prev, abits);
- prev = cur;
- run = 0;
- } else {
- run++;
- }
- } while (idx < num_coeffs);
-
- if (run) {
- if (run < 0x10)
- bits += 4;
- else
- bits += 15;
- }
-
- return bits;
-}
-
-static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
- int trellis_node, int x, int y, int mbs_per_slice,
- ProresThreadData *td)
-{
- ProresContext *ctx = avctx->priv_data;
- int i, q, pq, xp, yp;
- const uint16_t *src;
- int slice_width_factor = av_log2(mbs_per_slice);
- int num_cblocks[MAX_PLANES], pwidth;
- int plane_factor[MAX_PLANES], is_chroma[MAX_PLANES];
- const int min_quant = ctx->profile_info->min_quant;
- const int max_quant = ctx->profile_info->max_quant;
- int error, bits, bits_limit;
- int mbs, prev, cur, new_score;
- int slice_bits[TRELLIS_WIDTH], slice_score[TRELLIS_WIDTH];
- int overquant;
- uint16_t *qmat;
- int linesize[4], line_add;
-
- if (ctx->pictures_per_frame == 1)
- line_add = 0;
- else
- line_add = ctx->cur_picture_idx ^ !pic->top_field_first;
- mbs = x + mbs_per_slice;
-
- for (i = 0; i < ctx->num_planes; i++) {
- is_chroma[i] = (i == 1 || i == 2);
- plane_factor[i] = slice_width_factor + 2;
- if (is_chroma[i])
- plane_factor[i] += ctx->chroma_factor - 3;
- if (!is_chroma[i] || ctx->chroma_factor == CFACTOR_Y444) {
- xp = x << 4;
- yp = y << 4;
- num_cblocks[i] = 4;
- pwidth = avctx->width;
- } else {
- xp = x << 3;
- yp = y << 4;
- num_cblocks[i] = 2;
- pwidth = avctx->width >> 1;
- }
-
- linesize[i] = pic->linesize[i] * ctx->pictures_per_frame;
- src = (const uint16_t*)(pic->data[i] + yp * linesize[i] +
- line_add * pic->linesize[i]) + xp;
-
- if (i < 3) {
- get_slice_data(ctx, src, linesize[i], xp, yp,
- pwidth, avctx->height / ctx->pictures_per_frame,
- td->blocks[i], td->emu_buf,
- mbs_per_slice, num_cblocks[i], is_chroma[i]);
- } else {
- get_alpha_data(ctx, src, linesize[i], xp, yp,
- pwidth, avctx->height / ctx->pictures_per_frame,
- td->blocks[i], mbs_per_slice, ctx->alpha_bits);
- }
- }
-
- for (q = min_quant; q < max_quant + 2; q++) {
- td->nodes[trellis_node + q].prev_node = -1;
- td->nodes[trellis_node + q].quant = q;
- }
-
- // todo: maybe perform coarser quantising to fit into frame size when needed
- for (q = min_quant; q <= max_quant; q++) {
- bits = 0;
- error = 0;
- for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
- bits += estimate_slice_plane(ctx, &error, i,
- src, linesize[i],
- mbs_per_slice,
- num_cblocks[i], plane_factor[i],
- ctx->quants[q], td);
- }
- if (ctx->alpha_bits)
- bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
- mbs_per_slice, q, td->blocks[3]);
- if (bits > 65000 * 8) {
- error = SCORE_LIMIT;
- break;
- }
- slice_bits[q] = bits;
- slice_score[q] = error;
- }
- if (slice_bits[max_quant] <= ctx->bits_per_mb * mbs_per_slice) {
- slice_bits[max_quant + 1] = slice_bits[max_quant];
- slice_score[max_quant + 1] = slice_score[max_quant] + 1;
- overquant = max_quant;
- } else {
- for (q = max_quant + 1; q < 128; q++) {
- bits = 0;
- error = 0;
- if (q < MAX_STORED_Q) {
- qmat = ctx->quants[q];
- } else {
- qmat = td->custom_q;
- for (i = 0; i < 64; i++)
- qmat[i] = ctx->quant_mat[i] * q;
- }
- for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
- bits += estimate_slice_plane(ctx, &error, i,
- src, linesize[i],
- mbs_per_slice,
- num_cblocks[i], plane_factor[i],
- qmat, td);
- }
- if (ctx->alpha_bits)
- bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
- mbs_per_slice, q, td->blocks[3]);
- if (bits <= ctx->bits_per_mb * mbs_per_slice)
- break;
- }
-
- slice_bits[max_quant + 1] = bits;
- slice_score[max_quant + 1] = error;
- overquant = q;
- }
- td->nodes[trellis_node + max_quant + 1].quant = overquant;
-
- bits_limit = mbs * ctx->bits_per_mb;
- for (pq = min_quant; pq < max_quant + 2; pq++) {
- prev = trellis_node - TRELLIS_WIDTH + pq;
-
- for (q = min_quant; q < max_quant + 2; q++) {
- cur = trellis_node + q;
-
- bits = td->nodes[prev].bits + slice_bits[q];
- error = slice_score[q];
- if (bits > bits_limit)
- error = SCORE_LIMIT;
-
- if (td->nodes[prev].score < SCORE_LIMIT && error < SCORE_LIMIT)
- new_score = td->nodes[prev].score + error;
- else
- new_score = SCORE_LIMIT;
- if (td->nodes[cur].prev_node == -1 ||
- td->nodes[cur].score >= new_score) {
-
- td->nodes[cur].bits = bits;
- td->nodes[cur].score = new_score;
- td->nodes[cur].prev_node = prev;
- }
- }
- }
-
- error = td->nodes[trellis_node + min_quant].score;
- pq = trellis_node + min_quant;
- for (q = min_quant + 1; q < max_quant + 2; q++) {
- if (td->nodes[trellis_node + q].score <= error) {
- error = td->nodes[trellis_node + q].score;
- pq = trellis_node + q;
- }
- }
-
- return pq;
-}
-
-static int find_quant_thread(AVCodecContext *avctx, void *arg,
- int jobnr, int threadnr)
-{
- ProresContext *ctx = avctx->priv_data;
- ProresThreadData *td = ctx->tdata + threadnr;
- int mbs_per_slice = ctx->mbs_per_slice;
- int x, y = jobnr, mb, q = 0;
-
- for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) {
- while (ctx->mb_width - x < mbs_per_slice)
- mbs_per_slice >>= 1;
- q = find_slice_quant(avctx, avctx->coded_frame,
- (mb + 1) * TRELLIS_WIDTH, x, y,
- mbs_per_slice, td);
- }
-
- for (x = ctx->slices_width - 1; x >= 0; x--) {
- ctx->slice_q[x + y * ctx->slices_width] = td->nodes[q].quant;
- q = td->nodes[q].prev_node;
- }
-
- return 0;
-}
-
-static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *pic, int *got_packet)
-{
- ProresContext *ctx = avctx->priv_data;
- uint8_t *orig_buf, *buf, *slice_hdr, *slice_sizes, *tmp;
- uint8_t *picture_size_pos;
- PutBitContext pb;
- int x, y, i, mb, q = 0;
- int sizes[4] = { 0 };
- int slice_hdr_size = 2 + 2 * (ctx->num_planes - 1);
- int frame_size, picture_size, slice_size;
- int pkt_size, ret;
- uint8_t frame_flags;
-
- *avctx->coded_frame = *pic;
- avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
- avctx->coded_frame->key_frame = 1;
-
- pkt_size = ctx->frame_size_upper_bound + FF_MIN_BUFFER_SIZE;
-
- if ((ret = ff_alloc_packet(pkt, pkt_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
- return ret;
- }
-
- orig_buf = pkt->data;
-
- // frame atom
- orig_buf += 4; // frame size
- bytestream_put_be32 (&orig_buf, FRAME_ID); // frame container ID
- buf = orig_buf;
-
- // frame header
- tmp = buf;
- buf += 2; // frame header size will be stored here
- bytestream_put_be16 (&buf, 0); // version 1
- bytestream_put_buffer(&buf, ctx->vendor, 4);
- bytestream_put_be16 (&buf, avctx->width);
- bytestream_put_be16 (&buf, avctx->height);
-
- frame_flags = ctx->chroma_factor << 6;
- if (avctx->flags & CODEC_FLAG_INTERLACED_DCT)
- frame_flags |= pic->top_field_first ? 0x04 : 0x08;
- bytestream_put_byte (&buf, frame_flags);
-
- bytestream_put_byte (&buf, 0); // reserved
- bytestream_put_byte (&buf, avctx->color_primaries);
- bytestream_put_byte (&buf, avctx->color_trc);
- bytestream_put_byte (&buf, avctx->colorspace);
- bytestream_put_byte (&buf, 0x40 | (ctx->alpha_bits >> 3));
- bytestream_put_byte (&buf, 0); // reserved
- if (ctx->quant_sel != QUANT_MAT_DEFAULT) {
- bytestream_put_byte (&buf, 0x03); // matrix flags - both matrices are present
- // luma quantisation matrix
- for (i = 0; i < 64; i++)
- bytestream_put_byte(&buf, ctx->quant_mat[i]);
- // chroma quantisation matrix
- for (i = 0; i < 64; i++)
- bytestream_put_byte(&buf, ctx->quant_mat[i]);
- } else {
- bytestream_put_byte (&buf, 0x00); // matrix flags - default matrices are used
- }
- bytestream_put_be16 (&tmp, buf - orig_buf); // write back frame header size
-
- for (ctx->cur_picture_idx = 0;
- ctx->cur_picture_idx < ctx->pictures_per_frame;
- ctx->cur_picture_idx++) {
- // picture header
- picture_size_pos = buf + 1;
- bytestream_put_byte (&buf, 0x40); // picture header size (in bits)
- buf += 4; // picture data size will be stored here
- bytestream_put_be16 (&buf, ctx->slices_per_picture);
- bytestream_put_byte (&buf, av_log2(ctx->mbs_per_slice) << 4); // slice width and height in MBs
-
- // seek table - will be filled during slice encoding
- slice_sizes = buf;
- buf += ctx->slices_per_picture * 2;
-
- // slices
- if (!ctx->force_quant) {
- ret = avctx->execute2(avctx, find_quant_thread, NULL, NULL,
- ctx->mb_height);
- if (ret)
- return ret;
- }
-
- for (y = 0; y < ctx->mb_height; y++) {
- int mbs_per_slice = ctx->mbs_per_slice;
- for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) {
- q = ctx->force_quant ? ctx->force_quant
- : ctx->slice_q[mb + y * ctx->slices_width];
-
- while (ctx->mb_width - x < mbs_per_slice)
- mbs_per_slice >>= 1;
-
- bytestream_put_byte(&buf, slice_hdr_size << 3);
- slice_hdr = buf;
- buf += slice_hdr_size - 1;
- init_put_bits(&pb, buf, (pkt_size - (buf - orig_buf)) * 8);
- encode_slice(avctx, pic, &pb, sizes, x, y, q, mbs_per_slice);
-
- bytestream_put_byte(&slice_hdr, q);
- slice_size = slice_hdr_size + sizes[ctx->num_planes - 1];
- for (i = 0; i < ctx->num_planes - 1; i++) {
- bytestream_put_be16(&slice_hdr, sizes[i]);
- slice_size += sizes[i];
- }
- bytestream_put_be16(&slice_sizes, slice_size);
- buf += slice_size - slice_hdr_size;
- }
- }
-
- if (ctx->pictures_per_frame == 1)
- picture_size = buf - picture_size_pos - 6;
- else
- picture_size = buf - picture_size_pos + 1;
- bytestream_put_be32(&picture_size_pos, picture_size);
- }
-
- orig_buf -= 8;
- frame_size = buf - orig_buf;
- bytestream_put_be32(&orig_buf, frame_size);
-
- pkt->size = frame_size;
- pkt->flags |= AV_PKT_FLAG_KEY;
- *got_packet = 1;
-
- return 0;
-}
-
-static av_cold int encode_close(AVCodecContext *avctx)
-{
- ProresContext *ctx = avctx->priv_data;
- int i;
-
- av_freep(&avctx->coded_frame);
-
- if (ctx->tdata) {
- for (i = 0; i < avctx->thread_count; i++)
- av_free(ctx->tdata[i].nodes);
- }
- av_freep(&ctx->tdata);
- av_freep(&ctx->slice_q);
-
- return 0;
-}
-
-static av_cold int encode_init(AVCodecContext *avctx)
-{
- ProresContext *ctx = avctx->priv_data;
- int mps;
- int i, j;
- int min_quant, max_quant;
- int interlaced = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT);
-
- avctx->bits_per_raw_sample = 10;
- avctx->coded_frame = avcodec_alloc_frame();
- if (!avctx->coded_frame)
- return AVERROR(ENOMEM);
-
- ff_proresdsp_init(&ctx->dsp);
- ff_init_scantable(ctx->dsp.dct_permutation, &ctx->scantable,
- interlaced ? ff_prores_interlaced_scan
- : ff_prores_progressive_scan);
-
- mps = ctx->mbs_per_slice;
- if (mps & (mps - 1)) {
- av_log(avctx, AV_LOG_ERROR,
- "there should be an integer power of two MBs per slice\n");
- return AVERROR(EINVAL);
- }
- if (av_pix_fmt_desc_get(avctx->pix_fmt)->flags & AV_PIX_FMT_FLAG_ALPHA) {
- if (ctx->alpha_bits & 7) {
- av_log(avctx, AV_LOG_ERROR, "alpha bits should be 0, 8 or 16\n");
- return AVERROR(EINVAL);
- }
- } else {
- ctx->alpha_bits = 0;
- }
-
- ctx->chroma_factor = avctx->pix_fmt == AV_PIX_FMT_YUV422P10
- ? CFACTOR_Y422
- : CFACTOR_Y444;
- ctx->profile_info = prores_profile_info + ctx->profile;
- ctx->num_planes = 3 + !!ctx->alpha_bits;
-
- ctx->mb_width = FFALIGN(avctx->width, 16) >> 4;
-
- if (interlaced)
- ctx->mb_height = FFALIGN(avctx->height, 32) >> 5;
- else
- ctx->mb_height = FFALIGN(avctx->height, 16) >> 4;
-
- ctx->slices_width = ctx->mb_width / mps;
- ctx->slices_width += av_popcount(ctx->mb_width - ctx->slices_width * mps);
- ctx->slices_per_picture = ctx->mb_height * ctx->slices_width;
- ctx->pictures_per_frame = 1 + interlaced;
-
- if (ctx->quant_sel == -1)
- ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant];
- else
- ctx->quant_mat = prores_quant_matrices[ctx->quant_sel];
-
- if (strlen(ctx->vendor) != 4) {
- av_log(avctx, AV_LOG_ERROR, "vendor ID should be 4 bytes\n");
- return AVERROR_INVALIDDATA;
- }
-
- ctx->force_quant = avctx->global_quality / FF_QP2LAMBDA;
- if (!ctx->force_quant) {
- if (!ctx->bits_per_mb) {
- for (i = 0; i < NUM_MB_LIMITS - 1; i++)
- if (prores_mb_limits[i] >= ctx->mb_width * ctx->mb_height *
- ctx->pictures_per_frame)
- break;
- ctx->bits_per_mb = ctx->profile_info->br_tab[i];
- } else if (ctx->bits_per_mb < 128) {
- av_log(avctx, AV_LOG_ERROR, "too few bits per MB, please set at least 128\n");
- return AVERROR_INVALIDDATA;
- }
-
- min_quant = ctx->profile_info->min_quant;
- max_quant = ctx->profile_info->max_quant;
- for (i = min_quant; i < MAX_STORED_Q; i++) {
- for (j = 0; j < 64; j++)
- ctx->quants[i][j] = ctx->quant_mat[j] * i;
- }
-
- ctx->slice_q = av_malloc(ctx->slices_per_picture * sizeof(*ctx->slice_q));
- if (!ctx->slice_q) {
- encode_close(avctx);
- return AVERROR(ENOMEM);
- }
-
- ctx->tdata = av_mallocz(avctx->thread_count * sizeof(*ctx->tdata));
- if (!ctx->tdata) {
- encode_close(avctx);
- return AVERROR(ENOMEM);
- }
-
- for (j = 0; j < avctx->thread_count; j++) {
- ctx->tdata[j].nodes = av_malloc((ctx->slices_width + 1)
- * TRELLIS_WIDTH
- * sizeof(*ctx->tdata->nodes));
- if (!ctx->tdata[j].nodes) {
- encode_close(avctx);
- return AVERROR(ENOMEM);
- }
- for (i = min_quant; i < max_quant + 2; i++) {
- ctx->tdata[j].nodes[i].prev_node = -1;
- ctx->tdata[j].nodes[i].bits = 0;
- ctx->tdata[j].nodes[i].score = 0;
- }
- }
- } else {
- int ls = 0;
-
- if (ctx->force_quant > 64) {
- av_log(avctx, AV_LOG_ERROR, "too large quantiser, maximum is 64\n");
- return AVERROR_INVALIDDATA;
- }
-
- for (j = 0; j < 64; j++) {
- ctx->quants[0][j] = ctx->quant_mat[j] * ctx->force_quant;
- ls += av_log2((1 << 11) / ctx->quants[0][j]) * 2 + 1;
- }
-
- ctx->bits_per_mb = ls * 8;
- if (ctx->chroma_factor == CFACTOR_Y444)
- ctx->bits_per_mb += ls * 4;
- if (ctx->num_planes == 4)
- ctx->bits_per_mb += ls * 4;
- }
-
- ctx->frame_size_upper_bound = ctx->pictures_per_frame *
- ctx->slices_per_picture *
- (2 + 2 * ctx->num_planes +
- (mps * ctx->bits_per_mb) / 8)
- + 200;
-
- avctx->codec_tag = ctx->profile_info->tag;
-
- av_log(avctx, AV_LOG_DEBUG,
- "profile %d, %d slices, interlacing: %s, %d bits per MB\n",
- ctx->profile, ctx->slices_per_picture * ctx->pictures_per_frame,
- interlaced ? "yes" : "no", ctx->bits_per_mb);
- av_log(avctx, AV_LOG_DEBUG, "frame size upper bound: %d\n",
- ctx->frame_size_upper_bound);
-
- return 0;
-}
-
-#define OFFSET(x) offsetof(ProresContext, x)
-#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
-
-static const AVOption options[] = {
- { "mbs_per_slice", "macroblocks per slice", OFFSET(mbs_per_slice),
- AV_OPT_TYPE_INT, { .i64 = 8 }, 1, MAX_MBS_PER_SLICE, VE },
- { "profile", NULL, OFFSET(profile), AV_OPT_TYPE_INT,
- { .i64 = PRORES_PROFILE_STANDARD },
- PRORES_PROFILE_PROXY, PRORES_PROFILE_4444, VE, "profile" },
- { "proxy", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_PROXY },
- 0, 0, VE, "profile" },
- { "lt", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_LT },
- 0, 0, VE, "profile" },
- { "standard", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_STANDARD },
- 0, 0, VE, "profile" },
- { "hq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_HQ },
- 0, 0, VE, "profile" },
- { "4444", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_4444 },
- 0, 0, VE, "profile" },
- { "vendor", "vendor ID", OFFSET(vendor),
- AV_OPT_TYPE_STRING, { .str = "Lavc" }, CHAR_MIN, CHAR_MAX, VE },
- { "bits_per_mb", "desired bits per macroblock", OFFSET(bits_per_mb),
- AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 8192, VE },
- { "quant_mat", "quantiser matrix", OFFSET(quant_sel), AV_OPT_TYPE_INT,
- { .i64 = -1 }, -1, QUANT_MAT_DEFAULT, VE, "quant_mat" },
- { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = -1 },
- 0, 0, VE, "quant_mat" },
- { "proxy", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_PROXY },
- 0, 0, VE, "quant_mat" },
- { "lt", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_LT },
- 0, 0, VE, "quant_mat" },
- { "standard", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_STANDARD },
- 0, 0, VE, "quant_mat" },
- { "hq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_HQ },
- 0, 0, VE, "quant_mat" },
- { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_DEFAULT },
- 0, 0, VE, "quant_mat" },
- { "alpha_bits", "bits for alpha plane", OFFSET(alpha_bits), AV_OPT_TYPE_INT,
- { .i64 = 16 }, 0, 16, VE },
- { NULL }
-};
-
-static const AVClass proresenc_class = {
- .class_name = "ProRes encoder",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-AVCodec ff_prores_encoder = {
- .name = "prores",
- .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"),
- .type = AVMEDIA_TYPE_VIDEO,
- .id = AV_CODEC_ID_PRORES,
- .priv_data_size = sizeof(ProresContext),
- .init = encode_init,
- .close = encode_close,
- .encode2 = encode_frame,
- .capabilities = CODEC_CAP_SLICE_THREADS,
- .pix_fmts = (const enum AVPixelFormat[]) {
- AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
- AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE
- },
- .priv_class = &proresenc_class,
-};
diff --git a/libavcodec/proresenc_anatoliy.c b/libavcodec/proresenc_anatoliy.c
new file mode 100644
index 0000000..e124b41
--- a/dev/null
+++ b/libavcodec/proresenc_anatoliy.c
@@ -0,0 +1,626 @@
+/*
+ * 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 "dsputil.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 {
+ 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)
+{
+ int16_t *p = (int16_t*)pixels;
+ int i, j;
+
+ stride >>= 1;
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 8; j++) {
+ block[j] = p[j];
+ }
+ p += stride;
+ block += 8;
+ }
+}
+
+static void fdct_get(uint8_t *pixels, int stride, int16_t* block)
+{
+ get(pixels, stride, block);
+ ff_jpeg_fdct_islow_10(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)
+{
+ 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(src, src_stride, block + (0 << 6));
+ fdct_get(src + 8 * src_stride, src_stride, block + ((2 - chroma) << 6));
+ if (!chroma) {
+ fdct_get(src + 16, src_stride, block + (1 << 6));
+ fdct_get(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;
+ }
+ if (avctx->width & 0x1) {
+ av_log(avctx, AV_LOG_ERROR,
+ "frame width needs to be multiple of 2\n");
+ return -1;
+ }
+
+ 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;
+ }
+
+ 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 = avcodec_alloc_frame();
+ 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_kostya.c b/libavcodec/proresenc_kostya.c
new file mode 100644
index 0000000..510b408
--- a/dev/null
+++ b/libavcodec/proresenc_kostya.c
@@ -0,0 +1,1276 @@
+/*
+ * Apple ProRes encoder
+ *
+ * Copyright (c) 2012 Konstantin Shishkov
+ *
+ * This encoder appears to be based on Anatoliy Wassermans considering
+ * similarities in the bugs.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avcodec.h"
+#include "dsputil.h"
+#include "put_bits.h"
+#include "bytestream.h"
+#include "internal.h"
+#include "proresdsp.h"
+#include "proresdata.h"
+
+#define CFACTOR_Y422 2
+#define CFACTOR_Y444 3
+
+#define MAX_MBS_PER_SLICE 8
+
+#define MAX_PLANES 4
+
+enum {
+ PRORES_PROFILE_PROXY = 0,
+ PRORES_PROFILE_LT,
+ PRORES_PROFILE_STANDARD,
+ PRORES_PROFILE_HQ,
+ PRORES_PROFILE_4444,
+};
+
+enum {
+ QUANT_MAT_PROXY = 0,
+ QUANT_MAT_LT,
+ QUANT_MAT_STANDARD,
+ QUANT_MAT_HQ,
+ QUANT_MAT_DEFAULT,
+};
+
+static const uint8_t prores_quant_matrices[][64] = {
+ { // proxy
+ 4, 7, 9, 11, 13, 14, 15, 63,
+ 7, 7, 11, 12, 14, 15, 63, 63,
+ 9, 11, 13, 14, 15, 63, 63, 63,
+ 11, 11, 13, 14, 63, 63, 63, 63,
+ 11, 13, 14, 63, 63, 63, 63, 63,
+ 13, 14, 63, 63, 63, 63, 63, 63,
+ 13, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ },
+ { // LT
+ 4, 5, 6, 7, 9, 11, 13, 15,
+ 5, 5, 7, 8, 11, 13, 15, 17,
+ 6, 7, 9, 11, 13, 15, 15, 17,
+ 7, 7, 9, 11, 13, 15, 17, 19,
+ 7, 9, 11, 13, 14, 16, 19, 23,
+ 9, 11, 13, 14, 16, 19, 23, 29,
+ 9, 11, 13, 15, 17, 21, 28, 35,
+ 11, 13, 16, 17, 21, 28, 35, 41,
+ },
+ { // standard
+ 4, 4, 5, 5, 6, 7, 7, 9,
+ 4, 4, 5, 6, 7, 7, 9, 9,
+ 5, 5, 6, 7, 7, 9, 9, 10,
+ 5, 5, 6, 7, 7, 9, 9, 10,
+ 5, 6, 7, 7, 8, 9, 10, 12,
+ 6, 7, 7, 8, 9, 10, 12, 15,
+ 6, 7, 7, 9, 10, 11, 14, 17,
+ 7, 7, 9, 10, 11, 14, 17, 21,
+ },
+ { // high quality
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 5,
+ 4, 4, 4, 4, 4, 4, 5, 5,
+ 4, 4, 4, 4, 4, 5, 5, 6,
+ 4, 4, 4, 4, 5, 5, 6, 7,
+ 4, 4, 4, 4, 5, 6, 7, 7,
+ },
+ { // codec default
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ },
+};
+
+#define NUM_MB_LIMITS 4
+static const int prores_mb_limits[NUM_MB_LIMITS] = {
+ 1620, // up to 720x576
+ 2700, // up to 960x720
+ 6075, // up to 1440x1080
+ 9216, // up to 2048x1152
+};
+
+static const struct prores_profile {
+ const char *full_name;
+ uint32_t tag;
+ int min_quant;
+ int max_quant;
+ int br_tab[NUM_MB_LIMITS];
+ int quant;
+} prores_profile_info[5] = {
+ {
+ .full_name = "proxy",
+ .tag = MKTAG('a', 'p', 'c', 'o'),
+ .min_quant = 4,
+ .max_quant = 8,
+ .br_tab = { 300, 242, 220, 194 },
+ .quant = QUANT_MAT_PROXY,
+ },
+ {
+ .full_name = "LT",
+ .tag = MKTAG('a', 'p', 'c', 's'),
+ .min_quant = 1,
+ .max_quant = 9,
+ .br_tab = { 720, 560, 490, 440 },
+ .quant = QUANT_MAT_LT,
+ },
+ {
+ .full_name = "standard",
+ .tag = MKTAG('a', 'p', 'c', 'n'),
+ .min_quant = 1,
+ .max_quant = 6,
+ .br_tab = { 1050, 808, 710, 632 },
+ .quant = QUANT_MAT_STANDARD,
+ },
+ {
+ .full_name = "high quality",
+ .tag = MKTAG('a', 'p', 'c', 'h'),
+ .min_quant = 1,
+ .max_quant = 6,
+ .br_tab = { 1566, 1216, 1070, 950 },
+ .quant = QUANT_MAT_HQ,
+ },
+ {
+ .full_name = "4444",
+ .tag = MKTAG('a', 'p', '4', 'h'),
+ .min_quant = 1,
+ .max_quant = 6,
+ .br_tab = { 2350, 1828, 1600, 1425 },
+ .quant = QUANT_MAT_HQ,
+ }
+};
+
+#define TRELLIS_WIDTH 16
+#define SCORE_LIMIT INT_MAX / 2
+
+struct TrellisNode {
+ int prev_node;
+ int quant;
+ int bits;
+ int score;
+};
+
+#define MAX_STORED_Q 16
+
+typedef struct ProresThreadData {
+ DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE];
+ DECLARE_ALIGNED(16, uint16_t, emu_buf)[16 * 16];
+ int16_t custom_q[64];
+ struct TrellisNode *nodes;
+} ProresThreadData;
+
+typedef struct ProresContext {
+ AVClass *class;
+ DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE];
+ DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16];
+ int16_t quants[MAX_STORED_Q][64];
+ int16_t custom_q[64];
+ const uint8_t *quant_mat;
+
+ ProresDSPContext dsp;
+ ScanTable scantable;
+
+ int mb_width, mb_height;
+ int mbs_per_slice;
+ int num_chroma_blocks, chroma_factor;
+ int slices_width;
+ int slices_per_picture;
+ int pictures_per_frame; // 1 for progressive, 2 for interlaced
+ int cur_picture_idx;
+ int num_planes;
+ int bits_per_mb;
+ int force_quant;
+ int alpha_bits;
+
+ char *vendor;
+ int quant_sel;
+
+ int frame_size_upper_bound;
+
+ int profile;
+ const struct prores_profile *profile_info;
+
+ int *slice_q;
+
+ ProresThreadData *tdata;
+} ProresContext;
+
+static void get_slice_data(ProresContext *ctx, const uint16_t *src,
+ int linesize, int x, int y, int w, int h,
+ int16_t *blocks, uint16_t *emu_buf,
+ int mbs_per_slice, int blocks_per_mb, int is_chroma)
+{
+ const uint16_t *esrc;
+ const int mb_width = 4 * blocks_per_mb;
+ int elinesize;
+ int i, j, k;
+
+ for (i = 0; i < mbs_per_slice; i++, src += mb_width) {
+ if (x >= w) {
+ memset(blocks, 0, 64 * (mbs_per_slice - i) * blocks_per_mb
+ * sizeof(*blocks));
+ return;
+ }
+ if (x + mb_width <= w && y + 16 <= h) {
+ esrc = src;
+ elinesize = linesize;
+ } else {
+ int bw, bh, pix;
+
+ esrc = emu_buf;
+ elinesize = 16 * sizeof(*emu_buf);
+
+ bw = FFMIN(w - x, mb_width);
+ bh = FFMIN(h - y, 16);
+
+ for (j = 0; j < bh; j++) {
+ memcpy(emu_buf + j * 16,
+ (const uint8_t*)src + j * linesize,
+ bw * sizeof(*src));
+ pix = emu_buf[j * 16 + bw - 1];
+ for (k = bw; k < mb_width; k++)
+ emu_buf[j * 16 + k] = pix;
+ }
+ for (; j < 16; j++)
+ memcpy(emu_buf + j * 16,
+ emu_buf + (bh - 1) * 16,
+ mb_width * sizeof(*emu_buf));
+ }
+ if (!is_chroma) {
+ ctx->dsp.fdct(esrc, elinesize, blocks);
+ blocks += 64;
+ if (blocks_per_mb > 2) {
+ ctx->dsp.fdct(esrc + 8, elinesize, blocks);
+ blocks += 64;
+ }
+ ctx->dsp.fdct(esrc + elinesize * 4, elinesize, blocks);
+ blocks += 64;
+ if (blocks_per_mb > 2) {
+ ctx->dsp.fdct(esrc + elinesize * 4 + 8, elinesize, blocks);
+ blocks += 64;
+ }
+ } else {
+ ctx->dsp.fdct(esrc, elinesize, blocks);
+ blocks += 64;
+ ctx->dsp.fdct(esrc + elinesize * 4, elinesize, blocks);
+ blocks += 64;
+ if (blocks_per_mb > 2) {
+ ctx->dsp.fdct(esrc + 8, elinesize, blocks);
+ blocks += 64;
+ ctx->dsp.fdct(esrc + elinesize * 4 + 8, elinesize, blocks);
+ blocks += 64;
+ }
+ }
+
+ x += mb_width;
+ }
+}
+
+static void get_alpha_data(ProresContext *ctx, const uint16_t *src,
+ int linesize, int x, int y, int w, int h,
+ int16_t *blocks, int mbs_per_slice, int abits)
+{
+ const int slice_width = 16 * mbs_per_slice;
+ int i, j, copy_w, copy_h;
+
+ copy_w = FFMIN(w - x, slice_width);
+ copy_h = FFMIN(h - y, 16);
+ for (i = 0; i < copy_h; i++) {
+ memcpy(blocks, src, copy_w * sizeof(*src));
+ if (abits == 8)
+ for (j = 0; j < copy_w; j++)
+ blocks[j] >>= 2;
+ else
+ for (j = 0; j < copy_w; j++)
+ blocks[j] = (blocks[j] << 6) | (blocks[j] >> 4);
+ for (j = copy_w; j < slice_width; j++)
+ blocks[j] = blocks[copy_w - 1];
+ blocks += slice_width;
+ src += linesize >> 1;
+ }
+ for (; i < 16; i++) {
+ memcpy(blocks, blocks - slice_width, slice_width * sizeof(*blocks));
+ blocks += slice_width;
+ }
+}
+
+/**
+ * Write an unsigned rice/exp golomb codeword.
+ */
+static inline void encode_vlc_codeword(PutBitContext *pb, unsigned codebook, int val)
+{
+ unsigned int rice_order, exp_order, switch_bits, switch_val;
+ int exponent;
+
+ /* number of prefix bits to switch between Rice and expGolomb */
+ switch_bits = (codebook & 3) + 1;
+ rice_order = codebook >> 5; /* rice code order */
+ exp_order = (codebook >> 2) & 7; /* exp golomb code order */
+
+ switch_val = switch_bits << rice_order;
+
+ if (val >= switch_val) {
+ val -= switch_val - (1 << exp_order);
+ exponent = av_log2(val);
+
+ put_bits(pb, exponent - exp_order + switch_bits, 0);
+ put_bits(pb, exponent + 1, val);
+ } else {
+ exponent = val >> rice_order;
+
+ if (exponent)
+ put_bits(pb, exponent, 0);
+ put_bits(pb, 1, 1);
+ if (rice_order)
+ put_sbits(pb, rice_order, val);
+ }
+}
+
+#define GET_SIGN(x) ((x) >> 31)
+#define MAKE_CODE(x) (((x) << 1) ^ GET_SIGN(x))
+
+static void encode_dcs(PutBitContext *pb, int16_t *blocks,
+ int blocks_per_slice, int scale)
+{
+ int i;
+ int codebook = 3, code, dc, prev_dc, delta, sign, new_sign;
+
+ prev_dc = (blocks[0] - 0x4000) / scale;
+ encode_vlc_codeword(pb, FIRST_DC_CB, MAKE_CODE(prev_dc));
+ sign = 0;
+ codebook = 3;
+ blocks += 64;
+
+ for (i = 1; i < blocks_per_slice; i++, blocks += 64) {
+ dc = (blocks[0] - 0x4000) / scale;
+ delta = dc - prev_dc;
+ new_sign = GET_SIGN(delta);
+ delta = (delta ^ sign) - sign;
+ code = MAKE_CODE(delta);
+ encode_vlc_codeword(pb, ff_prores_dc_codebook[codebook], code);
+ codebook = (code + (code & 1)) >> 1;
+ codebook = FFMIN(codebook, 3);
+ sign = new_sign;
+ prev_dc = dc;
+ }
+}
+
+static void encode_acs(PutBitContext *pb, int16_t *blocks,
+ int blocks_per_slice,
+ int plane_size_factor,
+ const uint8_t *scan, const int16_t *qmat)
+{
+ int idx, i;
+ int run, level, run_cb, lev_cb;
+ int max_coeffs, abs_level;
+
+ max_coeffs = blocks_per_slice << 6;
+ run_cb = ff_prores_run_to_cb_index[4];
+ lev_cb = ff_prores_lev_to_cb_index[2];
+ run = 0;
+
+ for (i = 1; i < 64; i++) {
+ for (idx = scan[i]; idx < max_coeffs; idx += 64) {
+ level = blocks[idx] / qmat[scan[i]];
+ if (level) {
+ abs_level = FFABS(level);
+ encode_vlc_codeword(pb, ff_prores_ac_codebook[run_cb], run);
+ encode_vlc_codeword(pb, ff_prores_ac_codebook[lev_cb],
+ abs_level - 1);
+ put_sbits(pb, 1, GET_SIGN(level));
+
+ run_cb = ff_prores_run_to_cb_index[FFMIN(run, 15)];
+ lev_cb = ff_prores_lev_to_cb_index[FFMIN(abs_level, 9)];
+ run = 0;
+ } else {
+ run++;
+ }
+ }
+ }
+}
+
+static int encode_slice_plane(ProresContext *ctx, PutBitContext *pb,
+ const uint16_t *src, int linesize,
+ int mbs_per_slice, int16_t *blocks,
+ int blocks_per_mb, int plane_size_factor,
+ const int16_t *qmat)
+{
+ int blocks_per_slice, saved_pos;
+
+ saved_pos = put_bits_count(pb);
+ blocks_per_slice = mbs_per_slice * blocks_per_mb;
+
+ encode_dcs(pb, blocks, blocks_per_slice, qmat[0]);
+ encode_acs(pb, blocks, blocks_per_slice, plane_size_factor,
+ ctx->scantable.permutated, qmat);
+ flush_put_bits(pb);
+
+ return (put_bits_count(pb) - saved_pos) >> 3;
+}
+
+static void put_alpha_diff(PutBitContext *pb, int cur, int prev, int abits)
+{
+ const int mask = (1 << abits) - 1;
+ const int dbits = (abits == 8) ? 4 : 7;
+ const int dsize = 1 << dbits - 1;
+ int diff = cur - prev;
+
+ diff &= mask;
+ if (diff >= (1 << abits) - dsize)
+ diff -= 1 << abits;
+ if (diff < -dsize || diff > dsize || !diff) {
+ put_bits(pb, 1, 1);
+ put_bits(pb, abits, diff);
+ } else {
+ put_bits(pb, 1, 0);
+ put_bits(pb, dbits - 1, FFABS(diff) - 1);
+ put_bits(pb, 1, diff < 0);
+ }
+}
+
+static void put_alpha_run(PutBitContext *pb, int run)
+{
+ if (run) {
+ put_bits(pb, 1, 0);
+ if (run < 0x10)
+ put_bits(pb, 4, run);
+ else
+ put_bits(pb, 15, run);
+ } else {
+ put_bits(pb, 1, 1);
+ }
+}
+
+// todo alpha quantisation for high quants
+static int encode_alpha_plane(ProresContext *ctx, PutBitContext *pb,
+ const uint16_t *src, int linesize,
+ int mbs_per_slice, uint16_t *blocks,
+ int quant)
+{
+ const int abits = ctx->alpha_bits;
+ const int mask = (1 << abits) - 1;
+ const int num_coeffs = mbs_per_slice * 256;
+ int saved_pos = put_bits_count(pb);
+ int prev = mask, cur;
+ int idx = 0;
+ int run = 0;
+
+ cur = blocks[idx++];
+ put_alpha_diff(pb, cur, prev, abits);
+ prev = cur;
+ do {
+ cur = blocks[idx++];
+ if (cur != prev) {
+ put_alpha_run (pb, run);
+ put_alpha_diff(pb, cur, prev, abits);
+ prev = cur;
+ run = 0;
+ } else {
+ run++;
+ }
+ } while (idx < num_coeffs);
+ if (run)
+ put_alpha_run(pb, run);
+ flush_put_bits(pb);
+ return (put_bits_count(pb) - saved_pos) >> 3;
+}
+
+static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
+ PutBitContext *pb,
+ int sizes[4], int x, int y, int quant,
+ int mbs_per_slice)
+{
+ ProresContext *ctx = avctx->priv_data;
+ int i, xp, yp;
+ int total_size = 0;
+ const uint16_t *src;
+ int slice_width_factor = av_log2(mbs_per_slice);
+ int num_cblocks, pwidth, linesize, line_add;
+ int plane_factor, is_chroma;
+ uint16_t *qmat;
+
+ if (ctx->pictures_per_frame == 1)
+ line_add = 0;
+ else
+ line_add = ctx->cur_picture_idx ^ !pic->top_field_first;
+
+ if (ctx->force_quant) {
+ qmat = ctx->quants[0];
+ } else if (quant < MAX_STORED_Q) {
+ qmat = ctx->quants[quant];
+ } else {
+ qmat = ctx->custom_q;
+ for (i = 0; i < 64; i++)
+ qmat[i] = ctx->quant_mat[i] * quant;
+ }
+
+ for (i = 0; i < ctx->num_planes; i++) {
+ is_chroma = (i == 1 || i == 2);
+ plane_factor = slice_width_factor + 2;
+ if (is_chroma)
+ plane_factor += ctx->chroma_factor - 3;
+ if (!is_chroma || ctx->chroma_factor == CFACTOR_Y444) {
+ xp = x << 4;
+ yp = y << 4;
+ num_cblocks = 4;
+ pwidth = avctx->width;
+ } else {
+ xp = x << 3;
+ yp = y << 4;
+ num_cblocks = 2;
+ pwidth = avctx->width >> 1;
+ }
+
+ linesize = pic->linesize[i] * ctx->pictures_per_frame;
+ src = (const uint16_t*)(pic->data[i] + yp * linesize +
+ line_add * pic->linesize[i]) + xp;
+
+ if (i < 3) {
+ get_slice_data(ctx, src, linesize, xp, yp,
+ pwidth, avctx->height / ctx->pictures_per_frame,
+ ctx->blocks[0], ctx->emu_buf,
+ mbs_per_slice, num_cblocks, is_chroma);
+ sizes[i] = encode_slice_plane(ctx, pb, src, linesize,
+ mbs_per_slice, ctx->blocks[0],
+ num_cblocks, plane_factor,
+ qmat);
+ } else {
+ get_alpha_data(ctx, src, linesize, xp, yp,
+ pwidth, avctx->height / ctx->pictures_per_frame,
+ ctx->blocks[0], mbs_per_slice, ctx->alpha_bits);
+ sizes[i] = encode_alpha_plane(ctx, pb, src, linesize,
+ mbs_per_slice, ctx->blocks[0],
+ quant);
+ }
+ total_size += sizes[i];
+ }
+ return total_size;
+}
+
+static inline int estimate_vlc(unsigned codebook, int val)
+{
+ unsigned int rice_order, exp_order, switch_bits, switch_val;
+ int exponent;
+
+ /* number of prefix bits to switch between Rice and expGolomb */
+ switch_bits = (codebook & 3) + 1;
+ rice_order = codebook >> 5; /* rice code order */
+ exp_order = (codebook >> 2) & 7; /* exp golomb code order */
+
+ switch_val = switch_bits << rice_order;
+
+ if (val >= switch_val) {
+ val -= switch_val - (1 << exp_order);
+ exponent = av_log2(val);
+
+ return exponent * 2 - exp_order + switch_bits + 1;
+ } else {
+ return (val >> rice_order) + rice_order + 1;
+ }
+}
+
+static int estimate_dcs(int *error, int16_t *blocks, int blocks_per_slice,
+ int scale)
+{
+ int i;
+ int codebook = 3, code, dc, prev_dc, delta, sign, new_sign;
+ int bits;
+
+ prev_dc = (blocks[0] - 0x4000) / scale;
+ bits = estimate_vlc(FIRST_DC_CB, MAKE_CODE(prev_dc));
+ sign = 0;
+ codebook = 3;
+ blocks += 64;
+ *error += FFABS(blocks[0] - 0x4000) % scale;
+
+ for (i = 1; i < blocks_per_slice; i++, blocks += 64) {
+ dc = (blocks[0] - 0x4000) / scale;
+ *error += FFABS(blocks[0] - 0x4000) % scale;
+ delta = dc - prev_dc;
+ new_sign = GET_SIGN(delta);
+ delta = (delta ^ sign) - sign;
+ code = MAKE_CODE(delta);
+ bits += estimate_vlc(ff_prores_dc_codebook[codebook], code);
+ codebook = (code + (code & 1)) >> 1;
+ codebook = FFMIN(codebook, 3);
+ sign = new_sign;
+ prev_dc = dc;
+ }
+
+ return bits;
+}
+
+static int estimate_acs(int *error, int16_t *blocks, int blocks_per_slice,
+ int plane_size_factor,
+ const uint8_t *scan, const int16_t *qmat)
+{
+ int idx, i;
+ int run, level, run_cb, lev_cb;
+ int max_coeffs, abs_level;
+ int bits = 0;
+
+ max_coeffs = blocks_per_slice << 6;
+ run_cb = ff_prores_run_to_cb_index[4];
+ lev_cb = ff_prores_lev_to_cb_index[2];
+ run = 0;
+
+ for (i = 1; i < 64; i++) {
+ for (idx = scan[i]; idx < max_coeffs; idx += 64) {
+ level = blocks[idx] / qmat[scan[i]];
+ *error += FFABS(blocks[idx]) % qmat[scan[i]];
+ if (level) {
+ abs_level = FFABS(level);
+ bits += estimate_vlc(ff_prores_ac_codebook[run_cb], run);
+ bits += estimate_vlc(ff_prores_ac_codebook[lev_cb],
+ abs_level - 1) + 1;
+
+ run_cb = ff_prores_run_to_cb_index[FFMIN(run, 15)];
+ lev_cb = ff_prores_lev_to_cb_index[FFMIN(abs_level, 9)];
+ run = 0;
+ } else {
+ run++;
+ }
+ }
+ }
+
+ return bits;
+}
+
+static int estimate_slice_plane(ProresContext *ctx, int *error, int plane,
+ const uint16_t *src, int linesize,
+ int mbs_per_slice,
+ int blocks_per_mb, int plane_size_factor,
+ const int16_t *qmat, ProresThreadData *td)
+{
+ int blocks_per_slice;
+ int bits;
+
+ blocks_per_slice = mbs_per_slice * blocks_per_mb;
+
+ bits = estimate_dcs(error, td->blocks[plane], blocks_per_slice, qmat[0]);
+ bits += estimate_acs(error, td->blocks[plane], blocks_per_slice,
+ plane_size_factor, ctx->scantable.permutated, qmat);
+
+ return FFALIGN(bits, 8);
+}
+
+static int est_alpha_diff(int cur, int prev, int abits)
+{
+ const int mask = (1 << abits) - 1;
+ const int dbits = (abits == 8) ? 4 : 7;
+ const int dsize = 1 << dbits - 1;
+ int diff = cur - prev;
+
+ diff &= mask;
+ if (diff >= (1 << abits) - dsize)
+ diff -= 1 << abits;
+ if (diff < -dsize || diff > dsize || !diff)
+ return abits + 1;
+ else
+ return dbits + 1;
+}
+
+static int estimate_alpha_plane(ProresContext *ctx, int *error,
+ const uint16_t *src, int linesize,
+ int mbs_per_slice, int quant,
+ int16_t *blocks)
+{
+ const int abits = ctx->alpha_bits;
+ const int mask = (1 << abits) - 1;
+ const int num_coeffs = mbs_per_slice * 256;
+ int prev = mask, cur;
+ int idx = 0;
+ int run = 0;
+ int bits;
+
+ *error = 0;
+ cur = blocks[idx++];
+ bits = est_alpha_diff(cur, prev, abits);
+ prev = cur;
+ do {
+ cur = blocks[idx++];
+ if (cur != prev) {
+ if (!run)
+ bits++;
+ else if (run < 0x10)
+ bits += 4;
+ else
+ bits += 15;
+ bits += est_alpha_diff(cur, prev, abits);
+ prev = cur;
+ run = 0;
+ } else {
+ run++;
+ }
+ } while (idx < num_coeffs);
+
+ if (run) {
+ if (run < 0x10)
+ bits += 4;
+ else
+ bits += 15;
+ }
+
+ return bits;
+}
+
+static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
+ int trellis_node, int x, int y, int mbs_per_slice,
+ ProresThreadData *td)
+{
+ ProresContext *ctx = avctx->priv_data;
+ int i, q, pq, xp, yp;
+ const uint16_t *src;
+ int slice_width_factor = av_log2(mbs_per_slice);
+ int num_cblocks[MAX_PLANES], pwidth;
+ int plane_factor[MAX_PLANES], is_chroma[MAX_PLANES];
+ const int min_quant = ctx->profile_info->min_quant;
+ const int max_quant = ctx->profile_info->max_quant;
+ int error, bits, bits_limit;
+ int mbs, prev, cur, new_score;
+ int slice_bits[TRELLIS_WIDTH], slice_score[TRELLIS_WIDTH];
+ int overquant;
+ uint16_t *qmat;
+ int linesize[4], line_add;
+
+ if (ctx->pictures_per_frame == 1)
+ line_add = 0;
+ else
+ line_add = ctx->cur_picture_idx ^ !pic->top_field_first;
+ mbs = x + mbs_per_slice;
+
+ for (i = 0; i < ctx->num_planes; i++) {
+ is_chroma[i] = (i == 1 || i == 2);
+ plane_factor[i] = slice_width_factor + 2;
+ if (is_chroma[i])
+ plane_factor[i] += ctx->chroma_factor - 3;
+ if (!is_chroma[i] || ctx->chroma_factor == CFACTOR_Y444) {
+ xp = x << 4;
+ yp = y << 4;
+ num_cblocks[i] = 4;
+ pwidth = avctx->width;
+ } else {
+ xp = x << 3;
+ yp = y << 4;
+ num_cblocks[i] = 2;
+ pwidth = avctx->width >> 1;
+ }
+
+ linesize[i] = pic->linesize[i] * ctx->pictures_per_frame;
+ src = (const uint16_t*)(pic->data[i] + yp * linesize[i] +
+ line_add * pic->linesize[i]) + xp;
+
+ if (i < 3) {
+ get_slice_data(ctx, src, linesize[i], xp, yp,
+ pwidth, avctx->height / ctx->pictures_per_frame,
+ td->blocks[i], td->emu_buf,
+ mbs_per_slice, num_cblocks[i], is_chroma[i]);
+ } else {
+ get_alpha_data(ctx, src, linesize[i], xp, yp,
+ pwidth, avctx->height / ctx->pictures_per_frame,
+ td->blocks[i], mbs_per_slice, ctx->alpha_bits);
+ }
+ }
+
+ for (q = min_quant; q < max_quant + 2; q++) {
+ td->nodes[trellis_node + q].prev_node = -1;
+ td->nodes[trellis_node + q].quant = q;
+ }
+
+ // todo: maybe perform coarser quantising to fit into frame size when needed
+ for (q = min_quant; q <= max_quant; q++) {
+ bits = 0;
+ error = 0;
+ for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
+ bits += estimate_slice_plane(ctx, &error, i,
+ src, linesize[i],
+ mbs_per_slice,
+ num_cblocks[i], plane_factor[i],
+ ctx->quants[q], td);
+ }
+ if (ctx->alpha_bits)
+ bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
+ mbs_per_slice, q, td->blocks[3]);
+ if (bits > 65000 * 8) {
+ error = SCORE_LIMIT;
+ break;
+ }
+ slice_bits[q] = bits;
+ slice_score[q] = error;
+ }
+ if (slice_bits[max_quant] <= ctx->bits_per_mb * mbs_per_slice) {
+ slice_bits[max_quant + 1] = slice_bits[max_quant];
+ slice_score[max_quant + 1] = slice_score[max_quant] + 1;
+ overquant = max_quant;
+ } else {
+ for (q = max_quant + 1; q < 128; q++) {
+ bits = 0;
+ error = 0;
+ if (q < MAX_STORED_Q) {
+ qmat = ctx->quants[q];
+ } else {
+ qmat = td->custom_q;
+ for (i = 0; i < 64; i++)
+ qmat[i] = ctx->quant_mat[i] * q;
+ }
+ for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
+ bits += estimate_slice_plane(ctx, &error, i,
+ src, linesize[i],
+ mbs_per_slice,
+ num_cblocks[i], plane_factor[i],
+ qmat, td);
+ }
+ if (ctx->alpha_bits)
+ bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
+ mbs_per_slice, q, td->blocks[3]);
+ if (bits <= ctx->bits_per_mb * mbs_per_slice)
+ break;
+ }
+
+ slice_bits[max_quant + 1] = bits;
+ slice_score[max_quant + 1] = error;
+ overquant = q;
+ }
+ td->nodes[trellis_node + max_quant + 1].quant = overquant;
+
+ bits_limit = mbs * ctx->bits_per_mb;
+ for (pq = min_quant; pq < max_quant + 2; pq++) {
+ prev = trellis_node - TRELLIS_WIDTH + pq;
+
+ for (q = min_quant; q < max_quant + 2; q++) {
+ cur = trellis_node + q;
+
+ bits = td->nodes[prev].bits + slice_bits[q];
+ error = slice_score[q];
+ if (bits > bits_limit)
+ error = SCORE_LIMIT;
+
+ if (td->nodes[prev].score < SCORE_LIMIT && error < SCORE_LIMIT)
+ new_score = td->nodes[prev].score + error;
+ else
+ new_score = SCORE_LIMIT;
+ if (td->nodes[cur].prev_node == -1 ||
+ td->nodes[cur].score >= new_score) {
+
+ td->nodes[cur].bits = bits;
+ td->nodes[cur].score = new_score;
+ td->nodes[cur].prev_node = prev;
+ }
+ }
+ }
+
+ error = td->nodes[trellis_node + min_quant].score;
+ pq = trellis_node + min_quant;
+ for (q = min_quant + 1; q < max_quant + 2; q++) {
+ if (td->nodes[trellis_node + q].score <= error) {
+ error = td->nodes[trellis_node + q].score;
+ pq = trellis_node + q;
+ }
+ }
+
+ return pq;
+}
+
+static int find_quant_thread(AVCodecContext *avctx, void *arg,
+ int jobnr, int threadnr)
+{
+ ProresContext *ctx = avctx->priv_data;
+ ProresThreadData *td = ctx->tdata + threadnr;
+ int mbs_per_slice = ctx->mbs_per_slice;
+ int x, y = jobnr, mb, q = 0;
+
+ for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) {
+ while (ctx->mb_width - x < mbs_per_slice)
+ mbs_per_slice >>= 1;
+ q = find_slice_quant(avctx, avctx->coded_frame,
+ (mb + 1) * TRELLIS_WIDTH, x, y,
+ mbs_per_slice, td);
+ }
+
+ for (x = ctx->slices_width - 1; x >= 0; x--) {
+ ctx->slice_q[x + y * ctx->slices_width] = td->nodes[q].quant;
+ q = td->nodes[q].prev_node;
+ }
+
+ return 0;
+}
+
+static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pic, int *got_packet)
+{
+ ProresContext *ctx = avctx->priv_data;
+ uint8_t *orig_buf, *buf, *slice_hdr, *slice_sizes, *tmp;
+ uint8_t *picture_size_pos;
+ PutBitContext pb;
+ int x, y, i, mb, q = 0;
+ int sizes[4] = { 0 };
+ int slice_hdr_size = 2 + 2 * (ctx->num_planes - 1);
+ int frame_size, picture_size, slice_size;
+ int pkt_size, ret;
+ uint8_t frame_flags;
+
+ *avctx->coded_frame = *pic;
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+ avctx->coded_frame->key_frame = 1;
+
+ pkt_size = ctx->frame_size_upper_bound + FF_MIN_BUFFER_SIZE;
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, pkt_size)) < 0)
+ return ret;
+
+ orig_buf = pkt->data;
+
+ // frame atom
+ orig_buf += 4; // frame size
+ bytestream_put_be32 (&orig_buf, FRAME_ID); // frame container ID
+ buf = orig_buf;
+
+ // frame header
+ tmp = buf;
+ buf += 2; // frame header size will be stored here
+ bytestream_put_be16 (&buf, 0); // version 1
+ bytestream_put_buffer(&buf, ctx->vendor, 4);
+ bytestream_put_be16 (&buf, avctx->width);
+ bytestream_put_be16 (&buf, avctx->height);
+
+ frame_flags = ctx->chroma_factor << 6;
+ if (avctx->flags & CODEC_FLAG_INTERLACED_DCT)
+ frame_flags |= pic->top_field_first ? 0x04 : 0x08;
+ bytestream_put_byte (&buf, frame_flags);
+
+ bytestream_put_byte (&buf, 0); // reserved
+ bytestream_put_byte (&buf, avctx->color_primaries);
+ bytestream_put_byte (&buf, avctx->color_trc);
+ bytestream_put_byte (&buf, avctx->colorspace);
+ bytestream_put_byte (&buf, 0x40 | (ctx->alpha_bits >> 3));
+ bytestream_put_byte (&buf, 0); // reserved
+ if (ctx->quant_sel != QUANT_MAT_DEFAULT) {
+ bytestream_put_byte (&buf, 0x03); // matrix flags - both matrices are present
+ // luma quantisation matrix
+ for (i = 0; i < 64; i++)
+ bytestream_put_byte(&buf, ctx->quant_mat[i]);
+ // chroma quantisation matrix
+ for (i = 0; i < 64; i++)
+ bytestream_put_byte(&buf, ctx->quant_mat[i]);
+ } else {
+ bytestream_put_byte (&buf, 0x00); // matrix flags - default matrices are used
+ }
+ bytestream_put_be16 (&tmp, buf - orig_buf); // write back frame header size
+
+ for (ctx->cur_picture_idx = 0;
+ ctx->cur_picture_idx < ctx->pictures_per_frame;
+ ctx->cur_picture_idx++) {
+ // picture header
+ picture_size_pos = buf + 1;
+ bytestream_put_byte (&buf, 0x40); // picture header size (in bits)
+ buf += 4; // picture data size will be stored here
+ bytestream_put_be16 (&buf, ctx->slices_per_picture);
+ bytestream_put_byte (&buf, av_log2(ctx->mbs_per_slice) << 4); // slice width and height in MBs
+
+ // seek table - will be filled during slice encoding
+ slice_sizes = buf;
+ buf += ctx->slices_per_picture * 2;
+
+ // slices
+ if (!ctx->force_quant) {
+ ret = avctx->execute2(avctx, find_quant_thread, NULL, NULL,
+ ctx->mb_height);
+ if (ret)
+ return ret;
+ }
+
+ for (y = 0; y < ctx->mb_height; y++) {
+ int mbs_per_slice = ctx->mbs_per_slice;
+ for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) {
+ q = ctx->force_quant ? ctx->force_quant
+ : ctx->slice_q[mb + y * ctx->slices_width];
+
+ while (ctx->mb_width - x < mbs_per_slice)
+ mbs_per_slice >>= 1;
+
+ bytestream_put_byte(&buf, slice_hdr_size << 3);
+ slice_hdr = buf;
+ buf += slice_hdr_size - 1;
+ init_put_bits(&pb, buf, (pkt_size - (buf - orig_buf)) * 8);
+ encode_slice(avctx, pic, &pb, sizes, x, y, q, mbs_per_slice);
+
+ bytestream_put_byte(&slice_hdr, q);
+ slice_size = slice_hdr_size + sizes[ctx->num_planes - 1];
+ for (i = 0; i < ctx->num_planes - 1; i++) {
+ bytestream_put_be16(&slice_hdr, sizes[i]);
+ slice_size += sizes[i];
+ }
+ bytestream_put_be16(&slice_sizes, slice_size);
+ buf += slice_size - slice_hdr_size;
+ }
+ }
+
+ picture_size = buf - (picture_size_pos - 1);
+ bytestream_put_be32(&picture_size_pos, picture_size);
+ }
+
+ orig_buf -= 8;
+ frame_size = buf - orig_buf;
+ bytestream_put_be32(&orig_buf, frame_size);
+
+ pkt->size = frame_size;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+
+ return 0;
+}
+
+static av_cold int encode_close(AVCodecContext *avctx)
+{
+ ProresContext *ctx = avctx->priv_data;
+ int i;
+
+ av_freep(&avctx->coded_frame);
+
+ if (ctx->tdata) {
+ for (i = 0; i < avctx->thread_count; i++)
+ av_free(ctx->tdata[i].nodes);
+ }
+ av_freep(&ctx->tdata);
+ av_freep(&ctx->slice_q);
+
+ return 0;
+}
+
+static av_cold int encode_init(AVCodecContext *avctx)
+{
+ ProresContext *ctx = avctx->priv_data;
+ int mps;
+ int i, j;
+ int min_quant, max_quant;
+ int interlaced = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT);
+
+ avctx->bits_per_raw_sample = 10;
+ avctx->coded_frame = avcodec_alloc_frame();
+ if (!avctx->coded_frame)
+ return AVERROR(ENOMEM);
+
+ ff_proresdsp_init(&ctx->dsp, avctx);
+ ff_init_scantable(ctx->dsp.dct_permutation, &ctx->scantable,
+ interlaced ? ff_prores_interlaced_scan
+ : ff_prores_progressive_scan);
+
+ mps = ctx->mbs_per_slice;
+ if (mps & (mps - 1)) {
+ av_log(avctx, AV_LOG_ERROR,
+ "there should be an integer power of two MBs per slice\n");
+ return AVERROR(EINVAL);
+ }
+ if (av_pix_fmt_desc_get(avctx->pix_fmt)->flags & AV_PIX_FMT_FLAG_ALPHA) {
+ if (ctx->alpha_bits & 7) {
+ av_log(avctx, AV_LOG_ERROR, "alpha bits should be 0, 8 or 16\n");
+ return AVERROR(EINVAL);
+ }
+ } else {
+ ctx->alpha_bits = 0;
+ }
+
+ ctx->chroma_factor = avctx->pix_fmt == AV_PIX_FMT_YUV422P10
+ ? CFACTOR_Y422
+ : CFACTOR_Y444;
+ ctx->profile_info = prores_profile_info + ctx->profile;
+ ctx->num_planes = 3 + !!ctx->alpha_bits;
+
+ ctx->mb_width = FFALIGN(avctx->width, 16) >> 4;
+
+ if (interlaced)
+ ctx->mb_height = FFALIGN(avctx->height, 32) >> 5;
+ else
+ ctx->mb_height = FFALIGN(avctx->height, 16) >> 4;
+
+ ctx->slices_width = ctx->mb_width / mps;
+ ctx->slices_width += av_popcount(ctx->mb_width - ctx->slices_width * mps);
+ ctx->slices_per_picture = ctx->mb_height * ctx->slices_width;
+ ctx->pictures_per_frame = 1 + interlaced;
+
+ if (ctx->quant_sel == -1)
+ ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant];
+ else
+ ctx->quant_mat = prores_quant_matrices[ctx->quant_sel];
+
+ if (strlen(ctx->vendor) != 4) {
+ av_log(avctx, AV_LOG_ERROR, "vendor ID should be 4 bytes\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->force_quant = avctx->global_quality / FF_QP2LAMBDA;
+ if (!ctx->force_quant) {
+ if (!ctx->bits_per_mb) {
+ for (i = 0; i < NUM_MB_LIMITS - 1; i++)
+ if (prores_mb_limits[i] >= ctx->mb_width * ctx->mb_height *
+ ctx->pictures_per_frame)
+ break;
+ ctx->bits_per_mb = ctx->profile_info->br_tab[i];
+ } else if (ctx->bits_per_mb < 128) {
+ av_log(avctx, AV_LOG_ERROR, "too few bits per MB, please set at least 128\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ min_quant = ctx->profile_info->min_quant;
+ max_quant = ctx->profile_info->max_quant;
+ for (i = min_quant; i < MAX_STORED_Q; i++) {
+ for (j = 0; j < 64; j++)
+ ctx->quants[i][j] = ctx->quant_mat[j] * i;
+ }
+
+ ctx->slice_q = av_malloc(ctx->slices_per_picture * sizeof(*ctx->slice_q));
+ if (!ctx->slice_q) {
+ encode_close(avctx);
+ return AVERROR(ENOMEM);
+ }
+
+ ctx->tdata = av_mallocz(avctx->thread_count * sizeof(*ctx->tdata));
+ if (!ctx->tdata) {
+ encode_close(avctx);
+ return AVERROR(ENOMEM);
+ }
+
+ for (j = 0; j < avctx->thread_count; j++) {
+ ctx->tdata[j].nodes = av_malloc((ctx->slices_width + 1)
+ * TRELLIS_WIDTH
+ * sizeof(*ctx->tdata->nodes));
+ if (!ctx->tdata[j].nodes) {
+ encode_close(avctx);
+ return AVERROR(ENOMEM);
+ }
+ for (i = min_quant; i < max_quant + 2; i++) {
+ ctx->tdata[j].nodes[i].prev_node = -1;
+ ctx->tdata[j].nodes[i].bits = 0;
+ ctx->tdata[j].nodes[i].score = 0;
+ }
+ }
+ } else {
+ int ls = 0;
+
+ if (ctx->force_quant > 64) {
+ av_log(avctx, AV_LOG_ERROR, "too large quantiser, maximum is 64\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (j = 0; j < 64; j++) {
+ ctx->quants[0][j] = ctx->quant_mat[j] * ctx->force_quant;
+ ls += av_log2((1 << 11) / ctx->quants[0][j]) * 2 + 1;
+ }
+
+ ctx->bits_per_mb = ls * 8;
+ if (ctx->chroma_factor == CFACTOR_Y444)
+ ctx->bits_per_mb += ls * 4;
+ if (ctx->num_planes == 4)
+ ctx->bits_per_mb += ls * 4;
+ }
+
+ ctx->frame_size_upper_bound = ctx->pictures_per_frame *
+ ctx->slices_per_picture *
+ (2 + 2 * ctx->num_planes +
+ (mps * ctx->bits_per_mb) / 8)
+ + 200;
+
+ avctx->codec_tag = ctx->profile_info->tag;
+
+ av_log(avctx, AV_LOG_DEBUG,
+ "profile %d, %d slices, interlacing: %s, %d bits per MB\n",
+ ctx->profile, ctx->slices_per_picture * ctx->pictures_per_frame,
+ interlaced ? "yes" : "no", ctx->bits_per_mb);
+ av_log(avctx, AV_LOG_DEBUG, "frame size upper bound: %d\n",
+ ctx->frame_size_upper_bound);
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(ProresContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+
+static const AVOption options[] = {
+ { "mbs_per_slice", "macroblocks per slice", OFFSET(mbs_per_slice),
+ AV_OPT_TYPE_INT, { .i64 = 8 }, 1, MAX_MBS_PER_SLICE, VE },
+ { "profile", NULL, OFFSET(profile), AV_OPT_TYPE_INT,
+ { .i64 = PRORES_PROFILE_STANDARD },
+ PRORES_PROFILE_PROXY, PRORES_PROFILE_4444, VE, "profile" },
+ { "proxy", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_PROXY },
+ 0, 0, VE, "profile" },
+ { "lt", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_LT },
+ 0, 0, VE, "profile" },
+ { "standard", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_STANDARD },
+ 0, 0, VE, "profile" },
+ { "hq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_HQ },
+ 0, 0, VE, "profile" },
+ { "4444", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_4444 },
+ 0, 0, VE, "profile" },
+ { "vendor", "vendor ID", OFFSET(vendor),
+ AV_OPT_TYPE_STRING, { .str = "Lavc" }, CHAR_MIN, CHAR_MAX, VE },
+ { "bits_per_mb", "desired bits per macroblock", OFFSET(bits_per_mb),
+ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 8192, VE },
+ { "quant_mat", "quantiser matrix", OFFSET(quant_sel), AV_OPT_TYPE_INT,
+ { .i64 = -1 }, -1, QUANT_MAT_DEFAULT, VE, "quant_mat" },
+ { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = -1 },
+ 0, 0, VE, "quant_mat" },
+ { "proxy", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_PROXY },
+ 0, 0, VE, "quant_mat" },
+ { "lt", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_LT },
+ 0, 0, VE, "quant_mat" },
+ { "standard", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_STANDARD },
+ 0, 0, VE, "quant_mat" },
+ { "hq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_HQ },
+ 0, 0, VE, "quant_mat" },
+ { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_DEFAULT },
+ 0, 0, VE, "quant_mat" },
+ { "alpha_bits", "bits for alpha plane", OFFSET(alpha_bits), AV_OPT_TYPE_INT,
+ { .i64 = 16 }, 0, 16, VE },
+ { NULL }
+};
+
+static const AVClass proresenc_class = {
+ .class_name = "ProRes encoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_prores_ks_encoder = {
+ .name = "prores_ks",
+ .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_PRORES,
+ .priv_data_size = sizeof(ProresContext),
+ .init = encode_init,
+ .close = encode_close,
+ .encode2 = encode_frame,
+ .capabilities = CODEC_CAP_SLICE_THREADS,
+ .pix_fmts = (const enum AVPixelFormat[]) {
+ AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
+ AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE
+ },
+ .priv_class = &proresenc_class,
+};
diff --git a/libavcodec/psymodel.c b/libavcodec/psymodel.c
index a2af611..bfc85b3 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
*/
@@ -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,7 +104,10 @@ 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);
@@ -112,6 +116,9 @@ av_cold struct FFPsyPreprocessContext* ff_psy_preprocess_init(AVCodecContext *av
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,11 +126,12 @@ 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);
}
}
diff --git a/libavcodec/psymodel.h b/libavcodec/psymodel.h
index 1cc3066..d1a126a 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 b646f66..b8beac3 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
*/
@@ -43,6 +43,8 @@
#include <pthread.h>
#elif HAVE_W32THREADS
#include "compat/w32pthreads.h"
+#elif HAVE_OS2THREADS
+#include "compat/os2threads.h"
#endif
typedef int (action_func)(AVCodecContext *c, void *arg);
@@ -64,6 +66,12 @@ typedef struct ThreadContext {
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;
} ThreadContext;
/**
@@ -98,6 +106,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;
@@ -111,6 +123,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;
/**
@@ -249,7 +264,8 @@ static int thread_init_internal(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);
@@ -297,6 +313,9 @@ static int thread_init_internal(AVCodecContext *avctx)
return 0;
}
+#define THREAD_SAFE_CALLBACKS(avctx) \
+((avctx)->thread_safe_callbacks || (!(avctx)->get_buffer && (avctx)->get_buffer2 == avcodec_default_get_buffer2))
+
/**
* Codec worker thread.
*
@@ -311,20 +330,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);
avcodec_get_frame_defaults(&p->frame);
p->got_frame = 0;
p->result = codec->decode(avctx, &p->frame, &p->got_frame, &p->avpkt);
@@ -335,14 +350,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;
}
@@ -388,9 +410,15 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src,
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;
}
if (for_user) {
+ dst->delay = src->thread_count - 1;
dst->coded_frame = src->coded_frame;
} else {
if (dst->codec->update_thread_context)
@@ -432,6 +460,7 @@ 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) {
@@ -462,7 +491,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);
@@ -522,18 +552,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 = p->avctx->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);
}
@@ -570,9 +612,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;
@@ -623,7 +666,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;
@@ -641,7 +684,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;
@@ -661,6 +704,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);
@@ -681,6 +728,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;
}
}
@@ -693,7 +741,11 @@ static void 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;
@@ -706,6 +758,7 @@ static void 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);
@@ -752,7 +805,8 @@ static int 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);
@@ -821,8 +875,10 @@ static int 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;
@@ -861,18 +917,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->thread_opaque;
+ 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->thread_opaque;
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;
}
@@ -889,6 +957,7 @@ int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags)
}
pthread_mutex_lock(&p->parent->buffer_mutex);
+
FF_DISABLE_DEPRECATION_WARNINGS
if (avctx->thread_safe_callbacks || (
#if FF_API_GET_BUFFER
@@ -898,11 +967,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);
@@ -912,7 +981,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)
@@ -923,6 +992,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->thread_opaque;
+ if (!(avctx->active_thread_type & FF_THREAD_FRAME) || avctx->thread_safe_callbacks ||
+ avctx->get_format == avcodec_default_get_format)
+ return avctx->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->thread_opaque;
@@ -1029,3 +1132,62 @@ void ff_thread_free(AVCodecContext *avctx)
else
thread_free(avctx);
}
+
+void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n)
+{
+ ThreadContext *p = avctx->thread_opaque;
+ 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)
+{
+ ThreadContext *p = avctx->thread_opaque;
+ 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) {
+ ThreadContext *p = avctx->thread_opaque;
+ p->thread_count = avctx->thread_count;
+ p->entries = av_mallocz(count * sizeof(int));
+
+ if (!p->entries) {
+ return AVERROR(ENOMEM);
+ }
+
+ p->entries_count = count;
+ p->progress_mutex = av_malloc(p->thread_count * sizeof(pthread_mutex_t));
+ p->progress_cond = av_malloc(p->thread_count * sizeof(pthread_cond_t));
+
+ 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)
+{
+ ThreadContext *p = avctx->thread_opaque;
+ memset(p->entries, 0, p->entries_count * sizeof(int));
+}
diff --git a/libavcodec/ptx.c b/libavcodec/ptx.c
index 527e39a..6da9f02 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;
@@ -59,10 +59,8 @@ static int ptx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return ret;
if (w != avctx->width || h != avctx->height)
avcodec_set_dimensions(avctx, w, h);
- 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;
@@ -70,13 +68,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 e3412cb..e2c4a61 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
*/
@@ -34,6 +34,7 @@
#include "libavutil/common.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
+#include "libavutil/avassert.h"
#include "mathops.h"
#include "config.h"
@@ -141,7 +142,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;
@@ -150,6 +151,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;
@@ -163,6 +165,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;
@@ -176,7 +179,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));
}
@@ -212,8 +215,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..7ddeed4 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
*/
@@ -257,7 +257,7 @@ 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
};
diff --git a/libavcodec/qcelpdec.c b/libavcodec/qcelpdec.c
index 7d9427c..9650711 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) {
@@ -486,7 +484,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++)
@@ -695,10 +693,8 @@ 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) {
diff --git a/libavcodec/qdm2.c b/libavcodec/qdm2.c
index 04e7def..0a9eea0 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;
@@ -1814,8 +1856,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 +1886,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 +1909,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 +1948,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 +2022,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++) {
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 38cf829..edde937 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;
@@ -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;
@@ -167,10 +169,10 @@ static void qpeg_decode_inter(QpegContext *qctx, uint8_t *dst,
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) {
@@ -250,7 +255,8 @@ static int decode_frame(AVCodecContext *avctx,
{
uint8_t ctable[128];
QpegContext * const a = avctx->priv_data;
- AVFrame * const p = &a->pic;
+ AVFrame * p = &a->pic;
+ AVFrame * 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 = a->pic.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, a->pic.linesize[0], avctx->width, avctx->height);
} else {
- qpeg_decode_inter(a, outdata, a->pic.linesize[0], avctx->width, avctx->height, delta, ctable, a->refdata);
+ qpeg_decode_inter(a, outdata, a->pic.linesize[0], avctx->width, avctx->height, delta, ctable, a->ref.data[0]);
}
/* make the palette available on the way out */
@@ -292,12 +300,27 @@ 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_init(AVCodecContext *avctx){
QpegContext * const a = avctx->priv_data;
+ avcodec_get_frame_defaults(&a->pic);
+ avcodec_get_frame_defaults(&a->ref);
a->avctx = avctx;
avctx->pix_fmt= AV_PIX_FMT_PAL8;
- a->refdata = av_malloc(avctx->width * avctx->height);
+
+ decode_flush(avctx);
avcodec_get_frame_defaults(&a->pic);
@@ -307,10 +330,11 @@ static av_cold int decode_init(AVCodecContext *avctx){
static av_cold int decode_end(AVCodecContext *avctx){
QpegContext * const a = avctx->priv_data;
AVFrame * const p = &a->pic;
+ AVFrame * const ref= &a->ref;
av_frame_unref(p);
+ av_frame_unref(ref);
- av_free(a->refdata);
return 0;
}
@@ -323,5 +347,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/qtrle.c b/libavcodec/qtrle.c
index f41569a..4eeeea4 100644
--- a/libavcodec/qtrle.c
+++ b/libavcodec/qtrle.c
@@ -2,20 +2,20 @@
* Quicktime Animation (RLE) 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
*/
@@ -41,7 +41,7 @@
typedef struct QtrleContext {
AVCodecContext *avctx;
- AVFrame frame;
+ AVFrame *frame;
GetByteContext g;
uint32_t pal[256];
@@ -58,18 +58,26 @@ 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];
- int pixel_limit = s->frame.linesize[0] * s->avctx->height;
+ int row_inc = s->frame->linesize[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;
}
}
}
@@ -110,17 +121,17 @@ 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];
- int pixel_limit = s->frame.linesize[0] * s->avctx->height;
+ int row_inc = s->frame->linesize[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;
while (lines_to_change--) {
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 */
@@ -166,16 +177,16 @@ 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];
- int pixel_limit = s->frame.linesize[0] * s->avctx->height;
+ int row_inc = s->frame->linesize[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;
@@ -216,16 +226,16 @@ 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];
- int pixel_limit = s->frame.linesize[0] * s->avctx->height;
+ int row_inc = s->frame->linesize[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;
}
}
@@ -260,16 +270,16 @@ 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];
- int pixel_limit = s->frame.linesize[0] * s->avctx->height;
+ int row_inc = s->frame->linesize[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;
@@ -307,16 +317,16 @@ static void qtrle_decode_32bpp(QtrleContext *s, int row_ptr, int lines_to_change
{
int rle_code;
int pixel_ptr;
- int row_inc = s->frame.linesize[0];
+ int row_inc = s->frame->linesize[0];
unsigned int argb;
- unsigned char *rgb = s->frame.data[0];
- int pixel_limit = s->frame.linesize[0] * s->avctx->height;
+ 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;
@@ -385,7 +395,9 @@ static av_cold int qtrle_decode_init(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
}
- avcodec_get_frame_defaults(&s->frame);
+ s->frame = av_frame_alloc();
+ if (!s->frame)
+ return AVERROR(ENOMEM);
return 0;
}
@@ -401,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)
@@ -424,11 +434,13 @@ 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;
}
- row_ptr = s->frame.linesize[0] * start_line;
+ row_ptr = s->frame->linesize[0] * start_line;
switch (avctx->bits_per_coded_sample) {
case 1:
@@ -476,16 +488,16 @@ static int qtrle_decode_frame(AVCodecContext *avctx,
const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL);
if (pal) {
- s->frame.palette_has_changed = 1;
+ s->frame->palette_has_changed = 1;
memcpy(s->pal, pal, AVPALETTE_SIZE);
}
/* make the palette available on the way out */
- memcpy(s->frame.data[1], s->pal, AVPALETTE_SIZE);
+ memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE);
}
done:
- if ((ret = av_frame_ref(data, &s->frame)) < 0)
+ if ((ret = av_frame_ref(data, s->frame)) < 0)
return ret;
*got_frame = 1;
@@ -497,7 +509,7 @@ static av_cold int qtrle_decode_end(AVCodecContext *avctx)
{
QtrleContext *s = avctx->priv_data;
- av_frame_unref(&s->frame);
+ av_frame_free(&s->frame);
return 0;
}
diff --git a/libavcodec/qtrleenc.c b/libavcodec/qtrleenc.c
index a428459..2395cff 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
*/
@@ -40,6 +40,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
@@ -63,13 +64,19 @@ typedef struct QtrleEncContext {
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:
+ s->logical_width = avctx->width / 4;
+ s->pixel_size = 4;
+ break;
case AV_PIX_FMT_RGB555BE:
s->pixel_size = 2;
break;
@@ -83,24 +90,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((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 = &s->frame;
return 0;
}
@@ -110,26 +117,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;
@@ -139,8 +146,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->frame.key_frame && !memcmp(this_line, prev_line, s->pixel_size))
skipcount = FFMIN(skipcount + 1, MAX_RLE_SKIP);
else
@@ -176,31 +232,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 */
@@ -225,12 +272,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;
}
}
@@ -246,7 +309,7 @@ static int encode_frame(QtrleEncContext *s, const AVFrame *p, uint8_t *buf)
uint8_t *orig_buf = buf;
if (!s->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],
@@ -288,11 +351,8 @@ static int qtrle_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
*p = *pict;
- 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 */
@@ -337,6 +397,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..80230f5
--- a/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 = avcodec_alloc_frame();
+
+ 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..fe9a5bc 100644
--- a/libavcodec/ra144.c
+++ b/libavcodec/ra144.c
@@ -2,20 +2,20 @@
* Real Audio 1.0 (14.4K)
* 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;
@@ -1687,12 +1694,12 @@ 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 buffer_a[BLOCKSIZE];
+ int16_t *block;
int m[3];
if (cba_idx) {
diff --git a/libavcodec/ra144.h b/libavcodec/ra144.h
index 81d6964..763495d 100644
--- a/libavcodec/ra144.h
+++ b/libavcodec/ra144.h
@@ -2,20 +2,20 @@
* Real Audio 1.0 (14.4K)
* 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,7 +30,7 @@
#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 {
@@ -56,7 +56,7 @@ 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];
} RA144Context;
void ff_copy_and_dup(int16_t *target, const int16_t *source, int offset);
@@ -69,7 +69,7 @@ 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,
+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..b7add7f 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
*/
@@ -45,7 +45,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 +66,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 +76,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 +85,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 +122,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 9f953d4..3558254 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
*/
@@ -197,8 +197,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;
@@ -336,7 +336,8 @@ static void ra144_encode_subblock(RA144Context *ractx,
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;
@@ -446,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
@@ -537,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;
}
@@ -555,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..c1b9b6b 100644
--- a/libavcodec/ra288.c
+++ b/libavcodec/ra288.c
@@ -2,20 +2,20 @@
* RealAudio 2.0 (28.8K)
* 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..7323eea 100644
--- a/libavcodec/ra288.h
+++ b/libavcodec/ra288.h
@@ -2,20 +2,20 @@
* RealAudio 2.0 (28.8K)
* 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..69150a5 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;
}
diff --git a/libavcodec/rangecoder.h b/libavcodec/rangecoder.h
index ad9c81f..88e555f 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 5aaf151..7db248e 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
*/
@@ -63,6 +63,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) {
@@ -124,6 +129,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->avctx->rc_eq ? s->avctx->rc_eq : "tex^qComp",
const_names, func1_names, func1,
@@ -147,6 +159,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;
@@ -275,7 +289,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);
}
}
}
@@ -300,7 +314,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;
@@ -314,6 +328,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;
}
@@ -490,7 +507,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;
@@ -749,19 +766,24 @@ 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;
+ 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 {
@@ -892,7 +914,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;
@@ -901,7 +923,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 */
@@ -948,6 +970,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..959b6a2 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
*/
diff --git a/libavcodec/raw.c b/libavcodec/raw.c
index 4ccc6cc..c3f3de1 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
*/
@@ -64,6 +64,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') },
@@ -82,10 +83,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_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') },
@@ -115,6 +124,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 ) },
@@ -122,7 +143,9 @@ 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_Y400A, MKTAG('Y', '2', 0 , 8 ) },
+ { AV_PIX_FMT_YUVA422P, MKTAG('Y', '4', 10 , 8 ) },
+ { AV_PIX_FMT_YUVA444P, MKTAG('Y', '4', 0 , 8 ) },
+ { AV_PIX_FMT_GRAY8A, MKTAG('Y', '2', 0 , 8 ) },
{ AV_PIX_FMT_YUVA420P9LE, MKTAG('Y', '4', 11 , 9 ) },
{ AV_PIX_FMT_YUVA420P9BE, MKTAG( 9 , 11 , '4', 'Y') },
@@ -143,10 +166,25 @@ 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') },
+
/* 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 */
@@ -154,8 +192,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') },
@@ -163,6 +203,7 @@ const PixelFormatTag ff_raw_pix_fmt_tags[] = {
/* special */
{ AV_PIX_FMT_RGB565LE,MKTAG( 3 , 0 , 0 , 0 ) }, /* flipped RGB565LE */
{ AV_PIX_FMT_YUV444P, MKTAG('Y', 'V', '2', '4') }, /* YUV444P, swapped UV */
+ { AV_PIX_FMT_YUYV422, MKTAG('Y', 'V', 'Y', 'U') }, /* YUYV, swapped UV */
{ AV_PIX_FMT_NONE, 0 },
};
diff --git a/libavcodec/raw.h b/libavcodec/raw.h
index bf66671..3e59f28 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,17 @@
#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 av_export const PixelFormatTag ff_raw_pix_fmt_tags[];
+#if LIBAVCODEC_VERSION_MAJOR < 55
+enum AVPixelFormat ff_find_pix_fmt(const PixelFormatTag *tags, unsigned int fourcc);
+#endif
+enum AVPixelFormat avpriv_find_pix_fmt(const PixelFormatTag *tags, unsigned int fourcc);
#endif /* AVCODEC_RAW_H */
diff --git a/libavcodec/rawdec.c b/libavcodec/rawdec.c
index 24d06f3..dd47f53 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
*/
@@ -26,27 +26,44 @@
#include "avcodec.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 tff;
} RawVideoContext;
+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 AVClass rawdec_class = {
+ .class_name = "rawdec",
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
static const PixelFormatTag 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_RGB444, 12 },
- { AV_PIX_FMT_RGB555, 15 },
- { AV_PIX_FMT_RGB555, 16 },
+ { AV_PIX_FMT_RGB444LE, 12 },
+ { AV_PIX_FMT_RGB555LE, 15 },
+ { AV_PIX_FMT_RGB555LE, 16 },
{ AV_PIX_FMT_BGR24, 24 },
- { AV_PIX_FMT_RGB32, 32 },
+ { AV_PIX_FMT_BGRA, 32 },
{ AV_PIX_FMT_NONE, 0 },
};
@@ -64,7 +81,7 @@ static const PixelFormatTag pix_fmt_bps_mov[] = {
{ AV_PIX_FMT_NONE, 0 },
};
-static enum AVPixelFormat find_pix_fmt(const PixelFormatTag *tags,
+enum AVPixelFormat avpriv_find_pix_fmt(const PixelFormatTag *tags,
unsigned int fourcc)
{
while (tags->pix_fmt >= 0) {
@@ -72,24 +89,32 @@ static enum AVPixelFormat find_pix_fmt(const PixelFormatTag *tags,
return tags->pix_fmt;
tags++;
}
- return AV_PIX_FMT_YUV420P;
+ return AV_PIX_FMT_NONE;
+}
+
+#if LIBAVCODEC_VERSION_MAJOR < 55
+enum AVPixelFormat ff_find_pix_fmt(const PixelFormatTag *tags, unsigned int fourcc)
+{
+ return avpriv_find_pix_fmt(tags, fourcc);
}
+#endif
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,
+ if ( avctx->codec_tag == MKTAG('r','a','w',' ')
+ || avctx->codec_tag == MKTAG('N','O','1','6'))
+ avctx->pix_fmt = avpriv_find_pix_fmt(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(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);
+ 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(pix_fmt_bps_avi,
avctx->bits_per_coded_sample);
desc = av_pix_fmt_desc_get(avctx->pix_fmt);
@@ -108,15 +133,21 @@ 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',' ')))
+ (!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->frame_size = avpicture_get_size(avctx->pix_fmt, avctx->width,
+ avctx->height);
+ }
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;
@@ -141,8 +172,9 @@ 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 linesize_align = 4;
+ int res, len;
int need_copy = !avpkt->buf || context->is_2_4_bpp || context->is_yuv2;
- int res;
AVFrame *frame = data;
AVPicture *picture = data;
@@ -151,13 +183,19 @@ static int raw_decode(AVCodecContext *avctx, void *data, int *got_frame,
frame->key_frame = 1;
frame->reordered_opaque = avctx->reordered_opaque;
frame->pkt_pts = avctx->pkt->pts;
+ av_frame_set_pkt_pos (frame, avctx->pkt->pos);
+ av_frame_set_pkt_duration(frame, avctx->pkt->duration);
+
+ if (context->tff >= 0) {
+ frame->interlaced_frame = 1;
+ frame->top_field_first = context->tff;
+ }
- if (buf_size < context->frame_size - (avctx->pix_fmt == AV_PIX_FMT_PAL8 ?
- AVPALETTE_SIZE : 0))
- return -1;
+ 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])
@@ -169,21 +207,24 @@ 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 (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;
}
@@ -191,9 +232,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) {
+ 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,
@@ -202,20 +252,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;
@@ -229,6 +303,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;
@@ -239,6 +318,22 @@ static int raw_decode(AVCodecContext *avctx, void *data, int *got_frame,
line += picture->linesize[0];
}
}
+ if (avctx->codec_tag == AV_RL32("YVYU") &&
+ avctx->pix_fmt == AV_PIX_FMT_YUYV422) {
+ int x, y;
+ uint8_t *line = picture->data[0];
+ for(y = 0; y < avctx->height; y++) {
+ for(x = 0; x < avctx->width - 1; x += 2)
+ FFSWAP(uint8_t, line[2*x + 1], line[2*x + 3]);
+ line += picture->linesize[0];
+ }
+ }
+
+ 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;
@@ -261,4 +356,5 @@ AVCodec ff_rawvideo_decoder = {
.init = raw_init_decoder,
.close = raw_close_decoder,
.decode = raw_decode,
+ .priv_class = &rawdec_class,
};
diff --git a/libavcodec/rawenc.c b/libavcodec/rawenc.c
index 6c90d33..036261d 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
*/
@@ -36,8 +36,8 @@ static av_cold int raw_init_encoder(AVCodecContext *avctx)
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
avctx->coded_frame = avctx->priv_data;
+ avcodec_get_frame_defaults(avctx->coded_frame);
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 +52,7 @@ static int raw_encode(AVCodecContext *avctx, AVPacket *pkt,
if (ret < 0)
return ret;
- if ((ret = ff_alloc_packet(pkt, ret)) < 0)
+ if ((ret = ff_alloc_packet2(avctx, pkt, ret)) < 0)
return ret;
if ((ret = avpicture_layout((const AVPicture *)frame, avctx->pix_fmt, avctx->width,
avctx->height, pkt->data, pkt->size)) < 0)
diff --git a/libavcodec/rdft.c b/libavcodec/rdft.c
index 54cf14a..218dd4c 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..5fb0323 100644
--- a/libavcodec/rdft.h
+++ b/libavcodec/rdft.h
@@ -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
*/
diff --git a/libavcodec/realtextdec.c b/libavcodec/realtextdec.c
new file mode 100644
index 0000000..4578897
--- a/dev/null
+++ b/libavcodec/realtextdec.c
@@ -0,0 +1,83 @@
+/*
+ * 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++;
+ }
+ av_bprintf(buf, "\r\n");
+ return 0;
+}
+
+static int realtext_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_sub_ptr, AVPacket *avpkt)
+{
+ 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))
+ ff_ass_add_rect(sub, buf.str, avpkt->pts, avpkt->duration, 0);
+ *got_sub_ptr = sub->num_rects > 0;
+ av_bprint_finalize(&buf, NULL);
+ 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..f950288
--- a/dev/null
+++ b/libavcodec/resample.c
@@ -0,0 +1,435 @@
+/*
+ * 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((nb_samples + s->temp_len) * sizeof(short));
+ memcpy(bufin[i], s->temp[i], s->temp_len * sizeof(short));
+ buftmp2[i] = bufin[i] + s->temp_len;
+ bufout[i] = av_malloc(lenout * sizeof(short));
+ }
+
+ 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(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;
+ }
+ }
+
+ 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..9b63b53
--- a/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(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(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..c80283d 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
*/
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 7301578..50ab59a 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 77df079..eb8fc25 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 eed2f22..3834897 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
*/
diff --git a/libavcodec/roqvideodec.c b/libavcodec/roqvideodec.c
index ac7d4ba..8e7dffe 100644
--- a/libavcodec/roqvideodec.c
+++ b/libavcodec/roqvideodec.c
@@ -1,20 +1,20 @@
/*
* 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_ERROR, "Input buffer too small\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_ERROR, "Input buffer too small\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);
}
}
@@ -193,10 +204,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..bf0756c 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.
*/
/*
@@ -1041,10 +1041,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 +1052,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);
diff --git a/libavcodec/rpza.c b/libavcodec/rpza.c
index d209f58..4917369 100644
--- a/libavcodec/rpza.c
+++ b/libavcodec/rpza.c
@@ -2,20 +2,20 @@
* Quicktime Video (RPZA) Video Decoder
* 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
*/
@@ -85,7 +85,7 @@ static void rpza_decode_stream(RpzaContext *s)
unsigned short *pixels = (unsigned short *)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;
@@ -141,6 +141,7 @@ static void rpza_decode_stream(RpzaContext *s)
colorA = AV_RB16 (&s->buf[stream_ptr]);
stream_ptr += 2;
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++){
@@ -149,7 +150,6 @@ static void rpza_decode_stream(RpzaContext *s)
}
block_ptr += row_inc;
}
- ADVANCE_BLOCK();
}
break;
@@ -188,6 +188,7 @@ static void rpza_decode_stream(RpzaContext *s)
if (s->size - stream_ptr < n_blocks * 4)
return;
while (n_blocks--) {
+ ADVANCE_BLOCK();
block_ptr = row_ptr + pixel_ptr;
for (pixel_y = 0; pixel_y < 4; pixel_y++) {
index = s->buf[stream_ptr++];
@@ -198,7 +199,6 @@ static void rpza_decode_stream(RpzaContext *s)
}
block_ptr += row_inc;
}
- ADVANCE_BLOCK();
}
break;
@@ -206,6 +206,7 @@ static void rpza_decode_stream(RpzaContext *s)
case 0x00:
if (s->size - stream_ptr < 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++){
@@ -219,7 +220,6 @@ static void rpza_decode_stream(RpzaContext *s)
}
block_ptr += row_inc;
}
- ADVANCE_BLOCK();
break;
/* Unknown opcode */
@@ -256,10 +256,8 @@ static int rpza_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;
- }
rpza_decode_stream(s);
diff --git a/libavcodec/rtjpeg.c b/libavcodec/rtjpeg.c
index f5abe63..860d958 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 c544b0b..294b06c 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 f790c1f..5206533 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
*/
@@ -302,7 +302,7 @@ static int rv20_decode_picture_header(RVDecContext *rv)
int rpr_bits;
i = get_bits(&s->gb, 2);
- switch (i) {
+ switch(i) {
case 0: s->pict_type = AV_PICTURE_TYPE_I; break;
case 1: s->pict_type = AV_PICTURE_TYPE_I; break; //hmm ...
case 2: s->pict_type = AV_PICTURE_TYPE_P; break;
@@ -312,6 +312,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 == NULL && s->pict_type == AV_PICTURE_TYPE_B) {
av_log(s->avctx, AV_LOG_ERROR, "early B-frame\n");
return AVERROR_INVALIDDATA;
@@ -329,7 +333,7 @@ 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;
@@ -356,11 +360,20 @@ static int rv20_decode_picture_header(RVDecContext *rv)
new_h = s->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});
avcodec_set_dimensions(s->avctx, new_w, new_h);
s->width = new_w;
s->height = new_h;
@@ -371,7 +384,8 @@ 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);
}
- } 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);
@@ -390,15 +404,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);
@@ -409,14 +425,15 @@ 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, "num:%5d x:%2d y:%2d type:%d qscale:%2d rnd:%d\n",
seq, s->mb_x, s->mb_y, s->pict_type, s->qscale, s->no_rounding);
}
- 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;
}
@@ -441,7 +458,6 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx)
s->avctx = avctx;
s->out_format = FMT_H263;
s->codec_id = avctx->codec_id;
- avctx->flags |= CODEC_FLAG_EMU_EDGE;
s->orig_width = s->width = avctx->coded_width;
s->orig_height = s->height = avctx->coded_height;
@@ -473,7 +489,7 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx)
if (avctx->debug & FF_DEBUG_PICT_INFO) {
av_log(avctx, AV_LOG_DEBUG, "ver:%X ver0:%X\n", rv->sub_id,
- avctx->extradata_size >= 4 ? ((uint32_t*)avctx->extradata)[0] : -1);
+ ((uint32_t*)avctx->extradata)[0]);
}
avctx->pix_fmt = AV_PIX_FMT_YUV420P;
@@ -519,7 +535,8 @@ static int rv10_decode_packet(AVCodecContext *avctx,
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;
}
@@ -551,6 +568,7 @@ static int rv10_decode_packet(AVCodecContext *avctx,
}
}
+
av_dlog(avctx, "qscale=%d\n", s->qscale);
/* default quantization values */
@@ -662,6 +680,8 @@ static int rv10_decode_frame(AVCodecContext *avctx,
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) {
@@ -715,11 +735,13 @@ static int rv10_decode_frame(AVCodecContext *avctx,
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 != NULL) {
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) {
@@ -743,6 +765,7 @@ AVCodec ff_rv10_decoder = {
.close = rv10_decode_end,
.decode = rv10_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
.pix_fmts = ff_pixfmt_list_420,
};
@@ -757,5 +780,6 @@ AVCodec ff_rv20_decoder = {
.decode = rv10_decode_frame,
.capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY,
.flush = ff_mpeg_flush,
+ .max_lowres = 3,
.pix_fmts = ff_pixfmt_list_420,
};
diff --git a/libavcodec/rv10enc.c b/libavcodec/rv10enc.c
index 9b23d7d..1f85743 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 67879e2..b943116 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 ffb433b..7690da7 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
*/
@@ -50,6 +50,11 @@ static int rv30_parse_slice_header(RV34DecContext *r, GetBitContext *gb, SliceIn
skip_bits1(gb);
si->pts = get_bits(gb, 13);
rpr = get_bits(gb, r->rpr);
+ if (r->s.avctx->extradata_size < 8 + rpr*2) {
+ av_log(r->s.avctx, AV_LOG_WARNING,
+ "Extradata does not contain selected resolution\n");
+ rpr = 0;
+ }
if(rpr){
w = r->s.avctx->extradata[6 + rpr*2] << 2;
h = r->s.avctx->extradata[7 + rpr*2] << 2;
@@ -73,7 +78,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;
}
@@ -257,7 +262,6 @@ static av_cold int rv30_decode_init(AVCodecContext *avctx)
if(avctx->extradata_size - 8 < (r->rpr - 1) * 2){
av_log(avctx, AV_LOG_ERROR, "Insufficient extradata - need at least %d bytes, got %d\n",
6 + r->rpr * 2, avctx->extradata_size);
- return AVERROR(EINVAL);
}
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..9cc48a6 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
*/
diff --git a/libavcodec/rv30dsp.c b/libavcodec/rv30dsp.c
index d4b122e..5e47b64 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 7eb97e7..f84fb00 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"
@@ -212,7 +213,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)
{
@@ -723,13 +724,16 @@ static inline void rv34_mc(RV34DecContext *r, const int block_type,
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, (width<<3)+6, (height<<3)+6,
- src_x - 2, src_y - 2, s->h_edge_pos, s->v_edge_pos);
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, s->linesize, srcY, s->linesize,
+ (width<<3)+6, (height<<3)+6, 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, (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, (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, s->uvlinesize, srcU, 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, s->uvlinesize, srcV, 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;
}
@@ -1330,7 +1334,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;
}
@@ -1401,6 +1405,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;
@@ -1580,18 +1588,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 != NULL) {
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)
@@ -1653,7 +1673,7 @@ 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.",
+ 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);
@@ -1665,6 +1685,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;
avcodec_set_dimensions(s->avctx, s->width, s->height);
diff --git a/libavcodec/rv34.h b/libavcodec/rv34.h
index c32c089..475f17a 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
*/
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 c5d4e39..7e28b26 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 def3990..17a2f91 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
*/
@@ -228,8 +228,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;
@@ -356,7 +359,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 a7af1d6..bdd9a3e 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
*/
@@ -27,6 +27,7 @@
#include "avcodec.h"
#include "h264qpel.h"
#include "rv34dsp.h"
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#define RV40_LOWPASS(OPNAME, OP) \
@@ -218,7 +219,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++){\
@@ -251,7 +252,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..a7e5b1d
--- a/dev/null
+++ b/libavcodec/s302menc.c
@@ -0,0 +1,177 @@
+/*
+ * 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 "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..39ac608
--- a/dev/null
+++ b/libavcodec/samidec.c
@@ -0,0 +1,158 @@
+/*
+ * 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\r\n", 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;
+ ff_ass_add_rect(sub, sami->full.str, ts_start, ts_duration, 0);
+ }
+ *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
new file mode 100644
index 0000000..76da8bb
--- a/dev/null
+++ b/libavcodec/sanm.c
@@ -0,0 +1,1307 @@
+/*
+ * LucasArts Smush video decoder
+ * Copyright (c) 2006 Cyril Zorin
+ * Copyright (c) 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
+ */
+
+// #define DEBUG 1
+
+#include "avcodec.h"
+#include "copy_block.h"
+#include "bytestream.h"
+#include "internal.h"
+#include "libavutil/bswap.h"
+#include "libavutil/imgutils.h"
+#include "sanm_data.h"
+#include "libavutil/avassert.h"
+
+#define NGLYPHS 256
+
+typedef struct {
+ AVCodecContext *avctx;
+ GetByteContext gb;
+
+ int version, subversion;
+ uint32_t pal[256];
+ int16_t delta_pal[768];
+
+ int pitch;
+ int width, height;
+ int aligned_width, aligned_height;
+ int prev_seq;
+
+ AVFrame *frame;
+ uint16_t *frm0, *frm1, *frm2;
+ uint8_t *stored_frame;
+ uint32_t frm0_size, frm1_size, frm2_size;
+ uint32_t stored_frame_size;
+
+ uint8_t *rle_buf;
+ unsigned int rle_buf_size;
+
+ int rotate_code;
+
+ long npixels, buf_size;
+
+ uint16_t codebook[256];
+ uint16_t small_codebook[4];
+
+ int8_t p4x4glyphs[NGLYPHS][16];
+ int8_t p8x8glyphs[NGLYPHS][64];
+} SANMVideoContext;
+
+typedef struct {
+ int seq_num, codec, rotate_code, rle_output_size;
+
+ uint16_t bg_color;
+ uint32_t width, height;
+} SANMFrameHeader;
+
+enum GlyphEdge {
+ LEFT_EDGE,
+ TOP_EDGE,
+ RIGHT_EDGE,
+ BOTTOM_EDGE,
+ NO_EDGE
+};
+
+enum GlyphDir {
+ DIR_LEFT,
+ DIR_UP,
+ DIR_RIGHT,
+ DIR_DOWN,
+ NO_DIR
+};
+
+/**
+ * Return enum GlyphEdge of box where point (x, y) lies.
+ *
+ * @param x x point coordinate
+ * @param y y point coordinate
+ * @param edge_size box width/height.
+ */
+static enum GlyphEdge which_edge(int x, int y, int edge_size)
+{
+ const int edge_max = edge_size - 1;
+
+ if (!y) {
+ return BOTTOM_EDGE;
+ } else if (y == edge_max) {
+ return TOP_EDGE;
+ } else if (!x) {
+ return LEFT_EDGE;
+ } else if (x == edge_max) {
+ return RIGHT_EDGE;
+ } else {
+ return NO_EDGE;
+ }
+}
+
+static enum GlyphDir which_direction(enum GlyphEdge edge0, enum GlyphEdge edge1)
+{
+ if ((edge0 == LEFT_EDGE && edge1 == RIGHT_EDGE) ||
+ (edge1 == LEFT_EDGE && edge0 == RIGHT_EDGE) ||
+ (edge0 == BOTTOM_EDGE && edge1 != TOP_EDGE) ||
+ (edge1 == BOTTOM_EDGE && edge0 != TOP_EDGE)) {
+ return DIR_UP;
+ } else if ((edge0 == TOP_EDGE && edge1 != BOTTOM_EDGE) ||
+ (edge1 == TOP_EDGE && edge0 != BOTTOM_EDGE)) {
+ return DIR_DOWN;
+ } else if ((edge0 == LEFT_EDGE && edge1 != RIGHT_EDGE) ||
+ (edge1 == LEFT_EDGE && edge0 != RIGHT_EDGE)) {
+ return DIR_LEFT;
+ } else if ((edge0 == TOP_EDGE && edge1 == BOTTOM_EDGE) ||
+ (edge1 == TOP_EDGE && edge0 == BOTTOM_EDGE) ||
+ (edge0 == RIGHT_EDGE && edge1 != LEFT_EDGE) ||
+ (edge1 == RIGHT_EDGE && edge0 != LEFT_EDGE)) {
+ return DIR_RIGHT;
+ }
+
+ return NO_DIR;
+}
+
+/**
+ * Interpolate two points.
+ */
+static void interp_point(int8_t *points, int x0, int y0, int x1, int y1,
+ int pos, int npoints)
+{
+ if (npoints) {
+ points[0] = (x0 * pos + x1 * (npoints - pos) + (npoints >> 1)) / npoints;
+ points[1] = (y0 * pos + y1 * (npoints - pos) + (npoints >> 1)) / npoints;
+ } else {
+ points[0] = x0;
+ points[1] = y0;
+ }
+}
+
+/**
+ * Construct glyphs by iterating through vectors coordinates.
+ *
+ * @param pglyphs pointer to table where glyphs are stored
+ * @param xvec pointer to x component of vectors coordinates
+ * @param yvec pointer to y component of vectors coordinates
+ * @param side_length glyph width/height.
+ */
+static void make_glyphs(int8_t *pglyphs, const int8_t *xvec, const int8_t *yvec,
+ const int side_length)
+{
+ const int glyph_size = side_length * side_length;
+ int8_t *pglyph = pglyphs;
+
+ int i, j;
+ for (i = 0; i < GLYPH_COORD_VECT_SIZE; i++) {
+ int x0 = xvec[i];
+ int y0 = yvec[i];
+ enum GlyphEdge edge0 = which_edge(x0, y0, side_length);
+
+ for (j = 0; j < GLYPH_COORD_VECT_SIZE; j++, pglyph += glyph_size) {
+ int x1 = xvec[j];
+ int y1 = yvec[j];
+ enum GlyphEdge edge1 = which_edge(x1, y1, side_length);
+ enum GlyphDir dir = which_direction(edge0, edge1);
+ int npoints = FFMAX(FFABS(x1 - x0), FFABS(y1 - y0));
+ int ipoint;
+
+ for (ipoint = 0; ipoint <= npoints; ipoint++) {
+ int8_t point[2];
+ int irow, icol;
+
+ interp_point(point, x0, y0, x1, y1, ipoint, npoints);
+
+ switch (dir) {
+ case DIR_UP:
+ for (irow = point[1]; irow >= 0; irow--)
+ pglyph[point[0] + irow * side_length] = 1;
+ break;
+
+ case DIR_DOWN:
+ for (irow = point[1]; irow < side_length; irow++)
+ pglyph[point[0] + irow * side_length] = 1;
+ break;
+
+ case DIR_LEFT:
+ for (icol = point[0]; icol >= 0; icol--)
+ pglyph[icol + point[1] * side_length] = 1;
+ break;
+
+ case DIR_RIGHT:
+ for (icol = point[0]; icol < side_length; icol++)
+ pglyph[icol + point[1] * side_length] = 1;
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void init_sizes(SANMVideoContext *ctx, int width, int height)
+{
+ ctx->width = width;
+ ctx->height = height;
+ ctx->npixels = width * height;
+
+ ctx->aligned_width = FFALIGN(width, 8);
+ ctx->aligned_height = FFALIGN(height, 8);
+
+ ctx->buf_size = ctx->aligned_width * ctx->aligned_height * sizeof(ctx->frm0[0]);
+ ctx->pitch = width;
+}
+
+static void destroy_buffers(SANMVideoContext *ctx)
+{
+ av_freep(&ctx->frm0);
+ av_freep(&ctx->frm1);
+ av_freep(&ctx->frm2);
+ av_freep(&ctx->stored_frame);
+ av_freep(&ctx->rle_buf);
+ ctx->frm0_size =
+ ctx->frm1_size =
+ ctx->frm2_size = 0;
+}
+
+static av_cold int init_buffers(SANMVideoContext *ctx)
+{
+ av_fast_padded_malloc(&ctx->frm0, &ctx->frm0_size, ctx->buf_size);
+ av_fast_padded_malloc(&ctx->frm1, &ctx->frm1_size, ctx->buf_size);
+ av_fast_padded_malloc(&ctx->frm2, &ctx->frm2_size, ctx->buf_size);
+ if (!ctx->version)
+ av_fast_padded_malloc(&ctx->stored_frame, &ctx->stored_frame_size, ctx->buf_size);
+
+ if (!ctx->frm0 || !ctx->frm1 || !ctx->frm2 || (!ctx->stored_frame && !ctx->version)) {
+ destroy_buffers(ctx);
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
+static void rotate_bufs(SANMVideoContext *ctx, int rotate_code)
+{
+ av_dlog(ctx->avctx, "rotate %d\n", rotate_code);
+ if (rotate_code == 2)
+ FFSWAP(uint16_t*, ctx->frm1, ctx->frm2);
+ FFSWAP(uint16_t*, ctx->frm2, ctx->frm0);
+}
+
+static av_cold int decode_init(AVCodecContext *avctx)
+{
+ SANMVideoContext *ctx = avctx->priv_data;
+
+ ctx->avctx = avctx;
+ ctx->version = !avctx->extradata_size;
+
+ avctx->pix_fmt = ctx->version ? AV_PIX_FMT_RGB565 : AV_PIX_FMT_PAL8;
+
+ init_sizes(ctx, avctx->width, avctx->height);
+ if (init_buffers(ctx)) {
+ av_log(avctx, AV_LOG_ERROR, "error allocating buffers\n");
+ return AVERROR(ENOMEM);
+ }
+
+ make_glyphs(ctx->p4x4glyphs[0], glyph4_x, glyph4_y, 4);
+ make_glyphs(ctx->p8x8glyphs[0], glyph8_x, glyph8_y, 8);
+
+ if (!ctx->version) {
+ int i;
+
+ if (avctx->extradata_size < 1026) {
+ av_log(avctx, AV_LOG_ERROR, "not enough extradata\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->subversion = AV_RL16(avctx->extradata);
+ for (i = 0; i < 256; i++)
+ ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4);
+ }
+
+ return 0;
+}
+
+static av_cold int decode_end(AVCodecContext *avctx)
+{
+ SANMVideoContext *ctx = avctx->priv_data;
+
+ destroy_buffers(ctx);
+
+ return 0;
+}
+
+static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
+{
+ int opcode, color, run_len, left = out_size;
+
+ while (left > 0) {
+ opcode = bytestream2_get_byte(&ctx->gb);
+ run_len = (opcode >> 1) + 1;
+ if (run_len > left || bytestream2_get_bytes_left(&ctx->gb) <= 0)
+ return AVERROR_INVALIDDATA;
+
+ if (opcode & 1) {
+ color = bytestream2_get_byte(&ctx->gb);
+ memset(dst, color, run_len);
+ } else {
+ if (bytestream2_get_bytes_left(&ctx->gb) < run_len)
+ return AVERROR_INVALIDDATA;
+ bytestream2_get_bufferu(&ctx->gb, dst, run_len);
+ }
+
+ dst += run_len;
+ left -= run_len;
+ }
+
+ return 0;
+}
+
+static int old_codec1(SANMVideoContext *ctx, int top,
+ int left, int width, int height)
+{
+ uint8_t *dst = ((uint8_t*)ctx->frm0) + left + top * ctx->pitch;
+ int i, j, len, flag, code, val, pos, end;
+
+ for (i = 0; i < height; i++) {
+ pos = 0;
+
+ if (bytestream2_get_bytes_left(&ctx->gb) < 2)
+ return AVERROR_INVALIDDATA;
+
+ len = bytestream2_get_le16u(&ctx->gb);
+ end = bytestream2_tell(&ctx->gb) + len;
+
+ while (bytestream2_tell(&ctx->gb) < end) {
+ if (bytestream2_get_bytes_left(&ctx->gb) < 2)
+ return AVERROR_INVALIDDATA;
+
+ code = bytestream2_get_byteu(&ctx->gb);
+ flag = code & 1;
+ code = (code >> 1) + 1;
+ if (pos + code > width)
+ return AVERROR_INVALIDDATA;
+ if (flag) {
+ val = bytestream2_get_byteu(&ctx->gb);
+ if (val)
+ memset(dst + pos, val, code);
+ pos += code;
+ } else {
+ if (bytestream2_get_bytes_left(&ctx->gb) < code)
+ return AVERROR_INVALIDDATA;
+ for (j = 0; j < code; j++) {
+ val = bytestream2_get_byteu(&ctx->gb);
+ if (val)
+ dst[pos] = val;
+ pos++;
+ }
+ }
+ }
+ dst += ctx->pitch;
+ }
+ ctx->rotate_code = 0;
+
+ return 0;
+}
+
+static inline void codec37_mv(uint8_t *dst, const uint8_t *src,
+ int height, int stride, int x, int y)
+{
+ int pos, i, j;
+
+ pos = x + y * stride;
+ for (j = 0; j < 4; j++) {
+ for (i = 0; i < 4; i++) {
+ if ((pos + i) < 0 || (pos + i) >= height * stride)
+ dst[i] = 0;
+ else
+ dst[i] = src[i];
+ }
+ dst += stride;
+ src += stride;
+ pos += stride;
+ }
+}
+
+static int old_codec37(SANMVideoContext *ctx, int top,
+ int left, int width, int height)
+{
+ int stride = ctx->pitch;
+ int i, j, k, t;
+ int skip_run = 0;
+ int compr, mvoff, seq, flags;
+ uint32_t decoded_size;
+ uint8_t *dst, *prev;
+
+ compr = bytestream2_get_byte(&ctx->gb);
+ mvoff = bytestream2_get_byte(&ctx->gb);
+ seq = bytestream2_get_le16(&ctx->gb);
+ decoded_size = bytestream2_get_le32(&ctx->gb);
+ bytestream2_skip(&ctx->gb, 4);
+ flags = bytestream2_get_byte(&ctx->gb);
+ bytestream2_skip(&ctx->gb, 3);
+
+ if (decoded_size > ctx->height * stride - left - top * stride) {
+ decoded_size = ctx->height * stride - left - top * stride;
+ av_log(ctx->avctx, AV_LOG_WARNING, "decoded size is too large\n");
+ }
+
+ ctx->rotate_code = 0;
+
+ if (((seq & 1) || !(flags & 1)) && (compr && compr != 2))
+ rotate_bufs(ctx, 1);
+
+ dst = ((uint8_t*)ctx->frm0) + left + top * stride;
+ prev = ((uint8_t*)ctx->frm2) + left + top * stride;
+
+ if (mvoff > 2) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "invalid motion base value %d\n", mvoff);
+ return AVERROR_INVALIDDATA;
+ }
+ av_dlog(ctx->avctx, "compression %d\n", compr);
+ switch (compr) {
+ case 0:
+ for (i = 0; i < height; i++) {
+ bytestream2_get_buffer(&ctx->gb, dst, width);
+ dst += stride;
+ }
+ memset(ctx->frm1, 0, ctx->height * stride);
+ memset(ctx->frm2, 0, ctx->height * stride);
+ break;
+ case 2:
+ if (rle_decode(ctx, dst, decoded_size))
+ return AVERROR_INVALIDDATA;
+ memset(ctx->frm1, 0, ctx->frm1_size);
+ memset(ctx->frm2, 0, ctx->frm2_size);
+ break;
+ case 3:
+ case 4:
+ if (flags & 4) {
+ for (j = 0; j < height; j += 4) {
+ for (i = 0; i < width; i += 4) {
+ int code;
+ if (skip_run) {
+ skip_run--;
+ copy_block4(dst + i, prev + i, stride, stride, 4);
+ continue;
+ }
+ if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+ return AVERROR_INVALIDDATA;
+ code = bytestream2_get_byteu(&ctx->gb);
+ switch (code) {
+ case 0xFF:
+ if (bytestream2_get_bytes_left(&ctx->gb) < 16)
+ return AVERROR_INVALIDDATA;
+ for (k = 0; k < 4; k++)
+ bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
+ break;
+ case 0xFE:
+ if (bytestream2_get_bytes_left(&ctx->gb) < 4)
+ return AVERROR_INVALIDDATA;
+ for (k = 0; k < 4; k++)
+ memset(dst + i + k * stride, bytestream2_get_byteu(&ctx->gb), 4);
+ break;
+ case 0xFD:
+ if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+ return AVERROR_INVALIDDATA;
+ t = bytestream2_get_byteu(&ctx->gb);
+ for (k = 0; k < 4; k++)
+ memset(dst + i + k * stride, t, 4);
+ break;
+ default:
+ if (compr == 4 && !code) {
+ if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+ return AVERROR_INVALIDDATA;
+ skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
+ i -= 4;
+ } else {
+ int mx, my;
+
+ mx = c37_mv[(mvoff * 255 + code) * 2 ];
+ my = c37_mv[(mvoff * 255 + code) * 2 + 1];
+ codec37_mv(dst + i, prev + i + mx + my * stride,
+ ctx->height, stride, i + mx, j + my);
+ }
+ }
+ }
+ dst += stride * 4;
+ prev += stride * 4;
+ }
+ } else {
+ for (j = 0; j < height; j += 4) {
+ for (i = 0; i < width; i += 4) {
+ int code;
+ if (skip_run) {
+ skip_run--;
+ copy_block4(dst + i, prev + i, stride, stride, 4);
+ continue;
+ }
+ code = bytestream2_get_byte(&ctx->gb);
+ if (code == 0xFF) {
+ if (bytestream2_get_bytes_left(&ctx->gb) < 16)
+ return AVERROR_INVALIDDATA;
+ for (k = 0; k < 4; k++)
+ bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
+ } else if (compr == 4 && !code) {
+ if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+ return AVERROR_INVALIDDATA;
+ skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
+ i -= 4;
+ } else {
+ int mx, my;
+
+ mx = c37_mv[(mvoff * 255 + code) * 2];
+ my = c37_mv[(mvoff * 255 + code) * 2 + 1];
+ codec37_mv(dst + i, prev + i + mx + my * stride,
+ ctx->height, stride, i + mx, j + my);
+ }
+ }
+ dst += stride * 4;
+ prev += stride * 4;
+ }
+ }
+ break;
+ default:
+ av_log(ctx->avctx, AV_LOG_ERROR,
+ "subcodec 37 compression %d not implemented\n", compr);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ return 0;
+}
+
+static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1,
+ uint8_t *prev2, int stride, int tbl, int size)
+{
+ int code, k, t;
+ uint8_t colors[2];
+ int8_t *pglyph;
+
+ if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+ return AVERROR_INVALIDDATA;
+
+ code = bytestream2_get_byteu(&ctx->gb);
+ if (code >= 0xF8) {
+ switch (code) {
+ case 0xFF:
+ if (size == 2) {
+ if (bytestream2_get_bytes_left(&ctx->gb) < 4)
+ return AVERROR_INVALIDDATA;
+ dst[0] = bytestream2_get_byteu(&ctx->gb);
+ dst[1] = bytestream2_get_byteu(&ctx->gb);
+ dst[0+stride] = bytestream2_get_byteu(&ctx->gb);
+ dst[1+stride] = bytestream2_get_byteu(&ctx->gb);
+ } else {
+ size >>= 1;
+ if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
+ return AVERROR_INVALIDDATA;
+ if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
+ stride, tbl, size))
+ return AVERROR_INVALIDDATA;
+ dst += size * stride;
+ prev1 += size * stride;
+ prev2 += size * stride;
+ if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
+ return AVERROR_INVALIDDATA;
+ if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
+ stride, tbl, size))
+ return AVERROR_INVALIDDATA;
+ }
+ break;
+ case 0xFE:
+ if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+ return AVERROR_INVALIDDATA;
+
+ t = bytestream2_get_byteu(&ctx->gb);
+ for (k = 0; k < size; k++)
+ memset(dst + k * stride, t, size);
+ break;
+ case 0xFD:
+ if (bytestream2_get_bytes_left(&ctx->gb) < 3)
+ return AVERROR_INVALIDDATA;
+
+ code = bytestream2_get_byteu(&ctx->gb);
+ pglyph = (size == 8) ? ctx->p8x8glyphs[code] : ctx->p4x4glyphs[code];
+ bytestream2_get_bufferu(&ctx->gb, colors, 2);
+
+ for (k = 0; k < size; k++)
+ for (t = 0; t < size; t++)
+ dst[t + k * stride] = colors[!*pglyph++];
+ break;
+ case 0xFC:
+ for (k = 0; k < size; k++)
+ memcpy(dst + k * stride, prev1 + k * stride, size);
+ break;
+ default:
+ k = bytestream2_tell(&ctx->gb);
+ bytestream2_seek(&ctx->gb, tbl + (code & 7), SEEK_SET);
+ t = bytestream2_get_byte(&ctx->gb);
+ bytestream2_seek(&ctx->gb, k, SEEK_SET);
+ for (k = 0; k < size; k++)
+ memset(dst + k * stride, t, size);
+ }
+ } else {
+ int mx = motion_vectors[code][0];
+ int my = motion_vectors[code][1];
+ int index = prev2 - (const uint8_t*)ctx->frm2;
+
+ av_assert2(index >= 0 && index < (ctx->buf_size>>1));
+
+ if (index < - mx - my*stride ||
+ (ctx->buf_size>>1) - index < mx + size + (my + size - 1)*stride) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "MV is invalid \n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (k = 0; k < size; k++)
+ memcpy(dst + k * stride, prev2 + mx + (my + k) * stride, size);
+ }
+
+ return 0;
+}
+
+static int old_codec47(SANMVideoContext *ctx, int top,
+ int left, int width, int height)
+{
+ int i, j, seq, compr, new_rot, tbl_pos, skip;
+ int stride = ctx->pitch;
+ uint8_t *dst = ((uint8_t*)ctx->frm0) + left + top * stride;
+ uint8_t *prev1 = (uint8_t*)ctx->frm1;
+ uint8_t *prev2 = (uint8_t*)ctx->frm2;
+ uint32_t decoded_size;
+
+ tbl_pos = bytestream2_tell(&ctx->gb);
+ seq = bytestream2_get_le16(&ctx->gb);
+ compr = bytestream2_get_byte(&ctx->gb);
+ new_rot = bytestream2_get_byte(&ctx->gb);
+ skip = bytestream2_get_byte(&ctx->gb);
+ bytestream2_skip(&ctx->gb, 9);
+ decoded_size = bytestream2_get_le32(&ctx->gb);
+ bytestream2_skip(&ctx->gb, 8);
+
+ if (decoded_size > ctx->height * stride - left - top * stride) {
+ decoded_size = ctx->height * stride - left - top * stride;
+ av_log(ctx->avctx, AV_LOG_WARNING, "decoded size is too large\n");
+ }
+
+ if (skip & 1)
+ bytestream2_skip(&ctx->gb, 0x8080);
+ if (!seq) {
+ ctx->prev_seq = -1;
+ memset(prev1, 0, ctx->height * stride);
+ memset(prev2, 0, ctx->height * stride);
+ }
+ av_dlog(ctx->avctx, "compression %d\n", compr);
+ switch (compr) {
+ case 0:
+ if (bytestream2_get_bytes_left(&ctx->gb) < width * height)
+ return AVERROR_INVALIDDATA;
+ for (j = 0; j < height; j++) {
+ bytestream2_get_bufferu(&ctx->gb, dst, width);
+ dst += stride;
+ }
+ break;
+ case 1:
+ if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1))
+ return AVERROR_INVALIDDATA;
+ for (j = 0; j < height; j += 2) {
+ for (i = 0; i < width; i += 2) {
+ dst[i] = dst[i + 1] =
+ dst[stride + i] = dst[stride + i + 1] = bytestream2_get_byteu(&ctx->gb);
+ }
+ dst += stride * 2;
+ }
+ break;
+ case 2:
+ if (seq == ctx->prev_seq + 1) {
+ for (j = 0; j < height; j += 8) {
+ for (i = 0; i < width; i += 8) {
+ if (process_block(ctx, dst + i, prev1 + i, prev2 + i, stride,
+ tbl_pos + 8, 8))
+ return AVERROR_INVALIDDATA;
+ }
+ dst += stride * 8;
+ prev1 += stride * 8;
+ prev2 += stride * 8;
+ }
+ }
+ break;
+ case 3:
+ memcpy(ctx->frm0, ctx->frm2, ctx->pitch * ctx->height);
+ break;
+ case 4:
+ memcpy(ctx->frm0, ctx->frm1, ctx->pitch * ctx->height);
+ break;
+ case 5:
+ if (rle_decode(ctx, dst, decoded_size))
+ return AVERROR_INVALIDDATA;
+ break;
+ default:
+ av_log(ctx->avctx, AV_LOG_ERROR,
+ "subcodec 47 compression %d not implemented\n", compr);
+ return AVERROR_PATCHWELCOME;
+ }
+ if (seq == ctx->prev_seq + 1)
+ ctx->rotate_code = new_rot;
+ else
+ ctx->rotate_code = 0;
+ ctx->prev_seq = seq;
+
+ return 0;
+}
+
+static int process_frame_obj(SANMVideoContext *ctx)
+{
+ uint16_t codec, top, left, w, h;
+
+ codec = bytestream2_get_le16u(&ctx->gb);
+ left = bytestream2_get_le16u(&ctx->gb);
+ top = bytestream2_get_le16u(&ctx->gb);
+ w = bytestream2_get_le16u(&ctx->gb);
+ h = bytestream2_get_le16u(&ctx->gb);
+
+ if (!w || !h) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "dimensions are invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (ctx->width < left + w || ctx->height < top + h) {
+ if (av_image_check_size(FFMAX(left + w, ctx->width),
+ FFMAX(top + h, ctx->height), 0, ctx->avctx) < 0)
+ return AVERROR_INVALIDDATA;
+ avcodec_set_dimensions(ctx->avctx, FFMAX(left + w, ctx->width),
+ FFMAX(top + h, ctx->height));
+ init_sizes(ctx, FFMAX(left + w, ctx->width),
+ FFMAX(top + h, ctx->height));
+ if (init_buffers(ctx)) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "error resizing buffers\n");
+ return AVERROR(ENOMEM);
+ }
+ }
+ bytestream2_skip(&ctx->gb, 4);
+
+ av_dlog(ctx->avctx, "subcodec %d\n", codec);
+ switch (codec) {
+ case 1:
+ case 3:
+ return old_codec1(ctx, top, left, w, h);
+ break;
+ case 37:
+ return old_codec37(ctx, top, left, w, h);
+ break;
+ case 47:
+ return old_codec47(ctx, top, left, w, h);
+ break;
+ default:
+ avpriv_request_sample(ctx->avctx, "unknown subcodec %d", codec);
+ return AVERROR_PATCHWELCOME;
+ }
+}
+
+static int decode_0(SANMVideoContext *ctx)
+{
+ uint16_t *frm = ctx->frm0;
+ int x, y;
+
+ if (bytestream2_get_bytes_left(&ctx->gb) < ctx->width * ctx->height * 2) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "insufficient data for raw frame\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (y = 0; y < ctx->height; y++) {
+ for (x = 0; x < ctx->width; x++)
+ frm[x] = bytestream2_get_le16u(&ctx->gb);
+ frm += ctx->pitch;
+ }
+ return 0;
+}
+
+static int decode_nop(SANMVideoContext *ctx)
+{
+ avpriv_request_sample(ctx->avctx, "unknown/unsupported compression type");
+ return AVERROR_PATCHWELCOME;
+}
+
+static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, int pitch)
+{
+ uint8_t *dst = (uint8_t *)pdest;
+ uint8_t *src = (uint8_t *)psrc;
+ int stride = pitch * 2;
+
+ switch (block_size) {
+ case 2:
+ copy_block4(dst, src, stride, stride, 2);
+ break;
+ case 4:
+ copy_block8(dst, src, stride, stride, 4);
+ break;
+ case 8:
+ copy_block16(dst, src, stride, stride, 8);
+ break;
+ }
+}
+
+static void fill_block(uint16_t *pdest, uint16_t color, int block_size, int pitch)
+{
+ int x, y;
+
+ pitch -= block_size;
+ for (y = 0; y < block_size; y++, pdest += pitch)
+ for (x = 0; x < block_size; x++)
+ *pdest++ = color;
+}
+
+static int draw_glyph(SANMVideoContext *ctx, uint16_t *dst, int index, uint16_t fg_color,
+ uint16_t bg_color, int block_size, int pitch)
+{
+ int8_t *pglyph;
+ uint16_t colors[2] = { fg_color, bg_color };
+ int x, y;
+
+ if (index >= NGLYPHS) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "ignoring nonexistent glyph #%u\n", index);
+ return AVERROR_INVALIDDATA;
+ }
+
+ pglyph = block_size == 8 ? ctx->p8x8glyphs[index] : ctx->p4x4glyphs[index];
+ pitch -= block_size;
+
+ for (y = 0; y < block_size; y++, dst += pitch)
+ for (x = 0; x < block_size; x++)
+ *dst++ = colors[*pglyph++];
+ return 0;
+}
+
+static int opcode_0xf7(SANMVideoContext *ctx, int cx, int cy, int block_size, int pitch)
+{
+ uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
+
+ if (block_size == 2) {
+ uint32_t indices;
+
+ if (bytestream2_get_bytes_left(&ctx->gb) < 4)
+ return AVERROR_INVALIDDATA;
+
+ indices = bytestream2_get_le32u(&ctx->gb);
+ dst[0] = ctx->codebook[indices & 0xFF]; indices >>= 8;
+ dst[1] = ctx->codebook[indices & 0xFF]; indices >>= 8;
+ dst[pitch] = ctx->codebook[indices & 0xFF]; indices >>= 8;
+ dst[pitch + 1] = ctx->codebook[indices & 0xFF];
+ } else {
+ uint16_t fgcolor, bgcolor;
+ int glyph;
+
+ if (bytestream2_get_bytes_left(&ctx->gb) < 3)
+ return AVERROR_INVALIDDATA;
+
+ glyph = bytestream2_get_byteu(&ctx->gb);
+ bgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
+ fgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
+
+ draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
+ }
+ return 0;
+}
+
+static int opcode_0xf8(SANMVideoContext *ctx, int cx, int cy, int block_size, int pitch)
+{
+ uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
+
+ if (block_size == 2) {
+ if (bytestream2_get_bytes_left(&ctx->gb) < 8)
+ return AVERROR_INVALIDDATA;
+
+ dst[0] = bytestream2_get_le16u(&ctx->gb);
+ dst[1] = bytestream2_get_le16u(&ctx->gb);
+ dst[pitch] = bytestream2_get_le16u(&ctx->gb);
+ dst[pitch + 1] = bytestream2_get_le16u(&ctx->gb);
+ } else {
+ uint16_t fgcolor, bgcolor;
+ int glyph;
+
+ if (bytestream2_get_bytes_left(&ctx->gb) < 5)
+ return AVERROR_INVALIDDATA;
+
+ glyph = bytestream2_get_byteu(&ctx->gb);
+ bgcolor = bytestream2_get_le16u(&ctx->gb);
+ fgcolor = bytestream2_get_le16u(&ctx->gb);
+
+ draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
+ }
+ return 0;
+}
+
+static int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my,
+ int block_size)
+{
+ int start_pos = cx + mx + (cy + my) * ctx->pitch;
+ int end_pos = start_pos + (block_size - 1) * (ctx->pitch + 1);
+
+ int good = start_pos >= 0 && end_pos < (ctx->buf_size >> 1);
+
+ if (!good) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "ignoring invalid motion vector (%i, %i)->(%u, %u), block size = %u\n",
+ cx + mx, cy + my, cx, cy, block_size);
+ }
+
+ return good;
+}
+
+static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size)
+{
+ int16_t mx, my, index;
+ int opcode;
+
+ if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+ return AVERROR_INVALIDDATA;
+
+ opcode = bytestream2_get_byteu(&ctx->gb);
+
+ av_dlog(ctx->avctx, "opcode 0x%0X cx %d cy %d blk %d\n", opcode, cx, cy, blk_size);
+ switch (opcode) {
+ default:
+ mx = motion_vectors[opcode][0];
+ my = motion_vectors[opcode][1];
+
+ if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
+ copy_block(ctx->frm0 + cx + ctx->pitch * cy,
+ ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
+ blk_size, ctx->pitch);
+ }
+ break;
+ case 0xF5:
+ if (bytestream2_get_bytes_left(&ctx->gb) < 2)
+ return AVERROR_INVALIDDATA;
+ index = bytestream2_get_le16u(&ctx->gb);
+
+ mx = index % ctx->width;
+ my = index / ctx->width;
+
+ if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
+ copy_block(ctx->frm0 + cx + ctx->pitch * cy,
+ ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
+ blk_size, ctx->pitch);
+ }
+ break;
+ case 0xF6:
+ copy_block(ctx->frm0 + cx + ctx->pitch * cy,
+ ctx->frm1 + cx + ctx->pitch * cy,
+ blk_size, ctx->pitch);
+ break;
+ case 0xF7:
+ opcode_0xf7(ctx, cx, cy, blk_size, ctx->pitch);
+ break;
+
+ case 0xF8:
+ opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
+ break;
+ case 0xF9:
+ case 0xFA:
+ case 0xFB:
+ case 0xFC:
+ fill_block(ctx->frm0 + cx + cy * ctx->pitch,
+ ctx->small_codebook[opcode - 0xf9], blk_size, ctx->pitch);
+ break;
+ case 0xFD:
+ if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+ return AVERROR_INVALIDDATA;
+ fill_block(ctx->frm0 + cx + cy * ctx->pitch,
+ ctx->codebook[bytestream2_get_byteu(&ctx->gb)], blk_size, ctx->pitch);
+ break;
+ case 0xFE:
+ if (bytestream2_get_bytes_left(&ctx->gb) < 2)
+ return AVERROR_INVALIDDATA;
+ fill_block(ctx->frm0 + cx + cy * ctx->pitch,
+ bytestream2_get_le16u(&ctx->gb), blk_size, ctx->pitch);
+ break;
+ case 0xFF:
+ if (blk_size == 2) {
+ opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
+ } else {
+ blk_size >>= 1;
+ if (codec2subblock(ctx, cx , cy , blk_size))
+ return AVERROR_INVALIDDATA;
+ if (codec2subblock(ctx, cx + blk_size, cy , blk_size))
+ return AVERROR_INVALIDDATA;
+ if (codec2subblock(ctx, cx , cy + blk_size, blk_size))
+ return AVERROR_INVALIDDATA;
+ if (codec2subblock(ctx, cx + blk_size, cy + blk_size, blk_size))
+ return AVERROR_INVALIDDATA;
+ }
+ break;
+ }
+ return 0;
+}
+
+static int decode_2(SANMVideoContext *ctx)
+{
+ int cx, cy, ret;
+
+ for (cy = 0; cy < ctx->aligned_height; cy += 8) {
+ for (cx = 0; cx < ctx->aligned_width; cx += 8) {
+ if (ret = codec2subblock(ctx, cx, cy, 8))
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int decode_3(SANMVideoContext *ctx)
+{
+ memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size);
+ return 0;
+}
+
+static int decode_4(SANMVideoContext *ctx)
+{
+ memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size);
+ return 0;
+}
+
+static int decode_5(SANMVideoContext *ctx)
+{
+#if HAVE_BIGENDIAN
+ uint16_t *frm;
+ int npixels;
+#endif
+ uint8_t *dst = (uint8_t*)ctx->frm0;
+
+ if (rle_decode(ctx, dst, ctx->buf_size))
+ return AVERROR_INVALIDDATA;
+
+#if HAVE_BIGENDIAN
+ npixels = ctx->npixels;
+ frm = ctx->frm0;
+ while (npixels--) {
+ *frm = av_bswap16(*frm);
+ frm++;
+ }
+#endif
+
+ return 0;
+}
+
+static int decode_6(SANMVideoContext *ctx)
+{
+ int npixels = ctx->npixels;
+ uint16_t *frm = ctx->frm0;
+
+ if (bytestream2_get_bytes_left(&ctx->gb) < npixels) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "insufficient data for frame\n");
+ return AVERROR_INVALIDDATA;
+ }
+ while (npixels--)
+ *frm++ = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
+
+ return 0;
+}
+
+static int decode_8(SANMVideoContext *ctx)
+{
+ uint16_t *pdest = ctx->frm0;
+ uint8_t *rsrc;
+ long npixels = ctx->npixels;
+
+ av_fast_malloc(&ctx->rle_buf, &ctx->rle_buf_size, npixels);
+ if (!ctx->rle_buf) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "RLE buffer allocation failed\n");
+ return AVERROR(ENOMEM);
+ }
+ rsrc = ctx->rle_buf;
+
+ if (rle_decode(ctx, rsrc, npixels))
+ return AVERROR_INVALIDDATA;
+
+ while (npixels--)
+ *pdest++ = ctx->codebook[*rsrc++];
+
+ return 0;
+}
+
+typedef int (*frm_decoder)(SANMVideoContext *ctx);
+
+static const frm_decoder v1_decoders[] = {
+ decode_0, decode_nop, decode_2, decode_3, decode_4, decode_5,
+ decode_6, decode_nop, decode_8
+};
+
+static int read_frame_header(SANMVideoContext *ctx, SANMFrameHeader *hdr)
+{
+ int i, ret;
+
+ if ((ret = bytestream2_get_bytes_left(&ctx->gb)) < 560) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "too short input frame (%d bytes)\n",
+ ret);
+ return AVERROR_INVALIDDATA;
+ }
+ bytestream2_skip(&ctx->gb, 8); // skip pad
+
+ hdr->width = bytestream2_get_le32u(&ctx->gb);
+ hdr->height = bytestream2_get_le32u(&ctx->gb);
+
+ if (hdr->width != ctx->width || hdr->height != ctx->height) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "variable size frames are not implemented\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ hdr->seq_num = bytestream2_get_le16u(&ctx->gb);
+ hdr->codec = bytestream2_get_byteu(&ctx->gb);
+ hdr->rotate_code = bytestream2_get_byteu(&ctx->gb);
+
+ bytestream2_skip(&ctx->gb, 4); // skip pad
+
+ for (i = 0; i < 4; i++)
+ ctx->small_codebook[i] = bytestream2_get_le16u(&ctx->gb);
+ hdr->bg_color = bytestream2_get_le16u(&ctx->gb);
+
+ bytestream2_skip(&ctx->gb, 2); // skip pad
+
+ hdr->rle_output_size = bytestream2_get_le32u(&ctx->gb);
+ for (i = 0; i < 256; i++)
+ ctx->codebook[i] = bytestream2_get_le16u(&ctx->gb);
+
+ bytestream2_skip(&ctx->gb, 8); // skip pad
+
+ av_dlog(ctx->avctx, "subcodec %d\n", hdr->codec);
+ return 0;
+}
+
+static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color)
+{
+ while (buf_size--)
+ *pbuf++ = color;
+}
+
+static int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr)
+{
+ uint8_t *dst;
+ const uint8_t *src = (uint8_t*) ctx->frm0;
+ int ret, dstpitch, height = ctx->height;
+ int srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 1);
+
+ if ((ret = ff_get_buffer(ctx->avctx, ctx->frame, 0)) < 0)
+ return ret;
+
+ dst = ctx->frame->data[0];
+ dstpitch = ctx->frame->linesize[0];
+
+ while (height--) {
+ memcpy(dst, src, srcpitch);
+ src += srcpitch;
+ dst += dstpitch;
+ }
+
+ return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame_ptr, AVPacket *pkt)
+{
+ SANMVideoContext *ctx = avctx->priv_data;
+ int i, ret;
+
+ ctx->frame = data;
+ bytestream2_init(&ctx->gb, pkt->data, pkt->size);
+
+ if (!ctx->version) {
+ int to_store = 0;
+
+ while (bytestream2_get_bytes_left(&ctx->gb) >= 8) {
+ uint32_t sig, size;
+ int pos;
+
+ sig = bytestream2_get_be32u(&ctx->gb);
+ size = bytestream2_get_be32u(&ctx->gb);
+ pos = bytestream2_tell(&ctx->gb);
+
+ if (bytestream2_get_bytes_left(&ctx->gb) < size) {
+ av_log(avctx, AV_LOG_ERROR, "incorrect chunk size %d\n", size);
+ break;
+ }
+ switch (sig) {
+ case MKBETAG('N', 'P', 'A', 'L'):
+ if (size != 256 * 3) {
+ av_log(avctx, AV_LOG_ERROR, "incorrect palette block size %d\n",
+ size);
+ return AVERROR_INVALIDDATA;
+ }
+ for (i = 0; i < 256; i++)
+ ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
+ break;
+ case MKBETAG('F', 'O', 'B', 'J'):
+ if (size < 16)
+ return AVERROR_INVALIDDATA;
+ if (ret = process_frame_obj(ctx))
+ return ret;
+ break;
+ case MKBETAG('X', 'P', 'A', 'L'):
+ if (size == 6 || size == 4) {
+ uint8_t tmp[3];
+ int j;
+
+ for (i = 0; i < 256; i++) {
+ for (j = 0; j < 3; j++) {
+ int t = (ctx->pal[i] >> (16 - j * 8)) & 0xFF;
+ tmp[j] = av_clip_uint8((t * 129 + ctx->delta_pal[i * 3 + j]) >> 7);
+ }
+ ctx->pal[i] = 0xFFU << 24 | AV_RB24(tmp);
+ }
+ } else {
+ if (size < 768 * 2 + 4) {
+ av_log(avctx, AV_LOG_ERROR, "incorrect palette change block size %d\n",
+ size);
+ return AVERROR_INVALIDDATA;
+ }
+ bytestream2_skipu(&ctx->gb, 4);
+ for (i = 0; i < 768; i++)
+ ctx->delta_pal[i] = bytestream2_get_le16u(&ctx->gb);
+ if (size >= 768 * 5 + 4) {
+ for (i = 0; i < 256; i++)
+ ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
+ } else {
+ memset(ctx->pal, 0, sizeof(ctx->pal));
+ }
+ }
+ break;
+ case MKBETAG('S', 'T', 'O', 'R'):
+ to_store = 1;
+ break;
+ case MKBETAG('F', 'T', 'C', 'H'):
+ memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size);
+ break;
+ default:
+ bytestream2_skip(&ctx->gb, size);
+ av_log(avctx, AV_LOG_DEBUG, "unknown/unsupported chunk %x\n", sig);
+ break;
+ }
+
+ bytestream2_seek(&ctx->gb, pos + size, SEEK_SET);
+ if (size & 1)
+ bytestream2_skip(&ctx->gb, 1);
+ }
+ if (to_store)
+ memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size);
+ if ((ret = copy_output(ctx, NULL)))
+ return ret;
+ memcpy(ctx->frame->data[1], ctx->pal, 1024);
+ } else {
+ SANMFrameHeader header;
+
+ if ((ret = read_frame_header(ctx, &header)))
+ return ret;
+
+ ctx->rotate_code = header.rotate_code;
+ if ((ctx->frame->key_frame = !header.seq_num)) {
+ ctx->frame->pict_type = AV_PICTURE_TYPE_I;
+ fill_frame(ctx->frm1, ctx->npixels, header.bg_color);
+ fill_frame(ctx->frm2, ctx->npixels, header.bg_color);
+ } else {
+ ctx->frame->pict_type = AV_PICTURE_TYPE_P;
+ }
+
+ if (header.codec < FF_ARRAY_ELEMS(v1_decoders)) {
+ if ((ret = v1_decoders[header.codec](ctx))) {
+ av_log(avctx, AV_LOG_ERROR,
+ "subcodec %d: error decoding frame\n", header.codec);
+ return ret;
+ }
+ } else {
+ avpriv_request_sample(avctx, "subcodec %d",
+ header.codec);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ if ((ret = copy_output(ctx, &header)))
+ return ret;
+ }
+ if (ctx->rotate_code)
+ rotate_bufs(ctx, ctx->rotate_code);
+
+ *got_frame_ptr = 1;
+
+ return pkt->size;
+}
+
+AVCodec ff_sanm_decoder = {
+ .name = "sanm",
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts SMUSH video"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_SANM,
+ .priv_data_size = sizeof(SANMVideoContext),
+ .init = decode_init,
+ .close = decode_end,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/sanm_data.h b/libavcodec/sanm_data.h
new file mode 100644
index 0000000..8fccf38
--- a/dev/null
+++ b/libavcodec/sanm_data.h
@@ -0,0 +1,248 @@
+/*
+ * LucasArts Smush video decoder
+ * Copyright (c) 2006 Cyril Zorin
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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_SANM_DATA_H
+#define AVCODEC_SANM_DATA_H
+
+#include <stdint.h>
+
+#define GLYPH_COORD_VECT_SIZE 16
+
+static const int8_t glyph4_x[GLYPH_COORD_VECT_SIZE] =
+ { 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 };
+static const int8_t glyph4_y[GLYPH_COORD_VECT_SIZE] =
+ { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 };
+static const int8_t glyph8_x[GLYPH_COORD_VECT_SIZE] =
+ { 0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0 };
+static const int8_t glyph8_y[GLYPH_COORD_VECT_SIZE] =
+ { 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1 };
+
+static const int8_t motion_vectors[256][2] =
+{
+ { 0, 0}, { -1, -43}, { 6, -43}, { -9, -42}, { 13, -41},
+ {-16, -40}, { 19, -39}, {-23, -36}, { 26, -34}, { -2, -33},
+ { 4, -33}, {-29, -32}, { -9, -32}, { 11, -31}, {-16, -29},
+ { 32, -29}, { 18, -28}, {-34, -26}, {-22, -25}, { -1, -25},
+ { 3, -25}, { -7, -24}, { 8, -24}, { 24, -23}, { 36, -23},
+ {-12, -22}, { 13, -21}, {-38, -20}, { 0, -20}, {-27, -19},
+ { -4, -19}, { 4, -19}, {-17, -18}, { -8, -17}, { 8, -17},
+ { 18, -17}, { 28, -17}, { 39, -17}, {-12, -15}, { 12, -15},
+ {-21, -14}, { -1, -14}, { 1, -14}, {-41, -13}, { -5, -13},
+ { 5, -13}, { 21, -13}, {-31, -12}, {-15, -11}, { -8, -11},
+ { 8, -11}, { 15, -11}, { -2, -10}, { 1, -10}, { 31, -10},
+ {-23, -9}, {-11, -9}, { -5, -9}, { 4, -9}, { 11, -9},
+ { 42, -9}, { 6, -8}, { 24, -8}, {-18, -7}, { -7, -7},
+ { -3, -7}, { -1, -7}, { 2, -7}, { 18, -7}, {-43, -6},
+ {-13, -6}, { -4, -6}, { 4, -6}, { 8, -6}, {-33, -5},
+ { -9, -5}, { -2, -5}, { 0, -5}, { 2, -5}, { 5, -5},
+ { 13, -5}, {-25, -4}, { -6, -4}, { -3, -4}, { 3, -4},
+ { 9, -4}, {-19, -3}, { -7, -3}, { -4, -3}, { -2, -3},
+ { -1, -3}, { 0, -3}, { 1, -3}, { 2, -3}, { 4, -3},
+ { 6, -3}, { 33, -3}, {-14, -2}, {-10, -2}, { -5, -2},
+ { -3, -2}, { -2, -2}, { -1, -2}, { 0, -2}, { 1, -2},
+ { 2, -2}, { 3, -2}, { 5, -2}, { 7, -2}, { 14, -2},
+ { 19, -2}, { 25, -2}, { 43, -2}, { -7, -1}, { -3, -1},
+ { -2, -1}, { -1, -1}, { 0, -1}, { 1, -1}, { 2, -1},
+ { 3, -1}, { 10, -1}, { -5, 0}, { -3, 0}, { -2, 0},
+ { -1, 0}, { 1, 0}, { 2, 0}, { 3, 0}, { 5, 0},
+ { 7, 0}, {-10, 1}, { -7, 1}, { -3, 1}, { -2, 1},
+ { -1, 1}, { 0, 1}, { 1, 1}, { 2, 1}, { 3, 1},
+ {-43, 2}, {-25, 2}, {-19, 2}, {-14, 2}, { -5, 2},
+ { -3, 2}, { -2, 2}, { -1, 2}, { 0, 2}, { 1, 2},
+ { 2, 2}, { 3, 2}, { 5, 2}, { 7, 2}, { 10, 2},
+ { 14, 2}, {-33, 3}, { -6, 3}, { -4, 3}, { -2, 3},
+ { -1, 3}, { 0, 3}, { 1, 3}, { 2, 3}, { 4, 3},
+ { 19, 3}, { -9, 4}, { -3, 4}, { 3, 4}, { 7, 4},
+ { 25, 4}, {-13, 5}, { -5, 5}, { -2, 5}, { 0, 5},
+ { 2, 5}, { 5, 5}, { 9, 5}, { 33, 5}, { -8, 6},
+ { -4, 6}, { 4, 6}, { 13, 6}, { 43, 6}, {-18, 7},
+ { -2, 7}, { 0, 7}, { 2, 7}, { 7, 7}, { 18, 7},
+ {-24, 8}, { -6, 8}, {-42, 9}, {-11, 9}, { -4, 9},
+ { 5, 9}, { 11, 9}, { 23, 9}, {-31, 10}, { -1, 10},
+ { 2, 10}, {-15, 11}, { -8, 11}, { 8, 11}, { 15, 11},
+ { 31, 12}, {-21, 13}, { -5, 13}, { 5, 13}, { 41, 13},
+ { -1, 14}, { 1, 14}, { 21, 14}, {-12, 15}, { 12, 15},
+ {-39, 17}, {-28, 17}, {-18, 17}, { -8, 17}, { 8, 17},
+ { 17, 18}, { -4, 19}, { 0, 19}, { 4, 19}, { 27, 19},
+ { 38, 20}, {-13, 21}, { 12, 22}, {-36, 23}, {-24, 23},
+ { -8, 24}, { 7, 24}, { -3, 25}, { 1, 25}, { 22, 25},
+ { 34, 26}, {-18, 28}, {-32, 29}, { 16, 29}, {-11, 31},
+ { 9, 32}, { 29, 32}, { -4, 33}, { 2, 33}, {-26, 34},
+ { 23, 36}, {-19, 39}, { 16, 40}, {-13, 41}, { 9, 42},
+ { -6, 43}, { 1, 43}, { 0, 0}, { 0, 0}, { 0, 0},
+};
+
+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,
+};
+#endif /* AVCODEC_SANM_DATA_H */
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 4d07af5..b4d5824 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;
}
@@ -285,4 +286,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 ca531f0..be17f2e 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 476311d..e373825 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"
@@ -40,7 +41,7 @@ typedef struct SgiState {
* @param out_buf Points to one line after the output buffer.
* @param out_end end of line in output buffer
* @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_row(SgiState *s, uint8_t *out_buf,
uint8_t *out_end, int pixelstride)
@@ -48,16 +49,17 @@ static int expand_rle_row(SgiState *s, uint8_t *out_buf,
unsigned char pixel, count;
unsigned char *orig = out_buf;
- while (1) {
+ while (out_buf < out_end) {
if (bytestream2_get_bytes_left(&s->g) < 1)
return AVERROR_INVALIDDATA;
pixel = bytestream2_get_byteu(&s->g);
if (!(count = (pixel & 0x7f))) {
- return (out_buf - orig) / pixelstride;
+ break;
}
/* Check for buffer overflow. */
- if(out_buf + pixelstride * count >= out_end) return -1;
+ if (out_end - out_buf <= pixelstride * (count - 1))
+ return AVERROR_INVALIDDATA;
if (pixel & 0x80) {
while (count--) {
@@ -73,13 +75,14 @@ static int expand_rle_row(SgiState *s, uint8_t *out_buf,
}
}
}
+ return (out_buf - orig) / pixelstride;
}
/**
* 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)
{
@@ -100,7 +103,7 @@ static int read_rle_sgi(uint8_t *out_buf, SgiState *s)
dest_row -= s->linesize;
start_offset = bytestream2_get_be32(&g_table);
bytestream2_seek(&s->g, start_offset, SEEK_SET);
- if (expand_rle_row(s, dest_row + z, dest_row + FFABS(s->linesize),
+ if (expand_rle_row(s, dest_row + z, dest_row + s->width*s->depth,
s->depth) != s->width) {
return AVERROR_INVALIDDATA;
}
@@ -112,16 +115,15 @@ static int read_rle_sgi(uint8_t *out_buf, SgiState *s)
/**
* Read an uncompressed SGI image.
* @param out_buf output buffer
- * @param out_end end ofoutput 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, uint8_t* out_end,
- SgiState *s)
+static int read_uncompressed_sgi(unsigned char* out_buf, SgiState *s)
{
int x, y, z;
unsigned int offset = s->height * s->width * s->bytes_per_channel;
GetByteContext gp[4];
+ uint8_t *out_end;
/* Test buffer size. */
if (offset * s->depth > bytestream2_get_bytes_left(&s->g))
@@ -166,48 +168,46 @@ 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 || rle)) {
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) {
avctx->pix_fmt = s->bytes_per_channel == 2 ? AV_PIX_FMT_GRAY16BE : AV_PIX_FMT_GRAY8;
} else if (s->depth == SGI_RGB) {
avctx->pix_fmt = s->bytes_per_channel == 2 ? AV_PIX_FMT_RGB48BE : AV_PIX_FMT_RGB24;
- } else if (s->depth == SGI_RGBA && s->bytes_per_channel == 1) {
- avctx->pix_fmt = AV_PIX_FMT_RGBA;
+ } else if (s->depth == SGI_RGBA) {
+ 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;
}
if (av_image_check_size(s->width, s->height, 0, avctx))
- return -1;
+ return AVERROR_INVALIDDATA;
avcodec_set_dimensions(avctx, s->width, s->height);
- 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;
@@ -222,15 +222,13 @@ static int decode_frame(AVCodecContext *avctx,
if (rle) {
ret = read_rle_sgi(out_end, s);
} else {
- ret = read_uncompressed_sgi(out_buf, out_end, s);
+ 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;
}
AVCodec ff_sgi_decoder = {
diff --git a/libavcodec/sgienc.c b/libavcodec/sgienc.c
index 6a595c7..48532ff 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
*/
@@ -28,16 +28,12 @@
#define SGI_SINGLE_CHAN 2
#define SGI_MULTI_CHAN 3
-typedef struct SgiContext {
- AVFrame picture;
-} SgiContext;
-
static av_cold int encode_init(AVCodecContext *avctx)
{
- SgiContext *s = avctx->priv_data;
-
- avcodec_get_frame_defaults(&s->picture);
- avctx->coded_frame = &s->picture;
+ if (avctx->width > 65535 || avctx->height > 65535) {
+ av_log(avctx, AV_LOG_ERROR, "SGI does not support resolutions above 65535x65535\n");
+ return -1;
+ }
return 0;
}
@@ -45,19 +41,20 @@ static av_cold int encode_init(AVCodecContext *avctx)
static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *frame, int *got_packet)
{
- SgiContext *s = avctx->priv_data;
- AVFrame * const p = &s->picture;
+ AVFrame * const p = (AVFrame *)frame;
uint8_t *offsettab, *lengthtab, *in_buf, *encode_buf, *buf;
int x, y, z, length, tablesize, ret;
- unsigned int width, height, depth, dimension;
+ unsigned int width, height, depth, dimension, bytes_per_channel, pixmax, put_be;
unsigned char *end_buf;
- *p = *frame;
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
width = avctx->width;
height = avctx->height;
+ bytes_per_channel = 1;
+ pixmax = 0xFF;
+ put_be = HAVE_BIGENDIAN;
switch (avctx->pix_fmt) {
case AV_PIX_FMT_GRAY8:
@@ -72,6 +69,33 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
dimension = SGI_MULTI_CHAN;
depth = SGI_RGBA;
break;
+ case AV_PIX_FMT_GRAY16LE:
+ put_be = !HAVE_BIGENDIAN;
+ case AV_PIX_FMT_GRAY16BE:
+ avctx->coder_type = FF_CODER_TYPE_RAW;
+ bytes_per_channel = 2;
+ pixmax = 0xFFFF;
+ dimension = SGI_SINGLE_CHAN;
+ depth = SGI_GRAYSCALE;
+ break;
+ case AV_PIX_FMT_RGB48LE:
+ put_be = !HAVE_BIGENDIAN;
+ case AV_PIX_FMT_RGB48BE:
+ avctx->coder_type = FF_CODER_TYPE_RAW;
+ bytes_per_channel = 2;
+ pixmax = 0xFFFF;
+ dimension = SGI_MULTI_CHAN;
+ depth = SGI_RGB;
+ break;
+ case AV_PIX_FMT_RGBA64LE:
+ put_be = !HAVE_BIGENDIAN;
+ case AV_PIX_FMT_RGBA64BE:
+ avctx->coder_type = FF_CODER_TYPE_RAW;
+ bytes_per_channel = 2;
+ pixmax = 0xFFFF;
+ dimension = SGI_MULTI_CHAN;
+ depth = SGI_RGBA;
+ break;
default:
return AVERROR_INVALIDDATA;
}
@@ -83,25 +107,22 @@ 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, 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;
/* Encode header. */
bytestream_put_be16(&buf, SGI_MAGIC);
bytestream_put_byte(&buf, avctx->coder_type != FF_CODER_TYPE_RAW); /* RLE 1 - VERBATIM 0*/
- bytestream_put_byte(&buf, 1); /* bytes_per_channel */
+ bytestream_put_byte(&buf, bytes_per_channel);
bytestream_put_be16(&buf, dimension);
bytestream_put_be16(&buf, width);
bytestream_put_be16(&buf, height);
bytestream_put_be16(&buf, depth);
- /* The rest are constant in this implementation. */
bytestream_put_be32(&buf, 0L); /* pixmin */
- bytestream_put_be32(&buf, 255L); /* pixmax */
+ bytestream_put_be32(&buf, pixmax);
bytestream_put_be32(&buf, 0L); /* dummy */
/* name */
@@ -151,11 +172,19 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
av_free(encode_buf);
} else {
for (z = 0; z < depth; z++) {
- in_buf = p->data[0] + p->linesize[0] * (height - 1) + z;
+ in_buf = p->data[0] + p->linesize[0] * (height - 1) + z * bytes_per_channel;
for (y = 0; y < height; y++) {
for (x = 0; x < width * depth; x += depth)
+ if (bytes_per_channel == 1) {
bytestream_put_byte(&buf, in_buf[x]);
+ } else {
+ if (put_be) {
+ bytestream_put_be16(&buf, ((uint16_t *)in_buf)[x]);
+ } else {
+ bytestream_put_le16(&buf, ((uint16_t *)in_buf)[x]);
+ }
+ }
in_buf -= p->linesize[0];
}
@@ -175,10 +204,13 @@ AVCodec ff_sgi_encoder = {
.long_name = NULL_IF_CONFIG_SMALL("SGI image"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_SGI,
- .priv_data_size = sizeof(SgiContext),
.init = encode_init,
.encode2 = encode_frame,
.pix_fmts = (const enum AVPixelFormat[]){
- AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA,
+ AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGB48BE,
+ AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_RGBA64BE,
+ AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
},
};
diff --git a/libavcodec/sgirledec.c b/libavcodec/sgirledec.c
new file mode 100644
index 0000000..fd3cc5e
--- a/dev/null
+++ b/libavcodec/sgirledec.c
@@ -0,0 +1,151 @@
+/*
+ * SGI RLE 8-bit decoder
+ * Copyright (c) 2012 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
+ * SGI RLE 8-bit decoder
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+
+typedef struct SGIRLEContext {
+ AVFrame *frame;
+} SGIRLEContext;
+
+static av_cold int sgirle_decode_init(AVCodecContext *avctx)
+{
+ SGIRLEContext *s = avctx->priv_data;
+ avctx->pix_fmt = AV_PIX_FMT_BGR8;
+ s->frame = av_frame_alloc();
+ if (!s->frame)
+ return AVERROR(ENOMEM);
+ return 0;
+}
+
+/**
+ * Convert SGI RGB332 pixel into AV_PIX_FMT_BGR8
+ * SGI RGB332 is packed RGB 3:3:2, 8bpp, (msb)3R 2B 3G(lsb)
+ */
+#define RGB332_TO_BGR8(x) (((x << 3) & 0xC0) | ((x << 3) & 0x38) | ((x >> 5) & 7))
+
+static av_always_inline void memcpy_rgb332_to_bgr8(uint8_t *dst, const uint8_t *src, int size)
+{
+ int i;
+ for (i = 0; i < size; i++)
+ dst[i] = RGB332_TO_BGR8(src[i]);
+}
+
+/**
+ * @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)
+ * @return <0 on error
+ */
+static int decode_sgirle8(AVCodecContext *avctx, 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;
+
+#define INC_XY(n) \
+ x += n; \
+ if (x >= width) { \
+ y++; \
+ if (y >= height) \
+ return 0; \
+ x = 0; \
+ }
+
+ while (src_end - src >= 2) {
+ uint8_t v = *src++;
+ if (v > 0 && v < 0xC0) {
+ do {
+ int length = FFMIN(v, width - x);
+ if (length <= 0)
+ break;
+ memset(dst + y*linesize + x, RGB332_TO_BGR8(*src), length);
+ INC_XY(length);
+ v -= length;
+ } while (v > 0);
+ src++;
+ } else if (v >= 0xC1) {
+ v -= 0xC0;
+ do {
+ int length = FFMIN3(v, width - x, src_end - src);
+ if (src_end - src < length || length <= 0)
+ break;
+ memcpy_rgb332_to_bgr8(dst + y*linesize + x, src, length);
+ INC_XY(length);
+ src += length;
+ v -= length;
+ } while (v > 0);
+ } else {
+ avpriv_request_sample(avctx, "opcode %d", v);
+ return AVERROR_PATCHWELCOME;
+ }
+ }
+ return 0;
+}
+
+static int sgirle_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ SGIRLEContext *s = avctx->priv_data;
+ int ret;
+
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
+ return ret;
+
+ ret = decode_sgirle8(avctx, s->frame->data[0], avpkt->data, avpkt->size, avctx->width, avctx->height, s->frame->linesize[0]);
+ if (ret < 0)
+ return ret;
+
+ *got_frame = 1;
+ if ((ret = av_frame_ref(data, s->frame)) < 0)
+ return ret;
+
+ return avpkt->size;
+}
+
+static av_cold int sgirle_decode_end(AVCodecContext *avctx)
+{
+ SGIRLEContext *s = avctx->priv_data;
+
+ av_frame_free(&s->frame);
+
+ return 0;
+}
+
+AVCodec ff_sgirle_decoder = {
+ .name = "sgirle",
+ .long_name = NULL_IF_CONFIG_SMALL("SGI RLE 8-bit"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_SGIRLE,
+ .priv_data_size = sizeof(SGIRLEContext),
+ .init = sgirle_decode_init,
+ .close = sgirle_decode_end,
+ .decode = sgirle_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/sh4/dsputil_sh4.c b/libavcodec/sh4/dsputil_sh4.c
index 6fd287d..82b75ae 100644
--- a/libavcodec/sh4/dsputil_sh4.c
+++ b/libavcodec/sh4/dsputil_sh4.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2003 BERO <bero@geocities.co.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/sh4/dsputil_sh4.h b/libavcodec/sh4/dsputil_sh4.h
index 9c2b311..2ba9354 100644
--- a/libavcodec/sh4/dsputil_sh4.h
+++ b/libavcodec/sh4/dsputil_sh4.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 "libavcodec/avcodec.h"
#include "libavcodec/dsputil.h"
+#include "libavcodec/hpeldsp.h"
void ff_idct_sh4(int16_t *block);
diff --git a/libavcodec/sh4/idct_sh4.c b/libavcodec/sh4/idct_sh4.c
index 768b334..d4e8711 100644
--- a/libavcodec/sh4/idct_sh4.c
+++ b/libavcodec/sh4/idct_sh4.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2001-2003 BERO <bero@geocities.co.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/sh4/sh4.h b/libavcodec/sh4/sh4.h
index acd12e6..5d46540 100644
--- a/libavcodec/sh4/sh4.h
+++ b/libavcodec/sh4/sh4.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/libavcodec/shorten.c b/libavcodec/shorten.c
index 31251ac..c25097c 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;
}
@@ -182,13 +185,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++)
@@ -200,7 +207,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;
@@ -221,7 +228,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;
}
@@ -247,10 +254,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);
}
@@ -261,18 +269,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 },
@@ -436,9 +432,9 @@ 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);
+ 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);
@@ -451,7 +447,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);
@@ -565,7 +561,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 */
@@ -604,15 +600,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;
}
@@ -665,5 +676,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..73f62b4 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
diff --git a/libavcodec/simple_idct.h b/libavcodec/simple_idct.h
index e257290..7c0734b 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 367bc34..64a7be0 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
*/
@@ -62,8 +62,9 @@
#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
+#if BIT_DEPTH == 10
#define W1 90901
#define W2 85627
#define W3 77062
@@ -75,6 +76,19 @@
#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))
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..17260a0 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
*/
@@ -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..bfd8ade 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"
diff --git a/libavcodec/sipr16kdata.h b/libavcodec/sipr16kdata.h
index ec60c29..96bf0e9 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
*/
diff --git a/libavcodec/siprdata.h b/libavcodec/siprdata.h
index 92037a4..ed804ee 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
*/
diff --git a/libavcodec/smacker.c b/libavcodec/smacker.c
index ffd816f..3cdb0d5 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
*/
@@ -48,7 +48,7 @@
*/
typedef struct SmackVContext {
AVCodecContext *avctx;
- AVFrame pic;
+ AVFrame *pic;
int *mmap_tbl, *mclr_tbl, *full_tbl, *type_tbl;
int mmap_last[3], mclr_last[3], full_last[3], type_last[3];
@@ -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;
@@ -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,39 +408,38 @@ 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];
+ pal = (uint32_t*)smk->pic->data[1];
bytestream2_init(&gb2, avpkt->data, avpkt->size);
flags = bytestream2_get_byteu(&gb2);
- smk->pic.palette_has_changed = flags & 1;
- smk->pic.key_frame = !!(flags & 2);
- if(smk->pic.key_frame)
- smk->pic.pict_type = AV_PICTURE_TYPE_I;
+ smk->pic->palette_has_changed = flags & 1;
+ smk->pic->key_frame = !!(flags & 2);
+ if (smk->pic->key_frame)
+ smk->pic->pict_type = AV_PICTURE_TYPE_I;
else
- smk->pic.pict_type = AV_PICTURE_TYPE_P;
+ 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];
+ out = smk->pic->data[0];
+ stride = smk->pic->linesize[0];
while(blk < blocks) {
int type, run, mode;
uint16_t pix;
@@ -435,7 +453,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
int hi, lo;
clr = smk_get_code(&gb, smk->mclr_tbl, smk->mclr_last);
map = smk_get_code(&gb, smk->mmap_tbl, smk->mmap_last);
- out = smk->pic.data[0] + (blk / bw) * (stride * 4) + (blk % bw) * 4;
+ out = smk->pic->data[0] + (blk / bw) * (stride * 4) + (blk % bw) * 4;
hi = clr >> 8;
lo = clr & 0xFF;
for(i = 0; i < 4; i++) {
@@ -456,7 +474,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
else if(get_bits1(&gb)) mode = 2;
}
while(run-- && blk < blocks){
- out = smk->pic.data[0] + (blk / bw) * (stride * 4) + (blk % bw) * 4;
+ out = smk->pic->data[0] + (blk / bw) * (stride * 4) + (blk % bw) * 4;
switch(mode){
case 0:
for(i = 0; i < 4; i++) {
@@ -508,7 +526,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
mode = type >> 8;
while(run-- && blk < blocks){
uint32_t col;
- out = smk->pic.data[0] + (blk / bw) * (stride * 4) + (blk % bw) * 4;
+ out = smk->pic->data[0] + (blk / bw) * (stride * 4) + (blk % bw) * 4;
col = mode * 0x01010101;
for(i = 0; i < 4; i++) {
*((uint32_t*)out) = col;
@@ -521,7 +539,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
}
- if ((ret = av_frame_ref(data, &smk->pic)) < 0)
+ if ((ret = av_frame_ref(data, smk->pic)) < 0)
return ret;
*got_frame = 1;
@@ -546,7 +564,7 @@ static av_cold int decode_end(AVCodecContext *avctx)
av_freep(&smk->full_tbl);
av_freep(&smk->type_tbl);
- av_frame_unref(&smk->pic);
+ av_frame_free(&smk->pic);
return 0;
}
@@ -560,28 +578,32 @@ 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;
avctx->pix_fmt = AV_PIX_FMT_PAL8;
- avcodec_get_frame_defaults(&c->pic);
/* 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;
}
+ c->pic = av_frame_alloc();
+ if (!c->pic)
+ return AVERROR(ENOMEM);
+
return 0;
}
-
static av_cold int smka_decode_init(AVCodecContext *avctx)
{
if (avctx->channels < 1 || avctx->channels > 2) {
@@ -621,7 +643,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");
@@ -641,10 +669,8 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
/* 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];
@@ -684,16 +710,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];
@@ -702,11 +738,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];
@@ -718,11 +762,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 {
@@ -730,6 +780,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 d28597b..3b836e7 100644
--- a/libavcodec/smc.c
+++ b/libavcodec/smc.c
@@ -2,20 +2,20 @@
* Quicktime Graphics (SMC) Video Decoder
* Copyright (C) 2003 the ffmpeg project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -84,7 +84,7 @@ static void smc_decode_stream(SmcContext *s)
int stride = s->frame.linesize[0];
int i;
int chunk_size;
- int buf_size = (int) (s->gb.buffer_end - s->gb.buffer_start);
+ int buf_size = bytestream2_size(&s->gb);
unsigned char opcode;
int n_blocks;
unsigned int color_flags;
@@ -434,10 +434,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..f883ecf
--- a/dev/null
+++ b/libavcodec/smvjpegdec.c
@@ -0,0 +1,205 @@
+/*
+ * 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 */
+ avcodec_set_dimensions(avctx, mjpeg_data->width,
+ mjpeg_data->height / s->frames_per_jpeg);
+
+ 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;
+
+ jpg->picture_ptr = NULL;
+ av_frame_free(&s->picture[0]);
+ av_frame_free(&s->picture[1]);
+ ff_codec_close_recursive(s->avctx);
+ av_freep(&s->avctx);
+ return 0;
+}
+
+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..b54c491
--- a/dev/null
+++ b/libavcodec/snow.c
@@ -0,0 +1,708 @@
+/*
+ * 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 "dsputil.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;
+ }
+ }
+ }
+}
+
+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(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, 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, stride, src, 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(b_w>1 && b_h>1);
+ 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)) || !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_dsputil_init(&s->dsp, 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->dsp.put_qpel_pixels_tab [0][dy+dx/4]=\
+ s->dsp.put_no_rnd_qpel_pixels_tab[0][dy+dx/4]=\
+ s->h264qpel.put_h264_qpel_pixels_tab[0][dy+dx/4];\
+ s->dsp.put_qpel_pixels_tab [1][dy+dx/4]=\
+ s->dsp.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_OR_GOTO(avctx, s->spatial_idwt_buffer, width * height * sizeof(IDWTELEM), fail);
+ FF_ALLOCZ_OR_GOTO(avctx, s->spatial_dwt_buffer, width * height * sizeof(DWTELEM), fail); //FIXME this does not belong here
+ FF_ALLOCZ_OR_GOTO(avctx, s->temp_dwt_buffer, width * sizeof(DWTELEM), fail);
+ FF_ALLOCZ_OR_GOTO(avctx, s->temp_idwt_buffer, width * sizeof(IDWTELEM), fail);
+ FF_ALLOC_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_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(((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;
+ int w= s->avctx->width; //FIXME round up to x16 ?
+ int h= s->avctx->height;
+
+ if (s->current_picture->data[0] && !(s->avctx->flags&CODEC_FLAG_EMU_EDGE)) {
+ s->dsp.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->dsp.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->dsp.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_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_get_buffer(s->avctx, s->current_picture, AV_GET_BUFFER_FLAG_REF)) < 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]->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..1222a77
--- a/dev/null
+++ b/libavcodec/snow.h
@@ -0,0 +1,704 @@
+/*
+ * 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 "dsputil.h"
+#include "hpeldsp.h"
+#include "snow_dwt.h"
+
+#include "rangecoder.h"
+#include "mathops.h"
+#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;
+ DSPContext dsp;
+ HpelDSPContext hdsp;
+ VideoDSPContext vdsp;
+ H264QpelContext h264qpel;
+ SnowDWTContext dwt;
+ 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, BlockNode *block,
+ int plane_index, int w, int h);
+/* 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;
+ }else 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;
+ }else 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]]);
+
+ 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]);
+
+ 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..28edf6a
--- a/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 "dsputil.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(sizeof(IDWTELEM *) * line_count);
+ if (!buf->line)
+ return AVERROR(ENOMEM);
+ buf->data_stack = av_malloc(sizeof(IDWTELEM *) * max_allocated_lines);
+ 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(sizeof(IDWTELEM) * line_width);
+ 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(void *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(void *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(void *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(void *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(void *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(void *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(void *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(DSPContext *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..0806b38
--- a/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(void *v, uint8_t *pix1, uint8_t *pix2, int line_size, int h);
+int ff_w97_32_c(void *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
--- a/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..c9d40b8
--- a/dev/null
+++ b/libavcodec/snowdec.c
@@ -0,0 +1,598 @@
+/*
+ * 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 "dsputil.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 -1;\
+ }\
+ 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 -1;
+ 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 -1;
+ }
+ 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 -1;
+ }
+
+
+ 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 -1;
+ }
+
+ 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(decode_header(s)<0)
+ return -1;
+ 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(ff_snow_frame_start(s) < 0)
+ return -1;
+ //keyframe flag duplication mess FIXME
+ if(avctx->debug&FF_DEBUG_PICT_INFO)
+ av_log(avctx, AV_LOG_ERROR, "keyframe:%d qlog:%d\n", s->keyframe, s->qlog);
+
+ 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))
+ av_frame_ref(picture, s->current_picture);
+ else
+ av_frame_ref(picture, s->mconly_picture);
+
+ *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..5177285
--- a/dev/null
+++ b/libavcodec/snowenc.c
@@ -0,0 +1,2018 @@
+/*
+ * 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 "dsputil.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;
+
+ if(avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL){
+ av_log(avctx, AV_LOG_ERROR, "This codec 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 -1;
+ }
+
+ 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_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((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->dsp, s->dsp.me_cmp, s->avctx->me_cmp);
+ ff_set_cmp(&s->dsp, s->dsp.me_sub_cmp, s->avctx->me_sub_cmp);
+
+ s->input_picture = av_frame_alloc();
+ if (!s->input_picture)
+ return AVERROR(ENOMEM);
+ if ((ret = ff_get_buffer(s->avctx, s->input_picture, AV_GET_BUFFER_FLAG_REF)) < 0)
+ return ret;
+
+ if(s->avctx->me_method == ME_ITER){
+ int i;
+ 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(size*sizeof(int16_t[2]));
+ s->ref_scores[i]= av_mallocz(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_squareTbl + 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;
+
+// assert(score==256*256*256*64-1);
+ 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->dsp.me_cmp[0](&s->m, src + off, dst + off, ref_stride, 16);
+ }
+ }
+ }else{
+ av_assert2(block_w==8);
+ distortion = s->dsp.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->dsp.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 */
+ coef_sum = (uint64_t)coef_sum * coef_sum >> 16;
+ av_assert0(coef_sum < INT_MAX);
+
+ 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,
+ 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->dsp.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
+
+ ff_snow_frame_start(s);
+ avctx->coded_frame= s->current_picture;
+
+ s->m.current_picture_ptr= &s->m.current_picture;
+ s->m.last_picture.f.pts = s->m.current_picture.f.pts;
+ 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.current_picture.f.data[0] = s->current_picture->data[0];
+ s->m. last_picture.f.data[0] = s->last_picture[0]->data[0];
+ s->m. new_picture.f.data[0] = s-> input_picture->data[0];
+ s->m. last_picture_ptr= &s->m. last_picture;
+ s->m.linesize=
+ s->m. last_picture.f.linesize[0] =
+ s->m. new_picture.f.linesize[0] =
+ s->m.current_picture.f.linesize[0] = 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.dsp= s->dsp; //move
+ s->m.hdsp = s->hdsp;
+ ff_init_me(&s->m);
+ s->hdsp = s->m.hdsp;
+ s->dsp= s->m.dsp;
+ }
+
+ 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:
+
+ if (pic->pict_type == AV_PICTURE_TYPE_I)
+ s->spatial_decomposition_count= 5;
+ else
+ 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[] = {
+ { "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..31bbe46
--- a/dev/null
+++ b/libavcodec/sonic.c
@@ -0,0 +1,989 @@
+/*
+ * 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"
+
+/**
+ * @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 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);
+}
+
+#if 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, version = 0;
+
+ 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, version); // version
+ if (version == 1)
+ {
+ 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 ls: %d dr: %d taps: %d block: %d frame: %d downsamp: %d\n",
+ 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;
+ PutBitContext pb;
+ int i, j, ch, quant = 0, x = 0;
+ int ret;
+ const short *samples = (const int16_t*)frame->data[0];
+
+ if ((ret = ff_alloc_packet2(avctx, avpkt, s->frame_size * 5 + 1000)) < 0)
+ return ret;
+
+ init_put_bits(&pb, avpkt->data, avpkt->size);
+
+ // 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(&pb, 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 = sqrt(2.0)*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);
+
+ set_ue_golomb(&pb, quant);
+
+ 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(&pb, 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);
+
+ flush_put_bits(&pb);
+ avpkt->size = (put_bits_count(&pb)+7)/8;
+ *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, version;
+
+ 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);
+
+ version = get_bits(&gb, 2);
+ if (version > 1)
+ {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported Sonic version, please report\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (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 ls: %d dr: %d taps: %d block: %d frame: %d downsamp: %d\n",
+ 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;
+ GetBitContext gb;
+ 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);
+
+ init_get_bits8(&gb, buf, buf_size);
+
+ intlist_read(&gb, 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_ue_golomb(&gb) * 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(&gb, 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]);
+
+ align_get_bits(&gb);
+
+ *got_frame_ptr = 1;
+
+ return (get_bits_count(&gb)+7)/8;
+}
+
+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..004fcbb 100644
--- a/libavcodec/sp5x.h
+++ b/libavcodec/sp5x.h
@@ -2,20 +2,20 @@
* Sunplus JPEG tables
* 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..81f3c24 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"),
@@ -115,3 +118,4 @@ AVCodec ff_amv_decoder = {
.close = ff_mjpeg_decode_end,
.decode = sp5x_decode_frame,
};
+#endif
diff --git a/libavcodec/sparc/dsputil_vis.c b/libavcodec/sparc/dsputil_vis.c
index cee2e1d..414d6ca 100644
--- a/libavcodec/sparc/dsputil_vis.c
+++ b/libavcodec/sparc/dsputil_vis.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2003 David S. Miller <davem@redhat.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/sparc/dsputil_vis.h b/libavcodec/sparc/dsputil_vis.h
index d7f6e01..d7e2e63 100644
--- a/libavcodec/sparc/dsputil_vis.h
+++ b/libavcodec/sparc/dsputil_vis.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/sparc/hpeldsp_vis.c b/libavcodec/sparc/hpeldsp_vis.c
index bca32e2..be2a85d 100644
--- a/libavcodec/sparc/hpeldsp_vis.c
+++ b/libavcodec/sparc/hpeldsp_vis.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2003 David S. Miller <davem@redhat.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/sparc/simple_idct_vis.c b/libavcodec/sparc/simple_idct_vis.c
index 2057d66..c9923e0 100644
--- a/libavcodec/sparc/simple_idct_vis.c
+++ b/libavcodec/sparc/simple_idct_vis.c
@@ -5,20 +5,20 @@
* I did consult the following fine web page about dct
* http://www.geocities.com/ssavekar/dct.htm
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/sparc/vis.h b/libavcodec/sparc/vis.h
index ff2fb9d..107ff96 100644
--- a/libavcodec/sparc/vis.h
+++ b/libavcodec/sparc/vis.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2003 David S. Miller <davem@redhat.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/srtdec.c b/libavcodec/srtdec.c
index bbc8061..b16645a 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"
@@ -49,7 +50,7 @@ typedef struct {
static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
const char *in, int x1, int y1, int x2, int y2)
{
- char c, *param, buffer[128], tmp[128];
+ char *param, buffer[128], tmp[128];
int len, tag_close, sptr = 1, line_start = 1, an = 0, end = 0;
SrtStack stack[16];
@@ -60,10 +61,11 @@ 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,
+ snprintf(out, out_end-out,
"{\\an1}{\\move(%d,%d,%d,%d)}", x1, y1, x2, y2);
else
- out += snprintf(out, out_end-out, "{\\an1}{\\pos(%d,%d)}", x1, y1);
+ snprintf(out, out_end-out, "{\\an1}{\\pos(%d,%d)}", x1, y1);
+ out += strlen(out);
}
for (; out < out_end && !end && *in; in++) {
@@ -77,7 +79,8 @@ static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
}
while (out[-1] == ' ')
out--;
- out += snprintf(out, out_end-out, "\\N");
+ snprintf(out, out_end-out, "\\N");
+ if(out<out_end) out += strlen(out);
line_start = 1;
break;
case ' ':
@@ -86,16 +89,18 @@ static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
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;
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 +115,9 @@ 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,
+ snprintf(out, out_end-out,
"%s", stack[j].param[i]);
+ if(out<out_end) out += strlen(out);
break;
}
} else {
@@ -145,13 +151,16 @@ static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
param++;
}
for (i=0; i<PARAM_NUMBER; i++)
- if (stack[sptr].param[i][0])
- out += snprintf(out, out_end-out,
+ if (stack[sptr].param[i][0]) {
+ snprintf(out, out_end-out,
"%s", stack[sptr].param[i]);
+ if(out<out_end) out += strlen(out);
+ }
}
} else if (!buffer[1] && strspn(buffer, "bisu") == 1) {
- out += snprintf(out, out_end-out,
+ snprintf(out, out_end-out,
"{\\%c%d}", buffer[0], !tag_close);
+ if(out<out_end) out += strlen(out);
} else {
unknown = 1;
snprintf(tmp, sizeof(tmp), "</%s>", buffer);
@@ -180,7 +189,7 @@ static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
out -= 2;
while (out[-1] == ' ')
out--;
- out += snprintf(out, out_end-out, "\r\n");
+ snprintf(out, out_end-out, "\r\n");
return in;
}
@@ -195,7 +204,8 @@ static const char *read_ts(const char *buf, int *ts_start, int *ts_end,
"%*[ ]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;
+ buf += strcspn(buf, "\n");
+ buf += !!*buf;
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;
@@ -213,30 +223,61 @@ static int srt_decode_frame(AVCodecContext *avctx,
char buffer[2048];
const char *ptr = avpkt->data;
const char *end = avpkt->data + avpkt->size;
+ int size;
+ 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);
-
while (ptr < end && *ptr) {
- ptr = read_ts(ptr, &ts_start, &ts_end, &x1, &y1, &x2, &y2);
- if (!ptr)
- break;
+ if (avctx->codec->id == AV_CODEC_ID_SRT) {
+ ptr = read_ts(ptr, &ts_start, &ts_end, &x1, &y1, &x2, &y2);
+ if (!ptr)
+ break;
+ } else {
+ // 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});
+ }
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);
+ ff_ass_add_rect(sub, buffer, ts_start, ts_end-ts_start, 0);
}
*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"),
+ .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle with embedded timing"),
.type = AVMEDIA_TYPE_SUBTITLE,
.id = AV_CODEC_ID_SRT,
.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..3036a7f
--- a/dev/null
+++ b/libavcodec/srtenc.c
@@ -0,0 +1,324 @@
+/*
+ * 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 "ass_split.h"
+#include "ass.h"
+
+
+#define SRT_STACK_SIZE 64
+
+typedef struct {
+ AVCodecContext *avctx;
+ ASSSplitContext *ass_ctx;
+ char buffer[2048];
+ char *ptr;
+ char *end;
+ char *dialog_start;
+ int count;
+ 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);
+ s->ptr += vsnprintf(s->ptr, s->end - s->ptr, 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);
+ return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
+}
+
+static void srt_text_cb(void *priv, const char *text, int len)
+{
+ SRTContext *s = priv;
+ av_strlcpy(s->ptr, text, FFMIN(s->end-s->ptr, len+1));
+ s->ptr += 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)
+{
+ SRTContext *s = priv;
+
+ if (s->avctx->codec->id == AV_CODEC_ID_SRT) {
+ char buffer[32];
+ int len = snprintf(buffer, sizeof(buffer),
+ " X1:%03u X2:%03u Y1:%03u Y2:%03u", x1, x2, y1, y2);
+ if (s->end - s->ptr > len) {
+ memmove(s->dialog_start+len, s->dialog_start, s->ptr-s->dialog_start+1);
+ memcpy(s->dialog_start, buffer, len);
+ s->ptr += len;
+ }
+ }
+}
+
+static void srt_end_cb(void *priv)
+{
+ SRTContext *s = priv;
+
+ srt_stack_push_pop(priv, 0, 1);
+ if (s->avctx->codec->id == AV_CODEC_ID_SRT)
+ srt_print(priv, "\r\n\r\n");
+}
+
+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, 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++) {
+ if (avctx->codec->id == AV_CODEC_ID_SRT) {
+ int sh, sm, ss, sc = 10 * dialog->start;
+ int eh, em, es, ec = 10 * dialog->end;
+ sh = sc/3600000; sc -= 3600000*sh;
+ sm = sc/ 60000; sc -= 60000*sm;
+ ss = sc/ 1000; sc -= 1000*ss;
+ eh = ec/3600000; ec -= 3600000*eh;
+ em = ec/ 60000; ec -= 60000*em;
+ es = ec/ 1000; ec -= 1000*es;
+ srt_print(s,"%d\r\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\r\n",
+ ++s->count, sh, sm, ss, sc, eh, em, es, ec);
+ s->dialog_start = s->ptr - 2;
+ }
+ s->alignment_applied = 0;
+ srt_style_apply(s, dialog->style);
+ ff_ass_split_override_codes(&srt_callbacks, s, dialog->text);
+ }
+ }
+
+ if (s->ptr == s->buffer)
+ return 0;
+
+ len = av_strlcpy(buf, s->buffer, bufsize);
+
+ if (len > bufsize-1) {
+ av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
+ return -1;
+ }
+
+ return len;
+}
+
+static int srt_encode_close(AVCodecContext *avctx)
+{
+ SRTContext *s = avctx->priv_data;
+ ff_ass_split_free(s->ass_ctx);
+ return 0;
+}
+
+#if CONFIG_SRT_ENCODER
+/* deprecated encoder */
+AVCodec ff_srt_encoder = {
+ .name = "srt",
+ .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle with embedded timing"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_SRT,
+ .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/subviewerdec.c b/libavcodec/subviewerdec.c
new file mode 100644
index 0000000..63be418
--- a/dev/null
+++ b/libavcodec/subviewerdec.c
@@ -0,0 +1,83 @@
+/*
+ * 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++;
+ }
+ }
+
+ av_bprintf(buf, "\r\n");
+ return 0;
+}
+
+static int subviewer_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_sub_ptr, AVPacket *avpkt)
+{
+ char c;
+ AVSubtitle *sub = data;
+ const char *ptr = avpkt->data;
+ AVBPrint buf;
+
+ /* To be removed later */
+ if (ptr && sscanf(ptr, "%*u:%*u:%*u.%*u,%*u:%*u:%*u.%*u%c", &c) == 1) {
+ av_log(avctx, AV_LOG_ERROR, "AVPacket is not clean (contains timing "
+ "information). You need to upgrade your libavformat or "
+ "sanitize your packet.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ 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))
+ ff_ass_add_rect(sub, buf.str, avpkt->pts, avpkt->duration, 0);
+ *got_sub_ptr = sub->num_rects > 0;
+ av_bprint_finalize(&buf, NULL);
+ 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 4147cf0..a373df7 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;
}
@@ -74,10 +74,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;
@@ -85,6 +92,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;
@@ -92,17 +102,15 @@ static int sunrast_decode_frame(AVCodecContext *avctx, void *data,
if (w != avctx->width || h != avctx->height)
avcodec_set_dimensions(avctx, w, h);
- 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) {
@@ -115,13 +123,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;
@@ -162,6 +177,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 58d0fb8..0879ce6 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
*/
@@ -25,7 +25,6 @@
#include "sunrast.h"
typedef struct SUNRASTContext {
- AVFrame picture;
PutByteContext p;
int depth; ///< depth of pixel
int length; ///< length (bytes) of image
@@ -56,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;
@@ -83,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;
}
@@ -128,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)
@@ -154,9 +148,6 @@ static av_cold int sunrast_encode_init(AVCodecContext *avctx)
return AVERROR(EINVAL);
}
- avctx->coded_frame = &s->picture;
- avctx->coded_frame->key_frame = 1;
- avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
s->maptype = RMT_NONE;
s->maplength = 0;
@@ -189,7 +180,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..c219f22 100644
--- a/libavcodec/svq1.c
+++ b/libavcodec/svq1.c
@@ -8,20 +8,20 @@
*
* 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..8380f22 100644
--- a/libavcodec/svq1.h
+++ b/libavcodec/svq1.h
@@ -8,20 +8,20 @@
*
* 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..7926ce1 100644
--- a/libavcodec/svq1_cb.h
+++ b/libavcodec/svq1_cb.h
@@ -6,20 +6,20 @@
* 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..e56d894 100644
--- a/libavcodec/svq1_vlc.h
+++ b/libavcodec/svq1_vlc.h
@@ -1,20 +1,20 @@
/*
* 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 7d3ef50..5193798 100644
--- a/libavcodec/svq1dec.c
+++ b/libavcodec/svq1dec.c
@@ -8,20 +8,20 @@
*
* 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
*/
@@ -110,12 +110,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() \
@@ -151,7 +150,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)
@@ -341,8 +340,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 =
@@ -385,8 +383,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) */
@@ -398,8 +395,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) */
@@ -407,8 +403,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) */
@@ -416,8 +411,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 */
@@ -520,6 +514,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 */
@@ -558,7 +554,7 @@ static int svq1_decode_frame_header(AVCodecContext *avctx, AVFrame *frame)
svq1_parse_string(bitbuf, msg);
av_log(avctx, AV_LOG_INFO,
- "embedded message: \"%s\"\n", (char *)msg);
+ "embedded message:\n%s\n", (char *)msg);
}
skip_bits(bitbuf, 2);
@@ -570,20 +566,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) */
@@ -591,16 +587,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)
+ while (get_bits1(bitbuf))
skip_bits(bitbuf, 8);
}
+ s->width = width;
+ s->height = height;
return 0;
}
@@ -616,7 +614,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);
@@ -628,12 +626,14 @@ static int svq1_decode_frame(AVCodecContext *avctx, void *data,
if (s->frame_code != 0x20) {
uint32_t *src = (uint32_t *)(buf + 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;
@@ -675,8 +675,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;
diff --git a/libavcodec/svq1enc.c b/libavcodec/svq1enc.c
index fa94f52..a6c94ad 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
*/
@@ -32,11 +32,10 @@
#include "mpegvideo.h"
#include "h263.h"
#include "internal.h"
+#include "libavutil/avassert.h"
#include "svq1.h"
#include "svq1enc_cb.h"
-#undef NDEBUG
-#include <assert.h>
typedef struct SVQ1Context {
/* FIXME: Needed for motion estimation, should not be used for anything
@@ -96,7 +95,7 @@ static void svq1_write_header(SVQ1Context *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);
@@ -180,7 +179,7 @@ static int encode_block(SVQ1Context *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;
@@ -188,7 +187,7 @@ static int encode_block(SVQ1Context *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];
@@ -232,10 +231,10 @@ static int encode_block(SVQ1Context *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],
@@ -245,7 +244,7 @@ static int encode_block(SVQ1Context *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]);
}
@@ -436,10 +435,10 @@ static int svq1_encode_plane(SVQ1Context *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;
@@ -541,12 +540,9 @@ static int svq1_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
AVFrame temp;
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");
@@ -554,14 +550,16 @@ static int svq1_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
if (!s->current_picture.data[0]) {
- ff_get_buffer(avctx, &s->current_picture, 0);
- ff_get_buffer(avctx, &s->last_picture, 0);
+ if ((ret = ff_get_buffer(avctx, &s->current_picture, 0))< 0 ||
+ (ret = ff_get_buffer(avctx, &s->last_picture, 0)) < 0) {
+ return ret;
+ }
s->scratchbuf = av_malloc(s->current_picture.linesize[0] * 16 * 2);
}
- temp = s->current_picture;
- s->current_picture = s->last_picture;
- s->last_picture = temp;
+ av_frame_move_ref(&temp, &s->current_picture);
+ av_frame_move_ref(&s->current_picture, &s->last_picture);
+ av_frame_move_ref(&s->last_picture, &temp);
init_put_bits(&s->pb, pkt->data, pkt->size);
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 775e071..89bb616 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 "libavutil/attributes.h"
@@ -52,6 +52,7 @@
#include "golomb.h"
#include "hpeldsp.h"
#include "rectangle.h"
+#include "vdpau_internal.h"
#if CONFIG_ZLIB
#include <zlib.h>
@@ -76,6 +77,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;
@@ -236,14 +239,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) {
@@ -258,20 +264,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;
@@ -312,7 +317,8 @@ static inline void svq3_mc_dir_part(SVQ3Context *s,
src = pic->f.data[0] + mx + my * h->linesize;
if (emu) {
- h->vdsp.emulated_edge_mc(h->edge_emu_buffer, src, h->linesize,
+ h->vdsp.emulated_edge_mc(h->edge_emu_buffer, h->linesize,
+ src, h->linesize,
width + 1, height + 1,
mx, my, s->h_edge_pos, s->v_edge_pos);
src = h->edge_emu_buffer;
@@ -338,7 +344,8 @@ static inline void svq3_mc_dir_part(SVQ3Context *s,
src = pic->f.data[i] + mx + my * h->uvlinesize;
if (emu) {
- h->vdsp.emulated_edge_mc(h->edge_emu_buffer, src, h->uvlinesize,
+ h->vdsp.emulated_edge_mc(h->edge_emu_buffer, h->uvlinesize,
+ src, h->uvlinesize,
width + 1, height + 1,
mx, my, (s->h_edge_pos >> 1),
s->v_edge_pos >> 1);
@@ -611,7 +618,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:%d\n", vlc);
return -1;
}
@@ -680,7 +687,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=%d\n", vlc);
return -1;
}
@@ -796,8 +803,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);
}
@@ -878,6 +885,7 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
ff_hpeldsp_init(&s->hdsp, avctx->flags);
h->flags = avctx->flags;
h->is_complex = 1;
+ h->sps.chroma_format_idc = 1;
h->picture_structure = PICT_FRAME;
avctx->pix_fmt = avctx->codec->pix_fmts[0];
@@ -980,7 +988,7 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
int offset = get_bits_count(&gb) + 7 >> 3;
uint8_t *buf;
- if (watermark_height > 0 &&
+ if (watermark_height <= 0 ||
(uint64_t)watermark_width * 4 > UINT_MAX / watermark_height)
return -1;
@@ -1095,10 +1103,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 */
@@ -1113,10 +1122,21 @@ 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_malloc(&s->buf, &s->buf_size,
+ buf_size+FF_INPUT_BUFFER_PADDING_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;
@@ -1257,7 +1277,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)
@@ -1270,6 +1290,18 @@ static int svq3_decode_frame(AVCodecContext *avctx, void *data,
h->low_delay, h->mb_height * 16, h->mb_width * 16);
}
+ 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])
@@ -1306,6 +1338,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 8c67a23..7a57d8a 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 8e6f120..5f10530 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 7b73578..33edcc4 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..26d063e 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
*/
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 0d2dcbb..fcbe10a 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
*/
@@ -28,43 +28,48 @@
#include "libavutil/internal.h"
#include "libavutil/samplefmt.h"
#include "tak.h"
+#include "thread.h"
#include "avcodec.h"
#include "dsputil.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
DSPContext dsp;
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_dsputil_init(&s->dsp, avctx);
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 tmp, 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,75 @@ 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) {
+ 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--) {
+ tmp = y + tfilter[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->dsp.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) {
+ tmp = FFMIN(y, x);
+
+ for (i = 0; i < tmp; i++) {
+ int v = 1 << (filter_quant - 1);
+
+ if (filter_order & -16)
+ v += s->dsp.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 +498,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 +586,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 +600,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 +624,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->dsp.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->dsp.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 +673,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)) {
+ hsize = get_bits_count(gb) / 8;
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,8 +721,8 @@ 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 (s->ti.bps != avctx->bits_per_raw_sample) {
+ avctx->bits_per_raw_sample = s->ti.bps;
if ((ret = set_bps_params(avctx)) < 0)
return ret;
}
@@ -741,10 +738,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 +763,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 +772,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 +862,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 +903,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 +938,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 9f0b286..b3616c2 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,29 +168,35 @@ 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 = av_image_check_size(w, h, 0, avctx)) < 0)
return ret;
- if(w != avctx->width || h != avctx->height)
+ if (w != avctx->width || h != avctx->height)
avcodec_set_dimensions(avctx, w, h);
- 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;
@@ -173,9 +205,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;
@@ -185,10 +217,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 */
@@ -199,30 +235,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
--- a/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 610621f..108e148 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
*/
@@ -29,10 +29,6 @@
#include "rle.h"
#include "targa.h"
-typedef struct TargaContext {
- AVFrame picture;
-} TargaContext;
-
/**
* RLE compress the image, with maximum size of out_size
* @param outbuf Output buffer
@@ -81,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) {
@@ -89,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);
@@ -101,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:
@@ -125,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);
@@ -152,28 +170,14 @@ static int targa_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return 0;
}
-static av_cold int targa_encode_init(AVCodecContext *avctx)
-{
- TargaContext *s = avctx->priv_data;
-
- avcodec_get_frame_defaults(&s->picture);
- s->picture.key_frame= 1;
- s->picture.pict_type = AV_PICTURE_TYPE_I;
- avctx->coded_frame= &s->picture;
-
- return 0;
-}
-
AVCodec ff_targa_encoder = {
.name = "targa",
.long_name = NULL_IF_CONFIG_SMALL("Truevision Targa image"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_TARGA,
- .priv_data_size = sizeof(TargaContext),
- .init = targa_encode_init,
.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..a8f9e40
--- a/dev/null
+++ b/libavcodec/textdec.c
@@ -0,0 +1,188 @@
+/*
+ * 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_event_to_ass(const AVCodecContext *avctx, AVBPrint *buf,
+ const char *p, const char *p_end)
+{
+ const TextContext *text = avctx->priv_data;
+
+ for (; p < p_end && *p; p++) {
+
+ /* forced custom line breaks, not accounted as "normal" EOL */
+ if (text->linebreaks && strchr(text->linebreaks, *p)) {
+ av_bprintf(buf, "\\N");
+
+ /* standard ASS escaping so random characters don't get mis-interpreted
+ * as ASS */
+ } else if (!text->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);
+ }
+ }
+ av_bprintf(buf, "\r\n");
+ return 0;
+}
+
+static int text_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_sub_ptr, AVPacket *avpkt)
+{
+ 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 &&
+ !text_event_to_ass(avctx, &buf, ptr, ptr + avpkt->size)) {
+ if (!av_bprint_is_complete(&buf)) {
+ av_bprint_finalize(&buf, NULL);
+ return AVERROR(ENOMEM);
+ }
+ ff_ass_add_rect(sub, buf.str, ts_start, ts_duration, 0);
+ }
+ *got_sub_ptr = sub->num_rects > 0;
+ av_bprint_finalize(&buf, NULL);
+ 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
+
+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_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 fe963ef..0da9afd 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;
}
@@ -232,10 +232,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 735eafe..2b100ed 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
*/
@@ -31,17 +30,22 @@
#endif
#include "libavutil/attributes.h"
+#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/imgutils.h"
#include "avcodec.h"
+#include "bytestream.h"
#include "faxcompr.h"
#include "internal.h"
#include "lzw.h"
#include "mathops.h"
#include "tiff.h"
+#include "tiff_data.h"
+#include "thread.h"
typedef struct TiffContext {
AVCodecContext *avctx;
+ GetByteContext gb;
int width, height;
unsigned int bpp, bppcount;
@@ -50,46 +54,230 @@ typedef struct TiffContext {
int le;
enum TiffCompr compr;
int invert;
+ int planar;
int fax_opts;
int predictor;
int fill_order;
int strips, rps, sstype;
int sot;
- const uint8_t *stripdata;
- const uint8_t *stripsizes;
- int stripsize, stripoff;
+ int stripsizesoff, stripsize, stripoff, strippos;
LZWState *lzw;
+
+ uint8_t *deinvert_buf;
+ int deinvert_buf_size;
+
+ int geotag_count;
+ TiffGeoTag *geotags;
} TiffContext;
-static unsigned tget_short(const uint8_t **p, 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);
+}
+
+#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)
{
- unsigned v = le ? AV_RL16(*p) : AV_RB16(*p);
- *p += 2;
- return v;
+ 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 unsigned tget_long(const uint8_t **p, int le)
+static const char *search_keyval(const TiffGeoTagKeyName *keys, int n, int id)
{
- unsigned v = le ? AV_RL32(*p) : AV_RB32(*p);
- *p += 4;
- return v;
+ TiffGeoTagKeyName *r = bsearch(&id, keys, n, sizeof(keys[0]), cmp_id_key);
+ if(r)
+ return r->name;
+
+ return NULL;
}
-static unsigned tget(const uint8_t **p, int type, int le)
+static char *get_geokey_val(int key, int val)
{
- switch (type) {
- case TIFF_BYTE:
- return *(*p)++;
- case TIFF_SHORT:
- return tget_short(p, le);
- case TIFF_LONG:
- return tget_long(p, le);
+ char *ap;
+
+ if (val == TIFF_GEO_KEY_UNDEFINED)
+ return av_strdup("undefined");
+ if (val == TIFF_GEO_KEY_USER_DEFINED)
+ return av_strdup("User-Defined");
+
+#define RET_GEOKEY_VAL(TYPE, array)\
+ if (val >= TIFF_##TYPE##_OFFSET &&\
+ val - TIFF_##TYPE##_OFFSET < FF_ARRAY_ELEMS(ff_tiff_##array##_codes))\
+ return av_strdup(ff_tiff_##array##_codes[val - TIFF_##TYPE##_OFFSET]);
+
+ switch (key) {
+ case TIFF_GT_MODEL_TYPE_GEOKEY:
+ RET_GEOKEY_VAL(GT_MODEL_TYPE, gt_model_type);
+ break;
+ case TIFF_GT_RASTER_TYPE_GEOKEY:
+ RET_GEOKEY_VAL(GT_RASTER_TYPE, gt_raster_type);
+ break;
+ case TIFF_GEOG_LINEAR_UNITS_GEOKEY:
+ case TIFF_PROJ_LINEAR_UNITS_GEOKEY:
+ case TIFF_VERTICAL_UNITS_GEOKEY:
+ RET_GEOKEY_VAL(LINEAR_UNIT, linear_unit);
+ break;
+ case TIFF_GEOG_ANGULAR_UNITS_GEOKEY:
+ case TIFF_GEOG_AZIMUTH_UNITS_GEOKEY:
+ RET_GEOKEY_VAL(ANGULAR_UNIT, angular_unit);
+ break;
+ case TIFF_GEOGRAPHIC_TYPE_GEOKEY:
+ RET_GEOKEY_VAL(GCS_TYPE, gcs_type);
+ RET_GEOKEY_VAL(GCSE_TYPE, gcse_type);
+ break;
+ case TIFF_GEOG_GEODETIC_DATUM_GEOKEY:
+ RET_GEOKEY_VAL(GEODETIC_DATUM, geodetic_datum);
+ RET_GEOKEY_VAL(GEODETIC_DATUM_E, geodetic_datum_e);
+ break;
+ case TIFF_GEOG_ELLIPSOID_GEOKEY:
+ RET_GEOKEY_VAL(ELLIPSOID, ellipsoid);
+ break;
+ case TIFF_GEOG_PRIME_MERIDIAN_GEOKEY:
+ RET_GEOKEY_VAL(PRIME_MERIDIAN, prime_meridian);
+ break;
+ case TIFF_PROJECTED_CS_TYPE_GEOKEY:
+ ap = av_strdup(search_keyval(ff_tiff_proj_cs_type_codes, FF_ARRAY_ELEMS(ff_tiff_proj_cs_type_codes), val));
+ if(ap) return ap;
+ break;
+ case TIFF_PROJECTION_GEOKEY:
+ ap = av_strdup(search_keyval(ff_tiff_projection_codes, FF_ARRAY_ELEMS(ff_tiff_projection_codes), val));
+ if(ap) return ap;
+ break;
+ case TIFF_PROJ_COORD_TRANS_GEOKEY:
+ RET_GEOKEY_VAL(COORD_TRANS, coord_trans);
+ break;
+ case TIFF_VERTICAL_CS_TYPE_GEOKEY:
+ RET_GEOKEY_VAL(VERT_CS, vert_cs);
+ RET_GEOKEY_VAL(ORTHO_VERT_CS, ortho_vert_cs);
+ break;
+
+ }
+
+ ap = av_malloc(14);
+ if (ap)
+ snprintf(ap, 14, "Unknown-%d", val);
+ return ap;
+}
+
+static char *doubles2str(double *dp, int count, const char *sep)
+{
+ int i;
+ char *ap, *ap0;
+ uint64_t component_len;
+ if (!sep) sep = ", ";
+ component_len = 15LL + 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, "%f%s", dp[i], sep);
+ if(l >= component_len) {
+ av_free(ap0);
+ return NULL;
+ }
+ ap += l;
+ }
+ ap0[strlen(ap0) - strlen(sep)] = '\0';
+ return ap0;
+}
+
+static int add_metadata(int count, int type,
+ const char *name, const char *sep, TiffContext *s, AVFrame *frame)
+{
+ switch(type) {
+ case TIFF_DOUBLE: return ff_tadd_doubles_metadata(count, name, sep, &s->gb, s->le, avpriv_frame_get_metadatap(frame));
+ case TIFF_SHORT : return ff_tadd_shorts_metadata(count, name, sep, &s->gb, s->le, avpriv_frame_get_metadatap(frame));
+ case TIFF_STRING: return ff_tadd_string_metadata(count, name, &s->gb, s->le, avpriv_frame_get_metadatap(frame));
+ default : return AVERROR_INVALIDDATA;
+ };
+}
+
+static void av_always_inline horizontal_fill(unsigned int bpp, uint8_t* dst,
+ int usePtr, const uint8_t *src,
+ uint8_t c, int width, int offset)
+{
+ 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:
- return UINT_MAX;
+ 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;
+}
+
#if CONFIG_ZLIB
static int tiff_uncompress(uint8_t *dst, unsigned long *len, const uint8_t *src,
int size)
@@ -97,7 +285,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;
@@ -123,6 +311,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,
@@ -133,7 +328,11 @@ 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);
+ }
dst += stride;
src += width;
}
@@ -144,9 +343,10 @@ static int tiff_unpack_zlib(TiffContext *s, uint8_t *dst, int stride,
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);
@@ -169,6 +369,11 @@ 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;
}
@@ -180,6 +385,9 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
const uint8_t *ssrc = src;
int width = ((s->width * s->bpp) + 7) >> 3;
+ if (s->planar)
+ width /= s->bppcount;
+
if (size <= 0)
return AVERROR_INVALIDDATA;
@@ -194,6 +402,14 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
#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;
@@ -202,7 +418,7 @@ 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);
+ return tiff_unpack_fax(s, dst, stride, src, size, width, lines);
}
for (line = 0; line < lines; line++) {
if (src - ssrc > size) {
@@ -214,7 +430,8 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
if (ssrc + size - src < width)
return AVERROR_INVALIDDATA;
if (!s->fill_order) {
- memcpy(dst, src, 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++)
@@ -224,9 +441,11 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
break;
case TIFF_PACKBITS:
for (pixels = 0; pixels < width;) {
- if (ssrc + size - src < 2)
+ if (ssrc + size - src < 2) {
+ av_log(s->avctx, AV_LOG_ERROR, "Read went out of bounds\n");
return AVERROR_INVALIDDATA;
- code = (int8_t) *src++;
+ }
+ code = s->fill_order ? (int8_t) ff_reverse[*src++]: (int8_t) *src++;
if (code >= 0) {
code++;
if (pixels + code > width ||
@@ -235,7 +454,8 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
"Copy went out of bounds\n");
return AVERROR_INVALIDDATA;
}
- memcpy(dst + pixels, src, code);
+ 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
@@ -246,10 +466,16 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
return AVERROR_INVALIDDATA;
}
c = *src++;
- memset(dst + pixels, c, code);
+ 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;
case TIFF_LZW:
pixels = ff_lzw_decode(s->lzw, dst, width);
@@ -258,6 +484,8 @@ 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);
break;
}
dst += stride;
@@ -265,15 +493,19 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
return 0;
}
-static int init_image(TiffContext *s, AVFrame *frame)
+static int init_image(TiffContext *s, ThreadFrame *frame)
{
int i, ret;
uint32_t *pal;
- 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;
- break;
+ if (!s->palette_is_set) {
+ s->avctx->pix_fmt = AV_PIX_FMT_MONOBLACK;
+ break;
+ }
+ case 21:
+ case 41:
case 81:
s->avctx->pix_fmt = AV_PIX_FMT_PAL8;
break;
@@ -283,11 +515,29 @@ static int init_image(TiffContext *s, AVFrame *frame)
case 161:
s->avctx->pix_fmt = s->le ? AV_PIX_FMT_GRAY16LE : AV_PIX_FMT_GRAY16BE;
break;
+ case 162:
+ s->avctx->pix_fmt = AV_PIX_FMT_GRAY8A;
+ break;
case 324:
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,
@@ -300,76 +550,49 @@ static int init_image(TiffContext *s, AVFrame *frame)
return ret;
avcodec_set_dimensions(s->avctx, s->width, s->height);
}
- 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) {
if (s->palette_is_set) {
- memcpy(frame->data[1], s->palette, sizeof(s->palette));
+ memcpy(frame->f->data[1], s->palette, sizeof(s->palette));
} else {
/* make default grayscale pal */
- pal = (uint32_t *) frame->data[1];
- for (i = 0; i < 256; i++)
- pal[i] = i * 0x010101;
+ 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, const uint8_t *start,
- const uint8_t *buf, const uint8_t *end_buf)
+static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
{
unsigned tag, type, count, off, value = 0;
- int i, j;
+ int i, j, k, pos, start;
+ int ret;
uint32_t *pal;
- const uint8_t *rp, *gp, *bp;
-
- if (end_buf - buf < 12)
- return AVERROR_INVALIDDATA;
- tag = tget_short(&buf, s->le);
- type = tget_short(&buf, s->le);
- count = tget_long(&buf, s->le);
- off = tget_long(&buf, s->le);
+ double *dp;
- 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:
- buf -= 4;
- value = tget(&buf, type, s->le);
- buf = NULL;
- break;
case TIFF_LONG:
- value = off;
- buf = NULL;
+ value = ff_tget(&s->gb, type, s->le);
break;
case TIFF_STRING:
if (count <= 4) {
- buf -= 4;
break;
}
default:
value = UINT_MAX;
- buf = start + off;
}
- } else {
- if (count <= 4 && type_sizes[type] * count <= 4)
- buf -= 4;
- else
- buf = start + off;
- }
-
- if (buf && (buf < start || buf > end_buf)) {
- av_log(s->avctx, AV_LOG_ERROR,
- "Tag referencing position outside the image\n");
- return AVERROR_INVALIDDATA;
}
switch (tag) {
@@ -392,14 +615,13 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
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;
- for (i = 0; i < count && buf < end_buf; i++)
- s->bpp += tget(&buf, type, s->le);
+ if (bytestream2_get_bytes_left(&s->gb) < type_sizes[type] * count)
+ return AVERROR_INVALIDDATA;
+ for (i = 0; i < count; i++)
+ s->bpp += ff_tget(&s->gb, type, s->le);
break;
default:
s->bpp = -1;
@@ -412,6 +634,11 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
"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;
@@ -449,7 +676,7 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
break;
case TIFF_ROWSPERSTRIP:
if (type == TIFF_LONG && value == UINT_MAX)
- value = s->avctx->height;
+ value = s->height;
if (value < 1) {
av_log(s->avctx, AV_LOG_ERROR,
"Incorrect value of rows per strip\n");
@@ -459,15 +686,15 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
break;
case TIFF_STRIP_OFFS:
if (count == 1) {
- s->stripdata = NULL;
+ s->strippos = 0;
s->stripoff = value;
} else
- s->stripdata = start + off;
+ s->strippos = off;
s->strips = count;
if (s->strips == 1)
s->rps = s->height;
s->sot = type;
- if (s->stripdata > end_buf) {
+ if (s->strippos > bytestream2_size(&s->gb)) {
av_log(s->avctx, AV_LOG_ERROR,
"Tag referencing position outside the image\n");
return AVERROR_INVALIDDATA;
@@ -475,20 +702,27 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
break;
case TIFF_STRIP_SIZE:
if (count == 1) {
- s->stripsizes = NULL;
+ s->stripsizesoff = 0;
s->stripsize = value;
s->strips = 1;
} else {
- s->stripsizes = start + off;
+ s->stripsizesoff = off;
}
s->strips = count;
s->sstype = type;
- if (s->stripsizes > end_buf) {
+ if (s->stripsizesoff > bytestream2_size(&s->gb)) {
av_log(s->avctx, AV_LOG_ERROR,
"Tag referencing position outside the image\n");
return AVERROR_INVALIDDATA;
}
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;
@@ -520,25 +754,21 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
case TIFF_PAL:
pal = (uint32_t *) s->palette;
off = type_sizes[type];
- if (count / 3 > 256 || end_buf - buf < count / 3 * off * 3)
+ if (count / 3 > 256 || bytestream2_get_bytes_left(&s->gb) < count / 3 * off * 3)
return AVERROR_INVALIDDATA;
- rp = buf;
- gp = buf + count / 3 * off;
- bp = buf + count / 3 * off * 2;
off = (type_sizes[type] - 1) << 3;
- for (i = 0; i < count / 3; i++) {
- j = (tget(&rp, type, s->le) >> off) << 16;
- j |= (tget(&gp, type, s->le) >> off) << 8;
- j |= tget(&bp, type, s->le) >> off;
- pal[i] = j;
+ for (k = 2; k >= 0; k--) {
+ for (i = 0; i < count / 3; i++) {
+ if (k == 2)
+ pal[i] = 0xFFU << 24;
+ j = (ff_tget(&s->gb, type, s->le) >> off) << (k * 8);
+ pal[i] |= j;
+ }
}
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_T4OPTIONS:
if (s->compr == TIFF_G3)
@@ -548,6 +778,137 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
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(sizeof(TiffGeoTag) * s->geotag_count);
+ 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(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,
@@ -556,96 +917,121 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
return AVERROR_INVALIDDATA;
}
}
+end:
+ bytestream2_seek(&s->gb, start, SEEK_SET);
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;
TiffContext *const s = avctx->priv_data;
AVFrame *const p = data;
- const uint8_t *orig_buf = buf, *end_buf = buf + buf_size;
+ 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;
+ GetByteContext stripsizes;
+ GetByteContext stripdata;
+
+ bytestream2_init(&s->gb, avpkt->data, avpkt->size);
// parse image header
- if (end_buf - buf < 8)
- return AVERROR_INVALIDDATA;
- id = AV_RL16(buf);
- buf += 2;
- 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->invert = 0;
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(&buf, le) != 42) {
- av_log(avctx, AV_LOG_ERROR,
- "The answer to life, universe and everything is not correct!\n");
- return AVERROR_INVALIDDATA;
- }
- // Reset these pointers so we can tell if they were set this frame
- s->stripsizes = s->stripdata = NULL;
+ 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(&buf, le);
- if (off >= UINT_MAX - 14 || end_buf - orig_buf < off + 14) {
- av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n");
+ bytestream2_seek(&s->gb, off, SEEK_SET);
+ entries = ff_tget_short(&s->gb, le);
+ if (bytestream2_get_bytes_left(&s->gb) < entries * 12)
return AVERROR_INVALIDDATA;
- }
- buf = orig_buf + off;
- entries = tget_short(&buf, le);
for (i = 0; i < entries; i++) {
- if ((ret = tiff_decode_tag(s, orig_buf, buf, end_buf)) < 0)
+ if ((ret = tiff_decode_tag(s, p)) < 0)
return ret;
- buf += 12;
}
- if (!s->stripdata && !s->stripoff) {
+
+ 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 = buf_size - s->stripoff;
+ s->stripsize = avpkt->size - s->stripoff;
+ }
+
+ if (s->stripsizesoff) {
+ 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 >= (unsigned)avpkt->size)
+ return AVERROR_INVALIDDATA;
+ bytestream2_init(&stripdata, avpkt->data + s->strippos, avpkt->size - s->strippos);
}
- stride = p->linesize[0];
- dst = p->data[0];
+
+ 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->stripsizes) {
- if (s->stripsizes >= end_buf)
- return AVERROR_INVALIDDATA;
- ssize = tget(&s->stripsizes, s->sstype, s->le);
- } else
+ if (s->stripsizesoff)
+ ssize = ff_tget(&stripsizes, s->sstype, s->le);
+ else
ssize = s->stripsize;
- if (s->stripdata) {
- if (s->stripdata >= end_buf)
- return AVERROR_INVALIDDATA;
- soff = tget(&s->stripdata, s->sot, s->le);
- } else
+ if (s->strippos)
+ soff = ff_tget(&stripdata, s->sot, s->le);
+ else
soff = s->stripoff;
- if (soff > buf_size || ssize > buf_size - soff) {
+ if (soff > avpkt->size || ssize > avpkt->size - soff) {
av_log(avctx, AV_LOG_ERROR, "Invalid strip size/offset\n");
return AVERROR_INVALIDDATA;
}
- if ((ret = tiff_unpack_strip(s, dst, stride, orig_buf + soff, ssize,
+ if ((ret = tiff_unpack_strip(s, dst, stride, avpkt->data + soff, ssize,
FFMIN(s->rps, s->height - i))) < 0) {
if (avctx->err_recognition & AV_EF_EXPLODE)
return ret;
@@ -654,30 +1040,58 @@ static int decode_frame(AVCodecContext *avctx,
dst += s->rps * stride;
}
if (s->predictor == 2) {
- dst = p->data[0];
+ dst = p->data[plane];
soff = s->bpp >> 3;
+ if (s->planar)
+ soff = FFMAX(soff / s->bppcount, 1);
ssize = s->width * soff;
- for (i = 0; i < s->height; i++) {
- for (j = soff; j < ssize; j++)
- dst[j] += dst[j - soff];
- dst += stride;
+ 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 ||
+ 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));
+ dst += stride;
+ }
+ } else {
+ for (i = 0; i < s->height; i++) {
+ for (j = soff; j < ssize; j++)
+ dst[j] += dst[j - soff];
+ dst += stride;
+ }
}
}
if (s->invert) {
- uint8_t *src;
- int j;
-
- src = p->data[0];
- for (j = 0; j < s->height; j++) {
- for (i = 0; i < p->linesize[0]; i++)
- src[i] = 255 - src[i];
- src += p->linesize[0];
+ dst = p->data[plane];
+ for (i = 0; i < s->height; i++) {
+ 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 += p->linesize[plane];
}
}
+ }
+
+ 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 buf_size;
+ return avpkt->size;
}
static av_cold int tiff_init(AVCodecContext *avctx)
@@ -697,7 +1111,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;
}
@@ -710,5 +1127,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 9052d2f..ae189b6 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_INVERT = 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 */
@@ -74,17 +98,76 @@ enum TiffCompr {
TIFF_DEFLATE = 0x80B2
};
-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
};
-/** 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..6a10d71
--- a/dev/null
+++ b/libavcodec/tiff_common.c
@@ -0,0 +1,317 @@
+/*
+ * 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)
+{
+ unsigned v = le ? bytestream2_get_le16(gb) : bytestream2_get_be16(gb);
+ return v;
+}
+
+
+unsigned ff_tget_long(GetByteContext *gb, int le)
+{
+ unsigned v = le ? bytestream2_get_le32(gb) : bytestream2_get_be32(gb);
+ return v;
+}
+
+
+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 char *auto_sep(int count, 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%f", 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, 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++) {
+ av_bprintf(&bp, "%s%5i", auto_sep(count, sep, i, 8), ff_tget_short(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_bytes_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(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++) {
+ av_bprintf(&bp, "%s%3i", auto_sep(count, sep, i, 16), bytestream2_get_byte(gb));
+ }
+
+ 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..01a7b08
--- a/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 endianess. */
+unsigned ff_tget_short(GetByteContext *gb, int le);
+
+/** Reads a long from the bytestream using given endianess. */
+unsigned ff_tget_long(GetByteContext *gb, int le);
+
+/** Reads a double from the bytestream using given endianess. */
+double ff_tget_double(GetByteContext *gb, int le);
+
+/** Reads a byte from the bytestream using given endianess. */
+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, 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, 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 endianess 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
--- a/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
--- a/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 528673b..f5d04ea 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 {
@@ -59,6 +61,12 @@ typedef struct TiffEncoderContext {
int bpp_tab_size; ///< bpp_tab size
int 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
@@ -67,10 +75,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
@@ -86,13 +96,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)
@@ -107,28 +117,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);
}
@@ -144,14 +155,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)
@@ -191,87 +202,99 @@ static void pack_yuv(TiffEncoderContext *s, uint8_t *dst, int lnum)
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 av_cold int encode_init(AVCodecContext *avctx)
+{
+ TiffEncoderContext *s = avctx->priv_data;
+
+ avctx->coded_frame = &s->picture;
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+ avctx->coded_frame->key_frame = 1;
+ s->avctx = avctx;
+
+ return 0;
+}
+
static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *pict, int *got_packet)
{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
TiffEncoderContext *s = avctx->priv_data;
AVFrame *const p = &s->picture;
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;
- const AVPixFmtDescriptor *pfd;
-
- s->avctx = avctx;
- *p = *pict;
- p->pict_type = AV_PICTURE_TYPE_I;
- p->key_frame = 1;
- avctx->coded_frame = &s->picture;
+ *p = *pict;
s->width = avctx->width;
s->height = avctx->height;
s->subsampling[0] = 1;
s->subsampling[1] = 1;
+ avctx->bits_per_coded_sample =
+ s->bpp = av_get_bits_per_pixel(desc);
+ s->bpp_tab_size = desc->nb_components;
+
switch (avctx->pix_fmt) {
+ case AV_PIX_FMT_RGBA64LE:
+ case AV_PIX_FMT_RGBA:
+ alpha = 1;
case AV_PIX_FMT_RGB48LE:
- case AV_PIX_FMT_GRAY16LE:
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 = 3;
- else if (pfd->flags & AV_PIX_FMT_FLAG_RGB)
- s->photometric_interpretation = 2;
- else
- s->photometric_interpretation = 1;
- 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 = 2;
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 = 1;
- s->bpp_tab_size = 0;
+ break;
+ case AV_PIX_FMT_PAL8:
+ s->photometric_interpretation = 3;
break;
case AV_PIX_FMT_MONOWHITE:
- s->bpp = 1;
s->photometric_interpretation = 0;
- 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 = 6;
- 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:
@@ -280,6 +303,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)
@@ -293,13 +319,10 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
strips = (s->height - 1) / s->rps + 1;
- if (!pkt->data &&
- (ret = av_new_packet(pkt,
+ if ((ret = ff_alloc_packet2(avctx, pkt,
avctx->width * avctx->height * s->bpp * 2 +
- avctx->height * 4 + FF_MIN_BUFFER_SIZE)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+ avctx->height * 4 + FF_MIN_BUFFER_SIZE)) < 0)
return ret;
- }
ptr = pkt->data;
s->buf_start = pkt->data;
s->buf = &ptr;
@@ -315,9 +338,10 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
offset = ptr;
bytestream_put_le32(&ptr, 0);
- strip_sizes = av_mallocz(sizeof(*strip_sizes) * strips);
- strip_offsets = av_mallocz(sizeof(*strip_offsets) * strips);
- if (!strip_sizes || !strip_offsets) {
+ 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;
}
@@ -325,8 +349,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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 == NULL) {
+ 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;
@@ -345,12 +369,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, yuv_line, j);
- memcpy(zbuf + zn, yuv_line, bytes_per_row);
+ pack_yuv(s, 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,
@@ -364,9 +388,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) {
@@ -375,17 +400,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, yuv_line, i);
- ret = encode_strip(s, yuv_line, ptr, bytes_per_row, s->compr);
+ pack_yuv(s, 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],
@@ -394,17 +419,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;
@@ -417,13 +443,13 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
add_entry1(s, TIFF_COMPR, TIFF_SHORT, s->compr);
add_entry1(s, TIFF_INVERT, 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);
add_entry(s, TIFF_YRES, TIFF_RATIONAL, 1, res);
add_entry1(s, TIFF_RES_UNIT, TIFF_SHORT, 2);
@@ -442,10 +468,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
@@ -464,15 +494,24 @@ 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_close(AVCodecContext *avctx)
+{
+ TiffEncoderContext *s = avctx->priv_data;
+
+ 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" },
@@ -496,13 +535,16 @@ AVCodec ff_tiff_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_TIFF,
.priv_data_size = sizeof(TiffEncoderContext),
+ .init = encode_init,
.encode2 = encode_frame,
+ .close = encode_close,
.pix_fmts = (const enum AVPixelFormat[]) {
- AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48LE, AV_PIX_FMT_PAL8,
- 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/timecode.c b/libavcodec/timecode.c
new file mode 100644
index 0000000..f9862e5
--- a/dev/null
+++ b/libavcodec/timecode.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2006 Smartjog S.A.S, Baptiste Coudurier <baptiste.coudurier@gmail.com>
+ * 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
+ * Timecode helpers
+ * This *private* API is deprecated, please use the one available in libavutil instead.
+ */
+
+#include "version.h"
+
+#if FF_API_OLD_TIMECODE
+
+#include <stdio.h>
+#include "timecode.h"
+#include "libavutil/log.h"
+
+int avpriv_framenum_to_drop_timecode(int frame_num)
+{
+ /* only works for NTSC 29.97 */
+ int d = frame_num / 17982;
+ int m = frame_num % 17982;
+ //if (m < 2) m += 2; /* not needed since -2,-1 / 1798 in C returns 0 */
+ return frame_num + 18 * d + 2 * ((m - 2) / 1798);
+}
+
+uint32_t avpriv_framenum_to_smpte_timecode(unsigned frame, int fps, int drop)
+{
+ 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
+}
+
+int avpriv_check_timecode_rate(void *avcl, AVRational rate, int drop)
+{
+ int fps;
+
+ if (!rate.num || !rate.den) {
+ av_log(avcl, AV_LOG_ERROR, "Timecode frame rate must be specified\n");
+ return -1;
+ }
+ fps = (rate.num + rate.den/2) / rate.den;
+ if (drop && fps != 30) {
+ av_log(avcl, AV_LOG_ERROR, "Drop frame is only allowed with 30000/1001 FPS\n");
+ return -2;
+ }
+ switch (fps) {
+ case 24:
+ case 25:
+ case 30: return 0;
+
+ default:
+ av_log(avcl, AV_LOG_ERROR, "Timecode frame rate not supported\n");
+ return -3;
+ }
+}
+
+char *avpriv_timecode_to_string(char *buf, const struct ff_timecode *tc, unsigned frame)
+{
+ int frame_num = tc->start + frame;
+ int fps = (tc->rate.num + tc->rate.den/2) / tc->rate.den;
+ int hh, mm, ss, ff, neg = 0;
+
+ if (tc->drop)
+ frame_num = avpriv_framenum_to_drop_timecode(frame_num);
+ if (frame_num < 0) {
+ frame_num = -frame_num;
+ neg = 1;
+ }
+ ff = frame_num % fps;
+ ss = frame_num / fps % 60;
+ mm = frame_num / (fps*60) % 60;
+ hh = frame_num / (fps*3600);
+ snprintf(buf, 16, "%s%02d:%02d:%02d%c%02d",
+ neg ? "-" : "",
+ hh, mm, ss, tc->drop ? ';' : ':', ff);
+ return buf;
+}
+
+int avpriv_init_smpte_timecode(void *avcl, struct ff_timecode *tc)
+{
+ int hh, mm, ss, ff, fps, ret;
+ char c;
+
+ if (sscanf(tc->str, "%d:%d:%d%c%d", &hh, &mm, &ss, &c, &ff) != 5) {
+ av_log(avcl, AV_LOG_ERROR, "unable to parse timecode, "
+ "syntax: hh:mm:ss[:;.]ff\n");
+ return -1;
+ }
+
+ tc->drop = c != ':'; // drop if ';', '.', ...
+
+ ret = avpriv_check_timecode_rate(avcl, tc->rate, tc->drop);
+ if (ret < 0)
+ return ret;
+
+ fps = (tc->rate.num + tc->rate.den/2) / tc->rate.den;
+ tc->start = (hh*3600 + mm*60 + ss) * fps + ff;
+
+ if (tc->drop) { /* adjust frame number */
+ int tmins = 60*hh + mm;
+ tc->start -= 2 * (tmins - tmins/10);
+ }
+ return 0;
+}
+
+int ff_framenum_to_drop_timecode(int frame_num)
+{
+ return avpriv_framenum_to_drop_timecode(frame_num);
+}
+
+uint32_t ff_framenum_to_smtpe_timecode(unsigned frame, int fps, int drop)
+{
+ return avpriv_framenum_to_smpte_timecode(frame, fps, drop);
+}
+
+int ff_init_smtpe_timecode(void *avcl, struct ff_timecode *tc)
+{
+ return avpriv_init_smpte_timecode(avcl, tc);
+}
+#endif
diff --git a/libavcodec/timecode.h b/libavcodec/timecode.h
new file mode 100644
index 0000000..8bc69e9
--- a/dev/null
+++ b/libavcodec/timecode.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2006 Smartjog S.A.S, Baptiste Coudurier <baptiste.coudurier@gmail.com>
+ * 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
+ * Timecode helpers header
+ * This *private* API is deprecated, please use the one available in libavutil instead.
+ */
+
+#ifndef AVCODEC_TIMECODE_H
+#define AVCODEC_TIMECODE_H
+
+#include "version.h"
+
+#if FF_API_OLD_TIMECODE
+
+#include <stdint.h>
+#include "avcodec.h"
+#include "libavutil/rational.h"
+
+#define TIMECODE_OPT(ctx, flags) \
+ "timecode", "set timecode value following hh:mm:ss[:;.]ff format, " \
+ "use ';' or '.' before frame number for drop frame", \
+ offsetof(ctx, tc.str), \
+ AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, flags
+
+struct ff_timecode {
+ char *str; ///< string following the hh:mm:ss[:;.]ff format
+ int start; ///< timecode frame start
+ int drop; ///< drop flag (1 if drop, else 0)
+ AVRational rate; ///< Frame rate in rational form
+};
+
+/**
+ * @brief Adjust frame number for NTSC drop frame time code
+ * @param frame_num Actual frame number to adjust
+ * @return Adjusted frame number
+ * @warning Adjustment is only valid in NTSC 29.97
+ */
+int avpriv_framenum_to_drop_timecode(int frame_num);
+
+/**
+ * @brief Convert frame id (timecode) to SMPTE 12M binary representation
+ * @param frame Frame number
+ * @param fps Frame rate
+ * @param drop Drop flag
+ * @return The actual binary representation
+ */
+uint32_t avpriv_framenum_to_smpte_timecode(unsigned frame, int fps, int drop);
+
+/**
+ * @brief Load timecode string in buf
+ * @param buf Destination buffer
+ * @param tc Timecode struct pointer
+ * @param frame Frame id (timecode frame is computed with tc->start+frame)
+ * @return a pointer to the buf parameter
+ * @note timecode representation can be a negative timecode and have
+ * more than 24 hours.
+ * @note buf must have enough space to store the timecode representation: 16
+ * bytes is the minimum required size.
+ */
+char *avpriv_timecode_to_string(char *buf, const struct ff_timecode *tc, unsigned frame);
+
+/**
+ * Check if timecode rate is valid and consistent with the drop flag.
+ *
+ * @return 0 on success, negative value on failure
+ */
+int avpriv_check_timecode_rate(void *avcl, AVRational rate, int drop);
+
+/**
+ * Parse SMTPE 12M time representation (hh:mm:ss[:;.]ff). str and rate fields
+ * from tc struct must be set.
+ *
+ * @param avcl A pointer to an arbitrary struct of which the first field is a
+ * pointer to an AVClass struct (used for av_log).
+ * @param tc Timecode struct pointer
+ * @return 0 on success, negative value on failure
+ * @warning Adjustement is only valid in NTSC 29.97
+ */
+int avpriv_init_smpte_timecode(void *avcl, struct ff_timecode *tc);
+
+attribute_deprecated int ff_framenum_to_drop_timecode(int frame_num);
+attribute_deprecated uint32_t ff_framenum_to_smtpe_timecode(unsigned frame, int fps, int drop);
+attribute_deprecated int ff_init_smtpe_timecode(void *avcl, struct ff_timecode *tc);
+#endif
+
+#endif /* AVCODEC_TIMECODE_H */
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/truemotion1.c b/libavcodec/truemotion1.c
index c1e0863..d72cee8 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
*/
@@ -317,7 +317,7 @@ static int truemotion1_decode_header(TrueMotion1Context *s)
const uint8_t *sel_vector_table;
header.header_size = ((s->buf[0] >> 5) | (s->buf[0] << 3)) & 0x7f;
- if (s->buf[0] < 0x10)
+ if (s->buf[0] < 0x10 || header.header_size >= s->size)
{
av_log(s->avctx, AV_LOG_ERROR, "invalid header size (%d)\n", s->buf[0]);
return AVERROR_INVALIDDATA;
@@ -407,6 +407,8 @@ static int truemotion1_decode_header(TrueMotion1Context *s)
s->avctx->pix_fmt = new_pix_fmt;
avcodec_set_dimensions(s->avctx, s->w, s->h);
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
@@ -473,6 +475,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;
}
@@ -513,6 +517,10 @@ hres,vres,i,i%vres (0 < i < 4)
}
#define APPLY_C_PREDICTOR() \
+ if(index > 1023){\
+ av_log(s->avctx, AV_LOG_ERROR, " index %d went out of bounds\n", index); \
+ return; \
+ }\
predictor_pair = s->c_predictor_table[index]; \
horiz_pred += (predictor_pair >> 1); \
if (predictor_pair & 1) { \
@@ -530,6 +538,10 @@ hres,vres,i,i%vres (0 < i < 4)
index++;
#define APPLY_C_PREDICTOR_24() \
+ if(index > 1023){\
+ av_log(s->avctx, AV_LOG_ERROR, " index %d went out of bounds\n", index); \
+ return; \
+ }\
predictor_pair = s->c_predictor_table[index]; \
horiz_pred += (predictor_pair >> 1); \
if (predictor_pair & 1) { \
@@ -548,6 +560,10 @@ hres,vres,i,i%vres (0 < i < 4)
#define APPLY_Y_PREDICTOR() \
+ if(index > 1023){\
+ av_log(s->avctx, AV_LOG_ERROR, " index %d went out of bounds\n", index); \
+ return; \
+ }\
predictor_pair = s->y_predictor_table[index]; \
horiz_pred += (predictor_pair >> 1); \
if (predictor_pair & 1) { \
@@ -565,6 +581,10 @@ hres,vres,i,i%vres (0 < i < 4)
index++;
#define APPLY_Y_PREDICTOR_24() \
+ if(index > 1023){\
+ av_log(s->avctx, AV_LOG_ERROR, " index %d went out of bounds\n", index); \
+ return; \
+ }\
predictor_pair = s->y_predictor_table[index]; \
horiz_pred += (predictor_pair >> 1); \
if (predictor_pair & 1) { \
@@ -852,10 +872,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);
@@ -877,7 +895,7 @@ static av_cold int truemotion1_decode_end(AVCodecContext *avctx)
TrueMotion1Context *s = avctx->priv_data;
av_frame_unref(&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 5d9408d..42badcb 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
*/
@@ -58,11 +58,14 @@ enum TM2_BLOCKS {
typedef struct TM2Context {
AVCodecContext *avctx;
- AVFrame pic;
+ AVFrame *pic;
GetBitContext gb;
DSPContext dsp;
+ uint8_t *buffer;
+ int buffer_size;
+
/* TM2 streams */
int *tokens[TM2_NUM_STREAMS];
int tok_lens[TM2_NUM_STREAMS];
@@ -85,7 +88,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;
@@ -166,9 +169,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);
@@ -190,11 +198,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);
@@ -214,6 +227,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];
}
@@ -270,6 +285,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);
@@ -278,8 +298,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;
}
@@ -322,7 +342,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) {
@@ -336,7 +360,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;
@@ -363,8 +387,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]++];
}
@@ -671,6 +700,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);
@@ -838,39 +872,36 @@ static int decode_frame(AVCodecContext *avctx,
TM2Context * const l = avctx->priv_data;
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size & ~3;
- AVFrame * const p = &l->pic;
+ 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->dsp.bswap_buf((uint32_t*)swbuf, (const uint32_t*)buf, buf_size >> 2);
+ l->dsp.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;
@@ -883,8 +914,7 @@ static int decode_frame(AVCodecContext *avctx,
l->cur = !l->cur;
*got_frame = 1;
- ret = av_frame_ref(data, &l->pic);
- av_free(swbuf);
+ ret = av_frame_ref(data, l->pic);
return (ret < 0) ? ret : buf_size;
}
@@ -900,13 +930,15 @@ static av_cold int decode_init(AVCodecContext *avctx)
}
l->avctx = avctx;
- avcodec_get_frame_defaults(&l->pic);
avctx->pix_fmt = AV_PIX_FMT_BGR24;
+ l->pic = av_frame_alloc();
+ if (!l->pic)
+ return AVERROR(ENOMEM);
ff_dsputil_init(&l->dsp, avctx);
- 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;
@@ -915,15 +947,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 ||
@@ -937,6 +969,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;
@@ -952,7 +985,6 @@ static av_cold int decode_init(AVCodecContext *avctx)
static av_cold int decode_end(AVCodecContext *avctx)
{
TM2Context * const l = avctx->priv_data;
- AVFrame *pic = &l->pic;
int i;
av_free(l->last);
@@ -967,8 +999,10 @@ 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_unref(pic);
+ av_frame_free(&l->pic);
return 0;
}
diff --git a/libavcodec/truespeech.c b/libavcodec/truespeech.c
index 3f56973..d3e3b20 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 c26853e..b4931ec 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;
@@ -68,21 +69,19 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
int buf_size = avpkt->size;
CamtasiaContext * const c = avctx->priv_data;
const unsigned char *encoded = buf;
- AVFrame *frame = data;
+ AVFrame *frame = c->frame;
int zret; // Zlib return code
int ret, 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_reget_buffer(avctx, frame)) < 0)
return ret;
- }
zret = inflateReset(&c->zstream);
if (zret != Z_OK) {
av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret);
return AVERROR_UNKNOWN;
}
- c->zstream.next_in = encoded;
+ c->zstream.next_in = (uint8_t*)encoded;
c->zstream.avail_in = len;
c->zstream.next_out = c->decomp_buf;
c->zstream.avail_out = c->decomp_size;
@@ -111,6 +110,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 */
@@ -136,7 +137,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
@@ -159,6 +160,8 @@ static av_cold int decode_init(AVCodecContext *avctx)
return AVERROR_UNKNOWN;
}
+ c->frame = av_frame_alloc();
+
return 0;
}
@@ -167,6 +170,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 3d22fd7..9bcfa38 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
*/
@@ -231,7 +231,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..b917881 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,22 @@
#define BITSTREAM_READER_LE
#include <limits.h>
+#include "ttadata.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,118 +53,51 @@ typedef struct TTAContext {
int32_t *decode_buffer;
+ uint8_t crc_pass[8];
+ uint8_t *pass;
TTAChannel *ch_ctx;
} 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 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)
{
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++;
+ 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];
}
- *(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);
+ 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;
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);
- memshl(c->dl, c->dl + 1);
- memshl(c->dx, c->dx + 1);
+ dl[4] = -dl[5]; dl[5] = -dl[6];
+ dl[6] = *in - dl[7]; dl[7] = *in;
+ dl[5] += dl[6]; dl[4] += dl[5];
}
-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];
-}
-
-static int tta_get_unary(GetBitContext *gb)
-{
- int ret = 0;
-
- // count ones
- while (get_bits_left(gb) > 0 && get_bits1(gb))
- ret++;
- return ret;
-}
+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 int tta_check_crc(TTAContext *s, const uint8_t *buf, int buf_size)
{
@@ -193,61 +113,96 @@ static int tta_check_crc(TTAContext *s, const uint8_t *buf, int buf_size)
return 0;
}
+static uint64_t tta_check_crc64(uint8_t *pass)
+{
+ 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));
+ }
+
+ return crc ^ UINT64_MAX;
+}
+
+static int allocate_buffers(AVCodecContext *avctx)
+{
+ TTAContext *s = avctx->priv_data;
+
+ if (s->bps < 3) {
+ s->decode_buffer = av_mallocz(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(avctx->channels * sizeof(*s->ch_ctx));
+ if (!s->ch_ctx) {
+ av_freep(&s->decode_buffer);
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
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 +219,33 @@ 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;
+ 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 +256,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 +270,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 +289,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 +300,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 +310,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 +318,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++;
}
@@ -421,32 +360,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 +409,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 +450,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
--- a/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
--- a/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/ttaenc.c b/libavcodec/ttaenc.c
new file mode 100644
index 0000000..e95dd6b
--- a/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(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 24f5747..e7ade93 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
*/
@@ -484,10 +484,8 @@ int ff_twinvq_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
if (tctx->discarded_packets >= 2) {
frame->nb_samples = mtab->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 = (float **)frame->extended_data;
}
@@ -514,7 +512,7 @@ int ff_twinvq_decode_frame(AVCodecContext *avctx, void *data,
*got_frame_ptr = 1;
- return avctx->block_align;
+ return ret;
}
/**
diff --git a/libavcodec/twinvq.h b/libavcodec/twinvq.h
index d3a548a..44215db 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 3b889f5..5e565db 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 0eca07f..7526f13 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"
@@ -67,10 +67,8 @@ static int txd_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return ret;
if (w != avctx->width || h != avctx->height)
avcodec_set_dimensions(avctx, w, h);
- 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;
@@ -83,6 +81,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);
@@ -95,9 +95,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:
@@ -107,6 +111,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 4f787a3..aee713f 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
*/
@@ -52,6 +52,7 @@ static av_cold int ulti_decode_init(AVCodecContext *avctx)
s->blocks = (s->width / 8) * (s->height / 8);
avctx->pix_fmt = AV_PIX_FMT_YUV410P;
avctx->coded_frame = &s->frame;
+ avctx->coded_frame = (AVFrame*) &s->frame;
s->ulti_codebook = ulti_codebook;
avcodec_get_frame_defaults(&s->frame);
@@ -226,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 9ef477f..186993d 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"
@@ -42,6 +44,7 @@
#include "dsputil.h"
#include "libavutil/opt.h"
#include "thread.h"
+#include "frame_thread_encoder.h"
#include "internal.h"
#include "bytestream.h"
#include "version.h"
@@ -49,9 +52,68 @@
#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;
@@ -74,30 +136,47 @@ 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);
}
void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size)
{
- void **p = ptr;
+ 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 + 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;
}
- 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, 0, min_size + FF_INPUT_BUFFER_PADDING_SIZE);
}
/* encoder management */
@@ -138,10 +217,9 @@ av_cold void avcodec_register(AVCodec *codec)
AVCodec **p;
avcodec_init();
p = &first_avcodec;
- while (*p != NULL)
- p = &(*p)->next;
- *p = codec;
codec->next = NULL;
+ while(avpriv_atomic_ptr_cas((void * volatile *)p, NULL, codec))
+ p = &(*p)->next;
if (codec->init_static_data)
codec->init_static_data(codec);
@@ -156,8 +234,8 @@ void avcodec_set_dimensions(AVCodecContext *s, int width, int height)
{
s->coded_width = width;
s->coded_height = height;
- s->width = width;
- s->height = height;
+ s->width = FF_CEIL_RSHIFT(width, s->lowres);
+ s->height = FF_CEIL_RSHIFT(height, s->lowres);
}
#if HAVE_NEON || ARCH_PPC || HAVE_MMX
@@ -180,6 +258,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:
@@ -195,22 +274,63 @@ 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_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_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_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_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_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:
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;
@@ -220,15 +340,18 @@ 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;
}
@@ -240,16 +363,27 @@ 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++)
@@ -271,6 +405,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)
@@ -293,10 +450,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) {
@@ -356,7 +513,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;
@@ -370,7 +530,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;
@@ -426,8 +586,10 @@ static int audio_get_buffer(AVCodecContext *avctx, AVFrame *frame)
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]);
@@ -472,6 +634,7 @@ static int video_get_buffer(AVCodecContext *s, AVFrame *pic)
for (i = 0; i < 4 && pool->pools[i]; i++) {
const int h_shift = i == 0 ? 0 : h_chroma_shift;
const int v_shift = i == 0 ? 0 : v_chroma_shift;
+ int is_planar = pool->pools[2] || (i==0 && s->pix_fmt == AV_PIX_FMT_GRAY8);
pic->linesize[i] = pool->linesize[i];
@@ -480,7 +643,7 @@ static int video_get_buffer(AVCodecContext *s, AVFrame *pic)
goto fail;
// no edge if EDGE EMU or not planar YUV
- if ((s->flags & CODEC_FLAG_EMU_EDGE) || !pool->pools[2])
+ if ((s->flags & CODEC_FLAG_EMU_EDGE) || !is_planar)
pic->data[i] = pic->buf[i]->data;
else {
pic->data[i] = pic->buf[i]->data +
@@ -504,6 +667,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;
@@ -527,49 +713,33 @@ 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)
+int ff_init_buffer_info(AVCodecContext *avctx, AVFrame *frame)
{
- 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_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
-{
- int ret;
+ if (avctx->pkt) {
+ frame->pkt_pts = avctx->pkt->pts;
+ av_frame_set_pkt_pos (frame, avctx->pkt->pos);
+ av_frame_set_pkt_duration(frame, avctx->pkt->duration);
+ av_frame_set_pkt_size (frame, avctx->pkt->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;
- switch (avctx->codec_type) {
+ switch (avctx->codec->type) {
case AVMEDIA_TYPE_VIDEO:
- frame->width = FFMAX(avctx->width, avctx->coded_width);
- frame->height = FFMAX(avctx->height, avctx->coded_height);
+ 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));
if (frame->format < 0)
frame->format = avctx->pix_fmt;
if (!frame->sample_aspect_ratio.num)
frame->sample_aspect_ratio = avctx->sample_aspect_ratio;
-
- if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0)
- return ret;
+ 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);
break;
case AVMEDIA_TYPE_AUDIO:
if (!frame->sample_rate)
@@ -592,23 +762,59 @@ 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;
+}
- frame->pkt_pts = avctx->pkt ? avctx->pkt->pts : AV_NOPTS_VALUE;
- frame->reordered_opaque = avctx->reordered_opaque;
+#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
+
+static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags)
+{
+ 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 ((ret = ff_init_buffer_info(avctx, frame)) < 0)
+ return ret;
#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
@@ -631,7 +837,7 @@ FF_DISABLE_DEPRECATION_WARNINGS
* avcodec_default_get_buffer
*/
if (frame->buf[0])
- return 0;
+ goto end;
priv = av_mallocz(sizeof(*priv));
if (!priv) {
@@ -707,6 +913,7 @@ do { \
av_buffer_unref(&dummy_buf);
+end:
frame->width = avctx->width;
frame->height = avctx->height;
@@ -731,13 +938,29 @@ FF_ENABLE_DEPRECATION_WARNINGS
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);
@@ -760,9 +983,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);
}
@@ -812,25 +1045,37 @@ enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const en
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->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 */
frame->extended_data = frame->data;
+ av_frame_set_colorspace(frame, AVCOL_SPC_UNSPECIFIED);
}
AVFrame *avcodec_alloc_frame(void)
{
- AVFrame *frame = av_mallocz(sizeof(AVFrame));
+ AVFrame *frame = av_malloc(sizeof(AVFrame));
if (frame == NULL)
return NULL;
+ frame->extended_data = NULL;
avcodec_get_frame_defaults(frame);
return frame;
@@ -851,6 +1096,64 @@ void avcodec_free_frame(AVFrame **frame)
av_freep(frame);
}
+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)
+
+int av_codec_get_max_lowres(const AVCodec *codec)
+{
+ return codec->max_lowres;
+}
+
+static void avcodec_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;
+}
+
+#if FF_API_AVCODEC_OPEN
+int attribute_align_arg avcodec_open(AVCodecContext *avctx, AVCodec *codec)
+{
+ return avcodec_open2(avctx, codec, NULL);
+}
+#endif
+
+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;
@@ -860,12 +1163,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)
@@ -877,18 +1180,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) {
@@ -922,15 +1216,19 @@ 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)
+ // only call avcodec_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)
avcodec_set_dimensions(avctx, avctx->coded_width, avctx->coded_height);
else if (avctx->width && avctx->height)
avcodec_set_dimensions(avctx, avctx->width, avctx->height);
+ }
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");
avcodec_set_dimensions(avctx, 0, 0);
}
@@ -952,14 +1250,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;
}
@@ -970,7 +1279,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;
@@ -979,6 +1300,13 @@ 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 (av_codec_is_encoder(avctx->codec)) {
int i;
if (avctx->codec->sample_fmts) {
@@ -993,7 +1321,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;
}
@@ -1002,8 +1333,13 @@ 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;
}
@@ -1013,55 +1349,90 @@ 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 &&
+ avctx->codec_id != AV_CODEC_ID_PNG // For mplayer
+ ) {
+ 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 (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;
}
}
@@ -1070,14 +1441,46 @@ 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) {
+ av_log(avctx, AV_LOG_ERROR, "Unable to open iconv context "
+ "with input character encoding \"%s\"\n", avctx->sub_charenc);
+ ret = AVERROR(errno);
+ 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
+ }
+ }
+ }
}
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;
@@ -1094,10 +1497,27 @@ 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;
+ avpkt->destruct = NULL;
+ }
+ }
if (avpkt->data) {
AVBufferRef *buf = avpkt->buf;
@@ -1107,8 +1527,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
@@ -1120,10 +1542,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.
*/
@@ -1137,6 +1567,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)
@@ -1171,7 +1602,8 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
AVFrame tmp;
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;
@@ -1200,8 +1632,10 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
/* check for valid frame size */
if (frame) {
if (avctx->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) {
- if (frame->nb_samples > avctx->frame_size)
+ if (frame->nb_samples > avctx->frame_size) {
+ av_log(avctx, AV_LOG_ERROR, "more samples than frame size (avcodec_encode_audio2)\n");
return AVERROR(EINVAL);
+ }
} else if (!(avctx->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) {
if (frame->nb_samples < avctx->frame_size &&
!avctx->internal->last_audio_frame) {
@@ -1214,6 +1648,7 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
}
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;
}
@@ -1234,9 +1669,30 @@ 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;
+ avpkt->destruct = user_pkt.destruct;
+ } 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;
}
@@ -1261,16 +1717,138 @@ 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 frame0 = { { 0 } };
+ AVFrame *frame;
+ int ret, samples_size, got_packet;
+
+ av_init_packet(&pkt);
+ pkt.data = buf;
+ pkt.size = buf_size;
+
+ if (samples) {
+ frame = &frame0;
+ avcodec_get_frame_defaults(frame);
+
+ 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");
+ 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)
+ 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)
+ 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);
+
+ 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);
@@ -1284,14 +1862,36 @@ 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;
+ avpkt->destruct = user_pkt.destruct;
+ } 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;
}
@@ -1301,6 +1901,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;
@@ -1314,13 +1916,44 @@ 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;
+ }
+ 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;
+ }
+ 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 void apply_param_change(AVCodecContext *avctx, AVPacket *avpkt)
{
int size = 0;
@@ -1363,19 +1996,55 @@ static void apply_param_change(AVCodecContext *avctx, AVPacket *avpkt)
}
}
+static int add_metadata_from_side_data(AVCodecContext *avctx, AVFrame *frame)
+{
+ int size, ret = 0;
+ const uint8_t *side_metadata;
+ const uint8_t *end;
+
+ side_metadata = av_packet_get_side_data(avctx->pkt,
+ AV_PKT_DATA_STRINGS_METADATA, &size);
+ if (!side_metadata)
+ goto end;
+ end = side_metadata + size;
+ if (size && end[-1])
+ return AVERROR_INVALIDDATA;
+ while (side_metadata < end) {
+ const uint8_t *key = side_metadata;
+ const uint8_t *val = side_metadata + strlen(key) + 1;
+ int ret;
+
+ if (val >= end)
+ return AVERROR_INVALIDDATA;
+
+ ret = av_dict_set(avpriv_frame_get_metadatap(frame), key, val, 0);
+ if (ret < 0)
+ break;
+ side_metadata = val + strlen(val) + 1;
+ }
+end:
+ return ret;
+}
+
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->pkt = avpkt;
- apply_param_change(avctx, avpkt);
+ return AVERROR(EINVAL);
avcodec_get_frame_defaults(picture);
@@ -1383,24 +2052,40 @@ int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *pi
av_frame_unref(&avci->to_free);
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);
+ apply_param_change(avctx, &tmp);
+ avctx->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);
emms_c(); //needed to avoid an emms_c() call before every return;
+ avctx->pkt = NULL;
+ if (did_split) {
+ av_packet_free_side_data(&tmp);
+ if(ret == tmp.size)
+ ret = avpkt->size;
+ }
+
if (ret < 0 && picture->data[0])
av_frame_unref(picture);
@@ -1412,6 +2097,10 @@ 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
ret = 0;
@@ -1423,10 +2112,59 @@ int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *pi
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 = { { 0 } };
+ int ret, got_frame = 0;
+
+ 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);
+ 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;
+ }
+ 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 planar, channels;
@@ -1434,28 +2172,118 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
*got_frame_ptr = 0;
- avctx->pkt = avpkt;
-
if (!avpkt->data && avpkt->size) {
av_log(avctx, AV_LOG_ERROR, "invalid packet: NULL data, size != 0\n");
return AVERROR(EINVAL);
}
-
- apply_param_change(avctx, avpkt);
+ 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);
+ }
avcodec_get_frame_defaults(frame);
if (!avctx->refcounted_frames)
av_frame_unref(&avci->to_free);
- 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;
+ // copy to ensure we do not change avpkt
+ AVPacket tmp = *avpkt;
+ int did_split = av_packet_split_side_data(&tmp);
+ apply_param_change(avctx, &tmp);
+
+ avctx->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->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);
+ }
+ if (avctx->internal->skip_samples && *got_frame_ptr) {
+ 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) {
+ 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;
+ }
+ }
+ avctx->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) {
avci->to_free = *frame;
avci->to_free.extended_data = avci->to_free.data;
@@ -1470,25 +2298,176 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
/* many decoders assign whole AVFrames, thus overwriting extended_data;
* make sure it's set correctly; assume decoders that actually use
* extended_data are doing it correctly */
- planar = av_sample_fmt_is_planar(frame->format);
- channels = av_get_channel_layout_nb_channels(frame->channel_layout);
- if (!(planar && channels > AV_NUM_DATA_POINTERS))
- frame->extended_data = frame->data;
+ if (*got_frame_ptr) {
+ planar = av_sample_fmt_is_planar(frame->format);
+ channels = av_frame_get_channels(frame);
+ if (!(planar && channels > AV_NUM_DATA_POINTERS))
+ frame->extended_data = frame->data;
+ } else {
+ frame->extended_data = NULL;
+ }
+
+ 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) {
+ 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);
+ ret = AVERROR(errno);
+ 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_assert0(!"requesting subtitles recoding without iconv");
+#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->pkt = avpkt;
*got_sub_ptr = 0;
- ret = avctx->codec->decode(avctx, sub, got_sub_ptr, avpkt);
- if (*got_sub_ptr)
- avctx->frame_number++;
+ avcodec_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);
+
+ pkt_recoded = tmp;
+ ret = recode_subtitle(avctx, &pkt_recoded, &tmp);
+ if (ret < 0) {
+ *got_sub_ptr = 0;
+ } else {
+ avctx->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->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;
}
@@ -1511,29 +2490,45 @@ void avsubtitle_free(AVSubtitle *sub)
memset(sub, 0, sizeof(AVSubtitle));
}
+av_cold int ff_codec_close_recursive(AVCodecContext *avctx)
+{
+ int ret = 0;
+
+ ff_unlock_avcodec();
+
+ ret = avcodec_close(avctx);
+
+ ff_lock_avcodec(NULL);
+ return ret;
+}
+
av_cold int avcodec_close(AVCodecContext *avctx)
{
- /* If there is a user-supplied mutex locking routine, call it. */
- if (lockmgr_cb) {
- if ((*lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN))
- return -1;
- }
+ int ret;
- entangled_thread_counter++;
- if (entangled_thread_counter != 1) {
- av_log(avctx, AV_LOG_ERROR, "insufficient thread locking around avcodec_open/close()\n");
- entangled_thread_counter--;
- return -1;
- }
+ if (!avctx)
+ return 0;
+
+ ret = ff_lock_avcodec(avctx);
+ if (ret < 0)
+ return ret;
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_unlock_avcodec();
+ ff_frame_thread_encoder_free(avctx);
+ ff_lock_avcodec(avctx);
+ }
if (HAVE_THREADS && avctx->thread_opaque)
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);
if (!avctx->refcounted_frames)
av_frame_unref(&avctx->internal->to_free);
for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++)
@@ -1550,19 +2545,33 @@ av_cold int avcodec_close(AVCodecContext *avctx)
av_freep(&avctx->extradata);
avctx->codec = NULL;
avctx->active_thread_type = 0;
- entangled_thread_counter--;
- /* Release any user-supplied mutex. */
- if (lockmgr_cb) {
- (*lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE);
- }
+ ff_unlock_avcodec();
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_OPUS_DEPRECATED: return AV_CODEC_ID_OPUS;
+ case AV_CODEC_ID_TAK_DEPRECATED : return AV_CODEC_ID_TAK;
+ 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_ESCAPE130_DEPRECATED : return AV_CODEC_ID_ESCAPE130;
+ case AV_CODEC_ID_G2M_DEPRECATED : return AV_CODEC_ID_G2M;
+ case AV_CODEC_ID_WEBP_DEPRECATED: return AV_CODEC_ID_WEBP;
+ 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) {
@@ -1614,27 +2623,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)
@@ -1644,7 +2650,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,
@@ -1659,49 +2665,66 @@ 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;
AVRational display_aspect_ratio;
- 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 if (enc->codec_name[0] != '\0') {
- codec_name = enc->codec_name;
- } 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->pix_fmt != AV_PIX_FMT_NONE) {
+ char detail[256] = "(";
+ const char *colorspace_name;
snprintf(buf + strlen(buf), buf_size - strlen(buf),
", %s",
av_get_pix_fmt_name(enc->pix_fmt));
+ if (enc->bits_per_raw_sample &&
+ 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),
+ enc->color_range == AVCOL_RANGE_MPEG ? "tv, ": "pc, ");
+
+ colorspace_name = av_get_colorspace_name(enc->colorspace);
+ if (colorspace_name)
+ av_strlcatf(detail, sizeof(detail), "%s, ", colorspace_name);
+
+ if (strlen(detail) > 1) {
+ detail[strlen(detail) - 2] = 0;
+ av_strlcatf(buf, buf_size, "%s)", detail);
+ }
}
if (enc->width) {
snprintf(buf + strlen(buf), buf_size - strlen(buf),
@@ -1713,7 +2736,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);
}
@@ -1730,12 +2753,6 @@ 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->sample_rate) {
snprintf(buf + strlen(buf), buf_size - strlen(buf),
", %d Hz", enc->sample_rate);
@@ -1748,16 +2765,20 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
}
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) {
@@ -1772,6 +2793,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);
}
}
@@ -1790,18 +2814,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)
@@ -1811,6 +2847,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);
}
@@ -1818,9 +2857,12 @@ 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:
@@ -1828,10 +2870,12 @@ int av_get_exact_bits_per_sample(enum AVCodecID codec_id)
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:
@@ -1860,6 +2904,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) {
@@ -1890,8 +2955,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 */
@@ -1900,11 +2965,10 @@ 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;
@@ -1950,6 +3014,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 */
@@ -1960,6 +3028,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;
@@ -1981,6 +3053,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) {
@@ -1998,11 +3073,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);
}
@@ -2012,8 +3091,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;
@@ -2058,7 +3141,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);
@@ -2075,8 +3158,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/MPlayer/incoming/ "
+ "and contact the ffmpeg-devel mailing list.\n");
va_end(argument_list);
}
@@ -2088,10 +3171,9 @@ static AVHWAccel *first_hwaccel = NULL;
void av_register_hwaccel(AVHWAccel *hwaccel)
{
AVHWAccel **p = &first_hwaccel;
- while (*p)
- p = &(*p)->next;
- *p = hwaccel;
hwaccel->next = NULL;
+ while(avpriv_atomic_ptr_cas((void * volatile *)p, NULL, hwaccel))
+ p = &(*p)->next;
}
AVHWAccel *av_hwaccel_next(AVHWAccel *hwaccel)
@@ -2130,6 +3212,38 @@ 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) {
@@ -2177,6 +3291,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 avctx->get_format(avctx, fmt);
+}
+
int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags)
{
f->owner = avctx;
@@ -2200,10 +3319,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)
@@ -2221,13 +3368,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 0a1317e..c00179e 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 3492595..e3ef22d 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
*/
@@ -70,7 +70,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, 10), last + 1,
bits, sizeof(*bits), sizeof(*bits),
codes, sizeof(*codes), sizeof(*codes),
syms, sizeof(*syms), sizeof(*syms), 0);
@@ -333,12 +333,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 36ac335..c4885a5 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
*/
@@ -405,7 +405,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.
@@ -503,15 +503,11 @@ 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;
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
--- a/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 7efbb96..51ec6ef 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
--- a/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..7a97d5a
--- a/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 = avcodec_alloc_frame();
+
+ 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
--- a/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..85cf7c8
--- a/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 = avcodec_alloc_frame();
+
+ 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 91cd823..c4ce3df 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 0532daf..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));
- 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 dfa2ec7..ea0f434 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
*/
@@ -25,7 +25,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.
*/
@@ -43,10 +43,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.
*/
@@ -147,11 +147,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],
@@ -258,7 +258,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];
@@ -281,7 +281,8 @@ static int vaapi_h264_start_frame(AVCodecContext *avctx,
if (!iq_matrix)
return -1;
memcpy(iq_matrix->ScalingList4x4, h->pps.scaling_matrix4, sizeof(iq_matrix->ScalingList4x4));
- memcpy(iq_matrix->ScalingList8x8, h->pps.scaling_matrix8, sizeof(iq_matrix->ScalingList8x8));
+ memcpy(iq_matrix->ScalingList8x8[0], h->pps.scaling_matrix8[0], sizeof(iq_matrix->ScalingList8x8[0]));
+ memcpy(iq_matrix->ScalingList8x8[1], h->pps.scaling_matrix8[3], sizeof(iq_matrix->ScalingList8x8[0]));
return 0;
}
diff --git a/libavcodec/vaapi_internal.h b/libavcodec/vaapi_internal.h
index 0292654..1ac0e9f 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..5afa406
--- a/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));
+ 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 cf0a4b5..d626f24 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
*/
diff --git a/libavcodec/vaapi_mpeg4.c b/libavcodec/vaapi_mpeg4.c
index a0f2966..5923b07 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
*/
@@ -122,25 +122,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 a9ab3c7..b8f0530 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 a349d8f..a8c71ed 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 {
DSPContext dsp;
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,14 +90,17 @@ 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];
- ctx->dsp.add_hfyu_median_prediction(dst, dst-stride, val,
- width, &left, &left_top);
+ ctx->dsp.add_hfyu_median_prediction(dst, dst-stride, val, width, &left, &left_top);
} else {
dst[0] = val[0];
for (j = 1; j < width; j++)
@@ -122,13 +121,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 +151,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;
diff --git a/libavcodec/vc1.c b/libavcodec/vc1.c
index d6586bf..f755811 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
*/
@@ -293,7 +293,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");
@@ -380,8 +380,9 @@ 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);
+ avcodec_set_dimensions(v->s.avctx, w, h);
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 +434,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);
@@ -502,9 +501,10 @@ static int decode_sequence_header_adv(VC1Context *v, GetBitContext *gb)
}
if (get_bits1(gb)) {
- v->color_prim = get_bits(gb, 8);
- v->transfer_char = get_bits(gb, 8);
- v->matrix_coef = get_bits(gb, 8);
+ v->s.avctx->color_primaries = get_bits(gb, 8);
+ v->s.avctx->color_trc = get_bits(gb, 8);
+ v->s.avctx->colorspace = get_bits(gb, 8);
+ v->s.avctx->color_range = AVCOL_RANGE_MPEG;
}
}
@@ -525,6 +525,7 @@ 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;
av_log(avctx, AV_LOG_DEBUG, "Entry point: %08X\n", show_bits_long(gb, 32));
v->broken_link = get_bits1(gb);
@@ -532,6 +533,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);
@@ -545,10 +548,14 @@ 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;
}
+ avcodec_set_dimensions(avctx, w, h);
if (v->extended_mv)
v->extended_dmv = get_bits1(gb);
if ((v->range_mapy_flag = get_bits1(gb))) {
@@ -622,6 +629,8 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
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 =
@@ -838,8 +847,11 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
int mbmodetab, imvtab, icbptab, twomvbptab, fourmvbptab; /* useful only for debugging */
int field_mode, fcm;
+ 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;
@@ -897,6 +909,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");
@@ -908,6 +922,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;
@@ -1180,7 +1196,6 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
if (v->bfraction == 0) {
return -1;
}
- return -1; // This codepath is still incomplete thus it is disabled
}
if (v->extended_mv)
v->mvrange = get_unary(gb, 0, 3);
@@ -1200,6 +1215,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 0ece45a..c77ab7c 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
*/
@@ -212,9 +212,6 @@ typedef struct VC1Context{
int panscanflag; ///< NUMPANSCANWIN, TOPLEFT{X,Y}, BOTRIGHT{X,Y} present
int refdist_flag; ///< REFDIST syntax element present in II, IP, PI or PP field picture headers
int extended_dmv; ///< Additional extended dmv range at P/B frame-level
- int color_prim; ///< 8bits, chroma coordinates of the color primaries
- int transfer_char; ///< 8bits, Opto-electronic transfer characteristics
- int matrix_coef; ///< 8bits, Color primaries->YCbCr transform matrix
int hrd_param_flag; ///< Presence of Hypothetical Reference
///< Decoder parameters
int psf; ///< Progressive Segmented Frame
@@ -227,6 +224,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)
@@ -353,7 +351,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_parser.c b/libavcodec/vc1_parser.c
index 1bedd98..cc29ce1 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
*/
@@ -45,11 +45,13 @@ static void vc1_extract_headers(AVCodecParserContext *s, AVCodecContext *avctx,
vpc->v.s.avctx = avctx;
vpc->v.parse_only = 1;
+ vpc->v.first_pic_header_flag = 1;
next = buf;
s->repeat_pict = 0;
for(start = buf, end = buf + buf_size; next < end; start = next){
int buf2_size, size;
+ int ret;
next = find_next_marker(start + 4, end);
size = next - start - 4;
@@ -65,9 +67,12 @@ static void vc1_extract_headers(AVCodecParserContext *s, AVCodecContext *avctx,
break;
case VC1_CODE_FRAME:
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)
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 84e8188..eecb045 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
*/
@@ -183,15 +183,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 caedfd8..682a9d2 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
*/
@@ -38,6 +38,8 @@
#include "msmpeg4data.h"
#include "unary.h"
#include "mathops.h"
+#include "vdpau_internal.h"
+#include "libavutil/avassert.h"
#undef NDEBUG
#include <assert.h>
@@ -452,15 +454,18 @@ static void vc1_mc_1mv(VC1Context *v, int dir)
uint8_t *uvbuf = s->edge_emu_buffer + 19 * s->linesize;
srcY -= s->mspel * (1 + s->linesize);
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer, srcY, s->linesize,
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, s->linesize,
+ srcY, s->linesize,
17 + s->mspel * 2, 17 + s->mspel * 2,
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->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, 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, s->uvlinesize, srcU, 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, s->uvlinesize, srcV, s->uvlinesize,
+ 8 + 1, 8 + 1, uvsrc_x, uvsrc_y,
+ s->h_edge_pos >> 1, v_edge_pos >> 1);
srcU = uvbuf;
srcV = uvbuf + 16;
/* if we deal with range reduction we need to scale source blocks */
@@ -625,6 +630,8 @@ static void 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;
@@ -693,7 +700,7 @@ static void vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg)
|| (unsigned)(src_y - (s->mspel << fieldmv)) > v_edge_pos - (my & 3) - ((8 + s->mspel * 2) << fieldmv)) {
srcY -= s->mspel * (1 + (s->linesize << fieldmv));
/* check emulate edge stride and offset */
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer, srcY, s->linesize,
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, s->linesize, srcY, s->linesize,
9 + s->mspel * 2, (9 + s->mspel * 2) << fieldmv,
src_x - s->mspel, src_y - (s->mspel << fieldmv),
s->h_edge_pos, v_edge_pos);
@@ -908,11 +915,11 @@ static void vc1_mc_4mv_chroma(VC1Context *v, int dir)
|| s->h_edge_pos < 18 || v_edge_pos < 18
|| (unsigned)uvsrc_x > (s->h_edge_pos >> 1) - 9
|| (unsigned)uvsrc_y > (v_edge_pos >> 1) - 9) {
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer , srcU, s->uvlinesize,
- 8 + 1, 8 + 1, uvsrc_x, uvsrc_y,
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, s->uvlinesize, srcU,
+ s->uvlinesize, 8 + 1, 8 + 1, uvsrc_x, uvsrc_y,
s->h_edge_pos >> 1, v_edge_pos >> 1);
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer + 16, srcV, s->uvlinesize,
- 8 + 1, 8 + 1, uvsrc_x, uvsrc_y,
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer + 16, s->uvlinesize, srcV,
+ s->uvlinesize, 8 + 1, 8 + 1, uvsrc_x, uvsrc_y,
s->h_edge_pos >> 1, v_edge_pos >> 1);
srcU = s->edge_emu_buffer;
srcV = s->edge_emu_buffer + 16;
@@ -1003,33 +1010,38 @@ static void 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
|| s->h_edge_pos < 10 || v_edge_pos < (5 << fieldmv)
|| (unsigned)uvsrc_x > (s->h_edge_pos >> 1) - 5
|| (unsigned)uvsrc_y > v_edge_pos - (5 << fieldmv)) {
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer, srcU, s->uvlinesize,
- 5, (5 << fieldmv), uvsrc_x, uvsrc_y,
- s->h_edge_pos >> 1, v_edge_pos);
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer + 16, srcV, s->uvlinesize,
- 5, (5 << fieldmv), uvsrc_x, uvsrc_y,
- s->h_edge_pos >> 1, v_edge_pos);
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, s->uvlinesize, srcU,
+ s->uvlinesize, 5, (5 << fieldmv), uvsrc_x,
+ uvsrc_y, s->h_edge_pos >> 1, v_edge_pos);
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer + 16, s->uvlinesize, srcV,
+ s->uvlinesize, 5, (5 << fieldmv), uvsrc_x,
+ uvsrc_y, s->h_edge_pos >> 1, v_edge_pos);
srcU = s->edge_emu_buffer;
srcV = s->edge_emu_buffer + 16;
@@ -1204,6 +1216,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
@@ -1666,7 +1679,7 @@ static inline void 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;
@@ -1800,11 +1813,10 @@ static inline void 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)
@@ -1843,27 +1855,28 @@ static inline void 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 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 */
@@ -1955,15 +1968,17 @@ static void vc1_interp_mc(VC1Context *v)
uint8_t *uvbuf = s->edge_emu_buffer + 19 * s->linesize;
srcY -= s->mspel * (1 + s->linesize);
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer, srcY, s->linesize,
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, s->linesize, srcY, s->linesize,
17 + s->mspel * 2, 17 + s->mspel * 2,
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->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, 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, s->uvlinesize, srcU, 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, s->uvlinesize, srcV, s->uvlinesize,
+ 8 + 1, 8 + 1, uvsrc_x, uvsrc_y,
+ s->h_edge_pos >> 1, v_edge_pos >> 1);
srcU = uvbuf;
srcV = uvbuf + 16;
/* if we deal with range reduction we need to scale source blocks */
@@ -2780,7 +2795,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;
@@ -2992,7 +3007,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;
@@ -3767,7 +3782,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);
@@ -3973,11 +3988,11 @@ static int vc1_decode_p_mb_intfi(VC1Context *v)
int val; /* temp values */
int first_block = 1;
int dst_idx, off;
- int pred_flag;
+ int pred_flag = 0;
int block_cbp = 0, pat, block_tt = 0;
int idx_mbmode = 0;
- mquant = v->pq; /* Loosy initialization */
+ mquant = v->pq; /* Lossy initialization */
idx_mbmode = get_vlc2(gb, v->mbmode_vlc->table, VC1_IF_MBMODE_VLC_BITS, 2);
if (idx_mbmode <= 1) { // intra MB
@@ -4245,9 +4260,9 @@ static void vc1_decode_b_mb_intfi(VC1Context *v)
int fwd;
int dmv_x[2], dmv_y[2], pred_flag[2];
int bmvtype = BMV_TYPE_BACKWARD;
- int idx_mbmode, interpmvp;
+ int idx_mbmode;
- mquant = v->pq; /* Loosy initialization */
+ mquant = v->pq; /* Lossy initialization */
s->mb_intra = 0;
idx_mbmode = get_vlc2(gb, v->mbmode_vlc->table, VC1_IF_MBMODE_VLC_BITS, 2);
@@ -4298,6 +4313,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)
@@ -4320,7 +4336,7 @@ 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) {
@@ -4533,9 +4549,9 @@ static int vc1_decode_b_mb_intfr(VC1Context *v)
if (mb_has_coeffs)
cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc->table, VC1_CBPCY_P_VLC_BITS, 2);
if (!direct) {
- if (bmvtype == BMV_TYPE_INTERPOLATED & twomv) {
+ if (bmvtype == BMV_TYPE_INTERPOLATED && twomv) {
v->fourmvbp = get_vlc2(gb, v->fourmvbp_vlc->table, VC1_4MV_BLOCK_PATTERN_VLC_BITS, 1);
- } else if (bmvtype == BMV_TYPE_INTERPOLATED | twomv) {
+ } else if (bmvtype == BMV_TYPE_INTERPOLATED || twomv) {
v->twomvbp = get_vlc2(gb, v->twomvbp_vlc->table, VC1_2MV_BLOCK_PATTERN_VLC_BITS, 1);
}
}
@@ -5424,6 +5440,7 @@ 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;
@@ -5441,10 +5458,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);
@@ -5523,7 +5538,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 ||
@@ -5569,6 +5585,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;
@@ -5585,8 +5602,18 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx)
avctx->flags |= CODEC_FLAG_EMU_EDGE;
v->s.flags |= CODEC_FLAG_EMU_EDGE;
- 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_h264chroma_init(&v->h264chroma, 8);
ff_vc1dsp_init(&v->vc1dsp);
@@ -5600,8 +5627,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) {
@@ -5635,16 +5662,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;
@@ -5687,6 +5714,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;
}
@@ -5738,14 +5770,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 */
@@ -5757,13 +5794,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;
@@ -5776,12 +5822,16 @@ 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;
+ if (avctx->hwaccel ||
+ s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
+ buf_start_second_field = start;
tmp = av_realloc(slices, sizeof(*slices) * (n_slices+1));
if (!tmp)
goto err;
@@ -5833,6 +5883,9 @@ 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
+ if (avctx->hwaccel ||
+ s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
+ buf_start_second_field = divider;
tmp = av_realloc(slices, sizeof(*slices) * (n_slices+1));
if (!tmp)
goto err;
@@ -5890,6 +5943,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;
}
@@ -5918,12 +5973,20 @@ 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;
+ }
+
// process pulldown flags
s->current_picture_ptr->f.repeat_pict = 0;
// Pulldown flags are only valid when 'broadcast' has been set.
@@ -5961,16 +6024,57 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
goto err;
}
+ v->s.current_picture_ptr->f.interlaced_frame = (v->fcm != PROGRESSIVE);
+ v->s.current_picture_ptr->f.top_field_first = v->tff;
+
s->me.qpel_put = s->dsp.put_qpel_pixels_tab;
s->me.qpel_avg = s->dsp.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;
@@ -5987,10 +6091,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) {
@@ -6001,7 +6102,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
continue;
}
v->second_field = 1;
- v->blocks_off = s->mb_width * s->mb_height << 1;
+ 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;
@@ -6032,8 +6133,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;
@@ -6054,6 +6168,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);
}
@@ -6077,11 +6193,11 @@ 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);
} else if (s->last_picture_ptr != NULL) {
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);
}
if (s->last_picture_ptr || s->low_delay) {
*got_frame = 1;
@@ -6158,6 +6274,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 12295ff..aab9d1a 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,8 +25,10 @@
*
*/
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "h264chroma.h"
+#include "rnd_avg.h"
#include "vc1dsp.h"
@@ -562,8 +564,8 @@ static av_always_inline int vc1_mspel_filter(const uint8_t *src, int stride, int
/** Function used to do motion compensation with bicubic interpolation
*/
-#define VC1_MSPEL_MC(OP, OPNAME)\
-static av_always_inline void OPNAME ## vc1_mspel_mc(uint8_t *dst, const uint8_t *src, int stride, int hmode, int vmode, int rnd)\
+#define VC1_MSPEL_MC(OP, OP4, OPNAME)\
+static av_always_inline void OPNAME ## vc1_mspel_mc(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int hmode, int vmode, int rnd)\
{\
int i, j;\
\
@@ -616,13 +618,24 @@ static av_always_inline void OPNAME ## vc1_mspel_mc(uint8_t *dst, const uint8_t
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;\
+ }\
}
#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 */
@@ -666,7 +679,7 @@ static void put_no_rnd_vc1_chroma_mc8_c(uint8_t *dst/*align 8*/, uint8_t *src/*a
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++)
{
@@ -690,7 +703,7 @@ static void put_no_rnd_vc1_chroma_mc4_c(uint8_t *dst, uint8_t *src, int stride,
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++)
{
@@ -711,7 +724,7 @@ static void avg_no_rnd_vc1_chroma_mc8_c(uint8_t *dst/*align 8*/, uint8_t *src/*a
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++)
{
@@ -728,6 +741,26 @@ static void avg_no_rnd_vc1_chroma_mc8_c(uint8_t *dst/*align 8*/, uint8_t *src/*a
}
}
+static void avg_no_rnd_vc1_chroma_mc4_c(uint8_t *dst/*align 8*/, uint8_t *src/*align 1*/, int stride, int h, int x, int y){
+ const int A=(8-x)*(8-y);
+ const int B=( x)*(8-y);
+ const int C=(8-x)*( y);
+ const int D=( x)*( y);
+ int i;
+
+ av_assert2(x<8 && y<8 && x>=0 && y>=0);
+
+ for(i=0; i<h; i++)
+ {
+ dst[0] = avg2(dst[0], ((A*src[0] + B*src[1] + C*src[stride+0] + D*src[stride+1] + 32 - 4) >> 6));
+ dst[1] = avg2(dst[1], ((A*src[1] + B*src[2] + C*src[stride+1] + D*src[stride+2] + 32 - 4) >> 6));
+ dst[2] = avg2(dst[2], ((A*src[2] + B*src[3] + C*src[stride+2] + D*src[stride+3] + 32 - 4) >> 6));
+ dst[3] = avg2(dst[3], ((A*src[3] + B*src[4] + C*src[stride+3] + D*src[stride+4] + 32 - 4) >> 6));
+ dst+= stride;
+ src+= stride;
+ }
+}
+
#if CONFIG_WMV3IMAGE_DECODER || CONFIG_VC1IMAGE_DECODER
static void sprite_h_c(uint8_t *dst, const uint8_t *src, int offset, int advance, int count)
@@ -808,7 +841,7 @@ 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] = ff_put_pixels8x8_c;
+ dsp->put_vc1_mspel_pixels_tab[ 0] = put_pixels8x8_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;
@@ -825,7 +858,7 @@ av_cold void ff_vc1dsp_init(VC1DSPContext* dsp) {
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] = ff_avg_pixels8x8_c;
+ dsp->avg_vc1_mspel_pixels_tab[ 0] = avg_pixels8x8_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;
@@ -845,6 +878,7 @@ av_cold void ff_vc1dsp_init(VC1DSPContext* dsp) {
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;
dsp->put_no_rnd_vc1_chroma_pixels_tab[1] = put_no_rnd_vc1_chroma_mc4_c;
+ dsp->avg_no_rnd_vc1_chroma_pixels_tab[1] = avg_no_rnd_vc1_chroma_mc4_c;
#if CONFIG_WMV3IMAGE_DECODER || CONFIG_VC1IMAGE_DECODER
dsp->sprite_h = sprite_h_c;
diff --git a/libavcodec/vc1dsp.h b/libavcodec/vc1dsp.h
index 84d4b70..a0d6048 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
*/
@@ -32,6 +32,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);
@@ -56,8 +58,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[16];
+ vc1op_pixels_func avg_vc1_mspel_pixels_tab[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.h b/libavcodec/vda.h
index 987b94f..b3d6399 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
*/
@@ -29,8 +29,6 @@
* Public libavcodec VDA header.
*/
-#include "libavcodec/version.h"
-
#include <stdint.h>
// emmintrin.h is unable to compile with -std=c99 -Werror=missing-prototypes
@@ -41,6 +39,8 @@
#include <VideoDecodeAcceleration/VDADecoder.h>
#undef Picture
+#include "libavcodec/version.h"
+
/**
* @defgroup lavc_codec_hwaccel_vda VDA
* @ingroup lavc_codec_hwaccel
@@ -50,7 +50,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.
*/
@@ -113,18 +113,38 @@ struct vda_context {
/**
* The current bitstream buffer.
+ *
+ * - encoding: unused
+ * - decoding: Set/Unset by libavcodec.
*/
uint8_t *priv_bitstream;
/**
* The current size of the bitstream.
+ *
+ * - encoding: unused
+ * - decoding: Set/Unset by libavcodec.
*/
int priv_bitstream_size;
/**
* The reference size used for fast reallocation.
+ *
+ * - encoding: unused
+ * - decoding: Set/Unset by libavcodec.
*/
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 6c1845a..c01a21a 100644
--- a/libavcodec/vda_h264.c
+++ b/libavcodec/vda_h264.c
@@ -1,39 +1,43 @@
/*
- * 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"
-#include "vda.h"
-/* 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,
- uint32_t infoFlags,
- CVImageBufferRef image_buffer)
+struct vda_buffer {
+ CVPixelBufferRef cv_buffer;
+};
+
+/* 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,
+ uint32_t infoFlags,
+ CVImageBufferRef image_buffer)
{
struct vda_context *vda_ctx = vda_hw_ctx;
@@ -71,7 +75,7 @@ static int vda_h264_start_frame(AVCodecContext *avctx,
av_unused const uint8_t *buffer,
av_unused uint32_t size)
{
- struct vda_context *vda_ctx = avctx->hwaccel_context;
+ struct vda_context *vda_ctx = avctx->hwaccel_context;
if (!vda_ctx->decoder)
return -1;
@@ -85,7 +89,7 @@ static int vda_h264_decode_slice(AVCodecContext *avctx,
const uint8_t *buffer,
uint32_t size)
{
- struct vda_context *vda_ctx = avctx->hwaccel_context;
+ struct vda_context *vda_ctx = avctx->hwaccel_context;
void *tmp;
if (!vda_ctx->decoder)
@@ -107,11 +111,20 @@ static int vda_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_h264_end_frame(AVCodecContext *avctx)
{
H264Context *h = avctx->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_ctx->priv_bitstream)
@@ -123,6 +136,20 @@ static int vda_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;
}
@@ -130,7 +157,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;
@@ -140,7 +167,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) {
@@ -182,9 +212,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);
diff --git a/libavcodec/vda_h264_dec.c b/libavcodec/vda_h264_dec.c
new file mode 100644
index 0000000..9463f6a
--- a/dev/null
+++ b/libavcodec/vda_h264_dec.c
@@ -0,0 +1,228 @@
+/*
+ * 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;
+} 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 int vdadec_decode(AVCodecContext *avctx,
+ void *data, int *got_frame, AVPacket *avpkt)
+{
+ VDADecoderContext *ctx = avctx->priv_data;
+ AVFrame *pic = data;
+ int ret;
+
+ ret = ff_h264_decoder.decode(avctx, data, got_frame, avpkt);
+ 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)
+ ff_h264_decoder.close(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;
+
+ 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;
+ }
+ avctx->hwaccel_context = vda_ctx;
+
+ /* changes callback functions */
+ avctx->get_format = get_format;
+ avctx->get_buffer2 = get_buffer2;
+#if FF_API_GET_BUFFER
+ // force the old get_buffer to be empty
+ avctx->get_buffer = NULL;
+#endif
+
+ /* init H.264 decoder */
+ ret = ff_h264_decoder.init(avctx);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 decoder.\n");
+ goto failed;
+ }
+ ctx->h264_initialized = 1;
+
+ return 0;
+
+failed:
+ vdadec_close(avctx);
+ return -1;
+}
+
+static void vdadec_flush(AVCodecContext *avctx)
+{
+ return ff_h264_decoder.flush(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/vdpau.c b/libavcodec/vdpau.c
index 9bcbc2e..7a4d145 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
*/
@@ -38,6 +38,13 @@
* @{
*/
+AVVDPAUContext *av_alloc_vdpaucontext(void)
+{
+ return av_mallocz(sizeof(AVVDPAUContext));
+}
+
+MAKE_ACCESSORS(AVVDPAUContext, vdpau_hwaccel, AVVDPAU_Render2, render2)
+
int ff_vdpau_common_start_frame(Picture *pic,
av_unused const uint8_t *buffer,
av_unused uint32_t size)
@@ -55,19 +62,24 @@ int ff_vdpau_common_start_frame(Picture *pic,
CONFIG_VC1_VDPAU_HWACCEL || CONFIG_WMV3_VDPAU_HWACCEL
int ff_vdpau_mpeg_end_frame(AVCodecContext *avctx)
{
+ int res = 0;
AVVDPAUContext *hwctx = avctx->hwaccel_context;
MpegEncContext *s = avctx->priv_data;
Picture *pic = s->current_picture_ptr;
struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private;
VdpVideoSurface surf = ff_vdpau_get_surface_id(pic);
+ if (!hwctx->render) {
+ res = hwctx->render2(avctx, &pic->f, (void *)&pic_ctx->info,
+ pic_ctx->bitstream_buffers_used, pic_ctx->bitstream_buffers);
+ } else
hwctx->render(hwctx->decoder, surf, (void *)&pic_ctx->info,
pic_ctx->bitstream_buffers_used, pic_ctx->bitstream_buffers);
ff_mpeg_draw_horiz_band(s, 0, s->avctx->height);
av_freep(&pic_ctx->bitstream_buffers);
- return 0;
+ return res;
}
#endif
@@ -90,4 +102,340 @@ int ff_vdpau_add_buffer(Picture *pic, const uint8_t *buf, uint32_t size)
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;
+ Picture *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) {
+ Picture **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->s.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(MpegEncContext *s, const uint8_t *buf,
+ int buf_size)
+{
+ 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 = !s->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 */
+
/* @}*/
diff --git a/libavcodec/vdpau.h b/libavcodec/vdpau.h
index 8bedea5..b1c836c 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,6 +51,15 @@
#include <vdpau/vdpau.h>
#include <vdpau/vdpau_x11.h>
+#include "libavutil/avconfig.h"
+#include "libavutil/attributes.h"
+
+#ifndef FF_API_CAP_VDPAU
+#define FF_API_CAP_VDPAU 1
+#endif
+#ifndef FF_API_BUFS_VDPAU
+#define FF_API_BUFS_VDPAU 1
+#endif
#if FF_API_BUFS_VDPAU
union AVVDPAUPictureInfo {
@@ -61,10 +70,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
@@ -119,8 +136,19 @@ 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);
+
#if FF_API_CAP_VDPAU
/** @brief The videoSurface is used for rendering. */
#define FF_VDPAU_STATE_USED_FOR_RENDER 1
@@ -132,19 +160,21 @@ typedef struct AVVDPAUContext {
#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. */
@@ -152,6 +182,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 3e84644..3f6415d 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
*/
@@ -188,19 +188,24 @@ static int vdpau_h264_decode_slice(AVCodecContext *avctx,
static int vdpau_h264_end_frame(AVCodecContext *avctx)
{
+ int res = 0;
AVVDPAUContext *hwctx = avctx->hwaccel_context;
H264Context *h = avctx->priv_data;
Picture *pic = h->cur_pic_ptr;
struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private;
VdpVideoSurface surf = ff_vdpau_get_surface_id(pic);
+ if (!hwctx->render) {
+ res = hwctx->render2(avctx, &pic->f, (void *)&pic_ctx->info,
+ pic_ctx->bitstream_buffers_used, pic_ctx->bitstream_buffers);
+ } else
hwctx->render(hwctx->decoder, surf, (void *)&pic_ctx->info,
pic_ctx->bitstream_buffers_used, pic_ctx->bitstream_buffers);
ff_h264_draw_horiz_band(h, 0, h->avctx->height);
av_freep(&pic_ctx->bitstream_buffers);
- return 0;
+ return res;
}
AVHWAccel ff_h264_vdpau_hwaccel = {
diff --git a/libavcodec/vdpau_internal.h b/libavcodec/vdpau_internal.h
index 9e4ab4e..b6701f3 100644
--- a/libavcodec/vdpau_internal.h
+++ b/libavcodec/vdpau_internal.h
@@ -4,28 +4,32 @@
*
* 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>
+#include "vdpau.h"
+#endif
#include "h264.h"
#include "mpegvideo.h"
@@ -35,6 +39,7 @@ static inline uintptr_t ff_vdpau_get_surface_id(Picture *pic)
return (uintptr_t)pic->f.data[3];
}
+#if CONFIG_VDPAU
#if !FF_API_BUFS_VDPAU
union AVVDPAUPictureInfo {
VdpPictureInfoH264 h264;
@@ -65,10 +70,28 @@ struct vdpau_picture_context {
*/
VdpBitstreamBuffer *bitstream_buffers;
};
+#endif
int ff_vdpau_common_start_frame(Picture *pic,
const uint8_t *buffer, uint32_t size);
int ff_vdpau_mpeg_end_frame(AVCodecContext *avctx);
int ff_vdpau_add_buffer(Picture *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(MpegEncContext *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 426d580..f21b341 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 8ccb3d6..84683a4 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
*/
diff --git a/libavcodec/vdpau_vc1.c b/libavcodec/vdpau_vc1.c
index c21a861..c6e3343 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);
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);
assert(ref != VDP_INVALID_HANDLE);
info->forward_reference = ref;
+ }
}
info->slice_count = 0;
diff --git a/libavcodec/version.h b/libavcodec/version.h
index e394c76..7528362 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
*/
@@ -26,9 +26,11 @@
* Libavcodec version macros.
*/
+#include "libavutil/avutil.h"
+
#define LIBAVCODEC_VERSION_MAJOR 55
-#define LIBAVCODEC_VERSION_MINOR 22
-#define LIBAVCODEC_VERSION_MICRO 0
+#define LIBAVCODEC_VERSION_MINOR 39
+#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \
@@ -49,6 +51,31 @@
#ifndef FF_API_REQUEST_CHANNELS
#define FF_API_REQUEST_CHANNELS (LIBAVCODEC_VERSION_MAJOR < 56)
#endif
+#ifndef FF_API_ALLOC_CONTEXT
+#define FF_API_ALLOC_CONTEXT (LIBAVCODEC_VERSION_MAJOR < 55)
+#endif
+#ifndef FF_API_AVCODEC_OPEN
+#define FF_API_AVCODEC_OPEN (LIBAVCODEC_VERSION_MAJOR < 55)
+#endif
+#ifndef FF_API_OLD_DECODE_AUDIO
+#define FF_API_OLD_DECODE_AUDIO (LIBAVCODEC_VERSION_MAJOR < 56)
+#endif
+#ifndef FF_API_OLD_TIMECODE
+#define FF_API_OLD_TIMECODE (LIBAVCODEC_VERSION_MAJOR < 55)
+#endif
+
+#ifndef FF_API_OLD_ENCODE_AUDIO
+#define FF_API_OLD_ENCODE_AUDIO (LIBAVCODEC_VERSION_MAJOR < 56)
+#endif
+#ifndef FF_API_OLD_ENCODE_VIDEO
+#define FF_API_OLD_ENCODE_VIDEO (LIBAVCODEC_VERSION_MAJOR < 56)
+#endif
+#ifndef FF_API_CODEC_ID
+#define FF_API_CODEC_ID (LIBAVCODEC_VERSION_MAJOR < 56)
+#endif
+#ifndef FF_API_AVCODEC_RESAMPLE
+#define FF_API_AVCODEC_RESAMPLE (LIBAVCODEC_VERSION_MAJOR < 56)
+#endif
#ifndef FF_API_DEINTERLACE
#define FF_API_DEINTERLACE (LIBAVCODEC_VERSION_MAJOR < 56)
#endif
diff --git a/libavcodec/videodsp.c b/libavcodec/videodsp.c
index a6a1d37..13e4a7b 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 bd2f763..e1f7ee5 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,15 +29,26 @@
#include <stddef.h>
#include <stdint.h>
+#define EMULATED_EDGE(depth) \
+void ff_emulated_edge_mc_ ## depth(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, 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 linesize number of bytes between 2 vertically adjacent samples
- * in both the source and destination buffers
+ * @param src_stride number of bytes between 2 vertically adjacent samples
+ * in source buffer
* @param block_w width of block
* @param block_h height of block
* @param src_x x coordinate of the top left sample of the block in the
@@ -47,8 +58,9 @@ 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 linesize, int block_w, int block_h,
+ void (*emulated_edge_mc)(uint8_t *dst, ptrdiff_t dst_stride,
+ const uint8_t *src, ptrdiff_t src_stride,
+ 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 5d5a32f..f7e7bfd 100644
--- a/libavcodec/videodsp_template.c
+++ b/libavcodec/videodsp_template.c
@@ -1,39 +1,43 @@
/*
- * 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 "bit_depth_template.c"
-
-static void FUNC(ff_emulated_edge_mc)(uint8_t *buf, const uint8_t *src,
- ptrdiff_t 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, ptrdiff_t buf_stride,
+ const uint8_t *src, ptrdiff_t src_stride,
+ 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) * linesize;
+ src -= src_y * src_stride;
+ src += (h - 1) * src_stride;
src_y = h - 1;
} else if (src_y <= -block_h) {
- src += (1 - block_h - src_y) * linesize;
+ src -= src_y * src_stride;
+ src += (1 - block_h) * src_stride;
src_y = 1 - block_h;
}
if (src_x >= w) {
@@ -48,34 +52,34 @@ 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 * linesize + start_x * sizeof(pixel);
+ src += start_y * src_stride + start_x * sizeof(pixel);
buf += start_x * sizeof(pixel);
// top
for (y = 0; y < start_y; y++) {
memcpy(buf, src, w * sizeof(pixel));
- buf += linesize;
+ buf += buf_stride;
}
// copy existing part
for (; y < end_y; y++) {
memcpy(buf, src, w * sizeof(pixel));
- src += linesize;
- buf += linesize;
+ src += src_stride;
+ buf += buf_stride;
}
// bottom
- src -= linesize;
+ src -= src_stride;
for (; y < block_h; y++) {
memcpy(buf, src, w * sizeof(pixel));
- buf += linesize;
+ buf += buf_stride;
}
- buf -= block_h * linesize + start_x * sizeof(pixel);
+ buf -= block_h * buf_stride + start_x * sizeof(pixel);
while (block_h--) {
pixel *bufp = (pixel *) buf;
@@ -88,6 +92,6 @@ static void FUNC(ff_emulated_edge_mc)(uint8_t *buf, const uint8_t *src,
for (x = end_x; x < block_w; x++) {
bufp[x] = bufp[end_x - 1];
}
- buf += linesize;
+ buf += buf_stride;
}
}
diff --git a/libavcodec/vima.c b/libavcodec/vima.c
new file mode 100644
index 0000000..f040e1b
--- a/dev/null
+++ b/libavcodec/vima.c
@@ -0,0 +1,239 @@
+/*
+ * LucasArts VIMA 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
+ */
+
+/**
+ * @file
+ * LucasArts VIMA audio decoder
+ * @author Paul B Mahol
+ */
+
+#include "libavutil/channel_layout.h"
+#include "avcodec.h"
+#include "get_bits.h"
+#include "internal.h"
+#include "adpcm_data.h"
+
+static int predict_table_init = 0;
+static uint16_t predict_table[5786 * 2];
+
+static const uint8_t size_table[] =
+{
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 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, 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,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+};
+
+static const int8_t index_table1[] =
+{
+ -1, 4, -1, 4
+};
+
+static const int8_t index_table2[] =
+{
+ -1, -1, 2, 6, -1, -1, 2, 6
+};
+
+static const int8_t index_table3[] =
+{
+ -1, -1, -1, -1, 1, 2, 4, 6,
+ -1, -1, -1, -1, 1, 2, 4, 6
+};
+
+static const int8_t index_table4[] =
+{
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 1, 1, 1, 2, 2, 4, 5, 6,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 1, 1, 1, 2, 2, 4, 5, 6
+};
+
+static const int8_t index_table5[] =
+{
+ -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, 4, 4, 4, 5, 5, 6, 6,
+ -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, 4, 4, 4, 5, 5, 6, 6
+};
+
+static const int8_t index_table6[] =
+{
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -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, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 6, 6, 6, 6,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -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, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 6, 6, 6, 6
+};
+
+static const int8_t* const step_index_tables[] =
+{
+ index_table1, index_table2, index_table3,
+ index_table4, index_table5, index_table6
+};
+
+static av_cold int decode_init(AVCodecContext *avctx)
+{
+ int start_pos;
+
+ avctx->sample_fmt = AV_SAMPLE_FMT_S16;
+
+ if (predict_table_init)
+ return 0;
+
+ for (start_pos = 0; start_pos < 64; start_pos++) {
+ unsigned int dest_pos, table_pos;
+
+ for (table_pos = 0, dest_pos = start_pos;
+ table_pos < FF_ARRAY_ELEMS(ff_adpcm_step_table);
+ table_pos++, dest_pos += 64) {
+ int put = 0, count, table_value;
+
+ table_value = ff_adpcm_step_table[table_pos];
+ for (count = 32; count != 0; count >>= 1) {
+ if (start_pos & count)
+ put += table_value;
+ table_value >>= 1;
+ }
+ predict_table[dest_pos] = put;
+ }
+ }
+ predict_table_init = 1;
+
+ return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame_ptr, AVPacket *pkt)
+{
+ GetBitContext gb;
+ AVFrame *frame = data;
+ int16_t pcm_data[2];
+ uint32_t samples;
+ int8_t channel_hint[2];
+ int ret, chan, channels = 1;
+
+ if (pkt->size < 13)
+ return AVERROR_INVALIDDATA;
+
+ if ((ret = init_get_bits8(&gb, pkt->data, pkt->size)) < 0)
+ return ret;
+
+ samples = get_bits_long(&gb, 32);
+ if (samples == 0xffffffff) {
+ skip_bits_long(&gb, 32);
+ samples = get_bits_long(&gb, 32);
+ }
+
+ if (samples > pkt->size * 2)
+ return AVERROR_INVALIDDATA;
+
+ channel_hint[0] = get_sbits(&gb, 8);
+ if (channel_hint[0] & 0x80) {
+ channel_hint[0] = ~channel_hint[0];
+ channels = 2;
+ }
+ avctx->channels = channels;
+ avctx->channel_layout = (channels == 2) ? AV_CH_LAYOUT_STEREO :
+ AV_CH_LAYOUT_MONO;
+ pcm_data[0] = get_sbits(&gb, 16);
+ if (channels > 1) {
+ channel_hint[1] = get_sbits(&gb, 8);
+ pcm_data[1] = get_sbits(&gb, 16);
+ }
+
+ frame->nb_samples = samples;
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+
+ for (chan = 0; chan < channels; chan++) {
+ uint16_t *dest = (uint16_t*)frame->data[0] + chan;
+ int step_index = channel_hint[chan];
+ int output = pcm_data[chan];
+ int sample;
+
+ for (sample = 0; sample < samples; sample++) {
+ int lookup_size, lookup, highbit, lowbits;
+
+ step_index = av_clip(step_index, 0, 88);
+ lookup_size = size_table[step_index];
+ lookup = get_bits(&gb, lookup_size);
+ highbit = 1 << (lookup_size - 1);
+ lowbits = highbit - 1;
+
+ if (lookup & highbit)
+ lookup ^= highbit;
+ else
+ highbit = 0;
+
+ if (lookup == lowbits) {
+ output = get_sbits(&gb, 16);
+ } else {
+ int predict_index, diff;
+
+ predict_index = (lookup << (7 - lookup_size)) | (step_index << 6);
+ predict_index = av_clip(predict_index, 0, 5785);
+ diff = predict_table[predict_index];
+ if (lookup)
+ diff += ff_adpcm_step_table[step_index] >> (lookup_size - 1);
+ if (highbit)
+ diff = -diff;
+
+ output = av_clip_int16(output + diff);
+ }
+
+ *dest = output;
+ dest += channels;
+
+ step_index += step_index_tables[lookup_size - 2][lookup];
+ }
+ }
+
+ *got_frame_ptr = 1;
+
+ return pkt->size;
+}
+
+AVCodec ff_vima_decoder = {
+ .name = "vima",
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts VIMA audio"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_VIMA,
+ .init = decode_init,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/vmdav.c b/libavcodec/vmdav.c
index b1ecace..ea0e842 100644
--- a/libavcodec/vmdav.c
+++ b/libavcodec/vmdav.c
@@ -2,20 +2,20 @@
* Sierra VMD Audio & Video Decoders
* 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
*/
@@ -43,6 +43,7 @@
#include <stdlib.h>
#include <string.h>
+#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "libavutil/common.h"
#include "libavutil/intreadwrite.h"
@@ -98,7 +99,7 @@ static void lz_unpack(const unsigned char *src, int src_len,
if (bytestream2_get_bytes_left(&gb) < 4)
return;
if (bytestream2_peek_le32(&gb) == 0x56781234) {
- bytestream2_get_le32(&gb);
+ bytestream2_skipu(&gb, 4);
qpos = 0x111;
speclen = 0xF + 3;
} else {
@@ -109,7 +110,7 @@ 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)
+ if (d_end - d < 8 || bytestream2_get_bytes_left(&gb) < 8)
return;
for (i = 0; i < 8; i++) {
queue[qpos++] = *d++ = bytestream2_get_byteu(&gb);
@@ -121,9 +122,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)
+ if (d_end - d < 1 || bytestream2_get_bytes_left(&gb) < 1)
return;
- queue[qpos++] = *d++ = bytestream2_get_byte(&gb);
+ queue[qpos++] = *d++ = bytestream2_get_byteu(&gb);
qpos &= QUEUE_MASK;
dataleft--;
} else {
@@ -133,7 +134,7 @@ 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)
+ if (d_end - d < chainlen)
return;
for (j = 0; j < chainlen; j++) {
*d = queue[chainofs++ & QUEUE_MASK];
@@ -147,9 +148,8 @@ static void lz_unpack(const unsigned char *src, int src_len,
}
}
}
-
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;
@@ -172,12 +172,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++) {
@@ -213,6 +213,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 ||
@@ -232,15 +242,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] &&
@@ -261,13 +262,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)
@@ -302,7 +303,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 */
@@ -314,7 +315,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;
}
@@ -360,7 +361,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;
}
@@ -387,9 +388,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;
@@ -407,9 +408,12 @@ 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;
}
+ avcodec_get_frame_defaults(&s->prev_frame);
+
return 0;
}
@@ -429,10 +433,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;
@@ -499,7 +501,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);
}
@@ -605,17 +607,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;
@@ -627,8 +628,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/vmnc.c b/libavcodec/vmnc.c
index 1073cb2..c1b6d4e 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
*/
@@ -57,7 +57,7 @@ enum HexTile_Flags {
*/
typedef struct VmncContext {
AVCodecContext *avctx;
- AVFrame pic;
+ AVFrame *frame;
int bpp;
int bpp2;
@@ -307,6 +307,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,
@@ -318,16 +320,15 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
GetByteContext *gb = &c->gb;
uint8_t *outptr;
int dx, dy, w, h, depth, enc, chunks, res, size_left, ret;
+ AVFrame *frame = c->frame;
- 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, frame)) < 0)
return ret;
- }
bytestream2_init(gb, buf, buf_size);
- c->pic.key_frame = 0;
- c->pic.pict_type = AV_PICTURE_TYPE_P;
+ frame->key_frame = 0;
+ frame->pict_type = AV_PICTURE_TYPE_P;
// restore screen after cursor
if (c->screendta) {
@@ -349,26 +350,34 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
dy = 0;
}
if ((w > 0) && (h > 0)) {
- outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0];
+ outptr = frame->data[0] + dx * c->bpp2 + dy * frame->linesize[0];
for (i = 0; i < h; i++) {
memcpy(outptr, c->screendta + i * c->cur_w * c->bpp2,
w * c->bpp2);
- outptr += c->pic.linesize[0];
+ outptr += frame->linesize[0];
}
}
}
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);
h = bytestream2_get_be16(gb);
enc = bytestream2_get_be32(gb);
- outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0];
+ outptr = frame->data[0] + dx * c->bpp2 + dy * frame->linesize[0];
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",
@@ -415,8 +424,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
bytestream2_skip(gb, 4);
break;
case MAGIC_WMVi: // ServerInitialization struct
- c->pic.key_frame = 1;
- c->pic.pict_type = AV_PICTURE_TYPE_I;
+ frame->key_frame = 1;
+ frame->pict_type = AV_PICTURE_TYPE_I;
depth = bytestream2_get_byte(gb);
if (depth != c->bpp) {
av_log(avctx, AV_LOG_INFO,
@@ -451,7 +460,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
}
paint_raw(outptr, w, h, gb, c->bpp2, c->bigendian,
- c->pic.linesize[0]);
+ frame->linesize[0]);
break;
case 0x00000005: // HexTile encoded rectangle
if ((dx + w > c->width) || (dy + h > c->height)) {
@@ -460,7 +469,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
w, h, dx, dy, c->width, c->height);
return AVERROR_INVALIDDATA;
}
- res = decode_hextile(c, outptr, gb, w, h, c->pic.linesize[0]);
+ res = decode_hextile(c, outptr, gb, w, h, frame->linesize[0]);
if (res < 0)
return res;
break;
@@ -489,18 +498,18 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
dy = 0;
}
if ((w > 0) && (h > 0)) {
- outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0];
+ outptr = frame->data[0] + dx * c->bpp2 + dy * frame->linesize[0];
for (i = 0; i < h; i++) {
memcpy(c->screendta + i * c->cur_w * c->bpp2, outptr,
w * c->bpp2);
- outptr += c->pic.linesize[0];
+ outptr += frame->linesize[0];
}
- outptr = c->pic.data[0];
- put_cursor(outptr, c->pic.linesize[0], c, c->cur_x, c->cur_y);
+ outptr = frame->data[0];
+ put_cursor(outptr, frame->linesize[0], c, c->cur_x, c->cur_y);
}
}
*got_frame = 1;
- if ((ret = av_frame_ref(data, &c->pic)) < 0)
+ if ((ret = av_frame_ref(data, frame)) < 0)
return ret;
/* always report that the buffer was completely consumed */
@@ -532,7 +541,9 @@ static av_cold int decode_init(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
}
- avcodec_get_frame_defaults(&c->pic);
+ c->frame = av_frame_alloc();
+ if (!c->frame)
+ return AVERROR(ENOMEM);
return 0;
}
@@ -541,11 +552,11 @@ static av_cold int decode_end(AVCodecContext *avctx)
{
VmncContext * const c = avctx->priv_data;
- av_frame_unref(&c->pic);
+ av_frame_free(&c->frame);
- 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..6eb765d 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 )
+ *
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with 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.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 c413135..fcbecc8 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
*/
@@ -165,7 +165,7 @@ static int parse_setup_header(AVCodecContext *avctx, VorbisParseContext *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:
@@ -196,7 +196,7 @@ int avpriv_vorbis_parse_extradata(AVCodecContext *avctx, VorbisParseContext *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;
}
@@ -222,11 +222,11 @@ int avpriv_vorbis_parse_frame(VorbisParseContext *s, const uint8_t *buf,
av_log(s->avctx, 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;
}
@@ -237,7 +237,7 @@ int avpriv_vorbis_parse_frame(VorbisParseContext *s, const uint8_t *buf,
void avpriv_vorbis_parse_reset(VorbisParseContext *s)
{
if (s->valid_extradata)
- s->previous_blocksize = s->mode_blocksize[0];
+ s->previous_blocksize = s->blocksize[0];
}
#if CONFIG_VORBIS_PARSER
diff --git a/libavcodec/vorbis_parser.h b/libavcodec/vorbis_parser.h
index 480a918..101df5d 100644
--- a/libavcodec/vorbis_parser.h
+++ b/libavcodec/vorbis_parser.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
*/
diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c
index d7fec98..a2f7dd2 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"
@@ -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_free(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_free(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_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);
+ }
}
- }
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_free(vc->mappings[i].magnitude);
+ av_free(vc->mappings[i].angle);
+ av_free(vc->mappings[i].mux);
+ }
av_freep(&vc->mappings);
}
@@ -692,7 +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->type == 2 ? vc->audio_channels : 1) * vc->blocksize[1] / 2 ||
(res_setup->end-res_setup->begin) / res_setup->partition_size > V_MAX_PARTITIONS) {
av_log(vc->avctx, AV_LOG_ERROR,
"partition out of bounds: type, begin, end, size, blocksize: %"PRIu16", %"PRIu32", %"PRIu32", %u, %"PRIu32"\n",
@@ -961,12 +970,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];
@@ -1185,7 +1194,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 +1210,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;
}
@@ -1316,6 +1328,11 @@ 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;
@@ -1381,7 +1398,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)) < 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) {
@@ -1699,12 +1718,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++)
diff --git a/libavcodec/vorbisdsp.c b/libavcodec/vorbisdsp.c
index 8e82c10..7843756 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 32fcfef..ed14049 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 f16060e..9ef6296 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
*/
@@ -140,9 +140,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]);
@@ -198,7 +198,7 @@ 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);
+ av_assert0(rc->type == 2);
rc->maxes = av_mallocz(sizeof(float[2]) * rc->classifications);
if (!rc->maxes)
return AVERROR(ENOMEM);
@@ -878,8 +878,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;
@@ -1013,7 +1013,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)
{
@@ -1029,10 +1028,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);
@@ -1089,10 +1086,10 @@ static int vorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
avpkt->size = put_bits_count(&pb) >> 3;
avpkt->duration = ff_samples_to_time_base(avctx, avctx->frame_size);
- if (frame)
+ if (frame) {
if (frame->pts != AV_NOPTS_VALUE)
avpkt->pts = ff_samples_to_time_base(avctx, frame->pts);
- else
+ } else
avpkt->pts = venc->next_pts;
if (avpkt->pts != AV_NOPTS_VALUE)
venc->next_pts = avpkt->pts + avpkt->duration;
@@ -1167,7 +1164,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;
}
@@ -1178,7 +1175,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 467dfd56..b21b6e2 100644
--- a/libavcodec/vp3.c
+++ b/libavcodec/vp3.c
@@ -1,20 +1,20 @@
/*
* 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
*/
@@ -76,6 +76,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] =
{
@@ -285,6 +289,8 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx)
av_freep(&s->motion_val[1]);
av_freep(&s->edge_emu_buffer);
+ s->theora_tables = 0;
+
/* release all frames */
vp3_decode_flush(avctx);
av_frame_free(&s->current_frame.f);
@@ -311,7 +317,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
@@ -398,7 +404,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));
@@ -1543,7 +1549,10 @@ static void render_slice(Vp3DecodeContext *s, int slice)
uint8_t *temp= s->edge_emu_buffer;
if(stride<0) temp -= 8*stride;
- s->vdsp.emulated_edge_mc(temp, motion_source, stride, 9, 9, src_x, src_y, plane_width, plane_height);
+ s->vdsp.emulated_edge_mc(temp, stride,
+ motion_source, stride,
+ 9, 9, src_x, src_y,
+ plane_width, plane_height);
motion_source= temp;
}
}
@@ -1573,19 +1582,13 @@ 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,
@@ -1632,16 +1635,16 @@ static av_cold int allocate_tables(AVCodecContext *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->coded_fragment_list[0] = av_malloc(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->superblock_coding = av_mallocz(s->superblock_count);
+ s->all_fragments = av_mallocz(s->fragment_count * sizeof(Vp3Fragment));
+ s->coded_fragment_list[0] = av_mallocz(s->fragment_count * sizeof(int));
+ s->dct_tokens_base = av_mallocz(64*s->fragment_count * sizeof(*s->dct_tokens_base));
+ s->motion_val[0] = av_mallocz(y_fragment_count * sizeof(*s->motion_val[0]));
+ s->motion_val[1] = av_mallocz(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(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] || !s->superblock_fragments || !s->macroblock_coding ||
@@ -1693,7 +1696,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);
@@ -1712,8 +1715,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;
@@ -1959,13 +1961,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++)
@@ -1998,10 +2031,9 @@ static int vp3_decode_frame(AVCodecContext *avctx,
return buf_size;
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]));
@@ -2029,10 +2061,8 @@ static int vp3_decode_frame(AVCodecContext *avctx,
av_log(s->avctx, AV_LOG_WARNING, "vp3: first frame not a keyframe\n");
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");
+ if (ff_thread_get_buffer(avctx, &s->golden_frame, 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)
goto error;
@@ -2226,6 +2256,10 @@ static int theora_decode_header(AVCodecContext *avctx, GetBitContext *gb)
{
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 */
}
@@ -2367,6 +2401,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)
@@ -2400,7 +2436,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 ef2c55b..ce15309 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 54d5a6c..904ec6a 100644
--- a/libavcodec/vp3data.h
+++ b/libavcodec/vp3data.h
@@ -1,20 +1,20 @@
/*
* 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/vp3dsp.c b/libavcodec/vp3dsp.c
index 94de0e5..5656629 100644
--- a/libavcodec/vp3dsp.c
+++ b/libavcodec/vp3dsp.c
@@ -1,20 +1,20 @@
/*
* 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
*/
diff --git a/libavcodec/vp3dsp.h b/libavcodec/vp3dsp.h
index 39c4408..3aded99 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 f4d1c7f..2ab90b7 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
*/
@@ -34,8 +34,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;
diff --git a/libavcodec/vp56.c b/libavcodec/vp56.c
index 35df0e0..6b9f386 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
*/
@@ -339,7 +339,7 @@ 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,
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, stride,
src + s->block_offset[b] + (dy-2)*stride + (dx-2),
stride, 12, 12, x, y,
s->plane_width[plane],
@@ -452,9 +452,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;
@@ -475,19 +475,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)
{
@@ -495,8 +502,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)
@@ -507,155 +515,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) {
- avcodec_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);
@@ -681,10 +717,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;
@@ -701,6 +741,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 f71b9a8..9a95296 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
*/
@@ -80,7 +80,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;
@@ -136,6 +136,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 */
@@ -190,8 +191,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;
@@ -204,7 +208,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);
@@ -365,15 +372,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);
@@ -381,15 +386,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 c009cad..f11531d 100644
--- a/libavcodec/vp56rac.c
+++ b/libavcodec/vp56rac.c
@@ -2,20 +2,20 @@
* VP5/6/8 decoder
* Copyright (c) 2010 Jason Garrett-Glaser <darkshikari@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with 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 fddfc9d..4cf11ee 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
*/
@@ -42,8 +42,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;
@@ -109,6 +108,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;
@@ -120,7 +120,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)
@@ -248,7 +248,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);
}
@@ -398,11 +399,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
@@ -599,6 +600,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;
@@ -608,6 +611,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;
@@ -615,16 +633,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]);
@@ -633,7 +664,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 = {
@@ -671,5 +701,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 910ec20..c302ff6 100644
--- a/libavcodec/vp8.c
+++ b/libavcodec/vp8.c
@@ -6,20 +6,20 @@
* Copyright (C) 2010 Jason Garrett-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
*/
@@ -45,7 +45,6 @@ static void free_buffers(VP8Context *s)
pthread_mutex_destroy(&s->thread_data[i].lock);
#endif
av_freep(&s->thread_data[i].filter_strength);
- av_freep(&s->thread_data[i].edge_emu_buffer);
}
av_freep(&s->thread_data);
av_freep(&s->macroblocks_base);
@@ -116,7 +115,7 @@ static int update_dimensions(VP8Context *s, int width, int height)
AVCodecContext *avctx = s->avctx;
int i;
- 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) {
if (av_image_check_size(width, height, 0, s->avctx))
return AVERROR_INVALIDDATA;
@@ -384,7 +383,7 @@ static int decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_size)
}
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 = update_dimensions(s, width, height)) < 0)
return ret;
}
@@ -700,9 +699,10 @@ void decode_mb_mode(VP8Context *s, VP8Macroblock *mb, int mb_x, int mb_y,
{
VP56RangeCoder *c = &s->c;
- if (s->segmentation.update_map)
- *segment = vp8_rac_get_tree(c, vp8_segmentid_tree, s->prob->segmentid);
- else if (s->segmentation.enabled)
+ 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;
@@ -1185,7 +1185,7 @@ void vp8_mc_luma(VP8Context *s, VP8ThreadData *td, uint8_t *dst,
uint8_t *src = ref->f->data[0];
if (AV_RN32A(mv)) {
-
+ int src_linesize = linesize;
int mx = (mv->x << 1)&7, mx_idx = subpel_idx[0][mx];
int my = (mv->y << 1)&7, my_idx = subpel_idx[0][my];
@@ -1197,12 +1197,15 @@ void vp8_mc_luma(VP8Context *s, VP8ThreadData *td, uint8_t *dst,
src += y_off * linesize + x_off;
if (x_off < mx_idx || x_off >= width - block_w - subpel_idx[2][mx] ||
y_off < my_idx || y_off >= height - block_h - subpel_idx[2][my]) {
- s->vdsp.emulated_edge_mc(td->edge_emu_buffer, src - my_idx * linesize - mx_idx, linesize,
- block_w + subpel_idx[1][mx], block_h + subpel_idx[1][my],
+ s->vdsp.emulated_edge_mc(td->edge_emu_buffer, 32,
+ src - my_idx * linesize - mx_idx, linesize,
+ block_w + subpel_idx[1][mx],
+ block_h + subpel_idx[1][my],
x_off - mx_idx, y_off - my_idx, width, height);
- src = td->edge_emu_buffer + mx_idx + linesize * my_idx;
+ src = td->edge_emu_buffer + mx_idx + 32 * my_idx;
+ src_linesize = 32;
}
- mc_func[my_idx][mx_idx](dst, linesize, src, linesize, block_h, mx, my);
+ mc_func[my_idx][mx_idx](dst, linesize, src, src_linesize, block_h, mx, my);
} else {
ff_thread_await_progress(ref, (3 + y_off + block_h) >> 4, 0);
mc_func[0][0](dst, linesize, src + y_off * linesize + x_off, linesize, block_h, 0, 0);
@@ -1247,17 +1250,21 @@ void vp8_mc_chroma(VP8Context *s, VP8ThreadData *td, uint8_t *dst1, uint8_t *dst
ff_thread_await_progress(ref, (3 + y_off + block_h + subpel_idx[2][my]) >> 3, 0);
if (x_off < mx_idx || x_off >= width - block_w - subpel_idx[2][mx] ||
y_off < my_idx || y_off >= height - block_h - subpel_idx[2][my]) {
- s->vdsp.emulated_edge_mc(td->edge_emu_buffer, src1 - my_idx * linesize - mx_idx, linesize,
- block_w + subpel_idx[1][mx], block_h + subpel_idx[1][my],
+ s->vdsp.emulated_edge_mc(td->edge_emu_buffer, 32,
+ src1 - my_idx * linesize - mx_idx, linesize,
+ 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 + linesize * my_idx;
- mc_func[my_idx][mx_idx](dst1, linesize, src1, linesize, block_h, mx, my);
+ src1 = td->edge_emu_buffer + mx_idx + 32 * my_idx;
+ mc_func[my_idx][mx_idx](dst1, linesize, src1, 32, block_h, mx, my);
- s->vdsp.emulated_edge_mc(td->edge_emu_buffer, src2 - my_idx * linesize - mx_idx, linesize,
- block_w + subpel_idx[1][mx], block_h + subpel_idx[1][my],
+ s->vdsp.emulated_edge_mc(td->edge_emu_buffer, 32,
+ src2 - my_idx * linesize - mx_idx, linesize,
+ 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 + linesize * my_idx;
- mc_func[my_idx][mx_idx](dst2, linesize, src2, linesize, block_h, mx, my);
+ src2 = td->edge_emu_buffer + mx_idx + 32 * my_idx;
+ mc_func[my_idx][mx_idx](dst2, linesize, src2, 32, block_h, mx, my);
} else {
mc_func[my_idx][mx_idx](dst1, linesize, src1, linesize, block_h, mx, my);
mc_func[my_idx][mx_idx](dst2, linesize, src2, linesize, block_h, mx, my);
@@ -1917,10 +1924,8 @@ int ff_vp8_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) {
@@ -1945,10 +1950,6 @@ int ff_vp8_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
s->linesize = curframe->tf.f->linesize[0];
s->uvlinesize = curframe->tf.f->linesize[1];
- if (!s->thread_data[0].edge_emu_buffer)
- for (i = 0; i < MAX_THREADS; i++)
- s->thread_data[i].edge_emu_buffer = av_malloc(21*s->linesize);
-
memset(s->top_nnz, 0, s->mb_width*sizeof(*s->top_nnz));
/* Zero macroblock structures for top/top-left prediction from outside the frame. */
if (!s->mb_layout)
@@ -2105,6 +2106,52 @@ static int vp8_decode_update_thread_context(AVCodecContext *dst, const AVCodecCo
return 0;
}
+static unsigned apply_padding(unsigned size) { return size + (size & 1); }
+
+static int webp_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
+ AVPacket *avpkt)
+{
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ AVPacket pkt = *avpkt;
+
+ if (buf_size >= 16
+ && AV_RL32(buf ) == AV_RL32("RIFF")
+ && AV_RL32(buf+ 8) == AV_RL32("WEBP")) {
+ unsigned riff_size = apply_padding(AV_RL32(buf+4)) + 8;
+ buf += 12; // Skip over main header
+ buf_size -= 12;
+ if (buf_size < 8 || riff_size < 8) {
+ av_log(avctx, AV_LOG_ERROR, "Incomplete header.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (AV_RL32(buf) == AV_RL32("VP8L")) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported WebP lossless format.\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ if (AV_RL32(buf) == AV_RL32("VP8X") && AV_RL32(buf+4) < (unsigned)buf_size) {
+ unsigned size = apply_padding(AV_RL32(buf+4) + 8);
+ buf += size;
+ buf_size -= size;
+ }
+ if (buf_size >= 8
+ && AV_RL32(buf) == AV_RL32("ALPH") && AV_RL32(buf+4) < (unsigned)buf_size) {
+ unsigned size = apply_padding(AV_RL32(buf+4) + 8);
+ buf += size;
+ buf_size -= size;
+ av_log(avctx, AV_LOG_WARNING, "Skipping alpha plane\n");
+ }
+ if (buf_size >= 8 && AV_RL32(buf) == AV_RL32("VP8 ")) {
+ buf += 8;
+ buf_size -= 8;
+ }
+ }
+ pkt.data = buf;
+ pkt.size = buf_size;
+
+ return ff_vp8_decode_frame(avctx, data, data_size, &pkt);
+}
+
AVCodec ff_vp8_decoder = {
.name = "vp8",
.long_name = NULL_IF_CONFIG_SMALL("On2 VP8"),
@@ -2119,3 +2166,18 @@ AVCodec ff_vp8_decoder = {
.init_thread_copy = ONLY_IF_THREADS_ENABLED(vp8_decode_init_thread_copy),
.update_thread_context = ONLY_IF_THREADS_ENABLED(vp8_decode_update_thread_context),
};
+
+// AVCodec ff_webp_decoder = {
+// .name = "webp",
+// .long_name = NULL_IF_CONFIG_SMALL("WebP"),
+// .type = AVMEDIA_TYPE_VIDEO,
+// .id = AV_CODEC_ID_WEBP,
+// .priv_data_size = sizeof(VP8Context),
+// .init = vp8_decode_init,
+// .close = vp8_decode_free,
+// .decode = webp_decode_frame,
+// .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS | CODEC_CAP_SLICE_THREADS,
+// .flush = vp8_decode_flush,
+// .init_thread_copy = ONLY_IF_THREADS_ENABLED(vp8_decode_init_thread_copy),
+// .update_thread_context = ONLY_IF_THREADS_ENABLED(vp8_decode_update_thread_context),
+// };
diff --git a/libavcodec/vp8.h b/libavcodec/vp8.h
index 6555629..c9a7906 100644
--- a/libavcodec/vp8.h
+++ b/libavcodec/vp8.h
@@ -6,20 +6,20 @@
* Copyright (C) 2010 Jason Garrett-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
*/
@@ -34,6 +34,8 @@
#include "thread.h"
#if HAVE_PTHREADS
#include <pthread.h>
+#elif HAVE_OS2THREADS
+#include "compat/os2threads.h"
#elif HAVE_W32THREADS
#include "compat/w32pthreads.h"
#endif
@@ -120,7 +122,7 @@ typedef struct VP8ThreadData {
#endif
int thread_mb_pos; // (mb_y << 16) | (mb_x & 0xFFFF)
int wait_mb_pos; // What the current thread is waiting on.
- uint8_t *edge_emu_buffer;
+ DECLARE_ALIGNED(16, uint8_t, edge_emu_buffer)[21*32];
VP8FilterStrength *filter_strength;
} VP8ThreadData;
diff --git a/libavcodec/vp8_parser.c b/libavcodec/vp8_parser.c
index 196de83..096961f 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 a48b0f6..0ea24d7 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 34e2da0..ba267fd 100644
--- a/libavcodec/vp8dsp.c
+++ b/libavcodec/vp8dsp.c
@@ -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
*/
@@ -415,7 +415,7 @@ VP8_EPEL_HV(8, 6, 6)
VP8_EPEL_HV(4, 6, 6)
#define VP8_BILINEAR(SIZE) \
-static void put_vp8_bilinear ## SIZE ## _h_c(uint8_t *dst, ptrdiff_t stride, uint8_t *src, ptrdiff_t s2, int h, int mx, int my) \
+static void put_vp8_bilinear ## SIZE ## _h_c(uint8_t *dst, ptrdiff_t dstride, uint8_t *src, ptrdiff_t sstride, int h, int mx, int my) \
{ \
int a = 8-mx, b = mx; \
int x, y; \
@@ -423,24 +423,24 @@ static void put_vp8_bilinear ## SIZE ## _h_c(uint8_t *dst, ptrdiff_t stride, uin
for (y = 0; y < h; y++) { \
for (x = 0; x < SIZE; x++) \
dst[x] = (a*src[x] + b*src[x+1] + 4) >> 3; \
- dst += stride; \
- src += stride; \
+ dst += dstride; \
+ src += sstride; \
} \
} \
-static void put_vp8_bilinear ## SIZE ## _v_c(uint8_t *dst, ptrdiff_t stride, uint8_t *src, ptrdiff_t s2, int h, int mx, int my) \
+static void put_vp8_bilinear ## SIZE ## _v_c(uint8_t *dst, ptrdiff_t dstride, uint8_t *src, ptrdiff_t sstride, int h, int mx, int my) \
{ \
int c = 8-my, d = my; \
int x, y; \
\
for (y = 0; y < h; y++) { \
for (x = 0; x < SIZE; x++) \
- dst[x] = (c*src[x] + d*src[x+stride] + 4) >> 3; \
- dst += stride; \
- src += stride; \
+ dst[x] = (c*src[x] + d*src[x+sstride] + 4) >> 3; \
+ dst += dstride; \
+ src += sstride; \
} \
} \
\
-static void put_vp8_bilinear ## SIZE ## _hv_c(uint8_t *dst, ptrdiff_t stride, uint8_t *src, ptrdiff_t s2, int h, int mx, int my) \
+static void put_vp8_bilinear ## SIZE ## _hv_c(uint8_t *dst, ptrdiff_t dstride, uint8_t *src, ptrdiff_t sstride, int h, int mx, int my) \
{ \
int a = 8-mx, b = mx; \
int c = 8-my, d = my; \
@@ -452,7 +452,7 @@ static void put_vp8_bilinear ## SIZE ## _hv_c(uint8_t *dst, ptrdiff_t stride, ui
for (x = 0; x < SIZE; x++) \
tmp[x] = (a*src[x] + b*src[x+1] + 4) >> 3; \
tmp += SIZE; \
- src += stride; \
+ src += sstride; \
} \
\
tmp = tmp_array; \
@@ -460,7 +460,7 @@ static void put_vp8_bilinear ## SIZE ## _hv_c(uint8_t *dst, ptrdiff_t stride, ui
for (y = 0; y < h; y++) { \
for (x = 0; x < SIZE; x++) \
dst[x] = (c*tmp[x] + d*tmp[x+SIZE] + 4) >> 3; \
- dst += stride; \
+ dst += dstride; \
tmp += SIZE; \
} \
}
diff --git a/libavcodec/vp8dsp.h b/libavcodec/vp8dsp.h
index 877e264..58ec65a 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
new file mode 100644
index 0000000..80bb9a5
--- a/dev/null
+++ b/libavcodec/vp9.c
@@ -0,0 +1,3578 @@
+/*
+ * VP9 compatible video decoder
+ *
+ * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
+ * Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "get_bits.h"
+#include "internal.h"
+#include "videodsp.h"
+#include "vp56.h"
+#include "vp9.h"
+#include "vp9data.h"
+#include "vp9dsp.h"
+#include "libavutil/avassert.h"
+
+#define VP9_SYNCCODE 0x498342
+
+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];
+};
+
+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;
+
+ 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, last_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], *f, *fb[10];
+
+ 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
+ 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;
+ struct VP9mvrefPair *mv[2];
+ struct 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;
+
+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 update_size(AVCodecContext *ctx, int w, int h)
+{
+ VP9Context *s = ctx->priv_data;
+ uint8_t *p;
+
+ if (s->above_partition_ctx && w == ctx->width && h == ctx->height)
+ return 0;
+
+ 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;
+
+#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)));
+ 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, struct VP9Filter *, 1);
+ assign(s->above_mv_ctx, VP56mv(*)[2], 16);
+ assign(s->segmentation_map, uint8_t *, 64 * s->sb_rows);
+ assign(s->mv[0], struct VP9mvrefPair *, 64 * s->sb_rows);
+ assign(s->mv[1], struct VP9mvrefPair *, 64 * s->sb_rows);
+#undef assign
+
+ 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;
+}
+
+static av_always_inline int inv_recenter_nonneg(int v, int m)
+{
+ 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[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,
+ 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100,
+ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 112, 113, 114, 115,
+ 116, 117, 118, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 130,
+ 131, 132, 133, 134, 135, 136, 138, 139, 140, 141, 142, 143, 144, 145,
+ 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
+ 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+ 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 203, 204, 205, 206,
+ 207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219, 220, 221,
+ 222, 223, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 236,
+ 237, 238, 239, 240, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251,
+ 252, 253,
+ };
+ int d;
+
+ /* 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
+ * 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
+ * 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'
+ * updates vs. the 'fine, exact' updates further down the range, which
+ * adds one extra dimension to this differential update model. */
+
+ if (!vp8_rac_get(c)) {
+ d = vp8_rac_get_uint(c, 4) + 0;
+ } else if (!vp8_rac_get(c)) {
+ d = vp8_rac_get_uint(c, 4) + 16;
+ } else if (!vp8_rac_get(c)) {
+ d = vp8_rac_get_uint(c, 5) + 32;
+ } else {
+ d = vp8_rac_get_uint(c, 7);
+ if (d >= 65)
+ d = (d << 1) - 65 + vp8_rac_get(c);
+ 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);
+}
+
+static int decode_frame_header(AVCodecContext *ctx,
+ const uint8_t *data, int size, int *ref)
+{
+ VP9Context *s = ctx->priv_data;
+ int c, i, j, k, l, m, n, w, h, max, size2, res, sharp;
+ const uint8_t *data2;
+
+ /* general header */
+ if ((res = init_get_bits8(&s->gb, data, size)) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to intialize bitstream reader\n");
+ return res;
+ }
+ if (get_bits(&s->gb, 2) != 0x2) { // frame marker
+ 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(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);
+ s->last_invisible = s->invisible;
+ s->invisible = !get_bits1(&s->gb);
+ s->errorres = get_bits1(&s->gb);
+ // FIXME disable this upon resolution change
+ s->use_last_frame_mvs = !s->errorres && !s->last_invisible;
+ if (s->keyframe) {
+ if (get_bits_long(&s->gb, 24) != VP9_SYNCCODE) { // synccode
+ 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(ctx, AV_LOG_ERROR, "RGB not supported in profile 0\n");
+ return AVERROR_INVALIDDATA;
+ }
+ s->fullrange = get_bits1(&s->gb);
+ // for profile 1, here follows the subsampling bits
+ s->refreshrefmask = 0xff;
+ w = get_bits(&s->gb, 16) + 1;
+ h = get_bits(&s->gb, 16) + 1;
+ 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);
+ if (s->intraonly) {
+ if (get_bits_long(&s->gb, 24) != VP9_SYNCCODE) { // synccode
+ av_log(ctx, AV_LOG_ERROR, "Invalid sync code\n");
+ return AVERROR_INVALIDDATA;
+ }
+ s->refreshrefmask = get_bits(&s->gb, 8);
+ w = get_bits(&s->gb, 16) + 1;
+ h = get_bits(&s->gb, 16) + 1;
+ if (get_bits1(&s->gb)) // display size
+ skip_bits(&s->gb, 32);
+ } else {
+ s->refreshrefmask = get_bits(&s->gb, 8);
+ s->refidx[0] = get_bits(&s->gb, 3);
+ s->signbias[0] = get_bits1(&s->gb);
+ s->refidx[1] = get_bits(&s->gb, 3);
+ 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]] || !s->refs[s->refidx[1]] ||
+ !s->refs[s->refidx[2]]) {
+ 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;
+ } else if (get_bits1(&s->gb)) {
+ w = s->refs[s->refidx[1]]->width;
+ h = s->refs[s->refidx[1]]->height;
+ } else if (get_bits1(&s->gb)) {
+ w = s->refs[s->refidx[2]]->width;
+ h = s->refs[s->refidx[2]]->height;
+ } else {
+ w = get_bits(&s->gb, 16) + 1;
+ h = get_bits(&s->gb, 16) + 1;
+ }
+ 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];
+ if (s->allowcompinter) {
+ if (s->signbias[0] == s->signbias[1]) {
+ s->fixcompref = 2;
+ s->varcompref[0] = 0;
+ s->varcompref[1] = 1;
+ } else if (s->signbias[0] == s->signbias[2]) {
+ s->fixcompref = 1;
+ s->varcompref[0] = 0;
+ s->varcompref[1] = 2;
+ } else {
+ s->fixcompref = 0;
+ s->varcompref[0] = 1;
+ s->varcompref[1] = 2;
+ }
+ }
+ }
+ }
+ 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
+ if (s->filter.sharpness != sharp)
+ memset(s->filter.lim_lut, 0, sizeof(s->filter.lim_lut));
+ s->filter.sharpness = sharp;
+ if ((s->lf_delta.enabled = get_bits1(&s->gb))) {
+ if (get_bits1(&s->gb)) {
+ for (i = 0; i < 4; i++)
+ if (get_bits1(&s->gb))
+ 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_sbits_inv(&s->gb, 6);
+ }
+ } else {
+ memset(&s->lf_delta, 0, sizeof(s->lf_delta));
+ }
+
+ /* quantization header data */
+ s->yac_qi = get_bits(&s->gb, 8);
+ s->ydc_qdelta = get_bits1(&s->gb) ? get_sbits_inv(&s->gb, 4) : 0;
+ s->uvdc_qdelta = get_bits1(&s->gb) ? get_sbits_inv(&s->gb, 4) : 0;
+ s->uvac_qdelta = get_bits1(&s->gb) ? get_sbits_inv(&s->gb, 4) : 0;
+ s->lossless = s->yac_qi == 0 && s->ydc_qdelta == 0 &&
+ s->uvdc_qdelta == 0 && s->uvac_qdelta == 0;
+
+ /* segmentation header info */
+ if ((s->segmentation.enabled = get_bits1(&s->gb))) {
+ if ((s->segmentation.update_map = get_bits1(&s->gb))) {
+ for (i = 0; i < 7; i++)
+ s->prob.seg[i] = get_bits1(&s->gb) ?
+ get_bits(&s->gb, 8) : 255;
+ if ((s->segmentation.temporal = get_bits1(&s->gb)))
+ for (i = 0; i < 3; i++)
+ s->prob.segpred[i] = get_bits1(&s->gb) ?
+ get_bits(&s->gb, 8) : 255;
+ }
+
+ 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_sbits_inv(&s->gb, 8);
+ if ((s->segmentation.feat[i].lf_enabled = get_bits1(&s->gb)))
+ 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);
+ }
+ }
+ } else {
+ s->segmentation.feat[0].q_enabled = 0;
+ s->segmentation.feat[0].lf_enabled = 0;
+ s->segmentation.feat[0].skip_enabled = 0;
+ s->segmentation.feat[0].ref_enabled = 0;
+ }
+
+ // set qmul[] based on Y/UV, AC/DC and segmentation Q idx deltas
+ for (i = 0; i < (s->segmentation.enabled ? 8 : 1); i++) {
+ int qyac, qydc, quvac, quvdc, lflvl, sh;
+
+ if (s->segmentation.feat[i].q_enabled) {
+ if (s->segmentation.absolute_vals)
+ qyac = s->segmentation.feat[i].q_val;
+ else
+ qyac = s->yac_qi + s->segmentation.feat[i].q_val;
+ } else {
+ 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] = 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) {
+ if (s->segmentation.absolute_vals)
+ lflvl = s->segmentation.feat[i].lf_val;
+ else
+ lflvl = s->filter.level + s->segmentation.feat[i].lf_val;
+ } else {
+ lflvl = s->filter.level;
+ }
+ s->segmentation.feat[i].lflvl[0][0] =
+ s->segmentation.feat[i].lflvl[0][1] =
+ av_clip_uintp2(lflvl + (s->lf_delta.ref[0] << sh), 6);
+ for (j = 1; j < 4; j++) {
+ s->segmentation.feat[i].lflvl[j][0] =
+ av_clip_uintp2(lflvl + ((s->lf_delta.ref[j] +
+ s->lf_delta.mode[0]) << sh), 6);
+ s->segmentation.feat[i].lflvl[j][1] =
+ av_clip_uintp2(lflvl + ((s->lf_delta.ref[j] +
+ s->lf_delta.mode[1]) << sh), 6);
+ }
+ }
+
+ /* tiling info */
+ 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;
+ s->tiling.log2_tile_cols++) ;
+ for (max = 0; (s->sb_cols >> max) >= 4; max++) ;
+ max = FFMAX(0, max - 1);
+ while (max > s->tiling.log2_tile_cols) {
+ if (get_bits1(&s->gb))
+ s->tiling.log2_tile_cols++;
+ else
+ break;
+ }
+ s->tiling.log2_tile_rows = decode012(&s->gb);
+ 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);
+ if (!s->c_b) {
+ 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 = 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(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(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 {
+ 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)?
+ s->prob.p = s->prob_ctx[c].p;
+
+ // txfm updates
+ if (s->lossless) {
+ s->txfmmode = TX_4X4;
+ } else {
+ s->txfmmode = vp8_rac_get_uint(&s->c, 2);
+ if (s->txfmmode == 3)
+ s->txfmmode += vp8_rac_get(&s->c);
+
+ if (s->txfmmode == TX_SWITCHABLE) {
+ for (i = 0; i < 2; i++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.tx8p[i] = update_prob(&s->c, s->prob.p.tx8p[i]);
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 2; j++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.tx16p[i][j] =
+ update_prob(&s->c, s->prob.p.tx16p[i][j]);
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 3; j++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.tx32p[i][j] =
+ update_prob(&s->c, s->prob.p.tx32p[i][j]);
+ }
+ }
+
+ // coef updates
+ for (i = 0; i < 4; i++) {
+ uint8_t (*ref)[2][6][6][3] = s->prob_ctx[c].coef[i];
+ if (vp8_rac_get(&s->c)) {
+ 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 *p = s->prob.coef[i][j][k][l][m];
+ uint8_t *r = ref[j][k][l][m];
+ 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)) {
+ p[n] = update_prob(&s->c, r[n]);
+ } else {
+ p[n] = r[n];
+ }
+ }
+ p[3] = 0;
+ }
+ } else {
+ 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 *p = s->prob.coef[i][j][k][l][m];
+ uint8_t *r = ref[j][k][l][m];
+ if (m > 3 && l == 0) // dc only has 3 pt
+ break;
+ memcpy(p, r, 3);
+ p[3] = 0;
+ }
+ }
+ if (s->txfmmode == i)
+ break;
+ }
+
+ // mode updates
+ for (i = 0; i < 3; i++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.skip[i] = update_prob(&s->c, s->prob.p.skip[i]);
+ if (!s->keyframe && !s->intraonly) {
+ for (i = 0; i < 7; i++)
+ for (j = 0; j < 3; j++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.mv_mode[i][j] =
+ update_prob(&s->c, s->prob.p.mv_mode[i][j]);
+
+ if (s->filtermode == FILTER_SWITCHABLE)
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 2; j++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.filter[i][j] =
+ update_prob(&s->c, s->prob.p.filter[i][j]);
+
+ for (i = 0; i < 4; i++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.intra[i] = update_prob(&s->c, s->prob.p.intra[i]);
+
+ if (s->allowcompinter) {
+ s->comppredmode = vp8_rac_get(&s->c);
+ if (s->comppredmode)
+ s->comppredmode += vp8_rac_get(&s->c);
+ if (s->comppredmode == PRED_SWITCHABLE)
+ for (i = 0; i < 5; i++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.comp[i] =
+ update_prob(&s->c, s->prob.p.comp[i]);
+ } else {
+ s->comppredmode = PRED_SINGLEREF;
+ }
+
+ if (s->comppredmode != PRED_COMPREF) {
+ for (i = 0; i < 5; i++) {
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.single_ref[i][0] =
+ update_prob(&s->c, s->prob.p.single_ref[i][0]);
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.single_ref[i][1] =
+ update_prob(&s->c, s->prob.p.single_ref[i][1]);
+ }
+ }
+
+ if (s->comppredmode != PRED_SINGLEREF) {
+ for (i = 0; i < 5; i++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.comp_ref[i] =
+ update_prob(&s->c, s->prob.p.comp_ref[i]);
+ }
+
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 9; j++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.y_mode[i][j] =
+ update_prob(&s->c, s->prob.p.y_mode[i][j]);
+
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 4; j++)
+ 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]);
+
+ // mv fields don't use the update_prob subexp model for some reason
+ for (i = 0; i < 3; i++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.mv_joint[i] = (vp8_rac_get_uint(&s->c, 7) << 1) | 1;
+
+ 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;
+
+ for (j = 0; j < 10; j++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.mv_comp[i].classes[j] =
+ (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;
+
+ for (j = 0; j < 10; j++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.mv_comp[i].bits[j] =
+ (vp8_rac_get_uint(&s->c, 7) << 1) | 1;
+ }
+
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 2; j++)
+ for (k = 0; k < 3; k++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.mv_comp[i].class0_fp[j][k] =
+ (vp8_rac_get_uint(&s->c, 7) << 1) | 1;
+
+ for (j = 0; j < 3; j++)
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.mv_comp[i].fp[j] =
+ (vp8_rac_get_uint(&s->c, 7) << 1) | 1;
+ }
+
+ if (s->highprecisionmvs) {
+ for (i = 0; i < 2; i++) {
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.mv_comp[i].class0_hp =
+ (vp8_rac_get_uint(&s->c, 7) << 1) | 1;
+
+ if (vp56_rac_get_prob_branchy(&s->c, 252))
+ s->prob.p.mv_comp[i].hp =
+ (vp8_rac_get_uint(&s->c, 7) << 1) | 1;
+ }
+ }
+ }
+
+ return (data2 - data) + size2;
+}
+
+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) {
+ struct 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) {
+ struct 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 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->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) {
+ struct 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 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->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) {
+ 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->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) {
+ 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 *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, 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 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 *const b = &s->b;
+ 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]), y;
+ int have_a = row > 0, have_l = col > s->tiling.tile_col_start;
+
+ 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, 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]);
+ av_assert1(pred < 8);
+ 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, 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, 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;
+ }
+
+ b->filter = vp8_rac_get_tree(&s->c, 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, 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]);
+ }
+ }
+
+ // 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 = 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_coeffs_b(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], 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) +
+ 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) +
+ (vp56_rac_get_prob(c, 148) << 1) +
+ vp56_rac_get_prob(c, 140);
+ } else {
+ val = 19 + (vp56_rac_get_prob(c, 176) << 3) +
+ (vp56_rac_get_prob(c, 155) << 2) +
+ (vp56_rac_get_prob(c, 140) << 1) +
+ 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) +
+ (vp56_rac_get_prob(c, 157) << 3) +
+ (vp56_rac_get_prob(c, 141) << 2) +
+ (vp56_rac_get_prob(c, 134) << 1) +
+ vp56_rac_get_prob(c, 130);
+ } else {
+ val = 67 + (vp56_rac_get_prob(c, 254) << 13) +
+ (vp56_rac_get_prob(c, 254) << 12) +
+ (vp56_rac_get_prob(c, 254) << 11) +
+ (vp56_rac_get_prob(c, 252) << 10) +
+ (vp56_rac_get_prob(c, 249) << 9) +
+ (vp56_rac_get_prob(c, 243) << 8) +
+ (vp56_rac_get_prob(c, 230) << 7) +
+ (vp56_rac_get_prob(c, 196) << 6) +
+ (vp56_rac_get_prob(c, 177) << 5) +
+ (vp56_rac_get_prob(c, 153) << 4) +
+ (vp56_rac_get_prob(c, 140) << 3) +
+ (vp56_rac_get_prob(c, 133) << 2) +
+ (vp56_rac_get_prob(c, 130) << 1) +
+ 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 *ctx)
+{
+ VP9Context *s = ctx->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), res;
+ int16_t (*qmul)[2] = s->segmentation.feat[b->seg_id].qmul;
+ int tx = 4 * s->lossless + b->tx;
+ const int16_t **yscans = vp9_scans[tx];
+ const int16_t (**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];
+
+ /* 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 = vp9_intra_txfm_type[b->mode[b->tx == TX_4X4 &&
+ b->bs > BS_8x8 ?
+ n : 0]];
+ int nnz = a[x] + l[y];
+ if ((res = decode_coeffs_b(&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 res;
+ a[x] = l[y] = !!res;
+ if (b->tx > TX_8X8) {
+ AV_WN16A(&s->eob[n], res);
+ } else {
+ s->eob[n] = res;
+ }
+ }
+ }
+ 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 ((res = decode_coeffs_b(&s->c, s->uvblock[pl] + 16 * n,
+ 16 * uvstep, b->uvtx, c, e, p, nnz,
+ uvscan, uvnb, uv_band_counts,
+ qmul[1])) < 0)
+ return res;
+ a[x] = l[y] = !!res;
+ if (b->uvtx > TX_8X8) {
+ AV_WN16A(&s->uveob[pl][n], res);
+ } else {
+ s->uveob[pl][n] = res;
+ }
+ }
+ }
+ 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, *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[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 *ctx, ptrdiff_t y_off, ptrdiff_t uv_off)
+{
+ VP9Context *s = ctx->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->f->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 = 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->f->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->f->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->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;
+ LOCAL_ALIGNED_16(uint8_t, a_buf, [48]);
+ uint8_t *a = &a_buf[16], l[32];
+ int eob = b->skip ? 0 : b->uvtx > TX_8X8 ? AV_RN16A(&s->uveob[p][n]) : s->uveob[p][n];
+
+ mode = check_intra_mode(s, mode, &a, ptr_r, s->f->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->f->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, 80,
+ ref - !!my * 3 * ref_stride - !!mx * 3,
+ 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,
+ 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, 80,
+ ref_u - !!my * 3 * src_stride_u - !!mx * 3, 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, 80,
+ ref_v - !!my * 3 * src_stride_v - !!mx * 3, 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 *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 = ctx->width, h = ctx->height;
+ ptrdiff_t ls_y = b->y_stride, ls_uv = b->uv_stride;
+
+ // 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, 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;
+ }
+ }
+ }
+}
+
+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 int 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 *const b = &s->b;
+ enum BlockSize bs = bl * 3 + bp;
+ int res, 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(ctx);
+ b->uvtx = b->tx - (w4 * 2 == (1 << b->tx) || h4 * 2 == (1 << b->tx));
+
+ if (!b->skip) {
+ if ((res = decode_coeffs(ctx)) < 0)
+ return res;
+ } 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->f->linesize[0] ||
+ (row + h4) > s->rows + 2 * !(ctx->flags & CODEC_FLAG_EMU_EDGE);
+ emu[1] = (col + w4) * 4 > s->f->linesize[1] ||
+ (row + h4) > s->rows + 2 * !(ctx->flags & CODEC_FLAG_EMU_EDGE);
+ if (emu[0]) {
+ b->dst[0] = s->tmp_y;
+ b->y_stride = 64;
+ } else {
+ b->dst[0] = s->f->data[0] + yoff;
+ b->y_stride = s->f->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->f->data[1] + uvoff;
+ b->dst[2] = s->f->data[2] + uvoff;
+ b->uv_stride = s->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](s->f->data[0] + yoff + o, s->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](s->f->data[1] + uvoff + o, s->f->linesize[1],
+ s->tmp_uv[0] + o, 32, h, 0, 0);
+ s->dsp.mc[n][0][0][0][0](s->f->data[2] + uvoff + o, s->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;
+
+ 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;
+}
+
+static int 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), res;
+ 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;
+
+ if (bl == BL_8X8) {
+ bp = vp8_rac_get_tree(&s->c, vp9_partition_tree, p);
+ res = decode_b(ctx, 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, vp9_partition_tree, p);
+ switch (bp) {
+ case PARTITION_NONE:
+ res = decode_b(ctx, row, col, lflvl, yoff, uvoff, bl, bp);
+ break;
+ case PARTITION_H:
+ if (!(res = decode_b(ctx, row, col, lflvl, yoff, uvoff, bl, bp))) {
+ yoff += hbs * 8 * s->f->linesize[0];
+ uvoff += hbs * 4 * s->f->linesize[1];
+ res = decode_b(ctx, row + hbs, col, lflvl, yoff, uvoff, bl, bp);
+ }
+ break;
+ case PARTITION_V:
+ if (!(res = decode_b(ctx, row, col, lflvl, yoff, uvoff, bl, bp))) {
+ yoff += hbs * 8;
+ uvoff += hbs * 4;
+ res = decode_b(ctx, row, col + hbs, lflvl, yoff, uvoff, bl, bp);
+ }
+ break;
+ case PARTITION_SPLIT:
+ if (!(res = decode_sb(ctx, row, col, lflvl, yoff, uvoff, bl + 1))) {
+ if (!(res = decode_sb(ctx, row, col + hbs, lflvl,
+ yoff + 8 * hbs, uvoff + 4 * hbs, bl + 1))) {
+ yoff += hbs * 8 * s->f->linesize[0];
+ uvoff += hbs * 4 * s->f->linesize[1];
+ if (!(res = decode_sb(ctx, row + hbs, col, lflvl,
+ yoff, uvoff, bl + 1)))
+ res = decode_sb(ctx, row + hbs, col + hbs, lflvl,
+ yoff + 8 * hbs, uvoff + 4 * hbs, bl + 1);
+ }
+ }
+ break;
+ }
+ } else if (vp56_rac_get_prob_branchy(&s->c, p[1])) {
+ bp = PARTITION_SPLIT;
+ if (!(res = decode_sb(ctx, row, col, lflvl, yoff, uvoff, bl + 1)))
+ res = decode_sb(ctx, row, col + hbs, lflvl,
+ yoff + 8 * hbs, uvoff + 4 * hbs, bl + 1);
+ } else {
+ bp = PARTITION_H;
+ res = decode_b(ctx, row, col, lflvl, yoff, uvoff, bl, bp);
+ }
+ } else if (row + hbs < s->rows) {
+ if (vp56_rac_get_prob_branchy(&s->c, p[2])) {
+ bp = PARTITION_SPLIT;
+ if (!(res = decode_sb(ctx, row, col, lflvl, yoff, uvoff, bl + 1))) {
+ yoff += hbs * 8 * s->f->linesize[0];
+ uvoff += hbs * 4 * s->f->linesize[1];
+ res = decode_sb(ctx, row + hbs, col, lflvl,
+ yoff, uvoff, bl + 1);
+ }
+ } else {
+ bp = PARTITION_V;
+ res = decode_b(ctx, row, col, lflvl, yoff, uvoff, bl, bp);
+ }
+ } else {
+ bp = PARTITION_SPLIT;
+ res = decode_sb(ctx, row, col, lflvl, yoff, uvoff, bl + 1);
+ }
+ s->counts.partition[bl][c][bp]++;
+
+ return res;
+}
+
+static void loopfilter_sb(AVCodecContext *ctx, struct VP9Filter *lflvl,
+ int row, int col, ptrdiff_t yoff, ptrdiff_t uvoff)
+{
+ VP9Context *s = ctx->priv_data;
+ uint8_t *dst = s->f->data[0] + yoff, *lvl = lflvl->level;
+ ptrdiff_t ls_y = s->f->linesize[0], ls_uv = s->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)
+
+ // filter edges between columns, Y plane (e.g. block1 | block2)
+ for (y = 0; y < 8; y += 2, dst += 16 * ls_y, lvl += 16) {
+ uint8_t *ptr = dst, *l = lvl, *hmask1 = lflvl->mask[0][0][y];
+ uint8_t *hmask2 = lflvl->mask[0][0][y + 1];
+ 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;
+
+ for (x = 1; hm & ~(x - 1); x <<= 1, ptr += 8, l++) {
+ if (hm1 & x) {
+ int L = *l, H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+
+ if (col || x > 1) {
+ if (hmask1[0] & x) {
+ if (hmask2[0] & x) {
+ av_assert2(l[8] == L);
+ s->dsp.loop_filter_16[0](ptr, ls_y, E, I, H);
+ } else {
+ s->dsp.loop_filter_8[2][0](ptr, ls_y, E, I, H);
+ }
+ } else if (hm2 & x) {
+ L = l[8];
+ H |= (L >> 4) << 8;
+ E |= s->filter.mblim_lut[L] << 8;
+ I |= s->filter.lim_lut[L] << 8;
+ s->dsp.loop_filter_mix2[!!(hmask1[1] & x)]
+ [!!(hmask2[1] & x)]
+ [0](ptr, ls_y, E, I, H);
+ } else {
+ s->dsp.loop_filter_8[!!(hmask1[1] & x)]
+ [0](ptr, ls_y, E, I, H);
+ }
+ }
+ } else if (hm2 & x) {
+ int L = l[8], H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+
+ if (col || x > 1) {
+ s->dsp.loop_filter_8[!!(hmask2[1] & x)]
+ [0](ptr + 8 * ls_y, ls_y, E, I, H);
+ }
+ }
+ if (hm13 & x) {
+ int L = *l, H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+
+ if (hm23 & x) {
+ L = l[8];
+ H |= (L >> 4) << 8;
+ E |= s->filter.mblim_lut[L] << 8;
+ I |= s->filter.lim_lut[L] << 8;
+ s->dsp.loop_filter_mix2[0][0][0](ptr + 4, ls_y, E, I, H);
+ } else {
+ s->dsp.loop_filter_8[0][0](ptr + 4, ls_y, E, I, H);
+ }
+ } else if (hm23 & x) {
+ int L = l[8], H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+
+ s->dsp.loop_filter_8[0][0](ptr + 8 * ls_y + 4, ls_y, E, I, H);
+ }
+ }
+ }
+
+ // block1
+ // filter edges between rows, Y plane (e.g. ------)
+ // block2
+ dst = s->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];
+ unsigned vm = vmask[0] | vmask[1] | vmask[2], vm3 = vmask[3];
+
+ for (x = 1; vm & ~(x - 1); x <<= 2, ptr += 16, l += 2) {
+ if (row || y) {
+ if (vm & x) {
+ int L = *l, H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+
+ if (vmask[0] & x) {
+ if (vmask[0] & (x << 1)) {
+ av_assert2(l[1] == L);
+ s->dsp.loop_filter_16[1](ptr, ls_y, E, I, H);
+ } else {
+ s->dsp.loop_filter_8[2][1](ptr, ls_y, E, I, H);
+ }
+ } else if (vm & (x << 1)) {
+ L = l[1];
+ H |= (L >> 4) << 8;
+ E |= s->filter.mblim_lut[L] << 8;
+ I |= s->filter.lim_lut[L] << 8;
+ s->dsp.loop_filter_mix2[!!(vmask[1] & x)]
+ [!!(vmask[1] & (x << 1))]
+ [1](ptr, ls_y, E, I, H);
+ } else {
+ s->dsp.loop_filter_8[!!(vmask[1] & x)]
+ [1](ptr, ls_y, E, I, H);
+ }
+ } else if (vm & (x << 1)) {
+ int L = l[1], H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+
+ s->dsp.loop_filter_8[!!(vmask[1] & (x << 1))]
+ [1](ptr + 8, ls_y, E, I, H);
+ }
+ }
+ if (vm3 & x) {
+ int L = *l, H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+
+ if (vm3 & (x << 1)) {
+ L = l[1];
+ H |= (L >> 4) << 8;
+ E |= s->filter.mblim_lut[L] << 8;
+ I |= s->filter.lim_lut[L] << 8;
+ s->dsp.loop_filter_mix2[0][0][1](ptr + ls_y * 4, ls_y, E, I, H);
+ } else {
+ s->dsp.loop_filter_8[0][1](ptr + ls_y * 4, ls_y, E, I, H);
+ }
+ } else if (vm3 & (x << 1)) {
+ int L = l[1], H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+
+ s->dsp.loop_filter_8[0][1](ptr + ls_y * 4 + 8, ls_y, E, I, H);
+ }
+ }
+ }
+
+ // same principle but for U/V planes
+ for (p = 0; p < 2; p++) {
+ lvl = lflvl->level;
+ dst = s->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];
+ unsigned hm1 = hmask1[0] | hmask1[1] | hmask1[2];
+ unsigned hm2 = hmask2[1] | hmask2[2], hm = hm1 | hm2;
+
+ for (x = 1; hm & ~(x - 1); x <<= 1, ptr += 4) {
+ if (col || x > 1) {
+ if (hm1 & x) {
+ int L = *l, H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+
+ if (hmask1[0] & x) {
+ if (hmask2[0] & x) {
+ av_assert2(l[16] == L);
+ s->dsp.loop_filter_16[0](ptr, ls_uv, E, I, H);
+ } else {
+ s->dsp.loop_filter_8[2][0](ptr, ls_uv, E, I, H);
+ }
+ } else if (hm2 & x) {
+ L = l[16];
+ H |= (L >> 4) << 8;
+ E |= s->filter.mblim_lut[L] << 8;
+ I |= s->filter.lim_lut[L] << 8;
+ s->dsp.loop_filter_mix2[!!(hmask1[1] & x)]
+ [!!(hmask2[1] & x)]
+ [0](ptr, ls_uv, E, I, H);
+ } else {
+ s->dsp.loop_filter_8[!!(hmask1[1] & x)]
+ [0](ptr, ls_uv, E, I, H);
+ }
+ } else if (hm2 & x) {
+ int L = l[16], H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+
+ s->dsp.loop_filter_8[!!(hmask2[1] & x)]
+ [0](ptr + 8 * ls_uv, ls_uv, E, I, H);
+ }
+ }
+ if (x & 0xAA)
+ l += 2;
+ }
+ }
+ lvl = lflvl->level;
+ dst = s->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];
+
+ for (x = 1; vm & ~(x - 1); x <<= 4, ptr += 16, l += 4) {
+ if (row || y) {
+ if (vm & x) {
+ int L = *l, H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+
+ if (vmask[0] & x) {
+ if (vmask[0] & (x << 2)) {
+ av_assert2(l[2] == L);
+ s->dsp.loop_filter_16[1](ptr, ls_uv, E, I, H);
+ } else {
+ s->dsp.loop_filter_8[2][1](ptr, ls_uv, E, I, H);
+ }
+ } else if (vm & (x << 2)) {
+ L = l[2];
+ H |= (L >> 4) << 8;
+ E |= s->filter.mblim_lut[L] << 8;
+ I |= s->filter.lim_lut[L] << 8;
+ s->dsp.loop_filter_mix2[!!(vmask[1] & x)]
+ [!!(vmask[1] & (x << 2))]
+ [1](ptr, ls_uv, E, I, H);
+ } else {
+ s->dsp.loop_filter_8[!!(vmask[1] & x)]
+ [1](ptr, ls_uv, E, I, H);
+ }
+ } else if (vm & (x << 2)) {
+ int L = l[2], H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+
+ s->dsp.loop_filter_8[!!(vmask[1] & (x << 2))]
+ [1](ptr + 8, ls_uv, E, I, H);
+ }
+ }
+ }
+ if (y & 1)
+ lvl += 16;
+ }
+ }
+}
+
+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_end = ((idx + 1) * n) >> log2_n;
+ *start = FFMIN(sb_start, n) << 3;
+ *end = FFMIN(sb_end, n) << 3;
+}
+
+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);
+}
+
+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;
+
+ 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 int vp9_decode_frame(AVCodecContext *ctx, void *out_pic,
+ int *got_frame, const uint8_t *data, int size)
+{
+ VP9Context *s = ctx->priv_data;
+ int res, tile_row, tile_col, i, ref, row, col;
+ ptrdiff_t yoff = 0, uvoff = 0;
+ //AVFrame *prev_frame = s->f; // for segmentation map
+
+ if ((res = decode_frame_header(ctx, data, size, &ref)) < 0) {
+ return res;
+ } else if (res == 0) {
+ if (!s->refs[ref]) {
+ av_log(ctx, AV_LOG_ERROR, "Requested reference %d not available\n", ref);
+ return AVERROR_INVALIDDATA;
+ }
+ if ((res = av_frame_ref(out_pic, s->refs[ref])) < 0)
+ return res;
+ *got_frame = 1;
+ return 0;
+ }
+ data += res;
+ size -= res;
+
+ // discard old references
+ for (i = 0; i < 10; i++) {
+ AVFrame *f = s->fb[i];
+ if (f->data[0] && f != s->f &&
+ f != s->refs[0] && f != s->refs[1] &&
+ f != s->refs[2] && f != s->refs[3] &&
+ f != s->refs[4] && f != s->refs[5] &&
+ f != s->refs[6] && f != s->refs[7])
+ av_frame_unref(f);
+ }
+
+ // find unused reference
+ for (i = 0; i < 10; i++)
+ if (!s->fb[i]->data[0])
+ break;
+ av_assert0(i < 10);
+ s->f = s->fb[i];
+ if ((res = ff_get_buffer(ctx, s->f,
+ s->refreshrefmask ? AV_GET_BUFFER_FLAG_REF : 0)) < 0)
+ return res;
+ s->f->key_frame = s->keyframe;
+ s->f->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
+
+ // 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) {
+ memset(s->above_mode_ctx, DC_PRED, s->cols * 2);
+ } 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++) {
+ 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)
+ 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->f->linesize[0] * 64,
+ uvoff += s->f->linesize[1] * 32) {
+ struct VP9Filter *lflvl_ptr = s->lflvl;
+ ptrdiff_t yoff2 = yoff, uvoff2 = uvoff;
+
+ for (tile_col = 0; tile_col < s->tiling.tile_cols; tile_col++) {
+ set_tile_offset(&s->tiling.tile_col_start, &s->tiling.tile_col_end,
+ tile_col, s->tiling.log2_tile_cols, s->sb_cols);
+
+ 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)
+ memset(lflvl_ptr->mask, 0, sizeof(lflvl_ptr->mask));
+
+ if ((res = decode_sb(ctx, row, col, lflvl_ptr,
+ yoff2, uvoff2, BL_64X64)) < 0)
+ return res;
+ }
+ 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->f->data[0] + yoff + 63 * s->f->linesize[0],
+ 8 * s->cols);
+ memcpy(s->intra_pred_data[1],
+ s->f->data[1] + uvoff + 31 * s->f->linesize[1],
+ 4 * s->cols);
+ memcpy(s->intra_pred_data[2],
+ s->f->data[2] + uvoff + 31 * s->f->linesize[2],
+ 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);
+ }
+ }
+ }
+ }
+
+ // bw adaptivity (or in case of parallel decoding mode, fw adaptivity
+ // probability maintenance between frames)
+ if (s->refreshctx) {
+ if (s->parallelmode) {
+ int i, 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);
+ s->prob_ctx[s->framectxid].p = s->prob.p;
+ } else {
+ adapt_probs(s);
+ }
+ }
+ FFSWAP(struct VP9mvrefPair *, s->mv[0], s->mv[1]);
+
+ // ref frame setup
+ for (i = 0; i < 8; i++)
+ if (s->refreshrefmask & (1 << i))
+ s->refs[i] = s->f;
+
+ if (!s->invisible) {
+ if ((res = av_frame_ref(out_pic, s->f)) < 0)
+ return res;
+ *got_frame = 1;
+ }
+
+ return 0;
+}
+
+static int vp9_decode_packet(AVCodecContext *avctx, void *out_pic,
+ int *got_frame, AVPacket *avpkt)
+{
+ const uint8_t *data = avpkt->data;
+ int size = avpkt->size, marker, res;
+
+ // read superframe index - this is a collection of individual frames that
+ // together lead to one visible frame
+ av_assert1(size > 0); // without CODEC_CAP_DELAY, this is implied
+ 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;
+ switch (nbytes) {
+#define case_n(a, rd) \
+ case a: \
+ while (n_frames--) { \
+ int sz = rd; \
+ idx += a; \
+ if (sz > size) { \
+ av_log(avctx, AV_LOG_ERROR, \
+ "Superframe packet size too big: %d > %d\n", \
+ sz, size); \
+ return AVERROR_INVALIDDATA; \
+ } \
+ res = vp9_decode_frame(avctx, out_pic, got_frame, \
+ data, sz); \
+ if (res < 0) \
+ return res; \
+ data += sz; \
+ size -= sz; \
+ } \
+ break;
+ case_n(1, *idx);
+ case_n(2, AV_RL16(idx));
+ case_n(3, AV_RL24(idx));
+ case_n(4, AV_RL32(idx));
+ }
+ return avpkt->size;
+ }
+ }
+ // 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 ((res = vp9_decode_frame(avctx, out_pic, got_frame, data, size)) < 0)
+ return res;
+ return avpkt->size;
+}
+
+static void vp9_decode_flush(AVCodecContext *ctx)
+{
+ VP9Context *s = ctx->priv_data;
+ int i;
+
+ for (i = 0; i < 10; i++)
+ if (s->fb[i]->data[0])
+ av_frame_unref(s->fb[i]);
+ for (i = 0; i < 8; i++)
+ s->refs[i] = NULL;
+ s->f = NULL;
+}
+
+static av_cold int vp9_decode_init(AVCodecContext *ctx)
+{
+ VP9Context *s = ctx->priv_data;
+ int i;
+
+ ctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ ff_vp9dsp_init(&s->dsp);
+ ff_videodsp_init(&s->vdsp, 8);
+ for (i = 0; i < 10; i++) {
+ s->fb[i] = av_frame_alloc();
+ if (!s->fb[i]) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to allocate frame buffer %d\n", i);
+ return AVERROR(ENOMEM);
+ }
+ }
+ s->filter.sharpness = -1;
+
+ return 0;
+}
+
+static av_cold int vp9_decode_free(AVCodecContext *ctx)
+{
+ VP9Context *s = ctx->priv_data;
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ if (s->fb[i]->data[0])
+ av_frame_unref(s->fb[i]);
+ av_frame_free(&s->fb[i]);
+ }
+ av_freep(&s->above_partition_ctx);
+ s->above_skip_ctx = s->above_txfm_ctx = s->above_mode_ctx = NULL;
+ s->above_y_nnz_ctx = s->above_uv_nnz_ctx[0] = s->above_uv_nnz_ctx[1] = NULL;
+ s->intra_pred_data[0] = s->intra_pred_data[1] = s->intra_pred_data[2] = NULL;
+ s->above_segpred_ctx = s->above_intra_ctx = s->above_comp_ctx = NULL;
+ s->above_ref_ctx = s->above_filter_ctx = NULL;
+ s->above_mv_ctx = NULL;
+ s->segmentation_map = NULL;
+ s->mv[0] = s->mv[1] = NULL;
+ s->lflvl = NULL;
+ av_freep(&s->c_b);
+ s->c_b_size = 0;
+
+ 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,
+ .close = vp9_decode_free,
+ .decode = vp9_decode_packet,
+ .capabilities = CODEC_CAP_DR1,
+ .flush = vp9_decode_flush,
+};
diff --git a/libavcodec/vp9.h b/libavcodec/vp9.h
new file mode 100644
index 0000000..9a29416
--- a/dev/null
+++ b/libavcodec/vp9.h
@@ -0,0 +1,72 @@
+/*
+ * 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_VP9_H
+#define AVCODEC_VP9_H
+
+enum TxfmMode {
+ TX_4X4,
+ TX_8X8,
+ TX_16X16,
+ TX_32X32,
+ N_TXFM_SIZES,
+ TX_SWITCHABLE = N_TXFM_SIZES,
+ N_TXFM_MODES
+};
+
+enum TxfmType {
+ DCT_DCT,
+ DCT_ADST,
+ ADST_DCT,
+ ADST_ADST,
+ N_TXFM_TYPES
+};
+
+enum IntraPredMode {
+ VERT_PRED,
+ HOR_PRED,
+ DC_PRED,
+ DIAG_DOWN_LEFT_PRED,
+ DIAG_DOWN_RIGHT_PRED,
+ VERT_RIGHT_PRED,
+ HOR_DOWN_PRED,
+ VERT_LEFT_PRED,
+ HOR_UP_PRED,
+ TM_VP8_PRED,
+ LEFT_DC_PRED,
+ TOP_DC_PRED,
+ DC_128_PRED,
+ DC_127_PRED,
+ DC_129_PRED,
+ N_INTRA_PRED_MODES
+};
+
+enum FilterMode {
+ FILTER_8TAP_SMOOTH,
+ FILTER_8TAP_REGULAR,
+ FILTER_8TAP_SHARP,
+ FILTER_BILINEAR,
+ FILTER_SWITCHABLE,
+};
+
+#endif /* AVCODEC_VP9_H */
diff --git a/libavcodec/vp9data.h b/libavcodec/vp9data.h
new file mode 100644
index 0000000..d38365a
--- a/dev/null
+++ b/libavcodec/vp9data.h
@@ -0,0 +1,2155 @@
+/*
+ * 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_VP9DATA_H
+#define AVCODEC_VP9DATA_H
+
+#include <stdint.h>
+
+#include "vp9.h"
+
+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 *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 (*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
new file mode 100644
index 0000000..6159616
--- a/dev/null
+++ b/libavcodec/vp9dsp.c
@@ -0,0 +1,2049 @@
+/*
+ * VP9 compatible video decoder
+ *
+ * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
+ * Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
+#include "vp9dsp.h"
+#include "rnd_avg.h"
+
+// FIXME see whether we can merge parts of this (perhaps at least 4x4 and 8x8)
+// back with h264pred.[ch]
+
+static void vert_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ unsigned p4 = AV_RN32A(top);
+
+ AV_WN32A(dst + stride * 0, p4);
+ AV_WN32A(dst + stride * 1, p4);
+ AV_WN32A(dst + stride * 2, p4);
+ AV_WN32A(dst + stride * 3, p4);
+}
+
+static void vert_8x8_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ uint64_t p8 = AV_RN64A(top);
+ int y;
+
+ for (y = 0; y < 8; y++) {
+ AV_WN64A(dst, p8);
+ dst += stride;
+ }
+}
+
+static void vert_16x16_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ uint64_t p8a = AV_RN64A(top + 0), p8b = AV_RN64A(top + 8);
+ int y;
+
+ for (y = 0; y < 16; y++) {
+ AV_WN64A(dst + 0, p8a);
+ AV_WN64A(dst + 8, p8b);
+ dst += stride;
+ }
+}
+
+static void vert_32x32_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ uint64_t p8a = AV_RN64A(top + 0), p8b = AV_RN64A(top + 8),
+ p8c = AV_RN64A(top + 16), p8d = AV_RN64A(top + 24);
+ int y;
+
+ for (y = 0; y < 32; y++) {
+ AV_WN64A(dst + 0, p8a);
+ AV_WN64A(dst + 8, p8b);
+ AV_WN64A(dst + 16, p8c);
+ AV_WN64A(dst + 24, p8d);
+ dst += stride;
+ }
+}
+
+static void hor_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ AV_WN32A(dst + stride * 0, left[0] * 0x01010101U);
+ AV_WN32A(dst + stride * 1, left[1] * 0x01010101U);
+ AV_WN32A(dst + stride * 2, left[2] * 0x01010101U);
+ AV_WN32A(dst + stride * 3, left[3] * 0x01010101U);
+}
+
+static void hor_8x8_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y;
+
+ for (y = 0; y < 8; y++) {
+ AV_WN64A(dst, left[y] * 0x0101010101010101ULL);
+ dst += stride;
+ }
+}
+
+static void hor_16x16_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y;
+
+ for (y = 0; y < 16; y++) {
+ uint64_t p8 = left[y] * 0x0101010101010101ULL;
+
+ AV_WN64A(dst + 0, p8);
+ AV_WN64A(dst + 8, p8);
+ dst += stride;
+ }
+}
+
+static void hor_32x32_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y;
+
+ for (y = 0; y < 32; y++) {
+ uint64_t p8 = left[y] * 0x0101010101010101ULL;
+
+ AV_WN64A(dst + 0, p8);
+ AV_WN64A(dst + 8, p8);
+ AV_WN64A(dst + 16, p8);
+ AV_WN64A(dst + 24, p8);
+ dst += stride;
+ }
+}
+
+static void tm_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y, tl = top[-1];
+
+ for (y = 0; y < 4; y++) {
+ int l_m_tl = left[y] - tl;
+
+ dst[0] = av_clip_uint8(top[0] + l_m_tl);
+ dst[1] = av_clip_uint8(top[1] + l_m_tl);
+ dst[2] = av_clip_uint8(top[2] + l_m_tl);
+ dst[3] = av_clip_uint8(top[3] + l_m_tl);
+ dst += stride;
+ }
+}
+
+static void tm_8x8_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y, tl = top[-1];
+
+ for (y = 0; y < 8; y++) {
+ int l_m_tl = left[y] - tl;
+
+ dst[0] = av_clip_uint8(top[0] + l_m_tl);
+ dst[1] = av_clip_uint8(top[1] + l_m_tl);
+ dst[2] = av_clip_uint8(top[2] + l_m_tl);
+ dst[3] = av_clip_uint8(top[3] + l_m_tl);
+ dst[4] = av_clip_uint8(top[4] + l_m_tl);
+ dst[5] = av_clip_uint8(top[5] + l_m_tl);
+ dst[6] = av_clip_uint8(top[6] + l_m_tl);
+ dst[7] = av_clip_uint8(top[7] + l_m_tl);
+ dst += stride;
+ }
+}
+
+static void tm_16x16_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y, tl = top[-1];
+
+ for (y = 0; y < 16; y++) {
+ int l_m_tl = left[y] - tl;
+
+ dst[ 0] = av_clip_uint8(top[ 0] + l_m_tl);
+ dst[ 1] = av_clip_uint8(top[ 1] + l_m_tl);
+ dst[ 2] = av_clip_uint8(top[ 2] + l_m_tl);
+ dst[ 3] = av_clip_uint8(top[ 3] + l_m_tl);
+ dst[ 4] = av_clip_uint8(top[ 4] + l_m_tl);
+ dst[ 5] = av_clip_uint8(top[ 5] + l_m_tl);
+ dst[ 6] = av_clip_uint8(top[ 6] + l_m_tl);
+ dst[ 7] = av_clip_uint8(top[ 7] + l_m_tl);
+ dst[ 8] = av_clip_uint8(top[ 8] + l_m_tl);
+ dst[ 9] = av_clip_uint8(top[ 9] + l_m_tl);
+ dst[10] = av_clip_uint8(top[10] + l_m_tl);
+ dst[11] = av_clip_uint8(top[11] + l_m_tl);
+ dst[12] = av_clip_uint8(top[12] + l_m_tl);
+ dst[13] = av_clip_uint8(top[13] + l_m_tl);
+ dst[14] = av_clip_uint8(top[14] + l_m_tl);
+ dst[15] = av_clip_uint8(top[15] + l_m_tl);
+ dst += stride;
+ }
+}
+
+static void tm_32x32_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y, tl = top[-1];
+
+ for (y = 0; y < 32; y++) {
+ int l_m_tl = left[y] - tl;
+
+ dst[ 0] = av_clip_uint8(top[ 0] + l_m_tl);
+ dst[ 1] = av_clip_uint8(top[ 1] + l_m_tl);
+ dst[ 2] = av_clip_uint8(top[ 2] + l_m_tl);
+ dst[ 3] = av_clip_uint8(top[ 3] + l_m_tl);
+ dst[ 4] = av_clip_uint8(top[ 4] + l_m_tl);
+ dst[ 5] = av_clip_uint8(top[ 5] + l_m_tl);
+ dst[ 6] = av_clip_uint8(top[ 6] + l_m_tl);
+ dst[ 7] = av_clip_uint8(top[ 7] + l_m_tl);
+ dst[ 8] = av_clip_uint8(top[ 8] + l_m_tl);
+ dst[ 9] = av_clip_uint8(top[ 9] + l_m_tl);
+ dst[10] = av_clip_uint8(top[10] + l_m_tl);
+ dst[11] = av_clip_uint8(top[11] + l_m_tl);
+ dst[12] = av_clip_uint8(top[12] + l_m_tl);
+ dst[13] = av_clip_uint8(top[13] + l_m_tl);
+ dst[14] = av_clip_uint8(top[14] + l_m_tl);
+ dst[15] = av_clip_uint8(top[15] + l_m_tl);
+ dst[16] = av_clip_uint8(top[16] + l_m_tl);
+ dst[17] = av_clip_uint8(top[17] + l_m_tl);
+ dst[18] = av_clip_uint8(top[18] + l_m_tl);
+ dst[19] = av_clip_uint8(top[19] + l_m_tl);
+ dst[20] = av_clip_uint8(top[20] + l_m_tl);
+ dst[21] = av_clip_uint8(top[21] + l_m_tl);
+ dst[22] = av_clip_uint8(top[22] + l_m_tl);
+ dst[23] = av_clip_uint8(top[23] + l_m_tl);
+ dst[24] = av_clip_uint8(top[24] + l_m_tl);
+ dst[25] = av_clip_uint8(top[25] + l_m_tl);
+ dst[26] = av_clip_uint8(top[26] + l_m_tl);
+ dst[27] = av_clip_uint8(top[27] + l_m_tl);
+ dst[28] = av_clip_uint8(top[28] + l_m_tl);
+ dst[29] = av_clip_uint8(top[29] + l_m_tl);
+ dst[30] = av_clip_uint8(top[30] + l_m_tl);
+ dst[31] = av_clip_uint8(top[31] + l_m_tl);
+ dst += stride;
+ }
+}
+
+static void dc_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ unsigned dc = 0x01010101U * ((left[0] + left[1] + left[2] + left[3] +
+ top[0] + top[1] + top[2] + top[3] + 4) >> 3);
+
+ AV_WN32A(dst + stride * 0, dc);
+ AV_WN32A(dst + stride * 1, dc);
+ AV_WN32A(dst + stride * 2, dc);
+ AV_WN32A(dst + stride * 3, dc);
+}
+
+static void dc_8x8_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ uint64_t dc = 0x0101010101010101ULL *
+ ((left[0] + left[1] + left[2] + left[3] + left[4] + left[5] +
+ left[6] + left[7] + top[0] + top[1] + top[2] + top[3] +
+ top[4] + top[5] + top[6] + top[7] + 8) >> 4);
+ int y;
+
+ for (y = 0; y < 8; y++) {
+ AV_WN64A(dst, dc);
+ dst += stride;
+ }
+}
+
+static void dc_16x16_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ uint64_t dc = 0x0101010101010101ULL *
+ ((left[0] + left[1] + left[2] + left[3] + left[4] + left[5] + left[6] +
+ left[7] + left[8] + left[9] + left[10] + left[11] + left[12] +
+ left[13] + left[14] + left[15] + top[0] + top[1] + top[2] + top[3] +
+ top[4] + top[5] + top[6] + top[7] + top[8] + top[9] + top[10] +
+ top[11] + top[12] + top[13] + top[14] + top[15] + 16) >> 5);
+ int y;
+
+ for (y = 0; y < 16; y++) {
+ AV_WN64A(dst + 0, dc);
+ AV_WN64A(dst + 8, dc);
+ dst += stride;
+ }
+}
+
+static void dc_32x32_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ uint64_t dc = 0x0101010101010101ULL *
+ ((left[0] + left[1] + left[2] + left[3] + left[4] + left[5] + left[6] +
+ left[7] + left[8] + left[9] + left[10] + left[11] + left[12] +
+ left[13] + left[14] + left[15] + left[16] + left[17] + left[18] +
+ left[19] + left[20] + left[21] + left[22] + left[23] + left[24] +
+ left[25] + left[26] + left[27] + left[28] + left[29] + left[30] +
+ left[31] + top[0] + top[1] + top[2] + top[3] + top[4] + top[5] +
+ top[6] + top[7] + top[8] + top[9] + top[10] + top[11] + top[12] +
+ top[13] + top[14] + top[15] + top[16] + top[17] + top[18] + top[19] +
+ top[20] + top[21] + top[22] + top[23] + top[24] + top[25] + top[26] +
+ top[27] + top[28] + top[29] + top[30] + top[31] + 32) >> 6);
+ int y;
+
+ for (y = 0; y < 32; y++) {
+ AV_WN64A(dst + 0, dc);
+ AV_WN64A(dst + 8, dc);
+ AV_WN64A(dst + 16, dc);
+ AV_WN64A(dst + 24, dc);
+ dst += stride;
+ }
+}
+
+static void dc_left_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ unsigned dc = 0x01010101U * ((left[0] + left[1] + left[2] + left[3] + 2) >> 2);
+
+ AV_WN32A(dst + stride * 0, dc);
+ AV_WN32A(dst + stride * 1, dc);
+ AV_WN32A(dst + stride * 2, dc);
+ AV_WN32A(dst + stride * 3, dc);
+}
+
+static void dc_left_8x8_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ uint64_t dc = 0x0101010101010101ULL *
+ ((left[0] + left[1] + left[2] + left[3] +
+ left[4] + left[5] + left[6] + left[7] + 4) >> 3);
+ int y;
+
+ for (y = 0; y < 8; y++) {
+ AV_WN64A(dst, dc);
+ dst += stride;
+ }
+}
+
+static void dc_left_16x16_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ uint64_t dc = 0x0101010101010101ULL *
+ ((left[0] + left[1] + left[2] + left[3] + left[4] + left[5] +
+ left[6] + left[7] + left[8] + left[9] + left[10] + left[11] +
+ left[12] + left[13] + left[14] + left[15] + 8) >> 4);
+ int y;
+
+ for (y = 0; y < 16; y++) {
+ AV_WN64A(dst + 0, dc);
+ AV_WN64A(dst + 8, dc);
+ dst += stride;
+ }
+}
+
+static void dc_left_32x32_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ uint64_t dc = 0x0101010101010101ULL *
+ ((left[0] + left[1] + left[2] + left[3] + left[4] + left[5] +
+ left[6] + left[7] + left[8] + left[9] + left[10] + left[11] +
+ left[12] + left[13] + left[14] + left[15] + left[16] + left[17] +
+ left[18] + left[19] + left[20] + left[21] + left[22] + left[23] +
+ left[24] + left[25] + left[26] + left[27] + left[28] + left[29] +
+ left[30] + left[31] + 16) >> 5);
+ int y;
+
+ for (y = 0; y < 32; y++) {
+ AV_WN64A(dst + 0, dc);
+ AV_WN64A(dst + 8, dc);
+ AV_WN64A(dst + 16, dc);
+ AV_WN64A(dst + 24, dc);
+ dst += stride;
+ }
+}
+
+static void dc_top_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ unsigned dc = 0x01010101U * ((top[0] + top[1] + top[2] + top[3] + 2) >> 2);
+
+ AV_WN32A(dst + stride * 0, dc);
+ AV_WN32A(dst + stride * 1, dc);
+ AV_WN32A(dst + stride * 2, dc);
+ AV_WN32A(dst + stride * 3, dc);
+}
+
+static void dc_top_8x8_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ uint64_t dc = 0x0101010101010101ULL *
+ ((top[0] + top[1] + top[2] + top[3] +
+ top[4] + top[5] + top[6] + top[7] + 4) >> 3);
+ int y;
+
+ for (y = 0; y < 8; y++) {
+ AV_WN64A(dst, dc);
+ dst += stride;
+ }
+}
+
+static void dc_top_16x16_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ uint64_t dc = 0x0101010101010101ULL *
+ ((top[0] + top[1] + top[2] + top[3] + top[4] + top[5] +
+ top[6] + top[7] + top[8] + top[9] + top[10] + top[11] +
+ top[12] + top[13] + top[14] + top[15] + 8) >> 4);
+ int y;
+
+ for (y = 0; y < 16; y++) {
+ AV_WN64A(dst + 0, dc);
+ AV_WN64A(dst + 8, dc);
+ dst += stride;
+ }
+}
+
+static void dc_top_32x32_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ uint64_t dc = 0x0101010101010101ULL *
+ ((top[0] + top[1] + top[2] + top[3] + top[4] + top[5] +
+ top[6] + top[7] + top[8] + top[9] + top[10] + top[11] +
+ top[12] + top[13] + top[14] + top[15] + top[16] + top[17] +
+ top[18] + top[19] + top[20] + top[21] + top[22] + top[23] +
+ top[24] + top[25] + top[26] + top[27] + top[28] + top[29] +
+ top[30] + top[31] + 16) >> 5);
+ int y;
+
+ for (y = 0; y < 32; y++) {
+ AV_WN64A(dst + 0, dc);
+ AV_WN64A(dst + 8, dc);
+ AV_WN64A(dst + 16, dc);
+ AV_WN64A(dst + 24, dc);
+ dst += stride;
+ }
+}
+
+static void dc_128_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ AV_WN32A(dst + stride * 0, 0x80808080U);
+ AV_WN32A(dst + stride * 1, 0x80808080U);
+ AV_WN32A(dst + stride * 2, 0x80808080U);
+ AV_WN32A(dst + stride * 3, 0x80808080U);
+}
+
+static void dc_128_8x8_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y;
+
+ for (y = 0; y < 8; y++) {
+ AV_WN64A(dst, 0x8080808080808080ULL);
+ dst += stride;
+ }
+}
+
+static void dc_128_16x16_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y;
+
+ for (y = 0; y < 16; y++) {
+ AV_WN64A(dst + 0, 0x8080808080808080ULL);
+ AV_WN64A(dst + 8, 0x8080808080808080ULL);
+ dst += stride;
+ }
+}
+
+static void dc_128_32x32_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y;
+
+ for (y = 0; y < 32; y++) {
+ AV_WN64A(dst + 0, 0x8080808080808080ULL);
+ AV_WN64A(dst + 8, 0x8080808080808080ULL);
+ AV_WN64A(dst + 16, 0x8080808080808080ULL);
+ AV_WN64A(dst + 24, 0x8080808080808080ULL);
+ dst += stride;
+ }
+}
+
+static void dc_127_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ AV_WN32A(dst + stride * 0, 0x7F7F7F7FU);
+ AV_WN32A(dst + stride * 1, 0x7F7F7F7FU);
+ AV_WN32A(dst + stride * 2, 0x7F7F7F7FU);
+ AV_WN32A(dst + stride * 3, 0x7F7F7F7FU);
+}
+
+static void dc_127_8x8_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y;
+
+ for (y = 0; y < 8; y++) {
+ AV_WN64A(dst, 0x7F7F7F7F7F7F7F7FULL);
+ dst += stride;
+ }
+}
+
+static void dc_127_16x16_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y;
+
+ for (y = 0; y < 16; y++) {
+ AV_WN64A(dst + 0, 0x7F7F7F7F7F7F7F7FULL);
+ AV_WN64A(dst + 8, 0x7F7F7F7F7F7F7F7FULL);
+ dst += stride;
+ }
+}
+
+static void dc_127_32x32_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y;
+
+ for (y = 0; y < 32; y++) {
+ AV_WN64A(dst + 0, 0x7F7F7F7F7F7F7F7FULL);
+ AV_WN64A(dst + 8, 0x7F7F7F7F7F7F7F7FULL);
+ AV_WN64A(dst + 16, 0x7F7F7F7F7F7F7F7FULL);
+ AV_WN64A(dst + 24, 0x7F7F7F7F7F7F7F7FULL);
+ dst += stride;
+ }
+}
+
+static void dc_129_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ AV_WN32A(dst + stride * 0, 0x81818181U);
+ AV_WN32A(dst + stride * 1, 0x81818181U);
+ AV_WN32A(dst + stride * 2, 0x81818181U);
+ AV_WN32A(dst + stride * 3, 0x81818181U);
+}
+
+static void dc_129_8x8_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y;
+
+ for (y = 0; y < 8; y++) {
+ AV_WN64A(dst, 0x8181818181818181ULL);
+ dst += stride;
+ }
+}
+
+static void dc_129_16x16_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y;
+
+ for (y = 0; y < 16; y++) {
+ AV_WN64A(dst + 0, 0x8181818181818181ULL);
+ AV_WN64A(dst + 8, 0x8181818181818181ULL);
+ dst += stride;
+ }
+}
+
+static void dc_129_32x32_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int y;
+
+ for (y = 0; y < 32; y++) {
+ AV_WN64A(dst + 0, 0x8181818181818181ULL);
+ AV_WN64A(dst + 8, 0x8181818181818181ULL);
+ AV_WN64A(dst + 16, 0x8181818181818181ULL);
+ AV_WN64A(dst + 24, 0x8181818181818181ULL);
+ dst += stride;
+ }
+}
+
+#define DST(x, y) dst[(x) + (y) * stride]
+
+static void diag_downleft_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int a0 = top[0], a1 = top[1], a2 = top[2], a3 = top[3],
+ a4 = top[4], a5 = top[5], a6 = top[6], a7 = top[7];
+
+ DST(0,0) = (a0 + a1 * 2 + a2 + 2) >> 2;
+ DST(1,0) = DST(0,1) = (a1 + a2 * 2 + a3 + 2) >> 2;
+ DST(2,0) = DST(1,1) = DST(0,2) = (a2 + a3 * 2 + a4 + 2) >> 2;
+ DST(3,0) = DST(2,1) = DST(1,2) = DST(0,3) = (a3 + a4 * 2 + a5 + 2) >> 2;
+ DST(3,1) = DST(2,2) = DST(1,3) = (a4 + a5 * 2 + a6 + 2) >> 2;
+ DST(3,2) = DST(2,3) = (a5 + a6 * 2 + a7 + 2) >> 2;
+ DST(3,3) = a7; // note: this is different from vp8 and such
+}
+
+#define def_diag_downleft(size) \
+static void diag_downleft_##size##x##size##_c(uint8_t *dst, ptrdiff_t stride, \
+ const uint8_t *left, const uint8_t *top) \
+{ \
+ int i, j; \
+ uint8_t v[size - 1]; \
+\
+ for (i = 0; i < size - 2; i++) \
+ v[i] = (top[i] + top[i + 1] * 2 + top[i + 2] + 2) >> 2; \
+ v[size - 2] = (top[size - 2] + top[size - 1] * 3 + 2) >> 2; \
+\
+ for (j = 0; j < size; j++) { \
+ memcpy(dst + j*stride, v + j, size - 1 - j); \
+ memset(dst + j*stride + size - 1 - j, top[size - 1], j + 1); \
+ } \
+}
+
+def_diag_downleft(8)
+def_diag_downleft(16)
+def_diag_downleft(32)
+
+static void diag_downright_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int tl = top[-1], a0 = top[0], a1 = top[1], a2 = top[2], a3 = top[3],
+ l0 = left[0], l1 = left[1], l2 = left[2], l3 = left[3];
+
+ DST(0,3) = (l1 + l2 * 2 + l3 + 2) >> 2;
+ DST(0,2) = DST(1,3) = (l0 + l1 * 2 + l2 + 2) >> 2;
+ DST(0,1) = DST(1,2) = DST(2,3) = (tl + l0 * 2 + l1 + 2) >> 2;
+ DST(0,0) = DST(1,1) = DST(2,2) = DST(3,3) = (l0 + tl * 2 + a0 + 2) >> 2;
+ DST(1,0) = DST(2,1) = DST(3,2) = (tl + a0 * 2 + a1 + 2) >> 2;
+ DST(2,0) = DST(3,1) = (a0 + a1 * 2 + a2 + 2) >> 2;
+ DST(3,0) = (a1 + a2 * 2 + a3 + 2) >> 2;
+}
+
+#define def_diag_downright(size) \
+static void diag_downright_##size##x##size##_c(uint8_t *dst, ptrdiff_t stride, \
+ const uint8_t *left, const uint8_t *top) \
+{ \
+ int i, j; \
+ uint8_t v[size + size - 1]; \
+\
+ for (i = 0; i < size - 2; i++) { \
+ v[i ] = (left[size - 1 - i] + left[size - 2 - i] * 2 + left[size - 3 - i] + 2) >> 2; \
+ v[size + 1 + i] = (top[i] + top[i + 1] * 2 + top[i + 2] + 2) >> 2; \
+ } \
+ v[size - 2] = (left[1] + left[0] * 2 + top[-1] + 2) >> 2; \
+ v[size - 1] = (left[0] + top[-1] * 2 + top[ 0] + 2) >> 2; \
+ v[size ] = (top[-1] + top[0] * 2 + top[ 1] + 2) >> 2; \
+\
+ for (j = 0; j < size; j++) \
+ memcpy(dst + j*stride, v + size - 1 - j, size); \
+}
+
+def_diag_downright(8)
+def_diag_downright(16)
+def_diag_downright(32)
+
+static void vert_right_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int tl = top[-1], a0 = top[0], a1 = top[1], a2 = top[2], a3 = top[3],
+ l0 = left[0], l1 = left[1], l2 = left[2];
+
+ DST(0,3) = (l0 + l1 * 2 + l2 + 2) >> 2;
+ DST(0,2) = (tl + l0 * 2 + l1 + 2) >> 2;
+ DST(0,0) = DST(1,2) = (tl + a0 + 1) >> 1;
+ DST(0,1) = DST(1,3) = (l0 + tl * 2 + a0 + 2) >> 2;
+ DST(1,0) = DST(2,2) = (a0 + a1 + 1) >> 1;
+ DST(1,1) = DST(2,3) = (tl + a0 * 2 + a1 + 2) >> 2;
+ DST(2,0) = DST(3,2) = (a1 + a2 + 1) >> 1;
+ DST(2,1) = DST(3,3) = (a0 + a1 * 2 + a2 + 2) >> 2;
+ DST(3,0) = (a2 + a3 + 1) >> 1;
+ DST(3,1) = (a1 + a2 * 2 + a3 + 2) >> 2;
+}
+
+#define def_vert_right(size) \
+static void vert_right_##size##x##size##_c(uint8_t *dst, ptrdiff_t stride, \
+ const uint8_t *left, const uint8_t *top) \
+{ \
+ int i, j; \
+ uint8_t ve[size + size/2 - 1], vo[size + size/2 - 1]; \
+\
+ for (i = 0; i < size/2 - 2; i++) { \
+ vo[i] = (left[size - 4 - i*2] + left[size - 3 - i*2] * 2 + left[size - 2 - i*2] + 2) >> 2; \
+ ve[i] = (left[size - 5 - i*2] + left[size - 4 - i*2] * 2 + left[size - 3 - i*2] + 2) >> 2; \
+ } \
+ vo[size/2 - 2] = (left[0] + left[1] * 2 + left[2] + 2) >> 2; \
+ ve[size/2 - 2] = (top[-1] + left[0] * 2 + left[1] + 2) >> 2; \
+\
+ ve[size/2 - 1] = (top[-1] + top[0] + 1) >> 1; \
+ vo[size/2 - 1] = (left[0] + top[-1] * 2 + top[0] + 2) >> 2; \
+ for (i = 0; i < size - 1; i++) { \
+ ve[size/2 + i] = (top[i] + top[i + 1] + 1) >> 1; \
+ vo[size/2 + i] = (top[i - 1] + top[i] * 2 + top[i + 1] + 2) >> 2; \
+ } \
+\
+ for (j = 0; j < size / 2; j++) { \
+ memcpy(dst + j*2 *stride, ve + size/2 - 1 - j, size); \
+ memcpy(dst + (j*2 + 1)*stride, vo + size/2 - 1 - j, size); \
+ } \
+}
+
+def_vert_right(8)
+def_vert_right(16)
+def_vert_right(32)
+
+static void hor_down_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int l0 = left[0], l1 = left[1], l2 = left[2], l3 = left[3],
+ tl = top[-1], a0 = top[0], a1 = top[1], a2 = top[2];
+
+ DST(2,0) = (tl + a0 * 2 + a1 + 2) >> 2;
+ DST(3,0) = (a0 + a1 * 2 + a2 + 2) >> 2;
+ DST(0,0) = DST(2,1) = (tl + l0 + 1) >> 1;
+ DST(1,0) = DST(3,1) = (a0 + tl * 2 + l0 + 2) >> 2;
+ DST(0,1) = DST(2,2) = (l0 + l1 + 1) >> 1;
+ DST(1,1) = DST(3,2) = (tl + l0 * 2 + l1 + 2) >> 2;
+ DST(0,2) = DST(2,3) = (l1 + l2 + 1) >> 1;
+ DST(1,2) = DST(3,3) = (l0 + l1 * 2 + l2 + 2) >> 2;
+ DST(0,3) = (l2 + l3 + 1) >> 1;
+ DST(1,3) = (l1 + l2 * 2 + l3 + 2) >> 2;
+}
+
+#define def_hor_down(size) \
+static void hor_down_##size##x##size##_c(uint8_t *dst, ptrdiff_t stride, \
+ const uint8_t *left, const uint8_t *top) \
+{ \
+ int i, j; \
+ uint8_t v[size * 3 - 2]; \
+\
+ for (i = 0; i < size - 2; i++) { \
+ v[i*2 ] = (left[size - 2 - i] + left[size - 1 - i] + 1) >> 1; \
+ v[i*2 + 1] = (left[size - 3 - i] + left[size - 2 - i] * 2 + left[size - 1 - i] + 2) >> 2; \
+ v[size*2 + i] = (top[i - 1] + top[i] * 2 + top[i + 1] + 2) >> 2; \
+ } \
+ v[size*2 - 2] = (top[-1] + left[0] + 1) >> 1; \
+ v[size*2 - 4] = (left[0] + left[1] + 1) >> 1; \
+ v[size*2 - 1] = (top[0] + top[-1] * 2 + left[0] + 2) >> 2; \
+ v[size*2 - 3] = (top[-1] + left[0] * 2 + left[1] + 2) >> 2; \
+\
+ for (j = 0; j < size; j++) \
+ memcpy(dst + j*stride, v + size*2 - 2 - j*2, size); \
+}
+
+def_hor_down(8)
+def_hor_down(16)
+def_hor_down(32)
+
+static void vert_left_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int a0 = top[0], a1 = top[1], a2 = top[2], a3 = top[3],
+ a4 = top[4], a5 = top[5], a6 = top[6];
+
+ DST(0,0) = (a0 + a1 + 1) >> 1;
+ DST(0,1) = (a0 + a1 * 2 + a2 + 2) >> 2;
+ DST(1,0) = DST(0,2) = (a1 + a2 + 1) >> 1;
+ DST(1,1) = DST(0,3) = (a1 + a2 * 2 + a3 + 2) >> 2;
+ DST(2,0) = DST(1,2) = (a2 + a3 + 1) >> 1;
+ DST(2,1) = DST(1,3) = (a2 + a3 * 2 + a4 + 2) >> 2;
+ DST(3,0) = DST(2,2) = (a3 + a4 + 1) >> 1;
+ DST(3,1) = DST(2,3) = (a3 + a4 * 2 + a5 + 2) >> 2;
+ DST(3,2) = (a4 + a5 + 1) >> 1;
+ DST(3,3) = (a4 + a5 * 2 + a6 + 2) >> 2;
+}
+
+#define def_vert_left(size) \
+static void vert_left_##size##x##size##_c(uint8_t *dst, ptrdiff_t stride, \
+ const uint8_t *left, const uint8_t *top) \
+{ \
+ int i, j; \
+ uint8_t ve[size - 1], vo[size - 1]; \
+\
+ for (i = 0; i < size - 2; i++) { \
+ ve[i] = (top[i] + top[i + 1] + 1) >> 1; \
+ vo[i] = (top[i] + top[i + 1] * 2 + top[i + 2] + 2) >> 2; \
+ } \
+ ve[size - 2] = (top[size - 2] + top[size - 1] + 1) >> 1; \
+ vo[size - 2] = (top[size - 2] + top[size - 1] * 3 + 2) >> 2; \
+\
+ for (j = 0; j < size / 2; j++) { \
+ memcpy(dst + j*2 * stride, ve + j, size - j - 1); \
+ memset(dst + j*2 * stride + size - j - 1, top[size - 1], j + 1); \
+ memcpy(dst + (j*2 + 1) * stride, vo + j, size - j - 1); \
+ memset(dst + (j*2 + 1) * stride + size - j - 1, top[size - 1], j + 1); \
+ } \
+}
+
+def_vert_left(8)
+def_vert_left(16)
+def_vert_left(32)
+
+static void hor_up_4x4_c(uint8_t *dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ int l0 = left[0], l1 = left[1], l2 = left[2], l3 = left[3];
+
+ DST(0,0) = (l0 + l1 + 1) >> 1;
+ DST(1,0) = (l0 + l1 * 2 + l2 + 2) >> 2;
+ DST(0,1) = DST(2,0) = (l1 + l2 + 1) >> 1;
+ DST(1,1) = DST(3,0) = (l1 + l2 * 2 + l3 + 2) >> 2;
+ DST(0,2) = DST(2,1) = (l2 + l3 + 1) >> 1;
+ DST(1,2) = DST(3,1) = (l2 + l3 * 3 + 2) >> 2;
+ DST(0,3) = DST(1,3) = DST(2,2) = DST(2,3) = DST(3,2) = DST(3,3) = l3;
+}
+
+#define def_hor_up(size) \
+static void hor_up_##size##x##size##_c(uint8_t *dst, ptrdiff_t stride, \
+ const uint8_t *left, const uint8_t *top) \
+{ \
+ int i, j; \
+ uint8_t v[size*2 - 2]; \
+\
+ for (i = 0; i < size - 2; i++) { \
+ v[i*2 ] = (left[i] + left[i + 1] + 1) >> 1; \
+ v[i*2 + 1] = (left[i] + left[i + 1] * 2 + left[i + 2] + 2) >> 2; \
+ } \
+ v[size*2 - 4] = (left[size - 2] + left[size - 1] + 1) >> 1; \
+ v[size*2 - 3] = (left[size - 2] + left[size - 1] * 3 + 2) >> 2; \
+\
+ for (j = 0; j < size / 2; j++) \
+ memcpy(dst + j*stride, v + j*2, size); \
+ for (j = size / 2; j < size; j++) { \
+ memcpy(dst + j*stride, v + j*2, size*2 - 2 - j*2); \
+ memset(dst + j*stride + size*2 - 2 - j*2, left[size - 1], \
+ 2 + j*2 - size); \
+ } \
+}
+
+def_hor_up(8)
+def_hor_up(16)
+def_hor_up(32)
+
+#undef DST
+
+static av_cold void vp9dsp_intrapred_init(VP9DSPContext *dsp)
+{
+#define init_intra_pred(tx, sz) \
+ dsp->intra_pred[tx][VERT_PRED] = vert_##sz##_c; \
+ dsp->intra_pred[tx][HOR_PRED] = hor_##sz##_c; \
+ dsp->intra_pred[tx][DC_PRED] = dc_##sz##_c; \
+ dsp->intra_pred[tx][DIAG_DOWN_LEFT_PRED] = diag_downleft_##sz##_c; \
+ dsp->intra_pred[tx][DIAG_DOWN_RIGHT_PRED] = diag_downright_##sz##_c; \
+ dsp->intra_pred[tx][VERT_RIGHT_PRED] = vert_right_##sz##_c; \
+ dsp->intra_pred[tx][HOR_DOWN_PRED] = hor_down_##sz##_c; \
+ dsp->intra_pred[tx][VERT_LEFT_PRED] = vert_left_##sz##_c; \
+ dsp->intra_pred[tx][HOR_UP_PRED] = hor_up_##sz##_c; \
+ dsp->intra_pred[tx][TM_VP8_PRED] = tm_##sz##_c; \
+ dsp->intra_pred[tx][LEFT_DC_PRED] = dc_left_##sz##_c; \
+ dsp->intra_pred[tx][TOP_DC_PRED] = dc_top_##sz##_c; \
+ dsp->intra_pred[tx][DC_128_PRED] = dc_128_##sz##_c; \
+ dsp->intra_pred[tx][DC_127_PRED] = dc_127_##sz##_c; \
+ dsp->intra_pred[tx][DC_129_PRED] = dc_129_##sz##_c
+
+ init_intra_pred(TX_4X4, 4x4);
+ init_intra_pred(TX_8X8, 8x8);
+ init_intra_pred(TX_16X16, 16x16);
+ init_intra_pred(TX_32X32, 32x32);
+
+#undef init_intra_pred
+}
+
+#define itxfm_wrapper(type_a, type_b, sz, bits) \
+static void type_a##_##type_b##_##sz##x##sz##_add_c(uint8_t *dst, \
+ ptrdiff_t stride, \
+ int16_t *block, int eob) \
+{ \
+ int i, j; \
+ int16_t tmp[sz * sz], out[sz]; \
+ for (i = 0; i < sz; i++) \
+ type_a##sz##_1d(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) \
+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(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;
+
+ out[0] = t0 + t3;
+ out[1] = t1 + t2;
+ out[2] = t1 - t2;
+ out[3] = t0 - t3;
+}
+
+static av_always_inline void iadst4_1d(const int16_t *in, ptrdiff_t stride,
+ int16_t *out, int pass)
+{
+ int t0, t1, t2, t3;
+
+ t0 = 5283 * IN(0) + 15212 * IN(2) + 9929 * IN(3);
+ t1 = 9929 * IN(0) - 5283 * IN(2) - 15212 * IN(3);
+ t2 = 13377 * (IN(0) - IN(2) + IN(3));
+ t3 = 13377 * IN(1);
+
+ out[0] = (t0 + t3 + (1 << 13)) >> 14;
+ out[1] = (t1 + t3 + (1 << 13)) >> 14;
+ out[2] = (t2 + (1 << 13)) >> 14;
+ out[3] = (t0 + t1 - t3 + (1 << 13)) >> 14;
+}
+
+itxfm_wrap(4, 4)
+
+static av_always_inline void idct8_1d(const 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;
+
+ t0 = t0a + t3a;
+ t1 = t1a + t2a;
+ t2 = t1a - t2a;
+ t3 = t0a - t3a;
+ t4 = t4a + t5a;
+ t5a = t4a - t5a;
+ t7 = t7a + t6a;
+ t6a = t7a - t6a;
+
+ t5 = ((t6a - t5a) * 11585 + (1 << 13)) >> 14;
+ t6 = ((t6a + t5a) * 11585 + (1 << 13)) >> 14;
+
+ out[0] = t0 + t7;
+ out[1] = t1 + t6;
+ out[2] = t2 + t5;
+ out[3] = t3 + t4;
+ out[4] = t3 - t4;
+ out[5] = t2 - t5;
+ out[6] = t1 - t6;
+ out[7] = t0 - t7;
+}
+
+static av_always_inline void iadst8_1d(const 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 = 16305 * IN(7) + 1606 * IN(0);
+ t1a = 1606 * IN(7) - 16305 * IN(0);
+ t2a = 14449 * IN(5) + 7723 * IN(2);
+ t3a = 7723 * IN(5) - 14449 * IN(2);
+ t4a = 10394 * IN(3) + 12665 * IN(4);
+ t5a = 12665 * IN(3) - 10394 * IN(4);
+ t6a = 4756 * IN(1) + 15679 * IN(6);
+ t7a = 15679 * IN(1) - 4756 * IN(6);
+
+ t0 = (t0a + t4a + (1 << 13)) >> 14;
+ t1 = (t1a + t5a + (1 << 13)) >> 14;
+ t2 = (t2a + t6a + (1 << 13)) >> 14;
+ t3 = (t3a + t7a + (1 << 13)) >> 14;
+ t4 = (t0a - t4a + (1 << 13)) >> 14;
+ t5 = (t1a - t5a + (1 << 13)) >> 14;
+ t6 = (t2a - t6a + (1 << 13)) >> 14;
+ t7 = (t3a - t7a + (1 << 13)) >> 14;
+
+ t4a = 15137 * t4 + 6270 * t5;
+ t5a = 6270 * t4 - 15137 * t5;
+ t6a = 15137 * t7 - 6270 * t6;
+ t7a = 6270 * t7 + 15137 * t6;
+
+ out[0] = t0 + t2;
+ out[7] = -(t1 + t3);
+ t2 = t0 - t2;
+ t3 = t1 - t3;
+
+ out[1] = -((t4a + t6a + (1 << 13)) >> 14);
+ out[6] = (t5a + t7a + (1 << 13)) >> 14;
+ t6 = (t4a - t6a + (1 << 13)) >> 14;
+ t7 = (t5a - t7a + (1 << 13)) >> 14;
+
+ out[3] = -(((t2 + t3) * 11585 + (1 << 13)) >> 14);
+ out[4] = ((t2 - t3) * 11585 + (1 << 13)) >> 14;
+ out[2] = ((t6 + t7) * 11585 + (1 << 13)) >> 14;
+ out[5] = -(((t6 - t7) * 11585 + (1 << 13)) >> 14);
+}
+
+itxfm_wrap(8, 5)
+
+static av_always_inline void idct16_1d(const 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;
+ t2a = (IN(4) * 6270 - IN(12) * 15137 + (1 << 13)) >> 14;
+ t3a = (IN(4) * 15137 + IN(12) * 6270 + (1 << 13)) >> 14;
+ t4a = (IN(2) * 3196 - IN(14) * 16069 + (1 << 13)) >> 14;
+ t7a = (IN(2) * 16069 + IN(14) * 3196 + (1 << 13)) >> 14;
+ t5a = (IN(10) * 13623 - IN(6) * 9102 + (1 << 13)) >> 14;
+ t6a = (IN(10) * 9102 + IN(6) * 13623 + (1 << 13)) >> 14;
+ t8a = (IN(1) * 1606 - IN(15) * 16305 + (1 << 13)) >> 14;
+ t15a = (IN(1) * 16305 + IN(15) * 1606 + (1 << 13)) >> 14;
+ t9a = (IN(9) * 12665 - IN(7) * 10394 + (1 << 13)) >> 14;
+ t14a = (IN(9) * 10394 + IN(7) * 12665 + (1 << 13)) >> 14;
+ t10a = (IN(5) * 7723 - IN(11) * 14449 + (1 << 13)) >> 14;
+ t13a = (IN(5) * 14449 + IN(11) * 7723 + (1 << 13)) >> 14;
+ t11a = (IN(13) * 15679 - IN(3) * 4756 + (1 << 13)) >> 14;
+ t12a = (IN(13) * 4756 + IN(3) * 15679 + (1 << 13)) >> 14;
+
+ t0 = t0a + t3a;
+ t1 = t1a + t2a;
+ t2 = t1a - t2a;
+ t3 = t0a - t3a;
+ t4 = t4a + t5a;
+ t5 = t4a - t5a;
+ t6 = t7a - t6a;
+ t7 = t7a + t6a;
+ t8 = t8a + t9a;
+ t9 = t8a - t9a;
+ t10 = t11a - t10a;
+ t11 = t11a + t10a;
+ t12 = t12a + t13a;
+ t13 = t12a - t13a;
+ t14 = t15a - t14a;
+ t15 = t15a + t14a;
+
+ t5a = ((t6 - t5) * 11585 + (1 << 13)) >> 14;
+ t6a = ((t6 + t5) * 11585 + (1 << 13)) >> 14;
+ t9a = ( t14 * 6270 - t9 * 15137 + (1 << 13)) >> 14;
+ t14a = ( t14 * 15137 + t9 * 6270 + (1 << 13)) >> 14;
+ t10a = (-(t13 * 15137 + t10 * 6270) + (1 << 13)) >> 14;
+ t13a = ( t13 * 6270 - t10 * 15137 + (1 << 13)) >> 14;
+
+ t0a = t0 + t7;
+ t1a = t1 + t6a;
+ t2a = t2 + t5a;
+ t3a = t3 + t4;
+ t4 = t3 - t4;
+ t5 = t2 - t5a;
+ t6 = t1 - t6a;
+ t7 = t0 - t7;
+ t8a = t8 + t11;
+ t9 = t9a + t10a;
+ t10 = t9a - t10a;
+ t11a = t8 - t11;
+ t12a = t15 - t12;
+ t13 = t14a - t13a;
+ t14 = t14a + t13a;
+ t15a = t15 + t12;
+
+ t10a = ((t13 - t10) * 11585 + (1 << 13)) >> 14;
+ t13a = ((t13 + t10) * 11585 + (1 << 13)) >> 14;
+ t11 = ((t12a - t11a) * 11585 + (1 << 13)) >> 14;
+ t12 = ((t12a + t11a) * 11585 + (1 << 13)) >> 14;
+
+ out[ 0] = t0a + t15a;
+ out[ 1] = t1a + t14;
+ out[ 2] = t2a + t13a;
+ out[ 3] = t3a + t12;
+ out[ 4] = t4 + t11;
+ out[ 5] = t5 + t10a;
+ out[ 6] = t6 + t9;
+ out[ 7] = t7 + t8a;
+ out[ 8] = t7 - t8a;
+ out[ 9] = t6 - t9;
+ out[10] = t5 - t10a;
+ out[11] = t4 - t11;
+ out[12] = t3a - t12;
+ out[13] = t2a - t13a;
+ out[14] = t1a - t14;
+ out[15] = t0a - t15a;
+}
+
+static av_always_inline void iadst16_1d(const 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;
+
+ t0 = IN(15) * 16364 + IN(0) * 804;
+ t1 = IN(15) * 804 - IN(0) * 16364;
+ t2 = IN(13) * 15893 + IN(2) * 3981;
+ t3 = IN(13) * 3981 - IN(2) * 15893;
+ t4 = IN(11) * 14811 + IN(4) * 7005;
+ t5 = IN(11) * 7005 - IN(4) * 14811;
+ t6 = IN(9) * 13160 + IN(6) * 9760;
+ t7 = IN(9) * 9760 - IN(6) * 13160;
+ t8 = IN(7) * 11003 + IN(8) * 12140;
+ t9 = IN(7) * 12140 - IN(8) * 11003;
+ t10 = IN(5) * 8423 + IN(10) * 14053;
+ t11 = IN(5) * 14053 - IN(10) * 8423;
+ t12 = IN(3) * 5520 + IN(12) * 15426;
+ t13 = IN(3) * 15426 - IN(12) * 5520;
+ t14 = IN(1) * 2404 + IN(14) * 16207;
+ t15 = IN(1) * 16207 - IN(14) * 2404;
+
+ t0a = (t0 + t8 + (1 << 13)) >> 14;
+ t1a = (t1 + t9 + (1 << 13)) >> 14;
+ t2a = (t2 + t10 + (1 << 13)) >> 14;
+ t3a = (t3 + t11 + (1 << 13)) >> 14;
+ t4a = (t4 + t12 + (1 << 13)) >> 14;
+ t5a = (t5 + t13 + (1 << 13)) >> 14;
+ t6a = (t6 + t14 + (1 << 13)) >> 14;
+ t7a = (t7 + t15 + (1 << 13)) >> 14;
+ t8a = (t0 - t8 + (1 << 13)) >> 14;
+ t9a = (t1 - t9 + (1 << 13)) >> 14;
+ t10a = (t2 - t10 + (1 << 13)) >> 14;
+ t11a = (t3 - t11 + (1 << 13)) >> 14;
+ t12a = (t4 - t12 + (1 << 13)) >> 14;
+ t13a = (t5 - t13 + (1 << 13)) >> 14;
+ t14a = (t6 - t14 + (1 << 13)) >> 14;
+ t15a = (t7 - t15 + (1 << 13)) >> 14;
+
+ t8 = t8a * 16069 + t9a * 3196;
+ t9 = t8a * 3196 - t9a * 16069;
+ t10 = t10a * 9102 + t11a * 13623;
+ t11 = t10a * 13623 - t11a * 9102;
+ t12 = t13a * 16069 - t12a * 3196;
+ t13 = t13a * 3196 + t12a * 16069;
+ t14 = t15a * 9102 - t14a * 13623;
+ t15 = t15a * 13623 + t14a * 9102;
+
+ t0 = t0a + t4a;
+ t1 = t1a + t5a;
+ t2 = t2a + t6a;
+ t3 = t3a + t7a;
+ t4 = t0a - t4a;
+ t5 = t1a - t5a;
+ t6 = t2a - t6a;
+ t7 = t3a - t7a;
+ t8a = (t8 + t12 + (1 << 13)) >> 14;
+ t9a = (t9 + t13 + (1 << 13)) >> 14;
+ t10a = (t10 + t14 + (1 << 13)) >> 14;
+ t11a = (t11 + t15 + (1 << 13)) >> 14;
+ t12a = (t8 - t12 + (1 << 13)) >> 14;
+ t13a = (t9 - t13 + (1 << 13)) >> 14;
+ t14a = (t10 - t14 + (1 << 13)) >> 14;
+ t15a = (t11 - t15 + (1 << 13)) >> 14;
+
+ t4a = t4 * 15137 + t5 * 6270;
+ t5a = t4 * 6270 - t5 * 15137;
+ t6a = t7 * 15137 - t6 * 6270;
+ t7a = t7 * 6270 + t6 * 15137;
+ t12 = t12a * 15137 + t13a * 6270;
+ t13 = t12a * 6270 - t13a * 15137;
+ t14 = t15a * 15137 - t14a * 6270;
+ t15 = t15a * 6270 + t14a * 15137;
+
+ out[ 0] = t0 + t2;
+ out[15] = -(t1 + t3);
+ t2a = t0 - t2;
+ t3a = t1 - t3;
+ out[ 3] = -((t4a + t6a + (1 << 13)) >> 14);
+ out[12] = (t5a + t7a + (1 << 13)) >> 14;
+ t6 = (t4a - t6a + (1 << 13)) >> 14;
+ t7 = (t5a - t7a + (1 << 13)) >> 14;
+ out[ 1] = -(t8a + t10a);
+ out[14] = t9a + t11a;
+ t10 = t8a - t10a;
+ t11 = t9a - t11a;
+ out[ 2] = (t12 + t14 + (1 << 13)) >> 14;
+ out[13] = -((t13 + t15 + (1 << 13)) >> 14);
+ t14a = (t12 - t14 + (1 << 13)) >> 14;
+ t15a = (t13 - t15 + (1 << 13)) >> 14;
+
+ out[ 7] = ((t2a + t3a) * -11585 + (1 << 13)) >> 14;
+ out[ 8] = ((t2a - t3a) * 11585 + (1 << 13)) >> 14;
+ out[ 4] = ((t7 + t6) * 11585 + (1 << 13)) >> 14;
+ out[11] = ((t7 - t6) * 11585 + (1 << 13)) >> 14;
+ out[ 6] = ((t11 + t10) * 11585 + (1 << 13)) >> 14;
+ out[ 9] = ((t11 - t10) * 11585 + (1 << 13)) >> 14;
+ out[ 5] = ((t14a + t15a) * -11585 + (1 << 13)) >> 14;
+ out[10] = ((t14a - t15a) * 11585 + (1 << 13)) >> 14;
+}
+
+itxfm_wrap(16, 6)
+
+static av_always_inline void idct32_1d(const 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 t0 = t0a + t3a;
+ int t1 = t1a + t2a;
+ int t2 = t1a - t2a;
+ int t3 = t0a - t3a;
+ int t4 = t4a + t5a;
+ int t5 = t4a - t5a;
+ int t6 = t7a - t6a;
+ int t7 = t7a + t6a;
+ int t8 = t8a + t9a;
+ int t9 = t8a - t9a;
+ int t10 = t11a - t10a;
+ int t11 = t11a + t10a;
+ int t12 = t12a + t13a;
+ int t13 = t12a - t13a;
+ int t14 = t15a - t14a;
+ int t15 = t15a + t14a;
+ int t16 = t16a + t17a;
+ int t17 = t16a - t17a;
+ int t18 = t19a - t18a;
+ int t19 = t19a + t18a;
+ int t20 = t20a + t21a;
+ int t21 = t20a - t21a;
+ int t22 = t23a - t22a;
+ int t23 = t23a + t22a;
+ int t24 = t24a + t25a;
+ int t25 = t24a - t25a;
+ int t26 = t27a - t26a;
+ int t27 = t27a + t26a;
+ int t28 = t28a + t29a;
+ int t29 = t28a - t29a;
+ int t30 = t31a - t30a;
+ int t31 = t31a + t30a;
+
+ t5a = ((t6 - t5) * 11585 + (1 << 13)) >> 14;
+ t6a = ((t6 + t5) * 11585 + (1 << 13)) >> 14;
+ t9a = ( t14 * 6270 - t9 * 15137 + (1 << 13)) >> 14;
+ t14a = ( t14 * 15137 + t9 * 6270 + (1 << 13)) >> 14;
+ t10a = (-(t13 * 15137 + t10 * 6270) + (1 << 13)) >> 14;
+ t13a = ( t13 * 6270 - t10 * 15137 + (1 << 13)) >> 14;
+ t17a = ( t30 * 3196 - t17 * 16069 + (1 << 13)) >> 14;
+ t30a = ( t30 * 16069 + t17 * 3196 + (1 << 13)) >> 14;
+ t18a = (-(t29 * 16069 + t18 * 3196) + (1 << 13)) >> 14;
+ t29a = ( t29 * 3196 - t18 * 16069 + (1 << 13)) >> 14;
+ t21a = ( t26 * 13623 - t21 * 9102 + (1 << 13)) >> 14;
+ t26a = ( t26 * 9102 + t21 * 13623 + (1 << 13)) >> 14;
+ t22a = (-(t25 * 9102 + t22 * 13623) + (1 << 13)) >> 14;
+ t25a = ( t25 * 13623 - t22 * 9102 + (1 << 13)) >> 14;
+
+ t0a = t0 + t7;
+ t1a = t1 + t6a;
+ t2a = t2 + t5a;
+ t3a = t3 + t4;
+ t4a = t3 - t4;
+ t5 = t2 - t5a;
+ t6 = t1 - t6a;
+ t7a = t0 - t7;
+ t8a = t8 + t11;
+ t9 = t9a + t10a;
+ t10 = t9a - t10a;
+ t11a = t8 - t11;
+ t12a = t15 - t12;
+ t13 = t14a - t13a;
+ t14 = t14a + t13a;
+ t15a = t15 + t12;
+ t16a = t16 + t19;
+ t17 = t17a + t18a;
+ t18 = t17a - t18a;
+ t19a = t16 - t19;
+ t20a = t23 - t20;
+ t21 = t22a - t21a;
+ t22 = t22a + t21a;
+ t23a = t23 + t20;
+ t24a = t24 + t27;
+ t25 = t25a + t26a;
+ t26 = t25a - t26a;
+ t27a = t24 - t27;
+ t28a = t31 - t28;
+ t29 = t30a - t29a;
+ t30 = t30a + t29a;
+ t31a = t31 + t28;
+
+ t10a = ((t13 - t10) * 11585 + (1 << 13)) >> 14;
+ t13a = ((t13 + t10) * 11585 + (1 << 13)) >> 14;
+ t11 = ((t12a - t11a) * 11585 + (1 << 13)) >> 14;
+ t12 = ((t12a + t11a) * 11585 + (1 << 13)) >> 14;
+ t18a = ( t29 * 6270 - t18 * 15137 + (1 << 13)) >> 14;
+ t29a = ( t29 * 15137 + t18 * 6270 + (1 << 13)) >> 14;
+ t19 = ( t28a * 6270 - t19a * 15137 + (1 << 13)) >> 14;
+ t28 = ( t28a * 15137 + t19a * 6270 + (1 << 13)) >> 14;
+ t20 = (-(t27a * 15137 + t20a * 6270) + (1 << 13)) >> 14;
+ t27 = ( t27a * 6270 - t20a * 15137 + (1 << 13)) >> 14;
+ t21a = (-(t26 * 15137 + t21 * 6270) + (1 << 13)) >> 14;
+ t26a = ( t26 * 6270 - t21 * 15137 + (1 << 13)) >> 14;
+
+ t0 = t0a + t15a;
+ t1 = t1a + t14;
+ t2 = t2a + t13a;
+ t3 = t3a + t12;
+ t4 = t4a + t11;
+ t5a = t5 + t10a;
+ t6a = t6 + t9;
+ t7 = t7a + t8a;
+ t8 = t7a - t8a;
+ t9a = t6 - t9;
+ t10 = t5 - t10a;
+ t11a = t4a - t11;
+ t12a = t3a - t12;
+ t13 = t2a - t13a;
+ t14a = t1a - t14;
+ t15 = t0a - t15a;
+ t16 = t16a + t23a;
+ t17a = t17 + t22;
+ t18 = t18a + t21a;
+ t19a = t19 + t20;
+ t20a = t19 - t20;
+ t21 = t18a - t21a;
+ t22a = t17 - t22;
+ t23 = t16a - t23a;
+ t24 = t31a - t24a;
+ t25a = t30 - t25;
+ t26 = t29a - t26a;
+ t27a = t28 - t27;
+ t28a = t28 + t27;
+ t29 = t29a + t26a;
+ t30a = t30 + t25;
+ t31 = t31a + t24a;
+
+ t20 = ((t27a - t20a) * 11585 + (1 << 13)) >> 14;
+ t27 = ((t27a + t20a) * 11585 + (1 << 13)) >> 14;
+ t21a = ((t26 - t21 ) * 11585 + (1 << 13)) >> 14;
+ t26a = ((t26 + t21 ) * 11585 + (1 << 13)) >> 14;
+ t22 = ((t25a - t22a) * 11585 + (1 << 13)) >> 14;
+ t25 = ((t25a + t22a) * 11585 + (1 << 13)) >> 14;
+ t23a = ((t24 - t23 ) * 11585 + (1 << 13)) >> 14;
+ t24a = ((t24 + t23 ) * 11585 + (1 << 13)) >> 14;
+
+ out[ 0] = t0 + t31;
+ out[ 1] = t1 + t30a;
+ out[ 2] = t2 + t29;
+ out[ 3] = t3 + t28a;
+ out[ 4] = t4 + t27;
+ out[ 5] = t5a + t26a;
+ out[ 6] = t6a + t25;
+ out[ 7] = t7 + t24a;
+ out[ 8] = t8 + t23a;
+ out[ 9] = t9a + t22;
+ out[10] = t10 + t21a;
+ out[11] = t11a + t20;
+ out[12] = t12a + t19a;
+ out[13] = t13 + t18;
+ out[14] = t14a + t17a;
+ out[15] = t15 + t16;
+ out[16] = t15 - t16;
+ out[17] = t14a - t17a;
+ out[18] = t13 - t18;
+ out[19] = t12a - t19a;
+ out[20] = t11a - t20;
+ out[21] = t10 - t21a;
+ out[22] = t9a - t22;
+ out[23] = t8 - t23a;
+ out[24] = t7 - t24a;
+ out[25] = t6a - t25;
+ out[26] = t5a - t26a;
+ out[27] = t4 - t27;
+ out[28] = t3 - t28a;
+ out[29] = t2 - t29;
+ out[30] = t1 - t30a;
+ out[31] = t0 - t31;
+}
+
+itxfm_wrapper(idct, idct, 32, 6)
+
+static av_always_inline void iwht4_1d(const int16_t *in, ptrdiff_t stride,
+ int16_t *out, int pass)
+{
+ int t0, t1, t2, t3, t4;
+
+ if (pass == 0) {
+ t0 = IN(0) >> 2;
+ t1 = IN(3) >> 2;
+ t2 = IN(1) >> 2;
+ t3 = IN(2) >> 2;
+ } else {
+ t0 = IN(0);
+ t1 = IN(3);
+ t2 = IN(1);
+ t3 = IN(2);
+ }
+
+ t0 += t2;
+ t3 -= t1;
+ t4 = (t0 - t3) >> 1;
+ t1 = t4 - t1;
+ t2 = t4 - t2;
+ t0 -= t1;
+ t3 += t2;
+
+ out[0] = t0;
+ out[1] = t1;
+ out[2] = t2;
+ out[3] = t3;
+}
+
+itxfm_wrapper(iwht, iwht, 4, 0)
+
+#undef IN
+#undef itxfm_wrapper
+#undef itxfm_wrap
+
+static av_cold void vp9dsp_itxfm_init(VP9DSPContext *dsp)
+{
+#define init_itxfm(tx, sz) \
+ dsp->itxfm_add[tx][DCT_DCT] = idct_idct_##sz##_add_c; \
+ dsp->itxfm_add[tx][DCT_ADST] = iadst_idct_##sz##_add_c; \
+ dsp->itxfm_add[tx][ADST_DCT] = idct_iadst_##sz##_add_c; \
+ dsp->itxfm_add[tx][ADST_ADST] = iadst_iadst_##sz##_add_c
+
+#define init_idct(tx, nm) \
+ dsp->itxfm_add[tx][DCT_DCT] = \
+ dsp->itxfm_add[tx][ADST_DCT] = \
+ dsp->itxfm_add[tx][DCT_ADST] = \
+ dsp->itxfm_add[tx][ADST_ADST] = nm##_add_c
+
+ init_itxfm(TX_4X4, 4x4);
+ init_itxfm(TX_8X8, 8x8);
+ init_itxfm(TX_16X16, 16x16);
+ init_idct(TX_32X32, idct_idct_32x32);
+ init_idct(4 /* lossless */, iwht_iwht_4x4);
+
+#undef init_itxfm
+#undef init_idct
+}
+
+static av_always_inline void loop_filter(uint8_t *dst, ptrdiff_t stride,
+ int E, int I, int H,
+ ptrdiff_t stridea, ptrdiff_t strideb,
+ int wd)
+{
+ int i;
+
+ for (i = 0; i < 8; i++, dst += stridea) {
+ int p7, p6, p5, p4;
+ int p3 = dst[strideb * -4], p2 = dst[strideb * -3];
+ int p1 = dst[strideb * -2], p0 = dst[strideb * -1];
+ int q0 = dst[strideb * +0], q1 = dst[strideb * +1];
+ int q2 = dst[strideb * +2], q3 = dst[strideb * +3];
+ int q4, q5, q6, q7;
+ int fm = FFABS(p3 - p2) <= I && FFABS(p2 - p1) <= I &&
+ FFABS(p1 - p0) <= I && FFABS(q1 - q0) <= I &&
+ FFABS(q2 - q1) <= I && FFABS(q3 - q2) <= I &&
+ FFABS(p0 - q0) * 2 + (FFABS(p1 - q1) >> 1) <= E;
+ int flat8out, flat8in;
+
+ if (!fm)
+ continue;
+
+ if (wd >= 16) {
+ p7 = dst[strideb * -8];
+ p6 = dst[strideb * -7];
+ p5 = dst[strideb * -6];
+ p4 = dst[strideb * -5];
+ q4 = dst[strideb * +4];
+ q5 = dst[strideb * +5];
+ q6 = dst[strideb * +6];
+ q7 = dst[strideb * +7];
+
+ flat8out = FFABS(p7 - p0) <= 1 && FFABS(p6 - p0) <= 1 &&
+ FFABS(p5 - p0) <= 1 && FFABS(p4 - p0) <= 1 &&
+ FFABS(q4 - q0) <= 1 && FFABS(q5 - q0) <= 1 &&
+ FFABS(q6 - q0) <= 1 && FFABS(q7 - q0) <= 1;
+ }
+
+ if (wd >= 8)
+ flat8in = FFABS(p3 - p0) <= 1 && FFABS(p2 - p0) <= 1 &&
+ FFABS(p1 - p0) <= 1 && FFABS(q1 - q0) <= 1 &&
+ FFABS(q2 - q0) <= 1 && FFABS(q3 - q0) <= 1;
+
+ if (wd >= 16 && flat8out && flat8in) {
+ dst[strideb * -7] = (p7 + p7 + p7 + p7 + p7 + p7 + p7 + p6 * 2 +
+ p5 + p4 + p3 + p2 + p1 + p0 + q0 + 8) >> 4;
+ dst[strideb * -6] = (p7 + p7 + p7 + p7 + p7 + p7 + p6 + p5 * 2 +
+ p4 + p3 + p2 + p1 + p0 + q0 + q1 + 8) >> 4;
+ dst[strideb * -5] = (p7 + p7 + p7 + p7 + p7 + p6 + p5 + p4 * 2 +
+ p3 + p2 + p1 + p0 + q0 + q1 + q2 + 8) >> 4;
+ dst[strideb * -4] = (p7 + p7 + p7 + p7 + p6 + p5 + p4 + p3 * 2 +
+ p2 + p1 + p0 + q0 + q1 + q2 + q3 + 8) >> 4;
+ dst[strideb * -3] = (p7 + p7 + p7 + p6 + p5 + p4 + p3 + p2 * 2 +
+ p1 + p0 + q0 + q1 + q2 + q3 + q4 + 8) >> 4;
+ dst[strideb * -2] = (p7 + p7 + p6 + p5 + p4 + p3 + p2 + p1 * 2 +
+ p0 + q0 + q1 + q2 + q3 + q4 + q5 + 8) >> 4;
+ dst[strideb * -1] = (p7 + p6 + p5 + p4 + p3 + p2 + p1 + p0 * 2 +
+ q0 + q1 + q2 + q3 + q4 + q5 + q6 + 8) >> 4;
+ dst[strideb * +0] = (p6 + p5 + p4 + p3 + p2 + p1 + p0 + q0 * 2 +
+ q1 + q2 + q3 + q4 + q5 + q6 + q7 + 8) >> 4;
+ dst[strideb * +1] = (p5 + p4 + p3 + p2 + p1 + p0 + q0 + q1 * 2 +
+ q2 + q3 + q4 + q5 + q6 + q7 + q7 + 8) >> 4;
+ dst[strideb * +2] = (p4 + p3 + p2 + p1 + p0 + q0 + q1 + q2 * 2 +
+ q3 + q4 + q5 + q6 + q7 + q7 + q7 + 8) >> 4;
+ dst[strideb * +3] = (p3 + p2 + p1 + p0 + q0 + q1 + q2 + q3 * 2 +
+ q4 + q5 + q6 + q7 + q7 + q7 + q7 + 8) >> 4;
+ dst[strideb * +4] = (p2 + p1 + p0 + q0 + q1 + q2 + q3 + q4 * 2 +
+ q5 + q6 + q7 + q7 + q7 + q7 + q7 + 8) >> 4;
+ dst[strideb * +5] = (p1 + p0 + q0 + q1 + q2 + q3 + q4 + q5 * 2 +
+ q6 + q7 + q7 + q7 + q7 + q7 + q7 + 8) >> 4;
+ dst[strideb * +6] = (p0 + q0 + q1 + q2 + q3 + q4 + q5 + q6 * 2 +
+ q7 + q7 + q7 + q7 + q7 + q7 + q7 + 8) >> 4;
+ } else if (wd >= 8 && flat8in) {
+ dst[strideb * -3] = (p3 + p3 + p3 + 2 * p2 + p1 + p0 + q0 + 4) >> 3;
+ dst[strideb * -2] = (p3 + p3 + p2 + 2 * p1 + p0 + q0 + q1 + 4) >> 3;
+ dst[strideb * -1] = (p3 + p2 + p1 + 2 * p0 + q0 + q1 + q2 + 4) >> 3;
+ dst[strideb * +0] = (p2 + p1 + p0 + 2 * q0 + q1 + q2 + q3 + 4) >> 3;
+ dst[strideb * +1] = (p1 + p0 + q0 + 2 * q1 + q2 + q3 + q3 + 4) >> 3;
+ dst[strideb * +2] = (p0 + q0 + q1 + 2 * q2 + q3 + q3 + q3 + 4) >> 3;
+ } else {
+ int hev = FFABS(p1 - p0) > H || FFABS(q1 - q0) > H;
+
+ if (hev) {
+ int f = av_clip_int8(3 * (q0 - p0) + av_clip_int8(p1 - q1)), 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)), 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);
+
+ f = (f1 + 1) >> 1;
+ dst[strideb * -2] = av_clip_uint8(p1 + f);
+ dst[strideb * +1] = av_clip_uint8(q1 - f);
+ }
+ }
+ }
+}
+
+#define lf_8_fn(dir, wd, stridea, strideb) \
+static void loop_filter_##dir##_##wd##_8_c(uint8_t *dst, \
+ ptrdiff_t stride, \
+ int E, int I, int H) \
+{ \
+ loop_filter(dst, stride, E, I, H, stridea, strideb, wd); \
+}
+
+#define lf_8_fns(wd) \
+lf_8_fn(h, wd, stride, 1) \
+lf_8_fn(v, wd, 1, stride)
+
+lf_8_fns(4)
+lf_8_fns(8)
+lf_8_fns(16)
+
+#undef lf_8_fn
+#undef lf_8_fns
+
+#define lf_16_fn(dir, stridea) \
+static void loop_filter_##dir##_16_16_c(uint8_t *dst, \
+ ptrdiff_t stride, \
+ int E, int I, int H) \
+{ \
+ loop_filter_##dir##_16_8_c(dst, stride, E, I, H); \
+ loop_filter_##dir##_16_8_c(dst + 8 * stridea, stride, E, I, H); \
+}
+
+lf_16_fn(h, stride)
+lf_16_fn(v, 1)
+
+#undef lf_16_fn
+
+#define lf_mix_fn(dir, wd1, wd2, stridea) \
+static void loop_filter_##dir##_##wd1##wd2##_16_c(uint8_t *dst, \
+ ptrdiff_t stride, \
+ int E, int I, int H) \
+{ \
+ loop_filter_##dir##_##wd1##_8_c(dst, stride, E & 0xff, I & 0xff, H & 0xff); \
+ loop_filter_##dir##_##wd2##_8_c(dst + 8 * stridea, stride, E >> 8, I >> 8, H >> 8); \
+}
+
+#define lf_mix_fns(wd1, wd2) \
+lf_mix_fn(h, wd1, wd2, stride) \
+lf_mix_fn(v, wd1, wd2, 1)
+
+lf_mix_fns(4, 4)
+lf_mix_fns(4, 8)
+lf_mix_fns(8, 4)
+lf_mix_fns(8, 8)
+
+#undef lf_mix_fn
+#undef lf_mix_fns
+
+static av_cold void vp9dsp_loopfilter_init(VP9DSPContext *dsp)
+{
+ dsp->loop_filter_8[0][0] = loop_filter_h_4_8_c;
+ dsp->loop_filter_8[0][1] = loop_filter_v_4_8_c;
+ dsp->loop_filter_8[1][0] = loop_filter_h_8_8_c;
+ dsp->loop_filter_8[1][1] = loop_filter_v_8_8_c;
+ dsp->loop_filter_8[2][0] = loop_filter_h_16_8_c;
+ dsp->loop_filter_8[2][1] = loop_filter_v_16_8_c;
+
+ dsp->loop_filter_16[0] = loop_filter_h_16_16_c;
+ dsp->loop_filter_16[1] = loop_filter_v_16_16_c;
+
+ dsp->loop_filter_mix2[0][0][0] = loop_filter_h_44_16_c;
+ dsp->loop_filter_mix2[0][0][1] = loop_filter_v_44_16_c;
+ dsp->loop_filter_mix2[0][1][0] = loop_filter_h_48_16_c;
+ dsp->loop_filter_mix2[0][1][1] = loop_filter_v_48_16_c;
+ dsp->loop_filter_mix2[1][0][0] = loop_filter_h_84_16_c;
+ dsp->loop_filter_mix2[1][0][1] = loop_filter_v_84_16_c;
+ dsp->loop_filter_mix2[1][1][0] = loop_filter_h_88_16_c;
+ dsp->loop_filter_mix2[1][1][1] = loop_filter_v_88_16_c;
+}
+
+static av_always_inline void copy_c(uint8_t *dst, ptrdiff_t dst_stride,
+ const uint8_t *src, ptrdiff_t src_stride,
+ int w, int h)
+{
+ do {
+ memcpy(dst, src, w);
+
+ dst += dst_stride;
+ src += src_stride;
+ } while (--h);
+}
+
+static av_always_inline void avg_c(uint8_t *dst, ptrdiff_t dst_stride,
+ const uint8_t *src, ptrdiff_t src_stride,
+ int w, int h)
+{
+ do {
+ int x;
+
+ for (x = 0; x < w; x += 4)
+ AV_WN32A(&dst[x], rnd_avg32(AV_RN32A(&dst[x]), AV_RN32(&src[x])));
+
+ dst += dst_stride;
+ src += src_stride;
+ } while (--h);
+}
+
+#define fpel_fn(type, sz) \
+static void type##sz##_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, int mx, int my) \
+{ \
+ type##_c(dst, dst_stride, src, src_stride, sz, h); \
+}
+
+#define copy_avg_fn(sz) \
+fpel_fn(copy, sz) \
+fpel_fn(avg, sz)
+
+copy_avg_fn(64)
+copy_avg_fn(32)
+copy_avg_fn(16)
+copy_avg_fn(8)
+copy_avg_fn(4)
+
+#undef fpel_fn
+#undef copy_avg_fn
+
+static const int8_t vp9_subpel_filters[3][15][8] = {
+ [FILTER_8TAP_REGULAR] = {
+ { 0, 1, -5, 126, 8, -3, 1, 0 },
+ { -1, 3, -10, 122, 18, -6, 2, 0 },
+ { -1, 4, -13, 118, 27, -9, 3, -1 },
+ { -1, 4, -16, 112, 37, -11, 4, -1 },
+ { -1, 5, -18, 105, 48, -14, 4, -1 },
+ { -1, 5, -19, 97, 58, -16, 5, -1 },
+ { -1, 6, -19, 88, 68, -18, 5, -1 },
+ { -1, 6, -19, 78, 78, -19, 6, -1 },
+ { -1, 5, -18, 68, 88, -19, 6, -1 },
+ { -1, 5, -16, 58, 97, -19, 5, -1 },
+ { -1, 4, -14, 48, 105, -18, 5, -1 },
+ { -1, 4, -11, 37, 112, -16, 4, -1 },
+ { -1, 3, -9, 27, 118, -13, 4, -1 },
+ { 0, 2, -6, 18, 122, -10, 3, -1 },
+ { 0, 1, -3, 8, 126, -5, 1, 0 },
+ }, [FILTER_8TAP_SHARP] = {
+ { -1, 3, -7, 127, 8, -3, 1, 0 },
+ { -2, 5, -13, 125, 17, -6, 3, -1 },
+ { -3, 7, -17, 121, 27, -10, 5, -2 },
+ { -4, 9, -20, 115, 37, -13, 6, -2 },
+ { -4, 10, -23, 108, 48, -16, 8, -3 },
+ { -4, 10, -24, 100, 59, -19, 9, -3 },
+ { -4, 11, -24, 90, 70, -21, 10, -4 },
+ { -4, 11, -23, 80, 80, -23, 11, -4 },
+ { -4, 10, -21, 70, 90, -24, 11, -4 },
+ { -3, 9, -19, 59, 100, -24, 10, -4 },
+ { -3, 8, -16, 48, 108, -23, 10, -4 },
+ { -2, 6, -13, 37, 115, -20, 9, -4 },
+ { -2, 5, -10, 27, 121, -17, 7, -3 },
+ { -1, 3, -6, 17, 125, -13, 5, -2 },
+ { 0, 1, -3, 8, 127, -7, 3, -1 },
+ }, [FILTER_8TAP_SMOOTH] = {
+ { -3, -1, 32, 64, 38, 1, -3, 0 },
+ { -2, -2, 29, 63, 41, 2, -3, 0 },
+ { -2, -2, 26, 63, 43, 4, -4, 0 },
+ { -2, -3, 24, 62, 46, 5, -4, 0 },
+ { -2, -3, 21, 60, 49, 7, -4, 0 },
+ { -1, -4, 18, 59, 51, 9, -4, 0 },
+ { -1, -4, 16, 57, 53, 12, -4, -1 },
+ { -1, -4, 14, 55, 55, 14, -4, -1 },
+ { -1, -4, 12, 53, 57, 16, -4, -1 },
+ { 0, -4, 9, 51, 59, 18, -4, -1 },
+ { 0, -4, 7, 49, 60, 21, -3, -2 },
+ { 0, -4, 5, 46, 62, 24, -3, -2 },
+ { 0, -4, 4, 43, 63, 26, -2, -2 },
+ { 0, -3, 2, 41, 63, 29, -2, -2 },
+ { 0, -3, 1, 38, 64, 32, -1, -3 },
+ }
+};
+
+#define FILTER_8TAP(src, x, F, stride) \
+ av_clip_uint8((F[0] * src[x + -3 * stride] + \
+ F[1] * src[x + -2 * stride] + \
+ F[2] * src[x + -1 * stride] + \
+ F[3] * src[x + +0 * stride] + \
+ F[4] * src[x + +1 * stride] + \
+ F[5] * src[x + +2 * stride] + \
+ F[6] * src[x + +3 * stride] + \
+ F[7] * src[x + +4 * stride] + 64) >> 7)
+
+static av_always_inline void do_8tap_1d_c(uint8_t *dst, 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)
+{
+ do {
+ int x;
+
+ for (x = 0; x < w; x++)
+ if (avg) {
+ dst[x] = (dst[x] + FILTER_8TAP(src, x, filter, ds) + 1) >> 1;
+ } else {
+ dst[x] = FILTER_8TAP(src, x, filter, ds);
+ }
+
+ dst += dst_stride;
+ src += src_stride;
+ } while (--h);
+}
+
+#define filter_8tap_1d_fn(opn, opa, dir, ds) \
+static av_noinline void opn##_8tap_1d_##dir##_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int w, int h, const 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)
+filter_8tap_1d_fn(put, 0, h, 1)
+filter_8tap_1d_fn(avg, 1, v, src_stride)
+filter_8tap_1d_fn(avg, 1, h, 1)
+
+#undef filter_8tap_1d_fn
+
+static av_always_inline void do_8tap_2d_c(uint8_t *dst, 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)
+{
+ int tmp_h = h + 7;
+ uint8_t tmp[64 * 71], *tmp_ptr = tmp;
+
+ src -= src_stride * 3;
+ do {
+ int x;
+
+ for (x = 0; x < w; x++)
+ tmp_ptr[x] = FILTER_8TAP(src, x, filterx, 1);
+
+ tmp_ptr += 64;
+ src += src_stride;
+ } while (--tmp_h);
+
+ tmp_ptr = tmp + 64 * 3;
+ do {
+ int x;
+
+ for (x = 0; x < w; x++)
+ if (avg) {
+ dst[x] = (dst[x] + FILTER_8TAP(tmp_ptr, x, filtery, 64) + 1) >> 1;
+ } else {
+ dst[x] = FILTER_8TAP(tmp_ptr, x, filtery, 64);
+ }
+
+ tmp_ptr += 64;
+ dst += dst_stride;
+ } while (--h);
+}
+
+#define filter_8tap_2d_fn(opn, opa) \
+static av_noinline void opn##_8tap_2d_hv_c(uint8_t *dst, 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)
+filter_8tap_2d_fn(avg, 1)
+
+#undef filter_8tap_2d_fn
+
+#undef FILTER_8TAP
+
+#define filter_fn_1d(sz, dir, dir_m, type, type_idx, avg) \
+static void avg##_8tap_##type##_##sz##dir##_c(uint8_t *dst, 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, 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) {
+ dst[x] = (dst[x] + FILTER_BILIN(src, x, mxy, ds) + 1) >> 1;
+ } else {
+ dst[x] = FILTER_BILIN(src, x, mxy, ds);
+ }
+
+ dst += dst_stride;
+ src += src_stride;
+ } while (--h);
+}
+
+#define bilin_1d_fn(opn, opa, dir, ds) \
+static av_noinline void opn##_bilin_1d_##dir##_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int w, int h, int mxy) \
+{ \
+ do_bilin_1d_c(dst, dst_stride, src, src_stride, w, h, ds, mxy, opa); \
+}
+
+bilin_1d_fn(put, 0, v, src_stride)
+bilin_1d_fn(put, 0, h, 1)
+bilin_1d_fn(avg, 1, v, src_stride)
+bilin_1d_fn(avg, 1, h, 1)
+
+#undef bilin_1d_fn
+
+static av_always_inline void do_bilin_2d_c(uint8_t *dst, 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;
+
+ do {
+ int x;
+
+ for (x = 0; x < w; x++)
+ tmp_ptr[x] = FILTER_BILIN(src, x, mx, 1);
+
+ tmp_ptr += 64;
+ src += src_stride;
+ } while (--tmp_h);
+
+ tmp_ptr = tmp;
+ do {
+ int x;
+
+ for (x = 0; x < w; x++)
+ if (avg) {
+ dst[x] = (dst[x] + FILTER_BILIN(tmp_ptr, x, my, 64) + 1) >> 1;
+ } else {
+ dst[x] = FILTER_BILIN(tmp_ptr, x, my, 64);
+ }
+
+ tmp_ptr += 64;
+ dst += dst_stride;
+ } while (--h);
+}
+
+#define bilin_2d_fn(opn, opa) \
+static av_noinline void opn##_bilin_2d_hv_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int w, int h, int mx, int my) \
+{ \
+ do_bilin_2d_c(dst, dst_stride, src, src_stride, w, h, mx, my, opa); \
+}
+
+bilin_2d_fn(put, 0)
+bilin_2d_fn(avg, 1)
+
+#undef bilin_2d_fn
+
+#undef FILTER_BILIN
+
+#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_set(put)
+filter_fn_set(avg)
+
+#undef filter_fn
+#undef filter_fn_set
+#undef filter_fn_1d
+#undef filter_fn_2d
+#undef bilinf_fn_1d
+#undef bilinf_fn_2d
+
+static av_cold void vp9dsp_mc_init(VP9DSPContext *dsp)
+{
+#define init_fpel(idx1, idx2, sz, type) \
+ dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][0][0] = type##sz##_c; \
+ dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][0][0] = type##sz##_c; \
+ dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][0][0] = type##sz##_c; \
+ dsp->mc[idx1][FILTER_BILINEAR ][idx2][0][0] = type##sz##_c
+
+#define init_copy_avg(idx, sz) \
+ init_fpel(idx, 0, sz, copy); \
+ init_fpel(idx, 1, sz, avg)
+
+ init_copy_avg(0, 64);
+ init_copy_avg(1, 32);
+ init_copy_avg(2, 16);
+ init_copy_avg(3, 8);
+ init_copy_avg(4, 4);
+
+#undef init_copy_avg
+#undef init_fpel
+
+#define init_subpel1(idx1, idx2, idxh, idxv, sz, dir, type) \
+ dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][idxh][idxv] = type##_8tap_smooth_##sz##dir##_c; \
+ dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][idxh][idxv] = type##_8tap_regular_##sz##dir##_c; \
+ dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][idxh][idxv] = type##_8tap_sharp_##sz##dir##_c; \
+ dsp->mc[idx1][FILTER_BILINEAR ][idx2][idxh][idxv] = type##_bilin_##sz##dir##_c
+
+#define init_subpel2(idx, idxh, idxv, dir, type) \
+ init_subpel1(0, idx, idxh, idxv, 64, dir, type); \
+ init_subpel1(1, idx, idxh, idxv, 32, dir, type); \
+ init_subpel1(2, idx, idxh, idxv, 16, dir, type); \
+ init_subpel1(3, idx, idxh, idxv, 8, dir, type); \
+ init_subpel1(4, idx, idxh, idxv, 4, dir, type)
+
+#define init_subpel3(idx, type) \
+ init_subpel2(idx, 1, 1, hv, type); \
+ init_subpel2(idx, 0, 1, v, type); \
+ init_subpel2(idx, 1, 0, h, type)
+
+ init_subpel3(0, put);
+ init_subpel3(1, avg);
+
+#undef init_subpel1
+#undef init_subpel2
+#undef init_subpel3
+}
+
+av_cold void ff_vp9dsp_init(VP9DSPContext *dsp)
+{
+ vp9dsp_intrapred_init(dsp);
+ vp9dsp_itxfm_init(dsp);
+ vp9dsp_loopfilter_init(dsp);
+ vp9dsp_mc_init(dsp);
+
+ if (ARCH_X86) ff_vp9dsp_init_x86(dsp);
+}
diff --git a/libavcodec/vp9dsp.h b/libavcodec/vp9dsp.h
new file mode 100644
index 0000000..74124e4
--- a/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 (1: 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/vqavideo.c b/libavcodec/vqavideo.c
index 86f2fcf..911e713 100644
--- a/libavcodec/vqavideo.c
+++ b/libavcodec/vqavideo.c
@@ -2,20 +2,20 @@
* Westwood Studios VQA Video Decoder
* 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;
}
@@ -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;
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++)
@@ -305,7 +304,7 @@ static int decode_format80(GetByteContext *gb, int src_size,
* 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",
+ av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n",
dest_index, dest_size);
return 0; // let's display what we decoded anyway
@@ -377,7 +376,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 +393,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 +411,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 +420,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 +429,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 +438,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 +450,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 +462,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 +531,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 +552,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 +581,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 +605,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..94a4cb4 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,102 +83,8 @@ 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; \
- } \
- }
-
static av_always_inline int get_tail(GetBitContext *gb, int k)
{
int p, e, res;
@@ -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;
@@ -723,6 +572,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,6 +606,7 @@ 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;
@@ -910,7 +767,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;
@@ -1027,7 +884,7 @@ 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);
@@ -1115,11 +972,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 +1032,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 +1090,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..081b7f7
--- a/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 131072
+
+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..d7a1c61
--- a/dev/null
+++ b/libavcodec/wavpackenc.c
@@ -0,0 +1,2989 @@
+/*
+ * 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 > 150000)
+ 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) && 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);
+
+ 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);
+ }
+
+ if ((ret = ff_alloc_packet2(avctx, avpkt, s->block_samples * avctx->channels * 8)) < 0)
+ return ret;
+ buf = avpkt->data;
+ buf_size = avpkt->size;
+
+ 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..7a482ce
--- a/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 *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 8ad24f8..213e1ce 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
*/
diff --git a/libavcodec/webvttdec.c b/libavcodec/webvttdec.c
new file mode 100644
index 0000000..6b86bed
--- a/dev/null
+++ b/libavcodec/webvttdec.c
@@ -0,0 +1,100 @@
+/*
+ * 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++;
+ }
+ av_bprintf(buf, "\r\n");
+ return 0;
+}
+
+static int webvtt_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_sub_ptr, AVPacket *avpkt)
+{
+ 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;
+ ff_ass_add_rect(sub, buf.str, ts_start, ts_duration, 0);
+ }
+ *got_sub_ptr = sub->num_rects > 0;
+ av_bprint_finalize(&buf, NULL);
+ 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/wma.c b/libavcodec/wma.c
index f5ea64a..0122ee6 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
*/
@@ -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 */
diff --git a/libavcodec/wma.h b/libavcodec/wma.h
index 513ba3f..c4056ec 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
*/
diff --git a/libavcodec/wma_common.c b/libavcodec/wma_common.c
index d1d8045..51467b2 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/wmadata.h b/libavcodec/wmadata.h
index 07a1afe..381f182 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 2dd5898..e6a0b04 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
*/
@@ -93,6 +93,13 @@ 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
+ }
+ }
+
if(ff_wma_init(avctx, flags2)<0)
return -1;
@@ -472,6 +479,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){
@@ -500,6 +512,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)
@@ -812,7 +828,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);
@@ -820,16 +837,18 @@ 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;
@@ -911,7 +930,7 @@ static int wma_decode_superframe(AVCodecContext *avctx, void *data,
*got_frame_ptr = 1;
- return avctx->block_align;
+ return buf_size;
fail:
/* when error, we reset the bit reservoir */
s->last_superframe_len = 0;
@@ -926,6 +945,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 +960,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 +976,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 899cae0..895a180 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
*/
@@ -23,9 +23,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)
@@ -37,13 +35,13 @@ static av_cold int encode_init(AVCodecContext *avctx)
s->avctx = avctx;
if(avctx->channels > MAX_CHANNELS) {
- av_log(avctx, AV_LOG_ERROR, "too many channels: got %i, need %i or fewer",
+ av_log(avctx, AV_LOG_ERROR, "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);
}
@@ -68,7 +66,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;
s->use_bit_reservoir = flags2 & 0x0002;
@@ -86,8 +84,7 @@ 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->delay = s->frame_len;
return 0;
@@ -147,7 +144,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
@@ -155,7 +152,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 */
q+= *ptr++;
@@ -171,7 +168,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;
@@ -180,7 +177,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
@@ -218,7 +215,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];
@@ -274,13 +271,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++) {
@@ -302,7 +299,7 @@ static int encode_block(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE],
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]);
if(code == 0){
@@ -332,7 +329,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;
@@ -347,7 +344,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;
@@ -366,46 +363,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)
+ 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;
- total_gain -= i;
- }else if(scoreR < best){
- best = scoreR;
- total_gain += i;
- }
- }
-#endif
- 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->delay);
@@ -415,6 +398,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"),
@@ -427,7 +411,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"),
@@ -440,3 +425,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 2f341c0..7a80248 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
*/
@@ -123,7 +123,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;
@@ -145,29 +145,29 @@ typedef struct WmallDecodeCtx {
int16_t lms_prevvalues[MAX_ORDER * 2];
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;
@@ -178,6 +178,11 @@ 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;
init_put_bits(&s->pb, s->frame_data, MAX_FRAMESIZE);
@@ -503,9 +508,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++) {
@@ -523,7 +528,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;
}
@@ -953,7 +958,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]) {
@@ -1020,8 +1025,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;
}
@@ -1179,9 +1182,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 2657a0e..d57c24d 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
*/
@@ -306,6 +306,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 */
@@ -338,8 +342,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 %i\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;
}
@@ -419,6 +423,10 @@ static av_cold int decode_init(AVCodecContext *avctx)
}
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;
+ }
}
@@ -435,9 +443,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;
}
}
@@ -491,6 +500,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))
@@ -669,7 +681,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)
{
@@ -1143,7 +1155,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) {
@@ -1173,6 +1185,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;
@@ -1183,10 +1196,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 {
@@ -1379,7 +1393,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;
}
@@ -1452,7 +1465,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) {
@@ -1461,7 +1474,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");
@@ -1469,13 +1482,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) {
@@ -1589,7 +1596,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 f4bc907..8d30259 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
*/
@@ -94,8 +94,8 @@ void ff_mspel_motion(MpegEncContext *s,
{
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);
@@ -117,15 +117,15 @@ void ff_mspel_motion(MpegEncContext *s,
uvlinesize = s->uvlinesize;
ptr = ref_picture[0] + (src_y * linesize) + src_x;
- if(s->flags&CODEC_FLAG_EMU_EDGE){
if(src_x<1 || src_y<1 || src_x + 17 >= s->h_edge_pos
|| src_y + h+1 >= v_edge_pos){
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr - 1 - s->linesize, s->linesize, 19, 19,
- src_x-1, src_y-1, s->h_edge_pos, s->v_edge_pos);
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, s->linesize,
+ ptr - 1 - s->linesize, s->linesize, 19, 19,
+ src_x-1, src_y-1,
+ s->h_edge_pos, s->v_edge_pos);
ptr= s->edge_emu_buffer + 1 + s->linesize;
emu=1;
}
- }
s->dsp.put_mspel_pixels_tab[dxy](dest_y , ptr , linesize);
s->dsp.put_mspel_pixels_tab[dxy](dest_y+8 , ptr+8 , linesize);
@@ -161,16 +161,18 @@ void ff_mspel_motion(MpegEncContext *s,
offset = (src_y * uvlinesize) + src_x;
ptr = ref_picture[1] + offset;
if(emu){
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr, s->uvlinesize, 9, 9,
- src_x, src_y, s->h_edge_pos>>1, s->v_edge_pos>>1);
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, s->uvlinesize,
+ ptr, s->uvlinesize, 9, 9, src_x, src_y,
+ s->h_edge_pos>>1, s->v_edge_pos>>1);
ptr= s->edge_emu_buffer;
}
pix_op[1][dxy](dest_cb, ptr, uvlinesize, h >> 1);
ptr = ref_picture[2] + offset;
if(emu){
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr, s->uvlinesize, 9, 9,
- src_x, src_y, s->h_edge_pos>>1, s->v_edge_pos>>1);
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, s->uvlinesize,
+ ptr, s->uvlinesize, 9, 9, src_x, src_y,
+ s->h_edge_pos>>1, s->v_edge_pos>>1);
ptr= s->edge_emu_buffer;
}
pix_op[1][dxy](dest_cr, ptr, uvlinesize, h >> 1);
diff --git a/libavcodec/wmv2.h b/libavcodec/wmv2.h
index e01f6c1..52739c1 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 740636c..4f2a5e9 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
*/
@@ -446,6 +446,8 @@ int ff_wmv2_decode_mb(MpegEncContext *s, int16_t block[6][64])
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 72dfe78..9627442 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 3368b3a..37bee20 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 256c4e5..ab5e085 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
*/
@@ -84,10 +84,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);
if(w->per_mb_rl_bit) put_bits(&s->pb, 1, s->per_mb_rl_table);
diff --git a/libavcodec/wnv1.c b/libavcodec/wnv1.c
index 7676c89..d8532e4 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;
}
@@ -82,7 +80,6 @@ static int decode_frame(AVCodecContext *avctx,
}
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 +131,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 ea6628c..da86815 100644
--- a/libavcodec/x86/Makefile
+++ b/libavcodec/x86/Makefile
@@ -24,9 +24,11 @@ OBJS-$(CONFIG_MPEGVIDEO) += x86/mpegvideo.o
OBJS-$(CONFIG_MPEGVIDEOENC) += x86/mpegvideoenc.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_V210_DECODER) += x86/v210-init.o
OBJS-$(CONFIG_TRUEHD_DECODER) += x86/mlpdsp.o
OBJS-$(CONFIG_VC1_DECODER) += x86/vc1dsp_init.o
OBJS-$(CONFIG_VIDEODSP) += x86/videodsp_init.o
@@ -34,6 +36,8 @@ OBJS-$(CONFIG_VORBIS_DECODER) += x86/vorbisdsp_init.o
OBJS-$(CONFIG_VP3DSP) += x86/vp3dsp_init.o
OBJS-$(CONFIG_VP6_DECODER) += x86/vp6dsp_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
OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o
MMX-OBJS-$(CONFIG_DSPUTIL) += x86/dsputil_mmx.o \
@@ -42,9 +46,12 @@ MMX-OBJS-$(CONFIG_DSPUTIL) += x86/dsputil_mmx.o \
x86/idct_sse2_xvid.o \
x86/rnd_mmx.o \
x86/simple_idct.o
+MMX-OBJS-$(CONFIG_DIRAC_DECODER) += x86/dirac_dwt.o
MMX-OBJS-$(CONFIG_HPELDSP) += x86/fpel_mmx.o \
x86/hpeldsp_mmx.o \
x86/rnd_mmx.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
YASM-OBJS += x86/deinterlace.o \
@@ -53,6 +60,8 @@ YASM-OBJS += x86/deinterlace.o \
YASM-OBJS-$(CONFIG_AAC_DECODER) += x86/sbrdsp.o
YASM-OBJS-$(CONFIG_AC3DSP) += x86/ac3dsp.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_DSPUTIL) += x86/dsputil.o \
x86/fpel.o \
x86/mpeg4qpel.o \
@@ -80,12 +89,16 @@ YASM-OBJS-$(CONFIG_HPELDSP) += x86/fpel.o \
YASM-OBJS-$(CONFIG_MPEGAUDIODSP) += x86/imdct36.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_V210_DECODER) += x86/v210.o
YASM-OBJS-$(CONFIG_VC1_DECODER) += x86/vc1dsp.o
YASM-OBJS-$(CONFIG_VIDEODSP) += x86/videodsp.o
YASM-OBJS-$(CONFIG_VORBIS_DECODER) += x86/vorbisdsp.o
YASM-OBJS-$(CONFIG_VP3DSP) += x86/vp3dsp.o
YASM-OBJS-$(CONFIG_VP6_DECODER) += x86/vp6dsp.o
YASM-OBJS-$(CONFIG_VP8_DECODER) += x86/vp8dsp.o
+YASM-OBJS-$(CONFIG_VP9_DECODER) += x86/vp9dsp.o
+YASM-OBJS-$(CONFIG_WEBP_DECODER) += x86/vp8dsp.o
diff --git a/libavcodec/x86/ac3dsp.asm b/libavcodec/x86/ac3dsp.asm
index b432318..89a64f5 100644
--- a/libavcodec/x86/ac3dsp.asm
+++ b/libavcodec/x86/ac3dsp.asm
@@ -2,20 +2,20 @@
;* x86-optimized AC-3 DSP utils
;* 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 ca10864..8c94db0 100644
--- a/libavcodec/x86/ac3dsp_init.c
+++ b/libavcodec/x86/ac3dsp_init.c
@@ -2,20 +2,20 @@
* x86-optimized AC-3 DSP utils
* 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
*/
@@ -51,6 +51,11 @@ void ff_ac3_extract_exponents_3dnow(uint8_t *exp, int32_t *coef, int nb_coefs);
void ff_ac3_extract_exponents_sse2 (uint8_t *exp, int32_t *coef, int nb_coefs);
void ff_ac3_extract_exponents_ssse3(uint8_t *exp, int32_t *coef, int nb_coefs);
+#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/cabac.h b/libavcodec/x86/cabac.h
index fdb0a29..7d431e5 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,6 +27,13 @@
#include "libavutil/internal.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)
+# define BROKEN_COMPILER 1
+#else
+# define BROKEN_COMPILER 0
+#endif
+
#if HAVE_INLINE_ASM
#ifdef BROKEN_RELOCATIONS
@@ -73,10 +80,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"\
"add"OPSIZE" $2 , "byte" \n\t"\
- "1: \n\t"\
"movzwl (%%"REG_c") , "tmp" \n\t"\
"lea -1("low") , %%ecx \n\t"\
"xor "low" , %%ecx \n\t"\
@@ -93,6 +97,7 @@
#else /* BROKEN_RELOCATIONS */
#define TABLES_ARG
+#define RIP_ARG
#if HAVE_FAST_CMOV
#define BRANCHLESS_GET_CABAC_UPDATE(ret, low, range, tmp)\
@@ -134,10 +139,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"\
"add"OPSIZE" $2 , "byte" \n\t"\
- "1: \n\t"\
"movzwl (%%"REG_c") , "tmp" \n\t"\
"lea -1("low") , %%ecx \n\t"\
"xor "low" , %%ecx \n\t"\
@@ -154,8 +156,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)
@@ -178,17 +179,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 */
+#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)
{
@@ -211,10 +214,9 @@ 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"
+ "add $2, %1 \n\t"
"addl %%edx, %%eax \n\t"
- "cmp %c5(%2), %1 \n\t"
- "jge 1f \n\t"
- "add"OPSIZE" $2, %c4(%2) \n\t"
+ "mov %1, %c4(%2) \n\t"
"1: \n\t"
"movl %%eax, %c3(%2) \n\t"
@@ -268,6 +270,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 9d2b950..068995d 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
*/
diff --git a/libavcodec/x86/constants.c b/libavcodec/x86/constants.c
index 5b8d1b2..3bba80b 100644
--- a/libavcodec/x86/constants.c
+++ b/libavcodec/x86/constants.c
@@ -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
*/
diff --git a/libavcodec/x86/constants.h b/libavcodec/x86/constants.h
index f38fbe3..8097bc4 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
*/
diff --git a/libavcodec/x86/dct32.asm b/libavcodec/x86/dct32.asm
index 9c147b9..6fd5ba3 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
diff --git a/libavcodec/x86/dct_init.c b/libavcodec/x86/dct_init.c
index 7bda5e8..85e2d0c 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
*/
diff --git a/libavcodec/x86/deinterlace.asm b/libavcodec/x86/deinterlace.asm
index b2828f3..3812dbe 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..04c514f
--- a/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 "dsputil_x86.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
--- a/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..a28bb82
--- a/dev/null
+++ b/libavcodec/x86/diracdsp_mmx.c
@@ -0,0 +1,104 @@
+/*
+ * 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 "dsputil_x86.h"
+#include "diracdsp_mmx.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
+
+void ff_diracdsp_init_mmx(DiracDSPContext* c)
+{
+ int mm_flags = av_get_cpu_flags();
+
+ if (!(mm_flags & AV_CPU_FLAG_MMX))
+ return;
+
+#if HAVE_YASM
+ 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
+#endif
+
+#if HAVE_MMX_INLINE
+ PIXFUNC(put, 0, mmx);
+ PIXFUNC(avg, 0, mmx);
+#endif
+
+#if HAVE_MMXEXT_INLINE
+ if (mm_flags & AV_CPU_FLAG_MMX2) {
+ PIXFUNC(avg, 0, mmxext);
+ }
+#endif
+
+ if (mm_flags & AV_CPU_FLAG_SSE2) {
+#if HAVE_YASM
+ 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;
+#endif
+#if HAVE_SSE2_INLINE
+ 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;
+#endif
+ }
+}
diff --git a/libavcodec/x86/diracdsp_mmx.h b/libavcodec/x86/diracdsp_mmx.h
new file mode 100644
index 0000000..8985854
--- a/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..3e9765b
--- a/dev/null
+++ b/libavcodec/x86/diracdsp_yasm.asm
@@ -0,0 +1,264 @@
+;******************************************************************************
+;* 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_3: times 8 dw 3
+pw_7: times 8 dw 7
+pw_16: times 8 dw 16
+pw_32: times 8 dw 32
+pb_128: times 16 db 128
+
+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_128]
+ 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.c b/libavcodec/x86/dnxhdenc.c
index 0bab69f..c7e776a 100644
--- a/libavcodec/x86/dnxhdenc.c
+++ b/libavcodec/x86/dnxhdenc.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/dsputil.asm b/libavcodec/x86/dsputil.asm
index 5d73ff8..77069e2 100644
--- a/libavcodec/x86/dsputil.asm
+++ b/libavcodec/x86/dsputil.asm
@@ -1,21 +1,23 @@
;******************************************************************************
;* MMX optimized DSP utils
;* 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
;******************************************************************************
@@ -605,6 +607,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/dsputil_init.c b/libavcodec/x86/dsputil_init.c
index a38cf24..2516f2a 100644
--- a/libavcodec/x86/dsputil_init.c
+++ b/libavcodec/x86/dsputil_init.c
@@ -1,18 +1,21 @@
/*
- * This file is part of Libav.
+ * 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
*/
@@ -543,24 +546,11 @@ static av_cold void dsputil_init_mmx(DSPContext *c, AVCodecContext *avctx,
c->clear_block = ff_clear_block_mmx;
c->clear_blocks = ff_clear_blocks_mmx;
c->draw_edges = ff_draw_edges_mmx;
-
- switch (avctx->idct_algo) {
- case FF_IDCT_AUTO:
- case FF_IDCT_SIMPLEMMX:
- c->idct_put = ff_simple_idct_put_mmx;
- c->idct_add = ff_simple_idct_add_mmx;
- c->idct = ff_simple_idct_mmx;
- c->idct_permutation_type = FF_SIMPLE_IDCT_PERM;
- break;
- case FF_IDCT_XVIDMMX:
- c->idct_put = ff_idct_xvid_mmx_put;
- c->idct_add = ff_idct_xvid_mmx_add;
- c->idct = ff_idct_xvid_mmx;
- break;
- }
}
+#if CONFIG_VIDEODSP && (ARCH_X86_32 || !HAVE_YASM)
c->gmc = ff_gmc_mmx;
+#endif
c->add_bytes = ff_add_bytes_mmx;
#endif /* HAVE_MMX_INLINE */
@@ -581,7 +571,7 @@ static av_cold void dsputil_init_mmxext(DSPContext *c, AVCodecContext *avctx,
#if HAVE_MMXEXT_INLINE
const int high_bit_depth = avctx->bits_per_raw_sample > 8;
- if (!high_bit_depth && avctx->idct_algo == FF_IDCT_XVIDMMX) {
+ if (!high_bit_depth && avctx->idct_algo == FF_IDCT_XVIDMMX && avctx->lowres == 0) {
c->idct_put = ff_idct_xvid_mmxext_put;
c->idct_add = ff_idct_xvid_mmxext_add;
c->idct = ff_idct_xvid_mmxext;
@@ -628,6 +618,12 @@ static av_cold void dsputil_init_sse(DSPContext *c, AVCodecContext *avctx,
c->vector_clipf = ff_vector_clipf_sse;
#endif /* HAVE_SSE_INLINE */
+
+#if HAVE_YASM
+#if HAVE_INLINE_ASM && CONFIG_VIDEODSP
+ c->gmc = ff_gmc_sse;
+#endif
+#endif /* HAVE_YASM */
}
static av_cold void dsputil_init_sse2(DSPContext *c, AVCodecContext *avctx,
@@ -636,7 +632,7 @@ static av_cold void dsputil_init_sse2(DSPContext *c, AVCodecContext *avctx,
#if HAVE_SSE2_INLINE
const int high_bit_depth = avctx->bits_per_raw_sample > 8;
- if (!high_bit_depth && avctx->idct_algo == FF_IDCT_XVIDMMX) {
+ if (!high_bit_depth && avctx->idct_algo == FF_IDCT_XVIDMMX && avctx->lowres == 0) {
c->idct_put = ff_idct_xvid_sse2_put;
c->idct_add = ff_idct_xvid_sse2_add;
c->idct = ff_idct_xvid_sse2;
@@ -692,12 +688,30 @@ av_cold void ff_dsputil_init_x86(DSPContext *c, AVCodecContext *avctx)
int cpu_flags = av_get_cpu_flags();
#if HAVE_7REGS && HAVE_INLINE_ASM
- if (cpu_flags & AV_CPU_FLAG_CMOV)
+ if (HAVE_MMX && cpu_flags & AV_CPU_FLAG_CMOV)
c->add_hfyu_median_prediction = ff_add_hfyu_median_prediction_cmov;
#endif
- if (X86_MMX(cpu_flags))
+ if (X86_MMX(cpu_flags)) {
+#if HAVE_INLINE_ASM
+ const int idct_algo = avctx->idct_algo;
+
+ if (avctx->lowres == 0 && avctx->bits_per_raw_sample <= 8) {
+ if (idct_algo == FF_IDCT_AUTO || idct_algo == FF_IDCT_SIMPLEMMX) {
+ c->idct_put = ff_simple_idct_put_mmx;
+ c->idct_add = ff_simple_idct_add_mmx;
+ c->idct = ff_simple_idct_mmx;
+ c->idct_permutation_type = FF_SIMPLE_IDCT_PERM;
+ } else if (idct_algo == FF_IDCT_XVIDMMX) {
+ c->idct_put = ff_idct_xvid_mmx_put;
+ c->idct_add = ff_idct_xvid_mmx_add;
+ c->idct = ff_idct_xvid_mmx;
+ }
+ }
+#endif /* HAVE_INLINE_ASM */
+
dsputil_init_mmx(c, avctx, cpu_flags);
+ }
if (X86_MMXEXT(cpu_flags))
dsputil_init_mmxext(c, avctx, cpu_flags);
diff --git a/libavcodec/x86/dsputil_mmx.c b/libavcodec/x86/dsputil_mmx.c
index 885c10a..805bacd 100644
--- a/libavcodec/x86/dsputil_mmx.c
+++ b/libavcodec/x86/dsputil_mmx.c
@@ -3,30 +3,33 @@
* 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.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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>
*/
#include "config.h"
+#include "libavutil/avassert.h"
#include "libavutil/cpu.h"
#include "libavutil/x86/asm.h"
+#include "libavcodec/videodsp.h"
#include "constants.h"
#include "dsputil_x86.h"
+#include "diracdsp_mmx.h"
#if HAVE_INLINE_ASM
@@ -279,7 +282,7 @@ void ff_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"
@@ -300,6 +303,25 @@ void ff_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 {
+ 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)
+ );
}
/* top and bottom (and hopefully also the corners) */
@@ -345,10 +367,16 @@ void ff_draw_edges_mmx(uint8_t *buf, int wrap, int width, int height,
}
}
-void ff_gmc_mmx(uint8_t *dst, uint8_t *src,
- int stride, int h, int ox, int oy,
- int dxx, int dxy, int dyx, int dyy,
- int shift, int r, int width, int height)
+typedef void emulated_edge_mc_func(uint8_t *dst, ptrdiff_t dst_stride,
+ const uint8_t *src, ptrdiff_t src_linesize,
+ int block_w, int block_h,
+ int src_x, int src_y, int w, int h);
+
+static av_always_inline void gmc(uint8_t *dst, uint8_t *src,
+ int stride, int h, int ox, int oy,
+ int dxx, int dxy, int dyx, int dyy,
+ int shift, int r, int width, int height,
+ emulated_edge_mc_func *emu_edge_fn)
{
const int w = 8;
const int ix = ox >> (16 + shift);
@@ -363,19 +391,24 @@ void ff_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) {
+ || (dxx | dxy | dyx | dyy) & 15
+ || (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);
@@ -383,6 +416,10 @@ void ff_gmc_mmx(uint8_t *dst, uint8_t *src,
}
src += ix + iy * stride;
+ if (need_emu) {
+ emu_edge_fn(edge_buf, stride, src, stride, w + 1, h + 1, ix, iy, width, height);
+ src = edge_buf;
+ }
__asm__ volatile (
"movd %0, %%mm6 \n\t"
@@ -461,6 +498,108 @@ void ff_gmc_mmx(uint8_t *dst, uint8_t *src,
}
}
+#if CONFIG_VIDEODSP
+#if HAVE_YASM
+#if ARCH_X86_32
+void ff_gmc_mmx(uint8_t *dst, uint8_t *src,
+ int stride, int h, int ox, int oy,
+ int dxx, int dxy, int dyx, int dyy,
+ int shift, int r, int width, int height)
+{
+ gmc(dst, src, stride, h, ox, oy, dxx, dxy, dyx, dyy, shift, r,
+ width, height, &ff_emulated_edge_mc_8);
+}
+#endif
+void ff_gmc_sse(uint8_t *dst, uint8_t *src,
+ int stride, int h, int ox, int oy,
+ int dxx, int dxy, int dyx, int dyy,
+ int shift, int r, int width, int height)
+{
+ gmc(dst, src, stride, h, ox, oy, dxx, dxy, dyx, dyy, shift, r,
+ width, height, &ff_emulated_edge_mc_8);
+}
+#else
+void ff_gmc_mmx(uint8_t *dst, uint8_t *src,
+ int stride, int h, int ox, int oy,
+ int dxx, int dxy, int dyx, int dyy,
+ int shift, int r, int width, int height)
+{
+ gmc(dst, src, stride, h, ox, oy, dxx, dxy, dyx, dyy, shift, r,
+ width, height, &ff_emulated_edge_mc_8);
+}
+#endif
+#endif
+
+#if CONFIG_DIRAC_DECODER
+#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);\
+ }\
+}
+
+#if HAVE_MMX_INLINE
+PIXELS16(static, ff_avg, , , _mmxext)
+DIRAC_PIXOP(put, ff_put, mmx)
+DIRAC_PIXOP(avg, ff_avg, mmx)
+#endif
+
+#if HAVE_YASM
+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);
+ }
+}
+#endif
+#endif
+
void ff_vector_clipf_sse(float *dst, const float *src,
float min, float max, int len)
{
diff --git a/libavcodec/x86/dsputil_qns_template.c b/libavcodec/x86/dsputil_qns_template.c
index 20a40a1..bde6b0a 100644
--- a/libavcodec/x86/dsputil_qns_template.c
+++ b/libavcodec/x86/dsputil_qns_template.c
@@ -5,20 +5,20 @@
* 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
*/
@@ -28,7 +28,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/dsputil_x86.c b/libavcodec/x86/dsputil_x86.c
index 144339b..f43b9d7 100644
--- a/libavcodec/x86/dsputil_x86.c
+++ b/libavcodec/x86/dsputil_x86.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
*/
diff --git a/libavcodec/x86/dsputil_x86.h b/libavcodec/x86/dsputil_x86.h
index c8615b2..356b2c1 100644
--- a/libavcodec/x86/dsputil_x86.h
+++ b/libavcodec/x86/dsputil_x86.h
@@ -2,20 +2,20 @@
* MMX optimized DSP utils
* 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
*/
@@ -129,6 +129,11 @@ void ff_gmc_mmx(uint8_t *dst, uint8_t *src,
int dxx, int dxy, int dyx, int dyy,
int shift, int r, int width, int height);
+void ff_gmc_sse(uint8_t *dst, uint8_t *src,
+ int stride, int h, int ox, int oy,
+ int dxx, int dxy, int dyx, int dyy,
+ int shift, int r, int width, int height);
+
void ff_vector_clipf_sse(float *dst, const float *src,
float min, float max, int len);
@@ -162,6 +167,10 @@ void ff_put_pixels8_xy2_mmx(uint8_t *block, const uint8_t *pixels,
void ff_put_pixels16_xy2_mmx(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
+
+void ff_mmx_idct(int16_t *block);
+void ff_mmxext_idct(int16_t *block);
+
void ff_deinterlace_line_mmx(uint8_t *dst,
const uint8_t *lum_m4, const uint8_t *lum_m3,
const uint8_t *lum_m2, const uint8_t *lum_m1,
diff --git a/libavcodec/x86/dsputilenc.asm b/libavcodec/x86/dsputilenc.asm
index 7e4fd81..1839bee 100644
--- a/libavcodec/x86/dsputilenc.asm
+++ b/libavcodec/x86/dsputilenc.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
;*****************************************************************************
diff --git a/libavcodec/x86/dsputilenc_mmx.c b/libavcodec/x86/dsputilenc_mmx.c
index 33c8d51..6205577 100644
--- a/libavcodec/x86/dsputilenc_mmx.c
+++ b/libavcodec/x86/dsputilenc_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
*/
@@ -424,8 +424,8 @@ static int nsse8_mmx(void *p, uint8_t * pix1, uint8_t * pix2, int line_size, int
static int vsad_intra16_mmx(void *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"\
@@ -487,8 +487,8 @@ static int vsad_intra16_mmxext(void *v, uint8_t *pix, uint8_t *dummy,
{
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), " #out0 "\n"\
@@ -527,9 +527,9 @@ static int vsad_intra16_mmxext(void *v, uint8_t *pix, uint8_t *dummy,
static int vsad16_mmx(void *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"\
@@ -607,9 +607,9 @@ static int vsad16_mmxext(void *v, uint8_t *pix1, uint8_t *pix2,
{
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)," #out0 "\n"\
@@ -661,8 +661,9 @@ static int vsad16_mmxext(void *v, uint8_t *pix1, uint8_t *pix2,
}
#undef SUM
-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/dwt_yasm.asm b/libavcodec/x86/dwt_yasm.asm
new file mode 100644
index 0000000..5253abc
--- a/dev/null
+++ b/libavcodec/x86/dwt_yasm.asm
@@ -0,0 +1,306 @@
+;******************************************************************************
+;* 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_1: times 8 dw 1
+pw_2: times 8 dw 2
+pw_8: times 8 dw 8
+pw_16: times 8 dw 16
+pw_1991: times 4 dw 9,-1
+
+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 6d595aa..11a13bb 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/fft.asm b/libavcodec/x86/fft.asm
index e4744a3..cae404c 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
@@ -305,6 +304,7 @@ IF%1 mova Z(1), m5
INIT_YMM avx
+%if HAVE_AVX_EXTERNAL
align 16
fft8_avx:
mova m0, Z(0)
@@ -394,6 +394,8 @@ fft32_interleave_avx:
jg .deint_loop
ret
+%endif
+
INIT_XMM sse
align 16
@@ -537,6 +539,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 +561,7 @@ cglobal fft_calc, 2,5,8
FFT_DISPATCH _interleave %+ SUFFIX, r1
REP_RET
+%endif
INIT_XMM sse
@@ -776,9 +780,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
@@ -1080,4 +1086,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/fmtconvert.asm b/libavcodec/x86/fmtconvert.asm
index e7803df..60078e2 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
;******************************************************************************
diff --git a/libavcodec/x86/fmtconvert_init.c b/libavcodec/x86/fmtconvert_init.c
index 3d75df9..d300dfd 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
*/
diff --git a/libavcodec/x86/fpel.asm b/libavcodec/x86/fpel.asm
index 43b039d..dc363d1 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
;******************************************************************************
diff --git a/libavcodec/x86/fpel_mmx.c b/libavcodec/x86/fpel_mmx.c
index 1ae8f86..384ab89 100644
--- a/libavcodec/x86/fpel_mmx.c
+++ b/libavcodec/x86/fpel_mmx.c
@@ -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
*/
diff --git a/libavcodec/x86/h263_loopfilter.asm b/libavcodec/x86/h263_loopfilter.asm
index a940aad..a21baf1 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/h264_chromamc.asm b/libavcodec/x86/h264_chromamc.asm
index b7b18e0..32681aa 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 aec7678..beb7c0f 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
;******************************************************************************
@@ -251,8 +251,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
@@ -260,8 +262,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 6e29ce7..1317783 100644
--- a/libavcodec/x86/h264_deblock.asm
+++ b/libavcodec/x86/h264_deblock.asm
@@ -7,20 +7,20 @@
;* Jason Garrett-Glaser <darkshikari@gmail.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
;******************************************************************************
@@ -382,8 +382,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
@@ -495,8 +497,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
@@ -768,8 +772,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
@@ -830,7 +836,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 3b81ef6..fdaf510 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>
;* Jason Garrett-Glaser <darkshikari@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -417,9 +417,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
@@ -712,8 +714,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
@@ -797,10 +801,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'
@@ -911,5 +917,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..0dc0a7c 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
*/
diff --git a/libavcodec/x86/h264_idct.asm b/libavcodec/x86/h264_idct.asm
index 2771291..9af98a9 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 4e51d2b..df21288 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
;-----------------------------------------------------------------------------
; h264_idct_add16(pixel *dst, const int *block_offset, dctcoef *block, int stride, const uint8_t nnzc[6*8])
@@ -115,9 +117,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
@@ -153,8 +157,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 h264_idct_dc_add(pixel *dst, dctcoef *block, int stride)
@@ -218,8 +224,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
;-----------------------------------------------------------------------------
; h264_idct_add16intra(pixel *dst, const int *block_offset, dctcoef *block, int stride, const uint8_t nnzc[6*8])
@@ -289,8 +297,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
;-----------------------------------------------------------------------------
@@ -324,8 +334,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 h264_idct8_add(pixel *dst, dctcoef *block, int stride)
@@ -531,8 +543,10 @@ h264_idct8_add1_10 %+ SUFFIX:
INIT_XMM sse2
IDCT8_ADD
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
IDCT8_ADD
+%endif
;-----------------------------------------------------------------------------
; h264_idct8_add4(pixel **dst, const int *block_offset, dctcoef *block, int stride, const uint8_t nnzc[6*8])
@@ -569,5 +583,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 b9db3f4..5c0dff4 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
;******************************************************************************
diff --git a/libavcodec/x86/h264_intrapred_10bit.asm b/libavcodec/x86/h264_intrapred_10bit.asm
index 1b7974b..54eaee5 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
;******************************************************************************
@@ -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 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 pred4x4_horizontal_down(pixel *src, const pixel *topright, int stride)
@@ -159,8 +163,10 @@ INIT_XMM sse2
PRED4x4_HD
INIT_XMM ssse3
PRED4x4_HD
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED4x4_HD
+%endif
;-----------------------------------------------------------------------------
; void pred4x4_dc(pixel *src, const pixel *topright, int stride)
@@ -228,8 +234,10 @@ cglobal pred4x4_down_left_10, 3, 3
INIT_XMM sse2
PRED4x4_DL
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED4x4_DL
+%endif
;-----------------------------------------------------------------------------
; void pred4x4_vertical_left(pixel *src, const pixel *topright, int stride)
@@ -255,8 +263,10 @@ cglobal pred4x4_vertical_left_10, 3, 3
INIT_XMM sse2
PRED4x4_VL
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED4x4_VL
+%endif
;-----------------------------------------------------------------------------
; void pred4x4_horizontal_up(pixel *src, const pixel *topright, int stride)
@@ -563,8 +573,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 pred8x8l_dc(pixel *src, int has_topleft, int has_topright, int stride)
@@ -620,8 +632,10 @@ cglobal pred8x8l_dc_10, 4, 6, 6
INIT_XMM sse2
PRED8x8L_DC
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED8x8L_DC
+%endif
;-----------------------------------------------------------------------------
; void pred8x8l_vertical(pixel *src, int has_topleft, int has_topright, int stride)
@@ -653,8 +667,10 @@ cglobal pred8x8l_vertical_10, 4, 4, 6
INIT_XMM sse2
PRED8x8L_VERTICAL
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED8x8L_VERTICAL
+%endif
;-----------------------------------------------------------------------------
; void pred8x8l_horizontal(uint8_t *src, int has_topleft, int has_topright, int stride)
@@ -707,8 +723,10 @@ INIT_XMM sse2
PRED8x8L_HORIZONTAL
INIT_XMM ssse3
PRED8x8L_HORIZONTAL
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED8x8L_HORIZONTAL
+%endif
;-----------------------------------------------------------------------------
;void pred8x8l_down_left(pixel *src, int has_topleft, int has_topright, int stride)
@@ -773,8 +791,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 pred8x8l_down_right(pixel *src, int has_topleft, int has_topright, int stride)
@@ -845,8 +865,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 pred8x8l_vertical_right(pixel *src, int has_topleft, int has_topright, int stride)
@@ -913,8 +935,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 pred8x8l_horizontal_up(pixel *src, int has_topleft, int has_topright, int stride)
@@ -972,8 +996,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 6dd98aa..ad2984b 100644
--- a/libavcodec/x86/h264_intrapred_init.c
+++ b/libavcodec/x86/h264_intrapred_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Jason Garrett-Glaser
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with 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 90857ce..fd6068f 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
*/
@@ -338,7 +338,7 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc21_ ## MMX(uint8_t *dst, uint8_t *
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);\
}\
@@ -348,7 +348,7 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc23_ ## MMX(uint8_t *dst, uint8_t *
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);\
}\
@@ -358,7 +358,7 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc12_ ## MMX(uint8_t *dst, uint8_t *
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);\
}\
@@ -368,7 +368,7 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc32_ ## MMX(uint8_t *dst, uint8_t *
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 e14df84..4561871 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
;******************************************************************************
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 646acdf..4759a06 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 3b09e42..b7845fd 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 eec1653..3d8d5b0 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 4164b83..30801c4 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
*/
@@ -211,6 +211,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 (chroma_format_idc == 1 && EXTERNAL_MMXEXT(cpu_flags))
@@ -366,4 +367,5 @@ av_cold void ff_h264dsp_init_x86(H264DSPContext *c, const int bit_depth,
#endif /* HAVE_ALIGNED_STACK */
}
}
+#endif
}
diff --git a/libavcodec/x86/hpeldsp.asm b/libavcodec/x86/hpeldsp.asm
index ec04d99..1a572a3 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
+;*
;* MMX optimized hpel 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/hpeldsp_init.c b/libavcodec/x86/hpeldsp_init.c
index 209781c..7db0683 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>
diff --git a/libavcodec/x86/hpeldsp_mmx.c b/libavcodec/x86/hpeldsp_mmx.c
index fece265..50db36d 100644
--- a/libavcodec/x86/hpeldsp_mmx.c
+++ b/libavcodec/x86/hpeldsp_mmx.c
@@ -3,20 +3,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/libavcodec/x86/hpeldsp_rnd_template.c b/libavcodec/x86/hpeldsp_rnd_template.c
index 516a03a..94e06d8 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
*/
diff --git a/libavcodec/x86/idct_mmx_xvid.c b/libavcodec/x86/idct_mmx_xvid.c
index 2772339..4cd6de1 100644
--- a/libavcodec/x86/idct_mmx_xvid.c
+++ b/libavcodec/x86/idct_mmx_xvid.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
*/
diff --git a/libavcodec/x86/idct_sse2_xvid.c b/libavcodec/x86/idct_sse2_xvid.c
index 50655d6..af4790c 100644
--- a/libavcodec/x86/idct_sse2_xvid.c
+++ b/libavcodec/x86/idct_sse2_xvid.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,22 +23,21 @@
*
* 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 "idct_xvid.h"
diff --git a/libavcodec/x86/idct_xvid.h b/libavcodec/x86/idct_xvid.h
index aea28ba..7a2847b 100644
--- a/libavcodec/x86/idct_xvid.h
+++ b/libavcodec/x86/idct_xvid.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/imdct36.asm b/libavcodec/x86/imdct36.asm
index 633fcd9..d311fbe 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
;******************************************************************************
@@ -370,8 +370,10 @@ DEFINE_IMDCT
INIT_XMM ssse3
DEFINE_IMDCT
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
DEFINE_IMDCT
+%endif
INIT_XMM sse
@@ -716,5 +718,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/lpc.c b/libavcodec/x86/lpc.c
index 12245c4..8a74755 100644
--- a/libavcodec/x86/lpc.c
+++ b/libavcodec/x86/lpc.c
@@ -2,26 +2,25 @@
* MMX optimized LPC DSP utils
* 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"
@@ -152,7 +151,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..9c48afe 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
*/
diff --git a/libavcodec/x86/mlpdsp.c b/libavcodec/x86/mlpdsp.c
index 72fc637..94849b7 100644
--- a/libavcodec/x86/mlpdsp.c
+++ b/libavcodec/x86/mlpdsp.c
@@ -2,25 +2,24 @@
* 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"
diff --git a/libavcodec/x86/motion_est.c b/libavcodec/x86/motion_est.c
index 41b9c5c..5f5d93e 100644
--- a/libavcodec/x86/motion_est.c
+++ b/libavcodec/x86/motion_est.c
@@ -5,25 +5,25 @@
*
* mostly 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 "libavutil/attributes.h"
-#include "libavutil/internal.h"
+#include "libavutil/avassert.h"
#include "libavutil/mem.h"
#include "libavutil/x86/asm.h"
#include "libavutil/x86/cpu.h"
@@ -41,7 +41,7 @@ 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"
@@ -204,7 +204,7 @@ static inline void sad8_4_mmxext(uint8_t *blk1, uint8_t *blk2,
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"
@@ -242,7 +242,7 @@ static inline void sad8_2_mmx(uint8_t *blk1a, uint8_t *blk1b, uint8_t *blk2, int
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"
@@ -332,7 +332,7 @@ static inline void sad8_y2a_mmx(uint8_t *blk1, uint8_t *blk2, int stride, int h)
#define PIX_SAD(suf)\
static int sad8_ ## suf(void *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":);\
\
@@ -342,7 +342,7 @@ static int sad8_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h
}\
static int sad8_x2_ ## suf(void *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"\
"movq %0, %%mm5 \n\t"\
@@ -356,7 +356,7 @@ static int sad8_x2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, in
\
static int sad8_y2_ ## suf(void *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"\
"movq %0, %%mm5 \n\t"\
@@ -370,7 +370,7 @@ static int sad8_y2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, in
\
static int sad8_xy2_ ## suf(void *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"\
::);\
@@ -467,7 +467,7 @@ av_cold void ff_dsputil_init_pix_mmx(DSPContext *c, AVCodecContext *avctx)
c->pix_abs[1][3] = sad8_xy2_mmxext;
}
}
- if (INLINE_SSE2(cpu_flags) && !(cpu_flags & AV_CPU_FLAG_3DNOW)) {
+ if (INLINE_SSE2(cpu_flags) && !(cpu_flags & AV_CPU_FLAG_3DNOW) && avctx->codec_id != AV_CODEC_ID_SNOW) {
c->sad[0]= sad16_sse2;
}
#endif /* HAVE_INLINE_ASM */
diff --git a/libavcodec/x86/mpeg4qpel.asm b/libavcodec/x86/mpeg4qpel.asm
index df20ea9..ca52375 100644
--- a/libavcodec/x86/mpeg4qpel.asm
+++ b/libavcodec/x86/mpeg4qpel.asm
@@ -1,21 +1,23 @@
;******************************************************************************
;* 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/mpegaudiodsp.c b/libavcodec/x86/mpegaudiodsp.c
index 3f0943c..9c6f795 100644
--- a/libavcodec/x86/mpegaudiodsp.c
+++ b/libavcodec/x86/mpegaudiodsp.c
@@ -2,20 +2,20 @@
* MMX 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,16 @@
#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);
+
+DECL(sse)
+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,
@@ -217,11 +222,15 @@ static void imdct36_blocks_ ## CPU1(float *out, float *buf, float *in, \
} \
}
+#if HAVE_SSE
DECL_IMDCT_BLOCKS(sse,sse)
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)
diff --git a/libavcodec/x86/mpegvideo.c b/libavcodec/x86/mpegvideo.c
index 07fd1e5..cee3d5f 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
*/
@@ -27,7 +27,7 @@
#include "libavcodec/mpegvideo.h"
#include "dsputil_x86.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)
@@ -36,7 +36,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)
@@ -112,7 +112,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] ];
@@ -172,7 +172,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;
@@ -240,7 +240,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;
@@ -307,7 +307,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] ];
@@ -372,7 +372,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] ];
@@ -553,11 +553,11 @@ static void denoise_dct_sse2(MpegEncContext *s, int16_t *block){
);
}
-#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)) {
@@ -573,5 +573,5 @@ av_cold void ff_MPV_common_init_x86(MpegEncContext *s)
if (INLINE_SSE2(cpu_flags)) {
s->denoise_dct = denoise_dct_sse2;
}
-#endif /* HAVE_INLINE_ASM */
+#endif /* HAVE_MMX_INLINE */
}
diff --git a/libavcodec/x86/mpegvideoenc.c b/libavcodec/x86/mpegvideoenc.c
index ca39a3b..97aa3c7 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
*/
@@ -81,7 +81,7 @@ extern uint16_t ff_inv_zigzag_direct16[64];
#include "mpegvideoenc_template.c"
#endif /* HAVE_SSSE3_INLINE */
-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;
diff --git a/libavcodec/x86/mpegvideoenc_template.c b/libavcodec/x86/mpegvideoenc_template.c
index 4d3fb74..1e0505e 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
*/
@@ -100,7 +100,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);
RENAMEl(ff_fdct) (block); //cannot be anything else ...
@@ -110,10 +110,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 (
@@ -128,8 +133,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];
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 855f209..aedacc2 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 d63382c..0273d61 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,11 +32,14 @@ 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_x86_init(ProresDSPContext *dsp)
+av_cold void ff_proresdsp_x86_init(ProresDSPContext *dsp, AVCodecContext *avctx)
{
#if ARCH_X86_64
int cpu_flags = av_get_cpu_flags();
+ if(avctx->flags & CODEC_FLAG_BITEXACT)
+ return;
+
if (EXTERNAL_SSE2(cpu_flags)) {
dsp->idct_permutation_type = FF_TRANSPOSE_IDCT_PERM;
dsp->idct_put = ff_prores_idct_put_10_sse2;
diff --git a/libavcodec/x86/qpel.asm b/libavcodec/x86/qpel.asm
index c90b393..c2ffb86 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/rnd_mmx.c b/libavcodec/x86/rnd_mmx.c
index db4515a..326e2f3 100644
--- a/libavcodec/x86/rnd_mmx.c
+++ b/libavcodec/x86/rnd_mmx.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/rnd_template.c b/libavcodec/x86/rnd_template.c
index e9a5a45..e37fc19 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 5f284b8..027efe9 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 7ec72be..e561935 100644
--- a/libavcodec/x86/rv40dsp.asm
+++ b/libavcodec/x86/rv40dsp.asm
@@ -4,20 +4,20 @@
;* Copyright (c) 2010 Jason Garrett-Glaser <darkshikari@gmail.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 781f467..75ba8ba 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
*/
diff --git a/libavcodec/x86/sbrdsp.asm b/libavcodec/x86/sbrdsp.asm
index 36a0918..adc13c4 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
;******************************************************************************
@@ -26,6 +26,12 @@ SECTION_RODATA
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
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
; sbr_qmf_deint_bfly(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,106 @@ 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
diff --git a/libavcodec/x86/sbrdsp_init.c b/libavcodec/x86/sbrdsp_init.c
index 9600852..2b912d0 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,23 @@ 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);
+
av_cold void ff_sbrdsp_init_x86(SBRDSPContext *s)
{
int cpu_flags = av_get_cpu_flags();
@@ -48,10 +62,15 @@ 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;
}
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 36f0b47..c666b1a 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 "libavcodec/simple_idct.h"
-#include "libavutil/internal.h"
#include "libavutil/mem.h"
#include "dsputil_x86.h"
@@ -81,7 +80,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(
diff --git a/libavcodec/x86/snowdsp.c b/libavcodec/x86/snowdsp.c
new file mode 100644
index 0000000..735e790
--- a/dev/null
+++ b/libavcodec/x86/snowdsp.c
@@ -0,0 +1,902 @@
+/*
+ * 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"
+#include "dsputil_x86.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
+
+#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):\
+ "%"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_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
+ c->inner_add_yblock = ff_snow_inner_add_yblock_sse2;
+ }
+ 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
+ }
+ c->inner_add_yblock = ff_snow_inner_add_yblock_mmx;
+ }
+ }
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/x86/v210-init.c b/libavcodec/x86/v210-init.c
new file mode 100644
index 0000000..02c5eaa
--- a/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..6554a43
--- a/dev/null
+++ b/libavcodec/x86/v210.asm
@@ -0,0 +1,88 @@
+;******************************************************************************
+;* 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 2
+
+; v210_planar_unpack(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width)
+cglobal v210_planar_unpack_%1_%2, 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
+v210_planar_unpack unaligned, ssse3
+%if HAVE_AVX_EXTERNAL
+INIT_AVX
+v210_planar_unpack unaligned, avx
+%endif
+
+INIT_XMM
+v210_planar_unpack aligned, ssse3
+%if HAVE_AVX_EXTERNAL
+INIT_AVX
+v210_planar_unpack aligned, avx
+%endif
diff --git a/libavcodec/x86/vc1dsp.asm b/libavcodec/x86/vc1dsp.asm
index adf08d7..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_mmx.c b/libavcodec/x86/vc1dsp_mmx.c
index 15fd2c8..5ceacd3 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"
diff --git a/libavcodec/x86/videodsp.asm b/libavcodec/x86/videodsp.asm
index 34f007f..1ac0257 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
;******************************************************************************
@@ -23,577 +23,409 @@
SECTION .text
-; void ff_emu_edge_core(uint8_t *buf, const uint8_t *src, x86_reg linesize,
-; x86_reg start_y, x86_reg end_y, x86_reg block_h,
-; x86_reg start_x, x86_reg end_x, x86_reg block_w);
-;
-; The actual function itself is below. It basically wraps a very simple
-; w = end_x - start_x
-; if (w) {
-; if (w > 22) {
-; jump to the slow loop functions
-; } else {
-; jump to the fast loop functions
-; }
-; }
-;
-; ... and then the same for left/right extend also. See below for loop
-; function implementations. Fast are fixed-width, slow is variable-width
-
-%macro EMU_EDGE_FUNC 0
-%if ARCH_X86_64
-%define w_reg r7
-cglobal emu_edge_core, 6, 9, 1
- mov r8, r5 ; save block_h
-%else
-%define w_reg r6
-cglobal emu_edge_core, 2, 7, 0
- mov r4, r4m ; end_y
- mov r5, r5m ; block_h
-%endif
+; slow vertical extension loop function. Works with variable-width, and
+; does per-line reading/writing of source data
+
+%macro V_COPY_ROW 2 ; type (top/body/bottom), h
+.%1_y_loop: ; do {
+ mov wq, r7mp ; initialize w (r7mp = wmp)
+.%1_x_loop: ; do {
+ movu m0, [srcq+wq] ; m0 = read($mmsize)
+ movu [dstq+wq], m0 ; write(m0, $mmsize)
+ add wq, mmsize ; w -= $mmsize
+ cmp wq, -mmsize ; } while (w > $mmsize);
+ jl .%1_x_loop
+ movu m0, [srcq-mmsize] ; m0 = read($mmsize)
+ movu [dstq-mmsize], m0 ; write(m0, $mmsize)
+%ifidn %1, body ; if ($type == body) {
+ add srcq, src_strideq ; src += src_stride
+%endif ; }
+ add dstq, dst_strideq ; dst += dst_stride
+ dec %2 ; } while (--$h);
+ jnz .%1_y_loop
+%endmacro
- ; start with vertical extend (top/bottom) and body pixel copy
- mov w_reg, r7m
- sub w_reg, r6m ; w = start_x - end_x
- sub r5, r4
+%macro vvar_fn 0
+; .----. <- zero
+; | | <- top is copied from first line in body of source
+; |----| <- start_y
+; | | <- body is copied verbatim (line-by-line) from source
+; |----| <- end_y
+; | | <- bottom is copied from last line in body of source
+; '----' <- bh
%if ARCH_X86_64
- sub r4, r3
-%else
- sub r4, dword r3m
+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 r1mp
+ mov srcq, r2mp
+ mov start_yq, r4mp
+ mov end_yq, r5mp
+ mov bhq, r6mp
%endif
- cmp w_reg, 22
- jg .slow_v_extend_loop
+ sub bhq, end_yq ; bh -= end_q
+ sub end_yq, start_yq ; end_q -= start_q
+ add srcq, r7mp ; (r7mp = wmp)
+ add dstq, r7mp ; (r7mp = wmp)
+ neg r7mp ; (r7mp = wmp)
+ test start_yq, start_yq ; if (start_q) {
+ jz .body
+ V_COPY_ROW top, start_yq ; v_copy_row(top, start_yq)
+.body: ; }
+ V_COPY_ROW body, end_yq ; v_copy_row(body, end_yq)
+ test bhq, bhq ; if (bh) {
+ jz .end
+ sub srcq, src_strideq ; src -= src_stride
+ V_COPY_ROW bottom, bhq ; v_copy_row(bottom, bh)
+.end: ; }
+ RET
+%endmacro
+
%if ARCH_X86_32
- mov r2, r2m ; linesize
-%endif
- sal w_reg, 7 ; w * 128
-%ifdef PIC
- lea rax, [.emuedge_v_extend_1 - (.emuedge_v_extend_2 - .emuedge_v_extend_1)]
- add w_reg, rax
-%else
- lea w_reg, [.emuedge_v_extend_1 - (.emuedge_v_extend_2 - .emuedge_v_extend_1)+w_reg]
+INIT_MMX mmx
+vvar_fn
%endif
- call w_reg ; fast top extend, body copy and bottom extend
-.v_extend_end:
- ; horizontal extend (left/right)
- mov w_reg, r6m ; start_x
- sub r0, w_reg
-%if ARCH_X86_64
- mov r3, r0 ; backup of buf+block_h*linesize
- mov r5, r8
-%else
- mov r0m, r0 ; backup of buf+block_h*linesize
- mov r5, r5m
-%endif
- test w_reg, w_reg
- jz .right_extend
- cmp w_reg, 22
- jg .slow_left_extend_loop
- mov r1, w_reg
- dec w_reg
- ; FIXME we can do a if size == 1 here if that makes any speed difference, test me
- sar w_reg, 1
- sal w_reg, 6
- ; r0=buf+block_h*linesize,r7(64)/r6(32)=start_x offset for funcs
- ; r6(rax)/r3(ebx)=val,r2=linesize,r1=start_x,r5=block_h
-%ifdef PIC
- lea rax, [.emuedge_extend_left_2]
- add w_reg, rax
-%else
- lea w_reg, [.emuedge_extend_left_2+w_reg]
-%endif
- call w_reg
+INIT_XMM sse
+vvar_fn
+
+%macro hvar_fn 0
+cglobal emu_edge_hvar, 5, 6, 1, dst, dst_stride, start_x, n_words, h, w
+ lea dstq, [dstq+n_wordsq*2]
+ neg n_wordsq
+ lea start_xq, [start_xq+n_wordsq*2]
+.y_loop: ; do {
+ ; FIXME also write a ssse3 version using pshufb
+ movzx wd, byte [dstq+start_xq] ; w = read(1)
+ imul wd, 0x01010101 ; w *= 0x01010101
+ movd m0, wd
+ mov wq, n_wordsq ; initialize w
+%if cpuflag(sse2)
+ pshufd m0, m0, q0000 ; splat
+%else ; mmx
+ punpckldq m0, m0 ; splat
+%endif ; mmx/sse
+.x_loop: ; do {
+ movu [dstq+wq*2], m0 ; write($reg, $mmsize)
+ add wq, mmsize/2 ; w -= $mmsize/2
+ cmp wq, -mmsize/2 ; } while (w > $mmsize/2)
+ jl .x_loop
+ movu [dstq-mmsize], m0 ; write($reg, $mmsize)
+ add dstq, dst_strideq ; dst += dst_stride
+ dec hq ; } while (h--)
+ jnz .y_loop
+ RET
+%endmacro
- ; now r3(64)/r0(32)=buf,r2=linesize,r8/r5=block_h,r6/r3=val, r7/r6=end_x, r1=block_w
-.right_extend:
%if ARCH_X86_32
- mov r0, r0m
- mov r5, r5m
-%endif
- mov w_reg, r7m ; end_x
- mov r1, r8m ; block_w
- mov r4, r1
- sub r1, w_reg
- jz .h_extend_end ; if (end_x == block_w) goto h_extend_end
- cmp r1, 22
- jg .slow_right_extend_loop
- dec r1
- ; FIXME we can do a if size == 1 here if that makes any speed difference, test me
- sar r1, 1
- sal r1, 6
-%ifdef PIC
- lea rax, [.emuedge_extend_right_2]
- add r1, rax
-%else
- lea r1, [.emuedge_extend_right_2+r1]
+INIT_MMX mmx
+hvar_fn
%endif
- call r1
-.h_extend_end:
- RET
-%if ARCH_X86_64
-%define vall al
-%define valh ah
-%define valw ax
-%define valw2 r7w
-%define valw3 r3w
-%if WIN64
-%define valw4 r7w
-%else ; unix64
-%define valw4 r3w
-%endif
-%define vald eax
-%else
-%define vall bl
-%define valh bh
-%define valw bx
-%define valw2 r6w
-%define valw3 valw2
-%define valw4 valw3
-%define vald ebx
-%define stack_offset 0x14
-%endif
-
-%endmacro
+INIT_XMM sse2
+hvar_fn
; macro to read/write a horizontal number of pixels (%2) to/from registers
-; on x86-64, - fills xmm0-15 for consecutive sets of 16 pixels
-; - if (%2 & 15 == 8) fills the last 8 bytes into rax
-; - else if (%2 & 8) fills 8 bytes into mm0
-; - if (%2 & 7 == 4) fills the last 4 bytes into rax
-; - else if (%2 & 4) fills 4 bytes into mm0-1
-; - if (%2 & 3 == 3) fills 2 bytes into r7/r3, and 1 into eax
-; (note that we're using r3 for body/bottom because it's a shorter
-; opcode, and then the loop fits in 128 bytes)
-; - else fills remaining bytes into rax
-; on x86-32, - fills mm0-7 for consecutive sets of 8 pixels
-; - if (%2 & 7 == 4) fills 4 bytes into ebx
-; - else if (%2 & 4) fills 4 bytes into mm0-7
-; - if (%2 & 3 == 3) fills 2 bytes into r6, and 1 into ebx
-; - else fills remaining bytes into ebx
+; on sse, - fills xmm0-15 for consecutive sets of 16 pixels
+; - if (%2 & 8) fills 8 bytes into xmm$next
+; - if (%2 & 4) fills 4 bytes into xmm$next
+; - if (%2 & 3) fills 1, 2 or 4 bytes in eax
+; on mmx, - fills mm0-7 for consecutive sets of 8 pixels
+; - if (%2 & 4) fills 4 bytes into mm$next
+; - if (%2 & 3) fills 1, 2 or 4 bytes in eax
; writing data out is in the same way
%macro READ_NUM_BYTES 2
-%assign %%src_off 0 ; offset in source buffer
-%assign %%smidx 0 ; mmx register idx
-%assign %%sxidx 0 ; xmm register idx
-
-%if cpuflag(sse)
-%rep %2/16
- movups xmm %+ %%sxidx, [r1+%%src_off]
-%assign %%src_off %%src_off+16
-%assign %%sxidx %%sxidx+1
-%endrep ; %2/16
+%assign %%off 0 ; offset in source buffer
+%assign %%mmx_idx 0 ; mmx register index
+%assign %%xmm_idx 0 ; xmm register index
+
+%rep %2/mmsize
+%if mmsize == 16
+ movu xmm %+ %%xmm_idx, [srcq+%%off]
+%assign %%xmm_idx %%xmm_idx+1
+%else ; mmx
+ movu mm %+ %%mmx_idx, [srcq+%%off]
+%assign %%mmx_idx %%mmx_idx+1
+%endif
+%assign %%off %%off+mmsize
+%endrep ; %2/mmsize
+
+%if mmsize == 16
+%if (%2-%%off) >= 8
+%if %2 > 16 && (%2-%%off) > 8
+ movu xmm %+ %%xmm_idx, [srcq+%2-16]
+%assign %%xmm_idx %%xmm_idx+1
+%assign %%off %2
+%else
+ movq mm %+ %%mmx_idx, [srcq+%%off]
+%assign %%mmx_idx %%mmx_idx+1
+%assign %%off %%off+8
+%endif
+%endif ; (%2-%%off) >= 8
%endif
-%if ARCH_X86_64
-%if (%2-%%src_off) == 8
- mov rax, [r1+%%src_off]
-%assign %%src_off %%src_off+8
-%endif ; (%2-%%src_off) == 8
-%endif ; x86-64
-
-%rep (%2-%%src_off)/8
- movq mm %+ %%smidx, [r1+%%src_off]
-%assign %%src_off %%src_off+8
-%assign %%smidx %%smidx+1
-%endrep ; (%2-%%dst_off)/8
-
-%if (%2-%%src_off) == 4
- mov vald, [r1+%%src_off]
-%elif (%2-%%src_off) & 4
- movd mm %+ %%smidx, [r1+%%src_off]
-%assign %%src_off %%src_off+4
-%endif ; (%2-%%src_off) ==/& 4
-
-%if (%2-%%src_off) == 1
- mov vall, [r1+%%src_off]
-%elif (%2-%%src_off) == 2
- mov valw, [r1+%%src_off]
-%elif (%2-%%src_off) == 3
-%ifidn %1, top
- mov valw2, [r1+%%src_off]
+%if (%2-%%off) >= 4
+%if %2 > 8 && (%2-%%off) > 4
+ movq mm %+ %%mmx_idx, [srcq+%2-8]
+%assign %%off %2
+%else
+ movd mm %+ %%mmx_idx, [srcq+%%off]
+%assign %%off %%off+4
+%endif
+%assign %%mmx_idx %%mmx_idx+1
+%endif ; (%2-%%off) >= 4
+
+%if (%2-%%off) >= 1
+%if %2 >= 4
+ movd mm %+ %%mmx_idx, [srcq+%2-4]
+%elif (%2-%%off) == 1
+ mov valb, [srcq+%2-1]
+%elif (%2-%%off) == 2
+ mov valw, [srcq+%2-2]
%elifidn %1, body
- mov valw3, [r1+%%src_off]
-%elifidn %1, bottom
- mov valw4, [r1+%%src_off]
-%endif ; %1 ==/!= top
- mov vall, [r1+%%src_off+2]
-%endif ; (%2-%%src_off) == 1/2/3
+ mov vald, [srcq+%2-3]
+%else
+ movd mm %+ %%mmx_idx, [srcq+%2-3]
+%endif
+%endif ; (%2-%%off) >= 1
%endmacro ; READ_NUM_BYTES
%macro WRITE_NUM_BYTES 2
-%assign %%dst_off 0 ; offset in destination buffer
-%assign %%dmidx 0 ; mmx register idx
-%assign %%dxidx 0 ; xmm register idx
-
-%if cpuflag(sse)
-%rep %2/16
- movups [r0+%%dst_off], xmm %+ %%dxidx
-%assign %%dst_off %%dst_off+16
-%assign %%dxidx %%dxidx+1
-%endrep ; %2/16
+%assign %%off 0 ; offset in destination buffer
+%assign %%mmx_idx 0 ; mmx register index
+%assign %%xmm_idx 0 ; xmm register index
+
+%rep %2/mmsize
+%if mmsize == 16
+ movu [dstq+%%off], xmm %+ %%xmm_idx
+%assign %%xmm_idx %%xmm_idx+1
+%else ; mmx
+ movu [dstq+%%off], mm %+ %%mmx_idx
+%assign %%mmx_idx %%mmx_idx+1
+%endif
+%assign %%off %%off+mmsize
+%endrep ; %2/mmsize
+
+%if mmsize == 16
+%if (%2-%%off) >= 8
+%if %2 > 16 && (%2-%%off) > 8
+ movu [dstq+%2-16], xmm %+ %%xmm_idx
+%assign %%xmm_idx %%xmm_idx+1
+%assign %%off %2
+%else
+ movq [dstq+%%off], mm %+ %%mmx_idx
+%assign %%mmx_idx %%mmx_idx+1
+%assign %%off %%off+8
+%endif
+%endif ; (%2-%%off) >= 8
%endif
-%if ARCH_X86_64
-%if (%2-%%dst_off) == 8
- mov [r0+%%dst_off], rax
-%assign %%dst_off %%dst_off+8
-%endif ; (%2-%%dst_off) == 8
-%endif ; x86-64
-
-%rep (%2-%%dst_off)/8
- movq [r0+%%dst_off], mm %+ %%dmidx
-%assign %%dst_off %%dst_off+8
-%assign %%dmidx %%dmidx+1
-%endrep ; (%2-%%dst_off)/8
-
-%if (%2-%%dst_off) == 4
- mov [r0+%%dst_off], vald
-%elif (%2-%%dst_off) & 4
- movd [r0+%%dst_off], mm %+ %%dmidx
-%assign %%dst_off %%dst_off+4
-%endif ; (%2-%%dst_off) ==/& 4
-
-%if (%2-%%dst_off) == 1
- mov [r0+%%dst_off], vall
-%elif (%2-%%dst_off) == 2
- mov [r0+%%dst_off], valw
-%elif (%2-%%dst_off) == 3
-%ifidn %1, top
- mov [r0+%%dst_off], valw2
+%if (%2-%%off) >= 4
+%if %2 > 8 && (%2-%%off) > 4
+ movq [dstq+%2-8], mm %+ %%mmx_idx
+%assign %%off %2
+%else
+ movd [dstq+%%off], mm %+ %%mmx_idx
+%assign %%off %%off+4
+%endif
+%assign %%mmx_idx %%mmx_idx+1
+%endif ; (%2-%%off) >= 4
+
+%if (%2-%%off) >= 1
+%if %2 >= 4
+ movd [dstq+%2-4], mm %+ %%mmx_idx
+%elif (%2-%%off) == 1
+ mov [dstq+%2-1], valb
+%elif (%2-%%off) == 2
+ mov [dstq+%2-2], valw
%elifidn %1, body
- mov [r0+%%dst_off], valw3
-%elifidn %1, bottom
- mov [r0+%%dst_off], valw4
-%endif ; %1 ==/!= top
- mov [r0+%%dst_off+2], vall
-%endif ; (%2-%%dst_off) == 1/2/3
+ mov [dstq+%2-3], valw
+ shr vald, 16
+ mov [dstq+%2-1], valb
+%else
+ movd vald, mm %+ %%mmx_idx
+ mov [dstq+%2-3], valw
+ shr vald, 16
+ mov [dstq+%2-1], valb
+%endif
+%endif ; (%2-%%off) >= 1
%endmacro ; WRITE_NUM_BYTES
; vertical top/bottom extend and body copy fast loops
; these are function pointers to set-width line copy functions, i.e.
; they read a fixed number of pixels into set registers, and write
; those out into the destination buffer
-; r0=buf,r1=src,r2=linesize,r3(64)/r3m(32)=start_x,r4=end_y,r5=block_h
-; r6(eax/64)/r3(ebx/32)=val_reg
-%macro VERTICAL_EXTEND 0
-%assign %%n 1
-%rep 22
-ALIGN 128
-.emuedge_v_extend_ %+ %%n:
- ; extend pixels above body
+%macro VERTICAL_EXTEND 2
+%assign %%n %1
+%rep 1+%2-%1
+%if %%n <= 3
%if ARCH_X86_64
- test r3 , r3 ; if (!start_y)
- jz .emuedge_copy_body_ %+ %%n %+ _loop ; goto body
-%else ; ARCH_X86_32
- cmp dword r3m, 0
- je .emuedge_copy_body_ %+ %%n %+ _loop
-%endif ; ARCH_X86_64/32
- READ_NUM_BYTES top, %%n ; read bytes
-.emuedge_extend_top_ %+ %%n %+ _loop: ; do {
- WRITE_NUM_BYTES top, %%n ; write bytes
- add r0 , r2 ; dst += linesize
+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, r2mp
+ mov start_yq, r4mp
+ mov end_yq, r5mp
+ mov bhq, r6mp
+%define dst_strideq r1mp
+%define src_strideq r3mp
+%endif ; x86-64/32
+%else
%if ARCH_X86_64
- dec r3d
-%else ; ARCH_X86_32
- dec dword r3m
-%endif ; ARCH_X86_64/32
- jnz .emuedge_extend_top_ %+ %%n %+ _loop ; } while (--start_y)
+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, r2mp
+ mov start_yq, r4mp
+ mov end_yq, r5mp
+ mov bhq, r6mp
+%define dst_strideq r1mp
+%define src_strideq r3mp
+%endif ; x86-64/32
+%endif
+ ; FIXME move this to c wrapper?
+ sub bhq, end_yq ; bh -= end_y
+ sub end_yq, start_yq ; end_y -= start_y
+
+ ; extend pixels above body
+ test start_yq, start_yq ; if (start_y) {
+ jz .body_loop
+ READ_NUM_BYTES top, %%n ; $variable_regs = read($n)
+.top_loop: ; do {
+ WRITE_NUM_BYTES top, %%n ; write($variable_regs, $n)
+ add dstq, dst_strideq ; dst += linesize
+ dec start_yq ; } while (--start_y)
+ jnz .top_loop ; }
; copy body pixels
-.emuedge_copy_body_ %+ %%n %+ _loop: ; do {
- READ_NUM_BYTES body, %%n ; read bytes
- WRITE_NUM_BYTES body, %%n ; write bytes
- add r0 , r2 ; dst += linesize
- add r1 , r2 ; src += linesize
- dec r4d
- jnz .emuedge_copy_body_ %+ %%n %+ _loop ; } while (--end_y)
+.body_loop: ; do {
+ READ_NUM_BYTES body, %%n ; $variable_regs = read($n)
+ WRITE_NUM_BYTES body, %%n ; write($variable_regs, $n)
+ add dstq, dst_strideq ; dst += dst_stride
+ add srcq, src_strideq ; src += src_stride
+ dec end_yq ; } while (--end_y)
+ jnz .body_loop
; copy bottom pixels
- test r5 , r5 ; if (!block_h)
- jz .emuedge_v_extend_end_ %+ %%n ; goto end
- sub r1 , r2 ; src -= linesize
- READ_NUM_BYTES bottom, %%n ; read bytes
-.emuedge_extend_bottom_ %+ %%n %+ _loop: ; do {
- WRITE_NUM_BYTES bottom, %%n ; write bytes
- add r0 , r2 ; dst += linesize
- dec r5d
- jnz .emuedge_extend_bottom_ %+ %%n %+ _loop ; } while (--block_h)
-
-.emuedge_v_extend_end_ %+ %%n:
-%if ARCH_X86_64
- ret
-%else ; ARCH_X86_32
- rep ret
-%endif ; ARCH_X86_64/32
+ test bhq, bhq ; if (block_h) {
+ jz .end
+ sub srcq, src_strideq ; src -= linesize
+ READ_NUM_BYTES bottom, %%n ; $variable_regs = read($n)
+.bottom_loop: ; do {
+ WRITE_NUM_BYTES bottom, %%n ; write($variable_regs, $n)
+ add dstq, dst_strideq ; dst += linesize
+ dec bhq ; } while (--bh)
+ jnz .bottom_loop ; }
+
+.end:
+ RET
%assign %%n %%n+1
-%endrep
-%endmacro VERTICAL_EXTEND
+%endrep ; 1+%2-%1
+%endmacro ; VERTICAL_EXTEND
+
+INIT_MMX mmx
+VERTICAL_EXTEND 1, 15
+%if ARCH_X86_32
+VERTICAL_EXTEND 16, 22
+%endif
+
+INIT_XMM sse
+VERTICAL_EXTEND 16, 22
; left/right (horizontal) fast extend functions
; these are essentially identical to the vertical extend ones above,
; just left/right separated because number of pixels to extend is
; obviously not the same on both sides.
-; for reading, pixels are placed in eax (x86-64) or ebx (x86-64) in the
-; lowest two bytes of the register (so val*0x0101), and are splatted
-; into each byte of mm0 as well if n_pixels >= 8
%macro READ_V_PIXEL 2
- mov vall, %2
- mov valh, vall
+ movzx vald, byte %2
+ imul vald, 0x01010101
%if %1 >= 8
- movd mm0, vald
-%if cpuflag(mmxext)
- pshufw mm0, mm0, 0
-%else ; mmx
- punpcklwd mm0, mm0
- punpckldq mm0, mm0
-%endif ; sse
-%endif ; %1 >= 8
-%endmacro
+ movd m0, vald
+%if mmsize == 16
+ pshufd m0, m0, q0000
+%else
+ punpckldq m0, m0
+%endif ; mmsize == 16
+%endif ; %1 > 16
+%endmacro ; READ_V_PIXEL
%macro WRITE_V_PIXEL 2
-%assign %%dst_off 0
-%rep %1/8
- movq [%2+%%dst_off], mm0
-%assign %%dst_off %%dst_off+8
-%endrep
-%if %1 & 4
-%if %1 >= 8
- movd [%2+%%dst_off], mm0
-%else ; %1 < 8
- mov [%2+%%dst_off] , valw
- mov [%2+%%dst_off+2], valw
-%endif ; %1 >=/< 8
-%assign %%dst_off %%dst_off+4
-%endif ; %1 & 4
-%if %1&2
- mov [%2+%%dst_off], valw
-%endif ; %1 & 2
-%endmacro
+%assign %%off 0
-; r0=buf+block_h*linesize, r1=start_x, r2=linesize, r5=block_h, r6/r3=val
-%macro LEFT_EXTEND 0
-%assign %%n 2
-%rep 11
-ALIGN 64
-.emuedge_extend_left_ %+ %%n: ; do {
- sub r0, r2 ; dst -= linesize
- READ_V_PIXEL %%n, [r0+r1] ; read pixels
- WRITE_V_PIXEL %%n, r0 ; write pixels
- dec r5
- jnz .emuedge_extend_left_ %+ %%n ; } while (--block_h)
-%if ARCH_X86_64
- ret
-%else ; ARCH_X86_32
- rep ret
-%endif ; ARCH_X86_64/32
-%assign %%n %%n+2
-%endrep
-%endmacro ; LEFT_EXTEND
-
-; r3/r0=buf+block_h*linesize, r2=linesize, r8/r5=block_h, r0/r6=end_x, r6/r3=val
-%macro RIGHT_EXTEND 0
-%assign %%n 2
-%rep 11
-ALIGN 64
-.emuedge_extend_right_ %+ %%n: ; do {
-%if ARCH_X86_64
- sub r3, r2 ; dst -= linesize
- READ_V_PIXEL %%n, [r3+w_reg-1] ; read pixels
- WRITE_V_PIXEL %%n, r3+r4-%%n ; write pixels
- dec r8
-%else ; ARCH_X86_32
- sub r0, r2 ; dst -= linesize
- READ_V_PIXEL %%n, [r0+w_reg-1] ; read pixels
- WRITE_V_PIXEL %%n, r0+r4-%%n ; write pixels
- dec r5
-%endif ; ARCH_X86_64/32
- jnz .emuedge_extend_right_ %+ %%n ; } while (--block_h)
-%if ARCH_X86_64
- ret
-%else ; ARCH_X86_32
- rep ret
-%endif ; ARCH_X86_64/32
-%assign %%n %%n+2
-%endrep
-
-%if ARCH_X86_32
-%define stack_offset 0x10
-%endif
-%endmacro ; RIGHT_EXTEND
-
-; below follow the "slow" copy/extend functions, these act on a non-fixed
-; width specified in a register, and run a loop to copy the full amount
-; of bytes. They are optimized for copying of large amounts of pixels per
-; line, so they unconditionally splat data into mm registers to copy 8
-; bytes per loop iteration. It could be considered to use xmm for x86-64
-; also, but I haven't optimized this as much (i.e. FIXME)
-%macro V_COPY_NPX 4-5
-%if %0 == 4
- test w_reg, %4
- jz .%1_skip_%4_px
-%else ; %0 == 5
-.%1_%4_px_loop:
-%endif
- %3 %2, [r1+cnt_reg]
- %3 [r0+cnt_reg], %2
- add cnt_reg, %4
-%if %0 == 5
- sub w_reg, %4
- test w_reg, %5
- jnz .%1_%4_px_loop
-%endif
-.%1_skip_%4_px:
-%endmacro
+%if %1 >= 8
-%macro V_COPY_ROW 2
-%ifidn %1, bottom
- sub r1, linesize
-%endif
-.%1_copy_loop:
- xor cnt_reg, cnt_reg
-%if notcpuflag(sse)
-%define linesize r2m
- V_COPY_NPX %1, mm0, movq, 8, 0xFFFFFFF8
-%else ; sse
- V_COPY_NPX %1, xmm0, movups, 16, 0xFFFFFFF0
-%if ARCH_X86_64
-%define linesize r2
- V_COPY_NPX %1, rax , mov, 8
-%else ; ARCH_X86_32
-%define linesize r2m
- V_COPY_NPX %1, mm0, movq, 8
-%endif ; ARCH_X86_64/32
-%endif ; sse
- V_COPY_NPX %1, vald, mov, 4
- V_COPY_NPX %1, valw, mov, 2
- V_COPY_NPX %1, vall, mov, 1
- mov w_reg, cnt_reg
-%ifidn %1, body
- add r1, linesize
-%endif
- add r0, linesize
- dec %2
- jnz .%1_copy_loop
-%endmacro
+%rep %1/mmsize
+ movu [%2+%%off], m0
+%assign %%off %%off+mmsize
+%endrep ; %1/mmsize
-%macro SLOW_V_EXTEND 0
-.slow_v_extend_loop:
-; r0=buf,r1=src,r2(64)/r2m(32)=linesize,r3(64)/r3m(32)=start_x,r4=end_y,r5=block_h
-; r8(64)/r3(later-64)/r2(32)=cnt_reg,r6(64)/r3(32)=val_reg,r7(64)/r6(32)=w=end_x-start_x
-%if ARCH_X86_64
- push r8 ; save old value of block_h
- test r3, r3
-%define cnt_reg r8
- jz .do_body_copy ; if (!start_y) goto do_body_copy
- V_COPY_ROW top, r3
+%if mmsize == 16
+%if %1-%%off >= 8
+%if %1 > 16 && %1-%%off > 8
+ movu [%2+%1-16], m0
+%assign %%off %1
%else
- cmp dword r3m, 0
-%define cnt_reg r2
- je .do_body_copy ; if (!start_y) goto do_body_copy
- V_COPY_ROW top, dword r3m
+ movq [%2+%%off], m0
+%assign %%off %%off+8
%endif
+%endif ; %1-%%off >= 8
+%endif ; mmsize == 16
-.do_body_copy:
- V_COPY_ROW body, r4
-
-%if ARCH_X86_64
- pop r8 ; restore old value of block_h
-%define cnt_reg r3
-%endif
- test r5, r5
-%if ARCH_X86_64
- jz .v_extend_end
+%if %1-%%off >= 4
+%if %1 > 8 && %1-%%off > 4
+ movq [%2+%1-8], m0
+%assign %%off %1
%else
- jz .skip_bottom_extend
-%endif
- V_COPY_ROW bottom, r5
-%if ARCH_X86_32
-.skip_bottom_extend:
- mov r2, r2m
+ movd [%2+%%off], m0
+%assign %%off %%off+4
%endif
- jmp .v_extend_end
-%endmacro
+%endif ; %1-%%off >= 4
-%macro SLOW_LEFT_EXTEND 0
-.slow_left_extend_loop:
-; r0=buf+block_h*linesize,r2=linesize,r6(64)/r3(32)=val,r5=block_h,r4=cntr,r7/r6=start_x
- mov r4, 8
- sub r0, linesize
- READ_V_PIXEL 8, [r0+w_reg]
-.left_extend_8px_loop:
- movq [r0+r4-8], mm0
- add r4, 8
- cmp r4, w_reg
- jle .left_extend_8px_loop
- sub r4, 8
- cmp r4, w_reg
- jge .left_extend_loop_end
-.left_extend_2px_loop:
- mov [r0+r4], valw
- add r4, 2
- cmp r4, w_reg
- jl .left_extend_2px_loop
-.left_extend_loop_end:
- dec r5
- jnz .slow_left_extend_loop
-%if ARCH_X86_32
- mov r2, r2m
-%endif
- jmp .right_extend
-%endmacro
+%else ; %1 < 8
-%macro SLOW_RIGHT_EXTEND 0
-.slow_right_extend_loop:
-; r3(64)/r0(32)=buf+block_h*linesize,r2=linesize,r4=block_w,r8(64)/r5(32)=block_h,
-; r7(64)/r6(32)=end_x,r6/r3=val,r1=cntr
-%if ARCH_X86_64
-%define buf_reg r3
-%define bh_reg r8
-%else
-%define buf_reg r0
-%define bh_reg r5
-%endif
- lea r1, [r4-8]
- sub buf_reg, linesize
- READ_V_PIXEL 8, [buf_reg+w_reg-1]
-.right_extend_8px_loop:
- movq [buf_reg+r1], mm0
- sub r1, 8
- cmp r1, w_reg
- jge .right_extend_8px_loop
- add r1, 8
- cmp r1, w_reg
- je .right_extend_loop_end
-.right_extend_2px_loop:
- sub r1, 2
- mov [buf_reg+r1], valw
- cmp r1, w_reg
- jg .right_extend_2px_loop
-.right_extend_loop_end:
- dec bh_reg
- jnz .slow_right_extend_loop
- jmp .h_extend_end
-%endmacro
+%rep %1/4
+ mov [%2+%%off], vald
+%assign %%off %%off+4
+%endrep ; %1/4
-%macro emu_edge 1
-INIT_XMM %1
-EMU_EDGE_FUNC
-VERTICAL_EXTEND
-LEFT_EXTEND
-RIGHT_EXTEND
-SLOW_V_EXTEND
-SLOW_LEFT_EXTEND
-SLOW_RIGHT_EXTEND
-%endmacro
+%endif ; %1 >=/< 8
+
+%if %1-%%off == 2
+ mov [%2+%%off], valw
+%endif ; (%1-%%off)/2
+%endmacro ; WRITE_V_PIXEL
+
+%macro H_EXTEND 2
+%assign %%n %1
+%rep 1+(%2-%1)/2
+cglobal emu_edge_hfix %+ %%n, 4, 5, 1, dst, dst_stride, start_x, bh, val
+.loop_y: ; do {
+ READ_V_PIXEL %%n, [dstq+start_xq] ; $variable_regs = read($n)
+ WRITE_V_PIXEL %%n, dstq ; write($variable_regs, $n)
+ add dstq, dst_strideq ; dst += dst_stride
+ dec bhq ; } while (--bh)
+ jnz .loop_y
+ RET
+%assign %%n %%n+2
+%endrep ; 1+(%2-%1)/2
+%endmacro ; H_EXTEND
-emu_edge sse
+INIT_MMX mmx
+H_EXTEND 2, 14
%if ARCH_X86_32
-emu_edge mmx
+H_EXTEND 16, 22
%endif
+INIT_XMM sse2
+H_EXTEND 16, 22
+
%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 f7fd267..0e6e0dd 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,28 +30,127 @@
#include "libavcodec/videodsp.h"
#if HAVE_YASM
-typedef void emu_edge_core_func(uint8_t *buf, const uint8_t *src,
- x86_reg linesize, x86_reg start_y,
- x86_reg end_y, x86_reg block_h,
- x86_reg start_x, x86_reg end_x,
- x86_reg block_w);
-extern emu_edge_core_func ff_emu_edge_core_mmx;
-extern emu_edge_core_func ff_emu_edge_core_sse;
-
-static av_always_inline void emulated_edge_mc(uint8_t *buf, const uint8_t *src,
- ptrdiff_t linesize,
- int block_w, int block_h,
- int src_x, int src_y,
- int w, int h,
- emu_edge_core_func *core_fn)
+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, 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);
+
+extern emu_edge_vfix_func ff_emu_edge_vfix1_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix2_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix3_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix4_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix5_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix6_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix7_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix8_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix9_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix10_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix11_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix12_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix13_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix14_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix15_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix16_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix17_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix18_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix19_mmx;
+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] = {
+ &ff_emu_edge_vfix1_mmx, &ff_emu_edge_vfix2_mmx, &ff_emu_edge_vfix3_mmx,
+ &ff_emu_edge_vfix4_mmx, &ff_emu_edge_vfix5_mmx, &ff_emu_edge_vfix6_mmx,
+ &ff_emu_edge_vfix7_mmx, &ff_emu_edge_vfix8_mmx, &ff_emu_edge_vfix9_mmx,
+ &ff_emu_edge_vfix10_mmx, &ff_emu_edge_vfix11_mmx, &ff_emu_edge_vfix12_mmx,
+ &ff_emu_edge_vfix13_mmx, &ff_emu_edge_vfix14_mmx, &ff_emu_edge_vfix15_mmx,
+ &ff_emu_edge_vfix16_mmx, &ff_emu_edge_vfix17_mmx, &ff_emu_edge_vfix18_mmx,
+ &ff_emu_edge_vfix19_mmx, &ff_emu_edge_vfix20_mmx, &ff_emu_edge_vfix21_mmx,
+ &ff_emu_edge_vfix22_mmx
+};
+#endif
+extern emu_edge_vvar_func ff_emu_edge_vvar_mmx;
+extern emu_edge_vfix_func ff_emu_edge_vfix16_sse;
+extern emu_edge_vfix_func ff_emu_edge_vfix17_sse;
+extern emu_edge_vfix_func ff_emu_edge_vfix18_sse;
+extern emu_edge_vfix_func ff_emu_edge_vfix19_sse;
+extern emu_edge_vfix_func ff_emu_edge_vfix20_sse;
+extern emu_edge_vfix_func ff_emu_edge_vfix21_sse;
+extern emu_edge_vfix_func ff_emu_edge_vfix22_sse;
+static emu_edge_vfix_func *vfixtbl_sse[22] = {
+ ff_emu_edge_vfix1_mmx, ff_emu_edge_vfix2_mmx, ff_emu_edge_vfix3_mmx,
+ ff_emu_edge_vfix4_mmx, ff_emu_edge_vfix5_mmx, ff_emu_edge_vfix6_mmx,
+ ff_emu_edge_vfix7_mmx, ff_emu_edge_vfix8_mmx, ff_emu_edge_vfix9_mmx,
+ ff_emu_edge_vfix10_mmx, ff_emu_edge_vfix11_mmx, ff_emu_edge_vfix12_mmx,
+ ff_emu_edge_vfix13_mmx, ff_emu_edge_vfix14_mmx, ff_emu_edge_vfix15_mmx,
+ ff_emu_edge_vfix16_sse, ff_emu_edge_vfix17_sse, ff_emu_edge_vfix18_sse,
+ ff_emu_edge_vfix19_sse, ff_emu_edge_vfix20_sse, ff_emu_edge_vfix21_sse,
+ ff_emu_edge_vfix22_sse
+};
+extern emu_edge_vvar_func ff_emu_edge_vvar_sse;
+
+typedef void emu_edge_hfix_func(uint8_t *dst, x86_reg dst_stride,
+ x86_reg start_x, x86_reg bh);
+typedef void emu_edge_hvar_func(uint8_t *dst, x86_reg dst_stride,
+ x86_reg start_x, x86_reg n_words, x86_reg bh);
+
+extern emu_edge_hfix_func ff_emu_edge_hfix2_mmx;
+extern emu_edge_hfix_func ff_emu_edge_hfix4_mmx;
+extern emu_edge_hfix_func ff_emu_edge_hfix6_mmx;
+extern emu_edge_hfix_func ff_emu_edge_hfix8_mmx;
+extern emu_edge_hfix_func ff_emu_edge_hfix10_mmx;
+extern emu_edge_hfix_func ff_emu_edge_hfix12_mmx;
+extern emu_edge_hfix_func ff_emu_edge_hfix14_mmx;
+extern emu_edge_hfix_func ff_emu_edge_hfix16_mmx;
+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] = {
+ 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,
+ ff_emu_edge_hfix20_mmx, ff_emu_edge_hfix22_mmx
+};
+#endif
+extern emu_edge_hvar_func ff_emu_edge_hvar_mmx;
+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] = {
+ 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;
+
+static av_always_inline void emulated_edge_mc(uint8_t *dst, ptrdiff_t dst_stride,
+ const uint8_t *src, ptrdiff_t src_stride,
+ 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_vvar_func *v_extend_var,
+ emu_edge_hfix_func **hfix_tbl,
+ emu_edge_hvar_func *h_extend_var)
{
- int start_y, start_x, end_y, end_x, src_y_add = 0;
+ x86_reg start_y, start_x, end_y, end_x, src_y_add = 0, p;
+
+ if(!w || !h)
+ return;
if (src_y >= h) {
- src_y_add = h - 1 - src_y;
+ src -= src_y*src_stride;
+ src_y_add = h - 1;
src_y = h - 1;
} else if (src_y <= -block_h) {
- src_y_add = 1 - block_h - src_y;
+ src -= src_y*src_stride;
+ src_y_add = 1 - block_h;
src_y = 1 - block_h;
}
if (src_x >= w) {
@@ -64,34 +165,73 @@ static av_always_inline void 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_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) * linesize + start_x;
- buf += start_x;
- core_fn(buf, src, linesize, start_y, end_y,
- block_h, start_x, end_x, block_w);
+ 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, dst_stride, src, src_stride,
+ start_y, end_y, block_h);
+ } else {
+ v_extend_var(dst + start_x, dst_stride, src, src_stride,
+ start_y, end_y, block_h, w);
+ }
+
+ // fill left
+ if (start_x) {
+ if (start_x <= 22) {
+ hfix_tbl[(start_x - 1) >> 1](dst, dst_stride, start_x, block_h);
+ } else {
+ h_extend_var(dst, dst_stride,
+ start_x, (start_x + 1) >> 1, block_h);
+ }
+ }
+
+ // fill right
+ p = block_w - end_x;
+ if (p) {
+ if (p <= 22) {
+ hfix_tbl[(p - 1) >> 1](dst + end_x - (p & 1), dst_stride,
+ -!(p & 1), block_h);
+ } else {
+ h_extend_var(dst + end_x - (p & 1), dst_stride,
+ -!(p & 1), (p + 1) >> 1, block_h);
+ }
+ }
}
#if ARCH_X86_32
-static av_noinline void emulated_edge_mc_mmx(uint8_t *buf, const uint8_t *src,
- ptrdiff_t linesize,
+static av_noinline void emulated_edge_mc_mmx(uint8_t *buf, ptrdiff_t buf_stride,
+ const uint8_t *src, 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, linesize, block_w, block_h, src_x, src_y,
- w, h, &ff_emu_edge_core_mmx);
+ emulated_edge_mc(buf, buf_stride, src, src_stride, block_w, block_h,
+ src_x, src_y, w, h, vfixtbl_mmx, &ff_emu_edge_vvar_mmx,
+ hfixtbl_mmx, &ff_emu_edge_hvar_mmx);
}
-#endif
-static av_noinline void emulated_edge_mc_sse(uint8_t *buf, const uint8_t *src,
- ptrdiff_t linesize,
+static av_noinline void emulated_edge_mc_sse(uint8_t *buf, ptrdiff_t buf_stride,
+ const uint8_t *src, 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, linesize, block_w, block_h, src_x, src_y,
- w, h, &ff_emu_edge_core_sse);
+ emulated_edge_mc(buf, buf_stride, src, src_stride, block_w, block_h,
+ src_x, src_y, w, h, vfixtbl_sse, &ff_emu_edge_vvar_sse,
+ hfixtbl_mmx, &ff_emu_edge_hvar_mmx);
+}
+#endif
+
+static av_noinline void emulated_edge_mc_sse2(uint8_t *buf, ptrdiff_t buf_stride,
+ const uint8_t *src, ptrdiff_t src_stride,
+ int block_w, int block_h,
+ int src_x, int src_y, int w, int h)
+{
+ emulated_edge_mc(buf, buf_stride, src, 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);
}
#endif /* HAVE_YASM */
@@ -114,8 +254,13 @@ av_cold void ff_videodsp_init_x86(VideoDSPContext *ctx, int bpc)
if (EXTERNAL_MMXEXT(cpu_flags)) {
ctx->prefetch = ff_prefetch_mmxext;
}
+#if ARCH_X86_32
if (EXTERNAL_SSE(cpu_flags) && bpc <= 8) {
ctx->emulated_edge_mc = emulated_edge_mc_sse;
}
+#endif /* ARCH_X86_32 */
+ if (EXTERNAL_SSE2(cpu_flags) && bpc <= 8) {
+ ctx->emulated_edge_mc = emulated_edge_mc_sse2;
+ }
#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 2a978b6..284a528 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 9e38014..1f02a6f 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/dsputil.h"
#include "libavcodec/vp3dsp.h"
@@ -40,10 +43,68 @@ 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"
+
+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_MMX_INLINE */
+
av_cold void ff_vp3dsp_init_x86(VP3DSPContext *c, int flags)
{
int cpu_flags = av_get_cpu_flags();
+#if HAVE_MMX_INLINE
+ c->put_no_rnd_pixels_l2 = put_vp_no_rnd_pixels8_l2_mmx;
+#endif /* 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..e71dbf8 100644
--- a/libavcodec/x86/vp56_arith.h
+++ b/libavcodec/x86/vp56_arith.h
@@ -4,20 +4,20 @@
* 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
*/
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 c4a500b..8718e23 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 1d7aadc..ca07333 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 Jason Garrett-Glaser <darkshikari@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with 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_init.c b/libavcodec/x86/vp8dsp_init.c
index 6d06666..dca00f5 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 Jason Garrett-Glaser <darkshikari@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -381,7 +381,7 @@ av_cold void ff_vp8dsp_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);
diff --git a/libavcodec/x86/vp9dsp.asm b/libavcodec/x86/vp9dsp.asm
new file mode 100644
index 0000000..f81ac72
--- a/dev/null
+++ b/libavcodec/x86/vp9dsp.asm
@@ -0,0 +1,278 @@
+;******************************************************************************
+;* VP9 SIMD optimizations
+;*
+;* Copyright (c) 2013 Ronald S. Bultje <rsbultje gmail com>
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+
+; FIXME share with vp8dsp.asm
+pw_256: times 8 dw 256
+
+%macro F8_TAPS 8
+times 8 db %1, %2
+times 8 db %3, %4
+times 8 db %5, %6
+times 8 db %7, %8
+%endmacro
+; int8_t ff_filters_ssse3[3][15][4][16]
+const filters_ssse3 ; smooth
+ F8_TAPS -3, -1, 32, 64, 38, 1, -3, 0
+ F8_TAPS -2, -2, 29, 63, 41, 2, -3, 0
+ F8_TAPS -2, -2, 26, 63, 43, 4, -4, 0
+ F8_TAPS -2, -3, 24, 62, 46, 5, -4, 0
+ F8_TAPS -2, -3, 21, 60, 49, 7, -4, 0
+ F8_TAPS -1, -4, 18, 59, 51, 9, -4, 0
+ F8_TAPS -1, -4, 16, 57, 53, 12, -4, -1
+ F8_TAPS -1, -4, 14, 55, 55, 14, -4, -1
+ F8_TAPS -1, -4, 12, 53, 57, 16, -4, -1
+ F8_TAPS 0, -4, 9, 51, 59, 18, -4, -1
+ F8_TAPS 0, -4, 7, 49, 60, 21, -3, -2
+ F8_TAPS 0, -4, 5, 46, 62, 24, -3, -2
+ F8_TAPS 0, -4, 4, 43, 63, 26, -2, -2
+ F8_TAPS 0, -3, 2, 41, 63, 29, -2, -2
+ F8_TAPS 0, -3, 1, 38, 64, 32, -1, -3
+ ; regular
+ F8_TAPS 0, 1, -5, 126, 8, -3, 1, 0
+ F8_TAPS -1, 3, -10, 122, 18, -6, 2, 0
+ F8_TAPS -1, 4, -13, 118, 27, -9, 3, -1
+ F8_TAPS -1, 4, -16, 112, 37, -11, 4, -1
+ F8_TAPS -1, 5, -18, 105, 48, -14, 4, -1
+ F8_TAPS -1, 5, -19, 97, 58, -16, 5, -1
+ F8_TAPS -1, 6, -19, 88, 68, -18, 5, -1
+ F8_TAPS -1, 6, -19, 78, 78, -19, 6, -1
+ F8_TAPS -1, 5, -18, 68, 88, -19, 6, -1
+ F8_TAPS -1, 5, -16, 58, 97, -19, 5, -1
+ F8_TAPS -1, 4, -14, 48, 105, -18, 5, -1
+ F8_TAPS -1, 4, -11, 37, 112, -16, 4, -1
+ F8_TAPS -1, 3, -9, 27, 118, -13, 4, -1
+ F8_TAPS 0, 2, -6, 18, 122, -10, 3, -1
+ F8_TAPS 0, 1, -3, 8, 126, -5, 1, 0
+ ; sharp
+ F8_TAPS -1, 3, -7, 127, 8, -3, 1, 0
+ F8_TAPS -2, 5, -13, 125, 17, -6, 3, -1
+ F8_TAPS -3, 7, -17, 121, 27, -10, 5, -2
+ F8_TAPS -4, 9, -20, 115, 37, -13, 6, -2
+ F8_TAPS -4, 10, -23, 108, 48, -16, 8, -3
+ F8_TAPS -4, 10, -24, 100, 59, -19, 9, -3
+ F8_TAPS -4, 11, -24, 90, 70, -21, 10, -4
+ F8_TAPS -4, 11, -23, 80, 80, -23, 11, -4
+ F8_TAPS -4, 10, -21, 70, 90, -24, 11, -4
+ F8_TAPS -3, 9, -19, 59, 100, -24, 10, -4
+ F8_TAPS -3, 8, -16, 48, 108, -23, 10, -4
+ F8_TAPS -2, 6, -13, 37, 115, -20, 9, -4
+ F8_TAPS -2, 5, -10, 27, 121, -17, 7, -3
+ F8_TAPS -1, 3, -6, 17, 125, -13, 5, -2
+ F8_TAPS 0, 1, -3, 8, 127, -7, 3, -1
+
+SECTION .text
+
+%macro filter_h_fn 1
+%assign %%px mmsize/2
+cglobal %1_8tap_1d_h_ %+ %%px, 6, 6, 11, dst, 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]
+%endif
+.loop:
+ movh m0, [srcq-3]
+ movh m1, [srcq-2]
+ movh m2, [srcq-1]
+ movh m3, [srcq+0]
+ movh m4, [srcq+1]
+ movh m5, [srcq+2]
+ punpcklbw m0, m1
+ punpcklbw m2, m3
+ movh m1, [srcq+3]
+ movh m3, [srcq+4]
+ add srcq, sstrideq
+ punpcklbw m4, m5
+ punpcklbw m1, m3
+ pmaddubsw m0, m7
+%if ARCH_X86_64 && mmsize > 8
+ pmaddubsw m2, m8
+ pmaddubsw m4, m9
+ pmaddubsw m1, m10
+%else
+ pmaddubsw m2, [filteryq+16]
+ pmaddubsw m4, [filteryq+32]
+ pmaddubsw m1, [filteryq+48]
+%endif
+ paddw m0, m2
+ paddw m4, m1
+ paddsw m0, m4
+ pmulhrsw m0, m6
+%ifidn %1, avg
+ movh m1, [dstq]
+%endif
+ packuswb m0, m0
+%ifidn %1, avg
+ pavgb m0, m1
+%endif
+ movh [dstq], m0
+ add dstq, dstrideq
+ dec hd
+ jg .loop
+ RET
+%endmacro
+
+INIT_MMX ssse3
+filter_h_fn put
+filter_h_fn avg
+
+INIT_XMM ssse3
+filter_h_fn put
+filter_h_fn avg
+
+%macro filter_v_fn 1
+%assign %%px mmsize/2
+%if ARCH_X86_64
+cglobal %1_8tap_1d_v_ %+ %%px, 6, 8, 11, dst, dstride, src, sstride, h, filtery, src4, sstride3
+%else
+cglobal %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
+ mova m7, [filteryq+ 0]
+ lea src4q, [srcq+sstrideq*4]
+%if ARCH_X86_64 && mmsize > 8
+ mova m8, [filteryq+16]
+ mova m9, [filteryq+32]
+ mova m10, [filteryq+48]
+%endif
+.loop:
+ ; FIXME maybe reuse loads from previous rows, or just
+ ; more generally unroll this to prevent multiple loads of
+ ; the same data?
+ movh m0, [srcq]
+ movh m1, [srcq+sstrideq]
+ movh m2, [srcq+sstrideq*2]
+ movh m3, [srcq+sstride3q]
+ movh m4, [src4q]
+ movh m5, [src4q+sstrideq]
+ punpcklbw m0, m1
+ punpcklbw m2, m3
+ movh m1, [src4q+sstrideq*2]
+ movh m3, [src4q+sstride3q]
+ add srcq, sstrideq
+ add src4q, sstrideq
+ punpcklbw m4, m5
+ punpcklbw m1, m3
+ pmaddubsw m0, m7
+%if ARCH_X86_64 && mmsize > 8
+ pmaddubsw m2, m8
+ pmaddubsw m4, m9
+ pmaddubsw m1, m10
+%else
+ pmaddubsw m2, [filteryq+16]
+ pmaddubsw m4, [filteryq+32]
+ pmaddubsw m1, [filteryq+48]
+%endif
+ paddw m0, m2
+ paddw m4, m1
+ paddsw m0, m4
+ pmulhrsw m0, m6
+%ifidn %1, avg
+ movh m1, [dstq]
+%endif
+ packuswb m0, m0
+%ifidn %1, avg
+ pavgb m0, m1
+%endif
+ movh [dstq], m0
+ add dstq, dstrideq
+ dec hd
+ jg .loop
+ RET
+%endmacro
+
+INIT_MMX ssse3
+filter_v_fn put
+filter_v_fn avg
+
+INIT_XMM ssse3
+filter_v_fn put
+filter_v_fn avg
+
+%macro fpel_fn 6
+%if %2 == 4
+%define %%srcfn movh
+%define %%dstfn movh
+%else
+%define %%srcfn movu
+%define %%dstfn mova
+%endif
+
+%if %2 <= 16
+cglobal %1%2, 5, 7, 4, dst, dstride, src, sstride, h, dstride3, sstride3
+ lea sstride3q, [sstrideq*3]
+ lea dstride3q, [dstrideq*3]
+%else
+cglobal %1%2, 5, 5, 4, dst, dstride, src, sstride, h
+%endif
+.loop:
+ %%srcfn m0, [srcq]
+ %%srcfn m1, [srcq+s%3]
+ %%srcfn m2, [srcq+s%4]
+ %%srcfn m3, [srcq+s%5]
+ lea srcq, [srcq+sstrideq*%6]
+%ifidn %1, avg
+ pavgb m0, [dstq]
+ pavgb m1, [dstq+d%3]
+ pavgb m2, [dstq+d%4]
+ pavgb m3, [dstq+d%5]
+%endif
+ %%dstfn [dstq], m0
+ %%dstfn [dstq+d%3], m1
+ %%dstfn [dstq+d%4], m2
+ %%dstfn [dstq+d%5], m3
+ lea dstq, [dstq+dstrideq*%6]
+ sub hd, %6
+ jnz .loop
+ RET
+%endmacro
+
+%define d16 16
+%define s16 16
+INIT_MMX mmx
+fpel_fn put, 4, strideq, strideq*2, stride3q, 4
+fpel_fn put, 8, strideq, strideq*2, stride3q, 4
+INIT_MMX sse
+fpel_fn avg, 4, strideq, strideq*2, stride3q, 4
+fpel_fn avg, 8, strideq, strideq*2, stride3q, 4
+INIT_XMM sse
+fpel_fn put, 16, strideq, strideq*2, stride3q, 4
+fpel_fn put, 32, mmsize, strideq, strideq+mmsize, 2
+fpel_fn put, 64, mmsize, mmsize*2, mmsize*3, 1
+INIT_XMM sse2
+fpel_fn avg, 16, strideq, strideq*2, stride3q, 4
+fpel_fn avg, 32, mmsize, strideq, strideq+mmsize, 2
+fpel_fn avg, 64, mmsize, mmsize*2, mmsize*3, 1
+%undef s16
+%undef d16
diff --git a/libavcodec/x86/vp9dsp_init.c b/libavcodec/x86/vp9dsp_init.c
new file mode 100644
index 0000000..cf7a1a4
--- a/dev/null
+++ b/libavcodec/x86/vp9dsp_init.c
@@ -0,0 +1,214 @@
+/*
+ * VP9 SIMD optimizations
+ *
+ * Copyright (c) 2013 Ronald S. Bultje <rsbultje gmail com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/cpu.h"
+#include "libavutil/mem.h"
+#include "libavutil/x86/asm.h"
+#include "libavcodec/vp9dsp.h"
+
+#if HAVE_YASM
+
+#define fpel_func(avg, sz, opt) \
+void ff_##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, 16, sse2);
+fpel_func(avg, 32, sse2);
+fpel_func(avg, 64, sse2);
+#undef fpel_func
+
+#define mc_func(avg, sz, dir, opt) \
+void ff_##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)[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);
+
+#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, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, const int8_t (*filter)[16]) \
+{ \
+ ff_##avg##_8tap_1d_##dir##_##hsz##_##opt(dst, dst_stride, src, \
+ src_stride, h, filter); \
+ ff_##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);
+
+#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, ptrdiff_t dst_stride, \
+ const uint8_t *src, 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, 64, src - 3 * src_stride, src_stride, \
+ h + 7, ff_filters_ssse3[f][mx - 1]); \
+ ff_##op##_8tap_1d_v_##sz##_ssse3(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)
+
+#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, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, int mx, int my) \
+{ \
+ ff_##op##_8tap_1d_##dir##_##sz##_ssse3(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)
+
+#undef filters_8tap_1d_fn
+#undef filters_8tap_1d_fn2
+#undef filters_8tap_1d_fn3
+#undef filter_8tap_1d_fn
+
+#endif /* HAVE_YASM */
+
+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_subpel1(idx1, idx2, idxh, idxv, sz, dir, type, opt) \
+ dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][idxh][idxv] = type##_8tap_smooth_##sz##dir##_##opt; \
+ dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][idxh][idxv] = type##_8tap_regular_##sz##dir##_##opt; \
+ dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][idxh][idxv] = type##_8tap_sharp_##sz##dir##_##opt
+
+#define init_subpel2(idx, idxh, idxv, dir, type, opt) \
+ init_subpel1(0, idx, idxh, idxv, 64, dir, type, opt); \
+ init_subpel1(1, idx, idxh, idxv, 32, dir, type, opt); \
+ init_subpel1(2, idx, idxh, idxv, 16, dir, type, opt); \
+ init_subpel1(3, idx, idxh, idxv, 8, dir, type, opt); \
+ init_subpel1(4, idx, idxh, idxv, 4, dir, type, opt)
+
+#define init_subpel3(idx, type, opt) \
+ init_subpel2(idx, 1, 1, hv, type, opt); \
+ init_subpel2(idx, 0, 1, v, type, opt); \
+ init_subpel2(idx, 1, 0, h, type, opt)
+
+ if (cpu_flags & AV_CPU_FLAG_MMX) {
+ init_fpel(4, 0, 4, put, mmx);
+ init_fpel(3, 0, 8, put, mmx);
+ }
+
+ if (cpu_flags & AV_CPU_FLAG_SSE) {
+ 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 (cpu_flags & AV_CPU_FLAG_SSE2) {
+ init_fpel(2, 1, 16, avg, sse2);
+ init_fpel(1, 1, 32, avg, sse2);
+ init_fpel(0, 1, 64, avg, sse2);
+ }
+
+ if (cpu_flags & AV_CPU_FLAG_SSSE3) {
+ init_subpel3(0, put, ssse3);
+ init_subpel3(1, avg, ssse3);
+ }
+
+#undef init_fpel
+#undef init_subpel1
+#undef init_subpel2
+#undef init_subpel3
+
+#endif /* HAVE_YASM */
+}
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/xan.c b/libavcodec/xan.c
index ed2563c..1c2e97c 100644
--- a/libavcodec/xan.c
+++ b/libavcodec/xan.c
@@ -2,20 +2,20 @@
* Wing Commander/Xan Video Decoder
* 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,15 +52,15 @@
typedef struct XanContext {
AVCodecContext *avctx;
- AVFrame last_frame;
+ 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;
@@ -71,6 +71,8 @@ typedef struct XanContext {
} XanContext;
+static av_cold int xan_decode_end(AVCodecContext *avctx);
+
static av_cold int xan_decode_init(AVCodecContext *avctx)
{
XanContext *s = avctx->priv_data;
@@ -90,20 +92,25 @@ static av_cold int xan_decode_init(AVCodecContext *avctx)
av_freep(&s->buffer1);
return AVERROR(ENOMEM);
}
+ s->last_frame = av_frame_alloc();
+ if (!s->last_frame) {
+ xan_decode_end(avctx);
+ return AVERROR(ENOMEM);
+ }
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;
GetBitContext gb;
if (ptr_len < 0)
@@ -133,13 +140,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);
@@ -188,14 +195,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];
@@ -227,14 +234,14 @@ 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)
return;
palette_plane = frame->data[0];
- prev_palette_plane = s->last_frame.data[0];
+ prev_palette_plane = s->last_frame->data[0];
if (!prev_palette_plane)
prev_palette_plane = palette_plane;
stride = frame->linesize[0];
@@ -243,6 +250,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) {
@@ -275,22 +288,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;
@@ -363,16 +376,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;
}
@@ -394,8 +419,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);
@@ -515,6 +545,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:
@@ -538,7 +572,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;
@@ -565,10 +599,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;
@@ -582,8 +614,8 @@ static int xan_decode_frame(AVCodecContext *avctx,
if (xan_wc3_decode_frame(s, frame) < 0)
return AVERROR_INVALIDDATA;
- av_frame_unref(&s->last_frame);
- if ((ret = av_frame_ref(&s->last_frame, frame)) < 0)
+ av_frame_unref(s->last_frame);
+ if ((ret = av_frame_ref(s->last_frame, frame)) < 0)
return ret;
*got_frame = 1;
@@ -596,7 +628,7 @@ static av_cold int xan_decode_end(AVCodecContext *avctx)
{
XanContext *s = avctx->priv_data;
- av_frame_unref(&s->last_frame);
+ av_frame_free(&s->last_frame);
av_freep(&s->buffer1);
av_freep(&s->buffer2);
diff --git a/libavcodec/xbmdec.c b/libavcodec/xbmdec.c
new file mode 100644
index 0000000..2976bec
--- a/dev/null
+++ b/libavcodec/xbmdec.c
@@ -0,0 +1,119 @@
+/*
+ * XBM image format
+ *
+ * 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 "mathops.h"
+#include "libavutil/avstring.h"
+
+static av_cold int xbm_decode_init(AVCodecContext *avctx)
+{
+ avctx->pix_fmt = AV_PIX_FMT_MONOWHITE;
+
+ return 0;
+}
+
+static int convert(uint8_t x)
+{
+ if (x >= 'a')
+ x -= 87;
+ else if (x >= 'A')
+ x -= 55;
+ else
+ x -= '0';
+ return x;
+}
+
+static int xbm_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *avpkt)
+{
+ AVFrame *p = data;
+ const uint8_t *end, *ptr = avpkt->data;
+ uint8_t *dst;
+ int ret, linesize, i, j;
+
+ end = avpkt->data + avpkt->size;
+ while (!avctx->width || !avctx->height) {
+ char name[256];
+ int number, len;
+
+ ptr += strcspn(ptr, "#");
+ if (sscanf(ptr, "#define %255s %u", name, &number) != 2) {
+ av_log(avctx, AV_LOG_ERROR, "Unexpected preprocessor directive\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ len = strlen(name);
+ if ((len > 6) && !avctx->height && !memcmp(name + len - 7, "_height", 7)) {
+ avctx->height = number;
+ } else if ((len > 5) && !avctx->width && !memcmp(name + len - 6, "_width", 6)) {
+ avctx->width = number;
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "Unknown define '%s'\n", name);
+ return AVERROR_INVALIDDATA;
+ }
+ ptr += strcspn(ptr, "\n\r") + 1;
+ }
+
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
+ return ret;
+
+ // goto start of image data
+ ptr += strcspn(ptr, "{") + 1;
+
+ linesize = (avctx->width + 7) / 8;
+ for (i = 0; i < avctx->height; i++) {
+ dst = p->data[0] + i * p->linesize[0];
+ for (j = 0; j < linesize; j++) {
+ uint8_t val;
+
+ ptr += strcspn(ptr, "x") + 1;
+ if (ptr < end && av_isxdigit(*ptr)) {
+ val = convert(*ptr);
+ 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;
+ }
+ }
+ }
+
+ p->key_frame = 1;
+ p->pict_type = AV_PICTURE_TYPE_I;
+
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+AVCodec ff_xbm_decoder = {
+ .name = "xbm",
+ .long_name = NULL_IF_CONFIG_SMALL("XBM (X BitMap) image"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_XBM,
+ .init = xbm_decode_init,
+ .decode = xbm_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/xbmenc.c b/libavcodec/xbmenc.c
index 8616372..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 = avcodec_alloc_frame();
- 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_freep(&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
--- a/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
--- a/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
--- a/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..e737f6d
--- a/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 = avcodec_alloc_frame();
+ 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..0636f8e 100644
--- a/libavcodec/xiph.c
+++ b/libavcodec/xiph.c
@@ -1,20 +1,20 @@
/*
- * Copyright (C) 2007 Libav Project
+ * Copyright (C) 2007 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/xiph.h b/libavcodec/xiph.h
index afaece7..cd8caa4 100644
--- a/libavcodec/xiph.h
+++ b/libavcodec/xiph.h
@@ -1,20 +1,20 @@
/*
- * Copyright (C) 2007 Libav Project
+ * Copyright (C) 2007 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/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..9dc80ee 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
@@ -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);
diff --git a/libavcodec/xvmc.h b/libavcodec/xvmc.h
index 1f77e4e..b2bf518 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
*/
diff --git a/libavcodec/xvmc_internal.h b/libavcodec/xvmc_internal.h
index 3c6aed8..04197ce 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
*/
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 8963c96..c28e19f 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
*/
@@ -141,7 +141,7 @@ static int xwd_decode_frame(AVCodecContext *avctx, void *data,
}
if (pixformat != XWD_Z_PIXMAP) {
- av_log(avctx, AV_LOG_ERROR, "pixmap format %d unsupported\n", pixformat);
+ avpriv_report_missing_feature(avctx, "Pixmap format %d", pixformat);
return AVERROR_PATCHWELCOME;
}
@@ -149,10 +149,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:
@@ -198,10 +201,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 87d6cff..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 = avcodec_alloc_frame();
- 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 7446305..56d5f49 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
*/
@@ -30,7 +30,7 @@
typedef struct XanContext {
AVCodecContext *avctx;
- AVFrame pic;
+ AVFrame *pic;
uint8_t *y_buffer;
uint8_t *scratch_buffer;
@@ -38,6 +38,8 @@ typedef struct XanContext {
GetByteContext gb;
} XanContext;
+static av_cold int xan_decode_end(AVCodecContext *avctx);
+
static av_cold int xan_decode_init(AVCodecContext *avctx)
{
XanContext *s = avctx->priv_data;
@@ -61,7 +63,13 @@ 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);
+ }
+
+ s->pic = av_frame_alloc();
+ if (!s->pic) {
+ xan_decode_end(avctx);
return AVERROR(ENOMEM);
}
@@ -199,39 +207,45 @@ static int xan_decode_chroma(AVCodecContext *avctx, unsigned chroma_off)
return dec_size;
}
- U = s->pic.data[1];
- V = s->pic.data[2];
+ U = s->pic->data[1];
+ V = s->pic->data[2];
src = s->scratch_buffer;
src_end = src + dec_size;
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];
+ U += s->pic->linesize[1];
+ V += s->pic->linesize[2];
}
if (avctx->height & 1) {
- memcpy(U, U - s->pic.linesize[1], avctx->width >> 1);
- memcpy(V, V - s->pic.linesize[2], avctx->width >> 1);
+ memcpy(U, U - s->pic->linesize[1], avctx->width >> 1);
+ memcpy(V, V - s->pic->linesize[2], avctx->width >> 1);
}
} else {
- uint8_t *U2 = U + s->pic.linesize[1];
- uint8_t *V2 = V + s->pic.linesize[2];
+ uint8_t *U2 = U + s->pic->linesize[1];
+ uint8_t *V2 = V + s->pic->linesize[2];
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;
@@ -239,16 +253,16 @@ static int xan_decode_chroma(AVCodecContext *avctx, unsigned chroma_off)
V[i] = V[i+1] = V2[i] = V2[i+1] = vval | (vval >> 5);
}
}
- U += s->pic.linesize[1] * 2;
- V += s->pic.linesize[2] * 2;
- U2 += s->pic.linesize[1] * 2;
- V2 += s->pic.linesize[2] * 2;
+ U += s->pic->linesize[1] * 2;
+ V += s->pic->linesize[2] * 2;
+ U2 += s->pic->linesize[1] * 2;
+ V2 += s->pic->linesize[2] * 2;
}
if (avctx->height & 3) {
int lines = ((avctx->height + 1) >> 1) - (avctx->height >> 2) * 2;
- memcpy(U, U - lines * s->pic.linesize[1], lines * s->pic.linesize[1]);
- memcpy(V, V - lines * s->pic.linesize[2], lines * s->pic.linesize[2]);
+ memcpy(U, U - lines * s->pic->linesize[1], lines * s->pic->linesize[1]);
+ memcpy(V, V - lines * s->pic->linesize[2], lines * s->pic->linesize[2]);
}
}
@@ -270,7 +284,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;
}
@@ -315,17 +329,20 @@ 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;
}
src = s->y_buffer;
- ybuf = s->pic.data[0];
+ ybuf = s->pic->data[0];
for (j = 0; j < avctx->height; j++) {
for (i = 0; i < avctx->width; i++)
ybuf[i] = (src[i] << 2) | (src[i] >> 3);
src += avctx->width;
- ybuf += s->pic.linesize[0];
+ ybuf += s->pic->linesize[0];
}
return 0;
@@ -365,12 +382,12 @@ static int xan_decode_frame_type1(AVCodecContext *avctx)
}
src = s->y_buffer;
- ybuf = s->pic.data[0];
+ ybuf = s->pic->data[0];
for (j = 0; j < avctx->height; j++) {
for (i = 0; i < avctx->width; i++)
ybuf[i] = (src[i] << 2) | (src[i] >> 3);
src += avctx->width;
- ybuf += s->pic.linesize[0];
+ ybuf += s->pic->linesize[0];
}
return 0;
@@ -384,10 +401,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);
@@ -405,7 +420,7 @@ static int xan_decode_frame(AVCodecContext *avctx,
if (ret)
return ret;
- if ((ret = av_frame_ref(data, &s->pic)) < 0)
+ if ((ret = av_frame_ref(data, s->pic)) < 0)
return ret;
*got_frame = 1;
@@ -417,7 +432,7 @@ static av_cold int xan_decode_end(AVCodecContext *avctx)
{
XanContext *s = avctx->priv_data;
- av_frame_unref(&s->pic);
+ av_frame_free(&s->pic);
av_freep(&s->y_buffer);
av_freep(&s->scratch_buffer);
diff --git a/libavcodec/y41pdec.c b/libavcodec/y41pdec.c
new file mode 100644
index 0000000..9d1e531
--- a/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..41666cc
--- a/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 = avcodec_alloc_frame();
+ 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
--- a/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..8d3907b
--- a/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 = avcodec_alloc_frame();
+
+ 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 135a809..80264b3 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 d17f37a..71e8287 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;
@@ -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 == NULL) {
@@ -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)) == NULL) {
+ if ((c->decomp_buf = av_mallocz(c->decomp_size)) == NULL) {
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 c039383..2907c99 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
*/
@@ -44,8 +44,6 @@
*/
typedef struct ZmbvEncContext {
AVCodecContext *avctx;
- AVFrame pic;
-
int range;
uint8_t *comp_buf, *work_buf;
uint8_t pal[768];
@@ -121,7 +119,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *pict, int *got_packet)
{
ZmbvEncContext * const c = avctx->priv_data;
- AVFrame * const p = &c->pic;
+ AVFrame * const p = (AVFrame *)pict;
uint8_t *src, *prev, *buf;
uint32_t *palptr;
int keyframe, chpal;
@@ -134,7 +132,6 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
c->curfrm++;
if(c->curfrm == c->keyint)
c->curfrm = 0;
- *p = *pict;
p->pict_type= keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
p->key_frame= keyframe;
chpal = !keyframe && memcmp(p->data[1], c->pal2, 1024);
@@ -229,10 +226,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);
@@ -314,8 +309,6 @@ static av_cold int encode_init(AVCodecContext *avctx)
return -1;
}
- avctx->coded_frame = &c->pic;
-
return 0;
}
diff --git a/libavdevice/Makefile b/libavdevice/Makefile
index 8fdae2d..21ca954 100644
--- a/libavdevice/Makefile
+++ b/libavdevice/Makefile
@@ -1,5 +1,8 @@
+include $(SUBDIR)../config.mak
+
NAME = avdevice
FFLIBS = avformat avcodec avutil
+FFLIBS-$(CONFIG_LAVFI_INDEV) += avfilter
HEADERS = avdevice.h \
version.h \
@@ -11,26 +14,47 @@ OBJS-$(HAVE_MSVCRT) += file_open.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_BKTR_INDEV) += bktr.o
+OBJS-$(CONFIG_CACA_OUTDEV) += caca.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_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_OSS_INDEV) += oss_audio.o
OBJS-$(CONFIG_OSS_OUTDEV) += oss_audio.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_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_XV_OUTDEV) += xv.o
# external libraries
OBJS-$(CONFIG_LIBCDIO_INDEV) += libcdio.o
OBJS-$(CONFIG_LIBDC1394_INDEV) += libdc1394.o
+SKIPHEADERS-$(CONFIG_DSHOW_INDEV) += dshow_capture.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 155f7a8..5178f30 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) \
@@ -49,15 +48,23 @@ void avdevice_register_all(void)
/* devices */
REGISTER_INOUTDEV(ALSA, alsa);
REGISTER_INDEV (BKTR, bktr);
+ REGISTER_OUTDEV (CACA, caca);
+ REGISTER_INDEV (DSHOW, dshow);
REGISTER_INDEV (DV1394, dv1394);
- REGISTER_INDEV (FBDEV, fbdev);
+ REGISTER_INOUTDEV(FBDEV, fbdev);
+ REGISTER_INDEV (IEC61883, iec61883);
REGISTER_INDEV (JACK, jack);
+ REGISTER_INDEV (LAVFI, lavfi);
+ REGISTER_INDEV (OPENAL, openal);
REGISTER_INOUTDEV(OSS, oss);
- REGISTER_INDEV (PULSE, pulse);
+ REGISTER_INOUTDEV(PULSE, pulse);
+ 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_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..4e63397 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;
}
diff --git a/libavdevice/alsa-audio-dec.c b/libavdevice/alsa-audio-dec.c
index 5b32ed9..03154b0 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,14 +118,14 @@ 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
- - 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;
diff --git a/libavdevice/alsa-audio-enc.c b/libavdevice/alsa-audio-enc.c
index bb4575f..0f4e4a2 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,8 +38,10 @@
*/
#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)
@@ -61,6 +63,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;
@@ -101,6 +104,17 @@ static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt)
return 0;
}
+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 = s1->streams[0]->cur_dts - delay;
+}
+
AVOutputFormat ff_alsa_muxer = {
.name = "alsa",
.long_name = NULL_IF_CONFIG_SMALL("ALSA audio output"),
@@ -110,5 +124,6 @@ AVOutputFormat ff_alsa_muxer = {
.write_header = audio_write_header,
.write_packet = audio_write_packet,
.write_trailer = ff_alsa_close,
+ .get_output_timestamp = audio_get_output_timestamp,
.flags = AVFMT_NOFILE,
};
diff --git a/libavdevice/alsa-audio.h b/libavdevice/alsa-audio.h
index 26eaee6..44b7c72 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,23 +32,28 @@
#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
diff --git a/libavdevice/avdevice.c b/libavdevice/avdevice.c
index 5a5c762..b9b18f2 100644
--- a/libavdevice/avdevice.c
+++ b/libavdevice/avdevice.c
@@ -1,36 +1,38 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License 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 "avdevice.h"
#include "config.h"
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;
}
diff --git a/libavdevice/avdevice.h b/libavdevice/avdevice.h
index 39166a5..93a044f 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,8 @@
* @}
*/
+#include "libavformat/avformat.h"
+
/**
* Return the LIBAVDEVICE_VERSION_INT constant.
*/
diff --git a/libavdevice/bktr.c b/libavdevice/bktr.c
index 06f4d86..4e25aa6 100644
--- a/libavdevice/bktr.c
+++ b/libavdevice/bktr.c
@@ -7,24 +7,23 @@
* 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 {
AVClass *class;
@@ -58,7 +58,6 @@ typedef struct {
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;
@@ -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 },
};
diff --git a/libavdevice/caca.c b/libavdevice/caca.c
new file mode 100644
index 0000000..0a74701
--- a/dev/null
+++ b/libavdevice/caca.c
@@ -0,0 +1,240 @@
+/*
+ * 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) {
+ av_log(s, AV_LOG_ERROR, "Failed to create canvas\n");
+ ret = AVERROR(errno);
+ 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) {
+ av_log(s, AV_LOG_ERROR, "Failed to create dither\n");
+ ret = AVERROR(errno);
+ 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) {
+ av_log(s, AV_LOG_ERROR, "Failed to create display\n");
+ list_drivers(c);
+ ret = AVERROR(errno);
+ 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,
+};
+
+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/dshow.c b/libavdevice/dshow.c
new file mode 100644
index 0000000..37efabe
--- a/dev/null
+++ b/libavdevice/dshow.c
@@ -0,0 +1,1095 @@
+/*
+ * 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;
+ 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_RGB32;
+ }
+ }
+ return avpriv_find_pix_fmt(ff_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)
+{
+ 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*100)/s->max_picture_buffer;
+
+ if(dropscore[++ctx->video_frame_num%ndropscores] <= buffer_fullness) {
+ av_log(s, AV_LOG_ERROR,
+ "real-time buffer %d%% full! frame dropped!\n", buffer_fullness);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+callback(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time)
+{
+ 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))
+ 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 += 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;
+#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 = ff_codec_get_id(avformat_get_riff_video_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 != ff_codec_get_id(avformat_get_riff_video_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)
+ goto next;
+ }
+
+ 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->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) {
+ codec->codec_id = ff_codec_get_id(avformat_get_riff_video_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->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->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, AV_PIX_FMT_NB-1, 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,
+};
+
+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..aff5019
--- a/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);
+};
+
+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
--- a/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..aaed58b
--- a/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_IEnumPins,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)
+{
+ IEnumPinsVtbl *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
--- a/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
--- a/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..30e4d95
--- a/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);
+
+ 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..0af5ea5 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--;
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.c b/libavdevice/fbdev.c
deleted file mode 100644
index 22c53a3..0000000
--- a/libavdevice/fbdev.c
+++ b/dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (c) 2011 Stefano Sabatini
- * Copyright (c) 2009 Giliard B. de Freitas <giliarde@gmail.com>
- * Copyright (C) 2002 Gunnar Monell <gmo@linux.nu>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * Linux framebuffer input device,
- * inspired by code from fbgrab.c by Gunnar Monell.
- * @see http://linux-fbdev.sourceforge.net/
- */
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <time.h>
-#include <linux/fb.h>
-
-#include "libavutil/internal.h"
-#include "libavutil/log.h"
-#include "libavutil/mem.h"
-#include "libavutil/opt.h"
-#include "libavutil/time.h"
-#include "libavutil/parseutils.h"
-#include "libavutil/pixdesc.h"
-#include "libavformat/avformat.h"
-#include "libavformat/internal.h"
-
-struct rgb_pixfmt_map_entry {
- int bits_per_pixel;
- int red_offset, green_offset, blue_offset, alpha_offset;
- enum AVPixelFormat pixfmt;
-};
-
-static struct rgb_pixfmt_map_entry rgb_pixfmt_map[] = {
- // bpp, red_offset, green_offset, blue_offset, alpha_offset, pixfmt
- { 32, 0, 8, 16, 24, AV_PIX_FMT_RGBA },
- { 32, 16, 8, 0, 24, AV_PIX_FMT_BGRA },
- { 32, 8, 16, 24, 0, AV_PIX_FMT_ARGB },
- { 32, 3, 2, 8, 0, AV_PIX_FMT_ABGR },
- { 24, 0, 8, 16, 0, AV_PIX_FMT_RGB24 },
- { 24, 16, 8, 0, 0, AV_PIX_FMT_BGR24 },
-};
-
-static enum AVPixelFormat get_pixfmt_from_fb_varinfo(struct fb_var_screeninfo *varinfo)
-{
- int i;
-
- for (i = 0; i < FF_ARRAY_ELEMS(rgb_pixfmt_map); i++) {
- struct rgb_pixfmt_map_entry *entry = &rgb_pixfmt_map[i];
- if (entry->bits_per_pixel == varinfo->bits_per_pixel &&
- entry->red_offset == varinfo->red.offset &&
- entry->green_offset == varinfo->green.offset &&
- entry->blue_offset == varinfo->blue.offset)
- return entry->pixfmt;
- }
-
- return AV_PIX_FMT_NONE;
-}
-
-typedef struct {
- AVClass *class; ///< class for private options
- int frame_size; ///< size in bytes of a grabbed frame
- AVRational framerate_q; ///< framerate
- char *framerate; ///< framerate string set by a private option
- int64_t time_frame; ///< time for the next frame to output (in 1/1000000 units)
-
- int fd; ///< framebuffer device file descriptor
- int width, height; ///< assumed frame resolution
- int frame_linesize; ///< linesize of the output frame, it is assumed to be constant
- int bytes_per_pixel;
-
- struct fb_var_screeninfo varinfo; ///< variable info;
- struct fb_fix_screeninfo fixinfo; ///< fixed info;
-
- uint8_t *data; ///< framebuffer data
-} FBDevContext;
-
-static av_cold int fbdev_read_header(AVFormatContext *avctx)
-{
- FBDevContext *fbdev = avctx->priv_data;
- AVStream *st = NULL;
- enum AVPixelFormat pix_fmt;
- int ret, flags = O_RDONLY;
-
- ret = av_parse_video_rate(&fbdev->framerate_q, fbdev->framerate);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "Could not parse framerate '%s'.\n", fbdev->framerate);
- return ret;
- }
-
- if (!(st = avformat_new_stream(avctx, NULL)))
- return AVERROR(ENOMEM);
- avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in microseconds */
-
- /* NONBLOCK is ignored by the fbdev driver, only set for consistency */
- if (avctx->flags & AVFMT_FLAG_NONBLOCK)
- flags |= O_NONBLOCK;
-
- if ((fbdev->fd = avpriv_open(avctx->filename, flags)) == -1) {
- ret = AVERROR(errno);
- av_log(avctx, AV_LOG_ERROR,
- "Could not open framebuffer device '%s': %s\n",
- avctx->filename, strerror(ret));
- return ret;
- }
-
- if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->varinfo) < 0) {
- ret = AVERROR(errno);
- av_log(avctx, AV_LOG_ERROR,
- "FBIOGET_VSCREENINFO: %s\n", strerror(errno));
- goto fail;
- }
-
- if (ioctl(fbdev->fd, FBIOGET_FSCREENINFO, &fbdev->fixinfo) < 0) {
- ret = AVERROR(errno);
- av_log(avctx, AV_LOG_ERROR,
- "FBIOGET_FSCREENINFO: %s\n", strerror(errno));
- goto fail;
- }
-
- pix_fmt = get_pixfmt_from_fb_varinfo(&fbdev->varinfo);
- if (pix_fmt == AV_PIX_FMT_NONE) {
- ret = AVERROR(EINVAL);
- av_log(avctx, AV_LOG_ERROR,
- "Framebuffer pixel format not supported.\n");
- goto fail;
- }
-
- fbdev->width = fbdev->varinfo.xres;
- fbdev->height = fbdev->varinfo.yres;
- fbdev->bytes_per_pixel = (fbdev->varinfo.bits_per_pixel + 7) >> 3;
- fbdev->frame_linesize = fbdev->width * fbdev->bytes_per_pixel;
- fbdev->frame_size = fbdev->frame_linesize * fbdev->height;
- fbdev->time_frame = AV_NOPTS_VALUE;
- fbdev->data = mmap(NULL, fbdev->fixinfo.smem_len, PROT_READ, MAP_SHARED, fbdev->fd, 0);
- if (fbdev->data == MAP_FAILED) {
- ret = AVERROR(errno);
- av_log(avctx, AV_LOG_ERROR, "Error in mmap(): %s\n", strerror(errno));
- goto fail;
- }
-
- st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
- st->codec->width = fbdev->width;
- st->codec->height = fbdev->height;
- st->codec->pix_fmt = pix_fmt;
- st->codec->time_base = (AVRational){fbdev->framerate_q.den, fbdev->framerate_q.num};
- st->codec->bit_rate =
- fbdev->width * fbdev->height * fbdev->bytes_per_pixel * av_q2d(fbdev->framerate_q) * 8;
-
- av_log(avctx, AV_LOG_INFO,
- "w:%d h:%d bpp:%d pixfmt:%s fps:%d/%d bit_rate:%d\n",
- fbdev->width, fbdev->height, fbdev->varinfo.bits_per_pixel,
- av_get_pix_fmt_name(pix_fmt),
- fbdev->framerate_q.num, fbdev->framerate_q.den,
- st->codec->bit_rate);
- return 0;
-
-fail:
- close(fbdev->fd);
- return ret;
-}
-
-static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
-{
- FBDevContext *fbdev = avctx->priv_data;
- int64_t curtime, delay;
- struct timespec ts;
- int i, ret;
- uint8_t *pin, *pout;
-
- if (fbdev->time_frame == AV_NOPTS_VALUE)
- fbdev->time_frame = av_gettime();
-
- /* wait based on the frame rate */
- curtime = av_gettime();
- delay = fbdev->time_frame - curtime;
- av_dlog(avctx,
- "time_frame:%"PRId64" curtime:%"PRId64" delay:%"PRId64"\n",
- fbdev->time_frame, curtime, delay);
- if (delay > 0) {
- if (avctx->flags & AVFMT_FLAG_NONBLOCK)
- return AVERROR(EAGAIN);
- ts.tv_sec = delay / 1000000;
- ts.tv_nsec = (delay % 1000000) * 1000;
- while (nanosleep(&ts, &ts) < 0 && errno == EINTR);
- }
- /* compute the time of the next frame */
- fbdev->time_frame += INT64_C(1000000) / av_q2d(fbdev->framerate_q);
-
- if ((ret = av_new_packet(pkt, fbdev->frame_size)) < 0)
- return ret;
-
- /* refresh fbdev->varinfo, visible data position may change at each call */
- if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->varinfo) < 0)
- av_log(avctx, AV_LOG_WARNING,
- "Error refreshing variable info: %s\n", strerror(errno));
-
- pkt->pts = curtime;
-
- /* compute visible data offset */
- pin = fbdev->data + fbdev->bytes_per_pixel * fbdev->varinfo.xoffset +
- fbdev->varinfo.yoffset * fbdev->fixinfo.line_length;
- pout = pkt->data;
-
- // TODO it'd be nice if the lines were aligned
- for (i = 0; i < fbdev->height; i++) {
- memcpy(pout, pin, fbdev->frame_linesize);
- pin += fbdev->fixinfo.line_length;
- pout += fbdev->frame_linesize;
- }
-
- return fbdev->frame_size;
-}
-
-static av_cold int fbdev_read_close(AVFormatContext *avctx)
-{
- FBDevContext *fbdev = avctx->priv_data;
-
- munmap(fbdev->data, fbdev->frame_size);
- close(fbdev->fd);
-
- return 0;
-}
-
-#define OFFSET(x) offsetof(FBDevContext, x)
-#define DEC AV_OPT_FLAG_DECODING_PARAM
-static const AVOption options[] = {
- { "framerate","", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC },
- { NULL },
-};
-
-static const AVClass fbdev_class = {
- .class_name = "fbdev indev",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-AVInputFormat ff_fbdev_demuxer = {
- .name = "fbdev",
- .long_name = NULL_IF_CONFIG_SMALL("Linux framebuffer"),
- .priv_data_size = sizeof(FBDevContext),
- .read_header = fbdev_read_header,
- .read_packet = fbdev_read_packet,
- .read_close = fbdev_read_close,
- .flags = AVFMT_NOFILE,
- .priv_class = &fbdev_class,
-};
diff --git a/libavdevice/fbdev_common.c b/libavdevice/fbdev_common.c
new file mode 100644
index 0000000..eb8f3d2
--- a/dev/null
+++ b/libavdevice/fbdev_common.c
@@ -0,0 +1,57 @@
+/*
+ * 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 "fbdev_common.h"
+#include "libavutil/common.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;
+}
diff --git a/libavdevice/fbdev_common.h b/libavdevice/fbdev_common.h
new file mode 100644
index 0000000..b6eea2f
--- a/dev/null
+++ b/libavdevice/fbdev_common.h
@@ -0,0 +1,32 @@
+/*
+ * 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"
+
+enum AVPixelFormat ff_get_pixfmt_from_fb_varinfo(struct fb_var_screeninfo *varinfo);
+
+#endif /* AVDEVICE_FBDEV_COMMON_H */
diff --git a/libavdevice/fbdev_dec.c b/libavdevice/fbdev_dec.c
new file mode 100644
index 0000000..14ebab3
--- a/dev/null
+++ b/libavdevice/fbdev_dec.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2009 Giliard B. de Freitas <giliarde@gmail.com>
+ * Copyright (C) 2002 Gunnar Monell <gmo@linux.nu>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Linux framebuffer input device,
+ * inspired by code from fbgrab.c by Gunnar Monell.
+ * @see http://linux-fbdev.sourceforge.net/
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <linux/fb.h>
+
+#include "libavutil/internal.h"
+#include "libavutil/log.h"
+#include "libavutil/mem.h"
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavformat/internal.h"
+#include "avdevice.h"
+#include "fbdev_common.h"
+
+typedef struct {
+ AVClass *class; ///< class for private options
+ int frame_size; ///< size in bytes of a grabbed frame
+ AVRational framerate_q; ///< framerate
+ int64_t time_frame; ///< time for the next frame to output (in 1/1000000 units)
+
+ int fd; ///< framebuffer device file descriptor
+ int width, height; ///< assumed frame resolution
+ int frame_linesize; ///< linesize of the output frame, it is assumed to be constant
+ int bytes_per_pixel;
+
+ struct fb_var_screeninfo varinfo; ///< variable info;
+ struct fb_fix_screeninfo fixinfo; ///< fixed info;
+
+ uint8_t *data; ///< framebuffer data
+} FBDevContext;
+
+static av_cold int fbdev_read_header(AVFormatContext *avctx)
+{
+ FBDevContext *fbdev = avctx->priv_data;
+ AVStream *st = NULL;
+ enum AVPixelFormat pix_fmt;
+ int ret, flags = O_RDONLY;
+
+ if (!(st = avformat_new_stream(avctx, NULL)))
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in microseconds */
+
+ /* NONBLOCK is ignored by the fbdev driver, only set for consistency */
+ if (avctx->flags & AVFMT_FLAG_NONBLOCK)
+ flags |= O_NONBLOCK;
+
+ if ((fbdev->fd = avpriv_open(avctx->filename, flags)) == -1) {
+ ret = AVERROR(errno);
+ av_log(avctx, AV_LOG_ERROR,
+ "Could not open framebuffer device '%s': %s\n",
+ avctx->filename, av_err2str(ret));
+ return ret;
+ }
+
+ if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->varinfo) < 0) {
+ ret = AVERROR(errno);
+ av_log(avctx, AV_LOG_ERROR,
+ "FBIOGET_VSCREENINFO: %s\n", av_err2str(ret));
+ goto fail;
+ }
+
+ if (ioctl(fbdev->fd, FBIOGET_FSCREENINFO, &fbdev->fixinfo) < 0) {
+ ret = AVERROR(errno);
+ av_log(avctx, AV_LOG_ERROR,
+ "FBIOGET_FSCREENINFO: %s\n", av_err2str(ret));
+ goto fail;
+ }
+
+ pix_fmt = ff_get_pixfmt_from_fb_varinfo(&fbdev->varinfo);
+ if (pix_fmt == AV_PIX_FMT_NONE) {
+ ret = AVERROR(EINVAL);
+ av_log(avctx, AV_LOG_ERROR,
+ "Framebuffer pixel format not supported.\n");
+ goto fail;
+ }
+
+ fbdev->width = fbdev->varinfo.xres;
+ fbdev->height = fbdev->varinfo.yres;
+ fbdev->bytes_per_pixel = (fbdev->varinfo.bits_per_pixel + 7) >> 3;
+ fbdev->frame_linesize = fbdev->width * fbdev->bytes_per_pixel;
+ fbdev->frame_size = fbdev->frame_linesize * fbdev->height;
+ fbdev->time_frame = AV_NOPTS_VALUE;
+ fbdev->data = mmap(NULL, fbdev->fixinfo.smem_len, PROT_READ, MAP_SHARED, fbdev->fd, 0);
+ if (fbdev->data == MAP_FAILED) {
+ ret = AVERROR(errno);
+ av_log(avctx, AV_LOG_ERROR, "Error in mmap(): %s\n", av_err2str(ret));
+ goto fail;
+ }
+
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->codec->width = fbdev->width;
+ st->codec->height = fbdev->height;
+ st->codec->pix_fmt = pix_fmt;
+ st->codec->time_base = av_inv_q(fbdev->framerate_q);
+ st->codec->bit_rate =
+ fbdev->width * fbdev->height * fbdev->bytes_per_pixel * av_q2d(fbdev->framerate_q) * 8;
+
+ av_log(avctx, AV_LOG_INFO,
+ "w:%d h:%d bpp:%d pixfmt:%s fps:%d/%d bit_rate:%d\n",
+ fbdev->width, fbdev->height, fbdev->varinfo.bits_per_pixel,
+ av_get_pix_fmt_name(pix_fmt),
+ fbdev->framerate_q.num, fbdev->framerate_q.den,
+ st->codec->bit_rate);
+ return 0;
+
+fail:
+ close(fbdev->fd);
+ return ret;
+}
+
+static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ FBDevContext *fbdev = avctx->priv_data;
+ int64_t curtime, delay;
+ struct timespec ts;
+ int i, ret;
+ uint8_t *pin, *pout;
+
+ if (fbdev->time_frame == AV_NOPTS_VALUE)
+ fbdev->time_frame = av_gettime();
+
+ /* wait based on the frame rate */
+ while (1) {
+ curtime = av_gettime();
+ delay = fbdev->time_frame - curtime;
+ av_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);
+ }
+
+ if ((ret = av_new_packet(pkt, fbdev->frame_size)) < 0)
+ return ret;
+
+ /* refresh fbdev->varinfo, visible data position may change at each call */
+ if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->varinfo) < 0)
+ av_log(avctx, AV_LOG_WARNING,
+ "Error refreshing variable info: %s\n", av_err2str(ret));
+
+ pkt->pts = curtime;
+
+ /* compute visible data offset */
+ pin = fbdev->data + fbdev->bytes_per_pixel * fbdev->varinfo.xoffset +
+ fbdev->varinfo.yoffset * fbdev->fixinfo.line_length;
+ pout = pkt->data;
+
+ for (i = 0; i < fbdev->height; i++) {
+ memcpy(pout, pin, fbdev->frame_linesize);
+ pin += fbdev->fixinfo.line_length;
+ pout += fbdev->frame_linesize;
+ }
+
+ return fbdev->frame_size;
+}
+
+static av_cold int fbdev_read_close(AVFormatContext *avctx)
+{
+ FBDevContext *fbdev = avctx->priv_data;
+
+ munmap(fbdev->data, fbdev->fixinfo.smem_len);
+ close(fbdev->fd);
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(FBDevContext, x)
+#define DEC AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ { "framerate","", OFFSET(framerate_q), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC },
+ { NULL },
+};
+
+static const AVClass fbdev_class = {
+ .class_name = "fbdev indev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_fbdev_demuxer = {
+ .name = "fbdev",
+ .long_name = NULL_IF_CONFIG_SMALL("Linux framebuffer"),
+ .priv_data_size = sizeof(FBDevContext),
+ .read_header = fbdev_read_header,
+ .read_packet = fbdev_read_packet,
+ .read_close = fbdev_read_close,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &fbdev_class,
+};
diff --git a/libavdevice/fbdev_enc.c b/libavdevice/fbdev_enc.c
new file mode 100644
index 0000000..098eedb
--- a/dev/null
+++ b/libavdevice/fbdev_enc.c
@@ -0,0 +1,206 @@
+/*
+ * 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"
+
+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;
+
+ 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 ((fbdev->fd = avpriv_open(h->filename, flags)) == -1) {
+ ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR,
+ "Could not open framebuffer device '%s': %s\n",
+ h->filename, 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;
+}
+
+#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,
+};
+
+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,
+ .flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
+ .priv_class = &fbdev_class,
+};
diff --git a/libavdevice/iec61883.c b/libavdevice/iec61883.c
new file mode 100644
index 0000000..a63566e
--- a/dev/null
+++ b/libavdevice/iec61883.c
@@ -0,0 +1,497 @@
+/*
+ * 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;
+
+#ifdef 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:
+#ifdef 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;
+
+#ifdef 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");
+#ifdef 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 = ff_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 = ff_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
+ */
+
+#ifdef 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);
+ ff_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,
+};
+
+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 c261514..5ba6731 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);
@@ -187,9 +187,7 @@ 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);
diff --git a/libavdevice/lavfi.c b/libavdevice/lavfi.c
new file mode 100644
index 0000000..559f721
--- a/dev/null
+++ b/libavdevice/lavfi.c
@@ -0,0 +1,435 @@
+/*
+ * 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) {
+ uint8_t *file_buf, *graph_buf;
+ size_t file_bufsize;
+ ret = av_file_map(lavfi->graph_filename,
+ &file_buf, &file_bufsize, 0, avctx);
+ if (ret < 0)
+ goto end;
+
+ /* create a 0-terminated string based on the read file */
+ graph_buf = av_malloc(file_bufsize + 1);
+ if (!graph_buf) {
+ av_file_unmap(file_buf, file_bufsize);
+ FAIL(AVERROR(ENOMEM));
+ }
+ memcpy(graph_buf, file_buf, file_bufsize);
+ graph_buf[file_bufsize] = 0;
+ av_file_unmap(file_buf, file_bufsize);
+ lavfi->graph_str = graph_buf;
+ }
+
+ 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)
+ FAIL(ret);
+
+ 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));
+ }
+
+ /* is an audio or video output? */
+ type = inout->filter_ctx->output_pads[inout->pad_idx].type;
+ if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Output '%s' is not a video or audio output, not yet supported\n", inout->name);
+ 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(sizeof(AVFilterContext *) * avctx->nb_streams);
+ 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;
+ }
+
+ lavfi->sinks[i] = sink;
+ if ((ret = avfilter_link(inout->filter_ctx, inout->pad_idx, sink, 0)) < 0)
+ FAIL(ret);
+ }
+
+ /* configure the graph */
+ if ((ret = avfilter_graph_config(lavfi->graph, avctx)) < 0)
+ FAIL(ret);
+
+ 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,
+};
+
+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/libcdio.c b/libavdevice/libcdio.c
index 06ddb4a..91052cc 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;
diff --git a/libavdevice/libdc1394.c b/libavdevice/libdc1394.c
index f030e3e..80cb1be 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
*/
diff --git a/libavdevice/openal-dec.c b/libavdevice/openal-dec.c
new file mode 100644
index 0000000..93633ff
--- a/dev/null
+++ b/libavdevice/openal-dec.c
@@ -0,0 +1,252 @@
+/*
+ * 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
+};
+
+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/oss_audio.c b/libavdevice/oss_audio.c
index f1cc91f..916908c 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
*/
@@ -39,7 +39,7 @@
#include "libavutil/opt.h"
#include "libavutil/time.h"
#include "libavcodec/avcodec.h"
-#include "libavformat/avformat.h"
+#include "avdevice.h"
#include "libavformat/internal.h"
#define AUDIO_BLOCK_SIZE 4096
@@ -77,8 +77,11 @@ static int audio_open(AVFormatContext *s1, int is_output, const char *audio_devi
}
/* 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 = AUDIO_BLOCK_SIZE;
diff --git a/libavdevice/pulse.c b/libavdevice/pulse.c
deleted file mode 100644
index a8e710d..0000000
--- a/libavdevice/pulse.c
+++ b/dev/null
@@ -1,190 +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/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;
-} 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;
- }
-
- 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 },
- { 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..bbc8c97
--- a/dev/null
+++ b/libavdevice/pulse_audio_common.c
@@ -0,0 +1,42 @@
+/*
+ * 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
+ */
+
+#include "libavutil/attributes.h"
+#include "libavcodec/avcodec.h"
+#include "pulse_audio_common.h"
+
+pa_sample_format_t av_cold 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;
+ }
+}
diff --git a/libavdevice/pulse_audio_common.h b/libavdevice/pulse_audio_common.h
new file mode 100644
index 0000000..e4409ba
--- a/dev/null
+++ b/libavdevice/pulse_audio_common.h
@@ -0,0 +1,29 @@
+/*
+ * 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/simple.h>
+
+pa_sample_format_t codec_id_to_pulse_format(int codec_id);
+
+#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..9cfc144
--- a/dev/null
+++ b/libavdevice/pulse_audio_dec.c
@@ -0,0 +1,173 @@
+/*
+ * 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
+ */
+
+/**
+ * @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/opt.h"
+#include "pulse_audio_common.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;
+} PulseData;
+
+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;
+ }
+
+ 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", "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 },
+ { 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_enc.c b/libavdevice/pulse_audio_enc.c
new file mode 100644
index 0000000..591e518
--- a/dev/null
+++ b/libavdevice/pulse_audio_enc.c
@@ -0,0 +1,167 @@
+/*
+ * 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 <pulse/simple.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 "pulse_audio_common.h"
+
+typedef struct PulseData {
+ AVClass *class;
+ const char *server;
+ const char *name;
+ const char *stream_name;
+ const char *device;
+ pa_simple *pa;
+ int64_t timestamp;
+} PulseData;
+
+static av_cold int pulse_write_header(AVFormatContext *h)
+{
+ PulseData *s = h->priv_data;
+ AVStream *st = NULL;
+ int ret;
+ pa_sample_spec ss;
+ pa_buffer_attr attr = { -1, -1, -1, -1, -1 };
+ const char *stream_name = s->stream_name;
+
+ 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";
+ }
+
+ ss.format = codec_id_to_pulse_format(st->codec->codec_id);
+ ss.rate = st->codec->sample_rate;
+ ss.channels = st->codec->channels;
+
+ s->pa = pa_simple_new(s->server, // Server
+ s->name, // Application name
+ PA_STREAM_PLAYBACK,
+ s->device, // Device
+ stream_name, // Description of a stream
+ &ss, // Sample format
+ NULL, // Use default channel map
+ &attr, // Buffering attributes
+ &ret); // Result
+
+ if (!s->pa) {
+ av_log(s, AV_LOG_ERROR, "pa_simple_new failed: %s\n", pa_strerror(ret));
+ return AVERROR(EIO);
+ }
+
+ avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
+
+ return 0;
+}
+
+static av_cold int pulse_write_trailer(AVFormatContext *h)
+{
+ PulseData *s = h->priv_data;
+ pa_simple_flush(s->pa, NULL);
+ pa_simple_free(s->pa);
+ s->pa = NULL;
+ return 0;
+}
+
+static int pulse_write_packet(AVFormatContext *h, AVPacket *pkt)
+{
+ PulseData *s = h->priv_data;
+ int error;
+
+ if (!pkt) {
+ if (pa_simple_flush(s->pa, &error) < 0) {
+ av_log(s, AV_LOG_ERROR, "pa_simple_flush failed: %s\n", pa_strerror(error));
+ return AVERROR(EIO);
+ }
+ return 0;
+ }
+
+ 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);
+ }
+
+ if (pa_simple_write(s->pa, pkt->data, pkt->size, &error) < 0) {
+ av_log(s, AV_LOG_ERROR, "pa_simple_write failed: %s\n", pa_strerror(error));
+ return AVERROR(EIO);
+ }
+
+ return 0;
+}
+
+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 = pa_simple_get_latency(s->pa, NULL);
+ *wall = av_gettime();
+ *dts = s->timestamp - latency;
+}
+
+#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 },
+ { NULL }
+};
+
+static const AVClass pulse_muxer_class = {
+ .class_name = "Pulse muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+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_trailer = pulse_write_trailer,
+ .get_output_timestamp = pulse_get_output_timestamp,
+ .flags = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH,
+ .priv_class = &pulse_muxer_class,
+};
diff --git a/libavdevice/sdl.c b/libavdevice/sdl.c
new file mode 100644
index 0000000..e708dfd
--- a/dev/null
+++ b/libavdevice/sdl.c
@@ -0,0 +1,236 @@
+/*
+ * 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 "libavutil/avstring.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.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;
+ int overlay_width, overlay_height; /**< size of the video in the window */
+ int overlay_x, overlay_y;
+ int overlay_fmt;
+ int sdl_was_already_inited;
+} 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;
+
+ av_freep(&sdl->window_title);
+ av_freep(&sdl->icon_title);
+
+ if (sdl->overlay) {
+ SDL_FreeYUVOverlay(sdl->overlay);
+ sdl->overlay = NULL;
+ }
+ if (!sdl->sdl_was_already_inited)
+ SDL_Quit();
+
+ return 0;
+}
+
+static int sdl_write_header(AVFormatContext *s)
+{
+ SDLContext *sdl = s->priv_data;
+ AVStream *st = s->streams[0];
+ AVCodecContext *encctx = st->codec;
+ AVRational sar, dar; /* sample and display aspect ratios */
+ int i, ret;
+ int flags = SDL_SWSURFACE | sdl->window_fullscreen ? SDL_FULLSCREEN : 0;
+
+ 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 (SDL_Init(SDL_INIT_VIDEO) != 0) {
+ av_log(s, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError());
+ 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 */
+ 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 */
+ sdl->overlay_width = sdl->window_width;
+ sdl->overlay_height = av_rescale(sdl->overlay_width, dar.den, dar.num);
+ } else {
+ /* fit in height */
+ sdl->overlay_height = sdl->window_height;
+ sdl->overlay_width = av_rescale(sdl->overlay_height, dar.num, dar.den);
+ }
+ } else {
+ if (sar.num > sar.den) {
+ sdl->overlay_width = encctx->width;
+ sdl->overlay_height = av_rescale(sdl->overlay_width, dar.den, dar.num);
+ } else {
+ sdl->overlay_height = encctx->height;
+ sdl->overlay_width = av_rescale(sdl->overlay_height, dar.num, dar.den);
+ }
+ sdl->window_width = sdl->overlay_width;
+ sdl->window_height = sdl->overlay_height;
+ }
+ sdl->overlay_x = (sdl->window_width - sdl->overlay_width ) / 2;
+ sdl->overlay_y = (sdl->window_height - sdl->overlay_height) / 2;
+
+ 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(s, AV_LOG_ERROR, "Unable to set video mode: %s\n", SDL_GetError());
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ 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);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ av_log(s, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d\n",
+ encctx->width, encctx->height, av_get_pix_fmt_name(encctx->pix_fmt), sar.num, sar.den,
+ sdl->overlay_width, sdl->overlay_height);
+ 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;
+ SDL_Rect rect = { sdl->overlay_x, sdl->overlay_y, sdl->overlay_width, sdl->overlay_height };
+ AVPicture pict;
+ int i;
+
+ avpicture_fill(&pict, pkt->data, encctx->pix_fmt, encctx->width, encctx->height);
+
+ 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, &rect);
+ SDL_UnlockYUVOverlay(sdl->overlay);
+
+ SDL_UpdateRect(sdl->surface, rect.x, rect.y, rect.w, rect.h);
+
+ 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,
+};
+
+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..806f478 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
*/
diff --git a/libavdevice/sndio_enc.c b/libavdevice/sndio_enc.c
index 6f69b9e..84d070e 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)
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..bf2c9e3
--- a/dev/null
+++ b/libavdevice/v4l.c
@@ -0,0 +1,362 @@
+/*
+ * 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,
+};
+
+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..572f0ed
--- a/dev/null
+++ b/libavdevice/v4l2-common.c
@@ -0,0 +1,96 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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 avpriv_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_CPIA1
+ { AV_PIX_FMT_NONE, AV_CODEC_ID_CPIA, V4L2_PIX_FMT_CPIA1 },
+#endif
+ { AV_PIX_FMT_NONE, AV_CODEC_ID_NONE, 0 },
+};
+
+uint32_t avpriv_fmt_ff2v4l(enum AVPixelFormat pix_fmt, enum AVCodecID codec_id)
+{
+ int i;
+
+ for (i = 0; avpriv_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
+ if ((codec_id == AV_CODEC_ID_NONE ||
+ avpriv_fmt_conversion_table[i].codec_id == codec_id) &&
+ (pix_fmt == AV_PIX_FMT_NONE ||
+ avpriv_fmt_conversion_table[i].ff_fmt == pix_fmt)) {
+ return avpriv_fmt_conversion_table[i].v4l2_fmt;
+ }
+ }
+
+ return 0;
+}
+
+enum AVPixelFormat avpriv_fmt_v4l2ff(uint32_t v4l2_fmt, enum AVCodecID codec_id)
+{
+ int i;
+
+ for (i = 0; avpriv_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
+ if (avpriv_fmt_conversion_table[i].v4l2_fmt == v4l2_fmt &&
+ avpriv_fmt_conversion_table[i].codec_id == codec_id) {
+ return avpriv_fmt_conversion_table[i].ff_fmt;
+ }
+ }
+
+ return AV_PIX_FMT_NONE;
+}
+
+enum AVCodecID avpriv_fmt_v4l2codec(uint32_t v4l2_fmt)
+{
+ int i;
+
+ for (i = 0; avpriv_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
+ if (avpriv_fmt_conversion_table[i].v4l2_fmt == v4l2_fmt) {
+ return avpriv_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..8aef234
--- a/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 av_export const struct fmt_map avpriv_fmt_conversion_table[];
+
+uint32_t avpriv_fmt_ff2v4l(enum AVPixelFormat pix_fmt, enum AVCodecID codec_id);
+enum AVPixelFormat avpriv_fmt_v4l2ff(uint32_t v4l2_fmt, enum AVCodecID codec_id);
+enum AVCodecID avpriv_fmt_v4l2codec(uint32_t v4l2_fmt);
+
+#endif /* AVDEVICE_V4L2_COMMON_H */
diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c
index adb289d..cb962b7 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 Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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,113 +42,144 @@ 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 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 ret;
int flags = O_RDWR;
+#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 = errno;
-
- av_log(ctx, AV_LOG_ERROR, "Cannot open video device %s : %s\n",
- ctx->filename, strerror(err));
-
- return AVERROR(err);
+ ret = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "Cannot open video device %s: %s\n",
+ ctx->filename, av_err2str(ret));
+ return ret;
}
- res = ioctl(fd, VIDIOC_QUERYCAP, &cap);
- if (res < 0) {
- err = errno;
+ if (v4l2_ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
+ ret = AVERROR(errno);
av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYCAP): %s\n",
- strerror(err));
-
+ av_err2str(ret));
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 = ENODEV;
-
+ ret = AVERROR(ENODEV);
goto fail;
}
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
av_log(ctx, AV_LOG_ERROR,
"The device does not support the streaming I/O method.\n");
- err = ENOSYS;
-
+ ret = AVERROR(ENOSYS);
goto fail;
}
return fd;
fail:
- close(fd);
- return AVERROR(err);
+ v4l2_close(fd);
+ return ret;
}
static int device_init(AVFormatContext *ctx, int *width, int *height,
@@ -176,14 +190,15 @@ static int device_init(AVFormatContext *ctx, int *width, int *height,
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;
- res = ioctl(fd, VIDIOC_S_FMT, &fmt);
+ if (v4l2_ioctl(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,
@@ -198,23 +213,24 @@ static int device_init(AVFormatContext *ctx, int *width, int *height,
"The V4L2 driver changed the pixel format "
"from 0x%08X to 0x%08X\n",
pix_fmt, fmt.fmt.pix.pixelformat);
- res = -1;
+ 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 fd)
{
int res;
v4l2_std_id std;
- res = ioctl(fd, VIDIOC_G_STD, &std);
+ res = v4l2_ioctl(fd, VIDIOC_G_STD, &std);
if (res < 0) {
return 0;
}
@@ -225,55 +241,13 @@ static int first_field(int fd)
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)
{
+ 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(fd, VIDIOC_ENUM_FRAMESIZES, &vfse)) {
switch (vfse.type) {
case V4L2_FRMSIZE_TYPE_DISCRETE:
av_log(ctx, AV_LOG_INFO, " %ux%u",
@@ -296,24 +270,25 @@ static void list_framesizes(AVFormatContext *ctx, int fd, uint32_t pixelformat)
static void list_formats(AVFormatContext *ctx, int fd, 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(fd, VIDIOC_ENUM_FMT, &vfd)) {
+ enum AVCodecID codec_id = avpriv_fmt_v4l2codec(vfd.pixelformat);
+ enum AVPixelFormat pix_fmt = avpriv_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 {
@@ -321,10 +296,8 @@ 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);
@@ -333,6 +306,30 @@ static void list_formats(AVFormatContext *ctx, int fd, int type)
}
}
+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;
@@ -343,34 +340,26 @@ static int mmap_init(AVFormatContext *ctx)
.memory = V4L2_MEMORY_MMAP
};
- res = ioctl(s->fd, VIDIOC_REQBUFS, &req);
- if (res < 0) {
- if (errno == EINVAL) {
- av_log(ctx, AV_LOG_ERROR, "Device does not support mmap\n");
- } else {
- av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_REQBUFS)\n");
- }
-
- return AVERROR(errno);
+ if (v4l2_ioctl(s->fd, VIDIOC_REQBUFS, &req) < 0) {
+ res = AVERROR(errno);
+ 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);
if (s->buf_start == NULL) {
av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer pointers\n");
-
return AVERROR(ENOMEM);
}
s->buf_len = av_malloc(sizeof(unsigned int) * s->buffers);
if (s->buf_len == NULL) {
av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer sizes\n");
av_free(s->buf_start);
-
return AVERROR(ENOMEM);
}
@@ -380,30 +369,27 @@ static int mmap_init(AVFormatContext *ctx)
.index = i,
.memory = V4L2_MEMORY_MMAP
};
-
- res = ioctl(s->fd, VIDIOC_QUERYBUF, &buf);
- if (res < 0) {
- av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYBUF)\n");
-
- return AVERROR(errno);
+ if (v4l2_ioctl(s->fd, VIDIOC_QUERYBUF, &buf) < 0) {
+ res = AVERROR(errno);
+ 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) {
- av_log(ctx, AV_LOG_ERROR, "mmap: %s\n", strerror(errno));
-
- return AVERROR(errno);
+ res = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "mmap: %s\n", av_err2str(res));
+ return res;
}
}
@@ -420,23 +406,86 @@ static void dummy_release_buffer(AVPacket *pkt)
static void mmap_release_buffer(void *opaque, uint8_t *data)
{
struct v4l2_buffer buf = { 0 };
- int res, fd;
+ int res;
struct buff_data *buf_descriptor = opaque;
struct video_data *s = buf_descriptor->s;
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)
+ if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) < 0) {
+ res = AVERROR(errno);
av_log(NULL, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n",
- strerror(errno));
+ av_err2str(res));
+ }
+
avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1);
}
+#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
+static int64_t av_gettime_monotonic(void)
+{
+ struct timespec tv;
+
+ clock_gettime(CLOCK_MONOTONIC, &tv);
+ return (int64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
+}
+#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)
+ 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);
+ }
+#endif
+ return 0;
+}
+
static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt)
{
struct video_data *s = ctx->priv_data;
@@ -444,28 +493,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) {
if (errno == EAGAIN) {
pkt->size = 0;
-
return AVERROR(EAGAIN);
}
- av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_DQBUF): %s\n",
- strerror(errno));
-
- return AVERROR(errno);
+ res = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_DQBUF): %s\n", av_err2str(res));
+ return res;
}
if (buf.index >= s->buffers) {
@@ -476,11 +515,16 @@ 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);
-
return AVERROR_INVALIDDATA;
}
@@ -490,15 +534,17 @@ 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");
+ if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) == 0)
+ avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1);
return res;
}
memcpy(pkt->data, s->buf_start[buf.index], buf.bytesused);
- res = ioctl(s->fd, VIDIOC_QBUF, &buf);
- if (res < 0) {
- av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF)\n");
+ if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) < 0) {
+ res = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", av_err2str(res));
av_free_packet(pkt);
- return AVERROR(errno);
+ return res;
}
avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1);
} else {
@@ -518,22 +564,26 @@ 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);
+ if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) == 0)
+ avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1);
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");
+ if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) == 0)
+ avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1);
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];
}
@@ -551,23 +601,19 @@ static int mmap_start(AVFormatContext *ctx)
.memory = V4L2_MEMORY_MMAP
};
- res = ioctl(s->fd, VIDIOC_QBUF, &buf);
- if (res < 0) {
- av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n",
- strerror(errno));
-
- return AVERROR(errno);
+ if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) < 0) {
+ res = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", 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) {
- av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_STREAMON): %s\n",
- strerror(errno));
-
- return AVERROR(errno);
+ if (v4l2_ioctl(s->fd, VIDIOC_STREAMON, &type) < 0) {
+ res = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_STREAMON): %s\n", av_err2str(res));
+ return res;
}
return 0;
@@ -582,9 +628,9 @@ 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);
@@ -593,15 +639,12 @@ static void mmap_close(struct video_data *s)
static int v4l2_set_parameters(AVFormatContext *s1)
{
struct video_data *s = s1->priv_data;
- struct v4l2_input input = { 0 };
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",
@@ -609,120 +652,153 @@ static int v4l2_set_parameters(AVFormatContext *s1)
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(s1, 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(s1, 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(s1, AV_LOG_ERROR, "ioctl(VIDIOC_S_STD): %s\n", av_err2str(ret));
+ return ret;
+ }
+ } else {
+ av_log(s1, 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)) {
+ tpf = &streamparm.parm.capture.timeperframe;
+ break;
+ }
+ av_log(s1, 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(s1, 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(s1, 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(s1, 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 (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) {
- av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_PARM): %s\n",
- strerror(errno));
- return AVERROR(errno);
+ if (v4l2_ioctl(s->fd, VIDIOC_S_PARM, &streamparm) < 0) {
+ ret = AVERROR(errno);
+ av_log(s1, 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 {
+ av_log(s1, 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});
+ s1->streams[0]->r_frame_rate = s1->streams[0]->avg_frame_rate;
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 *s1,
+ 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);
+ int ret, i;
- if (desired_format == 0 ||
- device_init(s1, width, height, desired_format) < 0) {
- int i;
+ *desired_format = avpriv_fmt_ff2v4l(pix_fmt, s1->video_codec_id);
- desired_format = 0;
- for (i = 0; i<FF_ARRAY_ELEMS(fmt_conversion_table); i++) {
+ if (*desired_format) {
+ ret = device_init(s1, width, height, *desired_format);
+ if (ret < 0) {
+ *desired_format = 0;
+ if (ret != AVERROR(EINVAL))
+ return ret;
+ }
+ }
+
+ if (!*desired_format) {
+ for (i = 0; avpriv_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; 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) {
+ avpriv_fmt_conversion_table[i].codec_id == s1->video_codec_id) {
+ av_log(s1, AV_LOG_DEBUG, "Trying to set codec:%s pix_fmt:%s\n",
+ avcodec_get_name(avpriv_fmt_conversion_table[i].codec_id),
+ (char *)av_x_if_null(av_get_pix_fmt_name(avpriv_fmt_conversion_table[i].ff_fmt), "none"));
+
+ *desired_format = avpriv_fmt_conversion_table[i].v4l2_fmt;
+ ret = device_init(s1, 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(s1, AV_LOG_ERROR, "Cannot find a proper format for "
+ "codec '%s' (id %d), pixel format '%s' (id %d)\n",
+ avcodec_get_name(s1->video_codec_id), s1->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 = avpriv_fmt_v4l2codec(*desired_format);
+ av_assert0(*codec_id != AV_CODEC_ID_NONE);
+ return ret;
}
static int v4l2_read_header(AVFormatContext *s1)
@@ -731,31 +807,65 @@ static int v4l2_read_header(AVFormatContext *s1)
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);
if (!st)
return AVERROR(ENOMEM);
+#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(s1);
if (s->fd < 0)
return s->fd;
+ if (s->channel != -1) {
+ /* set video input */
+ av_log(s1, 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(s1, AV_LOG_ERROR, "ioctl(VIDIOC_S_INPUT): %s\n", av_err2str(res));
+ return res;
+ }
+ } else {
+ /* get current video input */
+ if (v4l2_ioctl(s->fd, VIDIOC_G_INPUT, &s->channel) < 0) {
+ res = AVERROR(errno);
+ av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_INPUT): %s\n", av_err2str(res));
+ return res;
+ }
+ }
+
+ /* enum input */
+ input.index = s->channel;
+ if (v4l2_ioctl(s->fd, VIDIOC_ENUMINPUT, &input) < 0) {
+ res = AVERROR(errno);
+ av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_ENUMINPUT): %s\n", av_err2str(res));
+ return res;
+ }
+ s->std_id = input.std;
+ av_log(s1, AV_LOG_DEBUG, "Current input_channel: %d, input_name: %s, input_std: %"PRIx64"\n",
+ s->channel, input.name, (uint64_t)input.std);
+
if (s->list_format) {
list_formats(s1, s->fd, s->list_format);
return AVERROR_EXIT;
}
- avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
-
- 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_standard) {
+ list_standards(s1);
+ return AVERROR_EXIT;
}
+ 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);
@@ -773,15 +883,14 @@ static int v4l2_read_header(AVFormatContext *s1)
}
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,
"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) {
- av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_FMT): %s\n",
- strerror(errno));
- return AVERROR(errno);
+ if (v4l2_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;
}
s->width = fmt.fmt.pix.width;
@@ -790,41 +899,51 @@ static int v4l2_read_header(AVFormatContext *s1)
"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);
-
- return AVERROR(EIO);
+ res = device_try_init(s1, pix_fmt, &s->width, &s->height, &desired_format, &codec_id);
+ if (res < 0) {
+ v4l2_close(s->fd);
+ return res;
}
- if ((res = av_image_check_size(s->width, s->height, 0, s1) < 0))
+ /* 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 && s1->video_codec_id == AV_CODEC_ID_NONE)
+ s1->video_codec_id = codec_id;
+
+ if ((res = av_image_check_size(s->width, s->height, 0, s1)) < 0)
return res;
s->frame_format = desired_format;
- if ((res = v4l2_set_parameters(s1) < 0))
+ if ((res = v4l2_set_parameters(s1)) < 0)
return res;
- st->codec->pix_fmt = fmt_v4l2ff(desired_format, codec_id);
+ st->codec->pix_fmt = avpriv_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);
+ v4l2_close(s->fd);
return res;
}
- s->top_field_first = first_field(s->fd);
+ s->top_field_first = first_field(s, s->fd);
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;
@@ -861,23 +980,35 @@ static int v4l2_read_close(AVFormatContext *s1)
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) convertion functions", OFFSET(use_libv4l2), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
{ NULL },
};
@@ -889,7 +1020,7 @@ static const AVClass v4l2_class = {
};
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_header = v4l2_read_header,
diff --git a/libavdevice/v4l2enc.c b/libavdevice/v4l2enc.c
new file mode 100644
index 0000000..21f0ef6
--- a/dev/null
+++ b/libavdevice/v4l2enc.c
@@ -0,0 +1,110 @@
+/*
+ * 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 {
+ 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 = avpriv_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;
+}
+
+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,
+};
diff --git a/libavdevice/version.h b/libavdevice/version.h
index 9731606..4f4ec99 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/avutil.h"
-#define LIBAVDEVICE_VERSION_MAJOR 54
-#define LIBAVDEVICE_VERSION_MINOR 0
-#define LIBAVDEVICE_VERSION_MICRO 0
+#define LIBAVDEVICE_VERSION_MAJOR 55
+#define LIBAVDEVICE_VERSION_MINOR 5
+#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 fea85fc..014f18c 100644
--- a/libavdevice/vfwcap.c
+++ b/libavdevice/vfwcap.c
@@ -2,37 +2,35 @@
* 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"
/* Defines for VFW missing from MinGW.
* Remove this when MinGW incorporates them. */
#define HWND_MESSAGE ((HWND)-3)
-#define BI_RGB 0
-
/* End of missing MinGW defines */
struct vfw_ctx {
@@ -157,7 +155,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;
@@ -245,7 +243,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;
@@ -291,7 +289,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);
@@ -305,7 +303,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);
@@ -313,16 +311,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;
}
}
@@ -341,19 +344,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);
@@ -368,10 +369,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;
@@ -397,31 +398,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);
}
diff --git a/libavdevice/x11grab.c b/libavdevice/x11grab.c
index 8edbf7b..0e7b6ae 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
*/
@@ -37,13 +37,13 @@
*/
#include "config.h"
-#include "libavformat/avformat.h"
#include "libavformat/internal.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#include "libavutil/time.h"
#include <time.h>
+#include <X11/cursorfont.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xlibint.h>
@@ -53,6 +53,7 @@
#include <X11/extensions/shape.h>
#include <X11/extensions/XShm.h>
#include <X11/extensions/Xfixes.h>
+#include "avdevice.h"
/**
* X11 Device Demuxer context
@@ -63,9 +64,8 @@ struct x11grab {
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 */
@@ -76,8 +76,11 @@ struct x11grab {
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. */
};
@@ -164,33 +167,33 @@ x11grab_read_header(AVFormatContext *s1)
int y_off = 0;
int screen;
int use_shm;
- char *param, *offset;
+ char *dpyname, *offset;
int ret = 0;
- AVRational framerate;
+ Colormap color_map;
+ XColor color[256];
+ int i;
- param = av_strdup(s1->filename);
- if (!param)
+ 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;
}
- if ((ret = av_parse_video_size(&x11grab->width, &x11grab->height, x11grab->video_size)) < 0) {
- av_log(s1, AV_LOG_ERROR, "Couldn't parse video size.\n");
- goto out;
- }
- if ((ret = av_parse_video_rate(&framerate, x11grab->framerate)) < 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);
@@ -221,7 +224,7 @@ x11grab_read_header(AVFormatContext *s1)
}
use_shm = XShmQueryExtension(dpy);
- av_log(s1, AV_LOG_INFO, "shared memory extension %s found\n", use_shm ? "" : "not");
+ av_log(s1, AV_LOG_INFO, "shared memory extension%s found\n", use_shm ? "" : " not");
if(use_shm) {
int scr = XDefaultScreen(dpy);
@@ -260,6 +263,15 @@ x11grab_read_header(AVFormatContext *s1)
case 8:
av_log (s1, AV_LOG_DEBUG, "8 bit palette\n");
input_pixfmt = 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;
break;
case 16:
if ( image->red_mask == 0xf800 &&
@@ -296,7 +308,7 @@ x11grab_read_header(AVFormatContext *s1)
}
break;
case 32:
- input_pixfmt = AV_PIX_FMT_RGB32;
+ input_pixfmt = AV_PIX_FMT_0RGB32;
break;
default:
av_log(s1, AV_LOG_ERROR, "image depth %i not supported ... aborting\n", image->bits_per_pixel);
@@ -306,7 +318,7 @@ 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;
@@ -322,7 +334,7 @@ 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;
}
@@ -351,11 +363,19 @@ paint_mouse_pointer(XImage *image, struct x11grab *s)
* Anyone who performs further investigation of the xlib API likely risks
* permanent brain damage. */
uint8_t *pix = image->data;
+ Window w;
+ 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);
+ w = DefaultRootWindow(dpy);
+ attr.cursor = s->c;
+ XChangeWindowAttributes(dpy, w, CWCursor, &attr);
+
xcim = XFixesGetCursorImage(dpy);
x = xcim->x - xcim->xhot;
@@ -483,6 +503,16 @@ 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);
@@ -585,13 +615,16 @@ x11grab_read_close(AVFormatContext *s1)
#define OFFSET(x) offsetof(struct x11grab, 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 },
{ NULL },
};
diff --git a/libavdevice/xv.c b/libavdevice/xv.c
new file mode 100644
index 0000000..65f2f72
--- a/dev/null
+++ b/libavdevice/xv.c
@@ -0,0 +1,217 @@
+/*
+ * 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
+ * - add support to window id specification
+ */
+
+#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 "avdevice.h"
+
+typedef struct {
+ AVClass *class;
+ GC gc;
+
+ Window window;
+ char *window_title;
+ int window_width, window_height;
+ int window_x, window_y;
+
+ Display* display;
+ char *display_name;
+
+ XvImage* yuv_image;
+ int image_width, image_height;
+ XShmSegmentInfo yuv_shminfo;
+ int xv_port;
+} XVContext;
+
+static int xv_write_header(AVFormatContext *s)
+{
+ XVContext *xv = s->priv_data;
+ unsigned int num_adaptors;
+ XvAdaptorInfo *ai;
+ XvImageFormatValues *fv;
+ int num_formats = 0, j;
+ 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);
+ }
+
+ 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) {
+ xv->window_width = encctx->width;
+ xv->window_height = encctx->height;
+ }
+ 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)))
+ return AVERROR(ENOMEM);
+ }
+ XStoreName(xv->display, xv->window, xv->window_title);
+ XMapWindow(xv->display, xv->window);
+
+ if (XvQueryAdaptors(xv->display, DefaultRootWindow(xv->display), &num_adaptors, &ai) != Success)
+ return AVERROR_EXTERNAL;
+ xv->xv_port = ai[0].base_id;
+
+ if (encctx->pix_fmt != AV_PIX_FMT_YUV420P) {
+ av_log(s, AV_LOG_ERROR,
+ "Unsupported pixel format '%s', only yuv420p is currently supported\n",
+ av_get_pix_fmt_name(encctx->pix_fmt));
+ return AVERROR_PATCHWELCOME;
+ }
+
+ fv = XvListImageFormats(xv->display, xv->xv_port, &num_formats);
+ if (!fv)
+ return AVERROR_EXTERNAL;
+ for (j = 0; j < num_formats; j++) {
+ if (fv[j].id == MKTAG('I','4','2','0')) {
+ break;
+ }
+ }
+ XFree(fv);
+
+ if (j >= num_formats) {
+ av_log(s, AV_LOG_ERROR,
+ "Device does not support pixel format yuv420p, aborting\n");
+ return AVERROR(EINVAL);
+ }
+
+ 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,
+ MKTAG('I','4','2','0'), 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);
+
+ return 0;
+}
+
+static int xv_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ XVContext *xv = s->priv_data;
+ XvImage *img = xv->yuv_image;
+ XWindowAttributes window_attrs;
+ AVPicture pict;
+ AVCodecContext *ctx = s->streams[0]->codec;
+ int y, h;
+
+ h = img->height / 2;
+
+ avpicture_fill(&pict, pkt->data, ctx->pix_fmt, ctx->width, ctx->height);
+ for (y = 0; y < img->height; y++) {
+ memcpy(&img->data[img->offsets[0] + (y * img->pitches[0])],
+ &pict.data[0][y * pict.linesize[0]], img->pitches[0]);
+ }
+
+ for (y = 0; y < h; ++y) {
+ memcpy(&img->data[img->offsets[1] + (y * img->pitches[1])],
+ &pict.data[1][y * pict.linesize[1]], img->pitches[1]);
+ memcpy(&img->data[img->offsets[2] + (y * img->pitches[2])],
+ &pict.data[2][y * pict.linesize[2]], img->pitches[2]);
+ }
+
+ XGetWindowAttributes(xv->display, xv->window, &window_attrs);
+ if (XvShmPutImage(xv->display, xv->xv_port, xv->window, xv->gc,
+ xv->yuv_image, 0, 0, xv->image_width, xv->image_height, 0, 0,
+ window_attrs.width, window_attrs.height, 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 xv_write_trailer(AVFormatContext *s)
+{
+ XVContext *xv = s->priv_data;
+
+ XShmDetach(xv->display, &xv->yuv_shminfo);
+ shmdt(xv->yuv_image->data);
+ XFree(xv->yuv_image);
+ XCloseDisplay(xv->display);
+ return 0;
+}
+
+#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_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,
+};
+
+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_trailer = xv_write_trailer,
+ .flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
+ .priv_class = &xv_class,
+};
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 96fa8c0..3fcccf8 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -1,11 +1,30 @@
+include $(SUBDIR)../config.mak
+
NAME = avfilter
FFLIBS = avutil
-FFLIBS-$(CONFIG_ASYNCTS_FILTER) += avresample
-FFLIBS-$(CONFIG_MOVIE_FILTER) += avformat avcodec
-FFLIBS-$(CONFIG_RESAMPLE_FILTER) += avresample
-FFLIBS-$(CONFIG_SCALE_FILTER) += swscale
+FFLIBS-$(CONFIG_ACONVERT_FILTER) += swresample
+FFLIBS-$(CONFIG_AMOVIE_FILTER) += avformat avcodec
+FFLIBS-$(CONFIG_ARESAMPLE_FILTER) += swresample
+FFLIBS-$(CONFIG_ASYNCTS_FILTER) += avresample
+FFLIBS-$(CONFIG_ATEMPO_FILTER) += avcodec
+FFLIBS-$(CONFIG_DECIMATE_FILTER) += avcodec
+FFLIBS-$(CONFIG_DESHAKE_FILTER) += avcodec
+FFLIBS-$(CONFIG_MCDEINT_FILTER) += avcodec
+FFLIBS-$(CONFIG_MOVIE_FILTER) += avformat avcodec
+FFLIBS-$(CONFIG_MP_FILTER) += avcodec
+FFLIBS-$(CONFIG_PAN_FILTER) += swresample
+FFLIBS-$(CONFIG_PP_FILTER) += postproc
+FFLIBS-$(CONFIG_REMOVELOGO_FILTER) += avformat avcodec swscale
+FFLIBS-$(CONFIG_RESAMPLE_FILTER) += avresample
+FFLIBS-$(CONFIG_SAB_FILTER) += swscale
+FFLIBS-$(CONFIG_SCALE_FILTER) += swscale
+FFLIBS-$(CONFIG_SHOWSPECTRUM_FILTER) += avcodec
+FFLIBS-$(CONFIG_SMARTBLUR_FILTER) += swscale
+FFLIBS-$(CONFIG_SUBTITLES_FILTER) += avformat avcodec
-HEADERS = avfilter.h \
+HEADERS = asrc_abuffer.h \
+ avcodec.h \
+ avfilter.h \
avfiltergraph.h \
buffersink.h \
buffersrc.h \
@@ -21,78 +40,222 @@ 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_AVFORMAT) += lavfutils.o
+OBJS-$(CONFIG_SWSCALE) += lswsutils.o
+
+OBJS-$(CONFIG_ACONVERT_FILTER) += af_aconvert.o
+OBJS-$(CONFIG_ADELAY_FILTER) += af_adelay.o
+OBJS-$(CONFIG_AECHO_FILTER) += af_aecho.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
+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) += f_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_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_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_TREBLE_FILTER) += af_biquads.o
OBJS-$(CONFIG_VOLUME_FILTER) += af_volume.o
+OBJS-$(CONFIG_VOLUMEDETECT_FILTER) += af_volumedetect.o
+OBJS-$(CONFIG_AEVALSRC_FILTER) += asrc_aevalsrc.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_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_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_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_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_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_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) += vf_settb.o
+OBJS-$(CONFIG_SETTB_FILTER) += f_settb.o
OBJS-$(CONFIG_SHOWINFO_FILTER) += vf_showinfo.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_YADIF_FILTER) += vf_yadif.o
+OBJS-$(CONFIG_ZMQ_FILTER) += f_zmq.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_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
+
+SKIPHEADERS-$(CONFIG_LIBVIDSTAB) += vidstabutils.h
+SKIPHEADERS-$(CONFIG_OPENCL) += opencl_internal.h deshake_opencl_kernel.h unsharp_opencl_kernel.h
+
OBJS-$(HAVE_THREADS) += pthread.o
TOOLS = graph2dot
-TESTPROGS = filtfmts
+TESTPROGS = drawutils filtfmts formats
+
+TOOLS-$(CONFIG_LIBZMQ) += zmqsend
+
+clean::
+ $(RM) $(CLEANSUFFIXES:%=libavfilter/libmpcodecs/%)
diff --git a/libavfilter/af_aconvert.c b/libavfilter/af_aconvert.c
new file mode 100644
index 0000000..10497aa
--- a/dev/null
+++ b/libavfilter/af_aconvert.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram <smeenaks@ucsd.edu>
+ * 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
+ * sample format and channel layout conversion audio filter
+ */
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libswresample/swresample.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ enum AVSampleFormat out_sample_fmt;
+ int64_t out_chlayout;
+ struct SwrContext *swr;
+ char *format_str;
+ char *channel_layout_str;
+} AConvertContext;
+
+#define OFFSET(x) offsetof(AConvertContext, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM
+#define F AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption aconvert_options[] = {
+ { "sample_fmt", "", OFFSET(format_str), AV_OPT_TYPE_STRING, .flags = A|F },
+ { "channel_layout", "", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A|F },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(aconvert);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ AConvertContext *aconvert = ctx->priv;
+ int ret = 0;
+
+ av_log(ctx, AV_LOG_WARNING, "This filter is deprecated, use aformat instead\n");
+
+ aconvert->out_sample_fmt = AV_SAMPLE_FMT_NONE;
+ aconvert->out_chlayout = 0;
+
+ if (aconvert->format_str && strcmp(aconvert->format_str, "auto") &&
+ (ret = ff_parse_sample_format(&aconvert->out_sample_fmt, aconvert->format_str, ctx)) < 0)
+ return ret;
+ if (aconvert->channel_layout_str && strcmp(aconvert->channel_layout_str, "auto"))
+ return ff_parse_channel_layout(&aconvert->out_chlayout, aconvert->channel_layout_str, ctx);
+ return ret;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ AConvertContext *aconvert = ctx->priv;
+ swr_free(&aconvert->swr);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ AConvertContext *aconvert = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFilterChannelLayouts *layouts;
+
+ ff_formats_ref(ff_all_formats(AVMEDIA_TYPE_AUDIO),
+ &inlink->out_formats);
+ if (aconvert->out_sample_fmt != AV_SAMPLE_FMT_NONE) {
+ formats = NULL;
+ ff_add_format(&formats, aconvert->out_sample_fmt);
+ ff_formats_ref(formats, &outlink->in_formats);
+ } else
+ ff_formats_ref(ff_all_formats(AVMEDIA_TYPE_AUDIO),
+ &outlink->in_formats);
+
+ ff_channel_layouts_ref(ff_all_channel_layouts(),
+ &inlink->out_channel_layouts);
+ if (aconvert->out_chlayout != 0) {
+ layouts = NULL;
+ ff_add_channel_layout(&layouts, aconvert->out_chlayout);
+ ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts);
+ } else
+ ff_channel_layouts_ref(ff_all_channel_layouts(),
+ &outlink->in_channel_layouts);
+
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ int ret;
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AConvertContext *aconvert = ctx->priv;
+ char buf1[64], buf2[64];
+
+ /* if not specified in args, use the format and layout of the output */
+ if (aconvert->out_sample_fmt == AV_SAMPLE_FMT_NONE)
+ aconvert->out_sample_fmt = outlink->format;
+ if (aconvert->out_chlayout == 0)
+ aconvert->out_chlayout = outlink->channel_layout;
+
+ aconvert->swr = swr_alloc_set_opts(aconvert->swr,
+ aconvert->out_chlayout, aconvert->out_sample_fmt, inlink->sample_rate,
+ inlink->channel_layout, inlink->format, inlink->sample_rate,
+ 0, ctx);
+ if (!aconvert->swr)
+ return AVERROR(ENOMEM);
+ ret = swr_init(aconvert->swr);
+ if (ret < 0)
+ return ret;
+
+ av_get_channel_layout_string(buf1, sizeof(buf1),
+ -1, inlink ->channel_layout);
+ av_get_channel_layout_string(buf2, sizeof(buf2),
+ -1, outlink->channel_layout);
+ av_log(ctx, AV_LOG_VERBOSE,
+ "fmt:%s cl:%s -> fmt:%s cl:%s\n",
+ av_get_sample_fmt_name(inlink ->format), buf1,
+ av_get_sample_fmt_name(outlink->format), buf2);
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
+{
+ AConvertContext *aconvert = inlink->dst->priv;
+ const int n = insamplesref->nb_samples;
+ AVFilterLink *const outlink = inlink->dst->outputs[0];
+ AVFrame *outsamplesref = ff_get_audio_buffer(outlink, n);
+ int ret;
+
+ if (!outsamplesref)
+ return AVERROR(ENOMEM);
+ swr_convert(aconvert->swr, outsamplesref->extended_data, n,
+ (void *)insamplesref->extended_data, n);
+
+ av_frame_copy_props(outsamplesref, insamplesref);
+ av_frame_set_channels(outsamplesref, outlink->channels);
+ outsamplesref->channel_layout = outlink->channel_layout;
+
+ ret = ff_filter_frame(outlink, outsamplesref);
+ av_frame_free(&insamplesref);
+ return ret;
+}
+
+static const AVFilterPad aconvert_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad aconvert_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_aconvert = {
+ .name = "aconvert",
+ .description = NULL_IF_CONFIG_SMALL("Convert the input audio to sample_fmt:channel_layout."),
+ .priv_size = sizeof(AConvertContext),
+ .priv_class = &aconvert_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = aconvert_inputs,
+ .outputs = aconvert_outputs,
+};
diff --git a/libavfilter/af_adelay.c b/libavfilter/af_adelay.c
new file mode 100644
index 0000000..363b84d
--- a/dev/null
+++ b/libavfilter/af_adelay.c
@@ -0,0 +1,283 @@
+/*
+ * 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_free(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..9c86f8d
--- a/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);
+
+ if (frame != out_frame)
+ av_frame_free(&frame);
+
+ s->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], 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..fbf9802
--- a/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, (AVRational){1, outlink->sample_rate}, outlink->time_base);
+
+ 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..82b694b
--- a/dev/null
+++ b/libavfilter/af_amerge.c
@@ -0,0 +1,350 @@
+/*
+ * 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 "libswresample/swresample.h" // only for SWR_CH_MAX
+#include "avfilter.h"
+#include "audio.h"
+#include "bufferqueue.h"
+#include "internal.h"
+
+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,
+ (AVRational){ 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..7140b6c 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
*/
@@ -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.
@@ -552,17 +547,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..88a3a77
--- a/dev/null
+++ b/libavfilter/af_apad.c
@@ -0,0 +1,156 @@
+/*
+ * 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;
+ int64_t whole_len;
+} 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", "number of samples of silence to add", OFFSET(pad_len), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, A },
+ { "whole_len", "target number of samples in the audio stream", OFFSET(whole_len), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, 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 && apad->pad_len) {
+ av_log(ctx, AV_LOG_ERROR, "Both whole and pad length are set, this is not possible\n");
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ APadContext *apad = ctx->priv;
+
+ if (apad->whole_len)
+ apad->whole_len -= frame->nb_samples;
+
+ 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 = apad->whole_len;
+ apad->whole_len = 0;
+ }
+ if (apad->pad_len > 0) {
+ n_out = FFMIN(n_out, apad->pad_len);
+ apad->pad_len -= n_out;
+ }
+
+ 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..0fc45ea
--- a/dev/null
+++ b/libavfilter/af_aphaser.c
@@ -0,0 +1,358 @@
+/*
+ * 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"
+
+enum WaveType {
+ WAVE_SIN,
+ WAVE_TRI,
+ WAVE_NB,
+};
+
+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;
+}
+
+static void 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);
+ }
+ }
+}
+
+#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(p->modulation_buffer_length * sizeof(*p->modulation_buffer));
+
+ if (!p->modulation_buffer || !p->delay_buffer)
+ return AVERROR(ENOMEM);
+
+ 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..86e7b74
--- a/dev/null
+++ b/libavfilter/af_aresample.c
@@ -0,0 +1,309 @@
+/*
+ * 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;
+} 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) {
+ out_samplerates = ff_make_format_list((int[]){ out_rate, -1 });
+ } else {
+ out_samplerates = ff_all_samplerates();
+ }
+ ff_formats_ref(out_samplerates, &outlink->in_samplerates);
+
+ if(out_format != AV_SAMPLE_FMT_NONE) {
+ out_formats = ff_make_format_list((int[]){ out_format, -1 });
+ } else
+ out_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO);
+ ff_formats_ref(out_formats, &outlink->in_formats);
+
+ if(out_layout) {
+ out_layouts = avfilter_make_format64_list((int64_t[]){ out_layout, -1 });
+ } 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;
+ int n_out = n_in * aresample->ratio * 2 + 256;
+ AVFilterLink *const outlink = inlink->dst->outputs[0];
+ AVFrame *outsamplesref = ff_get_audio_buffer(outlink, n_out);
+ int ret;
+
+ 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;
+ }
+
+ outsamplesref->nb_samples = n_out;
+
+ ret = ff_filter_frame(outlink, outsamplesref);
+ aresample->req_fullfilled= 1;
+ av_frame_free(&insamplesref);
+ return ret;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AResampleContext *aresample = ctx->priv;
+ AVFilterLink *const inlink = outlink->src->inputs[0];
+ int ret;
+
+ aresample->req_fullfilled = 0;
+ do{
+ ret = ff_request_frame(ctx->inputs[0]);
+ }while(!aresample->req_fullfilled && ret>=0);
+
+ if (ret == AVERROR_EOF) {
+ AVFrame *outsamplesref;
+ int n_out = 4096;
+
+ outsamplesref = ff_get_audio_buffer(outlink, n_out);
+ if (!outsamplesref)
+ return AVERROR(ENOMEM);
+ n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out, 0, 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;
+#if 0
+ outsamplesref->pts = aresample->next_pts;
+ if(aresample->next_pts != AV_NOPTS_VALUE)
+ aresample->next_pts += av_rescale_q(n_out, (AVRational){1 ,outlink->sample_rate}, outlink->time_base);
+#else
+ outsamplesref->pts = swr_next_pts(aresample->swr, INT64_MIN);
+ outsamplesref->pts = ROUNDED_DIV(outsamplesref->pts, inlink->sample_rate);
+#endif
+
+ 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..fbcf275
--- a/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 += nb_out_samples;
+
+ 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
--- a/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 2a2edcf..783f9a6 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
*/
@@ -31,6 +31,7 @@
#include "libavutil/channel_layout.h"
#include "libavutil/common.h"
#include "libavutil/mem.h"
+#include "libavutil/timestamp.h"
#include "libavutil/samplefmt.h"
#include "audio.h"
@@ -42,24 +43,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;
@@ -72,12 +57,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];
@@ -91,11 +81,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:%08X ",
- 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);
@@ -104,19 +96,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
av_log(ctx, AV_LOG_INFO, "%08X ", s->plane_checksums[i]);
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[] = {
@@ -124,7 +113,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
--- a/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
--- a/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 b76ddf0..dc8805c 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
*/
@@ -49,21 +49,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)
{
@@ -296,9 +292,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 }
};
@@ -316,13 +312,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..c474d6a
--- a/dev/null
+++ b/libavfilter/af_atempo.c
@@ -0,0 +1,1196 @@
+/*
+ * 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);
+ }
+ }
+
+ // flush the remaininder 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);
+ if (ret < 0)
+ return ret;
+ atempo->dst_buffer = NULL;
+ atempo->dst = NULL;
+ atempo->dst_end = NULL;
+
+ 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..5bafad1
--- a/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) \
+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 (o2 < min) { \
+ av_log(NULL, AV_LOG_WARNING, "clipping\n"); \
+ obuf[i] = min; \
+ } else if (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 (o1 < min) { \
+ av_log(NULL, AV_LOG_WARNING, "clipping\n"); \
+ obuf[i] = min; \
+ } else if (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 (o0 < min) { \
+ av_log(NULL, AV_LOG_WARNING, "clipping\n"); \
+ obuf[i] = min; \
+ } else if (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)
+BIQUAD_FILTER(s32, int32_t, INT32_MIN, INT32_MAX)
+BIQUAD_FILTER(flt, float, -1., 1.)
+BIQUAD_FILTER(dbl, double, -1., 1.)
+
+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_channelmap.c b/libavfilter/af_channelmap.c
index 71d51e7..e5e8987 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);
@@ -387,7 +383,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 }
};
@@ -407,7 +404,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
new file mode 100644
index 0000000..ec1e962
--- a/dev/null
+++ b/libavfilter/af_compand.c
@@ -0,0 +1,518 @@
+/*
+ * Copyright (c) 1999 Chris Bagwell
+ * Copyright (c) 1999 Nick Bailey
+ * Copyright (c) 2007 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 "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 ChanParam {
+ double attack;
+ double decay;
+ double volume;
+} ChanParam;
+
+typedef struct CompandSegment {
+ double x, y;
+ double a, b;
+} CompandSegment;
+
+typedef struct CompandContext {
+ const AVClass *class;
+ char *attacks, *decays, *points;
+ CompandSegment *segments;
+ ChanParam *channels;
+ double in_min_lin;
+ double out_min_lin;
+ double curve_dB;
+ double gain_dB;
+ double initial_volume;
+ double delay;
+ uint8_t **delayptrs;
+ int delay_samples;
+ int delay_count;
+ int delay_index;
+ int64_t pts;
+
+ int (*compand)(AVFilterContext *ctx, AVFrame *frame);
+} CompandContext;
+
+#define OFFSET(x) offsetof(CompandContext, x)
+#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=NULL}, 0, 0, A },
+ { "decays", "set time over which decrease of volume is determined", OFFSET(decays), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A },
+ { "points", "set points of transfer function", OFFSET(points), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A },
+ { "soft-knee", "set soft-knee", OFFSET(curve_dB), AV_OPT_TYPE_DOUBLE, {.dbl=0.01}, 0.01, 900, A },
+ { "gain", "set output gain", OFFSET(gain_dB), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, A },
+ { "volume", "set initial volume", OFFSET(initial_volume), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 0, A },
+ { "delay", "set delay for samples before sending them to volume adjuster", OFFSET(delay), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 20, A },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(compand);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ CompandContext *s = ctx->priv;
+
+ if (!s->attacks || !s->decays || !s->points) {
+ av_log(ctx, AV_LOG_ERROR, "Missing attacks and/or decays and/or points.\n");
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ CompandContext *s = ctx->priv;
+
+ av_freep(&s->channels);
+ av_freep(&s->segments);
+ if (s->delayptrs)
+ av_freep(&s->delayptrs[0]);
+ av_freep(&s->delayptrs);
+}
+
+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 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 update_volume(ChanParam *cp, double in)
+{
+ double delta = in - cp->volume;
+
+ if (delta > 0.0)
+ cp->volume += delta * cp->attack;
+ else
+ cp->volume += delta * cp->decay;
+}
+
+static double get_volume(CompandContext *s, double in_lin)
+{
+ CompandSegment *cs;
+ double in_log, out_log;
+ int i;
+
+ if (in_lin < s->in_min_lin)
+ return s->out_min_lin;
+
+ in_log = log(in_lin);
+
+ for (i = 1;; i++)
+ if (in_log <= s->segments[i + 1].x)
+ break;
+
+ cs = &s->segments[i];
+ in_log -= cs->x;
+ out_log = cs->y + in_log * (cs->a * in_log + cs->b);
+
+ return exp(out_log);
+}
+
+static int compand_nodelay(AVFilterContext *ctx, AVFrame *frame)
+{
+ CompandContext *s = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ const int channels = inlink->channels;
+ const int nb_samples = frame->nb_samples;
+ AVFrame *out_frame;
+ int chan, i;
+
+ if (av_frame_is_writable(frame)) {
+ out_frame = frame;
+ } else {
+ out_frame = ff_get_audio_buffer(inlink, nb_samples);
+ if (!out_frame)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out_frame, frame);
+ }
+
+ for (chan = 0; chan < channels; 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_clipd(src[i] * get_volume(s, cp->volume), -1, 1);
+ }
+ }
+
+ if (frame != out_frame)
+ av_frame_free(&frame);
+
+ return ff_filter_frame(ctx->outputs[0], out_frame);
+}
+
+#define MOD(a, b) (((a) >= (b)) ? (a) - (b) : (a))
+
+static int compand_delay(AVFilterContext *ctx, AVFrame *frame)
+{
+ CompandContext *s = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ const int channels = inlink->channels;
+ const int nb_samples = frame->nb_samples;
+ int chan, i, av_uninit(dindex), oindex, av_uninit(count);
+ AVFrame *out_frame = NULL;
+
+ av_assert1(channels > 0); /* would corrupt delay_count and delay_index */
+
+ for (chan = 0; chan < channels; chan++) {
+ const double *src = (double *)frame->extended_data[chan];
+ double *dbuf = (double *)s->delayptrs[chan];
+ ChanParam *cp = &s->channels[chan];
+ double *dst;
+
+ count = s->delay_count;
+ dindex = s->delay_index;
+ for (i = 0, oindex = 0; i < nb_samples; i++) {
+ const double in = src[i];
+ update_volume(cp, fabs(in));
+
+ if (count >= s->delay_samples) {
+ if (!out_frame) {
+ out_frame = ff_get_audio_buffer(inlink, nb_samples - i);
+ if (!out_frame)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out_frame, frame);
+ out_frame->pts = s->pts;
+ s->pts += av_rescale_q(nb_samples - i, (AVRational){1, inlink->sample_rate}, inlink->time_base);
+ }
+
+ dst = (double *)out_frame->extended_data[chan];
+ dst[oindex++] = av_clipd(dbuf[dindex] * get_volume(s, cp->volume), -1, 1);
+ } else {
+ count++;
+ }
+
+ dbuf[dindex] = in;
+ dindex = MOD(dindex + 1, s->delay_samples);
+ }
+ }
+
+ s->delay_count = count;
+ s->delay_index = dindex;
+
+ av_frame_free(&frame);
+ return out_frame ? ff_filter_frame(ctx->outputs[0], out_frame) : 0;
+}
+
+static int compand_drain(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ CompandContext *s = ctx->priv;
+ const int channels = outlink->channels;
+ int chan, i, dindex;
+ AVFrame *frame = NULL;
+
+ frame = ff_get_audio_buffer(outlink, FFMIN(2048, s->delay_count));
+ if (!frame)
+ return AVERROR(ENOMEM);
+ frame->pts = s->pts;
+ s->pts += av_rescale_q(frame->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
+
+ for (chan = 0; chan < channels; chan++) {
+ double *dbuf = (double *)s->delayptrs[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_clipd(dbuf[dindex] * get_volume(s, cp->volume), -1, 1);
+ dindex = MOD(dindex + 1, s->delay_samples);
+ }
+ }
+ s->delay_count -= frame->nb_samples;
+ s->delay_index = dindex;
+
+ return ff_filter_frame(outlink, frame);
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ CompandContext *s = ctx->priv;
+ const int sample_rate = outlink->sample_rate;
+ double radius = s->curve_dB * M_LN10 / 20;
+ int nb_attacks, nb_decays, nb_points;
+ char *p, *saveptr = NULL;
+ int new_nb_items, num;
+ int i;
+
+ count_items(s->attacks, &nb_attacks);
+ count_items(s->decays, &nb_decays);
+ count_items(s->points, &nb_points);
+
+ if ((nb_attacks > outlink->channels) || (nb_decays > outlink->channels)) {
+ av_log(ctx, AV_LOG_ERROR, "Number of attacks/decays bigger than number of channels.\n");
+ return AVERROR(EINVAL);
+ }
+
+ uninit(ctx);
+
+ s->channels = av_mallocz_array(outlink->channels, sizeof(*s->channels));
+ s->segments = av_mallocz_array((nb_points + 4) * 2, sizeof(*s->segments));
+
+ if (!s->channels || !s->segments)
+ return AVERROR(ENOMEM);
+
+ p = s->attacks;
+ for (i = 0, new_nb_items = 0; i < nb_attacks; i++) {
+ 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)
+ return AVERROR(EINVAL);
+ }
+ nb_attacks = new_nb_items;
+
+ p = s->decays;
+ for (i = 0, new_nb_items = 0; i < nb_decays; i++) {
+ 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)
+ return AVERROR(EINVAL);
+ }
+ nb_decays = new_nb_items;
+
+ if (nb_attacks != nb_decays) {
+ av_log(ctx, AV_LOG_ERROR, "Number of attacks %d differs from number of decays %d.\n", nb_attacks, nb_decays);
+ return AVERROR(EINVAL);
+ }
+
+#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_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");
+ return AVERROR(EINVAL);
+ }
+ if (i && S(i - 1).x > S(i).x) {
+ av_log(ctx, AV_LOG_ERROR, "Transfer function input values must be increasing.\n");
+ return AVERROR(EINVAL);
+ }
+ 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++;
+ }
+ num = new_nb_items;
+
+ /* Add 0,0 if necessary */
+ if (num == 0 || S(num - 1).x)
+ num++;
+
+#undef S
+#define S(x) s->segments[2 * (x)]
+ /* Add a tail off segment at the start */
+ S(0).x = S(1).x - 2 * s->curve_dB;
+ S(0).y = S(1).y;
+ num++;
+
+ /* Join adjacent colinear segments */
+ for (i = 2; i < num; i++) {
+ double g1 = (S(i - 1).y - S(i - 2).y) * (S(i - 0).x - S(i - 1).x);
+ double g2 = (S(i - 0).y - S(i - 1).y) * (S(i - 1).x - S(i - 2).x);
+ int j;
+
+ if (fabs(g1 - g2))
+ continue;
+ num--;
+ for (j = --i; j < num; j++)
+ S(j) = S(j + 1);
+ }
+
+ for (i = 0; !i || s->segments[i - 2].x; i += 2) {
+ s->segments[i].y += s->gain_dB;
+ s->segments[i].x *= M_LN10 / 20;
+ s->segments[i].y *= M_LN10 / 20;
+ }
+
+#define L(x) s->segments[i - (x)]
+ for (i = 4; s->segments[i - 2].x; i += 2) {
+ double x, y, cx, cy, in1, in2, out1, out2, theta, len, r;
+
+ L(4).a = 0;
+ L(4).b = (L(2).y - L(4).y) / (L(2).x - L(4).x);
+
+ L(2).a = 0;
+ L(2).b = (L(0).y - L(2).y) / (L(0).x - L(2).x);
+
+ theta = atan2(L(2).y - L(4).y, L(2).x - L(4).x);
+ len = sqrt(pow(L(2).x - L(4).x, 2.) + pow(L(2).y - L(4).y, 2.));
+ r = FFMIN(radius, len);
+ L(3).x = L(2).x - r * cos(theta);
+ L(3).y = L(2).y - r * sin(theta);
+
+ theta = atan2(L(0).y - L(2).y, L(0).x - L(2).x);
+ len = sqrt(pow(L(0).x - L(2).x, 2.) + pow(L(0).y - L(2).y, 2.));
+ r = FFMIN(radius, len / 2);
+ x = L(2).x + r * cos(theta);
+ y = L(2).y + r * sin(theta);
+
+ cx = (L(3).x + L(2).x + x) / 3;
+ cy = (L(3).y + L(2).y + y) / 3;
+
+ L(2).x = x;
+ L(2).y = y;
+
+ in1 = cx - L(3).x;
+ out1 = cy - L(3).y;
+ in2 = L(2).x - L(3).x;
+ out2 = L(2).y - L(3).y;
+ L(3).a = (out2 / in2 - out1 / in1) / (in2-in1);
+ L(3).b = out1 / in1 - L(3).a * in1;
+ }
+ L(3).x = 0;
+ L(3).y = L(2).y;
+
+ s->in_min_lin = exp(s->segments[1].x);
+ s->out_min_lin = exp(s->segments[1].y);
+
+ for (i = 0; i < outlink->channels; i++) {
+ ChanParam *cp = &s->channels[i];
+
+ if (cp->attack > 1.0 / sample_rate)
+ cp->attack = 1.0 - exp(-1.0 / (sample_rate * cp->attack));
+ else
+ cp->attack = 1.0;
+ if (cp->decay > 1.0 / sample_rate)
+ cp->decay = 1.0 - exp(-1.0 / (sample_rate * cp->decay));
+ else
+ cp->decay = 1.0;
+ cp->volume = pow(10.0, s->initial_volume / 20);
+ }
+
+ s->delay_samples = s->delay * sample_rate;
+ if (s->delay_samples > 0) {
+ int ret;
+ if ((ret = av_samples_alloc_array_and_samples(&s->delayptrs, NULL,
+ outlink->channels,
+ s->delay_samples,
+ outlink->format, 0)) < 0)
+ return ret;
+ s->compand = compand_delay;
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ } else {
+ s->compand = compand_nodelay;
+ }
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ CompandContext *s = ctx->priv;
+
+ return s->compand(ctx, frame);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ CompandContext *s = ctx->priv;
+ int ret;
+
+ ret = ff_request_frame(ctx->inputs[0]);
+
+ if (ret == AVERROR_EOF && !ctx->is_disabled && s->delay_count)
+ ret = compand_drain(outlink);
+
+ return ret;
+}
+
+static const AVFilterPad compand_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad compand_outputs[] = {
+ {
+ .name = "default",
+ .request_frame = request_frame,
+ .config_props = config_output,
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_compand = {
+ .name = "compand",
+ .description = NULL_IF_CONFIG_SMALL("Compress or expand audio dynamic range."),
+ .query_formats = query_formats,
+ .priv_size = sizeof(CompandContext),
+ .priv_class = &compand_class,
+ .init = init,
+ .uninit = uninit,
+ .inputs = compand_inputs,
+ .outputs = compand_outputs,
+};
diff --git a/libavfilter/af_earwax.c b/libavfilter/af_earwax.c
new file mode 100644
index 0000000..c310997
--- a/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_join.c b/libavfilter/af_join.c
index ee87340..3e9ccc8 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)
@@ -479,6 +469,8 @@ 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->format = outlink->format;
frame->sample_rate = outlink->sample_rate;
frame->pts = s->input_frames[0]->pts;
frame->linesize[0] = linesize;
@@ -512,16 +504,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..82c3d70
--- a/dev/null
+++ b/libavfilter/af_ladspa.c
@@ -0,0 +1,703 @@
+/*
+ * 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,
+ av_x_if_null(desc->Name, "?"));
+ av_log(ctx, AV_LOG_VERBOSE, "Maker: %s\n", av_x_if_null(desc->Maker, "?"));
+ av_log(ctx, AV_LOG_VERBOSE, "Copyright: %s\n", 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..1a01664
--- a/dev/null
+++ b/libavfilter/af_pan.c
@@ -0,0 +1,422 @@
+/*
+ * 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_input_channels;
+ int nb_output_channels;
+
+ int pure_gains;
+ /* channel mapping specific */
+ int channel_map[SWR_CH_MAX];
+ 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, arg, ctx);
+ if (ret < 0)
+ goto fail;
+ pan->nb_output_channels = av_get_channel_layout_nb_channels(pan->out_channel_layout);
+
+ /* 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_layouts();
+ 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);
+ 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;
+
+ pan->nb_input_channels = av_get_channel_layout_nb_channels(link->channel_layout);
+ 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 (pan->nb_input_channels > SWR_CH_MAX ||
+ pan->nb_output_channels > SWR_CH_MAX) {
+ av_log(ctx, AV_LOG_ERROR,
+ "libswresample support a maximum of %d channels. "
+ "Feel free to ask for a higher limit.\n", SWR_CH_MAX);
+ 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);
+
+ // 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 < pan->nb_input_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 < pan->nb_input_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 < pan->nb_input_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 < pan->nb_input_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->data, n, (void *)insamples->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
--- a/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 224e0ed..bf32aa7 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
*/
@@ -298,9 +297,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 }
};
@@ -320,11 +319,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
--- a/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_volume.c b/libavfilter/af_volume.c
index 85d7067..cd24877 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
*/
@@ -41,24 +41,20 @@ static const char *precision_str[] = {
#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" },
- { NULL },
+#define F AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption volume_options[] = {
+ { "volume", "set volume adjustment",
+ OFFSET(volume), AV_OPT_TYPE_DOUBLE, { .dbl = 1.0 }, 0, 0x7fffff, 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" },
+ { 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)
{
@@ -84,8 +80,7 @@ static int query_formats(AVFilterContext *ctx)
AVFilterFormats *formats = NULL;
AVFilterChannelLayouts *layouts;
static const enum AVSampleFormat sample_fmts[][7] = {
- /* PRECISION_FIXED */
- {
+ [PRECISION_FIXED] = {
AV_SAMPLE_FMT_U8,
AV_SAMPLE_FMT_U8P,
AV_SAMPLE_FMT_S16,
@@ -94,14 +89,12 @@ 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
@@ -172,8 +165,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;
@@ -240,7 +231,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
out_buf = ff_get_audio_buffer(inlink, nb_samples);
if (!out_buf)
return AVERROR(ENOMEM);
- out_buf->pts = buf->pts;
+ av_frame_copy_props(out_buf, buf);
}
if (vol->precision != PRECISION_FIXED || vol->volume_i > 0) {
@@ -305,4 +296,5 @@ AVFilter ff_af_volume = {
.init = init,
.inputs = avfilter_af_volume_inputs,
.outputs = avfilter_af_volume_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
};
diff --git a/libavfilter/af_volume.h b/libavfilter/af_volume.h
index a1883ed..bd7932e 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
*/
diff --git a/libavfilter/af_volumedetect.c b/libavfilter/af_volumedetect.c
new file mode 100644
index 0000000..5de115e
--- a/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
--- a/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 f041f5c..a61ca0e 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,74 +45,198 @@ void avfilter_register_all(void)
return;
initialized = 1;
+#if FF_API_ACONVERT_FILTER
+ REGISTER_FILTER(ACONVERT, aconvert, af);
+#endif
+ REGISTER_FILTER(ADELAY, adelay, af);
+ REGISTER_FILTER(AECHO, aecho, 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(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(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(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(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(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(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(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(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(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(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(YADIF, yadif, vf);
+ REGISTER_FILTER(ZMQ, zmq, 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(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);
@@ -120,4 +245,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
--- a/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_aevalsrc.c b/libavfilter/asrc_aevalsrc.c
new file mode 100644
index 0000000..ded533d
--- a/dev/null
+++ b/libavfilter/asrc_aevalsrc.c
@@ -0,0 +1,242 @@
+/*
+ * 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[] = {
+ "n", ///< number of frame
+ "t", ///< timestamp expressed in seconds
+ "s", ///< sample rate
+ NULL
+};
+
+enum var_name {
+ VAR_N,
+ 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;
+ 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];
+} EvalContext;
+
+#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 av_cold int init(AVFilterContext *ctx)
+{
+ EvalContext *eval = ctx->priv;
+ char *args1 = av_strdup(eval->exprs);
+ char *expr, *buf;
+ int ret;
+
+ if (!args1) {
+ av_log(ctx, AV_LOG_ERROR, "Channels expressions list is empty\n");
+ ret = eval->exprs ? AVERROR(ENOMEM) : AVERROR(EINVAL);
+ goto end;
+ }
+
+ /* parse expressions */
+ buf = args1;
+ while (expr = av_strtok(buf, "|", &buf)) {
+ if (!av_dynarray2_add((void **)&eval->expr, &eval->nb_channels, sizeof(*eval->expr), NULL)) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ ret = av_expr_parse(&eval->expr[eval->nb_channels - 1], expr, var_names,
+ NULL, NULL, NULL, NULL, 0, ctx);
+ if (ret < 0)
+ goto end;
+ }
+
+ if (eval->chlayout_str) {
+ int n;
+ ret = ff_parse_channel_layout(&eval->chlayout, eval->chlayout_str, ctx);
+ if (ret < 0)
+ goto end;
+
+ n = av_get_channel_layout_nb_channels(eval->chlayout);
+ if (n != eval->nb_channels) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Mismatch between the specified number of channels '%d' "
+ "and the number of channels '%d' in the specified channel layout '%s'\n",
+ eval->nb_channels, n, eval->chlayout_str);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ } else {
+ /* guess channel layout from nb expressions/channels */
+ 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);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ }
+
+ if ((ret = ff_parse_sample_rate(&eval->sample_rate, eval->sample_rate_str, ctx)))
+ goto end;
+ eval->n = 0;
+
+end:
+ av_free(args1);
+ 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;
+
+ 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);
+}
+
+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,
+};
diff --git a/libavfilter/asrc_anullsrc.c b/libavfilter/asrc_anullsrc.c
index b1a449c..26b32e1 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->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
--- a/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
--- a/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..315c273 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;
@@ -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..605e5d2
--- a/dev/null
+++ b/libavfilter/avcodec.c
@@ -0,0 +1,157 @@
+/*
+ * 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(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
+
+#if FF_API_FILL_FRAME
+int avfilter_fill_frame_from_audio_buffer_ref(AVFrame *frame,
+ const AVFilterBufferRef *samplesref)
+{
+ return avfilter_copy_buf_props(frame, samplesref);
+}
+
+int avfilter_fill_frame_from_video_buffer_ref(AVFrame *frame,
+ const AVFilterBufferRef *picref)
+{
+ return avfilter_copy_buf_props(frame, picref);
+}
+
+int avfilter_fill_frame_from_buffer_ref(AVFrame *frame,
+ const AVFilterBufferRef *ref)
+{
+ return avfilter_copy_buf_props(frame, ref);
+}
+#endif
diff --git a/libavfilter/avcodec.h b/libavfilter/avcodec.h
new file mode 100644
index 0000000..8bbdad2
--- a/dev/null
+++ b/libavfilter/avcodec.h
@@ -0,0 +1,110 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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
+
+#if FF_API_FILL_FRAME
+/**
+ * Fill an AVFrame with the information stored in samplesref.
+ *
+ * @param frame an already allocated AVFrame
+ * @param samplesref an audio buffer reference
+ * @return >= 0 in case of success, a negative AVERROR code in case of
+ * failure
+ * @deprecated Use avfilter_copy_buf_props() instead.
+ */
+attribute_deprecated
+int avfilter_fill_frame_from_audio_buffer_ref(AVFrame *frame,
+ const AVFilterBufferRef *samplesref);
+
+/**
+ * Fill an AVFrame with the information stored in picref.
+ *
+ * @param frame an already allocated AVFrame
+ * @param picref a video buffer reference
+ * @return >= 0 in case of success, a negative AVERROR code in case of
+ * failure
+ * @deprecated Use avfilter_copy_buf_props() instead.
+ */
+attribute_deprecated
+int avfilter_fill_frame_from_video_buffer_ref(AVFrame *frame,
+ const AVFilterBufferRef *picref);
+
+/**
+ * Fill an AVFrame with information stored in ref.
+ *
+ * @param frame an already allocated AVFrame
+ * @param ref a video or audio buffer reference
+ * @return >= 0 in case of success, a negative AVERROR code in case of
+ * failure
+ * @deprecated Use avfilter_copy_buf_props() instead.
+ */
+attribute_deprecated
+int avfilter_fill_frame_from_buffer_ref(AVFrame *frame,
+ const AVFilterBufferRef *ref);
+#endif
+
+#endif /* AVFILTER_AVCODEC_H */
diff --git a/libavfilter/avf_avectorscope.c b/libavfilter/avf_avectorscope.c
new file mode 100644
index 0000000..3ca596c
--- a/dev/null
+++ b/libavfilter/avf_avectorscope.c
@@ -0,0 +1,273 @@
+/*
+ * 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..c211dc4
--- a/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 }, 2, 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,
+ (AVRational){ 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_showspectrum.c b/libavfilter/avf_showspectrum.c
new file mode 100644
index 0000000..33f8b82
--- a/dev/null
+++ b/libavfilter/avf_showspectrum.c
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2012 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 };
+
+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
+ int filled; ///< number of samples (per channel) filled in current rdft_buffer
+ int consumed; ///< number of samples (per channel) consumed from the input frame
+ float *window_func_lut; ///< Window function LUT
+ 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, 1, FLAGS },
+ { "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 },
+ { 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);
+ 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);
+ }
+ s->filled = 0;
+
+ /* pre-calc windowing function (hann here) */
+ 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);
+ for (i = 0; i < win_size; i++)
+ s->window_func_lut[i] = .5f * (1 - cos(2*M_PI*i / (win_size-1)));
+
+ /* 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;
+
+ 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;
+}
+
+inline static int push_frame(AVFilterLink *outlink)
+{
+ ShowSpectrumContext *s = outlink->src->priv;
+
+ s->xpos++;
+ if (s->xpos >= outlink->w)
+ s->xpos = 0;
+ s->filled = 0;
+ s->req_fullfilled = 1;
+
+ return ff_filter_frame(outlink, av_frame_clone(s->outpicref));
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ ShowSpectrumContext *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)
+ push_frame(outlink);
+ return ret;
+}
+
+static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples, int nb_samples)
+{
+ 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 ch, plane, n, y;
+ const int start = s->filled;
+ const int add_samples = FFMIN(win_size - start, nb_samples);
+
+ /* 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];
+
+ p += s->consumed;
+ for (n = 0; n < add_samples; n++)
+ s->rdft_data[ch][start + n] = p[n] * s->window_func_lut[start + n];
+ }
+ s->filled += add_samples;
+
+ /* complete RDFT window size? */
+ if (s->filled == win_size) {
+
+ /* channel height */
+ int h = s->channel_height;
+
+ /* 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) {
+ 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];
+ }
+ }
+
+ outpicref->pts = insamples->pts +
+ av_rescale_q(s->consumed,
+ (AVRational){ 1, inlink->sample_rate },
+ outlink->time_base);
+ ret = push_frame(outlink);
+ if (ret < 0)
+ return ret;
+ }
+
+ return add_samples;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ShowSpectrumContext *s = ctx->priv;
+ int ret = 0, left_samples = insamples->nb_samples;
+
+ s->consumed = 0;
+ while (left_samples) {
+ int ret = plot_spectrum_column(inlink, insamples, left_samples);
+ if (ret < 0)
+ break;
+ s->consumed += ret;
+ left_samples -= ret;
+ }
+
+ 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..0b45bd0
--- a/dev/null
+++ b/libavfilter/avf_showwaves.c
@@ -0,0 +1,256 @@
+/*
+ * 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_NB,
+};
+
+typedef struct {
+ const AVClass *class;
+ int w, h;
+ AVRational rate;
+ int buf_idx;
+ AVFrame *outpicref;
+ int req_fullfilled;
+ int n;
+ int sample_count_mod;
+ enum ShowWavesMode mode;
+} 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"},
+ { "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 },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(showwaves);
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ ShowWavesContext *showwaves = ctx->priv;
+
+ av_frame_free(&showwaves->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_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;
+
+ if (!showwaves->n)
+ showwaves->n = FFMAX(1, ((double)inlink->sample_rate / (showwaves->w * av_q2d(showwaves->rate))) + 0.5);
+
+ showwaves->buf_idx = 0;
+ 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)
+{
+ ShowWavesContext *showwaves = outlink->src->priv;
+ int ret;
+
+ if ((ret = ff_filter_frame(outlink, showwaves->outpicref)) >= 0)
+ showwaves->req_fullfilled = 1;
+ showwaves->outpicref = NULL;
+ showwaves->buf_idx = 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 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, k, h, ret = 0;
+ const int n = showwaves->n;
+ const int x = 255 / (nb_channels * n); /* multiplication factor, pre-computed to avoid in-loop divisions */
+
+ /* 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++) {
+ h = showwaves->h/2 - av_rescale(*p++, showwaves->h/2, MAX_INT16);
+ switch (showwaves->mode) {
+ case MODE_POINT:
+ if (h >= 0 && h < outlink->h)
+ *(outpicref->data[0] + showwaves->buf_idx + h * linesize) += x;
+ break;
+
+ case MODE_LINE:
+ {
+ int start = showwaves->h/2, end = av_clip(h, 0, outlink->h-1);
+ if (start > end) FFSWAP(int16_t, start, end);
+ for (k = start; k < end; k++)
+ *(outpicref->data[0] + showwaves->buf_idx + k * linesize) += x;
+ break;
+ }
+ }
+ }
+
+ 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 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."),
+ .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 b18c0cb..14ce55f 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,9 +224,13 @@ int avfilter_config_links(AVFilterContext *filter)
for (i = 0; i < filter->nb_inputs; i ++) {
AVFilterLink *link = filter->inputs[i];
+ AVFilterLink *inlink;
if (!link) continue;
+ inlink = link->src->nb_inputs ? link->src->inputs[0] : NULL;
+ link->current_pts = AV_NOPTS_VALUE;
+
switch (link->init_state) {
case AVLINK_INIT:
continue;
@@ -180,26 +258,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 && link->src->nb_inputs ?
- link->src->inputs[0]->time_base : AV_TIME_BASE_Q;
+ switch (link->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ if (!link->time_base.num && !link->time_base.den)
+ link->time_base = inlink ? inlink->time_base : AV_TIME_BASE_Q;
- if (link->type == AVMEDIA_TYPE_VIDEO) {
if (!link->sample_aspect_ratio.num && !link->sample_aspect_ratio.den)
- link->sample_aspect_ratio = link->src->nb_inputs ?
- link->src->inputs[0]->sample_aspect_ratio : (AVRational){1,1};
+ link->sample_aspect_ratio = inlink ?
+ inlink->sample_aspect_ratio : (AVRational){1,1};
- if (link->src->nb_inputs) {
+ if (inlink && !link->frame_rate.num && !link->frame_rate.den)
+ link->frame_rate = inlink->frame_rate;
+
+ if (inlink) {
if (!link->w)
- link->w = link->src->inputs[0]->w;
+ link->w = inlink->w;
if (!link->h)
- link->h = link->src->inputs[0]->h;
+ link->h = inlink->h;
} else if (!link->w || !link->h) {
av_log(link->src, AV_LOG_ERROR,
"Video source filters must set their output link's "
"width and height\n");
return AVERROR(EINVAL);
}
+ break;
+
+ case AVMEDIA_TYPE_AUDIO:
+ if (inlink) {
+ if (!link->time_base.num && !link->time_base.den)
+ link->time_base = inlink->time_base;
+ }
+
+ if (!link->time_base.num && !link->time_base.den)
+ link->time_base = (AVRational) {1, link->sample_rate};
}
if ((config_link = link->dstpad->config_props))
@@ -217,11 +308,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 : "",
@@ -231,9 +322,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 : "",
@@ -243,13 +334,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)
@@ -270,6 +381,80 @@ int ff_poll_frame(AVFilterLink *link)
return min;
}
+static const char *const var_names[] = { "t", "n", "pos", NULL };
+enum { VAR_T, VAR_N, VAR_POS, 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;
#if !FF_API_NOCONST_GET_NAME
@@ -284,7 +469,7 @@ 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;
}
@@ -292,10 +477,22 @@ AVFilter *avfilter_get_by_name(const char *name)
int avfilter_register(AVFilter *filter)
{
AVFilter **f = &first_filter;
- while (*f)
- f = &(*f)->next;
- *f = 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(avpriv_atomic_ptr_cas((void * volatile *)f, NULL, filter))
+ f = &(*f)->next;
+
return 0;
}
@@ -327,10 +524,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)
@@ -345,10 +542,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;
@@ -357,18 +560,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,
@@ -485,13 +690,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);
@@ -514,41 +722,93 @@ void avfilter_free(AVFilterContext *filter)
av_freep(&filter->inputs);
av_freep(&filter->outputs);
av_freep(&filter->priv);
+ while(filter->command_queue){
+ ff_command_queue_pop(filter);
+ }
+ av_opt_free(filter);
+ av_expr_free(filter->enable);
+ filter->enable = NULL;
+ av_freep(&filter->var_values);
av_freep(&filter->internal);
av_free(filter);
}
-/* process a list of value1:value2:..., each value corresponding
- * to subsequent AVOption, in the order they are declared */
-static int process_unnamed_options(AVFilterContext *ctx, AVDictionary **options,
- const char *args)
+static int process_options(AVFilterContext *ctx, AVDictionary **options,
+ const char *args)
{
const AVOption *o = NULL;
- const char *p = args;
- char *val;
+ int ret, count = 0;
+ char *av_uninit(parsed_key), *av_uninit(value);
+ const char *key;
+ int offset= -1;
+
+ if (!args)
+ return 0;
+
+ while (*args) {
+ const char *shorthand = NULL;
- while (*p) {
o = av_opt_next(ctx->priv, o);
- if (!o) {
- av_log(ctx, AV_LOG_ERROR, "More options provided than "
- "this filter supports.\n");
- return AVERROR(EINVAL);
+ if (o) {
+ if (o->type == AV_OPT_TYPE_CONST || o->offset == offset)
+ continue;
+ offset = o->offset;
+ shorthand = o->name;
}
- if (o->type == AV_OPT_TYPE_CONST)
- continue;
- val = av_get_token(&p, ":");
- if (!val)
- return AVERROR(ENOMEM);
+ ret = av_opt_get_key_value(&args, "=", ":",
+ shorthand ? AV_OPT_FLAG_IMPLICIT_KEY : 0,
+ &parsed_key, &value);
+ if (ret < 0) {
+ if (ret == AVERROR(EINVAL))
+ av_log(ctx, AV_LOG_ERROR, "No option name near '%s'\n", args);
+ else
+ av_log(ctx, AV_LOG_ERROR, "Unable to parse '%s': %s\n", args,
+ av_err2str(ret));
+ return ret;
+ }
+ if (*args)
+ args++;
+ if (parsed_key) {
+ key = parsed_key;
+ while ((o = av_opt_next(ctx->priv, o))); /* discard all remaining shorthand */
+ } else {
+ key = shorthand;
+ }
- av_dict_set(options, o->name, val, 0);
+ av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value);
- av_freep(&val);
- if (*p)
- p++;
+ 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_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
@@ -585,7 +845,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);
@@ -607,51 +869,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);
@@ -673,22 +904,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;
}
@@ -725,14 +992,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;
+ 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;
@@ -741,6 +1014,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);
@@ -758,7 +1032,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:
@@ -774,7 +1048,104 @@ 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_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;
+}
+
+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)
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 9f14afd..3518ad8 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,6 +191,8 @@ 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;
/**
@@ -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);
@@ -407,6 +434,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
@@ -544,6 +593,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;
/**
@@ -555,7 +625,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
@@ -601,6 +671,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
};
/**
@@ -623,7 +700,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
@@ -646,9 +723,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;
@@ -677,6 +756,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 attemps 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;
};
/**
@@ -692,6 +869,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
@@ -713,13 +905,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
@@ -734,8 +929,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);
@@ -752,7 +979,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);
@@ -935,7 +1162,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
@@ -994,6 +1221,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;
/**
@@ -1059,11 +1300,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);
@@ -1109,10 +1365,20 @@ 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.
*
- * @param graph the filter graph where to link the parsed graph context
+ * @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 grap context
* @param filters string to be parsed
* @param inputs linked list to the inputs of the graph
* @param outputs linked list to the outputs of the graph
@@ -1121,6 +1387,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.
@@ -1135,21 +1438,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,
@@ -1157,6 +1452,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 alphanummeric 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..506d79e 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,12 @@
#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 "libavcodec/avcodec.h" // avcodec_find_best_pix_fmt_of_2()
#include "avfilter.h"
#include "formats.h"
@@ -38,13 +39,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 +58,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 +115,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 +138,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 +171,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 +209,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 +224,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 +232,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 +262,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)
{
@@ -275,17 +292,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 +468,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 +536,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 +545,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,11 +560,11 @@ 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);
+ filter_query_formats(convert);
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))
+ 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,
@@ -392,14 +589,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= avcodec_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 +650,18 @@ 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);
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 +695,7 @@ do { \
\
if (!out_link->in_ ## list->nb) { \
add_format(&out_link->in_ ##list, fmt); \
+ ret = 1; \
break; \
} \
\
@@ -476,8 +718,42 @@ 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) {
+ /* 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 +881,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 +1020,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 +1077,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 +1099,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 +1191,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/bbox.c b/libavfilter/bbox.c
new file mode 100644
index 0000000..be9b2e6
--- a/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
--- a/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 88b5f22..1bbfab8 100644
--- a/libavfilter/buffer.c
+++ b/libavfilter/buffer.c
@@ -1,31 +1,38 @@
/*
- * 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 "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)
@@ -34,19 +41,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));
@@ -56,7 +76,7 @@ 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) *
nb_channels))) {
@@ -78,12 +98,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);
}
@@ -96,13 +120,17 @@ void avfilter_unref_bufferp(AVFilterBufferRef **ref)
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;
@@ -119,50 +147,6 @@ 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)
{
// copy common properties
@@ -170,9 +154,17 @@ void avfilter_copy_buffer_ref_props(AVFilterBufferRef *dst, AVFilterBufferRef *s
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..adbc0fd
--- a/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 32
+#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 2a22948..a6b24ad 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,120 @@
#include "internal.h"
typedef struct {
- 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_free(sink->fifo);
+ sink->fifo = NULL;
+ }
}
-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 +167,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 +182,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 +195,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(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 +275,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 +289,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 +315,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 +330,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 +577,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 +591,6 @@ static const AVFilterPad avfilter_asink_abuffer_inputs[] = {
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.filter_frame = filter_frame,
- .needs_fifo = 1
},
{ NULL }
};
@@ -244,9 +598,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 75cea35..ce96d08 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
*/
@@ -21,13 +21,33 @@
/**
* @file
- * memory buffer sink API
+ * memory buffer sink API for audio and video
*/
#include "avfilter.h"
#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.
@@ -66,6 +86,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 1a75990..6b6210d 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,27 @@
#include "formats.h"
#include "internal.h"
#include "video.h"
+#include "avcodec.h"
typedef struct {
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,58 +68,89 @@ typedef struct {
#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 ret;
+ s->nb_failed_requests = 0;
+
if (!frame) {
s->eof = 1;
return 0;
} else if (s->eof)
return AVERROR(EINVAL);
+ 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)
@@ -130,6 +166,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;
}
@@ -138,16 +178,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;
@@ -164,14 +209,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 { \
@@ -181,7 +229,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); \
@@ -229,7 +277,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);
@@ -238,41 +286,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 || c->pix_fmt >= AV_PIX_FMT_NB) {
- 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, .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 */
@@ -282,31 +336,25 @@ 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 },
{ "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)
{
@@ -315,17 +363,36 @@ static av_cold int init_audio(AVFilterContext *ctx)
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",
+ av_log(ctx, AV_LOG_ERROR, "Invalid sample format %s\n",
s->sample_fmt_str);
return AVERROR(EINVAL);
}
+ if (s->channel_layout_str) {
+ int n;
+ /* TODO reindent */
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);
+ }
if (!(s->fifo = av_fifo_alloc(sizeof(AVFrame*))))
return AVERROR(ENOMEM);
@@ -333,9 +400,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, s->sample_fmt_str,
s->sample_rate, s->channel_layout_str);
+ s->warning_limit = 100;
return ret;
}
@@ -371,7 +440,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:
@@ -392,14 +463,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;
}
@@ -407,18 +479,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)
@@ -445,7 +515,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,
@@ -453,6 +522,7 @@ AVFilter ff_vsrc_buffer = {
.inputs = NULL,
.outputs = avfilter_vsrc_buffer_outputs,
+ .priv_class = &buffer_class,
};
static const AVFilterPad avfilter_asrc_abuffer_outputs[] = {
@@ -470,7 +540,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,
@@ -478,4 +547,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 c6f7ff9..89613e1 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
*/
@@ -25,8 +25,58 @@
* Memory buffer source API.
*/
+#include "libavcodec/avcodec.h"
#include "avfilter.h"
+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 the filtergraph s.
@@ -50,6 +100,9 @@ int av_buffersrc_buffer(AVFilterContext *s, 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 *s, const AVFrame *frame);
@@ -67,7 +120,29 @@ int av_buffersrc_write_frame(AVFilterContext *s, 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 controled
+ * 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);
+
+
#endif /* AVFILTER_BUFFERSRC_H */
diff --git a/libavfilter/deshake.h b/libavfilter/deshake.h
new file mode 100644
index 0000000..c24090e
--- a/dev/null
+++ b/libavfilter/deshake.h
@@ -0,0 +1,104 @@
+/*
+ * 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_H
+#define AVFILTER_DESHAKE_H
+
+#include "config.h"
+#include "avfilter.h"
+#include "libavcodec/dsputil.h"
+#include "transform.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 vector; ///< Motion vector
+ double angle; ///< Angle of rotation
+ double zoom; ///< Zoom percentage
+} Transform;
+
+#if CONFIG_OPENCL
+
+typedef struct {
+ size_t matrix_size;
+ float matrix_y[9];
+ float matrix_uv[9];
+ cl_mem cl_matrix_y;
+ cl_mem cl_matrix_uv;
+ 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;
+ AVOpenCLKernelEnv kernel_env;
+} DeshakeOpenclContext;
+
+#endif
+
+typedef struct {
+ const AVClass *class;
+ 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
+ AVCodecContext *avctx;
+ DSPContext c; ///< Context providing optimized SAD methods
+ 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..eea873e
--- a/dev/null
+++ b/libavfilter/deshake_opencl.c
@@ -0,0 +1,176 @@
+/*
+ * 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
+ */
+
+/**
+ * @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 MATRIX_SIZE 6
+#define PLANE_NUM 3
+
+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;
+ const size_t global_work_size = width * height + 2 * ch * cw;
+ cl_int status;
+ DeshakeContext *deshake = ctx->priv;
+ FFOpenclParam opencl_param = {0};
+
+ opencl_param.ctx = ctx;
+ opencl_param.kernel = deshake->opencl_ctx.kernel_env.kernel;
+ ret = av_opencl_buffer_write(deshake->opencl_ctx.cl_matrix_y, (uint8_t *)matrix_y, deshake->opencl_ctx.matrix_size * sizeof(cl_float));
+ if (ret < 0)
+ return ret;
+ ret = av_opencl_buffer_write(deshake->opencl_ctx.cl_matrix_uv, (uint8_t *)matrix_uv, deshake->opencl_ctx.matrix_size * sizeof(cl_float));
+ if (ret < 0)
+ return ret;
+
+ if ((unsigned int)interpolate > INTERPOLATE_BIQUADRATIC) {
+ av_log(ctx, AV_LOG_ERROR, "Selected interpolate method is invalid\n");
+ return AVERROR(EINVAL);
+ }
+ ret = ff_opencl_set_parameter(&opencl_param,
+ FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_inbuf),
+ FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_outbuf),
+ FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_matrix_y),
+ FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_matrix_uv),
+ 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.kernel_env.command_queue,
+ deshake->opencl_ctx.kernel_env.kernel, 1, NULL,
+ &global_work_size, 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(deshake->opencl_ctx.kernel_env.command_queue);
+ 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.matrix_size = MATRIX_SIZE;
+ deshake->opencl_ctx.plane_num = PLANE_NUM;
+ ret = av_opencl_buffer_create(&deshake->opencl_ctx.cl_matrix_y,
+ deshake->opencl_ctx.matrix_size*sizeof(cl_float), CL_MEM_READ_ONLY, NULL);
+ if (ret < 0)
+ return ret;
+ ret = av_opencl_buffer_create(&deshake->opencl_ctx.cl_matrix_uv,
+ deshake->opencl_ctx.matrix_size*sizeof(cl_float), CL_MEM_READ_ONLY, NULL);
+ if (ret < 0)
+ return ret;
+ if (!deshake->opencl_ctx.kernel_env.kernel) {
+ ret = av_opencl_create_kernel(&deshake->opencl_ctx.kernel_env, "avfilter_transform");
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel for name 'avfilter_transform'\n");
+ return ret;
+ }
+ }
+ 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);
+ av_opencl_buffer_release(&deshake->opencl_ctx.cl_matrix_y);
+ av_opencl_buffer_release(&deshake->opencl_ctx.cl_matrix_uv);
+ av_opencl_release_kernel(&deshake->opencl_ctx.kernel_env);
+ 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..30d17d4
--- a/dev/null
+++ b/libavfilter/deshake_opencl.h
@@ -0,0 +1,38 @@
+/*
+ * 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"
+
+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..ca0bf83
--- a/dev/null
+++ b/libavfilter/deshake_opencl_kernel.h
@@ -0,0 +1,217 @@
+/*
+ * 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_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, float x, float y,
+ int w, int h,int stride, unsigned char def)
+{
+ return (x < 0 || y < 0 || x >= w || y >= h) ? def : src[(int)x + (int)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.5), (int)(y + 0.5), 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;
+
+ 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)));
+ }
+}
+
+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;
+
+ 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);
+ }
+}
+
+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(global unsigned char *src,
+ global unsigned char *dst,
+ global float *matrix,
+ global float *matrix2,
+ int interpolate,
+ int fillmethod,
+ 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 global_id = get_global_id(0);
+
+ 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 *tempdst;
+ global unsigned char *tempsrc;
+
+ int x;
+ int y;
+ float x_s;
+ float y_s;
+ int tempsrc_stride;
+ int tempdst_stride;
+ int temp_height;
+ int temp_width;
+ int curpos;
+ unsigned char def = 0;
+ if (global_id < width*height) {
+ y = global_id/width;
+ x = global_id%width;
+ x_s = x * matrix[0] + y * matrix[1] + matrix[2];
+ y_s = x * matrix[3] + y * matrix[4] + matrix[5];
+ tempdst = dst_y;
+ tempsrc = src_y;
+ tempsrc_stride = src_stride_lu;
+ tempdst_stride = dst_stride_lu;
+ temp_height = height;
+ temp_width = width;
+ } else if ((global_id >= width*height)&&(global_id < width*height + ch*cw)) {
+ y = (global_id - width*height)/cw;
+ x = (global_id - width*height)%cw;
+ x_s = x * matrix2[0] + y * matrix2[1] + matrix2[2];
+ y_s = x * matrix2[3] + y * matrix2[4] + matrix2[5];
+ tempdst = dst_u;
+ tempsrc = src_u;
+ tempsrc_stride = src_stride_ch;
+ tempdst_stride = dst_stride_ch;
+ temp_height = ch;
+ temp_width = cw;
+ } else {
+ y = (global_id - width*height - ch*cw)/cw;
+ x = (global_id - width*height - ch*cw)%cw;
+ x_s = x * matrix2[0] + y * matrix2[1] + matrix2[2];
+ y_s = x * matrix2[3] + y * matrix2[4] + matrix2[5];
+ tempdst = dst_v;
+ tempsrc = src_v;
+ tempsrc_stride = src_stride_ch;
+ tempdst_stride = dst_stride_ch;
+ temp_height = ch;
+ temp_width = cw;
+ }
+ curpos = y * tempdst_stride + x;
+ switch (fillmethod) {
+ case 0: //FILL_BLANK
+ def = 0;
+ break;
+ case 1: //FILL_ORIGINAL
+ def = tempsrc[y*tempsrc_stride+x];
+ break;
+ case 2: //FILL_CLAMP
+ y_s = clipf(y_s, 0, temp_height - 1);
+ x_s = clipf(x_s, 0, temp_width - 1);
+ def = tempsrc[(int)y_s * tempsrc_stride + (int)x_s];
+ break;
+ case 3: //FILL_MIRROR
+ y_s = mirror(y_s,temp_height - 1);
+ x_s = mirror(x_s,temp_width - 1);
+ def = tempsrc[(int)y_s * tempsrc_stride + (int)x_s];
+ break;
+ }
+ switch (interpolate) {
+ case 0: //INTERPOLATE_NEAREST
+ tempdst[curpos] = interpolate_nearest(x_s, y_s, tempsrc, temp_width, temp_height, tempsrc_stride, def);
+ break;
+ case 1: //INTERPOLATE_BILINEAR
+ tempdst[curpos] = interpolate_bilinear(x_s, y_s, tempsrc, temp_width, temp_height, tempsrc_stride, def);
+ break;
+ case 2: //INTERPOLATE_BIQUADRATIC
+ tempdst[curpos] = interpolate_biquadratic(x_s, y_s, tempsrc, temp_width, temp_height, tempsrc_stride, def);
+ break;
+ default:
+ return;
+ }
+}
+);
+
+#endif /* AVFILTER_DESHAKE_OPENCL_KERNEL_H */
diff --git a/libavfilter/drawutils.c b/libavfilter/drawutils.c
index e837760..a5064f8 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,436 @@ 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, pix_fmts[AV_PIX_FMT_NB + 1];
+ unsigned n = 0;
+ FFDrawContext draw;
+
+ for (i = 0; i < AV_PIX_FMT_NB; i++)
+ if (ff_draw_init(&draw, i, flags) >= 0)
+ pix_fmts[n++] = i;
+ pix_fmts[n++] = AV_PIX_FMT_NONE;
+ return ff_make_format_list(pix_fmts);
+}
+
+#ifdef TEST
+
+#undef printf
+
+int main(void)
+{
+ enum AVPixelFormat f;
+ const AVPixFmtDescriptor *desc;
+ FFDrawContext draw;
+ FFDrawColor color;
+ int r, i;
+
+ for (f = 0; f < AV_PIX_FMT_NB; 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..97e15cb
--- a/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[1].after = EXT_STOP;
+ if (!s->repeatlast) {
+ in[0].after = EXT_STOP;
+ 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
--- a/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..a2c6160
--- a/dev/null
+++ b/libavfilter/f_ebur128.c
@@ -0,0 +1,799 @@
+/*
+ * 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 True Peak
+ * @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 "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
+
+ /* 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;
+
+#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 },
+ { 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 */
+ if (ebur128->metadata)
+ 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;
+ int idx_bitposn = 0;
+ 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++) {
+
+ /* find the next bit that is set starting from the right */
+ while ((outlink->channel_layout & 1ULL<<idx_bitposn) == 0 && idx_bitposn < 63)
+ idx_bitposn++;
+
+ /* channel weighting */
+ if ((1ULL<<idx_bitposn & AV_CH_LOW_FREQUENCY) ||
+ (1ULL<<idx_bitposn & AV_CH_LOW_FREQUENCY_2)) {
+ ebur128->ch_weighting[i] = 0;
+ } else if (1ULL<<idx_bitposn & BACK_MASK) {
+ ebur128->ch_weighting[i] = 1.41;
+ } else {
+ ebur128->ch_weighting[i] = 1.0;
+ }
+
+ idx_bitposn++;
+
+ 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;
+
+ return 0;
+}
+
+#define ENERGY(loudness) (pow(10, ((loudness) + 0.691) / 10.))
+#define LOUDNESS(energy) (-0.691 + 10 * 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 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;
+
+ 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;
+
+ 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 SET_META(name, var) do { \
+ snprintf(metabuf, sizeof(metabuf), "%.3f", var); \
+ av_dict_set(&insamples->metadata, "lavfi.r128." name, metabuf, 0); \
+} while (0)
+ SET_META("M", loudness_400);
+ SET_META("S", loudness_3000);
+ SET_META("I", ebur128->integrated_loudness);
+ SET_META("LRA", ebur128->loudness_range);
+ SET_META("LRA.low", ebur128->lra_low);
+ SET_META("LRA.high", ebur128->lra_high);
+ }
+
+ av_log(ctx, ebur128->loglevel, "t: %-10s " LOG_FMT "\n",
+ av_ts2timestr(pts, &outlink->time_base),
+ loudness_400, loudness_3000,
+ ebur128->integrated_loudness, ebur128->loudness_range);
+ }
+ }
+
+ 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\n",
+ ebur128->integrated_loudness, ebur128->i400.rel_threshold,
+ ebur128->loudness_range, ebur128->i3000.rel_threshold,
+ ebur128->lra_low, ebur128->lra_high);
+
+ av_freep(&ebur128->y_line_ref);
+ av_freep(&ebur128->ch_weighting);
+ 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);
+}
+
+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
--- a/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..2c53e8c
--- a/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 *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..ec84da8
--- a/dev/null
+++ b/libavfilter/f_select.c
@@ -0,0 +1,533 @@
+/*
+ * 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 "avfilter.h"
+#include "audio.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+#if CONFIG_AVCODEC
+#include "libavcodec/dsputil.h"
+#endif
+
+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", ///< 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",
+ "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 {
+ 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
+#if CONFIG_AVCODEC
+ AVCodecContext *avctx; ///< codec context required for the DSPContext (scene detect only)
+ DSPContext c; ///< context providing optimized SAD methods (scene detect only)
+ double prev_mafd; ///< previous MAFD (scene detect only)
+#endif
+ 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 CONFIG_AVCODEC
+ if (select->do_scene_detect) {
+ select->avctx = avcodec_alloc_context3(NULL);
+ if (!select->avctx)
+ return AVERROR(ENOMEM);
+ avpriv_dsputil_init(&select->c, select->avctx);
+ }
+#endif
+ return 0;
+}
+
+#if CONFIG_AVCODEC
+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 &&
+ frame->linesize[0] == prev_picref->linesize[0]) {
+ 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 linesize = frame->linesize[0];
+
+ for (y = 0; y < frame->height - 8; y += 8) {
+ for (x = 0; x < frame->width*3 - 8; x += 8) {
+ sad += select->c.sad[1](select, p1 + x, p2 + x,
+ linesize, 8);
+ nb_sad += 8 * 8;
+ }
+ p1 += 8 * linesize;
+ p2 += 8 * linesize;
+ }
+ emms_c();
+ mafd = nb_sad ? 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;
+}
+#endif
+
+#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);
+
+ 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 CONFIG_AVCODEC
+ 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);
+ }
+#endif
+ 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],
+ (int)select->var_values[VAR_KEY]);
+
+ switch (inlink->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ av_log(inlink->dst, AV_LOG_DEBUG, " interlace_type:%c pict_type:%c scene:%f",
+ select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_P ? 'P' :
+ select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_T ? 'T' :
+ select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_B ? 'B' : '?',
+ av_get_picture_type_char(select->var_values[VAR_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:%d",
+ (int)select->var_values[VAR_SAMPLES_N],
+ (int)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 CONFIG_AVCODEC
+ if (select->do_scene_detect) {
+ av_frame_free(&select->prev_picref);
+ if (select->avctx) {
+ avcodec_close(select->avctx);
+ av_freep(&select->avctx);
+ }
+ }
+#endif
+}
+
+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)
+{
+ SelectContext *select = ctx->priv;
+ int ret;
+
+ if ((ret = init(ctx)) < 0)
+ return ret;
+
+ if (select->do_scene_detect && !CONFIG_AVCODEC) {
+ av_log(ctx, AV_LOG_ERROR, "Scene detection is not available without libavcodec.\n");
+ return AVERROR(EINVAL);
+ }
+
+ 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
--- a/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_settb.c b/libavfilter/f_settb.c
new file mode 100644
index 0000000..d511c14
--- a/dev/null
+++ b/libavfilter/f_settb.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 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
+ * Set timebase for the output link.
+ */
+
+#include <inttypes.h>
+#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/rational.h"
+#include "avfilter.h"
+#include "internal.h"
+#include "audio.h"
+#include "video.h"
+
+static const char *const var_names[] = {
+ "AVTB", /* default timebase 1/AV_TIME_BASE */
+ "intb", /* input timebase */
+ "sr", /* sample rate */
+ NULL
+};
+
+enum var_name {
+ VAR_AVTB,
+ VAR_INTB,
+ VAR_SR,
+ VAR_VARS_NB
+};
+
+typedef struct {
+ const AVClass *class;
+ char *tb_expr;
+ 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;
+ SetTBContext *settb = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVRational time_base;
+ int ret;
+ double res;
+
+ 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;
+
+ outlink->w = inlink->w;
+ outlink->h = inlink->h;
+
+ if ((ret = av_expr_parse_and_eval(&res, settb->tb_expr, var_names, settb->var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, NULL)) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid expression '%s' for timebase.\n", settb->tb_expr);
+ return ret;
+ }
+ time_base = av_d2q(res, INT_MAX);
+ if (time_base.num <= 0 || time_base.den <= 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Invalid non-positive values for the timebase num:%d or den:%d.\n",
+ time_base.num, time_base.den);
+ return AVERROR(EINVAL);
+ }
+
+ outlink->time_base = time_base;
+ av_log(outlink->src, AV_LOG_VERBOSE, "tb:%d/%d -> tb:%d/%d\n",
+ inlink ->time_base.num, inlink ->time_base.den,
+ outlink->time_base.num, outlink->time_base.den);
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+
+ if (av_cmp_q(inlink->time_base, outlink->time_base)) {
+ int64_t orig_pts = frame->pts;
+ frame->pts = av_rescale_q(frame->pts, inlink->time_base, outlink->time_base);
+ av_log(ctx, AV_LOG_DEBUG, "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n",
+ inlink ->time_base.num, inlink ->time_base.den, orig_pts,
+ outlink->time_base.num, outlink->time_base.den, frame->pts);
+ }
+
+ return ff_filter_frame(outlink, frame);
+}
+
+#if CONFIG_SETTB_FILTER
+
+DEFINE_OPTIONS(settb, VIDEO);
+AVFILTER_DEFINE_CLASS(settb);
+
+static const AVFilterPad avfilter_vf_settb_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad avfilter_vf_settb_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_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,
+};
+#endif
+
+#if CONFIG_ASETTB_FILTER
+
+DEFINE_OPTIONS(asettb, AUDIO);
+AVFILTER_DEFINE_CLASS(asettb);
+
+static const AVFilterPad avfilter_af_asettb_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad avfilter_af_asettb_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_asettb = {
+ .name = "asettb",
+ .description = NULL_IF_CONFIG_SMALL("Set timebase for the audio output link."),
+ .priv_size = sizeof(SetTBContext),
+ .inputs = avfilter_af_asettb_inputs,
+ .outputs = avfilter_af_asettb_outputs,
+ .priv_class = &asettb_class,
+};
+#endif
diff --git a/libavfilter/f_zmq.c b/libavfilter/f_zmq.c
new file mode 100644
index 0000000..d6c3c65
--- a/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 30e0b38..5310af2 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 69288af..e6c9b03 100644
--- a/libavfilter/filtfmts.c
+++ b/libavfilter/filtfmts.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
*/
@@ -22,9 +22,49 @@
#include "libavformat/avformat.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, filter_ctx->filter->inout##puts[i].name, \
+ 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, filter_ctx->filter->inout##puts[i].name, \
+ 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, filter_ctx->filter->inout##puts[i].name, buf); \
+ } \
+ } \
+ } \
+
+ PRINT_FMTS(in, out, IN);
+ PRINT_FMTS(out, in, OUT);
+}
+
int main(int argc, char **argv)
{
AVFilter *filter;
@@ -32,17 +72,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 */
@@ -71,12 +111,12 @@ int main(int argc, char **argv)
}
/* create a link for each of the input pads */
- for (i = 0; i < filter_ctx->input_count; i++) {
+ for (i = 0; i < filter_ctx->nb_inputs; i++) {
AVFilterLink *link = av_mallocz(sizeof(AVFilterLink));
link->type = filter_ctx->filter->inputs[i].type;
filter_ctx->inputs[i] = link;
}
- for (i = 0; i < filter_ctx->output_count; i++) {
+ for (i = 0; i < filter_ctx->nb_outputs; i++) {
AVFilterLink *link = av_mallocz(sizeof(AVFilterLink));
link->type = filter_ctx->filter->outputs[i].type;
filter_ctx->outputs[i] = link;
@@ -87,23 +127,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->input_count; i++) {
- AVFilterFormats *fmts = filter_ctx->inputs[i]->out_formats;
- for (j = 0; j < fmts->nb_formats; j++)
- printf("INPUT[%d] %s: %s\n",
- i, filter_ctx->filter->inputs[i].name,
- av_get_pix_fmt_name(fmts->formats[j]));
- }
-
- /* print the supported formats in output */
- for (i = 0; i < filter_ctx->output_count; i++) {
- AVFilterFormats *fmts = filter_ctx->outputs[i]->in_formats;
- for (j = 0; j < fmts->nb_formats; j++)
- printf("OUTPUT[%d] %s: %s\n",
- i, filter_ctx->filter->outputs[i].name,
- 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 1441161..d51bf3c 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.
*/
@@ -64,11 +70,17 @@ do {
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(sizeof(*ret->channel_layouts) *
+ ret_max)))
+ 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(sizeof(*formats->field)*count); \
+ 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)
@@ -223,6 +357,16 @@ 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;
@@ -244,6 +388,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;
}
@@ -334,13 +490,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++; \
} \
@@ -378,7 +534,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 :
@@ -386,9 +543,109 @@ 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 || (unsigned)pix_fmt >= AV_PIX_FMT_NB) {
+ 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 || (unsigned)sfmt >= AV_SAMPLE_FMT_NB) {
+ 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, const char *arg, void *log_ctx)
+{
+ char *tail;
+ int64_t 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;
+ 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
--- a/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
--- a/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/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..1b59321
--- a/dev/null
+++ b/libavfilter/graphdump.c
@@ -0,0 +1,164 @@
+/*
+ * 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];
+
+ if (!buf)
+ buf = &(AVBPrint){ 0 }; /* 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 00764b6..93033dc 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;
}
@@ -130,10 +132,10 @@ static int create_filter(AVFilterContext **filt_ctx, AVFilterGraph *ctx, int ind
if (args)
av_log(log_ctx, AV_LOG_ERROR, " with args '%s'", args);
av_log(log_ctx, AV_LOG_ERROR, "\n");
- return ret;
}
- return 0;
+ av_free(tmp_args);
+ return ret;
}
/**
@@ -150,7 +152,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)
@@ -383,7 +385,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;
@@ -398,18 +400,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++;
@@ -424,16 +425,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);
@@ -447,6 +449,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)
@@ -508,4 +511,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 44e7583..f8d0cce 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.
*/
@@ -137,9 +161,79 @@ 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 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, 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.
@@ -153,35 +247,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;
}
/**
@@ -201,6 +298,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.
*
@@ -215,6 +335,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..b7a103b
--- a/dev/null
+++ b/libavfilter/lavfutils.c
@@ -0,0 +1,98 @@
+/*
+ * 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;
+ }
+
+ 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 = avcodec_alloc_frame()) ) {
+ 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");
+ goto end;
+ }
+ ret = 0;
+
+ *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
--- a/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/libavfilter.v b/libavfilter/libavfilter.v
index 83e8887..a3d33a3 100644
--- a/libavfilter/libavfilter.v
+++ b/libavfilter/libavfilter.v
@@ -1,4 +1,5 @@
LIBAVFILTER_$MAJOR {
global: avfilter_*; av_*;
+ ff_default_query_formats;
local: *;
};
diff --git a/libavfilter/libmpcodecs/av_helpers.h b/libavfilter/libmpcodecs/av_helpers.h
new file mode 100644
index 0000000..90b67d5
--- a/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
--- a/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..61bf898
--- a/dev/null
+++ b/libavfilter/libmpcodecs/img_format.c
@@ -0,0 +1,233 @@
+/*
+ * 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_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_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;
+ 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..d4d64d8
--- a/dev/null
+++ b/libavfilter/libmpcodecs/img_format.h
@@ -0,0 +1,300 @@
+/*
+ * 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_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_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_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_RGB_DEPTH(fmt) ((fmt)&0x7F)
+#define IMGFMT_BGR_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
--- a/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..2a3a0fa
--- a/dev/null
+++ b/libavfilter/libmpcodecs/libvo/video_out.h
@@ -0,0 +1,281 @@
+/*
+ * 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 VO_EVENT_EXPOSE 1
+#define VO_EVENT_RESIZE 2
+#define VO_EVENT_KEYPRESS 4
+#define VO_EVENT_REINIT 8
+#define VO_EVENT_MOVE 16
+
+/* 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
+#define VOCTRL_GUI_NOWINDOW 19
+/* 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
+//#define VOCTRL_GUI_NOWINDOW 19
+/* 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_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 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);
+
+#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..100ace9
--- a/dev/null
+++ b/libavfilter/libmpcodecs/mp_image.c
@@ -0,0 +1,253 @@
+/*
+ * 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;
+ }
+ 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){
+ /* becouse we allocate the whole image in 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
--- a/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
--- a/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
--- a/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..0d26296
--- a/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 thru */
+#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..c926c51
--- a/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
+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
+ 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..7a3ef31
--- a/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
+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 != NULL) {
+ 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
+ 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 != NULL) {
+ 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 != NULL) {
+ 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..a8a33e2
--- a/dev/null
+++ b/libavfilter/libmpcodecs/vf_fspp.c
@@ -0,0 +1,2118 @@
+/*
+ * 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)
+ * Futher, 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"
+#include "libavcodec/dsputil.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
+};
+
+static const uint8_t __attribute__((aligned(32))) 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;
+ int32_t __attribute__((aligned(32))) 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)
+{
+ uint64_t __attribute__((aligned(8))) 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)
+ : "%"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)
+{
+ uint64_t __attribute__((aligned(8))) 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))
+ : "%"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)
+{
+ uint64_t __attribute__((aligned(8))) 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, 0*8+%3 \n\t" //t7
+ "punpcklbw %%mm7, %%mm3 \n\t"
+
+ "movq %%mm6, 1*8+%3 \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 1*8+%3, %%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 0*8+%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)
+ : "a"(line_size)
+ : "%"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..4db6c0a
--- a/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)
+ ".Lli0: \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 .Lli0 \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)
+ ".Lli1: \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 .Lli1 \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..30f9530
--- a/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))
+
+//===========================================================================//
+static const uint8_t __attribute__((aligned(8))) 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
--- a/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..54cc0f9
--- a/dev/null
+++ b/libavfilter/libmpcodecs/vf_uspp.c
@@ -0,0 +1,393 @@
+/*
+ * 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
+
+//===========================================================================//
+static const uint8_t __attribute__((aligned(8))) 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);
+ avcodec_open2(avctx_enc, enc, &opts);
+ av_dict_free(&opts);
+ assert(avctx_enc->codec);
+ }
+ vf->priv->frame= avcodec_alloc_frame();
+ vf->priv->frame_dec= avcodec_alloc_frame();
+
+ 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
--- a/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/lswsutils.c b/libavfilter/lswsutils.c
new file mode 100644
index 0000000..ebb4f93
--- a/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
--- a/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
--- a/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
--- a/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..92c4d08 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;
diff --git a/libavfilter/setpts.c b/libavfilter/setpts.c
index be190c0..cb6b2b9 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
*/
@@ -29,24 +29,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
@@ -56,15 +59,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,
@@ -78,6 +87,7 @@ typedef struct {
char *expr_str;
AVExpr *expr;
double var_values[VAR_VARS_NB];
+ enum AVMediaType type;
} SetPTSContext;
static av_cold int init(AVFilterContext *ctx)
@@ -91,34 +101,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)
{
@@ -126,30 +156,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);
-#ifdef DEBUG
av_log(inlink->dst, AV_LOG_DEBUG,
- "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));
-#endif
-
+ d2istr(setpts->var_values[VAR_PTS]),
+ setpts->var_values[VAR_T],
+ d2istr(setpts->var_values[VAR_POS]));
+ switch (inlink->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ av_log(inlink->dst, AV_LOG_DEBUG, " INTERLACED:%"PRId64,
+ (int64_t)setpts->var_values[VAR_INTERLACED]);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ av_log(inlink->dst, AV_LOG_DEBUG, " NB_SAMPLES:%"PRId64" NB_CONSUMED_SAMPLES:%"PRId64,
+ (int64_t)setpts->var_values[VAR_NB_SAMPLES],
+ (int64_t)setpts->var_values[VAR_NB_CONSUMED_SAMPLES]);
+ break;
+ }
+ av_log(inlink->dst, AV_LOG_DEBUG, " -> 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;
@@ -158,7 +201,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);
}
@@ -170,27 +218,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 }
};
@@ -215,23 +258,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 }
};
@@ -249,11 +288,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/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..5bec10f
--- a/dev/null
+++ b/libavfilter/src_movie.c
@@ -0,0 +1,603 @@
+/*
+ * 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 "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 {
+ AVStream *st;
+ int done;
+} MovieStream;
+
+typedef struct {
+ /* 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;
+ AVFrame *frame; ///< video frame to store the decoded images in
+
+ 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, 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, nb_streams = 1; *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++)
+ movie->out_index[movie->st[i].st->index] = i;
+
+ for (i = 0; i < nb_streams; i++) {
+ AVFilterPad pad = { 0 };
+ 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);
+ av_frame_free(&movie->frame);
+ 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,
+ 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;
+}
+
+#define describe_frameref(f, link) \
+ describe_frame_to_str((char[1024]){0}, 1024, f, link)
+
+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;
+ MovieStream *st;
+ int ret, got_frame = 0, pkt_out_id;
+ AVFilterLink *outlink;
+
+ 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];
+
+ movie->frame = av_frame_alloc();
+ if (!movie->frame)
+ return AVERROR(ENOMEM);
+
+ switch (st->st->codec->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ ret = avcodec_decode_video2(st->st->codec, movie->frame, &got_frame, pkt);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ ret = avcodec_decode_audio4(st->st->codec, movie->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(&movie->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(&movie->frame);
+ return 0;
+ }
+
+ av_dlog(ctx, "movie_push_frame(): file:'%s' %s\n", movie->file_name,
+ describe_frameref(movie->frame, outlink));
+
+ movie->frame->pts = av_frame_get_best_effort_timestamp(movie->frame);
+ ret = ff_filter_frame(outlink, movie->frame);
+ movie->frame = NULL;
+
+ 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
--- a/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
--- a/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 36a5653..fdc6245 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
*/
@@ -39,9 +39,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
@@ -69,10 +72,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;
@@ -88,52 +90,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
@@ -176,13 +179,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);
@@ -192,23 +194,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[] = {
{
@@ -222,9 +220,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 }
};
@@ -232,12 +230,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,
};
@@ -316,7 +311,7 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame)
}
if (drop) {
- s->eof = 1;
+ s->eof = inlink->closed = 1;
goto drop;
}
}
@@ -324,7 +319,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);
@@ -335,7 +330,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 },
@@ -346,7 +341,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:
@@ -355,23 +349,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[] = {
{
@@ -385,9 +375,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 }
};
@@ -395,12 +385,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..c225929
--- a/dev/null
+++ b/libavfilter/unsharp.h
@@ -0,0 +1,75 @@
+/*
+ * 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_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_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;
+ AVOpenCLKernelEnv kernel_env;
+} 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 {
+ 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..b373b66
--- a/dev/null
+++ b/libavfilter/unsharp_opencl.c
@@ -0,0 +1,283 @@
+/*
+ * 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
+ */
+
+/**
+ * @file
+ * unsharp input video
+ */
+
+#include "unsharp_opencl.h"
+#include "libavutil/common.h"
+#include "libavutil/opencl_internal.h"
+
+#define PLANE_NUM 3
+
+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(sizeof(uint32_t *) * (2 * step + 1));
+ 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(sizeof(uint32_t) * (2 * step_x + 1));
+ if (!mask_x) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ mask_y = av_mallocz(sizeof(uint32_t) * (2 * step_y + 1));
+ 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;
+ 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;
+ int cw = FF_CEIL_RSHIFT(link->w, unsharp->hsub);
+ int ch = FF_CEIL_RSHIFT(link->h, unsharp->vsub);
+ const size_t global_work_size = link->w * link->h + 2 * ch * cw;
+ FFOpenclParam opencl_param = {0};
+
+ opencl_param.ctx = ctx;
+ opencl_param.kernel = unsharp->opencl_ctx.kernel_env.kernel;
+ ret = ff_opencl_set_parameter(&opencl_param,
+ 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.kernel_env.command_queue,
+ unsharp->opencl_ctx.kernel_env.kernel, 1, NULL,
+ &global_work_size, 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.kernel_env.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;
+ 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;
+ if (!unsharp->opencl_ctx.kernel_env.kernel) {
+ ret = av_opencl_create_kernel(&unsharp->opencl_ctx.kernel_env, "unsharp");
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel with name 'unsharp'\n");
+ return ret;
+ }
+ }
+ return ret;
+}
+
+void ff_opencl_unsharp_uninit(AVFilterContext *ctx)
+{
+ UnsharpContext *unsharp = ctx->priv;
+ av_opencl_buffer_release(&unsharp->opencl_ctx.cl_inbuf);
+ av_opencl_buffer_release(&unsharp->opencl_ctx.cl_outbuf);
+ av_opencl_buffer_release(&unsharp->opencl_ctx.cl_luma_mask);
+ av_opencl_buffer_release(&unsharp->opencl_ctx.cl_chroma_mask);
+ av_opencl_release_kernel(&unsharp->opencl_ctx.kernel_env);
+ 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
--- a/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..0cc8e90
--- a/dev/null
+++ b/libavfilter/unsharp_opencl_kernel.h
@@ -0,0 +1,137 @@
+/*
+ * 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_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(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 02f348e..b9159a7 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/avutil.h"
#define LIBAVFILTER_VERSION_MAJOR 3
-#define LIBAVFILTER_VERSION_MINOR 11
-#define LIBAVFILTER_VERSION_MICRO 0
+#define LIBAVFILTER_VERSION_MINOR 90
+#define LIBAVFILTER_VERSION_MICRO 100
#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
@@ -53,12 +55,21 @@
#ifndef FF_API_FOO_COUNT
#define FF_API_FOO_COUNT (LIBAVFILTER_VERSION_MAJOR < 4)
#endif
+#ifndef FF_API_FILL_FRAME
+#define FF_API_FILL_FRAME (LIBAVFILTER_VERSION_MAJOR < 4)
+#endif
+#ifndef FF_API_BUFFERSRC_BUFFER
+#define FF_API_BUFFERSRC_BUFFER (LIBAVFILTER_VERSION_MAJOR < 4)
+#endif
#ifndef FF_API_AVFILTERBUFFER
#define FF_API_AVFILTERBUFFER (LIBAVFILTER_VERSION_MAJOR < 4)
#endif
#ifndef FF_API_OLD_FILTER_OPTS
#define FF_API_OLD_FILTER_OPTS (LIBAVFILTER_VERSION_MAJOR < 4)
#endif
+#ifndef FF_API_ACONVERT_FILTER
+#define FF_API_ACONVERT_FILTER (LIBAVFILTER_VERSION_MAJOR < 4)
+#endif
#ifndef FF_API_AVFILTER_OPEN
#define FF_API_AVFILTER_OPEN (LIBAVFILTER_VERSION_MAJOR < 4)
#endif
@@ -68,6 +79,12 @@
#ifndef FF_API_OLD_FILTER_REGISTER
#define FF_API_OLD_FILTER_REGISTER (LIBAVFILTER_VERSION_MAJOR < 4)
#endif
+#ifndef FF_API_OLD_GRAPH_PARSE
+#define FF_API_OLD_GRAPH_PARSE (LIBAVFILTER_VERSION_MAJOR < 4)
+#endif
+#ifndef FF_API_DRAWTEXT_OLD_TIMELINE
+#define FF_API_DRAWTEXT_OLD_TIMELINE (LIBAVFILTER_VERSION_MAJOR < 4)
+#endif
#ifndef FF_API_NOCONST_GET_NAME
#define FF_API_NOCONST_GET_NAME (LIBAVFILTER_VERSION_MAJOR < 4)
#endif
diff --git a/libavfilter/vf_alphamerge.c b/libavfilter/vf_alphamerge.c
new file mode 100644
index 0000000..5f0da35
--- a/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 51ae27f..f926ea9 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
*/
@@ -26,8 +26,10 @@
#include <float.h>
#include "libavutil/common.h"
+#include "libavutil/eval.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
#include "avfilter.h"
#include "internal.h"
@@ -37,25 +39,43 @@ typedef struct {
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_str;
} 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_str && 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_str, 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_str);
+ return AVERROR(EINVAL);
+ }
+ s->sar = s->dar = av_d2q(num / s->aspect_den, s->max);
+ } else
+#endif
+ if (s->ratio_str) {
+ ret = av_parse_ratio(&s->sar, s->ratio_str, s->max, 0, ctx);
+ if (ret < 0 || s->sar.num < 0 || s->sar.den <= 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Invalid string '%s' for aspect ratio\n", s->ratio_str);
+ return AVERROR(EINVAL);
+ }
+ s->dar = s->sar;
}
-
return 0;
}
-#endif
static int filter_frame(AVFilterLink *link, AVFrame *frame)
{
@@ -66,19 +86,30 @@ 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);
+ }
+}
#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;
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 {
@@ -86,36 +117,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_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags=FLAGS },
+ { "ratio", "set display aspect ratio", OFFSET(ratio_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags=FLAGS },
+ { "r", "set display aspect ratio", OFFSET(ratio_str), 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(dar), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, INT_MAX, 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 }
};
@@ -129,56 +157,55 @@ 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;
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_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags=FLAGS },
+ { "ratio", "set sample (pixel) aspect ratio", OFFSET(ratio_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags=FLAGS },
+ { "r", "set sample (pixel) aspect ratio", OFFSET(ratio_str), 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(sar), AV_OPT_TYPE_RATIONAL, { .dbl = 1 }, 0, INT_MAX, 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 }
};
@@ -192,18 +219,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..6c6aab1
--- a/dev/null
+++ b/libavfilter/vf_bbox.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * bounding box detection filter
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/timestamp.h"
+#include "avfilter.h"
+#include "bbox.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ int min_val;
+} BBoxContext;
+
+#define OFFSET(x) offsetof(BBoxContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption bbox_options[] = {
+ { "min_val", "set minimum luminance value for bounding box", OFFSET(min_val), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 254, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(bbox);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUV440P,
+ AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_NONE,
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+#define SET_META(key, value) \
+ snprintf(buf, sizeof(buf), "%d", value); \
+ av_dict_set(metadata, key, buf, 0);
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ BBoxContext *bbox = ctx->priv;
+ FFBoundingBox box;
+ int has_bbox, w, h;
+ char buf[32];
+
+ 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..90a28a9
--- a/dev/null
+++ b/libavfilter/vf_blackdetect.c
@@ -0,0 +1,204 @@
+/*
+ * 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 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;
+}
+
+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;
+ }
+ } else if (blackdetect->black_started) {
+ /* black ends here */
+ blackdetect->black_started = 0;
+ blackdetect->black_end = picref->pts;
+ check_black_end(ctx);
+ }
+
+ 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 039f055..9b0c973 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 {
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)
@@ -72,11 +72,16 @@ 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",
+ 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);
s->frame++;
s->nblack = 0;
@@ -84,28 +89,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 +120,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..d422a9c
--- a/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 1f26549..3183f43 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 {
int radius;
int power;
+ char *radius_expr;
} FilterParam;
typedef struct {
@@ -65,9 +66,6 @@ typedef struct {
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_colorbalance.c b/libavfilter/vf_colorbalance.c
new file mode 100644
index 0000000..c151c33
--- a/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
--- a/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..e1b48fa
--- a/dev/null
+++ b/libavfilter/vf_colormatrix.c
@@ -0,0 +1,388 @@
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 *color_modes[] = {"bt709", "fcc", "bt601", "smpte240m"};
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ ColorMatrixContext *color = ctx->priv;
+
+ if (color->source == COLOR_MODE_NONE || color->dest == COLOR_MODE_NONE) {
+ av_log(ctx, AV_LOG_ERROR, "Unspecified source or 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);
+ }
+
+ color->mode = color->source * 4 + color->dest;
+
+ calc_coefficients(ctx);
+
+ 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 (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 55175a0..fcc85c5 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
*/
@@ -37,7 +37,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
return AVERROR(ENOMEM);
}
av_frame_copy_props(out, in);
- av_image_copy(out->data, out->linesize, in->data, in->linesize,
+ av_image_copy(out->data, out->linesize, (const uint8_t**) in->data, in->linesize,
in->format, in->width, in->height);
av_frame_free(&in);
@@ -46,10 +46,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 }
};
@@ -63,9 +62,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 1aa8466..261db33 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 {
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; fmt < AV_PIX_FMT_NB; 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 ea9e47d..4a6b658 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,23 @@ static int config_input(AVFilterLink *inlink)
return 0;
}
+#define SET_META(key, value) \
+ snprintf(buf, sizeof(buf), "%d", value); \
+ av_dict_set(metadata, key, buf, 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;
+ char buf[32];
// 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;
@@ -183,6 +189,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 +209,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 +240,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..5123430
--- a/dev/null
+++ b/libavfilter/vf_curves.c
@@ -0,0 +1,552 @@
+/*
+ * 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;
+
+#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) \
+ return AVERROR_INVALIDDATA; \
+ 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_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ int x, y, direct = 0;
+ AVFilterContext *ctx = inlink->dst;
+ CurvesContext *curves = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out;
+ uint8_t *dst;
+ const uint8_t *src;
+ 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];
+
+ 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);
+ }
+
+ dst = out->data[0];
+ src = in ->data[0];
+
+ for (y = 0; y < inlink->h; y++) {
+ for (x = 0; x < inlink->w * 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];
+ }
+
+ if (!direct)
+ 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,
+};
diff --git a/libavfilter/vf_dctdnoiz.c b/libavfilter/vf_dctdnoiz.c
new file mode 100644
index 0000000..71b8536
--- a/dev/null
+++ b/libavfilter/vf_dctdnoiz.c
@@ -0,0 +1,433 @@
+/*
+ * 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
+ */
+
+/**
+ * A simple, relatively efficient and extremely slow DCT image denoiser.
+ * @see http://www.ipol.im/pub/art/2011/ys-dct/
+ */
+
+#include "libavcodec/avfft.h"
+#include "libavutil/eval.h"
+#include "libavutil/opt.h"
+#include "drawutils.h"
+#include "internal.h"
+
+#define NBITS 4
+#define BSIZE (1<<(NBITS))
+
+static const char *const var_names[] = { "c", NULL };
+enum { VAR_C, VAR_VARS_NB };
+
+typedef struct {
+ const AVClass *class;
+
+ /* coefficient factor expression */
+ char *expr_str;
+ AVExpr *expr;
+ double var_values[VAR_VARS_NB];
+
+ int pr_width, pr_height; // width and height to process
+ float sigma; // used when no expression are st
+ float th; // threshold (3*sigma)
+ float color_dct[3][3]; // 3x3 DCT for color decorrelation
+ float *cbuf[2][3]; // two planar rgb color buffers
+ 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 (BSIZE - overlap)
+ DCTContext *dct, *idct; // DCT and inverse DCT contexts
+ float *block, *tmp_block; // two BSIZE x BSIZE block buffers
+} DCTdnoizContext;
+
+#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<<NBITS)-1}, 0, (1<<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 },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(dctdnoiz);
+
+static float *dct_block(DCTdnoizContext *ctx, const float *src, int src_linesize)
+{
+ int x, y;
+ float *column;
+
+ for (y = 0; y < BSIZE; y++) {
+ float *line = ctx->block;
+
+ memcpy(line, src, BSIZE * sizeof(*line));
+ src += src_linesize;
+ av_dct_calc(ctx->dct, line);
+
+ column = ctx->tmp_block + y;
+ column[0] = line[0] * (1. / sqrt(BSIZE));
+ column += BSIZE;
+ for (x = 1; x < BSIZE; x++) {
+ *column = line[x] * sqrt(2. / BSIZE);
+ column += BSIZE;
+ }
+ }
+
+ column = ctx->tmp_block;
+ for (x = 0; x < BSIZE; x++) {
+ av_dct_calc(ctx->dct, column);
+ column[0] *= 1. / sqrt(BSIZE);
+ for (y = 1; y < BSIZE; y++)
+ column[y] *= sqrt(2. / BSIZE);
+ column += BSIZE;
+ }
+
+ for (y = 0; y < BSIZE; y++)
+ for (x = 0; x < BSIZE; x++)
+ ctx->block[y*BSIZE + x] = ctx->tmp_block[x*BSIZE + y];
+
+ return ctx->block;
+}
+
+static void idct_block(DCTdnoizContext *ctx, float *dst, int dst_linesize)
+{
+ int x, y;
+ float *block = ctx->block;
+ float *tmp = ctx->tmp_block;
+
+ for (y = 0; y < BSIZE; y++) {
+ block[0] *= sqrt(BSIZE);
+ for (x = 1; x < BSIZE; x++)
+ block[x] *= 1./sqrt(2. / BSIZE);
+ av_dct_calc(ctx->idct, block);
+ block += BSIZE;
+ }
+
+ block = ctx->block;
+ for (y = 0; y < BSIZE; y++) {
+ tmp[0] = block[y] * sqrt(BSIZE);
+ for (x = 1; x < BSIZE; x++)
+ tmp[x] = block[x*BSIZE + y] * (1./sqrt(2. / BSIZE));
+ av_dct_calc(ctx->idct, tmp);
+ for (x = 0; x < BSIZE; x++)
+ dst[x*dst_linesize + y] += tmp[x];
+ }
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ DCTdnoizContext *s = ctx->priv;
+ int i, x, y, bx, by, linesize, *iweights;
+ const float dct_3x3[3][3] = {
+ { 1./sqrt(3), 1./sqrt(3), 1./sqrt(3) },
+ { 1./sqrt(2), 0, -1./sqrt(2) },
+ { 1./sqrt(6), -2./sqrt(6), 1./sqrt(6) },
+ };
+ uint8_t rgba_map[4];
+
+ ff_fill_rgba_map(rgba_map, inlink->format);
+ for (y = 0; y < 3; y++)
+ for (x = 0; x < 3; x++)
+ s->color_dct[y][x] = dct_3x3[rgba_map[y]][rgba_map[x]];
+
+ 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);
+
+ 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);
+ }
+
+ 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;
+
+ if (s->expr_str) {
+ int ret = av_expr_parse(&s->expr, s->expr_str, var_names,
+ NULL, NULL, NULL, NULL, 0, ctx);
+ if (ret < 0)
+ return ret;
+ }
+
+ s->th = s->sigma * 3.;
+ s->step = BSIZE - s->overlap;
+ s->dct = av_dct_init(NBITS, DCT_II);
+ s->idct = av_dct_init(NBITS, DCT_III);
+ s->block = av_malloc(BSIZE * BSIZE * sizeof(*s->block));
+ s->tmp_block = av_malloc(BSIZE * BSIZE * sizeof(*s->tmp_block));
+
+ if (!s->dct || !s->idct || !s->tmp_block || !s->block)
+ return AVERROR(ENOMEM);
+
+ 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;
+}
+
+static void color_decorrelation(float dct3ch[3][3], float **dst, int dst_linesize,
+ const uint8_t *src, int src_linesize, int w, int h)
+{
+ 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[0] * dct3ch[0][0] + srcp[1] * dct3ch[0][1] + srcp[2] * dct3ch[0][2];
+ dstp_g[x] = srcp[0] * dct3ch[1][0] + srcp[1] * dct3ch[1][1] + srcp[2] * dct3ch[1][2];
+ dstp_b[x] = srcp[0] * dct3ch[2][0] + srcp[1] * dct3ch[2][1] + srcp[2] * dct3ch[2][2];
+ srcp += 3;
+ }
+ src += src_linesize;
+ dstp_r += dst_linesize;
+ dstp_g += dst_linesize;
+ dstp_b += dst_linesize;
+ }
+}
+
+static void color_correlation(float dct3ch[3][3], uint8_t *dst, int dst_linesize,
+ float **src, int src_linesize, int w, int h)
+{
+ 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[0] = av_clip_uint8(src_r[x] * dct3ch[0][0] + src_g[x] * dct3ch[1][0] + src_b[x] * dct3ch[2][0]);
+ dstp[1] = av_clip_uint8(src_r[x] * dct3ch[0][1] + src_g[x] * dct3ch[1][1] + src_b[x] * dct3ch[2][1]);
+ dstp[2] = av_clip_uint8(src_r[x] * dct3ch[0][2] + src_g[x] * dct3ch[1][2] + src_b[x] * dct3ch[2][2]);
+ dstp += 3;
+ }
+ dst += dst_linesize;
+ src_r += src_linesize;
+ src_g += src_linesize;
+ src_b += src_linesize;
+ }
+}
+
+static void filter_plane(AVFilterContext *ctx,
+ float *dst, int dst_linesize,
+ const float *src, int src_linesize,
+ int w, int h)
+{
+ int x, y, bx, by;
+ DCTdnoizContext *s = ctx->priv;
+ float *dst0 = dst;
+ const float *weights = s->weights;
+
+ // reset block sums
+ memset(dst, 0, h * dst_linesize * sizeof(*dst));
+
+ // block dct sums
+ for (y = 0; y < h - BSIZE + 1; y += s->step) {
+ for (x = 0; x < w - BSIZE + 1; x += s->step) {
+ float *ftb = dct_block(s, src + x, src_linesize);
+
+ if (s->expr) {
+ for (by = 0; by < BSIZE; by++) {
+ for (bx = 0; bx < BSIZE; bx++) {
+ s->var_values[VAR_C] = FFABS(*ftb);
+ *ftb++ *= av_expr_eval(s->expr, s->var_values, s);
+ }
+ }
+ } else {
+ for (by = 0; by < BSIZE; by++) {
+ for (bx = 0; bx < BSIZE; bx++) {
+ if (FFABS(*ftb) < s->th)
+ *ftb = 0;
+ ftb++;
+ }
+ }
+ }
+ idct_block(s, dst + x, dst_linesize);
+ }
+ src += s->step * src_linesize;
+ dst += s->step * dst_linesize;
+ }
+
+ // average blocks
+ dst = dst0;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++)
+ dst[x] *= weights[x];
+ dst += dst_linesize;
+ weights += dst_linesize;
+ }
+}
+
+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);
+ }
+
+ color_decorrelation(s->color_dct, s->cbuf[0], s->p_linesize,
+ in->data[0], in->linesize[0], s->pr_width, s->pr_height);
+ for (plane = 0; plane < 3; plane++)
+ filter_plane(ctx, s->cbuf[1][plane], s->p_linesize,
+ s->cbuf[0][plane], s->p_linesize,
+ s->pr_width, s->pr_height);
+ color_correlation(s->color_dct, 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_dct_end(s->dct);
+ av_dct_end(s->idct);
+ av_free(s->block);
+ av_free(s->tmp_block);
+ 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]);
+ }
+ av_expr_free(s->expr);
+}
+
+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,
+};
diff --git a/libavfilter/vf_decimate.c b/libavfilter/vf_decimate.c
new file mode 100644
index 0000000..034d524
--- a/dev/null
+++ b/libavfilter/vf_decimate.c
@@ -0,0 +1,397 @@
+/*
+ * 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
+ 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 (dm->ppsrc) {
+ av_frame_free(&frame);
+ frame = dm->clean_src[i];
+ }
+ frame->pts = outlink->frame_count * dm->ts_unit;
+ 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(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)
+{
+ const 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);
+ }
+
+ 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_delogo.c b/libavfilter/vf_delogo.c
index 4175e47..fbc8983 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;
#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..1d62c44
--- a/dev/null
+++ b/libavfilter/vf_deshake.c
@@ -0,0 +1,580 @@
+/*
+ * 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 "libavcodec/dsputil.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
+
+#define MAX_R 64
+
+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->c.sad[0](deshake, src1 + cy * stride + cx, \
+ src2 + (j) * stride + (i), stride, \
+ deshake->blocksize)
+
+ 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 libavcodec sad functions
+ 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 counts[2*MAX_R+1][2*MAX_R+1];
+ int count_max_value = 0;
+ int contrast;
+
+ int pos;
+ double *angles = av_malloc(sizeof(*angles) * width * height / (16 * deshake->blocksize));
+ int center_x = 0, center_y = 0;
+ double p_x, p_y;
+
+ // Reset counts to zero
+ for (x = 0; x < deshake->rx * 2 + 1; x++) {
+ for (y = 0; y < deshake->ry * 2 + 1; y++) {
+ 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 libavcodec sad functions
+ 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) {
+ counts[mv.x + deshake->rx][mv.y + deshake->ry] += 1;
+ if (x > deshake->rx && y > deshake->ry)
+ 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(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 ", counts[x][y]);
+ if (counts[x][y] > count_max_value) {
+ t->vector.x = x - deshake->rx;
+ t->vector.y = y - deshake->ry;
+ count_max_value = counts[x][y];
+ }
+ }
+ //av_log(NULL, AV_LOG_ERROR, "\n");
+ }
+
+ p_x = (center_x - width / 2);
+ p_y = (center_y - height / 2);
+ t->vector.x += (cos(t->angle)-1)*p_x - sin(t->angle)*p_y;
+ t->vector.y += sin(t->angle)*p_x + (cos(t->angle)-1)*p_y;
+
+ // Clamp max shift & rotation?
+ t->vector.x = av_clipf(t->vector.x, -deshake->rx * 2, deshake->rx * 2);
+ t->vector.y = av_clipf(t->vector.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);
+ av_free(angles);
+}
+
+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->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.vector.x = 0;
+ deshake->last.vector.y = 0;
+ deshake->last.angle = 0;
+ deshake->last.zoom = 0;
+
+ deshake->avctx = avcodec_alloc_context3(NULL);
+ avpriv_dsputil_init(&deshake->c, deshake->avctx);
+
+ 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);
+ if (deshake->fp)
+ fclose(deshake->fp);
+ if (deshake->avctx)
+ avcodec_close(deshake->avctx);
+ av_freep(&deshake->avctx);
+}
+
+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.vector.x = t.vector.x;
+ orig.vector.y = t.vector.y;
+ orig.angle = t.angle;
+ orig.zoom = t.zoom;
+
+ // Generate a one-sided moving exponential average
+ deshake->avg.vector.x = alpha * t.vector.x + (1.0 - alpha) * deshake->avg.vector.x;
+ deshake->avg.vector.y = alpha * t.vector.y + (1.0 - alpha) * deshake->avg.vector.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.vector.x -= deshake->avg.vector.x;
+ t.vector.y -= deshake->avg.vector.y;
+ t.angle -= deshake->avg.angle;
+ t.zoom -= deshake->avg.zoom;
+
+ // Invert the motion to undo it
+ t.vector.x *= -1;
+ t.vector.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.vector.x, deshake->avg.vector.x, t.vector.x, orig.vector.y, deshake->avg.vector.y, t.vector.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.vector.x += deshake->last.vector.x;
+ t.vector.y += deshake->last.vector.y;
+ t.angle += deshake->last.angle;
+ t.zoom += deshake->last.zoom;
+
+ // Shrink motion by 10% to keep things centered in the camera frame
+ t.vector.x *= 0.9;
+ t.vector.y *= 0.9;
+ t.angle *= 0.9;
+
+ // Store the last absolute motion information
+ deshake->last.vector.x = t.vector.x;
+ deshake->last.vector.y = t.vector.y;
+ deshake->last.angle = t.angle;
+ deshake->last.zoom = t.zoom;
+
+ // Generate a luma transformation matrix
+ avfilter_get_matrix(t.vector.x, t.vector.y, t.angle, 1.0 + t.zoom / 100.0, matrix_y);
+ // Generate a chroma transformation matrix
+ avfilter_get_matrix(t.vector.x / (link->w / CHROMA_WIDTH(link)), t.vector.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 2241974..dd884a7 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 {
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 703b472..dde3b0a 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
*/
@@ -29,15 +29,16 @@
#include <sys/time.h>
#include <time.h>
-#include "libavutil/colorspace.h"
+#include "config.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/tree.h"
#include "libavutil/lfg.h"
#include "avfilter.h"
@@ -50,19 +51,28 @@
#include <freetype/config/ftheader.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
+#if CONFIG_FONTCONFIG
+#include <fontconfig/fontconfig.h>
+#endif
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
};
@@ -83,86 +93,118 @@ 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 {
const AVClass *class;
+ enum expansion_mode exp_mode; ///< expansion mode to use for the text
+ int reinit; ///< tells if the filter is being reinited
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
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;
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 boxcolor; ///< background color
+
FT_Library library; ///< freetype font library handle
FT_Face face; ///< freetype font face 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;
+#if FF_API_DRAWTEXT_OLD_TIMELINE
+ char *draw_expr; ///< expression for draw
+ AVExpr *draw_pexpr; ///< parsed expression for draw
int draw; ///< set to zero to prevent drawing
+#endif
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
+ 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", 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 },
+ {"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},
+ {"boxcolor", "set box color", OFFSET(boxcolor.rgba), AV_OPT_TYPE_COLOR, {.str="white"}, 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},
+ {"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 FF_API_DRAWTEXT_OLD_TIMELINE
+ {"draw", "if false do not draw (deprecated)", OFFSET(draw_expr), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
+#endif
+
+ {"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},
/* 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" },
@@ -181,19 +223,10 @@ 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 {
@@ -280,62 +313,159 @@ error:
return ret;
}
+static int load_font_file(AVFilterContext *ctx, const char *path, int index,
+ const char **error)
+{
+ DrawTextContext *s = ctx->priv;
+ int err;
+
+ err = FT_New_Face(s->library, path, index, &s->face);
+ if (err) {
+ *error = FT_ERRMSG(err);
+ return AVERROR(EINVAL);
+ }
+ return 0;
+}
+
+#if CONFIG_FONTCONFIG
+static int load_font_fontconfig(AVFilterContext *ctx, const char **error)
+{
+ DrawTextContext *s = ctx->priv;
+ FcConfig *fontconfig;
+ FcPattern *pattern, *fpat;
+ FcResult result = FcResultMatch;
+ FcChar8 *filename;
+ int err, index;
+ double size;
+
+ fontconfig = FcInitLoadConfigAndFonts();
+ if (!fontconfig) {
+ *error = "impossible to init fontconfig\n";
+ return AVERROR(EINVAL);
+ }
+ pattern = FcNameParse(s->fontfile ? s->fontfile :
+ (uint8_t *)(intptr_t)"default");
+ if (!pattern) {
+ *error = "could not parse fontconfig pattern";
+ return AVERROR(EINVAL);
+ }
+ if (!FcConfigSubstitute(fontconfig, pattern, FcMatchPattern)) {
+ *error = "could not substitue fontconfig options"; /* very unlikely */
+ return AVERROR(EINVAL);
+ }
+ FcDefaultSubstitute(pattern);
+ fpat = FcFontMatch(fontconfig, pattern, &result);
+ if (!fpat || result != FcResultMatch) {
+ *error = "impossible to find a matching font";
+ return AVERROR(EINVAL);
+ }
+ if (FcPatternGetString (fpat, FC_FILE, 0, &filename) != FcResultMatch ||
+ FcPatternGetInteger(fpat, FC_INDEX, 0, &index ) != FcResultMatch ||
+ FcPatternGetDouble (fpat, FC_SIZE, 0, &size ) != FcResultMatch) {
+ *error = "impossible to find font information";
+ return AVERROR(EINVAL);
+ }
+ 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, error);
+ if (err)
+ return err;
+ FcPatternDestroy(fpat);
+ FcPatternDestroy(pattern);
+ FcConfigDestroy(fontconfig);
+ return 0;
+}
+#endif
+
+static int load_font(AVFilterContext *ctx)
+{
+ DrawTextContext *s = ctx->priv;
+ int err;
+ const char *error = "unknown error\n";
+
+ /* load the face, and set up the encoding, which is by default UTF-8 */
+ err = load_font_file(ctx, s->fontfile, 0, &error);
+ if (!err)
+ return 0;
+#if CONFIG_FONTCONFIG
+ err = load_font_fontconfig(ctx, &error);
+ if (!err)
+ return 0;
+#endif
+ av_log(ctx, AV_LOG_ERROR, "Could not load font \"%s\": %s\n",
+ s->fontfile, error);
+ return err;
+}
+
+static int load_textfile(AVFilterContext *ctx)
+{
+ DrawTextContext *s = ctx->priv;
+ int err;
+ uint8_t *textbuf;
+ 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 (!(s->text = av_realloc(s->text, textbuf_size + 1)))
+ return AVERROR(ENOMEM);
+ memcpy(s->text, textbuf, textbuf_size);
+ s->text[textbuf_size] = 0;
+ av_file_unmap(textbuf, textbuf_size);
+
+ return 0;
+}
+
static av_cold int init(AVFilterContext *ctx)
{
int err;
DrawTextContext *s = ctx->priv;
Glyph *glyph;
- if (!s->fontfile) {
+#if FF_API_DRAWTEXT_OLD_TIMELINE
+ if (s->draw_expr)
+ av_log(ctx, AV_LOG_WARNING, "'draw' option is deprecated and will be removed soon, "
+ "you are encouraged to use the generic timeline support through the 'enable' option\n");
+#endif
+
+ if (!s->fontfile && !CONFIG_FONTCONFIG) {
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 (!(s->text = av_malloc(textbuf_size+1)))
- 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 ((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)))) {
@@ -344,12 +474,11 @@ 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));
@@ -362,37 +491,33 @@ static av_cold int init(AVFilterContext *ctx)
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);
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);
+ av_freep(&glyph->glyph);
av_free(elem);
return 0;
}
@@ -400,25 +525,25 @@ 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);
+#if FF_API_DRAWTEXT_OLD_TIMELINE
+ av_expr_free(s->draw_pexpr);
+ s->x_pexpr = s->y_pexpr = s->draw_pexpr = NULL;
+#endif
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_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);
}
static inline int is_newline(uint32_t c)
@@ -426,298 +551,267 @@ 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;
-
-#if HAVE_LOCALTIME_R
- time_t now = time(0);
- struct tm ltime;
- uint8_t *buf = s->expanded_text;
- int buf_size = s->expanded_text_size;
-
- if (!buf)
- buf_size = 2*strlen(s->text)+1;
+ int ret;
- localtime_r(&now, &ltime);
+ 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->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;
- 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_lfg_init(&s->prng, av_get_random_seed());
- if (!buf)
- return AVERROR(ENOMEM);
- text = s->expanded_text = buf;
- s->expanded_text_size = buf_size;
+ av_expr_free(s->x_pexpr);
+ av_expr_free(s->y_pexpr);
+#if FF_API_DRAWTEXT_OLD_TIMELINE
+ av_expr_free(s->draw_pexpr);
+ s->x_pexpr = s->y_pexpr = s->draw_pexpr = NULL;
+#else
+ s->x_pexpr = s->y_pexpr = NULL;
#endif
- 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;
- }
- }
-
- /* 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) {
- ret = load_glyph(ctx, &glyph, code);
- if (ret)
- return ret;
- }
-
- y_min = FFMIN(glyph->bbox.yMin, y_min);
- y_max = FFMAX(glyph->bbox.yMax, y_max);
- }
- 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;);
-
- /* skip the \n in the sequence \r\n */
- if (prev_code == '\r' && code == '\n')
- continue;
-
- prev_code = code;
- if (is_newline(code)) {
- str_w = FFMAX(str_w, x - s->x);
- y += text_height;
- x = 0;
- continue;
- }
+ 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)
- /* get glyph */
- prev_glyph = glyph;
- dummy.code = code;
- glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
+ return AVERROR(EINVAL);
+#if FF_API_DRAWTEXT_OLD_TIMELINE
+ if (s->draw_expr &&
+ (ret = av_expr_parse(&s->draw_pexpr, s->draw_expr, var_names,
+ NULL, NULL, fun2_names, fun2, 0, ctx)) < 0)
+ return ret;
+#endif
- /* 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;
- }
+ return 0;
+}
- if (x + glyph->bbox.xMax >= width) {
- str_w = FFMAX(str_w, x);
- y += text_height;
- x = 0;
- }
+static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
+{
+ DrawTextContext *s = ctx->priv;
- /* 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;
+ if (!strcmp(cmd, "reinit")) {
+ int ret;
+ uninit(ctx);
+ s->reinit = 1;
+ if ((ret = init(ctx)) < 0)
+ return ret;
+ return config_input(ctx->inputs[0]);
}
- str_w = FFMIN(width - 1, FFMAX(str_w, x));
- y = FFMIN(y + text_height, height - 1);
+ return AVERROR(ENOSYS);
+}
- 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_pict_type(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
+{
+ DrawTextContext *s = ctx->priv;
+ av_bprintf(bp, "%c", av_get_picture_type_char(s->var_values[VAR_PICT_TYPE]));
return 0;
}
-
-static int config_input(AVFilterLink *inlink)
+static int func_pts(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);
- int ret;
- s->hsub = pix_desc->log2_chroma_w;
- s->vsub = pix_desc->log2_chroma_h;
+ av_bprintf(bp, "%.6f", s->var_values[VAR_T]);
+ return 0;
+}
- s->var_values[VAR_E ] = M_E;
- s->var_values[VAR_PHI] = M_PHI;
- s->var_values[VAR_PI ] = M_PI;
+static int func_frame_num(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
+{
+ DrawTextContext *s = ctx->priv;
- 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;
+ av_bprintf(bp, "%d", (int)s->var_values[VAR_N]);
+ return 0;
+}
- s->var_values[VAR_X] = 0;
- s->var_values[VAR_Y] = 0;
- s->var_values[VAR_T] = NAN;
+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);
- av_lfg_init(&s->prng, av_get_random_seed());
+ if (e && e->value)
+ av_bprintf(bp, "%s", e->value);
+ return 0;
+}
- 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)
- return AVERROR(EINVAL);
+#if !HAVE_LOCALTIME_R
+static void localtime_r(const time_t *t, struct tm *tm)
+{
+ *tm = *localtime(t);
+}
+#endif
- 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;
+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;
+
+ time(&now);
+ if (tag == 'L')
+ localtime_r(&now, &tm);
+ else
+ tm = *gmtime(&now);
+ av_bprint_strftime(bp, fmt, &tm);
+ return 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];
- }
+static int func_eval_expr(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
+{
+ DrawTextContext *s = ctx->priv;
+ double res;
+ int ret;
- s->draw = 1;
+ 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);
- return dtext_prepare_text(ctx);
+ return ret;
}
-#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 },
+ { "pict_type", 0, 0, 0, func_pict_type },
+ { "pts", 0, 0, 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)
{
- 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]);
+ DrawTextContext *s = ctx->priv;
+ char *text = s->text;
+ AVBPrint *bp = &s->expanded_text;
+ 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, const uint8_t rgbcolor[4], FFDrawColor *color, int x, int y)
{
- 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;
@@ -736,15 +830,15 @@ static int draw_glyphs(DrawTextContext *s, AVFrame *frame,
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;
+ y1 = s->positions[i].y+s->y+y;
+
+ ff_blend_mask(&s->dc, color,
+ frame->data, frame->linesize, width, height,
+ glyph->bitmap.buffer, glyph->bitmap.pitch,
+ glyph->bitmap.width, glyph->bitmap.rows,
+ glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 0 : 3,
+ 0, x1, y1);
}
return 0;
@@ -754,107 +848,202 @@ 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)) < 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;
+ }
+
+ 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);
+#if FF_API_DRAWTEXT_OLD_TIMELINE
+ if (s->draw_pexpr){
+ s->draw = av_expr_eval(s->draw_pexpr, s->var_values, &s->prng);
+
+ if(!s->draw)
+ return 0;
+ }
+ if (ctx->is_disabled)
+ return 0;
+#endif
+
+ 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)
+ if ((ret = draw_glyphs(s, frame, width, height, s->shadowcolor.rgba,
+ &s->shadowcolor, s->shadowx, s->shadowy)) < 0)
return ret;
}
- if ((ret = draw_glyphs(s, frame, width, height,
- s->fontcolor_rgba,
- s->fontcolor,
- s->x,
- s->y)) < 0)
+ if ((ret = draw_glyphs(s, frame, width, height, s->fontcolor.rgba,
+ &s->fontcolor, 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;
+ 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);
-
- normalize_double(&s->x, s->var_values[VAR_X]);
- normalize_double(&s->y, s->var_values[VAR_Y]);
-
- 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);
+ s->var_values[VAR_PICT_TYPE] = frame->pict_type;
+ s->metadata = av_frame_get_metadata(frame);
- if (s->draw)
- draw_text(inlink->dst, frame, frame->width, frame->height);
+ draw_text(ctx, frame, frame->width, frame->height);
- s->var_values[VAR_N] += 1.0;
+ av_log(ctx, AV_LOG_DEBUG, "n:%d t:%f text_w:%d text_h:%d x:%d y:%d\n",
+ (int)s->var_values[VAR_N], s->var_values[VAR_T],
+ (int)s->var_values[VAR_TEXT_W], (int)s->var_values[VAR_TEXT_H],
+ s->x, s->y);
- return ff_filter_frame(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 }
};
@@ -875,7 +1064,12 @@ 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,
+#if FF_API_DRAWTEXT_OLD_TIMELINE
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
+#else
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+#endif
};
diff --git a/libavfilter/vf_edgedetect.c b/libavfilter/vf_edgedetect.c
new file mode 100644
index 0000000..c8ec734
--- a/dev/null
+++ b/libavfilter/vf_edgedetect.c
@@ -0,0 +1,331 @@
+/*
+ * 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
+ * Edge detection filter
+ *
+ * @see https://en.wikipedia.org/wiki/Canny_edge_detector
+ */
+
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct {
+ const AVClass *class;
+ uint8_t *tmpbuf;
+ uint16_t *gradients;
+ char *directions;
+ double low, high;
+ uint8_t low_u8, high_u8;
+} 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 },
+ { 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)
+{
+ 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));
+ return 0;
+}
+
+static int config_props(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ EdgeDetectContext *edgedetect = ctx->priv;
+
+ edgedetect->tmpbuf = av_malloc(inlink->w * inlink->h);
+ edgedetect->gradients = av_calloc(inlink->w * inlink->h, sizeof(*edgedetect->gradients));
+ edgedetect->directions = av_malloc(inlink->w * inlink->h);
+ if (!edgedetect->tmpbuf || !edgedetect->gradients || !edgedetect->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(AVFilterContext *ctx, int w, int h,
+ uint16_t *dst, int dst_linesize,
+ const uint8_t *src, int src_linesize)
+{
+ int i, j;
+ EdgeDetectContext *edgedetect = ctx->priv;
+
+ for (j = 1; j < h - 1; j++) {
+ dst += dst_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);
+ edgedetect->directions[j*w + i] = get_rounded_direction(gx, gy);
+ }
+ }
+}
+
+static void non_maximum_suppression(AVFilterContext *ctx, int w, int h,
+ uint8_t *dst, int dst_linesize,
+ const uint16_t *src, int src_linesize)
+{
+ int i, j;
+ EdgeDetectContext *edgedetect = ctx->priv;
+
+#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;
+ src += src_linesize;
+ for (i = 1; i < w - 1; i++) {
+ switch (edgedetect->directions[j*w + 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(AVFilterContext *ctx, int w, int h,
+ uint8_t *dst, int dst_linesize,
+ const uint8_t *src, int src_linesize)
+{
+ int i, j;
+ EdgeDetectContext *edgedetect = ctx->priv;
+ const int low = edgedetect->low_u8;
+ const int high = edgedetect->high_u8;
+
+ 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 int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ EdgeDetectContext *edgedetect = ctx->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ uint8_t *tmpbuf = edgedetect->tmpbuf;
+ uint16_t *gradients = edgedetect->gradients;
+ 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);
+ }
+
+ /* gaussian filter to reduce noise */
+ gaussian_blur(ctx, inlink->w, inlink->h,
+ tmpbuf, inlink->w,
+ in->data[0], in->linesize[0]);
+
+ /* compute the 16-bits gradients and directions for the next step */
+ sobel(ctx, inlink->w, inlink->h,
+ gradients, 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(ctx, inlink->w, inlink->h,
+ tmpbuf, inlink->w,
+ gradients, inlink->w);
+
+ /* keep high values, or low values surrounded by high values */
+ double_threshold(ctx, inlink->w, inlink->h,
+ out->data[0], out->linesize[0],
+ tmpbuf, inlink->w);
+
+ if (!direct)
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ EdgeDetectContext *edgedetect = ctx->priv;
+ av_freep(&edgedetect->tmpbuf);
+ av_freep(&edgedetect->gradients);
+ av_freep(&edgedetect->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_extractplanes.c b/libavfilter/vf_extractplanes.c
new file mode 100644
index 0000000..fadd2dd
--- a/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 b6bd775..088bd65 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,26 @@
* based heavily on vf_negate.c by Bobby Bingham
*/
+#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 +53,14 @@ typedef struct {
int type;
int factor, fade_per_frame;
int start_frame, nb_frames;
- unsigned int frame_index, stop_frame;
+ unsigned int frame_index;
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;
} FadeContext;
static av_cold int init(AVFilterContext *ctx)
@@ -50,18 +68,27 @@ 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
+ }
+
+ // 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->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);
return 0;
}
@@ -72,7 +99,10 @@ static int query_formats(AVFilterContext *ctx)
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
};
@@ -80,6 +110,13 @@ static int query_formats(AVFilterContext *ctx)
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 +126,15 @@ 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;
}
@@ -97,9 +143,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 +153,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 +166,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 +188,145 @@ 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));
-
- 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));
+ // 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))
+ && (s->frame_index >= s->start_frame)) {
+ // Time to start fading
+ s->fade_state = VF_FADE_FADING;
+
+ // 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 = s->frame_index;
+ }
}
}
+ if (s->fade_state == VF_FADE_FADING) {
+ if (s->duration == 0) {
+ // Fading based on frame count
+ s->factor = (s->frame_index - s->start_frame) * s->fade_per_frame;
+ if (s->frame_index > (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);
+
+ // Invert fade_factor if Fading Out
+ if (s->type == 1) {
+ 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 {
+ /* luma or rgb plane */
+ 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));
+ }
+ }
+ }
+
s->frame_index++;
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 },
+ { 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 +341,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
--- a/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
--- a/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 a930e15..84088a0 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"
@@ -54,6 +51,7 @@ static int query_formats(AVFilterContext *ctx)
for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++) {
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
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) {
@@ -72,24 +70,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;
-}
-
-static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
-{
- AVFilterContext *ctx = inlink->dst;
- AVFilterLink *outlink = ctx->outputs[0];
- return ff_get_video_buffer(outlink, w, h);
+ return av_image_fill_linesizes(s->line_size, inlink->format, inlink->w);
}
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
@@ -97,8 +79,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) {
@@ -109,14 +92,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.
@@ -125,11 +121,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
@@ -137,46 +134,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,
- .get_video_buffer = get_video_buffer,
- .filter_frame = filter_frame,
- .needs_writable = 1,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -197,4 +192,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 22628d7..2e9ff27 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
*/
@@ -52,7 +52,7 @@ static av_cold int init(AVFilterContext *ctx)
FormatContext *s = ctx->priv;
const char *cur, *sep;
char pix_fmt_name[AV_PIX_FMT_NAME_MAXSIZE];
- int pix_fmt_name_len;
+ int pix_fmt_name_len, ret;
enum AVPixelFormat pix_fmt;
/* parse the list of formats */
@@ -68,12 +68,9 @@ static av_cold int init(AVFilterContext *ctx)
memcpy(pix_fmt_name, cur, pix_fmt_name_len);
pix_fmt_name[pix_fmt_name_len] = 0;
- pix_fmt = av_get_pix_fmt(pix_fmt_name);
- if (pix_fmt == AV_PIX_FMT_NONE) {
- av_log(ctx, AV_LOG_ERROR, "Unknown pixel format: %s\n", pix_fmt_name);
- return -1;
- }
+ if ((ret = ff_parse_pixel_format(&pix_fmt, pix_fmt_name, ctx)) < 0)
+ return ret;
s->listed_pix_fmt_flags[pix_fmt] = 1;
}
@@ -101,7 +98,7 @@ static AVFilterFormats *make_format_list(FormatContext *s, int flag)
#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
@@ -111,12 +108,8 @@ static int query_formats_format(AVFilterContext *ctx)
return 0;
}
-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[] = {
{
@@ -136,18 +129,14 @@ 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."),
-
- .init = init,
-
+ .name = "format",
+ .description = NULL_IF_CONFIG_SMALL("Convert the input video to one of the specified pixel formats."),
+ .init = init,
.query_formats = query_formats_format,
-
- .priv_size = sizeof(FormatContext),
- .priv_class = &format_class,
-
- .inputs = avfilter_vf_format_inputs,
- .outputs = avfilter_vf_format_outputs,
+ .priv_size = sizeof(FormatContext),
+ .priv_class = &format_class,
+ .inputs = avfilter_vf_format_inputs,
+ .outputs = avfilter_vf_format_outputs,
};
#endif /* CONFIG_FORMAT_FILTER */
@@ -158,12 +147,8 @@ static int query_formats_noformat(AVFilterContext *ctx)
return 0;
}
-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[] = {
{
@@ -183,17 +168,13 @@ 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."),
-
- .init = init,
-
+ .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,
.query_formats = query_formats_noformat,
-
- .priv_size = sizeof(FormatContext),
- .priv_class = &noformat_class,
-
- .inputs = avfilter_vf_noformat_inputs,
- .outputs = avfilter_vf_noformat_outputs,
+ .priv_size = sizeof(FormatContext),
+ .priv_class = &noformat_class,
+ .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 0c7023f..1d1b947 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
*/
@@ -45,7 +49,7 @@ typedef struct FPSContext {
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
@@ -56,28 +60,24 @@ 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*))))
return AVERROR(ENOMEM);
@@ -102,7 +102,7 @@ static av_cold void uninit(AVFilterContext *ctx)
{
FPSContext *s = ctx->priv;
if (s->fifo) {
- s->drop += av_fifo_size(s->fifo) / sizeof(AVFilterBufferRef*);
+ s->drop += av_fifo_size(s->fifo) / sizeof(AVFrame*);
flush_fifo(s->fifo);
av_fifo_free(s->fifo);
}
@@ -115,7 +115,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;
@@ -183,7 +184,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *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,
@@ -204,13 +205,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->pts, inlink->time_base,
+ outlink->time_base, s->rounding);
if (delta < 1) {
/* drop the frame and everything buffered except the first */
@@ -272,8 +273,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
static const AVFilterPad avfilter_vf_fps_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
.filter_frame = filter_frame,
},
{ NULL }
@@ -291,14 +292,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_framestep.c b/libavfilter/vf_framestep.c
new file mode 100644
index 0000000..9087f46
--- a/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 {
+ 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 0d0866a..a070eb4 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
*/
@@ -67,8 +67,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 +138,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 +151,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 +211,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,29 +230,60 @@ 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;
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 */
+ /* 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 = strtok_r(p, ":", &ptr); p = NULL)
- if (s->dl_handle = load_path(ctx, p, dl_name))
+ 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;
+ }
+
+ 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;
+ }
+ if (!s->dl_handle) {
+ ret = load_path(ctx, &s->dl_handle, "/usr/local/lib/frei0r-1/", dl_name);
+ if (ret < 0)
+ return ret;
+ }
+ if (!s->dl_handle) {
+ ret = load_path(ctx, &s->dl_handle, "/usr/lib/frei0r-1/", 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);
@@ -265,7 +301,7 @@ static av_cold int frei0r_init(AVFilterContext *ctx,
return AVERROR(EINVAL);
if (f0r_init() < 0) {
- av_log(ctx, AV_LOG_ERROR, "Could not init the frei0r module");
+ av_log(ctx, AV_LOG_ERROR, "Could not init the frei0r module\n");
return AVERROR(EINVAL);
}
@@ -320,7 +356,7 @@ static int config_input_props(AVFilterLink *inlink)
if (s->destruct && s->instance)
s->destruct(s->instance);
if (!(s->instance = s->construct(inlink->w, inlink->h))) {
- av_log(ctx, AV_LOG_ERROR, "Impossible to load frei0r instance");
+ av_log(ctx, AV_LOG_ERROR, "Impossible to load frei0r instance\n");
return AVERROR(EINVAL);
}
@@ -373,19 +409,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[] = {
{
@@ -406,38 +437,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);
}
@@ -452,11 +468,12 @@ 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);
if (!(s->instance = s->construct(outlink->w, outlink->h))) {
- av_log(ctx, AV_LOG_ERROR, "Impossible to load frei0r instance");
+ av_log(ctx, AV_LOG_ERROR, "Impossible to load frei0r instance\n");
return AVERROR(EINVAL);
}
@@ -480,20 +497,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[] = {
{
@@ -506,17 +518,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
--- a/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 79f6790..6ae7c60 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;
@@ -125,9 +125,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)
@@ -148,9 +148,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
};
@@ -167,12 +168,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;
@@ -195,13 +196,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;
@@ -224,19 +222,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[] = {
{
@@ -264,7 +258,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 6034b68..19b6606 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 {
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; fmt < AV_PIX_FMT_NB; 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
--- a/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
--- a/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 cd9f0d2..518a23d 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.
*/
@@ -229,15 +229,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
};
@@ -276,12 +276,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 {
@@ -293,17 +295,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)
@@ -313,21 +319,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[] = {
{
@@ -339,6 +340,7 @@ static const AVFilterPad avfilter_vf_hqdn3d_inputs[] = {
{ NULL }
};
+
static const AVFilterPad avfilter_vf_hqdn3d_outputs[] = {
{
.name = "default",
@@ -350,14 +352,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 5cdbb12..268ac9a 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_hue.c b/libavfilter/vf_hue.c
new file mode 100644
index 0000000..faa2e8d
--- a/dev/null
+++ b/libavfilter/vf_hue.c
@@ -0,0 +1,449 @@
+/*
+ * 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;
+ 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_c(new_u);
+ h->lut_v[i][j] = av_clip_uint8_c(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);
+
+ 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.f 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 (old_hue_sin != hue->hue_sin || old_hue_cos != hue->hue_cos)
+ create_chrominance_lut(hue, hue->hue_cos, hue->hue_sin);
+
+ if (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);
+ 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..d441a5f
--- a/dev/null
+++ b/libavfilter/vf_idet.c
@@ -0,0 +1,308 @@
+/*
+ * 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 "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "internal.h"
+
+#define HIST_SIZE 4
+
+typedef enum {
+ TFF,
+ BFF,
+ PROGRSSIVE,
+ UNDETERMINED,
+} Type;
+
+typedef struct {
+ const AVClass *class;
+ float interlace_threshold;
+ float progressive_threshold;
+
+ Type last_type;
+ int prestat[4];
+ int poststat[4];
+
+ uint8_t history[HIST_SIZE];
+
+ AVFrame *cur;
+ AVFrame *next;
+ AVFrame *prev;
+ int (*filter_line)(const uint8_t *prev, const uint8_t *cur, const uint8_t *next, int w);
+
+ const AVPixFmtDescriptor *csp;
+} IDETContext;
+
+#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 },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(idet);
+
+static const char *type2str(Type type)
+{
+ switch(type) {
+ case TFF : return "Top Field First ";
+ case BFF : return "Bottom Field First";
+ case PROGRSSIVE : return "Progressive ";
+ case UNDETERMINED: return "Undetermined ";
+ }
+ return NULL;
+}
+
+static int 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;
+}
+
+static int 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;
+ Type type, best_type;
+ int match = 0;
+
+ 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);
+ }
+ }
+
+ 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 = PROGRSSIVE;
+ }else{
+ type = UNDETERMINED;
+ }
+
+ 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 == PROGRSSIVE){
+ idet->cur->interlaced_frame = 0;
+ }
+
+ idet->prestat [ type] ++;
+ idet->poststat[idet->last_type] ++;
+ av_log(ctx, AV_LOG_DEBUG, "Single frame:%s, Multi frame:%s\n", type2str(type), type2str(idet->last_type));
+}
+
+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 = (void*)filter_line_c_16bit;
+
+ filter(ctx);
+
+ return ff_filter_frame(ctx->outputs[0], av_frame_clone(idet->cur));
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ IDETContext *idet = ctx->priv;
+
+ av_log(ctx, AV_LOG_INFO, "Single frame detection: TFF:%d BFF:%d Progressive:%d Undetermined:%d\n",
+ idet->prestat[TFF],
+ idet->prestat[BFF],
+ idet->prestat[PROGRSSIVE],
+ idet->prestat[UNDETERMINED]
+ );
+ av_log(ctx, AV_LOG_INFO, "Multi frame detection: TFF:%d BFF:%d Progressive:%d Undetermined:%d\n",
+ idet->poststat[TFF],
+ idet->poststat[BFF],
+ idet->poststat[PROGRSSIVE],
+ idet->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->last_type = UNDETERMINED;
+ memset(idet->history, UNDETERMINED, HIST_SIZE);
+
+ idet->filter_line = filter_line_c;
+
+ 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,
+ },
+ { 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_il.c b/libavfilter/vf_il.c
new file mode 100644
index 0000000..e755caa
--- a/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; fmt < AV_PIX_FMT_NB; 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 aea4fdb..86e42e2 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 {
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)
@@ -108,8 +104,11 @@ static int config_out_props(AVFilterLink *outlink)
outlink->w = inlink->w;
outlink->h = inlink->h;
outlink->time_base = inlink->time_base;
+ outlink->frame_rate = inlink->frame_rate;
// half framerate
outlink->time_base.num *= 2;
+ outlink->frame_rate.den *= 2;
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
av_log(ctx, AV_LOG_VERBOSE, "%s interlacing %s lowpass filter\n",
s->scan == MODE_TFF ? "tff" : "bff", (s->lowpass) ? "with" : "without");
@@ -126,7 +125,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];
@@ -187,7 +186,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
out = av_frame_clone(s->cur);
out->pts /= 2; // adjust pts to new framerate
ret = ff_filter_frame(outlink, out);
- s->got_output = 1;
return ret;
}
@@ -210,20 +208,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;
}
@@ -239,10 +223,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 }
};
@@ -251,12 +234,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..1f8e091
--- a/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 = srcp_saved = inpic->data[plane];
+ src_linesize = inpic->linesize[plane];
+ psrc_linesize = kerndeint->tmp_linesize[plane];
+ dstp = 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_libopencv.c b/libavfilter/vf_libopencv.c
index fa913f7..2306b09 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
*/
@@ -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 c59dcd6..9f30ae0 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 {
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 {
#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
@@ -183,8 +162,8 @@ static double compute_gammaval(void *opaque, double gamma)
}
static double (* const funcs1[])(void *, double) = {
- clip,
- compute_gammaval,
+ (void *)clip,
+ (void *)compute_gammaval,
NULL
};
@@ -199,8 +178,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 +196,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 +213,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 +266,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 +286,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 +305,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 +423,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 +431,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..79566be
--- a/dev/null
+++ b/libavfilter/vf_lut3d.c
@@ -0,0 +1,796 @@
+/*
+ * 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;
+ int is16bit;
+ struct rgbvec (*interp_8) (const struct LUT3DContext*, uint8_t, uint8_t, uint8_t);
+ struct rgbvec (*interp_16)(const struct LUT3DContext*, uint16_t, uint16_t, uint16_t);
+ 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;
+
+#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 struct rgbvec interp_##nbits##_##name(const LUT3DContext *lut3d, \
+ uint##nbits##_t r, \
+ uint##nbits##_t g, \
+ uint##nbits##_t b) \
+{ \
+ const float scale = (1. / ((1<<nbits) - 1)) * (lut3d->lutsize - 1); \
+ const struct rgbvec scaled_rgb = {r * scale, g * scale, b * scale}; \
+ return interp_##name(lut3d, &scaled_rgb); \
+}
+
+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; seems to be generated by
+ * Davinci */
+static int parse_dat(AVFilterContext *ctx, FILE *f)
+{
+ LUT3DContext *lut3d = ctx->priv;
+ const int size = lut3d->lutsize;
+ int i, j, k;
+
+ for (k = 0; k < size; k++) {
+ for (j = 0; j < size; j++) {
+ for (i = 0; i < size; i++) {
+ char line[MAX_LINE_SIZE];
+ struct rgbvec *vec = &lut3d->lut[k][j][i];
+ NEXT_LINE(skip_line(line));
+ sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b);
+ }
+ }
+ }
+ 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[k][j][i];
+
+ 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)
+{
+ 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:
+ lut3d->is16bit = 1;
+ }
+
+ ff_fill_rgba_map(lut3d->rgba_map, inlink->format);
+ lut3d->step = av_get_padded_bits_per_pixel(desc) >> (3 + lut3d->is16bit);
+
+#define SET_FUNC(name) do { \
+ if (lut3d->is16bit) lut3d->interp_16 = interp_16_##name; \
+ else lut3d->interp_8 = 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;
+}
+
+#define FILTER(nbits) do { \
+ uint8_t *dstrow = out->data[0]; \
+ const uint8_t *srcrow = in ->data[0]; \
+ \
+ for (y = 0; y < inlink->h; y++) { \
+ uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
+ const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
+ for (x = 0; x < inlink->w * step; x += step) { \
+ struct rgbvec vec = lut3d->interp_##nbits(lut3d, src[x + r], src[x + g], src[x + b]); \
+ 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]; \
+ } \
+} while (0)
+
+static AVFrame *apply_lut(AVFilterLink *inlink, AVFrame *in)
+{
+ int x, y, direct = 0;
+ AVFilterContext *ctx = inlink->dst;
+ LUT3DContext *lut3d = ctx->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *out;
+ 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];
+
+ 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 NULL;
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ if (lut3d->is16bit) FILTER(16);
+ else FILTER(8);
+
+ if (!direct)
+ 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")) {
+ lut3d->lutsize = 33;
+ 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,
+};
+#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[k][j][i]; \
+ 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,
+};
+#endif
diff --git a/libavfilter/vf_mcdeint.c b/libavfilter/vf_mcdeint.c
new file mode 100644
index 0000000..2aa2e27
--- a/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..06a17fb
--- a/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}, .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; i < AV_PIX_FMT_NB; 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..f32c81f
--- a/dev/null
+++ b/libavfilter/vf_mp.c
@@ -0,0 +1,791 @@
+/*
+ * 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},
+
+ {IMGFMT_XVMC_MOCO_MPEG2, AV_PIX_FMT_XVMC_MPEG2_MC},
+ {IMGFMT_XVMC_IDCT_MPEG2, AV_PIX_FMT_XVMC_MPEG2_IDCT},
+ {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 inpolite 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;
+
+ picref->type = AVMEDIA_TYPE_VIDEO;
+
+ 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..099622a
--- a/dev/null
+++ b/libavfilter/vf_mpdecimate.c
@@ -0,0 +1,257 @@
+/*
+ * 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/timestamp.h"
+#include "libavcodec/dsputil.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
+ DSPContext dspctx; ///< context providing optimized diff routines
+ AVCodecContext *avctx; ///< codec context required for the DSPContext
+} 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, uint8_t *ref, int linesize,
+ int w, int h)
+{
+ DecimateContext *decimate = ctx->priv;
+ DSPContext *dspctx = &decimate->dspctx;
+
+ int x, y;
+ int d, c = 0;
+ int t = (w/16)*(h/16)*decimate->frac;
+ int16_t block[8*8];
+
+ /* compute difference for blocks of 8x8 bytes */
+ for (y = 0; y < h-7; y += 4) {
+ for (x = 8; x < w-7; x += 4) {
+ dspctx->diff_pixels(block,
+ cur+x+y*linesize,
+ ref+x+y*linesize, linesize);
+ d = dspctx->sum_abs_dctelem(block);
+ 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], 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;
+
+ 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);
+
+ decimate->avctx = avcodec_alloc_context3(NULL);
+ if (!decimate->avctx)
+ return AVERROR(ENOMEM);
+ avpriv_dsputil_init(&decimate->dspctx, decimate->avctx);
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ DecimateContext *decimate = ctx->priv;
+ av_frame_free(&decimate->ref);
+ if (decimate->avctx) {
+ avcodec_close(decimate->avctx);
+ av_freep(&decimate->avctx);
+ }
+}
+
+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..c29afa2
--- a/dev/null
+++ b/libavfilter/vf_noise.c
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2013 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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 "libavutil/x86/asm.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.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];
+} FilterParams;
+
+typedef struct {
+ const AVClass *class;
+ int nb_planes;
+ int bytewidth[4];
+ int height[4];
+ FilterParams all;
+ FilterParams param[4];
+ int rand_shift[MAX_RES];
+ int rand_shift_init;
+ void (*line_noise)(uint8_t *dst, const uint8_t *src, int8_t *noise, int len, int shift);
+ void (*line_noise_avg)(uint8_t *dst, const uint8_t *src, int len, int8_t **shift);
+} NoiseContext;
+
+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);
+
+ 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));
+
+ if (!n->rand_shift_init) {
+ for (i = 0; i < MAX_RES; i++)
+ n->rand_shift[i] = av_lfg_get(lfg) & (MAX_SHIFT - 1);
+ n->rand_shift_init = 1;
+ }
+
+ fp->noise = noise;
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ int fmt;
+
+ for (fmt = 0; fmt < AV_PIX_FMT_NB; 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;
+}
+
+static inline void line_noise_c(uint8_t *dst, const uint8_t *src, 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);
+ }
+}
+
+#define ASMALIGN(ZEROBITS) ".p2align " #ZEROBITS "\n\t"
+
+static void line_noise_mmx(uint8_t *dst, const uint8_t *src,
+ int8_t *noise, int len, int shift)
+{
+#if HAVE_MMX_INLINE
+ 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"
+ ASMALIGN(4)
+ "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)
+ line_noise_c(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0);
+#endif
+}
+
+static void line_noise_mmxext(uint8_t *dst, const uint8_t *src,
+ int8_t *noise, int len, int shift)
+{
+#if HAVE_MMXEXT_INLINE
+ 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"
+ ASMALIGN(4)
+ "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)
+ line_noise_c(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0);
+#endif
+}
+
+static inline void line_noise_avg_c(uint8_t *dst, const uint8_t *src,
+ int len, int8_t **shift)
+{
+ int i;
+ int8_t *src2 = (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 inline void line_noise_avg_mmx(uint8_t *dst, const uint8_t *src,
+ int len, int8_t **shift)
+{
+#if HAVE_MMX_INLINE
+ x86_reg mmx_len= len&(~7);
+
+ __asm__ volatile(
+ "mov %5, %%"REG_a" \n\t"
+ ASMALIGN(4)
+ "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){
+ int8_t *shift2[3]={shift[0]+mmx_len, shift[1]+mmx_len, shift[2]+mmx_len};
+ line_noise_avg_c(dst+mmx_len, src+mmx_len, len-mmx_len, shift2);
+ }
+#endif
+}
+
+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;
+ AVLFG *lfg = &p->lfg;
+ int shift, 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);
+ if (flags & NOISE_TEMPORAL)
+ shift = av_lfg_get(lfg) & (MAX_SHIFT - 1);
+ else
+ shift = n->rand_shift[ix];
+
+ if (flags & NOISE_AVERAGED) {
+ n->line_noise_avg(dst, src, width, p->prev_shift[ix]);
+ p->prev_shift[ix][shift & 3] = noise + shift;
+ } else {
+ n->line_noise(dst, src, noise, width, 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;
+
+ 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);
+ }
+
+ 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;
+ int cpu_flags = av_get_cpu_flags();
+
+ 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 = line_noise_c;
+ n->line_noise_avg = line_noise_avg_c;
+
+ if (HAVE_MMX_INLINE &&
+ cpu_flags & AV_CPU_FLAG_MMX) {
+ n->line_noise = line_noise_mmx;
+ n->line_noise_avg = line_noise_avg_mmx;
+ }
+ if (HAVE_MMXEXT_INLINE &&
+ cpu_flags & AV_CPU_FLAG_MMXEXT)
+ n->line_noise = line_noise_mmxext;
+
+ 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_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 5155573..9047dee 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,84 +30,232 @@
#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 "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
};
#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 {
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_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;
-
- 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_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_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;
}
@@ -115,65 +263,57 @@ 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\n",
+ "main w:%d h:%d fmt:%s overlay w:%d h:%d fmt:%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));
-
- 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;
@@ -182,71 +322,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;
}
@@ -258,127 +523,91 @@ static void blend_frame(AVFilterContext *ctx,
}
}
-static int filter_frame_main(AVFilterLink *inlink, AVFrame *frame)
+static AVFrame *do_blend(AVFilterContext *ctx, AVFrame *mainpic,
+ const AVFrame *second)
{
- OverlayContext *s = inlink->dst->priv;
-
- av_assert0(!s->main);
- s->main = frame;
+ OverlayContext *s = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+
+ /* TODO: reindent */
+ if (s->eval_mode == EVAL_MODE_FRAME) {
+ int64_t pos = av_frame_get_pkt_pos(mainpic);
+
+ 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;
+
+ 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 filter_frame_overlay(AVFilterLink *inlink, AVFrame *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
{
OverlayContext *s = inlink->dst->priv;
-
- av_assert0(!s->over_next);
- s->over_next = frame;
-
- return 0;
+ return ff_dualinput_filter_frame(&s->dinput, inlink, inpicref);
}
-static int output_frame(AVFilterContext *ctx)
+static int request_frame(AVFilterLink *outlink)
{
- OverlayContext *s = ctx->priv;
- AVFilterLink *outlink = ctx->outputs[0];
- int ret = ff_filter_frame(outlink, s->main);
- s->main = NULL;
-
- return ret;
+ OverlayContext *s = outlink->src->priv;
+ return ff_dualinput_request_frame(&s->dinput, outlink);
}
-static int handle_overlay_eof(AVFilterContext *ctx)
+static av_cold int init(AVFilterContext *ctx)
{
OverlayContext *s = ctx->priv;
- if (s->over_prev)
- blend_frame(ctx, s->main, s->over_prev, s->x, s->y);
- return output_frame(ctx);
-}
-
-static int request_frame(AVFilterLink *outlink)
-{
- 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;
- }
-
- /* get a new frame on the overlay input, on EOF
- * reuse previous */
- 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;
- }
-
- 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->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->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;
}
-
- 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 },
- { NULL },
+#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 },
+ { "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" },
+ { "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 }
};
@@ -394,16 +623,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..95ba43b
--- a/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(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 0609767..2740c63 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 {
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->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);
+ 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);
- 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->draw.pixelstep[planes[i]] +
(s->y >> 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..f433226
--- a/dev/null
+++ b/libavfilter/vf_perspective.c
@@ -0,0 +1,403 @@
+/*
+ * 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;
+
+ void (*perspective)(struct PerspectiveContext *s,
+ uint8_t *dst, int dst_linesize,
+ uint8_t *src, int src_linesize,
+ int w, int h, int hsub, int vsub);
+} PerspectiveContext;
+
+#define OFFSET(x) offsetof(PerspectiveContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+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" },
+ { 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, q;
+ 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);
+
+ 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;
+
+ 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 + q * w * h) + 0.5);
+ v = (int)floor(SUB_PIXELS * (x3 * x + x4 * y + x5) /
+ (x6 * x + x7 * y + q * w * h) + 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;
+}
+
+static void resample_cubic(PerspectiveContext *s,
+ uint8_t *dst, int dst_linesize,
+ uint8_t *src, int src_linesize,
+ int w, int h, int hsub, int vsub)
+{
+ const int linesize = s->linesize[0];
+ int x, y;
+
+ for (y = 0; y < h; 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;
+ }
+ }
+}
+
+static void resample_linear(PerspectiveContext *s,
+ uint8_t *dst, int dst_linesize,
+ uint8_t *src, int src_linesize,
+ int w, int h, int hsub, int vsub)
+{
+ const int linesize = s->linesize[0];
+ int x, y;
+
+ for (y = 0; y < h; 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;
+ }
+ }
+}
+
+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;
+ s->perspective(s, out->data[plane], out->linesize[plane],
+ frame->data[plane], frame->linesize[plane],
+ s->linesize[plane], s->height[plane], hsub, vsub);
+ }
+
+ 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,
+};
diff --git a/libavfilter/vf_phase.c b/libavfilter/vf_phase.c
new file mode 100644
index 0000000..2dcc6fa
--- a/dev/null
+++ b/libavfilter/vf_phase.c
@@ -0,0 +1,320 @@
+/*
+ * 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;
+ 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(AVFilterContext *ctx, PhaseContext *s,
+ AVFrame *old, AVFrame *new)
+{
+ double bdiff, tdiff, pdiff, scale;
+ const int ns = new->linesize[0];
+ const int os = old->linesize[0];
+ uint8_t *nptr = new->data[0];
+ uint8_t *optr = old->data[0];
+ const int h = new->height;
+ const int w = new->width;
+ int bdif, tdif, pdif;
+ enum PhaseMode mode = s->mode;
+ uint8_t *end, *rend;
+ int top, t;
+
+ 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 {
+ bdiff = pdiff = tdiff = 0.0;
+
+ for (end = nptr + (h - 2) * ns, nptr += ns, optr += os, top = 0;
+ nptr < end; nptr += ns - w, optr += os - w, top ^= 1) {
+ 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;
+ }
+
+ 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;
+
+ 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) {
+ mode = PROGRESSIVE;
+ s->frame = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!s->frame) {
+ av_frame_free(&in);
+ av_frame_free(&out);
+ return AVERROR(ENOMEM);
+ }
+ } else {
+ mode = analyze_plane(ctx, s, s->frame, in);
+ }
+
+ for (plane = 0; plane < s->nb_planes; plane++) {
+ uint8_t *buf = s->frame->data[plane];
+ 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]);
+ memcpy(buf, from, s->linesize[plane]);
+
+ buf += s->frame->linesize[plane];
+ from += in->linesize[plane];
+ to += out->linesize[plane];
+ }
+ }
+
+ av_frame_free(&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,
+};
diff --git a/libavfilter/vf_pixdesctest.c b/libavfilter/vf_pixdesctest.c
index 5c6b625..54ddf89 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
*/
@@ -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..c72fdc6
--- a/dev/null
+++ b/libavfilter/vf_pp.c
@@ -0,0 +1,186 @@
+/*
+ * 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_YUV444P, AV_PIX_FMT_YUVJ444P,
+ 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_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_YUVJ444P:
+ case AV_PIX_FMT_YUV444P: flags |= PP_FORMAT_444; 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..4915816
--- a/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 heigth 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..69e1e91
--- a/dev/null
+++ b/libavfilter/vf_pullup.c
@@ -0,0 +1,768 @@
+/*
+ * 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, int 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, int 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, int 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 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)
+ return NULL;
+
+ f->next->prev = f;
+ f = f->next;
+ if (alloc_metrics(s, f) < 0)
+ 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]);
+ }
+
+ 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] - (v + lv) + ABS(v - lv);
+ int rc = f->next->combs[i] - (v + rv) + ABS(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 *, int))
+{
+ 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;
+ PullupField *f;
+ int i;
+
+ f = s->head;
+ while (f) {
+ av_free(f->diffs);
+ av_free(f->combs);
+ av_free(f->vars);
+ if (f == s->last) {
+ av_freep(&s->last);
+ break;
+ }
+ f = f->next;
+ av_freep(&f->prev);
+ };
+
+ 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..3213b4d
--- a/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, int s);
+ int (*comb)(const uint8_t *a, const uint8_t *b, int s);
+ int (*var )(const uint8_t *a, const uint8_t *b, int 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..01a585c
--- a/dev/null
+++ b/libavfilter/vf_removelogo.c
@@ -0,0 +1,581 @@
+/*
+ * 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(sizeof(int **) * (s->max_mask_size + 1));
+ if (!mask)
+ return AVERROR(ENOMEM);
+
+ for (a = 0; a <= s->max_mask_size; a++) {
+ mask[a] = (int **)av_malloc(sizeof(int *) * ((a * 2) + 1));
+ if (!mask[a])
+ return AVERROR(ENOMEM);
+ for (b = -a; b <= a; b++) {
+ mask[a][b + a] = (int *)av_malloc(sizeof(int) * ((a * 2) + 1));
+ if (!mask[a][b + a])
+ 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..e242ee2
--- a/dev/null
+++ b/libavfilter/vf_rotate.c
@@ -0,0 +1,489 @@
+/*
+ * 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"
+
+static const char *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 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 INT_PI 205887 //(M_PI * FIXP)
+
+/**
+ * Compute the sin of a using integer values.
+ * Input 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 third term */
+ a2 = (a*a)/FIXP;
+ for (i = 2; i < 7; i += 2) {
+ res += a;
+ a = -a*a2 / (FIXP*i*(i+1));
+ }
+ return res;
+}
+
+/**
+ * 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;
+}
+
+#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/2;
+ y = yprime + yi + FIXP*inh/2;
+
+ for (i = 0; i < outw; i++) {
+ int32_t v;
+ int x1, y1;
+ uint8_t *pin, *pout;
+ x += c;
+ y -= s;
+ 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;
+ }
+ }
+ }
+ 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;
+ 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/2 * c, .yi = outw/2 * s,
+ .xprime = -outh/2 * s,
+ .yprime = -outh/2 * c,
+ .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..51bbc5a
--- a/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(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 096397f..283c0b7 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,34 +35,33 @@
#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",
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,
VARS_NB
@@ -71,6 +70,8 @@ enum var_name {
typedef struct {
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:
@@ -78,30 +79,79 @@ typedef struct {
* -1 = keep original aspect
*/
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 +160,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)
@@ -133,7 +186,7 @@ static int query_formats(AVFilterContext *ctx)
if (ctx->outputs[0]) {
formats = NULL;
for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++)
- 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);
@@ -145,10 +198,33 @@ 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);
int64_t w, h;
@@ -156,16 +232,14 @@ static int config_props(AVFilterLink *outlink)
char *expr;
int ret;
- 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_DAR] = var_values[VAR_A] = (double) inlink->w / inlink->h;
+ var_values[VAR_A] = (double) inlink->w / inlink->h;
var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ?
(double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
+ var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR];
var_values[VAR_HSUB] = 1 << desc->log2_chroma_w;
var_values[VAR_VSUB] = 1 << desc->log2_chroma_h;
@@ -206,6 +280,19 @@ static int config_props(AVFilterLink *outlink)
if (h == -1)
h = av_rescale(w, inlink->h, inlink->w);
+ 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 ||
(w * inlink->h) > INT_MAX)
@@ -215,49 +302,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);
- 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
+ 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
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);
@@ -275,38 +445,114 @@ 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 = -1}, -1, 512, FLAGS },
+ { "in_h_chr_pos", "input horizontal chroma position in luma grid/256", OFFSET(in_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -1}, -1, 512, FLAGS },
+ { "out_v_chr_pos", "output vertical chroma position in luma grid/256" , OFFSET(out_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -1}, -1, 512, FLAGS },
+ { "out_h_chr_pos", "output horizontal chroma position in luma grid/256", OFFSET(out_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -1}, -1, 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,
+ .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 }
@@ -322,17 +568,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 fc69c89..0000000
--- a/libavfilter/vf_select.c
+++ b/dev/null
@@ -1,362 +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 {
- 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);
- av_log(inlink->dst, AV_LOG_DEBUG,
- "n:%d pts:%d t:%f interlace_type:%c key:%d pict_type:%c "
- "-> select:%f\n",
- (int)select->var_values[VAR_N],
- (int)select->var_values[VAR_PTS],
- select->var_values[VAR_T],
- select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_P ? 'P' :
- select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_T ? 'T' :
- select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_B ? 'B' : '?',
- (int)select->var_values[VAR_KEY],
- av_get_picture_type_char(select->var_values[VAR_PICT_TYPE]),
- res);
-
- 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
--- a/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
--- a/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_settb.c b/libavfilter/vf_settb.c
deleted file mode 100644
index 87b60a7..0000000
--- a/libavfilter/vf_settb.c
+++ b/dev/null
@@ -1,161 +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
- * Set timebase for the output link.
- */
-
-#include <inttypes.h>
-#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/rational.h"
-#include "avfilter.h"
-#include "internal.h"
-#include "video.h"
-
-static const char *const var_names[] = {
- "E",
- "PHI",
- "PI",
- "AVTB", /* default timebase 1/AV_TIME_BASE */
- "intb", /* input timebase */
- NULL
-};
-
-enum var_name {
- VAR_E,
- VAR_PHI,
- VAR_PI,
- VAR_AVTB,
- VAR_INTB,
- VAR_VARS_NB
-};
-
-typedef struct {
- const AVClass *class;
- char *tb_expr;
- double var_values[VAR_VARS_NB];
-} SetTBContext;
-
-static int config_output_props(AVFilterLink *outlink)
-{
- AVFilterContext *ctx = outlink->src;
- SetTBContext *settb = ctx->priv;
- AVFilterLink *inlink = ctx->inputs[0];
- AVRational time_base;
- 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);
-
- outlink->w = inlink->w;
- outlink->h = inlink->h;
-
- if ((ret = av_expr_parse_and_eval(&res, settb->tb_expr, var_names, settb->var_values,
- NULL, NULL, NULL, NULL, NULL, 0, NULL)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Invalid expression '%s' for timebase.\n", settb->tb_expr);
- return ret;
- }
- time_base = av_d2q(res, INT_MAX);
- if (time_base.num <= 0 || time_base.den <= 0) {
- av_log(ctx, AV_LOG_ERROR,
- "Invalid non-positive values for the timebase num:%d or den:%d.\n",
- time_base.num, time_base.den);
- return AVERROR(EINVAL);
- }
-
- outlink->time_base = time_base;
- av_log(outlink->src, AV_LOG_VERBOSE, "tb:%d/%d -> tb:%d/%d\n",
- inlink ->time_base.num, inlink ->time_base.den,
- outlink->time_base.num, outlink->time_base.den);
-
- return 0;
-}
-
-static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
-{
- AVFilterContext *ctx = inlink->dst;
- AVFilterLink *outlink = ctx->outputs[0];
-
- if (av_cmp_q(inlink->time_base, outlink->time_base)) {
- int64_t orig_pts = frame->pts;
- frame->pts = av_rescale_q(frame->pts, inlink->time_base, outlink->time_base);
- av_log(ctx, AV_LOG_DEBUG, "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n",
- inlink ->time_base.num, inlink ->time_base.den, orig_pts,
- outlink->time_base.num, outlink->time_base.den, frame->pts);
- }
-
- return ff_filter_frame(outlink, frame);
-}
-
-#define OFFSET(x) offsetof(SetTBContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "expr", "Expression determining the output timebase", OFFSET(tb_expr), AV_OPT_TYPE_STRING, { .str = "intb" }, .flags = FLAGS },
- { NULL },
-};
-
-static const AVClass settb_class = {
- .class_name = "settb",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-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,
- },
- { NULL }
-};
-
-static const AVFilterPad avfilter_vf_settb_outputs[] = {
- {
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .config_props = config_output_props,
- },
- { NULL }
-};
-
-AVFilter ff_vf_settb = {
- .name = "settb",
- .description = NULL_IF_CONFIG_SMALL("Set timebase for the output link."),
-
- .priv_size = sizeof(SetTBContext),
- .priv_class = &settb_class,
-
- .inputs = avfilter_vf_settb_inputs,
-
- .outputs = avfilter_vf_settb_outputs,
-};
diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c
index e89ffe0..ade3e1a 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
*/
@@ -26,26 +26,25 @@
#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/timestamp.h"
#include "avfilter.h"
#include "internal.h"
#include "video.h"
-typedef struct {
- unsigned int frame;
-} ShowInfoContext;
-
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;
int i, plane, vsub = desc->log2_chroma_h;
- for (plane = 0; frame->data[plane] && plane < 4; plane++) {
- size_t linesize = av_image_get_linesize(frame->format, frame->width, plane);
+ for (plane = 0; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++) {
+ int64_t linesize = av_image_get_linesize(frame->format, frame->width, 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;
+
+ if (linesize < 0)
+ return linesize;
for (i = 0; i < h; i++) {
plane_checksum[plane] = av_adler32_update(plane_checksum[plane], data, linesize);
@@ -55,11 +54,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
}
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:%u plane_checksum:[%u %u %u %u]\n",
- showinfo->frame,
- frame->pts, frame->pts * av_q2d(inlink->time_base),
+ "checksum:%08X plane_checksum:[%08X",
+ 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,
@@ -67,18 +66,20 @@ 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, " %08X", plane_checksum[plane]);
+ 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 }
};
@@ -94,10 +95,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_smartblur.c b/libavfilter/vf_smartblur.c
new file mode 100644
index 0000000..114ac6f
--- a/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 substract '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)
+ /* substract '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 substract '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..683e333
--- a/dev/null
+++ b/libavfilter/vf_spp.c
@@ -0,0 +1,437 @@
+/*
+ * 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 "libavcodec/dsputil.h"
+#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
+};
+
+#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 }
+};
+
+AVFILTER_DEFINE_CLASS(spp);
+
+// 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->dsp.get_pixels(block, p->src + index, linesize);
+ p->dsp.fdct(block);
+ p->requantize(block2, block, qp, p->dsp.idct_permutation);
+ p->dsp.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(spp->temp_linesize * h * sizeof(*spp->temp));
+ spp->src = av_malloc(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(AVFilterContext *ctx)
+{
+ SPPContext *spp = ctx->priv;
+
+ spp->avctx = avcodec_alloc_context3(NULL);
+ if (!spp->avctx)
+ return AVERROR(ENOMEM);
+ avpriv_dsputil_init(&spp->dsp, spp->avctx);
+ 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->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 = init,
+ .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..c4293b6
--- a/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/dsputil.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;
+ DSPContext dsp;
+ 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
--- a/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..e44f61d
--- a/dev/null
+++ b/libavfilter/vf_subtitles.c
@@ -0,0 +1,366 @@
+/*
+ * 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;
+ uint8_t rgba_map[4];
+ int pix_step[4]; ///< steps per pixel for each plane of the main output
+ int original_w, original_h;
+ 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[] = {
+ AV_LOG_QUIET, /* 0 */
+ AV_LOG_PANIC, /* 1 */
+ AV_LOG_FATAL, /* 2 */
+ AV_LOG_ERROR, /* 3 */
+ AV_LOG_WARNING, /* 4 */
+ AV_LOG_INFO, /* 5 */
+ AV_LOG_VERBOSE, /* 6 */
+ AV_LOG_DEBUG, /* 7 */
+};
+
+static void ass_log(int ass_level, const char *fmt, va_list args, void *ctx)
+{
+ int level = ass_libavfilter_log_level_map[ass_level];
+
+ 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);
+ }
+
+ ass_set_fonts(ass->renderer, NULL, NULL, 1, NULL, 1);
+ 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);
+
+ 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
+ {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;
+
+ 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},
+ {NULL},
+};
+
+AVFILTER_DEFINE_CLASS(subtitles);
+
+static av_cold int init_subtitles(AVFilterContext *ctx)
+{
+ int ret, sid;
+ 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 */
+ ret = av_find_best_stream(fmt, AVMEDIA_TYPE_SUBTITLE, -1, -1, NULL, 0);
+ 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];
+
+ /* 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
--- a/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..71ae243
--- a/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; fmt < AV_PIX_FMT_NB; 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..811ae27
--- a/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; fmt < AV_PIX_FMT_NB; 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
--- a/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..786f4f6
--- a/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,
+ (AVRational){ 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..9c1b848
--- a/dev/null
+++ b/libavfilter/vf_tinterlace.c
@@ -0,0 +1,384 @@
+/*
+ * 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 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;
+ }
+ 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);
+ 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 ((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;
+
+ /* 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 06a88c7..7e471d4 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
*/
@@ -37,6 +37,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,
@@ -49,36 +55,26 @@ typedef struct {
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; fmt < AV_PIX_FMT_NB; 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;
}
@@ -90,6 +86,23 @@ static int config_props_output(AVFilterLink *outlink)
const AVPixFmtDescriptor *desc_out = av_pix_fmt_desc_get(outlink->format);
const AVPixFmtDescriptor *desc_in = av_pix_fmt_desc_get(inlink->format);
+ if (trans->dir&4) {
+ av_log(ctx, AV_LOG_WARNING,
+ "dir values greater than 3 are deprecated, use the passthrough option instead\n");
+ trans->dir &= 3;
+ trans->passthrough = TRANSPOSE_PT_TYPE_LANDSCAPE;
+ }
+
+ if ((inlink->w >= inlink->h && trans->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) ||
+ (inlink->w <= inlink->h && trans->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) {
+ av_log(ctx, AV_LOG_VERBOSE,
+ "w:%d h:%d -> w:%d h:%d (passthrough mode)\n",
+ inlink->w, inlink->h, inlink->w, inlink->h);
+ return 0;
+ } else {
+ trans->passthrough = TRANSPOSE_PT_TYPE_NONE;
+ }
+
trans->hsub = desc_in->log2_chroma_w;
trans->vsub = desc_in->log2_chroma_h;
@@ -110,41 +123,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 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];
@@ -154,63 +169,114 @@ 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,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .get_video_buffer = get_video_buffer,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -225,14 +291,12 @@ static const AVFilterPad avfilter_vf_transpose_outputs[] = {
};
AVFilter ff_vf_transpose = {
- .name = "transpose",
- .description = NULL_IF_CONFIG_SMALL("Transpose input video."),
-
- .priv_size = sizeof(TransContext),
- .priv_class = &transpose_class,
-
+ .name = "transpose",
+ .description = NULL_IF_CONFIG_SMALL("Transpose input video."),
+ .priv_size = sizeof(TransContext),
+ .priv_class = &transpose_class,
.query_formats = query_formats,
-
- .inputs = avfilter_vf_transpose_inputs,
- .outputs = avfilter_vf_transpose_outputs,
+ .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 842ec7e..b9f6821 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 {
- 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,48 @@ 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(sizeof(*(fp->sc[z])) * (width + 2 * fp->steps_x))))
+ 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 +221,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 +234,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 +242,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 +299,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 ced946e..f6908e4 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..b2977ff
--- a/dev/null
+++ b/libavfilter/vf_vidstabdetect.c
@@ -0,0 +1,217 @@
+/*
+ * 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 = 9}, 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;
+ vs_set_mem_and_log_functions();
+ 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, av_2_vs_pixel_format(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, " 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) {
+ av_log(ctx, AV_LOG_ERROR, "cannot write to transform file");
+ return AVERROR(errno);
+ }
+ 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..3c0a5ee
--- a/dev/null
+++ b/libavfilter/vf_vidstabtransform.c
@@ -0,0 +1,291 @@
+/*
+ * 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;
+} 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", "path to the file storing the transforms", OFFSET(input),
+ AV_OPT_TYPE_STRING, {.str = DEFAULT_INPUT_NAME}, .flags = FLAGS },
+ {"smoothing", "number of frames*2 + 1 used for lowpass filtering", OFFSETC(smoothing),
+ AV_OPT_TYPE_INT, {.i64 = 10}, 1, 1000, FLAGS},
+ {"maxshift", "maximal number of pixels to translate image", OFFSETC(maxShift),
+ AV_OPT_TYPE_INT, {.i64 = -1}, -1, 500, FLAGS},
+ {"maxangle", "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", "1: invert transforms", OFFSETC(invert),
+ AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS},
+ {"relative", "consider transforms as 0: absolute, 1: relative", OFFSETC(relative),
+ AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, FLAGS},
+ {"zoom", "percentage to zoom >0: zoom in, <0 zoom out", OFFSETC(zoom),
+ AV_OPT_TYPE_DOUBLE, {.dbl = 0}, -100, 100, FLAGS},
+ {"optzoom", "0: nothing, 1: determine optimal zoom (added to 'zoom')", OFFSETC(optZoom),
+ AV_OPT_TYPE_INT, {.i64 = 1}, 0, 2, FLAGS},
+ {"interpol", "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", "if 1: virtual tripod mode (equiv. to relative=0:smoothing=0)", OFFSET(tripod),
+ 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;
+ vs_set_mem_and_log_functions();
+ 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,
+ av_2_vs_pixel_format(ctx, inlink->format)) ||
+ !vsFrameInfoInit(&fi_dest, inlink->w, inlink->h,
+ av_2_vs_pixel_format(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;
+ if (tc->tripod) {
+ av_log(ctx, AV_LOG_INFO, "Virtual tripod mode: relative=0, smoothing=0");
+ tc->conf.relative = 0;
+ tc->conf.smoothing = 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, " 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 ? "On" : "Off");
+ av_log(ctx, AV_LOG_INFO, " interpol = %s\n", getInterpolationTypeName(tc->conf.interpolType));
+
+ f = fopen(tc->input, "r");
+ if (f == NULL) {
+ av_log(ctx, AV_LOG_ERROR, "cannot open input file %s\n", tc->input);
+ return AVERROR(errno);
+ } else {
+ VSManyLocalMotions mlms;
+ if (vsReadLocalMotionsFile(f, &mlms) == VS_OK) {
+ // calculate the actual transforms from the local motions
+ if (vsLocalmotions2TransformsSimple(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..8ce7b7e
--- a/dev/null
+++ b/libavfilter/vf_vignette.c
@@ -0,0 +1,339 @@
+/*
+ * 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;
+ AVFilterContext *ctx = inlink->dst;
+ VignetteContext *s = ctx->priv;
+ AVFilterLink *outlink = inlink->dst->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 (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;
+ }
+ }
+ }
+
+ 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(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
--- a/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_yadif.c b/libavfilter/vf_yadif.c
index fb5d641..7ffce9a 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 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.
*/
+#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);
@@ -322,7 +328,20 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame)
if (!yadif->cur)
return 0;
- 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);
@@ -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)
@@ -386,41 +405,13 @@ static int request_frame(AVFilterLink *link)
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"),
+
+ { "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"),
-static const AVClass yadif_class = {
- .class_name = "yadif",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
+ { "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/video.c b/libavfilter/video.c
index 23bf867..74c9161 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));
@@ -106,7 +111,7 @@ AVFrame *ff_get_video_buffer(AVFilterLink *link, int w, int h)
AVFrame *ret = NULL;
av_unused char buf[16];
- 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..dd6486d
--- a/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 av_2_vs_pixel_format(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 vs_2_av_log_wrapper(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 vs_set_mem_and_log_functions(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 = vs_2_av_log_wrapper;
+
+ VS_ERROR = 0;
+ VS_OK = 1;
+}
diff --git a/libavfilter/vidstabutils.h b/libavfilter/vidstabutils.h
new file mode 100644
index 0000000..f1c20e6
--- a/dev/null
+++ b/libavfilter/vidstabutils.h
@@ -0,0 +1,36 @@
+/*
+ * 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"
+
+/* ** some conversions from avlib to vid.stab constants and functions *** */
+
+/** converts the pixelformat of avlib into the one of the vid.stab library */
+VSPixelFormat av_2_vs_pixel_format(AVFilterContext *ctx, enum AVPixelFormat pf);
+
+/** sets the memory allocation function and logging constants to av versions */
+void vs_set_mem_and_log_functions(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..95eabc1
--- a/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(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(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 d72d072..0000000
--- a/libavfilter/vsrc_color.c
+++ b/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 {
- 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
--- a/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..19dddf9
--- a/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(sizeof(*mb->point_cache)*mb->cache_allocated);
+ mb-> next_cache= av_malloc(sizeof(*mb-> next_cache)*mb->cache_allocated);
+ mb-> zyklus = av_malloc(sizeof(*mb->zyklus) * (mb->maxiter+16));
+
+ 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 3e9f41d..0000000
--- a/libavfilter/vsrc_movie.c
+++ b/dev/null
@@ -1,285 +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 "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 {
- 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;
- AVStream av_unused *st = movie->format_ctx->streams[movie->stream_index];
-
- 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(st->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
--- a/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 f7766fa..0000000
--- a/libavfilter/vsrc_nullsrc.c
+++ b/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 {
- 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 9e12852..0ad1474 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 {
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..6a252b4 100644
--- a/libavfilter/x86/Makefile
+++ b/libavfilter/x86/Makefile
@@ -1,9 +1,12 @@
OBJS-$(CONFIG_GRADFUN_FILTER) += x86/vf_gradfun_init.o
OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d_init.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_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 b661a9a..674f60a 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
*/
@@ -27,10 +27,11 @@
#include "libavfilter/gradfun.h"
#if HAVE_YASM
-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);
-static void gradfun_filter_line_mmxext(uint8_t *dst, uint8_t *src, uint16_t *dc,
+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)
{
@@ -45,10 +46,10 @@ static void gradfun_filter_line_mmxext(uint8_t *dst, uint8_t *src, uint16_t *dc,
thresh, 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);
-static void gradfun_filter_line_ssse3(uint8_t *dst, uint8_t *src, uint16_t *dc, int width, int thresh, const uint16_t *dithers)
+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)
{
intptr_t x;
if (width & 7) {
@@ -62,9 +63,9 @@ static void gradfun_filter_line_ssse3(uint8_t *dst, uint8_t *src, uint16_t *dc,
thresh, 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);
-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);
-static void gradfun_blur_line_sse2(uint16_t *dc, uint16_t *buf, uint16_t *buf1, uint8_t *src, int src_linesize, int width)
+void ff_gradfun_blur_line_movdqa_sse2(intptr_t x, uint16_t *buf, 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, const uint16_t *buf1, uint16_t *dc, const uint8_t *src1, const uint8_t *src2);
+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 2893a54..4abb878 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_pullup.asm b/libavfilter/x86/vf_pullup.asm
new file mode 100644
index 0000000..3689b04
--- a/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 r4, 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, [secondq]
+ 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 r4, 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 r4, 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..9948abf
--- a/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, int s);
+int ff_pullup_filter_comb_mmx(const uint8_t *a, const uint8_t *b, int s);
+int ff_pullup_filter_var_mmx (const uint8_t *a, const uint8_t *b, int 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
--- a/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 bc4b3ce..ebc505c 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 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.
;******************************************************************************
@@ -90,17 +90,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 +109,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 +119,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 +166,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 +220,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 5978a4f..ae09bb0 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 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.
*/
#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,18 +35,65 @@ 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)
{
#if HAVE_YASM
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;
+ }
#endif /* HAVE_YASM */
}
diff --git a/libavfilter/x86/yadif-10.asm b/libavfilter/x86/yadif-10.asm
new file mode 100644
index 0000000..d586deb
--- a/dev/null
+++ b/libavfilter/x86/yadif-10.asm
@@ -0,0 +1,282 @@
+;*****************************************************************************
+;* 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 General Public License as published by
+;* the Free Software Foundation; either version 2 of the License, or
+;* (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;* GNU General Public License for more details.
+;*
+;* You should have received a copy of the GNU General Public License along
+;* with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+;* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+
+pw_1: times 8 dw 1
+
+SECTION .text
+
+%macro PABS 2
+%if cpuflag(ssse3)
+ pabsw %1, %1
+%else
+ pxor %2, %2
+ pcmpgtw %2, %1
+ pxor %1, %2
+ psubw %1, %2
+%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
+%if mmsize == 16
+ psrldq m5, 2
+%else
+ psrlq m5, 16
+%endif
+ mova m4, m2
+ psubusw m2, m3
+ psubusw m3, m4
+ PMAXUW m2, m3
+ mova m3, m2
+ mova m4, m2
+%if mmsize == 16
+ psrldq m3, 2
+ psrldq m4, 4
+%else
+ psrlq m3, 16
+ psrlq m4, 32
+%endif
+ 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
+ PABS m2, m4
+ LOAD m3, [prevq+t1]
+ LOAD m4, [prevq+t0]
+ psubw m3, m0
+ psubw m4, m1
+ PABS m3, m5
+ PABS m4, m5
+ 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
+ PABS m3, m5
+ PABS m4, m5
+ 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
+ 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
+%if mmsize == 16
+ mova m3, m2
+ psrldq m3, 4
+%else
+ mova m3, m2
+ psrlq m3, 32
+%endif
+ 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..a2e6006
--- a/dev/null
+++ b/libavfilter/x86/yadif-16.asm
@@ -0,0 +1,347 @@
+;*****************************************************************************
+;* 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 General Public License as published by
+;* the Free Software Foundation; either version 2 of the License, or
+;* (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;* GNU General Public License for more details.
+;*
+;* You should have received a copy of the GNU General Public License along
+;* with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+;* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+
+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 PIXSHIFT1 1
+%if cpuflag(sse2)
+ psrldq %1, 2
+%else
+ psrlq %1, 16
+%endif
+%endmacro
+
+%macro PIXSHIFT2 1
+%if cpuflag(sse2)
+ psrldq %1, 4
+%else
+ psrlq %1, 32
+%endif
+%endmacro
+
+%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
+%if mmsize == 16
+ psrldq m5, 2
+%else
+ psrlq m5, 16
+%endif
+ punpcklwd m5, m7
+ mova m4, m2
+ psubusw m2, m3
+ psubusw m3, m4
+ PMAXUW m2, m3
+ mova m3, m2
+ mova m4, m2
+%if mmsize == 16
+ psrldq m3, 2
+ psrldq m4, 4
+%else
+ psrlq m3, 16
+ psrlq m4, 32
+%endif
+ 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 intruction 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
+%if mmsize == 16
+ mova m3, m2
+ psrldq m3, 4
+%else
+ mova m3, m2
+ psrlq m3, 32
+%endif
+ 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 6936723..3ddf005 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 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.
*/
@@ -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 7a87c36..6e63c67 100644
--- a/libavformat/4xm.c
+++ b/libavformat/4xm.c
@@ -2,20 +2,20 @@
* 4X Technologies .4xm File Demuxer (no muxer)
* 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
*/
@@ -131,8 +131,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);
@@ -152,6 +155,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)
@@ -219,9 +227,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;
}
@@ -277,7 +290,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 (url_feof(pb))
return AVERROR(EIO);
switch (fourcc_tag) {
case LIST_TAG:
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 9bc9cdf..ff92a4c 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -1,3 +1,5 @@
+include $(SUBDIR)../config.mak
+
NAME = avformat
FFLIBS = avcodec avutil
@@ -12,7 +14,6 @@ OBJS = allformats.o \
format.o \
id3v1.o \
id3v2.o \
- log2_tab.o \
metadata.o \
mux.o \
options.o \
@@ -51,47 +52,66 @@ 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
# 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
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_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
+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_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) += daud.o
OBJS-$(CONFIG_DAUD_MUXER) += daud.o
OBJS-$(CONFIG_DFA_DEMUXER) += dfa.o
@@ -100,6 +120,7 @@ OBJS-$(CONFIG_DIRAC_MUXER) += rawenc.o
OBJS-$(CONFIG_DNXHD_DEMUXER) += dnxhddec.o rawdec.o
OBJS-$(CONFIG_DNXHD_MUXER) += rawenc.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
@@ -109,6 +130,7 @@ 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
@@ -127,22 +149,30 @@ 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
OBJS-$(CONFIG_H263_MUXER) += rawenc.o
OBJS-$(CONFIG_H264_DEMUXER) += h264dec.o rawdec.o
OBJS-$(CONFIG_H264_MUXER) += rawenc.o
+OBJS-$(CONFIG_HEVC_DEMUXER) += hevcdec.o rawdec.o
OBJS-$(CONFIG_HLS_DEMUXER) += hls.o
OBJS-$(CONFIG_HLS_MUXER) += hlsenc.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,14 +182,20 @@ OBJS-$(CONFIG_IMAGE2PIPE_DEMUXER) += img2dec.o img2.o
OBJS-$(CONFIG_IMAGE2PIPE_MUXER) += img2enc.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_LVF_DEMUXER) += lvfdec.o
OBJS-$(CONFIG_LXF_DEMUXER) += lxfdec.o
OBJS-$(CONFIG_M4V_DEMUXER) += m4vdec.o rawdec.o
OBJS-$(CONFIG_M4V_MUXER) += rawenc.o
@@ -169,16 +205,19 @@ OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \
isom.o avc.o \
flacenc_header.o avlanguage.o wv.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_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
OBJS-$(CONFIG_MOV_MUXER) += movenc.o isom.o avc.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
OBJS-$(CONFIG_MP3_MUXER) += mp3enc.o rawenc.o id3v2enc.o
@@ -196,13 +235,17 @@ 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_MVI_DEMUXER) += mvi.o
+OBJS-$(CONFIG_MV_DEMUXER) += mvdec.o
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
@@ -224,6 +267,7 @@ 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_PAF_DEMUXER) += paf.o
OBJS-$(CONFIG_PCM_ALAW_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_ALAW_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_F32BE_DEMUXER) += pcmdec.o pcm.o
@@ -264,17 +308,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
@@ -295,8 +344,10 @@ 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_SEGAFILM_DEMUXER) += segafilm.o
OBJS-$(CONFIG_SEGMENT_MUXER) += segment.o
@@ -306,46 +357,61 @@ OBJS-$(CONFIG_SMACKER_DEMUXER) += smacker.o
OBJS-$(CONFIG_SMJPEG_DEMUXER) += smjpegdec.o smjpeg.o
OBJS-$(CONFIG_SMJPEG_MUXER) += smjpegenc.o smjpeg.o
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_SRT_DEMUXER) += srtdec.o subtitles.o
+OBJS-$(CONFIG_SRT_MUXER) += srtenc.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_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_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 \
flacenc_header.o avlanguage.o wv.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 asf.o asfenc.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
@@ -353,15 +419,25 @@ OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg.o
OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpeg.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
# 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
@@ -387,10 +463,6 @@ OBJS-$(CONFIG_UNIX_PROTOCOL) += unix.o
SKIPHEADERS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh.h
SKIPHEADERS-$(CONFIG_NETWORK) += network.h rtsp.h
-
-EXAMPLES = metadata \
- output \
-
TESTPROGS = seek \
srtp \
url \
@@ -401,6 +473,4 @@ TOOLS = aviocat \
ismindex \
pktdumper \
probetest \
-
-$(SUBDIR)output-example$(EXESUF): ELIBS = $(patsubst %,$(LD_LIB),swscale avutil)
-$(SUBDIR)output-example$(EXESUF): $(call PATH_LIBNAME,swscale)
+ seek_print \
diff --git a/libavformat/a64.c b/libavformat/a64.c
index 15a0475..786c75c 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"
diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c
index 8d87ce6..d93e75e 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,16 +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;
@@ -48,6 +48,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);
@@ -71,9 +72,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..3db2339 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,7 +27,7 @@
static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id)
{
int max_frames, first_frames = 0, frames;
- uint8_t *buf, *buf2, *end;
+ const uint8_t *buf, *buf2, *end;
AC3HeaderInfo hdr;
GetBitContext gbc;
enum AVCodecID codec_id = AV_CODEC_ID_AC3;
@@ -37,14 +37,36 @@ 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);
+ 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_header(&gbc, &hdr) < 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 + hdr.frame_size > end)
+ break;
+ if (buf[0] == 0x77 && buf[1] == 0x0B) {
+ av_assert0(hdr.frame_size <= sizeof(buf3));
+ for(i=8; i<hdr.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, hdr.frame_size - 2))
break;
if (hdr.bitstream_id > 10)
codec_id = AV_CODEC_ID_EAC3;
@@ -57,31 +79,11 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id)
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
--- a/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..c5feac4
--- a/dev/null
+++ b/libavformat/adp.c
@@ -0,0 +1,91 @@
+/*
+ * 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;
+
+ 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;
+
+ 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 (url_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 e7c9ca6..f25f966 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,16 +24,20 @@
#include "libavcodec/put_bits.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/mpeg4audio.h"
+#include "libavutil/opt.h"
#include "avformat.h"
+#include "apetag.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;
uint8_t pce_data[MAX_PCE_SIZE];
} ADTSContext;
@@ -162,6 +166,30 @@ 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_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,4 +200,6 @@ 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,
};
diff --git a/libavformat/adxdec.c b/libavformat/adxdec.c
index 49e1930..0a0436f 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
*/
@@ -78,8 +78,7 @@ 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_alloc_extradata(avctx, c->header_size))
return AVERROR(ENOMEM);
if (avio_read(s->pb, avctx->extradata, c->header_size) < c->header_size) {
av_freep(&avctx->extradata);
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
--- a/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..6f82d93 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 (url_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);
+ 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,32 @@ 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_alloc_extradata(st->codec, size))
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,7 +345,7 @@ static int aiff_read_packet(AVFormatContext *s,
return AVERROR_EOF;
/* Now for that packet */
- if (st->codec->block_align >= 33) // GSM, QCLP, IMA4
+ if (st->codec->block_align >= 17) // GSM, QCLP, IMA4
size = st->codec->block_align;
else
size = (MAX_SIZE / st->codec->block_align) * st->codec->block_align;
@@ -314,6 +354,8 @@ static int aiff_read_packet(AVFormatContext *s,
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 abcc424..7c0b4fb 100644
--- a/libavformat/aiffenc.c
+++ b/libavformat/aiffenc.c
@@ -2,42 +2,124 @@
* 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 "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);
+
+ 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)
@@ -52,7 +134,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;
@@ -63,6 +144,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 */
@@ -91,6 +183,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 */
@@ -98,7 +196,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);
@@ -108,16 +207,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;
@@ -128,10 +265,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);
@@ -143,12 +276,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"),
@@ -156,9 +323,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 d72a127..20f48c0 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
*/
@@ -63,43 +63,58 @@ 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 (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 (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);
@@ -110,16 +125,21 @@ void av_register_all(void)
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);
REGISTER_MUXDEMUX(H263, h263);
REGISTER_MUXDEMUX(H264, h264);
+ REGISTER_DEMUXER (HEVC, hevc);
REGISTER_MUXDEMUX(HLS, hls);
+ REGISTER_MUXDEMUX(ICO, ico);
REGISTER_DEMUXER (IDCIN, idcin);
+ REGISTER_DEMUXER (IDF, idf);
REGISTER_DEMUXER (IFF, iff);
REGISTER_MUXDEMUX(ILBC, ilbc);
REGISTER_MUXDEMUX(IMAGE2, image2);
@@ -127,18 +147,24 @@ void av_register_all(void)
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_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 (MM, mm);
@@ -161,19 +187,24 @@ void av_register_all(void)
REGISTER_DEMUXER (MPEGTSRAW, mpegtsraw);
REGISTER_DEMUXER (MPEGVIDEO, mpegvideo);
REGISTER_MUXER (MPJPEG, mpjpeg);
+ REGISTER_DEMUXER (MPL2, mpl2);
+ REGISTER_DEMUXER (MPSUB, mpsub);
REGISTER_DEMUXER (MSNWC_TCP, msnwc_tcp);
REGISTER_DEMUXER (MTV, mtv);
+ REGISTER_DEMUXER (MV, mv);
REGISTER_DEMUXER (MVI, mvi);
REGISTER_MUXDEMUX(MXF, mxf);
REGISTER_MUXER (MXF_D10, mxf_d10);
REGISTER_DEMUXER (MXG, mxg);
REGISTER_DEMUXER (NC, nc);
+ REGISTER_DEMUXER (NISTSPHERE, nistsphere);
REGISTER_DEMUXER (NSV, nsv);
REGISTER_MUXER (NULL, null);
REGISTER_MUXDEMUX(NUT, nut);
REGISTER_DEMUXER (NUV, nuv);
REGISTER_MUXDEMUX(OGG, ogg);
REGISTER_MUXDEMUX(OMA, oma);
+ REGISTER_DEMUXER (PAF, paf);
REGISTER_MUXDEMUX(PCM_ALAW, pcm_alaw);
REGISTER_MUXDEMUX(PCM_MULAW, pcm_mulaw);
REGISTER_MUXDEMUX(PCM_F64BE, pcm_f64be);
@@ -194,20 +225,27 @@ 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);
#if CONFIG_RTPDEC
ff_register_rtp_dynamic_payload_handlers();
@@ -215,52 +253,68 @@ void av_register_all(void)
#endif
REGISTER_DEMUXER (SEGAFILM, segafilm);
REGISTER_MUXER (SEGMENT, segment);
+ REGISTER_MUXER (SEGMENT, stream_segment);
REGISTER_DEMUXER (SHORTEN, shorten);
REGISTER_DEMUXER (SIFF, siff);
REGISTER_DEMUXER (SMACKER, smacker);
REGISTER_MUXDEMUX(SMJPEG, smjpeg);
REGISTER_MUXER (SMOOTHSTREAMING, smoothstreaming);
+ REGISTER_DEMUXER (SMUSH, smush);
REGISTER_DEMUXER (SOL, sol);
REGISTER_MUXDEMUX(SOX, sox);
REGISTER_MUXDEMUX(SPDIF, spdif);
REGISTER_MUXDEMUX(SRT, srt);
REGISTER_DEMUXER (STR, str);
+ REGISTER_DEMUXER (SUBVIEWER1, subviewer1);
+ REGISTER_DEMUXER (SUBVIEWER, subviewer);
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_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(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);
/* 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);
@@ -285,9 +339,14 @@ void av_register_all(void)
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);
}
diff --git a/libavformat/amr.c b/libavformat/amr.c
index 3b1a468..db9bb4e 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
*/
@@ -26,6 +26,7 @@ Only mono files are supported.
*/
+#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "avformat.h"
#include "internal.h"
@@ -111,7 +112,7 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt)
int read, size = 0, toc, mode;
int64_t pos = avio_tell(s->pb);
- if (s->pb->eof_reached) {
+ if (url_feof(s->pb)) {
return AVERROR(EIO);
}
@@ -131,8 +132,6 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt)
};
size = packed_size[mode];
- } else {
- assert(0);
}
if (!size || av_new_packet(pkt, size))
diff --git a/libavformat/anm.c b/libavformat/anm.c
index f781492..1c58575 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 (url_feof(s->pb))
return AVERROR(EIO);
if (anm->page < 0)
diff --git a/libavformat/apc.c b/libavformat/apc.c
index 0b6c583..08ae935 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,10 +52,7 @@ 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)
+ if (ff_alloc_extradata(st->codec, 2 * 4))
return AVERROR(ENOMEM);
/* initial predictor values for adpcm decoder */
@@ -82,6 +80,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..613a59d 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 {
@@ -172,14 +170,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,7 +256,7 @@ 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,
@@ -340,7 +338,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 +351,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 +364,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 +383,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 (url_feof(s->pb))
return AVERROR_EOF;
if (ape->currentframe >= ape->totalframes)
return AVERROR_EOF;
@@ -413,6 +411,8 @@ 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)
+ return ret;
pkt->pts = ape->frames[ape->currentframe].pts;
pkt->stream_index = 0;
diff --git a/libavformat/apetag.c b/libavformat/apetag.c
index d4be91c..a376a0b 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
*/
@@ -27,8 +27,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)
@@ -90,14 +88,13 @@ 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_alloc_extradata(st->codec, size))
return AVERROR(ENOMEM);
if (avio_read(pb, st->codec->extradata, size) != size) {
av_freep(&st->codec->extradata);
+ st->codec->extradata_size = 0;
return AVERROR(EIO);
}
- st->codec->extradata_size = size;
st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT;
}
} else {
@@ -130,7 +127,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;
}
@@ -172,43 +169,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;
+
+ if (!string_is_ascii(e->key)) {
+ av_log(s, AV_LOG_WARNING, "Non ASCII keys are not allowed\n");
+ continue;
+ }
- 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
+ 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
@@ -216,12 +231,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..810f95b
--- a/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 (!url_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..904d348 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,21 @@
#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 ds_span; /* descrambling */
int ds_packet_size;
@@ -47,6 +54,9 @@ typedef struct ASFStream {
int palette_changed;
uint32_t palette[256];
+
+ int payload_ext_ct;
+ ASFPayload payload[8];
} ASFStream;
typedef struct ASFMainHeader {
@@ -178,4 +188,6 @@ extern const AVMetadataConv ff_asf_metadata_conv[];
extern AVInputFormat ff_asf_demuxer;
+void ff_put_guid(AVIOContext *s, const ff_asf_guid *g);
+
#endif /* AVFORMAT_ASF_H */
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 5b4366e..528bcbd 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
*/
@@ -68,7 +68,6 @@ typedef struct {
unsigned int packet_frag_size;
int64_t packet_frag_timestamp;
int packet_multi_size;
- int packet_obj_size;
int packet_time_delta;
int packet_time_start;
int64_t packet_pos;
@@ -96,12 +95,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) */
@@ -127,7 +122,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);
@@ -281,16 +276,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);
@@ -302,7 +301,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;
@@ -367,17 +366,12 @@ 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) < 10000)
+ st->duration = asf->hdr.play_time /
(10000000 / 1000) - start_time;
}
ff_get_guid(pb, &g);
@@ -405,6 +399,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);
@@ -430,7 +425,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)
@@ -467,9 +462,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);
}
@@ -538,8 +535,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);
@@ -548,10 +547,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;
@@ -715,12 +722,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);
@@ -737,7 +748,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)
@@ -768,19 +779,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 (url_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");
}
}
}
@@ -794,8 +816,8 @@ static int asf_read_header(AVFormatContext *s)
avio_rl64(pb);
avio_r8(pb);
avio_r8(pb);
- if (pb->eof_reached)
- return -1;
+ if (url_feof(pb))
+ return AVERROR_EOF;
asf->data_offset = avio_tell(pb);
asf->packet_size_left = 0;
@@ -894,20 +916,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 (!url_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 (!url_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(!url_feof(pb)) {
avio_seek(pb, -1, SEEK_CUR); // FIXME
}
@@ -923,12 +945,12 @@ static int asf_get_packet(AVFormatContext *s, AVIOContext *pb)
av_log(s, AV_LOG_ERROR,
"invalid packet_length %d 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 %d at:%"PRId64"\n", padsize, avio_tell(pb));
- return -1;
+ return AVERROR_INVALIDDATA;
}
asf->packet_timestamp = avio_rl32(pb);
@@ -948,7 +970,7 @@ static int asf_get_packet(AVFormatContext *s, AVIOContext *pb)
av_log(s, AV_LOG_ERROR,
"invalid packet header length %d for pktlen %d-%d 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)
@@ -966,13 +988,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);
@@ -980,26 +1005,62 @@ 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;
+ 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
@@ -1012,18 +1073,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;
@@ -1031,16 +1092,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;
@@ -1062,8 +1119,7 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
ASFStream *asf_st = 0;
for (;;) {
int ret;
-
- if (pb->eof_reached)
+ if (url_feof(pb))
return AVERROR_EOF;
if (asf->packet_size_left < FRAME_HEADER_SIZE ||
@@ -1088,7 +1144,7 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
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);
@@ -1098,7 +1154,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);
@@ -1107,37 +1164,30 @@ 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) {
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);
+ av_new_packet(&asf_st->pkt, asf_st->packet_obj_size);
asf_st->seq = asf->packet_seq;
asf_st->pkt.dts = asf->packet_frag_timestamp - asf->hdr.preroll;
asf_st->pkt.stream_index = asf->stream_index;
@@ -1158,7 +1208,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)
@@ -1313,21 +1363,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);
@@ -1338,6 +1401,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;
@@ -1353,11 +1417,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;
}
@@ -1368,8 +1434,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;
@@ -1392,17 +1457,21 @@ static void 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;
- avio_seek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET);
+ if(avio_seek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET) < 0) {
+ asf->index_read= -1;
+ return;
+ }
+
ff_get_guid(s->pb, &g);
/* 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 || url_feof(s->pb)) {
avio_seek(s->pb, current_pos, SEEK_SET);
+ asf->index_read= -1;
return;
}
avio_skip(s->pb, gsize - 24);
@@ -1412,6 +1481,7 @@ static void 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);
ff_get_guid(s->pb, &g);
itime = avio_rl64(s->pb);
@@ -1434,7 +1504,7 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index)
last_pos = pos;
}
}
- asf->index_read = ict > 0;
+ asf->index_read = ict > 1;
}
avio_seek(s->pb, current_pos, SEEK_SET);
}
@@ -1444,8 +1514,6 @@ 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;
if (s->packet_size <= 0)
return -1;
@@ -1462,16 +1530,18 @@ static int asf_read_seek(AVFormatContext *s, int stream_index,
if (!asf->index_read)
asf_build_simple_index(s, stream_index);
- if ((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;
}
}
@@ -1479,6 +1549,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 e1a7189..b4a3ffb 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,7 @@
#define ASF_INDEXED_INTERVAL 10000000
-#define ASF_INDEX_BLOCK 600
+#define ASF_INDEX_BLOCK (1<<9)
#define ASF_PACKET_ERROR_CORRECTION_DATA_SIZE 0x2
#define ASF_PACKET_ERROR_CORRECTION_FLAGS \
@@ -195,33 +196,36 @@ 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)
+void ff_put_guid(AVIOContext *s, const ff_asf_guid *g)
{
- assert(sizeof(*g) == 16);
+ av_assert0(sizeof(*g) == 16);
avio_write(s, *g, sizeof(*g));
}
@@ -245,7 +249,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 +297,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 +315,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
@@ -386,7 +390,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
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 +399,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));
@@ -411,7 +415,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
/* unknown headers */
hpos = put_header(pb, &ff_asf_head1_guid);
- put_guid(pb, &ff_asf_head2_guid);
+ ff_put_guid(pb, &ff_asf_head2_guid);
avio_wl32(pb, 6);
avio_wl16(pb, 0);
end_header(pb, hpos);
@@ -460,7 +464,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 +482,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);
@@ -529,7 +533,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++) {
AVCodec *p;
@@ -599,9 +603,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); /* ??? */
@@ -615,10 +619,8 @@ static int asf_write_header(AVFormatContext *s)
s->packet_size = PACKET_SIZE;
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
@@ -637,6 +639,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;
}
@@ -663,7 +668,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++)
@@ -702,20 +707,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);
@@ -730,7 +734,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;
@@ -753,7 +757,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
@@ -761,7 +765,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,16 +827,59 @@ static void put_frame(AVFormatContext *s, ASFStream *stream, AVStream *avst,
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;
@@ -842,41 +889,26 @@ 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;
}
@@ -886,9 +918,9 @@ static int asf_write_index(AVFormatContext *s, ASFIndex *index,
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);
@@ -904,6 +936,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)
@@ -911,8 +944,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) {
@@ -924,7 +960,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;
}
@@ -935,7 +971,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,
@@ -954,7 +990,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 0041ca4..35fcb51 100644
--- a/libavformat/assdec.c
+++ b/libavformat/assdec.c
@@ -2,37 +2,34 @@
* SSA/ASS demuxer
* 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/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;
}ASSContext;
-static int probe(AVProbeData *p)
+static int ass_probe(AVProbeData *p)
{
const char *header= "[Script Info]";
@@ -43,174 +40,130 @@ static int probe(AVProbeData *p)
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_ts(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;
+ int64_t end;
+ int hh1, mm1, ss1, ms1;
+ int hh2, mm2, ss2, ms2;
+
+ if (sscanf(p, "%*[^,],%d:%d:%d%*c%d,%d:%d:%d%*c%d",
+ &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 event_cmp(const void *_a, const void *_b)
+static int64_t get_line(AVBPrint *buf, AVIOContext *pb)
{
- const uint8_t *const *a = _a, *const *b = _b;
- return get_pts(*a) - get_pts(*b);
+ int64_t pos = avio_tell(pb);
+
+ av_bprint_clear(buf);
+ for (;;) {
+ char c = avio_r8(pb);
+ 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;
+ int header_remaining, res = 0;
AVStream *st;
- int allocated[2]={0};
- uint8_t *p, **dst[2]={0};
- int pos[2]={0};
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;
header_remaining= INT_MAX;
- dst[0] = &st->codec->extradata;
- dst[1] = &ass->event_buffer;
- while(!pb->eof_reached){
- uint8_t line[MAX_LINESIZE];
- len = ff_get_line(pb, line, sizeof(line));
+ av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprint_init(&line, 0, AV_BPRINT_SIZE_UNLIMITED);
- if(!memcmp(line, "[Events]", 8))
- header_remaining= 2;
- else if(line[0]=='[')
- header_remaining= INT_MAX;
+ for (;;) {
+ int64_t pos = get_line(&line, s->pb);
- i= header_remaining==0;
+ if (!line.str[0]) // EOF
+ break;
- if(i && get_pts(line) == AV_NOPTS_VALUE)
- continue;
+ if (!memcmp(line.str, "[Events]", 8))
+ header_remaining= 2;
+ else if (line.str[0]=='[')
+ header_remaining= INT_MAX;
- 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++;
+ if (header_remaining) {
+ av_bprintf(&header, "%s", line.str);
+ header_remaining--;
+ } else {
+ int64_t ts_start = AV_NOPTS_VALUE;
+ int duration = -1;
+ AVPacket *sub;
+
+ if (read_ts(line.str, &ts_start, &duration) < 0)
+ continue;
+ sub = ff_subtitles_queue_insert(&ass->q, line.str, line.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);
+ av_bprint_finalize(&line, NULL);
- 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:
+ 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;
-
- if(ass->event_index >= ass->event_count)
- return AVERROR(EIO);
-
- p= ass->event[ ass->event_index ];
-
- end= strchr(p, '\n');
- av_new_packet(pkt, end ? end-p+1 : strlen(p));
- 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..9fb9f23 100644
--- a/libavformat/assenc.c
+++ b/libavformat/assenc.c
@@ -2,27 +2,29 @@
* 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 "avformat.h"
+#include "internal.h"
typedef struct ASSContext{
unsigned int extra_index;
+ int write_ts; // 0: ssa (timing in payload), 1: ass (matroska like)
}ASSContext;
static int write_header(AVFormatContext *s)
@@ -31,10 +33,13 @@ static int write_header(AVFormatContext *s)
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;
}
+ ass->write_ts = avctx->codec_id == AV_CODEC_ID_ASS;
+ avpriv_set_pts_info(s->streams[0], 64, 1, 100);
while(ass->extra_index < avctx->extradata_size){
uint8_t *p = avctx->extradata + ass->extra_index;
@@ -57,7 +62,32 @@ static int write_header(AVFormatContext *s)
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;
+ int64_t start = pkt->pts;
+ int64_t end = start + pkt->duration;
+ int hh1, mm1, ss1, ms1;
+ int hh2, mm2, ss2, ms2;
+
+ p = pkt->data + strcspn(pkt->data, ",") + 1; // skip ReadOrder
+ 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;
+ avio_printf(s->pb, "Dialogue: %ld,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n",
+ layer, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, p);
+ } else {
+ avio_write(s->pb, pkt->data, pkt->size);
+ }
+
return 0;
}
@@ -82,5 +112,5 @@ 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,
};
diff --git a/libavformat/ast.c b/libavformat/ast.c
new file mode 100644
index 0000000..9de74aa
--- a/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
--- a/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..8862744
--- a/dev/null
+++ b/libavformat/astdec.c
@@ -0,0 +1,119 @@
+/*
+ * 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') &&
+ AV_RB16(p->buf + 10) &&
+ AV_RB16(p->buf + 12) &&
+ AV_RB32(p->buf + 16))
+ return AVPROBE_SCORE_MAX / 3 * 2;
+ return 0;
+}
+
+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 (url_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..edd802c
--- a/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 (enc->frame_number == 1)
+ 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 * enc->frame_number)) / 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 6b252b2..edf0f32 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 e4cde9d..2aa95f3 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
*/
@@ -47,6 +47,10 @@ int ff_audio_interleave_init(AVFormatContext *s,
if (!samples_per_frame)
return -1;
+ if (!time_base.num) {
+ av_log(s, AV_LOG_ERROR, "timebase not set for audio interleave\n");
+ return -1;
+ }
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
AudioInterleaveContext *aic = st->priv_data;
@@ -80,7 +84,8 @@ static int interleave_new_audio_packet(AVFormatContext *s, AVPacket *pkt,
if (!size || (!flush && size == av_fifo_size(aic->fifo)))
return 0;
- av_new_packet(pkt, size);
+ if (av_new_packet(pkt, size) < 0)
+ return AVERROR(ENOMEM);
av_fifo_generic_read(aic->fifo, pkt->data, size, NULL);
pkt->dts = pkt->pts = aic->dts;
@@ -113,10 +118,13 @@ int ff_audio_rechunk_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt
}
av_fifo_generic_write(aic->fifo, pkt->data, pkt->size, NULL);
} else {
+ int ret;
// rewrite pts and dts to be decoded time line position
pkt->pts = pkt->dts = aic->dts;
aic->dts += pkt->duration;
- ff_interleave_add_packet(s, pkt, compare_ts);
+ ret = ff_interleave_add_packet(s, pkt, compare_ts);
+ if (ret < 0)
+ return ret;
}
pkt = NULL;
}
@@ -125,8 +133,14 @@ 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))
- ff_interleave_add_packet(s, &new_pkt, compare_ts);
+ int ret;
+ while ((ret = interleave_new_audio_packet(s, &new_pkt, i, flush)) > 0) {
+ ret = ff_interleave_add_packet(s, &new_pkt, compare_ts);
+ if (ret < 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 2fd5ac8..f5c513b 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 579756e..972e19b 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 50e4f5c..6bd54ce 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).
@@ -220,7 +220,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.
*
@@ -337,6 +337,7 @@ typedef struct AVProbeData {
int buf_size; /**< Size of buf except extra allocated bytes */
} AVProbeData;
+#define AVPROBE_SCORE_RETRY (AVPROBE_SCORE_MAX/4)
#define AVPROBE_SCORE_EXTENSION 50 ///< score for file extension
#define AVPROBE_SCORE_MAX 100 ///< maximum score
@@ -359,14 +360,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
@@ -436,8 +447,12 @@ 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);
} AVOutputFormat;
/**
* @}
@@ -464,7 +479,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;
@@ -577,11 +592,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).
@@ -613,6 +636,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
@@ -658,10 +695,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;
@@ -712,11 +751,18 @@ 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;
+ double (*duration_error)[2][MAX_STD_TIMEBASES];
+ int64_t codec_info_duration;
+ int64_t codec_info_duration_fields;
int found_decoder;
+ int64_t last_duration;
+
/**
* Those are used for average framerate estimation.
*/
@@ -730,11 +776,18 @@ typedef struct AVStream {
int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */
#if FF_API_REFERENCE_DTS
- /* a hack to keep ABI compatibility for avconv, which accesses parser even
+ /* a hack to keep ABI compatibility for ffmpeg and other applications, which accesses parser even
* though it should not */
int64_t do_not_use;
#endif
// 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;
@@ -767,8 +820,83 @@ 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;
+
+ /**
+ * 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;
+
} AVStream;
+AVRational av_stream_get_r_frame_rate(const AVStream *s);
+void av_stream_set_r_frame_rate(AVStream *s, AVRational r);
+
#define AV_PROGRAM_RUNNING 1
/**
@@ -784,6 +912,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
@@ -796,6 +941,17 @@ typedef struct AVChapter {
AVDictionary *metadata;
} AVChapter;
+
+/**
+ * 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)
+};
+
/**
* Format I/O context.
* New fields can be added to the end with minor version bumps.
@@ -874,7 +1030,7 @@ typedef struct AVFormatContext {
/**
* Decoding: 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;
@@ -892,6 +1048,10 @@ typedef struct AVFormatContext {
#define AVFMT_FLAG_CUSTOM_IO 0x0080 ///< The caller has supplied a custom AVIOContext, don't avio_close() it.
#define AVFMT_FLAG_DISCARD_CORRUPT 0x0100 ///< Discard frames marked corrupted
#define AVFMT_FLAG_FLUSH_PACKETS 0x0200 ///< Flush the AVIOContext every packet.
+#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.
/**
* decoding: size of data to probe; encoding: unused.
@@ -1000,6 +1160,108 @@ typedef struct AVFormatContext {
*/
int debug;
#define FF_FDEBUG_TS 0x0001
+
+ /**
+ * 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;
+
+ /**
+ * Avoid negative timestamps during muxing.
+ * 0 -> allow negative timestamps
+ * 1 -> avoid negative timestamps
+ * -1 -> choose automatically (default)
+ * Note, this only works when interleave_packet_per_dts is in use.
+ * - encoding: Set by user via AVOptions (NO direct access)
+ * - decoding: unused
+ */
+ int avoid_negative_ts;
+
+ /**
+ * 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)
+ */
+ unsigned int 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;
+
/*****************************************************************
* 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
@@ -1041,6 +1303,7 @@ typedef struct AVFormatContext {
/**
* Offset to remap timestamps to be non-negative.
* Expressed in timebase units.
+ * @see AVStream.mux_ts_offset
*/
int64_t offset;
@@ -1049,8 +1312,54 @@ typedef struct AVFormatContext {
*/
AVRational offset_timebase;
+ /**
+ * 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;
} 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);
+
+/**
+ * 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;
@@ -1088,7 +1397,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);
@@ -1154,13 +1462,16 @@ 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 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
* defaults to be set, so codec should be provided if it is known.
*
* @return newly created stream or NULL on error.
*/
-AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c);
+AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c);
AVProgram *av_new_program(AVFormatContext *s, int id);
@@ -1169,6 +1480,35 @@ AVProgram *av_new_program(AVFormatContext *s, int id);
*/
+#if FF_API_ALLOC_OUTPUT_CONTEXT
+/**
+ * @deprecated deprecated in favor of avformat_alloc_output_context2()
+ */
+attribute_deprecated
+AVFormatContext *avformat_alloc_output_context(const char *format,
+ AVOutputFormat *oformat,
+ const char *filename);
+#endif
+
+/**
+ * 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
* @{
@@ -1201,6 +1541,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
@@ -1212,9 +1561,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);
@@ -1240,6 +1597,29 @@ 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);
+
+#if FF_API_FORMAT_PARAMETERS
+/**
+ * Read packets of a media file to get stream information. This
+ * is useful for file formats with no headers such as MPEG. This
+ * function also computes the real framerate in case of MPEG-2 repeat
+ * frame mode.
+ * The logical file position is not changed by this function;
+ * examined packets may be buffered for later processing.
+ *
+ * @param ic media file handle
+ * @return >=0 if OK, AVERROR_xxx on error
+ * @todo Let the user decide somehow what information is needed so that
+ * we do not waste time getting stuff the user does not need.
+ *
+ * @deprecated use avformat_find_stream_info.
+ */
+attribute_deprecated
+int av_find_stream_info(AVFormatContext *ic);
+#endif
+
/**
* Read packets of a media file to get stream information. This
* is useful for file formats with no headers such as MPEG. This
@@ -1264,6 +1644,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.
@@ -1294,6 +1686,24 @@ int av_find_best_stream(AVFormatContext *ic,
AVCodec **decoder_ret,
int flags);
+#if FF_API_READ_PACKET
+/**
+ * @deprecated use AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE to read raw
+ * unprocessed packets
+ *
+ * Read a transport packet from a media file.
+ *
+ * This function is obsolete and should never be used.
+ * Use av_read_frame() instead.
+ *
+ * @param s media file handle
+ * @param pkt is filled
+ * @return 0 if OK, AVERROR_xxx on error
+ */
+attribute_deprecated
+int av_read_packet(AVFormatContext *s, AVPacket *pkt);
+#endif
+
/**
* Return the next frame of a stream.
* This function returns what is stored in the file, and does not validate
@@ -1348,6 +1758,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 stream_index index of the stream which is used as time base reference
* @param min_ts smallest acceptable timestamp
@@ -1375,6 +1786,17 @@ int av_read_play(AVFormatContext *s);
*/
int av_read_pause(AVFormatContext *s);
+#if FF_API_CLOSE_INPUT_FILE
+/**
+ * @deprecated use avformat_close_input()
+ * Close a media file (but not its codecs).
+ *
+ * @param s media file handle
+ */
+attribute_deprecated
+void av_close_input_file(AVFormatContext *s);
+#endif
+
/**
* Close an opened input AVFormatContext. Free it and all its contents
* and set *s to NULL.
@@ -1384,6 +1806,30 @@ void avformat_close_input(AVFormatContext **s);
* @}
*/
+#if FF_API_NEW_STREAM
+/**
+ * Add a new stream to a media file.
+ *
+ * Can only be called in the read_header() function. If the flag
+ * AVFMTCTX_NOHEADER is in the format context, then new streams
+ * can be added in read_packet too.
+ *
+ * @param s media file handle
+ * @param id file-format-dependent stream ID
+ */
+attribute_deprecated
+AVStream *av_new_stream(AVFormatContext *s, int id);
+#endif
+
+#if FF_API_SET_PTS_INFO
+/**
+ * @deprecated this function is not supposed to be called outside of lavf
+ */
+attribute_deprecated
+void av_set_pts_info(AVStream *s, int pts_wrap_bits,
+ unsigned int pts_num, unsigned int pts_den);
+#endif
+
#define AVSEEK_FLAG_BACKWARD 1 ///< seek backward
#define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes
#define AVSEEK_FLAG_ANY 4 ///< seek to any frame, even non-keyframes
@@ -1491,6 +1937,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);
+
+
+/**
* @}
*/
@@ -1572,6 +2037,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);
/**
@@ -1706,11 +2183,60 @@ const struct AVCodecTag *avformat_get_riff_video_tags(void);
* @return the table mapping RIFF FourCCs for audio to AVCodecID.
*/
const struct AVCodecTag *avformat_get_riff_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/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 edc9c93..1a40e94 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -2,25 +2,27 @@
* 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 "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"
@@ -31,9 +33,6 @@
#include "internal.h"
#include "riff.h"
-#undef NDEBUG
-#include <assert.h>
-
typedef struct AVIStream {
int64_t frame_offset; /* current frame (video) or byte (audio) counter
* (used to compute the pts) */
@@ -56,12 +55,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;
@@ -70,9 +73,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' },
@@ -149,7 +169,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 "
@@ -192,9 +212,10 @@ 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 (url_feof(pb))
return AVERROR_INVALIDDATA;
if (last_pos == pos || pos == base - 8)
@@ -212,7 +233,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 (url_feof(pb))
return AVERROR_INVALIDDATA;
pos = avio_tell(pb);
@@ -222,16 +243,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;
}
@@ -364,6 +390,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;
@@ -371,8 +398,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 */
@@ -380,7 +409,7 @@ static int avi_read_header(AVFormatContext *s)
codec_type = -1;
frame_period = 0;
for (;;) {
- if (pb->eof_reached)
+ if (url_feof(pb))
goto fail;
tag = avio_rl32(pb);
size = avio_rl32(pb);
@@ -400,7 +429,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'))
@@ -428,7 +457,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;
@@ -484,6 +513,9 @@ 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;
if (CONFIG_DV_DEMUXER) {
@@ -511,7 +543,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 */
@@ -542,6 +574,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",
@@ -563,20 +599,27 @@ 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];
@@ -590,7 +633,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')) {
@@ -600,14 +643,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_alloc_extradata(st->codec, st->codec->extradata_size))
return AVERROR(ENOMEM);
- }
avio_read(pb,
st->codec->extradata,
st->codec->extradata_size);
@@ -620,7 +662,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;
@@ -629,12 +671,8 @@ 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
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;
}
@@ -647,11 +685,6 @@ 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 == 0 && st->codec->height > 0 &&
st->codec->extradata_size < 1U << 30) {
@@ -701,15 +734,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;
@@ -720,9 +765,31 @@ 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_alloc_extradata(st->codec, size))
+ return AVERROR(ENOMEM);
+ avio_read(pb, st->codec->extradata, st->codec->extradata_size);
+ }
+
+ if (st->codec->extradata_size & 1) //FIXME check if the encoder really did this correctly
+ avio_r8(pb);
+ }
+ 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;
@@ -771,7 +838,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 */
@@ -791,13 +858,27 @@ fail:
if (!avi->index_loaded && pb->seekable)
avi_load_index(s);
- avi->index_loaded = 1;
- avi->non_interleaved |= guess_ni_flag(s);
+ avi->index_loaded |= 1;
+ avi->non_interleaved |= guess_ni_flag(s) | (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");
@@ -901,7 +982,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(unsigned *d)
{
if (d[0] >= '0' && d[0] <= '9' &&
d[1] >= '0' && d[1] <= '9') {
@@ -911,6 +992,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;
@@ -922,7 +1007,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); !url_feof(pb); i++) {
int j;
for (j = 0; j < 7; j++)
@@ -934,7 +1019,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##
@@ -971,16 +1056,22 @@ start_sync:
st = s->streams[n];
ast = st->priv_data;
+ if (!ast) {
+ av_log(s, AV_LOG_WARNING, "Skiping 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;
@@ -997,9 +1088,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) {
@@ -1010,7 +1101,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;
@@ -1045,6 +1136,8 @@ start_sync:
}
}
+ if (pb->error)
+ return pb->error;
return AVERROR_EOF;
}
@@ -1101,10 +1194,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,
@@ -1119,15 +1209,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:
@@ -1154,8 +1247,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,
@@ -1177,7 +1271,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;
@@ -1215,14 +1309,32 @@ FF_ENABLE_DEPRECATION_WARNINGS
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
AVIndexEntry *e;
int index;
- assert(st->index_entries);
+ av_assert0(st->index_entries);
index = av_index_search_timestamp(st, ast->frame_offset, 0);
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;
}
@@ -1234,6 +1346,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;
}
@@ -1253,7 +1381,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)
@@ -1266,8 +1396,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 (url_feof(pb))
+ return -1;
+
tag = avio_rl32(pb);
flags = avio_rl32(pb);
pos = avio_rl32(pb);
@@ -1282,7 +1420,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;
}
@@ -1290,16 +1428,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;
}
@@ -1310,6 +1457,8 @@ static int guess_ni_flag(AVFormatContext *s)
int64_t last_start = 0;
int64_t first_end = INT64_MAX;
int64_t oldpos = avio_tell(s->pb);
+ int *idx;
+ int64_t min_pos, pos;
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
@@ -1333,7 +1482,35 @@ static int guess_ni_flag(AVFormatContext *s)
first_end = st->index_entries[n - 1].pos;
}
avio_seek(s->pb, oldpos, SEEK_SET);
- return last_start > first_end;
+ if (last_start > first_end)
+ return 1;
+ idx= av_calloc(s->nb_streams, sizeof(*idx));
+ if (!idx)
+ return 0;
+ for (min_pos=pos=0; min_pos!=INT64_MAX; pos= min_pos+1LU) {
+ int64_t max_dts = INT64_MIN/2, min_dts= INT64_MAX/2;
+ min_pos = INT64_MAX;
+
+ for (i=0; i<s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ AVIStream *ast = st->priv_data;
+ int n= st->nb_index_entries;
+ while (idx[i]<n && st->index_entries[idx[i]].pos < pos)
+ idx[i]++;
+ if (idx[i] < n) {
+ min_dts = FFMIN(min_dts, av_rescale_q(st->index_entries[idx[i]].timestamp/FFMAX(ast->sample_size, 1), st->time_base, AV_TIME_BASE_Q));
+ min_pos = FFMIN(min_pos, st->index_entries[idx[i]].pos);
+ }
+ if (idx[i])
+ max_dts = FFMAX(max_dts, av_rescale_q(st->index_entries[idx[i]-1].timestamp/FFMAX(ast->sample_size, 1), st->time_base, AV_TIME_BASE_Q));
+ }
+ if (max_dts - min_dts > 2*AV_TIME_BASE) {
+ av_free(idx);
+ return 1;
+ }
+ }
+ av_free(idx);
+ return 0;
}
static int avi_load_index(AVFormatContext *s)
@@ -1342,16 +1519,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 (url_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,
@@ -1361,12 +1541,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
}
@@ -1391,7 +1576,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
@@ -1403,16 +1588,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;
@@ -1426,15 +1618,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;
@@ -1450,35 +1645,47 @@ 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((int64_t)st2->time_base.num * ast2->rate ==
+ (int64_t)st2->time_base.den * ast2->scale);
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;
}
@@ -1527,4 +1734,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 66339af..3401cbc 100644
--- a/libavformat/avienc.c
+++ b/libavformat/avienc.c
@@ -2,22 +2,25 @@
* 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"
@@ -25,6 +28,8 @@
#include "riff.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
+#include "libavutil/avassert.h"
+#include "libavutil/timestamp.h"
/*
* TODO:
@@ -52,7 +57,7 @@ typedef struct {
typedef struct {
int64_t frames_hdr_strm;
- int audio_strm_length;
+ int64_t audio_strm_length;
int packet_count;
int entry;
@@ -117,7 +122,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(stream, &au_byterate, &au_ssize, &au_scale);
@@ -130,7 +135,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);
}
@@ -151,7 +156,7 @@ static int avi_write_header(AVFormatContext *s)
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++) {
@@ -242,9 +247,18 @@ static int avi_write_header(AVFormatContext *s)
ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
+ if ( stream->codec_type == AVMEDIA_TYPE_VIDEO
+ && stream->codec_id != AV_CODEC_ID_XSUB
+ && au_byterate > 1000LL*au_scale) {
+ au_byterate = 600;
+ au_scale = 1;
+ }
+ avpriv_set_pts_info(s->streams[i], 64, au_scale, au_byterate);
+ if(stream->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(s->streams[i], 64, au_scale, au_byterate);
avio_wl32(pb, 0); /* start */
avist->frames_hdr_strm = avio_tell(pb); /* remember this offset to fill later */
@@ -268,6 +282,8 @@ static int avi_write_header(AVFormatContext *s)
ff_end_tag(pb, strh);
if(stream->codec_type != AVMEDIA_TYPE_DATA){
+ int ret;
+
strf = ff_start_tag(pb, "strf");
switch(stream->codec_type) {
case AVMEDIA_TYPE_SUBTITLE:
@@ -278,12 +294,15 @@ static int avi_write_header(AVFormatContext *s)
ff_put_bmp_header(pb, stream, ff_codec_bmp_tags, 0);
break;
case AVMEDIA_TYPE_AUDIO:
- if (ff_put_wav_header(pb, stream) < 0) {
- return -1;
+ if ((ret = ff_put_wav_header(pb, stream)) < 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(stream->codec_type), "?"));
+ return AVERROR(EINVAL);
}
ff_end_tag(pb, strf);
if ((t = av_dict_get(s->streams[i]->metadata, "title", NULL, 0))) {
@@ -388,10 +407,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;
@@ -500,14 +522,21 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
AVCodecContext *enc= s->streams[stream_index]->codec;
int size= pkt->size;
- while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avist->packet_count){
+ av_dlog(s, "dts:%s packet_count:%d stream_index:%d\n", av_ts2str(pkt->dts), avist->packet_count, stream_index);
+ while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && 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++;
@@ -533,19 +562,19 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
}
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;
}
@@ -610,7 +639,7 @@ 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;
}
diff --git a/libavformat/avio.c b/libavformat/avio.c
index e07b236..b297ce8 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
*/
@@ -121,6 +121,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);
@@ -140,8 +150,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)
@@ -192,12 +227,21 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags,
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 (!first_protocol) {
+ av_log(NULL, AV_LOG_WARNING, "No URL Protocols are registered. "
+ "Missing call to av_register_all()?\n");
+ }
+
+ 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';
@@ -210,6 +254,8 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags,
return url_alloc_for_protocol(puc, up, filename, flags, int_cb);
}
*puc = NULL;
+ if (!strcmp("https", proto_str))
+ av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile with openssl or gnutls enabled.\n");
return AVERROR_PROTOCOL_NOT_FOUND;
}
@@ -239,9 +285,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;
@@ -249,17 +298,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();
+ else if (av_gettime() > 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;
}
@@ -286,7 +340,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)
@@ -299,8 +353,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 */
@@ -314,12 +369,18 @@ 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);
+}
+
+
int avio_check(const char *url, int flags)
{
URLContext *h;
@@ -366,7 +427,7 @@ int ffurl_get_multi_file_handle(URLContext *h, int **handles, int *numhandles)
if (!h->prot->url_get_multi_file_handle) {
if (!h->prot->url_get_file_handle)
return AVERROR(ENOSYS);
- *handles = av_malloc(sizeof(*handles));
+ *handles = av_malloc(sizeof(**handles));
if (!*handles)
return AVERROR(ENOMEM);
*numhandles = 1;
diff --git a/libavformat/avio.h b/libavformat/avio.h
index b6d3cb3..4f4ac3c 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,6 +115,37 @@ 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;
} AVIOContext;
/* unbuffered I/O */
@@ -146,6 +177,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 +223,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 +239,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 +256,23 @@ 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 url_feof(AVIOContext *s);
+
/** @warning currently size is limited */
int avio_printf(AVIOContext *s, const char *fmt, ...) av_printf_format(2, 3);
+/**
+ * Force flushing of buffered data to the output s.
+ *
+ * Force the buffered data to be immediately written to the output,
+ * without to wait to fill the internal buffer.
+ */
void avio_flush(AVIOContext *s);
-
/**
* Read size bytes from AVIOContext into buf.
* @return number of bytes read or AVERROR
@@ -311,6 +351,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
@@ -320,7 +368,7 @@ int avio_get_str16be(AVIOContext *pb, int maxlen, char *buf, int buflen);
* In case of failure the pointed to value is set to NULL.
* @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);
@@ -339,7 +387,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,
@@ -417,13 +465,13 @@ 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
*/
diff --git a/libavformat/avio_internal.h b/libavformat/avio_internal.h
index fdc98ec..8441d49 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 gurantee is lost.
+ */
+int ffio_ensure_seekback(AVIOContext *s, int 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);
@@ -114,7 +125,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 5064eb8..8218078 100644
--- a/libavformat/aviobuf.c
+++ b/libavformat/aviobuf.c
@@ -2,20 +2,20 @@
* 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
*/
@@ -24,6 +24,7 @@
#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"
@@ -80,6 +81,7 @@ int ffio_init_context(AVIOContext *s,
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 +123,34 @@ AVIOContext *avio_alloc_context(
return s;
}
+static void writeout(AVIOContext *s, const uint8_t *data, int len)
+{
+ 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->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;
- }
- }
+ 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;
}
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 +172,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);
@@ -205,13 +218,14 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
offset += offset1;
}
offset1 = offset - pos;
- if (!s->must_flush &&
+ if (!s->must_flush && (!s->direct || !s->seek) &&
offset1 >= 0 && offset1 <= (s->buf_end - s->buffer)) {
/* 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);
@@ -229,6 +243,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 +253,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 +277,31 @@ int64_t avio_size(AVIOContext *s)
return size;
}
+int url_feof(AVIOContext *s)
+{
+ if(!s)
+ return 0;
+ if(s->eof_reached){
+ s->eof_reached=0;
+ fill_buffer(s);
+ }
+ return s->eof_reached;
+}
+
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)
@@ -316,7 +347,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 +366,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 +414,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->buffer_size > max_buffer_size) {
+ if (dst == s->buffer) {
+ ffio_set_buf_size(s, max_buffer_size);
- s->checksum_ptr = dst = s->buffer;
- len = s->buffer_size;
+ s->checksum_ptr = dst = s->buffer;
+ }
+ av_assert0(len >= max_buffer_size);
+ len = max_buffer_size;
}
if (s->read_packet)
@@ -405,6 +438,7 @@ static void fill_buffer(AVIOContext *s)
s->pos += len;
s->buf_ptr = dst;
s->buf_end = dst + len;
+ s->bytes_read += len;
}
}
@@ -453,7 +487,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) {
@@ -465,6 +499,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;
@@ -484,8 +519,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 (url_feof(s)) return AVERROR_EOF;
}
return size1 - size;
}
@@ -533,8 +568,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 (url_feof(s)) return AVERROR_EOF;
}
return len;
}
@@ -686,11 +721,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) {
@@ -701,6 +737,31 @@ int ffio_fdopen(AVIOContext **s, URLContext *h)
return 0;
}
+int ffio_ensure_seekback(AVIOContext *s, int buf_size)
+{
+ uint8_t *buffer;
+ int max_buffer_size = s->max_packet_size ?
+ s->max_packet_size : IO_BUFFER_SIZE;
+
+ buf_size += s->buf_ptr - s->buffer + max_buffer_size;
+
+ if (buf_size < s->buffer_size || s->seekable)
+ return 0;
+ av_assert0(!s->write_flag);
+
+ buffer = av_malloc(buf_size);
+ if (!buffer)
+ return AVERROR(ENOMEM);
+
+ memcpy(buffer, s->buffer, s->buffer_size);
+ av_free(s->buffer);
+ s->buf_ptr = buffer + (s->buf_ptr - s->buffer);
+ s->buf_end = buffer + (s->buf_end - s->buffer);
+ s->buffer = buffer;
+ s->buffer_size = buf_size;
+ return 0;
+}
+
int ffio_set_buf_size(AVIOContext *s, int buf_size)
{
uint8_t *buffer;
@@ -718,7 +779,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;
@@ -730,27 +791,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) {
@@ -801,6 +867,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);
}
diff --git a/libavformat/avisynth.c b/libavformat/avisynth.c
index e411d35..e35306b 100644
--- a/libavformat/avisynth.c
+++ b/libavformat/avisynth.c
@@ -1,229 +1,685 @@
/*
- * AviSynth support
- * Copyright (c) 2006 DivX, Inc.
+ * Avi/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
*/
-#include <windows.h>
-#include <vfw.h>
-
#include "libavutil/internal.h"
+#include "libavcodec/internal.h"
#include "avformat.h"
#include "internal.h"
-#include "riff.h"
-
-typedef struct {
- PAVISTREAM handle;
- AVISTREAMINFO info;
- DWORD read;
- LONG chunck_size;
- LONG chunck_samples;
-} AviSynthStream;
-
-typedef struct {
- PAVIFILE file;
- AviSynthStream *streams;
- int nb_streams;
- int next_stream;
+
+/* Enable function pointer definitions for runtime loading. */
+#define AVSC_NO_DECLSPEC
+
+/* Platform-specific directives for AviSynth vs AvxSynth. */
+#ifdef _WIN32
+ #include <windows.h>
+ #undef EXTERN_C
+ #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 "compat/avisynth/avxsynth_c.h"
+ #if defined (__APPLE__)
+ #define AVISYNTH_LIB "libavxsynth.dylib"
+ #else
+ #define AVISYNTH_LIB "libavxsynth.so"
+ #endif
+
+ #define LoadLibrary(x) dlopen(x, RTLD_NOW | RTLD_GLOBAL)
+ #define GetProcAddress dlsym
+ #define FreeLibrary dlclose
+#endif
+
+typedef struct AviSynthLibrary {
+ void *library;
+#define AVSC_DECLARE_FUNC(name) name ## _func name
+ AVSC_DECLARE_FUNC(avs_bit_blt);
+ AVSC_DECLARE_FUNC(avs_clip_get_error);
+ AVSC_DECLARE_FUNC(avs_create_script_environment);
+ AVSC_DECLARE_FUNC(avs_delete_script_environment);
+ AVSC_DECLARE_FUNC(avs_get_audio);
+ AVSC_DECLARE_FUNC(avs_get_error);
+ AVSC_DECLARE_FUNC(avs_get_frame);
+ AVSC_DECLARE_FUNC(avs_get_version);
+ AVSC_DECLARE_FUNC(avs_get_video_info);
+ AVSC_DECLARE_FUNC(avs_invoke);
+ AVSC_DECLARE_FUNC(avs_release_clip);
+ AVSC_DECLARE_FUNC(avs_release_value);
+ AVSC_DECLARE_FUNC(avs_release_video_frame);
+ AVSC_DECLARE_FUNC(avs_take_clip);
+#undef AVSC_DECLARE_FUNC
+} AviSynthLibrary;
+
+typedef struct AviSynthContext {
+ AVS_ScriptEnvironment *env;
+ AVS_Clip *clip;
+ const AVS_VideoInfo *vi;
+
+ /* avisynth_read_packet_video() iterates over this. */
+ int n_planes;
+ const int *planes;
+
+ int curr_stream;
+ int curr_frame;
+ int64_t curr_sample;
+
+ int error;
+
+ /* Linked list pointers. */
+ struct AviSynthContext *next;
} AviSynthContext;
-static int avisynth_read_header(AVFormatContext *s)
+static const int avs_planes_packed[1] = { 0 };
+static const int avs_planes_grey[1] = { AVS_PLANAR_Y };
+static const int avs_planes_yuv[3] = { AVS_PLANAR_Y, AVS_PLANAR_U,
+ AVS_PLANAR_V };
+
+/* A conflict between C++ global objects, atexit, and dynamic loading requires
+ * us to register our own atexit handler to prevent double freeing. */
+static AviSynthLibrary *avs_library = NULL;
+static int avs_atexit_called = 0;
+
+/* Linked list of AviSynthContexts. An atexit handler destroys this list. */
+static AviSynthContext *avs_ctx_list = NULL;
+
+static av_cold void avisynth_atexit_handler(void);
+
+static av_cold int avisynth_load_library(void)
+{
+ avs_library = av_mallocz(sizeof(AviSynthLibrary));
+ if (!avs_library)
+ return AVERROR_UNKNOWN;
+
+ avs_library->library = LoadLibrary(AVISYNTH_LIB);
+ if (!avs_library->library)
+ goto init_fail;
+
+#define LOAD_AVS_FUNC(name, continue_on_fail) \
+ avs_library->name = \
+ (void *)GetProcAddress(avs_library->library, #name); \
+ if (!continue_on_fail && !avs_library->name) \
+ goto fail;
+
+ LOAD_AVS_FUNC(avs_bit_blt, 0);
+ LOAD_AVS_FUNC(avs_clip_get_error, 0);
+ LOAD_AVS_FUNC(avs_create_script_environment, 0);
+ LOAD_AVS_FUNC(avs_delete_script_environment, 0);
+ LOAD_AVS_FUNC(avs_get_audio, 0);
+ LOAD_AVS_FUNC(avs_get_error, 1); // New to AviSynth 2.6
+ LOAD_AVS_FUNC(avs_get_frame, 0);
+ LOAD_AVS_FUNC(avs_get_version, 0);
+ LOAD_AVS_FUNC(avs_get_video_info, 0);
+ LOAD_AVS_FUNC(avs_invoke, 0);
+ LOAD_AVS_FUNC(avs_release_clip, 0);
+ LOAD_AVS_FUNC(avs_release_value, 0);
+ LOAD_AVS_FUNC(avs_release_video_frame, 0);
+ LOAD_AVS_FUNC(avs_take_clip, 0);
+#undef LOAD_AVS_FUNC
+
+ atexit(avisynth_atexit_handler);
+ return 0;
+
+fail:
+ FreeLibrary(avs_library->library);
+init_fail:
+ av_freep(&avs_library);
+ return AVERROR_UNKNOWN;
+}
+
+/* Note that avisynth_context_create and avisynth_context_destroy
+ * do not allocate or free the actual context! That is taken care of
+ * by libavformat. */
+static av_cold int avisynth_context_create(AVFormatContext *s)
{
AviSynthContext *avs = s->priv_data;
- HRESULT res;
- AVIFILEINFO info;
- DWORD id;
- AVStream *st;
- AviSynthStream *stream;
- wchar_t filename_wchar[1024] = { 0 };
- char filename_char[1024] = { 0 };
-
- AVIFileInit();
-
- /* AviSynth cannot accept UTF-8 file names. */
- MultiByteToWideChar(CP_UTF8, 0, s->filename, -1, filename_wchar, 1024);
- WideCharToMultiByte(CP_THREAD_ACP, 0, filename_wchar, -1, filename_char,
- 1024, NULL, NULL);
- res = AVIFileOpen(&avs->file, filename_char,
- OF_READ | OF_SHARE_DENY_WRITE, NULL);
- if (res != S_OK) {
- av_log(s, AV_LOG_ERROR, "AVIFileOpen failed with error %ld", res);
- AVIFileExit();
- return -1;
- }
-
- res = AVIFileInfo(avs->file, &info, sizeof(info));
- if (res != S_OK) {
- av_log(s, AV_LOG_ERROR, "AVIFileInfo failed with error %ld", res);
- AVIFileExit();
- return -1;
- }
-
- avs->streams = av_mallocz(info.dwStreams * sizeof(AviSynthStream));
-
- for (id = 0; id < info.dwStreams; id++) {
- stream = &avs->streams[id];
- stream->read = 0;
- if (AVIFileGetStream(avs->file, &stream->handle, 0, id) == S_OK &&
- AVIStreamInfo(stream->handle, &stream->info,
- sizeof(stream->info)) == S_OK) {
- if (stream->info.fccType == streamtypeAUDIO) {
- WAVEFORMATEX wvfmt;
- LONG struct_size = sizeof(WAVEFORMATEX);
- if (AVIStreamReadFormat(stream->handle, 0,
- &wvfmt, &struct_size) != S_OK)
- continue;
-
- st = avformat_new_stream(s, NULL);
- st->id = id;
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
-
- st->codec->block_align = wvfmt.nBlockAlign;
- st->codec->channels = wvfmt.nChannels;
- st->codec->sample_rate = wvfmt.nSamplesPerSec;
- st->codec->bit_rate = wvfmt.nAvgBytesPerSec * 8;
- st->codec->bits_per_coded_sample = wvfmt.wBitsPerSample;
-
- stream->chunck_samples = wvfmt.nSamplesPerSec *
- (uint64_t)info.dwScale /
- (uint64_t)info.dwRate;
- stream->chunck_size = stream->chunck_samples *
- wvfmt.nChannels *
- wvfmt.wBitsPerSample / 8;
-
- st->codec->codec_tag = wvfmt.wFormatTag;
- st->codec->codec_id =
- ff_wav_codec_get_id(wvfmt.wFormatTag,
- st->codec->bits_per_coded_sample);
- } else if (stream->info.fccType == streamtypeVIDEO) {
- BITMAPINFO imgfmt;
- LONG struct_size = sizeof(BITMAPINFO);
-
- stream->chunck_size = stream->info.dwSampleSize;
- stream->chunck_samples = 1;
-
- if (AVIStreamReadFormat(stream->handle, 0, &imgfmt,
- &struct_size) != S_OK)
- continue;
-
- st = avformat_new_stream(s, NULL);
- st->id = id;
- st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->avg_frame_rate.num = stream->info.dwRate;
- st->avg_frame_rate.den = stream->info.dwScale;
-
- st->codec->width = imgfmt.bmiHeader.biWidth;
- st->codec->height = imgfmt.bmiHeader.biHeight;
-
- st->codec->bits_per_coded_sample = imgfmt.bmiHeader.biBitCount;
- st->codec->bit_rate = (uint64_t)stream->info.dwSampleSize *
- (uint64_t)stream->info.dwRate * 8 /
- (uint64_t)stream->info.dwScale;
- st->codec->codec_tag = imgfmt.bmiHeader.biCompression;
- st->codec->codec_id =
- ff_codec_get_id(ff_codec_bmp_tags,
- imgfmt.bmiHeader.biCompression);
-
- st->duration = stream->info.dwLength;
- } else {
- AVIStreamRelease(stream->handle);
- continue;
- }
-
- avs->nb_streams++;
-
- st->codec->stream_codec_tag = stream->info.fccHandler;
-
- avpriv_set_pts_info(st, 64, info.dwScale, info.dwRate);
- st->start_time = stream->info.dwStart;
+ int ret;
+
+ if (!avs_library)
+ if (ret = avisynth_load_library())
+ return ret;
+
+ avs->env = avs_library->avs_create_script_environment(3);
+ if (avs_library->avs_get_error) {
+ const char *error = avs_library->avs_get_error(avs->env);
+ if (error) {
+ av_log(s, AV_LOG_ERROR, "%s\n", error);
+ return AVERROR_UNKNOWN;
}
}
+ if (!avs_ctx_list) {
+ avs_ctx_list = avs;
+ } else {
+ avs->next = avs_ctx_list;
+ avs_ctx_list = avs;
+ }
+
return 0;
}
-static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt)
+static av_cold void avisynth_context_destroy(AviSynthContext *avs)
+{
+ if (avs_atexit_called)
+ return;
+
+ if (avs == avs_ctx_list) {
+ avs_ctx_list = avs->next;
+ } else {
+ AviSynthContext *prev = avs_ctx_list;
+ while (prev->next != avs)
+ prev = prev->next;
+ prev->next = avs->next;
+ }
+
+ if (avs->clip) {
+ avs_library->avs_release_clip(avs->clip);
+ avs->clip = NULL;
+ }
+ if (avs->env) {
+ avs_library->avs_delete_script_environment(avs->env);
+ avs->env = NULL;
+ }
+}
+
+static av_cold void avisynth_atexit_handler(void)
+{
+ AviSynthContext *avs = avs_ctx_list;
+
+ while (avs) {
+ AviSynthContext *next = avs->next;
+ avisynth_context_destroy(avs);
+ avs = next;
+ }
+ FreeLibrary(avs_library->library);
+ av_freep(&avs_library);
+
+ avs_atexit_called = 1;
+}
+
+/* Create AVStream from audio and video data. */
+static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st)
{
AviSynthContext *avs = s->priv_data;
- HRESULT res;
- AviSynthStream *stream;
- int stream_id = avs->next_stream;
- LONG read_size;
+ int planar = 0; // 0: packed, 1: YUV, 2: Y8
+
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->codec->width = avs->vi->width;
+ st->codec->height = avs->vi->height;
+
+ st->time_base = (AVRational) { avs->vi->fps_denominator,
+ avs->vi->fps_numerator };
+ st->avg_frame_rate = (AVRational) { avs->vi->fps_numerator,
+ avs->vi->fps_denominator };
+ st->start_time = 0;
+ st->duration = avs->vi->num_frames;
+ st->nb_frames = avs->vi->num_frames;
+
+ switch (avs->vi->pixel_type) {
+#ifdef USING_AVISYNTH
+ case AVS_CS_YV24:
+ st->codec->pix_fmt = AV_PIX_FMT_YUV444P;
+ planar = 1;
+ break;
+ case AVS_CS_YV16:
+ st->codec->pix_fmt = AV_PIX_FMT_YUV422P;
+ planar = 1;
+ break;
+ case AVS_CS_YV411:
+ st->codec->pix_fmt = AV_PIX_FMT_YUV411P;
+ planar = 1;
+ break;
+ case AVS_CS_Y8:
+ st->codec->pix_fmt = AV_PIX_FMT_GRAY8;
+ planar = 2;
+ break;
+#endif
+ case AVS_CS_BGR24:
+ st->codec->pix_fmt = AV_PIX_FMT_BGR24;
+ break;
+ case AVS_CS_BGR32:
+ st->codec->pix_fmt = AV_PIX_FMT_RGB32;
+ break;
+ case AVS_CS_YUY2:
+ st->codec->pix_fmt = AV_PIX_FMT_YUYV422;
+ break;
+ case AVS_CS_YV12:
+ st->codec->pix_fmt = AV_PIX_FMT_YUV420P;
+ planar = 1;
+ break;
+ case AVS_CS_I420: // Is this even used anywhere?
+ st->codec->pix_fmt = AV_PIX_FMT_YUV420P;
+ planar = 1;
+ break;
+ default:
+ av_log(s, AV_LOG_ERROR,
+ "unknown AviSynth colorspace %d\n", avs->vi->pixel_type);
+ avs->error = 1;
+ return AVERROR_UNKNOWN;
+ }
- // handle interleaving manually...
- stream = &avs->streams[stream_id];
+ switch (planar) {
+ case 2: // Y8
+ avs->n_planes = 1;
+ avs->planes = avs_planes_grey;
+ break;
+ case 1: // YUV
+ avs->n_planes = 3;
+ avs->planes = avs_planes_yuv;
+ break;
+ default:
+ avs->n_planes = 1;
+ avs->planes = avs_planes_packed;
+ }
+ return 0;
+}
- if (stream->read >= stream->info.dwLength)
- return AVERROR(EIO);
+static int avisynth_create_stream_audio(AVFormatContext *s, AVStream *st)
+{
+ AviSynthContext *avs = s->priv_data;
- if (av_new_packet(pkt, stream->chunck_size))
- return AVERROR(EIO);
- pkt->stream_index = stream_id;
- pkt->pts = avs->streams[stream_id].read /
- avs->streams[stream_id].chunck_samples;
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->sample_rate = avs->vi->audio_samples_per_second;
+ st->codec->channels = avs->vi->nchannels;
+ st->time_base = (AVRational) { 1,
+ avs->vi->audio_samples_per_second };
+
+ switch (avs->vi->sample_type) {
+ case AVS_SAMPLE_INT8:
+ st->codec->codec_id = AV_CODEC_ID_PCM_U8;
+ break;
+ case AVS_SAMPLE_INT16:
+ st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
+ break;
+ case AVS_SAMPLE_INT24:
+ st->codec->codec_id = AV_CODEC_ID_PCM_S24LE;
+ break;
+ case AVS_SAMPLE_INT32:
+ st->codec->codec_id = AV_CODEC_ID_PCM_S32LE;
+ break;
+ case AVS_SAMPLE_FLOAT:
+ st->codec->codec_id = AV_CODEC_ID_PCM_F32LE;
+ break;
+ default:
+ av_log(s, AV_LOG_ERROR,
+ "unknown AviSynth sample type %d\n", avs->vi->sample_type);
+ avs->error = 1;
+ return AVERROR_UNKNOWN;
+ }
+ return 0;
+}
- res = AVIStreamRead(stream->handle, stream->read, stream->chunck_samples,
- pkt->data, stream->chunck_size, &read_size, NULL);
+static int avisynth_create_stream(AVFormatContext *s)
+{
+ AviSynthContext *avs = s->priv_data;
+ AVStream *st;
+ int ret;
+ int id = 0;
+
+ if (avs_has_video(avs->vi)) {
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR_UNKNOWN;
+ st->id = id++;
+ if (ret = avisynth_create_stream_video(s, st))
+ return ret;
+ }
+ if (avs_has_audio(avs->vi)) {
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR_UNKNOWN;
+ st->id = id++;
+ if (ret = avisynth_create_stream_audio(s, st))
+ return ret;
+ }
+ return 0;
+}
- pkt->pts = stream->read;
- pkt->size = read_size;
+static int avisynth_open_file(AVFormatContext *s)
+{
+ AviSynthContext *avs = s->priv_data;
+ AVS_Value arg, val;
+ int ret;
+#ifdef USING_AVISYNTH
+ char filename_ansi[MAX_PATH * 4];
+ wchar_t filename_wc[MAX_PATH * 4];
+#endif
+
+ if (ret = avisynth_context_create(s))
+ return ret;
+
+#ifdef USING_AVISYNTH
+ /* Convert UTF-8 to ANSI code page */
+ MultiByteToWideChar(CP_UTF8, 0, s->filename, -1, filename_wc, MAX_PATH * 4);
+ WideCharToMultiByte(CP_THREAD_ACP, 0, filename_wc, -1, filename_ansi,
+ MAX_PATH * 4, NULL, NULL);
+ arg = avs_new_value_string(filename_ansi);
+#else
+ arg = avs_new_value_string(s->filename);
+#endif
+ val = avs_library->avs_invoke(avs->env, "Import", arg, 0);
+ if (avs_is_error(val)) {
+ av_log(s, AV_LOG_ERROR, "%s\n", avs_as_error(val));
+ ret = AVERROR_UNKNOWN;
+ goto fail;
+ }
+ if (!avs_is_clip(val)) {
+ av_log(s, AV_LOG_ERROR, "AviSynth script did not return a clip\n");
+ ret = AVERROR_UNKNOWN;
+ goto fail;
+ }
+
+ avs->clip = avs_library->avs_take_clip(val, avs->env);
+ avs->vi = avs_library->avs_get_video_info(avs->clip);
- stream->read += stream->chunck_samples;
+ /* Release the AVS_Value as it will go out of scope. */
+ avs_library->avs_release_value(val);
- // prepare for the next stream to read
- do
- avs->next_stream = (avs->next_stream + 1) % avs->nb_streams;
- while (avs->next_stream != stream_id &&
- s->streams[avs->next_stream]->discard >= AVDISCARD_ALL);
+ if (ret = avisynth_create_stream(s))
+ goto fail;
- return (res == S_OK) ? pkt->size : -1;
+ return 0;
+
+fail:
+ avisynth_context_destroy(avs);
+ return ret;
}
-static int avisynth_read_close(AVFormatContext *s)
+static void avisynth_next_stream(AVFormatContext *s, AVStream **st,
+ AVPacket *pkt, int *discard)
{
AviSynthContext *avs = s->priv_data;
- int i;
- for (i = 0; i < avs->nb_streams; i++)
- AVIStreamRelease(avs->streams[i].handle);
+ pkt->stream_index = avs->curr_stream++;
+ avs->curr_stream %= s->nb_streams;
+
+ *st = s->streams[pkt->stream_index];
+ if ((*st)->discard == AVDISCARD_ALL)
+ *discard = 1;
+ else
+ *discard = 0;
+
+ return;
+}
+
+/* Copy AviSynth clip data into an AVPacket. */
+static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt,
+ int discard)
+{
+ AviSynthContext *avs = s->priv_data;
+ AVS_VideoFrame *frame;
+ unsigned char *dst_p;
+ const unsigned char *src_p;
+ int n, i, plane, rowsize, planeheight, pitch, bits;
+ const char *error;
+
+ if (avs->curr_frame >= avs->vi->num_frames)
+ return AVERROR_EOF;
+
+ /* This must happen even if the stream is discarded to prevent desync. */
+ n = avs->curr_frame++;
+ if (discard)
+ return 0;
+
+ pkt->pts = n;
+ pkt->dts = n;
+ pkt->duration = 1;
+
+#ifdef USING_AVISYNTH
+ /* Define the bpp values for the new AviSynth 2.6 colorspaces.
+ * Since AvxSynth doesn't have these functions, special-case
+ * it in order to avoid implicit declaration errors. */
+
+ if (avs_is_yv24(avs->vi))
+ bits = 24;
+ else if (avs_is_yv16(avs->vi))
+ bits = 16;
+ else if (avs_is_yv411(avs->vi))
+ bits = 12;
+ else if (avs_is_y8(avs->vi))
+ bits = 8;
+ else
+#endif
+ bits = avs_bits_per_pixel(avs->vi);
+
+ /* Without the cast to int64_t, calculation overflows at about 9k x 9k
+ * resolution. */
+ pkt->size = (((int64_t)avs->vi->width *
+ (int64_t)avs->vi->height) * bits) / 8;
+ if (!pkt->size)
+ return AVERROR_UNKNOWN;
+ pkt->data = av_malloc(pkt->size);
+ if (!pkt->data)
+ return AVERROR(ENOMEM);
+
+ frame = avs_library->avs_get_frame(avs->clip, n);
+ error = avs_library->avs_clip_get_error(avs->clip);
+ if (error) {
+ av_log(s, AV_LOG_ERROR, "%s\n", error);
+ avs->error = 1;
+ av_freep(&pkt->data);
+ return AVERROR_UNKNOWN;
+ }
+
+ dst_p = pkt->data;
+ for (i = 0; i < avs->n_planes; i++) {
+ plane = avs->planes[i];
+ 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)) {
+ src_p = src_p + (planeheight - 1) * pitch;
+ pitch = -pitch;
+ }
+
+ avs_library->avs_bit_blt(avs->env, dst_p, rowsize, src_p, pitch,
+ rowsize, planeheight);
+ dst_p += rowsize * planeheight;
+ }
- av_free(avs->streams);
- AVIFileRelease(avs->file);
- AVIFileExit();
+ avs_library->avs_release_video_frame(frame);
return 0;
}
-static int avisynth_read_seek(AVFormatContext *s, int stream_index,
- int64_t pts, int flags)
+static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt,
+ int discard)
+{
+ AviSynthContext *avs = s->priv_data;
+ AVRational fps, samplerate;
+ int samples;
+ int64_t n;
+ const char *error;
+
+ if (avs->curr_sample >= avs->vi->num_audio_samples)
+ return AVERROR_EOF;
+
+ fps.num = avs->vi->fps_numerator;
+ fps.den = avs->vi->fps_denominator;
+ samplerate.num = avs->vi->audio_samples_per_second;
+ samplerate.den = 1;
+
+ if (avs_has_video(avs->vi)) {
+ if (avs->curr_frame < avs->vi->num_frames)
+ samples = av_rescale_q(avs->curr_frame, samplerate, fps) -
+ avs->curr_sample;
+ else
+ samples = av_rescale_q(1, samplerate, fps);
+ } else {
+ samples = 1000;
+ }
+
+ /* After seeking, audio may catch up with video. */
+ if (samples <= 0) {
+ pkt->size = 0;
+ pkt->data = NULL;
+ return 0;
+ }
+
+ if (avs->curr_sample + samples > avs->vi->num_audio_samples)
+ samples = avs->vi->num_audio_samples - avs->curr_sample;
+
+ /* This must happen even if the stream is discarded to prevent desync. */
+ n = avs->curr_sample;
+ avs->curr_sample += samples;
+ if (discard)
+ return 0;
+
+ pkt->pts = n;
+ pkt->dts = n;
+ pkt->duration = samples;
+
+ pkt->size = avs_bytes_per_channel_sample(avs->vi) *
+ samples * avs->vi->nchannels;
+ if (!pkt->size)
+ return AVERROR_UNKNOWN;
+ pkt->data = av_malloc(pkt->size);
+ if (!pkt->data)
+ return AVERROR(ENOMEM);
+
+ avs_library->avs_get_audio(avs->clip, pkt->data, n, samples);
+ error = avs_library->avs_clip_get_error(avs->clip);
+ if (error) {
+ av_log(s, AV_LOG_ERROR, "%s\n", error);
+ avs->error = 1;
+ av_freep(&pkt->data);
+ return AVERROR_UNKNOWN;
+ }
+ return 0;
+}
+
+static av_cold int avisynth_read_header(AVFormatContext *s)
+{
+ int ret;
+
+ // Calling library must implement a lock for thread-safe opens.
+ if (ret = avpriv_lock_avformat())
+ return ret;
+
+ if (ret = avisynth_open_file(s)) {
+ avpriv_unlock_avformat();
+ return ret;
+ }
+
+ avpriv_unlock_avformat();
+ return 0;
+}
+
+static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt)
{
AviSynthContext *avs = s->priv_data;
- int stream_id;
+ AVStream *st;
+ int discard = 0;
+ int ret;
+
+ if (avs->error)
+ return AVERROR_UNKNOWN;
+
+ pkt->destruct = av_destruct_packet;
+
+ /* If either stream reaches EOF, try to read the other one before
+ * giving up. */
+ avisynth_next_stream(s, &st, pkt, &discard);
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ ret = avisynth_read_packet_video(s, pkt, discard);
+ if (ret == AVERROR_EOF && avs_has_audio(avs->vi)) {
+ avisynth_next_stream(s, &st, pkt, &discard);
+ return avisynth_read_packet_audio(s, pkt, discard);
+ }
+ } else {
+ ret = avisynth_read_packet_audio(s, pkt, discard);
+ if (ret == AVERROR_EOF && avs_has_video(avs->vi)) {
+ avisynth_next_stream(s, &st, pkt, &discard);
+ return avisynth_read_packet_video(s, pkt, discard);
+ }
+ }
- for (stream_id = 0; stream_id < avs->nb_streams; stream_id++)
- avs->streams[stream_id].read =
- pts * avs->streams[stream_id].chunck_samples;
+ return ret;
+}
+
+static av_cold int avisynth_read_close(AVFormatContext *s)
+{
+ if (avpriv_lock_avformat())
+ return AVERROR_UNKNOWN;
+
+ avisynth_context_destroy(s->priv_data);
+ avpriv_unlock_avformat();
+ return 0;
+}
+
+static int avisynth_read_seek(AVFormatContext *s, int stream_index,
+ int64_t timestamp, int flags)
+{
+ AviSynthContext *avs = s->priv_data;
+ AVStream *st;
+ AVRational fps, samplerate;
+
+ if (avs->error)
+ return AVERROR_UNKNOWN;
+
+ fps = (AVRational) { avs->vi->fps_numerator,
+ avs->vi->fps_denominator };
+ samplerate = (AVRational) { avs->vi->audio_samples_per_second, 1 };
+
+ st = s->streams[stream_index];
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ /* AviSynth frame counts are signed int. */
+ if ((timestamp >= avs->vi->num_frames) ||
+ (timestamp > INT_MAX) ||
+ (timestamp < 0))
+ return AVERROR_EOF;
+ avs->curr_frame = timestamp;
+ if (avs_has_audio(avs->vi))
+ avs->curr_sample = av_rescale_q(timestamp, samplerate, fps);
+ } else {
+ if ((timestamp >= avs->vi->num_audio_samples) || (timestamp < 0))
+ return AVERROR_EOF;
+ /* Force frame granularity for seeking. */
+ if (avs_has_video(avs->vi)) {
+ avs->curr_frame = av_rescale_q(timestamp, fps, samplerate);
+ avs->curr_sample = av_rescale_q(avs->curr_frame, samplerate, fps);
+ } else {
+ avs->curr_sample = timestamp;
+ }
+ }
return 0;
}
AVInputFormat ff_avisynth_demuxer = {
.name = "avisynth",
- .long_name = NULL_IF_CONFIG_SMALL("AviSynth"),
+ .long_name = NULL_IF_CONFIG_SMALL("AviSynth script"),
.priv_data_size = sizeof(AviSynthContext),
.read_header = avisynth_read_header,
.read_packet = avisynth_read_packet,
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..02edf45
--- a/dev/null
+++ b/libavformat/avr.c
@@ -0,0 +1,93 @@
+/*
+ * 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 AVPROBE_SCORE_EXTENSION;
+ return 0;
+}
+
+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 3e95a36..7814301 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 120e145..b8f08c1 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
*/
@@ -189,7 +189,8 @@ static int read_frame(BVID_DemuxContext *vid, AVIOContext *pb, AVPacket *pkt,
if (vid->palette) {
uint8_t *pdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE,
BVID_PALETTE_SIZE);
- memcpy(pdata, vid->palette, BVID_PALETTE_SIZE);
+ if (pdata)
+ memcpy(pdata, vid->palette, BVID_PALETTE_SIZE);
av_freep(&vid->palette);
}
@@ -209,8 +210,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 || url_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..b65a582 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 || url_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 (url_feof(pb))
return AVERROR(EIO);
state = 256*state + avio_r8(pb);
}
diff --git a/libavformat/bink.c b/libavformat/bink.c
index f093e7c..6db73cc 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
*/
@@ -116,10 +116,8 @@ 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 (ff_alloc_extradata(vst->codec, 4))
return AVERROR(ENOMEM);
- vst->codec->extradata_size = 4;
avio_read(pb, vst->codec->extradata, 4);
bink->num_audio_tracks = avio_rl32(pb);
@@ -152,10 +150,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);
}
@@ -202,7 +198,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);
diff --git a/libavformat/bintext.c b/libavformat/bintext.c
new file mode 100644
index 0000000..d50a8d9
--- a/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 (url_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..0be471a
--- a/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(url_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
--- a/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
--- a/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..7781b3c
--- a/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 (!url_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 additonal 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 (url_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
--- a/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 6950eb2..e954c65 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
*/
@@ -69,7 +69,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;
@@ -86,7 +86,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);
@@ -130,8 +130,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.
@@ -154,13 +153,10 @@ 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_alloc_extradata(st->codec, size))
return AVERROR(ENOMEM);
avio_read(pb, st->codec->extradata, size);
- st->codec->extradata_size = size;
}
return 0;
@@ -211,7 +207,7 @@ static void read_info_chunk(AVFormatContext *s, int64_t size)
for (i = 0; i < nb_entries; 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);
}
@@ -224,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 */
@@ -244,7 +240,7 @@ static int read_header(AVFormatContext *s)
/* parse each chunk */
found_data = 0;
- while (!pb->eof_reached) {
+ while (!url_feof(pb)) {
/* stop at data chunk if seeking is not supported or
data chunk size is unknown */
@@ -253,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 (url_feof(pb))
break;
switch (tag) {
@@ -289,15 +286,20 @@ static int read_header(AVFormatContext *s)
default:
#define _(x) ((x) >= ' ' ? (x) : ' ')
- av_log(s, AV_LOG_WARNING, "skipping CAF chunk: %08X (%c%c%c%c)\n",
- tag, _(tag>>24), _((tag>>16)&0xFF), _((tag>>8)&0xFF), _(tag&0xFF));
+ av_log(s, AV_LOG_WARNING, "skipping CAF chunk: %08X (%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)
@@ -306,7 +308,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 {
@@ -335,13 +337,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 (url_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);
}
@@ -392,7 +396,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..cd3a0be
--- a/dev/null
+++ b/libavformat/cafenc.c
@@ -0,0 +1,280 @@
+/*
+ * 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) {
+ 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 (1024 - 4 * channels) * 8 / (4 * channels) + 1;
+ case AV_CODEC_ID_ADPCM_MS:
+ return (1024 - 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;
+
+ switch (enc->codec_id) {
+ case AV_CODEC_ID_AAC:
+ case AV_CODEC_ID_AC3:
+ 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:
+ case AV_CODEC_ID_PCM_ALAW:
+ case AV_CODEC_ID_PCM_MULAW:
+ 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;
+ }
+
+ 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, samples_per_packet(enc->codec_id, enc->channels)); //< 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)); ///< 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..5ca3c80 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
*/
diff --git a/libavformat/cdg.c b/libavformat/cdg.c
index 974880a..2d40d3d 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
*/
@@ -60,6 +60,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;
}
@@ -68,5 +74,6 @@ AVInputFormat ff_cdg_demuxer = {
.long_name = NULL_IF_CONFIG_SMALL("CD Graphics"),
.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..ab8a846 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 (url_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/concat.c b/libavformat/concat.c
index 416bbf5..3bbc83d 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
*/
@@ -111,9 +111,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..428c749
--- a/dev/null
+++ b/libavformat/concatdec.c
@@ -0,0 +1,408 @@
+/*
+ * 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/avstring.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "avformat.h"
+#include "internal.h"
+#include "url.h"
+
+typedef struct {
+ char *url;
+ int64_t start_time;
+ int64_t duration;
+} ConcatFile;
+
+typedef struct {
+ AVClass *class;
+ ConcatFile *files;
+ ConcatFile *cur_file;
+ unsigned nb_files;
+ AVFormatContext *avf;
+ int safe;
+ int seekable;
+} 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;
+ size_t url_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));
+ }
+ 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 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);
+ 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);
+ 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;
+ 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);
+ 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;
+ AVStream *st, *source_st;
+ 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)
+ FAIL(ret);
+ } 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);
+ FAIL(ret);
+ }
+ file->duration = dur;
+ } 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)
+ FAIL(ret);
+ 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;
+ }
+
+ if ((ret = open_file(avf, 0)) < 0)
+ FAIL(ret);
+ for (i = 0; i < cat->avf->nb_streams; i++) {
+ if (!(st = avformat_new_stream(avf, NULL)))
+ FAIL(AVERROR(ENOMEM));
+ source_st = cat->avf->streams[i];
+ if ((ret = avcodec_copy_context(st->codec, source_st->codec)) < 0)
+ FAIL(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;
+
+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 concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
+{
+ ConcatContext *cat = avf->priv_data;
+ int ret;
+ int64_t delta;
+
+ while (1) {
+ if ((ret = av_read_frame(cat->avf, pkt)) != AVERROR_EOF ||
+ (ret = open_next_file(avf)) < 0)
+ break;
+ }
+ 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 },
+ { 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 3b30cc9..ac06380 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
*/
@@ -57,7 +57,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 f58e152..0458a2d 100644
--- a/libavformat/cutils.c
+++ b/libavformat/cutils.c
@@ -2,46 +2,25 @@
* 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
*/
#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
--- a/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/daud.c b/libavformat/daud.c
index bb7ab7f..6983785 100644
--- a/libavformat/daud.c
+++ b/libavformat/daud.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 (url_feof(pb))
return AVERROR(EIO);
size = avio_rb16(pb);
avio_rb16(pb); // unknown
@@ -77,7 +77,7 @@ 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",
};
#endif
diff --git a/libavformat/dfa.c b/libavformat/dfa.c
index fa32d1f..12516af 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
*/
@@ -36,13 +36,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);
@@ -62,6 +64,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;
}
diff --git a/libavformat/diracdec.c b/libavformat/diracdec.c
index f275212..6636ead 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
*/
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/dsicin.c b/libavformat/dsicin.c
index 6a7c8b9..4a54680 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 (url_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..23cbe93 100644
--- a/libavformat/dtsdec.c
+++ b/libavformat/dtsdec.c
@@ -2,20 +2,20 @@
* 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
*/
@@ -34,6 +34,7 @@ static int dts_probe(AVProbeData *p)
uint32_t state = -1;
int markers[3] = {0};
int sum, max;
+ int64_t diff = 0;
buf = p->buf;
@@ -54,12 +55,16 @@ static int dts_probe(AVProbeData *p)
if (state == DCA_MARKER_14B_LE)
if ((bytestream_get_be16(&bufp) & 0xF0FF) == 0xF007)
markers[2]++;
+
+ if (buf - p->buf >= 4)
+ diff += FFABS(AV_RL16(buf) - AV_RL16(buf-4));
}
sum = markers[0] + markers[1] + markers[2];
max = markers[1] > markers[0];
max = markers[2] > markers[max] ? 2 : max;
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..55c4ca6
--- a/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 (!url_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/dv.c b/libavformat/dv.c
index b0dad63..e3b0d0a 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 DVprofile* sys; /* Current DV profile. E.g.: 525/60, 625/50 */
@@ -89,6 +91,9 @@ static const uint8_t *dv_extract_pack(uint8_t *frame, enum dv_pack_type t)
case dv_video_control:
offs = (80 * 5 + 48 + 5);
break;
+ case dv_timecode:
+ offs = (80*1 + 3 + 3);
+ break;
default:
return NULL;
}
@@ -137,9 +142,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 +159,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;
@@ -278,11 +289,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);
avctx->time_base = c->sys->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 +304,22 @@ static int dv_extract_video_info(DVDemuxContext *c, uint8_t *frame)
return size;
}
+static int dv_extract_timecode(DVDemuxContext* c, 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 +363,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 +378,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 +404,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;
@@ -413,10 +437,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;
}
@@ -430,6 +457,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;
@@ -441,7 +500,7 @@ static int dv_read_header(AVFormatContext *s)
state = avio_rb32(s->pb);
while ((state & 0xffffff7f) != 0x1f07003f) {
- if (s->pb->eof_reached) {
+ if (url_feof(s->pb)) {
av_log(s, AV_LOG_ERROR, "Cannot find DV header.\n");
return -1;
}
@@ -456,7 +515,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);
@@ -473,6 +532,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;
}
@@ -484,13 +546,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;
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 93ae0b5..e37bd23 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 DVprofile* 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] = {
@@ -77,34 +82,15 @@ 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;
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);
@@ -369,6 +355,10 @@ static void dv_delete_mux(DVMuxContext *c)
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"
@@ -376,7 +366,19 @@ static int dv_write_header(AVFormatContext *s)
" (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 a1b85fe..22ee2a9 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
*/
@@ -65,12 +65,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);
@@ -90,7 +90,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')){
@@ -103,14 +103,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 && !url_feof(pb)){
tag = avio_rl32(pb);
fsize = avio_rl32(pb);
if(tag == MKTAG('d', 'a', 't', 'a')) break;
@@ -168,7 +168,7 @@ 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){
+ while(!url_feof(s->pb) && c->frames){
avio_read(s->pb, buf, 4);
switch(AV_RL32(buf)){
case MKTAG('N', 'U', 'L', 'L'):
@@ -191,7 +191,7 @@ static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt)
size = AV_RB32(buf + 5);
if(size > 0xFFFFFF){
av_log(s, AV_LOG_ERROR, "Frame size is too big: %d\n", size);
- return -1;
+ return AVERROR_INVALIDDATA;
}
if(av_new_packet(pkt, size + DXA_EXTRA_SIZE + pal_size) < 0)
return AVERROR(ENOMEM);
@@ -209,10 +209,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 9d00c2d..97c19c9 100644
--- a/libavformat/electronicarts.c
+++ b/libavformat/electronicarts.c
@@ -2,20 +2,20 @@
* 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
*/
@@ -66,6 +66,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;
@@ -106,7 +107,7 @@ static int process_audio_header_elements(AVFormatContext *s)
ea->sample_rate = -1;
ea->num_channels = 1;
- while (!pb->eof_reached && in_header) {
+ while (!url_feof(pb) && in_header) {
int in_subheader;
uint8_t byte;
byte = avio_r8(pb);
@@ -115,7 +116,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 (!url_feof(pb) && in_subheader) {
uint8_t subbyte;
subbyte = avio_r8(pb);
@@ -209,8 +210,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) {
@@ -218,7 +218,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;
@@ -227,15 +234,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;
}
@@ -276,9 +282,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);
}
}
@@ -304,15 +310,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)
@@ -350,7 +364,7 @@ static int process_ea_header(AVFormatContext *s)
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);
@@ -362,7 +376,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);
@@ -378,7 +392,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:
@@ -403,7 +416,7 @@ static int process_ea_header(AVFormatContext *s)
break;
case MVhd_TAG:
- process_video_header_vp6(s);
+ err = process_video_header_vp6(s);
break;
}
@@ -447,7 +460,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) {
@@ -458,12 +471,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) {
@@ -513,11 +531,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)
@@ -545,6 +564,11 @@ 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;
+ }
ret = av_get_packet(pb, pkt, chunk_size);
if (ret < 0)
return ret;
@@ -615,9 +639,15 @@ static int ea_read_packet(AVFormatContext *s, AVPacket *pkt)
key = AV_PKT_FLAG_KEY;
case MV0F_TAG:
get_video_packet:
- 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;
@@ -629,6 +659,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
--- a/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
index 70c3e88..b392b8d 100644
--- a/libavformat/ffm.h
+++ b/libavformat/ffm.h
@@ -1,21 +1,21 @@
/*
- * FFM (avserver live feed) common header
+ * FFM (ffserver live feed) common header
* 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
*/
@@ -54,6 +54,7 @@ typedef struct FFMContext {
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
index e6730eb..b20ee13 100644
--- a/libavformat/ffmdec.c
+++ b/libavformat/ffmdec.c
@@ -1,21 +1,21 @@
/*
- * FFM (avserver live feed) demuxer
+ * FFM (ffserver live feed) 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
*/
@@ -24,6 +24,7 @@
#include "avformat.h"
#include "internal.h"
#include "ffm.h"
+#include "avio_internal.h"
static int ffm_is_avail_data(AVFormatContext *s, int size)
{
@@ -60,7 +61,7 @@ static int ffm_resync(AVFormatContext *s, int state)
{
av_log(s, AV_LOG_ERROR, "resyncing\n");
while (state != PACKET_ID) {
- if (s->pb->eof_reached) {
+ if (url_feof(s->pb)) {
av_log(s, AV_LOG_ERROR, "cannot find FFM syncword\n");
return -1;
}
@@ -89,6 +90,11 @@ static int ffm_read_data(AVFormatContext *s,
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)
@@ -105,8 +111,8 @@ static int ffm_read_data(AVFormatContext *s,
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 * 3) {
- avio_seek(pb, -ffm->packet_size * 2, SEEK_CUR);
+ 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 */
@@ -222,6 +228,138 @@ static int ffm_close(AVFormatContext *s)
return 0;
}
+static int ffm2_read_header(AVFormatContext *s)
+{
+ FFMContext *ffm = s->priv_data;
+ AVStream *st;
+ AVIOContext *pb = s->pb;
+ AVCodecContext *codec;
+
+ 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;
+ }
+
+ while(!url_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)
+ 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_alloc_extradata(codec, avio_rb32(pb)))
+ return AVERROR(ENOMEM);
+ avio_read(pb, codec->extradata, codec->extradata_size);
+ }
+ 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 -1;
+}
static int ffm_read_header(AVFormatContext *s)
{
@@ -234,6 +372,8 @@ static int ffm_read_header(AVFormatContext *s)
/* 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);
@@ -243,7 +383,7 @@ static int ffm_read_header(AVFormatContext *s)
/* get also filesize */
if (pb->seekable) {
ffm->file_size = avio_size(pb);
- if (ffm->write_index)
+ if (ffm->write_index && 0)
adjust_write_index(s);
} else {
ffm->file_size = (UINT64_C(1) << 63) - 1;
@@ -326,9 +466,7 @@ static int ffm_read_header(AVFormatContext *s)
goto fail;
}
if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
- codec->extradata_size = avio_rb32(pb);
- codec->extradata = av_malloc(codec->extradata_size);
- if (!codec->extradata)
+ if (ff_alloc_extradata(codec, avio_rb32(pb)))
return AVERROR(ENOMEM);
avio_read(pb, codec->extradata, codec->extradata_size);
}
@@ -380,7 +518,9 @@ static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt)
duration = AV_RB24(ffm->header + 5);
- av_new_packet(pkt, size);
+ 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);
@@ -422,11 +562,25 @@ static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, in
av_dlog(s, "wanted_pts=%0.6f\n", wanted_pts / 1000000.0);
/* find the position using linear interpolation (better than
dichotomy in typical cases) */
- pos_min = FFM_PACKET_SIZE;
- pos_max = ffm->file_size - FFM_PACKET_SIZE;
+ 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);
@@ -464,14 +618,14 @@ 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] == '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 (AVserver live feed)"),
+ .long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed)"),
.priv_data_size = sizeof(FFMContext),
.read_probe = ffm_probe,
.read_header = ffm_read_header,
diff --git a/libavformat/ffmenc.c b/libavformat/ffmenc.c
index 91658e1..eb809eb 100644
--- a/libavformat/ffmenc.c
+++ b/libavformat/ffmenc.c
@@ -1,28 +1,28 @@
/*
- * FFM (avserver live feed) muxer
+ * FFM (ffserver live feed) muxer
* 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 <assert.h>
-
#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"
@@ -36,7 +36,7 @@ static void flush_packet(AVFormatContext *s)
fill_size = ffm->packet_end - ffm->packet_ptr;
memset(ffm->packet_ptr, 0, fill_size);
- assert(avio_tell(pb) % ffm->packet_size == 0);
+ av_assert1(avio_tell(pb) % ffm->packet_size == 0);
/* put header */
avio_wb16(pb, PACKET_ID);
@@ -83,21 +83,41 @@ static void ffm_write_data(AVFormatContext *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', '1'));
+ 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++) {
@@ -106,10 +126,14 @@ static int ffm_write_header(AVFormatContext *s)
}
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 */
@@ -119,6 +143,13 @@ static int ffm_write_header(AVFormatContext *s)
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:
@@ -165,20 +196,21 @@ static int ffm_write_header(AVFormatContext *s)
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;
}
- if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
- avio_wb32(pb, codec->extradata_size);
- avio_write(pb, codec->extradata, codec->extradata_size);
- }
}
+ pb = s->pb;
+
+ avio_wb64(pb, 0); // end of header
/* flush until end of block reached */
while ((avio_tell(pb) % ffm->packet_size) != 0)
@@ -189,7 +221,7 @@ static int ffm_write_header(AVFormatContext *s)
/* init packet mux */
ffm->packet_ptr = ffm->packet;
ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE;
- assert(ffm->packet_end >= ffm->packet);
+ av_assert0(ffm->packet_end >= ffm->packet);
ffm->frame_offset = 0;
ffm->dts = 0;
ffm->first_packet = 1;
@@ -199,11 +231,12 @@ static int ffm_write_header(AVFormatContext *s)
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 = pkt->dts;
+ dts = ffm->start_time + pkt->dts;
/* packet size & key_frame */
header[0] = pkt->stream_index;
header[1] = 0;
@@ -211,7 +244,7 @@ static int ffm_write_packet(AVFormatContext *s, AVPacket *pkt)
header[1] |= FLAG_KEY_FRAME;
AV_WB24(header+2, pkt->size);
AV_WB24(header+5, pkt->duration);
- AV_WB64(header+8, pkt->pts);
+ 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);
@@ -236,8 +269,7 @@ static int ffm_write_trailer(AVFormatContext *s)
AVOutputFormat ff_ffm_muxer = {
.name = "ffm",
- .long_name = NULL_IF_CONFIG_SMALL("FFM (AVserver live feed)"),
- .mime_type = "",
+ .long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed)"),
.extensions = "ffm",
.priv_data_size = sizeof(FFMContext),
.audio_codec = AV_CODEC_ID_MP2,
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..19c14e4 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 (!url_feof(s) && (buf[0] == ';' || buf[0] == '#' || buf[0] == 0));
}
static AVChapter *read_chapter(AVFormatContext *s)
@@ -128,14 +128,14 @@ static int read_header(AVFormatContext *s)
AVDictionary **m = &s->metadata;
uint8_t line[1024];
- while(!s->pb->eof_reached) {
+ while(!url_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 +145,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..2defc75 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 },
+ { "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,6 +104,17 @@ static int file_get_handle(URLContext *h)
static int file_check(URLContext *h, int mask)
{
+#if HAVE_ACCESS && defined(R_OK)
+ int ret = 0;
+ if (access(h->filename, F_OK) < 0)
+ return AVERROR(errno);
+ if (mask&AVIO_FLAG_READ)
+ if (access(h->filename, R_OK) >= 0)
+ ret |= AVIO_FLAG_READ;
+ if (mask&AVIO_FLAG_WRITE)
+ if (access(h->filename, W_OK) >= 0)
+ ret |= AVIO_FLAG_WRITE;
+#else
struct stat st;
int ret = stat(h->filename, &st);
if (ret < 0)
@@ -83,7 +122,7 @@ static int file_check(URLContext *h, int mask)
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 +133,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 +155,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 +169,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 +232,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 3fa6842..1cd1a48 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;
}
@@ -80,7 +80,7 @@ static int read_packet(AVFormatContext *s,
FilmstripDemuxContext *film = s->priv_data;
AVStream *st = s->streams[0];
- if (s->pb->eof_reached)
+ if (url_feof(s->pb))
return AVERROR(EIO);
pkt->dts = avio_tell(s->pb) / (st->codec->width * (st->codec->height + film->leading) * 4);
pkt->size = av_get_packet(s->pb, pkt, st->codec->width * st->codec->height * 4);
diff --git a/libavformat/filmstripenc.c b/libavformat/filmstripenc.c
index 90d9a76..85d49be 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
*/
@@ -64,7 +64,7 @@ static int write_trailer(AVFormatContext *s)
avio_wb16(pb, st->codec->width);
avio_wb16(pb, st->codec->height);
avio_wb16(pb, 0); // leading
- avio_wb16(pb, 1/av_q2d(st->codec->time_base));
+ avio_wb16(pb, st->codec->time_base.den / st->codec->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 69d2724..12d73e4 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"
@@ -43,8 +45,7 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
if (type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types) || type < 0) {
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;
}
@@ -59,6 +60,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 +82,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) {
@@ -107,8 +108,7 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
goto fail;
}
if (!(data = av_buffer_alloc(len))) {
- ret = AVERROR(ENOMEM);
- goto fail;
+ RETURN_ERROR(AVERROR(ENOMEM));
}
if (avio_read(pb, data->data, len) != len) {
av_log(s, AV_LOG_ERROR, "Error reading attached picture data.\n");
@@ -119,8 +119,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 ecbb7ec..29310b8 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 (!url_feof(s->pb) && !metadata_last) {
avio_read(s->pb, header, 4);
avpriv_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 */
@@ -78,12 +77,10 @@ static int flac_read_header(AVFormatContext *s)
FLACStreaminfo si;
/* 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;
@@ -105,24 +102,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);
@@ -133,8 +131,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) {
@@ -147,6 +144,10 @@ static int flac_read_header(AVFormatContext *s)
}
return 0;
+
+fail:
+ av_free(buffer);
+ return ret;
}
static int flac_probe(AVProbeData *p)
diff --git a/libavformat/flacenc.c b/libavformat/flacenc.c
index 1e4042e..87e9362 100644
--- a/libavformat/flacenc.c
+++ b/libavformat/flacenc.c
@@ -2,25 +2,26 @@
* 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
*/
#include "libavcodec/flac.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "flacenc.h"
#include "vorbiscomment.h"
#include "libavcodec/bytestream.h"
@@ -31,17 +32,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, count;
uint8_t *p, *p0;
@@ -69,6 +67,15 @@ static int flac_write_header(struct AVFormatContext *s)
int ret;
AVCodecContext *codec = s->streams[0]->codec;
+ 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);
+ }
+
ret = ff_flac_write_header(s->pb, codec, 0);
if (ret)
return ret;
diff --git a/libavformat/flacenc.h b/libavformat/flacenc.h
index 2edda67..e83ee32 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 c1f7c86..e16c14b 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..7235f2e 100644
--- a/libavformat/flic.c
+++ b/libavformat/flic.c
@@ -2,20 +2,20 @@
* FLI/FLC Animation File Demuxer
* 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 c65c90c..1024001 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,6 +53,7 @@ typedef struct {
} validate_index[2];
int validate_next;
int validate_count;
+ int searched_for_end;
} FLVContext;
static int flv_probe(AVProbeData *p)
@@ -80,6 +77,11 @@ static AVStream *create_stream(AVFormatContext *s, int codec_type)
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 +191,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 +230,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 +246,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);
@@ -254,8 +257,11 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream,
case FLV_CODECID_H264:
vcodec->codec_id = AV_CODEC_ID_H264;
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 +287,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, "Skiping 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 +345,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 +355,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 +395,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)
@@ -481,6 +486,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") ||
@@ -514,6 +524,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".
@@ -522,6 +533,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
@@ -540,10 +552,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)
@@ -576,6 +590,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);
@@ -588,19 +604,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_alloc_extradata(st->codec, size))
return AVERROR(ENOMEM);
- st->codec->extradata_size = size;
avio_read(s->pb, st->codec->extradata, st->codec->extradata_size);
return 0;
}
@@ -742,10 +757,12 @@ 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 */
@@ -756,7 +773,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
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)
+ if (url_feof(s->pb))
return AVERROR_EOF;
avio_skip(s->pb, 3); /* stream id, always 0 */
flags = 0;
@@ -783,24 +800,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;
@@ -813,50 +834,66 @@ 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 (!is_audio &&
- st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
- if (flv_same_video_codec(st->codec, flags))
+ } 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 (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);
- av_dlog(s, "%d %X %d \n", is_audio, flags, st->discard);
- 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 (i == s->nb_streams) {
+ 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", stream_type, flags, st->discard);
+ 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;
}
- if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY)
+ if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || stream_type == FLV_STREAM_TYPE_AUDIO)
av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME);
break;
}
// 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) >>
@@ -884,15 +921,16 @@ skip:
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;
@@ -904,19 +942,19 @@ skip:
if (flv->wrong_dts)
dts = AV_NOPTS_VALUE;
}
- if (type == 0) {
+ if (type == 0 && (!st->codec->extradata || st->codec->codec_id == AV_CODEC_ID_AAC)) {
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) {
+ if (st->codec->codec_id == AV_CODEC_ID_AAC && 0) {
MPEG4AudioConfig cfg;
- avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata,
- st->codec->extradata_size * 8, 1);
+ if (avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata,
+ st->codec->extradata_size * 8, 1) >= 0) {
st->codec->channels = cfg.channels;
st->codec->channel_layout = 0;
if (cfg.ext_sample_rate)
@@ -925,6 +963,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);
@@ -940,31 +979,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:
@@ -987,7 +1026,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,
@@ -1004,5 +1043,5 @@ AVInputFormat ff_flv_demuxer = {
.read_seek = flv_read_seek,
.read_close = flv_read_close,
.extensions = "flv",
- .priv_class = &class,
+ .priv_class = &flv_class,
};
diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
index ca453f6..9224103 100644
--- a/libavformat/flvenc.c
+++ b/libavformat/flvenc.c
@@ -1,37 +1,39 @@
/*
* 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 },
@@ -77,12 +79,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 +107,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 +150,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;
@@ -215,8 +218,9 @@ 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);
}
break;
case AVMEDIA_TYPE_AUDIO:
@@ -231,14 +235,16 @@ static int flv_write_header(AVFormatContext *s)
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");
+ 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 */
@@ -337,6 +343,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);
@@ -363,7 +385,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);
@@ -406,7 +428,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);
}
@@ -435,12 +457,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)
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;
@@ -452,9 +474,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;
@@ -462,7 +484,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;
@@ -473,11 +495,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 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;
@@ -526,6 +558,7 @@ 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_VP6F || enc->codec_id == AV_CODEC_ID_VP6A) {
if (enc->extradata_size)
@@ -535,7 +568,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 3a510cd..ac9100b 100644
--- a/libavformat/format.c
+++ b/libavformat/format.c
@@ -2,25 +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 "avformat.h"
#include "internal.h"
+#include "libavutil/atomic.h"
#include "libavutil/avstring.h"
/**
@@ -52,22 +53,18 @@ void av_register_input_format(AVInputFormat *format)
{
AVInputFormat **p = &first_iformat;
- while (*p != NULL)
- p = &(*p)->next;
-
- *p = format;
format->next = NULL;
+ while(avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
+ p = &(*p)->next;
}
void av_register_output_format(AVOutputFormat *format)
{
AVOutputFormat **p = &first_oformat;
- while (*p != NULL)
- p = &(*p)->next;
-
- *p = format;
format->next = NULL;
+ while(avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
+ p = &(*p)->next;
}
int av_match_ext(const char *filename, const char *extensions)
@@ -134,7 +131,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 && match_format(short_name, fmt->name))
score += 100;
if (fmt->mime_type && mime_type && !strcmp(fmt->mime_type, mime_type))
score += 10;
@@ -154,6 +151,10 @@ enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name,
const char *filename, const char *mime_type,
enum AVMediaType type)
{
+ if (!strcmp(fmt->name, "segment") || !strcmp(fmt->name, "ssegment")) {
+ fmt = av_guess_format(NULL, filename, NULL);
+ }
+
if (type == AVMEDIA_TYPE_VIDEO) {
enum AVCodecID codec_id = AV_CODEC_ID_NONE;
diff --git a/libavformat/framecrcenc.c b/libavformat/framecrcenc.c
index dd55c12..dbe49b5 100644
--- a/libavformat/framecrcenc.c
+++ b/libavformat/framecrcenc.c
@@ -2,24 +2,25 @@
* 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 "libavutil/adler32.h"
+#include "libavutil/avstring.h"
#include "avformat.h"
#include "internal.h"
@@ -28,8 +29,31 @@ 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%08x\n",
+ snprintf(buf, sizeof(buf), "%d, %10"PRId64", %10"PRId64", %8d, %8d, 0x%08x",
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;
}
@@ -37,7 +61,6 @@ 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,
diff --git a/libavformat/framehash.c b/libavformat/framehash.c
index 28e9e84..f97f59b 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->streams[0]->codec->flags & CODEC_FLAG_BITEXACT))
+ avio_printf(s->pb, "#software: %s\n", LIBAVFORMAT_IDENT);
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den);
diff --git a/libavformat/frmdec.c b/libavformat/frmdec.c
new file mode 100644
index 0000000..a6f19af
--- a/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..ed9a3db
--- a/dev/null
+++ b/libavformat/ftp.c
@@ -0,0 +1,721 @@
+/*
+ * 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;
+ 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);
+
+ if (strlen(buf) < 4)
+ continue;
+
+ err = 0;
+ for (i = 0; i < 3; ++i) {
+ if (buf[i] < '0' || buf[i] > '9')
+ continue;
+ err *= 10;
+ err += buf[i] - '0';
+ }
+ dash = !!(buf[3] == '-');
+
+ for (i = 0; response_codes[i]; ++i) {
+ if (err == response_codes[i]) {
+ if (line)
+ av_bprintf(&line_buffer, "%s", buf);
+ code_found = 1;
+ result = err;
+ break;
+ }
+ }
+ }
+
+ 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 ((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, 500, 530, 0}; /* 500, 530 are incorrect codes */
+ static const int pass_codes[] = {230, 503, 530, 0}; /* 503, 530 are incorrect codes */
+
+ /* 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(FTPContext *s)
+{
+ char *res = NULL, *start = NULL, *end = NULL;
+ int i;
+ static const char *command = "PASV\r\n";
+ static const int pasv_codes[] = {227, 501, 0}; /* 501 is incorrect code */
+
+ 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;
+ av_log(s, AV_LOG_ERROR, "Set passive mode failed\n"
+ "Your FTP server may use IPv6 which is not supported yet.\n");
+ 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, 501, 550, 0}; /* 501, 550 are incorrect codes */
+
+ 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, 550, 554, 0}; /* 550, 554 are incorrect codes */
+
+ 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, 500, 504, 0}; /* 500, 504 are incorrect codes */
+
+ 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, 500, 501, 0}; /* 500, 501 are incorrect codes */
+
+ 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_connect_control_connection(URLContext *h)
+{
+ char buf[CONTROL_BUFFER_SIZE], opts_format[20], *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) {
+ snprintf(opts_format, sizeof(opts_format), "%d", s->rw_timeout);
+ av_dict_set(&opts, "timeout", opts_format, 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;
+ }
+ }
+ return 0;
+}
+
+static int ftp_connect_data_connection(URLContext *h)
+{
+ int err;
+ char buf[CONTROL_BUFFER_SIZE], opts_format[20];
+ AVDictionary *opts = NULL;
+ FTPContext *s = h->priv_data;
+
+ if (!s->conn_data) {
+ /* Enter passive mode */
+ 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) {
+ snprintf(opts_format, sizeof(opts_format), "%d", s->rw_timeout);
+ av_dict_set(&opts, "timeout", opts_format, 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);
+
+ /* XXX: Simulate behaviour of lseek in file protocol, which could be treated as a reference */
+ new_pos = FFMAX(0, new_pos);
+ 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
--- a/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..f6e7625 100644
--- a/libavformat/gif.c
+++ b/libavformat/gif.c
@@ -4,347 +4,186 @@
*
* 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,
int loop_count, uint32_t *palette)
{
int i;
- unsigned int v;
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, 0); /* aspect ratio */
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, 0); /* aspect ratio */
}
- /* 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(pb, width, height, gif->loop, NULL);
+ } else {
+ gif_image_write_header(pb, 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 +192,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 ms) after the last frame", OFFSET(last_delay),
+ AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 65535, ENC },
{ NULL },
};
@@ -372,9 +213,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..2981bca
--- a/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 (url_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)) && !url_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 || url_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/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 6feb3c3..c36479a 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
*/
@@ -31,9 +31,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
@@ -94,12 +116,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;
@@ -143,6 +163,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:
@@ -150,6 +176,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;
@@ -226,6 +256,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);
@@ -239,7 +270,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);
}
}
@@ -249,15 +282,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 %u (%x)\n", map_cnt, map_cnt);
map_cnt = 1000;
@@ -317,8 +351,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;
@@ -329,6 +361,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];
@@ -363,10 +405,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
@@ -385,7 +438,7 @@ static int gxf_header(AVFormatContext *s) {
#define READ_ONE() \
{ \
- if (!max_interval-- || pb->eof_reached) \
+ if (!max_interval-- || url_feof(pb)) \
goto out; \
tmp = tmp << 8 | avio_r8(pb); \
}
@@ -447,7 +500,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 (!url_feof(pb))
av_log(s, AV_LOG_ERROR, "sync lost\n");
return -1;
}
@@ -499,7 +552,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..5fa5100 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);
}
@@ -863,6 +950,7 @@ static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt)
int64_t pos = avio_tell(pb);
int padding = 0;
int 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..8d882ae 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
*/
@@ -33,7 +33,7 @@ static int h261_probe(AVProbeData *p)
int src_fmt=0;
GetBitContext gb;
- init_get_bits(&gb, p->buf, p->buf_size*8);
+ init_get_bits8(&gb, p->buf, p->buf_size);
for(i=0; i<p->buf_size*8; i++){
if ((code & 0x01ff0000) || !(code & 0xff00)) {
diff --git a/libavformat/h263dec.c b/libavformat/h263dec.c
index 4d826d8..e6e0345 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
*/
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/hevcdec.c b/libavformat/hevcdec.c
new file mode 100644
index 0000000..88abcc6
--- a/dev/null
+++ b/libavformat/hevcdec.c
@@ -0,0 +1,66 @@
+/*
+ * RAW HEVC video demuxer
+ * Copyright (c) 2013 Dirk Farin <dirk.farin@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 "avformat.h"
+#include "rawdec.h"
+
+#include "libavcodec/hevc.h"
+
+static int hevc_probe(AVProbeData *p)
+{
+ uint32_t code = -1;
+ int vps = 0, sps = 0, pps = 0, irap = 0;
+ int i;
+
+ for (i = 0; i < p->buf_size - 1; i++) {
+ code = (code << 8) + p->buf[i];
+ if ((code & 0xffffff00) == 0x100) {
+ uint8_t nal2 = p->buf[i + 1];
+ int type = (code & 0x7E) >> 1;
+
+ if (code & 0x81) // forbidden and reserved zero bits
+ return 0;
+
+ if (nal2 & 0xf8) // reserved zero
+ return 0;
+
+ switch (type) {
+ case NAL_VPS: vps++; break;
+ case NAL_SPS: sps++; break;
+ case NAL_PPS: pps++; break;
+ case NAL_BLA_N_LP:
+ case NAL_BLA_W_LP:
+ case NAL_BLA_W_RADL:
+ case NAL_CRA_NUT:
+ case NAL_IDR_N_LP:
+ case NAL_IDR_W_RADL: irap++; break;
+ }
+ }
+ }
+
+ // printf("vps=%d, sps=%d, pps=%d, irap=%d\n", vps, sps, pps, irap);
+
+ if (vps && sps && pps && irap)
+ return AVPROBE_SCORE_EXTENSION + 1; // 1 more than .mpg
+ return 0;
+}
+
+FF_DEF_RAWVIDEO_DEMUXER(hevc, "raw HEVC video", hevc_probe, "hevc,h265,265", AV_CODEC_ID_HEVC)
diff --git a/libavformat/hls.c b/libavformat/hls.c
index ea16f8a..231f630 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -2,20 +2,20 @@
* Apple HTTP Live Streaming 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
*/
@@ -103,6 +103,8 @@ typedef struct HLSContext {
int64_t seek_timestamp;
int seek_flags;
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
} HLSContext;
static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
@@ -139,6 +141,8 @@ static void free_variant_list(HLSContext *c)
av_free(var);
}
av_freep(&c->variants);
+ av_freep(&c->cookies);
+ av_freep(&c->user_agent);
c->n_variants = 0;
}
@@ -208,14 +212,24 @@ static int parse_playlist(HLSContext *c, const char *url,
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;
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);
+
+ ret = avio_open2(&in, url, AVIO_FLAG_READ,
+ c->interrupt_callback, &opts);
+ av_dict_free(&opts);
+ if (ret < 0)
return ret;
}
@@ -229,7 +243,7 @@ static int parse_playlist(HLSContext *c, const char *url,
free_segment_list(var);
var->finished = 0;
}
- while (!in->eof_reached) {
+ while (!url_feof(in)) {
read_chomp_line(in, line, sizeof(line));
if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) {
struct variant_info info = {{0}};
@@ -324,19 +338,27 @@ fail:
return ret;
}
-static int open_input(struct variant *var)
+static int open_input(HLSContext *c, struct variant *var)
{
+ AVDictionary *opts = NULL;
+ int ret;
struct segment *seg = var->segments[var->cur_seq_no - var->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, "seekable", "0", 0);
+
if (seg->key_type == KEY_NONE) {
- return ffurl_open(&var->input, seg->url, AVIO_FLAG_READ,
- &var->parent->interrupt_callback, NULL);
+ ret = ffurl_open(&var->input, seg->url, AVIO_FLAG_READ,
+ &var->parent->interrupt_callback, &opts);
+ goto cleanup;
} 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)) {
URLContext *uc;
if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ,
- &var->parent->interrupt_callback, NULL) == 0) {
+ &var->parent->interrupt_callback, &opts) == 0) {
if (ffurl_read_complete(uc, var->key, sizeof(var->key))
!= sizeof(var->key)) {
av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n",
@@ -358,17 +380,25 @@ static int open_input(struct variant *var)
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;
+ goto cleanup;
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) {
+ /* Need to repopulate options */
+ av_dict_free(&opts);
+ av_dict_set(&opts, "seekable", "0", 0);
+ if ((ret = ffurl_connect(var->input, &opts)) < 0) {
ffurl_close(var->input);
var->input = NULL;
- return ret;
+ goto cleanup;
}
- return 0;
+ ret = 0;
}
- return AVERROR(ENOSYS);
+ else
+ ret = AVERROR(ENOSYS);
+
+cleanup:
+ av_dict_free(&opts);
+ return ret;
}
static int read_data(void *opaque, uint8_t *buf, int buf_size)
@@ -413,7 +443,7 @@ reload:
goto reload;
}
- ret = open_input(v);
+ ret = open_input(c, v);
if (ret < 0)
return ret;
}
@@ -446,11 +476,27 @@ reload:
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;
+ // 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);
+ }
+
if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0)
goto fail;
@@ -520,6 +566,7 @@ static int hls_read_header(AVFormatContext *s)
* 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. */
+ av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", v->segments[0]->url);
avformat_free_context(v->ctx);
v->ctx = NULL;
goto fail;
@@ -577,7 +624,7 @@ static int recheck_discard_flags(AVFormatContext *s, int first)
/* Check if any new streams are needed */
for (i = 0; i < c->n_variants; i++)
- c->variants[i]->cur_needed = 0;;
+ c->variants[i]->cur_needed = 0;
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
@@ -627,7 +674,7 @@ start:
AVStream *st;
ret = av_read_frame(var->ctx, &var->pkt);
if (ret < 0) {
- if (!var->pb.eof_reached)
+ if (!url_feof(&var->pb) && ret != AVERROR_EOF)
return ret;
reset_packet(&var->pkt);
break;
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 3dd4273..dcd53e5 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -2,20 +2,20 @@
* 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
*/
@@ -165,8 +165,10 @@ static int hls_start(AVFormatContext *s)
int err = 0;
if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
- c->basename, c->wrap ? c->number % c->wrap : c->number) < 0)
+ c->basename, c->wrap ? c->number % c->wrap : c->number) < 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,
@@ -249,6 +251,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) {
@@ -259,10 +262,12 @@ 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
+ is_ref_pkt = can_split = 0;
+
+ if (is_ref_pkt)
hls->duration = av_rescale(pkt->pts - hls->end_pts,
st->time_base.num, st->time_base.den);
@@ -314,10 +319,10 @@ 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(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(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(size), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E},
+ {"hls_wrap", "set number after which the index wraps", OFFSET(wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E},
{ NULL },
};
diff --git a/libavformat/hlsproto.c b/libavformat/hlsproto.c
index ec357de..f6fcbe5 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 (!url_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/http.c b/libavformat/http.c
index 344507e..c5b5c53 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
*/
@@ -33,7 +33,7 @@
#include <zlib.h>
#endif
-/* 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
@@ -50,18 +50,29 @@ typedef struct {
int line_count;
int http_code;
int64_t chunksize; /**< Used if "Transfer-Encoding: chunked" otherwise -1. */
+ char *content_type;
+ char *user_agent;
int64_t off, filesize;
+ int icy_data_read; ///< how much data was read since last ICY metadata packet
+ int icy_metaint; ///< after how many bytes of read data a new metadata packet will be found
char location[MAX_URL_SIZE];
HTTPAuthState auth_state;
HTTPAuthState proxy_auth_state;
char *headers;
int willclose; /**< Set if the server correctly handles Connection: close and will close the connection after feeding us the content. */
+ int seekable; /**< Control seekability, 0 = disable, 1 = enable, -1 = probe. */
int chunked_post;
int end_chunked_post; /**< A flag which indicates if the end of chunked encoding has been sent. */
int end_header; /**< A flag which indicates we have finished to read POST reply. */
int multiple_requests; /**< A flag which indicates if we use persistent connections. */
uint8_t *post_data;
int post_datalen;
+ int is_akamai;
+ char *mime_type;
+ char *cookies; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
+ int icy;
+ char *icy_metadata_headers;
+ char *icy_metadata_packet;
#if CONFIG_ZLIB
int compressed;
z_stream inflate_stream;
@@ -74,11 +85,20 @@ typedef struct {
#define OFFSET(x) offsetof(HTTPContext, x)
#define D AV_OPT_FLAG_DECODING_PARAM
#define E AV_OPT_FLAG_ENCODING_PARAM
+#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", "custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|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", "force a content type", 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 },
{"multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E },
-{"post_data", "custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D|E },
+{"post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D|E },
+{"mime_type", "set MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 },
+{"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, 0 },
+{"icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D },
+{"icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 },
+{"icy_metadata_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 },
{"auth_type", "HTTP authentication type", OFFSET(auth_state.auth_type), AV_OPT_TYPE_INT, {.i64 = HTTP_AUTH_NONE}, HTTP_AUTH_NONE, HTTP_AUTH_BASIC, D|E, "auth_type" },
{"none", "No auth method set, autodetect", 0, AV_OPT_TYPE_CONST, {.i64 = HTTP_AUTH_NONE}, 0, 0, D|E, "auth_type" },
{"basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, {.i64 = HTTP_AUTH_BASIC}, 0, 0, D|E, "auth_type" },
@@ -174,8 +194,7 @@ static int http_open_cnx(URLContext *h, AVDictionary **options)
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;
@@ -183,8 +202,7 @@ static int http_open_cnx(URLContext *h, AVDictionary **options)
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;
@@ -192,8 +210,7 @@ static int http_open_cnx(URLContext *h, AVDictionary **options)
if ((s->http_code == 301 || s->http_code == 302 || 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
@@ -206,8 +223,7 @@ static int http_open_cnx(URLContext *h, AVDictionary **options)
return 0;
fail:
if (s->hd)
- ffurl_close(s->hd);
- s->hd = NULL;
+ ffurl_closep(&s->hd);
return AVERROR(EIO);
}
@@ -218,6 +234,7 @@ int ff_http_do_new_request(URLContext *h, const char *uri)
int ret;
s->off = 0;
+ s->icy_data_read = 0;
av_strlcpy(s->location, uri, sizeof(s->location));
av_dict_copy(&options, s->chained_options, 0);
@@ -232,7 +249,10 @@ static int http_open(URLContext *h, const char *uri, int flags,
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;
av_strlcpy(s->location, uri, sizeof(s->location));
@@ -296,6 +316,7 @@ static int process_line(URLContext *h, char *line, int line_count,
{
HTTPContext *s = h->priv_data;
char *tag, *p, *end;
+ char redirected_location[MAX_URL_SIZE];
/* end of header */
if (line[0] == '\0') {
@@ -335,7 +356,8 @@ static int process_line(URLContext *h, char *line, int line_count,
while (av_isspace(*p))
p++;
if (!av_strcasecmp(tag, "Location")) {
- av_strlcpy(s->location, p, sizeof(s->location));
+ ff_make_absolute_url(redirected_location, sizeof(redirected_location), s->location, p);
+ av_strlcpy(s->location, redirected_location, sizeof(s->location));
*new_location = 1;
} else if (!av_strcasecmp (tag, "Content-Length") && s->filesize == -1) {
s->filesize = strtoll(p, NULL, 10);
@@ -348,8 +370,9 @@ static int process_line(URLContext *h, char *line, int line_count,
if ((slash = strchr(p, '/')) && strlen(slash) > 0)
s->filesize = strtoll(slash+1, NULL, 10);
}
- h->is_streamed = 0; /* we _can_ in fact seek */
- } else if (!av_strcasecmp(tag, "Accept-Ranges") && !strncmp(p, "bytes", 5)) {
+ if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647))
+ h->is_streamed = 0; /* we _can_ in fact seek */
+ } else if (!av_strcasecmp(tag, "Accept-Ranges") && !strncmp(p, "bytes", 5) && s->seekable == -1) {
h->is_streamed = 0;
} else if (!av_strcasecmp (tag, "Transfer-Encoding") && !av_strncasecmp(p, "chunked", 7)) {
s->filesize = -1;
@@ -363,6 +386,34 @@ 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") && !av_strcasecmp (p, "AkamaiGHost")) {
+ s->is_akamai = 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)) {
+ // Concat all Icy- header lines
+ char *buf = av_asprintf("%s%s: %s\n",
+ s->icy_metadata_headers ? s->icy_metadata_headers : "", tag, p);
+ if (!buf)
+ return AVERROR(ENOMEM);
+ av_freep(&s->icy_metadata_headers);
+ s->icy_metadata_headers = buf;
} else if (!av_strcasecmp (tag, "Content-Encoding")) {
if (!av_strncasecmp(p, "gzip", 4) || !av_strncasecmp(p, "deflate", 7)) {
#if CONFIG_ZLIB
@@ -386,13 +437,109 @@ static int process_line(URLContext *h, char *line, int line_count,
// 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 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))) {
+ cookie = NULL;
+ if (!av_strncasecmp("path=", param, 5)) {
+ av_free(cpath);
+ cpath = av_strdup(&param[5]);
+ } else if (!av_strncasecmp("domain=", param, 7)) {
+ av_free(cdomain);
+ cdomain = av_strdup(&param[7]);
+ } else if (!av_strncasecmp("secure", param, 6) ||
+ !av_strncasecmp("comment", param, 7) ||
+ !av_strncasecmp("max-age", param, 7) ||
+ !av_strncasecmp("version", param, 7)) {
+ // ignore Comment, Max-Age, Secure and Version
+ } else {
+ av_free(cvalue);
+ cvalue = av_strdup(param);
+ }
+ }
+ 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!) */
@@ -432,7 +579,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
{
HTTPContext *s = h->priv_data;
int post, err;
- char headers[1024] = "";
+ char headers[4096] = "";
char *authstr = NULL, *proxyauthstr = NULL;
int64_t off = s->off;
int len = 0;
@@ -469,12 +616,15 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
/* set default headers if needed */
if (!has_header(s->headers, "\r\nUser-Agent: "))
- len += av_strlcatf(headers + len, sizeof(headers) - len,
- "User-Agent: %s\r\n", LIBAVFORMAT_IDENT);
+ len += av_strlcatf(headers + len, sizeof(headers) - len,
+ "User-Agent: %s\r\n", s->user_agent);
if (!has_header(s->headers, "\r\nAccept: "))
len += av_strlcpy(headers + len, "Accept: */*\r\n",
sizeof(headers) - len);
- if (!has_header(s->headers, "\r\nRange: ") && !post)
+ // 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 && (s->off > 0 || s->seekable == -1))
len += av_strlcatf(headers + len, sizeof(headers) - len,
"Range: bytes=%"PRId64"-\r\n", s->off);
if (send_expect_100 && !has_header(s->headers, "\r\nExpect: "))
@@ -497,6 +647,21 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
if (!has_header(s->headers, "\r\nContent-Length: ") && s->post_data)
len += av_strlcatf(headers + len, sizeof(headers) - len,
"Content-Length: %d\r\n", s->post_datalen);
+ 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)) {
+ 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);
+ }
/* now add in custom headers */
if (s->headers)
@@ -530,6 +695,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
s->buf_end = s->buffer;
s->line_count = 0;
s->off = 0;
+ s->icy_data_read = 0;
s->filesize = -1;
s->willclose = 0;
s->end_chunked_post = 0;
@@ -569,6 +735,7 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size)
}
if (len > 0) {
s->off += len;
+ s->icy_data_read += len;
if (s->chunksize > 0)
s->chunksize -= len;
}
@@ -642,6 +809,32 @@ static int http_read(URLContext *h, uint8_t *buf, int size)
}
size = FFMIN(size, s->chunksize);
}
+ if (s->icy_metaint > 0) {
+ int remaining = s->icy_metaint - s->icy_data_read; /* until next metadata packet */
+ if (!remaining) {
+ // The metadata packet is variable sized. It has a 1 byte header
+ // which sets the length of the packet (divided by 16). If it's 0,
+ // the metadata doesn't change. After the packet, icy_metaint bytes
+ // of normal data follow.
+ int ch = http_getc(s);
+ if (ch < 0)
+ return ch;
+ if (ch > 0) {
+ char data[255 * 16 + 1];
+ int n;
+ int ret;
+ ch *= 16;
+ for (n = 0; n < ch; n++)
+ data[n] = http_getc(s);
+ data[ch + 1] = 0;
+ if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
+ return ret;
+ }
+ s->icy_data_read = 0;
+ remaining = s->icy_metaint;
+ }
+ size = FFMIN(size, remaining);
+ }
#if CONFIG_ZLIB
if (s->compressed)
return http_buf_read_compressed(h, buf, size);
@@ -708,7 +901,7 @@ static int http_close(URLContext *h)
}
if (s->hd)
- ffurl_close(s->hd);
+ ffurl_closep(&s->hd);
av_dict_free(&s->chained_options);
return ret;
}
@@ -796,7 +989,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;
}
@@ -811,7 +1004,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);
@@ -867,8 +1063,7 @@ 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;
}
diff --git a/libavformat/http.h b/libavformat/http.h
index f0d9d4a..a19ad8e 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
*/
@@ -38,7 +38,7 @@ 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
diff --git a/libavformat/httpauth.c b/libavformat/httpauth.c
index b96da3e..5ca48b9 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
*/
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/icodec.c b/libavformat/icodec.c
new file mode 100644
index 0000000..fa308da
--- a/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 / 3;
+ 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(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..561c6ca
--- a/dev/null
+++ b/libavformat/icoenc.c
@@ -0,0 +1,202 @@
+/*
+ * 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 {
+ av_log(s, AV_LOG_ERROR, "Unsupported codec %s\n", c->codec_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(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..d73adc7 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",
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..4bc76a3 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"
@@ -258,7 +271,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
* Parse a text tag.
*/
static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen,
- const char *key)
+ AVDictionary **metadata, const char *key)
{
uint8_t *dst;
int encoding, dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_VAL;
@@ -293,7 +306,7 @@ 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);
}
/**
@@ -487,7 +500,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,6 +518,53 @@ fail:
avio_seek(pb, end, SEEK_SET);
}
+static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, char *ttag, ID3v2ExtraMeta **extra_meta)
+{
+ AVRational time_base = {1, 1000};
+ uint32_t start, end;
+ AVChapter *chapter;
+ uint8_t *dst = NULL;
+ int taglen;
+ char tag[5];
+
+ 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) {
+ avio_read(pb, tag, 4);
+ tag[4] = 0;
+ taglen = avio_rb32(pb);
+ avio_skip(pb, 2);
+ len -= 10;
+ if (taglen < 0 || taglen > len) {
+ av_free(dst);
+ return;
+ }
+ 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);
+ av_free(dst);
+}
+
typedef struct ID3v2EMFunc {
const char *tag3;
const char *tag4;
@@ -516,6 +576,7 @@ typedef struct ID3v2EMFunc {
static const ID3v2EMFunc id3v2_extra_meta_funcs[] = {
{ "GEO", "GEOB", read_geobtag, free_geobtag },
{ "PIC", "APIC", read_apic, free_apic },
+ { "CHAP","CHAP", read_chapter, NULL },
{ NULL }
};
@@ -528,7 +589,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)))
@@ -541,7 +602,8 @@ static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
static void id3v2_parse(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;
int taghdrlen;
@@ -550,7 +612,11 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
AVIOContext *pbx;
unsigned char *buffer = NULL;
int buffer_size = 0;
- const ID3v2EMFunc *extra_func;
+ const ID3v2EMFunc *extra_func = NULL;
+ unsigned char *uncompressed_buffer = NULL;
+ int uncompressed_buffer_size = 0;
+
+ av_log(s, AV_LOG_DEBUG, "id3v2 ver:%d flags:%02X len:%d\n", version, flags, len);
switch (version) {
case 2:
@@ -586,11 +652,19 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
goto error;
}
avio_skip(s->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 dlen;
if (isv34) {
avio_read(s->pb, tag, 4);
@@ -606,13 +680,13 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
tag[3] = 0;
tlen = avio_rb24(s->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;
+
+ if (len < 0)
+ break;
+
next = avio_tell(s->pb) + tlen;
if (!tlen) {
@@ -623,30 +697,50 @@ 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(s->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);
+ av_log(s, AV_LOG_WARNING, "Skipping %s ID3v2 frame %s.\n", type, tag);
avio_skip(s->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 = s->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(s->pb) + tlen;
+ uint8_t *b;
+
b = buffer;
- while (avio_tell(s->pb) < end && !s->pb->eof_reached) {
+ while (avio_tell(s->pb) < end && b - buffer < tlen && !s->pb->eof_reached) {
*b++ = avio_r8(s->pb);
if (*(b - 1) == 0xff && avio_tell(s->pb) < end - 1 &&
+ b - buffer < tlen &&
!s->pb->eof_reached ) {
uint8_t val = avio_r8(s->pb);
*b++ = val ? val : avio_r8(s->pb);
@@ -656,18 +750,48 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
NULL);
tlen = b - buffer;
pbx = &pb; // read from sync buffer
- } else {
- pbx = s->pb; // read straight from input
}
+
+#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(s->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, uncompressed_buffer, dlen, 0, NULL, NULL, NULL, NULL);
+ tlen = dlen;
+ pbx = &pb; // read from sync buffer
+ }
+#endif
if (tag[0] == 'T')
/* parse text tag */
- read_ttag(s, pbx, tlen, tag);
+ read_ttag(s, pbx, tlen, &s->metadata, tag);
else
/* parse special meta tag */
extra_func->read(s, pbx, tlen, tag, extra_meta);
} else if (!tag[0]) {
if (tag[1])
- av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
+ av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding\n");
avio_skip(s->pb, tlen);
break;
}
@@ -686,6 +810,7 @@ error:
version, reason);
avio_seek(s->pb, end, SEEK_SET);
av_free(buffer);
+ av_free(uncompressed_buffer);
return;
}
@@ -701,8 +826,10 @@ void ff_id3v2_read(AVFormatContext *s, const char *magic,
/* 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)
+ if (ret != ID3v2_HEADER_SIZE) {
+ avio_seek(s->pb, off, SEEK_SET);
break;
+ }
found_header = ff_id3v2_match(buf, magic);
if (found_header) {
/* parse ID3v2 header */
diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h
index 7cb4296..e893922 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
*/
diff --git a/libavformat/id3v2enc.c b/libavformat/id3v2enc.c
index df00f05..6052244 100644
--- a/libavformat/id3v2enc.c
+++ b/libavformat/id3v2enc.c
@@ -1,32 +1,36 @@
/*
* 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
*/
#include <stdint.h>
#include <string.h>
+#include "libavutil/avstring.h"
#include "libavutil/dict.h"
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "avio.h"
+#include "avio_internal.h"
#include "id3v2.h"
+#define PADDING_BYTES 10
+
static void id3v2_put_size(AVIOContext *pb, int size)
{
avio_w8(pb, size >> 21 & 0x7f);
@@ -109,6 +113,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)
{
@@ -123,31 +165,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;
}
@@ -155,6 +197,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];
@@ -195,6 +295,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);
@@ -222,7 +326,15 @@ int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt)
void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb)
{
- int64_t cur_pos = avio_tell(pb);
+ int64_t cur_pos;
+
+ /* adding an arbitrary amount of padding bytes at the end of the
+ * ID3 metadata fixes cover art display for some software (iTunes,
+ * Traktor, Serato, Torq) */
+ 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);
diff --git a/libavformat/idcin.c b/libavformat/idcin.c
index 2536e8b..9671fca 100644
--- a/libavformat/idcin.c
+++ b/libavformat/idcin.c
@@ -2,20 +2,20 @@
* id Quake II CIN File Demuxer
* 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,7 @@ typedef struct IdcinDemuxContext {
static int idcin_probe(AVProbeData *p)
{
- unsigned int number;
+ unsigned int number, sample_rate;
/*
* This is what you could call a "probabilistic" file check: id CIN
@@ -122,18 +122,18 @@ static int idcin_probe(AVProbeData *p)
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;
/* return half certainty since this check is a bit sketchy */
@@ -196,8 +196,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);
+ if (ff_alloc_extradata(st->codec, HUFFMAN_TABLE_SIZE))
+ return AVERROR(ENOMEM);
ret = avio_read(pb, st->codec->extradata, HUFFMAN_TABLE_SIZE);
if (ret < 0) {
return ret;
@@ -260,7 +260,7 @@ static int idcin_read_packet(AVFormatContext *s,
unsigned char palette_buffer[768];
uint32_t palette[256];
- if (s->pb->eof_reached)
+ if (url_feof(s->pb))
return s->pb->error ? s->pb->error : AVERROR_EOF;
if (idcin->next_chunk_is_video) {
@@ -288,7 +288,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 +305,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)
@@ -317,9 +321,9 @@ static int idcin_read_packet(AVFormatContext *s,
pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE,
AVPALETTE_SIZE);
- if (ret < 0) {
+ if (!pal) {
av_free_packet(pkt);
- return ret;
+ return AVERROR(ENOMEM);
}
memcpy(pal, palette, AVPALETTE_SIZE);
pkt->flags |= AV_PKT_FLAG_KEY;
diff --git a/libavformat/idroqdec.c b/libavformat/idroqdec.c
index 82eff24..8cdd72e 100644
--- a/libavformat/idroqdec.c
+++ b/libavformat/idroqdec.c
@@ -2,20 +2,20 @@
* id RoQ (.roq) File Demuxer
* 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 (url_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..50c4280 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
*/
diff --git a/libavformat/iff.c b/libavformat/iff.c
index 79f5f16..edf308b 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
*/
@@ -29,13 +28,19 @@
* http://wiki.multimedia.cx/index.php?title=IFF
*/
+#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 "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')
@@ -43,7 +48,13 @@
#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_FORM MKTAG('F','O','R','M')
#define ID_ANNO MKTAG('A','N','N','O')
@@ -54,31 +65,49 @@
#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;
+ 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,
@@ -102,19 +131,38 @@ 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_RGBN) )
return AVPROBE_SCORE_MAX;
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;
+ uint8_t *buf;
uint32_t chunk_id, data_size;
- int compression = -1;
+ 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)
@@ -125,8 +173,12 @@ static int iff_read_header(AVFormatContext *s)
avio_skip(pb, 8);
// codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content
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(!url_feof(pb)) {
uint64_t orig_pos;
int res;
const char *metadata_tag = NULL;
@@ -144,12 +196,38 @@ 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_MDAT:
iff->body_pos = avio_tell(pb);
+ iff->body_end = iff->body_pos + data_size;
iff->body_size = data_size;
break;
@@ -165,17 +243,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 %d\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;
@@ -187,38 +271,78 @@ 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_ANNO:
- case ID_TEXT:
- metadata_tag = "comment";
+ 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_AUTH:
- metadata_tag = "artist";
+ 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_COPYRIGHT:
- metadata_tag = "copyright";
+ 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_NAME:
- metadata_tag = "title";
+ 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"; break;
+ case ID_AUTH: metadata_tag = "artist"; break;
+ case ID_COPYRIGHT: metadata_tag = "copyright"; break;
+ case ID_NAME: metadata_tag = "title"; 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;
}
}
@@ -231,7 +355,29 @@ static int iff_read_header(AVFormatContext *s)
case AVMEDIA_TYPE_AUDIO:
avpriv_set_pts_info(st, 32, 1, st->codec->sample_rate);
- switch(compression) {
+ 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;
+ }
+
+ 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;
+ } else {
+ switch (iff->svx8_compression) {
case COMP_NONE:
st->codec->codec_id = AV_CODEC_ID_PCM_S8_PLANAR;
break;
@@ -242,27 +388,44 @@ static int iff_read_header(AVFormatContext *s)
st->codec->codec_id = AV_CODEC_ID_8SVX_EXP;
break;
default:
- av_log(s, AV_LOG_ERROR, "unknown compression method\n");
+ 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;
@@ -276,19 +439,37 @@ 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_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);
+ } 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;
}
@@ -300,4 +481,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 3b49a32..7539359 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
*/
@@ -31,8 +31,11 @@ typedef struct {
static const IdStrMap img_tags[] = {
{ AV_CODEC_ID_MJPEG, "jpeg" },
{ AV_CODEC_ID_MJPEG, "jpg" },
+ { AV_CODEC_ID_MJPEG, "jps" },
{ AV_CODEC_ID_LJPEG, "ljpg" },
+ { AV_CODEC_ID_JPEGLS, "jls" },
{ AV_CODEC_ID_PNG, "png" },
+ { AV_CODEC_ID_PNG, "pns" },
{ AV_CODEC_ID_PNG, "mng" },
{ AV_CODEC_ID_PPM, "ppm" },
{ AV_CODEC_ID_PPM, "pnm" },
@@ -45,28 +48,34 @@ 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_PCX, "pcx" },
+ { AV_CODEC_ID_BRENDER_PIX, "pix" },
{ AV_CODEC_ID_SUNRAST, "sun" },
{ AV_CODEC_ID_SUNRAST, "ras" },
{ AV_CODEC_ID_SUNRAST, "rs" },
{ AV_CODEC_ID_SUNRAST, "im1" },
{ AV_CODEC_ID_SUNRAST, "im8" },
{ AV_CODEC_ID_SUNRAST, "im24" },
+ { AV_CODEC_ID_SUNRAST, "im32" },
{ AV_CODEC_ID_SUNRAST, "sunras" },
+ { AV_CODEC_ID_JPEG2000, "j2c" },
{ AV_CODEC_ID_JPEG2000, "jp2" },
{ AV_CODEC_ID_JPEG2000, "jpc" },
{ AV_CODEC_ID_JPEG2000, "j2k" },
{ AV_CODEC_ID_DPX, "dpx" },
+ { AV_CODEC_ID_EXR, "exr" },
{ AV_CODEC_ID_PICTOR, "pic" },
+ { AV_CODEC_ID_V210X, "yuv10" },
{ AV_CODEC_ID_WEBP, "webp" },
{ AV_CODEC_ID_XBM, "xbm" },
+ { AV_CODEC_ID_XFACE, "xface" },
{ AV_CODEC_ID_XWD, "xwd" },
{ AV_CODEC_ID_NONE, NULL }
};
diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c
index 9acb6f6..5163e69 100644
--- a/libavformat/img2dec.c
+++ b/libavformat/img2dec.c
@@ -3,23 +3,24 @@
* 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 <sys/stat.h>
#include "libavutil/avstring.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
@@ -27,20 +28,43 @@
#include "libavutil/parseutils.h"
#include "avformat.h"
#include "internal.h"
+#if HAVE_GLOB
+#include <glob.h>
+
+/* 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 */
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. */
- char *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. */
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;
static const int sizes[][2] = {
@@ -70,15 +94,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 +142,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,6 +182,10 @@ 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 (av_match_ext(p->filename, "raw") || av_match_ext(p->filename, "gif"))
+ return 5;
else
return AVPROBE_SCORE_EXTENSION;
}
@@ -138,11 +195,9 @@ static int img_read_probe(AVProbeData *p)
static int 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 +212,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 +225,86 @@ 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)
+ 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) {
@@ -207,8 +314,12 @@ static int img_read_header(AVFormatContext *s1)
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = s1->audio_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 (st->codec->codec_id == AV_CODEC_ID_LJPEG)
+ st->codec->codec_id = AV_CODEC_ID_MJPEG;
}
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
pix_fmt != AV_PIX_FMT_NONE)
@@ -220,7 +331,8 @@ static int img_read_header(AVFormatContext *s1)
static int 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;
int size[3] = { 0 }, ret[3] = { 0 };
AVIOContext *f[3] = { NULL };
@@ -233,10 +345,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,7 +366,7 @@ 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;
}
@@ -257,14 +375,28 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
infer_size(&codec->width, &codec->height, size[0]);
} else {
f[0] = s1->pb;
- if (f[0]->eof_reached)
+ if (url_feof(f[0]))
return AVERROR(EIO);
- size[0] = 4096;
+ if (s->frame_size > 0) {
+ size[0] = s->frame_size;
+ } else {
+ size[0] = 4096;
+ }
}
- av_new_packet(pkt, size[0] + size[1] + size[2]);
+ if (av_new_packet(pkt, size[0] + size[1] + size[2]) < 0)
+ return AVERROR(ENOMEM);
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;
+ 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;
+ }
pkt->size = 0;
for (i = 0; i < 3; i++) {
@@ -283,18 +415,59 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
} 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 },
+ { "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, 1, DEC },
{ NULL },
};
@@ -312,6 +485,8 @@ AVInputFormat ff_image2_demuxer = {
.read_probe = img_read_probe,
.read_header = img_read_header,
.read_packet = img_read_packet,
+ .read_close = img_read_close,
+ .read_seek = img_read_seek,
.flags = AVFMT_NOFILE,
.priv_class = &img2_class,
};
diff --git a/libavformat/img2enc.c b/libavformat/img2enc.c
index 7b94869..8adf352 100644
--- a/libavformat/img2enc.c
+++ b/libavformat/img2enc.c
@@ -3,42 +3,48 @@
* 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/avstring.h"
#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.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;
} 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);
+ const char *str;
av_strlcpy(img->path, s->filename, sizeof(img->path));
@@ -48,74 +54,77 @@ static int write_header(AVFormatContext *s)
else
img->is_pipe = 1;
+ str = strrchr(img->path, '.');
+ img->split_planes = str
+ && !av_strcasecmp(str + 1, "y")
+ && s->nb_streams == 1
+ && st->codec->codec_id == AV_CODEC_ID_RAWVIDEO
+ && 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;
+ time(&now0);
+ tm = localtime(&now0);
+ 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] = ((int[]){'U','V','A','x'})[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 {
avio_write(pb[0], pkt->data, pkt->size);
}
avio_flush(pb[0]);
@@ -130,8 +139,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 +157,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,xbm",
+ .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",
.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 1bc3e51..36ee4c0 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
@@ -42,20 +46,18 @@ typedef struct CodecMime{
enum AVCodecID id;
} CodecMime;
-void ff_dynarray_add(intptr_t **tab_ptr, int *nb_ptr, intptr_t elem);
-
#ifdef __GNUC__
#define dynarray_add(tab, nb_ptr, elem)\
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
@@ -78,8 +80,9 @@ 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
*/
-void ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
+int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
int (*compare)(AVFormatContext *, AVPacket *, AVPacket *));
void ff_read_frame_flush(AVFormatContext *s);
@@ -243,6 +246,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().
*
@@ -312,6 +318,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.
*/
@@ -339,4 +347,27 @@ 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 choosen timebase allows sample accurate timestamps based
+ * on the framerate or sample rate for audio streams. It also is
+ * at least as precisse as 1/min_precission would be.
+ */
+AVRational ff_choose_timebase(AVFormatContext *s, AVStream *st, int min_precission);
+
+/**
+ * Generate standard extradata for AVC-Intra based on width/height and field order.
+ */
+void ff_generate_avci_extradata(AVStream *st);
+
+/**
+ * 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);
+
#endif /* AVFORMAT_INTERNAL_H */
diff --git a/libavformat/ipmovie.c b/libavformat/ipmovie.c
index 60ae939..676363b 100644
--- a/libavformat/ipmovie.c
+++ b/libavformat/ipmovie.c
@@ -2,20 +2,20 @@
* Interplay MVE File Demuxer
* 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 (url_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 (url_feof(pb)) {
chunk_type = CHUNK_EOF;
break;
}
@@ -476,7 +476,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 +527,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 +545,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 (url_feof(pb))
return AVERROR_EOF;
}
/* initialize private context members */
@@ -561,6 +563,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 +627,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 +637,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
--- a/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
--- a/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
--- a/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
--- a/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 014096d..112fbb3 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
*/
@@ -68,7 +68,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 */
@@ -81,13 +80,28 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
{ AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'B', 'G', 'R') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('b', '1', '6', 'g') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('b', '4', '8', 'r') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('b', 'x', 'b', 'g') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('b', 'x', 'r', 'g') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('b', 'x', 'y', 'v') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('N', 'O', '1', '6') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('D', 'V', 'O', 'O') }, /* Digital Voodoo SD 8 Bit */
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', '4', '2', '0') }, /* Radius DV YUV PAL */
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', '4', '1', '1') }, /* Radius DV YUV NTSC */
{ 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) */
@@ -131,11 +145,15 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
{ AV_CODEC_ID_8BPS, MKTAG('8', 'B', 'P', 'S') }, /* Planar RGB (8BPS) */
{ AV_CODEC_ID_SMC, MKTAG('s', 'm', 'c', ' ') }, /* Apple Graphics (SMC) */
{ AV_CODEC_ID_QTRLE, MKTAG('r', 'l', 'e', ' ') }, /* Apple Animation (RLE) */
+ { AV_CODEC_ID_SGIRLE, MKTAG('r', 'l', 'e', '1') }, /* SGI RLE 8-bit */
{ AV_CODEC_ID_MSRLE, MKTAG('W', 'R', 'L', 'E') },
{ AV_CODEC_ID_QDRAW, MKTAG('q', 'd', 'r', 'w') }, /* QuickDraw */
{ AV_CODEC_ID_RAWVIDEO, MKTAG('W', 'R', 'A', 'W') },
+ { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') }, /* HEVC/H.265 which indicates parameter sets shall not be in ES */
+ { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') }, /* HEVC/H.265 which indicates parameter sets may be in ES */
+
{ AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') }, /* AVC-1/H.264 */
{ AV_CODEC_ID_H264, MKTAG('a', 'i', '5', 'p') }, /* AVC-Intra 50M 720p24/30/60 */
{ AV_CODEC_ID_H264, MKTAG('a', 'i', '5', 'q') }, /* AVC-Intra 50M 720p25/50 */
@@ -149,9 +167,12 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
{ AV_CODEC_ID_H264, MKTAG('a', 'i', '1', '3') }, /* AVC-Intra 100M 1080p24/30/60 */
{ AV_CODEC_ID_H264, MKTAG('a', 'i', '1', '5') }, /* AVC-Intra 100M 1080i50 */
{ AV_CODEC_ID_H264, MKTAG('a', 'i', '1', '6') }, /* AVC-Intra 100M 1080i60 */
+ { AV_CODEC_ID_H264, MKTAG('a', 'i', 'v', 'x') }, /* XAVC 4:2:2 10bit */
+ { AV_CODEC_ID_H264, MKTAG('A', 'V', 'i', 'n') }, /* AVC-Intra with implicit SPS/PPS */
{ AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', '1') }, /* Apple MPEG-1 Camcorder */
{ AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'e', 'g') }, /* MPEG */
+ { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', ' ') },
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', '2', 'v', '1') }, /* Apple MPEG-2 Camcorder */
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('h', 'd', 'v', '1') }, /* MPEG2 HDV 720p30 */
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('h', 'd', 'v', '2') }, /* MPEG2 HDV 1080i60 */
@@ -169,6 +190,7 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '4', 'p') }, /* MPEG2 IMX PAL 625/50 40mb/s produced by FCP */
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '3', 'n') }, /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '3', 'p') }, /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
+ { AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', '5', '1') }, /* XDCAM HD422 720p30 CBR */
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', '5', '4') }, /* XDCAM HD422 720p24 CBR */
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', '5', '5') }, /* XDCAM HD422 720p25 CBR */
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', '5', '9') }, /* XDCAM HD422 720p60 CBR */
@@ -203,6 +225,7 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
{ AV_CODEC_ID_TIFF, MKTAG('t', 'i', 'f', 'f') }, /* TIFF embedded in MOV */
{ AV_CODEC_ID_GIF, MKTAG('g', 'i', 'f', ' ') }, /* embedded gif files as frames (usually one "click to play movie" frame) */
{ AV_CODEC_ID_PNG, MKTAG('p', 'n', 'g', ' ') },
+ { AV_CODEC_ID_PNG, MKTAG('M', 'N', 'G', ' ') },
{ AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') }, /* SMPTE RP 2025 */
{ AV_CODEC_ID_CAVS, MKTAG('a', 'v', 's', '2') },
@@ -215,12 +238,14 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
{ AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'V', 'u', 'p') },
{ AV_CODEC_ID_SGI, MKTAG('s', 'g', 'i', ' ') }, /* SGI */
{ AV_CODEC_ID_DPX, MKTAG('d', 'p', 'x', ' ') }, /* DPX */
+ { AV_CODEC_ID_EXR, MKTAG('e', 'x', 'r', ' ') }, /* OpenEXR */
{ AV_CODEC_ID_PRORES, MKTAG('a', 'p', 'c', 'h') }, /* Apple ProRes 422 High Quality */
{ AV_CODEC_ID_PRORES, MKTAG('a', 'p', 'c', 'n') }, /* Apple ProRes 422 Standard Definition */
{ AV_CODEC_ID_PRORES, MKTAG('a', 'p', 'c', 's') }, /* Apple ProRes 422 LT */
{ AV_CODEC_ID_PRORES, MKTAG('a', 'p', 'c', 'o') }, /* Apple ProRes 422 Proxy */
{ AV_CODEC_ID_PRORES, MKTAG('a', 'p', '4', 'h') }, /* Apple ProRes 4444 */
+ { AV_CODEC_ID_FLIC, MKTAG('f', 'l', 'i', 'c') },
{ AV_CODEC_ID_AIC, MKTAG('i', 'c', 'o', 'd') },
@@ -273,13 +298,17 @@ const AVCodecTag ff_codec_movaudio_tags[] = {
{ AV_CODEC_ID_QDM2, MKTAG('Q', 'D', 'M', '2') },
{ AV_CODEC_ID_QDMC, MKTAG('Q', 'D', 'M', 'C') },
{ AV_CODEC_ID_SPEEX, MKTAG('s', 'p', 'e', 'x') }, /* Flash Media Server */
+ { AV_CODEC_ID_SPEEX, MKTAG('S', 'P', 'X', 'N') },
{ 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 },
};
@@ -342,7 +371,7 @@ int ff_mov_lang_to_iso639(unsigned code, char to[4])
memset(to, 0, 4);
/* is it the mangled iso code? */
/* see http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt */
- if (code > 138) {
+ if (code >= 0x400 && code != 0x7fff) {
for (i = 2; i >= 0; i--) {
to[i] = 0x60 + (code & 0x1f);
code >>= 5;
@@ -414,6 +443,11 @@ int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext
avio_rb32(pb); /* max bitrate */
avio_rb32(pb); /* avg bitrate */
+ if(avcodec_is_open(st->codec)) {
+ av_log(fc, AV_LOG_DEBUG, "codec open in read_dec_config_descr\n");
+ return -1;
+ }
+
st->codec->codec_id= ff_codec_get_id(ff_mp4_obj_type, object_type_id);
av_dlog(fc, "esds object type id 0x%02x\n", object_type_id);
len = ff_mp4_read_descr(fc, pb, &tag);
@@ -422,11 +456,9 @@ 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)
+ if (ff_alloc_extradata(st->codec, len))
return AVERROR(ENOMEM);
avio_read(pb, st->codec->extradata, len);
- st->codec->extradata_size = len;
if (st->codec->codec_id == AV_CODEC_ID_AAC) {
MPEG4AudioConfig cfg;
avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata,
@@ -449,3 +481,95 @@ 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
+}
+
diff --git a/libavformat/isom.h b/libavformat/isom.h
index 94f1296..828e500 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
*/
@@ -94,6 +94,7 @@ typedef struct MOVSbgp {
typedef struct MOVStreamContext {
AVIOContext *pb;
+ int pb_is_copied;
int ffindex; ///< AVStream index
int next_chunk;
unsigned int chunk_count;
@@ -108,14 +109,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;
@@ -125,6 +129,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
@@ -132,12 +137,15 @@ typedef struct MOVStreamContext {
uint32_t palette[256];
int has_palette;
int64_t data_size;
+ uint32_t tmcd_flags; ///< tmcd track flags
int64_t track_end; ///< used for dts generation in fragmented movie files
+ int start_pad; ///< amount of samples to skip due to enc-dec delay
unsigned int rap_group_count;
MOVSbgp *rap_group;
} MOVStreamContext;
typedef struct MOVContext {
+ AVClass *avclass;
AVFormatContext *fc;
int time_scale;
int64_t duration; ///< duration of the longest track
@@ -151,7 +159,11 @@ 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;
} MOVContext;
int ff_mp4_read_descr_len(AVIOContext *pb);
@@ -199,5 +211,6 @@ int ff_mov_read_esds(AVFormatContext *fc, AVIOContext *pb, MOVAtom atom);
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);
#endif /* AVFORMAT_ISOM_H */
diff --git a/libavformat/iss.c b/libavformat/iss.c
index 3f7f4fe..e4335b4 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
*/
@@ -88,6 +88,11 @@ static av_cold int iss_read_header(AVFormatContext *s)
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..45bae22 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"
diff --git a/libavformat/jacosubdec.c b/libavformat/jacosubdec.c
new file mode 100644
index 0000000..e2cbaad
--- a/dev/null
+++ b/libavformat/jacosubdec.c
@@ -0,0 +1,270 @@
+/*
+ * 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;
+ return (sscanf(ptr, "%*u:%*u:%*u.%*u %*u:%*u:%*u.%*u %c", &c) == 1 ||
+ sscanf(ptr, "@%*u @%*u %c", &c) == 1);
+}
+
+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 (!url_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
--- a/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 cf9df8c..69ac8f2 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
*/
@@ -33,10 +33,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 {
@@ -53,8 +53,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;
}
@@ -142,7 +142,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 (!url_feof(s->pb) && jv->pts < ast->nb_index_entries) {
const AVIndexEntry *e = ast->index_entries + jv->pts;
const JVFrame *jvf = jv->frames + jv->pts;
@@ -166,7 +166,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt)
AV_WL32(pkt->data, jvf->video_size);
pkt->data[4] = jvf->video_type;
- if (avio_read(pb, pkt->data + JV_PREAMBLE_SIZE, size) < 0)
+ if ((size = avio_read(pb, pkt->data + JV_PREAMBLE_SIZE, size)) < 0)
return AVERROR(EIO);
pkt->size = size + JV_PREAMBLE_SIZE;
@@ -218,6 +218,15 @@ static int read_seek(AVFormatContext *s, int stream_index,
return 0;
}
+static int read_close(AVFormatContext *s)
+{
+ JVDemuxContext *jv = s->priv_data;
+
+ av_freep(&jv->frames);
+
+ return 0;
+}
+
AVInputFormat ff_jv_demuxer = {
.name = "jv",
.long_name = NULL_IF_CONFIG_SMALL("Bitmap Brothers JV"),
@@ -226,4 +235,5 @@ AVInputFormat ff_jv_demuxer = {
.read_header = read_header,
.read_packet = read_packet,
.read_seek = read_seek,
+ .read_close = read_close,
};
diff --git a/libavformat/latmenc.c b/libavformat/latmenc.c
index 7270292..e69de2b 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..0b47668 100644
--- a/libavformat/libavformat.v
+++ b/libavformat/libavformat.v
@@ -1,4 +1,37 @@
LIBAVFORMAT_$MAJOR {
global: av*;
+ #FIXME those are for ffserver
+ ff_inet_aton;
+ ff_socket_nonblock;
+ ffm_set_write_index;
+ ffm_read_write_index;
+ ffm_write_write_index;
+ ff_mpegts_parse_close;
+ ff_mpegts_parse_open;
+ ff_mpegts_parse_packet;
+ 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;
+ ffurl_protocol_next;
+ url_open;
+ url_close;
+ url_write;
+ #those are deprecated, remove on next bump
+ url_*;
+ ff_timefilter_destroy;
+ ff_timefilter_new;
+ ff_timefilter_update;
+ ff_timefilter_reset;
+ get_*;
+ put_*;
+ ff_codec_get_id;
local: *;
};
diff --git a/libavformat/libgme.c b/libavformat/libgme.c
new file mode 100644
index 0000000..1ae63dc
--- a/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 + 1;
+ 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..836b7c2
--- a/dev/null
+++ b/libavformat/libmodplug.c
@@ -0,0 +1,381 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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
+*/
+
+#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 *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..be8f3cb
--- a/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((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..ca71f9f
--- a/dev/null
+++ b/libavformat/libquvi.c
@@ -0,0 +1,146 @@
+/*
+ * 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/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;
+
+ 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 7133bd6..5b4c39d 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
*/
diff --git a/libavformat/libssh.c b/libavformat/libssh.c
new file mode 100644
index 0000000..4a9b867
--- a/dev/null
+++ b/libavformat/libssh.c
@@ -0,0 +1,229 @@
+/*
+ * 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>
+#include <libssh/sftp.h>
+#include "libavutil/avstring.h"
+#include "libavutil/opt.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;
+} LIBSSHContext;
+
+static int libssh_close(URLContext *h)
+{
+ LIBSSHContext *s = h->priv_data;
+ if (s->file)
+ sftp_close(s->file);
+ if (s->sftp)
+ sftp_free(s->sftp);
+ if (s->session) {
+ ssh_disconnect(s->session);
+ ssh_free(s->session);
+ }
+ return 0;
+}
+
+static int libssh_open(URLContext *h, const char *url, int flags)
+{
+ static const int verbosity = SSH_LOG_NOLOG;
+ LIBSSHContext *s = h->priv_data;
+ char proto[10], path[MAX_URL_SIZE], hostname[1024], credencials[1024];
+ int port = 22, access, ret;
+ long timeout = s->rw_timeout * 1000;
+ const char *user = NULL, *pass = NULL;
+ char *end = NULL;
+ sftp_attributes stat;
+
+ 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 (!(s->session = ssh_new())) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ user = av_strtok(credencials, ":", &end);
+ pass = av_strtok(end, ":", &end);
+ ssh_options_set(s->session, SSH_OPTIONS_HOST, hostname);
+ ssh_options_set(s->session, SSH_OPTIONS_PORT, &port);
+ ssh_options_set(s->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
+ if (timeout > 0)
+ ssh_options_set(s->session, SSH_OPTIONS_TIMEOUT_USEC, &timeout);
+ if (user)
+ ssh_options_set(s->session, SSH_OPTIONS_USER, user);
+
+ if (ssh_connect(s->session) != SSH_OK) {
+ av_log(h, AV_LOG_ERROR, "Connection failed. %s\n", ssh_get_error(s->session));
+ ret = AVERROR(EIO);
+ goto fail;
+ }
+
+ if (pass && ssh_userauth_password(s->session, NULL, pass) != SSH_AUTH_SUCCESS) {
+ av_log(h, AV_LOG_ERROR, "Error authenticating with password: %s\n", ssh_get_error(s->session));
+ ret = AVERROR(EACCES);
+ goto fail;
+ }
+
+ if (!(s->sftp = sftp_new(s->session))) {
+ av_log(h, AV_LOG_ERROR, "SFTP session creation failed: %s\n", ssh_get_error(s->session));
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if (sftp_init(s->sftp) != SSH_OK) {
+ av_log(h, AV_LOG_ERROR, "Error initializing sftp session: %s\n", ssh_get_error(s->session));
+ ret = AVERROR(EIO);
+ goto fail;
+ }
+
+ if ((flags & AVIO_FLAG_WRITE) && (flags & AVIO_FLAG_READ)) {
+ access = O_CREAT | O_RDWR;
+ if (s->trunc)
+ access |= O_TRUNC;
+ } else if (flags & AVIO_FLAG_WRITE) {
+ access = O_CREAT | O_WRONLY;
+ if (s->trunc)
+ access |= O_TRUNC;
+ } else {
+ access = O_RDONLY;
+ }
+
+ if (!(s->file = sftp_open(s->sftp, path, access, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH))) {
+ av_log(h, AV_LOG_ERROR, "Error opening sftp file: %s\n", ssh_get_error(s->session));
+ ret = AVERROR(EIO);
+ goto fail;
+ }
+
+ if (!(stat = sftp_fstat(s->file))) {
+ av_log(h, AV_LOG_WARNING, "Cannot stat remote file %s.\n", path);
+ s->filesize = -1;
+ } else {
+ s->filesize = stat->size;
+ sftp_attributes_free(stat);
+ }
+
+ return 0;
+
+ fail:
+ libssh_close(h);
+ return ret;
+}
+
+static int64_t libssh_seek(URLContext *h, int64_t pos, int whence)
+{
+ LIBSSHContext *s = h->priv_data;
+ int64_t newpos;
+
+ if (s->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 s->filesize;
+ case SEEK_SET:
+ newpos = pos;
+ break;
+ case SEEK_CUR:
+ newpos = sftp_tell64(s->file);
+ break;
+ case SEEK_END:
+ newpos = s->filesize + pos;
+ break;
+ default:
+ return AVERROR(EINVAL);
+ }
+
+ if (sftp_seek64(s->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 *s = h->priv_data;
+ int bytes_read;
+
+ if ((bytes_read = sftp_read(s->file, buf, size)) < 0) {
+ av_log(h, 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 *s = h->priv_data;
+ int bytes_written;
+
+ if ((bytes_written = sftp_write(s->file, buf, size)) < 0) {
+ av_log(h, 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 },
+ {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 b67b68e..c8ea421 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
*/
@@ -35,7 +35,7 @@
#define LMLM4_MAX_PACKET_SIZE 1024 * 1024
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);
@@ -93,8 +93,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..05ef0fe
--- a/dev/null
+++ b/libavformat/loasdec.c
@@ -0,0 +1,87 @@
+/*
+ * 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"
+
+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) != 0x2B7)
+ 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/lvfdec.c b/libavformat/lvfdec.c
new file mode 100644
index 0000000..a809c67
--- a/dev/null
+++ b/libavformat/lvfdec.c
@@ -0,0 +1,148 @@
+/*
+ * 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 AVPROBE_SCORE_EXTENSION;
+ return 0;
+}
+
+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 (!url_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 (!url_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 859fc71..f0a9639 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
*/
@@ -90,7 +90,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 (url_feof(s->pb))
return AVERROR_EOF;
memmove(buf, &buf[1], LXF_IDENT_LENGTH-1);
@@ -138,8 +138,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))
@@ -258,6 +259,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 04bd062..c2fd4d7 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
*/
@@ -45,7 +45,7 @@ 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 > 3 ? AVPROBE_SCORE_EXTENSION : AVPROBE_SCORE_EXTENSION/2;
return 0;
}
diff --git a/libavformat/matroska.c b/libavformat/matroska.c
index 7976be0..77a88a8 100644
--- a/libavformat/matroska.c
+++ b/libavformat/matroska.c
@@ -2,25 +2,28 @@
* Matroska common data
* 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
*/
#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},
@@ -32,6 +35,8 @@ const CodecTags ff_mkv_codec_tags[]={
{"A_MPEG/L2" , AV_CODEC_ID_MP2},
{"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},
@@ -52,14 +57,27 @@ 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},
+#if FF_API_ASS_SSA
{"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},
+#endif
+ {"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},
@@ -70,12 +88,14 @@ const CodecTags ff_mkv_codec_tags[]={
{"V_MPEG4/ISO/AP" , AV_CODEC_ID_MPEG4},
{"V_MPEG4/ISO/SP" , AV_CODEC_ID_MPEG4},
{"V_MPEG4/ISO/AVC" , AV_CODEC_ID_H264},
+ {"V_MPEGH/ISO/HEVC" , AV_CODEC_ID_HEVC},
{"V_MPEG4/MS/V3" , AV_CODEC_ID_MSMPEG4V3},
{"V_PRORES" , AV_CODEC_ID_PRORES},
{"V_REAL/RV10" , AV_CODEC_ID_RV10},
{"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},
@@ -92,6 +112,7 @@ 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},
{"" , AV_CODEC_ID_NONE}
};
@@ -101,3 +122,27 @@ const AVMetadataConv ff_mkv_metadata_conv[] = {
{ "PART_NUMBER" , "track" },
{ 0 }
};
+
+const char * const ff_matroska_video_stereo_mode[MATROSKA_VIDEO_STEREO_MODE_COUNT] = {
+ "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",
+};
diff --git a/libavformat/matroska.h b/libavformat/matroska.h
index 0dbc724..3bb5aee 100644
--- a/libavformat/matroska.h
+++ b/libavformat/matroska.h
@@ -2,20 +2,20 @@
* Matroska constants
* 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,14 +78,21 @@
#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
#define MATROSKA_ID_CODECINFOURL 0x3B4040
#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
@@ -113,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
@@ -131,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
@@ -141,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 */
@@ -170,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 */
@@ -177,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
@@ -211,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 {
@@ -243,15 +268,20 @@ 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_MODE_COUNT 15
+#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_STEREO_MODE_COUNT];
+extern const char * const ff_matroska_video_stereo_plane[MATROSKA_VIDEO_STEREO_PLANE_COUNT];
#endif /* AVFORMAT_MATROSKA_H */
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index e6c9adf..52e095f 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
*/
@@ -39,6 +39,7 @@
#include "matroska.h"
#include "libavcodec/bytestream.h"
#include "libavcodec/mpeg4audio.h"
+#include "libavutil/base64.h"
#include "libavutil/intfloat.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/avstring.h"
@@ -102,9 +103,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 {
@@ -113,7 +120,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 {
@@ -134,6 +143,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;
@@ -145,13 +163,17 @@ typedef struct {
uint64_t default_duration;
uint64_t flag_default;
uint64_t flag_forced;
+ uint64_t codec_delay;
+ uint64_t seek_preroll;
MatroskaTrackVideo video;
MatroskaTrackAudio audio;
+ MatroskaTrackOperation operation;
EbmlList encodings;
AVStream *stream;
int64_t end_timecode;
int ms_compat;
+ uint64_t max_block_additional_id;
} MatroskaTrack;
typedef struct {
@@ -230,6 +252,7 @@ typedef struct {
uint64_t time_scale;
double duration;
char *title;
+ EbmlBin date_utc;
EbmlList tracks;
EbmlList attachments;
EbmlList chapters;
@@ -267,6 +290,9 @@ typedef struct {
int64_t reference;
uint64_t non_simple;
EbmlBin bin;
+ uint64_t additional_id;
+ EbmlBin additional;
+ uint64_t discard_padding;
} MatroskaBlock;
static EbmlSyntax ebml_header[] = {
@@ -291,25 +317,26 @@ static EbmlSyntax matroska_info[] = {
{ 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_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_VIDEOSTEREOMODE, EBML_UINT, 0, offsetof(MatroskaTrackVideo,stereo_mode) },
+ { 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 },
{ MATROSKA_ID_VIDEOPIXELCROPR, EBML_NONE },
{ MATROSKA_ID_VIDEODISPLAYUNIT, EBML_NONE },
{ MATROSKA_ID_VIDEOFLAGINTERLACED,EBML_NONE },
- { MATROSKA_ID_VIDEOSTEREOMODE, EBML_NONE },
{ MATROSKA_ID_VIDEOASPECTRATIO, EBML_NONE },
{ 0 }
};
@@ -328,10 +355,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 }
};
@@ -341,6 +379,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) },
@@ -355,7 +409,11 @@ static EbmlSyntax matroska_track[] = {
{ 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_CODECDELAY, EBML_UINT, 0, offsetof(MatroskaTrack,codec_delay) },
+ { 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 },
@@ -364,7 +422,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 }
};
@@ -422,6 +479,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 }
};
@@ -495,10 +554,23 @@ 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_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock,duration) },
+ { MATROSKA_ID_DISCARDPADDING, EBML_UINT, 0, offsetof(MatroskaBlock,discard_padding) },
{ MATROSKA_ID_BLOCKREFERENCE, EBML_UINT, 0, offsetof(MatroskaBlock,reference) },
{ MATROSKA_ID_CODECSTATE, EBML_NONE },
{ 1, EBML_UINT, 0, offsetof(MatroskaBlock,non_simple), {.u=1} },
@@ -571,7 +643,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 (!url_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 ||
@@ -623,7 +695,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 (!url_feof(pb)) {
int64_t pos = avio_tell(pb);
av_log(matroska->ctx, AV_LOG_ERROR,
"Read error at pos. %"PRIu64" (0x%"PRIx64")\n",
@@ -733,14 +805,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_malloc(length)))
+ 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);
}
@@ -884,16 +957,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++;
@@ -924,7 +996,10 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska,
return ebml_parse_nest(matroska, syntax->def.n, data);
case EBML_PASS: return ebml_parse_id(matroska, syntax->def.n, id, data);
case EBML_STOP: return 1;
- default: return avio_skip(pb,length)<0 ? AVERROR(EIO) : 0;
+ default:
+ if(ffio_limit(pb, length) != length)
+ return AVERROR(EIO);
+ return avio_skip(pb,length)<0 ? AVERROR(EIO) : 0;
}
if (res == AVERROR_INVALIDDATA)
av_log(matroska->ctx, AV_LOG_ERROR, "Invalid element\n");
@@ -1028,7 +1103,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) {
@@ -1036,6 +1111,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;
@@ -1084,7 +1164,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);
@@ -1115,7 +1198,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);
@@ -1141,6 +1227,7 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size,
return result;
}
+#if FF_API_ASS_SSA
static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska,
AVPacket *pkt, uint64_t display_duration)
{
@@ -1148,7 +1235,8 @@ static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska,
char *layer, *ptr = pkt->data, *end = ptr+pkt->size;
for (; *ptr!=',' && ptr<end-1; ptr++);
if (*ptr == ',')
- layer = ++ptr;
+ ptr++;
+ layer = ptr;
for (; *ptr!=',' && ptr<end-1; ptr++);
if (*ptr == ',') {
int64_t end_pts = pkt->pts + display_duration;
@@ -1176,17 +1264,17 @@ static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska,
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);
+ memcpy(out->data + out->size - in->size, in->data, in->size);
av_free_packet(in);
av_free(in);
return 0;
}
+#endif
static void matroska_convert_tag(AVFormatContext *s, EbmlList *list,
AVDictionary **metadata, char *prefix)
@@ -1328,26 +1416,20 @@ 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) {
- EbmlList *seekhead_list = &matroska->seekhead;
- MatroskaSeekhead *seekhead = seekhead_list->elem;
+static void matroska_add_index_entries(MatroskaDemuxContext *matroska) {
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
@@ -1369,6 +1451,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" };
@@ -1390,6 +1487,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 *ptm = gmtime(&creation_time);
+ if (!ptm) return;
+ strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", ptm);
+ av_dict_set(metadata, "creation_time", buffer, 0);
+}
+
static int matroska_read_header(AVFormatContext *s)
{
MatroskaDemuxContext *matroska = s->priv_data;
@@ -1402,20 +1510,25 @@ static int matroska_read_header(AVFormatContext *s)
int64_t pos;
Ebml ebml = { 0 };
AVStream *st;
- int i, j, res;
+ int i, j, k, res;
matroska->ctx = s;
/* First read the EBML header. */
if (ebml_parse(matroska, ebml_syntax, &ebml)
|| ebml.version > EBML_VERSION || ebml.max_size > sizeof(uint64_t)
- || ebml.id_length > sizeof(uint32_t) || ebml.doctype_version > 2) {
+ || ebml.id_length > sizeof(uint32_t) || 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]))
@@ -1449,21 +1562,27 @@ static int matroska_read_header(AVFormatContext *s)
* 1000 / AV_TIME_BASE;
av_dict_set(&s->metadata, "title", matroska->title, 0);
+ if (matroska->date_utc.size == 8)
+ matroska_metadata_creation_time(&s->metadata, AV_RB64(matroska->date_utc.data));
+
tracks = matroska->tracks.elem;
for (i=0; i < matroska->tracks.nb_elem; i++) {
MatroskaTrack *track = &tracks[i];
enum AVCodecID codec_id = AV_CODEC_ID_NONE;
- EbmlList *encodings_list = &tracks->encodings;
+ EbmlList *encodings_list = &track->encodings;
MatroskaTrackEncoding *encodings = encodings_list->elem;
uint8_t *extradata = NULL;
int extradata_size = 0;
int extradata_offset = 0;
+ uint32_t fourcc = 0;
AVIOContext b;
+ char* key_id_base64 = NULL;
/* 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);
@@ -1475,10 +1594,12 @@ static int matroska_read_header(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;
@@ -1487,8 +1608,24 @@ static int matroska_read_header(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
@@ -1498,7 +1635,7 @@ static int matroska_read_header(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");
@@ -1528,15 +1665,23 @@ static int matroska_read_header(AVFormatContext *s)
}
st = track->stream = avformat_new_stream(s, NULL);
- if (st == NULL)
+ if (st == NULL) {
+ 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.data != NULL) {
track->ms_compat = 1;
- track->video.fourcc = AV_RL32(track->codec_priv.data + 16);
- codec_id = ff_codec_get_id(ff_codec_bmp_tags, track->video.fourcc);
+ fourcc = AV_RL32(track->codec_priv.data + 16);
+ codec_id = ff_codec_get_id(ff_codec_bmp_tags, fourcc);
extradata_offset = 40;
} else if (!strcmp(track->codec_id, "A_MS/ACM")
&& track->codec_priv.size >= 14
@@ -1552,8 +1697,8 @@ static int matroska_read_header(AVFormatContext *s)
} else if (!strcmp(track->codec_id, "V_QUICKTIME")
&& (track->codec_priv.size >= 86)
&& (track->codec_priv.data != NULL)) {
- 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);
+ codec_id = ff_codec_get_id(ff_codec_movvideo_tags, fourcc);
} else if (codec_id == AV_CODEC_ID_PCM_S16BE) {
switch (track->audio.bitdepth) {
case 8: codec_id = AV_CODEC_ID_PCM_U8; break;
@@ -1584,7 +1729,7 @@ static int matroska_read_header(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. */
@@ -1599,7 +1744,7 @@ static int matroska_read_header(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 == NULL)
return AVERROR(ENOMEM);
ffio_init_context(&b, extradata, extradata_size, 1,
@@ -1608,17 +1753,21 @@ static int matroska_read_header(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 || codec_id == AV_CODEC_ID_RV40) {
extradata_offset = 26;
} 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);
avio_skip(&b, 22);
@@ -1632,13 +1781,15 @@ static int matroska_read_header(AVFormatContext *s)
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];
}
@@ -1672,11 +1823,8 @@ static int matroska_read_header(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 == NULL)
+ 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);
@@ -1684,8 +1832,10 @@ static int matroska_read_header(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;
st->codec->width = track->video.pixel_width;
st->codec->height = track->video.pixel_height;
av_reduce(&st->sample_aspect_ratio.num,
@@ -1693,21 +1843,75 @@ static int matroska_read_header(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->need_parsing = AVSTREAM_PARSE_HEADERS;
+ 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->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_STEREO_MODE_COUNT)
+ 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;
+ }
}
} else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) {
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->sample_rate = track->audio.out_samplerate;
st->codec->channels = track->audio.channels;
+ 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,
+ (AVRational){1, 1000000000},
+ (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 FF_API_ASS_SSA
+ if (st->codec->codec_id == AV_CODEC_ID_SSA ||
+ st->codec->codec_id == AV_CODEC_ID_ASS)
+#else
+ if (st->codec->codec_id == AV_CODEC_ID_ASS)
+#endif
matroska->contains_ssa = 1;
}
}
@@ -1725,10 +1929,8 @@ static int matroska_read_header(AVFormatContext *s)
av_dict_set(&st->metadata, "mimetype", attachements[j].mime, 0);
st->codec->codec_id = AV_CODEC_ID_NONE;
st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT;
- st->codec->extradata = av_malloc(attachements[j].bin.size);
- if(st->codec->extradata == NULL)
+ if (ff_alloc_extradata(st->codec, attachements[j].bin.size))
break;
- st->codec->extradata_size = attachements[j].bin.size;
memcpy(st->codec->extradata, attachements[j].bin.data, attachements[j].bin.size);
for (i=0; ff_mkv_mime_tags[i].id != AV_CODEC_ID_NONE; i++) {
@@ -1755,6 +1957,8 @@ static int matroska_read_header(AVFormatContext *s)
max_start = chapters[i].start;
}
+ matroska_add_index_entries(matroska);
+
matroska_convert_tags(s);
return 0;
@@ -1824,7 +2028,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;
@@ -1838,18 +2042,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;
@@ -1873,10 +2077,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;
@@ -1886,10 +2090,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;
@@ -1917,7 +2121,7 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
MatroskaTrack *track,
AVStream *st,
uint8_t *data, int size,
- uint64_t timecode, uint64_t duration,
+ uint64_t timecode,
int64_t pos)
{
int a = st->codec->block_align;
@@ -1948,7 +2152,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) {
av_log(matroska->ctx, AV_LOG_ERROR,
"Corrupt generic RM-style audio packet size\n");
return AVERROR_INVALIDDATA;
@@ -1966,8 +2170,11 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
}
while (track->audio.pkt_cnt) {
- AVPacket *pkt = av_mallocz(sizeof(AVPacket));
- av_new_packet(pkt, a);
+ AVPacket *pkt = NULL;
+ if (!(pkt = av_mallocz(sizeof(AVPacket))) || av_new_packet(pkt, a) < 0){
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
memcpy(pkt->data, track->audio.buf
+ a * (h*w / a - track->audio.pkt_cnt--), a);
pkt->pts = track->audio.buf_timecode;
@@ -2061,19 +2268,135 @@ 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 == NULL) {
+ 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 == NULL) {
+ 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,
+ uint64_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;
@@ -2098,7 +2421,8 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
/* XXX: prevent data copy... */
if (av_new_packet(pkt, pkt_size + offset) < 0) {
av_free(pkt);
- return AVERROR(ENOMEM);
+ res = AVERROR(ENOMEM);
+ goto fail;
}
if (st->codec->codec_id == AV_CODEC_ID_PRORES) {
@@ -2110,23 +2434,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 == NULL) {
+ 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 == NULL) {
+ 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_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;
+ }
+#if FF_API_ASS_SSA
if (st->codec->codec_id == AV_CODEC_ID_SSA)
- matroska_fix_ass_packet(matroska, pkt, duration);
+ matroska_fix_ass_packet(matroska, pkt, lace_duration);
if (matroska->prev_pkt &&
timecode != AV_NOPTS_VALUE &&
@@ -2138,6 +2510,10 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
dynarray_add(&matroska->packets,&matroska->num_packets,pkt);
matroska->prev_pkt = pkt;
}
+#else
+ dynarray_add(&matroska->packets, &matroska->num_packets, pkt);
+ matroska->prev_pkt = pkt;
+#endif
return 0;
fail:
@@ -2149,7 +2525,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, uint64_t discard_padding)
{
uint64_t timecode = AV_NOPTS_VALUE;
MatroskaTrack *track;
@@ -2158,7 +2535,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");
@@ -2177,8 +2555,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;
@@ -2196,9 +2575,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,
@@ -2207,22 +2591,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 ||
@@ -2231,21 +2622,32 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
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:
@@ -2293,18 +2695,22 @@ 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;
}
@@ -2324,16 +2730,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);
+ blocks[i].duration, is_keyframe, NULL, 0, 0,
+ pos, blocks[i].discard_padding);
}
ebml_free(matroska_cluster, &cluster);
return res;
@@ -2342,22 +2746,16 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt)
{
MatroskaDemuxContext *matroska = s->priv_data;
- int ret = 0;
- while (!ret && matroska_deliver_packet(matroska, pkt)) {
+ while (matroska_deliver_packet(matroska, pkt)) {
int64_t pos = avio_tell(matroska->ctx->pb);
if (matroska->done)
return AVERROR_EOF;
if (matroska_parse_cluster(matroska) < 0)
- ret = matroska_resync(matroska, pos);
+ matroska_resync(matroska, pos);
}
- if (ret == AVERROR_INVALIDDATA && pkt->data) {
- pkt->flags |= AV_PKT_FLAG_CORRUPT;
- return 0;
- }
-
- return ret;
+ return 0;
}
static int matroska_read_seek(AVFormatContext *s, int stream_index,
@@ -2369,13 +2767,13 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index,
int i, index, index_sub, index_min;
/* Parse the CUES now since we need the index data to seek. */
- if (matroska->cues_parsing_deferred) {
- matroska_parse_cues(matroska);
+ if (matroska->cues_parsing_deferred > 0) {
matroska->cues_parsing_deferred = 0;
+ matroska_parse_cues(matroska);
}
if (!st->nb_index_entries)
- return 0;
+ goto err;
timestamp = FFMAX(timestamp, st->index_entries[0].timestamp);
if ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) {
@@ -2389,8 +2787,8 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index,
}
matroska_clear_queue(matroska);
- if (index < 0)
- return 0;
+ if (index < 0 || (matroska->cues_parsing_deferred < 0 && index == st->nb_index_entries - 1))
+ goto err;
index_min = index;
for (i=0; i < matroska->tracks.nb_elem; i++) {
@@ -2399,22 +2797,40 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index,
tracks[i].audio.buf_timecode = AV_NOPTS_VALUE;
tracks[i].end_timecode = 0;
if (tracks[i].type == MATROSKA_TRACK_TYPE_SUBTITLE
- && !tracks[i].stream->discard != AVDISCARD_ALL) {
+ && tracks[i].stream->discard != AVDISCARD_ALL) {
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)
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index f3a35f8..d8355b2 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -2,31 +2,33 @@
* 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
*/
#include "avc.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 "wv.h"
#include "libavutil/avstring.h"
@@ -38,9 +40,11 @@
#include "libavutil/opt.h"
#include "libavutil/random_seed.h"
#include "libavutil/samplefmt.h"
+#include "libavutil/sha.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
@@ -65,6 +69,8 @@ typedef struct {
uint64_t pts;
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 {
@@ -75,6 +81,7 @@ typedef struct {
typedef struct {
int write_dts;
+ int has_cue;
} mkv_track;
#define MODE_MATROSKAv2 0x01
@@ -103,6 +110,8 @@ typedef struct MatroskaMuxContext {
int cluster_size_limit;
int64_t cues_pos;
int64_t cluster_time_limit;
+
+ uint32_t chapter_id_offset;
int wrote_chapters;
} MatroskaMuxContext;
@@ -111,13 +120,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)
{
@@ -128,7 +140,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)));
}
/**
@@ -138,10 +150,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);
}
/**
@@ -165,18 +176,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)
@@ -188,7 +199,7 @@ 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_float(AVIOContext *pb, unsigned int elementid, double val)
@@ -221,7 +232,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
@@ -231,8 +242,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, uint64_t expectedsize)
@@ -255,9 +265,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);
}
@@ -294,17 +302,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 == NULL)
+ return AVERROR(ENOMEM);
+ seekhead->entries = entries;
seekhead->entries[seekhead->num_entries].elementid = elementid;
seekhead->entries[seekhead->num_entries++].segmentpos = filepos - seekhead->segment_offset;
@@ -359,7 +366,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;
@@ -375,27 +382,29 @@ 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, 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 == NULL)
+ 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].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(AVIOContext *pb, mkv_cues *cues, mkv_track *tracks, int num_tracks)
{
ebml_master cues_element;
int64_t currentpos;
@@ -414,10 +423,20 @@ static int64_t mkv_write_cues(AVIOContext *pb, mkv_cues *cues, int num_tracks)
// 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].tracknum - 1;
+ av_assert0(tracknum>=0 && tracknum<num_tracks);
+ if (tracks[tracknum].has_cue)
+ 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;
@@ -508,7 +527,7 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, AVCodecCo
avio_write(dyn_cp, codec->extradata + 12,
codec->extradata_size - 12);
}
- else if (codec->extradata_size)
+ else if (codec->extradata_size && codec->codec_id != AV_CODEC_ID_TTA)
avio_write(dyn_cp, codec->extradata, codec->extradata_size);
} else if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
if (qt_id) {
@@ -520,8 +539,9 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, AVCodecCo
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);
@@ -531,8 +551,9 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, AVCodecCo
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;
@@ -552,7 +573,7 @@ static int mkv_write_tracks(AVFormatContext *s)
MatroskaMuxContext *mkv = s->priv_data;
AVIOContext *pb = s->pb;
ebml_master tracks;
- int i, j, ret;
+ int i, j, ret, default_stream_exists = 0;
ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_TRACKS, avio_tell(pb));
if (ret < 0) return ret;
@@ -560,6 +581,10 @@ static int mkv_write_tracks(AVFormatContext *s)
tracks = start_ebml_master(pb, MATROSKA_ID_TRACKS, 0);
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
+ default_stream_exists |= st->disposition & AV_DISPOSITION_DEFAULT;
+ }
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
AVCodecContext *codec = st->codec;
ebml_master subinfo, track;
int native_id = 0;
@@ -567,6 +592,8 @@ static int mkv_write_tracks(AVFormatContext *s)
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;
AVDictionaryEntry *tag;
if (codec->codec_type == AVMEDIA_TYPE_ATTACHMENT) {
@@ -576,6 +603,8 @@ static int mkv_write_tracks(AVFormatContext *s)
if (!bit_depth)
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);
@@ -588,34 +617,74 @@ static int mkv_write_tracks(AVFormatContext *s)
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:"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));
- // 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 (st->disposition & AV_DISPOSITION_FORCED)
+ put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGFORCED, 1);
+
+ if (mkv->mode == MODE_WEBM && codec->codec_id == AV_CODEC_ID_WEBVTT) {
+ const char *codec_id;
+ if (st->disposition & AV_DISPOSITION_CAPTIONS) {
+ codec_id = "D_WEBVTT/CAPTIONS";
+ native_id = MATROSKA_TRACK_TYPE_SUBTITLE;
+ } else if (st->disposition & AV_DISPOSITION_DESCRIPTIONS) {
+ codec_id = "D_WEBVTT/DESCRIPTIONS";
+ native_id = MATROSKA_TRACK_TYPE_METADATA;
+ } else if (st->disposition & AV_DISPOSITION_METADATA) {
+ codec_id = "D_WEBVTT/METADATA";
+ native_id = MATROSKA_TRACK_TYPE_METADATA;
+ } else {
+ codec_id = "D_WEBVTT/SUBTITLES";
+ native_id = MATROSKA_TRACK_TYPE_SUBTITLE;
+ }
+ put_ebml_string(pb, MATROSKA_ID_CODECID, codec_id);
+ } else {
+ // look for a codec ID string specific to mkv to use,
+ // if none are found, use AVI codes
+ for (j = 0; ff_mkv_codec_tags[j].id != AV_CODEC_ID_NONE; j++) {
+ if (ff_mkv_codec_tags[j].id == codec->codec_id) {
+ put_ebml_string(pb, MATROSKA_ID_CODECID, ff_mkv_codec_tags[j].str);
+ native_id = 1;
+ break;
+ }
}
}
+ if (codec->codec_id == AV_CODEC_ID_OPUS) {
+ uint64_t codec_delay =av_rescale_q(codec->delay,
+ (AVRational){1, codec->sample_rate},
+ (AVRational){1, 1000000000});
+ put_ebml_uint(pb, MATROSKA_ID_CODECDELAY, codec_delay);
+ 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_VORBIS)) {
+ codec->codec_id == AV_CODEC_ID_VP9 ||
+ ((codec->codec_id == AV_CODEC_ID_OPUS)&&(codec->strict_std_compliance <= FF_COMPLIANCE_EXPERIMENTAL)) ||
+ codec->codec_id == AV_CODEC_ID_VORBIS ||
+ codec->codec_id == AV_CODEC_ID_WEBVTT)) {
av_log(s, AV_LOG_ERROR,
- "Only VP8 video and Vorbis audio are supported for WebM.\n");
+ "Only VP8,VP9 video and Vorbis,Opus(experimental, use -strict -2) 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);
- put_ebml_uint(pb, MATROSKA_ID_TRACKDEFAULTDURATION, av_q2d(codec->time_base)*1E9);
+ if(st->avg_frame_rate.num && st->avg_frame_rate.den && 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) &&
@@ -637,30 +706,64 @@ static int mkv_write_tracks(AVFormatContext *s)
// XXX: interlace flag?
put_ebml_uint (pb, MATROSKA_ID_VIDEOPIXELWIDTH , codec->width);
put_ebml_uint (pb, MATROSKA_ID_VIDEOPIXELHEIGHT, codec->height);
- if ((tag = av_dict_get(s->metadata, "stereo_mode", NULL, 0))) {
- uint8_t stereo_fmt = atoi(tag->value);
- int valid_fmt = 0;
-
- switch (mkv->mode) {
- case MODE_WEBM:
- if (stereo_fmt <= MATROSKA_VIDEO_STEREOMODE_TYPE_TOP_BOTTOM
- || stereo_fmt == MATROSKA_VIDEO_STEREOMODE_TYPE_RIGHT_LEFT)
- valid_fmt = 1;
+
+ if ((tag = av_dict_get(st->metadata, "stereo_mode", NULL, 0)) ||
+ (tag = av_dict_get( s->metadata, "stereo_mode", NULL, 0))) {
+ // save stereo mode flag
+ uint64_t st_mode = MATROSKA_VIDEO_STEREO_MODE_COUNT;
+
+ for (j=0; j<MATROSKA_VIDEO_STEREO_MODE_COUNT; j++)
+ if (!strcmp(tag->value, ff_matroska_video_stereo_mode[j])){
+ st_mode = j;
+ break;
+ }
+
+ if ((mkv->mode == MODE_WEBM && st_mode > 3 && st_mode != 11)
+ || st_mode >= MATROSKA_VIDEO_STEREO_MODE_COUNT) {
+ av_log(s, AV_LOG_ERROR,
+ "The specified stereo mode is not valid.\n");
+ return AVERROR(EINVAL);
+ } else
+ put_ebml_uint(pb, MATROSKA_ID_VIDEOSTEREOMODE, st_mode);
+
+ switch (st_mode) {
+ case 1:
+ case 8:
+ case 9:
+ case 11:
+ display_width_div = 2;
break;
- case MODE_MATROSKAv2:
- if (stereo_fmt <= MATROSKA_VIDEO_STEREOMODE_TYPE_BOTH_EYES_BLOCK_RL)
- valid_fmt = 1;
+ case 2:
+ case 3:
+ case 6:
+ case 7:
+ display_height_div = 2;
break;
}
+ }
- if (valid_fmt)
- put_ebml_uint (pb, MATROSKA_ID_VIDEOSTEREOMODE, stereo_fmt);
+ if ((tag = av_dict_get(st->metadata, "alpha_mode", NULL, 0)) ||
+ (tag = av_dict_get( s->metadata, "alpha_mode", NULL, 0)) ||
+ (codec->pix_fmt == AV_PIX_FMT_YUVA420P)) {
+ put_ebml_uint(pb, MATROSKA_ID_VIDEOALPHAMODE, 1);
}
+
if (st->sample_aspect_ratio.num) {
- int d_width = codec->width*av_q2d(st->sample_aspect_ratio);
- put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH , d_width);
- put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, codec->height);
- put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYUNIT, 3);
+ 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;
@@ -683,18 +786,25 @@ static int mkv_write_tracks(AVFormatContext *s)
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);
@@ -729,7 +839,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,
@@ -803,21 +913,33 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int eleme
end_ebml_master(s->pb, targets);
while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX)))
- if (av_strcasecmp(t->key, "title"))
+ if (av_strcasecmp(t->key, "title") && av_strcasecmp(t->key, "stereo_mode"))
mkv_write_simpletag(s->pb, t);
end_ebml_master(s->pb, tag);
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;
}
@@ -825,7 +947,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);
@@ -835,10 +957,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;
}
@@ -870,6 +992,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;
@@ -899,9 +1022,25 @@ static int mkv_write_attachments(AVFormatContext *s)
return AVERROR(EINVAL);
}
+ if (st->codec->flags & CODEC_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);
@@ -920,6 +1059,22 @@ static int mkv_write_header(AVFormatContext *s)
if (!strcmp(s->oformat->name, "webm")) mkv->mode = MODE_WEBM;
else mkv->mode = MODE_MATROSKAv2;
+ if (s->avoid_negative_ts < 0)
+ s->avoid_negative_ts = 1;
+
+ 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;
+ }
+
mkv->tracks = av_mallocz(s->nb_streams * sizeof(*mkv->tracks));
if (!mkv->tracks)
return AVERROR(ENOMEM);
@@ -930,7 +1085,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 , 4);
put_ebml_uint (pb, EBML_ID_DOCTYPEREADVERSION , 2);
end_ebml_master(pb, ebml_header);
@@ -965,6 +1120,18 @@ static int mkv_write_header(AVFormatContext *s)
put_ebml_string(pb, MATROSKA_ID_MUXINGAPP , LIBAVFORMAT_IDENT);
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
@@ -976,6 +1143,9 @@ static int mkv_write_header(AVFormatContext *s)
ret = mkv_write_tracks(s);
if (ret < 0) return ret;
+ for (i = 0; i < s->nb_chapters; i++)
+ mkv->chapter_id_offset = FFMAX(mkv->chapter_id_offset, 1LL - s->chapters[i]->id);
+
if (mkv->mode != MODE_WEBM) {
ret = mkv_write_chapters(s);
if (ret < 0) return ret;
@@ -1001,6 +1171,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);
@@ -1040,11 +1211,12 @@ static int ass_get_duration(const uint8_t *p)
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;
+ start = 3600000LL*sh + 60000LL*sm + 1000LL*ss + 10LL*sc;
+ end = 3600000LL*eh + 60000LL*em + 1000LL*es + 10LL*ec;
return end - start;
}
+#if FF_API_ASS_SSA
static int mkv_write_ass_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
{
MatroskaMuxContext *mkv = s->priv_data;
@@ -1089,6 +1261,7 @@ static int mkv_write_ass_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *p
return max_duration;
}
+#endif
static int mkv_strip_wavpack(const uint8_t *src, uint8_t **pdst, int *size)
{
@@ -1148,9 +1321,11 @@ 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, 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",
@@ -1174,6 +1349,30 @@ 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);
avio_w8(pb, 0x80 | (pkt->stream_index + 1)); // this assumes stream_index is less than 126
@@ -1182,6 +1381,24 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb,
avio_write(pb, data + offset, size);
if (data != pkt->data)
av_free(data);
+
+ if (discard_padding) {
+ put_ebml_uint(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);
+ }
}
static int srt_get_duration(uint8_t **buf)
@@ -1198,7 +1415,7 @@ static int srt_get_duration(uint8_t **buf)
s_hsec += 1000*s_sec; e_hsec += 1000*e_sec;
duration = e_hsec - s_hsec;
}
- *buf += strcspn(*buf, "\n") + 1;
+ *buf += ff_subtitles_next_line(*buf);
}
return duration;
}
@@ -1219,6 +1436,44 @@ static int mkv_write_srt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *p
return duration;
}
+static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
+{
+ MatroskaMuxContext *mkv = s->priv_data;
+ ebml_master blockgroup;
+ 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 pkt->duration;
+}
+
static void mkv_flush_dynbuf(AVFormatContext *s)
{
MatroskaMuxContext *mkv = s->priv_data;
@@ -1243,6 +1498,7 @@ 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;
if (ts == AV_NOPTS_VALUE) {
av_log(s, AV_LOG_ERROR, "Can't write packet with unknown timestamp\n");
@@ -1250,34 +1506,48 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
}
if (!s->pb->seekable) {
- if (!mkv->dyn_bc)
- avio_open_dyn_buf(&mkv->dyn_bc);
+ if (!mkv->dyn_bc) {
+ if ((ret = avio_open_dyn_buf(&mkv->dyn_bc)) < 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);
+#if FF_API_ASS_SSA
} else if (codec->codec_id == AV_CODEC_ID_SSA) {
duration = mkv_write_ass_blocks(s, pb, pkt);
+#endif
} else if (codec->codec_id == AV_CODEC_ID_SRT) {
duration = mkv_write_srt_blocks(s, pb, pkt);
+ } 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 ((codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe) || codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+ ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, ts, mkv->cluster_pos, relative_packet_pos,
+ codec->codec_type == AVMEDIA_TYPE_SUBTITLE ? duration : -1);
if (ret < 0) return ret;
}
@@ -1310,7 +1580,7 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
cluster_size = avio_tell(pb);
}
- if (mkv->cluster_pos &&
+ if (mkv->cluster_pos != -1 &&
(cluster_size > mkv->cluster_size_limit ||
cluster_time > mkv->cluster_time_limit ||
(codec_type == AVMEDIA_TYPE_VIDEO && keyframe &&
@@ -1319,7 +1589,7 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
" bytes, pts %" PRIu64 "dts %" PRIu64 "\n",
avio_tell(pb), pkt->pts, pkt->dts);
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);
@@ -1344,6 +1614,9 @@ 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);
return ret;
@@ -1358,11 +1631,11 @@ 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);
@@ -1392,7 +1665,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);
}
@@ -1409,7 +1682,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(pb, 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, "Insufficient space reserved for cues: %d "
@@ -1423,7 +1696,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(pb, mkv->cues, mkv->tracks, s->nb_streams);
}
ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_CUES, cuespos);
@@ -1442,7 +1715,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);
@@ -1465,6 +1738,31 @@ 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[] = {
@@ -1498,9 +1796,14 @@ 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
},
+#if FF_API_ASS_SSA
.subtitle_codec = AV_CODEC_ID_SSA,
+#else
+ .subtitle_codec = AV_CODEC_ID_ASS,
+#endif
.query_codec = mkv_query_codec,
.priv_class = &matroska_class,
};
@@ -1522,6 +1825,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,
@@ -1540,7 +1844,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),
@@ -1552,7 +1856,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..8b14fba 100644
--- a/libavformat/md5enc.c
+++ b/libavformat/md5enc.c
@@ -2,38 +2,45 @@
* 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;
};
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 +51,54 @@ 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 },
+ { 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 +106,7 @@ AVOutputFormat ff_md5_muxer = {
.write_packet = write_packet,
.write_trailer = write_trailer,
.flags = AVFMT_NOTIMESTAMPS,
+ .priv_class = &md5enc_class,
};
#endif
@@ -91,18 +114,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: 1\n");
+ 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 +141,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 +163,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-example.c b/libavformat/metadata-example.c
deleted file mode 100644
index 7bf77e7..0000000
--- a/libavformat/metadata-example.c
+++ b/dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2011 Reinhard Tartler
- *
- * 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
- * @example libavformat/metadata-example.c
- * Shows how the metadata API can be used in application programs.
- */
-
-#include <stdio.h>
-
-#include <libavformat/avformat.h>
-#include <libavutil/dict.h>
-
-int main (int argc, char **argv)
-{
- AVFormatContext *fmt_ctx = NULL;
- AVDictionaryEntry *tag = NULL;
- int ret;
-
- if (argc != 2) {
- printf("usage: %s <input_file>\n"
- "example program to demonstrate the use of the libavformat metadata API.\n"
- "\n", argv[0]);
- return 1;
- }
-
- av_register_all();
- if ((ret = avformat_open_input(&fmt_ctx, argv[1], NULL, NULL)))
- return ret;
-
- 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);
- return 0;
-}
diff --git a/libavformat/metadata.c b/libavformat/metadata.c
index 77fb298..fc3a9d7 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
*/
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..dec6bfc
--- a/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 (url_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..7b49e43
--- a/dev/null
+++ b/libavformat/microdvddec.c
@@ -0,0 +1,167 @@
+/*
+ * 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"
+
+#define MAX_LINESIZE 2048
+
+
+typedef struct {
+ FFDemuxSubtitlesQueue q;
+} 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 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[MAX_LINESIZE];
+
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ while (!url_feof(s->pb)) {
+ char *p = line;
+ AVPacket *sub;
+ int64_t pos = avio_tell(s->pb);
+ int len = ff_get_line(s->pb, line, sizeof(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);
+ 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);
+ 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;
+}
+
+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,
+};
diff --git a/libavformat/microdvdenc.c b/libavformat/microdvdenc.c
new file mode 100644
index 0000000..4d84384
--- a/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
--- a/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/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..cb87a6d 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->streams[0]->codec->flags & CODEC_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->streams[0]->codec->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 (url_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 192e703..46fbede 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..482ece4 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;
}
@@ -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 a17b4c1..1673036 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 void mms_put_utf16(MMSContext *mms, const uint8_t *src)
{
AVIOContext bic;
int size = mms->write_out_ptr - mms->out_buffer;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 60fb999..eec8485 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
*/
@@ -34,6 +34,8 @@
#include "libavutil/mathematics.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"
@@ -126,6 +128,74 @@ static int mov_metadata_gnre(MOVContext *c, AVIOContext *pb,
return 0;
}
+static int mov_read_custom_metadata(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ char key[1024]={0}, data[1024]={0};
+ 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;
+
+ if (atom.size <= 8) return 0;
+
+ for (i = 0; i < 3; i++) { // Parse up to three sub-atoms looking for name and data.
+ int data_size = avio_rb32(pb);
+ int tag = avio_rl32(pb);
+ int str_size = 0, skip_size = 0;
+ char *target = NULL;
+
+ switch (tag) {
+ case MKTAG('n','a','m','e'):
+ avio_rb32(pb); // version/flags
+ str_size = skip_size = data_size - 12;
+ atom.size -= 12;
+ target = key;
+ break;
+ case MKTAG('d','a','t','a'):
+ avio_rb32(pb); // version/flags
+ avio_rb32(pb); // reserved (zero)
+ str_size = skip_size = data_size - 16;
+ atom.size -= 16;
+ target = data;
+ break;
+ default:
+ skip_size = data_size - 8;
+ str_size = 0;
+ break;
+ }
+
+ if (target) {
+ str_size = FFMIN3(sizeof(data)-1, str_size, atom.size);
+ avio_read(pb, target, str_size);
+ target[str_size] = 0;
+ }
+ atom.size -= skip_size;
+
+ // If we didn't read the full data chunk for the sub-atom, skip to the end of it.
+ if (skip_size > str_size) avio_skip(pb, skip_size - str_size);
+ }
+
+ if (*key && *data) {
+ if (strcmp(key, "iTunSMPB") == 0) {
+ int priming, remainder, samples;
+ if(sscanf(data, "%*X %X %X %X", &priming, &remainder, &samples) == 3){
+ if(priming>0 && priming<16384)
+ sc->start_pad = priming;
+ return 1;
+ }
+ }
+ if (strcmp(key, "cdec") == 0) {
+// av_dict_set(&st->metadata, key, data, 0);
+ return 1;
+ }
+ }
+ return 0;
+}
+
static const uint32_t mac_to_unicode[128] = {
0x00C4,0x00C5,0x00C7,0x00C9,0x00D1,0x00D6,0x00DC,0x00E1,
0x00E0,0x00E2,0x00E4,0x00E3,0x00E5,0x00E7,0x00E9,0x00E8,
@@ -156,7 +226,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;
@@ -205,6 +275,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_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
#ifdef MOV_EXPORT_ALL_METADATA
@@ -216,6 +297,9 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
uint32_t data_type = 0, str_size;
int (*parse)(MOVContext*, AVIOContext*, unsigned, const char*) = NULL;
+ if (c->itunes_metadata && atom.type == MKTAG('-','-','-','-'))
+ return mov_read_custom_metadata(c, pb, atom);
+
switch (atom.type) {
case MKTAG(0xa9,'n','a','m'): key = "title"; break;
case MKTAG(0xa9,'a','u','t'):
@@ -224,6 +308,8 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
case MKTAG(0xa9,'w','r','t'): key = "composer"; 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;
@@ -234,6 +320,9 @@ 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;
case MKTAG( 't','v','s','h'): key = "show"; break;
@@ -253,6 +342,10 @@ 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");
}
if (c->itunes_metadata && atom.size > 8) {
@@ -297,7 +390,7 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (parse)
parse(c, pb, str_size, key);
else {
- if (data_type == 3 || (data_type == 0 && langcode < 0x800)) { // MAC Encoded
+ if (data_type == 3 || (data_type == 0 && (langcode < 0x400 || langcode == 0x7fff))) { // MAC Encoded
mov_read_mac_string(c, pb, str_size, str, sizeof(str));
} else {
avio_read(pb, str, str_size);
@@ -366,6 +459,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);
@@ -415,7 +509,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(url_feof(pb))
return AVERROR_EOF;
type = avio_rb16(pb);
len = avio_rb16(pb);
@@ -462,6 +556,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;
@@ -491,6 +587,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;
}
@@ -584,6 +693,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;
@@ -597,7 +709,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;
}
@@ -671,6 +785,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' */
@@ -686,13 +806,16 @@ static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom)
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;
- time -= 2082844800; /* seconds between 1904-01-01 and Epoch */
- ptm = gmtime(&time);
+ time_t timet;
+ if(time >= 2082844800)
+ time -= 2082844800; /* seconds between 1904-01-01 and Epoch */
+ timet = time;
+ ptm = gmtime(&timet);
if (!ptm) return;
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", ptm);
av_dict_set(metadata, "creation_time", buffer, 0);
@@ -706,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;
@@ -746,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 */
@@ -763,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 */
@@ -778,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;
}
@@ -815,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) {
@@ -873,7 +975,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;
@@ -883,6 +986,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;
@@ -898,6 +1005,62 @@ static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom)
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)
+{
+ return mov_read_extradata(c, pb, atom, AV_CODEC_ID_AVUI);
+}
+
+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)
+{
+ 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;
@@ -909,13 +1072,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_alloc_extradata(st->codec, atom.size))
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;
@@ -951,10 +1114,8 @@ static int mov_read_glbl(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return mov_read_default(c, pb, atom);
}
av_free(st->codec->extradata);
- st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, atom.size))
return AVERROR(ENOMEM);
- st->codec->extradata_size = atom.size;
avio_read(pb, st->codec->extradata, atom.size);
return 0;
}
@@ -976,10 +1137,8 @@ static int mov_read_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
av_free(st->codec->extradata);
- st->codec->extradata = av_mallocz(atom.size - 7 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, atom.size - 7))
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);
return 0;
@@ -1004,10 +1163,8 @@ static int mov_read_strf(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return AVERROR_INVALIDDATA;
av_free(st->codec->extradata);
- st->codec->extradata = av_mallocz(atom.size - 40 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, atom.size - 40))
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;
@@ -1089,7 +1246,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;
@@ -1129,8 +1288,11 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
if (len < 31)
avio_skip(pb, 31 - len);
/* codec_tag YV12 triggers an UV swap in rawdec.c */
- if (!memcmp(st->codec->codec_name, "Planar Y'CbCr 8-bit 4:2:0", 25))
+ if (!memcmp(st->codec->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(st->codec->codec_name, "Sorenson H263", 13))
@@ -1148,7 +1310,7 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
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;
@@ -1158,8 +1320,11 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
color_index = 255;
color_dec = 256 / (color_count - 1);
for (j = 0; j < color_count; j++) {
+ if (st->codec->codec_id == AV_CODEC_ID_CINEPAK){
+ r = g = b = color_count - 1 - color_index;
+ } else
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;
@@ -1179,7 +1344,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 */
@@ -1188,10 +1353,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);
@@ -1199,7 +1363,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);
}
}
}
@@ -1212,6 +1376,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 */
@@ -1227,7 +1392,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 */
@@ -1312,11 +1479,19 @@ 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_alloc_extradata(st->codec, size))
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;
+ }
} else {
/* other codec type, just skip (rtp, mp4s ...) */
avio_skip(pb, size);
@@ -1371,6 +1546,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:
@@ -1379,6 +1557,12 @@ 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:
+ st->need_parsing = AVSTREAM_PARSE_FULL;
+ break;
+ case AV_CODEC_ID_MPEG1VIDEO:
+ st->need_parsing = AVSTREAM_PARSE_FULL;
+ break;
case AV_CODEC_ID_VC1:
st->need_parsing = AVSTREAM_PARSE_FULL;
break;
@@ -1395,10 +1579,9 @@ static int mov_skip_multiple_stsd(MOVContext *c, AVIOContext *pb,
int video_codec_id = ff_codec_get_id(ff_codec_movvideo_tags, format);
if (codec_tag &&
- (codec_tag == AV_RL32("avc1") ||
(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. */
@@ -1407,6 +1590,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;
}
@@ -1430,15 +1618,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 %d 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;
}
@@ -1451,7 +1639,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
id = mov_codec_id(st, format);
- av_dlog(c->fc, "size=%d 4CC= %c%c%c%c 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);
@@ -1471,7 +1659,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
if (ret < 0)
return ret;
}
- /* this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...) */
+ /* this will read extra atoms at the end (wave, alac, damr, avcC, hvcC, SMI ...) */
a.size = size - (avio_tell(pb) - start_pos);
if (a.size > 8) {
if ((ret = mov_read_default(c, pb, a)) < 0)
@@ -1591,6 +1779,8 @@ static int mov_read_stss(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (!entries)
{
sc->keyframe_absent = 1;
+ if (!st->need_parsing)
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
return 0;
}
if (entries >= UINT_MAX / sizeof(int))
@@ -1632,6 +1822,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;
@@ -1709,10 +1900,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;
sc->stts_data = av_malloc(entries * sizeof(*sc->stts_data));
if (!sc->stts_data)
@@ -1724,6 +1913,12 @@ 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 in STTS %d\n", sample_duration);
+ sample_duration = 1;
+ }
if (sample_count < 0) {
av_log(c->fc, AV_LOG_ERROR, "Invalid sample_count=%d\n", sample_count);
return AVERROR_INVALIDDATA;
@@ -1750,6 +1945,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;
@@ -1781,8 +1983,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;
@@ -1848,12 +2061,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;
@@ -1871,11 +2085,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;
@@ -1888,10 +2102,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) {
@@ -1918,7 +2144,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
}
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++];
@@ -2035,14 +2261,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 */
@@ -2074,11 +2300,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;
@@ -2106,12 +2347,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);
@@ -2119,14 +2355,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 &&
@@ -2135,9 +2374,21 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
((double)st->codec->width * sc->height), INT_MAX);
}
- if (st->duration != AV_NOPTS_VALUE && st->duration > 0)
+ if (st->duration > 0)
av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
sc->time_scale*st->nb_frames, st->duration, 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.
+ if (!st->codec->extradata_size && st->codec->codec_id == AV_CODEC_ID_H264 &&
+ st->codec->codec_tag != MKTAG('a', 'v', 'c', '1')) {
+ ff_generate_avci_extradata(st);
}
switch (st->codec->codec_id) {
@@ -2245,6 +2496,21 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sc->width = width >> 16;
sc->height = height >> 16;
+ //Assign clockwise rotate values based on transform matrix so that
+ //we can compensate for iPhone orientation during capture.
+
+ if (display_matrix[1][0] == -65536 && display_matrix[0][1] == 65536) {
+ av_dict_set(&st->metadata, "rotate", "90", 0);
+ }
+
+ if (display_matrix[0][0] == -65536 && display_matrix[1][1] == -65536) {
+ av_dict_set(&st->metadata, "rotate", "180", 0);
+ }
+
+ if (display_matrix[1][0] == 65536 && display_matrix[0][1] == -65536) {
+ av_dict_set(&st->metadata, "rotate", "270", 0);
+ }
+
// transform the display width/height according to the matrix
// skip this if the display matrix is the default identity matrix
// or if it is rotating the picture, ex iPhone 3GS
@@ -2324,6 +2590,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 */
@@ -2358,7 +2627,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);
@@ -2406,6 +2675,7 @@ 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);
sc->ctts_count++;
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
keyframe = 1;
@@ -2470,7 +2740,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 */
@@ -2509,9 +2779,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;
@@ -2522,9 +2793,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);
@@ -2532,22 +2805,109 @@ 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=\"")) != NULL) {
+ 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 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','t','t','s'), mov_read_ctts }, /* composition time to sample */
@@ -2561,7 +2921,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 },
@@ -2571,8 +2931,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 },
@@ -2590,6 +2950,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 },
@@ -2604,6 +2965,9 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('c','h','a','n'), mov_read_chan }, /* channel layout */
{ 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 },
{ 0, NULL }
};
@@ -2615,25 +2979,33 @@ 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 && !url_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 (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)
@@ -2688,46 +3060,81 @@ 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('j','P',' ',' '): /* jpeg 2000 signature */
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 {
+ 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
@@ -2789,7 +3196,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);
}
}
@@ -2800,6 +3207,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;
@@ -2815,8 +3265,15 @@ static int mov_read_close(AVFormatContext *s)
av_freep(&sc->drefs[j].dir);
}
av_freep(&sc->drefs);
- if (sc->pb && sc->pb != s->pb)
+ if (!sc->pb_is_copied)
avio_close(sc->pb);
+ sc->pb = NULL;
+ av_freep(&sc->chunk_offsets);
+ av_freep(&sc->keyframes);
+ av_freep(&sc->sample_sizes);
+ av_freep(&sc->stps_data);
+ av_freep(&sc->stsc_data);
+ av_freep(&sc->stts_data);
}
if (mov->dv_demux) {
@@ -2829,15 +3286,50 @@ static int mov_read_close(AVFormatContext *s)
}
av_freep(&mov->trex_data);
+ av_freep(&mov->bitrates);
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 mov_read_header(AVFormatContext *s)
{
MOVContext *mov = s->priv_data;
AVIOContext *pb = s->pb;
- int err;
+ int i, j, err;
MOVAtom atom = { AV_RL32("root") };
mov->fc = s;
@@ -2860,11 +3352,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 (mov->trex_data) {
- int i;
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
MOVStreamContext *sc = st->priv_data;
@@ -2873,6 +3399,12 @@ static int mov_read_header(AVFormatContext *s)
}
}
+ 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];
+ }
+ }
+
return 0;
}
@@ -2909,6 +3441,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) {
@@ -2918,7 +3451,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)
+ url_feof(s->pb))
return AVERROR_EOF;
av_dlog(s, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb));
goto retry;
@@ -2927,6 +3460,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",
@@ -2949,7 +3487,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);
@@ -3026,8 +3564,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);
@@ -3038,7 +3574,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;
@@ -3048,6 +3587,23 @@ 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},
+ {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"),
@@ -3057,4 +3613,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..e7b5221 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
*/
@@ -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 8f7153a..cfb73d7 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
*/
@@ -46,6 +46,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 (not supported by QuickTime)", 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" },
@@ -54,13 +55,15 @@ static const AVOption options[] = {
{ "faststart", "Run a second pass to put the index (moov atom) at the beginning of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FASTSTART}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "omit_tfhd_offset", "Omit the base data offset in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_OMIT_TFHD_OFFSET}, 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},
+ { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, 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},
{ NULL },
};
@@ -72,6 +75,8 @@ static const AVClass flavor ## _muxer_class = {\
.version = LIBAVUTIL_VERSION_INT,\
};
+static int get_moov_size(AVFormatContext *s);
+
//FIXME support 64 bit variant with wide placeholders
static int64_t update_size(AVIOContext *pb, int64_t pos)
{
@@ -83,6 +88,12 @@ static int64_t update_size(AVIOContext *pb, int64_t pos)
return curpos - pos;
}
+static int supports_edts(MOVMuxContext *mov)
+{
+ // EDTS with fragments is tricky as we don't know the duration when its written
+ return (mov->use_editlist<0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) || mov->use_editlist>0;
+}
+
static int co64_required(const MOVTrack *track)
{
if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
@@ -97,13 +108,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
@@ -159,10 +172,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;
@@ -269,6 +282,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;
@@ -278,10 +307,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");
@@ -312,12 +353,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
@@ -331,6 +370,22 @@ 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)
{
int64_t pos = avio_tell(pb);
@@ -382,9 +437,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 */
@@ -392,11 +449,16 @@ 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_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) {
@@ -557,6 +619,8 @@ 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;
@@ -579,9 +643,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 */
@@ -610,10 +682,19 @@ 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
+ 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 ?
@@ -621,13 +702,27 @@ 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_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);
@@ -660,19 +755,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);
@@ -781,20 +863,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->enc->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->enc->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;
}
@@ -802,11 +884,84 @@ 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 = MKTAG('m', '2', 'v', '1'); //fallback tag
+ int interlaced = track->enc->field_order > AV_FIELD_PROGRESSIVE;
+ AVStream *st = track->st;
+ int rate = av_q2d(find_fps(s, st));
+
+ 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 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 },
@@ -832,7 +987,8 @@ static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
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;
}
}
@@ -847,11 +1003,14 @@ 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_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_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
@@ -888,7 +1047,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') },
@@ -980,6 +1139,32 @@ static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
return 16;
}
+static void find_compressor(char * compressor_name, int len, MOVTrack *track)
+{
+ 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 && track->enc->codec && track->enc->codec->name) {
+ av_strlcpy(compressor_name, track->enc->codec->name, 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);
@@ -1015,8 +1200,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 && track->enc->codec && track->enc->codec->name)
- av_strlcpy(compressor_name, track->enc->codec->name, 32);
+ find_compressor(compressor_name, 32, track);
avio_w8(pb, strlen(compressor_name));
avio_write(pb, compressor_name, 31);
@@ -1029,17 +1213,17 @@ 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_H264) {
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) {
@@ -1048,6 +1232,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);
@@ -1079,6 +1269,27 @@ static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
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;
+
+ 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_wb24(pb, 0); /* Reserved */
+ /* TODO: source reference string */
+#else
avio_wb32(pb, 0); /* size */
ffio_wfourcc(pb, "tmcd"); /* Data format */
@@ -1086,6 +1297,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);
}
@@ -1192,6 +1404,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 */
@@ -1237,9 +1450,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 */
@@ -1250,7 +1486,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)
@@ -1290,9 +1555,14 @@ 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('c','6','0','8')) {
+ hdlr_type = "clcp";
+ descr = "ClosedCaptionHandler";
+ } else {
if (track->tag == MKTAG('t','x','3','g')) hdlr_type = "sbtl";
else hdlr_type = "text";
descr = "SubtitleHandler";
+ }
} else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) {
hdlr_type = "hint";
descr = "HintHandler";
@@ -1351,12 +1621,15 @@ static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track)
else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
mov_write_smhd_tag(pb);
else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) {
- if (track->tag == MKTAG('t','e','x','t')) mov_write_gmhd_tag(pb);
- else mov_write_nmhd_tag(pb);
+ if (track->tag == MKTAG('t','e','x','t') || track->tag == MKTAG('c','6','0','8')) {
+ 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);
@@ -1412,11 +1685,30 @@ static int mov_write_mdia_tag(AVIOContext *pb, MOVTrack *track)
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, MOVTrack *track, AVStream *st)
{
int64_t duration = av_rescale_rnd(track->track_duration, MOV_TIMESCALE,
track->timescale, AV_ROUND_UP);
int version = duration < INT32_MAX ? 0 : 1;
+ int rotation = 0;
if (track->mode == MODE_ISM)
version = 1;
@@ -1453,16 +1745,19 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st)
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)) {
@@ -1500,6 +1795,12 @@ static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, track->enc->height << 16);
avio_wb32(pb, 20);
+ ffio_wfourcc(pb, "prof");
+ avio_wb32(pb, 0);
+ avio_wb32(pb, width << 16);
+ avio_wb32(pb, track->enc->height << 16);
+
+ avio_wb32(pb, 20);
ffio_wfourcc(pb, "enof");
avio_wb32(pb, 0);
avio_wb32(pb, track->enc->width << 16);
@@ -1542,6 +1843,10 @@ static int mov_write_edts_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, -1);
}
avio_wb32(pb, 0x00010000);
+ } else {
+ 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); //FFMIN needed due to rounding
+ duration += delay;
}
/* duration */
@@ -1613,11 +1918,8 @@ static int mov_write_trak_tag(AVIOContext *pb, MOVMuxContext *mov,
avio_wb32(pb, 0); /* size */
ffio_wfourcc(pb, "trak");
mov_write_tkhd_tag(pb, track, st);
- if (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS ||
- (track->entry && track->cluster[0].dts)) {
- if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
- mov_write_edts_tag(pb, track); // PSP Movies require edts box
- }
+ if (supports_edts(mov))
+ mov_write_edts_tag(pb, track); // PSP Movies and several other cases require edts box
if (track->tref_tag)
mov_write_tref_tag(pb, track);
mov_write_mdia_tag(pb, track);
@@ -1627,7 +1929,7 @@ static int mov_write_trak_tag(AVIOContext *pb, MOVMuxContext *mov,
mov_write_udta_sdp(pb, track);
if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO && track->mode == MODE_MOV) {
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);
}
return update_size(pb, pos);
@@ -1727,15 +2029,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) */
@@ -1821,28 +2115,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)
@@ -1867,7 +2212,14 @@ 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_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);
}
@@ -1995,7 +2347,10 @@ 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);
} else {
@@ -2066,6 +2421,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)
{
@@ -2080,6 +2458,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)
@@ -2094,6 +2475,14 @@ 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;
+ mov->tracks[i].track_duration = mov->tracks[src_trk].track_duration;
+ }
+ }
mov_write_mvhd_tag(pb, mov);
if (mov->mode != MODE_MOV && !mov->iods_skip)
@@ -2137,7 +2526,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
};
@@ -2338,7 +2727,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
};
@@ -2360,7 +2749,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
};
@@ -2384,8 +2773,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;
@@ -2741,10 +3129,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)
@@ -2753,12 +3139,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);
@@ -2901,6 +3284,9 @@ 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
@@ -2913,6 +3299,16 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
memcpy(trk->vos_data, enc->extradata, trk->vos_len);
}
+ if (enc->codec_id == AV_CODEC_ID_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 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) {
/* from x264 or from bytestream h264 */
/* nal reformating needed */
@@ -2947,6 +3343,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;
@@ -2957,9 +3354,13 @@ 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 && !supports_edts(mov)) {
+ trk->cluster[trk->entry].dts = trk->start_dts = 0;
+ }
if (trk->start_dts == AV_NOPTS_VALUE)
trk->start_dts = 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");
@@ -2994,12 +3395,8 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
return 0;
}
-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;
@@ -3009,7 +3406,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);
@@ -3024,6 +3421,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);
}
}
@@ -3031,12 +3495,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');
@@ -3045,11 +3509,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 == NULL)
+#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_free(&buf);
+ }
+ }
+#endif
for (i = 0; i < s->nb_chapters; i++) {
AVChapter *c = s->chapters[i];
@@ -3075,6 +3585,43 @@ 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;
+
+ /* 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
@@ -3132,18 +3679,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);
@@ -3153,8 +3702,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, hint_track = 0, tmcd_track = 0;
/* Default mode == MP4 */
mov->mode = MODE_MP4;
@@ -3189,7 +3738,12 @@ static int mov_write_header(AVFormatContext *s)
av_log(s, AV_LOG_WARNING, "The faststart flag is incompatible "
"with fragmentation and custom IO, disabling faststart\n");
mov->flags &= ~FF_MOV_FLAG_FASTSTART;
- }
+ } else
+ mov->reserved_moov_size = -1;
+ }
+
+ if (!supports_edts(mov) && s->avoid_negative_ts < 0) {
+ s->avoid_negative_ts = 1;
}
/* Non-seekable output is ok if using fragmentation. If ism_lookahead
@@ -3200,10 +3754,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);
}
@@ -3226,6 +3790,32 @@ 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));
@@ -3238,6 +3828,7 @@ static int mov_write_header(AVFormatContext *s)
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
track->enc = st->codec;
+ track->st = st;
track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
if (track->language < 0)
track->language = 0;
@@ -3262,7 +3853,13 @@ static int mov_write_header(AVFormatContext *s)
}
track->height = track->tag >> 24 == 'n' ? 486 : 576;
}
- track->timescale = st->codec->time_base.den;
+ if (mov->video_track_timescale) {
+ track->timescale = mov->video_track_timescale;
+ } else {
+ track->timescale = st->codec->time_base.den;
+ while(track->timescale < 10000)
+ track->timescale *= 2;
+ }
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"
@@ -3270,17 +3867,23 @@ 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);
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) {
track->audio_vbr = 1;
}
if (track->mode != MODE_MOV &&
@@ -3293,6 +3896,8 @@ static int mov_write_header(AVFormatContext *s)
track->timescale = st->codec->time_base.den;
} else if (st->codec->codec_type == AVMEDIA_TYPE_DATA) {
track->timescale = st->codec->time_base.den;
+ } else {
+ track->timescale = MOV_TIMESCALE;
}
if (!track->height)
track->height = st->codec->height;
@@ -3321,6 +3926,12 @@ static int mov_write_header(AVFormatContext *s)
mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
}
+ 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 (mov->flags & FF_MOV_FLAG_FASTSTART)
mov->reserved_moov_pos = avio_tell(pb);
@@ -3342,12 +3953,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 (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 (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)
@@ -3478,6 +4108,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.
@@ -3505,7 +4148,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");
@@ -3514,6 +4157,19 @@ static int mov_write_trailer(AVFormatContext *s)
avio_seek(s->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");
+ for (i = 0; i < size; i++)
+ avio_w8(pb, 0);
+ avio_seek(pb, moov_pos, SEEK_SET);
} else {
mov_write_moov_tag(pb, mov, s);
}
@@ -3681,7 +4337,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 1b669e8..09f3ea7 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,16 +82,23 @@ 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 vos_len;
@@ -104,7 +112,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;
@@ -140,6 +148,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;
@@ -147,6 +156,7 @@ typedef struct MOVMuxContext {
int flags;
int rtp_flags;
+
int iods_skip;
int iods_video_profile;
int iods_audio_profile;
@@ -158,6 +168,10 @@ typedef struct MOVMuxContext {
int ism_lookahead;
AVIOContext *mdat_buf;
+ int use_editlist;
+ int video_track_timescale;
+
+ int reserved_moov_size; ///< 0 for disabled, -1 for automatic, size otherwise
int64_t reserved_moov_pos;
} MOVMuxContext;
diff --git a/libavformat/movenchint.c b/libavformat/movenchint.c
index a8f5f34..9d6a66e 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
*/
@@ -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;
diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c
index 5c263ed..30ec777 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/dict.h"
@@ -35,8 +36,15 @@
#define XING_TOC_COUNT 100
-typedef struct MP3DecContext {
+typedef struct {
+ AVClass *class;
+ int64_t filesize;
+ int64_t header_filesize;
int xing_toc;
+ int start_pad;
+ int end_pad;
+ int usetoc;
+ int is_cbr;
} MP3DecContext;
/* mp3 read */
@@ -46,7 +54,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;
@@ -73,31 +81,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) 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) return 1;
+ else return 0;
//mpegps_mp3_unrecognized_format.mpg has max_frames=3
}
@@ -105,22 +95,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;
}
/**
@@ -128,10 +120,11 @@ static void read_xing_toc(AVFormatContext *s, int64_t filesize, int64_t duration
*/
static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base)
{
+ MP3DecContext *mp3 = s->priv_data;
uint32_t v, spf;
unsigned frames = 0; /* Total number of frames in file */
unsigned size = 0; /* Total number of bytes in the stream */
- const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}};
+ static const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}};
MPADecodeHeader c;
int vbrtag_size = 0;
int is_cbr;
@@ -157,9 +150,21 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base)
frames = avio_rb32(s->pb);
if(v & XING_FLAG_SIZE)
size = avio_rb32(s->pb);
- if (v & XING_FLAG_TOC && frames)
+ if (v & XING_FLAG_TOC)
read_xing_toc(s, size, av_rescale_q(frames, (AVRational){spf, c.sample_rate},
st->time_base));
+ if(v & 8)
+ avio_skip(s->pb, 4);
+
+ v = avio_rb32(s->pb);
+ if(v == MKBETAG('L', 'A', 'M', 'E') || v == MKBETAG('L', 'a', 'v', 'f')) {
+ avio_skip(s->pb, 21-4);
+ v= avio_rb24(s->pb);
+ mp3->start_pad = v>>12;
+ mp3-> end_pad = v&4095;
+ st->skip_samples = mp3->start_pad + 528 + 1;
+ av_log(s, AV_LOG_DEBUG, "pad %d %d\n", mp3->start_pad, mp3-> end_pad);
+ }
}
/* Check for VBRI tag (always 32 bytes after end of mpegaudio header) */
@@ -187,11 +192,15 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base)
if (size && frames && !is_cbr)
st->codec->bit_rate = av_rescale(size, 8 * c.sample_rate, frames * (int64_t)spf);
+ mp3->is_cbr = is_cbr;
+ mp3->header_filesize = size;
+
return 0;
}
static int mp3_read_header(AVFormatContext *s)
{
+ MP3DecContext *mp3 = s->priv_data;
AVStream *st;
int64_t off;
@@ -201,17 +210,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);
@@ -223,15 +236,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;
@@ -241,38 +265,93 @@ 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;
+
+ if (mp3->is_cbr && st->duration > 0 && mp3->header_filesize > s->data_offset) {
+ 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];
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
+ for(i=0; i<4096; i++) {
+ int64_t pos = ie->pos + i*dir;
+ for(j=0; j<MIN_VALID; j++) {
+ ret = check(s, pos);
+ if(ret < 0)
+ break;
+ pos += ret;
}
+ if(j==MIN_VALID)
+ break;
}
+ if(j!=MIN_VALID)
+ i=0;
- return AVERROR_EOF;
+ ret = avio_seek(s->pb, ie->pos + i*dir, 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)"),
@@ -283,4 +362,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 574a3b2..a5f672b 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
*/
@@ -51,11 +51,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, "TDRL", 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);
@@ -110,19 +111,22 @@ 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;
- int32_t header;
- MPADecodeHeader mpah;
- int srate_idx, i, channels;
- int bitrate_idx;
- int xing_offset;
- int ver = 0;
+ int bitrate_idx;
+ int best_bitrate_idx = -1;
+ int best_bitrate_error= INT_MAX;
+ int xing_offset;
+ int32_t header, mask;
+ MPADecodeHeader c;
+ int srate_idx, ver = 0, i, channels;
+ int needed;
+ const char *vendor = (codec->flags & CODEC_FLAG_BITEXACT) ? "Lavf" : LIBAVFORMAT_IDENT;
if (!s->pb->seekable)
- 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];
@@ -136,9 +140,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) {
@@ -146,41 +149,76 @@ 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;
}
- /* 64 kbps frame, should be large enough */
- bitrate_idx = (ver == 3) ? 5 : 8;
-
/* 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 |= (bitrate_idx << 4 | srate_idx << 2) << 8;
+ header |= (srate_idx << 2) << 8;
header |= channels << 6;
- avio_wb32(s->pb, header);
- avpriv_mpegaudio_decode_header(&mpah, header);
+ for (bitrate_idx=1; bitrate_idx<15; bitrate_idx++) {
+ int error;
+ avpriv_mpegaudio_decode_header(&c, header | (bitrate_idx << (4+8)));
+ error= FFABS(c.bit_rate - codec->bit_rate);
+ 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++) {
+ if (15 == bitrate_idx)
+ return -1;
+ mask = bitrate_idx << (4+8);
+ header |= mask;
+ avpriv_mpegaudio_decode_header(&c, header);
+ xing_offset=xing_offtbl[c.lsf == 1][c.nb_channels == 1];
+ needed = 4 // header
+ + xing_offset
+ + 4 // xing tag
+ + 4 // frames/size/toc flags
+ + 4 // frames
+ + 4 // size
+ + XING_TOC_SIZE // toc
+ + 24
+ ;
+
+ if (needed <= c.frame_size)
+ break;
+ header &= ~mask;
+ }
- av_assert0(mpah.frame_size >= XING_MAX_SIZE);
+ avio_wb32(s->pb, header);
- xing_offset = xing_offtbl[ver != 3][codec->channels == 1];
ffio_fill(s->pb, 0, xing_offset);
mp3->xing_offset = avio_tell(s->pb);
ffio_wfourcc(s->pb, "Xing");
avio_wb32(s->pb, 0x01 | 0x02 | 0x04); // frames / size / TOC
- mp3->size = mpah.frame_size;
- mp3->want = 1;
+ mp3->size = c.frame_size;
+ mp3->want=1;
+ mp3->seen=0;
+ mp3->pos=0;
avio_wb32(s->pb, 0); // frames
avio_wb32(s->pb, 0); // size
- // TOC
- for (i = 0; i < XING_TOC_SIZE; i++)
- avio_w8(s->pb, 255 * i / XING_TOC_SIZE);
+ // toc
+ for (i = 0; i < XING_TOC_SIZE; ++i)
+ avio_w8(s->pb, (uint8_t)(255 * i / XING_TOC_SIZE));
- mpah.frame_size -= 4 + xing_offset + 4 + 4 + 4 + 4 + XING_TOC_SIZE;
- ffio_fill(s->pb, 0, mpah.frame_size);
+ for (i = 0; i < strlen(vendor); ++i)
+ avio_w8(s->pb, vendor[i]);
+ for (; i < 21; ++i)
+ avio_w8(s->pb, 0);
+ avio_wb24(s->pb, FFMAX(codec->delay - 528 - 1, 0)<<12);
+
+ ffio_fill(s->pb, 0, c.frame_size - needed);
+
+ return 0;
}
/*
@@ -201,7 +239,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;
@@ -217,17 +255,43 @@ static int mp3_write_audio_packet(AVFormatContext *s, AVPacket *pkt)
{
MP3Context *mp3 = s->priv_data;
- if (mp3->xing_offset && pkt->size >= 4) {
+ if (pkt->data && pkt->size >= 4) {
MPADecodeHeader c;
+ int av_unused base;
+ uint32_t head = AV_RB32(pkt->data);
- avpriv_mpegaudio_decode_header(&c, AV_RB32(pkt->data));
+ if (ff_mpa_check_header(head) < 0) {
+ av_log(s, AV_LOG_WARNING, "Audio packet of size %d (starting with %08X...) "
+ "is invalid, writing it anyway.\n", pkt->size, head);
+ return ff_raw_write_packet(s, pkt);
+ }
+ avpriv_mpegaudio_decode_header(&c, head);
if (!mp3->initial_bitrate)
mp3->initial_bitrate = c.bit_rate;
if ((c.bit_rate == 0) || (mp3->initial_bitrate != c.bit_rate))
mp3->has_variable_bitrate = 1;
- mp3_xing_add_frame(mp3, pkt);
+#ifdef FILTER_VBR_HEADERS
+ /* filter out XING and INFO headers. */
+ base = 4 + xing_offtbl[c.lsf == 1][c.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);
}
return ff_raw_write_packet(s, pkt);
@@ -301,6 +365,17 @@ static int mp3_write_trailer(struct AVFormatContext *s)
return 0;
}
+static int query_codec(enum AVCodecID id, int std_compliance)
+{
+ const CodecMime *cm= ff_id3v2_mime_tags;
+ while(cm->id != AV_CODEC_ID_NONE) {
+ if(id == cm->id)
+ return MKTAG('A', 'P', 'I', 'C');
+ cm++;
+ }
+ return -1;
+}
+
#if CONFIG_MP2_MUXER
AVOutputFormat ff_mp2_muxer = {
.name = "mp2",
@@ -436,6 +511,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..8abc488 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,8 +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);
+ if (ff_alloc_extradata(st->codec, 16))
+ return AVERROR(ENOMEM);
avio_read(s->pb, st->codec->extradata, 16);
st->codec->sample_rate = mpc_rate[st->codec->extradata[2] & 3];
avpriv_set_pts_info(st, 32, MPC_FRAMESIZE, st->codec->sample_rate);
@@ -196,11 +196,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..7017c18 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)
@@ -150,7 +150,7 @@ 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;
}
@@ -213,7 +213,7 @@ static int mpc8_read_header(AVFormatContext *s)
return AVERROR_INVALIDDATA;
}
- while(!pb->eof_reached){
+ while(!url_feof(pb)){
pos = avio_tell(pb);
mpc8_get_chunk_header(pb, &tag, &size);
if(tag == TAG_STREAMHDR)
@@ -241,8 +241,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);
+ if (ff_alloc_extradata(st->codec, 2))
+ return AVERROR(ENOMEM);
avio_read(pb, st->codec->extradata, st->codec->extradata_size);
st->codec->channels = (st->codec->extradata[1] >> 4) + 1;
@@ -251,6 +251,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 +269,7 @@ static int mpc8_read_packet(AVFormatContext *s, AVPacket *pkt)
int tag;
int64_t pos, size;
- while(!s->pb->eof_reached){
+ while(!url_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 7430bb0..1ea58d5 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
&& (p[4] & 0xC0) != 0x40
@@ -74,6 +80,7 @@ static int mpegps_probe(AVProbeData *p)
// 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 == 0x1fd && pes) vid++; //VC1
else if((code & 0xf0) == VIDEO_ID && !pes) invalid++;
else if((code & 0xe0) == AUDIO_ID && !pes) invalid++;
@@ -81,18 +88,19 @@ static int mpegps_probe(AVProbeData *p)
}
}
- 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 more than .mpg
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;
}
@@ -101,25 +109,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;
@@ -144,7 +157,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 (url_feof(pb))
break;
v = avio_r8(pb);
n--;
@@ -218,7 +231,7 @@ static int mpegps_read_pes_header(AVFormatContext *s,
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(url_feof(s->pb))
return AVERROR_EOF;
//FIXME we should remember header_state
return AVERROR(EAGAIN);
@@ -233,21 +246,82 @@ static int mpegps_read_pes_header(AVFormatContext *s,
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);
@@ -257,7 +331,9 @@ static int mpegps_read_pes_header(AVFormatContext *s,
/* 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;
@@ -265,6 +341,8 @@ static int mpegps_read_pes_header(AVFormatContext *s,
len = avio_rb16(s->pb);
pts =
dts = AV_NOPTS_VALUE;
+ if (startcode != PRIVATE_STREAM_2)
+ {
/* stuffing */
for(;;) {
if (len < 1)
@@ -338,22 +416,11 @@ static int mpegps_read_pes_header(AVFormatContext *s,
}
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;
@@ -380,20 +447,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 supress 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 */
@@ -404,7 +481,6 @@ static int mpegps_read_packet(AVFormatContext *s,
}
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;
@@ -427,9 +503,9 @@ static int mpegps_read_packet(AVFormatContext *s,
} 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];
@@ -438,8 +514,11 @@ static int mpegps_read_packet(AVFormatContext *s,
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;
@@ -453,7 +532,11 @@ static int mpegps_read_packet(AVFormatContext *s,
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;
@@ -467,19 +550,6 @@ static int mpegps_read_packet(AVFormatContext *s,
} 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 */
@@ -493,10 +563,24 @@ static int mpegps_read_packet(AVFormatContext *s,
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;
pkt->dts = dts;
@@ -547,3 +631,319 @@ 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,"
+
+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;
+
+ 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);
+ ret = avformat_open_input(&vobsub->sub_ctx, sub_name, &ff_mpegps_demuxer, 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 (!url_feof(s->pb)) {
+ char line[2048];
+ int len = ff_get_line(s->pb, line, sizeof(line));
+
+ if (!len)
+ break;
+
+ line[strcspn(line, "\r\n")] = 0;
+
+ if (!strncmp(line, "id:", 3)) {
+ int n, stream_id = 0;
+ char id[64] = {0};
+
+ n = sscanf(line, "id: %63[^,], index: %u", id, &stream_id);
+ if (n != 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;
+ }
+
+ 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);
+ av_log(s, AV_LOG_DEBUG, "IDX stream[%d] id=%s\n", stream_id, id);
+ header_parsed = 1;
+
+ } else if (st && !strncmp(line, "timestamp:", 10)) {
+ AVPacket *sub;
+ int hh, mm, ss, ms;
+ int64_t pos, timestamp;
+ const char *p = line + 10;
+
+ if (!s->nb_streams) {
+ av_log(s, AV_LOG_ERROR, "Timestamp declared before any stream\n");
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+
+ 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);
+ break;
+ }
+ timestamp = (hh*3600LL + mm*60LL + ss) * 1000LL + ms + delay;
+ timestamp = av_rescale_q(timestamp, (AVRational){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 (st && !strncmp(line, "alt:", 4)) {
+ const char *p = line + 4;
+
+ while (*p == ' ')
+ p++;
+ av_dict_set(&st->metadata, "title", p, 0);
+ av_log(s, AV_LOG_DEBUG, "IDX stream[%d] name=%s\n", st->id, p);
+ 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;
+}
+
+#define FAIL(r) do { ret = r; goto fail; } while (0)
+
+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 = 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;
+ FAIL(ret);
+ }
+ 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)
+ FAIL(ret);
+
+ 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 629f2f0..cf10d6a 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
*/
@@ -41,7 +41,7 @@
#define AUDIO_ID 0xc0
#define VIDEO_ID 0xe0
#define AC3_ID 0x80
-#define DTS_ID 0x8a
+#define DTS_ID 0x88
#define LPCM_ID 0xa0
#define SUB_ID 0x20
diff --git a/libavformat/mpegenc.c b/libavformat/mpegenc.c
index 85a12d6..0a9d69b 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
*/
@@ -66,6 +66,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;
@@ -264,8 +265,7 @@ static int put_system_header(AVFormatContext *ctx, uint8_t *buf,int only_for_str
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;
}
@@ -320,7 +320,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;
@@ -379,6 +379,10 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx)
av_log(ctx, AV_LOG_WARNING, "VBV buffer size not set, muxing may fail\n");
stream->max_buffer_size = 230*1024; //FIXME this is probably too small as default
}
+ 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:
@@ -416,12 +420,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) {
@@ -480,7 +490,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:
for(i=0;i<ctx->nb_streams;i++) {
@@ -838,7 +848,7 @@ static int flush_packet(AVFormatContext *ctx, int stream_index,
/* output data */
assert(payload_size - stuffing_size <= av_fifo_size(stream->fifo));
- av_fifo_generic_read(stream->fifo, ctx->pb, payload_size - stuffing_size, &avio_write);
+ av_fifo_generic_read(stream->fifo, ctx->pb, payload_size - stuffing_size, (void*)avio_write);
stream->bytes_to_iframe -= payload_size - stuffing_size;
}else{
payload_size=
@@ -903,7 +913,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;
}
@@ -935,7 +945,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,
@@ -945,14 +955,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;
@@ -1059,13 +1071,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);
@@ -1133,7 +1154,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, INT_MAX, 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 d623452..c91018e 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -2,20 +2,20 @@
* MPEG2 transport stream (aka DVB) demuxer
* Copyright (c) 2002-2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
#include "libavcodec/bytestream.h"
#include "libavcodec/get_bits.h"
#include "libavcodec/mathops.h"
@@ -52,7 +53,7 @@ enum MpegTSFilterType {
typedef struct MpegTSFilter MpegTSFilter;
-typedef int PESCallback(MpegTSFilter *f, const uint8_t *buf, int len, int is_start, int64_t pos);
+typedef int PESCallback(MpegTSFilter *f, const uint8_t *buf, int len, int is_start, int64_t pos, int64_t cur_pcr);
typedef struct MpegTSPESFilter {
PESCallback *pes_cb;
@@ -98,9 +99,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;
@@ -108,6 +111,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,12 +132,14 @@ 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;
};
-static const AVOption options[] = {
+static const AVOption mpegtsraw_options[] = {
{"compute_pcr", "Compute exact PCR for each transport stream packet.", offsetof(MpegTSContext, mpeg2ts_compute_pcr), AV_OPT_TYPE_INT,
{.i64 = 0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
{ NULL },
@@ -140,7 +148,20 @@ static const AVOption options[] = {
static const AVClass mpegtsraw_class = {
.class_name = "mpegtsraw demuxer",
.item_name = av_default_item_name,
- .option = options,
+ .option = mpegtsraw_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static const AVOption 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 },
+ { NULL },
+};
+
+static const AVClass mpegts_class = {
+ .class_name = "mpegts demuxer",
+ .item_name = av_default_item_name,
+ .option = mpegts_options,
.version = LIBAVUTIL_VERSION_INT,
};
@@ -179,14 +200,30 @@ typedef struct PESContext {
uint8_t header[MAX_PES_HEADER_SIZE];
AVBufferRef *buffer;
SLConfigDescr sl;
+ int64_t last_pcr;
} PESContext;
extern AVInputFormat ff_mpegts_demuxer;
+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)
ts->prg[i].nb_pids = 0;
@@ -229,6 +266,17 @@ static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, unsigned i
p->pids[p->nb_pids++] = pid;
}
+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
@@ -280,6 +328,7 @@ static int discard_pid(MpegTSContext *ts, unsigned int pid)
static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1,
const uint8_t *buf, int buf_size, int is_start)
{
+ MpegTSContext *ts = s->priv_data;
MpegTSSectionFilter *tss = &tss1->u.section_filter;
int len;
@@ -307,10 +356,19 @@ static void write_section_data(AVFormatContext *s, 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);
}
}
@@ -400,7 +458,7 @@ static int analyze(const uint8_t *buf, int size, int packet_size, int *index){
memset(stat, 0, packet_size*sizeof(int));
for(x=i=0; i<size-3; i++){
- if(buf[i] == 0x47 && !(buf[i+1] & 0x80) && (buf[i+3] & 0x30)){
+ if(buf[i] == 0x47 && !(buf[i+1] & 0x80) && buf[i+3] != 0x47){
stat[x]++;
if(stat[x] > best_score){
best_score= stat[x];
@@ -535,8 +593,13 @@ static const StreamType ISO_types[] = {
{ 0x04, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 },
{ 0x0f, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC },
{ 0x10, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG4 },
+ /* Makito encoder sets stream type 0x11 for AAC,
+ * so auto-detect LOAS/LATM instead of hardcoding it. */
+#if !CONFIG_LOAS_DEMUXER
{ 0x11, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC_LATM }, /* LATM syntax */
+#endif
{ 0x1b, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 },
+ { 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC },
{ 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS },
{ 0xd1, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC },
{ 0xea, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 },
@@ -551,6 +614,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 },
};
@@ -569,10 +634,17 @@ static const StreamType REGD_types[] = {
{ MKTAG('D','T','S','1'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS },
{ 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 },
{ 0 },
};
+static const StreamType METADATA_types[] = {
+ { MKTAG('K','L','V','A'), AVMEDIA_TYPE_DATA, AV_CODEC_ID_SMPTE_KLV },
+ { 0 },
+};
+
/* descriptor present */
static const StreamType DESC_types[] = {
{ 0x6a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, /* AC-3 descriptor */
@@ -586,10 +658,16 @@ static const StreamType DESC_types[] = {
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;
}
}
@@ -598,6 +676,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;
@@ -613,7 +699,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) {
@@ -643,6 +730,10 @@ 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;
}
@@ -681,6 +772,13 @@ static void new_pes_packet(PESContext *pes, AVPacket *pkt)
pes->flags = 0;
}
+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, const uint8_t *buf, int buf_size)
{
GetBitContext gb;
@@ -688,6 +786,7 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf
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);
if (sl->use_au_start)
@@ -726,9 +825,9 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf
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)
@@ -749,7 +848,7 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf
/* return non zero if a packet could be constructed */
static int mpegts_push_data(MpegTSFilter *filter,
const uint8_t *buf, int buf_size, int is_start,
- int64_t pos)
+ int64_t pos, int64_t pcr)
{
PESContext *pes = filter->u.pes_filter.opaque;
MpegTSContext *ts = pes->ts;
@@ -759,6 +858,9 @@ static int mpegts_push_data(MpegTSFilter *filter,
if(!ts->pkt)
return 0;
+ if (pcr != -1)
+ pes->last_pcr = pcr;
+
if (is_start) {
if (pes->state == MPEGTS_PAYLOAD && pes->data_index > 0) {
new_pes_packet(pes, ts->pkt);
@@ -819,10 +921,10 @@ 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;
@@ -905,6 +1007,38 @@ static int mpegts_push_data(MpegTSFilter *filter,
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 && f->type == MPEGTS_PES) {
+ PESContext *pcrpes = f->u.pes_filter.opaque;
+ if (pcrpes && pcrpes->last_pcr != -1 && pcrpes->st && pcrpes->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 = pcrpes->last_pcr / 300;
+ pes->st->pts_wrap_reference = pcrpes->st->pts_wrap_reference;
+ pes->st->pts_wrap_behavior = pcrpes->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:
@@ -961,6 +1095,7 @@ static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid)
pes->state = MPEGTS_SKIP;
pes->pts = AV_NOPTS_VALUE;
pes->dts = AV_NOPTS_VALUE;
+ pes->last_pcr = -1;
tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes);
if (!tss) {
av_free(pes);
@@ -1292,15 +1427,17 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
break;
case 0x1F: /* FMC descriptor */
get16(pp, desc_end);
- if (mp4_descr_count > 0 && st->codec->codec_id == AV_CODEC_ID_AAC_LATM &&
+ if (mp4_descr_count > 0 && (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,
mp4_descr->dec_config_descr_len, 0, 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 */
@@ -1330,9 +1467,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
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;
+ if (!ff_alloc_extradata(st->codec, 4)) {
memcpy(st->codec->extradata, *pp, 4);
}
}
@@ -1362,6 +1497,18 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
if (st->codec->codec_id == AV_CODEC_ID_NONE)
mpegts_find_stream_type(st, st->codec->codec_tag, REGD_types);
break;
+ case 0x52: /* stream identifier descriptor */
+ st->stream_identifier = 1 + get8(pp, desc_end);
+ break;
+ case 0x26: /* metadata descriptor */
+ if (get16(pp, desc_end) == 0xFFFF)
+ *pp += 4;
+ if (get8(pp, desc_end) == 0xFF) {
+ st->codec->codec_tag = bytestream_get_le32(pp);
+ if (st->codec->codec_id == AV_CODEC_ID_NONE)
+ mpegts_find_stream_type(st, st->codec->codec_tag, METADATA_types);
+ }
+ break;
default:
break;
}
@@ -1404,6 +1551,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
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);
@@ -1440,7 +1588,7 @@ 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;
for(;;) {
st = 0;
@@ -1452,12 +1600,16 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
if (pid < 0)
break;
pid &= 0x1fff;
+ if (pid == ts->current_pid)
+ break;
/* 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;
@@ -1466,6 +1618,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 {
@@ -1474,6 +1628,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;
}
@@ -1520,6 +1676,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);
@@ -1531,6 +1688,8 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
if (h->tid != PAT_TID)
return;
+ ts->stream->ts_id = h->id;
+
clear_programs(ts);
for(;;) {
sid = get16(&p, p_end);
@@ -1541,20 +1700,42 @@ 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);
+ 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)
+ clear_avprogram(ts, ts->stream->programs[j]->id);
+ }
+ }
}
static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
@@ -1634,6 +1815,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)
{
@@ -1655,6 +1839,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 */
@@ -1675,7 +1860,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) {
@@ -1697,7 +1882,10 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
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) {
@@ -1726,15 +1914,53 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
}
} else {
int ret;
+ int64_t pcr = -1;
+ int64_t pcr_h;
+ int pcr_l;
+ if (parse_pcr(&pcr_h, &pcr_l, packet) == 0)
+ pcr = pcr_h * 300 + pcr_l;
// 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)
+ pos - ts->raw_packet_size, pcr)) < 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)
@@ -1744,10 +1970,11 @@ static int mpegts_resync(AVFormatContext *s)
for(i = 0;i < MAX_RESYNC_SIZE; i++) {
c = avio_r8(pb);
- if (pb->eof_reached)
+ if (url_feof(pb))
return -1;
if (c == 0x47) {
avio_seek(pb, -1, SEEK_CUR);
+ reanalyze(s->priv_data);
return 0;
}
}
@@ -1769,7 +1996,7 @@ static int read_packet(AVFormatContext *s, uint8_t *buf, int raw_packet_size, co
/* check packet sync byte */
if ((*data)[0] != 0x47) {
/* find a new packet start */
- avio_seek(pb, -TS_PACKET_SIZE, SEEK_CUR);
+ avio_seek(pb, -raw_packet_size, SEEK_CUR);
if (mpegts_resync(s) < 0)
return AVERROR(EAGAIN);
else
@@ -1792,7 +2019,7 @@ static void finished_reading_packet(AVFormatContext *s, int raw_packet_size)
static int handle_packets(MpegTSContext *ts, int nb_packets)
{
AVFormatContext *s = ts->stream;
- uint8_t packet[TS_PACKET_SIZE+FF_INPUT_BUFFER_PADDING_SIZE];
+ uint8_t packet[TS_PACKET_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
const uint8_t *data;
int packet_num, ret = 0;
@@ -1807,6 +2034,7 @@ static int handle_packets(MpegTSContext *ts, int nb_packets)
av_buffer_unref(&pes->buffer);
pes->data_index = 0;
pes->state = MPEGTS_SKIP; /* skip until pes header */
+ pes->last_pcr = -1;
}
ts->pids[i]->last_cc = -1;
}
@@ -1817,11 +2045,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;
@@ -1837,24 +2069,34 @@ 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 -1;
- 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;
-// 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;
- else return -1;
+ av_dlog(0, "TS score: %d %d\n", sumscore, maxscore);
+
+ if (sumscore > 6) return AVPROBE_SCORE_MAX + sumscore - CHECK_COUNT;
+ else if (maxscore > 6) return AVPROBE_SCORE_MAX/2 + sumscore - CHECK_COUNT;
+ else return -1;
}
/* return the 90kHz PCR and the extension for the 27MHz PCR. return
@@ -1886,22 +2128,33 @@ static int parse_pcr(int64_t *ppcr_high, int *ppcr_low,
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;
- /* read the first 1024 bytes to get packet size */
+ ffio_ensure_seekback(pb, s->probesize);
+
+ /* read the first 8192 bytes to get packet size */
pos = avio_tell(pb);
len = avio_read(pb, buf, sizeof(buf));
- if (len != sizeof(buf))
- goto fail;
- ts->raw_packet_size = get_packet_size(buf, sizeof(buf));
- if (ts->raw_packet_size <= 0)
- goto fail;
+ 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;
@@ -1909,8 +2162,7 @@ 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);
@@ -1948,7 +2200,7 @@ static int mpegts_read_header(AVFormatContext *s)
for(;;) {
ret = read_packet(s, packet, ts->raw_packet_size, &data);
if (ret < 0)
- return -1;
+ goto fail;
pid = AV_RB16(data + 1) & 0x1fff;
if ((pcr_pid == -1 || pcr_pid == pid) &&
parse_pcr(&pcr_h, &pcr_l, data) == 0) {
@@ -1976,7 +2228,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;
fail:
return -1;
@@ -2042,6 +2294,7 @@ static int mpegts_read_packet(AVFormatContext *s,
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) {
@@ -2078,66 +2331,68 @@ 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;
int64_t pos, timestamp;
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;
- 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)
+ 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;
+ 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;
-
- if (ff_seek_frame_binary(s, stream_index, target_ts, flags) < 0)
- return -1;
-
- pos= avio_tell(s->pb);
-
- for(;;) {
- avio_seek(s->pb, pos, SEEK_SET);
- if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
- return -1;
-// pid = AV_RB16(buf + 1) & 0x1fff;
- if(buf[1] & 0x40) break;
- pos += ts->raw_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 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;
}
/**************************************************************/
@@ -2154,6 +2409,9 @@ 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;
}
@@ -2166,10 +2424,8 @@ int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt,
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 -1;
if (buf[0] != 0x47) {
@@ -2179,6 +2435,8 @@ 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;
@@ -2198,9 +2456,9 @@ 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,
};
AVInputFormat ff_mpegtsraw_demuxer = {
@@ -2210,8 +2468,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 fafe98f..269c23b 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
*/
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index 8efd93e..1d51b97 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -2,20 +2,20 @@
* 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
*/
@@ -25,6 +25,7 @@
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
#include "libavcodec/internal.h"
#include "avformat.h"
#include "internal.h"
@@ -76,12 +77,15 @@ typedef struct MpegTSWrite {
int pmt_start_pid;
int start_pid;
+ int m2ts_mode;
int reemit_pat_pmt; // backward compatibility
#define MPEGTS_FLAG_REEMIT_PAT_PMT 0x01
#define MPEGTS_FLAG_AAC_LATM 0x02
int flags;
+ int copyts;
+ int tables_version;
} MpegTSWrite;
/* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */
@@ -96,9 +100,12 @@ static const AVOption options[] = {
{ "mpegts_service_id", "Set service_id field.",
offsetof(MpegTSWrite, service_id), AV_OPT_TYPE_INT, {.i64 = 0x0001 }, 0x0001, 0xffff, AV_OPT_FLAG_ENCODING_PARAM},
{ "mpegts_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},
+ offsetof(MpegTSWrite, pmt_start_pid), AV_OPT_TYPE_INT, {.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},
{ "pes_payload_size", "Minimum PES packet payload in bytes",
offsetof(MpegTSWrite, pes_payload_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT_PES_PAYLOAD_SIZE}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
@@ -113,6 +120,10 @@ static const AVOption options[] = {
// backward compatibility
{ "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},
{ NULL },
};
@@ -191,7 +202,7 @@ static int mpegts_write_section1(MpegTSSection *s, int tid, int id,
tot_len = 3 + 5 + len + 4;
/* check if not too big */
if (tot_len > 1024)
- return -1;
+ return AVERROR_INVALIDDATA;
q = section;
*q++ = tid;
@@ -209,7 +220,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 */
@@ -223,6 +234,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;
@@ -243,7 +255,7 @@ 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);
}
@@ -311,6 +323,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;
@@ -374,13 +400,23 @@ 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);
desc_length_ptr[0] = val >> 8;
desc_length_ptr[1] = val;
}
- 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);
}
@@ -435,7 +471,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);
}
@@ -458,9 +494,28 @@ static MpegTSService *mpegts_add_service(MpegTSWrite *ts,
return service;
}
+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);
}
@@ -601,9 +656,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) {
@@ -620,6 +676,8 @@ static int mpegts_write_header(AVFormatContext *s)
service->pcr_packet_period =
pcr_st->codec->time_base.den/(10*pcr_st->codec->time_base.num);
}
+ if(!service->pcr_packet_period)
+ service->pcr_packet_period = 1;
}
// output a PCR as soon as possible
@@ -636,6 +694,14 @@ static int mpegts_write_header(AVFormatContext *s)
service->pcr_packet_period,
ts->sdt_packet_period, ts->pat_packet_period);
+ if (ts->m2ts_mode == -1) {
+ if (av_match_ext(s->filename, "m2ts")) {
+ ts->m2ts_mode = 1;
+ } else {
+ ts->m2ts_mode = 0;
+ }
+ }
+
avio_flush(s->pb);
return 0;
@@ -659,7 +725,7 @@ static int mpegts_write_header(AVFormatContext *s)
}
/* 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;
@@ -668,7 +734,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++) {
@@ -677,12 +743,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;
@@ -709,6 +769,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);
}
@@ -734,6 +795,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);
}
@@ -755,7 +817,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
@@ -771,7 +833,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;
}
@@ -801,10 +863,12 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
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) {
@@ -874,6 +938,10 @@ 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) {
@@ -903,6 +971,17 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
*/
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;
+ }
len = payload_size + header_len + 3;
if (private_code != 0)
len++;
@@ -911,8 +990,8 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
*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;
@@ -935,6 +1014,17 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
*/
*q++ = 0x00 | 0x60;
}
+ /* 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 (private_code != 0)
*q++ = private_code;
is_start = 0;
@@ -970,9 +1060,11 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
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;
}
static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
@@ -983,8 +1075,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, "resend_headers option is deprecated, use -mpegts_flags resend_headers\n");
@@ -998,14 +1090,16 @@ 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");
- return AVERROR(EINVAL);
+ av_log(s, AV_LOG_ERROR, "first pts value must be set\n");
+ return AVERROR_INVALIDDATA;
}
ts_st->first_pts_check = 0;
@@ -1014,9 +1108,12 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
uint32_t state = -1;
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 -bsf h264_mp4toannexb\n");
+ "no startcode found, use the h264_mp4toannexb bitstream filter (-bsf h264_mp4toannexb)\n");
return AVERROR(EINVAL);
+ }
+ av_log(s, AV_LOG_WARNING, "H.264 bitstream error, startcode missing\n");
}
do {
@@ -1039,7 +1136,7 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
} else if (st->codec->codec_id == AV_CODEC_ID_AAC) {
if (pkt->size < 2) {
av_log(s, AV_LOG_ERROR, "AAC packet too short\n");
- return AVERROR(EINVAL);
+ return AVERROR_INVALIDDATA;
}
if ((AV_RB16(pkt->data) & 0xfff0) != 0xfff0) {
int ret;
@@ -1048,7 +1145,7 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
if (!ts_st->amux) {
av_log(s, AV_LOG_ERROR, "AAC bitstream not in ADTS format "
"and extradata missing\n");
- return AVERROR(EINVAL);
+ return AVERROR_INVALIDDATA;
}
av_init_packet(&pkt2);
@@ -1071,28 +1168,36 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
}
}
- if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
+ 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 || 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);
av_free(data);
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;
@@ -1168,7 +1273,7 @@ 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",
+ .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..a400978 100644
--- a/libavformat/mpegvideodec.c
+++ b/libavformat/mpegvideodec.c
@@ -3,20 +3,20 @@
* 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
*/
@@ -34,8 +34,9 @@
static int mpegvideo_probe(AVProbeData *p)
{
uint32_t code= -1;
- int pic=0, seq=0, slice=0, pspack=0, pes=0;
+ int pic=0, seq=0, slice=0, pspack=0, vpes=0, apes=0, res=0, sicle=0;
int i;
+ uint32_t last = 0;
for(i=0; i<p->buf_size; i++){
code = (code<<8) + p->buf[i];
@@ -43,15 +44,28 @@ static int mpegvideo_probe(AVProbeData *p)
switch(code){
case SEQ_START_CODE: 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 & 0x1f0) == VIDEO_ID) pes++;
- else if((code & 0x1e0) == AUDIO_ID) pes++;
+ 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) 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 2114189..2586ea8 100644
--- a/libavformat/mpjpeg.c
+++ b/libavformat/mpjpeg.c
@@ -2,33 +2,33 @@
* 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 "avformat.h"
/* Multipart JPEG */
-#define BOUNDARY_TAG "avserver"
+#define BOUNDARY_TAG "ffserver"
static int mpjpeg_write_header(AVFormatContext *s)
{
uint8_t buf1[256];
- snprintf(buf1, sizeof(buf1), "--%s\n", BOUNDARY_TAG);
+ snprintf(buf1, sizeof(buf1), "--%s\r\n", BOUNDARY_TAG);
avio_write(s->pb, buf1, strlen(buf1));
avio_flush(s->pb);
return 0;
@@ -38,11 +38,14 @@ static int mpjpeg_write_packet(AVFormatContext *s, AVPacket *pkt)
{
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", BOUNDARY_TAG);
avio_write(s->pb, buf1, strlen(buf1));
return 0;
}
diff --git a/libavformat/mpl2dec.c b/libavformat/mpl2dec.c
new file mode 100644
index 0000000..17b302d
--- a/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 (!url_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..c5bdcdb
--- a/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 (!url_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..0ac1c30 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 && !url_feof(pb));
- if(pb->eof_reached) {
- av_log(ctx, AV_LOG_ERROR, "Could not find valid start.");
+ if(url_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 ed250bc..0517dd2 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
*/
@@ -42,10 +42,10 @@ 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;
@@ -57,7 +57,7 @@ static int mtv_probe(AVProbeData *p)
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])))
+ if(p->buf_size < 57 || !(p->buf[51] && AV_RL16(&p->buf[52]) | AV_RL16(&p->buf[54])))
return 0;
/* If width or height are 0 then imagesize header field should not */
@@ -96,13 +96,19 @@ static int mtv_read_header(AVFormatContext *s)
/* Calculate width and height if missing from header */
- if(!mtv->img_width)
+ if(mtv->img_bpp>>3){
+ if(!mtv->img_width && mtv->img_height)
mtv->img_width=mtv->img_segment_size / (mtv->img_bpp>>3)
/ mtv->img_height;
- if(!mtv->img_height)
+ if(!mtv->img_height && mtv->img_width)
mtv->img_height=mtv->img_segment_size / (mtv->img_bpp>>3)
/ mtv->img_width;
+ }
+ 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(EINVAL);
+ }
avio_skip(pb, 4);
audio_subsegments = avio_rl16(pb);
diff --git a/libavformat/mux.c b/libavformat/mux.c
index 505ed2e..eff7caa 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,7 +49,7 @@
/**
* @file
- * muxing functions for use within Libav
+ * muxing functions for use within libavformat
*/
/* fraction handling */
@@ -101,6 +102,88 @@ static void frac_add(AVFrac *f, int64_t incr)
f->num = num;
}
+AVRational ff_choose_timebase(AVFormatContext *s, AVStream *st, int min_precission)
+{
+ AVRational q;
+ int j;
+
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ q = (AVRational){1, st->codec->sample_rate};
+ } else {
+ q = st->codec->time_base;
+ }
+ for (j=2; j<14; j+= 1+(j>2))
+ while (q.den / q.num < min_precission && q.num % j == 0)
+ q.num /= j;
+ while (q.den / q.num < min_precission && 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;
+}
+
+#if FF_API_ALLOC_OUTPUT_CONTEXT
+AVFormatContext *avformat_alloc_output_context(const char *format,
+ AVOutputFormat *oformat, const char *filename)
+{
+ AVFormatContext *avctx;
+ int ret = avformat_alloc_output_context2(&avctx, oformat, format, filename);
+ return ret < 0 ? NULL : avctx;
+}
+#endif
+
static int validate_codec_tag(AVFormatContext *s, AVStream *st)
{
const AVCodecTag *avctag;
@@ -148,6 +231,9 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
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_dict(s->priv_data, &tmp)) < 0)
+ goto fail;
// some sanity checks
if (s->nb_streams == 0 && !(of->flags & AVFMT_NOSTREAMS)) {
@@ -185,18 +271,18 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
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.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;
}
@@ -205,21 +291,23 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
}
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;
}
@@ -305,6 +393,8 @@ 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;
}
@@ -312,20 +402,24 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options)
if ((ret = init_pts(s)) < 0)
return ret;
+ if (s->avoid_negative_ts < 0) {
+ if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) {
+ s->avoid_negative_ts = 0;
+ } else
+ s->avoid_negative_ts = 1;
+ }
+
return 0;
}
//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, frame_size, i;
- 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);
-
-/* if(pkt->pts == AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE)
- * return AVERROR(EINVAL);*/
+ 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);
/* duration field */
if (pkt->duration == 0) {
@@ -340,6 +434,11 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt)
//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;
@@ -360,17 +459,18 @@ 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 < dts in stream %d\n", st->index);
+ av_log(s, AV_LOG_ERROR, "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;
@@ -395,37 +495,53 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt)
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;
- if (!(s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS))) {
- AVRational time_base = s->streams[pkt->stream_index]->time_base;
- int64_t offset = 0;
+ int ret, did_split;
- if (!s->offset && pkt->dts != AV_NOPTS_VALUE && pkt->dts < 0) {
+ if (s->avoid_negative_ts > 0) {
+ AVStream *st = s->streams[pkt->stream_index];
+ int64_t offset = st->mux_ts_offset;
+
+ if (pkt->dts < 0 && pkt->dts != AV_NOPTS_VALUE && !s->offset) {
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);
}
+
+ did_split = av_packet_split_side_data(pkt);
ret = s->oformat->write_packet(s, pkt);
- if (s->pb && ret >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
+ 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;
}
@@ -434,8 +550,14 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
int 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)
+ avio_flush(s->pb);
+ if (ret >= 0 && s->pb && s->pb->error < 0)
+ ret = s->pb->error;
+ return ret;
+ }
return 1;
}
@@ -445,18 +567,26 @@ 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;
}
-void ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
+#define CHUNK_START 0x1000
+
+int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
int (*compare)(AVFormatContext *, AVPacket *, AVPacket *))
{
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)
+ return AVERROR(ENOMEM);
this_pktl->pkt = *pkt;
#if FF_API_DESTRUCT_PACKET
FF_DISABLE_DEPRECATION_WARNINGS
@@ -464,23 +594,48 @@ FF_DISABLE_DEPRECATION_WARNINGS
FF_ENABLE_DEPRECATION_WARNINGS
#endif
pkt->buf = NULL;
- av_dup_packet(&this_pktl->pkt); // duplicate the packet if it uses non-alloced memory
+ av_dup_packet(&this_pktl->pkt); // duplicate the packet if it uses non-allocated memory
+ av_copy_packet_side_data(&this_pktl->pkt, &this_pktl->pkt); // copy side data
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:
@@ -489,6 +644,7 @@ next_non_null:
s->streams[pkt->stream_index]->last_in_packet_buffer =
*next_point = this_pktl;
+ return 0;
}
static int interleave_compare_dts(AVFormatContext *s, AVPacket *next,
@@ -498,6 +654,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;
@@ -508,27 +674,59 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out,
AVPacket *pkt, int flush)
{
AVPacketList *pktl;
- int stream_count = 0;
- int i;
+ int stream_count = 0, noninterleaved_count = 0;
+ int64_t delta_dts_max = 0;
+ int i, ret;
if (pkt) {
- ff_interleave_add_packet(s, pkt, interleave_compare_dts);
+ ret = ff_interleave_add_packet(s, pkt, interleave_compare_dts);
+ if (ret < 0)
+ return ret;
}
- for (i = 0; i < s->nb_streams; i++)
- stream_count += !!s->streams[i]->last_in_packet_buffer;
+ 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_SUBTITLE) {
+ ++noninterleaved_count;
+ }
+ }
- if (stream_count && (s->nb_streams == stream_count || flush)) {
+ if (s->nb_streams == stream_count) {
+ flush = 1;
+ } else if (!flush) {
+ for (i=0; i < s->nb_streams; i++) {
+ if (s->streams[i]->last_in_packet_buffer) {
+ int64_t delta_dts =
+ av_rescale_q(s->streams[i]->last_in_packet_buffer->pkt.dts,
+ s->streams[i]->time_base,
+ AV_TIME_BASE_Q) -
+ av_rescale_q(s->packet_buffer->pkt.dts,
+ s->streams[s->packet_buffer->pkt.stream_index]->time_base,
+ AV_TIME_BASE_Q);
+ delta_dts_max= FFMAX(delta_dts_max, delta_dts);
+ }
+ }
+ if (s->nb_streams == stream_count+noninterleaved_count &&
+ delta_dts_max > 20*AV_TIME_BASE) {
+ av_log(s, AV_LOG_DEBUG, "flushing with %d noninterleaved\n", noninterleaved_count);
+ flush = 1;
+ }
+ }
+ 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);
@@ -567,8 +765,8 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && pkt->size == 0)
return 0;
- 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))
return ret;
@@ -594,6 +792,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;
}
}
@@ -617,15 +817,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);
@@ -636,6 +839,15 @@ 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)
{
@@ -651,5 +863,9 @@ 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);
+ if (pkt->duration)
+ local_pkt.duration = av_rescale_q(pkt->duration,
+ src->streams[pkt->stream_index]->time_base,
+ dst->streams[dst_stream]->time_base);
return av_write_frame(dst, &local_pkt);
}
diff --git a/libavformat/mvdec.c b/libavformat/mvdec.c
new file mode 100644
index 0000000..5525233
--- a/dev/null
+++ b/libavformat/mvdec.c
@@ -0,0 +1,441 @@
+/*
+ * Silicon Graphics Movie demuxer
+ * Copyright (c) 2012 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
+ * Silicon Graphics Movie demuxer
+ */
+
+#include "libavutil/eval.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/rational.h"
+#include "avformat.h"
+#include "internal.h"
+
+typedef struct {
+ int nb_video_tracks;
+ int nb_audio_tracks;
+
+ int eof_count; /**< number of streams that have finished */
+ int stream_index; /**< current stream index */
+ int frame[2]; /**< frame nb for current stream */
+} MvContext;
+
+#define AUDIO_FORMAT_SIGNED 401
+
+static int mv_probe(AVProbeData *p)
+{
+ if (AV_RB32(p->buf) == MKBETAG('M','O','V','I') && AV_RB16(p->buf + 4) < 3)
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static char * var_read_string(AVIOContext *pb, int size)
+{
+ char *str = av_malloc(size + 1);
+ int n;
+ if (!str)
+ return NULL;
+ n = avio_get_str(pb, size, str, size + 1);
+ if (n < size)
+ avio_skip(pb, size - n);
+ return str;
+}
+
+static int var_read_int(AVIOContext *pb, int size)
+{
+ int v;
+ char * s = var_read_string(pb, size);
+ if (!s || sscanf(s, "%d", &v) != 1)
+ v = 0;
+ av_free(s);
+ return v;
+}
+
+static AVRational var_read_float(AVIOContext *pb, int size)
+{
+ AVRational v;
+ char * s = var_read_string(pb, size);
+ if (!s)
+ return (AVRational){0, 0};
+ v = av_d2q(av_strtod(s, NULL), INT_MAX);
+ av_free(s);
+ return v;
+}
+
+static void var_read_metadata(AVFormatContext *avctx, const char *tag, int size)
+{
+ char *value = var_read_string(avctx->pb, size);
+ if (value)
+ av_dict_set(&avctx->metadata, tag, value, AV_DICT_DONT_STRDUP_VAL);
+}
+
+static int set_channels(AVFormatContext *avctx, AVStream *st, int channels) {
+ if (channels <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "Channel count %d invalid\n", channels);
+ return AVERROR_INVALIDDATA;
+ }
+ st->codec->channels = channels;
+ st->codec->channel_layout = (st->codec->channels == 1) ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
+ return 0;
+}
+
+/**
+ * Parse global variable
+ * @return < 0 if unknown
+ */
+static int parse_global_var(AVFormatContext *avctx, AVStream *st, const char *name, int size)
+{
+ MvContext *mv = avctx->priv_data;
+ AVIOContext *pb = avctx->pb;
+ if (!strcmp(name, "__NUM_I_TRACKS")) {
+ mv->nb_video_tracks = var_read_int(pb, size);
+ } else if (!strcmp(name, "__NUM_A_TRACKS")) {
+ mv->nb_audio_tracks = var_read_int(pb, size);
+ } else if (!strcmp(name, "COMMENT") || !strcmp(name, "TITLE")) {
+ var_read_metadata(avctx, name, size);
+ } else if (!strcmp(name, "LOOP_MODE") || !strcmp(name, "NUM_LOOPS") || !strcmp(name, "OPTIMIZED")) {
+ avio_skip(pb, size); // ignore
+ } else
+ return -1;
+
+ return 0;
+}
+
+/**
+ * Parse audio variable
+ * @return < 0 if unknown
+ */
+static int parse_audio_var(AVFormatContext *avctx, AVStream *st, const char *name, int size)
+{
+ AVIOContext *pb = avctx->pb;
+ if (!strcmp(name, "__DIR_COUNT")) {
+ st->nb_frames = var_read_int(pb, size);
+ } else if (!strcmp(name, "AUDIO_FORMAT")) {
+ st->codec->codec_id = var_read_int(pb, size);
+ } else if (!strcmp(name, "COMPRESSION")) {
+ st->codec->codec_tag = var_read_int(pb, size);
+ } else if (!strcmp(name, "DEFAULT_VOL")) {
+ var_read_metadata(avctx, name, size);
+ } else if (!strcmp(name, "NUM_CHANNELS")) {
+ return set_channels(avctx, st, var_read_int(pb, size));
+ } else if (!strcmp(name, "SAMPLE_RATE")) {
+ st->codec->sample_rate = var_read_int(pb, size);
+ avpriv_set_pts_info(st, 33, 1, st->codec->sample_rate);
+ } else if (!strcmp(name, "SAMPLE_WIDTH")) {
+ st->codec->bits_per_coded_sample = var_read_int(pb, size) * 8;
+ } else
+ return -1;
+ return 0;
+}
+
+/**
+ * Parse video variable
+ * @return < 0 if unknown
+ */
+static int parse_video_var(AVFormatContext *avctx, AVStream *st, const char *name, int size)
+{
+ AVIOContext *pb = avctx->pb;
+ if (!strcmp(name, "__DIR_COUNT")) {
+ st->nb_frames = st->duration = var_read_int(pb, size);
+ } else if (!strcmp(name, "COMPRESSION")) {
+ char * str = var_read_string(pb, size);
+ if (!str)
+ return AVERROR_INVALIDDATA;
+ if (!strcmp(str, "1")) {
+ st->codec->codec_id = AV_CODEC_ID_MVC1;
+ } else if (!strcmp(str, "2")) {
+ st->codec->pix_fmt = AV_PIX_FMT_ABGR;
+ st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ } else if (!strcmp(str, "3")) {
+ st->codec->codec_id = AV_CODEC_ID_SGIRLE;
+ } else if (!strcmp(str, "10")) {
+ st->codec->codec_id = AV_CODEC_ID_MJPEG;
+ } else if (!strcmp(str, "MVC2")) {
+ st->codec->codec_id = AV_CODEC_ID_MVC2;
+ } else {
+ avpriv_request_sample(avctx, "video compression %s", str);
+ }
+ av_free(str);
+ } else if (!strcmp(name, "FPS")) {
+ AVRational fps = var_read_float(pb, size);
+ avpriv_set_pts_info(st, 64, fps.den, fps.num);
+ } else if (!strcmp(name, "HEIGHT")) {
+ st->codec->height = var_read_int(pb, size);
+ } else if (!strcmp(name, "PIXEL_ASPECT")) {
+ st->sample_aspect_ratio = var_read_float(pb, size);
+ av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den,
+ st->sample_aspect_ratio.num, st->sample_aspect_ratio.den, INT_MAX);
+ } else if (!strcmp(name, "WIDTH")) {
+ st->codec->width = var_read_int(pb, size);
+ } else if (!strcmp(name, "ORIENTATION")) {
+ if (var_read_int(pb, size) == 1101) {
+ st->codec->extradata = av_strdup("BottomUp");
+ st->codec->extradata_size = 9;
+ }
+ } else if (!strcmp(name, "Q_SPATIAL") || !strcmp(name, "Q_TEMPORAL")) {
+ var_read_metadata(avctx, name, size);
+ } else if (!strcmp(name, "INTERLACING") || !strcmp(name, "PACKING")) {
+ avio_skip(pb, size); // ignore
+ } else
+ return -1;
+ return 0;
+}
+
+static void read_table(AVFormatContext *avctx, AVStream *st, int (*parse)(AVFormatContext *avctx, AVStream *st, const char *name, int size))
+{
+ int count, i;
+ AVIOContext *pb = avctx->pb;
+ avio_skip(pb, 4);
+ count = avio_rb32(pb);
+ avio_skip(pb, 4);
+ for (i = 0; i < count; i++) {
+ char name[17];
+ int size;
+ avio_read(pb, name, 16);
+ name[sizeof(name) - 1] = 0;
+ size = avio_rb32(pb);
+ if (parse(avctx, st, name, size) < 0) {
+ avpriv_request_sample(avctx, "variable %s", name);
+ avio_skip(pb, size);
+ }
+ }
+}
+
+static void read_index(AVIOContext *pb, AVStream *st)
+{
+ uint64_t timestamp = 0;
+ int i;
+ for (i = 0; i < st->nb_frames; i++) {
+ uint32_t pos = avio_rb32(pb);
+ uint32_t size = avio_rb32(pb);
+ avio_skip(pb, 8);
+ av_add_index_entry(st, pos, timestamp, size, 0, AVINDEX_KEYFRAME);
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ timestamp += size / (st->codec->channels * 2);
+ } else {
+ timestamp++;
+ }
+ }
+}
+
+static int mv_read_header(AVFormatContext *avctx)
+{
+ MvContext *mv = avctx->priv_data;
+ AVIOContext *pb = avctx->pb;
+ AVStream *ast = NULL, *vst = NULL; //initialization to suppress warning
+ int version, i;
+
+ avio_skip(pb, 4);
+
+ version = avio_rb16(pb);
+ if (version == 2) {
+ uint64_t timestamp;
+ int v;
+ avio_skip(pb, 22);
+
+ /* allocate audio track first to prevent unnecessary seeking
+ (audio packet always precede video packet for a given frame) */
+ ast = avformat_new_stream(avctx, NULL);
+ if (!ast)
+ return AVERROR(ENOMEM);
+
+ vst = avformat_new_stream(avctx, NULL);
+ if (!vst)
+ return AVERROR(ENOMEM);
+ vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ avpriv_set_pts_info(vst, 64, 1, 15);
+ vst->nb_frames = avio_rb32(pb);
+ v = avio_rb32(pb);
+ switch (v) {
+ case 1:
+ vst->codec->codec_id = AV_CODEC_ID_MVC1;
+ break;
+ case 2:
+ vst->codec->pix_fmt = AV_PIX_FMT_ARGB;
+ vst->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ break;
+ default:
+ avpriv_request_sample(avctx, "video compression %i", v);
+ break;
+ }
+ vst->codec->codec_tag = 0;
+ vst->codec->width = avio_rb32(pb);
+ vst->codec->height = avio_rb32(pb);
+ avio_skip(pb, 12);
+
+ ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ ast->nb_frames = vst->nb_frames;
+ ast->codec->sample_rate = avio_rb32(pb);
+ avpriv_set_pts_info(ast, 33, 1, ast->codec->sample_rate);
+ if (set_channels(avctx, ast, avio_rb32(pb)) < 0)
+ return AVERROR_INVALIDDATA;
+
+ v = avio_rb32(pb);
+ if (v == AUDIO_FORMAT_SIGNED) {
+ ast->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
+ } else {
+ avpriv_request_sample(avctx, "audio compression (format %i)", v);
+ }
+
+ avio_skip(pb, 12);
+ var_read_metadata(avctx, "title", 0x80);
+ var_read_metadata(avctx, "comment", 0x100);
+ avio_skip(pb, 0x80);
+
+ timestamp = 0;
+ for (i = 0; i < vst->nb_frames; i++) {
+ uint32_t pos = avio_rb32(pb);
+ uint32_t asize = avio_rb32(pb);
+ uint32_t vsize = avio_rb32(pb);
+ avio_skip(pb, 8);
+ av_add_index_entry(ast, pos, timestamp, asize, 0, AVINDEX_KEYFRAME);
+ av_add_index_entry(vst, pos + asize, i, vsize, 0, AVINDEX_KEYFRAME);
+ timestamp += asize / (ast->codec->channels * 2);
+ }
+ } else if (!version && avio_rb16(pb) == 3) {
+ avio_skip(pb, 4);
+
+ read_table(avctx, NULL, parse_global_var);
+
+ if (mv->nb_audio_tracks > 1) {
+ avpriv_request_sample(avctx, "multiple audio streams support");
+ return AVERROR_PATCHWELCOME;
+ } else if (mv->nb_audio_tracks) {
+ ast = avformat_new_stream(avctx, NULL);
+ if (!ast)
+ return AVERROR(ENOMEM);
+ ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ /* temporarily store compression value in codec_tag; format value in codec_id */
+ read_table(avctx, ast, parse_audio_var);
+ if (ast->codec->codec_tag == 100 && ast->codec->codec_id == AUDIO_FORMAT_SIGNED && ast->codec->bits_per_coded_sample == 16) {
+ ast->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
+ } else {
+ avpriv_request_sample(avctx, "audio compression %i (format %i, width %i)",
+ ast->codec->codec_tag, ast->codec->codec_id, ast->codec->bits_per_coded_sample);
+ ast->codec->codec_id = AV_CODEC_ID_NONE;
+ }
+ ast->codec->codec_tag = 0;
+ if (ast->codec->channels <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "No valid channel count found\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ if (mv->nb_video_tracks > 1) {
+ avpriv_request_sample(avctx, "multiple video streams support");
+ return AVERROR_PATCHWELCOME;
+ } else if (mv->nb_video_tracks) {
+ vst = avformat_new_stream(avctx, NULL);
+ if (!vst)
+ return AVERROR(ENOMEM);
+ vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ read_table(avctx, vst, parse_video_var);
+ }
+
+ if (mv->nb_audio_tracks)
+ read_index(pb, ast);
+
+ if (mv->nb_video_tracks)
+ read_index(pb, vst);
+ } else {
+ avpriv_request_sample(avctx, "version %i", version);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ return 0;
+}
+
+static int mv_read_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ MvContext *mv = avctx->priv_data;
+ AVIOContext *pb = avctx->pb;
+ AVStream *st = avctx->streams[mv->stream_index];
+ const AVIndexEntry *index;
+ int frame = mv->frame[mv->stream_index];
+ int ret;
+ uint64_t pos;
+
+ if (frame < st->nb_index_entries) {
+ index = &st->index_entries[frame];
+ pos = avio_tell(pb);
+ if (index->pos > pos)
+ avio_skip(pb, index->pos - pos);
+ else if (index->pos < pos) {
+ if (!pb->seekable)
+ return AVERROR(EIO);
+ ret = avio_seek(pb, index->pos, SEEK_SET);
+ if (ret < 0)
+ return ret;
+ }
+ ret = av_get_packet(pb, pkt, index->size);
+ if (ret < 0)
+ return ret;
+
+ pkt->stream_index = mv->stream_index;
+ pkt->pts = index->timestamp;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+
+ mv->frame[mv->stream_index]++;
+ mv->eof_count = 0;
+ } else {
+ mv->eof_count++;
+ if (mv->eof_count >= avctx->nb_streams)
+ return AVERROR_EOF;
+ }
+
+ mv->stream_index++;
+ if (mv->stream_index >= avctx->nb_streams)
+ mv->stream_index = 0;
+
+ return 0;
+}
+
+static int mv_read_seek(AVFormatContext *avctx, int stream_index, int64_t timestamp, int flags)
+{
+ MvContext *mv = avctx->priv_data;
+ AVStream *st = avctx->streams[stream_index];
+ int frame, i;
+
+ if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
+ return AVERROR(ENOSYS);
+
+ if (!avctx->pb->seekable)
+ return AVERROR(EIO);
+
+ frame = av_index_search_timestamp(st, timestamp, flags);
+ if (frame < 0)
+ return -1;
+
+ for (i = 0; i < avctx->nb_streams; i++)
+ mv->frame[i] = frame;
+ return 0;
+}
+
+AVInputFormat ff_mv_demuxer = {
+ .name = "mv",
+ .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Movie"),
+ .priv_data_size = sizeof(MvContext),
+ .read_probe = mv_probe,
+ .read_header = mv_read_header,
+ .read_packet = mv_read_packet,
+ .read_seek = mv_read_seek,
+};
diff --git a/libavformat/mvi.c b/libavformat/mvi.c
index 69b0aed..5efc443 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
*/
@@ -52,8 +52,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 040d8a2..4a4158a 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
*/
@@ -41,9 +41,11 @@ const MXFCodecUL ff_mxf_codec_uls[] = {
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x01,0x02,0x00 }, 13, AV_CODEC_ID_DVVIDEO }, /* DV25 IEC PAL */
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 }, 14, AV_CODEC_ID_JPEG2000 }, /* JPEG2000 Codestream */
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x01,0x7F,0x00,0x00,0x00 }, 13, AV_CODEC_ID_RAWVIDEO }, /* Uncompressed */
+ { { 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,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,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,0x01,0x04,0x02,0x02,0x01,0x00,0x00,0x00,0x00 }, 13, AV_CODEC_ID_PCM_S16LE }, /* Uncompressed */
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x01,0x7F,0x00,0x00,0x00 }, 13, AV_CODEC_ID_PCM_S16LE },
@@ -104,3 +106,32 @@ int ff_mxf_decode_pixel_layout(const char pixel_layout[16], enum AVPixelFormat *
return -1;
}
+
+static const MXFSamplesPerFrame mxf_samples_per_frames[] = {
+ { { 1001, 24000 }, { 2002, 0, 0, 0, 0, 0 } }, // FILM 23.976
+ { { 1, 24}, { 2000, 0, 0, 0, 0, 0 } }, // FILM 24
+ { { 1001, 30000 }, { 1602, 1601, 1602, 1601, 1602, 0 } }, // NTSC 29.97
+ { { 1001, 60000 }, { 801, 801, 801, 801, 800, 0 } }, // NTSC 59.94
+ { { 1, 25 }, { 1920, 0, 0, 0, 0, 0 } }, // PAL 25
+ { { 1, 50 }, { 960, 0, 0, 0, 0, 0 } }, // PAL 50
+};
+
+const MXFSamplesPerFrame *ff_mxf_get_samples_per_frame(AVFormatContext *s, AVRational time_base)
+{
+ int i;
+ for (i = 0; i < FF_ARRAY_ELEMS(mxf_samples_per_frames); i++) {
+ if (!av_cmp_q(mxf_samples_per_frames[i].time_base, time_base))
+ return &mxf_samples_per_frames[i];
+ }
+
+ // Find closest container time base for approximative codec time base like 1/29.97, 1/30, ...
+ for (i = 0; i < FF_ARRAY_ELEMS(mxf_samples_per_frames); i++) {
+ if (fabs(av_q2d(mxf_samples_per_frames[i].time_base) - av_q2d(time_base)) < 0.0001) {
+ av_log(s, AV_LOG_WARNING, "%d/%d input time base matched %d/%d container time base\n",
+ time_base.num, time_base.den,
+ mxf_samples_per_frames[i].time_base.num, mxf_samples_per_frames[i].time_base.den);
+ return &mxf_samples_per_frames[i];
+ }
+ }
+ return NULL;
+}
diff --git a/libavformat/mxf.h b/libavformat/mxf.h
index 773f30f..4c751e8 100644
--- a/libavformat/mxf.h
+++ b/libavformat/mxf.h
@@ -2,25 +2,26 @@
* 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
#define AVFORMAT_MXF_H
+#include "avformat.h"
#include "libavcodec/avcodec.h"
#include <stdint.h>
@@ -47,11 +48,11 @@ enum MXFMetadataSetType {
};
enum MXFFrameLayout {
- FullFrame = 0,
- MixedFields,
- OneField,
- SegmentedFrame,
- SeparateFields
+ FullFrame = 0,
+ SeparateFields,
+ OneField,
+ MixedFields,
+ SegmentedFrame,
};
typedef struct KLVPacket {
@@ -66,11 +67,17 @@ typedef struct MXFCodecUL {
int id;
} MXFCodecUL;
+typedef struct {
+ struct AVRational time_base;
+ int samples_per_frame[6];
+} MXFSamplesPerFrame;
+
extern const MXFCodecUL ff_mxf_data_definition_uls[];
extern const MXFCodecUL ff_mxf_codec_uls[];
extern const MXFCodecUL ff_mxf_pixel_format_uls[];
int ff_mxf_decode_pixel_layout(const char pixel_layout[16], enum AVPixelFormat *pix_fmt);
+const MXFSamplesPerFrame *ff_mxf_get_samples_per_frame(AVFormatContext *s, AVRational time_base);
#define PRINT_KEY(pc, s, x) av_dlog(pc, "%s %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", s, \
(x)[0], (x)[1], (x)[2], (x)[3], (x)[4], (x)[5], (x)[6], (x)[7], (x)[8], (x)[9], (x)[10], (x)[11], (x)[12], (x)[13], (x)[14], (x)[15])
diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index dedf636..d0cbeea 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
*/
@@ -44,8 +44,10 @@
*/
#include "libavutil/aes.h"
+#include "libavutil/avassert.h"
#include "libavutil/mathematics.h"
#include "libavcodec/bytestream.h"
+#include "libavutil/timecode.h"
#include "avformat.h"
#include "internal.h"
#include "mxf.h"
@@ -67,7 +69,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 {
@@ -114,12 +116,23 @@ 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;
MXFSequence *sequence; /* mandatory, and only one */
UID sequence_ref;
int track_id;
uint8_t track_number[4];
AVRational edit_rate;
int intra_only;
+ uint64_t sample_count;
+ int64_t original_duration; ///< duration before multiplying st->duration by SampleRate/EditRate
} MXFTrack;
typedef struct {
@@ -134,6 +147,7 @@ typedef struct {
int frame_layout; /* See MXFFrameLayout enum */
int channels;
int bits_per_sample;
+ int field_dominance;
unsigned int component_depth;
unsigned int horiz_subsampling;
unsigned int vert_subsampling;
@@ -199,6 +213,7 @@ 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;
@@ -228,6 +243,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 };
@@ -238,6 +255,7 @@ static const uint8_t mxf_klv_key[] = { 0x06,0x0e,0x2b,0x
static const uint8_t mxf_crypto_source_container_ul[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x02,0x02,0x00,0x00,0x00 };
static const uint8_t mxf_encrypted_triplet_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x04,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x7e,0x01,0x00 };
static const uint8_t mxf_encrypted_essence_container[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0b,0x01,0x00 };
+static const uint8_t mxf_random_index_pack_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x02,0x01,0x01,0x11,0x01,0x00 };
static const uint8_t mxf_sony_mpeg4_extradata[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0e,0x06,0x06,0x02,0x02,0x01,0x00,0x00 };
#define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y)))
@@ -260,7 +278,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 && !url_feof(pb); i++) {
b = avio_r8(pb);
if (b == key[0])
i = 0;
@@ -310,7 +328,7 @@ static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st, AVPacket *pkt,
data_ptr = pkt->data;
end_ptr = pkt->data + length;
buf_ptr = pkt->data + 4; /* skip SMPTE 331M header */
- for (; buf_ptr + st->codec->channels*4 < end_ptr; ) {
+ for (; buf_ptr + st->codec->channels*4 <= end_ptr; ) {
for (i = 0; i < st->codec->channels; i++) {
uint32_t sample = bytestream_get_le32(&buf_ptr);
if (st->codec->bits_per_coded_sample == 24)
@@ -397,12 +415,14 @@ 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);
+ }
+ 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;
}
@@ -410,20 +430,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 (mxf->partitions_count+1 >= UINT_MAX / sizeof(*mxf->partitions))
+ tmp_part = av_realloc_array(mxf->partitions, mxf->partitions_count + 1, sizeof(*mxf->partitions));
+ if (!tmp_part)
return AVERROR(ENOMEM);
-
- if ((err = av_reallocp_array(&mxf->partitions, mxf->partitions_count + 1,
- sizeof(*mxf->partitions))) < 0) {
- mxf->partitions_count = 0;
- return err;
- }
+ mxf->partitions = tmp_part;
if (mxf->parsing_backward) {
/* insert the new partition pack in the middle
@@ -508,7 +523,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:
@@ -519,10 +534,8 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
/* only nag once */
if (!mxf->op)
- av_log(mxf->fc, AV_LOG_WARNING,
- "\"OPAtom\" with %u ECs - assuming %s\n",
- nb_essence_containers,
- op == OP1a ? "OP1a" : "OPAtom");
+ av_log(mxf->fc, AV_LOG_WARNING, "\"OPAtom\" with %u ECs - assuming %s\n",
+ nb_essence_containers, op == OP1a ? "OP1a" : "OPAtom");
mxf->op = op;
} else
@@ -535,7 +548,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
if (partition->kag_size <= 0 || partition->kag_size > (1 << 20)) {
av_log(mxf->fc, AV_LOG_WARNING, "invalid KAGSize %i - guessing ", partition->kag_size);
- if (mxf->op == OPSonyOpt)
+ if (mxf->op == OPSONYOpt)
partition->kag_size = 512;
else
partition->kag_size = 1;
@@ -548,15 +561,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 (mxf->metadata_sets_count+1 >= UINT_MAX / sizeof(*mxf->metadata_sets))
+ tmp = av_realloc_array(mxf->metadata_sets, mxf->metadata_sets_count + 1, sizeof(*mxf->metadata_sets));
+ if (!tmp)
return AVERROR(ENOMEM);
- 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;
- }
+ mxf->metadata_sets = tmp;
mxf->metadata_sets[mxf->metadata_sets_count] = metadata_set;
mxf->metadata_sets_count++;
return 0;
@@ -578,9 +588,7 @@ static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int siz
switch (tag) {
case 0x1901:
mxf->packages_count = avio_rb32(pb);
- if (mxf->packages_count >= UINT_MAX / sizeof(UID))
- return AVERROR_INVALIDDATA;
- mxf->packages_refs = av_malloc(mxf->packages_count * sizeof(UID));
+ 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 */
@@ -618,9 +626,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 */
@@ -630,6 +636,23 @@ 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_track(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
{
MXFTrack *track = arg;
@@ -663,9 +686,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 */
@@ -681,9 +702,7 @@ static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int size
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 */
@@ -706,29 +725,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);
@@ -780,17 +783,18 @@ 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);
value = avio_r8(pb);
av_dlog(NULL, "pixel layout: code %#x\n", code);
- if (ofs < 16) {
+ 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);
@@ -803,9 +807,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 */
@@ -833,6 +835,9 @@ static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int
descriptor->aspect_ratio.num = avio_rb32(pb);
descriptor->aspect_ratio.den = avio_rb32(pb);
break;
+ case 0x3212:
+ descriptor->field_dominance = avio_r8(pb);
+ break;
case 0x3301:
descriptor->component_depth = avio_rb32(pb);
break;
@@ -861,7 +866,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)) {
- descriptor->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
+ 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);
if (!descriptor->extradata)
return AVERROR(ENOMEM);
descriptor->extradata_size = size;
@@ -955,9 +964,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);
@@ -972,19 +980,23 @@ static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segment
/* sort segments by {BodySID, IndexSID, IndexStartPosition}, remove duplicates while we're at it */
for (i = 0; i < nb_segments; i++) {
int best = -1, best_body_sid = -1, best_index_sid = -1, best_index_start = -1;
+ uint64_t best_index_duration = 0;
for (j = 0; j < nb_segments; j++) {
MXFIndexTableSegment *s = unsorted_segments[j];
/* Require larger BosySID, IndexSID or IndexStartPosition then the previous entry. This removes duplicates.
* We want the smallest values for the keys than what we currently have, unless this is the first such entry this time around.
+ * If we come across an entry with the same IndexStartPosition but larger IndexDuration, then we'll prefer it over the one we currently have.
*/
if ((i == 0 || s->body_sid > last_body_sid || s->index_sid > last_index_sid || s->index_start_position > last_index_start) &&
- (best == -1 || s->body_sid < best_body_sid || s->index_sid < best_index_sid || s->index_start_position < best_index_start)) {
+ (best == -1 || s->body_sid < best_body_sid || s->index_sid < best_index_sid || s->index_start_position < best_index_start ||
+ (s->index_start_position == best_index_start && s->index_duration > best_index_duration))) {
best = j;
best_body_sid = s->body_sid;
best_index_sid = s->index_sid;
best_index_start = s->index_start_position;
+ best_index_duration = s->index_duration;
}
}
@@ -1125,14 +1137,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);
}
@@ -1237,9 +1243,7 @@ static int mxf_compute_index_tables(MXFContext *mxf)
}
}
- if (mxf->nb_index_tables > INT_MAX / sizeof(MXFIndexTable) ||
- !(mxf->index_tables = av_mallocz(mxf->nb_index_tables *
- sizeof(MXFIndexTable)))) {
+ if (!(mxf->index_tables = av_calloc(mxf->nb_index_tables, sizeof(MXFIndexTable)))) {
av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate index tables\n");
ret = AVERROR(ENOMEM);
goto finish_decoding_index;
@@ -1258,12 +1262,8 @@ static int mxf_compute_index_tables(MXFContext *mxf)
for (i = j = 0; j < mxf->nb_index_tables; i += mxf->index_tables[j++].nb_segments) {
MXFIndexTable *t = &mxf->index_tables[j];
- if (t->nb_segments >
- (INT_MAX / sizeof(MXFIndexTableSegment *)) ||
- !(t->segments = av_mallocz(t->nb_segments *
- sizeof(MXFIndexTableSegment*)))) {
- av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate IndexTableSegment"
- " pointer array\n");
+ if (!(t->segments = av_calloc(t->nb_segments, sizeof(MXFIndexTableSegment*)))) {
+ av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate IndexTableSegment pointer array\n");
ret = AVERROR(ENOMEM);
goto finish_decoding_index;
}
@@ -1307,12 +1307,20 @@ 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_structural_metadata(MXFContext *mxf)
@@ -1339,25 +1347,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;
@@ -1415,12 +1446,21 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
}
st->id = source_track->track_id;
st->priv_data = source_track;
- st->duration = component->duration;
+ source_track->original_duration = st->duration = component->duration;
if (st->duration == -1)
st->duration = AV_NOPTS_VALUE;
st->start_time = component->start_position;
+ if (material_track->edit_rate.num <= 0 || material_track->edit_rate.den <= 0) {
+ av_log(mxf->fc, AV_LOG_WARNING,
+ "invalid edit rate (%d/%d) found on stream #%d, defaulting to 25/1\n",
+ material_track->edit_rate.num, material_track->edit_rate.den, st->index);
+ material_track->edit_rate = (AVRational){25, 1};
+ }
avpriv_set_pts_info(st, 64, material_track->edit_rate.den, material_track->edit_rate.num);
+ /* ensure SourceTrack EditRate == MaterialTrack EditRate since only the former is accessible via st->priv_data */
+ source_track->edit_rate = material_track->edit_rate;
+
PRINT_KEY(mxf->fc, "data definition ul", source_track->sequence->data_definition_ul);
codec_ul = mxf_get_codec_ul(ff_mxf_data_definition_uls, &source_track->sequence->data_definition_ul);
st->codec->codec_type = codec_ul->id;
@@ -1465,51 +1505,51 @@ 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;
- if (descriptor->extradata) {
- st->codec->extradata = descriptor->extradata;
- st->codec->extradata_size = descriptor->extradata_size;
+ 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");
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
source_track->intra_only = mxf_is_intra_only(descriptor);
container_ul = mxf_get_codec_ul(mxf_picture_essence_container_uls, essence_container_ul);
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:
- /* Turn field height into frame height. */
- st->codec->height *= 2;
+ st->codec->height *= 2; /* Turn field height into frame height. */
+ 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 */
@@ -1524,8 +1564,9 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
st->need_parsing = AVSTREAM_PARSE_HEADERS;
} 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;
@@ -1540,6 +1581,10 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
avpriv_set_pts_info(st, 64, 1, 48000);
}
+ /* if duration is set, rescale it from EditRate to SampleRate */
+ if (st->duration != AV_NOPTS_VALUE)
+ st->duration = av_rescale_q(st->duration, av_inv_q(material_track->edit_rate), st->time_base);
+
/* TODO: implement AV_CODEC_ID_RAWAUDIO */
if (st->codec->codec_id == AV_CODEC_ID_PCM_S16LE) {
if (descriptor->bits_per_sample > 16 && descriptor->bits_per_sample <= 24)
@@ -1555,6 +1600,13 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
st->need_parsing = AVSTREAM_PARSE_FULL;
}
}
+ if (descriptor->extradata) {
+ if (!ff_alloc_extradata(st->codec, descriptor->extradata_size)) {
+ memcpy(st->codec->extradata, descriptor->extradata, descriptor->extradata_size);
+ }
+ } else if(st->codec->codec_id == AV_CODEC_ID_H264) {
+ ff_generate_avci_extradata(st);
+ }
if (st->codec->codec_type != AVMEDIA_TYPE_DATA && (*essence_container_ul)[15] > 0x01) {
/* TODO: decode timestamps */
st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS;
@@ -1566,6 +1618,124 @@ fail_and_free:
return ret;
}
+static int mxf_read_utf16_string(AVIOContext *pb, int size, char** str)
+{
+ int ret;
+ size_t buf_size;
+
+ if (size < 0)
+ return AVERROR(EINVAL);
+
+ buf_size = size + size/2 + 1;
+ *str = av_malloc(buf_size);
+ if (!*str)
+ return AVERROR(ENOMEM);
+
+ if ((ret = avio_get_str16be(pb, size, *str, buf_size)) < 0) {
+ av_freep(str);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int mxf_uid_to_str(UID uid, char **str)
+{
+ int i;
+ char *p;
+ p = *str = av_mallocz(sizeof(UID) * 2 + 4 + 1);
+ if (!p)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < sizeof(UID); i++) {
+ snprintf(p, 2 + 1, "%.2x", uid[i]);
+ p += 2;
+ if (i == 3 || i == 5 || i == 7 || i == 9) {
+ snprintf(p, 1 + 1, "-");
+ p++;
+ }
+ }
+ return 0;
+}
+
+static int mxf_timestamp_to_str(uint64_t timestamp, char **str)
+{
+ struct tm time = {0};
+ time.tm_year = (timestamp >> 48) - 1900;
+ time.tm_mon = (timestamp >> 40 & 0xFF) - 1;
+ time.tm_mday = (timestamp >> 32 & 0xFF);
+ time.tm_hour = (timestamp >> 24 & 0xFF);
+ time.tm_min = (timestamp >> 16 & 0xFF);
+ time.tm_sec = (timestamp >> 8 & 0xFF);
+
+ /* ensure month/day are valid */
+ time.tm_mon = FFMAX(time.tm_mon, 0);
+ time.tm_mday = FFMAX(time.tm_mday, 1);
+
+ *str = av_mallocz(32);
+ if (!*str)
+ return AVERROR(ENOMEM);
+ strftime(*str, 32, "%Y-%m-%d %H:%M:%S", &time);
+
+ return 0;
+}
+
+#define SET_STR_METADATA(pb, name, str) do { \
+ if ((ret = mxf_read_utf16_string(pb, size, &str)) < 0) \
+ return ret; \
+ av_dict_set(&s->metadata, name, str, AV_DICT_DONT_STRDUP_VAL); \
+} while (0)
+
+#define SET_UID_METADATA(pb, name, var, str) do { \
+ avio_read(pb, var, 16); \
+ if ((ret = mxf_uid_to_str(var, &str)) < 0) \
+ return ret; \
+ av_dict_set(&s->metadata, name, str, AV_DICT_DONT_STRDUP_VAL); \
+} while (0)
+
+#define SET_TS_METADATA(pb, name, var, str) do { \
+ var = avio_rb64(pb); \
+ if ((ret = mxf_timestamp_to_str(var, &str)) < 0) \
+ return ret; \
+ av_dict_set(&s->metadata, name, str, AV_DICT_DONT_STRDUP_VAL); \
+} while (0)
+
+static int mxf_read_identification_metadata(void *arg, AVIOContext *pb, int tag, int size, UID _uid, int64_t klv_offset)
+{
+ MXFContext *mxf = arg;
+ AVFormatContext *s = mxf->fc;
+ int ret;
+ UID uid = { 0 };
+ char *str = NULL;
+ uint64_t ts;
+ switch (tag) {
+ case 0x3C01:
+ SET_STR_METADATA(pb, "company_name", str);
+ break;
+ case 0x3C02:
+ SET_STR_METADATA(pb, "product_name", str);
+ break;
+ case 0x3C04:
+ SET_STR_METADATA(pb, "product_version", str);
+ break;
+ case 0x3C05:
+ SET_UID_METADATA(pb, "product_uid", uid, str);
+ break;
+ case 0x3C06:
+ SET_TS_METADATA(pb, "modification_date", ts, str);
+ break;
+ case 0x3C08:
+ SET_STR_METADATA(pb, "application_platform", str);
+ break;
+ case 0x3C09:
+ SET_UID_METADATA(pb, "generation_uid", uid, str);
+ break;
+ case 0x3C0A:
+ SET_UID_METADATA(pb, "uid", uid, str);
+ break;
+ }
+ return 0;
+}
+
static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = {
{ { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x05,0x01,0x00 }, mxf_read_primer_pack },
{ { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x01,0x00 }, mxf_read_partition_pack },
@@ -1578,6 +1748,7 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = {
{ { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x03,0x04,0x00 }, mxf_read_partition_pack },
{ { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x04,0x02,0x00 }, mxf_read_partition_pack },
{ { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x04,0x04,0x00 }, mxf_read_partition_pack },
+ { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x30,0x00 }, mxf_read_identification_metadata },
{ { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x18,0x00 }, mxf_read_content_storage, 0, AnyType },
{ { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x37,0x00 }, mxf_read_source_package, sizeof(MXFPackage), SourcePackage },
{ { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x36,0x00 }, mxf_read_material_package, sizeof(MXFPackage), MaterialPackage },
@@ -1592,6 +1763,7 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = {
{ { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* AES3 */
{ { 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,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 },
@@ -1605,7 +1777,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 && !url_feof(pb)) {
int ret;
int tag = avio_rb16(pb);
int size = avio_rb16(pb); /* KLV specified by 0x53 */
@@ -1636,6 +1808,9 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF
/* Accept the 64k local set limit being exceeded (Avid). Don't accept
* it extending past the end of the KLV though (zzuf5.mxf). */
if (avio_tell(pb) > klv_end) {
+ if (ctx_size)
+ av_free(ctx);
+
av_log(mxf->fc, AV_LOG_ERROR,
"local tag %#04x extends past end of local set @ %#"PRIx64"\n",
tag, klv->offset);
@@ -1679,31 +1854,33 @@ static int mxf_parse_handle_essence(MXFContext *mxf)
if (mxf->parsing_backward) {
return mxf_seek_to_previous_partition(mxf);
- } else {
- if (!mxf->footer_partition) {
- av_dlog(mxf->fc, "no footer\n");
- return 0;
- }
+ } else if (mxf->footer_partition || mxf->last_partition){
+ uint64_t offset;
- av_dlog(mxf->fc, "seeking to footer\n");
+ offset = mxf->footer_partition ? mxf->footer_partition : mxf->last_partition;
+
+ av_dlog(mxf->fc, "seeking to last partition\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 footer\n");
+ av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing last partition\n");
return -1;
}
- /* seek to footer partition 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 footer @ 0x%"PRIx64" (%"PRId64") - partial file?\n",
- mxf->run_in + mxf->footer_partition, ret);
+ /* seek to last partition and parse backward */
+ if ((ret = avio_seek(pb, mxf->run_in + offset, SEEK_SET)) < 0) {
+ av_log(mxf->fc, AV_LOG_ERROR, "failed to seek to last partition @ 0x%"PRIx64" (%"PRId64") - partial file?\n",
+ mxf->run_in + offset, ret);
return ret;
}
mxf->current_partition = NULL;
mxf->parsing_backward = 1;
+ } else {
+ av_dlog(mxf->fc, "can't find last partition\n");
+ return 0;
}
return 1;
@@ -1719,8 +1896,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)
{
@@ -1760,38 +1936,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 */
@@ -1828,6 +1972,34 @@ static void mxf_handle_small_eubc(AVFormatContext *s)
mxf->edit_units_per_packet = 1920;
}
+static void mxf_read_random_index_pack(AVFormatContext *s)
+{
+ MXFContext *mxf = s->priv_data;
+ uint32_t length;
+ int64_t file_size;
+ KLVPacket klv;
+
+ if (!s->pb->seekable)
+ return;
+
+ file_size = avio_size(s->pb);
+ avio_seek(s->pb, file_size - 4, SEEK_SET);
+ length = avio_rb32(s->pb);
+ if (length <= 32 || length >= FFMIN(file_size, INT_MAX))
+ goto end;
+ avio_seek(s->pb, file_size - length, SEEK_SET);
+ if (klv_read_packet(&klv, s->pb) < 0 ||
+ !IS_KLV_KEY(klv.key, mxf_random_index_pack_key) ||
+ klv.length != length - 20)
+ goto end;
+
+ avio_skip(s->pb, klv.length - 12);
+ mxf->last_partition = avio_rb64(s->pb);
+
+end:
+ avio_seek(s->pb, mxf->run_in, SEEK_SET);
+}
+
static int mxf_read_header(AVFormatContext *s)
{
MXFContext *mxf = s->priv_data;
@@ -1846,7 +2018,9 @@ static int mxf_read_header(AVFormatContext *s)
mxf->fc = s;
mxf->run_in = avio_tell(s->pb);
- while (!s->pb->eof_reached) {
+ mxf_read_random_index_pack(s);
+
+ while (!url_feof(s->pb)) {
const MXFMetadataReadTableEntry *metadata;
if (klv_read_packet(&klv, s->pb) < 0) {
@@ -1865,13 +2039,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)
@@ -1931,10 +2124,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 */
@@ -1942,12 +2135,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;
}
/**
@@ -1964,11 +2162,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) {
@@ -1986,29 +2182,76 @@ 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;
return next_ofs;
}
+static int mxf_compute_sample_count(MXFContext *mxf, int stream_index, uint64_t *sample_count)
+{
+ int i, total = 0, size = 0;
+ AVStream *st = mxf->fc->streams[stream_index];
+ MXFTrack *track = st->priv_data;
+ AVRational time_base = av_inv_q(track->edit_rate);
+ AVRational sample_rate = av_inv_q(st->time_base);
+ const MXFSamplesPerFrame *spf = NULL;
+
+ if ((sample_rate.num / sample_rate.den) == 48000)
+ spf = ff_mxf_get_samples_per_frame(mxf->fc, time_base);
+ if (!spf) {
+ int remainder = (sample_rate.num * time_base.num) % (time_base.den * sample_rate.den);
+ *sample_count = av_q2d(av_mul_q((AVRational){mxf->current_edit_unit, 1},
+ av_mul_q(sample_rate, time_base)));
+ if (remainder)
+ av_log(mxf->fc, AV_LOG_WARNING,
+ "seeking detected on stream #%d with time base (%d/%d) and sample rate (%d/%d), audio pts won't be accurate.\n",
+ stream_index, time_base.num, time_base.den, sample_rate.num, sample_rate.den);
+ return 0;
+ }
+
+ while (spf->samples_per_frame[size]) {
+ total += spf->samples_per_frame[size];
+ size++;
+ }
+
+ av_assert2(size);
+
+ *sample_count = (mxf->current_edit_unit / size) * (uint64_t)total;
+ for (i = 0; i < mxf->current_edit_unit % size; i++) {
+ *sample_count += spf->samples_per_frame[i];
+ }
+
+ return 0;
+}
+
+static int mxf_set_audio_pts(MXFContext *mxf, AVCodecContext *codec, AVPacket *pkt)
+{
+ MXFTrack *track = mxf->fc->streams[pkt->stream_index]->priv_data;
+ pkt->pts = track->sample_count;
+ if ( codec->channels <= 0
+ || av_get_bits_per_sample(codec->codec_id) <= 0
+ || codec->channels * (int64_t)av_get_bits_per_sample(codec->codec_id) < 8)
+ return AVERROR(EINVAL);
+ track->sample_count += pkt->size / (codec->channels * (int64_t)av_get_bits_per_sample(codec->codec_id) / 8);
+ return 0;
+}
+
static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
{
KLVPacket klv;
MXFContext *mxf = s->priv_data;
- while (!s->pb->eof_reached) {
- if (klv_read_packet(&klv, s->pb) < 0)
- return -1;
+ while (klv_read_packet(&klv, s->pb) == 0) {
+ int ret;
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)) {
- int res = mxf_decrypt_triplet(s, pkt, &klv);
- if (res < 0) {
+ ret = mxf_decrypt_triplet(s, pkt, &klv);
+ if (ret < 0) {
av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
return 0;
}
@@ -2018,6 +2261,7 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
int64_t next_ofs, next_klv;
AVStream *st;
MXFTrack *track;
+ AVCodecContext *codec;
if (index < 0) {
av_log(s, AV_LOG_ERROR, "error getting stream index %d\n", AV_RB32(klv.key+12));
@@ -2034,9 +2278,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 "
@@ -2049,31 +2292,33 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
if (klv.key[12] == 0x06 && klv.key[13] == 0x01 && klv.key[14] == 0x10) {
if (mxf_get_d10_aes3_packet(s->pb, s->streams[index], pkt, klv.length) < 0) {
av_log(s, AV_LOG_ERROR, "error reading D-10 aes3 frame\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
} else {
- int ret = av_get_packet(s->pb, pkt, klv.length);
+ ret = av_get_packet(s->pb, pkt, klv.length);
if (ret < 0)
return ret;
}
pkt->stream_index = index;
pkt->pos = klv.offset;
- if (s->streams[index]->codec->codec_type == AVMEDIA_TYPE_VIDEO && next_ofs >= 0) {
- /* mxf->current_edit_unit good - see if we have an
- * index table to derive timestamps from */
+ codec = s->streams[index]->codec;
+ if (codec->codec_type == AVMEDIA_TYPE_VIDEO && next_ofs >= 0) {
+ /* mxf->current_edit_unit good - see if we have an index table to derive timestamps from */
MXFIndexTable *t = &mxf->index_tables[0];
- if (mxf->nb_index_tables >= 1 &&
- mxf->current_edit_unit < t->nb_ptses) {
+ if (mxf->nb_index_tables >= 1 && mxf->current_edit_unit < t->nb_ptses) {
pkt->dts = mxf->current_edit_unit + t->first_dts;
pkt->pts = t->ptses[mxf->current_edit_unit];
} else if (track->intra_only) {
/* intra-only -> PTS = EditUnit.
- * let utils.c figure out DTS since it can be
- * < PTS if low_delay = 0 (Sony IMX30) */
+ * let utils.c figure out DTS since it can be < PTS if low_delay = 0 (Sony IMX30) */
pkt->pts = mxf->current_edit_unit;
}
+ } else if (codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ int ret = mxf_set_audio_pts(mxf, codec, pkt);
+ if (ret < 0)
+ return ret;
}
/* seek for truncated packets */
@@ -2084,7 +2329,7 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
skip:
avio_skip(s->pb, klv.length);
}
- return AVERROR_EOF;
+ return url_feof(s->pb) ? AVERROR_EOF : -1;
}
static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
@@ -2128,22 +2373,26 @@ 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;
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && t->ptses &&
mxf->current_edit_unit >= 0 && 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 (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ int ret = mxf_set_audio_pts(mxf, st->codec, pkt);
+ if (ret < 0)
+ return ret;
}
- pkt->stream_index = 0;
mxf->current_edit_unit += edit_units;
return 0;
}
-
static int mxf_read_close(AVFormatContext *s)
{
MXFContext *mxf = s->priv_data;
@@ -2157,6 +2406,9 @@ static int mxf_read_close(AVFormatContext *s)
for (i = 0; i < mxf->metadata_sets_count; i++) {
switch (mxf->metadata_sets[i]->type) {
+ case Descriptor:
+ av_freep(&((MXFDescriptor *)mxf->metadata_sets[i])->extradata);
+ break;
case MultipleDescriptor:
av_freep(&((MXFDescriptor *)mxf->metadata_sets[i])->sub_descriptors_refs);
break;
@@ -2183,10 +2435,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);
@@ -2194,8 +2448,8 @@ 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;
@@ -2217,8 +2471,14 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
int64_t seconds;
MXFContext* mxf = s->priv_data;
int64_t seekpos;
- int ret;
+ int i, ret;
+ int64_t ret64;
MXFIndexTable *t;
+ MXFTrack *source_track = st->priv_data;
+
+ /* if audio then truncate sample_time to EditRate */
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ sample_time = av_rescale_q(sample_time, st->time_base, av_inv_q(source_track->edit_rate));
if (mxf->nb_index_tables <= 0) {
if (!s->bit_rate)
@@ -2227,9 +2487,10 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
sample_time = 0;
seconds = av_rescale(sample_time, st->time_base.num, st->time_base.den);
- if ((ret = avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET)) < 0)
- return ret;
+ if ((ret64 = avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET)) < 0)
+ return ret64;
ff_update_cur_dts(s, st, sample_time);
+ mxf->current_edit_unit = sample_time;
} else {
t = &mxf->index_tables[0];
@@ -2244,7 +2505,7 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
} else {
/* no IndexEntryArray (one or more CBR segments)
* make sure we don't seek past the end */
- sample_time = FFMIN(sample_time, st->duration - 1);
+ 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)
@@ -2254,6 +2515,20 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
mxf->current_edit_unit = sample_time;
avio_seek(s->pb, seekpos, SEEK_SET);
}
+
+ // Update all tracks sample count
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *cur_st = s->streams[i];
+ MXFTrack *cur_track = cur_st->priv_data;
+ uint64_t current_sample_count = 0;
+ if (cur_st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ ret = mxf_compute_sample_count(mxf, i, &current_sample_count);
+ if (ret < 0)
+ return ret;
+
+ cur_track->sample_count = current_sample_count;
+ }
+ }
return 0;
}
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index 4fd5687..5e77a3f 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
*/
@@ -34,15 +34,18 @@
#include <math.h>
#include <time.h>
+#include "libavutil/opt.h"
#include "libavutil/random_seed.h"
+#include "libavutil/timecode.h"
+#include "libavutil/avassert.h"
#include "libavcodec/bytestream.h"
+#include "libavcodec/dnxhddata.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;
@@ -68,9 +71,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 {
@@ -87,6 +93,8 @@ 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_NONE }
};
@@ -163,6 +171,101 @@ 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 },
{ { 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 },
@@ -170,6 +273,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;
@@ -183,10 +287,9 @@ 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;
@@ -279,6 +382,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 */
@@ -426,18 +530,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)
@@ -447,7 +558,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 + 16 * 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);
@@ -476,7 +587,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
@@ -499,7 +610,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;
@@ -664,7 +775,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);
@@ -672,7 +783,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)
@@ -720,7 +831,7 @@ static void mxf_write_multi_descriptor(AVFormatContext *s)
mxf_write_metadata_key(pb, 0x014400);
PRINT_KEY(s, "multiple descriptor key", pb->buf_ptr - 16);
- klv_encode_ber_length(pb, 64 + 16 * s->nb_streams);
+ klv_encode_ber_length(pb, 64 + 16LL * s->nb_streams);
mxf_write_local_tag(pb, 16, 0x3C0A);
mxf_write_uuid(pb, MultipleDescriptor, 0);
@@ -784,8 +895,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);
@@ -808,7 +922,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);
@@ -820,9 +934,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;
@@ -847,6 +961,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)
@@ -857,13 +977,14 @@ 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);
// bit rate
mxf_write_local_tag(pb, 4, 0x8000);
- avio_wb32(pb, st->codec->bit_rate);
+ avio_wb32(pb, sc->video_bit_rate);
// profile and level
mxf_write_local_tag(pb, 1, 0x8007);
@@ -1053,8 +1174,8 @@ static void mxf_write_index_table_segment(AVFormatContext *s)
if (mxf->edit_unit_byte_count) {
klv_encode_ber_length(pb, 80);
} else {
- klv_encode_ber_length(pb, 85 + 12+(s->nb_streams+1)*6 +
- 12+mxf->edit_units_count*(11+mxf->slice_count*4));
+ klv_encode_ber_length(pb, 85 + 12+(s->nb_streams+1LL)*6 +
+ 12+mxf->edit_units_count*(11+mxf->slice_count*4LL));
}
// instance id
@@ -1176,9 +1297,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)));
}
}
@@ -1216,7 +1336,7 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
// write klv
avio_write(pb, key, 16);
- klv_encode_ber_length(pb, 88 + 16 * 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
@@ -1279,6 +1399,154 @@ 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 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
@@ -1316,7 +1584,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;
@@ -1328,6 +1595,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
@@ -1336,21 +1605,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) {
@@ -1406,17 +1660,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;
@@ -1428,44 +1683,54 @@ 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;
- }
- if (fabs(av_q2d(st->codec->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->codec->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->codec->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) {
@@ -1519,7 +1784,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))
@@ -1536,10 +1804,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;
@@ -1548,24 +1816,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;
@@ -1573,7 +1823,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);
@@ -1582,7 +1832,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 {
@@ -1594,8 +1844,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);
@@ -1612,7 +1861,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;
@@ -1628,13 +1878,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);
}
}
@@ -1693,6 +1941,16 @@ 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;
+ }
}
if (!mxf->header_written) {
@@ -1760,7 +2018,7 @@ static void mxf_write_random_index_pack(AVFormatContext *s)
int i;
avio_write(pb, random_index_pack_key, 16);
- klv_encode_ber_length(pb, 28 + 12*mxf->body_partitions_count);
+ klv_encode_ber_length(pb, 28 + 12LL*mxf->body_partitions_count);
if (mxf->edit_unit_byte_count)
avio_wb32(pb, 1); // BodySID of header partition
diff --git a/libavformat/mxg.c b/libavformat/mxg.c
index 1d1488c..b2b5b86 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 (!url_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..8cb7ed4 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 (url_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..2ba435d 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)
{
@@ -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();
+ else if (av_gettime() - 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();
diff --git a/libavformat/network.h b/libavformat/network.h
index 1d3fb7b..c60e142 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
diff --git a/libavformat/nistspheredec.c b/libavformat/nistspheredec.c
new file mode 100644
index 0000000..c09df9c
--- a/dev/null
+++ b/libavformat/nistspheredec.c
@@ -0,0 +1,128 @@
+/*
+ * 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;
+ 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 (!url_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];
+ sscanf(buffer, "%31s %*s %31s", key, value);
+ av_dict_set(&s->metadata, key, value, AV_DICT_APPEND);
+ }
+ }
+
+ 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 18ebbe3..4a749a2 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_assert(vwidth%16==0) */
+ uint16_t vheight; /* av_assert(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 (url_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 (url_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 (url_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 (url_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 (url_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 (url_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 */
@@ -732,10 +734,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 */
@@ -747,19 +747,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..7da297b 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
*/
diff --git a/libavformat/nut.c b/libavformat/nut.c
index d9a042b..8b8a4cb 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,32 +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('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('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', 'R', 'A', 64 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'B', 'A', 64 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(64 , 'B', 'R', 'A') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(64 , 'R', 'B', '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', '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') },
@@ -121,40 +144,59 @@ 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_NONE, 0 }
};
-const AVCodecTag ff_nut_audio_tags[] = {
+static const AVCodecTag nut_audio_extra_tags[] = {
{ 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, nut_audio_extra_tags, ff_nut_data_tags, 0
};
void ff_nut_reset_ts(NUTContext *nut, AVRational time_base, int64_t val)
@@ -170,7 +212,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;
}
@@ -196,6 +238,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 6357b3d..da456ac 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
*/
@@ -78,6 +78,7 @@ typedef struct StreamContext {
int msb_pts_shift;
int max_pts_distance;
int decode_delay; //FIXME duplicate of has_b_frames
+ int64_t *keyframe_pts;
} StreamContext;
typedef struct ChapterContext {
@@ -100,6 +101,9 @@ typedef struct NUTContext {
int header_count;
AVRational *time_base;
struct AVTreeNode *syncpoints;
+ int sp_count;
+ int64_t max_pts;
+ AVRational *max_pts_tb;
} NUTContext;
extern const AVCodecTag ff_nut_subtitle_tags[];
diff --git a/libavformat/nutdec.c b/libavformat/nutdec.c
index 6328549..aa7ca67 100644
--- a/libavformat/nutdec.c
+++ b/libavformat/nutdec.c
@@ -3,24 +3,25 @@
* 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/mathematics.h"
@@ -29,11 +30,11 @@
#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 +73,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 +100,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 +143,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 (!url_feof(bc)) {
state = (state << 8) | avio_r8(bc);
if ((state >> 56) != 'N')
continue;
@@ -230,6 +243,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));
@@ -297,7 +312,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;
@@ -317,7 +332,7 @@ 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);
}
if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
@@ -325,7 +340,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);
@@ -398,8 +415,8 @@ static int decode_stream_header(NUTContext *nut)
GET_V(st->codec->extradata_size, tmp < (1 << 30));
if (st->codec->extradata_size) {
- st->codec->extradata = av_mallocz(st->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
+ if (ff_alloc_extradata(st->codec, st->codec->extradata_size))
+ return AVERROR(ENOMEM);
avio_read(bc, st->codec->extradata, st->codec->extradata_size);
}
@@ -514,6 +531,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"))
av_dict_set(metadata, name, str_value, 0);
@@ -531,7 +556,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;
@@ -542,7 +568,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);
@@ -552,8 +578,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;
@@ -561,6 +587,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;
@@ -569,23 +608,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)
@@ -605,7 +660,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--)
@@ -625,7 +680,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);
@@ -712,7 +767,7 @@ static int nut_read_header(AVFormatContext *s)
find_and_decode_index(nut);
avio_seek(bc, orig_pos, SEEK_SET);
}
- assert(nut->next_startcode == SYNCPOINT_STARTCODE);
+ av_assert0(nut->next_startcode == SYNCPOINT_STARTCODE);
ff_metadata_conv_ctx(s, NULL, ff_nut_metadata_conv);
@@ -757,7 +812,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)
@@ -822,7 +877,8 @@ static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code)
return 1;
}
- av_new_packet(pkt, size + nut->header_len[header_idx]);
+ if (av_new_packet(pkt, size + nut->header_len[header_idx]) < 0)
+ return AVERROR(ENOMEM);
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);
@@ -851,7 +907,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
pos -= 8;
} else {
frame_code = avio_r8(bc);
- if (bc->eof_reached)
+ if (url_feof(bc))
return AVERROR_EOF;
if (frame_code == 'N') {
tmp = frame_code;
@@ -905,21 +961,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,
@@ -936,6 +989,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;
@@ -968,7 +1023,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);
@@ -1000,6 +1055,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 acce86c..b6d754d 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
*/
@@ -23,6 +23,7 @@
#include "libavutil/mathematics.h"
#include "libavutil/tree.h"
#include "libavutil/dict.h"
+#include "libavutil/avassert.h"
#include "libavcodec/mpegaudiodata.h"
#include "nut.h"
#include "internal.h"
@@ -60,12 +61,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);
@@ -99,8 +97,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];
@@ -169,6 +166,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) {
@@ -184,29 +194,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;
@@ -229,6 +242,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;
@@ -243,15 +258,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;
@@ -282,8 +295,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);
@@ -342,17 +354,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;
@@ -381,22 +388,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++) {
@@ -410,30 +409,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);
@@ -509,20 +495,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) {
@@ -568,6 +562,51 @@ 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 = (nus->keyframe_pts[j] != AV_NOPTS_VALUE) ^ (j+1 == nut->sp_count);
+ int n = 0;
+ 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;
@@ -641,12 +680,11 @@ static int nut_write_header(AVFormatContext *s)
nut->avf = s;
- 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);
@@ -657,8 +695,13 @@ static int nut_write_header(AVFormatContext *s)
AVStream *st = s->streams[i];
int ssize;
AVRational time_base;
- ff_parse_specific_params(st->codec, &time_base.den, &ssize,
- &time_base.num);
+ ff_parse_specific_params(st->codec, &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);
@@ -695,7 +738,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);
@@ -703,9 +746,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;
}
@@ -762,8 +806,8 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
AVIOContext *bc = s->pb, *dyn_bc;
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;
@@ -772,7 +816,7 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
av_log(s, AV_LOG_ERROR,
"Negative pts not supported stream %d, pts %"PRId64"\n",
pkt->stream_index, pkt->pts);
- return AVERROR_INVALIDDATA;
+ return AVERROR(EINVAL);
}
if (1LL << (20 + 3 * nut->header_count) <= avio_tell(bc))
@@ -781,8 +825,7 @@ 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 (pkt->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.
@@ -817,8 +860,19 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts)) < 0)
return ret;
+
+ 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)
+ return AVERROR(ENOMEM);
+ 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)
@@ -862,9 +916,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;
}
@@ -883,7 +936,7 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
frame_code = i;
}
}
- assert(frame_code != -1);
+ av_assert0(frame_code != -1);
fc = &nut->frame_code[frame_code];
flags = fc->flags;
needed_flags = get_needed_flags(nut, nus, fc, pkt);
@@ -895,27 +948,20 @@ 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_CHECKSUM)
- avio_wl32(bc, ffio_get_checksum(bc));
- else
- ffio_get_checksum(bc);
+ 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_CHECKSUM) avio_wl32(bc, ffio_get_checksum(bc));
+ else ffio_get_checksum(bc);
- 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)
+ if (flags & FLAG_KEY) {
av_add_index_entry(
s->streams[pkt->stream_index],
nut->last_syncpoint_pos,
@@ -923,6 +969,14 @@ 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;
+ }
+
+ 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;
+ }
return 0;
}
@@ -930,12 +984,22 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
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) {
+ 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);
diff --git a/libavformat/nuv.c b/libavformat/nuv.c
index 9336912..32d0e02 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 (!url_feof(pb)) {
int size, subtype;
frametype = avio_r8(pb);
@@ -86,10 +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_alloc_extradata(vst->codec, size))
return AVERROR(ENOMEM);
- vst->codec->extradata_size = size;
avio_read(pb, vst->codec->extradata, size);
size = 0;
if (!myth)
@@ -195,6 +193,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 +237,7 @@ static int nuv_packet(AVFormatContext *s, AVPacket *pkt)
nuv_frametype frametype;
int ret, size;
- while (!pb->eof_reached) {
+ while (!url_feof(pb)) {
int copyhdrsize = ctx->rtjpg_video ? HDRSIZE : 0;
uint64_t pos = avio_tell(pb);
@@ -262,10 +263,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 +303,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(!url_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 (!url_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 +385,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..a099eb3 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"
@@ -56,6 +57,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)
{
@@ -95,9 +99,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 +119,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 +138,13 @@ 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;
+ }
}
+ ogg->page_pos = -1;
ogg->curidx = -1;
return 0;
@@ -150,38 +162,105 @@ static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
return NULL;
}
-static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
+/**
+ * Replace the current stream with a new one. This is a typical webradio
+ * situation where a new audio stream spawn (identified with a new serial) and
+ * must replace the previous one (track switch).
+ */
+static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
{
struct ogg *ogg = s->priv_data;
- int idx = ogg->nstreams++;
- AVStream *st;
struct ogg_stream *os;
+ const struct ogg_codec *codec;
+ int i = 0;
+
+ if (s->pb->seekable) {
+ uint8_t magic[8];
+ int64_t pos = avio_tell(s->pb);
+ avio_skip(s->pb, nsegs);
+ avio_read(s->pb, magic, sizeof(magic));
+ avio_seek(s->pb, pos, SEEK_SET);
+ codec = ogg_find_codec(magic, sizeof(magic));
+ if (!codec) {
+ av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (i = 0; i < ogg->nstreams; i++) {
+ if (ogg->streams[i].codec == codec)
+ break;
+ }
+ if (i >= ogg->nstreams)
+ return ogg_new_stream(s, serial);
+ } else if (ogg->nstreams != 1) {
+ avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
+ return AVERROR_PATCHWELCOME;
+ }
- os = av_realloc(ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
+ os = &ogg->streams[i];
- if (!os)
- return AVERROR(ENOMEM);
+ os->serial = serial;
+ return i;
- ogg->streams = os;
+#if 0
+ buf = os->buf;
+ bufsize = os->bufsize;
+ codec = os->codec;
+
+ if (!ogg->state || ogg->state->streams[i].private != os->private)
+ av_freep(&ogg->streams[i].private);
+
+ /* 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;
- memset(ogg->streams + idx, 0, sizeof(*ogg->streams));
+ 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;
+ }
- os = ogg->streams + idx;
+ /* 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 +282,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 +317,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 (url_feof(bc))
return AVERROR_EOF;
sync[sp++ & 3] = c;
@@ -241,8 +336,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 +349,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);
- }
-
- ogg->curidx = -1;
- ogg->nstreams = 0;
+ if (data_packets_seen(ogg))
+ idx = ogg_replace_stream(s, serial, nsegs);
+ else
+ idx = ogg_new_stream(s, serial);
- 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 +378,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 +417,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 +440,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 +492,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 +535,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 +545,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 +565,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 +586,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 +633,14 @@ 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_free(ogg->streams);
+ av_freep(&ogg->streams);
return 0;
}
@@ -551,22 +648,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 +716,32 @@ 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;
+ if (psize && s->streams[idx]->codec->codec_id == AV_CODEC_ID_THEORA) {
+ if (!!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40)) {
+ 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 +755,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,6 +774,18 @@ 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 == NULL) {
+ av_free_packet(pkt);
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
+ AV_WL32(side_data + 4, os->end_trimming);
+ }
+
return psize;
}
@@ -648,22 +795,33 @@ 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;
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 +832,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 +868,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 918378d..c31859f 100644
--- a/libavformat/oggdec.h
+++ b/libavformat/oggdec.h
@@ -81,7 +81,10 @@ 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
void *private;
};
@@ -98,6 +101,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 +109,7 @@ struct ogg {
#define OGG_FLAG_BOS 2
#define OGG_FLAG_EOS 4
-#define OGG_NOGRANULE_VALUE -1ull
+#define OGG_NOGRANULE_VALUE (-1ull)
extern const struct ogg_codec ff_celt_codec;
extern const struct ogg_codec ff_dirac_codec;
diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c
index e01c365..1883501 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
*/
@@ -75,10 +75,12 @@ 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",
- OFFSET(pref_duration), AV_OPT_TYPE_INT, { .i64 = 1000000 }, 0, INT64_MAX, PARAM },
+ OFFSET(pref_duration), AV_OPT_TYPE_INT64, { .i64 = 1000000 }, 0, INT64_MAX, PARAM },
{ NULL },
};
@@ -137,6 +139,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)
@@ -207,9 +214,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;
@@ -268,7 +280,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;
unsigned int count;
@@ -389,7 +401,7 @@ static int ogg_build_opus_headers(AVCodecContext *avctx,
static int ogg_write_header(AVFormatContext *s)
{
OGGContext *ogg = s->priv_data;
- OGGStreamContext *oggstream;
+ OGGStreamContext *oggstream = NULL;
int i, j;
if (ogg->pref_size)
@@ -399,13 +411,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);
- else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den);
if (st->codec->codec_id != AV_CODEC_ID_VORBIS &&
st->codec->codec_id != AV_CODEC_ID_THEORA &&
@@ -434,11 +446,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,
st->codec->flags & CODEC_FLAG_BITEXACT,
- &s->metadata);
+ &st->metadata);
if (err) {
av_log(s, AV_LOG_ERROR, "Error writing FLAC headers\n");
av_freep(&st->priv_data);
@@ -447,7 +461,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,
st->codec->flags & CODEC_FLAG_BITEXACT,
- &s->metadata);
+ &st->metadata);
if (err) {
av_log(s, AV_LOG_ERROR, "Error writing Speex headers\n");
av_freep(&st->priv_data);
@@ -456,7 +470,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,
st->codec->flags & CODEC_FLAG_BITEXACT,
- &s->metadata);
+ &st->metadata);
if (err) {
av_log(s, AV_LOG_ERROR, "Error writing Opus headers\n");
av_freep(&st->priv_data);
@@ -477,7 +491,7 @@ static int ogg_write_header(AVFormatContext *s)
}
p = ogg_write_vorbiscomment(7, st->codec->flags & CODEC_FLAG_BITEXACT,
- &oggstream->header_len[1], &s->metadata,
+ &oggstream->header_len[1], &st->metadata,
framing_bit);
oggstream->header[1] = p;
if (!p)
@@ -508,7 +522,7 @@ static int ogg_write_header(AVFormatContext *s)
AVStream *st = s->streams[j];
OGGStreamContext *oggstream = st->priv_data;
for (i = 1; i < 3; i++) {
- if (oggstream && oggstream->header_len[i])
+ if (oggstream->header_len[i])
ogg_buffer_data(s, st, oggstream->header[i],
oggstream->header_len[i], 0, 1);
}
@@ -600,7 +614,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);
diff --git a/libavformat/oggparsecelt.c b/libavformat/oggparsecelt.c
index 0deccc2..f3c2c1a 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,16 +44,12 @@ static int celt_header(AVFormatContext *s, int idx)
uint32_t version, sample_rate, nb_channels, frame_size;
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);
- av_free(priv);
+ if (!priv)
+ return AVERROR(ENOMEM);
+ if (ff_alloc_extradata(st->codec, 2 * sizeof(uint32_t)) < 0)
return AVERROR(ENOMEM);
- }
version = AV_RL32(p + 28);
/* unused header size field skipped */
sample_rate = AV_RL32(p + 36);
@@ -62,21 +58,18 @@ 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->frame_size = frame_size;
- 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..73bc495 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
*/
diff --git a/libavformat/oggparseflac.c b/libavformat/oggparseflac.c
index f59b400..f69533f 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
*/
@@ -62,10 +62,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);
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
} else if (mdt == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
@@ -78,11 +77,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 56ea557..b8c502a 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);
bytestream2_skip(&p, 4); /* default_len */
@@ -86,8 +90,18 @@ ogm_header(AVFormatContext *s, int idx)
st->codec->channels = bytestream2_get_le16(&p);
bytestream2_skip(&p, 2); /* block_align */
st->codec->bit_rate = bytestream2_get_le32(&p) * 8;
- st->codec->sample_rate = spu * 10000000 / time_unit;
+ st->codec->sample_rate = time_unit ? spu * 10000000 / time_unit : 0;
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);
diff --git a/libavformat/oggparseopus.c b/libavformat/oggparseopus.c
index babd0f0..78aa333 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
*/
@@ -41,29 +41,28 @@ 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);
+ /*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;
avpriv_set_pts_info(st, 64, 1, 48000);
@@ -121,10 +120,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 +136,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 f437c69..d94b0c2 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
*/
@@ -37,6 +37,9 @@ static int skeleton_header(AVFormatContext *s, int idx)
strcpy(st->codec->codec_name, "skeleton");
st->codec->codec_type = AVMEDIA_TYPE_DATA;
+ if ((os->flags & OGG_FLAG_EOS) && os->psize == 0)
+ return 1;
+
if (os->psize < 8)
return -1;
@@ -47,7 +50,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;
@@ -61,7 +64,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);
@@ -74,12 +77,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 42480a3..1b9de9c 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 25210ab..0fd5812 100644
--- a/libavformat/oggparsetheora.c
+++ b/libavformat/oggparsetheora.c
@@ -110,7 +110,6 @@ theora_header (AVFormatContext * s, int idx)
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_THEORA;
st->need_parsing = AVSTREAM_PARSE_HEADERS;
-
}
break;
case 0x81:
@@ -120,6 +119,7 @@ theora_header (AVFormatContext * s, int idx)
return -1;
break;
default:
+ av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]);
return -1;
}
@@ -163,10 +163,47 @@ theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, int64_t *dts)
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 c19b545..36ad738 100644
--- a/libavformat/oggparsevorbis.c
+++ b/libavformat/oggparsevorbis.c
@@ -141,9 +141,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);
@@ -201,12 +202,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;
@@ -269,6 +273,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;
@@ -276,7 +281,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
@@ -341,23 +351,28 @@ static int vorbis_packet(AVFormatContext *s, int idx)
* 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)) {
+ int seg, d;
uint8_t *last_pkt = os->buf + os->pstart;
uint8_t *next_pkt = last_pkt;
- int first_duration = 0;
avpriv_vorbis_parse_reset(&priv->vp);
duration = 0;
- for (seg = 0; seg < os->nsegs; seg++) {
+ seg = os->segp;
+ d = avpriv_vorbis_parse_frame(&priv->vp, last_pkt, 1);
+ 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++) {
if (os->segments[seg] < 255) {
int d = avpriv_vorbis_parse_frame(&priv->vp, last_pkt, 1);
if (d < 0) {
duration = os->granule;
break;
}
- if (!duration)
- first_duration = d;
duration += d;
last_pkt = next_pkt + os->segments[seg];
}
@@ -365,10 +380,11 @@ 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 (s->streams[idx]->start_time == AV_NOPTS_VALUE) {
+ s->streams[idx]->start_time = FFMAX(os->lastpts, 0);
+ if (s->streams[idx]->duration)
+ s->streams[idx]->duration -= s->streams[idx]->start_time;
+ }
priv->final_pts = AV_NOPTS_VALUE;
avpriv_vorbis_parse_reset(&priv->vp);
}
@@ -376,7 +392,7 @@ static int vorbis_packet(AVFormatContext *s, int idx)
/* parse packet duration */
if (os->psize > 0) {
duration = avpriv_vorbis_parse_frame(&priv->vp, os->buf + os->pstart, 1);
- if (duration <= 0) {
+ if (duration < 0) {
os->pflags |= AV_PKT_FLAG_CORRUPT;
return 0;
}
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 e5a2090..4017db3 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
*/
@@ -37,7 +37,6 @@
* - Sound data organized in packets follow the EA3 header
* (can be encrypted using the Sony DRM!).
*
- * CODEC SUPPORT: Only ATRAC3 codec is currently supported!
*/
#include "libavutil/channel_layout.h"
@@ -172,13 +171,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);
@@ -237,6 +232,12 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header)
av_log(s, AV_LOG_ERROR, "Invalid encryption header\n");
return AVERROR_INVALIDDATA;
}
+ if ( OMA_ENC_HEADER_SIZE + oc->k_size + oc->e_size + oc->i_size + 8 > geob->datasize
+ || OMA_ENC_HEADER_SIZE + 48 > geob->datasize
+ ) {
+ av_log(s, AV_LOG_ERROR, "Too little GEOB data\n");
+ return AVERROR_INVALIDDATA;
+ }
oc->rid = AV_RB32(&gdata[OMA_ENC_HEADER_SIZE + 28]);
av_log(s, AV_LOG_DEBUG, "RID: %.8x\n", oc->rid);
@@ -263,7 +264,7 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header)
!nprobe(s, gdata, geob->datasize, oc->n_val))
break;
}
- if (i >= sizeof(leaf_table)) {
+ if (i >= FF_ARRAY_ELEMS(leaf_table)) {
av_log(s, AV_LOG_ERROR, "Invalid key\n");
return AVERROR_INVALIDDATA;
}
@@ -348,12 +349,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
@@ -384,7 +383,7 @@ static int oma_read_header(AVFormatContext *s)
av_log(s, AV_LOG_ERROR, "Unsupported codec ATRAC3+!\n");
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:
diff --git a/libavformat/omaenc.c b/libavformat/omaenc.c
index ea28e10..b947987 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 d99f04a..5218e5b 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"
@@ -76,6 +76,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,
@@ -83,6 +90,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)
@@ -103,6 +112,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 54bf25f..8145325 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
*/
@@ -31,6 +33,8 @@
#define D AV_OPT_FLAG_DECODING_PARAM
static const AVOption avformat_options[] = {
+{"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(probesize), AV_OPT_TYPE_INT, {.i64 = 5000000 }, 32, INT_MAX, 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"},
@@ -41,8 +45,12 @@ static const AVOption avformat_options[] = {
{"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"},
-{"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},
+{"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, D},
+{"analyzeduration", "specify how many microseconds are analyzed to probe the input", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT, {.i64 = 5*AV_TIME_BASE }, 0, INT_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 */
@@ -50,6 +58,9 @@ static const AVOption avformat_options[] = {
{"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},
{"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"},
@@ -58,6 +69,14 @@ 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"},
+{"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},
+{"avoid_negative_ts", "shift timestamps to make them non-negative. 1 enables, 0 disables, default of -1 enables when required by target format.", OFFSET(avoid_negative_ts), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, E},
+{"skip_initial_bytes", "set number of bytes to skip before reading header and frames", OFFSET(skip_initial_bytes), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_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},
{NULL},
};
diff --git a/libavformat/os_support.c b/libavformat/os_support.c
index 4ae5ac1..3218956 100644
--- a/libavformat/os_support.c
+++ b/libavformat/os_support.c
@@ -3,20 +3,20 @@
* 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
*/
diff --git a/libavformat/os_support.h b/libavformat/os_support.h
index ae8cef7..7c7cd1f 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,8 +33,17 @@
#if defined(_WIN32) && !defined(__MINGW32CE__)
# include <fcntl.h>
+# ifdef lseek
+# undef lseek
+# endif
# define lseek(f,p,w) _lseeki64((f), (p), (w))
+# ifdef stat
+# undef stat
+# endif
# define stat _stati64
+# ifdef fstat
+# undef fstat
+# endif
# define fstat(f,s) _fstati64((f), (s))
#endif /* defined(__MINGW32__) && !defined(__MINGW32CE__) */
@@ -45,8 +54,6 @@
#include <io.h>
#endif
#define mkdir(a, b) _mkdir(a)
-#else
-#include <sys/stat.h>
#endif
static inline int is_dos_path(const char *path)
diff --git a/libavformat/output-example.c b/libavformat/output-example.c
deleted file mode 100644
index 496b7f8..0000000
--- a/libavformat/output-example.c
+++ b/dev/null
@@ -1,527 +0,0 @@
-/*
- * Copyright (c) 2003 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/**
- * @file
- * libavformat API example.
- *
- * @example libavformat/output-example.c
- * Output a media file in any supported libavformat format.
- * The default codecs are used.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
-#include "libavutil/mathematics.h"
-#include "libavformat/avformat.h"
-#include "libswscale/swscale.h"
-
-/* 5 seconds stream duration */
-#define STREAM_DURATION 5.0
-#define STREAM_FRAME_RATE 25 /* 25 images/s */
-#define STREAM_NB_FRAMES ((int)(STREAM_DURATION * STREAM_FRAME_RATE))
-#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */
-
-static int sws_flags = SWS_BICUBIC;
-
-/**************************************************************/
-/* audio output */
-
-static float t, tincr, tincr2;
-static int16_t *samples;
-static int audio_input_frame_size;
-
-/*
- * add an audio output stream
- */
-static AVStream *add_audio_stream(AVFormatContext *oc, enum AVCodecID codec_id)
-{
- AVCodecContext *c;
- AVStream *st;
- AVCodec *codec;
-
- /* find the audio encoder */
- codec = avcodec_find_encoder(codec_id);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- st = avformat_new_stream(oc, codec);
- if (!st) {
- fprintf(stderr, "Could not alloc stream\n");
- exit(1);
- }
-
- c = st->codec;
-
- /* put sample parameters */
- c->sample_fmt = AV_SAMPLE_FMT_S16;
- c->bit_rate = 64000;
- c->sample_rate = 44100;
- c->channels = 2;
-
- // some formats want stream headers to be separate
- if (oc->oformat->flags & AVFMT_GLOBALHEADER)
- c->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
- return st;
-}
-
-static void open_audio(AVFormatContext *oc, AVStream *st)
-{
- AVCodecContext *c;
-
- c = st->codec;
-
- /* open it */
- if (avcodec_open2(c, NULL, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
- }
-
- /* init signal generator */
- t = 0;
- tincr = 2 * M_PI * 110.0 / c->sample_rate;
- /* increment frequency by 110 Hz per second */
- tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;
-
- if (c->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)
- audio_input_frame_size = 10000;
- else
- audio_input_frame_size = c->frame_size;
- samples = av_malloc(audio_input_frame_size *
- av_get_bytes_per_sample(c->sample_fmt) *
- c->channels);
-}
-
-/* Prepare a 16 bit dummy audio frame of 'frame_size' samples and
- * 'nb_channels' channels. */
-static void get_audio_frame(int16_t *samples, int frame_size, int nb_channels)
-{
- int j, i, v;
- int16_t *q;
-
- q = samples;
- for (j = 0; j < frame_size; j++) {
- v = (int)(sin(t) * 10000);
- for (i = 0; i < nb_channels; i++)
- *q++ = v;
- t += tincr;
- tincr += tincr2;
- }
-}
-
-static void write_audio_frame(AVFormatContext *oc, AVStream *st)
-{
- AVCodecContext *c;
- AVPacket pkt = { 0 }; // data and size must be 0;
- AVFrame *frame = avcodec_alloc_frame();
- int got_packet;
-
- av_init_packet(&pkt);
- c = st->codec;
-
- get_audio_frame(samples, audio_input_frame_size, c->channels);
- frame->nb_samples = audio_input_frame_size;
- avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,
- (uint8_t *)samples,
- audio_input_frame_size *
- av_get_bytes_per_sample(c->sample_fmt) *
- c->channels, 1);
-
- avcodec_encode_audio2(c, &pkt, frame, &got_packet);
- if (!got_packet)
- return;
-
- pkt.stream_index = st->index;
-
- /* 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);
- }
- avcodec_free_frame(&frame);
-}
-
-static void close_audio(AVFormatContext *oc, AVStream *st)
-{
- avcodec_close(st->codec);
-
- av_free(samples);
-}
-
-/**************************************************************/
-/* video output */
-
-static AVFrame *picture, *tmp_picture;
-static int frame_count;
-
-/* Add a video output stream. */
-static AVStream *add_video_stream(AVFormatContext *oc, enum AVCodecID codec_id)
-{
- AVCodecContext *c;
- AVStream *st;
- AVCodec *codec;
-
- /* find the video encoder */
- codec = avcodec_find_encoder(codec_id);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- st = avformat_new_stream(oc, codec);
- if (!st) {
- fprintf(stderr, "Could not alloc stream\n");
- exit(1);
- }
-
- c = 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. */
- c->time_base.den = STREAM_FRAME_RATE;
- c->time_base.num = 1;
- 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;
-
- return st;
-}
-
-static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
-{
- AVFrame *picture;
- uint8_t *picture_buf;
- int size;
-
- picture = avcodec_alloc_frame();
- if (!picture)
- return NULL;
- size = avpicture_get_size(pix_fmt, width, height);
- picture_buf = av_malloc(size);
- if (!picture_buf) {
- av_free(picture);
- return NULL;
- }
- avpicture_fill((AVPicture *)picture, picture_buf,
- pix_fmt, width, height);
- return picture;
-}
-
-static void open_video(AVFormatContext *oc, AVStream *st)
-{
- AVCodecContext *c;
-
- c = st->codec;
-
- /* open the codec */
- if (avcodec_open2(c, NULL, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
- }
-
- /* Allocate the encoded raw picture. */
- picture = alloc_picture(c->pix_fmt, c->width, c->height);
- if (!picture) {
- fprintf(stderr, "Could not allocate picture\n");
- exit(1);
- }
-
- /* If the output format is not YUV420P, then a temporary YUV420P
- * picture is needed too. It is then converted to the required
- * output format. */
- tmp_picture = NULL;
- if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
- tmp_picture = alloc_picture(AV_PIX_FMT_YUV420P, c->width, c->height);
- if (!tmp_picture) {
- fprintf(stderr, "Could not allocate temporary picture\n");
- exit(1);
- }
- }
-}
-
-/* Prepare a dummy image. */
-static void fill_yuv_image(AVFrame *pict, int frame_index,
- int width, int height)
-{
- int x, y, i;
-
- i = frame_index;
-
- /* Y */
- for (y = 0; y < height; y++)
- for (x = 0; x < width; x++)
- pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
-
- /* Cb and Cr */
- for (y = 0; y < height / 2; y++) {
- for (x = 0; x < width / 2; x++) {
- pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
- pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
- }
- }
-}
-
-static void write_video_frame(AVFormatContext *oc, AVStream *st)
-{
- int ret;
- AVCodecContext *c;
- static struct SwsContext *img_convert_ctx;
-
- c = st->codec;
-
- if (frame_count >= STREAM_NB_FRAMES) {
- /* No more frames to compress. The codec has a latency of a few
- * frames if using B-frames, so we get the last frames by
- * passing the same picture again. */
- } else {
- if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
- /* as we only generate a YUV420P picture, we must convert it
- * to the codec pixel format if needed */
- if (img_convert_ctx == NULL) {
- img_convert_ctx = sws_getContext(c->width, c->height,
- AV_PIX_FMT_YUV420P,
- c->width, c->height,
- c->pix_fmt,
- sws_flags, NULL, NULL, NULL);
- if (img_convert_ctx == NULL) {
- fprintf(stderr,
- "Cannot initialize the conversion context\n");
- exit(1);
- }
- }
- fill_yuv_image(tmp_picture, frame_count, c->width, c->height);
- sws_scale(img_convert_ctx, tmp_picture->data, tmp_picture->linesize,
- 0, c->height, picture->data, picture->linesize);
- } else {
- fill_yuv_image(picture, frame_count, c->width, c->height);
- }
- }
-
- if (oc->oformat->flags & AVFMT_RAWPICTURE) {
- /* Raw video case - the API will change slightly in the near
- * future for that. */
- AVPacket pkt;
- av_init_packet(&pkt);
-
- pkt.flags |= AV_PKT_FLAG_KEY;
- pkt.stream_index = st->index;
- pkt.data = (uint8_t *)picture;
- pkt.size = sizeof(AVPicture);
-
- ret = av_interleaved_write_frame(oc, &pkt);
- } else {
- AVPacket pkt = { 0 };
- int got_packet;
- av_init_packet(&pkt);
-
- /* encode the image */
- ret = avcodec_encode_video2(c, &pkt, picture, &got_packet);
- /* If size is zero, it means the image was buffered. */
- if (!ret && got_packet && pkt.size) {
- if (pkt.pts != AV_NOPTS_VALUE) {
- pkt.pts = av_rescale_q(pkt.pts,
- c->time_base, st->time_base);
- }
- if (pkt.dts != AV_NOPTS_VALUE) {
- pkt.dts = av_rescale_q(pkt.dts,
- c->time_base, st->time_base);
- }
- pkt.stream_index = st->index;
-
- /* Write the compressed frame to the media file. */
- ret = av_interleaved_write_frame(oc, &pkt);
- } else {
- ret = 0;
- }
- }
- if (ret != 0) {
- fprintf(stderr, "Error while writing video frame\n");
- exit(1);
- }
- frame_count++;
-}
-
-static void close_video(AVFormatContext *oc, AVStream *st)
-{
- avcodec_close(st->codec);
- av_free(picture->data[0]);
- av_free(picture);
- if (tmp_picture) {
- av_free(tmp_picture->data[0]);
- av_free(tmp_picture);
- }
-}
-
-/**************************************************************/
-/* media file output */
-
-int main(int argc, char **argv)
-{
- const char *filename;
- AVOutputFormat *fmt;
- AVFormatContext *oc;
- AVStream *audio_st, *video_st;
- double audio_pts, video_pts;
- int i;
-
- /* Initialize libavcodec, and register all codecs and formats. */
- av_register_all();
-
- if (argc != 2) {
- printf("usage: %s output_file\n"
- "API example program to output a media file with libavformat.\n"
- "The output format is automatically guessed according to the file extension.\n"
- "Raw images can also be output by using '%%d' in the filename\n"
- "\n", argv[0]);
- return 1;
- }
-
- filename = argv[1];
-
- /* Autodetect the output format from the name. default is MPEG. */
- fmt = av_guess_format(NULL, filename, NULL);
- if (!fmt) {
- printf("Could not deduce output format from file extension: using MPEG.\n");
- fmt = av_guess_format("mpeg", NULL, NULL);
- }
- if (!fmt) {
- fprintf(stderr, "Could not find suitable output format\n");
- return 1;
- }
-
- /* Allocate the output media context. */
- oc = avformat_alloc_context();
- if (!oc) {
- fprintf(stderr, "Memory error\n");
- return 1;
- }
- oc->oformat = fmt;
- snprintf(oc->filename, sizeof(oc->filename), "%s", filename);
-
- /* Add the audio and video streams using the default format codecs
- * and initialize the codecs. */
- video_st = NULL;
- audio_st = NULL;
- if (fmt->video_codec != AV_CODEC_ID_NONE) {
- video_st = add_video_stream(oc, fmt->video_codec);
- }
- if (fmt->audio_codec != AV_CODEC_ID_NONE) {
- audio_st = add_audio_stream(oc, fmt->audio_codec);
- }
-
- /* Now that all the parameters are set, we can open the audio and
- * video codecs and allocate the necessary encode buffers. */
- if (video_st)
- open_video(oc, video_st);
- if (audio_st)
- open_audio(oc, audio_st);
-
- av_dump_format(oc, 0, filename, 1);
-
- /* open the output file, if needed */
- if (!(fmt->flags & AVFMT_NOFILE)) {
- if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) {
- fprintf(stderr, "Could not open '%s'\n", filename);
- return 1;
- }
- }
-
- /* Write the stream header, if any. */
- avformat_write_header(oc, NULL);
-
- for (;;) {
- /* Compute current audio and video time. */
- if (audio_st)
- audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den;
- else
- audio_pts = 0.0;
-
- if (video_st)
- video_pts = (double)video_st->pts.val * video_st->time_base.num /
- video_st->time_base.den;
- else
- video_pts = 0.0;
-
- if ((!audio_st || audio_pts >= STREAM_DURATION) &&
- (!video_st || video_pts >= STREAM_DURATION))
- break;
-
- /* write interleaved audio and video frames */
- if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
- write_audio_frame(oc, audio_st);
- } else {
- write_video_frame(oc, video_st);
- }
- }
-
- /* Write the trailer, if any. The trailer must be written before you
- * close the CodecContexts open when you wrote the header; otherwise
- * av_write_trailer() may try to use memory that was freed on
- * av_codec_close(). */
- av_write_trailer(oc);
-
- /* Close each codec. */
- if (video_st)
- close_video(oc, video_st);
- if (audio_st)
- close_audio(oc, audio_st);
-
- /* Free the streams. */
- for (i = 0; i < oc->nb_streams; i++) {
- av_freep(&oc->streams[i]->codec);
- av_freep(&oc->streams[i]);
- }
-
- if (!(fmt->flags & AVFMT_NOFILE))
- /* Close the output file. */
- avio_close(oc->pb);
-
- /* free the stream */
- av_free(oc);
-
- return 0;
-}
diff --git a/libavformat/paf.c b/libavformat/paf.c
new file mode 100644
index 0000000..09aefe6
--- a/dev/null
+++ b/libavformat/paf.c
@@ -0,0 +1,262 @@
+/*
+ * Packed Animation 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/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"
+
+typedef struct {
+ uint32_t buffer_size;
+ uint32_t frame_blks;
+ uint32_t nb_frames;
+ uint32_t start_offset;
+ uint32_t preload_count;
+ uint32_t max_video_blks;
+ uint32_t max_audio_blks;
+
+ uint32_t current_frame;
+ uint32_t current_frame_count;
+ uint32_t current_frame_block;
+
+ uint32_t *blocks_count_table;
+ uint32_t *frames_offset_table;
+ uint32_t *blocks_offset_table;
+
+ uint8_t *video_frame;
+ int video_size;
+
+ uint8_t *audio_frame;
+ uint8_t *temp_audio_frame;
+ int audio_size;
+
+ int got_audio;
+} PAFDemuxContext;
+
+static int read_probe(AVProbeData *p)
+{
+ if ((p->buf_size >= strlen(MAGIC)) &&
+ !memcmp(p->buf, MAGIC, strlen(MAGIC)))
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int read_close(AVFormatContext *s)
+{
+ PAFDemuxContext *p = s->priv_data;
+
+ av_freep(&p->blocks_count_table);
+ av_freep(&p->frames_offset_table);
+ av_freep(&p->blocks_offset_table);
+ av_freep(&p->video_frame);
+ av_freep(&p->audio_frame);
+ av_freep(&p->temp_audio_frame);
+
+ return 0;
+}
+
+static void read_table(AVFormatContext *s, uint32_t *table, uint32_t count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ table[i] = avio_rl32(s->pb);
+
+ avio_skip(s->pb, 4 * (FFALIGN(count, 512) - count));
+}
+
+static int read_header(AVFormatContext *s)
+{
+ PAFDemuxContext *p = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *ast, *vst;
+ int ret = 0;
+
+ avio_skip(pb, 132);
+
+ vst = avformat_new_stream(s, 0);
+ if (!vst)
+ return AVERROR(ENOMEM);
+
+ vst->start_time = 0;
+ vst->nb_frames =
+ vst->duration =
+ p->nb_frames = avio_rl32(pb);
+ avio_skip(pb, 4);
+ vst->codec->width = avio_rl32(pb);
+ vst->codec->height = avio_rl32(pb);
+ avio_skip(pb, 4);
+ vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ vst->codec->codec_tag = 0;
+ vst->codec->codec_id = AV_CODEC_ID_PAF_VIDEO;
+ avpriv_set_pts_info(vst, 64, 1, 10);
+
+ ast = avformat_new_stream(s, 0);
+ if (!ast)
+ return AVERROR(ENOMEM);
+
+ ast->start_time = 0;
+ ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ ast->codec->codec_tag = 0;
+ ast->codec->codec_id = AV_CODEC_ID_PAF_AUDIO;
+ ast->codec->channels = 2;
+ ast->codec->channel_layout = AV_CH_LAYOUT_STEREO;
+ ast->codec->sample_rate = 22050;
+ avpriv_set_pts_info(ast, 64, 1, 22050);
+
+ p->buffer_size = avio_rl32(pb);
+ p->preload_count = avio_rl32(pb);
+ p->frame_blks = avio_rl32(pb);
+ p->start_offset = avio_rl32(pb);
+ p->max_video_blks = avio_rl32(pb);
+ p->max_audio_blks = avio_rl32(pb);
+ if (p->buffer_size < 175 ||
+ p->max_audio_blks < 2 ||
+ p->max_video_blks < 1 ||
+ p->frame_blks < 1 ||
+ p->nb_frames < 1 ||
+ p->preload_count < 1 ||
+ p->buffer_size > 2048 ||
+ p->max_video_blks > 2048 ||
+ p->max_audio_blks > 2048 ||
+ p->nb_frames > INT_MAX / sizeof(uint32_t) ||
+ p->frame_blks > INT_MAX / sizeof(uint32_t))
+ return AVERROR_INVALIDDATA;
+
+ p->blocks_count_table = av_mallocz(p->nb_frames * sizeof(uint32_t));
+ p->frames_offset_table = av_mallocz(p->nb_frames * sizeof(uint32_t));
+ p->blocks_offset_table = av_mallocz(p->frame_blks * sizeof(uint32_t));
+
+ p->video_size = p->max_video_blks * p->buffer_size;
+ p->video_frame = av_mallocz(p->video_size);
+
+ p->audio_size = p->max_audio_blks * p->buffer_size;
+ p->audio_frame = av_mallocz(p->audio_size);
+ p->temp_audio_frame = av_mallocz(p->audio_size);
+
+ if (!p->blocks_count_table ||
+ !p->frames_offset_table ||
+ !p->blocks_offset_table ||
+ !p->video_frame ||
+ !p->audio_frame ||
+ !p->temp_audio_frame) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ avio_seek(pb, p->buffer_size, SEEK_SET);
+
+ read_table(s, p->blocks_count_table, p->nb_frames);
+ read_table(s, p->frames_offset_table, p->nb_frames);
+ read_table(s, p->blocks_offset_table, p->frame_blks);
+
+ p->got_audio = 0;
+ p->current_frame = 0;
+ p->current_frame_block = 0;
+
+ avio_seek(pb, p->start_offset, SEEK_SET);
+
+ return 0;
+
+fail:
+ read_close(s);
+
+ return ret;
+}
+
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ PAFDemuxContext *p = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint32_t count, offset;
+ int size, i;
+
+ if (p->current_frame >= p->nb_frames)
+ return AVERROR_EOF;
+
+ if (url_feof(pb))
+ return AVERROR_EOF;
+
+ if (p->got_audio) {
+ if (av_new_packet(pkt, p->audio_size) < 0)
+ return AVERROR(ENOMEM);
+
+ memcpy(pkt->data, p->temp_audio_frame, p->audio_size);
+ pkt->duration = PAF_SOUND_SAMPLES * (p->audio_size / PAF_SOUND_FRAME_SIZE);
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ pkt->stream_index = 1;
+ p->got_audio = 0;
+ return pkt->size;
+ }
+
+ count = (p->current_frame == 0) ? p->preload_count : p->blocks_count_table[p->current_frame - 1];
+ for (i = 0; i < count; i++) {
+ if (p->current_frame_block >= p->frame_blks)
+ return AVERROR_INVALIDDATA;
+
+ offset = p->blocks_offset_table[p->current_frame_block] & ~(1U << 31);
+ if (p->blocks_offset_table[p->current_frame_block] & (1U << 31)) {
+ if (offset > p->audio_size - p->buffer_size)
+ return AVERROR_INVALIDDATA;
+
+ avio_read(pb, p->audio_frame + offset, p->buffer_size);
+ if (offset == (p->max_audio_blks - 2) * p->buffer_size) {
+ memcpy(p->temp_audio_frame, p->audio_frame, p->audio_size);
+ p->got_audio = 1;
+ }
+ } else {
+ if (offset > p->video_size - p->buffer_size)
+ return AVERROR_INVALIDDATA;
+
+ avio_read(pb, p->video_frame + offset, p->buffer_size);
+ }
+ p->current_frame_block++;
+ }
+
+ if (p->frames_offset_table[p->current_frame] >= p->video_size)
+ return AVERROR_INVALIDDATA;
+
+ size = p->video_size - p->frames_offset_table[p->current_frame];
+
+ if (av_new_packet(pkt, size) < 0)
+ return AVERROR(ENOMEM);
+
+ pkt->stream_index = 0;
+ pkt->duration = 1;
+ memcpy(pkt->data, p->video_frame + p->frames_offset_table[p->current_frame], size);
+ if (pkt->data[0] & 0x20)
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ p->current_frame++;
+
+ return pkt->size;
+}
+
+AVInputFormat ff_paf_demuxer = {
+ .name = "paf",
+ .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File"),
+ .priv_data_size = sizeof(PAFDemuxContext),
+ .read_probe = read_probe,
+ .read_header = read_header,
+ .read_packet = read_packet,
+ .read_close = read_close,
+};
diff --git a/libavformat/pcm.c b/libavformat/pcm.c
index 892e8ca..2fe44dc 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,26 @@
#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;
+ if (ret < 0)
+ return ret;
+
+ 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 716d8b7..f4264d9 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,29 +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);
- assert(bps); // if false there IS a bug elsewhere (NOT in this function)
- 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 },
};
@@ -99,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, \
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..a69a316
--- a/dev/null
+++ b/libavformat/pjsdec.c
@@ -0,0 +1,137 @@
+/*
+ * 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, "\"") + 1;
+ *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 (!url_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 484be43..71f450e 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 (url_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,15 @@ static int pmp_packet(AVFormatContext *s, AVPacket *pkt)
int ret = 0;
int i;
- if (pb->eof_reached)
+ if (url_feof(pb))
return AVERROR_EOF;
if (pmp->cur_stream == 0) {
int num_packets;
pmp->audio_packets = avio_r8(pb);
+ if (!pmp->audio_packets) {
+ avpriv_request_sample(s, "0 audio packets");
+ return AVERROR_PATCHWELCOME;
+ }
num_packets = (pmp->num_streams - 1) * pmp->audio_packets + 1;
avio_skip(pb, 8);
pmp->current_packet = 0;
@@ -138,7 +156,7 @@ 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
@@ -146,14 +164,13 @@ static int pmp_packet(AVFormatContext *s, AVPacket *pkt)
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..3409d6a 100644
--- a/libavformat/psxstr.c
+++ b/libavformat/psxstr.c
@@ -2,20 +2,20 @@
* Sony Playstation (PSX) STR File Demuxer
* 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)
@@ -257,7 +291,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
break;
}
- if (pb->eof_reached)
+ if (url_feof(pb))
return AVERROR(EIO);
}
}
diff --git a/libavformat/pva.c b/libavformat/pva.c
index 3abfc18..9b7a40a 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 (AV_RB16(buf) == PVA_MAGIC && buf[2] && buf[2] < 3 && buf[4] == 0x55)
+ if (len < 0)
+ return 0;
+
+ 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) {
diff --git a/libavformat/pvfdec.c b/libavformat/pvfdec.c
new file mode 100644
index 0000000..c678046
--- a/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..1ef86fe 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(!url_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 41e1700..a9ff22a 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"
#define RAW_PACKET_SIZE 1024
@@ -45,12 +46,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;
}
@@ -61,7 +58,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 */
@@ -73,7 +70,6 @@ int ff_raw_video_read_header(AVFormatContext *s)
{
AVStream *st;
FFRawVideoDemuxerContext *s1 = s->priv_data;
- AVRational framerate;
int ret = 0;
@@ -85,29 +81,45 @@ 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->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_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 CONFIG_LATM_DEMUXER
AVInputFormat ff_latm_demuxer = {
.name = "latm",
@@ -121,7 +133,7 @@ AVInputFormat ff_latm_demuxer = {
#endif
#if CONFIG_MJPEG_DEMUXER
-FF_DEF_RAWVIDEO_DEMUXER(mjpeg, "raw MJPEG video", NULL, "mjpg,mjpeg", AV_CODEC_ID_MJPEG)
+FF_DEF_RAWVIDEO_DEMUXER(mjpeg, "raw MJPEG video", NULL, "mjpg,mjpeg,mpo", AV_CODEC_ID_MJPEG)
#endif
#if CONFIG_MLP_DEMUXER
diff --git a/libavformat/rawdec.h b/libavformat/rawdec.h
index a548778..5910855 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[];
diff --git a/libavformat/rawenc.c b/libavformat/rawenc.c
index 852a27d..7a1fa93 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
*/
@@ -68,6 +68,15 @@ AVOutputFormat ff_cavsvideo_muxer = {
};
#endif
+#if CONFIG_DATA_MUXER
+AVOutputFormat ff_data_muxer = {
+ .name = "data",
+ .long_name = NULL_IF_CONFIG_SMALL("raw data"),
+ .write_packet = ff_raw_write_packet,
+ .flags = AVFMT_NOTIMESTAMPS,
+};
+#endif
+
#if CONFIG_DIRAC_MUXER
AVOutputFormat ff_dirac_muxer = {
.name = "dirac",
@@ -131,6 +140,19 @@ AVOutputFormat ff_g722_muxer = {
};
#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_packet = ff_raw_write_packet,
+ .flags = AVFMT_NOTIMESTAMPS,
+};
+#endif
+
#if CONFIG_H261_MUXER
AVOutputFormat ff_h261_muxer = {
.name = "h261",
@@ -243,18 +265,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",
@@ -266,3 +276,15 @@ AVOutputFormat ff_truehd_muxer = {
.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_packet = ff_raw_write_packet,
+ .flags = AVFMT_NOTIMESTAMPS,
+};
+#endif
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 a90c168..201a3e0 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;
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..5e4981a
--- a/dev/null
+++ b/libavformat/realtextdec.c
@@ -0,0 +1,153 @@
+/*
+ * 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)
+{
+ const unsigned char *ptr = p->buf;
+
+ if (AV_RB24(ptr) == 0xEFBBBF)
+ ptr += 3; /* skip UTF-8 BOM */
+ return !av_strncasecmp(ptr, "<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
+
+ 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 (!url_feof(s->pb)) {
+ AVPacket *sub;
+ const int64_t pos = avio_tell(s->pb) - (c != 0);
+ int n = ff_smil_extract_next_chunk(s->pb, &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..6d4c8c5
--- a/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 (url_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/riff.c b/libavformat/riff.c
index 2668d19..849c1bf 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') },
@@ -33,7 +36,12 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_H264, MKTAG('x', '2', '6', '4') },
{ AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
{ AV_CODEC_ID_H264, MKTAG('D', 'A', 'V', 'C') },
+ { AV_CODEC_ID_H264, MKTAG('S', 'M', 'V', '2') },
{ AV_CODEC_ID_H264, MKTAG('V', 'S', 'S', 'H') },
+ { AV_CODEC_ID_H264, MKTAG('Q', '2', '6', '4') }, /* QNAP surveillance system */
+ { AV_CODEC_ID_H264, MKTAG('V', '2', '6', '4') },
+ { AV_CODEC_ID_H264, MKTAG('G', 'A', 'V', 'C') }, /* GeoVision camera */
+ { AV_CODEC_ID_H264, MKTAG('U', 'M', 'S', 'V') },
{ 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') },
@@ -41,11 +49,11 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_H263, MKTAG('V', 'X', '1', 'K') },
{ AV_CODEC_ID_H263, MKTAG('Z', 'y', 'G', 'o') },
{ AV_CODEC_ID_H263, MKTAG('M', '2', '6', '3') },
+ { AV_CODEC_ID_H263, MKTAG('l', 's', 'v', 'm') },
{ 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') },
@@ -78,6 +86,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_MPEG4, MKTAG('G', 'E', 'O', 'X') },
/* flipped video */
{ AV_CODEC_ID_MPEG4, MKTAG('H', 'D', 'X', '4') },
+ { AV_CODEC_ID_MPEG4, MKTAG('D', 'M', '4', 'V') },
{ AV_CODEC_ID_MPEG4, MKTAG('D', 'M', 'K', '2') },
{ AV_CODEC_ID_MPEG4, MKTAG('D', 'I', 'G', 'I') },
{ AV_CODEC_ID_MPEG4, MKTAG('I', 'N', 'M', 'C') },
@@ -92,8 +101,11 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_MPEG4, MKTAG('G', 'E', 'O', 'V') },
/* Samsung SHR-6040 */
{ AV_CODEC_ID_MPEG4, MKTAG('S', 'I', 'P', 'P') },
+ { AV_CODEC_ID_MPEG4, MKTAG('S', 'M', '4', 'V') },
{ AV_CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'X') },
{ AV_CODEC_ID_MPEG4, MKTAG('D', 'r', 'e', 'X') },
+ { AV_CODEC_ID_MPEG4, MKTAG('Q', 'M', 'P', '4') }, /* QNAP Systems */
+ { AV_CODEC_ID_MPEG4, MKTAG('P', 'L', 'V', '1') }, /* Pelco DVR MPEG-4 */
{ AV_CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') },
{ AV_CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '3') },
{ AV_CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', 'G', '3') },
@@ -110,6 +122,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_MSMPEG4V1, MKTAG('M', 'P', '4', '1') },
{ AV_CODEC_ID_WMV1, MKTAG('W', 'M', 'V', '1') },
{ AV_CODEC_ID_WMV2, MKTAG('W', 'M', 'V', '2') },
+ { AV_CODEC_ID_WMV2, MKTAG('G', 'X', 'V', 'E') },
{ AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'd') },
{ AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', 'd') },
{ AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', '1') },
@@ -125,6 +138,10 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') },
{ AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', 's') },
{ AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', '1') },
+ { AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'i', 's') },
+ { AV_CODEC_ID_DVVIDEO, MKTAG('p', 'd', 'v', 'c') },
+ { AV_CODEC_ID_DVVIDEO, MKTAG('S', 'L', '2', '5') },
+ { AV_CODEC_ID_DVVIDEO, MKTAG('S', 'L', 'D', 'V') },
{ AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '1') },
{ AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '2') },
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', 'g', '2') },
@@ -144,6 +161,8 @@ const AVCodecTag ff_codec_bmp_tags[] = {
/* Matrox MPEG-2 intra-only */
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('M', '7', '0', '1') },
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', 'g', 'v') },
+ { AV_CODEC_ID_MPEG1VIDEO, MKTAG('B', 'W', '1', '0') },
+ { AV_CODEC_ID_MPEG1VIDEO, MKTAG('X', 'M', 'P', 'G') }, /* Xing MPEG intra only */
{ AV_CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') },
{ AV_CODEC_ID_MJPEG, MKTAG('L', 'J', 'P', 'G') },
{ AV_CODEC_ID_MJPEG, MKTAG('d', 'm', 'b', '1') },
@@ -158,7 +177,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 */
@@ -213,11 +232,16 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_RAWVIDEO, MKTAG('Y', 'U', 'V', '9') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('Y', 'V', 'U', '9') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('a', 'u', 'v', '2') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', 'V', 'Y', 'U') },
{ AV_CODEC_ID_FRWU, MKTAG('F', 'R', 'W', 'U') },
{ 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') },
@@ -252,8 +276,10 @@ 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') },
{ AV_CODEC_ID_FLASHSV, MKTAG('F', 'S', 'V', '1') },
{ AV_CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', '1') },
{ AV_CODEC_ID_TSCC, MKTAG('t', 's', 'c', 'c') },
@@ -269,6 +295,8 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_VC1IMAGE, MKTAG('W', 'V', 'P', '2') },
{ AV_CODEC_ID_LOCO, MKTAG('L', 'O', 'C', 'O') },
{ AV_CODEC_ID_WNV1, MKTAG('W', 'N', 'V', '1') },
+ { AV_CODEC_ID_WNV1, MKTAG('Y', 'U', 'V', '8') },
+ { AV_CODEC_ID_AASC, MKTAG('A', 'A', 'S', '4') },
{ AV_CODEC_ID_AASC, MKTAG('A', 'A', 'S', 'C') },
{ AV_CODEC_ID_INDEO2, MKTAG('R', 'T', '2', '1') },
{ AV_CODEC_ID_FRAPS, MKTAG('F', 'P', 'S', '1') },
@@ -282,6 +310,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_JPEG2000, MKTAG('M', 'J', '2', 'C') },
{ AV_CODEC_ID_JPEG2000, MKTAG('L', 'J', '2', 'C') },
{ AV_CODEC_ID_JPEG2000, MKTAG('L', 'J', '2', 'K') },
+ { AV_CODEC_ID_JPEG2000, MKTAG('I', 'P', 'J', '2') },
{ AV_CODEC_ID_VMNC, MKTAG('V', 'M', 'n', 'c') },
{ AV_CODEC_ID_TARGA, MKTAG('t', 'g', 'a', ' ') },
{ AV_CODEC_ID_PNG, MKTAG('M', 'P', 'N', 'G') },
@@ -297,15 +326,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_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') },
{ AV_CODEC_ID_TSCC2, MKTAG('T', 'S', 'C', '2') },
@@ -313,6 +347,8 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_CLLC, MKTAG('C', 'L', 'L', 'C') },
{ AV_CODEC_ID_MSS2, MKTAG('M', 'S', 'S', '2') },
{ AV_CODEC_ID_SVQ3, MKTAG('S', 'V', 'Q', '3') },
+ { AV_CODEC_ID_012V, MKTAG('0', '1', '2', 'v') },
+ { AV_CODEC_ID_012V, MKTAG('a', '1', '2', 'v') },
{ AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '2') },
{ AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '3') },
{ AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '4') },
@@ -332,12 +368,17 @@ 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 }, /* msn audio */
+ { AV_CODEC_ID_AMR_NB, 0x0038 }, /* rogue format number */
+ { AV_CODEC_ID_G723_1, 0x0042 },
{ AV_CODEC_ID_ADPCM_G726, 0x0045 },
{ AV_CODEC_ID_MP2, 0x0050 },
{ AV_CODEC_ID_MP3, 0x0055 },
@@ -347,9 +388,11 @@ const AVCodecTag ff_codec_wav_tags[] = {
{ AV_CODEC_ID_ADPCM_IMA_DK4, 0x0061 },
/* rogue format number */
{ AV_CODEC_ID_ADPCM_IMA_DK3, 0x0062 },
+ { AV_CODEC_ID_ADPCM_G726, 0x0064 },
{ 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 },
@@ -367,9 +410,14 @@ const AVCodecTag ff_codec_wav_tags[] = {
{ AV_CODEC_ID_AAC_LATM, 0x1602 },
{ AV_CODEC_ID_AC3, 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 },
+ { AV_CODEC_ID_XAN_DPCM, 0x594a },
+ { AV_CODEC_ID_G723_1, 0xA100 },
+ { AV_CODEC_ID_AAC, 0xA106 },
{ AV_CODEC_ID_SPEEX, 0xA109 },
{ AV_CODEC_ID_FLAC, 0xF1AC },
{ AV_CODEC_ID_ADPCM_SWF, ('S' << 8) + 'F' },
@@ -388,7 +436,9 @@ const AVMetadataConv ff_riff_info_conv[] = {
{ "INAM", "title" },
{ "IPRD", "album" },
{ "IPRT", "track" },
+ { "ITRK", "track" },
{ "ISFT", "encoder" },
+ { "ISMP", "timecode" },
{ "ITCH", "encoded_by" },
{ 0 },
};
diff --git a/libavformat/riff.h b/libavformat/riff.h
index f458f26..1bf437e 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,14 @@ 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 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(AVCodecContext *stream, int *au_rate, int *au_ssize, int *au_scale);
@@ -91,10 +91,7 @@ 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));
-}
+void ff_get_guid(AVIOContext *s, ff_asf_guid *g);
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..de8eb5f 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
*/
@@ -37,6 +37,13 @@ const AVCodecGuid ff_codec_wav_guids[] = {
{ AV_CODEC_ID_NONE }
};
+void 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));
+}
+
enum AVCodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid)
{
int i;
@@ -57,7 +64,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,12 +115,9 @@ 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_alloc_extradata(codec, cbSize))
return AVERROR(ENOMEM);
avio_read(pb, codec->extradata, codec->extradata_size);
size -= cbSize;
@@ -132,7 +139,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 +162,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 +197,23 @@ int ff_read_riff_info(AVFormatContext *s, int64_t size)
chunk_code = avio_rl32(pb);
chunk_size = avio_rl32(pb);
-
+ if (url_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 +228,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 +238,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 98e97c0..bcfe018 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
*/
@@ -39,10 +39,14 @@ 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 */
@@ -77,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 {
@@ -104,6 +110,10 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc)
// blkalign = 144 * enc->bit_rate/enc->sample_rate;
} 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
@@ -115,6 +125,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;
}
@@ -146,6 +158,11 @@ 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) {
+ hdrsize += 20;
+ 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;
@@ -197,7 +214,7 @@ void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc,
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);
@@ -257,7 +274,7 @@ void ff_riff_write_info_tag(AVIOContext *pb, const char *tag, const char *str)
static const char riff_tags[][5] = {
"IARL", "IART", "ICMS", "ICMT", "ICOP", "ICRD", "ICRP", "IDIM", "IDPI",
"IENG", "IGNR", "IKEY", "ILGT", "ILNG", "IMED", "INAM", "IPLT", "IPRD",
- "IPRT", "ISBJ", "ISFT", "ISHP", "ISRC", "ISRF", "ITCH",
+ "IPRT", "ITRK", "ISBJ", "ISFT", "ISHP", "ISMP", "ISRC", "ISRF", "ITCH",
{ 0 }
};
diff --git a/libavformat/rl2.c b/libavformat/rl2.c
index ab33aab..ff40064 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
*/
@@ -107,10 +107,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);
@@ -129,9 +125,7 @@ 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_alloc_extradata(st->codec, st->codec->extradata_size))
return AVERROR(ENOMEM);
if(avio_read(pb,st->codec->extradata,st->codec->extradata_size) !=
@@ -140,6 +134,11 @@ static av_cold int rl2_read_header(AVFormatContext *s)
/** 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;
@@ -233,7 +232,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 d61f569..b0876fe 100644
--- a/libavformat/rmdec.c
+++ b/libavformat/rmdec.c
@@ -2,29 +2,31 @@
* "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 "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"
@@ -84,11 +86,9 @@ static int rm_read_extradata(AVIOContext *pb, AVCodecContext *avctx, unsigned si
{
if (size >= 1<<24)
return -1;
- avctx->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!avctx->extradata)
+ if (ff_alloc_extradata(avctx, size))
return AVERROR(ENOMEM);
avctx->extradata_size = avio_read(pb, avctx->extradata, size);
- memset(avctx->extradata + avctx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
if (avctx->extradata_size != size)
return AVERROR(EIO);
return 0;
@@ -98,6 +98,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);
@@ -127,9 +128,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")
@@ -139,6 +143,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;
@@ -148,6 +154,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 */
@@ -157,7 +164,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 */
@@ -196,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;
@@ -222,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);
@@ -269,7 +285,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
case DEINT_ID_VBRF:
break;
default:
- av_log(NULL,0,"Unknown interleaver %X\n", ast->deint_id);
+ av_log(s, AV_LOG_ERROR, "Unknown interleaver %X\n", ast->deint_id);
return AVERROR_INVALIDDATA;
}
@@ -285,7 +301,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;
@@ -308,11 +324,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);
@@ -335,6 +378,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;
@@ -429,7 +475,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);
@@ -444,7 +490,7 @@ static int rm_read_header(AVFormatContext *s)
avio_skip(pb, tag_size - 8);
for(;;) {
- if (pb->eof_reached)
+ if (url_feof(pb))
return -1;
tag = avio_rl32(pb);
tag_size = avio_rb32(pb);
@@ -466,7 +512,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 */
@@ -490,12 +537,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'):
@@ -548,7 +597,7 @@ static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_
AVStream *st;
uint32_t state=0xFFFFFFFF;
- while(!pb->eof_reached){
+ while(!url_feof(pb)){
int len, num, i;
*pos= avio_tell(pb) - 3;
if(rm->remaining_len > 0){
@@ -615,8 +664,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;
@@ -629,34 +680,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;
@@ -665,12 +729,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;
@@ -721,11 +791,13 @@ ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb,
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) ||
@@ -811,13 +883,14 @@ ff_rm_retrieve_cache (AVFormatContext *s, AVIOContext *pb,
{
RMDemuxContext *rm = s->priv_data;
- assert (rm->audio_pkt_cnt > 0);
+ av_assert0 (rm->audio_pkt_cnt > 0);
if (ast->deint_id == DEINT_ID_VBRF ||
ast->deint_id == DEINT_ID_VBRS)
av_get_packet(pb, pkt, ast->sub_packet_lengths[ast->sub_packet_cnt - rm->audio_pkt_cnt]);
else {
- av_new_packet(pkt, st->codec->block_align);
+ if(av_new_packet(pkt, st->codec->block_align) < 0)
+ return AVERROR(ENOMEM);
memcpy(pkt->data, ast->pkt.data + st->codec->block_align * //FIXME avoid this
(ast->sub_packet_h * ast->audio_framesize / st->codec->block_align - rm->audio_pkt_cnt),
st->codec->block_align);
@@ -836,7 +909,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;
@@ -845,7 +918,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) {
@@ -864,11 +939,13 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
st = s->streams[i];
}
- if(len<0 || s->pb->eof_reached)
+ if(len<0 || url_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)
@@ -920,7 +997,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;
@@ -952,6 +1031,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"),
@@ -961,6 +1052,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 fba8feb..17192ff 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++) {
s->streams[n]->id = n;
codec = s->streams[n]->codec;
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 42b47f8..61a2316 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
*/
@@ -58,7 +58,7 @@ static int read_line(AVIOContext * pb, char* line, int bufsize)
break;
if (b == '\n') {
line[i] = '\0';
- return 0;
+ return url_feof(pb) ? -1 : 0;
}
line[i] = b;
}
@@ -168,9 +168,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;
}
@@ -220,11 +219,8 @@ 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 %i not supported yet!\n",
- audio_format);
- }
+ if (ast->codec->codec_id == AV_CODEC_ID_NONE)
+ avpriv_request_sample(s, "Audio format %i", audio_format);
avpriv_set_pts_info(ast, 32, 1, ast->codec->bit_rate);
} else {
for (i = 0; i < 3; i++)
@@ -252,10 +248,10 @@ 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,
+ if (3 != sscanf(line, "%"SCNd64" , %"SCNd64" ; %"SCNd64,
&offset, &video_size, &audio_size))
error = -1;
av_add_index_entry(vst, offset, i * rpl->frames_per_chunk,
@@ -287,7 +283,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..37e544a
--- a/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 AVPROBE_SCORE_EXTENSION;
+ return 0;
+}
+
+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. */
+
+ if (ff_alloc_extradata(codec, 32))
+ return AVERROR(ENOMEM);
+
+ start = avio_rl32(pb);
+
+ if (avio_read(s->pb, codec->extradata, 32) != 32)
+ return AVERROR_INVALIDDATA;
+
+ 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 (url_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 cc76f9a..ee679b6 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 89a6614..49909ee 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 f58f668..375ae2f 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
*/
diff --git a/libavformat/rtmppkt.h b/libavformat/rtmppkt.h
index 7121d7e..fb79fed 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 027f6f6..a4d7f0e 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
@@ -269,9 +269,6 @@ static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
*value = '\0';
value++;
- if (!field || !value)
- goto fail;
-
ff_amf_write_field_name(p, field);
} else {
goto fail;
@@ -318,7 +315,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;
@@ -1171,7 +1168,7 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt)
for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
tosend[i] = av_lfg_get(&rnd) >> 24;
- if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
+ if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
/* When the client wants to use RTMPE, we have to change the command
* byte to 0x06 which means to use encrypted data and we have to set
* the flash version to at least 9.0.115.0. */
@@ -1249,7 +1246,7 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt)
if (ret < 0)
return ret;
- if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
+ if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
/* Compute the shared secret key sent by the server and initialize
* the RC4 encryption. */
if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
@@ -1279,7 +1276,7 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt)
if (ret < 0)
return ret;
- if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
+ if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
/* Encrypt the signature to be send to the server. */
ff_rtmpe_encrypt_sig(rt->stream, tosend +
RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
@@ -1291,13 +1288,13 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt)
RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
return ret;
- if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
+ if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
/* Set RC4 keys for encryption and update the keystreams. */
if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
return ret;
}
} else {
- if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
+ if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
/* Compute the shared secret key sent by the server and initialize
* the RC4 encryption. */
if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
@@ -1315,7 +1312,7 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt)
RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
return ret;
- if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
+ if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
/* Set RC4 keys for encryption and update the keystreams. */
if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
return ret;
@@ -2272,7 +2269,7 @@ static int get_packet(URLContext *s, int for_header)
}
}
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;
@@ -2483,16 +2480,20 @@ reconnect:
fname = strchr(p + 1, '/');
if (!fname || (c && c < fname)) {
fname = p + 1;
- av_strlcpy(rt->app, path + 1, p - path);
+ av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
} else {
fname++;
- av_strlcpy(rt->app, path + 1, fname - path - 1);
+ av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
}
}
}
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;
}
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 3984489..fed4e57 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
*/
@@ -837,7 +837,7 @@ int ff_parse_fmtp(AVStream *stream, PayloadContext *data, const char *p,
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 6b16117..9321066 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
*/
diff --git a/libavformat/rtpdec_amr.c b/libavformat/rtpdec_amr.c
index fd18ff2..211cf17 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 7c893af..123894f 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
*/
diff --git a/libavformat/rtpdec_formats.h b/libavformat/rtpdec_formats.h
index e5f4ccb..9caeb5c 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
*/
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_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 5e0169b..be657c0 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
*/
diff --git a/libavformat/rtpdec_ilbc.c b/libavformat/rtpdec_ilbc.c
index 2e99734..2bd8614 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..80fe295 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
*/
diff --git a/libavformat/rtpdec_latm.c b/libavformat/rtpdec_latm.c
index 050595c..fdeff3a 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 bec5c7d..0ea5594 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..5b851c4 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
*/
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..ee8a48a 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
*/
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 2049e4f..887a65e 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
@@ -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 d330607..9fd361d 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
*/
@@ -96,7 +96,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;
}
@@ -126,9 +126,12 @@ static int rtp_write_header(AVFormatContext *s1)
// 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 (st->codec->flags & CODEC_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) {
diff --git a/libavformat/rtpenc.h b/libavformat/rtpenc.h
index 9d7340d..b0c9630 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
@@ -90,7 +90,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 10c4020..dea1f70 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_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..0493008 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
*/
diff --git a/libavformat/rtpenc_h264.c b/libavformat/rtpenc_h264.c
index 206d9ba..b6c16e1 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_jpeg.c b/libavformat/rtpenc_jpeg.c
index 04df658..7eb0e23 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 0f31539..a8cbd97 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])
@@ -280,6 +281,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);
@@ -327,19 +329,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 16b5d41..2abb36b 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"
@@ -89,7 +90,9 @@ const AVOption ff_rtsp_options[] = {
{ "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 },
+ { "stimeout", "timeout (in micro seconds) of socket 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 },
};
@@ -724,7 +727,7 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st)
s->ctx_flags |= AVFMTCTX_NOHEADER;
if (s->oformat && CONFIG_RTSP_MUXER) {
- int ret = ff_rtp_chain_mux_open(&rtsp_st->transport_priv, s, st,
+ int ret = ff_rtp_chain_mux_open((AVFormatContext **)&rtsp_st->transport_priv, s, st,
rtsp_st->rtp_handle,
RTSP_TCP_MAX_PACKET_SIZE,
rtsp_st->stream_index);
@@ -1216,7 +1219,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);
@@ -1327,10 +1330,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. */
@@ -1384,7 +1383,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;
@@ -1701,7 +1699,8 @@ redirect:
}
} else {
/* open the tcp connection */
- ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, NULL);
+ ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port,
+ "?timeout=%d", rt->stimeout);
if (ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,
&s->interrupt_callback, NULL) < 0) {
err = AVERROR(EIO);
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index c6f2ffa..2dc4b6c 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
@@ -75,7 +75,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
@@ -391,9 +391,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 -
diff --git a/libavformat/rtspcodes.h b/libavformat/rtspcodes.h
index 31ab336..4245e48 100644
--- a/libavformat/rtspcodes.h
+++ b/libavformat/rtspcodes.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
*/
diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c
index 43dcb47..3615226 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
*/
@@ -738,7 +738,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);
diff --git a/libavformat/rtspenc.c b/libavformat/rtspenc.c
index d8e5b0e..bea1831 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
*/
diff --git a/libavformat/samidec.c b/libavformat/samidec.c
new file mode 100644
index 0000000..2eaee6f
--- a/dev/null
+++ b/libavformat/samidec.c
@@ -0,0 +1,137 @@
+/*
+ * 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)
+{
+ const unsigned char *ptr = p->buf;
+
+ if (AV_RB24(ptr) == 0xEFBBBF)
+ ptr += 3; /* skip UTF-8 BOM */
+ return !strncmp(ptr, "<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;
+
+ 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 (!url_feof(s->pb)) {
+ AVPacket *sub;
+ const int64_t pos = avio_tell(s->pb) - (c != 0);
+ int is_sync, n = ff_smil_extract_next_chunk(s->pb, &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..fe7bd82 100644
--- a/libavformat/sapdec.c
+++ b/libavformat/sapdec.c
@@ -2,20 +2,20 @@
* 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
*/
diff --git a/libavformat/sapenc.c b/libavformat/sapenc.c
index 7e2bba7..9fc78a8 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
*/
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..36cd8a3
--- a/dev/null
+++ b/libavformat/sbgdec.c
@@ -0,0 +1,1511 @@
+/*
+ * 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 "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;
+
+ 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(&now0);
+ 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 66b31cc..f88cd27 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
*/
@@ -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)
- abort();
+ if (info.sinfo_stream > s->max_streams) {
+ av_log(h, AV_LOG_ERROR, "bad input data\n");
+ return AVERROR(EINVAL);
+ }
ret = ff_sctp_send(s->fd, buf + 2, size - 2, &info, MSG_EOR);
} else
ret = send(s->fd, buf, size, 0);
diff --git a/libavformat/sdp.c b/libavformat/sdp.c
index 186f83b..0124218 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
*/
@@ -438,7 +438,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)
@@ -575,6 +575,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:
av_strlcatf(buff, size, "a=rtpmap:%d opus/48000\r\n",
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 e17cdcc..07c3f79 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
*/
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 5643f33..a56568c 100644
--- a/libavformat/segafilm.c
+++ b/libavformat/segafilm.c
@@ -2,20 +2,20 @@
* Sega FILM Format (CPK) Demuxer
* 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)
@@ -86,8 +83,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)
@@ -111,19 +106,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
@@ -213,7 +203,7 @@ static int film_read_header(AVFormatContext *s)
for (i = 0; i < film->sample_count; i++) {
/* load the next sample record and transfer it to an internal struct */
if (avio_read(pb, scratch, 16) != 16) {
- av_free(film->sample_table);
+ av_freep(&film->sample_table);
return AVERROR(EIO);
}
film->sample_table[i].sample_offset =
@@ -250,11 +240,9 @@ 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];
@@ -268,43 +256,6 @@ static int film_read_packet(AVFormatContext *s,
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)
@@ -323,8 +274,7 @@ static int film_read_close(AVFormatContext *s)
{
FilmDemuxContext *film = s->priv_data;
- av_free(film->sample_table);
- av_free(film->stereo_buffer);
+ av_freep(&film->sample_table);
return 0;
}
diff --git a/libavformat/segment.c b/libavformat/segment.c
index d79a327..05e29d4 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -1,58 +1,122 @@
/*
- * 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 "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/timestamp.h"
+
+typedef struct SegmentListEntry {
+ int index;
+ double start_time, end_time;
+ int64_t start_pts;
+ int64_t offset_pts;
+ char filename[1024];
+ struct SegmentListEntry *next;
+} 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_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. */
- 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 *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
+ 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;
+
+ 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;
+
+ int is_first_pkt; ///< tells if it is the first packet in the segment
} 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)
{
@@ -66,68 +130,63 @@ static int segment_mux_init(AVFormatContext *s)
oc->oformat = seg->oformat;
oc->interrupt_callback = s->interrupt_callback;
+ 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;
}
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;
- 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));
-
- for (i = FFMAX(0, seg->number - seg->size);
- i < seg->number; i++) {
- avio_printf(seg->pb, "#EXTINF:%d,\n", (int)seg->time);
- av_get_frame_filename(buf, sizeof(buf), s->filename, i);
- avio_printf(seg->pb, "%s\n", buf);
+ 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);
}
-
- if (last)
- avio_printf(seg->pb, "#EXT-X-ENDLIST\n");
-fail:
- avio_closep(&seg->pb);
- return ret;
+ av_strlcpy(seg->cur_entry.filename, oc->filename, sizeof(seg->cur_entry.filename));
+ return 0;
}
static int segment_start(AVFormatContext *s, int write_header)
{
- SegmentContext *c = s->priv_data;
- AVFormatContext *oc = c->avf;
+ SegmentContext *seg = s->priv_data;
+ AVFormatContext *oc = seg->avf;
int err = 0;
if (write_header) {
avformat_free_context(oc);
- c->avf = NULL;
+ seg->avf = NULL;
if ((err = segment_mux_init(s)) < 0)
return err;
- oc = c->avf;
+ oc = seg->avf;
}
- if (c->wrap)
- c->number %= c->wrap;
-
- if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
- s->filename, c->number++) < 0)
- return AVERROR(EINVAL);
+ seg->segment_idx++;
+ 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)
@@ -141,21 +200,252 @@ static int segment_start(AVFormatContext *s, int write_header)
return err;
}
+ seg->is_first_pkt = 1;
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)
+ 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");
+
+ 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_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(sizeof(**times) * *nb_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(sizeof(**frames) * *nb_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;
@@ -176,31 +466,117 @@ 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;
+ 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)
- goto fail;
+ 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);
+ }
- for (i = 0; i < s->nb_streams; i++)
- seg->has_video +=
- (s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO);
+ 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->has_video > 1)
- av_log(s, AV_LOG_WARNING,
- "More than a single video stream present, "
- "expect issues decoding it.\n");
+ 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 ((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);
@@ -219,11 +595,8 @@ 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,
@@ -238,6 +611,10 @@ static int seg_write_header(AVFormatContext *s)
avio_close(oc->pb);
goto fail;
}
+ seg->is_first_pkt = 1;
+
+ 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);
@@ -246,20 +623,10 @@ 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:
if (ret) {
if (seg->list)
- avio_close(seg->pb);
+ avio_close(seg->list_pb);
if (seg->avf)
avformat_free_context(seg->avf);
}
@@ -271,52 +638,81 @@ 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;
+ int64_t end_pts = INT64_MAX, offset;
+ int start_frame = INT_MAX;
+ int ret;
- if (seg->has_video) {
- can_split = st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
- pkt->flags & AV_PKT_FLAG_KEY;
+ if (seg->times) {
+ end_pts = seg->segment_count < seg->nb_times ?
+ seg->times[seg->segment_count] : INT64_MAX;
+ } else if (seg->frames) {
+ start_frame = seg->segment_count <= seg->nb_frames ?
+ seg->frames[seg->segment_count] : INT_MAX;
+ } else {
+ 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 is_key:%d frame:%d\n",
+ pkt->stream_index, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &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->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))) {
+ 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;
- 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;
- }
- }
- }
+ seg->cur_entry.index = seg->segment_idx;
+ 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);
+ } else if (pkt->pts != AV_NOPTS_VALUE) {
+ seg->cur_entry.end_time =
+ FFMAX(seg->cur_entry.end_time, (double)(pkt->pts + pkt->duration) * av_q2d(st->time_base));
+ }
+
+ if (seg->is_first_pkt) {
+ av_log(s, AV_LOG_DEBUG, "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);
+ seg->is_first_pkt = 0;
}
+ 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(oc, pkt->stream_index, pkt, s);
fail:
+ if (pkt->stream_index == seg->reference_stream_index)
+ seg->frame_count++;
+
if (ret < 0) {
if (seg->list)
- avio_close(seg->pb);
+ avio_close(seg->list_pb);
avformat_free_context(oc);
}
@@ -327,27 +723,33 @@ 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_opt_free(seg);
+ av_freep(&seg->times);
+ av_freep(&seg->frames);
+
+ cur = seg->segment_list_entries;
+ while (cur) {
+ next = cur->next;
+ av_free(cur);
+ cur = next;
}
-fail:
- avio_close(seg->pb);
avformat_free_context(oc);
return ret;
}
@@ -355,16 +757,35 @@ 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 },
+ { "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_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_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_start_number", "set the sequence number of the first segment", OFFSET(segment_idx), 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 },
};
@@ -375,14 +796,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..8749ec1 100644
--- a/libavformat/sierravmd.c
+++ b/libavformat/sierravmd.c
@@ -2,20 +2,20 @@
* Sierra VMD Format Demuxer
* 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);
}
@@ -240,8 +250,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 +264,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 +302,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..c8b68ab 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,16 @@ 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);
+ avio_read(s->pb, pkt->data + 2 + c->gmcsize, size);
pkt->stream_index = 0;
c->curstrm = -1;
}else{
@@ -225,7 +232,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 5af5e50..527faf7 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
*/
@@ -110,7 +110,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);
@@ -124,7 +124,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"
@@ -140,10 +140,15 @@ static int smacker_read_header(AVFormatContext *s)
/* setup data */
if(smk->frames > 0xFFFFFF) {
av_log(s, AV_LOG_ERROR, "Too many frames: %i\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'));
@@ -158,7 +163,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;
@@ -180,6 +185,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) {
@@ -210,19 +217,16 @@ 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 %i 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);
@@ -246,7 +250,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 (url_feof(s->pb) || smk->cur_frame >= smk->frames)
return AVERROR_EOF;
/* if we demuxed all streams, pass another frame */
@@ -263,6 +267,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;
@@ -308,7 +314,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;
}
@@ -344,7 +350,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);
@@ -365,16 +371,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 623df71..38ac2fb 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
*/
@@ -56,7 +56,7 @@ static int smjpeg_read_header(AVFormatContext *s)
duration = avio_rb32(pb); // in msec
- while (!pb->eof_reached) {
+ while (!url_feof(pb)) {
htype = avio_rl32(pb);
switch (htype) {
case SMJPEG_TXT:
@@ -106,10 +106,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);
@@ -139,7 +139,7 @@ static int smjpeg_read_packet(AVFormatContext *s, AVPacket *pkt)
int64_t pos;
int ret;
- if (s->pb->eof_reached)
+ if (url_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 2fe01b1..fe18a95 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
*/
@@ -289,7 +289,11 @@ static int ism_write_header(AVFormatContext *s)
int ret = 0, i;
AVOutputFormat *oformat;
- mkdir(s->filename, 0777);
+ if (mkdir(s->filename, 0777) < 0) {
+ av_log(s, AV_LOG_ERROR, "mkdir failed\n");
+ ret = AVERROR(errno);
+ goto fail;
+ }
oformat = av_guess_format("ismv", NULL, NULL);
if (!oformat) {
@@ -316,7 +320,11 @@ static int ism_write_header(AVFormatContext *s)
goto fail;
}
snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%d)", s->filename, s->streams[i]->codec->bit_rate);
- mkdir(os->dirname, 0777);
+ if (mkdir(os->dirname, 0777) < 0) {
+ ret = AVERROR(errno);
+ av_log(s, AV_LOG_ERROR, "mkdir failed\n");
+ goto fail;
+ }
ctx = avformat_alloc_context();
if (!ctx) {
@@ -422,7 +430,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
};
@@ -565,7 +573,7 @@ static int ism_write_packet(AVFormatContext *s, AVPacket *pkt)
SmoothStreamingContext *c = s->priv_data;
AVStream *st = s->streams[pkt->stream_index];
OutputStream *os = &c->streams[pkt->stream_index];
- int64_t end_dts = (c->nb_fragments + 1) * c->min_frag_duration;
+ int64_t end_dts = (c->nb_fragments + 1LL) * c->min_frag_duration;
int ret;
if (st->first_dts == AV_NOPTS_VALUE)
diff --git a/libavformat/smush.c b/libavformat/smush.c
new file mode 100644
index 0000000..e9c1937
--- a/dev/null
+++ b/libavformat/smush.c
@@ -0,0 +1,238 @@
+/*
+ * LucasArts Smush demuxer
+ * Copyright (c) 2006 Cyril Zorin
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License 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 "avio.h"
+
+typedef struct {
+ int version;
+ int audio_stream_index;
+ int video_stream_index;
+} SMUSHContext;
+
+static int smush_read_probe(AVProbeData *p)
+{
+ if (((AV_RL32(p->buf) == MKTAG('S', 'A', 'N', 'M') &&
+ AV_RL32(p->buf + 8) == MKTAG('S', 'H', 'D', 'R')) ||
+ (AV_RL32(p->buf) == MKTAG('A', 'N', 'I', 'M') &&
+ AV_RL32(p->buf + 8) == MKTAG('A', 'H', 'D', 'R')))) {
+ return AVPROBE_SCORE_MAX;
+ }
+
+ return 0;
+}
+
+static int smush_read_header(AVFormatContext *ctx)
+{
+ SMUSHContext *smush = ctx->priv_data;
+ AVIOContext *pb = ctx->pb;
+ AVStream *vst, *ast;
+ uint32_t magic, nframes, size, subversion, i;
+ uint32_t width = 0, height = 0, got_audio = 0, read = 0;
+ uint32_t sample_rate, channels, palette[256];
+
+ magic = avio_rb32(pb);
+ avio_skip(pb, 4); // skip movie size
+
+ if (magic == MKBETAG('A', 'N', 'I', 'M')) {
+ if (avio_rb32(pb) != MKBETAG('A', 'H', 'D', 'R'))
+ return AVERROR_INVALIDDATA;
+
+ size = avio_rb32(pb);
+ if (size < 3 * 256 + 6)
+ return AVERROR_INVALIDDATA;
+
+ smush->version = 0;
+ subversion = avio_rl16(pb);
+ nframes = avio_rl16(pb);
+
+ avio_skip(pb, 2); // skip pad
+
+ for (i = 0; i < 256; i++)
+ palette[i] = avio_rb24(pb);
+
+ avio_skip(pb, size - (3 * 256 + 6));
+ } else if (magic == MKBETAG('S', 'A', 'N', 'M') ) {
+ if (avio_rb32(pb) != MKBETAG('S', 'H', 'D', 'R'))
+ return AVERROR_INVALIDDATA;
+
+ size = avio_rb32(pb);
+ if (size < 14)
+ return AVERROR_INVALIDDATA;
+
+ smush->version = 1;
+ subversion = avio_rl16(pb);
+ nframes = avio_rl32(pb);
+ avio_skip(pb, 2); // skip pad
+ width = avio_rl16(pb);
+ height = avio_rl16(pb);
+ avio_skip(pb, 2); // skip pad
+ avio_skip(pb, size - 14);
+
+ if (avio_rb32(pb) != MKBETAG('F', 'L', 'H', 'D'))
+ return AVERROR_INVALIDDATA;
+
+ size = avio_rb32(pb);
+ while (!got_audio && ((read + 8) < size)) {
+ uint32_t sig, chunk_size;
+
+ if (url_feof(pb))
+ return AVERROR_EOF;
+
+ sig = avio_rb32(pb);
+ chunk_size = avio_rb32(pb);
+ read += 8;
+ switch (sig) {
+ case MKBETAG('W', 'a', 'v', 'e'):
+ got_audio = 1;
+ sample_rate = avio_rl32(pb);
+ channels = avio_rl32(pb);
+ avio_skip(pb, chunk_size - 8);
+ read += chunk_size;
+ break;
+ case MKBETAG('B', 'l', '1', '6'):
+ case MKBETAG('A', 'N', 'N', 'O'):
+ avio_skip(pb, chunk_size);
+ read += chunk_size;
+ break;
+ default:
+ return AVERROR_INVALIDDATA;
+ break;
+ }
+ }
+
+ avio_skip(pb, size - read);
+ } else {
+ av_log(ctx, AV_LOG_ERROR, "Wrong magic\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ vst = avformat_new_stream(ctx, 0);
+ if (!vst)
+ return AVERROR(ENOMEM);
+
+ smush->video_stream_index = vst->index;
+
+ vst->start_time = 0;
+ vst->duration =
+ vst->nb_frames = nframes;
+ vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ vst->codec->codec_id = AV_CODEC_ID_SANM;
+ vst->codec->codec_tag = 0;
+ vst->codec->width = width;
+ vst->codec->height = height;
+
+ avpriv_set_pts_info(vst, 64, 66667, 1000000);
+
+ if (!smush->version) {
+ if (ff_alloc_extradata(vst->codec, 1024 + 2))
+ return AVERROR(ENOMEM);
+
+ AV_WL16(vst->codec->extradata, subversion);
+ for (i = 0; i < 256; i++)
+ AV_WL32(vst->codec->extradata + 2 + i * 4, palette[i]);
+ }
+
+ if (got_audio) {
+ ast = avformat_new_stream(ctx, 0);
+ if (!ast)
+ return AVERROR(ENOMEM);
+
+ smush->audio_stream_index = ast->index;
+
+ ast->start_time = 0;
+ ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ ast->codec->codec_id = AV_CODEC_ID_VIMA;
+ ast->codec->codec_tag = 0;
+ ast->codec->sample_rate = sample_rate;
+ ast->codec->channels = channels;
+
+ avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
+ }
+
+ return 0;
+}
+
+static int smush_read_packet(AVFormatContext *ctx, AVPacket *pkt)
+{
+ SMUSHContext *smush = ctx->priv_data;
+ AVIOContext *pb = ctx->pb;
+ int done = 0;
+
+ while (!done) {
+ uint32_t sig, size;
+
+ if (url_feof(pb))
+ return AVERROR_EOF;
+
+ sig = avio_rb32(pb);
+ size = avio_rb32(pb);
+
+ switch (sig) {
+ case MKBETAG('F', 'R', 'M', 'E'):
+ if (smush->version)
+ break;
+ if (av_get_packet(pb, pkt, size) < 0)
+ return AVERROR(EIO);
+
+ pkt->stream_index = smush->video_stream_index;
+ done = 1;
+ break;
+ case MKBETAG('B', 'l', '1', '6'):
+ if (av_get_packet(pb, pkt, size) < 0)
+ return AVERROR(EIO);
+
+ pkt->stream_index = smush->video_stream_index;
+ pkt->duration = 1;
+ done = 1;
+ break;
+ case MKBETAG('W', 'a', 'v', 'e'):
+ if (size < 13)
+ return AVERROR_INVALIDDATA;
+ if (av_get_packet(pb, pkt, size) < 13)
+ return AVERROR(EIO);
+
+ pkt->stream_index = smush->audio_stream_index;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ pkt->duration = AV_RB32(pkt->data);
+ if (pkt->duration == 0xFFFFFFFFu)
+ pkt->duration = AV_RB32(pkt->data + 8);
+ done = 1;
+ break;
+ default:
+ avio_skip(pb, size);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+AVInputFormat ff_smush_demuxer = {
+ .name = "smush",
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts Smush"),
+ .priv_data_size = sizeof(SMUSHContext),
+ .read_probe = smush_read_probe,
+ .read_header = smush_read_header,
+ .read_packet = smush_read_packet,
+};
diff --git a/libavformat/sol.c b/libavformat/sol.c
index 92599b1..77c754a 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 (url_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 3e5d2e3..e219d75 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;
@@ -77,21 +78,13 @@ static int sox_write_header(AVFormatContext *s)
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,6 +116,6 @@ 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,
};
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..6984350 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
*/
@@ -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 (url_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 c350f72..210d63f 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
*/
@@ -92,7 +92,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,
@@ -395,15 +395,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));
@@ -520,13 +520,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 */
@@ -552,5 +552,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..7f911bd 100644
--- a/libavformat/srtdec.c
+++ b/libavformat/srtdec.c
@@ -2,101 +2,164 @@
* 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;
+ const unsigned char *ptr = p->buf;
int i, v, num = 0;
if (AV_RB24(ptr) == 0xEFBBBF)
ptr += 3; /* skip UTF-8 BOM */
+ while (*ptr == '\r' || *ptr == '\n')
+ ptr++;
for (i=0; i<2; i++) {
- if (num == i && sscanf(ptr, "%*d:%*2d:%*2d%*1[,.]%*3d --> %*d:%*2d:%*2d%*1[,.]%3d", &v) == 1)
+ if ((num == i || num + 1 == 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;
+ ptr += ff_subtitles_next_line(ptr);
}
return 0;
}
+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++) {
+ 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 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;
+
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 (!url_feof(s->pb)) {
+ ff_subtitles_read_chunk(s->pb, &buf);
+
+ if (buf.len) {
+ int64_t pos = avio_tell(s->pb);
+ 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 int srt_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ SRTContext *srt = s->priv_data;
+ return ff_subtitles_queue_read_packet(&srt->q, pkt);
}
-static inline int is_eol(char c)
+static int srt_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
{
- return c == '\r' || c == '\n';
+ 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_packet(AVFormatContext *s, AVPacket *pkt)
+static int srt_read_close(AVFormatContext *s)
{
- 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;
+ 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..b43504b
--- a/dev/null
+++ b/libavformat/srtenc.c
@@ -0,0 +1,115 @@
+/*
+ * 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 &&
+ avf->streams[0]->codec->codec_id != AV_CODEC_ID_SRT) {
+ 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;
+ int write_ts = avf->streams[0]->codec->codec_id != AV_CODEC_ID_SRT;
+
+ if (write_ts) {
+ 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);
+ if (write_ts)
+ 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/subtitles.c b/libavformat/subtitles.c
new file mode 100644
index 0000000..fce2bf1
--- a/dev/null
+++ b/libavformat/subtitles.c
@@ -0,0 +1,283 @@
+/*
+ * 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 "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+
+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_chunk(AVIOContext *pb, AVBPrint *buf, char *c)
+{
+ int i = 0;
+ char end_chr;
+
+ if (!*c) // cached char?
+ *c = avio_r8(pb);
+ if (!*c)
+ return 0;
+
+ end_chr = *c == '<' ? '>' : '<';
+ do {
+ av_bprint_chars(buf, *c, 1);
+ *c = avio_r8(pb);
+ 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_chunk(AVIOContext *pb, 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 = avio_r8(pb);
+
+ 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++;
+ }
+}
diff --git a/libavformat/subtitles.h b/libavformat/subtitles.h
new file mode 100644
index 0000000..b5a96ec
--- a/dev/null
+++ b/libavformat/subtitles.h
@@ -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
+ */
+
+#ifndef AVFORMAT_SUBTITLES_H
+#define AVFORMAT_SUBTITLES_H
+
+#include <stdint.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
+};
+
+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_chunk(AVIOContext *pb, 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 Read a subtitles chunk.
+ *
+ * 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 pb 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_chunk(AVIOContext *pb, 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;
+}
+
+#endif /* AVFORMAT_SUBTITLES_H */
diff --git a/libavformat/subviewer1dec.c b/libavformat/subviewer1dec.c
new file mode 100644
index 0000000..1b831b7
--- a/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 (!url_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..9e645d2
--- a/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 (!url_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/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 79c3c1d..c1667b3 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;
@@ -76,6 +132,13 @@ typedef struct SWFContext {
int tag;
AVFifoBuffer *audio_fifo;
AVCodecContext *audio_enc, *video_enc;
+#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..54e0f6d 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 (url_feof(pb))
+ return AVERROR_EOF;
tag = avio_rl16(pb);
len = tag & 0x3f;
@@ -61,6 +63,39 @@ static int swf_probe(AVProbeData *p)
return 0;
}
+#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 +103,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 +138,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 +171,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 +202,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 +210,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 +220,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 +270,132 @@ 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);
+
+ 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;
+ }
+ st->codec->width = width;
+ st->codec->height = height;
+
+ if ((res = av_new_packet(pkt, out_len - colormapsize * colormapbpp)) < 0)
+ goto bitmap_end;
+ pkt->pos = pos;
+ pkt->stream_index = st->index;
+
+ switch (bmp_fmt) {
+ case 3:
+ st->codec->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:
+ st->codec->pix_fmt = AV_PIX_FMT_RGB555;
+ break;
+ case 5:
+ st->codec->pix_fmt = alpha_bmp ? AV_PIX_FMT_ARGB : AV_PIX_FMT_0RGB;
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ 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 +427,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;
@@ -233,13 +453,29 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
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 +483,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 be2e5cd..8d9cf0c 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)
@@ -425,7 +430,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 */
@@ -454,7 +459,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)
@@ -484,8 +489,10 @@ static int swf_write_trailer(AVFormatContext *s)
enc = s->streams[i]->codec;
if (enc->codec_type == AVMEDIA_TYPE_VIDEO)
video_enc = enc;
- else
+ else {
av_fifo_free(swf->audio_fifo);
+ swf->audio_fifo = NULL;
+ }
}
put_swf_tag(s, TAG_END);
@@ -498,8 +505,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..2ed8a1e 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 (!url_feof(pb)) {
enum TAKMetaDataType type;
int size;
@@ -71,16 +79,27 @@ 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);
- 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 +107,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 +152,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 +180,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 cbd5142..634d99d 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -2,24 +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"
#include "os_support.h"
@@ -29,22 +31,43 @@
#endif
typedef struct TCPContext {
+ const AVClass *class;
int fd;
+ int listen;
+ int open_timeout;
+ int rw_timeout;
+ int listen_timeout;
} TCPContext;
+#define OFFSET(x) offsetof(TCPContext, x)
+#define D AV_OPT_FLAG_DECODING_PARAM
+#define E AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+{"listen", "listen on port instead of connecting", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E },
+{"timeout", "timeout of socket i/o operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
+{"listen_timeout", "connection awaiting timeout", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
+{NULL}
+};
+
+static const AVClass tcp_context_class = {
+ .class_name = "tcp",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
/* return non zero if error */
static int tcp_open(URLContext *h, const char *uri, int flags)
{
struct addrinfo hints = { 0 }, *ai, *cur_ai;
int port, fd = -1;
TCPContext *s = h->priv_data;
- int listen_socket = 0;
const char *p;
char buf[256];
int ret;
- int timeout = 100, listen_timeout = -1;
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);
@@ -57,18 +80,22 @@ 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))
- listen_socket = 1;
+ s->listen = 1;
if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
- timeout = strtol(buf, NULL, 10);
+ s->rw_timeout = strtol(buf, NULL, 10);
}
if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) {
- listen_timeout = strtol(buf, NULL, 10);
+ 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);
- if (listen_socket)
+ if (s->listen)
hints.ai_flags |= AI_PASSIVE;
if (!hostname[0])
ret = getaddrinfo(NULL, portstr, &hints, &ai);
@@ -92,15 +119,15 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
goto fail;
}
- if (listen_socket) {
+ if (s->listen) {
if ((fd = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
- listen_timeout, h)) < 0) {
+ s->listen_timeout, h)) < 0) {
ret = fd;
goto fail1;
}
} else {
if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
- timeout * 100, h, !!cur_ai->ai_next)) < 0) {
+ s->open_timeout / 1000, h, !!cur_ai->ai_next)) < 0) {
if (ret == AVERROR_EXIT)
goto fail1;
@@ -136,8 +163,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);
@@ -150,8 +177,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, 0);
@@ -196,5 +223,6 @@ URLProtocol ff_tcp_protocol = {
.url_get_file_handle = tcp_get_file_handle,
.url_shutdown = tcp_shutdown,
.priv_data_size = sizeof(TCPContext),
+ .priv_data_class = &tcp_context_class,
.flags = URL_PROTOCOL_FLAG_NETWORK,
};
diff --git a/libavformat/tedcaptionsdec.c b/libavformat/tedcaptionsdec.c
new file mode 100644
index 0000000..68063fa
--- a/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..12ea0ea
--- a/dev/null
+++ b/libavformat/tee.c
@@ -0,0 +1,498 @@
+/*
+ * 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;
+ }
+ *pkt = new_pkt;
+
+ bsf_ctx = bsf_ctx->next;
+ }
+
+ 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));
+ }
+
+ 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 = ret_all;
+ 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..3717b8f 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
*/
@@ -41,7 +41,7 @@ typedef struct ThpDemuxContext {
unsigned char components[16];
AVStream* vst;
int has_audio;
- int audiosize;
+ unsigned audiosize;
} ThpDemuxContext;
@@ -59,6 +59,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 +72,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. */
@@ -107,6 +110,8 @@ static int thp_read_header(AVFormatContext *s)
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,13 +147,13 @@ 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);
diff --git a/libavformat/tiertexseq.c b/libavformat/tiertexseq.c
index 45300f9..917a331 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
*/
diff --git a/libavformat/tls.c b/libavformat/tls.c
index 1baecf4..5da82db7 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
*/
@@ -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;
@@ -147,9 +173,12 @@ static int tls_open(URLContext *h, const char *uri, int flags)
struct addrinfo hints = { 0 }, *ai = NULL;
const char *proxy_path;
int use_proxy;
+ const char *p = strchr(uri, '?');
ff_tls_init();
+ if(p && av_find_info_tag(buf, sizeof(buf), "listen", p))
+ c->listen = 1;
if (c->listen)
snprintf(opts, sizeof(opts), "?listen=1");
@@ -188,8 +217,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);
@@ -207,7 +240,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);
@@ -258,8 +292,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));
@@ -275,7 +312,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..8be4dbf 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 (url_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..3afb9b2 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 (url_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 5897881..194945b 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
*/
@@ -48,6 +48,7 @@ static int txd_read_header(AVFormatContext *s) {
st->codec->time_base.den = 5;
st->codec->time_base.num = 1;
/* the parameters will be extracted from the compressed bitstream */
+
return 0;
}
@@ -61,7 +62,7 @@ next_chunk:
chunk_size = avio_rl32(pb);
marker = avio_rl32(pb);
- if (s->pb->eof_reached)
+ if (url_feof(s->pb))
return AVERROR_EOF;
if (marker != TXD_MARKER && marker != TXD_MARKER2) {
av_log(s, AV_LOG_ERROR, "marker does not match\n");
@@ -69,17 +70,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..3c0d6bf 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,87 @@
#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_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
+
typedef struct {
+ const AVClass *class;
int udp_fd;
int ttl;
int buffer_size;
int is_multicast;
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;
} 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", "Socket 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 },
+{"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 },
+{"ttl", "Set the time to live value (for multicast only)", OFFSET(ttl), AV_OPT_TYPE_INT, {.i64 = 16}, 0, INT_MAX, E },
+{"connect", "Should connect() 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", "In read mode: if no data arrived in more than this time interval, raise error", 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 void log_net_error(void *ctx, int level, const char* prefix)
{
@@ -317,6 +373,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 +435,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 +532,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,6 +547,17 @@ 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);
}
@@ -440,7 +565,7 @@ static int udp_open(URLContext *h, const char *uri, int flags)
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 +573,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 +593,17 @@ 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);
+ }
+ /* 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,7 +620,7 @@ 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;
@@ -566,10 +708,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_free(s->fifo);
for (i = 0; i < num_include_sources; i++)
av_freep(&include_sources[i]);
for (i = 0; i < num_exclude_sources; i++)
@@ -581,6 +756,50 @@ static int udp_read(URLContext *h, uint8_t *buf, int size)
{
UDPContext *s = h->priv_data;
int ret;
+ int avail, nonblock = h->flags & AVIO_FLAG_NONBLOCK;
+
+#if HAVE_PTHREAD_CANCEL
+ 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 +807,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;
}
@@ -615,10 +835,22 @@ static int udp_write(URLContext *h, const uint8_t *buf, int size)
static int udp_close(URLContext *h)
{
UDPContext *s = h->priv_data;
+ int ret;
if (s->is_multicast && (h->flags & AVIO_FLAG_READ))
udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr);
closesocket(s->udp_fd);
+#if HAVE_PTHREAD_CANCEL
+ if (s->thread_started) {
+ 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_free(s->fifo);
return 0;
}
@@ -630,5 +862,6 @@ 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,
};
diff --git a/libavformat/unix.c b/libavformat/unix.c
index ab57c68..0e61318 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 eeda1f0..47e1584 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 c27d079..686fe29 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
*/
@@ -48,6 +48,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 {
@@ -100,7 +101,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,
@@ -129,7 +130,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,
@@ -181,11 +182,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);
/**
@@ -271,7 +273,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 987d682..3bb837a 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
*/
@@ -23,6 +23,7 @@
#include "avio_internal.h"
#include "internal.h"
#include "libavcodec/internal.h"
+#include "libavcodec/raw.h"
#include "libavcodec/bytestream.h"
#include "libavutil/opt.h"
#include "libavutil/dict.h"
@@ -35,6 +36,7 @@
#include "libavutil/mathematics.h"
#include "libavutil/parseutils.h"
#include "libavutil/time.h"
+#include "libavutil/timestamp.h"
#include "riff.h"
#include "audiointerleave.h"
#include "url.h"
@@ -48,38 +50,115 @@
/**
* @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)
+
+static 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;
- int orig_pos = pkt->pos; // av_grow_packet might reset pos
+ 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 +168,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 +188,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)
@@ -138,19 +221,23 @@ int av_filename_number_test(const char *filename)
return filename && (av_get_frame_filename(buf, sizeof(buf), filename, 1)>=0);
}
-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
+ nodat = 1;
}
fmt = NULL;
@@ -160,44 +247,43 @@ AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score
score = 0;
if (fmt1->read_probe) {
score = fmt1->read_probe(&lpd);
+ if(fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions))
+ score = FFMAX(score, nodat ? AVPROBE_SCORE_EXTENSION / 2 - 1 : 1);
} else if (fmt1->extensions) {
if (av_match_ext(lpd.filename, fmt1->extensions)) {
score = AVPROBE_SCORE_EXTENSION;
}
}
- if (score > *score_max) {
- *score_max = score;
+ if (score > score_max) {
+ score_max = score;
fmt = fmt1;
- }else if (score == *score_max)
+ }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)
+ 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);
}
-static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeData *pd, int score)
+static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeData *pd)
{
static const struct {
const char *name; enum AVCodecID id; enum AVMediaType type;
@@ -207,14 +293,16 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeDa
{ "dts" , AV_CODEC_ID_DTS , AVMEDIA_TYPE_AUDIO },
{ "eac3" , AV_CODEC_ID_EAC3 , AVMEDIA_TYPE_AUDIO },
{ "h264" , AV_CODEC_ID_H264 , 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",
pd->buf_size, MAX_PROBE_PACKETS - st->probe_packets, fmt->name, score);
@@ -226,29 +314,45 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeDa
}
}
}
- return !!fmt;
+ return score;
}
/************************************************************/
/* input media file */
-/** size of probe buffer, for guessing file type from file contents */
-#define PROBE_BUF_MIN 2048
-#define PROBE_BUF_MAX (1<<20)
+int av_demuxer_open(AVFormatContext *ic){
+ int err;
-int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
+ 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;
+}
+
+
+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 : "", NULL, -offset };
unsigned char *buf = NULL;
- int ret = 0, probe_size;
+ uint8_t *mime_type;
+ int ret = 0, probe_size, buf_offset = 0;
+ int score = 0;
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) {
+ av_log(logctx, AV_LOG_ERROR,
+ "Specified probe size value %u cannot be < %u\n", max_probe_size, PROBE_BUF_MIN);
return AVERROR(EINVAL);
}
@@ -256,14 +360,20 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
return AVERROR(EINVAL);
}
+ 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);
+ }
+
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;
- int buf_offset = (probe_size == PROBE_BUF_MIN) ? 0 : probe_size>>1;
if (probe_size < offset) {
continue;
}
+ score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0;
/* read probe data */
if ((ret = av_reallocp(&buf, probe_size + AVPROBE_PADDING_SIZE)) < 0)
@@ -277,7 +387,7 @@ 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_size = buf_offset += ret;
pd.buf = &buf[offset];
memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE);
@@ -285,10 +395,10 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
/* guess file format */
*fmt = av_probe_input_format2(&pd, 1, &score);
if(*fmt){
- if(score <= AVPROBE_SCORE_MAX/4){ //this can only be true in the last iteration
- av_log(logctx, AV_LOG_WARNING, "Format detected only with low score of %d, misdetection possible!\n", score);
+ if(score <= AVPROBE_SCORE_RETRY){ //this can only be true in the last iteration
+ av_log(logctx, AV_LOG_WARNING, "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);
+ av_log(logctx, AV_LOG_DEBUG, "Format %s probed with size=%d and score=%d\n", (*fmt)->name, probe_size, score);
}
}
@@ -298,37 +408,47 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
}
/* rewind. reuse probe buffer to avoid seeking */
- if ((ret = ffio_rewind_with_probe_data(pb, buf, pd.buf_size)) < 0)
- av_free(buf);
+ ret = ffio_rewind_with_probe_data(pb, &buf, pd.buf_size);
- 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;
}
+
/* 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->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->probesize);
}
static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
@@ -348,7 +468,7 @@ 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++)
@@ -373,6 +493,10 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma
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;
@@ -384,6 +508,8 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma
if ((ret = init_input(s, filename, &tmp)) < 0)
goto fail;
+ s->probe_score = ret;
+ avio_skip(s->pb, s->skip_initial_bytes);
/* check filename in case an image number is expected */
if (s->iformat->flags & AVFMT_NEEDNUMBER) {
@@ -414,19 +540,24 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma
if (s->pb)
ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
- 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;
@@ -450,38 +581,66 @@ 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, "nothing to probe for stream %d\n",
+ 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_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;
@@ -498,16 +657,11 @@ 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);
@@ -528,6 +682,7 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
if ((err = probe_codec(s, st, NULL)) < 0)
return err;
}
+ av_assert0(st->request_probe <= 0);
}
continue;
}
@@ -541,22 +696,25 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
continue;
}
- st= s->streams[pkt->stream_index];
+ if(!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA))
+ av_packet_merge_side_data(pkt);
- 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(pkt->stream_index >= (unsigned)s->nb_streams){
+ av_log(s, AV_LOG_ERROR, "Invalid stream index %d\n", pkt->stream_index);
+ continue;
}
- if(!pktl && (st->codec->codec_id != AV_CODEC_ID_PROBE ||
- !st->probe_packets))
+ st= s->streams[pkt->stream_index];
+ 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);
@@ -567,8 +725,27 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
}
}
+#if FF_API_READ_PACKET
+int av_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ return ff_read_packet(s, pkt);
+}
+#endif
+
+
/**********************************************************/
+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;
+}
+
/**
* Get the number of samples of an audio frame. Return -1 on error.
*/
@@ -587,6 +764,13 @@ int ff_get_audio_frame_size(AVCodecContext *enc, int size, int mux)
if (enc->frame_size > 1)
return enc->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(!mux && enc->bit_rate>0 && size>0 && enc->sample_rate>0 && enc->block_align>1) {
+ if (enc->codec_id == AV_CODEC_ID_WMAV1 || enc->codec_id == AV_CODEC_ID_WMAV2)
+ return ((int64_t)size * 8 * enc->sample_rate) / enc->bit_rate;
+ }
+
return -1;
}
@@ -603,9 +787,9 @@ void ff_compute_frame_duration(int *pnum, int *pden, AVStream *st,
*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;
@@ -637,41 +821,161 @@ void ff_compute_frame_duration(int *pnum, int *pden, AVStream *st,
}
}
-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->parse_queue_end)
+ return s->packet_buffer;
+ return NULL;
+}
+
+static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index)
+{
+ if (s->correct_ts_overflow && st->pts_wrap_bits < 63 &&
+ st->pts_wrap_reference == AV_NOPTS_VALUE && st->first_dts != AV_NOPTS_VALUE) {
+ int i;
+
+ // reference time stamp should be 60 s before first time stamp
+ int64_t pts_wrap_reference = st->first_dts - 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
+ int pts_wrap_behavior = (st->first_dts < (1LL<<st->pts_wrap_bits) - (1LL<<st->pts_wrap_bits-3)) ||
+ (st->first_dts < (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;
+
+ AVProgram *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;
+ }
+ return 0;
}
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->parse_queue ? s->parse_queue : s->packet_buffer;
+ 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)
+ if(st->first_dts != AV_NOPTS_VALUE || dts == AV_NOPTS_VALUE || st->cur_dts == AV_NOPTS_VALUE || is_relative(dts))
return;
- st->first_dts= dts - st->cur_dts;
+ delay = st->codec->has_b_frames;
+ st->first_dts= dts - (st->cur_dts - RELATIVE_TS_BASE);
st->cur_dts= dts;
+ shift = st->first_dts - RELATIVE_TS_BASE;
- for(; pktl; pktl= pktl->next){
+ for (i=0; i<MAX_REORDER_DELAY+1; i++)
+ pts_buffer[i] = AV_NOPTS_VALUE;
+
+ if (is_relative(pts))
+ pts += shift;
+
+ for(; pktl; pktl= get_next_pkt(s, st, pktl)){
if(pktl->pkt.stream_index != stream_index)
continue;
- //FIXME think more about this check
- if(pktl->pkt.pts != AV_NOPTS_VALUE && pktl->pkt.pts == pktl->pkt.dts)
- pktl->pkt.pts += st->first_dts;
+ if(is_relative(pktl->pkt.pts))
+ pktl->pkt.pts += shift;
- if(pktl->pkt.dts != AV_NOPTS_VALUE)
- pktl->pkt.dts += st->first_dts;
+ if(is_relative(pktl->pkt.dts))
+ pktl->pkt.dts += shift;
if(st->start_time == AV_NOPTS_VALUE && pktl->pkt.pts != AV_NOPTS_VALUE)
st->start_time= pktl->pkt.pts;
+
+ if(pktl->pkt.pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY && has_decode_delay_been_guessed(st)){
+ pts_buffer[0]= pktl->pkt.pts;
+ for(i=0; i<delay && pts_buffer[i] > pts_buffer[i+1]; i++)
+ FFSWAP(int64_t, pts_buffer[i], pts_buffer[i+1]);
+ if(pktl->pkt.dts == AV_NOPTS_VALUE)
+ pktl->pkt.dts= pts_buffer[0];
+ }
+ }
+
+ if (update_wrap_reference(s, st, stream_index) && st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) {
+ // correct first time stamps to negative values
+ st->first_dts = wrap_timestamp(st, st->first_dts);
+ st->cur_dts = wrap_timestamp(st, st->cur_dts);
+ pkt->dts = wrap_timestamp(st, pkt->dts);
+ pkt->pts = wrap_timestamp(st, pkt->pts);
+ pts = wrap_timestamp(st, pts);
}
+
if (st->start_time == AV_NOPTS_VALUE)
st->start_time = pts;
}
@@ -679,38 +983,47 @@ 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->parse_queue ? s->parse_queue : s->packet_buffer;
+ int64_t cur_dts= RELATIVE_TS_BASE;
if(st->first_dts != AV_NOPTS_VALUE){
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 || pktl->pkt.duration)
break;
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->parse_queue ? s->parse_queue : s->packet_buffer;
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
+ if(pktl->pkt.pts == pktl->pkt.dts && (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;
}
@@ -726,6 +1039,10 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
if((s->flags & AVFMT_FLAG_IGNDTS) && pkt->pts != AV_NOPTS_VALUE)
pkt->dts= AV_NOPTS_VALUE;
+ if (st->codec->codec_id != AV_CODEC_ID_H264 && pc && pc->pict_type == AV_PICTURE_TYPE_B)
+ //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;
@@ -739,26 +1056,29 @@ 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 mpeg2 in mpeg-ps lack dts (issue171 / input_file.mpg)
// we take the conservative approach and discard both
// Note, if this is misbehaving for a H.264 file then possibly 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= pkt->pts= 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")) // 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) {
+ if (pkt->duration == 0) {
ff_compute_frame_duration(&num, &den, st, pc, 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);
-
- 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 */
@@ -775,10 +1095,8 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
if(pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts > pkt->dts)
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);
+ av_dlog(NULL, "IN delayed:%d pts:%s, dts:%s cur_dts:%s st:%d pc:%p duration:%d\n",
+ presentation_delayed, av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts), pkt->stream_index, pc, pkt->duration);
/* 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){
@@ -787,7 +1105,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
/* 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;
@@ -803,57 +1121,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) {
+ pkt->duration ) {
int duration = pkt->duration;
- if (!duration && st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
- ff_compute_frame_duration(&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;
- }
+ /* 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 = pkt->pts + duration;
}
}
- 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];
- if(st->codec->codec_id == AV_CODEC_ID_H264){ // we skipped it above so we try here
- update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts); // this should happen on the first packet
- }
- if(pkt->dts > st->cur_dts)
- st->cur_dts = pkt->dts;
}
+ if(st->codec->codec_id == AV_CODEC_ID_H264){ // we skipped it above so we try here
+ update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts, pkt); // this should happen on the first packet
+ }
+ 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;
@@ -887,6 +1188,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)) {
@@ -898,6 +1202,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;
@@ -936,19 +1241,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;
@@ -1028,17 +1332,17 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
if (cur_pkt.pts != AV_NOPTS_VALUE &&
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",
+ av_log(s, AV_LOG_WARNING, "Invalid timestamps stream=%d, pts=%s, dts=%s, size=%d\n",
cur_pkt.stream_index,
- cur_pkt.pts,
- cur_pkt.dts,
+ 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",
+ av_log(s, AV_LOG_DEBUG, "ff_read_packet stream=%d, pts=%s, dts=%s, size=%d, duration=%d, flags=%d\n",
cur_pkt.stream_index,
- cur_pkt.pts,
- cur_pkt.dts,
+ av_ts2str(cur_pkt.pts),
+ av_ts2str(cur_pkt.dts),
cur_pkt.size,
cur_pkt.duration,
cur_pkt.flags);
@@ -1046,12 +1350,17 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
if (st->need_parsing && !st->parser && !(s->flags & AVFMT_FLAG_NOPARSE)) {
st->parser = av_parser_init(st->codec->codec_id);
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) {
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;
}
}
@@ -1072,16 +1381,25 @@ 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(s->debug & FF_FDEBUG_TS)
- av_log(s, AV_LOG_DEBUG, "read_frame_internal stream=%d, pts=%"PRId64", dts=%"PRId64", size=%d, duration=%d, flags=%d\n",
+ av_log(s, AV_LOG_DEBUG, "read_frame_internal stream=%d, pts=%s, dts=%s, size=%d, duration=%d, flags=%d\n",
pkt->stream_index,
- pkt->pts,
- pkt->dts,
+ av_ts2str(pkt->pts),
+ av_ts2str(pkt->dts),
pkt->size,
pkt->duration,
pkt->flags);
@@ -1093,15 +1411,19 @@ 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) {
@@ -1109,22 +1431,40 @@ 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,
+ 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);
@@ -1140,6 +1480,30 @@ 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 (st->skip_samples) {
+ uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
+ if (p) {
+ AV_WL32(p, st->skip_samples);
+ av_log(s, AV_LOG_DEBUG, "demuxer injecting skip %d\n", st->skip_samples);
+ }
+ st->skip_samples = 0;
+ }
+
+ 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 */
@@ -1194,7 +1558,8 @@ void ff_read_frame_flush(AVFormatContext *s)
st->parser = NULL;
}
st->last_IP_pts = AV_NOPTS_VALUE;
- st->cur_dts = AV_NOPTS_VALUE; /* we set the current DTS to an unspecified origin */
+ if(st->first_dts == AV_NOPTS_VALUE) st->cur_dts = RELATIVE_TS_BASE;
+ else st->cur_dts = AV_NOPTS_VALUE; /* we set the current DTS to an unspecified origin */
st->probe_packets = MAX_PROBE_PACKETS;
@@ -1240,6 +1605,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) *
@@ -1254,7 +1628,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){
@@ -1278,6 +1652,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);
@@ -1324,6 +1699,15 @@ int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp,
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)
{
AVInputFormat *avif= s->iformat;
@@ -1336,7 +1720,7 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts
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;
@@ -1353,22 +1737,22 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts
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);
+ av_dlog(s, "using cached pos_max=0x%"PRIx64" pos_limit=0x%"PRIx64" dts_max=%s\n",
+ pos_max, pos_limit, av_ts2str(ts_max));
}
}
@@ -1380,54 +1764,83 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts
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, int flags, int64_t *ts_ret,
int64_t (*read_timestamp)(struct AVFormatContext *, int , 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){
@@ -1436,8 +1849,8 @@ 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){
@@ -1459,13 +1872,14 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
pos= pos_limit;
start_pos= pos;
- ts = read_timestamp(s, stream_index, &pos, INT64_MAX); //may pass pos_limit instead of -1
+ ts = ff_read_timestamp(s, stream_index, &pos, INT64_MAX, read_timestamp); //may pass pos_limit instead of -1
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");
@@ -1485,12 +1899,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;
}
@@ -1506,6 +1922,8 @@ static int seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, in
avio_seek(s->pb, pos, SEEK_SET);
+ s->io_repositioned = 1;
+
return 0;
}
@@ -1526,9 +1944,10 @@ static int seek_frame_generic(AVFormatContext *s,
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;
@@ -1545,9 +1964,13 @@ static int seek_frame_generic(AVFormatContext *s,
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);
@@ -1614,10 +2037,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;
}
@@ -1626,14 +2061,32 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int
{
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;
}
@@ -1643,10 +2096,19 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int
// 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
}
/*******************************************************/
@@ -1678,43 +2140,71 @@ 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++) {
st = ic->streams[i];
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, AV_TIME_BASE_Q);
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) {
+ }
+ if (ic->pb && (filesize = avio_size(ic->pb)) > 0 && ic->duration != AV_NOPTS_VALUE) {
/* compute the bitrate */
- ic->bit_rate = (double)filesize * 8.0 * AV_TIME_BASE /
+ double bitrate = (double)filesize * 8.0 * AV_TIME_BASE /
(double)ic->duration;
+ if (bitrate >= 0 && bitrate <= INT_MAX)
+ ic->bit_rate = bitrate;
}
- }
}
static void fill_all_stream_timings(AVFormatContext *ic)
@@ -1737,7 +2227,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 */
@@ -1763,16 +2253,21 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic)
if (filesize > 0) {
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)
+ 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)
@@ -1828,11 +2323,11 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
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);
@@ -1868,14 +2363,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);
@@ -1895,40 +2392,58 @@ 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)
+
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;
+ if (avctx->codec_id == AV_CODEC_ID_NONE)
+ FAIL("unknown codec");
+ 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, AVDictionary **options)
+static int try_decode_frame(AVFormatContext *s, AVStream *st, AVPacket *avpkt, AVDictionary **options)
{
const AVCodec *codec;
int got_picture = 1, ret = 0;
AVFrame *frame = avcodec_alloc_frame();
+ AVSubtitle subtitle;
AVPacket pkt = *avpkt;
if (!frame)
@@ -1937,8 +2452,7 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option
if (!avcodec_is_open(st->codec) && !st->info->found_decoder) {
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;
@@ -1967,7 +2481,7 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option
while ((pkt.size > 0 || (!pkt.data && got_picture)) &&
ret >= 0 &&
- (!has_codec_parameters(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;
@@ -1980,18 +2494,26 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option
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:
avcodec_free_frame(&frame);
return ret;
@@ -2030,6 +2552,7 @@ enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags)
default: return AV_CODEC_ID_NONE;
}
} else {
+ bps += 7;
bps >>= 3;
if (sflags & (1 << (bps - 1))) {
switch (bps) {
@@ -2053,10 +2576,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;
}
@@ -2093,8 +2631,8 @@ static void compute_chapters_end(AVFormatContext *s)
}
static int get_std_framerate(int i){
- if(i<60*12) return i*1001;
- else return ((const int[]){24,30,60,12,15})[i-60*12]*1000*12;
+ if(i<60*12) return (i+1)*1001;
+ else return ((const int[]){24,30,60,12,15,48})[i-60*12]*1000*12;
}
/*
@@ -2110,6 +2648,7 @@ static int tb_unreliable(AVCodecContext *c){
|| 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_H264
)
@@ -2117,28 +2656,74 @@ static int tb_unreliable(AVCodecContext *c){
return 0;
}
+#if FF_API_FORMAT_PARAMETERS
+int av_find_stream_info(AVFormatContext *ic)
+{
+ return avformat_find_stream_info(ic, NULL);
+}
+#endif
+
+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 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);
int orig_nb_streams = ic->nb_streams; // new streams might appear, no options for those
+ int flush_codecs = ic->probesize > 0;
+
+ if(ic->pb)
+ av_log(ic, AV_LOG_DEBUG, "File position before avformat_find_stream_info() is %"PRId64"\n", avio_tell(ic->pb));
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 h264 decoder will not extract SPS
* and PPS to extradata during multi-threaded decoding */
@@ -2151,7 +2736,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
: &thread_opt);
//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);
@@ -2161,6 +2746,9 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
}
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;
}
@@ -2179,7 +2767,7 @@ 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
@@ -2188,9 +2776,11 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
fps_analyze_framecount *= 2;
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( tb_unreliable(st->codec) && !st->avg_frame_rate.num
- && st->codec_info_nb_frames < fps_analyze_framecount
+ if( tb_unreliable(st->codec) && !(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)
@@ -2208,13 +2798,21 @@ 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) {
ret = count;
- av_log(ic, AV_LOG_DEBUG, "Probe buffer size limit %d reached\n", ic->probesize);
+ av_log(ic, AV_LOG_DEBUG, "Probe buffer size limit of %d bytes reached\n", ic->probesize);
+ for (i = 0; i < ic->nb_streams; i++)
+ if (!ic->streams[i]->r_frame_rate.num &&
+ ic->streams[i]->info->duration_count <= 1 &&
+ 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;
}
@@ -2226,43 +2824,18 @@ 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);
-
- ret = -1; /* we could not have all the codec parameters before EOF */
- 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;
}
@@ -2274,7 +2847,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
/* 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, "Non-increasing DTS in stream %d: "
+ 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,
st->info->fps_last_dts, st->codec_info_nb_frames, pkt->dts);
@@ -2301,23 +2874,70 @@ 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 reached\n");
+ }
+ 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 >= ic->max_analyze_duration) {
+ av_log(ic, AV_LOG_VERBOSE, "max_analyze_duration %d reached at %"PRId64" microseconds\n", ic->max_analyze_duration, t);
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
+ {
+ int64_t last = st->info->last_dts;
+
+ if( pkt->dts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && pkt->dts > last
+ && pkt->dts - (uint64_t)last < INT64_MAX){
+ double dts= (is_relative(pkt->dts) ? pkt->dts - RELATIVE_TS_BASE : pkt->dts) * av_q2d(st->time_base);
+ int64_t duration= pkt->dts - 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++) {
+ 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++;
+ // ignore the first 4 values, they might have some random jitter
+ if (st->info->duration_count > 3 && is_relative(pkt->dts) == is_relative(last))
+ st->info->duration_gcd = av_gcd(st->info->duration_gcd, duration);
+ }
+ if (pkt->dts != AV_NOPTS_VALUE)
+ st->info->last_dts = 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_malloc(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);
- memset(st->codec->extradata + i, 0, FF_INPUT_BUFFER_PADDING_SIZE);
}
}
@@ -2330,12 +2950,37 @@ 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, (options && i < orig_nb_streams ) ? &options[i] : NULL);
+ try_decode_frame(ic, st, pkt, (options && i < orig_nb_streams ) ? &options[i] : NULL);
st->codec_info_nb_frames++;
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];
@@ -2344,20 +2989,24 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
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(ff_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*/
@@ -2375,6 +3024,51 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
best_fps, 12*1001, INT_MAX);
}
}
+ // 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;
+
+ 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;
+ 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 && (!st->r_frame_rate.num || (double)num/(12*1001) < 1.01 * av_q2d(st->r_frame_rate)))
+ av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, 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= av_get_bits_per_sample(st->codec->codec_id);
@@ -2394,27 +3088,56 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
}
}
+ if(ic->probesize)
estimate_timings(ic, old_offset);
+ if (ret >= 0 && ic->nb_streams)
+ ret = -1; /* we could not have all the codec parameters before EOF */
+ 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++) {
- if (ic->streams[i]->codec)
+ st = ic->streams[i];
+ if (ic->streams[i]->codec && 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, "File position after avformat_find_stream_info() is %"PRId64"\n", avio_tell(ic->pb));
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;
}
@@ -2426,12 +3149,12 @@ int av_find_best_stream(AVFormatContext *ic,
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;
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;
@@ -2448,16 +3171,23 @@ int av_find_best_stream(AVFormatContext *ic,
if (st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED|AV_DISPOSITION_VISUAL_IMPAIRED))
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;
+ 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) {
@@ -2491,32 +3221,41 @@ int av_read_pause(AVFormatContext *s)
return AVERROR(ENOSYS);
}
+void ff_free_stream(AVFormatContext *s, AVStream *st){
+ av_assert0(s->nb_streams>0);
+ av_assert0(s->streams[ s->nb_streams-1 ] == st);
+
+ 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;
- AVStream *st;
+
+ if (!s)
+ return;
av_opt_free(s);
if (s->iformat && s->iformat->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];
- 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);
@@ -2527,7 +3266,7 @@ 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);
@@ -2535,10 +3274,23 @@ void avformat_free_context(AVFormatContext *s)
av_free(s);
}
+#if FF_API_CLOSE_INPUT_FILE
+void av_close_input_file(AVFormatContext *s)
+{
+ avformat_close_input(&s);
+}
+#endif
+
void avformat_close_input(AVFormatContext **ps)
{
- AVFormatContext *s = *ps;
- AVIOContext *pb = s->pb;
+ AVFormatContext *s;
+ AVIOContext *pb;
+
+ if (!ps || !*ps)
+ return;
+
+ s = *ps;
+ pb = s->pb;
if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
(s->flags & AVFMT_FLAG_CUSTOM_IO))
@@ -2558,15 +3310,28 @@ void avformat_close_input(AVFormatContext **ps)
avio_close(pb);
}
-AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c)
+#if FF_API_NEW_STREAM
+AVStream *av_new_stream(AVFormatContext *s, int id)
+{
+ AVStream *st = avformat_new_stream(s, NULL);
+ if (st)
+ st->id = id;
+ return st;
+}
+#endif
+
+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)
@@ -2575,6 +3340,7 @@ AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c)
av_free(st);
return NULL;
}
+ st->info->last_dts = AV_NOPTS_VALUE;
st->codec = avcodec_alloc_context3(c);
if (s->iformat) {
@@ -2588,9 +3354,11 @@ AVStream *avformat_new_stream(AVFormatContext *s, 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;
/* default pts setting is MPEG-like */
avpriv_set_pts_info(st, 33, 1, 90000);
@@ -2600,6 +3368,9 @@ AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c)
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;
@@ -2626,6 +3397,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;
}
@@ -2658,6 +3434,7 @@ void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int i
{
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);
@@ -2672,12 +3449,10 @@ void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int i
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,8 +3472,21 @@ 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))
- av_log(ctx, AV_LOG_INFO, "%s %-16s: %s\n", indent, tag->key, tag->value);
+ if(strcmp("language", tag->key)){
+ const char *p = tag->value;
+ av_log(ctx, AV_LOG_INFO, "%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");
+ }
}
}
}
@@ -2712,7 +3500,7 @@ static void dump_stream_format(AVFormatContext *ic, int i, int index, int is_out
int g = av_gcd(st->time_base.num, st->time_base.den);
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
avcodec_string(buf, sizeof(buf), st->codec, is_output);
- av_log(NULL, AV_LOG_INFO, " Stream #%d.%d", index, i);
+ av_log(NULL, AV_LOG_INFO, " Stream #%d:%d", index, i);
/* the pid is an important information, so we display it */
/* XXX: add a generic system */
if (flags & AVFMT_SHOW_IDS)
@@ -2728,13 +3516,17 @@ static void dump_stream_format(AVFormatContext *ic, int i, int index, int is_out
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){
if(st->avg_frame_rate.den && st->avg_frame_rate.num)
print_fps(av_q2d(st->avg_frame_rate), "fps");
+#if FF_API_R_FRAME_RATE
+ if(st->r_frame_rate.den && st->r_frame_rate.num)
+ print_fps(av_q2d(st->r_frame_rate), "tbr");
+#endif
if(st->time_base.den && st->time_base.num)
print_fps(1/av_q2d(st->time_base), "tbn");
if(st->codec->time_base.den && st->codec->time_base.num)
@@ -2784,8 +3576,9 @@ void av_dump_format(AVFormatContext *ic,
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;
@@ -2985,7 +3778,7 @@ void av_url_split(char *proto, int proto_size,
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;
if (proto_size > 0) proto[0] = 0;
@@ -3007,8 +3800,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
@@ -3017,9 +3813,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 '@' */
}
@@ -3088,6 +3885,14 @@ int ff_hex_to_data(uint8_t *data, const char *p)
return len;
}
+#if FF_API_SET_PTS_INFO
+void av_set_pts_info(AVStream *s, int pts_wrap_bits,
+ unsigned int pts_num, unsigned int pts_den)
+{
+ avpriv_set_pts_info(s, pts_wrap_bits, pts_num, pts_den);
+}
+#endif
+
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits,
unsigned int pts_num, unsigned int pts_den)
{
@@ -3099,10 +3904,11 @@ void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits,
av_log(NULL, AV_LOG_WARNING, "st:%d has too large timebase, reducing\n", s->index);
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", s->index);
+ av_log(NULL, AV_LOG_ERROR, "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;
}
@@ -3172,20 +3978,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(AVOutputFormat *ofmt, enum AVCodecID codec_id, int std_compliance)
@@ -3264,3 +4064,195 @@ 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;
+
+ if (st->codec->ticks_per_frame > 1) {
+ AVRational codec_fr = av_inv_q(st->codec->time_base);
+ AVRational avg_fr = st->avg_frame_rate;
+ codec_fr.den *= st->codec->ticks_per_frame;
+ 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 == '#') {
+ int sid;
+ char *endptr;
+ sid = strtol(spec + 1, &endptr, 0);
+ if (!*endptr)
+ return st->id == sid;
+ } else if (!*spec) /* empty specifier, matches everything */
+ return 1;
+
+ av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
+ return AVERROR(EINVAL);
+}
+
+void ff_generate_avci_extradata(AVStream *st)
+{
+ static const uint8_t avci100_1080p_extradata[] = {
+ // SPS
+ 0x00, 0x00, 0x00, 0x01, 0x67, 0x7a, 0x10, 0x29,
+ 0xb6, 0xd4, 0x20, 0x22, 0x33, 0x19, 0xc6, 0x63,
+ 0x23, 0x21, 0x01, 0x11, 0x98, 0xce, 0x33, 0x19,
+ 0x18, 0x21, 0x02, 0x56, 0xb9, 0x3d, 0x7d, 0x7e,
+ 0x4f, 0xe3, 0x3f, 0x11, 0xf1, 0x9e, 0x08, 0xb8,
+ 0x8c, 0x54, 0x43, 0xc0, 0x78, 0x02, 0x27, 0xe2,
+ 0x70, 0x1e, 0x30, 0x10, 0x10, 0x14, 0x00, 0x00,
+ 0x03, 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0xca,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // PPS
+ 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x33, 0x48,
+ 0xd0
+ };
+ static const uint8_t avci100_1080i_extradata[] = {
+ // SPS
+ 0x00, 0x00, 0x00, 0x01, 0x67, 0x7a, 0x10, 0x29,
+ 0xb6, 0xd4, 0x20, 0x22, 0x33, 0x19, 0xc6, 0x63,
+ 0x23, 0x21, 0x01, 0x11, 0x98, 0xce, 0x33, 0x19,
+ 0x18, 0x21, 0x03, 0x3a, 0x46, 0x65, 0x6a, 0x65,
+ 0x24, 0xad, 0xe9, 0x12, 0x32, 0x14, 0x1a, 0x26,
+ 0x34, 0xad, 0xa4, 0x41, 0x82, 0x23, 0x01, 0x50,
+ 0x2b, 0x1a, 0x24, 0x69, 0x48, 0x30, 0x40, 0x2e,
+ 0x11, 0x12, 0x08, 0xc6, 0x8c, 0x04, 0x41, 0x28,
+ 0x4c, 0x34, 0xf0, 0x1e, 0x01, 0x13, 0xf2, 0xe0,
+ 0x3c, 0x60, 0x20, 0x20, 0x28, 0x00, 0x00, 0x03,
+ 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0x94, 0x00,
+ // PPS
+ 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x33, 0x48,
+ 0xd0
+ };
+ static const uint8_t avci50_1080i_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, 0x6e, 0x61,
+ 0x87, 0x3e, 0x73, 0x4d, 0x98, 0x0c, 0x03, 0x06,
+ 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, 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,
+ 0x11
+ };
+ static const uint8_t avci100_720p_extradata[] = {
+ // SPS
+ 0x00, 0x00, 0x00, 0x01, 0x67, 0x7a, 0x10, 0x29,
+ 0xb6, 0xd4, 0x20, 0x2a, 0x33, 0x1d, 0xc7, 0x62,
+ 0xa1, 0x08, 0x40, 0x54, 0x66, 0x3b, 0x8e, 0xc5,
+ 0x42, 0x02, 0x10, 0x25, 0x64, 0x2c, 0x89, 0xe8,
+ 0x85, 0xe4, 0x21, 0x4b, 0x90, 0x83, 0x06, 0x95,
+ 0xd1, 0x06, 0x46, 0x97, 0x20, 0xc8, 0xd7, 0x43,
+ 0x08, 0x11, 0xc2, 0x1e, 0x4c, 0x91, 0x0f, 0x01,
+ 0x40, 0x16, 0xec, 0x07, 0x8c, 0x04, 0x04, 0x05,
+ 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03,
+ 0x00, 0x64, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // PPS
+ 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x31, 0x12,
+ 0x11
+ };
+ int size = 0;
+ const uint8_t *data = 0;
+ if (st->codec->width == 1920) {
+ if (st->codec->field_order == AV_FIELD_PROGRESSIVE) {
+ data = avci100_1080p_extradata;
+ size = sizeof(avci100_1080p_extradata);
+ } else {
+ data = avci100_1080i_extradata;
+ size = sizeof(avci100_1080i_extradata);
+ }
+ } else if (st->codec->width == 1440) {
+ data = avci50_1080i_extradata;
+ size = sizeof(avci50_1080i_extradata);
+ } else if (st->codec->width == 1280) {
+ data = avci100_720p_extradata;
+ size = sizeof(avci100_720p_extradata);
+ }
+ if (!size)
+ return;
+ av_freep(&st->codec->extradata);
+ if (ff_alloc_extradata(st->codec, size))
+ return;
+ memcpy(st->codec->extradata, data, size);
+}
diff --git a/libavformat/vc1test.c b/libavformat/vc1test.c
index 859188f..bf1bfe0 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,8 +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);
- st->codec->extradata_size = VC1_EXTRADATA_SIZE;
+ if (ff_alloc_extradata(st->codec, VC1_EXTRADATA_SIZE))
+ return AVERROR(ENOMEM);
avio_read(pb, st->codec->extradata, VC1_EXTRADATA_SIZE);
st->codec->height = avio_rl32(pb);
st->codec->width = avio_rl32(pb);
@@ -92,7 +92,7 @@ static int vc1t_read_packet(AVFormatContext *s,
int keyframe = 0;
uint32_t pts;
- if(pb->eof_reached)
+ if(url_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 791933f..8305438 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/avutil.h"
#define LIBAVFORMAT_VERSION_MAJOR 55
-#define LIBAVFORMAT_VERSION_MINOR 7
-#define LIBAVFORMAT_VERSION_MICRO 0
+#define LIBAVFORMAT_VERSION_MINOR 19
+#define LIBAVFORMAT_VERSION_MICRO 104
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \
@@ -52,4 +52,28 @@
#define FF_API_REFERENCE_DTS (LIBAVFORMAT_VERSION_MAJOR < 56)
#endif
+#ifndef FF_API_ALLOC_OUTPUT_CONTEXT
+#define FF_API_ALLOC_OUTPUT_CONTEXT (LIBAVFORMAT_VERSION_MAJOR < 56)
+#endif
+#ifndef FF_API_FORMAT_PARAMETERS
+#define FF_API_FORMAT_PARAMETERS (LIBAVFORMAT_VERSION_MAJOR < 56)
+#endif
+#ifndef FF_API_NEW_STREAM
+#define FF_API_NEW_STREAM (LIBAVFORMAT_VERSION_MAJOR < 56)
+#endif
+#ifndef FF_API_SET_PTS_INFO
+#define FF_API_SET_PTS_INFO (LIBAVFORMAT_VERSION_MAJOR < 56)
+#endif
+#ifndef FF_API_CLOSE_INPUT_FILE
+#define FF_API_CLOSE_INPUT_FILE (LIBAVFORMAT_VERSION_MAJOR < 56)
+#endif
+#ifndef FF_API_READ_PACKET
+#define FF_API_READ_PACKET (LIBAVFORMAT_VERSION_MAJOR < 56)
+#endif
+#ifndef FF_API_ASS_SSA
+#define FF_API_ASS_SSA (LIBAVFORMAT_VERSION_MAJOR < 56)
+#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..e0a1814
--- a/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 (url_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 (url_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 (url_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 d18eac2..29e9363 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 56936d7..f17a0c1 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 95e1a56..4e631e3 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..73a48db
--- a/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 (!url_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..4cd0a6d 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
*/
@@ -132,6 +132,11 @@ 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
@@ -158,7 +163,7 @@ static int vqf_read_header(AVFormatContext *s)
header_size -= len;
- } while (header_size >= 0);
+ } while (header_size >= 0 && !url_feof(s->pb));
switch (rate_flag) {
case -1:
@@ -215,9 +220,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);
diff --git a/libavformat/w64.c b/libavformat/w64.c
new file mode 100644
index 0000000..ef2d90a
--- a/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
--- a/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 a3471fd..202683b 100644
--- a/libavformat/wavdec.c
+++ b/libavformat/wavdec.c
@@ -6,25 +6,26 @@
* 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
*/
#include "libavutil/avassert.h"
#include "libavutil/dict.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
@@ -35,10 +36,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
@@ -49,25 +65,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 (url_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;
}
@@ -90,6 +108,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, 4);
+ }
+}
+
static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream **st)
{
AVIOContext *pb = s->pb;
@@ -103,7 +129,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);
@@ -165,7 +193,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],
@@ -220,6 +248,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);
@@ -235,7 +267,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 */
@@ -248,20 +280,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 (url_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");
@@ -298,22 +332,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;
}
}
@@ -326,11 +400,15 @@ 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 (!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;
@@ -349,23 +427,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 (!url_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)
@@ -375,16 +448,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;
}
@@ -406,7 +547,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) {
@@ -422,6 +577,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)"),
@@ -432,31 +600,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;
@@ -464,7 +618,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;
@@ -472,7 +626,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 */
@@ -480,38 +634,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 (!url_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;
+
+ 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);
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ } else if (!memcmp(guid, ff_w64_guid_fact, 16)) {
+ int64_t samples;
- avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ 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;
- size = find_guid(pb, guid_data);
- if (size < 0) {
- av_log(s, AV_LOG_ERROR, "could not find data guid\n");
- return AVERROR_INVALIDDATA;
+ 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 (url_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 86ed557..fea38cf 100644
--- a/libavformat/wavenc.c
+++ b/libavformat/wavenc.c
@@ -2,20 +2,26 @@
* 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>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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 +39,23 @@
#include "internal.h"
#include "riff.h"
+#define RF64_AUTO (-1)
+#define RF64_NEVER 0
+#define RF64_ALWAYS 1
+
typedef struct WAVMuxContext {
const AVClass *class;
int64_t data;
int64_t fact_pos;
+ int64_t ds64;
int64_t minpts;
int64_t maxpts;
int last_duration;
int write_bext;
+ int rf64;
} WAVMuxContext;
+#if CONFIG_WAV_MUXER
static inline void bwf_write_bext_string(AVFormatContext *s, const char *key, int maxlen)
{
AVDictionaryEntry *tag;
@@ -103,10 +116,24 @@ static int wav_write_header(AVFormatContext *s)
AVIOContext *pb = s->pb;
int64_t fmt;
- ffio_wfourcc(pb, "RIFF");
- avio_wl32(pb, 0); /* file length */
+ 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, 0); /* file length */
+ }
+
ffio_wfourcc(pb, "WAVE");
+ 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);
+ }
+
/* format header */
fmt = ff_start_tag(pb, "fmt ");
if (ff_put_wav_header(pb, s->streams[0]->codec) < 0) {
@@ -159,29 +186,63 @@ 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);
-
/* 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);
+ ff_end_tag(pb, wav->data);
+ 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);
}
@@ -193,6 +254,10 @@ 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 },
+ { "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" },
{ NULL },
};
@@ -218,3 +283,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) {
+ 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..657380a 100644
--- a/libavformat/wc3movie.c
+++ b/libavformat/wc3movie.c
@@ -2,20 +2,20 @@
* Wing Commander III Movie (.mve) File Demuxer
* 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
*/
@@ -158,7 +158,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 (url_feof(pb))
return AVERROR(EIO);
} while (fourcc_tag != BRCH_TAG);
@@ -210,7 +210,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 (url_feof(pb))
return AVERROR(EIO);
switch (fourcc_tag) {
diff --git a/libavformat/webvttdec.c b/libavformat/webvttdec.c
new file mode 100644
index 0000000..0654485
--- a/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 += 3;
+ 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..bd19a83
--- a/dev/null
+++ b/libavformat/webvttenc.c
@@ -0,0 +1,99 @@
+/*
+ * 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",
+ .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..f2bd3a1 100644
--- a/libavformat/westwood_aud.c
+++ b/libavformat/westwood_aud.c
@@ -2,20 +2,20 @@
* Westwood Studios AUD Format Demuxer
* 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..1d4bb5a 100644
--- a/libavformat/westwood_vqa.c
+++ b/libavformat/westwood_vqa.c
@@ -2,20 +2,20 @@
* Westwood Studios VQA Format Demuxer
* 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,9 +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 (ff_alloc_extradata(st->codec, VQA_HEADER_SIZE))
+ return AVERROR(ENOMEM);
+ header = (uint8_t *)st->codec->extradata;
if (avio_read(pb, st->codec->extradata, VQA_HEADER_SIZE) !=
VQA_HEADER_SIZE) {
return AVERROR(EIO);
@@ -130,9 +130,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 +166,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))
+ ret= av_get_packet(pb, pkt, chunk_size);
+ if (ret<0)
return AVERROR(EIO);
- ret = avio_read(pb, pkt->data, chunk_size);
- if (ret != chunk_size) {
- av_free_packet(pkt);
- return AVERROR(EIO);
- }
switch (chunk_type) {
case SND0_TAG:
@@ -223,9 +219,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 +230,8 @@ static int wsvqa_read_packet(AVFormatContext *s,
switch (chunk_type) {
case SND1_TAG:
/* unpacked size is stored in header */
- pkt->duration = AV_RL16(pkt->data) / wsvqa->channels;
+ if(pkt->data)
+ pkt->duration = AV_RL16(pkt->data) / wsvqa->channels;
break;
case SND2_TAG:
/* 2 samples/byte, 1 or 2 samples per frame depending on stereo */
diff --git a/libavformat/wtv.c b/libavformat/wtv.c
deleted file mode 100644
index b144eb6..0000000
--- a/libavformat/wtv.c
+++ b/dev/null
@@ -1,1115 +0,0 @@
-/*
- * Windows Television (WTV) demuxer
- * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * Windows Television (WTV) demuxer
- * @author Peter Ross <pross@xvid.org>
- */
-
-#include "libavutil/channel_layout.h"
-#include "libavutil/intreadwrite.h"
-#include "libavutil/intfloat.h"
-#include "libavutil/dict.h"
-#include "avformat.h"
-#include "internal.h"
-#include "riff.h"
-#include "asf.h"
-#include "mpegts.h"
-
-/* Macros for formating GUIDs */
-#define PRI_PRETTY_GUID \
- "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x"
-#define ARG_PRETTY_GUID(g) \
- AV_RL32(g),AV_RL16(g+4),AV_RL16(g+6),g[8],g[9],g[10],g[11],g[12],g[13],g[14],g[15]
-#define LEN_PRETTY_GUID 34
-
-/*
- *
- * File system routines
- *
- */
-
-#define WTV_SECTOR_BITS 12
-#define WTV_SECTOR_SIZE (1 << WTV_SECTOR_BITS)
-#define WTV_BIGSECTOR_BITS 18
-
-#define SHIFT_SECTOR_BITS(a) ((int64_t)(a) << WTV_SECTOR_BITS)
-
-typedef struct {
- AVIOContext *pb_filesystem; /** file system (AVFormatContext->pb) */
-
- int sector_bits; /** sector shift bits; used to convert sector number into pb_filesystem offset */
- uint32_t *sectors; /** file allocation table */
- int nb_sectors; /** number of sectors */
-
- int error;
- int64_t position;
- int64_t length;
-} WtvFile;
-
-static int64_t seek_by_sector(AVIOContext *pb, int64_t sector, int64_t offset)
-{
- return avio_seek(pb, SHIFT_SECTOR_BITS(sector) + offset, SEEK_SET);
-}
-
-/**
- * @return bytes read, 0 on end of file, or <0 on error
- */
-static int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size)
-{
- WtvFile *wf = opaque;
- AVIOContext *pb = wf->pb_filesystem;
- int nread = 0;
-
- if (wf->error || pb->error)
- return -1;
- if (wf->position >= wf->length || pb->eof_reached)
- return 0;
-
- buf_size = FFMIN(buf_size, wf->length - wf->position);
- while(nread < buf_size) {
- int n;
- int remaining_in_sector = (1 << wf->sector_bits) - (wf->position & ((1 << wf->sector_bits) - 1));
- int read_request = FFMIN(buf_size - nread, remaining_in_sector);
-
- n = avio_read(pb, buf, read_request);
- if (n <= 0)
- break;
- nread += n;
- buf += n;
- wf->position += n;
- if (n == remaining_in_sector) {
- int i = wf->position >> wf->sector_bits;
- if (i >= wf->nb_sectors ||
- (wf->sectors[i] != wf->sectors[i - 1] + (1 << (wf->sector_bits - WTV_SECTOR_BITS)) &&
- seek_by_sector(pb, wf->sectors[i], 0) < 0)) {
- wf->error = 1;
- break;
- }
- }
- }
- return nread;
-}
-
-/**
- * @return position (or file length)
- */
-static int64_t wtvfile_seek(void *opaque, int64_t offset, int whence)
-{
- WtvFile *wf = opaque;
- AVIOContext *pb = wf->pb_filesystem;
-
- if (whence == AVSEEK_SIZE)
- return wf->length;
- else if (whence == SEEK_CUR)
- offset = wf->position + offset;
- else if (whence == SEEK_END)
- offset = wf->length;
-
- wf->error = offset < 0 || offset >= wf->length ||
- seek_by_sector(pb, wf->sectors[offset >> wf->sector_bits],
- offset & ((1 << wf->sector_bits) - 1)) < 0;
- wf->position = offset;
- return offset;
-}
-
-/**
- * read non-zero integers (le32) from input stream
- * @param pb
- * @param[out] data destination
- * @param count maximum number of integers to read
- * @return total number of integers read
- */
-static int read_ints(AVIOContext *pb, uint32_t *data, int count)
-{
- int i, total = 0;
- for (i = 0; i < count; i++) {
- if ((data[total] = avio_rl32(pb)))
- total++;
- }
- return total;
-}
-
-/**
- * Open file
- * @param first_sector First sector
- * @param length Length of file (bytes)
- * @param depth File allocation table depth
- * @return NULL on error
- */
-static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int depth, AVFormatContext *s)
-{
- AVIOContext *pb;
- WtvFile *wf;
- uint8_t *buffer;
-
- if (seek_by_sector(s->pb, first_sector, 0) < 0)
- return NULL;
-
- wf = av_mallocz(sizeof(WtvFile));
- if (!wf)
- return NULL;
-
- if (depth == 0) {
- wf->sectors = av_malloc(sizeof(uint32_t));
- if (!wf->sectors) {
- av_free(wf);
- return NULL;
- }
- wf->sectors[0] = first_sector;
- wf->nb_sectors = 1;
- wf->sector_bits = WTV_SECTOR_BITS;
- } else if (depth == 1) {
- wf->sectors = av_malloc(WTV_SECTOR_SIZE);
- if (!wf->sectors) {
- av_free(wf);
- return NULL;
- }
- wf->nb_sectors = read_ints(s->pb, wf->sectors, WTV_SECTOR_SIZE / 4);
- wf->sector_bits = length & (1ULL<<63) ? WTV_SECTOR_BITS : WTV_BIGSECTOR_BITS;
- } else if (depth == 2) {
- uint32_t sectors1[WTV_SECTOR_SIZE / 4];
- int nb_sectors1 = read_ints(s->pb, sectors1, WTV_SECTOR_SIZE / 4);
- int i;
-
- wf->sectors = av_malloc(SHIFT_SECTOR_BITS(nb_sectors1));
- if (!wf->sectors) {
- av_free(wf);
- return NULL;
- }
- wf->nb_sectors = 0;
- for (i = 0; i < nb_sectors1; i++) {
- if (seek_by_sector(s->pb, sectors1[i], 0) < 0)
- break;
- wf->nb_sectors += read_ints(s->pb, wf->sectors + i * WTV_SECTOR_SIZE / 4, WTV_SECTOR_SIZE / 4);
- }
- wf->sector_bits = length & (1ULL<<63) ? WTV_SECTOR_BITS : WTV_BIGSECTOR_BITS;
- } else {
- av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (0x%x)\n", depth);
- av_free(wf);
- return NULL;
- }
-
- if (!wf->nb_sectors) {
- av_free(wf->sectors);
- av_free(wf);
- return NULL;
- }
-
- /* check length */
- length &= 0xFFFFFFFFFFFF;
- if (length > ((int64_t)wf->nb_sectors << wf->sector_bits)) {
- av_log(s, AV_LOG_WARNING, "reported file length (0x%"PRIx64") exceeds number of available sectors (0x%"PRIx64")\n", length, (int64_t)wf->nb_sectors << wf->sector_bits);
- length = (int64_t)wf->nb_sectors << wf->sector_bits;
- }
- wf->length = length;
-
- /* seek to initial sector */
- wf->position = 0;
- if (seek_by_sector(s->pb, wf->sectors[0], 0) < 0) {
- av_free(wf->sectors);
- av_free(wf);
- return NULL;
- }
-
- wf->pb_filesystem = s->pb;
- buffer = av_malloc(1 << wf->sector_bits);
- if (!buffer) {
- av_free(wf->sectors);
- av_free(wf);
- return NULL;
- }
-
- pb = avio_alloc_context(buffer, 1 << wf->sector_bits, 0, wf,
- wtvfile_read_packet, NULL, wtvfile_seek);
- if (!pb) {
- av_free(buffer);
- av_free(wf->sectors);
- av_free(wf);
- }
- return pb;
-}
-
-static const ff_asf_guid dir_entry_guid =
- {0x92,0xB7,0x74,0x91,0x59,0x70,0x70,0x44,0x88,0xDF,0x06,0x3B,0x82,0xCC,0x21,0x3D};
-
-/**
- * Open file using filename
- * @param[in] buf directory buffer
- * @param buf_size directory buffer size
- * @param[in] filename
- * @param filename_size size of filename
- * @return NULL on error
- */
-static AVIOContext * wtvfile_open2(AVFormatContext *s, const uint8_t *buf, int buf_size, const uint8_t *filename, int filename_size)
-{
- const uint8_t *buf_end = buf + buf_size;
-
- while(buf + 48 <= buf_end) {
- int dir_length, name_size, first_sector, depth;
- uint64_t file_length;
- const uint8_t *name;
- if (ff_guidcmp(buf, dir_entry_guid)) {
- av_log(s, AV_LOG_ERROR, "unknown guid "FF_PRI_GUID", expected dir_entry_guid; "
- "remaining directory entries ignored\n", FF_ARG_GUID(buf));
- break;
- }
- dir_length = AV_RL16(buf + 16);
- file_length = AV_RL64(buf + 24);
- name_size = 2 * AV_RL32(buf + 32);
- if (name_size < 0) {
- av_log(s, AV_LOG_ERROR,
- "bad filename length, remaining directory entries ignored\n");
- break;
- }
- if (48 + name_size > buf_end - buf) {
- av_log(s, AV_LOG_ERROR, "filename exceeds buffer size; remaining directory entries ignored\n");
- break;
- }
- first_sector = AV_RL32(buf + 40 + name_size);
- depth = AV_RL32(buf + 44 + name_size);
-
- /* compare file name; test optional null terminator */
- name = buf + 40;
- if (name_size >= filename_size &&
- !memcmp(name, filename, filename_size) &&
- (name_size < filename_size + 2 || !AV_RN16(name + filename_size)))
- return wtvfile_open_sector(first_sector, file_length, depth, s);
-
- buf += dir_length;
- }
- return 0;
-}
-
-#define wtvfile_open(s, buf, buf_size, filename) \
- wtvfile_open2(s, buf, buf_size, filename, sizeof(filename))
-
-/**
- * Close file opened with wtvfile_open_sector(), or wtv_open()
- */
-static void wtvfile_close(AVIOContext *pb)
-{
- WtvFile *wf = pb->opaque;
- av_free(wf->sectors);
- av_free(wf);
- av_free(pb->buffer);
- av_free(pb);
-}
-
-/*
- *
- * Main demuxer
- *
- */
-
-typedef struct {
- int seen_data;
-} WtvStream;
-
-typedef struct {
- AVIOContext *pb; /** timeline file */
- int64_t epoch;
- int64_t pts; /** pts for next data chunk */
- int64_t last_valid_pts; /** latest valid pts, used for interative seeking */
-
- /* maintain private seek index, as the AVIndexEntry->pos is relative to the
- start of the 'timeline' file, not the file system (AVFormatContext->pb) */
- AVIndexEntry *index_entries;
- int nb_index_entries;
- unsigned int index_entries_allocated_size;
-} WtvContext;
-
-/* WTV GUIDs */
-static const ff_asf_guid wtv_guid =
- {0xB7,0xD8,0x00,0x20,0x37,0x49,0xDA,0x11,0xA6,0x4E,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
-static const ff_asf_guid metadata_guid =
- {0x5A,0xFE,0xD7,0x6D,0xC8,0x1D,0x8F,0x4A,0x99,0x22,0xFA,0xB1,0x1C,0x38,0x14,0x53};
-static const ff_asf_guid timestamp_guid =
- {0x5B,0x05,0xE6,0x1B,0x97,0xA9,0x49,0x43,0x88,0x17,0x1A,0x65,0x5A,0x29,0x8A,0x97};
-static const ff_asf_guid data_guid =
- {0x95,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
-static const ff_asf_guid stream_guid =
- {0xED,0xA4,0x13,0x23,0x2D,0xBF,0x4F,0x45,0xAD,0x8A,0xD9,0x5B,0xA7,0xF9,0x1F,0xEE};
-static const ff_asf_guid stream2_guid =
- {0xA2,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
-static const ff_asf_guid EVENTID_SubtitleSpanningEvent =
- {0x48,0xC0,0xCE,0x5D,0xB9,0xD0,0x63,0x41,0x87,0x2C,0x4F,0x32,0x22,0x3B,0xE8,0x8A};
-static const ff_asf_guid EVENTID_LanguageSpanningEvent =
- {0x6D,0x66,0x92,0xE2,0x02,0x9C,0x8D,0x44,0xAA,0x8D,0x78,0x1A,0x93,0xFD,0xC3,0x95};
-static const ff_asf_guid EVENTID_AudioDescriptorSpanningEvent =
- {0x1C,0xD4,0x7B,0x10,0xDA,0xA6,0x91,0x46,0x83,0x69,0x11,0xB2,0xCD,0xAA,0x28,0x8E};
-static const ff_asf_guid EVENTID_CtxADescriptorSpanningEvent =
- {0xE6,0xA2,0xB4,0x3A,0x47,0x42,0x34,0x4B,0x89,0x6C,0x30,0xAF,0xA5,0xD2,0x1C,0x24};
-static const ff_asf_guid EVENTID_CSDescriptorSpanningEvent =
- {0xD9,0x79,0xE7,0xEf,0xF0,0x97,0x86,0x47,0x80,0x0D,0x95,0xCF,0x50,0x5D,0xDC,0x66};
-static const ff_asf_guid EVENTID_DVBScramblingControlSpanningEvent =
- {0xC4,0xE1,0xD4,0x4B,0xA1,0x90,0x09,0x41,0x82,0x36,0x27,0xF0,0x0E,0x7D,0xCC,0x5B};
-static const ff_asf_guid EVENTID_StreamIDSpanningEvent =
- {0x68,0xAB,0xF1,0xCA,0x53,0xE1,0x41,0x4D,0xA6,0xB3,0xA7,0xC9,0x98,0xDB,0x75,0xEE};
-static const ff_asf_guid EVENTID_TeletextSpanningEvent =
- {0x50,0xD9,0x99,0x95,0x33,0x5F,0x17,0x46,0xAF,0x7C,0x1E,0x54,0xB5,0x10,0xDA,0xA3};
-static const ff_asf_guid EVENTID_AudioTypeSpanningEvent =
- {0xBE,0xBF,0x1C,0x50,0x49,0xB8,0xCE,0x42,0x9B,0xE9,0x3D,0xB8,0x69,0xFB,0x82,0xB3};
-
-/* Windows media GUIDs */
-
-/* Media types */
-static const ff_asf_guid mediatype_audio =
- {'a','u','d','s',FF_MEDIASUBTYPE_BASE_GUID};
-static const ff_asf_guid mediatype_video =
- {'v','i','d','s',FF_MEDIASUBTYPE_BASE_GUID};
-static const ff_asf_guid mediasubtype_mpeg1payload =
- {0x81,0xEB,0x36,0xE4,0x4F,0x52,0xCE,0x11,0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70};
-static const ff_asf_guid mediatype_mpeg2_sections =
- {0x6C,0x17,0x5F,0x45,0x06,0x4B,0xCE,0x47,0x9A,0xEF,0x8C,0xAE,0xF7,0x3D,0xF7,0xB5};
-static const ff_asf_guid mediatype_mpeg2_pes =
- {0x20,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA};
-static const ff_asf_guid mediatype_mstvcaption =
- {0x89,0x8A,0x8B,0xB8,0x49,0xB0,0x80,0x4C,0xAD,0xCF,0x58,0x98,0x98,0x5E,0x22,0xC1};
-
-/* Media subtypes */
-static const ff_asf_guid mediasubtype_cpfilters_processed =
- {0x28,0xBD,0xAD,0x46,0xD0,0x6F,0x96,0x47,0x93,0xB2,0x15,0x5C,0x51,0xDC,0x04,0x8D};
-static const ff_asf_guid mediasubtype_dvb_subtitle =
- {0xC3,0xCB,0xFF,0x34,0xB3,0xD5,0x71,0x41,0x90,0x02,0xD4,0xC6,0x03,0x01,0x69,0x7F};
-static const ff_asf_guid mediasubtype_teletext =
- {0xE3,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA};
-static const ff_asf_guid mediasubtype_dtvccdata =
- {0xAA,0xDD,0x2A,0xF5,0xF0,0x36,0xF5,0x43,0x95,0xEA,0x6D,0x86,0x64,0x84,0x26,0x2A};
-static const ff_asf_guid mediasubtype_mpeg2_sections =
- {0x79,0x85,0x9F,0x4A,0xF8,0x6B,0x92,0x43,0x8A,0x6D,0xD2,0xDD,0x09,0xFA,0x78,0x61};
-
-/* Formats */
-static const ff_asf_guid format_cpfilters_processed =
- {0x6F,0xB3,0x39,0x67,0x5F,0x1D,0xC2,0x4A,0x81,0x92,0x28,0xBB,0x0E,0x73,0xD1,0x6A};
-static const ff_asf_guid format_waveformatex =
- {0x81,0x9F,0x58,0x05,0x56,0xC3,0xCE,0x11,0xBF,0x01,0x00,0xAA,0x00,0x55,0x59,0x5A};
-static const ff_asf_guid format_videoinfo2 =
- {0xA0,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA};
-static const ff_asf_guid format_mpeg2_video =
- {0xE3,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA};
-static const ff_asf_guid format_none =
- {0xD6,0x17,0x64,0x0F,0x18,0xC3,0xD0,0x11,0xA4,0x3F,0x00,0xA0,0xC9,0x22,0x31,0x96};
-
-static const AVCodecGuid video_guids[] = {
- {AV_CODEC_ID_MPEG2VIDEO, {0x26,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}},
- {AV_CODEC_ID_NONE}
-};
-
-static int read_probe(AVProbeData *p)
-{
- return ff_guidcmp(p->buf, wtv_guid) ? 0 : AVPROBE_SCORE_MAX;
-}
-
-/**
- * Convert win32 FILETIME to ISO-8601 string
- */
-static void filetime_to_iso8601(char *buf, int buf_size, int64_t value)
-{
- time_t t = (value / 10000000LL) - 11644473600LL;
- struct tm *tm = gmtime(&t);
- if (tm)
- strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", gmtime(&t));
- else
- buf[0] = '\0';
-}
-
-/**
- * Convert crazy time (100ns since 1 Jan 0001) to ISO-8601 string
- */
-static void crazytime_to_iso8601(char *buf, int buf_size, int64_t value)
-{
- time_t t = (value / 10000000LL) - 719162LL*86400LL;
- struct tm *tm = gmtime(&t);
- if (tm)
- strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", gmtime(&t));
- else
- buf[0] = '\0';
-}
-
-/**
- * Convert OLE DATE to ISO-8601 string
- */
-static void oledate_to_iso8601(char *buf, int buf_size, int64_t value)
-{
- time_t t = 631112400LL + 86400*av_int2double(value);
- struct tm *tm = gmtime(&t);
- if (tm)
- strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", gmtime(&t));
- else
- buf[0] = '\0';
-}
-
-static void get_attachment(AVFormatContext *s, AVIOContext *pb, int length)
-{
- char mime[1024];
- char description[1024];
- unsigned int filesize;
- AVStream *st;
- int64_t pos = avio_tell(pb);
-
- avio_get_str16le(pb, INT_MAX, mime, sizeof(mime));
- if (strcmp(mime, "image/jpeg"))
- goto done;
-
- avio_r8(pb);
- avio_get_str16le(pb, INT_MAX, description, sizeof(description));
- filesize = avio_rl32(pb);
- if (!filesize)
- goto done;
-
- st = avformat_new_stream(s, NULL);
- if (!st)
- goto done;
- av_dict_set(&st->metadata, "title", description, 0);
- st->codec->codec_id = AV_CODEC_ID_MJPEG;
- st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT;
- st->codec->extradata = av_mallocz(filesize);
- st->id = -1;
- if (!st->codec->extradata)
- goto done;
- st->codec->extradata_size = filesize;
- avio_read(pb, st->codec->extradata, filesize);
-done:
- avio_seek(pb, pos + length, SEEK_SET);
-}
-
-static void get_tag(AVFormatContext *s, AVIOContext *pb, const char *key, int type, int length)
-{
- int buf_size = FFMAX(2*length, LEN_PRETTY_GUID) + 1;
- char *buf = av_malloc(buf_size);
- if (!buf)
- return;
-
- if (type == 0 && length == 4) {
- snprintf(buf, buf_size, "%"PRIi32, avio_rl32(pb));
- } else if (type == 1) {
- avio_get_str16le(pb, length, buf, buf_size);
- if (!strlen(buf)) {
- av_free(buf);
- return;
- }
- } else if (type == 3 && length == 4) {
- strcpy(buf, avio_rl32(pb) ? "true" : "false");
- } else if (type == 4 && length == 8) {
- int64_t num = avio_rl64(pb);
- if (!strcmp(key, "WM/EncodingTime") ||
- !strcmp(key, "WM/MediaOriginalBroadcastDateTime"))
- filetime_to_iso8601(buf, buf_size, num);
- else if (!strcmp(key, "WM/WMRVEncodeTime") ||
- !strcmp(key, "WM/WMRVEndTime"))
- crazytime_to_iso8601(buf, buf_size, num);
- else if (!strcmp(key, "WM/WMRVExpirationDate"))
- oledate_to_iso8601(buf, buf_size, num);
- else if (!strcmp(key, "WM/WMRVBitrate"))
- snprintf(buf, buf_size, "%f", av_int2double(num));
- else
- snprintf(buf, buf_size, "%"PRIi64, num);
- } else if (type == 5 && length == 2) {
- snprintf(buf, buf_size, "%"PRIi16, avio_rl16(pb));
- } else if (type == 6 && length == 16) {
- ff_asf_guid guid;
- avio_read(pb, guid, 16);
- snprintf(buf, buf_size, PRI_PRETTY_GUID, ARG_PRETTY_GUID(guid));
- } else if (type == 2 && !strcmp(key, "WM/Picture")) {
- get_attachment(s, pb, length);
- av_freep(&buf);
- return;
- } else {
- av_freep(&buf);
- av_log(s, AV_LOG_WARNING, "unsupported metadata entry; key:%s, type:%d, length:0x%x\n", key, type, length);
- avio_skip(pb, length);
- return;
- }
-
- av_dict_set(&s->metadata, key, buf, 0);
- av_freep(&buf);
-}
-
-/**
- * Parse metadata entries
- */
-static void parse_legacy_attrib(AVFormatContext *s, AVIOContext *pb)
-{
- ff_asf_guid guid;
- int length, type;
- while(!pb->eof_reached) {
- char key[1024];
- ff_get_guid(pb, &guid);
- type = avio_rl32(pb);
- length = avio_rl32(pb);
- if (!length)
- break;
- if (ff_guidcmp(&guid, metadata_guid)) {
- av_log(s, AV_LOG_WARNING, "unknown guid "FF_PRI_GUID", expected metadata_guid; "
- "remaining metadata entries ignored\n", FF_ARG_GUID(guid));
- break;
- }
- avio_get_str16le(pb, INT_MAX, key, sizeof(key));
- get_tag(s, pb, key, type, length);
- }
-
- ff_metadata_conv(&s->metadata, NULL, ff_asf_metadata_conv);
-}
-
-/**
- * parse VIDEOINFOHEADER2 structure
- * @return bytes consumed
- */
-static int parse_videoinfoheader2(AVFormatContext *s, AVStream *st)
-{
- WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
-
- avio_skip(pb, 72); // picture aspect ratio is unreliable
- ff_get_bmp_header(pb, st);
-
- return 72 + 40;
-}
-
-/**
- * Parse MPEG1WAVEFORMATEX extradata structure
- */
-static void parse_mpeg1waveformatex(AVStream *st)
-{
- /* fwHeadLayer */
- switch (AV_RL16(st->codec->extradata)) {
- case 0x0001 : st->codec->codec_id = AV_CODEC_ID_MP1; break;
- case 0x0002 : st->codec->codec_id = AV_CODEC_ID_MP2; break;
- case 0x0004 : st->codec->codec_id = AV_CODEC_ID_MP3; break;
- }
-
- st->codec->bit_rate = AV_RL32(st->codec->extradata + 2); /* dwHeadBitrate */
-
- /* dwHeadMode */
- switch (AV_RL16(st->codec->extradata + 6)) {
- case 1 :
- case 2 :
- case 4 : st->codec->channels = 2;
- st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
- break;
- case 8 : st->codec->channels = 1;
- st->codec->channel_layout = AV_CH_LAYOUT_MONO;
- break;
- }
-}
-
-/**
- * Initialise stream
- * @param st Stream to initialise, or NULL to create and initialise new stream
- * @return NULL on error
- */
-static AVStream * new_stream(AVFormatContext *s, AVStream *st, int sid, int codec_type)
-{
- if (st) {
- if (st->codec->extradata) {
- av_freep(&st->codec->extradata);
- st->codec->extradata_size = 0;
- }
- } else {
- WtvStream *wst = av_mallocz(sizeof(WtvStream));
- if (!wst)
- return NULL;
- st = avformat_new_stream(s, NULL);
- if (!st)
- return NULL;
- st->id = sid;
- st->priv_data = wst;
- }
- st->codec->codec_type = codec_type;
- st->need_parsing = AVSTREAM_PARSE_FULL;
- avpriv_set_pts_info(st, 64, 1, 10000000);
- return st;
-}
-
-/**
- * parse Media Type structure and populate stream
- * @param st Stream, or NULL to create new stream
- * @param mediatype Mediatype GUID
- * @param subtype Subtype GUID
- * @param formattype Format GUID
- * @param size Size of format buffer
- * @return NULL on error
- */
-static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid,
- ff_asf_guid mediatype, ff_asf_guid subtype,
- ff_asf_guid formattype, int size)
-{
- WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
- if (!ff_guidcmp(subtype, mediasubtype_cpfilters_processed) &&
- !ff_guidcmp(formattype, format_cpfilters_processed)) {
- ff_asf_guid actual_subtype;
- ff_asf_guid actual_formattype;
-
- if (size < 32) {
- av_log(s, AV_LOG_WARNING, "format buffer size underflow\n");
- avio_skip(pb, size);
- return NULL;
- }
-
- avio_skip(pb, size - 32);
- ff_get_guid(pb, &actual_subtype);
- ff_get_guid(pb, &actual_formattype);
- avio_seek(pb, -size, SEEK_CUR);
-
- st = parse_media_type(s, st, sid, mediatype, actual_subtype, actual_formattype, size - 32);
- avio_skip(pb, 32);
- return st;
- } else if (!ff_guidcmp(mediatype, mediatype_audio)) {
- st = new_stream(s, st, sid, AVMEDIA_TYPE_AUDIO);
- if (!st)
- return NULL;
- if (!ff_guidcmp(formattype, format_waveformatex)) {
- int ret = ff_get_wav_header(pb, st->codec, size);
- if (ret < 0)
- return NULL;
- } else {
- if (ff_guidcmp(formattype, format_none))
- av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
- avio_skip(pb, size);
- }
-
- if (!memcmp(subtype + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) {
- st->codec->codec_id = ff_wav_codec_get_id(AV_RL32(subtype), st->codec->bits_per_coded_sample);
- } else if (!ff_guidcmp(subtype, mediasubtype_mpeg1payload)) {
- if (st->codec->extradata && st->codec->extradata_size >= 22)
- parse_mpeg1waveformatex(st);
- else
- av_log(s, AV_LOG_WARNING, "MPEG1WAVEFORMATEX underflow\n");
- } else {
- st->codec->codec_id = ff_codec_guid_get_id(ff_codec_wav_guids, subtype);
- if (st->codec->codec_id == AV_CODEC_ID_NONE)
- av_log(s, AV_LOG_WARNING, "unknown subtype:"FF_PRI_GUID"\n", FF_ARG_GUID(subtype));
- }
- return st;
- } else if (!ff_guidcmp(mediatype, mediatype_video)) {
- st = new_stream(s, st, sid, AVMEDIA_TYPE_VIDEO);
- if (!st)
- return NULL;
- if (!ff_guidcmp(formattype, format_videoinfo2)) {
- int consumed = parse_videoinfoheader2(s, st);
- avio_skip(pb, FFMAX(size - consumed, 0));
- } else if (!ff_guidcmp(formattype, format_mpeg2_video)) {
- int consumed = parse_videoinfoheader2(s, st);
- avio_skip(pb, FFMAX(size - consumed, 0));
- } else {
- if (ff_guidcmp(formattype, format_none))
- av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
- avio_skip(pb, size);
- }
-
- if (!memcmp(subtype + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) {
- st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(subtype));
- } else {
- st->codec->codec_id = ff_codec_guid_get_id(video_guids, subtype);
- }
- if (st->codec->codec_id == AV_CODEC_ID_NONE)
- av_log(s, AV_LOG_WARNING, "unknown subtype:"FF_PRI_GUID"\n", FF_ARG_GUID(subtype));
- return st;
- } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_pes) &&
- !ff_guidcmp(subtype, mediasubtype_dvb_subtitle)) {
- st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE);
- if (!st)
- return NULL;
- if (ff_guidcmp(formattype, format_none))
- av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
- avio_skip(pb, size);
- st->codec->codec_id = AV_CODEC_ID_DVB_SUBTITLE;
- return st;
- } else if (!ff_guidcmp(mediatype, mediatype_mstvcaption) &&
- (!ff_guidcmp(subtype, mediasubtype_teletext) || !ff_guidcmp(subtype, mediasubtype_dtvccdata))) {
- st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE);
- if (!st)
- return NULL;
- if (ff_guidcmp(formattype, format_none))
- av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
- avio_skip(pb, size);
- st->codec->codec_id = AV_CODEC_ID_DVB_TELETEXT;
- return st;
- } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_sections) &&
- !ff_guidcmp(subtype, mediasubtype_mpeg2_sections)) {
- if (ff_guidcmp(formattype, format_none))
- av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
- avio_skip(pb, size);
- return NULL;
- }
-
- av_log(s, AV_LOG_WARNING, "unknown media type, mediatype:"FF_PRI_GUID
- ", subtype:"FF_PRI_GUID", formattype:"FF_PRI_GUID"\n",
- FF_ARG_GUID(mediatype), FF_ARG_GUID(subtype), FF_ARG_GUID(formattype));
- avio_skip(pb, size);
- return NULL;
-}
-
-enum {
- SEEK_TO_DATA = 0,
- SEEK_TO_PTS,
-};
-
-/**
- * Parse WTV chunks
- * @param mode SEEK_TO_DATA or SEEK_TO_PTS
- * @param seekts timestamp
- * @param[out] len_ptr Length of data chunk
- * @return stream index of data chunk, or <0 on error
- */
-static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_ptr)
-{
- WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
- while (!pb->eof_reached) {
- ff_asf_guid g;
- int len, sid, consumed;
-
- ff_get_guid(pb, &g);
- len = avio_rl32(pb);
- if (len < 32)
- break;
- sid = avio_rl32(pb) & 0x7FFF;
- avio_skip(pb, 8);
- consumed = 32;
-
- if (!ff_guidcmp(g, stream_guid)) {
- if (ff_find_stream_index(s, sid) < 0) {
- ff_asf_guid mediatype, subtype, formattype;
- int size;
- avio_skip(pb, 28);
- ff_get_guid(pb, &mediatype);
- ff_get_guid(pb, &subtype);
- avio_skip(pb, 12);
- ff_get_guid(pb, &formattype);
- size = avio_rl32(pb);
- parse_media_type(s, 0, sid, mediatype, subtype, formattype, size);
- consumed += 92 + size;
- }
- } else if (!ff_guidcmp(g, stream2_guid)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (stream_index >= 0 && !((WtvStream*)s->streams[stream_index]->priv_data)->seen_data) {
- ff_asf_guid mediatype, subtype, formattype;
- int size;
- avio_skip(pb, 12);
- ff_get_guid(pb, &mediatype);
- ff_get_guid(pb, &subtype);
- avio_skip(pb, 12);
- ff_get_guid(pb, &formattype);
- size = avio_rl32(pb);
- parse_media_type(s, s->streams[stream_index], sid, mediatype, subtype, formattype, size);
- consumed += 76 + size;
- }
- } else if (!ff_guidcmp(g, EVENTID_AudioDescriptorSpanningEvent) ||
- !ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) ||
- !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent) ||
- !ff_guidcmp(g, EVENTID_StreamIDSpanningEvent) ||
- !ff_guidcmp(g, EVENTID_SubtitleSpanningEvent) ||
- !ff_guidcmp(g, EVENTID_TeletextSpanningEvent)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (stream_index >= 0) {
- AVStream *st = s->streams[stream_index];
- uint8_t buf[258];
- const uint8_t *pbuf = buf;
- int buf_size;
-
- avio_skip(pb, 8);
- consumed += 8;
- if (!ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) ||
- !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent)) {
- avio_skip(pb, 6);
- consumed += 6;
- }
-
- buf_size = FFMIN(len - consumed, sizeof(buf));
- avio_read(pb, buf, buf_size);
- consumed += buf_size;
- ff_parse_mpeg2_descriptor(s, st, 0, &pbuf, buf + buf_size, NULL, 0, 0, NULL);
- }
- } else if (!ff_guidcmp(g, EVENTID_AudioTypeSpanningEvent)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (stream_index >= 0) {
- AVStream *st = s->streams[stream_index];
- int audio_type;
- avio_skip(pb, 8);
- audio_type = avio_r8(pb);
- if (audio_type == 2)
- st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED;
- else if (audio_type == 3)
- st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
- consumed += 9;
- }
- } else if (!ff_guidcmp(g, EVENTID_DVBScramblingControlSpanningEvent)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (stream_index >= 0) {
- avio_skip(pb, 12);
- if (avio_rl32(pb))
- av_log(s, AV_LOG_WARNING, "DVB scrambled stream detected (st:%d), decoding will likely fail\n", stream_index);
- consumed += 16;
- }
- } else if (!ff_guidcmp(g, EVENTID_LanguageSpanningEvent)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (stream_index >= 0) {
- AVStream *st = s->streams[stream_index];
- uint8_t language[4];
- avio_skip(pb, 12);
- avio_read(pb, language, 3);
- if (language[0]) {
- language[3] = 0;
- av_dict_set(&st->metadata, "language", language, 0);
- if (!strcmp(language, "nar") || !strcmp(language, "NAR"))
- st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
- }
- consumed += 15;
- }
- } else if (!ff_guidcmp(g, timestamp_guid)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (stream_index >= 0) {
- avio_skip(pb, 8);
- wtv->pts = avio_rl64(pb);
- consumed += 16;
- if (wtv->pts == -1)
- wtv->pts = AV_NOPTS_VALUE;
- else {
- wtv->last_valid_pts = wtv->pts;
- if (wtv->epoch == AV_NOPTS_VALUE || wtv->pts < wtv->epoch)
- wtv->epoch = wtv->pts;
- if (mode == SEEK_TO_PTS && wtv->pts >= seekts) {
-#define WTV_PAD8(x) (((x) + 7) & ~7)
- avio_skip(pb, WTV_PAD8(len) - consumed);
- return 0;
- }
- }
- }
- } else if (!ff_guidcmp(g, data_guid)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (mode == SEEK_TO_DATA && stream_index >= 0 && len > 32) {
- WtvStream *wst = s->streams[stream_index]->priv_data;
- wst->seen_data = 1;
- if (len_ptr) {
- *len_ptr = len;
- }
- return stream_index;
- }
- } else if (
- !ff_guidcmp(g, /* DSATTRIB_CAPTURE_STREAMTIME */ (const ff_asf_guid){0x14,0x56,0x1A,0x0C,0xCD,0x30,0x40,0x4F,0xBC,0xBF,0xD0,0x3E,0x52,0x30,0x62,0x07}) ||
- !ff_guidcmp(g, /* DSATTRIB_PicSampleSeq */ (const ff_asf_guid){0x02,0xAE,0x5B,0x2F,0x8F,0x7B,0x60,0x4F,0x82,0xD6,0xE4,0xEA,0x2F,0x1F,0x4C,0x99}) ||
- !ff_guidcmp(g, /* DSATTRIB_TRANSPORT_PROPERTIES */ (const ff_asf_guid){0x12,0xF6,0x22,0xB6,0xAD,0x47,0x71,0x46,0xAD,0x6C,0x05,0xA9,0x8E,0x65,0xDE,0x3A}) ||
- !ff_guidcmp(g, /* dvr_ms_vid_frame_rep_data */ (const ff_asf_guid){0xCC,0x32,0x64,0xDD,0x29,0xE2,0xDB,0x40,0x80,0xF6,0xD2,0x63,0x28,0xD2,0x76,0x1F}) ||
- !ff_guidcmp(g, /* EVENTID_ChannelChangeSpanningEvent */ (const ff_asf_guid){0xE5,0xC5,0x67,0x90,0x5C,0x4C,0x05,0x42,0x86,0xC8,0x7A,0xFE,0x20,0xFE,0x1E,0xFA}) ||
- !ff_guidcmp(g, /* EVENTID_ChannelInfoSpanningEvent */ (const ff_asf_guid){0x80,0x6D,0xF3,0x41,0x32,0x41,0xC2,0x4C,0xB1,0x21,0x01,0xA4,0x32,0x19,0xD8,0x1B}) ||
- !ff_guidcmp(g, /* EVENTID_ChannelTypeSpanningEvent */ (const ff_asf_guid){0x51,0x1D,0xAB,0x72,0xD2,0x87,0x9B,0x48,0xBA,0x11,0x0E,0x08,0xDC,0x21,0x02,0x43}) ||
- !ff_guidcmp(g, /* EVENTID_PIDListSpanningEvent */ (const ff_asf_guid){0x65,0x8F,0xFC,0x47,0xBB,0xE2,0x34,0x46,0x9C,0xEF,0xFD,0xBF,0xE6,0x26,0x1D,0x5C}) ||
- !ff_guidcmp(g, /* EVENTID_SignalAndServiceStatusSpanningEvent */ (const ff_asf_guid){0xCB,0xC5,0x68,0x80,0x04,0x3C,0x2B,0x49,0xB4,0x7D,0x03,0x08,0x82,0x0D,0xCE,0x51}) ||
- !ff_guidcmp(g, /* EVENTID_StreamTypeSpanningEvent */ (const ff_asf_guid){0xBC,0x2E,0xAF,0x82,0xA6,0x30,0x64,0x42,0xA8,0x0B,0xAD,0x2E,0x13,0x72,0xAC,0x60}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x1E,0xBE,0xC3,0xC5,0x43,0x92,0xDC,0x11,0x85,0xE5,0x00,0x12,0x3F,0x6F,0x73,0xB9}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x3B,0x86,0xA2,0xB1,0xEB,0x1E,0xC3,0x44,0x8C,0x88,0x1C,0xA3,0xFF,0xE3,0xE7,0x6A}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x4E,0x7F,0x4C,0x5B,0xC4,0xD0,0x38,0x4B,0xA8,0x3E,0x21,0x7F,0x7B,0xBF,0x52,0xE7}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x63,0x36,0xEB,0xFE,0xA1,0x7E,0xD9,0x11,0x83,0x08,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x70,0xE9,0xF1,0xF8,0x89,0xA4,0x4C,0x4D,0x83,0x73,0xB8,0x12,0xE0,0xD5,0xF8,0x1E}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x96,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x97,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0xA1,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D})) {
- //ignore known guids
- } else
- av_log(s, AV_LOG_WARNING, "unsupported chunk:"FF_PRI_GUID"\n", FF_ARG_GUID(g));
-
- avio_skip(pb, WTV_PAD8(len) - consumed);
- }
- return AVERROR_EOF;
-}
-
-/* declare utf16le strings */
-#define _ , 0,
-static const uint8_t timeline_le16[] =
- {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e', 0};
-static const uint8_t table_0_entries_legacy_attrib_le16[] =
- {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
-static const uint8_t table_0_entries_time_le16[] =
- {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'t'_'i'_'m'_'e', 0};
-static const uint8_t timeline_table_0_entries_Events_le16[] =
- {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e'_'.'_'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'E'_'v'_'e'_'n'_'t'_'s', 0};
-#undef _
-
-static int read_header(AVFormatContext *s)
-{
- WtvContext *wtv = s->priv_data;
- int root_sector, root_size;
- uint8_t root[WTV_SECTOR_SIZE];
- AVIOContext *pb;
- int64_t timeline_pos;
- int ret;
-
- wtv->epoch =
- wtv->pts =
- wtv->last_valid_pts = AV_NOPTS_VALUE;
-
- /* read root directory sector */
- avio_skip(s->pb, 0x30);
- root_size = avio_rl32(s->pb);
- if (root_size > sizeof(root)) {
- av_log(s, AV_LOG_ERROR, "root directory size exceeds sector size\n");
- return AVERROR_INVALIDDATA;
- }
- avio_skip(s->pb, 4);
- root_sector = avio_rl32(s->pb);
-
- seek_by_sector(s->pb, root_sector, 0);
- root_size = avio_read(s->pb, root, root_size);
- if (root_size < 0)
- return AVERROR_INVALIDDATA;
-
- /* parse chunks up until first data chunk */
- wtv->pb = wtvfile_open(s, root, root_size, timeline_le16);
- if (!wtv->pb) {
- av_log(s, AV_LOG_ERROR, "timeline data missing\n");
- return AVERROR_INVALIDDATA;
- }
-
- ret = parse_chunks(s, SEEK_TO_DATA, 0, 0);
- if (ret < 0)
- return ret;
- avio_seek(wtv->pb, -32, SEEK_CUR);
-
- timeline_pos = avio_tell(s->pb); // save before opening another file
-
- /* read metadata */
- pb = wtvfile_open(s, root, root_size, table_0_entries_legacy_attrib_le16);
- if (pb) {
- parse_legacy_attrib(s, pb);
- wtvfile_close(pb);
- }
-
- /* read seek index */
- if (s->nb_streams) {
- AVStream *st = s->streams[0];
- pb = wtvfile_open(s, root, root_size, table_0_entries_time_le16);
- if (pb) {
- while(1) {
- uint64_t timestamp = avio_rl64(pb);
- uint64_t frame_nb = avio_rl64(pb);
- if (pb->eof_reached)
- break;
- ff_add_index_entry(&wtv->index_entries, &wtv->nb_index_entries, &wtv->index_entries_allocated_size,
- 0, timestamp, frame_nb, 0, AVINDEX_KEYFRAME);
- }
- wtvfile_close(pb);
-
- if (wtv->nb_index_entries) {
- pb = wtvfile_open(s, root, root_size, timeline_table_0_entries_Events_le16);
- if (pb) {
- int i;
- while (1) {
- uint64_t frame_nb = avio_rl64(pb);
- uint64_t position = avio_rl64(pb);
- if (pb->eof_reached)
- break;
- for (i = wtv->nb_index_entries - 1; i >= 0; i--) {
- AVIndexEntry *e = wtv->index_entries + i;
- if (frame_nb > e->size)
- break;
- if (position > e->pos)
- e->pos = position;
- }
- }
- wtvfile_close(pb);
- st->duration = wtv->index_entries[wtv->nb_index_entries - 1].timestamp;
- }
- }
- }
- }
-
- avio_seek(s->pb, timeline_pos, SEEK_SET);
- return 0;
-}
-
-static int read_packet(AVFormatContext *s, AVPacket *pkt)
-{
- WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
- int stream_index, len, ret;
-
- stream_index = parse_chunks(s, SEEK_TO_DATA, 0, &len);
- if (stream_index < 0)
- return stream_index;
-
- ret = av_get_packet(pb, pkt, len - 32);
- if (ret < 0)
- return ret;
- pkt->stream_index = stream_index;
- pkt->pts = wtv->pts;
- avio_skip(pb, WTV_PAD8(len) - len);
- return 0;
-}
-
-static int read_seek(AVFormatContext *s, int stream_index,
- int64_t ts, int flags)
-{
- WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
- AVStream *st = s->streams[0];
- int64_t ts_relative;
- int i;
-
- if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
- return AVERROR(ENOSYS);
-
- /* timestamp adjustment is required because wtv->pts values are absolute,
- * whereas AVIndexEntry->timestamp values are relative to epoch. */
- ts_relative = ts;
- if (wtv->epoch != AV_NOPTS_VALUE)
- ts_relative -= wtv->epoch;
-
- i = ff_index_search_timestamp(wtv->index_entries, wtv->nb_index_entries, ts_relative, flags);
- if (i < 0) {
- if (wtv->last_valid_pts == AV_NOPTS_VALUE || ts < wtv->last_valid_pts)
- avio_seek(pb, 0, SEEK_SET);
- else if (st->duration != AV_NOPTS_VALUE && ts_relative > st->duration && wtv->nb_index_entries)
- avio_seek(pb, wtv->index_entries[wtv->nb_index_entries - 1].pos, SEEK_SET);
- if (parse_chunks(s, SEEK_TO_PTS, ts, 0) < 0)
- return AVERROR(ERANGE);
- return 0;
- }
- wtv->pts = wtv->index_entries[i].timestamp;
- if (wtv->epoch != AV_NOPTS_VALUE)
- wtv->pts += wtv->epoch;
- wtv->last_valid_pts = wtv->pts;
- avio_seek(pb, wtv->index_entries[i].pos, SEEK_SET);
- return 0;
-}
-
-static int read_close(AVFormatContext *s)
-{
- WtvContext *wtv = s->priv_data;
- av_free(wtv->index_entries);
- wtvfile_close(wtv->pb);
- return 0;
-}
-
-AVInputFormat ff_wtv_demuxer = {
- .name = "wtv",
- .long_name = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"),
- .priv_data_size = sizeof(WtvContext),
- .read_probe = read_probe,
- .read_header = read_header,
- .read_packet = read_packet,
- .read_seek = read_seek,
- .read_close = read_close,
- .flags = AVFMT_SHOW_IDS,
-};
diff --git a/libavformat/wtv.h b/libavformat/wtv.h
new file mode 100644
index 0000000..efe90d6
--- a/dev/null
+++ b/libavformat/wtv.h
@@ -0,0 +1,58 @@
+/*
+ * 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;
+#endif /* AVFORMAT_WTV_H */
diff --git a/libavformat/wtv_common.c b/libavformat/wtv_common.c
new file mode 100644
index 0000000..5b1e61b
--- a/dev/null
+++ b/libavformat/wtv_common.c
@@ -0,0 +1,82 @@
+/*
+ * 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 AVCodecGuid ff_video_guids[] = {
+ {AV_CODEC_ID_MPEG2VIDEO, {0x26,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}},
+ {AV_CODEC_ID_NONE}
+};
diff --git a/libavformat/wtvdec.c b/libavformat/wtvdec.c
new file mode 100644
index 0000000..9bbea9c
--- a/dev/null
+++ b/libavformat/wtvdec.c
@@ -0,0 +1,1095 @@
+/*
+ * Windows Television (WTV) demuxer
+ * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Windows Television (WTV) demuxer
+ * @author Peter Ross <pross@xvid.org>
+ */
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/intfloat.h"
+#include "avformat.h"
+#include "internal.h"
+#include "wtv.h"
+#include "mpegts.h"
+
+/* Macros for formating GUIDs */
+#define PRI_PRETTY_GUID \
+ "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x"
+#define ARG_PRETTY_GUID(g) \
+ AV_RL32(g),AV_RL16(g+4),AV_RL16(g+6),g[8],g[9],g[10],g[11],g[12],g[13],g[14],g[15]
+#define LEN_PRETTY_GUID 34
+
+/*
+ *
+ * File system routines
+ *
+ */
+
+typedef struct {
+ AVIOContext *pb_filesystem; /**< file system (AVFormatContext->pb) */
+
+ int sector_bits; /**< sector shift bits; used to convert sector number into pb_filesystem offset */
+ uint32_t *sectors; /**< file allocation table */
+ int nb_sectors; /**< number of sectors */
+
+ int error;
+ int64_t position;
+ int64_t length;
+} WtvFile;
+
+static int64_t seek_by_sector(AVIOContext *pb, int64_t sector, int64_t offset)
+{
+ return avio_seek(pb, (sector << WTV_SECTOR_BITS) + offset, SEEK_SET);
+}
+
+/**
+ * @return bytes read, 0 on end of file, or <0 on error
+ */
+static int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size)
+{
+ WtvFile *wf = opaque;
+ AVIOContext *pb = wf->pb_filesystem;
+ int nread = 0;
+
+ if (wf->error || pb->error)
+ return -1;
+ if (wf->position >= wf->length || url_feof(pb))
+ return 0;
+
+ buf_size = FFMIN(buf_size, wf->length - wf->position);
+ while(nread < buf_size) {
+ int n;
+ int remaining_in_sector = (1 << wf->sector_bits) - (wf->position & ((1 << wf->sector_bits) - 1));
+ int read_request = FFMIN(buf_size - nread, remaining_in_sector);
+
+ n = avio_read(pb, buf, read_request);
+ if (n <= 0)
+ break;
+ nread += n;
+ buf += n;
+ wf->position += n;
+ if (n == remaining_in_sector) {
+ int i = wf->position >> wf->sector_bits;
+ if (i >= wf->nb_sectors ||
+ (wf->sectors[i] != wf->sectors[i - 1] + (1 << (wf->sector_bits - WTV_SECTOR_BITS)) &&
+ seek_by_sector(pb, wf->sectors[i], 0) < 0)) {
+ wf->error = 1;
+ break;
+ }
+ }
+ }
+ return nread;
+}
+
+/**
+ * @return position (or file length)
+ */
+static int64_t wtvfile_seek(void *opaque, int64_t offset, int whence)
+{
+ WtvFile *wf = opaque;
+ AVIOContext *pb = wf->pb_filesystem;
+
+ if (whence == AVSEEK_SIZE)
+ return wf->length;
+ else if (whence == SEEK_CUR)
+ offset = wf->position + offset;
+ else if (whence == SEEK_END)
+ offset = wf->length;
+
+ wf->error = offset < 0 || offset >= wf->length ||
+ seek_by_sector(pb, wf->sectors[offset >> wf->sector_bits],
+ offset & ((1 << wf->sector_bits) - 1)) < 0;
+ wf->position = offset;
+ return offset;
+}
+
+/**
+ * read non-zero integers (le32) from input stream
+ * @param pb
+ * @param[out] data destination
+ * @param count maximum number of integers to read
+ * @return total number of integers read
+ */
+static int read_ints(AVIOContext *pb, uint32_t *data, int count)
+{
+ int i, total = 0;
+ for (i = 0; i < count; i++) {
+ if ((data[total] = avio_rl32(pb)))
+ total++;
+ }
+ return total;
+}
+
+/**
+ * Open file
+ * @param first_sector First sector
+ * @param length Length of file (bytes)
+ * @param depth File allocation table depth
+ * @return NULL on error
+ */
+static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int depth, AVFormatContext *s)
+{
+ AVIOContext *pb;
+ WtvFile *wf;
+ uint8_t *buffer;
+
+ if (seek_by_sector(s->pb, first_sector, 0) < 0)
+ return NULL;
+
+ wf = av_mallocz(sizeof(WtvFile));
+ if (!wf)
+ return NULL;
+
+ if (depth == 0) {
+ wf->sectors = av_malloc(sizeof(uint32_t));
+ if (!wf->sectors) {
+ av_free(wf);
+ return NULL;
+ }
+ wf->sectors[0] = first_sector;
+ wf->nb_sectors = 1;
+ } else if (depth == 1) {
+ wf->sectors = av_malloc(WTV_SECTOR_SIZE);
+ if (!wf->sectors) {
+ av_free(wf);
+ return NULL;
+ }
+ wf->nb_sectors = read_ints(s->pb, wf->sectors, WTV_SECTOR_SIZE / 4);
+ } else if (depth == 2) {
+ uint32_t sectors1[WTV_SECTOR_SIZE / 4];
+ int nb_sectors1 = read_ints(s->pb, sectors1, WTV_SECTOR_SIZE / 4);
+ int i;
+
+ wf->sectors = av_malloc_array(nb_sectors1, 1 << WTV_SECTOR_BITS);
+ if (!wf->sectors) {
+ av_free(wf);
+ return NULL;
+ }
+ wf->nb_sectors = 0;
+ for (i = 0; i < nb_sectors1; i++) {
+ if (seek_by_sector(s->pb, sectors1[i], 0) < 0)
+ break;
+ wf->nb_sectors += read_ints(s->pb, wf->sectors + i * WTV_SECTOR_SIZE / 4, WTV_SECTOR_SIZE / 4);
+ }
+ } else {
+ av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (0x%x)\n", depth);
+ av_free(wf);
+ return NULL;
+ }
+ wf->sector_bits = length & (1ULL<<63) ? WTV_SECTOR_BITS : WTV_BIGSECTOR_BITS;
+
+ if (!wf->nb_sectors) {
+ av_free(wf->sectors);
+ av_free(wf);
+ return NULL;
+ }
+
+ if ((int64_t)wf->sectors[wf->nb_sectors - 1] << WTV_SECTOR_BITS > avio_tell(s->pb))
+ av_log(s, AV_LOG_WARNING, "truncated file\n");
+
+ /* check length */
+ length &= 0xFFFFFFFFFFFF;
+ if (length > ((int64_t)wf->nb_sectors << wf->sector_bits)) {
+ av_log(s, AV_LOG_WARNING, "reported file length (0x%"PRIx64") exceeds number of available sectors (0x%"PRIx64")\n", length, (int64_t)wf->nb_sectors << wf->sector_bits);
+ length = (int64_t)wf->nb_sectors << wf->sector_bits;
+ }
+ wf->length = length;
+
+ /* seek to initial sector */
+ wf->position = 0;
+ if (seek_by_sector(s->pb, wf->sectors[0], 0) < 0) {
+ av_free(wf->sectors);
+ av_free(wf);
+ return NULL;
+ }
+
+ wf->pb_filesystem = s->pb;
+ buffer = av_malloc(1 << wf->sector_bits);
+ if (!buffer) {
+ av_free(wf->sectors);
+ av_free(wf);
+ return NULL;
+ }
+
+ pb = avio_alloc_context(buffer, 1 << wf->sector_bits, 0, wf,
+ wtvfile_read_packet, NULL, wtvfile_seek);
+ if (!pb) {
+ av_free(buffer);
+ av_free(wf->sectors);
+ av_free(wf);
+ }
+ return pb;
+}
+
+/**
+ * Open file using filename
+ * @param[in] buf directory buffer
+ * @param buf_size directory buffer size
+ * @param[in] filename
+ * @param filename_size size of filename
+ * @return NULL on error
+ */
+static AVIOContext * wtvfile_open2(AVFormatContext *s, const uint8_t *buf, int buf_size, const uint8_t *filename, int filename_size)
+{
+ const uint8_t *buf_end = buf + buf_size;
+
+ while(buf + 48 <= buf_end) {
+ int dir_length, name_size, first_sector, depth;
+ uint64_t file_length;
+ const uint8_t *name;
+ if (ff_guidcmp(buf, ff_dir_entry_guid)) {
+ av_log(s, AV_LOG_ERROR, "unknown guid "FF_PRI_GUID", expected dir_entry_guid; "
+ "remaining directory entries ignored\n", FF_ARG_GUID(buf));
+ break;
+ }
+ dir_length = AV_RL16(buf + 16);
+ file_length = AV_RL64(buf + 24);
+ name_size = 2 * AV_RL32(buf + 32);
+ if (name_size < 0) {
+ av_log(s, AV_LOG_ERROR,
+ "bad filename length, remaining directory entries ignored\n");
+ break;
+ }
+ if (48 + (int64_t)name_size > buf_end - buf) {
+ av_log(s, AV_LOG_ERROR, "filename exceeds buffer size; remaining directory entries ignored\n");
+ break;
+ }
+ first_sector = AV_RL32(buf + 40 + name_size);
+ depth = AV_RL32(buf + 44 + name_size);
+
+ /* compare file name; test optional null terminator */
+ name = buf + 40;
+ if (name_size >= filename_size &&
+ !memcmp(name, filename, filename_size) &&
+ (name_size < filename_size + 2 || !AV_RN16(name + filename_size)))
+ return wtvfile_open_sector(first_sector, file_length, depth, s);
+
+ buf += dir_length;
+ }
+ return 0;
+}
+
+#define wtvfile_open(s, buf, buf_size, filename) \
+ wtvfile_open2(s, buf, buf_size, filename, sizeof(filename))
+
+/**
+ * Close file opened with wtvfile_open_sector(), or wtv_open()
+ */
+static void wtvfile_close(AVIOContext *pb)
+{
+ WtvFile *wf = pb->opaque;
+ av_free(wf->sectors);
+ av_freep(&pb->opaque);
+ av_freep(&pb->buffer);
+ av_free(pb);
+}
+
+/*
+ *
+ * Main demuxer
+ *
+ */
+
+typedef struct {
+ int seen_data;
+} WtvStream;
+
+typedef struct {
+ AVIOContext *pb; /**< timeline file */
+ int64_t epoch;
+ int64_t pts; /**< pts for next data chunk */
+ int64_t last_valid_pts; /**< latest valid pts, used for interative seeking */
+
+ /* maintain private seek index, as the AVIndexEntry->pos is relative to the
+ start of the 'timeline' file, not the file system (AVFormatContext->pb) */
+ AVIndexEntry *index_entries;
+ int nb_index_entries;
+ unsigned int index_entries_allocated_size;
+} WtvContext;
+
+/* WTV GUIDs */
+static const ff_asf_guid EVENTID_SubtitleSpanningEvent =
+ {0x48,0xC0,0xCE,0x5D,0xB9,0xD0,0x63,0x41,0x87,0x2C,0x4F,0x32,0x22,0x3B,0xE8,0x8A};
+static const ff_asf_guid EVENTID_LanguageSpanningEvent =
+ {0x6D,0x66,0x92,0xE2,0x02,0x9C,0x8D,0x44,0xAA,0x8D,0x78,0x1A,0x93,0xFD,0xC3,0x95};
+static const ff_asf_guid EVENTID_AudioDescriptorSpanningEvent =
+ {0x1C,0xD4,0x7B,0x10,0xDA,0xA6,0x91,0x46,0x83,0x69,0x11,0xB2,0xCD,0xAA,0x28,0x8E};
+static const ff_asf_guid EVENTID_CtxADescriptorSpanningEvent =
+ {0xE6,0xA2,0xB4,0x3A,0x47,0x42,0x34,0x4B,0x89,0x6C,0x30,0xAF,0xA5,0xD2,0x1C,0x24};
+static const ff_asf_guid EVENTID_CSDescriptorSpanningEvent =
+ {0xD9,0x79,0xE7,0xEf,0xF0,0x97,0x86,0x47,0x80,0x0D,0x95,0xCF,0x50,0x5D,0xDC,0x66};
+static const ff_asf_guid EVENTID_DVBScramblingControlSpanningEvent =
+ {0xC4,0xE1,0xD4,0x4B,0xA1,0x90,0x09,0x41,0x82,0x36,0x27,0xF0,0x0E,0x7D,0xCC,0x5B};
+static const ff_asf_guid EVENTID_StreamIDSpanningEvent =
+ {0x68,0xAB,0xF1,0xCA,0x53,0xE1,0x41,0x4D,0xA6,0xB3,0xA7,0xC9,0x98,0xDB,0x75,0xEE};
+static const ff_asf_guid EVENTID_TeletextSpanningEvent =
+ {0x50,0xD9,0x99,0x95,0x33,0x5F,0x17,0x46,0xAF,0x7C,0x1E,0x54,0xB5,0x10,0xDA,0xA3};
+static const ff_asf_guid EVENTID_AudioTypeSpanningEvent =
+ {0xBE,0xBF,0x1C,0x50,0x49,0xB8,0xCE,0x42,0x9B,0xE9,0x3D,0xB8,0x69,0xFB,0x82,0xB3};
+
+/* Windows media GUIDs */
+
+/* Media types */
+static const ff_asf_guid mediasubtype_mpeg1payload =
+ {0x81,0xEB,0x36,0xE4,0x4F,0x52,0xCE,0x11,0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70};
+static const ff_asf_guid mediatype_mpeg2_sections =
+ {0x6C,0x17,0x5F,0x45,0x06,0x4B,0xCE,0x47,0x9A,0xEF,0x8C,0xAE,0xF7,0x3D,0xF7,0xB5};
+static const ff_asf_guid mediatype_mpeg2_pes =
+ {0x20,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA};
+static const ff_asf_guid mediatype_mstvcaption =
+ {0x89,0x8A,0x8B,0xB8,0x49,0xB0,0x80,0x4C,0xAD,0xCF,0x58,0x98,0x98,0x5E,0x22,0xC1};
+
+/* Media subtypes */
+static const ff_asf_guid mediasubtype_dvb_subtitle =
+ {0xC3,0xCB,0xFF,0x34,0xB3,0xD5,0x71,0x41,0x90,0x02,0xD4,0xC6,0x03,0x01,0x69,0x7F};
+static const ff_asf_guid mediasubtype_teletext =
+ {0xE3,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA};
+static const ff_asf_guid mediasubtype_dtvccdata =
+ {0xAA,0xDD,0x2A,0xF5,0xF0,0x36,0xF5,0x43,0x95,0xEA,0x6D,0x86,0x64,0x84,0x26,0x2A};
+static const ff_asf_guid mediasubtype_mpeg2_sections =
+ {0x79,0x85,0x9F,0x4A,0xF8,0x6B,0x92,0x43,0x8A,0x6D,0xD2,0xDD,0x09,0xFA,0x78,0x61};
+
+/* Formats */
+static const ff_asf_guid format_videoinfo2 =
+ {0xA0,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA};
+
+static int read_probe(AVProbeData *p)
+{
+ return ff_guidcmp(p->buf, ff_wtv_guid) ? 0 : AVPROBE_SCORE_MAX;
+}
+
+/**
+ * Convert win32 FILETIME to ISO-8601 string
+ * @return <0 on error
+ */
+static int filetime_to_iso8601(char *buf, int buf_size, int64_t value)
+{
+ time_t t = (value / 10000000LL) - 11644473600LL;
+ struct tm *tm = gmtime(&t);
+ if (!tm)
+ return -1;
+ strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", gmtime(&t));
+ return 0;
+}
+
+/**
+ * Convert crazy time (100ns since 1 Jan 0001) to ISO-8601 string
+ * @return <0 on error
+ */
+static int crazytime_to_iso8601(char *buf, int buf_size, int64_t value)
+{
+ time_t t = (value / 10000000LL) - 719162LL*86400LL;
+ struct tm *tm = gmtime(&t);
+ if (!tm)
+ return -1;
+ strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", gmtime(&t));
+ return 0;
+}
+
+/**
+ * Convert OLE DATE to ISO-8601 string
+ * @return <0 on error
+ */
+static int oledate_to_iso8601(char *buf, int buf_size, int64_t value)
+{
+ time_t t = (av_int2double(value) - 25569.0) * 86400;
+ struct tm *result= gmtime(&t);
+ if (!result)
+ return -1;
+ strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", result);
+ return 0;
+}
+
+static void get_attachment(AVFormatContext *s, AVIOContext *pb, int length)
+{
+ char mime[1024];
+ char description[1024];
+ unsigned int filesize;
+ AVStream *st;
+ int ret;
+ int64_t pos = avio_tell(pb);
+
+ avio_get_str16le(pb, INT_MAX, mime, sizeof(mime));
+ if (strcmp(mime, "image/jpeg"))
+ goto done;
+
+ avio_r8(pb);
+ avio_get_str16le(pb, INT_MAX, description, sizeof(description));
+ filesize = avio_rl32(pb);
+ if (!filesize)
+ goto done;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ goto done;
+ av_dict_set(&st->metadata, "title", description, 0);
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_MJPEG;
+ st->id = -1;
+ ret = av_get_packet(pb, &st->attached_pic, filesize);
+ if (ret < 0)
+ goto done;
+ st->attached_pic.stream_index = st->index;
+ st->attached_pic.flags |= AV_PKT_FLAG_KEY;
+ st->disposition |= AV_DISPOSITION_ATTACHED_PIC;
+done:
+ avio_seek(pb, pos + length, SEEK_SET);
+}
+
+static void get_tag(AVFormatContext *s, AVIOContext *pb, const char *key, int type, int length)
+{
+ int buf_size;
+ char *buf;
+
+ if (!strcmp(key, "WM/MediaThumbType")) {
+ avio_skip(pb, length);
+ return;
+ }
+
+ buf_size = FFMAX(2*length, LEN_PRETTY_GUID) + 1;
+ buf = av_malloc(buf_size);
+ if (!buf)
+ return;
+
+ if (type == 0 && length == 4) {
+ snprintf(buf, buf_size, "%"PRIi32, avio_rl32(pb));
+ } else if (type == 1) {
+ avio_get_str16le(pb, length, buf, buf_size);
+ if (!strlen(buf)) {
+ av_free(buf);
+ return;
+ }
+ } else if (type == 3 && length == 4) {
+ strcpy(buf, avio_rl32(pb) ? "true" : "false");
+ } else if (type == 4 && length == 8) {
+ int64_t num = avio_rl64(pb);
+ if (!strcmp(key, "WM/EncodingTime") ||
+ !strcmp(key, "WM/MediaOriginalBroadcastDateTime")) {
+ if (filetime_to_iso8601(buf, buf_size, num) < 0) {
+ av_free(buf);
+ return;
+ }
+ } else if (!strcmp(key, "WM/WMRVEncodeTime") ||
+ !strcmp(key, "WM/WMRVEndTime")) {
+ if (crazytime_to_iso8601(buf, buf_size, num) < 0) {
+ av_free(buf);
+ return;
+ }
+ } else if (!strcmp(key, "WM/WMRVExpirationDate")) {
+ if (oledate_to_iso8601(buf, buf_size, num) < 0 ) {
+ av_free(buf);
+ return;
+ }
+ } else if (!strcmp(key, "WM/WMRVBitrate"))
+ snprintf(buf, buf_size, "%f", av_int2double(num));
+ else
+ snprintf(buf, buf_size, "%"PRIi64, num);
+ } else if (type == 5 && length == 2) {
+ snprintf(buf, buf_size, "%"PRIi16, avio_rl16(pb));
+ } else if (type == 6 && length == 16) {
+ ff_asf_guid guid;
+ avio_read(pb, guid, 16);
+ snprintf(buf, buf_size, PRI_PRETTY_GUID, ARG_PRETTY_GUID(guid));
+ } else if (type == 2 && !strcmp(key, "WM/Picture")) {
+ get_attachment(s, pb, length);
+ av_freep(&buf);
+ return;
+ } else {
+ av_freep(&buf);
+ av_log(s, AV_LOG_WARNING, "unsupported metadata entry; key:%s, type:%d, length:0x%x\n", key, type, length);
+ avio_skip(pb, length);
+ return;
+ }
+
+ av_dict_set(&s->metadata, key, buf, 0);
+ av_freep(&buf);
+}
+
+/**
+ * Parse metadata entries
+ */
+static void parse_legacy_attrib(AVFormatContext *s, AVIOContext *pb)
+{
+ ff_asf_guid guid;
+ int length, type;
+ while(!url_feof(pb)) {
+ char key[1024];
+ ff_get_guid(pb, &guid);
+ type = avio_rl32(pb);
+ length = avio_rl32(pb);
+ if (!length)
+ break;
+ if (ff_guidcmp(&guid, ff_metadata_guid)) {
+ av_log(s, AV_LOG_WARNING, "unknown guid "FF_PRI_GUID", expected metadata_guid; "
+ "remaining metadata entries ignored\n", FF_ARG_GUID(guid));
+ break;
+ }
+ avio_get_str16le(pb, INT_MAX, key, sizeof(key));
+ get_tag(s, pb, key, type, length);
+ }
+
+ ff_metadata_conv(&s->metadata, NULL, ff_asf_metadata_conv);
+}
+
+/**
+ * parse VIDEOINFOHEADER2 structure
+ * @return bytes consumed
+ */
+static int parse_videoinfoheader2(AVFormatContext *s, AVStream *st)
+{
+ WtvContext *wtv = s->priv_data;
+ AVIOContext *pb = wtv->pb;
+
+ avio_skip(pb, 72); // picture aspect ratio is unreliable
+ ff_get_bmp_header(pb, st, NULL);
+
+ return 72 + 40;
+}
+
+/**
+ * Parse MPEG1WAVEFORMATEX extradata structure
+ */
+static void parse_mpeg1waveformatex(AVStream *st)
+{
+ /* fwHeadLayer */
+ switch (AV_RL16(st->codec->extradata)) {
+ case 0x0001 : st->codec->codec_id = AV_CODEC_ID_MP1; break;
+ case 0x0002 : st->codec->codec_id = AV_CODEC_ID_MP2; break;
+ case 0x0004 : st->codec->codec_id = AV_CODEC_ID_MP3; break;
+ }
+
+ st->codec->bit_rate = AV_RL32(st->codec->extradata + 2); /* dwHeadBitrate */
+
+ /* dwHeadMode */
+ switch (AV_RL16(st->codec->extradata + 6)) {
+ case 1 :
+ case 2 :
+ case 4 : st->codec->channels = 2;
+ st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
+ break;
+ case 8 : st->codec->channels = 1;
+ st->codec->channel_layout = AV_CH_LAYOUT_MONO;
+ break;
+ }
+}
+
+/**
+ * Initialise stream
+ * @param st Stream to initialise, or NULL to create and initialise new stream
+ * @return NULL on error
+ */
+static AVStream * new_stream(AVFormatContext *s, AVStream *st, int sid, int codec_type)
+{
+ if (st) {
+ if (st->codec->extradata) {
+ av_freep(&st->codec->extradata);
+ st->codec->extradata_size = 0;
+ }
+ } else {
+ WtvStream *wst = av_mallocz(sizeof(WtvStream));
+ if (!wst)
+ return NULL;
+ st = avformat_new_stream(s, NULL);
+ if (!st) {
+ av_free(wst);
+ return NULL;
+ }
+ st->id = sid;
+ st->priv_data = wst;
+ }
+ st->codec->codec_type = codec_type;
+ st->need_parsing = AVSTREAM_PARSE_FULL;
+ avpriv_set_pts_info(st, 64, 1, 10000000);
+ return st;
+}
+
+/**
+ * parse Media Type structure and populate stream
+ * @param st Stream, or NULL to create new stream
+ * @param mediatype Mediatype GUID
+ * @param subtype Subtype GUID
+ * @param formattype Format GUID
+ * @param size Size of format buffer
+ * @return NULL on error
+ */
+static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid,
+ ff_asf_guid mediatype, ff_asf_guid subtype,
+ ff_asf_guid formattype, int size)
+{
+ WtvContext *wtv = s->priv_data;
+ AVIOContext *pb = wtv->pb;
+ if (!ff_guidcmp(subtype, ff_mediasubtype_cpfilters_processed) &&
+ !ff_guidcmp(formattype, ff_format_cpfilters_processed)) {
+ ff_asf_guid actual_subtype;
+ ff_asf_guid actual_formattype;
+
+ if (size < 32) {
+ av_log(s, AV_LOG_WARNING, "format buffer size underflow\n");
+ avio_skip(pb, size);
+ return NULL;
+ }
+
+ avio_skip(pb, size - 32);
+ ff_get_guid(pb, &actual_subtype);
+ ff_get_guid(pb, &actual_formattype);
+ avio_seek(pb, -size, SEEK_CUR);
+
+ st = parse_media_type(s, st, sid, mediatype, actual_subtype, actual_formattype, size - 32);
+ avio_skip(pb, 32);
+ return st;
+ } else if (!ff_guidcmp(mediatype, ff_mediatype_audio)) {
+ st = new_stream(s, st, sid, AVMEDIA_TYPE_AUDIO);
+ if (!st)
+ return NULL;
+ if (!ff_guidcmp(formattype, ff_format_waveformatex)) {
+ int ret = ff_get_wav_header(pb, st->codec, size);
+ if (ret < 0)
+ return NULL;
+ } else {
+ if (ff_guidcmp(formattype, ff_format_none))
+ av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
+ avio_skip(pb, size);
+ }
+
+ if (!memcmp(subtype + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) {
+ st->codec->codec_id = ff_wav_codec_get_id(AV_RL32(subtype), st->codec->bits_per_coded_sample);
+ } else if (!ff_guidcmp(subtype, mediasubtype_mpeg1payload)) {
+ if (st->codec->extradata && st->codec->extradata_size >= 22)
+ parse_mpeg1waveformatex(st);
+ else
+ av_log(s, AV_LOG_WARNING, "MPEG1WAVEFORMATEX underflow\n");
+ } else {
+ st->codec->codec_id = ff_codec_guid_get_id(ff_codec_wav_guids, subtype);
+ if (st->codec->codec_id == AV_CODEC_ID_NONE)
+ av_log(s, AV_LOG_WARNING, "unknown subtype:"FF_PRI_GUID"\n", FF_ARG_GUID(subtype));
+ }
+ return st;
+ } else if (!ff_guidcmp(mediatype, ff_mediatype_video)) {
+ st = new_stream(s, st, sid, AVMEDIA_TYPE_VIDEO);
+ if (!st)
+ return NULL;
+ if (!ff_guidcmp(formattype, format_videoinfo2)) {
+ int consumed = parse_videoinfoheader2(s, st);
+ avio_skip(pb, FFMAX(size - consumed, 0));
+ } else if (!ff_guidcmp(formattype, ff_format_mpeg2_video)) {
+ int consumed = parse_videoinfoheader2(s, st);
+ avio_skip(pb, FFMAX(size - consumed, 0));
+ } else {
+ if (ff_guidcmp(formattype, ff_format_none))
+ av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
+ avio_skip(pb, size);
+ }
+
+ if (!memcmp(subtype + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) {
+ st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(subtype));
+ } else {
+ st->codec->codec_id = ff_codec_guid_get_id(ff_video_guids, subtype);
+ }
+ if (st->codec->codec_id == AV_CODEC_ID_NONE)
+ av_log(s, AV_LOG_WARNING, "unknown subtype:"FF_PRI_GUID"\n", FF_ARG_GUID(subtype));
+ return st;
+ } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_pes) &&
+ !ff_guidcmp(subtype, mediasubtype_dvb_subtitle)) {
+ st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE);
+ if (!st)
+ return NULL;
+ if (ff_guidcmp(formattype, ff_format_none))
+ av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
+ avio_skip(pb, size);
+ st->codec->codec_id = AV_CODEC_ID_DVB_SUBTITLE;
+ return st;
+ } else if (!ff_guidcmp(mediatype, mediatype_mstvcaption) &&
+ (!ff_guidcmp(subtype, mediasubtype_teletext) || !ff_guidcmp(subtype, mediasubtype_dtvccdata))) {
+ st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE);
+ if (!st)
+ return NULL;
+ if (ff_guidcmp(formattype, ff_format_none))
+ av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
+ avio_skip(pb, size);
+ st->codec->codec_id = !ff_guidcmp(subtype, mediasubtype_teletext) ? AV_CODEC_ID_DVB_TELETEXT : AV_CODEC_ID_EIA_608;
+ return st;
+ } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_sections) &&
+ !ff_guidcmp(subtype, mediasubtype_mpeg2_sections)) {
+ if (ff_guidcmp(formattype, ff_format_none))
+ av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
+ avio_skip(pb, size);
+ return NULL;
+ }
+
+ av_log(s, AV_LOG_WARNING, "unknown media type, mediatype:"FF_PRI_GUID
+ ", subtype:"FF_PRI_GUID", formattype:"FF_PRI_GUID"\n",
+ FF_ARG_GUID(mediatype), FF_ARG_GUID(subtype), FF_ARG_GUID(formattype));
+ avio_skip(pb, size);
+ return NULL;
+}
+
+enum {
+ SEEK_TO_DATA = 0,
+ SEEK_TO_PTS,
+};
+
+/**
+ * Parse WTV chunks
+ * @param mode SEEK_TO_DATA or SEEK_TO_PTS
+ * @param seekts timestamp
+ * @param[out] len_ptr Length of data chunk
+ * @return stream index of data chunk, or <0 on error
+ */
+static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_ptr)
+{
+ WtvContext *wtv = s->priv_data;
+ AVIOContext *pb = wtv->pb;
+ while (!url_feof(pb)) {
+ ff_asf_guid g;
+ int len, sid, consumed;
+
+ ff_get_guid(pb, &g);
+ len = avio_rl32(pb);
+ if (len < 32)
+ break;
+ sid = avio_rl32(pb) & 0x7FFF;
+ avio_skip(pb, 8);
+ consumed = 32;
+
+ if (!ff_guidcmp(g, ff_SBE2_STREAM_DESC_EVENT)) {
+ if (ff_find_stream_index(s, sid) < 0) {
+ ff_asf_guid mediatype, subtype, formattype;
+ int size;
+ avio_skip(pb, 28);
+ ff_get_guid(pb, &mediatype);
+ ff_get_guid(pb, &subtype);
+ avio_skip(pb, 12);
+ ff_get_guid(pb, &formattype);
+ size = avio_rl32(pb);
+ parse_media_type(s, 0, sid, mediatype, subtype, formattype, size);
+ consumed += 92 + size;
+ }
+ } else if (!ff_guidcmp(g, ff_stream2_guid)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0 && s->streams[stream_index]->priv_data && !((WtvStream*)s->streams[stream_index]->priv_data)->seen_data) {
+ ff_asf_guid mediatype, subtype, formattype;
+ int size;
+ avio_skip(pb, 12);
+ ff_get_guid(pb, &mediatype);
+ ff_get_guid(pb, &subtype);
+ avio_skip(pb, 12);
+ ff_get_guid(pb, &formattype);
+ size = avio_rl32(pb);
+ parse_media_type(s, s->streams[stream_index], sid, mediatype, subtype, formattype, size);
+ consumed += 76 + size;
+ }
+ } else if (!ff_guidcmp(g, EVENTID_AudioDescriptorSpanningEvent) ||
+ !ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) ||
+ !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent) ||
+ !ff_guidcmp(g, EVENTID_StreamIDSpanningEvent) ||
+ !ff_guidcmp(g, EVENTID_SubtitleSpanningEvent) ||
+ !ff_guidcmp(g, EVENTID_TeletextSpanningEvent)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0) {
+ AVStream *st = s->streams[stream_index];
+ uint8_t buf[258];
+ const uint8_t *pbuf = buf;
+ int buf_size;
+
+ avio_skip(pb, 8);
+ consumed += 8;
+ if (!ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) ||
+ !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent)) {
+ avio_skip(pb, 6);
+ consumed += 6;
+ }
+
+ buf_size = FFMIN(len - consumed, sizeof(buf));
+ avio_read(pb, buf, buf_size);
+ consumed += buf_size;
+ ff_parse_mpeg2_descriptor(s, st, 0, &pbuf, buf + buf_size, NULL, 0, 0, NULL);
+ }
+ } else if (!ff_guidcmp(g, EVENTID_AudioTypeSpanningEvent)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0) {
+ AVStream *st = s->streams[stream_index];
+ int audio_type;
+ avio_skip(pb, 8);
+ audio_type = avio_r8(pb);
+ if (audio_type == 2)
+ st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED;
+ else if (audio_type == 3)
+ st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
+ consumed += 9;
+ }
+ } else if (!ff_guidcmp(g, EVENTID_DVBScramblingControlSpanningEvent)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0) {
+ avio_skip(pb, 12);
+ if (avio_rl32(pb))
+ av_log(s, AV_LOG_WARNING, "DVB scrambled stream detected (st:%d), decoding will likely fail\n", stream_index);
+ consumed += 16;
+ }
+ } else if (!ff_guidcmp(g, EVENTID_LanguageSpanningEvent)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0) {
+ AVStream *st = s->streams[stream_index];
+ uint8_t language[4];
+ avio_skip(pb, 12);
+ avio_read(pb, language, 3);
+ if (language[0]) {
+ language[3] = 0;
+ av_dict_set(&st->metadata, "language", language, 0);
+ if (!strcmp(language, "nar") || !strcmp(language, "NAR"))
+ st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
+ }
+ consumed += 15;
+ }
+ } else if (!ff_guidcmp(g, ff_timestamp_guid)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0) {
+ avio_skip(pb, 8);
+ wtv->pts = avio_rl64(pb);
+ consumed += 16;
+ if (wtv->pts == -1)
+ wtv->pts = AV_NOPTS_VALUE;
+ else {
+ wtv->last_valid_pts = wtv->pts;
+ if (wtv->epoch == AV_NOPTS_VALUE || wtv->pts < wtv->epoch)
+ wtv->epoch = wtv->pts;
+ if (mode == SEEK_TO_PTS && wtv->pts >= seekts) {
+ avio_skip(pb, WTV_PAD8(len) - consumed);
+ return 0;
+ }
+ }
+ }
+ } else if (!ff_guidcmp(g, ff_data_guid)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (mode == SEEK_TO_DATA && stream_index >= 0 && len > 32 && s->streams[stream_index]->priv_data) {
+ WtvStream *wst = s->streams[stream_index]->priv_data;
+ wst->seen_data = 1;
+ if (len_ptr) {
+ *len_ptr = len;
+ }
+ return stream_index;
+ }
+ } else if (!ff_guidcmp(g, /* DSATTRIB_WMDRMProtectionInfo */ (const ff_asf_guid){0x83,0x95,0x74,0x40,0x9D,0x6B,0xEC,0x4E,0xB4,0x3C,0x67,0xA1,0x80,0x1E,0x1A,0x9B})) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0)
+ av_log(s, AV_LOG_WARNING, "encrypted stream detected (st:%d), decoding will likely fail\n", stream_index);
+ } else if (
+ !ff_guidcmp(g, /* DSATTRIB_CAPTURE_STREAMTIME */ (const ff_asf_guid){0x14,0x56,0x1A,0x0C,0xCD,0x30,0x40,0x4F,0xBC,0xBF,0xD0,0x3E,0x52,0x30,0x62,0x07}) ||
+ !ff_guidcmp(g, /* DSATTRIB_PBDATAG_ATTRIBUTE */ (const ff_asf_guid){0x79,0x66,0xB5,0xE0,0xB9,0x12,0xCC,0x43,0xB7,0xDF,0x57,0x8C,0xAA,0x5A,0x7B,0x63}) ||
+ !ff_guidcmp(g, /* DSATTRIB_PicSampleSeq */ (const ff_asf_guid){0x02,0xAE,0x5B,0x2F,0x8F,0x7B,0x60,0x4F,0x82,0xD6,0xE4,0xEA,0x2F,0x1F,0x4C,0x99}) ||
+ !ff_guidcmp(g, /* DSATTRIB_TRANSPORT_PROPERTIES */ ff_DSATTRIB_TRANSPORT_PROPERTIES) ||
+ !ff_guidcmp(g, /* dvr_ms_vid_frame_rep_data */ (const ff_asf_guid){0xCC,0x32,0x64,0xDD,0x29,0xE2,0xDB,0x40,0x80,0xF6,0xD2,0x63,0x28,0xD2,0x76,0x1F}) ||
+ !ff_guidcmp(g, /* EVENTID_ChannelChangeSpanningEvent */ (const ff_asf_guid){0xE5,0xC5,0x67,0x90,0x5C,0x4C,0x05,0x42,0x86,0xC8,0x7A,0xFE,0x20,0xFE,0x1E,0xFA}) ||
+ !ff_guidcmp(g, /* EVENTID_ChannelInfoSpanningEvent */ (const ff_asf_guid){0x80,0x6D,0xF3,0x41,0x32,0x41,0xC2,0x4C,0xB1,0x21,0x01,0xA4,0x32,0x19,0xD8,0x1B}) ||
+ !ff_guidcmp(g, /* EVENTID_ChannelTypeSpanningEvent */ (const ff_asf_guid){0x51,0x1D,0xAB,0x72,0xD2,0x87,0x9B,0x48,0xBA,0x11,0x0E,0x08,0xDC,0x21,0x02,0x43}) ||
+ !ff_guidcmp(g, /* EVENTID_PIDListSpanningEvent */ (const ff_asf_guid){0x65,0x8F,0xFC,0x47,0xBB,0xE2,0x34,0x46,0x9C,0xEF,0xFD,0xBF,0xE6,0x26,0x1D,0x5C}) ||
+ !ff_guidcmp(g, /* EVENTID_SignalAndServiceStatusSpanningEvent */ (const ff_asf_guid){0xCB,0xC5,0x68,0x80,0x04,0x3C,0x2B,0x49,0xB4,0x7D,0x03,0x08,0x82,0x0D,0xCE,0x51}) ||
+ !ff_guidcmp(g, /* EVENTID_StreamTypeSpanningEvent */ (const ff_asf_guid){0xBC,0x2E,0xAF,0x82,0xA6,0x30,0x64,0x42,0xA8,0x0B,0xAD,0x2E,0x13,0x72,0xAC,0x60}) ||
+ !ff_guidcmp(g, (const ff_asf_guid){0x1E,0xBE,0xC3,0xC5,0x43,0x92,0xDC,0x11,0x85,0xE5,0x00,0x12,0x3F,0x6F,0x73,0xB9}) ||
+ !ff_guidcmp(g, (const ff_asf_guid){0x3B,0x86,0xA2,0xB1,0xEB,0x1E,0xC3,0x44,0x8C,0x88,0x1C,0xA3,0xFF,0xE3,0xE7,0x6A}) ||
+ !ff_guidcmp(g, (const ff_asf_guid){0x4E,0x7F,0x4C,0x5B,0xC4,0xD0,0x38,0x4B,0xA8,0x3E,0x21,0x7F,0x7B,0xBF,0x52,0xE7}) ||
+ !ff_guidcmp(g, (const ff_asf_guid){0x63,0x36,0xEB,0xFE,0xA1,0x7E,0xD9,0x11,0x83,0x08,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) ||
+ !ff_guidcmp(g, (const ff_asf_guid){0x70,0xE9,0xF1,0xF8,0x89,0xA4,0x4C,0x4D,0x83,0x73,0xB8,0x12,0xE0,0xD5,0xF8,0x1E}) ||
+ !ff_guidcmp(g, ff_index_guid) ||
+ !ff_guidcmp(g, ff_sync_guid) ||
+ !ff_guidcmp(g, ff_stream1_guid) ||
+ !ff_guidcmp(g, (const ff_asf_guid){0xF7,0x10,0x02,0xB9,0xEE,0x7C,0xED,0x4E,0xBD,0x7F,0x05,0x40,0x35,0x86,0x18,0xA1})) {
+ //ignore known guids
+ } else
+ av_log(s, AV_LOG_WARNING, "unsupported chunk:"FF_PRI_GUID"\n", FF_ARG_GUID(g));
+
+ avio_skip(pb, WTV_PAD8(len) - consumed);
+ }
+ return AVERROR_EOF;
+}
+
+static int read_header(AVFormatContext *s)
+{
+ WtvContext *wtv = s->priv_data;
+ int root_sector, root_size;
+ uint8_t root[WTV_SECTOR_SIZE];
+ AVIOContext *pb;
+ int64_t timeline_pos;
+ int ret;
+
+ wtv->epoch =
+ wtv->pts =
+ wtv->last_valid_pts = AV_NOPTS_VALUE;
+
+ /* read root directory sector */
+ avio_skip(s->pb, 0x30);
+ root_size = avio_rl32(s->pb);
+ if (root_size > sizeof(root)) {
+ av_log(s, AV_LOG_ERROR, "root directory size exceeds sector size\n");
+ return AVERROR_INVALIDDATA;
+ }
+ avio_skip(s->pb, 4);
+ root_sector = avio_rl32(s->pb);
+
+ seek_by_sector(s->pb, root_sector, 0);
+ root_size = avio_read(s->pb, root, root_size);
+ if (root_size < 0)
+ return AVERROR_INVALIDDATA;
+
+ /* parse chunks up until first data chunk */
+ wtv->pb = wtvfile_open(s, root, root_size, ff_timeline_le16);
+ if (!wtv->pb) {
+ av_log(s, AV_LOG_ERROR, "timeline data missing\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ret = parse_chunks(s, SEEK_TO_DATA, 0, 0);
+ if (ret < 0)
+ return ret;
+ avio_seek(wtv->pb, -32, SEEK_CUR);
+
+ timeline_pos = avio_tell(s->pb); // save before opening another file
+
+ /* read metadata */
+ pb = wtvfile_open(s, root, root_size, ff_table_0_entries_legacy_attrib_le16);
+ if (pb) {
+ parse_legacy_attrib(s, pb);
+ wtvfile_close(pb);
+ }
+
+ /* read seek index */
+ if (s->nb_streams) {
+ AVStream *st = s->streams[0];
+ pb = wtvfile_open(s, root, root_size, ff_table_0_entries_time_le16);
+ if (pb) {
+ while(1) {
+ uint64_t timestamp = avio_rl64(pb);
+ uint64_t frame_nb = avio_rl64(pb);
+ if (url_feof(pb))
+ break;
+ ff_add_index_entry(&wtv->index_entries, &wtv->nb_index_entries, &wtv->index_entries_allocated_size,
+ 0, timestamp, frame_nb, 0, AVINDEX_KEYFRAME);
+ }
+ wtvfile_close(pb);
+
+ if (wtv->nb_index_entries) {
+ pb = wtvfile_open(s, root, root_size, ff_timeline_table_0_entries_Events_le16);
+ if (pb) {
+ int i;
+ while (1) {
+ uint64_t frame_nb = avio_rl64(pb);
+ uint64_t position = avio_rl64(pb);
+ if (url_feof(pb))
+ break;
+ for (i = wtv->nb_index_entries - 1; i >= 0; i--) {
+ AVIndexEntry *e = wtv->index_entries + i;
+ if (frame_nb > e->size)
+ break;
+ if (position > e->pos)
+ e->pos = position;
+ }
+ }
+ wtvfile_close(pb);
+ st->duration = wtv->index_entries[wtv->nb_index_entries - 1].timestamp;
+ }
+ }
+ }
+ }
+
+ avio_seek(s->pb, timeline_pos, SEEK_SET);
+ return 0;
+}
+
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ WtvContext *wtv = s->priv_data;
+ AVIOContext *pb = wtv->pb;
+ int stream_index, len, ret;
+
+ stream_index = parse_chunks(s, SEEK_TO_DATA, 0, &len);
+ if (stream_index < 0)
+ return stream_index;
+
+ ret = av_get_packet(pb, pkt, len - 32);
+ if (ret < 0)
+ return ret;
+ pkt->stream_index = stream_index;
+ pkt->pts = wtv->pts;
+ avio_skip(pb, WTV_PAD8(len) - len);
+ return 0;
+}
+
+static int read_seek(AVFormatContext *s, int stream_index,
+ int64_t ts, int flags)
+{
+ WtvContext *wtv = s->priv_data;
+ AVIOContext *pb = wtv->pb;
+ AVStream *st = s->streams[0];
+ int64_t ts_relative;
+ int i;
+
+ if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
+ return AVERROR(ENOSYS);
+
+ /* timestamp adjustment is required because wtv->pts values are absolute,
+ * whereas AVIndexEntry->timestamp values are relative to epoch. */
+ ts_relative = ts;
+ if (wtv->epoch != AV_NOPTS_VALUE)
+ ts_relative -= wtv->epoch;
+
+ i = ff_index_search_timestamp(wtv->index_entries, wtv->nb_index_entries, ts_relative, flags);
+ if (i < 0) {
+ if (wtv->last_valid_pts == AV_NOPTS_VALUE || ts < wtv->last_valid_pts) {
+ if (avio_seek(pb, 0, SEEK_SET) < 0)
+ return -1;
+ } else if (st->duration != AV_NOPTS_VALUE && ts_relative > st->duration && wtv->nb_index_entries) {
+ if (avio_seek(pb, wtv->index_entries[wtv->nb_index_entries - 1].pos, SEEK_SET) < 0)
+ return -1;
+ }
+ if (parse_chunks(s, SEEK_TO_PTS, ts, 0) < 0)
+ return AVERROR(ERANGE);
+ return 0;
+ }
+ if (avio_seek(pb, wtv->index_entries[i].pos, SEEK_SET) < 0)
+ return -1;
+ wtv->pts = wtv->index_entries[i].timestamp;
+ if (wtv->epoch != AV_NOPTS_VALUE)
+ wtv->pts += wtv->epoch;
+ wtv->last_valid_pts = wtv->pts;
+ return 0;
+}
+
+static int read_close(AVFormatContext *s)
+{
+ WtvContext *wtv = s->priv_data;
+ av_freep(&wtv->index_entries);
+ wtvfile_close(wtv->pb);
+ return 0;
+}
+
+AVInputFormat ff_wtv_demuxer = {
+ .name = "wtv",
+ .long_name = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"),
+ .priv_data_size = sizeof(WtvContext),
+ .read_probe = read_probe,
+ .read_header = read_header,
+ .read_packet = read_packet,
+ .read_seek = read_seek,
+ .read_close = read_close,
+ .flags = AVFMT_SHOW_IDS,
+};
diff --git a/libavformat/wtvenc.c b/libavformat/wtvenc.c
new file mode 100644
index 0000000..04e6cc2
--- a/dev/null
+++ b/libavformat/wtvenc.c
@@ -0,0 +1,805 @@
+/*
+ * 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 "wtv.h"
+#include "asf.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)
+
+static 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;
+}
+
+/**
+ * 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 int write_stream_codec_info(AVFormatContext *s, AVStream *st)
+{
+ WtvContext *wctx = s->priv_data;
+ const ff_asf_guid *g, *media_type, *format_type;
+ 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 = &ff_format_mpeg2_video;
+ } 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;
+ } else {
+ av_log(s, AV_LOG_ERROR, "unknown codec_type (0x%x)\n", st->codec->codec_type);
+ return -1;
+ }
+
+ if (g == NULL) {
+ av_log(s, AV_LOG_ERROR, "can't get video codec_id (0x%x) guid.\n", st->codec->codec_id);
+ 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) {
+ if (wctx->first_video_flag) {
+ write_pad(pb, 216); //The size is sensitive.
+ wctx->first_video_flag = 0;
+ } else {
+ write_pad(pb, 72); // aspect ratio
+ ff_put_bmp_header(pb, st->codec, ff_codec_bmp_tags, 0);
+ }
+ } else {
+ ff_put_wav_header(pb, st->codec);
+ }
+ 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);
+ ff_put_guid(pb, g); // actual_subtype
+ 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;
+
+ if (s->streams[pkt->stream_index]->codec->codec_id == AV_CODEC_ID_MJPEG && !wctx->thumbnail.size) {
+ av_copy_packet(&wctx->thumbnail, pkt);
+ return 0;
+ }
+
+ /* 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..4eaec40 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;
@@ -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 (url_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 2b2fd45..20f9bea 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,10 +182,6 @@ 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));
if (!xmv->audio) {
ret = AVERROR(ENOMEM);
@@ -196,25 +189,23 @@ static int xmv_read_header(AVFormatContext *s)
}
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 %d.\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 f4ff815..135faf2 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
*/
diff --git a/libavformat/yop.c b/libavformat/yop.c
index 8caeb07..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,11 @@ 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_size = 8;
-
- video_stream->codec->extradata = av_mallocz(video_stream->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
-
- if (!video_stream->codec->extradata)
+ if (ff_alloc_extradata(video_stream->codec, 8))
return AVERROR(ENOMEM);
// Audio
@@ -99,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.c b/libavformat/yuv4mpeg.c
index cc2755f..1999c73 100644
--- a/libavformat/yuv4mpeg.c
+++ b/libavformat/yuv4mpeg.c
@@ -2,20 +2,20 @@
* YUV4MPEG format
* 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
*/
@@ -27,11 +27,6 @@
#define Y4M_FRAME_MAGIC "FRAME"
#define Y4M_LINE_MAX 256
-struct frame_attributes {
- int interlaced_frame;
- int top_field_first;
-};
-
#if CONFIG_YUV4MPEGPIPE_MUXER
static int yuv4_generate_header(AVFormatContext *s, char* buf)
{
@@ -57,11 +52,21 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf)
inter = 'p'; /* progressive is the default */
if (st->codec->coded_frame && st->codec->coded_frame->interlaced_frame)
inter = st->codec->coded_frame->top_field_first ? 't' : 'b';
+ if (st->codec->field_order == AV_FIELD_PROGRESSIVE) {
+ inter = 'p';
+ } else if (st->codec->field_order == AV_FIELD_TB || st->codec->field_order == AV_FIELD_TT) {
+ inter = 't';
+ } else if (st->codec->field_order == AV_FIELD_BT || st->codec->field_order == AV_FIELD_BB) {
+ inter = 'b';
+ }
switch (st->codec->pix_fmt) {
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;
@@ -78,6 +83,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 */
@@ -92,7 +142,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;
@@ -100,7 +150,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) {
@@ -123,18 +174,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];
@@ -147,6 +230,7 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
ptr2 += picture->linesize[2];
}
}
+
return 0;
}
@@ -162,15 +246,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->streams[0]->codec->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);
}
@@ -182,7 +301,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,
@@ -201,7 +319,7 @@ static int yuv4_read_header(AVFormatContext *s)
{
char header[MAX_YUV4_HEADER + 10]; // Include headroom for
// the longest option
- char *tokstart, *tokend, *header_end;
+ char *tokstart, *tokend, *header_end, interlaced = '?';
int i;
AVIOContext *pb = s->pb;
int width = -1, height = -1, raten = 0,
@@ -209,7 +327,6 @@ static int yuv4_read_header(AVFormatContext *s)
enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE, alt_pix_fmt = AV_PIX_FMT_NONE;
enum AVChromaLocation chroma_sample_location = AVCHROMA_LOC_UNSPECIFIED;
AVStream *st;
- struct frame_attributes *s1 = s->priv_data;
for (i = 0; i < MAX_YUV4_HEADER; i++) {
header[i] = avio_r8(pb);
@@ -225,8 +342,6 @@ static int yuv4_read_header(AVFormatContext *s)
if (strncmp(header, Y4M_MAGIC, strlen(Y4M_MAGIC)))
return -1;
- s1->interlaced_frame = 0;
- s1->top_field_first = 0;
header_end = &header[i + 1]; // Include space
for (tokstart = &header[strlen(Y4M_MAGIC) + 1];
tokstart < header_end; tokstart++) {
@@ -251,20 +366,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 "
@@ -275,28 +422,7 @@ static int yuv4_read_header(AVFormatContext *s)
tokstart++;
break;
case 'I': // Interlace type
- switch (*tokstart++){
- case '?':
- break;
- case 'p':
- s1->interlaced_frame = 0;
- break;
- case 't':
- s1->interlaced_frame = 1;
- s1->top_field_first = 1;
- break;
- case 'b':
- s1->interlaced_frame = 1;
- s1->top_field_first = 0;
- break;
- 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;
- }
+ interlaced = *tokstart++;
break;
case 'F': // Frame rate
sscanf(tokstart, "%d:%d", &raten, &rated); // 0:0 if unknown
@@ -318,6 +444,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)
@@ -367,6 +523,27 @@ static int yuv4_read_header(AVFormatContext *s)
st->sample_aspect_ratio = (AVRational){ aspectn, aspectd };
st->codec->chroma_sample_location = chroma_sample_location;
+ switch (interlaced){
+ case 'p':
+ st->codec->field_order = AV_FIELD_PROGRESSIVE;
+ break;
+ case 't':
+ st->codec->field_order = AV_FIELD_TB;
+ break;
+ case 'b':
+ st->codec->field_order = AV_FIELD_BT;
+ break;
+ case 'm':
+ av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains mixed "
+ "interlaced and non-interlaced frames.\n");
+ case '?':
+ st->codec->field_order = AV_FIELD_UNKNOWN;
+ break;
+ default:
+ av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n");
+ return AVERROR(EINVAL);
+ }
+
return 0;
}
@@ -376,7 +553,6 @@ static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt)
char header[MAX_FRAME_HEADER+1];
int packet_size, width, height, ret;
AVStream *st = s->streams[0];
- struct frame_attributes *s1 = s->priv_data;
for (i = 0; i < MAX_FRAME_HEADER; i++) {
header[i] = avio_r8(s->pb);
@@ -408,11 +584,6 @@ static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt)
else if (ret != packet_size)
return s->pb->eof_reached ? AVERROR_EOF : AVERROR(EIO);
- if (st->codec->coded_frame) {
- st->codec->coded_frame->interlaced_frame = s1->interlaced_frame;
- st->codec->coded_frame->top_field_first = s1->top_field_first;
- }
-
pkt->stream_index = 0;
return 0;
}
@@ -430,7 +601,6 @@ static int yuv4_probe(AVProbeData *pd)
AVInputFormat ff_yuv4mpegpipe_demuxer = {
.name = "yuv4mpegpipe",
.long_name = NULL_IF_CONFIG_SMALL("YUV4MPEG pipe"),
- .priv_data_size = sizeof(struct frame_attributes),
.read_probe = yuv4_probe,
.read_header = yuv4_read_header,
.read_packet = yuv4_read_packet,
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 092ce0c..98f77f0 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/audio_convert.c b/libavresample/audio_convert.c
index 371617c..e73105d 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 6a3089d..5cf6b9d 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 c52f518..1521d7e 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 97236bb..b2b8bdd 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 073609e..1b48fe5 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
*/
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 8da1b48..935ed5a 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 d26f2ca..f62e533 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
*/
@@ -272,7 +272,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/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 057f89a..2946126 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 7859ec6..a0dda6f 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 69c9bab..525828c 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 4544dab..3b56baa 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 5b0fbec..06da90f 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 2dd3d06..db1e087 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/log.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
@@ -627,10 +627,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 3cc4441..bd52ca6 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 932f6f2..bec88b0 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/libavutil/Makefile b/libavutil/Makefile
index 9381c77..7b3b439 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -1,3 +1,5 @@
+include $(SUBDIR)../config.mak
+
NAME = avutil
HEADERS = adler32.h \
@@ -10,6 +12,7 @@ HEADERS = adler32.h \
avutil.h \
base64.h \
blowfish.h \
+ bprint.h \
bswap.h \
buffer.h \
channel_layout.h \
@@ -31,6 +34,7 @@ HEADERS = adler32.h \
mathematics.h \
md5.h \
mem.h \
+ murmur3.h \
dict.h \
old_pix_fmts.h \
opt.h \
@@ -39,14 +43,20 @@ HEADERS = adler32.h \
pixfmt.h \
random_seed.h \
rational.h \
+ ripemd.h \
samplefmt.h \
sha.h \
+ sha512.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 \
@@ -61,6 +71,7 @@ OBJS = adler32.o \
avstring.o \
base64.o \
blowfish.o \
+ bprint.o \
buffer.o \
channel_layout.o \
cpu.o \
@@ -73,6 +84,7 @@ OBJS = adler32.o \
file_open.o \
float_dsp.o \
frame.o \
+ hash.o \
hmac.o \
imgutils.o \
intfloat_readwrite.o \
@@ -84,6 +96,7 @@ OBJS = adler32.o \
mathematics.o \
md5.o \
mem.o \
+ murmur3.o \
dict.o \
opt.o \
parseutils.o \
@@ -91,14 +104,19 @@ OBJS = adler32.o \
random_seed.o \
rational.o \
rc4.o \
+ ripemd.o \
samplefmt.o \
sha.o \
+ sha512.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/%)
@@ -107,6 +125,7 @@ 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 \
@@ -114,17 +133,35 @@ TESTPROGS = adler32 \
avstring \
base64 \
blowfish \
+ bprint \
cpu \
crc \
des \
+ error \
eval \
+ file \
fifo \
hmac \
lfg \
lls \
md5 \
+ murmur3 \
opt \
+ pca \
parseutils \
+ random_seed \
+ rational \
+ ripemd \
sha \
+ sha512 \
tree \
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/adler32.c b/libavutil/adler32.c
index 7f5afdb..bc9b9a7 100644
--- a/libavutil/adler32.c
+++ b/libavutil/adler32.c
@@ -23,6 +23,8 @@
#include "config.h"
#include "adler32.h"
+#include "common.h"
+#include "intreadwrite.h"
#define BASE 65521L /* largest prime smaller than 65536 */
@@ -37,16 +39,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;
@@ -56,6 +88,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"
@@ -86,4 +119,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 a8ff6f9..8c08d2b 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
*/
@@ -25,7 +25,12 @@
#include "attributes.h"
/**
+ * @defgroup lavu_adler32 Adler32
* @ingroup lavu_crypto
+ * @{
+ */
+
+/**
* Calculate the Adler32 checksum of a buffer.
*
* Passing the return value to a subsequent av_adler32_update() call
@@ -40,4 +45,8 @@
unsigned long av_adler32_update(unsigned long adler, const uint8_t *buf,
unsigned int len) av_pure;
+/**
+ * @}
+ */
+
#endif /* AVUTIL_ADLER32_H */
diff --git a/libavutil/aes.c b/libavutil/aes.c
index 4656a48..a3eb295 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
*/
@@ -39,9 +39,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)
{
@@ -266,6 +264,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"
@@ -338,4 +337,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 4638200..9cdcce9 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 85ea662..3f7674b 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
*/
diff --git a/libavutil/arm/cpu.h b/libavutil/arm/cpu.h
index 52e839c..c545589 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
*/
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 39a5e95..38148b3 100644
--- a/libavutil/arm/float_dsp_init_arm.c
+++ b/libavutil/arm/float_dsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* ARM optimized DSP 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/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 31cb6ae..1fe52ab 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 8295280..8695fbd 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/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 add489a..04182f2 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
*/
@@ -105,7 +105,7 @@ void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval)
#endif /* !HAVE_MEMORYBARRIER && !HAVE_SYNC_VAL_COMPARE_AND_SWAP && !HAVE_MACHINE_RW_BARRIER */
#ifdef TEST
-#include <assert.h>
+#include "avassert.h"
int main(void)
{
@@ -113,10 +113,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 a5c5fe8..fd7d8fc 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..2bb43c3 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
*/
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 84e8b7f..f4ee078 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 9f476c9..8c0e5b2 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..cfbde89 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
*/
diff --git a/libavutil/audio_fifo.h b/libavutil/audio_fifo.h
index 8c76388..903b8f1 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
*/
@@ -85,7 +85,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);
@@ -99,7 +100,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 3ea7be0..eed58fa 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
*/
@@ -28,6 +28,7 @@
#include "common.h"
#include "mem.h"
#include "avstring.h"
+#include "bprint.h"
int av_strstart(const char *str, const char *pfx, const char **ptr)
{
@@ -54,11 +55,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 +69,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 +109,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 +180,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 +268,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';
@@ -239,7 +312,7 @@ int av_isxdigit(int c)
int main(void)
{
int i;
- const char *strings[] = {
+ static const char * const strings[] = {
"''",
"",
":",
diff --git a/libavutil/avstring.h b/libavutil/avstring.h
index b7d1098..438ef79 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
*/
@@ -131,6 +131,16 @@ 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);
/**
+ * 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 +162,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.
*/
int av_isdigit(int c);
@@ -191,7 +225,7 @@ static inline int av_tolower(int c)
*/
int av_isxdigit(int c);
-/*
+/**
* Locale-independent case-insensitive compare.
* @note This means only ASCII-range characters are case-insensitive
*/
@@ -219,6 +253,48 @@ const char *av_basename(const char *path);
*/
const char *av_dirname(char *path);
+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);
+
/**
* @}
*/
diff --git a/libavutil/avutil.h b/libavutil/avutil.h
index 6bb5510..4692c00 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 @subpage 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 lsws "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
@@ -148,43 +149,6 @@
/**
- * @defgroup preproc_misc Preprocessor String Macros
- *
- * String manipulation macros
- *
- * @{
- */
-
-#define AV_STRINGIFY(s) AV_TOSTRING(s)
-#define AV_TOSTRING(s) #s
-
-#define AV_GLUE(a, b) a ## b
-#define AV_JOIN(a, b) AV_GLUE(a, b)
-
-#define AV_PRAGMA(s) _Pragma(#s)
-
-/**
- * @}
- */
-
-/**
- * @defgroup version_utils Library Version Macros
- *
- * Useful to check and match library version in order to maintain
- * backward compatibility.
- *
- * @{
- */
-
-#define AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c)
-#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c
-#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c)
-
-/**
- * @}
- */
-
-/**
* @addtogroup lavu_ver
* @{
*/
@@ -224,6 +188,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
* @{
*
@@ -244,7 +214,7 @@ enum AVMediaType {
* @}
* @defgroup lavu_time Timestamp specific
*
- * Libav internal timebase and timestamp definitions
+ * FFmpeg internal timebase and timestamp definitions
*
* @{
*/
@@ -256,7 +226,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
@@ -281,7 +251,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
@@ -303,8 +274,43 @@ char av_get_picture_type_char(enum AVPictureType pict_type);
* @}
*/
+#include "common.h"
#include "error.h"
#include "version.h"
+#include "mathematics.h"
+#include "rational.h"
+#include "intfloat_readwrite.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)
/**
* @}
diff --git a/libavutil/base64.c b/libavutil/base64.c
index 725b035..348690d 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,106 @@
#include "common.h"
#include "base64.h"
+#include "intreadwrite.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 +147,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 +173,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 +195,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 +244,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..7786e3b
--- a/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-dependant. */
+
+ 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..839ec1e
--- a/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(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 8a350e1..06f6548 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
*/
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/channel_layout.c b/libavutil/channel_layout.c
index 79e398e..2b85de3 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
*/
@@ -26,41 +26,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 {
@@ -70,19 +76,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 },
@@ -92,40 +97,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);
@@ -133,7 +165,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;
@@ -141,58 +177,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,
@@ -216,6 +261,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;
@@ -229,3 +285,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 15b6887..ba4f96d 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
@@ -128,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);
@@ -141,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.
*/
@@ -149,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.
@@ -176,6 +195,26 @@ 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 caa6b19..b1203ad 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
*/
@@ -48,6 +48,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)
@@ -62,6 +67,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
@@ -91,6 +99,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;
@@ -147,8 +175,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;
}
/**
@@ -196,6 +224,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;
@@ -231,7 +279,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))
@@ -247,12 +295,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;\
@@ -370,6 +423,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
@@ -397,6 +453,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 c96dfa9..1dc5abb 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
*/
@@ -23,7 +23,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
@@ -40,12 +42,15 @@
#include <unistd.h>
#endif
-static int cpuflags_mask = -1, checked;
+static int flags, checked;
+
+void av_force_cpu_flags(int arg){
+ flags = arg;
+ checked = arg != -1;
+}
int av_get_cpu_flags(void)
{
- static int flags;
-
if (checked)
return flags;
@@ -53,16 +58,15 @@ int av_get_cpu_flags(void)
if (ARCH_PPC) flags = ff_get_cpu_flags_ppc();
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)
@@ -131,8 +135,73 @@ 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" },
+ { "fma4" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_FMA4 }, .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" },
+#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;
@@ -157,6 +226,11 @@ 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;
}
diff --git a/libavutil/cpu.h b/libavutil/cpu.h
index 29036e3..55c3ec9 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_ALTIVEC 0x0001 ///< standard
@@ -61,25 +63,47 @@
/**
* 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 08f6e85..8597a32 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 2cdf588..b429fe1 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,
@@ -211,6 +250,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;
@@ -219,10 +263,11 @@ 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 },
};
-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)
@@ -302,8 +347,9 @@ int main(void)
{
uint8_t buf[1999];
int i;
- int p[4][3] = { { AV_CRC_32_IEEE_LE, 0xEDB88320, 0x3D5CDD04 },
+ int p[5][3] = { { AV_CRC_32_IEEE_LE, 0xEDB88320, 0x3D5CDD04 },
{ AV_CRC_32_IEEE , 0x04C11DB7, 0xC0F5BAE0 },
+ { AV_CRC_24_IEEE , 0x864CFB , 0xB704CE },
{ AV_CRC_16_ANSI , 0x8005 , 0x1FBB },
{ AV_CRC_8_ATM , 0x07 , 0xE3 }
};
@@ -312,7 +358,7 @@ int main(void)
for (i = 0; i < sizeof(buf); i++)
buf[i] = i + i * i;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < 5; 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 0540619..f4219ca 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 {
@@ -33,6 +39,7 @@ typedef enum {
AV_CRC_16_CCITT,
AV_CRC_32_IEEE,
AV_CRC_32_IEEE_LE, /*< reversed bitorder version of AV_CRC_32_IEEE */
+ AV_CRC_24_IEEE = 12,
AV_CRC_MAX, /*< Not part of public API! Do not use outside libavutil. */
}AVCRCId;
@@ -71,4 +78,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 9ac4831..3a0e84c 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
*/
@@ -48,8 +48,8 @@ av_dict_get(AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int
for(; i<m->count; i++){
const char *s= m->elems[i].key;
- if(flags & AV_DICT_MATCH_CASE) for(j=0; s[j] == key[j] && key[j]; j++);
- else for(j=0; av_toupper(s[j]) == av_toupper(key[j]) && key[j]; j++);
+ if(flags & AV_DICT_MATCH_CASE) for(j=0; s[j] == key[j] && key[j]; j++);
+ else for(j=0; av_toupper(s[j]) == av_toupper(key[j]) && key[j]; j++);
if(key[j])
continue;
if(s[j] && !(flags & AV_DICT_IGNORE_SUFFIX))
@@ -86,17 +86,20 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
}
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 );
+ 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)))
+ char *newval = av_mallocz(len);
+ if (!newval)
return AVERROR(ENOMEM);
- av_strlcat(oldval, value, len);
- m->elems[m->count].value = oldval;
+ 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++;
diff --git a/libavutil/dict.h b/libavutil/dict.h
index ab23f26..38f03a4 100644
--- a/libavutil/dict.h
+++ b/libavutil/dict.h
@@ -1,25 +1,31 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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
diff --git a/libavutil/error.c b/libavutil/error.c
index 6803d2d..bd66354 100644
--- a/libavutil/error.c
+++ b/libavutil/error.c
@@ -1,54 +1,71 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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
#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
+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(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(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" },
+};
+
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 +75,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 3dfd880..f3fd7bb 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
*/
@@ -26,7 +26,6 @@
#include <errno.h>
#include <stddef.h>
-#include "avutil.h"
/**
* @addtogroup lavu_error
@@ -45,23 +44,35 @@
#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 AV_ERROR_MAX_STRING_SIZE 64
+
/**
* Put a description of the AVERROR code errnum in errbuf.
* In case of failure the global variable errno is set to indicate the
@@ -77,6 +88,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 48f8e66..635e538 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"
typedef struct Parser {
@@ -48,10 +50,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,
@@ -76,11 +78,23 @@ 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 },
+};
+
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') {
@@ -128,10 +142,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,
} type;
double value; // is sign in other types
union {
@@ -140,9 +155,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) {
@@ -160,29 +181,117 @@ 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_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);
}
}
}
@@ -196,6 +305,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);
}
@@ -228,6 +339,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==NULL) {
@@ -258,6 +378,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);
@@ -278,6 +402,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;
@@ -286,18 +411,30 @@ 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 {
for (i=0; p->func1_names && p->func1_names[i]; i++) {
if (strmatch(next, p->func1_names[i])) {
@@ -326,7 +463,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)
@@ -373,7 +510,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);
@@ -400,7 +537,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);
@@ -423,7 +560,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);
@@ -452,7 +589,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);
@@ -483,8 +620,21 @@ 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:
+ 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];
}
}
@@ -508,7 +658,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;
@@ -532,6 +682,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);
@@ -541,6 +692,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;
@@ -652,6 +804,32 @@ 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)",
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..ca25bc5 100644
--- a/libavutil/fifo.c
+++ b/libavutil/fifo.c
@@ -3,22 +3,24 @@
* 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"
@@ -38,7 +40,7 @@ AVFifoBuffer *av_fifo_alloc(unsigned int size)
void av_fifo_free(AVFifoBuffer *f)
{
if (f) {
- av_free(f->buffer);
+ av_freep(&f->buffer);
av_free(f);
}
}
@@ -68,7 +70,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 +81,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 +146,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..849b9a6 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
*/
@@ -95,6 +95,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 +104,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..45fe853 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,69 @@ 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 == NULL) {
+ 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..389076f 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
*/
@@ -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,8 +85,10 @@ 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;
diff --git a/libavutil/float_dsp.c b/libavutil/float_dsp.c
index 3707e06..efff47f 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;
@@ -130,5 +133,7 @@ av_cold void avpriv_float_dsp_init(AVFloatDSPContext *fdsp, int bit_exact)
ff_float_dsp_init_ppc(fdsp, bit_exact);
#elif ARCH_X86
ff_float_dsp_init_x86(fdsp);
+#elif ARCH_MIPS
+ ff_float_dsp_init_mips(fdsp);
#endif
}
diff --git a/libavutil/float_dsp.h b/libavutil/float_dsp.h
index b215dad..d0447d6 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
*/
@@ -147,7 +147,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.
@@ -184,5 +184,6 @@ void avpriv_float_dsp_init(AVFloatDSPContext *fdsp, int strict);
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 99bdd8a..39e2a13 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 *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,10 +93,17 @@ 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 */
+ frame->colorspace = AVCOL_SPC_UNSPECIFIED;
frame->extended_data = frame->data;
}
@@ -47,6 +114,7 @@ AVFrame *av_frame_alloc(void)
if (!frame)
return NULL;
+ frame->extended_data = NULL;
get_frame_defaults(frame);
return frame;
@@ -73,21 +141,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);
if (!frame->buf[i])
goto fail;
@@ -111,11 +183,12 @@ fail:
static int get_audio_buffer(AVFrame *frame, int align)
{
- int channels = av_get_channel_layout_nb_channels(frame->channel_layout);
+ int channels = frame->channels;
int planar = av_sample_fmt_is_planar(frame->format);
int planes = planar ? channels : 1;
int ret, i;
+ CHECK_CHANNELS_CONSISTENCY(frame);
if (!frame->linesize[0]) {
ret = av_samples_get_buffer_size(&frame->linesize[0], channels,
frame->nb_samples, frame->format,
@@ -165,7 +238,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);
@@ -178,6 +251,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;
@@ -192,7 +266,8 @@ int av_frame_ref(AVFrame *dst, const AVFrame *src)
return ret;
if (src->nb_samples) {
- int ch = av_get_channel_layout_nb_channels(src->channel_layout);
+ int ch = src->channels;
+ CHECK_CHANNELS_CONSISTENCY(src);
av_samples_copy(dst->extended_data, src->extended_data, 0, 0,
dst->nb_samples, ch, dst->format);
} else {
@@ -203,7 +278,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);
@@ -231,12 +308,13 @@ 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);
if (!dst->extended_data) {
@@ -286,6 +364,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);
}
@@ -306,8 +387,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]);
@@ -329,6 +411,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);
@@ -336,7 +419,8 @@ int av_frame_make_writable(AVFrame *frame)
return ret;
if (tmp.nb_samples) {
- int ch = av_get_channel_layout_nb_channels(tmp.channel_layout);
+ int ch = tmp.channels;
+ CHECK_CHANNELS_CONSISTENCY(&tmp);
av_samples_copy(tmp.extended_data, frame->extended_data, 0, 0,
frame->nb_samples, ch, frame->format);
} else {
@@ -373,12 +457,24 @@ 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->decode_error_flags = src->decode_error_flags;
+ dst->colorspace = src->colorspace;
+ dst->color_range = src->color_range;
+
+ av_dict_copy(&dst->metadata, src->metadata, 0);
memcpy(dst->error, src->error, sizeof(dst->error));
@@ -399,6 +495,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;
}
@@ -408,9 +516,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;
diff --git a/libavutil/frame.h b/libavutil/frame.h
index bbff3d1..3be6892 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
*/
@@ -30,6 +30,26 @@
#include "rational.h"
#include "samplefmt.h"
+enum AVColorSpace{
+ AVCOL_SPC_RGB = 0,
+ AVCOL_SPC_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B
+ AVCOL_SPC_UNSPECIFIED = 2,
+ AVCOL_SPC_FCC = 4,
+ AVCOL_SPC_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601
+ AVCOL_SPC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC / functionally identical to above
+ AVCOL_SPC_SMPTE240M = 7,
+ AVCOL_SPC_YCOCG = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16
+ AVCOL_SPC_NB , ///< Not part of ABI
+};
+#define AVCOL_SPC_YCGCO AVCOL_SPC_YCOCG
+
+enum AVColorRange{
+ AVCOL_RANGE_UNSPECIFIED = 0,
+ AVCOL_RANGE_MPEG = 1, ///< the normal 219*2^(n-8) "MPEG" YUV ranges
+ AVCOL_RANGE_JPEG = 2, ///< the normal 2^n-1 "JPEG" YUV ranges
+ AVCOL_RANGE_NB , ///< Not part of ABI
+};
+
enum AVFrameSideDataType {
/**
* The data is the AVPanScan struct defined in libavcodec.
@@ -47,7 +67,7 @@ typedef struct AVFrameSideData {
/**
* This structure describes decoded (raw) audio or video data.
*
- * AVFrame must be allocated using av_frame_alloc(). Not that this only
+ * AVFrame must be allocated using av_frame_alloc(). Note that this only
* allocates the AVFrame itself, the buffers for the data must be managed
* through other means (see below).
* AVFrame must be freed with av_frame_free().
@@ -69,12 +89,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];
@@ -85,6 +113,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 multiplies 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.
*/
@@ -154,7 +187,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 isnt used)
+ * This is also the Presentation time of this AVFrame calculated from
+ * only AVPacket.dts values without pts values.
*/
int64_t pkt_dts;
@@ -350,9 +385,139 @@ typedef struct AVFrame {
AVFrameSideData **side_data;
int nb_side_data;
+
+ /**
+ * 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;
+
+ /**
+ * 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;
+
+ /**
+ * 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;
+
+
+ /**
+ * 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().
*
@@ -374,7 +539,7 @@ AVFrame *av_frame_alloc(void);
void av_frame_free(AVFrame **frame);
/**
- * Setup a new reference to the data described by an given frame.
+ * Setup a new reference to the data described by a given frame.
*
* Copy frame properties from src to dst and create a new reference for each
* AVBufferRef from src.
diff --git a/libavutil/hash.c b/libavutil/hash.c
new file mode 100644
index 0000000..a8cf80b
--- a/dev/null
+++ b/libavutil/hash.c
@@ -0,0 +1,204 @@
+/*
+ * 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 "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;
+
+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_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..9bf715e
--- a/dev/null
+++ b/libavutil/hash.h
@@ -0,0 +1,90 @@
+/*
+ * 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);
+
+/**
+ * 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 a8b4d2a..d8a579f 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 "pixdesc.h"
@@ -45,27 +47,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 */
@@ -75,20 +95,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;
@@ -170,7 +181,7 @@ int avpriv_set_systematic_pal2(uint32_t pal[256], enum AVPixelFormat pix_fmt)
default:
return AVERROR(EINVAL);
}
- pal[i] = b + (g<<8) + (r<<16);
+ pal[i] = b + (g<<8) + (r<<16) + (0xFFU<<24);
}
return 0;
@@ -188,7 +199,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++)
@@ -234,6 +245,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;
@@ -266,8 +279,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],
@@ -275,3 +292,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 7151013..ab32d66 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
*/
@@ -99,6 +99,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
*/
@@ -117,6 +120,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 == NULL 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
--- a/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
--- a/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 7b178c2..cf3420c 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
*/
@@ -37,7 +37,9 @@
#include "config.h"
#include "attributes.h"
#include "timer.h"
+#include "cpu.h"
#include "dict.h"
+#include "version.h"
#if ARCH_X86
# include "x86/emms.h"
@@ -62,7 +64,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 +83,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
@@ -143,12 +151,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,4 +220,8 @@ void avpriv_request_sample(void *avc,
*/
int avpriv_open(const char *filename, int flags, ...);
+#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/intfloat_readwrite.c b/libavutil/intfloat_readwrite.c
index 6838563..142331d 100644
--- a/libavutil/intfloat_readwrite.c
+++ b/libavutil/intfloat_readwrite.c
@@ -3,20 +3,20 @@
*
* 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
*/
@@ -26,6 +26,7 @@
*/
#include <stdint.h>
+#include "common.h"
#include "mathematics.h"
#include "intfloat_readwrite.h"
@@ -88,7 +89,7 @@ AVExtFloat av_dbl2ext(double d){
ext.mantissa[i] = m>>(56-(i<<3));
} else if (f != 0.0) {
ext.exponent[0] = 0x7f; ext.exponent[1] = 0xff;
- if (f != INFINITY)
+ if (!isinf(f))
ext.mantissa[0] = ~0;
}
if (d < 0)
diff --git a/libavutil/intfloat_readwrite.h b/libavutil/intfloat_readwrite.h
index f093b92..9709f4d 100644
--- a/libavutil/intfloat_readwrite.h
+++ b/libavutil/intfloat_readwrite.h
@@ -1,20 +1,20 @@
/*
* 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
*/
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..e140d82 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,6 +35,10 @@
* @{
*/
+#if ARCH_ARM
+# include "arm/intmath.h"
+#endif
+
#if HAVE_FAST_CLZ && AV_GCC_VERSION_AT_LEAST(3,4)
#ifndef ff_log2
diff --git a/libavutil/intreadwrite.h b/libavutil/intreadwrite.h
index f77fd60..7ee6977 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,7 +47,7 @@ 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.
*/
@@ -114,6 +114,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 +176,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 +234,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 +247,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 +262,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 +279,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 +300,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 +325,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 +460,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/libavutil.v b/libavutil/libavutil.v
index e9f04cb..eb16ae1 100644
--- a/libavutil/libavutil.v
+++ b/libavutil/libavutil.v
@@ -1,4 +1,4 @@
LIBAVUTIL_$MAJOR {
- global: av*;
+ global: av*; ff_*;
local: *;
};
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..abed8ef 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
*/
diff --git a/libavutil/lls.h b/libavutil/lls.h
index 27c0d5e..c62d78a 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
*/
diff --git a/libavutil/log.c b/libavutil/log.c
index 7d574f6..56ef53b 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,25 +34,75 @@
#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
#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,
+};
+
static int16_t background, attr_orig;
static HANDLE con;
#define set_color(x) SetConsoleTextAttribute(con, background | color[x])
+#define set_256color set_color
#define reset_color() SetConsoleTextAttribute(con, attr_orig)
#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)
+
+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,
+};
+
+#define set_color(x) fprintf(stderr, "\033[%d;3%dm", (color[x] >> 4) & 15, color[x] & 15)
+#define set_256color(x) fprintf(stderr, "\033[48;5;%dm\033[38;5;%dm", (color[x] >> 16) & 0xff, (color[x] >> 8) & 0xff)
#define reset_color() fprintf(stderr, "\033[0m")
#endif
static int use_color = -1;
@@ -74,15 +124,18 @@ static void colored_fputs(int level, const char *str)
use_color = !getenv("NO_COLOR") && !getenv("AV_LOG_FORCE_NOCOLOR") &&
(getenv("TERM") && isatty(2) ||
getenv("AV_LOG_FORCE_COLOR"));
+ if (getenv("AV_LOG_FORCE_256COLOR"))
+ use_color *= 256;
#else
use_color = getenv("AV_LOG_FORCE_COLOR") && !getenv("NO_COLOR") &&
!getenv("AV_LOG_FORCE_NOCOLOR");
#endif
}
- if (use_color) {
+ if (use_color == 1) {
set_color(level);
- }
+ } else if (use_color == 256)
+ set_256color(level);
fputs(str, stderr);
if (use_color) {
reset_color();
@@ -94,52 +147,120 @@ const char *av_default_item_name(void *ptr)
return (*(AVClass **) ptr)->class_name;
}
-void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl)
+AVClassCategory av_default_get_category(void *ptr)
+{
+ return (*(AVClass **) ptr)->category;
+}
+
+static void sanitize(uint8_t *line){
+ while(*line){
+ if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
+ *line='?';
+ line++;
+ }
+}
+
+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 void format_line(void *ptr, int level, const char *fmt, va_list vl,
+ AVBPrint part[3], int *print_prefix, int type[2])
{
- static int print_prefix = 1;
- static int count;
- static char prev[1024];
- char line[1024];
- static int is_atty;
AVClass* avc = ptr ? *(AVClass **) ptr : NULL;
- if (level > av_log_level)
- return;
- line[0] = 0;
- if (print_prefix && avc) {
+ av_bprint_init(part+0, 0, 1);
+ av_bprint_init(part+1, 0, 1);
+ av_bprint_init(part+2, 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 *) ptr) +
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(ptr), ptr);
+ if(type) type[1] = get_category(ptr);
}
- vsnprintf(line + strlen(line), sizeof(line) - strlen(line), fmt, vl);
+ av_vbprintf(part+2, fmt, vl);
- print_prefix = strlen(line) && line[strlen(line) - 1] == '\n';
+ if(*part[0].str || *part[1].str || *part[2].str) {
+ char lastc = part[2].len ? part[2].str[part[2].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[3];
+ format_line(ptr, level, fmt, vl, part, print_prefix, NULL);
+ snprintf(line, line_size, "%s%s%s", part[0].str, part[1].str, part[2].str);
+ av_bprint_finalize(part+2, 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[3];
+ char line[LINE_SZ];
+ static int is_atty;
+ int type[2];
+
+ 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", part[0].str, part[1].str, part[2].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), line);
- av_strlcpy(prev, line, sizeof line);
+ strcpy(prev, line);
+ sanitize(part[0].str);
+ colored_fputs(type[0], part[0].str);
+ sanitize(part[1].str);
+ colored_fputs(type[1], part[1].str);
+ sanitize(part[2].str);
+ colored_fputs(av_clip(level >> 3, 0, 6), part[2].str);
+end:
+ av_bprint_finalize(part+2, NULL);
+#if HAVE_PTHREADS
+ pthread_mutex_unlock(&mutex);
+#endif
}
static void (*av_log_callback)(void*, int, const char*, va_list) =
@@ -159,7 +280,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)
@@ -186,14 +309,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/MPlayer/incoming/ "
+ "and contact the ffmpeg-devel mailing list.\n");
}
void avpriv_request_sample(void *avc, const char *msg, ...)
diff --git a/libavutil/log.h b/libavutil/log.h
index 05d2826..55459e8 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,23 @@
#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_NB, ///< not part of ABI/API
+}AVClassCategory;
+
+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 +104,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 +179,8 @@ typedef struct AVClass {
*/
#define AV_LOG_DEBUG 48
+#define AV_LOG_MAX_OFFSET (AV_LOG_DEBUG - AV_LOG_QUIET)
+
/**
* @}
*/
@@ -202,6 +240,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.
@@ -231,6 +272,17 @@ void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl);
* @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
@@ -240,7 +292,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
/**
@@ -249,7 +301,7 @@ 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
void av_log_set_flags(int arg);
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 5c5ebc8..221a66b 100644
--- a/libavutil/lzo.c
+++ b/libavutil/lzo.c
@@ -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
*/
@@ -102,7 +102,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,
@@ -128,11 +128,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;
}
@@ -195,3 +195,47 @@ 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");
+ 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);
+ 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");
+ 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/mathematics.c b/libavutil/mathematics.c
index 137683e..f9cf87d 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
*/
@@ -23,11 +23,12 @@
* miscellaneous math routines and tables
*/
-#include <assert.h>
#include <stdint.h>
#include <limits.h>
#include "mathematics.h"
+#include "libavutil/common.h"
+#include "avassert.h"
#include "version.h"
#if FF_API_AV_REVERSE
@@ -58,9 +59,15 @@ 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;
- assert(c > 0);
- assert(b >=0);
- assert((unsigned)rnd<=5 && rnd!=4);
+ av_assert2(c > 0);
+ av_assert2(b >=0);
+ av_assert2((unsigned)(rnd&~AV_ROUND_PASS_MINMAX)<=5 && (rnd&~AV_ROUND_PASS_MINMAX)!=4);
+
+ 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));
@@ -128,6 +135,8 @@ int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
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) return 1;
return 0;
@@ -139,3 +148,26 @@ 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);
+}
diff --git a/libavutil/mathematics.h b/libavutil/mathematics.h
index 043dd0f..71f0392 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,30 @@
#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_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 +70,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 +89,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 +102,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 +130,17 @@ 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 timesbase
+ * @param fs_tb Duration and *last timebase
+ * @param duration duration till the next call
+ * @param out_tb Output timesbase
+ */
+int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb);
+
+/**
* @}
*/
diff --git a/libavutil/md5.c b/libavutil/md5.c
index efb993e..63fc37d 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)
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 15a8c07..5aad97a 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,6 +36,7 @@
#include <malloc.h>
#endif
+#include "avassert.h"
#include "avutil.h"
#include "intreadwrite.h"
#include "mem.h"
@@ -54,9 +57,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)
{
@@ -66,23 +78,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
@@ -110,6 +127,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;
}
@@ -120,7 +145,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
@@ -128,14 +153,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;
@@ -166,27 +210,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
@@ -209,6 +246,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;
@@ -221,6 +265,80 @@ char *av_strdup(const char *s)
return ptr;
}
+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;
+}
+
+void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
+{
+ /* see similar ffmpeg.c:grow_array() */
+ int nb, nb_alloc;
+ intptr_t *tab;
+
+ nb = *nb_ptr;
+ tab = *(intptr_t**)tab_ptr;
+ if ((nb & (nb - 1)) == 0) {
+ if (nb == 0) {
+ nb_alloc = 1;
+ } else {
+ if (nb > INT_MAX / (2 * sizeof(intptr_t)))
+ goto fail;
+ nb_alloc = nb * 2;
+ }
+ tab = av_realloc(tab, nb_alloc * sizeof(intptr_t));
+ if (!tab)
+ goto fail;
+ *(intptr_t**)tab_ptr = tab;
+ }
+ tab[nb++] = (intptr_t)elem;
+ *nb_ptr = nb;
+ return;
+
+fail:
+ av_freep(tab_ptr);
+ *nb_ptr = 0;
+}
+
+void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
+ const uint8_t *elem_data)
+{
+ int nb = *nb_ptr, nb_alloc;
+ uint8_t *tab = *tab_ptr, *tab_elem_data;
+
+ if ((nb & (nb - 1)) == 0) {
+ if (nb == 0) {
+ nb_alloc = 1;
+ } else {
+ if (nb > INT_MAX / (2 * elem_size))
+ goto fail;
+ nb_alloc = nb * 2;
+ }
+ tab = av_realloc(tab, nb_alloc * elem_size);
+ if (!tab)
+ goto fail;
+ *tab_ptr = tab;
+ }
+ *nb_ptr = nb + 1;
+ tab_elem_data = tab + nb*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);
+ return tab_elem_data;
+
+fail:
+ av_freep(tab_ptr);
+ *nb_ptr = 0;
+ return NULL;
+}
+
static void fill16(uint8_t *dst, int len)
{
uint32_t v = AV_RN16(dst - 2);
@@ -344,3 +462,4 @@ void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
*dst = *src;
}
}
+
diff --git a/libavutil/mem.h b/libavutil/mem.h
index 99dc4cc..77b7adc 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
@@ -218,6 +241,14 @@ av_alloc_size(1, 2) static inline void *av_mallocz_array(size_t nmemb, size_t si
char *av_strdup(const char *s) 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
@@ -227,9 +258,76 @@ char *av_strdup(const char *s) av_malloc_attrib;
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_dynarray2_add()
+ */
+void av_dynarray_add(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()
+ */
+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
--- a/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
--- a/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
--- a/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/murmur3.c b/libavutil/murmur3.c
new file mode 100644
index 0000000..701fa6a
--- a/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
--- a/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 a0ae06b..3ee8aec 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
*/
@@ -104,9 +106,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
@@ -120,6 +126,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
@@ -127,6 +140,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..e0b28c3
--- a/dev/null
+++ b/libavutil/opencl.c
@@ -0,0 +1,812 @@
+/*
+ * 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"
+#include "avstring.h"
+#include "log.h"
+#include "avassert.h"
+#include "opt.h"
+
+#if HAVE_PTHREADS
+
+#include <pthread.h>
+static pthread_mutex_t atomic_opencl_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#define LOCK_OPENCL pthread_mutex_lock(&atomic_opencl_lock)
+#define UNLOCK_OPENCL pthread_mutex_unlock(&atomic_opencl_lock)
+
+#elif !HAVE_THREADS
+#define LOCK_OPENCL
+#define UNLOCK_OPENCL
+#endif
+
+
+#define MAX_KERNEL_NUM 500
+#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;
+ char *build_options;
+ cl_platform_id platform_id;
+ cl_device_type device_type;
+ cl_context context;
+ cl_device_id device_id;
+ cl_command_queue command_queue;
+ int program_count;
+ cl_program programs[MAX_KERNEL_CODE_NUM];
+ int kernel_code_count;
+ KernelCode kernel_code[MAX_KERNEL_CODE_NUM];
+ int kernel_count;
+ 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},
+ { "build_options", "build options of opencl", OFFSET(build_options), AV_OPT_TYPE_STRING, {.str="-I."}, CHAR_MIN, CHAR_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, CL_DEVICE_TYPE_DEFAULT};
+
+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 < sizeof(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(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(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(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(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);
+}
+
+int av_opencl_set_option(const char *key, const char *val)
+{
+ int ret = 0;
+ 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 = 0;
+ 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;
+}
+
+int av_opencl_create_kernel(AVOpenCLKernelEnv *env, const char *kernel_name)
+{
+ cl_int status;
+ int i, ret = 0;
+ LOCK_OPENCL;
+ if (strlen(kernel_name) + 1 > AV_OPENCL_MAX_KERNEL_NAME_SIZE) {
+ av_log(&opencl_ctx, AV_LOG_ERROR, "Created kernel name %s is too long\n", kernel_name);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ if (!env->kernel) {
+ if (opencl_ctx.kernel_count >= MAX_KERNEL_NUM) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not create kernel with name '%s', maximum number of kernels %d already reached\n",
+ kernel_name, MAX_KERNEL_NUM);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ if (opencl_ctx.program_count == 0) {
+ av_log(&opencl_ctx, AV_LOG_ERROR, "Program count of OpenCL is 0, can not create kernel\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ for (i = 0; i < opencl_ctx.program_count; i++) {
+ env->kernel = clCreateKernel(opencl_ctx.programs[i], kernel_name, &status);
+ if (status == CL_SUCCESS)
+ break;
+ }
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR, "Could not create OpenCL kernel: %s\n", av_opencl_errstr(status));
+ ret = AVERROR_EXTERNAL;
+ goto end;
+ }
+ opencl_ctx.kernel_count++;
+ env->command_queue = opencl_ctx.command_queue;
+ av_strlcpy(env->kernel_name, kernel_name, sizeof(env->kernel_name));
+ }
+end:
+ UNLOCK_OPENCL;
+ return ret;
+}
+
+void av_opencl_release_kernel(AVOpenCLKernelEnv *env)
+{
+ cl_int status;
+ LOCK_OPENCL;
+ if (!env->kernel)
+ goto end;
+ status = clReleaseKernel(env->kernel);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR, "Could not release kernel: %s\n",
+ av_opencl_errstr(status));
+ }
+ env->kernel = NULL;
+ env->command_queue = NULL;
+ env->kernel_name[0] = 0;
+ opencl_ctx.kernel_count--;
+end:
+ UNLOCK_OPENCL;
+}
+
+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;
+}
+
+static int compile_kernel_file(OpenclContext *opencl_ctx)
+{
+ cl_int status;
+ int i, kernel_code_count = 0;
+ const char *kernel_code[MAX_KERNEL_CODE_NUM] = {NULL};
+ size_t kernel_code_len[MAX_KERNEL_CODE_NUM] = {0};
+
+ for (i = 0; i < opencl_ctx->kernel_code_count; i++) {
+ if (!opencl_ctx->kernel_code[i].is_compiled) {
+ kernel_code[kernel_code_count] = opencl_ctx->kernel_code[i].kernel_string;
+ kernel_code_len[kernel_code_count] = strlen(opencl_ctx->kernel_code[i].kernel_string);
+ opencl_ctx->kernel_code[i].is_compiled = 1;
+ kernel_code_count++;
+ }
+ }
+ if (!kernel_code_count)
+ return 0;
+ /* create a CL program using the kernel source */
+ opencl_ctx->programs[opencl_ctx->program_count] = clCreateProgramWithSource(opencl_ctx->context,
+ kernel_code_count,
+ kernel_code,
+ kernel_code_len,
+ &status);
+ if(status != CL_SUCCESS) {
+ av_log(opencl_ctx, AV_LOG_ERROR,
+ "Could not create OpenCL program with source code: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ if (!opencl_ctx->programs[opencl_ctx->program_count]) {
+ av_log(opencl_ctx, AV_LOG_ERROR, "Created program is NULL\n");
+ return AVERROR_EXTERNAL;
+ }
+ status = clBuildProgram(opencl_ctx->programs[opencl_ctx->program_count], 1, &(opencl_ctx->device_id),
+ opencl_ctx->build_options, NULL, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(opencl_ctx, AV_LOG_ERROR,
+ "Could not compile OpenCL kernel: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ opencl_ctx->program_count++;
+ return 0;
+}
+
+int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env)
+{
+ int ret = 0;
+ 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;
+ }
+ ret = compile_kernel_file(&opencl_ctx);
+ 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;
+ int i;
+ LOCK_OPENCL;
+ opencl_ctx.init_count--;
+ if (opencl_ctx.is_user_created)
+ goto end;
+ if (opencl_ctx.init_count > 0 || opencl_ctx.kernel_count > 0)
+ goto end;
+ for (i = 0; i < opencl_ctx.program_count; i++) {
+ if (opencl_ctx.programs[i]) {
+ status = clReleaseProgram(opencl_ctx.programs[i]);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not release OpenCL program: %s\n", av_opencl_errstr(status));
+ }
+ opencl_ctx.programs[i] = NULL;
+ }
+ }
+ 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) && (opencl_ctx.kernel_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;
+}
diff --git a/libavutil/opencl.h b/libavutil/opencl.h
new file mode 100644
index 0000000..094c108
--- a/dev/null
+++ b/libavutil/opencl.h
@@ -0,0 +1,287 @@
+/*
+ * 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
+ */
+
+/**
+ * @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 "dict.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_command_queue command_queue;
+ cl_kernel kernel;
+ char kernel_name[AV_OPENCL_MAX_KERNEL_NAME_SIZE];
+} AVOpenCLKernelEnv;
+
+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:
+ * - build_options: set options to compile registered kernels code
+ * - 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 and compile the kernel
+ * code registered with av_opencl_register_kernel_code().
+ *
+ * @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);
+
+/**
+ * Create kernel object in the specified kernel environment.
+ *
+ * @param env pointer to kernel environment which is filled with
+ * the environment used to run the kernel
+ * @param kernel_name kernel function name
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_create_kernel(AVOpenCLKernelEnv *env, const char *kernel_name);
+
+/**
+ * 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 kernel object.
+ *
+ * @param env kernel environment where the kernel object was created
+ * with av_opencl_create_kernel()
+ */
+void av_opencl_release_kernel(AVOpenCLKernelEnv *env);
+
+/**
+ * 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);
+
+#endif /* LIBAVUTIL_OPENCL_H */
diff --git a/libavutil/opencl_internal.c b/libavutil/opencl_internal.c
new file mode 100644
index 0000000..3d996ab
--- a/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 ff_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..34b39a0
--- a/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 ff_opencl_set_parameter(FFOpenclParam *opencl_param, ...);
diff --git a/libavutil/opt.c b/libavutil/opt.c
index ede4a49..46f60aa 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,44 @@
#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_FIND_OPT
+//FIXME order them and do a bin search
+const AVOption *av_find_opt(void *v, const char *name, const char *unit, int mask, int flags)
+{
+ const AVOption *o = NULL;
+
+ while ((o = av_next_option(v, o))) {
+ if (!strcmp(o->name, name) && (!unit || (o->unit && !strcmp(o->unit, unit))) && (o->flags & mask) == flags)
+ return o;
+ }
+ return NULL;
+}
+#endif
+
+#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 +75,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 +95,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;
@@ -207,13 +252,28 @@ static int set_string_number(void *obj, void *target_obj, const AVOption *o, con
return 0;
}
+#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)
+ 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);
dst = ((uint8_t*)target_obj) + o->offset;
@@ -226,6 +286,93 @@ 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:
+ if (!val || !strcmp(val, "none")) {
+ *(int *)dst = *((int *)dst + 1) = 0;
+ return 0;
+ }
+ ret = av_parse_video_size(dst, ((int *)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;
+ case AV_OPT_TYPE_VIDEO_RATE:
+ 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;
+ case AV_OPT_TYPE_PIXEL_FMT:
+ if (!val || !strcmp(val, "none")) {
+ ret = AV_PIX_FMT_NONE;
+ } else {
+ ret = av_get_pix_fmt(val);
+ if (ret == AV_PIX_FMT_NONE) {
+ char *tail;
+ ret = strtol(val, &tail, 0);
+ if (*tail || (unsigned)ret >= AV_PIX_FMT_NB) {
+ av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as pixel format\n", val);
+ return AVERROR(EINVAL);
+ }
+ }
+ }
+ *(enum AVPixelFormat *)dst = ret;
+ return 0;
+ case AV_OPT_TYPE_SAMPLE_FMT:
+ if (!val || !strcmp(val, "none")) {
+ ret = AV_SAMPLE_FMT_NONE;
+ } else {
+ ret = av_get_sample_fmt(val);
+ if (ret == AV_SAMPLE_FMT_NONE) {
+ char *tail;
+ ret = strtol(val, &tail, 0);
+ if (*tail || (unsigned)ret >= AV_SAMPLE_FMT_NB) {
+ av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as sample format\n", val);
+ return AVERROR(EINVAL);
+ }
+ }
+ }
+ *(enum AVSampleFormat *)dst = ret;
+ return 0;
+ 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:
+ 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;
+ }
+ break;
+ 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");
@@ -260,6 +407,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);
@@ -289,8 +462,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)
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);
@@ -299,19 +472,164 @@ 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;
+ const AVClass *class = *(AVClass **)obj;
+
+ 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);
+ }
+
+#if LIBAVUTIL_VERSION_MAJOR < 53
+ if (class->version && class->version < AV_VERSION_INT(52, 11, 100)) {
+ min = -1;
+ max = nb_fmts-1;
+ } else
+#endif
+ {
+ min = FFMIN(o->min, -1);
+ max = FFMAX(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);
+ }
+ *(int *)(((int64_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_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
{
void *dst, *target_obj;
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;
@@ -323,7 +641,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);
@@ -340,6 +660,28 @@ int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
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"d:%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 *)dst)[0], ((int *)dst)[1], ((int *)dst)[2], ((int *)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);
}
@@ -350,7 +692,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;
@@ -360,6 +702,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:
@@ -367,13 +711,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;
@@ -385,7 +767,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;
@@ -397,7 +779,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)
@@ -407,6 +823,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_flag_is_set(void *obj, const char *field_name, const char *flag_name)
{
const AVOption *field = av_opt_find(obj, field_name, NULL, 0, 0);
@@ -420,10 +881,31 @@ 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 == (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 {
+ 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))
@@ -440,48 +922,136 @@ 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' : '.');
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);
@@ -503,8 +1073,20 @@ 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 AVClass *class = *(AVClass **)s;
const AVOption *opt = NULL;
while ((opt = av_opt_next(s, opt)) != NULL) {
+#if FF_API_OLD_AVOPTIONS
+ if ((opt->flags & mask) != flags)
+ continue;
+#endif
switch (opt->type) {
case AV_OPT_TYPE_CONST:
/* Nothing to be done here */
@@ -512,6 +1094,8 @@ void av_opt_set_defaults(void *s)
case AV_OPT_TYPE_FLAGS:
case AV_OPT_TYPE_INT:
case AV_OPT_TYPE_INT64:
+ case AV_OPT_TYPE_DURATION:
+ case AV_OPT_TYPE_CHANNEL_LAYOUT:
av_opt_set_int(s, opt->name, opt->default_val.i64, 0);
break;
case AV_OPT_TYPE_DOUBLE:
@@ -527,9 +1111,28 @@ void av_opt_set_defaults(void *s)
av_opt_set_q(s, opt->name, val, 0);
}
break;
+ case AV_OPT_TYPE_COLOR:
case AV_OPT_TYPE_STRING:
+ case AV_OPT_TYPE_IMAGE_SIZE:
+ case AV_OPT_TYPE_VIDEO_RATE:
av_opt_set(s, opt->name, opt->default_val.str, 0);
break;
+ case AV_OPT_TYPE_PIXEL_FMT:
+#if LIBAVUTIL_VERSION_MAJOR < 53
+ if (class->version && class->version < AV_VERSION_INT(52, 10, 100))
+ av_opt_set(s, opt->name, opt->default_val.str, 0);
+ else
+#endif
+ av_opt_set_pixel_fmt(s, opt->name, opt->default_val.i64, 0);
+ break;
+ case AV_OPT_TYPE_SAMPLE_FMT:
+#if LIBAVUTIL_VERSION_MAJOR < 53
+ if (class->version && class->version < AV_VERSION_INT(52, 10, 100))
+ av_opt_set(s, opt->name, opt->default_val.str, 0);
+ else
+#endif
+ av_opt_set_sample_fmt(s, opt->name, opt->default_val.i64, 0);
+ break;
case AV_OPT_TYPE_BINARY:
/* Cannot set default for binary */
break;
@@ -579,7 +1182,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)
@@ -610,6 +1213,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;
@@ -648,9 +1363,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;
@@ -671,7 +1391,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;
@@ -699,6 +1419,111 @@ 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;
+}
+
+int av_opt_query_ranges(AVOptionRanges **ranges_arg, void *obj, const char *key, int flags)
+{
+ 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;
+
+ return callback(ranges_arg, obj, key, flags);
+}
+
+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;
+ 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 0;
+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;
+
+ for (i = 0; i < ranges->nb_ranges; i++) {
+ AVOptionRange *range = ranges->range[i];
+ av_freep(&range->str);
+ av_freep(&ranges->range[i]);
+ }
+ av_freep(&ranges->range);
+ av_freep(rangesp);
+}
+
#ifdef TEST
typedef struct TestContext
@@ -709,6 +1534,13 @@ 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;
} TestContext;
#define OFFSET(x) offsetof(TestContext, x)
@@ -720,12 +1552,19 @@ 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 },
+{"rational", "set rational", OFFSET(rational), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, 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 = 0}, 0, INT_MAX, 0, "flags" },
{"cool", "set cool flag ", 0, AV_OPT_TYPE_CONST, {.i64 = TEST_FLAG_COOL}, INT_MIN, INT_MAX, 0, "flags" },
{"lame", "set lame flag ", 0, AV_OPT_TYPE_CONST, {.i64 = TEST_FLAG_LAME}, INT_MIN, INT_MAX, 0, "flags" },
{"mu", "set mu flag ", 0, AV_OPT_TYPE_CONST, {.i64 = TEST_FLAG_MU}, INT_MIN, INT_MAX, 0, "flags" },
+{"size", "set size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE,{0}, 0, 0 },
+{"pix_fmt", "set pixfmt", OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_NONE}, -1, AV_PIX_FMT_NB-1},
+{"sample_fmt", "set samplefmt", OFFSET(sample_fmt), AV_OPT_TYPE_SAMPLE_FMT, {.i64 = AV_SAMPLE_FMT_NONE}, -1, AV_SAMPLE_FMT_NB-1},
+{"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 = 0}, 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},
{NULL},
};
@@ -746,8 +1585,8 @@ int main(void)
printf("\nTesting av_set_options_string()\n");
{
- TestContext test_ctx;
- const char *options[] = {
+ TestContext test_ctx = { 0 };
+ static const char * const options[] = {
"",
":",
"=",
@@ -767,11 +1606,32 @@ 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",
};
test_ctx.class = &test_class;
av_opt_set_defaults(&test_ctx);
- test_ctx.string = av_strdup("default");
av_log_set_level(AV_LOG_DEBUG);
@@ -781,6 +1641,37 @@ int main(void)
av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]);
printf("\n");
}
+ 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_DEBUG);
+
+ 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)
+ av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]);
+ printf("\n");
+ }
+ av_opt_free(&test_ctx);
}
return 0;
diff --git a/libavutil/opt.h b/libavutil/opt.h
index 0181379..14faa6e 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
@@ -225,6 +227,24 @@ enum AVOptionType{
AV_OPT_TYPE_RATIONAL,
AV_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length
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
};
/**
@@ -266,6 +286,7 @@ typedef struct AVOption {
#define AV_OPT_FLAG_AUDIO_PARAM 8
#define AV_OPT_FLAG_VIDEO_PARAM 16
#define AV_OPT_FLAG_SUBTITLE_PARAM 32
+#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
/**
@@ -277,6 +298,85 @@ typedef struct AVOption {
} AVOption;
/**
+ * A single allowed range of values, or a single allowed value.
+ */
+typedef struct AVOptionRange {
+ const char *str;
+ double value_min, value_max; ///< For string ranges this represents the min/max length, for dimensions this represents the min/max pixel count
+ double component_min, component_max; ///< For string this represents the unicode range for chars, 0-127 limits to ASCII
+ int is_range; ///< if set to 1 the struct encodes a range, if set to 0 a single value
+} AVOptionRange;
+
+/**
+ * List of AVOptionRange structs
+ */
+typedef struct AVOptionRanges {
+ AVOptionRange **range;
+ int nb_ranges;
+} AVOptionRanges;
+
+
+#if FF_API_FIND_OPT
+/**
+ * Look for an option in obj. Look only for the options which
+ * have the flags set as specified in mask and flags (that is,
+ * for which it is the case that (opt->flags & mask) == flags).
+ *
+ * @param[in] obj a pointer to a struct whose first element is a
+ * pointer to an AVClass
+ * @param[in] name the name of the option to look for
+ * @param[in] unit the unit of the option to look for, or any if NULL
+ * @return a pointer to the option found, or NULL if no option
+ * has been found
+ *
+ * @deprecated use av_opt_find.
+ */
+attribute_deprecated
+const AVOption *av_find_opt(void *obj, const char *name, const char *unit, int mask, int flags);
+#endif
+
+#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
@@ -294,12 +394,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
@@ -314,6 +420,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 string and binary options in obj.
*/
void av_opt_free(void *obj);
@@ -328,7 +464,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
@@ -345,6 +481,39 @@ 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);
/**
+ * 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
* @{
* This group of functions can be used to evaluate option strings
@@ -485,6 +654,27 @@ int av_opt_set_int (void *obj, const char *name, int64_t val, int search_f
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);
+
+/**
+ * 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))
/**
* @}
*/
@@ -499,17 +689,68 @@ int av_opt_set_bin (void *obj, const char *name, const uint8_t *val, int size,
* @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);
/**
* @}
+ */
+/**
+ * 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
+ *
+ * The result must be freed with av_opt_freep_ranges.
+ *
+ * @return >= 0 on success, a negative errro code otherwise
+ */
+int av_opt_query_ranges(AVOptionRanges **, void *obj, const char *key, int flags);
+
+/**
+ * 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
+ *
+ * The result must be freed with av_opt_free_ranges.
+ *
+ * @return >= 0 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 0e3fd9e..e793e2d 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
*/
@@ -31,6 +31,36 @@
#include "random_seed.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;
@@ -79,6 +109,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[]= {
@@ -96,7 +138,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++) {
@@ -107,10 +149,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);
@@ -123,7 +169,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)
@@ -133,10 +178,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;
@@ -147,7 +190,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 } },
@@ -215,8 +258,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 } },
@@ -359,7 +402,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) {
@@ -373,6 +420,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,
@@ -399,19 +460,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;
@@ -471,7 +539,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;
@@ -481,9 +549,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 };
+ int today = 0, negative = 0, microseconds = 0;
int i;
static const char * const date_fmt[] = {
"%Y-%m-%d",
@@ -493,58 +563,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(&now);
- } else {
- dt = *localtime(&now);
- }
- 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 */
@@ -553,50 +606,60 @@ 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) {
/* parse timestr as S+ */
- dt.tm_sec = strtol(p, (char **)&q, 10);
- if (q == p) {
- /* the parsing didn't succeed */
- *timeval = INT64_MIN;
+ dt.tm_sec = strtol(p, (void *)&q, 10);
+ if (q == p) /* the parsing didn't succeed */
return AVERROR(EINVAL);
- }
dt.tm_min = 0;
dt.tm_hour = 0;
}
}
/* 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(&now) : *localtime(&now);
+ 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;
}
@@ -642,6 +705,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");
@@ -689,6 +759,8 @@ int main(void)
int i;
uint8_t rgba[4];
static const char *const color_names[] = {
+ "bikeshed",
+ "RaNdOm",
"foo",
"red",
"Red ",
@@ -731,6 +803,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..311b6bc
--- a/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(sizeof(*pca->z) * n);
+ 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, 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..00ddd60
--- a/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, 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 49c9072..9a33000 100644
--- a/libavutil/pixdesc.c
+++ b/libavutil/pixdesc.c
@@ -2,31 +2,33 @@
* 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 "common.h"
#include "pixfmt.h"
#include "pixdesc.h"
#include "internal.h"
#include "intreadwrite.h"
+#include "avstring.h"
void av_read_image_line(uint16_t *dst,
const uint8_t *data[4], const int linesize[4],
@@ -169,9 +171,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,
},
@@ -223,6 +225,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,
@@ -293,9 +307,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,
},
@@ -335,9 +349,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,
},
@@ -347,9 +361,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,
},
@@ -359,9 +373,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,
},
@@ -420,8 +434,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,
},
@@ -431,10 +445,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,
},
@@ -457,10 +471,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,
},
@@ -470,13 +484,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,
@@ -533,7 +595,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,
@@ -570,7 +632,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",
@@ -855,6 +917,32 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
},
.flags = AV_PIX_FMT_FLAG_RGB,
},
+ [AV_PIX_FMT_RGBA64BE] = {
+ .name = "rgba64be",
+ .nb_components= 4,
+ .log2_chroma_w= 0,
+ .log2_chroma_h= 0,
+ .comp = {
+ { 0, 7, 1, 0, 15 }, /* R */
+ { 0, 7, 3, 0, 15 }, /* G */
+ { 0, 7, 5, 0, 15 }, /* B */
+ { 0, 7, 7, 0, 15 }, /* A */
+ },
+ .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_ALPHA,
+ },
+ [AV_PIX_FMT_RGBA64LE] = {
+ .name = "rgba64le",
+ .nb_components= 4,
+ .log2_chroma_w= 0,
+ .log2_chroma_h= 0,
+ .comp = {
+ { 0, 7, 1, 0, 15 }, /* R */
+ { 0, 7, 3, 0, 15 }, /* G */
+ { 0, 7, 5, 0, 15 }, /* B */
+ { 0, 7, 7, 0, 15 }, /* A */
+ },
+ .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA,
+ },
[AV_PIX_FMT_RGB565BE] = {
.name = "rgb565be",
.nb_components = 3,
@@ -933,9 +1021,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,
},
@@ -945,21 +1033,47 @@ 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,
},
+ [AV_PIX_FMT_BGRA64BE] = {
+ .name = "bgra64be",
+ .nb_components= 4,
+ .log2_chroma_w= 0,
+ .log2_chroma_h= 0,
+ .comp = {
+ { 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,
+ },
+ [AV_PIX_FMT_BGRA64LE] = {
+ .name = "bgra64le",
+ .nb_components= 4,
+ .log2_chroma_w= 0,
+ .log2_chroma_h= 0,
+ .comp = {
+ { 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,
+ },
[AV_PIX_FMT_BGR565BE] = {
.name = "bgr565be",
.nb_components = 3,
.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,
},
@@ -969,9 +1083,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,
},
@@ -981,9 +1095,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,
},
@@ -993,9 +1107,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,
},
@@ -1005,9 +1119,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,
},
@@ -1017,9 +1131,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,
},
@@ -1041,12 +1155,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,
@@ -1095,6 +1203,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,
@@ -1167,6 +1323,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,
@@ -1263,14 +1467,68 @@ 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_Y400A] = {
- .name = "y400a",
+ [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_GRAY8A] = {
+ .name = "gray8a",
.nb_components = 2,
.comp = {
{ 0, 1, 1, 0, 7 }, /* Y */
@@ -1284,9 +1542,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,
},
@@ -1296,9 +1554,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,
},
@@ -1308,9 +1566,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,
},
@@ -1320,9 +1578,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,
},
@@ -1332,9 +1590,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,
},
@@ -1344,9 +1650,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
+ { 2, 1, 1, 0, 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,
},
@@ -1356,12 +1662,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,
@@ -1392,6 +1737,75 @@ 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
+ },
+ [AV_PIX_FMT_BAYER_BGGR16LE] = {
+ .name = "bayer_bggr16le",
+ BAYER16_DESC_COMMON
+ },
+ [AV_PIX_FMT_BAYER_BGGR16BE] = {
+ .name = "bayer_bggr16be",
+ BAYER16_DESC_COMMON
+ },
+ [AV_PIX_FMT_BAYER_RGGB8] = {
+ .name = "bayer_rggb8",
+ BAYER8_DESC_COMMON
+ },
+ [AV_PIX_FMT_BAYER_RGGB16LE] = {
+ .name = "bayer_rggb16le",
+ BAYER16_DESC_COMMON
+ },
+ [AV_PIX_FMT_BAYER_RGGB16BE] = {
+ .name = "bayer_rggb16be",
+ BAYER16_DESC_COMMON
+ },
+ [AV_PIX_FMT_BAYER_GBRG8] = {
+ .name = "bayer_gbrg8",
+ BAYER8_DESC_COMMON
+ },
+ [AV_PIX_FMT_BAYER_GBRG16LE] = {
+ .name = "bayer_gbrg16le",
+ BAYER16_DESC_COMMON
+ },
+ [AV_PIX_FMT_BAYER_GBRG16BE] = {
+ .name = "bayer_gbrg16be",
+ BAYER16_DESC_COMMON
+ },
+ [AV_PIX_FMT_BAYER_GRBG8] = {
+ .name = "bayer_grbg8",
+ BAYER8_DESC_COMMON
+ },
+ [AV_PIX_FMT_BAYER_GRBG16LE] = {
+ .name = "bayer_grbg16le",
+ BAYER16_DESC_COMMON
+ },
+ [AV_PIX_FMT_BAYER_GRBG16BE] = {
+ .name = "bayer_grbg16be",
+ BAYER16_DESC_COMMON
+ },
[AV_PIX_FMT_NV16] = {
.name = "nv16",
.nb_components = 3,
@@ -1487,6 +1901,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)
{
/* print header */
@@ -1512,8 +1946,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;
}
@@ -1554,50 +1991,62 @@ int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
return ret;
}
+void ff_check_pixfmt_descriptors(void){
+ int i, j;
-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
+ 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);
- switch (pix_fmt) {
- PIX_FMT_SWAP_ENDIANNESS(GRAY16);
- 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);
+ 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);
+ }
+ }
+}
- 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);
+enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt)
+{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
+ char name[16];
+ int i;
- PIX_FMT_SWAP_ENDIANNESS(XYZ12);
- default:
+ if (!desc || strlen(desc->name) < 2)
return AV_PIX_FMT_NONE;
- }
-#undef PIX_FMT_SWAP_ENDIANNESS
+ 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);
}
diff --git a/libavutil/pixdesc.h b/libavutil/pixdesc.h
index e5a16f4..e88bf9b 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
*/
@@ -78,9 +78,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];
}AVPixFmtDescriptor;
@@ -110,7 +113,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.
*/
@@ -186,7 +189,7 @@ void av_write_image_line(const uint16_t *src, uint8_t *data[4], const int linesi
* 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);
@@ -200,7 +203,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
@@ -222,6 +225,12 @@ char *av_get_pix_fmt_string (char *buf, int buf_size, enum AVPixelFormat pix_fmt
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.
*/
@@ -246,9 +255,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 avcodec_get_chroma_sub_sample() for a function that asserts a
+ * valid pixel format instead of returning an error code.
+ * Its recommanded 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
*/
@@ -261,6 +275,7 @@ 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.
diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h
index 43633e7..7b17a4f 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 {
@@ -139,9 +142,15 @@ enum AVPixelFormat {
AV_PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0
AV_PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), little-endian, most significant bits to 1
AV_PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), big-endian, most significant bits to 1
- AV_PIX_FMT_Y400A, ///< 8bit gray, 8bit alpha
+ AV_PIX_FMT_GRAY8A, ///< 8bit gray, 8bit alpha
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
@@ -155,6 +164,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
@@ -162,8 +178,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
@@ -182,12 +205,62 @@ 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
+
+#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 */
+
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
@@ -195,6 +268,15 @@ 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
+#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
@@ -205,6 +287,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_RGB48 AV_PIX_FMT_NE(RGB48BE, RGB48LE)
@@ -222,13 +306,30 @@ 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_RGBA64 AV_PIX_FMT_NE(RGBA64BE, RGBA64LE)
+#define AV_PIX_FMT_BGRA64 AV_PIX_FMT_NE(BGRA64BE, BGRA64LE)
#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)
@@ -246,12 +347,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
@@ -269,12 +375,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
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..8cee82c 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
*/
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 fec54e6..3667703 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 f2e0b13..fbf6d85 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
*/
diff --git a/libavutil/qsort.h b/libavutil/qsort.h
new file mode 100644
index 0000000..30edcc8
--- a/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 4680081..aa89024 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
*/
@@ -30,9 +30,17 @@
#include <fcntl.h>
#include <math.h>
#include <time.h>
+#include <string.h>
+#include "avassert.h"
#include "internal.h"
#include "timer.h"
#include "random_seed.h"
+#include "sha.h"
+#include "intreadwrite.h"
+
+#ifndef TEST
+#define TEST 0
+#endif
static int read_random(uint32_t *dst, const char *file)
{
@@ -53,34 +61,46 @@ static int read_random(uint32_t *dst, const char *file)
static uint32_t get_generic_seed(void)
{
+ uint8_t tmp[120];
+ struct AVSHA *sha = (void*)tmp;
clock_t last_t = 0;
- int bits = 0;
- uint64_t random = 0;
- unsigned i;
- float s = 0.000000000001;
+ 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 (i = 0; bits < 64; i++) {
+ for (;;) {
clock_t t = clock();
- if (last_t && fabs(t - last_t) > s || t == (clock_t) -1) {
- if (i < 10000 && s < (1 << 24)) {
- s += s;
- i = t = 0;
- } else {
- random = 2 * random + (i & 1);
- bits++;
- }
+
+ if(last_t == t){
+ buffer[i&511]++;
+ }else{
+ buffer[++i&511]+= (t-last_t) % 3294638521U;
+ if(last_i && i-last_i > 4 || i-last_i > 64 || TEST && i-last_i > 8)
+ break;
}
last_t = t;
}
-#ifdef AV_READ_TIME
- random ^= AV_READ_TIME();
-#else
- random ^= clock();
-#endif
- random += random >> 32;
+ if(TEST)
+ buffer[0] = buffer[1] = 0;
- return random;
+ av_sha_init(sha, 160);
+ av_sha_update(sha, (uint8_t*)buffer, sizeof(buffer));
+ av_sha_final(sha, digest);
+ return AV_RB32(digest) + AV_RB32(digest+16);
}
uint32_t av_get_random_seed(void)
@@ -104,3 +124,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..ec2f2e5 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,31 @@ 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);
+ }
+ }
+ }
+ }
+ return 0;
+}
+#endif
diff --git a/libavutil/rational.h b/libavutil/rational.h
index 5d7dab7..b9800ee 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
*/
@@ -55,7 +55,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/ripemd.c b/libavutil/ripemd.c
new file mode 100644
index 0000000..1ceb24b
--- a/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
--- a/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 389f726..08ecc83 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)
@@ -98,6 +107,14 @@ int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt)
0 : sample_fmt_info[sample_fmt].bits >> 3;
}
+#if FF_API_GET_BITS_PER_SAMPLE_FMT
+int av_get_bits_per_sample_fmt(enum AVSampleFormat sample_fmt)
+{
+ return sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB ?
+ 0 : sample_fmt_info[sample_fmt].bits;
+}
+#endif
+
int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt)
{
if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
@@ -147,14 +164,18 @@ 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;
+#if FF_API_SAMPLES_UTILS_RETURN_ZERO
return 0;
+#else
+ return buf_size;
+#endif
}
int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels,
@@ -179,7 +200,26 @@ 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);
+#if FF_API_SAMPLES_UTILS_RETURN_ZERO
return 0;
+#else
+ return size;
+#endif
+}
+
+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,
@@ -195,8 +235,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 33cbded..db17d43 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
*/
@@ -37,7 +37,7 @@
* [-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
+ * The data layout as used in av_samples_fill_arrays() and elsewhere in FFmpeg
* (such as AVFrame in libavcodec) is as follows:
*
* For planar sample formats, each audio channel is in a separate data plane,
@@ -76,6 +76,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
@@ -111,6 +119,14 @@ enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt);
*/
char *av_get_sample_fmt_string(char *buf, int buf_size, enum AVSampleFormat sample_fmt);
+#if FF_API_GET_BITS_PER_SAMPLE_FMT
+/**
+ * @deprecated Use av_get_bytes_per_sample() instead.
+ */
+attribute_deprecated
+int av_get_bits_per_sample_fmt(enum AVSampleFormat sample_fmt);
+#endif
+
/**
* Return number of bytes per sample.
*
@@ -142,16 +158,20 @@ int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples,
enum AVSampleFormat sample_fmt, int align);
/**
- * 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.
@@ -163,7 +183,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,
@@ -184,13 +206,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
--- a/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
--- a/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
--- a/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..97e09ea
--- a/dev/null
+++ b/libavutil/softfloat.h
@@ -0,0 +1,126 @@
+/*
+ * 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"
+
+#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(a.mant + 0x40000000 < 0){
+ a.exp++;
+ a.mant>>=1;
+ }
+ 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;
+ 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<0) return av_normalize1_sf((SoftFloat){b.exp, b.mant + (a.mant >> (-t))});
+ else return av_normalize1_sf((SoftFloat){a.exp, a.mant + (b.mant >> t )});
+}
+
+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/time.c b/libavutil/time.c
index 62cd445..5a00e70 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
*/
diff --git a/libavutil/time.h b/libavutil/time.h
index b01a97d..90eb436 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
*/
diff --git a/libavutil/timecode.c b/libavutil/timecode.c
new file mode 100644
index 0000000..d396032
--- a/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, 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
--- a/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 ea5c891..3e242f3 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
*/
diff --git a/libavutil/timestamp.h b/libavutil/timestamp.h
new file mode 100644
index 0000000..f63a08c
--- a/dev/null
+++ b/libavutil/timestamp.h
@@ -0,0 +1,74 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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"
+
+#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/utils.c b/libavutil/utils.c
index 9b18c97..dc84162 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,54 @@
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 gurantees 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");
+ }
+
+ ff_check_pixfmt_descriptors();
+ 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)
@@ -53,3 +92,22 @@ char av_get_picture_type_char(enum AVPictureType pict_type)
default: return '?';
}
}
+
+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;
+}
diff --git a/libavutil/version.h b/libavutil/version.h
index 635055f..67a2acd 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -1,25 +1,63 @@
/*
- * 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
*/
#ifndef AVUTIL_VERSION_H
#define AVUTIL_VERSION_H
-#include "avutil.h"
+/**
+ * @defgroup preproc_misc Preprocessor String Macros
+ *
+ * String manipulation macros
+ *
+ * @{
+ */
+
+#define AV_STRINGIFY(s) AV_TOSTRING(s)
+#define AV_TOSTRING(s) #s
+
+#define AV_GLUE(a, b) a ## b
+#define AV_JOIN(a, b) AV_GLUE(a, b)
+
+#define AV_PRAGMA(s) _Pragma(#s)
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup version_utils Library Version Macros
+ *
+ * Useful to check and match library version in order to maintain
+ * backward compatibility.
+ *
+ * @{
+ */
+
+#define AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c)
+#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c
+#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c)
+
+/**
+ * @}
+ */
+
/**
* @file
@@ -36,9 +74,9 @@
* @{
*/
-#define LIBAVUTIL_VERSION_MAJOR 52
-#define LIBAVUTIL_VERSION_MINOR 16
-#define LIBAVUTIL_VERSION_MICRO 0
+#define LIBAVUTIL_VERSION_MAJOR 52
+#define LIBAVUTIL_VERSION_MINOR 48
+#define LIBAVUTIL_VERSION_MICRO 100
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
LIBAVUTIL_VERSION_MINOR, \
@@ -61,6 +99,15 @@
* @{
*/
+#ifndef FF_API_GET_BITS_PER_SAMPLE_FMT
+#define FF_API_GET_BITS_PER_SAMPLE_FMT (LIBAVUTIL_VERSION_MAJOR < 53)
+#endif
+#ifndef FF_API_FIND_OPT
+#define FF_API_FIND_OPT (LIBAVUTIL_VERSION_MAJOR < 53)
+#endif
+#ifndef FF_API_OLD_AVOPTIONS
+#define FF_API_OLD_AVOPTIONS (LIBAVUTIL_VERSION_MAJOR < 53)
+#endif
#ifndef FF_API_PIX_FMT
#define FF_API_PIX_FMT (LIBAVUTIL_VERSION_MAJOR < 53)
#endif
@@ -79,6 +126,9 @@
#ifndef FF_API_CPU_FLAG_MMX2
#define FF_API_CPU_FLAG_MMX2 (LIBAVUTIL_VERSION_MAJOR < 53)
#endif
+#ifndef FF_API_SAMPLES_UTILS_RETURN_ZERO
+#define FF_API_SAMPLES_UTILS_RETURN_ZERO (LIBAVUTIL_VERSION_MAJOR < 53)
+#endif
#ifndef FF_API_LLS_PRIVATE
#define FF_API_LLS_PRIVATE (LIBAVUTIL_VERSION_MAJOR < 53)
#endif
@@ -88,9 +138,13 @@
#ifndef FF_API_VDPAU
#define FF_API_VDPAU (LIBAVUTIL_VERSION_MAJOR < 53)
#endif
+#ifndef FF_API_GET_CHANNEL_LAYOUT_COMPAT
+#define FF_API_GET_CHANNEL_LAYOUT_COMPAT (LIBAVUTIL_VERSION_MAJOR < 53)
+#endif
/**
* @}
*/
#endif /* AVUTIL_VERSION_H */
+
diff --git a/libavutil/x86/asm.h b/libavutil/x86/asm.h
index e30f5db..70ccac7 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
*/
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 0e06d5d..18049ea 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
*/
diff --git a/libavutil/x86/cpu.h b/libavutil/x86/cpu.h
index 5303c5a..3724357 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 e739ebe..56876a8 100644
--- a/libavutil/x86/cpuid.asm
+++ b/libavutil/x86/cpuid.asm
@@ -4,20 +4,20 @@
;* Authors: Loren Merritt <lorenm@u.washington.edu>
;* Jason Garrett-Glaser <darkshikari@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along 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 10330ff..49d4876 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
;******************************************************************************
@@ -44,8 +46,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)
@@ -83,8 +87,10 @@ 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
;------------------------------------------------------------------------------
; void ff_vector_fmul_scalar(float *dst, const float *src, float mul, int len)
@@ -188,8 +194,10 @@ ALIGN 16
INIT_XMM sse
VECTOR_FMUL_ADD
+%if HAVE_AVX_EXTERNAL
INIT_YMM avx
VECTOR_FMUL_ADD
+%endif
;-----------------------------------------------------------------------------
; void vector_fmul_reverse(float *dst, const float *src0, const float *src1,
@@ -225,8 +233,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
@@ -264,8 +274,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..97f7b7c 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
*/
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..181ca38 100644
--- a/libavutil/x86/lls_init.c
+++ b/libavutil/x86/lls_init.c
@@ -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
*/
diff --git a/libavutil/x86/timer.h b/libavutil/x86/timer.h
index cdd67dd..d812d46 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
*/
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 6350a5c..420e293 100644
--- a/libavutil/x86/x86inc.asm
+++ b/libavutil/x86/x86inc.asm
@@ -853,6 +853,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
diff --git a/libavutil/x86/x86util.asm b/libavutil/x86/x86util.asm
index 11779cf..59e5df2 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
;******************************************************************************
diff --git a/libavutil/x86_cpu.h b/libavutil/x86_cpu.h
new file mode 100644
index 0000000..bec1c77
--- a/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
--- a/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
--- a/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 d1efebf..5bb4cf7 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
*/
@@ -38,32 +38,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);
@@ -159,7 +243,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];
@@ -180,6 +264,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 7d2b07b..0899c92 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..3fb5a70
--- a/dev/null
+++ b/libpostproc/Makefile
@@ -0,0 +1,9 @@
+include $(SUBDIR)../config.mak
+
+NAME = postproc
+FFLIBS = avutil
+
+HEADERS = postprocess.h \
+ version.h \
+
+OBJS = postprocess.o
diff --git a/libpostproc/libpostproc.v b/libpostproc/libpostproc.v
new file mode 100644
index 0000000..e65d76f
--- a/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..b34943f
--- a/dev/null
+++ b/libpostproc/postprocess.c
@@ -0,0 +1,1045 @@
+/*
+ * 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},
+ {NULL, NULL,0,0,0,0} //End Marker
+};
+
+static const char *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(void *p)
+{
+ __asm__ volatile( "prefetchnta (%0)\n\t"
+ : : "r" (p)
+ );
+}
+
+static inline void prefetcht0(void *p)
+{
+ __asm__ volatile( "prefetcht0 (%0)\n\t"
+ : : "r" (p)
+ );
+}
+
+static inline void prefetcht1(void *p)
+{
+ __asm__ volatile( "prefetcht1 (%0)\n\t"
+ : : "r" (p)
+ );
+}
+
+static inline void prefetcht2(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++){
+ if(((unsigned)(src[0] - src[1] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[1] - src[2] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[2] - src[3] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[3] - src[4] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[4] - src[5] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[5] - src[6] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[6] - src[7] + dcOffset)) < dcThreshold) numEq++;
+ 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++){
+ if(((unsigned)(src[0] - src[0+stride] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[1] - src[1+stride] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[2] - src[2+stride] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[3] - src[3+stride] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[4] - src[4+stride] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[5] - src[5+stride] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[6] - src[6+stride] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[7] - src[7+stride] + dcOffset)) < dcThreshold) numEq++;
+ 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) ){
+ if( isHorizMinMaxOk_C(src, stride, c->QP) )
+ return 1;
+ else
+ return 0;
+ }else{
+ return 2;
+ }
+}
+
+static inline int vertClassify_C(const uint8_t src[], int stride, const PPContext *c)
+{
+ if( isVertDC_C(src, stride, c) ){
+ if( isVertMinMaxOk_C(src, stride, c->QP) )
+ return 1;
+ else
+ return 0;
+ }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= d<0 ? 0 : d;
+ d= d>q ? q : d;
+ }
+ else
+ {
+ d= d>0 ? 0 : d;
+ d= d<q ? q : d;
+ }
+
+ 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 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;
+
+ if(((unsigned)(src[-1*step] - src[0*step] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[ 0*step] - src[1*step] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[ 1*step] - src[2*step] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[ 2*step] - src[3*step] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[ 3*step] - src[4*step] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[ 4*step] - src[5*step] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[ 5*step] - src[6*step] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[ 6*step] - src[7*step] + dcOffset)) < dcThreshold) numEq++;
+ if(((unsigned)(src[ 7*step] - src[8*step] + dcOffset)) < dcThreshold) numEq++;
+ 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;
+
+ 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= d<0 ? 0 : d;
+ d= d>q ? q : d;
+ }else{
+ d= d>0 ? 0 : d;
+ d= d<q ? q : d;
+ }
+
+ 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(;;){
+ char *filterName;
+ int q= 1000000; //PP_QUALITY_MAX;
+ int chrom=-1;
+ int luma=-1;
+ char *option;
+ 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
+
+ filterToken= strtok(p, filterDelimiters);
+ if(filterToken == NULL) break;
+ p+= strlen(filterToken) + 1; // p points to next filterToken
+ filterName= strtok(filterToken, optionDelimiters);
+ av_log(NULL, AV_LOG_DEBUG, "pp: %s::%s\n", filterToken, filterName);
+
+ if(*filterName == '-'){
+ enable=0;
+ filterName++;
+ }
+
+ for(;;){ //for all options
+ option= strtok(NULL, optionDelimiters);
+ if(option == NULL) 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]!=NULL; 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!=NULL; 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]!=NULL; 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]!=NULL; 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]!=NULL && 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]!=NULL && 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 alignment, 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, 8, stride*24+32);
+ reallocAlign((void **)&c->tempSrc, 8, stride*24);
+ reallocAlign((void **)&c->tempBlocks, 8, 2*16*8);
+ reallocAlign((void **)&c->yHistogram, 8, 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], 8, stride*mbHeight*16 + 17*1024);
+ reallocAlign((void **)&c->tempBlurredPast[i], 8, 256*((height+7)&(~7))/2 + 17*1024);//FIXME size
+ }
+
+ reallocAlign((void **)&c->deintTemp, 8, 2*width+32);
+ reallocAlign((void **)&c->nonBQPTable, 8, qpStride*mbHeight*sizeof(QP_STORE_T));
+ reallocAlign((void **)&c->stdQPTable, 8, qpStride*mbHeight*sizeof(QP_STORE_T));
+ reallocAlign((void **)&c->forcedQPTable, 8, 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<3; i++) av_free(c->tempBlurred[i]);
+ for(i=0; i<3; 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 = (PPMode*)vm;
+ PPContext *c = (PPContext*)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==NULL || (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= mbHeight * absQPStride;
+ 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= mbHeight * QPStride;
+ 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);
+
+ 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..928e01f
--- a/dev/null
+++ b/libpostproc/postprocess.h
@@ -0,0 +1,106 @@
+/*
+ * 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_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
--- a/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..b1b8f0c
--- a/dev/null
+++ b/libpostproc/postprocess_internal.h
@@ -0,0 +1,179 @@
+/*
+ * 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
+
+//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
+
+#define CLIP av_clip_uint8
+
+/**
+ * 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..74b0ab4
--- a/dev/null
+++ b/libpostproc/postprocess_template.c
@@ -0,0 +1,3714 @@
+/*
+ * 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)(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)
+ : "%"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)
+ : "%"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)
+ : "%"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= 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++;
+ }
+#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)
+ : "%"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] = CLIP((-src[0] + 9*src[stride*2] + 9*src[stride*4] - src[stride*6])>>4);
+ src[stride*5] = CLIP((-src[stride*2] + 9*src[stride*4] + 9*src[stride*6] - src[stride*8])>>4);
+ src[stride*7] = CLIP((-src[stride*4] + 9*src[stride*6] + 9*src[stride*8] - src[stride*10])>>4);
+ src[stride*9] = CLIP((-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]= CLIP((-t1 + 4*src[stride*0] + 2*t2 + 4*src[stride*2] - src[stride*3] + 4)>>3);
+ t1= src[stride*4];
+ src[stride*3]= CLIP((-t2 + 4*src[stride*2] + 2*t1 + 4*src[stride*4] - src[stride*5] + 4)>>3);
+ t2= src[stride*6];
+ src[stride*5]= CLIP((-t1 + 4*src[stride*4] + 2*t2 + 4*src[stride*6] - src[stride*7] + 4)>>3);
+ t1= src[stride*8];
+ src[stride*7]= CLIP((-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
+ 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
+ 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]= CLIP((-(t1 + src[stride*2]) + 2*(t2 + src[stride*1]) + 6*t3 + 4)>>3);
+ t1= src[stride*1];
+ src[stride*1]= CLIP((-(t2 + src[stride*3]) + 2*(t3 + src[stride*2]) + 6*t1 + 4)>>3);
+ t2= src[stride*2];
+ src[stride*2]= CLIP((-(t3 + src[stride*4]) + 2*(t1 + src[stride*3]) + 6*t2 + 4)>>3);
+ t3= src[stride*3];
+ src[stride*3]= CLIP((-(t1 + src[stride*5]) + 2*(t2 + src[stride*4]) + 6*t3 + 4)>>3);
+ t1= src[stride*4];
+ src[stride*4]= CLIP((-(t2 + src[stride*6]) + 2*(t3 + src[stride*5]) + 6*t1 + 4)>>3);
+ t2= src[stride*5];
+ src[stride*5]= CLIP((-(t3 + src[stride*7]) + 2*(t1 + src[stride*6]) + 6*t2 + 4)>>3);
+ t3= src[stride*6];
+ src[stride*6]= CLIP((-(t1 + src[stride*8]) + 2*(t2 + src[stride*7]) + 6*t3 + 4)>>3);
+ t1= src[stride*7];
+ src[stride*7]= CLIP((-(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
+}
+
+/**
+ * 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, 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, 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, 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
+ __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)
+ : "%"REG_a, "%"REG_d, "%"REG_c, "memory"
+ );
+#else //TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+{
+ 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
+}
+#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, PPContext *c){
+ 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)
+ );
+
+ 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)
+ : "%"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
+ int i;
+#endif
+ if(levelFix){
+#if TEMPLATE_PP_MMX
+ __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
+ for(i=0; i<8; i++)
+ memcpy( &(dst[dstStride*i]),
+ &(src[srcStride*i]), BLOCK_SIZE);
+#endif //TEMPLATE_PP_MMX
+ }else{
+#if TEMPLATE_PP_MMX
+ __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
+ for(i=0; i<8; i++)
+ memcpy( &(dst[dstStride*i]),
+ &(src[srcStride*i]), BLOCK_SIZE);
+#endif //TEMPLATE_PP_MMX
+ }
+}
+
+/**
+ * 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 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
+/*
+ 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
+/*
+ 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);
+ }
+ }
+
+#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);
+ }
+
+ 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);
+ }
+#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/version.h b/libpostproc/version.h
new file mode 100644
index 0000000..111db44
--- a/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 52
+#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 58f6360..e48aba1 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 $@ $<
- -@ $(if $(STRIP), $(STRIP) -wN '..@*' $@)
+ -$(STRIP) -wN '..@*' $@
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 @@ $(EXAMPLES) $(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) $(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),*-example$(EXESUF) *-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..0b75bd0
--- a/dev/null
+++ b/libswresample/Makefile
@@ -0,0 +1,18 @@
+include $(SUBDIR)../config.mak
+
+NAME = swresample
+FFLIBS = avutil
+
+HEADERS = swresample.h \
+ version.h \
+
+OBJS = audioconvert.o \
+ dither.o \
+ rematrix.o \
+ resample.o \
+ swresample.o \
+
+OBJS-$(CONFIG_LIBSOXR) += soxr_resample.o
+OBJS-$(CONFIG_SHARED) += log2_tab.o
+
+TESTPROGS = swresample
diff --git a/libswresample/arm/Makefile b/libswresample/arm/Makefile
new file mode 100644
index 0000000..55683cb
--- a/dev/null
+++ b/libswresample/arm/Makefile
@@ -0,0 +1,2 @@
+OBJS += arm/audio_convert_init.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
--- a/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..471a2d8
--- a/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 swri_oldapi_conv_flt_to_s16_neon
+ beq 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/audioconvert.c b/libswresample/audioconvert.c
new file mode 100644
index 0000000..4ba0ff1
--- a/dev/null
+++ b/libswresample/audioconvert.c
@@ -0,0 +1,224 @@
+/*
+ * 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 - 0x80)<<8)
+CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<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);
+
+ 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
--- a/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..7cbe410
--- a/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((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
--- a/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..9b797bd
--- a/dev/null
+++ b/libswresample/libswresample.v
@@ -0,0 +1,4 @@
+LIBSWRESAMPLE_$MAJOR {
+ global: swr_*; ff_*; swresample_*;
+ local: *;
+};
diff --git a/libswresample/log2_tab.c b/libswresample/log2_tab.c
new file mode 100644
index 0000000..47a1df0
--- a/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
--- a/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/rematrix.c b/libswresample/rematrix.c
new file mode 100644
index 0000000..5c98e68
--- a/dev/null
+++ b/libswresample/rematrix.c
@@ -0,0 +1,500 @@
+/*
+ * 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
+
+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[64][64]={{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(!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<64; 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;
+ for(j=0; j<64; j++){
+ s->matrix[out_i][in_i]= matrix[i][j];
+ if(matrix[i][j]){
+ sum += fabs(matrix[i][j]);
+ }
+ if(in_ch_layout & (1ULL<<j))
+ in_i++;
+ }
+ maxcoef= FFMAX(maxcoef, sum);
+ if(out_ch_layout & (1ULL<<i))
+ 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(out->ch_count == av_get_channel_layout_nb_channels(s->out_ch_layout));
+ av_assert0(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
--- a/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..8b1b6ca
--- a/dev/null
+++ b/libswresample/resample.c
@@ -0,0 +1,372 @@
+/*
+ * 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/log.h"
+#include "libavutil/avassert.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 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;
+} ResampleContext;
+
+/**
+ * 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(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);
+ }
+
+ 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->index= -phase_count*((c->filter_length-1)/2);
+ c->frac= 0;
+
+ 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;
+ return 0;
+}
+
+#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
+
+// XXX FIXME the whole C loop should be written in asm so this x86 specific code here isnt needed
+#if HAVE_MMXEXT_INLINE
+
+#include "x86/resample_mmx.h"
+
+#define TEMPLATE_RESAMPLE_S16_MMX2
+#include "resample_template.c"
+#undef TEMPLATE_RESAMPLE_S16_MMX2
+
+#if HAVE_SSSE3_INLINE
+#define TEMPLATE_RESAMPLE_S16_SSSE3
+#include "resample_template.c"
+#undef TEMPLATE_RESAMPLE_S16_SSSE3
+#endif
+
+#endif // HAVE_MMXEXT_INLINE
+
+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= 0;
+
+ for(i=0; i<dst->ch_count; i++){
+#if HAVE_MMXEXT_INLINE
+#if HAVE_SSSE3_INLINE
+ if(c->format == AV_SAMPLE_FMT_S16P && (mm_flags&AV_CPU_FLAG_SSSE3)) ret= swri_resample_int16_ssse3(c, (int16_t*)dst->ch[i], (const int16_t*)src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count);
+ else
+#endif
+ if(c->format == AV_SAMPLE_FMT_S16P && (mm_flags&AV_CPU_FLAG_MMX2 )){
+ ret= swri_resample_int16_mmx2 (c, (int16_t*)dst->ch[i], (const int16_t*)src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count);
+ need_emms= 1;
+ } else
+#endif
+ if(c->format == AV_SAMPLE_FMT_S16P) ret= swri_resample_int16(c, (int16_t*)dst->ch[i], (const int16_t*)src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count);
+ else if(c->format == AV_SAMPLE_FMT_S32P) ret= swri_resample_int32(c, (int32_t*)dst->ch[i], (const int32_t*)src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count);
+ else if(c->format == AV_SAMPLE_FMT_FLTP) ret= swri_resample_float(c, (float *)dst->ch[i], (const float *)src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count);
+ else if(c->format == AV_SAMPLE_FMT_DBLP) ret= swri_resample_double(c,(double *)dst->ch[i], (const double *)src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count);
+ }
+ if(need_emms)
+ emms_c();
+ 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;
+}
+
+struct Resampler const swri_resampler={
+ resample_init,
+ resample_free,
+ multiple_resample,
+ resample_flush,
+ set_compensation,
+ get_delay,
+};
diff --git a/libswresample/resample_template.c b/libswresample/resample_template.c
new file mode 100644
index 0000000..5bc12bc
--- a/dev/null
+++ b/libswresample/resample_template.c
@@ -0,0 +1,211 @@
+/*
+ * 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 FELEML 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 FELEML 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 FELEML 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) \
+ || defined(TEMPLATE_RESAMPLE_S16_MMX2) \
+ || defined(TEMPLATE_RESAMPLE_S16_SSSE3)
+
+# 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
+
+# if defined(TEMPLATE_RESAMPLE_S16)
+# define RENAME(N) N ## _int16
+# elif defined(TEMPLATE_RESAMPLE_S16_MMX2)
+# define COMMON_CORE COMMON_CORE_INT16_MMX2
+# define RENAME(N) N ## _int16_mmx2
+# elif defined(TEMPLATE_RESAMPLE_S16_SSSE3)
+# define COMMON_CORE COMMON_CORE_INT16_SSSE3
+# define RENAME(N) N ## _int16_ssse3
+# endif
+
+#endif
+
+int RENAME(swri_resample)(ResampleContext *c, DELEM *dst, const DELEM *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;
+
+ av_assert1(c->filter_shift == FILTER_SHIFT);
+ av_assert1(c->felem_size == sizeof(FELEM));
+
+ 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;
+ av_assert2(index >= 0);
+ *consumed= index >> c->phase_shift;
+ index &= c->phase_mask;
+ }else if(compensation_distance == 0 && !c->linear && index >= 0){
+ int sample_index = 0;
+ for(dst_index=0; dst_index < dst_size; dst_index++){
+ FELEM *filter;
+ sample_index += index >> c->phase_shift;
+ index &= c->phase_mask;
+ filter= ((FELEM*)c->filter_bank) + c->filter_alloc*index;
+
+ if(sample_index + c->filter_length > src_size){
+ break;
+ }else{
+#ifdef COMMON_CORE
+ COMMON_CORE
+#else
+ FELEM2 val=0;
+ for(i=0; i<c->filter_length; i++){
+ val += src[sample_index + i] * (FELEM2)filter[i];
+ }
+ OUT(dst[dst_index], val);
+#endif
+ }
+
+ frac += dst_incr_frac;
+ index += dst_incr;
+ if(frac >= c->src_incr){
+ frac -= c->src_incr;
+ index++;
+ }
+ }
+ *consumed = sample_index;
+ }else{
+ int sample_index = 0;
+ for(dst_index=0; dst_index < dst_size; dst_index++){
+ FELEM *filter;
+ FELEM2 val=0;
+
+ sample_index += index >> c->phase_shift;
+ index &= c->phase_mask;
+ filter = ((FELEM*)c->filter_bank) + c->filter_alloc*index;
+
+ if(sample_index + c->filter_length > src_size || -sample_index >= src_size){
+ break;
+ }else if(sample_index < 0){
+ for(i=0; i<c->filter_length; i++)
+ val += src[FFABS(sample_index + i)] * (FELEM2)filter[i];
+ }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_alloc];
+ }
+ 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];
+ }
+ }
+
+ OUT(dst[dst_index], val);
+
+ 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(sample_index, 0);
+ index += FFMIN(sample_index, 0) << c->phase_shift;
+
+ if(compensation_distance){
+ compensation_distance -= dst_index;
+ av_assert1(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;
+}
+
+#undef COMMON_CORE
+#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..4c000db
--- a/dev/null
+++ b/libswresample/soxr_resample.c
@@ -0,0 +1,93 @@
+/*
+ * 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);
+}
+
+struct Resampler const soxr_resampler={
+ create, destroy, process, flush, NULL /* set_compensation */, get_delay,
+};
+
diff --git a/libswresample/swresample-test.c b/libswresample/swresample-test.c
new file mode 100644
index 0000000..379d385
--- a/dev/null
+++ b/libswresample/swresample-test.c
@@ -0,0 +1,414 @@
+/*
+ * 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 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 varing 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..30c3434
--- a/dev/null
+++ b/libswresample/swresample.c
@@ -0,0 +1,934 @@
+/*
+ * 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 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 ALIGN 32
+
+//TODO split options array out?
+#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 , AV_SAMPLE_FMT_NB-1, PARAM},
+{"in_sample_fmt" , "set input sample format" , OFFSET( in_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , AV_SAMPLE_FMT_NB-1, PARAM},
+{"osf" , "set output sample format" , OFFSET(out_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , AV_SAMPLE_FMT_NB-1, PARAM},
+{"out_sample_fmt" , "set output sample format" , OFFSET(out_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , AV_SAMPLE_FMT_NB-1, PARAM},
+{"tsf" , "set internal sample format" , OFFSET(int_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , AV_SAMPLE_FMT_NB-1, PARAM},
+{"internal_sample_fmt" , "set internal sample format" , OFFSET(int_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , AV_SAMPLE_FMT_NB-1, 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,
+};
+
+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;
+}
+
+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;
+}
+
+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;
+
+ av_opt_set_int(s, "ocl", out_ch_layout, 0);
+ av_opt_set_int(s, "osf", out_sample_fmt, 0);
+ av_opt_set_int(s, "osr", out_sample_rate, 0);
+ av_opt_set_int(s, "icl", in_ch_layout, 0);
+ av_opt_set_int(s, "isf", in_sample_fmt, 0);
+ av_opt_set_int(s, "isr", in_sample_rate, 0);
+ av_opt_set_int(s, "tsf", AV_SAMPLE_FMT_NONE, 0);
+ av_opt_set_int(s, "ich", av_get_channel_layout_nb_channels(s-> in_ch_layout), 0);
+ av_opt_set_int(s, "och", av_get_channel_layout_nb_channels(s->out_ch_layout), 0);
+ av_opt_set_int(s, "uch", 0, 0);
+ return s;
+}
+
+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);
+}
+
+static void free_temp(AudioData *a){
+ av_free(a->data);
+ memset(a, 0, sizeof(*a));
+}
+
+av_cold void swr_free(SwrContext **ss){
+ SwrContext *s= *ss;
+ if(s){
+ 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);
+ if (s->resampler)
+ s->resampler->free(&s->resample);
+ swri_rematrix_free(s);
+ }
+
+ av_freep(ss);
+}
+
+av_cold int swr_init(struct SwrContext *s){
+ int ret;
+ s->in_buffer_index= 0;
+ s->in_buffer_count= 0;
+ s->resample_in_constraint= 0;
+ 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);
+ memset(s->in.ch, 0, sizeof(s->in.ch));
+ memset(s->out.ch, 0, sizeof(s->out.ch));
+ 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;
+
+ 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;
+
+ 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;
+
+ 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) && !s->in_buffer_count){
+ s->in_buffer_index=0;
+ ret= s->resampler->multiple_resample(s->resample, &out, out_count, &in, in_count, &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;
+ }
+ 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_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;
+
+ 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;
+ continue;
+ }
+
+ if(s->drop_output || !out_arg)
+ 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){
+ 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, NULL, 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..3811301
--- a/dev/null
+++ b/libswresample/swresample.h
@@ -0,0 +1,311 @@
+/*
+ * 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.
+ *
+ * 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):
+ * @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
+ *
+ * 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
+ * as described above, or by using swr_alloc_set_opts(), 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 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().
+ * There will be no memory leak if the data is not completely flushed before
+ * swr_free().
+ */
+
+#include <stdint.h>
+#include "libavutil/samplefmt.h"
+
+#include "libswresample/version.h"
+
+#if LIBSWRESAMPLE_VERSION_MAJOR < 1
+#define SWR_CH_MAX 32 ///< Maximum number of channels
+#endif
+
+#define SWR_FLAG_RESAMPLE 1 ///< Force resampling even if equal sample rate
+//TODO use int resample ?
+//long term TODO can we enable this dynamically?
+
+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 */
+};
+
+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().
+ */
+const AVClass *swr_get_class(void);
+
+/**
+ * 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.
+ *
+ * @return AVERROR error code in case of failure.
+ */
+int swr_init(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 Swr context, can be NULL
+ * @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);
+
+/**
+ * Free the given SwrContext and set the pointer to NULL.
+ */
+void swr_free(struct SwrContext **s);
+
+/**
+ * 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.
+ * Convertion 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.
+ * First is when automatic timestamp compensation is not used, (min_compensation >= FLT_MAX)
+ * in this case timestamps will be passed through with delays compensated
+ * Second is when automatic timestamp compensation is used, (min_compensation < FLT_MAX)
+ * in this case the output timestamps will match output sample numbers
+ *
+ * @param pts timestamp for the next input sample, INT64_MIN if unknown
+ * @return the output timestamp for the next output sample
+ */
+int64_t swr_next_pts(struct SwrContext *s, int64_t pts);
+
+/**
+ * Activate resampling compensation.
+ */
+int swr_set_compensation(struct SwrContext *s, int sample_delta, int compensation_distance);
+
+/**
+ * Set a customized input channel mapping.
+ *
+ * @param s allocated Swr context, not yet initialized
+ * @param channel_map customized input channel mapping (array of channel
+ * indexes, -1 for a muted channel)
+ * @return 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 AVERROR error code in case of failure.
+ */
+int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride);
+
+/**
+ * Drops the specified number of output samples.
+ */
+int swr_drop_output(struct SwrContext *s, int count);
+
+/**
+ * Injects the specified number of silence samples.
+ */
+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
+ * if its set to 1 the returned delay is in seconds
+ * if its set to 1000 the returned delay is in milli seconds
+ * if its set to the input sample rate then the returned delay is in input samples
+ * if its set to the output sample rate then the returned delay is in output samples
+ * an exact rounding free delay can be found by using LCM(in_sample_rate, out_sample_rate)
+ * @returns the delay in 1/base units.
+ */
+int64_t swr_get_delay(struct SwrContext *s, int64_t base);
+
+/**
+ * Return the LIBSWRESAMPLE_VERSION_INT constant.
+ */
+unsigned swresample_version(void);
+
+/**
+ * Return the swr build-time configuration.
+ */
+const char *swresample_configuration(void);
+
+/**
+ * Return the swr license.
+ */
+const char *swresample_license(void);
+
+/**
+ * @}
+ */
+
+#endif /* SWRESAMPLE_SWRESAMPLE_H */
diff --git a/libswresample/swresample_internal.h b/libswresample/swresample_internal.h
new file mode 100644
index 0000000..ab19f21
--- a/dev/null
+++ b/libswresample/swresample_internal.h
@@ -0,0 +1,199 @@
+/*
+ * 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 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 isnt 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);
+
+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;
+};
+
+extern struct Resampler const swri_resampler;
+
+int swri_realloc_audio(AudioData *a, int count);
+int swri_resample_int16(struct ResampleContext *c, int16_t *dst, const int16_t *src, int *consumed, int src_size, int dst_size, int update_ctx);
+int swri_resample_int32(struct ResampleContext *c, int32_t *dst, const int32_t *src, int *consumed, int src_size, int dst_size, int update_ctx);
+int swri_resample_float(struct ResampleContext *c, float *dst, const float *src, int *consumed, int src_size, int dst_size, int update_ctx);
+int swri_resample_double(struct ResampleContext *c,double *dst, const double *src, int *consumed, int src_size, int dst_size, int update_ctx);
+
+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_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/version.h b/libswresample/version.h
new file mode 100644
index 0000000..464c86d
--- a/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 0
+#define LIBSWRESAMPLE_VERSION_MINOR 17
+#define LIBSWRESAMPLE_VERSION_MICRO 104
+
+#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..e8feede
--- a/dev/null
+++ b/libswresample/x86/Makefile
@@ -0,0 +1,3 @@
+YASM-OBJS += x86/swresample_x86.o\
+ x86/audio_convert.o\
+ x86/rematrix.o\
diff --git a/libswresample/x86/audio_convert.asm b/libswresample/x86/audio_convert.asm
new file mode 100644
index 0000000..b6e9e5d
--- a/dev/null
+++ b/libswresample/x86/audio_convert.asm
@@ -0,0 +1,465 @@
+;******************************************************************************
+;* 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(sse4)
+ SBUTTERFLYPS 0, 1, 6
+ SBUTTERFLYPS 2, 3, 6
+ SBUTTERFLYPS 4, 5, 6
+
+ blendps m6, m4, m0, 1100b
+ movlhps m0, m2
+ movhlps m4, m2
+ blendps m2, m5, m1, 1100b
+ 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
+ cmpnltps %1, %5
+ paddd %1, %6
+ cvtps2dq %6, %2
+ cmpnltps %2, %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 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
+
+
+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
+
+INIT_XMM sse4
+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
+
+%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
diff --git a/libswresample/x86/rematrix.asm b/libswresample/x86/rematrix.asm
new file mode 100644
index 0000000..f0ae959
--- a/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/resample_mmx.h b/libswresample/x86/resample_mmx.h
new file mode 100644
index 0000000..d96fd5a
--- a/dev/null
+++ b/libswresample/x86/resample_mmx.h
@@ -0,0 +1,70 @@
+/*
+ * 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 "libavutil/x86/asm.h"
+#include "libavutil/cpu.h"
+#include "libswresample/swresample_internal.h"
+
+int swri_resample_int16_mmx2 (struct ResampleContext *c, int16_t *dst, const int16_t *src, int *consumed, int src_size, int dst_size, int update_ctx);
+int swri_resample_int16_ssse3(struct ResampleContext *c, int16_t *dst, const int16_t *src, int *consumed, int src_size, int dst_size, int update_ctx);
+
+DECLARE_ALIGNED(16, const uint64_t, ff_resample_int16_rounder)[2] = { 0x0000000000004000ULL, 0x0000000000000000ULL};
+
+#define COMMON_CORE_INT16_MMX2 \
+ x86_reg len= -2*c->filter_length;\
+__asm__ volatile(\
+ "movq "MANGLE(ff_resample_int16_rounder)", %%mm0 \n\t"\
+ "1: \n\t"\
+ "movq (%1, %0), %%mm1 \n\t"\
+ "pmaddwd (%2, %0), %%mm1 \n\t"\
+ "paddd %%mm1, %%mm0 \n\t"\
+ "add $8, %0 \n\t"\
+ " js 1b \n\t"\
+ "pshufw $0x0E, %%mm0, %%mm1 \n\t"\
+ "paddd %%mm1, %%mm0 \n\t"\
+ "psrad $15, %%mm0 \n\t"\
+ "packssdw %%mm0, %%mm0 \n\t"\
+ "movd %%mm0, (%3) \n\t"\
+ : "+r" (len)\
+ : "r" (((uint8_t*)(src+sample_index))-len),\
+ "r" (((uint8_t*)filter)-len),\
+ "r" (dst+dst_index)\
+);
+
+#define COMMON_CORE_INT16_SSSE3 \
+ x86_reg len= -2*c->filter_length;\
+__asm__ volatile(\
+ "movdqa "MANGLE(ff_resample_int16_rounder)", %%xmm0 \n\t"\
+ "1: \n\t"\
+ "movdqu (%1, %0), %%xmm1 \n\t"\
+ "pmaddwd (%2, %0), %%xmm1 \n\t"\
+ "paddd %%xmm1, %%xmm0 \n\t"\
+ "add $16, %0 \n\t"\
+ " js 1b \n\t"\
+ "phaddd %%xmm0, %%xmm0 \n\t"\
+ "phaddd %%xmm0, %%xmm0 \n\t"\
+ "psrad $15, %%xmm0 \n\t"\
+ "packssdw %%xmm0, %%xmm0 \n\t"\
+ "movd %%xmm0, (%3) \n\t"\
+ : "+r" (len)\
+ : "r" (((uint8_t*)(src+sample_index))-len),\
+ "r" (((uint8_t*)filter)-len),\
+ "r" (dst+dst_index)\
+);
diff --git a/libswresample/x86/swresample_x86.c b/libswresample/x86/swresample_x86.c
new file mode 100644
index 0000000..581dc17
--- a/dev/null
+++ b/libswresample/x86/swresample_x86.c
@@ -0,0 +1,200 @@
+/*
+ * 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 "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)
+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 (mm_flags & flag) {\
+ 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(AV_CPU_FLAG_MMX, mmx)
+MULTI_CAPS_FUNC(AV_CPU_FLAG_SSE2, sse2)
+
+ if(mm_flags & AV_CPU_FLAG_MMX) {
+ 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(mm_flags & AV_CPU_FLAG_SSE2) {
+ 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(mm_flags & AV_CPU_FLAG_SSSE3) {
+ 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(mm_flags & AV_CPU_FLAG_SSE4) {
+ 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_sse4;
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_pack_6ch_int32_to_float_a_sse4;
+ if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP)
+ ac->simd_f = ff_pack_6ch_float_to_int32_a_sse4;
+ }
+ }
+ if(HAVE_AVX_EXTERNAL && mm_flags & AV_CPU_FLAG_AVX) {
+ 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;
+ }
+ }
+}
+
+#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){
+ 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(mm_flags & AV_CPU_FLAG_MMX) {
+ 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(mm_flags & AV_CPU_FLAG_SSE2) {
+ 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(mm_flags & AV_CPU_FLAG_SSE) {
+ 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(HAVE_AVX_EXTERNAL && mm_flags & AV_CPU_FLAG_AVX) {
+ 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));
+ }
+}
diff --git a/libswscale/Makefile b/libswscale/Makefile
index 0799b45..dd00f7d 100644
--- a/libswscale/Makefile
+++ b/libswscale/Makefile
@@ -1,3 +1,5 @@
+include $(SUBDIR)../config.mak
+
NAME = swscale
FFLIBS = avutil
diff --git a/libswscale/bfin/internal_bfin.S b/libswscale/bfin/internal_bfin.S
index b007f07..eab30aa 100644
--- a/libswscale/bfin/internal_bfin.S
+++ b/libswscale/bfin/internal_bfin.S
@@ -5,20 +5,20 @@
* Blackfin video color space converter operations
* convert I420 YV12 to RGB in various formats
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along 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/bfin/swscale_bfin.c b/libswscale/bfin/swscale_bfin.c
index 43c23b4..33c3ec5 100644
--- a/libswscale/bfin/swscale_bfin.c
+++ b/libswscale/bfin/swscale_bfin.c
@@ -3,20 +3,20 @@
*
* Blackfin software video scaler 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/libswscale/bfin/yuv2rgb_bfin.c b/libswscale/bfin/yuv2rgb_bfin.c
index 603a33a..2a36ad5 100644
--- a/libswscale/bfin/yuv2rgb_bfin.c
+++ b/libswscale/bfin/yuv2rgb_bfin.c
@@ -4,23 +4,24 @@
* Blackfin video color space converter operations
* convert I420 YV12 to RGB in various formats
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License 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 <stdint.h>
#include "config.h"
@@ -196,7 +197,7 @@ av_cold SwsFunc ff_yuv2rgb_init_bfin(SwsContext *c)
}
av_log(c, AV_LOG_INFO, "BlackFin accelerated color space converter %s\n",
- sws_format_name(c->dstFormat));
+ av_get_pix_fmt_name(c->dstFormat));
return f;
}
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/input.c b/libswscale/input.c
index 2e8d43f..919b232 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,115 @@
#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)
+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)
+
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 +146,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 +168,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 +183,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 +195,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 +247,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 +255,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 +268,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 +281,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 +295,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,12 +309,13 @@ 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;
@@ -249,8 +337,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 +346,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 +390,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 +518,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 +526,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 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;
@@ -395,7 +539,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;
@@ -410,7 +554,7 @@ static void bswap16UV_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *_src1,
/* 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;
@@ -418,7 +562,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;
@@ -426,7 +570,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,
@@ -440,14 +584,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);
@@ -455,218 +599,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)
{
@@ -699,6 +838,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;
@@ -708,9 +854,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;
@@ -721,14 +875,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:
@@ -742,14 +903,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:
@@ -760,6 +928,12 @@ 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_RGB48BE:
c->chrToYV12 = rgb48BEToUV_half_c;
break;
@@ -793,6 +967,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;
@@ -829,6 +1007,12 @@ 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_RGB48BE:
c->chrToYV12 = rgb48BEToUV_c;
break;
@@ -907,6 +1091,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;
@@ -916,9 +1107,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;
@@ -929,9 +1129,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;
@@ -954,9 +1161,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;
@@ -1059,9 +1273,21 @@ 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;
}
if (c->alpPixBuf) {
+ if (is16BPS(srcFormat) || isNBPS(srcFormat)) {
+ if (HAVE_BIGENDIAN == !isBE(srcFormat))
+ c->alpToYV12 = bswap16Y_c;
+ }
switch (srcFormat) {
+ 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;
@@ -1073,6 +1299,9 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_Y400A:
c->alpToYV12 = uyvyToY_c;
break;
+ case AV_PIX_FMT_PAL8 :
+ c->alpToYV12 = palToA_c;
+ break;
}
}
}
diff --git a/libswscale/options.c b/libswscale/options.c
index e7765d6..9e8703f 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,26 @@ 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 = -1 }, -1, 512, VE },
+ { "src_h_chr_pos", "source horizontal chroma position in luma grid/256", OFFSET(src_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 512, VE },
+ { "dst_v_chr_pos", "destination vertical chroma position in luma grid/256" , OFFSET(dst_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 512, VE },
+ { "dst_h_chr_pos", "destination horizontal chroma position in luma grid/256", OFFSET(dst_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 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" },
+
{ 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 e1d01b0..ddb0d0c 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
@@ -516,10 +592,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);
}
@@ -536,10 +614,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);
@@ -551,10 +636,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);
@@ -581,12 +673,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(B_R + Y1, 30) >> 14);
+ output_pixel(&dest[1], av_clip_uintp2( G + Y1, 30) >> 14);
+ output_pixel(&dest[2], av_clip_uintp2(R_B + Y1, 30) >> 14);
+ output_pixel(&dest[3], av_clip_uintp2(A1 , 30) >> 14);
+ output_pixel(&dest[4], av_clip_uintp2(B_R + Y2, 30) >> 14);
+ output_pixel(&dest[5], av_clip_uintp2( G + Y2, 30) >> 14);
+ output_pixel(&dest[6], av_clip_uintp2(R_B + 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(B_R + Y1, 30) >> 14);
+ output_pixel(&dest[1], av_clip_uintp2( G + Y1, 30) >> 14);
+ output_pixel(&dest[2], av_clip_uintp2(R_B + Y1, 30) >> 14);
+ output_pixel(&dest[3], av_clip_uintp2(A1 , 30) >> 14);
+ output_pixel(&dest[4], av_clip_uintp2(B_R + Y2, 30) >> 14);
+ output_pixel(&dest[5], av_clip_uintp2( G + Y2, 30) >> 14);
+ output_pixel(&dest[6], av_clip_uintp2(R_B + 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(B_R + Y1, 30) >> 14);
+ output_pixel(&dest[1], av_clip_uintp2( G + Y1, 30) >> 14);
+ output_pixel(&dest[2], av_clip_uintp2(R_B + Y1, 30) >> 14);
+ output_pixel(&dest[3], av_clip_uintp2(A1 , 30) >> 14);
+ output_pixel(&dest[4], av_clip_uintp2(B_R + Y2, 30) >> 14);
+ output_pixel(&dest[5], av_clip_uintp2( G + Y2, 30) >> 14);
+ output_pixel(&dest[6], av_clip_uintp2(R_B + 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(B_R + Y1, 30) >> 14);
+ output_pixel(&dest[1], av_clip_uintp2( G + Y1, 30) >> 14);
+ output_pixel(&dest[2], av_clip_uintp2(R_B + Y1, 30) >> 14);
+ output_pixel(&dest[3], av_clip_uintp2(A1 , 30) >> 14);
+ output_pixel(&dest[4], av_clip_uintp2(B_R + Y2, 30) >> 14);
+ output_pixel(&dest[5], av_clip_uintp2( G + Y2, 30) >> 14);
+ output_pixel(&dest[6], av_clip_uintp2(R_B + 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;
@@ -599,12 +910,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
@@ -644,7 +955,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],
@@ -685,7 +996,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;
@@ -752,7 +1063,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, \
@@ -767,7 +1078,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], \
@@ -781,7 +1092,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, \
@@ -795,13 +1106,17 @@ 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)
/*
* Write out 2 RGB pixels in the target pixel format. This function takes a
@@ -812,7 +1127,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)
@@ -833,9 +1148,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];
}
@@ -848,6 +1169,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];
@@ -866,19 +1188,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];
@@ -953,12 +1275,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;
@@ -974,10 +1290,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);
@@ -1006,16 +1321,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;
@@ -1041,25 +1349,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);
}
@@ -1070,25 +1371,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);
}
@@ -1111,7 +1405,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], \
@@ -1120,8 +1415,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, \
@@ -1151,6 +1448,98 @@ 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;
+ 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);
+ 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,
@@ -1161,13 +1550,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];
@@ -1180,7 +1574,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];
}
@@ -1188,78 +1582,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,
@@ -1271,16 +1723,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];
@@ -1323,10 +1776,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)) {
@@ -1334,6 +1791,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]);
}
}
}
@@ -1357,10 +1816,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;
@@ -1373,77 +1839,161 @@ 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_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..86f40ab 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
*/
@@ -295,7 +295,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 21adfe1..ec9ff71 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,
@@ -105,7 +106,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))
@@ -181,13 +181,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
}
@@ -220,9 +220,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);
}
}
@@ -256,13 +256,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
}
@@ -276,9 +276,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);
}
}
@@ -315,18 +315,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, \
@@ -346,3 +334,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 79c378d..340cc70 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 3da2b0b..98e3a14 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
}
@@ -376,9 +355,9 @@ static inline void yuvPlanartoyuy2_c(const uint8_t *ysrc, const uint8_t *usrc,
const uint8_t *yc = ysrc, *uc = usrc, *vc = vsrc;
for (i = 0; i < chromWidth; i += 2) {
uint64_t k = yc[0] + (uc[0] << 8) +
- (yc[1] << 16) + (vc[0] << 24);
+ (yc[1] << 16) + (unsigned)(vc[0] << 24);
uint64_t l = yc[2] + (uc[1] << 8) +
- (yc[3] << 16) + (vc[1] << 24);
+ (yc[3] << 16) + (unsigned)(vc[1] << 24);
*ldst++ = k + (l << 32);
yc += 4;
uc += 2;
@@ -440,9 +419,9 @@ static inline void yuvPlanartouyvy_c(const uint8_t *ysrc, const uint8_t *usrc,
const uint8_t *yc = ysrc, *uc = usrc, *vc = vsrc;
for (i = 0; i < chromWidth; i += 2) {
uint64_t k = uc[0] + (yc[0] << 8) +
- (vc[0] << 16) + (yc[1] << 24);
+ (vc[0] << 16) + (unsigned)(yc[1] << 24);
uint64_t l = uc[1] + (yc[2] << 8) +
- (vc[1] << 16) + (yc[3] << 24);
+ (vc[1] << 16) + (unsigned)(yc[3] << 24);
*ldst++ = k + (l << 32);
yc += 4;
uc += 2;
@@ -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;
@@ -838,7 +823,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);
@@ -858,7 +843,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);
@@ -876,7 +861,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);
@@ -896,7 +881,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);
@@ -935,7 +920,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;
vu9_to_vu12 = vu9_to_vu12_c;
yvu9_to_yuy2 = yvu9_to_yuy2_c;
diff --git a/libswscale/sparc/yuv2rgb_vis.c b/libswscale/sparc/yuv2rgb_vis.c
index cd8a8b0..ed00837 100644
--- a/libswscale/sparc/yuv2rgb_vis.c
+++ b/libswscale/sparc/yuv2rgb_vis.c
@@ -2,20 +2,20 @@
* VIS optimized software YUV to RGB converter
* Copyright (c) 2007 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/libswscale/swscale-test.c b/libswscale/swscale-test.c
index 12fa9ed..e0b887e 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
*/
@@ -51,7 +51,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;
@@ -90,7 +90,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;
@@ -106,6 +106,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]) {
@@ -123,7 +124,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;
@@ -139,6 +140,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]) {
@@ -164,7 +166,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],
@@ -177,6 +179,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]) {
@@ -195,7 +198,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)) {
@@ -302,7 +305,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) {
@@ -313,7 +316,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;
}
@@ -342,7 +346,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 };
@@ -352,34 +356,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) {
@@ -399,9 +389,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..710dce3 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -1,29 +1,29 @@
/*
- * 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"
@@ -35,7 +35,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 +44,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 +62,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 +73,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 +98,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];
@@ -232,7 +217,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;
+ dst[i] = (dst[i]*(14071/4) + (33561947<<4)/4)>>12;
}
static void hyscale_fast_c(SwsContext *c, int16_t *dst, int dstWidth,
@@ -246,6 +231,8 @@ static void hyscale_fast_c(SwsContext *c, int16_t *dst, int dstWidth,
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;
}
// *** horizontal scale Y line to temp buffer
@@ -258,16 +245,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;
}
@@ -295,6 +285,10 @@ static void hcscale_fast_c(SwsContext *c, int16_t *dst1, int16_t *dst2,
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;
+ }
}
static av_always_inline void hcscale(SwsContext *c, int16_t *dst1,
@@ -309,14 +303,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 +350,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 +373,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 +386,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 +413,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]%16 !=0 || dstStride[1]%16 !=0 ||
+ dstStride[2]%16 !=0 || dstStride[3]%16 != 0) {
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 +424,19 @@ static int swscale(SwsContext *c, const uint8_t *src[],
}
}
+ if ( (uintptr_t)dst[0]%16 || (uintptr_t)dst[1]%16 || (uintptr_t)dst[2]%16
+ || (uintptr_t)src[0]%16 || (uintptr_t)src[1]%16 || (uintptr_t)src[2]%16
+ || dstStride[0]%16 || dstStride[1]%16 || dstStride[2]%16 || dstStride[3]%16
+ || srcStride[0]%16 || srcStride[1]%16 || srcStride[2]%16 || srcStride[3]%16
+ ) {
+ 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 +461,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 +480,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 +491,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 +509,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 +531,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 +566,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 +666,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 +675,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);
}
@@ -728,8 +714,9 @@ 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;
@@ -739,12 +726,12 @@ static av_cold void sws_init_swscale(SwsContext *c)
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->dstBpc <= 14) {
if (c->srcRange) {
c->lumConvertRange = lumRangeFromJpeg_c;
c->chrConvertRange = chrRangeFromJpeg_c;
@@ -779,3 +766,349 @@ 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_c(r,0,4095);
+ g = av_clip_c(g,0,4095);
+ b = av_clip_c(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->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) {
+ 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_c(x,0,4095);
+ y = av_clip_c(y,0,4095);
+ z = av_clip_c(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 (!srcSlice || !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;
+ }
+ 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 p, r, g, b, y, u, v, a = 0xff;
+ if (c->srcFormat == AV_PIX_FMT_PAL8) {
+ 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 e69a694..42702b7 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
*/
@@ -23,8 +23,13 @@
/**
* @file
- * @brief
- * external api for the swscale stuff
+ * @ingroup lsws
+ * external API header
+ */
+
+/**
+ * @defgroup lsws Libswscale
+ * @{
*/
#include <stdint.h>
@@ -77,6 +82,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
/**
@@ -222,7 +228,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],
@@ -343,4 +355,8 @@ void sws_convertPalette8ToPacked24(const uint8_t *src, uint8_t *dst, int num_pix
*/
const AVClass *sws_get_class(void);
+/**
+ * @}
+ */
+
#endif /* SWSCALE_SWSCALE_H */
diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h
index 5737724..33fdfc2 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
*/
@@ -30,16 +30,19 @@
#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 256
+#define DITHER1XBPP
+
#if HAVE_BIGENDIAN
#define ALT32_CORR (-1)
#else
@@ -58,6 +61,14 @@
struct SwsContext;
+typedef enum SwsDither {
+ SWS_DITHER_NONE = 0,
+ SWS_DITHER_AUTO,
+ SWS_DITHER_BAYER,
+ SWS_DITHER_ED,
+ 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[]);
@@ -351,10 +362,23 @@ 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];
+ uint8_t *table_rV[256 + 2*YUVRGB_TABLE_HEADROOM];
+ uint8_t *table_gU[256 + 2*YUVRGB_TABLE_HEADROOM];
+ int table_gV[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, teh 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 +386,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;
@@ -418,8 +450,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];
@@ -453,6 +485,17 @@ typedef struct SwsContext {
#if HAVE_VIS
DECLARE_ALIGNED(8, uint64_t, sparc_coeffs)[10];
#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;
@@ -464,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);
/** @} */
/**
@@ -557,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)
@@ -575,7 +621,13 @@ SwsFunc ff_yuv2rgb_init_vis(SwsContext *c);
SwsFunc ff_yuv2rgb_init_ppc(SwsContext *c);
SwsFunc ff_yuv2rgb_init_bfin(SwsContext *c);
+#if FF_API_SWS_FORMAT_NAME
+/**
+ * @deprecated Use av_get_pix_fmt_name() instead.
+ */
+attribute_deprecated
const char *sws_format_name(enum AVPixelFormat format);
+#endif
static av_always_inline int is16BPS(enum AVPixelFormat pix_fmt)
{
@@ -588,9 +640,11 @@ static av_always_inline int is9_OR_10BPS(enum AVPixelFormat pix_fmt)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
av_assert0(desc);
- return desc->comp[0].depth_minus1 == 8 || desc->comp[0].depth_minus1 == 9;
+ return desc->comp[0].depth_minus1 >= 8 && desc->comp[0].depth_minus1 <= 13;
}
+#define isNBPS(x) is9_OR_10BPS(x)
+
static av_always_inline int isBE(enum AVPixelFormat pix_fmt)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
@@ -621,8 +675,8 @@ static av_always_inline int isRGB(enum AVPixelFormat pix_fmt)
#if 0 // FIXME
#define isGray(x) \
- (!(av_pix_fmt_descriptors[x].flags & AV_PIX_FMT_FLAG_PAL) && \
- av_pix_fmt_descriptors[x].nb_components <= 2)
+ (!(av_pix_fmt_desc_get(x)->flags & AV_PIX_FMT_FLAG_PAL) && \
+ av_pix_fmt_desc_get(x)->nb_components <= 2)
#else
#define isGray(x) \
((x) == AV_PIX_FMT_GRAY8 || \
@@ -631,9 +685,12 @@ static av_always_inline int isRGB(enum AVPixelFormat pix_fmt)
(x) == AV_PIX_FMT_GRAY16LE)
#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_RGBA64BE || \
+ (x) == AV_PIX_FMT_RGBA64LE || \
(x) == AV_PIX_FMT_RGB32 || \
(x) == AV_PIX_FMT_RGB32_1 || \
(x) == AV_PIX_FMT_RGB24 || \
@@ -647,11 +704,14 @@ static av_always_inline int isRGB(enum AVPixelFormat pix_fmt)
(x) == AV_PIX_FMT_RGB4 || \
(x) == AV_PIX_FMT_RGB4_BYTE || \
(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_BGRA64BE || \
+ (x) == AV_PIX_FMT_BGRA64LE || \
(x) == AV_PIX_FMT_BGR32 || \
(x) == AV_PIX_FMT_BGR32_1 || \
(x) == AV_PIX_FMT_BGR24 || \
@@ -665,19 +725,54 @@ static av_always_inline int isRGB(enum AVPixelFormat pix_fmt)
(x) == AV_PIX_FMT_BGR4 || \
(x) == AV_PIX_FMT_BGR4_BYTE || \
(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 isAnyRGB(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_UYVY422 \
+ || (x)==AV_PIX_FMT_Y400A \
+ || 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);
@@ -686,6 +781,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);
@@ -712,18 +808,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_Y400A);
+ 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];
@@ -755,4 +852,24 @@ void ff_sws_init_output_funcs(SwsContext *c,
void ff_sws_init_swscale_ppc(SwsContext *c);
void ff_sws_init_swscale_x86(SwsContext *c);
+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 3e5f49e..83086f7 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)
@@ -300,19 +321,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;
@@ -330,7 +355,7 @@ static int palToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY;
const uint8_t *srcPtr = src[0];
- if (srcFormat == AV_PIX_FMT_Y400A) {
+ if (srcFormat == AV_PIX_FMT_GRAY8A) {
switch (dstFormat) {
case AV_PIX_FMT_RGB32 : conv = gray8aToPacked32; break;
case AV_PIX_FMT_BGR32 : conv = gray8aToPacked32; break;
@@ -352,7 +377,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);
@@ -364,6 +389,185 @@ static int palToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
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)
@@ -467,6 +671,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)
@@ -548,6 +768,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)
@@ -557,17 +791,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)) {
@@ -583,6 +811,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)) ||
@@ -624,6 +878,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;
}
@@ -635,34 +892,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 * srcStride[0]);
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];
}
@@ -675,13 +950,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;
@@ -720,7 +996,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);
@@ -731,25 +1007,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[],
@@ -760,174 +1036,132 @@ 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) {
+ int orig_length = length;
+ for (i = 0; i < height; i++) {
+ if(isBE(c->srcFormat) == HAVE_BIGENDIAN &&
+ isBE(c->dstFormat) == HAVE_BIGENDIAN &&
+ shiftonly) {
+ unsigned shift = dst_depth - src_depth;
+ length = orig_length;
+#if HAVE_FAST_64BIT
+#define FAST_COPY_UP(shift) \
+ for (j = 0; j < length - 3; j += 4) { \
+ uint64_t v = AV_RN64A(srcPtr2 + j); \
+ AV_WN64A(dstPtr2 + j, v << shift); \
+ } \
+ length &= 3;
+#else
+#define FAST_COPY_UP(shift) \
+ for (j = 0; j < length - 1; j += 2) { \
+ uint32_t v = AV_RN32A(srcPtr2 + j); \
+ AV_WN32A(dstPtr2 + j, v << shift); \
+ } \
+ length &= 1;
+#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 = 0; j < length; j++){ \
+ unsigned int v= r(&srcPtr2[j]);\
+ w(&dstPtr2[j], v<<(dst_depth-src_depth));\
+ }\
+ }else{\
+ for (j = 0; 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)) {
@@ -984,7 +1218,7 @@ 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);
}
@@ -1005,6 +1239,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 || \
@@ -1016,6 +1254,18 @@ 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_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;
@@ -1023,23 +1273,40 @@ void ff_get_unscaled_swscale(SwsContext *c)
/* bswap 16 bits per pixel/component packed formats */
if (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_GRAY16) ||
+ 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_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) {
@@ -1070,13 +1337,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_GRAY8A)
/* 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 &&
@@ -1095,177 +1363,6 @@ void ff_get_unscaled_swscale(SwsContext *c)
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 p, r, g, b, y, u, v;
- if (c->srcFormat == AV_PIX_FMT_PAL8) {
- 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_Y400A) {
- 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);
-
- 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);
- break;
- case AV_PIX_FMT_BGR32_1:
-#if HAVE_BIGENDIAN
- case AV_PIX_FMT_BGR24:
-#endif
- c->pal_rgb[i] = (r + (g << 8) + (b << 16)) << 8;
- break;
- case AV_PIX_FMT_RGB32_1:
-#if HAVE_BIGENDIAN
- case AV_PIX_FMT_RGB24:
-#endif
- c->pal_rgb[i] = (b + (g << 8) + (r << 16)) << 8;
- 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);
- }
- }
- }
-
- // 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);
- }
-}
-
/* Convert the palette to the same packed 32-bit format as the palette */
void sws_convertPalette8ToPacked32(const uint8_t *src, uint8_t *dst,
int num_pixels, const uint8_t *palette)
diff --git a/libswscale/utils.c b/libswscale/utils.c
index 2111fc2..69087dc 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,6 +38,7 @@
#endif
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "libavutil/avutil.h"
#include "libavutil/bswap.h"
#include "libavutil/cpu.h"
@@ -52,20 +53,23 @@
#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
@@ -90,6 +94,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_UYVY422] = { 1, 1 },
@@ -106,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 },
@@ -133,6 +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] = { 1, 1 },
+ [AV_PIX_FMT_RGBA64LE] = { 1, 1 },
[AV_PIX_FMT_RGB565BE] = { 1, 1 },
[AV_PIX_FMT_RGB565LE] = { 1, 1 },
[AV_PIX_FMT_RGB555BE] = { 1, 1 },
@@ -154,27 +165,48 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = {
[AV_PIX_FMT_Y400A] = { 1, 0 },
[AV_PIX_FMT_BGR48BE] = { 1, 1 },
[AV_PIX_FMT_BGR48LE] = { 1, 1 },
+ [AV_PIX_FMT_BGRA64BE] = { 0, 0 },
+ [AV_PIX_FMT_BGRA64LE] = { 0, 0 },
[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 },
};
int sws_isSupportedInput(enum AVPixelFormat pix_fmt)
@@ -195,6 +227,7 @@ int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt)
format_entries[pix_fmt].is_supported_endianness : 0;
}
+#if FF_API_SWS_FORMAT_NAME
const char *sws_format_name(enum AVPixelFormat format)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
@@ -203,6 +236,7 @@ const char *sws_format_name(enum AVPixelFormat format)
else
return "Unknown format";
}
+#endif
static double getSplineCoeff(double a, double b, double c, double d,
double dist)
@@ -217,12 +251,21 @@ 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 < 0) {
+ pos = (128 << chr_subsample) - 128;
+ }
+ pos += 128; // relative to ideal left edge
+ return pos >> chr_subsample;
+}
+
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;
@@ -230,7 +273,7 @@ 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)
@@ -238,7 +281,7 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
// 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);
- if (FFABS(xInc - 0x10000) < 10) { // unscaled
+ if (FFABS(xInc - 0x10000) < 10 && srcPos == dstPos) { // unscaled
int i;
filterSize = 1;
FF_ALLOCZ_OR_GOTO(NULL, filter,
@@ -250,12 +293,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);
- 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;
@@ -266,12 +309,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);
- 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;
@@ -279,8 +322,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;
@@ -309,8 +351,7 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
else if (flags & SWS_BILINEAR)
sizeFactor = 2;
else {
- sizeFactor = 0; // GCC warning killer
- assert(0);
+ av_assert0(0);
}
if (xInc <= 1 << 16)
@@ -324,7 +365,7 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
FF_ALLOC_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 - ((filterSize - 2) << 16)) / (1 << 17);
int j;
@@ -358,7 +399,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) {
@@ -409,8 +450,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;
@@ -423,13 +463,13 @@ 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);
+ av_assert0(filter2Size > 0);
FF_ALLOCZ_OR_GOTO(NULL, filter2, filter2Size * dstW * sizeof(*filter2), fail);
for (i = 0; i < dstW; i++) {
@@ -505,19 +545,21 @@ 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);
+ av_assert0(filterSize > 0);
filter = av_malloc(filterSize * dstW * sizeof(*filter));
if (filterSize >= MAX_FILTER_SIZE * 16 /
- ((flags & SWS_ACCURATE_RND) ? APCK_SIZE : 16) || !filter)
+ ((flags & SWS_ACCURATE_RND) ? APCK_SIZE : 16) || !filter) {
+ av_log(NULL, AV_LOG_ERROR, "sws: filterSize %d is too large, try less extreem scaling or increase MAX_FILTER_SIZE and recompile\n", filterSize);
goto fail;
+ }
*outFilterSize = filterSize;
if (flags & SWS_PRINT_INFO)
@@ -541,29 +583,27 @@ 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;
}
}
@@ -582,6 +622,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);
@@ -604,6 +648,8 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
ret = 0;
fail:
+ if(ret < 0)
+ av_log(NULL, AV_LOG_ERROR, "sws: initFilter failed\n");
av_free(filter);
av_free(filter2);
return ret;
@@ -775,40 +821,180 @@ static av_cold int init_hscaler_mmxext(int dstW, int xInc, uint8_t *filterCode,
}
#endif /* HAVE_MMXEXT_INLINE */
-static void getSubSampleFactors(int *h, int *v, enum AVPixelFormat format)
+static void fill_rgb2yuv_table(SwsContext *c, const int table[4], int dstRange)
{
- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
- *h = desc->log2_chroma_w;
- *v = desc->log2_chroma_h;
+ 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;
+ }
+ 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);
+}
+
+static void fill_xyztables(struct SwsContext *c)
+{
+ 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;
+ 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;
c->srcRange = srcRange;
c->dstRange = dstRange;
- if (isYUV(c->dstFormat) || isGray(c->dstFormat))
+
+ fill_xyztables(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;
}
@@ -816,7 +1002,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;
@@ -836,6 +1022,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;
@@ -845,11 +1034,41 @@ static int handle_jpeg(enum AVPixelFormat *format)
case AV_PIX_FMT_YUVJ440P:
*format = AV_PIX_FMT_YUV440P;
return 1;
+ case AV_PIX_FMT_GRAY8:
+ 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);
+}
+
SwsContext *sws_alloc_context(void)
{
SwsContext *c = av_mallocz(sizeof(SwsContext));
@@ -865,7 +1084,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 };
@@ -873,13 +1092,12 @@ 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;
cpu_flags = av_get_cpu_flags();
flags = c->flags;
@@ -889,16 +1107,32 @@ 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 (!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);
+
+ 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");
+ 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);
}
}
@@ -918,19 +1152,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",
@@ -958,9 +1192,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) {
+ 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,
@@ -981,10 +1262,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;
}
@@ -1004,16 +1290,20 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
srcFormat != AV_PIX_FMT_RGB4_BYTE && srcFormat != AV_PIX_FMT_BGR4_BYTE &&
srcFormat != AV_PIX_FMT_GBRP9BE && srcFormat != AV_PIX_FMT_GBRP9LE &&
srcFormat != AV_PIX_FMT_GBRP10BE && srcFormat != AV_PIX_FMT_GBRP10LE &&
+ srcFormat != AV_PIX_FMT_GBRP12BE && srcFormat != AV_PIX_FMT_GBRP12LE &&
+ srcFormat != AV_PIX_FMT_GBRP14BE && srcFormat != AV_PIX_FMT_GBRP14LE &&
srcFormat != AV_PIX_FMT_GBRP16BE && srcFormat != AV_PIX_FMT_GBRP16LE &&
((dstW >> c->chrDstHSubSample) <= (srcW >> 1) ||
(flags & SWS_FAST_BILINEAR)))
c->chrSrcHSubSample = 1;
- // Note the -((-x)>>y) is so that we always round toward +inf.
- c->chrSrcW = -((-srcW) >> c->chrSrcHSubSample);
- c->chrSrcH = -((-srcH) >> c->chrSrcVSubSample);
- c->chrDstW = -((-dstW) >> c->chrDstHSubSample);
- c->chrDstH = -((-dstH) >> c->chrDstVSubSample);
+ // Note the FF_CEIL_RSHIFT is so that we always round toward +inf.
+ c->chrSrcW = FF_CEIL_RSHIFT(srcW, c->chrSrcHSubSample);
+ c->chrSrcH = FF_CEIL_RSHIFT(srcH, c->chrSrcVSubSample);
+ c->chrDstW = FF_CEIL_RSHIFT(dstW, c->chrDstHSubSample);
+ c->chrDstH = FF_CEIL_RSHIFT(dstH, c->chrDstVSubSample);
+
+ FF_ALLOC_OR_GOTO(c, c->formatConvBuffer, FFALIGN(srcW*2+78, 16) * 2, fail);
/* unscaled special cases */
if (unscaled && !usesHFilter && !usesVFilter &&
@@ -1024,7 +1314,7 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
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));
+ av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat));
return 0;
}
}
@@ -1035,21 +1325,22 @@ 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) {
+
+ if (INLINE_MMXEXT(cpu_flags) && c->srcBpc == 8 && c->dstBpc <= 14) {
c->canMMXEXTBeUsed = (dstW >= srcW && (dstW & 31) == 0 &&
(srcW & 15) == 0) ? 1 : 0;
if (!c->canMMXEXTBeUsed && dstW >= srcW && (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;
@@ -1070,7 +1361,7 @@ 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;
}
@@ -1111,21 +1402,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( dstW, c->lumXInc, c->lumMmxextFilterCode,
+ c->hLumFilter, (uint32_t*)c->hLumFilterPos, 8);
init_hscaler_mmxext(c->chrDstW, c->chrXInc, c->chrMmxextFilterCode,
- c->hChrFilter, c->hChrFilterPos, 4);
+ 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 */
@@ -1138,14 +1440,18 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
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,
&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
@@ -1159,14 +1465,19 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
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,
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
@@ -1208,6 +1519,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);
@@ -1223,9 +1537,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);
@@ -1242,38 +1556,46 @@ 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) {
+ const char *scaler, *cpucaps;
if (flags & SWS_FAST_BILINEAR)
- av_log(c, AV_LOG_INFO, "FAST_BILINEAR scaler, ");
+ scaler = "FAST_BILINEAR scaler";
else if (flags & SWS_BILINEAR)
- av_log(c, AV_LOG_INFO, "BILINEAR scaler, ");
+ scaler = "BILINEAR scaler";
else if (flags & SWS_BICUBIC)
- av_log(c, AV_LOG_INFO, "BICUBIC scaler, ");
+ scaler = "BICUBIC scaler";
else if (flags & SWS_X)
- av_log(c, AV_LOG_INFO, "Experimental scaler, ");
+ scaler = "Experimental scaler";
else if (flags & SWS_POINT)
- av_log(c, AV_LOG_INFO, "Nearest Neighbor / POINT scaler, ");
+ scaler = "Nearest Neighbor / POINT scaler";
else if (flags & SWS_AREA)
- av_log(c, AV_LOG_INFO, "Area Averaging scaler, ");
+ scaler = "Area Averaging scaler";
else if (flags & SWS_BICUBLIN)
- av_log(c, AV_LOG_INFO, "luma BICUBIC / chroma BILINEAR scaler, ");
+ scaler = "luma BICUBIC / chroma BILINEAR scaler";
else if (flags & SWS_GAUSS)
- av_log(c, AV_LOG_INFO, "Gaussian scaler, ");
+ scaler = "Gaussian scaler";
else if (flags & SWS_SINC)
- av_log(c, AV_LOG_INFO, "Sinc scaler, ");
+ scaler = "Sinc scaler";
else if (flags & SWS_LANCZOS)
- av_log(c, AV_LOG_INFO, "Lanczos scaler, ");
+ scaler = "Lanczos scaler";
else if (flags & SWS_SPLINE)
- av_log(c, AV_LOG_INFO, "Bicubic spline scaler, ");
+ scaler = "Bicubic spline scaler";
else
- av_log(c, AV_LOG_INFO, "ehh flags invalid?! ");
+ scaler = "ehh flags invalid?!";
- av_log(c, AV_LOG_INFO, "from %s to %s%s ",
- sws_format_name(srcFormat),
+ av_log(c, AV_LOG_INFO, "%s, 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 ||
@@ -1282,18 +1604,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,
@@ -1327,8 +1651,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;
@@ -1336,9 +1658,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);
@@ -1413,7 +1732,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;
@@ -1428,7 +1752,12 @@ SwsVector *sws_getGaussianVec(double variance, double quality)
const int length = (int)(variance * quality + 0.5) | 1;
int i;
double middle = (length - 1) * 0.5;
- SwsVector *vec = sws_allocVec(length);
+ SwsVector *vec;
+
+ if(variance < 0 || quality < 0)
+ return NULL;
+
+ vec = sws_allocVec(length);
if (!vec)
return NULL;
@@ -1595,14 +1924,12 @@ void sws_convVec(SwsVector *a, SwsVector *b)
SwsVector *sws_cloneVec(SwsVector *a)
{
- int i;
SwsVector *vec = sws_allocVec(a->length);
if (!vec)
return NULL;
- for (i = 0; i < a->length; i++)
- vec->coeff[i] = a->coeff[i];
+ memcpy(vec->coeff, a->coeff, a->length * sizeof(*a->coeff));
return vec;
}
@@ -1647,14 +1974,10 @@ void sws_freeFilter(SwsFilter *filter)
if (!filter)
return;
- if (filter->lumH)
- sws_freeVec(filter->lumH);
- if (filter->lumV)
- sws_freeVec(filter->lumV);
- if (filter->chrH)
- sws_freeVec(filter->chrH);
- if (filter->chrV)
- sws_freeVec(filter->chrV);
+ sws_freeVec(filter->lumH);
+ sws_freeVec(filter->lumV);
+ sws_freeVec(filter->chrH);
+ sws_freeVec(filter->chrV);
av_free(filter);
}
@@ -1683,6 +2006,9 @@ void sws_freeContext(SwsContext *c)
av_freep(&c->alpPixBuf);
}
+ for (i = 0; i < 4; i++)
+ av_freep(&c->dither_error[i]);
+
av_freep(&c->vLumFilter);
av_freep(&c->vChrFilter);
av_freep(&c->hLumFilter);
@@ -1717,7 +2043,7 @@ void sws_freeContext(SwsContext *c)
#endif /* HAVE_MMX_INLINE */
av_freep(&c->yuvTable);
- av_free(c->formatConvBuffer);
+ av_freep(&c->formatConvBuffer);
av_free(c);
}
@@ -1755,19 +2081,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 5483673..360ec82 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/avutil.h"
#define LIBSWSCALE_VERSION_MAJOR 2
-#define LIBSWSCALE_VERSION_MINOR 1
-#define LIBSWSCALE_VERSION_MICRO 2
+#define LIBSWSCALE_VERSION_MINOR 5
+#define LIBSWSCALE_VERSION_MICRO 101
#define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \
LIBSWSCALE_VERSION_MINOR, \
@@ -52,5 +52,8 @@
#ifndef FF_API_SWS_CPU_CAPS
#define FF_API_SWS_CPU_CAPS (LIBSWSCALE_VERSION_MAJOR < 3)
#endif
+#ifndef FF_API_SWS_FORMAT_NAME
+#define FF_API_SWS_FORMAT_NAME (LIBSWSCALE_VERSION_MAJOR < 3)
+#endif
#endif /* SWSCALE_VERSION_H */
diff --git a/libswscale/x86/Makefile b/libswscale/x86/Makefile
index b94b14a..e767a5c 100644
--- a/libswscale/x86/Makefile
+++ b/libswscale/x86/Makefile
@@ -1,3 +1,5 @@
+$(SUBDIR)x86/swscale_mmx.o: CFLAGS += $(NOREDZONE_FLAGS)
+
OBJS += x86/rgb2rgb.o \
x86/swscale.o \
x86/yuv2rgb.o \
diff --git a/libswscale/x86/input.asm b/libswscale/x86/input.asm
index 6f5677e..0c4f30e 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
@@ -322,6 +348,7 @@ cglobal %2%3%4%5 %+ ToY, 3, 3, %1, dst, src, w
movsxd wq, wd
%endif
lea srcq, [srcq+wq*4]
+ add wq, wq
add dstq, wq
neg wq
mova m4, [rgb_Yrnd]
@@ -329,8 +356,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,12 +367,11 @@ 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
REP_RET
%endif ; %0 == 3
@@ -354,7 +380,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 +401,22 @@ 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
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,25 +432,22 @@ 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
REP_RET
%endif ; ARCH_X86_64 && %0 == 3
@@ -451,8 +475,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 +515,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 +585,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 +619,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 +640,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 +652,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 +685,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 +693,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 d4f2580..986afc4 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,10 @@ 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;
-#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))
diff --git a/libswscale/x86/rgb2rgb_template.c b/libswscale/x86/rgb2rgb_template.c
index 5aeef8c..d684b70 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
*/
@@ -129,14 +129,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" \
@@ -715,27 +712,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;
@@ -754,9 +730,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"
@@ -784,9 +761,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"
@@ -832,9 +810,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);
}
}
@@ -856,9 +834,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"
@@ -886,9 +866,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"
@@ -933,9 +915,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);
}
}
@@ -978,11 +960,12 @@ 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)
:"memory");
d += 16;
s += 4;
@@ -992,9 +975,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;
}
}
@@ -1019,11 +1002,13 @@ 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)
:"memory");
d += 16;
s += 4;
@@ -1033,9 +1018,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;
}
}
@@ -1627,10 +1612,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) {
@@ -1638,7 +1628,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"
@@ -1657,12 +1647,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"
@@ -1682,12 +1670,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"
@@ -1702,7 +1688,7 @@ 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)
: "%"REG_a, "%"REG_d
);
ydst += lumStride;
@@ -1712,7 +1698,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"
@@ -1761,19 +1747,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"
@@ -1823,19 +1807,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"
@@ -1854,7 +1836,7 @@ 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)
: "%"REG_a, "%"REG_d
);
@@ -1867,8 +1849,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
@@ -2371,7 +2354,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);
@@ -2397,7 +2380,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);
@@ -2421,7 +2404,7 @@ 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);
@@ -2447,7 +2430,7 @@ 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);
@@ -2503,7 +2486,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);
diff --git a/libswscale/x86/scale.asm b/libswscale/x86/scale.asm
index 440a27b..940f357 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
diff --git a/libswscale/x86/swscale.c b/libswscale/x86/swscale.c
index 0b5f870..a86f9f8 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,15 @@ 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 +114,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 +183,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 +194,83 @@ 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){
+ return yuv2yuvX_MMXEXT(filter, filterSize, src, dest, dstW, dither, offset);
+ }
+ if (offset) {
+ __asm__ volatile("movq (%0), %%xmm3\n\t"
+ "movdqa %%xmm3, %%xmm4\n\t"
+ "psrlq $24, %%xmm3\n\t"
+ "psllq $40, %%xmm4\n\t"
+ "por %%xmm4, %%xmm3\n\t"
+ :: "r"(dither)
+ );
+ } else {
+ __asm__ volatile("movq (%0), %%xmm3\n\t"
+ :: "r"(dither)
+ );
+ }
+ filterSize--;
+ __asm__ volatile(
+ "pxor %%xmm0, %%xmm0\n\t"
+ "punpcklbw %%xmm0, %%xmm3\n\t"
+ "movd %0, %%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"
+ ::"m"(filterSize)
+ );
+ __asm__ volatile(
+ "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"\
+ :: "g" (filter),
+ "r" (dest-offset), "g" ((x86_reg)(dstW+offset)), "m" (offset)
+ : "%"REG_d, "%"REG_S, "%"REG_c
+ );
+}
+#endif
+
#endif /* HAVE_INLINE_ASM */
#define SCALE_FUNC(filter_n, from_bpc, to_bpc, opt) \
@@ -216,10 +284,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 +347,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 +388,31 @@ av_cold void ff_sws_init_swscale_x86(SwsContext *c)
#if HAVE_MMXEXT_INLINE
if (cpu_flags & AV_CPU_FLAG_MMXEXT)
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 +427,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; \
+ default: if (condition_8bit) /*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 80a3ad9..c7a1bb4 100644
--- a/libswscale/x86/swscale_template.c
+++ b/libswscale/x86/swscale_template.c
@@ -1,25 +1,26 @@
/*
- * 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
*/
#undef REAL_MOVNTQ
#undef MOVNTQ
+#undef MOVNTQ2
#undef PREFETCH
#if COMPILE_TEMPLATE_MMXEXT
@@ -30,11 +31,95 @@
#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"\
@@ -260,7 +345,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
@@ -293,7 +378,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
@@ -350,7 +435,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
@@ -374,7 +459,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
@@ -427,7 +512,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
@@ -451,7 +536,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
@@ -584,7 +669,7 @@ 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
@@ -608,7 +693,7 @@ 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
@@ -649,7 +734,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 */
@@ -670,7 +755,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 */
@@ -786,8 +871,8 @@ static void RENAME(yuv2rgb32_2)(SwsContext *c, const int16_t *buf[2],
: "%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"
@@ -1559,9 +1644,9 @@ 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) {
@@ -1574,6 +1659,8 @@ 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;
@@ -1585,7 +1672,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:
@@ -1614,7 +1700,7 @@ 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) {
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 9968a8d..a54b84a 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"
@@ -74,10 +73,6 @@ av_cold SwsFunc ff_yuv2rgb_init_x86(SwsContext *c)
#if HAVE_MMX_INLINE
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 (cpu_flags & AV_CPU_FLAG_MMXEXT) {
switch (c->dstFormat) {
diff --git a/libswscale/x86/yuv2rgb_template.c b/libswscale/x86/yuv2rgb_template.c
index b028e93..c879102 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
*/
@@ -43,17 +43,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 \
@@ -141,6 +138,7 @@
: "+r" (index), "+r" (image) \
: "r" (pu - index), "r" (pv - index), "r"(&c->redDither), \
"r" (py - 2*index) \
+ : "memory" \
); \
} \
@@ -148,6 +146,7 @@
: "+r" (index), "+r" (image) \
: "r" (pu - index), "r" (pv - index), "r"(&c->redDither), \
"r" (py - 2*index), "r" (pa - 2*index) \
+ : "memory" \
); \
} \
@@ -188,7 +187,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)
@@ -216,7 +215,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)
@@ -306,7 +305,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)
@@ -324,7 +323,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)
@@ -368,7 +367,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)
@@ -389,7 +388,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)
@@ -411,7 +410,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)
@@ -432,7 +431,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 f939bbe..77c56a9 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]; \
@@ -574,7 +615,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:
@@ -585,23 +626,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;
@@ -616,36 +655,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;
}
}
@@ -688,7 +723,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];
@@ -733,12 +768,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:
@@ -851,6 +886,7 @@ av_cold int ff_yuv2rgb_c_init_tables(SwsContext *c, const int inv_table[4],
fill_gv_table(c->table_gV, 1, cgv);
break;
case 32:
+ case 64:
base = (c->dstFormat == AV_PIX_FMT_RGB32_1 ||
c->dstFormat == AV_PIX_FMT_BGR32_1) ? 8 : 0;
rbase = base + (isRgb ? 16 : 0);
@@ -876,7 +912,6 @@ av_cold int ff_yuv2rgb_c_init_tables(SwsContext *c, const int inv_table[4],
fill_gv_table(c->table_gV, 4, cgv);
break;
default:
- c->yuvTable = NULL;
if(!isPlanar(c->dstFormat) || bpp <= 24)
av_log(c, AV_LOG_ERROR, "%ibpp not supported by yuv2rgb\n", bpp);
return -1;
diff --git a/presets/libvpx-1080p.avpreset b/presets/libvpx-1080p.avpreset
deleted file mode 100644
index 5c7da6f..0000000
--- a/presets/libvpx-1080p.avpreset
+++ b/dev/null
@@ -1,17 +0,0 @@
-g=120
-lag-in-frames=16
-deadline=good
-cpu-used=0
-profile=1
-qmax=51
-qmin=11
-slices=4
-b=2M
-
-#ignored unless using -pass 2
-maxrate=24M
-minrate=100k
-auto-alt-ref=1
-arnr-maxframes=7
-arnr-strength=5
-arnr-type=centered
diff --git a/presets/libvpx-1080p.ffpreset b/presets/libvpx-1080p.ffpreset
new file mode 100644
index 0000000..cf25932
--- a/dev/null
+++ b/presets/libvpx-1080p.ffpreset
@@ -0,0 +1,19 @@
+vcodec=libvpx
+
+g=120
+lag-in-frames=16
+deadline=good
+cpu-used=0
+vprofile=1
+qmax=51
+qmin=11
+slices=4
+b=2M
+
+#ignored unless using -pass 2
+maxrate=24M
+minrate=100k
+auto-alt-ref=1
+arnr-maxframes=7
+arnr-strength=5
+arnr-type=centered
diff --git a/presets/libvpx-1080p50_60.avpreset b/presets/libvpx-1080p50_60.avpreset
deleted file mode 100644
index f85d3d6..0000000
--- a/presets/libvpx-1080p50_60.avpreset
+++ b/dev/null
@@ -1,17 +0,0 @@
-g=120
-lag-in-frames=25
-deadline=good
-cpu-used=0
-profile=1
-qmax=51
-qmin=11
-slices=4
-b=2M
-
-#ignored unless using -pass 2
-maxrate=24M
-minrate=100k
-auto-alt-ref=1
-arnr-maxframes=7
-arnr-strength=5
-arnr-type=centered
diff --git a/presets/libvpx-1080p50_60.ffpreset b/presets/libvpx-1080p50_60.ffpreset
new file mode 100644
index 0000000..4a88040
--- a/dev/null
+++ b/presets/libvpx-1080p50_60.ffpreset
@@ -0,0 +1,19 @@
+vcodec=libvpx
+
+g=120
+lag-in-frames=25
+deadline=good
+cpu-used=0
+vprofile=1
+qmax=51
+qmin=11
+slices=4
+b=2M
+
+#ignored unless using -pass 2
+maxrate=24M
+minrate=100k
+auto-alt-ref=1
+arnr-maxframes=7
+arnr-strength=5
+arnr-type=centered
diff --git a/presets/libvpx-360p.avpreset b/presets/libvpx-360p.avpreset
deleted file mode 100644
index 2cb9e38..0000000
--- a/presets/libvpx-360p.avpreset
+++ b/dev/null
@@ -1,16 +0,0 @@
-g=120
-lag-in-frames=16
-deadline=good
-cpu-used=0
-profile=0
-qmax=63
-qmin=0
-b=768k
-
-#ignored unless using -pass 2
-maxrate=1.5M
-minrate=40k
-auto-alt-ref=1
-arnr-maxframes=7
-arnr-strength=5
-arnr-type=centered
diff --git a/presets/libvpx-360p.ffpreset b/presets/libvpx-360p.ffpreset
new file mode 100644
index 0000000..f9729ba
--- a/dev/null
+++ b/presets/libvpx-360p.ffpreset
@@ -0,0 +1,18 @@
+vcodec=libvpx
+
+g=120
+lag-in-frames=16
+deadline=good
+cpu-used=0
+vprofile=0
+qmax=63
+qmin=0
+b=768k
+
+#ignored unless using -pass 2
+maxrate=1.5M
+minrate=40k
+auto-alt-ref=1
+arnr-maxframes=7
+arnr-strength=5
+arnr-type=centered
diff --git a/presets/libvpx-720p.avpreset b/presets/libvpx-720p.avpreset
deleted file mode 100644
index 3c7e396..0000000
--- a/presets/libvpx-720p.avpreset
+++ b/dev/null
@@ -1,17 +0,0 @@
-g=120
-lag-in-frames=16
-deadline=good
-cpu-used=0
-profile=0
-qmax=51
-qmin=11
-slices=4
-b=2M
-
-#ignored unless using -pass 2
-maxrate=24M
-minrate=100k
-auto-alt-ref=1
-arnr-maxframes=7
-arnr-strength=5
-arnr-type=centered
diff --git a/presets/libvpx-720p.ffpreset b/presets/libvpx-720p.ffpreset
new file mode 100644
index 0000000..e84cc15
--- a/dev/null
+++ b/presets/libvpx-720p.ffpreset
@@ -0,0 +1,19 @@
+vcodec=libvpx
+
+g=120
+lag-in-frames=16
+deadline=good
+cpu-used=0
+vprofile=0
+qmax=51
+qmin=11
+slices=4
+b=2M
+
+#ignored unless using -pass 2
+maxrate=24M
+minrate=100k
+auto-alt-ref=1
+arnr-maxframes=7
+arnr-strength=5
+arnr-type=centered
diff --git a/presets/libvpx-720p50_60.avpreset b/presets/libvpx-720p50_60.avpreset
deleted file mode 100644
index 6139300..0000000
--- a/presets/libvpx-720p50_60.avpreset
+++ b/dev/null
@@ -1,17 +0,0 @@
-g=120
-lag-in-frames=25
-deadline=good
-cpu-used=0
-profile=0
-qmax=51
-qmin=11
-slices=4
-b=2M
-
-#ignored unless using -pass 2
-maxrate=24M
-minrate=100k
-auto-alt-ref=1
-arnr-maxframes=7
-arnr-strength=5
-arnr-type=centered
diff --git a/presets/libvpx-720p50_60.ffpreset b/presets/libvpx-720p50_60.ffpreset
new file mode 100644
index 0000000..8fce2bf
--- a/dev/null
+++ b/presets/libvpx-720p50_60.ffpreset
@@ -0,0 +1,19 @@
+vcodec=libvpx
+
+g=120
+lag-in-frames=25
+deadline=good
+cpu-used=0
+vprofile=0
+qmax=51
+qmin=11
+slices=4
+b=2M
+
+#ignored unless using -pass 2
+maxrate=24M
+minrate=100k
+auto-alt-ref=1
+arnr-maxframes=7
+arnr-strength=5
+arnr-type=centered
diff --git a/presets/libx264-baseline.avpreset b/presets/libx264-baseline.avpreset
deleted file mode 100644
index 0626e28..0000000
--- a/presets/libx264-baseline.avpreset
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/dev/null
@@ -1,4 +0,0 @@
-profile=baseline
-level=13
-maxrate=768000
-bufsize=3000000
diff --git a/presets/libx264-ipod320.ffpreset b/presets/libx264-ipod320.ffpreset
new file mode 100644
index 0000000..76722bd
--- a/dev/null
+++ b/presets/libx264-ipod320.ffpreset
@@ -0,0 +1,6 @@
+vcodec=libx264
+
+vprofile=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
+++ b/dev/null
@@ -1,4 +0,0 @@
-profile=baseline
-level=30
-maxrate=10000000
-bufsize=10000000
diff --git a/presets/libx264-ipod640.ffpreset b/presets/libx264-ipod640.ffpreset
new file mode 100644
index 0000000..51f7564
--- a/dev/null
+++ b/presets/libx264-ipod640.ffpreset
@@ -0,0 +1,6 @@
+vcodec=libx264
+
+vprofile=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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/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
+++ b/dev/null
@@ -1,2 +0,0 @@
-preset=veryslow
-fastfirstpass=1
diff --git a/tests/Makefile b/tests/Makefile
index 5eb7ffd..6f128e8 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,6 +1,18 @@
+FFSERVER_REFFILE = $(SRC_PATH)/tests/ffserver.regression.ref
+
VREF = tests/vsynth1/00.pgm
AREF = tests/data/asynth1.sw
+
+$(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
@@ -18,7 +30,16 @@ tests/data/vsynth1.yuv: tests/videogen$(HOSTEXESUF) | tests/data
tests/data/vsynth2.yuv: tests/rotozoom$(HOSTEXESUF) | tests/data
$(M)$< $(SRC_PATH)/tests/lena.pnm $@
-tests/data/asynth% tests/data/vsynth%.yuv tests/vsynth%/00.pgm: TAG = GEN
+tests/data/ffprobe-test.nut: ffmpeg$(EXESUF) | tests/data
+ $(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 $(SRC_PATH)/tests/test.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 $@ 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
@@ -72,11 +93,16 @@ 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
include $(SRC_PATH)/tests/fate/indeo.mak
include $(SRC_PATH)/tests/fate/libavcodec.mak
@@ -84,6 +110,7 @@ include $(SRC_PATH)/tests/fate/libavdevice.mak
include $(SRC_PATH)/tests/fate/libavformat.mak
include $(SRC_PATH)/tests/fate/libavresample.mak
include $(SRC_PATH)/tests/fate/libavutil.mak
+include $(SRC_PATH)/tests/fate/libswresample.mak
include $(SRC_PATH)/tests/fate/lossless-audio.mak
include $(SRC_PATH)/tests/fate/lossless-video.mak
include $(SRC_PATH)/tests/fate/microsoft.mak
@@ -97,6 +124,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
@@ -106,33 +134,45 @@ include $(SRC_PATH)/tests/fate/vqf.mak
include $(SRC_PATH)/tests/fate/wavpack.mak
include $(SRC_PATH)/tests/fate/wma.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)'
@@ -143,7 +183,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
@@ -157,7 +197,7 @@ 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))
diff --git a/tests/audiogen.c b/tests/audiogen.c
index ce6f785..e705061 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
--- a/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 b6c7384..48e9dd0 100755
--- a/tests/fate-run.sh
+++ b/tests/fate-run.sh
@@ -72,37 +72,41 @@ run(){
}
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 -
}
enc_dec_pcm(){
@@ -114,8 +118,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"
@@ -136,20 +140,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" "$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" "$samples"
}
video_filter(){
@@ -158,12 +168,12 @@ 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:
}
pixdesc(){
- pix_fmts="$(avconv -pix_fmts list 2>/dev/null | awk 'NR > 8 && /^IO/ { print $2 }' | sort)"
+ pix_fmts="$(ffmpeg -pix_fmts list 2>/dev/null | awk 'NR > 8 && /^IO/ { print $2 }' | sort)"
for pix_fmt in $pix_fmts; do
test=$pix_fmt
video_filter "format=$pix_fmt,pixdesctest" -pix_fmt $pix_fmt
@@ -172,27 +182,38 @@ pixdesc(){
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)
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
}
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=$?
@@ -226,5 +247,11 @@ 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."
+else
+ echo "Updating reference failed, possibly no output file was generated."
+fi
exit $err
diff --git a/tests/fate-update.sh b/tests/fate-update.sh
new file mode 100755
index 0000000..6b4668f
--- a/dev/null
+++ b/tests/fate-update.sh
@@ -0,0 +1,55 @@
+#! /bin/sh
+
+set -e
+
+base=$(dirname $0)
+ref="${base}/ref/fate"
+
+FATE_DB_URL="http://fate.multimedia.cx/fate-tests.sqlite.bz2"
+FATE_DB=$(mktemp fate-db.XXXXXX)
+SQL_TESTS='SELECT id,short_name,command FROM test_spec WHERE active=1 ORDER BY short_name'
+
+do_sql(){
+ sqlite3 -noheader -separator ' ' "$FATE_DB" "$@"
+}
+
+wget -q -O - "$FATE_DB_URL" | bunzip2 > "$FATE_DB"
+mkdir -p "$ref"
+exec 3>"$base/fate.mak"
+
+do_sql "$SQL_TESTS" | while read id name command; do
+ case "$name" in
+ 00-full-regression|ffmpeg-help|binsize-*) continue ;;
+ esac
+ case "$command" in
+ {MD5}*)
+ command="${command#*ffmpeg}"; command="${command% -}"
+ command="md5 $command"
+ ;;
+ {*}*) continue ;;
+ *-f\ framecrc\ -)
+ command="${command#*ffmpeg}"; command="${command% -f *}"
+ command="framecrc $command"
+ ;;
+ *-f\ framemd5\ -)
+ command="${command#*ffmpeg}"; command="${command% -f *}"
+ command="framemd5 $command"
+ ;;
+ *-f\ crc\ -)
+ command="${command#*ffmpeg}"; command="${command% -f *}"
+ command="crc $command"
+ ;;
+ *)
+ echo "Unhandled command '$command'"
+ exit 1
+ ;;
+ esac
+ command=$(echo "$command" | sed 's/\$SAMPLES_PATH/$(SAMPLES)/g')
+ command=$(echo "$command" | sed 's/ *$//')
+ do_sql "SELECT expected_stdout FROM test_spec WHERE id=$id" | awk '/./{print}' > "$ref/$name"
+ printf "FATE_TESTS += fate-${name}\n" >&3
+ printf "fate-${name}: CMD = %s\n" "$command" >&3
+done
+
+exec 3<&-
+rm -f "$FATE_DB"
diff --git a/tests/fate-valgrind.supp b/tests/fate-valgrind.supp
new file mode 100644
index 0000000..db72c54
--- a/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 6e0c0c6..f371291 100755
--- a/tests/fate.sh
+++ b/tests/fate.sh
@@ -35,16 +35,18 @@ checkout(){
update()(
cd ${src} || return
case "$repo" in
- git:*) git fetch --force; git reset --hard origin/master ;;
+ git:*) git fetch --force && git reset --hard FETCH_HEAD ;;
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"} \
diff --git a/tests/fate/aac.mak b/tests/fate/aac.mak
index c49106b..b85a8e8 100644
--- a/tests/fate/aac.mak
+++ b/tests/fate/aac.mak
@@ -73,6 +73,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 $(REF) -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
@@ -90,7 +107,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..f386499 100644
--- a/tests/fate/ac3.mak
+++ b/tests/fate/ac3.mak
@@ -53,6 +53,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 +66,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 0eb6227..78508bc 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 -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
@@ -58,10 +72,48 @@ 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 55f2556..6b1dd3c 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 a0e0caf..6b5d1a9 100644
--- a/tests/fate/audio.mak
+++ b/tests/fate/audio.mak
@@ -10,35 +10,55 @@ 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, 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, VMD, VMDAUDIO) += fate-sierra-vmd-audio
+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 = -244
+fate-nellymoser-aref-encode: CMP_TARGET = 9612
+fate-nellymoser-aref-encode: SIZE_TOLERANCE = 268
+
+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_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, SMUSH, VIMA) += fate-vima
+fate-vima: CMD = framecrc -i $(TARGET_SAMPLES)/smush/ronin_part.znm -vn
+
+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 7ef68ad..5f9c8c1 100644
--- a/tests/fate/avformat.mak
+++ b/tests/fate/avformat.mak
@@ -1,19 +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
@@ -31,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
@@ -40,14 +45,28 @@ 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 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..743274d 100644
--- a/tests/fate/demux.mak
+++ b/tests/fate/demux.mak
@@ -1,71 +1,108 @@
-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_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-$(CONFIG_MATROSKA_DEMUXER) += fate-mkv
+fate-mkv: CMD = framecrc -i $(TARGET_SAMPLES)/mkv/test7_cut.mkv -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_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..e456bbd
--- a/dev/null
+++ b/tests/fate/exif.mak
@@ -0,0 +1,14 @@
+# 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 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..21cdd5f
--- a/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_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 tests/data/vsynth2.yuv \
+ -ss 132 -i $(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 $(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 $(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
--- a/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 20d5638..1f3a262 100644
--- a/tests/fate/fft.mak
+++ b/tests/fate/fft.mak
@@ -38,5 +38,22 @@ $(FATE_FFT_FIXED): libavcodec/fft-fixed-test$(EXESUF)
$(FATE_FFT_FIXED): CMD = run libavcodec/fft-fixed-test $(CPUFLAGS:%=-c%) $(ARGS)
$(FATE_FFT_FIXED): REF = /dev/null
-FATE-$(call ALLYES, AVCODEC FFT) += $(FATE_FFT) $(FATE_FFT_FIXED)
-fate-fft: $(FATE_FFT) $(FATE_FFT_FIXED)
+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) $(FATE_FFT_FIXED) $(FATE_FFT_FIXED32)
+fate-fft: $(FATE_FFT) $(FATE_FFT_FIXED) $(FATE_FFT_FIXED32)
diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak
index 9bf148c..84c4b0d 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 = $(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: SRC = $(TARGET_PATH)/tests/data/asynth-44100-6.wav
fate-filter-channelmap: tests/data/asynth-44100-6.wav
fate-filter-channelmap: CMD = md5 -i $(SRC) -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/channelmap -f wav -flags +bitexact
fate-filter-channelmap: CMP = oneline
-fate-filter-channelmap: REF = 21f1977c4f9705e2057083f84764e685
+fate-filter-channelmap: REF = 06168d06085e2c0603e4e118ba4cade2
FATE_AFILTER-$(call FILTERDEMDECENCMUX, CHANNELSPLIT, WAV, PCM_S16LE, PCM_S16LE, PCM_S16LE) += fate-filter-channelsplit
fate-filter-channelsplit: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav
@@ -62,12 +73,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 573121d..963bbd7 100644
--- a/tests/fate/filter-video.mak
+++ b/tests/fate/filter-video.mak
@@ -1,25 +1,45 @@
-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_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_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: CMD = framecrc -f lavfi -graph_file $(SRC_PATH)/tests/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
@@ -33,17 +53,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: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_complex_script $(SRC_PATH)/tests/filtergraphs/overlay_rgb
+
+FATE_FILTER_VSYNTH-$(call ALLYES, SPLIT_FILTER SCALE_FILTER PAD_FILTER OVERLAY_FILTER) += fate-filter-overlay_yuv420
+fate-filter-overlay_yuv420: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_complex_script $(SRC_PATH)/tests/filtergraphs/overlay_yuv420
+
+FATE_FILTER_VSYNTH-$(call ALLYES, SPLIT_FILTER SCALE_FILTER PAD_FILTER OVERLAY_FILTER) += fate-filter-overlay_yuv444
+fate-filter-overlay_yuv444: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_complex_script $(SRC_PATH)/tests/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-$(call ALLYES, SETPTS_FILTER SETTB_FILTER) += fate-filter-setpts
fate-filter-setpts: tests/data/filtergraphs/setpts
fate-filter-setpts: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_script $(TARGET_PATH)/tests/data/filtergraphs/setpts
+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
@@ -62,8 +106,25 @@ 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: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/smjpeg/scenwin.mjpg -filter_complex_script $(SRC_PATH)/tests/filtergraphs/hqdn3d -an
+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: CMD = framecrc -i $(TARGET_SAMPLES)/vmd/12.vmd -filter_script $(SRC_PATH)/tests/filtergraphs/gradfun -an -frames:v 20
+
+FATE_FILTER-$(call ALLYES, TESTSRC_FILTER SINE_FILTER CONCAT_FILTER) += fate-filter-concat
+fate-filter-concat: CMD = framecrc -filter_complex_script $(SRC_PATH)/tests/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: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_complex_script $(SRC_PATH)/tests/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: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_complex_script $(SRC_PATH)/tests/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"
@@ -89,47 +150,181 @@ 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, 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-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"
+
FATE_FILTER_VSYNTH-$(CONFIG_FORMAT_FILTER) += fate-filter-pixdesc
fate-filter-pixdesc: CMD = pixdesc
-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-$(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-$(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 = $(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 = $(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 = $(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..feda240
--- a/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 = $(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 13bbd11..55270d0 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 \
@@ -190,179 +201,190 @@ FATE_H264-$(call ALLYES, MOV_DEMUXER H264_MP4TOANNEXB_BSF) += fate-h264-bsf-mp4t
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
new file mode 100644
index 0000000..e15497d
--- a/dev/null
+++ b/tests/fate/hevc.mak
@@ -0,0 +1,156 @@
+HEVC_SAMPLES = \
+ AMP_A_Samsung_4 \
+ AMP_B_Samsung_4 \
+ AMVP_C_Samsung_4 \
+ AMP_D_Hisilicon \
+ AMP_E_Hisilicon \
+ AMP_F_Hisilicon_3 \
+ AMVP_A_MTK_4 \
+ AMVP_B_MTK_4 \
+ CAINIT_A_SHARP_4 \
+ CAINIT_B_SHARP_4 \
+ CAINIT_C_SHARP_3 \
+ CAINIT_D_SHARP_3 \
+ CAINIT_E_SHARP_3 \
+ CAINIT_F_SHARP_3 \
+ CAINIT_G_SHARP_3 \
+ CAINIT_H_SHARP_3 \
+ CIP_A_Panasonic_3 \
+ cip_B_NEC_2 \
+ CIP_C_Panasonic_2 \
+ 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_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 \
+ EXT_A_ericsson_3 \
+ ipcm_A_NEC_2 \
+ ipcm_B_NEC_2 \
+ ipcm_C_NEC_2 \
+ ipcm_D_NEC_2 \
+ IPRED_A_docomo_2 \
+ IPRED_B_Nokia_3 \
+ IPRED_C_Mitsubishi_2 \
+ LS_A_Orange_2 \
+ LS_B_ORANGE_3 \
+ MAXBINS_A_TI_4 \
+ MAXBINS_B_TI_4 \
+ MAXBINS_C_TI_4 \
+ MERGE_A_TI_3 \
+ MERGE_B_TI_3 \
+ MERGE_C_TI_3 \
+ MERGE_D_TI_3 \
+ MERGE_E_TI_3 \
+ MERGE_F_MTK_4 \
+ MERGE_G_HHI_4 \
+ MVCLIP_A_qualcomm_3 \
+ MVDL1ZERO_A_docomo_3 \
+ MVEDGE_A_qualcomm_3 \
+ NUT_A_ericsson_4 \
+ PICSIZE_A_Bossen_1 \
+ PICSIZE_B_Bossen_1 \
+ PICSIZE_C_Bossen_1 \
+ PICSIZE_D_Bossen_1 \
+ PMERGE_A_TI_3 \
+ PMERGE_B_TI_3 \
+ PMERGE_C_TI_3 \
+ PMERGE_D_TI_3 \
+ 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_B_Bossen_1 \
+ RPLM_A_qualcomm_4 \
+ RPLM_B_qualcomm_4 \
+ RPS_A_docomo_4 \
+ RPS_B_qualcomm_5 \
+ RPS_C_ericsson_4 \
+ RPS_D_ericsson_5 \
+ RPS_E_qualcomm_5 \
+ RQT_A_HHI_4 \
+ RQT_B_HHI_4 \
+ RQT_C_HHI_4 \
+ RQT_D_HHI_4 \
+ RQT_E_HHI_4 \
+ RQT_F_HHI_4 \
+ RQT_G_HHI_4 \
+ SAO_A_MediaTek_4 \
+ SAO_B_MediaTek_5 \
+ SAO_C_Samsung_4 \
+ SAO_D_Samsung_4 \
+ SAO_E_Canon_4 \
+ SAO_F_Canon_3 \
+ SAO_G_Canon_3 \
+ SDH_A_Orange_3 \
+ SLICES_A_Rovi_3 \
+ SLIST_A_Sony_4 \
+ SLIST_B_Sony_8 \
+ SLIST_C_Sony_3 \
+ SLIST_D_Sony_9 \
+ STRUCT_A_Samsung_5 \
+ STRUCT_B_Samsung_4 \
+ TILES_A_Cisco_2 \
+ TILES_B_Cisco_1 \
+ TMVP_A_MS_2 \
+ TSCL_A_VIDYO_5 \
+ TSCL_B_VIDYO_4 \
+ TSKIP_A_MS_2 \
+ WP_A_Toshiba_3 \
+ WP_B_Toshiba_3 \
+ WPP_A_ericsson_MAIN_2 \
+ WPP_B_ericsson_MAIN_2 \
+ WPP_C_ericsson_MAIN_2 \
+ WPP_D_ericsson_MAIN_2 \
+ WPP_E_ericsson_MAIN_2 \
+ WPP_F_ericsson_MAIN_2 \
+
+HEVC_SAMPLES_10BIT = \
+ DBLK_A_MAIN10_VIXS_2 \
+ WP_A_MAIN10_Toshiba_3 \
+ WP_MAIN10_B_Toshiba_3 \
+ WPP_A_ericsson_MAIN10_2 \
+ WPP_B_ericsson_MAIN10_2 \
+ WPP_C_ericsson_MAIN10_2 \
+ WPP_D_ericsson_MAIN10_2 \
+ WPP_E_ericsson_MAIN10_2 \
+ WPP_F_ericsson_MAIN10_2 \
+
+# 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)
+
+define FATE_HEVC_TEST
+FATE_HEVC += fate-hevc-conformance-$(1)
+fate-hevc-conformance-$(1): CMD = framecrc -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 drop -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit -pix_fmt yuv420p10le
+endef
+
+$(foreach N,$(HEVC_SAMPLES),$(eval $(call FATE_HEVC_TEST,$(N))))
+$(foreach N,$(HEVC_SAMPLES_10BIT),$(eval $(call FATE_HEVC_TEST_10BIT,$(N))))
+
+FATE_HEVC-$(call DEMDEC, HEVC, HEVC) += $(FATE_HEVC)
+
+FATE_SAMPLES_AVCONV += $(FATE_HEVC-yes)
+
+fate-hevc: $(FATE_HEVC-yes)
diff --git a/tests/fate/image.mak b/tests/fate/image.mak
index f7cc325..926d637 100644
--- a/tests/fate/image.mak
+++ b/tests/fate/image.mak
@@ -1,10 +1,30 @@
-FATE_SAMPLES_AVCONV-$(call DEMDEC, IMAGE2, DPX) += fate-dpx
+FATE_IMAGE-$(call DEMDEC, IMAGE2, DPX) += fate-dpx
fate-dpx: CMD = framecrc -i $(TARGET_SAMPLES)/dpx/lighthouse_rgb48.dpx
-FATE_SAMPLES_AVCONV-$(call DEMDEC, IMAGE2, PICTOR) += fate-pictor
+FATE_EXR += fate-exr-slice-raw
+fate-exr-slice-raw: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_slice_raw.exr -pix_fmt rgba64le
+
+FATE_EXR += fate-exr-slice-rle
+fate-exr-slice-rle: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_slice_rle.exr -pix_fmt rgba64le
+
+FATE_EXR += fate-exr-slice-zip1
+fate-exr-slice-zip1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_slice_zip1.exr -pix_fmt rgba64le
+
+FATE_EXR += fate-exr-slice-zip16
+fate-exr-slice-zip16: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_slice_zip16.exr -pix_fmt rgba64le
+
+FATE_EXR += fate-exr-slice-pxr24
+fate-exr-slice-pxr24: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_slice_pxr24.exr -pix_fmt rgb48le
+
+FATE_EXR-$(call DEMDEC, IMAGE2, EXR) += $(FATE_EXR)
+
+FATE_IMAGE += $(FATE_EXR-yes)
+fate-exr: $(FATE_EXR-yes)
+
+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 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_SUNRASTER += fate-sunraster-1bit-raw
@@ -30,7 +50,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 \
@@ -49,7 +69,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
@@ -73,5 +93,13 @@ 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_IMAGE += $(FATE_IMAGE-yes)
+
+FATE_SAMPLES_FFMPEG += $(FATE_IMAGE)
+fate-image: $(FATE_IMAGE)
diff --git a/tests/fate/libavcodec.mak b/tests/fate/libavcodec.mak
index 6e81f57..b5fa4f0 100644
--- a/tests/fate/libavcodec.mak
+++ b/tests/fate/libavcodec.mak
@@ -3,7 +3,7 @@ fate-golomb: libavcodec/golomb-test$(EXESUF)
fate-golomb: CMD = run libavcodec/golomb-test
fate-golomb: REF = /dev/null
-FATE_LIBAVCODEC-yes += fate-idct8x8
+FATE_LIBAVCODEC-$(CONFIG_DCT) += fate-idct8x8
fate-idct8x8: libavcodec/dct-test$(EXESUF)
fate-idct8x8: CMD = run libavcodec/dct-test -i
fate-idct8x8: CMP = null
diff --git a/tests/fate/libavresample.mak b/tests/fate/libavresample.mak
index 6ae2ddc..d7c856b 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
@@ -20,14 +20,14 @@ $(call CROSS_TEST,$(MIX_CHANNELS),MIX,flt,fltp)
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
@@ -41,7 +41,7 @@ $(call CROSS_TEST,$(SAMPLERATES),RESAMPLE,dblp,f64le,f64)
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 6f24496..eeece47 100644
--- a/tests/fate/libavutil.mak
+++ b/tests/fate/libavutil.mak
@@ -25,6 +25,10 @@ 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-crc
fate-crc: libavutil/crc-test$(EXESUF)
fate-crc: CMD = run libavutil/crc-test
@@ -50,14 +54,30 @@ 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 += 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
diff --git a/tests/fate/libswresample.mak b/tests/fate/libswresample.mak
new file mode 100644
index 0000000..dd47de9
--- a/dev/null
+++ b/tests/fate/libswresample.mak
@@ -0,0 +1,276 @@
+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
+
+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
+
+#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
+endef
+
+
+$(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)
+
+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 b8298ea..41954c0 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_MSVIDEO1 += fate-msvideo1-8bit
@@ -7,7 +7,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
@@ -17,7 +17,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
@@ -38,5 +42,10 @@ fate-vc1_sa20021: CMD = framecrc -i $(TARGET_SAMPLES)/vc1/SA20021.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/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 8481f28..82d7e3a 100644
--- a/tests/fate/real.mak
+++ b/tests/fate/real.mak
@@ -1,22 +1,22 @@
-FATE_SAMPLES_AVCONV-$(call DEMDEC, RM, RA_144) += fate-ra-144
+FATE_REAL-$(call DEMDEC, RM, RA_144) += fate-ra-144
fate-ra-144: CMD = md5 -i $(TARGET_SAMPLES)/real/ra3_in_rm_file.rm -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, RM, RA_288) += fate-ra-288
+FATE_REAL-$(call DEMDEC, RM, RA_288) += fate-ra-288
fate-ra-288: CMD = pcm -i $(TARGET_SAMPLES)/real/ra_288.rm
fate-ra-288: CMP = oneoff
fate-ra-288: REF = $(SAMPLES)/real/ra_288.pcm
fate-ra-288: FUZZ = 2
-FATE_SAMPLES_AVCONV-$(call DEMDEC, RM, COOK) += fate-ra-cook
+FATE_REAL-$(call DEMDEC, RM, COOK) += fate-ra-cook
fate-ra-cook: CMD = pcm -i $(TARGET_SAMPLES)/real/ra_cook.rm
fate-ra-cook: CMP = oneoff
fate-ra-cook: REF = $(SAMPLES)/real/ra_cook.pcm
-FATE_SAMPLES_AVCONV-$(call DEMDEC, RM, RV30) += fate-rv30
+FATE_REAL-$(call DEMDEC, RM, RV30) += fate-rv30
fate-rv30: CMD = framecrc -flags +bitexact -idct simple -i $(TARGET_SAMPLES)/real/rv30.rm -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, RM, RV40) += fate-rv40
-fate-rv40: CMD = framecrc -i $(TARGET_SAMPLES)/real/spygames-2MB.rmvb -t 10 -an -vsync 0
+FATE_REAL-$(call DEMDEC, RM, RV40) += fate-rv40
+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
@@ -36,5 +36,8 @@ fate-sipr-16k: REF = $(SAMPLES)/sipr/sipr_16k.pcm
$(FATE_SIPR): CMP = oneoff
-FATE_SAMPLES_AVCONV-$(call DEMDEC, RM, SIPR) += $(FATE_SIPR)
+FATE_REAL-$(call DEMDEC, RM, SIPR) += $(FATE_SIPR)
fate-sipr: $(FATE_SIPR)
+
+FATE_SAMPLES_FFMPEG += $(FATE_REAL-yes)
+fate-real: $(FATE_REAL-yes)
diff --git a/tests/fate/screen.mak b/tests/fate/screen.mak
index 5c30ed7..12250ca 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_FRAPS += fate-fraps-v0
@@ -23,7 +23,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
@@ -32,7 +32,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
@@ -44,7 +44,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
@@ -59,5 +59,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 a423711..fe8d3ab 100644
--- a/tests/fate/seek.mak
+++ b/tests/fate/seek.mak
@@ -89,6 +89,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
@@ -135,6 +137,8 @@ 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
@@ -179,6 +183,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
@@ -216,6 +221,7 @@ 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-%)
diff --git a/tests/fate/subtitles.mak b/tests/fate/subtitles.mak
new file mode 100644
index 0000000..33d798e
--- a/dev/null
+++ b/tests/fate/subtitles.mak
@@ -0,0 +1,62 @@
+FATE_SUBTITLES_ASS-$(call ALLYES, AQTITLE_DEMUXER TEXT_DECODER ICONV) += fate-sub-aqtitle
+fate-sub-aqtitle: CMD = md5 -sub_charenc windows-1250 -i $(TARGET_SAMPLES)/sub/AQTitle_capability_tester.aqt -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, JACOSUB, JACOSUB) += fate-sub-jacosub
+fate-sub-jacosub: CMD = md5 -i $(TARGET_SAMPLES)/sub/JACOsub_capability_tester.jss -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, MICRODVD, MICRODVD) += fate-sub-microdvd
+fate-sub-microdvd: CMD = md5 -i $(TARGET_SAMPLES)/sub/MicroDVD_capability_tester.sub -f ass
+
+FATE_SUBTITLES-$(call ALLYES, MICRODVD_DEMUXER MICRODVD_MUXER) += fate-sub-microdvd-remux
+fate-sub-microdvd-remux: CMD = md5 -i $(TARGET_SAMPLES)/sub/MicroDVD_capability_tester.sub -c:s copy -f microdvd
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, MOV, MOVTEXT) += fate-sub-movtext
+fate-sub-movtext: CMD = md5 -i $(TARGET_SAMPLES)/sub/MovText_capability_tester.mp4 -f ass
+
+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 = md5 -i $(TARGET_SAMPLES)/sub/MPL2_capability_tester.txt -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, MPSUB, TEXT) += fate-sub-mpsub
+fate-sub-mpsub: CMD = md5 -i $(TARGET_SAMPLES)/sub/MPSub_capability_tester.sub -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, MPSUB, TEXT) += fate-sub-mpsub-frames
+fate-sub-mpsub-frames: CMD = md5 -i $(TARGET_SAMPLES)/sub/MPSub_capability_tester_frames.sub -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, PJS, PJS) += fate-sub-pjs
+fate-sub-pjs: CMD = md5 -i $(TARGET_SAMPLES)/sub/PJS_capability_tester.pjs -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, REALTEXT, REALTEXT) += fate-sub-realtext
+fate-sub-realtext: CMD = md5 -i $(TARGET_SAMPLES)/sub/RealText_capability_tester.rt -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, SAMI, SAMI) += fate-sub-sami
+fate-sub-sami: CMD = md5 -i $(TARGET_SAMPLES)/sub/SAMI_capability_tester.smi -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, SRT, SUBRIP) += fate-sub-srt
+fate-sub-srt: CMD = md5 -i $(TARGET_SAMPLES)/sub/SubRip_capability_tester.srt -f ass
+
+FATE_SUBTITLES-$(call ALLYES, MOV_DEMUXER MOVTEXT_DECODER SUBRIP_ENCODER) += fate-sub-subripenc
+fate-sub-subripenc: CMD = md5 -i $(TARGET_SAMPLES)/sub/MovText_capability_tester.mp4 -scodec subrip -f srt
+
+FATE_SUBTITLES_ASS-$(call ALLYES, SUBVIEWER1_DEMUXER SUBVIEWER1_DECODER ICONV) += fate-sub-subviewer1
+fate-sub-subviewer1: CMD = md5 -sub_charenc windows-1250 -i $(TARGET_SAMPLES)/sub/SubViewer1_capability_tester.sub -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, SUBVIEWER, SUBVIEWER) += fate-sub-subviewer
+fate-sub-subviewer: CMD = md5 -i $(TARGET_SAMPLES)/sub/SubViewer_capability_tester.sub -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, VPLAYER, VPLAYER) += fate-sub-vplayer
+fate-sub-vplayer: CMD = md5 -i $(TARGET_SAMPLES)/sub/VPlayer_capability_tester.txt -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, WEBVTT, WEBVTT) += fate-sub-webvtt
+fate-sub-webvtt: CMD = md5 -i $(TARGET_SAMPLES)/sub/WebVTT_capability_tester.vtt -f ass
+
+FATE_SUBTITLES_ASS-$(call ALLYES, MICRODVD_DEMUXER MICRODVD_DECODER ICONV) += fate-sub-charenc
+fate-sub-charenc: CMD = md5 -sub_charenc cp1251 -i $(TARGET_SAMPLES)/sub/cp1251-subtitles.sub -f ass
+
+FATE_SUBTITLES-$(call ENCMUX, ASS, ASS) += $(FATE_SUBTITLES_ASS-yes)
+FATE_SUBTITLES += $(FATE_SUBTITLES-yes)
+
+FATE_SAMPLES_FFMPEG += $(FATE_SUBTITLES)
+fate-subtitles: $(FATE_SUBTITLES)
diff --git a/tests/fate/utvideo.mak b/tests/fate/utvideo.mak
index 161674f..6ec206b 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 -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 -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..3186c4c 100644
--- a/tests/fate/vcodec.mak
+++ b/tests/fate/vcodec.mak
@@ -2,10 +2,12 @@ fate-vsynth1-%: SRC = tests/data/vsynth1.yuv
fate-vsynth2-%: SRC = tests/data/vsynth2.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-vsynth%: CMP_UNIT = 1
fate-vsynth%: REF = $(SRC_PATH)/tests/ref/vsynth/$(@:fate-%=%)
+FATE_VCODEC-$(call ENCDEC, AMV, AVI) += amv
+
FATE_VCODEC-$(call ENCDEC, ASV1, AVI) += asv1
fate-vsynth%-asv1: ENCOPTS = -qscale 10
@@ -19,20 +21,20 @@ FATE_VCODEC-$(call ENCDEC, DNXHD, DNXHD) += dnxhd-720p \
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,8 +54,9 @@ 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
@@ -62,6 +65,11 @@ 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
@@ -82,11 +90,19 @@ 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
@@ -184,13 +200,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 +225,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 +236,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 = -strict -2 -qscale 2 -flags +qpel \
+ -me_method iter -dia_size 2 \
+ -cmp 12 -subcmp 12 -s 128x64
+
+fate-vsynth%-snow-hpel: ENCOPTS = -strict -2 -qscale 2 \
+ -me_method iter -dia_size 2 \
+ -cmp 12 -subcmp 12 -s 128x64
+
+fate-vsynth%-snow-ll: ENCOPTS = -strict -2 -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,6 +276,12 @@ 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-%)
diff --git a/tests/fate/video.mak b/tests/fate/video.mak
index 137b05f..c5527ce 100644
--- a/tests/fate/video.mak
+++ b/tests/fate/video.mak
@@ -4,37 +4,40 @@ 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, 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 +49,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 +78,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 +114,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,16 +129,16 @@ 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_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 -sws_flags +bitexact -vf pad=512:512:80:112 -f roq -t 0.2
FATE_IFF-$(CONFIG_IFF_BYTERUN1_DECODER) += fate-iff-byterun1
@@ -145,42 +150,48 @@ 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, AVI, KGV1) += fate-kgv1
+FATE_VIDEO-$(call DEMDEC, JV, JV) += fate-jv
+fate-jv: CMD = framecrc -i $(TARGET_SAMPLES)/jv/intro.jv -pix_fmt rgb24 -an
+
+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 -flags +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_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
@@ -188,43 +199,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, AVI, QPEG) += fate-qpeg
+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_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, VMD, VMDVIDEO) += fate-sierra-vmd-video
+FATE_VIDEO-$(call DEMDEC, SMUSH, SANM) += fate-sanm
+fate-sanm: CMD = framecrc -i $(TARGET_SAMPLES)/smush/ronin_part.znm -an -pix_fmt rgb24
+
+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
@@ -233,42 +247,50 @@ 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 -flags +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, 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 8ea726b..8398903 100644
--- a/tests/fate/vpx.mak
+++ b/tests/fate/vpx.mak
@@ -19,9 +19,15 @@ 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_SAMPLES_AVCONV += $(FATE_VP6-yes)
fate-vp6: $(FATE_VP6-yes)
@@ -37,18 +43,47 @@ 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)
-$(call FATE_VP8_FULL,-emu-edge,-flags +emu_edge)
-
+$(eval $(call FATE_VP8_FULL))
+$(eval $(call FATE_VP8_FULL,-emu-edge,-flags +emu_edge))
FATE_SAMPLES_AVCONV-$(CONFIG_VP8_DECODER) += $(FATE_VP8-yes)
fate-vp8: $(FATE_VP8-yes)
+
+define FATE_VP9_SUITE
+FATE_VP9-$(CONFIG_MATROSKA_DEMUXER) += fate-vp9$(2)-$(1)
+fate-vp9$(2)-$(1): CMD = framemd5 $(3) -i $(TARGET_SAMPLES)/vp9-test-vectors/vp90-2-$(1).webm
+fate-vp9$(2)-$(1): REF = $(SRC_PATH)/tests/ref/fate/vp9-$(1)
+endef
+
+VP9_Q = 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 \
+ 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 \
+ 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 \
+ 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
+VP9_SHARP = 1 2 3 4 5 6 7
+VP9_SIZE_A = 08 10 16 18 32 34 64 66
+VP9_SIZE_B = 196 198 200 202 208 210 224 226
+
+define FATE_VP9_FULL
+$(foreach Q,$(VP9_Q),$(eval $(call FATE_VP9_SUITE,00-quantizer-$(Q),$(1),$(2))))
+$(foreach SHARP,$(VP9_SHARP),$(eval $(call FATE_VP9_SUITE,01-sharpness-$(SHARP),$(1),$(2))))
+$(foreach W,$(VP9_SIZE_A),$(eval $(foreach H,$(VP9_SIZE_A),$(eval $(call FATE_VP9_SUITE,02-size-$(W)x$(H),$(1),$(2))))))
+$(foreach W,$(VP9_SIZE_B),$(eval $(foreach H,$(VP9_SIZE_B),$(eval $(call FATE_VP9_SUITE,03-size-$(W)x$(H),$(1),$(2))))))
+$(eval $(call FATE_VP9_SUITE,03-deltaq,$(1),$(2)))
+$(eval $(call FATE_VP9_SUITE,2pass-akiyo,$(1),$(2)))
+$(eval $(call FATE_VP9_SUITE,segmentation-akiyo,$(1),$(2)))
+$(eval $(call FATE_VP9_SUITE,tiling-pedestrian,$(1),$(2)))
+endef
+
+$(eval $(call FATE_VP9_FULL))
+$(eval $(call FATE_VP9_FULL,-emu-edge,-flags +emu_edge))
+FATE_SAMPLES_AVCONV-$(CONFIG_VP9_DECODER) += $(FATE_VP9-yes)
+fate-vp9: $(FATE_VP9-yes)
diff --git a/tests/fate/vqf.mak b/tests/fate/vqf.mak
index 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 912c64a..98e0998 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 -flags +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 -flags +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
--- a/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..1e6994a
--- a/dev/null
+++ b/tests/ffserver.conf
@@ -0,0 +1,307 @@
+#
+# 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.
+
+Port 9999
+RTSPPort 9990
+
+# Address on which the server is bound. Only useful if you have
+# several network interfaces.
+
+BindAddress 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 pgmyuv -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
+
+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
+
+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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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_yuv444 b/tests/filtergraphs/overlay_yuv444
new file mode 100644
index 0000000..bda0fd6
--- a/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
--- a/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 d9c8a8f..a4b2ad5 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="${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"
+do_lavf avi "" "-acodec mp2 -ab 64k"
fi
if [ -n "$do_asf" ] ; then
-do_lavf asf "" "-acodec mp2" "-r 25"
+do_lavf asf "" "-acodec mp2 -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
+do_lavf_timecode mpg "-ab 64k"
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,7 +91,7 @@ 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"
+do_lavf ts "" "-ab 64k -mpegts_transport_stream_id 42"
fi
if [ -n "$do_swf" ] ; then
@@ -82,28 +102,62 @@ if [ -n "$do_ffm" ] ; then
do_lavf ffm
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"
+do_lavf nut "" "-acodec mp2 -ab 64k"
fi
if [ -n "$do_mkv" ] ; then
-do_lavf mkv "" "-c:a mp2 -c:v mpeg4"
+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"
+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
@@ -149,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
@@ -168,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
@@ -218,7 +295,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
@@ -233,10 +310,30 @@ if [ -n "$do_rso" ] ; then
do_audio_only rso
fi
+if [ -n "$do_smjpeg" ] ; then
+do_lavf smjpeg "" "-f smjpeg"
+fi
+
if [ -n "$do_sox" ] ; then
do_audio_only sox
fi
+if [ -n "$do_caf" ] ; then
+do_audio_only caf
+fi
+
+if [ -n "$do_ast" ] ; then
+do_audio_only ast "-ac 2" "-loopstart 1 -loopend 10"
+fi
+
+if [ -n "$do_ircam" ] ; then
+do_audio_only ircam
+fi
+
+if [ -n "$do_w64" ] ; then
+do_audio_only w64
+fi
+
# pix_fmt conversions
if [ -n "$do_pixfmt" ] ; then
diff --git a/tests/md5.sh b/tests/md5.sh
index 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-ima_qt b/tests/ref/acodec/adpcm-ima_qt
index 8001527..ace5325 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
stddev: 904.76 PSNR: 37.20 MAXDIFF:34029 bytes: 1058400/ 1058560
diff --git a/tests/ref/acodec/adpcm_ima_qt b/tests/ref/acodec/adpcm_ima_qt
new file mode 100644
index 0000000..a50c30a
--- a/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..2739b01 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
+8d9fb9f5433962e7880b666e6e2e428e *tests/data/fate/acodec-alac.mov
+389018 tests/data/fate/acodec-alac.mov
64151e4bcc2b717aa5a8454d424d6a1f *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..1cc3770 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
+151eef9097f944726968bec48649f00a *tests/data/fate/acodec-flac.flac
+361582 tests/data/fate/acodec-flac.flac
64151e4bcc2b717aa5a8454d424d6a1f *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..9f88a76
--- a/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
+d70776846d77c652bceed281fcca9cc8 *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/pcm-f32be b/tests/ref/acodec/pcm-f32be
index 5b0f498..5bd700c 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
+e74eb6b65cb397ce541bac120b00680a *tests/data/fate/acodec-pcm-f32be.au
+2116832 tests/data/fate/acodec-pcm-f32be.au
64151e4bcc2b717aa5a8454d424d6a1f *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-f64be b/tests/ref/acodec/pcm-f64be
index dd882d3..fd0cff6 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
+8c8ba9d2c68384c5f077306e220f1188 *tests/data/fate/acodec-pcm-f64be.au
+4233632 tests/data/fate/acodec-pcm-f64be.au
64151e4bcc2b717aa5a8454d424d6a1f *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-s16be b/tests/ref/acodec/pcm-s16be
index 61e5664..de7c5c7 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
+d2515f35266ae6dba525c700bb76d893 *tests/data/fate/acodec-pcm-s16be.mov
+1059069 tests/data/fate/acodec-pcm-s16be.mov
64151e4bcc2b717aa5a8454d424d6a1f *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..8116480
--- a/dev/null
+++ b/tests/ref/acodec/pcm-s16be_planar
@@ -0,0 +1,4 @@
+cd87e6fc3bddb85c945c050d8c3fba11 *tests/data/fate/acodec-pcm-s16be_planar.nut
+1060673 tests/data/fate/acodec-pcm-s16be_planar.nut
+64151e4bcc2b717aa5a8454d424d6a1f *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_planar b/tests/ref/acodec/pcm-s16le_planar
new file mode 100644
index 0000000..c933001
--- a/dev/null
+++ b/tests/ref/acodec/pcm-s16le_planar
@@ -0,0 +1,4 @@
+74af9a0ae4f68451102a2f7524b2d55f *tests/data/fate/acodec-pcm-s16le_planar.nut
+1060673 tests/data/fate/acodec-pcm-s16le_planar.nut
+64151e4bcc2b717aa5a8454d424d6a1f *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..70271d2 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
+0f4a37a77619124f486f656f03c53d33 *tests/data/fate/acodec-pcm-s24be.mov
+1588323 tests/data/fate/acodec-pcm-s24be.mov
64151e4bcc2b717aa5a8454d424d6a1f *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_planar b/tests/ref/acodec/pcm-s24le_planar
new file mode 100644
index 0000000..14d4cec
--- a/dev/null
+++ b/tests/ref/acodec/pcm-s24le_planar
@@ -0,0 +1,4 @@
+83e315ce8083a6d035f801bb862942bf *tests/data/fate/acodec-pcm-s24le_planar.nut
+1590202 tests/data/fate/acodec-pcm-s24le_planar.nut
+64151e4bcc2b717aa5a8454d424d6a1f *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..03f14c1 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
+d6380bf54ac3e452c190ce302c264bf0 *tests/data/fate/acodec-pcm-s32be.mov
+2117527 tests/data/fate/acodec-pcm-s32be.mov
64151e4bcc2b717aa5a8454d424d6a1f *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_planar b/tests/ref/acodec/pcm-s32le_planar
new file mode 100644
index 0000000..7648766
--- a/dev/null
+++ b/tests/ref/acodec/pcm-s32le_planar
@@ -0,0 +1,4 @@
+f6199b2c698bd5dd1438b53431357bec *tests/data/fate/acodec-pcm-s32le_planar.nut
+2120148 tests/data/fate/acodec-pcm-s32le_planar.nut
+64151e4bcc2b717aa5a8454d424d6a1f *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..a5a459a 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
+00a9d90e06e8ecb79e5dd4c6c8460836 *tests/data/fate/acodec-pcm-s8.mov
+529853 tests/data/fate/acodec-pcm-s8.mov
651d4eb8d98dfcdda96ae6c43d8f156b *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..6ab6ee0
--- a/dev/null
+++ b/tests/ref/acodec/pcm-s8_planar
@@ -0,0 +1,4 @@
+ce99d95295ade9945849ef7c1de8c4ca *tests/data/fate/acodec-pcm-s8_planar.nut
+531054 tests/data/fate/acodec-pcm-s8_planar.nut
+651d4eb8d98dfcdda96ae6c43d8f156b *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..0214975
--- a/dev/null
+++ b/tests/ref/acodec/pcm-u16be
@@ -0,0 +1,4 @@
+eab6206a2cec3c5a3be47fdaa826faff *tests/data/fate/acodec-pcm-u16be.nut
+1060673 tests/data/fate/acodec-pcm-u16be.nut
+64151e4bcc2b717aa5a8454d424d6a1f *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..e45fe08
--- a/dev/null
+++ b/tests/ref/acodec/pcm-u16le
@@ -0,0 +1,4 @@
+8fceb284cc6a5a114b6ce7a10fd08020 *tests/data/fate/acodec-pcm-u16le.nut
+1060673 tests/data/fate/acodec-pcm-u16le.nut
+64151e4bcc2b717aa5a8454d424d6a1f *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..ddab6e8
--- a/dev/null
+++ b/tests/ref/acodec/pcm-u24be
@@ -0,0 +1,4 @@
+d1a55f46c88ed1efa77d05b60259675d *tests/data/fate/acodec-pcm-u24be.nut
+1590202 tests/data/fate/acodec-pcm-u24be.nut
+64151e4bcc2b717aa5a8454d424d6a1f *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..df06ca4
--- a/dev/null
+++ b/tests/ref/acodec/pcm-u24le
@@ -0,0 +1,4 @@
+6d7df9b7e074548cf18dd16365862f1b *tests/data/fate/acodec-pcm-u24le.nut
+1590202 tests/data/fate/acodec-pcm-u24le.nut
+64151e4bcc2b717aa5a8454d424d6a1f *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..6a53919
--- a/dev/null
+++ b/tests/ref/acodec/pcm-u32be
@@ -0,0 +1,4 @@
+7078e6d7e80247b8531d5cc16d09f385 *tests/data/fate/acodec-pcm-u32be.nut
+2120148 tests/data/fate/acodec-pcm-u32be.nut
+64151e4bcc2b717aa5a8454d424d6a1f *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..18a5d15
--- a/dev/null
+++ b/tests/ref/acodec/pcm-u32le
@@ -0,0 +1,4 @@
+34df9a7e1fe60da0bc6ec0485b68726e *tests/data/fate/acodec-pcm-u32le.nut
+2120148 tests/data/fate/acodec-pcm-u32le.nut
+64151e4bcc2b717aa5a8454d424d6a1f *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/roqaudio b/tests/ref/acodec/roqaudio
new file mode 100644
index 0000000..8632504
--- a/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
+be6d954adaf984f2dc65a3ff50b55f26 *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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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/ansi256 b/tests/ref/fate/ansi256
new file mode 100644
index 0000000..94acd45
--- a/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
--- a/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
--- a/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/bprint b/tests/ref/fate/bprint
new file mode 100644
index 0000000..b33c1ae
--- a/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
--- a/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..f9af8fa 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, 0x76183b91
+0, 1, 1, 1, 622080, 0x2ca5e808
+0, 2, 2, 1, 622080, 0xc503eda4
+0, 3, 3, 1, 622080, 0xa0dbf06c
+0, 4, 4, 1, 622080, 0xf4363cfa
+0, 5, 5, 1, 622080, 0xaa7dd9b8
+0, 6, 6, 1, 622080, 0x3ab6223b
+0, 7, 7, 1, 622080, 0xe402644b
+0, 8, 8, 1, 622080, 0xd0da3ade
+0, 9, 9, 1, 622080, 0x0aff6151
+0, 10, 10, 1, 622080, 0x02aea3d5
+0, 11, 11, 1, 622080, 0x5d8eeccd
+0, 12, 12, 1, 622080, 0x54384735
+0, 13, 13, 1, 622080, 0x890d71c2
+0, 14, 14, 1, 622080, 0xc60ae25b
+0, 15, 15, 1, 622080, 0xe589e774
+0, 16, 16, 1, 622080, 0x03471e74
+0, 17, 17, 1, 622080, 0x4e22302c
+0, 18, 18, 1, 622080, 0x00333583
+0, 19, 19, 1, 622080, 0xd6eae7d9
+0, 20, 20, 1, 622080, 0x72fe94f7
+0, 21, 21, 1, 622080, 0x3ebbad1e
+0, 22, 22, 1, 622080, 0x2fb1de4b
+0, 23, 23, 1, 622080, 0x3bfea6d2
+0, 24, 24, 1, 622080, 0x0fb551b2
+0, 25, 25, 1, 622080, 0xb203284f
+0, 26, 26, 1, 622080, 0xb3baac30
+0, 27, 27, 1, 622080, 0x15f2c1c7
+0, 28, 28, 1, 622080, 0xb2b530ce
+0, 29, 29, 1, 622080, 0xbbaaf241
+0, 30, 30, 1, 622080, 0x01bc9dfc
+0, 31, 31, 1, 622080, 0x8a449a42
+0, 32, 32, 1, 622080, 0xdc63d73f
+0, 33, 33, 1, 622080, 0xf06bc231
+0, 34, 34, 1, 622080, 0x19e04295
+0, 35, 35, 1, 622080, 0x1e7d1acd
+0, 36, 36, 1, 622080, 0x43878b48
+0, 37, 37, 1, 622080, 0xcd94b702
+0, 38, 38, 1, 622080, 0xd2706cf1
+0, 39, 39, 1, 622080, 0x47d636f3
+0, 40, 40, 1, 622080, 0x4a516acc
+0, 41, 41, 1, 622080, 0x52b7d89a
+0, 42, 42, 1, 622080, 0xc9ba03be
+0, 43, 43, 1, 622080, 0x6d17785e
+0, 44, 44, 1, 622080, 0x8264871b
+0, 45, 45, 1, 622080, 0xd59c84c0
+0, 46, 46, 1, 622080, 0x2b86d6cd
+0, 47, 47, 1, 622080, 0x9c5a5f51
+0, 48, 48, 1, 622080, 0x221f79ca
+0, 49, 49, 1, 622080, 0x98edb3ec
+0, 50, 50, 1, 622080, 0x9a31262c
+0, 51, 51, 1, 622080, 0x18f48378
+0, 52, 52, 1, 622080, 0x957c3d9c
+0, 53, 53, 1, 622080, 0x9cc6866e
+0, 54, 54, 1, 622080, 0x45613726
+0, 55, 55, 1, 622080, 0x7a6c5e65
+0, 56, 56, 1, 622080, 0x976d7a11
+0, 57, 57, 1, 622080, 0x192aea08
+0, 58, 58, 1, 622080, 0x8d4fc823
+0, 59, 59, 1, 622080, 0x1f9c55d7
+0, 60, 60, 1, 622080, 0xd4336d41
+0, 61, 61, 1, 622080, 0x7aa650cd
+0, 62, 62, 1, 622080, 0x8efaaeb1
+0, 63, 63, 1, 622080, 0x3d8c3053
+0, 64, 64, 1, 622080, 0x1e2b64b0
+0, 65, 65, 1, 622080, 0x0436b1a7
+0, 66, 66, 1, 622080, 0xc5120072
+0, 67, 67, 1, 622080, 0x0203b245
+0, 68, 68, 1, 622080, 0x9815582b
+0, 69, 69, 1, 622080, 0x3c60c359
+0, 70, 70, 1, 622080, 0x1a26b948
+0, 71, 71, 1, 622080, 0x56079812
+0, 72, 72, 1, 622080, 0x7b192a55
+0, 73, 73, 1, 622080, 0x335632ab
+0, 74, 74, 1, 622080, 0xd0c12eb8
+0, 75, 75, 1, 622080, 0x93bf46cb
+0, 76, 76, 1, 622080, 0xce67ce24
+0, 77, 77, 1, 622080, 0xff95bb26
+0, 78, 78, 1, 622080, 0x5e750705
+0, 79, 79, 1, 622080, 0x45a35725
+0, 80, 80, 1, 622080, 0xd8e93c39
+0, 81, 81, 1, 622080, 0xa9f8db50
+0, 82, 82, 1, 622080, 0xf90a862e
+0, 83, 83, 1, 622080, 0x5e5a4216
+0, 84, 84, 1, 622080, 0xaaf45ed6
+0, 85, 85, 1, 622080, 0x1933cda5
+0, 86, 86, 1, 622080, 0x7ff68d91
+0, 87, 87, 1, 622080, 0x10038fe9
+0, 88, 88, 1, 622080, 0x9b3425a6
+0, 89, 89, 1, 622080, 0x8d2a141d
+0, 90, 90, 1, 622080, 0x698a333e
+0, 91, 91, 1, 622080, 0x334685d1
+0, 92, 92, 1, 622080, 0x40317d40
+0, 93, 93, 1, 622080, 0xd3c6f519
+0, 94, 94, 1, 622080, 0xfc2210c2
+0, 95, 95, 1, 622080, 0x3761df34
+0, 96, 96, 1, 622080, 0xef25462a
+0, 97, 97, 1, 622080, 0x0fd38121
+0, 98, 98, 1, 622080, 0x184856a6
+0, 99, 99, 1, 622080, 0xc57c9f12
+0, 100, 100, 1, 622080, 0x39874291
+0, 101, 101, 1, 622080, 0x7c13cec4
+0, 102, 102, 1, 622080, 0xc4192a76
+0, 103, 103, 1, 622080, 0x2af404e3
+0, 104, 104, 1, 622080, 0x1ee18f41
+0, 105, 105, 1, 622080, 0xfb4d9ee5
+0, 106, 106, 1, 622080, 0x50aae4ff
+0, 107, 107, 1, 622080, 0x030f91fe
+0, 108, 108, 1, 622080, 0x3a3ee08c
+0, 109, 109, 1, 622080, 0x50121423
+0, 110, 110, 1, 622080, 0xda39e2d6
+0, 111, 111, 1, 622080, 0x9e13ccd6
+0, 112, 112, 1, 622080, 0xb72a22a7
+0, 113, 113, 1, 622080, 0xb76904d5
+0, 114, 114, 1, 622080, 0xcffa04a8
+0, 115, 115, 1, 622080, 0x2984bf3f
+0, 116, 116, 1, 622080, 0x274b5778
+0, 117, 117, 1, 622080, 0xf059413a
+0, 118, 118, 1, 622080, 0x969fae57
+0, 119, 119, 1, 622080, 0x75c29097
+0, 120, 120, 1, 622080, 0x2bf3b07d
+0, 121, 121, 1, 622080, 0x9f43271d
+0, 122, 122, 1, 622080, 0x67bf23f3
+0, 123, 123, 1, 622080, 0xa8edcf33
+0, 124, 124, 1, 622080, 0x17a0789e
+0, 125, 125, 1, 622080, 0x14b67cc7
+0, 126, 126, 1, 622080, 0x779215cd
+0, 127, 127, 1, 622080, 0x8b460a21
+0, 128, 128, 1, 622080, 0x0502ad7d
+0, 129, 129, 1, 622080, 0x6860678f
+0, 130, 130, 1, 622080, 0xe180469e
+0, 131, 131, 1, 622080, 0x9a992835
+0, 132, 132, 1, 622080, 0x2efafa33
+0, 133, 133, 1, 622080, 0xe24e59b2
+0, 134, 134, 1, 622080, 0xfb774d53
+0, 135, 135, 1, 622080, 0x3de4ea81
+0, 136, 136, 1, 622080, 0xaf9aa1d6
+0, 137, 137, 1, 622080, 0xa0e3722f
+0, 138, 138, 1, 622080, 0x81684492
+0, 139, 139, 1, 622080, 0xa4e971fb
+0, 140, 140, 1, 622080, 0x4a1903c8
+0, 141, 141, 1, 622080, 0x26304e4a
+0, 142, 142, 1, 622080, 0x867983a4
+0, 143, 143, 1, 622080, 0x2e7e4d13
+0, 144, 144, 1, 622080, 0x736f4682
+0, 145, 145, 1, 622080, 0x426a95fa
+0, 146, 146, 1, 622080, 0x2bc8850c
+0, 147, 147, 1, 622080, 0x047e77ab
+0, 148, 148, 1, 622080, 0x414ab77f
+0, 149, 149, 1, 622080, 0x42681090
+0, 150, 150, 1, 622080, 0x80744ccb
+0, 151, 151, 1, 622080, 0x50e2ecc0
+0, 152, 152, 1, 622080, 0x5c9fe70e
+0, 153, 153, 1, 622080, 0x016461ee
+0, 154, 154, 1, 622080, 0xd42f019a
+0, 155, 155, 1, 622080, 0x8171bf41
+0, 156, 156, 1, 622080, 0xf4d8ef7e
+0, 157, 157, 1, 622080, 0xf2d513c8
+0, 158, 158, 1, 622080, 0xb5b07704
+0, 159, 159, 1, 622080, 0x2168a07a
+0, 160, 160, 1, 622080, 0x840418f9
+0, 161, 161, 1, 622080, 0xd36f1b7c
+0, 162, 162, 1, 622080, 0x52532604
+0, 163, 163, 1, 622080, 0x0856d6eb
+0, 164, 164, 1, 622080, 0x21748734
+0, 165, 165, 1, 622080, 0xbd315c05
+0, 166, 166, 1, 622080, 0x1cea8103
+0, 167, 167, 1, 622080, 0x71f6e3cb
+0, 168, 168, 1, 622080, 0xb12d7aa7
+0, 169, 169, 1, 622080, 0x54dd2acb
+0, 170, 170, 1, 622080, 0xe8f93765
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/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 1c24aea..89273d8 100644
--- a/tests/ref/fate/crc
+++ b/tests/ref/fate/crc
@@ -1,4 +1,5 @@
crc EDB88320 = 3D5CDD04
crc 04C11DB7 = E0BAF5C0
+crc 00864CFB = 326039
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
--- a/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/ea-mad b/tests/ref/fate/ea-mad
index ce1df4a..1ea92fd 100644
--- a/tests/ref/fate/ea-mad
+++ b/tests/ref/fate/ea-mad
@@ -1,97 +1,97 @@
-#tb 0: 1/90000
-0, 0, 0, 0, 535680, 0x889c32cf
-0, 2970, 2970, 0, 535680, 0x0b1ef044
-0, 5940, 5940, 0, 535680, 0xa7d0818b
-0, 8910, 8910, 0, 535680, 0xf392e4e1
-0, 11880, 11880, 0, 535680, 0x08480c69
-0, 14850, 14850, 0, 535680, 0x2b8af1ed
-0, 17820, 17820, 0, 535680, 0x0d58e062
-0, 20790, 20790, 0, 535680, 0xd140ced0
-0, 23760, 23760, 0, 535680, 0xbd0e6652
-0, 26730, 26730, 0, 535680, 0xdc2f2a6b
-0, 29700, 29700, 0, 535680, 0x97c31a38
-0, 32670, 32670, 0, 535680, 0x1a2bdf38
-0, 35640, 35640, 0, 535680, 0xb3af3ac4
-0, 38610, 38610, 0, 535680, 0x07a52577
-0, 41580, 41580, 0, 535680, 0x78407368
-0, 44550, 44550, 0, 535680, 0xd2a9efc3
-0, 47520, 47520, 0, 535680, 0x36df2f29
-0, 50490, 50490, 0, 535680, 0x9821d8f7
-0, 53460, 53460, 0, 535680, 0xf64321aa
-0, 56430, 56430, 0, 535680, 0x53e4d9aa
-0, 59400, 59400, 0, 535680, 0xdbd6f853
-0, 62370, 62370, 0, 535680, 0x5d40cf8b
-0, 65340, 65340, 0, 535680, 0xe624af9d
-0, 68310, 68310, 0, 535680, 0xd9dbb4cd
-0, 71280, 71280, 0, 535680, 0xf14e72ec
-0, 74250, 74250, 0, 535680, 0xb35c18f6
-0, 77220, 77220, 0, 535680, 0xc96d7757
-0, 80190, 80190, 0, 535680, 0xdfb937df
-0, 83160, 83160, 0, 535680, 0x40cd71d7
-0, 86130, 86130, 0, 535680, 0x15e176d6
-0, 89100, 89100, 0, 535680, 0x7f891b24
-0, 92070, 92070, 0, 535680, 0xb87a8c32
-0, 95040, 95040, 0, 535680, 0x0c01541f
-0, 98010, 98010, 0, 535680, 0x9eee99b3
-0, 100980, 100980, 0, 535680, 0xd65eb689
-0, 103950, 103950, 0, 535680, 0x6e733cfa
-0, 106920, 106920, 0, 535680, 0xac536670
-0, 109890, 109890, 0, 535680, 0x002275b8
-0, 112860, 112860, 0, 535680, 0x6a5385cb
-0, 115830, 115830, 0, 535680, 0xd129ade3
-0, 118800, 118800, 0, 535680, 0x32cab5d7
-0, 121770, 121770, 0, 535680, 0x08be1c8f
-0, 124740, 124740, 0, 535680, 0x59e1fba0
-0, 127710, 127710, 0, 535680, 0x138aee3a
-0, 130680, 130680, 0, 535680, 0x4cfbcd5e
-0, 133650, 133650, 0, 535680, 0xf6cf0fb4
-0, 136620, 136620, 0, 535680, 0xb13a06de
-0, 139590, 139590, 0, 535680, 0x59176f00
-0, 142560, 142560, 0, 535680, 0xf84b4ca3
-0, 145530, 145530, 0, 535680, 0x7fd09f73
-0, 148500, 148500, 0, 535680, 0x3be383b8
-0, 151470, 151470, 0, 535680, 0xa7118e51
-0, 154440, 154440, 0, 535680, 0xbd83120c
-0, 157410, 157410, 0, 535680, 0x3bc9d256
-0, 160380, 160380, 0, 535680, 0xb6c87f87
-0, 163350, 163350, 0, 535680, 0xe80d110a
-0, 166320, 166320, 0, 535680, 0xb3a83362
-0, 169290, 169290, 0, 535680, 0xfb39eb52
-0, 172260, 172260, 0, 535680, 0xbf6e1220
-0, 175230, 175230, 0, 535680, 0x9ecdfbae
-0, 178200, 178200, 0, 535680, 0x069a65f5
-0, 181170, 181170, 0, 535680, 0x206e372c
-0, 184140, 184140, 0, 535680, 0x58c83dd4
-0, 187110, 187110, 0, 535680, 0xc3562b03
-0, 190080, 190080, 0, 535680, 0xd1ed85a0
-0, 193050, 193050, 0, 535680, 0xb6205f4b
-0, 196020, 196020, 0, 535680, 0xaedf8bfa
-0, 198990, 198990, 0, 535680, 0xa48d5dea
-0, 201960, 201960, 0, 535680, 0xff82e7c1
-0, 204930, 204930, 0, 535680, 0xc9560222
-0, 207900, 207900, 0, 535680, 0x0fafa549
-0, 210870, 210870, 0, 535680, 0x8d556ccb
-0, 213840, 213840, 0, 535680, 0x802aac1f
-0, 216810, 216810, 0, 535680, 0x7d0fa168
-0, 219780, 219780, 0, 535680, 0x1a9255c9
-0, 222750, 222750, 0, 535680, 0xb4ec7e35
-0, 225720, 225720, 0, 535680, 0x48fac072
-0, 228690, 228690, 0, 535680, 0x1e260135
-0, 231660, 231660, 0, 535680, 0xce4d5079
-0, 234630, 234630, 0, 535680, 0x13e5e4ed
-0, 237600, 237600, 0, 535680, 0x592305ec
-0, 240570, 240570, 0, 535680, 0x9e227508
-0, 243540, 243540, 0, 535680, 0x1d37e5ea
-0, 246510, 246510, 0, 535680, 0x7eae7692
-0, 249480, 249480, 0, 535680, 0xf452e4b9
-0, 252450, 252450, 0, 535680, 0x1460e7e9
-0, 255420, 255420, 0, 535680, 0xc6d8a638
-0, 258390, 258390, 0, 535680, 0x854f5fb0
-0, 261360, 261360, 0, 535680, 0x854f5fb0
-0, 264330, 264330, 0, 535680, 0x70a02d87
-0, 267300, 267300, 0, 535680, 0x9a4ad464
-0, 270270, 270270, 0, 535680, 0x9a4ad464
-0, 273240, 273240, 0, 535680, 0x9a4ad464
-0, 276210, 276210, 0, 535680, 0x9a4ad464
-0, 279180, 279180, 0, 535680, 0x9a4ad464
-0, 282150, 282150, 0, 535680, 0x9a4ad464
+#tb 0: 33/1000
+0, 0, 0, 1, 535680, 0x889c32cf
+0, 1, 1, 1, 535680, 0x0b1ef044
+0, 2, 2, 1, 535680, 0xa7d0818b
+0, 3, 3, 1, 535680, 0xf392e4e1
+0, 4, 4, 1, 535680, 0x08480c69
+0, 5, 5, 1, 535680, 0x2b8af1ed
+0, 6, 6, 1, 535680, 0x0d58e062
+0, 7, 7, 1, 535680, 0xd140ced0
+0, 8, 8, 1, 535680, 0xbd0e6652
+0, 9, 9, 1, 535680, 0xdc2f2a6b
+0, 10, 10, 1, 535680, 0x97c31a38
+0, 11, 11, 1, 535680, 0x1a2bdf38
+0, 12, 12, 1, 535680, 0xb3af3ac4
+0, 13, 13, 1, 535680, 0x07a52577
+0, 14, 14, 1, 535680, 0x78407368
+0, 15, 15, 1, 535680, 0xd2a9efc3
+0, 16, 16, 1, 535680, 0x36df2f29
+0, 17, 17, 1, 535680, 0x9821d8f7
+0, 18, 18, 1, 535680, 0xf64321aa
+0, 19, 19, 1, 535680, 0x53e4d9aa
+0, 20, 20, 1, 535680, 0xdbd6f853
+0, 21, 21, 1, 535680, 0x5d40cf8b
+0, 22, 22, 1, 535680, 0xe624af9d
+0, 23, 23, 1, 535680, 0xd9dbb4cd
+0, 24, 24, 1, 535680, 0xf14e72ec
+0, 25, 25, 1, 535680, 0xb35c18f6
+0, 26, 26, 1, 535680, 0xc96d7757
+0, 27, 27, 1, 535680, 0xdfb937df
+0, 28, 28, 1, 535680, 0x40cd71d7
+0, 29, 29, 1, 535680, 0x15e176d6
+0, 30, 30, 1, 535680, 0x7f891b24
+0, 31, 31, 1, 535680, 0xb87a8c32
+0, 32, 32, 1, 535680, 0x0c01541f
+0, 33, 33, 1, 535680, 0x9eee99b3
+0, 34, 34, 1, 535680, 0xd65eb689
+0, 35, 35, 1, 535680, 0x6e733cfa
+0, 36, 36, 1, 535680, 0xac536670
+0, 37, 37, 1, 535680, 0x002275b8
+0, 38, 38, 1, 535680, 0x6a5385cb
+0, 39, 39, 1, 535680, 0xd129ade3
+0, 40, 40, 1, 535680, 0x32cab5d7
+0, 41, 41, 1, 535680, 0x08be1c8f
+0, 42, 42, 1, 535680, 0x59e1fba0
+0, 43, 43, 1, 535680, 0x138aee3a
+0, 44, 44, 1, 535680, 0x4cfbcd5e
+0, 45, 45, 1, 535680, 0xf6cf0fb4
+0, 46, 46, 1, 535680, 0xb13a06de
+0, 47, 47, 1, 535680, 0x59176f00
+0, 48, 48, 1, 535680, 0xf84b4ca3
+0, 49, 49, 1, 535680, 0x7fd09f73
+0, 50, 50, 1, 535680, 0x3be383b8
+0, 51, 51, 1, 535680, 0xa7118e51
+0, 52, 52, 1, 535680, 0xbd83120c
+0, 53, 53, 1, 535680, 0x3bc9d256
+0, 54, 54, 1, 535680, 0xb6c87f87
+0, 55, 55, 1, 535680, 0xe80d110a
+0, 56, 56, 1, 535680, 0xb3a83362
+0, 57, 57, 1, 535680, 0xfb39eb52
+0, 58, 58, 1, 535680, 0xbf6e1220
+0, 59, 59, 1, 535680, 0x9ecdfbae
+0, 60, 60, 1, 535680, 0x069a65f5
+0, 61, 61, 1, 535680, 0x206e372c
+0, 62, 62, 1, 535680, 0x58c83dd4
+0, 63, 63, 1, 535680, 0xc3562b03
+0, 64, 64, 1, 535680, 0xd1ed85a0
+0, 65, 65, 1, 535680, 0xb6205f4b
+0, 66, 66, 1, 535680, 0xaedf8bfa
+0, 67, 67, 1, 535680, 0xa48d5dea
+0, 68, 68, 1, 535680, 0xff82e7c1
+0, 69, 69, 1, 535680, 0xc9560222
+0, 70, 70, 1, 535680, 0x0fafa549
+0, 71, 71, 1, 535680, 0x8d556ccb
+0, 72, 72, 1, 535680, 0x802aac1f
+0, 73, 73, 1, 535680, 0x7d0fa168
+0, 74, 74, 1, 535680, 0x1a9255c9
+0, 75, 75, 1, 535680, 0xb4ec7e35
+0, 76, 76, 1, 535680, 0x48fac072
+0, 77, 77, 1, 535680, 0x1e260135
+0, 78, 78, 1, 535680, 0xce4d5079
+0, 79, 79, 1, 535680, 0x13e5e4ed
+0, 80, 80, 1, 535680, 0x592305ec
+0, 81, 81, 1, 535680, 0x9e227508
+0, 82, 82, 1, 535680, 0x1d37e5ea
+0, 83, 83, 1, 535680, 0x7eae7692
+0, 84, 84, 1, 535680, 0xf452e4b9
+0, 85, 85, 1, 535680, 0x1460e7e9
+0, 86, 86, 1, 535680, 0xc6d8a638
+0, 87, 87, 1, 535680, 0x854f5fb0
+0, 88, 88, 1, 535680, 0x854f5fb0
+0, 89, 89, 1, 535680, 0x70a02d87
+0, 90, 90, 1, 535680, 0x9a4ad464
+0, 91, 91, 1, 535680, 0x9a4ad464
+0, 92, 92, 1, 535680, 0x9a4ad464
+0, 93, 93, 1, 535680, 0x9a4ad464
+0, 94, 94, 1, 535680, 0x9a4ad464
+0, 95, 95, 1, 535680, 0x9a4ad464
diff --git a/tests/ref/fate/ea-tgq b/tests/ref/fate/ea-tgq
index edb04fa..5c0648d 100644
--- a/tests/ref/fate/ea-tgq
+++ b/tests/ref/fate/ea-tgq
@@ -1,279 +1,279 @@
-#tb 0: 1/90000
-0, 0, 0, 0, 34944, 0xe33671a4
-0, 6000, 6000, 0, 34944, 0xe33671a4
-0, 12000, 12000, 0, 34944, 0xe33671a4
-0, 18000, 18000, 0, 34944, 0xe33671a4
-0, 24000, 24000, 0, 34944, 0xe33671a4
-0, 30000, 30000, 0, 34944, 0xe33671a4
-0, 36000, 36000, 0, 34944, 0xe33671a4
-0, 42000, 42000, 0, 34944, 0xe33671a4
-0, 48000, 48000, 0, 34944, 0xe33671a4
-0, 54000, 54000, 0, 34944, 0xe33671a4
-0, 60000, 60000, 0, 34944, 0xe33671a4
-0, 66000, 66000, 0, 34944, 0xe33671a4
-0, 72000, 72000, 0, 34944, 0xe33671a4
-0, 78000, 78000, 0, 34944, 0xe33671a4
-0, 84000, 84000, 0, 34944, 0xe33671a4
-0, 90000, 90000, 0, 34944, 0x63196b41
-0, 96000, 96000, 0, 34944, 0x308d6f10
-0, 102000, 102000, 0, 34944, 0x86026ced
-0, 108000, 108000, 0, 34944, 0xaa6a6bc9
-0, 114000, 114000, 0, 34944, 0x58276ee3
-0, 120000, 120000, 0, 34944, 0x402d70c2
-0, 126000, 126000, 0, 34944, 0x948d74bf
-0, 132000, 132000, 0, 34944, 0x3d31759c
-0, 138000, 138000, 0, 34944, 0x638c734e
-0, 144000, 144000, 0, 34944, 0xe218768a
-0, 150000, 150000, 0, 34944, 0xed6678ff
-0, 156000, 156000, 0, 34944, 0x381b7dda
-0, 162000, 162000, 0, 34944, 0x216680e7
-0, 168000, 168000, 0, 34944, 0xaca5810f
-0, 174000, 174000, 0, 34944, 0xf70b81eb
-0, 180000, 180000, 0, 34944, 0x3675858b
-0, 186000, 186000, 0, 34944, 0xa51188c3
-0, 192000, 192000, 0, 34944, 0x3a848bf1
-0, 198000, 198000, 0, 34944, 0x67608d4d
-0, 204000, 204000, 0, 34944, 0xafe49165
-0, 210000, 210000, 0, 34944, 0x7e8a94a7
-0, 216000, 216000, 0, 34944, 0x3b889432
-0, 222000, 222000, 0, 34944, 0x97e89623
-0, 228000, 228000, 0, 34944, 0x07819793
-0, 234000, 234000, 0, 34944, 0xdac39b87
-0, 240000, 240000, 0, 34944, 0x4d8c9d93
-0, 246000, 246000, 0, 34944, 0xcf009fa7
-0, 252000, 252000, 0, 34944, 0x2f109f6e
-0, 258000, 258000, 0, 34944, 0xcedda4eb
-0, 264000, 264000, 0, 34944, 0xfe89a6df
-0, 270000, 270000, 0, 34944, 0x195ea7a9
-0, 276000, 276000, 0, 34944, 0x9287ab92
-0, 282000, 282000, 0, 34944, 0x6d21af54
-0, 288000, 288000, 0, 34944, 0xd627b28b
-0, 294000, 294000, 0, 34944, 0x3ad5b6fd
-0, 300000, 300000, 0, 34944, 0x5101b64d
-0, 306000, 306000, 0, 34944, 0xb968b8ca
-0, 312000, 312000, 0, 34944, 0xa105b74a
-0, 318000, 318000, 0, 34944, 0xc056bdd6
-0, 324000, 324000, 0, 34944, 0xec7fc1d9
-0, 330000, 330000, 0, 34944, 0x92c3c3e0
-0, 336000, 336000, 0, 34944, 0x9bffc45c
-0, 342000, 342000, 0, 34944, 0x5aabca4b
-0, 348000, 348000, 0, 34944, 0xcbdacb26
-0, 354000, 354000, 0, 34944, 0xed6cce3f
-0, 360000, 360000, 0, 34944, 0xcc61cfb8
-0, 366000, 366000, 0, 34944, 0x7a97d427
-0, 372000, 372000, 0, 34944, 0x7cdbd5ec
-0, 378000, 378000, 0, 34944, 0x5851d9c4
-0, 384000, 384000, 0, 34944, 0x69d5dd1d
-0, 390000, 390000, 0, 34944, 0xdf30dcf4
-0, 396000, 396000, 0, 34944, 0x2359e084
-0, 402000, 402000, 0, 34944, 0xe0bae491
-0, 408000, 408000, 0, 34944, 0xa716e4fd
-0, 414000, 414000, 0, 34944, 0xe48aeaf4
-0, 420000, 420000, 0, 34944, 0x0a0deb21
-0, 426000, 426000, 0, 34944, 0xe8a56e12
-0, 432000, 432000, 0, 34944, 0x0d72c98e
-0, 438000, 438000, 0, 34944, 0x71a7bb9d
-0, 444000, 444000, 0, 34944, 0xc0c8c108
-0, 450000, 450000, 0, 34944, 0x1d1fc3ba
-0, 456000, 456000, 0, 34944, 0xebcfc67f
-0, 462000, 462000, 0, 34944, 0x2921cb5b
-0, 468000, 468000, 0, 34944, 0x793ed099
-0, 474000, 474000, 0, 34944, 0xefebd9e8
-0, 480000, 480000, 0, 34944, 0x163c2330
-0, 486000, 486000, 0, 34944, 0x35155672
-0, 492000, 492000, 0, 34944, 0x05474e2e
-0, 498000, 498000, 0, 34944, 0x9433542f
-0, 504000, 504000, 0, 34944, 0x777d5a13
-0, 510000, 510000, 0, 34944, 0x87526776
-0, 516000, 516000, 0, 34944, 0x4c3c72c1
-0, 522000, 522000, 0, 34944, 0x70407b87
-0, 528000, 528000, 0, 34944, 0x2358861d
-0, 534000, 534000, 0, 34944, 0xec61923f
-0, 540000, 540000, 0, 34944, 0x0bb2a0d4
-0, 546000, 546000, 0, 34944, 0x6b6d8624
-0, 552000, 552000, 0, 34944, 0x624761ec
-0, 558000, 558000, 0, 34944, 0xff23b926
-0, 564000, 564000, 0, 34944, 0x07fc7ca5
-0, 570000, 570000, 0, 34944, 0xa8d3ffda
-0, 576000, 576000, 0, 34944, 0xa2d31265
-0, 582000, 582000, 0, 34944, 0x5e58225e
-0, 588000, 588000, 0, 34944, 0x284b2fb0
-0, 594000, 594000, 0, 34944, 0x205b3cb1
-0, 600000, 600000, 0, 34944, 0x3fa64a09
-0, 606000, 606000, 0, 34944, 0xa5de5097
-0, 612000, 612000, 0, 34944, 0x00686cea
-0, 618000, 618000, 0, 34944, 0x465a8282
-0, 624000, 624000, 0, 34944, 0x4ceb8189
-0, 630000, 630000, 0, 34944, 0x14698509
-0, 636000, 636000, 0, 34944, 0x232c830d
-0, 642000, 642000, 0, 34944, 0x0739807c
-0, 648000, 648000, 0, 34944, 0x83b0861e
-0, 654000, 654000, 0, 34944, 0xbdc094b1
-0, 660000, 660000, 0, 34944, 0xc4c0a605
-0, 666000, 666000, 0, 34944, 0x8376b059
-0, 672000, 672000, 0, 34944, 0x2035b939
-0, 678000, 678000, 0, 34944, 0xb6bfc812
-0, 684000, 684000, 0, 34944, 0xc5d4d5c4
-0, 690000, 690000, 0, 34944, 0x492c954e
-0, 696000, 696000, 0, 34944, 0xd23f0dcc
-0, 702000, 702000, 0, 34944, 0x22d7ff6c
-0, 708000, 708000, 0, 34944, 0xd08b4168
-0, 714000, 714000, 0, 34944, 0xa82e4062
-0, 720000, 720000, 0, 34944, 0xcc4f2f31
-0, 726000, 726000, 0, 34944, 0x964b0307
-0, 732000, 732000, 0, 34944, 0xe8130606
-0, 738000, 738000, 0, 34944, 0x5fb744bf
-0, 744000, 744000, 0, 34944, 0x1546a88b
-0, 750000, 750000, 0, 34944, 0xe6e4d94d
-0, 756000, 756000, 0, 34944, 0x8d1ea97e
-0, 762000, 762000, 0, 34944, 0x3bb1fb55
-0, 768000, 768000, 0, 34944, 0x3c37e9cc
-0, 774000, 774000, 0, 34944, 0xe2d22521
-0, 780000, 780000, 0, 34944, 0x7c0ec8cc
-0, 786000, 786000, 0, 34944, 0x7c2dc956
-0, 792000, 792000, 0, 34944, 0x7fe3c263
-0, 798000, 798000, 0, 34944, 0x9a65b813
-0, 804000, 804000, 0, 34944, 0x7ea7cb14
-0, 810000, 810000, 0, 34944, 0x31ded64e
-0, 816000, 816000, 0, 34944, 0x50f30ad1
-0, 822000, 822000, 0, 34944, 0x12eac45c
-0, 828000, 828000, 0, 34944, 0x984b6335
-0, 834000, 834000, 0, 34944, 0x3b9b02f0
-0, 840000, 840000, 0, 34944, 0x4629d2a4
-0, 846000, 846000, 0, 34944, 0x38687e89
-0, 852000, 852000, 0, 34944, 0xb76620fe
-0, 858000, 858000, 0, 34944, 0x66347155
-0, 864000, 864000, 0, 34944, 0x6e6bc297
-0, 870000, 870000, 0, 34944, 0x452a653a
-0, 876000, 876000, 0, 34944, 0x8c8a0683
-0, 882000, 882000, 0, 34944, 0xaf5d7c2d
-0, 888000, 888000, 0, 34944, 0x3064a7e1
-0, 894000, 894000, 0, 34944, 0xc0657fc4
-0, 900000, 900000, 0, 34944, 0x1f129266
-0, 906000, 906000, 0, 34944, 0x35adedfb
-0, 912000, 912000, 0, 34944, 0x40a3db0d
-0, 918000, 918000, 0, 34944, 0x87bebb37
-0, 924000, 924000, 0, 34944, 0x04d7ffed
-0, 930000, 930000, 0, 34944, 0x9bde3180
-0, 936000, 936000, 0, 34944, 0xc35c25bd
-0, 942000, 942000, 0, 34944, 0x820bf4bb
-0, 948000, 948000, 0, 34944, 0x876163ef
-0, 954000, 954000, 0, 34944, 0x3ab6dac0
-0, 960000, 960000, 0, 34944, 0x69a9ef73
-0, 966000, 966000, 0, 34944, 0x0df3813c
-0, 972000, 972000, 0, 34944, 0x1bba0947
-0, 978000, 978000, 0, 34944, 0x0b7883d4
-0, 984000, 984000, 0, 34944, 0xa9972f7e
-0, 990000, 990000, 0, 34944, 0x603d08fe
-0, 996000, 996000, 0, 34944, 0x05f4f111
-0, 1002000, 1002000, 0, 34944, 0xb24fdb42
-0, 1008000, 1008000, 0, 34944, 0xfe2ad344
-0, 1014000, 1014000, 0, 34944, 0xda4bcb8f
-0, 1020000, 1020000, 0, 34944, 0xd28aca6b
-0, 1026000, 1026000, 0, 34944, 0x9486c260
-0, 1032000, 1032000, 0, 34944, 0xad9fc04d
-0, 1038000, 1038000, 0, 34944, 0x9333c0ca
-0, 1044000, 1044000, 0, 34944, 0x96e9c226
-0, 1050000, 1050000, 0, 34944, 0x3e89bd6f
-0, 1056000, 1056000, 0, 34944, 0x7a2dbd32
-0, 1062000, 1062000, 0, 34944, 0xe578ba53
-0, 1068000, 1068000, 0, 34944, 0xb77ebab1
-0, 1074000, 1074000, 0, 34944, 0xd8bfbcb1
-0, 1080000, 1080000, 0, 34944, 0x15d9bc97
-0, 1086000, 1086000, 0, 34944, 0x09c3b9f0
-0, 1092000, 1092000, 0, 34944, 0xd8c8b944
-0, 1098000, 1098000, 0, 34944, 0x2c2fb996
-0, 1104000, 1104000, 0, 34944, 0xd7a8b7e7
-0, 1110000, 1110000, 0, 34944, 0xce34b843
-0, 1116000, 1116000, 0, 34944, 0xba69e9fd
-0, 1122000, 1122000, 0, 34944, 0x1b3f1adc
-0, 1128000, 1128000, 0, 34944, 0x48f515aa
-0, 1134000, 1134000, 0, 34944, 0x864e12bb
-0, 1140000, 1140000, 0, 34944, 0xca571996
-0, 1146000, 1146000, 0, 34944, 0x1d5a1af0
-0, 1152000, 1152000, 0, 34944, 0x3d1e171f
-0, 1158000, 1158000, 0, 34944, 0xb57417ca
-0, 1164000, 1164000, 0, 34944, 0x6e6d1e9d
-0, 1170000, 1170000, 0, 34944, 0xc9971899
-0, 1176000, 1176000, 0, 34944, 0xe0b112c8
-0, 1182000, 1182000, 0, 34944, 0x121b0cd9
-0, 1188000, 1188000, 0, 34944, 0x418e0eff
-0, 1194000, 1194000, 0, 34944, 0x9e1b07d8
-0, 1200000, 1200000, 0, 34944, 0x5590064a
-0, 1206000, 1206000, 0, 34944, 0x7a170b14
-0, 1212000, 1212000, 0, 34944, 0xf25709f0
-0, 1218000, 1218000, 0, 34944, 0x94fa099a
-0, 1224000, 1224000, 0, 34944, 0x081e06ae
-0, 1230000, 1230000, 0, 34944, 0xcfc40417
-0, 1236000, 1236000, 0, 34944, 0xed33096f
-0, 1242000, 1242000, 0, 34944, 0xd73a07e2
-0, 1248000, 1248000, 0, 34944, 0xc512077d
-0, 1254000, 1254000, 0, 34944, 0x27d7021d
-0, 1260000, 1260000, 0, 34944, 0xab59fd20
-0, 1266000, 1266000, 0, 34944, 0xcc2400b7
-0, 1272000, 1272000, 0, 34944, 0xcb3bfb99
-0, 1278000, 1278000, 0, 34944, 0x0974fb1a
-0, 1284000, 1284000, 0, 34944, 0xef79f8ba
-0, 1290000, 1290000, 0, 34944, 0xf932f3a2
-0, 1296000, 1296000, 0, 34944, 0xa32df1bc
-0, 1302000, 1302000, 0, 34944, 0xdbe0f532
-0, 1308000, 1308000, 0, 34944, 0x234cf142
-0, 1314000, 1314000, 0, 34944, 0xe68befd0
-0, 1320000, 1320000, 0, 34944, 0xe4e7ee45
-0, 1326000, 1326000, 0, 34944, 0x0283eff1
-0, 1332000, 1332000, 0, 34944, 0xc8d3f6db
-0, 1338000, 1338000, 0, 34944, 0x0aa6ee88
-0, 1344000, 1344000, 0, 34944, 0xcc3de527
-0, 1350000, 1350000, 0, 34944, 0x9db0ebef
-0, 1356000, 1356000, 0, 34944, 0xa207e9db
-0, 1362000, 1362000, 0, 34944, 0x35b3e74a
-0, 1368000, 1368000, 0, 34944, 0x1988e848
-0, 1374000, 1374000, 0, 34944, 0x727de73c
-0, 1380000, 1380000, 0, 34944, 0x05d5e709
-0, 1386000, 1386000, 0, 34944, 0x3214e4b2
-0, 1392000, 1392000, 0, 34944, 0xed85e0a9
-0, 1398000, 1398000, 0, 34944, 0xf6c9e100
-0, 1404000, 1404000, 0, 34944, 0x57a8dbaf
-0, 1410000, 1410000, 0, 34944, 0xc75fdf41
-0, 1416000, 1416000, 0, 34944, 0x736fde24
-0, 1422000, 1422000, 0, 34944, 0x8d4bde80
-0, 1428000, 1428000, 0, 34944, 0x3220dc86
-0, 1434000, 1434000, 0, 34944, 0xe498da85
-0, 1440000, 1440000, 0, 34944, 0x0655daed
-0, 1446000, 1446000, 0, 34944, 0xb22ad874
-0, 1452000, 1452000, 0, 34944, 0x8198d411
-0, 1458000, 1458000, 0, 34944, 0xd0d2d557
-0, 1464000, 1464000, 0, 34944, 0xd740d1ff
-0, 1470000, 1470000, 0, 34944, 0x2783d00e
-0, 1476000, 1476000, 0, 34944, 0x7abdcd6b
-0, 1482000, 1482000, 0, 34944, 0x2e47d1eb
-0, 1488000, 1488000, 0, 34944, 0xfe1bcf60
-0, 1494000, 1494000, 0, 34944, 0xf0f0d5bb
-0, 1500000, 1500000, 0, 34944, 0x9af7d581
-0, 1506000, 1506000, 0, 34944, 0xb325ca3d
-0, 1512000, 1512000, 0, 34944, 0xd88abfbd
-0, 1518000, 1518000, 0, 34944, 0xf2bab746
-0, 1524000, 1524000, 0, 34944, 0xac44a7dd
-0, 1530000, 1530000, 0, 34944, 0x609e9ea3
-0, 1536000, 1536000, 0, 34944, 0xa39993b9
-0, 1542000, 1542000, 0, 34944, 0x9c948911
-0, 1548000, 1548000, 0, 34944, 0x72f8822d
-0, 1554000, 1554000, 0, 34944, 0x7f3f7a8c
-0, 1560000, 1560000, 0, 34944, 0x7ab475f9
-0, 1566000, 1566000, 0, 34944, 0x536f73aa
-0, 1572000, 1572000, 0, 34944, 0x86cb71e5
-0, 1578000, 1578000, 0, 34944, 0x17157186
-0, 1584000, 1584000, 0, 34944, 0xe33671a4
-0, 1590000, 1590000, 0, 34944, 0xe33671a4
-0, 1596000, 1596000, 0, 34944, 0xe33671a4
-0, 1602000, 1602000, 0, 34944, 0xe33671a4
-0, 1608000, 1608000, 0, 34944, 0xe33671a4
-0, 1614000, 1614000, 0, 34944, 0xe33671a4
-0, 1620000, 1620000, 0, 34944, 0xe33671a4
-0, 1626000, 1626000, 0, 34944, 0xe33671a4
-0, 1632000, 1632000, 0, 34944, 0xe33671a4
-0, 1638000, 1638000, 0, 34944, 0xe33671a4
-0, 1644000, 1644000, 0, 34944, 0xe33671a4
-0, 1650000, 1650000, 0, 34944, 0xe33671a4
-0, 1656000, 1656000, 0, 34944, 0xe33671a4
-0, 1662000, 1662000, 0, 34944, 0xe33671a4
+#tb 0: 1/15
+0, 0, 0, 1, 34944, 0xe33671a4
+0, 1, 1, 1, 34944, 0xe33671a4
+0, 2, 2, 1, 34944, 0xe33671a4
+0, 3, 3, 1, 34944, 0xe33671a4
+0, 4, 4, 1, 34944, 0xe33671a4
+0, 5, 5, 1, 34944, 0xe33671a4
+0, 6, 6, 1, 34944, 0xe33671a4
+0, 7, 7, 1, 34944, 0xe33671a4
+0, 8, 8, 1, 34944, 0xe33671a4
+0, 9, 9, 1, 34944, 0xe33671a4
+0, 10, 10, 1, 34944, 0xe33671a4
+0, 11, 11, 1, 34944, 0xe33671a4
+0, 12, 12, 1, 34944, 0xe33671a4
+0, 13, 13, 1, 34944, 0xe33671a4
+0, 14, 14, 1, 34944, 0xe33671a4
+0, 15, 15, 1, 34944, 0x63196b41
+0, 16, 16, 1, 34944, 0x308d6f10
+0, 17, 17, 1, 34944, 0x86026ced
+0, 18, 18, 1, 34944, 0xaa6a6bc9
+0, 19, 19, 1, 34944, 0x58276ee3
+0, 20, 20, 1, 34944, 0x402d70c2
+0, 21, 21, 1, 34944, 0x948d74bf
+0, 22, 22, 1, 34944, 0x3d31759c
+0, 23, 23, 1, 34944, 0x638c734e
+0, 24, 24, 1, 34944, 0xe218768a
+0, 25, 25, 1, 34944, 0xed6678ff
+0, 26, 26, 1, 34944, 0x381b7dda
+0, 27, 27, 1, 34944, 0x216680e7
+0, 28, 28, 1, 34944, 0xaca5810f
+0, 29, 29, 1, 34944, 0xf70b81eb
+0, 30, 30, 1, 34944, 0x3675858b
+0, 31, 31, 1, 34944, 0xa51188c3
+0, 32, 32, 1, 34944, 0x3a848bf1
+0, 33, 33, 1, 34944, 0x67608d4d
+0, 34, 34, 1, 34944, 0xafe49165
+0, 35, 35, 1, 34944, 0x7e8a94a7
+0, 36, 36, 1, 34944, 0x3b889432
+0, 37, 37, 1, 34944, 0x97e89623
+0, 38, 38, 1, 34944, 0x07819793
+0, 39, 39, 1, 34944, 0xdac39b87
+0, 40, 40, 1, 34944, 0x4d8c9d93
+0, 41, 41, 1, 34944, 0xcf009fa7
+0, 42, 42, 1, 34944, 0x2f109f6e
+0, 43, 43, 1, 34944, 0xcedda4eb
+0, 44, 44, 1, 34944, 0xfe89a6df
+0, 45, 45, 1, 34944, 0x195ea7a9
+0, 46, 46, 1, 34944, 0x9287ab92
+0, 47, 47, 1, 34944, 0x6d21af54
+0, 48, 48, 1, 34944, 0xd627b28b
+0, 49, 49, 1, 34944, 0x3ad5b6fd
+0, 50, 50, 1, 34944, 0x5101b64d
+0, 51, 51, 1, 34944, 0xb968b8ca
+0, 52, 52, 1, 34944, 0xa105b74a
+0, 53, 53, 1, 34944, 0xc056bdd6
+0, 54, 54, 1, 34944, 0xec7fc1d9
+0, 55, 55, 1, 34944, 0x92c3c3e0
+0, 56, 56, 1, 34944, 0x9bffc45c
+0, 57, 57, 1, 34944, 0x5aabca4b
+0, 58, 58, 1, 34944, 0xcbdacb26
+0, 59, 59, 1, 34944, 0xed6cce3f
+0, 60, 60, 1, 34944, 0xcc61cfb8
+0, 61, 61, 1, 34944, 0x7a97d427
+0, 62, 62, 1, 34944, 0x7cdbd5ec
+0, 63, 63, 1, 34944, 0x5851d9c4
+0, 64, 64, 1, 34944, 0x69d5dd1d
+0, 65, 65, 1, 34944, 0xdf30dcf4
+0, 66, 66, 1, 34944, 0x2359e084
+0, 67, 67, 1, 34944, 0xe0bae491
+0, 68, 68, 1, 34944, 0xa716e4fd
+0, 69, 69, 1, 34944, 0xe48aeaf4
+0, 70, 70, 1, 34944, 0x0a0deb21
+0, 71, 71, 1, 34944, 0xe8a56e12
+0, 72, 72, 1, 34944, 0x0d72c98e
+0, 73, 73, 1, 34944, 0x71a7bb9d
+0, 74, 74, 1, 34944, 0xc0c8c108
+0, 75, 75, 1, 34944, 0x1d1fc3ba
+0, 76, 76, 1, 34944, 0xebcfc67f
+0, 77, 77, 1, 34944, 0x2921cb5b
+0, 78, 78, 1, 34944, 0x793ed099
+0, 79, 79, 1, 34944, 0xefebd9e8
+0, 80, 80, 1, 34944, 0x163c2330
+0, 81, 81, 1, 34944, 0x35155672
+0, 82, 82, 1, 34944, 0x05474e2e
+0, 83, 83, 1, 34944, 0x9433542f
+0, 84, 84, 1, 34944, 0x777d5a13
+0, 85, 85, 1, 34944, 0x87526776
+0, 86, 86, 1, 34944, 0x4c3c72c1
+0, 87, 87, 1, 34944, 0x70407b87
+0, 88, 88, 1, 34944, 0x2358861d
+0, 89, 89, 1, 34944, 0xec61923f
+0, 90, 90, 1, 34944, 0x0bb2a0d4
+0, 91, 91, 1, 34944, 0x6b6d8624
+0, 92, 92, 1, 34944, 0x624761ec
+0, 93, 93, 1, 34944, 0xff23b926
+0, 94, 94, 1, 34944, 0x07fc7ca5
+0, 95, 95, 1, 34944, 0xa8d3ffda
+0, 96, 96, 1, 34944, 0xa2d31265
+0, 97, 97, 1, 34944, 0x5e58225e
+0, 98, 98, 1, 34944, 0x284b2fb0
+0, 99, 99, 1, 34944, 0x205b3cb1
+0, 100, 100, 1, 34944, 0x3fa64a09
+0, 101, 101, 1, 34944, 0xa5de5097
+0, 102, 102, 1, 34944, 0x00686cea
+0, 103, 103, 1, 34944, 0x465a8282
+0, 104, 104, 1, 34944, 0x4ceb8189
+0, 105, 105, 1, 34944, 0x14698509
+0, 106, 106, 1, 34944, 0x232c830d
+0, 107, 107, 1, 34944, 0x0739807c
+0, 108, 108, 1, 34944, 0x83b0861e
+0, 109, 109, 1, 34944, 0xbdc094b1
+0, 110, 110, 1, 34944, 0xc4c0a605
+0, 111, 111, 1, 34944, 0x8376b059
+0, 112, 112, 1, 34944, 0x2035b939
+0, 113, 113, 1, 34944, 0xb6bfc812
+0, 114, 114, 1, 34944, 0xc5d4d5c4
+0, 115, 115, 1, 34944, 0x492c954e
+0, 116, 116, 1, 34944, 0xd23f0dcc
+0, 117, 117, 1, 34944, 0x22d7ff6c
+0, 118, 118, 1, 34944, 0xd08b4168
+0, 119, 119, 1, 34944, 0xa82e4062
+0, 120, 120, 1, 34944, 0xcc4f2f31
+0, 121, 121, 1, 34944, 0x964b0307
+0, 122, 122, 1, 34944, 0xe8130606
+0, 123, 123, 1, 34944, 0x5fb744bf
+0, 124, 124, 1, 34944, 0x1546a88b
+0, 125, 125, 1, 34944, 0xe6e4d94d
+0, 126, 126, 1, 34944, 0x8d1ea97e
+0, 127, 127, 1, 34944, 0x3bb1fb55
+0, 128, 128, 1, 34944, 0x3c37e9cc
+0, 129, 129, 1, 34944, 0xe2d22521
+0, 130, 130, 1, 34944, 0x7c0ec8cc
+0, 131, 131, 1, 34944, 0x7c2dc956
+0, 132, 132, 1, 34944, 0x7fe3c263
+0, 133, 133, 1, 34944, 0x9a65b813
+0, 134, 134, 1, 34944, 0x7ea7cb14
+0, 135, 135, 1, 34944, 0x31ded64e
+0, 136, 136, 1, 34944, 0x50f30ad1
+0, 137, 137, 1, 34944, 0x12eac45c
+0, 138, 138, 1, 34944, 0x984b6335
+0, 139, 139, 1, 34944, 0x3b9b02f0
+0, 140, 140, 1, 34944, 0x4629d2a4
+0, 141, 141, 1, 34944, 0x38687e89
+0, 142, 142, 1, 34944, 0xb76620fe
+0, 143, 143, 1, 34944, 0x66347155
+0, 144, 144, 1, 34944, 0x6e6bc297
+0, 145, 145, 1, 34944, 0x452a653a
+0, 146, 146, 1, 34944, 0x8c8a0683
+0, 147, 147, 1, 34944, 0xaf5d7c2d
+0, 148, 148, 1, 34944, 0x3064a7e1
+0, 149, 149, 1, 34944, 0xc0657fc4
+0, 150, 150, 1, 34944, 0x1f129266
+0, 151, 151, 1, 34944, 0x35adedfb
+0, 152, 152, 1, 34944, 0x40a3db0d
+0, 153, 153, 1, 34944, 0x87bebb37
+0, 154, 154, 1, 34944, 0x04d7ffed
+0, 155, 155, 1, 34944, 0x9bde3180
+0, 156, 156, 1, 34944, 0xc35c25bd
+0, 157, 157, 1, 34944, 0x820bf4bb
+0, 158, 158, 1, 34944, 0x876163ef
+0, 159, 159, 1, 34944, 0x3ab6dac0
+0, 160, 160, 1, 34944, 0x69a9ef73
+0, 161, 161, 1, 34944, 0x0df3813c
+0, 162, 162, 1, 34944, 0x1bba0947
+0, 163, 163, 1, 34944, 0x0b7883d4
+0, 164, 164, 1, 34944, 0xa9972f7e
+0, 165, 165, 1, 34944, 0x603d08fe
+0, 166, 166, 1, 34944, 0x05f4f111
+0, 167, 167, 1, 34944, 0xb24fdb42
+0, 168, 168, 1, 34944, 0xfe2ad344
+0, 169, 169, 1, 34944, 0xda4bcb8f
+0, 170, 170, 1, 34944, 0xd28aca6b
+0, 171, 171, 1, 34944, 0x9486c260
+0, 172, 172, 1, 34944, 0xad9fc04d
+0, 173, 173, 1, 34944, 0x9333c0ca
+0, 174, 174, 1, 34944, 0x96e9c226
+0, 175, 175, 1, 34944, 0x3e89bd6f
+0, 176, 176, 1, 34944, 0x7a2dbd32
+0, 177, 177, 1, 34944, 0xe578ba53
+0, 178, 178, 1, 34944, 0xb77ebab1
+0, 179, 179, 1, 34944, 0xd8bfbcb1
+0, 180, 180, 1, 34944, 0x15d9bc97
+0, 181, 181, 1, 34944, 0x09c3b9f0
+0, 182, 182, 1, 34944, 0xd8c8b944
+0, 183, 183, 1, 34944, 0x2c2fb996
+0, 184, 184, 1, 34944, 0xd7a8b7e7
+0, 185, 185, 1, 34944, 0xce34b843
+0, 186, 186, 1, 34944, 0xba69e9fd
+0, 187, 187, 1, 34944, 0x1b3f1adc
+0, 188, 188, 1, 34944, 0x48f515aa
+0, 189, 189, 1, 34944, 0x864e12bb
+0, 190, 190, 1, 34944, 0xca571996
+0, 191, 191, 1, 34944, 0x1d5a1af0
+0, 192, 192, 1, 34944, 0x3d1e171f
+0, 193, 193, 1, 34944, 0xb57417ca
+0, 194, 194, 1, 34944, 0x6e6d1e9d
+0, 195, 195, 1, 34944, 0xc9971899
+0, 196, 196, 1, 34944, 0xe0b112c8
+0, 197, 197, 1, 34944, 0x121b0cd9
+0, 198, 198, 1, 34944, 0x418e0eff
+0, 199, 199, 1, 34944, 0x9e1b07d8
+0, 200, 200, 1, 34944, 0x5590064a
+0, 201, 201, 1, 34944, 0x7a170b14
+0, 202, 202, 1, 34944, 0xf25709f0
+0, 203, 203, 1, 34944, 0x94fa099a
+0, 204, 204, 1, 34944, 0x081e06ae
+0, 205, 205, 1, 34944, 0xcfc40417
+0, 206, 206, 1, 34944, 0xed33096f
+0, 207, 207, 1, 34944, 0xd73a07e2
+0, 208, 208, 1, 34944, 0xc512077d
+0, 209, 209, 1, 34944, 0x27d7021d
+0, 210, 210, 1, 34944, 0xab59fd20
+0, 211, 211, 1, 34944, 0xcc2400b7
+0, 212, 212, 1, 34944, 0xcb3bfb99
+0, 213, 213, 1, 34944, 0x0974fb1a
+0, 214, 214, 1, 34944, 0xef79f8ba
+0, 215, 215, 1, 34944, 0xf932f3a2
+0, 216, 216, 1, 34944, 0xa32df1bc
+0, 217, 217, 1, 34944, 0xdbe0f532
+0, 218, 218, 1, 34944, 0x234cf142
+0, 219, 219, 1, 34944, 0xe68befd0
+0, 220, 220, 1, 34944, 0xe4e7ee45
+0, 221, 221, 1, 34944, 0x0283eff1
+0, 222, 222, 1, 34944, 0xc8d3f6db
+0, 223, 223, 1, 34944, 0x0aa6ee88
+0, 224, 224, 1, 34944, 0xcc3de527
+0, 225, 225, 1, 34944, 0x9db0ebef
+0, 226, 226, 1, 34944, 0xa207e9db
+0, 227, 227, 1, 34944, 0x35b3e74a
+0, 228, 228, 1, 34944, 0x1988e848
+0, 229, 229, 1, 34944, 0x727de73c
+0, 230, 230, 1, 34944, 0x05d5e709
+0, 231, 231, 1, 34944, 0x3214e4b2
+0, 232, 232, 1, 34944, 0xed85e0a9
+0, 233, 233, 1, 34944, 0xf6c9e100
+0, 234, 234, 1, 34944, 0x57a8dbaf
+0, 235, 235, 1, 34944, 0xc75fdf41
+0, 236, 236, 1, 34944, 0x736fde24
+0, 237, 237, 1, 34944, 0x8d4bde80
+0, 238, 238, 1, 34944, 0x3220dc86
+0, 239, 239, 1, 34944, 0xe498da85
+0, 240, 240, 1, 34944, 0x0655daed
+0, 241, 241, 1, 34944, 0xb22ad874
+0, 242, 242, 1, 34944, 0x8198d411
+0, 243, 243, 1, 34944, 0xd0d2d557
+0, 244, 244, 1, 34944, 0xd740d1ff
+0, 245, 245, 1, 34944, 0x2783d00e
+0, 246, 246, 1, 34944, 0x7abdcd6b
+0, 247, 247, 1, 34944, 0x2e47d1eb
+0, 248, 248, 1, 34944, 0xfe1bcf60
+0, 249, 249, 1, 34944, 0xf0f0d5bb
+0, 250, 250, 1, 34944, 0x9af7d581
+0, 251, 251, 1, 34944, 0xb325ca3d
+0, 252, 252, 1, 34944, 0xd88abfbd
+0, 253, 253, 1, 34944, 0xf2bab746
+0, 254, 254, 1, 34944, 0xac44a7dd
+0, 255, 255, 1, 34944, 0x609e9ea3
+0, 256, 256, 1, 34944, 0xa39993b9
+0, 257, 257, 1, 34944, 0x9c948911
+0, 258, 258, 1, 34944, 0x72f8822d
+0, 259, 259, 1, 34944, 0x7f3f7a8c
+0, 260, 260, 1, 34944, 0x7ab475f9
+0, 261, 261, 1, 34944, 0x536f73aa
+0, 262, 262, 1, 34944, 0x86cb71e5
+0, 263, 263, 1, 34944, 0x17157186
+0, 264, 264, 1, 34944, 0xe33671a4
+0, 265, 265, 1, 34944, 0xe33671a4
+0, 266, 266, 1, 34944, 0xe33671a4
+0, 267, 267, 1, 34944, 0xe33671a4
+0, 268, 268, 1, 34944, 0xe33671a4
+0, 269, 269, 1, 34944, 0xe33671a4
+0, 270, 270, 1, 34944, 0xe33671a4
+0, 271, 271, 1, 34944, 0xe33671a4
+0, 272, 272, 1, 34944, 0xe33671a4
+0, 273, 273, 1, 34944, 0xe33671a4
+0, 274, 274, 1, 34944, 0xe33671a4
+0, 275, 275, 1, 34944, 0xe33671a4
+0, 276, 276, 1, 34944, 0xe33671a4
+0, 277, 277, 1, 34944, 0xe33671a4
diff --git a/tests/ref/fate/ea-tqi b/tests/ref/fate/ea-tqi
index ba0073b..72afb81 100644
--- a/tests/ref/fate/ea-tqi
+++ b/tests/ref/fate/ea-tqi
@@ -1,27 +1,27 @@
-#tb 0: 1/90000
-0, 0, 0, 0, 115200, 0x375ec573
-0, 6000, 6000, 0, 115200, 0x375ec573
-0, 12000, 12000, 0, 115200, 0x375ec573
-0, 18000, 18000, 0, 115200, 0x375ec573
-0, 24000, 24000, 0, 115200, 0x375ec573
-0, 30000, 30000, 0, 115200, 0x375ec573
-0, 36000, 36000, 0, 115200, 0x375ec573
-0, 42000, 42000, 0, 115200, 0x375ec573
-0, 48000, 48000, 0, 115200, 0x0b4d31bf
-0, 54000, 54000, 0, 115200, 0xdd724598
-0, 60000, 60000, 0, 115200, 0xc3077e75
-0, 66000, 66000, 0, 115200, 0xbf70778a
-0, 72000, 72000, 0, 115200, 0x117eb766
-0, 78000, 78000, 0, 115200, 0x4617fbad
-0, 84000, 84000, 0, 115200, 0x5f5b02d2
-0, 90000, 90000, 0, 115200, 0x2a9c5325
-0, 96000, 96000, 0, 115200, 0x14a89e2a
-0, 102000, 102000, 0, 115200, 0xe69aa994
-0, 108000, 108000, 0, 115200, 0xfbacf589
-0, 114000, 114000, 0, 115200, 0x1d714c6e
-0, 120000, 120000, 0, 115200, 0x6eff66cb
-0, 126000, 126000, 0, 115200, 0xee21c1cb
-0, 132000, 132000, 0, 115200, 0xce714ada
-0, 138000, 138000, 0, 115200, 0xf89d56c3
-0, 144000, 144000, 0, 115200, 0x65fd5e60
-0, 150000, 150000, 0, 115200, 0x0c256424
+#tb 0: 1/15
+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
+0, 5, 5, 1, 115200, 0x375ec573
+0, 6, 6, 1, 115200, 0x375ec573
+0, 7, 7, 1, 115200, 0x375ec573
+0, 8, 8, 1, 115200, 0x0b4d31bf
+0, 9, 9, 1, 115200, 0xdd724598
+0, 10, 10, 1, 115200, 0xc3077e75
+0, 11, 11, 1, 115200, 0xbf70778a
+0, 12, 12, 1, 115200, 0x117eb766
+0, 13, 13, 1, 115200, 0x4617fbad
+0, 14, 14, 1, 115200, 0x5f5b02d2
+0, 15, 15, 1, 115200, 0x2a9c5325
+0, 16, 16, 1, 115200, 0x14a89e2a
+0, 17, 17, 1, 115200, 0xe69aa994
+0, 18, 18, 1, 115200, 0xfbacf589
+0, 19, 19, 1, 115200, 0x1d714c6e
+0, 20, 20, 1, 115200, 0x6eff66cb
+0, 21, 21, 1, 115200, 0xee21c1cb
+0, 22, 22, 1, 115200, 0xce714ada
+0, 23, 23, 1, 115200, 0xf89d56c3
+0, 24, 24, 1, 115200, 0x65fd5e60
+0, 25, 25, 1, 115200, 0x0c256424
diff --git a/tests/ref/fate/eval b/tests/ref/fate/eval
index b01e5a5..97e0b20 100644
--- a/tests/ref/fate/eval
+++ b/tests/ref/fate/eval
@@ -190,5 +190,83 @@ 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
+
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..4109c15
--- a/dev/null
+++ b/tests/ref/fate/exif-image-embedded
@@ -0,0 +1,360 @@
+[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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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..b579442
--- a/dev/null
+++ b/tests/ref/fate/exif-image-jpg
@@ -0,0 +1,224 @@
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=0
+pkt_pts_time=0.000000
+pkt_dts=0
+pkt_dts_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..16c06c2
--- a/dev/null
+++ b/tests/ref/fate/exif-image-tiff
@@ -0,0 +1,25 @@
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=0
+pkt_pts_time=0.000000
+pkt_dts=0
+pkt_dts_time=0.000000
+pkt_duration=1
+pkt_duration_time=0.040000
+pkt_pos=N/A
+pkt_size=67604
+width=200
+height=112
+pix_fmt=rgb24
+sample_aspect_ratio=N/A
+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/exr-slice-pxr24 b/tests/ref/fate/exr-slice-pxr24
new file mode 100644
index 0000000..c46e897
--- a/dev/null
+++ b/tests/ref/fate/exr-slice-pxr24
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3840000, 0xdcfb341d
diff --git a/tests/ref/fate/exr-slice-raw b/tests/ref/fate/exr-slice-raw
new file mode 100644
index 0000000..a8b4b27
--- a/dev/null
+++ b/tests/ref/fate/exr-slice-raw
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3169800, 0x6a356d0d
diff --git a/tests/ref/fate/exr-slice-rle b/tests/ref/fate/exr-slice-rle
new file mode 100644
index 0000000..a8b4b27
--- a/dev/null
+++ b/tests/ref/fate/exr-slice-rle
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3169800, 0x6a356d0d
diff --git a/tests/ref/fate/exr-slice-zip1 b/tests/ref/fate/exr-slice-zip1
new file mode 100644
index 0000000..a8b4b27
--- a/dev/null
+++ b/tests/ref/fate/exr-slice-zip1
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3169800, 0x6a356d0d
diff --git a/tests/ref/fate/exr-slice-zip16 b/tests/ref/fate/exr-slice-zip16
new file mode 100644
index 0000000..a8b4b27
--- a/dev/null
+++ b/tests/ref/fate/exr-slice-zip16
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3169800, 0x6a356d0d
diff --git a/tests/ref/fate/ffmpeg-filter_complex b/tests/ref/fate/ffmpeg-filter_complex
new file mode 100644
index 0000000..54d318d
--- a/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
--- a/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..eb82edb
--- a/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=572|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|pkt_duration=1024|pkt_duration_time=0.023220|pkt_pos=572|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=2647|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|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=2647|pkt_size=N/A|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=233068|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|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=233068|pkt_size=N/A|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=263073|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|pkt_duration=1024|pkt_duration_time=0.023220|pkt_pos=263073|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=265151|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|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=265151|pkt_size=N/A|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=495575|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|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=495575|pkt_size=N/A|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=525580|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|pkt_duration=1024|pkt_duration_time=0.023220|pkt_pos=525580|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=527651|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|pkt_duration=1024|pkt_duration_time=0.023220|pkt_pos=527651|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=529729|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|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=529729|pkt_size=N/A|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=760153|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|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=760153|pkt_size=N/A|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=790158|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|pkt_duration=1024|pkt_duration_time=0.023220|pkt_pos=790158|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=792229|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|pkt_duration=1024|pkt_duration_time=0.023220|pkt_pos=792229|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=794307|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|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=794307|pkt_size=N/A|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=1024731|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|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=1024731|pkt_size=N/A|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|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²
+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|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|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
+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|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|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
+format|filename=tests/data/ffprobe-test.nut|nb_streams=3|nb_programs=0|format_name=nut|start_time=0.000000|duration=0.120000|size=1054812|bit_rate=70320800|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..10d1bf1
--- a/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,572,K
+frame,audio,1,0,0.000000,0,0.000000,1024,0.023220,572,2048,s16,1024,1,unknown
+packet,video,1,0,0.000000,0,0.000000,2048,0.040000,N/A,N/A,230400,2647,K
+frame,video,1,0,0.000000,0,0.000000,2048,0.040000,2647,N/A,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,233068,K
+frame,video,1,0,0.000000,0,0.000000,2048,0.040000,233068,N/A,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,263073,K
+frame,audio,1,1024,0.023220,1024,0.023220,1024,0.023220,263073,2048,s16,1024,1,unknown
+packet,video,1,2048,0.040000,2048,0.040000,2048,0.040000,N/A,N/A,230400,265151,K
+frame,video,1,2048,0.040000,2048,0.040000,2048,0.040000,265151,N/A,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,495575,K
+frame,video,1,2048,0.040000,2048,0.040000,2048,0.040000,495575,N/A,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,525580,K
+frame,audio,1,2048,0.046440,2048,0.046440,1024,0.023220,525580,2048,s16,1024,1,unknown
+packet,audio,0,3072,0.069660,3072,0.069660,1024,0.023220,N/A,N/A,2048,527651,K
+frame,audio,1,3072,0.069660,3072,0.069660,1024,0.023220,527651,2048,s16,1024,1,unknown
+packet,video,1,4096,0.080000,4096,0.080000,2048,0.040000,N/A,N/A,230400,529729,K
+frame,video,1,4096,0.080000,4096,0.080000,2048,0.040000,529729,N/A,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,760153,K
+frame,video,1,4096,0.080000,4096,0.080000,2048,0.040000,760153,N/A,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,790158,K
+frame,audio,1,4096,0.092880,4096,0.092880,1024,0.023220,790158,2048,s16,1024,1,unknown
+packet,audio,0,5120,0.116100,5120,0.116100,1024,0.023220,N/A,N/A,2048,792229,K
+frame,audio,1,5120,0.116100,5120,0.116100,1024,0.023220,792229,2048,s16,1024,1,unknown
+packet,video,1,6144,0.120000,6144,0.120000,2048,0.040000,N/A,N/A,230400,794307,K
+frame,video,1,6144,0.120000,6144,0.120000,2048,0.040000,794307,N/A,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,1024731,K
+frame,video,1,6144,0.120000,6144,0.120000,2048,0.040000,1024731,N/A,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,6,6,0,0,0,0,0,0,0,0,0,0,0,mc²
+stream,1,rawvideo,unknown,video,1/51200,RGB[24],0x18424752,320,240,0,1:1,4:3,rgb24,-99,N/A,N/A,25/1,25/1,1/51200,0,0.000000,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
+stream,2,rawvideo,unknown,video,1/51200,RGB[24],0x18424752,100,100,0,1:1,1:1,rgb24,-99,N/A,N/A,25/1,25/1,1/51200,0,0.000000,N/A,N/A,N/A,N/A,4,4,0,0,0,0,0,0,0,0,0,0,0
+format,tests/data/ffprobe-test.nut,3,0,nut,0.000000,0.120000,1054812,70320800,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..c6d9b28
--- a/dev/null
+++ b/tests/ref/fate/ffprobe_default
@@ -0,0 +1,616 @@
+[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=572
+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
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=572
+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=2647
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=2647
+pkt_size=N/A
+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=233068
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=233068
+pkt_size=N/A
+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=263073
+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
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=263073
+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=265151
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=265151
+pkt_size=N/A
+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=495575
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=495575
+pkt_size=N/A
+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=525580
+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
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=525580
+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=527651
+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
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=527651
+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=529729
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=529729
+pkt_size=N/A
+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=760153
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=760153
+pkt_size=N/A
+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=790158
+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
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=790158
+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=792229
+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
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=792229
+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=794307
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=794307
+pkt_size=N/A
+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=1024731
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=1024731
+pkt_size=N/A
+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
+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²
+[/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
+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
+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
+[/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
+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
+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
+[/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=1054812
+bit_rate=70320800
+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..ae280b7
--- a/dev/null
+++ b/tests/ref/fate/ffprobe_flat
@@ -0,0 +1,552 @@
+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="572"
+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.pkt_duration=1024
+packets_and_frames.frame.0.pkt_duration_time="0.023220"
+packets_and_frames.frame.0.pkt_pos="572"
+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="2647"
+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.pkt_duration=2048
+packets_and_frames.frame.1.pkt_duration_time="0.040000"
+packets_and_frames.frame.1.pkt_pos="2647"
+packets_and_frames.frame.1.pkt_size="N/A"
+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="233068"
+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.pkt_duration=2048
+packets_and_frames.frame.2.pkt_duration_time="0.040000"
+packets_and_frames.frame.2.pkt_pos="233068"
+packets_and_frames.frame.2.pkt_size="N/A"
+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="263073"
+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.pkt_duration=1024
+packets_and_frames.frame.3.pkt_duration_time="0.023220"
+packets_and_frames.frame.3.pkt_pos="263073"
+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="265151"
+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.pkt_duration=2048
+packets_and_frames.frame.4.pkt_duration_time="0.040000"
+packets_and_frames.frame.4.pkt_pos="265151"
+packets_and_frames.frame.4.pkt_size="N/A"
+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="495575"
+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.pkt_duration=2048
+packets_and_frames.frame.5.pkt_duration_time="0.040000"
+packets_and_frames.frame.5.pkt_pos="495575"
+packets_and_frames.frame.5.pkt_size="N/A"
+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="525580"
+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.pkt_duration=1024
+packets_and_frames.frame.6.pkt_duration_time="0.023220"
+packets_and_frames.frame.6.pkt_pos="525580"
+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="527651"
+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.pkt_duration=1024
+packets_and_frames.frame.7.pkt_duration_time="0.023220"
+packets_and_frames.frame.7.pkt_pos="527651"
+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="529729"
+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.pkt_duration=2048
+packets_and_frames.frame.8.pkt_duration_time="0.040000"
+packets_and_frames.frame.8.pkt_pos="529729"
+packets_and_frames.frame.8.pkt_size="N/A"
+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="760153"
+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.pkt_duration=2048
+packets_and_frames.frame.9.pkt_duration_time="0.040000"
+packets_and_frames.frame.9.pkt_pos="760153"
+packets_and_frames.frame.9.pkt_size="N/A"
+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="790158"
+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.pkt_duration=1024
+packets_and_frames.frame.10.pkt_duration_time="0.023220"
+packets_and_frames.frame.10.pkt_pos="790158"
+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="792229"
+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.pkt_duration=1024
+packets_and_frames.frame.11.pkt_duration_time="0.023220"
+packets_and_frames.frame.11.pkt_pos="792229"
+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="794307"
+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.pkt_duration=2048
+packets_and_frames.frame.12.pkt_duration_time="0.040000"
+packets_and_frames.frame.12.pkt_pos="794307"
+packets_and_frames.frame.12.pkt_size="N/A"
+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="1024731"
+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.pkt_duration=2048
+packets_and_frames.frame.13.pkt_duration_time="0.040000"
+packets_and_frames.frame.13.pkt_pos="1024731"
+packets_and_frames.frame.13.pkt_size="N/A"
+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.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.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.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.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.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.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.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
+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="1054812"
+format.bit_rate="70320800"
+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..c47a0c4
--- a/dev/null
+++ b/tests/ref/fate/ffprobe_ini
@@ -0,0 +1,629 @@
+# 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=572
+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
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=572
+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=2647
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=2647
+pkt_size=N/A
+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=233068
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=233068
+pkt_size=N/A
+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=263073
+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
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=263073
+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=265151
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=265151
+pkt_size=N/A
+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=495575
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=495575
+pkt_size=N/A
+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=525580
+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
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=525580
+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=527651
+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
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=527651
+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=529729
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=529729
+pkt_size=N/A
+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=760153
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=760153
+pkt_size=N/A
+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=790158
+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
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=790158
+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=792229
+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
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=792229
+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=794307
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=794307
+pkt_size=N/A
+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=1024731
+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
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=1024731
+pkt_size=N/A
+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
+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²
+
+[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
+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
+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
+
+[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
+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
+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
+
+[format]
+filename=tests/data/ffprobe-test.nut
+nb_streams=3
+nb_programs=0
+format_name=nut
+start_time=0.000000
+duration=0.120000
+size=1054812
+bit_rate=70320800
+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..f0bdb19
--- a/dev/null
+++ b/tests/ref/fate/ffprobe_json
@@ -0,0 +1,600 @@
+{
+ "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": "572",
+ "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",
+ "pkt_duration": 1024,
+ "pkt_duration_time": "0.023220",
+ "pkt_pos": "572",
+ "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": "2647",
+ "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",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "2647",
+ "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": "233068",
+ "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",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "233068",
+ "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": "263073",
+ "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",
+ "pkt_duration": 1024,
+ "pkt_duration_time": "0.023220",
+ "pkt_pos": "263073",
+ "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": "265151",
+ "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",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "265151",
+ "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": "495575",
+ "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",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "495575",
+ "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": "525580",
+ "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",
+ "pkt_duration": 1024,
+ "pkt_duration_time": "0.023220",
+ "pkt_pos": "525580",
+ "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": "527651",
+ "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",
+ "pkt_duration": 1024,
+ "pkt_duration_time": "0.023220",
+ "pkt_pos": "527651",
+ "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": "529729",
+ "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",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "529729",
+ "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": "760153",
+ "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",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "760153",
+ "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": "790158",
+ "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",
+ "pkt_duration": 1024,
+ "pkt_duration_time": "0.023220",
+ "pkt_pos": "790158",
+ "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": "792229",
+ "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",
+ "pkt_duration": 1024,
+ "pkt_duration_time": "0.023220",
+ "pkt_pos": "792229",
+ "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": "794307",
+ "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",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "794307",
+ "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": "1024731",
+ "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",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "1024731",
+ "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²"
+ }
+ },
+ {
+ "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"
+ }
+ },
+ {
+ "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
+ }
+ }
+ ],
+ "format": {
+ "filename": "tests/data/ffprobe-test.nut",
+ "nb_streams": 3,
+ "nb_programs": 0,
+ "format_name": "nut",
+ "start_time": "0.000000",
+ "duration": "0.120000",
+ "size": "1054812",
+ "bit_rate": "70320800",
+ "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..0abca38
--- a/dev/null
+++ b/tests/ref/fate/ffprobe_xml
@@ -0,0 +1,54 @@
+<?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="572" 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" pkt_duration="1024" pkt_duration_time="0.023220" pkt_pos="572" 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="2647" 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" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="2647" 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="233068" 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" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="233068" 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="263073" 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" pkt_duration="1024" pkt_duration_time="0.023220" pkt_pos="263073" 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="265151" 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" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="265151" 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="495575" 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" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="495575" 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="525580" 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" pkt_duration="1024" pkt_duration_time="0.023220" pkt_pos="525580" 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="527651" 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" pkt_duration="1024" pkt_duration_time="0.023220" pkt_pos="527651" 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="529729" 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" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="529729" 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="760153" 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" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="760153" 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="790158" 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" pkt_duration="1024" pkt_duration_time="0.023220" pkt_pos="790158" 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="792229" 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" pkt_duration="1024" pkt_duration_time="0.023220" pkt_pos="792229" 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="794307" 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" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="794307" 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="1024731" 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" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="1024731" 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²"/>
+ </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"/>
+ </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"/>
+ </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="1054812" bit_rate="70320800" probe_score="100">
+ <tag key="title" value="ffprobe test file"/>
+ <tag key="comment" value="&apos;A comment with CSV, XML &amp; JSON special chars&apos;: &lt;tag value=&quot;x&quot;&gt;"/>
+ <tag key="comment2" value="I ♥ ĂœĂ±Ă®Ă§Ă¸d€"/>
+ </format>
+</ffprobe>
diff --git a/tests/ref/fate/film-cvid b/tests/ref/fate/film-cvid
index 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-adelay b/tests/ref/fate/filter-adelay
new file mode 100644
index 0000000..ac1c584
--- a/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
--- a/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
--- a/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-colorchannelmixer b/tests/ref/fate/filter-colorchannelmixer
new file mode 100644
index 0000000..4e9e9d3
--- a/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..9ec093d
--- a/dev/null
+++ b/tests/ref/fate/filter-colormatrix1
@@ -0,0 +1 @@
+colormatrix1 600fef16b66cff4ee76540ff2a8f4480
diff --git a/tests/ref/fate/filter-colormatrix2 b/tests/ref/fate/filter-colormatrix2
new file mode 100644
index 0000000..9961bae
--- a/dev/null
+++ b/tests/ref/fate/filter-colormatrix2
@@ -0,0 +1 @@
+colormatrix2 e4ba95b7dd5e0862aa5f5e3ddc54bda4
diff --git a/tests/ref/fate/filter-concat b/tests/ref/fate/filter-concat
new file mode 100644
index 0000000..73e4185
--- a/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..dec7f29 100644
--- a/tests/ref/fate/filter-crop
+++ b/tests/ref/fate/filter-crop
@@ -1 +1 @@
-crop 3d163f156eaddf41d2be20736f973539
+crop f7b5236ddf88224188051c7c43503a14
diff --git a/tests/ref/fate/filter-crop_scale b/tests/ref/fate/filter-crop_scale
index 82e5394..e692a8a 100644
--- a/tests/ref/fate/filter-crop_scale
+++ b/tests/ref/fate/filter-crop_scale
@@ -1 +1 @@
-crop_scale 0a3d45d58b805b8c47416b9239535f94
+crop_scale c298d61e731a97d0a9600e7fde80b6b4
diff --git a/tests/ref/fate/filter-crop_scale_vflip b/tests/ref/fate/filter-crop_scale_vflip
index 29574f7..9a7d326 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 56b8204e72d0680b139a8d9dd756e332
diff --git a/tests/ref/fate/filter-crop_vflip b/tests/ref/fate/filter-crop_vflip
index a3f8200..d6d6bad 100644
--- a/tests/ref/fate/filter-crop_vflip
+++ b/tests/ref/fate/filter-crop_vflip
@@ -1 +1 @@
-crop_vflip 628542e17b6900ee79b1429183ae01b0
+crop_vflip 8368eb12fa29acc5826bade961257375
diff --git a/tests/ref/fate/filter-curves b/tests/ref/fate/filter-curves
new file mode 100644
index 0000000..a96f0ee
--- a/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..5044eed
--- a/dev/null
+++ b/tests/ref/fate/filter-edgedetect
@@ -0,0 +1 @@
+edgedetect 9d67cf98d604f5dbde6f20a88664c683
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-gradfun-sample b/tests/ref/fate/filter-gradfun-sample
new file mode 100644
index 0000000..595f82a
--- a/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
--- a/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
--- a/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-hqdn3d-sample b/tests/ref/fate/filter-hqdn3d-sample
new file mode 100644
index 0000000..97718f9
--- a/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..ab412a7
--- a/dev/null
+++ b/tests/ref/fate/filter-hue
@@ -0,0 +1 @@
+hue faddb090f2eefa663b9539fd67451352
diff --git a/tests/ref/fate/filter-idet b/tests/ref/fate/filter-idet
new file mode 100644
index 0000000..2c6c2ae
--- a/dev/null
+++ b/tests/ref/fate/filter-idet
@@ -0,0 +1 @@
+idet 1077e3cb6fc4916b5441dd08cea4c9a8
diff --git a/tests/ref/fate/filter-lavd-life b/tests/ref/fate/filter-lavd-life
new file mode 100644
index 0000000..565f88a
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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..67251df
--- a/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.880000
+pkt_pts=5800|tag:lavfi.scene_score=1.000000
+pkt_pts=6720|tag:lavfi.scene_score=0.460000
+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.840000
+pkt_pts=15700|tag:lavfi.scene_score=1.000000
+pkt_pts=18500|tag:lavfi.scene_score=0.470000
+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
--- a/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..0b9b9b8 100644
--- a/tests/ref/fate/filter-null
+++ b/tests/ref/fate/filter-null
@@ -1 +1 @@
-null eba2f135a08829387e2f698ff72a2939
+null 61fffd2d8425759a33ae07e718d0242d
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
--- a/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
--- a/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_yuv444 b/tests/ref/fate/filter-overlay_yuv444
new file mode 100644
index 0000000..0b2d9f7
--- a/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..7a6f61e
--- a/dev/null
+++ b/tests/ref/fate/filter-pad
@@ -0,0 +1 @@
+pad 8122d716097523d0875e2d55b0926105
diff --git a/tests/ref/fate/filter-phase b/tests/ref/fate/filter-phase
new file mode 100644
index 0000000..e0ec8d6
--- a/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 b/tests/ref/fate/filter-pixdesc
index 23452ae..56373fb 100644
--- a/tests/ref/fate/filter-pixdesc
+++ b/tests/ref/fate/filter-pixdesc
@@ -1,89 +1,115 @@
-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
+0bgr 2b46a6ce47a19ffc240e4e93f498f491
+0rgb e90e5d377a3e5af69fdf7b60cbf88f51
+abgr 1a147fa04ed70b9a7e67a4c89052f630
+argb 997df0b5c268a0d8f9c611cae4e01e05
+bgr0 b61591a68252e66c576b9bb074a9eaed
+bgr24 d6370f6dc34df2ea66e1718baf74137b
+bgr444be aba6dfea008ae12c2120a95f54293904
+bgr444le cfb5401e8f076cc8675e17ed1114a3df
+bgr48be ab65229b64606f6408cd732b967c0b01
+bgr48le f1b4e718cadee9bd2978289153ce43de
+bgr4_byte de96505ef9ad7078f87b4dfdf6fe4b61
+bgr555be 8d5de9e9200d622f27dc73958a85045c
+bgr555le 74eb9837706143a40e26305a16a79369
+bgr565be 13a36d6502be88fc0c2aec05b8d2d501
+bgr565le ed027571692aecd522aa65a90cc7e09b
+bgr8 71ef789609c746c2e7e4be9dec29062c
+bgra 0364b074268682ea46168742a8239f7d
+gbrap 412a2449fdfaeb5ebdf5e4196cc7391a
+gbrp 4778f8cc2bdbcd65e272ea1761cdca6d
+gbrp10be 0be11fe4b2324054be6f949e81966691
+gbrp10le 173f89ae58fd4d01d6a365318e4da3b1
+gbrp12be 1f5231ed7e4589a3ec98fa79134bdc6a
+gbrp12le cc4830a263fecadeea535c4938b5cee1
+gbrp14be 6f5143374536e1cf1595260e91c86b7b
+gbrp14le 937ff1dd9f498b39f9e882316e371fbf
+gbrp9be c76ab5850c9bc72bbbf36caa6d1c5ac7
+gbrp9le 5ad363dc9570187ad3e3f2344fbb30cf
+gray 2ee2ea2340d0ecf2dfa6f90f87384799
+gray16be 389f4e5a8ab413b3af32767b59ed7f9e
+gray16le a1f912941247e45b394b9cf4f0e81130
+monob 309b5785a36bd988d17e15d88f4ffad1
+monow 8809a02bc69b58d1114b09ca79ebffad
+nv12 75e90c54d858b993e99f4ee6d2a2a38f
+nv21 8831a3f411015d45fbc5dd191245ba9c
+rgb0 5774780b3c532896300fa326fcde01a8
+rgb24 c71ba90f69f15c8275232bb3f62d0ced
+rgb444be 26eaec65d7efd2b0c9c13b47dfd9b241
+rgb444le 5f29863553107110ea817f52151d77b7
+rgb48be a3bc81c46c21818a989f23104a599ab0
+rgb48le e87c661ac49aea1f1e93939802883d92
+rgb4_byte 293b1b84f01efd90bde40cb3faffc127
+rgb555be 5229183fa64d4e5c7e3703d8263ee6ae
+rgb555le c3e9978cb2a4129a5575935e8cbc433a
+rgb565be bc123b962629ead1a06af0c18cbb6e5f
+rgb565le 20757fafe4756e62d845b2ab4c0b8f93
+rgb8 e01614f5416dcc8ad365ad7a57afc9fb
+rgba 53796fa4c392a1b2659595b6a284f8c4
+rgba64be c05fbb1ada1b48fb1eb192fc200af2b6
+rgba64le 1b826cc613666f545274e8a7799d69f1
+uyvy422 3f411f947e3ac8f842c88e717d68bd9a
+xyz12be 71f608adceed8e8997aa463203b1a648
+xyz12le dc524e3726ba1df0d2f406db3a2c08aa
+yuv410p 7dcf3f4770c8b494290ceacd2c2ce6db
+yuv411p 9461b188dab6f8b90d9a27e353a89f58
+yuv420p 61fffd2d8425759a33ae07e718d0242d
+yuv420p10be 2abf90242cb021cb6fcf9f2c3c92f6a7
+yuv420p10le 180b7e4de684c7225d2fb37614f842cb
+yuv420p12be 256c9e6cfc878a8abf681b30777c0620
+yuv420p12le 8dc8b86c4790da3769d4a62e87608623
+yuv420p14be 8d22756c5d2b9e501924c082bfb22a6c
+yuv420p14le c9da19d4818bcb119ad6481b75778f7e
+yuv420p16be 4ccdcca6dd6a960f9a3333f0aee095bd
+yuv420p16le 9c5847d9b0de258a10ee906dc47e24ea
+yuv420p9be fa7ad4f73232aac0e35def62af1e2c39
+yuv420p9le 3720ba1786b56c8f4913e67dddebbb07
+yuv422p eee223e92f1f2e5ad4186b411ebf5816
+yuv422p10be 80fa87750491dcc3e93d175b64835654
+yuv422p10le e1640cd315bd96c6b59f7753825a7306
+yuv422p12be 5c6d86e919515d1af71f8004a6252f9e
+yuv422p12le 7f331cadb0ab75d07656d29f47bd8bd9
+yuv422p14be 4f4e186ba683b90fe990cccc4db7e521
+yuv422p14le d78016c9119b1f1d1c922bd5aaf47732
+yuv422p16be 1f3c216927d17966a009a42def124bba
+yuv422p16le 90adbdffaeea9b09398339c8a1322b02
+yuv422p9be e46446534dd0821029d3b831c9c1d1b0
+yuv422p9le 520e418a2429f7efee511b7fcbf45ab6
+yuv440p 456d83524b299f2fa1bb988e421554d9
+yuv444p 068bc09d282d18c9fa35c2787943fc2a
+yuv444p10be 9f6e1490080a454243daee9229425e1e
+yuv444p10le cc183e51041351d9ac06c4df6e8ad5f7
+yuv444p12be 34f63ac6a47ac681016105d3bfb3e118
+yuv444p12le 7964701bfe8d718edf97f6e0002935bd
+yuv444p14be 4ad3a9d52fe9c050150c0f7d2f3cf63d
+yuv444p14le 69575e5a94b978f159c4fdb1a61587b0
+yuv444p16be 4000b12fa88ed0feef182da31c7e6b96
+yuv444p16le 96a857dba8dc6792c58daec872825b32
+yuv444p9be 07727e5c9040b7f0a17d591288ac330d
+yuv444p9le 4d12d20a68dc28618594c96c2ade4ff4
+yuva420p 3a8c5c142e051367c196f95696e0e2c3
+yuva420p10be 1b7c5ec6691498e24676ce6ed97f62f8
+yuva420p10le 4c13322bca914df2727da91cca85ca1a
+yuva420p16be 6afcf758f4b66c0b4173c942d42212d7
+yuva420p16le 13e195aa96329eb49921b6f9f07b875c
+yuva420p9be 05a78390de312dfd21ac666a9da05fbd
+yuva420p9le 78f5593bf51a31841ef83df41d0316eb
+yuva422p 45ae66d6f69fd5b77e6831e98d228bf4
+yuva422p10be 18284c58b926fe2389605c692a703145
+yuva422p10le b934d28b615729a24bebf0381c465e37
+yuva422p16be c3f7354b6013b43439e02aa02be5fe69
+yuva422p16le a7ccc43820683ab15061d14cf8efce6c
+yuva422p9be 14c55a16d19499b54b4341f135d3e558
+yuva422p9le a8bf168e5d2709222192d0aff46b1373
+yuva444p 86b05da54db8c7e8cf5b6638e19c6fc5
+yuva444p10be 8c417158165c00fbd42def60cbc27d69
+yuva444p10le 5f303ef3fb56faed69b4cc1c760ac6ae
+yuva444p16be 52a9591ec0d5059e49b1b2803f8582aa
+yuva444p16le a9272ac197e4a4195662ce90f533976c
+yuva444p9be f72f646ef07cdab613420585aba041ac
+yuva444p9le 6d431b0a27bf4f86ea44ef5f14247a01
+yuvj411p 037accc8e48ac9928a580cddf444f129
+yuvj420p 73661456012f20cda81207b14bb0c0a5
+yuvj422p aa97862b57f47c5a6506156e9aaf129a
+yuvj440p ff8b9884a49d546b035f5d2ac1e673df
+yuvj444p b8142888d80b8065c54045839e79b331
+yuyv422 f06a4fbbdb32807d05de825daa2c3a1b
diff --git a/tests/ref/fate/filter-pixfmts-copy b/tests/ref/fate/filter-pixfmts-copy
index 23452ae..edb246b 100644
--- a/tests/ref/fate/filter-pixfmts-copy
+++ b/tests/ref/fate/filter-pixfmts-copy
@@ -1,89 +1,116 @@
-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
+0bgr a06d3a7652e4885c65895e0e168aab28
+0rgb b6b5653d2228cdf2ba3c55a72f2e713f
+abgr 1a147fa04ed70b9a7e67a4c89052f630
+argb 997df0b5c268a0d8f9c611cae4e01e05
+bgr0 218df6dc3eb5094a0c16a8bd18bc3999
+bgr24 d6370f6dc34df2ea66e1718baf74137b
+bgr444be aba6dfea008ae12c2120a95f54293904
+bgr444le cfb5401e8f076cc8675e17ed1114a3df
+bgr48be ab65229b64606f6408cd732b967c0b01
+bgr48le f1b4e718cadee9bd2978289153ce43de
+bgr4_byte de96505ef9ad7078f87b4dfdf6fe4b61
+bgr555be 8d5de9e9200d622f27dc73958a85045c
+bgr555le 74eb9837706143a40e26305a16a79369
+bgr565be 13a36d6502be88fc0c2aec05b8d2d501
+bgr565le ed027571692aecd522aa65a90cc7e09b
+bgr8 71ef789609c746c2e7e4be9dec29062c
+bgra 0364b074268682ea46168742a8239f7d
+gbrap 412a2449fdfaeb5ebdf5e4196cc7391a
+gbrp 4778f8cc2bdbcd65e272ea1761cdca6d
+gbrp10be 0be11fe4b2324054be6f949e81966691
+gbrp10le 173f89ae58fd4d01d6a365318e4da3b1
+gbrp12be 1f5231ed7e4589a3ec98fa79134bdc6a
+gbrp12le cc4830a263fecadeea535c4938b5cee1
+gbrp14be 6f5143374536e1cf1595260e91c86b7b
+gbrp14le 937ff1dd9f498b39f9e882316e371fbf
+gbrp9be c76ab5850c9bc72bbbf36caa6d1c5ac7
+gbrp9le 5ad363dc9570187ad3e3f2344fbb30cf
+gray 2ee2ea2340d0ecf2dfa6f90f87384799
+gray16be 389f4e5a8ab413b3af32767b59ed7f9e
+gray16le a1f912941247e45b394b9cf4f0e81130
+monob 309b5785a36bd988d17e15d88f4ffad1
+monow 8809a02bc69b58d1114b09ca79ebffad
+nv12 75e90c54d858b993e99f4ee6d2a2a38f
+nv21 8831a3f411015d45fbc5dd191245ba9c
+pal8 13de2a1c3c80cb64d14e2bc4f6f461d0
+rgb0 992f5ad24802cc255edab45c3084db4a
+rgb24 c71ba90f69f15c8275232bb3f62d0ced
+rgb444be 26eaec65d7efd2b0c9c13b47dfd9b241
+rgb444le 5f29863553107110ea817f52151d77b7
+rgb48be a3bc81c46c21818a989f23104a599ab0
+rgb48le e87c661ac49aea1f1e93939802883d92
+rgb4_byte 293b1b84f01efd90bde40cb3faffc127
+rgb555be 5229183fa64d4e5c7e3703d8263ee6ae
+rgb555le c3e9978cb2a4129a5575935e8cbc433a
+rgb565be bc123b962629ead1a06af0c18cbb6e5f
+rgb565le 20757fafe4756e62d845b2ab4c0b8f93
+rgb8 e01614f5416dcc8ad365ad7a57afc9fb
+rgba 53796fa4c392a1b2659595b6a284f8c4
+rgba64be c05fbb1ada1b48fb1eb192fc200af2b6
+rgba64le 1b826cc613666f545274e8a7799d69f1
+uyvy422 3f411f947e3ac8f842c88e717d68bd9a
+xyz12be b91ff224254afceb4a8f803d56eb52a1
+xyz12le dc524e3726ba1df0d2f406db3a2c08aa
+yuv410p 7dcf3f4770c8b494290ceacd2c2ce6db
+yuv411p 9461b188dab6f8b90d9a27e353a89f58
+yuv420p 61fffd2d8425759a33ae07e718d0242d
+yuv420p10be 2abf90242cb021cb6fcf9f2c3c92f6a7
+yuv420p10le 180b7e4de684c7225d2fb37614f842cb
+yuv420p12be 256c9e6cfc878a8abf681b30777c0620
+yuv420p12le 8dc8b86c4790da3769d4a62e87608623
+yuv420p14be 8d22756c5d2b9e501924c082bfb22a6c
+yuv420p14le c9da19d4818bcb119ad6481b75778f7e
+yuv420p16be 4ccdcca6dd6a960f9a3333f0aee095bd
+yuv420p16le 9c5847d9b0de258a10ee906dc47e24ea
+yuv420p9be fa7ad4f73232aac0e35def62af1e2c39
+yuv420p9le 3720ba1786b56c8f4913e67dddebbb07
+yuv422p eee223e92f1f2e5ad4186b411ebf5816
+yuv422p10be 80fa87750491dcc3e93d175b64835654
+yuv422p10le e1640cd315bd96c6b59f7753825a7306
+yuv422p12be 5c6d86e919515d1af71f8004a6252f9e
+yuv422p12le 7f331cadb0ab75d07656d29f47bd8bd9
+yuv422p14be 4f4e186ba683b90fe990cccc4db7e521
+yuv422p14le d78016c9119b1f1d1c922bd5aaf47732
+yuv422p16be 1f3c216927d17966a009a42def124bba
+yuv422p16le 90adbdffaeea9b09398339c8a1322b02
+yuv422p9be e46446534dd0821029d3b831c9c1d1b0
+yuv422p9le 520e418a2429f7efee511b7fcbf45ab6
+yuv440p 456d83524b299f2fa1bb988e421554d9
+yuv444p 068bc09d282d18c9fa35c2787943fc2a
+yuv444p10be 9f6e1490080a454243daee9229425e1e
+yuv444p10le cc183e51041351d9ac06c4df6e8ad5f7
+yuv444p12be 34f63ac6a47ac681016105d3bfb3e118
+yuv444p12le 7964701bfe8d718edf97f6e0002935bd
+yuv444p14be 4ad3a9d52fe9c050150c0f7d2f3cf63d
+yuv444p14le 69575e5a94b978f159c4fdb1a61587b0
+yuv444p16be 4000b12fa88ed0feef182da31c7e6b96
+yuv444p16le 96a857dba8dc6792c58daec872825b32
+yuv444p9be 07727e5c9040b7f0a17d591288ac330d
+yuv444p9le 4d12d20a68dc28618594c96c2ade4ff4
+yuva420p 3a8c5c142e051367c196f95696e0e2c3
+yuva420p10be 1b7c5ec6691498e24676ce6ed97f62f8
+yuva420p10le 4c13322bca914df2727da91cca85ca1a
+yuva420p16be 6afcf758f4b66c0b4173c942d42212d7
+yuva420p16le 13e195aa96329eb49921b6f9f07b875c
+yuva420p9be 05a78390de312dfd21ac666a9da05fbd
+yuva420p9le 78f5593bf51a31841ef83df41d0316eb
+yuva422p 45ae66d6f69fd5b77e6831e98d228bf4
+yuva422p10be 18284c58b926fe2389605c692a703145
+yuva422p10le b934d28b615729a24bebf0381c465e37
+yuva422p16be c3f7354b6013b43439e02aa02be5fe69
+yuva422p16le a7ccc43820683ab15061d14cf8efce6c
+yuva422p9be 14c55a16d19499b54b4341f135d3e558
+yuva422p9le a8bf168e5d2709222192d0aff46b1373
+yuva444p 86b05da54db8c7e8cf5b6638e19c6fc5
+yuva444p10be 8c417158165c00fbd42def60cbc27d69
+yuva444p10le 5f303ef3fb56faed69b4cc1c760ac6ae
+yuva444p16be 52a9591ec0d5059e49b1b2803f8582aa
+yuva444p16le a9272ac197e4a4195662ce90f533976c
+yuva444p9be f72f646ef07cdab613420585aba041ac
+yuva444p9le 6d431b0a27bf4f86ea44ef5f14247a01
+yuvj411p 037accc8e48ac9928a580cddf444f129
+yuvj420p 73661456012f20cda81207b14bb0c0a5
+yuvj422p aa97862b57f47c5a6506156e9aaf129a
+yuvj440p ff8b9884a49d546b035f5d2ac1e673df
+yuvj444p b8142888d80b8065c54045839e79b331
+yuyv422 f06a4fbbdb32807d05de825daa2c3a1b
diff --git a/tests/ref/fate/filter-pixfmts-crop b/tests/ref/fate/filter-pixfmts-crop
index cbbcf90..9651fb9 100644
--- a/tests/ref/fate/filter-pixfmts-crop
+++ b/tests/ref/fate/filter-pixfmts-crop
@@ -1,42 +1,112 @@
-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 ba367adf7943b91cf7f98aefe3f7f9ea
+0rgb c83c555fe20def126bf1b8967442aa97
+abgr ef31d9057f6e65a7c3308a1b1daa98fa
+argb 5e5e261c4870e0de05d56ff640b9550a
+bgr0 c8729ca08c5d29ecd5ca21c0ea8c54ce
+bgr24 44bec15f35513de7e957b3d59b53cb7b
+bgr444be d56f795721020fc7a598e3b07f3fba1e
+bgr444le 53224fc7360806c19fbd873e13fd0c68
+bgr48be 0b5ebce3c48eb8614d79e204b5268603
+bgr48le c4ab61a8b9d502132730c6abb6ffd84c
+bgr4_byte cab930dbe1fe77d58b41837ecdcb8460
+bgr555be 67162782fdb86813f446d8e1c21c73e9
+bgr555le 85913cfa8dab465f7dcfcfe7f9001a01
+bgr565be ee9a1debb896d41c53a026f9e6ce006b
+bgr565le ab7b6055bc3b6b7edc9a5e4de43ec90d
+bgr8 f85ff16e21d922ad6d32648ef3acfbfb
+bgra 9f2e37d73ad3b759fc9d6b12ee668c38
+gbrap 32c0326859b41ae1fee015648162c6a0
+gbrp 0f59d3a61d391c3dea6f6e5861e9c2f7
+gbrp10be bc12b34950af11e3f1016acbe2d5dec5
+gbrp10le 0ff56c84154050f992fefc357449da9a
+gbrp12be b2154eaa6344a37ace82e42b757585e2
+gbrp12le 77956c63e99444fc61c306643acba403
+gbrp14be 3ab29f18610ce10ce2e5c99b1af78415
+gbrp14le d1465f7280f35aa0a70709e5a7bee1a4
+gbrp9be f17b7ba66ba35ed0fcbbb5c32c7e0f56
+gbrp9le fc11219debfbe8dd8c3d6f0ef92c4d50
+gray 6d34024704f862c75db3ba6989a4a039
+gray16be 02ac848ad4e28c06938599563ba81ff7
+gray16le 672aebfeb8a0f4067b3c6064340056e4
+nv12 923a313a7013fb0e87608155ef6aa9a4
+nv21 21e6b9273bb74203beabeb9edb9cf95c
+pal8 e1fd50b8a8a67fb5abd8b44abc778bbb
+rgb0 8bd7785a8421b3f60e5eae2d2968a546
+rgb24 d044123f1fe50f656f2101dd3f091ead
+rgb444be 6a076e84d0cdbae2ba29412a28587e81
+rgb444le f82d127ca2a40ec822171b79a11df65d
+rgb48be ef5507f88948b54218911d12e1dbef36
+rgb48le 6d045d5990d6ada64a112e3b581a7b38
+rgb4_byte 0f0f9ee31c65dc60da49bf98a1b06dcf
+rgb555be 48fa619bfd04f6dee05416b02605c031
+rgb555le 292cff1f824e49076bad50a07ab1c749
+rgb565be 0dd6f6a5a8713bd1c3d9826bb7a88eab
+rgb565le 6afd85faa8c6f0f330969539178eb9a2
+rgb8 87cf541b110e35a6f9a983e9cde85e15
+rgba 7abe1af7b97f5b9a7aa5ad3e4bf32f76
+rgba64be 2eed28b61af25790c02cc658e5f86b9b
+rgba64le de8bc34c6d573488d87e87ce8c7ad07f
+xyz12be 7ea4ce13143195dfe1ed340bc9e86b2f
+xyz12le e4e86ef100e07cda561a22811f242e5d
+yuv410p 126e0da1da4fd89be28087b8367bbb36
+yuv411p b94f0af107fc4796aca70c0a36d374c5
+yuv420p 74c6b331bd30f005e6c75a192423ad90
+yuv420p10be 1321772e0586e9b89386e792ed9f5277
+yuv420p10le 726b637741fe28c26d57a1dd814ef14b
+yuv420p12be 5c3bf63a61fe41acb958614d4a7c8923
+yuv420p12le 073c6fa32443c1df26243b598fb5a34e
+yuv420p14be 9460b8507137516ae437d00380921cb9
+yuv420p14le fd162a79436a9585ed44814fa3dc02fd
+yuv420p16be 2d3c84ebff77479e8c5b6e3e59ec4e45
+yuv420p16le e2c906f2751609bf8cbcbeb2f629319a
+yuv420p9be d40531645b7ddecf4778f652549c121c
+yuv420p9le fbffd583dd189a546cf4df144a735f66
+yuv422p 124bc8d668072de1bb3b894cc4bae859
+yuv422p10be 3d6195bb0c4cc9498ef42227839db9d5
+yuv422p10le d19bdc9ba4e76b38c076ac93e99e6ef4
+yuv422p12be f2c2f23269fa969e3e3f0ba5e065bc98
+yuv422p12le 6d07ba50dcdaf43bd8b73233ed11e4d9
+yuv422p14be 3115c4c01f6a8b9930b32ec8a12f52ac
+yuv422p14le 00ba7302e4e4db2c70ba0712f2fc8574
+yuv422p16be 3ec47e2709107fcc388b5e0abebf7eaf
+yuv422p16le a4183a62917bf8568fe11ff446dd18f9
+yuv422p9be 05c2d9a95f329133a9fa03c46eaaf0cd
+yuv422p9le ea559e7009aef6c36de0daa8061740f7
+yuv440p 15c81c685fa5b9db95150caff14ff83f
+yuv444p 12b752f78af72666627cea2d0c274cdb
+yuv444p10be 6a5d1574657bdadd435c59227b6772d0
+yuv444p10le cc6e8453e6ffeeca98055722f9833fb0
+yuv444p12be 39086bcf3ad336391c2a378b32d9cd1b
+yuv444p12le ccc98011edecb7c643e6250c34ae9b3d
+yuv444p14be b05b5999610b1369d0873212543697f8
+yuv444p14le a4ae35bb8a377d593635126671d1af30
+yuv444p16be f2bf0e22a1d184e37eaa199a76cf22ba
+yuv444p16le c11b151dced5c8854d385373fa4dcc8f
+yuv444p9be 0b4e2a096a7ada2d6fab3f7d5160326c
+yuv444p9le 04b00046c0409849f89bca191298257b
+yuva420p 920c5d1b965eeb72e3a0e343696face3
+yuva420p10be c2d580dee6da641c176c6357e74d14bd
+yuva420p10le 51781f8328a0ad69466e729cfc31bbc6
+yuva420p16be 1855e36526638e5d364b1d29bd49141b
+yuva420p16le 2476b93493a30cce3c8fe07ea3ce3761
+yuva420p9be 7c9d877f0c06529d60beb5fcbe5a6f47
+yuva420p9le 392387fc9b414576e003abed4f8bf389
+yuva422p 1bc930cf64afc7cc99362fee5d8e08d8
+yuva422p10be 3382c54dd78aec916210edef29aa268f
+yuva422p10le 93862b68e0dc6ea812fa36fbb1641b48
+yuva422p16be a44509ccee5dd71a67f8138a8dca7620
+yuva422p16le 4a0b4f7cb3fda825acd6eeef7efa4aae
+yuva422p9be f3d9d423699ccf369b50ea7dfefb16da
+yuva422p9le f65115fd89e0cbabc975a15e764b4d30
+yuva444p 1cf9c2dddb0e2f082eca981b2226bdb1
+yuva444p10be e60f55491f67bb69962e4c2a29868da2
+yuva444p10le 6a7a95f6af4ef3ce47e2b20bc2453746
+yuva444p16be 0caa51254006811d244e150fa34f2e90
+yuva444p16le 5f073f7771254bace1d07279c56c9613
+yuva444p9be 3d64778ebee876c77e77066fd57336b9
+yuva444p9le 85a80221022b5de7cb3233845392d8c6
+yuvj411p 55f4d5f22146e7771ec4e5729a438f48
+yuvj420p f9183e49f42bae31d7d85b92161fa82f
+yuvj422p aabeed60a6e1b2cf88665ac627bf531f
+yuvj440p 5ae4f404b42f3167f978473d9a3737fc
+yuvj444p 6728997f65b879fd5a3175cb449a8f0c
diff --git a/tests/ref/fate/filter-pixfmts-field b/tests/ref/fate/filter-pixfmts-field
new file mode 100644
index 0000000..d4822b1
--- a/dev/null
+++ b/tests/ref/fate/filter-pixfmts-field
@@ -0,0 +1,116 @@
+0bgr 57434af4bddb691877f2400c704604eb
+0rgb fc2ba950163aeee98590181e31fcd202
+abgr 3c78d0a72484a1ecd3cae245b9fa988c
+argb d5057a2be412864719ffb8ba129c1f2c
+bgr0 b33c6b58b0d7bf6ce07d5a2d7c267040
+bgr24 bd6620738df19410d5df5f31e7451709
+bgr444be 219e318b7e0e05050181e71df6b9539d
+bgr444le 8354f2cf5b30de0233d302a74816649d
+bgr48be 22be50bd0aa39f07ad1b1aa57cb741ce
+bgr48le c4b0f8057b3eac237e9228e83bdc4c66
+bgr4_byte d4c3304b4b823a130c335379e4d3444d
+bgr555be c3072da465233dbfc8f61dc7a9766d2c
+bgr555le be83adcf0b802b061442f0c564fd5987
+bgr565be bf955b9a035af0e613cf1de249f55f9d
+bgr565le 6dd85cd5e19266c53a54cbcf06d396a7
+bgr8 9669f6974f0fc1c0afa1c7d4df093c0b
+bgra f7cabae31dd7465dab2203f45db646f8
+gbrap fdb15f25cd6db3d19a7df727e0f4de3a
+gbrp 0867ccbcdf50a02871ad7788e3e0931e
+gbrp10be c452475d38b13a4707634eff74001215
+gbrp10le 009a9f7ba2ac9a8c67269bf3a76581c5
+gbrp12be e1e01fbefb6ab400a7eb460aa9ad6acd
+gbrp12le cf2fd4db9e69d82acb0aedfc094ebc9a
+gbrp14be 52ce4bffdd04a2f51ab2d3ae4e78dfa5
+gbrp14le 775b50257b848007c4ef3441ba772db1
+gbrp9be c293422f1395bfddc788282eef139ed6
+gbrp9le 0d2bb77c25d84611ec6222f3dffe11c0
+gray 42a0ad7625a0481183e375e38679d8d3
+gray16be a447af6482b922c9997ac02e5d3535f1
+gray16le c1dd0db327295898ff282d07f48c105d
+monob 1b7fb7e69a913a0a1c0dffc54e5899ea
+monow b5d3778a054fc73d515d36f8a6bc693b
+nv12 b3829e9ae2a15349432b7efac4236068
+nv21 963cf5780e07301ff2906bf345b6d0ff
+pal8 bfedafc3bf19c2c12eeb87125833142a
+rgb0 d7481143742ff68abfbac4195edbede0
+rgb24 908d5494062c617bc87149c9daaf2167
+rgb444be 281a8f186a2726c2b31aa7e09e21c865
+rgb444le 93f9ee6265d8ad5e744ab652563f9b78
+rgb48be 0d1d60e1639edb2758ad776cb5583970
+rgb48le c958b5e98324263e97de2bb528f5bda4
+rgb4_byte 2ec97bf65649e3d47eb6812701544593
+rgb555be 21b9138b229d4065b02d38b5b62f18d1
+rgb555le 0307ee34e562b2fb2b1c6988ae18b2b2
+rgb565be e8f3ebcbb9a5fff000eca8a312f89782
+rgb565le 53bbd558fb0dcd82f1fad83ea855c3ad
+rgb8 67bfdd4fa88b1ab9be876f42dfc75683
+rgba d0ebdf1495bc6b7e9d3bfbe2813a9d16
+rgba64be 53363baf266592e0ac02b3f8242ec4fb
+rgba64le a630eaa38545b2be741f000ab58451e5
+uyvy422 a6a52504a16f09b8f2ec2405bc8190b5
+xyz12be 33d0b7ef124a9e94d2d13a2cad1dfc00
+xyz12le bab6403abf58e69575900802ffef8f38
+yuv410p 3feb55b1e2a385b488c82e808a12587b
+yuv411p ab3dd8e6cf1452afe2d2e976e4726370
+yuv420p 52e26ad198368e2326bef97cdfa6a2bb
+yuv420p10be 04353bfc21e9b88cd7776e83be756742
+yuv420p10le 3f8e7167dbd12976c6ee516b8c952363
+yuv420p12be b058ac076c8a5fe522b9fd9b8422054e
+yuv420p12le ad0bf28e69eeb14eac5d8f9ea8b801f1
+yuv420p14be c7a435d42f07928332ecb21a7d96ad7a
+yuv420p14le 5507e8db4e58c9517012686a7408996b
+yuv420p16be 5241d64e9fa2fd6590fd23ea0e8a6f90
+yuv420p16le 78da606f761a4fb62fdac05aa5092742
+yuv420p9be e4bcaf5d6a7030f950b08501327f6175
+yuv420p9le bbf80e57389578be66d4a7a12335a613
+yuv422p e461a21995da361b88202339a2ebb879
+yuv422p10be a3e13070215f5a016ac9bae7e7115417
+yuv422p10le 8e9e3d9adc8fdb8a0a03d79bdc31eefe
+yuv422p12be 6a2aca2ea007534e729203641a82c3a3
+yuv422p12le aef072b55c6e9df8fd9f398d79f864df
+yuv422p14be 34e5f31372c0fdb4d77ccb7fd7bddb2f
+yuv422p14le c2c50fbea0cff7edad5c5e907380cbad
+yuv422p16be 55cfed8fa610f82b6625e16871dab235
+yuv422p16le e2488df0f22987fe7ed12a5ef2adf835
+yuv422p9be 80fcdd7fd9cdd79632104dcc32f78b4b
+yuv422p9le e0ec9f94c875297ee5d0546274df40e9
+yuv440p f8e80596babcdb94378ec8bebf2dd46d
+yuv444p 572bad9e12ed53e242658fa613412279
+yuv444p10be c5304f086afc4624d4fffb66a3cf3cb8
+yuv444p10le d1754974b936f74028752d49413d30aa
+yuv444p12be 7ec8fd2d7986d6e923dfed572589e643
+yuv444p12le 79d0e287e2171a53cf4f285c0d1e83ef
+yuv444p14be be021957cd819ca3146f3247138ccae9
+yuv444p14le bac0b0c70bcf72272d724f0cd1ac411e
+yuv444p16be 3a67c28325978db734ba03b1828c15da
+yuv444p16le c6dc275a4277fd3c65535253bb298263
+yuv444p9be f47357cdd775fc399aeab3ae58712fb9
+yuv444p9le e29799ecb6fac9f5b6d85bc34d248d4b
+yuva420p 82ab09bb7a3a24bf95aeb3fa9d939847
+yuva420p10be f4559039e99ecf74a58e7063b1e7c5d3
+yuva420p10le 32b3858b01be5bfe2579dadd1be3ab12
+yuva420p16be c580495d34c6ac6e3e3b81772a0f3070
+yuva420p16le 1c49deeafb8f81e9186f3906c9b1a670
+yuva420p9be a788d7cc6ad67ad52619a08da126569a
+yuva420p9le c1579a5c015908f26b76480d82f6a648
+yuva422p c162b37ce05360c47b2a2224ea0748ad
+yuva422p10be b7c0adc12a8602ab8b40b611785cc18c
+yuva422p10le 97f91d820f8ba642a3f9ae0901d03826
+yuva422p16be 1c61492076be33404894c1d3ec578d87
+yuva422p16le 1c085c9479a57eea35e74c264c947d73
+yuva422p9be 271c6cc091052731373ef5313bc76435
+yuva422p9le b8c2e963ac35371e8aa6a05d5c252b37
+yuva444p 4a85f1f17e95829cd53c9a28928fd8eb
+yuva444p10be 04c1026f4328ebf24bd7906291b33464
+yuva444p10le 3e8ea3b211bd7ac99cb96ebf71d0e75a
+yuva444p16be ac5c17adeb0ef6730a0de1dbd1d14a1a
+yuva444p16le 41f1a82eb686d7191bdb00206f723247
+yuva444p9be 413d01385a8b008031b2ab3ef0b9eff4
+yuva444p9le 33ede0bd20bfd85489d266ac81d035d6
+yuvj411p dbcc5e7ef64335ad30b8b9717bfa63d9
+yuvj420p 762dc6a157d0bee72da3e3d852668aef
+yuvj422p 8cec955c1c62b00b6798361ef82962b7
+yuvj440p 7b469444994d8b52766ee461bcb795ea
+yuvj444p b395162325af489c465a3e6a31fbb0e7
+yuyv422 1efb17cd0a48d2e956fd574ea6f412e7
diff --git a/tests/ref/fate/filter-pixfmts-fieldorder b/tests/ref/fate/filter-pixfmts-fieldorder
new file mode 100644
index 0000000..d743caa
--- a/dev/null
+++ b/tests/ref/fate/filter-pixfmts-fieldorder
@@ -0,0 +1,89 @@
+0bgr a8559fc1395908cda27a27bf79819d61
+0rgb 704924e65927896b84bd645ca59fb7f2
+abgr f479df06a4b73d348b3af004923d7eb9
+argb c16c9af56802c3b821b30c613c041622
+bgr0 b7ee10fec20508b64dfca22d61533a88
+bgr24 a1c59acf60652578b802e7f6639d1ac5
+bgr444be d41639928d05bdee67fa2a76c7f74533
+bgr444le 45f616b1ec9014f8d618878c4db850c1
+bgr48be 7015ba40d142742e5c6a39113fee58af
+bgr48le fd33d4a60a789d170b871784d0859089
+bgr4_byte d1ff07684bc1be194d26cdf598385b8e
+bgr555be 2295d642e02f9dcb49c20142bfdd9c1a
+bgr555le a95883301ab991a3cf8bb063b7912410
+bgr565be c37ced8fa4951da20831edf9bd46b35c
+bgr565le da0ee7f773efa07fdacc62b7deac452b
+bgr8 94a043f6d5e01de077a92a9be6f77582
+bgra 02db5e046ced11d3f09d901cae205e2f
+gbrap 5317a66b677c943203b2a5e93607dc68
+gbrp b1ffeba90a60e9a23c9f35466c135069
+gbrp10be 07b2842fdf9b92f6cd8e8cf3a8abdfac
+gbrp10le 7fa5429bb4bc6f0e1f3c190bc8064b38
+gbrp12be 5ea6cb457c88b4b3d48f6f63b6208828
+gbrp12le f969a3b017a0f46008f81453174f4ecd
+gbrp14be b2879b691564f66b88e63efd268de8c5
+gbrp14le 7baa94cd296e6ec8e41446bca95151e4
+gbrp9be a6eb7cde03f19a25bf13627d731a2c9a
+gbrp9le 1b6d228b97a370ec76707ed2dcc15a66
+gray 3258910ef8c6f0c4a331368e7af87507
+gray16be 50cc8a29e8e81e174676542347804a4f
+gray16le fb93e8aa2deed734dfd1ca6a5c48cf18
+rgb0 5f8f8076e2b9a2422cac25a4f0459d79
+rgb24 66ca89ced3ade4c239ad6c5a79a6b8cd
+rgb444be 7197a09137ab5630a26226396bb7e313
+rgb444le 2d10d7d2ef4527152a9ba8b2020c8d41
+rgb48be 7aee07b85b137365eb04a7ea4c10dcfe
+rgb48le debaa00dfed0234efd1441aea8195026
+rgb4_byte 12d6a5a7ca40c531a4d480546ed766eb
+rgb555be 5d36ead35aa8820daab7d84e1ffbb4ac
+rgb555le 10f43b4c9b06742abc114f0ff1864111
+rgb565be 998ca430a1173f194d78a92695e097f9
+rgb565le 99be7760861aa9c1d3d743a1ea311689
+rgb8 6303c75883c1e2e7e13644fb5dcd11a7
+rgba af33be882959a2fc963d6e5984d24b6d
+rgba64be 9ae73ceaa9d95e7981b4df559b0d3b6d
+rgba64le 86997e62f62d2a5351b5ca9c9c93c2d1
+uyvy422 a07829fe630b59855c80d87d0e8f0dbb
+xyz12be 5785613045b051cee508625dde3357df
+xyz12le 3645601dc8bfbdff68cc823a0fc85b27
+yuv411p 3d3d427999863945aa5ec03edf98c19a
+yuv422p 961d8a22bfe8868eb3c743b4241a3c99
+yuv422p10be 845e80406c880f33a384b5ebdd21796d
+yuv422p10le 0dbf5d1eb94f10cc4413976fa175fa90
+yuv422p12be 9e96f9324d0a4eac4b45161b02c14209
+yuv422p12le db17368e8cd5409826a088ee26ad2a1b
+yuv422p14be e20b379fb17e50f279a5ecd9c895537f
+yuv422p14le 9440b0c46dadddc19154054978fce20c
+yuv422p16be 09d09b64aa4b6ae8479a833622bf27e8
+yuv422p16le 03dbbf3394ba66cda54ef53772258dae
+yuv422p9be 7c59e15cb5e6eac9cd090c6ecab4c6b8
+yuv422p9le 98b6b1fbacdfd4c25dbda89b675b660b
+yuv444p 709ffd0e95a9438b14d9ba59c0237a61
+yuv444p10be 5ae7571651faebac6dca2ee4fd24610c
+yuv444p10le eb3acb92448d8b0e6f145e9d8af43378
+yuv444p12be df1e9bb90364d874dbac41a8237d6068
+yuv444p12le 7e21d00cb42404df0780317dc135f03d
+yuv444p14be 6abf70b4b7ff55552327230e08e3dd52
+yuv444p14le 85597559a748aa5aeed2d7dc49d7f66e
+yuv444p16be 2a19a8ca44198d0e90c02fd4db24d0c6
+yuv444p16le 5cb12916afef8c82d1796fdc39b97174
+yuv444p9be fc731b5b0afe0a9de6bd46179c692efa
+yuv444p9le 7449c543e528067afed5d3c96f7b8da2
+yuva422p d07e0ed0cb20eee67007b154f02cf37c
+yuva422p10be 56bfd0af50b9450f72061c605f6537dd
+yuva422p10le bfe1df3aae3e02f0a2ddbd404199e6ac
+yuva422p16be db80a2e1ddc93126206ad4864f67b50c
+yuva422p16le 847e541568b4bce64f916d42173c93c7
+yuva422p9be 5487d986b52f5744a8adac77e46c08f1
+yuva422p9le 6faa61b431b2e0bd4064e5fcecb7130a
+yuva444p 377f65cb10dd8013011e185b6aa66697
+yuva444p10be 5e42b4e4b6b1bfd12aa5869750cd2cce
+yuva444p10le c1fddd5f488fd4f8d1e07288f8a49182
+yuva444p16be ba2b267e0cc0c36041f3db4f4072ee9e
+yuva444p16le c2cfda36aa173be3a4a5c9a8fd66d8db
+yuva444p9be e047805a8f9552a6e0b6d4f772126808
+yuva444p9le 28336905569a55e935d708527a3c9d9d
+yuvj411p 09f79c56109a13eefb68ee729d9a624b
+yuvj422p 942043a34ac7d0f65edced1f6361259c
+yuvj444p 7e4758df8eb9b18ad60e1b69a913f8c8
+yuyv422 6b0c70d5ebf1685857b65456c547ea1c
diff --git a/tests/ref/fate/filter-pixfmts-hflip b/tests/ref/fate/filter-pixfmts-hflip
index 3741713..d672346 100644
--- a/tests/ref/fate/filter-pixfmts-hflip
+++ b/tests/ref/fate/filter-pixfmts-hflip
@@ -1,42 +1,112 @@
-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 03d8a8920dbb408218376baee8665649
+0rgb 6ee5f3b85ec38953df0762ddd0bdf561
+abgr 8ab842e280c8b31f66450e8951dfedfa
+argb cdb6aa47939d49c0ff72537bfc8c82e0
+bgr0 1b0b59382ddbbf045be6b160b7df5881
+bgr24 5b64fd60e2050946b50da1f4945127fb
+bgr444be b52c1b9d9dc02cb46c04e80d97139e60
+bgr444le 48172797fa65a25c0ad30ddc7e8f5bcb
+bgr48be 58e292c33eb60708171c3393a5700615
+bgr48le e1be8e6bfe26acdee258e76329d2f03d
+bgr4_byte af34e1158edfbc8c6929365d651a9549
+bgr555be c82d7877f7ef25ee1154d05b240cf54c
+bgr555le b7a4e2c66807a82bd132dfcf8540bfb5
+bgr565be 3b464a00c619410eac7bdea9c96faf60
+bgr565le 4b4c708d4ad222f41734dce68e9d48b6
+bgr8 ad1db7a17cdfab2ede6f22c2415a3fbf
+bgra 85fa06ad9fd156c3179a647a2e741b60
+gbrap 5fbf0a36ee9486161a862a4b2d6f8242
+gbrp 8b00ca96932c9bce5bca01ee621e0957
+gbrp10be df96591083deab8382c1907ea1e99e9e
+gbrp10le 98769f5176bd3872f494aea8039d8475
+gbrp12be 9a0ee0322bbd7a25ffd85b0070c5a563
+gbrp12le 2f3899d712ee3e1510b0f442ceaeb505
+gbrp14be 966af80018ebf6b0576004362c1ba395
+gbrp14le 297e71281660b905711330a86eca8a71
+gbrp9be 8268b9a1e9f4d6a42e57db9c81d82fa5
+gbrp9le b3a09bba825e16e6d160328706a9f62f
+gray aaa9c2fe3c2a2a43a4b35226ea689b3c
+gray16be d206a080739d89cb7dc0009ad4082ed4
+gray16le 7ebcfd9401ba85e584230de8fc02986d
+nv12 719adbc47fa74e92f83150921917483f
+nv21 9c833b3ce53539d270e1f21e4319797b
+pal8 19c8735b23feeed18ec2d37913a5f3f8
+rgb0 ce26538ebe1ec09dec3dde5e4d8a1405
+rgb24 c2752464ac2b549268e9638745dba857
+rgb444be 85586541cc7eb12e05ff7162b12304c2
+rgb444le 670da20b82403e00609bf2c1f5611223
+rgb48be a9ee2c9946d8d54dba60cebbdbe43886
+rgb48le 28e2cf59b789249dbd0859f58f4ae55d
+rgb4_byte 31dca70b4f3537afa9840cea1b062acf
+rgb555be c010cc746ce9483b47387ba846670179
+rgb555le a768de014e0908dfa886108da376b2e5
+rgb565be 6727e71974c8e5dad157925c10ee1532
+rgb565le b0a2b4817775289cfc415bb951f9ae0c
+rgb8 22fdbd14ce296c1afa9bb4a6ea09b3fe
+rgba a37789c4df73c3bd8648ad1fe9d3f991
+rgba64be 286067334e4bca33fba7ebb1706890a2
+rgba64le 2a8b3dd5045df299259636d8e6b62589
+xyz12be 079dac329f0d93df7a7e71b260f13dd9
+xyz12le 31c4f953548326b27920c5939bcf2cce
+yuv410p a1280c2b9b562dba3c2d35a1e5fc4b23
+yuv411p 6bf10756ac5c7841db63a97106ff911b
+yuv420p 45f4a06481f2cd8e28fb29c7c151e110
+yuv420p10be ddfef981d53de0f808173bb267203ca6
+yuv420p10le 966b8c55de4d8a12bdc8db3d9ad3ae6d
+yuv420p12be 735da68f3ac8380a993f46a460c02432
+yuv420p12le 3a71ae4e6a7b106b3e1532c6d148fa61
+yuv420p14be d921d7b364d0a7bde183ba717a77f1d4
+yuv420p14le ab410b636acd41234cc396967f66c859
+yuv420p16be cde798cad650bcb087943442a399c8ea
+yuv420p16le b7124c56605eeb12f3d13287ddc77f3a
+yuv420p9be b0f6044fb40cf0ef41cc536311566cc6
+yuv420p9le 086f9320167a755faed18c0a3a36c0e6
+yuv422p c3982fbb57e796881efedae11b8346de
+yuv422p10be a3db158525c7794fd06b4d20e558e64d
+yuv422p10le 31cf611e502584fcf846d3ba2583028a
+yuv422p12be 8cafc31b579b168a71f7093a161b8023
+yuv422p12le be83ffe86cb99ecfef76affb2b73d5b2
+yuv422p14be 96870c66856e2669095ccdea034558ab
+yuv422p14le 46dcb0160aa8ada4025b365873a78d6c
+yuv422p16be 4b96fb571e686185d96b4a97e3413d5f
+yuv422p16le 503bc49bace58dae1767173746a16056
+yuv422p9be 0ffc1bfde0b679e6e7b7e0c8c84e686a
+yuv422p9le 3c061cdb9f302c8f8806b409bd2b0aca
+yuv440p 44f78792c5766ab896fbe0d718976946
+yuv444p a36b8ce12de27971b52e93267fe6583f
+yuv444p10be 90e94770d3eb4693b09925f549d7311e
+yuv444p10le 8a26fba7c2223d72cd5ad00c1941948f
+yuv444p12be 24bdad5d7ddca614da7d105e931c49e8
+yuv444p12le a996cb8a1c062d2238b58a5db9b990dd
+yuv444p14be a9f7dd66b6f54bbdbf176894b01d7422
+yuv444p14le 6204f763af4a0d26f41ddca1d1ae9741
+yuv444p16be 9370058632b2582ab7a21725ec4f4e1d
+yuv444p16le 0674c63a0e8debbfc010a2730da66a13
+yuv444p9be b1327e7ca47a950ee99bd2a7e05f56d0
+yuv444p9le 2f89171f0470eefa9f89fdc43874dc1d
+yuva420p a62cf0a72905b54a7ef10fcaeff723bc
+yuva420p10be 602b6a8c0b16ce2b55ddcae443e75dac
+yuva420p10le 1c086d4ee0619ac65cb5a69481b981ca
+yuva420p16be 51c45f4227ba86159f46c65783d64cef
+yuva420p16le e87030429a965f2ddc8f07ca49014573
+yuva420p9be a48309403dc66dc5242cac19cc7598e5
+yuva420p9le ae2dcb326eb3a2ff170f498077ae5624
+yuva422p 6e7c30ea252a41b70d26250f624ab284
+yuva422p10be e0ee8576f9328ca4ec174a8c084f2235
+yuva422p10le b489c203b9b0ebc42adb794bb10a3c4f
+yuva422p16be 550b1d2ecbc3d5f50041816090d62a02
+yuva422p16le 73a426eb63685247ea037389595cb43a
+yuva422p9be c65251c422cd3c81ff5d97d207312292
+yuva422p9le 3405924773c6bdc42325a8a1ff658595
+yuva444p e32ba5dcb01ba848e7dead04112b1aa5
+yuva444p10be 97549388c7f9fbc1425b1663b46c43d1
+yuva444p10le 0b88bed194caea2fa06f458034b1b90e
+yuva444p16be 2dd545e4ddb0f134322eee1c1de4c2ff
+yuva444p16le 1e144cc9ea16429c1655c67e2f12f5c9
+yuva444p9be e37fa0743bf720fbe31605714d7f7ad6
+yuva444p9le 9bd4083c1384a55e91f02630161dc4c3
+yuvj411p 042671398bc17a5f52aa9d791b361c5c
+yuvj420p 86370b945c5d19d809ee92386d476a53
+yuvj422p d3bda08bd4b92a256a8ec8432c4767d1
+yuvj440p dbae7083c82f20a38fc55e6f8bc374bc
+yuvj444p 55ce75c7bd172b28703e82f64186e6b6
diff --git a/tests/ref/fate/filter-pixfmts-histeq b/tests/ref/fate/filter-pixfmts-histeq
new file mode 100644
index 0000000..a250902
--- a/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..d9a7a86
--- a/dev/null
+++ b/tests/ref/fate/filter-pixfmts-il
@@ -0,0 +1,115 @@
+0bgr b85afb77d7c3198ad7ff9ca5cceb970b
+0rgb 7ca2257e526092027c67311e273767bf
+abgr 4df961441de91db58f5a8a80603de585
+argb db1e1e487a489674fbf260f56ac2705d
+bgr0 4335fb9738bb6ca5d6d39d738b934bbd
+bgr24 7446301030e6a26853aca2036309fa8a
+bgr444be f80a44936b1295d14b0bac1db624d02e
+bgr444le cfc1511a390f7ca18516540c31c097c3
+bgr48be 0b1084ac65d328552bd62b4e819ab91d
+bgr48le 04e4f510b6d586dc9082af43a59c0ede
+bgr4_byte 2dfd29e0705fbb2b590458028cb2939d
+bgr555be 5622aa808b389095658a203970bd6028
+bgr555le 6a5ad1e35cbacc45aeb9fd593c6f61ba
+bgr565be 5ff7a76d9f58800e38f21a84d88c7129
+bgr565le 485b2b6f589a936d6fb12d0033809dca
+bgr8 d7fae34b87a67556c273585d9140ff96
+bgra 7b4abc57f0ee99a0226e9bfd5d25cf9e
+gbrap 583131faa19f062f6523321da52066de
+gbrp a2db88b8efce6681a3c858be2c229a33
+gbrp10be 714a32d10c27395406f4e4afb20a2216
+gbrp10le e44229ebb1cf96d3ce1960d092e0dfc2
+gbrp12be 09fc9ba31c8c0c8c9cd89767fda92800
+gbrp12le 2c778bcef911d43795e3f6c3b97be09f
+gbrp14be 35d6dc9135fe910dc26b64f03de2d42b
+gbrp14le 778c97b5ed06b9f1a230840a15771bac
+gbrp9be b9fc10ab1ddad0e7945d6b047725d078
+gbrp9le ef3d6bc8069b95cae31100908a7fa967
+gray 2cadbaed81ee12181bda9f4aa87ddbc0
+gray16be cd9c1367dabd2f1858ae4f31693e622f
+gray16le 4ef774c282280d7ed4780690df6e5cb4
+monob 07cffe7f5f25f39c3aa38866303791c6
+monow f2d1bdb939813a49abd6348ecfbb2703
+nv12 6847b3f7141ca1e3c40d3a494f0e13cb
+nv21 e7a8e94001151e2bdd68a0ee7e4ac544
+rgb0 0d1dfb1edc9b4a7ad28dde9a1b0bee23
+rgb24 15781da8615974ed12b18f7439a25d6f
+rgb444be 19bc79cdbafee996eb48feea597d761e
+rgb444le de61209ae25f005d357b68e0836c4739
+rgb48be fa24415175a0759ac49949a948820f27
+rgb48le 82d5d55b03dfd9a74f0cc087793cdfc6
+rgb4_byte 7ec4d55df1bfb02ffa9956d85ade89f7
+rgb555be 34ef691ed2b6d22136c086d37bb0fefd
+rgb555le 04b20c057eed7dcaee1858d45500ba54
+rgb565be 077604cc5dc91008b018264db73c8f0c
+rgb565le a97549f25e63dd0dd404db41bbe05c07
+rgb8 a35d3c3b9b87261c7417076a8b18fdb8
+rgba 8ca9c8db589615ebbaa964be4ce62d08
+rgba64be 576dfc2fd1937f9e594c4004fafd83f2
+rgba64le 7938eccc1f05f13710ec351767b47a36
+uyvy422 8be40aded4b407ff66305911ba5ce2ce
+xyz12be ba8a8152ca6e8b338e1dc5ace0a729b6
+xyz12le 1f20849dcf44539ce351346c73bdff1a
+yuv410p 92112d85ba4f74cbd3044945c0f33402
+yuv411p b6b22000e5275c92baf5afc417c32a70
+yuv420p fca7fbbff753612a718ee13e1dfe2af2
+yuv420p10be 15c655b60ff5d212657e0620ed69fadf
+yuv420p10le c9c71c78e00034af1b0fdcfe68615c6f
+yuv420p12be a5377d262bd05698b2bbcfc8dd2b15ea
+yuv420p12le 7d076ea30985ecf2eb590041a45f2cc6
+yuv420p14be 7a33da52fed0ffdc7f90ebcb677dc155
+yuv420p14le f431bf16d8204fb919ba0abf4ea54288
+yuv420p16be 254b78ba00a928d22cba98380546fe9d
+yuv420p16le e6c182b47c3b57814d28248dbbaaea35
+yuv420p9be b1eafb2e864fa86c08684d8dd4628535
+yuv420p9le f07b2282c50f8eb6f138029d748eadfe
+yuv422p ffc2693b9e1d39b59aabb9a7e1dffe05
+yuv422p10be e83db7f2f485bea0ea808f22ffcdb7bc
+yuv422p10le bfd8fbeb5d89ba3904514d835aa6947d
+yuv422p12be 5f31197795eda7998a0ec813496e57f1
+yuv422p12le 903939621d457a034c0181032164b3c1
+yuv422p14be 8d08189d27d3a97fbecec7edd690c691
+yuv422p14le 01b717875b85707185acd48ac75dd6f9
+yuv422p16be 0feb24228cc5ec3963dc0bde913d14be
+yuv422p16le 0d6fe6924f14e77b2fef02e7ad1c47c8
+yuv422p9be 003b2032a30281845dfb6f9a7ebccc71
+yuv422p9le 427c505eb27af0059aeafffd1a858189
+yuv440p 23b55dcf6c876f0c53cf46960b13e6a3
+yuv444p 7730197c0570d46493d50bc163244754
+yuv444p10be 74b13f67114ac0f92af7bb427d6335ae
+yuv444p10le 9ab09ae4acc46a2fa04fdbde1373a9f9
+yuv444p12be 76320bae89f10947e692b6ce1fa22b93
+yuv444p12le a79e40c464df640ba97c13456616b25c
+yuv444p14be de7f737796d1de38a8227511b91d3378
+yuv444p14le 7c27d1b7846beb3565ce086c7df1131f
+yuv444p16be 1d51af32b9e077bf1ad750c6a1787b2c
+yuv444p16le 94a936f571861f25f2539ba099cafd56
+yuv444p9be 384dd0aa411d00b2deb2363a9f345db9
+yuv444p9le 77758bad5ca383b3a698fdcb38a85f20
+yuva420p 24337fc952d7f9c633756549a7b94146
+yuva420p10be f586830e7605b5bbc307f6f5c532958c
+yuva420p10le 7bc9e81d18021dbb7c96ceeef4a18090
+yuva420p16be 54362c9d57d26ead878b9eb05a523785
+yuva420p16le af55baa12d11c0ac6c9065df730d81ef
+yuva420p9be a290f1b1e1fe18ac22fed3535562ff98
+yuva420p9le 89d0fa6679548757044c0e1971c1cbfd
+yuva422p e3fe9f137a37e1b3817fe8579d2d2acc
+yuva422p10be 4aa77b690225054f9b5c7ce7c66950e8
+yuva422p10le e7c6538112fc1d9539f4635dedf52eae
+yuva422p16be 0e5a1b0b52d42f4f07d7e63dbe4ab83b
+yuva422p16le 5b3a1219d7224650929e6272693f1cd3
+yuva422p9be 9d6f936fa9666e2bcbada5188e2a4942
+yuva422p9le 0f97c4d357e103e7263705b918a37824
+yuva444p fe4dbba35f355d68b6c254c06db1cbad
+yuva444p10be 3926a29639556a11acc95888e29517d6
+yuva444p10le 1b68842a69b3b9d5a23854217b410c69
+yuva444p16be 45ec67a0828aedf18f1ed54fcfb0ff83
+yuva444p16le 7b8e5963f19e6fe7fd409b34af014489
+yuva444p9be 6d2905a9e61ce4ff5b3d7b972a7333eb
+yuva444p9le e2ffdb1d867a1b78f3bd38d600b17193
+yuvj411p 840bb5fc87ba0d3101d5c25b3f480923
+yuvj420p d1a8d9cf6b4035ac5d6439ab2754b09d
+yuvj422p d20df6138cdf62d7f3b93eb1277827d6
+yuvj440p 17a24a86f279febaebb66d65509088e8
+yuvj444p 326bb83d1aec23d941894a1324984c56
+yuyv422 f9121733169ca5437e95e7600a7c5aea
diff --git a/tests/ref/fate/filter-pixfmts-kerndeint b/tests/ref/fate/filter-pixfmts-kerndeint
new file mode 100644
index 0000000..2769319
--- a/dev/null
+++ b/tests/ref/fate/filter-pixfmts-kerndeint
@@ -0,0 +1,10 @@
+0bgr 58fb0bda60562ce17e75f1c3459d0504
+0rgb d29f6a7b63ade359ec81f5856633ec06
+abgr 71071045b8ec66a6d0a38bb3fed1ca51
+argb 93ba0daa1e945ad1a6f8c0c1cd2e1858
+bgr0 364b8bcd1c7a384902077bc7190c5ea3
+bgra 81ac8315a4c66e363bc6fa3e99d9cd2b
+rgb0 ae0c2afbc266345c1372276755595105
+rgba 42a6cc9b815ca0ee69c29db3616ce25e
+yuv420p 40ca042814882b0b791cbec38e289702
+yuyv422 f549c98059ba9ce50e28204256d13b5d
diff --git a/tests/ref/fate/filter-pixfmts-lut b/tests/ref/fate/filter-pixfmts-lut
new file mode 100644
index 0000000..387464b
--- a/dev/null
+++ b/tests/ref/fate/filter-pixfmts-lut
@@ -0,0 +1,19 @@
+abgr c1e31c876e806cbfa8ef58441d1dee6f
+argb 1239bf03999d8767c2e03863e22955a8
+bgr24 0ed1377b8c34489e716650edb593494d
+bgra 87a4b656459a5f8ee2a0e5a994c61439
+rgb24 a1466d9fc7d1726dda3bfe80dfcc1b44
+rgba 980b5fb376926ca9c5a0a5b82a0ab162
+yuv410p ec9e2e31c1c702676362f5445efd4354
+yuv411p 9caecd7961e1011db685cc4d60220fd1
+yuv420p 8796295e7d132dd0f616fed149633ad9
+yuv422p 2a3f79670546a0e582ab00cb83bb3b79
+yuv440p d7e3ffabdb376f49a02cd641907df726
+yuv444p 13ef53a3dd3f77516e2c5237bf43b0c5
+yuva420p 34c07d6c05233f333a933a50a3dbfa61
+yuva422p 352406873ef88f865af0f27760f37663
+yuva444p 8efb7b3d809946fdf01f3c426a6cdf83
+yuvj420p 5a8771944ba995a831ca272526f440e5
+yuvj422p ab379523c4e79ca1e3c72adc46b918ff
+yuvj440p 8e82847ed2f7a3a22ebdb2372e941fc4
+yuvj444p 4a98641643a7a51292c61c71e221ddc4
diff --git a/tests/ref/fate/filter-pixfmts-null b/tests/ref/fate/filter-pixfmts-null
index 23452ae..edb246b 100644
--- a/tests/ref/fate/filter-pixfmts-null
+++ b/tests/ref/fate/filter-pixfmts-null
@@ -1,89 +1,116 @@
-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
+0bgr a06d3a7652e4885c65895e0e168aab28
+0rgb b6b5653d2228cdf2ba3c55a72f2e713f
+abgr 1a147fa04ed70b9a7e67a4c89052f630
+argb 997df0b5c268a0d8f9c611cae4e01e05
+bgr0 218df6dc3eb5094a0c16a8bd18bc3999
+bgr24 d6370f6dc34df2ea66e1718baf74137b
+bgr444be aba6dfea008ae12c2120a95f54293904
+bgr444le cfb5401e8f076cc8675e17ed1114a3df
+bgr48be ab65229b64606f6408cd732b967c0b01
+bgr48le f1b4e718cadee9bd2978289153ce43de
+bgr4_byte de96505ef9ad7078f87b4dfdf6fe4b61
+bgr555be 8d5de9e9200d622f27dc73958a85045c
+bgr555le 74eb9837706143a40e26305a16a79369
+bgr565be 13a36d6502be88fc0c2aec05b8d2d501
+bgr565le ed027571692aecd522aa65a90cc7e09b
+bgr8 71ef789609c746c2e7e4be9dec29062c
+bgra 0364b074268682ea46168742a8239f7d
+gbrap 412a2449fdfaeb5ebdf5e4196cc7391a
+gbrp 4778f8cc2bdbcd65e272ea1761cdca6d
+gbrp10be 0be11fe4b2324054be6f949e81966691
+gbrp10le 173f89ae58fd4d01d6a365318e4da3b1
+gbrp12be 1f5231ed7e4589a3ec98fa79134bdc6a
+gbrp12le cc4830a263fecadeea535c4938b5cee1
+gbrp14be 6f5143374536e1cf1595260e91c86b7b
+gbrp14le 937ff1dd9f498b39f9e882316e371fbf
+gbrp9be c76ab5850c9bc72bbbf36caa6d1c5ac7
+gbrp9le 5ad363dc9570187ad3e3f2344fbb30cf
+gray 2ee2ea2340d0ecf2dfa6f90f87384799
+gray16be 389f4e5a8ab413b3af32767b59ed7f9e
+gray16le a1f912941247e45b394b9cf4f0e81130
+monob 309b5785a36bd988d17e15d88f4ffad1
+monow 8809a02bc69b58d1114b09ca79ebffad
+nv12 75e90c54d858b993e99f4ee6d2a2a38f
+nv21 8831a3f411015d45fbc5dd191245ba9c
+pal8 13de2a1c3c80cb64d14e2bc4f6f461d0
+rgb0 992f5ad24802cc255edab45c3084db4a
+rgb24 c71ba90f69f15c8275232bb3f62d0ced
+rgb444be 26eaec65d7efd2b0c9c13b47dfd9b241
+rgb444le 5f29863553107110ea817f52151d77b7
+rgb48be a3bc81c46c21818a989f23104a599ab0
+rgb48le e87c661ac49aea1f1e93939802883d92
+rgb4_byte 293b1b84f01efd90bde40cb3faffc127
+rgb555be 5229183fa64d4e5c7e3703d8263ee6ae
+rgb555le c3e9978cb2a4129a5575935e8cbc433a
+rgb565be bc123b962629ead1a06af0c18cbb6e5f
+rgb565le 20757fafe4756e62d845b2ab4c0b8f93
+rgb8 e01614f5416dcc8ad365ad7a57afc9fb
+rgba 53796fa4c392a1b2659595b6a284f8c4
+rgba64be c05fbb1ada1b48fb1eb192fc200af2b6
+rgba64le 1b826cc613666f545274e8a7799d69f1
+uyvy422 3f411f947e3ac8f842c88e717d68bd9a
+xyz12be b91ff224254afceb4a8f803d56eb52a1
+xyz12le dc524e3726ba1df0d2f406db3a2c08aa
+yuv410p 7dcf3f4770c8b494290ceacd2c2ce6db
+yuv411p 9461b188dab6f8b90d9a27e353a89f58
+yuv420p 61fffd2d8425759a33ae07e718d0242d
+yuv420p10be 2abf90242cb021cb6fcf9f2c3c92f6a7
+yuv420p10le 180b7e4de684c7225d2fb37614f842cb
+yuv420p12be 256c9e6cfc878a8abf681b30777c0620
+yuv420p12le 8dc8b86c4790da3769d4a62e87608623
+yuv420p14be 8d22756c5d2b9e501924c082bfb22a6c
+yuv420p14le c9da19d4818bcb119ad6481b75778f7e
+yuv420p16be 4ccdcca6dd6a960f9a3333f0aee095bd
+yuv420p16le 9c5847d9b0de258a10ee906dc47e24ea
+yuv420p9be fa7ad4f73232aac0e35def62af1e2c39
+yuv420p9le 3720ba1786b56c8f4913e67dddebbb07
+yuv422p eee223e92f1f2e5ad4186b411ebf5816
+yuv422p10be 80fa87750491dcc3e93d175b64835654
+yuv422p10le e1640cd315bd96c6b59f7753825a7306
+yuv422p12be 5c6d86e919515d1af71f8004a6252f9e
+yuv422p12le 7f331cadb0ab75d07656d29f47bd8bd9
+yuv422p14be 4f4e186ba683b90fe990cccc4db7e521
+yuv422p14le d78016c9119b1f1d1c922bd5aaf47732
+yuv422p16be 1f3c216927d17966a009a42def124bba
+yuv422p16le 90adbdffaeea9b09398339c8a1322b02
+yuv422p9be e46446534dd0821029d3b831c9c1d1b0
+yuv422p9le 520e418a2429f7efee511b7fcbf45ab6
+yuv440p 456d83524b299f2fa1bb988e421554d9
+yuv444p 068bc09d282d18c9fa35c2787943fc2a
+yuv444p10be 9f6e1490080a454243daee9229425e1e
+yuv444p10le cc183e51041351d9ac06c4df6e8ad5f7
+yuv444p12be 34f63ac6a47ac681016105d3bfb3e118
+yuv444p12le 7964701bfe8d718edf97f6e0002935bd
+yuv444p14be 4ad3a9d52fe9c050150c0f7d2f3cf63d
+yuv444p14le 69575e5a94b978f159c4fdb1a61587b0
+yuv444p16be 4000b12fa88ed0feef182da31c7e6b96
+yuv444p16le 96a857dba8dc6792c58daec872825b32
+yuv444p9be 07727e5c9040b7f0a17d591288ac330d
+yuv444p9le 4d12d20a68dc28618594c96c2ade4ff4
+yuva420p 3a8c5c142e051367c196f95696e0e2c3
+yuva420p10be 1b7c5ec6691498e24676ce6ed97f62f8
+yuva420p10le 4c13322bca914df2727da91cca85ca1a
+yuva420p16be 6afcf758f4b66c0b4173c942d42212d7
+yuva420p16le 13e195aa96329eb49921b6f9f07b875c
+yuva420p9be 05a78390de312dfd21ac666a9da05fbd
+yuva420p9le 78f5593bf51a31841ef83df41d0316eb
+yuva422p 45ae66d6f69fd5b77e6831e98d228bf4
+yuva422p10be 18284c58b926fe2389605c692a703145
+yuva422p10le b934d28b615729a24bebf0381c465e37
+yuva422p16be c3f7354b6013b43439e02aa02be5fe69
+yuva422p16le a7ccc43820683ab15061d14cf8efce6c
+yuva422p9be 14c55a16d19499b54b4341f135d3e558
+yuva422p9le a8bf168e5d2709222192d0aff46b1373
+yuva444p 86b05da54db8c7e8cf5b6638e19c6fc5
+yuva444p10be 8c417158165c00fbd42def60cbc27d69
+yuva444p10le 5f303ef3fb56faed69b4cc1c760ac6ae
+yuva444p16be 52a9591ec0d5059e49b1b2803f8582aa
+yuva444p16le a9272ac197e4a4195662ce90f533976c
+yuva444p9be f72f646ef07cdab613420585aba041ac
+yuva444p9le 6d431b0a27bf4f86ea44ef5f14247a01
+yuvj411p 037accc8e48ac9928a580cddf444f129
+yuvj420p 73661456012f20cda81207b14bb0c0a5
+yuvj422p aa97862b57f47c5a6506156e9aaf129a
+yuvj440p ff8b9884a49d546b035f5d2ac1e673df
+yuvj444p b8142888d80b8065c54045839e79b331
+yuyv422 f06a4fbbdb32807d05de825daa2c3a1b
diff --git a/tests/ref/fate/filter-pixfmts-pad b/tests/ref/fate/filter-pixfmts-pad
index 03db5a7..82f30b6 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 36ba5b43e0ac64d8daad4f897efd8cdf
+0rgb cc3ca0f63885af19b3daa4504cadcc19
+abgr 9ddb78f395d7d3f75b65b5309223c0c5
+argb e5fbb7bb282a80897b8f730627f68876
+bgr0 c55368036cccbb0af471d6bd82abe02a
+bgr24 67f9fd70dc6d9896b7122976b33932b4
+bgra c8dd017b5a3b55e8b9d0ac1cdcf327bd
+gbrap 8551b62534034c8aaebaa7d9fdefdfe9
+gbrp 9257834cbecf3842c2a6a820601a7504
+gray ca280f6888a9b66688b5f8ea68fe454a
+rgb0 b1977b45634c4db58a183a07feb2acff
+rgb24 e73de9dc0fdd78f4853c168603cc7aba
+rgba 5a36df3c5ba623b589728a5a442e98e2
+yuv410p ff246b8b41d3d4a3eb90414ae3031123
+yuv411p a82c606c665fa747679aa8bfffa8a5db
+yuv420p 0fe4d9031999f83ca96292ec2025f272
+yuv422p 5e0bffdac30b39f1bae9ec54fd9a6a34
+yuv440p 5e338303cd89d1d76ab918e5bec1e90d
+yuv444p 248bdf9747d5c3718580dc2279e2e273
+yuva420p b5bdefbb0c5b302b6d18ee4df7c1d7c7
+yuva422p 8b56b36d9eb3c382d2a5a695107e759d
+yuva444p 389cf95e98bf24684a42d5d67b913e16
+yuvj411p 5f10066e6a85d4785064ccdbb7259775
+yuvj420p d182ac937d312e4894c1bc548883bf1c
+yuvj422p 26ac91b5daf6f2f1f3c22be489e994a3
+yuvj440p 63e2b94f81e0a6f2868055a4c8258b63
+yuvj444p 64f103c7db8fc803d062db7ed2b8dc76
diff --git a/tests/ref/fate/filter-pixfmts-rotate b/tests/ref/fate/filter-pixfmts-rotate
new file mode 100644
index 0000000..0438aef
--- a/dev/null
+++ b/tests/ref/fate/filter-pixfmts-rotate
@@ -0,0 +1,20 @@
+0bgr 1040a5c4645582fc271f7be40ea5aaf7
+0rgb 7f21fcf8fd658de854b75dd8c47b0b00
+abgr 24f441d2e6e67cae2d3451aa1dad23a7
+argb 993002f41f621d04cd76278e466c03eb
+bgr0 efe11efe2840fa84ee95cdb913463bc1
+bgr24 d0f449e8b38e07c947bd808f441a8ace
+bgra 54cebf01881cb63ec3727f7cc23b0a6b
+gbrap 6d69c0cd0cba6300065f8d990e35b081
+gbrp db3b6345d2a5c0fb524f93486d97193e
+gray 5a896c38449a0fb08129a7394952eb31
+rgb0 c29f92ff5224044c7272c763fa5321e6
+rgb24 739f0eb47e76ce5c87354d5631ac2d5b
+rgba f25570a798f24e8174729d978872c272
+yuv410p 22e673170464119cafb1a973c5a8080c
+yuv420p afed4567a1b2d54ca9bc87bbdfff9a34
+yuv444p df57aba68928092b54f6b75ab01e3110
+yuva420p ad9bdb4f21855550a6f94e2d96588097
+yuva444p b6a345f46ef75814033f733ccb4da42e
+yuvj420p ccc0724c2ff91daa3848db1f4d91d010
+yuvj444p 9165b6e7c647c93cd24011d931890edb
diff --git a/tests/ref/fate/filter-pixfmts-scale b/tests/ref/fate/filter-pixfmts-scale
index 80816ec..d2c8574 100644
--- a/tests/ref/fate/filter-pixfmts-scale
+++ b/tests/ref/fate/filter-pixfmts-scale
@@ -1,89 +1,116 @@
-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
+0bgr a96ce0c378614d884139ec32d7b17fc0
+0rgb 70414c01ffbd3d420806c21b32a3158c
+abgr d507465437881ceea4dac96ad72bcfa8
+argb 95964959d3580719b6df04457ed091ca
+bgr0 46c2957c538060d305d82f3890f703e8
+bgr24 1d684e701a851dc502051d064b49552e
+bgr444be 9af6abe0bc74cdcc75b4ab2f441f5f67
+bgr444le b8c0e693ae2cbd7c03abcc3aeb4bf7b4
+bgr48be 3aa33b667b9baefe3f17ef44360688cd
+bgr48le eaf353ab363fbb279fd72d6c6e3b8855
+bgr4_byte 2f2c6b57017092b981ffcd4a9eb54d3a
+bgr555be 9d71206c1a5373b8978126e5f5779726
+bgr555le 025caaa21fed9d14c382cac26af778c8
+bgr565be fca6f07daf23d9dd84381dd4c9afd959
+bgr565le f524e9f16bdd68b247dbcb621e543fc0
+bgr8 2a6509639c181fb7829721bdbf78187c
+bgra fec5335edde2f1ee1f40d2fe4305855c
+gbrap 76ddf2bedea40c8743f4117b786d4773
+gbrp e2704defddf1cb8d75f0c80fec6491d3
+gbrp10be 7dce0805f7ead7d480bd83323d76bf9c
+gbrp10le 24b220d50ffcb3fdffe11ef63f0ea758
+gbrp12be 49ae16b634cd12b108c0ac153f053549
+gbrp12le 889da16199f9cf1449d93cc0ca8c5a15
+gbrp14be e63375705d6915035c7bce0faa4934e5
+gbrp14le eb6cb4555edb175d807fe1b5382d2fc7
+gbrp9be 2c9adb80abc16546cac69b4872aaf557
+gbrp9le fcfa1684553e3e185179462bca347649
+gray c45dcee08887f43dc463f79d7ecd7d68
+gray16be 70064f9acdc5e3935ccda67e765bf2fb
+gray16le 578241fb43029e5ae841a3c94d940dce
+monob 91ec2a25b13f6ca34d42da778b217de0
+monow a991455fda8f60f373aeb744456996b9
+nv12 0617f1e13ae4a43d4cb49282b9c02f71
+nv21 8a00d5d29766c1251eeda74c0ddee3f2
+pal8 c4101024891e078d67ae480e15c380b5
+rgb0 9bccae1af3f4c3e6a126c98a595a2481
+rgb24 64aeb63d9e9735277255eba4f7a47082
+rgb444be 88f534c5d07ebf5a4374484aed540893
+rgb444le c243685bfad7c243a78892a0dafe2b9f
+rgb48be 874c8e2305ce9d82165ffddf2854d1f2
+rgb48le 877075f2ff2d9a0aec6fec843385f126
+rgb4_byte 37dce6bf5eea65cbc8c934a047190048
+rgb555be 8aeefa1fc4eba200abee3b1eb52186af
+rgb555le 0495a7c13f9b0d0253379d5ae90cf6c4
+rgb565be 5168b66e69c25351948085e5fc51bb3a
+rgb565le 301a4d41f0db3aaed341d812ed0d7927
+rgb8 8f24090953a7616ff319aa981e32c1e2
+rgba aec2346373d91abdc8c0301b44513128
+rgba64be 5ce6f591ac8be4edcf5c3350d2d2d3f5
+rgba64le 12baab5162019de2053db39a3bfca868
+uyvy422 479105bc4c7fbb4a33ca8745aa8c2de8
+xyz12be 6769a0b3b3b6d7a674542c8cd3e3644e
+xyz12le b4f967df71db5c38c222f9236c341031
+yuv410p d0daa93f5cee83360e219e39563ab6da
+yuv411p e5c8f3ca024a88dd07e0a92db3e2133d
+yuv420p 485d9af8608f926ffffbf42230b4150d
+yuv420p10be e4f12002b46549779886f27fd3c6c645
+yuv420p10le 698b7a346ae6d1315280d3e28c86b973
+yuv420p12be 10ccb1da4f69f5578e017ffdaa19adf6
+yuv420p12le 4f68fcfeee4fb70ea941979cc6a39d1f
+yuv420p14be d7b1183a6ca2f5d80d1bddf609c35995
+yuv420p14le 934dbea61d804e7c66e805a45f1e3914
+yuv420p16be 6ebcf48a9317c6265430cd3ba5f569a2
+yuv420p16le 604a7215f384488a38aa0cffdbcbe17e
+yuv420p9be 7b293aec92897bf0a32ec3a02a20acf9
+yuv420p9le f37fdff7d6c62ebe2ab0cf791cd049db
+yuv422p b1724528079199908c667b3428a7c01c
+yuv422p10be 1c7281254fb980c123148dfd145c4a05
+yuv422p10le 959caa253354e897f01848db21b8006e
+yuv422p12be 9e1db2326fb3dd3a8f8d32f3a6f61305
+yuv422p12le 5a4aecf4baf74358551e75fd7f1549cd
+yuv422p14be e75088b934f86ddb6a7ff1749b77687c
+yuv422p14le 2cdae3e0447b35ddee6161639107205b
+yuv422p16be 4ccc3e0bc94eaf3a3350e4d694c3a56c
+yuv422p16le dde889032f13fa5f8d76b8484dd73116
+yuv422p9be ba5eae7669d02a13f54a592344612098
+yuv422p9le 2deb39425d924a15c8946df79ceaa579
+yuv440p 19de0ba1fd354b42189e96cdf73ef7cc
+yuv444p fba8a00cd0b182af82e9de3b2f4d2c8a
+yuv444p10be db89397ac4d33e66b5eab3678661f73a
+yuv444p10le 28208677f07d4e4191ef228c096f3297
+yuv444p12be 55d291347d13f98b520c7d0cf7e0bdfe
+yuv444p12le fd12d6054262cebda2a9b1a2ac4dac98
+yuv444p14be a078f34e001828d576e748ca0850af56
+yuv444p14le d02ba5c47b0bbb359df8ef478aa4c395
+yuv444p16be 07e27200d2f4382090ca260874f02e92
+yuv444p16le f8bac16bf1f2afbd3626e07bcc815a9f
+yuv444p9be db739906e3ae3b8792cdc5a0c3387565
+yuv444p9le 693b8d30958ef1a37296b1690b4b36d2
+yuva420p df46b738bdaf30d3a7f880b5ae45b092
+yuva420p10be 8e5f3b069fdf2f0c14f49ad827991092
+yuva420p10le ce4ac1961e0466c40448353cf76b3282
+yuva420p16be aa8ca29a93936c62ef038ca8a57f47d7
+yuva420p16le ee0cbb31f9cdb897c1982df0caa8ffa0
+yuva420p9be b8ca5603123aeb953b9d4fc8ec8e35e1
+yuva420p9le 220212a81cda0f2d112f7ae96d532ff9
+yuva422p 650755270debb03d2c03b2e93b64c576
+yuva422p10be 8d077362542a73c72aadb885510ea0c7
+yuva422p10le 80f729d9f8f438d2ab87909797c27873
+yuva422p16be 0b8f9385498d2449b18fb15237b0a448
+yuva422p16le ce22b20deb93b4846a5043aa104f22d1
+yuva422p9be 822df465d12916d8852340d6b56247c8
+yuva422p9le f69c09e872838fe392dfe1825263d3f1
+yuva444p 72083e0941cc45af9f97b89d3cd16112
+yuva444p10be 42e159c62771239fa14d06a2db3b357d
+yuva444p10le ee9786aee055c39da2dfbdb91ab834b5
+yuva444p16be 36a8797545163c24fc0d73f669c3108c
+yuva444p16le c017c229aacb832a12c2297fb080a7a0
+yuva444p9be 8bfb5decfc8b71478b090a5b48c316c3
+yuva444p9le 2c7bfb90f7db9faab6862537801e1143
+yuvj411p 4e37fb8600e001c387bc67cd8cf8ce33
+yuvj420p 31386dce60a2dcc493da5d0ed9d880df
+yuvj422p 492452e50a3fe66724840cad29be4098
+yuvj440p 7632893e81d3f4f3ace3755f97479897
+yuvj444p 389388dd5d623f660c30ab840807ce82
+yuyv422 518be9b5ac93c365c0962453770fbe73
diff --git a/tests/ref/fate/filter-pixfmts-super2xsai b/tests/ref/fate/filter-pixfmts-super2xsai
new file mode 100644
index 0000000..964d04a
--- a/dev/null
+++ b/tests/ref/fate/filter-pixfmts-super2xsai
@@ -0,0 +1,14 @@
+abgr b04e3dfb0043f6eb04a573d2d13052eb
+argb 257e33717d23298430025c0665642cd5
+bgr24 3765d88f93d4ae8baa2cfbc64b0b32e1
+bgr555be 81832e6269c509be55bba49bdd0ebed5
+bgr555le 56772e91aefba4013890d156866730ce
+bgr565be 0b3c420fbddcec5a420c285b3c4b8792
+bgr565le 6cbded26d2bab8204afe2115384c09a8
+bgra c81430c3d1465e37b6acaa19cc54e932
+rgb24 9899359a817e705dc5b9cc363d35a625
+rgb555be 9b60d9aa1f3c78edf9936894f37e3243
+rgb555le 917fa8565f35882404a45fee3a947bf7
+rgb565be 12edaab49440fbb3aa4c1835fd697745
+rgb565le 5bf91cb1767066f23f0c672dedb4d476
+rgba 71687289b6c3ab6fa727d468de459026
diff --git a/tests/ref/fate/filter-pixfmts-swapuv b/tests/ref/fate/filter-pixfmts-swapuv
new file mode 100644
index 0000000..7bc3e3d
--- a/dev/null
+++ b/tests/ref/fate/filter-pixfmts-swapuv
@@ -0,0 +1,62 @@
+yuv410p 5b295ab25ea56129be1a901d19b14f94
+yuv411p d764e5278d2745f497a099468ce08f6d
+yuv420p 7c44249ab61c7974edd269966884a357
+yuv420p10be ffe06addb7ffe7742ff885bffccda9d9
+yuv420p10le 285d971c468cad73a4d9669939ee942d
+yuv420p12be 2f7e4da722d45a757c5fb38031685165
+yuv420p12le 9db66b795b28e654136f8a5170482b4a
+yuv420p14be 35b9055f4b92a78a9b312f1471ffa270
+yuv420p14le 61817af578e8c6b5cacb120dca9008b0
+yuv420p16be 75e0bbe9a4f29e96eeae88207208827e
+yuv420p16le 340538ba047c5739242cd043d1f6c67b
+yuv420p9be 5e5bf3d0249cf5cdbd31bb58746e766b
+yuv420p9le 8adc79b7768cc8f7220381c3fe8f3090
+yuv422p 6c2d87652f18bc1b0e40cf794a061bd2
+yuv422p10be 711e7e00ab91aeee82e18ed84117345a
+yuv422p10le cdb2c605b45a3ce840dc967bcca5893f
+yuv422p12be ff378d3990ef37e6b43aee27880be256
+yuv422p12le 9e023fe6f0fc4626e3b2733326c8ff34
+yuv422p14be f9f144674eb0b6945d9e7c8c3f84e2ee
+yuv422p14le dc7fc4fcbc9b571f357df173d3521f98
+yuv422p16be 45a44b3298488c4979a5c184c95720f8
+yuv422p16le 479e36c10a498669ea003192289eee85
+yuv422p9be 37eaf23d5f5a331e949f7b4ec50a44ae
+yuv422p9le 267710ff84ef671419982f04cc111ad6
+yuv440p 5cd5fd358c63e130eacb77867c486f7d
+yuv444p 22bf5f86ca3e9fff950d2b2ea6da65be
+yuv444p10be 97a809d37853acb4864ef75f6e3aff24
+yuv444p10le 5081c59d16157eabc73d49c6b903d530
+yuv444p12be 183bff4f9470a4d4f980aac98a9181e7
+yuv444p12le a57dc2f043659d1d1c7260b76e5d8745
+yuv444p14be a0fd8199b6a05e799c3646e6dacff968
+yuv444p14le 1107f410652e9ecb4540b3d896c1252f
+yuv444p16be f285bda960402c031303d8da5ab2f5f6
+yuv444p16le dd72a55624c37d955bc66f54dd7d0770
+yuv444p9be 02fac80656a1aa16573ac89bf3bcb2ae
+yuv444p9le f9009efe8e174f7b62edd9496d375af9
+yuva420p 99559efdc598a611e8a445726aae52df
+yuva420p10be 5ebfba649292669bf4a42ae812811ac9
+yuva420p10le b3ca09bde07e20e6674390f7946b6e93
+yuva420p16be 10d49b187aa0e9f6980c0fe2583a403f
+yuva420p16le 8520c00011f8040ce3d760b4d73bdf40
+yuva420p9be ab70cda1f3ae2822a70e84fec2130f6e
+yuva420p9le 70b5fc0e4b4d48c36530ea4ef1e3353b
+yuva422p 05fb65386a03cd61094348b15cd4bc8c
+yuva422p10be 3ffe3b85704883bbf9666b06afa0e1dc
+yuva422p10le 47a89fc53f0777f8cb973ccd25f2f09e
+yuva422p16be 805df2b4709283b34002b25e2e229e0a
+yuva422p16le 675315e192ded36ccec229a4aea28e89
+yuva422p9be aedf684bcacc4e2375622ba9fd4f3846
+yuva422p9le 41aa087d23cfa8fae5a4e6406442fa8f
+yuva444p 70d4cba3980d5a1c16d5c29526e71ee5
+yuva444p10be a0e80fe85810531348352b47ba4b712d
+yuva444p10le c0caa122748be4a1467ce0f0600165cc
+yuva444p16be 5722e1a5b09b3808e5bbd9a7db1add49
+yuva444p16le 342725e837355d66019ec05ffa5b6c4c
+yuva444p9be bcea6ad30ced293dbba9d7a6780d52ec
+yuva444p9le bbd56cf86dadd7db8625d3679c6acc45
+yuvj411p 8c6457a0ec6d796884e88f88ae17c9e3
+yuvj420p 06d3226d86dbd01cd359d8a1507d0e6b
+yuvj422p 8f87a2f4261297545b53b3f237c5bf1a
+yuvj440p 92c7d84f41d703878ae53911d03d23c9
+yuvj444p 1eda19f660d5902e047bb8c43f182fb3
diff --git a/tests/ref/fate/filter-pixfmts-tinterlace_merge b/tests/ref/fate/filter-pixfmts-tinterlace_merge
new file mode 100644
index 0000000..2dba4ce
--- a/dev/null
+++ b/tests/ref/fate/filter-pixfmts-tinterlace_merge
@@ -0,0 +1,14 @@
+gray 6575994300fa6c32755e68a9c7398247
+yuv410p c9bad1317b496071d6d895238638e07d
+yuv411p aeab23fbe2fa1a509fb45d873759819b
+yuv420p 9794d11e59ec7bcdf9e30a433e4137b1
+yuv422p e852e61e455db8ee3981ea942d510b0f
+yuv440p 7d74a024260b8676492cec372293c64a
+yuv444p a38a3f65d2f358cde5e9547c897cfcd5
+yuva420p c1dc15d6ee78587d9f825acd795673d7
+yuva422p efba80640dc04e9cbb27078ce084d397
+yuva444p 3e4158d682df2da3d07134946d082f67
+yuvj420p 3ee7014727ee64b45292a4f15ba028d8
+yuvj422p 4f990d5473f15571276adb5770b3b773
+yuvj440p 9a005e8b8431aaa762fde8d942fd11a9
+yuvj444p e29bf9f42e3a3632e09df529979e0040
diff --git a/tests/ref/fate/filter-pixfmts-tinterlace_pad b/tests/ref/fate/filter-pixfmts-tinterlace_pad
new file mode 100644
index 0000000..f642e3d
--- a/dev/null
+++ b/tests/ref/fate/filter-pixfmts-tinterlace_pad
@@ -0,0 +1,14 @@
+gray 28646014a43963751d1862332972f60d
+yuv410p 17163d1b4f21d894598fc62e6aeb8141
+yuv411p f4d71c30c21d6a6f99079f7dd83abc6b
+yuv420p f8bbae33295741c1c17d33ff8ee16f7f
+yuv422p 4fa67d1580d3453942bb0950c5784f6e
+yuv440p e0ee9b11a8cb7b95f82d91235593d49d
+yuv444p f0558305fb7ca65b5b86d3ee88c4201e
+yuva420p 7c76c0ca03a62275d25e8140c68da2b9
+yuva422p 0e4295715852540e26188a4452d5d215
+yuva444p 59d5236aeac03a6bbef7c536a22d18b6
+yuvj420p b5b7baf11946a2265fc56e48be5b0436
+yuvj422p 2e70ab700851d12a773f926bb1785235
+yuvj440p 93319f9c8a02ee793966fae40f7e42fd
+yuvj444p 81a124fffe0214bee5205c90ae0dd201
diff --git a/tests/ref/fate/filter-pixfmts-vflip b/tests/ref/fate/filter-pixfmts-vflip
index f0ad5eb..83347b5 100644
--- a/tests/ref/fate/filter-pixfmts-vflip
+++ b/tests/ref/fate/filter-pixfmts-vflip
@@ -1,89 +1,116 @@
-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
+0bgr 30d1f7d7081c012556da0373e6d389ee
+0rgb 66cd838e9c19f750c61efd73f66c42ac
+abgr e6cc18ed21293e455d1dc63f9e1645e4
+argb b5383d783698a0b3d753d01f2498e490
+bgr0 f99729e70a94d1c278c292a7acdddae5
+bgr24 c48ec71c68a9840572a548c2ad141028
+bgr444be ab9253d2f836f58ff8f3f2b4ec76abdc
+bgr444le b1bd8245a286b615e75e10d34fda4e62
+bgr48be b5355b4fa578b9422288507cf7fba2b6
+bgr48le 11dc232500b6339f58a9981f46d1d7a9
+bgr4_byte 531fd9a2249a213c89b1afc9788d070e
+bgr555be 54ba55dc1dcc5a7f27f2727976be6583
+bgr555le a45c637fe5ce84b238b1e6f66fc8c852
+bgr565be 7100c2ddfee42e7efafec1ccefecf7c6
+bgr565le 9fab295d966386d4ef99d5b43066da47
+bgr8 275ce12eeb05de67a6915f67cbb43ce5
+bgra d29c35871248c476c366e678db580982
+gbrap 29844a8e4334493fdd2d499bcb532535
+gbrp d3f2823513bfdac8f714385513cc396b
+gbrp10be 49b93ac01777e4bafcb9afd4d9d74533
+gbrp10le 61c0cbb0978d26494d3a233042e1e256
+gbrp12be 36f58621c2a10141cdae56c82cd99946
+gbrp12le 33dd0c50bc6c9cec92e8afcce076dff3
+gbrp14be 488b314f58b3e41d67c1b093ce19a7fb
+gbrp14le 48b4273ff29b6b68a05a6027254ff75e
+gbrp9be b4361a1ad66cdff0d32d4af769a8a960
+gbrp9le 5bc148ca18ff1bf7095e78a4e65ed8ab
+gray 800813149a825964025e75cf14ec528b
+gray16be 9b23f3e79c54a6ccb62e0135a32e3045
+gray16le 93cfa8fbb2a86ead275ce1817444e6d5
+monob c395a8efb9477b4ec53a77326e41ccd7
+monow efaee1c763ccd5ce1a8519d2ed5aa5a9
+nv12 77373304a9c732b65dab0a33afba9295
+nv21 1e70b3ce8be75f91f465a6d62df550c3
+pal8 be51ffaaad8e8428f2ce1e10d5729d3d
+rgb0 84a83e576fc59ffd1ac5549fd7aa0023
+rgb24 a00171a51cbbdcc61ecbd0198b2e2513
+rgb444be 09a819863d3fe75518376cdac01c069f
+rgb444le 4ab35fc85b8550be2a9b96dec9bf7306
+rgb48be 97a30a902d26b4840235926dae9028dd
+rgb48le 82b33a864bab70d5463d57eaf693e78c
+rgb4_byte afbfab537406988eab7460ec748a0389
+rgb555be 95e417e9429622245e2d2e0b1c3ab3e4
+rgb555le e4b35d8e9c1710f6d051fb4bda8700cc
+rgb565be c70d86afbd68a073f2d4fe0eee3a9832
+rgb565le 991576c5d3308a73068a826543b3e7af
+rgb8 42230235c5a2a66c0f9a2fcd20f9f5cd
+rgba a6973a2940a378d2a8284194da26eec0
+rgba64be 52ee01b66ee3d52e4726a12fbb819950
+rgba64le 60541d81afcea71a27629c4e5d137dcb
+uyvy422 21c48162379321bb83ec2399535f9253
+xyz12be 7070af64e30fa689e3627b1dde7506f4
+xyz12le 4c4b31100b836638e7e61181997c49e1
+yuv410p 8699f50c04f8ac931aa5a8306827364b
+yuv411p 47af34559b92b68851df4c2b170f7736
+yuv420p c59b35b82b5a195128736021913b35a4
+yuv420p10be fc5eed1744cdd033728362772a450e32
+yuv420p10le 141e6b39adac979765c846f3a5a8293c
+yuv420p12be 0e0145d3592d56362c1bcc62cbd78a78
+yuv420p12le 8c3a2b27126df203786d4e05fd79e269
+yuv420p14be 6a11c75aa378f9628cd8fc3339474e68
+yuv420p14le e8b683876508bc0371582e2b8c0eb191
+yuv420p16be c467fae3a1936f3f91c19dd1c0c63e49
+yuv420p16le 87f09595ac106e694c538382179bfcc5
+yuv420p9be 31bc440f64fdd8d9e7cba897881345ec
+yuv420p9le c6fed3016f03c49aa01bdcd63f846d3a
+yuv422p 5e48541d3e659046ac0e1eacb038485f
+yuv422p10be 9097b4d06f1fc598375b7c6480a2ba50
+yuv422p10le da7bd36f65cac06bd54bc9857493d835
+yuv422p12be 9c0fd650ec9872fbe06e82dc41a7399f
+yuv422p12le 3bdb982268c06b8876e206d8b89b4583
+yuv422p14be bb0fc25212c2aa9f273aad2d562c3384
+yuv422p14le 1f89e82da25ce459db456ed27631054f
+yuv422p16be 95ed65e718929dbeb5092bf0d852026d
+yuv422p16le c62e554dde4a170177bec2efc3f4f1a2
+yuv422p9be b249cd58eaab5ccac6bae3e184774362
+yuv422p9le 696fc2a55f155edaaa9fc289574b2bb8
+yuv440p fca8395b7e43e2d0f38dd6ba822ef747
+yuv444p 1ef971a434c53e81c578e3c7cb9cbcad
+yuv444p10be 3114a7469c2b9c440a9a9ccbd6e167d6
+yuv444p10le 34cb8774a1eb627b5f32825ac7d0ae9a
+yuv444p12be 2fd83655c3223d176243d7ff871df3cc
+yuv444p12le cfec541fde2894656f6b3401177b7604
+yuv444p14be 11671a128afd177e5eda13bd2e93ac26
+yuv444p14le 5aefe5d3f78e4f3b86ed7041a20f9b8e
+yuv444p16be 35340098dc6956c34afce17bc6ffcedd
+yuv444p16le 201e3acfa6f7628dfe2a1663de1128b1
+yuv444p9be 6143c321929ade9e0bc93ddea926e936
+yuv444p9le e43ba2026848ec803fabf74d77c10125
+yuva420p dc8fd115eaf203a3eac351b92a7d8f18
+yuva420p10be b3aaa8a5c9b9c3c9d66053159af3ec99
+yuva420p10le f7a8ae85fcac45db1f1689a1ab7cc63e
+yuva420p16be b5c54895e87521f65a298d33bab5eb08
+yuva420p16le 95e208bc6644e23a2126ac5fca085f06
+yuva420p9be 1ba55d16f060bf54698dd7200523b44f
+yuva420p9le 4b57b8bd1534743f6740502c74bef385
+yuva422p 6091f9c62a121c09eadb02e9173b2da2
+yuva422p10be a6e8352978f263ea89e63ad06a9339b1
+yuva422p10le ee39cfa1d29c294dc096f739bf454478
+yuva422p16be 3fa019b3d5e6dcb7c8e338837b9cffe1
+yuva422p16le 871f244989e14f5d3eda45abb6b3dfd1
+yuva422p9be 923c816778f782ff8a56bcd1b14ef08d
+yuva422p9le bd882d40af0369d9ef7891c8e7891024
+yuva444p 9a55e83047abcc7a709f20805070135e
+yuva444p10be 6258901ef2ddfdb526a1038d92e8b63c
+yuva444p10le 24b8ef0f63e60f0f0a4d47a5870ad773
+yuva444p16be 4699a802e8ea3e74e968122980c0b0b0
+yuva444p16le 6f54a8cff38c54a235b92a0f1314e0aa
+yuva444p9be 7472bb4b0c774d5d741035086d5e4330
+yuva444p9le ae11ddd5a3e8d69a36989f6f2a8897a1
+yuvj411p be518349f35aa67e048b854ff2da60c4
+yuvj420p 200b0332de9944e76c94d2e0699a5a2d
+yuvj422p a19a89ef145305cf224ef5aa247d075a
+yuvj440p 4240c9348d28af5f3edd0e642002bd2c
+yuvj444p 9e11298ba9c4faae0f5c81420d2123f2
+yuyv422 867fff568fa4170503779c48e5f25e6e
diff --git a/tests/ref/fate/filter-pp b/tests/ref/fate/filter-pp
new file mode 100644
index 0000000..1f7efef
--- a/dev/null
+++ b/tests/ref/fate/filter-pp
@@ -0,0 +1 @@
+pp 62a6acf1969155f29249fd0757540f9f
diff --git a/tests/ref/fate/filter-pp2 b/tests/ref/fate/filter-pp2
new file mode 100644
index 0000000..b32bd1a
--- a/dev/null
+++ b/tests/ref/fate/filter-pp2
@@ -0,0 +1 @@
+pp2 efcfe545df8f869e3a93ae25a3e08967
diff --git a/tests/ref/fate/filter-pp3 b/tests/ref/fate/filter-pp3
new file mode 100644
index 0000000..ccf2eeb
--- a/dev/null
+++ b/tests/ref/fate/filter-pp3
@@ -0,0 +1 @@
+pp3 39af1a30d0ea0e906df264773adfcaa6
diff --git a/tests/ref/fate/filter-pp4 b/tests/ref/fate/filter-pp4
new file mode 100644
index 0000000..0557ca6
--- a/dev/null
+++ b/tests/ref/fate/filter-pp4
@@ -0,0 +1 @@
+pp4 d79a3727359f62747edb82cc92ed040b
diff --git a/tests/ref/fate/filter-pp5 b/tests/ref/fate/filter-pp5
new file mode 100644
index 0000000..4265566
--- a/dev/null
+++ b/tests/ref/fate/filter-pp5
@@ -0,0 +1 @@
+pp5 5dc5a1f0c67d8a78e32cf50f47d1b27f
diff --git a/tests/ref/fate/filter-pp6 b/tests/ref/fate/filter-pp6
new file mode 100644
index 0000000..ca40024
--- a/dev/null
+++ b/tests/ref/fate/filter-pp6
@@ -0,0 +1 @@
+pp6 40fb584b10082dff87fb947a1bccdbef
diff --git a/tests/ref/fate/filter-scale200 b/tests/ref/fate/filter-scale200
index 17103a2..f267522 100644
--- a/tests/ref/fate/filter-scale200
+++ b/tests/ref/fate/filter-scale200
@@ -1 +1 @@
-scale200 aebdc1c3e08da2a925ba7212b1fadee0
+scale200 e84ce966038a9f8f915704959f64278d
diff --git a/tests/ref/fate/filter-scale500 b/tests/ref/fate/filter-scale500
index 93ba4f2..ec4a699 100644
--- a/tests/ref/fate/filter-scale500
+++ b/tests/ref/fate/filter-scale500
@@ -1 +1 @@
-scale500 ef865c51156e55ce1ce38c8f90a709e6
+scale500 24e89b23ba4286162c2026181db8d2b7
diff --git a/tests/ref/fate/filter-select b/tests/ref/fate/filter-select
new file mode 100644
index 0000000..a9d2be0
--- a/dev/null
+++ b/tests/ref/fate/filter-select
@@ -0,0 +1 @@
+select 7975bb8d0e326af9369379927324f1a6
diff --git a/tests/ref/fate/filter-separatefields b/tests/ref/fate/filter-separatefields
new file mode 100644
index 0000000..46cb470
--- a/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..5bc7d5d
--- a/dev/null
+++ b/tests/ref/fate/filter-setdar
@@ -0,0 +1 @@
+setdar 04b06d4622b116cdae756d4b475b9d5d
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..86592e8
--- a/dev/null
+++ b/tests/ref/fate/filter-setsar
@@ -0,0 +1 @@
+setsar 04b06d4622b116cdae756d4b475b9d5d
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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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..5cfbf50
--- a/dev/null
+++ b/tests/ref/fate/filter-thumbnail
@@ -0,0 +1 @@
+thumbnail 33c479d5701943253df5e6adc6bc8746
diff --git a/tests/ref/fate/filter-tile b/tests/ref/fate/filter-tile
new file mode 100644
index 0000000..376acfc
--- a/dev/null
+++ b/tests/ref/fate/filter-tile
@@ -0,0 +1 @@
+tile bfd98570151154d078b14398f867f0e8
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..ee49247 100644
--- a/tests/ref/fate/filter-vflip
+++ b/tests/ref/fate/filter-vflip
@@ -1 +1 @@
-vflip 2e6d6062e8cad37fb3ab2c433b55f382
+vflip c59b35b82b5a195128736021913b35a4
diff --git a/tests/ref/fate/filter-vflip_crop b/tests/ref/fate/filter-vflip_crop
index 6bb832f..43c944a 100644
--- a/tests/ref/fate/filter-vflip_crop
+++ b/tests/ref/fate/filter-vflip_crop
@@ -1 +1 @@
-vflip_crop 72ee0d0dfc8af0cd94a466760313654d
+vflip_crop cd56578bb7e89ca0853467dfecab244b
diff --git a/tests/ref/fate/filter-vflip_vflip b/tests/ref/fate/filter-vflip_vflip
index b719745..f401fc7 100644
--- a/tests/ref/fate/filter-vflip_vflip
+++ b/tests/ref/fate/filter-vflip_vflip
@@ -1 +1 @@
-vflip_vflip eba2f135a08829387e2f698ff72a2939
+vflip_vflip 61fffd2d8425759a33ae07e718d0242d
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/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..b93adca
--- a/dev/null
+++ b/tests/ref/fate/force_key_frames
@@ -0,0 +1,4 @@
+5423335cd809e631a2e03f97585348e0 *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
--- a/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
--- a/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..6abb565
--- a/dev/null
+++ b/tests/ref/fate/gif-color
@@ -0,0 +1,174 @@
+#tb 0: 1/100
+0, 0, 0, 1, 188356, 0xf0944065
+0, 10, 10, 1, 188356, 0x146ed4c4
+0, 20, 20, 1, 188356, 0x96866a6f
+0, 30, 30, 1, 188356, 0xe15e1f1c
+0, 40, 40, 1, 188356, 0x0662c1d0
+0, 50, 50, 1, 188356, 0x88fa6cc4
+0, 60, 60, 1, 188356, 0x3cce2f71
+0, 70, 70, 1, 188356, 0x1510f9f3
+0, 80, 80, 1, 188356, 0xf27e9fa8
+0, 90, 90, 1, 188356, 0x0f4b64a2
+0, 100, 100, 1, 188356, 0x3d2714a5
+0, 110, 110, 1, 188356, 0x392ce45d
+0, 120, 120, 1, 188356, 0x2eadb79f
+0, 130, 130, 1, 188356, 0x68109314
+0, 140, 140, 1, 188356, 0x4eca71ac
+0, 150, 150, 1, 188356, 0xa9aa5907
+0, 160, 160, 1, 188356, 0x2a5d08c0
+0, 170, 170, 1, 188356, 0x942bba84
+0, 180, 180, 1, 188356, 0xbee38983
+0, 190, 190, 1, 188356, 0xa0d65a5a
+0, 200, 200, 1, 188356, 0x47270bee
+0, 210, 210, 1, 188356, 0xc020dc40
+0, 220, 220, 1, 188356, 0x978dbc8f
+0, 230, 230, 1, 188356, 0x6b1e9f1b
+0, 240, 240, 1, 188356, 0xd8078bf4
+0, 250, 250, 1, 188356, 0x94ca7bd7
+0, 260, 260, 1, 188356, 0xac745e77
+0, 270, 270, 1, 188356, 0x73154f2c
+0, 280, 280, 1, 188356, 0x31200601
+0, 290, 290, 1, 188356, 0x6525dd42
+0, 300, 300, 1, 188356, 0xa29b985a
+0, 310, 310, 1, 188356, 0xe3e074d8
+0, 320, 320, 1, 188356, 0xb87b3222
+0, 330, 330, 1, 188356, 0x5b9a11f2
+0, 340, 340, 1, 188356, 0x25f7f8c9
+0, 350, 350, 1, 188356, 0x0235e93c
+0, 360, 360, 1, 188356, 0x2a42d643
+0, 370, 370, 1, 188356, 0xfb7acddb
+0, 380, 380, 1, 188356, 0xecbbbf5e
+0, 390, 390, 1, 188356, 0xeba4bc9a
+0, 400, 400, 1, 188356, 0x4317b36b
+0, 410, 410, 1, 188356, 0x7316ae1a
+0, 420, 420, 1, 188356, 0xb5ccad05
+0, 430, 430, 1, 188356, 0x38afb0dc
+0, 440, 440, 1, 188356, 0xf11cad55
+0, 450, 450, 1, 188356, 0x3d77b400
+0, 460, 460, 1, 188356, 0xf084b9b9
+0, 470, 470, 1, 188356, 0x02a4c584
+0, 480, 480, 1, 188356, 0x14f4d52e
+0, 490, 490, 1, 188356, 0x55118432
+0, 500, 500, 1, 188356, 0x4ad82e9f
+0, 510, 510, 1, 188356, 0xc6eafc52
+0, 520, 520, 1, 188356, 0xf4bdc575
+0, 530, 530, 1, 188356, 0x8429689e
+0, 540, 540, 1, 188356, 0xaa23019e
+0, 550, 550, 1, 188356, 0xaf52c3a5
+0, 560, 560, 1, 188356, 0x1d387c32
+0, 570, 570, 1, 188356, 0x543d5cd2
+0, 580, 580, 1, 188356, 0x8cdb399c
+0, 590, 590, 1, 188356, 0xcceb292f
+0, 600, 600, 1, 188356, 0xa87115e8
+0, 610, 610, 1, 188356, 0x9665ec8f
+0, 620, 620, 1, 188356, 0xad99baf4
+0, 630, 630, 1, 188356, 0xc6e5a2b5
+0, 640, 640, 1, 188356, 0xe2a48359
+0, 650, 650, 1, 188356, 0x3a270df0
+0, 660, 660, 1, 188356, 0xcc34826b
+0, 670, 670, 1, 188356, 0x15ec2dcc
+0, 680, 680, 1, 188356, 0x8874c5f9
+0, 690, 690, 1, 188356, 0x829966e8
+0, 700, 700, 1, 188356, 0x691f1ebb
+0, 710, 710, 1, 188356, 0x00e3e184
+0, 720, 720, 1, 188356, 0x97739332
+0, 730, 730, 1, 188356, 0x507769aa
+0, 740, 740, 1, 188356, 0xddfb3069
+0, 750, 750, 1, 188356, 0x7296f749
+0, 760, 760, 1, 188356, 0x0555ca32
+0, 770, 770, 1, 188356, 0x4554c683
+0, 780, 780, 1, 188356, 0x2398c10f
+0, 790, 790, 1, 188356, 0x1c5ccfa0
+0, 800, 800, 1, 188356, 0xa580f3c8
+0, 810, 810, 1, 188356, 0x4fadea78
+0, 820, 820, 1, 188356, 0x4a57db38
+0, 830, 830, 1, 188356, 0x9e98df6d
+0, 840, 840, 1, 188356, 0xfeb3dec9
+0, 850, 850, 1, 188356, 0xbf16ef7a
+0, 860, 860, 1, 188356, 0xdc23fc48
+0, 870, 870, 1, 188356, 0x3bf2e401
+0, 880, 880, 1, 188356, 0xc832bcf4
+0, 890, 890, 1, 188356, 0x977db44f
+0, 900, 900, 1, 188356, 0x18d39d96
+0, 910, 910, 1, 188356, 0x9adf60d8
+0, 920, 920, 1, 188356, 0x567b667a
+0, 930, 930, 1, 188356, 0xd4a45e8e
+0, 940, 940, 1, 188356, 0x94a24cc7
+0, 950, 950, 1, 188356, 0x086f0a53
+0, 960, 960, 1, 188356, 0xcbf3ebcb
+0, 970, 970, 1, 188356, 0x1a40a7b9
+0, 980, 980, 1, 188356, 0xe16d8964
+0, 990, 990, 1, 188356, 0x3edd7dfa
+0, 1000, 1000, 1, 188356, 0xba417fa5
+0, 1010, 1010, 1, 188356, 0x734a7611
+0, 1020, 1020, 1, 188356, 0xfa1e7b1e
+0, 1030, 1030, 1, 188356, 0x1af23355
+0, 1040, 1040, 1, 188356, 0x28d41390
+0, 1050, 1050, 1, 188356, 0x2838c58d
+0, 1060, 1060, 1, 188356, 0x4e2ba2a8
+0, 1070, 1070, 1, 188356, 0xcedc99ae
+0, 1080, 1080, 1, 188356, 0xb06ba12d
+0, 1090, 1090, 1, 188356, 0x38c997b6
+0, 1100, 1100, 1, 188356, 0x12dba0dc
+0, 1110, 1110, 1, 188356, 0x5f86496a
+0, 1120, 1120, 1, 188356, 0x0b74216d
+0, 1130, 1130, 1, 188356, 0xdbddbada
+0, 1140, 1140, 1, 188356, 0x7d168af2
+0, 1150, 1150, 1, 188356, 0x22d4462b
+0, 1160, 1160, 1, 188356, 0xc248265d
+0, 1170, 1170, 1, 188356, 0x37a41b0d
+0, 1180, 1180, 1, 188356, 0x9ebd24f1
+0, 1190, 1190, 1, 188356, 0xf21f1633
+0, 1200, 1200, 1, 188356, 0x1db62004
+0, 1210, 1210, 1, 188356, 0xcc241ac1
+0, 1220, 1220, 1, 188356, 0x224d2637
+0, 1230, 1230, 1, 188356, 0x1bd8390c
+0, 1240, 1240, 1, 188356, 0xd8e64966
+0, 1250, 1250, 1, 188356, 0x96e66287
+0, 1260, 1260, 1, 188356, 0xa83c9a32
+0, 1270, 1270, 1, 188356, 0x3a5faeba
+0, 1280, 1280, 1, 188356, 0x8200cd87
+0, 1290, 1290, 1, 188356, 0x6326e591
+0, 1300, 1300, 1, 188356, 0xb5d70993
+0, 1310, 1310, 1, 188356, 0x954d5da2
+0, 1320, 1320, 1, 188356, 0x38b1788b
+0, 1330, 1330, 1, 188356, 0x4aafa131
+0, 1340, 1340, 1, 188356, 0xaff2be78
+0, 1350, 1350, 1, 188356, 0x9bd7eb69
+0, 1360, 1360, 1, 188356, 0x0d2b17c9
+0, 1370, 1370, 1, 188356, 0xf5d8a764
+0, 1380, 1380, 1, 188356, 0xa302dfb2
+0, 1390, 1390, 1, 188356, 0xe8a32ac1
+0, 1400, 1400, 1, 188356, 0x50a8470d
+0, 1410, 1410, 1, 188356, 0x52826061
+0, 1420, 1420, 1, 188356, 0x26e88798
+0, 1430, 1430, 1, 188356, 0x1448acb8
+0, 1440, 1440, 1, 188356, 0xfb380972
+0, 1450, 1450, 1, 188356, 0x184976e8
+0, 1460, 1460, 1, 188356, 0xa349a871
+0, 1470, 1470, 1, 188356, 0x617ed8b1
+0, 1480, 1480, 1, 188356, 0xb6bc1425
+0, 1490, 1490, 1, 188356, 0xafe74efd
+0, 1500, 1500, 1, 188356, 0x0b8b61e5
+0, 1510, 1510, 1, 188356, 0xc6ad67a7
+0, 1520, 1520, 1, 188356, 0x4da186fe
+0, 1530, 1530, 1, 188356, 0xe08f9975
+0, 1540, 1540, 1, 188356, 0xa43f8ba4
+0, 1550, 1550, 1, 188356, 0xcad4b6b5
+0, 1560, 1560, 1, 188356, 0x7e70d51e
+0, 1570, 1570, 1, 188356, 0x429b0b5b
+0, 1580, 1580, 1, 188356, 0xea92350d
+0, 1590, 1590, 1, 188356, 0x9a7440f8
+0, 1600, 1600, 1, 188356, 0x63a2be6e
+0, 1610, 1610, 1, 188356, 0x59b64b50
+0, 1620, 1620, 1, 188356, 0x63c4a10e
+0, 1630, 1630, 1, 188356, 0x6146e5e0
+0, 1640, 1640, 1, 188356, 0x603b2ae5
+0, 1650, 1650, 1, 188356, 0x818bc774
+0, 1660, 1660, 1, 188356, 0xa5ce278f
+0, 1670, 1670, 1, 188356, 0x4d85684d
+0, 1680, 1680, 1, 188356, 0xbbda9cad
+0, 1690, 1690, 1, 188356, 0xfee2e78e
+0, 1700, 1700, 1, 188356, 0x681d2635
+0, 1710, 1710, 1, 188356, 0x05354903
+0, 1720, 1720, 1, 188356, 0x8eecac99
diff --git a/tests/ref/fate/gif-demux b/tests/ref/fate/gif-demux
new file mode 100644
index 0000000..547b9ce
--- a/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..dbfaa48
--- a/dev/null
+++ b/tests/ref/fate/gif-disposal-background
@@ -0,0 +1,6 @@
+#tb 0: 1/100
+0, 0, 0, 1, 10368, 0x8b200cc8
+0, 50, 50, 1, 10368, 0x4e208e4f
+0, 100, 100, 1, 10368, 0x044dba8b
+0, 150, 150, 1, 10368, 0x1d617e09
+0, 200, 200, 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..0ce4112
--- a/dev/null
+++ b/tests/ref/fate/gif-disposal-restore
@@ -0,0 +1,4 @@
+#tb 0: 1/100
+0, 0, 0, 1, 112320, 0xb8afe429
+0, 10, 10, 1, 112320, 0xae588a4b
+0, 310, 310, 1, 112320, 0xccdd27b7
diff --git a/tests/ref/fate/gif-gray b/tests/ref/fate/gif-gray
new file mode 100644
index 0000000..5a133bd
--- a/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..dceaf52
--- a/dev/null
+++ b/tests/ref/fate/gifenc-bgr4_byte
@@ -0,0 +1,174 @@
+#tb 0: 1/100
+0, 0, 0, 1, 508, 0xa1b80fc0
+0, 10, 10, 1, 213, 0x4f554bd7, S=1, 1024, 0xb6327c81
+0, 20, 20, 1, 131, 0x283b2988, S=1, 1024, 0xae3a7c81
+0, 30, 30, 1, 384, 0xc4fea72a, S=1, 1024, 0xb6327c81
+0, 40, 40, 1, 381, 0x050ba2b8, S=1, 1024, 0x9e4a7c81
+0, 50, 50, 1, 430, 0x00cfb2ae, S=1, 1024, 0x9e4a7c81
+0, 60, 60, 1, 518, 0xc8e5d827, S=1, 1024, 0x9e4a7c81
+0, 70, 70, 1, 535, 0x326ce62a, S=1, 1024, 0x9e4a7c81
+0, 80, 80, 1, 438, 0x34d6b7c0, S=1, 1024, 0xb6327c81
+0, 90, 90, 1, 923, 0x9fb1a37c, S=1, 1024, 0xb6327c81
+0, 100, 100, 1, 694, 0xf20449a5, S=1, 1024, 0xb6327c81
+0, 110, 110, 1, 1194, 0x67cd2ab5, S=1, 1024, 0xb6327c81
+0, 120, 120, 1, 1291, 0x1d23539d, S=1, 1024, 0xb6327c81
+0, 130, 130, 1, 1245, 0x065f32e6, S=1, 1024, 0xb6327c81
+0, 140, 140, 1, 1330, 0x83ec51a4, S=1, 1024, 0xb6327c81
+0, 150, 150, 1, 1276, 0x2acf38dc, S=1, 1024, 0xb6327c81
+0, 160, 160, 1, 1475, 0x4cd197ef, S=1, 1024, 0xb6327c81
+0, 170, 170, 1, 1784, 0xd1e84ae6, S=1, 1024, 0xde0a7c81
+0, 180, 180, 1, 1675, 0x092dfa86, S=1, 1024, 0xde0a7c81
+0, 190, 190, 1, 1509, 0x639aaa00, S=1, 1024, 0xde0a7c81
+0, 200, 200, 1, 1705, 0xfd3719d5, S=1, 1024, 0xde0a7c81
+0, 210, 210, 1, 1745, 0x8a761db4, S=1, 1024, 0xde0a7c81
+0, 220, 220, 1, 1642, 0x18830245, S=1, 1024, 0xde0a7c81
+0, 230, 230, 1, 1718, 0x3c8d1ebe, S=1, 1024, 0xde0a7c81
+0, 240, 240, 1, 1900, 0x2ea879d1, S=1, 1024, 0xde0a7c81
+0, 250, 250, 1, 1807, 0x02b35230, S=1, 1024, 0xde0a7c81
+0, 260, 260, 1, 1915, 0x22d48344, S=1, 1024, 0xde0a7c81
+0, 270, 270, 1, 2100, 0x55fcd063, S=1, 1024, 0xde0a7c81
+0, 280, 280, 1, 2700, 0x7cc5f08b, S=1, 1024, 0xde0a7c81
+0, 290, 290, 1, 2673, 0xb997a80d, S=1, 1024, 0xde0a7c81
+0, 300, 300, 1, 2895, 0xab69484d, S=1, 1024, 0xde0a7c81
+0, 310, 310, 1, 3257, 0xf753cf24, S=1, 1024, 0xde0a7c81
+0, 320, 320, 1, 3179, 0x34f2c13b, S=1, 1024, 0xde0a7c81
+0, 330, 330, 1, 3296, 0x7c06e72f, S=1, 1024, 0xde0a7c81
+0, 340, 340, 1, 3600, 0x4ca67634, S=1, 1024, 0xde0a7c81
+0, 350, 350, 1, 3699, 0xabe89fe3, S=1, 1024, 0xde0a7c81
+0, 360, 360, 1, 3814, 0x1869d3f4, S=1, 1024, 0xde0a7c81
+0, 370, 370, 1, 3627, 0x19bd7da7, S=1, 1024, 0xde0a7c81
+0, 380, 380, 1, 2950, 0x048a6055, S=1, 1024, 0xde0a7c81
+0, 390, 390, 1, 3086, 0x64ec8fc2, S=1, 1024, 0xde0a7c81
+0, 400, 400, 1, 3094, 0x1a388553, S=1, 1024, 0xde0a7c81
+0, 410, 410, 1, 3456, 0x01432c82, S=1, 1024, 0xde0a7c81
+0, 420, 420, 1, 4108, 0xf9505c66, S=1, 1024, 0xde0a7c81
+0, 430, 430, 1, 4217, 0x7f985ba4, S=1, 1024, 0xde0a7c81
+0, 440, 440, 1, 3613, 0xd0684d83, S=1, 1024, 0xde0a7c81
+0, 450, 450, 1, 3910, 0x0070e692, S=1, 1024, 0xde0a7c81
+0, 460, 460, 1, 4461, 0x5cc9e33d, S=1, 1024, 0xde0a7c81
+0, 470, 470, 1, 4593, 0x33a32dd1, S=1, 1024, 0xde0a7c81
+0, 480, 480, 1, 4822, 0x59549883, S=1, 1024, 0xde0a7c81
+0, 490, 490, 1, 5398, 0xb7bac31e, S=1, 1024, 0xde0a7c81
+0, 500, 500, 1, 5266, 0x21c695aa, S=1, 1024, 0xde0a7c81
+0, 510, 510, 1, 5416, 0xf305e3ed, S=1, 1024, 0xde0a7c81
+0, 520, 520, 1, 5519, 0x857d071f, S=1, 1024, 0xde0a7c81
+0, 530, 530, 1, 5701, 0x8f885c9c, S=1, 1024, 0xde0a7c81
+0, 540, 540, 1, 6160, 0x48523e83, S=1, 1024, 0xde0a7c81
+0, 550, 550, 1, 6233, 0x8fd2511e, S=1, 1024, 0xde0a7c81
+0, 560, 560, 1, 5911, 0x92d4c516, S=1, 1024, 0xde0a7c81
+0, 570, 570, 1, 5997, 0xbd7cfa15, S=1, 1024, 0xde0a7c81
+0, 580, 580, 1, 5946, 0x8f5fedff, S=1, 1024, 0xde0a7c81
+0, 590, 590, 1, 6468, 0x45c0cb8c, S=1, 1024, 0xde0a7c81
+0, 600, 600, 1, 6737, 0x4e1e39ac, S=1, 1024, 0xde0a7c81
+0, 610, 610, 1, 6275, 0x1d5e8f4c, S=1, 1024, 0xde0a7c81
+0, 620, 620, 1, 6641, 0x844b3aad, S=1, 1024, 0xde0a7c81
+0, 630, 630, 1, 6378, 0x52568640, S=1, 1024, 0xde0a7c81
+0, 640, 640, 1, 6257, 0xfabc585f, S=1, 1024, 0xde0a7c81
+0, 650, 650, 1, 6908, 0xf261701c, S=1, 1024, 0xde0a7c81
+0, 660, 660, 1, 7230, 0xb4f524ce, S=1, 1024, 0xde0a7c81
+0, 670, 670, 1, 7556, 0x89c1a712, S=1, 1024, 0xde0a7c81
+0, 680, 680, 1, 7413, 0x553970a4, S=1, 1024, 0xde0a7c81
+0, 690, 690, 1, 7476, 0x24d2a761, S=1, 1024, 0xde0a7c81
+0, 700, 700, 1, 7596, 0xf072e431, S=1, 1024, 0xde0a7c81
+0, 710, 710, 1, 7756, 0x131205c0, S=1, 1024, 0xde0a7c81
+0, 720, 720, 1, 8015, 0xf4536a7f, S=1, 1024, 0xde0a7c81
+0, 730, 730, 1, 8128, 0xba80be2b, S=1, 1024, 0xde0a7c81
+0, 740, 740, 1, 8101, 0x44ceb3a2, S=1, 1024, 0xde0a7c81
+0, 750, 750, 1, 7863, 0x55043dfd, S=1, 1024, 0xde0a7c81
+0, 760, 760, 1, 7960, 0x38399182, S=1, 1024, 0xde0a7c81
+0, 770, 770, 1, 8238, 0x1d52ecf3, S=1, 1024, 0xde0a7c81
+0, 780, 780, 1, 8321, 0xd8d24a5c, S=1, 1024, 0xde0a7c81
+0, 790, 790, 1, 8562, 0x4a0cc02b, S=1, 1024, 0xde0a7c81
+0, 800, 800, 1, 8746, 0x2db40da7, S=1, 1024, 0xde0a7c81
+0, 810, 810, 1, 8578, 0x46f9a4c1, S=1, 1024, 0xde0a7c81
+0, 820, 820, 1, 8878, 0xf58d5a19, S=1, 1024, 0xde0a7c81
+0, 830, 830, 1, 9077, 0x78de57f6, S=1, 1024, 0xde0a7c81
+0, 840, 840, 1, 9310, 0x8c10f77a, S=1, 1024, 0xde0a7c81
+0, 850, 850, 1, 9394, 0x741f431e, S=1, 1024, 0xde0a7c81
+0, 860, 860, 1, 9161, 0x6f499587, S=1, 1024, 0xde0a7c81
+0, 870, 870, 1, 9462, 0x628936c3, S=1, 1024, 0xde0a7c81
+0, 880, 880, 1, 9650, 0x4cb4936e, S=1, 1024, 0xde0a7c81
+0, 890, 890, 1, 9701, 0x5e069c40, S=1, 1024, 0xde0a7c81
+0, 900, 900, 1, 9523, 0x66a13c83, S=1, 1024, 0xde0a7c81
+0, 910, 910, 1, 9891, 0x43ea0e93, S=1, 1024, 0xde0a7c81
+0, 920, 920, 1, 10005, 0x96a849e7, S=1, 1024, 0xde0a7c81
+0, 930, 930, 1, 10038, 0x68032d25, S=1, 1024, 0xde0a7c81
+0, 940, 940, 1, 10086, 0xef59458d, S=1, 1024, 0xde0a7c81
+0, 950, 950, 1, 10438, 0x3466fed0, S=1, 1024, 0xde0a7c81
+0, 960, 960, 1, 10583, 0x8bdd5477, S=1, 1024, 0xde0a7c81
+0, 970, 970, 1, 10581, 0x69d27fee, S=1, 1024, 0xde0a7c81
+0, 980, 980, 1, 10807, 0xde62d6e3, S=1, 1024, 0xde0a7c81
+0, 990, 990, 1, 11111, 0x34eb4c13, S=1, 1024, 0xde0a7c81
+0, 1000, 1000, 1, 11194, 0x584f6b73, S=1, 1024, 0xde0a7c81
+0, 1010, 1010, 1, 11240, 0xc90ba13f, S=1, 1024, 0xde0a7c81
+0, 1020, 1020, 1, 11483, 0x59c4f3c5, S=1, 1024, 0xde0a7c81
+0, 1030, 1030, 1, 11680, 0xc62c5bc1, S=1, 1024, 0xde0a7c81
+0, 1040, 1040, 1, 11785, 0xc9bab793, S=1, 1024, 0xde0a7c81
+0, 1050, 1050, 1, 11436, 0xc9c40809, S=1, 1024, 0xde0a7c81
+0, 1060, 1060, 1, 11928, 0x4b77c9a7, S=1, 1024, 0xde0a7c81
+0, 1070, 1070, 1, 11932, 0x722abcbe, S=1, 1024, 0xde0a7c81
+0, 1080, 1080, 1, 12281, 0x0d136f53, S=1, 1024, 0xde0a7c81
+0, 1090, 1090, 1, 12334, 0x04a47f78, S=1, 1024, 0xde0a7c81
+0, 1100, 1100, 1, 12452, 0xa02db188, S=1, 1024, 0xde0a7c81
+0, 1110, 1110, 1, 12695, 0x1a813b2e, S=1, 1024, 0xde0a7c81
+0, 1120, 1120, 1, 12668, 0x81b24f79, S=1, 1024, 0xde0a7c81
+0, 1130, 1130, 1, 12957, 0x4da59f8c, S=1, 1024, 0xde0a7c81
+0, 1140, 1140, 1, 13054, 0x7abedf5a, S=1, 1024, 0xde0a7c81
+0, 1150, 1150, 1, 13147, 0x138f2bbd, S=1, 1024, 0xde0a7c81
+0, 1160, 1160, 1, 13171, 0x43c1195f, S=1, 1024, 0xde0a7c81
+0, 1170, 1170, 1, 13198, 0x2c8d58d4, S=1, 1024, 0xde0a7c81
+0, 1180, 1180, 1, 13211, 0x12c36193, S=1, 1024, 0xde0a7c81
+0, 1190, 1190, 1, 13210, 0xfe496107, S=1, 1024, 0xde0a7c81
+0, 1200, 1200, 1, 13467, 0x4d8ea128, S=1, 1024, 0xde0a7c81
+0, 1210, 1210, 1, 13665, 0x94caddde, S=1, 1024, 0xde0a7c81
+0, 1220, 1220, 1, 13692, 0xe38febd9, S=1, 1024, 0xde0a7c81
+0, 1230, 1230, 1, 13821, 0xee592e62, S=1, 1024, 0xde0a7c81
+0, 1240, 1240, 1, 13946, 0xceb09235, S=1, 1024, 0xde0a7c81
+0, 1250, 1250, 1, 14063, 0x7361d2f5, S=1, 1024, 0xde0a7c81
+0, 1260, 1260, 1, 14124, 0x226bcac1, S=1, 1024, 0xde0a7c81
+0, 1270, 1270, 1, 14331, 0x0649512b, S=1, 1024, 0xde0a7c81
+0, 1280, 1280, 1, 14469, 0x0d7da45b, S=1, 1024, 0xde0a7c81
+0, 1290, 1290, 1, 14536, 0x73cca242, S=1, 1024, 0xde0a7c81
+0, 1300, 1300, 1, 14608, 0x1f3dd14e, S=1, 1024, 0xde0a7c81
+0, 1310, 1310, 1, 14898, 0xd13d258e, S=1, 1024, 0xde0a7c81
+0, 1320, 1320, 1, 14978, 0xfa049fea, S=1, 1024, 0xde0a7c81
+0, 1330, 1330, 1, 15142, 0x1dfad60c, S=1, 1024, 0xde0a7c81
+0, 1340, 1340, 1, 15129, 0x5962bae7, S=1, 1024, 0xde0a7c81
+0, 1350, 1350, 1, 15243, 0x2c2c113b, S=1, 1024, 0xde0a7c81
+0, 1360, 1360, 1, 15337, 0x3cab623b, S=1, 1024, 0xde0a7c81
+0, 1370, 1370, 1, 15638, 0xbff3a100, S=1, 1024, 0xde0a7c81
+0, 1380, 1380, 1, 15912, 0x13bf1fb2, S=1, 1024, 0xde0a7c81
+0, 1390, 1390, 1, 16041, 0x01134246, S=1, 1024, 0xde0a7c81
+0, 1400, 1400, 1, 16228, 0xe2f80035, S=1, 1024, 0xde0a7c81
+0, 1410, 1410, 1, 16262, 0xc8d3ea51, S=1, 1024, 0xde0a7c81
+0, 1420, 1420, 1, 16371, 0xe7da07f2, S=1, 1024, 0xde0a7c81
+0, 1430, 1430, 1, 16661, 0x10ada592, S=1, 1024, 0xde0a7c81
+0, 1440, 1440, 1, 16917, 0xbfb717e5, S=1, 1024, 0xde0a7c81
+0, 1450, 1450, 1, 17149, 0x4074ca41, S=1, 1024, 0xde0a7c81
+0, 1460, 1460, 1, 17172, 0xf749b49f, S=1, 1024, 0xde0a7c81
+0, 1470, 1470, 1, 17315, 0x2abea8a0, S=1, 1024, 0xde0a7c81
+0, 1480, 1480, 1, 17397, 0x14f71122, S=1, 1024, 0xde0a7c81
+0, 1490, 1490, 1, 17431, 0xce49f2d3, S=1, 1024, 0xde0a7c81
+0, 1500, 1500, 1, 17576, 0x7c6552ad, S=1, 1024, 0xde0a7c81
+0, 1510, 1510, 1, 17764, 0x1d198d60, S=1, 1024, 0xde0a7c81
+0, 1520, 1520, 1, 17826, 0xe1727f57, S=1, 1024, 0xde0a7c81
+0, 1530, 1530, 1, 17918, 0xb78d9b9f, S=1, 1024, 0xde0a7c81
+0, 1540, 1540, 1, 17823, 0xc9fabf19, S=1, 1024, 0xde0a7c81
+0, 1550, 1550, 1, 18142, 0xeb5b21a9, S=1, 1024, 0xde0a7c81
+0, 1560, 1560, 1, 18257, 0x7b38822c, S=1, 1024, 0xde0a7c81
+0, 1570, 1570, 1, 18337, 0xd395c279, S=1, 1024, 0xde0a7c81
+0, 1580, 1580, 1, 18293, 0x6c3b3766, S=1, 1024, 0xde0a7c81
+0, 1590, 1590, 1, 18418, 0x2abcbcf8, S=1, 1024, 0xde0a7c81
+0, 1600, 1600, 1, 18607, 0x79424730, S=1, 1024, 0xde0a7c81
+0, 1610, 1610, 1, 18916, 0x8707bbc6, S=1, 1024, 0xde0a7c81
+0, 1620, 1620, 1, 19073, 0xd82c03f6, S=1, 1024, 0xde0a7c81
+0, 1630, 1630, 1, 19168, 0xb7d6fe27, S=1, 1024, 0xde0a7c81
+0, 1640, 1640, 1, 19210, 0x79f301eb, S=1, 1024, 0xde0a7c81
+0, 1650, 1650, 1, 19398, 0x0a5663c6, S=1, 1024, 0xde0a7c81
+0, 1660, 1660, 1, 19480, 0x4fe09e5b, S=1, 1024, 0xde0a7c81
+0, 1670, 1670, 1, 19659, 0xab971088, S=1, 1024, 0xde0a7c81
+0, 1680, 1680, 1, 19672, 0x2e331553, S=1, 1024, 0xde0a7c81
+0, 1690, 1690, 1, 19936, 0x2eea628a, S=1, 1024, 0xde0a7c81
+0, 1700, 1700, 1, 19975, 0xd6bb9ab2, S=1, 1024, 0xde0a7c81
+0, 1710, 1710, 1, 20021, 0xf7e98dc5, S=1, 1024, 0xde0a7c81
+0, 1720, 1720, 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..49db763
--- a/dev/null
+++ b/tests/ref/fate/gifenc-bgr8
@@ -0,0 +1,174 @@
+#tb 0: 1/100
+0, 0, 0, 1, 552, 0x271a2dd3
+0, 10, 10, 1, 297, 0x90168a95, S=1, 1024, 0xf351799f
+0, 20, 20, 1, 438, 0x91efce1b, S=1, 1024, 0xf351799f
+0, 30, 30, 1, 450, 0x7c2dcfad, S=1, 1024, 0xf351799f
+0, 40, 40, 1, 547, 0xc131fd3b, S=1, 1024, 0xf351799f
+0, 50, 50, 1, 614, 0x68182006, S=1, 1024, 0xf351799f
+0, 60, 60, 1, 642, 0x78bb1f5f, S=1, 1024, 0xf351799f
+0, 70, 70, 1, 660, 0x35c033a2, S=1, 1024, 0xf351799f
+0, 80, 80, 1, 821, 0xaf30790b, S=1, 1024, 0xf351799f
+0, 90, 90, 1, 1157, 0x741c2da1, S=1, 1024, 0xf351799f
+0, 100, 100, 1, 179, 0x3a27517c, S=1, 1024, 0xf351799f
+0, 110, 110, 1, 1333, 0x5ee76f3c, S=1, 1024, 0xf351799f
+0, 120, 120, 1, 1638, 0x5f640e86, S=1, 1024, 0xf351799f
+0, 130, 130, 1, 1531, 0xccb8e437, S=1, 1024, 0xf351799f
+0, 140, 140, 1, 1720, 0xc95d45ec, S=1, 1024, 0xf351799f
+0, 150, 150, 1, 1910, 0x56cc831e, S=1, 1024, 0xf351799f
+0, 160, 160, 1, 2124, 0x9cc8e130, S=1, 1024, 0xf351799f
+0, 170, 170, 1, 2248, 0x05a325b1, S=1, 1024, 0xf351799f
+0, 180, 180, 1, 2311, 0xdc633703, S=1, 1024, 0xf351799f
+0, 190, 190, 1, 2408, 0x91c26f3e, S=1, 1024, 0xf351799f
+0, 200, 200, 1, 2601, 0x8cf3c157, S=1, 1024, 0xf351799f
+0, 210, 210, 1, 2687, 0x8f6400e6, S=1, 1024, 0xf351799f
+0, 220, 220, 1, 2784, 0xaa880e55, S=1, 1024, 0xf351799f
+0, 230, 230, 1, 2884, 0x46f546f6, S=1, 1024, 0xf351799f
+0, 240, 240, 1, 2982, 0x807c7ad5, S=1, 1024, 0xf351799f
+0, 250, 250, 1, 3101, 0xbcc89bec, S=1, 1024, 0xf351799f
+0, 260, 260, 1, 3253, 0xd032f3fa, S=1, 1024, 0xf351799f
+0, 270, 270, 1, 3329, 0xe4d42430, S=1, 1024, 0xf351799f
+0, 280, 280, 1, 3572, 0xf8058aa0, S=1, 1024, 0xf351799f
+0, 290, 290, 1, 3807, 0x3d2af9f3, S=1, 1024, 0xf351799f
+0, 300, 300, 1, 2750, 0x814d1c33, S=1, 1024, 0xf351799f
+0, 310, 310, 1, 4031, 0x3b077006, S=1, 1024, 0xf351799f
+0, 320, 320, 1, 3025, 0x86729c1c, S=1, 1024, 0xf351799f
+0, 330, 330, 1, 4295, 0xf71b0b38, S=1, 1024, 0xf351799f
+0, 340, 340, 1, 2044, 0x5adcb93b, S=1, 1024, 0xf351799f
+0, 350, 350, 1, 3212, 0xcf79eeed, S=1, 1024, 0xf351799f
+0, 360, 360, 1, 2281, 0x68464d30, S=1, 1024, 0xf351799f
+0, 370, 370, 1, 3633, 0x0010992f, S=1, 1024, 0xf351799f
+0, 380, 380, 1, 3552, 0x23697490, S=1, 1024, 0xf351799f
+0, 390, 390, 1, 3690, 0x62afdbb8, S=1, 1024, 0xf351799f
+0, 400, 400, 1, 1558, 0x7a13e53b, S=1, 1024, 0xf351799f
+0, 410, 410, 1, 940, 0xb1b6cba2, S=1, 1024, 0xf351799f
+0, 420, 420, 1, 273, 0x3687799b, S=1, 1024, 0xf351799f
+0, 430, 430, 1, 930, 0x29f3b0c4, S=1, 1024, 0xf351799f
+0, 440, 440, 1, 271, 0xe7af807c, S=1, 1024, 0xf351799f
+0, 450, 450, 1, 196, 0xf5ab51ee, S=1, 1024, 0xf351799f
+0, 460, 460, 1, 4299, 0x67ec0d55, S=1, 1024, 0xf351799f
+0, 470, 470, 1, 4895, 0xb394406c, S=1, 1024, 0xf351799f
+0, 480, 480, 1, 4928, 0x233919d7, S=1, 1024, 0xf351799f
+0, 490, 490, 1, 4941, 0x58a357da, S=1, 1024, 0xf351799f
+0, 500, 500, 1, 4154, 0x21f2ac33, S=1, 1024, 0xf351799f
+0, 510, 510, 1, 4678, 0xab3cc050, S=1, 1024, 0xf351799f
+0, 520, 520, 1, 4741, 0x1974b581, S=1, 1024, 0xf351799f
+0, 530, 530, 1, 4982, 0x891456d5, S=1, 1024, 0xf351799f
+0, 540, 540, 1, 5179, 0x860fc6a1, S=1, 1024, 0xf351799f
+0, 550, 550, 1, 5046, 0xce9183d3, S=1, 1024, 0xf351799f
+0, 560, 560, 1, 5140, 0xa6d7b9af, S=1, 1024, 0xf351799f
+0, 570, 570, 1, 4289, 0xb415f717, S=1, 1024, 0xf351799f
+0, 580, 580, 1, 5079, 0xa8d59e01, S=1, 1024, 0xf351799f
+0, 590, 590, 1, 5284, 0xea34e3b3, S=1, 1024, 0xf351799f
+0, 600, 600, 1, 5426, 0x556a15cd, S=1, 1024, 0xf351799f
+0, 610, 610, 1, 4645, 0x061e8936, S=1, 1024, 0xf351799f
+0, 620, 620, 1, 5263, 0x7536cf7d, S=1, 1024, 0xf351799f
+0, 630, 630, 1, 5221, 0x9fbac3ca, S=1, 1024, 0xf351799f
+0, 640, 640, 1, 5217, 0x02269bd2, S=1, 1024, 0xf351799f
+0, 650, 650, 1, 5395, 0x120fff66, S=1, 1024, 0xf351799f
+0, 660, 660, 1, 5220, 0x77cedcc5, S=1, 1024, 0xf351799f
+0, 670, 670, 1, 5704, 0xba42dd96, S=1, 1024, 0xf351799f
+0, 680, 680, 1, 5636, 0xcb91a25b, S=1, 1024, 0xf351799f
+0, 690, 690, 1, 5818, 0x8dc0df92, S=1, 1024, 0xf351799f
+0, 700, 700, 1, 5763, 0x51d5d5f0, S=1, 1024, 0xf351799f
+0, 710, 710, 1, 6116, 0x09558b48, S=1, 1024, 0xf351799f
+0, 720, 720, 1, 6069, 0x41926817, S=1, 1024, 0xf351799f
+0, 730, 730, 1, 5796, 0x7fbeda44, S=1, 1024, 0xf351799f
+0, 740, 740, 1, 5999, 0xe07d3770, S=1, 1024, 0xf351799f
+0, 750, 750, 1, 6220, 0x6607b06f, S=1, 1024, 0xf351799f
+0, 760, 760, 1, 6374, 0x7628e533, S=1, 1024, 0xf351799f
+0, 770, 770, 1, 6465, 0xfe956b15, S=1, 1024, 0xf351799f
+0, 780, 780, 1, 7019, 0x6c9a1aef, S=1, 1024, 0xf351799f
+0, 790, 790, 1, 7255, 0x5fa5c1bf, S=1, 1024, 0xf351799f
+0, 800, 800, 1, 8197, 0xf11d6ef2, S=1, 1024, 0xf351799f
+0, 810, 810, 1, 8358, 0x027279e8, S=1, 1024, 0xf351799f
+0, 820, 820, 1, 7708, 0x607f8e8b, S=1, 1024, 0xf351799f
+0, 830, 830, 1, 7412, 0x6bb2105f, S=1, 1024, 0xf351799f
+0, 840, 840, 1, 7541, 0xfdc02154, S=1, 1024, 0xf351799f
+0, 850, 850, 1, 7948, 0x916ecd8b, S=1, 1024, 0xf351799f
+0, 860, 860, 1, 8408, 0x1f97d414, S=1, 1024, 0xf351799f
+0, 870, 870, 1, 8056, 0x9cbf159c, S=1, 1024, 0xf351799f
+0, 880, 880, 1, 7401, 0x2625addb, S=1, 1024, 0xf351799f
+0, 890, 890, 1, 7494, 0x2877eacb, S=1, 1024, 0xf351799f
+0, 900, 900, 1, 7806, 0xe32574a3, S=1, 1024, 0xf351799f
+0, 910, 910, 1, 7768, 0x25ed7ee7, S=1, 1024, 0xf351799f
+0, 920, 920, 1, 7749, 0x6d8e978e, S=1, 1024, 0xf351799f
+0, 930, 930, 1, 8047, 0xec4b150c, S=1, 1024, 0xf351799f
+0, 940, 940, 1, 7618, 0x88cf30d5, S=1, 1024, 0xf351799f
+0, 950, 950, 1, 7979, 0x0eb1cf2a, S=1, 1024, 0xf351799f
+0, 960, 960, 1, 12062, 0xb49d9125, S=1, 1024, 0xf351799f
+0, 970, 970, 1, 12317, 0x2d8fd6e9, S=1, 1024, 0xf351799f
+0, 980, 980, 1, 12217, 0x9b3be549, S=1, 1024, 0xf351799f
+0, 990, 990, 1, 11227, 0x067e9118, S=1, 1024, 0xf351799f
+0, 1000, 1000, 1, 11108, 0x5e5b0afd, S=1, 1024, 0xf351799f
+0, 1010, 1010, 1, 11366, 0xb38e8d15, S=1, 1024, 0xf351799f
+0, 1020, 1020, 1, 11896, 0xeb3e35ca, S=1, 1024, 0xf351799f
+0, 1030, 1030, 1, 11479, 0xbf7581e9, S=1, 1024, 0xf351799f
+0, 1040, 1040, 1, 13395, 0x415b38d8, S=1, 1024, 0xf351799f
+0, 1050, 1050, 1, 12913, 0x61544631, S=1, 1024, 0xf351799f
+0, 1060, 1060, 1, 13864, 0xd39fe768, S=1, 1024, 0xf351799f
+0, 1070, 1070, 1, 13551, 0x76c167d1, S=1, 1024, 0xf351799f
+0, 1080, 1080, 1, 14041, 0x2f206888, S=1, 1024, 0xf351799f
+0, 1090, 1090, 1, 14144, 0x9ec030d3, S=1, 1024, 0xf351799f
+0, 1100, 1100, 1, 14277, 0xa84b3a9b, S=1, 1024, 0xf351799f
+0, 1110, 1110, 1, 14424, 0xf5f1e06e, S=1, 1024, 0xf351799f
+0, 1120, 1120, 1, 14689, 0xbca0adb5, S=1, 1024, 0xf351799f
+0, 1130, 1130, 1, 14598, 0xc1d45745, S=1, 1024, 0xf351799f
+0, 1140, 1140, 1, 15213, 0x8f3080fc, S=1, 1024, 0xf351799f
+0, 1150, 1150, 1, 15425, 0xb0aa8f59, S=1, 1024, 0xf351799f
+0, 1160, 1160, 1, 15595, 0x1406e5d5, S=1, 1024, 0xf351799f
+0, 1170, 1170, 1, 15598, 0x48ec7d08, S=1, 1024, 0xf351799f
+0, 1180, 1180, 1, 15863, 0x5381db7b, S=1, 1024, 0xf351799f
+0, 1190, 1190, 1, 15717, 0xb87a1b87, S=1, 1024, 0xf351799f
+0, 1200, 1200, 1, 16078, 0x5bab2453, S=1, 1024, 0xf351799f
+0, 1210, 1210, 1, 16225, 0xa1f88113, S=1, 1024, 0xf351799f
+0, 1220, 1220, 1, 16135, 0x6af2f4e1, S=1, 1024, 0xf351799f
+0, 1230, 1230, 1, 16661, 0xf02a3343, S=1, 1024, 0xf351799f
+0, 1240, 1240, 1, 16619, 0xc71935a4, S=1, 1024, 0xf351799f
+0, 1250, 1250, 1, 16829, 0x29849844, S=1, 1024, 0xf351799f
+0, 1260, 1260, 1, 16944, 0x3423ae77, S=1, 1024, 0xf351799f
+0, 1270, 1270, 1, 17119, 0x609b4409, S=1, 1024, 0xf351799f
+0, 1280, 1280, 1, 17150, 0xf85dfd31, S=1, 1024, 0xf351799f
+0, 1290, 1290, 1, 17321, 0x38eccb10, S=1, 1024, 0xf351799f
+0, 1300, 1300, 1, 17395, 0x0ba08b85, S=1, 1024, 0xf351799f
+0, 1310, 1310, 1, 17666, 0x6fbc0264, S=1, 1024, 0xf351799f
+0, 1320, 1320, 1, 17730, 0x3dcc64a6, S=1, 1024, 0xf351799f
+0, 1330, 1330, 1, 17934, 0xb539974b, S=1, 1024, 0xf351799f
+0, 1340, 1340, 1, 17944, 0x2214ec94, S=1, 1024, 0xf351799f
+0, 1350, 1350, 1, 18238, 0x70f9ff1d, S=1, 1024, 0xf351799f
+0, 1360, 1360, 1, 18391, 0x4b149209, S=1, 1024, 0xf351799f
+0, 1370, 1370, 1, 18543, 0x45a1c02f, S=1, 1024, 0xf351799f
+0, 1380, 1380, 1, 18939, 0x2789a88c, S=1, 1024, 0xf351799f
+0, 1390, 1390, 1, 19145, 0x5daafd7a, S=1, 1024, 0xf351799f
+0, 1400, 1400, 1, 19120, 0x565f80e6, S=1, 1024, 0xf351799f
+0, 1410, 1410, 1, 19130, 0xff70cc21, S=1, 1024, 0xf351799f
+0, 1420, 1420, 1, 19494, 0xbfa284db, S=1, 1024, 0xf351799f
+0, 1430, 1430, 1, 19534, 0x3d40743b, S=1, 1024, 0xf351799f
+0, 1440, 1440, 1, 19747, 0x33c9b108, S=1, 1024, 0xf351799f
+0, 1450, 1450, 1, 20114, 0x9d223e36, S=1, 1024, 0xf351799f
+0, 1460, 1460, 1, 20257, 0xe7bdaf43, S=1, 1024, 0xf351799f
+0, 1470, 1470, 1, 20370, 0x0c5f1970, S=1, 1024, 0xf351799f
+0, 1480, 1480, 1, 20292, 0x6986d20e, S=1, 1024, 0xf351799f
+0, 1490, 1490, 1, 20491, 0xd88e4c08, S=1, 1024, 0xf351799f
+0, 1500, 1500, 1, 20647, 0x1aefaffc, S=1, 1024, 0xf351799f
+0, 1510, 1510, 1, 20666, 0x43e4aaaa, S=1, 1024, 0xf351799f
+0, 1520, 1520, 1, 21007, 0xa7ca3ef0, S=1, 1024, 0xf351799f
+0, 1530, 1530, 1, 21058, 0x06814351, S=1, 1024, 0xf351799f
+0, 1540, 1540, 1, 21153, 0x3c852b10, S=1, 1024, 0xf351799f
+0, 1550, 1550, 1, 21078, 0x8df15855, S=1, 1024, 0xf351799f
+0, 1560, 1560, 1, 21458, 0xd3a531d6, S=1, 1024, 0xf351799f
+0, 1570, 1570, 1, 21669, 0x88baca53, S=1, 1024, 0xf351799f
+0, 1580, 1580, 1, 21581, 0xd692fa1f, S=1, 1024, 0xf351799f
+0, 1590, 1590, 1, 21654, 0x30fb9061, S=1, 1024, 0xf351799f
+0, 1600, 1600, 1, 21987, 0xe7646d8b, S=1, 1024, 0xf351799f
+0, 1610, 1610, 1, 22205, 0x0fc55b6a, S=1, 1024, 0xf351799f
+0, 1620, 1620, 1, 22475, 0x4bc4c032, S=1, 1024, 0xf351799f
+0, 1630, 1630, 1, 22490, 0x58ca23f6, S=1, 1024, 0xf351799f
+0, 1640, 1640, 1, 22460, 0xf9ceb0ac, S=1, 1024, 0xf351799f
+0, 1650, 1650, 1, 22861, 0xb05f0f84, S=1, 1024, 0xf351799f
+0, 1660, 1660, 1, 22746, 0x0df23a5c, S=1, 1024, 0xf351799f
+0, 1670, 1670, 1, 23165, 0xbd7147ad, S=1, 1024, 0xf351799f
+0, 1680, 1680, 1, 23273, 0x9781a34f, S=1, 1024, 0xf351799f
+0, 1690, 1690, 1, 23211, 0x69c7606b, S=1, 1024, 0xf351799f
+0, 1700, 1700, 1, 23648, 0xdafde037, S=1, 1024, 0xf351799f
+0, 1710, 1710, 1, 23675, 0x2a2147ed, S=1, 1024, 0xf351799f
+0, 1720, 1720, 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..8fdc3b3
--- a/dev/null
+++ b/tests/ref/fate/gifenc-gray
@@ -0,0 +1,174 @@
+#tb 0: 1/100
+0, 0, 0, 1, 579, 0x0d0e3ab8
+0, 10, 10, 1, 150, 0x178b3a8c, S=1, 1024, 0xc2f67c9f
+0, 20, 20, 1, 155, 0x941743f5, S=1, 1024, 0xc2f67c9f
+0, 30, 30, 1, 144, 0x68c73711, S=1, 1024, 0xc2f67c9f
+0, 40, 40, 1, 152, 0xaf9a3f2e, S=1, 1024, 0xc2f67c9f
+0, 50, 50, 1, 136, 0x68593d85, S=1, 1024, 0xc2f67c9f
+0, 60, 60, 1, 134, 0x0dcb373f, S=1, 1024, 0xc2f67c9f
+0, 70, 70, 1, 129, 0x3baf3279, S=1, 1024, 0xc2f67c9f
+0, 80, 80, 1, 123, 0x9c963148, S=1, 1024, 0xc2f67c9f
+0, 90, 90, 1, 123, 0x5c272d6b, S=1, 1024, 0xc2f67c9f
+0, 100, 100, 1, 150, 0x5f8d41aa, S=1, 1024, 0xc2f67c9f
+0, 110, 110, 1, 134, 0x6f582fee, S=1, 1024, 0xc2f67c9f
+0, 120, 120, 1, 134, 0x85d53038, S=1, 1024, 0xc2f67c9f
+0, 130, 130, 1, 123, 0x6d2a2cb2, S=1, 1024, 0xc2f67c9f
+0, 140, 140, 1, 127, 0x1e78327b, S=1, 1024, 0xc2f67c9f
+0, 150, 150, 1, 119, 0xbafc2c31, S=1, 1024, 0xc2f67c9f
+0, 160, 160, 1, 138, 0x57553638, S=1, 1024, 0xc2f67c9f
+0, 170, 170, 1, 140, 0xf7423adb, S=1, 1024, 0xc2f67c9f
+0, 180, 180, 1, 122, 0x7e592f8b, S=1, 1024, 0xc2f67c9f
+0, 190, 190, 1, 123, 0xaa7d313c, S=1, 1024, 0xc2f67c9f
+0, 200, 200, 1, 140, 0x4fd63b34, S=1, 1024, 0xc2f67c9f
+0, 210, 210, 1, 123, 0x67753163, S=1, 1024, 0xc2f67c9f
+0, 220, 220, 1, 123, 0x02193147, S=1, 1024, 0xc2f67c9f
+0, 230, 230, 1, 124, 0xa85131e9, S=1, 1024, 0xc2f67c9f
+0, 240, 240, 1, 122, 0xef8731e2, S=1, 1024, 0xc2f67c9f
+0, 250, 250, 1, 122, 0x06d432c9, S=1, 1024, 0xc2f67c9f
+0, 260, 260, 1, 123, 0xcc8831cd, S=1, 1024, 0xc2f67c9f
+0, 270, 270, 1, 118, 0xa1d33166, S=1, 1024, 0xc2f67c9f
+0, 280, 280, 1, 159, 0xcc8c454c, S=1, 1024, 0xc2f67c9f
+0, 290, 290, 1, 140, 0x8a0231ad, S=1, 1024, 0xc2f67c9f
+0, 300, 300, 1, 163, 0xe78248d2, S=1, 1024, 0xc2f67c9f
+0, 310, 310, 1, 142, 0x3b293489, S=1, 1024, 0xc2f67c9f
+0, 320, 320, 1, 170, 0x5f504b12, S=1, 1024, 0xc2f67c9f
+0, 330, 330, 1, 146, 0x38a53693, S=1, 1024, 0xc2f67c9f
+0, 340, 340, 1, 132, 0xb18a3499, S=1, 1024, 0xc2f67c9f
+0, 350, 350, 1, 113, 0x55182bda, S=1, 1024, 0xc2f67c9f
+0, 360, 360, 1, 132, 0xaced3333, S=1, 1024, 0xc2f67c9f
+0, 370, 370, 1, 120, 0x9ffe2e4f, S=1, 1024, 0xc2f67c9f
+0, 380, 380, 1, 135, 0x6223351e, S=1, 1024, 0xc2f67c9f
+0, 390, 390, 1, 123, 0x269b3058, S=1, 1024, 0xc2f67c9f
+0, 400, 400, 1, 119, 0x17052def, S=1, 1024, 0xc2f67c9f
+0, 410, 410, 1, 119, 0x36da2ee2, S=1, 1024, 0xc2f67c9f
+0, 420, 420, 1, 120, 0x984e31be, S=1, 1024, 0xc2f67c9f
+0, 430, 430, 1, 114, 0xfd382c9d, S=1, 1024, 0xc2f67c9f
+0, 440, 440, 1, 125, 0x926a36c6, S=1, 1024, 0xc2f67c9f
+0, 450, 450, 1, 117, 0xbceb3183, S=1, 1024, 0xc2f67c9f
+0, 460, 460, 1, 116, 0xf4c72d82, S=1, 1024, 0xc2f67c9f
+0, 470, 470, 1, 124, 0x0c19343c, S=1, 1024, 0xc2f67c9f
+0, 480, 480, 1, 117, 0x1f032eb1, S=1, 1024, 0xc2f67c9f
+0, 490, 490, 1, 135, 0x31a437e6, S=1, 1024, 0xc2f67c9f
+0, 500, 500, 1, 131, 0x4c1735fe, S=1, 1024, 0xc2f67c9f
+0, 510, 510, 1, 122, 0xb7603463, S=1, 1024, 0xc2f67c9f
+0, 520, 520, 1, 122, 0x7f5e34e1, S=1, 1024, 0xc2f67c9f
+0, 530, 530, 1, 124, 0x9562350f, S=1, 1024, 0xc2f67c9f
+0, 540, 540, 1, 126, 0x18b33759, S=1, 1024, 0xc2f67c9f
+0, 550, 550, 1, 117, 0x748f3243, S=1, 1024, 0xc2f67c9f
+0, 560, 560, 1, 109, 0x72832fe7, S=1, 1024, 0xc2f67c9f
+0, 570, 570, 1, 120, 0x748a2e38, S=1, 1024, 0xc2f67c9f
+0, 580, 580, 1, 120, 0x61f82fb2, S=1, 1024, 0xc2f67c9f
+0, 590, 590, 1, 122, 0x2a6b3282, S=1, 1024, 0xc2f67c9f
+0, 600, 600, 1, 116, 0x8b542de6, S=1, 1024, 0xc2f67c9f
+0, 610, 610, 1, 119, 0xf33c318e, S=1, 1024, 0xc2f67c9f
+0, 620, 620, 1, 116, 0xff182f36, S=1, 1024, 0xc2f67c9f
+0, 630, 630, 1, 119, 0xeb9e2fcc, S=1, 1024, 0xc2f67c9f
+0, 640, 640, 1, 118, 0xe82d304e, S=1, 1024, 0xc2f67c9f
+0, 650, 650, 1, 137, 0x98303d30, S=1, 1024, 0xc2f67c9f
+0, 660, 660, 1, 149, 0x01123fff, S=1, 1024, 0xc2f67c9f
+0, 670, 670, 1, 115, 0x4ca92f75, S=1, 1024, 0xc2f67c9f
+0, 680, 680, 1, 131, 0xf4193bc0, S=1, 1024, 0xc2f67c9f
+0, 690, 690, 1, 115, 0xda5e2f30, S=1, 1024, 0xc2f67c9f
+0, 700, 700, 1, 100, 0x9ba32a58, S=1, 1024, 0xc2f67c9f
+0, 710, 710, 1, 109, 0xa47e2c91, S=1, 1024, 0xc2f67c9f
+0, 720, 720, 1, 120, 0x22452fd6, S=1, 1024, 0xc2f67c9f
+0, 730, 730, 1, 116, 0xd3c52c26, S=1, 1024, 0xc2f67c9f
+0, 740, 740, 1, 106, 0x95b42c9f, S=1, 1024, 0xc2f67c9f
+0, 750, 750, 1, 96, 0xfdc12639, S=1, 1024, 0xc2f67c9f
+0, 760, 760, 1, 99, 0x210f251b, S=1, 1024, 0xc2f67c9f
+0, 770, 770, 1, 119, 0x173b341c, S=1, 1024, 0xc2f67c9f
+0, 780, 780, 1, 119, 0x3bca2f29, S=1, 1024, 0xc2f67c9f
+0, 790, 790, 1, 213, 0x9e905d4c, S=1, 1024, 0xc2f67c9f
+0, 800, 800, 1, 209, 0xa0015e94, S=1, 1024, 0xc2f67c9f
+0, 810, 810, 1, 120, 0x36762bd4, S=1, 1024, 0xc2f67c9f
+0, 820, 820, 1, 119, 0x019b2edc, S=1, 1024, 0xc2f67c9f
+0, 830, 830, 1, 124, 0x211d30e7, S=1, 1024, 0xc2f67c9f
+0, 840, 840, 1, 125, 0x538732ff, S=1, 1024, 0xc2f67c9f
+0, 850, 850, 1, 123, 0x2887308a, S=1, 1024, 0xc2f67c9f
+0, 860, 860, 1, 119, 0x7ff930f4, S=1, 1024, 0xc2f67c9f
+0, 870, 870, 1, 119, 0xa50c2e16, S=1, 1024, 0xc2f67c9f
+0, 880, 880, 1, 107, 0x9ed02cea, S=1, 1024, 0xc2f67c9f
+0, 890, 890, 1, 119, 0xc234332a, S=1, 1024, 0xc2f67c9f
+0, 900, 900, 1, 115, 0x38353092, S=1, 1024, 0xc2f67c9f
+0, 910, 910, 1, 162, 0x6cda4644, S=1, 1024, 0xc2f67c9f
+0, 920, 920, 1, 124, 0x2f683081, S=1, 1024, 0xc2f67c9f
+0, 930, 930, 1, 116, 0x72952d04, S=1, 1024, 0xc2f67c9f
+0, 940, 940, 1, 84, 0x1a532301, S=1, 1024, 0xc2f67c9f
+0, 950, 950, 1, 176, 0xfb3c5400, S=1, 1024, 0xc2f67c9f
+0, 960, 960, 1, 137, 0x253132d1, S=1, 1024, 0xc2f67c9f
+0, 970, 970, 1, 179, 0x2b38528b, S=1, 1024, 0xc2f67c9f
+0, 980, 980, 1, 150, 0xbe413cbe, S=1, 1024, 0xc2f67c9f
+0, 990, 990, 1, 140, 0x9e93392a, S=1, 1024, 0xc2f67c9f
+0, 1000, 1000, 1, 129, 0x577e331e, S=1, 1024, 0xc2f67c9f
+0, 1010, 1010, 1, 146, 0x16ff3924, S=1, 1024, 0xc2f67c9f
+0, 1020, 1020, 1, 133, 0x756a3163, S=1, 1024, 0xc2f67c9f
+0, 1030, 1030, 1, 190, 0x3e865b77, S=1, 1024, 0xc2f67c9f
+0, 1040, 1040, 1, 159, 0xdf393fc8, S=1, 1024, 0xc2f67c9f
+0, 1050, 1050, 1, 188, 0x84be5168, S=1, 1024, 0xc2f67c9f
+0, 1060, 1060, 1, 163, 0x4c0e41f0, S=1, 1024, 0xc2f67c9f
+0, 1070, 1070, 1, 144, 0x5fda3792, S=1, 1024, 0xc2f67c9f
+0, 1080, 1080, 1, 136, 0x028c3800, S=1, 1024, 0xc2f67c9f
+0, 1090, 1090, 1, 150, 0x75d43a8d, S=1, 1024, 0xc2f67c9f
+0, 1100, 1100, 1, 134, 0x81123999, S=1, 1024, 0xc2f67c9f
+0, 1110, 1110, 1, 198, 0x0a875baa, S=1, 1024, 0xc2f67c9f
+0, 1120, 1120, 1, 169, 0xfdd7458c, S=1, 1024, 0xc2f67c9f
+0, 1130, 1130, 1, 210, 0x9b195be4, S=1, 1024, 0xc2f67c9f
+0, 1140, 1140, 1, 174, 0x0a424a76, S=1, 1024, 0xc2f67c9f
+0, 1150, 1150, 1, 137, 0xb1b535fd, S=1, 1024, 0xc2f67c9f
+0, 1160, 1160, 1, 122, 0x4d3f327b, S=1, 1024, 0xc2f67c9f
+0, 1170, 1170, 1, 152, 0x5e423b0c, S=1, 1024, 0xc2f67c9f
+0, 1180, 1180, 1, 137, 0xd13a39f7, S=1, 1024, 0xc2f67c9f
+0, 1190, 1190, 1, 156, 0x40864321, S=1, 1024, 0xc2f67c9f
+0, 1200, 1200, 1, 140, 0xbe1e393c, S=1, 1024, 0xc2f67c9f
+0, 1210, 1210, 1, 179, 0xaf204635, S=1, 1024, 0xc2f67c9f
+0, 1220, 1220, 1, 116, 0x5ac83123, S=1, 1024, 0xc2f67c9f
+0, 1230, 1230, 1, 118, 0x22bc2ec5, S=1, 1024, 0xc2f67c9f
+0, 1240, 1240, 1, 123, 0xc9b5302d, S=1, 1024, 0xc2f67c9f
+0, 1250, 1250, 1, 125, 0x5cee3077, S=1, 1024, 0xc2f67c9f
+0, 1260, 1260, 1, 194, 0xccc159ca, S=1, 1024, 0xc2f67c9f
+0, 1270, 1270, 1, 122, 0x4d243229, S=1, 1024, 0xc2f67c9f
+0, 1280, 1280, 1, 124, 0x948f330b, S=1, 1024, 0xc2f67c9f
+0, 1290, 1290, 1, 133, 0xd53c35ca, S=1, 1024, 0xc2f67c9f
+0, 1300, 1300, 1, 126, 0xc5543710, S=1, 1024, 0xc2f67c9f
+0, 1310, 1310, 1, 208, 0x6cf15ea2, S=1, 1024, 0xc2f67c9f
+0, 1320, 1320, 1, 131, 0xa8d33505, S=1, 1024, 0xc2f67c9f
+0, 1330, 1330, 1, 114, 0x0ae53001, S=1, 1024, 0xc2f67c9f
+0, 1340, 1340, 1, 129, 0xe9ff37c4, S=1, 1024, 0xc2f67c9f
+0, 1350, 1350, 1, 120, 0x02623359, S=1, 1024, 0xc2f67c9f
+0, 1360, 1360, 1, 164, 0x9dc545e5, S=1, 1024, 0xc2f67c9f
+0, 1370, 1370, 1, 245, 0xc170715a, S=1, 1024, 0xc2f67c9f
+0, 1380, 1380, 1, 215, 0xc93d5fbe, S=1, 1024, 0xc2f67c9f
+0, 1390, 1390, 1, 225, 0x14866349, S=1, 1024, 0xc2f67c9f
+0, 1400, 1400, 1, 123, 0x70cd2b64, S=1, 1024, 0xc2f67c9f
+0, 1410, 1410, 1, 124, 0xe9002fb5, S=1, 1024, 0xc2f67c9f
+0, 1420, 1420, 1, 125, 0x106e309b, S=1, 1024, 0xc2f67c9f
+0, 1430, 1430, 1, 122, 0x050e32b0, S=1, 1024, 0xc2f67c9f
+0, 1440, 1440, 1, 224, 0xf548614f, S=1, 1024, 0xc2f67c9f
+0, 1450, 1450, 1, 239, 0x125c6ade, S=1, 1024, 0xc2f67c9f
+0, 1460, 1460, 1, 127, 0x398734b6, S=1, 1024, 0xc2f67c9f
+0, 1470, 1470, 1, 126, 0x2ff431e5, S=1, 1024, 0xc2f67c9f
+0, 1480, 1480, 1, 124, 0x9583313b, S=1, 1024, 0xc2f67c9f
+0, 1490, 1490, 1, 126, 0xc1fc3692, S=1, 1024, 0xc2f67c9f
+0, 1500, 1500, 1, 123, 0xd0bf3170, S=1, 1024, 0xc2f67c9f
+0, 1510, 1510, 1, 117, 0x651f3032, S=1, 1024, 0xc2f67c9f
+0, 1520, 1520, 1, 119, 0x268a3078, S=1, 1024, 0xc2f67c9f
+0, 1530, 1530, 1, 117, 0x9e4d3283, S=1, 1024, 0xc2f67c9f
+0, 1540, 1540, 1, 149, 0x8f1043ba, S=1, 1024, 0xc2f67c9f
+0, 1550, 1550, 1, 127, 0x352338bc, S=1, 1024, 0xc2f67c9f
+0, 1560, 1560, 1, 113, 0xf877314e, S=1, 1024, 0xc2f67c9f
+0, 1570, 1570, 1, 128, 0x88103a62, S=1, 1024, 0xc2f67c9f
+0, 1580, 1580, 1, 111, 0xbf0630d9, S=1, 1024, 0xc2f67c9f
+0, 1590, 1590, 1, 146, 0x159c44f7, S=1, 1024, 0xc2f67c9f
+0, 1600, 1600, 1, 237, 0x4e45662e, S=1, 1024, 0xc2f67c9f
+0, 1610, 1610, 1, 233, 0x8f9e6354, S=1, 1024, 0xc2f67c9f
+0, 1620, 1620, 1, 160, 0x9c3f431f, S=1, 1024, 0xc2f67c9f
+0, 1630, 1630, 1, 125, 0xbd2b33c6, S=1, 1024, 0xc2f67c9f
+0, 1640, 1640, 1, 131, 0x3ecd3ba5, S=1, 1024, 0xc2f67c9f
+0, 1650, 1650, 1, 231, 0xdf286db6, S=1, 1024, 0xc2f67c9f
+0, 1660, 1660, 1, 153, 0xb6da408d, S=1, 1024, 0xc2f67c9f
+0, 1670, 1670, 1, 126, 0x6741365e, S=1, 1024, 0xc2f67c9f
+0, 1680, 1680, 1, 113, 0x658f2c90, S=1, 1024, 0xc2f67c9f
+0, 1690, 1690, 1, 125, 0xc0033320, S=1, 1024, 0xc2f67c9f
+0, 1700, 1700, 1, 122, 0xe38a2db1, S=1, 1024, 0xc2f67c9f
+0, 1710, 1710, 1, 145, 0x29d63e83, S=1, 1024, 0xc2f67c9f
+0, 1720, 1720, 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..a483dab
--- a/dev/null
+++ b/tests/ref/fate/gifenc-pal8
@@ -0,0 +1,174 @@
+#tb 0: 1/100
+0, 0, 0, 1, 1320, 0x95d1a9e9, S=1, 1024, 0xec907a9e
+0, 10, 10, 1, 1463, 0xa697fe95, S=1, 1024, 0xec907a9e
+0, 20, 20, 1, 1638, 0x7ea154fa, S=1, 1024, 0xec907a9e
+0, 30, 30, 1, 1755, 0x7e0b9c4d, S=1, 1024, 0xec907a9e
+0, 40, 40, 1, 1896, 0x4aacc768, S=1, 1024, 0xec907a9e
+0, 50, 50, 1, 2038, 0x209d1490, S=1, 1024, 0xec907a9e
+0, 60, 60, 1, 2168, 0x0c405606, S=1, 1024, 0xec907a9e
+0, 70, 70, 1, 2258, 0xc2fa9229, S=1, 1024, 0xec907a9e
+0, 80, 80, 1, 2442, 0x0d4bec48, S=1, 1024, 0xec907a9e
+0, 90, 90, 1, 2565, 0x15742730, S=1, 1024, 0xec907a9e
+0, 100, 100, 1, 2733, 0x2eb57d95, S=1, 1024, 0xec907a9e
+0, 110, 110, 1, 2849, 0x9f16ad46, S=1, 1024, 0xec907a9e
+0, 120, 120, 1, 2981, 0xf139f908, S=1, 1024, 0xec907a9e
+0, 130, 130, 1, 3082, 0x57144aec, S=1, 1024, 0xec907a9e
+0, 140, 140, 1, 3200, 0x35227f42, S=1, 1024, 0xec907a9e
+0, 150, 150, 1, 3316, 0xf6d7c002, S=1, 1024, 0xec907a9e
+0, 160, 160, 1, 3462, 0x27a20d23, S=1, 1024, 0xec907a9e
+0, 170, 170, 1, 3600, 0xaecb2b02, S=1, 1024, 0xec907a9e
+0, 180, 180, 1, 3712, 0x947d49d1, S=1, 1024, 0xec907a9e
+0, 190, 190, 1, 3838, 0xf87eb223, S=1, 1024, 0xec907a9e
+0, 200, 200, 1, 3949, 0x4152eedf, S=1, 1024, 0xec907a9e
+0, 210, 210, 1, 4084, 0x512c1e34, S=1, 1024, 0xec907a9e
+0, 220, 220, 1, 4187, 0xc5715a14, S=1, 1024, 0xec907a9e
+0, 230, 230, 1, 4323, 0x6326a0f5, S=1, 1024, 0xec907a9e
+0, 240, 240, 1, 4426, 0x5f6bd655, S=1, 1024, 0xec907a9e
+0, 250, 250, 1, 4564, 0xc62005fd, S=1, 1024, 0xec907a9e
+0, 260, 260, 1, 4664, 0x43e97006, S=1, 1024, 0xec907a9e
+0, 270, 270, 1, 4808, 0xf6e08d4f, S=1, 1024, 0xec907a9e
+0, 280, 280, 1, 4932, 0x2d51e0b5, S=1, 1024, 0xec907a9e
+0, 290, 290, 1, 5072, 0x577430c8, S=1, 1024, 0xec907a9e
+0, 300, 300, 1, 5247, 0xd9fe945d, S=1, 1024, 0xec907a9e
+0, 310, 310, 1, 5353, 0x27eec140, S=1, 1024, 0xec907a9e
+0, 320, 320, 1, 5536, 0xde59038d, S=1, 1024, 0xec907a9e
+0, 330, 330, 1, 5691, 0x358970e4, S=1, 1024, 0xec907a9e
+0, 340, 340, 1, 5835, 0xd89201d8, S=1, 1024, 0xec907a9e
+0, 350, 350, 1, 5967, 0x1c2e1fee, S=1, 1024, 0xec907a9e
+0, 360, 360, 1, 6082, 0xd4b88e90, S=1, 1024, 0xec907a9e
+0, 370, 370, 1, 6277, 0x020fe685, S=1, 1024, 0xec907a9e
+0, 380, 380, 1, 6382, 0xc1db2297, S=1, 1024, 0xec907a9e
+0, 390, 390, 1, 6509, 0xc65473a6, S=1, 1024, 0xec907a9e
+0, 400, 400, 1, 6621, 0xca917a35, S=1, 1024, 0xec907a9e
+0, 410, 410, 1, 6714, 0x70f29b1d, S=1, 1024, 0xec907a9e
+0, 420, 420, 1, 6822, 0x6f02e7ec, S=1, 1024, 0xec907a9e
+0, 430, 430, 1, 6880, 0x95440d97, S=1, 1024, 0xec907a9e
+0, 440, 440, 1, 6983, 0xab7a43fb, S=1, 1024, 0xec907a9e
+0, 450, 450, 1, 7085, 0xc3427580, S=1, 1024, 0xec907a9e
+0, 460, 460, 1, 7242, 0x3d00c5f0, S=1, 1024, 0xec907a9e
+0, 470, 470, 1, 7349, 0x453fad59, S=1, 1024, 0xec907a9e
+0, 480, 480, 1, 7514, 0xbd862667, S=1, 1024, 0xec907a9e
+0, 490, 490, 1, 7575, 0xf8cb3c77, S=1, 1024, 0xec907a9e
+0, 500, 500, 1, 7759, 0x1fe6ab40, S=1, 1024, 0xec907a9e
+0, 510, 510, 1, 7846, 0x3853fd0f, S=1, 1024, 0xec907a9e
+0, 520, 520, 1, 7975, 0x88d02c47, S=1, 1024, 0xec907a9e
+0, 530, 530, 1, 8092, 0xe28a3368, S=1, 1024, 0xec907a9e
+0, 540, 540, 1, 8188, 0x159a5d3b, S=1, 1024, 0xec907a9e
+0, 550, 550, 1, 8307, 0x598cae50, S=1, 1024, 0xec907a9e
+0, 560, 560, 1, 8436, 0xd104ee50, S=1, 1024, 0xec907a9e
+0, 570, 570, 1, 8498, 0x0b1527ed, S=1, 1024, 0xec907a9e
+0, 580, 580, 1, 8559, 0x0f722288, S=1, 1024, 0xec907a9e
+0, 590, 590, 1, 8661, 0x3efb2500, S=1, 1024, 0xec907a9e
+0, 600, 600, 1, 8774, 0x1e188a8b, S=1, 1024, 0xec907a9e
+0, 610, 610, 1, 8848, 0x5b438dbb, S=1, 1024, 0xec907a9e
+0, 620, 620, 1, 8968, 0x4b47ecb3, S=1, 1024, 0xec907a9e
+0, 630, 630, 1, 9036, 0x7a8e0791, S=1, 1024, 0xec907a9e
+0, 640, 640, 1, 9114, 0x7379131a, S=1, 1024, 0xec907a9e
+0, 650, 650, 1, 9258, 0x06099246, S=1, 1024, 0xec907a9e
+0, 660, 660, 1, 9423, 0x721ac9ab, S=1, 1024, 0xec907a9e
+0, 670, 670, 1, 9529, 0xbb1c0d18, S=1, 1024, 0xec907a9e
+0, 680, 680, 1, 9608, 0xc29a05f0, S=1, 1024, 0xec907a9e
+0, 690, 690, 1, 9668, 0xf35221ff, S=1, 1024, 0xec907a9e
+0, 700, 700, 1, 9709, 0x8c6d33f0, S=1, 1024, 0xec907a9e
+0, 710, 710, 1, 9810, 0x2d5b59f4, S=1, 1024, 0xec907a9e
+0, 720, 720, 1, 9879, 0x110ea6e5, S=1, 1024, 0xec907a9e
+0, 730, 730, 1, 10038, 0x5945f5f4, S=1, 1024, 0xec907a9e
+0, 740, 740, 1, 10120, 0xab24f519, S=1, 1024, 0xec907a9e
+0, 750, 750, 1, 10218, 0x090d305a, S=1, 1024, 0xec907a9e
+0, 760, 760, 1, 10231, 0xa77e6a66, S=1, 1024, 0xec907a9e
+0, 770, 770, 1, 10313, 0x192254b7, S=1, 1024, 0xec907a9e
+0, 780, 780, 1, 10444, 0x36609934, S=1, 1024, 0xec907a9e
+0, 790, 790, 1, 10670, 0xfa971206, S=1, 1024, 0xec907a9e
+0, 800, 800, 1, 10902, 0x01b59fd5, S=1, 1024, 0xec907a9e
+0, 810, 810, 1, 10992, 0x1f2ab0bc, S=1, 1024, 0xec907a9e
+0, 820, 820, 1, 11044, 0x7f5b1dc2, S=1, 1024, 0xec907a9e
+0, 830, 830, 1, 11170, 0x0beaee49, S=1, 1024, 0xec907a9e
+0, 840, 840, 1, 11267, 0xb1ae3808, S=1, 1024, 0xec907a9e
+0, 850, 850, 1, 11427, 0x2cc9aa3f, S=1, 1024, 0xec907a9e
+0, 860, 860, 1, 11529, 0x654de4f3, S=1, 1024, 0xec907a9e
+0, 870, 870, 1, 11632, 0xf4972bdf, S=1, 1024, 0xec907a9e
+0, 880, 880, 1, 11825, 0x0cd2548c, S=1, 1024, 0xec907a9e
+0, 890, 890, 1, 11864, 0x80758637, S=1, 1024, 0xec907a9e
+0, 900, 900, 1, 11950, 0xf8246fba, S=1, 1024, 0xec907a9e
+0, 910, 910, 1, 12088, 0x1b99c82b, S=1, 1024, 0xec907a9e
+0, 920, 920, 1, 12161, 0x682cf4ad, S=1, 1024, 0xec907a9e
+0, 930, 930, 1, 12305, 0x9f62069a, S=1, 1024, 0xec907a9e
+0, 940, 940, 1, 12296, 0xe08dd96c, S=1, 1024, 0xec907a9e
+0, 950, 950, 1, 12497, 0x9a20b2d0, S=1, 1024, 0xec907a9e
+0, 960, 960, 1, 12660, 0x4d1d05ea, S=1, 1024, 0xec907a9e
+0, 970, 970, 1, 12763, 0x12542531, S=1, 1024, 0xec907a9e
+0, 980, 980, 1, 12917, 0x7d0944dc, S=1, 1024, 0xec907a9e
+0, 990, 990, 1, 13021, 0xa1c89f22, S=1, 1024, 0xec907a9e
+0, 1000, 1000, 1, 13184, 0xe13ad0be, S=1, 1024, 0xec907a9e
+0, 1010, 1010, 1, 13315, 0x11b93a5d, S=1, 1024, 0xec907a9e
+0, 1020, 1020, 1, 13337, 0x677e54ef, S=1, 1024, 0xec907a9e
+0, 1030, 1030, 1, 13536, 0x48b7b5de, S=1, 1024, 0xec907a9e
+0, 1040, 1040, 1, 13728, 0x03f4d302, S=1, 1024, 0xec907a9e
+0, 1050, 1050, 1, 13822, 0x973b97ec, S=1, 1024, 0xec907a9e
+0, 1060, 1060, 1, 14002, 0x0de77dfc, S=1, 1024, 0xec907a9e
+0, 1070, 1070, 1, 14156, 0xf1b1d4e1, S=1, 1024, 0xec907a9e
+0, 1080, 1080, 1, 14256, 0x355320cc, S=1, 1024, 0xec907a9e
+0, 1090, 1090, 1, 14451, 0x306cb131, S=1, 1024, 0xec907a9e
+0, 1100, 1100, 1, 14508, 0xca729c8e, S=1, 1024, 0xec907a9e
+0, 1110, 1110, 1, 14683, 0x7abec197, S=1, 1024, 0xec907a9e
+0, 1120, 1120, 1, 14852, 0xa5b90496, S=1, 1024, 0xec907a9e
+0, 1130, 1130, 1, 15090, 0xcd29839d, S=1, 1024, 0xec907a9e
+0, 1140, 1140, 1, 15225, 0xfd85f899, S=1, 1024, 0xec907a9e
+0, 1150, 1150, 1, 15340, 0x07411310, S=1, 1024, 0xec907a9e
+0, 1160, 1160, 1, 15473, 0xe90086c1, S=1, 1024, 0xec907a9e
+0, 1170, 1170, 1, 15583, 0x524da1f3, S=1, 1024, 0xec907a9e
+0, 1180, 1180, 1, 15683, 0x404cbd62, S=1, 1024, 0xec907a9e
+0, 1190, 1190, 1, 15779, 0x3ec01717, S=1, 1024, 0xec907a9e
+0, 1200, 1200, 1, 15934, 0xac8b4c03, S=1, 1024, 0xec907a9e
+0, 1210, 1210, 1, 16116, 0xb4fa83c9, S=1, 1024, 0xec907a9e
+0, 1220, 1220, 1, 16153, 0x18f669c1, S=1, 1024, 0xec907a9e
+0, 1230, 1230, 1, 16303, 0x765b10e4, S=1, 1024, 0xec907a9e
+0, 1240, 1240, 1, 16460, 0xc4a8149a, S=1, 1024, 0xec907a9e
+0, 1250, 1250, 1, 16475, 0x48664e2d, S=1, 1024, 0xec907a9e
+0, 1260, 1260, 1, 16710, 0x8a599742, S=1, 1024, 0xec907a9e
+0, 1270, 1270, 1, 16848, 0x8634a3d5, S=1, 1024, 0xec907a9e
+0, 1280, 1280, 1, 16955, 0x01f1ebda, S=1, 1024, 0xec907a9e
+0, 1290, 1290, 1, 17044, 0xd57b47df, S=1, 1024, 0xec907a9e
+0, 1300, 1300, 1, 17153, 0xc5cf7bc7, S=1, 1024, 0xec907a9e
+0, 1310, 1310, 1, 17375, 0xbbeea767, S=1, 1024, 0xec907a9e
+0, 1320, 1320, 1, 17476, 0xd7a25686, S=1, 1024, 0xec907a9e
+0, 1330, 1330, 1, 17602, 0x1c99b228, S=1, 1024, 0xec907a9e
+0, 1340, 1340, 1, 17676, 0xd860d1d2, S=1, 1024, 0xec907a9e
+0, 1350, 1350, 1, 17799, 0xe4ccb3ae, S=1, 1024, 0xec907a9e
+0, 1360, 1360, 1, 17930, 0xf322e416, S=1, 1024, 0xec907a9e
+0, 1370, 1370, 1, 18201, 0xc6f1cfa7, S=1, 1024, 0xec907a9e
+0, 1380, 1380, 1, 18409, 0x7cdfe609, S=1, 1024, 0xec907a9e
+0, 1390, 1390, 1, 18686, 0xf65e5519, S=1, 1024, 0xec907a9e
+0, 1400, 1400, 1, 18790, 0x6d5c8a90, S=1, 1024, 0xec907a9e
+0, 1410, 1410, 1, 18891, 0x4702a6cf, S=1, 1024, 0xec907a9e
+0, 1420, 1420, 1, 18995, 0x69e5e02d, S=1, 1024, 0xec907a9e
+0, 1430, 1430, 1, 19058, 0xc56f0272, S=1, 1024, 0xec907a9e
+0, 1440, 1440, 1, 19223, 0xe89733f6, S=1, 1024, 0xec907a9e
+0, 1450, 1450, 1, 19501, 0xdb80f9e9, S=1, 1024, 0xec907a9e
+0, 1460, 1460, 1, 19566, 0xa3952da8, S=1, 1024, 0xec907a9e
+0, 1470, 1470, 1, 19692, 0x65925150, S=1, 1024, 0xec907a9e
+0, 1480, 1480, 1, 19730, 0x1352599a, S=1, 1024, 0xec907a9e
+0, 1490, 1490, 1, 19916, 0xd246bf9b, S=1, 1024, 0xec907a9e
+0, 1500, 1500, 1, 20136, 0x1c462eea, S=1, 1024, 0xec907a9e
+0, 1510, 1510, 1, 20210, 0xdec93f63, S=1, 1024, 0xec907a9e
+0, 1520, 1520, 1, 20311, 0xdff7836e, S=1, 1024, 0xec907a9e
+0, 1530, 1530, 1, 20377, 0x753d813f, S=1, 1024, 0xec907a9e
+0, 1540, 1540, 1, 20478, 0x7592b1a8, S=1, 1024, 0xec907a9e
+0, 1550, 1550, 1, 20597, 0x58313994, S=1, 1024, 0xec907a9e
+0, 1560, 1560, 1, 20717, 0xcdd9c665, S=1, 1024, 0xec907a9e
+0, 1570, 1570, 1, 20816, 0x803b4b03, S=1, 1024, 0xec907a9e
+0, 1580, 1580, 1, 20912, 0xce36ce22, S=1, 1024, 0xec907a9e
+0, 1590, 1590, 1, 20975, 0x1d08e543, S=1, 1024, 0xec907a9e
+0, 1600, 1600, 1, 21130, 0xc966e24c, S=1, 1024, 0xec907a9e
+0, 1610, 1610, 1, 21343, 0x735e614e, S=1, 1024, 0xec907a9e
+0, 1620, 1620, 1, 21455, 0x78d7afd1, S=1, 1024, 0xec907a9e
+0, 1630, 1630, 1, 21533, 0x62a10f46, S=1, 1024, 0xec907a9e
+0, 1640, 1640, 1, 21645, 0x8e53a12f, S=1, 1024, 0xec907a9e
+0, 1650, 1650, 1, 21931, 0x3b2f7226, S=1, 1024, 0xec907a9e
+0, 1660, 1660, 1, 22009, 0xf06bc58a, S=1, 1024, 0xec907a9e
+0, 1670, 1670, 1, 22115, 0xeeb1c5d7, S=1, 1024, 0xec907a9e
+0, 1680, 1680, 1, 22211, 0xcbab1084, S=1, 1024, 0xec907a9e
+0, 1690, 1690, 1, 22380, 0xf07d5cb7, S=1, 1024, 0xec907a9e
+0, 1700, 1700, 1, 22443, 0xcb79441c, S=1, 1024, 0xec907a9e
+0, 1710, 1710, 1, 22588, 0xcad49814, S=1, 1024, 0xec907a9e
+0, 1720, 1720, 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..16696da
--- a/dev/null
+++ b/tests/ref/fate/gifenc-rgb4_byte
@@ -0,0 +1,174 @@
+#tb 0: 1/100
+0, 0, 0, 1, 508, 0xf04a113b
+0, 10, 10, 1, 213, 0x23c24d3d, S=1, 1024, 0xf7700427
+0, 20, 20, 1, 131, 0x56d22a39, S=1, 1024, 0x03730427
+0, 30, 30, 1, 384, 0xb1d8a4bd, S=1, 1024, 0xf7700427
+0, 40, 40, 1, 381, 0x37a3a2c9, S=1, 1024, 0xf3740427
+0, 50, 50, 1, 430, 0x162bb3d3, S=1, 1024, 0xf3740427
+0, 60, 60, 1, 518, 0x195bd738, S=1, 1024, 0xf3740427
+0, 70, 70, 1, 535, 0x12cde6b7, S=1, 1024, 0xf3740427
+0, 80, 80, 1, 438, 0xa653b946, S=1, 1024, 0x0b6b0427
+0, 90, 90, 1, 923, 0xd2e2a35f, S=1, 1024, 0x0b6b0427
+0, 100, 100, 1, 694, 0xe1cf4a1f, S=1, 1024, 0x0b6b0427
+0, 110, 110, 1, 1194, 0xa6152c8a, S=1, 1024, 0x0b6b0427
+0, 120, 120, 1, 1291, 0x94d25581, S=1, 1024, 0x0b6b0427
+0, 130, 130, 1, 1245, 0x5b483525, S=1, 1024, 0x0b6b0427
+0, 140, 140, 1, 1330, 0xfb5351c8, S=1, 1024, 0x0b6b0427
+0, 150, 150, 1, 1276, 0x6f403914, S=1, 1024, 0x0b6b0427
+0, 160, 160, 1, 1475, 0xbf459755, S=1, 1024, 0x0b6b0427
+0, 170, 170, 1, 1784, 0xe9954aa7, S=1, 1024, 0xecb30526
+0, 180, 180, 1, 1675, 0x219dfaf8, S=1, 1024, 0xecb30526
+0, 190, 190, 1, 1509, 0xd7f5abbe, S=1, 1024, 0xecb30526
+0, 200, 200, 1, 1705, 0x44a01729, S=1, 1024, 0xecb30526
+0, 210, 210, 1, 1745, 0x31ff1f89, S=1, 1024, 0xecb30526
+0, 220, 220, 1, 1642, 0x55420147, S=1, 1024, 0xecb30526
+0, 230, 230, 1, 1718, 0x68ef1cb8, S=1, 1024, 0xecb30526
+0, 240, 240, 1, 1900, 0xd7737a09, S=1, 1024, 0xecb30526
+0, 250, 250, 1, 1807, 0x4f6c5140, S=1, 1024, 0xecb30526
+0, 260, 260, 1, 1915, 0x976d80e6, S=1, 1024, 0xecb30526
+0, 270, 270, 1, 2100, 0x0ae6d1ce, S=1, 1024, 0xecb30526
+0, 280, 280, 1, 2700, 0x7a89f104, S=1, 1024, 0xecb30526
+0, 290, 290, 1, 2673, 0xf6b6a71d, S=1, 1024, 0xecb30526
+0, 300, 300, 1, 2895, 0x9079484b, S=1, 1024, 0xecb30526
+0, 310, 310, 1, 3257, 0x0b0cd125, S=1, 1024, 0xecb30526
+0, 320, 320, 1, 3179, 0x3ee2c161, S=1, 1024, 0xecb30526
+0, 330, 330, 1, 3296, 0x6230e506, S=1, 1024, 0xecb30526
+0, 340, 340, 1, 3600, 0x021775d7, S=1, 1024, 0xecb30526
+0, 350, 350, 1, 3699, 0xfb03a043, S=1, 1024, 0xecb30526
+0, 360, 360, 1, 3814, 0x96a8d57e, S=1, 1024, 0xecb30526
+0, 370, 370, 1, 3627, 0x33a37f8f, S=1, 1024, 0xecb30526
+0, 380, 380, 1, 2950, 0x50806197, S=1, 1024, 0xecb30526
+0, 390, 390, 1, 3086, 0x72068d4c, S=1, 1024, 0xecb30526
+0, 400, 400, 1, 3094, 0x2880861f, S=1, 1024, 0xecb30526
+0, 410, 410, 1, 3456, 0x6d232a96, S=1, 1024, 0xecb30526
+0, 420, 420, 1, 4108, 0x46d75ebb, S=1, 1024, 0xecb30526
+0, 430, 430, 1, 4217, 0x04a258f4, S=1, 1024, 0xecb30526
+0, 440, 440, 1, 3613, 0x667f4ff8, S=1, 1024, 0xecb30526
+0, 450, 450, 1, 3910, 0x8f37e73e, S=1, 1024, 0xecb30526
+0, 460, 460, 1, 4461, 0x5db9e0bf, S=1, 1024, 0xecb30526
+0, 470, 470, 1, 4593, 0x883f2f49, S=1, 1024, 0xecb30526
+0, 480, 480, 1, 4822, 0x03d99b73, S=1, 1024, 0xecb30526
+0, 490, 490, 1, 5398, 0x39f7bff4, S=1, 1024, 0xecb30526
+0, 500, 500, 1, 5266, 0xd5ab9630, S=1, 1024, 0xecb30526
+0, 510, 510, 1, 5416, 0x5876e16f, S=1, 1024, 0xecb30526
+0, 520, 520, 1, 5519, 0x30ed05d8, S=1, 1024, 0xecb30526
+0, 530, 530, 1, 5701, 0x5bae5af7, S=1, 1024, 0xecb30526
+0, 540, 540, 1, 6160, 0x98364177, S=1, 1024, 0xecb30526
+0, 550, 550, 1, 6233, 0x52a05075, S=1, 1024, 0xecb30526
+0, 560, 560, 1, 5911, 0x04bfc46a, S=1, 1024, 0xecb30526
+0, 570, 570, 1, 5997, 0xf1e6f586, S=1, 1024, 0xecb30526
+0, 580, 580, 1, 5946, 0xe6f3f055, S=1, 1024, 0xecb30526
+0, 590, 590, 1, 6468, 0xc8a3cf61, S=1, 1024, 0xecb30526
+0, 600, 600, 1, 6737, 0xc27b3b79, S=1, 1024, 0xecb30526
+0, 610, 610, 1, 6275, 0x84d88e2b, S=1, 1024, 0xecb30526
+0, 620, 620, 1, 6641, 0xb44b3534, S=1, 1024, 0xecb30526
+0, 630, 630, 1, 6378, 0x3965888b, S=1, 1024, 0xecb30526
+0, 640, 640, 1, 6257, 0x12115750, S=1, 1024, 0xecb30526
+0, 650, 650, 1, 6908, 0x57137217, S=1, 1024, 0xecb30526
+0, 660, 660, 1, 7230, 0xbacc24ee, S=1, 1024, 0xecb30526
+0, 670, 670, 1, 7556, 0x1aa2a694, S=1, 1024, 0xecb30526
+0, 680, 680, 1, 7413, 0xbc9e7718, S=1, 1024, 0xecb30526
+0, 690, 690, 1, 7476, 0xb2a1aba0, S=1, 1024, 0xecb30526
+0, 700, 700, 1, 7596, 0x3301e56d, S=1, 1024, 0xecb30526
+0, 710, 710, 1, 7756, 0x8f2504f8, S=1, 1024, 0xecb30526
+0, 720, 720, 1, 8015, 0xd4146c80, S=1, 1024, 0xecb30526
+0, 730, 730, 1, 8128, 0x11b2bf4c, S=1, 1024, 0xecb30526
+0, 740, 740, 1, 8101, 0xc627adbe, S=1, 1024, 0xecb30526
+0, 750, 750, 1, 7863, 0xe99f3f3b, S=1, 1024, 0xecb30526
+0, 760, 760, 1, 7960, 0x4bc091b8, S=1, 1024, 0xecb30526
+0, 770, 770, 1, 8238, 0x1086ea8a, S=1, 1024, 0xecb30526
+0, 780, 780, 1, 8321, 0x3a404791, S=1, 1024, 0xecb30526
+0, 790, 790, 1, 8562, 0xcbdcc01e, S=1, 1024, 0xecb30526
+0, 800, 800, 1, 8746, 0xec190b22, S=1, 1024, 0xecb30526
+0, 810, 810, 1, 8578, 0x12e7a4e8, S=1, 1024, 0xecb30526
+0, 820, 820, 1, 8878, 0x51c05771, S=1, 1024, 0xecb30526
+0, 830, 830, 1, 9077, 0xe12b589b, S=1, 1024, 0xecb30526
+0, 840, 840, 1, 9310, 0xde3bf881, S=1, 1024, 0xecb30526
+0, 850, 850, 1, 9394, 0x1eba46cc, S=1, 1024, 0xecb30526
+0, 860, 860, 1, 9161, 0x7c359911, S=1, 1024, 0xecb30526
+0, 870, 870, 1, 9462, 0xccda3664, S=1, 1024, 0xecb30526
+0, 880, 880, 1, 9650, 0x6e6292fc, S=1, 1024, 0xecb30526
+0, 890, 890, 1, 9701, 0x08909b95, S=1, 1024, 0xecb30526
+0, 900, 900, 1, 9523, 0xe61b38bb, S=1, 1024, 0xecb30526
+0, 910, 910, 1, 9891, 0x96b90b98, S=1, 1024, 0xecb30526
+0, 920, 920, 1, 10005, 0x2db84c80, S=1, 1024, 0xecb30526
+0, 930, 930, 1, 10038, 0x37e52a72, S=1, 1024, 0xecb30526
+0, 940, 940, 1, 10086, 0x135a43e4, S=1, 1024, 0xecb30526
+0, 950, 950, 1, 10438, 0x472c0372, S=1, 1024, 0xecb30526
+0, 960, 960, 1, 10583, 0xcf4c5862, S=1, 1024, 0xecb30526
+0, 970, 970, 1, 10581, 0xce658137, S=1, 1024, 0xecb30526
+0, 980, 980, 1, 10807, 0x3954dad9, S=1, 1024, 0xecb30526
+0, 990, 990, 1, 11111, 0x5f8d504f, S=1, 1024, 0xecb30526
+0, 1000, 1000, 1, 11194, 0x3c7e6a77, S=1, 1024, 0xecb30526
+0, 1010, 1010, 1, 11240, 0x5112a0a3, S=1, 1024, 0xecb30526
+0, 1020, 1020, 1, 11483, 0xaf10f4fa, S=1, 1024, 0xecb30526
+0, 1030, 1030, 1, 11680, 0x44a25971, S=1, 1024, 0xecb30526
+0, 1040, 1040, 1, 11785, 0x7350b5db, S=1, 1024, 0xecb30526
+0, 1050, 1050, 1, 11436, 0xe3170ad5, S=1, 1024, 0xecb30526
+0, 1060, 1060, 1, 11928, 0x13d8c885, S=1, 1024, 0xecb30526
+0, 1070, 1070, 1, 11932, 0xecb5bdf7, S=1, 1024, 0xecb30526
+0, 1080, 1080, 1, 12281, 0x18bb76d5, S=1, 1024, 0xecb30526
+0, 1090, 1090, 1, 12334, 0x16147fc3, S=1, 1024, 0xecb30526
+0, 1100, 1100, 1, 12452, 0x61a8b3d7, S=1, 1024, 0xecb30526
+0, 1110, 1110, 1, 12695, 0x8b703e74, S=1, 1024, 0xecb30526
+0, 1120, 1120, 1, 12668, 0x19505176, S=1, 1024, 0xecb30526
+0, 1130, 1130, 1, 12957, 0x3b839f0d, S=1, 1024, 0xecb30526
+0, 1140, 1140, 1, 13054, 0xb8a5e3db, S=1, 1024, 0xecb30526
+0, 1150, 1150, 1, 13147, 0xdf5c2e68, S=1, 1024, 0xecb30526
+0, 1160, 1160, 1, 13171, 0x15961ca2, S=1, 1024, 0xecb30526
+0, 1170, 1170, 1, 13198, 0xfd855718, S=1, 1024, 0xecb30526
+0, 1180, 1180, 1, 13211, 0x1a625e31, S=1, 1024, 0xecb30526
+0, 1190, 1190, 1, 13210, 0x246661c9, S=1, 1024, 0xecb30526
+0, 1200, 1200, 1, 13467, 0xfcaaa461, S=1, 1024, 0xecb30526
+0, 1210, 1210, 1, 13665, 0x8100dbf2, S=1, 1024, 0xecb30526
+0, 1220, 1220, 1, 13692, 0xddd1eab9, S=1, 1024, 0xecb30526
+0, 1230, 1230, 1, 13821, 0xc70e2af0, S=1, 1024, 0xecb30526
+0, 1240, 1240, 1, 13946, 0xe15d9134, S=1, 1024, 0xecb30526
+0, 1250, 1250, 1, 14063, 0xf652d232, S=1, 1024, 0xecb30526
+0, 1260, 1260, 1, 14124, 0x756ccc81, S=1, 1024, 0xecb30526
+0, 1270, 1270, 1, 14331, 0x56d64fe8, S=1, 1024, 0xecb30526
+0, 1280, 1280, 1, 14469, 0x4c3faa7f, S=1, 1024, 0xecb30526
+0, 1290, 1290, 1, 14536, 0xad02a19b, S=1, 1024, 0xecb30526
+0, 1300, 1300, 1, 14608, 0x0971d168, S=1, 1024, 0xecb30526
+0, 1310, 1310, 1, 14898, 0x1a6827b3, S=1, 1024, 0xecb30526
+0, 1320, 1320, 1, 14978, 0xf9709fef, S=1, 1024, 0xecb30526
+0, 1330, 1330, 1, 15142, 0x3598da63, S=1, 1024, 0xecb30526
+0, 1340, 1340, 1, 15129, 0x062fb976, S=1, 1024, 0xecb30526
+0, 1350, 1350, 1, 15243, 0x0a6a12f9, S=1, 1024, 0xecb30526
+0, 1360, 1360, 1, 15337, 0x0f9a65d6, S=1, 1024, 0xecb30526
+0, 1370, 1370, 1, 15638, 0xf7bc9ef5, S=1, 1024, 0xecb30526
+0, 1380, 1380, 1, 15912, 0x2d5b26bb, S=1, 1024, 0xecb30526
+0, 1390, 1390, 1, 16041, 0xbfaf4857, S=1, 1024, 0xecb30526
+0, 1400, 1400, 1, 16228, 0xdac701f0, S=1, 1024, 0xecb30526
+0, 1410, 1410, 1, 16262, 0xcd0ae5e4, S=1, 1024, 0xecb30526
+0, 1420, 1420, 1, 16371, 0x9d4f0e73, S=1, 1024, 0xecb30526
+0, 1430, 1430, 1, 16661, 0xd37ba990, S=1, 1024, 0xecb30526
+0, 1440, 1440, 1, 16917, 0xd5b01774, S=1, 1024, 0xecb30526
+0, 1450, 1450, 1, 17149, 0x435ecdd4, S=1, 1024, 0xecb30526
+0, 1460, 1460, 1, 17172, 0x045fb234, S=1, 1024, 0xecb30526
+0, 1470, 1470, 1, 17315, 0xc5ddadab, S=1, 1024, 0xecb30526
+0, 1480, 1480, 1, 17397, 0xff8e15b6, S=1, 1024, 0xecb30526
+0, 1490, 1490, 1, 17431, 0x6832f8c0, S=1, 1024, 0xecb30526
+0, 1500, 1500, 1, 17576, 0x5c2a5445, S=1, 1024, 0xecb30526
+0, 1510, 1510, 1, 17764, 0x609f8c3b, S=1, 1024, 0xecb30526
+0, 1520, 1520, 1, 17826, 0x538c8532, S=1, 1024, 0xecb30526
+0, 1530, 1530, 1, 17918, 0x84fc9a95, S=1, 1024, 0xecb30526
+0, 1540, 1540, 1, 17823, 0x788fbada, S=1, 1024, 0xecb30526
+0, 1550, 1550, 1, 18142, 0x56881e47, S=1, 1024, 0xecb30526
+0, 1560, 1560, 1, 18257, 0xa35b86cf, S=1, 1024, 0xecb30526
+0, 1570, 1570, 1, 18337, 0x82ddbc21, S=1, 1024, 0xecb30526
+0, 1580, 1580, 1, 18293, 0xf0d838d6, S=1, 1024, 0xecb30526
+0, 1590, 1590, 1, 18418, 0x7ed8bba6, S=1, 1024, 0xecb30526
+0, 1600, 1600, 1, 18607, 0xccea47f6, S=1, 1024, 0xecb30526
+0, 1610, 1610, 1, 18916, 0x880ebd63, S=1, 1024, 0xecb30526
+0, 1620, 1620, 1, 19073, 0x055f02e3, S=1, 1024, 0xecb30526
+0, 1630, 1630, 1, 19168, 0xcc2c02d7, S=1, 1024, 0xecb30526
+0, 1640, 1640, 1, 19210, 0xa538ffc1, S=1, 1024, 0xecb30526
+0, 1650, 1650, 1, 19398, 0x4777644d, S=1, 1024, 0xecb30526
+0, 1660, 1660, 1, 19480, 0xcb2aa0fa, S=1, 1024, 0xecb30526
+0, 1670, 1670, 1, 19659, 0xe3c1122d, S=1, 1024, 0xecb30526
+0, 1680, 1680, 1, 19672, 0x1d1e193f, S=1, 1024, 0xecb30526
+0, 1690, 1690, 1, 19936, 0xcd036346, S=1, 1024, 0xecb30526
+0, 1700, 1700, 1, 19975, 0x96529b21, S=1, 1024, 0xecb30526
+0, 1710, 1710, 1, 20021, 0xcdaf8bb5, S=1, 1024, 0xecb30526
+0, 1720, 1720, 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..226b26e
--- a/dev/null
+++ b/tests/ref/fate/gifenc-rgb8
@@ -0,0 +1,174 @@
+#tb 0: 1/100
+0, 0, 0, 1, 552, 0x47602c6c
+0, 10, 10, 1, 297, 0x49dd8847, S=1, 1024, 0xcfc8799f
+0, 20, 20, 1, 438, 0x4776d352, S=1, 1024, 0xcfc8799f
+0, 30, 30, 1, 450, 0x2254d187, S=1, 1024, 0xcfc8799f
+0, 40, 40, 1, 547, 0xe16104bc, S=1, 1024, 0xcfc8799f
+0, 50, 50, 1, 614, 0x0fdc2027, S=1, 1024, 0xcfc8799f
+0, 60, 60, 1, 642, 0xa0af1edf, S=1, 1024, 0xcfc8799f
+0, 70, 70, 1, 660, 0xd0763931, S=1, 1024, 0xcfc8799f
+0, 80, 80, 1, 821, 0xc38f7fac, S=1, 1024, 0xcfc8799f
+0, 90, 90, 1, 1157, 0x4c112ecd, S=1, 1024, 0xcfc8799f
+0, 100, 100, 1, 179, 0x0690541c, S=1, 1024, 0xcfc8799f
+0, 110, 110, 1, 1333, 0x216f70a7, S=1, 1024, 0xcfc8799f
+0, 120, 120, 1, 1638, 0x901c093d, S=1, 1024, 0xcfc8799f
+0, 130, 130, 1, 1531, 0xc9bae5ff, S=1, 1024, 0xcfc8799f
+0, 140, 140, 1, 1720, 0xce854743, S=1, 1024, 0xcfc8799f
+0, 150, 150, 1, 1910, 0x2690866d, S=1, 1024, 0xcfc8799f
+0, 160, 160, 1, 2124, 0xa586dad0, S=1, 1024, 0xcfc8799f
+0, 170, 170, 1, 2248, 0x9ddc2a88, S=1, 1024, 0xcfc8799f
+0, 180, 180, 1, 2311, 0xd64235af, S=1, 1024, 0xcfc8799f
+0, 190, 190, 1, 2408, 0xe2a66cc9, S=1, 1024, 0xcfc8799f
+0, 200, 200, 1, 2601, 0xeab6c267, S=1, 1024, 0xcfc8799f
+0, 210, 210, 1, 2687, 0xfe1d0311, S=1, 1024, 0xcfc8799f
+0, 220, 220, 1, 2784, 0xca600dee, S=1, 1024, 0xcfc8799f
+0, 230, 230, 1, 2884, 0xc7134b99, S=1, 1024, 0xcfc8799f
+0, 240, 240, 1, 2982, 0x0b1e7825, S=1, 1024, 0xcfc8799f
+0, 250, 250, 1, 3101, 0x3e029e0e, S=1, 1024, 0xcfc8799f
+0, 260, 260, 1, 3253, 0x846af678, S=1, 1024, 0xcfc8799f
+0, 270, 270, 1, 3329, 0x29a81b71, S=1, 1024, 0xcfc8799f
+0, 280, 280, 1, 3572, 0xa3e08a52, S=1, 1024, 0xcfc8799f
+0, 290, 290, 1, 3807, 0x18e1fed2, S=1, 1024, 0xcfc8799f
+0, 300, 300, 1, 2750, 0xff6e1f9e, S=1, 1024, 0xcfc8799f
+0, 310, 310, 1, 4031, 0x6d4f7329, S=1, 1024, 0xcfc8799f
+0, 320, 320, 1, 3025, 0xb43c9e94, S=1, 1024, 0xcfc8799f
+0, 330, 330, 1, 4295, 0xc1850a80, S=1, 1024, 0xcfc8799f
+0, 340, 340, 1, 2044, 0x0440c072, S=1, 1024, 0xcfc8799f
+0, 350, 350, 1, 3212, 0xe91af08f, S=1, 1024, 0xcfc8799f
+0, 360, 360, 1, 2281, 0x6a414aa1, S=1, 1024, 0xcfc8799f
+0, 370, 370, 1, 3633, 0xac779aa3, S=1, 1024, 0xcfc8799f
+0, 380, 380, 1, 3552, 0xed2c75b2, S=1, 1024, 0xcfc8799f
+0, 390, 390, 1, 3690, 0x2020dd0d, S=1, 1024, 0xcfc8799f
+0, 400, 400, 1, 1558, 0x2c14e4b2, S=1, 1024, 0xcfc8799f
+0, 410, 410, 1, 940, 0x4927cd90, S=1, 1024, 0xcfc8799f
+0, 420, 420, 1, 273, 0x138c7831, S=1, 1024, 0xcfc8799f
+0, 430, 430, 1, 930, 0xf1c3ae3f, S=1, 1024, 0xcfc8799f
+0, 440, 440, 1, 271, 0x6d338044, S=1, 1024, 0xcfc8799f
+0, 450, 450, 1, 196, 0xa5de5322, S=1, 1024, 0xcfc8799f
+0, 460, 460, 1, 4299, 0x5bac0d86, S=1, 1024, 0xcfc8799f
+0, 470, 470, 1, 4895, 0xc43639a6, S=1, 1024, 0xcfc8799f
+0, 480, 480, 1, 4928, 0xf17d13e8, S=1, 1024, 0xcfc8799f
+0, 490, 490, 1, 4941, 0x71915520, S=1, 1024, 0xcfc8799f
+0, 500, 500, 1, 4154, 0xc860b8a6, S=1, 1024, 0xcfc8799f
+0, 510, 510, 1, 4678, 0x2651c339, S=1, 1024, 0xcfc8799f
+0, 520, 520, 1, 4741, 0xffd6bb45, S=1, 1024, 0xcfc8799f
+0, 530, 530, 1, 4982, 0x132c5977, S=1, 1024, 0xcfc8799f
+0, 540, 540, 1, 5179, 0x97aac3a1, S=1, 1024, 0xcfc8799f
+0, 550, 550, 1, 5046, 0x836a80cd, S=1, 1024, 0xcfc8799f
+0, 560, 560, 1, 5140, 0xa725c1e7, S=1, 1024, 0xcfc8799f
+0, 570, 570, 1, 4289, 0x7b3afbc0, S=1, 1024, 0xcfc8799f
+0, 580, 580, 1, 5079, 0xb2e7a2de, S=1, 1024, 0xcfc8799f
+0, 590, 590, 1, 5284, 0xb757dfe1, S=1, 1024, 0xcfc8799f
+0, 600, 600, 1, 5426, 0xf9f11e57, S=1, 1024, 0xcfc8799f
+0, 610, 610, 1, 4645, 0xf0f289e1, S=1, 1024, 0xcfc8799f
+0, 620, 620, 1, 5263, 0x8617d7e9, S=1, 1024, 0xcfc8799f
+0, 630, 630, 1, 5221, 0x26e3ca43, S=1, 1024, 0xcfc8799f
+0, 640, 640, 1, 5217, 0x90989cfb, S=1, 1024, 0xcfc8799f
+0, 650, 650, 1, 5395, 0xe29a01cb, S=1, 1024, 0xcfc8799f
+0, 660, 660, 1, 5220, 0xe2dee355, S=1, 1024, 0xcfc8799f
+0, 670, 670, 1, 5704, 0xcfbcd55e, S=1, 1024, 0xcfc8799f
+0, 680, 680, 1, 5636, 0x7fc2a1e5, S=1, 1024, 0xcfc8799f
+0, 690, 690, 1, 5818, 0x6090ebbd, S=1, 1024, 0xcfc8799f
+0, 700, 700, 1, 5763, 0xc110c791, S=1, 1024, 0xcfc8799f
+0, 710, 710, 1, 6116, 0xb4ee8e30, S=1, 1024, 0xcfc8799f
+0, 720, 720, 1, 6069, 0x21b263db, S=1, 1024, 0xcfc8799f
+0, 730, 730, 1, 5796, 0x2514df52, S=1, 1024, 0xcfc8799f
+0, 740, 740, 1, 5999, 0x1c3c3701, S=1, 1024, 0xcfc8799f
+0, 750, 750, 1, 6220, 0x8340b150, S=1, 1024, 0xcfc8799f
+0, 760, 760, 1, 6374, 0x00d8eaa5, S=1, 1024, 0xcfc8799f
+0, 770, 770, 1, 6465, 0x74c4778a, S=1, 1024, 0xcfc8799f
+0, 780, 780, 1, 7019, 0xdb1a28a3, S=1, 1024, 0xcfc8799f
+0, 790, 790, 1, 7255, 0x1e19b76e, S=1, 1024, 0xcfc8799f
+0, 800, 800, 1, 8197, 0x26bc6a79, S=1, 1024, 0xcfc8799f
+0, 810, 810, 1, 8358, 0x118781e0, S=1, 1024, 0xcfc8799f
+0, 820, 820, 1, 7708, 0xfc0c963d, S=1, 1024, 0xcfc8799f
+0, 830, 830, 1, 7412, 0xdcc311ee, S=1, 1024, 0xcfc8799f
+0, 840, 840, 1, 7541, 0x4d2819c1, S=1, 1024, 0xcfc8799f
+0, 850, 850, 1, 7948, 0xf12eca3d, S=1, 1024, 0xcfc8799f
+0, 860, 860, 1, 8408, 0x43add468, S=1, 1024, 0xcfc8799f
+0, 870, 870, 1, 8056, 0x2d162377, S=1, 1024, 0xcfc8799f
+0, 880, 880, 1, 7401, 0x26ebb649, S=1, 1024, 0xcfc8799f
+0, 890, 890, 1, 7494, 0x35fcf9ae, S=1, 1024, 0xcfc8799f
+0, 900, 900, 1, 7806, 0x4238723d, S=1, 1024, 0xcfc8799f
+0, 910, 910, 1, 7768, 0xb01e795a, S=1, 1024, 0xcfc8799f
+0, 920, 920, 1, 7749, 0x6ab39c12, S=1, 1024, 0xcfc8799f
+0, 930, 930, 1, 8047, 0x0e5f24aa, S=1, 1024, 0xcfc8799f
+0, 940, 940, 1, 7618, 0xd787340f, S=1, 1024, 0xcfc8799f
+0, 950, 950, 1, 7979, 0x0824c4df, S=1, 1024, 0xcfc8799f
+0, 960, 960, 1, 12062, 0xc46d9d92, S=1, 1024, 0xcfc8799f
+0, 970, 970, 1, 12317, 0x1314dc0c, S=1, 1024, 0xcfc8799f
+0, 980, 980, 1, 12217, 0x78c2ed30, S=1, 1024, 0xcfc8799f
+0, 990, 990, 1, 11227, 0x2a578eb9, S=1, 1024, 0xcfc8799f
+0, 1000, 1000, 1, 11108, 0x4eaa068c, S=1, 1024, 0xcfc8799f
+0, 1010, 1010, 1, 11366, 0x48f8993f, S=1, 1024, 0xcfc8799f
+0, 1020, 1020, 1, 11896, 0x32414841, S=1, 1024, 0xcfc8799f
+0, 1030, 1030, 1, 11479, 0xeaa38225, S=1, 1024, 0xcfc8799f
+0, 1040, 1040, 1, 13395, 0xaa9d4c72, S=1, 1024, 0xcfc8799f
+0, 1050, 1050, 1, 12913, 0x28854353, S=1, 1024, 0xcfc8799f
+0, 1060, 1060, 1, 13864, 0x663df630, S=1, 1024, 0xcfc8799f
+0, 1070, 1070, 1, 13551, 0xf7ba7be7, S=1, 1024, 0xcfc8799f
+0, 1080, 1080, 1, 14041, 0x2dc071b9, S=1, 1024, 0xcfc8799f
+0, 1090, 1090, 1, 14144, 0x33a03d1d, S=1, 1024, 0xcfc8799f
+0, 1100, 1100, 1, 14277, 0x6bda5935, S=1, 1024, 0xcfc8799f
+0, 1110, 1110, 1, 14424, 0xa696efd8, S=1, 1024, 0xcfc8799f
+0, 1120, 1120, 1, 14689, 0x8e3ad12c, S=1, 1024, 0xcfc8799f
+0, 1130, 1130, 1, 14598, 0x544668b4, S=1, 1024, 0xcfc8799f
+0, 1140, 1140, 1, 15213, 0x60009558, S=1, 1024, 0xcfc8799f
+0, 1150, 1150, 1, 15425, 0x86e5adf4, S=1, 1024, 0xcfc8799f
+0, 1160, 1160, 1, 15595, 0x878d09b9, S=1, 1024, 0xcfc8799f
+0, 1170, 1170, 1, 15598, 0x10daabc4, S=1, 1024, 0xcfc8799f
+0, 1180, 1180, 1, 15863, 0x2462016c, S=1, 1024, 0xcfc8799f
+0, 1190, 1190, 1, 15717, 0xe05041c4, S=1, 1024, 0xcfc8799f
+0, 1200, 1200, 1, 16078, 0x7c8f3a8c, S=1, 1024, 0xcfc8799f
+0, 1210, 1210, 1, 16225, 0x9771a52e, S=1, 1024, 0xcfc8799f
+0, 1220, 1220, 1, 16135, 0x2dfc1692, S=1, 1024, 0xcfc8799f
+0, 1230, 1230, 1, 16661, 0x09c96d7e, S=1, 1024, 0xcfc8799f
+0, 1240, 1240, 1, 16619, 0xc4735b56, S=1, 1024, 0xcfc8799f
+0, 1250, 1250, 1, 16829, 0x589dc13f, S=1, 1024, 0xcfc8799f
+0, 1260, 1260, 1, 16944, 0x997cd18f, S=1, 1024, 0xcfc8799f
+0, 1270, 1270, 1, 17119, 0x6c396b60, S=1, 1024, 0xcfc8799f
+0, 1280, 1280, 1, 17150, 0x8e603d31, S=1, 1024, 0xcfc8799f
+0, 1290, 1290, 1, 17321, 0x0bbcee5a, S=1, 1024, 0xcfc8799f
+0, 1300, 1300, 1, 17395, 0x99f0c974, S=1, 1024, 0xcfc8799f
+0, 1310, 1310, 1, 17666, 0x37184223, S=1, 1024, 0xcfc8799f
+0, 1320, 1320, 1, 17730, 0xa0d385b3, S=1, 1024, 0xcfc8799f
+0, 1330, 1330, 1, 17934, 0xb22cc97d, S=1, 1024, 0xcfc8799f
+0, 1340, 1340, 1, 17944, 0x0cd309c6, S=1, 1024, 0xcfc8799f
+0, 1350, 1350, 1, 18238, 0x6b7e3237, S=1, 1024, 0xcfc8799f
+0, 1360, 1360, 1, 18391, 0x4df3c48a, S=1, 1024, 0xcfc8799f
+0, 1370, 1370, 1, 18543, 0x90a2f238, S=1, 1024, 0xcfc8799f
+0, 1380, 1380, 1, 18939, 0xc57dda5b, S=1, 1024, 0xcfc8799f
+0, 1390, 1390, 1, 19145, 0x1267294a, S=1, 1024, 0xcfc8799f
+0, 1400, 1400, 1, 19120, 0xeac6a9c3, S=1, 1024, 0xcfc8799f
+0, 1410, 1410, 1, 19130, 0x31f3edbc, S=1, 1024, 0xcfc8799f
+0, 1420, 1420, 1, 19494, 0x3259a2f3, S=1, 1024, 0xcfc8799f
+0, 1430, 1430, 1, 19534, 0xda22a752, S=1, 1024, 0xcfc8799f
+0, 1440, 1440, 1, 19747, 0x8805c379, S=1, 1024, 0xcfc8799f
+0, 1450, 1450, 1, 20114, 0xaaf96864, S=1, 1024, 0xcfc8799f
+0, 1460, 1460, 1, 20257, 0x7223da26, S=1, 1024, 0xcfc8799f
+0, 1470, 1470, 1, 20370, 0x08ef382a, S=1, 1024, 0xcfc8799f
+0, 1480, 1480, 1, 20292, 0x4b47f207, S=1, 1024, 0xcfc8799f
+0, 1490, 1490, 1, 20491, 0xeedd6d1c, S=1, 1024, 0xcfc8799f
+0, 1500, 1500, 1, 20647, 0xb0d1dd45, S=1, 1024, 0xcfc8799f
+0, 1510, 1510, 1, 20666, 0x382cc8a4, S=1, 1024, 0xcfc8799f
+0, 1520, 1520, 1, 21007, 0x398f4f7d, S=1, 1024, 0xcfc8799f
+0, 1530, 1530, 1, 21058, 0xd6616a9d, S=1, 1024, 0xcfc8799f
+0, 1540, 1540, 1, 21153, 0x988749db, S=1, 1024, 0xcfc8799f
+0, 1550, 1550, 1, 21078, 0x1b328059, S=1, 1024, 0xcfc8799f
+0, 1560, 1560, 1, 21458, 0x6348529c, S=1, 1024, 0xcfc8799f
+0, 1570, 1570, 1, 21669, 0xcf63e2de, S=1, 1024, 0xcfc8799f
+0, 1580, 1580, 1, 21581, 0x1fc021af, S=1, 1024, 0xcfc8799f
+0, 1590, 1590, 1, 21654, 0x899dab18, S=1, 1024, 0xcfc8799f
+0, 1600, 1600, 1, 21987, 0x634086fe, S=1, 1024, 0xcfc8799f
+0, 1610, 1610, 1, 22205, 0x617a7335, S=1, 1024, 0xcfc8799f
+0, 1620, 1620, 1, 22475, 0x9fa2e01c, S=1, 1024, 0xcfc8799f
+0, 1630, 1630, 1, 22490, 0x7dc5376c, S=1, 1024, 0xcfc8799f
+0, 1640, 1640, 1, 22460, 0x33e6bbfe, S=1, 1024, 0xcfc8799f
+0, 1650, 1650, 1, 22861, 0x18993510, S=1, 1024, 0xcfc8799f
+0, 1660, 1660, 1, 22746, 0xdff85615, S=1, 1024, 0xcfc8799f
+0, 1670, 1670, 1, 23165, 0xf0ac66a3, S=1, 1024, 0xcfc8799f
+0, 1680, 1680, 1, 23273, 0x13869ad9, S=1, 1024, 0xcfc8799f
+0, 1690, 1690, 1, 23211, 0xd30b6205, S=1, 1024, 0xcfc8799f
+0, 1700, 1700, 1, 23648, 0xa0cef01b, S=1, 1024, 0xcfc8799f
+0, 1710, 1710, 1, 23675, 0x760460b9, S=1, 1024, 0xcfc8799f
+0, 1720, 1720, 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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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-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-AMP_A_Samsung_4 b/tests/ref/fate/hevc-conformance-AMP_A_Samsung_4
new file mode 100644
index 0000000..84487a5
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-AMP_A_Samsung_4
@@ -0,0 +1,61 @@
+#tb 0: 1/25
+0, 0, 0, 1, 6144000, 0xf7da9a00
+0, 1, 1, 1, 6144000, 0xf5cfc76f
+0, 2, 2, 1, 6144000, 0x20663e82
+0, 3, 3, 1, 6144000, 0xbff3d1e7
+0, 4, 4, 1, 6144000, 0x6f1b824d
+0, 5, 5, 1, 6144000, 0x4d75e5c9
+0, 6, 6, 1, 6144000, 0xb4443853
+0, 7, 7, 1, 6144000, 0x6943bbcb
+0, 8, 8, 1, 6144000, 0x1748b8d3
+0, 9, 9, 1, 6144000, 0x0e15caec
+0, 10, 10, 1, 6144000, 0xf7553ff4
+0, 11, 11, 1, 6144000, 0x34007146
+0, 12, 12, 1, 6144000, 0xd115a7ad
+0, 13, 13, 1, 6144000, 0x1adc8d27
+0, 14, 14, 1, 6144000, 0x2c3a43a6
+0, 15, 15, 1, 6144000, 0x1820500a
+0, 16, 16, 1, 6144000, 0xb33cf5af
+0, 17, 17, 1, 6144000, 0x5ba58d5a
+0, 18, 18, 1, 6144000, 0x453f35bc
+0, 19, 19, 1, 6144000, 0x4e6ac2ab
+0, 20, 20, 1, 6144000, 0xfab2b132
+0, 21, 21, 1, 6144000, 0xf903b7bf
+0, 22, 22, 1, 6144000, 0x160ebf13
+0, 23, 23, 1, 6144000, 0xd147c884
+0, 24, 24, 1, 6144000, 0x266abc04
+0, 25, 25, 1, 6144000, 0x9fabf642
+0, 26, 26, 1, 6144000, 0x1ad4f6c7
+0, 27, 27, 1, 6144000, 0x41fa1e6f
+0, 28, 28, 1, 6144000, 0x14b2b3b4
+0, 29, 29, 1, 6144000, 0x19c6d13e
+0, 30, 30, 1, 6144000, 0x414f5a36
+0, 31, 31, 1, 6144000, 0x439278aa
+0, 32, 32, 1, 6144000, 0xf8e73a55
+0, 33, 33, 1, 6144000, 0xf4cf7779
+0, 34, 34, 1, 6144000, 0x86ac3a16
+0, 35, 35, 1, 6144000, 0xdc9abdb8
+0, 36, 36, 1, 6144000, 0x9ab68a62
+0, 37, 37, 1, 6144000, 0xcd290547
+0, 38, 38, 1, 6144000, 0xd2eb88bb
+0, 39, 39, 1, 6144000, 0x126e084e
+0, 40, 40, 1, 6144000, 0x1aa5302c
+0, 41, 41, 1, 6144000, 0x689cb93e
+0, 42, 42, 1, 6144000, 0xaa9e3be6
+0, 43, 43, 1, 6144000, 0x33dc9ead
+0, 44, 44, 1, 6144000, 0xcb943dd3
+0, 45, 45, 1, 6144000, 0x22a67b19
+0, 46, 46, 1, 6144000, 0x3bfb741a
+0, 47, 47, 1, 6144000, 0x9238e595
+0, 48, 48, 1, 6144000, 0xf0fb6381
+0, 49, 49, 1, 6144000, 0x6ea42af1
+0, 50, 50, 1, 6144000, 0x47d9c3a7
+0, 51, 51, 1, 6144000, 0x9f73966b
+0, 52, 52, 1, 6144000, 0xdf777adc
+0, 53, 53, 1, 6144000, 0xf51f206e
+0, 54, 54, 1, 6144000, 0x465c350a
+0, 55, 55, 1, 6144000, 0x9253a45a
+0, 56, 56, 1, 6144000, 0x72c89751
+0, 57, 57, 1, 6144000, 0x0405cdfc
+0, 58, 58, 1, 6144000, 0xc5ede0c7
+0, 59, 59, 1, 6144000, 0xcf1c2b5e
diff --git a/tests/ref/fate/hevc-conformance-AMP_B_Samsung_4 b/tests/ref/fate/hevc-conformance-AMP_B_Samsung_4
new file mode 100644
index 0000000..034f7b8
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-AMP_B_Samsung_4
@@ -0,0 +1,61 @@
+#tb 0: 1/25
+0, 0, 0, 1, 6144000, 0xcd32ef33
+0, 1, 1, 1, 6144000, 0x58ce681d
+0, 2, 2, 1, 6144000, 0x77a732b6
+0, 3, 3, 1, 6144000, 0xa95418d0
+0, 4, 4, 1, 6144000, 0xa1593606
+0, 5, 5, 1, 6144000, 0x0d5429bc
+0, 6, 6, 1, 6144000, 0xe7cd205c
+0, 7, 7, 1, 6144000, 0x52c30ff4
+0, 8, 8, 1, 6144000, 0xf0a0f686
+0, 9, 9, 1, 6144000, 0xa6371d86
+0, 10, 10, 1, 6144000, 0x18bf1478
+0, 11, 11, 1, 6144000, 0xb84c6322
+0, 12, 12, 1, 6144000, 0x12f35f80
+0, 13, 13, 1, 6144000, 0xa9009e83
+0, 14, 14, 1, 6144000, 0x08568380
+0, 15, 15, 1, 6144000, 0xb01e98e8
+0, 16, 16, 1, 6144000, 0x0796ee90
+0, 17, 17, 1, 6144000, 0x3bb7cbef
+0, 18, 18, 1, 6144000, 0x7c3d6929
+0, 19, 19, 1, 6144000, 0x62c0e56c
+0, 20, 20, 1, 6144000, 0xd05907f7
+0, 21, 21, 1, 6144000, 0x9aa33b33
+0, 22, 22, 1, 6144000, 0xc47a0195
+0, 23, 23, 1, 6144000, 0xa5a5db13
+0, 24, 24, 1, 6144000, 0x54fda44b
+0, 25, 25, 1, 6144000, 0x7695be2f
+0, 26, 26, 1, 6144000, 0x247228e1
+0, 27, 27, 1, 6144000, 0xec38b2f7
+0, 28, 28, 1, 6144000, 0x223b098d
+0, 29, 29, 1, 6144000, 0xdd13f4bf
+0, 30, 30, 1, 6144000, 0x42651b46
+0, 31, 31, 1, 6144000, 0xc0b2ac9a
+0, 32, 32, 1, 6144000, 0x574908ee
+0, 33, 33, 1, 6144000, 0x070f0d88
+0, 34, 34, 1, 6144000, 0xc68ee679
+0, 35, 35, 1, 6144000, 0x4d571c82
+0, 36, 36, 1, 6144000, 0xec7f28cb
+0, 37, 37, 1, 6144000, 0x07ca3ccd
+0, 38, 38, 1, 6144000, 0xa5161fd7
+0, 39, 39, 1, 6144000, 0xb0908b25
+0, 40, 40, 1, 6144000, 0x4fa56c5e
+0, 41, 41, 1, 6144000, 0x1ad84207
+0, 42, 42, 1, 6144000, 0xc862a32b
+0, 43, 43, 1, 6144000, 0x341b9b0a
+0, 44, 44, 1, 6144000, 0xa940cdab
+0, 45, 45, 1, 6144000, 0x57521b2d
+0, 46, 46, 1, 6144000, 0x31969dee
+0, 47, 47, 1, 6144000, 0x7a09e240
+0, 48, 48, 1, 6144000, 0x14e6c360
+0, 49, 49, 1, 6144000, 0x0dfd6085
+0, 50, 50, 1, 6144000, 0xdf231a1e
+0, 51, 51, 1, 6144000, 0x6d1e9ce1
+0, 52, 52, 1, 6144000, 0xc6c2fb26
+0, 53, 53, 1, 6144000, 0xd4bc5e3e
+0, 54, 54, 1, 6144000, 0xa4a56b9e
+0, 55, 55, 1, 6144000, 0x8ba6349f
+0, 56, 56, 1, 6144000, 0x0683757f
+0, 57, 57, 1, 6144000, 0xe3840d8b
+0, 58, 58, 1, 6144000, 0x2fdf2ae6
+0, 59, 59, 1, 6144000, 0xea877e27
diff --git a/tests/ref/fate/hevc-conformance-AMP_D_Hisilicon b/tests/ref/fate/hevc-conformance-AMP_D_Hisilicon
new file mode 100644
index 0000000..6e17b83
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-AMP_D_Hisilicon
@@ -0,0 +1,101 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0x1559c293
+0, 1, 1, 1, 3110400, 0xd0802706
+0, 2, 2, 1, 3110400, 0xb48cf229
+0, 3, 3, 1, 3110400, 0x4108509b
+0, 4, 4, 1, 3110400, 0xd1cec277
+0, 5, 5, 1, 3110400, 0x3e68c589
+0, 6, 6, 1, 3110400, 0x1543a517
+0, 7, 7, 1, 3110400, 0x5ddcd669
+0, 8, 8, 1, 3110400, 0x09bd4c27
+0, 9, 9, 1, 3110400, 0xd583bfa1
+0, 10, 10, 1, 3110400, 0xe9411279
+0, 11, 11, 1, 3110400, 0xe07e6f3f
+0, 12, 12, 1, 3110400, 0xcfd23191
+0, 13, 13, 1, 3110400, 0x24276734
+0, 14, 14, 1, 3110400, 0x485aeafe
+0, 15, 15, 1, 3110400, 0xb8039a85
+0, 16, 16, 1, 3110400, 0x1d154e19
+0, 17, 17, 1, 3110400, 0xaa3ce800
+0, 18, 18, 1, 3110400, 0xe2601cba
+0, 19, 19, 1, 3110400, 0xb6657a57
+0, 20, 20, 1, 3110400, 0x34dbda52
+0, 21, 21, 1, 3110400, 0x921e218a
+0, 22, 22, 1, 3110400, 0x7de5262f
+0, 23, 23, 1, 3110400, 0x1a97e083
+0, 24, 24, 1, 3110400, 0x4bfc81d0
+0, 25, 25, 1, 3110400, 0x583396e6
+0, 26, 26, 1, 3110400, 0xc96bcd39
+0, 27, 27, 1, 3110400, 0x483cf7cf
+0, 28, 28, 1, 3110400, 0x20882e52
+0, 29, 29, 1, 3110400, 0x93d352fe
+0, 30, 30, 1, 3110400, 0x0c932722
+0, 31, 31, 1, 3110400, 0x78c5a9f0
+0, 32, 32, 1, 3110400, 0xcea3bddd
+0, 33, 33, 1, 3110400, 0x3e4e7c77
+0, 34, 34, 1, 3110400, 0xbe048a0a
+0, 35, 35, 1, 3110400, 0x1cf7ea0d
+0, 36, 36, 1, 3110400, 0xeb60343a
+0, 37, 37, 1, 3110400, 0x2158ed1f
+0, 38, 38, 1, 3110400, 0x3a7126b1
+0, 39, 39, 1, 3110400, 0x282804ff
+0, 40, 40, 1, 3110400, 0x292ed438
+0, 41, 41, 1, 3110400, 0x49a9769d
+0, 42, 42, 1, 3110400, 0xdfc12632
+0, 43, 43, 1, 3110400, 0xff3da16a
+0, 44, 44, 1, 3110400, 0x134b68c6
+0, 45, 45, 1, 3110400, 0x717e6f1d
+0, 46, 46, 1, 3110400, 0x283293f5
+0, 47, 47, 1, 3110400, 0x3d401456
+0, 48, 48, 1, 3110400, 0x500eddac
+0, 49, 49, 1, 3110400, 0x2a96fbff
+0, 50, 50, 1, 3110400, 0x9d75f303
+0, 51, 51, 1, 3110400, 0x08d1fa48
+0, 52, 52, 1, 3110400, 0xa685a8da
+0, 53, 53, 1, 3110400, 0xc19216d8
+0, 54, 54, 1, 3110400, 0x61ebd7f2
+0, 55, 55, 1, 3110400, 0x866c9002
+0, 56, 56, 1, 3110400, 0x3edda174
+0, 57, 57, 1, 3110400, 0x4e848db7
+0, 58, 58, 1, 3110400, 0x1dd822ba
+0, 59, 59, 1, 3110400, 0x8157b534
+0, 60, 60, 1, 3110400, 0x72637dbe
+0, 61, 61, 1, 3110400, 0xc6fc1305
+0, 62, 62, 1, 3110400, 0xbfadeee4
+0, 63, 63, 1, 3110400, 0xad20c230
+0, 64, 64, 1, 3110400, 0x5afff02b
+0, 65, 65, 1, 3110400, 0x5e533c71
+0, 66, 66, 1, 3110400, 0x52e10588
+0, 67, 67, 1, 3110400, 0x13a6dbb1
+0, 68, 68, 1, 3110400, 0xc74de5ae
+0, 69, 69, 1, 3110400, 0x382aafb8
+0, 70, 70, 1, 3110400, 0x5e0a11b2
+0, 71, 71, 1, 3110400, 0x049fe7cc
+0, 72, 72, 1, 3110400, 0x9d79484e
+0, 73, 73, 1, 3110400, 0x1116ced8
+0, 74, 74, 1, 3110400, 0x5d8d075d
+0, 75, 75, 1, 3110400, 0x49392496
+0, 76, 76, 1, 3110400, 0x5f24b3b3
+0, 77, 77, 1, 3110400, 0x6ca1c16d
+0, 78, 78, 1, 3110400, 0x131a16d2
+0, 79, 79, 1, 3110400, 0x39e2f9a1
+0, 80, 80, 1, 3110400, 0x988bd0ee
+0, 81, 81, 1, 3110400, 0xa6c050ec
+0, 82, 82, 1, 3110400, 0x5275142a
+0, 83, 83, 1, 3110400, 0x5705923d
+0, 84, 84, 1, 3110400, 0x3098d52d
+0, 85, 85, 1, 3110400, 0xb16e2eb7
+0, 86, 86, 1, 3110400, 0x0dee6bc8
+0, 87, 87, 1, 3110400, 0x577acf61
+0, 88, 88, 1, 3110400, 0x2b70d954
+0, 89, 89, 1, 3110400, 0x26b5f1c5
+0, 90, 90, 1, 3110400, 0x2351ad88
+0, 91, 91, 1, 3110400, 0xe5bdf6ad
+0, 92, 92, 1, 3110400, 0xaf0d83de
+0, 93, 93, 1, 3110400, 0xaee86799
+0, 94, 94, 1, 3110400, 0xe73fe067
+0, 95, 95, 1, 3110400, 0x46b90697
+0, 96, 96, 1, 3110400, 0xb270f77a
+0, 97, 97, 1, 3110400, 0xf33aa535
+0, 98, 98, 1, 3110400, 0xcafe6eec
+0, 99, 99, 1, 3110400, 0xcf051a31
diff --git a/tests/ref/fate/hevc-conformance-AMP_E_Hisilicon b/tests/ref/fate/hevc-conformance-AMP_E_Hisilicon
new file mode 100644
index 0000000..c1b7f2e
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-AMP_E_Hisilicon
@@ -0,0 +1,101 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0xf9342188
+0, 1, 1, 1, 3110400, 0x46638dc4
+0, 2, 2, 1, 3110400, 0x96da436e
+0, 3, 3, 1, 3110400, 0xae9ee064
+0, 4, 4, 1, 3110400, 0x03fc9d17
+0, 5, 5, 1, 3110400, 0xd7ba9ab8
+0, 6, 6, 1, 3110400, 0x9f3cc881
+0, 7, 7, 1, 3110400, 0x911c9e2a
+0, 8, 8, 1, 3110400, 0x2c1bdec1
+0, 9, 9, 1, 3110400, 0xffc2cfb2
+0, 10, 10, 1, 3110400, 0x34136d4c
+0, 11, 11, 1, 3110400, 0x400dca0c
+0, 12, 12, 1, 3110400, 0x5a3d3c71
+0, 13, 13, 1, 3110400, 0x5bd262f9
+0, 14, 14, 1, 3110400, 0x27bbec47
+0, 15, 15, 1, 3110400, 0x53ca3f78
+0, 16, 16, 1, 3110400, 0x7fee4170
+0, 17, 17, 1, 3110400, 0x393d318c
+0, 18, 18, 1, 3110400, 0x203f26f1
+0, 19, 19, 1, 3110400, 0x35e00c3e
+0, 20, 20, 1, 3110400, 0x995afdde
+0, 21, 21, 1, 3110400, 0xa8b623b9
+0, 22, 22, 1, 3110400, 0x047e53bd
+0, 23, 23, 1, 3110400, 0xc7e69515
+0, 24, 24, 1, 3110400, 0x7e5ade49
+0, 25, 25, 1, 3110400, 0x863cddc9
+0, 26, 26, 1, 3110400, 0xb1f6189c
+0, 27, 27, 1, 3110400, 0x622d6d1d
+0, 28, 28, 1, 3110400, 0x1e82ef1a
+0, 29, 29, 1, 3110400, 0x06a7054a
+0, 30, 30, 1, 3110400, 0x736bd4a9
+0, 31, 31, 1, 3110400, 0x1db8ead3
+0, 32, 32, 1, 3110400, 0x1d872697
+0, 33, 33, 1, 3110400, 0x86b11604
+0, 34, 34, 1, 3110400, 0x54bee045
+0, 35, 35, 1, 3110400, 0x3577fa15
+0, 36, 36, 1, 3110400, 0x717b6c0b
+0, 37, 37, 1, 3110400, 0x5e0f0b6e
+0, 38, 38, 1, 3110400, 0x054ecc86
+0, 39, 39, 1, 3110400, 0x9ec29ad1
+0, 40, 40, 1, 3110400, 0x7c3b56e4
+0, 41, 41, 1, 3110400, 0xcf4cf721
+0, 42, 42, 1, 3110400, 0x43c01adb
+0, 43, 43, 1, 3110400, 0x6abb4879
+0, 44, 44, 1, 3110400, 0x90473c9f
+0, 45, 45, 1, 3110400, 0x5f5bb9a9
+0, 46, 46, 1, 3110400, 0x08678e6b
+0, 47, 47, 1, 3110400, 0xf4ad0c9b
+0, 48, 48, 1, 3110400, 0x22870cc8
+0, 49, 49, 1, 3110400, 0xb417cf63
+0, 50, 50, 1, 3110400, 0xb7a1588e
+0, 51, 51, 1, 3110400, 0x7a35ac81
+0, 52, 52, 1, 3110400, 0xcd1c6d82
+0, 53, 53, 1, 3110400, 0x181b9920
+0, 54, 54, 1, 3110400, 0xf2417d5e
+0, 55, 55, 1, 3110400, 0x8a67e02b
+0, 56, 56, 1, 3110400, 0xe7b99077
+0, 57, 57, 1, 3110400, 0x6814e5c2
+0, 58, 58, 1, 3110400, 0xd8bce44d
+0, 59, 59, 1, 3110400, 0x9faf4ebc
+0, 60, 60, 1, 3110400, 0x3daa5fbf
+0, 61, 61, 1, 3110400, 0x747921ba
+0, 62, 62, 1, 3110400, 0xbe30214e
+0, 63, 63, 1, 3110400, 0x8f5533fe
+0, 64, 64, 1, 3110400, 0x835a4545
+0, 65, 65, 1, 3110400, 0xfa99f4c8
+0, 66, 66, 1, 3110400, 0x9559c5db
+0, 67, 67, 1, 3110400, 0xd0d096f8
+0, 68, 68, 1, 3110400, 0x7b24dbb0
+0, 69, 69, 1, 3110400, 0x4a8aa189
+0, 70, 70, 1, 3110400, 0x876bab32
+0, 71, 71, 1, 3110400, 0xc930bec9
+0, 72, 72, 1, 3110400, 0x009841d8
+0, 73, 73, 1, 3110400, 0x93e5be89
+0, 74, 74, 1, 3110400, 0x82260331
+0, 75, 75, 1, 3110400, 0x7ef2e971
+0, 76, 76, 1, 3110400, 0x606b638a
+0, 77, 77, 1, 3110400, 0xf08b84df
+0, 78, 78, 1, 3110400, 0x8a609222
+0, 79, 79, 1, 3110400, 0xa76cb2f3
+0, 80, 80, 1, 3110400, 0x2b611cb3
+0, 81, 81, 1, 3110400, 0x81d5b315
+0, 82, 82, 1, 3110400, 0x6f385e43
+0, 83, 83, 1, 3110400, 0x5959a754
+0, 84, 84, 1, 3110400, 0x1cf4935c
+0, 85, 85, 1, 3110400, 0xc8da3639
+0, 86, 86, 1, 3110400, 0x50a2ee3d
+0, 87, 87, 1, 3110400, 0xd33ad53a
+0, 88, 88, 1, 3110400, 0xe7ed4eff
+0, 89, 89, 1, 3110400, 0x7d72d260
+0, 90, 90, 1, 3110400, 0x16ca295b
+0, 91, 91, 1, 3110400, 0xf126df1d
+0, 92, 92, 1, 3110400, 0x0aca09d1
+0, 93, 93, 1, 3110400, 0x6aefb52b
+0, 94, 94, 1, 3110400, 0xf797ee6d
+0, 95, 95, 1, 3110400, 0xf1053ace
+0, 96, 96, 1, 3110400, 0xf7f91618
+0, 97, 97, 1, 3110400, 0xc711acf8
+0, 98, 98, 1, 3110400, 0x31123f40
+0, 99, 99, 1, 3110400, 0xc7b703dc
diff --git a/tests/ref/fate/hevc-conformance-AMP_F_Hisilicon_3 b/tests/ref/fate/hevc-conformance-AMP_F_Hisilicon_3
new file mode 100644
index 0000000..71ce9c7
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-AMP_F_Hisilicon_3
@@ -0,0 +1,101 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0xa5d2b8b0
+0, 1, 1, 1, 3110400, 0x13035cfa
+0, 2, 2, 1, 3110400, 0x96b16f86
+0, 3, 3, 1, 3110400, 0x09e96331
+0, 4, 4, 1, 3110400, 0xd2662da8
+0, 5, 5, 1, 3110400, 0x77d3db00
+0, 6, 6, 1, 3110400, 0xaa025e5b
+0, 7, 7, 1, 3110400, 0x77284bc5
+0, 8, 8, 1, 3110400, 0x625b165e
+0, 9, 9, 1, 3110400, 0x69c0b4c8
+0, 10, 10, 1, 3110400, 0x52e627a4
+0, 11, 11, 1, 3110400, 0x774eaf6a
+0, 12, 12, 1, 3110400, 0xa9042cad
+0, 13, 13, 1, 3110400, 0xf367e96a
+0, 14, 14, 1, 3110400, 0x4687e2d9
+0, 15, 15, 1, 3110400, 0xe57d46b8
+0, 16, 16, 1, 3110400, 0x074da0b5
+0, 17, 17, 1, 3110400, 0xbf8dd856
+0, 18, 18, 1, 3110400, 0xb9cae21e
+0, 19, 19, 1, 3110400, 0xa43687fc
+0, 20, 20, 1, 3110400, 0x83cce559
+0, 21, 21, 1, 3110400, 0xb19963d9
+0, 22, 22, 1, 3110400, 0x636d69b7
+0, 23, 23, 1, 3110400, 0xfcfe1a00
+0, 24, 24, 1, 3110400, 0x0a804c37
+0, 25, 25, 1, 3110400, 0x6af0c5ec
+0, 26, 26, 1, 3110400, 0xccec0692
+0, 27, 27, 1, 3110400, 0x0547e98d
+0, 28, 28, 1, 3110400, 0xc4dc2caa
+0, 29, 29, 1, 3110400, 0x43473ac6
+0, 30, 30, 1, 3110400, 0xd5e9a795
+0, 31, 31, 1, 3110400, 0x3227df7b
+0, 32, 32, 1, 3110400, 0x087e57bb
+0, 33, 33, 1, 3110400, 0x892f5ad0
+0, 34, 34, 1, 3110400, 0xeeb23459
+0, 35, 35, 1, 3110400, 0xd1efe2a6
+0, 36, 36, 1, 3110400, 0x5abd5104
+0, 37, 37, 1, 3110400, 0x6b018b83
+0, 38, 38, 1, 3110400, 0x91617ca7
+0, 39, 39, 1, 3110400, 0x601cd6ad
+0, 40, 40, 1, 3110400, 0xf81cb126
+0, 41, 41, 1, 3110400, 0x4bb949df
+0, 42, 42, 1, 3110400, 0xed94fea0
+0, 43, 43, 1, 3110400, 0x39ba8fec
+0, 44, 44, 1, 3110400, 0xc65e113c
+0, 45, 45, 1, 3110400, 0x627344cb
+0, 46, 46, 1, 3110400, 0x5680c16a
+0, 47, 47, 1, 3110400, 0x12d02cfc
+0, 48, 48, 1, 3110400, 0x2e409afa
+0, 49, 49, 1, 3110400, 0xfd4142f2
+0, 50, 50, 1, 3110400, 0x6db3965a
+0, 51, 51, 1, 3110400, 0x578962c5
+0, 52, 52, 1, 3110400, 0x68d75bd1
+0, 53, 53, 1, 3110400, 0x568fbb72
+0, 54, 54, 1, 3110400, 0xf3c03b95
+0, 55, 55, 1, 3110400, 0xeb67b532
+0, 56, 56, 1, 3110400, 0x0e445b34
+0, 57, 57, 1, 3110400, 0x32c04ad2
+0, 58, 58, 1, 3110400, 0x239d1a14
+0, 59, 59, 1, 3110400, 0xcb295635
+0, 60, 60, 1, 3110400, 0x7e347c1d
+0, 61, 61, 1, 3110400, 0x74e1fcf7
+0, 62, 62, 1, 3110400, 0x6e399603
+0, 63, 63, 1, 3110400, 0xe3bbdbcd
+0, 64, 64, 1, 3110400, 0xddd336f3
+0, 65, 65, 1, 3110400, 0x7834e9f7
+0, 66, 66, 1, 3110400, 0xb53a7f1f
+0, 67, 67, 1, 3110400, 0x1f52cbb6
+0, 68, 68, 1, 3110400, 0xea26692a
+0, 69, 69, 1, 3110400, 0xa4e1765f
+0, 70, 70, 1, 3110400, 0x6367794d
+0, 71, 71, 1, 3110400, 0x69bff6d1
+0, 72, 72, 1, 3110400, 0xdf52ef08
+0, 73, 73, 1, 3110400, 0x002892b7
+0, 74, 74, 1, 3110400, 0x1ca49791
+0, 75, 75, 1, 3110400, 0x8de95d1d
+0, 76, 76, 1, 3110400, 0x9c9c38cf
+0, 77, 77, 1, 3110400, 0x9f9947cd
+0, 78, 78, 1, 3110400, 0xe5da908b
+0, 79, 79, 1, 3110400, 0x032415ae
+0, 80, 80, 1, 3110400, 0x0fef3a03
+0, 81, 81, 1, 3110400, 0xd04c1b77
+0, 82, 82, 1, 3110400, 0x5d46813b
+0, 83, 83, 1, 3110400, 0x1dbeaa76
+0, 84, 84, 1, 3110400, 0x2b2eea1a
+0, 85, 85, 1, 3110400, 0x7138da47
+0, 86, 86, 1, 3110400, 0xe9a43ef8
+0, 87, 87, 1, 3110400, 0x02f7b1bf
+0, 88, 88, 1, 3110400, 0xd1cdf8b1
+0, 89, 89, 1, 3110400, 0x2e924022
+0, 90, 90, 1, 3110400, 0x59d68bcf
+0, 91, 91, 1, 3110400, 0x3dc70503
+0, 92, 92, 1, 3110400, 0x26aeb1fa
+0, 93, 93, 1, 3110400, 0x91434f9d
+0, 94, 94, 1, 3110400, 0x91411f14
+0, 95, 95, 1, 3110400, 0xd99a172a
+0, 96, 96, 1, 3110400, 0x19678f5a
+0, 97, 97, 1, 3110400, 0xc6c357ae
+0, 98, 98, 1, 3110400, 0xba6cd89f
+0, 99, 99, 1, 3110400, 0x657af6cf
diff --git a/tests/ref/fate/hevc-conformance-AMVP_A_MTK_4 b/tests/ref/fate/hevc-conformance-AMVP_A_MTK_4
new file mode 100644
index 0000000..59115fb
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-AMVP_A_MTK_4
@@ -0,0 +1,31 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x88619f80
+0, 1, 1, 1, 149760, 0x550bdaf0
+0, 2, 2, 1, 149760, 0xb769fa4c
+0, 3, 3, 1, 149760, 0x3c2c2e9a
+0, 4, 4, 1, 149760, 0x75316bcc
+0, 5, 5, 1, 149760, 0x7b9ba7ff
+0, 6, 6, 1, 149760, 0x9981ea7b
+0, 7, 7, 1, 149760, 0x3f682105
+0, 8, 8, 1, 149760, 0x63252c25
+0, 9, 9, 1, 149760, 0x44427967
+0, 10, 10, 1, 149760, 0x24199a9e
+0, 11, 11, 1, 149760, 0xaa30c241
+0, 12, 12, 1, 149760, 0xf24faaaf
+0, 13, 13, 1, 149760, 0x0291c766
+0, 14, 14, 1, 149760, 0xb826e44f
+0, 15, 15, 1, 149760, 0xbc2310b8
+0, 16, 16, 1, 149760, 0xcfd81d4a
+0, 17, 17, 1, 149760, 0xb356484a
+0, 18, 18, 1, 149760, 0x02bf515a
+0, 19, 19, 1, 149760, 0x729d778c
+0, 20, 20, 1, 149760, 0x3ade8453
+0, 21, 21, 1, 149760, 0xfedead3d
+0, 22, 22, 1, 149760, 0x46bfc8db
+0, 23, 23, 1, 149760, 0x8590f422
+0, 24, 24, 1, 149760, 0x6d2dfd9d
+0, 25, 25, 1, 149760, 0x373f2c82
+0, 26, 26, 1, 149760, 0xa12f3ca1
+0, 27, 27, 1, 149760, 0x34be4b0d
+0, 28, 28, 1, 149760, 0x24f538b9
+0, 29, 29, 1, 149760, 0xd1616303
diff --git a/tests/ref/fate/hevc-conformance-AMVP_B_MTK_4 b/tests/ref/fate/hevc-conformance-AMVP_B_MTK_4
new file mode 100644
index 0000000..1f998c4
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-AMVP_B_MTK_4
@@ -0,0 +1,42 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xcfffa013
+0, 1, 1, 1, 149760, 0x5166146a
+0, 2, 2, 1, 149760, 0xc3cc318e
+0, 3, 3, 1, 149760, 0x5bb465f9
+0, 4, 4, 1, 149760, 0x10c97bd4
+0, 5, 5, 1, 149760, 0xd9d5c4ab
+0, 6, 6, 1, 149760, 0x5112e11d
+0, 7, 7, 1, 149760, 0xde3803d6
+0, 8, 8, 1, 149760, 0x82c62409
+0, 9, 9, 1, 149760, 0x28f88d53
+0, 10, 10, 1, 149760, 0x796fb89d
+0, 11, 11, 1, 149760, 0x1b95dd75
+0, 12, 12, 1, 149760, 0xfcc9ced4
+0, 13, 13, 1, 149760, 0x6b00ee9c
+0, 14, 14, 1, 149760, 0xdb72e81a
+0, 15, 15, 1, 149760, 0x0c771a25
+0, 16, 16, 1, 149760, 0x959a2215
+0, 17, 17, 1, 149760, 0xf1d672ce
+0, 18, 18, 1, 149760, 0x2f407a06
+0, 19, 19, 1, 149760, 0xee389f83
+0, 20, 20, 1, 149760, 0x2e0695dd
+0, 21, 21, 1, 149760, 0xf80ac1eb
+0, 22, 22, 1, 149760, 0x29decec4
+0, 23, 23, 1, 149760, 0xff34eb5e
+0, 24, 24, 1, 149760, 0x1c85fe71
+0, 25, 25, 1, 149760, 0x056dae51
+0, 26, 26, 1, 149760, 0x78a99f1d
+0, 27, 27, 1, 149760, 0xe507b40c
+0, 28, 28, 1, 149760, 0xbd3fa06c
+0, 29, 29, 1, 149760, 0x3475d95b
+0, 30, 30, 1, 149760, 0x9b25d416
+0, 31, 31, 1, 149760, 0x73c4ec88
+0, 32, 32, 1, 149760, 0xd4437e12
+0, 33, 33, 1, 149760, 0xcf08c736
+0, 34, 34, 1, 149760, 0x0cedd0d6
+0, 35, 35, 1, 149760, 0xc317e9bc
+0, 36, 36, 1, 149760, 0x0dcbd636
+0, 37, 37, 1, 149760, 0x4e6501b0
+0, 38, 38, 1, 149760, 0x5f9c02bb
+0, 39, 39, 1, 149760, 0x43052939
+0, 40, 40, 1, 149760, 0x8ec12318
diff --git a/tests/ref/fate/hevc-conformance-AMVP_C_Samsung_4 b/tests/ref/fate/hevc-conformance-AMVP_C_Samsung_4
new file mode 100644
index 0000000..16d3446
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-AMVP_C_Samsung_4
@@ -0,0 +1,61 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x8087662a
+0, 1, 1, 1, 599040, 0x5278d8db
+0, 2, 2, 1, 599040, 0x73c74090
+0, 3, 3, 1, 599040, 0xde0d8317
+0, 4, 4, 1, 599040, 0xd9d4c26c
+0, 5, 5, 1, 599040, 0x603a10bd
+0, 6, 6, 1, 599040, 0xa91e9b91
+0, 7, 7, 1, 599040, 0x73567e6a
+0, 8, 8, 1, 599040, 0x67912cc6
+0, 9, 9, 1, 599040, 0x98d3fb2c
+0, 10, 10, 1, 599040, 0x50c6d7fc
+0, 11, 11, 1, 599040, 0x8ae23020
+0, 12, 12, 1, 599040, 0x9eaa976f
+0, 13, 13, 1, 599040, 0x3cadf6c0
+0, 14, 14, 1, 599040, 0x7d498902
+0, 15, 15, 1, 599040, 0x525decac
+0, 16, 16, 1, 599040, 0x081485cc
+0, 17, 17, 1, 599040, 0x3fd6ba7a
+0, 18, 18, 1, 599040, 0x8bbbaa4c
+0, 19, 19, 1, 599040, 0x9e60a407
+0, 20, 20, 1, 599040, 0x394becb9
+0, 21, 21, 1, 599040, 0x068dffb5
+0, 22, 22, 1, 599040, 0x531fd221
+0, 23, 23, 1, 599040, 0x3aa6922e
+0, 24, 24, 1, 599040, 0x089d2456
+0, 25, 25, 1, 599040, 0x7c432995
+0, 26, 26, 1, 599040, 0x3693613d
+0, 27, 27, 1, 599040, 0x8b6d902f
+0, 28, 28, 1, 599040, 0x7c9a947b
+0, 29, 29, 1, 599040, 0x51d9e4c6
+0, 30, 30, 1, 599040, 0xdc7f62f3
+0, 31, 31, 1, 599040, 0x9da6cba0
+0, 32, 32, 1, 599040, 0x1bef8581
+0, 33, 33, 1, 599040, 0xc19c4211
+0, 34, 34, 1, 599040, 0x7824188e
+0, 35, 35, 1, 599040, 0xd0511050
+0, 36, 36, 1, 599040, 0x39d93e78
+0, 37, 37, 1, 599040, 0x1e0dc88e
+0, 38, 38, 1, 599040, 0x2cd7522e
+0, 39, 39, 1, 599040, 0x538928a5
+0, 40, 40, 1, 599040, 0x95549fb2
+0, 41, 41, 1, 599040, 0x1f57d5c1
+0, 42, 42, 1, 599040, 0xc99fa8c6
+0, 43, 43, 1, 599040, 0x567f4e7e
+0, 44, 44, 1, 599040, 0x23d3d54f
+0, 45, 45, 1, 599040, 0xe8f74d97
+0, 46, 46, 1, 599040, 0xd2b03a4d
+0, 47, 47, 1, 599040, 0xe59c4faf
+0, 48, 48, 1, 599040, 0x46da921d
+0, 49, 49, 1, 599040, 0x7a344fa3
+0, 50, 50, 1, 599040, 0xbc736fd4
+0, 51, 51, 1, 599040, 0xfe5c362c
+0, 52, 52, 1, 599040, 0x115ed271
+0, 53, 53, 1, 599040, 0x3c4913fc
+0, 54, 54, 1, 599040, 0x1e1f8114
+0, 55, 55, 1, 599040, 0x08c06e58
+0, 56, 56, 1, 599040, 0x599f07f6
+0, 57, 57, 1, 599040, 0xc922a0c9
+0, 58, 58, 1, 599040, 0xc77b5201
+0, 59, 59, 1, 599040, 0x4c2cde6d
diff --git a/tests/ref/fate/hevc-conformance-CAINIT_A_SHARP_4 b/tests/ref/fate/hevc-conformance-CAINIT_A_SHARP_4
new file mode 100644
index 0000000..53b621b
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-CAINIT_A_SHARP_4
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x001f0c48
+0, 1, 1, 1, 599040, 0x83120d87
+0, 2, 2, 1, 599040, 0x10c267aa
+0, 3, 3, 1, 599040, 0xef591aef
+0, 4, 4, 1, 599040, 0xded62c79
+0, 5, 5, 1, 599040, 0xe7c1c748
+0, 6, 6, 1, 599040, 0x14db55d0
+0, 7, 7, 1, 599040, 0x73c4156b
+0, 8, 8, 1, 599040, 0x0cec903c
+0, 9, 9, 1, 599040, 0x791029a0
+0, 10, 10, 1, 599040, 0x0fe72908
+0, 11, 11, 1, 599040, 0xd0ebe0be
+0, 12, 12, 1, 599040, 0x473cb5aa
+0, 13, 13, 1, 599040, 0xe774cf8c
+0, 14, 14, 1, 599040, 0x3d63909f
+0, 15, 15, 1, 599040, 0xe05af465
+0, 16, 16, 1, 599040, 0x9679aa54
+0, 17, 17, 1, 599040, 0xe9d2ef49
+0, 18, 18, 1, 599040, 0x1e797cac
+0, 19, 19, 1, 599040, 0xf3d51077
+0, 20, 20, 1, 599040, 0x74e3b5e0
+0, 21, 21, 1, 599040, 0xb97e5178
+0, 22, 22, 1, 599040, 0x7c79a425
+0, 23, 23, 1, 599040, 0xfeeedb62
+0, 24, 24, 1, 599040, 0x8d5a3686
+0, 25, 25, 1, 599040, 0x3f6109e4
+0, 26, 26, 1, 599040, 0x365df50e
+0, 27, 27, 1, 599040, 0xd65876a1
+0, 28, 28, 1, 599040, 0xfa21e766
+0, 29, 29, 1, 599040, 0x2f24ed68
+0, 30, 30, 1, 599040, 0x0e90e5d4
+0, 31, 31, 1, 599040, 0xd044eb9c
+0, 32, 32, 1, 599040, 0xe55e8b18
+0, 33, 33, 1, 599040, 0xa92b93b6
+0, 34, 34, 1, 599040, 0x9b6827c6
+0, 35, 35, 1, 599040, 0x486e155b
+0, 36, 36, 1, 599040, 0xbff46adc
+0, 37, 37, 1, 599040, 0x61637615
+0, 38, 38, 1, 599040, 0xc0423ea9
+0, 39, 39, 1, 599040, 0xda80f8d8
+0, 40, 40, 1, 599040, 0xe0f77fcc
+0, 41, 41, 1, 599040, 0x68bef4cf
+0, 42, 42, 1, 599040, 0xd2e0699b
+0, 43, 43, 1, 599040, 0xcc6cd663
+0, 44, 44, 1, 599040, 0x00ed2594
+0, 45, 45, 1, 599040, 0x140b6efb
+0, 46, 46, 1, 599040, 0xa418f9d0
+0, 47, 47, 1, 599040, 0x500083a3
+0, 48, 48, 1, 599040, 0x619045ec
+0, 49, 49, 1, 599040, 0xdf0ce1e6
diff --git a/tests/ref/fate/hevc-conformance-CAINIT_B_SHARP_4 b/tests/ref/fate/hevc-conformance-CAINIT_B_SHARP_4
new file mode 100644
index 0000000..9aeb3b1
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-CAINIT_B_SHARP_4
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x001f0c48
+0, 1, 1, 1, 599040, 0xf8160d82
+0, 2, 2, 1, 599040, 0x5f2060e2
+0, 3, 3, 1, 599040, 0x421104a7
+0, 4, 4, 1, 599040, 0xded62c79
+0, 5, 5, 1, 599040, 0x782b4517
+0, 6, 6, 1, 599040, 0xcf47861d
+0, 7, 7, 1, 599040, 0xd401373c
+0, 8, 8, 1, 599040, 0x0cec903c
+0, 9, 9, 1, 599040, 0x2dec6230
+0, 10, 10, 1, 599040, 0xe8d25791
+0, 11, 11, 1, 599040, 0x243af0ad
+0, 12, 12, 1, 599040, 0x4f77c47b
+0, 13, 13, 1, 599040, 0x9777f7c4
+0, 14, 14, 1, 599040, 0xc5c5be51
+0, 15, 15, 1, 599040, 0xb9b27b63
+0, 16, 16, 1, 599040, 0xc333f76b
+0, 17, 17, 1, 599040, 0x6bd00f09
+0, 18, 18, 1, 599040, 0x7f76875d
+0, 19, 19, 1, 599040, 0xc9e80bec
+0, 20, 20, 1, 599040, 0x8681b48f
+0, 21, 21, 1, 599040, 0xefaa5077
+0, 22, 22, 1, 599040, 0x73cc72a4
+0, 23, 23, 1, 599040, 0x55c8bc27
+0, 24, 24, 1, 599040, 0x9d84419d
+0, 25, 25, 1, 599040, 0x89db2dfe
+0, 26, 26, 1, 599040, 0x39a012fe
+0, 27, 27, 1, 599040, 0x9ae88b01
+0, 28, 28, 1, 599040, 0x0928f3d0
+0, 29, 29, 1, 599040, 0x39359eb1
+0, 30, 30, 1, 599040, 0x3e00a5b5
+0, 31, 31, 1, 599040, 0xaf1b1809
+0, 32, 32, 1, 599040, 0xe55e8b18
+0, 33, 33, 1, 599040, 0xa4739b3d
+0, 34, 34, 1, 599040, 0x224d47d4
+0, 35, 35, 1, 599040, 0x3ce1d830
+0, 36, 36, 1, 599040, 0xd3b33990
+0, 37, 37, 1, 599040, 0x15c3ae0e
+0, 38, 38, 1, 599040, 0xcce735aa
+0, 39, 39, 1, 599040, 0x173d8406
+0, 40, 40, 1, 599040, 0xe0f77fcc
+0, 41, 41, 1, 599040, 0xbeefe9eb
+0, 42, 42, 1, 599040, 0xb3d761cf
+0, 43, 43, 1, 599040, 0x75ffe5f0
+0, 44, 44, 1, 599040, 0xf446226e
+0, 45, 45, 1, 599040, 0xf425475a
+0, 46, 46, 1, 599040, 0x5180ee65
+0, 47, 47, 1, 599040, 0x5edb78f9
+0, 48, 48, 1, 599040, 0x28eb41c5
+0, 49, 49, 1, 599040, 0x0d65d9d3
diff --git a/tests/ref/fate/hevc-conformance-CAINIT_C_SHARP_3 b/tests/ref/fate/hevc-conformance-CAINIT_C_SHARP_3
new file mode 100644
index 0000000..c891c44
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-CAINIT_C_SHARP_3
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x2b58dee2
+0, 1, 1, 1, 599040, 0x2b58dee2
+0, 2, 2, 1, 599040, 0xcd9295f4
+0, 3, 3, 1, 599040, 0xc052f81f
+0, 4, 4, 1, 599040, 0xfe5932ed
+0, 5, 5, 1, 599040, 0x8a8aa4b9
+0, 6, 6, 1, 599040, 0x6ac33b24
+0, 7, 7, 1, 599040, 0xd053bb83
+0, 8, 8, 1, 599040, 0xa9cf6ba6
+0, 9, 9, 1, 599040, 0x3d5a1a3b
+0, 10, 10, 1, 599040, 0x90997f48
+0, 11, 11, 1, 599040, 0xc99390bd
+0, 12, 12, 1, 599040, 0x9723079d
+0, 13, 13, 1, 599040, 0x7f0fe29b
+0, 14, 14, 1, 599040, 0x778afdb4
+0, 15, 15, 1, 599040, 0x72963905
+0, 16, 16, 1, 599040, 0xa677b29c
+0, 17, 17, 1, 599040, 0x88bdccd8
+0, 18, 18, 1, 599040, 0x8be37199
+0, 19, 19, 1, 599040, 0x6628117a
+0, 20, 20, 1, 599040, 0xefa701b0
+0, 21, 21, 1, 599040, 0x75d6705d
+0, 22, 22, 1, 599040, 0x85242d6f
+0, 23, 23, 1, 599040, 0xd559eaa6
+0, 24, 24, 1, 599040, 0xe0663879
+0, 25, 25, 1, 599040, 0x3255d67c
+0, 26, 26, 1, 599040, 0xf41a4d73
+0, 27, 27, 1, 599040, 0xda630d57
+0, 28, 28, 1, 599040, 0x7b8eec79
+0, 29, 29, 1, 599040, 0x70dff7a6
+0, 30, 30, 1, 599040, 0x4b600806
+0, 31, 31, 1, 599040, 0xdcbbc54d
+0, 32, 32, 1, 599040, 0x7e6e66b4
+0, 33, 33, 1, 599040, 0x645ce246
+0, 34, 34, 1, 599040, 0x03d3117c
+0, 35, 35, 1, 599040, 0x7c3cab88
+0, 36, 36, 1, 599040, 0x5cdaeeef
+0, 37, 37, 1, 599040, 0x4cce6d93
+0, 38, 38, 1, 599040, 0x78c28e4c
+0, 39, 39, 1, 599040, 0x8acbe642
+0, 40, 40, 1, 599040, 0xcd0a39f8
+0, 41, 41, 1, 599040, 0x9c580311
+0, 42, 42, 1, 599040, 0x668eab11
+0, 43, 43, 1, 599040, 0xc76f6206
+0, 44, 44, 1, 599040, 0xe0baf2a2
+0, 45, 45, 1, 599040, 0x430db206
+0, 46, 46, 1, 599040, 0x9c1565ad
+0, 47, 47, 1, 599040, 0xfc302be0
+0, 48, 48, 1, 599040, 0x6ccfc206
+0, 49, 49, 1, 599040, 0x46c7722d
diff --git a/tests/ref/fate/hevc-conformance-CAINIT_D_SHARP_3 b/tests/ref/fate/hevc-conformance-CAINIT_D_SHARP_3
new file mode 100644
index 0000000..0294a7e
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-CAINIT_D_SHARP_3
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x2b58dee2
+0, 1, 1, 1, 599040, 0x2b58dee2
+0, 2, 2, 1, 599040, 0xb055b638
+0, 3, 3, 1, 599040, 0x3e2b06c9
+0, 4, 4, 1, 599040, 0xa0e53610
+0, 5, 5, 1, 599040, 0x5f6eca50
+0, 6, 6, 1, 599040, 0x516e679d
+0, 7, 7, 1, 599040, 0xdbbbf791
+0, 8, 8, 1, 599040, 0x04be5abc
+0, 9, 9, 1, 599040, 0x85283636
+0, 10, 10, 1, 599040, 0x1bcdb857
+0, 11, 11, 1, 599040, 0x258bb8a8
+0, 12, 12, 1, 599040, 0x33340003
+0, 13, 13, 1, 599040, 0xa2cc0dc3
+0, 14, 14, 1, 599040, 0x2b83400f
+0, 15, 15, 1, 599040, 0xf33ba886
+0, 16, 16, 1, 599040, 0x73f43f10
+0, 17, 17, 1, 599040, 0x63ff4628
+0, 18, 18, 1, 599040, 0x41170243
+0, 19, 19, 1, 599040, 0x84f34b72
+0, 20, 20, 1, 599040, 0x4913e415
+0, 21, 21, 1, 599040, 0x38cfaac3
+0, 22, 22, 1, 599040, 0xb2f0650c
+0, 23, 23, 1, 599040, 0xe0d12249
+0, 24, 24, 1, 599040, 0xca931ca0
+0, 25, 25, 1, 599040, 0xfc14d1cb
+0, 26, 26, 1, 599040, 0xb74667d8
+0, 27, 27, 1, 599040, 0xfdc22b8b
+0, 28, 28, 1, 599040, 0x30b425eb
+0, 29, 29, 1, 599040, 0xc31f3b73
+0, 30, 30, 1, 599040, 0xefda0062
+0, 31, 31, 1, 599040, 0x8fe0d742
+0, 32, 32, 1, 599040, 0xdaa54d1d
+0, 33, 33, 1, 599040, 0x2188ae4b
+0, 34, 34, 1, 599040, 0x7ef0f088
+0, 35, 35, 1, 599040, 0xcfd2619f
+0, 36, 36, 1, 599040, 0x3b0fca50
+0, 37, 37, 1, 599040, 0x78746df2
+0, 38, 38, 1, 599040, 0xdc917e1b
+0, 39, 39, 1, 599040, 0xc6cf2732
+0, 40, 40, 1, 599040, 0xdbd2f5f2
+0, 41, 41, 1, 599040, 0x45a8cba3
+0, 42, 42, 1, 599040, 0xe276b712
+0, 43, 43, 1, 599040, 0x36057004
+0, 44, 44, 1, 599040, 0xe0da7e77
+0, 45, 45, 1, 599040, 0x823e7c30
+0, 46, 46, 1, 599040, 0x62c9457a
+0, 47, 47, 1, 599040, 0xf6743a30
+0, 48, 48, 1, 599040, 0x8db4f476
+0, 49, 49, 1, 599040, 0x79537927
diff --git a/tests/ref/fate/hevc-conformance-CAINIT_E_SHARP_3 b/tests/ref/fate/hevc-conformance-CAINIT_E_SHARP_3
new file mode 100644
index 0000000..430426b
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-CAINIT_E_SHARP_3
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x1cf21d79
+0, 1, 1, 1, 599040, 0x1cf21d79
+0, 2, 2, 1, 599040, 0xb54ee9e0
+0, 3, 3, 1, 599040, 0x757f33f0
+0, 4, 4, 1, 599040, 0x783e06bc
+0, 5, 5, 1, 599040, 0x73127ae7
+0, 6, 6, 1, 599040, 0x52f86193
+0, 7, 7, 1, 599040, 0x8e8afa2c
+0, 8, 8, 1, 599040, 0x29359620
+0, 9, 9, 1, 599040, 0x23f46fd3
+0, 10, 10, 1, 599040, 0x00c9d47d
+0, 11, 11, 1, 599040, 0xcabcca8d
+0, 12, 12, 1, 599040, 0x02e92d89
+0, 13, 13, 1, 599040, 0x3e97268f
+0, 14, 14, 1, 599040, 0xba6230c2
+0, 15, 15, 1, 599040, 0x4393aa3b
+0, 16, 16, 1, 599040, 0x06b1b9c8
+0, 17, 17, 1, 599040, 0xcc2aa30b
+0, 18, 18, 1, 599040, 0x3e029a11
+0, 19, 19, 1, 599040, 0x0ec1fc36
+0, 20, 20, 1, 599040, 0xd61dd438
+0, 21, 21, 1, 599040, 0xa7b1816b
+0, 22, 22, 1, 599040, 0xa98ef225
+0, 23, 23, 1, 599040, 0x368912ca
+0, 24, 24, 1, 599040, 0x1ae95cbe
+0, 25, 25, 1, 599040, 0x0e01f8ed
+0, 26, 26, 1, 599040, 0x05497937
+0, 27, 27, 1, 599040, 0x735c2420
+0, 28, 28, 1, 599040, 0x0ef80004
+0, 29, 29, 1, 599040, 0xd744091b
+0, 30, 30, 1, 599040, 0x0f3b1576
+0, 31, 31, 1, 599040, 0x24e4fab9
+0, 32, 32, 1, 599040, 0x6b5d7fca
+0, 33, 33, 1, 599040, 0x2afcdaec
+0, 34, 34, 1, 599040, 0x39dfd5b6
+0, 35, 35, 1, 599040, 0xe5844f4e
+0, 36, 36, 1, 599040, 0xf26920d9
+0, 37, 37, 1, 599040, 0x8feb56e2
+0, 38, 38, 1, 599040, 0x6433712f
+0, 39, 39, 1, 599040, 0xba311758
+0, 40, 40, 1, 599040, 0x09f87643
+0, 41, 41, 1, 599040, 0x68562c28
+0, 42, 42, 1, 599040, 0x9465e267
+0, 43, 43, 1, 599040, 0x03e2802f
+0, 44, 44, 1, 599040, 0xa61ed250
+0, 45, 45, 1, 599040, 0x5ab680db
+0, 46, 46, 1, 599040, 0xc4663840
+0, 47, 47, 1, 599040, 0xefe83a4f
+0, 48, 48, 1, 599040, 0x7bfb4ecd
+0, 49, 49, 1, 599040, 0xcafdbfd0
diff --git a/tests/ref/fate/hevc-conformance-CAINIT_F_SHARP_3 b/tests/ref/fate/hevc-conformance-CAINIT_F_SHARP_3
new file mode 100644
index 0000000..aeba53b
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-CAINIT_F_SHARP_3
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x1cf21d79
+0, 1, 1, 1, 599040, 0x1cf21d79
+0, 2, 2, 1, 599040, 0xc182eaa8
+0, 3, 3, 1, 599040, 0x260358ee
+0, 4, 4, 1, 599040, 0x381e5b16
+0, 5, 5, 1, 599040, 0x329dacd8
+0, 6, 6, 1, 599040, 0x7306d51c
+0, 7, 7, 1, 599040, 0x869d359b
+0, 8, 8, 1, 599040, 0xf8fc941a
+0, 9, 9, 1, 599040, 0x0798842b
+0, 10, 10, 1, 599040, 0xe6e1f54e
+0, 11, 11, 1, 599040, 0xc7d5ba9e
+0, 12, 12, 1, 599040, 0xc8c5507a
+0, 13, 13, 1, 599040, 0x97ae604a
+0, 14, 14, 1, 599040, 0x14dd4139
+0, 15, 15, 1, 599040, 0xb2f998dc
+0, 16, 16, 1, 599040, 0xc3a3a6bc
+0, 17, 17, 1, 599040, 0x1f95be77
+0, 18, 18, 1, 599040, 0xb7fd124b
+0, 19, 19, 1, 599040, 0x25703b3c
+0, 20, 20, 1, 599040, 0x3bddeba7
+0, 21, 21, 1, 599040, 0xffcc9b6d
+0, 22, 22, 1, 599040, 0x3dd66a0a
+0, 23, 23, 1, 599040, 0xe9607af7
+0, 24, 24, 1, 599040, 0x218cdc65
+0, 25, 25, 1, 599040, 0x88f97761
+0, 26, 26, 1, 599040, 0x62e1f5d4
+0, 27, 27, 1, 599040, 0xcc3cd429
+0, 28, 28, 1, 599040, 0xb4290272
+0, 29, 29, 1, 599040, 0x4f73142c
+0, 30, 30, 1, 599040, 0x753eefd9
+0, 31, 31, 1, 599040, 0xea77e837
+0, 32, 32, 1, 599040, 0xfa927e55
+0, 33, 33, 1, 599040, 0x3dff1295
+0, 34, 34, 1, 599040, 0x513c2088
+0, 35, 35, 1, 599040, 0x9822b7f0
+0, 36, 36, 1, 599040, 0xc4770af6
+0, 37, 37, 1, 599040, 0x7cb576fb
+0, 38, 38, 1, 599040, 0x2af8ca3a
+0, 39, 39, 1, 599040, 0x0a324910
+0, 40, 40, 1, 599040, 0x1aeb3d7a
+0, 41, 41, 1, 599040, 0x82de1408
+0, 42, 42, 1, 599040, 0x7ebad7f4
+0, 43, 43, 1, 599040, 0xd100bcc1
+0, 44, 44, 1, 599040, 0x4719dc40
+0, 45, 45, 1, 599040, 0xd82f658b
+0, 46, 46, 1, 599040, 0x8c596a54
+0, 47, 47, 1, 599040, 0xd0b4572c
+0, 48, 48, 1, 599040, 0xdc3c5a89
+0, 49, 49, 1, 599040, 0x4f0ad888
diff --git a/tests/ref/fate/hevc-conformance-CAINIT_G_SHARP_3 b/tests/ref/fate/hevc-conformance-CAINIT_G_SHARP_3
new file mode 100644
index 0000000..e0501be
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-CAINIT_G_SHARP_3
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0xd9b73cbe
+0, 1, 1, 1, 599040, 0xd9b73cbe
+0, 2, 2, 1, 599040, 0xe4e5dd7c
+0, 3, 3, 1, 599040, 0xa7333d7e
+0, 4, 4, 1, 599040, 0x6b82552b
+0, 5, 5, 1, 599040, 0x4f02e2a4
+0, 6, 6, 1, 599040, 0x8fdcc50a
+0, 7, 7, 1, 599040, 0x2481542d
+0, 8, 8, 1, 599040, 0x73d0dfad
+0, 9, 9, 1, 599040, 0x842b8cd2
+0, 10, 10, 1, 599040, 0x87b3a3b2
+0, 11, 11, 1, 599040, 0xe4decf78
+0, 12, 12, 1, 599040, 0xfba7dd51
+0, 13, 13, 1, 599040, 0x3dc1e85c
+0, 14, 14, 1, 599040, 0xea8a4987
+0, 15, 15, 1, 599040, 0xa3cc5c8c
+0, 16, 16, 1, 599040, 0x10a09cd8
+0, 17, 17, 1, 599040, 0x6739c5f7
+0, 18, 18, 1, 599040, 0x819af14a
+0, 19, 19, 1, 599040, 0xe9d65a5c
+0, 20, 20, 1, 599040, 0x09def54e
+0, 21, 21, 1, 599040, 0x8595aa5d
+0, 22, 22, 1, 599040, 0xc3f134d7
+0, 23, 23, 1, 599040, 0xdac9496a
+0, 24, 24, 1, 599040, 0x760f0897
+0, 25, 25, 1, 599040, 0x8daddaf5
+0, 26, 26, 1, 599040, 0xed313947
+0, 27, 27, 1, 599040, 0xc875ed4d
+0, 28, 28, 1, 599040, 0xdb5d0b3b
+0, 29, 29, 1, 599040, 0x7cbc0e6a
+0, 30, 30, 1, 599040, 0x193bbc9f
+0, 31, 31, 1, 599040, 0x4f20d599
+0, 32, 32, 1, 599040, 0x09e545e8
+0, 33, 33, 1, 599040, 0x0637d524
+0, 34, 34, 1, 599040, 0x11a3bd85
+0, 35, 35, 1, 599040, 0x304155ce
+0, 36, 36, 1, 599040, 0x6636291b
+0, 37, 37, 1, 599040, 0xc4039e80
+0, 38, 38, 1, 599040, 0xd73ca756
+0, 39, 39, 1, 599040, 0x96a68426
+0, 40, 40, 1, 599040, 0xd945391c
+0, 41, 41, 1, 599040, 0x95a83264
+0, 42, 42, 1, 599040, 0x6356a243
+0, 43, 43, 1, 599040, 0xb9b8973e
+0, 44, 44, 1, 599040, 0xf361d0d9
+0, 45, 45, 1, 599040, 0x2783b0e2
+0, 46, 46, 1, 599040, 0x870ac424
+0, 47, 47, 1, 599040, 0xa8397c01
+0, 48, 48, 1, 599040, 0xf1bc2ac0
+0, 49, 49, 1, 599040, 0x82fbb428
diff --git a/tests/ref/fate/hevc-conformance-CAINIT_H_SHARP_3 b/tests/ref/fate/hevc-conformance-CAINIT_H_SHARP_3
new file mode 100644
index 0000000..01ab258
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-CAINIT_H_SHARP_3
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0xd9b73cbe
+0, 1, 1, 1, 599040, 0xd9b73cbe
+0, 2, 2, 1, 599040, 0x93a3fabf
+0, 3, 3, 1, 599040, 0x245a522e
+0, 4, 4, 1, 599040, 0xff1e8bb4
+0, 5, 5, 1, 599040, 0x03390b9a
+0, 6, 6, 1, 599040, 0x27030635
+0, 7, 7, 1, 599040, 0x431c6312
+0, 8, 8, 1, 599040, 0xeddc5f83
+0, 9, 9, 1, 599040, 0x34168a1e
+0, 10, 10, 1, 599040, 0xf4d795a4
+0, 11, 11, 1, 599040, 0xe716ea67
+0, 12, 12, 1, 599040, 0xf3b8446d
+0, 13, 13, 1, 599040, 0x082d12d0
+0, 14, 14, 1, 599040, 0x68e12e99
+0, 15, 15, 1, 599040, 0x3fd079df
+0, 16, 16, 1, 599040, 0x6087fb37
+0, 17, 17, 1, 599040, 0x12c2142e
+0, 18, 18, 1, 599040, 0xb3bcf682
+0, 19, 19, 1, 599040, 0xcec84ee7
+0, 20, 20, 1, 599040, 0x12a4fb43
+0, 21, 21, 1, 599040, 0x85749580
+0, 22, 22, 1, 599040, 0x6df99536
+0, 23, 23, 1, 599040, 0x377282a6
+0, 24, 24, 1, 599040, 0xe296f874
+0, 25, 25, 1, 599040, 0x1b29cd1a
+0, 26, 26, 1, 599040, 0x1cf633c9
+0, 27, 27, 1, 599040, 0xf8cd2544
+0, 28, 28, 1, 599040, 0x61c05325
+0, 29, 29, 1, 599040, 0x87646c89
+0, 30, 30, 1, 599040, 0x5b840711
+0, 31, 31, 1, 599040, 0x5bc4c181
+0, 32, 32, 1, 599040, 0x91ce695a
+0, 33, 33, 1, 599040, 0xed54dcca
+0, 34, 34, 1, 599040, 0xc41fef8e
+0, 35, 35, 1, 599040, 0x9da8830b
+0, 36, 36, 1, 599040, 0xb76cec12
+0, 37, 37, 1, 599040, 0xef9661f0
+0, 38, 38, 1, 599040, 0xe1d38227
+0, 39, 39, 1, 599040, 0xce440134
+0, 40, 40, 1, 599040, 0x41a54dd1
+0, 41, 41, 1, 599040, 0xdd83da8e
+0, 42, 42, 1, 599040, 0xf9cee595
+0, 43, 43, 1, 599040, 0x6f5db54d
+0, 44, 44, 1, 599040, 0x00b6f064
+0, 45, 45, 1, 599040, 0xfbaa978d
+0, 46, 46, 1, 599040, 0x2c9ee1d7
+0, 47, 47, 1, 599040, 0xe8c4be1f
+0, 48, 48, 1, 599040, 0x132a260f
+0, 49, 49, 1, 599040, 0x8571a213
diff --git a/tests/ref/fate/hevc-conformance-CIP_A_Panasonic_3 b/tests/ref/fate/hevc-conformance-CIP_A_Panasonic_3
new file mode 100644
index 0000000..afa4854
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-CIP_A_Panasonic_3
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x6e1f16d0
+0, 1, 1, 1, 149760, 0x5be5bde9
diff --git a/tests/ref/fate/hevc-conformance-CIP_C_Panasonic_2 b/tests/ref/fate/hevc-conformance-CIP_C_Panasonic_2
new file mode 100644
index 0000000..3346e20
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-CIP_C_Panasonic_2
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xcd1019b2
+0, 1, 1, 1, 149760, 0xeb39efeb
diff --git a/tests/ref/fate/hevc-conformance-DBLK_A_MAIN10_VIXS_2 b/tests/ref/fate/hevc-conformance-DBLK_A_MAIN10_VIXS_2
new file mode 100644
index 0000000..50be4f1
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DBLK_A_MAIN10_VIXS_2
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 76032, 0x4313935b
+0, 1, 1, 1, 76032, 0x4c8071b5
+0, 2, 2, 1, 76032, 0x5e627edc
+0, 3, 3, 1, 76032, 0xb51a996d
+0, 4, 4, 1, 76032, 0x77d1800b
+0, 5, 5, 1, 76032, 0x4fb9bf3f
+0, 6, 6, 1, 76032, 0x838f8c05
+0, 7, 7, 1, 76032, 0xa87aabb6
diff --git a/tests/ref/fate/hevc-conformance-DBLK_A_SONY_3 b/tests/ref/fate/hevc-conformance-DBLK_A_SONY_3
new file mode 100644
index 0000000..589cbf3
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DBLK_A_SONY_3
@@ -0,0 +1,31 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x154e6dd9
+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
new file mode 100644
index 0000000..077b38e
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DBLK_B_SONY_3
@@ -0,0 +1,31 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0xda0cb5d4
+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
new file mode 100644
index 0000000..823988d
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DBLK_C_SONY_3
@@ -0,0 +1,31 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x57369bf4
+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
new file mode 100644
index 0000000..3d9e43b
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DBLK_D_VIXS_1
@@ -0,0 +1,9 @@
+#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_D_VIXS_2 b/tests/ref/fate/hevc-conformance-DBLK_D_VIXS_2
new file mode 100644
index 0000000..2bdc548
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DBLK_D_VIXS_2
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 1382400, 0x6ef5c76e
+0, 1, 1, 1, 1382400, 0x1e1926b1
+0, 2, 2, 1, 1382400, 0x69888786
+0, 3, 3, 1, 1382400, 0x1f193659
+0, 4, 4, 1, 1382400, 0x566eb1df
+0, 5, 5, 1, 1382400, 0x49b3a668
+0, 6, 6, 1, 1382400, 0x1b774ed8
+0, 7, 7, 1, 1382400, 0x2296a2bc
diff --git a/tests/ref/fate/hevc-conformance-DBLK_E_VIXS_1 b/tests/ref/fate/hevc-conformance-DBLK_E_VIXS_1
new file mode 100644
index 0000000..c3ebaf2
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DBLK_E_VIXS_1
@@ -0,0 +1,9 @@
+#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_E_VIXS_2 b/tests/ref/fate/hevc-conformance-DBLK_E_VIXS_2
new file mode 100644
index 0000000..4c8b07d
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DBLK_E_VIXS_2
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 1382400, 0xecfdf606
+0, 1, 1, 1, 1382400, 0x0b0382e1
+0, 2, 2, 1, 1382400, 0xbef3afd6
+0, 3, 3, 1, 1382400, 0x6a2bcabb
+0, 4, 4, 1, 1382400, 0x663f991c
+0, 5, 5, 1, 1382400, 0xb49b94d8
+0, 6, 6, 1, 1382400, 0x07399433
+0, 7, 7, 1, 1382400, 0x9cca09df
diff --git a/tests/ref/fate/hevc-conformance-DBLK_F_VIXS_1 b/tests/ref/fate/hevc-conformance-DBLK_F_VIXS_1
new file mode 100644
index 0000000..59f51ef
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DBLK_F_VIXS_1
@@ -0,0 +1,9 @@
+#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_F_VIXS_2 b/tests/ref/fate/hevc-conformance-DBLK_F_VIXS_2
new file mode 100644
index 0000000..3ff62e5
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DBLK_F_VIXS_2
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 1382400, 0xea27f7bd
+0, 1, 1, 1, 1382400, 0x423e555b
+0, 2, 2, 1, 1382400, 0x87898ae0
+0, 3, 3, 1, 1382400, 0xfee4beab
+0, 4, 4, 1, 1382400, 0xe5367019
+0, 5, 5, 1, 1382400, 0x3e74b3aa
+0, 6, 6, 1, 1382400, 0x4d8ab61a
+0, 7, 7, 1, 1382400, 0x22500e13
diff --git a/tests/ref/fate/hevc-conformance-DBLK_G_VIXS_1 b/tests/ref/fate/hevc-conformance-DBLK_G_VIXS_1
new file mode 100644
index 0000000..4b9793b
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DBLK_G_VIXS_1
@@ -0,0 +1,9 @@
+#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-DBLK_G_VIXS_2 b/tests/ref/fate/hevc-conformance-DBLK_G_VIXS_2
new file mode 100644
index 0000000..4c8b07d
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DBLK_G_VIXS_2
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 1382400, 0xecfdf606
+0, 1, 1, 1, 1382400, 0x0b0382e1
+0, 2, 2, 1, 1382400, 0xbef3afd6
+0, 3, 3, 1, 1382400, 0x6a2bcabb
+0, 4, 4, 1, 1382400, 0x663f991c
+0, 5, 5, 1, 1382400, 0xb49b94d8
+0, 6, 6, 1, 1382400, 0x07399433
+0, 7, 7, 1, 1382400, 0x9cca09df
diff --git a/tests/ref/fate/hevc-conformance-DELTAQP_B_SONY_3 b/tests/ref/fate/hevc-conformance-DELTAQP_B_SONY_3
new file mode 100644
index 0000000..3ba3bb5
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DELTAQP_B_SONY_3
@@ -0,0 +1,31 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x7ea9597c
+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
new file mode 100644
index 0000000..d616bac
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DELTAQP_C_SONY_3
@@ -0,0 +1,31 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0xcb2969c5
+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-DSLICE_A_HHI_5 b/tests/ref/fate/hevc-conformance-DSLICE_A_HHI_5
new file mode 100644
index 0000000..6cd113b
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DSLICE_A_HHI_5
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0xdc18cd12
+0, 1, 1, 1, 3110400, 0x42f7020d
+0, 2, 2, 1, 3110400, 0x6ac4421a
+0, 3, 3, 1, 3110400, 0xdbf78c86
+0, 4, 4, 1, 3110400, 0x123f9c50
+0, 5, 5, 1, 3110400, 0x9356a73f
+0, 6, 6, 1, 3110400, 0xc54a446b
+0, 7, 7, 1, 3110400, 0xdfa92401
+0, 8, 8, 1, 3110400, 0xd3226c6a
+0, 9, 9, 1, 3110400, 0xa0bd149a
+0, 10, 10, 1, 3110400, 0xc38c58cc
+0, 11, 11, 1, 3110400, 0xf1871f13
+0, 12, 12, 1, 3110400, 0xfdf151d5
+0, 13, 13, 1, 3110400, 0x65ca7286
+0, 14, 14, 1, 3110400, 0xac2d80dc
+0, 15, 15, 1, 3110400, 0x3e024908
+0, 16, 16, 1, 3110400, 0x22a66454
+0, 17, 17, 1, 3110400, 0x83b6cac8
+0, 18, 18, 1, 3110400, 0xe1bccc50
+0, 19, 19, 1, 3110400, 0x76be567e
+0, 20, 20, 1, 3110400, 0x743c4335
+0, 21, 21, 1, 3110400, 0xd3d28565
+0, 22, 22, 1, 3110400, 0x2ab3a5a2
+0, 23, 23, 1, 3110400, 0x9141f68e
+0, 24, 24, 1, 3110400, 0xe90fac3b
+0, 25, 25, 1, 3110400, 0xdc8e496d
+0, 26, 26, 1, 3110400, 0x4ea216b9
+0, 27, 27, 1, 3110400, 0xd1f8a08e
+0, 28, 28, 1, 3110400, 0x2b512b98
+0, 29, 29, 1, 3110400, 0x6af060b6
+0, 30, 30, 1, 3110400, 0x69389c02
+0, 31, 31, 1, 3110400, 0x7a8cef2f
+0, 32, 32, 1, 3110400, 0x8f5bd7eb
+0, 33, 33, 1, 3110400, 0x3960d741
+0, 34, 34, 1, 3110400, 0x86c2c23b
+0, 35, 35, 1, 3110400, 0x6d0d258a
+0, 36, 36, 1, 3110400, 0xaff6795b
+0, 37, 37, 1, 3110400, 0x97b9cb1e
+0, 38, 38, 1, 3110400, 0x5966d391
+0, 39, 39, 1, 3110400, 0xb9c90726
+0, 40, 40, 1, 3110400, 0x3ab5836d
+0, 41, 41, 1, 3110400, 0xcc3c95e7
+0, 42, 42, 1, 3110400, 0x190df1ce
+0, 43, 43, 1, 3110400, 0x64e6f266
+0, 44, 44, 1, 3110400, 0x98dfdcdd
+0, 45, 45, 1, 3110400, 0xd8889aff
+0, 46, 46, 1, 3110400, 0x969775b8
+0, 47, 47, 1, 3110400, 0x8f3dec20
+0, 48, 48, 1, 3110400, 0xbd2b80ca
+0, 49, 49, 1, 3110400, 0x68baa6f7
diff --git a/tests/ref/fate/hevc-conformance-DSLICE_B_HHI_5 b/tests/ref/fate/hevc-conformance-DSLICE_B_HHI_5
new file mode 100644
index 0000000..7626d76
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DSLICE_B_HHI_5
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0x96995c57
+0, 1, 1, 1, 3110400, 0x2924a10f
+0, 2, 2, 1, 3110400, 0x892e146c
+0, 3, 3, 1, 3110400, 0x9b0b8733
+0, 4, 4, 1, 3110400, 0xb09ffc2d
+0, 5, 5, 1, 3110400, 0x588e04a0
+0, 6, 6, 1, 3110400, 0xa9ed178c
+0, 7, 7, 1, 3110400, 0x54254788
+0, 8, 8, 1, 3110400, 0x4fa444bc
+0, 9, 9, 1, 3110400, 0xe97d958a
+0, 10, 10, 1, 3110400, 0x8e168461
+0, 11, 11, 1, 3110400, 0xc39e551f
+0, 12, 12, 1, 3110400, 0xb5649a69
+0, 13, 13, 1, 3110400, 0x64eb3085
+0, 14, 14, 1, 3110400, 0xb4485019
+0, 15, 15, 1, 3110400, 0x989e4c47
+0, 16, 16, 1, 3110400, 0x0ff21984
+0, 17, 17, 1, 3110400, 0xe81b3ddd
+0, 18, 18, 1, 3110400, 0x6404610f
+0, 19, 19, 1, 3110400, 0xa61c3403
+0, 20, 20, 1, 3110400, 0x033ca068
+0, 21, 21, 1, 3110400, 0x3513dff4
+0, 22, 22, 1, 3110400, 0xe903a3c2
+0, 23, 23, 1, 3110400, 0xd40b3248
+0, 24, 24, 1, 3110400, 0xa257fb35
+0, 25, 25, 1, 3110400, 0x6fcab221
+0, 26, 26, 1, 3110400, 0x079a34c7
+0, 27, 27, 1, 3110400, 0x7308ecbc
+0, 28, 28, 1, 3110400, 0x1cf2dffb
+0, 29, 29, 1, 3110400, 0x59a0a84d
+0, 30, 30, 1, 3110400, 0x6b76450f
+0, 31, 31, 1, 3110400, 0x27de01f3
+0, 32, 32, 1, 3110400, 0x8541fe8b
+0, 33, 33, 1, 3110400, 0x07b740d9
+0, 34, 34, 1, 3110400, 0x735d36e9
+0, 35, 35, 1, 3110400, 0x0336ac98
+0, 36, 36, 1, 3110400, 0xab9f7d33
+0, 37, 37, 1, 3110400, 0xc5f62e67
+0, 38, 38, 1, 3110400, 0x68d6c250
+0, 39, 39, 1, 3110400, 0xaf26c339
+0, 40, 40, 1, 3110400, 0xfa920d0f
+0, 41, 41, 1, 3110400, 0xac9c6a89
+0, 42, 42, 1, 3110400, 0xa0d0cbd0
+0, 43, 43, 1, 3110400, 0x9d517b81
+0, 44, 44, 1, 3110400, 0x3c3b2b89
+0, 45, 45, 1, 3110400, 0x3cf50b0c
+0, 46, 46, 1, 3110400, 0xee319ebe
+0, 47, 47, 1, 3110400, 0x5b7c3397
+0, 48, 48, 1, 3110400, 0x1a089921
+0, 49, 49, 1, 3110400, 0x69718487
diff --git a/tests/ref/fate/hevc-conformance-DSLICE_C_HHI_5 b/tests/ref/fate/hevc-conformance-DSLICE_C_HHI_5
new file mode 100644
index 0000000..c4275cb
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-DSLICE_C_HHI_5
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0x62a2ceab
+0, 1, 1, 1, 3110400, 0x5e4d6adc
+0, 2, 2, 1, 3110400, 0x4ad0955d
+0, 3, 3, 1, 3110400, 0x17fd7b7c
+0, 4, 4, 1, 3110400, 0xe8270ac1
+0, 5, 5, 1, 3110400, 0xbc32bf86
+0, 6, 6, 1, 3110400, 0x13cc365c
+0, 7, 7, 1, 3110400, 0xef503eb5
+0, 8, 8, 1, 3110400, 0xcc9506f4
+0, 9, 9, 1, 3110400, 0xdc213a9e
+0, 10, 10, 1, 3110400, 0xe567c736
+0, 11, 11, 1, 3110400, 0x0a79aad4
+0, 12, 12, 1, 3110400, 0x61773cff
+0, 13, 13, 1, 3110400, 0x2e93a037
+0, 14, 14, 1, 3110400, 0xf419a7bf
+0, 15, 15, 1, 3110400, 0xa57b06bf
+0, 16, 16, 1, 3110400, 0x6e94960a
+0, 17, 17, 1, 3110400, 0x11f22564
+0, 18, 18, 1, 3110400, 0x850e5f7c
+0, 19, 19, 1, 3110400, 0xdfad06af
+0, 20, 20, 1, 3110400, 0xf2912aee
+0, 21, 21, 1, 3110400, 0x57e1c391
+0, 22, 22, 1, 3110400, 0xc8976a8f
+0, 23, 23, 1, 3110400, 0x88fb8b68
+0, 24, 24, 1, 3110400, 0xbe0e314b
+0, 25, 25, 1, 3110400, 0x33ae23f8
+0, 26, 26, 1, 3110400, 0x4db83c5c
+0, 27, 27, 1, 3110400, 0xa5f71a9d
+0, 28, 28, 1, 3110400, 0x34bb4f19
+0, 29, 29, 1, 3110400, 0xb1fee8d9
+0, 30, 30, 1, 3110400, 0x369990b7
+0, 31, 31, 1, 3110400, 0x6bfdbd4a
+0, 32, 32, 1, 3110400, 0x709dd60d
+0, 33, 33, 1, 3110400, 0x4213781c
+0, 34, 34, 1, 3110400, 0x7810dadd
+0, 35, 35, 1, 3110400, 0x1bc02bc6
+0, 36, 36, 1, 3110400, 0x760ed4aa
+0, 37, 37, 1, 3110400, 0xe2b45e4d
+0, 38, 38, 1, 3110400, 0x517b8d0a
+0, 39, 39, 1, 3110400, 0xf145ed7e
+0, 40, 40, 1, 3110400, 0xd8cbc454
+0, 41, 41, 1, 3110400, 0xa80f26f7
+0, 42, 42, 1, 3110400, 0x340a418d
+0, 43, 43, 1, 3110400, 0x5a0f7264
+0, 44, 44, 1, 3110400, 0xf2936a6d
+0, 45, 45, 1, 3110400, 0x841e715b
+0, 46, 46, 1, 3110400, 0xb17e4131
+0, 47, 47, 1, 3110400, 0x40e3ba7b
+0, 48, 48, 1, 3110400, 0x610254f7
+0, 49, 49, 1, 3110400, 0x76aa8b44
diff --git a/tests/ref/fate/hevc-conformance-ENTP_A_LG_2 b/tests/ref/fate/hevc-conformance-ENTP_A_LG_2
new file mode 100644
index 0000000..5697619
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-ENTP_A_LG_2
@@ -0,0 +1,51 @@
+#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_B_LG_2 b/tests/ref/fate/hevc-conformance-ENTP_B_LG_2
new file mode 100644
index 0000000..0251f30
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-ENTP_B_LG_2
@@ -0,0 +1,51 @@
+#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_C_LG_3 b/tests/ref/fate/hevc-conformance-ENTP_C_LG_3
new file mode 100644
index 0000000..3c0946e
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-ENTP_C_LG_3
@@ -0,0 +1,51 @@
+#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-EXT_A_ericsson_3 b/tests/ref/fate/hevc-conformance-EXT_A_ericsson_3
new file mode 100644
index 0000000..bf4616a
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-EXT_A_ericsson_3
@@ -0,0 +1,4 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8ce7200b
+0, 1, 1, 1, 149760, 0xf97412f6
+0, 2, 2, 1, 149760, 0x0ea132c4
diff --git a/tests/ref/fate/hevc-conformance-IPRED_A_docomo_2 b/tests/ref/fate/hevc-conformance-IPRED_A_docomo_2
new file mode 100644
index 0000000..33878fd
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-IPRED_A_docomo_2
@@ -0,0 +1,21 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0xac658d10
+0, 1, 1, 1, 599040, 0xe3f65389
+0, 2, 2, 1, 599040, 0xfbd644b0
+0, 3, 3, 1, 599040, 0x3ac49569
+0, 4, 4, 1, 599040, 0x75abc5e2
+0, 5, 5, 1, 599040, 0xe787ddcd
+0, 6, 6, 1, 599040, 0x1df5f293
+0, 7, 7, 1, 599040, 0xa87774aa
+0, 8, 8, 1, 599040, 0x42b2bec6
+0, 9, 9, 1, 599040, 0x89f22378
+0, 10, 10, 1, 599040, 0x0d4e5397
+0, 11, 11, 1, 599040, 0xf4430d13
+0, 12, 12, 1, 599040, 0xfd2ff520
+0, 13, 13, 1, 599040, 0x21bf374b
+0, 14, 14, 1, 599040, 0xcba1032e
+0, 15, 15, 1, 599040, 0x58247f24
+0, 16, 16, 1, 599040, 0x7985788a
+0, 17, 17, 1, 599040, 0x3306488e
+0, 18, 18, 1, 599040, 0x8bcbf22e
+0, 19, 19, 1, 599040, 0xb7a7ae5c
diff --git a/tests/ref/fate/hevc-conformance-IPRED_B_Nokia_3 b/tests/ref/fate/hevc-conformance-IPRED_B_Nokia_3
new file mode 100644
index 0000000..4de7c3c
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-IPRED_B_Nokia_3
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0x11ef5ddd
diff --git a/tests/ref/fate/hevc-conformance-IPRED_C_Mitsubishi_2 b/tests/ref/fate/hevc-conformance-IPRED_C_Mitsubishi_2
new file mode 100644
index 0000000..bff448b
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-IPRED_C_Mitsubishi_2
@@ -0,0 +1,5 @@
+#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-LS_A_Orange_2 b/tests/ref/fate/hevc-conformance-LS_A_Orange_2
new file mode 100644
index 0000000..4dd4ad4
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-LS_A_Orange_2
@@ -0,0 +1,10 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x94a51701
+0, 1, 1, 1, 149760, 0x67c71885
+0, 2, 2, 1, 149760, 0x218f1751
+0, 3, 3, 1, 149760, 0x56951bef
+0, 4, 4, 1, 149760, 0x76aec81e
+0, 5, 5, 1, 149760, 0x20df61ac
+0, 6, 6, 1, 149760, 0x2eacf616
+0, 7, 7, 1, 149760, 0x06322ce2
+0, 8, 8, 1, 149760, 0xf14aa104
diff --git a/tests/ref/fate/hevc-conformance-LS_B_ORANGE_3 b/tests/ref/fate/hevc-conformance-LS_B_ORANGE_3
new file mode 100644
index 0000000..34dc379
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-LS_B_ORANGE_3
@@ -0,0 +1,26 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x25267761
+0, 1, 1, 1, 599040, 0x4b4b6846
+0, 2, 2, 1, 599040, 0x78e251e8
+0, 3, 3, 1, 599040, 0xd5b261b0
+0, 4, 4, 1, 599040, 0x2c4cf4e1
+0, 5, 5, 1, 599040, 0x67dc648f
+0, 6, 6, 1, 599040, 0x3c43bffc
+0, 7, 7, 1, 599040, 0x43dca917
+0, 8, 8, 1, 599040, 0x86c9915e
+0, 9, 9, 1, 599040, 0xcfc4f95c
+0, 10, 10, 1, 599040, 0x1ad40bab
+0, 11, 11, 1, 599040, 0x88b5419e
+0, 12, 12, 1, 599040, 0x94e89a06
+0, 13, 13, 1, 599040, 0x3c68f4a6
+0, 14, 14, 1, 599040, 0xc573ac93
+0, 15, 15, 1, 599040, 0x3c401779
+0, 16, 16, 1, 599040, 0x33358319
+0, 17, 17, 1, 599040, 0xbecb022e
+0, 18, 18, 1, 599040, 0x824ca6c1
+0, 19, 19, 1, 599040, 0x9d13a2b8
+0, 20, 20, 1, 599040, 0xbdd4b44b
+0, 21, 21, 1, 599040, 0x7e43e7e9
+0, 22, 22, 1, 599040, 0x88c39a97
+0, 23, 23, 1, 599040, 0xe0462f05
+0, 24, 24, 1, 599040, 0xc5651fd1
diff --git a/tests/ref/fate/hevc-conformance-MAXBINS_A_TI_4 b/tests/ref/fate/hevc-conformance-MAXBINS_A_TI_4
new file mode 100644
index 0000000..9110cf6
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-MAXBINS_A_TI_4
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x9cad90f9
+0, 1, 1, 1, 149760, 0x7deeab1c
diff --git a/tests/ref/fate/hevc-conformance-MAXBINS_B_TI_4 b/tests/ref/fate/hevc-conformance-MAXBINS_B_TI_4
new file mode 100644
index 0000000..5cad961
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-MAXBINS_B_TI_4
@@ -0,0 +1,4 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x211e8487
+0, 1, 1, 1, 149760, 0xa53b13d8
+0, 2, 2, 1, 149760, 0xb63cc103
diff --git a/tests/ref/fate/hevc-conformance-MAXBINS_C_TI_4 b/tests/ref/fate/hevc-conformance-MAXBINS_C_TI_4
new file mode 100644
index 0000000..2eb3843
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-MAXBINS_C_TI_4
@@ -0,0 +1,4 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xa8d7adfa
+0, 1, 1, 1, 149760, 0x76d1ddfe
+0, 2, 2, 1, 149760, 0x56599cae
diff --git a/tests/ref/fate/hevc-conformance-MERGE_A_TI_3 b/tests/ref/fate/hevc-conformance-MERGE_A_TI_3
new file mode 100644
index 0000000..0ab6acc
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-MERGE_A_TI_3
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8edb27d7
+0, 1, 1, 1, 149760, 0x16eb25a8
+0, 2, 2, 1, 149760, 0xcfff29c8
+0, 3, 3, 1, 149760, 0x4c9721e9
+0, 4, 4, 1, 149760, 0xee52e28d
+0, 5, 5, 1, 149760, 0xc25d9657
+0, 6, 6, 1, 149760, 0x0f644c82
+0, 7, 7, 1, 149760, 0x6f57aea1
diff --git a/tests/ref/fate/hevc-conformance-MERGE_B_TI_3 b/tests/ref/fate/hevc-conformance-MERGE_B_TI_3
new file mode 100644
index 0000000..2f9395f
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-MERGE_B_TI_3
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8edb27d7
+0, 1, 1, 1, 149760, 0xb5932505
+0, 2, 2, 1, 149760, 0xa5b20e66
+0, 3, 3, 1, 149760, 0x0d9f17cb
+0, 4, 4, 1, 149760, 0xf2b1dc80
+0, 5, 5, 1, 149760, 0xab8c8272
+0, 6, 6, 1, 149760, 0x50662cf4
+0, 7, 7, 1, 149760, 0x83cc8d5f
diff --git a/tests/ref/fate/hevc-conformance-MERGE_C_TI_3 b/tests/ref/fate/hevc-conformance-MERGE_C_TI_3
new file mode 100644
index 0000000..bcc5a1a
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-MERGE_C_TI_3
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8edb27d7
+0, 1, 1, 1, 149760, 0x88cb1216
+0, 2, 2, 1, 149760, 0x6d1024da
+0, 3, 3, 1, 149760, 0x90b13981
+0, 4, 4, 1, 149760, 0x4296ed51
+0, 5, 5, 1, 149760, 0x4da5926f
+0, 6, 6, 1, 149760, 0xa74b4368
+0, 7, 7, 1, 149760, 0x518fb0fc
diff --git a/tests/ref/fate/hevc-conformance-MERGE_D_TI_3 b/tests/ref/fate/hevc-conformance-MERGE_D_TI_3
new file mode 100644
index 0000000..7b4df26
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-MERGE_D_TI_3
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8edb27d7
+0, 1, 1, 1, 149760, 0x3220183c
+0, 2, 2, 1, 149760, 0x43a21acc
+0, 3, 3, 1, 149760, 0x7bde17f9
+0, 4, 4, 1, 149760, 0x98a1cece
+0, 5, 5, 1, 149760, 0x3d7b64b9
+0, 6, 6, 1, 149760, 0xd9311172
+0, 7, 7, 1, 149760, 0x90d192a3
diff --git a/tests/ref/fate/hevc-conformance-MERGE_E_TI_3 b/tests/ref/fate/hevc-conformance-MERGE_E_TI_3
new file mode 100644
index 0000000..8491172
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-MERGE_E_TI_3
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8edb27d7
+0, 1, 1, 1, 149760, 0x187419b5
+0, 2, 2, 1, 149760, 0x61100980
+0, 3, 3, 1, 149760, 0xd799123e
+0, 4, 4, 1, 149760, 0x9011c8d0
+0, 5, 5, 1, 149760, 0xeafe7d99
+0, 6, 6, 1, 149760, 0x94f32245
+0, 7, 7, 1, 149760, 0x8185910a
diff --git a/tests/ref/fate/hevc-conformance-MERGE_F_MTK_4 b/tests/ref/fate/hevc-conformance-MERGE_F_MTK_4
new file mode 100644
index 0000000..34a0979
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-MERGE_F_MTK_4
@@ -0,0 +1,42 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xcfffa013
+0, 1, 1, 1, 149760, 0xec800e71
+0, 2, 2, 1, 149760, 0x9fb014c7
+0, 3, 3, 1, 149760, 0xfd7a48a8
+0, 4, 4, 1, 149760, 0x99816bb5
+0, 5, 5, 1, 149760, 0x8645acaa
+0, 6, 6, 1, 149760, 0xd2a8e04b
+0, 7, 7, 1, 149760, 0xf96f038d
+0, 8, 8, 1, 149760, 0x82c62409
+0, 9, 9, 1, 149760, 0x64907b29
+0, 10, 10, 1, 149760, 0xfe29990e
+0, 11, 11, 1, 149760, 0xce2dc52d
+0, 12, 12, 1, 149760, 0x164fb2c5
+0, 13, 13, 1, 149760, 0xbcf8ca2d
+0, 14, 14, 1, 149760, 0xe59dc9bc
+0, 15, 15, 1, 149760, 0x2ab10400
+0, 16, 16, 1, 149760, 0xef111c81
+0, 17, 17, 1, 149760, 0xd08466b1
+0, 18, 18, 1, 149760, 0x6d356ff0
+0, 19, 19, 1, 149760, 0x16a59175
+0, 20, 20, 1, 149760, 0xd7888866
+0, 21, 21, 1, 149760, 0x2b22b943
+0, 22, 22, 1, 149760, 0x3b4fc3fe
+0, 23, 23, 1, 149760, 0x4ec8ee47
+0, 24, 24, 1, 149760, 0x0126f17b
+0, 25, 25, 1, 149760, 0x1176ad14
+0, 26, 26, 1, 149760, 0x2d4da75f
+0, 27, 27, 1, 149760, 0x144bb9e4
+0, 28, 28, 1, 149760, 0x5176a21b
+0, 29, 29, 1, 149760, 0x5e3fe673
+0, 30, 30, 1, 149760, 0xa533db65
+0, 31, 31, 1, 149760, 0x3009f3f8
+0, 32, 32, 1, 149760, 0xd4437e12
+0, 33, 33, 1, 149760, 0x5b03cd64
+0, 34, 34, 1, 149760, 0xdc40d49b
+0, 35, 35, 1, 149760, 0xf8cef0f6
+0, 36, 36, 1, 149760, 0x241be1b7
+0, 37, 37, 1, 149760, 0x23830404
+0, 38, 38, 1, 149760, 0x6ef7087e
+0, 39, 39, 1, 149760, 0xaf351e5b
+0, 40, 40, 1, 149760, 0x4cf40a64
diff --git a/tests/ref/fate/hevc-conformance-MERGE_G_HHI_4 b/tests/ref/fate/hevc-conformance-MERGE_G_HHI_4
new file mode 100644
index 0000000..2e88350
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-MERGE_G_HHI_4
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x65433cfe
+0, 1, 1, 1, 599040, 0x9309e2c5
diff --git a/tests/ref/fate/hevc-conformance-MVCLIP_A_qualcomm_3 b/tests/ref/fate/hevc-conformance-MVCLIP_A_qualcomm_3
new file mode 100644
index 0000000..6756221
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-MVCLIP_A_qualcomm_3
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xa5b11720
+0, 1, 1, 1, 149760, 0x42e52c6e
+0, 2, 2, 1, 149760, 0x27b15a30
+0, 3, 3, 1, 149760, 0x4d759826
+0, 4, 4, 1, 149760, 0xfb6daf0c
diff --git a/tests/ref/fate/hevc-conformance-MVDL1ZERO_A_docomo_3 b/tests/ref/fate/hevc-conformance-MVDL1ZERO_A_docomo_3
new file mode 100644
index 0000000..2019db2
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-MVDL1ZERO_A_docomo_3
@@ -0,0 +1,501 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x9b27dc7d
+0, 1, 1, 1, 599040, 0x796cdd26
+0, 2, 2, 1, 599040, 0xd3c9dca9
+0, 3, 3, 1, 599040, 0xf7b2876a
+0, 4, 4, 1, 599040, 0x296701c8
+0, 5, 5, 1, 599040, 0xf9a80f9a
+0, 6, 6, 1, 599040, 0x7cbe9656
+0, 7, 7, 1, 599040, 0x17093be8
+0, 8, 8, 1, 599040, 0x2a0e196e
+0, 9, 9, 1, 599040, 0x3492c809
+0, 10, 10, 1, 599040, 0xbc5523f3
+0, 11, 11, 1, 599040, 0xf618ff66
+0, 12, 12, 1, 599040, 0x07060c9d
+0, 13, 13, 1, 599040, 0xd5a8fb5d
+0, 14, 14, 1, 599040, 0x780e18b9
+0, 15, 15, 1, 599040, 0xff553fbd
+0, 16, 16, 1, 599040, 0x715cce2d
+0, 17, 17, 1, 599040, 0x8a834c19
+0, 18, 18, 1, 599040, 0xbc4a0c21
+0, 19, 19, 1, 599040, 0xc85fed31
+0, 20, 20, 1, 599040, 0xcbb97b56
+0, 21, 21, 1, 599040, 0x518111dd
+0, 22, 22, 1, 599040, 0x5a680f48
+0, 23, 23, 1, 599040, 0x02956f28
+0, 24, 24, 1, 599040, 0x10845ef6
+0, 25, 25, 1, 599040, 0x2ad3c6d7
+0, 26, 26, 1, 599040, 0xa9f725e9
+0, 27, 27, 1, 599040, 0xb835f470
+0, 28, 28, 1, 599040, 0x693bf01d
+0, 29, 29, 1, 599040, 0x50bf3b77
+0, 30, 30, 1, 599040, 0x304873e3
+0, 31, 31, 1, 599040, 0x707a6af9
+0, 32, 32, 1, 599040, 0x50bf2017
+0, 33, 33, 1, 599040, 0x2c583f11
+0, 34, 34, 1, 599040, 0xe738080b
+0, 35, 35, 1, 599040, 0x549984e6
+0, 36, 36, 1, 599040, 0xa22e8a96
+0, 37, 37, 1, 599040, 0xc9f222cd
+0, 38, 38, 1, 599040, 0x28d944bc
+0, 39, 39, 1, 599040, 0x2e366350
+0, 40, 40, 1, 599040, 0xbcc2eb12
+0, 41, 41, 1, 599040, 0x074d3fdd
+0, 42, 42, 1, 599040, 0x0e0bd820
+0, 43, 43, 1, 599040, 0xf078af68
+0, 44, 44, 1, 599040, 0xaeed7222
+0, 45, 45, 1, 599040, 0xb66100cd
+0, 46, 46, 1, 599040, 0x848cd1c5
+0, 47, 47, 1, 599040, 0xa6bf930c
+0, 48, 48, 1, 599040, 0x32501b56
+0, 49, 49, 1, 599040, 0x2498d992
+0, 50, 50, 1, 599040, 0x03481b78
+0, 51, 51, 1, 599040, 0x551d7c11
+0, 52, 52, 1, 599040, 0xfbdc629d
+0, 53, 53, 1, 599040, 0x1f438ded
+0, 54, 54, 1, 599040, 0x4d25ce07
+0, 55, 55, 1, 599040, 0x4fe8f8aa
+0, 56, 56, 1, 599040, 0x5d65d790
+0, 57, 57, 1, 599040, 0xfcba4efb
+0, 58, 58, 1, 599040, 0x50b483a3
+0, 59, 59, 1, 599040, 0x12fd4b31
+0, 60, 60, 1, 599040, 0x71014417
+0, 61, 61, 1, 599040, 0xeed88bc4
+0, 62, 62, 1, 599040, 0xb2d4710d
+0, 63, 63, 1, 599040, 0xbe4dfe69
+0, 64, 64, 1, 599040, 0x9b7844b6
+0, 65, 65, 1, 599040, 0xe2e691bf
+0, 66, 66, 1, 599040, 0xb24200dc
+0, 67, 67, 1, 599040, 0xf29cb5bf
+0, 68, 68, 1, 599040, 0x90350310
+0, 69, 69, 1, 599040, 0xbe1cc3c1
+0, 70, 70, 1, 599040, 0xaae58f97
+0, 71, 71, 1, 599040, 0x0d5cb388
+0, 72, 72, 1, 599040, 0x0fa734e3
+0, 73, 73, 1, 599040, 0xaa41543a
+0, 74, 74, 1, 599040, 0x3e6e1d4b
+0, 75, 75, 1, 599040, 0x6426e543
+0, 76, 76, 1, 599040, 0xe65ad058
+0, 77, 77, 1, 599040, 0xf7f1744d
+0, 78, 78, 1, 599040, 0xa8fa32da
+0, 79, 79, 1, 599040, 0xa2c80e49
+0, 80, 80, 1, 599040, 0x22b972e9
+0, 81, 81, 1, 599040, 0x2462823b
+0, 82, 82, 1, 599040, 0xa7fd0432
+0, 83, 83, 1, 599040, 0x38d22ea4
+0, 84, 84, 1, 599040, 0xb472f4d6
+0, 85, 85, 1, 599040, 0x36c107a0
+0, 86, 86, 1, 599040, 0x9abb5ce0
+0, 87, 87, 1, 599040, 0x74b2861c
+0, 88, 88, 1, 599040, 0xba3d04d3
+0, 89, 89, 1, 599040, 0x65132373
+0, 90, 90, 1, 599040, 0x63585754
+0, 91, 91, 1, 599040, 0xa6c0f4d4
+0, 92, 92, 1, 599040, 0xc2cf9c33
+0, 93, 93, 1, 599040, 0xdf6d16af
+0, 94, 94, 1, 599040, 0x94566b11
+0, 95, 95, 1, 599040, 0x8070818d
+0, 96, 96, 1, 599040, 0x4acc92c1
+0, 97, 97, 1, 599040, 0xb520033c
+0, 98, 98, 1, 599040, 0xc82e7058
+0, 99, 99, 1, 599040, 0xb23367bc
+0, 100, 100, 1, 599040, 0x1fa25586
+0, 101, 101, 1, 599040, 0x2b2abbb8
+0, 102, 102, 1, 599040, 0xb9b74546
+0, 103, 103, 1, 599040, 0x4c4a2ef9
+0, 104, 104, 1, 599040, 0x5eb54025
+0, 105, 105, 1, 599040, 0x1e1cbcc6
+0, 106, 106, 1, 599040, 0xc3bf1017
+0, 107, 107, 1, 599040, 0xdbda1761
+0, 108, 108, 1, 599040, 0x19241b7c
+0, 109, 109, 1, 599040, 0x791dda93
+0, 110, 110, 1, 599040, 0x444a152f
+0, 111, 111, 1, 599040, 0x0b69d08b
+0, 112, 112, 1, 599040, 0xd024abae
+0, 113, 113, 1, 599040, 0x724e0d78
+0, 114, 114, 1, 599040, 0x648f9c09
+0, 115, 115, 1, 599040, 0xee114298
+0, 116, 116, 1, 599040, 0x92d1e98f
+0, 117, 117, 1, 599040, 0xb623cb10
+0, 118, 118, 1, 599040, 0xf8e9b414
+0, 119, 119, 1, 599040, 0xe47a0981
+0, 120, 120, 1, 599040, 0xdc78d28d
+0, 121, 121, 1, 599040, 0xd36d9ad5
+0, 122, 122, 1, 599040, 0xe7bea48e
+0, 123, 123, 1, 599040, 0x0dd39d1d
+0, 124, 124, 1, 599040, 0xb66a18ee
+0, 125, 125, 1, 599040, 0x6085d265
+0, 126, 126, 1, 599040, 0xb9ef646b
+0, 127, 127, 1, 599040, 0x544140a4
+0, 128, 128, 1, 599040, 0x9c546327
+0, 129, 129, 1, 599040, 0xd74d4a8e
+0, 130, 130, 1, 599040, 0x98a504e0
+0, 131, 131, 1, 599040, 0x88849351
+0, 132, 132, 1, 599040, 0xa519f6c7
+0, 133, 133, 1, 599040, 0xc548df7f
+0, 134, 134, 1, 599040, 0x8e690444
+0, 135, 135, 1, 599040, 0x5edbdced
+0, 136, 136, 1, 599040, 0xd3e189c2
+0, 137, 137, 1, 599040, 0x286d44a2
+0, 138, 138, 1, 599040, 0xe946f83e
+0, 139, 139, 1, 599040, 0xdc94ae6d
+0, 140, 140, 1, 599040, 0x5d4e95dc
+0, 141, 141, 1, 599040, 0x2c03280f
+0, 142, 142, 1, 599040, 0x368c6b23
+0, 143, 143, 1, 599040, 0x2fc5d2ee
+0, 144, 144, 1, 599040, 0x85e8f3ec
+0, 145, 145, 1, 599040, 0xd1fdcf69
+0, 146, 146, 1, 599040, 0xa663cf5a
+0, 147, 147, 1, 599040, 0x5d644057
+0, 148, 148, 1, 599040, 0xfdd039e0
+0, 149, 149, 1, 599040, 0x9cdb6369
+0, 150, 150, 1, 599040, 0x3c4ca86b
+0, 151, 151, 1, 599040, 0x27ac4d91
+0, 152, 152, 1, 599040, 0x3f13a8bb
+0, 153, 153, 1, 599040, 0xbcd984c5
+0, 154, 154, 1, 599040, 0xa55eb124
+0, 155, 155, 1, 599040, 0xb09c4a47
+0, 156, 156, 1, 599040, 0x0da7fd48
+0, 157, 157, 1, 599040, 0xa01dc374
+0, 158, 158, 1, 599040, 0xe428b3b0
+0, 159, 159, 1, 599040, 0xff3fcc43
+0, 160, 160, 1, 599040, 0xbc5491c1
+0, 161, 161, 1, 599040, 0x34e51a66
+0, 162, 162, 1, 599040, 0xb63f5acd
+0, 163, 163, 1, 599040, 0xe12f417d
+0, 164, 164, 1, 599040, 0x789bb191
+0, 165, 165, 1, 599040, 0x5fdeaa57
+0, 166, 166, 1, 599040, 0x65034250
+0, 167, 167, 1, 599040, 0xab577632
+0, 168, 168, 1, 599040, 0x1338c7eb
+0, 169, 169, 1, 599040, 0x5a84b078
+0, 170, 170, 1, 599040, 0x9f3fd6c2
+0, 171, 171, 1, 599040, 0x23cd7f3f
+0, 172, 172, 1, 599040, 0x43701c5c
+0, 173, 173, 1, 599040, 0x72eff5aa
+0, 174, 174, 1, 599040, 0x858a7280
+0, 175, 175, 1, 599040, 0x5d1da2b1
+0, 176, 176, 1, 599040, 0x2b6fae7b
+0, 177, 177, 1, 599040, 0x3d96cd3f
+0, 178, 178, 1, 599040, 0x5d6d48e5
+0, 179, 179, 1, 599040, 0x829023ee
+0, 180, 180, 1, 599040, 0xeafa5127
+0, 181, 181, 1, 599040, 0x1adf2830
+0, 182, 182, 1, 599040, 0x35f07617
+0, 183, 183, 1, 599040, 0x7aa691e2
+0, 184, 184, 1, 599040, 0xd11b3ed2
+0, 185, 185, 1, 599040, 0x69c12b52
+0, 186, 186, 1, 599040, 0x34fb8557
+0, 187, 187, 1, 599040, 0xd06c84ff
+0, 188, 188, 1, 599040, 0x26338170
+0, 189, 189, 1, 599040, 0x3d24f1e9
+0, 190, 190, 1, 599040, 0x28a99f46
+0, 191, 191, 1, 599040, 0x22421eea
+0, 192, 192, 1, 599040, 0xc53b57eb
+0, 193, 193, 1, 599040, 0x752433b8
+0, 194, 194, 1, 599040, 0x6332eaaa
+0, 195, 195, 1, 599040, 0x559d273f
+0, 196, 196, 1, 599040, 0xe9811056
+0, 197, 197, 1, 599040, 0x61acf706
+0, 198, 198, 1, 599040, 0x3893c930
+0, 199, 199, 1, 599040, 0x5d6d3f58
+0, 200, 200, 1, 599040, 0xb645df35
+0, 201, 201, 1, 599040, 0x6af7f2eb
+0, 202, 202, 1, 599040, 0xeb456cc5
+0, 203, 203, 1, 599040, 0x32abac64
+0, 204, 204, 1, 599040, 0x1327da04
+0, 205, 205, 1, 599040, 0x73ca53b9
+0, 206, 206, 1, 599040, 0xe940d23e
+0, 207, 207, 1, 599040, 0xc6fdf611
+0, 208, 208, 1, 599040, 0xc72e4309
+0, 209, 209, 1, 599040, 0xecab46a1
+0, 210, 210, 1, 599040, 0xb248b91e
+0, 211, 211, 1, 599040, 0xe9aeb62c
+0, 212, 212, 1, 599040, 0x5827cf39
+0, 213, 213, 1, 599040, 0x763a74d6
+0, 214, 214, 1, 599040, 0x232e397c
+0, 215, 215, 1, 599040, 0xe2ef8213
+0, 216, 216, 1, 599040, 0xddcbe94f
+0, 217, 217, 1, 599040, 0xe8a8919a
+0, 218, 218, 1, 599040, 0x5860fae0
+0, 219, 219, 1, 599040, 0x525b1a95
+0, 220, 220, 1, 599040, 0x50e36027
+0, 221, 221, 1, 599040, 0xd05ee599
+0, 222, 222, 1, 599040, 0xc1e7b87b
+0, 223, 223, 1, 599040, 0x2edfa52c
+0, 224, 224, 1, 599040, 0xca147244
+0, 225, 225, 1, 599040, 0x9e0a77b7
+0, 226, 226, 1, 599040, 0x88ac8035
+0, 227, 227, 1, 599040, 0xe34c890a
+0, 228, 228, 1, 599040, 0xbe4feadd
+0, 229, 229, 1, 599040, 0xd5a7503d
+0, 230, 230, 1, 599040, 0xae18e82d
+0, 231, 231, 1, 599040, 0x66cf3881
+0, 232, 232, 1, 599040, 0x9f08a65c
+0, 233, 233, 1, 599040, 0xeb3e1a58
+0, 234, 234, 1, 599040, 0x2b83004a
+0, 235, 235, 1, 599040, 0x65be32c9
+0, 236, 236, 1, 599040, 0x231586fa
+0, 237, 237, 1, 599040, 0x7e5724fb
+0, 238, 238, 1, 599040, 0xfebe47b6
+0, 239, 239, 1, 599040, 0xfeeb9a38
+0, 240, 240, 1, 599040, 0x44e90683
+0, 241, 241, 1, 599040, 0x546d03f4
+0, 242, 242, 1, 599040, 0x211a534e
+0, 243, 243, 1, 599040, 0x12d2a800
+0, 244, 244, 1, 599040, 0xa6022d19
+0, 245, 245, 1, 599040, 0x6bedd152
+0, 246, 246, 1, 599040, 0x6f7de80b
+0, 247, 247, 1, 599040, 0x778f0771
+0, 248, 248, 1, 599040, 0xe63e4241
+0, 249, 249, 1, 599040, 0xa0298023
+0, 250, 250, 1, 599040, 0xc4c5b8b2
+0, 251, 251, 1, 599040, 0xcca64f1c
+0, 252, 252, 1, 599040, 0xfec4d1a0
+0, 253, 253, 1, 599040, 0xcb7c4b80
+0, 254, 254, 1, 599040, 0x0795f7b7
+0, 255, 255, 1, 599040, 0x5f45706c
+0, 256, 256, 1, 599040, 0x927f04d8
+0, 257, 257, 1, 599040, 0x4c201f08
+0, 258, 258, 1, 599040, 0xdb447b37
+0, 259, 259, 1, 599040, 0xae33725e
+0, 260, 260, 1, 599040, 0x474281af
+0, 261, 261, 1, 599040, 0xe198764e
+0, 262, 262, 1, 599040, 0xb226916f
+0, 263, 263, 1, 599040, 0x8a7156a5
+0, 264, 264, 1, 599040, 0x5fe639ab
+0, 265, 265, 1, 599040, 0xaa62b79e
+0, 266, 266, 1, 599040, 0x94618e23
+0, 267, 267, 1, 599040, 0x47ba12f0
+0, 268, 268, 1, 599040, 0xd33c215e
+0, 269, 269, 1, 599040, 0x581e0537
+0, 270, 270, 1, 599040, 0x19dce924
+0, 271, 271, 1, 599040, 0x95329055
+0, 272, 272, 1, 599040, 0x6d2eb80f
+0, 273, 273, 1, 599040, 0x11d5e940
+0, 274, 274, 1, 599040, 0x30aec978
+0, 275, 275, 1, 599040, 0xd742df04
+0, 276, 276, 1, 599040, 0xef9ef4ae
+0, 277, 277, 1, 599040, 0x51d8fb34
+0, 278, 278, 1, 599040, 0xbb6e070a
+0, 279, 279, 1, 599040, 0x785a9813
+0, 280, 280, 1, 599040, 0xb94d8771
+0, 281, 281, 1, 599040, 0x8bd2fe53
+0, 282, 282, 1, 599040, 0x6b600868
+0, 283, 283, 1, 599040, 0x4b1d6a6f
+0, 284, 284, 1, 599040, 0x974f6365
+0, 285, 285, 1, 599040, 0xebefa21d
+0, 286, 286, 1, 599040, 0x8ce62dad
+0, 287, 287, 1, 599040, 0x7a6e6e1b
+0, 288, 288, 1, 599040, 0x3746d218
+0, 289, 289, 1, 599040, 0xc1aa50d9
+0, 290, 290, 1, 599040, 0xda60f976
+0, 291, 291, 1, 599040, 0x98274aa8
+0, 292, 292, 1, 599040, 0xdf09c760
+0, 293, 293, 1, 599040, 0xeb485b8f
+0, 294, 294, 1, 599040, 0xad76453b
+0, 295, 295, 1, 599040, 0x6eaee19a
+0, 296, 296, 1, 599040, 0x464e9cc8
+0, 297, 297, 1, 599040, 0xccd0bd12
+0, 298, 298, 1, 599040, 0xc7345e2b
+0, 299, 299, 1, 599040, 0xe51dd0a9
+0, 300, 300, 1, 599040, 0x11b9586b
+0, 301, 301, 1, 599040, 0xcb2c85b8
+0, 302, 302, 1, 599040, 0x024ce62d
+0, 303, 303, 1, 599040, 0x8c1da4eb
+0, 304, 304, 1, 599040, 0x9924ed3f
+0, 305, 305, 1, 599040, 0xc8f89a61
+0, 306, 306, 1, 599040, 0x52db38f2
+0, 307, 307, 1, 599040, 0xf1baca44
+0, 308, 308, 1, 599040, 0x8d1b322e
+0, 309, 309, 1, 599040, 0x5e8a990e
+0, 310, 310, 1, 599040, 0xfe281b7c
+0, 311, 311, 1, 599040, 0x065ced47
+0, 312, 312, 1, 599040, 0x962087db
+0, 313, 313, 1, 599040, 0x2e932805
+0, 314, 314, 1, 599040, 0x9a4b4946
+0, 315, 315, 1, 599040, 0x504bea02
+0, 316, 316, 1, 599040, 0xff97cf64
+0, 317, 317, 1, 599040, 0xcca9a61c
+0, 318, 318, 1, 599040, 0x1ab70ff5
+0, 319, 319, 1, 599040, 0x99ed2919
+0, 320, 320, 1, 599040, 0xa02f40d2
+0, 321, 321, 1, 599040, 0x8a1d83c2
+0, 322, 322, 1, 599040, 0xaacec6c2
+0, 323, 323, 1, 599040, 0x4f6fe261
+0, 324, 324, 1, 599040, 0x1dde4745
+0, 325, 325, 1, 599040, 0xa17bdf95
+0, 326, 326, 1, 599040, 0xcb5b56b3
+0, 327, 327, 1, 599040, 0x7088cdd4
+0, 328, 328, 1, 599040, 0xca02bafb
+0, 329, 329, 1, 599040, 0x3c5ca543
+0, 330, 330, 1, 599040, 0x4ab80de3
+0, 331, 331, 1, 599040, 0x75edb57b
+0, 332, 332, 1, 599040, 0x772ef858
+0, 333, 333, 1, 599040, 0xd7fa8d9f
+0, 334, 334, 1, 599040, 0xbc515acc
+0, 335, 335, 1, 599040, 0xb1b66d54
+0, 336, 336, 1, 599040, 0x40290b6a
+0, 337, 337, 1, 599040, 0xd1ff952e
+0, 338, 338, 1, 599040, 0x5641abf7
+0, 339, 339, 1, 599040, 0x3411e0fd
+0, 340, 340, 1, 599040, 0xed4abbaf
+0, 341, 341, 1, 599040, 0x34d40ea4
+0, 342, 342, 1, 599040, 0xa9983db0
+0, 343, 343, 1, 599040, 0x58dc8d9a
+0, 344, 344, 1, 599040, 0x24a989a2
+0, 345, 345, 1, 599040, 0xc9d1dcdd
+0, 346, 346, 1, 599040, 0x6df3031f
+0, 347, 347, 1, 599040, 0xa67339d9
+0, 348, 348, 1, 599040, 0x545b3ed1
+0, 349, 349, 1, 599040, 0xb4d98187
+0, 350, 350, 1, 599040, 0xdd2f8588
+0, 351, 351, 1, 599040, 0x2aee5737
+0, 352, 352, 1, 599040, 0xe7c90c87
+0, 353, 353, 1, 599040, 0xb547f0bc
+0, 354, 354, 1, 599040, 0x69cc594a
+0, 355, 355, 1, 599040, 0xa01adf9c
+0, 356, 356, 1, 599040, 0x77021bc9
+0, 357, 357, 1, 599040, 0x1cd7e74b
+0, 358, 358, 1, 599040, 0x4d284292
+0, 359, 359, 1, 599040, 0xe57fd832
+0, 360, 360, 1, 599040, 0x76992cf7
+0, 361, 361, 1, 599040, 0x88156158
+0, 362, 362, 1, 599040, 0xc872db18
+0, 363, 363, 1, 599040, 0xc0487bf4
+0, 364, 364, 1, 599040, 0x9f3aab7b
+0, 365, 365, 1, 599040, 0xfddd1c86
+0, 366, 366, 1, 599040, 0x2a991cff
+0, 367, 367, 1, 599040, 0x97e3623f
+0, 368, 368, 1, 599040, 0x69e5900a
+0, 369, 369, 1, 599040, 0x7a5167ec
+0, 370, 370, 1, 599040, 0x74bf045a
+0, 371, 371, 1, 599040, 0x5b2c1554
+0, 372, 372, 1, 599040, 0xc7e9c2e1
+0, 373, 373, 1, 599040, 0x9d76e364
+0, 374, 374, 1, 599040, 0x2c365ed8
+0, 375, 375, 1, 599040, 0x3b7bb213
+0, 376, 376, 1, 599040, 0x00a34fa9
+0, 377, 377, 1, 599040, 0x0a82f6b8
+0, 378, 378, 1, 599040, 0x34f8cf6b
+0, 379, 379, 1, 599040, 0x283a256f
+0, 380, 380, 1, 599040, 0x89dfe63a
+0, 381, 381, 1, 599040, 0x757c7bc3
+0, 382, 382, 1, 599040, 0xbcbf4f4a
+0, 383, 383, 1, 599040, 0x45fe93d3
+0, 384, 384, 1, 599040, 0xa93c4724
+0, 385, 385, 1, 599040, 0x25862ef7
+0, 386, 386, 1, 599040, 0xff94b8eb
+0, 387, 387, 1, 599040, 0x9d350c21
+0, 388, 388, 1, 599040, 0x90d6cce5
+0, 389, 389, 1, 599040, 0x5c3e51c8
+0, 390, 390, 1, 599040, 0x8f966096
+0, 391, 391, 1, 599040, 0xddc8ad04
+0, 392, 392, 1, 599040, 0xb64a170a
+0, 393, 393, 1, 599040, 0xfb8fa0c6
+0, 394, 394, 1, 599040, 0x99fa48dc
+0, 395, 395, 1, 599040, 0xd62e9344
+0, 396, 396, 1, 599040, 0x55ff8d51
+0, 397, 397, 1, 599040, 0x1e9809bd
+0, 398, 398, 1, 599040, 0x00f0122d
+0, 399, 399, 1, 599040, 0x5af2911e
+0, 400, 400, 1, 599040, 0xbfcd6c1d
+0, 401, 401, 1, 599040, 0xd809c652
+0, 402, 402, 1, 599040, 0xee36969a
+0, 403, 403, 1, 599040, 0x9c0ed842
+0, 404, 404, 1, 599040, 0x4e07a2b0
+0, 405, 405, 1, 599040, 0xa5b3202b
+0, 406, 406, 1, 599040, 0x4c1add0e
+0, 407, 407, 1, 599040, 0x489b2fa9
+0, 408, 408, 1, 599040, 0xa088c512
+0, 409, 409, 1, 599040, 0x4f6121ac
+0, 410, 410, 1, 599040, 0x1959f62b
+0, 411, 411, 1, 599040, 0x2d51a5c4
+0, 412, 412, 1, 599040, 0x95e70f4f
+0, 413, 413, 1, 599040, 0x4eab3c11
+0, 414, 414, 1, 599040, 0xf2c2b9b5
+0, 415, 415, 1, 599040, 0x62f50ffe
+0, 416, 416, 1, 599040, 0x2104d2f8
+0, 417, 417, 1, 599040, 0x42a8b39f
+0, 418, 418, 1, 599040, 0x857f1fe6
+0, 419, 419, 1, 599040, 0x6ac5190d
+0, 420, 420, 1, 599040, 0x228d7a0b
+0, 421, 421, 1, 599040, 0x0042ef94
+0, 422, 422, 1, 599040, 0x4a83e001
+0, 423, 423, 1, 599040, 0xc43fec08
+0, 424, 424, 1, 599040, 0x5e029548
+0, 425, 425, 1, 599040, 0xbc89dea9
+0, 426, 426, 1, 599040, 0x6c5d88cf
+0, 427, 427, 1, 599040, 0x3a5dabfb
+0, 428, 428, 1, 599040, 0x876e1e54
+0, 429, 429, 1, 599040, 0x55715da8
+0, 430, 430, 1, 599040, 0x199c039b
+0, 431, 431, 1, 599040, 0x0286f71e
+0, 432, 432, 1, 599040, 0xf9a244a1
+0, 433, 433, 1, 599040, 0xf5655275
+0, 434, 434, 1, 599040, 0xde3dba0c
+0, 435, 435, 1, 599040, 0x617f8963
+0, 436, 436, 1, 599040, 0x0fe0e661
+0, 437, 437, 1, 599040, 0x8ba905ea
+0, 438, 438, 1, 599040, 0xb2812b34
+0, 439, 439, 1, 599040, 0x32d61c8b
+0, 440, 440, 1, 599040, 0xb7603400
+0, 441, 441, 1, 599040, 0x232c278f
+0, 442, 442, 1, 599040, 0xdf61c27d
+0, 443, 443, 1, 599040, 0xa053482f
+0, 444, 444, 1, 599040, 0x109724d3
+0, 445, 445, 1, 599040, 0x49d36800
+0, 446, 446, 1, 599040, 0x4a103bff
+0, 447, 447, 1, 599040, 0x7cd3813b
+0, 448, 448, 1, 599040, 0xeef677d7
+0, 449, 449, 1, 599040, 0xc5ad66c2
+0, 450, 450, 1, 599040, 0xa06e472d
+0, 451, 451, 1, 599040, 0x53182cc5
+0, 452, 452, 1, 599040, 0x9e62bfc0
+0, 453, 453, 1, 599040, 0x93515843
+0, 454, 454, 1, 599040, 0x5e0778d7
+0, 455, 455, 1, 599040, 0x957a6d55
+0, 456, 456, 1, 599040, 0x0bc26b3d
+0, 457, 457, 1, 599040, 0x5e0bc514
+0, 458, 458, 1, 599040, 0x7f717a98
+0, 459, 459, 1, 599040, 0x8497968c
+0, 460, 460, 1, 599040, 0x8fb527b8
+0, 461, 461, 1, 599040, 0x8580e487
+0, 462, 462, 1, 599040, 0x59b2d7cc
+0, 463, 463, 1, 599040, 0x5fbc38d7
+0, 464, 464, 1, 599040, 0xb1ba014e
+0, 465, 465, 1, 599040, 0x10481d8f
+0, 466, 466, 1, 599040, 0xd42e42e0
+0, 467, 467, 1, 599040, 0x14a361c1
+0, 468, 468, 1, 599040, 0x58378917
+0, 469, 469, 1, 599040, 0xaeb99a82
+0, 470, 470, 1, 599040, 0x5666ef55
+0, 471, 471, 1, 599040, 0xbd0ce495
+0, 472, 472, 1, 599040, 0xf13af36c
+0, 473, 473, 1, 599040, 0x55e8b101
+0, 474, 474, 1, 599040, 0x4e2966b4
+0, 475, 475, 1, 599040, 0xd973e873
+0, 476, 476, 1, 599040, 0x72d55685
+0, 477, 477, 1, 599040, 0x48eee8c2
+0, 478, 478, 1, 599040, 0x61291b38
+0, 479, 479, 1, 599040, 0x91f839f8
+0, 480, 480, 1, 599040, 0x0a4e9585
+0, 481, 481, 1, 599040, 0x02e0f1f0
+0, 482, 482, 1, 599040, 0xc104009c
+0, 483, 483, 1, 599040, 0x9417127e
+0, 484, 484, 1, 599040, 0x4630302e
+0, 485, 485, 1, 599040, 0x692141ea
+0, 486, 486, 1, 599040, 0x1ebed0bd
+0, 487, 487, 1, 599040, 0x362544a8
+0, 488, 488, 1, 599040, 0xd9cbef36
+0, 489, 489, 1, 599040, 0x54cda997
+0, 490, 490, 1, 599040, 0x79463ed1
+0, 491, 491, 1, 599040, 0xe95b66eb
+0, 492, 492, 1, 599040, 0x5bdaa63e
+0, 493, 493, 1, 599040, 0x72ced562
+0, 494, 494, 1, 599040, 0xcb2bdc53
+0, 495, 495, 1, 599040, 0x4ff80855
+0, 496, 496, 1, 599040, 0x68515ba6
+0, 497, 497, 1, 599040, 0x56228d2d
+0, 498, 498, 1, 599040, 0xb72a68ed
+0, 499, 499, 1, 599040, 0x111cc604
diff --git a/tests/ref/fate/hevc-conformance-MVEDGE_A_qualcomm_3 b/tests/ref/fate/hevc-conformance-MVEDGE_A_qualcomm_3
new file mode 100644
index 0000000..0db06c5
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-MVEDGE_A_qualcomm_3
@@ -0,0 +1,18 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x1d68213a
+0, 1, 1, 1, 149760, 0x9cc81d30
+0, 2, 2, 1, 149760, 0xa3cf6438
+0, 3, 3, 1, 149760, 0x6acf213a
+0, 4, 4, 1, 149760, 0x0f75ce7b
+0, 5, 5, 1, 149760, 0x5e0286a7
+0, 6, 6, 1, 149760, 0xc62cd2b0
+0, 7, 7, 1, 149760, 0x7d9af3ac
+0, 8, 8, 1, 149760, 0x9d58afc7
+0, 9, 9, 1, 149760, 0x91c5ad7f
+0, 10, 10, 1, 149760, 0xc43c5b0a
+0, 11, 11, 1, 149760, 0x6b8cc1a5
+0, 12, 12, 1, 149760, 0x4cebb13e
+0, 13, 13, 1, 149760, 0xca136846
+0, 14, 14, 1, 149760, 0xba22e581
+0, 15, 15, 1, 149760, 0x2844ddd3
+0, 16, 16, 1, 149760, 0xf943399e
diff --git a/tests/ref/fate/hevc-conformance-NUT_A_ericsson_4 b/tests/ref/fate/hevc-conformance-NUT_A_ericsson_4
new file mode 100644
index 0000000..fe65880
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-NUT_A_ericsson_4
@@ -0,0 +1,35 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8ce7200b
+0, 1, 1, 1, 149760, 0x73610669
+0, 2, 2, 1, 149760, 0x42942047
+0, 3, 3, 1, 149760, 0x57334d85
+0, 4, 4, 1, 149760, 0xdd97fbb3
+0, 5, 5, 1, 149760, 0x10469b12
+0, 6, 6, 1, 149760, 0x9b4231f0
+0, 7, 7, 1, 149760, 0x2b295a52
+0, 8, 8, 1, 149760, 0xdaf7c29f
+0, 9, 9, 1, 149760, 0x6798d072
+0, 10, 10, 1, 149760, 0xf77ae91e
+0, 11, 11, 1, 149760, 0xe2d516c9
+0, 12, 12, 1, 149760, 0x5cf0b221
+0, 13, 13, 1, 149760, 0x1d34991e
+0, 14, 14, 1, 149760, 0xb730d93a
+0, 15, 15, 1, 149760, 0x643b1861
+0, 16, 16, 1, 149760, 0x436586ff
+0, 17, 17, 1, 149760, 0xa65d9b80
+0, 18, 18, 1, 149760, 0x1d395210
+0, 19, 19, 1, 149760, 0x0580f2be
+0, 20, 20, 1, 149760, 0x8e4cea96
+0, 21, 21, 1, 149760, 0x6c98d019
+0, 22, 22, 1, 149760, 0x842803c8
+0, 23, 23, 1, 149760, 0xddc196ee
+0, 24, 24, 1, 149760, 0x89e45523
+0, 25, 25, 1, 149760, 0x2a36b008
+0, 26, 26, 1, 149760, 0x14a319f7
+0, 27, 27, 1, 149760, 0x7394854c
+0, 28, 28, 1, 149760, 0x26dcf933
+0, 29, 29, 1, 149760, 0x5b000b7e
+0, 30, 30, 1, 149760, 0x6e76bded
+0, 31, 31, 1, 149760, 0x0284d92d
+0, 32, 32, 1, 149760, 0xf14a25e0
+0, 33, 33, 1, 149760, 0x10c03d98
diff --git a/tests/ref/fate/hevc-conformance-PICSIZE_A_Bossen_1 b/tests/ref/fate/hevc-conformance-PICSIZE_A_Bossen_1
new file mode 100644
index 0000000..4c09ca5
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-PICSIZE_A_Bossen_1
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 13368960, 0x830b3a1d
+0, 1, 1, 1, 13368960, 0x120ca009
+0, 2, 2, 1, 13368960, 0xc94e0d86
+0, 3, 3, 1, 13368960, 0x3e97d237
+0, 4, 4, 1, 13368960, 0x1caaa873
+0, 5, 5, 1, 13368960, 0xc6af86c6
+0, 6, 6, 1, 13368960, 0x277ee61a
+0, 7, 7, 1, 13368960, 0x7832ef4e
+0, 8, 8, 1, 13368960, 0x328142e9
+0, 9, 9, 1, 13368960, 0xbe22f686
diff --git a/tests/ref/fate/hevc-conformance-PICSIZE_B_Bossen_1 b/tests/ref/fate/hevc-conformance-PICSIZE_B_Bossen_1
new file mode 100644
index 0000000..a3ab7c8
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-PICSIZE_B_Bossen_1
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 13368960, 0xe1e32c3d
+0, 1, 1, 1, 13368960, 0x75a503d3
+0, 2, 2, 1, 13368960, 0x71f33a0a
+0, 3, 3, 1, 13368960, 0xd9fe5306
+0, 4, 4, 1, 13368960, 0x2528926a
+0, 5, 5, 1, 13368960, 0x4ae4e500
+0, 6, 6, 1, 13368960, 0x01949c16
+0, 7, 7, 1, 13368960, 0x57b6ea2f
+0, 8, 8, 1, 13368960, 0xfd2b2055
+0, 9, 9, 1, 13368960, 0xc4246a9b
diff --git a/tests/ref/fate/hevc-conformance-PICSIZE_C_Bossen_1 b/tests/ref/fate/hevc-conformance-PICSIZE_C_Bossen_1
new file mode 100644
index 0000000..10520d1
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-PICSIZE_C_Bossen_1
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3339072, 0x28be238d
+0, 1, 1, 1, 3339072, 0x43b62aae
+0, 2, 2, 1, 3339072, 0x36259da6
+0, 3, 3, 1, 3339072, 0xd0dbbc1e
+0, 4, 4, 1, 3339072, 0x20df7c7c
+0, 5, 5, 1, 3339072, 0xb8872e77
+0, 6, 6, 1, 3339072, 0xceb4cce4
+0, 7, 7, 1, 3339072, 0x4ffa1dab
+0, 8, 8, 1, 3339072, 0x1c687703
+0, 9, 9, 1, 3339072, 0x5a0fa46f
diff --git a/tests/ref/fate/hevc-conformance-PICSIZE_D_Bossen_1 b/tests/ref/fate/hevc-conformance-PICSIZE_D_Bossen_1
new file mode 100644
index 0000000..6f1c4fb
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-PICSIZE_D_Bossen_1
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3339072, 0xcb16f53e
+0, 1, 1, 1, 3339072, 0x6f1da8ec
+0, 2, 2, 1, 3339072, 0x978dae98
+0, 3, 3, 1, 3339072, 0x34becc01
+0, 4, 4, 1, 3339072, 0x9c900137
+0, 5, 5, 1, 3339072, 0x02fe1d40
+0, 6, 6, 1, 3339072, 0xda9703b6
+0, 7, 7, 1, 3339072, 0x73e5ff5a
+0, 8, 8, 1, 3339072, 0xeec94fab
+0, 9, 9, 1, 3339072, 0xf4a36fc5
diff --git a/tests/ref/fate/hevc-conformance-PMERGE_A_TI_3 b/tests/ref/fate/hevc-conformance-PMERGE_A_TI_3
new file mode 100644
index 0000000..8491172
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-PMERGE_A_TI_3
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8edb27d7
+0, 1, 1, 1, 149760, 0x187419b5
+0, 2, 2, 1, 149760, 0x61100980
+0, 3, 3, 1, 149760, 0xd799123e
+0, 4, 4, 1, 149760, 0x9011c8d0
+0, 5, 5, 1, 149760, 0xeafe7d99
+0, 6, 6, 1, 149760, 0x94f32245
+0, 7, 7, 1, 149760, 0x8185910a
diff --git a/tests/ref/fate/hevc-conformance-PMERGE_B_TI_3 b/tests/ref/fate/hevc-conformance-PMERGE_B_TI_3
new file mode 100644
index 0000000..1f15a02
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-PMERGE_B_TI_3
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8edb27d7
+0, 1, 1, 1, 149760, 0xcebf1b76
+0, 2, 2, 1, 149760, 0x33930fb0
+0, 3, 3, 1, 149760, 0xb2933277
+0, 4, 4, 1, 149760, 0x2ff5fd5d
+0, 5, 5, 1, 149760, 0x6616a17a
+0, 6, 6, 1, 149760, 0x3abc48ad
+0, 7, 7, 1, 149760, 0xc12491ef
diff --git a/tests/ref/fate/hevc-conformance-PMERGE_C_TI_3 b/tests/ref/fate/hevc-conformance-PMERGE_C_TI_3
new file mode 100644
index 0000000..bf474cc
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-PMERGE_C_TI_3
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8edb27d7
+0, 1, 1, 1, 149760, 0x2c271a9b
+0, 2, 2, 1, 149760, 0x53e419f3
+0, 3, 3, 1, 149760, 0x96c92a29
+0, 4, 4, 1, 149760, 0x62d5e85b
+0, 5, 5, 1, 149760, 0xea307d47
+0, 6, 6, 1, 149760, 0x9cc40dec
+0, 7, 7, 1, 149760, 0x37d977fa
diff --git a/tests/ref/fate/hevc-conformance-PMERGE_D_TI_3 b/tests/ref/fate/hevc-conformance-PMERGE_D_TI_3
new file mode 100644
index 0000000..2af0e1f
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-PMERGE_D_TI_3
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8edb27d7
+0, 1, 1, 1, 149760, 0xf11a32ce
+0, 2, 2, 1, 149760, 0x0802237c
+0, 3, 3, 1, 149760, 0x366621a7
+0, 4, 4, 1, 149760, 0x89aacefd
+0, 5, 5, 1, 149760, 0xb3837d16
+0, 6, 6, 1, 149760, 0x5f822072
+0, 7, 7, 1, 149760, 0x24cb9377
diff --git a/tests/ref/fate/hevc-conformance-PMERGE_E_TI_3 b/tests/ref/fate/hevc-conformance-PMERGE_E_TI_3
new file mode 100644
index 0000000..df97237
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-PMERGE_E_TI_3
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8edb27d7
+0, 1, 1, 1, 149760, 0xea7b30bf
+0, 2, 2, 1, 149760, 0x273d092a
+0, 3, 3, 1, 149760, 0xef4e0ff0
+0, 4, 4, 1, 149760, 0x9805e02c
+0, 5, 5, 1, 149760, 0xdeb17cbc
+0, 6, 6, 1, 149760, 0xe5c903a4
+0, 7, 7, 1, 149760, 0x838d66b9
diff --git a/tests/ref/fate/hevc-conformance-POC_A_Bossen_3 b/tests/ref/fate/hevc-conformance-POC_A_Bossen_3
new file mode 100644
index 0000000..885d0e4
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-POC_A_Bossen_3
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xda17acd4
+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-PPS_A_qualcomm_7 b/tests/ref/fate/hevc-conformance-PPS_A_qualcomm_7
new file mode 100644
index 0000000..ef57f74
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-PPS_A_qualcomm_7
@@ -0,0 +1,82 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x87159328
+0, 1, 1, 1, 599040, 0x825672ff
+0, 2, 2, 1, 599040, 0x2f4224ff
+0, 3, 3, 1, 599040, 0x4be431ff
+0, 4, 4, 1, 599040, 0xa0118b14
+0, 5, 5, 1, 599040, 0x488aac33
+0, 6, 6, 1, 599040, 0x1edd0d4e
+0, 7, 7, 1, 599040, 0x7f4562a2
+0, 8, 8, 1, 599040, 0xe177a7d4
+0, 9, 9, 1, 599040, 0x32d2fd58
+0, 10, 10, 1, 599040, 0x81d50c36
+0, 11, 11, 1, 599040, 0xdf32810d
+0, 12, 12, 1, 599040, 0xc4f50543
+0, 13, 13, 1, 599040, 0x777bfdce
+0, 14, 14, 1, 599040, 0x01db8731
+0, 15, 15, 1, 599040, 0x74ae2b2c
+0, 16, 16, 1, 599040, 0x424e130a
+0, 17, 17, 1, 599040, 0x7002f7c8
+0, 18, 18, 1, 599040, 0xde098c5b
+0, 19, 19, 1, 599040, 0x072ca0e3
+0, 20, 20, 1, 599040, 0x6c50e3ba
+0, 21, 21, 1, 599040, 0xa398c530
+0, 22, 22, 1, 599040, 0xcd8a780a
+0, 23, 23, 1, 599040, 0x7c849e63
+0, 24, 24, 1, 599040, 0xb70e2a1f
+0, 25, 25, 1, 599040, 0xc00d893c
+0, 26, 26, 1, 599040, 0x5da32c94
+0, 27, 27, 1, 599040, 0xc3177b8c
+0, 28, 28, 1, 599040, 0x06668480
+0, 29, 29, 1, 599040, 0xbceeac78
+0, 30, 30, 1, 599040, 0x162d5cd1
+0, 31, 31, 1, 599040, 0x071b71c4
+0, 32, 32, 1, 599040, 0xfe61e0b2
+0, 33, 33, 1, 599040, 0xe78c121f
+0, 34, 34, 1, 599040, 0x3b47c051
+0, 35, 35, 1, 599040, 0x10c1eedd
+0, 36, 36, 1, 599040, 0x09cf2d2c
+0, 37, 37, 1, 599040, 0xc4272450
+0, 38, 38, 1, 599040, 0x3a9e0db7
+0, 39, 39, 1, 599040, 0xe62595ad
+0, 40, 40, 1, 599040, 0xc03669a5
+0, 41, 41, 1, 599040, 0x4fbb058e
+0, 42, 42, 1, 599040, 0xaaee8771
+0, 43, 43, 1, 599040, 0xcc4f3a71
+0, 44, 44, 1, 599040, 0xc5717c31
+0, 45, 45, 1, 599040, 0xe2bc02fc
+0, 46, 46, 1, 599040, 0x380e06eb
+0, 47, 47, 1, 599040, 0x15d4ba04
+0, 48, 48, 1, 599040, 0xb9204342
+0, 49, 49, 1, 599040, 0xb9d9a246
+0, 50, 50, 1, 599040, 0xb5611280
+0, 51, 51, 1, 599040, 0xc80e3909
+0, 52, 52, 1, 599040, 0xef93ecbd
+0, 53, 53, 1, 599040, 0xdd6b435e
+0, 54, 54, 1, 599040, 0x1622f253
+0, 55, 55, 1, 599040, 0x41cd55a6
+0, 56, 56, 1, 599040, 0x7ed864e7
+0, 57, 57, 1, 599040, 0x1604c563
+0, 58, 58, 1, 599040, 0x1d5a3dc9
+0, 59, 59, 1, 599040, 0xa904a8a5
+0, 60, 60, 1, 599040, 0x19c43226
+0, 61, 61, 1, 599040, 0x60d803e0
+0, 62, 62, 1, 599040, 0xe862b0e0
+0, 63, 63, 1, 599040, 0x37c76c51
+0, 64, 64, 1, 599040, 0x8528cc3c
+0, 65, 65, 1, 599040, 0x03ece1f9
+0, 66, 66, 1, 599040, 0x8f0ef28e
+0, 67, 67, 1, 599040, 0x92164007
+0, 68, 68, 1, 599040, 0x9d3c2ecf
+0, 69, 69, 1, 599040, 0xacf536d4
+0, 70, 70, 1, 599040, 0xbdf6165f
+0, 71, 71, 1, 599040, 0xbc19f80a
+0, 72, 72, 1, 599040, 0x128a6480
+0, 73, 73, 1, 599040, 0xb487c333
+0, 74, 74, 1, 599040, 0x8dc350fa
+0, 75, 75, 1, 599040, 0x0043fe96
+0, 76, 76, 1, 599040, 0x47b502a5
+0, 77, 77, 1, 599040, 0xf62b761f
+0, 78, 78, 1, 599040, 0x608f63c3
+0, 79, 79, 1, 599040, 0xe285d93d
+0, 80, 80, 1, 599040, 0x1c3404cf
diff --git a/tests/ref/fate/hevc-conformance-PS_A_VIDYO_3 b/tests/ref/fate/hevc-conformance-PS_A_VIDYO_3
new file mode 100644
index 0000000..8f7e5e6
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-PS_A_VIDYO_3
@@ -0,0 +1,26 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x88619f80
+0, 1, 1, 1, 149760, 0x550bdaf0
+0, 2, 2, 1, 149760, 0x4121f7a2
+0, 3, 3, 1, 149760, 0x210b1d07
+0, 4, 4, 1, 149760, 0x731b7758
+0, 5, 5, 1, 149760, 0x17adb789
+0, 6, 6, 1, 149760, 0x98b2f080
+0, 7, 7, 1, 149760, 0xc0be1f2a
+0, 8, 8, 1, 149760, 0xc01e387a
+0, 9, 9, 1, 149760, 0xd932822b
+0, 10, 10, 1, 149760, 0x16c0a1df
+0, 11, 11, 1, 149760, 0x5aa6c005
+0, 12, 12, 1, 149760, 0xd3aab602
+0, 13, 13, 1, 149760, 0x4e6ecab1
+0, 14, 14, 1, 149760, 0x8a86f1f2
+0, 15, 15, 1, 149760, 0x2ed21e1b
+0, 16, 16, 1, 149760, 0x80892f24
+0, 17, 17, 1, 149760, 0xb8a952ef
+0, 18, 18, 1, 149760, 0x557e57fb
+0, 19, 19, 1, 149760, 0x2b825b2c
+0, 20, 20, 1, 149760, 0x30b69b5e
+0, 21, 21, 1, 149760, 0x802ebf08
+0, 22, 22, 1, 149760, 0x95aadc8e
+0, 23, 23, 1, 149760, 0x4d4c02b7
+0, 24, 24, 1, 149760, 0x3fdd1762
diff --git a/tests/ref/fate/hevc-conformance-PS_B_VIDYO_3 b/tests/ref/fate/hevc-conformance-PS_B_VIDYO_3
new file mode 100644
index 0000000..8f7e5e6
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-PS_B_VIDYO_3
@@ -0,0 +1,26 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x88619f80
+0, 1, 1, 1, 149760, 0x550bdaf0
+0, 2, 2, 1, 149760, 0x4121f7a2
+0, 3, 3, 1, 149760, 0x210b1d07
+0, 4, 4, 1, 149760, 0x731b7758
+0, 5, 5, 1, 149760, 0x17adb789
+0, 6, 6, 1, 149760, 0x98b2f080
+0, 7, 7, 1, 149760, 0xc0be1f2a
+0, 8, 8, 1, 149760, 0xc01e387a
+0, 9, 9, 1, 149760, 0xd932822b
+0, 10, 10, 1, 149760, 0x16c0a1df
+0, 11, 11, 1, 149760, 0x5aa6c005
+0, 12, 12, 1, 149760, 0xd3aab602
+0, 13, 13, 1, 149760, 0x4e6ecab1
+0, 14, 14, 1, 149760, 0x8a86f1f2
+0, 15, 15, 1, 149760, 0x2ed21e1b
+0, 16, 16, 1, 149760, 0x80892f24
+0, 17, 17, 1, 149760, 0xb8a952ef
+0, 18, 18, 1, 149760, 0x557e57fb
+0, 19, 19, 1, 149760, 0x2b825b2c
+0, 20, 20, 1, 149760, 0x30b69b5e
+0, 21, 21, 1, 149760, 0x802ebf08
+0, 22, 22, 1, 149760, 0x95aadc8e
+0, 23, 23, 1, 149760, 0x4d4c02b7
+0, 24, 24, 1, 149760, 0x3fdd1762
diff --git a/tests/ref/fate/hevc-conformance-RAP_A_docomo_4 b/tests/ref/fate/hevc-conformance-RAP_A_docomo_4
new file mode 100644
index 0000000..268f4cd
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RAP_A_docomo_4
@@ -0,0 +1,87 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x1ae5f13d
+0, 1, 1, 1, 149760, 0x0a6ad0e3
+0, 2, 2, 1, 149760, 0x2415af05
+0, 3, 3, 1, 149760, 0xf50f6eef
+0, 4, 4, 1, 149760, 0xef65835c
+0, 5, 5, 1, 149760, 0x4929b5cb
+0, 6, 6, 1, 149760, 0x165c6f55
+0, 7, 7, 1, 149760, 0x9caaa249
+0, 8, 8, 1, 149760, 0x6c25c4cf
+0, 9, 9, 1, 149760, 0x4678cef0
+0, 10, 10, 1, 149760, 0x72e04433
+0, 11, 11, 1, 149760, 0x36f8aa9d
+0, 12, 12, 1, 149760, 0x255189ad
+0, 13, 13, 1, 149760, 0x712d7f7f
+0, 14, 14, 1, 149760, 0x4d088988
+0, 15, 15, 1, 149760, 0xc0da3925
+0, 16, 16, 1, 149760, 0x9990db7c
+0, 17, 17, 1, 149760, 0xb02cc0e8
+0, 18, 18, 1, 149760, 0x3e859d8f
+0, 19, 19, 1, 149760, 0xce786bc1
+0, 20, 20, 1, 149760, 0x87555e5f
+0, 21, 21, 1, 149760, 0x3c95fb7e
+0, 22, 22, 1, 149760, 0xf092b65e
+0, 23, 23, 1, 149760, 0x7db2c04c
+0, 24, 24, 1, 149760, 0x7d39eb21
+0, 25, 25, 1, 149760, 0x2cfd7d57
+0, 26, 26, 1, 149760, 0xb1902c06
+0, 27, 27, 1, 149760, 0xe0eae1d7
+0, 28, 28, 1, 149760, 0xf8212977
+0, 29, 29, 1, 149760, 0x6cb31328
+0, 30, 30, 1, 149760, 0x862ab736
+0, 31, 31, 1, 149760, 0xc7a87f44
+0, 32, 32, 1, 149760, 0x8ff7a1a1
+0, 33, 33, 1, 149760, 0xd7bee49b
+0, 34, 34, 1, 149760, 0x1925db84
+0, 35, 35, 1, 149760, 0xf32a7dc6
+0, 36, 36, 1, 149760, 0x02a1e3b6
+0, 37, 37, 1, 149760, 0xb6398aad
+0, 38, 38, 1, 149760, 0xa3756e2d
+0, 39, 39, 1, 149760, 0xf90f3732
+0, 40, 40, 1, 149760, 0x3b05115a
+0, 41, 41, 1, 149760, 0x81ca9bdb
+0, 42, 42, 1, 149760, 0xa75ee938
+0, 43, 43, 1, 149760, 0x9e5c232f
+0, 44, 44, 1, 149760, 0x64cb04e9
+0, 45, 45, 1, 149760, 0x4064df52
+0, 46, 46, 1, 149760, 0x47fa0afc
+0, 47, 47, 1, 149760, 0xd209252e
+0, 48, 48, 1, 149760, 0x2f811f02
+0, 49, 49, 1, 149760, 0x733b6721
+0, 50, 50, 1, 149760, 0x30b12427
+0, 51, 51, 1, 149760, 0xdf58d3e2
+0, 52, 52, 1, 149760, 0xc144d7be
+0, 53, 53, 1, 149760, 0x48f0ac79
+0, 54, 54, 1, 149760, 0xb8d8a2c6
+0, 55, 55, 1, 149760, 0x2a7d916d
+0, 56, 56, 1, 149760, 0xd9d38cd5
+0, 57, 57, 1, 149760, 0xd7c7f9a6
+0, 58, 58, 1, 149760, 0x64d0df7a
+0, 59, 59, 1, 149760, 0x4e365cff
+0, 60, 60, 1, 149760, 0x74bc2a8b
+0, 61, 61, 1, 149760, 0x70a7cd2b
+0, 62, 62, 1, 149760, 0x0836b51e
+0, 63, 63, 1, 149760, 0xbc37b5d7
+0, 64, 64, 1, 149760, 0xb6d651e5
+0, 65, 65, 1, 149760, 0x7aa0e35f
+0, 66, 66, 1, 149760, 0x0fbc89a3
+0, 67, 67, 1, 149760, 0x2ca2f2a6
+0, 68, 68, 1, 149760, 0xf742c5c5
+0, 69, 69, 1, 149760, 0x4117208f
+0, 70, 70, 1, 149760, 0xec392efb
+0, 71, 71, 1, 149760, 0xbfba5063
+0, 72, 72, 1, 149760, 0xb2499f48
+0, 73, 73, 1, 149760, 0xf1183244
+0, 74, 74, 1, 149760, 0x364a6400
+0, 75, 75, 1, 149760, 0xfcfddf36
+0, 76, 76, 1, 149760, 0xbcc1b37e
+0, 77, 77, 1, 149760, 0xab364748
+0, 78, 78, 1, 149760, 0xebb27fcd
+0, 79, 79, 1, 149760, 0xe2e7a723
+0, 80, 80, 1, 149760, 0xf671b5e0
+0, 81, 81, 1, 149760, 0xbf0cc349
+0, 82, 82, 1, 149760, 0xf195d868
+0, 83, 83, 1, 149760, 0xe0097460
+0, 84, 84, 1, 149760, 0x3d4c1812
+0, 85, 85, 1, 149760, 0x133cd867
diff --git a/tests/ref/fate/hevc-conformance-RAP_B_Bossen_1 b/tests/ref/fate/hevc-conformance-RAP_B_Bossen_1
new file mode 100644
index 0000000..4bea997
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RAP_B_Bossen_1
@@ -0,0 +1,84 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xb989ae7a
+0, 1, 1, 1, 149760, 0x4765caed
+0, 2, 2, 1, 149760, 0xd908c148
+0, 3, 3, 1, 149760, 0xf6ebd66c
+0, 4, 4, 1, 149760, 0x5d5ea14b
+0, 5, 5, 1, 149760, 0xcc939a7c
+0, 6, 6, 1, 149760, 0xa91b8243
+0, 7, 7, 1, 149760, 0x61926618
+0, 8, 8, 1, 149760, 0xe440099c
+0, 9, 9, 1, 149760, 0x18b88a73
+0, 10, 10, 1, 149760, 0xa669f2a9
+0, 11, 11, 1, 149760, 0xc2f6af3a
+0, 12, 12, 1, 149760, 0x02465354
+0, 13, 13, 1, 149760, 0x54e51ff9
+0, 14, 14, 1, 149760, 0xb9f3c056
+0, 15, 15, 1, 149760, 0x050274f9
+0, 16, 16, 1, 149760, 0xd7a413c1
+0, 17, 17, 1, 149760, 0x6e92cda4
+0, 18, 18, 1, 149760, 0x9cb86d4d
+0, 19, 19, 1, 149760, 0x95f440a3
+0, 20, 20, 1, 149760, 0x6dabd616
+0, 21, 21, 1, 149760, 0xd6a0b62d
+0, 22, 22, 1, 149760, 0x585c811b
+0, 23, 23, 1, 149760, 0x50a4d6fc
+0, 24, 24, 1, 149760, 0xe419eb23
+0, 25, 25, 1, 149760, 0x1f0fc316
+0, 26, 26, 1, 149760, 0xf61dc981
+0, 27, 27, 1, 149760, 0xff34d001
+0, 28, 28, 1, 149760, 0x598be76c
+0, 29, 29, 1, 149760, 0xbb50a4d6
+0, 30, 30, 1, 149760, 0x2add9abd
+0, 31, 31, 1, 149760, 0xd74185c7
+0, 32, 32, 1, 149760, 0xcdad6e8e
+0, 33, 33, 1, 149760, 0x54d704ad
+0, 34, 34, 1, 149760, 0xe52e7fc0
+0, 35, 35, 1, 149760, 0xdb331061
+0, 36, 36, 1, 149760, 0x7dacb973
+0, 37, 37, 1, 149760, 0xfc8d5670
+0, 38, 38, 1, 149760, 0xca9024cd
+0, 39, 39, 1, 149760, 0x7fc9bbc2
+0, 40, 40, 1, 149760, 0xe9c386a9
+0, 41, 41, 1, 149760, 0xd0dd1a21
+0, 42, 42, 1, 149760, 0x4b57d734
+0, 43, 43, 1, 149760, 0x55607afc
+0, 44, 44, 1, 149760, 0x567c3e8b
+0, 45, 45, 1, 149760, 0x312eda16
+0, 46, 46, 1, 149760, 0xafcbacf8
+0, 47, 47, 1, 149760, 0xcbde8420
+0, 48, 48, 1, 149760, 0x88a2f29e
+0, 49, 49, 1, 149760, 0x417bf220
+0, 50, 50, 1, 149760, 0xa454835a
+0, 51, 51, 1, 149760, 0x16bf2871
+0, 52, 52, 1, 149760, 0x51253402
+0, 53, 53, 1, 149760, 0x13822dfd
+0, 54, 54, 1, 149760, 0x5e099d3d
+0, 55, 55, 1, 149760, 0xcc19fe87
+0, 56, 56, 1, 149760, 0x7f5f6ce2
+0, 57, 57, 1, 149760, 0x79797a94
+0, 58, 58, 1, 149760, 0x16f26086
+0, 59, 59, 1, 149760, 0x01aedea3
+0, 60, 60, 1, 149760, 0xcafd3221
+0, 61, 61, 1, 149760, 0xcbd61c1f
+0, 62, 62, 1, 149760, 0xf46839e5
+0, 63, 63, 1, 149760, 0x87fb61ee
+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
diff --git a/tests/ref/fate/hevc-conformance-RPLM_A_qualcomm_4 b/tests/ref/fate/hevc-conformance-RPLM_A_qualcomm_4
new file mode 100644
index 0000000..372d120
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RPLM_A_qualcomm_4
@@ -0,0 +1,301 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xdb5e3b56
+0, 1, 1, 1, 149760, 0xd5320970
+0, 2, 2, 1, 149760, 0x9387ed18
+0, 3, 3, 1, 149760, 0x3ab6fde8
+0, 4, 4, 1, 149760, 0xf5d39a39
+0, 5, 5, 1, 149760, 0xf8c15b34
+0, 6, 6, 1, 149760, 0x12261fdc
+0, 7, 7, 1, 149760, 0x8ed03f57
+0, 8, 8, 1, 149760, 0x04d29f74
+0, 9, 9, 1, 149760, 0x86daf75e
+0, 10, 10, 1, 149760, 0x85d817a4
+0, 11, 11, 1, 149760, 0xf9c97006
+0, 12, 12, 1, 149760, 0x60baf6ad
+0, 13, 13, 1, 149760, 0x7272aa6b
+0, 14, 14, 1, 149760, 0x18e00ede
+0, 15, 15, 1, 149760, 0x60592cfe
+0, 16, 16, 1, 149760, 0x7d49650d
+0, 17, 17, 1, 149760, 0x865e7b22
+0, 18, 18, 1, 149760, 0xad6a33e4
+0, 19, 19, 1, 149760, 0x7c8ab573
+0, 20, 20, 1, 149760, 0x0c7d8afa
+0, 21, 21, 1, 149760, 0xb0e567a3
+0, 22, 22, 1, 149760, 0x3c2ccbf1
+0, 23, 23, 1, 149760, 0x0804aead
+0, 24, 24, 1, 149760, 0x0dcb6756
+0, 25, 25, 1, 149760, 0x99bc82dd
+0, 26, 26, 1, 149760, 0x4d2907f1
+0, 27, 27, 1, 149760, 0xc4c330ff
+0, 28, 28, 1, 149760, 0x6c73cef4
+0, 29, 29, 1, 149760, 0xbaa82ab1
+0, 30, 30, 1, 149760, 0xeea3d591
+0, 31, 31, 1, 149760, 0x8240d007
+0, 32, 32, 1, 149760, 0x698f11e4
+0, 33, 33, 1, 149760, 0x46700948
+0, 34, 34, 1, 149760, 0x819e62d9
+0, 35, 35, 1, 149760, 0x0cfe1471
+0, 36, 36, 1, 149760, 0xf30dc9da
+0, 37, 37, 1, 149760, 0x81ea3390
+0, 38, 38, 1, 149760, 0x85bc8dec
+0, 39, 39, 1, 149760, 0x01d3451a
+0, 40, 40, 1, 149760, 0x626dc94b
+0, 41, 41, 1, 149760, 0xf50f2a66
+0, 42, 42, 1, 149760, 0x6294bc3e
+0, 43, 43, 1, 149760, 0x41427bc1
+0, 44, 44, 1, 149760, 0xe200ecf3
+0, 45, 45, 1, 149760, 0xc44785c5
+0, 46, 46, 1, 149760, 0xadc8c3cf
+0, 47, 47, 1, 149760, 0x6c57fb6d
+0, 48, 48, 1, 149760, 0x139cddc1
+0, 49, 49, 1, 149760, 0xc5c9def6
+0, 50, 50, 1, 149760, 0xa8da3f7b
+0, 51, 51, 1, 149760, 0x21823d13
+0, 52, 52, 1, 149760, 0x00e265fd
+0, 53, 53, 1, 149760, 0x289f21d2
+0, 54, 54, 1, 149760, 0xa96d8d0b
+0, 55, 55, 1, 149760, 0x4e50b434
+0, 56, 56, 1, 149760, 0x4e469eae
+0, 57, 57, 1, 149760, 0x62a258af
+0, 58, 58, 1, 149760, 0xc61beb2b
+0, 59, 59, 1, 149760, 0x15d7853b
+0, 60, 60, 1, 149760, 0xd5b8941b
+0, 61, 61, 1, 149760, 0x6312a7c5
+0, 62, 62, 1, 149760, 0x2da74d59
+0, 63, 63, 1, 149760, 0x5fd72bc7
+0, 64, 64, 1, 149760, 0x4035f027
+0, 65, 65, 1, 149760, 0xbe9992e2
+0, 66, 66, 1, 149760, 0xb96093b8
+0, 67, 67, 1, 149760, 0x1024bd43
+0, 68, 68, 1, 149760, 0x1376a3fe
+0, 69, 69, 1, 149760, 0xdf93ec7f
+0, 70, 70, 1, 149760, 0x17d27bfa
+0, 71, 71, 1, 149760, 0x440cb7aa
+0, 72, 72, 1, 149760, 0x8b230df3
+0, 73, 73, 1, 149760, 0x2526130e
+0, 74, 74, 1, 149760, 0x77926a77
+0, 75, 75, 1, 149760, 0x8562bddc
+0, 76, 76, 1, 149760, 0xda86bb2e
+0, 77, 77, 1, 149760, 0x2b4f921b
+0, 78, 78, 1, 149760, 0xf13bca77
+0, 79, 79, 1, 149760, 0x53e76b99
+0, 80, 80, 1, 149760, 0x29a2f5bb
+0, 81, 81, 1, 149760, 0x83a8c4f8
+0, 82, 82, 1, 149760, 0xbe6d8f45
+0, 83, 83, 1, 149760, 0x03d3bf96
+0, 84, 84, 1, 149760, 0x3a0bd29e
+0, 85, 85, 1, 149760, 0xdb656a22
+0, 86, 86, 1, 149760, 0x557b020e
+0, 87, 87, 1, 149760, 0x573ee5f2
+0, 88, 88, 1, 149760, 0x5484faea
+0, 89, 89, 1, 149760, 0x06bb73ae
+0, 90, 90, 1, 149760, 0x3d4049fa
+0, 91, 91, 1, 149760, 0xe574eedb
+0, 92, 92, 1, 149760, 0x1c46205d
+0, 93, 93, 1, 149760, 0x0c5c322e
+0, 94, 94, 1, 149760, 0x2bbeed95
+0, 95, 95, 1, 149760, 0x225897dc
+0, 96, 96, 1, 149760, 0x0a39aa8b
+0, 97, 97, 1, 149760, 0x3242e156
+0, 98, 98, 1, 149760, 0x1790ee85
+0, 99, 99, 1, 149760, 0x55ef9dac
+0, 100, 100, 1, 149760, 0x98e1c49e
+0, 101, 101, 1, 149760, 0x479a84b5
+0, 102, 102, 1, 149760, 0x1711b4f9
+0, 103, 103, 1, 149760, 0xd7d25fce
+0, 104, 104, 1, 149760, 0x7bde1977
+0, 105, 105, 1, 149760, 0x25777a4d
+0, 106, 106, 1, 149760, 0x7b55ed5f
+0, 107, 107, 1, 149760, 0xb28e59e6
+0, 108, 108, 1, 149760, 0x8314281a
+0, 109, 109, 1, 149760, 0x3a5ceeb3
+0, 110, 110, 1, 149760, 0x33760ed8
+0, 111, 111, 1, 149760, 0x19332370
+0, 112, 112, 1, 149760, 0xf25d1f68
+0, 113, 113, 1, 149760, 0x4d665712
+0, 114, 114, 1, 149760, 0x3e310eb7
+0, 115, 115, 1, 149760, 0xafa3c1bb
+0, 116, 116, 1, 149760, 0xf0b7a7ec
+0, 117, 117, 1, 149760, 0xa88a747a
+0, 118, 118, 1, 149760, 0x7b7e6e85
+0, 119, 119, 1, 149760, 0xbc8f8ede
+0, 120, 120, 1, 149760, 0x449f7d2f
+0, 121, 121, 1, 149760, 0x9bc70c53
+0, 122, 122, 1, 149760, 0x8544dc98
+0, 123, 123, 1, 149760, 0xef687641
+0, 124, 124, 1, 149760, 0x0c962219
+0, 125, 125, 1, 149760, 0x4325ae76
+0, 126, 126, 1, 149760, 0xcec7a18c
+0, 127, 127, 1, 149760, 0x941ee8a2
+0, 128, 128, 1, 149760, 0x3eaf3f55
+0, 129, 129, 1, 149760, 0x5b571274
+0, 130, 130, 1, 149760, 0x0532488a
+0, 131, 131, 1, 149760, 0x893fbaf7
+0, 132, 132, 1, 149760, 0xd0155ddf
+0, 133, 133, 1, 149760, 0x83ec86ee
+0, 134, 134, 1, 149760, 0xedffba86
+0, 135, 135, 1, 149760, 0x838c19de
+0, 136, 136, 1, 149760, 0x8482639d
+0, 137, 137, 1, 149760, 0x9501004d
+0, 138, 138, 1, 149760, 0x1db0525f
+0, 139, 139, 1, 149760, 0x8b431467
+0, 140, 140, 1, 149760, 0x972e7d24
+0, 141, 141, 1, 149760, 0xd8151b94
+0, 142, 142, 1, 149760, 0x1ded6a85
+0, 143, 143, 1, 149760, 0x03497fe2
+0, 144, 144, 1, 149760, 0x07427bb7
+0, 145, 145, 1, 149760, 0x33c085ef
+0, 146, 146, 1, 149760, 0x0feda1d0
+0, 147, 147, 1, 149760, 0xf86930e7
+0, 148, 148, 1, 149760, 0x42c2ea09
+0, 149, 149, 1, 149760, 0xcfb76b86
+0, 150, 150, 1, 149760, 0x672e2fce
+0, 151, 151, 1, 149760, 0xb006ec79
+0, 152, 152, 1, 149760, 0xdbc8511c
+0, 153, 153, 1, 149760, 0x3278b299
+0, 154, 154, 1, 149760, 0xd19fe063
+0, 155, 155, 1, 149760, 0x13bb8951
+0, 156, 156, 1, 149760, 0xec5cfe36
+0, 157, 157, 1, 149760, 0x9381a0e7
+0, 158, 158, 1, 149760, 0x304cf3c0
+0, 159, 159, 1, 149760, 0xd380511c
+0, 160, 160, 1, 149760, 0xbd1abe11
+0, 161, 161, 1, 149760, 0x7b220293
+0, 162, 162, 1, 149760, 0xbbe85931
+0, 163, 163, 1, 149760, 0x316e422a
+0, 164, 164, 1, 149760, 0x5e5db530
+0, 165, 165, 1, 149760, 0xc48d6ddb
+0, 166, 166, 1, 149760, 0x9adf5d65
+0, 167, 167, 1, 149760, 0x2adb94de
+0, 168, 168, 1, 149760, 0xbc052746
+0, 169, 169, 1, 149760, 0xac4d3569
+0, 170, 170, 1, 149760, 0x3cd8fdee
+0, 171, 171, 1, 149760, 0x34bfd6ed
+0, 172, 172, 1, 149760, 0xf72fec4b
+0, 173, 173, 1, 149760, 0xf8c5b374
+0, 174, 174, 1, 149760, 0x28ff7382
+0, 175, 175, 1, 149760, 0xac3b49f4
+0, 176, 176, 1, 149760, 0x9d995a62
+0, 177, 177, 1, 149760, 0xe0b292f1
+0, 178, 178, 1, 149760, 0x4edbd05d
+0, 179, 179, 1, 149760, 0x4fd5038b
+0, 180, 180, 1, 149760, 0x899d2101
+0, 181, 181, 1, 149760, 0x0733f804
+0, 182, 182, 1, 149760, 0xe4297100
+0, 183, 183, 1, 149760, 0x5aff9292
+0, 184, 184, 1, 149760, 0x41eda25c
+0, 185, 185, 1, 149760, 0xb4d7aaf2
+0, 186, 186, 1, 149760, 0xbd99fade
+0, 187, 187, 1, 149760, 0xdea6d265
+0, 188, 188, 1, 149760, 0xa2d3bdcd
+0, 189, 189, 1, 149760, 0x38f8a729
+0, 190, 190, 1, 149760, 0x0a356f1b
+0, 191, 191, 1, 149760, 0x865411a5
+0, 192, 192, 1, 149760, 0xd6720a40
+0, 193, 193, 1, 149760, 0xf40589f9
+0, 194, 194, 1, 149760, 0x0646106d
+0, 195, 195, 1, 149760, 0x88e55688
+0, 196, 196, 1, 149760, 0xda2fce82
+0, 197, 197, 1, 149760, 0xc823200b
+0, 198, 198, 1, 149760, 0xc9513041
+0, 199, 199, 1, 149760, 0x798d0e88
+0, 200, 200, 1, 149760, 0xb6d4f15a
+0, 201, 201, 1, 149760, 0xab5b24a4
+0, 202, 202, 1, 149760, 0x9888aa8d
+0, 203, 203, 1, 149760, 0xbf13bbf4
+0, 204, 204, 1, 149760, 0x5450bb23
+0, 205, 205, 1, 149760, 0x12aec398
+0, 206, 206, 1, 149760, 0xa5e1579a
+0, 207, 207, 1, 149760, 0xbeeb07e1
+0, 208, 208, 1, 149760, 0x209a9f1b
+0, 209, 209, 1, 149760, 0x4d3d1c1a
+0, 210, 210, 1, 149760, 0xb4edd703
+0, 211, 211, 1, 149760, 0xc71adf66
+0, 212, 212, 1, 149760, 0x40006d36
+0, 213, 213, 1, 149760, 0x1c5485c9
+0, 214, 214, 1, 149760, 0xa3d8c9a1
+0, 215, 215, 1, 149760, 0x9bfac6de
+0, 216, 216, 1, 149760, 0xed3b0782
+0, 217, 217, 1, 149760, 0x8f075ce2
+0, 218, 218, 1, 149760, 0xb744fa07
+0, 219, 219, 1, 149760, 0xa9356722
+0, 220, 220, 1, 149760, 0xd792bd01
+0, 221, 221, 1, 149760, 0xa124618b
+0, 222, 222, 1, 149760, 0x7492bb54
+0, 223, 223, 1, 149760, 0x67dcefca
+0, 224, 224, 1, 149760, 0x8a7f716d
+0, 225, 225, 1, 149760, 0x7775bb01
+0, 226, 226, 1, 149760, 0xe4a845e5
+0, 227, 227, 1, 149760, 0x79a3962d
+0, 228, 228, 1, 149760, 0x4f395ad7
+0, 229, 229, 1, 149760, 0x3948ce05
+0, 230, 230, 1, 149760, 0x037e6c07
+0, 231, 231, 1, 149760, 0x91881ae9
+0, 232, 232, 1, 149760, 0x937e2545
+0, 233, 233, 1, 149760, 0xdc892763
+0, 234, 234, 1, 149760, 0x96ebd47f
+0, 235, 235, 1, 149760, 0xfecbf8c6
+0, 236, 236, 1, 149760, 0xe1443808
+0, 237, 237, 1, 149760, 0xe0cd36c0
+0, 238, 238, 1, 149760, 0xb485eb4d
+0, 239, 239, 1, 149760, 0x36edf31f
+0, 240, 240, 1, 149760, 0x988bb97f
+0, 241, 241, 1, 149760, 0xc266c616
+0, 242, 242, 1, 149760, 0x7ec4c3f4
+0, 243, 243, 1, 149760, 0xedf5e2ff
+0, 244, 244, 1, 149760, 0xbdd351e3
+0, 245, 245, 1, 149760, 0x900e194e
+0, 246, 246, 1, 149760, 0x5dc7daad
+0, 247, 247, 1, 149760, 0x1ce37e7e
+0, 248, 248, 1, 149760, 0x15982333
+0, 249, 249, 1, 149760, 0x976bb72e
+0, 250, 250, 1, 149760, 0x0b42e05e
+0, 251, 251, 1, 149760, 0xffbcc758
+0, 252, 252, 1, 149760, 0x6377782d
+0, 253, 253, 1, 149760, 0x8aa42a80
+0, 254, 254, 1, 149760, 0x8e0ab3fd
+0, 255, 255, 1, 149760, 0xdfdd49d4
+0, 256, 256, 1, 149760, 0x2659a6cb
+0, 257, 257, 1, 149760, 0x1e9a3d51
+0, 258, 258, 1, 149760, 0x7a66d80d
+0, 259, 259, 1, 149760, 0x5756a9e9
+0, 260, 260, 1, 149760, 0x0fa8d6dd
+0, 261, 261, 1, 149760, 0x885799a5
+0, 262, 262, 1, 149760, 0xb8d02df7
+0, 263, 263, 1, 149760, 0xd2e2800c
+0, 264, 264, 1, 149760, 0xa26ee27a
+0, 265, 265, 1, 149760, 0x7c86750f
+0, 266, 266, 1, 149760, 0xb4694ea1
+0, 267, 267, 1, 149760, 0x89d0b75a
+0, 268, 268, 1, 149760, 0x92b9af80
+0, 269, 269, 1, 149760, 0x107dd610
+0, 270, 270, 1, 149760, 0x8ad35f55
+0, 271, 271, 1, 149760, 0xccc32cb1
+0, 272, 272, 1, 149760, 0xd08ce4ff
+0, 273, 273, 1, 149760, 0x30bd8d0a
+0, 274, 274, 1, 149760, 0x01b74d14
+0, 275, 275, 1, 149760, 0x79aa7a3b
+0, 276, 276, 1, 149760, 0x5f7a40fc
+0, 277, 277, 1, 149760, 0x8837643e
+0, 278, 278, 1, 149760, 0xb6b66baa
+0, 279, 279, 1, 149760, 0xf4ae17cd
+0, 280, 280, 1, 149760, 0xe0d2546a
+0, 281, 281, 1, 149760, 0x0e118751
+0, 282, 282, 1, 149760, 0x0732e19c
+0, 283, 283, 1, 149760, 0x9cfe27b3
+0, 284, 284, 1, 149760, 0x1c77b242
+0, 285, 285, 1, 149760, 0x25be3938
+0, 286, 286, 1, 149760, 0x735ce859
+0, 287, 287, 1, 149760, 0x2bca0f6e
+0, 288, 288, 1, 149760, 0xcce3eb48
+0, 289, 289, 1, 149760, 0xf3556dd8
+0, 290, 290, 1, 149760, 0xcb2cecb4
+0, 291, 291, 1, 149760, 0x9c489742
+0, 292, 292, 1, 149760, 0xbe25370d
+0, 293, 293, 1, 149760, 0x798ff17f
+0, 294, 294, 1, 149760, 0x2f1a46c4
+0, 295, 295, 1, 149760, 0x7d119bd6
+0, 296, 296, 1, 149760, 0x42ceab74
+0, 297, 297, 1, 149760, 0x6fcbe2ef
+0, 298, 298, 1, 149760, 0x290fe6da
+0, 299, 299, 1, 149760, 0x6b280a24
diff --git a/tests/ref/fate/hevc-conformance-RPLM_B_qualcomm_4 b/tests/ref/fate/hevc-conformance-RPLM_B_qualcomm_4
new file mode 100644
index 0000000..a34dcc0
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RPLM_B_qualcomm_4
@@ -0,0 +1,301 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x82ff0cca
+0, 1, 1, 1, 149760, 0xcd05ba17
+0, 2, 2, 1, 149760, 0x33a5b924
+0, 3, 3, 1, 149760, 0xc0a8d82f
+0, 4, 4, 1, 149760, 0xa18c8ce6
+0, 5, 5, 1, 149760, 0x4d3c4902
+0, 6, 6, 1, 149760, 0xf118cb2a
+0, 7, 7, 1, 149760, 0xb37643c0
+0, 8, 8, 1, 149760, 0x0d6f8a70
+0, 9, 9, 1, 149760, 0xeaebd0f0
+0, 10, 10, 1, 149760, 0x81cce277
+0, 11, 11, 1, 149760, 0x85f216cc
+0, 12, 12, 1, 149760, 0x799cc7c7
+0, 13, 13, 1, 149760, 0x575f76da
+0, 14, 14, 1, 149760, 0x79e10395
+0, 15, 15, 1, 149760, 0x80f62423
+0, 16, 16, 1, 149760, 0x13657087
+0, 17, 17, 1, 149760, 0xcd147ae1
+0, 18, 18, 1, 149760, 0xcee71159
+0, 19, 19, 1, 149760, 0x6fa7b8d5
+0, 20, 20, 1, 149760, 0xd90bd038
+0, 21, 21, 1, 149760, 0x13eead73
+0, 22, 22, 1, 149760, 0xe2eddfc8
+0, 23, 23, 1, 149760, 0x1f07a4f6
+0, 24, 24, 1, 149760, 0x90b25f59
+0, 25, 25, 1, 149760, 0xd0dd86ba
+0, 26, 26, 1, 149760, 0x3008066c
+0, 27, 27, 1, 149760, 0x74ec54dd
+0, 28, 28, 1, 149760, 0xa423046c
+0, 29, 29, 1, 149760, 0x8a410bca
+0, 30, 30, 1, 149760, 0x55337573
+0, 31, 31, 1, 149760, 0x55d3623c
+0, 32, 32, 1, 149760, 0x699d234b
+0, 33, 33, 1, 149760, 0xbcd029b6
+0, 34, 34, 1, 149760, 0xa56e6600
+0, 35, 35, 1, 149760, 0x1dfc4a28
+0, 36, 36, 1, 149760, 0x9a72d671
+0, 37, 37, 1, 149760, 0xc01812ae
+0, 38, 38, 1, 149760, 0x8ef428c2
+0, 39, 39, 1, 149760, 0x6e79de92
+0, 40, 40, 1, 149760, 0xf315ba7c
+0, 41, 41, 1, 149760, 0xa678caff
+0, 42, 42, 1, 149760, 0xbd2049c0
+0, 43, 43, 1, 149760, 0x649323ea
+0, 44, 44, 1, 149760, 0x686eb3a4
+0, 45, 45, 1, 149760, 0x89725136
+0, 46, 46, 1, 149760, 0xc4db7e6f
+0, 47, 47, 1, 149760, 0xf6f0d823
+0, 48, 48, 1, 149760, 0x44b3a07a
+0, 49, 49, 1, 149760, 0xf23c221d
+0, 50, 50, 1, 149760, 0x858f11ef
+0, 51, 51, 1, 149760, 0xcd5311c4
+0, 52, 52, 1, 149760, 0x72c9297d
+0, 53, 53, 1, 149760, 0xf6acd772
+0, 54, 54, 1, 149760, 0x8c0f91ed
+0, 55, 55, 1, 149760, 0x7ef6f2be
+0, 56, 56, 1, 149760, 0x1237a677
+0, 57, 57, 1, 149760, 0x66e461f9
+0, 58, 58, 1, 149760, 0x3e06e1b3
+0, 59, 59, 1, 149760, 0xa6f6065c
+0, 60, 60, 1, 149760, 0x16e38cc0
+0, 61, 61, 1, 149760, 0x05762de1
+0, 62, 62, 1, 149760, 0xbda617c5
+0, 63, 63, 1, 149760, 0x75b904a9
+0, 64, 64, 1, 149760, 0x2f8bf179
+0, 65, 65, 1, 149760, 0x9be6a533
+0, 66, 66, 1, 149760, 0xf4eb99e8
+0, 67, 67, 1, 149760, 0xf3a68b9a
+0, 68, 68, 1, 149760, 0x34b86f19
+0, 69, 69, 1, 149760, 0x6a71cc04
+0, 70, 70, 1, 149760, 0xe206a202
+0, 71, 71, 1, 149760, 0xdfa8dea6
+0, 72, 72, 1, 149760, 0x8ef7fb73
+0, 73, 73, 1, 149760, 0x67a8de32
+0, 74, 74, 1, 149760, 0xc8c16870
+0, 75, 75, 1, 149760, 0xf5e5d04d
+0, 76, 76, 1, 149760, 0x79d0cc8d
+0, 77, 77, 1, 149760, 0xcd80a22b
+0, 78, 78, 1, 149760, 0x12dce452
+0, 79, 79, 1, 149760, 0x0586aa3d
+0, 80, 80, 1, 149760, 0x5a4d0c1e
+0, 81, 81, 1, 149760, 0x25dbe94e
+0, 82, 82, 1, 149760, 0x3236bbe8
+0, 83, 83, 1, 149760, 0x3b4bc068
+0, 84, 84, 1, 149760, 0x3f32c299
+0, 85, 85, 1, 149760, 0x5b0738e5
+0, 86, 86, 1, 149760, 0x0c1d0c80
+0, 87, 87, 1, 149760, 0x76ace6f5
+0, 88, 88, 1, 149760, 0xc738ff39
+0, 89, 89, 1, 149760, 0x0f078335
+0, 90, 90, 1, 149760, 0x0e941631
+0, 91, 91, 1, 149760, 0x284ee7d6
+0, 92, 92, 1, 149760, 0xce9b49b8
+0, 93, 93, 1, 149760, 0x7c132570
+0, 94, 94, 1, 149760, 0xa983dc5e
+0, 95, 95, 1, 149760, 0x994e4d69
+0, 96, 96, 1, 149760, 0xb8f599ed
+0, 97, 97, 1, 149760, 0xee81b454
+0, 98, 98, 1, 149760, 0xf27bdeee
+0, 99, 99, 1, 149760, 0xc7628895
+0, 100, 100, 1, 149760, 0x003521d1
+0, 101, 101, 1, 149760, 0x7ed9b167
+0, 102, 102, 1, 149760, 0x47598b95
+0, 103, 103, 1, 149760, 0x879b347e
+0, 104, 104, 1, 149760, 0x55f8f8c1
+0, 105, 105, 1, 149760, 0xdddc5dda
+0, 106, 106, 1, 149760, 0xc531c9a1
+0, 107, 107, 1, 149760, 0x28ef0e7e
+0, 108, 108, 1, 149760, 0x4c090cbd
+0, 109, 109, 1, 149760, 0x5818f270
+0, 110, 110, 1, 149760, 0x89ea1f0e
+0, 111, 111, 1, 149760, 0x263925ef
+0, 112, 112, 1, 149760, 0x4e7d45b8
+0, 113, 113, 1, 149760, 0xa98dbf77
+0, 114, 114, 1, 149760, 0xaa0239b3
+0, 115, 115, 1, 149760, 0x4eaa2226
+0, 116, 116, 1, 149760, 0x9927c7f9
+0, 117, 117, 1, 149760, 0x17f09e34
+0, 118, 118, 1, 149760, 0x45cc73e9
+0, 119, 119, 1, 149760, 0x21836e14
+0, 120, 120, 1, 149760, 0x14c38cf6
+0, 121, 121, 1, 149760, 0x18ee35ee
+0, 122, 122, 1, 149760, 0x4f55f781
+0, 123, 123, 1, 149760, 0x85556339
+0, 124, 124, 1, 149760, 0xc41e3261
+0, 125, 125, 1, 149760, 0xed34ba27
+0, 126, 126, 1, 149760, 0x91e7841c
+0, 127, 127, 1, 149760, 0x1605bd75
+0, 128, 128, 1, 149760, 0xb5af2fbc
+0, 129, 129, 1, 149760, 0x9024b2d8
+0, 130, 130, 1, 149760, 0xda8d3c03
+0, 131, 131, 1, 149760, 0xc23a9686
+0, 132, 132, 1, 149760, 0xf9c8686b
+0, 133, 133, 1, 149760, 0xec09b569
+0, 134, 134, 1, 149760, 0x398df9bb
+0, 135, 135, 1, 149760, 0x716c2934
+0, 136, 136, 1, 149760, 0x0a6ea078
+0, 137, 137, 1, 149760, 0x777739fe
+0, 138, 138, 1, 149760, 0x80417304
+0, 139, 139, 1, 149760, 0xe0a5c378
+0, 140, 140, 1, 149760, 0x9565a659
+0, 141, 141, 1, 149760, 0xdf6f1938
+0, 142, 142, 1, 149760, 0xe60d5639
+0, 143, 143, 1, 149760, 0xa89fa739
+0, 144, 144, 1, 149760, 0xd1529b40
+0, 145, 145, 1, 149760, 0x48a7d440
+0, 146, 146, 1, 149760, 0x5946afbb
+0, 147, 147, 1, 149760, 0x2cad2855
+0, 148, 148, 1, 149760, 0x7ac1d993
+0, 149, 149, 1, 149760, 0x0841a016
+0, 150, 150, 1, 149760, 0x35ea4bd2
+0, 151, 151, 1, 149760, 0x5371effa
+0, 152, 152, 1, 149760, 0xd6445a37
+0, 153, 153, 1, 149760, 0x782ea184
+0, 154, 154, 1, 149760, 0x919c2013
+0, 155, 155, 1, 149760, 0x0ea79614
+0, 156, 156, 1, 149760, 0x1ac0e835
+0, 157, 157, 1, 149760, 0x32a36ada
+0, 158, 158, 1, 149760, 0x6b0ad17c
+0, 159, 159, 1, 149760, 0xcd442d19
+0, 160, 160, 1, 149760, 0x0dd1df50
+0, 161, 161, 1, 149760, 0xe26b248f
+0, 162, 162, 1, 149760, 0x490348bb
+0, 163, 163, 1, 149760, 0x638b547e
+0, 164, 164, 1, 149760, 0xb2cbe2ca
+0, 165, 165, 1, 149760, 0xc6cfaa86
+0, 166, 166, 1, 149760, 0xe2317842
+0, 167, 167, 1, 149760, 0xe6e7cd9b
+0, 168, 168, 1, 149760, 0x55bf48cb
+0, 169, 169, 1, 149760, 0xefee6ea0
+0, 170, 170, 1, 149760, 0x2bb127fa
+0, 171, 171, 1, 149760, 0xebbf0725
+0, 172, 172, 1, 149760, 0xb40718a1
+0, 173, 173, 1, 149760, 0x33c8e7da
+0, 174, 174, 1, 149760, 0xfeea8d03
+0, 175, 175, 1, 149760, 0x52f47fa9
+0, 176, 176, 1, 149760, 0xb08fa2f6
+0, 177, 177, 1, 149760, 0xc9adcd96
+0, 178, 178, 1, 149760, 0xb8981cc2
+0, 179, 179, 1, 149760, 0x547b1eaa
+0, 180, 180, 1, 149760, 0x10733813
+0, 181, 181, 1, 149760, 0x14edfa3d
+0, 182, 182, 1, 149760, 0x28ae8eb3
+0, 183, 183, 1, 149760, 0x9b94a69c
+0, 184, 184, 1, 149760, 0x42f67a2a
+0, 185, 185, 1, 149760, 0x1ead65e6
+0, 186, 186, 1, 149760, 0x30b99840
+0, 187, 187, 1, 149760, 0xafdebbda
+0, 188, 188, 1, 149760, 0xc31cda7f
+0, 189, 189, 1, 149760, 0xe7afdfa8
+0, 190, 190, 1, 149760, 0xc8358146
+0, 191, 191, 1, 149760, 0xb8ea3a3b
+0, 192, 192, 1, 149760, 0xebbb2c0e
+0, 193, 193, 1, 149760, 0xe911c057
+0, 194, 194, 1, 149760, 0x843f3082
+0, 195, 195, 1, 149760, 0xd18f6dcb
+0, 196, 196, 1, 149760, 0xd0f67de3
+0, 197, 197, 1, 149760, 0xa7077645
+0, 198, 198, 1, 149760, 0xb7432bef
+0, 199, 199, 1, 149760, 0x9e3284ee
+0, 200, 200, 1, 149760, 0x931ec601
+0, 201, 201, 1, 149760, 0xd0f92a35
+0, 202, 202, 1, 149760, 0x2141c549
+0, 203, 203, 1, 149760, 0x46abf101
+0, 204, 204, 1, 149760, 0x92069ea7
+0, 205, 205, 1, 149760, 0xbf0dd536
+0, 206, 206, 1, 149760, 0xc0c34245
+0, 207, 207, 1, 149760, 0xd9f60e8b
+0, 208, 208, 1, 149760, 0xe20cb181
+0, 209, 209, 1, 149760, 0xdf58fbd2
+0, 210, 210, 1, 149760, 0xe047e805
+0, 211, 211, 1, 149760, 0xe6dd0520
+0, 212, 212, 1, 149760, 0xa7a1a7dd
+0, 213, 213, 1, 149760, 0x6bd6d799
+0, 214, 214, 1, 149760, 0x9fcbda54
+0, 215, 215, 1, 149760, 0xe9b8bf5a
+0, 216, 216, 1, 149760, 0x818d2b8d
+0, 217, 217, 1, 149760, 0x021c5b55
+0, 218, 218, 1, 149760, 0x0da93d94
+0, 219, 219, 1, 149760, 0x7d66b00d
+0, 220, 220, 1, 149760, 0xf84ab99e
+0, 221, 221, 1, 149760, 0xbc866ed2
+0, 222, 222, 1, 149760, 0x8075f6fa
+0, 223, 223, 1, 149760, 0x64540cad
+0, 224, 224, 1, 149760, 0xf3e28d9a
+0, 225, 225, 1, 149760, 0xb88fef8b
+0, 226, 226, 1, 149760, 0x1c782c83
+0, 227, 227, 1, 149760, 0xb89e4047
+0, 228, 228, 1, 149760, 0x593815a7
+0, 229, 229, 1, 149760, 0xa41a68d1
+0, 230, 230, 1, 149760, 0x7fdc56e5
+0, 231, 231, 1, 149760, 0xea8a0533
+0, 232, 232, 1, 149760, 0xc74709cc
+0, 233, 233, 1, 149760, 0xecca373c
+0, 234, 234, 1, 149760, 0x1dae228f
+0, 235, 235, 1, 149760, 0xbb900da8
+0, 236, 236, 1, 149760, 0xf71e4935
+0, 237, 237, 1, 149760, 0x8587d747
+0, 238, 238, 1, 149760, 0x5382afdd
+0, 239, 239, 1, 149760, 0x4075dea6
+0, 240, 240, 1, 149760, 0x1ccde8f2
+0, 241, 241, 1, 149760, 0x8065ed82
+0, 242, 242, 1, 149760, 0x0726bb8a
+0, 243, 243, 1, 149760, 0xedf2172c
+0, 244, 244, 1, 149760, 0x552cce61
+0, 245, 245, 1, 149760, 0x32851927
+0, 246, 246, 1, 149760, 0x15e8ae45
+0, 247, 247, 1, 149760, 0x9265625c
+0, 248, 248, 1, 149760, 0x11612465
+0, 249, 249, 1, 149760, 0x9f5586fa
+0, 250, 250, 1, 149760, 0x77f295a1
+0, 251, 251, 1, 149760, 0xb0757b88
+0, 252, 252, 1, 149760, 0xa0bd3d9c
+0, 253, 253, 1, 149760, 0x12471db6
+0, 254, 254, 1, 149760, 0x5c329d6b
+0, 255, 255, 1, 149760, 0x62f32654
+0, 256, 256, 1, 149760, 0xeafeb1f0
+0, 257, 257, 1, 149760, 0x707f6647
+0, 258, 258, 1, 149760, 0xe8acda33
+0, 259, 259, 1, 149760, 0x1e9dcb1b
+0, 260, 260, 1, 149760, 0x984a4a40
+0, 261, 261, 1, 149760, 0x066b9585
+0, 262, 262, 1, 149760, 0x5e2d2091
+0, 263, 263, 1, 149760, 0x6a6a5172
+0, 264, 264, 1, 149760, 0xc4c4fe94
+0, 265, 265, 1, 149760, 0x6ed2c46b
+0, 266, 266, 1, 149760, 0x810f27f8
+0, 267, 267, 1, 149760, 0xc27ca970
+0, 268, 268, 1, 149760, 0xfd3dae79
+0, 269, 269, 1, 149760, 0x9744ce6d
+0, 270, 270, 1, 149760, 0x45772f2a
+0, 271, 271, 1, 149760, 0x482ed805
+0, 272, 272, 1, 149760, 0x9606c429
+0, 273, 273, 1, 149760, 0x79a9ca8a
+0, 274, 274, 1, 149760, 0xf625806e
+0, 275, 275, 1, 149760, 0x0c9eed01
+0, 276, 276, 1, 149760, 0xb0007687
+0, 277, 277, 1, 149760, 0x620a7b35
+0, 278, 278, 1, 149760, 0x5d6fa9dc
+0, 279, 279, 1, 149760, 0x92c86275
+0, 280, 280, 1, 149760, 0xca1886f0
+0, 281, 281, 1, 149760, 0x6363a557
+0, 282, 282, 1, 149760, 0x32ab19ca
+0, 283, 283, 1, 149760, 0xa6113c10
+0, 284, 284, 1, 149760, 0x257fd46a
+0, 285, 285, 1, 149760, 0xb8af4e28
+0, 286, 286, 1, 149760, 0x9716d086
+0, 287, 287, 1, 149760, 0x0cc14c4d
+0, 288, 288, 1, 149760, 0xd194f150
+0, 289, 289, 1, 149760, 0xb7cd7cf8
+0, 290, 290, 1, 149760, 0xae1bb1a3
+0, 291, 291, 1, 149760, 0xb4cc355f
+0, 292, 292, 1, 149760, 0x617c1ecb
+0, 293, 293, 1, 149760, 0xf2d1f288
+0, 294, 294, 1, 149760, 0x109bcb52
+0, 295, 295, 1, 149760, 0xe61a97dd
+0, 296, 296, 1, 149760, 0xc629ac10
+0, 297, 297, 1, 149760, 0xb91acded
+0, 298, 298, 1, 149760, 0x54ccb321
+0, 299, 299, 1, 149760, 0x1ad3c115
diff --git a/tests/ref/fate/hevc-conformance-RPS_A_docomo_4 b/tests/ref/fate/hevc-conformance-RPS_A_docomo_4
new file mode 100644
index 0000000..e29a74b
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RPS_A_docomo_4
@@ -0,0 +1,45 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8edb27d7
+0, 1, 1, 1, 149760, 0x0bdf13f8
+0, 2, 2, 1, 149760, 0x45e702c7
+0, 3, 3, 1, 149760, 0x7a3a0c9a
+0, 4, 4, 1, 149760, 0xab0ed81d
+0, 5, 5, 1, 149760, 0xe2d4722a
+0, 6, 6, 1, 149760, 0x1df1f103
+0, 7, 7, 1, 149760, 0xdde42fb8
+0, 8, 8, 1, 149760, 0xfe2eb624
+0, 9, 9, 1, 149760, 0x121ff262
+0, 10, 10, 1, 149760, 0x64e5e7ba
+0, 11, 11, 1, 149760, 0x61b40e67
+0, 12, 12, 1, 149760, 0x8ceeb33f
+0, 13, 13, 1, 149760, 0xcbff6fc5
+0, 14, 14, 1, 149760, 0x07d6f767
+0, 15, 15, 1, 149760, 0x5cff14a5
+0, 16, 16, 1, 149760, 0x5c336ca3
+0, 17, 17, 1, 149760, 0x424990cd
+0, 18, 18, 1, 149760, 0x2c423459
+0, 19, 19, 1, 149760, 0xaff700ac
+0, 20, 20, 1, 149760, 0xaab9e6f4
+0, 21, 21, 1, 149760, 0x7979bfd4
+0, 22, 22, 1, 149760, 0x5096ee11
+0, 23, 23, 1, 149760, 0x4f02d1d0
+0, 24, 24, 1, 149760, 0x0c6468d2
+0, 25, 25, 1, 149760, 0x707e9307
+0, 26, 26, 1, 149760, 0xf4a71dc8
+0, 27, 27, 1, 149760, 0xbefc67f0
+0, 28, 28, 1, 149760, 0x05b8f3a9
+0, 29, 29, 1, 149760, 0xcd080a46
+0, 30, 30, 1, 149760, 0x1b5ab043
+0, 31, 31, 1, 149760, 0xd4b896e2
+0, 32, 32, 1, 149760, 0xbd342d08
+0, 33, 33, 1, 149760, 0x0b993f3c
+0, 34, 34, 1, 149760, 0xd89190e2
+0, 35, 35, 1, 149760, 0x507f2663
+0, 36, 36, 1, 149760, 0x6994c08f
+0, 37, 37, 1, 149760, 0xcf0209b2
+0, 38, 38, 1, 149760, 0x9695327c
+0, 39, 39, 1, 149760, 0x7116fdb3
+0, 40, 40, 1, 149760, 0x1294b154
+0, 41, 41, 1, 149760, 0x7ed1f716
+0, 42, 42, 1, 149760, 0xdc4880da
+0, 43, 43, 1, 149760, 0xa5955d35
diff --git a/tests/ref/fate/hevc-conformance-RPS_B_qualcomm_5 b/tests/ref/fate/hevc-conformance-RPS_B_qualcomm_5
new file mode 100644
index 0000000..3b24e75
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RPS_B_qualcomm_5
@@ -0,0 +1,301 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xdb5e3b56
+0, 1, 1, 1, 149760, 0xe328e677
+0, 2, 2, 1, 149760, 0x8f18f4c0
+0, 3, 3, 1, 149760, 0xf48de64c
+0, 4, 4, 1, 149760, 0x2937ad23
+0, 5, 5, 1, 149760, 0x93f166d2
+0, 6, 6, 1, 149760, 0x80e4e9c2
+0, 7, 7, 1, 149760, 0xb2a35da7
+0, 8, 8, 1, 149760, 0xf4fbb5c2
+0, 9, 9, 1, 149760, 0x2193bd91
+0, 10, 10, 1, 149760, 0xd4eec3b4
+0, 11, 11, 1, 149760, 0xb2e20b91
+0, 12, 12, 1, 149760, 0xaf8d17dc
+0, 13, 13, 1, 149760, 0x2189ac78
+0, 14, 14, 1, 149760, 0x52b8130f
+0, 15, 15, 1, 149760, 0xdfbc2f0a
+0, 16, 16, 1, 149760, 0x4c0269cf
+0, 17, 17, 1, 149760, 0xf99bb7d2
+0, 18, 18, 1, 149760, 0xada1495f
+0, 19, 19, 1, 149760, 0x57c42893
+0, 20, 20, 1, 149760, 0x022d29ca
+0, 21, 21, 1, 149760, 0x9883a271
+0, 22, 22, 1, 149760, 0xc8c132d7
+0, 23, 23, 1, 149760, 0xa97f8b43
+0, 24, 24, 1, 149760, 0x1bc187fa
+0, 25, 25, 1, 149760, 0x7b93951b
+0, 26, 26, 1, 149760, 0x88fd367c
+0, 27, 27, 1, 149760, 0x29471b92
+0, 28, 28, 1, 149760, 0x3ba820f1
+0, 29, 29, 1, 149760, 0x0a223169
+0, 30, 30, 1, 149760, 0x70fee1d5
+0, 31, 31, 1, 149760, 0x5f5cf053
+0, 32, 32, 1, 149760, 0x698f11e4
+0, 33, 33, 1, 149760, 0x65314fd4
+0, 34, 34, 1, 149760, 0x7a689450
+0, 35, 35, 1, 149760, 0x28774ca0
+0, 36, 36, 1, 149760, 0x0751f804
+0, 37, 37, 1, 149760, 0x875a6fb9
+0, 38, 38, 1, 149760, 0xde1f5309
+0, 39, 39, 1, 149760, 0x82701dd6
+0, 40, 40, 1, 149760, 0x13a2f45e
+0, 41, 41, 1, 149760, 0xfc3b140c
+0, 42, 42, 1, 149760, 0x4518ab47
+0, 43, 43, 1, 149760, 0xe5459482
+0, 44, 44, 1, 149760, 0x4cfafc6e
+0, 45, 45, 1, 149760, 0xc7cd5e43
+0, 46, 46, 1, 149760, 0x1ee79746
+0, 47, 47, 1, 149760, 0xccc73c83
+0, 48, 48, 1, 149760, 0xd9ecafc7
+0, 49, 49, 1, 149760, 0x65221c9d
+0, 50, 50, 1, 149760, 0x219b0b4b
+0, 51, 51, 1, 149760, 0x9d1e2010
+0, 52, 52, 1, 149760, 0x11685e16
+0, 53, 53, 1, 149760, 0x37eb1297
+0, 54, 54, 1, 149760, 0x99088778
+0, 55, 55, 1, 149760, 0xb41cbf25
+0, 56, 56, 1, 149760, 0x56f78bda
+0, 57, 57, 1, 149760, 0x6c284868
+0, 58, 58, 1, 149760, 0x37f245b9
+0, 59, 59, 1, 149760, 0x79682de2
+0, 60, 60, 1, 149760, 0x5a04f379
+0, 61, 61, 1, 149760, 0xfecc668b
+0, 62, 62, 1, 149760, 0x29328d8c
+0, 63, 63, 1, 149760, 0x8aff3ad7
+0, 64, 64, 1, 149760, 0x4035f027
+0, 65, 65, 1, 149760, 0xe7cead1d
+0, 66, 66, 1, 149760, 0x18578492
+0, 67, 67, 1, 149760, 0xd3ab3f9d
+0, 68, 68, 1, 149760, 0x6f866e38
+0, 69, 69, 1, 149760, 0x6a47800c
+0, 70, 70, 1, 149760, 0x01c6305e
+0, 71, 71, 1, 149760, 0x489ab5a8
+0, 72, 72, 1, 149760, 0xb2570787
+0, 73, 73, 1, 149760, 0xb0d5d478
+0, 74, 74, 1, 149760, 0x88484ccc
+0, 75, 75, 1, 149760, 0xb4c6be2c
+0, 76, 76, 1, 149760, 0x461d874c
+0, 77, 77, 1, 149760, 0x3be464b0
+0, 78, 78, 1, 149760, 0x06aa9443
+0, 79, 79, 1, 149760, 0xe0e625a3
+0, 80, 80, 1, 149760, 0x17e2daeb
+0, 81, 81, 1, 149760, 0x58a1a350
+0, 82, 82, 1, 149760, 0xcd4983ce
+0, 83, 83, 1, 149760, 0x90459a42
+0, 84, 84, 1, 149760, 0x899dedaa
+0, 85, 85, 1, 149760, 0x814e3529
+0, 86, 86, 1, 149760, 0x5795a2e5
+0, 87, 87, 1, 149760, 0xcedb245c
+0, 88, 88, 1, 149760, 0x37f9dd30
+0, 89, 89, 1, 149760, 0x320d899e
+0, 90, 90, 1, 149760, 0x6a33ffca
+0, 91, 91, 1, 149760, 0x6620b9eb
+0, 92, 92, 1, 149760, 0xfc8b1e1b
+0, 93, 93, 1, 149760, 0x835a0dd9
+0, 94, 94, 1, 149760, 0xcee4a9b0
+0, 95, 95, 1, 149760, 0x2c2972f0
+0, 96, 96, 1, 149760, 0x0a39aa8b
+0, 97, 97, 1, 149760, 0xa8a9c0bf
+0, 98, 98, 1, 149760, 0xd563c087
+0, 99, 99, 1, 149760, 0xb0f88320
+0, 100, 100, 1, 149760, 0x0ffffd6b
+0, 101, 101, 1, 149760, 0x95269e8c
+0, 102, 102, 1, 149760, 0xd0d4acd9
+0, 103, 103, 1, 149760, 0x7cf06805
+0, 104, 104, 1, 149760, 0xa5192bbe
+0, 105, 105, 1, 149760, 0x2fed928b
+0, 106, 106, 1, 149760, 0x549edd04
+0, 107, 107, 1, 149760, 0xa42b55d7
+0, 108, 108, 1, 149760, 0xeab32579
+0, 109, 109, 1, 149760, 0x95a727c3
+0, 110, 110, 1, 149760, 0x76714576
+0, 111, 111, 1, 149760, 0x5efc352a
+0, 112, 112, 1, 149760, 0x154a2c06
+0, 113, 113, 1, 149760, 0x516faf62
+0, 114, 114, 1, 149760, 0x622b6d64
+0, 115, 115, 1, 149760, 0x2ada08a9
+0, 116, 116, 1, 149760, 0xf24efa06
+0, 117, 117, 1, 149760, 0x5979b33e
+0, 118, 118, 1, 149760, 0x2130a282
+0, 119, 119, 1, 149760, 0x1ee8b3d1
+0, 120, 120, 1, 149760, 0x840c6913
+0, 121, 121, 1, 149760, 0xa37049b8
+0, 122, 122, 1, 149760, 0x8d95efb0
+0, 123, 123, 1, 149760, 0x22d3afb2
+0, 124, 124, 1, 149760, 0x113d6c6f
+0, 125, 125, 1, 149760, 0xb407014d
+0, 126, 126, 1, 149760, 0x33a8e5c9
+0, 127, 127, 1, 149760, 0x2689ced2
+0, 128, 128, 1, 149760, 0x3eaf3f55
+0, 129, 129, 1, 149760, 0x93ad7fa5
+0, 130, 130, 1, 149760, 0x30c15154
+0, 131, 131, 1, 149760, 0xdce68c7a
+0, 132, 132, 1, 149760, 0xea092d4c
+0, 133, 133, 1, 149760, 0xed679468
+0, 134, 134, 1, 149760, 0x9128c0d5
+0, 135, 135, 1, 149760, 0xd4f121ba
+0, 136, 136, 1, 149760, 0xe5e228f0
+0, 137, 137, 1, 149760, 0x8246dae3
+0, 138, 138, 1, 149760, 0x8a3b430c
+0, 139, 139, 1, 149760, 0x9a8edc3d
+0, 140, 140, 1, 149760, 0x68b0af97
+0, 141, 141, 1, 149760, 0x90d54b52
+0, 142, 142, 1, 149760, 0xd6395796
+0, 143, 143, 1, 149760, 0x70986b40
+0, 144, 144, 1, 149760, 0xc0b4a9c8
+0, 145, 145, 1, 149760, 0x760b973b
+0, 146, 146, 1, 149760, 0xe8fe9846
+0, 147, 147, 1, 149760, 0x61062c97
+0, 148, 148, 1, 149760, 0x9148e99b
+0, 149, 149, 1, 149760, 0x962c6a1e
+0, 150, 150, 1, 149760, 0x57bb088f
+0, 151, 151, 1, 149760, 0x2b0fa8c5
+0, 152, 152, 1, 149760, 0x00f932fc
+0, 153, 153, 1, 149760, 0x4cc58697
+0, 154, 154, 1, 149760, 0xd2bf178f
+0, 155, 155, 1, 149760, 0xc510c1cd
+0, 156, 156, 1, 149760, 0xc48e0192
+0, 157, 157, 1, 149760, 0xa03e7fe5
+0, 158, 158, 1, 149760, 0xb68ce060
+0, 159, 159, 1, 149760, 0x653951c8
+0, 160, 160, 1, 149760, 0xbd1abe11
+0, 161, 161, 1, 149760, 0xad7a2366
+0, 162, 162, 1, 149760, 0xb018279e
+0, 163, 163, 1, 149760, 0xd5994bff
+0, 164, 164, 1, 149760, 0x3eb7e082
+0, 165, 165, 1, 149760, 0x87257b3a
+0, 166, 166, 1, 149760, 0x12fc4c4d
+0, 167, 167, 1, 149760, 0x9fbfa94d
+0, 168, 168, 1, 149760, 0x61714cae
+0, 169, 169, 1, 149760, 0xae291b59
+0, 170, 170, 1, 149760, 0x8f161442
+0, 171, 171, 1, 149760, 0x603cf3a5
+0, 172, 172, 1, 149760, 0xf9f214a0
+0, 173, 173, 1, 149760, 0xbbf5dcb9
+0, 174, 174, 1, 149760, 0x8af1a1ab
+0, 175, 175, 1, 149760, 0x16f581e5
+0, 176, 176, 1, 149760, 0xdadd8eed
+0, 177, 177, 1, 149760, 0x2f1acd8e
+0, 178, 178, 1, 149760, 0xa28bd660
+0, 179, 179, 1, 149760, 0x7902dd67
+0, 180, 180, 1, 149760, 0x9b771dc2
+0, 181, 181, 1, 149760, 0x0fc82bda
+0, 182, 182, 1, 149760, 0xd6128167
+0, 183, 183, 1, 149760, 0xe57b7a2f
+0, 184, 184, 1, 149760, 0x1e158d0e
+0, 185, 185, 1, 149760, 0x682c7c60
+0, 186, 186, 1, 149760, 0x32096bbe
+0, 187, 187, 1, 149760, 0x297652f2
+0, 188, 188, 1, 149760, 0x056c7432
+0, 189, 189, 1, 149760, 0x0469b39a
+0, 190, 190, 1, 149760, 0x00044bc9
+0, 191, 191, 1, 149760, 0x766c0bad
+0, 192, 192, 1, 149760, 0xd6720a40
+0, 193, 193, 1, 149760, 0x814895eb
+0, 194, 194, 1, 149760, 0x1a84fcbc
+0, 195, 195, 1, 149760, 0x8b9442aa
+0, 196, 196, 1, 149760, 0x290187d1
+0, 197, 197, 1, 149760, 0x8f87294f
+0, 198, 198, 1, 149760, 0x8c49a125
+0, 199, 199, 1, 149760, 0xe169806a
+0, 200, 200, 1, 149760, 0x18c0e2f1
+0, 201, 201, 1, 149760, 0xb92b0e67
+0, 202, 202, 1, 149760, 0x98d2acef
+0, 203, 203, 1, 149760, 0x179eeaec
+0, 204, 204, 1, 149760, 0xa054a7bb
+0, 205, 205, 1, 149760, 0x5f78d160
+0, 206, 206, 1, 149760, 0x09f9a40f
+0, 207, 207, 1, 149760, 0xfb4a59f5
+0, 208, 208, 1, 149760, 0xdc5ca1f2
+0, 209, 209, 1, 149760, 0xf2254927
+0, 210, 210, 1, 149760, 0xfda4fab3
+0, 211, 211, 1, 149760, 0x45ab23cc
+0, 212, 212, 1, 149760, 0x1f69c006
+0, 213, 213, 1, 149760, 0x326bb5a1
+0, 214, 214, 1, 149760, 0x810dad28
+0, 215, 215, 1, 149760, 0x96dfc515
+0, 216, 216, 1, 149760, 0xc685fd80
+0, 217, 217, 1, 149760, 0x18da42f4
+0, 218, 218, 1, 149760, 0x11773807
+0, 219, 219, 1, 149760, 0x3f54c458
+0, 220, 220, 1, 149760, 0xa5dff146
+0, 221, 221, 1, 149760, 0x4bc3ffcb
+0, 222, 222, 1, 149760, 0x84801971
+0, 223, 223, 1, 149760, 0x2ff65539
+0, 224, 224, 1, 149760, 0x8a7f716d
+0, 225, 225, 1, 149760, 0xe7e8cdd0
+0, 226, 226, 1, 149760, 0xc8567d5f
+0, 227, 227, 1, 149760, 0x63986bcd
+0, 228, 228, 1, 149760, 0x8817f648
+0, 229, 229, 1, 149760, 0xa0152e36
+0, 230, 230, 1, 149760, 0x2eca851e
+0, 231, 231, 1, 149760, 0x09c0f0cb
+0, 232, 232, 1, 149760, 0xf1c81b23
+0, 233, 233, 1, 149760, 0x93096c98
+0, 234, 234, 1, 149760, 0x1fe47331
+0, 235, 235, 1, 149760, 0x79c0b70e
+0, 236, 236, 1, 149760, 0xb1929b60
+0, 237, 237, 1, 149760, 0xb42ea35a
+0, 238, 238, 1, 149760, 0x42d5bf86
+0, 239, 239, 1, 149760, 0xa83efbd4
+0, 240, 240, 1, 149760, 0xbdd2f313
+0, 241, 241, 1, 149760, 0x85a5dbd4
+0, 242, 242, 1, 149760, 0xc475b180
+0, 243, 243, 1, 149760, 0x63911e68
+0, 244, 244, 1, 149760, 0x5b79baab
+0, 245, 245, 1, 149760, 0xa22d310e
+0, 246, 246, 1, 149760, 0x243ef7b5
+0, 247, 247, 1, 149760, 0x813fdc95
+0, 248, 248, 1, 149760, 0xbb7d19fa
+0, 249, 249, 1, 149760, 0x199ae62c
+0, 250, 250, 1, 149760, 0x7a4ce5b2
+0, 251, 251, 1, 149760, 0xd632a9d3
+0, 252, 252, 1, 149760, 0xc07b75fe
+0, 253, 253, 1, 149760, 0x5bae6a88
+0, 254, 254, 1, 149760, 0x29b411e0
+0, 255, 255, 1, 149760, 0x78706cbe
+0, 256, 256, 1, 149760, 0x2659a6cb
+0, 257, 257, 1, 149760, 0xefb170f8
+0, 258, 258, 1, 149760, 0x9dd107b8
+0, 259, 259, 1, 149760, 0xf38b5ce5
+0, 260, 260, 1, 149760, 0xd7e0f10e
+0, 261, 261, 1, 149760, 0x080b9e49
+0, 262, 262, 1, 149760, 0xa2274c3b
+0, 263, 263, 1, 149760, 0x3d3376c9
+0, 264, 264, 1, 149760, 0xe04719e3
+0, 265, 265, 1, 149760, 0xfe4123e3
+0, 266, 266, 1, 149760, 0x769a3cf6
+0, 267, 267, 1, 149760, 0xaf0be9e6
+0, 268, 268, 1, 149760, 0xe9baa873
+0, 269, 269, 1, 149760, 0x4f5fb405
+0, 270, 270, 1, 149760, 0x207b401e
+0, 271, 271, 1, 149760, 0xb1483351
+0, 272, 272, 1, 149760, 0x5fe3dc9f
+0, 273, 273, 1, 149760, 0xb35dcae7
+0, 274, 274, 1, 149760, 0x8cc69de4
+0, 275, 275, 1, 149760, 0xd6e29308
+0, 276, 276, 1, 149760, 0xf8f53227
+0, 277, 277, 1, 149760, 0xaf483e80
+0, 278, 278, 1, 149760, 0x287cdfc9
+0, 279, 279, 1, 149760, 0xf72b93eb
+0, 280, 280, 1, 149760, 0x09c26976
+0, 281, 281, 1, 149760, 0xae58601f
+0, 282, 282, 1, 149760, 0x7f951546
+0, 283, 283, 1, 149760, 0x81e742b2
+0, 284, 284, 1, 149760, 0xb16554a6
+0, 285, 285, 1, 149760, 0xcdafc4c0
+0, 286, 286, 1, 149760, 0x0bb335bc
+0, 287, 287, 1, 149760, 0xe1e4ba60
+0, 288, 288, 1, 149760, 0xcce3eb48
+0, 289, 289, 1, 149760, 0x8b8992a9
+0, 290, 290, 1, 149760, 0x0a5ff2f6
+0, 291, 291, 1, 149760, 0xb04b8ed1
+0, 292, 292, 1, 149760, 0x0c874aae
+0, 293, 293, 1, 149760, 0x19d6f138
+0, 294, 294, 1, 149760, 0x30e322f2
+0, 295, 295, 1, 149760, 0x67a5700c
+0, 296, 296, 1, 149760, 0xb65bd462
+0, 297, 297, 1, 149760, 0xe267d09e
+0, 298, 298, 1, 149760, 0x8824c043
+0, 299, 299, 1, 149760, 0x680cfc20
diff --git a/tests/ref/fate/hevc-conformance-RPS_C_ericsson_4 b/tests/ref/fate/hevc-conformance-RPS_C_ericsson_4
new file mode 100644
index 0000000..e97e7ea
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RPS_C_ericsson_4
@@ -0,0 +1,41 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8ce7200b
+0, 1, 1, 1, 149760, 0x85340cda
+0, 2, 2, 1, 149760, 0x16fd1f91
+0, 3, 3, 1, 149760, 0x7d8d312d
+0, 4, 4, 1, 149760, 0xae6ed875
+0, 5, 5, 1, 149760, 0xccac730a
+0, 6, 6, 1, 149760, 0x3d321c3f
+0, 7, 7, 1, 149760, 0x18e05688
+0, 8, 8, 1, 149760, 0x23fec4de
+0, 9, 9, 1, 149760, 0x3e0de0ca
+0, 10, 10, 1, 149760, 0x4789e861
+0, 11, 11, 1, 149760, 0x34550f71
+0, 12, 12, 1, 149760, 0xb0b1b4a7
+0, 13, 13, 1, 149760, 0xb9b8967e
+0, 14, 14, 1, 149760, 0x92e7f3c5
+0, 15, 15, 1, 149760, 0x61c0f62e
+0, 16, 16, 1, 149760, 0x819648c5
+0, 17, 17, 1, 149760, 0xe0286f95
+0, 18, 18, 1, 149760, 0xc2d85311
+0, 19, 19, 1, 149760, 0xbb07ec4e
+0, 20, 20, 1, 149760, 0xe073f10b
+0, 21, 21, 1, 149760, 0xd2e8c52f
+0, 22, 22, 1, 149760, 0x12020583
+0, 23, 23, 1, 149760, 0x0dfecaba
+0, 24, 24, 1, 149760, 0xe35f8ee5
+0, 25, 25, 1, 149760, 0x267bbf14
+0, 26, 26, 1, 149760, 0x371037a8
+0, 27, 27, 1, 149760, 0x3d188434
+0, 28, 28, 1, 149760, 0xce81fd31
+0, 29, 29, 1, 149760, 0xfbbf2801
+0, 30, 30, 1, 149760, 0x9af9d1b6
+0, 31, 31, 1, 149760, 0x14e2feea
+0, 32, 32, 1, 149760, 0x83f04b3a
+0, 33, 33, 1, 149760, 0xfc30687f
+0, 34, 34, 1, 149760, 0xaec2be07
+0, 35, 35, 1, 149760, 0xc7da6926
+0, 36, 36, 1, 149760, 0x50d20e8e
+0, 37, 37, 1, 149760, 0xd0fa63e9
+0, 38, 38, 1, 149760, 0x9d15906a
+0, 39, 39, 1, 149760, 0x4c685317
diff --git a/tests/ref/fate/hevc-conformance-RPS_D_ericsson_5 b/tests/ref/fate/hevc-conformance-RPS_D_ericsson_5
new file mode 100644
index 0000000..2851704
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RPS_D_ericsson_5
@@ -0,0 +1,69 @@
+#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, 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-RPS_E_qualcomm_5 b/tests/ref/fate/hevc-conformance-RPS_E_qualcomm_5
new file mode 100644
index 0000000..82c25e1
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RPS_E_qualcomm_5
@@ -0,0 +1,301 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8edb27d7
+0, 1, 1, 1, 149760, 0xd62a31bc
+0, 2, 2, 1, 149760, 0xec822f84
+0, 3, 3, 1, 149760, 0x7a0a0f25
+0, 4, 4, 1, 149760, 0x461dd882
+0, 5, 5, 1, 149760, 0x62777923
+0, 6, 6, 1, 149760, 0x063c2559
+0, 7, 7, 1, 149760, 0x03b34c02
+0, 8, 8, 1, 149760, 0xe999bdad
+0, 9, 9, 1, 149760, 0x3285f731
+0, 10, 10, 1, 149760, 0x1f8ffaaa
+0, 11, 11, 1, 149760, 0xd7c956f4
+0, 12, 12, 1, 149760, 0xb9e3da56
+0, 13, 13, 1, 149760, 0x1200953f
+0, 14, 14, 1, 149760, 0x06c212cc
+0, 15, 15, 1, 149760, 0xaaa84f01
+0, 16, 16, 1, 149760, 0x7a606de8
+0, 17, 17, 1, 149760, 0x47e49e5a
+0, 18, 18, 1, 149760, 0x666a3370
+0, 19, 19, 1, 149760, 0x187b6b6c
+0, 20, 20, 1, 149760, 0x3c8f0ef4
+0, 21, 21, 1, 149760, 0xc3e59d36
+0, 22, 22, 1, 149760, 0xecb40b3b
+0, 23, 23, 1, 149760, 0x0ae9e31e
+0, 24, 24, 1, 149760, 0xd324746b
+0, 25, 25, 1, 149760, 0xc337c3d5
+0, 26, 26, 1, 149760, 0xd3883c16
+0, 27, 27, 1, 149760, 0xa28b836c
+0, 28, 28, 1, 149760, 0x1cd61f86
+0, 29, 29, 1, 149760, 0x52b51344
+0, 30, 30, 1, 149760, 0x3980a396
+0, 31, 31, 1, 149760, 0x85d0e262
+0, 32, 32, 1, 149760, 0xbd342d08
+0, 33, 33, 1, 149760, 0xc6114038
+0, 34, 34, 1, 149760, 0xc3ab6ca9
+0, 35, 35, 1, 149760, 0x6db56aa7
+0, 36, 36, 1, 149760, 0x22df9ab0
+0, 37, 37, 1, 149760, 0xfa6d2caf
+0, 38, 38, 1, 149760, 0xc1b64e52
+0, 39, 39, 1, 149760, 0x4b9c1d64
+0, 40, 40, 1, 149760, 0xbab6de8f
+0, 41, 41, 1, 149760, 0xfc0e1193
+0, 42, 42, 1, 149760, 0x8fa0a268
+0, 43, 43, 1, 149760, 0x80cf5e07
+0, 44, 44, 1, 149760, 0xe9720cd6
+0, 45, 45, 1, 149760, 0xa9bb2593
+0, 46, 46, 1, 149760, 0xc2e3e7c6
+0, 47, 47, 1, 149760, 0xc9a4ffd6
+0, 48, 48, 1, 149760, 0x9acebbe2
+0, 49, 49, 1, 149760, 0xb3a6bee1
+0, 50, 50, 1, 149760, 0xd1f12057
+0, 51, 51, 1, 149760, 0x9a2306c0
+0, 52, 52, 1, 149760, 0xd1ee37ff
+0, 53, 53, 1, 149760, 0xb0e1dca1
+0, 54, 54, 1, 149760, 0x35646e46
+0, 55, 55, 1, 149760, 0x803baac5
+0, 56, 56, 1, 149760, 0x7ee17b15
+0, 57, 57, 1, 149760, 0x03274ce1
+0, 58, 58, 1, 149760, 0xf3db2fea
+0, 59, 59, 1, 149760, 0xc3c4ff33
+0, 60, 60, 1, 149760, 0x0fc4786e
+0, 61, 61, 1, 149760, 0x27505756
+0, 62, 62, 1, 149760, 0x4c797266
+0, 63, 63, 1, 149760, 0xeba43f1b
+0, 64, 64, 1, 149760, 0x1ae5f13d
+0, 65, 65, 1, 149760, 0x97e186b1
+0, 66, 66, 1, 149760, 0xc0556895
+0, 67, 67, 1, 149760, 0x4e4d18ed
+0, 68, 68, 1, 149760, 0x39811c80
+0, 69, 69, 1, 149760, 0x6bca8c2f
+0, 70, 70, 1, 149760, 0x27ec4807
+0, 71, 71, 1, 149760, 0x50cea38b
+0, 72, 72, 1, 149760, 0x7ec4c09d
+0, 73, 73, 1, 149760, 0xb2a8afee
+0, 74, 74, 1, 149760, 0x0e943cbf
+0, 75, 75, 1, 149760, 0x7c119ea8
+0, 76, 76, 1, 149760, 0x71e194e5
+0, 77, 77, 1, 149760, 0x6a5d792d
+0, 78, 78, 1, 149760, 0xb8aeb406
+0, 79, 79, 1, 149760, 0x263767f2
+0, 80, 80, 1, 149760, 0xcfbef5ae
+0, 81, 81, 1, 149760, 0xad7eb01c
+0, 82, 82, 1, 149760, 0x612d937d
+0, 83, 83, 1, 149760, 0x90a591fd
+0, 84, 84, 1, 149760, 0x582a60dd
+0, 85, 85, 1, 149760, 0x2640124e
+0, 86, 86, 1, 149760, 0x1c12b037
+0, 87, 87, 1, 149760, 0xc916c4e7
+0, 88, 88, 1, 149760, 0x43d2bfe6
+0, 89, 89, 1, 149760, 0xdc7460c4
+0, 90, 90, 1, 149760, 0xc46e21a8
+0, 91, 91, 1, 149760, 0xe08dbd50
+0, 92, 92, 1, 149760, 0xf40bceed
+0, 93, 93, 1, 149760, 0x0ab01b81
+0, 94, 94, 1, 149760, 0xe6ab1f16
+0, 95, 95, 1, 149760, 0x6b4f6a62
+0, 96, 96, 1, 149760, 0x8ff7a1a1
+0, 97, 97, 1, 149760, 0x079be281
+0, 98, 98, 1, 149760, 0xa24bc187
+0, 99, 99, 1, 149760, 0xfbed7e79
+0, 100, 100, 1, 149760, 0xa27c2048
+0, 101, 101, 1, 149760, 0xe6119831
+0, 102, 102, 1, 149760, 0xc75684c6
+0, 103, 103, 1, 149760, 0x76575ef4
+0, 104, 104, 1, 149760, 0xebd32a7e
+0, 105, 105, 1, 149760, 0x6e5c703a
+0, 106, 106, 1, 149760, 0x3c43d0b3
+0, 107, 107, 1, 149760, 0xcc3354af
+0, 108, 108, 1, 149760, 0xa7bc26f3
+0, 109, 109, 1, 149760, 0xb04b0400
+0, 110, 110, 1, 149760, 0x3e5d3995
+0, 111, 111, 1, 149760, 0x549331ae
+0, 112, 112, 1, 149760, 0xd39031c0
+0, 113, 113, 1, 149760, 0xada1a1bd
+0, 114, 114, 1, 149760, 0xd08a4bcb
+0, 115, 115, 1, 149760, 0xcbefb4fa
+0, 116, 116, 1, 149760, 0xb311a7e0
+0, 117, 117, 1, 149760, 0xab23a6f2
+0, 118, 118, 1, 149760, 0xa90a6dfb
+0, 119, 119, 1, 149760, 0xafcc72b7
+0, 120, 120, 1, 149760, 0xe7c48044
+0, 121, 121, 1, 149760, 0x4449cf72
+0, 122, 122, 1, 149760, 0xfe4ba9d7
+0, 123, 123, 1, 149760, 0x76623bda
+0, 124, 124, 1, 149760, 0x8d071b0b
+0, 125, 125, 1, 149760, 0x777aaefa
+0, 126, 126, 1, 149760, 0xab995bab
+0, 127, 127, 1, 149760, 0xfd0e8e0c
+0, 128, 128, 1, 149760, 0xb6d651e5
+0, 129, 129, 1, 149760, 0x0646c2d0
+0, 130, 130, 1, 149760, 0xefc2561a
+0, 131, 131, 1, 149760, 0xaa86dcd1
+0, 132, 132, 1, 149760, 0x0caf821e
+0, 133, 133, 1, 149760, 0x55a5e7fa
+0, 134, 134, 1, 149760, 0x1a011bae
+0, 135, 135, 1, 149760, 0xe7a922b2
+0, 136, 136, 1, 149760, 0x4b968175
+0, 137, 137, 1, 149760, 0xc0bc1018
+0, 138, 138, 1, 149760, 0x58775461
+0, 139, 139, 1, 149760, 0x77dad082
+0, 140, 140, 1, 149760, 0x995e78d7
+0, 141, 141, 1, 149760, 0xc6360898
+0, 142, 142, 1, 149760, 0xbd0b48ce
+0, 143, 143, 1, 149760, 0x6d076602
+0, 144, 144, 1, 149760, 0xc3459e98
+0, 145, 145, 1, 149760, 0x8e53625e
+0, 146, 146, 1, 149760, 0xd1ba7915
+0, 147, 147, 1, 149760, 0xf41a48e7
+0, 148, 148, 1, 149760, 0xc3fbdcc3
+0, 149, 149, 1, 149760, 0x1f726dcf
+0, 150, 150, 1, 149760, 0x6f882d61
+0, 151, 151, 1, 149760, 0x2e02c8c5
+0, 152, 152, 1, 149760, 0x35ed54c6
+0, 153, 153, 1, 149760, 0x11dd8c48
+0, 154, 154, 1, 149760, 0xc95bf20b
+0, 155, 155, 1, 149760, 0x64f96433
+0, 156, 156, 1, 149760, 0x1ab5d8d5
+0, 157, 157, 1, 149760, 0x3af856f0
+0, 158, 158, 1, 149760, 0xdaa3bd1b
+0, 159, 159, 1, 149760, 0x25c64816
+0, 160, 160, 1, 149760, 0x6a4cc5d7
+0, 161, 161, 1, 149760, 0xf8e815f5
+0, 162, 162, 1, 149760, 0xa0bf431e
+0, 163, 163, 1, 149760, 0x09567fc4
+0, 164, 164, 1, 149760, 0x2d9408d7
+0, 165, 165, 1, 149760, 0xe09fff24
+0, 166, 166, 1, 149760, 0x6d58a81b
+0, 167, 167, 1, 149760, 0x0280e181
+0, 168, 168, 1, 149760, 0x465e63d1
+0, 169, 169, 1, 149760, 0xedb432a0
+0, 170, 170, 1, 149760, 0xdff70d73
+0, 171, 171, 1, 149760, 0x9386fdb4
+0, 172, 172, 1, 149760, 0xdcb03cb9
+0, 173, 173, 1, 149760, 0x3538dbd4
+0, 174, 174, 1, 149760, 0xc637709d
+0, 175, 175, 1, 149760, 0x7a1a6681
+0, 176, 176, 1, 149760, 0x403ca1e0
+0, 177, 177, 1, 149760, 0xe562d48a
+0, 178, 178, 1, 149760, 0x90a2e933
+0, 179, 179, 1, 149760, 0x0e9e167a
+0, 180, 180, 1, 149760, 0x2da90c4d
+0, 181, 181, 1, 149760, 0x2ce92218
+0, 182, 182, 1, 149760, 0x164a613d
+0, 183, 183, 1, 149760, 0x336d9e2e
+0, 184, 184, 1, 149760, 0x598986e6
+0, 185, 185, 1, 149760, 0xd0039cfc
+0, 186, 186, 1, 149760, 0x8e74c5e6
+0, 187, 187, 1, 149760, 0xb95fa63c
+0, 188, 188, 1, 149760, 0xc688c596
+0, 189, 189, 1, 149760, 0x4757034b
+0, 190, 190, 1, 149760, 0xc9ac948a
+0, 191, 191, 1, 149760, 0x580b9d60
+0, 192, 192, 1, 149760, 0xf39031d6
+0, 193, 193, 1, 149760, 0x2d68ad7b
+0, 194, 194, 1, 149760, 0xf72815ea
+0, 195, 195, 1, 149760, 0xc16323fa
+0, 196, 196, 1, 149760, 0x8a65665e
+0, 197, 197, 1, 149760, 0xcf1d5a89
+0, 198, 198, 1, 149760, 0x03f3011a
+0, 199, 199, 1, 149760, 0x24c47cbc
+0, 200, 200, 1, 149760, 0xcc89db6d
+0, 201, 201, 1, 149760, 0xd8332e3c
+0, 202, 202, 1, 149760, 0x8a73af5f
+0, 203, 203, 1, 149760, 0x9079e1c5
+0, 204, 204, 1, 149760, 0x7b70b098
+0, 205, 205, 1, 149760, 0x8a0fc720
+0, 206, 206, 1, 149760, 0x92644eef
+0, 207, 207, 1, 149760, 0x75cc5f7a
+0, 208, 208, 1, 149760, 0xf04b9756
+0, 209, 209, 1, 149760, 0x156b33cd
+0, 210, 210, 1, 149760, 0x4876d087
+0, 211, 211, 1, 149760, 0x393c01c8
+0, 212, 212, 1, 149760, 0x29b0a5d9
+0, 213, 213, 1, 149760, 0xd76249a1
+0, 214, 214, 1, 149760, 0xb946135e
+0, 215, 215, 1, 149760, 0x4968f245
+0, 216, 216, 1, 149760, 0xb91e27b2
+0, 217, 217, 1, 149760, 0x485bfa6c
+0, 218, 218, 1, 149760, 0xe7f9fe28
+0, 219, 219, 1, 149760, 0x46a6a837
+0, 220, 220, 1, 149760, 0xd2cf971c
+0, 221, 221, 1, 149760, 0xcb518e01
+0, 222, 222, 1, 149760, 0x7870fcd4
+0, 223, 223, 1, 149760, 0x8af73981
+0, 224, 224, 1, 149760, 0xa90281a7
+0, 225, 225, 1, 149760, 0x3fd9c634
+0, 226, 226, 1, 149760, 0x5c4e7e8a
+0, 227, 227, 1, 149760, 0x520d80e9
+0, 228, 228, 1, 149760, 0xd94a7e31
+0, 229, 229, 1, 149760, 0x2a846f4e
+0, 230, 230, 1, 149760, 0x71f027f1
+0, 231, 231, 1, 149760, 0x6edbe368
+0, 232, 232, 1, 149760, 0x5c9923eb
+0, 233, 233, 1, 149760, 0xff230eab
+0, 234, 234, 1, 149760, 0xc7a5ca99
+0, 235, 235, 1, 149760, 0x50732f2a
+0, 236, 236, 1, 149760, 0xa9f3c8bc
+0, 237, 237, 1, 149760, 0x7fa53464
+0, 238, 238, 1, 149760, 0xe4c2edcd
+0, 239, 239, 1, 149760, 0x43f1e758
+0, 240, 240, 1, 149760, 0xdb6b153b
+0, 241, 241, 1, 149760, 0x0979d792
+0, 242, 242, 1, 149760, 0xaae4a6fd
+0, 243, 243, 1, 149760, 0x7ffd1046
+0, 244, 244, 1, 149760, 0x083becd8
+0, 245, 245, 1, 149760, 0xba86428d
+0, 246, 246, 1, 149760, 0xd4cf652a
+0, 247, 247, 1, 149760, 0xe518a1e4
+0, 248, 248, 1, 149760, 0xfbcf0017
+0, 249, 249, 1, 149760, 0xd827b5b1
+0, 250, 250, 1, 149760, 0x6b95eb0d
+0, 251, 251, 1, 149760, 0x625bf8f9
+0, 252, 252, 1, 149760, 0xde17b8b8
+0, 253, 253, 1, 149760, 0xfd731e76
+0, 254, 254, 1, 149760, 0xae0ce756
+0, 255, 255, 1, 149760, 0x15ec506d
+0, 256, 256, 1, 149760, 0xfc9dba5c
+0, 257, 257, 1, 149760, 0x87e46ba1
+0, 258, 258, 1, 149760, 0x31f1d787
+0, 259, 259, 1, 149760, 0xfbde528e
+0, 260, 260, 1, 149760, 0x152becf8
+0, 261, 261, 1, 149760, 0x008386d7
+0, 262, 262, 1, 149760, 0x53c00ef9
+0, 263, 263, 1, 149760, 0x322d4f0b
+0, 264, 264, 1, 149760, 0xd31bf0ec
+0, 265, 265, 1, 149760, 0x66b5097e
+0, 266, 266, 1, 149760, 0xa9cd719f
+0, 267, 267, 1, 149760, 0x427cdc52
+0, 268, 268, 1, 149760, 0x6647dabc
+0, 269, 269, 1, 149760, 0x651df15f
+0, 270, 270, 1, 149760, 0x4ce124c7
+0, 271, 271, 1, 149760, 0x8ad42ad7
+0, 272, 272, 1, 149760, 0x7303ce98
+0, 273, 273, 1, 149760, 0x0c8ad3ab
+0, 274, 274, 1, 149760, 0x86859065
+0, 275, 275, 1, 149760, 0x97f23fc7
+0, 276, 276, 1, 149760, 0x6fde3d1a
+0, 277, 277, 1, 149760, 0xca12860e
+0, 278, 278, 1, 149760, 0xd0c98709
+0, 279, 279, 1, 149760, 0x8f234c79
+0, 280, 280, 1, 149760, 0xbc6987fa
+0, 281, 281, 1, 149760, 0x40246698
+0, 282, 282, 1, 149760, 0x7f83b9ad
+0, 283, 283, 1, 149760, 0x87a3596b
+0, 284, 284, 1, 149760, 0x0ba5d7f6
+0, 285, 285, 1, 149760, 0x2a015c97
+0, 286, 286, 1, 149760, 0xa1a73e7b
+0, 287, 287, 1, 149760, 0x3c1d8178
+0, 288, 288, 1, 149760, 0x2207f0b6
+0, 289, 289, 1, 149760, 0x1f56738a
+0, 290, 290, 1, 149760, 0x0014e5b6
+0, 291, 291, 1, 149760, 0xe0113ffa
+0, 292, 292, 1, 149760, 0x7df23683
+0, 293, 293, 1, 149760, 0x2a1afb23
+0, 294, 294, 1, 149760, 0x072ced03
+0, 295, 295, 1, 149760, 0x7afca5d3
+0, 296, 296, 1, 149760, 0x6055b3da
+0, 297, 297, 1, 149760, 0xa785c79c
+0, 298, 298, 1, 149760, 0x3606db52
+0, 299, 299, 1, 149760, 0x007fdd05
diff --git a/tests/ref/fate/hevc-conformance-RQT_A_HHI_4 b/tests/ref/fate/hevc-conformance-RQT_A_HHI_4
new file mode 100644
index 0000000..5f2b9da
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RQT_A_HHI_4
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x5c0f5423
+0, 1, 1, 1, 599040, 0x3d23be58
diff --git a/tests/ref/fate/hevc-conformance-RQT_B_HHI_4 b/tests/ref/fate/hevc-conformance-RQT_B_HHI_4
new file mode 100644
index 0000000..dcf2691
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RQT_B_HHI_4
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x69854954
+0, 1, 1, 1, 599040, 0x695ebc85
diff --git a/tests/ref/fate/hevc-conformance-RQT_C_HHI_4 b/tests/ref/fate/hevc-conformance-RQT_C_HHI_4
new file mode 100644
index 0000000..2e88350
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RQT_C_HHI_4
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x65433cfe
+0, 1, 1, 1, 599040, 0x9309e2c5
diff --git a/tests/ref/fate/hevc-conformance-RQT_D_HHI_4 b/tests/ref/fate/hevc-conformance-RQT_D_HHI_4
new file mode 100644
index 0000000..7f73896
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RQT_D_HHI_4
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x88d741bf
+0, 1, 1, 1, 599040, 0xbbd9ab22
diff --git a/tests/ref/fate/hevc-conformance-RQT_E_HHI_4 b/tests/ref/fate/hevc-conformance-RQT_E_HHI_4
new file mode 100644
index 0000000..f062318
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RQT_E_HHI_4
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0xce2e511d
+0, 1, 1, 1, 599040, 0xe55192d0
diff --git a/tests/ref/fate/hevc-conformance-RQT_F_HHI_4 b/tests/ref/fate/hevc-conformance-RQT_F_HHI_4
new file mode 100644
index 0000000..26bf5ac
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RQT_F_HHI_4
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x65433cfe
+0, 1, 1, 1, 599040, 0x6f99cc5f
diff --git a/tests/ref/fate/hevc-conformance-RQT_G_HHI_4 b/tests/ref/fate/hevc-conformance-RQT_G_HHI_4
new file mode 100644
index 0000000..d36ea01
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-RQT_G_HHI_4
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x5c0f5423
+0, 1, 1, 1, 599040, 0xe805b181
diff --git a/tests/ref/fate/hevc-conformance-SAO_A_MediaTek_4 b/tests/ref/fate/hevc-conformance-SAO_A_MediaTek_4
new file mode 100644
index 0000000..01226d9
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-SAO_A_MediaTek_4
@@ -0,0 +1,61 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x304198c2
+0, 1, 1, 1, 149760, 0xe765e30d
+0, 2, 2, 1, 149760, 0x0130a054
+0, 3, 3, 1, 149760, 0x169ed0c3
+0, 4, 4, 1, 149760, 0x334881a5
+0, 5, 5, 1, 149760, 0x06cadd37
+0, 6, 6, 1, 149760, 0x5ec4a7ee
+0, 7, 7, 1, 149760, 0x595fd534
+0, 8, 8, 1, 149760, 0xa1d97197
+0, 9, 9, 1, 149760, 0xf79a9d84
+0, 10, 10, 1, 149760, 0x10d84f28
+0, 11, 11, 1, 149760, 0xab375848
+0, 12, 12, 1, 149760, 0x3079f8ca
+0, 13, 13, 1, 149760, 0xac101dfb
+0, 14, 14, 1, 149760, 0x5354f852
+0, 15, 15, 1, 149760, 0x64d709d5
+0, 16, 16, 1, 149760, 0xff669ff2
+0, 17, 17, 1, 149760, 0xd20dd474
+0, 18, 18, 1, 149760, 0x32439e22
+0, 19, 19, 1, 149760, 0x3ae5a118
+0, 20, 20, 1, 149760, 0xebe245ef
+0, 21, 21, 1, 149760, 0x9d046e35
+0, 22, 22, 1, 149760, 0x2e5b2347
+0, 23, 23, 1, 149760, 0x0e683e86
+0, 24, 24, 1, 149760, 0xccc1019e
+0, 25, 25, 1, 149760, 0x42a9571a
+0, 26, 26, 1, 149760, 0x8999386c
+0, 27, 27, 1, 149760, 0x3d164645
+0, 28, 28, 1, 149760, 0x657afc5e
+0, 29, 29, 1, 149760, 0x06f832f9
+0, 30, 30, 1, 149760, 0xfbedfe1e
+0, 31, 31, 1, 149760, 0x1edc2fc5
+0, 32, 32, 1, 149760, 0xe1cee4e7
+0, 33, 33, 1, 149760, 0x43a823e0
+0, 34, 34, 1, 149760, 0xc2f42916
+0, 35, 35, 1, 149760, 0x51db1483
+0, 36, 36, 1, 149760, 0x54a9d6bf
+0, 37, 37, 1, 149760, 0x7324e246
+0, 38, 38, 1, 149760, 0x2523cc9d
+0, 39, 39, 1, 149760, 0xfa3bdce3
+0, 40, 40, 1, 149760, 0xcf9fb7bb
+0, 41, 41, 1, 149760, 0xe914e23c
+0, 42, 42, 1, 149760, 0x6c9fd72a
+0, 43, 43, 1, 149760, 0x3580cca9
+0, 44, 44, 1, 149760, 0x1d4ec5c0
+0, 45, 45, 1, 149760, 0x52c4d418
+0, 46, 46, 1, 149760, 0xb728ae3e
+0, 47, 47, 1, 149760, 0x6616ae50
+0, 48, 48, 1, 149760, 0x6f1a919d
+0, 49, 49, 1, 149760, 0x6e76b774
+0, 50, 50, 1, 149760, 0x6075b37d
+0, 51, 51, 1, 149760, 0xeeb7b8df
+0, 52, 52, 1, 149760, 0xfd979056
+0, 53, 53, 1, 149760, 0xc0fda5ee
+0, 54, 54, 1, 149760, 0xd1329055
+0, 55, 55, 1, 149760, 0x9b179f0f
+0, 56, 56, 1, 149760, 0x7461850a
+0, 57, 57, 1, 149760, 0xe63a86ea
+0, 58, 58, 1, 149760, 0xe85c6f94
+0, 59, 59, 1, 149760, 0x0b857d13
diff --git a/tests/ref/fate/hevc-conformance-SAO_B_MediaTek_5 b/tests/ref/fate/hevc-conformance-SAO_B_MediaTek_5
new file mode 100644
index 0000000..9da0268
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-SAO_B_MediaTek_5
@@ -0,0 +1,61 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0xe56f6a5c
+0, 1, 1, 1, 599040, 0x31ec1bb9
+0, 2, 2, 1, 599040, 0xf3ce0311
+0, 3, 3, 1, 599040, 0x1ae1c223
+0, 4, 4, 1, 599040, 0x4369499d
+0, 5, 5, 1, 599040, 0xd7366bd6
+0, 6, 6, 1, 599040, 0x6d3a9099
+0, 7, 7, 1, 599040, 0x49dea495
+0, 8, 8, 1, 599040, 0x375640e7
+0, 9, 9, 1, 599040, 0x76b6f9b0
+0, 10, 10, 1, 599040, 0x7d1f48cf
+0, 11, 11, 1, 599040, 0x4a01899c
+0, 12, 12, 1, 599040, 0x34ff06e6
+0, 13, 13, 1, 599040, 0x270d874f
+0, 14, 14, 1, 599040, 0x5a091d5c
+0, 15, 15, 1, 599040, 0x36406961
+0, 16, 16, 1, 599040, 0xd32f2687
+0, 17, 17, 1, 599040, 0x8d533cb5
+0, 18, 18, 1, 599040, 0x5f189f98
+0, 19, 19, 1, 599040, 0x32b76de3
+0, 20, 20, 1, 599040, 0x2dd0e738
+0, 21, 21, 1, 599040, 0xbc24fe31
+0, 22, 22, 1, 599040, 0xfd5e6578
+0, 23, 23, 1, 599040, 0x23ea676c
+0, 24, 24, 1, 599040, 0xa86d1f70
+0, 25, 25, 1, 599040, 0xef35e81e
+0, 26, 26, 1, 599040, 0x19e5b355
+0, 27, 27, 1, 599040, 0x9dab17b3
+0, 28, 28, 1, 599040, 0x1aebe590
+0, 29, 29, 1, 599040, 0x6fd9b16e
+0, 30, 30, 1, 599040, 0xd2f3087b
+0, 31, 31, 1, 599040, 0x4bdc5019
+0, 32, 32, 1, 599040, 0xeccd10a0
+0, 33, 33, 1, 599040, 0x1eacd33c
+0, 34, 34, 1, 599040, 0xc73d2b6d
+0, 35, 35, 1, 599040, 0xe1305f2b
+0, 36, 36, 1, 599040, 0xb66c5e54
+0, 37, 37, 1, 599040, 0x0ac17870
+0, 38, 38, 1, 599040, 0x9d976180
+0, 39, 39, 1, 599040, 0x0be7d418
+0, 40, 40, 1, 599040, 0x5c4fb909
+0, 41, 41, 1, 599040, 0x7a4de7c2
+0, 42, 42, 1, 599040, 0x9c0d3ed3
+0, 43, 43, 1, 599040, 0xf9b2ba7e
+0, 44, 44, 1, 599040, 0x78e77b58
+0, 45, 45, 1, 599040, 0xc30ead17
+0, 46, 46, 1, 599040, 0x647c9095
+0, 47, 47, 1, 599040, 0x070d61a3
+0, 48, 48, 1, 599040, 0x0ec33c61
+0, 49, 49, 1, 599040, 0x0adcf4f3
+0, 50, 50, 1, 599040, 0x5cbb5aa6
+0, 51, 51, 1, 599040, 0xb9f99f74
+0, 52, 52, 1, 599040, 0xebc3c13e
+0, 53, 53, 1, 599040, 0x40e76036
+0, 54, 54, 1, 599040, 0xf08d2df3
+0, 55, 55, 1, 599040, 0x47442b55
+0, 56, 56, 1, 599040, 0x147622c1
+0, 57, 57, 1, 599040, 0xc95508a3
+0, 58, 58, 1, 599040, 0x361b8995
+0, 59, 59, 1, 599040, 0x51086ed4
diff --git a/tests/ref/fate/hevc-conformance-SAO_C_Samsung_4 b/tests/ref/fate/hevc-conformance-SAO_C_Samsung_4
new file mode 100644
index 0000000..f87921d
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-SAO_C_Samsung_4
@@ -0,0 +1,61 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xf923a1a0
+0, 1, 1, 1, 149760, 0x614d851a
+0, 2, 2, 1, 149760, 0xc3976ce4
+0, 3, 3, 1, 149760, 0x39925bdc
+0, 4, 4, 1, 149760, 0x86067422
+0, 5, 5, 1, 149760, 0x60dc6078
+0, 6, 6, 1, 149760, 0xac79a412
+0, 7, 7, 1, 149760, 0x3b1bab1e
+0, 8, 8, 1, 149760, 0x7562555f
+0, 9, 9, 1, 149760, 0xf0a2385f
+0, 10, 10, 1, 149760, 0xd2661fa6
+0, 11, 11, 1, 149760, 0x89b30a0a
+0, 12, 12, 1, 149760, 0x3c59f8cb
+0, 13, 13, 1, 149760, 0x70e4da0a
+0, 14, 14, 1, 149760, 0x5e60caa8
+0, 15, 15, 1, 149760, 0x9828a7e0
+0, 16, 16, 1, 149760, 0x11e069a1
+0, 17, 17, 1, 149760, 0xe98a55c2
+0, 18, 18, 1, 149760, 0xaa9f64e5
+0, 19, 19, 1, 149760, 0x03c32cea
+0, 20, 20, 1, 149760, 0x869e0f6e
+0, 21, 21, 1, 149760, 0x54baeff8
+0, 22, 22, 1, 149760, 0xf1f8cc04
+0, 23, 23, 1, 149760, 0x1724aafb
+0, 24, 24, 1, 149760, 0xaf01b9f8
+0, 25, 25, 1, 149760, 0xb1b5bbe9
+0, 26, 26, 1, 149760, 0xd9e6d5a4
+0, 27, 27, 1, 149760, 0x8351ca2d
+0, 28, 28, 1, 149760, 0x38dceffe
+0, 29, 29, 1, 149760, 0x3bffe1c4
+0, 30, 30, 1, 149760, 0x4075b534
+0, 31, 31, 1, 149760, 0x0e8fb246
+0, 32, 32, 1, 149760, 0x70fceafb
+0, 33, 33, 1, 149760, 0x940bec8d
+0, 34, 34, 1, 149760, 0x7d34f896
+0, 35, 35, 1, 149760, 0x39a1d77f
+0, 36, 36, 1, 149760, 0x9755e104
+0, 37, 37, 1, 149760, 0xd584cb48
+0, 38, 38, 1, 149760, 0x06ecdd44
+0, 39, 39, 1, 149760, 0x0226a40d
+0, 40, 40, 1, 149760, 0xb53aaf56
+0, 41, 41, 1, 149760, 0xdad4a984
+0, 42, 42, 1, 149760, 0xa58c9eb0
+0, 43, 43, 1, 149760, 0x7330bde6
+0, 44, 44, 1, 149760, 0x98fcabd9
+0, 45, 45, 1, 149760, 0x9570b74a
+0, 46, 46, 1, 149760, 0x3c1eab60
+0, 47, 47, 1, 149760, 0x2038a069
+0, 48, 48, 1, 149760, 0x672fa347
+0, 49, 49, 1, 149760, 0xa7328b16
+0, 50, 50, 1, 149760, 0x677b6a87
+0, 51, 51, 1, 149760, 0xb036b028
+0, 52, 52, 1, 149760, 0x7a7f9966
+0, 53, 53, 1, 149760, 0xc34b7c39
+0, 54, 54, 1, 149760, 0xb44345ed
+0, 55, 55, 1, 149760, 0x90193c4a
+0, 56, 56, 1, 149760, 0x90986e7b
+0, 57, 57, 1, 149760, 0x5e8e6545
+0, 58, 58, 1, 149760, 0x3ac7758e
+0, 59, 59, 1, 149760, 0x4dd271fb
diff --git a/tests/ref/fate/hevc-conformance-SAO_D_Samsung_4 b/tests/ref/fate/hevc-conformance-SAO_D_Samsung_4
new file mode 100644
index 0000000..ce1cefe
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-SAO_D_Samsung_4
@@ -0,0 +1,61 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x0d2edbbc
+0, 1, 1, 1, 149760, 0x4830af95
+0, 2, 2, 1, 149760, 0x39e8d3bb
+0, 3, 3, 1, 149760, 0x3cc8d639
+0, 4, 4, 1, 149760, 0xfcfe8415
+0, 5, 5, 1, 149760, 0xa6cf9a48
+0, 6, 6, 1, 149760, 0x0fe191b3
+0, 7, 7, 1, 149760, 0x71d26e20
+0, 8, 8, 1, 149760, 0x1ee5541a
+0, 9, 9, 1, 149760, 0x4ac56652
+0, 10, 10, 1, 149760, 0x967e7c2c
+0, 11, 11, 1, 149760, 0x2011ba0c
+0, 12, 12, 1, 149760, 0x2da4bc05
+0, 13, 13, 1, 149760, 0x6354fac2
+0, 14, 14, 1, 149760, 0x799e66ce
+0, 15, 15, 1, 149760, 0x2ca24940
+0, 16, 16, 1, 149760, 0x2a102e28
+0, 17, 17, 1, 149760, 0x652edcce
+0, 18, 18, 1, 149760, 0xb1c34a9a
+0, 19, 19, 1, 149760, 0xfae6ce90
+0, 20, 20, 1, 149760, 0xf42fddbf
+0, 21, 21, 1, 149760, 0x2a8532c3
+0, 22, 22, 1, 149760, 0xbe43addc
+0, 23, 23, 1, 149760, 0x3545f94a
+0, 24, 24, 1, 149760, 0xa35fa6fa
+0, 25, 25, 1, 149760, 0xfed8577f
+0, 26, 26, 1, 149760, 0xac03b492
+0, 27, 27, 1, 149760, 0x1fbdabc9
+0, 28, 28, 1, 149760, 0x99707175
+0, 29, 29, 1, 149760, 0x95e69481
+0, 30, 30, 1, 149760, 0xd68412d8
+0, 31, 31, 1, 149760, 0x9f900e37
+0, 32, 32, 1, 149760, 0x7e6eceba
+0, 33, 33, 1, 149760, 0xd1ca85af
+0, 34, 34, 1, 149760, 0x352b1d50
+0, 35, 35, 1, 149760, 0xdef3e377
+0, 36, 36, 1, 149760, 0x08efcc16
+0, 37, 37, 1, 149760, 0xc20a7c74
+0, 38, 38, 1, 149760, 0xa8e45939
+0, 39, 39, 1, 149760, 0x322546cf
+0, 40, 40, 1, 149760, 0xf7167766
+0, 41, 41, 1, 149760, 0x959f808f
+0, 42, 42, 1, 149760, 0xcca5ccc3
+0, 43, 43, 1, 149760, 0x18789407
+0, 44, 44, 1, 149760, 0xf6c97e87
+0, 45, 45, 1, 149760, 0x58aaba55
+0, 46, 46, 1, 149760, 0xc3529005
+0, 47, 47, 1, 149760, 0x3847adb4
+0, 48, 48, 1, 149760, 0xa4d589db
+0, 49, 49, 1, 149760, 0x9c50dd88
+0, 50, 50, 1, 149760, 0xad087c44
+0, 51, 51, 1, 149760, 0x4a6b656d
+0, 52, 52, 1, 149760, 0x6ec79bcf
+0, 53, 53, 1, 149760, 0x82756cb6
+0, 54, 54, 1, 149760, 0x8b3a9a6a
+0, 55, 55, 1, 149760, 0x775c0430
+0, 56, 56, 1, 149760, 0xbaa08d27
+0, 57, 57, 1, 149760, 0x686cd03f
+0, 58, 58, 1, 149760, 0x1b10dc94
+0, 59, 59, 1, 149760, 0xde81e414
diff --git a/tests/ref/fate/hevc-conformance-SAO_E_Canon_4 b/tests/ref/fate/hevc-conformance-SAO_E_Canon_4
new file mode 100644
index 0000000..92aa7f4
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-SAO_E_Canon_4
@@ -0,0 +1,17 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x1613b277
+0, 1, 1, 1, 149760, 0xf92d5543
+0, 2, 2, 1, 149760, 0xf119ba8e
+0, 3, 3, 1, 149760, 0xbce35d0a
+0, 4, 4, 1, 149760, 0x0f4dc325
+0, 5, 5, 1, 149760, 0xc95379ae
+0, 6, 6, 1, 149760, 0xbf4e9b84
+0, 7, 7, 1, 149760, 0x3a7c3cdf
+0, 8, 8, 1, 149760, 0x8d5e8895
+0, 9, 9, 1, 149760, 0x3128397e
+0, 10, 10, 1, 149760, 0x4389dee6
+0, 11, 11, 1, 149760, 0x8a6a7236
+0, 12, 12, 1, 149760, 0x638049ef
+0, 13, 13, 1, 149760, 0x0075da54
+0, 14, 14, 1, 149760, 0x5fd84a25
+0, 15, 15, 1, 149760, 0xfbd4af2b
diff --git a/tests/ref/fate/hevc-conformance-SAO_F_Canon_3 b/tests/ref/fate/hevc-conformance-SAO_F_Canon_3
new file mode 100644
index 0000000..cf24055
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-SAO_F_Canon_3
@@ -0,0 +1,17 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x92b5107a
+0, 1, 1, 1, 149760, 0x97eb31ef
+0, 2, 2, 1, 149760, 0xeb743e30
+0, 3, 3, 1, 149760, 0x5fc53434
+0, 4, 4, 1, 149760, 0x75fb1d63
+0, 5, 5, 1, 149760, 0xba0aeb27
+0, 6, 6, 1, 149760, 0x3f0f1780
+0, 7, 7, 1, 149760, 0xf5d0f052
+0, 8, 8, 1, 149760, 0x598ee54e
+0, 9, 9, 1, 149760, 0x09fcf908
+0, 10, 10, 1, 149760, 0x68209041
+0, 11, 11, 1, 149760, 0x05f519e9
+0, 12, 12, 1, 149760, 0xfdecf9b3
+0, 13, 13, 1, 149760, 0x40c96df8
+0, 14, 14, 1, 149760, 0x4b3d1b7b
+0, 15, 15, 1, 149760, 0xc0691cd9
diff --git a/tests/ref/fate/hevc-conformance-SAO_G_Canon_3 b/tests/ref/fate/hevc-conformance-SAO_G_Canon_3
new file mode 100644
index 0000000..5ce6772
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-SAO_G_Canon_3
@@ -0,0 +1,17 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xc4f239e0
+0, 1, 1, 1, 149760, 0xf57a2e44
+0, 2, 2, 1, 149760, 0xbf1e9995
+0, 3, 3, 1, 149760, 0x5fa25087
+0, 4, 4, 1, 149760, 0x709b4c3f
+0, 5, 5, 1, 149760, 0x63abbd5c
+0, 6, 6, 1, 149760, 0xbd87092a
+0, 7, 7, 1, 149760, 0x59156f4a
+0, 8, 8, 1, 149760, 0xf8ed7d88
+0, 9, 9, 1, 149760, 0xdac1cecf
+0, 10, 10, 1, 149760, 0x7ba3b408
+0, 11, 11, 1, 149760, 0xad4bd5f5
+0, 12, 12, 1, 149760, 0x4b1f83c6
+0, 13, 13, 1, 149760, 0x7329797f
+0, 14, 14, 1, 149760, 0x1d201f16
+0, 15, 15, 1, 149760, 0xde263a30
diff --git a/tests/ref/fate/hevc-conformance-SDH_A_Orange_3 b/tests/ref/fate/hevc-conformance-SDH_A_Orange_3
new file mode 100644
index 0000000..caf90ee
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-SDH_A_Orange_3
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0x0117aa5d
+0, 1, 1, 1, 3110400, 0xa737bc56
diff --git a/tests/ref/fate/hevc-conformance-SLICES_A_Rovi_3 b/tests/ref/fate/hevc-conformance-SLICES_A_Rovi_3
new file mode 100644
index 0000000..f884f7f
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-SLICES_A_Rovi_3
@@ -0,0 +1,10 @@
+#tb 0: 1/25
+0, 0, 0, 1, 460800, 0x7f06cb02
+0, 1, 1, 1, 460800, 0x1ad483aa
+0, 2, 2, 1, 460800, 0x1bbbc991
+0, 3, 3, 1, 460800, 0x8fe7afa5
+0, 4, 4, 1, 460800, 0xe609cb0b
+0, 5, 5, 1, 460800, 0xcc65fec8
+0, 6, 6, 1, 460800, 0xa0601519
+0, 7, 7, 1, 460800, 0x8b0d3002
+0, 8, 8, 1, 460800, 0x7b1191af
diff --git a/tests/ref/fate/hevc-conformance-SLIST_A_Sony_4 b/tests/ref/fate/hevc-conformance-SLIST_A_Sony_4
new file mode 100644
index 0000000..ebb65c3
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-SLIST_A_Sony_4
@@ -0,0 +1,66 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0xbd0eb43e
+0, 1, 1, 1, 599040, 0x4c3a98b5
+0, 2, 2, 1, 599040, 0x105410dc
+0, 3, 3, 1, 599040, 0xffaff69c
+0, 4, 4, 1, 599040, 0x39cb22ea
+0, 5, 5, 1, 599040, 0xa19296c3
+0, 6, 6, 1, 599040, 0x84cad39d
+0, 7, 7, 1, 599040, 0x5dc5c5a9
+0, 8, 8, 1, 599040, 0xc6a2c0dd
+0, 9, 9, 1, 599040, 0xeb5947bf
+0, 10, 10, 1, 599040, 0x9f8f9ce5
+0, 11, 11, 1, 599040, 0xdce5be4e
+0, 12, 12, 1, 599040, 0x07141c84
+0, 13, 13, 1, 599040, 0x3a05273d
+0, 14, 14, 1, 599040, 0xa16a112c
+0, 15, 15, 1, 599040, 0x6fa79123
+0, 16, 16, 1, 599040, 0xbda4cf46
+0, 17, 17, 1, 599040, 0xa5a81a05
+0, 18, 18, 1, 599040, 0x7370af29
+0, 19, 19, 1, 599040, 0xbd70e89e
+0, 20, 20, 1, 599040, 0xe7850613
+0, 21, 21, 1, 599040, 0xfaa8cf89
+0, 22, 22, 1, 599040, 0x30a78a21
+0, 23, 23, 1, 599040, 0x5520a8cf
+0, 24, 24, 1, 599040, 0xbcd93ea7
+0, 25, 25, 1, 599040, 0xd8ce632c
+0, 26, 26, 1, 599040, 0x87c6476f
+0, 27, 27, 1, 599040, 0xf6799dcc
+0, 28, 28, 1, 599040, 0xc0370664
+0, 29, 29, 1, 599040, 0x17196bd3
+0, 30, 30, 1, 599040, 0xe7ae6de3
+0, 31, 31, 1, 599040, 0x0345bc72
+0, 32, 32, 1, 599040, 0x7b86141e
+0, 33, 33, 1, 599040, 0x65564792
+0, 34, 34, 1, 599040, 0xf90c7f54
+0, 35, 35, 1, 599040, 0x00ce2f3c
+0, 36, 36, 1, 599040, 0xe6b185f2
+0, 37, 37, 1, 599040, 0x513942f1
+0, 38, 38, 1, 599040, 0x7c27b03a
+0, 39, 39, 1, 599040, 0xa201fea3
+0, 40, 40, 1, 599040, 0x5023fd92
+0, 41, 41, 1, 599040, 0xe05ba218
+0, 42, 42, 1, 599040, 0x84b61765
+0, 43, 43, 1, 599040, 0xfa6c8f65
+0, 44, 44, 1, 599040, 0xede8ef78
+0, 45, 45, 1, 599040, 0xcd2763f2
+0, 46, 46, 1, 599040, 0xb83e3bc6
+0, 47, 47, 1, 599040, 0x99fb3a3e
+0, 48, 48, 1, 599040, 0x3dd1e5ac
+0, 49, 49, 1, 599040, 0x776d7464
+0, 50, 50, 1, 599040, 0xaea89891
+0, 51, 51, 1, 599040, 0xfc0f1ec9
+0, 52, 52, 1, 599040, 0x2621f36f
+0, 53, 53, 1, 599040, 0x41101bbc
+0, 54, 54, 1, 599040, 0x7a5d4d0e
+0, 55, 55, 1, 599040, 0xc04fb148
+0, 56, 56, 1, 599040, 0x889d8186
+0, 57, 57, 1, 599040, 0x26f091bf
+0, 58, 58, 1, 599040, 0xe6644a2d
+0, 59, 59, 1, 599040, 0xd48efb7f
+0, 60, 60, 1, 599040, 0xe25204e3
+0, 61, 61, 1, 599040, 0x928f2efd
+0, 62, 62, 1, 599040, 0x535a4f2d
+0, 63, 63, 1, 599040, 0x2672ad63
+0, 64, 64, 1, 599040, 0x194f1463
diff --git a/tests/ref/fate/hevc-conformance-SLIST_B_Sony_8 b/tests/ref/fate/hevc-conformance-SLIST_B_Sony_8
new file mode 100644
index 0000000..fc39039
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-SLIST_B_Sony_8
@@ -0,0 +1,66 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0xbd0eb43e
+0, 1, 1, 1, 599040, 0x3ea696c4
+0, 2, 2, 1, 599040, 0x866beffc
+0, 3, 3, 1, 599040, 0x89622860
+0, 4, 4, 1, 599040, 0x416bcaf8
+0, 5, 5, 1, 599040, 0x4098709b
+0, 6, 6, 1, 599040, 0x8d1ef343
+0, 7, 7, 1, 599040, 0xbd1bbc79
+0, 8, 8, 1, 599040, 0xc6a2c0dd
+0, 9, 9, 1, 599040, 0x438cc40e
+0, 10, 10, 1, 599040, 0xb666a438
+0, 11, 11, 1, 599040, 0x114580e4
+0, 12, 12, 1, 599040, 0xb75c41dc
+0, 13, 13, 1, 599040, 0x52e1e32f
+0, 14, 14, 1, 599040, 0x22835865
+0, 15, 15, 1, 599040, 0xfb0e0003
+0, 16, 16, 1, 599040, 0xebcb1ef9
+0, 17, 17, 1, 599040, 0xd6939619
+0, 18, 18, 1, 599040, 0xe22afdd8
+0, 19, 19, 1, 599040, 0xff4a248f
+0, 20, 20, 1, 599040, 0x9fc3878e
+0, 21, 21, 1, 599040, 0xce2f6499
+0, 22, 22, 1, 599040, 0x04aa9986
+0, 23, 23, 1, 599040, 0x68ba9838
+0, 24, 24, 1, 599040, 0x62e950a9
+0, 25, 25, 1, 599040, 0x5161526d
+0, 26, 26, 1, 599040, 0xcdde709e
+0, 27, 27, 1, 599040, 0x8c48ded1
+0, 28, 28, 1, 599040, 0x3451ecbb
+0, 29, 29, 1, 599040, 0xfc5a5fca
+0, 30, 30, 1, 599040, 0x7c0090fe
+0, 31, 31, 1, 599040, 0xbc4eb1de
+0, 32, 32, 1, 599040, 0x5350cf4f
+0, 33, 33, 1, 599040, 0x175152d6
+0, 34, 34, 1, 599040, 0xcf65acea
+0, 35, 35, 1, 599040, 0x099a7298
+0, 36, 36, 1, 599040, 0x31b7a2a2
+0, 37, 37, 1, 599040, 0xd6a71415
+0, 38, 38, 1, 599040, 0xe68880e7
+0, 39, 39, 1, 599040, 0x0c7d0373
+0, 40, 40, 1, 599040, 0xfb56ac78
+0, 41, 41, 1, 599040, 0x1177b0dd
+0, 42, 42, 1, 599040, 0x1393026f
+0, 43, 43, 1, 599040, 0xc6346b58
+0, 44, 44, 1, 599040, 0x2949cd11
+0, 45, 45, 1, 599040, 0xff867f22
+0, 46, 46, 1, 599040, 0xef196e4d
+0, 47, 47, 1, 599040, 0x17a2332c
+0, 48, 48, 1, 599040, 0x45d59fbc
+0, 49, 49, 1, 599040, 0x5f51575c
+0, 50, 50, 1, 599040, 0x6049a451
+0, 51, 51, 1, 599040, 0x4d6086ac
+0, 52, 52, 1, 599040, 0xd709596b
+0, 53, 53, 1, 599040, 0xacdbc22f
+0, 54, 54, 1, 599040, 0x45c11bb5
+0, 55, 55, 1, 599040, 0x608a7c7e
+0, 56, 56, 1, 599040, 0x242a67c9
+0, 57, 57, 1, 599040, 0x2d186d8a
+0, 58, 58, 1, 599040, 0x07ed9fd5
+0, 59, 59, 1, 599040, 0xaee9a49b
+0, 60, 60, 1, 599040, 0xaeb2b2a2
+0, 61, 61, 1, 599040, 0x4ca2d84b
+0, 62, 62, 1, 599040, 0x4254b5f6
+0, 63, 63, 1, 599040, 0x105c7a25
+0, 64, 64, 1, 599040, 0x87b51bce
diff --git a/tests/ref/fate/hevc-conformance-SLIST_C_Sony_3 b/tests/ref/fate/hevc-conformance-SLIST_C_Sony_3
new file mode 100644
index 0000000..482e56f
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-SLIST_C_Sony_3
@@ -0,0 +1,66 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0xc3e98658
+0, 1, 1, 1, 599040, 0x621fa0b7
+0, 2, 2, 1, 599040, 0x53b2e637
+0, 3, 3, 1, 599040, 0x1db118c2
+0, 4, 4, 1, 599040, 0xa25003ba
+0, 5, 5, 1, 599040, 0x51de524b
+0, 6, 6, 1, 599040, 0x5f01f648
+0, 7, 7, 1, 599040, 0x43d8c9cb
+0, 8, 8, 1, 599040, 0xf7f6c7f6
+0, 9, 9, 1, 599040, 0xb08885ec
+0, 10, 10, 1, 599040, 0x1e6e91a7
+0, 11, 11, 1, 599040, 0x18549abd
+0, 12, 12, 1, 599040, 0xef523cbc
+0, 13, 13, 1, 599040, 0x87985e99
+0, 14, 14, 1, 599040, 0x37521482
+0, 15, 15, 1, 599040, 0xe9fbc0ce
+0, 16, 16, 1, 599040, 0x20bab233
+0, 17, 17, 1, 599040, 0xbe3525e6
+0, 18, 18, 1, 599040, 0xace46e50
+0, 19, 19, 1, 599040, 0xf709b3a9
+0, 20, 20, 1, 599040, 0xf2690bc8
+0, 21, 21, 1, 599040, 0x7eacdec3
+0, 22, 22, 1, 599040, 0xaed66c65
+0, 23, 23, 1, 599040, 0x066b2fa6
+0, 24, 24, 1, 599040, 0x5dc050bd
+0, 25, 25, 1, 599040, 0x170e7de1
+0, 26, 26, 1, 599040, 0x2ccd7b16
+0, 27, 27, 1, 599040, 0x4f7bc972
+0, 28, 28, 1, 599040, 0x72d7f274
+0, 29, 29, 1, 599040, 0x44d2396e
+0, 30, 30, 1, 599040, 0xe4dc9b54
+0, 31, 31, 1, 599040, 0xfacba54d
+0, 32, 32, 1, 599040, 0x7b86141e
+0, 33, 33, 1, 599040, 0x65564792
+0, 34, 34, 1, 599040, 0xf90c7f54
+0, 35, 35, 1, 599040, 0x00ce2f3c
+0, 36, 36, 1, 599040, 0xe6b185f2
+0, 37, 37, 1, 599040, 0x513942f1
+0, 38, 38, 1, 599040, 0x7c27b03a
+0, 39, 39, 1, 599040, 0xa201fea3
+0, 40, 40, 1, 599040, 0x5023fd92
+0, 41, 41, 1, 599040, 0xe05ba218
+0, 42, 42, 1, 599040, 0x84b61765
+0, 43, 43, 1, 599040, 0xfa6c8f65
+0, 44, 44, 1, 599040, 0xede8ef78
+0, 45, 45, 1, 599040, 0xcd2763f2
+0, 46, 46, 1, 599040, 0xb83e3bc6
+0, 47, 47, 1, 599040, 0x99fb3a3e
+0, 48, 48, 1, 599040, 0x3dd1e5ac
+0, 49, 49, 1, 599040, 0x776d7464
+0, 50, 50, 1, 599040, 0xaea89891
+0, 51, 51, 1, 599040, 0xfc0f1ec9
+0, 52, 52, 1, 599040, 0x2621f36f
+0, 53, 53, 1, 599040, 0x41101bbc
+0, 54, 54, 1, 599040, 0x7a5d4d0e
+0, 55, 55, 1, 599040, 0xc04fb148
+0, 56, 56, 1, 599040, 0x889d8186
+0, 57, 57, 1, 599040, 0x26f091bf
+0, 58, 58, 1, 599040, 0xe6644a2d
+0, 59, 59, 1, 599040, 0xd48efb7f
+0, 60, 60, 1, 599040, 0xe25204e3
+0, 61, 61, 1, 599040, 0x928f2efd
+0, 62, 62, 1, 599040, 0x535a4f2d
+0, 63, 63, 1, 599040, 0x2672ad63
+0, 64, 64, 1, 599040, 0x194f1463
diff --git a/tests/ref/fate/hevc-conformance-SLIST_D_Sony_9 b/tests/ref/fate/hevc-conformance-SLIST_D_Sony_9
new file mode 100644
index 0000000..384f81f
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-SLIST_D_Sony_9
@@ -0,0 +1,66 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0xf3038515
+0, 1, 1, 1, 599040, 0xb1bc9386
+0, 2, 2, 1, 599040, 0xa069e86f
+0, 3, 3, 1, 599040, 0xdf7c4cb7
+0, 4, 4, 1, 599040, 0xefaa2ac5
+0, 5, 5, 1, 599040, 0x81c67c18
+0, 6, 6, 1, 599040, 0xeb1a0669
+0, 7, 7, 1, 599040, 0xbab3c0b8
+0, 8, 8, 1, 599040, 0x82b99936
+0, 9, 9, 1, 599040, 0x027a90d1
+0, 10, 10, 1, 599040, 0x5d6d7489
+0, 11, 11, 1, 599040, 0xeaaf6d39
+0, 12, 12, 1, 599040, 0x7788f8fa
+0, 13, 13, 1, 599040, 0x654393e8
+0, 14, 14, 1, 599040, 0xc6c2237c
+0, 15, 15, 1, 599040, 0x8b16d890
+0, 16, 16, 1, 599040, 0x2c36eed0
+0, 17, 17, 1, 599040, 0x02792aa8
+0, 18, 18, 1, 599040, 0xf4088e47
+0, 19, 19, 1, 599040, 0xea9796ad
+0, 20, 20, 1, 599040, 0xa4aecc01
+0, 21, 21, 1, 599040, 0x2ec8c1c4
+0, 22, 22, 1, 599040, 0xcfa87d49
+0, 23, 23, 1, 599040, 0x012b62f1
+0, 24, 24, 1, 599040, 0xd8b72ae0
+0, 25, 25, 1, 599040, 0xe0ca1977
+0, 26, 26, 1, 599040, 0x3f048981
+0, 27, 27, 1, 599040, 0xe416a928
+0, 28, 28, 1, 599040, 0xdfef9086
+0, 29, 29, 1, 599040, 0xd810cd6a
+0, 30, 30, 1, 599040, 0x11fab789
+0, 31, 31, 1, 599040, 0x90a890d5
+0, 32, 32, 1, 599040, 0x0dabef8d
+0, 33, 33, 1, 599040, 0x7a32557d
+0, 34, 34, 1, 599040, 0xc3427914
+0, 35, 35, 1, 599040, 0x65266a45
+0, 36, 36, 1, 599040, 0x8b5e9213
+0, 37, 37, 1, 599040, 0x4e2e2b0a
+0, 38, 38, 1, 599040, 0xaebdb406
+0, 39, 39, 1, 599040, 0xca35eadb
+0, 40, 40, 1, 599040, 0xb711adc7
+0, 41, 41, 1, 599040, 0x594d28b9
+0, 42, 42, 1, 599040, 0x27fec3c9
+0, 43, 43, 1, 599040, 0x35fe73ce
+0, 44, 44, 1, 599040, 0x3069c845
+0, 45, 45, 1, 599040, 0x2df2a12d
+0, 46, 46, 1, 599040, 0x96d42f5c
+0, 47, 47, 1, 599040, 0x95d9319b
+0, 48, 48, 1, 599040, 0x4f8c92aa
+0, 49, 49, 1, 599040, 0x29620b31
+0, 50, 50, 1, 599040, 0x3d1441f7
+0, 51, 51, 1, 599040, 0x7040914d
+0, 52, 52, 1, 599040, 0x95a73274
+0, 53, 53, 1, 599040, 0xda51c6c7
+0, 54, 54, 1, 599040, 0x41592676
+0, 55, 55, 1, 599040, 0xf21c682b
+0, 56, 56, 1, 599040, 0x5d6b65cf
+0, 57, 57, 1, 599040, 0x13fc6e8e
+0, 58, 58, 1, 599040, 0xe05ec001
+0, 59, 59, 1, 599040, 0x06113d89
+0, 60, 60, 1, 599040, 0x1d74bd0d
+0, 61, 61, 1, 599040, 0x757ffab3
+0, 62, 62, 1, 599040, 0x0599c7fb
+0, 63, 63, 1, 599040, 0x8aaa91ed
+0, 64, 64, 1, 599040, 0x79582f08
diff --git a/tests/ref/fate/hevc-conformance-STRUCT_A_Samsung_5 b/tests/ref/fate/hevc-conformance-STRUCT_A_Samsung_5
new file mode 100644
index 0000000..da5cfa1
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-STRUCT_A_Samsung_5
@@ -0,0 +1,61 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x479fa7ca
+0, 1, 1, 1, 149760, 0x761fb3a3
+0, 2, 2, 1, 149760, 0xa0f4cd97
+0, 3, 3, 1, 149760, 0x22a0c92b
+0, 4, 4, 1, 149760, 0xdedc8cb2
+0, 5, 5, 1, 149760, 0x38da8674
+0, 6, 6, 1, 149760, 0xe5d77e68
+0, 7, 7, 1, 149760, 0x31cc6196
+0, 8, 8, 1, 149760, 0xdb70f4d3
+0, 9, 9, 1, 149760, 0x966b6f89
+0, 10, 10, 1, 149760, 0x2297ff66
+0, 11, 11, 1, 149760, 0x2a2fa4e7
+0, 12, 12, 1, 149760, 0x217442b7
+0, 13, 13, 1, 149760, 0x5341ff7f
+0, 14, 14, 1, 149760, 0xb413af37
+0, 15, 15, 1, 149760, 0x61c86ce5
+0, 16, 16, 1, 149760, 0x6b1a0c63
+0, 17, 17, 1, 149760, 0x4596d2e5
+0, 18, 18, 1, 149760, 0xafc0abbd
+0, 19, 19, 1, 149760, 0xb9197a81
+0, 20, 20, 1, 149760, 0xf67d43f3
+0, 21, 21, 1, 149760, 0xe7ef11f2
+0, 22, 22, 1, 149760, 0x89180592
+0, 23, 23, 1, 149760, 0xf6900816
+0, 24, 24, 1, 149760, 0x7cb2f3c0
+0, 25, 25, 1, 149760, 0x71c269f5
+0, 26, 26, 1, 149760, 0x19720666
+0, 27, 27, 1, 149760, 0x5794f402
+0, 28, 28, 1, 149760, 0xe08bf8d2
+0, 29, 29, 1, 149760, 0x11638859
+0, 30, 30, 1, 149760, 0x5024fddc
+0, 31, 31, 1, 149760, 0x8b3d4a37
+0, 32, 32, 1, 149760, 0x5f727144
+0, 33, 33, 1, 149760, 0xb6cf2d76
+0, 34, 34, 1, 149760, 0xf528b070
+0, 35, 35, 1, 149760, 0x3e95f116
+0, 36, 36, 1, 149760, 0x1db5f92a
+0, 37, 37, 1, 149760, 0xf8331667
+0, 38, 38, 1, 149760, 0x57ca4161
+0, 39, 39, 1, 149760, 0x7add32bd
+0, 40, 40, 1, 149760, 0x4b84af44
+0, 41, 41, 1, 149760, 0xf3e1eeaf
+0, 42, 42, 1, 149760, 0x0d602ea8
+0, 43, 43, 1, 149760, 0x420bfdf8
+0, 44, 44, 1, 149760, 0x6e2eb72f
+0, 45, 45, 1, 149760, 0x0450e4ba
+0, 46, 46, 1, 149760, 0xbfa60971
+0, 47, 47, 1, 149760, 0x89791529
+0, 48, 48, 1, 149760, 0x4e32e37b
+0, 49, 49, 1, 149760, 0x273f0927
+0, 50, 50, 1, 149760, 0x0373f961
+0, 51, 51, 1, 149760, 0x5f105bd2
+0, 52, 52, 1, 149760, 0x6b1b290a
+0, 53, 53, 1, 149760, 0xeaad4ccb
+0, 54, 54, 1, 149760, 0xeb21c2e6
+0, 55, 55, 1, 149760, 0x342ff483
+0, 56, 56, 1, 149760, 0x0ac70398
+0, 57, 57, 1, 149760, 0x5366fd7c
+0, 58, 58, 1, 149760, 0xc05249b6
+0, 59, 59, 1, 149760, 0x32279e70
diff --git a/tests/ref/fate/hevc-conformance-STRUCT_B_Samsung_4 b/tests/ref/fate/hevc-conformance-STRUCT_B_Samsung_4
new file mode 100644
index 0000000..c03111c
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-STRUCT_B_Samsung_4
@@ -0,0 +1,61 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x4b489a60
+0, 1, 1, 1, 599040, 0x80369c9a
+0, 2, 2, 1, 599040, 0x33189b1a
+0, 3, 3, 1, 599040, 0x01d73abb
+0, 4, 4, 1, 599040, 0xd5de0ab7
+0, 5, 5, 1, 599040, 0xf7b9f1c3
+0, 6, 6, 1, 599040, 0xe72b6446
+0, 7, 7, 1, 599040, 0xf78cc5d6
+0, 8, 8, 1, 599040, 0x9c6d33a2
+0, 9, 9, 1, 599040, 0xacb6cb08
+0, 10, 10, 1, 599040, 0x2a215019
+0, 11, 11, 1, 599040, 0xcd89d5be
+0, 12, 12, 1, 599040, 0x60403ebb
+0, 13, 13, 1, 599040, 0xc5c62e88
+0, 14, 14, 1, 599040, 0x93403d23
+0, 15, 15, 1, 599040, 0x6b86071d
+0, 16, 16, 1, 599040, 0xfaaad32f
+0, 17, 17, 1, 599040, 0x68651db5
+0, 18, 18, 1, 599040, 0xfbedeba6
+0, 19, 19, 1, 599040, 0x7fa3a0c0
+0, 20, 20, 1, 599040, 0x76b34545
+0, 21, 21, 1, 599040, 0x34e4c1cd
+0, 22, 22, 1, 599040, 0xfad3eda9
+0, 23, 23, 1, 599040, 0xf4324901
+0, 24, 24, 1, 599040, 0x991b4fde
+0, 25, 25, 1, 599040, 0xd9d7823d
+0, 26, 26, 1, 599040, 0xd8a80ca5
+0, 27, 27, 1, 599040, 0x19ae0251
+0, 28, 28, 1, 599040, 0xfa68cda7
+0, 29, 29, 1, 599040, 0xb9c72f07
+0, 30, 30, 1, 599040, 0xf1df5f78
+0, 31, 31, 1, 599040, 0xda75192b
+0, 32, 32, 1, 599040, 0x1102b6e6
+0, 33, 33, 1, 599040, 0x259ec490
+0, 34, 34, 1, 599040, 0xee1dabe5
+0, 35, 35, 1, 599040, 0xf6bf5454
+0, 36, 36, 1, 599040, 0x058061be
+0, 37, 37, 1, 599040, 0x2f9aebeb
+0, 38, 38, 1, 599040, 0x169c0bff
+0, 39, 39, 1, 599040, 0xeffb5a9f
+0, 40, 40, 1, 599040, 0xb3bbebac
+0, 41, 41, 1, 599040, 0x174af746
+0, 42, 42, 1, 599040, 0x8359db57
+0, 43, 43, 1, 599040, 0xdd7693ad
+0, 44, 44, 1, 599040, 0x05aebad4
+0, 45, 45, 1, 599040, 0xc34fd8bc
+0, 46, 46, 1, 599040, 0x2798f32e
+0, 47, 47, 1, 599040, 0x319b9b8c
+0, 48, 48, 1, 599040, 0xa28d783f
+0, 49, 49, 1, 599040, 0x5c79026f
+0, 50, 50, 1, 599040, 0xd4ae9b08
+0, 51, 51, 1, 599040, 0x79b19064
+0, 52, 52, 1, 599040, 0xe773bd75
+0, 53, 53, 1, 599040, 0xfbeda52a
+0, 54, 54, 1, 599040, 0x2ed916e6
+0, 55, 55, 1, 599040, 0xd3243fe7
+0, 56, 56, 1, 599040, 0xfdbc20e8
+0, 57, 57, 1, 599040, 0x80983226
+0, 58, 58, 1, 599040, 0x51c66b23
+0, 59, 59, 1, 599040, 0x30816b80
diff --git a/tests/ref/fate/hevc-conformance-TILES_A_Cisco_2 b/tests/ref/fate/hevc-conformance-TILES_A_Cisco_2
new file mode 100644
index 0000000..63c9722
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-TILES_A_Cisco_2
@@ -0,0 +1,101 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0xfc052e85
+0, 1, 1, 1, 3110400, 0xfb49bf20
+0, 2, 2, 1, 3110400, 0x549eef2b
+0, 3, 3, 1, 3110400, 0xc3857801
+0, 4, 4, 1, 3110400, 0xb27d6aea
+0, 5, 5, 1, 3110400, 0xa52e1d58
+0, 6, 6, 1, 3110400, 0x02d348e6
+0, 7, 7, 1, 3110400, 0x45a9c47c
+0, 8, 8, 1, 3110400, 0xc308e886
+0, 9, 9, 1, 3110400, 0x43cd6ed6
+0, 10, 10, 1, 3110400, 0x29a054ce
+0, 11, 11, 1, 3110400, 0x76fbd08e
+0, 12, 12, 1, 3110400, 0x8638d5e2
+0, 13, 13, 1, 3110400, 0xfb4b7823
+0, 14, 14, 1, 3110400, 0x66185e15
+0, 15, 15, 1, 3110400, 0x82eaea0a
+0, 16, 16, 1, 3110400, 0x5895f1c6
+0, 17, 17, 1, 3110400, 0x0a28a1c7
+0, 18, 18, 1, 3110400, 0x37f2ecc8
+0, 19, 19, 1, 3110400, 0x0ad8b6c1
+0, 20, 20, 1, 3110400, 0x90300dcb
+0, 21, 21, 1, 3110400, 0x9731112d
+0, 22, 22, 1, 3110400, 0x5078ba88
+0, 23, 23, 1, 3110400, 0xdcfbacae
+0, 24, 24, 1, 3110400, 0x40769123
+0, 25, 25, 1, 3110400, 0xa09f4d29
+0, 26, 26, 1, 3110400, 0xa3749feb
+0, 27, 27, 1, 3110400, 0xb04c36ae
+0, 28, 28, 1, 3110400, 0x4d30c177
+0, 29, 29, 1, 3110400, 0xe247070a
+0, 30, 30, 1, 3110400, 0x84c669d5
+0, 31, 31, 1, 3110400, 0x3e0529e6
+0, 32, 32, 1, 3110400, 0xd0d58b7a
+0, 33, 33, 1, 3110400, 0x05de0ffa
+0, 34, 34, 1, 3110400, 0x7d10a27f
+0, 35, 35, 1, 3110400, 0x87dd43fe
+0, 36, 36, 1, 3110400, 0xc6f39e98
+0, 37, 37, 1, 3110400, 0x9bf5a18b
+0, 38, 38, 1, 3110400, 0x4880f4e6
+0, 39, 39, 1, 3110400, 0xbba7a2fd
+0, 40, 40, 1, 3110400, 0x82fe2a14
+0, 41, 41, 1, 3110400, 0x7e701e1c
+0, 42, 42, 1, 3110400, 0x23cdbc0c
+0, 43, 43, 1, 3110400, 0xf15977e6
+0, 44, 44, 1, 3110400, 0x50df6fe2
+0, 45, 45, 1, 3110400, 0x8913ddde
+0, 46, 46, 1, 3110400, 0x633c8c0e
+0, 47, 47, 1, 3110400, 0xea604347
+0, 48, 48, 1, 3110400, 0xa5049365
+0, 49, 49, 1, 3110400, 0x35da77a8
+0, 50, 50, 1, 3110400, 0xcfa4af57
+0, 51, 51, 1, 3110400, 0x5a3bfe64
+0, 52, 52, 1, 3110400, 0x91f9ee34
+0, 53, 53, 1, 3110400, 0x21b0df73
+0, 54, 54, 1, 3110400, 0x7807baf2
+0, 55, 55, 1, 3110400, 0x96dbaf03
+0, 56, 56, 1, 3110400, 0xb8d29f57
+0, 57, 57, 1, 3110400, 0x1a04f732
+0, 58, 58, 1, 3110400, 0x54a34b35
+0, 59, 59, 1, 3110400, 0x4850a07a
+0, 60, 60, 1, 3110400, 0x7010be29
+0, 61, 61, 1, 3110400, 0x7178d2e7
+0, 62, 62, 1, 3110400, 0x17483898
+0, 63, 63, 1, 3110400, 0x4c55872a
+0, 64, 64, 1, 3110400, 0xe67b0f06
+0, 65, 65, 1, 3110400, 0x958789cf
+0, 66, 66, 1, 3110400, 0x5cd6ba06
+0, 67, 67, 1, 3110400, 0xb7852fe2
+0, 68, 68, 1, 3110400, 0x8b67bd9f
+0, 69, 69, 1, 3110400, 0x9555c0ff
+0, 70, 70, 1, 3110400, 0x6b99aab7
+0, 71, 71, 1, 3110400, 0xcab904b7
+0, 72, 72, 1, 3110400, 0xeb915c25
+0, 73, 73, 1, 3110400, 0xd3066bd8
+0, 74, 74, 1, 3110400, 0xa2d45cb5
+0, 75, 75, 1, 3110400, 0x011db978
+0, 76, 76, 1, 3110400, 0xf35b9f2c
+0, 77, 77, 1, 3110400, 0x6afd3bde
+0, 78, 78, 1, 3110400, 0xa1ad77b7
+0, 79, 79, 1, 3110400, 0x8b4d3823
+0, 80, 80, 1, 3110400, 0xd806be79
+0, 81, 81, 1, 3110400, 0x29dcff87
+0, 82, 82, 1, 3110400, 0x202fb0f7
+0, 83, 83, 1, 3110400, 0xacfc7d1d
+0, 84, 84, 1, 3110400, 0xf04bdcb8
+0, 85, 85, 1, 3110400, 0x89cef288
+0, 86, 86, 1, 3110400, 0x657315e2
+0, 87, 87, 1, 3110400, 0x1615cb5f
+0, 88, 88, 1, 3110400, 0xc6986395
+0, 89, 89, 1, 3110400, 0x6b77258e
+0, 90, 90, 1, 3110400, 0xcd9975ae
+0, 91, 91, 1, 3110400, 0x5044fd0f
+0, 92, 92, 1, 3110400, 0x20dd1132
+0, 93, 93, 1, 3110400, 0xdb5a0b84
+0, 94, 94, 1, 3110400, 0xf40d29ae
+0, 95, 95, 1, 3110400, 0xe88bffed
+0, 96, 96, 1, 3110400, 0x3e50146a
+0, 97, 97, 1, 3110400, 0xaacd9bfa
+0, 98, 98, 1, 3110400, 0x270b2c2a
+0, 99, 99, 1, 3110400, 0xc727f760
diff --git a/tests/ref/fate/hevc-conformance-TILES_B_Cisco_1 b/tests/ref/fate/hevc-conformance-TILES_B_Cisco_1
new file mode 100644
index 0000000..9c37121
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-TILES_B_Cisco_1
@@ -0,0 +1,101 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0x3471f473
+0, 1, 1, 1, 3110400, 0xb371a3e8
+0, 2, 2, 1, 3110400, 0x6d83c623
+0, 3, 3, 1, 3110400, 0x62d68b96
+0, 4, 4, 1, 3110400, 0xa8ed6ea9
+0, 5, 5, 1, 3110400, 0xcabe52be
+0, 6, 6, 1, 3110400, 0xbbb23578
+0, 7, 7, 1, 3110400, 0xb1609c77
+0, 8, 8, 1, 3110400, 0x61e7c2a7
+0, 9, 9, 1, 3110400, 0x6d8b34ad
+0, 10, 10, 1, 3110400, 0xde0dfa96
+0, 11, 11, 1, 3110400, 0x48c2b0b0
+0, 12, 12, 1, 3110400, 0x647b6f90
+0, 13, 13, 1, 3110400, 0xd37f2dda
+0, 14, 14, 1, 3110400, 0x1b0dd122
+0, 15, 15, 1, 3110400, 0x0b050786
+0, 16, 16, 1, 3110400, 0xcd9ce7e5
+0, 17, 17, 1, 3110400, 0xb92a4ee4
+0, 18, 18, 1, 3110400, 0x4fa4d97c
+0, 19, 19, 1, 3110400, 0x109777eb
+0, 20, 20, 1, 3110400, 0xc3d2236a
+0, 21, 21, 1, 3110400, 0x1cd12d07
+0, 22, 22, 1, 3110400, 0xdd1ef75d
+0, 23, 23, 1, 3110400, 0xd00c0906
+0, 24, 24, 1, 3110400, 0x8de79207
+0, 25, 25, 1, 3110400, 0x18017e1e
+0, 26, 26, 1, 3110400, 0x4329f68a
+0, 27, 27, 1, 3110400, 0x6a402bae
+0, 28, 28, 1, 3110400, 0x90eb1a20
+0, 29, 29, 1, 3110400, 0xe3474876
+0, 30, 30, 1, 3110400, 0xd652e216
+0, 31, 31, 1, 3110400, 0xeb458ebb
+0, 32, 32, 1, 3110400, 0xc5aff075
+0, 33, 33, 1, 3110400, 0xcb4d72e7
+0, 34, 34, 1, 3110400, 0x5504d9c5
+0, 35, 35, 1, 3110400, 0xcd0147b4
+0, 36, 36, 1, 3110400, 0xe2f0001e
+0, 37, 37, 1, 3110400, 0xa2199fe5
+0, 38, 38, 1, 3110400, 0x2f269683
+0, 39, 39, 1, 3110400, 0x7cf11244
+0, 40, 40, 1, 3110400, 0xf39cb39d
+0, 41, 41, 1, 3110400, 0x0e195a06
+0, 42, 42, 1, 3110400, 0x195e31e3
+0, 43, 43, 1, 3110400, 0xc43cd272
+0, 44, 44, 1, 3110400, 0x9dc1c4ea
+0, 45, 45, 1, 3110400, 0x846cd55f
+0, 46, 46, 1, 3110400, 0xe9468052
+0, 47, 47, 1, 3110400, 0xc5bb38ff
+0, 48, 48, 1, 3110400, 0xd1886697
+0, 49, 49, 1, 3110400, 0x23f2012b
+0, 50, 50, 1, 3110400, 0x669d63ff
+0, 51, 51, 1, 3110400, 0xced83804
+0, 52, 52, 1, 3110400, 0x005f5f3d
+0, 53, 53, 1, 3110400, 0x772efc80
+0, 54, 54, 1, 3110400, 0x94012838
+0, 55, 55, 1, 3110400, 0x99770054
+0, 56, 56, 1, 3110400, 0x8654c655
+0, 57, 57, 1, 3110400, 0xed3d19f4
+0, 58, 58, 1, 3110400, 0x8efc2172
+0, 59, 59, 1, 3110400, 0x9aaf930d
+0, 60, 60, 1, 3110400, 0xbe32f43e
+0, 61, 61, 1, 3110400, 0x6008f53e
+0, 62, 62, 1, 3110400, 0xb87897b9
+0, 63, 63, 1, 3110400, 0xe2406eb1
+0, 64, 64, 1, 3110400, 0xbdfa067b
+0, 65, 65, 1, 3110400, 0x82a16dbd
+0, 66, 66, 1, 3110400, 0x909aa5f0
+0, 67, 67, 1, 3110400, 0xc63836b5
+0, 68, 68, 1, 3110400, 0xaf7ad199
+0, 69, 69, 1, 3110400, 0xfa010078
+0, 70, 70, 1, 3110400, 0x00c0c24e
+0, 71, 71, 1, 3110400, 0xbda7cc4e
+0, 72, 72, 1, 3110400, 0xda97f9d5
+0, 73, 73, 1, 3110400, 0xd359e94a
+0, 74, 74, 1, 3110400, 0xcd48c131
+0, 75, 75, 1, 3110400, 0xb52ca032
+0, 76, 76, 1, 3110400, 0x55a69650
+0, 77, 77, 1, 3110400, 0x7241c1a9
+0, 78, 78, 1, 3110400, 0xf06c5744
+0, 79, 79, 1, 3110400, 0xe1befd73
+0, 80, 80, 1, 3110400, 0xe8ffea92
+0, 81, 81, 1, 3110400, 0xd76e40b6
+0, 82, 82, 1, 3110400, 0xbf5f5b4c
+0, 83, 83, 1, 3110400, 0x0eb8d128
+0, 84, 84, 1, 3110400, 0x453dd680
+0, 85, 85, 1, 3110400, 0x7114fada
+0, 86, 86, 1, 3110400, 0xa3b4e7a8
+0, 87, 87, 1, 3110400, 0xbca356f0
+0, 88, 88, 1, 3110400, 0x80a83fa3
+0, 89, 89, 1, 3110400, 0x713a33d4
+0, 90, 90, 1, 3110400, 0x4fda8aea
+0, 91, 91, 1, 3110400, 0x31ed1a88
+0, 92, 92, 1, 3110400, 0x736312a0
+0, 93, 93, 1, 3110400, 0x60aff0c5
+0, 94, 94, 1, 3110400, 0xee66bd76
+0, 95, 95, 1, 3110400, 0xe8f9a352
+0, 96, 96, 1, 3110400, 0xb51520de
+0, 97, 97, 1, 3110400, 0xd0542466
+0, 98, 98, 1, 3110400, 0x92c2f3e1
+0, 99, 99, 1, 3110400, 0xbbe1839a
diff --git a/tests/ref/fate/hevc-conformance-TMVP_A_MS_2 b/tests/ref/fate/hevc-conformance-TMVP_A_MS_2
new file mode 100644
index 0000000..a626af8
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-TMVP_A_MS_2
@@ -0,0 +1,18 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xdb5e3b56
+0, 1, 1, 1, 149760, 0x496f2a41
+0, 2, 2, 1, 149760, 0x0690ee0a
+0, 3, 3, 1, 149760, 0x5648fb4e
+0, 4, 4, 1, 149760, 0xd58bbe51
+0, 5, 5, 1, 149760, 0x647c4520
+0, 6, 6, 1, 149760, 0x0e361335
+0, 7, 7, 1, 149760, 0xd1a4289b
+0, 8, 8, 1, 149760, 0x04d29f74
+0, 9, 9, 1, 149760, 0x3bbffc55
+0, 10, 10, 1, 149760, 0xefe30f2b
+0, 11, 11, 1, 149760, 0x3a336f52
+0, 12, 12, 1, 149760, 0x0dffed51
+0, 13, 13, 1, 149760, 0x5a9db757
+0, 14, 14, 1, 149760, 0x5e7313c5
+0, 15, 15, 1, 149760, 0xbffb3a0e
+0, 16, 16, 1, 149760, 0x073966e9
diff --git a/tests/ref/fate/hevc-conformance-TSCL_A_VIDYO_5 b/tests/ref/fate/hevc-conformance-TSCL_A_VIDYO_5
new file mode 100644
index 0000000..84d4219
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-TSCL_A_VIDYO_5
@@ -0,0 +1,74 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xcfffa013
+0, 1, 1, 1, 149760, 0x5166146a
+0, 2, 2, 1, 149760, 0xc3cc318e
+0, 3, 3, 1, 149760, 0xcedf65a0
+0, 4, 4, 1, 149760, 0x10c97bd4
+0, 5, 5, 1, 149760, 0xd9d5c4ab
+0, 6, 6, 1, 149760, 0x5112e11d
+0, 7, 7, 1, 149760, 0xde3803d6
+0, 8, 8, 1, 149760, 0x82c62409
+0, 9, 9, 1, 149760, 0x69a587f2
+0, 10, 10, 1, 149760, 0x90e2ac16
+0, 11, 11, 1, 149760, 0xdc2ed2ba
+0, 12, 12, 1, 149760, 0xcabec51f
+0, 13, 13, 1, 149760, 0x915de948
+0, 14, 14, 1, 149760, 0xd824e422
+0, 15, 15, 1, 149760, 0x10f91769
+0, 16, 16, 1, 149760, 0xf8ea1f0a
+0, 17, 17, 1, 149760, 0x88306494
+0, 18, 18, 1, 149760, 0x4b667403
+0, 19, 19, 1, 149760, 0x190b939f
+0, 20, 20, 1, 149760, 0xe754929d
+0, 21, 21, 1, 149760, 0xdd1eb9b5
+0, 22, 22, 1, 149760, 0x5ef1c64b
+0, 23, 23, 1, 149760, 0xab92e9f9
+0, 24, 24, 1, 149760, 0x873fec38
+0, 25, 25, 1, 149760, 0x1f0ca11f
+0, 26, 26, 1, 149760, 0xa2f591ca
+0, 27, 27, 1, 149760, 0x2713a994
+0, 28, 28, 1, 149760, 0xfbdba1f9
+0, 29, 29, 1, 149760, 0x3742ed2e
+0, 30, 30, 1, 149760, 0xf43fe43c
+0, 31, 31, 1, 149760, 0xa84ff250
+0, 32, 32, 1, 149760, 0xd4437e12
+0, 33, 33, 1, 149760, 0xcf08c736
+0, 34, 34, 1, 149760, 0x0cedd0d6
+0, 35, 35, 1, 149760, 0xc317e9bc
+0, 36, 36, 1, 149760, 0x0dcbd636
+0, 37, 37, 1, 149760, 0x4e6501b0
+0, 38, 38, 1, 149760, 0x5f9c02bb
+0, 39, 39, 1, 149760, 0x43052939
+0, 40, 40, 1, 149760, 0x8ec12318
+0, 41, 41, 1, 149760, 0xc51577f3
+0, 42, 42, 1, 149760, 0xbda1775b
+0, 43, 43, 1, 149760, 0x62b7b2a2
+0, 44, 44, 1, 149760, 0x5dd68203
+0, 45, 45, 1, 149760, 0xe004b4bf
+0, 46, 46, 1, 149760, 0x1469769f
+0, 47, 47, 1, 149760, 0x96f57e0a
+0, 48, 48, 1, 149760, 0x75e58819
+0, 49, 49, 1, 149760, 0xf826a158
+0, 50, 50, 1, 149760, 0xf789a3bd
+0, 51, 51, 1, 149760, 0x9d8fb09a
+0, 52, 52, 1, 149760, 0x1d33bbe5
+0, 53, 53, 1, 149760, 0x7e93e014
+0, 54, 54, 1, 149760, 0x04ade2e6
+0, 55, 55, 1, 149760, 0xb93a2c32
+0, 56, 56, 1, 149760, 0x5fa73dc3
+0, 57, 57, 1, 149760, 0xa70099ee
+0, 58, 58, 1, 149760, 0xcc5aaf3e
+0, 59, 59, 1, 149760, 0x4e83f938
+0, 60, 60, 1, 149760, 0x9faae668
+0, 61, 61, 1, 149760, 0x7a5cbf24
+0, 62, 62, 1, 149760, 0x4b23714c
+0, 63, 63, 1, 149760, 0x55d246ad
+0, 64, 64, 1, 149760, 0xd3378be9
+0, 65, 65, 1, 149760, 0xf5ef9731
+0, 66, 66, 1, 149760, 0xc4ba3ad7
+0, 67, 67, 1, 149760, 0xd9182d2c
+0, 68, 68, 1, 149760, 0x0ff5eaa5
+0, 69, 69, 1, 149760, 0xefe21a58
+0, 70, 70, 1, 149760, 0x4cad2a57
+0, 71, 71, 1, 149760, 0x24a35d1a
+0, 72, 72, 1, 149760, 0xeb1b6a6e
diff --git a/tests/ref/fate/hevc-conformance-TSCL_B_VIDYO_4 b/tests/ref/fate/hevc-conformance-TSCL_B_VIDYO_4
new file mode 100644
index 0000000..6ee24ac
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-TSCL_B_VIDYO_4
@@ -0,0 +1,74 @@
+#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
+0, 33, 33, 1, 149760, 0xf7aea3b6
+0, 34, 34, 1, 149760, 0x53f482c9
+0, 35, 35, 1, 149760, 0x7184b3ae
+0, 36, 36, 1, 149760, 0xb425b53d
+0, 37, 37, 1, 149760, 0xfb7cce6e
+0, 38, 38, 1, 149760, 0x820bc1ef
+0, 39, 39, 1, 149760, 0xbb0de30a
+0, 40, 40, 1, 149760, 0xbdcb0af2
+0, 41, 41, 1, 149760, 0xf2404ff7
+0, 42, 42, 1, 149760, 0xd6636f0a
+0, 43, 43, 1, 149760, 0x0e908b06
+0, 44, 44, 1, 149760, 0x36a158f4
+0, 45, 45, 1, 149760, 0x178d5bbd
+0, 46, 46, 1, 149760, 0xba9a6d14
+0, 47, 47, 1, 149760, 0x89145886
+0, 48, 48, 1, 149760, 0x6ec26794
+0, 49, 49, 1, 149760, 0xf6ac7551
+0, 50, 50, 1, 149760, 0xc829c66f
+0, 51, 51, 1, 149760, 0x64d50d50
+0, 52, 52, 1, 149760, 0x215dd855
+0, 53, 53, 1, 149760, 0x8b2ffec3
+0, 54, 54, 1, 149760, 0x1a0b7bcd
+0, 55, 55, 1, 149760, 0x14a5ad0e
+0, 56, 56, 1, 149760, 0x88c34286
+0, 57, 57, 1, 149760, 0xe2706fa9
+0, 58, 58, 1, 149760, 0x8de2decf
+0, 59, 59, 1, 149760, 0x1b37e5d7
+0, 60, 60, 1, 149760, 0xaf8d175a
+0, 61, 61, 1, 149760, 0x0f4aec5f
+0, 62, 62, 1, 149760, 0x3818df10
+0, 63, 63, 1, 149760, 0xe791d309
+0, 64, 64, 1, 149760, 0x6ad9aa0d
+0, 65, 65, 1, 149760, 0x1e1ab8a1
+0, 66, 66, 1, 149760, 0xd0ef526a
+0, 67, 67, 1, 149760, 0x45da3cf1
+0, 68, 68, 1, 149760, 0x3cb4eee6
+0, 69, 69, 1, 149760, 0x3e816ebc
+0, 70, 70, 1, 149760, 0x29d45e93
+0, 71, 71, 1, 149760, 0x824b5bc2
+0, 72, 72, 1, 149760, 0x015e6fd2
diff --git a/tests/ref/fate/hevc-conformance-TSKIP_A_MS_2 b/tests/ref/fate/hevc-conformance-TSKIP_A_MS_2
new file mode 100644
index 0000000..1226e11
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-TSKIP_A_MS_2
@@ -0,0 +1,18 @@
+#tb 0: 1/25
+0, 0, 0, 1, 1382400, 0xaea37937
+0, 1, 1, 1, 1382400, 0x39d687d0
+0, 2, 2, 1, 1382400, 0x8ea04595
+0, 3, 3, 1, 1382400, 0x5d5a40d2
+0, 4, 4, 1, 1382400, 0x6915eb4e
+0, 5, 5, 1, 1382400, 0xe8bb612d
+0, 6, 6, 1, 1382400, 0xd331085a
+0, 7, 7, 1, 1382400, 0x2193bc30
+0, 8, 8, 1, 1382400, 0xaeb19418
+0, 9, 9, 1, 1382400, 0xb524eac3
+0, 10, 10, 1, 1382400, 0x141908a2
+0, 11, 11, 1, 1382400, 0x527ab6ac
+0, 12, 12, 1, 1382400, 0xe9a73d9f
+0, 13, 13, 1, 1382400, 0x2eb0aa14
+0, 14, 14, 1, 1382400, 0x6981af42
+0, 15, 15, 1, 1382400, 0xbb0bbd7a
+0, 16, 16, 1, 1382400, 0xf0779b81
diff --git a/tests/ref/fate/hevc-conformance-WPP_A_ericsson_MAIN10_2 b/tests/ref/fate/hevc-conformance-WPP_A_ericsson_MAIN10_2
new file mode 100644
index 0000000..fe46c99
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WPP_A_ericsson_MAIN10_2
@@ -0,0 +1,49 @@
+#tb 0: 1/25
+0, 0, 0, 1, 299520, 0xa3f96d63
+0, 1, 1, 1, 299520, 0x5f788f3f
+0, 2, 2, 1, 299520, 0x41c7d0ae
+0, 3, 3, 1, 299520, 0x14a9175c
+0, 4, 4, 1, 299520, 0x5215ed5f
+0, 5, 5, 1, 299520, 0xffa5ab17
+0, 6, 6, 1, 299520, 0x7d179b2b
+0, 7, 7, 1, 299520, 0x87280332
+0, 8, 8, 1, 299520, 0xca5e278f
+0, 9, 9, 1, 299520, 0x89d59325
+0, 10, 10, 1, 299520, 0x6593cfa5
+0, 11, 11, 1, 299520, 0x216ce552
+0, 12, 12, 1, 299520, 0x4494f2ac
+0, 13, 13, 1, 299520, 0xc9aafeb4
+0, 14, 14, 1, 299520, 0xe93a43ab
+0, 15, 15, 1, 299520, 0x89bdba99
+0, 16, 16, 1, 299520, 0xdc529079
+0, 17, 17, 1, 299520, 0xfbc29de7
+0, 18, 18, 1, 299520, 0xa8c6c853
+0, 19, 19, 1, 299520, 0xd552dc1f
+0, 20, 20, 1, 299520, 0x60a7d5d9
+0, 21, 21, 1, 299520, 0x4b784987
+0, 22, 22, 1, 299520, 0xec9bd2a0
+0, 23, 23, 1, 299520, 0x71e1d437
+0, 24, 24, 1, 299520, 0x5776a225
+0, 25, 25, 1, 299520, 0x01598543
+0, 26, 26, 1, 299520, 0x8abb1f7b
+0, 27, 27, 1, 299520, 0xa3a0bb58
+0, 28, 28, 1, 299520, 0x4a718127
+0, 29, 29, 1, 299520, 0x6b1647bc
+0, 30, 30, 1, 299520, 0x7b653009
+0, 31, 31, 1, 299520, 0xca15d4be
+0, 32, 32, 1, 299520, 0xf8075689
+0, 33, 33, 1, 299520, 0x2717f2e6
+0, 34, 34, 1, 299520, 0x53ad6267
+0, 35, 35, 1, 299520, 0x29fedd49
+0, 36, 36, 1, 299520, 0x4e8aa5db
+0, 37, 37, 1, 299520, 0xca316c94
+0, 38, 38, 1, 299520, 0x8071fd57
+0, 39, 39, 1, 299520, 0xc9915cd3
+0, 40, 40, 1, 299520, 0xab335447
+0, 41, 41, 1, 299520, 0xf733a390
+0, 42, 42, 1, 299520, 0x1fa14afb
+0, 43, 43, 1, 299520, 0xe5d7ae71
+0, 44, 44, 1, 299520, 0xb48c2ee6
+0, 45, 45, 1, 299520, 0xe288ebcc
+0, 46, 46, 1, 299520, 0xa4000bdd
+0, 47, 47, 1, 299520, 0xf3fdee3a
diff --git a/tests/ref/fate/hevc-conformance-WPP_A_ericsson_MAIN_2 b/tests/ref/fate/hevc-conformance-WPP_A_ericsson_MAIN_2
new file mode 100644
index 0000000..497c802
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WPP_A_ericsson_MAIN_2
@@ -0,0 +1,49 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xfbb3d914
+0, 1, 1, 1, 149760, 0xdccd707b
+0, 2, 2, 1, 149760, 0x32008963
+0, 3, 3, 1, 149760, 0x0fcdd808
+0, 4, 4, 1, 149760, 0x69f0e1a5
+0, 5, 5, 1, 149760, 0x1be36c09
+0, 6, 6, 1, 149760, 0x18a1588f
+0, 7, 7, 1, 149760, 0xdc46acd8
+0, 8, 8, 1, 149760, 0xec46760a
+0, 9, 9, 1, 149760, 0xe87fc7b5
+0, 10, 10, 1, 149760, 0x7c78d960
+0, 11, 11, 1, 149760, 0x73e2ea91
+0, 12, 12, 1, 149760, 0x9164db8c
+0, 13, 13, 1, 149760, 0x31a6124b
+0, 14, 14, 1, 149760, 0x8a143aed
+0, 15, 15, 1, 149760, 0x15a364f4
+0, 16, 16, 1, 149760, 0x93b8560e
+0, 17, 17, 1, 149760, 0xc2aa985c
+0, 18, 18, 1, 149760, 0xe83ca4da
+0, 19, 19, 1, 149760, 0x6c79cb07
+0, 20, 20, 1, 149760, 0x2c24c739
+0, 21, 21, 1, 149760, 0x6a60f769
+0, 22, 22, 1, 149760, 0x13f00ad1
+0, 23, 23, 1, 149760, 0x59dd330d
+0, 24, 24, 1, 149760, 0x8815348c
+0, 25, 25, 1, 149760, 0x88576cd4
+0, 26, 26, 1, 149760, 0xfa3d6b9c
+0, 27, 27, 1, 149760, 0x810c8145
+0, 28, 28, 1, 149760, 0xf2357fcc
+0, 29, 29, 1, 149760, 0xc885a093
+0, 30, 30, 1, 149760, 0x5939a048
+0, 31, 31, 1, 149760, 0x9f93a489
+0, 32, 32, 1, 149760, 0xc11a879e
+0, 33, 33, 1, 149760, 0x5221c04b
+0, 34, 34, 1, 149760, 0x7dcdca90
+0, 35, 35, 1, 149760, 0xfdd8df1e
+0, 36, 36, 1, 149760, 0x3a88c802
+0, 37, 37, 1, 149760, 0x50ff1081
+0, 38, 38, 1, 149760, 0x6388f458
+0, 39, 39, 1, 149760, 0x85623a2b
+0, 40, 40, 1, 149760, 0x1bfd34a4
+0, 41, 41, 1, 149760, 0xb6037b88
+0, 42, 42, 1, 149760, 0xd24e65c7
+0, 43, 43, 1, 149760, 0xd2bd8fac
+0, 44, 44, 1, 149760, 0x602f64d0
+0, 45, 45, 1, 149760, 0x59415d5e
+0, 46, 46, 1, 149760, 0x9faf5737
+0, 47, 47, 1, 149760, 0x66ce56a9
diff --git a/tests/ref/fate/hevc-conformance-WPP_B_ericsson_MAIN10_2 b/tests/ref/fate/hevc-conformance-WPP_B_ericsson_MAIN10_2
new file mode 100644
index 0000000..d199d38
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WPP_B_ericsson_MAIN10_2
@@ -0,0 +1,49 @@
+#tb 0: 1/25
+0, 0, 0, 1, 299520, 0x66b3cef3
+0, 1, 1, 1, 299520, 0x99df880f
+0, 2, 2, 1, 299520, 0xb4a03801
+0, 3, 3, 1, 299520, 0x1510c9e2
+0, 4, 4, 1, 299520, 0x42fe77b1
+0, 5, 5, 1, 299520, 0x815e1727
+0, 6, 6, 1, 299520, 0x6dd002f4
+0, 7, 7, 1, 299520, 0x2650e944
+0, 8, 8, 1, 299520, 0x3268c1e9
+0, 9, 9, 1, 299520, 0xced41a5f
+0, 10, 10, 1, 299520, 0x91334b97
+0, 11, 11, 1, 299520, 0xc5bb7ff6
+0, 12, 12, 1, 299520, 0x26e27c35
+0, 13, 13, 1, 299520, 0x482da6cb
+0, 14, 14, 1, 299520, 0xfe742e8e
+0, 15, 15, 1, 299520, 0x3f395752
+0, 16, 16, 1, 299520, 0x189936e5
+0, 17, 17, 1, 299520, 0x56a58a07
+0, 18, 18, 1, 299520, 0x798d8de9
+0, 19, 19, 1, 299520, 0x5d8e947f
+0, 20, 20, 1, 299520, 0x65477654
+0, 21, 21, 1, 299520, 0x5012d167
+0, 22, 22, 1, 299520, 0xe889bb27
+0, 23, 23, 1, 299520, 0x4611c1e6
+0, 24, 24, 1, 299520, 0xb093402b
+0, 25, 25, 1, 299520, 0xddc065d8
+0, 26, 26, 1, 299520, 0x6986e1d9
+0, 27, 27, 1, 299520, 0x0e539004
+0, 28, 28, 1, 299520, 0x4768f9ed
+0, 29, 29, 1, 299520, 0xfad20b53
+0, 30, 30, 1, 299520, 0x82f9c996
+0, 31, 31, 1, 299520, 0x6b366d79
+0, 32, 32, 1, 299520, 0x5a35d42e
+0, 33, 33, 1, 299520, 0xf3849013
+0, 34, 34, 1, 299520, 0x6b8eae50
+0, 35, 35, 1, 299520, 0x0f854274
+0, 36, 36, 1, 299520, 0x31685299
+0, 37, 37, 1, 299520, 0x77357bfb
+0, 38, 38, 1, 299520, 0xd67f1807
+0, 39, 39, 1, 299520, 0x371e7eb6
+0, 40, 40, 1, 299520, 0xe2ee3531
+0, 41, 41, 1, 299520, 0x50f242f1
+0, 42, 42, 1, 299520, 0x265ed919
+0, 43, 43, 1, 299520, 0xad496c85
+0, 44, 44, 1, 299520, 0xb2aef047
+0, 45, 45, 1, 299520, 0xac5c4451
+0, 46, 46, 1, 299520, 0x2b26a0cb
+0, 47, 47, 1, 299520, 0x5738d837
diff --git a/tests/ref/fate/hevc-conformance-WPP_B_ericsson_MAIN_2 b/tests/ref/fate/hevc-conformance-WPP_B_ericsson_MAIN_2
new file mode 100644
index 0000000..bb61b10
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WPP_B_ericsson_MAIN_2
@@ -0,0 +1,49 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x3772de54
+0, 1, 1, 1, 149760, 0x571d885e
+0, 2, 2, 1, 149760, 0x71576f09
+0, 3, 3, 1, 149760, 0xf0724ce0
+0, 4, 4, 1, 149760, 0x2cc6e355
+0, 5, 5, 1, 149760, 0x0ca14365
+0, 6, 6, 1, 149760, 0x5aeb4b4d
+0, 7, 7, 1, 149760, 0xb018561c
+0, 8, 8, 1, 149760, 0x8fb07521
+0, 9, 9, 1, 149760, 0x9e1ccc5b
+0, 10, 10, 1, 149760, 0x0cf3de9f
+0, 11, 11, 1, 149760, 0x918cf512
+0, 12, 12, 1, 149760, 0x9a60e5c4
+0, 13, 13, 1, 149760, 0xc3b01d10
+0, 14, 14, 1, 149760, 0x929b34a6
+0, 15, 15, 1, 149760, 0x1f9462ac
+0, 16, 16, 1, 149760, 0xcadf511e
+0, 17, 17, 1, 149760, 0x318e9af6
+0, 18, 18, 1, 149760, 0x0860a371
+0, 19, 19, 1, 149760, 0x13e3c4d1
+0, 20, 20, 1, 149760, 0xfa27cbf6
+0, 21, 21, 1, 149760, 0x407ffed5
+0, 22, 22, 1, 149760, 0xa3c00c3b
+0, 23, 23, 1, 149760, 0x926938c6
+0, 24, 24, 1, 149760, 0xf5792acf
+0, 25, 25, 1, 149760, 0x66e16a48
+0, 26, 26, 1, 149760, 0xd46e7041
+0, 27, 27, 1, 149760, 0x814c84ee
+0, 28, 28, 1, 149760, 0x165b750a
+0, 29, 29, 1, 149760, 0x24ad9df0
+0, 30, 30, 1, 149760, 0x11189e4e
+0, 31, 31, 1, 149760, 0xb841a5b6
+0, 32, 32, 1, 149760, 0xea738605
+0, 33, 33, 1, 149760, 0xbbf0ca3f
+0, 34, 34, 1, 149760, 0xcfb5d03c
+0, 35, 35, 1, 149760, 0x0654f0b7
+0, 36, 36, 1, 149760, 0x1c2cd18d
+0, 37, 37, 1, 149760, 0x9a4602ae
+0, 38, 38, 1, 149760, 0xf2a2ff5a
+0, 39, 39, 1, 149760, 0x9c153c77
+0, 40, 40, 1, 149760, 0x5ed23e56
+0, 41, 41, 1, 149760, 0x1eb58383
+0, 42, 42, 1, 149760, 0x725e70f2
+0, 43, 43, 1, 149760, 0x652aa56c
+0, 44, 44, 1, 149760, 0x7f736ad2
+0, 45, 45, 1, 149760, 0x0827700a
+0, 46, 46, 1, 149760, 0x76a06370
+0, 47, 47, 1, 149760, 0xa7fe6f9d
diff --git a/tests/ref/fate/hevc-conformance-WPP_C_ericsson_MAIN10_2 b/tests/ref/fate/hevc-conformance-WPP_C_ericsson_MAIN10_2
new file mode 100644
index 0000000..b1e6312
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WPP_C_ericsson_MAIN10_2
@@ -0,0 +1,49 @@
+#tb 0: 1/25
+0, 0, 0, 1, 299520, 0xbc71d699
+0, 1, 1, 1, 299520, 0x3207e1f9
+0, 2, 2, 1, 299520, 0xdd2087b5
+0, 3, 3, 1, 299520, 0xb512c976
+0, 4, 4, 1, 299520, 0x22957011
+0, 5, 5, 1, 299520, 0x8ce04965
+0, 6, 6, 1, 299520, 0x9cf37cba
+0, 7, 7, 1, 299520, 0xd52f8b2d
+0, 8, 8, 1, 299520, 0x2f55a94d
+0, 9, 9, 1, 299520, 0x53d3cc42
+0, 10, 10, 1, 299520, 0xbc33f3a1
+0, 11, 11, 1, 299520, 0x5e67d0de
+0, 12, 12, 1, 299520, 0x5708ecc5
+0, 13, 13, 1, 299520, 0x104869c0
+0, 14, 14, 1, 299520, 0xaf2a8638
+0, 15, 15, 1, 299520, 0xbdf1d001
+0, 16, 16, 1, 299520, 0xa3f71579
+0, 17, 17, 1, 299520, 0x68cedb09
+0, 18, 18, 1, 299520, 0xa4262d4d
+0, 19, 19, 1, 299520, 0x99320c8d
+0, 20, 20, 1, 299520, 0x57be6268
+0, 21, 21, 1, 299520, 0xc7e14cfc
+0, 22, 22, 1, 299520, 0x3d906541
+0, 23, 23, 1, 299520, 0x804b2f29
+0, 24, 24, 1, 299520, 0x93cf0ae2
+0, 25, 25, 1, 299520, 0x0fd2f932
+0, 26, 26, 1, 299520, 0xf869a25c
+0, 27, 27, 1, 299520, 0xa2dc56cd
+0, 28, 28, 1, 299520, 0x075b14a7
+0, 29, 29, 1, 299520, 0x233b0085
+0, 30, 30, 1, 299520, 0x80a69c4c
+0, 31, 31, 1, 299520, 0xf45f21af
+0, 32, 32, 1, 299520, 0x88dcab6e
+0, 33, 33, 1, 299520, 0xc1df3e99
+0, 34, 34, 1, 299520, 0xac298452
+0, 35, 35, 1, 299520, 0x6b4cc1e3
+0, 36, 36, 1, 299520, 0xfd39c597
+0, 37, 37, 1, 299520, 0xe60f808c
+0, 38, 38, 1, 299520, 0x27c47830
+0, 39, 39, 1, 299520, 0x4fd9ec76
+0, 40, 40, 1, 299520, 0x3249e084
+0, 41, 41, 1, 299520, 0x40632223
+0, 42, 42, 1, 299520, 0x9b68d213
+0, 43, 43, 1, 299520, 0x9e210ed8
+0, 44, 44, 1, 299520, 0x54489508
+0, 45, 45, 1, 299520, 0xc799df16
+0, 46, 46, 1, 299520, 0x020b2211
+0, 47, 47, 1, 299520, 0xcc1a1683
diff --git a/tests/ref/fate/hevc-conformance-WPP_C_ericsson_MAIN_2 b/tests/ref/fate/hevc-conformance-WPP_C_ericsson_MAIN_2
new file mode 100644
index 0000000..49c4f21
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WPP_C_ericsson_MAIN_2
@@ -0,0 +1,49 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x0948e521
+0, 1, 1, 1, 149760, 0x37afb384
+0, 2, 2, 1, 149760, 0xe1864c4a
+0, 3, 3, 1, 149760, 0x143344eb
+0, 4, 4, 1, 149760, 0x34cce612
+0, 5, 5, 1, 149760, 0x45ce60b3
+0, 6, 6, 1, 149760, 0x17b36585
+0, 7, 7, 1, 149760, 0x6447ebe5
+0, 8, 8, 1, 149760, 0x0f4282c7
+0, 9, 9, 1, 149760, 0xa0c3dab3
+0, 10, 10, 1, 149760, 0x0f3ceb7c
+0, 11, 11, 1, 149760, 0xb861f311
+0, 12, 12, 1, 149760, 0x620fe482
+0, 13, 13, 1, 149760, 0xa3dc1603
+0, 14, 14, 1, 149760, 0x6b7a3a6c
+0, 15, 15, 1, 149760, 0x01d16e5e
+0, 16, 16, 1, 149760, 0xe12f6009
+0, 17, 17, 1, 149760, 0xc96d98bd
+0, 18, 18, 1, 149760, 0x542e9f47
+0, 19, 19, 1, 149760, 0x5bcbc3b8
+0, 20, 20, 1, 149760, 0x3be2c63a
+0, 21, 21, 1, 149760, 0xd63df815
+0, 22, 22, 1, 149760, 0x5c210d61
+0, 23, 23, 1, 149760, 0xc7fb33b8
+0, 24, 24, 1, 149760, 0xa9f13508
+0, 25, 25, 1, 149760, 0xbf636172
+0, 26, 26, 1, 149760, 0xf1966847
+0, 27, 27, 1, 149760, 0xcc0579eb
+0, 28, 28, 1, 149760, 0x467673cb
+0, 29, 29, 1, 149760, 0x4dbca3f2
+0, 30, 30, 1, 149760, 0xada29bc9
+0, 31, 31, 1, 149760, 0x2983a0d5
+0, 32, 32, 1, 149760, 0x3864832a
+0, 33, 33, 1, 149760, 0x6a06b61d
+0, 34, 34, 1, 149760, 0x90a0d994
+0, 35, 35, 1, 149760, 0x3c58f375
+0, 36, 36, 1, 149760, 0x365bd42a
+0, 37, 37, 1, 149760, 0x5665f25f
+0, 38, 38, 1, 149760, 0x75d8fe8f
+0, 39, 39, 1, 149760, 0xc67e3508
+0, 40, 40, 1, 149760, 0x2e7b428b
+0, 41, 41, 1, 149760, 0x59cf741c
+0, 42, 42, 1, 149760, 0x2cc77eb4
+0, 43, 43, 1, 149760, 0x4957970a
+0, 44, 44, 1, 149760, 0xa69f7323
+0, 45, 45, 1, 149760, 0xaf1f6772
+0, 46, 46, 1, 149760, 0x864a5a76
+0, 47, 47, 1, 149760, 0x57795407
diff --git a/tests/ref/fate/hevc-conformance-WPP_D_ericsson_MAIN10_2 b/tests/ref/fate/hevc-conformance-WPP_D_ericsson_MAIN10_2
new file mode 100644
index 0000000..83cf10c
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WPP_D_ericsson_MAIN10_2
@@ -0,0 +1,49 @@
+#tb 0: 1/25
+0, 0, 0, 1, 46080, 0xc50ed6b4
+0, 1, 1, 1, 46080, 0x2aeac52d
+0, 2, 2, 1, 46080, 0xe3e36cd3
+0, 3, 3, 1, 46080, 0x81c6b317
+0, 4, 4, 1, 46080, 0x20e24e33
+0, 5, 5, 1, 46080, 0xc4a64f17
+0, 6, 6, 1, 46080, 0xf95a5014
+0, 7, 7, 1, 46080, 0x8d9e9a26
+0, 8, 8, 1, 46080, 0x5f0f4592
+0, 9, 9, 1, 46080, 0xa1b54f9f
+0, 10, 10, 1, 46080, 0x3d5c3673
+0, 11, 11, 1, 46080, 0xca6e5e83
+0, 12, 12, 1, 46080, 0x93eca575
+0, 13, 13, 1, 46080, 0xf84bab2b
+0, 14, 14, 1, 46080, 0xf22599d1
+0, 15, 15, 1, 46080, 0xf916673f
+0, 16, 16, 1, 46080, 0xbb11a29b
+0, 17, 17, 1, 46080, 0x047e1dd7
+0, 18, 18, 1, 46080, 0x9a975834
+0, 19, 19, 1, 46080, 0xa3fe84d4
+0, 20, 20, 1, 46080, 0x08e1c2f4
+0, 21, 21, 1, 46080, 0xbbbcf81b
+0, 22, 22, 1, 46080, 0x4abb0255
+0, 23, 23, 1, 46080, 0x20052dda
+0, 24, 24, 1, 46080, 0x10290ef3
+0, 25, 25, 1, 46080, 0x9e7633d0
+0, 26, 26, 1, 46080, 0x60d0fb3a
+0, 27, 27, 1, 46080, 0xe0209fb3
+0, 28, 28, 1, 46080, 0xea006c44
+0, 29, 29, 1, 46080, 0xe0b84e96
+0, 30, 30, 1, 46080, 0x35e507d7
+0, 31, 31, 1, 46080, 0x4107fcd6
+0, 32, 32, 1, 46080, 0x1b34af49
+0, 33, 33, 1, 46080, 0x4ab91078
+0, 34, 34, 1, 46080, 0x130750dd
+0, 35, 35, 1, 46080, 0x592dbe41
+0, 36, 36, 1, 46080, 0xfd39cf6b
+0, 37, 37, 1, 46080, 0xbe9ee5b7
+0, 38, 38, 1, 46080, 0x25ebde48
+0, 39, 39, 1, 46080, 0x2becd45c
+0, 40, 40, 1, 46080, 0x9b5fdfdb
+0, 41, 41, 1, 46080, 0xededa5f5
+0, 42, 42, 1, 46080, 0x476bc4e5
+0, 43, 43, 1, 46080, 0x4a4a0a4e
+0, 44, 44, 1, 46080, 0x1324f41b
+0, 45, 45, 1, 46080, 0xc503cfc8
+0, 46, 46, 1, 46080, 0x53f7c74c
+0, 47, 47, 1, 46080, 0xc861b5a3
diff --git a/tests/ref/fate/hevc-conformance-WPP_D_ericsson_MAIN_2 b/tests/ref/fate/hevc-conformance-WPP_D_ericsson_MAIN_2
new file mode 100644
index 0000000..6e6fc32
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WPP_D_ericsson_MAIN_2
@@ -0,0 +1,49 @@
+#tb 0: 1/25
+0, 0, 0, 1, 23040, 0x6977dbca
+0, 1, 1, 1, 23040, 0xd9bfcb5c
+0, 2, 2, 1, 23040, 0xbdd5a346
+0, 3, 3, 1, 23040, 0x021877cd
+0, 4, 4, 1, 23040, 0xb8a45933
+0, 5, 5, 1, 23040, 0xc289338e
+0, 6, 6, 1, 23040, 0x6968e57d
+0, 7, 7, 1, 23040, 0x1142c50c
+0, 8, 8, 1, 23040, 0xcf86c357
+0, 9, 9, 1, 23040, 0xf73de7ec
+0, 10, 10, 1, 23040, 0x2103ed06
+0, 11, 11, 1, 23040, 0xf0ecc0e2
+0, 12, 12, 1, 23040, 0xa7b1971f
+0, 13, 13, 1, 23040, 0x4454871a
+0, 14, 14, 1, 23040, 0xc5088346
+0, 15, 15, 1, 23040, 0x89189469
+0, 16, 16, 1, 23040, 0x320d977a
+0, 17, 17, 1, 23040, 0xbdc0a95b
+0, 18, 18, 1, 23040, 0xbcfec5c9
+0, 19, 19, 1, 23040, 0xb68ceb37
+0, 20, 20, 1, 23040, 0x41a60b0c
+0, 21, 21, 1, 23040, 0x0e662b47
+0, 22, 22, 1, 23040, 0x0e2440b7
+0, 23, 23, 1, 23040, 0x77415a77
+0, 24, 24, 1, 23040, 0x62936fdf
+0, 25, 25, 1, 23040, 0xaa987f9d
+0, 26, 26, 1, 23040, 0xaf0c8764
+0, 27, 27, 1, 23040, 0x645c913e
+0, 28, 28, 1, 23040, 0x2f249b06
+0, 29, 29, 1, 23040, 0xb54fb546
+0, 30, 30, 1, 23040, 0xc669c247
+0, 31, 31, 1, 23040, 0xe308bb8f
+0, 32, 32, 1, 23040, 0xb920b69d
+0, 33, 33, 1, 23040, 0x86d5c0ff
+0, 34, 34, 1, 23040, 0x7d5ec3e4
+0, 35, 35, 1, 23040, 0x5ca1cdb0
+0, 36, 36, 1, 23040, 0xdc11cf9e
+0, 37, 37, 1, 23040, 0x1a7fd0d5
+0, 38, 38, 1, 23040, 0x9884d5cd
+0, 39, 39, 1, 23040, 0xcafbd5fb
+0, 40, 40, 1, 23040, 0xc670ceb7
+0, 41, 41, 1, 23040, 0x63cecef7
+0, 42, 42, 1, 23040, 0xfe29c28c
+0, 43, 43, 1, 23040, 0x368dc66e
+0, 44, 44, 1, 23040, 0x2ec7c4de
+0, 45, 45, 1, 23040, 0x8954c9d6
+0, 46, 46, 1, 23040, 0xff89ca68
+0, 47, 47, 1, 23040, 0x5ae0b290
diff --git a/tests/ref/fate/hevc-conformance-WPP_E_ericsson_MAIN10_2 b/tests/ref/fate/hevc-conformance-WPP_E_ericsson_MAIN10_2
new file mode 100644
index 0000000..dbf6f78
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WPP_E_ericsson_MAIN10_2
@@ -0,0 +1,49 @@
+#tb 0: 1/25
+0, 0, 0, 1, 92160, 0x591c992e
+0, 1, 1, 1, 92160, 0xe7a8cd8b
+0, 2, 2, 1, 92160, 0x2e7528bb
+0, 3, 3, 1, 92160, 0x92438eae
+0, 4, 4, 1, 92160, 0x15cc21b9
+0, 5, 5, 1, 92160, 0x3f14a50e
+0, 6, 6, 1, 92160, 0xdbc712e7
+0, 7, 7, 1, 92160, 0x277b2d3f
+0, 8, 8, 1, 92160, 0x05478988
+0, 9, 9, 1, 92160, 0x46888b9c
+0, 10, 10, 1, 92160, 0xb1f46d1b
+0, 11, 11, 1, 92160, 0xa86771fa
+0, 12, 12, 1, 92160, 0x1294944a
+0, 13, 13, 1, 92160, 0xe134cd44
+0, 14, 14, 1, 92160, 0x5fdbf1fb
+0, 15, 15, 1, 92160, 0x01f04b2e
+0, 16, 16, 1, 92160, 0x50989c28
+0, 17, 17, 1, 92160, 0x3202cf37
+0, 18, 18, 1, 92160, 0x67fbdb0f
+0, 19, 19, 1, 92160, 0x4d453062
+0, 20, 20, 1, 92160, 0x799c3e16
+0, 21, 21, 1, 92160, 0xdda76a94
+0, 22, 22, 1, 92160, 0x392d0fc9
+0, 23, 23, 1, 92160, 0x1196e850
+0, 24, 24, 1, 92160, 0x8758d8a9
+0, 25, 25, 1, 92160, 0xb632c2b3
+0, 26, 26, 1, 92160, 0xf3ba5e47
+0, 27, 27, 1, 92160, 0x3ae40182
+0, 28, 28, 1, 92160, 0xf285e2eb
+0, 29, 29, 1, 92160, 0x826aee47
+0, 30, 30, 1, 92160, 0xe06ba18b
+0, 31, 31, 1, 92160, 0xf34b6ef5
+0, 32, 32, 1, 92160, 0xf94045ab
+0, 33, 33, 1, 92160, 0xd0ae63f4
+0, 34, 34, 1, 92160, 0x4c35afc1
+0, 35, 35, 1, 92160, 0x9a150816
+0, 36, 36, 1, 92160, 0x1a4214d4
+0, 37, 37, 1, 92160, 0x9f042653
+0, 38, 38, 1, 92160, 0xf69a40a8
+0, 39, 39, 1, 92160, 0xb8462c18
+0, 40, 40, 1, 92160, 0xf42d4748
+0, 41, 41, 1, 92160, 0x4968dc19
+0, 42, 42, 1, 92160, 0xc8e6001f
+0, 43, 43, 1, 92160, 0xebb42677
+0, 44, 44, 1, 92160, 0x3fb805dd
+0, 45, 45, 1, 92160, 0x1953cfc1
+0, 46, 46, 1, 92160, 0x633108f4
+0, 47, 47, 1, 92160, 0x65aedf42
diff --git a/tests/ref/fate/hevc-conformance-WPP_E_ericsson_MAIN_2 b/tests/ref/fate/hevc-conformance-WPP_E_ericsson_MAIN_2
new file mode 100644
index 0000000..ac478c6
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WPP_E_ericsson_MAIN_2
@@ -0,0 +1,49 @@
+#tb 0: 1/25
+0, 0, 0, 1, 46080, 0xcd234724
+0, 1, 1, 1, 46080, 0x66649579
+0, 2, 2, 1, 46080, 0x4317d38d
+0, 3, 3, 1, 46080, 0x308dfc39
+0, 4, 4, 1, 46080, 0xe08e3015
+0, 5, 5, 1, 46080, 0xaa0a3e44
+0, 6, 6, 1, 46080, 0x491b61cf
+0, 7, 7, 1, 46080, 0x9c5a9749
+0, 8, 8, 1, 46080, 0x4384ae34
+0, 9, 9, 1, 46080, 0xfd2bf2c1
+0, 10, 10, 1, 46080, 0xf29b18d7
+0, 11, 11, 1, 46080, 0xc1912df5
+0, 12, 12, 1, 46080, 0x9cc3344b
+0, 13, 13, 1, 46080, 0x41c062a3
+0, 14, 14, 1, 46080, 0xa5ec8417
+0, 15, 15, 1, 46080, 0x94e5aed6
+0, 16, 16, 1, 46080, 0x1af6ce24
+0, 17, 17, 1, 46080, 0xd73c0272
+0, 18, 18, 1, 46080, 0xb7b41c50
+0, 19, 19, 1, 46080, 0x7fa442dc
+0, 20, 20, 1, 46080, 0x513e5f5a
+0, 21, 21, 1, 46080, 0x46a1848b
+0, 22, 22, 1, 46080, 0xcf31a1c4
+0, 23, 23, 1, 46080, 0x3ee8c90c
+0, 24, 24, 1, 46080, 0xc54fdd27
+0, 25, 25, 1, 46080, 0x59830556
+0, 26, 26, 1, 46080, 0xf8c70cc7
+0, 27, 27, 1, 46080, 0x44a519f9
+0, 28, 28, 1, 46080, 0xdd0323d3
+0, 29, 29, 1, 46080, 0x93874212
+0, 30, 30, 1, 46080, 0xba8e4d8e
+0, 31, 31, 1, 46080, 0x5c3f4fb0
+0, 32, 32, 1, 46080, 0x37084bf2
+0, 33, 33, 1, 46080, 0xad256b1b
+0, 34, 34, 1, 46080, 0x862b7a7d
+0, 35, 35, 1, 46080, 0x4a2e8d56
+0, 36, 36, 1, 46080, 0xe99d8f5a
+0, 37, 37, 1, 46080, 0xe41a9456
+0, 38, 38, 1, 46080, 0xe7339f1c
+0, 39, 39, 1, 46080, 0xfa38a6c3
+0, 40, 40, 1, 46080, 0x219e97d2
+0, 41, 41, 1, 46080, 0x652d9cc2
+0, 42, 42, 1, 46080, 0x40bf8f94
+0, 43, 43, 1, 46080, 0x2fee9e23
+0, 44, 44, 1, 46080, 0xeea39203
+0, 45, 45, 1, 46080, 0x69819b5c
+0, 46, 46, 1, 46080, 0x511ba0b5
+0, 47, 47, 1, 46080, 0x85fd892f
diff --git a/tests/ref/fate/hevc-conformance-WPP_F_ericsson_MAIN10_2 b/tests/ref/fate/hevc-conformance-WPP_F_ericsson_MAIN10_2
new file mode 100644
index 0000000..2f103b7
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WPP_F_ericsson_MAIN10_2
@@ -0,0 +1,49 @@
+#tb 0: 1/25
+0, 0, 0, 1, 138240, 0x99f196ae
+0, 1, 1, 1, 138240, 0x45f407de
+0, 2, 2, 1, 138240, 0xdaef815b
+0, 3, 3, 1, 138240, 0x6812ba5a
+0, 4, 4, 1, 138240, 0x1099912d
+0, 5, 5, 1, 138240, 0xf58ee932
+0, 6, 6, 1, 138240, 0x79df05d8
+0, 7, 7, 1, 138240, 0xa0813719
+0, 8, 8, 1, 138240, 0xe9c7c5c0
+0, 9, 9, 1, 138240, 0xe8c5aba3
+0, 10, 10, 1, 138240, 0x7f0ed0b6
+0, 11, 11, 1, 138240, 0x1bdcfd20
+0, 12, 12, 1, 138240, 0x3b1fc007
+0, 13, 13, 1, 138240, 0xf6a9d270
+0, 14, 14, 1, 138240, 0x3a2d47d4
+0, 15, 15, 1, 138240, 0xbeb9685f
+0, 16, 16, 1, 138240, 0x4cb6eb4a
+0, 17, 17, 1, 138240, 0xa456dcdf
+0, 18, 18, 1, 138240, 0x2933f8e1
+0, 19, 19, 1, 138240, 0x27de28e9
+0, 20, 20, 1, 138240, 0x557c0e51
+0, 21, 21, 1, 138240, 0x6f106540
+0, 22, 22, 1, 138240, 0xf78421a4
+0, 23, 23, 1, 138240, 0xa94029a7
+0, 24, 24, 1, 138240, 0xacfa2b8b
+0, 25, 25, 1, 138240, 0x32e7d347
+0, 26, 26, 1, 138240, 0xe4c17fac
+0, 27, 27, 1, 138240, 0x47e61949
+0, 28, 28, 1, 138240, 0xd248e34b
+0, 29, 29, 1, 138240, 0xb747dc2c
+0, 30, 30, 1, 138240, 0x3a0eaf61
+0, 31, 31, 1, 138240, 0x4e254b5f
+0, 32, 32, 1, 138240, 0xf434f578
+0, 33, 33, 1, 138240, 0xe799308e
+0, 34, 34, 1, 138240, 0xb3e67c89
+0, 35, 35, 1, 138240, 0xb6ceb379
+0, 36, 36, 1, 138240, 0xd70bea99
+0, 37, 37, 1, 138240, 0xad0717a8
+0, 38, 38, 1, 138240, 0x2b50f085
+0, 39, 39, 1, 138240, 0xb334e518
+0, 40, 40, 1, 138240, 0xe7311c3a
+0, 41, 41, 1, 138240, 0x7c46dc19
+0, 42, 42, 1, 138240, 0x18c20dfa
+0, 43, 43, 1, 138240, 0x8bc0f6ae
+0, 44, 44, 1, 138240, 0x91a8c381
+0, 45, 45, 1, 138240, 0x2ba57297
+0, 46, 46, 1, 138240, 0x99d982f0
+0, 47, 47, 1, 138240, 0x0f84942a
diff --git a/tests/ref/fate/hevc-conformance-WPP_F_ericsson_MAIN_2 b/tests/ref/fate/hevc-conformance-WPP_F_ericsson_MAIN_2
new file mode 100644
index 0000000..6256d96
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WPP_F_ericsson_MAIN_2
@@ -0,0 +1,49 @@
+#tb 0: 1/25
+0, 0, 0, 1, 69120, 0x28326a13
+0, 1, 1, 1, 69120, 0x1f41a4a7
+0, 2, 2, 1, 69120, 0x803ceeb4
+0, 3, 3, 1, 69120, 0x1eba4049
+0, 4, 4, 1, 69120, 0x61a25512
+0, 5, 5, 1, 69120, 0x4db37e41
+0, 6, 6, 1, 69120, 0x00f69308
+0, 7, 7, 1, 69120, 0x7478c70f
+0, 8, 8, 1, 69120, 0xba1bd40b
+0, 9, 9, 1, 69120, 0x31d416bc
+0, 10, 10, 1, 69120, 0xd0c042bd
+0, 11, 11, 1, 69120, 0xe7a75aba
+0, 12, 12, 1, 69120, 0xb4235b4c
+0, 13, 13, 1, 69120, 0xaad387c3
+0, 14, 14, 1, 69120, 0xb97aab7a
+0, 15, 15, 1, 69120, 0x1acdda47
+0, 16, 16, 1, 69120, 0x2c95f726
+0, 17, 17, 1, 69120, 0xba3f2ebb
+0, 18, 18, 1, 69120, 0x15fc4901
+0, 19, 19, 1, 69120, 0x56387074
+0, 20, 20, 1, 69120, 0xe9638772
+0, 21, 21, 1, 69120, 0x344db5ec
+0, 22, 22, 1, 69120, 0xf54bd087
+0, 23, 23, 1, 69120, 0x5b35fbe4
+0, 24, 24, 1, 69120, 0x052c0947
+0, 25, 25, 1, 69120, 0xe562417c
+0, 26, 26, 1, 69120, 0x502a4776
+0, 27, 27, 1, 69120, 0x46b05919
+0, 28, 28, 1, 69120, 0x103161a1
+0, 29, 29, 1, 69120, 0xd83e8318
+0, 30, 30, 1, 69120, 0xd7ce8fb1
+0, 31, 31, 1, 69120, 0xda3f8ac5
+0, 32, 32, 1, 69120, 0xecd17de1
+0, 33, 33, 1, 69120, 0x7beeab11
+0, 34, 34, 1, 69120, 0xb295b81f
+0, 35, 35, 1, 69120, 0x785ec9ab
+0, 36, 36, 1, 69120, 0x58a3c317
+0, 37, 37, 1, 69120, 0x05feda91
+0, 38, 38, 1, 69120, 0xd21fdcab
+0, 39, 39, 1, 69120, 0x0d6ce0ee
+0, 40, 40, 1, 69120, 0x40ddc715
+0, 41, 41, 1, 69120, 0x5489d3e1
+0, 42, 42, 1, 69120, 0x7f57c42b
+0, 43, 43, 1, 69120, 0xd470cca3
+0, 44, 44, 1, 69120, 0xfb80c51c
+0, 45, 45, 1, 69120, 0x76b1d068
+0, 46, 46, 1, 69120, 0x5b01d81e
+0, 47, 47, 1, 69120, 0x21cfc241
diff --git a/tests/ref/fate/hevc-conformance-WP_A_MAIN10_Toshiba_3 b/tests/ref/fate/hevc-conformance-WP_A_MAIN10_Toshiba_3
new file mode 100644
index 0000000..b2dadba
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WP_A_MAIN10_Toshiba_3
@@ -0,0 +1,257 @@
+#tb 0: 1/25
+0, 0, 0, 1, 299520, 0x7750edc7
+0, 1, 1, 1, 299520, 0x97fb359b
+0, 2, 2, 1, 299520, 0x89ac22bc
+0, 3, 3, 1, 299520, 0x4f7e0ecc
+0, 4, 4, 1, 299520, 0x7367f210
+0, 5, 5, 1, 299520, 0x5c2274e3
+0, 6, 6, 1, 299520, 0x11f26352
+0, 7, 7, 1, 299520, 0x2c712fcc
+0, 8, 8, 1, 299520, 0x44d700aa
+0, 9, 9, 1, 299520, 0x7426fc80
+0, 10, 10, 1, 299520, 0xd31d2fef
+0, 11, 11, 1, 299520, 0xd7c8d389
+0, 12, 12, 1, 299520, 0x2a8283e7
+0, 13, 13, 1, 299520, 0x429f5e44
+0, 14, 14, 1, 299520, 0x5c818504
+0, 15, 15, 1, 299520, 0x1057090e
+0, 16, 16, 1, 299520, 0x61404e77
+0, 17, 17, 1, 299520, 0x8ce43ed3
+0, 18, 18, 1, 299520, 0xf08e6c4d
+0, 19, 19, 1, 299520, 0xb133a69f
+0, 20, 20, 1, 299520, 0xd1be15a5
+0, 21, 21, 1, 299520, 0xe875543f
+0, 22, 22, 1, 299520, 0x0310f356
+0, 23, 23, 1, 299520, 0x5ee0a7d9
+0, 24, 24, 1, 299520, 0xacd092bb
+0, 25, 25, 1, 299520, 0x878ef783
+0, 26, 26, 1, 299520, 0xed9a2c06
+0, 27, 27, 1, 299520, 0x0a4cb661
+0, 28, 28, 1, 299520, 0x69aed89b
+0, 29, 29, 1, 299520, 0xaa75d081
+0, 30, 30, 1, 299520, 0x4c0402c6
+0, 31, 31, 1, 299520, 0x7050b8f8
+0, 32, 32, 1, 299520, 0x20cf8db8
+0, 33, 33, 1, 299520, 0xa615d0cb
+0, 34, 34, 1, 299520, 0x3170b77f
+0, 35, 35, 1, 299520, 0x781f17a5
+0, 36, 36, 1, 299520, 0x8767468b
+0, 37, 37, 1, 299520, 0x8f291a78
+0, 38, 38, 1, 299520, 0x87534588
+0, 39, 39, 1, 299520, 0xb4861cee
+0, 40, 40, 1, 299520, 0x38b6ba36
+0, 41, 41, 1, 299520, 0x757ebda4
+0, 42, 42, 1, 299520, 0xeccca3c0
+0, 43, 43, 1, 299520, 0x8af415a3
+0, 44, 44, 1, 299520, 0x37064dea
+0, 45, 45, 1, 299520, 0xfea46d66
+0, 46, 46, 1, 299520, 0x038d776f
+0, 47, 47, 1, 299520, 0x2b905161
+0, 48, 48, 1, 299520, 0x60230f44
+0, 49, 49, 1, 299520, 0x828f8991
+0, 50, 50, 1, 299520, 0x7c5ded06
+0, 51, 51, 1, 299520, 0xef38fd3a
+0, 52, 52, 1, 299520, 0x4c08ea42
+0, 53, 53, 1, 299520, 0x66dd9974
+0, 54, 54, 1, 299520, 0x4af1e690
+0, 55, 55, 1, 299520, 0x3fce05be
+0, 56, 56, 1, 299520, 0x07ccca7a
+0, 57, 57, 1, 299520, 0x1113a830
+0, 58, 58, 1, 299520, 0xe095faa8
+0, 59, 59, 1, 299520, 0x01da87b4
+0, 60, 60, 1, 299520, 0xecd3ea56
+0, 61, 61, 1, 299520, 0x8b80d26b
+0, 62, 62, 1, 299520, 0x625b4844
+0, 63, 63, 1, 299520, 0x1f96bc19
+0, 64, 64, 1, 299520, 0x8de15c59
+0, 65, 65, 1, 299520, 0x8de15c59
+0, 66, 66, 1, 299520, 0xe0f88d0d
+0, 67, 67, 1, 299520, 0xe0f88d0d
+0, 68, 68, 1, 299520, 0xf951adca
+0, 69, 69, 1, 299520, 0x3159e1a0
+0, 70, 70, 1, 299520, 0xa3b9764d
+0, 71, 71, 1, 299520, 0xa294c4db
+0, 72, 72, 1, 299520, 0x9ddd0aa8
+0, 73, 73, 1, 299520, 0x47702302
+0, 74, 74, 1, 299520, 0xebd66219
+0, 75, 75, 1, 299520, 0x9daa6030
+0, 76, 76, 1, 299520, 0x74aad521
+0, 77, 77, 1, 299520, 0x74aad521
+0, 78, 78, 1, 299520, 0x6be83092
+0, 79, 79, 1, 299520, 0x87e19ded
+0, 80, 80, 1, 299520, 0x41f4552c
+0, 81, 81, 1, 299520, 0xdbbd4643
+0, 82, 82, 1, 299520, 0x85505e9d
+0, 83, 83, 1, 299520, 0x33692949
+0, 84, 84, 1, 299520, 0x2d3ded88
+0, 85, 85, 1, 299520, 0x211ed3d4
+0, 86, 86, 1, 299520, 0x9dd3c6b8
+0, 87, 87, 1, 299520, 0x96016144
+0, 88, 88, 1, 299520, 0xdb86dd3a
+0, 89, 89, 1, 299520, 0x2a07d782
+0, 90, 90, 1, 299520, 0x4baeac21
+0, 91, 91, 1, 299520, 0x9426dbd3
+0, 92, 92, 1, 299520, 0x69203a74
+0, 93, 93, 1, 299520, 0x69203a74
+0, 94, 94, 1, 299520, 0xcb3e55c2
+0, 95, 95, 1, 299520, 0xbbc8dea2
+0, 96, 96, 1, 299520, 0x19b27f0d
+0, 97, 97, 1, 299520, 0x0edb8988
+0, 98, 98, 1, 299520, 0x0b3a8feb
+0, 99, 99, 1, 299520, 0xa2a3a4b4
+0, 100, 100, 1, 299520, 0xeb26e563
+0, 101, 101, 1, 299520, 0xd3fb037e
+0, 102, 102, 1, 299520, 0x106089ed
+0, 103, 103, 1, 299520, 0x606fb6ed
+0, 104, 104, 1, 299520, 0x6e14a326
+0, 105, 105, 1, 299520, 0x875cfdab
+0, 106, 106, 1, 299520, 0xa1f316f9
+0, 107, 107, 1, 299520, 0x444fff4a
+0, 108, 108, 1, 299520, 0x9c7b6c8a
+0, 109, 109, 1, 299520, 0xffd0ffa3
+0, 110, 110, 1, 299520, 0x278941d9
+0, 111, 111, 1, 299520, 0x05a1552f
+0, 112, 112, 1, 299520, 0x5b564fbc
+0, 113, 113, 1, 299520, 0x25ffb96d
+0, 114, 114, 1, 299520, 0x6e389daf
+0, 115, 115, 1, 299520, 0x1b48132b
+0, 116, 116, 1, 299520, 0xcc9b5df0
+0, 117, 117, 1, 299520, 0xe8895d00
+0, 118, 118, 1, 299520, 0x35ea30df
+0, 119, 119, 1, 299520, 0x8dcf07b4
+0, 120, 120, 1, 299520, 0x1cf3780e
+0, 121, 121, 1, 299520, 0x5f1a6062
+0, 122, 122, 1, 299520, 0xe2ac4ed0
+0, 123, 123, 1, 299520, 0x07fe56aa
+0, 124, 124, 1, 299520, 0xe892eab8
+0, 125, 125, 1, 299520, 0xdeda11d7
+0, 126, 126, 1, 299520, 0xc8134b3f
+0, 127, 127, 1, 299520, 0x8baa039a
+0, 128, 128, 1, 299520, 0x8ec71908
+0, 129, 129, 1, 299520, 0x8ec71908
+0, 130, 130, 1, 299520, 0x73ae1f71
+0, 131, 131, 1, 299520, 0xb615e210
+0, 132, 132, 1, 299520, 0x7afe31e6
+0, 133, 133, 1, 299520, 0x38362f5b
+0, 134, 134, 1, 299520, 0xbb7c2fad
+0, 135, 135, 1, 299520, 0xe08720c1
+0, 136, 136, 1, 299520, 0xb1118297
+0, 137, 137, 1, 299520, 0x33740a04
+0, 138, 138, 1, 299520, 0x567c1e9c
+0, 139, 139, 1, 299520, 0x3911af2a
+0, 140, 140, 1, 299520, 0xec64ec95
+0, 141, 141, 1, 299520, 0x83128903
+0, 142, 142, 1, 299520, 0xd11a7835
+0, 143, 143, 1, 299520, 0xd96bc851
+0, 144, 144, 1, 299520, 0x726696ba
+0, 145, 145, 1, 299520, 0x35c6b8e4
+0, 146, 146, 1, 299520, 0xd238e317
+0, 147, 147, 1, 299520, 0xf28c861b
+0, 148, 148, 1, 299520, 0x5d49132b
+0, 149, 149, 1, 299520, 0xcbadef81
+0, 150, 150, 1, 299520, 0x1fbcfda6
+0, 151, 151, 1, 299520, 0xa18a07b6
+0, 152, 152, 1, 299520, 0xa1631bb5
+0, 153, 153, 1, 299520, 0xcb80f2d6
+0, 154, 154, 1, 299520, 0x88b23aae
+0, 155, 155, 1, 299520, 0xbaa50ebe
+0, 156, 156, 1, 299520, 0x1bc7151d
+0, 157, 157, 1, 299520, 0x7254b9a4
+0, 158, 158, 1, 299520, 0xd66682cb
+0, 159, 159, 1, 299520, 0x846c055b
+0, 160, 160, 1, 299520, 0x4d0ac94f
+0, 161, 161, 1, 299520, 0xf9a01b25
+0, 162, 162, 1, 299520, 0x193dc288
+0, 163, 163, 1, 299520, 0xf43fb875
+0, 164, 164, 1, 299520, 0xf4fd6452
+0, 165, 165, 1, 299520, 0xafcdfb2a
+0, 166, 166, 1, 299520, 0x5c342ad7
+0, 167, 167, 1, 299520, 0xfe7943ec
+0, 168, 168, 1, 299520, 0xc7e8a82d
+0, 169, 169, 1, 299520, 0x99b1ed3f
+0, 170, 170, 1, 299520, 0x4decbdb8
+0, 171, 171, 1, 299520, 0x3cb0ccc2
+0, 172, 172, 1, 299520, 0x3b210547
+0, 173, 173, 1, 299520, 0xb8dee8bf
+0, 174, 174, 1, 299520, 0x75124e85
+0, 175, 175, 1, 299520, 0xbd390ba5
+0, 176, 176, 1, 299520, 0x5030302d
+0, 177, 177, 1, 299520, 0x38a4c990
+0, 178, 178, 1, 299520, 0x6d091561
+0, 179, 179, 1, 299520, 0x4598d16a
+0, 180, 180, 1, 299520, 0xa60c8a7c
+0, 181, 181, 1, 299520, 0x1987b4ab
+0, 182, 182, 1, 299520, 0x3fc66893
+0, 183, 183, 1, 299520, 0x3fc66893
+0, 184, 184, 1, 299520, 0x84694e9d
+0, 185, 185, 1, 299520, 0x84694e9d
+0, 186, 186, 1, 299520, 0xa736933c
+0, 187, 187, 1, 299520, 0x994e35f8
+0, 188, 188, 1, 299520, 0x80999aab
+0, 189, 189, 1, 299520, 0x5cf09e35
+0, 190, 190, 1, 299520, 0x8678f05d
+0, 191, 191, 1, 299520, 0xe4ca13df
+0, 192, 192, 1, 299520, 0x0ab1fc5b
+0, 193, 193, 1, 299520, 0x949977a6
+0, 194, 194, 1, 299520, 0x0ab1fc5b
+0, 195, 195, 1, 299520, 0xb5677d4e
+0, 196, 196, 1, 299520, 0xefd5e34c
+0, 197, 197, 1, 299520, 0xfb5875da
+0, 198, 198, 1, 299520, 0x3520759c
+0, 199, 199, 1, 299520, 0xc30dbfb6
+0, 200, 200, 1, 299520, 0xcedb09c4
+0, 201, 201, 1, 299520, 0xced1dc4a
+0, 202, 202, 1, 299520, 0xcf7d3425
+0, 203, 203, 1, 299520, 0xede92113
+0, 204, 204, 1, 299520, 0x6ca1204e
+0, 205, 205, 1, 299520, 0x04a46f67
+0, 206, 206, 1, 299520, 0x1bd8fe03
+0, 207, 207, 1, 299520, 0x11dab44d
+0, 208, 208, 1, 299520, 0xc0d1109c
+0, 209, 209, 1, 299520, 0x9e19c78f
+0, 210, 210, 1, 299520, 0xcffab4cb
+0, 211, 211, 1, 299520, 0x07582785
+0, 212, 212, 1, 299520, 0x43182694
+0, 213, 213, 1, 299520, 0x76f8c058
+0, 214, 214, 1, 299520, 0x895cbd03
+0, 215, 215, 1, 299520, 0xec9f9014
+0, 216, 216, 1, 299520, 0xd9cc6c00
+0, 217, 217, 1, 299520, 0xf15c775e
+0, 218, 218, 1, 299520, 0xe4b60e06
+0, 219, 219, 1, 299520, 0x5d825ea9
+0, 220, 220, 1, 299520, 0xd39d2f4a
+0, 221, 221, 1, 299520, 0x9b8dfedc
+0, 222, 222, 1, 299520, 0xc851ce8f
+0, 223, 223, 1, 299520, 0xdc399f09
+0, 224, 224, 1, 299520, 0xbce817c6
+0, 225, 225, 1, 299520, 0x48cc865e
+0, 226, 226, 1, 299520, 0xf875c060
+0, 227, 227, 1, 299520, 0xb3b4b0a3
+0, 228, 228, 1, 299520, 0xce683731
+0, 229, 229, 1, 299520, 0xeddd5126
+0, 230, 230, 1, 299520, 0x2ecf505e
+0, 231, 231, 1, 299520, 0x631c4af2
+0, 232, 232, 1, 299520, 0x1cc7742e
+0, 233, 233, 1, 299520, 0xc5124083
+0, 234, 234, 1, 299520, 0x4a851970
+0, 235, 235, 1, 299520, 0xbfad7925
+0, 236, 236, 1, 299520, 0x92058c0e
+0, 237, 237, 1, 299520, 0x7ecd39b5
+0, 238, 238, 1, 299520, 0x58887a74
+0, 239, 239, 1, 299520, 0xb0825813
+0, 240, 240, 1, 299520, 0xbc763455
+0, 241, 241, 1, 299520, 0x3b259a45
+0, 242, 242, 1, 299520, 0xb200177c
+0, 243, 243, 1, 299520, 0x1cb15851
+0, 244, 244, 1, 299520, 0xd73a92cd
+0, 245, 245, 1, 299520, 0xe43419cf
+0, 246, 246, 1, 299520, 0xf0facff1
+0, 247, 247, 1, 299520, 0xc931e638
+0, 248, 248, 1, 299520, 0xc33e31e7
+0, 249, 249, 1, 299520, 0x03b43a26
+0, 250, 250, 1, 299520, 0x85d64d60
+0, 251, 251, 1, 299520, 0x86a8848c
+0, 252, 252, 1, 299520, 0x5f09afaf
+0, 253, 253, 1, 299520, 0xb7e92098
+0, 254, 254, 1, 299520, 0xf1957fad
+0, 255, 255, 1, 299520, 0xf29dc4b0
diff --git a/tests/ref/fate/hevc-conformance-WP_A_Toshiba_3 b/tests/ref/fate/hevc-conformance-WP_A_Toshiba_3
new file mode 100644
index 0000000..a8c5df3
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WP_A_Toshiba_3
@@ -0,0 +1,257 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xf4bafc83
+0, 1, 1, 1, 149760, 0x611ca492
+0, 2, 2, 1, 149760, 0x8fa9bbb1
+0, 3, 3, 1, 149760, 0x3926aed3
+0, 4, 4, 1, 149760, 0x33e4f7f0
+0, 5, 5, 1, 149760, 0x03cc4fab
+0, 6, 6, 1, 149760, 0xbfae58e5
+0, 7, 7, 1, 149760, 0x0e6f1fea
+0, 8, 8, 1, 149760, 0x5a2ed57e
+0, 9, 9, 1, 149760, 0x5513cc3a
+0, 10, 10, 1, 149760, 0xd610ccca
+0, 11, 11, 1, 149760, 0xbf27617f
+0, 12, 12, 1, 149760, 0x878cd03b
+0, 13, 13, 1, 149760, 0x7b7ec3e9
+0, 14, 14, 1, 149760, 0xdaff0ba7
+0, 15, 15, 1, 149760, 0xce3be576
+0, 16, 16, 1, 149760, 0x16d32b84
+0, 17, 17, 1, 149760, 0xb7f6a144
+0, 18, 18, 1, 149760, 0x4dfb9b67
+0, 19, 19, 1, 149760, 0x29cb06ba
+0, 20, 20, 1, 149760, 0xcee5f14c
+0, 21, 21, 1, 149760, 0xe05bde26
+0, 22, 22, 1, 149760, 0xf717e789
+0, 23, 23, 1, 149760, 0xbbbf0ce8
+0, 24, 24, 1, 149760, 0x0e3ccfb1
+0, 25, 25, 1, 149760, 0x84204399
+0, 26, 26, 1, 149760, 0x02063b2b
+0, 27, 27, 1, 149760, 0xa4198aab
+0, 28, 28, 1, 149760, 0x4a4075aa
+0, 29, 29, 1, 149760, 0x1869435b
+0, 30, 30, 1, 149760, 0x04a12a8b
+0, 31, 31, 1, 149760, 0x7ab3f640
+0, 32, 32, 1, 149760, 0xba55f83a
+0, 33, 33, 1, 149760, 0xa8abaa48
+0, 34, 34, 1, 149760, 0x25483cb4
+0, 35, 35, 1, 149760, 0xc6925d6d
+0, 36, 36, 1, 149760, 0xc944b04d
+0, 37, 37, 1, 149760, 0xd7093017
+0, 38, 38, 1, 149760, 0x8d11c574
+0, 39, 39, 1, 149760, 0xdbaab3e1
+0, 40, 40, 1, 149760, 0xb412a3d9
+0, 41, 41, 1, 149760, 0x37b918a6
+0, 42, 42, 1, 149760, 0x6f6e7575
+0, 43, 43, 1, 149760, 0x059a55de
+0, 44, 44, 1, 149760, 0xe75aa6e6
+0, 45, 45, 1, 149760, 0x627394bf
+0, 46, 46, 1, 149760, 0xbcf99ab9
+0, 47, 47, 1, 149760, 0x29c52e30
+0, 48, 48, 1, 149760, 0x22056e1a
+0, 49, 49, 1, 149760, 0xf272fa39
+0, 50, 50, 1, 149760, 0x4b89033e
+0, 51, 51, 1, 149760, 0x0a59e138
+0, 52, 52, 1, 149760, 0x61a1a6c8
+0, 53, 53, 1, 149760, 0xe5414697
+0, 54, 54, 1, 149760, 0x6db38ec2
+0, 55, 55, 1, 149760, 0x2d09b0ba
+0, 56, 56, 1, 149760, 0x014a751e
+0, 57, 57, 1, 149760, 0x3e6f78d6
+0, 58, 58, 1, 149760, 0xed483aab
+0, 59, 59, 1, 149760, 0xcf366ee0
+0, 60, 60, 1, 149760, 0x4fc5e2dc
+0, 61, 61, 1, 149760, 0xf2a16393
+0, 62, 62, 1, 149760, 0xaa7ff5be
+0, 63, 63, 1, 149760, 0xa8c4c963
+0, 64, 64, 1, 149760, 0x3af766cf
+0, 65, 65, 1, 149760, 0x3af766cf
+0, 66, 66, 1, 149760, 0x11de29e7
+0, 67, 67, 1, 149760, 0x3aa137c0
+0, 68, 68, 1, 149760, 0x6f5bf4c4
+0, 69, 69, 1, 149760, 0xa5b8f392
+0, 70, 70, 1, 149760, 0x106ee459
+0, 71, 71, 1, 149760, 0x65dd99cc
+0, 72, 72, 1, 149760, 0x96facd15
+0, 73, 73, 1, 149760, 0x3355cb07
+0, 74, 74, 1, 149760, 0xe994f26b
+0, 75, 75, 1, 149760, 0xe955f0d5
+0, 76, 76, 1, 149760, 0xb740949e
+0, 77, 77, 1, 149760, 0x0b95963b
+0, 78, 78, 1, 149760, 0xdf7cf302
+0, 79, 79, 1, 149760, 0x8805c30d
+0, 80, 80, 1, 149760, 0xc30c832a
+0, 81, 81, 1, 149760, 0x696836a7
+0, 82, 82, 1, 149760, 0x696836a7
+0, 83, 83, 1, 149760, 0x4c7e0e68
+0, 84, 84, 1, 149760, 0xfee52485
+0, 85, 85, 1, 149760, 0xebbe8381
+0, 86, 86, 1, 149760, 0xb30ff0a9
+0, 87, 87, 1, 149760, 0x4ddafbfb
+0, 88, 88, 1, 149760, 0x5449c902
+0, 89, 89, 1, 149760, 0x79e61161
+0, 90, 90, 1, 149760, 0x72f1a340
+0, 91, 91, 1, 149760, 0xf98bae64
+0, 92, 92, 1, 149760, 0x253dd19f
+0, 93, 93, 1, 149760, 0x253dd19f
+0, 94, 94, 1, 149760, 0xc16e6af4
+0, 95, 95, 1, 149760, 0x66f2a539
+0, 96, 96, 1, 149760, 0xfccfd340
+0, 97, 97, 1, 149760, 0xd76a28c9
+0, 98, 98, 1, 149760, 0x38797af0
+0, 99, 99, 1, 149760, 0x06165c19
+0, 100, 100, 1, 149760, 0x9afee257
+0, 101, 101, 1, 149760, 0x1b2ce435
+0, 102, 102, 1, 149760, 0xb3e2de89
+0, 103, 103, 1, 149760, 0xb585e81f
+0, 104, 104, 1, 149760, 0x6743ece6
+0, 105, 105, 1, 149760, 0xfe5a001f
+0, 106, 106, 1, 149760, 0x064a778f
+0, 107, 107, 1, 149760, 0x99907eef
+0, 108, 108, 1, 149760, 0x1b9ec247
+0, 109, 109, 1, 149760, 0x52adad6c
+0, 110, 110, 1, 149760, 0xf5176bd9
+0, 111, 111, 1, 149760, 0xefdfa365
+0, 112, 112, 1, 149760, 0xa2e8447f
+0, 113, 113, 1, 149760, 0x3ea43a87
+0, 114, 114, 1, 149760, 0xbe643579
+0, 115, 115, 1, 149760, 0x518ae330
+0, 116, 116, 1, 149760, 0x49d815e6
+0, 117, 117, 1, 149760, 0xbfbb1bf0
+0, 118, 118, 1, 149760, 0x19596f6f
+0, 119, 119, 1, 149760, 0x4f6cbeec
+0, 120, 120, 1, 149760, 0xdd3f7460
+0, 121, 121, 1, 149760, 0xf2bb54f3
+0, 122, 122, 1, 149760, 0xb9d5d7cd
+0, 123, 123, 1, 149760, 0xe62736a5
+0, 124, 124, 1, 149760, 0x29c6f950
+0, 125, 125, 1, 149760, 0x99e1faed
+0, 126, 126, 1, 149760, 0x5c149afe
+0, 127, 127, 1, 149760, 0xb4118f9b
+0, 128, 128, 1, 149760, 0x262d7f30
+0, 129, 129, 1, 149760, 0x262d7f30
+0, 130, 130, 1, 149760, 0x13e286ed
+0, 131, 131, 1, 149760, 0xee6b3447
+0, 132, 132, 1, 149760, 0x9e749867
+0, 133, 133, 1, 149760, 0xdbca6bab
+0, 134, 134, 1, 149760, 0x154c9331
+0, 135, 135, 1, 149760, 0x653a3058
+0, 136, 136, 1, 149760, 0x739c1e57
+0, 137, 137, 1, 149760, 0x8e05e122
+0, 138, 138, 1, 149760, 0xe21f583a
+0, 139, 139, 1, 149760, 0xa58149fc
+0, 140, 140, 1, 149760, 0x90bd3787
+0, 141, 141, 1, 149760, 0x385aa42a
+0, 142, 142, 1, 149760, 0xf2589fc6
+0, 143, 143, 1, 149760, 0xd5233b3b
+0, 144, 144, 1, 149760, 0x2cc2d9cc
+0, 145, 145, 1, 149760, 0xb9b0eeef
+0, 146, 146, 1, 149760, 0xa9a60da9
+0, 147, 147, 1, 149760, 0xb854378a
+0, 148, 148, 1, 149760, 0xa76e2c37
+0, 149, 149, 1, 149760, 0xbe5c0542
+0, 150, 150, 1, 149760, 0x4d78b907
+0, 151, 151, 1, 149760, 0x6119f5d7
+0, 152, 152, 1, 149760, 0x195ae3c8
+0, 153, 153, 1, 149760, 0x35e9de61
+0, 154, 154, 1, 149760, 0x99f0df3b
+0, 155, 155, 1, 149760, 0x1a0ebfee
+0, 156, 156, 1, 149760, 0x4ece0a87
+0, 157, 157, 1, 149760, 0x670773b9
+0, 158, 158, 1, 149760, 0xae8c2789
+0, 159, 159, 1, 149760, 0xa145e3f8
+0, 160, 160, 1, 149760, 0x130d2ea3
+0, 161, 161, 1, 149760, 0x9afdf6dc
+0, 162, 162, 1, 149760, 0x8f8ed056
+0, 163, 163, 1, 149760, 0x8d50ad5c
+0, 164, 164, 1, 149760, 0x50b41bbb
+0, 165, 165, 1, 149760, 0xe8a89c0b
+0, 166, 166, 1, 149760, 0x4862c664
+0, 167, 167, 1, 149760, 0x9f99193f
+0, 168, 168, 1, 149760, 0x3d2ea4d8
+0, 169, 169, 1, 149760, 0xfcb83723
+0, 170, 170, 1, 149760, 0x2e135fe9
+0, 171, 171, 1, 149760, 0xcd059eeb
+0, 172, 172, 1, 149760, 0xcc2914ab
+0, 173, 173, 1, 149760, 0x63a4cf21
+0, 174, 174, 1, 149760, 0x0bdf9666
+0, 175, 175, 1, 149760, 0x8fcd46d9
+0, 176, 176, 1, 149760, 0xa2a94d81
+0, 177, 177, 1, 149760, 0x72da1124
+0, 178, 178, 1, 149760, 0x4faf50a2
+0, 179, 179, 1, 149760, 0x52168ea8
+0, 180, 180, 1, 149760, 0x766cd6e4
+0, 181, 181, 1, 149760, 0x9a76dd3f
+0, 182, 182, 1, 149760, 0xacf745bb
+0, 183, 183, 1, 149760, 0xacf745bb
+0, 184, 184, 1, 149760, 0x5d0f5914
+0, 185, 185, 1, 149760, 0x5d0f5914
+0, 186, 186, 1, 149760, 0x491b5959
+0, 187, 187, 1, 149760, 0xce9bf07f
+0, 188, 188, 1, 149760, 0x45123e08
+0, 189, 189, 1, 149760, 0x7ec1ced4
+0, 190, 190, 1, 149760, 0x7ec1ced4
+0, 191, 191, 1, 149760, 0xd383e72e
+0, 192, 192, 1, 149760, 0x29558d4c
+0, 193, 193, 1, 149760, 0xdcea6ec3
+0, 194, 194, 1, 149760, 0x29558d4c
+0, 195, 195, 1, 149760, 0x55b305ad
+0, 196, 196, 1, 149760, 0x68326c39
+0, 197, 197, 1, 149760, 0x89c8c0f7
+0, 198, 198, 1, 149760, 0x1fb33243
+0, 199, 199, 1, 149760, 0xa07b14e8
+0, 200, 200, 1, 149760, 0x6b37b02f
+0, 201, 201, 1, 149760, 0x7453171e
+0, 202, 202, 1, 149760, 0xec95ce93
+0, 203, 203, 1, 149760, 0xdbb0481b
+0, 204, 204, 1, 149760, 0xe44eaafd
+0, 205, 205, 1, 149760, 0xcdf5dfd5
+0, 206, 206, 1, 149760, 0x42695b4e
+0, 207, 207, 1, 149760, 0xe4e26db0
+0, 208, 208, 1, 149760, 0xada778f6
+0, 209, 209, 1, 149760, 0x77dab36a
+0, 210, 210, 1, 149760, 0xcabeb23d
+0, 211, 211, 1, 149760, 0x43d21021
+0, 212, 212, 1, 149760, 0xe4a5280c
+0, 213, 213, 1, 149760, 0xeb408a99
+0, 214, 214, 1, 149760, 0x0751fc6c
+0, 215, 215, 1, 149760, 0x2e770c68
+0, 216, 216, 1, 149760, 0x5a799fb0
+0, 217, 217, 1, 149760, 0x0e2e22dd
+0, 218, 218, 1, 149760, 0x276e6e88
+0, 219, 219, 1, 149760, 0xf83b9da4
+0, 220, 220, 1, 149760, 0xd4599290
+0, 221, 221, 1, 149760, 0xd4599290
+0, 222, 222, 1, 149760, 0xcf41ec75
+0, 223, 223, 1, 149760, 0x84af0bfc
+0, 224, 224, 1, 149760, 0x59db5c12
+0, 225, 225, 1, 149760, 0x0405a92a
+0, 226, 226, 1, 149760, 0xfde2c0fe
+0, 227, 227, 1, 149760, 0x96a68bab
+0, 228, 228, 1, 149760, 0x7e9d4983
+0, 229, 229, 1, 149760, 0x27b724c9
+0, 230, 230, 1, 149760, 0x402cdb15
+0, 231, 231, 1, 149760, 0x0d89328b
+0, 232, 232, 1, 149760, 0x08847a7e
+0, 233, 233, 1, 149760, 0x8eb7f52f
+0, 234, 234, 1, 149760, 0x49bf75bb
+0, 235, 235, 1, 149760, 0xbd6c77e3
+0, 236, 236, 1, 149760, 0x9eb5a5c0
+0, 237, 237, 1, 149760, 0xb5900c9b
+0, 238, 238, 1, 149760, 0xa9278bd6
+0, 239, 239, 1, 149760, 0x688d4c01
+0, 240, 240, 1, 149760, 0xe2669ce6
+0, 241, 241, 1, 149760, 0xb80590b9
+0, 242, 242, 1, 149760, 0xcdcc0036
+0, 243, 243, 1, 149760, 0xad653077
+0, 244, 244, 1, 149760, 0xe87179ae
+0, 245, 245, 1, 149760, 0x91553e8b
+0, 246, 246, 1, 149760, 0xd254f2b4
+0, 247, 247, 1, 149760, 0xe284e289
+0, 248, 248, 1, 149760, 0x09118405
+0, 249, 249, 1, 149760, 0x5f46d196
+0, 250, 250, 1, 149760, 0xfee1f4be
+0, 251, 251, 1, 149760, 0xbccf48bc
+0, 252, 252, 1, 149760, 0x48327792
+0, 253, 253, 1, 149760, 0x3d893b3c
+0, 254, 254, 1, 149760, 0xb2ae071d
+0, 255, 255, 1, 149760, 0x278e0be3
diff --git a/tests/ref/fate/hevc-conformance-WP_B_Toshiba_3 b/tests/ref/fate/hevc-conformance-WP_B_Toshiba_3
new file mode 100644
index 0000000..7dbc72b
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WP_B_Toshiba_3
@@ -0,0 +1,257 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xd8bf0c39
+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
new file mode 100644
index 0000000..332c7df
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-WP_MAIN10_B_Toshiba_3
@@ -0,0 +1,257 @@
+#tb 0: 1/25
+0, 0, 0, 1, 299520, 0x6ecba46b
+0, 1, 1, 1, 299520, 0x54e6ef0a
+0, 2, 2, 1, 299520, 0x7a4d46c5
+0, 3, 3, 1, 299520, 0xccd57f4e
+0, 4, 4, 1, 299520, 0xbe0cb48d
+0, 5, 5, 1, 299520, 0x10e7b49f
+0, 6, 6, 1, 299520, 0x81aa72e2
+0, 7, 7, 1, 299520, 0x5bf7b51f
+0, 8, 8, 1, 299520, 0xfcedee4a
+0, 9, 9, 1, 299520, 0x586c99b6
+0, 10, 10, 1, 299520, 0x414ca13c
+0, 11, 11, 1, 299520, 0x3f0162f2
+0, 12, 12, 1, 299520, 0x4d450c05
+0, 13, 13, 1, 299520, 0x0a58bd84
+0, 14, 14, 1, 299520, 0x26e8394d
+0, 15, 15, 1, 299520, 0xfd78121b
+0, 16, 16, 1, 299520, 0x6afeaf44
+0, 17, 17, 1, 299520, 0x3e9a9270
+0, 18, 18, 1, 299520, 0x58b889ca
+0, 19, 19, 1, 299520, 0x0245ba62
+0, 20, 20, 1, 299520, 0xddecc5ab
+0, 21, 21, 1, 299520, 0x32cf3cd9
+0, 22, 22, 1, 299520, 0x5c0a0440
+0, 23, 23, 1, 299520, 0x9d3e2fee
+0, 24, 24, 1, 299520, 0x2894c708
+0, 25, 25, 1, 299520, 0x25be67d5
+0, 26, 26, 1, 299520, 0xe3ece9d6
+0, 27, 27, 1, 299520, 0xcc98e38b
+0, 28, 28, 1, 299520, 0xc448c794
+0, 29, 29, 1, 299520, 0xb4f75575
+0, 30, 30, 1, 299520, 0xac74a437
+0, 31, 31, 1, 299520, 0x09c7f2e2
+0, 32, 32, 1, 299520, 0xbfaed8ab
+0, 33, 33, 1, 299520, 0xb077d700
+0, 34, 34, 1, 299520, 0x6efa0545
+0, 35, 35, 1, 299520, 0xb8c1802d
+0, 36, 36, 1, 299520, 0x794774f8
+0, 37, 37, 1, 299520, 0x1098f4ff
+0, 38, 38, 1, 299520, 0x80ab8bfc
+0, 39, 39, 1, 299520, 0xc324c3bc
+0, 40, 40, 1, 299520, 0x1eee77cd
+0, 41, 41, 1, 299520, 0x7147e72e
+0, 42, 42, 1, 299520, 0x1a34883c
+0, 43, 43, 1, 299520, 0x74e93e31
+0, 44, 44, 1, 299520, 0x89410382
+0, 45, 45, 1, 299520, 0xfcce0ce1
+0, 46, 46, 1, 299520, 0x07bb33c6
+0, 47, 47, 1, 299520, 0xc1ee7318
+0, 48, 48, 1, 299520, 0xd1c4bd2d
+0, 49, 49, 1, 299520, 0xa670cfae
+0, 50, 50, 1, 299520, 0x718de79b
+0, 51, 51, 1, 299520, 0x85e40b78
+0, 52, 52, 1, 299520, 0x15362e72
+0, 53, 53, 1, 299520, 0xc6e523fa
+0, 54, 54, 1, 299520, 0x3e536edd
+0, 55, 55, 1, 299520, 0x9312996e
+0, 56, 56, 1, 299520, 0x9456d53c
+0, 57, 57, 1, 299520, 0x7bc01398
+0, 58, 58, 1, 299520, 0x5a40bcb4
+0, 59, 59, 1, 299520, 0xcfe126ce
+0, 60, 60, 1, 299520, 0xd9e1adf1
+0, 61, 61, 1, 299520, 0x9027b1ae
+0, 62, 62, 1, 299520, 0x4c1372fb
+0, 63, 63, 1, 299520, 0xe475a00b
+0, 64, 64, 1, 299520, 0x945bc646
+0, 65, 65, 1, 299520, 0xc33dbab3
+0, 66, 66, 1, 299520, 0x9e4afb82
+0, 67, 67, 1, 299520, 0x1bffa858
+0, 68, 68, 1, 299520, 0x3bc78ad7
+0, 69, 69, 1, 299520, 0xa096e683
+0, 70, 70, 1, 299520, 0xb889aa23
+0, 71, 71, 1, 299520, 0x8ffad857
+0, 72, 72, 1, 299520, 0x59d3cc7c
+0, 73, 73, 1, 299520, 0x47d1377a
+0, 74, 74, 1, 299520, 0xea73e864
+0, 75, 75, 1, 299520, 0x0994bd5c
+0, 76, 76, 1, 299520, 0xdf779d85
+0, 77, 77, 1, 299520, 0x8238cfa7
+0, 78, 78, 1, 299520, 0x8f2e94cc
+0, 79, 79, 1, 299520, 0x9e0b0df8
+0, 80, 80, 1, 299520, 0x98ac1ce5
+0, 81, 81, 1, 299520, 0xc1c293ed
+0, 82, 82, 1, 299520, 0x1f1dfedb
+0, 83, 83, 1, 299520, 0xe7297d56
+0, 84, 84, 1, 299520, 0xa1390726
+0, 85, 85, 1, 299520, 0xf0e828e8
+0, 86, 86, 1, 299520, 0x108b8291
+0, 87, 87, 1, 299520, 0xd8830efb
+0, 88, 88, 1, 299520, 0xeee3d2f0
+0, 89, 89, 1, 299520, 0xa35d5b29
+0, 90, 90, 1, 299520, 0xa14d0840
+0, 91, 91, 1, 299520, 0xfa894a56
+0, 92, 92, 1, 299520, 0xd50005b5
+0, 93, 93, 1, 299520, 0xba625134
+0, 94, 94, 1, 299520, 0xce7dd782
+0, 95, 95, 1, 299520, 0x9e04e32f
+0, 96, 96, 1, 299520, 0x07e6d466
+0, 97, 97, 1, 299520, 0x4e66e1d4
+0, 98, 98, 1, 299520, 0x80aa6be6
+0, 99, 99, 1, 299520, 0xa4564be8
+0, 100, 100, 1, 299520, 0x7d34e443
+0, 101, 101, 1, 299520, 0xd5a08c86
+0, 102, 102, 1, 299520, 0xa73e63e8
+0, 103, 103, 1, 299520, 0x93937eb2
+0, 104, 104, 1, 299520, 0x0c08ba8f
+0, 105, 105, 1, 299520, 0x1d6b1a8c
+0, 106, 106, 1, 299520, 0x2e0272b4
+0, 107, 107, 1, 299520, 0x47177676
+0, 108, 108, 1, 299520, 0x6af7ffce
+0, 109, 109, 1, 299520, 0x0564a4bc
+0, 110, 110, 1, 299520, 0x7f664100
+0, 111, 111, 1, 299520, 0x6decd6ae
+0, 112, 112, 1, 299520, 0xb2d94adc
+0, 113, 113, 1, 299520, 0x55d33809
+0, 114, 114, 1, 299520, 0x5b126674
+0, 115, 115, 1, 299520, 0xd25d5750
+0, 116, 116, 1, 299520, 0x789a7f89
+0, 117, 117, 1, 299520, 0xdd082ab2
+0, 118, 118, 1, 299520, 0x3e6132ee
+0, 119, 119, 1, 299520, 0xe48209ca
+0, 120, 120, 1, 299520, 0x707d3b24
+0, 121, 121, 1, 299520, 0x8af19539
+0, 122, 122, 1, 299520, 0x0bbb4c38
+0, 123, 123, 1, 299520, 0xaaba4bd6
+0, 124, 124, 1, 299520, 0xa325d79e
+0, 125, 125, 1, 299520, 0x2bd4b64a
+0, 126, 126, 1, 299520, 0xab0c59a7
+0, 127, 127, 1, 299520, 0x260a56fc
+0, 128, 128, 1, 299520, 0xa1a55847
+0, 129, 129, 1, 299520, 0xa1a55847
+0, 130, 130, 1, 299520, 0x01438514
+0, 131, 131, 1, 299520, 0xa511e8bd
+0, 132, 132, 1, 299520, 0x7ebfd5b9
+0, 133, 133, 1, 299520, 0xdf4f1365
+0, 134, 134, 1, 299520, 0x6266911a
+0, 135, 135, 1, 299520, 0xe8eefcab
+0, 136, 136, 1, 299520, 0x7e74ca0d
+0, 137, 137, 1, 299520, 0x4b21d349
+0, 138, 138, 1, 299520, 0xa8b9ef41
+0, 139, 139, 1, 299520, 0x3187ee5b
+0, 140, 140, 1, 299520, 0x3fadb935
+0, 141, 141, 1, 299520, 0x8dca0391
+0, 142, 142, 1, 299520, 0x68215cc6
+0, 143, 143, 1, 299520, 0x7c81f366
+0, 144, 144, 1, 299520, 0x1a976381
+0, 145, 145, 1, 299520, 0x8ac095f4
+0, 146, 146, 1, 299520, 0xf5f8752b
+0, 147, 147, 1, 299520, 0xd8c03c80
+0, 148, 148, 1, 299520, 0x445a2e07
+0, 149, 149, 1, 299520, 0xddb83c6f
+0, 150, 150, 1, 299520, 0xc6dfe76a
+0, 151, 151, 1, 299520, 0x860a120f
+0, 152, 152, 1, 299520, 0x1ec91a95
+0, 153, 153, 1, 299520, 0x0180cc49
+0, 154, 154, 1, 299520, 0x63a115e3
+0, 155, 155, 1, 299520, 0x8848e971
+0, 156, 156, 1, 299520, 0x49246622
+0, 157, 157, 1, 299520, 0x3169db32
+0, 158, 158, 1, 299520, 0xcf01d8a3
+0, 159, 159, 1, 299520, 0x57a1a9c1
+0, 160, 160, 1, 299520, 0x517670eb
+0, 161, 161, 1, 299520, 0x4e2e6b5a
+0, 162, 162, 1, 299520, 0x06240a68
+0, 163, 163, 1, 299520, 0xa0d076a1
+0, 164, 164, 1, 299520, 0xb73c4515
+0, 165, 165, 1, 299520, 0x9f523268
+0, 166, 166, 1, 299520, 0x6fdcc6a2
+0, 167, 167, 1, 299520, 0xf3f5b69f
+0, 168, 168, 1, 299520, 0xce33a286
+0, 169, 169, 1, 299520, 0xce46e834
+0, 170, 170, 1, 299520, 0x14a6fe0d
+0, 171, 171, 1, 299520, 0x39a8145f
+0, 172, 172, 1, 299520, 0x91981d47
+0, 173, 173, 1, 299520, 0x1507d9be
+0, 174, 174, 1, 299520, 0x4525d4a2
+0, 175, 175, 1, 299520, 0x95e058ab
+0, 176, 176, 1, 299520, 0x8de2438a
+0, 177, 177, 1, 299520, 0xf43dc0ff
+0, 178, 178, 1, 299520, 0xaf232f4b
+0, 179, 179, 1, 299520, 0x8adabd81
+0, 180, 180, 1, 299520, 0x1e837b72
+0, 181, 181, 1, 299520, 0xb79f811d
+0, 182, 182, 1, 299520, 0x1532fb05
+0, 183, 183, 1, 299520, 0x2e3f6341
+0, 184, 184, 1, 299520, 0x10c82269
+0, 185, 185, 1, 299520, 0x8c39bd0c
+0, 186, 186, 1, 299520, 0x64fefe7b
+0, 187, 187, 1, 299520, 0x3ef6d5c7
+0, 188, 188, 1, 299520, 0x571c1edc
+0, 189, 189, 1, 299520, 0xe9e1584c
+0, 190, 190, 1, 299520, 0xd150a0db
+0, 191, 191, 1, 299520, 0x5d140f2d
+0, 192, 192, 1, 299520, 0xea00f302
+0, 193, 193, 1, 299520, 0xdd4e0fc4
+0, 194, 194, 1, 299520, 0x51c760fa
+0, 195, 195, 1, 299520, 0x68d5d26e
+0, 196, 196, 1, 299520, 0xde594a02
+0, 197, 197, 1, 299520, 0xac6d361a
+0, 198, 198, 1, 299520, 0xef6506ae
+0, 199, 199, 1, 299520, 0x744737a8
+0, 200, 200, 1, 299520, 0x2bd0834b
+0, 201, 201, 1, 299520, 0x348a8d0f
+0, 202, 202, 1, 299520, 0x93e165c8
+0, 203, 203, 1, 299520, 0x208d305c
+0, 204, 204, 1, 299520, 0xb927ed9a
+0, 205, 205, 1, 299520, 0xd252b13a
+0, 206, 206, 1, 299520, 0x11a59b2d
+0, 207, 207, 1, 299520, 0xc27785d0
+0, 208, 208, 1, 299520, 0x5c654cb5
+0, 209, 209, 1, 299520, 0x3d03a387
+0, 210, 210, 1, 299520, 0xdb0dc19d
+0, 211, 211, 1, 299520, 0x2ef3bbba
+0, 212, 212, 1, 299520, 0x7d36cd79
+0, 213, 213, 1, 299520, 0xa9ceca1e
+0, 214, 214, 1, 299520, 0x33db4d99
+0, 215, 215, 1, 299520, 0x8d28a55e
+0, 216, 216, 1, 299520, 0x554864a6
+0, 217, 217, 1, 299520, 0x6a336557
+0, 218, 218, 1, 299520, 0xd2285832
+0, 219, 219, 1, 299520, 0x9509f5f8
+0, 220, 220, 1, 299520, 0x8e479b03
+0, 221, 221, 1, 299520, 0x9513a8c3
+0, 222, 222, 1, 299520, 0x81080fac
+0, 223, 223, 1, 299520, 0x6c447b69
+0, 224, 224, 1, 299520, 0xbf4c2fbd
+0, 225, 225, 1, 299520, 0x1a77306e
+0, 226, 226, 1, 299520, 0xd485864b
+0, 227, 227, 1, 299520, 0x4e87b787
+0, 228, 228, 1, 299520, 0xe28e7153
+0, 229, 229, 1, 299520, 0x2ab24b9b
+0, 230, 230, 1, 299520, 0xffcb7357
+0, 231, 231, 1, 299520, 0x5e1e2b7e
+0, 232, 232, 1, 299520, 0x58d39e6d
+0, 233, 233, 1, 299520, 0x4a2b836a
+0, 234, 234, 1, 299520, 0xa1728e1e
+0, 235, 235, 1, 299520, 0x33e5bdd4
+0, 236, 236, 1, 299520, 0x3b144d98
+0, 237, 237, 1, 299520, 0xe72c4de2
+0, 238, 238, 1, 299520, 0x031350cb
+0, 239, 239, 1, 299520, 0x146fba58
+0, 240, 240, 1, 299520, 0x1b6679c7
+0, 241, 241, 1, 299520, 0x27e9d545
+0, 242, 242, 1, 299520, 0x5105beeb
+0, 243, 243, 1, 299520, 0x80284fd3
+0, 244, 244, 1, 299520, 0x426a5d65
+0, 245, 245, 1, 299520, 0xdcc33f89
+0, 246, 246, 1, 299520, 0x29e805ec
+0, 247, 247, 1, 299520, 0x89a09ed9
+0, 248, 248, 1, 299520, 0x60ad258c
+0, 249, 249, 1, 299520, 0xb44ee9b1
+0, 250, 250, 1, 299520, 0x184d6a88
+0, 251, 251, 1, 299520, 0xb4c8cefe
+0, 252, 252, 1, 299520, 0x358a0407
+0, 253, 253, 1, 299520, 0xa5cb97eb
+0, 254, 254, 1, 299520, 0x3d6a096e
+0, 255, 255, 1, 299520, 0xcb266e78
diff --git a/tests/ref/fate/hevc-conformance-cip_B_NEC_2 b/tests/ref/fate/hevc-conformance-cip_B_NEC_2
new file mode 100644
index 0000000..016f0f1
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-cip_B_NEC_2
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xcbda260f
+0, 1, 1, 1, 149760, 0xbd8d32a9
+0, 2, 2, 1, 149760, 0x39562006
+0, 3, 3, 1, 149760, 0xbc62475b
+0, 4, 4, 1, 149760, 0x1bf1fb79
diff --git a/tests/ref/fate/hevc-conformance-ipcm_A_NEC_2 b/tests/ref/fate/hevc-conformance-ipcm_A_NEC_2
new file mode 100644
index 0000000..145f590
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-ipcm_A_NEC_2
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x2356474c
diff --git a/tests/ref/fate/hevc-conformance-ipcm_B_NEC_2 b/tests/ref/fate/hevc-conformance-ipcm_B_NEC_2
new file mode 100644
index 0000000..d917cbc
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-ipcm_B_NEC_2
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xc80d43f8
diff --git a/tests/ref/fate/hevc-conformance-ipcm_C_NEC_2 b/tests/ref/fate/hevc-conformance-ipcm_C_NEC_2
new file mode 100644
index 0000000..6c89cea
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-ipcm_C_NEC_2
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xb92d38ee
diff --git a/tests/ref/fate/hevc-conformance-ipcm_D_NEC_2 b/tests/ref/fate/hevc-conformance-ipcm_D_NEC_2
new file mode 100644
index 0000000..2ccff05
--- a/dev/null
+++ b/tests/ref/fate/hevc-conformance-ipcm_D_NEC_2
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xa24d17f8
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..9d25b13 100644
--- a/tests/ref/fate/idroq-video-encode
+++ b/tests/ref/fate/idroq-video-encode
@@ -1 +1 @@
-2ac89fa0e5600152667bcbc661f06cfe
+50fa863f7820bb22ddeb74d5adf5f0bc
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..f13e691 100644
--- a/tests/ref/fate/iv8-demux
+++ b/tests/ref/fate/iv8-demux
@@ -19,8 +19,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
new file mode 100644
index 0000000..b0a6008
--- a/dev/null
+++ b/tests/ref/fate/jv
@@ -0,0 +1,8 @@
+#tb 0: 2/25
+0, 0, 0, 1, 192000, 0x00000000
+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..c57fce0
--- a/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
+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
--- a/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..f8a6e21 100644
--- a/tests/ref/fate/lmlm4-demux
+++ b/tests/ref/fate/lmlm4-demux
@@ -3,215 +3,215 @@
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
--- a/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
--- a/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..98c8540
--- a/dev/null
+++ b/tests/ref/fate/mapchan-6ch-extract-2
@@ -0,0 +1,2 @@
+6f091fe8c0be88c75921731dc9f74314
+5c2d162b9024329eb367295d37b8ca0a
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..f42de0c
--- a/dev/null
+++ b/tests/ref/fate/mapchan-6ch-extract-2-downmix-mono
@@ -0,0 +1 @@
+959645ed73e6d08d8f1e947eac5d0b92
diff --git a/tests/ref/fate/mapchan-silent-mono b/tests/ref/fate/mapchan-silent-mono
new file mode 100644
index 0000000..a867e3b
--- a/dev/null
+++ b/tests/ref/fate/mapchan-silent-mono
@@ -0,0 +1 @@
+4f5148f08587a4b9794aa52aec7852ac
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..78440b2
--- a/dev/null
+++ b/tests/ref/fate/mkv
@@ -0,0 +1,217 @@
+#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/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/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..a781c08 100644
--- a/tests/ref/fate/mtv
+++ b/tests/ref/fate/mtv
@@ -133,6 +133,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
--- a/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..454722e 100644
--- a/tests/ref/fate/mxf-demux
+++ b/tests/ref/fate/mxf-demux
@@ -2,98 +2,98 @@
#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
--- a/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..f03aded 100644
--- a/tests/ref/fate/nc-demux
+++ b/tests/ref/fate/nc-demux
@@ -1,92 +1,92 @@
#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
--- a/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/paf-audio b/tests/ref/fate/paf-audio
new file mode 100644
index 0000000..ba47d5d
--- a/dev/null
+++ b/tests/ref/fate/paf-audio
@@ -0,0 +1,7 @@
+#tb 0: 1/22050
+0, 0, 0, 57330, 229320, 0x062508b4
+0, 57330, 57330, 57330, 229320, 0x0a966cbf
+0, 114660, 114660, 57330, 229320, 0xee9bad45
+0, 171990, 171990, 57330, 229320, 0xde88274e
+0, 229320, 229320, 57330, 229320, 0x2fdeeaf6
+0, 286650, 286650, 57330, 229320, 0xf793fe5b
diff --git a/tests/ref/fate/paf-demux b/tests/ref/fate/paf-demux
new file mode 100644
index 0000000..857fb54
--- a/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/paf-video b/tests/ref/fate/paf-video
new file mode 100644
index 0000000..ed37c28
--- a/dev/null
+++ b/tests/ref/fate/paf-video
@@ -0,0 +1,153 @@
+#tb 0: 1/10
+0, 0, 0, 1, 147456, 0x00000000
+0, 1, 1, 1, 147456, 0x7be40798
+0, 2, 2, 1, 147456, 0x44bc2fc0
+0, 3, 3, 1, 147456, 0x82676740
+0, 4, 4, 1, 147456, 0xd8b8ad10
+0, 5, 5, 1, 147456, 0x816f1c51
+0, 6, 6, 1, 147456, 0x43cdb992
+0, 7, 7, 1, 147456, 0x795198be
+0, 8, 8, 1, 147456, 0x4738b47b
+0, 9, 9, 1, 147456, 0xd05f2cca
+0, 10, 10, 1, 147456, 0xe1b2d879
+0, 11, 11, 1, 147456, 0x538e0987
+0, 12, 12, 1, 147456, 0x2009cbce
+0, 13, 13, 1, 147456, 0xf4fedfdf
+0, 14, 14, 1, 147456, 0x288cfddb
+0, 15, 15, 1, 147456, 0x27be3801
+0, 16, 16, 1, 147456, 0xba20cf85
+0, 17, 17, 1, 147456, 0x16dda72f
+0, 18, 18, 1, 147456, 0x06742d33
+0, 19, 19, 1, 147456, 0x268b800a
+0, 20, 20, 1, 147456, 0x3094518e
+0, 21, 21, 1, 147456, 0xea944b0d
+0, 22, 22, 1, 147456, 0xf99990e0
+0, 23, 23, 1, 147456, 0x609a90de
+0, 24, 24, 1, 147456, 0xcde18594
+0, 25, 25, 1, 147456, 0x86b3d02d
+0, 26, 26, 1, 147456, 0x38d99cd7
+0, 27, 27, 1, 147456, 0x5cbfa3d2
+0, 28, 28, 1, 147456, 0xf292759f
+0, 29, 29, 1, 147456, 0xdae223dd
+0, 30, 30, 1, 147456, 0x55097657
+0, 31, 31, 1, 147456, 0x5ea6276c
+0, 32, 32, 1, 147456, 0x85532d21
+0, 33, 33, 1, 147456, 0x21c447d1
+0, 34, 34, 1, 147456, 0x6cbb700d
+0, 35, 35, 1, 147456, 0x889c443a
+0, 36, 36, 1, 147456, 0xad4171fd
+0, 37, 37, 1, 147456, 0xab26d665
+0, 38, 38, 1, 147456, 0xcf8a2e29
+0, 39, 39, 1, 147456, 0xc934a62a
+0, 40, 40, 1, 147456, 0xacca580c
+0, 41, 41, 1, 147456, 0xacca580c
+0, 42, 42, 1, 147456, 0xacca580c
+0, 43, 43, 1, 147456, 0xacca580c
+0, 44, 44, 1, 147456, 0xacca580c
+0, 45, 45, 1, 147456, 0xacca580c
+0, 46, 46, 1, 147456, 0xacca580c
+0, 47, 47, 1, 147456, 0xacca580c
+0, 48, 48, 1, 147456, 0xacca580c
+0, 49, 49, 1, 147456, 0xacca580c
+0, 50, 50, 1, 147456, 0xacca580c
+0, 51, 51, 1, 147456, 0xacca580c
+0, 52, 52, 1, 147456, 0xacca580c
+0, 53, 53, 1, 147456, 0xacca580c
+0, 54, 54, 1, 147456, 0xacca580c
+0, 55, 55, 1, 147456, 0xacca580c
+0, 56, 56, 1, 147456, 0xacca580c
+0, 57, 57, 1, 147456, 0xacca580c
+0, 58, 58, 1, 147456, 0xdd6a7104
+0, 59, 59, 1, 147456, 0x33e84c72
+0, 60, 60, 1, 147456, 0x86526e6a
+0, 61, 61, 1, 147456, 0x569863ad
+0, 62, 62, 1, 147456, 0x6269920f
+0, 63, 63, 1, 147456, 0x9ce49665
+0, 64, 64, 1, 147456, 0x782fcf56
+0, 65, 65, 1, 147456, 0x4401ef4a
+0, 66, 66, 1, 147456, 0xe06ffba8
+0, 67, 67, 1, 147456, 0xc87b2af3
+0, 68, 68, 1, 147456, 0x9fcaf0ef
+0, 69, 69, 1, 147456, 0x00000000
+0, 70, 70, 1, 147456, 0x00000000
+0, 71, 71, 1, 147456, 0x00000000
+0, 72, 72, 1, 147456, 0x00000000
+0, 73, 73, 1, 147456, 0x00000000
+0, 74, 74, 1, 147456, 0x00000000
+0, 75, 75, 1, 147456, 0x00000000
+0, 76, 76, 1, 147456, 0x00000000
+0, 77, 77, 1, 147456, 0x00000000
+0, 78, 78, 1, 147456, 0x00000000
+0, 79, 79, 1, 147456, 0x00000000
+0, 80, 80, 1, 147456, 0xc30c145f
+0, 81, 81, 1, 147456, 0x2d51e3c6
+0, 82, 82, 1, 147456, 0x5d41d6d2
+0, 83, 83, 1, 147456, 0x7abf857a
+0, 84, 84, 1, 147456, 0xd72e22f3
+0, 85, 85, 1, 147456, 0x89548b30
+0, 86, 86, 1, 147456, 0xd26fc965
+0, 87, 87, 1, 147456, 0xc664fe62
+0, 88, 88, 1, 147456, 0x51608d9e
+0, 89, 89, 1, 147456, 0xf188e257
+0, 90, 90, 1, 147456, 0x3d82f8bd
+0, 91, 91, 1, 147456, 0x08e38aa9
+0, 92, 92, 1, 147456, 0xb0c78fc3
+0, 93, 93, 1, 147456, 0xeec1ce57
+0, 94, 94, 1, 147456, 0xac75dd73
+0, 95, 95, 1, 147456, 0x94beecca
+0, 96, 96, 1, 147456, 0xfa417ee8
+0, 97, 97, 1, 147456, 0x68ee990a
+0, 98, 98, 1, 147456, 0x3df4bcd2
+0, 99, 99, 1, 147456, 0xff68d376
+0, 100, 100, 1, 147456, 0x4a211592
+0, 101, 101, 1, 147456, 0x6ce6b6f2
+0, 102, 102, 1, 147456, 0x8f17ca91
+0, 103, 103, 1, 147456, 0xcb94232c
+0, 104, 104, 1, 147456, 0x46b58bcd
+0, 105, 105, 1, 147456, 0x260e8b49
+0, 106, 106, 1, 147456, 0xd9f55cb1
+0, 107, 107, 1, 147456, 0x96e0b93c
+0, 108, 108, 1, 147456, 0xdbb4e51c
+0, 109, 109, 1, 147456, 0x3a4c7fcd
+0, 110, 110, 1, 147456, 0x25c58597
+0, 111, 111, 1, 147456, 0xfc0afd6a
+0, 112, 112, 1, 147456, 0x65aae479
+0, 113, 113, 1, 147456, 0x9c060d17
+0, 114, 114, 1, 147456, 0xac1f5d8c
+0, 115, 115, 1, 147456, 0x627bf813
+0, 116, 116, 1, 147456, 0x2b6d2bbc
+0, 117, 117, 1, 147456, 0x4d6b8274
+0, 118, 118, 1, 147456, 0x89ab152b
+0, 119, 119, 1, 147456, 0xdcb31afc
+0, 120, 120, 1, 147456, 0x9aac1a8b
+0, 121, 121, 1, 147456, 0xe8ad1a42
+0, 122, 122, 1, 147456, 0x05e019de
+0, 123, 123, 1, 147456, 0x541e1991
+0, 124, 124, 1, 147456, 0xeb5d182b
+0, 125, 125, 1, 147456, 0x00ef16e4
+0, 126, 126, 1, 147456, 0xe91a164b
+0, 127, 127, 1, 147456, 0xc37014bf
+0, 128, 128, 1, 147456, 0xb87b130a
+0, 129, 129, 1, 147456, 0x879f1202
+0, 130, 130, 1, 147456, 0x8de710f6
+0, 131, 131, 1, 147456, 0x499910b0
+0, 132, 132, 1, 147456, 0x494f0f49
+0, 133, 133, 1, 147456, 0x1d090f09
+0, 134, 134, 1, 147456, 0x31930e92
+0, 135, 135, 1, 147456, 0x42fe0d72
+0, 136, 136, 1, 147456, 0xc8980c5d
+0, 137, 137, 1, 147456, 0xd1fc0b7b
+0, 138, 138, 1, 147456, 0x2b620a27
+0, 139, 139, 1, 147456, 0xe9cf08f4
+0, 140, 140, 1, 147456, 0x4fb707ea
+0, 141, 141, 1, 147456, 0x8ec706fa
+0, 142, 142, 1, 147456, 0xde090640
+0, 143, 143, 1, 147456, 0xf7b1059d
+0, 144, 144, 1, 147456, 0xf7b1059d
+0, 145, 145, 1, 147456, 0x581902c4
+0, 146, 146, 1, 147456, 0x2b18d1e7
+0, 147, 147, 1, 147456, 0xe07b8612
+0, 148, 148, 1, 147456, 0xdf341f10
+0, 149, 149, 1, 147456, 0x5c43a9df
+0, 150, 150, 1, 147456, 0xaf121817
+0, 151, 151, 1, 147456, 0x53ba70bf
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/pmp-demux b/tests/ref/fate/pmp-demux
new file mode 100644
index 0000000..b481db7
--- a/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/prores-422 b/tests/ref/fate/prores-422
index 379739f..acd09e3 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, 0xe8e9d448
+0, 1, 1, 1, 8294400, 0xe8e9d448
diff --git a/tests/ref/fate/prores-422_hq b/tests/ref/fate/prores-422_hq
index dc93c33..a404ef4 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, 0x817063b0
+0, 1, 1, 1, 8294400, 0x817063b0
diff --git a/tests/ref/fate/prores-422_lt b/tests/ref/fate/prores-422_lt
index 1c50840..09e2408 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, 0xcd4ccde1
+0, 1, 1, 1, 8294400, 0xcd4ccde1
diff --git a/tests/ref/fate/prores-422_proxy b/tests/ref/fate/prores-422_proxy
index 3763b00..d716f87 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, 0x51d29320
+0, 1, 1, 1, 8294400, 0x51d29320
diff --git a/tests/ref/fate/prores-alpha b/tests/ref/fate/prores-alpha
index 97be6cf..9a8b9ee 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, 0x8dcdb600
+0, 1, 1, 1, 16588800, 0x8dcdb600
diff --git a/tests/ref/fate/prores-alpha_skip b/tests/ref/fate/prores-alpha_skip
new file mode 100644
index 0000000..bdb5c6e
--- a/dev/null
+++ b/tests/ref/fate/prores-alpha_skip
@@ -0,0 +1,3 @@
+#tb 0: 100/2997
+0, 0, 0, 1, 12441600, 0x254d8f95
+0, 1, 1, 1, 12441600, 0x254d8f95
diff --git a/tests/ref/fate/prores-transparency b/tests/ref/fate/prores-transparency
new file mode 100644
index 0000000..9c71d33
--- a/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, 0x20778f5e
+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..a2921a4
--- a/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, 0x58bff47d
+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
--- a/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
--- a/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
--- a/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
--- a/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
new file mode 100644
index 0000000..8b6f903
--- a/dev/null
+++ b/tests/ref/fate/sanm
@@ -0,0 +1,16 @@
+#tb 0: 66667/1000000
+0, 0, 0, 1, 921600, 0x00000000
+0, 1, 1, 1, 921600, 0x00000000
+0, 2, 2, 1, 921600, 0x00000000
+0, 3, 3, 1, 921600, 0x00000000
+0, 4, 4, 1, 921600, 0x00000000
+0, 5, 5, 1, 921600, 0x00000000
+0, 6, 6, 1, 921600, 0x00000000
+0, 7, 7, 1, 921600, 0x00000000
+0, 8, 8, 1, 921600, 0x00000000
+0, 9, 9, 1, 921600, 0x00000000
+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/sha512 b/tests/ref/fate/sha512
new file mode 100644
index 0000000..6009115
--- a/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
--- a/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
--- a/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..c477b0a
--- a/dev/null
+++ b/tests/ref/fate/sub-aqtitle
@@ -0,0 +1 @@
+1c68def68db6536c235819cbe0638e00
diff --git a/tests/ref/fate/sub-charenc b/tests/ref/fate/sub-charenc
new file mode 100644
index 0000000..ef72754
--- a/dev/null
+++ b/tests/ref/fate/sub-charenc
@@ -0,0 +1 @@
+9615088d613931b50fd5016c7535b99a
diff --git a/tests/ref/fate/sub-jacosub b/tests/ref/fate/sub-jacosub
new file mode 100644
index 0000000..b65aee2
--- a/dev/null
+++ b/tests/ref/fate/sub-jacosub
@@ -0,0 +1 @@
+4e8f2d1d4130251163432d2a448680be
diff --git a/tests/ref/fate/sub-microdvd b/tests/ref/fate/sub-microdvd
new file mode 100644
index 0000000..2059989
--- a/dev/null
+++ b/tests/ref/fate/sub-microdvd
@@ -0,0 +1 @@
+35e133576aa3881d2de8dbf39a8d6df7
diff --git a/tests/ref/fate/sub-microdvd-remux b/tests/ref/fate/sub-microdvd-remux
new file mode 100644
index 0000000..24b5d3d
--- a/dev/null
+++ b/tests/ref/fate/sub-microdvd-remux
@@ -0,0 +1 @@
+669e51e357f8a8bd060f2499149c2ded
diff --git a/tests/ref/fate/sub-movtext b/tests/ref/fate/sub-movtext
new file mode 100644
index 0000000..d91c243
--- a/dev/null
+++ b/tests/ref/fate/sub-movtext
@@ -0,0 +1 @@
+21453e8ddbbe35d1368a99fe563c969d
diff --git a/tests/ref/fate/sub-movtextenc b/tests/ref/fate/sub-movtextenc
new file mode 100644
index 0000000..fef4a97
--- a/dev/null
+++ b/tests/ref/fate/sub-movtextenc
@@ -0,0 +1 @@
+8cb21f3632e1c86358429fb9402d19d4
diff --git a/tests/ref/fate/sub-mpl2 b/tests/ref/fate/sub-mpl2
new file mode 100644
index 0000000..8835dd2
--- a/dev/null
+++ b/tests/ref/fate/sub-mpl2
@@ -0,0 +1 @@
+3c2fb62002aec3af16d83135a0e3b0fc
diff --git a/tests/ref/fate/sub-mpsub b/tests/ref/fate/sub-mpsub
new file mode 100644
index 0000000..4e36648
--- a/dev/null
+++ b/tests/ref/fate/sub-mpsub
@@ -0,0 +1 @@
+2c5fafec41479e1d09a32f85e8927d03
diff --git a/tests/ref/fate/sub-mpsub-frames b/tests/ref/fate/sub-mpsub-frames
new file mode 100644
index 0000000..d5bb44e
--- a/dev/null
+++ b/tests/ref/fate/sub-mpsub-frames
@@ -0,0 +1 @@
+cbe6e45848ef77e3080487a88b122104
diff --git a/tests/ref/fate/sub-pjs b/tests/ref/fate/sub-pjs
new file mode 100644
index 0000000..8b382e7
--- a/dev/null
+++ b/tests/ref/fate/sub-pjs
@@ -0,0 +1 @@
+d044f6ffdee48e48efff072b33baee0a
diff --git a/tests/ref/fate/sub-realtext b/tests/ref/fate/sub-realtext
new file mode 100644
index 0000000..42ac3bb
--- a/dev/null
+++ b/tests/ref/fate/sub-realtext
@@ -0,0 +1 @@
+5366f62be001f6fd4a7f48893828bf51
diff --git a/tests/ref/fate/sub-sami b/tests/ref/fate/sub-sami
new file mode 100644
index 0000000..308e000
--- a/dev/null
+++ b/tests/ref/fate/sub-sami
@@ -0,0 +1 @@
+00642e143339b4ca29dc6e990436387c
diff --git a/tests/ref/fate/sub-srt b/tests/ref/fate/sub-srt
index 5a14664..ba5e50a 100644
--- a/tests/ref/fate/sub-srt
+++ b/tests/ref/fate/sub-srt
@@ -1 +1 @@
-03b2a3f7e7e83624c8e4d1b5569df758
+a246a00ed72655cb8db3eaf64a522e0d
diff --git a/tests/ref/fate/sub-subripenc b/tests/ref/fate/sub-subripenc
new file mode 100644
index 0000000..9666e9b
--- a/dev/null
+++ b/tests/ref/fate/sub-subripenc
@@ -0,0 +1 @@
+b7cb0eeb34af0da364e29b238f0634ae
diff --git a/tests/ref/fate/sub-subviewer b/tests/ref/fate/sub-subviewer
new file mode 100644
index 0000000..abae1f7
--- a/dev/null
+++ b/tests/ref/fate/sub-subviewer
@@ -0,0 +1 @@
+aef995d49af4517b40589b72cfa918f7
diff --git a/tests/ref/fate/sub-subviewer1 b/tests/ref/fate/sub-subviewer1
new file mode 100644
index 0000000..052431a
--- a/dev/null
+++ b/tests/ref/fate/sub-subviewer1
@@ -0,0 +1 @@
+cbeb015b1125757eed814f212cfc6c9c
diff --git a/tests/ref/fate/sub-vplayer b/tests/ref/fate/sub-vplayer
new file mode 100644
index 0000000..b8fc40e
--- a/dev/null
+++ b/tests/ref/fate/sub-vplayer
@@ -0,0 +1 @@
+c8201c542f43a9ea42a787ac74d28049
diff --git a/tests/ref/fate/sub-webvtt b/tests/ref/fate/sub-webvtt
new file mode 100644
index 0000000..45cccde
--- a/dev/null
+++ b/tests/ref/fate/sub-webvtt
@@ -0,0 +1 @@
+2cf38e2c99f8717f78a91a3f31197fb4
diff --git a/tests/ref/fate/sub2video b/tests/ref/fate/sub2video
new file mode 100644
index 0000000..39d00c7
--- a/dev/null
+++ b/tests/ref/fate/sub2video
@@ -0,0 +1,95 @@
+#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/targa-conformance-CCM8 b/tests/ref/fate/targa-conformance-CCM8
index aad3bfc..45bb181 100644
--- a/tests/ref/fate/targa-conformance-CCM8
+++ b/tests/ref/fate/targa-conformance-CCM8
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 65536, 0xcf98bc29
+0, 0, 0, 1, 65536, 0x47e97fe9
diff --git a/tests/ref/fate/targa-conformance-UCM8 b/tests/ref/fate/targa-conformance-UCM8
index aad3bfc..45bb181 100644
--- a/tests/ref/fate/targa-conformance-UCM8
+++ b/tests/ref/fate/targa-conformance-UCM8
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 65536, 0xcf98bc29
+0, 0, 0, 1, 65536, 0x47e97fe9
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/txd-16bpp b/tests/ref/fate/txd-16bpp
index 3a23c0b..9522873 100644
--- a/tests/ref/fate/txd-16bpp
+++ b/tests/ref/fate/txd-16bpp
@@ -1,12 +1,12 @@
-#tb 0: 1/90000
-0, 0, 0, 0, 16384, 0x213f9ea8
-0, 18000, 18000, 0, 16384, 0x8185fdb1
-0, 36000, 36000, 0, 16384, 0xf03581d1
-0, 54000, 54000, 0, 16384, 0x629cd573
-0, 72000, 72000, 0, 16384, 0xfe7a5b63
-0, 90000, 90000, 0, 16384, 0x4afc05b2
-0, 108000, 108000, 0, 16384, 0x074b8515
-0, 126000, 126000, 0, 16384, 0x17fde900
-0, 144000, 144000, 0, 16384, 0x831bac76
-0, 162000, 162000, 0, 16384, 0x2fb579f3
-0, 180000, 180000, 0, 16384, 0x68762bed
+#tb 0: 1/5
+0, 0, 0, 1, 16384, 0x213f9ea8
+0, 1, 1, 1, 16384, 0x8185fdb1
+0, 2, 2, 1, 16384, 0xf03581d1
+0, 3, 3, 1, 16384, 0x629cd573
+0, 4, 4, 1, 16384, 0xfe7a5b63
+0, 5, 5, 1, 16384, 0x4afc05b2
+0, 6, 6, 1, 16384, 0x074b8515
+0, 7, 7, 1, 16384, 0x17fde900
+0, 8, 8, 1, 16384, 0x831bac76
+0, 9, 9, 1, 16384, 0x2fb579f3
+0, 10, 10, 1, 16384, 0x68762bed
diff --git a/tests/ref/fate/txd-pal8 b/tests/ref/fate/txd-pal8
index 3f0aab2..61fee80 100644
--- a/tests/ref/fate/txd-pal8
+++ b/tests/ref/fate/txd-pal8
@@ -1,2 +1,2 @@
-#tb 0: 1/90000
-0, 0, 0, 0, 786432, 0x56654d61
+#tb 0: 1/5
+0, 0, 0, 1, 786432, 0x56654d61
diff --git a/tests/ref/fate/unknown_layout-ac3 b/tests/ref/fate/unknown_layout-ac3
new file mode 100644
index 0000000..d332efc
--- a/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
--- a/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..87d5f27 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
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..207c688 100644
--- a/tests/ref/fate/utvideoenc_rgb_none
+++ b/tests/ref/fate/utvideoenc_rgb_none
@@ -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, 301052, 8645cb98470205cceea3c2026223b69f
0, 1, 1, 1, 301068, 9123c3c31ac0bc0832bb07e8c6d5b372
0, 2, 2, 1, 300840, 394aa034eba2b306efa8171efc5fb960
diff --git a/tests/ref/fate/utvideoenc_rgba_left b/tests/ref/fate/utvideoenc_rgba_left
index 757febe..79a4ba7 100644
--- a/tests/ref/fate/utvideoenc_rgba_left
+++ b/tests/ref/fate/utvideoenc_rgba_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, 195264, 5869dee2126d98ecc1fab1e69720906a
0, 1, 1, 1, 195272, 1bd08dcde1061b0d9273bdc6dd901382
0, 2, 2, 1, 195892, 2b3fc3632bcd1cc44f777fb97a56f79b
diff --git a/tests/ref/fate/utvideoenc_rgba_median b/tests/ref/fate/utvideoenc_rgba_median
index 1198a33..88adb0c 100644
--- a/tests/ref/fate/utvideoenc_rgba_median
+++ b/tests/ref/fate/utvideoenc_rgba_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, 195096, 29ad3287ab4d7f4d46968c6d38ba049b
0, 1, 1, 1, 195040, 2c7b4f5f0aee96dca6dc30ce01b3c74d
0, 2, 2, 1, 196044, 7ffc6ab3c4a2eee436ef6a59c72ffb04
diff --git a/tests/ref/fate/utvideoenc_rgba_none b/tests/ref/fate/utvideoenc_rgba_none
index 555409f..3221277 100644
--- a/tests/ref/fate/utvideoenc_rgba_none
+++ b/tests/ref/fate/utvideoenc_rgba_none
@@ -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, 301312, 6912d70f7c20db0b5079a99443ffe65c
0, 1, 1, 1, 301328, 53f1b7d3c2f87ecfe9c9d305771421c5
0, 2, 2, 1, 301100, 7040f2b50dc10b2565fa899ba007983d
diff --git a/tests/ref/fate/utvideoenc_yuv420_left b/tests/ref/fate/utvideoenc_yuv420_left
index cec5a28..0ce4f9d 100644
--- a/tests/ref/fate/utvideoenc_yuv420_left
+++ b/tests/ref/fate/utvideoenc_yuv420_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, 59796, a7136363bc4b9ac663178e5c7f24bae7
0, 1, 1, 1, 60012, d296cf24776234599e22526598de838c
0, 2, 2, 1, 61040, e889f81df51b75acf8131de97f9da4e3
diff --git a/tests/ref/fate/utvideoenc_yuv420_median b/tests/ref/fate/utvideoenc_yuv420_median
index ddd074b..a730f48 100644
--- a/tests/ref/fate/utvideoenc_yuv420_median
+++ b/tests/ref/fate/utvideoenc_yuv420_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, 62876, c21650baa099fb2dfd35d4f8ddce16d1
0, 1, 1, 1, 62832, 034a1996d13c15ee0bf482ddc398aac9
0, 2, 2, 1, 64076, 1f39fd5fc926195b90a3374682a80eac
diff --git a/tests/ref/fate/utvideoenc_yuv420_none b/tests/ref/fate/utvideoenc_yuv420_none
index 555eee2..b960760 100644
--- a/tests/ref/fate/utvideoenc_yuv420_none
+++ b/tests/ref/fate/utvideoenc_yuv420_none
@@ -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, 144508, 83af3948090ebb44a0091815e4edc61e
0, 1, 1, 1, 144496, 950742e357ee489fcda4f783b8df3b4c
0, 2, 2, 1, 144376, 4b818cf0a50e9338fea26101073e445e
diff --git a/tests/ref/fate/utvideoenc_yuv422_left b/tests/ref/fate/utvideoenc_yuv422_left
index d9afc2c..069a221 100644
--- a/tests/ref/fate/utvideoenc_yuv422_left
+++ b/tests/ref/fate/utvideoenc_yuv422_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, 91788, e14e576f1f9abd095f13ceca627adb59
0, 1, 1, 1, 92140, 4b7db11c2d35fa91ff1b6f65c184e3fa
0, 2, 2, 1, 93268, 6ef5cb83a4db2afbf14467cbc4b6c4f7
diff --git a/tests/ref/fate/utvideoenc_yuv422_median b/tests/ref/fate/utvideoenc_yuv422_median
index e1c8fcd..cb9ca44 100644
--- a/tests/ref/fate/utvideoenc_yuv422_median
+++ b/tests/ref/fate/utvideoenc_yuv422_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, 89732, 698174b0d0d68e98774363ca7926f6e1
0, 1, 1, 1, 89652, f0789b7c32ef44207dfc5a454bb5ccee
0, 2, 2, 1, 90868, 6df1dcb1957efca736e88adfbad8557b
diff --git a/tests/ref/fate/utvideoenc_yuv422_none b/tests/ref/fate/utvideoenc_yuv422_none
index ca77177..d15235c 100644
--- a/tests/ref/fate/utvideoenc_yuv422_none
+++ b/tests/ref/fate/utvideoenc_yuv422_none
@@ -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, 191800, 0e1d199f87997ba47e98596b6087d7d4
0, 1, 1, 1, 191820, b35714d0635214095ac06d35da00ed32
0, 2, 2, 1, 191668, 8336829e44f5b90034e5da33dcd27f1f
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/vc1-ism b/tests/ref/fate/vc1-ism
index 4daca95..7d3b0ab 100644
--- a/tests/ref/fate/vc1-ism
+++ b/tests/ref/fate/vc1-ism
@@ -1,121 +1,121 @@
-#tb 0: 1/10000000
-0, 423334, 423334, 0, 37440, 0xd1bc5235
-0, 840000, 840000, 0, 37440, 0x158e6167
-0, 1256666, 1256666, 0, 37440, 0x0faa4481
-0, 1670000, 1670000, 0, 37440, 0x427158c5
-0, 2086666, 2086666, 0, 37440, 0x4eb53ac6
-0, 2500000, 2500000, 0, 37440, 0x99304eea
-0, 2916666, 2916666, 0, 37440, 0xcc554a6f
-0, 3340000, 3340000, 0, 37440, 0xabeb6c35
-0, 3756666, 3756666, 0, 37440, 0xddfc7e18
-0, 4170000, 4170000, 0, 37440, 0xaa79b504
-0, 4586666, 4586666, 0, 37440, 0x5cb1c839
-0, 5000000, 5000000, 0, 37440, 0x7e36ecca
-0, 5416666, 5416666, 0, 37440, 0xf486f425
-0, 5840000, 5840000, 0, 37440, 0xf1b4138f
-0, 6256666, 6256666, 0, 37440, 0x966f1a49
-0, 6670000, 6670000, 0, 37440, 0x5eff21da
-0, 7086666, 7086666, 0, 37440, 0x333f39b1
-0, 7500000, 7500000, 0, 37440, 0x62e5963e
-0, 7916666, 7916666, 0, 37440, 0x26930671
-0, 8340000, 8340000, 0, 37440, 0x27b4bb6c
-0, 8756666, 8756666, 0, 37440, 0xdbd07766
-0, 9170000, 9170000, 0, 37440, 0x04260104
-0, 9586666, 9586666, 0, 37440, 0x9b1e078b
-0, 10000000, 10000000, 0, 37440, 0xdf4e2474
-0, 10416666, 10416666, 0, 37440, 0x57d44986
-0, 10840000, 10840000, 0, 37440, 0x8780e34c
-0, 11256666, 11256666, 0, 37440, 0xf80c8bc0
-0, 11670000, 11670000, 0, 37440, 0x630a7583
-0, 12086666, 12086666, 0, 37440, 0x235ae089
-0, 12500000, 12500000, 0, 37440, 0x984b8f0e
-0, 12916666, 12916666, 0, 37440, 0x865cf592
-0, 13340000, 13340000, 0, 37440, 0x70f376f2
-0, 13756666, 13756666, 0, 37440, 0x8b30c035
-0, 14170000, 14170000, 0, 37440, 0xde772d79
-0, 14586666, 14586666, 0, 37440, 0x8e076be5
-0, 15000000, 15000000, 0, 37440, 0x3dc2bd9f
-0, 15416666, 15416666, 0, 37440, 0xb782eb67
-0, 15840000, 15840000, 0, 37440, 0x02025d73
-0, 16256666, 16256666, 0, 37440, 0x86bbbce8
-0, 16670000, 16670000, 0, 37440, 0xd6554f62
-0, 17086666, 17086666, 0, 37440, 0xb831b917
-0, 17500000, 17500000, 0, 37440, 0x80643560
-0, 17916666, 17916666, 0, 37440, 0x4ecf9afd
-0, 18340000, 18340000, 0, 37440, 0x9ce51e0b
-0, 18756666, 18756666, 0, 37440, 0x179466cd
-0, 19170000, 19170000, 0, 37440, 0x145fc900
-0, 19586666, 19586666, 0, 37440, 0xb1b50402
-0, 20000000, 20000000, 0, 37440, 0x0a87552a
-0, 20416666, 20416666, 0, 37440, 0x8f53821d
-0, 20840000, 20840000, 0, 37440, 0x1c07c825
-0, 21256666, 21256666, 0, 37440, 0x49dde82f
-0, 21670000, 21670000, 0, 37440, 0xb1a32605
-0, 22086666, 22086666, 0, 37440, 0x410f3cd5
-0, 22500000, 22500000, 0, 37440, 0xff5e6696
-0, 22916666, 22916666, 0, 37440, 0x96f678c9
-0, 23340000, 23340000, 0, 37440, 0x6c9e9e68
-0, 23756666, 23756666, 0, 37440, 0x79a2a655
-0, 24170000, 24170000, 0, 37440, 0xf237bd6c
-0, 24586666, 24586666, 0, 37440, 0x4051b611
-0, 25000000, 25000000, 0, 37440, 0xc7ccc918
-0, 25416666, 25416666, 0, 37440, 0xbd02c122
-0, 25840000, 25840000, 0, 37440, 0xacb3c881
-0, 26256666, 26256666, 0, 37440, 0x2abdb940
-0, 26670000, 26670000, 0, 37440, 0x19d5be85
-0, 27086666, 27086666, 0, 37440, 0xfa5fb1ba
-0, 27503332, 27503332, 0, 37440, 0xdae7a7aa
-0, 27919998, 27919998, 0, 37440, 0x6b0f9f69
-0, 28340000, 28340000, 0, 37440, 0x353e8201
-0, 28756666, 28756666, 0, 37440, 0xa21443aa
-0, 29170000, 29170000, 0, 37440, 0x66c8d7e0
-0, 29586666, 29586666, 0, 37440, 0xc332068e
-0, 30000000, 30000000, 0, 37440, 0x71431b9b
-0, 30416666, 30416666, 0, 37440, 0x392f15cb
-0, 30840000, 30840000, 0, 37440, 0x95a146bb
-0, 31256666, 31256666, 0, 37440, 0x7c51740a
-0, 31670000, 31670000, 0, 37440, 0xa3bdd43c
-0, 32086666, 32086666, 0, 37440, 0xa079f965
-0, 32500000, 32500000, 0, 37440, 0xa95423ea
-0, 32916666, 32916666, 0, 37440, 0xd1bd2c67
-0, 33340000, 33340000, 0, 37440, 0x6cf82844
-0, 33756666, 33756666, 0, 37440, 0xd401e128
-0, 34170000, 34170000, 0, 37440, 0x1f7db118
-0, 34586666, 34586666, 0, 37440, 0x2e0a65a9
-0, 35000000, 35000000, 0, 37440, 0x321c1c40
-0, 35416666, 35416666, 0, 37440, 0x95b2a127
-0, 35840000, 35840000, 0, 37440, 0xa1471f4b
-0, 36256666, 36256666, 0, 37440, 0x29d148c0
-0, 36670000, 36670000, 0, 37440, 0x24c07107
-0, 37086666, 37086666, 0, 37440, 0x0ead678d
-0, 37500000, 37500000, 0, 37440, 0xd0ca6495
-0, 37916666, 37916666, 0, 37440, 0x08f935ef
-0, 38340000, 38340000, 0, 37440, 0xb5ec3c38
-0, 38756666, 38756666, 0, 37440, 0xce371628
-0, 39170000, 39170000, 0, 37440, 0x68170812
-0, 39586666, 39586666, 0, 37440, 0xe222699e
-0, 40000000, 40000000, 0, 37440, 0xd688706c
-0, 40416666, 40416666, 0, 37440, 0x81a033f9
-0, 40840000, 40840000, 0, 37440, 0x28bd0fbf
-0, 41256666, 41256666, 0, 37440, 0xe36db7b2
-0, 41670000, 41670000, 0, 37440, 0x30559121
-0, 42086666, 42086666, 0, 37440, 0xbf2b5fc8
-0, 42500000, 42500000, 0, 37440, 0x4b427672
-0, 42916666, 42916666, 0, 37440, 0x0544b0b4
-0, 43340000, 43340000, 0, 37440, 0x38a70b06
-0, 43756666, 43756666, 0, 37440, 0x4ed62607
-0, 44170000, 44170000, 0, 37440, 0x6efe8ea6
-0, 44586666, 44586666, 0, 37440, 0x81197e11
-0, 45000000, 45000000, 0, 37440, 0xf4060050
-0, 45416666, 45416666, 0, 37440, 0xaf205f13
-0, 45840000, 45840000, 0, 37440, 0x5fa21382
-0, 46256666, 46256666, 0, 37440, 0x8627ad05
-0, 46670000, 46670000, 0, 37440, 0xf7130133
-0, 47086666, 47086666, 0, 37440, 0x76dea7ba
-0, 47500000, 47500000, 0, 37440, 0x1dbae1be
-0, 47916666, 47916666, 0, 37440, 0x74a933f7
-0, 48340000, 48340000, 0, 37440, 0xbdcd41a3
-0, 48756666, 48756666, 0, 37440, 0xf0fe8c1c
-0, 49170000, 49170000, 0, 37440, 0xc0036222
-0, 49586666, 49586666, 0, 37440, 0x3058385c
-0, 49586667, 49586667, 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/vima b/tests/ref/fate/vima
new file mode 100644
index 0000000..6984c5d
--- a/dev/null
+++ b/tests/ref/fate/vima
@@ -0,0 +1,17 @@
+#tb 0: 1/22050
+0, 0, 0, 73500, 294000, 0x37d439ee
+0, 73500, 73500, 1470, 5880, 0xe524b177
+0, 74970, 74970, 1470, 5880, 0x9e784af1
+0, 76440, 76440, 1470, 5880, 0x821989b0
+0, 77910, 77910, 1470, 5880, 0x8f4993da
+0, 79380, 79380, 1470, 5880, 0x889a9035
+0, 80850, 80850, 1470, 5880, 0x7f0f5299
+0, 82320, 82320, 1470, 5880, 0xf12f5d2a
+0, 83790, 83790, 1470, 5880, 0xd6292fda
+0, 85260, 85260, 1470, 5880, 0xe1b8405f
+0, 86730, 86730, 1470, 5880, 0xe23d2d44
+0, 88200, 88200, 1470, 5880, 0xe20631a4
+0, 89670, 89670, 1470, 5880, 0x3f72210f
+0, 91140, 91140, 1470, 5880, 0xec0b3fe8
+0, 92610, 92610, 1470, 5880, 0x9615f198
+0, 94080, 94080, 1470, 5880, 0x500226ce
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
--- a/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..f857a87
--- a/dev/null
+++ b/tests/ref/fate/vp8-alpha
@@ -0,0 +1,121 @@
+#tb 0: 1/1000
+0, 1, 1, 0, 2108, 0x59b92a34, S=1, 1900, 0x8fb3adc5
+0, 33, 33, 0, 142, 0x2f2a3fed, F=0x0, S=1, 160, 0xa13346af
+0, 66, 66, 0, 157, 0x17804767, F=0x0, S=1, 209, 0x64115f15
+0, 100, 100, 0, 206, 0x537262ca, F=0x0, S=1, 317, 0x44a09dd0
+0, 133, 133, 0, 259, 0x73ff74b6, F=0x0, S=1, 384, 0x2ee2c588
+0, 166, 166, 0, 320, 0x0fcf8ce4, F=0x0, S=1, 415, 0xff68c953
+0, 200, 200, 0, 377, 0x8fffb5f5, F=0x0, S=1, 475, 0x4166f3eb
+0, 233, 233, 0, 407, 0xe476c19e, F=0x0, S=1, 193, 0x3ff75489
+0, 266, 266, 0, 539, 0x90202334, F=0x0, S=1, 681, 0x776656b0
+0, 300, 300, 0, 560, 0xc6e2168d, F=0x0, S=1, 585, 0xddc81b8a
+0, 333, 333, 0, 597, 0x201a32a7, F=0x0, S=1, 574, 0x8baa1d65
+0, 366, 366, 0, 770, 0xab2b8891, F=0x0, S=1, 666, 0xcd8e51eb
+0, 400, 400, 0, 708, 0xc2386711, F=0x0, S=1, 706, 0x046b6444
+0, 433, 433, 0, 905, 0x7211c52d, F=0x0, S=1, 814, 0x5e288def
+0, 466, 466, 0, 770, 0xda4f8574, F=0x0, S=1, 829, 0xa0e8a949
+0, 500, 500, 0, 955, 0xf9a1d77a, F=0x0, S=1, 857, 0x9b63b955
+0, 533, 533, 0, 970, 0xff4de39a, F=0x0, S=1, 153, 0x3b00416c
+0, 566, 566, 0, 978, 0x12bcf81f, F=0x0, S=1, 1181, 0xce175555
+0, 600, 600, 0, 1233, 0x2903744a, F=0x0, S=1, 860, 0x737eb566
+0, 633, 633, 0, 1118, 0x7f274f50, F=0x0, S=1, 933, 0xb669c6b6
+0, 666, 666, 0, 941, 0x6bffd4b1, F=0x0, S=1, 1058, 0x07581cee
+0, 700, 700, 0, 1598, 0xc007219f, F=0x0, S=1, 939, 0x2c0bdc45
+0, 733, 733, 0, 1218, 0x25d962b6, F=0x0, S=1, 1090, 0x96482341
+0, 766, 766, 0, 1200, 0x86b85be3, F=0x0, S=1, 189, 0x3f085309
+0, 800, 800, 0, 1329, 0x298a848a, F=0x0, S=1, 1426, 0x6ea3df12
+0, 833, 833, 0, 1500, 0xe437edec, F=0x0, S=1, 1244, 0x32836b8d
+0, 866, 866, 0, 1288, 0xc4447dd5, F=0x0, S=1, 1289, 0x06a57b0f
+0, 900, 900, 0, 1281, 0xb5bf7e9f, F=0x0, S=1, 1227, 0xd96d5697
+0, 933, 933, 0, 1372, 0x09be9014, F=0x0, S=1, 1556, 0x2630fbff
+0, 966, 966, 0, 1238, 0x42ce6316, F=0x0, S=1, 1287, 0x1d3084f6
+0, 1000, 1000, 0, 1655, 0xb94b45c2, F=0x0, S=1, 1494, 0x34dbd1a4
+0, 1033, 1033, 0, 1164, 0xf6b93ad0, F=0x0, S=1, 1337, 0xba6d9673
+0, 1066, 1066, 0, 1084, 0x58c50fb5, F=0x0, S=1, 1384, 0x3fabb82b
+0, 1100, 1100, 0, 1151, 0x0b3f3359, F=0x0, S=1, 1353, 0x08e2a1d7
+0, 1133, 1133, 0, 1277, 0xa3ae77e1, F=0x0, S=1, 1409, 0xf65cb9f7
+0, 1166, 1166, 0, 782, 0xdcf671ff, F=0x0, S=1, 1408, 0x01e2ac53
+0, 1200, 1200, 0, 926, 0xe913c286, F=0x0, S=1, 1320, 0x32e38e42
+0, 1233, 1233, 0, 970, 0x3d86e5ae, F=0x0, S=1, 1608, 0x40b52618
+0, 1266, 1266, 0, 1353, 0xe4f197b2, F=0x0, S=1, 1272, 0xf1d272a5
+0, 1300, 1300, 0, 685, 0x629b4ce4, F=0x0, S=1, 1257, 0x14845de9
+0, 1333, 1333, 0, 743, 0x6f1172a3, F=0x0, S=1, 1260, 0xa6c66fda
+0, 1366, 1366, 0, 789, 0x94fc84cd, F=0x0, S=1, 1009, 0x7daaf2b0
+0, 1400, 1400, 0, 1460, 0x668adb82, F=0x0, S=1, 944, 0x44b6ccf5
+0, 1433, 1433, 0, 766, 0x49c884ef, F=0x0, S=1, 996, 0x8646e6dd
+0, 1466, 1466, 0, 1037, 0x24831498, F=0x0, S=1, 983, 0x14a9e7a6
+0, 1500, 1500, 0, 943, 0x1f53d180, F=0x0, S=1, 1107, 0x02f72acb
+0, 1533, 1533, 0, 1152, 0xbf6a35ae, F=0x0, S=1, 1026, 0xd57afda0
+0, 1566, 1566, 0, 730, 0x42806abf, F=0x0, S=1, 1029, 0xfb0402d5
+0, 1600, 1600, 0, 975, 0xa5ffec57, F=0x0, S=1, 1081, 0xe2890cea
+0, 1633, 1633, 0, 970, 0xbe8ee224, F=0x0, S=1, 1151, 0x7b0d3b20
+0, 1666, 1666, 0, 1012, 0x20c6f0d8, F=0x0, S=1, 979, 0xc25cd69c
+0, 1700, 1700, 0, 874, 0x1a2fb4da, F=0x0, S=1, 943, 0xdb2dc9f8
+0, 1733, 1733, 0, 869, 0xab0caf3d, F=0x0, S=1, 934, 0x48b9bfcc
+0, 1766, 1766, 0, 863, 0xd8caa2e5, F=0x0, S=1, 874, 0x0b34b026
+0, 1800, 1800, 0, 1246, 0x47866cdc, F=0x0, S=1, 818, 0x0c908eeb
+0, 1833, 1833, 0, 742, 0xa6296ac1, F=0x0, S=1, 921, 0x97b6b053
+0, 1866, 1866, 0, 828, 0x0b568d7a, F=0x0, S=1, 969, 0x3314dbfa
+0, 1900, 1900, 0, 825, 0x6d329394, F=0x0, S=1, 982, 0x5f66e68c
+0, 1933, 1933, 0, 836, 0x8ace8dfb, F=0x0, S=1, 929, 0x9ffdc2fd
+0, 1966, 1966, 0, 1774, 0xd4686726, F=0x0, S=1, 909, 0x11a9c07a
+0, 2000, 2000, 0, 1803, 0x08c879ce, F=0x0, S=1, 1525, 0x1e11f02f
+0, 2033, 2033, 0, 518, 0x7c32fc72, F=0x0, S=1, 785, 0xfc1f792a
+0, 2066, 2066, 0, 790, 0x3dac8aa0, F=0x0, S=1, 876, 0x0918c88d
+0, 2100, 2100, 0, 927, 0x4feccb24, F=0x0, S=1, 1059, 0xbcaa05c7
+0, 2133, 2133, 0, 835, 0x29d39266, F=0x0, S=1, 980, 0x4913e409
+0, 2166, 2166, 0, 951, 0xc1dddd12, F=0x0, S=1, 1041, 0x0541047e
+0, 2200, 2200, 0, 876, 0x2f6eb89d, F=0x0, S=1, 949, 0x2d56c53b
+0, 2233, 2233, 0, 959, 0xf0dedabd, F=0x0, S=1, 1022, 0x8d33f5fa
+0, 2266, 2266, 0, 860, 0x9274ab39, F=0x0, S=1, 1061, 0x289c0132
+0, 2300, 2300, 0, 863, 0x7058ba30, F=0x0, S=1, 940, 0x1f32d4a3
+0, 2333, 2333, 0, 1021, 0xcabdf84f, F=0x0, S=1, 887, 0xda8ab95e
+0, 2366, 2366, 0, 897, 0x9867c8e8, F=0x0, S=1, 840, 0xd93eaaf5
+0, 2400, 2400, 0, 897, 0x6a16b5db, F=0x0, S=1, 977, 0x7b77dc9b
+0, 2433, 2433, 0, 953, 0xe9b4cf1f, F=0x0, S=1, 921, 0x75a8ca45
+0, 2466, 2466, 0, 847, 0x0335ad37, F=0x0, S=1, 1000, 0x2691f3bd
+0, 2500, 2500, 0, 902, 0x3360b315, F=0x0, S=1, 1008, 0xd5e1deb6
+0, 2533, 2533, 0, 881, 0xf5309d59, F=0x0, S=1, 1113, 0xdbef3065
+0, 2566, 2566, 0, 974, 0x7c2de3ce, F=0x0, S=1, 1086, 0x365626bb
+0, 2600, 2600, 0, 974, 0xf42bd9f5, F=0x0, S=1, 1039, 0xa7e9060d
+0, 2633, 2633, 0, 1029, 0x7c33f4d0, F=0x0, S=1, 1041, 0xf4affa59
+0, 2666, 2666, 0, 881, 0x9021a565, F=0x0, S=1, 1039, 0xc1e00521
+0, 2700, 2700, 0, 1157, 0xe1c136f7, F=0x0, S=1, 917, 0x357ac7d3
+0, 2733, 2733, 0, 649, 0xdffb3cb7, F=0x0, S=1, 976, 0xa386e05e
+0, 2766, 2766, 0, 758, 0xb67875f3, F=0x0, S=1, 1041, 0xae4e0a63
+0, 2800, 2800, 0, 1105, 0x8ffb1a26, F=0x0, S=1, 962, 0x211ddc5e
+0, 2833, 2833, 0, 866, 0xa60eb2d9, F=0x0, S=1, 929, 0xe9e4c84b
+0, 2866, 2866, 0, 912, 0xcd34bf9b, F=0x0, S=1, 946, 0xfce9d359
+0, 2900, 2900, 0, 868, 0x5651a343, F=0x0, S=1, 809, 0x624a8ef9
+0, 2933, 2933, 0, 997, 0xfa66eaeb, F=0x0, S=1, 992, 0xc913e5e2
+0, 2966, 2966, 0, 1111, 0x3f272497, F=0x0, S=1, 1007, 0xf78ee6a7
+0, 3000, 3000, 0, 842, 0xe442999f, F=0x0, S=1, 972, 0x25a0d25c
+0, 3033, 3033, 0, 1030, 0x6f97ffad, F=0x0, S=1, 993, 0x4059fd6b
+0, 3066, 3066, 0, 1176, 0x66e64926, F=0x0, S=1, 951, 0x2762cdf1
+0, 3100, 3100, 0, 803, 0xfd1699cb, F=0x0, S=1, 959, 0x5cf9d56c
+0, 3133, 3133, 0, 972, 0x1cdff00e, F=0x0, S=1, 1023, 0xeaf20900
+0, 3166, 3166, 0, 907, 0x17f8acca, F=0x0, S=1, 1054, 0xeb010c4d
+0, 3200, 3200, 0, 915, 0x3569b545, F=0x0, S=1, 987, 0x73b2e159
+0, 3233, 3233, 0, 1021, 0x14c5076a, F=0x0, S=1, 1007, 0x6c4bf7f0
+0, 3266, 3266, 0, 837, 0xbf86b0ef, F=0x0, S=1, 963, 0xf472d31a
+0, 3300, 3300, 0, 885, 0x1caac123, F=0x0, S=1, 1052, 0x2b7bfd20
+0, 3333, 3333, 0, 1355, 0x299e8d3c, F=0x0, S=1, 858, 0x2bbca3f0
+0, 3366, 3366, 0, 784, 0xb0bd7e9d, F=0x0, S=1, 969, 0xc865dc00
+0, 3400, 3400, 0, 991, 0xbc7ddda9, F=0x0, S=1, 1028, 0x801b00a6
+0, 3433, 3433, 0, 986, 0xb356f6b1, F=0x0, S=1, 1056, 0x8b840add
+0, 3466, 3466, 0, 978, 0x94a3e87e, F=0x0, S=1, 1018, 0xe766fa52
+0, 3500, 3500, 0, 976, 0x55ddd14a, F=0x0, S=1, 992, 0x58a9ddfe
+0, 3533, 3533, 0, 1241, 0x1ec867f7, F=0x0, S=1, 966, 0xa329e84f
+0, 3566, 3566, 0, 975, 0xecf5dbb3, F=0x0, S=1, 899, 0xa7539f4d
+0, 3600, 3600, 0, 1129, 0xb7243037, F=0x0, S=1, 1057, 0xbd0d10bd
+0, 3633, 3633, 0, 913, 0xe5f1d03d, F=0x0, S=1, 1092, 0xeb9621f8
+0, 3666, 3666, 0, 943, 0x87d0ed78, F=0x0, S=1, 1057, 0x079c1054
+0, 3700, 3700, 0, 917, 0x536cc3fd, F=0x0, S=1, 946, 0xd2b9d0e2
+0, 3733, 3733, 0, 892, 0x4dffb1e2, F=0x0, S=1, 930, 0x70c9cc40
+0, 3766, 3766, 0, 957, 0x1a98e71c, F=0x0, S=1, 719, 0x6fec614a
+0, 3800, 3800, 0, 893, 0xf405b2c3, F=0x0, S=1, 821, 0x63529cab
+0, 3833, 3833, 0, 978, 0xa0a8d5f6, F=0x0, S=1, 745, 0x3c616219
+0, 3866, 3866, 0, 887, 0xfa7cb65d, F=0x0, S=1, 768, 0xb8f07885
+0, 3900, 3900, 0, 867, 0xd808ade7, F=0x0, S=1, 783, 0xf82b6b9a
+0, 3933, 3933, 0, 1068, 0x6f8b135a, F=0x0, S=1, 807, 0x52028d50
+0, 3966, 3966, 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
new file mode 100644
index 0000000..e2afb9c
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-00
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..4d9b081
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-01
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..09e6299
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-02
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..0c22157
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-03
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..730a012
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-04
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..0f2dd7a
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-05
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..c6c1282
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-06
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..cdc6ec5
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-07
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..f405cef
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-08
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..bc5e86a
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-09
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..93e46a9
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-10
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..0924f54
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-11
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..9213e9d
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-12
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..80d1a6c
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-13
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..e7ab21d
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-14
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..842ab6e
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-15
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..7478558
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-16
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..3a5b1c1
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-17
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..baf3bc3
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-18
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..2ba95e1
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-19
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..8119688
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-20
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..0e94992
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-21
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..90533aa
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-22
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..d16d198
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-23
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..eccdfd6
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-24
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..70a76b3
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-25
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..d9308dc
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-26
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..d2efd69
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-27
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..85919fc
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-28
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..cc6eae7
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-29
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..4f26b58
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-30
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..4c9bf96
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-31
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..ef49c4e
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-32
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..374c44e
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-33
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..aa9c833
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-34
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..820725b
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-35
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..4a39a13
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-36
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..96e526f
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-37
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..9f61d33
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-38
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..396a1a3
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-39
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..dc77394
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-40
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..667549c
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-41
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..c7fbfbc
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-42
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..090ce6f
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-43
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..130b5fa
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-44
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..5cb7105
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-45
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..cb51f72
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-46
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..0bf90b4
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-47
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..2604a53
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-48
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..3403d1d
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-49
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..f2cdc8e
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-50
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..87ab57e
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-51
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..f3a14d1
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-52
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..784925d
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-53
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..daa6f5d
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-54
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..0a48cf9
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-55
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..f1f6069
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-56
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..499b57e
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-57
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..2a10350
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-58
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..8ae9bd3
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-59
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..a409462
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-60
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..92aa67f
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-61
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..d17d3d6
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-62
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..d7765be
--- a/dev/null
+++ b/tests/ref/fate/vp9-00-quantizer-63
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..02e6e16
--- a/dev/null
+++ b/tests/ref/fate/vp9-01-sharpness-1
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 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
new file mode 100644
index 0000000..51238c1
--- a/dev/null
+++ b/tests/ref/fate/vp9-01-sharpness-2
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 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
new file mode 100644
index 0000000..e1af6f6
--- a/dev/null
+++ b/tests/ref/fate/vp9-01-sharpness-3
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 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
new file mode 100644
index 0000000..977095f
--- a/dev/null
+++ b/tests/ref/fate/vp9-01-sharpness-4
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 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
new file mode 100644
index 0000000..c0cf715
--- a/dev/null
+++ b/tests/ref/fate/vp9-01-sharpness-5
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 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
new file mode 100644
index 0000000..2e52d32
--- a/dev/null
+++ b/tests/ref/fate/vp9-01-sharpness-6
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 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
new file mode 100644
index 0000000..b2b5fda
--- a/dev/null
+++ b/tests/ref/fate/vp9-01-sharpness-7
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 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
new file mode 100644
index 0000000..403a131
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-08x08
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..01d8818
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-08x10
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..d72aafc
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-08x16
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..8615d7b
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-08x18
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..55ab620
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-08x32
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..bdcedbf
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-08x34
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..3226dfa
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-08x64
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..7aaa369
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-08x66
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..5708cd3
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-10x08
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..a60e36b
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-10x10
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..659d491
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-10x16
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..d4069c9
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-10x18
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..f5ec31c
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-10x32
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..950b04e
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-10x34
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..04a5e7e
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-10x64
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..f26965a
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-10x66
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..84e9b17
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-16x08
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..8490e4e
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-16x10
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..fb6f0c8
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-16x16
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..fadce55
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-16x18
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..02a2676
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-16x32
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..97e527f
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-16x34
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..63dbf24
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-16x64
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..f7d0102
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-16x66
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..08aabcc
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-18x08
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..9323a14
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-18x10
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..a3a91b9
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-18x16
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..b90faf3
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-18x18
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..b7bd74b
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-18x32
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..0f46da7
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-18x34
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..172422c
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-18x64
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..c400956
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-18x66
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..2df5adc
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-32x08
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..f5f45fb
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-32x10
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..4aac211
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-32x16
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..2b30219
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-32x18
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..e9de2ed
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-32x32
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..e1e00fd
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-32x34
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..c39c88d
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-32x64
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..d036df1
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-32x66
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..5869186
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-34x08
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..a2ce10e
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-34x10
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..0c8dc67
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-34x16
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..8c92b2d
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-34x18
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..a9f804e
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-34x32
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..4bed149
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-34x34
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..ac61f27
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-34x64
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..2bc9eb6
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-34x66
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..e1e01ee
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-64x08
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..046e7ee
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-64x10
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..16cb5dd
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-64x16
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..427acca
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-64x18
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..a0f033e
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-64x32
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..a852272
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-64x34
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..418febe
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-64x64
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..d358bd6
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-64x66
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..426f91b
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-66x08
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..8e0133a
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-66x10
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..4bdc1ba
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-66x16
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..3b395dd
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-66x18
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..14b9cb0
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-66x32
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..79bc91c
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-66x34
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..a89e10f
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-66x64
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..73aa4e7
--- a/dev/null
+++ b/tests/ref/fate/vp9-02-size-66x66
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..293abad
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-deltaq
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..1c4156b
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-196x196
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..294c7de
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-196x198
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..d0882e5
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-196x200
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..20f46ea
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-196x202
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..b1ffd8f
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-196x208
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..7248874
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-196x210
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..fb49188
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-196x224
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..0ef318a
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-196x226
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..2d02a49
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-198x196
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..f458f53
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-198x198
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..176b9d9
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-198x200
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..371a874
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-198x202
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..95b2e06
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-198x208
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..1e2790a
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-198x210
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..7cccf9b
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-198x224
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..81136e6
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-198x226
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..670d115
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-200x196
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..fd37506
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-200x198
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..d5806a1
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-200x200
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..3f6ee8b
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-200x202
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..ea1cb0c
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-200x208
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..7c459d2
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-200x210
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..19a786c
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-200x224
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..dd7967d
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-200x226
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..1af7c58
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-202x196
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..d51ee96
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-202x198
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..f75e192
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-202x200
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..af7cb9a
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-202x202
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..cc85d27
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-202x208
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..d51fcc6
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-202x210
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..0a36bd3
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-202x224
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..6bc31f9
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-202x226
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..b06557f
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-208x196
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..84da7dd
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-208x198
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..0943abf
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-208x200
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..b181224
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-208x202
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..7bcbfdc
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-208x208
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..7dbccf6
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-208x210
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..70d64ea
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-208x224
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..7d9020c
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-208x226
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..a6813b4
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-210x196
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..c14d20c
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-210x198
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..873525b
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-210x200
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..91e229e
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-210x202
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..a77ac5f
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-210x208
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..fa9f158
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-210x210
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..1e1d225
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-210x224
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..5563363
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-210x226
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..1275e9e
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-224x196
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..39e0825
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-224x198
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..8fbc5b1
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-224x200
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..3e212ac
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-224x202
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..a925e1a
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-224x208
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..3c59459
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-224x210
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..610578b
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-224x224
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..874e595
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-224x226
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..43d55b9
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-226x196
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..fe2c477
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-226x198
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..b16c531
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-226x200
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..818038d
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-226x202
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..cda6f99
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-226x208
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..fa83e1d
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-226x210
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..50d81cb
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-226x224
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..88b3c43
--- a/dev/null
+++ b/tests/ref/fate/vp9-03-size-226x226
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 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
new file mode 100644
index 0000000..2f32092
--- a/dev/null
+++ b/tests/ref/fate/vp9-2pass-akiyo
@@ -0,0 +1,55 @@
+#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-segmentation-akiyo b/tests/ref/fate/vp9-segmentation-akiyo
new file mode 100644
index 0000000..b850754
--- a/dev/null
+++ b/tests/ref/fate/vp9-segmentation-akiyo
@@ -0,0 +1,55 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 20cf714300c5e28ffb77bf9c682129bc
+0, 1, 1, 1, 152064, 2f271e4de29f87d6b90511fbafdf9fbb
+0, 2, 2, 1, 152064, 2f271e4de29f87d6b90511fbafdf9fbb
+0, 3, 3, 1, 152064, a88532a043f5f2c6bce729a8e20ee5af
+0, 4, 4, 1, 152064, 8d7b5482ed8072a7c95d722783773436
+0, 5, 5, 1, 152064, 04872d8619b163b5e0c20123ccddf7dc
+0, 6, 6, 1, 152064, ed6d9677782aa6e87b6576541391557f
+0, 7, 7, 1, 152064, 689f71108e9bf024cd9ccf48800dcdc7
+0, 8, 8, 1, 152064, f7c555792884499bb62a8e739b201739
+0, 9, 9, 1, 152064, 7fed82c38ce428a178c56f6131eff5ec
+0, 10, 10, 1, 152064, fb638e587ade05baa027bb63edc7ec7c
+0, 11, 11, 1, 152064, 319295f5aa44661a80570e844050156a
+0, 12, 12, 1, 152064, de2d8635966a1cd57290eac449a5fb4b
+0, 13, 13, 1, 152064, 9ac3d711a00aac6b17004bb6451e4cab
+0, 14, 14, 1, 152064, d12eced084e72b5230493e2dc2de0f0a
+0, 15, 15, 1, 152064, 197761d11407fed723a63b8e28cb8e19
+0, 16, 16, 1, 152064, 28d8e807bc142b74f1eaf30dbbf1b7bd
+0, 17, 17, 1, 152064, abe88f1f7490d13ba3def9511beaceec
+0, 18, 18, 1, 152064, 7d297b9c989ebc0408fd41b14900242a
+0, 19, 19, 1, 152064, d5e7adfa2b207d860feff5c894585fd1
+0, 20, 20, 1, 152064, aea3e9de9de237f8379785f3467dc9c9
+0, 21, 21, 1, 152064, 211967cd949c1d83a8cc4c8267aa6034
+0, 22, 22, 1, 152064, 3f49bf8e0434114c15b867be2d53d283
+0, 23, 23, 1, 152064, 8d5e629c0e941ca6f049ed2bb59d09a8
+0, 24, 24, 1, 152064, d359620957877534bc94cd137dc652fe
+0, 25, 25, 1, 152064, 83610fc1969fdfa267e7e462a83ea40c
+0, 26, 26, 1, 152064, b2d20dcc3f77a238ce7210991eebe1a7
+0, 27, 27, 1, 152064, a42ad37808f30e1d968882bf42e9c641
+0, 28, 28, 1, 152064, 55084cded938266a2c3c658dcc162781
+0, 29, 29, 1, 152064, e392a3a7d33e10e95fc9cdf0a2080eac
+0, 30, 30, 1, 152064, 73977c4827463c17e63c0769bb90722f
+0, 31, 31, 1, 152064, cb5dd87344af7d6fd4ed0e06cb90d9c2
+0, 32, 32, 1, 152064, 533338860124e392cef2039468c22f75
+0, 33, 33, 1, 152064, da30f077490042367502a6fe11a46e0f
+0, 34, 34, 1, 152064, 860ab1bfbd3fe6a27bee5ef8c4e0b600
+0, 35, 35, 1, 152064, 339ec3863eaed689d46289ffe47bc45d
+0, 36, 36, 1, 152064, ffa6c990577093106796ed0dee56c483
+0, 37, 37, 1, 152064, 3fcdc2bc064c79f35ea81a715ff089d0
+0, 38, 38, 1, 152064, adaef9ec97e23a542db22bcd23c740bd
+0, 39, 39, 1, 152064, ddcff4bd2c9579181182eb49add0ce3c
+0, 40, 40, 1, 152064, b3b039c84cffb9272c8ddf9086748696
+0, 41, 41, 1, 152064, 70939a961ec1e4697031b79e7ebb7919
+0, 42, 42, 1, 152064, 6b3ff2e003749c6ffeb2d71edecf884c
+0, 43, 43, 1, 152064, 5e4efc96971f81218c472482b5a79374
+0, 44, 44, 1, 152064, 279132c87d81a5747824b06423bf6785
+0, 45, 45, 1, 152064, 1da48caa08007523aab41a56e21dd99b
+0, 46, 46, 1, 152064, 36ecffb2bfcb587d2556fddcbbd3448b
+0, 47, 47, 1, 152064, 7823e3c86cd5a05c2959c7ef4d1cfa89
+0, 48, 48, 1, 152064, b53f78afbad1a43f7aea58814eacd824
+0, 49, 49, 1, 152064, b9b127b4bc54123bec19b2f4a3fa157c
diff --git a/tests/ref/fate/vp9-tiling-pedestrian b/tests/ref/fate/vp9-tiling-pedestrian
new file mode 100644
index 0000000..2915323
--- a/dev/null
+++ b/tests/ref/fate/vp9-tiling-pedestrian
@@ -0,0 +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/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/wmv8-drm b/tests/ref/fate/wmv8-drm
index c2a6dd5..31291d3 100644
--- a/tests/ref/fate/wmv8-drm
+++ b/tests/ref/fate/wmv8-drm
@@ -1,131 +1,131 @@
-#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
-0, 6791, 6791, 0, 84480, 0x2676a064
+#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
+0, 163, 163, 1, 84480, 0x0998a064
diff --git a/tests/ref/fate/wmv8-drm-nodec b/tests/ref/fate/wmv8-drm-nodec
index d6bf15e..76c4e75 100644
--- a/tests/ref/fate/wmv8-drm-nodec
+++ b/tests/ref/fate/wmv8-drm-nodec
@@ -5,148 +5,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
--- a/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..362c55b 100644
--- a/tests/ref/fate/wtv-demux
+++ b/tests/ref/fate/wtv-demux
@@ -33,109 +33,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/xface b/tests/ref/fate/xface
new file mode 100644
index 0000000..7f1f1e6
--- a/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..49f22c9 100644
--- a/tests/ref/fate/xmv-demux
+++ b/tests/ref/fate/xmv-demux
@@ -7,32 +7,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 +40,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 +80,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/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..f104c98 100644
--- a/tests/ref/fate/zmbv-8bit
+++ b/tests/ref/fate/zmbv-8bit
@@ -1,4 +1,4 @@
-#tb 0: 1000000/70086303
+#tb 0: 15967/1119068
0, 0, 0, 1, 192000, 0x5234b617
0, 1, 1, 1, 192000, 0x5234b617
0, 2, 2, 1, 192000, 0x5234b617
@@ -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
--- a/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..6f201e0
--- a/dev/null
+++ b/tests/ref/lavf-fate/mp3
@@ -0,0 +1,3 @@
+6bdea919dc6856d76ef2553698e2b0d3 *./tests/data/lavf-fate/lavf.mp3
+96376 ./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..b77476d
--- a/dev/null
+++ b/tests/ref/lavf-fate/ogg_vp3
@@ -0,0 +1,3 @@
+adbe6c30bdfe934dc5ae397f4db2960d *./tests/data/lavf-fate/lavf.ogg
+417644 ./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 572cfc5..a90e547 100644
--- a/tests/ref/lavf/asf
+++ b/tests/ref/lavf/asf
@@ -1,3 +1,3 @@
-327385dd5f418faa6237089a40159b78 *./tests/data/lavf/lavf.asf
-333375 ./tests/data/lavf/lavf.asf
+6bc7dc5698c3607fad8937d14560e50c *./tests/data/lavf/lavf.asf
+333581 ./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
--- a/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..3cbb44f 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
+8d3a3554cbe21bc232603ca26b0c4d3e *./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
--- a/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..3c8e5b1 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=0x25bdd732
+e9949bc767924e1e7d28856029fee024 *./tests/data/lavf/lavf.dv
+3480000 ./tests/data/lavf/lavf.dv
+./tests/data/lavf/lavf.dv CRC=0xc4f27ca7
+87d3b20f656235671383a7eaa2f66330 *./tests/data/lavf/lavf.dv
3600000 ./tests/data/lavf/lavf.dv
./tests/data/lavf/lavf.dv CRC=0x0e868a82
diff --git a/tests/ref/lavf/ffm b/tests/ref/lavf/ffm
index 7518a81..7071866 100644
--- a/tests/ref/lavf/ffm
+++ b/tests/ref/lavf/ffm
@@ -1,3 +1,3 @@
-f3f0c42283b75bc826f499f048085c27 *./tests/data/lavf/lavf.ffm
+6f1443b952819cff1dae875529675e88 *./tests/data/lavf/lavf.ffm
376832 ./tests/data/lavf/lavf.ffm
-./tests/data/lavf/lavf.ffm CRC=0xdd24439e
+./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
--- a/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 1d38b6f..f014bec 100644
--- a/tests/ref/lavf/flv_fmt
+++ b/tests/ref/lavf/flv_fmt
@@ -1,3 +1,3 @@
-62c3177547fb5853a5116661802e1ae2 *./tests/data/lavf/lavf.flv
-329541 ./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..4d90abe 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
+8aef8081e8afa445f63f320f4a1c5edb *./tests/data/lavf/lavf.gif
+2030198 ./tests/data/lavf/lavf.gif
+./tests/data/lavf/lavf.gif CRC=0x0dc5477c
diff --git a/tests/ref/lavf/gxf b/tests/ref/lavf/gxf
index e25d4f2..14a2c87 100644
--- a/tests/ref/lavf/gxf
+++ b/tests/ref/lavf/gxf
@@ -1,3 +1,9 @@
-eaa16531d0b2f3e3ade2186cf33dbf86 *./tests/data/lavf/lavf.gxf
-796392 ./tests/data/lavf/lavf.gxf
-./tests/data/lavf/lavf.gxf CRC=0xd04c769f
+9c96119322262ed2c43b34fd415233cc *./tests/data/lavf/lavf.gxf
+795876 ./tests/data/lavf/lavf.gxf
+./tests/data/lavf/lavf.gxf CRC=0xda7cebbc
+260acc1c88a1706e5aaa74eff99ac389 *./tests/data/lavf/lavf.gxf
+794656 ./tests/data/lavf/lavf.gxf
+./tests/data/lavf/lavf.gxf CRC=0x7f0c9089
+3cb8bab80b73a95f51e50989ccf06817 *./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
--- a/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..dd4b162
--- a/dev/null
+++ b/tests/ref/lavf/ismv
@@ -0,0 +1,9 @@
+ec3e7d37755378cbe9907175768afbac *./tests/data/lavf/lavf.ismv
+312453 ./tests/data/lavf/lavf.ismv
+./tests/data/lavf/lavf.ismv CRC=0x9d9a638a
+a4b6fb1f46848622477230f69040942c *./tests/data/lavf/lavf.ismv
+321359 ./tests/data/lavf/lavf.ismv
+./tests/data/lavf/lavf.ismv CRC=0xe8130120
+ec3e7d37755378cbe9907175768afbac *./tests/data/lavf/lavf.ismv
+312453 ./tests/data/lavf/lavf.ismv
+./tests/data/lavf/lavf.ismv CRC=0x9d9a638a
diff --git a/tests/ref/lavf/jpg b/tests/ref/lavf/jpg
index 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 2bf1543..51fd2e7 100644
--- a/tests/ref/lavf/mkv
+++ b/tests/ref/lavf/mkv
@@ -1,3 +1,6 @@
-7c21e1e6b4fe71f361564f8eebedf4e1 *./tests/data/lavf/lavf.mkv
-320268 ./tests/data/lavf/lavf.mkv
-./tests/data/lavf/lavf.mkv CRC=0x7d5d3cda
+5e3e58192b11644477474a25bef2e022 *./tests/data/lavf/lavf.mkv
+472559 ./tests/data/lavf/lavf.mkv
+./tests/data/lavf/lavf.mkv CRC=0xec6c3c68
+6aac0de39634046f23a3447b08380efe *./tests/data/lavf/lavf.mkv
+320288 ./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..6c73753 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
+65ba2cff95100a4914b2ff507eb42818 *./tests/data/lavf/lavf.mov
+366421 ./tests/data/lavf/lavf.mov
+./tests/data/lavf/lavf.mov CRC=0xbb2b949b
+b9b988b23b5e5aff8760d0475908f837 *./tests/data/lavf/lavf.mov
+357511 ./tests/data/lavf/lavf.mov
+./tests/data/lavf/lavf.mov CRC=0xbb2b949b
+5c5c79e09490763a2692c91c5985b7ea *./tests/data/lavf/lavf.mov
+366593 ./tests/data/lavf/lavf.mov
+./tests/data/lavf/lavf.mov CRC=0xa9793231
+c1d4ff07ccad169cb6fca003661f0c12 *./tests/data/lavf/lavf.mov
+356893 ./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..9feff66 100644
--- a/tests/ref/lavf/mpg
+++ b/tests/ref/lavf/mpg
@@ -1,3 +1,9 @@
-7df31ba8a5909e3c88b1d1a3f93c4ec2 *./tests/data/lavf/lavf.mpg
+0a8c879bf813b6b758806088f29842dc *./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
+d9446ae7b49de006a5a0f052ea9333ca *./tests/data/lavf/lavf.mpg
+389120 ./tests/data/lavf/lavf.mpg
+./tests/data/lavf/lavf.mpg CRC=0x60ba4ab9
+edfef790122870cf4652e8a92ca558a0 *./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 c69e278..b1918f5 100644
--- a/tests/ref/lavf/mxf
+++ b/tests/ref/lavf/mxf
@@ -1,3 +1,9 @@
-21d359aecf0453a5910d2c1a9ec906b2 *./tests/data/lavf/lavf.mxf
-525881 ./tests/data/lavf/lavf.mxf
-./tests/data/lavf/lavf.mxf CRC=0x773f059a
+967f6ee9223c865328f4891465191108 *./tests/data/lavf/lavf.mxf
+525369 ./tests/data/lavf/lavf.mxf
+./tests/data/lavf/lavf.mxf CRC=0xdbfff6f1
+a085845074129d732fc6adb5601e3b5e *./tests/data/lavf/lavf.mxf
+560697 ./tests/data/lavf/lavf.mxf
+./tests/data/lavf/lavf.mxf CRC=0x3ff4178e
+ce535b606423d117675213b16275206a *./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 98569c4..8e08bdd 100644
--- a/tests/ref/lavf/mxf_d10
+++ b/tests/ref/lavf/mxf_d10
@@ -1,3 +1,3 @@
-b66087558cd1ff8e64290ffd856c88bc *./tests/data/lavf/lavf.mxf_d10
+28cf73e6d35a8f7aba30c0ed2bd84924 *./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..6c42a40 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
+66386a488ee35e4592b605f63ef90a73 *./tests/data/lavf/lavf.nut
+319902 ./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..f8b58c4 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
+304a201b4afa3583b206bdeef177ce6b *./tests/data/lavf/lavf.ogg
+13495 ./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..50048ed 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
+ebd43e97839b2538a79f35757e84ffb0 *./tests/data/images/pam/02.pam
+./tests/data/images/pam/%02d.pam CRC=0x831a2963
+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..40e7cca 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
+62b26c9582ba37dd37b76191338f3770 *./tests/data/images/png/02.png
+./tests/data/images/png/%02d.png CRC=0x831a2963
+41687 ./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
--- a/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 0fe358b..02921ed 100644
--- a/tests/ref/lavf/ts
+++ b/tests/ref/lavf/ts
@@ -1,3 +1,3 @@
-647875edb0d1afb9fd0477cbfde3fe8b *./tests/data/lavf/lavf.ts
-406456 ./tests/data/lavf/lavf.ts
-./tests/data/lavf/lavf.ts CRC=0xb4ca6cdc
+a876e6bde8a2e8c7eca878869433ad3b *./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..7da4f09
--- a/dev/null
+++ b/tests/ref/lavf/w64
@@ -0,0 +1,3 @@
+062b91c34d570a90af8d55427804878e *./tests/data/lavf/lavf.w64
+88312 ./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..600c26a 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
+eb5a869456d2e9107bb195c8c99be1a1 *./tests/data/lavf/lavf.wav
+88276 ./tests/data/lavf/lavf.wav
./tests/data/lavf/lavf.wav CRC=0x3a1da17e
diff --git a/tests/ref/lavf/wtv b/tests/ref/lavf/wtv
new file mode 100644
index 0000000..fe1b83c
--- a/dev/null
+++ b/tests/ref/lavf/wtv
@@ -0,0 +1,3 @@
+98dd5205889313542da71351fbaf4172 *./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
--- a/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-flac b/tests/ref/seek/acodec-flac
index 15ab0d2..ab31891 100644
--- a/tests/ref/seek/acodec-flac
+++ b/tests/ref/seek/acodec-flac
@@ -1,49 +1,49 @@
-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: 0 st: 0 flags:1 dts: 0.809796 pts: 0.809796 pos: 27366 size: 615
ret:-1 st: 0 flags:1 ts:-0.317506
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: 0 st: 0 flags:1 dts: 0.365714 pts: 0.365714 pos: 16890 size: 614
ret:-1 st: 0 flags:1 ts:-0.740839
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: 0 st: 0 flags:1 dts: 0.888163 pts: 0.888163 pos: 29211 size: 620
ret:-1 st:-1 flags:1 ts:-0.222493
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: 0 st: 0 flags:1 dts: 0.470204 pts: 0.470204 pos: 19353 size: 608
ret:-1 st:-1 flags:1 ts:-0.645825
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/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 89ec4c2..9a14895 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: 575 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 689 size: 208
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147775 size: 209
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 689 size: 208
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301375 size: 209
+ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147889 size: 209
ret: 0 st: 0 flags:0 ts: 0.788000
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301375 size: 209
+ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147889 size: 209
ret: 0 st: 0 flags:1 ts:-0.317000
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 575 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 689 size: 208
ret: 0 st: 1 flags:0 ts: 2.577000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330175 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330289 size: 209
ret: 0 st: 1 flags:1 ts: 1.471000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330175 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330289 size: 209
ret: 0 st:-1 flags:0 ts: 0.365002
-ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147775 size: 209
+ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147889 size: 209
ret: 0 st:-1 flags:1 ts:-0.740831
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 575 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 689 size: 208
ret: 0 st: 0 flags:0 ts: 2.153000
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301375 size: 209
+ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301489 size: 209
ret: 0 st: 0 flags:1 ts: 1.048000
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301375 size: 209
+ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301489 size: 209
ret: 0 st: 1 flags:0 ts:-0.058000
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 575 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 689 size: 208
ret: 0 st: 1 flags:1 ts: 2.836000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330175 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330289 size: 209
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301375 size: 209
+ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301489 size: 209
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147775 size: 209
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 689 size: 208
ret: 0 st: 0 flags:0 ts:-0.482000
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 575 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 689 size: 208
ret: 0 st: 0 flags:1 ts: 2.413000
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301375 size: 209
+ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301489 size: 209
ret: 0 st: 1 flags:0 ts: 1.307000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330175 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330289 size: 209
ret: 0 st: 1 flags:1 ts: 0.201000
-ret: 0 st: 1 flags:1 dts: 0.183000 pts: 0.183000 pos: 70975 size: 209
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 689 size: 208
ret: 0 st:-1 flags:0 ts:-0.904994
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 575 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 689 size: 208
ret: 0 st:-1 flags:1 ts: 1.989173
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301375 size: 209
+ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301489 size: 209
ret: 0 st: 0 flags:0 ts: 0.883000
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301375 size: 209
+ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147889 size: 209
ret: 0 st: 0 flags:1 ts:-0.222000
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 575 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 689 size: 208
ret: 0 st: 1 flags:0 ts: 2.672000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330175 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330289 size: 209
ret: 0 st: 1 flags:1 ts: 1.566000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330175 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330289 size: 209
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147775 size: 209
+ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147889 size: 209
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 575 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 689 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
index 2597220..eceed1a 100644
--- a/tests/ref/seek/lavf-ffm
+++ b/tests/ref/seek/lavf-ffm
@@ -1,26 +1,26 @@
-ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24664
+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: 24664
+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.772766 pts: 0.772766 pos: 315392 size: 209
+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: 24664
+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.328685 pts: 0.328685 pos: 155648 size: 209
+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: 24664
+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: 24664
+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
@@ -28,7 +28,7 @@ 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: 24664
+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
@@ -36,18 +36,18 @@ 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: 24664
+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: 1 flags:1 dts: 0.877256 pts: 0.877256 pos: 339968 size: 209
+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: 24664
+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.459297 pts: 0.459297 pos: 204800 size: 209
+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: 24664
+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 2e7a0bc..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: 199 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: 199 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: 298403 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: 298403 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: 298403 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: 149441 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: 298403 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: 199 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: 298403 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: 149441 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: 199 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: 298403 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: 199 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: 199 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: 298403 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: 298403 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: 298403 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: 149441 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 bc7ff3b..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: 741640 size: 54736
+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: 653328 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: 741640 size: 54736
+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: 741640 size: 54736
+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: 302676 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: 741640 size: 54736
+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: 741640 size: 54736
+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: 741640 size: 54736
+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: 741640 size: 54736
+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: 497156 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: 741640 size: 54736
+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: 741640 size: 54736
+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: 209504 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: 741640 size: 54736
+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: 696044 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: 741640 size: 54736
+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: 741640 size: 54736
+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: 370660 size: 54628
+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 f575165..bf6cab0 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.000000 pts: 0.000000 pos: 518 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 537 size: 208
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 734 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 753 size: 27837
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292156 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292167 size: 27834
ret: 0 st: 0 flags:0 ts: 0.788000
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292156 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292167 size: 27834
ret: 0 st: 0 flags:1 ts:-0.317000
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 734 size: 27837
-ret: 0 st: 1 flags:0 ts: 2.577000
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 753 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.993000 pts: 0.993000 pos: 319997 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320008 size: 209
ret: 0 st:-1 flags:0 ts: 0.365002
-ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146709 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146720 size: 27925
ret: 0 st:-1 flags:1 ts:-0.740831
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 734 size: 27837
-ret: 0 st: 0 flags:0 ts: 2.153000
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 753 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: 292156 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292167 size: 27834
ret: 0 st: 1 flags:0 ts:-0.058000
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 518 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 537 size: 208
ret: 0 st: 1 flags:1 ts: 2.836000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 319997 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: 320008 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: 146709 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146720 size: 27925
ret: 0 st: 0 flags:0 ts:-0.482000
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 734 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 753 size: 27837
ret: 0 st: 0 flags:1 ts: 2.413000
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292156 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: 292167 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.000000 pts: 0.000000 pos: 518 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 537 size: 208
ret: 0 st:-1 flags:0 ts:-0.904994
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 734 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 753 size: 27837
ret: 0 st:-1 flags:1 ts: 1.989173
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292156 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292167 size: 27834
ret: 0 st: 0 flags:0 ts: 0.883000
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292156 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292167 size: 27834
ret: 0 st: 0 flags:1 ts:-0.222000
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 734 size: 27837
-ret: 0 st: 1 flags:0 ts: 2.672000
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 753 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.993000 pts: 0.993000 pos: 319997 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320008 size: 209
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146709 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146720 size: 27925
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 734 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 753 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..93a9a23 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: 1739 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: 1739 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: 326943 size: 1024
+ret: 0 st: 0 flags:0 ts: 0.788359
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 327967 size: 27834
+ret: 0 st: 0 flags:1 ts:-0.317500
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1739 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: 327967 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: 165221 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: 1739 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: 326943 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: 1739 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: 327967 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: 164197 size: 1024
+ret: 0 st: 0 flags:0 ts:-0.481641
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1739 size: 27837
+ret: 0 st: 0 flags:1 ts: 2.412500
+ret: 0 st: 1 flags:1 dts: 0.952018 pts: 0.952018 pos: 326943 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: 1739 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: 1739 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: 326943 size: 1024
+ret: 0 st: 0 flags:0 ts: 0.883359
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 327967 size: 27834
+ret: 0 st: 0 flags:1 ts:-0.222500
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1739 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: 327967 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: 165221 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: 1739 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 5f2cf5d..9b23466 100644
--- a/tests/ref/seek/lavf-mxf
+++ b/tests/ref/seek/lavf-mxf
@@ -2,47 +2,47 @@ 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: 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: 24712
+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: 24712
+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: 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: 24712
+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: 24787
+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: 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: 24712
+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: 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: 24712
+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: 24787
+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: 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: 24712
+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.840000 pts: 0.960000 pos: 460800 size: 24712
+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: 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: 24712
+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: 24712
+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: 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: 24712
+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: 24712
+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: 24801
diff --git a/tests/ref/seek/lavf-mxf_d10 b/tests/ref/seek/lavf-mxf_d10
index e091c77..17cca29 100644
--- a/tests/ref/seek/lavf-mxf_d10
+++ b/tests/ref/seek/lavf-mxf_d10
@@ -34,7 +34,7 @@ ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000
ret: 0 st: 1 flags:0 ts: 1.306667
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000
ret: 0 st: 1 flags:1 ts: 0.200833
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos:1071104 size:150000
ret: 0 st:-1 flags:0 ts:-0.904994
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000
ret: 0 st:-1 flags:1 ts: 1.989173
diff --git a/tests/ref/seek/lavf-nut b/tests/ref/seek/lavf-nut
index fc3ef63..ef47ceb 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: 339 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: 567 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: 146434 size: 27925
+ret: 0 st: 0 flags:0 ts: 0.788340
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146434 size: 27925
+ret: 0 st: 0 flags:1 ts:-0.317500
+ret: 0 st: 0 flags:1 dts: 0.010918 pts: 0.010918 pos: 567 size: 27837
+ret: 0 st: 1 flags:0 ts: 2.576667
+ret: 0 st: 1 flags:1 dts: 0.862041 pts: 0.862041 pos: 271259 size: 209
+ret: 0 st: 1 flags:1 ts: 1.470839
+ret: 0 st: 1 flags:1 dts: 0.862041 pts: 0.862041 pos: 271259 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: 146434 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: 567 size: 27837
+ret: 0 st: 0 flags:0 ts: 2.153340
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146434 size: 27925
+ret: 0 st: 0 flags:1 ts: 1.047500
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146434 size: 27925
+ret: 0 st: 1 flags:0 ts:-0.058322
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 339 size: 208
+ret: 0 st: 1 flags:1 ts: 2.835828
+ret: 0 st: 1 flags:1 dts: 0.862041 pts: 0.862041 pos: 271259 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: 146434 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: 146434 size: 27925
+ret: 0 st: 0 flags:0 ts:-0.481660
+ret: 0 st: 0 flags:1 dts: 0.010918 pts: 0.010918 pos: 567 size: 27837
+ret: 0 st: 0 flags:1 ts: 2.412500
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146434 size: 27925
+ret: 0 st: 1 flags:0 ts: 1.306667
+ret: 0 st: 1 flags:1 dts: 0.862041 pts: 0.862041 pos: 271259 size: 209
+ret: 0 st: 1 flags:1 ts: 0.200839
+ret: 0 st: 1 flags:1 dts: 0.182857 pts: 0.182857 pos: 71901 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: 567 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: 146434 size: 27925
+ret: 0 st: 0 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146434 size: 27925
+ret: 0 st: 0 flags:1 ts:-0.222500
+ret: 0 st: 0 flags:1 dts: 0.010918 pts: 0.010918 pos: 567 size: 27837
+ret: 0 st: 1 flags:0 ts: 2.671678
+ret: 0 st: 1 flags:1 dts: 0.862041 pts: 0.862041 pos: 271259 size: 209
+ret: 0 st: 1 flags:1 ts: 1.565850
+ret: 0 st: 1 flags:1 dts: 0.862041 pts: 0.862041 pos: 271259 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: 146434 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: 567 size: 27837
diff --git a/tests/ref/seek/lavf-ogg b/tests/ref/seek/lavf-ogg
index 109ae32..583526e 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: 143 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: 143 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: 143 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: 143 size: 1364
+ret: 0 st: 0 flags:1 ts:-0.317506
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 143 size: 1364
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 143 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: 143 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: 143 size: 1364
+ret: 0 st: 0 flags:1 ts:-0.740839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 143 size: 1364
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 143 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: 143 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: 143 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: 143 size: 1364
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 143 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: 143 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: 143 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: 143 size: 1364
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 143 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: 143 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: 143 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: 143 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: 143 size: 1364
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 143 size: 1364
+ret: 0 st: 0 flags:0 ts: 2.671678
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 143 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: 143 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: 143 size: 1364
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 143 size: 1364
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-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-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 df7c4af..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: 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: 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: 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: 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: 24801
+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: 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: 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..16a33be 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: 76 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: 76 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: 69608 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: 76 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: 32270 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: 76 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: 76 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: 55128 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: 76 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: 17790 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: 76 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: 77986 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: 76 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: 40648 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: 76 size: 4096
diff --git a/tests/ref/seek/lavf-wtv b/tests/ref/seek/lavf-wtv
new file mode 100644
index 0000000..71703c5
--- a/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: 26344 size: 208
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26344 size: 208
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294744 size: 209
+ret: 0 st: 0 flags:0 ts: 0.788334
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294744 size: 209
+ret: 0 st: 0 flags:1 ts:-0.317499
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26344 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: 294744 size: 209
+ret: 0 st:-1 flags:0 ts: 0.365002
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26344 size: 208
+ret: 0 st:-1 flags:1 ts:-0.740831
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26344 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: 26344 size: 208
+ret: 0 st: 1 flags:0 ts:-0.058330
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26344 size: 208
+ret: 0 st: 1 flags:1 ts: 2.835837
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294744 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: 26344 size: 208
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26344 size: 208
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294744 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: 99352 size: 209
+ret: 0 st:-1 flags:0 ts:-0.904994
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26344 size: 208
+ret: 0 st:-1 flags:1 ts: 1.989173
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294744 size: 209
+ret: 0 st: 0 flags:0 ts: 0.883340
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294744 size: 209
+ret: 0 st: 0 flags:1 ts:-0.222493
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26344 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: 294744 size: 209
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26344 size: 208
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26344 size: 208
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-flv b/tests/ref/seek/vsynth2-flv
index 6952a4e..d4aecda 100644
--- a/tests/ref/seek/vsynth2-flv
+++ b/tests/ref/seek/vsynth2-flv
@@ -18,15 +18,15 @@ ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 52585 size: 11127
ret: 0 st: 0 flags:0 ts:-0.058000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size: 10380
ret: 0 st: 0 flags:1 ts: 2.836000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 117158 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: 117158 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: 25960 size: 10089
ret: 0 st: 0 flags:0 ts:-0.482000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size: 10380
ret: 0 st: 0 flags:1 ts: 2.413000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 117158 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: 83240 size: 12295
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: 199 size: 10380
ret: 0 st: 0 flags:0 ts:-0.905000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size: 10380
ret: 0 st: 0 flags:1 ts: 1.989000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 117158 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: 52585 size: 11127
ret:-1 st:-1 flags:1 ts:-0.222493
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-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 d06b7cb..06d8f7a 100644
--- a/tests/ref/seek/vsynth2-mpeg2-422
+++ b/tests/ref/seek/vsynth2-mpeg2-422
@@ -2,45 +2,45 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17497
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17497
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 325162 size: 19936
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 200736 size: 22575
-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: 265477 size: 21329
-ret: 0 st: 0 flags:0 ts: 0.360000
+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.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.880000 pts: NOPTS pos: 200736 size: 22575
-ret: 0 st: 0 flags:0 ts:-0.040000
+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.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 325162 size: 19936
+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: 325162 size: 19936
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 325397 size: 19967
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 104454 size: 28984
-ret: 0 st: 0 flags:0 ts:-0.480000
+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.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 325162 size: 19936
+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: 265477 size: 21329
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 265466 size: 21329
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17497
-ret: 0 st: 0 flags:0 ts:-0.920000
+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: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 325162 size: 19936
+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: 200736 size: 22575
+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: 265477 size: 21329
+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: 200736 size: 22575
+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 698cedf..b096f6f 100644
--- a/tests/ref/seek/vsynth2-mpeg2-idct-int
+++ b/tests/ref/seek/vsynth2-mpeg2-idct-int
@@ -3,43 +3,43 @@ ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9911
ret: 0 st:-1 flags:1 ts: 1.894167
ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 127925 size: 11918
-ret: 0 st: 0 flags:0 ts: 0.800000
+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.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.440000 pts: NOPTS pos: 127925 size: 11918
-ret: 0 st: 0 flags:0 ts: 0.360000
+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.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: 79103 size: 10909
-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: 9911
-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: 1.920000 pts: NOPTS pos: 182138 size: 12183
ret: 0 st:-1 flags:0 ts: 1.730004
ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 182138 size: 12183
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 38992 size: 9985
-ret: 0 st: 0 flags:0 ts:-0.480000
+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.400000
+ret: 0 st: 0 flags:1 ts: 2.412505
ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 182138 size: 12183
ret: 0 st:-1 flags:0 ts: 1.306672
ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 127925 size: 11918
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9911
-ret: 0 st: 0 flags:0 ts:-0.920000
+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: 2.000000
+ret: 0 st: 0 flags:1 ts: 1.989173
ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 182138 size: 12183
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 79103 size: 10909
ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.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.440000 pts: NOPTS pos: 127925 size: 11918
ret: 0 st:-1 flags:0 ts: 0.460008
ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 38992 size: 9985
diff --git a/tests/ref/seek/vsynth2-mpeg2-ilace b/tests/ref/seek/vsynth2-mpeg2-ilace
index a2427f3..d2a7838 100644
--- a/tests/ref/seek/vsynth2-mpeg2-ilace
+++ b/tests/ref/seek/vsynth2-mpeg2-ilace
@@ -2,45 +2,45 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 132607 size: 11970
-ret: 0 st: 0 flags:0 ts: 0.800000
+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.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.440000 pts: NOPTS pos: 132607 size: 11970
-ret: 0 st: 0 flags:0 ts: 0.360000
+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.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: 82152 size: 10965
-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: 9961
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 188429 size: 12232
+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: 188429 size: 12232
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 188425 size: 12232
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 40546 size: 10045
-ret: 0 st: 0 flags:0 ts:-0.480000
+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.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 188429 size: 12232
+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: 132607 size: 11970
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 132603 size: 11970
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
-ret: 0 st: 0 flags:0 ts:-0.920000
+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: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 188429 size: 12232
+ret: 0 st: 0 flags:1 ts: 1.989173
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 188425 size: 12232
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 82152 size: 10965
ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 132607 size: 11970
+ret:-1 st: 0 flags:0 ts: 2.671674
+ret: 0 st: 0 flags:1 ts: 1.565841
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 132603 size: 11970
ret: 0 st:-1 flags:0 ts: 0.460008
ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 40546 size: 10045
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg2-ivlc-qprd b/tests/ref/seek/vsynth2-mpeg2-ivlc-qprd
index 9a623c2..330dc16 100644
--- a/tests/ref/seek/vsynth2-mpeg2-ivlc-qprd
+++ b/tests/ref/seek/vsynth2-mpeg2-ivlc-qprd
@@ -3,43 +3,43 @@ ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 16239
ret: 0 st:-1 flags:1 ts: 1.894167
ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 227500 size: 12725
-ret: 0 st: 0 flags:0 ts: 0.800000
+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.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.360000 pts: NOPTS pos: 196681 size: 13159
-ret: 0 st: 0 flags:0 ts: 0.360000
+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.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.880000 pts: NOPTS pos: 164167 size: 13921
-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: 16239
-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: 1.840000 pts: NOPTS pos: 227500 size: 12725
ret: 0 st:-1 flags:0 ts: 1.730004
ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 227500 size: 12725
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 98748 size: 29165
-ret: 0 st: 0 flags:0 ts:-0.480000
+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.400000
+ret: 0 st: 0 flags:1 ts: 2.412505
ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 227500 size: 12725
ret: 0 st:-1 flags:0 ts: 1.306672
ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 196681 size: 13159
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 16239
-ret: 0 st: 0 flags:0 ts:-0.920000
+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: 2.000000
+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: 164167 size: 13921
+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:-1 st: 0 flags:0 ts: 2.671674
+ret: 0 st: 0 flags:1 ts: 1.565841
ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 196681 size: 13159
ret: 0 st:-1 flags:0 ts: 0.460008
ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 164167 size: 13921
diff --git a/tests/ref/seek/vsynth2-mpeg2-thread b/tests/ref/seek/vsynth2-mpeg2-thread
index d8c9e28..8e16f43 100644
--- a/tests/ref/seek/vsynth2-mpeg2-thread
+++ b/tests/ref/seek/vsynth2-mpeg2-thread
@@ -2,45 +2,45 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 158225 size: 12232
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 67790 size: 10965
-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: 110330 size: 11970
-ret: 0 st: 0 flags:0 ts: 0.360000
+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.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.880000 pts: NOPTS pos: 67790 size: 10965
-ret: 0 st: 0 flags:0 ts:-0.040000
+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.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 158225 size: 12232
+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: 158225 size: 12232
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 158232 size: 12232
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 30747 size: 10045
-ret: 0 st: 0 flags:0 ts:-0.480000
+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.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 158225 size: 12232
+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: 110330 size: 11970
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 110336 size: 11970
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
-ret: 0 st: 0 flags:0 ts:-0.920000
+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: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 158225 size: 12232
+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: 67790 size: 10965
+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: 110330 size: 11970
+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: 67790 size: 10965
+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 f1909b6..49ec819 100644
--- a/tests/ref/seek/vsynth2-mpeg2-thread-ivlc
+++ b/tests/ref/seek/vsynth2-mpeg2-thread-ivlc
@@ -2,45 +2,45 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9954
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9954
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 157678 size: 11930
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 67723 size: 10791
-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: 110080 size: 11697
-ret: 0 st: 0 flags:0 ts: 0.360000
+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.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.880000 pts: NOPTS pos: 67723 size: 10791
-ret: 0 st: 0 flags:0 ts:-0.040000
+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.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 157678 size: 11930
+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: 157678 size: 11930
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 157685 size: 11930
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 30744 size: 9980
-ret: 0 st: 0 flags:0 ts:-0.480000
+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.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 157678 size: 11930
+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: 110080 size: 11697
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 110086 size: 11697
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9954
-ret: 0 st: 0 flags:0 ts:-0.920000
+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: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 157678 size: 11930
+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: 67723 size: 10791
+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: 110080 size: 11697
+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: 67723 size: 10791
+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-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-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
--- a/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
--- a/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..f7c7f57
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-amv
@@ -0,0 +1,4 @@
+34c4d4033d31c7401d32fee9d6ce0de2 *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-avui b/tests/ref/vsynth/vsynth1-avui
new file mode 100644
index 0000000..a4937ac
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-avui
@@ -0,0 +1,4 @@
+55af74b378fb938d5ea6e0a37c149f16 *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..5207d92 100644
--- a/tests/ref/vsynth/vsynth1-cljr
+++ b/tests/ref/vsynth/vsynth1-cljr
@@ -1,4 +1,4 @@
-41fc45d5e8bca3cf2be35457b188cdb3 *tests/data/fate/vsynth1-cljr.avi
+eb9131f74c29cda83ba706293c85afb4 *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..62aa0b9 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
+8d0f7b3424ada79f87053022bf888797 *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..59423e7 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
+790777baa4bb70c4e32cb13649cc26bf *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
--- a/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..d051e8d 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
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..bc4b802 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
diff --git a/tests/ref/vsynth/vsynth1-dv-50 b/tests/ref/vsynth/vsynth1-dv-50
index 18ee398..e747075 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
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
--- a/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..22c9341 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
+394aa2d2ee50abbc2372e6d126c7eb5a *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..2a4f41c
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-ffv1.0
@@ -0,0 +1,4 @@
+91c237f18bc19975077c85175daed734 *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..d752c4b 100644
--- a/tests/ref/vsynth/vsynth1-ffvhuff
+++ b/tests/ref/vsynth/vsynth1-ffvhuff
@@ -1,4 +1,4 @@
-2279cfd5efce9dc3435b814f1f95dcbc *tests/data/fate/vsynth1-ffvhuff.avi
+96789e7ed68de5314e65bc496c75e0a5 *tests/data/fate/vsynth1-ffvhuff.avi
5987196 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-flashsv b/tests/ref/vsynth/vsynth1-flashsv
index b934d8d..8b27830 100644
--- a/tests/ref/vsynth/vsynth1-flashsv
+++ b/tests/ref/vsynth/vsynth1-flashsv
@@ -1,4 +1,4 @@
97894502b4cb57aca1105b6333f72dae *tests/data/fate/vsynth1-flashsv.flv
14681925 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
+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
--- a/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 4b57bdf..3a21e6a 100644
--- a/tests/ref/vsynth/vsynth1-flv
+++ b/tests/ref/vsynth/vsynth1-flv
@@ -1,4 +1,4 @@
-d6a80659cedee7698aefe9c4a8285fa4 *tests/data/fate/vsynth1-flv.flv
-636269 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..02b956b 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
+2e613918f64c3473b887306fc5eb3c3d *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-h263 b/tests/ref/vsynth/vsynth1-h263
index d5916fa..f985d61 100644
--- a/tests/ref/vsynth/vsynth1-h263
+++ b/tests/ref/vsynth/vsynth1-h263
@@ -1,4 +1,4 @@
-130ae384b6f12fd7d18979aa5371523a *tests/data/fate/vsynth1-h263.avi
+36abb66d2480121f66a23e07d2b903be *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..f60e252 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
+ec2262cb7c674fd85afb14d9eb27d9d6 *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..72ef0ff 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
+03ebe03b70ee93524ec30c5abb69205a *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..ed08365 100644
--- a/tests/ref/vsynth/vsynth1-huffyuv
+++ b/tests/ref/vsynth/vsynth1-huffyuv
@@ -1,4 +1,4 @@
-cd93849c8e9846490d8f950f1b2319d5 *tests/data/fate/vsynth1-huffyuv.avi
+829bf3e22e5d1df2aa9a709c9d5aff57 *tests/data/fate/vsynth1-huffyuv.avi
7933788 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-jpeg2000 b/tests/ref/vsynth/vsynth1-jpeg2000
new file mode 100644
index 0000000..cf53feb
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-jpeg2000
@@ -0,0 +1,4 @@
+e6e3d338eeb394d6fadc7bbb55fa9e6e *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..f8399f2
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-jpeg2000-97
@@ -0,0 +1,4 @@
+c135eb14e9f219242180270c2a242634 *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..fc21074 100644
--- a/tests/ref/vsynth/vsynth1-jpegls
+++ b/tests/ref/vsynth/vsynth1-jpegls
@@ -1,4 +1,4 @@
f8acf917e24ea6c9200f2cdf99744ca9 *tests/data/fate/vsynth1-jpegls.avi
9089800 tests/data/fate/vsynth1-jpegls.avi
-947cb24ec45a453348ae6fe3fa278071 *tests/data/fate/vsynth1-jpegls.out.rawvideo
-stddev: 2.85 PSNR: 39.03 MAXDIFF: 49 bytes: 7603200/ 7603200
+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 e229db5..7464a38 100644
--- a/tests/ref/vsynth/vsynth1-ljpeg
+++ b/tests/ref/vsynth/vsynth1-ljpeg
@@ -1,4 +1,4 @@
-2b1a2d5ad7f357df955d8548320d13f7 *tests/data/fate/vsynth1-ljpeg.avi
-6312924 tests/data/fate/vsynth1-ljpeg.avi
+ef0a38e7c24a4d7367a461ad8acac2c1 *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..80f15ca 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
+3d3a9cef95621e1c153649721c5a8590 *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..e631a2b
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-mjpeg-422
@@ -0,0 +1,4 @@
+cd452cb6a2967b2f3bd2d31de6c95bf1 *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..ba24914
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-mjpeg-444
@@ -0,0 +1,4 @@
+94ca37e075ee24047b5dcd8f27b51a9f *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..b350cda 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
+490e08209e30f162cf3f2a6f2e49c7ce *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..5c9e3c1 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
+fc095c7816920052fd0b91329c60cf29 *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 1ee3674..8dbc88b 100644
--- a/tests/ref/vsynth/vsynth1-mpeg2
+++ b/tests/ref/vsynth/vsynth1-mpeg2
@@ -1,4 +1,4 @@
-fbddea2368cd2028fc8db4dfd4682e94 *tests/data/fate/vsynth1-mpeg2.mpeg2video
-728044 tests/data/fate/vsynth1-mpeg2.mpeg2video
-b41ca49c1a02e66ce64d262e2cdaec15 *tests/data/fate/vsynth1-mpeg2.out.rawvideo
+5434d2fbac67dc1a910883c9c04644fa *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 5948446..bb0dce7 100644
--- a/tests/ref/vsynth/vsynth1-mpeg2-422
+++ b/tests/ref/vsynth/vsynth1-mpeg2-422
@@ -1,4 +1,4 @@
-af0cb75451aaa807beb5102707a98823 *tests/data/fate/vsynth1-mpeg2-422.mpeg2video
-728200 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
+0af0a148bf44bed5d260cafae6cc53e7 *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-ilace b/tests/ref/vsynth/vsynth1-mpeg2-ilace
index be08c31..b83b04c 100644
--- a/tests/ref/vsynth/vsynth1-mpeg2-ilace
+++ b/tests/ref/vsynth/vsynth1-mpeg2-ilace
@@ -1,4 +1,4 @@
-ec3f6713c88a2b41f6c369fd64341077 *tests/data/fate/vsynth1-mpeg2-ilace.mpeg2video
-737473 tests/data/fate/vsynth1-mpeg2-ilace.mpeg2video
-97615390fdd69abfcbc7e02df863a7d2 *tests/data/fate/vsynth1-mpeg2-ilace.out.rawvideo
+8492b04953b04dbef51cbe065f894e47 *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 5ef30cd..4e00f0a 100644
--- a/tests/ref/vsynth/vsynth1-mpeg2-ivlc-qprd
+++ b/tests/ref/vsynth/vsynth1-mpeg2-ivlc-qprd
@@ -1,4 +1,4 @@
-8f6b20714918e6443e0c03716ed06f0d *tests/data/fate/vsynth1-mpeg2-ivlc-qprd.mpeg2video
-783552 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
+f5e8917781d576d0721d44a3111d3efa *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 55a4fab..fd56bf0 100644
--- a/tests/ref/vsynth/vsynth1-mpeg2-thread
+++ b/tests/ref/vsynth/vsynth1-mpeg2-thread
@@ -1,4 +1,4 @@
-ecd183706688bd977c9994c3d1b23d61 *tests/data/fate/vsynth1-mpeg2-thread.mpeg2video
-801313 tests/data/fate/vsynth1-mpeg2-thread.mpeg2video
-d1658911ca83f5616c1d32abc40750de *tests/data/fate/vsynth1-mpeg2-thread.out.rawvideo
+c52f961dd53263cd9e7785a0d46949b7 *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 7d04052..235dfe5 100644
--- a/tests/ref/vsynth/vsynth1-mpeg2-thread-ivlc
+++ b/tests/ref/vsynth/vsynth1-mpeg2-thread-ivlc
@@ -1,4 +1,4 @@
-23d600b026222253c2340e23300a4c02 *tests/data/fate/vsynth1-mpeg2-thread-ivlc.mpeg2video
-791773 tests/data/fate/vsynth1-mpeg2-thread-ivlc.mpeg2video
-d1658911ca83f5616c1d32abc40750de *tests/data/fate/vsynth1-mpeg2-thread-ivlc.out.rawvideo
+6c5ac0817a7fc501ed6d91e9b9899ed3 *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..9a58987 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
+a52ff2ce472737e07462d6b51673a886 *tests/data/fate/vsynth1-mpeg4.mp4
+540024 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..00ea53d 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
+2aa8bfefc09135a9a25dc23e3a14c6a4 *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..a67cc14 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
+b12cf575e8a28975cfeb67c23870afdd *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..b694362 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
+5a6d923425ff437924d4723aa73a817f *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..e71dd2b 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
+6515d1676d4d0c92c85c0468c53261aa *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-qpel b/tests/ref/vsynth/vsynth1-mpeg4-qpel
index 1ff1dce..67b72a1 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
+594626acf31cbfc4a14af4d9b3cd8a6c *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..0475e70 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
+96590e5921628ff84d109624e6124911 *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..96e41be 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
+59cf839b030f7df30b95fd300c4defb1 *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..a998273 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
+14059560812963039e852f4f6419c238 *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..5ca268b
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-mpng
@@ -0,0 +1,4 @@
+10bcdf8600d3985aeb57dc774df2b747 *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..4adabbe 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
+7d9d622b04156246348bde2e3a4d9c9c *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..775d575 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
+a0539692d72e763448fc0dbe98d92ea3 *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..0ab8860
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-msvideo1
@@ -0,0 +1,4 @@
+bea8dd62e64453fb08e4f3d19be23792 *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..bc1d883 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
+176b9fa03cc0946c6a41f2dcfad46805 *tests/data/fate/vsynth1-prores.mov
+5022821 tests/data/fate/vsynth1-prores.mov
+a2e2d1d45341a94ff994d1d92629f778 *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..76d9d30
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-prores_ks
@@ -0,0 +1,4 @@
+1d5522ee2fb507a66d236a09a172dc16 *tests/data/fate/vsynth1-prores_ks.mov
+3858911 tests/data/fate/vsynth1-prores_ks.mov
+0a4153637d0cc0a88a8bcbf04cfaf8c6 *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..25d61ce 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
+d909610eb8ad5250a73f0be4c9c29b82 *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..3aaba24
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-qtrlegray
@@ -0,0 +1,4 @@
+6ef537a90e5295670701bdeaf5eb4ce1 *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..15b56a2
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-r210
@@ -0,0 +1,4 @@
+80c966b18025897207ab624206a6e7a0 *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..3db3348 100644
--- a/tests/ref/vsynth/vsynth1-rgb
+++ b/tests/ref/vsynth/vsynth1-rgb
@@ -1,4 +1,4 @@
d78bcd5828862c3342388ec8a2c34fef *tests/data/fate/vsynth1-rgb.avi
15213248 tests/data/fate/vsynth1-rgb.avi
-243325fb2cae1a9245efd49aff936327 *tests/data/fate/vsynth1-rgb.out.rawvideo
-stddev: 3.42 PSNR: 37.43 MAXDIFF: 48 bytes: 7603200/ 7603200
+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-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..701b5cc
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-snow
@@ -0,0 +1,4 @@
+44fed844eb715fba0cc2433e7d7713bb *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..c22ad0a
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-snow-hpel
@@ -0,0 +1,4 @@
+f60c8cb8f41b66bc38df87e9bdb84b34 *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..1636af5
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-snow-ll
@@ -0,0 +1,4 @@
+bdc7a025cd306f3da0d377b06bbe909b *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..a7de66e 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
+69afe0f66844ac3edb83d97994099fc0 *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-v308 b/tests/ref/vsynth/vsynth1-v308
new file mode 100644
index 0000000..7dc5de9
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-v308
@@ -0,0 +1,4 @@
+05552ba36d003f8d5fec739c5ed90a67 *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..f1523d1
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-v408
@@ -0,0 +1,4 @@
+415c94a79b0eb58c445221a362e0054e *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..8d24543 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
+2760d19cb77d84bd5bfc588d23306113 *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..872ffc9 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
+4ab9357e6369c81fecb1ebcbc7551f0c *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..93fa938
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-y41p
@@ -0,0 +1,4 @@
+c9fce228075067c51511d8b070fde340 *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..2eeff80 100644
--- a/tests/ref/vsynth/vsynth1-yuv
+++ b/tests/ref/vsynth/vsynth1-yuv
@@ -1,4 +1,4 @@
-a9c708ba20f5c562fb1c89f6aa841c8c *tests/data/fate/vsynth1-yuv.avi
+9622cbbe3ced7490f50e74cf088bc7c9 *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..5c473a2
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-yuv4
@@ -0,0 +1,4 @@
+45805be52d9807f0c6f76011a64bf67b *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..f5441e1
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth1-zlib
@@ -0,0 +1,4 @@
+fd52fff386f172bb3aef97761b99331c *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
--- a/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..6937df3
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-amv
@@ -0,0 +1,4 @@
+26d039bc37b2186d57522a8e3dc76217 *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-avui b/tests/ref/vsynth/vsynth2-avui
new file mode 100644
index 0000000..424a15e
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-avui
@@ -0,0 +1,4 @@
+ec8425d8916254687ce700c940eb6664 *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..c93da2e 100644
--- a/tests/ref/vsynth/vsynth2-cljr
+++ b/tests/ref/vsynth/vsynth2-cljr
@@ -1,4 +1,4 @@
-5745ff1d80a6f454ae448dcf0bce50e0 *tests/data/fate/vsynth2-cljr.avi
+d9da8b1a1e78a8f0438d37c10f975ba3 *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..1f9b783 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
+4bbed3e8b6bc301d9bbdc83859f3a847 *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..cf3ba7b 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
+a57ce32ab22ae60bf21655b0d1ba3b07 *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
--- a/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..0d1465c 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
diff --git a/tests/ref/vsynth/vsynth2-dv-411 b/tests/ref/vsynth/vsynth2-dv-411
index 00ecace..d0e6d29 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
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..c5ac608 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
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
--- a/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..6caffdd 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
+0837dc7e6f625e2f6ac16140562c079d *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..962c17c
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-ffv1.0
@@ -0,0 +1,4 @@
+3a757276e299bf88c30e06dfb53f1c99 *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..164e773 100644
--- a/tests/ref/vsynth/vsynth2-ffvhuff
+++ b/tests/ref/vsynth/vsynth2-ffvhuff
@@ -1,4 +1,4 @@
-f6a213ef136012a3d189d09468d80dd3 *tests/data/fate/vsynth2-ffvhuff.avi
+6689843a60dcc046fe1d7be3afab2cab *tests/data/fate/vsynth2-ffvhuff.avi
4988044 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-flashsv b/tests/ref/vsynth/vsynth2-flashsv
index cbe79e6..e44fa8f 100644
--- a/tests/ref/vsynth/vsynth2-flashsv
+++ b/tests/ref/vsynth/vsynth2-flashsv
@@ -1,4 +1,4 @@
0667077971e0cb63b5f49c580006e90e *tests/data/fate/vsynth2-flashsv.flv
12368953 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
+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
--- a/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 6864a1b..ab31755 100644
--- a/tests/ref/vsynth/vsynth2-flv
+++ b/tests/ref/vsynth/vsynth2-flv
@@ -1,4 +1,4 @@
-2edc92093d36506bcc0a5c0e17e86113 *tests/data/fate/vsynth2-flv.flv
-131360 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..f9091c7 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
+dc32bc8a9e6eae15362ab86f8156f96a *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-h263 b/tests/ref/vsynth/vsynth2-h263
index b2ce370..944d8ea 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
+949d8c9926914751af5f433af0f8fd65 *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..a704318 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
+7825a0bdf024673da2371829e3f01cc3 *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..b4ebed9 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
+3894234818ed65426b5f20f058d27c73 *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..9b67815 100644
--- a/tests/ref/vsynth/vsynth2-huffyuv
+++ b/tests/ref/vsynth/vsynth2-huffyuv
@@ -1,4 +1,4 @@
-30d509aca4a7298cf7667581a5e37671 *tests/data/fate/vsynth2-huffyuv.avi
+b5ae95ae03856ee14bbd38784a02f3ca *tests/data/fate/vsynth2-huffyuv.avi
6455220 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-jpeg2000 b/tests/ref/vsynth/vsynth2-jpeg2000
new file mode 100644
index 0000000..cacd467
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-jpeg2000
@@ -0,0 +1,4 @@
+fc49816ba28731689872f5c87ca91c10 *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..e7fce13
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-jpeg2000-97
@@ -0,0 +1,4 @@
+3ac3e49a89136bddde9e44bac3e5b4ed *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..f8f7081 100644
--- a/tests/ref/vsynth/vsynth2-jpegls
+++ b/tests/ref/vsynth/vsynth2-jpegls
@@ -1,4 +1,4 @@
f34315ed0e30cf4d94dd21ff1d4cea1b *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 fa2f978..2136fe8 100644
--- a/tests/ref/vsynth/vsynth2-ljpeg
+++ b/tests/ref/vsynth/vsynth2-ljpeg
@@ -1,4 +1,4 @@
-db9fd56e154b1056c9443a82a96db6f5 *tests/data/fate/vsynth2-ljpeg.avi
-4766902 tests/data/fate/vsynth2-ljpeg.avi
+b691d815bb7e40ac4ff8c0e51d8c08ff *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..f1780c5 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
+302197cccebb4d9797a08d06ca189533 *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..fc0a4ba
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-mjpeg-422
@@ -0,0 +1,4 @@
+1ec800caa1dd2244677220d8a2b342ca *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..b09f889
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-mjpeg-444
@@ -0,0 +1,4 @@
+10abd087833f9bdf3b77c1aa37dc11e5 *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..bc94fbc 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
+c6f1a98dd7201b1e5d7f0f69d7e9577d *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..f4864a5 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
+8300bede250c3987f1c5bc9bbd1d78e1 *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 a2a2ca6..b5f5af9 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2
+++ b/tests/ref/vsynth/vsynth2-mpeg2
@@ -1,4 +1,4 @@
-2d55ce623a7be4e8136f80266e487678 *tests/data/fate/vsynth2-mpeg2.mpeg2video
-198667 tests/data/fate/vsynth2-mpeg2.mpeg2video
-b7cae8a1f751b821cddcbe4d5dbc518c *tests/data/fate/vsynth2-mpeg2.out.rawvideo
+81fc934ad6901b6c37a59b94ccda8de7 *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 2405cf0..14d751b 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-422
+++ b/tests/ref/vsynth/vsynth2-mpeg2-422
@@ -1,4 +1,4 @@
-2c8e33c2d2efab86fc16a195f6877682 *tests/data/fate/vsynth2-mpeg2-422.mpeg2video
-356124 tests/data/fate/vsynth2-mpeg2-422.mpeg2video
-df6e54e2d8a4feb8382029286857ca6d *tests/data/fate/vsynth2-mpeg2-422.out.rawvideo
-stddev: 3.16 PSNR: 38.13 MAXDIFF: 49 bytes: 7603200/ 7603200
+99ba26ba009e0172855a9dadaefef2d9 *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-ilace b/tests/ref/vsynth/vsynth2-mpeg2-ilace
index e488bc5..2f9a306 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-ilace
+++ b/tests/ref/vsynth/vsynth2-mpeg2-ilace
@@ -1,4 +1,4 @@
-f90197a8b6e62ae25f82625337f27240 *tests/data/fate/vsynth2-mpeg2-ilace.mpeg2video
-204579 tests/data/fate/vsynth2-mpeg2-ilace.mpeg2video
-ea5057b60146c06d40449cdfc686bf13 *tests/data/fate/vsynth2-mpeg2-ilace.out.rawvideo
+a6f4c4dbd7f73b73e876fbd7a9650610 *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-thread b/tests/ref/vsynth/vsynth2-mpeg2-thread
index f43cdbc..40552fe 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-thread
+++ b/tests/ref/vsynth/vsynth2-mpeg2-thread
@@ -1,4 +1,4 @@
-889c754a42d7689b228853e1ece6d345 *tests/data/fate/vsynth2-mpeg2-thread.mpeg2video
-179650 tests/data/fate/vsynth2-mpeg2-thread.mpeg2video
-8c6a7ed2eb73bd18fd2bb9829464100d *tests/data/fate/vsynth2-mpeg2-thread.out.rawvideo
+38af1e2261ae363abea5818db74ea241 *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 2c42a21..9bcac8b 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-thread-ivlc
+++ b/tests/ref/vsynth/vsynth2-mpeg2-thread-ivlc
@@ -1,4 +1,4 @@
-10b900e32809758857c596d56746e00e *tests/data/fate/vsynth2-mpeg2-thread-ivlc.mpeg2video
-178801 tests/data/fate/vsynth2-mpeg2-thread-ivlc.mpeg2video
-8c6a7ed2eb73bd18fd2bb9829464100d *tests/data/fate/vsynth2-mpeg2-thread-ivlc.out.rawvideo
+9cb6b65e05fa854da2ad08b34fe032aa *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..0956543 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
+3d99aa9393f2a1a9319580b78df2bf3d *tests/data/fate/vsynth2-mpeg4.mp4
+119661 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..175552d 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
+4b39d46a436f1bce59e2902cec3478e9 *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-error b/tests/ref/vsynth/vsynth2-mpeg4-error
index 35dd03d..c6a2218 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
+599a21c149a150072db364298dbcdda2 *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..45db4b6 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
+e1cf863ec6c0a4975d49326df63342ca *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-qpel b/tests/ref/vsynth/vsynth2-mpeg4-qpel
index cab264a..8705bd5 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
+b36ad1ca7ac6e1aff6d69b8df4386011 *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..1bbda29 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
+ee24ddde5e3c06a6c44093a59e7ac413 *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..2a26a16 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
+20028333988bb7a0888a79799ea63b19 *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..d8d87c4 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
+d50954ec2c64c2634d88ba1df879dde0 *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..2e6865c
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-mpng
@@ -0,0 +1,4 @@
+b8f9aa584da89837058c96fc5c3a6562 *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..274cecc 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
+6eb2a9770c223636befacfba83f72c44 *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..a851a2f 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
+e0929f2cebefc9f6259870b806829de3 *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..a915c13
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-msvideo1
@@ -0,0 +1,4 @@
+6c1709d61202ec2e73b467e76cb79f9b *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..99f56de 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
+af885572d77d28e5ede27932bd68cdde *tests/data/fate/vsynth2-prores.mov
+2844076 tests/data/fate/vsynth2-prores.mov
+b5844025c0f4c7c37db702c3213db232 *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..9d05832
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-prores_ks
@@ -0,0 +1,4 @@
+c1c71cf2dbd6e332aacb6ab1c6affa59 *tests/data/fate/vsynth2-prores_ks.mov
+3884596 tests/data/fate/vsynth2-prores_ks.mov
+ca2f6c1162635dedfa468c90f1fdc0ef *tests/data/fate/vsynth2-prores_ks.out.rawvideo
+stddev: 0.92 PSNR: 48.77 MAXDIFF: 10 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-qtrle b/tests/ref/vsynth/vsynth2-qtrle
index ac2b557..0ae2d00 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
+3172f6a2c63e591048fe3309795f2d7a *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..8f01304
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-qtrlegray
@@ -0,0 +1,4 @@
+5304bbafd31bb8bf3d274f1d01db81f5 *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..a91c12a
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-r210
@@ -0,0 +1,4 @@
+4568992c4f5562be06374519a419d3a3 *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..6f5169d 100644
--- a/tests/ref/vsynth/vsynth2-rgb
+++ b/tests/ref/vsynth/vsynth2-rgb
@@ -1,4 +1,4 @@
01199075994e44f282fbb6a8e3ccc668 *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-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..12f3811
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-snow
@@ -0,0 +1,4 @@
+4b6236e23ae4a52655f2c24c5a09380a *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..955f1bf
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-snow-hpel
@@ -0,0 +1,4 @@
+9872032345c33cf8e8fc26ab655be3d3 *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..9a72549
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-snow-ll
@@ -0,0 +1,4 @@
+30b40e0bf64f92b23d6f94056c0c6da5 *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..72cc6f9 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
+ab9b1f922c4ae1b5d602bdeebc8b185d *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-v308 b/tests/ref/vsynth/vsynth2-v308
new file mode 100644
index 0000000..f7c46fc
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-v308
@@ -0,0 +1,4 @@
+aba17ed2860ac714da0e378ebe47e7bb *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..4c63dec
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-v408
@@ -0,0 +1,4 @@
+d689d4a53081765f0fbc965554c06faa *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..6e56b6f 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
+dc2affb9b9a95a09dd69c25c75c50174 *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..5de4898 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
+1b0e968e180346914c11875f4eec57eb *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..ac9d64a
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-y41p
@@ -0,0 +1,4 @@
+0689a7a5c4dd6ac6ac515b54d45d249e *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..d6b8736 100644
--- a/tests/ref/vsynth/vsynth2-yuv
+++ b/tests/ref/vsynth/vsynth2-yuv
@@ -1,4 +1,4 @@
-d08219372af7a764c1afbc99a1002fe0 *tests/data/fate/vsynth2-yuv.avi
+0029ade090172b34687cdc9163748e47 *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..8fa347a
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-yuv4
@@ -0,0 +1,4 @@
+00454056d8560cde37409e0b578209d8 *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..0a7ed3c
--- a/dev/null
+++ b/tests/ref/vsynth/vsynth2-zlib
@@ -0,0 +1,4 @@
+d0e240b5241c3e0a5f813644d3dc5d9f *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
--- a/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/vsynth1/cljr b/tests/ref/vsynth1/cljr
new file mode 100644
index 0000000..6002bbb
--- a/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
--- a/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
--- a/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
--- a/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
--- a/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 ce5aee8..7538795 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}
+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
--- a/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..b4fc02c 100644
--- a/tests/tiny_psnr.c
+++ b/tests/tiny_psnr.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,9 +22,9 @@
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
-#include <assert.h>
#include <math.h>
#include <float.h>
+#include <limits.h>
#include "libavutil/intfloat.h"
#include "libavutil/intreadwrite.h"
@@ -57,6 +57,21 @@ uint64_t exp16_table[21] = {
582360139072LL,
};
+#if 0
+// 16.16 fixpoint exp()
+static unsigned int exp16(unsigned int a){
+ int i;
+ int out= 1<<16;
+
+ for(i=19;i>=0;i--){
+ if(a&(1<<i))
+ out= (out*exp16_table[i] + (1<<15))>>16;
+ }
+
+ return out;
+}
+#endif
+
// 16.16 fixpoint log()
static int64_t log16(uint64_t a)
{
@@ -115,79 +130,47 @@ static double get_f64l(uint8_t *p)
return av_int2double(AV_RL64(p));
}
-int main(int argc, char *argv[])
+static int run_psnr(FILE *f[2], int len, int shift, int skip_bytes)
{
int i, j;
uint64_t sse = 0;
double sse_d = 0.0;
- FILE *f[2];
uint8_t buf[2][SIZE];
- int len = 1;
- int64_t max;
- int shift = argc < 5 ? 0 : atoi(argv[4]);
- int skip_bytes = argc < 6 ? 0 : atoi(argv[5]);
+ int64_t max = (1LL << (8 * len)) - 1;
int size0 = 0;
int size1 = 0;
uint64_t maxdist = 0;
double maxdist_d = 0.0;
+ int noseek;
- if (argc < 3) {
- printf("tiny_psnr <file1> <file2> [<elem size> [<shift> [<skip bytes>]]]\n");
- printf("WAV headers are skipped automatically.\n");
- return 1;
- }
-
- if (argc > 3) {
- if (!strcmp(argv[3], "u8")) {
- len = 1;
- } else if (!strcmp(argv[3], "s16")) {
- len = 2;
- } else if (!strcmp(argv[3], "f32")) {
- len = 4;
- } else if (!strcmp(argv[3], "f64")) {
- len = 8;
- } else {
- char *end;
- len = strtol(argv[3], &end, 0);
- if (*end || len < 1 || len > 2) {
- fprintf(stderr, "Unsupported sample format: %s\n", argv[3]);
- return 1;
- }
- }
- }
-
- max = (1LL << (8 * len)) - 1;
+ noseek = fseek(f[0], 0, SEEK_SET) ||
+ fseek(f[1], 0, SEEK_SET);
- f[0] = fopen(argv[1], "rb");
- f[1] = fopen(argv[2], "rb");
- if (!f[0] || !f[1]) {
- fprintf(stderr, "Could not open input files.\n");
- return 1;
- }
-
- for (i = 0; i < 2; i++) {
- uint8_t *p = buf[i];
- if (fread(p, 1, 12, f[i]) != 12)
- return 1;
- if (!memcmp(p, "RIFF", 4) &&
- !memcmp(p + 8, "WAVE", 4)) {
- if (fread(p, 1, 8, f[i]) != 8)
+ if (!noseek) {
+ for (i = 0; i < 2; i++) {
+ uint8_t *p = buf[i];
+ if (fread(p, 1, 12, f[i]) != 12)
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]);
@@ -255,16 +238,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 +257,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\n", argv[3]);
+ return 1;
+ }
+ }
+ }
+
+ if (argc < 3) {
+ printf("tiny_psnr <file1> <file2> [<elem size> [<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..759a84b
--- a/dev/null
+++ b/tests/tiny_ssim.c
@@ -0,0 +1,216 @@
+/*
+ * 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 <inttypes.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;
+}
+
+double ssd_to_psnr( uint64_t ssd, uint64_t denom )
+{
+ return -10*log((double)ssd/(denom*255*255))/log(10);
+}
+
+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);
+ frame_size = w*h*3/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++ )
+ {
+ 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[i] += ssd_plane ( plane[0][i], plane[1][i], w*h>>2*!!i );
+ ssim[i] += ssim_plane( plane[0][i], w>>!!i,
+ plane[1][i], w>>!!i,
+ w>>!!i, h>>!!i, temp, NULL );
+ }
+ }
+
+ if( !frames ) return 0;
+
+ printf( "PSNR Y:%.3f U:%.3f V:%.3f All:%.3f\n",
+ 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\n",
+ ssim[0] / frames,
+ ssim[1] / frames,
+ ssim[2] / frames,
+ (ssim[0]*4 + ssim[1] + ssim[2]) / (frames*6) );
+
+ return 0;
+}
diff --git a/tests/utils.c b/tests/utils.c
index 2fdc491..e8ef06f 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
*/
diff --git a/tests/videogen.c b/tests/videogen.c
index 0b7f67e..94e6e77 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
*/
diff --git a/tools/aviocat.c b/tools/aviocat.c
index 52a96bd..e161d58 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
--- a/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
--- a/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..8b3a093
--- a/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 git://github.com/CyanogenMod/android_frameworks_base.git ../android-source/frameworks/base
+git clone --depth=1 --branch gingerbread-release git://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
--- a/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..1a699ce
--- a/dev/null
+++ b/tools/crypto_bench.c
@@ -0,0 +1,358 @@
+/*
+ * 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"
+
+#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"
+
+#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);
+}
+
+/***************************************************************************
+ * 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>
+
+#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);
+}
+
+#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 == NULL)
+ 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);
+}
+
+#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);
+}
+
+#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")
+};
+
+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/enum_options.c b/tools/enum_options.c
new file mode 100644
index 0000000..c2a295c
--- a/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
--- a/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..66b1032
--- a/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%s\n", prompt, 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..086d48a
--- a/dev/null
+++ b/tools/ffhash.c
@@ -0,0 +1,149 @@
+/*
+ * 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/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 uint8_t *res;
+
+static void usage(void)
+{
+ int i = 0;
+ const char *name;
+
+ printf("usage: ffhash [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)
+{
+ int i, len = av_hash_get_size(hash);
+
+ printf("%s=0x", av_hash_get_name(hash));
+ av_hash_final(hash, res);
+ for (i = 0; i < len; i++)
+ printf("%02x", res[i]);
+}
+
+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) {
+ close(fd);
+ finish();
+ printf("+READ-FAILED: %s", strerror(errno));
+ 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;
+
+ if (argc == 1) {
+ usage();
+ return 0;
+ }
+
+ if ((ret = av_hash_alloc(&hash, argv[1])) < 0) {
+ switch(ret) {
+ case AVERROR(EINVAL):
+ printf("Invalid hash type: %s\n", argv[1]);
+ break;
+ case AVERROR(ENOMEM):
+ printf("%s\n", strerror(errno));
+ break;
+ }
+ return 1;
+ }
+ res = av_malloc(av_hash_get_size(hash));
+ if (!res) {
+ printf("%s\n", strerror(errno));
+ return 1;
+ }
+
+ for (i = 2; i < argc; i++)
+ ret |= check(argv[i]);
+
+ if (argc < 3)
+ ret |= check(NULL);
+
+ av_hash_freep(&hash);
+ av_freep(&res);
+
+ return ret;
+}
diff --git a/tools/fourcc2pixfmt.c b/tools/fourcc2pixfmt.c
new file mode 100644
index 0000000..1a653ed
--- a/dev/null
+++ b/tools/fourcc2pixfmt.c
@@ -0,0 +1,123 @@
+/*
+ * 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, char sep)
+{
+ int i;
+
+ for (i = 0; ff_raw_pix_fmt_tags[i].pix_fmt != AV_PIX_FMT_NONE; i++) {
+ if (ff_raw_pix_fmt_tags[i].pix_fmt == pix_fmt) {
+ char buf[32];
+ av_get_codec_tag_string(buf, sizeof(buf), ff_raw_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 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; ff_raw_pix_fmt_tags[i].pix_fmt != AV_PIX_FMT_NONE; i++) {
+ char buf[32];
+ av_get_codec_tag_string(buf, sizeof(buf), ff_raw_pix_fmt_tags[i].fourcc);
+ printf("%s: %s\n", buf, av_get_pix_fmt_name(ff_raw_pix_fmt_tags[i].pix_fmt));
+ }
+ }
+
+ if (list_pix_fmt_fourccs) {
+ for (i = 0; i < AV_PIX_FMT_NB; 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, ' ');
+ 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, '\n');
+ }
+
+ return 0;
+}
diff --git a/tools/graph2dot.c b/tools/graph2dot.c
index 692ada2..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
*/
@@ -25,9 +25,9 @@
#include <stdio.h>
#include <string.h>
+#include "libavutil/channel_layout.h"
#include "libavutil/mem.h"
#include "libavutil/pixdesc.h"
-#include "libavutil/audioconvert.h"
#include "libavfilter/avfilter.h"
#if !HAVE_GETOPT
@@ -58,43 +58,47 @@ static void print_digraph(FILE *outfile, AVFilterGraph *graph)
fprintf(outfile, "node [shape=box]\n");
fprintf(outfile, "rankdir=LR\n");
- for (i = 0; i < graph->filter_count; i++) {
+ for (i = 0; i < graph->nb_filters; i++) {
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);
- for (j = 0; j < filter_ctx->output_count; j++) {
+ for (j = 0; j < filter_ctx->nb_outputs; j++) {
AVFilterLink *link = filter_ctx->outputs[j];
if (link) {
char dst_filter_ctx_label[128];
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 a51c5b7..4dc3e12 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.
@@ -35,6 +35,8 @@
#include <stdio.h>
#include <string.h>
+#include "cmdutils.h"
+
#include "libavformat/avformat.h"
#include "libavformat/os_support.h"
#include "libavutil/intreadwrite.h"
@@ -126,7 +128,8 @@ static int write_fragments(struct Tracks *tracks, int start_index,
struct Track *track = tracks->tracks[i];
const char *type = track->is_video ? "video" : "audio";
snprintf(dirname, sizeof(dirname), "QualityLevels(%d)", track->bitrate);
- mkdir(dirname, 0777);
+ if (mkdir(dirname, 0777) == -1)
+ return AVERROR(errno);
for (j = 0; j < track->chunks; j++) {
snprintf(filename, sizeof(filename), "%s/Fragments(%s=%"PRId64")",
dirname, type, track->offsets[j].time);
@@ -218,7 +221,7 @@ static int read_mfra(struct Tracks *tracks, int start_index,
}
if (split)
- write_fragments(tracks, start_index, f);
+ err = write_fragments(tracks, start_index, f);
fail:
if (f)
@@ -247,7 +250,10 @@ static int get_video_private_data(struct Track *track, AVCodecContext *codec)
if (codec->codec_id == AV_CODEC_ID_VC1)
return get_private_data(track, codec);
- avio_open_dyn_buf(&io);
+ if (avio_open_dyn_buf(&io) < 0) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
if (codec->extradata_size < 11 || codec->extradata[0] != 1)
goto fail;
sps_size = AV_RB16(&codec->extradata[6]);
diff --git a/tools/make_chlayout_test b/tools/make_chlayout_test
new file mode 100755
index 0000000..fcdbda3
--- a/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..093d02e
--- a/dev/null
+++ b/tools/missing_codec_desc
@@ -0,0 +1,37 @@
+#!/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_TTF=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..e015913
--- a/dev/null
+++ b/tools/normalize.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python2
+
+import sys, subprocess
+
+if len(sys.argv) > 1:
+ 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..59a16ef 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_]*'
@@ -50,7 +50,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 +67,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)\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
--- a/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..b13c6f9 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
*/
@@ -49,12 +49,29 @@ static void probe(AVProbeData *pd, int type, int p, int size)
}
}
-int main(void)
+int main(int argc, char **argv)
{
unsigned int p, i, type, size, retry;
AVProbeData pd;
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 +79,16 @@ 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 = "";
+ 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;
diff --git a/tools/qt-faststart.c b/tools/qt-faststart.c
index f33d6fa..cb36c43 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
@@ -37,6 +37,8 @@
#define ftello(x) _ftelli64(x)
#endif
+#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
+
#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1])
#define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \
@@ -77,7 +79,7 @@
#define CO64_ATOM QT_ATOM('c', 'o', '6', '4')
#define ATOM_PREAMBLE_SIZE 8
-#define COPY_BUFFER_SIZE 1024
+#define COPY_BUFFER_SIZE 33554432
int main(int argc, char *argv[])
{
@@ -95,8 +97,8 @@ int main(int argc, char *argv[])
uint64_t i, j;
uint32_t offset_count;
uint64_t current_offset;
- uint64_t start_offset = 0;
- unsigned char copy_buffer[COPY_BUFFER_SIZE];
+ int64_t start_offset = 0;
+ unsigned char *copy_buffer = NULL;
int bytes_to_copy;
if (argc != 3) {
@@ -134,22 +136,27 @@ int main(int argc, char *argv[])
atom_size);
goto error_out;
}
- fseeko(infile, -ATOM_PREAMBLE_SIZE, SEEK_CUR);
- if (fread(ftyp_atom, atom_size, 1, infile) != 1) {
+ if ( fseeko(infile, -ATOM_PREAMBLE_SIZE, SEEK_CUR)
+ || fread(ftyp_atom, atom_size, 1, infile) != 1
+ || (start_offset = ftello(infile))<0) {
perror(argv[1]);
goto error_out;
}
- start_offset = ftello(infile);
} else {
+ int ret;
/* 64-bit special case */
if (atom_size == 1) {
if (fread(atom_bytes, ATOM_PREAMBLE_SIZE, 1, infile) != 1) {
break;
}
atom_size = BE_64(&atom_bytes[0]);
- fseeko(infile, atom_size - ATOM_PREAMBLE_SIZE * 2, SEEK_CUR);
+ ret = fseeko(infile, atom_size - ATOM_PREAMBLE_SIZE * 2, SEEK_CUR);
} else {
- fseeko(infile, atom_size - ATOM_PREAMBLE_SIZE, SEEK_CUR);
+ ret = fseeko(infile, atom_size - ATOM_PREAMBLE_SIZE, SEEK_CUR);
+ }
+ if(ret) {
+ perror(argv[1]);
+ goto error_out;
}
}
printf("%c%c%c%c %10"PRIu64" %"PRIu64"\n",
@@ -190,7 +197,10 @@ int main(int argc, char *argv[])
/* moov atom was, in fact, the last atom in the chunk; load the whole
* moov atom */
- fseeko(infile, -atom_size, SEEK_END);
+ if (fseeko(infile, -atom_size, SEEK_END)) {
+ perror(argv[1]);
+ goto error_out;
+ }
last_offset = ftello(infile);
moov_atom_size = atom_size;
moov_atom = malloc(moov_atom_size);
@@ -219,14 +229,18 @@ int main(int argc, char *argv[])
atom_type = BE_32(&moov_atom[i]);
if (atom_type == STCO_ATOM) {
printf(" patching stco atom...\n");
- atom_size = BE_32(&moov_atom[i - 4]);
+ atom_size = (uint32_t)BE_32(&moov_atom[i - 4]);
if (i + atom_size - 4 > moov_atom_size) {
printf(" bad atom size\n");
goto error_out;
}
offset_count = BE_32(&moov_atom[i + 8]);
+ if (i + 12LL + offset_count * 4LL > moov_atom_size) {
+ printf(" bad atom size\n");
+ goto error_out;
+ }
for (j = 0; j < offset_count; j++) {
- current_offset = BE_32(&moov_atom[i + 12 + j * 4]);
+ current_offset = (uint32_t)BE_32(&moov_atom[i + 12 + j * 4]);
current_offset += moov_atom_size;
moov_atom[i + 12 + j * 4 + 0] = (current_offset >> 24) & 0xFF;
moov_atom[i + 12 + j * 4 + 1] = (current_offset >> 16) & 0xFF;
@@ -236,12 +250,16 @@ int main(int argc, char *argv[])
i += atom_size - 4;
} else if (atom_type == CO64_ATOM) {
printf(" patching co64 atom...\n");
- atom_size = BE_32(&moov_atom[i - 4]);
+ atom_size = (uint32_t)BE_32(&moov_atom[i - 4]);
if (i + atom_size - 4 > moov_atom_size) {
printf(" bad atom size\n");
goto error_out;
}
offset_count = BE_32(&moov_atom[i + 8]);
+ if (i + 12LL + offset_count * 8LL > moov_atom_size) {
+ printf(" bad atom size\n");
+ goto error_out;
+ }
for (j = 0; j < offset_count; j++) {
current_offset = BE_64(&moov_atom[i + 12 + j * 8]);
current_offset += moov_atom_size;
@@ -266,7 +284,11 @@ int main(int argc, char *argv[])
}
if (start_offset > 0) { /* seek after ftyp atom */
- fseeko(infile, start_offset, SEEK_SET);
+ if (fseeko(infile, start_offset, SEEK_SET)) {
+ perror(argv[1]);
+ goto error_out;
+ }
+
last_offset -= start_offset;
}
@@ -293,12 +315,15 @@ int main(int argc, char *argv[])
}
/* copy the remainder of the infile, from offset 0 -> last_offset - 1 */
+ bytes_to_copy = FFMIN(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) {
- if (last_offset > COPY_BUFFER_SIZE)
- bytes_to_copy = COPY_BUFFER_SIZE;
- else
- bytes_to_copy = last_offset;
+ bytes_to_copy = FFMIN(bytes_to_copy, last_offset);
if (fread(copy_buffer, bytes_to_copy, 1, infile) != 1) {
perror(argv[1]);
@@ -315,6 +340,7 @@ int main(int argc, char *argv[])
fclose(outfile);
free(moov_atom);
free(ftyp_atom);
+ free(copy_buffer);
return 0;
@@ -325,5 +351,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
--- a/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/unwrap-diff b/tools/unwrap-diff
new file mode 100755
index 0000000..ccea99b
--- a/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..11585f9
--- a/dev/null
+++ b/tools/yuvcmp.c
@@ -0,0 +1,182 @@
+/*
+ * 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>
+#include <unistd.h>
+
+
+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..ae3c8d7
--- a/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 *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;
+ }
+
+ ctx = zmq_ctx_new();
+ if (!ctx) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Could not create ZMQ context: %s\n", zmq_strerror(errno));
+ return 1;
+ }
+
+ socket = zmq_socket(ctx, ZMQ_REQ);
+ if (!socket) {
+ av_log(ctx, 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(ctx, 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(ctx, 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(ctx, 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(ctx, 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(ctx);
+ return ret;
+}
diff --git a/tools/zmqshell.py b/tools/zmqshell.py
new file mode 100755
index 0000000..a7d1126
--- a/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..8d084c2 100755
--- a/version.sh
+++ b/version.sh
@@ -1,11 +1,33 @@
#!/bin/sh
# check for git short hash
-revision=$(cd "$1" && git describe --always 2> /dev/null)
+if ! test "$revision"; then
+ revision=$(cd "$1" && git describe --tags --match N 2> /dev/null)
+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,7 +39,7 @@ if [ -z "$2" ]; then
exit
fi
-NEW_REVISION="#define LIBAV_VERSION \"$version\""
+NEW_REVISION="#define FFMPEG_VERSION \"$version\""
OLD_REVISION=$(cat version.h 2> /dev/null)
# Update version.h only on revision changes to avoid spurious rebuilds