summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore30
-rw-r--r--CREDITS59
-rw-r--r--Changelog407
-rw-r--r--INSTALL9
-rw-r--r--LICENSE64
-rw-r--r--MAINTAINERS490
-rw-r--r--Makefile107
-rw-r--r--README12
-rw-r--r--RELEASE2
-rw-r--r--arch.mak5
-rw-r--r--avprobe.c969
-rw-r--r--cmdutils.c652
-rw-r--r--cmdutils.h103
-rw-r--r--cmdutils_common_opts.h11
-rw-r--r--common.mak76
-rw-r--r--compat/avisynth/avisynth_c.h879
-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/plan9/main.c8
-rw-r--r--compat/strtod.c8
-rw-r--r--compat/va_copy.h26
-rwxr-xr-xconfigure859
-rw-r--r--doc/APIchanges753
-rw-r--r--doc/Doxyfile17
-rw-r--r--doc/Makefile78
-rw-r--r--doc/RELEASE_NOTES101
-rw-r--r--doc/authors.texi11
-rw-r--r--doc/avplay.texi182
-rw-r--r--doc/avprobe.texi141
-rw-r--r--doc/avtools-common-opts.texi171
-rw-r--r--doc/bitstream_filters.texi24
-rw-r--r--doc/build_system.txt25
-rw-r--r--doc/codecs.texi1069
-rw-r--r--doc/decoders.texi89
-rw-r--r--doc/default.css149
-rw-r--r--doc/demuxers.texi320
-rw-r--r--doc/developer.texi387
-rw-r--r--doc/devices.texi21
-rw-r--r--doc/encoders.texi215
-rw-r--r--doc/errno.txt174
-rw-r--r--doc/eval.texi156
-rw-r--r--doc/examples/Makefile37
-rw-r--r--doc/examples/README18
-rw-r--r--doc/examples/decoding_encoding.c (renamed from libavcodec/api-example.c)298
-rw-r--r--doc/examples/demuxing.c342
-rw-r--r--doc/examples/filtering_audio.c265
-rw-r--r--doc/examples/filtering_video.c251
-rw-r--r--doc/examples/metadata.c (renamed from libavformat/metadata-example.c)4
-rw-r--r--doc/examples/muxing.c (renamed from libavformat/output-example.c)341
-rw-r--r--doc/examples/resampling_audio.c211
-rw-r--r--doc/examples/scaling_video.c141
-rw-r--r--doc/faq.texi312
-rw-r--r--doc/fate.texi258
-rw-r--r--doc/fate_config.sh.template25
-rw-r--r--doc/ffmpeg-bitstream-filters.texi45
-rw-r--r--doc/ffmpeg-codecs.texi42
-rw-r--r--doc/ffmpeg-devices.texi42
-rw-r--r--doc/ffmpeg-filters.texi42
-rw-r--r--doc/ffmpeg-formats.texi42
-rw-r--r--doc/ffmpeg-protocols.texi42
-rw-r--r--doc/ffmpeg-resampler.texi44
-rw-r--r--doc/ffmpeg-scaler.texi43
-rw-r--r--doc/ffmpeg-utils.texi42
-rw-r--r--doc/ffmpeg.texi (renamed from doc/avconv.texi)773
-rw-r--r--doc/ffmpeg.txt47
-rw-r--r--doc/ffplay.texi274
-rw-r--r--doc/ffprobe.texi560
-rw-r--r--doc/ffprobe.xsd198
-rw-r--r--doc/ffserver.conf (renamed from doc/avserver.conf)25
-rw-r--r--doc/ffserver.texi (renamed from doc/avserver.texi)196
-rw-r--r--doc/filter_design.txt270
-rw-r--r--doc/filters.texi7560
-rw-r--r--doc/formats.texi146
-rw-r--r--doc/general.texi232
-rw-r--r--doc/git-howto.texi91
-rw-r--r--doc/git-howto.txt19
-rw-r--r--doc/indevs.texi556
-rw-r--r--doc/issue_tracker.txt213
-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.texi4
-rw-r--r--doc/mips.txt70
-rw-r--r--doc/multithreading.txt4
-rw-r--r--doc/muxers.texi444
-rw-r--r--doc/nut.texi5
-rw-r--r--doc/optimization.txt8
-rw-r--r--doc/outdevs.texi129
-rw-r--r--doc/platform.texi65
-rw-r--r--doc/print_options.c2
-rw-r--r--doc/protocols.texi260
-rw-r--r--doc/resampler.texi222
-rw-r--r--doc/scaler.texi99
-rw-r--r--doc/snow.txt630
-rw-r--r--doc/soc.txt6
-rw-r--r--doc/swresample.txt46
-rw-r--r--doc/t2h.init146
-rwxr-xr-xdoc/texi2pod.pl77
-rw-r--r--doc/utils.texi592
-rw-r--r--ffmpeg.c (renamed from avconv.c)1952
-rw-r--r--ffmpeg.h (renamed from avconv.h)140
-rw-r--r--ffmpeg_filter.c (renamed from avconv_filter.c)405
-rw-r--r--ffmpeg_opt.c (renamed from avconv_opt.c)902
-rw-r--r--ffplay.c (renamed from avplay.c)2262
-rw-r--r--ffprobe.c2327
-rw-r--r--ffserver.c (renamed from avserver.c)192
-rw-r--r--libavcodec/012v.c153
-rw-r--r--libavcodec/4xm.c162
-rw-r--r--libavcodec/8bps.c35
-rw-r--r--libavcodec/8svx.c121
-rw-r--r--libavcodec/Makefile180
-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.c8
-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.c14
-rw-r--r--libavcodec/aacdec.c271
-rw-r--r--libavcodec/aacdectab.h8
-rw-r--r--libavcodec/aacenc.c34
-rw-r--r--libavcodec/aacenc.h13
-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.c2
-rw-r--r--libavcodec/aacpsdsp.h1
-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.c71
-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.c21
-rw-r--r--libavcodec/ac3enc_fixed.c23
-rw-r--r--libavcodec/ac3enc_float.c22
-rw-r--r--libavcodec/ac3enc_template.c37
-rw-r--r--libavcodec/ac3tab.c8
-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.c303
-rw-r--r--libavcodec/adpcm.h12
-rw-r--r--libavcodec/adpcm_data.c21
-rw-r--r--libavcodec/adpcm_data.h10
-rw-r--r--libavcodec/adpcmenc.c60
-rw-r--r--libavcodec/adx.c5
-rw-r--r--libavcodec/adx.h8
-rw-r--r--libavcodec/adxdec.c15
-rw-r--r--libavcodec/adxenc.c12
-rw-r--r--libavcodec/alac.c99
-rw-r--r--libavcodec/alac_data.c8
-rw-r--r--libavcodec/alac_data.h8
-rw-r--r--libavcodec/alacenc.c12
-rw-r--r--libavcodec/allcodecs.c114
-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.c110
-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.c33
-rw-r--r--libavcodec/arm/aac.h8
-rw-r--r--libavcodec/arm/ac3dsp_init_arm.c18
-rw-r--r--libavcodec/arm/ac3dsp_neon.S44
-rw-r--r--libavcodec/arm/asm-offsets.h8
-rw-r--r--libavcodec/arm/dca.h76
-rw-r--r--libavcodec/arm/dcadsp_init_arm.c8
-rw-r--r--libavcodec/arm/dcadsp_neon.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.S2
-rw-r--r--libavcodec/arm/fft_init_arm.c10
-rw-r--r--libavcodec/arm/fft_neon.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/h264chroma_init_arm.c8
-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.S8
-rw-r--r--libavcodec/arm/mathops.h8
-rw-r--r--libavcodec/arm/mdct_neon.S8
-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/rdft_neon.S8
-rw-r--r--libavcodec/arm/rv34dsp_init_arm.c8
-rw-r--r--libavcodec/arm/rv40dsp_init_arm.c8
-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/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/vp56dsp_init_arm.c8
-rw-r--r--libavcodec/arm/vp56dsp_neon.S8
-rw-r--r--libavcodec/arm/vp8.h8
-rw-r--r--libavcodec/arm/vp8_armv6.S8
-rw-r--r--libavcodec/arm/vp8dsp_init_arm.c8
-rw-r--r--libavcodec/arm/vp8dsp_neon.S8
-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.c70
-rw-r--r--libavcodec/asv.c8
-rw-r--r--libavcodec/asv.h8
-rw-r--r--libavcodec/asvdec.c20
-rw-r--r--libavcodec/asvenc.c18
-rw-r--r--libavcodec/atrac.c8
-rw-r--r--libavcodec/atrac.h8
-rw-r--r--libavcodec/atrac1.c19
-rw-r--r--libavcodec/atrac1data.h8
-rw-r--r--libavcodec/atrac3.c52
-rw-r--r--libavcodec/atrac3data.h8
-rw-r--r--libavcodec/audio_frame_queue.c151
-rw-r--r--libavcodec/audio_frame_queue.h6
-rw-r--r--libavcodec/audioconvert.c8
-rw-r--r--libavcodec/audioconvert.h8
-rw-r--r--libavcodec/aura.c12
-rw-r--r--libavcodec/avcodec.h763
-rw-r--r--libavcodec/avfft.c8
-rw-r--r--libavcodec/avfft.h8
-rw-r--r--libavcodec/avpacket.c183
-rw-r--r--libavcodec/avpicture.c73
-rw-r--r--libavcodec/avr32/mathops.h8
-rw-r--r--libavcodec/avrndec.c132
-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.c18
-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.c14
-rw-r--r--libavcodec/bgmc.h8
-rw-r--r--libavcodec/bink.c83
-rw-r--r--libavcodec/binkaudio.c20
-rw-r--r--libavcodec/binkdata.h8
-rw-r--r--libavcodec/binkdsp.c8
-rw-r--r--libavcodec/bintext.c258
-rw-r--r--libavcodec/bintext.h37
-rw-r--r--libavcodec/bit_depth_template.c5
-rw-r--r--libavcodec/bitstream.c50
-rw-r--r--libavcodec/bitstream_filter.c8
-rw-r--r--libavcodec/bmp.c73
-rw-r--r--libavcodec/bmp.h12
-rw-r--r--libavcodec/bmp_parser.c91
-rw-r--r--libavcodec/bmpenc.c37
-rw-r--r--libavcodec/bmv.c21
-rw-r--r--libavcodec/brender_pix.c219
-rw-r--r--libavcodec/bytestream.h18
-rw-r--r--libavcodec/c93.c23
-rw-r--r--libavcodec/cabac.c164
-rw-r--r--libavcodec/cabac.h8
-rw-r--r--libavcodec/cabac_functions.h14
-rw-r--r--libavcodec/cavs.c12
-rw-r--r--libavcodec/cavs.h10
-rw-r--r--libavcodec/cavs_parser.c8
-rw-r--r--libavcodec/cavsdata.c8
-rw-r--r--libavcodec/cavsdec.c64
-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.h8
-rw-r--r--libavcodec/cdgraphics.c34
-rw-r--r--libavcodec/cdxl.c28
-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.c8
-rw-r--r--libavcodec/cinepak.c267
-rw-r--r--libavcodec/cljr.c70
-rw-r--r--libavcodec/cllc.c18
-rw-r--r--libavcodec/cngdec.c12
-rw-r--r--libavcodec/cngenc.c8
-rw-r--r--libavcodec/codec_desc.c419
-rw-r--r--libavcodec/cook.c60
-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.c20
-rw-r--r--libavcodec/dcadata.h42
-rw-r--r--libavcodec/dcadec.c677
-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/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.c585
-rw-r--r--libavcodec/dirac_dwt.h126
-rw-r--r--libavcodec/dirac_parser.c12
-rw-r--r--libavcodec/diracdec.c1938
-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.c99
-rw-r--r--libavcodec/dnxhdenc.h10
-rw-r--r--libavcodec/dpcm.c19
-rw-r--r--libavcodec/dpx.c181
-rw-r--r--libavcodec/dpxenc.c128
-rw-r--r--libavcodec/dsicinav.c66
-rw-r--r--libavcodec/dsputil.c238
-rw-r--r--libavcodec/dsputil.h19
-rw-r--r--libavcodec/dsputil_template.c16
-rw-r--r--libavcodec/dump_extradata_bsf.c8
-rw-r--r--libavcodec/dv.c44
-rw-r--r--libavcodec/dv_profile.c38
-rw-r--r--libavcodec/dv_profile.h6
-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.c195
-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.c47
-rw-r--r--libavcodec/dvdsub_parser.c8
-rw-r--r--libavcodec/dvdsubdec.c147
-rw-r--r--libavcodec/dvdsubenc.c393
-rw-r--r--libavcodec/dxa.c70
-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.c8
-rw-r--r--libavcodec/eacmv.c32
-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.c28
-rw-r--r--libavcodec/eatqi.c15
-rw-r--r--libavcodec/elbg.c13
-rw-r--r--libavcodec/elbg.h8
-rw-r--r--libavcodec/error_resilience.c201
-rw-r--r--libavcodec/error_resilience.h8
-rw-r--r--libavcodec/escape124.c18
-rw-r--r--libavcodec/escape130.c319
-rw-r--r--libavcodec/evrcdata.h1499
-rw-r--r--libavcodec/evrcdec.c917
-rw-r--r--libavcodec/exr.c813
-rw-r--r--libavcodec/faandct.h8
-rw-r--r--libavcodec/faanidct.c8
-rw-r--r--libavcodec/faanidct.h8
-rw-r--r--libavcodec/faxcompr.c31
-rw-r--r--libavcodec/faxcompr.h8
-rw-r--r--libavcodec/fft-fixed-test.c8
-rw-r--r--libavcodec/fft-internal.h8
-rw-r--r--libavcodec/fft-test.c28
-rw-r--r--libavcodec/fft.c9
-rw-r--r--libavcodec/fft.h9
-rw-r--r--libavcodec/fft_fixed.c8
-rw-r--r--libavcodec/fft_float.c8
-rw-r--r--libavcodec/ffv1.c153
-rw-r--r--libavcodec/ffv1.h56
-rw-r--r--libavcodec/ffv1dec.c498
-rw-r--r--libavcodec/ffv1enc.c432
-rw-r--r--libavcodec/ffwavesynth.c484
-rw-r--r--libavcodec/flac.c11
-rw-r--r--libavcodec/flac.h8
-rw-r--r--libavcodec/flac_parser.c29
-rw-r--r--libavcodec/flacdata.c10
-rw-r--r--libavcodec/flacdata.h10
-rw-r--r--libavcodec/flacdec.c99
-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.c33
-rw-r--r--libavcodec/flashsv2enc.c931
-rw-r--r--libavcodec/flashsvenc.c14
-rw-r--r--libavcodec/flicvideo.c134
-rw-r--r--libavcodec/flv.h8
-rw-r--r--libavcodec/flvdec.c15
-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.c214
-rw-r--r--libavcodec/frwu.c43
-rw-r--r--libavcodec/g722.c8
-rw-r--r--libavcodec/g722dec.c12
-rw-r--r--libavcodec/g722enc.c7
-rw-r--r--libavcodec/g723_1.c1298
-rw-r--r--libavcodec/g723_1_data.h171
-rw-r--r--libavcodec/g726.c16
-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.h34
-rw-r--r--libavcodec/gif.c264
-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.c5
-rw-r--r--libavcodec/gsmdec.c20
-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.c22
-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.c131
-rw-r--r--libavcodec/h264.c841
-rw-r--r--libavcodec/h264.h59
-rw-r--r--libavcodec/h264_cabac.c77
-rw-r--r--libavcodec/h264_cavlc.c129
-rw-r--r--libavcodec/h264_direct.c17
-rw-r--r--libavcodec/h264_loopfilter.c21
-rw-r--r--libavcodec/h264_mb_template.c25
-rw-r--r--libavcodec/h264_mc_template.c14
-rw-r--r--libavcodec/h264_mp4toannexb_bsf.c39
-rw-r--r--libavcodec/h264_mvpred.h19
-rw-r--r--libavcodec/h264_parser.c104
-rw-r--r--libavcodec/h264_ps.c144
-rw-r--r--libavcodec/h264_refs.c72
-rw-r--r--libavcodec/h264_sei.c83
-rw-r--r--libavcodec/h264addpx_template.c8
-rw-r--r--libavcodec/h264chroma.c8
-rw-r--r--libavcodec/h264chroma.h8
-rw-r--r--libavcodec/h264chroma_template.c22
-rw-r--r--libavcodec/h264data.h18
-rw-r--r--libavcodec/h264dsp.c26
-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/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.c29
-rw-r--r--libavcodec/huffman.h8
-rw-r--r--libavcodec/huffyuv.c13
-rw-r--r--libavcodec/huffyuv.h8
-rw-r--r--libavcodec/huffyuvdec.c105
-rw-r--r--libavcodec/huffyuvenc.c147
-rw-r--r--libavcodec/idcinvideo.c23
-rw-r--r--libavcodec/iff.c690
-rw-r--r--libavcodec/iirfilter.c15
-rw-r--r--libavcodec/iirfilter.h31
-rw-r--r--libavcodec/imc.c36
-rw-r--r--libavcodec/imcdata.h8
-rw-r--r--libavcodec/imgconvert.c319
-rw-r--r--libavcodec/imgconvert.h8
-rw-r--r--libavcodec/imx_dump_header_bsf.c8
-rw-r--r--libavcodec/indeo2.c13
-rw-r--r--libavcodec/indeo2data.h8
-rw-r--r--libavcodec/indeo3.c67
-rw-r--r--libavcodec/indeo3data.h8
-rw-r--r--libavcodec/indeo4.c65
-rw-r--r--libavcodec/indeo5.c54
-rw-r--r--libavcodec/indeo5data.h8
-rw-r--r--libavcodec/intelh263dec.c14
-rw-r--r--libavcodec/internal.h78
-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.c48
-rw-r--r--libavcodec/ituh263enc.c20
-rw-r--r--libavcodec/ivi_common.c73
-rw-r--r--libavcodec/ivi_common.h11
-rw-r--r--libavcodec/ivi_dsp.c84
-rw-r--r--libavcodec/ivi_dsp.h12
-rw-r--r--libavcodec/j2k.c391
-rw-r--r--libavcodec/j2k.h234
-rw-r--r--libavcodec/j2k_dwt.c386
-rw-r--r--libavcodec/j2k_dwt.h63
-rw-r--r--libavcodec/j2kdec.c1095
-rw-r--r--libavcodec/j2kenc.c1046
-rw-r--r--libavcodec/jacosub.h45
-rw-r--r--libavcodec/jacosubdec.c205
-rw-r--r--libavcodec/jpeg2000.c8
-rw-r--r--libavcodec/jpeg2000.h8
-rw-r--r--libavcodec/jpeg2000dec.c15
-rw-r--r--libavcodec/jpeg2000dwt.c8
-rw-r--r--libavcodec/jpeg2000dwt.h8
-rw-r--r--libavcodec/jpegls.c14
-rw-r--r--libavcodec/jpegls.h12
-rw-r--r--libavcodec/jpeglsdec.c58
-rw-r--r--libavcodec/jpeglsdec.h8
-rw-r--r--libavcodec/jpeglsenc.c25
-rw-r--r--libavcodec/jrevdct.c213
-rw-r--r--libavcodec/jvdec.c42
-rw-r--r--libavcodec/kbdwin.c12
-rw-r--r--libavcodec/kbdwin.h8
-rw-r--r--libavcodec/kgv1dec.c39
-rw-r--r--libavcodec/kmvc.c37
-rw-r--r--libavcodec/lagarith.c134
-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.c22
-rw-r--r--libavcodec/libaacplus.c143
-rw-r--r--libavcodec/libavcodec.v27
-rw-r--r--libavcodec/libcelt_dec.c140
-rw-r--r--libavcodec/libfaac.c13
-rw-r--r--libavcodec/libfdk-aacenc.c12
-rw-r--r--libavcodec/libgsm.c46
-rw-r--r--libavcodec/libilbc.c26
-rw-r--r--libavcodec/libmp3lame.c19
-rw-r--r--libavcodec/libopencore-amr.c31
-rw-r--r--libavcodec/libopenjpegdec.c148
-rw-r--r--libavcodec/libopenjpegenc.c305
-rw-r--r--libavcodec/libopus.c8
-rw-r--r--libavcodec/libopus.h8
-rw-r--r--libavcodec/libopusdec.c49
-rw-r--r--libavcodec/libopusenc.c29
-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.c30
-rw-r--r--libavcodec/libspeexenc.c13
-rw-r--r--libavcodec/libstagefright.cpp597
-rw-r--r--libavcodec/libtheoraenc.c79
-rw-r--r--libavcodec/libtwolame.c196
-rw-r--r--libavcodec/libutvideo.h61
-rw-r--r--libavcodec/libutvideodec.cpp199
-rw-r--r--libavcodec/libutvideoenc.cpp239
-rw-r--r--libavcodec/libvo-aacenc.c20
-rw-r--r--libavcodec/libvo-amrwbenc.c14
-rw-r--r--libavcodec/libvorbisdec.c199
-rw-r--r--libavcodec/libvorbisenc.c (renamed from libavcodec/libvorbis.c)98
-rw-r--r--libavcodec/libvpxdec.c8
-rw-r--r--libavcodec/libvpxenc.c163
-rw-r--r--libavcodec/libx264.c177
-rw-r--r--libavcodec/libxavs.c18
-rw-r--r--libavcodec/libxvid.c68
-rw-r--r--libavcodec/libxvid.h8
-rw-r--r--libavcodec/libxvid_rc.c58
-rw-r--r--libavcodec/ljpegenc.c35
-rw-r--r--libavcodec/loco.c91
-rw-r--r--libavcodec/lpc.c19
-rw-r--r--libavcodec/lpc.h11
-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.c10
-rw-r--r--libavcodec/mace.c14
-rw-r--r--libavcodec/mathops.h8
-rw-r--r--libavcodec/mathtables.c10
-rw-r--r--libavcodec/mdct.c8
-rw-r--r--libavcodec/mdct_fixed.c8
-rw-r--r--libavcodec/mdct_float.c8
-rw-r--r--libavcodec/mdec.c12
-rw-r--r--libavcodec/microdvddec.c377
-rw-r--r--libavcodec/mimic.c20
-rw-r--r--libavcodec/mips/Makefile21
-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_init_table.c67
-rw-r--r--libavcodec/mips/fft_mips.c534
-rw-r--r--libavcodec/mips/fft_table.h63
-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.c8
-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.c8
-rw-r--r--libavcodec/mjpegbdec.c16
-rw-r--r--libavcodec/mjpegdec.c701
-rw-r--r--libavcodec/mjpegdec.h13
-rw-r--r--libavcodec/mjpegenc.c140
-rw-r--r--libavcodec/mjpegenc.h10
-rw-r--r--libavcodec/mlp.c8
-rw-r--r--libavcodec/mlp.h8
-rw-r--r--libavcodec/mlp_parser.c51
-rw-r--r--libavcodec/mlp_parser.h12
-rw-r--r--libavcodec/mlpdec.c71
-rw-r--r--libavcodec/mlpdsp.c8
-rw-r--r--libavcodec/mlpdsp.h8
-rw-r--r--libavcodec/mmvideo.c27
-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.c44
-rw-r--r--libavcodec/motionpixels_tablegen.c8
-rw-r--r--libavcodec/motionpixels_tablegen.h10
-rw-r--r--libavcodec/movsub_bsf.c8
-rw-r--r--libavcodec/movtextdec.c116
-rw-r--r--libavcodec/movtextenc.c165
-rw-r--r--libavcodec/mp3_header_compress_bsf.c8
-rw-r--r--libavcodec/mp3_header_decompress_bsf.c8
-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.c16
-rw-r--r--libavcodec/mpeg12.h8
-rw-r--r--libavcodec/mpeg12data.c76
-rw-r--r--libavcodec/mpeg12data.h11
-rw-r--r--libavcodec/mpeg12dec.c365
-rw-r--r--libavcodec/mpeg12decdata.h8
-rw-r--r--libavcodec/mpeg12enc.c109
-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.c20
-rw-r--r--libavcodec/mpeg4video_parser.h8
-rw-r--r--libavcodec/mpeg4videodec.c235
-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.h13
-rw-r--r--libavcodec/mpegaudiodata.c18
-rw-r--r--libavcodec/mpegaudiodata.h8
-rw-r--r--libavcodec/mpegaudiodec.c82
-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.h3
-rw-r--r--libavcodec/mpegaudiodsp_data.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.c1144
-rw-r--r--libavcodec/mpegvideo.h61
-rw-r--r--libavcodec/mpegvideo_enc.c381
-rw-r--r--libavcodec/mpegvideo_motion.c29
-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.c26
-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.c19
-rw-r--r--libavcodec/msrle.c25
-rw-r--r--libavcodec/msrledec.c75
-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.c16
-rw-r--r--libavcodec/mss2dsp.c11
-rw-r--r--libavcodec/mss2dsp.h8
-rw-r--r--libavcodec/mss3.c14
-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.c13
-rw-r--r--libavcodec/nuv.c52
-rw-r--r--libavcodec/old_codec_ids.h397
-rw-r--r--libavcodec/options.c112
-rw-r--r--libavcodec/options_table.h81
-rw-r--r--libavcodec/os2threads.h162
-rw-r--r--libavcodec/paf.c451
-rw-r--r--libavcodec/paf.h28
-rw-r--r--libavcodec/pamenc.c80
-rw-r--r--libavcodec/parser.c39
-rw-r--r--libavcodec/parser.h8
-rw-r--r--libavcodec/pcm-mpeg.c19
-rw-r--r--libavcodec/pcm.c165
-rw-r--r--libavcodec/pcm_tablegen.c8
-rw-r--r--libavcodec/pcm_tablegen.h8
-rw-r--r--libavcodec/pcx.c110
-rw-r--r--libavcodec/pcxenc.c30
-rw-r--r--libavcodec/pgssubdec.c238
-rw-r--r--libavcodec/pictordec.c56
-rw-r--r--libavcodec/png.c17
-rw-r--r--libavcodec/png.h15
-rw-r--r--libavcodec/png_parser.c120
-rw-r--r--libavcodec/pngdec.c466
-rw-r--r--libavcodec/pngdsp.c8
-rw-r--r--libavcodec/pngdsp.h8
-rw-r--r--libavcodec/pngenc.c148
-rw-r--r--libavcodec/pnm.c60
-rw-r--r--libavcodec/pnm.h8
-rw-r--r--libavcodec/pnm_parser.c8
-rw-r--r--libavcodec/pnmdec.c70
-rw-r--r--libavcodec/pnmenc.c19
-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.c8
-rw-r--r--libavcodec/ppc/h264chroma_init.c8
-rw-r--r--libavcodec/ppc/h264chroma_template.c8
-rw-r--r--libavcodec/ppc/h264dsp.c8
-rw-r--r--libavcodec/ppc/h264qpel.c8
-rw-r--r--libavcodec/ppc/h264qpel_template.c8
-rw-r--r--libavcodec/ppc/hpeldsp_altivec.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.c8
-rw-r--r--libavcodec/proresdata.h8
-rw-r--r--libavcodec/proresdec.h54
-rw-r--r--libavcodec/proresdec2.c597
-rw-r--r--libavcodec/proresdec_lgpl.c (renamed from libavcodec/proresdec.c)6
-rw-r--r--libavcodec/proresdsp.c12
-rw-r--r--libavcodec/proresdsp.h13
-rw-r--r--libavcodec/proresenc_anatoliy.c626
-rw-r--r--libavcodec/proresenc_kostya.c (renamed from libavcodec/proresenc.c)18
-rw-r--r--libavcodec/psymodel.c22
-rw-r--r--libavcodec/psymodel.h10
-rw-r--r--libavcodec/pthread.c165
-rw-r--r--libavcodec/ptx.c20
-rw-r--r--libavcodec/put_bits.h19
-rw-r--r--libavcodec/qcelpdata.h12
-rw-r--r--libavcodec/qcelpdec.c14
-rw-r--r--libavcodec/qdm2.c128
-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.c63
-rw-r--r--libavcodec/qtrle.c25
-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.h12
-rw-r--r--libavcodec/ra144dec.c16
-rw-r--r--libavcodec/ra144enc.c20
-rw-r--r--libavcodec/ra288.c25
-rw-r--r--libavcodec/ra288.h8
-rw-r--r--libavcodec/ralf.c4
-rw-r--r--libavcodec/rangecoder.c15
-rw-r--r--libavcodec/rangecoder.h16
-rw-r--r--libavcodec/ratecontrol.c47
-rw-r--r--libavcodec/ratecontrol.h8
-rw-r--r--libavcodec/raw.c39
-rw-r--r--libavcodec/raw.h15
-rw-r--r--libavcodec/rawdec.c139
-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.c8
-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.c12
-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.c41
-rw-r--r--libavcodec/rv34.h8
-rw-r--r--libavcodec/rv34data.h8
-rw-r--r--libavcodec/rv34vlc.h8
-rw-r--r--libavcodec/rv40.c13
-rw-r--r--libavcodec/rv40data.h8
-rw-r--r--libavcodec/rv40dsp.c13
-rw-r--r--libavcodec/rv40vlc2.h8
-rw-r--r--libavcodec/s302m.c25
-rw-r--r--libavcodec/s3tc.c8
-rw-r--r--libavcodec/s3tc.h8
-rw-r--r--libavcodec/samidec.c158
-rw-r--r--libavcodec/sanm.c1305
-rw-r--r--libavcodec/sanm_data.h248
-rw-r--r--libavcodec/sbr.h38
-rw-r--r--libavcodec/sbrdsp.c3
-rw-r--r--libavcodec/sbrdsp.h1
-rw-r--r--libavcodec/sgi.h8
-rw-r--r--libavcodec/sgidec.c49
-rw-r--r--libavcodec/sgienc.c70
-rw-r--r--libavcodec/sgirledec.c149
-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.c79
-rw-r--r--libavcodec/simple_idct.c8
-rw-r--r--libavcodec/simple_idct.h8
-rw-r--r--libavcodec/simple_idct_template.c8
-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.c8
-rw-r--r--libavcodec/sipr16kdata.h8
-rw-r--r--libavcodec/siprdata.h8
-rw-r--r--libavcodec/smacker.c141
-rw-r--r--libavcodec/smc.c14
-rw-r--r--libavcodec/snow.c690
-rw-r--r--libavcodec/snow.h703
-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.c587
-rw-r--r--libavcodec/snowenc.c2112
-rw-r--r--libavcodec/sonic.c1001
-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.c88
-rw-r--r--libavcodec/srtenc.c324
-rw-r--r--libavcodec/subviewerdec.c83
-rw-r--r--libavcodec/sunrast.c63
-rw-r--r--libavcodec/sunrastenc.c21
-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.c58
-rw-r--r--libavcodec/svq1enc.c48
-rw-r--r--libavcodec/svq1enc_cb.h8
-rw-r--r--libavcodec/svq3.c77
-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.c37
-rw-r--r--libavcodec/tak.h11
-rw-r--r--libavcodec/tak_parser.c24
-rw-r--r--libavcodec/takdec.c316
-rw-r--r--libavcodec/targa.c162
-rw-r--r--libavcodec/targa.h15
-rw-r--r--libavcodec/targa_y216dec.c90
-rw-r--r--libavcodec/targaenc.c48
-rw-r--r--libavcodec/textdec.c188
-rw-r--r--libavcodec/thread.h18
-rw-r--r--libavcodec/tiertexseqv.c14
-rw-r--r--libavcodec/tiff.c780
-rw-r--r--libavcodec/tiff.h117
-rw-r--r--libavcodec/tiff_data.c1870
-rw-r--r--libavcodec/tiff_data.h92
-rw-r--r--libavcodec/tiffenc.c237
-rw-r--r--libavcodec/timecode.c150
-rw-r--r--libavcodec/timecode.h106
-rw-r--r--libavcodec/tmv.c16
-rw-r--r--libavcodec/truemotion1.c30
-rw-r--r--libavcodec/truemotion1data.h8
-rw-r--r--libavcodec/truemotion2.c76
-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.c197
-rw-r--r--libavcodec/twinvq.c17
-rw-r--r--libavcodec/twinvq_data.h8
-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.c1413
-rw-r--r--libavcodec/utvideo.c8
-rw-r--r--libavcodec/utvideo.h8
-rw-r--r--libavcodec/utvideodec.c14
-rw-r--r--libavcodec/utvideoenc.c20
-rw-r--r--libavcodec/v210dec.c121
-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.c8
-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_mpeg2.c8
-rw-r--r--libavcodec/vaapi_mpeg4.c10
-rw-r--r--libavcodec/vaapi_vc1.c12
-rw-r--r--libavcodec/vb.c18
-rw-r--r--libavcodec/vble.c107
-rw-r--r--libavcodec/vc1.c145
-rw-r--r--libavcodec/vc1.h25
-rw-r--r--libavcodec/vc1_parser.c8
-rw-r--r--libavcodec/vc1acdata.h8
-rw-r--r--libavcodec/vc1data.c22
-rw-r--r--libavcodec/vc1data.h26
-rw-r--r--libavcodec/vc1dec.c841
-rw-r--r--libavcodec/vc1dsp.c60
-rw-r--r--libavcodec/vc1dsp.h14
-rw-r--r--libavcodec/vcr1.c21
-rw-r--r--libavcodec/vda.h23
-rw-r--r--libavcodec/vda_h264.c44
-rw-r--r--libavcodec/vda_h264_dec.c271
-rw-r--r--libavcodec/vdpau.c10
-rw-r--r--libavcodec/vdpau.h28
-rw-r--r--libavcodec/vdpau_h264.c8
-rw-r--r--libavcodec/vdpau_internal.h8
-rw-r--r--libavcodec/vdpau_mpeg12.c8
-rw-r--r--libavcodec/vdpau_mpeg4.c8
-rw-r--r--libavcodec/vdpau_vc1.c10
-rw-r--r--libavcodec/version.h39
-rw-r--r--libavcodec/videodsp.c9
-rw-r--r--libavcodec/videodsp.h16
-rw-r--r--libavcodec/videodsp_template.c29
-rw-r--r--libavcodec/vima.c239
-rw-r--r--libavcodec/vmdav.c107
-rw-r--r--libavcodec/vmnc.c21
-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.c10
-rw-r--r--libavcodec/vorbisdec.c132
-rw-r--r--libavcodec/vorbisdsp.c8
-rw-r--r--libavcodec/vorbisdsp.h8
-rw-r--r--libavcodec/vorbisenc.c21
-rw-r--r--libavcodec/vp3.c84
-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.c286
-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.c53
-rw-r--r--libavcodec/vp6data.h8
-rw-r--r--libavcodec/vp6dsp.c8
-rw-r--r--libavcodec/vp8.c84
-rw-r--r--libavcodec/vp8.h10
-rw-r--r--libavcodec/vp8_parser.c8
-rw-r--r--libavcodec/vp8data.h8
-rw-r--r--libavcodec/vp8dsp.c8
-rw-r--r--libavcodec/vp8dsp.h8
-rw-r--r--libavcodec/vqavideo.c98
-rw-r--r--libavcodec/w32pthreads.h1
-rw-r--r--libavcodec/wavpack.c40
-rw-r--r--libavcodec/webvttdec.c100
-rw-r--r--libavcodec/wma.c14
-rw-r--r--libavcodec/wma.h10
-rw-r--r--libavcodec/wma_common.h8
-rw-r--r--libavcodec/wmadata.h10
-rw-r--r--libavcodec/wmadec.c40
-rw-r--r--libavcodec/wmaenc.c83
-rw-r--r--libavcodec/wmalosslessdec.c43
-rw-r--r--libavcodec/wmaprodata.h8
-rw-r--r--libavcodec/wmaprodec.c31
-rw-r--r--libavcodec/wmavoice.c32
-rw-r--r--libavcodec/wmavoice_data.h8
-rw-r--r--libavcodec/wmv2.c12
-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.c14
-rw-r--r--libavcodec/ws-snd1.c14
-rw-r--r--libavcodec/x86/Makefile11
-rw-r--r--libavcodec/x86/ac3dsp.asm8
-rw-r--r--libavcodec/x86/ac3dsp_init.c13
-rw-r--r--libavcodec/x86/cabac.h18
-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/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.c75
-rw-r--r--libavcodec/x86/dsputil_mmx.c166
-rw-r--r--libavcodec/x86/dsputil_qns_template.c10
-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.asm22
-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.asm4
-rw-r--r--libavcodec/x86/h264_deblock.asm20
-rw-r--r--libavcodec/x86/h264_deblock_10bit.asm8
-rw-r--r--libavcodec/x86/h264_i386.h8
-rw-r--r--libavcodec/x86/h264_idct.asm8
-rw-r--r--libavcodec/x86/h264_idct_10bit.asm16
-rw-r--r--libavcodec/x86/h264_intrapred.asm8
-rw-r--r--libavcodec/x86/h264_intrapred_10bit.asm26
-rw-r--r--libavcodec/x86/h264_intrapred_init.c8
-rw-r--r--libavcodec/x86/h264_qpel.c16
-rw-r--r--libavcodec/x86/h264_qpel_8bit.asm8
-rw-r--r--libavcodec/x86/h264_weight.asm15
-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.c10
-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.c9
-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.c20
-rw-r--r--libavcodec/x86/mpegvideoenc.c10
-rw-r--r--libavcodec/x86/mpegvideoenc_template.c21
-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/rv40dsp_init.c8
-rw-r--r--libavcodec/x86/sbrdsp.asm184
-rw-r--r--libavcodec/x86/sbrdsp_init.c19
-rw-r--r--libavcodec/x86/simple_idct.c9
-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.asm8
-rw-r--r--libavcodec/x86/videodsp_init.c26
-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/vp56dsp.asm8
-rw-r--r--libavcodec/x86/vp56dsp_init.c8
-rw-r--r--libavcodec/x86/vp8dsp.asm8
-rw-r--r--libavcodec/x86/vp8dsp_init.c8
-rw-r--r--libavcodec/x86/w64xmmtest.c7
-rw-r--r--libavcodec/xan.c58
-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.c39
-rw-r--r--libavcodec/xsubdec.c17
-rw-r--r--libavcodec/xsubenc.c10
-rw-r--r--libavcodec/xvmc.h8
-rw-r--r--libavcodec/xvmc_internal.h8
-rw-r--r--libavcodec/xwd.h8
-rw-r--r--libavcodec/xwddec.c19
-rw-r--r--libavcodec/xwdenc.c43
-rw-r--r--libavcodec/xxan.c92
-rw-r--r--libavcodec/y41pdec.c92
-rw-r--r--libavcodec/y41penc.c102
-rw-r--r--libavcodec/yop.c46
-rw-r--r--libavcodec/yuv4dec.c84
-rw-r--r--libavcodec/yuv4enc.c91
-rw-r--r--libavcodec/zerocodec.c6
-rw-r--r--libavcodec/zmbv.c120
-rw-r--r--libavcodec/zmbvenc.c12
-rw-r--r--libavdevice/Makefile17
-rw-r--r--libavdevice/alldevices.c16
-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.c35
-rw-r--r--libavdevice/iec61883.c497
-rw-r--r--libavdevice/jack_audio.c14
-rw-r--r--libavdevice/lavfi.c435
-rw-r--r--libavdevice/libcdio.c2
-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.c2
-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.c46
-rw-r--r--libavdevice/timefilter.h27
-rw-r--r--libavdevice/v4l.c363
-rw-r--r--libavdevice/v4l2.c681
-rw-r--r--libavdevice/version.h16
-rw-r--r--libavdevice/vfwcap.c51
-rw-r--r--libavdevice/x11grab.c73
-rw-r--r--libavfilter/Makefile174
-rw-r--r--libavfilter/af_aconvert.c189
-rw-r--r--libavfilter/af_afade.c300
-rw-r--r--libavfilter/af_aformat.c26
-rw-r--r--libavfilter/af_amerge.c350
-rw-r--r--libavfilter/af_amix.c23
-rw-r--r--libavfilter/af_anull.c15
-rw-r--r--libavfilter/af_apad.c156
-rw-r--r--libavfilter/af_aphaser.c358
-rw-r--r--libavfilter/af_aresample.c311
-rw-r--r--libavfilter/af_asetnsamples.c198
-rw-r--r--libavfilter/af_asetrate.c119
-rw-r--r--libavfilter/af_ashowinfo.c36
-rw-r--r--libavfilter/af_astats.c274
-rw-r--r--libavfilter/af_astreamsync.c240
-rw-r--r--libavfilter/af_asyncts.c22
-rw-r--r--libavfilter/af_atempo.c1196
-rw-r--r--libavfilter/af_biquads.c620
-rw-r--r--libavfilter/af_channelmap.c16
-rw-r--r--libavfilter/af_channelsplit.c15
-rw-r--r--libavfilter/af_earwax.c167
-rw-r--r--libavfilter/af_join.c11
-rw-r--r--libavfilter/af_pan.c423
-rw-r--r--libavfilter/af_silencedetect.c167
-rw-r--r--libavfilter/af_volume.c48
-rw-r--r--libavfilter/af_volume.h8
-rw-r--r--libavfilter/af_volumedetect.c161
-rw-r--r--libavfilter/all_channel_layouts.inc68
-rw-r--r--libavfilter/allfilters.c117
-rw-r--r--libavfilter/asink_anullsink.c10
-rw-r--r--libavfilter/asrc_abuffer.h91
-rw-r--r--libavfilter/asrc_aevalsrc.c255
-rw-r--r--libavfilter/asrc_anullsrc.c110
-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.c423
-rw-r--r--libavfilter/avf_showspectrum.c502
-rw-r--r--libavfilter/avf_showwaves.c256
-rw-r--r--libavfilter/avfilter.c578
-rw-r--r--libavfilter/avfilter.h410
-rw-r--r--libavfilter/avfiltergraph.c521
-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.c421
-rw-r--r--libavfilter/buffersink.h102
-rw-r--r--libavfilter/buffersrc.c187
-rw-r--r--libavfilter/buffersrc.h75
-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.c472
-rw-r--r--libavfilter/drawutils.h120
-rw-r--r--libavfilter/f_ebur128.c800
-rw-r--r--libavfilter/f_interleave.c259
-rw-r--r--libavfilter/f_perms.c178
-rw-r--r--libavfilter/f_select.c537
-rw-r--r--libavfilter/f_sendcmd.c578
-rw-r--r--libavfilter/f_settb.c (renamed from libavfilter/vf_settb.c)85
-rw-r--r--libavfilter/f_zmq.c276
-rw-r--r--libavfilter/fifo.c9
-rw-r--r--libavfilter/filtfmts.c72
-rw-r--r--libavfilter/formats.c333
-rw-r--r--libavfilter/formats.h65
-rw-r--r--libavfilter/gradfun.h16
-rw-r--r--libavfilter/graphdump.c164
-rw-r--r--libavfilter/graphparser.c122
-rw-r--r--libavfilter/internal.h159
-rw-r--r--libavfilter/lavfutils.c95
-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/help_mp.h2126
-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/mpbswap.h34
-rw-r--r--libavfilter/libmpcodecs/mpc_info.h43
-rw-r--r--libavfilter/libmpcodecs/pullup.c823
-rw-r--r--libavfilter/libmpcodecs/pullup.h102
-rw-r--r--libavfilter/libmpcodecs/vf.h169
-rw-r--r--libavfilter/libmpcodecs/vf_dint.c214
-rw-r--r--libavfilter/libmpcodecs/vf_eq.c240
-rw-r--r--libavfilter/libmpcodecs/vf_eq2.c519
-rw-r--r--libavfilter/libmpcodecs/vf_fil.c116
-rw-r--r--libavfilter/libmpcodecs/vf_fspp.c2118
-rw-r--r--libavfilter/libmpcodecs/vf_ilpack.c458
-rw-r--r--libavfilter/libmpcodecs/vf_mcdeint.c340
-rw-r--r--libavfilter/libmpcodecs/vf_perspective.c345
-rw-r--r--libavfilter/libmpcodecs/vf_phase.c303
-rw-r--r--libavfilter/libmpcodecs/vf_pp7.c491
-rw-r--r--libavfilter/libmpcodecs/vf_pullup.c316
-rw-r--r--libavfilter/libmpcodecs/vf_qp.c178
-rw-r--r--libavfilter/libmpcodecs/vf_sab.c324
-rw-r--r--libavfilter/libmpcodecs/vf_scale.h34
-rw-r--r--libavfilter/libmpcodecs/vf_softpulldown.c163
-rw-r--r--libavfilter/libmpcodecs/vf_spp.c621
-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/setpts.c127
-rw-r--r--libavfilter/split.c34
-rw-r--r--libavfilter/src_movie.c611
-rw-r--r--libavfilter/transform.c202
-rw-r--r--libavfilter/transform.h127
-rw-r--r--libavfilter/trim.c18
-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.h23
-rw-r--r--libavfilter/vf_alphamerge.c208
-rw-r--r--libavfilter/vf_aspect.c120
-rw-r--r--libavfilter/vf_bbox.c107
-rw-r--r--libavfilter/vf_blackdetect.c202
-rw-r--r--libavfilter/vf_blackframe.c35
-rw-r--r--libavfilter/vf_blend.c469
-rw-r--r--libavfilter/vf_boxblur.c90
-rw-r--r--libavfilter/vf_colorbalance.c213
-rw-r--r--libavfilter/vf_colorchannelmixer.c360
-rw-r--r--libavfilter/vf_colormatrix.c389
-rw-r--r--libavfilter/vf_copy.c10
-rw-r--r--libavfilter/vf_crop.c99
-rw-r--r--libavfilter/vf_cropdetect.c31
-rw-r--r--libavfilter/vf_curves.c552
-rw-r--r--libavfilter/vf_dctdnoiz.c431
-rw-r--r--libavfilter/vf_decimate.c397
-rw-r--r--libavfilter/vf_delogo.c66
-rw-r--r--libavfilter/vf_deshake.c575
-rw-r--r--libavfilter/vf_drawbox.c72
-rw-r--r--libavfilter/vf_drawgrid.c206
-rw-r--r--libavfilter/vf_drawtext.c1032
-rw-r--r--libavfilter/vf_edgedetect.c331
-rw-r--r--libavfilter/vf_extractplanes.c335
-rw-r--r--libavfilter/vf_fade.c227
-rw-r--r--libavfilter/vf_field.c118
-rw-r--r--libavfilter/vf_fieldmatch.c984
-rw-r--r--libavfilter/vf_fieldorder.c28
-rw-r--r--libavfilter/vf_format.c18
-rw-r--r--libavfilter/vf_fps.c51
-rw-r--r--libavfilter/vf_framestep.c100
-rw-r--r--libavfilter/vf_frei0r.c86
-rw-r--r--libavfilter/vf_geq.c271
-rw-r--r--libavfilter/vf_gradfun.c45
-rw-r--r--libavfilter/vf_hflip.c72
-rw-r--r--libavfilter/vf_histeq.c283
-rw-r--r--libavfilter/vf_histogram.c329
-rw-r--r--libavfilter/vf_hqdn3d.c35
-rw-r--r--libavfilter/vf_hqdn3d.h12
-rw-r--r--libavfilter/vf_hue.c377
-rw-r--r--libavfilter/vf_idet.c318
-rw-r--r--libavfilter/vf_il.c214
-rw-r--r--[-rwxr-xr-x]libavfilter/vf_interlace.c19
-rw-r--r--libavfilter/vf_kerndeint.c320
-rw-r--r--libavfilter/vf_libopencv.c27
-rw-r--r--libavfilter/vf_lut.c199
-rw-r--r--libavfilter/vf_mp.c854
-rw-r--r--libavfilter/vf_mpdecimate.c259
-rw-r--r--libavfilter/vf_noise.c475
-rw-r--r--libavfilter/vf_null.c13
-rw-r--r--libavfilter/vf_overlay.c739
-rw-r--r--libavfilter/vf_owdenoise.c342
-rw-r--r--libavfilter/vf_pad.c180
-rw-r--r--libavfilter/vf_pixdesctest.c12
-rw-r--r--libavfilter/vf_pp.c184
-rw-r--r--libavfilter/vf_removelogo.c582
-rw-r--r--libavfilter/vf_scale.c186
-rw-r--r--libavfilter/vf_select.c362
-rw-r--r--libavfilter/vf_separatefields.c111
-rw-r--r--libavfilter/vf_setfield.c95
-rw-r--r--libavfilter/vf_showinfo.c30
-rw-r--r--libavfilter/vf_smartblur.c306
-rw-r--r--libavfilter/vf_stereo3d.c623
-rw-r--r--libavfilter/vf_subtitles.c366
-rw-r--r--libavfilter/vf_super2xsai.c352
-rw-r--r--libavfilter/vf_swapuv.c111
-rw-r--r--libavfilter/vf_telecine.c284
-rw-r--r--libavfilter/vf_thumbnail.c240
-rw-r--r--libavfilter/vf_tile.c242
-rw-r--r--libavfilter/vf_tinterlace.c397
-rw-r--r--libavfilter/vf_transpose.c131
-rw-r--r--libavfilter/vf_unsharp.c203
-rw-r--r--libavfilter/vf_vflip.c14
-rw-r--r--libavfilter/vf_vidstabdetect.c218
-rw-r--r--libavfilter/vf_vidstabtransform.c292
-rw-r--r--libavfilter/vf_yadif.c138
-rw-r--r--libavfilter/video.c51
-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.c466
-rw-r--r--libavfilter/vsrc_mandelbrot.c432
-rw-r--r--libavfilter/vsrc_movie.c287
-rw-r--r--libavfilter/vsrc_mptestsrc.c365
-rw-r--r--libavfilter/vsrc_nullsrc.c136
-rw-r--r--libavfilter/vsrc_testsrc.c618
-rw-r--r--libavfilter/x86/Makefile2
-rw-r--r--libavfilter/x86/af_volume.asm10
-rw-r--r--libavfilter/x86/af_volume_init.c8
-rw-r--r--libavfilter/x86/vf_gradfun.c14
-rw-r--r--libavfilter/x86/vf_hqdn3d.asm8
-rw-r--r--libavfilter/x86/vf_hqdn3d_init.c10
-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.c32
-rw-r--r--libavformat/Makefile105
-rw-r--r--libavformat/a64.c9
-rw-r--r--libavformat/aacdec.c19
-rw-r--r--libavformat/ac3dec.c68
-rw-r--r--libavformat/act.c207
-rw-r--r--libavformat/adp.c91
-rw-r--r--libavformat/adtsenc.c9
-rw-r--r--libavformat/aea.c8
-rw-r--r--libavformat/afc.c81
-rw-r--r--libavformat/aiff.h11
-rw-r--r--libavformat/aiffdec.c89
-rw-r--r--libavformat/aiffenc.c198
-rw-r--r--libavformat/allformats.c78
-rw-r--r--libavformat/amr.c14
-rw-r--r--libavformat/anm.c10
-rw-r--r--libavformat/apc.c9
-rw-r--r--libavformat/ape.c29
-rw-r--r--libavformat/apetag.c12
-rw-r--r--libavformat/apetag.h17
-rw-r--r--libavformat/apetagenc.c65
-rw-r--r--libavformat/aqtitledec.c148
-rw-r--r--libavformat/asf.c9
-rw-r--r--libavformat/asf.h18
-rw-r--r--libavformat/asfcrypt.c8
-rw-r--r--libavformat/asfcrypt.h8
-rw-r--r--libavformat/asfdec.c207
-rw-r--r--libavformat/asfenc.c152
-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.c87
-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.h498
-rw-r--r--libavformat/avi.h8
-rw-r--r--libavformat/avidec.c378
-rw-r--r--libavformat/avienc.c68
-rw-r--r--libavformat/avio.c87
-rw-r--r--libavformat/avio.h74
-rw-r--r--libavformat/avio_internal.h12
-rw-r--r--libavformat/aviobuf.c127
-rw-r--r--libavformat/avisynth.c762
-rw-r--r--libavformat/avlanguage.c8
-rw-r--r--libavformat/avlanguage.h8
-rw-r--r--libavformat/avr.c100
-rw-r--r--libavformat/avs.c13
-rw-r--r--libavformat/bethsoftvid.c15
-rw-r--r--libavformat/bfi.c18
-rw-r--r--libavformat/bink.c10
-rw-r--r--libavformat/bintext.c395
-rw-r--r--libavformat/bit.c156
-rw-r--r--libavformat/bluray.c235
-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.c44
-rw-r--r--libavformat/cafenc.c279
-rw-r--r--libavformat/cavsvideodec.c8
-rw-r--r--libavformat/cdg.c15
-rw-r--r--libavformat/cdxl.c53
-rw-r--r--libavformat/concat.c8
-rw-r--r--libavformat/concatdec.c407
-rw-r--r--libavformat/crcenc.c9
-rw-r--r--libavformat/crypto.c6
-rw-r--r--libavformat/cutils.c29
-rw-r--r--libavformat/data_uri.c118
-rw-r--r--libavformat/daud.c13
-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.c8
-rw-r--r--libavformat/dtshddec.c139
-rw-r--r--libavformat/dv.c94
-rw-r--r--libavformat/dv.h10
-rw-r--r--libavformat/dvenc.c59
-rw-r--r--libavformat/dxa.c26
-rw-r--r--libavformat/eacdata.c17
-rw-r--r--libavformat/electronicarts.c85
-rw-r--r--libavformat/epafdec.c104
-rw-r--r--libavformat/ffm.h11
-rw-r--r--libavformat/ffmdec.c186
-rw-r--r--libavformat/ffmenc.c68
-rw-r--r--libavformat/ffmeta.h8
-rw-r--r--libavformat/ffmetadec.c12
-rw-r--r--libavformat/ffmetaenc.c8
-rw-r--r--libavformat/file.c42
-rw-r--r--libavformat/filmstripdec.c12
-rw-r--r--libavformat/filmstripenc.c10
-rw-r--r--libavformat/flacdec.c51
-rw-r--r--libavformat/flacenc.c20
-rw-r--r--libavformat/flacenc.h8
-rw-r--r--libavformat/flacenc_header.c8
-rw-r--r--libavformat/flic.c15
-rw-r--r--libavformat/flv.h32
-rw-r--r--libavformat/flvdec.c238
-rw-r--r--libavformat/flvenc.c115
-rw-r--r--libavformat/framecrcenc.c36
-rw-r--r--libavformat/frmdec.c110
-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.c324
-rw-r--r--libavformat/gopher.c8
-rw-r--r--libavformat/gsmdec.c1
-rw-r--r--libavformat/gxf.c69
-rw-r--r--libavformat/gxf.h8
-rw-r--r--libavformat/gxfenc.c118
-rw-r--r--libavformat/h261dec.c8
-rw-r--r--libavformat/h263dec.c8
-rw-r--r--libavformat/h264dec.c8
-rw-r--r--libavformat/hls.c132
-rw-r--r--libavformat/hlsenc.c35
-rw-r--r--libavformat/hlsproto.c12
-rw-r--r--libavformat/http.c217
-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.c170
-rw-r--r--libavformat/id3v2.h8
-rw-r--r--libavformat/id3v2enc.c51
-rw-r--r--libavformat/idcin.c20
-rw-r--r--libavformat/idroqdec.c13
-rw-r--r--libavformat/idroqenc.c8
-rw-r--r--libavformat/iff.c294
-rw-r--r--libavformat/ilbc.c9
-rw-r--r--libavformat/img2.c20
-rw-r--r--libavformat/img2dec.c235
-rw-r--r--libavformat/img2enc.c85
-rw-r--r--libavformat/ingenientdec.c21
-rw-r--r--libavformat/internal.h35
-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.c133
-rw-r--r--libavformat/isom.h23
-rw-r--r--libavformat/iss.c13
-rw-r--r--libavformat/iv8.c8
-rw-r--r--libavformat/ivfdec.c8
-rw-r--r--libavformat/ivfenc.c9
-rw-r--r--libavformat/jacosubdec.c270
-rw-r--r--libavformat/jacosubenc.c42
-rw-r--r--libavformat/jvdec.c26
-rw-r--r--libavformat/latmenc.c83
-rw-r--r--libavformat/libavformat.v33
-rw-r--r--libavformat/libmodplug.c368
-rw-r--r--libavformat/libnut.c322
-rw-r--r--libavformat/libquvi.c146
-rw-r--r--libavformat/librtmp.c8
-rw-r--r--libavformat/lmlm4.c14
-rw-r--r--libavformat/loasdec.c87
-rw-r--r--libavformat/lvfdec.c148
-rw-r--r--libavformat/lxfdec.c139
-rw-r--r--libavformat/m4vdec.c10
-rw-r--r--libavformat/matroska.c47
-rw-r--r--libavformat/matroska.h36
-rw-r--r--libavformat/matroskadec.c538
-rw-r--r--libavformat/matroskaenc.c230
-rw-r--r--libavformat/md5enc.c78
-rw-r--r--libavformat/md5proto.c8
-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.c64
-rw-r--r--libavformat/mmst.c10
-rw-r--r--libavformat/mov.c678
-rw-r--r--libavformat/mov_chan.c3
-rw-r--r--libavformat/movenc.c1000
-rw-r--r--libavformat/movenc.h28
-rw-r--r--libavformat/movenchint.c8
-rw-r--r--libavformat/mp3dec.c139
-rw-r--r--libavformat/mp3enc.c162
-rw-r--r--libavformat/mpc.c12
-rw-r--r--libavformat/mpc8.c29
-rw-r--r--libavformat/mpeg.c486
-rw-r--r--libavformat/mpeg.h8
-rw-r--r--libavformat/mpegenc.c40
-rw-r--r--libavformat/mpegts.c311
-rw-r--r--libavformat/mpegts.h8
-rw-r--r--libavformat/mpegtsenc.c188
-rw-r--r--libavformat/mpegvideodec.c34
-rw-r--r--libavformat/mpjpeg.c20
-rw-r--r--libavformat/mpl2dec.c146
-rw-r--r--libavformat/mpsubdec.c139
-rw-r--r--libavformat/msnwc_tcp.c14
-rw-r--r--libavformat/mtv.c20
-rw-r--r--libavformat/mux.c334
-rw-r--r--libavformat/mvdec.c441
-rw-r--r--libavformat/mvi.c14
-rw-r--r--libavformat/mxf.c41
-rw-r--r--libavformat/mxf.h25
-rw-r--r--libavformat/mxfdec.c623
-rw-r--r--libavformat/mxfenc.c436
-rw-r--r--libavformat/mxg.c22
-rw-r--r--libavformat/ncdec.c10
-rw-r--r--libavformat/network.c25
-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.c165
-rw-r--r--libavformat/nut.h12
-rw-r--r--libavformat/nutdec.c114
-rw-r--r--libavformat/nutenc.c280
-rw-r--r--libavformat/nuv.c96
-rw-r--r--libavformat/oggdec.c339
-rw-r--r--libavformat/oggdec.h6
-rw-r--r--libavformat/oggenc.c39
-rw-r--r--libavformat/oggparsecelt.c14
-rw-r--r--libavformat/oggparsedirac.c8
-rw-r--r--libavformat/oggparseflac.c8
-rw-r--r--libavformat/oggparseogm.c23
-rw-r--r--libavformat/oggparseopus.c135
-rw-r--r--libavformat/oggparseskeleton.c12
-rw-r--r--libavformat/oggparsespeex.c5
-rw-r--r--libavformat/oggparsetheora.c39
-rw-r--r--libavformat/oggparsevorbis.c50
-rw-r--r--libavformat/oma.c9
-rw-r--r--libavformat/omadec.c23
-rw-r--r--libavformat/omaenc.c5
-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.h17
-rw-r--r--libavformat/paf.c261
-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.c23
-rw-r--r--libavformat/rawdec.c54
-rw-r--r--libavformat/rawdec.h10
-rw-r--r--libavformat/rawenc.c55
-rw-r--r--libavformat/rawenc.h8
-rw-r--r--libavformat/rawvideodec.c40
-rw-r--r--libavformat/rdt.c10
-rw-r--r--libavformat/rdt.h8
-rw-r--r--libavformat/realtextdec.c153
-rw-r--r--libavformat/redspark.c167
-rw-r--r--libavformat/riff.c131
-rw-r--r--libavformat/riff.h17
-rw-r--r--libavformat/rl2.c13
-rw-r--r--libavformat/rm.c8
-rw-r--r--libavformat/rm.h10
-rw-r--r--libavformat/rmdec.c138
-rw-r--r--libavformat/rmenc.c19
-rw-r--r--libavformat/rmsipr.c8
-rw-r--r--libavformat/rmsipr.h8
-rw-r--r--libavformat/rpl.c18
-rw-r--r--libavformat/rsd.c170
-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.c8
-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_h264.c8
-rw-r--r--libavformat/rtpdec_ilbc.c8
-rw-r--r--libavformat/rtpdec_jpeg.c8
-rw-r--r--libavformat/rtpdec_latm.c8
-rw-r--r--libavformat/rtpdec_mpeg12.c8
-rw-r--r--libavformat/rtpdec_mpeg4.c10
-rw-r--r--libavformat/rtpdec_mpegts.c8
-rw-r--r--libavformat/rtpdec_qcelp.c8
-rw-r--r--libavformat/rtpdec_qdm2.c11
-rw-r--r--libavformat/rtpdec_qt.c8
-rw-r--r--libavformat/rtpdec_svq3.c8
-rw-r--r--libavformat/rtpdec_vp8.c8
-rw-r--r--libavformat/rtpdec_xiph.c13
-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.c11
-rw-r--r--libavformat/rtpenc_chain.h8
-rw-r--r--libavformat/rtpenc_h263.c12
-rw-r--r--libavformat/rtpenc_h264.c8
-rw-r--r--libavformat/rtpenc_jpeg.c8
-rw-r--r--libavformat/rtpenc_latm.c4
-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.c9
-rw-r--r--libavformat/rtsp.c20
-rw-r--r--libavformat/rtsp.h15
-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.c9
-rw-r--r--libavformat/sauce.c10
-rw-r--r--libavformat/sauce.h8
-rw-r--r--libavformat/sbgdec.c1513
-rw-r--r--libavformat/sctp.c8
-rw-r--r--libavformat/sdp.c24
-rw-r--r--libavformat/seek-test.c38
-rw-r--r--libavformat/seek.c8
-rw-r--r--libavformat/seek.h8
-rw-r--r--libavformat/segafilm.c17
-rw-r--r--libavformat/segment.c705
-rw-r--r--libavformat/sierravmd.c77
-rw-r--r--libavformat/siff.c59
-rw-r--r--libavformat/smacker.c32
-rw-r--r--libavformat/smjpeg.c8
-rw-r--r--libavformat/smjpeg.h8
-rw-r--r--libavformat/smjpegdec.c14
-rw-r--r--libavformat/smjpegenc.c11
-rw-r--r--libavformat/smoothstreamingenc.c22
-rw-r--r--libavformat/smush.c240
-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.c21
-rw-r--r--libavformat/srtdec.c145
-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.c231
-rw-r--r--libavformat/subtitles.h99
-rw-r--r--libavformat/subviewer1dec.c124
-rw-r--r--libavformat/subviewerdec.c194
-rw-r--r--libavformat/swf.c8
-rw-r--r--libavformat/swf.h102
-rw-r--r--libavformat/swfdec.c299
-rw-r--r--libavformat/swfenc.c27
-rw-r--r--libavformat/takdec.c12
-rw-r--r--libavformat/tcp.c62
-rw-r--r--libavformat/tedcaptionsdec.c365
-rw-r--r--libavformat/tee.c278
-rw-r--r--libavformat/thp.c21
-rw-r--r--libavformat/tiertexseq.c8
-rw-r--r--libavformat/tls.c73
-rw-r--r--libavformat/tmv.c10
-rw-r--r--libavformat/tta.c21
-rw-r--r--libavformat/tty.c43
-rw-r--r--libavformat/txd.c33
-rw-r--r--libavformat/udp.c257
-rw-r--r--libavformat/url-test.c8
-rw-r--r--libavformat/url.h12
-rw-r--r--libavformat/urldecode.c8
-rw-r--r--libavformat/urldecode.h8
-rw-r--r--libavformat/utils.c1668
-rw-r--r--libavformat/vc1test.c10
-rw-r--r--libavformat/vc1testenc.c12
-rw-r--r--libavformat/version.h42
-rw-r--r--libavformat/vivo.c313
-rw-r--r--libavformat/voc.c8
-rw-r--r--libavformat/voc.h8
-rw-r--r--libavformat/vocdec.c10
-rw-r--r--libavformat/vocenc.c22
-rw-r--r--libavformat/vorbiscomment.c8
-rw-r--r--libavformat/vorbiscomment.h8
-rw-r--r--libavformat/vplayerdec.c128
-rw-r--r--libavformat/vqf.c17
-rw-r--r--libavformat/w64.c50
-rw-r--r--libavformat/w64.h31
-rw-r--r--libavformat/wavdec.c305
-rw-r--r--libavformat/wavenc.c199
-rw-r--r--libavformat/wc3movie.c12
-rw-r--r--libavformat/webvttdec.c176
-rw-r--r--libavformat/westwood_aud.c10
-rw-r--r--libavformat/westwood_vqa.c24
-rw-r--r--libavformat/wtv.c1110
-rw-r--r--libavformat/wtv.h58
-rw-r--r--libavformat/wtvdec.c1084
-rw-r--r--libavformat/wtvenc.c809
-rw-r--r--libavformat/wv.c22
-rw-r--r--libavformat/wvenc.c143
-rw-r--r--libavformat/xa.c8
-rw-r--r--libavformat/xmv.c186
-rw-r--r--libavformat/xwma.c14
-rw-r--r--libavformat/yop.c22
-rw-r--r--libavformat/yuv4mpeg.c291
-rw-r--r--libavresample/arm/audio_convert_init.c8
-rw-r--r--libavresample/arm/audio_convert_neon.S8
-rw-r--r--libavresample/resample_template.c8
-rw-r--r--libavresample/utils.c6
-rw-r--r--libavresample/x86/audio_convert.asm34
-rw-r--r--libavresample/x86/audio_mix.asm8
-rw-r--r--libavresample/x86/dither.asm8
-rw-r--r--libavresample/x86/dither_init.c8
-rw-r--r--libavutil/Makefile28
-rw-r--r--libavutil/adler32.c46
-rw-r--r--libavutil/adler32.h8
-rw-r--r--libavutil/aes.c12
-rw-r--r--libavutil/aes.h12
-rw-r--r--libavutil/arm/asm.S8
-rw-r--r--libavutil/arm/bswap.h8
-rw-r--r--libavutil/arm/float_dsp_arm.h8
-rw-r--r--libavutil/arm/float_dsp_init_arm.c8
-rw-r--r--libavutil/arm/float_dsp_init_vfp.c8
-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.h42
-rw-r--r--libavutil/audio_fifo.h7
-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.c92
-rw-r--r--libavutil/avstring.h86
-rw-r--r--libavutil/avutil.h106
-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.c339
-rw-r--r--libavutil/bprint.h200
-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.c155
-rw-r--r--libavutil/channel_layout.h44
-rw-r--r--libavutil/colorspace.h8
-rw-r--r--libavutil/common.h68
-rw-r--r--libavutil/cpu.c84
-rw-r--r--libavutil/cpu.h42
-rw-r--r--libavutil/crc.c8
-rw-r--r--libavutil/crc.h8
-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.c224
-rw-r--r--libavutil/eval.h8
-rw-r--r--libavutil/fifo.c63
-rw-r--r--libavutil/fifo.h21
-rw-r--r--libavutil/file.c74
-rw-r--r--libavutil/file.h20
-rw-r--r--libavutil/float_dsp.c15
-rw-r--r--libavutil/float_dsp.h11
-rw-r--r--libavutil/frame.c111
-rw-r--r--libavutil/frame.h128
-rw-r--r--libavutil/hash.c154
-rw-r--r--libavutil/hash.h78
-rw-r--r--libavutil/hmac.c8
-rw-r--r--libavutil/hmac.h8
-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.h14
-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.c172
-rw-r--r--libavutil/log.h61
-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.c20
-rw-r--r--libavutil/md5.h12
-rw-r--r--libavutil/mem.c167
-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.c814
-rw-r--r--libavutil/opt.h253
-rw-r--r--libavutil/parseutils.c274
-rw-r--r--libavutil/parseutils.h62
-rw-r--r--libavutil/pca.c248
-rw-r--r--libavutil/pca.h35
-rw-r--r--libavutil/pixdesc.c561
-rw-r--r--libavutil/pixdesc.h37
-rw-r--r--libavutil/pixfmt.h106
-rw-r--r--libavutil/ppc/cpu.c10
-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.h8
-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.c36
-rw-r--r--libavutil/rational.h8
-rw-r--r--libavutil/rc4.c8
-rw-r--r--libavutil/rc4.h8
-rw-r--r--libavutil/samplefmt.c61
-rw-r--r--libavutil/samplefmt.h60
-rw-r--r--libavutil/sh4/bswap.h8
-rw-r--r--libavutil/sha.c14
-rw-r--r--libavutil/sha.h12
-rw-r--r--libavutil/softfloat.c72
-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.c16
-rw-r--r--libavutil/tree.h20
-rw-r--r--libavutil/utils.c64
-rw-r--r--libavutil/version.h67
-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/timer.h8
-rw-r--r--libavutil/x86/x86inc.asm45
-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.c99
-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.mak19
-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.c147
-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.c472
-rw-r--r--libswresample/rematrix_template.c100
-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.c932
-rw-r--r--libswresample/swresample.h311
-rw-r--r--libswresample/swresample_internal.h197
-rw-r--r--libswresample/version.h45
-rw-r--r--libswresample/x86/Makefile3
-rw-r--r--libswresample/x86/audio_convert.asm461
-rw-r--r--libswresample/x86/rematrix.asm251
-rw-r--r--libswresample/x86/resample_mmx.h70
-rw-r--r--libswresample/x86/swresample_x86.c195
-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.c622
-rw-r--r--libswscale/options.c17
-rw-r--r--libswscale/output.c912
-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.c511
-rw-r--r--libswscale/swscale.h32
-rw-r--r--libswscale/swscale_internal.h169
-rw-r--r--libswscale/swscale_unscaled.c790
-rw-r--r--libswscale/utils.c443
-rw-r--r--libswscale/version.h15
-rw-r--r--libswscale/x86/Makefile2
-rw-r--r--libswscale/x86/input.asm198
-rw-r--r--libswscale/x86/output.asm4
-rw-r--r--libswscale/x86/rgb2rgb.c12
-rw-r--r--libswscale/x86/rgb2rgb_template.c151
-rw-r--r--libswscale/x86/scale.asm4
-rw-r--r--libswscale/x86/swscale.c137
-rw-r--r--libswscale/x86/swscale_template.c130
-rw-r--r--libswscale/x86/yuv2rgb.c12
-rw-r--r--libswscale/x86/yuv2rgb_template.c35
-rw-r--r--libswscale/yuv2rgb.c124
-rw-r--r--presets/libvpx-1080p.ffpreset (renamed from presets/libvpx-1080p.avpreset)4
-rw-r--r--presets/libvpx-1080p50_60.ffpreset (renamed from presets/libvpx-1080p50_60.avpreset)4
-rw-r--r--presets/libvpx-360p.ffpreset (renamed from presets/libvpx-360p.avpreset)4
-rw-r--r--presets/libvpx-720p.ffpreset (renamed from presets/libvpx-720p.avpreset)4
-rw-r--r--presets/libvpx-720p50_60.ffpreset (renamed from presets/libvpx-720p50_60.avpreset)4
-rw-r--r--presets/libx264-baseline.avpreset1
-rw-r--r--presets/libx264-fast.avpreset1
-rw-r--r--presets/libx264-fast_firstpass.avpreset2
-rw-r--r--presets/libx264-faster.avpreset1
-rw-r--r--presets/libx264-faster_firstpass.avpreset2
-rw-r--r--presets/libx264-ipod320.ffpreset (renamed from presets/libx264-ipod320.avpreset)4
-rw-r--r--presets/libx264-ipod640.ffpreset (renamed from presets/libx264-ipod640.avpreset)4
-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/Makefile65
-rw-r--r--tests/audiogen.c8
-rw-r--r--tests/base64.c8
-rwxr-xr-xtests/copycooker.sh30
-rwxr-xr-xtests/fate-run.sh75
-rwxr-xr-xtests/fate-update.sh55
-rw-r--r--tests/fate-valgrind.supp31
-rwxr-xr-xtests/fate.sh3
-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.mak16
-rw-r--r--tests/fate/demux.mak87
-rw-r--r--tests/fate/ea.mak15
-rw-r--r--tests/fate/ffmpeg.mak48
-rw-r--r--tests/fate/ffprobe.mak33
-rw-r--r--tests/fate/filter-audio.mak22
-rw-r--r--tests/fate/filter-video.mak191
-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/image.mak37
-rw-r--r--tests/fate/libavutil.mak12
-rw-r--r--tests/fate/lossless-audio.mak26
-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.mak10
-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.mak74
-rw-r--r--tests/fate/video.mak161
-rw-r--r--tests/fate/voice.mak24
-rw-r--r--tests/fate/vpx.mak7
-rw-r--r--tests/fate/vqf.mak9
-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/adpcm-ms-mono2
-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-vid142
-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/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/cyberia-c932
-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/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_default613
-rw-r--r--tests/ref/fate/ffprobe_flat549
-rw-r--r--tests/ref/fate/ffprobe_ini626
-rw-r--r--tests/ref/fate/ffprobe_json598
-rw-r--r--tests/ref/fate/ffprobe_xml54
-rw-r--r--tests/ref/fate/film-cvid220
-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-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-pixdesc201
-rw-r--r--tests/ref/fate/filter-pixfmts-copy204
-rw-r--r--tests/ref/fate/filter-pixfmts-crop85
-rw-r--r--tests/ref/fate/filter-pixfmts-field115
-rw-r--r--tests/ref/fate/filter-pixfmts-hflip153
-rw-r--r--tests/ref/fate/filter-pixfmts-histeq6
-rw-r--r--tests/ref/fate/filter-pixfmts-il114
-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-null204
-rw-r--r--tests/ref/fate/filter-pixfmts-pad43
-rw-r--r--tests/ref/fate/filter-pixfmts-scale204
-rw-r--r--tests/ref/fate/filter-pixfmts-super2xsai14
-rw-r--r--tests/ref/fate/filter-pixfmts-swapuv61
-rw-r--r--tests/ref/fate/filter-pixfmts-tinterlace_merge10
-rw-r--r--tests/ref/fate/filter-pixfmts-tinterlace_pad10
-rw-r--r--tests/ref/fate/filter-pixfmts-vflip204
-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-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-container4
-rw-r--r--tests/ref/fate/h264-lossless20
-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/msvideo1-8bit1
-rw-r--r--tests/ref/fate/mtv2
-rw-r--r--tests/ref/fate/murmur31
-rw-r--r--tests/ref/fate/mxf-demux176
-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-rtjpeg20
-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/parseutils41
-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/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/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/smc240
-rw-r--r--tests/ref/fate/smjpeg425
-rw-r--r--tests/ref/fate/smjpeg-demux2
-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/sub2video94
-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/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/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/vp6f350
-rw-r--r--tests/ref/fate/vp8-alpha121
-rw-r--r--tests/ref/fate/vp8-sign-bias3
-rw-r--r--tests/ref/fate/vp8-size-change62
-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/aiff6
-rw-r--r--tests/ref/lavf/alaw6
-rw-r--r--tests/ref/lavf/asf6
-rw-r--r--tests/ref/lavf/ast3
-rw-r--r--tests/ref/lavf/au6
-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/mmf6
-rw-r--r--tests/ref/lavf/mov15
-rw-r--r--tests/ref/lavf/mpg10
-rw-r--r--tests/ref/lavf/mulaw6
-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/ogg6
-rw-r--r--tests/ref/lavf/pam17
-rw-r--r--tests/ref/lavf/pcx4
-rw-r--r--tests/ref/lavf/pgm2
-rw-r--r--tests/ref/lavf/pixfmt14
-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/rso6
-rw-r--r--tests/ref/lavf/sgi2
-rw-r--r--tests/ref/lavf/smjpeg3
-rw-r--r--tests/ref/lavf/sox6
-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/voc6
-rw-r--r--tests/ref/lavf/voc_s166
-rw-r--r--tests/ref/lavf/w643
-rw-r--r--tests/ref/lavf/wav6
-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-alaw2
-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-mulaw2
-rw-r--r--tests/ref/seek/lavf-mxf40
-rw-r--r--tests/ref/seek/lavf-mxf_d1028
-rw-r--r--tests/ref/seek/lavf-nut86
-rw-r--r--tests/ref/seek/lavf-ogg80
-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-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-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-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-j2k4
-rw-r--r--tests/ref/vsynth/vsynth1-jpegls4
-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-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-j2k4
-rw-r--r--tests/ref/vsynth/vsynth2-jpegls4
-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.c152
-rw-r--r--tests/tiny_ssim.c216
-rw-r--r--tests/utils.c10
-rw-r--r--tests/videogen.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/cws2fws.c14
-rw-r--r--tools/enum_options.c143
-rw-r--r--tools/ffadler.c87
-rw-r--r--tools/ffescape.c180
-rw-r--r--tools/ffeval.c138
-rw-r--r--tools/fourcc2pixfmt.c123
-rw-r--r--tools/graph2dot.c36
-rw-r--r--tools/ismindex.c14
-rwxr-xr-xtools/make_chlayout_test114
-rwxr-xr-xtools/missing_codec_desc37
-rwxr-xr-xtools/normalize.py33
-rwxr-xr-xtools/patcheck10
-rw-r--r--tools/pktdumper.c8
-rwxr-xr-xtools/plotframes164
-rw-r--r--tools/probetest.c33
-rw-r--r--tools/qt-faststart.c57
-rw-r--r--tools/seek_print.c107
-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-xversion.sh26
2926 files changed, 242988 insertions, 44393 deletions
diff --git a/.gitignore b/.gitignore
index 000f149..dd93958 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,21 @@
/tests/data/
/tests/rotozoom
/tests/tiny_psnr
+/tests/tiny_ssim
/tests/videogen
/tests/vsynth1/
/tools/aviocat
+/tools/ffbisect
+/tools/bisect.need
/tools/cws2fws
+/tools/fourcc2pixfmt
+/tools/ffescape
+/tools/ffeval
/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 97e7a32..c9b92d3 100644
--- a/Changelog
+++ b/Changelog
@@ -1,74 +1,150 @@
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>:
+- 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")
-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
@@ -81,44 +157,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
@@ -188,23 +363,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
@@ -214,44 +406,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
@@ -259,6 +434,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
@@ -270,6 +446,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
@@ -316,7 +493,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
@@ -329,11 +506,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:
@@ -574,6 +786,7 @@ version 0.5:
- Gopher client support
- MXF D-10 muxer
- generic metadata API
+- flash ScreenVideo2 encoder
version 0.4.9-pre1:
@@ -776,7 +989,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..e243960 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,27 +1,50 @@
-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_hue.c
+ - vf_kerndeint.c
+ - vf_mp.c
+ - vf_noise.c
+ - vf_owdenoise.c
+ - vf_pp.c
+ - vf_smartblur.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 +64,35 @@ 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:
+ - 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..372f2a8
--- /dev/null
+++ b/MAINTAINERS
@@ -0,0 +1,490 @@
+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 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 Mike Melanson
+website Robert Swain, Lou Logan
+build system (configure,Makefiles) Diego Biurrun, Mans Rullgard
+project server ĂrpĂ¡d Gereöffy, Michael Niedermayer, Reimar Döffinger
+mailinglists Michael Niedermayer, Baptiste Coudurier, Lou Logan
+presets Robert Swain
+metadata subsystem Aurelien Jacobs
+release management Michael Niedermayer
+
+
+libavutil
+=========
+
+External Interfaces:
+ libavutil/avutil.h Michael Niedermayer
+Internal Interfaces:
+ libavutil/common.h Michael Niedermayer
+
+Other:
+ intfloat* Michael Niedermayer
+ rational.c, rational.h Michael Niedermayer
+ mathematics.c, mathematics.h Michael Niedermayer
+ integer.c, integer.h Michael Niedermayer
+ bswap.h
+ opencl.c, opencl.h Wei Gao
+
+
+libavcodec
+==========
+
+Generic Parts:
+ External Interfaces:
+ avcodec.h Michael Niedermayer
+ utility code:
+ utils.c Michael Niedermayer
+ mem.c Michael Niedermayer
+ opt.c, opt.h Michael Niedermayer
+ arithmetic expression evaluator:
+ eval.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
+
+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
+ celp_filters.* Vitor Sessak
+ cdxl.c Paul B Mahol
+ 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
+ dxa.c Kostya Shishkov
+ dv.c Roman Shaposhnik
+ eacmv*, eaidct*, eat* Peter Ross
+ 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
+ h264* Loren Merritt, Michael Niedermayer
+ h261* Michael Niedermayer
+ h263* 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
+ libgsm.c Michel Bardiaux
+ libdirac* David Conrad
+ 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
+ libxavs.c Stefan Gehrer
+ libx264.c Mans Rullgard, Jason Garrett-Glaser
+ 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
+ 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
+ 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_enc.c Oded Shimon
+ vorbis_dec.c Denes Balatoni, David Conrad
+ 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
+ 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
+
+
+ iec61883.c Georg Lippitsch
+ libdc1394.c Roman Shaposhnik
+ v4l2.c Luca Abeni
+ vfwcap.c Ramiro Polla
+ dshow.c Roger Pack
+
+libavfilter
+===========
+
+Generic parts:
+ graphdump.c Nicolas George
+
+Filters:
+ af_amerge.c Nicolas George
+ af_astreamsync.c Nicolas George
+ af_atempo.c Pavel Koshevoy
+ af_pan.c Nicolas George
+ vf_drawgrid.c Andrey Utkin
+ 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
+ aiff.c Baptiste Coudurier
+ ape.c Kostya Shishkov
+ ass* Aurelien Jacobs
+ astdec.c Paul B Mahol
+ astenc.c James Almer
+ avi* Michael Niedermayer
+ avisynth.c AvxSynth Team
+ 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
+ ipmovie.c Mike Melanson
+ img2*.c Michael Niedermayer
+ 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
+ microdvd* Aurelien Jacobs
+ mgsts.c Paul B Mahol
+ mm.c Peter Ross
+ mov.c Michael Niedermayer, Baptiste Coudurier
+ movenc.c Michael Niedermayer, Baptiste Coudurier
+ 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
+ westwood.c Mike Melanson
+ wtv.c Peter Ross
+ wv.c Kostya Shishkov
+ wvenc.c Paul B Mahol
+
+Protocols:
+ bluray.c Petri Hintukainen
+ http.c Ronald S. Bultje
+ 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
+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
+========
+
+1.2 Michael Niedermayer
+1.1 Michael Niedermayer
+1.0 Michael Niedermayer
+
+If you want to maintain an older release, please contact us
+
+
+GnuPG Fingerprints of maintainers and contributors
+==================================================
+
+Anssi Hannula 1A92 FF42 2DD9 8D2E 8AF7 65A9 4278 C520 513D F3CB
+Anton Khirnov 6D0C 6625 56F8 65D1 E5F5 814B B50A 1241 C067 07AB
+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
+Gwenole Beauchesne 2E63 B3A6 3E44 37E2 017D 2704 53C7 6266 B153 99C4
+Jaikrishnan Menon 61A1 F09F 01C9 2D45 78E1 C862 25DC 8831 AF70 D368
+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 42ef8b0..7addffb 100644
--- a/Makefile
+++ b/Makefile
@@ -1,76 +1,33 @@
+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))
+BASENAMES = ffmpeg ffplay ffprobe ffserver
+ALLPROGS = $(BASENAMES:%=%$(PROGSSUF)$(EXESUF))
+ALLPROGS_G = $(BASENAMES:%=%$(PROGSSUF)_g$(EXESUF))
ALLMANPAGES = $(BASENAMES:%=%.1)
FFLIBS-$(CONFIG_AVDEVICE) += avdevice
@@ -78,11 +35,14 @@ 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
@@ -93,6 +53,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 +73,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 +93,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 +135,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 +151,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 +180,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..3d529fb 100644
--- a/RELEASE
+++ b/RELEASE
@@ -1 +1 @@
-10_alpha1
+1.1.git
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/avprobe.c b/avprobe.c
deleted file mode 100644
index c410cd2..0000000
--- a/avprobe.c
+++ /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 exit_program(void)
-{
- 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
-} ProbeElementType;
-
-typedef struct {
- const char *name;
- ProbeElementType type;
- int64_t index;
- int64_t nb_elems;
-} ProbeElement;
-
-typedef struct {
- ProbeElement *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);
-} OutputContext;
-
-static AVIOContext *probe_out = NULL;
-static OutputContext 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;
- ProbeElement *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(ProbeElement) * (octx.level + 1));
-
- if (!octx.prefix || !name) {
- fprintf(stderr, "Out of memory\n");
- exit(1);
- }
-
- if (octx.level) {
- ProbeElement *parent = octx.prefix + octx.level -1;
- if (parent->type == ARRAY)
- count = parent->nb_elems;
- parent->nb_elems++;
- }
-
- octx.prefix[octx.level++] = (ProbeElement){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(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);
-
- atexit(exit_program);
-
- 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(1);
- }
-
- probe_out = avio_alloc_context(buffer, AVP_BUFFSIZE, 1, NULL, NULL,
- probe_buf_write, NULL);
- if (!probe_out)
- exit(1);
-
- probe_header();
- ret = probe_file(input_filename);
- probe_footer();
- avio_flush(probe_out);
- avio_close(probe_out);
-
- avformat_network_deinit();
-
- return ret;
-}
diff --git a/cmdutils.c b/cmdutils.c
index 1ff964b..f5cddb1 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"
@@ -52,18 +56,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)
@@ -72,6 +85,8 @@ void uninit_opts(void)
sws_freeContext(sws_opts);
sws_opts = NULL;
#endif
+
+ av_dict_free(&swr_opts);
av_dict_free(&format_opts);
av_dict_free(&codec_opts);
av_dict_free(&resample_opts);
@@ -82,6 +97,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);
+}
+
double parse_number_or_die(const char *context, const char *numstr, int type,
double min, double max)
{
@@ -147,8 +176,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);
@@ -267,7 +298,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;
}
}
@@ -394,34 +426,74 @@ 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);
+ }
+ }
}
#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);
@@ -430,29 +502,54 @@ int opt_default(void *optctx, const char *opt, const char *arg)
if ((o = av_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 = av_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 = av_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 && av_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=av_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=av_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;
}
@@ -497,6 +594,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;
@@ -507,6 +605,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));
@@ -564,6 +663,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);
}
@@ -580,6 +680,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);
@@ -594,8 +695,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;
@@ -692,6 +797,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);
@@ -711,6 +823,129 @@ 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_log_set_level(FFMAX(av_log_get_level(), AV_LOG_VERBOSE));
+ 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(1);
+ }
+ av_max_alloc(max);
+ return 0;
+}
+
+int opt_cpuflags(void *optctx, const char *opt, const char *arg)
+{
+ int ret;
+ unsigned flags = av_get_cpu_flags();
+
+ if ((ret = av_parse_cpu_caps(&flags, arg)) < 0)
+ return ret;
+
+ av_force_cpu_flags(flags);
+ return 0;
+}
+
int opt_timelimit(void *optctx, const char *opt, const char *arg)
{
#if HAVE_SETRLIMIT
@@ -724,6 +959,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];
@@ -739,6 +994,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) { \
@@ -746,7 +1002,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, \
@@ -755,7 +1011,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", \
@@ -777,24 +1033,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;
@@ -802,12 +1074,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"
@@ -820,8 +1093,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"
@@ -835,8 +1109,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"
@@ -849,8 +1124,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"
@@ -864,9 +1140,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;
}
@@ -921,7 +1196,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) { \
@@ -983,7 +1258,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 '?';
}
}
@@ -999,6 +1276,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(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;
@@ -1013,7 +1320,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"
@@ -1025,9 +1333,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" : ".");
@@ -1056,30 +1366,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))
@@ -1088,6 +1405,7 @@ static void print_codecs(int encoder)
printf("\n");
}
}
+ av_free(codecs);
}
int show_decoders(void *optctx, const char *opt, const char *arg)
@@ -1131,11 +1449,36 @@ 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;
+ char descr[64], *descr_cur;
+ int i, j;
+ const AVFilterPad *pad;
- printf("Filters:\n");
+ printf("Filters:\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("%-16s %-10s %s\n", filter->name, descr, filter->description);
+ }
#endif
return 0;
}
@@ -1173,6 +1516,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;
@@ -1206,13 +1578,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);
}
}
@@ -1271,6 +1643,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;
@@ -1282,29 +1655,40 @@ 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);
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
@@ -1364,6 +1748,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");
@@ -1388,58 +1777,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");
}
@@ -1451,56 +1829,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,
@@ -1597,15 +1929,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 2372b3f..8a5dada 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;
/**
@@ -57,7 +67,7 @@ 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);
@@ -72,6 +82,16 @@ 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_cpuflags(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.
*/
@@ -105,7 +125,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);
@@ -136,7 +156,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.
@@ -174,13 +194,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);
@@ -223,7 +243,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;
/**
@@ -244,6 +264,7 @@ typedef struct OptionGroup {
AVDictionary *format_opts;
AVDictionary *resample_opts;
struct SwsContext *sws_opts;
+ AVDictionary *swr_opts;
} OptionGroup;
/**
@@ -370,30 +391,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);
@@ -412,28 +437,39 @@ 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.
*/
@@ -457,38 +493,14 @@ int read_yesno(void);
*/
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.
*
@@ -514,10 +526,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)
@@ -540,4 +549,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 619cd89..b57abaf 100644
--- a/cmdutils_common_opts.h
+++ b/cmdutils_common_opts.h
@@ -12,6 +12,13 @@
{ "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" },
+ { "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 a1d9d1e..dc4133a 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)
@@ -51,7 +125,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/avisynth/avisynth_c.h b/compat/avisynth/avisynth_c.h
new file mode 100644
index 0000000..84b6e13
--- /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/avxsynth_c.h b/compat/avisynth/avxsynth_c.h
new file mode 100644
index 0000000..7a81e21
--- /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
--- /dev/null
+++ b/compat/avisynth/windowsPorts/basicDataTypeConversions.h
@@ -0,0 +1,85 @@
+#ifndef __DATA_TYPE_CONVERSIONS_H__
+#define __DATA_TYPE_CONVERSIONS_H__
+
+#include <stdint.h>
+#include <wchar.h>
+
+#ifdef __cplusplus
+namespace avxsynth {
+#endif // __cplusplus
+
+typedef int64_t __int64;
+typedef int32_t __int32;
+#ifdef __cplusplus
+typedef bool BOOL;
+#else
+typedef uint32_t BOOL;
+#endif // __cplusplus
+typedef void* HMODULE;
+typedef void* LPVOID;
+typedef void* PVOID;
+typedef PVOID HANDLE;
+typedef HANDLE HWND;
+typedef HANDLE HINSTANCE;
+typedef void* HDC;
+typedef void* HBITMAP;
+typedef void* HICON;
+typedef void* HFONT;
+typedef void* HGDIOBJ;
+typedef void* HBRUSH;
+typedef void* HMMIO;
+typedef void* HACMSTREAM;
+typedef void* HACMDRIVER;
+typedef void* HIC;
+typedef void* HACMOBJ;
+typedef HACMSTREAM* LPHACMSTREAM;
+typedef void* HACMDRIVERID;
+typedef void* LPHACMDRIVER;
+typedef unsigned char BYTE;
+typedef BYTE* LPBYTE;
+typedef char TCHAR;
+typedef TCHAR* LPTSTR;
+typedef const TCHAR* LPCTSTR;
+typedef char* LPSTR;
+typedef LPSTR LPOLESTR;
+typedef const char* LPCSTR;
+typedef LPCSTR LPCOLESTR;
+typedef wchar_t WCHAR;
+typedef unsigned short WORD;
+typedef unsigned int UINT;
+typedef UINT MMRESULT;
+typedef uint32_t DWORD;
+typedef DWORD COLORREF;
+typedef DWORD FOURCC;
+typedef DWORD HRESULT;
+typedef DWORD* LPDWORD;
+typedef DWORD* DWORD_PTR;
+typedef int32_t LONG;
+typedef int32_t* LONG_PTR;
+typedef LONG_PTR LRESULT;
+typedef uint32_t ULONG;
+typedef uint32_t* ULONG_PTR;
+//typedef __int64_t intptr_t;
+typedef uint64_t _fsize_t;
+
+
+//
+// Structures
+//
+
+typedef struct _GUID {
+ DWORD Data1;
+ WORD Data2;
+ WORD Data3;
+ BYTE Data4[8];
+} GUID;
+
+typedef GUID REFIID;
+typedef GUID CLSID;
+typedef CLSID* LPCLSID;
+typedef GUID IID;
+
+#ifdef __cplusplus
+}; // namespace avxsynth
+#endif // __cplusplus
+#endif // __DATA_TYPE_CONVERSIONS_H__
diff --git a/compat/avisynth/windowsPorts/windows2linux.h b/compat/avisynth/windowsPorts/windows2linux.h
new file mode 100644
index 0000000..5476afe
--- /dev/null
+++ b/compat/avisynth/windowsPorts/windows2linux.h
@@ -0,0 +1,77 @@
+#ifndef __WINDOWS2LINUX_H__
+#define __WINDOWS2LINUX_H__
+
+/*
+ * LINUX SPECIFIC DEFINITIONS
+*/
+//
+// Data types conversions
+//
+#include <stdlib.h>
+#include <string.h>
+#include "basicDataTypeConversions.h"
+
+#ifdef __cplusplus
+namespace avxsynth {
+#endif // __cplusplus
+//
+// purposefully define the following MSFT definitions
+// to mean nothing (as they do not mean anything on Linux)
+//
+#define __stdcall
+#define __cdecl
+#define noreturn
+#define __declspec(x)
+#define STDAPI extern "C" HRESULT
+#define STDMETHODIMP HRESULT __stdcall
+#define STDMETHODIMP_(x) x __stdcall
+
+#define STDMETHOD(x) virtual HRESULT x
+#define STDMETHOD_(a, x) virtual a x
+
+#ifndef TRUE
+#define TRUE true
+#endif
+
+#ifndef FALSE
+#define FALSE false
+#endif
+
+#define S_OK (0x00000000)
+#define S_FALSE (0x00000001)
+#define E_NOINTERFACE (0X80004002)
+#define E_POINTER (0x80004003)
+#define E_FAIL (0x80004005)
+#define E_OUTOFMEMORY (0x8007000E)
+
+#define INVALID_HANDLE_VALUE ((HANDLE)((LONG_PTR)-1))
+#define FAILED(hr) ((hr) & 0x80000000)
+#define SUCCEEDED(hr) (!FAILED(hr))
+
+
+//
+// Functions
+//
+#define MAKEDWORD(a,b,c,d) ((a << 24) | (b << 16) | (c << 8) | (d))
+#define MAKEWORD(a,b) ((a << 8) | (b))
+
+#define lstrlen strlen
+#define lstrcpy strcpy
+#define lstrcmpi strcasecmp
+#define _stricmp strcasecmp
+#define InterlockedIncrement(x) __sync_fetch_and_add((x), 1)
+#define InterlockedDecrement(x) __sync_fetch_and_sub((x), 1)
+// Windows uses (new, old) ordering but GCC has (old, new)
+#define InterlockedCompareExchange(x,y,z) __sync_val_compare_and_swap(x,z,y)
+
+#define UInt32x32To64(a, b) ( (uint64_t) ( ((uint64_t)((uint32_t)(a))) * ((uint32_t)(b)) ) )
+#define Int64ShrlMod32(a, b) ( (uint64_t) ( (uint64_t)(a) >> (b) ) )
+#define Int32x32To64(a, b) ((__int64)(((__int64)((long)(a))) * ((long)(b))))
+
+#define MulDiv(nNumber, nNumerator, nDenominator) (int32_t) (((int64_t) (nNumber) * (int64_t) (nNumerator) + (int64_t) ((nDenominator)/2)) / (int64_t) (nDenominator))
+
+#ifdef __cplusplus
+}; // namespace avxsynth
+#endif // __cplusplus
+
+#endif // __WINDOWS2LINUX_H__
diff --git a/compat/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
--- /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/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/va_copy.h b/compat/va_copy.h
new file mode 100644
index 0000000..f894771
--- /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/configure b/configure
index 7bcaac3..015b1bf 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,9 +78,10 @@ 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]
+ --datadir=DIR install data files in DIR [PREFIX/share/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]
@@ -97,31 +98,41 @@ 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
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
@@ -130,10 +141,10 @@ Component options:
--disable-fft disable FFT code
Hardware accelerators:
- --enable-dxva2 enable DXVA2 code
+ --disable-dxva2 disable DXVA2 code [autodetect]
--enable-vaapi enable VAAPI code
--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
@@ -174,39 +185,63 @@ 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-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 encoding via libfdk-aac [no]
+ --enable-libflite enable flite (voice synthesis) support via libflite [no]
--enable-libfreetype enable libfreetype [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-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-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-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]
@@ -217,12 +252,14 @@ Advanced options (experts only):
--target-exec=CMD command to run executables on target
--target-path=DIR path to view of build directory on target
--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
@@ -231,12 +268,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)
@@ -274,14 +313,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
@@ -326,7 +378,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-user@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
@@ -614,6 +666,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;
}
}
}"
@@ -647,6 +705,10 @@ add_cflags(){
append CFLAGS $($cflags_filter "$@")
}
+add_cxxflags(){
+ append CXXFLAGS $($cflags_filter "$@")
+}
+
add_asflags(){
append ASFLAGS $($asflags_filter "$@")
}
@@ -697,6 +759,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
@@ -737,7 +806,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(){
@@ -746,9 +815,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
@@ -783,9 +854,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
}
@@ -811,7 +890,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
@@ -824,10 +903,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
}
@@ -844,7 +923,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(){
@@ -876,13 +974,21 @@ 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"
headers="$2"
funcs="$3"
shift 3
- $pkg_config --exists $pkg || return
+ $pkg_config --exists $pkg 2>/dev/null || return
pkg_cflags=$($pkg_config --cflags $pkg)
pkg_libs=$($pkg_config --libs $pkg)
check_func_headers "$headers" "$funcs" $pkg_cflags $pkg_libs "$@" &&
@@ -891,7 +997,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(){
@@ -908,9 +1014,10 @@ check_exec_crash(){
static void sighandler(int sig){
raise(SIGTERM);
}
-int foo(void){
+int func(void){
$code
}
+int (*func_ptr)(void) = func;
int main(void){
signal(SIGILL, sighandler);
signal(SIGFPE, sighandler);
@@ -918,7 +1025,7 @@ int main(void){
#ifdef SIGBUS
signal(SIGBUS, sighandler);
#endif
- foo();
+ return func_ptr();
}
EOF
}
@@ -950,7 +1057,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(){
@@ -969,6 +1076,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"
@@ -1034,26 +1149,46 @@ COMPONENT_LIST="
EXTERNAL_LIBRARY_LIST="
avisynth
bzlib
+ crystalhd
+ fontconfig
frei0r
gnutls
+ iconv
+ libaacplus
+ libass
+ libbluray
+ libcaca
libcdio
+ libcelt
libdc1394
libfaac
libfdk_aac
+ libflite
libfreetype
libgsm
+ libiec61883
libilbc
+ libmodplug
libmp3lame
+ libnut
libopencore_amrnb
libopencore_amrwb
libopencv
libopenjpeg
libopus
libpulse
+ libquvi
librtmp
libschroedinger
+ libshine
+ libsoxr
libspeex
+ libstagefright_h264
libtheora
+ libtwolame
+ libutvideo
+ libv4l2
+ libvidstab
libvo_aacenc
libvo_amrwbenc
libvorbis
@@ -1061,17 +1196,29 @@ EXTERNAL_LIBRARY_LIST="
libx264
libxavs
libxvid
+ libzmq
+ openal
+ opencl
openssl
x11grab
zlib
"
+DOCUMENT_LIST="
+ doc
+ htmlpages
+ manpages
+ podpages
+ txtpages
+"
+
HWACCEL_LIST="
dxva2
vaapi
vda
vdpau
"
+
LIBRARY_LIST="
avcodec
avdevice
@@ -1079,33 +1226,40 @@ 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_fork_abi
lsp
lzo
mdct
memalign_hack
+ memory_poisoning
network
nonfree
pic
@@ -1125,6 +1279,7 @@ CONFIG_LIST="
THREADS_LIST='
pthreads
w32threads
+ os2threads
'
ATOMICS_LIST='
@@ -1190,6 +1345,10 @@ ARCH_EXT_LIST="
altivec
ppc4xx
vis
+ mipsfpu
+ mips32r2
+ mipsdspr1
+ mipsdspr2
"
HAVE_LIST_CMDLINE='
@@ -1201,11 +1360,13 @@ HAVE_LIST_CMDLINE='
HAVE_LIST_PUB='
bigendian
fast_unaligned
+ incompatible_fork_abi
'
MATH_FUNCS="
atanf
atan2f
+ cbrt
cbrtf
cosf
exp2
@@ -1239,6 +1400,7 @@ HAVE_LIST="
$THREADS_LIST
$ATOMICS_LIST
$MATH_FUNCS
+ access
aligned_malloc
aligned_stack
alsa_asoundlib_h
@@ -1246,12 +1408,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
@@ -1284,6 +1449,7 @@ HAVE_LIST="
getrusage
getservbyport
gettimeofday
+ glob
gnu_as
gsm_h
i686
@@ -1292,6 +1458,7 @@ HAVE_LIST="
io_h
isatty
jack_port_get_latency_range
+ kbhit
ldbrx
libdc1394_1
libdc1394_2
@@ -1299,9 +1466,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
@@ -1312,9 +1481,15 @@ HAVE_LIST="
mprotect
msvcrt
nanosleep
+ openjpeg_1_5_openjpeg_h
+ PeekNamedPipe
+ perl
+ pod2man
poll_h
posix_memalign
+ pthread_cancel
rdtsc
+ rsync_contimeout
sched_getaffinity
sdl
SetConsoleTextAttribute
@@ -1325,14 +1500,13 @@ 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
@@ -1349,6 +1523,8 @@ HAVE_LIST="
sys_soundcard_h
sys_time_h
sys_videoio_h
+ termios_h
+ texi2html
threads
unistd_h
usleep
@@ -1366,6 +1542,7 @@ CONFIG_EXTRA="
ac3dsp
audio_frame_queue
dsputil
+ frame_thread_encoder
gcrypt
golomb
gplv3
@@ -1402,6 +1579,7 @@ CMDLINE_SELECT="
logging
lto
optimizations
+ stripping
"
PATHS_LIST='
@@ -1419,10 +1597,12 @@ CMDLINE_SET="
ar
arch
as
+ assert_level
build_suffix
cc
cpu
cross_prefix
+ cxx
dep_cc
extra_version
host_cc
@@ -1431,24 +1611,30 @@ 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
toolchain
+ valgrind
+ yasmexe
"
CMDLINE_APPEND="
extra_cflags
+ extra_cxxflags
host_cppflags
"
@@ -1465,6 +1651,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"
@@ -1511,12 +1702,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
@@ -1531,6 +1723,7 @@ als_decoder_select="dsputil"
amrnb_decoder_select="lsp"
amrwb_decoder_select="lsp"
amv_decoder_select="dsputil hpeldsp"
+amv_encoder_select="aandcttables"
ape_decoder_select="dsputil"
asv1_decoder_select="dsputil"
asv1_encoder_select="dsputil"
@@ -1548,6 +1741,7 @@ 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"
@@ -1556,8 +1750,9 @@ 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"
@@ -1566,11 +1761,13 @@ flac_decoder_select="golomb"
flac_encoder_select="dsputil golomb lpc"
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"
+g729_decoder_select="dsputil"
h261_decoder_select="error_resilience mpegvideo"
h261_encoder_select="aandcttables mpegvideoenc"
h263_decoder_select="error_resilience h263_parser mpegvideo"
@@ -1628,7 +1825,7 @@ mxpeg_decoder_select="dsputil hpeldsp"
nellymoser_decoder_select="mdct sinewin"
nellymoser_encoder_select="audio_frame_queue mdct sinewin"
nuv_decoder_select="dsputil lzo"
-png_decoder_select="dsputil zlib"
+png_decoder_select="zlib"
png_encoder_select="dsputil zlib"
prores_decoder_select="dsputil"
prores_encoder_select="dsputil"
@@ -1636,6 +1833,7 @@ 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"
@@ -1644,6 +1842,11 @@ 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"
+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"
svq1_decoder_select="hpeldsp"
svq1_encoder_select="aandcttables dsputil hpeldsp mpegvideoenc"
@@ -1654,7 +1857,7 @@ theora_decoder_select="vp3_decoder"
tiff_decoder_suggest="zlib"
tiff_encoder_suggest="zlib"
thp_decoder_select="dsputil hpeldsp"
-truehd_decoder_select="mlp_decoder"
+truehd_decoder_select="mlp_parser"
truemotion2_decoder_select="dsputil"
truespeech_decoder_select="dsputil"
tscc_decoder_select="zlib"
@@ -1691,6 +1894,7 @@ 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"
@@ -1701,10 +1905,13 @@ 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"
@@ -1717,18 +1924,22 @@ 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"
@@ -1737,6 +1948,7 @@ 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"
@@ -1749,6 +1961,8 @@ 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_encoder_deps="libfdk_aac"
@@ -1759,6 +1973,7 @@ 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"
@@ -1770,15 +1985,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"
@@ -1786,18 +2007,26 @@ libvpx_vp8_encoder_deps="libvpx"
libvpx_vp9_decoder_deps="libvpx"
libvpx_vp9_encoder_deps="libvpx"
libx264_encoder_deps="libx264"
+libx264rgb_encoder_deps="libx264"
libxavs_encoder_deps="libxavs"
libxvid_encoder_deps="libxvid"
+libutvideo_decoder_deps="libutvideo"
+libutvideo_encoder_deps="libutvideo"
# demuxers / muxers
ac3_demuxer_select="ac3_parser"
asf_stream_muxer_select="asf_muxer"
avisynth_demuxer_deps="avisynth"
dirac_demuxer_select="dirac_parser"
+dts_demuxer_select="dca_parser"
+dtshd_demuxer_select="dca_parser"
eac3_demuxer_select="ac3_parser"
+f4v_muxer_select="mov_muxer"
flac_demuxer_select="flac_parser"
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_suggest="bzlib lzo zlib"
mov_demuxer_suggest="zlib"
@@ -1821,28 +2050,40 @@ 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_deps="wav_demuxer"
+w64_muxer_deps="wav_muxer"
# indevs / outdevs
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 dv_demuxer"
fbdev_indev_deps="linux_fb_h"
-jack_indev_deps="jack_jack_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"
+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"
vfwcap_indev_deps="capCreateCaptureWindow vfwcap_defines"
vfwcap_indev_extralibs="-lavicap32"
-x11grab_indev_deps="x11grab XShmCreateImage"
+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"
@@ -1877,21 +2118,60 @@ tls_protocol_select="tcp_protocol"
udp_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 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"
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"
+hue_filter_deps="gpl"
interlace_filter_deps="gpl"
+kerndeint_filter_deps="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"
+noise_filter_deps="gpl"
resample_filter_deps="avresample"
ocv_filter_deps="libopencv"
+owdenoise_filter_deps="gpl"
+pan_filter_deps="swresample"
+pp_filter_deps="gpl postproc"
+removelogo_filter_deps="avcodec avformat swscale"
scale_filter_deps="swscale"
+smartblur_filter_deps="gpl swscale"
+showspectrum_filter_deps="avcodec rdft"
+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"
@@ -1899,20 +2179,26 @@ 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 swscale 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 ffm_muxer fork rtp_protocol rtsp_demuxer !shared"
-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 ffm_muxer fork 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
@@ -1921,7 +2207,7 @@ logfile="config.log"
# installation paths
prefix_default="/usr/local"
bindir_default='${prefix}/bin'
-datadir_default='${prefix}/share/avconv'
+datadir_default='${prefix}/share/ffmpeg'
incdir_default='${prefix}/include'
libdir_default='${prefix}/lib'
mandir_default='${prefix}/share/man'
@@ -1930,14 +2216,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"
-yasmexe="yasm"
+strip_default="strip"
+yasmexe_default="yasm"
nogas=":"
@@ -1950,12 +2239,16 @@ 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
@@ -1965,7 +2258,7 @@ enable dxva2 vdpau
# build settings
SHFLAGS='-shared -Wl,-soname,$$(@F)'
-AVSERVERLDFLAGS=-Wl,-E
+FFSERVERLDFLAGS=-Wl,-E
LIBPREF="lib"
LIBSUF=".a"
FULLNAME='$(NAME)$(BUILDSUF)'
@@ -1988,6 +2281,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'
@@ -2023,7 +2318,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(){
@@ -2143,7 +2438,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')
@@ -2164,6 +2461,8 @@ for opt do
;;
--help|-h) show_help
;;
+ --fatal-warnings) enable fatal_warnings
+ ;;
*)
optname="${opt%%=*}"
optname="${optname#--}"
@@ -2181,7 +2480,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
@@ -2193,12 +2492,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_default="${cross_prefix}${strip_default}"
sysinclude_default="${sysroot}/usr/include"
+test -n "$valgrind" && toolchain="valgrind-memcheck"
+
case "$toolchain" in
clang-asan)
cc_default="clang"
@@ -2211,8 +2514,8 @@ case "$toolchain" in
add_ldflags -fsanitize=thread -pie
;;
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"
@@ -2230,7 +2533,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
@@ -2273,6 +2576,7 @@ trap 'rm -f -- $TMPFILES' EXIT
tmpfile TMPASM .asm
tmpfile TMPC .c
+tmpfile TMPCPP .cpp
tmpfile TMPE $EXESUF
tmpfile TMPH .h
tmpfile TMPO .o
@@ -2323,6 +2627,7 @@ msvc_flags(){
-Wall) echo -W4 -wd4244 -wd4127 -wd4018 -wd4389 \
-wd4146 -wd4057 -wd4204 -wd4706 -wd4305 \
-wd4152 -wd4324 -we4013 -wd4100 -wd4214 \
+ -wd4554 \
-wd4996 -wd4273 ;;
-std=c99) ;;
-fno-math-errno) ;;
@@ -2368,7 +2673,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 ;;
@@ -2523,7 +2829,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
@@ -2548,6 +2854,7 @@ probe_cc(){
if [ $pfx = hostcc ]; then
append _cflags -Dsnprintf=_snprintf
fi
+ disable stripping
fi
eval ${pfx}_type=\$_type
@@ -2628,6 +2935,7 @@ else
fi
add_cflags $extra_cflags
+add_cxxflags $extra_cxxflags
add_asflags $extra_cflags
if test -n "$sysroot"; then
@@ -2668,7 +2976,7 @@ case "$arch" in
aarch64|arm64)
arch="aarch64"
;;
- arm*)
+ arm*|iPad*)
arch="arm"
;;
mips*|IP*)
@@ -2692,7 +3000,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
@@ -2802,6 +3110,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
@@ -2910,6 +3240,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>
@@ -2955,6 +3286,11 @@ case "$arch" in
spic=$shared
fi
;;
+ ppc)
+ check_cc <<EOF && subarch="ppc64"
+ int test[(int)sizeof(char*) - 7];
+EOF
+ ;;
esac
enable $subarch
@@ -2968,7 +3304,7 @@ case $target_os in
host_libs=
;;
sunos)
- AVSERVERLDFLAGS=""
+ FFSERVERLDFLAGS=""
SHFLAGS='-shared -Wl,-h,$$(@F)'
enabled x86 && SHFLAGS="-mimpure-text $SHFLAGS"
network_extralibs="-lsocket -lnsl"
@@ -2985,6 +3321,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
@@ -3001,17 +3338,19 @@ 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)'
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME).$(LIBMAJOR)$(SLIBSUF)'
- AVSERVERLDFLAGS=-Wl,-bind_at_load
+ FFSERVERLDFLAGS=-Wl,-bind_at_load
objformat="macho"
enabled x86_64 && objformat="macho64"
enabled_any pic shared ||
@@ -3036,14 +3375,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
disable pic
@@ -3102,12 +3448,13 @@ case $target_os in
ranlib="echo ignoring ranlib"
;;
os/2*)
+ strip="lxlite -CS"
ln_s="cp -f"
objformat="aout"
add_cppflags -D_GNU_SOURCE
add_ldflags -Zomf -Zbin-files -Zargs-wild -Zmap
SHFLAGS='$(SUBDIR)$(NAME).def -Zdll -Zomf'
- AVSERVERLDFLAGS=""
+ FFSERVERLDFLAGS=""
LIBSUF="_s.a"
SLIBPREF=""
SLIBSUF=".dll"
@@ -3123,6 +3470,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
@@ -3147,7 +3495,7 @@ case $target_os in
;;
osf1)
add_cppflags -D_OSF_SOURCE -D_POSIX_PII -D_REENTRANT
- AVSERVERLDFLAGS=
+ FFSERVERLDFLAGS=
;;
minix)
;;
@@ -3160,7 +3508,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)
@@ -3190,6 +3538,11 @@ 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"
+ fi
elif check_func_headers stdlib.h _get_doserrno; then
libc_type=msvcrt
add_compat strtod.o strtod=avpriv_strtod
@@ -3220,7 +3573,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
@@ -3242,15 +3595,22 @@ 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 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 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
@@ -3307,7 +3667,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
@@ -3316,7 +3679,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
@@ -3343,6 +3706,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
@@ -3431,8 +3802,9 @@ EOF
elf*) enabled debug && append YASMFLAGS $yasm_debug ;;
esac
- check_yasm "vextractf128 xmm0, ymm0, 0" && enable yasm ||
+ check_yasm "pextrd [eax], xmm0, 1" && enable yasm ||
die "yasm not found, use --disable-yasm for a crippled build"
+ check_yasm "vextractf128 xmm0, ymm0, 0" || disable avx_external
check_yasm "vfmaddps ymm0, ymm1, ymm2, ymm3" || disable fma4_external
check_yasm "CPU amdnop" && enabled i686 && enable cpunop
fi
@@ -3503,6 +3875,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
@@ -3522,8 +3896,6 @@ check_func ${malloc_prefix}posix_memalign && enable posix_memalign
check_func_headers malloc.h _aligned_malloc && enable aligned_malloc
check_func setrlimit
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()"
@@ -3532,7 +3904,10 @@ check_builtin MemoryBarrier windows.h "MemoryBarrier()"
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
@@ -3543,12 +3918,15 @@ 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_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
@@ -3556,12 +3934,14 @@ check_header sys/param.h
check_header sys/resource.h
check_header sys/select.h
check_header sys/time.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
@@ -3572,7 +3952,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
:
@@ -3597,11 +3977,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 machine_rw_barrier && enabled atomic_cas_ptr && enable atomics_suncc
enabled MemoryBarrier && enable atomics_win32
check_lib math.h sin -lm && LIBM="-lm"
+disabled crystalhd || check_lib libcrystalhd/libcrystalhd_if.h DtsCrystalHDVersion -lcrystalhd || disable crystalhd
enabled vaapi && require vaapi va/va.h vaInitialize -lva
atan2f_args=2
@@ -3613,42 +3998,83 @@ 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 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 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_frame
+enabled libsoxr && require libsoxr soxr.h soxr_create -lsoxr
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 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 openal && { { for al_libs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do
+ check_lib 'AL/al.h' alGetError "${al_libs}" && break; done } ||
+ die "ERROR: openal not found"; } &&
+ { check_cpp_condition "AL/al.h" "defined(AL_VERSION_1_1)" ||
+ die "ERROR: openal must be installed and version must be 1.1 or compatible"; }
+enabled opencl && { check_lib2 OpenCL/cl.h clEnqueueNDRangeKernel -Wl,-framework,OpenCL ||
+ check_lib2 CL/cl.h clEnqueueNDRangeKernel -lOpenCL ||
+ die "ERROR: opencl not found"; } &&
+ { check_cpp_condition "OpenCL/cl.h" "defined(CL_VERSION_1_2)" ||
+ check_cpp_condition "CL/cl.h" "defined(CL_VERSION_1_2)" ||
+ die "ERROR: opencl must be installed and version must be 1.2 or compatible"; }
enabled 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 ||
@@ -3668,17 +4094,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
@@ -3687,6 +4129,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; } ||
@@ -3697,12 +4141,19 @@ 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
@@ -3716,10 +4167,20 @@ require X11 X11/Xlib.h XOpenDisplay -lX11 &&
require Xext X11/extensions/XShm.h XShmCreateImage -lXext &&
require Xfixes X11/extensions/Xfixes.h XFixesGetCursorImage -lXfixes
+if ! disabled vaapi; then
+ check_lib va/va.h vaInitialize -lva && {
+ check_cpp_condition va/va_version.h "VA_CHECK_VERSION(0,32,0)" ||
+ warn "Please upgrade to VA-API >= 0.32 if you would like full VA-API support.";
+ } || disable vaapi
+fi
+
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
@@ -3732,17 +4193,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 &&
@@ -3795,17 +4256,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
@@ -3828,7 +4297,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
elif enabled llvm_gcc; then
check_cflags -mllvm -stack-alignment=16
@@ -3863,6 +4331,7 @@ case $target_os in
;;
esac
+enable frame_thread_encoder
enabled_any $THREADS_LIST && enable threads
enabled_any $ATOMICS_LIST && enable atomics_native
@@ -3873,9 +4342,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"
@@ -3883,6 +4385,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
@@ -3909,6 +4414,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}"
@@ -3919,15 +4431,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 "libshine enabled ${libshine-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
@@ -3956,15 +4476,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
@@ -3973,9 +4497,13 @@ BINDIR=\$(DESTDIR)$bindir
DATADIR=\$(DESTDIR)$datadir
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
@@ -3988,24 +4516,30 @@ AR=$ar
ARFLAGS=$arflags
AR_O=$ar_o
RANLIB=$ranlib
+CP=cp -p
LN_S=$ln_s
+STRIP=$strip
CPPFLAGS=$CPPFLAGS
CFLAGS=$CFLAGS
+CXXFLAGS=$CXXFLAGS
ASFLAGS=$ASFLAGS
AS_C=$AS_C
AS_O=$AS_O
CC_C=$CC_C
CC_E=$CC_E
CC_O=$CC_O
+CXX_C=$CXX_C
+CXX_O=$CXX_O
LD_O=$LD_O
LD_LIB=$LD_LIB
LD_PATH=$LD_PATH
DLLTOOL=$dlltool
LDFLAGS=$LDFLAGS
-LDFLAGS-avserver=$AVSERVERLDFLAGS
+LDFLAGS-ffserver=$FFSERVERLDFLAGS
SHFLAGS=$(echo $($ldflags_filter $SHFLAGS))
YASMFLAGS=$YASMFLAGS
BUILDSUF=$build_suffix
+PROGSSUF=$progs_suffix
FULLNAME=$FULLNAME
LIBPREF=$LIBPREF
LIBSUF=$LIBSUF
@@ -4015,6 +4549,7 @@ SLIBSUF=$SLIBSUF
EXESUF=$EXESUF
EXTRA_VERSION=$extra_version
CCDEP=$CCDEP
+CXXDEP=$CXXDEP
CCDEP_FLAGS=$CCDEP_FLAGS
ASDEP=$ASDEP
ASDEP_FLAGS=$ASDEP_FLAGS
@@ -4037,14 +4572,14 @@ HOSTCC_O=$HOSTCC_O
HOSTLD_O=$HOSTLD_O
TARGET_EXEC=$target_exec $target_exec_args
TARGET_PATH=$target_path
-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}
@@ -4055,7 +4590,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(){
@@ -4073,18 +4609,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
@@ -4095,13 +4636,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
@@ -4121,7 +4667,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
@@ -4134,7 +4683,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
@@ -4150,31 +4699,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} -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 fe1e1b3..9bb479d 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,172 @@ 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-05-13 - xxxxxxx - lavu 52.31.100 - mem.h
+ Add av_dynarray2_add().
+
+2013-05-12 - xxxxxxx - lavfi 3.65.100
+ Add AVFILTER_FLAG_SUPPORT_TIMELINE* filter flags.
+
+2013-04-19 - xxxxxxx - lavc 55.4.100
+ Add AV_CODEC_PROP_TEXT_SUB property for text based subtitles codec.
+
+2013-04-18 - xxxxxxx - 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 - xxxxxxx - lavu 25.26.100 - avutil.h,opt.h
+ Add av_int_list_length()
+ and av_opt_set_int_list().
+
+2013-03-30 - xxxxxxx - lavu 52.24.100 - samplefmt.h
+ Add av_samples_alloc_array_and_samples().
+
+2013-03-29 - xxxxxxx - lavf 55.1.100 - avformat.h
+ Add av_guess_frame_rate()
+
+2013-03-20 - xxxxxxx - lavu 52.22.100 - opt.h
+ Add AV_OPT_TYPE_DURATION value to AVOptionType enum.
+
+2013-03-17 - xxxxxx - lavu 52.20.100 - opt.h
+ Add AV_OPT_TYPE_VIDEO_RATE value to AVOptionType enum.
+
+2013-03-07 - xxxxxx - lavu 52.18.100 - avstring.h,bprint.h
+ Add av_escape() and av_bprint_escape() API.
+
+2013-02-24 - xxxxxx - 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 - 2ada584d - 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-xx - xxxxxxx - lavu 52.11.0 - pixdesc.h
Replace PIX_FMT_* flags with AV_PIX_FMT_FLAG_*.
@@ -99,41 +259,40 @@ lavd 54.0.0, lavfi 3.5.0
2013-01-15 - 8ee288d - lavu 52.5.0 - hmac.h
Add AVHMAC.
-2013-01-13 - 44e065d - lavc 54.36.0 - vdpau.h
+2013-01-13 - 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.
@@ -141,23 +300,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.
@@ -165,101 +324,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
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()
@@ -271,137 +419,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-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-03-20 - 3c90cc2 - lavfo 54.2.0
+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.10.100 / 54.8.0
+ f095391 / 6699d07 Add av_get_exact_bits_per_sample()
+ f095391 / 9524cf7 Add av_get_audio_frame_duration()
-2012-03-05 - lavc 54.8.0
- 6699d07 Add av_get_exact_bits_per_sample()
- 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:
@@ -409,220 +575,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.
+
+ 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-16 - 05e84c9, 25de595 - lavf 53.2.0 - avformat.h
+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
@@ -643,9 +953,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
@@ -678,11 +991,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.
@@ -712,6 +1025,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 3b2236c..faaa462 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
@@ -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 43e4632..9189c7b 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -1,65 +1,115 @@
-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
+
+MANPAGES = $(PROGS-yes:%=doc/%.1) $(PROGS-yes:%=doc/%-all.1) $(COMPONENTS-yes:%=doc/%.1) $(LIBRARIES-yes:%=doc/%.3)
+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-man:
+
+ifdef CONFIG_MANPAGES
install-progs-$(CONFIG_DOC): install-man
install-man: $(MANPAGES)
$(Q)mkdir -p "$(MANDIR)/man1"
$(INSTALL) -m 644 $(MANPAGES) "$(MANDIR)/man1"
+endif
uninstall: uninstall-man
uninstall-man:
$(RM) $(addprefix "$(MANDIR)/man1/",$(ALLMANPAGES))
-clean::
- $(RM) doc/*.html doc/*.pod doc/*.1 $(CLEANSUFFIXES:%=doc/%) doc/avoptions_*.texi
+clean:: docclean
+
+distclean:: docclean
+ $(RM) doc/config.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..2faf40d 100644
--- a/doc/RELEASE_NOTES
+++ b/doc/RELEASE_NOTES
@@ -1,101 +1,16 @@
Release Notes
=============
-* 9 "Plain Nine"
+* 1.2 "Magic" March, 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
--- /dev/null
+++ b/doc/authors.texi
@@ -0,0 +1,11 @@
+@chapter Authors
+
+The FFmpeg developers.
+
+For details about the authorship, see the Git history of the project
+(git://source.ffmpeg.org/ffmpeg), e.g. by typing the command
+@command{git log} in the FFmpeg source directory, or browsing the
+online repository at @url{http://source.ffmpeg.org}.
+
+Maintainers for the specific components are listed in the file
+@file{MAINTAINERS} in the source code tree.
diff --git a/doc/avplay.texi b/doc/avplay.texi
deleted file mode 100644
index b856f9b..0000000
--- a/doc/avplay.texi
+++ /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
+++ /dev/null
@@ -1,141 +0,0 @@
-\input texinfo @c -*- texinfo -*-
-
-@settitle avprobe Documentation
-@titlepage
-@center @titlefont{avprobe Documentation}
-@end titlepage
-
-@top
-
-@contents
-
-@chapter Synopsis
-
-The generic syntax is:
-
-@example
-@c man begin SYNOPSIS
-avprobe [options] [@file{input_file}]
-@c man end
-@end example
-
-@chapter Description
-@c man begin DESCRIPTION
-
-avprobe gathers information from multimedia streams and prints it in
-human- and machine-readable fashion.
-
-For example it can be used to check the format of the container used
-by a multimedia stream and the format and type of each media stream
-contained in it.
-
-If a filename is specified in input, avprobe will try to open and
-probe the file content. If the file cannot be opened or recognized as
-a multimedia file, a positive exit code is returned.
-
-avprobe may be employed both as a standalone application or in
-combination with a textual filter, which may perform more
-sophisticated processing, e.g. statistical processing or plotting.
-
-Options are used to list some of the formats supported by avprobe or
-for specifying which information to display, and for setting how
-avprobe will show it.
-
-avprobe output is designed to be easily parsable by any INI or JSON
-parsers.
-
-@c man end
-
-@chapter Options
-@c man begin OPTIONS
-
-@include avtools-common-opts.texi
-
-@section Main options
-
-@table @option
-
-@item -f @var{format}
-Force format to use.
-
-@item -of @var{formatter}
-Use a specific formatter to output the document. The following
-formatters are available
-@table @option
-@item ini
-
-@item json
-
-@item old
-Pseudo-INI format that used to be the only one available in old
-avprobe versions.
-@end table
-
-@item -unit
-Show the unit of the displayed values.
-
-@item -prefix
-Use SI prefixes for the displayed values.
-Unless the "-byte_binary_prefix" option is used all the prefixes
-are decimal.
-
-@item -byte_binary_prefix
-Force the use of binary prefixes for byte values.
-
-@item -sexagesimal
-Use sexagesimal format HH:MM:SS.MICROSECONDS for time values.
-
-@item -pretty
-Prettify the format of the displayed values, it corresponds to the
-options "-unit -prefix -byte_binary_prefix -sexagesimal".
-
-@item -show_format
-Show information about the container format of the input multimedia
-stream.
-
-All the container format information is printed within a section with
-name "FORMAT".
-
-@item -show_format_entry @var{name}
-Like @option{-show_format}, but only prints the specified entry of the
-container format information, rather than all. This option may be given more
-than once, then all specified entries will be shown.
-
-@item -show_packets
-Show information about each packet contained in the input multimedia
-stream.
-
-The information for each single packet is printed within a dedicated
-section with name "PACKET".
-
-@item -show_streams
-Show information about each media stream contained in the input
-multimedia stream.
-
-Each media stream information is printed within a dedicated section
-with name "STREAM".
-
-@end table
-@c man end
-
-@include demuxers.texi
-@include muxers.texi
-@include protocols.texi
-@include indevs.texi
-
-@ignore
-
-@setfilename avprobe
-@settitle avprobe media prober
-
-@c man begin SEEALSO
-avconv(1), avplay(1) and the Libav HTML documentation
-@c man end
-
-@c man begin AUTHORS
-The Libav developers
-@c man end
-
-@end ignore
-
-@bye
diff --git a/doc/avtools-common-opts.texi b/doc/avtools-common-opts.texi
index 4be5412..3892a4a 100644
--- a/doc/avtools-common-opts.texi
+++ b/doc/avtools-common-opts.texi
@@ -1,32 +1,33 @@
-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.
+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
-with "no" the option name, for example using "-nofoo" in the
-command line will set to false the boolean option with name "foo".
+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) does a given option belong to.
+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} option contains
-@code{a:1} stream specifer, which matches the second audio stream. Therefore it
+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 stream, the option is then applied to all
+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}
+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:
@@ -35,17 +36,21 @@ Possible forms of stream specifiers are:
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
+@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 matches stream number @var{stream_index} in
-program with id @var{program_id}. Otherwise matches all streams in this program.
+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 av* tools.
+These options are shared amongst the ff* tools.
@table @option
@@ -86,14 +91,6 @@ 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.
@@ -121,18 +118,39 @@ Show available pixel formats.
@item -sample_fmts
Show available sample formats.
-@item -loglevel @var{loglevel} | -v @var{loglevel}
+@item -layouts
+Show channel names and standard channel layouts.
+
+@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
@@ -141,8 +159,94 @@ 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.
+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
@@ -164,7 +268,7 @@ 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
+ffmpeg -i input.flac -id3v2_version 3 out.mp3
@end example
All codec AVOptions are obviously per-stream, so the chapter on stream
@@ -175,6 +279,3 @@ 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..2ee00c1 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,7 +10,7 @@ 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.
@@ -23,6 +23,20 @@ Below is a description of the currently available bitstream filters.
@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 +48,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 +71,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
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..2adadc0
--- /dev/null
+++ b/doc/codecs.texi
@@ -0,0 +1,1069 @@
+@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 sub_id @var{integer}
+Deprecated, currently unused.
+
+@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.
+
+@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
+@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 libmpeg2mmx
+
+@item mmi
+
+@item arm
+
+@item altivec
+
+@item sh4
+
+@item simplearm
+
+@item simplearmv5te
+
+@item simplearmv6
+
+@item simpleneon
+
+@item simplealpha
+
+@item h264
+
+@item vp3
+
+@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 inter_threshold @var{integer} (@emph{encoding,video})
+
+@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 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 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.
+@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..2d812a2
--- /dev/null
+++ b/doc/decoders.texi
@@ -0,0 +1,89 @@
+@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.
+
+@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
+
+@c man end SUBTILES DECODERS
diff --git a/doc/default.css b/doc/default.css
new file mode 100644
index 0000000..77a3514
--- /dev/null
+++ b/doc/default.css
@@ -0,0 +1,149 @@
+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, h2, h3 {
+ padding-left: 0.4em;
+ border-radius: 4px;
+ padding-bottom: 0.2em;
+ padding-top: 0.2em;
+ 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: 0.9em;
+ background-color: #ABE3AB;
+}
+
+h3 {
+ color: #313131;
+ font-size: 0.8em;
+ margin-bottom: -8px;
+ background-color: #BBF3BB;
+}
+
+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 b78cf68..c75e1ab 100644
--- a/doc/demuxers.texi
+++ b/doc/demuxers.texi
@@ -1,30 +1,150 @@
@chapter Demuxers
@c man begin DEMUXERS
-Demuxers are configured elements in Libav which allow to read the
+Demuxers are configured elements in FFmpeg which allow to 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".
+
+@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 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.
-The pattern may contain the string "%d" or "%0@var{N}d", which
+This demuxer accepts the following options:
+@table @option
+@item framerate
+Set the frame rate for the video stream. It defaults to 25.
+@item loop
+If set to 1, loop over the input. Default value is 0.
+@item pattern_type
+Select the pattern type used to interpret the provided filename.
+
+@var{pattern_type} accepts one of the following values.
+@table @option
+@item sequence
+Select a sequence pattern type, used to specify a sequence of files
+indexed by sequential numbers.
+
+A sequence pattern may contain the string "%d" or "%0@var{N}d", which
specifies the position of the characters representing a sequential
number in each filename matched by the pattern. If the form
"%d0@var{N}d" is used, the string representing the number in each
@@ -32,13 +152,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,46 +164,160 @@ 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".
-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:
+This pattern type is deprecated in favor of @var{glob} and
+@var{sequence}.
+@end table
+
+Default value is @var{glob_sequence}.
+@item pixel_format
+Set the pixel format of the images to read. If not specified the pixel
+format is guessed from the first image file in the sequence.
+@item start_number
+Set the index of the file matched by the image file pattern to start
+to read from. Default value is 0.
+@item start_number_range
+Set the index interval range to check when looking for the first image
+file in the sequence, starting from @var{start_number}. Default value
+is 5.
+@item 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 -i 'img-%03d.jpeg' -r 10 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 -start_number 100 -i 'img-%03d.jpeg' -r 10 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 -pattern_type glob -i "*.png" -r 10 out.mkv
@end example
+@end itemize
+
+@section rawvideo
+
+Raw video demuxer.
+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.
+
+This demuxer accepts the following options:
@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 framerate
+Set input video frame rate. Default value is 25.
+
+@item pixel_format
+Set the input video pixel format. Default value is @code{yuv420p}.
+
+@item video_size
+Set the input video size. This value must be specified explicitly.
@end table
-@section applehttp
+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
-Apple HTTP Live Streaming demuxer.
+@section sbg
-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".
+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 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
+
+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 INPUT DEVICES
+@c man end DEMUXERS
diff --git a/doc/developer.texi b/doc/developer.texi
index c3d0f20..90885ee 100644
--- a/doc/developer.texi
+++ b/doc/developer.texi
@@ -14,78 +14,47 @@
@section API
@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.
+decoding). Look at @file{doc/examples/decoding_encoding.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.
+demux code for several formats). Look at @file{ffplay.c} to use it in a
+player. See @file{doc/examples/muxing.c} to use it to generate audio or video
+streams.
@end itemize
-@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.
+@section Integrating libavcodec or libavformat in your program
+
+You can integrate all the source code of the libraries to link them
+statically to avoid any version problem. All you need is to provide a
+'config.mak' and a 'config.h' in the parent directory. See the defines
+generated by ./configure to understand what is needed.
+
+You can use libavcodec or libavformat in your commercial program, but
+@emph{any patch you make must be published}. The best way to proceed is
+to send your patches to the FFmpeg mailing list.
+
+@section Contributing
+
+There are 3 ways by which code gets into ffmpeg.
+@itemize @bullet
+@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
+
+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.
@anchor{Coding Rules}
@section Coding Rules
@subsection Code formatting conventions
-The code is written in K&R C style. That means the following:
-@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
-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.
-@item
-In case of a single-statement if, no curly braces are required:
-@example
-if (!pic || !picref)
- goto fail;
-@end example
-@item
-Do not put spaces immediately inside parentheses. @samp{if (ret)} is
-a valid style; @samp{if ( ret )} is not.
-@end itemize
There are the following guidelines regarding the indentation in files:
@itemize @bullet
@@ -101,7 +70,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
@@ -146,7 +115,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
@item
@@ -180,8 +149,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:
@itemize @bullet
@@ -199,8 +168,13 @@ For variables and functions visible outside of file scope, used internally
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.
@@ -222,10 +196,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
@@ -242,7 +216,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)
@@ -251,7 +225,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
@@ -268,16 +242,12 @@ For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}:
an "or any later version" clause is also acceptable, but LGPL is
preferred.
@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
a @samp{topic: short description} as a header, separated by a newline
@@ -285,21 +255,11 @@ For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}:
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
pieces. Also do not forget that if part B depends on part A, but A does not
@@ -307,37 +267,75 @@ For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}:
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.
-@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.
+ Also if you have doubts about splitting or not splitting, do not hesitate to
+ ask/discuss it on the developer mailing list.
+@item
+ Do not change behavior of the programs (renaming options etc) or public
+ API or ABI without first discussing it on the ffmpeg-devel mailing list.
+ Do not remove functionality from the code. Just improve!
+
+ Note: Redundant code can be removed.
+@item
+ 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
@@ -346,14 +344,16 @@ For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}:
(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.
@@ -361,35 +361,37 @@ For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}:
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
@@ -398,8 +400,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.
@@ -427,8 +429,8 @@ send a reminder by email. Your patch should eventually be dealt with.
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
@file{doc/general.texi}?
@@ -450,13 +452,20 @@ send a reminder by email. Your patch should eventually be dealt with.
@enumerate
@item
- Does @code{make check} pass with the patch applied?
+ Does @code{make fate} pass with the patch applied?
+@item
+ Was the patch generated with git format-patch or send-email?
+@item
+ Did you sign off your patch? (git commit -s)
+ See @url{http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob_plain;f=Documentation/SubmittingPatches} for the meaning
+ of sign off.
@item
- Is the patch against latest Libav git master branch?
+ Did you provide a clear git commit log message?
@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.)
+ 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
achieved with a smaller patch and/or simpler final code?
@@ -488,7 +497,7 @@ send a reminder by email. Your patch should eventually be dealt with.
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?
@item
@@ -501,7 +510,7 @@ send a reminder by email. Your patch should eventually be dealt with.
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
long as doing so does not break API/ABI compatibility.
@@ -509,16 +518,21 @@ send a reminder by email. Your patch should eventually be dealt with.
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,
@@ -532,27 +546,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 make sure that it does not break anything.
+Before submitting a patch (or committing to the repository), you should at least
+test that you did not break anything.
-If the code changed has already a test present in FATE you should run it,
-otherwise it is advised to add it.
+Running 'make fate' accomplishes this, please see @url{fate.html} for details.
-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.
+[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].
+
+@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:
@@ -563,7 +593,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.
@item
@@ -589,11 +619,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:
@@ -607,7 +637,7 @@ There are two kinds of releases:
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!
@@ -615,7 +645,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
@@ -628,7 +658,7 @@ inclusion into a point release:
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://ffmpeg.org/trac/ffmpeg}.
@item
Improves the included documentation.
@item
@@ -638,11 +668,6 @@ inclusion into a point release:
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
@@ -653,35 +678,25 @@ The release process involves the following steps:
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://ffmpeg.org/trac/ffmpeg/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
Publish the news entry.
diff --git a/doc/devices.texi b/doc/devices.texi
new file mode 100644
index 0000000..8f8b22a
--- /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 8db1481..79a13ee 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
@@ -369,7 +369,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
@@ -417,16 +417,182 @@ Selected by Encoder (default)
@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
+Requires the presence of the libx264 headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libx264}.
+
x264 supports an impressive number of features, including 8x8 and 4x4 adaptive
spatial transform, adaptive B-frame placement, CAVLC/CABAC entropy coding,
interlacing (MBAFF), lossless mode, psy optimizations for detail retention
(adaptive quantization, psy-RD, psy-trellis).
-The Libav wrapper provides a mapping for most of them using global options
+The FFmpeg 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.
@@ -434,11 +600,11 @@ a list of key=value tuples as accepted by x264_param_parse.
@subsection Option Mapping
The following options are supported by the x264 wrapper, the x264-equivalent
-options follow the Libav ones.
+options follow the FFmpeg ones.
@multitable @columnfractions .2 .2
@item b @tab bitrate
-Libav @code{b} option is expressed in bits/s, x264 @code{bitrate} in kilobits/s.
+FFmpeg @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
@@ -584,6 +750,23 @@ Possible values:
@item cbr
@end table
+
+@item x264opts @var{options}
+Allow to set any x264 option, see @code{x264 --fullhelp} for a list.
+
+@var{options} is a list of @var{key}=@var{value} couples separated by
+":". In @var{filter} and @var{psy-rd} options that use ":" as a separator
+themselves, use "," instead. They accept it as well since long ago but this
+is kept undocumented for some reason.
+
+For example to specify libx264 encoding options with @command{ffmpeg}:
+@example
+ffmpeg -i foo.mpg -vcodec libx264 -x264opts keyint=123:min-keyint=20 -an out.mkv
+@end example
+
+For more information about libx264 and the supported options see:
+@url{http://www.videolan.org/developers/x264.html}
+
@item -x264-params @var{string}
Override the x264 configuration using a :-separated list of key=value parameters.
@example
@@ -594,11 +777,27 @@ Override the x264 configuration using a :-separated list of key=value parameters
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
--- /dev/null
+++ b/doc/errno.txt
@@ -0,0 +1,174 @@
+The following table lists most error codes found in various operating
+systems supported by FFmpeg.
+
+ OS
+Code Std F LBMWwb Text (YMMV)
+
+E2BIG POSIX ++++++ Argument list too long
+EACCES POSIX ++++++ Permission denied
+EADDRINUSE POSIX +++..+ Address in use
+EADDRNOTAVAIL POSIX +++..+ Cannot assign requested address
+EADV +..... Advertise error
+EAFNOSUPPORT POSIX +++..+ Address family not supported
+EAGAIN POSIX + ++++++ Resource temporarily unavailable
+EALREADY POSIX +++..+ Operation already in progress
+EAUTH .++... Authentication error
+EBADARCH ..+... Bad CPU type in executable
+EBADE +..... Invalid exchange
+EBADEXEC ..+... Bad executable
+EBADF POSIX ++++++ Bad file descriptor
+EBADFD +..... File descriptor in bad state
+EBADMACHO ..+... Malformed Macho file
+EBADMSG POSIX ++4... Bad message
+EBADR +..... Invalid request descriptor
+EBADRPC .++... RPC struct is bad
+EBADRQC +..... Invalid request code
+EBADSLT +..... Invalid slot
+EBFONT +..... Bad font file format
+EBUSY POSIX - ++++++ Device or resource busy
+ECANCELED POSIX +++... Operation canceled
+ECHILD POSIX ++++++ No child processes
+ECHRNG +..... Channel number out of range
+ECOMM +..... Communication error on send
+ECONNABORTED POSIX +++..+ Software caused connection abort
+ECONNREFUSED POSIX - +++ss+ Connection refused
+ECONNRESET POSIX +++..+ Connection reset
+EDEADLK POSIX ++++++ Resource deadlock avoided
+EDEADLOCK +..++. File locking deadlock error
+EDESTADDRREQ POSIX +++... Destination address required
+EDEVERR ..+... Device error
+EDOM C89 - ++++++ Numerical argument out of domain
+EDOOFUS .F.... Programming error
+EDOTDOT +..... RFS specific error
+EDQUOT POSIX +++... Disc quota exceeded
+EEXIST POSIX ++++++ File exists
+EFAULT POSIX - ++++++ Bad address
+EFBIG POSIX - ++++++ File too large
+EFTYPE .++... Inappropriate file type or format
+EHOSTDOWN +++... Host is down
+EHOSTUNREACH POSIX +++..+ No route to host
+EHWPOISON +..... Memory page has hardware error
+EIDRM POSIX +++... Identifier removed
+EILSEQ C99 ++++++ Illegal byte sequence
+EINPROGRESS POSIX - +++ss+ Operation in progress
+EINTR POSIX - ++++++ Interrupted system call
+EINVAL POSIX + ++++++ Invalid argument
+EIO POSIX + ++++++ I/O error
+EISCONN POSIX +++..+ Socket is already connected
+EISDIR POSIX ++++++ Is a directory
+EISNAM +..... Is a named type file
+EKEYEXPIRED +..... Key has expired
+EKEYREJECTED +..... Key was rejected by service
+EKEYREVOKED +..... Key has been revoked
+EL2HLT +..... Level 2 halted
+EL2NSYNC +..... Level 2 not synchronized
+EL3HLT +..... Level 3 halted
+EL3RST +..... Level 3 reset
+ELIBACC +..... Can not access a needed shared library
+ELIBBAD +..... Accessing a corrupted shared library
+ELIBEXEC +..... Cannot exec a shared library directly
+ELIBMAX +..... Too many shared libraries
+ELIBSCN +..... .lib section in a.out corrupted
+ELNRNG +..... Link number out of range
+ELOOP POSIX +++..+ Too many levels of symbolic links
+EMEDIUMTYPE +..... Wrong medium type
+EMFILE POSIX ++++++ Too many open files
+EMLINK POSIX ++++++ Too many links
+EMSGSIZE POSIX +++..+ Message too long
+EMULTIHOP POSIX ++4... Multihop attempted
+ENAMETOOLONG POSIX - ++++++ Filen ame too long
+ENAVAIL +..... No XENIX semaphores available
+ENEEDAUTH .++... Need authenticator
+ENETDOWN POSIX +++..+ Network is down
+ENETRESET SUSv3 +++..+ Network dropped connection on reset
+ENETUNREACH POSIX +++..+ Network unreachable
+ENFILE POSIX ++++++ Too many open files in system
+ENOANO +..... No anode
+ENOATTR .++... Attribute not found
+ENOBUFS POSIX - +++..+ No buffer space available
+ENOCSI +..... No CSI structure available
+ENODATA XSR +N4... No message available
+ENODEV POSIX - ++++++ No such device
+ENOENT POSIX - ++++++ No such file or directory
+ENOEXEC POSIX ++++++ Exec format error
+ENOFILE ...++. No such file or directory
+ENOKEY +..... Required key not available
+ENOLCK POSIX ++++++ No locks available
+ENOLINK POSIX ++4... Link has been severed
+ENOMEDIUM +..... No medium found
+ENOMEM POSIX ++++++ Not enough space
+ENOMSG POSIX +++..+ No message of desired type
+ENONET +..... Machine is not on the network
+ENOPKG +..... Package not installed
+ENOPROTOOPT POSIX +++..+ Protocol not available
+ENOSPC POSIX ++++++ No space left on device
+ENOSR XSR +N4... No STREAM resources
+ENOSTR XSR +N4... Not a STREAM
+ENOSYS POSIX + ++++++ Function not implemented
+ENOTBLK +++... Block device required
+ENOTCONN POSIX +++..+ Socket is not connected
+ENOTDIR POSIX ++++++ Not a directory
+ENOTEMPTY POSIX ++++++ Directory not empty
+ENOTNAM +..... Not a XENIX named type file
+ENOTRECOVERABLE SUSv4 - +..... State not recoverable
+ENOTSOCK POSIX +++..+ Socket operation on non-socket
+ENOTSUP POSIX +++... Operation not supported
+ENOTTY POSIX ++++++ Inappropriate I/O control operation
+ENOTUNIQ +..... Name not unique on network
+ENXIO POSIX ++++++ No such device or address
+EOPNOTSUPP POSIX +++..+ Operation not supported (on socket)
+EOVERFLOW POSIX +++..+ Value too large to be stored in data type
+EOWNERDEAD SUSv4 +..... Owner died
+EPERM POSIX - ++++++ Operation not permitted
+EPFNOSUPPORT +++..+ Protocol family not supported
+EPIPE POSIX - ++++++ Broken pipe
+EPROCLIM .++... Too many processes
+EPROCUNAVAIL .++... Bad procedure for program
+EPROGMISMATCH .++... Program version wrong
+EPROGUNAVAIL .++... RPC prog. not avail
+EPROTO POSIX ++4... Protocol error
+EPROTONOSUPPORT POSIX - +++ss+ Protocol not supported
+EPROTOTYPE POSIX +++..+ Protocol wrong type for socket
+EPWROFF ..+... Device power is off
+ERANGE C89 - ++++++ Result too large
+EREMCHG +..... Remote address changed
+EREMOTE +++... Object is remote
+EREMOTEIO +..... Remote I/O error
+ERESTART +..... Interrupted system call should be restarted
+ERFKILL +..... Operation not possible due to RF-kill
+EROFS POSIX ++++++ Read-only file system
+ERPCMISMATCH .++... RPC version wrong
+ESHLIBVERS ..+... Shared library version mismatch
+ESHUTDOWN +++..+ Cannot send after socket shutdown
+ESOCKTNOSUPPORT +++... Socket type not supported
+ESPIPE POSIX ++++++ Illegal seek
+ESRCH POSIX ++++++ No such process
+ESRMNT +..... Srmount error
+ESTALE POSIX +++..+ Stale NFS file handle
+ESTRPIPE +..... Streams pipe error
+ETIME XSR +N4... Stream ioctl timeout
+ETIMEDOUT POSIX - +++ss+ Connection timed out
+ETOOMANYREFS +++... Too many references: cannot splice
+ETXTBSY POSIX +++... Text file busy
+EUCLEAN +..... Structure needs cleaning
+EUNATCH +..... Protocol driver not attached
+EUSERS +++... Too many users
+EWOULDBLOCK POSIX +++..+ Operation would block
+EXDEV POSIX ++++++ Cross-device link
+EXFULL +..... Exchange full
+
+Notations:
+
+F: used in FFmpeg (-: a few times, +: a lot)
+
+SUSv3: Single Unix Specification, version 3
+SUSv4: Single Unix Specification, version 4
+XSR: XSI STREAMS (obsolete)
+
+OS: availability on some supported operating systems
+L: GNU/Linux
+B: BSD (F: FreeBSD, N: NetBSD)
+M: MacOS X
+W: Microsoft Windows (s: emulated with winsock, see libavformat/network.h)
+w: Mingw32 (3.17) and Mingw64 (2.0.1)
+b: BeOS
diff --git a/doc/eval.texi b/doc/eval.texi
deleted file mode 100644
index e1fd7ee..0000000
--- a/doc/eval.texi
+++ /dev/null
@@ -1,156 +0,0 @@
-@chapter Expression Evaluation
-@c man begin EXPRESSION EVALUATION
-
-When evaluating an arithmetic expression, Libav uses an internal
-formula evaluator, implemented through the @file{libavutil/eval.h}
-interface.
-
-An expression may contain unary, binary operators, constants, and
-functions.
-
-Two expressions @var{expr1} and @var{expr2} can be combined to form
-another expression "@var{expr1};@var{expr2}".
-@var{expr1} and @var{expr2} are evaluated in turn, and the new
-expression evaluates to the value of @var{expr2}.
-
-The following binary operators are available: @code{+}, @code{-},
-@code{*}, @code{/}, @code{^}.
-
-The following unary operators are available: @code{+}, @code{-}.
-
-The following functions are available:
-@table @option
-@item sinh(x)
-@item cosh(x)
-@item tanh(x)
-@item sin(x)
-@item cos(x)
-@item tan(x)
-@item atan(x)
-@item asin(x)
-@item acos(x)
-@item exp(x)
-@item log(x)
-@item abs(x)
-@item squish(x)
-@item gauss(x)
-@item isinf(x)
-Return 1.0 if @var{x} is +/-INFINITY, 0.0 otherwise.
-@item isnan(x)
-Return 1.0 if @var{x} is NAN, 0.0 otherwise.
-
-@item mod(x, y)
-@item max(x, y)
-@item min(x, y)
-@item eq(x, y)
-@item gte(x, y)
-@item gt(x, y)
-@item lte(x, y)
-@item lt(x, y)
-@item st(var, expr)
-Allow to store the value of the expression @var{expr} in an internal
-variable. @var{var} specifies the number of the variable where to
-store the value, and it is a value ranging from 0 to 9. The function
-returns the value stored in the internal variable.
-
-@item ld(var)
-Allow to load the value of the internal variable with number
-@var{var}, which was previously stored with st(@var{var}, @var{expr}).
-The function returns the loaded value.
-
-@item while(cond, expr)
-Evaluate expression @var{expr} while the expression @var{cond} is
-non-zero, and returns the value of the last @var{expr} evaluation, or
-NAN if @var{cond} was always false.
-
-@item ceil(expr)
-Round the value of expression @var{expr} upwards to the nearest
-integer. For example, "ceil(1.5)" is "2.0".
-
-@item floor(expr)
-Round the value of expression @var{expr} downwards to the nearest
-integer. For example, "floor(-1.5)" is "-2.0".
-
-@item trunc(expr)
-Round the value of expression @var{expr} towards zero to the nearest
-integer. For example, "trunc(-1.5)" is "-1.0".
-
-@item sqrt(expr)
-Compute the square root of @var{expr}. This is equivalent to
-"(@var{expr})^.5".
-
-@item not(expr)
-Return 1.0 if @var{expr} is zero, 0.0 otherwise.
-@end table
-
-Note that:
-
-@code{*} works like AND
-
-@code{+} works like OR
-
-thus
-@example
-if A then B else C
-@end example
-is equivalent to
-@example
-A*B + not(A)*C
-@end example
-
-In your C code, you can extend the list of unary and binary functions,
-and define recognized constants, so that they are available for your
-expressions.
-
-The evaluator also recognizes the International System number
-postfixes. If 'i' is appended after the postfix, powers of 2 are used
-instead of powers of 10. The 'B' postfix multiplies the value for 8,
-and can be appended after another postfix or used alone. This allows
-using for example 'KB', 'MiB', 'G' and 'B' as postfix.
-
-Follows the list of available International System postfixes, with
-indication of the corresponding powers of 10 and of 2.
-@table @option
-@item y
--24 / -80
-@item z
--21 / -70
-@item a
--18 / -60
-@item f
--15 / -50
-@item p
--12 / -40
-@item n
--9 / -30
-@item u
--6 / -20
-@item m
--3 / -10
-@item c
--2
-@item d
--1
-@item h
-2
-@item k
-3 / 10
-@item K
-3 / 10
-@item M
-6 / 20
-@item G
-9 / 30
-@item T
-12 / 40
-@item P
-15 / 40
-@item E
-18 / 50
-@item Z
-21 / 60
-@item Y
-24 / 70
-@end table
-
-@c man end
diff --git a/doc/examples/Makefile b/doc/examples/Makefile
new file mode 100644
index 0000000..c849daa
--- /dev/null
+++ b/doc/examples/Makefile
@@ -0,0 +1,37 @@
+# use pkg-config for getting CFLAGS and LDLIBS
+FFMPEG_LIBS= libavdevice \
+ libavformat \
+ libavfilter \
+ libavcodec \
+ libswresample \
+ libswscale \
+ libavutil \
+
+CFLAGS += -Wall -O2 -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
+
+.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..a461813
--- /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 the
+doc/examples and run a command such as PKG_CONFIG_PATH=pc-uninstalled make.
diff --git a/libavcodec/api-example.c b/doc/examples/decoding_encoding.c
index 25b7cfe..976b611 100644
--- a/libavcodec/api-example.c
+++ b/doc/examples/decoding_encoding.c
@@ -1,47 +1,44 @@
/*
- * copyright (c) 2001 Fabrice Bellard
+ * Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
*
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
*
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
*/
/**
* @file
* libavcodec API use example.
*
- * @example 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
+ * 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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#ifdef HAVE_AV_CONFIG_H
-#undef HAVE_AV_CONFIG_H
-#endif
+#include <math.h>
-#include "libavcodec/avcodec.h"
-#include "libavutil/channel_layout.h"
-#include "libavutil/common.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/samplefmt.h"
+#include <libavutil/opt.h>
+#include <libavcodec/avcodec.h>
+#include <libavutil/channel_layout.h>
+#include <libavutil/common.h>
+#include <libavutil/imgutils.h>
+#include <libavutil/mathematics.h>
+#include <libavutil/samplefmt.h>
#define INBUF_SIZE 4096
#define AUDIO_INBUF_SIZE 20480
@@ -115,16 +112,20 @@ static void audio_encode_example(const char *filename)
uint16_t *samples;
float t, tincr;
- printf("Audio encoding\n");
+ printf("Encode audio file %s\n", filename);
/* find the MP2 encoder */
codec = avcodec_find_encoder(AV_CODEC_ID_MP2);
if (!codec) {
- fprintf(stderr, "codec not found\n");
+ fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
+ if (!c) {
+ fprintf(stderr, "Could not allocate audio codec context\n");
+ exit(1);
+ }
/* put sample parameters */
c->bit_rate = 64000;
@@ -132,7 +133,7 @@ static void audio_encode_example(const char *filename)
/* check that the encoder supports s16 pcm input */
c->sample_fmt = AV_SAMPLE_FMT_S16;
if (!check_sample_fmt(codec, c->sample_fmt)) {
- fprintf(stderr, "encoder does not support %s",
+ fprintf(stderr, "Encoder does not support sample format %s",
av_get_sample_fmt_name(c->sample_fmt));
exit(1);
}
@@ -144,20 +145,20 @@ static void audio_encode_example(const char *filename)
/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
+ fprintf(stderr, "Could not open codec\n");
exit(1);
}
f = fopen(filename, "wb");
if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
+ fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
/* frame containing input raw audio */
frame = avcodec_alloc_frame();
if (!frame) {
- fprintf(stderr, "could not allocate audio frame\n");
+ fprintf(stderr, "Could not allocate audio frame\n");
exit(1);
}
@@ -171,7 +172,7 @@ static void audio_encode_example(const char *filename)
c->sample_fmt, 0);
samples = av_malloc(buffer_size);
if (!samples) {
- fprintf(stderr, "could not allocate %d bytes for samples buffer\n",
+ fprintf(stderr, "Could not allocate %d bytes for samples buffer\n",
buffer_size);
exit(1);
}
@@ -179,7 +180,7 @@ static void audio_encode_example(const char *filename)
ret = avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,
(const uint8_t*)samples, buffer_size, 0);
if (ret < 0) {
- fprintf(stderr, "could not setup audio frame\n");
+ fprintf(stderr, "Could not setup audio frame\n");
exit(1);
}
@@ -201,9 +202,23 @@ static void audio_encode_example(const char *filename)
/* encode the samples */
ret = avcodec_encode_audio2(c, &pkt, frame, &got_output);
if (ret < 0) {
- fprintf(stderr, "error encoding audio frame\n");
+ fprintf(stderr, "Error encoding audio frame\n");
+ exit(1);
+ }
+ if (got_output) {
+ fwrite(pkt.data, 1, pkt.size, f);
+ av_free_packet(&pkt);
+ }
+ }
+
+ /* get the delayed frames */
+ for (got_output = 1; got_output; i++) {
+ ret = avcodec_encode_audio2(c, &pkt, NULL, &got_output);
+ if (ret < 0) {
+ fprintf(stderr, "Error encoding frame\n");
exit(1);
}
+
if (got_output) {
fwrite(pkt.data, 1, pkt.size, f);
av_free_packet(&pkt);
@@ -232,26 +247,30 @@ static void audio_decode_example(const char *outfilename, const char *filename)
av_init_packet(&avpkt);
- printf("Audio decoding\n");
+ printf("Decode audio file %s to %s\n", filename, outfilename);
/* find the mpeg audio decoder */
codec = avcodec_find_decoder(AV_CODEC_ID_MP2);
if (!codec) {
- fprintf(stderr, "codec not found\n");
+ fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
+ if (!c) {
+ fprintf(stderr, "Could not allocate audio codec context\n");
+ exit(1);
+ }
/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
+ fprintf(stderr, "Could not open codec\n");
exit(1);
}
f = fopen(filename, "rb");
if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
+ fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
outfile = fopen(outfilename, "wb");
@@ -269,7 +288,7 @@ static void audio_decode_example(const char *outfilename, const char *filename)
if (!decoded_frame) {
if (!(decoded_frame = avcodec_alloc_frame())) {
- fprintf(stderr, "out of memory\n");
+ fprintf(stderr, "Could not allocate audio frame\n");
exit(1);
}
} else
@@ -289,6 +308,8 @@ static void audio_decode_example(const char *outfilename, const char *filename)
}
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
@@ -314,27 +335,30 @@ static void audio_decode_example(const char *outfilename, const char *filename)
/*
* Video encoding example
*/
-static void video_encode_example(const char *filename)
+static void video_encode_example(const char *filename, int codec_id)
{
AVCodec *codec;
AVCodecContext *c= NULL;
int i, ret, x, y, got_output;
FILE *f;
- AVFrame *picture;
+ AVFrame *frame;
AVPacket pkt;
uint8_t endcode[] = { 0, 0, 1, 0xb7 };
- printf("Video encoding\n");
+ printf("Encode video file %s\n", filename);
/* find the mpeg1 video encoder */
- codec = avcodec_find_encoder(AV_CODEC_ID_MPEG1VIDEO);
+ codec = avcodec_find_encoder(codec_id);
if (!codec) {
- fprintf(stderr, "codec not found\n");
+ fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
- picture= avcodec_alloc_frame();
+ if (!c) {
+ fprintf(stderr, "Could not allocate video codec context\n");
+ exit(1);
+ }
/* put sample parameters */
c->bit_rate = 400000;
@@ -347,27 +371,38 @@ static void video_encode_example(const char *filename)
c->max_b_frames=1;
c->pix_fmt = AV_PIX_FMT_YUV420P;
+ if(codec_id == AV_CODEC_ID_H264)
+ av_opt_set(c->priv_data, "preset", "slow", 0);
+
/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
+ fprintf(stderr, "Could not open codec\n");
exit(1);
}
f = fopen(filename, "wb");
if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
+ fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
- ret = av_image_alloc(picture->data, picture->linesize, c->width, c->height,
+ 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 alloc raw picture buffer\n");
+ fprintf(stderr, "Could not allocate raw picture buffer\n");
exit(1);
}
- picture->format = c->pix_fmt;
- picture->width = c->width;
- picture->height = c->height;
/* encode 1 second of video */
for(i=0;i<25;i++) {
@@ -380,29 +415,29 @@ static void video_encode_example(const char *filename)
/* 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;
+ frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
}
}
/* Cb and Cr */
for(y=0;y<c->height/2;y++) {
for(x=0;x<c->width/2;x++) {
- picture->data[1][y * picture->linesize[1] + x] = 128 + y + i * 2;
- picture->data[2][y * picture->linesize[2] + x] = 64 + x + i * 5;
+ frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
+ frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
}
}
- picture->pts = i;
+ frame->pts = i;
/* encode the image */
- ret = avcodec_encode_video2(c, &pkt, picture, &got_output);
+ ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
if (ret < 0) {
- fprintf(stderr, "error encoding frame\n");
+ fprintf(stderr, "Error encoding frame\n");
exit(1);
}
if (got_output) {
- printf("encoding frame %3d (size=%5d)\n", i, pkt.size);
+ printf("Write frame %3d (size=%5d)\n", i, pkt.size);
fwrite(pkt.data, 1, pkt.size, f);
av_free_packet(&pkt);
}
@@ -414,12 +449,12 @@ static void video_encode_example(const char *filename)
ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
if (ret < 0) {
- fprintf(stderr, "error encoding frame\n");
+ fprintf(stderr, "Error encoding frame\n");
exit(1);
}
if (got_output) {
- printf("encoding frame %3d (size=%5d)\n", i, pkt.size);
+ printf("Write frame %3d (size=%5d)\n", i, pkt.size);
fwrite(pkt.data, 1, pkt.size, f);
av_free_packet(&pkt);
}
@@ -431,8 +466,8 @@ static void video_encode_example(const char *filename)
avcodec_close(c);
av_free(c);
- av_freep(&picture->data[0]);
- avcodec_free_frame(&picture);
+ av_freep(&frame->data[0]);
+ avcodec_free_frame(&frame);
printf("\n");
}
@@ -453,15 +488,42 @@ static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
fclose(f);
}
+static int decode_write_frame(const char *outfilename, AVCodecContext *avctx,
+ AVFrame *frame, int *frame_count, AVPacket *pkt, int last)
+{
+ int len, got_frame;
+ char buf[1024];
+
+ len = avcodec_decode_video2(avctx, frame, &got_frame, pkt);
+ if (len < 0) {
+ fprintf(stderr, "Error while decoding frame %d\n", *frame_count);
+ return len;
+ }
+ if (got_frame) {
+ printf("Saving %sframe %3d\n", last ? "last " : "", *frame_count);
+ fflush(stdout);
+
+ /* the picture is allocated by the decoder, no need to free it */
+ snprintf(buf, sizeof(buf), outfilename, *frame_count);
+ pgm_save(frame->data[0], frame->linesize[0],
+ avctx->width, avctx->height, buf);
+ (*frame_count)++;
+ }
+ if (pkt->data) {
+ pkt->size -= len;
+ pkt->data += len;
+ }
+ return 0;
+}
+
static void video_decode_example(const char *outfilename, const char *filename)
{
AVCodec *codec;
AVCodecContext *c= NULL;
- int frame, got_picture, len;
+ int frame_count;
FILE *f;
- AVFrame *picture;
+ AVFrame *frame;
uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
- char buf[1024];
AVPacket avpkt;
av_init_packet(&avpkt);
@@ -469,17 +531,20 @@ static void video_decode_example(const char *outfilename, const char *filename)
/* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */
memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
- printf("Video decoding\n");
+ printf("Decode video file %s to %s\n", filename, outfilename);
/* find the mpeg1 video decoder */
codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO);
if (!codec) {
- fprintf(stderr, "codec not found\n");
+ fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
- picture= avcodec_alloc_frame();
+ 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 */
@@ -490,19 +555,23 @@ static void video_decode_example(const char *outfilename, const char *filename)
/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
+ fprintf(stderr, "Could not open codec\n");
exit(1);
}
- /* the codec gives us the frame size, in samples */
-
f = fopen(filename, "rb");
if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
+ fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
- frame = 0;
+ 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)
@@ -524,26 +593,9 @@ static void video_decode_example(const char *outfilename, const char *filename)
/* here, we use a stream based decoder (mpeg1video), so we
feed decoder and see if it could decode a frame */
avpkt.data = inbuf;
- while (avpkt.size > 0) {
- len = avcodec_decode_video2(c, picture, &got_picture, &avpkt);
- if (len < 0) {
- fprintf(stderr, "Error while decoding frame %d\n", frame);
+ while (avpkt.size > 0)
+ if (decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 0) < 0)
exit(1);
- }
- if (got_picture) {
- printf("saving frame %3d\n", frame);
- fflush(stdout);
-
- /* the picture is allocated by the decoder. no need to
- free it */
- snprintf(buf, sizeof(buf), outfilename, frame);
- pgm_save(picture->data[0], picture->linesize[0],
- c->width, c->height, buf);
- frame++;
- }
- avpkt.size -= len;
- avpkt.data += len;
- }
}
/* some codecs, such as MPEG, transmit the I and P frame with a
@@ -551,46 +603,48 @@ static void video_decode_example(const char *outfilename, const char *filename)
chance to get the last frame of the video */
avpkt.data = NULL;
avpkt.size = 0;
- len = avcodec_decode_video2(c, picture, &got_picture, &avpkt);
- if (got_picture) {
- printf("saving last frame %3d\n", frame);
- fflush(stdout);
-
- /* the picture is allocated by the decoder. no need to
- free it */
- snprintf(buf, sizeof(buf), outfilename, frame);
- pgm_save(picture->data[0], picture->linesize[0],
- c->width, c->height, buf);
- frame++;
- }
+ decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 1);
fclose(f);
avcodec_close(c);
av_free(c);
- avcodec_free_frame(&picture);
+ avcodec_free_frame(&frame);
printf("\n");
}
int main(int argc, char **argv)
{
- const char *filename;
+ const char *output_type;
/* register all the codecs */
avcodec_register_all();
- if (argc <= 1) {
- audio_encode_example("/tmp/test.mp2");
- audio_decode_example("/tmp/test.sw", "/tmp/test.mp2");
-
- video_encode_example("/tmp/test.mpg");
- filename = "/tmp/test.mpg";
+ if (argc < 2) {
+ printf("usage: %s output_type\n"
+ "API example program to decode/encode a media stream with libavcodec.\n"
+ "This program generates a synthetic stream and encodes it to a file\n"
+ "named test.h264, test.mp2 or test.mpg depending on output_type.\n"
+ "The encoded stream is then decoded and written to a raw data output.\n"
+ "output_type must be 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 {
- filename = argv[1];
+ fprintf(stderr, "Invalid output type '%s', choose between 'h264', 'mp2', or 'mpg'\n",
+ output_type);
+ return 1;
}
- // audio_decode_example("/tmp/test.sw", filename);
- video_decode_example("/tmp/test%d.pgm", filename);
-
return 0;
}
diff --git a/doc/examples/demuxing.c b/doc/examples/demuxing.c
new file mode 100644
index 0000000..8a1b69b
--- /dev/null
+++ b/doc/examples/demuxing.c
@@ -0,0 +1,342 @@
+/*
+ * 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 uint8_t **audio_dst_data = NULL;
+static int audio_dst_linesize;
+static int audio_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;
+
+ 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;
+ }
+
+ if (*got_frame) {
+ 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));
+
+ ret = av_samples_alloc(audio_dst_data, &audio_dst_linesize, av_frame_get_channels(frame),
+ frame->nb_samples, frame->format, 1);
+ if (ret < 0) {
+ fprintf(stderr, "Could not allocate audio buffer\n");
+ return AVERROR(ENOMEM);
+ }
+
+ /* TODO: extend return code of the av_samples_* functions so that this call is not needed */
+ audio_dst_bufsize =
+ av_samples_get_buffer_size(NULL, av_frame_get_channels(frame),
+ frame->nb_samples, frame->format, 1);
+
+ /* copy audio data to destination buffer:
+ * this is required since rawaudio expects non aligned data */
+ av_samples_copy(audio_dst_data, frame->data, 0, 0,
+ frame->nb_samples, av_frame_get_channels(frame), frame->format);
+
+ /* write to rawaudio file */
+ fwrite(audio_dst_data[0], 1, audio_dst_bufsize, audio_dst_file);
+ av_freep(&audio_dst_data[0]);
+ }
+ }
+
+ return ret;
+}
+
+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) {
+ int nb_planes;
+
+ 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;
+ }
+
+ nb_planes = av_sample_fmt_is_planar(audio_dec_ctx->sample_fmt) ?
+ audio_dec_ctx->channels : 1;
+ audio_dst_data = av_mallocz(sizeof(uint8_t *) * nb_planes);
+ if (!audio_dst_data) {
+ fprintf(stderr, "Could not allocate audio data buffers\n");
+ ret = AVERROR(ENOMEM);
+ 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) {
+ decode_packet(&got_frame, 0);
+ av_free_packet(&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) {
+ const char *fmt;
+
+ if ((ret = get_format_from_sample_fmt(&fmt, audio_dec_ctx->sample_fmt)) < 0)
+ goto end;
+ printf("Play the output audio file with the command:\n"
+ "ffplay -f %s -ac %d -ar %d %s\n",
+ fmt, audio_dec_ctx->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]);
+ av_free(audio_dst_data);
+
+ return ret < 0;
+}
diff --git a/doc/examples/filtering_audio.c b/doc/examples/filtering_audio.c
new file mode 100644
index 0000000..b6b05a2
--- /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>
+
+const char *filter_descr = "aresample=8000,aformat=sample_fmts=s16:channel_layouts=mono";
+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();
+ const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 };
+ const int64_t out_channel_layouts[] = { AV_CH_LAYOUT_MONO, -1 };
+ 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(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..daa3966
--- /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(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/libavformat/metadata-example.c b/doc/examples/metadata.c
index 7bf77e7..9c1bcd7 100644
--- a/libavformat/metadata-example.c
+++ b/doc/examples/metadata.c
@@ -22,8 +22,8 @@
/**
* @file
- * @example libavformat/metadata-example.c
* Shows how the metadata API can be used in application programs.
+ * @example doc/examples/metadata.c
*/
#include <stdio.h>
@@ -51,6 +51,6 @@ int main (int argc, char **argv)
while ((tag = av_dict_get(fmt_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
printf("%s=%s\n", tag->key, tag->value);
- avformat_free_context(fmt_ctx);
+ avformat_close_input(&fmt_ctx);
return 0;
}
diff --git a/libavformat/output-example.c b/doc/examples/muxing.c
index 496b7f8..7305cc6 100644
--- a/libavformat/output-example.c
+++ b/doc/examples/muxing.c
@@ -24,9 +24,9 @@
* @file
* libavformat API example.
*
- * @example libavformat/output-example.c
* Output a media file in any supported libavformat format.
* The default codecs are used.
+ * @example doc/examples/muxing.c
*/
#include <stdlib.h>
@@ -34,12 +34,12 @@
#include <string.h>
#include <math.h>
-#include "libavutil/mathematics.h"
-#include "libavformat/avformat.h"
-#include "libswscale/swscale.h"
+#include <libavutil/mathematics.h>
+#include <libavformat/avformat.h>
+#include <libswscale/swscale.h>
/* 5 seconds stream duration */
-#define STREAM_DURATION 5.0
+#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 */
@@ -53,52 +53,94 @@ 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)
+/* Add an output stream. */
+static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec,
+ 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");
+ /* 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);
+ st = avformat_new_stream(oc, *codec);
if (!st) {
- fprintf(stderr, "Could not alloc stream\n");
+ fprintf(stderr, "Could not allocate stream\n");
exit(1);
}
-
+ st->id = oc->nb_streams-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;
+ switch ((*codec)->type) {
+ case AVMEDIA_TYPE_AUDIO:
+ st->id = 1;
+ c->sample_fmt = AV_SAMPLE_FMT_S16;
+ 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;
- // some formats want stream headers to be separate
+ default:
+ break;
+ }
+
+ /* 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)
+/**************************************************************/
+/* audio output */
+
+static float t, tincr, tincr2;
+static int16_t *samples;
+static int audio_input_frame_size;
+
+static void open_audio(AVFormatContext *oc, AVCodec *codec, AVStream *st)
{
AVCodecContext *c;
+ int ret;
c = st->codec;
/* open it */
- if (avcodec_open2(c, NULL, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
+ ret = avcodec_open2(c, codec, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open audio codec: %s\n", av_err2str(ret));
exit(1);
}
@@ -115,6 +157,10 @@ static void open_audio(AVFormatContext *oc, AVStream *st)
samples = av_malloc(audio_input_frame_size *
av_get_bytes_per_sample(c->sample_fmt) *
c->channels);
+ if (!samples) {
+ fprintf(stderr, "Could not allocate audio samples buffer\n");
+ exit(1);
+ }
}
/* Prepare a 16 bit dummy audio frame of 'frame_size' samples and
@@ -139,7 +185,7 @@ 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;
+ int got_packet, ret;
av_init_packet(&pkt);
c = st->codec;
@@ -152,15 +198,22 @@ static void write_audio_frame(AVFormatContext *oc, AVStream *st)
av_get_bytes_per_sample(c->sample_fmt) *
c->channels, 1);
- avcodec_encode_audio2(c, &pkt, frame, &got_packet);
+ 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. */
- if (av_interleaved_write_frame(oc, &pkt) != 0) {
- fprintf(stderr, "Error while writing audio frame\n");
+ 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);
@@ -176,115 +229,54 @@ static void close_audio(AVFormatContext *oc, AVStream *st)
/**************************************************************/
/* video output */
-static AVFrame *picture, *tmp_picture;
+static AVFrame *frame;
+static AVPicture src_picture, dst_picture;
static int frame_count;
-/* Add a video output stream. */
-static AVStream *add_video_stream(AVFormatContext *oc, enum AVCodecID codec_id)
+static void open_video(AVFormatContext *oc, AVCodec *codec, AVStream *st)
{
- AVCodecContext *c;
- AVStream *st;
- AVCodec *codec;
+ int ret;
+ AVCodecContext *c = st->codec;
- /* find the video encoder */
- codec = avcodec_find_encoder(codec_id);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
+ /* 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);
}
- 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");
+ /* 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. */
- picture = alloc_picture(c->pix_fmt, c->width, c->height);
- if (!picture) {
- fprintf(stderr, "Could not allocate picture\n");
+ 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. */
- 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");
+ 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(AVFrame *pict, int frame_index,
+static void fill_yuv_image(AVPicture *pict, int frame_index,
int width, int height)
{
int x, y, i;
@@ -308,10 +300,8 @@ static void fill_yuv_image(AVFrame *pict, int frame_index,
static void write_video_frame(AVFormatContext *oc, AVStream *st)
{
int ret;
- AVCodecContext *c;
- static struct SwsContext *img_convert_ctx;
-
- c = st->codec;
+ 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
@@ -321,35 +311,33 @@ static void write_video_frame(AVFormatContext *oc, AVStream *st)
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) {
+ 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,
- "Cannot initialize the conversion context\n");
+ "Could not 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);
+ 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(picture, frame_count, c->width, c->height);
+ fill_yuv_image(&dst_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. */
+ /* 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 = (uint8_t *)picture;
+ pkt.data = dst_picture.data[0];
pkt.size = sizeof(AVPicture);
ret = av_interleaved_write_frame(oc, &pkt);
@@ -359,17 +347,14 @@ static void write_video_frame(AVFormatContext *oc, AVStream *st)
av_init_packet(&pkt);
/* encode the image */
- ret = avcodec_encode_video2(c, &pkt, picture, &got_packet);
+ 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) {
- 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. */
@@ -379,7 +364,7 @@ static void write_video_frame(AVFormatContext *oc, AVStream *st)
}
}
if (ret != 0) {
- fprintf(stderr, "Error while writing video frame\n");
+ fprintf(stderr, "Error while writing video frame: %s\n", av_err2str(ret));
exit(1);
}
frame_count++;
@@ -388,12 +373,9 @@ static void write_video_frame(AVFormatContext *oc, AVStream *st)
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);
- }
+ av_free(src_picture.data[0]);
+ av_free(dst_picture.data[0]);
+ av_free(frame);
}
/**************************************************************/
@@ -405,8 +387,9 @@ int main(int argc, char **argv)
AVOutputFormat *fmt;
AVFormatContext *oc;
AVStream *audio_st, *video_st;
+ AVCodec *audio_codec, *video_codec;
double audio_pts, video_pts;
- int i;
+ int ret;
/* Initialize libavcodec, and register all codecs and formats. */
av_register_all();
@@ -414,65 +397,68 @@ int main(int argc, char **argv)
if (argc != 2) {
printf("usage: %s output_file\n"
"API example program to output a media file with libavformat.\n"
+ "This program generates a synthetic audio and video stream, encodes and\n"
+ "muxes them into a file named output_file.\n"
"The output format is automatically guessed according to the file extension.\n"
- "Raw images can also be output by using '%%d' in the filename\n"
+ "Raw images can also be output by using '%%d' in the filename.\n"
"\n", argv[0]);
return 1;
}
filename = argv[1];
- /* Autodetect the output format from the name. default is MPEG. */
- fmt = av_guess_format(NULL, filename, NULL);
- if (!fmt) {
+ /* allocate the output media context */
+ avformat_alloc_output_context2(&oc, NULL, NULL, filename);
+ if (!oc) {
printf("Could not deduce output format from file extension: using MPEG.\n");
- fmt = av_guess_format("mpeg", NULL, NULL);
+ avformat_alloc_output_context2(&oc, NULL, "mpeg", filename);
}
- if (!fmt) {
- fprintf(stderr, "Could not find suitable output format\n");
- return 1;
- }
-
- /* Allocate the output media context. */
- oc = avformat_alloc_context();
if (!oc) {
- fprintf(stderr, "Memory error\n");
return 1;
}
- oc->oformat = fmt;
- snprintf(oc->filename, sizeof(oc->filename), "%s", filename);
+ fmt = oc->oformat;
/* Add the audio and video streams using the default format codecs
* and initialize the codecs. */
video_st = NULL;
audio_st = NULL;
+
if (fmt->video_codec != AV_CODEC_ID_NONE) {
- video_st = add_video_stream(oc, fmt->video_codec);
+ video_st = add_stream(oc, &video_codec, fmt->video_codec);
}
if (fmt->audio_codec != AV_CODEC_ID_NONE) {
- audio_st = add_audio_stream(oc, fmt->audio_codec);
+ 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_st);
+ open_video(oc, video_codec, video_st);
if (audio_st)
- open_audio(oc, 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)) {
- if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) {
- fprintf(stderr, "Could not open '%s'\n", filename);
+ ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open '%s': %s\n", filename,
+ av_err2str(ret));
return 1;
}
}
/* Write the stream header, if any. */
- avformat_write_header(oc, NULL);
+ ret = avformat_write_header(oc, 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. */
if (audio_st)
@@ -495,6 +481,7 @@ int main(int argc, char **argv)
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);
}
}
@@ -510,18 +497,12 @@ int main(int argc, char **argv)
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);
+ 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
--- /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
--- /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 088ca03..4b0b09c 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
@@ -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,14 +214,14 @@ 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.
@@ -197,9 +229,9 @@ Just create an "input.avs" text file with this single line ...
@example
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}.
+
+Examples are also installed by default, usually in
+@code{$PREFIX/share/ffmpeg/examples}.
-Yes. Read the Developers Guide of the Libav documentation. Alternatively,
+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,88 @@ 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 ffmpeg_g, ffplay_g, etc. which contain full debug
+information. Those binaries are stripped to create ffmpeg, 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 can I find libav* headers for Pascal/Delphi?
+
+see @url{http://www.iversenit.dk/dev/ffmpeg-headers/}
+
+@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.
+
+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 r_frame_rate
+will be 150.
@section Why is @code{make fate} not running all tests?
diff --git a/doc/fate.texi b/doc/fate.texi
index bc6ab3e..28eadfd 100644
--- a/doc/fate.texi
+++ b/doc/fate.texi
@@ -1,152 +1,196 @@
\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 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}.
-@chapter Manual Run
-FATE regression test can be run through @command{make}.
-Specific Makefile targets and Makefile variables are available:
+ 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:
+
+ b1:31:c8:79:3f:04:1d:f8:f2:23:26:5a:fd:55:fa:92
+
+ 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
-@anchor{Makefile target}
-@section FATE Makefile targets
@table @option
-@item fate-list
-List all fate/regression test targets.
@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).
+ 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
+ Verbosity level, can be set to 0, 1 or 2.
+ @itemize
+ @item 0: show just the test arguments
+ @item 1: show just the command used in the test
+ @item 2: show everything
+ @end itemize
+
@item SAMPLES
-Specify or override the path to the FATE samples at make time, it has a
-meaning only while running the regression tests.
+ Specify or override the path to the FATE samples at make time, it has a
+ meaning only while running the regression tests.
+
@item THREADS
-Specify how many threads to use while running regression tests, it is
-quite useful to detect thread-related regressions.
+ Specify how many threads to use while running regression tests, it is
+ quite useful to detect thread-related regressions.
@item THREAD_TYPE
-Specify which threading strategy test, either @var{slice} or @var{frame},
-by default @var{slice+frame}
+ Specify which threading strategy test, either @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.
+ 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
-
-# the following are optional and map to configure options
-arch=
-cpu=
-cross_prefix=
-cc=
-target_os=
-sysroot=
-target_exec=
-target_path=
-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..f7bd625
--- /dev/null
+++ b/doc/fate_config.sh.template
@@ -0,0 +1,25 @@
+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
+
+# the following are optional and map to configure options
+arch=
+cpu=
+cross_prefix=
+cc=
+target_os=
+sysroot=
+target_exec=
+target_path=
+extra_cflags=
+extra_ldflags=
+extra_libs=
+extra_conf= # extra configure options not covered above
+
+#make= # name of GNU make if not 'make'
+makeopts= # extra options passed to 'make'
+#tar= # command to create a tar archive from its arguments on stdout,
+ # defaults to 'tar c'
diff --git a/doc/ffmpeg-bitstream-filters.texi b/doc/ffmpeg-bitstream-filters.texi
new file mode 100644
index 0000000..e33e005
--- /dev/null
+++ b/doc/ffmpeg-bitstream-filters.texi
@@ -0,0 +1,45 @@
+\input texinfo @c -*- texinfo -*-
+
+@settitle FFmpeg Bitstream Filters Documentation
+@titlepage
+@center @titlefont{FFmpeg Bitstream Filters Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes the bitstream filters provided by the
+libavcodec library.
+
+A bitstream filter operates on the encoded stream data, and performs
+bitstream level modifications without performing decoding.
+
+@c man end DESCRIPTION
+
+@include bitstream_filters.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavcodec.html,libavcodec}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavcodec(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-bitstream-filters
+@settitle FFmpeg bitstream filters
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-codecs.texi b/doc/ffmpeg-codecs.texi
new file mode 100644
index 0000000..6f8f5a3
--- /dev/null
+++ b/doc/ffmpeg-codecs.texi
@@ -0,0 +1,42 @@
+\input texinfo @c -*- texinfo -*-
+
+@settitle FFmpeg Codecs Documentation
+@titlepage
+@center @titlefont{FFmpeg Codecs Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes the codecs (decoders and encoders) provided by
+the libavcodec library.
+
+@c man end DESCRIPTION
+
+@include codecs.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavcodec.html,libavcodec}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavcodec(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-codecs
+@settitle FFmpeg codecs
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-devices.texi b/doc/ffmpeg-devices.texi
new file mode 100644
index 0000000..b44bd72
--- /dev/null
+++ b/doc/ffmpeg-devices.texi
@@ -0,0 +1,42 @@
+\input texinfo @c -*- texinfo -*-
+
+@settitle FFmpeg Devices Documentation
+@titlepage
+@center @titlefont{FFmpeg Devices Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes the input and output devices provided by the
+libavdevice library.
+
+@c man end DESCRIPTION
+
+@include devices.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavdevice.html,libavdevice}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavdevice(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-devices
+@settitle FFmpeg devices
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-filters.texi b/doc/ffmpeg-filters.texi
new file mode 100644
index 0000000..bb920ce
--- /dev/null
+++ b/doc/ffmpeg-filters.texi
@@ -0,0 +1,42 @@
+\input texinfo @c -*- texinfo -*-
+
+@settitle FFmpeg Filters Documentation
+@titlepage
+@center @titlefont{FFmpeg Filters Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes filters, sources, and sinks provided by the
+libavfilter library.
+
+@c man end DESCRIPTION
+
+@include filters.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavfilter.html,libavfilter}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavfilter(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-filters
+@settitle FFmpeg filters
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-formats.texi b/doc/ffmpeg-formats.texi
new file mode 100644
index 0000000..e205caa
--- /dev/null
+++ b/doc/ffmpeg-formats.texi
@@ -0,0 +1,42 @@
+\input texinfo @c -*- texinfo -*-
+
+@settitle FFmpeg Formats Documentation
+@titlepage
+@center @titlefont{FFmpeg Formats Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes the supported formats (muxers and demuxers)
+provided by the libavformat library.
+
+@c man end DESCRIPTION
+
+@include formats.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavformat.html,libavformat}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavformat(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-formats
+@settitle FFmpeg formats
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-protocols.texi b/doc/ffmpeg-protocols.texi
new file mode 100644
index 0000000..d992e75
--- /dev/null
+++ b/doc/ffmpeg-protocols.texi
@@ -0,0 +1,42 @@
+\input texinfo @c -*- texinfo -*-
+
+@settitle FFmpeg Protocols Documentation
+@titlepage
+@center @titlefont{FFmpeg Protocols Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes the input and output protocols provided by the
+libavformat library.
+
+@c man end DESCRIPTION
+
+@include protocols.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavformat.html,libavformat}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavformat(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-protocols
+@settitle FFmpeg protocols
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-resampler.texi b/doc/ffmpeg-resampler.texi
new file mode 100644
index 0000000..da3d033
--- /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 an 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..47b81a4
--- /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 an 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
--- /dev/null
+++ b/doc/ffmpeg-utils.texi
@@ -0,0 +1,42 @@
+\input texinfo @c -*- texinfo -*-
+
+@settitle FFmpeg Utilities Documentation
+@titlepage
+@center @titlefont{FFmpeg Utilities Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes some generic features and utilities provided
+by the libavutil library.
+
+@c man end DESCRIPTION
+
+@include utils.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavutil.html,libavutil}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavutil(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-utils
+@settitle FFmpeg utilities
+
+@end ignore
+
+@bye
diff --git a/doc/avconv.texi b/doc/ffmpeg.texi
index 1842422..7504b3a 100644
--- a/doc/avconv.texi
+++ b/doc/ffmpeg.texi
@@ -1,8 +1,8 @@
\input texinfo @c -*- texinfo -*-
-@settitle avconv Documentation
+@settitle ffmpeg Documentation
@titlepage
-@center @titlefont{avconv Documentation}
+@center @titlefont{ffmpeg Documentation}
@end titlepage
@top
@@ -11,37 +11,31 @@
@chapter Synopsis
-The generic syntax is:
-
-@example
-@c man begin SYNOPSIS
-avconv [global options] [[infile options][@option{-i} @var{infile}]]... @{[outfile options] @var{outfile}@}...
-@c man end
-@end example
+ffmpeg [@var{global_options}] @{[@var{input_file_options}] -i @file{input_file}@} ... @{[@var{output_file_options}] @file{output_file}@} ...
@chapter Description
@c man begin DESCRIPTION
-avconv is a very fast video and audio converter that can also grab from
+@command{ffmpeg} is a very fast video and audio converter that can also grab from
a live audio/video source. It can also convert between arbitrary sample
rates and resize video on the fly with a high quality polyphase filter.
-avconv reads from an arbitrary number of input "files" (which can be regular
+@command{ffmpeg} reads from an arbitrary number of input "files" (which can be regular
files, pipes, network streams, grabbing devices, etc.), specified by the
@code{-i} option, and writes to an arbitrary number of output "files", which are
specified by a plain output filename. Anything found on the command line which
cannot be interpreted as an option is considered to be an output filename.
-Each input or output file can in principle contain any number of streams of
-different types (video/audio/subtitle/attachment/data). Allowed number and/or
-types of streams can be limited by the container format. Selecting, which
-streams from which inputs go into output, is done either automatically or with
-the @code{-map} option (see the Stream selection chapter).
+Each input or output file can, in principle, contain any number of streams of
+different types (video/audio/subtitle/attachment/data). The allowed number and/or
+types of streams may be limited by the container format. Selecting which
+streams from which inputs will go into which output is either done automatically
+or with the @code{-map} option (see the Stream selection chapter).
To refer to input files in options, you must use their indices (0-based). E.g.
-the first input file is @code{0}, the second is @code{1} etc. Similarly, streams
+the first input file is @code{0}, the second is @code{1}, etc. Similarly, streams
within a file are referred to by their indices. E.g. @code{2:3} refers to the
-fourth stream in the third input file. See also the Stream specifiers chapter.
+fourth stream in the third input file. Also see the Stream specifiers chapter.
As a general rule, options are applied to the next specified
file. Therefore, order is important, and you can have the same
@@ -56,22 +50,22 @@ options apply ONLY to the next input or output file and are reset between files.
@itemize
@item
-To set the video bitrate of the output file to 64kbit/s:
+To set the video bitrate of the output file to 64 kbit/s:
@example
-avconv -i input.avi -b 64k output.avi
+ffmpeg -i input.avi -b:v 64k -bufsize 64k output.avi
@end example
@item
To force the frame rate of the output file to 24 fps:
@example
-avconv -i input.avi -r 24 output.avi
+ffmpeg -i input.avi -r 24 output.avi
@end example
@item
To force the frame rate of the input file (valid for raw formats only)
to 1 fps and the frame rate of the output file to 24 fps:
@example
-avconv -r 1 -i input.m2v -r 24 output.avi
+ffmpeg -r 1 -i input.m2v -r 24 output.avi
@end example
@end itemize
@@ -82,7 +76,7 @@ The format option may be needed for raw input files.
@chapter Detailed description
@c man begin DETAILED DESCRIPTION
-The transcoding process in @command{avconv} for each output can be described by
+The transcoding process in @command{ffmpeg} for each output can be described by
the following diagram:
@example
@@ -94,22 +88,22 @@ the following diagram:
@end example
-@command{avconv} calls the libavformat library (containing demuxers) to read
+@command{ffmpeg} calls the libavformat library (containing demuxers) to read
input files and get packets containing encoded data from them. When there are
-multiple input files, @command{avconv} tries to keep them synchronized by
+multiple input files, @command{ffmpeg} tries to keep them synchronized by
tracking lowest timestamp on any active input stream.
Encoded packets are then passed to the decoder (unless streamcopy is selected
for the stream, see further for a description). The decoder produces
uncompressed frames (raw video/PCM audio/...) which can be processed further by
-filtering (see next section). After filtering the frames are passed to the
-encoder, which encodes them and outputs encoded packets again. Finally those are
+filtering (see next section). After filtering, the frames are passed to the
+encoder, which encodes them and outputs encoded packets. Finally those are
passed to the muxer, which writes the encoded packets to the output file.
@section Filtering
-Before encoding, @command{avconv} can process raw audio and video frames using
+Before encoding, @command{ffmpeg} can process raw audio and video frames using
filters from the libavfilter library. Several chained filters form a filter
-graph. @command{avconv} distinguishes between two types of filtergraphs -
+graph. @command{ffmpeg} distinguishes between two types of filtergraphs:
simple and complex.
@subsection Simple filtergraphs
@@ -145,7 +139,7 @@ only sets timestamps and otherwise passes the frames unchanged.
@subsection Complex filtergraphs
Complex filtergraphs are those which cannot be described as simply a linear
-processing chain applied to one stream. This is the case e.g. when the graph has
+processing chain applied to one stream. This is the case, for example, when the graph has
more than one input and/or output, or when output stream type is different from
input. They can be represented with the following diagram:
@@ -170,19 +164,21 @@ input. They can be represented with the following diagram:
@end example
Complex filtergraphs are configured with the @option{-filter_complex} option.
-Note that this option is global, since a complex filtergraph by its nature
+Note that this option is global, since a complex filtergraph, by its nature,
cannot be unambiguously associated with a single stream or file.
+The @option{-lavfi} option is equivalent to @option{-filter_complex}.
+
A trivial example of a complex filtergraph is the @code{overlay} filter, which
has two video inputs and one video output, containing one video overlaid on top
of the other. Its audio counterpart is the @code{amix} filter.
@section Stream copy
Stream copy is a mode selected by supplying the @code{copy} parameter to the
-@option{-codec} option. It makes @command{avconv} omit the decoding and encoding
+@option{-codec} option. It makes @command{ffmpeg} omit the decoding and encoding
step for the specified stream, so it does only demuxing and muxing. It is useful
for changing the container format or modifying container-level metadata. The
-diagram above will in this case simplify to this:
+diagram above will, in this case, simplify to this:
@example
_______ ______________ ________
@@ -194,7 +190,7 @@ diagram above will in this case simplify to this:
@end example
Since there is no decoding or encoding, it is very fast and there is no quality
-loss. However it might not work in some cases because of many factors. Applying
+loss. However, it might not work in some cases because of many factors. Applying
filters is obviously also impossible, since filters work on uncompressed data.
@c man end DETAILED DESCRIPTION
@@ -202,12 +198,14 @@ filters is obviously also impossible, since filters work on uncompressed data.
@chapter Stream selection
@c man begin STREAM SELECTION
-By default avconv tries to pick the "best" stream of each type present in input
-files and add them to each output file. For video, this means the highest
-resolution, for audio the highest channel count. For subtitle it's simply the
-first subtitle stream.
+By default, @command{ffmpeg} includes only one stream of each type (video, audio, subtitle)
+present in the input files and adds them to each output file. It picks the
+"best" of each based upon the following criteria: for video, it is the stream
+with the highest resolution, for audio, it is the stream with the most channels, for
+subtitles, it is the first subtitle stream. In the case where several streams of
+the same type rate equally, the stream with the lowest index is chosen.
-You can disable some of those defaults by using @code{-vn/-an/-sn} options. For
+You can disable some of those defaults by using the @code{-vn/-an/-sn} options. For
full manual control, use the @code{-map} option, which disables the defaults just
described.
@@ -223,8 +221,8 @@ described.
@table @option
@item -f @var{fmt} (@emph{input/output})
-Force input or output file format. The format is normally autodetected for input
-files and guessed from file extension for output files, so this option is not
+Force input or output file format. The format is normally auto detected for input
+files and guessed from the file extension for output files, so this option is not
needed in most cases.
@item -i @var{filename} (@emph{input})
@@ -233,22 +231,26 @@ 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 reencoded.
+the stream is not to be re-encoded.
For example
@example
-avconv -i INPUT -map 0 -c:v libx264 -c:a copy OUTPUT
+ffmpeg -i INPUT -map 0 -c:v libx264 -c:a copy OUTPUT
@end example
encodes all video streams with libx264 and copies all audio streams.
For each stream, the last matching @code{c} option is applied, so
@example
-avconv -i INPUT -map 0 -c copy -c:v:1 libx264 -c:a:137 libvorbis OUTPUT
+ffmpeg -i INPUT -map 0 -c copy -c:v:1 libx264 -c:a:137 libvorbis OUTPUT
@end example
will copy all the streams except the second video, which will be encoded with
libx264, and the 138th audio, which will be encoded with libvorbis.
@@ -257,8 +259,16 @@ libx264, and the 138th audio, which will be encoded with libvorbis.
Stop writing the output after its duration reaches @var{duration}.
@var{duration} may be a number in seconds, or in @code{hh:mm:ss[.xxx]} form.
+-to and -t are mutually exclusive and -t has priority.
+
+@item -to @var{position} (@emph{output})
+Stop writing the output at @var{position}.
+@var{position} may be a number in seconds, or in @code{hh:mm:ss[.xxx]} form.
+
+-to and -t are mutually exclusive and -t has priority.
+
@item -fs @var{limit_size} (@emph{output})
-Set the file size limit.
+Set the file size limit, expressed in bytes.
@item -ss @var{position} (@emph{input/output})
When used as an input option (before @code{-i}), seeks in this input file to
@@ -275,6 +285,18 @@ 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.
@@ -287,12 +309,12 @@ also possible to delete metadata by using an empty value.
For example, for setting the title in the output file:
@example
-avconv -i in.avi -metadata title="my title" out.flv
+ffmpeg -i in.avi -metadata title="my title" out.flv
@end example
To set the language of the first audio stream:
@example
-avconv -i INPUT -metadata:s:a:0 language=eng OUTPUT
+ffmpeg -i INPUT -metadata:s:a:1 language=eng OUTPUT
@end example
@item -target @var{type} (@emph{output})
@@ -302,14 +324,14 @@ Specify target file type (@code{vcd}, @code{svcd}, @code{dvd}, @code{dv},
(bitrate, codecs, buffer sizes) are then set automatically. You can just type:
@example
-avconv -i myfile.avi -target vcd /tmp/vcd.mpg
+ffmpeg -i myfile.avi -target vcd /tmp/vcd.mpg
@end example
Nevertheless you can specify additional options as long as you know
they do not conflict with the standard, as in:
@example
-avconv -i myfile.avi -target vcd -bf 2 /tmp/vcd.mpg
+ffmpeg -i myfile.avi -target vcd -bf 2 /tmp/vcd.mpg
@end example
@item -dframes @var{number} (@emph{output})
@@ -323,13 +345,20 @@ Stop writing to the stream after @var{framecount} frames.
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).
+@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 also the @option{-filter_complex} option if you want to create filter graphs
-with multiple inputs and/or outputs.
+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
@@ -340,7 +369,34 @@ read.
Specify the preset for matching stream(s).
@item -stats (@emph{global})
-Print encoding progress/statistics. On by default.
+Print encoding progress/statistics. It is on by default, to explicitly
+disable it you need to specify @code{-nostats}.
+
+@item -progress @var{url} (@emph{global})
+Send program-friendly progress information to @var{url}.
+
+Progress information is written approximately every second and at the end of
+the encoding process. It is made of "@var{key}=@var{value}" lines. @var{key}
+consists of only alphanumeric characters. The last key of a sequence of
+progress information is always "progress".
+
+@item -stdin
+Enable interaction on standard input. On by default unless standard input is
+used as an input. To explicitly disable interaction you need to specify
+@code{-nostdin}.
+
+Disabling interaction on standard input is useful, for example, if
+ffmpeg is in the background process group. Roughly the same result can
+be achieved with @code{ffmpeg ... < /dev/null} but it requires a
+shell.
+
+@item -debug_ts (@emph{global})
+Print timestamp information. It is off by default. This option is
+mostly useful for testing and debugging purposes, and the output
+format may change from one version to another, so it should not be
+employed by portable scripts.
+
+See also the option @code{-fdebug ts}.
@item -attach @var{filename} (@emph{output})
Add an attachment to the output file. This is supported by a few formats
@@ -353,7 +409,7 @@ with @code{-map} or automatic mappings).
Note that for Matroska you also have to set the mimetype metadata tag:
@example
-avconv -i INPUT -attach DejaVuSans.ttf -metadata:s:2 mimetype=application/x-truetype-font out.mkv
+ffmpeg -i INPUT -attach DejaVuSans.ttf -metadata:s:2 mimetype=application/x-truetype-font out.mkv
@end example
(assuming that the attachment stream will be third in the output file).
@@ -364,11 +420,11 @@ will be used.
E.g. to extract the first attachment to a file named 'out.ttf':
@example
-avconv -dump_attachment:t:0 out.ttf INPUT
+ffmpeg -dump_attachment:t:0 out.ttf -i INPUT
@end example
To extract all attachments to files determined by the @code{filename} tag:
@example
-avconv -dump_attachment:t "" INPUT
+ffmpeg -dump_attachment:t "" -i INPUT
@end example
Technical note -- attachments are implemented as codec extradata, so this
@@ -389,8 +445,7 @@ 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).
+frame rate @var{fps}.
@item -s[:@var{stream_specifier}] @var{size} (@emph{input/output,per-stream})
Set frame size.
@@ -403,68 +458,7 @@ As an output option, this inserts the @code{scale} video filter to the
@emph{end} of the corresponding filtergraph. Please use the @code{scale} filter
directly to insert it at the beginning or some other place.
-The format is @samp{wxh} (default - same as source). The following
-abbreviations are recognized:
-@table @samp
-@item sqcif
-128x96
-@item qcif
-176x144
-@item cif
-352x288
-@item 4cif
-704x576
-@item 16cif
-1408x1152
-@item qqvga
-160x120
-@item qvga
-320x240
-@item vga
-640x480
-@item svga
-800x600
-@item xga
-1024x768
-@item uxga
-1600x1200
-@item qxga
-2048x1536
-@item sxga
-1280x1024
-@item qsxga
-2560x2048
-@item hsxga
-5120x4096
-@item wvga
-852x480
-@item wxga
-1366x768
-@item wsxga
-1600x1024
-@item wuxga
-1920x1200
-@item woxga
-2560x1600
-@item wqsxga
-3200x2048
-@item wquxga
-3840x2400
-@item whsxga
-6400x4096
-@item whuxga
-7680x4800
-@item cga
-320x200
-@item ega
-640x350
-@item hd480
-852x480
-@item hd720
-1280x720
-@item hd1080
-1920x1080
-@end table
+The format is @samp{wxh} (default - same as source).
@item -aspect[:@var{stream_specifier}] @var{aspect} (@emph{output,per-stream})
Set the video display aspect ratio specified by @var{aspect}.
@@ -474,6 +468,10 @@ form @var{num}:@var{den}, where @var{num} and @var{den} are the
numerator and denominator of the aspect ratio. For example "4:3",
"16:9", "1.3333", and "1.7777" are valid argument values.
+If used together with @option{-vcodec copy}, it will affect the aspect ratio
+stored at container level, but not the aspect ratio stored in encoded
+frames, if it exists.
+
@item -vn (@emph{output})
Disable video recording.
@@ -489,22 +487,24 @@ at the exact requested bitrate.
On pass 1, you may just deactivate audio and set output to null,
examples for Windows and Unix:
@example
-avconv -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y NUL
-avconv -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y /dev/null
+ffmpeg -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y NUL
+ffmpeg -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y /dev/null
@end example
@item -passlogfile[:@var{stream_specifier}] @var{prefix} (@emph{output,per-stream})
Set two-pass log file name prefix to @var{prefix}, the default file name
-prefix is ``av2pass''. The complete file name will be
+prefix is ``ffmpeg2pass''. The complete file name will be
@file{PREFIX-N.log}, where N is a number specific to the output
-stream.
+stream
-@item -vf @var{filter_graph} (@emph{output})
-@var{filter_graph} is a description of the filter graph to apply to
-the input video.
-Use the option "-filters" to show all the available filters (including
-also sources and sinks). This is an alias for @code{-filter:v}.
+@item -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
@@ -513,14 +513,33 @@ also sources and sinks). This is an alias for @code{-filter:v}.
@item -pix_fmt[:@var{stream_specifier}] @var{format} (@emph{input/output,per-stream})
Set pixel format. Use @code{-pix_fmts} to show all the supported
pixel formats.
+If the selected pixel format can not be selected, ffmpeg will print a
+warning and select the best pixel format supported by the encoder.
+If @var{pix_fmt} is prefixed by a @code{+}, ffmpeg will exit with an error
+if the requested pixel format can not be selected, and automatic conversions
+inside filtergraphs are disabled.
+If @var{pix_fmt} is a single @code{+}, ffmpeg selects the same pixel format
+as the input (or graph output) and automatic conversions are disabled.
+
@item -sws_flags @var{flags} (@emph{input/output})
Set SwScaler flags.
@item -vdt @var{n}
Discard threshold.
@item -rc_override[:@var{stream_specifier}] @var{override} (@emph{output,per-stream})
-rate control override for specific intervals
-
+Rate control override for specific intervals, formatted as "int,int,int"
+list separated with slashes. Two first values are the beginning and
+end frame numbers, last one is quantizer to use if positive, or quality
+factor if negative.
+
+@item -ilme
+Force interlacing support in encoder (MPEG-2 and MPEG-4 only).
+Use this option if your input file is interlaced and you want
+to keep the interlaced format for minimum losses.
+The alternative is to deinterlace the input stream with
+@option{-deinterlace}, but deinterlacing introduces losses.
+@item -psnr
+Calculate PSNR of compressed frames.
@item -vstats
Dump video coding statistics to @file{vstats_HHMMSS.log}.
@item -vstats_file @var{file}
@@ -532,13 +551,61 @@ Intra_dc_precision.
@item -vtag @var{fourcc/tag} (@emph{output})
Force video tag/fourcc. This is an alias for @code{-tag:v}.
@item -qphist (@emph{global})
-Show QP histogram.
+Show QP histogram
+@item -vbsf @var{bitstream_filter}
+Deprecated see -bsf
+
@item -force_key_frames[:@var{stream_specifier}] @var{time}[,@var{time}...] (@emph{output,per-stream})
+@item -force_key_frames[:@var{stream_specifier}] expr:@var{expr} (@emph{output,per-stream})
Force key frames at the specified timestamps, more precisely at the first
frames after each specified time.
+
+If the argument is prefixed with @code{expr:}, the string @var{expr}
+is interpreted like an expression and is evaluated for each frame. A
+key frame is forced in case the evaluation is non-zero.
+
+If one of the times is "@code{chapters}[@var{delta}]", it is expanded into
+the time of the beginning of all chapters in the file, shifted by
+@var{delta}, expressed as a time in seconds.
This option can be useful to ensure that a seek point is present at a
chapter mark or any other designated place in the output file.
-The timestamps must be specified in ascending order.
+
+For example, to insert a key frame at 5 minutes, plus key frames 0.1 second
+before the beginning of every chapter:
+@example
+-force_key_frames 0:05:00,chapters-0.1
+@end example
+
+The expression in @var{expr} can contain the following constants:
+@table @option
+@item n
+the number of current processed frame, starting from 0
+@item n_forced
+the number of forced frames
+@item prev_forced_n
+the number of the previous forced frame, it is @code{NAN} when no
+keyframe was forced yet
+@item prev_forced_t
+the time of the previous forced frame, it is @code{NAN} when no
+keyframe was forced yet
+@item t
+the time of the current processed frame
+@end table
+
+For example to force a key frame every 5 seconds, you can specify:
+@example
+-force_key_frames expr:gte(t,n_forced*5)
+@end example
+
+To force a key frame 5 seconds after the time of the last forced one,
+starting from second 13:
+@example
+-force_key_frames expr:if(isnan(prev_forced_t),gte(t,13),gte(t,prev_forced_t+5))
+@end example
+
+Note that forcing too many keyframes is very harmful for the lookahead
+algorithms of certain encoders: using fixed-GOP options or similar
+would be more efficient.
@item -copyinkf[:@var{stream_specifier}] (@emph{output,per-stream})
When doing stream copy, copy also non-key frames found at the
@@ -569,11 +636,12 @@ Set the audio codec. This is an alias for @code{-codec:a}.
@item -sample_fmt[:@var{stream_specifier}] @var{sample_fmt} (@emph{output,per-stream})
Set the audio sample format. Use @code{-sample_fmts} to get a list
of supported sample formats.
-@item -af @var{filter_graph} (@emph{output})
-@var{filter_graph} is a description of the filter graph to apply to
-the input audio.
-Use the option "-filters" to show all the available filters (including
-also sources and sinks). This is an alias for @code{-filter:a}.
+
+@item -af @var{filtergraph} (@emph{output})
+Create the filtergraph specified by @var{filtergraph} and use it to
+filter the stream.
+
+This is an alias for @code{-filter:a}, see the @ref{filter_option,,-filter option}.
@end table
@section Advanced Audio options:
@@ -581,15 +649,49 @@ also sources and sinks). This is an alias for @code{-filter:a}.
@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
@@ -617,7 +719,7 @@ graphs (see the @option{-filter_complex} option) to the output file.
For example, to map ALL streams from the first input file to output
@example
-avconv -i INPUT -map 0 output
+ffmpeg -i INPUT -map 0 output
@end example
For example, if you have two audio streams in the first input file,
@@ -625,7 +727,7 @@ these streams are identified by "0:0" and "0:1". You can use
@code{-map} to select which streams to place in an output file. For
example:
@example
-avconv -i INPUT -map 0:1 out.wav
+ffmpeg -i INPUT -map 0:1 out.wav
@end example
will map the input stream in @file{INPUT} identified by "0:1" to
the (single) output stream in @file{out.wav}.
@@ -635,21 +737,77 @@ For example, to select the stream with index 2 from input file
index 6 from input @file{b.mov} (specified by the identifier "1:6"),
and copy them to the output file @file{out.mov}:
@example
-avconv -i a.mov -i b.mov -c copy -map 0:2 -map 1:6 out.mov
+ffmpeg -i a.mov -i b.mov -c copy -map 0:2 -map 1:6 out.mov
@end example
To select all video and the third audio stream from an input file:
@example
-avconv -i INPUT -map 0:v -map 0:a:2 OUTPUT
+ffmpeg -i INPUT -map 0:v -map 0:a:2 OUTPUT
@end example
To map all the streams except the second audio, use negative mappings
@example
-avconv -i INPUT -map 0 -map -0:a:1 OUTPUT
+ffmpeg -i INPUT -map 0 -map -0:a:1 OUTPUT
@end example
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.
@@ -681,12 +839,12 @@ file index can be used to create a dummy mapping that just disables automatic co
For example to copy metadata from the first stream of the input file to global metadata
of the output file:
@example
-avconv -i in.ogg -map_metadata 0:s:0 out.mp3
+ffmpeg -i in.ogg -map_metadata 0:s:0 out.mp3
@end example
To do the reverse, i.e. copy global metadata to all audio streams:
@example
-avconv -i in.mkv -map_metadata:s:a 0:g out.mkv
+ffmpeg -i in.mkv -map_metadata:s:a 0:g out.mkv
@end example
Note that simple @code{0} would work as well in this example, since global
metadata is assumed by default.
@@ -696,38 +854,64 @@ Copy chapters from input file with index @var{input_file_index} to the next
output file. If no chapter mapping is specified, then chapters are copied from
the first input file with at least one chapter. Use a negative file index to
disable any chapter copying.
-@item -debug
-Print specific debug info.
+
@item -benchmark (@emph{global})
Show benchmarking information at the end of an encode.
Shows CPU time used and maximum memory consumption.
Maximum memory consumption is not supported on all systems,
it will usually display as 0 if not supported.
+@item -benchmark_all (@emph{global})
+Show benchmarking information during the encode.
+Shows CPU time used in various steps (audio/video encode/decode).
@item -timelimit @var{duration} (@emph{global})
-Exit after avconv has been running for @var{duration} seconds.
+Exit after ffmpeg has been running for @var{duration} seconds.
@item -dump (@emph{global})
Dump each input packet to stderr.
@item -hex (@emph{global})
When dumping packets, also dump the payload.
@item -re (@emph{input})
Read input at native frame rate. Mainly used to simulate a grab device.
+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). If
+your input(s) is coming from some other live streaming source (through HTTP or
+UDP for example) the server might already be in real-time, thus the option will
+likely not be required. On the other hand, this is meaningful if your input(s)
+is a file you are trying to push in real-time.
+@item -loop_input
+Loop over the input stream. Currently it works only for image
+streams. This option is used for automatic FFserver testing.
+This option is deprecated, use -loop 1.
+@item -loop_output @var{number_of_times}
+Repeatedly loop output for formats that support looping such as animated GIF
+(0 will loop the output infinitely).
+This option is deprecated, use -loop.
@item -vsync @var{parameter}
Video sync method.
+For compatibility reasons old values can be specified as numbers.
+Newly added values will have to be specified as strings always.
@table @option
-@item passthrough
+@item 0, passthrough
Each frame is passed with its timestamp from the demuxer to the muxer.
-@item cfr
+@item 1, cfr
Frames will be duplicated and dropped to achieve exactly the requested
-constant framerate.
-@item vfr
+constant frame rate.
+@item 2, vfr
Frames are passed through with their timestamp or dropped so as to
prevent 2 frames from having the same timestamp.
-@item auto
+@item drop
+As passthrough but destroys all timestamps, making the muxer generate
+fresh timestamps based on frame-rate.
+@item -1, auto
Chooses between 1 and 2 depending on muxer capabilities. This is the
default method.
@end table
+Note that the timestamps may be further modified by the muxer, after this.
+For example, in the case that the format option @option{avoid_negative_ts}
+is enabled.
+
With -map you can select from which stream the timestamps should be
taken. You can leave either video or audio unchanged and sync the
remaining stream(s) to the unchanged one.
@@ -737,11 +921,47 @@ Audio sync method. "Stretches/squeezes" the audio stream to match the timestamps
the parameter is the maximum samples per second by which the audio is changed.
-async 1 is a special case where only the start of the audio stream is corrected
without any later correction.
-This option has been deprecated. Use the @code{asyncts} audio filter instead.
+
+Note that the timestamps may be further modified by the muxer, after this.
+For example, in the case that the format option @option{avoid_negative_ts}
+is enabled.
+
+This option has been deprecated. Use the @code{aresample} audio filter instead.
+
@item -copyts
-Copy timestamps from input to output.
-@item -copytb
-Copy input stream time base from input to output when stream copying.
+Do not process input timestamps, but keep their values without trying
+to sanitize them. In particular, do not remove the initial start time
+offset value.
+
+Note that, depending on the @option{vsync} option or on specific muxer
+processing (e.g. in case the format option @option{avoid_negative_ts}
+is enabled) the output timestamps may mismatch with the input
+timestamps even when this option is selected.
+
+@item -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
@@ -759,32 +979,37 @@ may be reassigned to a different value.
For example, to set the stream 0 PID to 33 and the stream 1 PID to 36 for
an output mpegts file:
@example
-avconv -i infile -streamid 0:33 -streamid 1:36 out.ts
+ffmpeg -i infile -streamid 0:33 -streamid 1:36 out.ts
@end example
@item -bsf[:@var{stream_specifier}] @var{bitstream_filters} (@emph{output,per-stream})
-Set bitstream filters for matching streams. @var{bistream_filters} is
+Set bitstream filters for matching streams. @var{bitstream_filters} is
a comma-separated list of bitstream filters. Use the @code{-bsfs} option
to get the list of bitstream filters.
@example
-avconv -i h264.mp4 -c:v copy -bsf:v h264_mp4toannexb -an out.h264
+ffmpeg -i h264.mp4 -c:v copy -bsf:v h264_mp4toannexb -an out.h264
@end example
@example
-avconv -i file.mov -an -vn -bsf:s mov2textsub -c:s copy -f rawvideo sub.txt
+ffmpeg -i file.mov -an -vn -bsf:s mov2textsub -c:s copy -f rawvideo sub.txt
@end example
-@item -tag[:@var{stream_specifier}] @var{codec_tag} (@emph{output,per-stream})
+@item -tag[:@var{stream_specifier}] @var{codec_tag} (@emph{per-stream})
Force a tag/fourcc for matching streams.
-@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.
+@item -timecode @var{hh}:@var{mm}:@var{ss}SEP@var{ff}
+Specify Timecode for writing. @var{SEP} is ':' for non drop timecode and ';'
+(or '.') for drop.
+@example
+ffmpeg -i input.mpg -timecode 01:02:03.04 -r 30000/1001 -s ntsc output.mpg
+@end example
+@anchor{filter_complex_option}
@item -filter_complex @var{filtergraph} (@emph{global})
-Define a complex filter graph, i.e. one with arbitrary number of inputs and/or
+Define a complex filtergraph, i.e. one with arbitrary number of inputs and/or
outputs. For simple graphs -- those with one input and one output of the same
type -- see the @option{-filter} options. @var{filtergraph} is a description of
-the filter graph, as described in @ref{Filtergraph syntax}.
+the filtergraph, as described in the ``Filtergraph syntax'' section of the
+ffmpeg-filters manual.
Input link labels must refer to input streams using the
@code{[file_index:stream_specifier]} syntax (i.e. the same as @option{-map}
@@ -800,7 +1025,7 @@ normal input files.
For example, to overlay an image over video
@example
-avconv -i video.mkv -i image.png -filter_complex '[0:v][1:v]overlay[out]' -map
+ffmpeg -i video.mkv -i image.png -filter_complex '[0:v][1:v]overlay[out]' -map
'[out]' out.mkv
@end example
Here @code{[0:v]} refers to the first video stream in the first input file,
@@ -811,27 +1036,80 @@ of overlay.
Assuming there is only one video stream in each input file, we can omit input
labels, so the above is equivalent to
@example
-avconv -i video.mkv -i image.png -filter_complex 'overlay[out]' -map
+ffmpeg -i video.mkv -i image.png -filter_complex 'overlay[out]' -map
'[out]' out.mkv
@end example
Furthermore we can omit the output label and the single output from the filter
graph will be added to the output file automatically, so we can simply write
@example
-avconv -i video.mkv -i image.png -filter_complex 'overlay' out.mkv
+ffmpeg -i video.mkv -i image.png -filter_complex 'overlay' out.mkv
@end example
To generate 5 seconds of pure red video using lavfi @code{color} source:
@example
-avconv -filter_complex 'color=red' -t 5 out.mkv
+ffmpeg -filter_complex 'color=c=red' -t 5 out.mkv
@end example
+@item -lavfi @var{filtergraph} (@emph{global})
+Define a complex filtergraph, i.e. one with arbitrary number of inputs and/or
+outputs. Equivalent to @option{-filter_complex}.
+
@item -filter_complex_script @var{filename} (@emph{global})
This option is similar to @option{-filter_complex}, the only difference is that
its argument is the name of the file from which a complex filtergraph
description is to be read.
@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
@@ -845,7 +1123,7 @@ the Linux player does not seem to be very fast, so it can miss
frames. An example is:
@example
-avconv -g 3 -r 3 -t 10 -b 50k -s qcif -f rv10 /tmp/b.rm
+ffmpeg -g 3 -r 3 -t 10 -b:v 50k -s qcif -f rv10 /tmp/b.rm
@end example
@item
@@ -884,43 +1162,48 @@ A preset file contains a sequence of @var{option=value} pairs, one for
each line, specifying a sequence of options which can be specified also on
the command line. Lines starting with the hash ('#') character are ignored and
are used to provide comments. Empty lines are also ignored. Check the
-@file{presets} directory in the Libav source tree for examples.
+@file{presets} directory in the FFmpeg source tree for examples.
Preset files are specified with the @code{pre} option, this option takes a
-preset name as input. Avconv searches for a file named @var{preset_name}.avpreset in
-the directories @file{$AVCONV_DATADIR} (if set), and @file{$HOME/.avconv}, and in
-the data directory defined at configuration time (usually @file{$PREFIX/share/avconv})
+preset name as input. FFmpeg searches for a file named @var{preset_name}.avpreset in
+the directories @file{$AVCONV_DATADIR} (if set), and @file{$HOME/.ffmpeg}, and in
+the data directory defined at configuration time (usually @file{$PREFIX/share/ffmpeg})
in that order. For example, if the argument is @code{libx264-max}, it will
search for the file @file{libx264-max.avpreset}.
@section Video and Audio grabbing
-If you specify the input format and device then avconv can grab video
+If you specify the input format and device then ffmpeg can grab video
and audio directly.
@example
-avconv -f oss -i /dev/dsp -f video4linux2 -i /dev/video0 /tmp/out.mpg
+ffmpeg -f oss -i /dev/dsp -f video4linux2 -i /dev/video0 /tmp/out.mpg
+@end example
+
+Or with an ALSA audio source (mono input, card id 1) instead of OSS:
+@example
+ffmpeg -f alsa -ac 1 -i hw:1 -f video4linux2 -i /dev/video0 /tmp/out.mpg
@end example
Note that you must activate the right video source and channel before
-launching avconv with any TV viewer such as
+launching ffmpeg with any TV viewer such as
@uref{http://linux.bytesex.org/xawtv/, xawtv} by Gerd Knorr. You also
have to set the audio recording levels correctly with a
standard mixer.
@section X11 grabbing
-Grab the X11 display with avconv via
+Grab the X11 display with ffmpeg via
@example
-avconv -f x11grab -s cif -r 25 -i :0.0 /tmp/out.mpg
+ffmpeg -f x11grab -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
+ffmpeg -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
@@ -928,7 +1211,7 @@ variable. 10 is the x-offset and 20 the y-offset for the grabbing.
@section Video and Audio file format conversion
-Any supported file format and protocol can serve as input to avconv:
+Any supported file format and protocol can serve as input to ffmpeg:
Examples:
@itemize
@@ -936,7 +1219,7 @@ Examples:
You can use YUV files as input:
@example
-avconv -i /tmp/test%d.Y /tmp/out.mpg
+ffmpeg -i /tmp/test%d.Y /tmp/out.mpg
@end example
It will use the files:
@@ -948,13 +1231,13 @@ It will use the files:
The Y files use twice the resolution of the U and V files. They are
raw files, without header. They can be generated by all decent video
decoders. You must specify the size of the image with the @option{-s} option
-if avconv cannot guess it.
+if ffmpeg cannot guess it.
@item
You can input from a raw YUV420P file:
@example
-avconv -i /tmp/test.yuv /tmp/out.avi
+ffmpeg -i /tmp/test.yuv /tmp/out.avi
@end example
test.yuv is a file containing raw YUV planar data. Each frame is composed
@@ -965,14 +1248,14 @@ horizontal resolution.
You can output to a raw YUV420P file:
@example
-avconv -i mydivx.avi hugefile.yuv
+ffmpeg -i mydivx.avi hugefile.yuv
@end example
@item
You can set several input files and output files:
@example
-avconv -i /tmp/a.wav -s 640x480 -i /tmp/a.yuv /tmp/a.mpg
+ffmpeg -i /tmp/a.wav -s 640x480 -i /tmp/a.yuv /tmp/a.mpg
@end example
Converts the audio file a.wav and the raw YUV video file a.yuv
@@ -982,7 +1265,7 @@ to MPEG file a.mpg.
You can also do audio and video conversions at the same time:
@example
-avconv -i /tmp/a.wav -ar 22050 /tmp/a.mp2
+ffmpeg -i /tmp/a.wav -ar 22050 /tmp/a.mp2
@end example
Converts a.wav to MPEG audio at 22050 Hz sample rate.
@@ -992,7 +1275,7 @@ You can encode to several formats at the same time and define a
mapping from input stream to output streams:
@example
-avconv -i /tmp/a.wav -map 0:a -b 64k /tmp/a.mp2 -map 0:a -b 128k /tmp/b.mp2
+ffmpeg -i /tmp/a.wav -map 0:a -b:a 64k /tmp/a.mp2 -map 0:a -b:a 128k /tmp/b.mp2
@end example
Converts a.wav to a.mp2 at 64 kbits and to b.mp2 at 128 kbits. '-map
@@ -1003,7 +1286,7 @@ stream, in the order of the definition of output streams.
You can transcode decrypted VOBs:
@example
-avconv -i snatch_1.vob -f avi -c:v mpeg4 -b:v 800k -g 300 -bf 2 -c:a libmp3lame -b:a 128k snatch.avi
+ffmpeg -i snatch_1.vob -f avi -c:v mpeg4 -b:v 800k -g 300 -bf 2 -c:a libmp3lame -b:a 128k snatch.avi
@end example
This is a typical DVD ripping example; the input is a VOB file, the
@@ -1015,14 +1298,14 @@ to enable LAME support by passing @code{--enable-libmp3lame} to configure.
The mapping is particularly useful for DVD transcoding
to get the desired audio language.
-NOTE: To see the supported input formats, use @code{avconv -formats}.
+NOTE: To see the supported input formats, use @code{ffmpeg -formats}.
@item
You can extract images from a video, or create a video from many images:
For extracting images from a video:
@example
-avconv -i foo.avi -r 1 -s WxH -f image2 foo-%03d.jpeg
+ffmpeg -i foo.avi -r 1 -s WxH -f image2 foo-%03d.jpeg
@end example
This will extract one video frame per second from the video and will
@@ -1035,7 +1318,7 @@ combination with -ss to start extracting from a certain point in time.
For creating a video from many images:
@example
-avconv -f image2 -i foo-%03d.jpeg -r 12 -s WxH foo.avi
+ffmpeg -f image2 -i foo-%03d.jpeg -r 12 -s WxH foo.avi
@end example
The syntax @code{foo-%03d.jpeg} specifies to use a decimal number
@@ -1043,11 +1326,21 @@ composed of three digits padded with zeroes to express the sequence
number. It is the same syntax supported by the C printf function, but
only formats accepting a normal integer are suitable.
+When importing an image sequence, -i also supports expanding
+shell-like wildcard patterns (globbing) internally, by selecting the
+image2-specific @code{-pattern_type glob} option.
+
+For example, for creating a video from filenames matching the glob pattern
+@code{foo-*.jpeg}:
+@example
+ffmpeg -f image2 -pattern_type glob -i 'foo-*.jpeg' -r 12 -s WxH foo.avi
+@end example
+
@item
You can put many streams of the same type in the output:
@example
-avconv -i test1.avi -i test2.avi -map 0.3 -map 0.2 -map 0.1 -map 0.0 -c copy test12.nut
+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
@@ -1056,42 +1349,86 @@ 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
+ffmpeg -i myfile.avi -b 4000k -minrate 4000k -maxrate 4000k -bufsize 1835k out.m2v
@end example
@item
The four options lmin, lmax, mblmin and mblmax use 'lambda' units,
but you may use the QP2LAMBDA constant to easily convert from 'q' units:
@example
-avconv -i src.ext -lmax 21*QP2LAMBDA dst.ext
+ffmpeg -i src.ext -lmax 21*QP2LAMBDA dst.ext
@end example
@end itemize
@c man end EXAMPLES
-@include eval.texi
-@include encoders.texi
-@include demuxers.texi
-@include muxers.texi
-@include indevs.texi
-@include outdevs.texi
-@include protocols.texi
+@include config.texi
+@ifset config-all
+@ifset config-avutil
+@include utils.texi
+@end ifset
+@ifset config-avcodec
+@include codecs.texi
@include bitstream_filters.texi
+@end ifset
+@ifset config-avformat
+@include formats.texi
+@include protocols.texi
+@end ifset
+@ifset config-avdevice
+@include devices.texi
+@end ifset
+@ifset config-swresample
+@include resampler.texi
+@end ifset
+@ifset config-swscale
+@include scaler.texi
+@end ifset
+@ifset config-avfilter
@include filters.texi
-@include metadata.texi
+@end ifset
+@end ifset
+
+@chapter See Also
+
+@ifhtml
+@ifset config-all
+@url{ffmpeg.html,ffmpeg}
+@end ifset
+@ifset config-not-all
+@url{ffmpeg-all.html,ffmpeg-all},
+@end ifset
+@url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-utils.html,ffmpeg-utils},
+@url{ffmpeg-scaler.html,ffmpeg-scaler},
+@url{ffmpeg-resampler.html,ffmpeg-resampler},
+@url{ffmpeg-codecs.html,ffmpeg-codecs},
+@url{ffmpeg-bitstream-filters.html,ffmpeg-bitstream-filters},
+@url{ffmpeg-formats.html,ffmpeg-formats},
+@url{ffmpeg-devices.html,ffmpeg-devices},
+@url{ffmpeg-protocols.html,ffmpeg-protocols},
+@url{ffmpeg-filters.html,ffmpeg-filters}
+@end ifhtml
+
+@ifnothtml
+@ifset config-all
+ffmpeg(1),
+@end ifset
+@ifset config-not-all
+ffmpeg-all(1),
+@end ifset
+ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1),
+ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1),
+ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1)
+@end ifnothtml
+
+@include authors.texi
@ignore
-@setfilename avconv
-@settitle avconv video converter
-
-@c man begin SEEALSO
-avplay(1), avprobe(1) and the Libav HTML documentation
-@c man end
-
-@c man begin AUTHORS
-The Libav developers
-@c man end
+@setfilename ffmpeg
+@settitle ffmpeg video converter
@end ignore
diff --git a/doc/ffmpeg.txt b/doc/ffmpeg.txt
new file mode 100644
index 0000000..a028ca2
--- /dev/null
+++ b/doc/ffmpeg.txt
@@ -0,0 +1,47 @@
+ :
+ ffmpeg.c : libav*
+ ======== : ======
+ :
+ :
+ --------------------------------:---> AVStream...
+ InputStream input_streams[] / :
+ / :
+ InputFile input_files[] +==========================+ / ^ :
+ ------> 0 | : st ---:-----------:--/ : :
+ ^ +------+-----------+-----+ / +--------------------------+ : :
+ : | :ist_index--:-----:---------/ 1 | : st : | : :
+ : +------+-----------+-----+ +==========================+ : :
+ nb_input_files : | :ist_index--:-----:------------------> 2 | : st : | : :
+ : +------+-----------+-----+ +--------------------------+ : nb_input_streams :
+ : | :ist_index : | 3 | ... | : :
+ v +------+-----------+-----+ +--------------------------+ : :
+ --> 4 | | : :
+ | +--------------------------+ : :
+ | 5 | | : :
+ | +==========================+ v :
+ | :
+ | :
+ | :
+ | :
+ --------- --------------------------------:---> AVStream...
+ \ / :
+ OutputStream output_streams[] / :
+ \ / :
+ +======\======================/======+ ^ :
+ ------> 0 | : source_index : st-:--- | : :
+ OutputFile output_files[] / +------------------------------------+ : :
+ / 1 | : : : | : :
+ ^ +------+------------+-----+ / +------------------------------------+ : :
+ : | : ost_index -:-----:------/ 2 | : : : | : :
+ nb_output_files : +------+------------+-----+ +====================================+ : :
+ : | : ost_index -:-----|-----------------> 3 | : : : | : :
+ : +------+------------+-----+ +------------------------------------+ : nb_output_streams :
+ : | : : | 4 | | : :
+ : +------+------------+-----+ +------------------------------------+ : :
+ : | : : | 5 | | : :
+ v +------+------------+-----+ +------------------------------------+ : :
+ 6 | | : :
+ +------------------------------------+ : :
+ 7 | | : :
+ +====================================+ v :
+ :
diff --git a/doc/ffplay.texi b/doc/ffplay.texi
new file mode 100644
index 0000000..943cbb9
--- /dev/null
+++ b/doc/ffplay.texi
@@ -0,0 +1,274 @@
+\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 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}
+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.
+
+@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 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..01e9829
--- /dev/null
+++ b/doc/ffprobe.texi
@@ -0,0 +1,560 @@
+\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" or "STREAM" section.
+
+@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 -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 an 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 -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 -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 or
+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..eab97fb
--- /dev/null
+++ b/doc/ffprobe.xsd
@@ -0,0 +1,198 @@
+<?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="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="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="tag" type="ffprobe:tagType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="disposition" type="ffprobe:streamDispositionType" minOccurs="0" maxOccurs="1"/>
+ </xsd:sequence>
+
+ <xsd:attribute name="index" type="xsd:int" use="required"/>
+ <xsd:attribute name="codec_name" type="xsd:string" />
+ <xsd:attribute name="codec_long_name" type="xsd:string" />
+ <xsd:attribute name="profile" type="xsd:string" />
+ <xsd:attribute name="codec_type" type="xsd:string" />
+ <xsd:attribute name="codec_time_base" type="xsd:string" use="required"/>
+ <xsd:attribute name="codec_tag" type="xsd:string" use="required"/>
+ <xsd:attribute name="codec_tag_string" type="xsd:string" use="required"/>
+ <xsd:attribute name="extradata" type="xsd:string" />
+
+ <!-- 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="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="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="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: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="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/avserver.conf b/doc/ffserver.conf
index e1cd9fb..0f5922c 100644
--- a/doc/avserver.conf
+++ b/doc/ffserver.conf
@@ -12,7 +12,7 @@ BindAddress 0.0.0.0
# MaxClients maximum limit.
MaxHTTPConnections 2000
-# Number of simultaneous requests that can be handled. Since AVServer
+# 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
@@ -25,21 +25,20 @@ MaxBandwidth 1000
# '-' 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
+# 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 'avconv' to send a live feed to avserver. In this
+# You must use 'ffmpeg' to send a live feed to ffserver. In this
# example, you can type:
#
-# avconv http://localhost:8090/feed1.ffm
+# ffmpeg http://localhost:8090/feed1.ffm
-# avserver can also do time shifting. It means that it can stream any
+# 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
@@ -52,10 +51,10 @@ FileMaxSize 200K
# 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,
+# 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 avconv
+#Launch ffmpeg
# Only allow connections from localhost to the feed.
ACL allow 127.0.0.1
@@ -66,7 +65,7 @@ ACL allow 127.0.0.1
##################################################################
# 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
+# 'test1.mpg'). FFServer will send this stream when answering a
# request containing this filename.
<Stream test1.mpg>
@@ -331,7 +330,7 @@ StartSendOnKey
# multicast address with MulticastAddress. The port and the TTL can
# also be set.
#
-# An SDP file is automatically generated by avserver by adding the
+# 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.
@@ -368,5 +367,5 @@ ACL allow 192.168.0.0 192.168.255.255
# Redirect index.html to the appropriate site
<Redirect index.html>
-URL http://www.libav.org/
+URL http://www.ffmpeg.org/
</Redirect>
diff --git a/doc/avserver.texi b/doc/ffserver.texi
index 88e6221..bfc2e60 100644
--- a/doc/avserver.texi
+++ b/doc/ffserver.texi
@@ -1,62 +1,47 @@
\input texinfo @c -*- texinfo -*-
-@settitle avserver Documentation
+@settitle ffserver Documentation
@titlepage
-@center @titlefont{avserver Documentation}
+@center @titlefont{ffserver Documentation}
@end titlepage
@top
@contents
-@chapter Synopsys
+@chapter Synopsis
-The generic syntax is:
-
-@example
-@c man begin SYNOPSIS
-avserver [options]
-@c man end
-@end example
+ffserver [@var{options}]
@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).
+@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}).
-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.
+@command{ffserver} receives prerecorded files or FFM streams from some
+@command{ffmpeg} instance as input, then streams them over
+RTP/RTSP/HTTP.
-@section How does it work?
+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.
-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.
+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 <Stream> section in the configuration
-file.
+formats, each one specified by a @code{<Stream>} section in the
+configuration file.
@section Status stream
-avserver supports an HTTP interface which exposes the current status
+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
@@ -88,29 +73,21 @@ 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
+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 avconv:
+is some file which you can decode with ffmpeg:
@example
-./avserver -f doc/avserver.conf &
-./avconv -i INPUTFILE http://localhost:8090/feed1.ffm
+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
@@ -128,8 +105,8 @@ 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
+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
@@ -137,13 +114,13 @@ them up, and off you go.
@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
+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 avconv.
+starting ffmpeg.
@subsection The audio and video lose sync after a while.
@@ -165,14 +142,14 @@ I suspect that the new one is not available unless you have installed WMP 7].
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.
+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
-avserver.conf for a list of the currently available controls.
+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
@@ -186,7 +163,7 @@ finishes.]
* 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
+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
@@ -194,13 +171,13 @@ 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
+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, avserver will skip frames until a key_frame
+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 avserver.conf to limit
+* 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?
@@ -217,7 +194,7 @@ 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),
+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
@@ -236,6 +213,19 @@ 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
@@ -245,31 +235,85 @@ For example: @samp{http://localhost:8080/test.asf?date=2002-07-26T23:05:00}.
@table @option
@item -f @var{configfile}
-Use @file{configfile} instead of @file{/etc/avserver.conf}.
+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 avserver will not launch
-any avconv instances, you will have to launch them manually.
+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
-@ignore
-
-@setfilename avserver
-@settitle avserver video server
-
-@c man begin SEEALSO
+@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
-avconv(1), avplay(1), avprobe(1), the @file{avserver.conf}
-example and the Libav HTML documentation
-@c man end
+@ignore
-@c man begin AUTHORS
-The Libav developers
-@c man end
+@setfilename ffserver
+@settitle ffserver video server
@end ignore
diff --git a/doc/filter_design.txt b/doc/filter_design.txt
new file mode 100644
index 0000000..c303c3c
--- /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 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 2ee5ad5..cf2c1a4 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -1,3 +1,99 @@
+@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
+input --> split ---------------------> overlay --> output
+ | ^
+ | |
+ +-----> 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 +115,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 +137,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 +151,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 +214,231 @@ 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 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:
@@ -150,13 +462,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 +585,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 +720,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 +744,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,7 +858,32 @@ with a negative pts due to encoder delay.
@end table
+@section atempo
+
+Adjust audio tempo.
+
+The filter accepts exactly one parameter, the audio tempo. If not
+specified then the filter will assume nominal 1.0 tempo. Tempo must
+be in the [0.5, 2.0] range.
+
+@subsection Examples
+
+@itemize
+@item
+Slow down audio to 80% tempo:
+@example
+atempo=0.8
+@end example
+
+@item
+To speed up audio to 125% tempo:
+@example
+atempo=1.25
+@end example
+@end itemize
+
@section atrim
+
Trim the input so that the output contains one continuous subpart of the input.
This filter accepts the following options:
@@ -398,43 +936,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 +1076,126 @@ 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 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 +1222,225 @@ 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 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 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 +1456,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 +1482,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 +1495,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 an histogram of the
+registered volume values (from the maximum value to a cumulated 1/1000 of
+the samples).
+
+All volumes are in decibels relative to the maximum PCM value.
-Null audio source, never return audio frames. It is mainly useful as a
-template and to be employed in analysis / debugging tools.
+@subsection Examples
-It accepts as optional parameter a string of the form
-@var{sample_rate}:@var{channel_layout}.
+Here is an excerpt of the output:
+@example
+[Parsed_volumedetect_0 @ 0xa23120] mean_volume: -27 dB
+[Parsed_volumedetect_0 @ 0xa23120] max_volume: -4 dB
+[Parsed_volumedetect_0 @ 0xa23120] histogram_4db: 6
+[Parsed_volumedetect_0 @ 0xa23120] histogram_5db: 62
+[Parsed_volumedetect_0 @ 0xa23120] histogram_6db: 286
+[Parsed_volumedetect_0 @ 0xa23120] histogram_7db: 1042
+[Parsed_volumedetect_0 @ 0xa23120] histogram_8db: 2551
+[Parsed_volumedetect_0 @ 0xa23120] histogram_9db: 4609
+[Parsed_volumedetect_0 @ 0xa23120] histogram_10db: 8409
+@end example
-@var{sample_rate} specify the sample rate, and defaults to 44100.
+It means that:
+@itemize
+@item
+The mean square energy is approximately -27 dB, or 10^-2.7.
+@item
+The largest sample is at -4 dB, or more precisely between -4 dB and -5 dB.
+@item
+There are 6 samples at -4 dB, 62 at -5 dB, 286 at -6 dB, etc.
+@end itemize
-@var{channel_layout} 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.
+In other words, raising the volume by +4 dB does not cause any clipping,
+raising it by +5 dB causes clipping for 6 samples, etc.
-Check the channel_layout_map definition in
-@file{libavutil/channel_layout.c} for the mapping between strings and
-channel layout values.
+@c man end AUDIO FILTERS
-Follow some examples:
-@example
-# set the sample rate to 48000 Hz and the channel layout to CH_LAYOUT_MONO.
-anullsrc=48000:4
+@chapter Audio Sources
+@c man begin AUDIO SOURCES
-# same as
-anullsrc=48000:mono
-@end example
+Below is a description of the currently available audio sources.
@section abuffer
+
Buffer audio frames, and make them available to the filter chain.
-This source is not intended to be part of user-supplied graph descriptions 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 +1560,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, s
+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 +1854,129 @@ 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.
+
+@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 +1992,342 @@ 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}.
+
+@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 threshold
-Threshold below which a pixel value is considered black, defaults to 32.
+@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
@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
+@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 +2337,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 +2426,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=100:100:12:34
+@end example
+
+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 the central input area with size 100x100
-crop=out_w=100:out_h=100
+crop=100:100
+@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"
+@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 +2516,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 +2757,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.
@@ -927,10 +2778,9 @@ finding the right @var{x}, @var{y}, @var{w}, @var{h} parameters, and
@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 +2790,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,97 +2877,135 @@ Draw a colored box on the input image.
This filter accepts the following options:
@table @option
-
-@item x, y
+@item x
+@item y
Specify the top left corner coordinates of the box. Default to 0.
-@item width, height
+@item width, w
+@item height, h
Specify the width and height of the box, if 0 they are interpreted as
the input width and height. Default to 0.
-@item color
+@item color, c
Specify the color of the box to write, it can be the name of a color
-(case insensitive match) or a 0xRRGGBB[AA] sequence.
+(case insensitive match) or a 0xRRGGBB[AA] sequence. If the special
+value @code{invert} is used, the box edge color is the same as the
+video with inverted luma.
+
+@item thickness, t
+Set the thickness of the box edge. Default value is @code{4}.
@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
+@end itemize
-To enable compilation of this filter you need to configure Libav with
-@code{--enable-libfreetype}.
+@section drawgrid
-The filter also recognizes strftime() sequences in the provided text
-and expands them accordingly. Check the documentation of strftime().
+Draw a grid on the input image.
-The description of the accepted parameters follows.
+This filter accepts the following options:
@table @option
+@item x
+@item y
+Specify the coordinates of some point of grid intersection (meant to configure offset). Both default to 0.
+
+@item width, w
+@item height, h
+Specify the width and height of the grid cell, if 0 they are interpreted as the
+input width and height, respectively, minus @code{thickness}, so image gets
+framed. Default to 0.
+
+@item color, c
+Specify the color of the grid, it can be the name of a color
+(case insensitive match) or a 0xRRGGBB[AA] sequence. If the special
+value @code{invert} is used, the grid color is the same as the
+video with inverted luma.
+Note that you can append opacity value (in range of 0.0 - 1.0)
+to color name after @@ sign.
+
+@item thickness, t
+Set the thickness of the grid line. Default value is @code{1}.
+@end table
-@item fontfile
-The font file to be used for drawing text. Path must be included.
-This parameter is mandatory.
-
-@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}.
+@subsection Examples
-@item textfile
-A text file containing text to be drawn. The text must be a sequence
-of UTF-8 encoded characters.
+@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
+@end itemize
-This parameter is mandatory if no text string is specified with the
-parameter @var{text}.
+@anchor{drawtext}
+@section drawtext
-If both text and textfile are specified, an error is thrown.
+Draw text string or text from specified file on top of video using the
+libfreetype library.
-@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
+To enable compilation of this filter you need to configure FFmpeg with
+@code{--enable-libfreetype}.
-@item x, y
-the computed values for @var{x} and @var{y}. They are evaluated for
-each new frame.
+@subsection Syntax
-@item main_w, main_h
-main input width and height
+The description of the accepted parameters follows.
-@item W, H
-same as @var{main_w} and @var{main_h}
+@table @option
-@item text_w, text_h
-rendered text width and height
+@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 w, h
-same as @var{text_w} and @var{text_h}
+@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".
-@item n
-the number of frames processed, starting from 0
+@item draw
+Set an expression which specifies if the text should be drawn. If the
+expression evaluates to 0, the text is not drawn. This is useful for
+specifying that the text should be drawn only when specific conditions
+are met.
-@item t
-timestamp expressed in seconds, NAN if the input timestamp is unknown
+Default value is "1".
-@end table
+See below for the list of accepted constants and functions.
-The default value of @var{x} and @var{y} is 0.
+@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 fontsize
-The font size to be used for drawing text.
-The default value of @var{fontsize} is 16.
+@item fix_bounds
+If true, check and fix text coords to avoid clipping.
@item fontcolor
The color to be used for drawing fonts.
@@ -1045,27 +3013,13 @@ Either a string (e.g. "red") or in 0xRRGGBB[AA] format
(e.g. "0xff000033"), possibly followed by an alpha specifier.
The default value of @var{fontcolor} is "black".
-@item boxcolor
-The color to be used for drawing box around text.
-Either a string (e.g. "yellow") or in 0xRRGGBB[AA] format
-(e.g. "0xff00ff"), possibly followed by an alpha specifier.
-The default value of @var{boxcolor} is "white".
-
-@item box
-Used to draw a box around text using 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 fontfile
+The font file to be used for drawing text. Path must be included.
+This parameter is mandatory.
-@item shadowcolor
-The color to be used for drawing a shadow behind the drawn text. It
-can be a color name (e.g. "yellow") or a string in the 0xRRGGBB[AA]
-form (e.g. "0xff00ff"), possibly followed by an alpha specifier.
-The default value of @var{shadowcolor} is "black".
+@item 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 +3042,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 +3049,336 @@ 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. It
+can be a color name (e.g. "yellow") or a string in the 0xRRGGBB[AA]
+form (e.g. "0xff00ff"), possibly followed by an alpha specifier.
+The default value of @var{shadowcolor} is "black".
+
+@item 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 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 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:draw=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 +3386,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:0:30
+@end example
+
+The command above is equivalent to:
@example
-# fade in first 30 frames of video
-fade=type=in:nb_frames=30
+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 wont risk creating jerkiness due to duplicate frames when
+possible, but if there are bad edits or blended fields it will end up
+outputting combed frames when a good match might actually exist. On the other
+hand, @option{pcn_ub} mode is the most risky in terms of creating jerkiness,
+but will almost always find a good frame if there is one. The other values are
+all somewhere in between @option{pc} and @option{pcn_ub} in terms of risking
+jerkiness and creating duplicate frames versus finding good matches in sections
+with bad edits, orphaned fields, blended fields, etc.
+
+More details about p/c/n/u/b are available in @ref{p/c/n/u/b meaning} section.
+
+Available values are:
+
+@table @samp
+@item pc
+2-way matching (p/c)
+@item pc_n
+2-way matching, and trying 3rd match if still combed (p/c + n)
+@item pc_u
+2-way matching, and trying 3rd match (same order) if still combed (p/c + u)
+@item pc_n_ub
+2-way matching, trying 3rd match if still combed, and trying 4th/5th matches if
+still combed (p/c + n + u/b)
+@item pcn
+3-way matching (p/c/n)
+@item pcn_ub
+3-way matching, and trying 4th/5th matches if all 3 of the original matches are
+detected as combed (p/c/n + u/b)
+@end table
+
+The parenthesis at the end indicate the matches that would be used for that
+mode assuming @option{order}=@var{tff} (and @option{field} on @var{auto} or
+@var{top}).
+
+In terms of speed @option{pc} mode is by far the fastest and @option{pcn_ub} is
+the slowest.
+
+Default value is @var{pc_n}.
+
+@item ppsrc
+Mark the main input stream as a pre-processed input, and enable the secondary
+input stream as the clean source to pick the fields from. See the filter
+introduction for more details. It is similar to the @option{clip2} feature from
+VFM/TFM.
+
+Default value is @code{0} (disabled).
+
+@item field
+Set the field to match from. It is recommended to set this to the same value as
+@option{order} unless you experience matching failures with that setting. In
+certain circumstances changing the field that is used to match from can have a
+large impact on matching performance. Available values are:
+
+@table @samp
+@item auto
+Automatic (same value as @option{order}).
+@item bottom
+Match from the bottom field.
+@item top
+Match from the top field.
+@end table
+
+Default value is @var{auto}.
+
+@item mchroma
+Set whether or not chroma is included during the match comparisons. In most
+cases it is recommended to leave this enabled. You should set this to @code{0}
+only if your clip has bad chroma problems such as heavy rainbowing or other
+artifacts. Setting this to @code{0} could also be used to speed things up at
+the cost of some accuracy.
+
+Default value is @code{1}.
+
+@item y0
+@item y1
+These define an exclusion band which excludes the lines between @option{y0} and
+@option{y1} from being included in the field matching decision. An exclusion
+band can be used to ignore subtitles, a logo, or other things that may
+interfere with the matching. @option{y0} sets the starting scan line and
+@option{y1} sets the ending line; all lines in between @option{y0} and
+@option{y1} (including @option{y0} and @option{y1}) will be ignored. Setting
+@option{y0} and @option{y1} to the same value will disable the feature.
+@option{y0} and @option{y1} defaults to @code{0}.
+
+@item scthresh
+Set the scene change detection threshold as a percentage of maximum change on
+the luma plane. Good values are in the @code{[8.0, 14.0]} range. Scene change
+detection is only relevant in case @option{combmatch}=@var{sc}. The range for
+@option{scthresh} is @code{[0.0, 100.0]}.
+
+Default value is @code{12.0}.
+
+@item combmatch
+When @option{combatch} is not @var{none}, @code{fieldmatch} will take into
+account the combed scores of matches when deciding what match to use as the
+final match. Available values are:
+
+@table @samp
+@item none
+No final matching based on combed scores.
+@item sc
+Combed scores are only used when a scene change is detected.
+@item full
+Use combed scores all the time.
+@end table
+
+Default is @var{sc}.
+
+@item combdbg
+Force @code{fieldmatch} to calculate the combed metrics for certain matches and
+print them. This setting is known as @option{micout} in TFM/VFM vocabulary.
+Available values are:
+
+@table @samp
+@item none
+No forced calculation.
+@item pcn
+Force p/c/n calculations.
+@item pcnub
+Force p/c/n/u/b calculations.
+@end table
+
+Default value is @var{none}.
+
+@item cthresh
+This is the area combing threshold used for combed frame detection. This
+essentially controls how "strong" or "visible" combing must be to be detected.
+Larger values mean combing must be more visible and smaller values mean combing
+can be less visible or strong and still be detected. Valid settings are from
+@code{-1} (every pixel will be detected as combed) to @code{255} (no pixel will
+be detected as combed). This is basically a pixel difference value. A good
+range is @code{[8, 12]}.
+
+Default value is @code{9}.
+
+@item chroma
+Sets whether or not chroma is considered in the combed frame decision. Only
+disable this if your source has chroma problems (rainbowing, etc.) that are
+causing problems for the combed frame detection with chroma enabled. Actually,
+using @option{chroma}=@var{0} is usually more reliable, except for the case
+where there is chroma only combing in the source.
+
+Default value is @code{0}.
+
+@item blockx
+@item blocky
+Respectively set the x-axis and y-axis size of the window used during combed
+frame detection. This has to do with the size of the area in which
+@option{combpel} pixels are required to be detected as combed for a frame to be
+declared combed. See the @option{combpel} parameter description for more info.
+Possible values are any number that is a power of 2 starting at 4 and going up
+to 512.
+
+Default value is @code{16}.
+
+@item combpel
+The number of combed pixels inside any of the @option{blocky} by
+@option{blockx} size blocks on the frame for the frame to be detected as
+combed. While @option{cthresh} controls how "visible" the combing must be, this
+setting controls "how much" combing there must be in any localized area (a
+window defined by the @option{blockx} and @option{blocky} settings) on the
+frame. Minimum value is @code{0} and maximum is @code{blocky x blockx} (at
+which point no frames will ever be detected as combed). This setting is known
+as @option{MI} in TFM/VFM vocabulary.
+
+Default value is @code{80}.
+@end table
+
+@anchor{p/c/n/u/b meaning}
+@subsection p/c/n/u/b meaning
+
+@subsubsection p/c/n
+
+We assume the following telecined stream:
+
+@example
+Top fields: 1 2 2 3 4
+Bottom fields: 1 2 3 4 4
+@end example
+
+The numbers correspond to the progressive frame the fields relate to. Here, the
+first two frames are progressive, the 3rd and 4th are combed, and so on.
-# 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
+When @code{fieldmatch} is configured to run a matching from bottom
+(@option{field}=@var{bottom}) this is how this input stream get transformed:
-# make first 5 frames black, then fade in from frame 5-24
-fade=type=in:start_frame=5:nb_frames=20
+@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 +3814,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 +3829,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 +3841,7 @@ framework.
The filter does not take parameters.
+@anchor{format}
@section format
Convert the input video to one of the specified pixel formats.
@@ -1221,35 +3857,91 @@ 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}.
@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,28 +3970,141 @@ description), a position (specified by the syntax @var{X}/@var{Y},
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
+the luminance expression
+@item cb_expr
+the chrominance blue expression
+@item cr_expr
+the chrominance red expression
+@item alpha_expr
+the alpha expression
+@item r
+the red expression
+@item g
+the green expression
+@item b
+the blue expression
+@end table
+
+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 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. Returns 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. Returns 0 if there is no such plane.
+
+@item alpha(x, y)
+Return the value of the pixel at location (@var{x},@var{y}) of the alpha
+plane. Returns 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
+@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.
@@ -1325,23 +4130,189 @@ will be clipped to the valid range.
@end table
+Alternatively, the options can be specified as a flat string:
+@var{strength}[:@var{radius}]
+
+@subsection Examples
+
+@itemize
+@item
+Apply the filter with a @code{3.5} strength and radius of @code{8}:
@example
-# default parameters
-gradfun=strength=1.2:radius=16
+gradfun=3.5:8
+@end example
-# omitting radius
-gradfun=1.2
+@item
+Specify radius, omitting the strength (which will fall-back to the default
+value):
+@example
+gradfun=radius=8
@end example
+@end itemize
+
@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
-avconv -i in.avi -vf "hflip" out.avi
+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 G, B, R 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 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
+ffplay -i input -vf histogram
+@end example
+
+@end itemize
+
+@anchor{hqdn3d}
@section hqdn3d
High precision/quality 3d denoise filter. This filter aims to reduce
@@ -1368,6 +4339,162 @@ 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".
+@end table
+
+@option{h} and @option{H} are mutually exclusive, and can't be
+specified at the same time.
+
+The @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 s
+@item h
+@item H
+Modify the hue and/or the saturation 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, s
+@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
@@ -1398,6 +4525,58 @@ Enable (default) or disable the vertical lowpass filter to avoid twitter
interlacing and reduce moire patterns.
@end table
+@section kerndeint
+
+Deinterlace input video by applying Donald Graft's adaptive kernel
+deinterling. Work on interlaced parts of a video to produce
+progressive frames.
+
+The description of the accepted parameters follows.
+
+@table @option
+@item thresh
+Set the threshold which affects the filter's tolerance when
+determining if a pixel line must be processed. It must be an integer
+in the range [0,255] and defaults to 10. A value of 0 will result in
+applying the process on every pixels.
+
+@item map
+Paint pixels exceeding the threshold value to white if set to 1.
+Default is 0.
+
+@item order
+Set the fields order. Swap fields if set to 1, leave fields alone if
+0. Default is 0.
+
+@item sharp
+Enable additional sharpening if set to 1. Default is 0.
+
+@item twoway
+Enable twoway sharpening if set to 1. Default is 0.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Apply default values:
+@example
+kerndeint=thresh=10:map=0:order=0:sharp=0:twoway=0
+@end example
+
+@item
+Enable additional sharpening:
+@example
+kerndeint=sharp=1
+@end example
+
+@item
+Paint processed pixels in white:
+@example
+kerndeint=map=1
+@end example
+@end itemize
+
@section lut, lutrgb, lutyuv
Compute a look-up table for binding each pixel component input value
@@ -1408,19 +4587,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
@@ -1435,11 +4625,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
@@ -1473,35 +4660,159 @@ 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 mp
+
+Apply an MPlayer filter to the input video.
+
+This filter provides a wrapper around most 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 filters 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 dint
+@item eq2
+@item eq
+@item fil
+@item fspp
+@item ilpack
+@item mcdeint
+@item perspective
+@item phase
+@item pp7
+@item pullup
+@item qp
+@item sab
+@item softpulldown
+@item spp
+@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.
@@ -1523,15 +4834,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
@@ -1542,7 +4909,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:
@@ -1650,83 +5017,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
-The parameters are expressions containing the following parameters:
+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
+
+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, which is enabled by default.
+@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
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
-# insert a transparent PNG logo in the bottom left corner of the input
-avconv -i input -i logo -filter_complex 'overlay=x=10:y=main_h-overlay_h-10' output
+@item
+Insert a transparent PNG logo in the bottom left corner of the input,
+using the @command{ffmpeg} tool with the @code{-filter_complex} option:
+@example
+ffmpeg -i input -i logo -filter_complex 'overlay=10:main_h-overlay_h-10' output
+@end example
-# insert 2 different transparent PNG logos (second logo on bottom
-# right corner):
-avconv -i input -i logo1 -i logo2 -filter_complex
-'overlay=x=10:y=H-h-10,overlay=x=W-w-10:y=H-h-10' output
+@item
+Insert 2 different transparent PNG logos (second logo on bottom
+right corner) using the @command{ffmpeg} tool:
+@example
+ffmpeg -i input -i logo1 -i logo2 -filter_complex 'overlay=x=10:y=H-h-10,overlay=x=W-w-10:y=H-h-10' output
+@end example
-# add a transparent color layer on top of the main video,
-# WxH specifies the size of the main input to the overlay filter
-color=red@.3:WxH [over]; [in][over] overlay [out]
+@item
+Add a transparent color layer on top of the main video, @code{WxH}
+must specify the size of the main input to the overlay filter:
+@example
+color=color=red@@.3:size=WxH [over]; [in][over] overlay [out]
@end example
-You can chain together more overlays but the efficiency of such
-approach is yet to be tested.
+@item
+Play an original video and a filtered version (here with the deshake
+filter) side by side using the @command{ffplay} tool:
+@example
+ffplay input.avi -vf 'split[a][b]; [a]pad=iw*2:ih[src]; [b]deshake[filt]; [src][filt]overlay=w'
+@end example
+
+The above command is the same as:
+@example
+ffplay input.avi -vf 'split[b], pad=iw*2[src], [b]deshake, [src]overlay=w'
+@end example
+
+@item
+Make a sliding overlay appearing from the left to the right top part of the
+screen starting since time 2:
+@example
+overlay=x='if(gte(t,2), -w+(t-2)*20, NAN)':y=0
+@end example
+
+@item
+Compose output by putting two input videos side to side:
+@example
+ffmpeg -i left.avi -i right.avi -filter_complex "
+nullsrc=size=200x100 [background];
+[0:v] setpts=PTS-STARTPTS, scale=100x100 [left];
+[1:v] setpts=PTS-STARTPTS, scale=100x100 [right];
+[background][left] overlay=shortest=1 [background+left];
+[background+left][right] overlay=shortest=1:x=100 [left+right]
+"
+@end example
+
+@item
+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
+
+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.
+
+Default is @code{8}.
+
+@item luma_strength
+Set luma strength.
+
+Default is @code{1.0}
+
+@item chroma_strength
+Set chroma strength.
+
+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.
@@ -1734,71 +5270,111 @@ 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.
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 hsub, vsub
+@item sar
+input sample aspect ratio
+
+@item dar
+input display aspect ratio, it is the same as (@var{iw} / @var{ih}) * @var{sar}
+
+@item hsub
+@item vsub
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
+
+@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
-# double output size and put the input video in the bottom-right
-# corner of the output padded area
+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 pixdesctest
@@ -1812,49 +5388,286 @@ 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 vb/vdeblock[|difference[|flatness]]
+Vertical deblocking filter
+@table @option
+@item difference
+Difference factor where higher values mean more deblocking (default: @code{32}).
+@item flatness
+Flatness threshold where lower values mean more deblocking (default: @code{39}).
+@end table
+
+@item ha/hadeblock[|difference[|flatness]]
+Accurate horizontal deblocking filter
+@table @option
+@item difference
+Difference factor where higher values mean more deblocking (default: @code{32}).
+@item flatness
+Flatness threshold where lower values mean more deblocking (default: @code{39}).
+@end table
+
+@item va/vadeblock[|difference[|flatness]]
+Accurate vertical deblocking filter
+@table @option
+@item difference
+Difference factor where higher values mean more deblocking (default: @code{32}).
+@item flatness
+Flatness threshold where lower values mean more deblocking (default: @code{39}).
+@end table
+@end table
+
+The horizontal and vertical deblocking filters share the difference and
+flatness values so you cannot set different horizontal and vertical
+thresholds.
+
+@table @option
+@item h1/x1hdeblock
+Experimental horizontal deblocking filter
+
+@item v1/x1vdeblock
+Experimental vertical deblocking filter
+
+@item dr/dering
+Deringing filter
+
+@item tn/tmpnoise[|threshold1[|threshold2[|threshold3]]], temporal noise reducer
+@table @option
+@item threshold1
+larger -> stronger filtering
+@item threshold2
+larger -> stronger filtering
+@item threshold3
+larger -> stronger filtering
+@end table
+
+@item al/autolevels[:f/fullyrange], automatic brightness / contrast correction
+@table @option
+@item f/fullyrange
+Stretch luminance to @code{0-255}.
+@end table
+
+@item lb/linblenddeint
+Linear blend deinterlacing filter that deinterlaces the given block by
+filtering all lines with a @code{(1 2 1)} filter.
+
+@item li/linipoldeint
+Linear interpolating deinterlacing filter that deinterlaces the given block by
+linearly interpolating every second line.
+
+@item ci/cubicipoldeint
+Cubic interpolating deinterlacing filter deinterlaces the given block by
+cubically interpolating every second line.
+
+@item md/mediandeint
+Median deinterlacing filter that deinterlaces the given block by applying a
+median filter to every second line.
+
+@item fd/ffmpegdeint
+FFmpeg deinterlacing filter that deinterlaces the given block by filtering every
+second line with a @code{(-1 4 2 4 -1)} filter.
+
+@item l5/lowpass5
+Vertically applied FIR lowpass deinterlacing filter that deinterlaces the given
+block by filtering all lines with a @code{(-1 2 6 2 -1)} filter.
+
+@item fq/forceQuant[|quantizer]
+Overrides the quantizer table from the input with the constant quantizer you
+specify.
+@table @option
+@item quantizer
+Quantizer to use
+@end table
+
+@item de/default
+Default pp filter combination (@code{hb|a,vb|a,dr|a})
+
+@item fa/fast
+Fast pp filter combination (@code{h1|a,v1|a,dr|a})
+
+@item ac
+High quality pp filter combination (@code{ha|a|128|7,va|a,dr|a})
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Apply horizontal and vertical deblocking, deringing and automatic
+brightness/contrast:
+@example
+pp=hb/vb/dr/al
+@end example
+
+@item
+Apply default filters without brightness/contrast correction:
+@example
+pp=de/-al
+@end example
+
+@item
+Apply default filters and temporal denoiser:
+@example
+pp=default/tmpnoise|1|2|3
+@end example
+
+@item
+Apply deblocking on luminance only, and switch vertical deblocking on or off
+automatically depending on available CPU time:
+@example
+pp=hb|y/vb|a
+@end example
+@end itemize
+
+@section removelogo
+
+Suppress a TV station logo, using an image file to determine which
+pixels comprise the logo. It works by filling in the pixels that
+comprise the logo with neighboring pixels.
+
+The filter accepts the following options:
+
+@table @option
+@item 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
+
+Pixels in the provided bitmap image with a value of zero are not
+considered part of the logo, non-zero pixels are considered part of
+the logo. If you use white (255) for the logo and black (0) for the
+rest, you will be safe. For making the filter bitmap, it is
+recommended to take a screen capture of a black frame with the logo
+visible, and then using a threshold filter followed by the erode
+filter once or twice.
+
+If needed, little splotches can be fixed manually. Remember that if
+logo pixels are not covered, the filter quality will be much
+reduced. Marking too many pixels as part of the logo does not hurt as
+much, but it will increase the amount of blurring needed to cover over
+the image and will destroy more information than necessary, and extra
+pixels will slow things down on a large logo.
+
+@section 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.
+
+The filter accepts the following options:
+
+@table @option
+@item width, w
+Set the output video width expression. Default value is @code{iw}. See
+below for the list of accepted constants.
+
+@item height, h
+Set the output video height expression. Default value is @code{ih}.
+See below for the list of accepted constants.
+
+@item interl
+Set the interlacing. It accepts the following values:
+
+@table @option
+@item 1
+force interlaced aware scaling
+
+@item 0
+do not apply interlaced scaling
+
+@item -1
+select interlaced aware scaling depending on whether the source frames
+are flagged as interlaced or not
+@end table
+
+Default value is @code{0}.
+
+@item flags
+Set libswscale scaling flags. If not explictly specified the filter
+applies a bilinear scaling algorithm.
+
+@item size, s
+Set the video size, the value must be a valid abbreviation or in the
+form @var{width}x@var{height}.
+@end table
+
+The values of the @var{w} and @var{h} options are expressions
+containing the following constants:
-@item in_w, in_h
+@table @option
+@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 dar, a
-input display aspect ratio, same as @var{iw} / @var{ih}
+@item a
+same as @var{iw} / @var{ih}
@item sar
input sample aspect ratio
-@item hsub, vsub
+@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.
@end table
@@ -1870,401 +5683,701 @@ 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.
-The default value of @var{w} and @var{h} is 0.
+@subsection Examples
-Some examples follow:
+@itemize
+@item
+Scale the input video to a size of 200x100:
@example
-# scale the input video to a size of 200x100.
scale=w=200:h=100
+@end example
+
+This is equivalent to:
+@example
+scale=200:100
+@end example
-# scale the input to 2x
+or:
+@example
+scale=200x100
+@end example
+
+@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
-# the above is the same as
+@end example
+
+@item
+The above is the same as:
+@example
scale=2*in_w:2*in_h
+@end example
-# scale the input to half size
+@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
-# increase the width, and set the height to the same size
+@item
+Increase the width, and set the height to the same size:
+@example
scale=3/2*iw:ow
+@end example
-# seek for Greek harmony
+@item
+Seek for Greek harmony:
+@example
scale=iw:1/PHI*iw
scale=ih*PHI:ih
+@end example
-# increase the height, and set the width to 3/2 of the height
+@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
-# increase the size, but make the size a multiple of the chroma
+@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
-# increase the width to a maximum of 500 pixels, keep the same input aspect ratio
+@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 select
-Select frames to pass in output.
+@section separatefields
-This filter accepts the following options:
+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.
-@table @option
+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.
-@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 setdar, setsar
-@end table
+The @code{setdar} filter sets the Display Aspect Ratio for the filter
+output video.
-The expression can contain the following constants:
+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 PI
-Greek PI
+@item r, ratio, dar (@code{setdar} only), sar (@code{setsar} only)
+Set the aspect ratio used by the filter.
-@item PHI
-golden ratio
+The parameter can be a floating point number string, an expression, or
+a string of the form @var{num}:@var{den}, where @var{num} and
+@var{den} are the numerator and denominator of the aspect ratio. If
+the parameter is not specified, it is assumed the value "0".
+In case the form "@var{num}:@var{den}" is used, the @code{:} character
+should be escaped.
-@item E
-Euler number
+@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}.
-@item n
-the sequential number of the filtered frame, starting from 0
+@end table
-@item selected_n
-the sequential number of the selected frame, starting from 0
+@subsection Examples
-@item prev_selected_n
-the sequential number of the last selected frame, NAN if undefined
+@itemize
-@item TB
-timebase of the input timestamps
+@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 pts
-the PTS (Presentation TimeStamp) of the filtered video frame,
-expressed in @var{TB} units, NAN if undefined
+@item
+To change the sample aspect ratio to 10:11, specify:
+@example
+setsar=sar=10/11
+@end example
-@item t
-the PTS (Presentation TimeStamp) of the filtered video frame,
-expressed in seconds, NAN if undefined
+@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
-@item prev_pts
-the PTS of the previously filtered video frame, NAN if undefined
+@end itemize
-@item prev_selected_pts
-the PTS of the last previously filtered video frame, NAN if undefined
+@anchor{setfield}
+@section setfield
-@item prev_selected_t
-the PTS of the last previously selected video frame, NAN if undefined
+Force field for the output video frame.
-@item start_pts
-the PTS of the first video frame in the video, NAN if undefined
+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}).
-@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 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
-@item interlace_type
-the frame interlace type, can assume one of the following values:
+@section showinfo
+
+Show a line containing various information for each input video frame.
+The input video is not modified.
+
+The shown line contains a sequence of key/value pairs of the form
+@var{key}:@var{value}.
+
+A description of each shown parameter follows:
+
@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 n
+sequential number of the input frame, starting from 0
-@item key
-1 if the filtered frame is a key-frame, 0 otherwise
+@item pts
+Presentation TimeStamp of the input frame, expressed as a number of
+time base units. The time base unit depends on the filter input pad.
-@end table
+@item pts_time
+Presentation TimeStamp of the input frame, expressed as a number of
+seconds
-The default value of the select expression is "1".
+@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 video)
-Some examples follow:
+@item fmt
+pixel format name
-@example
-# select all frames in input
-select
+@item sar
+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}
+
+@item i
+interlaced mode ("P" for "progressive", "T" for top field first, "B"
+for bottom field first)
-# the above is the same as:
-select=expr=1
+@item iskey
+1 if the frame is a key frame, 0 otherwise
-# skip all frames:
-select=expr=0
+@item type
+picture type of the input frame ("I" for an I-frame, "P" for a
+P-frame, "B" for a B-frame, "?" for unknown type).
+Check also the documentation of the @code{AVPictureType} enum and of
+the @code{av_get_picture_type_char} function defined in
+@file{libavutil/avutil.h}.
-# select only I-frames
-select='expr=eq(pict_type\,I)'
+@item checksum
+Adler-32 checksum (printed in hexadecimal) of all the planes of the input frame
-# select one frame every 100
-select='not(mod(n\,100))'
+@item plane_checksum
+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
-# select only frames contained in the 10-20 time interval
-select='gte(t\,10)*lte(t\,20)'
+@anchor{smartblur}
+@section smartblur
-# select only I frames contained in the 10-20 time interval
-select='gte(t\,10)*lte(t\,20)*eq(pict_type\,I)'
+Blur the input video without impacting the outlines.
-# select frames with a minimum distance of 10 seconds
-select='isnan(prev_selected_t)+gte(t-prev_selected_t\,10)'
-@end example
+The filter accepts the following options:
-@anchor{setdar}
-@section setdar
+@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
-Set the Display Aspect Ratio for the filter output video.
+If a chroma option is not explicitly set, the corresponding luma value
+is set.
-This is done by changing the specified Sample (aka Pixel) Aspect
-Ratio, according to the following equation:
-@math{DAR = HORIZONTAL_RESOLUTION / VERTICAL_RESOLUTION * SAR}
+@section stereo3d
-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.
+Convert between different stereoscopic image formats.
-This filter accepts the following options:
+The filters accept the following options:
@table @option
+@item in
+Set stereoscopic image format of input.
-@item dar
-Output display aspect ratio, as a rational or a decimal number.
+Available values for input image formats are:
+@table @samp
+@item sbsl
+side by side parallel (left eye left, right eye right)
-@end table
+@item sbsr
+side by side crosseye (right eye left, left eye right)
-For example to change the display aspect ratio to 16:9, specify:
-@example
-setdar=dar=16/9
-# the above is equivalent to
-setdar=dar=1.77777
-@end example
+@item sbs2l
+side by side parallel with half width resolution
+(left eye left, right eye right)
-See also the @ref{setsar} filter documentation.
+@item sbs2r
+side by side crosseye with half width resolution
+(right eye left, left eye right)
-@section setpts
+@item abl
+above-below (left eye above, right eye below)
-Change the PTS (presentation timestamp) of the input video frames.
+@item abr
+above-below (right eye above, left eye below)
-This filter accepts the following options:
+@item ab2l
+above-below with half height resolution
+(left eye above, right eye below)
-@table @option
+@item ab2r
+above-below with half height resolution
+(right eye above, left eye below)
-@item expr
-The expression which is evaluated for each frame to construct its timestamp.
+@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
-The expression is evaluated through the eval API and can contain the following
-constants:
+@item out
+Set stereoscopic image format of output.
-@table @option
-@item PTS
-the presentation timestamp in input
+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 PI
-Greek PI
+@item argg
+anaglyph red/green gray
+(red filter on left eye, green filter on right eye)
-@item PHI
-golden ratio
+@item arcg
+anaglyph red/cyan gray
+(red filter on left eye, cyan filter on right eye)
-@item E
-Euler number
+@item arch
+anaglyph red/cyan half colored
+(red filter on left eye, cyan filter on right eye)
-@item N
-the count of the input frame, starting from 0.
+@item arcc
+anaglyph red/cyan color
+(red filter on left eye, cyan filter on right eye)
-@item STARTPTS
-the PTS of the first video frame
+@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 INTERLACED
-tell if the current frame is interlaced
+@item agmg
+anaglyph green/magenta gray
+(green filter on left eye, magenta filter on right eye)
-@item PREV_INPTS
-previous input PTS
+@item agmh
+anaglyph green/magenta half colored
+(green filter on left eye, magenta filter on right eye)
-@item PREV_OUTPTS
-previous output PTS
+@item agmc
+anaglyph green/magenta colored
+(green filter on left eye, magenta filter on right eye)
-@item RTCTIME
-wallclock (RTC) time in microseconds
+@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 RTCSTART
-wallclock (RTC) time at the start of the movie in microseconds
+@item aybg
+anaglyph yellow/blue gray
+(yellow filter on left eye, blue filter on right eye)
-@end table
+@item aybh
+anaglyph yellow/blue half colored
+(yellow filter on left eye, blue filter on right eye)
-Some examples follow:
+@item aybc
+anaglyph yellow/blue colored
+(yellow filter on left eye, blue filter on right eye)
-@example
-# start counting PTS from zero
-setpts=expr=PTS-STARTPTS
+@item aybd
+anaglyph yellow/blue color optimized with the least squares projection of dubois
+(yellow filter on left eye, blue filter on right eye)
-# fast motion
-setpts=expr=0.5*PTS
+@item irl
+interleaved rows (left eye has top row, right eye starts on next row)
-# slow motion
-setpts=2.0*PTS
+@item irr
+interleaved rows (right eye has top row, left eye starts on next row)
-# fixed rate 25 fps
-setpts=N/(25*TB)
+@item ml
+mono output (left eye only)
-# fixed rate 25 fps with some jitter
-setpts='1/(25*TB) * (N + 0.05 * sin(N*2*PI/25))'
+@item mr
+mono output (right eye only)
+@end table
+
+Default value is @samp{arcd}.
+@end table
-# generate timestamps from a "live source" and rebase onto the current timebase
-setpts='(RTCTIME - RTCSTART) / (TB * 1000000)"
+@subsection Examples
+
+@itemize
+@item
+Convert input video from side by side parallel to anaglyph yellow/blue dubois:
+@example
+stereo3d=sbsl:aybd
@end example
-@anchor{setsar}
-@section setsar
+@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
-Set the Sample (aka Pixel) Aspect Ratio for the filter output video.
+@anchor{subtitles}
+@section subtitles
-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}
+Draw subtitles on top of input video using the libass library.
-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.
+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.
-This filter accepts the following options:
+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 sar
-Output sample aspect ratio, as a rational or decimal number.
+@item original_size
+Specify the size of the original video, the video for which the ASS file
+was composed. 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
-For example to change the sample aspect ratio to 10:11, specify:
+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
-setsar=sar=10/11
+subtitles=sub.srt
@end example
-@section settb
+which is equivalent to:
+@example
+subtitles=filename=sub.srt
+@end example
-Set the timebase to use for the output frames timestamps.
-It is mainly useful for testing timebase configuration.
+@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 expr
-The expression which is evaluated into the output timebase.
+@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
-The expression can contain the constants "PI", "E", "PHI", "AVTB" (the
-default timebase), and "intb" (the input timebase).
+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.
-The default value for the input is "intb".
+@subsection Examples
-Follow some 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
-# set the timebase to 1/25
-settb=expr=1/25
+ffmpeg -i in.avi -vf thumbnail,scale=300:200 -frames:v 1 out.png
+@end example
+@end itemize
-# set the timebase to 1/10
-settb=expr=0.1
+@section tile
-#set the timebase to 1001/1000
-settb=1+0.001
+Tile several successive frames together.
-#set the timebase to 2*intb
-settb=2*intb
+The filter accepts the following options:
-#set the default timebase value
-settb=AVTB
-@end example
+@table @option
-@section showinfo
+@item layout
+Set the grid size (i.e. the number of lines and columns) in the form
+"@var{w}x@var{h}".
-Show a line containing various information for each input video frame.
-The input video is not modified.
+@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.
-The shown line contains a sequence of key/value pairs of the form
-@var{key}:@var{value}.
+@item margin
+Set the outer border margin in pixels.
-A description of each shown parameter follows:
+@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.
-@table @option
-@item n
-sequential number of the input frame, starting from 0
+@end table
-@item pts
-Presentation TimeStamp of the input frame, expressed as a number of
-time base units. The time base unit depends on the filter input pad.
+@subsection Examples
-@item pts_time
-Presentation TimeStamp of the input frame, expressed as a number of
-seconds
+@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 pos
-position of the frame in the input stream, -1 if this information in
-unavailable and/or meaningless (for example in case of synthetic video)
+@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
-@item fmt
-pixel format name
+@section tinterlace
-@item sar
-sample aspect ratio of the input frame, expressed in the form
-@var{num}/@var{den}
+Perform various types of temporal field interlacing.
-@item s
-size of the input frame, expressed in the form
-@var{width}x@var{height}
+Frames are counted starting from 1, so the first input frame is
+considered odd.
-@item i
-interlaced mode ("P" for "progressive", "T" for top field first, "B"
-for bottom field first)
+The filter accepts the following options:
-@item iskey
-1 if the frame is a key frame, 0 otherwise
+@table @option
-@item type
-picture type of the input frame ("I" for an I-frame, "P" for a
-P-frame, "B" for a B-frame, "?" for unknown type).
-Check also the documentation of the @code{AVPictureType} enum and of
-the @code{av_get_picture_type_char} function defined in
-@file{libavutil/avutil.h}.
+@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.
-@item checksum
-Adler-32 checksum of all the planes of the input frame
+Available values are:
-@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}]"
+@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
-@section split
+Numeric values are deprecated but are accepted for backward
+compatibility reasons.
-Split input video into several identical outputs.
+Default mode is @code{merge}.
-The filter accepts a single parameter which specifies the number of outputs. If
-unspecified, it defaults to 2.
+@item flags
+Specify flags influencing the filter process.
-For example
-@example
-avconv -i INPUT -filter_complex split=5 OUTPUT
-@end example
-will create 5 copies of the input video.
+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
@@ -2275,14 +6388,11 @@ This filter accepts the following options:
@table @option
@item dir
-The direction of the transpose.
-
-@end table
-
-The direction can assume the following values:
+Specify the transposition direction.
+Can assume the following values:
@table @samp
-@item cclock_flip
+@item 0, 4, cclock_flip
Rotate by 90 degrees counterclockwise and vertically flip (default), that is:
@example
L.R L.l
@@ -2290,7 +6400,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
@@ -2298,7 +6408,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
@@ -2306,7 +6416,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
@@ -2315,6 +6425,39 @@ 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.
@@ -2366,16 +6509,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.
@@ -2383,56 +6528,293 @@ 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.
-@item luma_msize_x
-Set the luma matrix horizontal 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 luma_msize_y
-Set the luma matrix vertical size. It can be an integer between 3
-and 13, default value is 5.
+Default value is 1.0.
-@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_x, cx
+Set the chroma matrix horizontal 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_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_y
-Set the chroma matrix vertical 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 luma_amount
-Set the chroma effect strength. It can be a float number between -2.0
-and 5.0, default value is 0.0.
+Negative values will blur the input video, while positive values will
+sharpen it, a value of zero will disable the effect.
+
+Default value is 0.0.
+
+@item opencl
+If set to 1, specify using OpenCL capabilities, only available if
+FFmpeg was configured with @code{--enable-opencl}. Default value is 0.
@end table
-Negative values for the amount will blur the input video, while positive
-values will sharpen. All parameters are optional and default to the
-equivalent of the string '5:5:1.0:5:5:0.0'.
+All parameters are optional and default to the equivalent of the
+string '5:5:1.0:5:5:0.0'.
+
+@subsection Examples
+@itemize
+@item
+Apply strong luma sharpen effect:
@example
-# Strong luma sharpen effect parameters
unsharp=luma_msize_x=7:luma_msize_y=7:luma_amount=2.5
+@end example
-# 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
-# Use the default values with @command{avconv}
-./avconv -i in.avi -vf "unsharp" out.mp4
+@item
+Analyze a video with medium shakiness using @command{ffmpeg}:
+@example
+ffmpeg -i input -vf vidstabdetect=shakiness=5:show=1 dummy.avi
@end example
+@end itemize
+
+@anchor{vidstabtransform}
+@section vidstabtransform
+
+Video stabilization/deshaking: pass 2 of 2,
+see @ref{vidstabdetect} for pass 1.
+
+Read a file with transform information for each frame and
+apply/compensate them. Together with the @ref{vidstabdetect}
+filter this can be used to deshake videos. See also
+@url{http://public.hronopik.de/vid.stab}. It is important to also use
+the 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
+if 1 then optimal zoom value is determined (default).
+Optimal zoom means no (or only little) border should be visible.
+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
+
+@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
-./avconv -i in.avi -vf "vflip" out.avi
+ffmpeg -i in.avi -vf "vflip" out.avi
@end example
+@anchor{yadif}
@section yadif
Deinterlace the input video ("yadif" means "yet another deinterlacing
@@ -2440,54 +6822,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
@@ -2504,10 +6886,13 @@ 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.
+
@item width
Input video width.
@@ -2515,14 +6900,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:
@@ -2533,123 +6927,264 @@ 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.
+
+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. Default value is "640x480".
-# 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]
+@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.
+
+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
-@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".
+For example the following:
+@example
+testsrc=t=dc_luma
+@end example
+
+will generate a "dc_luma" test pattern.
@section frei0r_src
Provide a frei0r source.
To enable compilation of this filter you need to install the frei0r
-header and configure Libav with --enable-frei0r.
+header and configure FFmpeg with @code{--enable-frei0r}.
This source accepts the following options:
@@ -2673,19 +7208,155 @@ 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.
+
+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.
+@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
+
+@section color, nullsrc, rgbtestsrc, smptebars, smptehdbars, testsrc
+
+The @code{color} source provides an uniformly colored input.
+
+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.
@@ -2694,6 +7365,12 @@ The sources accept the following options:
@table @option
+@item color, c
+Specify the color of the source, only used in the @code{color}
+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 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
@@ -2709,7 +7386,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...]]]
@@ -2719,6 +7396,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 used 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:
@@ -2727,7 +7412,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
@@ -2741,8 +7450,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
@@ -2751,3 +7465,1157 @@ 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. 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. 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='gte(t\,10)*lte(t\,20)'
+@end example
+
+@item
+Select only I frames contained in the 10-20 time interval:
+@example
+select='gte(t\,10)*lte(t\,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 TB
+the time base
+
+@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
+@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. 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. 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..44e4532
--- /dev/null
+++ b/doc/formats.texi
@@ -0,0 +1,146 @@
+@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 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 positive. 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 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
+
+@include demuxers.texi
+@include muxers.texi
+@include metadata.texi
diff --git a/doc/general.texi b/doc/general.texi
index ee87e9f..4f45497 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -11,11 +11,19 @@
@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 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 and VisualOn libraries
Spun off Google Android sources, OpenCore, VisualOn and Fraunhofer
@@ -25,13 +33,13 @@ libraries provide encoders for a number of audio codecs.
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
+upgrade FFmpeg's license to LGPL version 3 (or if you have enabled
GPL components, GPL version 3) 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 +49,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 +57,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 +65,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 +73,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 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 +97,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
@@ -90,14 +106,14 @@ 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
@@ -106,13 +122,13 @@ enable it.
-@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
@@ -120,27 +136,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.
@@ -153,7 +185,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
@@ -171,7 +203,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.
@@ -182,13 +215,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
@@ -199,9 +238,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
@@ -211,6 +254,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
@@ -238,6 +284,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
@@ -246,6 +293,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
@@ -256,6 +304,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
@@ -301,19 +350,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
@@ -322,10 +375,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
@@ -335,10 +390,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
@@ -349,16 +405,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
@@ -366,15 +422,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
@@ -391,7 +449,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
@@ -404,8 +461,10 @@ following image formats are supported:
@tab YUV, JPEG and some extension is not supported yet.
@item Truevision Targa @tab X @tab X
@tab Targa (.TGA) 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
@@ -421,13 +480,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 MJPEG-B @tab @tab X
@@ -447,13 +505,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
@@ -473,10 +536,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
@@ -496,11 +560,12 @@ following image formats are supported:
@item Electronic Arts TGQ video @tab @tab X
@item Electronic Arts TQI video @tab @tab X
@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
@@ -532,6 +597,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
@@ -540,6 +606,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.
@@ -578,8 +646,10 @@ 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 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
@@ -589,8 +659,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
@@ -601,11 +671,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
@@ -623,6 +698,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
@@ -641,6 +718,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
@@ -655,7 +735,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
@@ -684,19 +767,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
@@ -707,20 +792,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 Atrac 1 @tab @tab X
@item Atrac 3 @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
@@ -731,8 +819,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
@@ -749,6 +839,7 @@ following image formats are supported:
@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
@@ -759,7 +850,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 16-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
@@ -797,6 +892,10 @@ following image formats are supported:
@tab Used in Sierra VMD files.
@item Smacker audio @tab @tab X
@item SMPTE 302M AES3 audio @tab @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
@@ -804,6 +903,8 @@ following image formats are supported:
@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 WavPack @tab @tab X
@@ -826,12 +927,27 @@ 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 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 @tab X @tab @tab X
+@item XSUB @tab @tab @tab X @tab X
@end multitable
@code{X} means that the feature is supported.
@@ -872,13 +988,17 @@ 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 SDL @tab @tab X
@item Video4Linux2 @tab X @tab
@item VfW capture @tab X @tab
@item X11 grabbing @tab X @tab
@@ -886,4 +1006,16 @@ performance on systems without hardware floating point support).
@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..5e8d215 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,20 +291,181 @@ system:capture_1
system:capture_2
system:playback_1
system:playback_2
-libav:input_1
+ffmpeg:input_1
metro:120_bpm
-# Connect metro to the avconv writable client.
-$ jack_connect metro:120_bpm libav:input_1
+# Connect metro to the ffmpeg writable client.
+$ jack_connect metro:120_bpm ffmpeg:input_1
@end example
For more information read:
@url{http://jackaudio.org/}
+@section lavfi
+
+Libavfilter input virtual device.
+
+This input device reads data from the open output pads of a libavfilter
+filtergraph.
+
+For each filtergraph open output, the input device will create a
+corresponding stream which is mapped to the generated output. Currently
+only video data is supported. The filtergraph is specified through the
+option @option{graph}.
+
+@subsection Options
+
+@table @option
+
+@item graph
+Specify the filtergraph to use as input. Each video open output must be
+labelled by a unique string of the form "out@var{N}", where @var{N} is a
+number starting from 0 corresponding to the mapped input stream
+generated by the device.
+The first unlabelled output is automatically assigned to the "out0"
+label, but all the others need to be specified explicitly.
+
+If not specified defaults to the filename specified for the input
+device.
+
+@item graph_file
+Set the filename of the filtergraph to be read and sent to the other
+filters. Syntax of the filtergraph is the same as the one specified by
+the option @var{graph}.
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Create a color video stream and play it back with @command{ffplay}:
+@example
+ffplay -f lavfi -graph "color=c=pink [out0]" dummy
+@end example
+
+@item
+As the previous example, but use filename for specifying the graph
+description, and omit the "out0" label:
+@example
+ffplay -f lavfi color=c=pink
+@end example
+
+@item
+Create three different video test filtered sources and play them:
+@example
+ffplay -f lavfi -graph "testsrc [out0]; testsrc,hflip [out1]; testsrc,negate [out2]" test3
+@end example
+
+@item
+Read an audio stream from a file using the amovie source and play it
+back with @command{ffplay}:
+@example
+ffplay -f lavfi "amovie=test.wav"
+@end example
+
+@item
+Read an audio stream and a video stream and play it back with
+@command{ffplay}:
+@example
+ffplay -f lavfi "movie=test.avi[out0];amovie=test.wav[out1]"
+@end example
+
+@end itemize
+
@section libdc1394
IIDC1394 input device, based on libdc1394 and libraw1394.
+@section openal
+
+The OpenAL input device provides audio capture on all systems with a
+working OpenAL 1.1 implementation.
+
+To enable this input device during configuration, you need OpenAL
+headers and libraries installed on your system, and need to configure
+FFmpeg with @code{--enable-openal}.
+
+OpenAL headers and libraries should be provided as part of your OpenAL
+implementation, or as an additional download (an SDK). Depending on your
+installation you may need to specify additional flags via the
+@code{--extra-cflags} and @code{--extra-ldflags} for allowing the build
+system to locate the OpenAL headers and libraries.
+
+An incomplete list of OpenAL implementations follows:
+
+@table @strong
+@item Creative
+The official Windows implementation, providing hardware acceleration
+with supported devices and software fallback.
+See @url{http://openal.org/}.
+@item OpenAL Soft
+Portable, open source (LGPL) software implementation. Includes
+backends for the most common sound APIs on the Windows, Linux,
+Solaris, and BSD operating systems.
+See @url{http://kcat.strangesoft.net/openal.html}.
+@item Apple
+OpenAL is part of Core Audio, the official Mac OS X Audio interface.
+See @url{http://developer.apple.com/technologies/mac/audio-and-video.html}
+@end table
+
+This device allows to capture from an audio input device handled
+through OpenAL.
+
+You need to specify the name of the device to capture in the provided
+filename. If the empty string is provided, the device will
+automatically select the default device. You can get the list of the
+supported devices by using the option @var{list_devices}.
+
+@subsection Options
+
+@table @option
+
+@item channels
+Set the number of channels in the captured audio. Only the values
+@option{1} (monaural) and @option{2} (stereo) are currently supported.
+Defaults to @option{2}.
+
+@item sample_size
+Set the sample size (in bits) of the captured audio. Only the values
+@option{8} and @option{16} are currently supported. Defaults to
+@option{16}.
+
+@item sample_rate
+Set the sample rate (in Hz) of the captured audio.
+Defaults to @option{44.1k}.
+
+@item list_devices
+If set to @option{true}, print a list of devices and exit.
+Defaults to @option{false}.
+
+@end table
+
+@subsection Examples
+
+Print the list of OpenAL supported devices and exit:
+@example
+$ ffmpeg -list_devices true -f openal -i dummy out.ogg
+@end example
+
+Capture from the OpenAL device @file{DR-BT101 via PulseAudio}:
+@example
+$ ffmpeg -f openal -i 'DR-BT101 via PulseAudio' out.ogg
+@end example
+
+Capture from the default device (note the empty string '' as filename):
+@example
+$ ffmpeg -f openal -i '' out.ogg
+@end example
+
+Capture from two devices simultaneously, writing to two different files,
+within the same @command{ffmpeg} command:
+@example
+$ ffmpeg -f openal -i 'DR-BT101 via PulseAudio' out1.ogg -f openal -i 'ALSA Default' out2.ogg
+@end example
+Note: not all OpenAL implementations support multiple simultaneous capture -
+try the latest OpenAL Soft if the above does not work.
+
@section oss
Open Sound System input device.
@@ -145,10 +474,10 @@ The filename to provide to the input device is the device node
representing the OSS input device, and is usually set to
@file{/dev/dsp}.
-For example to grab from @file{/dev/dsp} using @command{avconv} use the
+For example to grab from @file{/dev/dsp} using @command{ffmpeg} use the
command:
@example
-avconv -f oss -i /dev/dsp /tmp/oss.wav
+ffmpeg -f oss -i /dev/dsp /tmp/oss.wav
@end example
For more information about OSS see:
@@ -165,10 +494,10 @@ 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}.
+the command @command{pactl list sources}.
@example
-avconv -f pulse -i default /tmp/pulse.wav
+ffmpeg -f pulse -i default /tmp/pulse.wav
@end example
@subsection @var{server} AVOption
@@ -188,7 +517,7 @@ The syntax is:
@end example
Specify the application name pulse will use when showing active clients,
-by default it is "libav"
+by default it is the LIBAVFORMAT_IDENT string
@subsection @var{stream_name} AVOption
@@ -248,16 +577,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), the device will always rely
+on libv4l2.
+
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 +600,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 +731,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 -r 25 -s 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 -r 25 -s 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 +762,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 -r 25 -s 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 -r 25 -s 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 -r 25 -s 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 -r 25 -s 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..d487f66
--- /dev/null
+++ b/doc/issue_tracker.txt
@@ -0,0 +1,213 @@
+FFmpeg's bug/patch/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, patches, 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)://ffmpeg.org/trac/ffmpeg
+
+Type:
+-----
+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
+
+patch
+ A patch as generated by diff which conforms to the patch submission and
+ development policy.
+
+
+Priority:
+---------
+critical
+ Bugs and patches which deal with data loss and security issues.
+ No feature request can be critical.
+
+important
+ Bugs which make FFmpeg unusable for a significant number of users, and
+ patches fixing them.
+ 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 and patches 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/Substatus:
+----------
+*/new/new
+ Initial state of new bugs, patches and feature requests submitted by
+ users.
+
+*/open/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, patches or feature requests which are duplicates.
+ Note that patches dealing with the same thing in a different way are not
+ 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/wont_fix
+ 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.
+
+patch/open/approved
+ Patches which have been reviewed and approved by a developer.
+ Such patches can be applied anytime by any other developer after some
+ reasonable testing (compile + regression tests + does the patch do
+ what the author claimed).
+
+patch/open/needs_changes
+ Patches which have been reviewed and need changes to be accepted.
+
+patch/closed/applied
+ Patches which have been applied.
+
+patch/closed/rejected
+ Patches which have been rejected.
+
+feature_request/closed/implemented
+ Feature requests which have been implemented.
+
+feature_request/closed/wont_implement
+ Feature requests which will not be implemented. The reasons here could
+ be legal, philosophical or others.
+
+Note, please do not use type-status-substatus combinations other than the
+above without asking on ffmpeg-dev first!
+
+Note2, if you provide the requested info do not forget to remove the
+needs_more_info substatus.
+
+Component:
+----------
+
+avcodec
+ issues in libavcodec/*
+
+avformat
+ issues in libavformat/*
+
+avutil
+ issues in libavutil/*
+
+regression test
+ issues in tests/*
+
+ffmpeg
+ issues in or related to ffmpeg.c
+
+ffplay
+ issues in or related to ffplay.c
+
+ffprobe
+ issues in or related to ffprobe.c
+
+ffserver
+ issues in or related to ffserver.c
+
+build system
+ issues in or related to configure/Makefile
+
+regression
+ bugs which were not present in a past revision
+
+trac
+ issues related to our issue tracker
diff --git a/doc/libavcodec.texi b/doc/libavcodec.texi
new file mode 100644
index 0000000..618f9f6
--- /dev/null
+++ b/doc/libavcodec.texi
@@ -0,0 +1,48 @@
+\input texinfo @c -*- texinfo -*-
+
+@settitle Libavcodec Documentation
+@titlepage
+@center @titlefont{Libavcodec Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+The libavcodec library provides a generic encoding/decoding framework
+and contains multiple decoders and encoders for audio, video and
+subtitle streams, and several bitstream filters.
+
+The shared architecture provides various services ranging from bit
+stream I/O to DSP optimizations, and makes it suitable for
+implementing robust and fast codecs as well as for experimentation.
+
+@c man end DESCRIPTION
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-codecs.html,ffmpeg-codecs}, @url{ffmpeg-bitstream-filters.html,bitstream-filters},
+@url{libavutil.html,libavutil}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-codecs(1), ffmpeg-bitstream-filters(1),
+libavutil(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename libavcodec
+@settitle media streams decoding and encoding library
+
+@end ignore
+
+@bye
diff --git a/doc/libavdevice.texi b/doc/libavdevice.texi
new file mode 100644
index 0000000..d5f790b
--- /dev/null
+++ b/doc/libavdevice.texi
@@ -0,0 +1,45 @@
+\input texinfo @c -*- texinfo -*-
+
+@settitle Libavdevice Documentation
+@titlepage
+@center @titlefont{Libavdevice Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+The libavdevice library provides a generic framework for grabbing from
+and rendering to many common multimedia input/output devices, and
+supports several input and output devices, including Video4Linux2,
+VfW, DShow, and ALSA.
+
+@c man end DESCRIPTION
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-devices.html,ffmpeg-devices},
+@url{libavutil.html,libavutil}, @url{libavcodec.html,libavcodec}, @url{libavformat.html,libavformat}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-devices(1),
+libavutil(3), libavcodec(3), libavformat(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename libavdevice
+@settitle multimedia device handling library
+
+@end ignore
+
+@bye
diff --git a/doc/libavfilter.texi b/doc/libavfilter.texi
index 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
--- /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
--- /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..1a5b01f
--- /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 an high sample rate of 44100Hz to 8000Hz. Audio
+conversion from high to low sample rate is a lossy process. Several
+resampling options and algorithms are available.
+
+@item
+@emph{Format conversion}: is the process of converting the type of
+samples, for example from 16-bit signed samples to unsigned 8-bit or
+float samples. It also handles packing conversion, when passing from
+packed layout (all samples belonging to distinct channels interleaved
+in the same buffer), to planar layout (all samples belonging to the
+same channel stored in a dedicated buffer or "plane").
+
+@item
+@emph{Rematrixing}: is the process of changing the channel layout, for
+example from stereo to mono. When the input channels cannot be mapped
+to the output streams, the process is lossy, since it involves
+different gain factors and mixing.
+@end itemize
+
+Various other audio conversions (e.g. stretching and padding) are
+enabled through dedicated options.
+
+@c man end DESCRIPTION
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-resampler.html,ffmpeg-resampler},
+@url{libavutil.html,libavutil}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-resampler(1),
+libavutil(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename libswresample
+@settitle audio resampling library
+
+@end ignore
+
+@bye
diff --git a/doc/libswscale.texi b/doc/libswscale.texi
new file mode 100644
index 0000000..818e988
--- /dev/null
+++ b/doc/libswscale.texi
@@ -0,0 +1,63 @@
+\input texinfo @c -*- texinfo -*-
+
+@settitle Libswscale Documentation
+@titlepage
+@center @titlefont{Libswscale Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+The libswscale library performs highly optimized image scaling and
+colorspace and pixel format conversion operations.
+
+Specifically, this library performs the following conversions:
+
+@itemize
+@item
+@emph{Rescaling}: is the process of changing the video size. Several
+rescaling options and algorithms are available. This is usually a
+lossy process.
+
+@item
+@emph{Pixel format conversion}: is the process of converting the image
+format and colorspace of the image, for example from planar YUV420P to
+RGB24 packed. It also handles packing conversion, that is converts
+from packed layout (all pixels belonging to distinct planes
+interleaved in the same buffer), to planar layout (all samples
+belonging to the same plane stored in a dedicated buffer or "plane").
+
+This is usually a lossy process in case the source and destination
+colorspaces differ.
+@end itemize
+
+@c man end DESCRIPTION
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-scaler.html,ffmpeg-scaler},
+@url{libavutil.html,libavutil}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-scaler(1),
+libavutil(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename libswscale
+@settitle video scaling and pixel format conversion library
+
+@end ignore
+
+@bye
diff --git a/doc/metadata.texi b/doc/metadata.texi
index cfaf491..2a28575 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
diff --git a/doc/mips.txt b/doc/mips.txt
new file mode 100644
index 0000000..051b819
--- /dev/null
+++ b/doc/mips.txt
@@ -0,0 +1,70 @@
+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/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 742e72a..dc627dc 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,7 +13,7 @@ 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.
@@ -35,20 +35,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 +56,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
-For example to compute the CRC of each decoded frame in the input, and
-store it in the file @file{out.crc}:
+@var{CRC} is a hexadecimal number 0-padded to 8 digits containing the
+CRC of the packet.
+
+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 +141,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 +155,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 +218,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
+positive number.
@item -update @var{number}
If @var{number} is nonzero, the filename will always be interpreted as just a
@@ -179,12 +252,46 @@ images.
@end table
+The image muxer supports the .Y.U.V image file format. This format is
+special in that that each image frame consists of three files, for
+each of the YUV420P components. To read or write this image file format,
+specify the name of the '.Y' file. The muxer will automatically open the
+'.U' and '.V' files as required.
+
+@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
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 +305,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 +318,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
@@ -239,12 +349,18 @@ more efficient), but with this option set, the muxer writes one moof/mdat
pair for each track, making it easier to separate tracks.
This option is implicitly set when writing ismv (Smooth Streaming) files.
+@item -movflags faststart
+Run a second pass moving the moov atom on top 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 mpegts
@@ -273,11 +389,11 @@ Set the first PID for data packets (default 0x0100, max 0x0f00).
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 \
@@ -295,19 +411,19 @@ Null muxer.
This muxer does not generate any output file, it is mainly useful for
testing or benchmarking purposes.
-For example to benchmark decoding with @command{avconv} you can use the
+For example to benchmark decoding with @command{ffmpeg} you can use the
command:
@example
-avconv -benchmark -i INPUT -f null out.null
+ffmpeg -benchmark -i INPUT -f null out.null
@end example
Note that the above command does not read or write the @file{out.null}
-file, but specifying the output file is required by the @command{avconv}
+file, but specifying the output file is required by the @command{ffmpeg}
syntax.
Alternatively you can write the command as:
@example
-avconv -benchmark -i INPUT -f null -
+ffmpeg -benchmark -i INPUT -f null -
@end example
@section matroska
@@ -332,7 +448,7 @@ Specifies the language of the track in the Matroska languages form
@table @option
-@item STEREO_MODE=@var{mode}
+@item stereo_mode=@var{mode}
Stereo 3D video layout of two views in a single video track
@table @option
@item mono
@@ -370,7 +486,7 @@ Both eyes laced in one Block, Right-eye view is first
For example a 3D WebM clip can be created using the following command line:
@example
-avconv -i sample_left_right_clip.mpg -an -c:v libvpx -metadata STEREO_MODE=left_right -y stereo_clip.webm
+ffmpeg -i sample_left_right_clip.mpg -an -c:v libvpx -metadata stereo_mode=left_right -y stereo_clip.webm
@end example
This muxer supports the following options:
@@ -394,7 +510,7 @@ have no effect if it is not.
@end table
-@section segment
+@section segment, stream_segment, ssegment
Basic stream segmenter.
@@ -402,29 +518,215 @@ 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}.
-Every segment starts with a video keyframe, if a video stream is present.
+@code{stream_segment} is a variant of the muxer used to write to
+streaming output formats, i.e. which do not require global headers,
+and is recommended for outputting e.g. to MPEG transport stream segments.
+@code{ssegment} is a shorter alias for @code{stream_segment}.
+
+Every segment starts with a keyframe of the selected reference stream,
+which is set through the @option{reference_stream} option.
+
+Note that if you want accurate splitting for a video file, you need to
+make the input key frames correspond to the exact splitting times
+expected by the segmenter, or the segment muxer will start the new
+segment with the key frame found next after the specified start
+time.
+
The segment muxer works best with a single constant frame rate video.
-Optionally it can generate a flat list of the created segments, one segment
-per line.
+Optionally it can generate a list of the created segments, by setting
+the option @var{segment_list}. The list type is specified by the
+@var{segment_list_type} option.
+
+The segment muxer supports the following options:
@table @option
+@item reference_stream @var{specifier}
+Set the reference stream, as specified by the string @var{specifier}.
+If @var{specifier} is set to @code{auto}, the reference is 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 ``auto''.
+
@item segment_format @var{format}
Override the inner container format, by default it is guessed by the filename
extension.
-@item segment_time @var{t}
-Set segment duration to @var{t} seconds.
+
@item segment_list @var{name}
-Generate also a listfile named @var{name}.
+Generate also a listfile named @var{name}. If not specified no
+listfile is generated.
+
+@item segment_list_flags @var{flags}
+Set flags affecting the segment list generation.
+
+It currently supports the following flags:
+@table @var
+@item cache
+Allow caching (only affects M3U8 list files).
+
+@item live
+Allow live-friendly file generation.
+@end table
+
+Default value is @code{cache}.
+
@item segment_list_size @var{size}
-Overwrite the listfile once it reaches @var{size} entries.
+Update the list file so that it contains at most 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 @option
+@item flat
+Generate a flat list for the created segments, one segment per line.
+
+@item csv, ext
+Generate a list for the created segments, one segment per line,
+each line matching the format (comma-separated values):
+@example
+@var{segment_filename},@var{segment_start_time},@var{segment_end_time}
+@end example
+
+@var{segment_filename} is the name of the output file generated by the
+muxer according to the provided pattern. CSV escaping (according to
+RFC4180) is applied if required.
+
+@var{segment_start_time} and @var{segment_end_time} specify
+the segment start and end time expressed in seconds.
+
+A list file with the suffix @code{".csv"} or @code{".ext"} will
+auto-select this format.
+
+@code{ext} is deprecated in favor or @code{csv}.
+
+@item ffconcat
+Generate an ffconcat file for the created segments. The resulting file
+can be read using the FFmpeg @ref{concat} demuxer.
+
+A list file with the suffix @code{".ffcat"} or @code{".ffconcat"} will
+auto-select this format.
+
+@item m3u8
+Generate an extended M3U8 file, version 3, compliant with
+@url{http://tools.ietf.org/id/draft-pantos-http-live-streaming}.
+
+A list file with the suffix @code{".m3u8"} will auto-select this format.
+@end table
+
+If not specified the type is guessed from the list file name suffix.
+
+@item segment_time @var{time}
+Set segment duration to @var{time}, the value must be a duration
+specification. Default value is "2". See also the
+@option{segment_times} option.
+
+Note that splitting may not be accurate, unless you force the
+reference stream key-frames at the given time. See the introductory
+notice and the examples below.
+
+@item segment_time_delta @var{delta}
+Specify the accuracy time when selecting the start time for a
+segment, expressed as a duration specification. Default value is "0".
+
+When delta is specified a key-frame will start a new segment if its
+PTS satisfies the relation:
+@example
+PTS >= start_time - time_delta
+@end example
+
+This option is useful when splitting video content, which is always
+split at GOP boundaries, in case a key frame is found just before the
+specified split time.
+
+In particular may be used in combination with the @file{ffmpeg} option
+@var{force_key_frames}. The key frame times specified by
+@var{force_key_frames} may not be set accurately because of rounding
+issues, with the consequence that a key frame time may result set just
+before the specified time. For constant frame rate videos a value of
+1/2*@var{frame_rate} should address the worst case mismatch between
+the specified time and the time set by @var{force_key_frames}.
+
+@item segment_times @var{times}
+Specify a list of split points. @var{times} contains a list of comma
+separated duration specifications, in increasing order. See also
+the @option{segment_time} option.
+
+@item segment_frames @var{frames}
+Specify a list of split video frame numbers. @var{frames} contains a
+list of comma separated integer numbers, in increasing order.
+
+This option specifies to start a new segment whenever a reference
+stream key frame is found and the sequential number (starting from 0)
+of the frame is greater or equal to the next value in the list.
+
@item segment_wrap @var{limit}
Wrap around segment index once it reaches @var{limit}.
+
+@item segment_start_number @var{number}
+Set the sequence number of the first segment. Defaults to @code{0}.
+
+@item reset_timestamps @var{1|0}
+Reset timestamps at the begin of each segment, so that each segment
+will start with near-zero timestamps. It is meant to ease the playback
+of the generated segments. May not work with some combinations of
+muxers/codecs. It is set to @code{0} by default.
@end table
+@subsection Examples
+
+@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
+
+@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
+
+@item
+As the example above, but use the @code{ffmpeg} @var{force_key_frames}
+option to force key frames in the input at the specified location, together
+with the segment option @var{segment_time_delta} to account for
+possible roundings operated when setting key frame times.
+@example
+ffmpeg -i in.mkv -force_key_frames 1,2,3,5,8,13,21 -codec:v mpeg4 -codec:a pcm_s16le -map 0 \
+-f segment -segment_list out.csv -segment_times 1,2,3,5,8,13,21 -segment_time_delta 0.05 out%03d.nut
+@end example
+In order to force key frames on the input file, transcoding is
+required.
+
+@item
+Segment the input file by splitting the input file according to the
+frame numbers sequence specified with the @var{segment_frames} option:
+@example
+ffmpeg -i in.mkv -codec copy -map 0 -f segment -segment_list out.csv -segment_frames 100,200,300,500,800 out%03d.nut
+@end example
+
+@item
+To convert the @file{in.mkv} to TS segments using the @code{libx264}
+and @code{libfaac} encoders:
+@example
+ffmpeg -i in.mkv -map 0 -codec:v libx264 -codec:a libfaac -f ssegment -segment_list out.list out%03d.ts
+@end example
+
+@item
+Segment the input file, and create an M3U8 live playlist (can be used
+as live HLS source):
@example
-avconv -i in.mkv -c copy -map 0 -f segment -list out.list out%03d.nut
+ffmpeg -re -i in.mkv -codec copy -map 0 -f segment -segment_list playlist.m3u8 \
+-segment_list_flags +live -segment_time 10 out%03d.mkv
@end example
+@end itemize
@section mp3
@@ -452,13 +754,14 @@ Examples:
Write an mp3 with an ID3v2.3 header and an ID3v1 footer:
@example
-avconv -i INPUT -id3v2_version 3 -write_id3v1 1 out.mp3
+ffmpeg -i INPUT -id3v2_version 3 -write_id3v1 1 out.mp3
@end example
-Attach a picture to an mp3:
+To attach a picture to an mp3 file select both the audio and the picture stream
+with @code{map}:
@example
-avconv -i input.mp3 -i cover.png -c copy -metadata:s:v title="Album cover"
--metadata:s:v comment="Cover (Front)" out.mp3
+ffmpeg -i input.mp3 -i cover.png -c copy -map 0 -map 1
+-metadata:s:v title="Album cover" -metadata:s:v comment="Cover (Front)" out.mp3
@end example
@section ogg
@@ -476,4 +779,39 @@ situations, giving a small seek granularity at the cost of additional container
overhead.
@end table
+@section tee
+
+The tee muxer can be used to write the same data to several files or any
+other kind of muxer. It can be used, for example, to both stream a video to
+the network and save it to disk at the same time.
+
+It is different from specifying several outputs to the @command{ffmpeg}
+command-line tool because the audio and video data will be encoded only once
+with the tee muxer; encoding can be a very expensive process. It is not
+useful when using the libavformat API directly because it is then possible
+to feed the same packets to several muxers directly.
+
+The slave outputs are specified in the file name given to the muxer,
+separated by '|'. If any of the slave name contains the '|' separator,
+leading or trailing spaces or any special character, it must be
+escaped (see the ``Quoting and escaping'' section in the ffmpeg-utils
+manual).
+
+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.
+
+Example: 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
+
+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..5896aba 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 which allow to 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,10 +22,133 @@ 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 oss
OSS (Open Sound System) output device.
+@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.
+@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.
diff --git a/doc/platform.texi b/doc/platform.texi
index 80dd029..0703000 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++
-Libav can be built with MSVC using a C99-to-C89 conversion utility and
+FFmpeg can be built with MSVC using a C99-to-C89 conversion utility and
wrapper.
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}
@@ -160,20 +165,20 @@ 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 Visual Studio 2010 and 2012, Pro and Express.
+@item FFmpeg has been tested with Visual Studio 2010 and 2012, Pro and Express.
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
@@ -225,14 +230,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
@@ -250,7 +255,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
@@ -260,7 +265,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
@@ -292,7 +297,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.
@@ -308,7 +313,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.
@@ -346,7 +351,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 498a808..c369cfd 100644
--- a/doc/print_options.c
+++ b/doc/print_options.c
@@ -115,6 +115,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 c777d83..0c56b8b 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
+Protocols are configured elements in FFmpeg which allow to access
resources which require the use of a particular protocol.
-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,41 @@ 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 concat
Physical concatenation protocol.
@@ -36,28 +66,37 @@ 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 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".
@@ -89,6 +128,63 @@ 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 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 +209,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,18 +234,18 @@ 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
Note that some formats (typically MOV), require the output protocol to
@@ -264,10 +360,10 @@ 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
@section rtmpe
@@ -340,14 +436,14 @@ 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
@@ -370,7 +466,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:
@@ -411,7 +507,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}.
@@ -421,27 +517,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
@@ -491,19 +592,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
@@ -525,13 +626,13 @@ 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 tcp
@@ -548,13 +649,60 @@ 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
+@section tls
+
+Transport Layer Security/Secure Sockets Layer
+
+The required syntax for a TLS/SSL url is:
+@example
+tls://@var{hostname}:@var{port}[?@var{options}]
+@end example
+
+@table @option
+
+@item listen
+Act as a server, listening for an incoming connection.
+
+@item cafile=@var{filename}
+Certificate authority file. The file must be in OpenSSL PEM format.
+
+@item cert=@var{filename}
+Certificate file. The file must be in OpenSSL PEM format.
+
+@item key=@var{filename}
+Private key file.
+
+@item verify=@var{0|1}
+Verify the peer's certificate.
+
+@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.
@@ -565,15 +713,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
@@ -581,13 +736,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
@@ -607,23 +762,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
@c man end PROTOCOLS
diff --git a/doc/resampler.texi b/doc/resampler.texi
new file mode 100644
index 0000000..d37d53d
--- /dev/null
+++ b/doc/resampler.texi
@@ -0,0 +1,222 @@
+@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
+Set the input channel layout.
+
+@item ocl, out_channel_layout
+Set the output channel layout.
+
+@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 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.
+
+@end table
+
+@c man end RESAMPLER OPTIONS
diff --git a/doc/scaler.texi b/doc/scaler.texi
new file mode 100644
index 0000000..c33b6d9
--- /dev/null
+++ b/doc/scaler.texi
@@ -0,0 +1,99 @@
+@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
+
+@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.
+
+@end table
+
+@c man end SCALER OPTIONS
diff --git a/doc/snow.txt b/doc/snow.txt
new file mode 100644
index 0000000..f991339
--- /dev/null
+++ b/doc/snow.txt
@@ -0,0 +1,630 @@
+=============================================
+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
+ 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<2; 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<2; 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)
+ 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
+
+
+
+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
+ 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
--- /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..2aab488 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,15 @@ $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">
EOT
$PRE_BODY_CLOSE = '</div></div>';
@@ -141,8 +24,8 @@ $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 ?
@@ -152,9 +35,9 @@ sub Libav_print_page_foot($$)
print $fh "</span></footer></div>\n";
}
-$float = \&Libav_float;
+$float = \&FFmpeg_float;
-sub Libav_float($$$$)
+sub FFmpeg_float($$$$)
{
my $text = shift;
my $float = shift;
@@ -181,8 +64,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 +78,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>
@@ -218,6 +101,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..75f7fdc
--- /dev/null
+++ b/doc/utils.texi
@@ -0,0 +1,592 @@
+@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
+
+The accepted syntax is:
+@example
+[-][HH:]MM:SS[.m...]
+[-]S+[.m...]
+@end example
+
+@var{HH} expresses the number of hours, @var{MM} the number a of minutes
+and @var{SS} the number of seconds.
+
+@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
+@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 (case insensitive match) or a
+[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 (0x00/0.0 means completely transparent,
+0xff/1.0 completely opaque).
+If the alpha component is not specified then 0xff is assumed.
+
+The string "random" will result in a random color.
+
+@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/avconv.c b/ffmpeg.c
index 7f8c6a6..785c334 100644
--- a/avconv.c
+++ b/ffmpeg.c
@@ -1,36 +1,47 @@
/*
- * avconv main
- * Copyright (c) 2000-2011 The libav developers.
+ * 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
*/
+/**
+ * @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 <signal.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 "libavresample/avresample.h"
+#include "libswresample/swresample.h"
#include "libavutil/opt.h"
#include "libavutil/channel_layout.h"
#include "libavutil/parseutils.h"
@@ -44,9 +55,14 @@
#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"
@@ -67,36 +83,64 @@
#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 "avconv.h"
+#include "ffmpeg.h"
#include "cmdutils.h"
#include "libavutil/avassert.h"
-const char program_name[] = "avconv";
+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 "av2pass"
+#define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass"
InputStream **input_streams = NULL;
int nb_input_streams = 0;
@@ -111,9 +155,159 @@ int nb_output_files = 0;
FilterGraph **filtergraphs;
int nb_filtergraphs;
-static void term_exit(void)
+#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)
{
- av_log(NULL, AV_LOG_QUIET, "");
+ 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;
@@ -125,10 +319,40 @@ sigterm_handler(int sig)
received_sigterm = sig;
received_nb_signals++;
term_exit();
+ if(received_nb_signals > 3)
+ exit(123);
}
-static void term_init(void)
+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;
+ atexit(term_exit);
+
+ 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
@@ -136,6 +360,62 @@ static void term_init(void)
#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;
@@ -147,6 +427,11 @@ static void exit_program(void)
{
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++) {
@@ -164,10 +449,12 @@ static void exit_program(void)
}
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->oformat->flags & AVFMT_NOFILE) && s->pb)
+ if (s && !(s->oformat->flags & AVFMT_NOFILE) && s->pb)
avio_close(s->pb);
avformat_free_context(s);
av_dict_free(&output_files[i]->opts);
@@ -184,10 +471,14 @@ static void exit_program(void)
avcodec_free_frame(&output_streams[i]->filtered_frame);
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]);
@@ -196,6 +487,8 @@ static void exit_program(void)
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]);
}
@@ -216,7 +509,6 @@ static void exit_program(void)
if (received_sigterm) {
av_log(NULL, AV_LOG_INFO, "Received signal %d: terminating.\n",
(int) received_sigterm);
- exit (255);
}
}
@@ -231,74 +523,23 @@ void assert_avoptions(AVDictionary *m)
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(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)
+static void update_benchmark(const char *fmt, ...)
{
- /* 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 (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);
}
-
- /* if none match, provide the one that matches quality closest */
- dec->request_sample_fmt = min_inc != INT_MAX ? inc_fmt : dec_fmt;
+ current_time = t;
}
}
@@ -308,6 +549,10 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
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
@@ -329,6 +574,17 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
&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,
@@ -336,7 +592,7 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
if (!new_pkt.buf)
exit(1);
} else if (a < 0) {
- av_log(NULL, AV_LOG_ERROR, "%s failed for stream %d, codec %s",
+ 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);
@@ -349,25 +605,41 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
}
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 "
+ (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(1);
}
- av_log(NULL, AV_LOG_WARNING, "changing to %"PRId64". This may result "
+ av_log(s, loglevel, "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);
+ 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);
@@ -375,6 +647,17 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
}
}
+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];
@@ -382,7 +665,7 @@ static int check_recording_time(OutputStream *ost)
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;
+ close_output_stream(ost);
return 0;
}
return 1;
@@ -399,14 +682,20 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
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\n");
+ av_log(NULL, AV_LOG_FATAL, "Audio encoding failed (avcodec_encode_audio2)\n");
exit(1);
}
+ update_benchmark("encode_audio %d.%d", ost->file_index, ost->index);
if (got_packet) {
if (pkt.pts != AV_NOPTS_VALUE)
@@ -416,25 +705,32 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
if (pkt.duration > 0)
pkt.duration = av_rescale_q(pkt.duration, enc->time_base, ost->st->time_base);
- write_frame(s, &pkt, ost);
+ 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,
- int64_t pts)
+ AVSubtitle *sub)
{
- static uint8_t *subtitle_out = NULL;
int subtitle_out_max_size = 1024 * 1024;
int subtitle_out_size, nb, i;
AVCodecContext *enc;
AVPacket pkt;
+ int64_t pts;
- if (pts == AV_NOPTS_VALUE) {
+ if (sub->pts == AV_NOPTS_VALUE) {
av_log(NULL, AV_LOG_ERROR, "Subtitle packets must have a pts\n");
if (exit_on_error)
exit(1);
@@ -455,16 +751,20 @@ static void do_subtitle_out(AVFormatContext *s,
else
nb = 1;
+ /* shift timestamp to honor -ss and make check_recording_time() work with -t */
+ pts = sub->pts - output_files[ost->file_index]->start_time;
for (i = 0; i < nb; i++) {
- ost->sync_opts = av_rescale_q(pts, ist->st->time_base, enc->time_base);
+ ost->sync_opts = av_rescale_q(pts, AV_TIME_BASE_Q, enc->time_base);
if (!check_recording_time(ost))
return;
- sub->pts = av_rescale_q(pts, ist->st->time_base, AV_TIME_BASE_Q);
+ 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) {
@@ -476,6 +776,7 @@ static void do_subtitle_out(AVFormatContext *s,
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 */
@@ -484,47 +785,90 @@ static void do_subtitle_out(AVFormatContext *s,
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 *frame_size)
+ 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));
- *frame_size = 0;
+ 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_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) {
+ 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);
}
- 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;
-
+ /* 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 &&
@@ -534,42 +878,99 @@ static void do_video_out(AVFormatContext *s,
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;
+ 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]) {
- in_picture->pict_type = AV_PICTURE_TYPE_I;
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(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);
- write_frame(s, &pkt, ost);
- *frame_size = pkt.size;
+ 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) {
@@ -584,6 +985,10 @@ static void do_video_out(AVFormatContext *s,
* 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)
@@ -608,14 +1013,14 @@ static void do_video_stats(OutputStream *ost, int frame_size)
enc = ost->st->codec;
if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
- frame_number = ost->frame_number;
+ 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->sync_opts * av_q2d(enc->time_base);
+ ti1 = ost->st->pts.val * av_q2d(enc->time_base);
if (ti1 < 0.01)
ti1 = 0.01;
@@ -627,135 +1032,105 @@ static void do_video_stats(OutputStream *ost, int frame_size)
}
}
-/*
- * 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) {
- filtered_frame->pts = av_rescale_q(filtered_frame->pts,
- ost->filter->filter->inputs[0]->time_base,
- ost->st->codec->time_base) -
- av_rescale_q(of->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.
+/**
+ * Get and encode new output from any of the filtergraphs, without causing
+ * activity.
*
- * 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.
+ * @return 0 for success, <0 for severe errors
*/
-static int poll_filters(void)
+static int reap_filters(void)
{
- int i, j, ret = 0;
-
- while (ret >= 0 && !received_sigterm) {
- OutputStream *ost = NULL;
- int64_t min_pts = INT64_MAX;
+ AVFrame *filtered_frame = NULL;
+ int i;
+ int64_t frame_pts;
- /* choose output stream with the lowest timestamp */
- for (i = 0; i < nb_output_streams; i++) {
- int64_t pts = output_streams[i]->sync_opts;
+ /* 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 (!output_streams[i]->filter || output_streams[i]->finished)
- continue;
+ if (!ost->filter)
+ 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->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;
}
- }
-
- if (!ost)
- break;
-
- ret = poll_filter(ost);
+ frame_pts = AV_NOPTS_VALUE;
+ if (filtered_frame->pts != AV_NOPTS_VALUE) {
+ 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(of->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
- if (ret == AVERROR_EOF) {
- OutputFile *of = output_files[ost->file_index];
- ost->finished = 1;
+ 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;
- if (of->shortest) {
- for (j = 0; j < of->ctx->nb_streams; j++)
- output_streams[of->ost_index + j]->finished = 1;
+ 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);
}
- ret = 0;
- } else if (ret == AVERROR(EAGAIN))
- return 0;
+ av_frame_unref(filtered_frame);
+ }
}
- return ret;
+ return 0;
}
-static void print_report(int is_last_report, int64_t timer_start)
+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, ti1, pts;
+ 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)
+ if (!print_stats && !is_last_report && !progress_avio)
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;
@@ -771,17 +1146,10 @@ static void print_report(int is_last_report, int64_t timer_start)
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;
+ av_bprint_init(&buf_script, 0, 1);
for (i = 0; i < nb_output_streams; i++) {
float q = -1;
ost = output_streams[i];
@@ -790,13 +1158,20 @@ static void print_report(int is_last_report, int64_t timer_start)
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 t = (av_gettime() - timer_start) / 1000000.0;
+ float fps, t = (cur_time-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);
+ 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) {
@@ -807,10 +1182,11 @@ static void print_report(int is_last_report, int64_t timer_start)
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) {
+ 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++) {
@@ -825,43 +1201,91 @@ static void print_report(int is_last_report, int64_t timer_start)
scale /= 4;
error_sum += error;
scale_sum += scale;
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%c:%2.2f ", type[j], psnr(error / 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 */
- pts = (double)ost->st->pts.val * av_q2d(ost->st->time_base);
- if ((pts < ti1) && (pts > 0))
- ti1 = pts;
+ 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));
}
- if (ti1 < 0.01)
- ti1 = 0.01;
- bitrate = (double)(total_size * 8) / ti1 / 1000.0;
+ 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),
- "size=%8.0fkB time=%0.2f bitrate=%6.1fkbits/s",
- (double)total_size / 1024, ti1, bitrate);
+ "%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);
- av_log(NULL, AV_LOG_INFO, "%s \r", buf);
+ 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 + extra_size;
+ 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 global headers:%1.0fkB muxing overhead %f%%\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");
+ }
}
}
@@ -910,12 +1334,14 @@ static void flush_encoders(void)
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(1);
}
- *size += ret;
+ *size += pkt.size;
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
@@ -930,6 +1356,9 @@ static void flush_encoders(void)
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)
@@ -949,7 +1378,7 @@ static int check_output_constraints(InputStream *ist, OutputStream *ost)
if (ost->source_index != ist_index)
return 0;
- if (of->start_time && ist->last_dts < of->start_time)
+ if (of->start_time && ist->pts < of->start_time)
return 0;
return 1;
@@ -959,6 +1388,7 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
{
OutputFile *of = output_files[ost->file_index];
int64_t ost_tb_start_time = av_rescale_q(of->start_time, AV_TIME_BASE_Q, ost->st->time_base);
+ AVPicture pict;
AVPacket opkt;
av_init_packet(&opkt);
@@ -967,9 +1397,13 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
!ost->copy_initial_nonkeyframes)
return;
+ if (!ost->frame_number && ist->pts < of->start_time &&
+ !ost->copy_prior_start)
+ return;
+
if (of->recording_time != INT64_MAX &&
- ist->last_dts >= of->recording_time + of->start_time) {
- ost->finished = 1;
+ ist->pts >= of->recording_time + of->start_time) {
+ close_output_stream(ost);
return;
}
@@ -979,6 +1413,8 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
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)
@@ -987,11 +1423,20 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
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);
+ 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;
@@ -1011,6 +1456,14 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
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++;
}
@@ -1022,6 +1475,8 @@ int guess_input_channel_layout(InputStream *ist)
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;
@@ -1038,6 +1493,7 @@ 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);
@@ -1045,23 +1501,38 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
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 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;
- }
+#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 ||
@@ -1097,17 +1568,44 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
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(1);
+ 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(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_q(decoded_frame->pts,
- ist->st->time_base,
- (AVRational){1, ist->st->codec->sample_rate});
+ 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;
@@ -1116,11 +1614,12 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
break;
} else
f = decoded_frame;
-
- err = av_buffersrc_add_frame(ist->filters[i]->filter, f);
+ err = av_buffersrc_add_frame_flags(ist->filters[i]->filter, f,
+ AV_BUFFERSRC_FLAG_PUSH);
if (err < 0)
break;
}
+ decoded_frame->pts = AV_NOPTS_VALUE;
av_frame_unref(ist->filter_frame);
av_frame_unref(decoded_frame);
@@ -1132,25 +1631,53 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
AVFrame *decoded_frame, *f;
void *buffer_to_free = NULL;
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;
}
- decoded_frame->pts = guess_correct_pts(&ist->pts_ctx, decoded_frame->pkt_pts,
- decoded_frame->pkt_dts);
+ 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)
@@ -1166,23 +1693,24 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
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) &&
+ 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(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);
@@ -1190,10 +1718,12 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
break;
} else
f = decoded_frame;
-
- err = av_buffersrc_add_frame(ist->filters[i]->filter, f);
- if (err < 0)
- break;
+ ret = av_buffersrc_add_frame_flags(ist->filters[i]->filter, f, AV_BUFFERSRC_FLAG_PUSH);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL,
+ "Failed to inject frame into filter network: %s\n", av_err2str(ret));
+ exit(1);
+ }
}
av_frame_unref(ist->filter_frame);
@@ -1207,9 +1737,35 @@ 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)
+
+ 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 (!*got_output)
+ }
+
+ 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++) {
@@ -1218,7 +1774,7 @@ static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
if (!check_output_constraints(ist, ost) || !ost->encoding_needed)
continue;
- do_subtitle_out(output_files[ost->file_index]->ctx, ost, ist, &subtitle, pkt->pts);
+ do_subtitle_out(output_files[ost->file_index]->ctx, ost, ist, &subtitle);
}
avsubtitle_free(&subtitle);
@@ -1228,12 +1784,24 @@ static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
/* pkt = NULL means EOF (needed to flush decoder buffers) */
static int output_packet(InputStream *ist, const AVPacket *pkt)
{
- int i;
- int got_output;
+ 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->last_dts;
+ ist->next_dts = ist->dts;
+ if (ist->next_pts == AV_NOPTS_VALUE)
+ ist->next_pts = ist->pts;
if (pkt == NULL) {
/* EOF handling */
@@ -1245,15 +1813,19 @@ static int output_packet(InputStream *ist, const AVPacket *pkt)
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);
+ 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 ret = 0;
+ int duration;
handle_eof:
- ist->last_dts = ist->next_dts;
+ 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,
@@ -1267,16 +1839,23 @@ static int output_packet(InputStream *ist, const AVPacket *pkt)
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);
- }
+ 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);
@@ -1287,8 +1866,14 @@ static int output_packet(InputStream *ist, const AVPacket *pkt)
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;
}
@@ -1299,21 +1884,30 @@ static int output_packet(InputStream *ist, const AVPacket *pkt)
/* handle stream copy */
if (!ist->decoding_needed) {
- ist->last_dts = ist->next_dts;
+ 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->st->codec->time_base.num != 0) {
- int ticks = ist->st->parser ? ist->st->parser->repeat_pict + 1 : ist->st->codec->ticks_per_frame;
+ 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];
@@ -1346,26 +1940,17 @@ static void print_sdp(void)
static int init_input_stream(int ist_index, char *error, int error_len)
{
- int i, ret;
+ int 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);
+ 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);
}
- /* 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))
@@ -1380,9 +1965,8 @@ static int init_input_stream(int ist_index, char *error, int error_len)
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_pts = AV_NOPTS_VALUE;
ist->next_dts = AV_NOPTS_VALUE;
- init_pts_correction(&ist->pts_ctx);
ist->is_start = 1;
return 0;
@@ -1392,32 +1976,28 @@ 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 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;
- int64_t t;
+ int n = 1, i, size, index = 0;
+ int64_t t, *pts;
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) {
+ 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(1);
}
@@ -1429,11 +2009,58 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost,
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);
+ 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(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)
@@ -1505,9 +2132,10 @@ static int transcode_init(void)
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_tag(oc->oformat->codec_tag, icodec->codec_id) <= 0)
+ !av_codec_get_tag2(oc->oformat->codec_tag, icodec->codec_id, &codec_tag))
codec->codec_tag = icodec->codec_tag;
}
@@ -1520,14 +2148,59 @@ static int transcode_init(void)
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;
+ 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);
switch (codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
@@ -1541,19 +2214,31 @@ static int transcode_init(void)
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 (!codec->sample_aspect_ratio.num) {
+ if (ost->frame_aspect_ratio.num) { // overridden by the -aspect cli option
+ codec->sample_aspect_ratio =
+ ost->st->sample_aspect_ratio =
+ 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 (!codec->sample_aspect_ratio.num) {
codec->sample_aspect_ratio =
ost->st->sample_aspect_ratio =
ist->st->sample_aspect_ratio.num ? ist->st->sample_aspect_ratio :
ist->st->codec->sample_aspect_ratio.num ?
ist->st->codec->sample_aspect_ratio : (AVRational){0, 1};
}
+ ost->st->avg_frame_rate = ist->st->avg_frame_rate;
break;
case AVMEDIA_TYPE_SUBTITLE:
codec->width = icodec->width;
@@ -1566,46 +2251,20 @@ static int transcode_init(void)
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), "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);
+ 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 = 1;
+ ist->decoding_needed++;
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)) {
@@ -1617,45 +2276,95 @@ static int transcode_init(void)
}
}
+ 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 = av_get_channel_layout_nb_channels(codec->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 = ost->filter->filter->inputs[0]->time_base;
+ 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 ? // overridden by the -aspect cli option
- av_d2q(ost->frame_aspect_ratio * codec->height/codec->width, 255) :
+ 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_INFO,
+ "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));
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 (!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)
- parse_forced_key_frames(ost->forced_keyframes, ost,
- ost->st->codec);
+ 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))) {
+ if (codec->flags & (CODEC_FLAG_PASS1 | CODEC_FLAG_PASS2)) {
char logfilename[1024];
FILE *f;
@@ -1666,15 +2375,7 @@ static int transcode_init(void)
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(1);
- }
- ost->logfile = f;
- } else {
+ if (codec->flags & CODEC_FLAG_PASS2) {
char *logbuffer;
size_t logbuffer_size;
if (cmdutils_read_file(logfilename, &logbuffer, &logbuffer_size) < 0) {
@@ -1684,6 +2385,15 @@ static int transcode_init(void)
}
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(1);
+ }
+ ost->logfile = f;
+ }
}
}
}
@@ -1699,7 +2409,8 @@ static int transcode_init(void)
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);
+ /* 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;
@@ -1716,10 +2427,14 @@ static int transcode_init(void)
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");
+ " It takes bits/s as argument, not kbits/s\n");
extra_size += ost->st->codec->extradata_size;
if (ost->st->codec->me_threshold)
@@ -1731,8 +2446,13 @@ static int transcode_init(void)
/* init input streams */
for (i = 0; i < nb_input_streams; i++)
- if ((ret = init_input_stream(i, error, sizeof(error))) < 0)
+ 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++) {
@@ -1763,7 +2483,7 @@ static int transcode_init(void)
ret = AVERROR(EINVAL);
goto dump_format;
}
- assert_avoptions(output_files[i]->opts);
+// assert_avoptions(output_files[i]->opts);
if (strcmp(oc->oformat->name, "rtp")) {
want_sdp = 0;
}
@@ -1860,7 +2580,7 @@ static int need_output(void)
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;
+ close_output_stream(output_streams[of->ost_index + j]);
continue;
}
@@ -1870,27 +2590,120 @@ static int need_output(void)
return 0;
}
-static InputFile *select_input_file(void)
+/**
+ * Select the output stream to process.
+ *
+ * @return selected output stream, or NULL if none available
+ */
+static OutputStream *choose_output(void)
{
- InputFile *ifile = NULL;
- int64_t ipts_min = INT64_MAX;
int i;
+ int64_t opts_min = INT64_MAX;
+ OutputStream *ost_min = NULL;
- for (i = 0; i < nb_input_streams; i++) {
- InputStream *ist = input_streams[i];
- int64_t ipts = ist->last_dts;
+ 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;
+}
- 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];
+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> <time> <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:%s\n", i, ret, buf);
+ } 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);
}
}
-
- return ifile;
+ 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 filtergraph\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
@@ -2009,7 +2822,7 @@ static int get_input_packet(InputFile *f, AVPacket *pkt)
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 pts = av_rescale(ist->dts, 1000000, AV_TIME_BASE);
int64_t now = av_gettime() - ist->start;
if (pts > now)
return AVERROR(EAGAIN);
@@ -2026,8 +2839,8 @@ static int get_input_packet(InputFile *f, AVPacket *pkt)
static int got_eagain(void)
{
int i;
- for (i = 0; i < nb_input_files; i++)
- if (input_files[i]->eagain)
+ for (i = 0; i < nb_output_streams; i++)
+ if (output_streams[i]->unavailable)
return 1;
return 0;
}
@@ -2037,41 +2850,25 @@ 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;
}
/*
- * 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)
+static int process_input(int file_index)
{
- InputFile *ifile;
+ InputFile *ifile = input_files[file_index];
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);
@@ -2098,7 +2895,7 @@ static int process_input(void)
if (ost->source_index == ifile->ist_index + i &&
(ost->stream_copy || ost->enc->type == AVMEDIA_TYPE_SUBTITLE))
- ost->finished= 1;
+ close_output_stream(ost);
}
}
@@ -2113,13 +2910,62 @@ static int process_input(void)
}
/* the following test is needed in case new streams appear
dynamically in stream : we ignore them */
- if (pkt.stream_index >= ifile->nb_streams)
+ 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)
@@ -2130,12 +2976,32 @@ static int process_input(void)
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 &&
- (is->iformat->flags & AVFMT_TS_DISCONT)) {
+ !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 ((FFABS(delta) > 1LL * dts_delta_threshold * AV_TIME_BASE || pkt_dts + 1 < ist->last_dts) && !copy_ts) {
+ 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+1<ist->pts){
ifile->ts_offset -= delta;
av_log(NULL, AV_LOG_DEBUG,
"timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
@@ -2144,12 +3010,46 @@ static int process_input(void)
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) {
- av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d\n",
- ist->file_index, ist->st->index);
+ 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(1);
}
@@ -2160,12 +3060,104 @@ discard_packet:
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, need_input = 1;
+ int ret, i;
AVFormatContext *os;
OutputStream *ost;
InputStream *ist;
@@ -2175,8 +3167,9 @@ static int transcode(void)
if (ret < 0)
goto fail;
- av_log(NULL, AV_LOG_INFO, "Press ctrl-c to stop encoding\n");
- term_init();
+ if (stdin_interaction) {
+ av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n");
+ }
timer_start = av_gettime();
@@ -2186,20 +3179,20 @@ static int transcode(void)
#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;
}
- /* read and process one input packet if needed */
- if (need_input) {
- ret = process_input();
- if (ret == AVERROR_EOF)
- need_input = 0;
- }
-
- ret = poll_filters();
+ ret = transcode_step();
if (ret < 0) {
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
continue;
@@ -2209,7 +3202,7 @@ static int transcode(void)
}
/* dump report by using the output first video and audio streams */
- print_report(0, timer_start);
+ print_report(0, timer_start, cur_time);
}
#if HAVE_PTHREADS
free_input_threads();
@@ -2222,7 +3215,6 @@ static int transcode(void)
output_packet(ist, NULL);
}
}
- poll_filters();
flush_encoders();
term_exit();
@@ -2234,7 +3226,7 @@ static int transcode(void)
}
/* dump report by using the first video and audio streams */
- print_report(1, timer_start);
+ print_report(1, timer_start, av_gettime());
/* close each encoder */
for (i = 0; i < nb_output_streams; i++) {
@@ -2272,8 +3264,10 @@ static int transcode(void)
ost->logfile = NULL;
}
av_freep(&ost->st->codec->subtitle_header);
- av_free(ost->forced_kf_pts);
+ 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);
}
}
@@ -2281,6 +3275,7 @@ static int transcode(void)
return ret;
}
+
static int64_t getutime(void)
{
#if HAVE_GETRUSAGE
@@ -2317,6 +3312,10 @@ static int64_t getmaxrss(void)
#endif
}
+static void log_callback_null(void *ptr, int level, const char *fmt, va_list vl)
+{
+}
+
int main(int argc, char **argv)
{
int ret;
@@ -2324,9 +3323,18 @@ int main(int argc, char **argv)
atexit(exit_program);
+ 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();
@@ -2335,10 +3343,12 @@ int main(int argc, char **argv)
av_register_all();
avformat_network_init();
- show_banner();
+ show_banner(argc, argv, options);
+
+ term_init();
/* parse options and open all input/output files */
- ret = avconv_parse_options(argc, argv);
+ ret = ffmpeg_parse_options(argc, argv);
if (ret < 0)
exit(1);
@@ -2350,19 +3360,27 @@ int main(int argc, char **argv)
/* file converter / grab */
if (nb_output_files <= 0) {
- fprintf(stderr, "At least one output file must be specified\n");
+ av_log(NULL, AV_LOG_FATAL, "At least one output file must be specified\n");
exit(1);
}
- ti = getutime();
+// if (nb_input_files == 0) {
+// av_log(NULL, AV_LOG_FATAL, "At least one input file must be specified\n");
+// exit(1);
+// }
+
+ current_time = ti = getutime();
if (transcode() < 0)
exit(1);
ti = getutime() - ti;
if (do_benchmark) {
- int maxrss = getmaxrss() / 1024;
- printf("bench: utime=%0.3fs maxrss=%ikB\n", ti / 1000000.0, maxrss);
+ 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 (2*decode_error_stat[0] < decode_error_stat[1])
+ exit(254);
- exit(0);
+ exit(received_nb_signals ? 255 : 0);
return 0;
}
diff --git a/avconv.h b/ffmpeg.h
index 1244d86..24e6d47 100644
--- a/avconv.h
+++ b/ffmpeg.h
@@ -1,28 +1,29 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef AVCONV_H
-#define AVCONV_H
+#ifndef FFMPEG_H
+#define FFMPEG_H
#include "config.h"
#include <stdint.h>
#include <stdio.h>
+#include <signal.h>
#if HAVE_PTHREADS
#include <pthread.h>
@@ -39,14 +40,20 @@
#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 {
@@ -58,12 +65,10 @@ typedef struct StreamMap {
char *linklabel; /* name of an output link, for mapping lavfi outputs */
} StreamMap;
-/* select an input file for an output file */
-typedef struct MetadataMap {
- int file; // file index
- char type; // type of metadata to copy -- (g)lobal, (s)tream, (c)hapter or (p)rogram
- int index; // stream/chapter/program number
-} MetadataMap;
+typedef struct {
+ int file_idx, stream_idx, channel_idx; // input
+ int ofile_idx, ostream_idx; // output
+} AudioChannelMap;
typedef struct OptionsContext {
OptionGroup *g;
@@ -97,9 +102,8 @@ typedef struct OptionsContext {
/* output options */
StreamMap *stream_maps;
int nb_stream_maps;
- /* first item specifies output metadata, second is input */
- MetadataMap (*meta_data_maps)[2];
- int nb_meta_data_maps;
+ AudioChannelMap *audio_channel_maps; /* one info entry per -map_channel */
+ int nb_audio_channel_maps; /* number of (valid) -map_channel settings */
int metadata_global_manual;
int metadata_streams_manual;
int metadata_chapters_manual;
@@ -109,6 +113,7 @@ typedef struct OptionsContext {
int chapters_input_file;
int64_t recording_time;
+ int64_t stop_time;
uint64_t limit_filesize;
float mux_preload;
float mux_max_delay;
@@ -155,14 +160,26 @@ typedef struct OptionsContext {
int nb_presets;
SpecifierOpt *copy_initial_nonkeyframes;
int nb_copy_initial_nonkeyframes;
+ SpecifierOpt *copy_prior_start;
+ int nb_copy_prior_start;
SpecifierOpt *filters;
int nb_filters;
SpecifierOpt *filter_scripts;
int nb_filter_scripts;
+ SpecifierOpt *reinit_filters;
+ int nb_reinit_filters;
+ SpecifierOpt *fix_sub_duration;
+ int nb_fix_sub_duration;
+ SpecifierOpt *canvas_sizes;
+ int nb_canvas_sizes;
SpecifierOpt *pass;
int nb_pass;
SpecifierOpt *passlogfiles;
int nb_passlogfiles;
+ SpecifierOpt *guess_layout_max;
+ int nb_guess_layout_max;
+ SpecifierOpt *apad;
+ int nb_apad;
} OptionsContext;
typedef struct InputFilter {
@@ -187,6 +204,7 @@ typedef struct FilterGraph {
const char *graph_desc;
AVFilterGraph *graph;
+ int reconfiguration;
InputFilter **inputs;
int nb_inputs;
@@ -205,16 +223,24 @@ typedef struct InputStream {
int64_t start; /* time when read started */
/* predicted dts of the next packet read for this stream or (when there are
- * several frames in a packet) of the next frame in current packet */
+ * several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */
int64_t next_dts;
- /* dts of the last packet read for this stream */
- int64_t last_dts;
- PtsCorrectionContext pts_ctx;
+ int64_t dts; ///< dts of the last packet read for this stream (in AV_TIME_BASE units)
+
+ int64_t next_pts; ///< synthetic pts for the next decode frame (in AV_TIME_BASE units)
+ int64_t pts; ///< current pts of the decoded frame (in AV_TIME_BASE units)
+ int wrap_correction_done;
+
+ int64_t filter_in_rescale_delta_last;
+
double ts_scale;
int 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;
@@ -225,20 +251,40 @@ typedef struct InputStream {
int resample_channels;
uint64_t resample_channel_layout;
+ int fix_sub_duration;
+ struct { /* previous decoded subtitle and related variables */
+ int got_output;
+ int ret;
+ AVSubtitle subtitle;
+ } prev_sub;
+
+ struct sub2video {
+ int64_t last_pts;
+ int64_t end_pts;
+ AVFrame *frame;
+ int w, h;
+ } sub2video;
+
+ int dr1;
+
/* decoded data from this stream goes into all those filters
* currently video and audio only */
InputFilter **filters;
int nb_filters;
+
+ int reinit_filters;
} 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 */
+ int ist_index; /* index of first stream in input_streams */
int64_t ts_offset;
- int nb_streams; /* number of stream that avconv is aware of; may be different
+ int64_t last_ts;
+ 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;
#if HAVE_PTHREADS
@@ -251,6 +297,17 @@ typedef struct InputFile {
#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 */
@@ -260,7 +317,6 @@ typedef struct OutputStream {
int frame_number;
/* input pts and corresponding output pts
for A/V sync */
- // double sync_ipts; /* dts from the AVPacket of the demuxer in second units */
struct InputStream *sync_ist; /* input stream to sync against */
int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ // FIXME look at frame_number
/* pts of the first frame encoded for this stream, used for limiting
@@ -278,13 +334,19 @@ typedef struct OutputStream {
int force_fps;
int top_field_first;
- float frame_aspect_ratio;
+ AVRational frame_aspect_ratio;
/* forced key frames */
int64_t *forced_kf_pts;
int forced_kf_count;
int forced_kf_index;
char *forced_keyframes;
+ AVExpr *forced_keyframes_pexpr;
+ double forced_keyframes_expr_const_values[FKF_NB];
+
+ /* audio only */
+ int audio_channels_map[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;
@@ -294,22 +356,26 @@ typedef struct OutputStream {
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;
- enum AVPixelFormat pix_fmts[2];
+ int keep_pix_fmt;
} 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;
+ 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;
@@ -331,28 +397,35 @@ 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 const AVIOInterruptCB int_cb;
extern const OptionDef options[];
-void reset_options(OptionsContext *o);
-void show_usage(void);
+void term_init(void);
+void term_exit(void);
-int opt_cpuflags(void *optctx, const char *opt, const char *arg);
+void reset_options(OptionsContext *o, int is_input);
+void show_usage(void);
void opt_output_file(void *optctx, const char *filename);
@@ -360,11 +433,14 @@ 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 avconv_parse_options(int argc, char **argv);
+int ffmpeg_parse_options(int argc, char **argv);
-#endif /* AVCONV_H */
+#endif /* FFMPEG_H */
diff --git a/avconv_filter.c b/ffmpeg_filter.c
index da8949c..ed4c9b1 100644
--- a/avconv_filter.c
+++ b/ffmpeg_filter.c
@@ -1,37 +1,137 @@
/*
- * avconv filter configuration
+ * ffmpeg filter configuration
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "avconv.h"
+#include "ffmpeg.h"
#include "libavfilter/avfilter.h"
+#include "libavfilter/buffersink.h"
#include "libavresample/avresample.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
#include "libavutil/channel_layout.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "libavutil/pixfmt.h"
+#include "libavutil/imgutils.h"
#include "libavutil/samplefmt.h"
+enum AVPixelFormat choose_pixel_fmt(AVStream *st, 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)
+{
+ 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(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) \
@@ -60,8 +160,8 @@ static char *choose_ ## var ## s(OutputStream *ost) \
return NULL; \
}
-DEF_CHOOSE_FORMAT(enum AVPixelFormat, pix_fmt, pix_fmts, AV_PIX_FMT_NONE,
- GET_PIX_FMT_NAME)
+// DEF_CHOOSE_FORMAT(enum AVPixelFormat, pix_fmt, pix_fmts, AV_PIX_FMT_NONE,
+// GET_PIX_FMT_NAME)
DEF_CHOOSE_FORMAT(enum AVSampleFormat, sample_fmt, sample_fmts,
AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME)
@@ -123,14 +223,17 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
int file_idx = strtol(in->name, &p, 0);
if (file_idx < 0 || file_idx >= nb_input_files) {
- av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtegraph description %s.\n",
+ av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtergraph description %s.\n",
file_idx, fg->graph_desc);
exit(1);
}
s = input_files[file_idx]->ctx;
for (i = 0; i < s->nb_streams; i++) {
- if (s->streams[i]->codec->codec_type != type)
+ enum AVMediaType stream_type = s->streams[i]->codec->codec_type;
+ if (stream_type != type &&
+ !(stream_type == AVMEDIA_TYPE_SUBTITLE &&
+ type == AVMEDIA_TYPE_VIDEO /* sub2video hack */))
continue;
if (check_stream_specifier(s, s->streams[i], *p == ':' ? p + 1 : p) == 1) {
st = s->streams[i];
@@ -152,7 +255,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
}
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,
+ "unlabeled input pad %d on filter %s\n", in->pad_idx,
in->filter_ctx->name);
exit(1);
}
@@ -160,7 +263,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
av_assert0(ist);
ist->discard = 0;
- ist->decoding_needed = 1;
+ ist->decoding_needed++;
ist->st->discard = AVDISCARD_NONE;
GROW_ARRAY(fg->inputs, fg->nb_inputs);
@@ -186,6 +289,10 @@ static int insert_trim(OutputStream *ost, AVFilterContext **last_filter, int *pa
if (of->recording_time == INT64_MAX && !of->start_time)
return 0;
+ // Use with duration and without output starttime is buggy with trim filters
+ if (!of->start_time)
+ return 0;
+
trim = avfilter_get_by_name(name);
if (!trim) {
av_log(NULL, AV_LOG_ERROR, "%s filter not present, cannot limit "
@@ -239,6 +346,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
ret = avfilter_graph_create_filter(&ofilter->filter,
avfilter_get_by_name("buffersink"),
name, NULL, NULL, fg->graph);
+
if (ret < 0)
return ret;
@@ -266,20 +374,21 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
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,
+ ret = avfilter_graph_create_filter(&filter,
avfilter_get_by_name("format"),
"format", pix_fmts, NULL,
- fg->graph)) < 0)
+ 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;
- av_freep(&pix_fmts);
}
- if (ost->frame_rate.num) {
+ if (ost->frame_rate.num && 0) {
AVFilterContext *fps;
char args[255];
@@ -315,18 +424,53 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
OutputStream *ost = ofilter->ost;
AVCodecContext *codec = ost->st->codec;
AVFilterContext *last_filter = out->filter_ctx;
+ OutputFile *of = output_files[ost->file_index];
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);
@@ -337,18 +481,17 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
if (sample_fmts || sample_rates || channel_layouts) {
AVFilterContext *format;
char args[256];
- int len = 0;
+ args[0] = 0;
if (sample_fmts)
- len += snprintf(args + len, sizeof(args) - len, "sample_fmts=%s:",
+ av_strlcatf(args, sizeof(args), "sample_fmts=%s:",
sample_fmts);
if (sample_rates)
- len += snprintf(args + len, sizeof(args) - len, "sample_rates=%s:",
+ av_strlcatf(args, sizeof(args), "sample_rates=%s:",
sample_rates);
if (channel_layouts)
- len += snprintf(args + len, sizeof(args) - len, "channel_layouts=%s:",
+ av_strlcatf(args, sizeof(args), "channel_layouts=%s:",
channel_layouts);
- args[len - 1] = 0;
av_freep(&sample_fmts);
av_freep(&sample_rates);
@@ -370,6 +513,27 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
pad_idx = 0;
}
+ if (audio_volume != 256 && 0) {
+ char args[256];
+
+ snprintf(args, sizeof(args), "%f", audio_volume / 256.);
+ AUTO_INSERT_FILTER("-vol", "volume", args);
+ }
+
+ if (ost->apad && of->shortest) {
+ char args[256];
+ int i;
+
+ for (i=0; i<of->ctx->nb_streams; i++)
+ if (of->ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ break;
+
+ if (i<of->ctx->nb_streams) {
+ snprintf(args, sizeof(args), "%s", ost->apad);
+ AUTO_INSERT_FILTER("-apad", "apad", args);
+ }
+ }
+
ret = insert_trim(ost, &last_filter, &pad_idx);
if (ret < 0)
return ret;
@@ -409,6 +573,42 @@ int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOu
}
}
+static int sub2video_prepare(InputStream *ist)
+{
+ AVFormatContext *avf = input_files[ist->file_index]->ctx;
+ int i, w, h;
+
+ /* Compute the size of the canvas for the subtitles stream.
+ If the subtitles codec has set a size, use it. Otherwise use the
+ maximum dimensions of the video streams in the same file. */
+ w = ist->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)
{
@@ -417,22 +617,41 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
InputStream *ist = ifilter->ist;
AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) :
ist->st->time_base;
+ AVRational fr = ist->framerate;
AVRational sar;
- char args[255], name[255];
+ AVBPrint args;
+ char name[255];
int pad_idx = in->pad_idx;
int ret;
+ 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;
- 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);
+ 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, filter, name,
- args, NULL, fg->graph)) < 0)
+ args.str, NULL, fg->graph)) < 0)
return ret;
if (ist->framerate.num) {
@@ -453,6 +672,24 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
pad_idx = 0;
}
+ 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(yadif, 0, first_filter, pad_idx)) < 0)
+ return ret;
+
+ first_filter = yadif;
+ pad_idx = 0;
+ }
+
if ((ret = avfilter_link(ifilter->filter, 0, first_filter, pad_idx)) < 0)
return ret;
return 0;
@@ -465,73 +702,81 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
AVFilter *filter = avfilter_get_by_name("abuffer");
InputStream *ist = ifilter->ist;
int pad_idx = in->pad_idx;
- char args[255], name[255];
+ AVBPrint args;
+ char name[255];
int ret;
- snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s"
- ":channel_layout=0x%"PRIx64,
+ 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),
- ist->st->codec->channel_layout);
+ 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, filter,
- name, args, NULL,
+ name, args.str, NULL,
fg->graph)) < 0)
return ret;
+#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(filt_ctx, 0, first_filter, pad_idx); \
+ if (ret < 0) \
+ return ret; \
+ \
+ first_filter = filt_ctx; \
+} while (0)
+
if (audio_sync_method > 0) {
- AVFilterContext *async;
- int len = 0;
-
- av_log(NULL, AV_LOG_WARNING, "-async has been deprecated. Used the "
- "asyncts audio filter instead.\n");
-
- if (audio_sync_method > 1)
- len += snprintf(args + len, sizeof(args) - len, "compensate=1:"
- "max_comp=%d:", audio_sync_method);
- snprintf(args + len, sizeof(args) - len, "min_delta=%f",
- audio_drift_threshold);
-
- snprintf(name, sizeof(name), "graph %d audio sync for input stream %d:%d",
- fg->index, ist->file_index, ist->st->index);
- ret = avfilter_graph_create_filter(&async,
- avfilter_get_by_name("asyncts"),
- name, args, NULL, fg->graph);
- if (ret < 0)
- return ret;
+ char args[256] = {0};
+
+ av_strlcatf(args, sizeof(args), "async=%d", audio_sync_method);
+ if (audio_drift_threshold != 0.1)
+ av_strlcatf(args, sizeof(args), ":min_hard_comp=%f", audio_drift_threshold);
+ if (!fg->reconfiguration)
+ av_strlcatf(args, sizeof(args), ":first_pts=0");
+ AUTO_INSERT_FILTER_INPUT("-async", "aresample", args);
+ }
- ret = avfilter_link(async, 0, first_filter, pad_idx);
- if (ret < 0)
- return ret;
+// if (ost->audio_channels_mapped) {
+// int i;
+// AVBPrint pan_buf;
+// av_bprint_init(&pan_buf, 256, 8192);
+// av_bprintf(&pan_buf, "0x%"PRIx64,
+// av_get_default_channel_layout(ost->audio_channels_mapped));
+// for (i = 0; i < ost->audio_channels_mapped; i++)
+// if (ost->audio_channels_map[i] != -1)
+// av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
+// AUTO_INSERT_FILTER_INPUT("-map_channel", "pan", pan_buf.str);
+// av_bprint_finalize(&pan_buf, NULL);
+// }
- first_filter = async;
- pad_idx = 0;
- }
if (audio_volume != 256) {
- AVFilterContext *volume;
+ char args[256];
av_log(NULL, AV_LOG_WARNING, "-vol has been deprecated. Use the volume "
"audio filter instead.\n");
- snprintf(args, sizeof(args), "volume=%f", audio_volume / 256.0);
-
- snprintf(name, sizeof(name), "graph %d volume for input stream %d:%d",
- fg->index, ist->file_index, ist->st->index);
- ret = avfilter_graph_create_filter(&volume,
- avfilter_get_by_name("volume"),
- name, args, NULL, fg->graph);
- if (ret < 0)
- return ret;
-
- ret = avfilter_link(volume, 0, first_filter, pad_idx);
- if (ret < 0)
- return ret;
-
- first_filter = volume;
- pad_idx = 0;
+ snprintf(args, sizeof(args), "%f", audio_volume / 256.);
+ AUTO_INSERT_FILTER_INPUT("-vol", "volume", args);
}
if ((ret = avfilter_link(ifilter->filter, 0, first_filter, pad_idx)) < 0)
return ret;
@@ -571,6 +816,15 @@ int configure_filtergraph(FilterGraph *fg)
snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags);
fg->graph->scale_sws_opts = av_strdup(args);
+ args[0] = 0;
+ while ((e = av_dict_get(ost->swr_opts, "", e,
+ AV_DICT_IGNORE_SUFFIX))) {
+ av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
+ }
+ if (strlen(args))
+ args[strlen(args)-1] = 0;
+ av_opt_set(fg->graph, "aresample_swr_opts", args, 0);
+
args[0] = '\0';
while ((e = av_dict_get(fg->outputs[0]->ost->resample_opts, "", e,
AV_DICT_IGNORE_SUFFIX))) {
@@ -620,6 +874,7 @@ int configure_filtergraph(FilterGraph *fg)
}
}
+ fg->reconfiguration = 1;
return 0;
}
diff --git a/avconv_opt.c b/ffmpeg_opt.c
index ae9b72e..2aff601 100644
--- a/avconv_opt.c
+++ b/ffmpeg_opt.c
@@ -1,26 +1,26 @@
/*
- * avconv option parsing
+ * ffmpeg option parsing
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
-#include "avconv.h"
+#include "ffmpeg.h"
#include "cmdutils.h"
#include "libavformat/avformat.h"
@@ -53,30 +53,50 @@
}\
}
+#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 copy_tb = -1;
+int debug_ts = 0;
int exit_on_error = 0;
-int print_stats = 1;
+int print_stats = -1;
int qp_hist = 0;
+int stdin_interaction = 1;
+int frame_bits_per_raw_sample = 0;
+
+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 using_stdin = 0;
+static int do_psnr = 0;
static int input_sync;
-static void uninit_options(OptionsContext *o)
+static int64_t recording_time = INT64_MAX;
+
+static void uninit_options(OptionsContext *o, int is_input)
{
const OptionDef *po = options;
int i;
@@ -103,16 +123,29 @@ static void uninit_options(OptionsContext *o)
for (i = 0; i < o->nb_stream_maps; i++)
av_freep(&o->stream_maps[i].linklabel);
av_freep(&o->stream_maps);
- av_freep(&o->meta_data_maps);
+ av_freep(&o->audio_channel_maps);
av_freep(&o->streamid_map);
+ av_freep(&o->attachments);
+
+ if (is_input)
+ recording_time = o->recording_time;
+ else
+ recording_time = INT64_MAX;
}
-static void init_options(OptionsContext *o)
+static void init_options(OptionsContext *o, int is_input)
{
memset(o, 0, sizeof(*o));
+ if (!is_input && recording_time != INT64_MAX) {
+ o->recording_time = recording_time;
+ av_log(NULL, AV_LOG_WARNING,
+ "-t is not an input option, keeping it for the next output;"
+ " consider fixing your command line.\n");
+ } else
+ o->recording_time = INT64_MAX;
+ o->stop_time = INT64_MAX;
o->mux_max_delay = 0.7;
- o->recording_time = INT64_MAX;
o->limit_filesize = UINT64_MAX;
o->chapters_input_file = INT_MAX;
}
@@ -135,28 +168,25 @@ static AVDictionary *strip_specifiers(AVDictionary *dict)
return ret;
}
-static double parse_frame_aspect_ratio(const char *arg)
+static int opt_sameq(void *optctx, const char *opt, const char *arg)
{
- int x = 0, y = 0;
- double ar = 0;
- const char *p;
- char *end;
+ av_log(NULL, AV_LOG_ERROR, "Option '%s' was removed. "
+ "If you are looking for an option to preserve the quality (which is not "
+ "what -%s was for), use -qscale 0 or an equivalent quality factor option.\n",
+ opt, opt);
+ return AVERROR(EINVAL);
+}
- p = strchr(arg, ':');
- if (p) {
- x = strtol(arg, &end, 10);
- if (end == p)
- y = strtol(end + 1, &end, 10);
- if (x > 0 && y > 0)
- ar = (double)x / (double)y;
- } else
- ar = strtod(arg, NULL);
+static int opt_video_channel(void *optctx, const char *opt, const char *arg)
+{
+ av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -channel.\n");
+ return opt_default(optctx, "channel", arg);
+}
- if (!ar) {
- av_log(NULL, AV_LOG_FATAL, "Incorrect aspect ratio specification.\n");
- exit(1);
- }
- return ar;
+static int opt_video_standard(void *optctx, const char *opt, const char *arg)
+{
+ av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -standard.\n");
+ return opt_default(optctx, "standard", arg);
}
static int opt_audio_codec(void *optctx, const char *opt, const char *arg)
@@ -188,7 +218,7 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
OptionsContext *o = optctx;
StreamMap *m = NULL;
int i, negative = 0, file_idx;
- int sync_file_idx = -1, sync_stream_idx;
+ int sync_file_idx = -1, sync_stream_idx = 0;
char *p, *sync;
char *map;
@@ -286,6 +316,65 @@ static int opt_attach(void *optctx, const char *opt, const char *arg)
return 0;
}
+static int opt_map_channel(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ int n;
+ AVStream *st;
+ AudioChannelMap *m;
+
+ GROW_ARRAY(o->audio_channel_maps, o->nb_audio_channel_maps);
+ m = &o->audio_channel_maps[o->nb_audio_channel_maps - 1];
+
+ /* muted channel syntax */
+ n = sscanf(arg, "%d:%d.%d", &m->channel_idx, &m->ofile_idx, &m->ostream_idx);
+ if ((n == 1 || n == 3) && m->channel_idx == -1) {
+ m->file_idx = m->stream_idx = -1;
+ if (n == 1)
+ m->ofile_idx = m->ostream_idx = -1;
+ return 0;
+ }
+
+ /* normal syntax */
+ n = sscanf(arg, "%d.%d.%d:%d.%d",
+ &m->file_idx, &m->stream_idx, &m->channel_idx,
+ &m->ofile_idx, &m->ostream_idx);
+
+ if (n != 3 && n != 5) {
+ av_log(NULL, AV_LOG_FATAL, "Syntax error, mapchan usage: "
+ "[file.stream.channel|-1][:syncfile:syncstream]\n");
+ exit(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(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(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(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(1);
+ }
+ return 0;
+}
+
/**
* Parse a metadata specifier passed as 'arg' parameter.
* @param arg metadata string to parse
@@ -323,7 +412,7 @@ static void parse_meta_type(char *arg, char *type, int *index, const char **stre
static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
{
AVDictionary **meta_in = NULL;
- AVDictionary **meta_out;
+ AVDictionary **meta_out = NULL;
int i, ret = 0;
char type_in, type_out;
const char *istream_spec = NULL, *ostream_spec = NULL;
@@ -332,6 +421,16 @@ static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFor
parse_meta_type(inspec, &type_in, &idx_in, &istream_spec);
parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);
+ if (!ic) {
+ if (type_out == 'g' || !*outspec)
+ o->metadata_global_manual = 1;
+ if (type_out == 's' || !*outspec)
+ o->metadata_streams_manual = 1;
+ if (type_out == 'c' || !*outspec)
+ o->metadata_chapters_manual = 1;
+ return 0;
+ }
+
if (type_in == 'g' || type_out == 'g')
o->metadata_global_manual = 1;
if (type_in == 's' || type_out == 's')
@@ -400,6 +499,20 @@ static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFor
return 0;
}
+static int opt_recording_timestamp(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ char buf[128];
+ int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;
+ struct tm time = *gmtime((time_t*)&recording_timestamp);
+ 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;
@@ -447,6 +560,7 @@ static AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *
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];
@@ -468,11 +582,30 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
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 (dec->lowres) {
+ dec->flags |= CODEC_FLAG_EMU_EDGE;
+ }
+
ist->resample_height = dec->height;
ist->resample_width = dec->width;
ist->resample_pix_fmt = dec->pix_fmt;
@@ -485,8 +618,13 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
exit(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;
@@ -496,7 +634,19 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
break;
case AVMEDIA_TYPE_DATA:
- case AVMEDIA_TYPE_SUBTITLE:
+ case AVMEDIA_TYPE_SUBTITLE: {
+ char *canvas_size = NULL;
+ if(!ist->dec)
+ ist->dec = avcodec_find_decoder(dec->codec_id);
+ MATCH_PER_STREAM_OPT(fix_sub_duration, i, ist->fix_sub_duration, ic, st);
+ MATCH_PER_STREAM_OPT(canvas_sizes, str, canvas_size, ic, st);
+ if (canvas_size &&
+ av_parse_video_size(&dec->width, &dec->height, canvas_size) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid canvas size: %s.\n", canvas_size);
+ exit(1);
+ }
+ break;
+ }
case AVMEDIA_TYPE_ATTACHMENT:
case AVMEDIA_TYPE_UNKNOWN:
break;
@@ -508,20 +658,23 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
static void assert_file_overwrite(const char *filename)
{
- if (!file_overwrite &&
+ if ((!file_overwrite || no_file_overwrite) &&
(strchr(filename, ':') == NULL || filename[1] == ':' ||
av_strstart(filename, "file:", NULL))) {
if (avio_check(filename, 0) == 0) {
- if (!using_stdin) {
+ if (stdin_interaction && (!no_file_overwrite || file_overwrite)) {
fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
fflush(stderr);
+ term_exit();
+ signal(SIGINT, SIG_DFL);
if (!read_yesno()) {
- fprintf(stderr, "Not overwriting - exiting\n");
+ av_log(NULL, AV_LOG_FATAL, "Not overwriting - exiting\n");
exit(1);
}
+ term_init();
}
else {
- fprintf(stderr,"File '%s' already exists. Exiting.\n", filename);
+ av_log(NULL, AV_LOG_FATAL, "File '%s' already exists. Exiting.\n", filename);
exit(1);
}
}
@@ -572,6 +725,9 @@ static int open_input_file(OptionsContext *o, const char *filename)
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))) {
@@ -583,8 +739,8 @@ static int open_input_file(OptionsContext *o, const char *filename)
if (!strcmp(filename, "-"))
filename = "pipe:";
- using_stdin |= !strncmp(filename, "pipe:", 5) ||
- !strcmp(filename, "/dev/stdin");
+ stdin_interaction &= strncmp(filename, "pipe:", 5) &&
+ strcmp(filename, "/dev/stdin");
/* get default parameters from command line */
ic = avformat_alloc_context();
@@ -624,10 +780,20 @@ static int open_input_file(OptionsContext *o, const char *filename)
if (o->nb_frame_pix_fmts)
av_dict_set(&o->g->format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0);
+ MATCH_PER_TYPE_OPT(codec_names, str, video_codec_name, ic, "v");
+ MATCH_PER_TYPE_OPT(codec_names, str, audio_codec_name, ic, "a");
+ MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, ic, "s");
+
+ ic->video_codec_id = video_codec_name ?
+ find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0)->id : AV_CODEC_ID_NONE;
+ ic->audio_codec_id = audio_codec_name ?
+ find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)->id : AV_CODEC_ID_NONE;
+ ic->subtitle_codec_id= subtitle_codec_name ?
+ find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)->id : AV_CODEC_ID_NONE;
ic->flags |= AVFMT_FLAG_NONBLOCK;
ic->interrupt_callback = int_cb;
- /* open the input file with generic libav function */
+ /* 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);
@@ -659,7 +825,7 @@ static int open_input_file(OptionsContext *o, const char *filename)
/* if seeking requested, we execute it */
if (o->start_time != 0) {
- ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
+ ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, timestamp, 0);
if (ret < 0) {
av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
filename, (double)timestamp / AV_TIME_BASE);
@@ -797,7 +963,7 @@ static void choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *
}
}
-static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type)
+static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type, int source_index)
{
OutputStream *ost;
AVStream *st = avformat_new_stream(oc, NULL);
@@ -805,6 +971,7 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
char *bsf = NULL, *next, *codec_tag = NULL;
AVBitStreamFilterContext *bsfc, *bsfc_prev = NULL;
double qscale = -1;
+ int i;
if (!st) {
av_log(NULL, AV_LOG_FATAL, "Could not alloc stream.\n");
@@ -863,6 +1030,16 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
ost->max_frames = INT64_MAX;
MATCH_PER_STREAM_OPT(max_frames, i64, ost->max_frames, oc, st);
+ for (i = 0; i<o->nb_max_frames; i++) {
+ char *p = o->max_frames[i].specifier;
+ if (!*p && type != AVMEDIA_TYPE_VIDEO) {
+ av_log(NULL, AV_LOG_WARNING, "Applying unspecific -frames to non video streams, maybe you meant -vframes ?\n");
+ break;
+ }
+ }
+
+ ost->copy_prior_start = -1;
+ MATCH_PER_STREAM_OPT(copy_prior_start, i, ost->copy_prior_start, oc ,st);
MATCH_PER_STREAM_OPT(bitstream_filters, str, bsf, oc, st);
while (bsf) {
@@ -900,9 +1077,18 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
av_opt_get_int(o->g->sws_opts, "sws_flags", 0, &ost->sws_flags);
+ av_dict_copy(&ost->swr_opts, o->g->swr_opts, 0);
+ if (ost->enc && av_get_exact_bits_per_sample(ost->enc->id) == 24)
+ av_dict_set(&ost->swr_opts, "output_sample_bits", "24", 0);
+
av_dict_copy(&ost->resample_opts, o->g->resample_opts, 0);
- ost->pix_fmts[0] = ost->pix_fmts[1] = AV_PIX_FMT_NONE;
+ ost->source_index = source_index;
+ if (source_index >= 0) {
+ ost->sync_ist = input_streams[source_index];
+ input_streams[source_index]->discard = 0;
+ input_streams[source_index]->st->discard = AVDISCARD_NONE;
+ }
ost->last_mux_dts = AV_NOPTS_VALUE;
return ost;
@@ -978,47 +1164,63 @@ static char *get_ost_filters(OptionsContext *o, AVFormatContext *oc,
"null" : "anull");
}
-static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
+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);
+ 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(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(1);
+ }
+ ost->frame_aspect_ratio = q;
+ }
+
if (!ost->stream_copy) {
const char *p = NULL;
- char *frame_rate = NULL, *frame_size = NULL;
- char *frame_aspect_ratio = NULL, *frame_pix_fmt = 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_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(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(1);
}
- 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);
-
+ 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(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))) {
@@ -1044,6 +1246,7 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
av_log(NULL, AV_LOG_FATAL, "error parsing rc_override\n");
exit(1);
}
+ /* FIXME realloc failure */
video_enc->rc_override =
av_realloc(video_enc->rc_override,
sizeof(RcOverride) * (i + 1));
@@ -1063,13 +1266,19 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
video_enc->rc_override_count = i;
video_enc->intra_dc_precision = intra_dc_precision - 8;
+ if (do_psnr)
+ video_enc->flags|= CODEC_FLAG_PSNR;
+
/* two pass mode */
MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
if (do_pass) {
- if (do_pass == 1) {
+ if (do_pass & 1) {
video_enc->flags |= CODEC_FLAG_PASS1;
- } else {
+ av_dict_set(&ost->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);
}
}
@@ -1098,13 +1307,14 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
return ost;
}
-static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
+static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
{
+ int n;
AVStream *st;
OutputStream *ost;
AVCodecContext *audio_enc;
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO);
+ ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO, source_index);
st = ost->st;
audio_enc = st->codec;
@@ -1124,19 +1334,37 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
+ MATCH_PER_STREAM_OPT(apad, str, ost->apad, oc, st);
+ ost->apad = av_strdup(ost->apad);
+
ost->avfilter = get_ost_filters(o, oc, ost);
if (!ost->avfilter)
exit(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)
+static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
{
OutputStream *ost;
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA);
+ ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA, source_index);
if (!ost->stream_copy) {
av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
exit(1);
@@ -1145,26 +1373,38 @@ static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc)
return ost;
}
-static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc)
+static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
{
- OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT);
+ OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT, source_index);
ost->stream_copy = 1;
ost->finished = 1;
return ost;
}
-static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc)
+static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
{
AVStream *st;
OutputStream *ost;
AVCodecContext *subtitle_enc;
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE);
+ ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE, source_index);
st = ost->st;
subtitle_enc = 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(1);
+ }
+ }
+
return ost;
}
@@ -1185,7 +1425,7 @@ static int opt_streamid(void *optctx, const char *opt, const char *arg)
exit(1);
}
*p++ = '\0';
- idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, INT_MAX);
+ idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, MAX_STREAMS-1);
o->streamid_map = grow_array(o->streamid_map, sizeof(*o->streamid_map), &o->nb_streamid_map, idx+1);
o->streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX);
return 0;
@@ -1198,7 +1438,7 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata)
AVChapter **tmp;
int i;
- tmp = av_realloc(os->chapters, sizeof(*os->chapters) * (is->nb_chapters + os->nb_chapters));
+ tmp = av_realloc_f(os->chapters, is->nb_chapters + os->nb_chapters, sizeof(*os->chapters));
if (!tmp)
return AVERROR(ENOMEM);
os->chapters = tmp;
@@ -1233,6 +1473,49 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata)
return 0;
}
+static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename)
+{
+ int i, err;
+ AVFormatContext *ic = avformat_alloc_context();
+
+ ic->interrupt_callback = int_cb;
+ err = avformat_open_input(&ic, filename, NULL, NULL);
+ if (err < 0)
+ return err;
+ /* copy stream format */
+ for(i=0;i<ic->nb_streams;i++) {
+ AVStream *st;
+ OutputStream *ost;
+ AVCodec *codec;
+ AVCodecContext *avctx;
+
+ codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
+ 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);
+ }
+
+ /* ffserver seeking with date=... needs a date reference */
+ err = parse_option(o, "metadata", "creation_time=now", options);
+
+ avformat_close_input(&ic);
+ return err;
+}
+
static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
AVFormatContext *oc)
{
@@ -1240,8 +1523,8 @@ static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
ofilter->out_tmp->pad_idx)) {
- case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc); break;
- case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc); break;
+ case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc, -1); break;
+ case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc, -1); break;
default:
av_log(NULL, AV_LOG_FATAL, "Only video and audio filters are supported "
"currently.\n");
@@ -1294,6 +1577,20 @@ static int open_output_file(OptionsContext *o, const char *filename)
exit(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) {
+ if (o->stop_time <= o->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 - o->start_time;
+ }
+ }
+
GROW_ARRAY(output_files, nb_output_files);
of = av_mallocz(sizeof(*of));
if (!of)
@@ -1310,33 +1607,18 @@ static int open_output_file(OptionsContext *o, const char *filename)
if (!strcmp(filename, "-"))
filename = "pipe:";
- oc = avformat_alloc_context();
+ err = avformat_alloc_output_context2(&oc, NULL, o->format, filename);
if (!oc) {
- print_error(filename, AVERROR(ENOMEM));
+ print_error(filename, err);
exit(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(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(1);
- }
- }
-
- oc->oformat = file_oformat;
+ file_oformat= oc->oformat;
oc->interrupt_callback = int_cb;
- av_strlcpy(oc->filename, filename, sizeof(oc->filename));
/* create streams for all unlabeled output pads */
for (i = 0; i < nb_filtergraphs; i++) {
@@ -1357,29 +1639,59 @@ static int open_output_file(OptionsContext *o, const char *filename)
}
}
- if (!o->nb_stream_maps) {
- /* pick the "best" stream of each type */
-#define NEW_STREAM(type, index)\
- if (index >= 0) {\
- ost = new_ ## type ## _stream(o, oc);\
- ost->source_index = index;\
- ost->sync_ist = input_streams[index];\
- input_streams[index]->discard = 0;\
- input_streams[index]->st->discard = AVDISCARD_NONE;\
+ if (!strcmp(file_oformat->name, "ffm") &&
+ 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(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(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 &&
- ist->st->codec->width * ist->st->codec->height > area) {
- area = ist->st->codec->width * ist->st->codec->height;
+ new_area > area) {
+ if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ continue;
+ area = new_area;
idx = i;
}
}
- NEW_STREAM(video, idx);
+ if (idx >= 0)
+ new_video_stream(o, oc, idx);
}
/* audio: most channels */
@@ -1393,14 +1705,16 @@ static int open_output_file(OptionsContext *o, const char *filename)
idx = i;
}
}
- NEW_STREAM(audio, idx);
+ if (idx >= 0)
+ new_audio_stream(o, oc, idx);
}
/* subtitles: pick first */
- if (!o->subtitle_disable && oc->oformat->subtitle_codec != AV_CODEC_ID_NONE) {
+ MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, oc, "s");
+ if (!o->subtitle_disable && (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_STREAM(subtitle, i);
+ new_subtitle_stream(o, oc, i);
break;
}
}
@@ -1430,29 +1744,34 @@ static int open_output_file(OptionsContext *o, const char *filename)
loop_end:
if (!ofilter) {
av_log(NULL, AV_LOG_FATAL, "Output with label '%s' does not exist "
- "in any defined filter graph.\n", map->linklabel);
+ "in any defined filter graph, or was already used elsewhere.\n", map->linklabel);
exit(1);
}
init_output_filter(ofilter, o, oc);
} else {
+ int src_idx = input_files[map->file_index]->ist_index + map->stream_index;
+
ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index];
+ if(o->subtitle_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
+ continue;
+ if(o-> audio_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ continue;
+ if(o-> video_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ continue;
+ if(o-> data_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_DATA)
+ continue;
+
switch (ist->st->codec->codec_type) {
- case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc); break;
- case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc); break;
- case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(o, oc); break;
- case AVMEDIA_TYPE_DATA: ost = new_data_stream(o, oc); break;
- case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc); break;
+ case AVMEDIA_TYPE_VIDEO: ost = new_video_stream (o, oc, src_idx); break;
+ case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream (o, oc, src_idx); break;
+ case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream (o, oc, src_idx); break;
+ case AVMEDIA_TYPE_DATA: ost = new_data_stream (o, oc, src_idx); break;
+ case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc, src_idx); break;
default:
av_log(NULL, AV_LOG_FATAL, "Cannot map stream #%d:%d - unsupported type.\n",
map->file_index, map->stream_index);
exit(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;
}
}
}
@@ -1481,10 +1800,10 @@ loop_end:
}
avio_read(pb, attachment, len);
- ost = new_attachment_stream(o, oc);
+ ost = new_attachment_stream(o, oc, -1);
ost->stream_copy = 0;
- ost->source_index = -1;
ost->attachment_filename = o->attachments[i];
+ ost->finished = 1;
ost->st->codec->extradata = attachment;
ost->st->codec->extradata_size = len;
@@ -1493,6 +1812,17 @@ loop_end:
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(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++) {
@@ -1545,7 +1875,8 @@ loop_end:
print_error(filename, err);
exit(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];
@@ -1553,7 +1884,6 @@ loop_end:
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++) {
@@ -1590,9 +1920,13 @@ loop_end:
!o->metadata_chapters_manual);
/* copy global metadata by default */
- if (!o->metadata_global_manual && nb_input_files)
+ if (!o->metadata_global_manual && nb_input_files){
av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata,
AV_DICT_DONT_OVERWRITE);
+ if(o->recording_time != INT64_MAX)
+ av_dict_set(&oc->metadata, "duration", NULL, 0);
+ av_dict_set(&oc->metadata, "creation_time", NULL, 0);
+ }
if (!o->metadata_streams_manual)
for (i = of->ost_index; i < nb_output_streams; i++) {
InputStream *ist;
@@ -1607,7 +1941,7 @@ loop_end:
AVDictionary **m;
char type, *val;
const char *stream_spec;
- int index = 0, j, ret;
+ int index = 0, j, ret = 0;
val = strchr(o->metadata[i].u.str, '=');
if (!val) {
@@ -1701,22 +2035,23 @@ static int opt_target(void *optctx, const char *opt, const char *arg)
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);
- opt_default(NULL, "g", norm == PAL ? "15" : "18");
+ av_dict_set(&o->g->codec_opts, "g", norm == PAL ? "15" : "18", 0);
- opt_default(NULL, "b", "1150000");
- opt_default(NULL, "maxrate", "1150000");
- opt_default(NULL, "minrate", "1150000");
- opt_default(NULL, "bufsize", "327680"); // 40*1024*8;
+ 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;
- opt_default(NULL, "b:a", "224000");
+ av_dict_set(&o->g->codec_opts, "b:a", "224000", 0);
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;
+ 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
@@ -1732,19 +2067,19 @@ static int opt_target(void *optctx, const char *opt, const char *arg)
parse_option(o, "s", norm == PAL ? "480x576" : "480x480", options);
parse_option(o, "r", frame_rates[norm], options);
- 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");
+ 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);
- opt_default(NULL, "b:a", "224000");
+ av_dict_set(&o->g->codec_opts, "b:a", "224000", 0);
parse_option(o, "ar", "44100", options);
- opt_default(NULL, "packetsize", "2324");
+ av_dict_set(&o->g->format_opts, "packetsize", "2324", 0);
} else if (!strcmp(arg, "dvd")) {
@@ -1754,17 +2089,18 @@ static int opt_target(void *optctx, const char *opt, const char *arg)
parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
parse_option(o, "r", frame_rates[norm], options);
- opt_default(NULL, "g", norm == PAL ? "15" : "18");
+ parse_option(o, "pix_fmt", "yuv420p", options);
+ av_dict_set(&o->g->codec_opts, "g", norm == PAL ? "15" : "18", 0);
- opt_default(NULL, "b", "6000000");
- opt_default(NULL, "maxrate", "9000000");
- opt_default(NULL, "minrate", "0"); // 1500000;
- opt_default(NULL, "bufsize", "1835008"); // 224*1024*8;
+ 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;
- 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
+ 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
- opt_default(NULL, "b:a", "448000");
+ av_dict_set(&o->g->codec_opts, "b:a", "448000", 0);
parse_option(o, "ar", "48000", options);
} else if (!strncmp(arg, "dv", 2)) {
@@ -1822,22 +2158,120 @@ static int opt_data_frames(void *optctx, const char *opt, const char *arg)
return parse_option(o, "frames:d", arg, options);
}
-static int opt_video_tag(void *optctx, const char *opt, const char *arg)
+static int opt_default_new(OptionsContext *o, const char *opt, const char *arg)
+{
+ int ret;
+ AVDictionary *cbak = codec_opts;
+ AVDictionary *fbak = format_opts;
+ codec_opts = NULL;
+ format_opts = NULL;
+
+ ret = opt_default(NULL, opt, arg);
+
+ av_dict_copy(&o->g->codec_opts , codec_opts, 0);
+ av_dict_copy(&o->g->format_opts, format_opts, 0);
+ av_dict_free(&codec_opts);
+ av_dict_free(&format_opts);
+ codec_opts = cbak;
+ format_opts = fbak;
+
+ return ret;
+}
+
+static int opt_preset(void *optctx, const char *opt, const char *arg)
{
OptionsContext *o = optctx;
- return parse_option(o, "tag:v", arg, options);
+ FILE *f=NULL;
+ char filename[1000], line[1000], tmp_line[1000];
+ const char *codec_name = NULL;
+
+ tmp_line[0] = *opt;
+ tmp_line[1] = 0;
+ MATCH_PER_TYPE_OPT(codec_names, str, codec_name, NULL, tmp_line);
+
+ if (!(f = get_preset_file(filename, sizeof(filename), arg, *opt == 'f', codec_name))) {
+ if(!strncmp(arg, "libx264-lossless", strlen("libx264-lossless"))){
+ av_log(NULL, AV_LOG_FATAL, "Please use -preset <speed> -qp 0\n");
+ }else
+ av_log(NULL, AV_LOG_FATAL, "File for preset '%s' not found\n", arg);
+ exit(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(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(1);
+ }
+ }
+
+ fclose(f);
+
+ return 0;
}
-static int opt_audio_tag(void *optctx, const char *opt, const char *arg)
+static int opt_old2new(void *optctx, const char *opt, const char *arg)
{
OptionsContext *o = optctx;
- return parse_option(o, "tag:a", arg, options);
+ char *s = av_asprintf("%s:%c", opt + 1, *opt);
+ int ret = parse_option(o, s, arg, options);
+ av_free(s);
+ return ret;
}
-static int opt_subtitle_tag(void *optctx, const char *opt, const char *arg)
+static int opt_bitrate(void *optctx, const char *opt, const char *arg)
{
OptionsContext *o = optctx;
- return parse_option(o, "tag:s", arg, options);
+ if(!strcmp(opt, "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)
@@ -1857,20 +2291,21 @@ 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;
}
-int opt_cpuflags(void *optctx, const char *opt, const char *arg)
+static int opt_timecode(void *optctx, const char *opt, const char *arg)
{
- int flags = av_parse_cpu_flags(arg);
-
- if (flags < 0)
- return flags;
-
- av_set_cpu_flags_mask(flags);
+ 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;
}
@@ -1889,7 +2324,7 @@ static int opt_channel_layout(void *optctx, const char *opt, const char *arg)
return AVERROR(EINVAL);
}
snprintf(layout_str, sizeof(layout_str), "%"PRIu64, layout);
- ret = opt_default(NULL, opt, layout_str);
+ ret = opt_default_new(o, opt, layout_str);
if (ret < 0)
return ret;
@@ -2003,15 +2438,16 @@ void show_help_default(const char *opt, const char *arg)
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);
+ show_help_children(swr_get_class(), AV_OPT_FLAG_AUDIO_PARAM);
+ show_help_children(avfilter_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM);
}
}
void show_usage(void)
{
- printf("Hyper fast Audio and Video encoder\n");
- printf("usage: %s [options] [[infile options] -i infile]... {[outfile options] outfile}...\n", program_name);
- printf("\n");
+ av_log(NULL, AV_LOG_INFO, "Hyper fast Audio and Video encoder\n");
+ av_log(NULL, AV_LOG_INFO, "usage: %s [options] [[infile options] -i infile]... {[outfile options] outfile}...\n", program_name);
+ av_log(NULL, AV_LOG_INFO, "\n");
}
enum OptGroup {
@@ -2033,7 +2469,7 @@ static int open_files(OptionGroupList *l, const char *inout,
OptionGroup *g = &l->groups[i];
OptionsContext o;
- init_options(&o);
+ init_options(&o, !strcmp(inout, "input"));
o.g = g;
ret = parse_optgroup(&o, g);
@@ -2045,7 +2481,7 @@ static int open_files(OptionGroupList *l, const char *inout,
av_log(NULL, AV_LOG_DEBUG, "Opening an %s file: %s.\n", inout, g->arg);
ret = open_file(&o, g->arg);
- uninit_options(&o);
+ uninit_options(&o, !strcmp(inout, "input"));
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error opening %s file %s.\n",
inout, g->arg);
@@ -2057,7 +2493,7 @@ static int open_files(OptionGroupList *l, const char *inout,
return 0;
}
-int avconv_parse_options(int argc, char **argv)
+int ffmpeg_parse_options(int argc, char **argv)
{
OptionParseContext octx;
uint8_t error[128];
@@ -2103,6 +2539,23 @@ fail:
return ret;
}
+static int opt_progress(void *optctx, const char *opt, const char *arg)
+{
+ AVIOContext *avio = NULL;
+ int ret;
+
+ if (!strcmp(arg, "-"))
+ arg = "pipe:";
+ ret = avio_open2(&avio, arg, AVIO_FLAG_WRITE, &int_cb, NULL);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Failed to open progress URL \"%s\": %s\n",
+ arg, av_err2str(ret));
+ return ret;
+ }
+ progress_avio = avio;
+ return 0;
+}
+
#define OFFSET(x) offsetof(OptionsContext, x)
const OptionDef options[] = {
/* main options */
@@ -2112,6 +2565,8 @@ const OptionDef options[] = {
"force format", "fmt" },
{ "y", OPT_BOOL, { &file_overwrite },
"overwrite output files" },
+ { "n", OPT_BOOL, { &no_file_overwrite },
+ "do not overwrite output files" },
{ "c", HAS_ARG | OPT_STRING | OPT_SPEC |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(codec_names) },
"codec name", "codec" },
@@ -2125,6 +2580,8 @@ const OptionDef options[] = {
OPT_OUTPUT, { .func_arg = opt_map },
"set input stream mapping",
"[-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]]" },
+ { "map_channel", HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_map_channel },
+ "map an audio channel from one stream to another", "file.stream.channel[:syncfile.syncstream]" },
{ "map_metadata", HAS_ARG | OPT_STRING | OPT_SPEC |
OPT_OUTPUT, { .off = OFFSET(metadata_map) },
"set metadata information of outfile from infile",
@@ -2132,9 +2589,11 @@ const OptionDef options[] = {
{ "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_OUTPUT, { .off = OFFSET(recording_time) },
+ { "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 |
@@ -2146,6 +2605,8 @@ const OptionDef options[] = {
{ "itsscale", HAS_ARG | OPT_DOUBLE | OPT_SPEC |
OPT_EXPERT | OPT_INPUT, { .off = OFFSET(ts_scale) },
"set the input ts scale", "scale" },
+ { "timestamp", HAS_ARG | OPT_PERFILE, { .func_arg = opt_recording_timestamp },
+ "set the recording timestamp ('now' to set the current time)", "time" },
{ "metadata", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(metadata) },
"add metadata", "string=string" },
{ "dframes", HAS_ARG | OPT_PERFILE | OPT_EXPERT |
@@ -2153,6 +2614,12 @@ const OptionDef options[] = {
"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 },
@@ -2173,18 +2640,25 @@ const OptionDef options[] = {
"audio drift threshold", "threshold" },
{ "copyts", OPT_BOOL | OPT_EXPERT, { &copy_ts },
"copy timestamps" },
- { "copytb", OPT_BOOL | OPT_EXPERT, { &copy_tb },
- "copy input stream time base when stream copying" },
+ { "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 |
@@ -2193,15 +2667,21 @@ const OptionDef options[] = {
{ "q", HAS_ARG | OPT_EXPERT | OPT_DOUBLE |
OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(qscale) },
"use fixed quality scale (VBR)", "q" },
- { "qscale", HAS_ARG | OPT_EXPERT | OPT_DOUBLE |
- OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(qscale) },
+ { "qscale", HAS_ARG | OPT_EXPERT | OPT_PERFILE |
+ OPT_OUTPUT, { .func_arg = opt_qscale },
"use fixed quality scale (VBR)", "q" },
+ { "profile", HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_profile },
+ "set profile", "profile" },
{ "filter", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filters) },
- "set stream filterchain", "filter_list" },
+ "set stream filtergraph", "filter_graph" },
{ "filter_script", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filter_scripts) },
"read stream filtergraph description from a file", "filename" },
+ { "reinit_filter", HAS_ARG | OPT_INT | OPT_SPEC | OPT_INPUT, { .off = OFFSET(reinit_filters) },
+ "reinit filtergraph on input parameter changes", "" },
{ "filter_complex", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex },
"create a complex filtergraph", "graph_description" },
+ { "lavfi", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex },
+ "create a complex filtergraph", "graph_description" },
{ "filter_complex_script", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex_script },
"read complex filtergraph description from a file", "filename" },
{ "stats", OPT_BOOL, { &print_stats },
@@ -2212,8 +2692,8 @@ const OptionDef options[] = {
{ "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC |
OPT_EXPERT | OPT_INPUT, { .off = OFFSET(dump_attachment) },
"extract an attachment into a file", "filename" },
- { "cpuflags", HAS_ARG | OPT_EXPERT, { .func_arg = opt_cpuflags },
- "set CPU flags mask", "mask" },
+ { "debug_ts", OPT_BOOL | OPT_EXPERT, { &debug_ts },
+ "print timestamp debugging info" },
/* video options */
{ "vframes", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_frames },
@@ -2221,7 +2701,7 @@ const OptionDef options[] = {
{ "r", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_rates) },
"set frame rate (Hz value, fraction or abbreviation)", "rate" },
- { "s", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
+ { "s", OPT_VIDEO | HAS_ARG | OPT_SUBTITLE | OPT_STRING | OPT_SPEC |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_sizes) },
"set frame size (WxH or abbreviation)", "size" },
{ "aspect", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
@@ -2230,7 +2710,11 @@ const OptionDef options[] = {
{ "pix_fmt", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_pix_fmts) },
"set pixel format", "format" },
- { "vn", OPT_VIDEO | OPT_BOOL | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(video_disable) },
+ { "bits_per_raw_sample", OPT_VIDEO | OPT_INT | HAS_ARG, { &frame_bits_per_raw_sample },
+ "set the number of bits per raw sample", "number" },
+ { "intra", OPT_VIDEO | OPT_BOOL | OPT_EXPERT, { &intra_only },
+ "deprecated use -g 1" },
+ { "vn", OPT_VIDEO | OPT_BOOL | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,{ .off = OFFSET(video_disable) },
"disable video" },
{ "vdt", OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT , { &video_discard },
"discard threshold", "n" },
@@ -2240,17 +2724,27 @@ const OptionDef options[] = {
{ "vcodec", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_INPUT |
OPT_OUTPUT, { .func_arg = opt_video_codec },
"force video codec ('copy' to copy stream)", "codec" },
+ { "sameq", OPT_VIDEO | OPT_EXPERT , { .func_arg = opt_sameq },
+ "Removed" },
+ { "same_quant", OPT_VIDEO | OPT_EXPERT , { .func_arg = opt_sameq },
+ "Removed" },
+ { "timecode", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_timecode },
+ "set initial TimeCode value.", "hh:mm:ss[:;.]ff" },
{ "pass", OPT_VIDEO | HAS_ARG | OPT_SPEC | OPT_INT | OPT_OUTPUT, { .off = OFFSET(pass) },
- "select the pass number (1 or 2)", "n" },
+ "select the pass number (1 to 3)", "n" },
{ "passlogfile", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC |
OPT_OUTPUT, { .off = OFFSET(passlogfiles) },
"select two pass log file name prefix", "prefix" },
+ { "deinterlace", OPT_VIDEO | OPT_BOOL | OPT_EXPERT, { &do_deinterlace },
+ "this option is deprecated, use the yadif filter instead" },
+ { "psnr", OPT_VIDEO | OPT_BOOL | OPT_EXPERT, { &do_psnr },
+ "calculate PSNR of compressed frames" },
{ "vstats", OPT_VIDEO | OPT_EXPERT , { &opt_vstats },
"dump video coding statistics to file" },
{ "vstats_file", OPT_VIDEO | HAS_ARG | OPT_EXPERT , { opt_vstats_file },
"dump video coding statistics to file", "file" },
{ "vf", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_filters },
- "video filters", "filter list" },
+ "set video filters", "filter_graph" },
{ "intra_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
OPT_OUTPUT, { .off = OFFSET(intra_matrices) },
"specify intra matrix coeffs", "matrix" },
@@ -2258,12 +2752,12 @@ const OptionDef options[] = {
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) },
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(top_field_first) },
"top=1/bottom=0/auto=-1 field first", "" },
{ "dc", OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT , { &intra_dc_precision },
"intra_dc_precision", "precision" },
{ "vtag", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
- OPT_OUTPUT, { .func_arg = opt_video_tag },
+ OPT_OUTPUT, { .func_arg = opt_old2new },
"force video tag/fourcc", "fourcc/tag" },
{ "qphist", OPT_VIDEO | OPT_BOOL | OPT_EXPERT , { &qp_hist },
"show QP histogram" },
@@ -2276,6 +2770,8 @@ const OptionDef options[] = {
{ "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(forced_key_frames) },
"force key frames at specified timestamps", "timestamps" },
+ { "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 },
@@ -2288,13 +2784,13 @@ const OptionDef options[] = {
{ "ac", OPT_AUDIO | HAS_ARG | OPT_INT | OPT_SPEC |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(audio_channels) },
"set number of audio channels", "channels" },
- { "an", OPT_AUDIO | OPT_BOOL | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(audio_disable) },
+ { "an", OPT_AUDIO | OPT_BOOL | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,{ .off = OFFSET(audio_disable) },
"disable audio" },
{ "acodec", OPT_AUDIO | HAS_ARG | OPT_PERFILE |
OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_audio_codec },
"force audio codec ('copy' to copy stream)", "codec" },
{ "atag", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
- OPT_OUTPUT, { .func_arg = opt_audio_tag },
+ OPT_OUTPUT, { .func_arg = opt_old2new },
"force audio tag/fourcc", "fourcc/tag" },
{ "vol", OPT_AUDIO | HAS_ARG | OPT_INT, { &audio_volume },
"change audio volume (256=normal)" , "volume" },
@@ -2305,17 +2801,27 @@ const OptionDef options[] = {
OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_channel_layout },
"set channel layout", "layout" },
{ "af", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_filters },
- "audio filters", "filter list" },
+ "set audio filters", "filter_graph" },
+ { "guess_layout_max", OPT_AUDIO | HAS_ARG | OPT_INT | OPT_SPEC | OPT_EXPERT | OPT_INPUT, { .off = OFFSET(guess_layout_max) },
+ "set the maximum number of channels to try to guess the channel layout" },
/* subtitle options */
- { "sn", OPT_SUBTITLE | OPT_BOOL | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(subtitle_disable) },
+ { "sn", OPT_SUBTITLE | OPT_BOOL | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(subtitle_disable) },
"disable subtitle" },
{ "scodec", OPT_SUBTITLE | HAS_ARG | OPT_PERFILE | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_subtitle_codec },
"force subtitle codec ('copy' to copy stream)", "codec" },
- { "stag", OPT_SUBTITLE | HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_subtitle_tag }
+ { "stag", OPT_SUBTITLE | HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_old2new }
, "force subtitle tag/fourcc", "fourcc/tag" },
+ { "fix_sub_duration", OPT_BOOL | OPT_EXPERT | OPT_SUBTITLE | OPT_SPEC | OPT_INPUT, { .off = OFFSET(fix_sub_duration) },
+ "fix subtitles duration" },
+ { "canvas_size", OPT_SUBTITLE | HAS_ARG | OPT_STRING | OPT_SPEC | OPT_INPUT, { .off = OFFSET(canvas_sizes) },
+ "set canvas size (WxH or abbreviation)", "size" },
/* grab options */
+ { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_channel },
+ "deprecated, use -channel", "channel" },
+ { "tvstd", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_standard },
+ "deprecated, use -standard", "standard" },
{ "isync", OPT_BOOL | OPT_EXPERT, { &input_sync }, "this option is deprecated and does nothing", "" },
/* muxer options */
@@ -2326,10 +2832,24 @@ const OptionDef options[] = {
{ "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/avplay.c b/ffplay.c
index ba59a8c..80c3091 100644
--- a/avplay.c
+++ b/ffplay.c
@@ -1,28 +1,33 @@
/*
- * avplay : Simple Media Player based on the Libav libraries
* 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
+ * 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"
@@ -31,36 +36,33 @@
#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 "libavresample/avresample.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 "cmdutils.h"
-
#include <SDL.h>
#include <SDL_thread.h>
-#ifdef __MINGW32__
-#undef main /* We don't want SDL to override our main() */
-#endif
+#include "cmdutils.h"
#include <assert.h>
-const char program_name[] = "avplay";
+const char program_name[] = "ffplay";
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
@@ -72,40 +74,55 @@ const int program_birth_year = 2003;
/* 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
+/* 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 */
-#define SAMPLE_ARRAY_SIZE (2 * 65536)
+/* 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 {
- AVPacketList *first_pkt, *last_pkt;
+ 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 2
+#define VIDEO_PICTURE_QUEUE_SIZE 4
#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;
+ int serial;
AVRational sar;
} VideoPicture;
@@ -115,6 +132,13 @@ typedef struct SubPicture {
AVSubtitle sub;
} SubPicture;
+typedef struct AudioParams {
+ int freq;
+ int channels;
+ int64_t channel_layout;
+ enum AVSampleFormat fmt;
+} AudioParams;
+
enum {
AV_SYNC_AUDIO_MASTER, /* default choice */
AV_SYNC_VIDEO_MASTER,
@@ -122,28 +146,33 @@ enum {
};
typedef struct VideoState {
- SDL_Thread *parse_tid;
+ SDL_Thread *read_tid;
SDL_Thread *video_tid;
- SDL_Thread *refresh_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_stream;
int av_sync_type;
- double external_clock; /* external clock base */
- int64_t external_clock_time;
+ double external_clock; ///< external clock base
+ double external_clock_drift; ///< external clock base - time (av_gettime) at which we updated external_clock
+ int64_t external_clock_time; ///< last reference time
+ double external_clock_speed; ///< speed of the external clock
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;
@@ -155,20 +184,29 @@ typedef struct VideoState {
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;
- 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;
+ 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;
+ double audio_current_pts;
+ double audio_current_pts_drift;
+ int frame_drops_early;
+ int frame_drops_late;
AVFrame *frame;
- int show_audio; /* if true, display audio samples */
+ 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;
@@ -176,6 +214,7 @@ typedef struct VideoState {
int rdft_bits;
FFTSample *rdft_data;
int xpos;
+ double last_vis_time;
SDL_Thread *subtitle_tid;
int subtitle_stream;
@@ -189,14 +228,20 @@ typedef struct VideoState {
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
+ 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;
- double video_current_pts; // current displayed pts (different from video_clock if frame fifos are used)
+ double video_current_pts; // current displayed pts
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
+ double max_frame_duration; // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity
+ int video_clock_serial;
VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
int pictq_size, pictq_rindex, pictq_windex;
SDL_mutex *pictq_mutex;
@@ -204,21 +249,23 @@ typedef struct VideoState {
#if !CONFIG_AVFILTER
struct SwsContext *img_convert_ctx;
#endif
+ SDL_Rect last_display_rect;
- // QETimer *video_timer;
char filename[1024];
int width, height, xleft, ytop;
-
- PtsCorrectionContext pts_ctx;
+ 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
- float skip_frames;
- float skip_frames_index;
- int refresh;
+ int last_video_stream, last_audio_stream, last_subtitle_stream;
+
+ SDL_cond *continue_read_thread;
} VideoState;
/* options specified by the user */
@@ -227,10 +274,13 @@ 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,
@@ -242,56 +292,122 @@ 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 lowres = 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;
+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 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 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;
+}
+
/* 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);
+ q->abort_request = 1;
}
static void packet_queue_flush(PacketQueue *q)
{
- AVPacketList *pkt, *pkt1;
+ MyAVPacketList *pkt, *pkt1;
SDL_LockMutex(q->mutex);
for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
@@ -306,60 +422,36 @@ static void packet_queue_flush(PacketQueue *q)
SDL_UnlockMutex(q->mutex);
}
-static void packet_queue_end(PacketQueue *q)
+static void packet_queue_destroy(PacketQueue *q)
{
packet_queue_flush(q);
SDL_DestroyMutex(q->mutex);
SDL_DestroyCond(q->cond);
}
-static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
+static void packet_queue_abort(PacketQueue *q)
{
- 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->abort_request = 1;
- 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)
+static void packet_queue_start(PacketQueue *q)
{
SDL_LockMutex(q->mutex);
-
- q->abort_request = 1;
-
- SDL_CondSignal(q->cond);
-
+ 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)
+static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)
{
- AVPacketList *pkt1;
+ MyAVPacketList *pkt1;
int ret;
SDL_LockMutex(q->mutex);
@@ -378,6 +470,8 @@ static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
q->nb_packets--;
q->size -= pkt1->pkt.size + sizeof(*pkt1);
*pkt = pkt1->pkt;
+ if (serial)
+ *serial = pkt1->serial;
av_free(pkt1);
ret = 1;
break;
@@ -393,7 +487,7 @@ static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
}
static inline void fill_rectangle(SDL_Surface *screen,
- int x, int y, int w, int h, int color)
+ int x, int y, int w, int h, int color, int update)
{
SDL_Rect rect;
rect.x = x;
@@ -401,6 +495,44 @@ static inline void fill_rectangle(SDL_Surface *screen,
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)\
@@ -637,45 +769,50 @@ 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;
- 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)
- {
+ 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))
- {
+ if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {
SDL_LockYUVOverlay (vp->bmp);
pict.data[0] = vp->bmp->pixels[0];
@@ -695,46 +832,28 @@ static void video_image_display(VideoState *is)
}
}
+ calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp);
- /* 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;
+ 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)
{
- a = a % b;
- if (a >= 0)
- return a;
- else
- return a + 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;
- int16_t time_diff;
+ int64_t time_diff;
int rdft_bits, nb_freq;
for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++)
@@ -742,19 +861,19 @@ static void video_audio_display(VideoState *s)
nb_freq = 1 << (rdft_bits - 1);
/* compute display index : center on currently output samples */
- channels = s->sdl_channels;
+ channels = s->audio_tgt.channels;
nb_display_channels = channels;
if (!s->paused) {
- int data_used = s->show_audio == 1 ? s->width : (2 * nb_freq);
+ int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);
n = 2 * channels;
- delay = audio_write_get_buf_size(s);
+ 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->sdl_sample_rate) / 1000000;
+ delay -= (time_diff * s->audio_tgt.freq) / 1000000;
}
delay += 2 * data_used;
@@ -762,7 +881,7 @@ static void video_audio_display(VideoState *s)
delay = data_used;
i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
- if (s->show_audio == 1) {
+ 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;
@@ -784,10 +903,10 @@ static void video_audio_display(VideoState *s)
}
bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
- if (s->show_audio == 1) {
+ if (s->show_mode == SHOW_MODE_WAVES) {
fill_rectangle(screen,
s->xleft, s->ytop, s->width, s->height,
- bgcolor);
+ bgcolor, 0);
fgcolor = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);
@@ -808,7 +927,7 @@ static void video_audio_display(VideoState *s)
}
fill_rectangle(screen,
s->xleft + x, ys, 1, y,
- fgcolor);
+ fgcolor, 0);
i += channels;
if (i >= SAMPLE_ARRAY_SIZE)
i -= SAMPLE_ARRAY_SIZE;
@@ -821,7 +940,7 @@ static void video_audio_display(VideoState *s)
y = s->ytop + ch * h;
fill_rectangle(screen,
s->xleft, y, s->width, 1,
- fgcolor);
+ fgcolor, 0);
}
SDL_UpdateRect(screen, s->xleft, s->ytop, s->width, s->height);
} else {
@@ -859,56 +978,102 @@ static void video_audio_display(VideoState *s)
fill_rectangle(screen,
s->xpos, s->height-y, 1, 1,
- fgcolor);
+ fgcolor, 0);
}
}
SDL_UpdateRect(screen, s->xpos, s->ytop, 1, s->height);
- s->xpos++;
+ if (!s->paused)
+ s->xpos++;
if (s->xpos >= s->width)
s->xpos= s->xleft;
}
}
-static int video_open(VideoState *is)
+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->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++) {
+ 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);
+ 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;
-#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;
+ w = default_width;
+ h = default_height;
}
if (screen && is->width == screen->w && screen->w == w
- && is->height== screen->h && screen->h == h)
+ && is->height== screen->h && screen->h == h && !force_set_video_mode)
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;
+ do_exit(is);
}
if (!window_title)
window_title = input_filename;
@@ -924,49 +1089,30 @@ static int video_open(VideoState *is)
static void video_display(VideoState *is)
{
if (!screen)
- video_open(cur_stream);
- if (is->audio_st && is->show_audio)
+ 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 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 (is->audio_clock_serial != is->audioq.serial)
+ return NAN;
+ if (is->paused) {
+ return is->audio_current_pts;
+ } else {
+ return is->audio_current_pts_drift + av_gettime() / 1000000.0;
}
- 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->video_clock_serial != is->videoq.serial)
+ return NAN;
if (is->paused) {
return is->video_current_pts;
} else {
@@ -977,32 +1123,82 @@ static double get_video_clock(VideoState *is)
/* 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);
+ if (is->paused) {
+ return is->external_clock;
+ } else {
+ double time = av_gettime() / 1000000.0;
+ return is->external_clock_drift + time - (time - is->external_clock_time / 1000000.0) * (1.0 - is->external_clock_speed);
+ }
}
-/* get the current master clock value */
-static double get_master_clock(VideoState *is)
-{
- double val;
-
+static int get_master_sync_type(VideoState *is) {
if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {
if (is->video_st)
- val = get_video_clock(is);
+ return AV_SYNC_VIDEO_MASTER;
else
- val = get_audio_clock(is);
+ return AV_SYNC_AUDIO_MASTER;
} else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {
if (is->audio_st)
- val = get_audio_clock(is);
+ return AV_SYNC_AUDIO_MASTER;
else
- val = get_video_clock(is);
+ return AV_SYNC_EXTERNAL_CLOCK;
} else {
- val = get_external_clock(is);
+ 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_video_clock(is);
+ break;
+ case AV_SYNC_AUDIO_MASTER:
+ val = get_audio_clock(is);
+ break;
+ default:
+ val = get_external_clock(is);
+ break;
}
return val;
}
+static void update_external_clock_pts(VideoState *is, double pts)
+{
+ is->external_clock_time = av_gettime();
+ is->external_clock = pts;
+ is->external_clock_drift = pts - is->external_clock_time / 1000000.0;
+}
+
+static void check_external_clock_sync(VideoState *is, double pts) {
+ double ext_clock = get_external_clock(is);
+ if (isnan(ext_clock) || fabs(ext_clock - pts) > AV_NOSYNC_THRESHOLD) {
+ update_external_clock_pts(is, pts);
+ }
+}
+
+static void update_external_clock_speed(VideoState *is, double speed) {
+ update_external_clock_pts(is, get_external_clock(is));
+ is->external_clock_speed = speed;
+}
+
+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) {
+ update_external_clock_speed(is, FFMAX(EXTERNAL_CLOCK_SPEED_MIN, is->external_clock_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)) {
+ update_external_clock_speed(is, FFMIN(EXTERNAL_CLOCK_SPEED_MAX, is->external_clock_speed + EXTERNAL_CLOCK_SPEED_STEP));
+ } else {
+ double speed = is->external_clock_speed;
+ if (speed != 1.0)
+ update_external_clock_speed(is, 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)
{
@@ -1013,11 +1209,12 @@ static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_by
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_pause(VideoState *is)
+static void stream_toggle_pause(VideoState *is)
{
if (is->paused) {
is->frame_timer += av_gettime() / 1000000.0 + is->video_current_pts_drift - is->video_current_pts;
@@ -1026,26 +1223,30 @@ static void stream_pause(VideoState *is)
}
is->video_current_pts_drift = is->video_current_pts - av_gettime() / 1000000.0;
}
+ update_external_clock_pts(is, get_external_clock(is));
is->paused = !is->paused;
}
-static double compute_target_time(double frame_current_pts, VideoState *is)
+static void toggle_pause(VideoState *is)
{
- double delay, sync_threshold, diff;
+ stream_toggle_pause(is);
+ is->step = 0;
+}
- /* compute nominal delay */
- delay = frame_current_pts - is->frame_last_pts;
- if (delay <= 0 || delay >= 10.0) {
- /* if incorrect delay, use previous one */
- delay = is->frame_last_delay;
- } else {
- is->frame_last_delay = delay;
- }
- is->frame_last_pts = frame_current_pts;
+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 (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) ||
- is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
+ 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_video_clock(is) - get_master_clock(is);
@@ -1054,63 +1255,140 @@ static double compute_target_time(double frame_current_pts, VideoState *is)
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 (!isnan(diff) && 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);
+ 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 - 1) {
+ 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;
+}
- return is->frame_timer;
+static void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) {
+ double time = av_gettime() / 1000000.0;
+ /* update current video pts */
+ is->video_current_pts = pts;
+ is->video_current_pts_drift = is->video_current_pts - time;
+ is->video_current_pos = pos;
+ is->frame_last_pts = pts;
+ is->video_clock_serial = serial;
+ if (is->videoq.serial == serial)
+ check_external_clock_sync(is, is->video_current_pts);
}
/* called to display each frame */
-static void video_refresh_timer(void *opaque)
+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) {
- // nothing to do, no picture to display in the que
+ 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 time = av_gettime() / 1000000.0;
- double next_target;
+ double last_duration, duration, delay;
/* dequeue the picture */
vp = &is->pictq[is->pictq_rindex];
- if (time < vp->target_clock)
+ 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;
+ }
+ delay = compute_target_delay(is->frame_last_duration, is);
+
+ time= av_gettime()/1000000.0;
+ if (time < is->frame_timer + delay) {
+ *remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);
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 (delay > 0)
+ is->frame_timer += delay * FFMAX(1, floor((time-is->frame_timer) / delay));
+
+ SDL_LockMutex(is->pictq_mutex);
+ if (!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];
- 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);
+ 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;
}
}
@@ -1159,29 +1437,18 @@ retry:
}
}
+display:
/* display picture */
- if (!display_disable)
+ if (!display_disable && is->show_mode == SHOW_MODE_VIDEO)
video_display(is);
- /* update queue size and signal for next picture */
- if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
- is->pictq_rindex = 0;
+ pictq_next_picture(is);
- SDL_LockMutex(is->pictq_mutex);
- is->pictq_size--;
- SDL_CondSignal(is->pictq_cond);
- SDL_UnlockMutex(is->pictq_mutex);
+ if (is->step && !is->paused)
+ stream_toggle_pause(is);
}
- } 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);
}
+ is->force_refresh = 0;
if (show_status) {
static int64_t last_time;
int64_t cur_time;
@@ -1202,63 +1469,25 @@ retry:
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);
+ printf("%7.2f A-V:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64" \r",
+ get_master_clock(is),
+ 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;
}
}
}
-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)
+static void alloc_picture(VideoState *is)
{
- VideoState *is = opaque;
VideoPicture *vp;
vp = &is->pictq[is->pictq_windex];
@@ -1266,15 +1495,7 @@ static void alloc_picture(void *opaque)
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
+ video_open(is, 0, vp);
vp->bmp = SDL_CreateYUVOverlay(vp->width, vp->height,
SDL_YV12_OVERLAY,
@@ -1283,9 +1504,9 @@ static void alloc_picture(void *opaque)
/* 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"
+ "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();
+ do_exit(is);
}
SDL_LockMutex(is->pictq_mutex);
@@ -1294,23 +1515,38 @@ static void alloc_picture(void *opaque)
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)
+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 CONFIG_AVFILTER
- AVPicture pict_src;
-#else
- int dst_pix_fmt = AV_PIX_FMT_YUV420P;
+
+#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);
- 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 &&
+ /* keep the last already displayed picture in the queue */
+ while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE - 2 &&
!is->videoq.abort_request) {
SDL_CondWait(is->pictq_cond, is->pictq_mutex);
}
@@ -1321,22 +1557,21 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t
vp = &is->pictq[is->pictq_windex];
+ vp->sar = src_frame->sample_aspect_ratio;
+
/* alloc or resize hardware picture buffer */
- if (!vp->bmp || vp->reallocate ||
-#if CONFIG_AVFILTER
- vp->width != is->out_video_filter->inputs[0]->w ||
- vp->height != is->out_video_filter->inputs[0]->h) {
-#else
- vp->width != is->video_st->codec->width ||
- vp->height != is->video_st->codec->height) {
-#endif
+ 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 */
+ locking problems. */
event.type = FF_ALLOC_EVENT;
event.user.data1 = is;
SDL_PushEvent(&event);
@@ -1346,6 +1581,12 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t
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)
@@ -1368,22 +1609,14 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t
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);
+ 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, vp->pix_fmt, vp->width, vp->height,
- dst_pix_fmt, sws_flags, NULL, NULL, NULL);
+ 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) {
fprintf(stderr, "Cannot initialize the conversion context\n");
exit(1);
@@ -1391,175 +1624,256 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t
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);
- 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)
+static int get_video_frame(VideoState *is, AVFrame *frame, AVPacket *pkt, int *serial)
{
- int got_picture, i;
+ int got_picture;
- if (packet_queue_get(&is->videoq, pkt, 1) < 0)
+ 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 que but thats harder)
- for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
- is->pictq[i].target_clock= 0;
- }
+ // 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;
- 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_last_duration = 0;
is->frame_timer = (double)av_gettime() / 1000000.0;
- is->skip_frames = 1;
- is->skip_frames_index = 0;
+ is->frame_last_dropped_pts = AV_NOPTS_VALUE;
+ SDL_UnlockMutex(is->pictq_mutex);
return 0;
}
- avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt);
+ if(avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt) < 0)
+ return 0;
if (got_picture) {
+ int ret = 1;
+ double dpts = NAN;
+
if (decoder_reorder_pts == -1) {
- *pts = guess_correct_pts(&is->pts_ctx, frame->pkt_pts, frame->pkt_dts);
+ frame->pts = av_frame_get_best_effort_timestamp(frame);
} else if (decoder_reorder_pts) {
- *pts = frame->pkt_pts;
+ frame->pts = frame->pkt_pts;
} else {
- *pts = frame->pkt_dts;
+ frame->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;
- }
+ 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);
- 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;
+ 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_video_clock(is) - 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 = pkt->pos;
+ 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);
}
- av_frame_unref(frame);
+
+ return ret;
}
return 0;
}
#if CONFIG_AVFILTER
-static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters)
+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(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_format;
+ 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), "%d:%d:%d:%d:%d:%d:%d",
- codec->width, codec->height, codec->pix_fmt,
+ 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, codec->sample_aspect_ratio.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"),
- "src", buffersrc_args, NULL,
+ "ffplay_buffer", 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();
+ goto fail;
- outputs->name = av_strdup("in");
- outputs->filter_ctx = filt_src;
- outputs->pad_idx = 0;
- outputs->next = NULL;
+ ret = avfilter_graph_create_filter(&filt_out,
+ avfilter_get_by_name("buffersink"),
+ "ffplay_buffersink", NULL, NULL, graph);
+ if (ret < 0)
+ goto fail;
- inputs->name = av_strdup("out");
- inputs->filter_ctx = filt_format;
- inputs->pad_idx = 0;
- inputs->next = NULL;
+ if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)
+ goto fail;
- 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;
- }
+ /* 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 = avfilter_graph_config(graph, NULL)) < 0)
- return ret;
+ 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 asrc_args[256];
+ int ret;
+
+ avfilter_graph_free(&is->agraph);
+ if (!(is->agraph = avfilter_graph_alloc()))
+ return AVERROR(ENOMEM);
+
+ 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)
@@ -1567,94 +1881,97 @@ 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;
+ int serial = 0;
#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;
+ int last_w = 0;
+ int last_h = 0;
+ enum AVPixelFormat last_format = -2;
+ int last_serial = -1;
#endif
for (;;) {
-#if CONFIG_AVFILTER
- AVRational tb;
-#endif
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, &pts_int, &pkt);
+ ret = get_video_frame(is, frame, &pkt, &serial);
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);
+ 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)) < 0)
+ 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 = is->video_st->codec->width;
- last_h = is->video_st->codec->height;
+ last_w = frame->width;
+ last_h = frame->height;
+ last_format = frame->format;
+ last_serial = serial;
}
- frame->pts = pts_int;
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) {
- ret = av_buffersink_get_frame(filt_out, frame);
+ is->frame_last_returned_time = av_gettime() / 1000000.0;
+
+ ret = av_buffersink_get_frame_flags(filt_out, frame, 0);
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);
+ 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 = pts_int * av_q2d(is->video_st->time_base);
- ret = output_picture2(is, frame, pts, pkt.pos);
+ pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(is->video_st->time_base);
+ ret = queue_picture(is, frame, pts, pkt.pos, serial);
+ av_frame_unref(frame);
#endif
if (ret < 0)
goto the_end;
-
-
- if (step)
- if (cur_stream)
- stream_pause(cur_stream);
}
the_end:
+ avcodec_flush_buffers(is->video_st->codec);
#if CONFIG_AVFILTER
- av_freep(&vfilters);
avfilter_graph_free(&graph);
#endif
av_free_packet(&pkt);
@@ -1676,7 +1993,7 @@ static int subtitle_thread(void *arg)
while (is->paused && !is->subtitleq.abort_request) {
SDL_Delay(10);
}
- if (packet_queue_get(&is->subtitleq, pkt, 1) < 0)
+ if (packet_queue_get(&is->subtitleq, pkt, 1, NULL) < 0)
break;
if (pkt->data == flush_pkt.data) {
@@ -1703,8 +2020,9 @@ static int subtitle_thread(void *arg)
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;
for (i = 0; i < sp->sub.num_rects; i++)
@@ -1750,27 +2068,20 @@ static void update_sample_display(VideoState *is, short *samples, int samples_si
}
}
-/* 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)
+/* 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 n, samples_size;
- double ref_clock;
-
- n = is->sdl_channels * av_get_bytes_per_sample(is->sdl_sample_fmt);
- samples_size = samples_size1;
+ int wanted_nb_samples = nb_samples;
/* 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)) {
+ if (get_master_sync_type(is) != AV_SYNC_AUDIO_MASTER) {
double diff, avg_diff;
- int wanted_size, min_size, max_size, nb_samples;
+ int min_nb_samples, max_nb_samples;
- ref_clock = get_master_clock(is);
- diff = get_audio_clock(is) - ref_clock;
+ diff = get_audio_clock(is) - get_master_clock(is);
- if (diff < AV_NOSYNC_THRESHOLD) {
+ 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 */
@@ -1780,39 +2091,14 @@ static int synchronize_audio(VideoState *is, short *samples,
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;
- }
+ 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 vpts=%0.3f %f\n",
- diff, avg_diff, samples_size - samples_size1,
- is->audio_clock, is->video_clock, is->audio_diff_threshold);
+ 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
@@ -1822,138 +2108,206 @@ static int synchronize_audio(VideoState *is, short *samples,
}
}
- return samples_size;
+ return wanted_nb_samples;
}
-/* decode one audio frame and returns its uncompressed size */
-static int audio_decode_frame(VideoState *is, double *pts_ptr)
+/**
+ * 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 n, len1, data_size, got_frame;
- double pts;
+ int len1, data_size, resampled_data_size;
+ int64_t dec_channel_layout;
+ int got_frame;
+ av_unused double audio_clock0;
int new_packet = 0;
int flush_complete = 0;
+ int wanted_nb_samples;
+ AVRational tb;
+ int ret;
+ int reconfigure;
for (;;) {
/* NOTE: the audio packet can contain several frames */
- while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet)) {
- int resample_changed, audio_resample;
-
+ while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet) || is->audio_buf_frames_pending) {
if (!is->frame) {
if (!(is->frame = avcodec_alloc_frame()))
return AVERROR(ENOMEM);
- } else
+ } else {
+ av_frame_unref(is->frame);
avcodec_get_frame_defaults(is->frame);
+ }
- if (flush_complete)
+ if (is->audioq.serial != is->audio_pkt_temp_serial)
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 (is->paused)
+ return -1;
+
+ if (!is->audio_buf_frames_pending) {
+ 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;
+ }
+
+ 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);
+ if (is->frame->pts == AV_NOPTS_VALUE && pkt_temp->pts != AV_NOPTS_VALUE)
+ is->frame->pts = av_rescale_q(pkt_temp->pts, is->audio_st->time_base, tb);
+ if (pkt_temp->pts != AV_NOPTS_VALUE)
+ pkt_temp->pts += (double) is->frame->nb_samples / is->frame->sample_rate / av_q2d(is->audio_st->time_base);
+
+#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 (!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;
+ if ((ret = av_buffersrc_add_frame(is->in_audio_filter, is->frame)) < 0)
+ return ret;
+ av_frame_unref(is->frame);
+#endif
}
- data_size = av_samples_get_buffer_size(NULL, dec->channels,
+#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;
+ }
+ 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);
- 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;
- }
+ 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) {
+ fprintf(stderr, "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;
}
- 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");
+ 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) {
+ fprintf(stderr, "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) {
+ fprintf(stderr, "swr_set_compensation() failed\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)
+ av_fast_malloc(&is->audio_buf1, &is->audio_buf1_size, out_size);
+ if (!is->audio_buf1)
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");
+ len2 = swr_convert(is->swr_ctx, out, out_count, in, is->frame->nb_samples);
+ if (len2 < 0) {
+ fprintf(stderr, "swr_convert() failed\n");
break;
}
+ if (len2 == out_count) {
+ fprintf(stderr, "warning: audio buffer is probably too small\n");
+ swr_init(is->swr_ctx);
+ }
is->audio_buf = is->audio_buf1;
- data_size = out_samples * osize * is->sdl_channels;
+ 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;
}
- /* 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);
+ 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;
+ is->audio_clock_serial = is->audio_pkt_temp_serial;
+ }
#ifdef DEBUG
{
static double last_clock;
- printf("audio: delay=%0.3f clock=%0.3f pts=%0.3f\n",
+ printf("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
is->audio_clock - last_clock,
- is->audio_clock, pts);
+ is->audio_clock, audio_clock0);
last_clock = is->audio_clock;
}
#endif
- return data_size;
+ return resampled_data_size;
}
/* free the current packet */
@@ -1961,25 +2315,24 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
av_free_packet(pkt);
memset(pkt_temp, 0, sizeof(*pkt_temp));
- if (is->paused || is->audioq.abort_request) {
+ if (is->audioq.abort_request) {
return -1;
}
+ if (is->audioq.nb_packets == 0)
+ SDL_CondSignal(is->continue_read_thread);
+
/* read next packet */
- if ((new_packet = packet_queue_get(&is->audioq, pkt, 1)) < 0)
+ if ((new_packet = 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);
flush_complete = 0;
+ is->audio_buf_frames_pending = 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;
- }
}
}
@@ -1988,22 +2341,21 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
{
VideoState *is = opaque;
int audio_size, len1;
- double pts;
+ 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, &pts);
+ audio_size = audio_decode_frame(is);
if (audio_size < 0) {
/* if error, just output silence */
is->audio_buf = is->silence_buf;
- is->audio_buf_size = sizeof(is->silence_buf);
+ is->audio_buf_size = sizeof(is->silence_buf) / frame_size * frame_size;
} else {
- if (is->show_audio)
+ if (is->show_mode != SHOW_MODE_VIDEO)
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;
@@ -2016,6 +2368,67 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
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. */
+ is->audio_current_pts = is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / bytes_per_sec;
+ is->audio_current_pts_drift = is->audio_current_pts - audio_callback_time / 1000000.0;
+ if (is->audioq.serial == is->audio_clock_serial)
+ check_external_clock_sync(is, is->audio_current_pts);
+}
+
+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;
+ 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) {
+ fprintf(stderr, "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) {
+ fprintf(stderr, "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) {
+ fprintf(stderr, "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) {
+ fprintf(stderr, "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) {
+ fprintf(stderr, "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 */
@@ -2024,78 +2437,89 @@ static int stream_component_open(VideoState *is, int stream_index)
AVFormatContext *ic = is->ic;
AVCodecContext *avctx;
AVCodec *codec;
- SDL_AudioSpec wanted_spec, spec;
+ const char *forced_codec_name = NULL;
AVDictionary *opts;
AVDictionaryEntry *t = NULL;
+ int sample_rate, nb_channels;
+ int64_t channel_layout;
+ int ret;
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;
+
+ 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) fprintf(stderr, "No codec could be found with name '%s'\n", forced_codec_name);
+ else fprintf(stderr, "No codec could be found with id %d\n", avctx->codec_id);
+ return -1;
+ }
+
+ avctx->codec_id = codec->id;
avctx->workaround_bugs = workaround_bugs;
+ avctx->lowres = lowres;
+ if(avctx->lowres > codec->max_lowres){
+ av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
+ codec->max_lowres);
+ avctx->lowres= codec->max_lowres;
+ }
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(avctx->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 (avctx->codec_type == AVMEDIA_TYPE_VIDEO)
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO)
av_dict_set(&opts, "refcounted_frames", "1", 0);
- if (!codec ||
- avcodec_open2(avctx, codec, &opts) < 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;
}
- /* 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];
+#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;
@@ -2104,23 +2528,29 @@ static int stream_component_open(VideoState *is, int stream_index)
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;
+ 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));
- packet_queue_init(&is->audioq);
+ memset(&is->audio_pkt_temp, 0, sizeof(is->audio_pkt_temp));
+
+ 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_init(&is->videoq);
+ 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_init(&is->subtitleq);
+ packet_queue_start(&is->subtitleq);
is->subtitle_tid = SDL_CreateThread(subtitle_thread, is);
break;
@@ -2145,13 +2575,13 @@ static void stream_component_close(VideoState *is, int stream_index)
SDL_CloseAudio();
- packet_queue_end(&is->audioq);
+ packet_queue_flush(&is->audioq);
av_free_packet(&is->audio_pkt);
- if (is->avr)
- avresample_free(&is->avr);
+ swr_free(&is->swr_ctx);
av_freep(&is->audio_buf1);
+ is->audio_buf1_size = 0;
is->audio_buf = NULL;
- avcodec_free_frame(&is->frame);
+ av_frame_free(&is->frame);
if (is->rdft) {
av_rdft_end(is->rdft);
@@ -2159,6 +2589,9 @@ static void stream_component_close(VideoState *is, int stream_index)
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);
@@ -2171,7 +2604,7 @@ static void stream_component_close(VideoState *is, int stream_index)
SDL_WaitThread(is->video_tid, NULL);
- packet_queue_end(&is->videoq);
+ packet_queue_flush(&is->videoq);
break;
case AVMEDIA_TYPE_SUBTITLE:
packet_queue_abort(&is->subtitleq);
@@ -2186,7 +2619,7 @@ static void stream_component_close(VideoState *is, int stream_index)
SDL_WaitThread(is->subtitle_tid, NULL);
- packet_queue_end(&is->subtitleq);
+ packet_queue_flush(&is->subtitleq);
break;
default:
break;
@@ -2212,17 +2645,30 @@ static void stream_component_close(VideoState *is, int stream_index)
}
}
-/* 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;
+ 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 decode_thread(void *arg)
+static int read_thread(void *arg)
{
VideoState *is = arg;
AVFormatContext *ic = NULL;
@@ -2234,16 +2680,16 @@ static int decode_thread(void *arg)
AVDictionaryEntry *t;
AVDictionary **opts;
int orig_nb_streams;
+ SDL_mutex *wait_mutex = SDL_CreateMutex();
memset(st_index, -1, sizeof(st_index));
- is->video_stream = -1;
- is->audio_stream = -1;
- is->subtitle_stream = -1;
-
- global_video_state = is;
+ 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);
@@ -2274,10 +2720,15 @@ static int decode_thread(void *arg)
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
+ 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);
+ 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) {
@@ -2294,6 +2745,8 @@ static int decode_thread(void *arg)
}
}
+ is->realtime = is_realtime(ic);
+
for (i = 0; i < ic->nb_streams; i++)
ic->streams[i]->discard = AVDISCARD_ALL;
if (!video_disable)
@@ -2306,7 +2759,7 @@ static int decode_thread(void *arg)
wanted_stream[AVMEDIA_TYPE_AUDIO],
st_index[AVMEDIA_TYPE_VIDEO],
NULL, 0);
- if (!video_disable)
+ if (!video_disable && !subtitle_disable)
st_index[AVMEDIA_TYPE_SUBTITLE] =
av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,
wanted_stream[AVMEDIA_TYPE_SUBTITLE],
@@ -2318,6 +2771,8 @@ static int decode_thread(void *arg)
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]);
@@ -2327,11 +2782,8 @@ static int decode_thread(void *arg)
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 (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]);
@@ -2343,6 +2795,9 @@ static int decode_thread(void *arg)
goto fail;
}
+ if (infinite_buffer < 0 && is->realtime)
+ infinite_buffer = 1;
+
for (;;) {
if (is->abort_request)
break;
@@ -2353,8 +2808,10 @@ static int decode_thread(void *arg)
else
av_read_play(ic);
}
-#if CONFIG_RTSP_DEMUXER
- if (is->paused && !strcmp(ic->iformat->name, "rtsp")) {
+#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);
@@ -2384,19 +2841,39 @@ static int decode_thread(void *arg)
packet_queue_flush(&is->videoq);
packet_queue_put(&is->videoq, &flush_pkt);
}
+ if (is->seek_flags & AVSEEK_FLAG_BYTE) {
+ update_external_clock_pts(is, NAN);
+ } else {
+ update_external_clock_pts(is, seek_target / (double)AV_TIME_BASE);
+ }
}
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);
+ }
+ is->queue_attachments_req = 0;
}
/* if the queue are full, no need to read more */
- if (!infinite_buffer &&
+ if (infinite_buffer<1 &&
(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)))) {
+ || ( (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_Delay(10);
+ SDL_LockMutex(wait_mutex);
+ SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
+ SDL_UnlockMutex(wait_mutex);
continue;
}
if (eof) {
@@ -2418,21 +2895,24 @@ static int decode_thread(void *arg)
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);
+ stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
} else if (autoexit) {
ret = AVERROR_EOF;
goto fail;
}
}
+ eof=0;
continue;
}
ret = av_read_frame(ic, pkt);
if (ret < 0) {
- if (ret == AVERROR_EOF || (ic->pb && ic->pb->eof_reached))
+ if (ret == AVERROR_EOF || url_feof(ic->pb))
eof = 1;
if (ic->pb && ic->pb->error)
break;
- SDL_Delay(100); /* wait for user event */
+ 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 */
@@ -2443,7 +2923,8 @@ static int decode_thread(void *arg)
<= ((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) {
+ } 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);
@@ -2458,9 +2939,6 @@ static int decode_thread(void *arg)
ret = 0;
fail:
- /* disable interrupting */
- global_video_state = NULL;
-
/* close each stream */
if (is->audio_stream >= 0)
stream_component_close(is, is->audio_stream);
@@ -2479,6 +2957,7 @@ static int decode_thread(void *arg)
event.user.data1 = is;
SDL_PushEvent(&event);
}
+ SDL_DestroyMutex(wait_mutex);
return 0;
}
@@ -2501,9 +2980,22 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
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();
+
+ update_external_clock_pts(is, NAN);
+ update_external_clock_speed(is, 1.0);
+ is->audio_current_pts_drift = -av_gettime() / 1000000.0;
+ is->video_current_pts_drift = is->audio_current_pts_drift;
+ is->audio_clock_serial = -1;
+ is->video_clock_serial = -1;
+ is->audio_last_serial = -1;
is->av_sync_type = av_sync_type;
- is->parse_tid = SDL_CreateThread(decode_thread, is);
- if (!is->parse_tid) {
+ is->read_tid = SDL_CreateThread(read_thread, is);
+ if (!is->read_tid) {
av_free(is);
return NULL;
}
@@ -2514,16 +3006,19 @@ static void stream_cycle_channel(VideoState *is, int codec_type)
{
AVFormatContext *ic = is->ic;
int start_index, stream_index;
+ int old_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;
+ 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;
for (;;) {
if (++stream_index >= is->ic->nb_streams)
@@ -2531,9 +3026,12 @@ static void stream_cycle_channel(VideoState *is, int codec_type)
if (codec_type == AVMEDIA_TYPE_SUBTITLE)
{
stream_index = -1;
+ is->last_subtitle_stream = -1;
goto the_end;
- } else
- stream_index = 0;
+ }
+ if (start_index == -1)
+ return;
+ stream_index = 0;
}
if (stream_index == start_index)
return;
@@ -2555,97 +3053,105 @@ static void stream_cycle_channel(VideoState *is, int codec_type)
}
}
the_end:
- stream_component_close(is, start_index);
+ stream_component_close(is, old_index);
stream_component_open(is, stream_index);
}
-static void toggle_full_screen(void)
+static void toggle_full_screen(VideoState *is)
{
#if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
- /* OS X needs to empty the picture_queue */
+ /* OS X needs to reallocate the SDL overlays */
int i;
for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
- cur_stream->pictq[i].reallocate = 1;
+ is->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;
+ video_open(is, 1, NULL);
}
-static void step_to_next_frame(void)
+static void toggle_audio_display(VideoState *is)
{
- if (cur_stream) {
- /* if the stream is paused unpause it, then step */
- if (cur_stream->paused)
- stream_pause(cur_stream);
+ 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;
}
- step = 1;
}
-static void toggle_audio_display(void)
-{
- if (cur_stream) {
- int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
- cur_stream->show_audio = (cur_stream->show_audio + 1) % 3;
- fill_rectangle(screen,
- cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height,
- bgcolor);
- SDL_UpdateRect(screen, cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height);
+static void 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(void)
+static void event_loop(VideoState *cur_stream)
{
SDL_Event event;
double incr, pos, frac;
for (;;) {
double x;
- SDL_WaitEvent(&event);
+ refresh_loop_wait_event(cur_stream, &event);
switch (event.type) {
case SDL_KEYDOWN:
if (exit_on_keydown) {
- do_exit();
+ do_exit(cur_stream);
break;
}
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
case SDLK_q:
- do_exit();
+ do_exit(cur_stream);
break;
case SDLK_f:
- toggle_full_screen();
+ toggle_full_screen(cur_stream);
+ cur_stream->force_refresh = 1;
break;
case SDLK_p:
case SDLK_SPACE:
- toggle_pause();
+ toggle_pause(cur_stream);
break;
case SDLK_s: // S: Step to next frame
- step_to_next_frame();
+ step_to_next_frame(cur_stream);
break;
case SDLK_a:
- if (cur_stream)
- stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
+ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
break;
case SDLK_v:
- if (cur_stream)
- stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
+ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
break;
case SDLK_t:
- if (cur_stream)
- stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
+ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
break;
case SDLK_w:
- toggle_audio_display();
+ 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;
@@ -2658,7 +3164,6 @@ static void event_loop(void)
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;
@@ -2674,21 +3179,32 @@ static void event_loop(void)
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();
+ 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 {
@@ -2696,7 +3212,6 @@ static void event_loop(void)
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);
@@ -2720,28 +3235,21 @@ static void event_loop(void)
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;
- }
+ cur_stream->force_refresh = 1;
break;
case SDL_QUIT:
case FF_QUIT_EVENT:
- do_exit();
+ do_exit(cur_stream);
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;
}
@@ -2750,9 +3258,8 @@ static void event_loop(void)
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);
+ 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)
@@ -2779,9 +3286,8 @@ static int opt_format(void *optctx, const char *opt, const char *arg)
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);
+ 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)
@@ -2811,12 +3317,49 @@ static int opt_duration(void *optctx, const char *opt, const char *arg)
return 0;
}
-static int opt_vismv(void *optctx, const char *opt, const char *arg)
+static int opt_show_mode(void *optctx, const char *opt, const char *arg)
{
- debug_mv = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX);
+ 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) {
+ 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;
+}
+
+static int opt_codec(void *optctx, const char *opt, const char *arg)
+{
+ const char *spec = strchr(opt, ':');
+ if (!spec) {
+ fprintf(stderr, "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:
+ fprintf(stderr, "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" },
@@ -2825,6 +3368,7 @@ static const OptionDef options[] = {
{ "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" },
@@ -2836,13 +3380,10 @@ static const OptionDef options[] = {
{ "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 }, "", "" },
+ { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, { &lowres }, "", "" },
{ "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" },
@@ -2854,19 +3395,25 @@ static const OptionDef options[] = {
{ "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" },
+ { "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" },
- { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { opt_default }, "generic catch all option", "" },
- { "i", 0, { NULL }, "avconv compatibility dummy option", ""},
+ { "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)
{
- printf("Simple media player\n");
- printf("usage: %s [options] input_file\n", program_name);
- printf("\n");
+ 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)
@@ -2880,6 +3427,8 @@ void show_help_default(const char *opt, const char *arg)
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"
@@ -2892,26 +3441,36 @@ void show_help_default(const char *opt, const char *arg)
"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 void opt_input_file(void *optctx, const char *filename)
+static int lockmgr(void **mtx, enum AVLockOp op)
{
- 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;
+ 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);
@@ -2929,7 +3488,10 @@ int main(int argc, char **argv)
init_opts();
- show_banner();
+ 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);
@@ -2944,11 +3506,16 @@ int main(int argc, char **argv)
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)) {
fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
+ fprintf(stderr, "(Did you set the DISPLAY variable?)\n");
exit(1);
}
@@ -2962,12 +3529,21 @@ int main(int argc, char **argv)
SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
+ if (av_lockmgr_register(lockmgr)) {
+ fprintf(stderr, "Could not initialize lock manager!\n");
+ do_exit(NULL);
+ }
+
av_init_packet(&flush_pkt);
flush_pkt.data = (uint8_t *)&flush_pkt;
- cur_stream = stream_open(input_filename, file_iformat);
+ is = stream_open(input_filename, file_iformat);
+ if (!is) {
+ fprintf(stderr, "Failed to initialize VideoState!\n");
+ do_exit(NULL);
+ }
- event_loop();
+ event_loop(is);
/* never returns */
diff --git a/ffprobe.c b/ffprobe.c
new file mode 100644
index 0000000..4d2d3e1
--- /dev/null
+++ b/ffprobe.c
@@ -0,0 +1,2327 @@
+/*
+ * 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/timecode.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_error = 0;
+static int do_show_format = 0;
+static int do_show_frames = 0;
+static int do_show_packets = 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;
+
+/* 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_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_VERSION,
+ SECTION_ID_ROOT,
+ SECTION_ID_STREAM,
+ SECTION_ID_STREAM_DISPOSITION,
+ SECTION_ID_STREAMS,
+ SECTION_ID_STREAM_TAGS,
+} SectionID;
+
+static struct section sections[] = {
+ [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_VERSION] = { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
+ [SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER,
+ { SECTION_ID_FORMAT, SECTION_ID_FRAMES, 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 exit_program(void)
+{
+ 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];
+} 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;
+
+ av_bprint_clear(&wctx->section_pbuf[wctx->level]);
+ if (parent_section &&
+ !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
+ compact->nested_section[wctx->level] = 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 (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] &&
+ !(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 read_packets(WriterContext *w, AVFormatContext *fmt_ctx)
+{
+ AVPacket pkt, pkt1;
+ AVFrame frame;
+ int i = 0;
+
+ av_init_packet(&pkt);
+
+ while (!av_read_frame(fmt_ctx, &pkt)) {
+ if (selected_streams[pkt.stream_index]) {
+ 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);
+ }
+}
+
+static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx)
+{
+ 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, 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);
+ print_int("bits_per_sample", av_get_bits_per_sample(dec_ctx->codec_id));
+ 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, 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, 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);
+ 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_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");
+ 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_ERROR,
+ "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_ERROR,
+ "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_ERROR, "Error while opening 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) {
+ 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;
+ } 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_streams)
+ show_streams(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(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);
+}
+
+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(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);
+
+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_streams", 0, {(void*)&opt_show_streams}, "show streams 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" },
+ { "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);
+ atexit(exit_program);
+
+ 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(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(STREAMS, streams);
+ SET_DO_SHOW(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_streams || 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);
+
+ uninit_opts();
+ for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
+ av_dict_free(&(sections[i].entries_to_show));
+
+ avformat_network_deinit();
+
+ return ret;
+}
diff --git a/avserver.c b/ffserver.c
index 16a24ff..ac9627f 100644
--- a/avserver.c
+++ b/ffserver.c
@@ -1,24 +1,28 @@
/*
- * Multiple format streaming server
* 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
*/
+/**
+ * @file
+ * multiple format streaming server based on the FFmpeg libraries
+ */
+
#include "config.h"
#if !HAVE_CLOSESOCKET
#define closesocket close
@@ -27,7 +31,7 @@
#include <stdlib.h>
#include <stdio.h>
#include "libavformat/avformat.h"
-// FIXME those are internal headers, avserver _really_ shouldn't use them
+// FIXME those are internal headers, ffserver _really_ shouldn't use them
#include "libavformat/ffm.h"
#include "libavformat/network.h"
#include "libavformat/os_support.h"
@@ -37,6 +41,7 @@
#include "libavformat/internal.h"
#include "libavformat/url.h"
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/lfg.h"
#include "libavutil/dict.h"
@@ -64,7 +69,7 @@
#include "cmdutils.h"
-const char program_name[] = "avserver";
+const char program_name[] = "ffserver";
const int program_birth_year = 2000;
static const OptionDef options[];
@@ -205,7 +210,7 @@ typedef struct IPAddressACL {
struct in_addr last;
} IPAddressACL;
-/* description of each stream of the avserver.conf file */
+/* description of each stream of the ffserver.conf file */
typedef struct FFStream {
enum StreamType stream_type;
char filename[1024]; /* stream filename */
@@ -228,8 +233,8 @@ typedef struct FFStream {
char title[512];
char copyright[512];
char comment[512];
- pid_t pid; /* of avconv process */
- time_t pid_start; /* of avconv process */
+ 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 */
@@ -303,9 +308,9 @@ static int rtp_new_av_stream(HTTPContext *c,
static const char *my_program_name;
-static const char *config_filename = "/etc/avserver.conf";
+static const char *config_filename;
-static int avserver_debug;
+static int ffserver_debug;
static int no_launch;
static int need_to_start_children;
@@ -327,7 +332,8 @@ static int64_t ffm_read_write_index(int fd)
{
uint8_t buf[8];
- lseek(fd, 8, SEEK_SET);
+ if (lseek(fd, 8, SEEK_SET) < 0)
+ return AVERROR(EIO);
if (read(fd, buf, 8) != 8)
return AVERROR(EIO);
return AV_RB64(buf);
@@ -340,7 +346,8 @@ static int ffm_write_write_index(int fd, int64_t pos)
for(i=0;i<8;i++)
buf[i] = (pos >> (56 - i * 8)) & 0xff;
- lseek(fd, 8, SEEK_SET);
+ if (lseek(fd, 8, SEEK_SET) < 0)
+ return AVERROR(EIO);
if (write(fd, buf, 8) != 8)
return AVERROR(EIO);
return 8;
@@ -354,7 +361,7 @@ static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
ffm->file_size = file_size;
}
-/* FIXME: make avserver work with IPv6 */
+/* 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)
{
@@ -389,14 +396,14 @@ static int resolve_host(struct in_addr *sin_addr, const char *hostname)
return 0;
}
-static char *ctime1(char *buf2)
+static char *ctime1(char *buf2, int buf_size)
{
time_t ti;
char *p;
ti = time(NULL);
p = ctime(&ti);
- strcpy(buf2, p);
+ av_strlcpy(buf2, p, buf_size);
p = buf2 + strlen(p) - 1;
if (*p == '\n')
*p = '\0';
@@ -409,7 +416,7 @@ static void http_vlog(const char *fmt, va_list vargs)
if (logfile) {
if (print_prefix) {
char buf[32];
- ctime1(buf);
+ ctime1(buf, sizeof(buf));
fprintf(logfile, "%s ", buf);
}
print_prefix = strstr(fmt, "\n") != NULL;
@@ -502,7 +509,7 @@ static void start_children(FFStream *feed)
slash = pathname;
else
slash++;
- strcpy(slash, "avconv");
+ strcpy(slash, "ffmpeg");
http_log("Launch command line: ");
http_log("%s ", pathname);
@@ -513,7 +520,7 @@ static void start_children(FFStream *feed)
for (i = 3; i < 256; i++)
close(i);
- if (!avserver_debug) {
+ 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))
@@ -571,15 +578,17 @@ static void start_multicast(void)
FFStream *stream;
char session_id[32];
HTTPContext *rtp_c;
- struct sockaddr_in dest_addr;
+ 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",
- av_lfg_get(&random_state), av_lfg_get(&random_state));
+ random0, random1);
/* choose a port if none given */
if (stream->multicast_port == 0) {
@@ -650,7 +659,7 @@ static int http_server(void)
return -1;
}
- http_log("AVserver started.\n");
+ http_log("FFserver started.\n");
start_children(first_feed);
@@ -694,7 +703,7 @@ static int http_server(void)
poll_entry->events = POLLOUT;
poll_entry++;
} else {
- /* when avserver is doing the timing, we work by
+ /* 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 */
@@ -777,16 +786,17 @@ static void start_wait_request(HTTPContext *c, int is_rtsp)
static void http_send_too_busy_reply(int fd)
{
- char buffer[300];
+ 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 %d, and this exceeds the limit of %d.</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);
}
@@ -911,6 +921,8 @@ static void close_connection(HTTPContext *c)
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;
@@ -1512,7 +1524,7 @@ static int http_parse_request(HTTPContext *c)
av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
- if (avserver_debug)
+ 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 */
@@ -1581,7 +1593,7 @@ static int http_parse_request(HTTPContext *c)
if (stream->stream_type == STREAM_TYPE_REDIRECT) {
c->http_error = 301;
q = c->buffer;
- q += snprintf(q, c->buffer_size,
+ snprintf(q, c->buffer_size,
"HTTP/1.0 301 Moved\r\n"
"Location: %s\r\n"
"Content-type: text/html\r\n"
@@ -1589,6 +1601,7 @@ static int http_parse_request(HTTPContext *c)
"<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;
@@ -1619,7 +1632,7 @@ static int http_parse_request(HTTPContext *c)
if (c->post == 0 && max_bandwidth < current_bandwidth) {
c->http_error = 503;
q = c->buffer;
- q += snprintf(q, c->buffer_size,
+ snprintf(q, c->buffer_size,
"HTTP/1.0 503 Server too busy\r\n"
"Content-type: text/html\r\n"
"\r\n"
@@ -1628,6 +1641,7 @@ static int http_parse_request(HTTPContext *c)
"<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;
@@ -1670,30 +1684,33 @@ static int http_parse_request(HTTPContext *c)
q = c->buffer;
switch(redir_type) {
case REDIR_ASX:
- q += snprintf(q, c->buffer_size,
+ 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"
+ //"<!-- 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:
- q += snprintf(q, c->buffer_size,
+ 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"
+ "# Autogenerated by ffserver\r\n"
"http://%s/%s%s\r\n", hostbuf, filename, info);
+ q += strlen(q);
break;
case REDIR_ASF:
- q += snprintf(q, c->buffer_size,
+ 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:
{
@@ -1703,12 +1720,13 @@ static int http_parse_request(HTTPContext *c)
p = strrchr(hostname, ':');
if (p)
*p = '\0';
- q += snprintf(q, c->buffer_size,
+ 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:
@@ -1718,10 +1736,11 @@ static int http_parse_request(HTTPContext *c)
socklen_t len;
struct sockaddr_in my_addr;
- q += snprintf(q, c->buffer_size,
+ 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);
@@ -1840,12 +1859,12 @@ static int http_parse_request(HTTPContext *c)
}
/* prepare http header */
- q = c->buffer;
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
+ 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";
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
+ 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")) {
@@ -1853,10 +1872,11 @@ static int http_parse_request(HTTPContext *c)
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);
+ 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);
}
- 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");
+ 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;
@@ -1867,7 +1887,7 @@ static int http_parse_request(HTTPContext *c)
send_error:
c->http_error = 404;
q = c->buffer;
- q += snprintf(q, c->buffer_size,
+ snprintf(q, c->buffer_size,
"HTTP/1.0 404 Not Found\r\n"
"Content-type: text/html\r\n"
"\r\n"
@@ -1875,6 +1895,7 @@ static int http_parse_request(HTTPContext *c)
"<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;
@@ -2024,7 +2045,7 @@ static void compute_status(HTTPContext *c)
if (stream->pid) {
avio_printf(pb, "Running as pid %d.\n", stream->pid);
-#if defined(linux) && !defined(CONFIG_NOCUTILS)
+#if defined(linux)
{
FILE *pid_stat;
char ps_cmd[64];
@@ -2039,7 +2060,7 @@ static void compute_status(HTTPContext *c)
char cpuperc[10];
char cpuused[64];
- if (fscanf(pid_stat, "%10s %64s", cpuperc,
+ 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);
@@ -2145,12 +2166,13 @@ static int open_input_stream(HTTPContext *c, const char *info)
char buf[128];
char input_filename[1024];
AVFormatContext *s = NULL;
- int i, ret;
+ 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)
@@ -2162,6 +2184,7 @@ static int open_input_stream(HTTPContext *c, const char *info)
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)
@@ -2177,6 +2200,10 @@ static int open_input_stream(HTTPContext *c, const char *info)
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) {
@@ -2273,7 +2300,7 @@ static int http_prepare_data(HTTPContext *c)
/*
* HACK to avoid mpeg ps muxer to spit many underflow errors
- * Default value from Libav
+ * Default value from FFmpeg
* Try to set it use configuration option
*/
c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
@@ -2934,12 +2961,14 @@ static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
{
AVFormatContext *avc;
AVStream *avs = NULL;
+ AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
int i;
avc = avformat_alloc_context();
- if (avc == NULL) {
+ 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;
@@ -3105,9 +3134,12 @@ static void rtsp_cmd_setup(HTTPContext *c, const char *url,
found:
/* generate session id if needed */
- if (h->session_id[0] == '\0')
+ 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",
- av_lfg_get(&random_state), av_lfg_get(&random_state));
+ random0, random1);
+ }
/* find rtp session, and create it if none found */
rtp_c = find_rtp_session(h->session_id);
@@ -3470,12 +3502,15 @@ static int rtp_new_av_stream(HTTPContext *c,
}
/********************************************************************/
-/* avserver initialization */
+/* 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;
@@ -3483,7 +3518,7 @@ static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int cop
fst->codec = avcodec_alloc_context3(NULL);
memcpy(fst->codec, codec, sizeof(AVCodecContext));
if (codec->extradata_size) {
- fst->codec->extradata = av_malloc(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);
}
@@ -3592,7 +3627,7 @@ static void extract_mpeg4_header(AVFormatContext *infile)
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 = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
st->codec->extradata_size = size;
memcpy(st->codec->extradata, pkt.data, size);
break;
@@ -3683,6 +3718,8 @@ static void build_feed_streams(void)
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;
@@ -3769,7 +3806,7 @@ static void build_feed_streams(void)
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");
+ http_log("Container doesn't support the required parameters\n");
exit(1);
}
/* XXX: need better api */
@@ -3823,6 +3860,9 @@ 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:
@@ -3928,10 +3968,10 @@ static void load_module(const char *filename)
return;
}
- init_func = dlsym(dll, "avserver_module_init");
+ init_func = dlsym(dll, "ffserver_module_init");
if (!init_func) {
fprintf(stderr,
- "%s: init function 'avserver_module_init()' not found\n",
+ "%s: init function 'ffserver_module_init()' not found\n",
filename);
dlclose(dll);
}
@@ -3940,7 +3980,7 @@ static void load_module(const char *filename)
}
#endif
-static int avserver_opt_default(const char *opt, const char *arg,
+static int ffserver_opt_default(const char *opt, const char *arg,
AVCodecContext *avctx, int type)
{
int ret = 0;
@@ -3950,7 +3990,7 @@ static int avserver_opt_default(const char *opt, const char *arg,
return ret;
}
-static int avserver_opt_preset(const char *arg,
+static int ffserver_opt_preset(const char *arg,
AVCodecContext *avctx, int type,
enum AVCodecID *audio_id, enum AVCodecID *video_id)
{
@@ -3981,7 +4021,7 @@ static int avserver_opt_preset(const char *arg,
*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){
+ }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;
@@ -3993,7 +4033,7 @@ static int avserver_opt_preset(const char *arg,
return ret;
}
-static AVOutputFormat *avserver_guess_format(const char *short_name, const char *filename,
+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);
@@ -4079,6 +4119,8 @@ static int parse_ffconfig(const char *filename)
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);
@@ -4115,7 +4157,7 @@ static int parse_ffconfig(const char *filename)
} else
max_bandwidth = llval;
} else if (!av_strcasecmp(cmd, "CustomLog")) {
- if (!avserver_debug)
+ if (!ffserver_debug)
get_arg(logfilename, sizeof(logfilename), &p);
} else if (!av_strcasecmp(cmd, "<Feed")) {
/*********************************************/
@@ -4165,10 +4207,7 @@ static int parse_ffconfig(const char *filename)
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",
+ 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);
@@ -4230,7 +4269,7 @@ static int parse_ffconfig(const char *filename)
stream = av_mallocz(sizeof(FFStream));
get_arg(stream->filename, sizeof(stream->filename), &p);
q = strrchr(stream->filename, '>');
- if (*q)
+ if (q)
*q = '\0';
for (s = first_stream; s; s = s->next) {
@@ -4239,9 +4278,10 @@ static int parse_ffconfig(const char *filename)
}
}
- stream->fmt = avserver_guess_format(NULL, stream->filename, NULL);
+ 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) {
@@ -4279,7 +4319,7 @@ static int parse_ffconfig(const char *filename)
/* 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);
+ stream->fmt = ffserver_guess_format(arg, NULL, NULL);
if (!stream->fmt) {
ERROR("Unknown Format: %s\n", arg);
}
@@ -4442,7 +4482,7 @@ static int parse_ffconfig(const char *filename)
avctx = &audio_enc;
type = AV_OPT_FLAG_AUDIO_PARAM;
}
- if (avserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_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") ||
@@ -4459,7 +4499,7 @@ static int parse_ffconfig(const char *filename)
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)) {
+ 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")) {
@@ -4642,13 +4682,13 @@ static void handle_child_exit(int sig)
static void opt_debug(void)
{
- avserver_debug = 1;
+ ffserver_debug = 1;
logfilename[0] = '-';
}
void show_help_default(const char *opt, const char *arg)
{
- printf("usage: avserver [options]\n"
+ 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);
@@ -4658,7 +4698,7 @@ 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" },
+ { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
{ NULL },
};
@@ -4670,12 +4710,15 @@ int main(int argc, char **argv)
av_register_all();
avformat_network_init();
- show_banner();
+ show_banner(argc, argv, options);
my_program_name = argv[0];
parse_options(NULL, argc, argv, options, NULL);
+ if (!config_filename)
+ config_filename = av_strdup("/etc/ffserver.conf");
+
unsetenv("http_proxy"); /* Kill the http_proxy */
av_lfg_init(&random_state, av_get_random_seed());
@@ -4688,6 +4731,7 @@ int main(int argc, char **argv)
fprintf(stderr, "Incorrect config file - exiting.\n");
exit(1);
}
+ av_freep(&config_filename);
/* open log file if needed */
if (logfilename[0] != '\0') {
diff --git a/libavcodec/012v.c b/libavcodec/012v.c
new file mode 100644
index 0000000..58e3cd6
--- /dev/null
+++ b/libavcodec/012v.c
@@ -0,0 +1,153 @@
+/*
+ * 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 (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",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_012V,
+ .init = zero12v_decode_init,
+ .decode = zero12v_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"),
+};
diff --git a/libavcodec/4xm.c b/libavcodec/4xm.c
index fd03134..d2c90ac 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:
- assert(0);
+ av_assert2(0);
}
}
@@ -342,10 +344,14 @@ static void decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src,
uint16_t *start = (uint16_t *)f->last_picture->data[0];
uint16_t *end = start + stride * (f->avctx->height - h + 1) - (1 << log2w);
- assert(code >= 0 && code <= 6);
+ av_assert2(code >= 0 && code <= 6);
if (code == 0) {
- src += f->mv[bytestream2_get_byte(&f->g)];
+ if (bytestream2_get_bytes_left(&f->g) < 1) {
+ av_log(f->avctx, AV_LOG_ERROR, "bytestream overread\n");
+ return;
+ }
+ src += f->mv[bytestream2_get_byteu(&f->g)];
if (start > src || src > end) {
av_log(f->avctx, AV_LOG_ERROR, "mv out of pic\n");
return;
@@ -364,21 +370,37 @@ static void decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src,
} else if (code == 3 && f->version < 2) {
mcdc(dst, src, log2w, h, stride, 1, 0);
} else if (code == 4) {
- src += f->mv[bytestream2_get_byte(&f->g)];
+ if (bytestream2_get_bytes_left(&f->g) < 1) {
+ av_log(f->avctx, AV_LOG_ERROR, "bytestream overread\n");
+ return;
+ }
+ src += f->mv[bytestream2_get_byteu(&f->g)];
if (start > src || src > end) {
av_log(f->avctx, AV_LOG_ERROR, "mv out of pic\n");
return;
}
- mcdc(dst, src, log2w, h, stride, 1, bytestream2_get_le16(&f->g2));
+ if (bytestream2_get_bytes_left(&f->g2) < 2){
+ av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n");
+ return;
+ }
+ mcdc(dst, src, log2w, h, stride, 1, bytestream2_get_le16u(&f->g2));
} else if (code == 5) {
- mcdc(dst, src, log2w, h, stride, 0, bytestream2_get_le16(&f->g2));
+ if (bytestream2_get_bytes_left(&f->g2) < 2) {
+ av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n");
+ return;
+ }
+ mcdc(dst, src, log2w, h, stride, 0, bytestream2_get_le16u(&f->g2));
} else if (code == 6) {
+ if (bytestream2_get_bytes_left(&f->g2) < 4) {
+ av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n");
+ return;
+ }
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);
}
}
}
@@ -397,6 +419,8 @@ static int decode_p_frame(FourXContext *f, AVFrame *frame,
if (f->version > 1) {
extra = 20;
+ if (length < extra)
+ return -1;
bitstream_size = AV_RL32(buf + 8);
wordstream_size = AV_RL32(buf + 12);
bytestream_size = AV_RL32(buf + 16);
@@ -407,13 +431,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;
}
@@ -454,6 +477,11 @@ 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)
@@ -554,7 +582,7 @@ static int decode_i_mb(FourXContext *f)
}
static const uint8_t *read_huffman_tables(FourXContext *f,
- const uint8_t * const buf)
+ const uint8_t * const buf, int buf_size)
{
int frequency[512] = { 0 };
uint8_t flag[512];
@@ -563,6 +591,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));
@@ -572,6 +601,10 @@ static const uint8_t *read_huffman_tables(FourXContext *f,
for (;;) {
int i;
+ 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++;
start = *ptr++;
@@ -585,6 +618,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 };
@@ -654,6 +692,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) {
@@ -665,6 +704,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);
@@ -698,16 +739,14 @@ 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;
- if (length < bitstream_size + 12) {
+ if (bitstream_size > (1<<26) || length < bitstream_size + 12) {
av_log(f->avctx, AV_LOG_ERROR, "packet size too small\n");
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;
@@ -719,12 +758,14 @@ static int decode_i_frame(FourXContext *f, AVFrame *frame, const uint8_t *buf, i
return AVERROR_INVALIDDATA;
}
- prestream = read_huffman_tables(f, prestream);
+ prestream = read_huffman_tables(f, prestream, buf + length - prestream);
if (!prestream) {
av_log(f->avctx, AV_LOG_ERROR, "Error reading Huffman tables.\n");
return AVERROR_INVALIDDATA;
}
+ av_assert0(prestream <= buf + length);
+
init_get_bits(&f->gb, buf + 4, 8 * bitstream_size);
prestream_size = length + buf - prestream;
@@ -765,6 +806,8 @@ static int decode_frame(AVCodecContext *avctx, void *data,
AVFrame *picture = data;
int i, frame_4cc, frame_size, ret;
+ if (buf_size < 12)
+ return AVERROR_INVALIDDATA;
frame_4cc = AV_RL32(buf);
if (buf_size != AV_RL32(buf + 4) + 8 || buf_size < 20)
av_log(f->avctx, AV_LOG_ERROR, "size mismatch %d %d\n",
@@ -777,6 +820,16 @@ static int decode_frame(AVCodecContext *avctx, void *data,
const int whole_size = AV_RL32(buf + 16);
CFrameBuffer *cfrm;
+ if (data_size < 0 || whole_size < 0) {
+ av_log(f->avctx, AV_LOG_ERROR, "sizes invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (f->version <= 1) {
+ av_log(f->avctx, AV_LOG_ERROR, "cfrm in version %d\n", f->version);
+ 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",
@@ -795,11 +848,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);
}
@@ -823,35 +879,40 @@ 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")) {
if (!f->last_picture->data[0]) {
if ((ret = ff_get_buffer(avctx, f->last_picture,
- AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
- memset(f->last_picture->data[0], 0, avctx->height * FFABS(f->last_picture->linesize[0]));
+ for (i=0; i<avctx->height; i++)
+ memset(f->last_picture->data[0] + i*f->last_picture->linesize[0], 0, 2*avctx->width);
}
- 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);
@@ -860,10 +921,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;
@@ -878,7 +938,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;
@@ -891,8 +955,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;
@@ -911,6 +976,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 fcb7b2b..a910551 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,25 +66,16 @@ static int decode_frame(AVCodecContext *avctx, void *data,
unsigned int dlen, p, row;
const unsigned char *lp, *dp;
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;
- }
/* 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);
@@ -93,6 +84,8 @@ static int decode_frame(AVCodecContext *avctx, void *data,
for (row = 0; row < height; row++) {
pixptr = frame->data[0] + row * frame->linesize[0] + planemap[p];
pixptr_end = pixptr + frame->linesize[0];
+ if(lp - encoded + row*2 + 1 >= buf_size)
+ return -1;
dlen = av_be2ne16(*(const unsigned short *)(lp + row * 2));
/* Decode a row of this plane */
while (dlen > 0) {
@@ -101,21 +94,21 @@ static int decode_frame(AVCodecContext *avctx, void *data,
if ((count = *dp++) <= 127) {
count++;
dlen -= count + 1;
- if (pixptr + count * px_inc > pixptr_end)
+ if (pixptr + count * planes > pixptr_end)
break;
if (dp + count > buf + buf_size)
return AVERROR_INVALIDDATA;
while (count--) {
*pixptr = *dp++;
- pixptr += px_inc;
+ pixptr += planes;
}
} else {
count = 257 - count;
- if (pixptr + count * px_inc > pixptr_end)
+ if (pixptr + count * planes > pixptr_end)
break;
while (count--) {
*pixptr = *dp;
- pixptr += px_inc;
+ pixptr += planes;
}
dp++;
dlen -= 2;
@@ -168,12 +161,12 @@ static av_cold int decode_init(AVCodecContext *avctx)
c->planemap[0] = 1; // 1st plane is red
c->planemap[1] = 2; // 2nd plane is green
c->planemap[2] = 3; // 3rd plane is blue
- c->planemap[3] = 0; // 4th plane is alpha???
+ c->planemap[3] = 0; // 4th plane is alpha
#else
c->planemap[0] = 2; // 1st plane is red
c->planemap[1] = 1; // 2nd plane is green
c->planemap[2] = 0; // 3rd plane is blue
- c->planemap[3] = 3; // 4th plane is alpha???
+ c->planemap[3] = 3; // 4th plane is alpha
#endif
break;
default:
diff --git a/libavcodec/8svx.c b/libavcodec/8svx.c
index 94eb319..82fda6f 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,48 +178,39 @@ 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",
.type = AVMEDIA_TYPE_AUDIO,
.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,
.long_name = NULL_IF_CONFIG_SMALL("8SVX fibonacci"),
.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",
.type = AVMEDIA_TYPE_AUDIO,
.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,
.long_name = NULL_IF_CONFIG_SMALL("8SVX exponential"),
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P,
AV_SAMPLE_FMT_NONE },
};
-
-AVCodec ff_pcm_s8_planar_decoder = {
- .name = "pcm_s8_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,
- .long_name = NULL_IF_CONFIG_SMALL("PCM signed 8-bit planar"),
- .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P,
- AV_SAMPLE_FMT_NONE },
-};
+#endif
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 2c3522e..4945592 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 \
@@ -19,17 +22,20 @@ 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 \
# parts needed for many different codecs
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 \
@@ -62,6 +68,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
@@ -69,6 +76,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 \
@@ -95,10 +103,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
@@ -108,16 +122,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
@@ -130,10 +153,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
@@ -162,21 +189,28 @@ OBJS-$(CONFIG_EIGHTBPS_DECODER) += 8bps.o
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
OBJS-$(CONFIG_FRAPS_DECODER) += fraps.o
OBJS-$(CONFIG_FRWU_DECODER) += frwu.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
@@ -192,10 +226,12 @@ 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_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
@@ -205,6 +241,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_J2K_DECODER) += j2kdec.o mqcdec.o mqc.o j2k.o j2k_dwt.o
+OBJS-$(CONFIG_J2K_ENCODER) += j2kenc.o mqcenc.o mqc.o j2k.o j2k_dwt.o
OBJS-$(CONFIG_JPEG2000_DECODER) += jpeg2000dec.o jpeg2000.o \
jpeg2000dwt.o mqcdec.o mqc.o
OBJS-$(CONFIG_JPEGLS_DECODER) += jpeglsdec.o jpegls.o \
@@ -219,6 +258,7 @@ OBJS-$(CONFIG_LOCO_DECODER) += loco.o
OBJS-$(CONFIG_MACE3_DECODER) += mace.o
OBJS-$(CONFIG_MACE6_DECODER) += mace.o
OBJS-$(CONFIG_MDEC_DECODER) += mdec.o mpeg12.o mpeg12data.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
@@ -226,6 +266,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
@@ -240,11 +282,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 \
@@ -261,12 +307,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
@@ -279,12 +330,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
+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 \
@@ -295,13 +350,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
@@ -314,9 +372,12 @@ 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_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 \
@@ -325,9 +386,20 @@ 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_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
@@ -337,15 +409,18 @@ 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
+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
@@ -359,6 +434,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
@@ -366,7 +445,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
@@ -381,8 +460,11 @@ 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_VPLAYER_DECODER) += textdec.o ass.o
OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o
OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o
+OBJS-$(CONFIG_WEBP_DECODER) += vp8.o vp8dsp.o vp56rac.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
@@ -403,13 +485,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
@@ -434,22 +524,30 @@ 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
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
@@ -469,7 +567,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
@@ -487,8 +587,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
@@ -504,6 +606,7 @@ 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
@@ -528,41 +631,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_ENCODER) += libfdk-aacenc.o
OBJS-$(CONFIG_LIBGSM_DECODER) += libgsm.o
@@ -585,13 +693,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
@@ -607,14 +721,17 @@ 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_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
@@ -628,6 +745,7 @@ OBJS-$(CONFIG_MLP_PARSER) += mlp_parser.o mlp.o
OBJS-$(CONFIG_MPEG4VIDEO_PARSER) += mpeg4video_parser.o h263.o \
mpeg4videodec.o mpeg4video.o \
ituh263dec.o h263dec.o
+OBJS-$(CONFIG_PNG_PARSER) += png_parser.o
OBJS-$(CONFIG_MPEGAUDIO_PARSER) += mpegaudio_parser.o \
mpegaudiodecheader.o mpegaudiodata.o
OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \
@@ -663,33 +781,43 @@ 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
+SKIPHEADERS-$(HAVE_OS2THREADS) += os2threads.h
SKIPHEADERS-$(HAVE_W32THREADS) += w32pthreads.h
-EXAMPLES = api
-
-TESTPROGS = dct \
+TESTPROGS = cabac \
+ dct \
fft \
fft-fixed \
golomb \
iirfilter \
+ imgconvert \
rangecoder \
+ snowenc \
+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
+++ /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 beddf9f..eaf7b46 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",
.type = AVMEDIA_TYPE_VIDEO,
@@ -383,7 +406,8 @@ AVCodec ff_a64multi_encoder = {
.long_name = NULL_IF_CONFIG_SMALL("Multicolor charset for Commodore 64"),
.capabilities = CODEC_CAP_DELAY,
};
-
+#endif
+#if CONFIG_A64MULTI5_ENCODER
AVCodec ff_a64multi5_encoder = {
.name = "a64multi5",
.type = AVMEDIA_TYPE_VIDEO,
@@ -396,3 +420,4 @@ AVCodec ff_a64multi5_encoder = {
.long_name = NULL_IF_CONFIG_SMALL("Multicolor charset for Commodore 64, extended with 5th color (colram)"),
.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 b12d2ba..d586e27 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;
@@ -302,9 +303,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 90b49c5..ca49d2f 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..c7d7b3a 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
*/
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 a45de9a..2b080ba 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..45fbc2d 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,7 +1112,7 @@ static void search_for_ms(AACEncContext *s, ChannelElement *cpe,
}
}
-AACCoefficientsEncoder ff_aac_coders[] = {
+AACCoefficientsEncoder ff_aac_coders[AAC_CODER_NB] = {
{
search_for_quantizers_faac,
encode_window_bands_info,
diff --git a/libavcodec/aacdec.c b/libavcodec/aacdec.c
index 3219ec6..cd7bbb0 100644
--- a/libavcodec/aacdec.c
+++ b/libavcodec/aacdec.c
@@ -7,20 +7,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
*/
@@ -80,6 +80,7 @@
*/
#include "libavutil/float_dsp.h"
+#include "libavutil/opt.h"
#include "avcodec.h"
#include "internal.h"
#include "get_bits.h"
@@ -106,12 +107,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)
{
@@ -128,7 +135,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
@@ -150,6 +157,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)) {
@@ -183,10 +194,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++) {
@@ -403,6 +412,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);
}
}
@@ -447,7 +458,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;
@@ -459,6 +471,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.
@@ -492,6 +521,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;
@@ -508,6 +539,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;
@@ -586,6 +619,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);
@@ -628,6 +663,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);
@@ -647,7 +686,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 -1;
}
skip_bits_long(gb, comment_len);
@@ -743,13 +782,15 @@ static int decode_audio_specific_config(AACContext *ac,
{
GetBitContext gb;
int i;
+ int 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");
- init_get_bits(&gb, data, bit_size);
+ if ((ret = init_get_bits(&gb, data, bit_size)) < 0)
+ return ret;
if ((i = avpriv_mpeg4audio_get_config(m4ac, data, bit_size, sync_extension)) < 0)
return -1;
@@ -787,7 +828,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;
@@ -839,6 +880,8 @@ static void reset_predictor_group(PredictorState *ps, int group_num)
ff_aac_spectral_codes[num], sizeof(ff_aac_spectral_codes[num][0]), 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;
@@ -846,6 +889,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) {
@@ -883,6 +928,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);
@@ -936,7 +986,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 -1;
}
skip_bits_long(gb, 8 * count);
@@ -1017,11 +1067,11 @@ static int decode_ics_info(AACContext *ac, IndividualChannelStream *ics,
if (ics->predictor_present) {
if (ac->oc[1].m4ac.object_type == AOT_AAC_MAIN) {
if (decode_prediction(ac, ics, gb)) {
- return AVERROR_INVALIDDATA;
+ goto fail;
}
} else if (ac->oc[1].m4ac.object_type == AOT_AAC_LC) {
av_log(ac->avctx, AV_LOG_ERROR, "Prediction is not allowed in AAC-LC.\n");
- return AVERROR_INVALIDDATA;
+ goto fail;
} else {
if ((ics->ltp.present = get_bits(gb, 1)))
decode_ltp(&ics->ltp, gb, ics->max_sfb);
@@ -1033,10 +1083,13 @@ static int decode_ics_info(AACContext *ac, IndividualChannelStream *ics,
av_log(ac->avctx, AV_LOG_ERROR,
"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;
}
/**
@@ -1067,7 +1120,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 -1;
}
if (sect_end > ics->max_sfb) {
@@ -1235,7 +1288,7 @@ static void decode_mid_side_stereo(ChannelElement *cpe, GetBitContext *gb,
for (idx = 0; idx < cpe->ch[0].ics.num_window_groups * cpe->ch[0].ics.max_sfb; 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);
}
}
@@ -1938,6 +1991,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.
*
@@ -1979,6 +2058,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:
@@ -2001,7 +2082,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;
@@ -2093,10 +2174,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])
@@ -2308,25 +2389,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_windowing(ac, &che->ch[0]);
+ ac->imdct_and_windowing(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_windowing(ac, &che->ch[1]);
+ ac->imdct_and_windowing(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);
@@ -2348,10 +2429,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) {
@@ -2364,6 +2447,21 @@ static int parse_adts_frame_header(AACContext *ac, GetBitContext *gb)
return -7;
} 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;
@@ -2381,13 +2479,14 @@ static int parse_adts_frame_header(AACContext *ac, GetBitContext *gb)
}
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;
@@ -2429,6 +2528,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:
@@ -2461,9 +2561,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;
@@ -2473,7 +2574,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 = -1;
goto fail;
}
@@ -2504,17 +2605,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);
@@ -2535,8 +2654,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);
@@ -2553,9 +2676,18 @@ 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;
+
init_get_bits(&gb, buf, buf_size * 8);
- if ((err = aac_decode_frame_int(avctx, data, got_frame_ptr, &gb)) < 0)
+ if ((err = aac_decode_frame_int(avctx, data, got_frame_ptr, &gb, avpkt)) < 0)
return err;
buf_consumed = (get_bits_count(&gb) + 7) >> 3;
@@ -2590,7 +2722,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
@@ -2635,10 +2767,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;
@@ -2681,9 +2818,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;
@@ -2796,14 +2933,15 @@ static int latm_decode_frame(AVCodecContext *avctx, void *out,
int muxlength, err;
GetBitContext gb;
- init_get_bits(&gb, avpkt->data, avpkt->size * 8);
+ if ((err = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0)
+ return err;
// check for LOAS sync word
if (get_bits(&gb, 11) != LOAS_SYNC_WORD)
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;
@@ -2833,7 +2971,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;
@@ -2850,6 +2988,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",
@@ -2865,6 +3037,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,
};
/*
@@ -2886,4 +3060,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 b2ad47b..362f02b 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,7 @@ 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 = 2}, 0, AAC_CODER_NB-1, AACENC_FLAGS},
{NULL}
};
@@ -802,6 +802,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",
.type = AVMEDIA_TYPE_AUDIO,
@@ -810,6 +817,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..cebdd18 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,11 @@
#include "audio_frame_queue.h"
#include "psymodel.h"
+#define AAC_CODER_NB 4
+
typedef struct AACEncOptions {
int stereo_mode;
+ int aac_coder;
} AACEncOptions;
struct AACEncContext;
@@ -82,4 +85,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 0c610ed..1f9c326 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..9526d3a 100644
--- a/libavcodec/aacpsdsp.c
+++ b/libavcodec/aacpsdsp.c
@@ -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..df01e0b 100644
--- a/libavcodec/aacpsdsp.h
+++ b/libavcodec/aacpsdsp.h
@@ -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 9176e37..6cbb8c4 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 56e5796..6ed3b4a 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 bce27c0..26ba30d 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,22 +84,37 @@ 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 ((ret = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
- return ret;
+ 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)
+ 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;
for (i = avctx->height - 1; i >= 0; i--) {
- memcpy(s->frame->data[0] + i * s->frame->linesize[0], buf, avctx->width * 3);
+ if (avctx->width * psize > buf_size) {
+ av_log(avctx, AV_LOG_ERROR, "Next line is beyond buffer bounds\n");
+ break;
+ }
+ memcpy(s->frame->data[0] + i * s->frame->linesize[0], buf, avctx->width * psize);
buf += stride;
+ buf_size -= stride;
}
break;
case 1:
@@ -86,6 +125,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 abfd380..a70d92a 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;
@@ -1322,7 +1322,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)) {
@@ -1353,6 +1353,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)) {
@@ -1371,19 +1375,18 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
/* get output buffer */
frame->nb_samples = s->num_blocks * 256;
- 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)) {
@@ -1392,13 +1395,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], 1024);
- for (ch = 0; ch < s->out_channels; ch++) {
+ memcpy(((float*)frame->data[ch]) + AC3_BLOCK_SIZE*blk, output[ch], 1024);
+ for (ch = 0; ch < s->out_channels; ch++)
output[ch] = s->outptr[channel_map[ch]];
- s->outptr[channel_map[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], 1024);
@@ -1424,6 +1431,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 6707fd2..6c99ef6 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..a0b810e 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;
diff --git a/libavcodec/ac3enc_fixed.c b/libavcodec/ac3enc_fixed.c
index e471edf..5d8dd5c 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 a225d9b..7864f41 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_template.c b/libavcodec/ac3enc_template.c
index ae9100c..0389c2e 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;
@@ -361,17 +364,9 @@ static void compute_rematrixing_strategy(AC3EncodeContext *s)
/* calculate 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..9d20d90 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
*/
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 a85e45f..c9d6f87 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 9502849..1259bd4 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;
}
@@ -145,6 +147,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:
@@ -225,6 +229,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 +323,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 +352,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 +462,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 +481,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 +496,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,6 +551,11 @@ 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:
if (avctx->block_align > 0)
buf_size = FFMIN(buf_size, avctx->block_align);
@@ -566,15 +597,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 +650,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;
@@ -770,7 +809,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
return AVERROR_INVALIDDATA;
}
}
- for (n = nb_samples >> (1 - st); 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 +910,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 +1017,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 +1205,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 +1215,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 +1301,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 +1404,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 +1501,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 +1517,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..0625fc9 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
*/
@@ -49,6 +49,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 +84,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..0ebb7c3 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
*/
@@ -30,10 +30,12 @@
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 14b1257..cef8b6f 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..4c88f81 100644
--- a/libavcodec/adx.c
+++ b/libavcodec/adx.c
@@ -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/adxdec.c b/libavcodec/adxdec.c
index 5221686..7d7fe3a 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 47620a2..df07c81 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/alac.c b/libavcodec/alac.c
index 9ef0653..0018b9a 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)
@@ -73,6 +73,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 +99,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 +110,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 +153,7 @@ static void rice_decompress(ALACContext *alac, int32_t *output_buffer,
history = 0;
}
}
+ return 0;
}
static inline int sign_only(int v)
@@ -184,7 +190,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 +269,7 @@ static int decode_element(AVCodecContext *avctx, AVFrame *frame, int ch_index,
alac->extra_bits = get_bits(&alac->gb, 2) << 3;
bps = alac->sample_size - alac->extra_bits + channels - 1;
- if (bps > 32) {
+ if (bps > 32U) {
av_log(avctx, AV_LOG_ERROR, "bps is unsupported: %d\n", bps);
return AVERROR_PATCHWELCOME;
}
@@ -283,17 +289,15 @@ static int decode_element(AVCodecContext *avctx, AVFrame *frame, int ch_index,
if (!alac->nb_samples) {
/* 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_get_buffer(avctx, frame, 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];
}
@@ -321,14 +325,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) {
@@ -353,6 +361,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);
@@ -373,6 +383,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++) {
@@ -388,6 +399,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;
}
@@ -413,12 +455,14 @@ 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;
}
channels = (element == TYPE_CPE) ? 2 : 1;
- if (ch + channels > alac->channels) {
+ if ( ch + channels > alac->channels
+ || ff_alac_channel_layout_offsets[alac->channels - 1][ch] + channels > alac->channels
+ ) {
av_log(avctx, AV_LOG_ERROR, "invalid element channel count\n");
return AVERROR_INVALIDDATA;
}
@@ -453,7 +497,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]);
}
@@ -464,13 +508,18 @@ static av_cold int alac_decode_close(AVCodecContext *avctx)
static int allocate_buffers(ALACContext *alac)
{
int ch;
- int buf_size = alac->max_samples_per_frame * sizeof(int32_t);
+ int buf_size;
+
+ if (alac->max_samples_per_frame > INT_MAX / sizeof(int32_t))
+ goto buf_alloc_fail;
+ buf_size = alac->max_samples_per_frame * sizeof(int32_t);
for (ch = 0; ch < FFMIN(alac->channels, 2); ch++) {
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);
}
@@ -516,24 +565,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;
@@ -549,7 +600,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;
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 0143240..4ee558c 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
*/
@@ -613,10 +613,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 45fea3a..4d5af67 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
*/
@@ -96,19 +96,24 @@ void avcodec_register_all(void)
REGISTER_ENCODER(A64MULTI, a64multi);
REGISTER_ENCODER(A64MULTI5, a64multi5);
REGISTER_DECODER(AASC, aasc);
- 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);
@@ -117,9 +122,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);
@@ -135,10 +142,12 @@ void avcodec_register_all(void)
REGISTER_DECODER(EIGHTSVX_EXP, eightsvx_exp);
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);
@@ -148,8 +157,10 @@ 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_ENCDEC (HUFFYUV, huffyuv);
REGISTER_DECODER(IDCIN, idcin);
@@ -160,6 +171,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(INDEO4, indeo4);
REGISTER_DECODER(INDEO5, indeo5);
REGISTER_DECODER(INTERPLAY_VIDEO, interplay_video);
+ REGISTER_ENCDEC (J2K, j2k);
REGISTER_DECODER(JPEG2000, jpeg2000);
REGISTER_ENCDEC (JPEGLS, jpegls);
REGISTER_DECODER(JV, jv);
@@ -178,21 +190,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);
@@ -202,12 +221,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);
@@ -217,14 +239,18 @@ void avcodec_register_all(void)
REGISTER_DECODER(RV30, rv30);
REGISTER_DECODER(RV40, rv40);
REGISTER_DECODER(S302M, s302m);
+ REGISTER_DECODER(SANM, sanm);
REGISTER_ENCDEC (SGI, sgi);
+ REGISTER_DECODER(SGIRLE, sgirle);
REGISTER_DECODER(SMACKER, smacker);
REGISTER_DECODER(SMC, smc);
+ 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);
@@ -239,10 +265,13 @@ 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);
@@ -255,18 +284,24 @@ void avcodec_register_all(void)
REGISTER_DECODER(VP6F, vp6f);
REGISTER_DECODER(VP8, vp8);
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);
@@ -287,11 +322,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);
@@ -312,6 +350,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);
@@ -320,6 +359,8 @@ 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);
@@ -346,15 +387,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_ENCDEC (PCM_S24LE_PLANAR, pcm_s24le_planar);
REGISTER_ENCDEC (PCM_S32BE, pcm_s32be);
REGISTER_ENCDEC (PCM_S32LE, pcm_s32le);
+ 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);
@@ -362,7 +406,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);
@@ -373,7 +417,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);
@@ -389,7 +435,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);
@@ -401,16 +449,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_ENCODER(LIBFDK_AAC, libfdk_aac);
REGISTER_ENCDEC (LIBGSM, libgsm);
@@ -422,22 +486,34 @@ 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(LIBX264, libx264);
+ REGISTER_ENCODER(LIBX264RGB, libx264rgb);
REGISTER_ENCODER(LIBXAVS, libxavs);
REGISTER_ENCODER(LIBXVID, libxvid);
+ 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);
@@ -445,6 +521,7 @@ void avcodec_register_all(void)
REGISTER_PARSER(DNXHD, dnxhd);
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);
@@ -455,6 +532,7 @@ void avcodec_register_all(void)
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 8451edb..e7aeb0c 100644
--- a/libavcodec/alsdec.c
+++ b/libavcodec/alsdec.c
@@ -2,20 +2,20 @@
* MPEG-4 ALS decoder
* Copyright (c) 2009 Thilo Borgmann <thilo.borgmann _at_ 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
*/
@@ -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 -1;
- 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;
}
}
@@ -961,14 +976,16 @@ static int decode_var_block_data(ALSDecContext *ctx, ALSBlockData *bd)
static int read_block(ALSDecContext *ctx, ALSBlockData *bd)
{
GetBitContext *gb = &ctx->gb;
+ int ret;
*bd->shift_lsbs = 0;
// read block type flag and read the samples accordingly
if (get_bits1(gb)) {
- if (read_var_block_data(ctx, bd))
- return -1;
+ if ((ret = read_var_block_data(ctx, bd)) < 0)
+ return ret;
} else {
- read_const_block_data(ctx, bd);
+ if ((ret = read_const_block_data(ctx, bd)) < 0)
+ return ret;
}
return 0;
@@ -1022,8 +1039,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);
@@ -1129,7 +1146,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];
@@ -1166,20 +1183,20 @@ 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 -1;
}
if (current->master_channel != c) {
current->time_diff_flag = get_bits1(gb);
- current->weighting[0] = mcc_weightings[av_clip(decode_rice(gb, 1) + 16, 0, 32)];
- current->weighting[1] = mcc_weightings[av_clip(decode_rice(gb, 2) + 14, 0, 32)];
- current->weighting[2] = mcc_weightings[av_clip(decode_rice(gb, 1) + 16, 0, 32)];
+ current->weighting[0] = mcc_weightings[av_clip(decode_rice(gb, 1) + 16, 0, 31)];
+ current->weighting[1] = mcc_weightings[av_clip(decode_rice(gb, 2) + 14, 0, 31)];
+ current->weighting[2] = mcc_weightings[av_clip(decode_rice(gb, 1) + 16, 0, 31)];
if (current->time_diff_flag) {
- current->weighting[3] = mcc_weightings[av_clip(decode_rice(gb, 1) + 16, 0, 32)];
- current->weighting[4] = mcc_weightings[av_clip(decode_rice(gb, 1) + 16, 0, 32)];
- current->weighting[5] = mcc_weightings[av_clip(decode_rice(gb, 1) + 16, 0, 32)];
+ current->weighting[3] = mcc_weightings[av_clip(decode_rice(gb, 1) + 16, 0, 31)];
+ current->weighting[4] = mcc_weightings[av_clip(decode_rice(gb, 1) + 16, 0, 31)];
+ current->weighting[5] = mcc_weightings[av_clip(decode_rice(gb, 1) + 16, 0, 31)];
current->time_diff_sign = get_bits1(gb);
current->time_diff_index = get_bits(gb, ctx->ltp_lag_length - 3) + 3;
@@ -1191,7 +1208,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 -1;
}
@@ -1223,7 +1240,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 -1;
}
@@ -1351,7 +1368,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 -1;
}
@@ -1400,6 +1417,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;
}
@@ -1459,19 +1477,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) {
@@ -1481,7 +1503,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) {
@@ -1718,7 +1740,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 fcaaab3..6376db1 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 c875d81..8c3eb56 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 1c4c7e2..9aef6d3 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 c851d88..68132df 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 d28e51a..1f55dab 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 {
@@ -1402,7 +1410,6 @@ static int ape_decode_frame(AVCodecContext *avctx, void *data,
int32_t *sample24;
int i, ch, ret;
int blockstodecode;
- int bytes_used = 0;
/* this should never be negative, but bad things will happen if it is, so
check it just to make sure. */
@@ -1467,8 +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;
}
-
- bytes_used = avpkt->size;
}
if (!s->data) {
@@ -1493,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;
@@ -1540,7 +1543,7 @@ static int ape_decode_frame(AVCodecContext *avctx, void *data,
*got_frame_ptr = 1;
- return bytes_used;
+ return !s->samples ? avpkt->size : 0;
}
static void ape_flush(AVCodecContext *avctx)
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/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..42f35e3 100644
--- a/libavcodec/arm/ac3dsp_neon.S
+++ b/libavcodec/arm/ac3dsp_neon.S
@@ -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 3e55e43..431b62e 100644
--- a/libavcodec/arm/dca.h
+++ b/libavcodec/arm/dca.h
@@ -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,
{
int 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 f0375c9..56568e0 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/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..fa33eac 100644
--- a/libavcodec/arm/fft_fixed_neon.S
+++ b/libavcodec/arm/fft_fixed_neon.S
@@ -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 9ec620f..8c98abc 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
*/
@@ -43,8 +43,10 @@ av_cold void ff_fft_init_arm(FFTContext *s)
int cpu_flags = av_get_cpu_flags();
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/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 c5f8fbf..1d99c97 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 fb12de1..7b012bc 100644
--- a/libavcodec/arm/fmtconvert_vfp.S
+++ b/libavcodec/arm/fmtconvert_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/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/h264dsp_init_arm.c b/libavcodec/arm/h264dsp_init_arm.c
index bb8b3b9..8dec1f6 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
*/
@@ -71,11 +71,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;
@@ -95,6 +98,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..6b28a97 100644
--- a/libavcodec/arm/int_neon.S
+++ b/libavcodec/arm/int_neon.S
@@ -2,20 +2,20 @@
* ARM NEON optimised integer operations
* Copyright (c) 2009 Kostya Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
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_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/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/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/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/simple_idct_arm.S b/libavcodec/arm/simple_idct_arm.S
index 8ba6c48..dd1c815 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/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/vp56dsp_init_arm.c b/libavcodec/arm/vp56dsp_init_arm.c
index 65e892d..f53cbae 100644
--- a/libavcodec/arm/vp56dsp_init_arm.c
+++ b/libavcodec/arm/vp56dsp_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/vp56dsp_neon.S b/libavcodec/arm/vp56dsp_neon.S
index 10b4d0f..03dd28d 100644
--- a/libavcodec/arm/vp56dsp_neon.S
+++ b/libavcodec/arm/vp56dsp_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_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_neon.S b/libavcodec/arm/vp8dsp_neon.S
index 0cd2efa..04e7c5c 100644
--- a/libavcodec/arm/vp8dsp_neon.S
+++ b/libavcodec/arm/vp8dsp_neon.S
@@ -4,20 +4,20 @@
* Copyright (c) 2010 Rob Clark <rob@ti.com>
* Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ass.c b/libavcodec/ass.c
index 098050a..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
--- /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
--- /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..7b8a540 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,47 @@ 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);
+ if (*p) p += strcspn(p, ",") + 1; // skip layer or marked
+ if (*p) p += strcspn(p, ",") + 1; // skip start timestamp
+ if (*p) p += strcspn(p, ",") + 1; // 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 +100,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 9f74abb..eb29e08 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;
@@ -279,8 +276,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;
@@ -307,6 +303,7 @@ static av_cold int decode_end(AVCodecContext *avctx)
return 0;
}
+#if CONFIG_ASV1_DECODER
AVCodec ff_asv1_decoder = {
.name = "asv1",
.type = AVMEDIA_TYPE_VIDEO,
@@ -318,7 +315,9 @@ AVCodec ff_asv1_decoder = {
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("ASUS V1"),
};
+#endif
+#if CONFIG_ASV2_DECODER
AVCodec ff_asv2_decoder = {
.name = "asv2",
.type = AVMEDIA_TYPE_VIDEO,
@@ -330,4 +329,5 @@ AVCodec ff_asv2_decoder = {
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("ASUS V2"),
};
+#endif
diff --git a/libavcodec/asvenc.c b/libavcodec/asvenc.c
index 2f48f73..a09aa73 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 ebdbe81..ea342a0 100644
--- a/libavcodec/atrac.c
+++ b/libavcodec/atrac.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
*/
diff --git a/libavcodec/atrac.h b/libavcodec/atrac.h
index 39fb331..8607b01 100644
--- a/libavcodec/atrac.h
+++ b/libavcodec/atrac.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/atrac1.c b/libavcodec/atrac1.c
index c829898..7c1d1eb 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 7d5dbeb..ebebe4b 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 bfc26fc..18957cb 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"
@@ -123,7 +124,7 @@ static float gain_tab1[16];
static float gain_tab2[31];
-/*
+/**
* Regular 512 points IMDCT without overlapping, with the exception of the
* swapping of odd bands caused by the reverse spectra of the QMF.
*
@@ -205,7 +206,7 @@ static av_cold int atrac3_decode_close(AVCodecContext *avctx)
return 0;
}
-/*
+/**
* Mantissa decoding
*
* @param selector which table the output values are coded with
@@ -267,7 +268,7 @@ static void read_quant_spectral_coeffs(GetBitContext *gb, int selector,
}
}
-/*
+/**
* Restore the quantized band spectrum coefficients
*
* @return subband count, fix for broken specification/files
@@ -324,7 +325,7 @@ static int decode_spectrum(GetBitContext *gb, float *output)
return num_subbands;
}
-/*
+/**
* Restore the quantized tonal components
*
* @param components tonal components
@@ -408,7 +409,7 @@ static int decode_tonal_components(GetBitContext *gb,
return component_count;
}
-/*
+/**
* Decode gain parameters for the coded bands
*
* @param block the gainblock for the current band
@@ -443,7 +444,7 @@ static int decode_gain_control(GetBitContext *gb, GainBlock *block,
return 0;
}
-/*
+/**
* Apply gain parameters and perform the MDCT overlapping part
*
* @param input input buffer
@@ -500,7 +501,7 @@ static void gain_compensate_and_overlap(float *input, float *prev,
memcpy(prev, &input[256], 256 * sizeof(*prev));
}
-/*
+/**
* Combine the tonal band spectrum and regular band spectrum
*
* @param spectrum output spectrum buffer
@@ -586,7 +587,7 @@ static void reverse_matrixing(float *su1, float *su2, int *prev_code,
}
break;
default:
- assert(0);
+ av_assert1(0);
}
}
}
@@ -627,7 +628,7 @@ static void channel_weighting(float *su1, float *su2, int *p3)
}
}
-/*
+/**
* Decode a Sound Unit
*
* @param snd the channel unit to be used
@@ -742,7 +743,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 * 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],
@@ -816,10 +817,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) {
@@ -840,7 +839,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;
@@ -859,14 +858,15 @@ static av_cold void atrac3_init_static_data(AVCodec *codec)
/* Generate gain tables */
for (i = 0; i < 16; i++)
- gain_tab1[i] = powf(2.0, (4 - i));
+ gain_tab1[i] = exp2f (4 - i);
for (i = -15; i < 16; i++)
- gain_tab2[i + 15] = powf(2.0, i * -0.125);
+ gain_tab2[i + 15] = exp2f (i * -0.125);
}
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;
@@ -877,6 +877,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 */
@@ -905,7 +909,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);
@@ -919,6 +923,11 @@ static av_cold int atrac3_decode_init(AVCodecContext *avctx)
return AVERROR(EINVAL);
}
+ if (q->coding_mode == JOINT_STEREO && avctx->channels < 2) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid coding mode\n");
+ return AVERROR_INVALIDDATA;
+ }
+
/* Check the extradata */
if (version != 4) {
@@ -998,7 +1007,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 40518ab..9963d4e 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..7e98afe 100644
--- a/libavcodec/audio_frame_queue.h
+++ b/libavcodec/audio_frame_queue.h
@@ -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
index 3714de7..5d8a348 100644
--- a/libavcodec/audioconvert.c
+++ b/libavcodec/audioconvert.c
@@ -2,20 +2,20 @@
* audio conversion
* 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/libavcodec/audioconvert.h b/libavcodec/audioconvert.h
index 7d76fd6..61124b3 100644
--- a/libavcodec/audioconvert.h
+++ b/libavcodec/audioconvert.h
@@ -3,20 +3,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
*/
diff --git a/libavcodec/aura.c b/libavcodec/aura.c
index b51aede..34d46ae 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 968f9e5..8f6a722 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
*/
@@ -31,6 +31,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"
@@ -89,7 +90,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.
@@ -267,6 +269,30 @@ enum AVCodecID {
AV_CODEC_ID_CLLC,
AV_CODEC_ID_MSS2,
AV_CODEC_ID_VP9,
+ 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'),
/* various PCM "codecs" */
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
@@ -298,6 +324,9 @@ enum AVCodecID {
AV_CODEC_ID_PCM_LXF,
AV_CODEC_ID_S302M,
AV_CODEC_ID_PCM_S8_PLANAR,
+ 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,
@@ -330,6 +359,11 @@ 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',' '),
/* AMR */
AV_CODEC_ID_AMR_NB = 0x12000,
@@ -407,9 +441,17 @@ 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_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.
@@ -422,10 +464,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
@@ -434,6 +496,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
};
/**
@@ -475,6 +541,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
@@ -484,7 +560,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
@@ -508,6 +584,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
};
/**
@@ -555,6 +632,7 @@ enum AVColorSpace{
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,
@@ -645,9 +723,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)
@@ -720,10 +800,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.
*/
@@ -744,6 +826,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
@@ -867,6 +957,52 @@ 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,
};
/**
@@ -877,7 +1013,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.
*
@@ -993,6 +1129,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 {
@@ -1128,6 +1266,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.
@@ -1162,7 +1305,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
@@ -1182,7 +1325,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
*/
@@ -1191,7 +1334,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
*/
@@ -1398,6 +1541,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
@@ -1710,7 +1855,7 @@ typedef struct AVCodecContext {
/** Field order
* - encoding: set by libavcodec
- * - decoding: Set by libavcodec
+ * - decoding: Set by user.
*/
enum AVFieldOrder field_order;
@@ -1774,7 +1919,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;
@@ -1793,9 +1938,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;
@@ -2174,9 +2320,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;
@@ -2323,6 +2469,11 @@ typedef struct AVCodecContext {
#define AV_EF_BUFFER (1<<2)
#define AV_EF_EXPLODE (1<<3)
+#define AV_EF_CAREFUL (1<<16)
+#define AV_EF_COMPLIANT (1<<17)
+#define AV_EF_AGGRESSIVE (1<<18)
+
+
/**
* opaque 64bit number (generally a PTS) that will be reordered and
* output in AVFrame.reordered_opaque
@@ -2343,8 +2494,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
@@ -2413,10 +2564,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
/**
@@ -2594,21 +2745,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.
*/
@@ -2648,8 +2799,75 @@ 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.
+ * - decodimg 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
+
} 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);
+
/**
* AVProfile.
*/
@@ -2690,7 +2908,7 @@ typedef struct AVCodec {
const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0
const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1
const uint64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0
- 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
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}
@@ -2867,9 +3085,6 @@ typedef struct AVPicture {
* @}
*/
-#define AVPALETTE_SIZE 1024
-#define AVPALETTE_COUNT 256
-
enum AVSubtitleType {
SUBTITLE_NONE,
@@ -2908,10 +3123,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;
@@ -2968,6 +3184,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
@@ -3005,6 +3255,22 @@ 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
@@ -3045,6 +3311,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().
@@ -3177,6 +3477,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
@@ -3216,6 +3530,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);
+
+
/**
* @}
*/
@@ -3286,6 +3605,66 @@ void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height);
void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
int linesize_align[AV_NUM_DATA_POINTERS]);
+#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.
*
@@ -3326,7 +3705,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.
@@ -3377,7 +3756,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.
@@ -3442,6 +3821,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];
@@ -3596,7 +3976,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,
@@ -3630,6 +4010,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.
*
@@ -3643,11 +4053,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
@@ -3671,6 +4082,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.
*
@@ -3716,6 +4147,103 @@ 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
* @{
@@ -3744,42 +4272,19 @@ 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.
- *
- * To allocate the buffer and fill in the AVPicture fields in one call,
- * use avpicture_alloc().
+ * Fill in the AVPicture fields, always assume a linesize alignment of
+ * 1.
*
- * @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
+ * @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()
+ * Copy pixel data from an AVPicture into a buffer, always assume a
+ * linesize alignment of 1.
*
- * @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 width, int height,
@@ -3788,14 +4293,9 @@ int avpicture_layout(const AVPicture* src, enum AVPixelFormat pix_fmt,
/**
* 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().
+ * Always assume a linesize alignment of 1.
*
- * @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).
+ * @see av_image_get_buffer_size().
*/
int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height);
@@ -3810,7 +4310,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);
@@ -3848,10 +4348,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
@@ -3882,7 +4393,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);
@@ -3892,7 +4404,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.
@@ -3904,9 +4416,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_fmt_of_list(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_FORK_ABI
enum AVPixelFormat avcodec_find_best_pix_fmt2(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);
@@ -3941,7 +4497,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.
*
@@ -3954,7 +4515,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,
@@ -3974,6 +4537,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.
@@ -4047,15 +4618,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 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
@@ -4067,7 +4644,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
@@ -4083,7 +4660,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
@@ -4123,7 +4700,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.
@@ -4138,6 +4715,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..26b3d4b 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
*/
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 df88f3f..198365e 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
*/
@@ -25,6 +25,17 @@
#include "libavutil/common.h"
#include "libavutil/mem.h"
#include "avcodec.h"
+#include "bytestream.h"
+#include "internal.h"
+
+void ff_packet_free_side_data(AVPacket *pkt)
+{
+ int i;
+ for (i = 0; i < pkt->side_data_elems; i++)
+ av_free(pkt->side_data[i].data);
+ av_freep(&pkt->side_data);
+ pkt->side_data_elems = 0;
+}
#if FF_API_DESTRUCT_PACKET
void av_destruct_packet(AVPacket *pkt)
@@ -168,6 +179,57 @@ do { \
dst = data; \
} while (0)
+/* Makes duplicates of data, side_data, but does not copy any other fields */
+static int copy_packet_data(AVPacket *pkt, AVPacket *src, int dup)
+{
+ 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
+ pkt->destruct = dummy_destruct_packet;
+#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;
+
+failed_alloc:
+ av_destruct_packet(pkt);
+ return AVERROR(ENOMEM);
+}
+
+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);
+ memset(pkt->side_data, 0,
+ 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;
+
+failed_alloc:
+ av_destruct_packet(pkt);
+ return AVERROR(ENOMEM);
+}
+
int av_dup_packet(AVPacket *pkt)
{
AVPacket tmp_pkt;
@@ -178,34 +240,15 @@ int av_dup_packet(AVPacket *pkt)
#endif
) {
tmp_pkt = *pkt;
-
- pkt->data = NULL;
- pkt->side_data = NULL;
- DUP_DATA(pkt->data, tmp_pkt.data, pkt->size, 1, ALLOC_BUF);
-#if FF_API_DESTRUCT_PACKET
- pkt->destruct = dummy_destruct_packet;
-#endif
-
- if (pkt->side_data_elems) {
- int i;
-
- DUP_DATA(pkt->side_data, tmp_pkt.side_data,
- pkt->side_data_elems * sizeof(*pkt->side_data), 0, ALLOC_MALLOC);
- 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;
- }
- }
+ return copy_packet_data(pkt, &tmp_pkt, 1);
}
return 0;
+}
-failed_alloc:
- av_free_packet(pkt);
- return AVERROR(ENOMEM);
+int av_copy_packet(AVPacket *dst, AVPacket *src)
+{
+ *dst = *src;
+ return copy_packet_data(dst, src, 0);
}
void av_free_packet(AVPacket *pkt)
@@ -270,6 +313,88 @@ 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
+ pkt->destruct = dummy_destruct_packet;
+#endif
+ pkt->size = size - FF_INPUT_BUFFER_PADDING_SIZE;
+ bytestream_put_buffer(&p, old.data, old.size);
+ for (i=old.side_data_elems-1; i>=0; i--) {
+ bytestream_put_buffer(&p, old.side_data[i].data, old.side_data[i].size);
+ bytestream_put_be32(&p, old.side_data[i].size);
+ *p++ = old.side_data[i].type | ((i==old.side_data_elems-1)*128);
+ }
+ bytestream_put_be64(&p, FF_MERGE_MARKER);
+ av_assert0(p-pkt->data == pkt->size);
+ memset(p, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ av_free_packet(&old);
+ pkt->side_data_elems = 0;
+ pkt->side_data = NULL;
+ return 1;
+ }
+ return 0;
+}
+
+int av_packet_split_side_data(AVPacket *pkt){
+ if (!pkt->side_data_elems && pkt->size >12 && AV_RB64(pkt->data + pkt->size - 8) == FF_MERGE_MARKER){
+ int i;
+ unsigned int size;
+ uint8_t *p;
+
+ p = pkt->data + pkt->size - 8 - 5;
+ for (i=1; ; i++){
+ size = AV_RB32(p);
+ if (size>INT_MAX || p - pkt->data < size)
+ return 0;
+ if (p[4]&128)
+ break;
+ p-= size+5;
+ }
+
+ pkt->side_data = av_malloc(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_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
+ pkt->side_data[i].size = size;
+ pkt->side_data[i].type = p[4]&127;
+ if (!pkt->side_data[i].data)
+ return AVERROR(ENOMEM);
+ memcpy(pkt->side_data[i].data, p-size, size);
+ pkt->size -= size + 5;
+ if(p[4]&128)
+ break;
+ p-= size+5;
+ }
+ pkt->size -= 8;
+ pkt->side_data_elems = i+1;
+ return 1;
+ }
+ return 0;
+}
+
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..40aca17
--- /dev/null
+++ b/libavcodec/avrndec.c
@@ -0,0 +1,132 @@
+/*
+ * 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",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_AVRN,
+ .priv_data_size = sizeof(AVRnContext),
+ .init = init,
+ .close = end,
+ .decode = decode_frame,
+ .long_name = NULL_IF_CONFIG_SMALL("Avid AVI Codec"),
+ .capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
+};
+
diff --git a/libavcodec/avs.c b/libavcodec/avs.c
index da27e00..e3733d7 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..a574f5b
--- /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",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_AVUI,
+ .init = avui_decode_init,
+ .decode = avui_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("Avid Meridien Uncompressed"),
+};
diff --git a/libavcodec/avuienc.c b/libavcodec/avuienc.c
new file mode 100644
index 0000000..a4970a0
--- /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",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("Avid Meridien Uncompressed"),
+};
diff --git a/libavcodec/bethsoftvideo.c b/libavcodec/bethsoftvideo.c
index b113bc4..474265f 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 10544c5..9cfcd14 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)
@@ -57,10 +58,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 +75,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..40e7d15 100644
--- a/libavcodec/bgmc.c
+++ b/libavcodec/bgmc.c
@@ -2,20 +2,20 @@
* Block Gilbert-Moore decoder
* Copyright (c) 2010 Thilo Borgmann <thilo.borgmann _at_ 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
*/
@@ -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..9e386fd 100644
--- a/libavcodec/bgmc.h
+++ b/libavcodec/bgmc.h
@@ -2,20 +2,20 @@
* Block Gilbert-Moore decoder
* Copyright (c) 2010 Thilo Borgmann <thilo.borgmann _at_ 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
*/
diff --git a/libavcodec/bink.c b/libavcodec/bink.c
index 7ec0cab..ce8dcb0 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
*/
@@ -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,6 +683,10 @@ 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;
+ }
}
quant = quant_matrices[quant_idx];
@@ -863,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:
@@ -896,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:
@@ -1133,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);
@@ -1174,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;
}
@@ -1231,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));
}
}
}
@@ -1311,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 1e34ab9..ef5569a 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
*/
@@ -83,14 +83,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
@@ -318,10 +318,8 @@ static int decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = s->frame_len;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
if (decode_block(s, (float **)frame->extended_data,
avctx->codec->id == AV_CODEC_ID_BINKAUDIO_DCT)) {
diff --git a/libavcodec/binkdata.h b/libavcodec/binkdata.h
index 60f0a59..b9dc1f2 100644
--- a/libavcodec/binkdata.h
+++ b/libavcodec/binkdata.h
@@ -2,20 +2,20 @@
* Bink video decoder
* Copyright (C) 2009 Kostya Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/binkdsp.c b/libavcodec/binkdsp.c
index a73c148..2a9ef3d 100644
--- a/libavcodec/binkdsp.c
+++ b/libavcodec/binkdsp.c
@@ -2,20 +2,20 @@
* Bink DSP routines
* Copyright (c) 2009 Kostya Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/bintext.c b/libavcodec/bintext.c
new file mode 100644
index 0000000..f8059aa
--- /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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("Binary text"),
+};
+#endif
+#if CONFIG_XBIN_DECODER
+AVCodec ff_xbin_decoder = {
+ .name = "xbin",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("eXtended BINary text"),
+};
+#endif
+#if CONFIG_IDF_DECODER
+AVCodec ff_idf_decoder = {
+ .name = "idf",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("iCEDraw text"),
+};
+#endif
diff --git a/libavcodec/bintext.h b/libavcodec/bintext.h
new file mode 100644
index 0000000..ea834a0
--- /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 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..1a6d007 100644
--- a/libavcodec/bit_depth_template.c
+++ b/libavcodec/bit_depth_template.c
@@ -17,6 +17,7 @@
*/
#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 2c8692a..7e297b9 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,7 @@
* bitstream api.
*/
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "mathops.h"
#include "get_bits.h"
@@ -106,8 +107,8 @@ static int alloc_table(VLC *vlc, int size, int use_static)
if(use_static)
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 -1;
}
@@ -158,6 +159,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)
@@ -267,11 +270,24 @@ int ff_init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes,
vlc->bits = nb_bits;
if(flags & INIT_VLC_USE_NEW_STATIC){
- if(vlc->table_size && vlc->table_size == vlc->table_allocated){
+ VLC dyn_vlc = *vlc;
+
+ if (vlc->table_size)
return 0;
- }else if(vlc->table_size){
- abort(); // fatal error, we are called on a partially initialized table
- }
+
+ ret = ff_init_vlc_sparse(&dyn_vlc, nb_bits, nb_codes,
+ bits, bits_wrap, bits_size,
+ codes, codes_wrap, codes_size,
+ symbols, symbols_wrap, symbols_size,
+ flags & ~INIT_VLC_USE_NEW_STATIC);
+ av_assert0(ret >= 0);
+ av_assert0(dyn_vlc.table_size <= vlc->table_allocated);
+ if(dyn_vlc.table_size < vlc->table_allocated)
+ av_log(NULL, AV_LOG_ERROR, "needed %d had %d\n", dyn_vlc.table_size, vlc->table_allocated);
+ memcpy(vlc->table, dyn_vlc.table, dyn_vlc.table_size * sizeof(*vlc->table));
+ vlc->table_size = dyn_vlc.table_size;
+ ff_free_vlc(&dyn_vlc);
+ return 0;
}else {
vlc->table = NULL;
vlc->table_allocated = 0;
@@ -282,14 +298,24 @@ int ff_init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes,
buf = av_malloc((nb_codes+1)*sizeof(VLCcode));
- assert(symbols_size <= 2 || !symbols);
+ av_assert0(symbols_size <= 2 || !symbols);
j = 0;
#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 in init_vlc\n");\
+ 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");\
+ av_free(buf);\
+ return -1;\
+ }\
if (flags & INIT_VLC_LE)\
buf[j].code = bitswap_32(buf[j].code);\
else\
@@ -313,8 +339,6 @@ int ff_init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes,
av_freep(&vlc->table);
return -1;
}
- 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 b2d61da..328a9f6 100644
--- a/libavcodec/bitstream_filter.c
+++ b/libavcodec/bitstream_filter.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
*/
diff --git a/libavcodec/bmp.c b/libavcodec/bmp.c
index 899fc8a..a3bb1a7 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,11 +243,15 @@ 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 doesnt 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;
}
@@ -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
--- /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 d27282d..ee23a0c 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;
@@ -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.
@@ -163,12 +163,11 @@ AVCodec ff_bmp_encoder = {
.name = "bmp",
.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 941051b..0f3f9f3 100644
--- a/libavcodec/bmv.c
+++ b/libavcodec/bmv.c
@@ -19,6 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "avcodec.h"
#include "bytestream.h"
@@ -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..b30b882
--- /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",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_BRENDER_PIX,
+ .decode = brpix_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("BRender PIX image"),
+};
diff --git a/libavcodec/bytestream.h b/libavcodec/bytestream.h
index 0f89558..af7f75b 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
*/
@@ -190,6 +190,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 b534669..c51f2fa 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
*/
@@ -129,10 +129,8 @@ static int decode_frame(AVCodecContext *avctx, void *data,
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 +168,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 +235,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 6ba9303..187b7dc 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
*/
@@ -73,7 +73,8 @@ static const uint8_t lps_range[64][4]= {
{ 6, 8, 9, 11}, { 6, 7, 9, 10}, { 6, 7, 8, 9}, { 2, 2, 2, 2},
};
-static uint8_t h264_mps_state[2 * 64];
+static uint8_t h264_lps_state[2*64];
+static uint8_t h264_mps_state[2*64];
static const uint8_t mps_state[64]= {
1, 2, 3, 4, 5, 6, 7, 8,
@@ -152,10 +153,14 @@ void ff_init_cabac_states(void)
h264_mps_state[2 * i + 1] = 2 * mps_state[i] + 1;
if( i ){
+ h264_lps_state[2*i+0]=
ff_h264_mlps_state[128-2*i-1]= 2*lps_state[i]+0;
+ h264_lps_state[2*i+1]=
ff_h264_mlps_state[128-2*i-2]= 2*lps_state[i]+1;
}else{
+ h264_lps_state[2*i+0]=
ff_h264_mlps_state[128-2*i-1]= 1;
+ h264_lps_state[2*i+1]=
ff_h264_mlps_state[128-2*i-2]= 0;
}
}
@@ -163,3 +168,152 @@ void ff_init_cabac_states(void)
ff_h264_last_coeff_flag_offset_8x8[i] = last_coeff_flag_offset_8x8[i];
}
}
+
+#ifdef TEST
+#define SIZE 10240
+
+#include "libavutil/lfg.h"
+#include "avcodec.h"
+#include "cabac.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 = h264_mps_state[*state];
+ }else{
+ c->low += c->range - RangeLPS;
+ c->range = RangeLPS;
+ *state= h264_lps_state[*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 484ba85..ee70fcf 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){
diff --git a/libavcodec/cavs.c b/libavcodec/cavs.c
index 47eaa0b..12af0c9 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
*/
@@ -673,7 +673,7 @@ int ff_cavs_next_mb(AVSContext *h) {
*
****************************************************************************/
-void ff_cavs_init_pic(AVSContext *h) {
+int ff_cavs_init_pic(AVSContext *h) {
int i;
/* clear some predictors */
@@ -693,6 +693,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 d33ff0a..b0cdb8f 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 c2c6772..ec4a819 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;
+ int i, esc_code, level, mask;
+ 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) {
+ if (cbp > 63U) {
av_log(h->avctx, AV_LOG_ERROR, "illegal inter cbp\n");
return -1;
}
@@ -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) {
+ if (cbp_code > 63U) {
av_log(h->avctx, AV_LOG_ERROR, "illegal intra cbp\n");
return -1;
}
@@ -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;
av_frame_unref(h->cur.f);
@@ -959,8 +976,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);
@@ -969,7 +988,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 */
@@ -1085,6 +1105,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;
@@ -1154,6 +1178,8 @@ static int cavs_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
*got_frame = 0;
if (!h->got_keyframe)
break;
+ if(!h->top_qp)
+ break;
init_get_bits(&h->gb, buf_ptr, input_size);
h->stc = stc;
if (decode_pic(h))
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 01963a3..a9d34dc 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
*/
diff --git a/libavcodec/cdgraphics.c b/libavcodec/cdgraphics.c
index 8be1460..d292317 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 ea52a0c..468b294 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) {
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..eaefaaa 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
*/
diff --git a/libavcodec/cinepak.c b/libavcodec/cinepak.c
index dff1b53..f5bc113 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 7e189cd..2120864 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 class = {
+ .class_name = "cljr encoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_cljr_encoder = {
.name = "cljr",
.type = AVMEDIA_TYPE_VIDEO,
@@ -160,5 +185,6 @@ AVCodec ff_cljr_encoder = {
.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV411P,
AV_PIX_FMT_NONE },
.long_name = NULL_IF_CONFIG_SMALL("Cirrus Logic AccuPak"),
+ .priv_class = &class,
};
#endif
diff --git a/libavcodec/cllc.c b/libavcodec/cllc.c
index a6b51b3..6378c79 100644
--- a/libavcodec/cllc.c
+++ b/libavcodec/cllc.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2012 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
*/
@@ -329,11 +329,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)
@@ -344,11 +341,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 a9b3ba0..675f77d 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 a553a3f..4ab3019 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 fe2cbab..b4fdd94 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,
},
{
@@ -419,6 +422,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 +749,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 +929,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,
},
{
@@ -926,7 +944,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.type = AVMEDIA_TYPE_VIDEO,
.name = "dpx",
.long_name = NULL_IF_CONFIG_SMALL("DPX 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_MAD,
@@ -1020,6 +1038,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.props = AV_CODEC_PROP_LOSSY,
},
{
+ .id = AV_CODEC_ID_WEBP,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "webp",
+ .long_name = NULL_IF_CONFIG_SMALL("WebP"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
.id = AV_CODEC_ID_PICTOR,
.type = AVMEDIA_TYPE_VIDEO,
.name = "pictor",
@@ -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,
},
{
@@ -1207,6 +1247,130 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("MS Windows Media Video V9 Screen"),
.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",
+ .long_name = NULL_IF_CONFIG_SMALL("Escape 130"),
+ .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_G2M,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "g2m",
+ .long_name = NULL_IF_CONFIG_SMALL("GoToMeeting"),
+ },
+ {
+ .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,
+ },
/* various PCM "codecs" */
{
@@ -1255,13 +1419,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,
@@ -1334,10 +1500,31 @@ 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,
+ },
+ {
+ .id = AV_CODEC_ID_PCM_S24LE_PLANAR,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "pcm_s24le_planar",
+ .long_name = NULL_IF_CONFIG_SMALL("PCM signed 24-bit little-endian planar"),
+ .props = AV_CODEC_PROP_LOSSLESS,
+ },
+ {
+ .id = AV_CODEC_ID_PCM_S32LE_PLANAR,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "pcm_s32le_planar",
+ .long_name = NULL_IF_CONFIG_SMALL("PCM signed 32-bit little-endian planar"),
.props = AV_CODEC_PROP_LOSSLESS,
},
{
@@ -1615,6 +1802,34 @@ 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,
+ },
/* AMR */
{
@@ -2106,6 +2321,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",
@@ -2126,6 +2373,20 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("TAK (Tom's lossless Audio Kompressor)"),
.props = AV_CODEC_PROP_LOSSLESS,
},
+ {
+ .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 */
{
@@ -2133,42 +2394,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,
@@ -2180,8 +2455,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 90d78eb..08cd401 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
*/
@@ -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/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 8a90857..313a1d2 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
*/
@@ -56,7 +56,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..4f83503
--- /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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("CPiA video format"),
+};
diff --git a/libavcodec/crystalhd.c b/libavcodec/crystalhd.c
new file mode 100644
index 0000000..5dee825
--- /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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (CrystalHD acceleration)"),
+ .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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 Video (CrystalHD acceleration)"),
+ .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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 Part 2 (CrystalHD acceleration)"),
+ .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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 Part 2 Microsoft variant version 3 (CrystalHD acceleration)"),
+ .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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("SMPTE VC-1 (CrystalHD acceleration)"),
+ .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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 9 (CrystalHD acceleration)"),
+ .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 6b8d144..0a5fa69 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 9011bc2..3a30138 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 4a3d812..c104268 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,10 +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;
- break;
- } else if (!pc1->lastmarker) {
+ if (!pc1->lastmarker || state == pc1->lastmarker || pc1->lastmarker == DCA_HD_MARKER) {
start_found = 1;
pc1->lastmarker = state;
break;
@@ -75,10 +72,11 @@ 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;
- if(!pc1->framesize){
+ // We have to check that we really read a full frame here, and that it isn't a pure HD frame, because their size is not constant.
+ if(!pc1->framesize && state == pc1->lastmarker && state != DCA_HD_MARKER){
pc1->framesize = pc1->hd_pos ? pc1->hd_pos : pc1->size;
}
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 0f73375..384a192 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);
@@ -580,6 +735,12 @@ static int dca_parse_frame_header(DCAContext *s)
s->lfe = get_bits(&s->gb, 2);
s->predictor_history = get_bits(&s->gb, 1);
+ if (s->lfe == 3) {
+ s->lfe = 0;
+ avpriv_request_sample(s->avctx, "LFE = 3");
+ return AVERROR_PATCHWELCOME;
+ }
+
/* TODO: check CRC */
if (s->crc_present)
s->header_crc = get_bits(&s->gb, 16);
@@ -638,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);
}
@@ -807,7 +968,7 @@ static int dca_subframe_header(DCAContext *s, int base_channel, int block_index)
"Invalid channel mode %d\n", am);
return AVERROR_INVALIDDATA;
}
- for (j = base_channel; j < s->prim_channels; j++) {
+ for (j = base_channel; j < FFMIN(s->prim_channels, FF_ARRAY_ELEMS(dca_default_coeffs[am])); j++) {
s->downmix_coef[j][0] = dca_default_coeffs[am][j][0];
s->downmix_coef[j][1] = dca_default_coeffs[am][j][1];
}
@@ -835,6 +996,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]);
@@ -846,8 +1008,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;
@@ -1048,7 +1214,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;
@@ -1293,7 +1459,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 */
}
@@ -1418,11 +1584,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)
@@ -1562,26 +1728,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);
@@ -1634,7 +2020,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))
@@ -1643,6 +2029,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);
+ }
+ }
}
/**
@@ -1655,15 +2068,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;
@@ -1704,7 +2127,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 */
@@ -1741,8 +2164,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))) {
@@ -1758,6 +2186,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: {
@@ -1797,49 +2226,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 */
@@ -1883,6 +2399,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 8b2dd42..249aff2 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 3c6f1f9..bb157f7 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..439be47
--- /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",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("DCA (DTS Coherent Acoustics)"),
+ .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
--- /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 0f7f5c3..3647336 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;
};
@@ -99,6 +99,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 },
@@ -110,6 +127,9 @@ static const struct algo idct_tab[] = {
{ "XVID-MMX", ff_idct_xvid_mmx, NO_PERM, AV_CPU_FLAG_MMX, 1 },
{ "XVID-MMXEXT", ff_idct_xvid_mmxext, NO_PERM, AV_CPU_FLAG_MMXEXT, 1 },
{ "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
@@ -170,7 +190,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;
@@ -179,7 +199,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++)
@@ -188,11 +208,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;
}
@@ -214,13 +236,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;
@@ -230,6 +255,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;
@@ -240,7 +266,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);
@@ -286,7 +312,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);
@@ -298,7 +324,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();
@@ -308,10 +335,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);
@@ -436,6 +463,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);
@@ -450,10 +496,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);
@@ -461,10 +507,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");
@@ -481,6 +528,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();
@@ -510,8 +558,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);
@@ -519,7 +568,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/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 2828af6..bba7626 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
--- /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
--- /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..a2848f0
--- /dev/null
+++ b/libavcodec/dirac_dwt.c
@@ -0,0 +1,585 @@
+/*
+ * 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);
+ }
+}
+
+int ff_spatial_idwt2(IDWTELEM *buffer, int width, int height, int stride,
+ enum dwt_type type, int decomposition_count, IDWTELEM *temp)
+{
+ DWTContext d;
+ int y;
+
+ if (ff_spatial_idwt_init2(&d, buffer, width, height, stride, type, decomposition_count, temp))
+ return -1;
+
+ for (y = 0; y < d.height; y += 4)
+ ff_spatial_idwt_slice2(&d, y);
+
+ return 0;
+}
diff --git a/libavcodec/dirac_dwt.h b/libavcodec/dirac_dwt.h
new file mode 100644
index 0000000..9514e95
--- /dev/null
+++ b/libavcodec/dirac_dwt.h
@@ -0,0 +1,126 @@
+/*
+ * 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);
+
+int ff_spatial_idwt2(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..81d2b65
--- /dev/null
+++ b/libavcodec/diracdec.c
@@ -0,0 +1,1938 @@
+/*
+ * 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;
+ int 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_bits(&gb, b->coeff_data, b->length*8);
+
+ 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], 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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("BBC Dirac VC-2"),
+};
diff --git a/libavcodec/diracdsp.c b/libavcodec/diracdsp.c
new file mode 100644
index 0000000..429241d
--- /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
--- /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 0a8bc59..e96369b 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)
@@ -391,6 +419,6 @@ 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,
.long_name = NULL_IF_CONFIG_SMALL("VC3/DNxHD"),
};
diff --git a/libavcodec/dnxhdenc.c b/libavcodec/dnxhdenc.c
index c834ec3..3b11183 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
*/
@@ -33,6 +33,7 @@
#include "internal.h"
#include "mpegvideo.h"
#include "dnxhdenc.h"
+#include "internal.h"
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
#define DNX10BIT_QMAT_SHIFT 18 // The largest value that will not lead to overflow for 10bit samples.
@@ -41,11 +42,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 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 +69,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 +138,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 +152,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 +161,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 +224,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 +267,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 +283,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;
@@ -497,15 +520,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 +551,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 +597,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 +847,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 +947,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 +978,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 +1031,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",
.type = AVMEDIA_TYPE_VIDEO,
@@ -1032,4 +1050,5 @@ AVCodec ff_dnxhd_encoder = {
AV_PIX_FMT_NONE },
.long_name = NULL_IF_CONFIG_SMALL("VC3/DNxHD"),
.priv_class = &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 88b7bd8..402b0f9 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 c1e8304..2fd5bdc 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
*/
@@ -37,12 +37,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 +58,17 @@ 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;
- 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 +98,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,10 +112,18 @@ static int decode_frame(AVCodecContext *avctx,
buf += 3;
avctx->bits_per_raw_sample =
bits_per_color = buf[0];
+ buf++;
+ packing = *((uint16_t*)buf);
- buf += 825;
+ buf += 824;
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
@@ -124,83 +144,112 @@ static int decode_frame(AVCodecContext *avctx,
} else {
avctx->pix_fmt = AV_PIX_FMT_RGB24;
}
- source_packet_size = elements;
- target_packet_size = elements;
+ total_size = avctx->width * avctx->height * elements;
break;
case 10:
- avctx->pix_fmt = AV_PIX_FMT_RGB48;
- target_packet_size = 6;
- source_packet_size = 4;
+ if (!packing) {
+ av_log(avctx, AV_LOG_ERROR, "Packing to 32bit required\n");
+ return -1;
+ }
+ avctx->pix_fmt = AV_PIX_FMT_GBRP10;
+ 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;
+ }
+ if (endian) {
+ avctx->pix_fmt = AV_PIX_FMT_GBRP12BE;
+ } else {
+ avctx->pix_fmt = AV_PIX_FMT_GBRP12LE;
+ }
+ total_size = 2 * avctx->width * avctx->height * elements;
+ break;
case 16:
if (endian) {
- avctx->pix_fmt = AV_PIX_FMT_RGB48BE;
+ avctx->pix_fmt = elements == 4 ? AV_PIX_FMT_RGBA64BE : AV_PIX_FMT_RGB48BE;
} else {
- avctx->pix_fmt = AV_PIX_FMT_RGB48LE;
+ avctx->pix_fmt = elements == 4 ? AV_PIX_FMT_RGBA64LE : AV_PIX_FMT_RGB48LE;
}
- target_packet_size = 6;
- source_packet_size = elements * 2;
+ total_size = 2 * avctx->width * avctx->height * elements;
break;
default:
av_log(avctx, AV_LOG_ERROR, "Unsupported color depth : %d\n", bits_per_color);
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");
+ 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] = *((uint16_t*)buf);
+ *dst[2] = (*dst[2] >> 4) | (*dst[2] << 12);
+ dst[2]++;
+ buf += 2;
+ *dst[0] = *((uint16_t*)buf);
+ *dst[0] = (*dst[0] >> 4) | (*dst[0] << 12);
+ dst[0]++;
+ buf += 2;
+ *dst[1] = *((uint16_t*)buf);
+ *dst[1] = (*dst[1] >> 4) | (*dst[1] << 12);
+ dst[1]++;
+ buf += 2;
+ // 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:
+ for (x = 0; x < avctx->height; x++) {
+ memcpy(ptr[0], buf, elements*avctx->width);
+ ptr[0] += p->linesize[0];
+ buf += elements*avctx->width;
+ }
+ break;
}
*got_frame = 1;
diff --git a/libavcodec/dpxenc.c b/libavcodec/dpxenc.c
index d263161..0a4662d 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,36 @@
#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_GBRP10BE:
+ case AV_PIX_FMT_GBRP10LE:
+ case AV_PIX_FMT_GBRP12BE:
+ case AV_PIX_FMT_GBRP12LE:
case AV_PIX_FMT_RGB24:
- break;
+ 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 +77,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 +86,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 +102,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 +167,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 +192,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 +210,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);
@@ -185,6 +245,12 @@ AVCodec ff_dpx_encoder = {
AV_PIX_FMT_RGBA,
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},
.long_name = NULL_IF_CONFIG_SMALL("DPX image"),
};
diff --git a/libavcodec/dsicinav.c b/libavcodec/dsicinav.c
index 959a82f..f0e8f02 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;
}
@@ -179,24 +198,29 @@ static int cin_decode_lzss(const unsigned char *src, int src_size, unsigned char
return 0;
}
-static void cin_decode_rle(const unsigned char *src, int src_size, unsigned char *dst, int dst_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) {
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, FFMIN(len, dst_end - dst));
src += len;
}
dst += len;
}
+ return 0;
}
static int cinvideo_decode_frame(AVCodecContext *avctx,
@@ -222,12 +246,12 @@ 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;
}
@@ -246,7 +270,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);
@@ -281,10 +305,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;
@@ -306,12 +328,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;
}
@@ -341,10 +361,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 3c7579d..b434589 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");
}
@@ -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)){
@@ -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,28 @@ 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->idct_algo==FF_IDCT_INT){
c->idct_put= jref_idct_put;
c->idct_add= jref_idct_add;
@@ -2575,6 +2737,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 +2852,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 +2903,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;
}
@@ -2756,3 +2926,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 3add4e8..4381caa 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_ppc(DSPContext* c, AVCodecContext *avctx);
void ff_dsputil_init_sh4(DSPContext* c, AVCodecContext *avctx);
void ff_dsputil_init_vis(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..94b7b42 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
*/
diff --git a/libavcodec/dv.c b/libavcodec/dv.c
index 5253b7f..39a87a9 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();
@@ -502,7 +513,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
@@ -510,13 +521,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;
@@ -607,7 +618,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]) {
@@ -617,11 +628,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];
@@ -808,6 +819,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 */
@@ -846,7 +858,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 */
@@ -953,10 +965,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..a1d9881 100644
--- a/libavcodec/dv_profile.c
+++ b/libavcodec/dv_profile.c
@@ -19,6 +19,7 @@
#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..97edce9 100644
--- a/libavcodec/dv_profile.h
+++ b/libavcodec/dv_profile.h
@@ -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 26d14bd..562db6a 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 b4aba49..955925a 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;
+
+ while (ctx->object_list) {
+ object = ctx->object_list;
+
+ ctx->object_list = object->next;
+
+ av_free(object);
+ }
+}
+
+static void delete_regions(DVBSubContext *ctx)
+{
+ DVBSubRegion *region;
- /* Should already be null */
- if (ctx->object_list)
- av_log(0, AV_LOG_ERROR, "Memory deallocation error!\n");
+ 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);
}
@@ -907,6 +940,7 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx,
const uint8_t *buf_end = buf + buf_size;
int i, clut_id;
+ int version;
DVBSubCLUT *clut;
int entry_id, depth , full_range;
int y, cr, cb, alpha;
@@ -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++;
@@ -980,6 +1020,7 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx,
if (depth & 0x20)
clut->clut256[entry_id] = RGBA(r,g,b,255 - alpha);
}
+ }
}
@@ -990,6 +1031,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 +1048,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 +1070,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 +1080,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 +1150,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 +1215,7 @@ static void dvbsub_parse_page_segment(AVCodecContext *avctx,
av_free(display);
}
+ }
}
@@ -1286,6 +1343,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 +1373,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 +1386,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 +1435,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 +1456,7 @@ static int dvbsub_decode(AVCodecContext *avctx,
int page_id;
int segment_length;
int i;
+ int got_segment = 0;
av_dlog(avctx, "DVB sub packet:\n");
@@ -1434,20 +1495,26 @@ 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);
+ 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 +1525,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
--- /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 cc9c232..48cbbfc 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));
@@ -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;
}
@@ -377,5 +377,6 @@ AVCodec ff_dvvideo_decoder = {
.close = dvvideo_close,
.decode = dvvideo_decode_frame,
.capabilities = CODEC_CAP_DR1 | CODEC_CAP_SLICE_THREADS,
+ .max_lowres = 3,
.long_name = NULL_IF_CONFIG_SMALL("DV (Digital Video)"),
};
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 eadde32..38af768 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,18 @@
#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];
} DVDSubContext;
static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *rgba, int num_values)
@@ -123,17 +129,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 +164,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);
@@ -179,14 +192,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;
@@ -339,9 +351,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 +360,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;
@@ -500,44 +516,88 @@ static int dvdsub_decode(AVCodecContext *avctx,
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);
- return 0;
+
+ 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;
}
+#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 class = {
+ .class_name = "dvdsubdec",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_dvdsub_decoder = {
.name = "dvdsub",
.type = AVMEDIA_TYPE_SUBTITLE,
@@ -546,4 +606,5 @@ AVCodec ff_dvdsub_decoder = {
.init = dvdsub_init,
.decode = dvdsub_decode,
.long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"),
+ .priv_class = &class,
};
diff --git a/libavcodec/dvdsubenc.c b/libavcodec/dvdsubenc.c
index 5e362b7..6e19623 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;
}
@@ -219,6 +436,8 @@ AVCodec ff_dvdsub_encoder = {
.name = "dvdsub",
.type = AVMEDIA_TYPE_SUBTITLE,
.id = AV_CODEC_ID_DVD_SUBTITLE,
+ .init = dvdsub_init,
.encode_sub = dvdsub_encode,
.long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"),
+ .priv_data_size = sizeof(DVDSubtitleContext),
};
diff --git a/libavcodec/dxa.c b/libavcodec/dxa.c
index 9e7f453..d30bfb2 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"
@@ -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,35 +203,27 @@ static int decode_13(AVCodecContext *avctx, DxaDecContext *c, uint8_t* dst,
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
{
AVFrame *frame = data;
- const uint8_t *buf = avpkt->data;
- int buf_size = avpkt->size;
DxaDecContext * const c = avctx->priv_data;
uint8_t *outptr, *srcptr, *tmpptr;
unsigned long dsize;
int i, j, compr, ret;
int stride;
- int orig_buf_size = buf_size;
int pc = 0;
+ GetByteContext gb;
- /* make the palette available on the way out */
- if(buf[0]=='C' && buf[1]=='M' && buf[2]=='A' && buf[3]=='P'){
- int r, g, b;
+ bytestream2_init(&gb, avpkt->data, avpkt->size);
- buf += 4;
+ /* make the palette available on the way out */
+ if (bytestream2_peek_le32(&gb) == MKTAG('C','M','A','P')) {
+ bytestream2_skip(&gb, 4);
for(i = 0; i < 256; i++){
- r = *buf++;
- g = *buf++;
- b = *buf++;
- c->pal[i] = (r << 16) | (g << 8) | b;
+ c->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&gb);
}
pc = 1;
- buf_size -= 768+4;
}
- if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
memcpy(frame->data[1], c->pal, AVPALETTE_SIZE);
frame->palette_has_changed = pc;
@@ -229,15 +232,19 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
tmpptr = c->prev.data[0];
stride = frame->linesize[0];
- if(buf[0]=='N' && buf[1]=='U' && buf[2]=='L' && buf[3]=='L')
+ if (bytestream2_get_le32(&gb) == MKTAG('N','U','L','L'))
compr = -1;
else
- compr = buf[4];
+ compr = bytestream2_get_byte(&gb);
dsize = c->dsize;
- if((compr != 4 && compr != -1) && uncompress(c->decomp_buf, &dsize, buf + 9, buf_size - 9) != Z_OK){
- av_log(avctx, AV_LOG_ERROR, "Uncompress failed!\n");
- return AVERROR_UNKNOWN;
+ if (compr != 4 && compr != -1) {
+ bytestream2_skip(&gb, 4);
+ if (uncompress(c->decomp_buf, &dsize, avpkt->data + bytestream2_tell(&gb),
+ bytestream2_get_bytes_left(&gb)) != Z_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Uncompress failed!\n");
+ return AVERROR_UNKNOWN;
+ }
}
switch(compr){
case -1:
@@ -258,7 +265,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
frame->key_frame = !(compr & 1);
frame->pict_type = (compr & 1) ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I;
for(j = 0; j < avctx->height; j++){
- if(compr & 1){
+ if((compr & 1) && tmpptr){
for(i = 0; i < avctx->width; i++)
outptr[i] = srcptr[i] ^ tmpptr[i];
tmpptr += stride;
@@ -272,10 +279,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
case 13:
frame->key_frame = 0;
frame->pict_type = AV_PICTURE_TYPE_P;
+ 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;
}
@@ -286,7 +297,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
*got_frame = 1;
/* always report that the buffer was completely consumed */
- return orig_buf_size;
+ return avpkt->size;
}
static av_cold int decode_init(AVCodecContext *avctx)
@@ -295,8 +306,11 @@ static av_cold int decode_init(AVCodecContext *avctx)
avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ avcodec_get_frame_defaults(&c->prev);
+
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_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
return AVERROR(ENOMEM);
}
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 69777fe..bca60bb 100644
--- a/libavcodec/eac3enc.c
+++ b/libavcodec/eac3enc.c
@@ -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/eacmv.c b/libavcodec/eacmv.c
index cf19a85..4e96c1a 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;
@@ -120,9 +121,10 @@ static void cmv_decode_inter(CmvContext *s, AVFrame *frame, const uint8_t *buf,
}else{ /* inter using last frame as reference */
int xoffset = (buf[i] & 0xF) - 7;
int yoffset = ((buf[i] >> 4)) - 7;
- cmv_motcomp(frame->data[0], frame->linesize[0],
- s->last_frame->data[0], s->last_frame->linesize[0],
- x*4, y*4, xoffset, yoffset, s->avctx->width, s->avctx->height);
+ if (s->last_frame->data[0])
+ cmv_motcomp(frame->data[0], frame->linesize[0],
+ s->last_frame->data[0], s->last_frame->linesize[0],
+ x*4, y*4, xoffset, yoffset, s->avctx->width, s->avctx->height);
}
i++;
}
@@ -139,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]);
@@ -150,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;
}
}
@@ -173,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 d4c167b..b6bf86d 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 9495066..cf93c06 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_bits(&gb, s->gb.buffer, FFMIN(bytestream2_get_bytes_left(&s->gb), mode) * 8);
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 1e0ec60..54074b3 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]);
@@ -180,7 +181,7 @@ static int tgv_decode_inter(TgvContext *s, AVFrame *frame,
/* read motion vectors */
mvbits = (num_mvs * 2 * 10 + 31) & ~31;
- if (buf + (mvbits >> 3) + 16 * num_blocks_raw + 8 * num_blocks_packed > buf_end)
+ if (buf_end - buf < (mvbits>>3) + 16*num_blocks_raw + 8*num_blocks_packed)
return AVERROR_INVALIDDATA;
init_get_bits(&gb, buf, mvbits);
@@ -220,8 +221,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 +259,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 +282,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 eba4b6f..1484ddc 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 4834b22..c9f5e1f 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)
}
}
}
+ // printf("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,13 +852,30 @@ 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->err_recognition || 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;
- };
+ }
+ 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");
@@ -864,6 +910,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;
@@ -884,7 +931,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;
@@ -907,7 +955,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;
@@ -934,6 +982,7 @@ void ff_er_frame_end(ERContext *s)
}
}
+#if 1
/* backward mark errors */
distance = 9999999;
for (error_type = 1; error_type <= 3; error_type++) {
@@ -958,6 +1007,7 @@ void ff_er_frame_end(ERContext *s)
distance = 9999999;
}
}
+#endif
/* forward mark errors */
error = 0;
@@ -972,7 +1022,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++) {
@@ -983,6 +1033,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++) {
@@ -995,8 +1046,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);
@@ -1086,6 +1137,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;
@@ -1153,15 +1205,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++) {
@@ -1183,6 +1237,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 b304dd8..3c83e58 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,7 +49,7 @@ typedef struct Escape124Context {
CodeBook codebooks[3];
} Escape124Context;
-static int can_safely_read(GetBitContext* gb, int bits) {
+static int can_safely_read(GetBitContext* gb, uint64_t bits) {
return get_bits_left(gb) >= bits;
}
@@ -62,6 +62,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 +90,7 @@ static CodeBook unpack_codebook(GetBitContext* gb, unsigned depth,
unsigned i, j;
CodeBook cb = { 0 };
- if (!can_safely_read(gb, size * 34))
+ if (!can_safely_read(gb, (uint64_t)size * 34))
return cb;
if (size >= INT_MAX / sizeof(MacroBlock))
@@ -214,6 +215,7 @@ 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);
@@ -269,10 +271,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;
diff --git a/libavcodec/escape130.c b/libavcodec/escape130.c
new file mode 100644
index 0000000..d24af79
--- /dev/null
+++ b/libavcodec/escape130.c
@@ -0,0 +1,319 @@
+/*
+ * Escape 130 Video Decoder
+ * Copyright (C) 2008 Eli Friedman (eli.friedman <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
+ */
+
+#include "avcodec.h"
+
+#define BITSTREAM_READER_LE
+#include "get_bits.h"
+#include "internal.h"
+
+
+typedef struct Escape130Context {
+ AVFrame frame;
+ uint8_t *bases;
+} Escape130Context;
+
+/**
+ * Initialize the decoder
+ * @param avctx decoder context
+ * @return 0 success, negative on error
+ */
+static av_cold int escape130_decode_init(AVCodecContext *avctx)
+{
+ Escape130Context *s = avctx->priv_data;
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ avcodec_get_frame_defaults(&s->frame);
+
+ if((avctx->width&1) || (avctx->height&1)){
+ av_log(avctx, AV_LOG_ERROR, "Dimensions are not a multiple of the block size\n");
+ return AVERROR(EINVAL);
+ }
+
+ s->bases= av_malloc(avctx->width * avctx->height /4);
+
+ return 0;
+}
+
+static av_cold int escape130_decode_close(AVCodecContext *avctx)
+{
+ Escape130Context *s = avctx->priv_data;
+
+ av_frame_unref(&s->frame);
+
+ av_freep(&s->bases);
+
+ return 0;
+}
+
+static unsigned decode_skip_count(GetBitContext* gb) {
+ unsigned value;
+ // This function reads a maximum of 27 bits,
+ // which is within the padding space
+ if (get_bits_left(gb) < 1+3)
+ return -1;
+
+ value = get_bits1(gb);
+ if (value)
+ return 0;
+
+ value = get_bits(gb, 3);
+ if (value)
+ return value;
+
+ value = get_bits(gb, 8);
+ if (value)
+ return value + 7;
+
+ value = get_bits(gb, 15);
+ if (value)
+ return value + 262;
+
+ return -1;
+}
+
+/**
+ * Decode a single frame
+ * @param avctx decoder context
+ * @param data decoded frame
+ * @param got_frame have decoded frame
+ * @param buf input buffer
+ * @param buf_size input buffer size
+ * @return 0 success, -1 on error
+ */
+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;
+
+ GetBitContext gb;
+ unsigned i;
+ int ret;
+
+ uint8_t *old_y, *old_cb, *old_cr,
+ *new_y, *new_cb, *new_cr;
+ unsigned old_y_stride, old_cb_stride, old_cr_stride,
+ new_y_stride, new_cb_stride, new_cr_stride;
+ unsigned total_blocks = avctx->width * avctx->height / 4,
+ block_index, row_index = 0;
+ unsigned y[4] = {0}, cb = 16, cr = 16;
+ unsigned skip = -1;
+ unsigned y_base = 0;
+ uint8_t *yb= s->bases;
+
+ AVFrame *frame = data;
+
+ init_get_bits(&gb, buf, buf_size * 8);
+
+ if (get_bits_left(&gb) < 128)
+ return -1;
+
+ // Header; no useful information in here
+ skip_bits_long(&gb, 128);
+
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
+ return ret;
+
+ new_y = frame->data[0];
+ new_cb = frame->data[1];
+ new_cr = frame->data[2];
+ new_y_stride = frame->linesize[0];
+ new_cb_stride = frame->linesize[1];
+ new_cr_stride = frame->linesize[2];
+ old_y = s->frame.data[0];
+ old_cb = s->frame.data[1];
+ old_cr = s->frame.data[2];
+ old_y_stride = s->frame.linesize[0];
+ old_cb_stride = s->frame.linesize[1];
+ old_cr_stride = s->frame.linesize[2];
+
+ av_log(avctx, AV_LOG_DEBUG,
+ "Strides: %i, %i\n",
+ new_y_stride, new_cb_stride);
+
+ for (block_index = 0; block_index < total_blocks; block_index++) {
+ // Note that this call will make us skip the rest of the blocks
+ // if the frame prematurely ends
+ if (skip == -1)
+ skip = decode_skip_count(&gb);
+
+ if (skip) {
+ if (old_y) {
+ y[0] = old_y[0] / 4;
+ y[1] = old_y[1] / 4;
+ y[2] = old_y[old_y_stride] / 4;
+ y[3] = old_y[old_y_stride+1] / 4;
+ y_base= yb[0];
+ cb = old_cb[0] / 8;
+ cr = old_cr[0] / 8;
+ } else {
+ y_base=y[0] = y[1] = y[2] = y[3] = 0;
+ cb = cr = 16;
+ }
+ } else {
+ if (get_bits1(&gb)) {
+ static const uint8_t offset_table[] = {2, 4, 10, 20};
+ static const int8_t sign_table[64][4] =
+ { {0, 0, 0, 0},
+ {-1, 1, 0, 0},
+ {1, -1, 0, 0},
+ {-1, 0, 1, 0},
+ {-1, 1, 1, 0},
+ {0, -1, 1, 0},
+ {1, -1, 1, 0},
+ {-1, -1, 1, 0},
+ {1, 0, -1, 0},
+ {0, 1, -1, 0},
+ {1, 1, -1, 0},
+ {-1, 1, -1, 0},
+ {1, -1, -1, 0},
+ {-1, 0, 0, 1},
+ {-1, 1, 0, 1},
+ {0, -1, 0, 1},
+
+ {0, 0, 0, 0},
+ {1, -1, 0, 1},
+ {-1, -1, 0, 1},
+ {-1, 0, 1, 1},
+ {-1, 1, 1, 1},
+ {0, -1, 1, 1},
+ {1, -1, 1, 1},
+ {-1, -1, 1, 1},
+ {0, 0, -1, 1},
+ {1, 0, -1, 1},
+ {-1, 0, -1, 1},
+ {0, 1, -1, 1},
+ {1, 1, -1, 1},
+ {-1, 1, -1, 1},
+ {0, -1, -1, 1},
+ {1, -1, -1, 1},
+
+ {0, 0, 0, 0},
+ {-1, -1, -1, 1},
+ {1, 0, 0, -1},
+ {0, 1, 0, -1},
+ {1, 1, 0, -1},
+ {-1, 1, 0, -1},
+ {1, -1, 0, -1},
+ {0, 0, 1, -1},
+ {1, 0, 1, -1},
+ {-1, 0, 1, -1},
+ {0, 1, 1, -1},
+ {1, 1, 1, -1},
+ {-1, 1, 1, -1},
+ {0, -1, 1, -1},
+ {1, -1, 1, -1},
+ {-1, -1, 1, -1},
+
+ {0, 0, 0, 0},
+ {1, 0, -1, -1},
+ {0, 1, -1, -1},
+ {1, 1, -1, -1},
+ {-1, 1, -1, -1},
+ {1, -1, -1, -1} };
+ unsigned sign_selector = get_bits(&gb, 6);
+ unsigned difference_selector = get_bits(&gb, 2);
+ y_base = 2 * get_bits(&gb, 5);
+ for (i = 0; i < 4; i++) {
+ y[i] = av_clip((int)y_base + offset_table[difference_selector] *
+ sign_table[sign_selector][i], 0, 63);
+ }
+ } else if (get_bits1(&gb)) {
+ if (get_bits1(&gb)) {
+ y_base = get_bits(&gb, 6);
+ } else {
+ unsigned adjust_index = get_bits(&gb, 3);
+ static const int8_t adjust[] = {-4, -3, -2, -1, 1, 2, 3, 4};
+ y_base = (y_base + adjust[adjust_index]) & 63;
+ }
+ for (i = 0; i < 4; i++)
+ y[i] = y_base;
+ }
+
+ if (get_bits1(&gb)) {
+ if (get_bits1(&gb)) {
+ cb = get_bits(&gb, 5);
+ cr = get_bits(&gb, 5);
+ } else {
+ unsigned adjust_index = get_bits(&gb, 3);
+ static const int8_t adjust[2][8] =
+ { { 1, 1, 0, -1, -1, -1, 0, 1 },
+ { 0, 1, 1, 1, 0, -1, -1, -1 } };
+ cb = (cb + adjust[0][adjust_index]) & 31;
+ cr = (cr + adjust[1][adjust_index]) & 31;
+ }
+ }
+ }
+ *yb++= y_base;
+
+ new_y[0] = y[0] * 4;
+ new_y[1] = y[1] * 4;
+ new_y[new_y_stride] = y[2] * 4;
+ new_y[new_y_stride + 1] = y[3] * 4;
+ *new_cb = cb * 8;
+ *new_cr = cr * 8;
+
+ if (old_y)
+ old_y += 2, old_cb++, old_cr++;
+ new_y += 2, new_cb++, new_cr++;
+ row_index++;
+ if (avctx->width / 2 == row_index) {
+ row_index = 0;
+ if (old_y) {
+ old_y += old_y_stride * 2 - avctx->width;
+ old_cb += old_cb_stride - avctx->width / 2;
+ old_cr += old_cr_stride - avctx->width / 2;
+ }
+ new_y += new_y_stride * 2 - avctx->width;
+ new_cb += new_cb_stride - avctx->width / 2;
+ new_cr += new_cr_stride - avctx->width / 2;
+ }
+
+ skip--;
+ }
+
+ av_log(avctx, AV_LOG_DEBUG,
+ "Escape sizes: %i, %i\n",
+ buf_size, get_bits_count(&gb) / 8);
+
+ av_frame_unref(&s->frame);
+ if ((ret = av_frame_ref(&s->frame, frame)) < 0)
+ return ret;
+
+ *got_frame = 1;
+
+ return buf_size;
+}
+
+
+AVCodec ff_escape130_decoder = {
+ .name = "escape130",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_ESCAPE130,
+ .priv_data_size = sizeof(Escape130Context),
+ .init = escape130_decode_init,
+ .close = escape130_decode_close,
+ .decode = escape130_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("Escape 130"),
+};
diff --git a/libavcodec/evrcdata.h b/libavcodec/evrcdata.h
new file mode 100644
index 0000000..cde1f57
--- /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..f104e33
--- /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",
+ .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),
+ .long_name = NULL_IF_CONFIG_SMALL("EVRC (Enhanced Variable Rate Codec)"),
+};
diff --git a/libavcodec/exr.c b/libavcodec/exr.c
new file mode 100644
index 0000000..af1bee0
--- /dev/null
+++ b/libavcodec/exr.c
@@ -0,0 +1,813 @@
+/*
+ * 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 "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;
+} 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;
+}
+
+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_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) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported version %d\n", version);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ flags = bytestream_get_le24(&buf);
+ if (flags & 0x2) {
+ av_log(avctx, AV_LOG_ERROR, "Tile based images are not supported\n");
+ 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;
+ int current_pixel_type = -1;
+ 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) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported subsampling %dx%d\n", 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;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Compression type %d is not supported\n", 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];
+ }
+
+ *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_free(td->uncompressed_data);
+ av_free(td->tmp);
+ }
+
+ av_freep(&s->thread_data);
+ s->thread_data_size = 0;
+ av_freep(&s->channels);
+
+ return 0;
+}
+
+AVCodec ff_exr_decoder = {
+ .name = "exr",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("OpenEXR image"),
+};
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 077e740..86be977 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
*/
@@ -163,8 +163,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){
@@ -172,10 +170,12 @@ static int decode_group3_2d_line(AVCodecContext *avctx, GetBitContext *gb,
return -1;
}
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 -1;
@@ -228,13 +228,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,
int ret;
int runsize= avctx->width + 2;
int err = 0;
+ 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,
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,7 +309,7 @@ int ff_ccitt_unpack(AVCodecContext *avctx,
}
}else{
int g3d1 = (compr == TIFF_G3) && !(opts & 1);
- if(compr!=TIFF_CCITT_RLE && find_group3_syncmarker(&gb, srcsize*8) < 0)
+ if(compr!=TIFF_CCITT_RLE && has_eol && find_group3_syncmarker(&gb, srcsize*8) < 0)
break;
if(compr==TIFF_CCITT_RLE || g3d1 || get_bits1(&gb))
ret = decode_group3_1d_line(avctx, &gb, avctx->width, runs, runend);
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-internal.h b/libavcodec/fft-internal.h
index c312625..d66731f 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
*/
diff --git a/libavcodec/fft-test.c b/libavcodec/fft-test.c
index 1e46750..66474ce 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
*/
@@ -148,7 +148,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;
@@ -164,7 +164,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;
@@ -205,7 +205,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;
}
@@ -288,10 +288,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;
}
}
@@ -408,11 +410,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;
diff --git a/libavcodec/fft.c b/libavcodec/fft.c
index 0b8140a..84d236d 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
*/
@@ -162,6 +162,7 @@ av_cold int ff_fft_init(FFTContext *s, int nbits, int inverse)
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);
diff --git a/libavcodec/fft.h b/libavcodec/fft.h
index d1425ad..910e143 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
*/
@@ -135,6 +135,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..3955efe 100644
--- a/libavcodec/fft_fixed.c
+++ b/libavcodec/fft_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/fft_float.c b/libavcodec/fft_float.c
index 24c9fdb..2149646 100644
--- a/libavcodec/fft_float.c
+++ b/libavcodec/fft_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/ffv1.c b/libavcodec/ffv1.c
index 378b55b..3299cc6 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-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,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,11 +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;
+ av_assert0(f->slice_count > 0);
for (i = 0; i < f->slice_count; i++) {
FFV1Context *fs = av_mallocz(sizeof(*fs));
@@ -203,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));
@@ -262,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..914eb10 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;
@@ -79,12 +90,13 @@ typedef struct FFV1Context {
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;
@@ -117,6 +130,14 @@ typedef struct FFV1Context {
int slice_y;
} 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 +216,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 499407e..eb2a1f0 100644
--- a/libavcodec/ffv1dec.c
+++ b/libavcodec/ffv1dec.c
@@ -3,20 +3,20 @@
*
* 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
*/
@@ -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);
@@ -194,29 +192,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 +226,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];
+ 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);
+ 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 + 1);
}
for (x = 0; x < w; x++) {
int g = sample[0][1][x];
@@ -255,12 +251,11 @@ static void decode_rgb_frame(FFV1Context *s, uint8_t *src[3], int w, int h,
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 +268,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));
@@ -332,15 +321,51 @@ static int decode_slice_header(FFV1Context *f, FFV1Context *fs)
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;
@@ -350,6 +375,7 @@ static int decode_slice(AVCodecContext *c, void *arg)
return ret;
if (f->cur->key_frame)
ffv1_clear_slice_state(f, fs);
+
width = fs->slice_width;
height = fs->slice_height;
x = fs->slice_x;
@@ -359,33 +385,25 @@ static int decode_slice(AVCodecContext *c, void *arg)
if (f->version == 3 && f->minor_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 +413,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 +439,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 +463,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;
@@ -466,10 +485,9 @@ static int read_extra_header(FFV1Context *f)
f->version = get_symbol(c, state, 0);
if (f->version > 2) {
c->bytestream_end -= 4;
- f->minor_version = get_symbol(c, state, 0);
+ f->minor_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];
@@ -485,15 +503,17 @@ static int read_extra_header(FFV1Context *f)
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 +536,8 @@ static int read_extra_header(FFV1Context *f)
if (f->version > 2) {
f->ec = get_symbol(c, state, 0);
+ if (f->minor_version > 2)
+ f->intra = get_symbol(c, state, 0);
}
if (f->version > 2) {
@@ -531,30 +553,25 @@ static int read_extra_header(FFV1Context *f)
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);
+ 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
@@ -575,88 +592,52 @@ static int read_header(FFV1Context *f)
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;
+ } 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_YUVA444P;
- break;
- case 0x10:
- f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P;
- break;
- case 0x11:
- f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P;
- break;
+ 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);
}
} else if (f->avctx->bits_per_raw_sample == 9) {
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;
+ 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);
}
} else if (f->avctx->bits_per_raw_sample == 10) {
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;
+ 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);
}
} 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;
+ 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);
@@ -668,22 +649,17 @@ 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 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);
@@ -704,16 +680,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;
}
@@ -725,23 +700,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;
}
@@ -776,12 +748,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;
@@ -789,11 +762,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;
@@ -802,10 +776,15 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void *data,
int i, ret;
uint8_t keystate = 128;
const uint8_t *buf_p;
- AVFrame *const p = data;
+ AVFrame *p;
+
+ if (f->last_picture.f)
+ ff_thread_release_buffer(avctx, &f->last_picture);
+ FFSWAP(ThreadFrame, f->picture, f->last_picture);
- f->cur = p;
+ f->cur = p = f->picture.f;
+ f->avctx = avctx;
ff_init_range_decoder(c, buf, buf_size);
ff_build_rac_states(c, 0.05 * (1LL << 32), 256 - 8);
@@ -825,27 +804,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;
@@ -855,7 +830,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;
}
}
@@ -865,56 +848,123 @@ 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;
+
+ f->picture.f = NULL;
+ f->last_picture.f = NULL;
+ f->sample_buffer = NULL;
+ f->quant_table_count = 0;
+ f->slice_count = 0;
+
+ return 0;
+}
+
+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;
+
+ if (!fdst->quant_table_count) {
+ memcpy(fdst, fsrc, sizeof(*fdst));
+
+ for (i = 0; i < fdst->quant_table_count; i++) {
+ fdst->initial_states[i] = av_malloc(fdst->context_count[i] * sizeof(*fdst->initial_states[i]));
+ memcpy(fdst->initial_states[i], fsrc->initial_states[i], fdst->context_count[i] * sizeof(*fdst->initial_states[i]));
+ }
+
+ fdst->picture.f = av_frame_alloc();
+ fdst->last_picture.f = av_frame_alloc();
+
+ if ((ret = ffv1_init_slice_contexts(fdst)) < 0)
+ return ret;
+ }
+
+ av_assert1(fdst->slice_count == fsrc->slice_count);
+
+ fdst->key_frame_ok = fsrc->key_frame_ok;
+
+ 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;
+ }
+ for (i = 0; i < fdst->slice_count; i++) {
+ FFV1Context *fsdst = fdst->slice_context[i];
+ FFV1Context *fssrc = fsrc->slice_context[i];
+
+ fsdst->slice_damaged = fssrc->slice_damaged;
+ }
+
+ fdst->fsrc = fsrc;
+
+ return 0;
+}
+
AVCodec ff_ffv1_decoder = {
.name = "ffv1",
.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 = init_thread_copy,
+ .update_thread_context = update_thread_context,
.capabilities = CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/ |
- CODEC_CAP_SLICE_THREADS,
+ CODEC_CAP_FRAME_THREADS | CODEC_CAP_SLICE_THREADS,
.long_name = NULL_IF_CONFIG_SMALL("FFmpeg video codec #1"),
};
diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
index b0c79b9..e745c7c 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>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free 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)
@@ -271,8 +367,8 @@ 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++)
@@ -280,12 +376,13 @@ static void encode_plane(FFV1Context *s, uint8_t *src, int w, int h,
encode_line(s, w, sample, plane_index, 8);
} 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);
}
@@ -293,16 +390,13 @@ static void encode_plane(FFV1Context *s, uint8_t *src, int w, int h,
}
}
-static void encode_rgb_frame(FFV1Context *s, uint8_t *src[3], int w, int h,
- int stride[3])
+static void 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,22 +407,20 @@ 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;
@@ -343,8 +435,8 @@ 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];
+ 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);
else
@@ -353,7 +445,6 @@ static void encode_rgb_frame(FFV1Context *s, uint8_t *src[3], int w, int h,
}
}
-
static void write_quant_table(RangeCoder *c, int16_t *quant_table)
{
int last = 0;
@@ -393,7 +484,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);
@@ -444,7 +535,7 @@ static int write_extradata(FFV1Context *f)
put_symbol(c, state, f->version, 0);
if (f->version > 2) {
if (f->version == 3)
- f->minor_version = 2;
+ f->minor_version = 3;
put_symbol(c, state, f->minor_version, 0);
}
@@ -485,12 +576,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 +605,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 +635,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 || (s->version==2 && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL)) {
s->version = 3;
}
@@ -578,19 +657,15 @@ 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 && 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:
@@ -616,15 +691,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:
@@ -635,74 +707,76 @@ static av_cold int ffv1_encode_init(AVCodecContext *avctx)
case AV_PIX_FMT_YUV411P:
case AV_PIX_FMT_YUV410P:
s->chroma_planes = desc->nb_components < 3 ? 0 : 1;
- s->colorspace = 0;
+ 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->colorspace = 0;
+ s->transparency = 1;
break;
case AV_PIX_FMT_RGB32:
- s->colorspace = 1;
+ s->colorspace = 1;
s->transparency = 1;
break;
+ case AV_PIX_FMT_0RGB32:
+ s->colorspace = 1;
+ break;
case AV_PIX_FMT_GBRP9:
if (!avctx->bits_per_raw_sample)
s->bits_per_raw_sample = 9;
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 +795,9 @@ 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;
-
- 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 +816,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,28 +857,40 @@ 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",
@@ -820,12 +902,14 @@ slices_ok:
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 +931,20 @@ 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);
}
static int encode_slice(AVCodecContext *c, void *arg)
@@ -874,10 +955,8 @@ 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;
if (p->key_frame)
ffv1_clear_slice_state(f, fs);
@@ -887,33 +966,30 @@ 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);
+ 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);
+ 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);
}
if (fs->transparency)
- encode_plane(fs, p->data[3] + ps * x + y * p->linesize[3], width,
- height, p->linesize[3], 2);
+ 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] };
+ 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);
}
emms_c();
@@ -921,28 +997,26 @@ static int encode_slice(AVCodecContext *c, void *arg)
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;
- 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, avctx->width*avctx->height*((8*2+1+1)*4)/8
+ + 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);
- *p = *pict;
+ av_frame_unref(p);
+ av_frame_ref(p, pict);
p->pict_type = AV_PICTURE_TYPE_I;
if (avctx->gop_size == 0 || f->picture_number % avctx->gop_size == 0) {
@@ -965,9 +1039,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,8 +1130,7 @@ 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 }
};
@@ -1079,20 +1151,18 @@ 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_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
},
diff --git a/libavcodec/ffwavesynth.c b/libavcodec/ffwavesynth.c
new file mode 100644
index 0000000..4f392f2
--- /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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("Wave synthesis pseudo-codec"),
+};
diff --git a/libavcodec/flac.c b/libavcodec/flac.c
index aa322b4..a79a809 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..2996398 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
*/
@@ -546,14 +546,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 +570,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 +615,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;
}
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 ec54dfc..1bf6dc7 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"
@@ -44,9 +45,6 @@
#include "flacdata.h"
#include "flacdsp.h"
-#undef NDEBUG
-#include <assert.h>
-
typedef struct FLACContext {
FLACSTREAMINFO
@@ -103,7 +101,7 @@ static av_cold int flac_decode_init(AVCodecContext *avctx)
return 0;
if (!avpriv_flac_is_extradata_valid(avctx, &format, &streaminfo))
- return -1;
+ return AVERROR_INVALIDDATA;
/* initialize based on the demuxer-supplied streamdata header */
avpriv_flac_parse_streaminfo(avctx, (FLACStreaminfo *)s, streaminfo);
@@ -130,7 +128,7 @@ static int allocate_buffers(FLACContext *s)
{
int buf_size;
- assert(s->max_blocksize);
+ av_assert0(s->max_blocksize);
buf_size = av_samples_get_buffer_size(NULL, s->channels, s->max_blocksize,
AV_SAMPLE_FMT_S32P, 0);
@@ -214,7 +212,7 @@ static int decode_residuals(FLACContext *s, int32_t *decoded, int pred_order)
if (method_type > 1) {
av_log(s->avctx, AV_LOG_ERROR, "illegal residual coding method %d\n",
method_type);
- return -1;
+ return AVERROR_INVALIDDATA;
}
rice_order = get_bits(&s->gb, 4);
@@ -223,7 +221,7 @@ static int decode_residuals(FLACContext *s, int32_t *decoded, int pred_order)
if (pred_order > samples) {
av_log(s->avctx, AV_LOG_ERROR, "invalid predictor order: %i > %i\n",
pred_order, samples);
- return -1;
+ return AVERROR_INVALIDDATA;
}
rice_bits = 4 + method_type;
@@ -252,15 +250,16 @@ 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;
+ 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++) {
decoded[i] = get_sbits_long(&s->gb, bps);
}
- if (decode_residuals(s, decoded, pred_order) < 0)
- return -1;
+ if ((ret = decode_residuals(s, decoded, pred_order)) < 0)
+ return ret;
if (pred_order > 0)
a = decoded[pred_order-1];
@@ -292,7 +291,7 @@ static int decode_subframe_fixed(FLACContext *s, int32_t *decoded,
break;
default:
av_log(s->avctx, AV_LOG_ERROR, "illegal pred order %d\n", pred_order);
- return -1;
+ return AVERROR_INVALIDDATA;
}
return 0;
@@ -301,7 +300,7 @@ static int decode_subframe_fixed(FLACContext *s, int32_t *decoded,
static int decode_subframe_lpc(FLACContext *s, int32_t *decoded, int pred_order,
int bps)
{
- int i;
+ int i, ret;
int coeff_prec, qlevel;
int coeffs[32];
@@ -313,21 +312,21 @@ static int decode_subframe_lpc(FLACContext *s, int32_t *decoded, int pred_order,
coeff_prec = get_bits(&s->gb, 4) + 1;
if (coeff_prec == 16) {
av_log(s->avctx, AV_LOG_ERROR, "invalid coeff precision\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
qlevel = get_sbits(&s->gb, 5);
if (qlevel < 0) {
av_log(s->avctx, AV_LOG_ERROR, "qlevel %d not supported, maybe buggy stream\n",
qlevel);
- return -1;
+ return AVERROR_INVALIDDATA;
}
for (i = 0; i < pred_order; i++) {
coeffs[pred_order - i - 1] = get_sbits(&s->gb, coeff_prec);
}
- if (decode_residuals(s, decoded, pred_order) < 0)
- return -1;
+ if ((ret = decode_residuals(s, decoded, pred_order)) < 0)
+ return ret;
s->dsp.lpc(decoded, coeffs, pred_order, qlevel, s->blocksize);
@@ -339,7 +338,7 @@ static inline int decode_subframe(FLACContext *s, int channel)
int32_t *decoded = s->decoded[channel];
int type, wasted = 0;
int bps = s->bps;
- int i, tmp;
+ int i, tmp, ret;
if (channel == 0) {
if (s->ch_mode == FLAC_CHMODE_RIGHT_SIDE)
@@ -351,7 +350,7 @@ static inline int decode_subframe(FLACContext *s, int channel)
if (get_bits1(&s->gb)) {
av_log(s->avctx, AV_LOG_ERROR, "invalid subframe padding\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
type = get_bits(&s->gb, 6);
@@ -384,14 +383,14 @@ static inline int decode_subframe(FLACContext *s, int channel)
for (i = 0; i < s->blocksize; i++)
decoded[i] = get_sbits_long(&s->gb, bps);
} else if ((type >= 8) && (type <= 12)) {
- if (decode_subframe_fixed(s, decoded, type & ~0x8, bps) < 0)
- return -1;
+ if ((ret = decode_subframe_fixed(s, decoded, type & ~0x8, bps)) < 0)
+ return ret;
} else if (type >= 32) {
- if (decode_subframe_lpc(s, decoded, (type & ~0x20)+1, bps) < 0)
- return -1;
+ if ((ret = decode_subframe_lpc(s, decoded, (type & ~0x20)+1, bps)) < 0)
+ return ret;
} else {
av_log(s->avctx, AV_LOG_ERROR, "invalid coding type\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
if (wasted) {
@@ -411,7 +410,7 @@ static int decode_frame(FLACContext *s)
if (ff_flac_decode_frame_header(s->avctx, gb, &fi, 0)) {
av_log(s->avctx, AV_LOG_ERROR, "invalid frame header\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
if (s->channels && fi.channels != s->channels && s->got_streaminfo) {
@@ -428,7 +427,7 @@ static int decode_frame(FLACContext *s)
if (!s->bps && !fi.bps) {
av_log(s->avctx, AV_LOG_ERROR, "bps not found in STREAMINFO or frame header\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
if (!fi.bps) {
fi.bps = s->bps;
@@ -448,14 +447,14 @@ static int decode_frame(FLACContext *s)
if (fi.blocksize > s->max_blocksize) {
av_log(s->avctx, AV_LOG_ERROR, "blocksize %d > %d\n", fi.blocksize,
s->max_blocksize);
- return -1;
+ return AVERROR_INVALIDDATA;
}
s->blocksize = fi.blocksize;
if (!s->samplerate && !fi.samplerate) {
av_log(s->avctx, AV_LOG_ERROR, "sample rate not found in STREAMINFO"
" or frame header\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
if (fi.samplerate == 0)
fi.samplerate = s->samplerate;
@@ -474,8 +473,8 @@ static int decode_frame(FLACContext *s)
/* subframes */
for (i = 0; i < s->channels; i++) {
- if (decode_subframe(s, i) < 0)
- return -1;
+ if ((ret = decode_subframe(s, i)) < 0)
+ return ret;
}
align_get_bits(gb);
@@ -504,6 +503,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 */
@@ -514,32 +523,38 @@ static int flac_decode_frame(AVCodecContext *avctx, void *data,
if (AV_RB32(buf) == MKBETAG('f','L','a','C')) {
if (!s->got_streaminfo && parse_streaminfo(s, buf, buf_size)) {
av_log(s->avctx, AV_LOG_ERROR, "invalid header\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
return get_metadata_size(buf, buf_size);
}
/* decode frame */
init_get_bits(&s->gb, buf, buf_size*8);
- if (decode_frame(s) < 0) {
+ if ((ret = decode_frame(s)) < 0) {
av_log(s->avctx, AV_LOG_ERROR, "decode_frame() failed\n");
- return -1;
+ return ret;
+ }
+ bytes_read = get_bits_count(&s->gb)/8;
+
+ if ((s->avctx->err_recognition & AV_EF_CRCCHECK) &&
+ 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;
}
- bytes_read = (get_bits_count(&s->gb)+7)/8;
/* 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;
- }
s->dsp.decorrelate[s->ch_mode](frame->data, s->decoded, s->channels,
s->blocksize, s->sample_shift);
if (bytes_read > buf_size) {
av_log(s->avctx, AV_LOG_ERROR, "overread: %d\n", bytes_read - buf_size);
- return -1;
+ return AVERROR_INVALIDDATA;
}
if (bytes_read < buf_size) {
av_log(s->avctx, AV_LOG_DEBUG, "underread: %d orig size: %d\n",
@@ -574,5 +589,5 @@ AVCodec ff_flac_decoder = {
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 15b0e55..1e9cc48 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" },
@@ -1324,7 +1349,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 2fbe221..9982b5e 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++) {
diff --git a/libavcodec/flashsv2enc.c b/libavcodec/flashsv2enc.c
new file mode 100644
index 0000000..1d0d196
--- /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",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video Version 2"),
+};
diff --git a/libavcodec/flashsvenc.c b/libavcodec/flashsvenc.c
index 0b78880..e6b181f 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 9795ff9..a2f9ef9 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]);
}
@@ -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,21 @@ 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)) {
+ 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 +239,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 +252,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 +286,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 +304,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 +328,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 +380,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 +401,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 +419,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 +434,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 +441,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 +503,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 +513,25 @@ 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)) {
+ 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 +549,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 +562,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 +577,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 +613,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 +628,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 +669,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 +685,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 3640d29..bb693d7 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;
@@ -128,6 +128,7 @@ AVCodec ff_flv_decoder = {
.close = ff_h263_decode_end,
.decode = ff_h263_decode_frame,
.capabilities = CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1,
+ .max_lowres = 3,
.long_name = NULL_IF_CONFIG_SMALL("FLV / Sorenson Spark / Sorenson H.263 (Flash Video)"),
.pix_fmts = ff_pixfmt_list_420,
};
diff --git a/libavcodec/flvenc.c b/libavcodec/flvenc.c
index 5427cbc..a68a6fa 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 5b7ab03..632c11d 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
*/
@@ -86,4 +86,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 93c3401..473a586 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
*/
@@ -92,5 +92,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..b11a54a
--- /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 "w32pthreads.h"
+#elif HAVE_OS2THREADS
+#include "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 = ff_get_logical_cpus(avctx);
+ 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
--- /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 66ecdef..00a38c6 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,6 +37,7 @@
#include "bytestream.h"
#include "dsputil.h"
#include "internal.h"
+#include "thread.h"
#define FPS_TAG MKTAG('F', 'P', 'S', 'x')
@@ -45,7 +46,6 @@
*/
typedef struct FrapsContext {
AVCodecContext *avctx;
- AVFrame frame;
uint8_t *tmpbuf;
int tmpbuf_size;
DSPContext dsp;
@@ -61,13 +61,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;
@@ -135,16 +131,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 i, j, ret, is_chroma;
+ const int planes = 3;
+ uint8_t *out;
header = AV_RL32(buf);
version = header & 0xff;
@@ -157,86 +154,89 @@ static int decode_frame(AVCodecContext *avctx,
return AVERROR_PATCHWELCOME;
}
- buf += 4;
- if (header_size == 8)
- buf += 4;
+ buf += header_size;
- pix_fmt = version & 1 ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_YUVJ420P;
- if (avctx->pix_fmt != pix_fmt && f->data[0]) {
- av_frame_unref(f);
+ if (version < 2) {
+ unsigned needed_size = avctx->width * avctx->height * 3;
+ if (version == 0) needed_size /= 2;
+ needed_size += header_size;
+ /* bit 31 means same as previous pic */
+ if (header & (1U<<31)) {
+ *got_frame = 0;
+ return buf_size;
+ }
+ if (buf_size != needed_size) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Invalid frame length %d (should be %d)\n",
+ buf_size, needed_size);
+ return AVERROR_INVALIDDATA;
+ }
+ } else {
+ /* skip frame */
+ if (buf_size == 8) {
+ *got_frame = 0;
+ return buf_size;
+ }
+ if (AV_RL32(buf) != FPS_TAG || buf_size < planes*1024 + 24) {
+ av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (i = 0; i < planes; i++) {
+ offs[i] = AV_RL32(buf + 4 + i * 4);
+ if (offs[i] >= buf_size - header_size || (i && offs[i] <= offs[i - 1] + 1024)) {
+ av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ offs[planes] = buf_size - header_size;
+ for (i = 0; i < planes; i++) {
+ av_fast_padded_malloc(&s->tmpbuf, &s->tmpbuf_size, offs[i + 1] - offs[i] - 1024);
+ if (!s->tmpbuf)
+ return AVERROR(ENOMEM);
+ }
}
- avctx->pix_fmt = pix_fmt;
+
+ f->pict_type = AV_PICTURE_TYPE_I;
+ f->key_frame = 1;
+
+ avctx->pix_fmt = version & 1 ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_YUVJ420P;
+
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
+ return ret;
switch (version) {
case 0:
default:
/* Fraps v0 is a reordered YUV420 */
- if ((buf_size != avctx->width * avctx->height * 3 / 2 + header_size) &&
- (buf_size != header_size)) {
- av_log(avctx, AV_LOG_ERROR,
- "Invalid frame length %d (should be %d)\n",
- buf_size,
- avctx->width * avctx->height * 3 / 2 + header_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;
- }
- /* bit 31 means same as previous pic */
- f->pict_type = (header & (1U << 31)) ? 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 ((buf_size != avctx->width * avctx->height * 3 + header_size) &&
- (buf_size != header_size) ) {
- av_log(avctx, AV_LOG_ERROR,
- "Invalid frame length %d (should be %d)\n",
- buf_size, avctx->width * avctx->height * 3 + header_size);
- return AVERROR_INVALIDDATA;
- }
-
- if ((ret = ff_reget_buffer(avctx, f)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
- return ret;
- }
- /* bit 31 means same as previous pic */
- f->pict_type = (header & (1U<<31))? 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:
@@ -245,37 +245,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,
@@ -289,36 +260,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) {
@@ -326,18 +268,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;
@@ -353,8 +297,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;
}
@@ -368,6 +310,6 @@ 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,
.long_name = NULL_IF_CONFIG_SMALL("Fraps"),
};
diff --git a/libavcodec/frwu.c b/libavcodec/frwu.c
index 1323727..b1c7408 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",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_FRWU,
+ .priv_data_size = sizeof(FRWUContext),
.init = decode_init,
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("Forward Uncompressed"),
+ .priv_class = &frwu_class,
};
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/g722dec.c b/libavcodec/g722dec.c
index 100dab2..1a489a7 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 b168a92..b276b4e 100644
--- a/libavcodec/g722enc.c
+++ b/libavcodec/g722enc.c
@@ -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 64b4e1f..6254c9a 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
*/
@@ -30,50 +30,16 @@
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "avcodec.h"
+#include "internal.h"
#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 +66,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 +90,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 +173,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 +223,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 +252,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 +341,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 +356,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 +537,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 +558,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 +775,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 +817,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 +905,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 +1185,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 +1341,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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("G.723.1"),
+ .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 6db00fe..58d0468 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>
@@ -347,10 +347,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++)
@@ -433,10 +431,8 @@ 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);
diff --git a/libavcodec/g729.h b/libavcodec/g729.h
new file mode 100644
index 0000000..6168313
--- /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
--- /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..85323ba
--- /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",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_G729,
+ .priv_data_size = sizeof(G729Context),
+ .init = decoder_init,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("G.729"),
+};
diff --git a/libavcodec/g729postfilter.c b/libavcodec/g729postfilter.c
new file mode 100644
index 0000000..fc90374
--- /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
--- /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..f16a508 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
@@ -126,7 +125,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
@@ -227,6 +226,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 +241,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);
@@ -255,6 +256,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;
@@ -303,20 +305,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 +382,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 +392,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 +410,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 8705e74..7a5e287 100644
--- a/libavcodec/gif.c
+++ b/libavcodec/gif.c
@@ -1,114 +1,196 @@
/*
- * 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
*/
+#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
#include "avcodec.h"
#include "bytestream.h"
#include "internal.h"
#include "lzw.h"
+#include "gif.h"
-/* The GIF format uses reversed order for bitstreams... */
-/* at least they don't use PDP_ENDIAN :) */
#define BITSTREAM_WRITER_LE
-
#include "put_bits.h"
typedef struct {
+ const AVClass *class;
AVFrame picture;
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);
+
+ 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);
+ }
+ }
- 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 */
+ /* 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, 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 +205,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 +212,61 @@ static av_cold int gif_encode_init(AVCodecContext *avctx)
{
GIFContext *s = avctx->priv_data;
+ if (avctx->width > 65535 || avctx->height > 65535) {
+ av_log(avctx, AV_LOG_ERROR, "GIF does not support resolutions above 65535x65535\n");
+ return AVERROR(EINVAL);
+ }
+
avctx->coded_frame = &s->picture;
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;
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 +281,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",
.type = AVMEDIA_TYPE_VIDEO,
@@ -192,4 +315,5 @@ AVCodec ff_gif_encoder = {
AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE
},
.long_name = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
+ .priv_class = &gif_class,
};
diff --git a/libavcodec/gif.h b/libavcodec/gif.h
new file mode 100644
index 0000000..b4cf665
--- /dev/null
+++ b/libavcodec/gif.h
@@ -0,0 +1,49 @@
+/*
+ * GIF format definitions
+ * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2006 Baptiste Coudurier
+ * Copyright (c) 2012 Vitaliy E Sugrobov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * GIF format definitions.
+ */
+
+#ifndef AVCODEC_GIFDEFS_H
+#define AVCODEC_GIFDEFS_H
+
+#include <stdint.h>
+
+static const uint8_t gif87a_sig[6] = "GIF87a";
+static const uint8_t gif89a_sig[6] = "GIF89a";
+
+#define GCE_DISPOSAL_NONE 0
+#define GCE_DISPOSAL_INPLACE 1
+#define GCE_DISPOSAL_BACKGROUND 2
+#define GCE_DISPOSAL_RESTORE 3
+
+#define GIF_TRAILER 0x3b
+#define GIF_EXTENSION_INTRODUCER 0x21
+#define GIF_IMAGE_SEPARATOR 0x2c
+#define GIF_GCE_EXT_LABEL 0xf9
+#define GIF_APP_EXT_LABEL 0xff
+#define NETSCAPE_EXT_STR "NETSCAPE2.0"
+
+#endif /* AVCODEC_GIFDEFS_H */
diff --git a/libavcodec/gifdec.c b/libavcodec/gifdec.c
index d8a3b74..4c1cb83 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",
.type = AVMEDIA_TYPE_VIDEO,
@@ -327,4 +540,5 @@ AVCodec ff_gif_decoder = {
.decode = gif_decode_frame,
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
+ .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 564ba4e..66607ad 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{
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;
}
@@ -136,7 +140,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;
@@ -147,7 +151,7 @@ static inline unsigned svq3_get_ue_golomb(GetBitContext *gb)
* read unsigned truncated exp golomb code.
*/
static inline int get_te0_golomb(GetBitContext *gb, int range){
- assert(range >= 1);
+ av_assert2(range >= 1);
if(range==1) return 0;
else if(range==2) return get_bits1(gb)^1;
@@ -158,7 +162,7 @@ static inline int get_te0_golomb(GetBitContext *gb, int range){
* read unsigned truncated exp golomb code.
*/
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;
else return get_ue_golomb(gb);
@@ -183,7 +187,11 @@ static inline int get_se_golomb(GetBitContext *gb){
return ff_se_golomb_vlc_code[buf];
}else{
- log= 2*av_log2(buf) - 31;
+ 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);
@@ -302,7 +310,9 @@ static inline int get_ur_golomb_jpegls(GetBitContext *gb, int k, int limit, int
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);
}
@@ -432,7 +442,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){
int e;
- assert(i>=0);
+ av_assert2(i>=0);
#if 0
if(i=0){
@@ -453,8 +463,8 @@ static inline void set_ue_golomb(PutBitContext *pb, int i){
* write truncated unsigned exp golomb code.
*/
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);
else set_ue_golomb(pb, i);
@@ -483,7 +493,7 @@ static inline void set_se_golomb(PutBitContext *pb, int i){
static inline void set_ur_golomb(PutBitContext *pb, int i, int k, int limit, int esc_len){
int e;
- assert(i>=0);
+ av_assert2(i>=0);
e= i>>k;
if(e<limit){
@@ -499,7 +509,7 @@ static inline void set_ur_golomb(PutBitContext *pb, int i, int k, int limit, int
static inline void set_ur_golomb_jpegls(PutBitContext *pb, int i, int k, int limit, int esc_len){
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..dd26f7d 100644
--- a/libavcodec/gsm_parser.c
+++ b/libavcodec/gsm_parser.c
@@ -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 d67f0b4..dc64267 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
*/
@@ -36,7 +36,8 @@ static av_cold int gsm_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;
switch (avctx->codec_id) {
@@ -69,10 +70,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 +100,7 @@ static void gsm_flush(AVCodecContext *avctx)
memset(s, 0, sizeof(*s));
}
+#if CONFIG_GSM_DECODER
AVCodec ff_gsm_decoder = {
.name = "gsm",
.type = AVMEDIA_TYPE_AUDIO,
@@ -112,7 +112,8 @@ AVCodec ff_gsm_decoder = {
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("GSM"),
};
-
+#endif
+#if CONFIG_GSM_MS_DECODER
AVCodec ff_gsm_ms_decoder = {
.name = "gsm_ms",
.type = AVMEDIA_TYPE_AUDIO,
@@ -124,3 +125,4 @@ AVCodec ff_gsm_ms_decoder = {
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("GSM Microsoft variant"),
};
+#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 8872c6c..b630344 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,6 +377,10 @@ 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) {
+ av_log(s->avctx, AV_LOG_ERROR, "illegal mtype %d\n", h->mtype);
+ return SLICE_ERROR;
+ }
h->mtype = ff_h261_mtype_map[h->mtype];
// Read mquant
@@ -633,12 +638,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;
@@ -663,5 +668,6 @@ AVCodec ff_h261_decoder = {
.close = h261_decode_end,
.decode = h261_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
.long_name = NULL_IF_CONFIG_SMALL("H.261"),
};
diff --git a/libavcodec/h261enc.c b/libavcodec/h261enc.c
index 6a8d993..bfa34ea 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 dec660e..a95cfb0 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
@@ -59,8 +59,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];
@@ -112,7 +112,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 313012a..bf9e072 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 "internal.h"
#include "avcodec.h"
@@ -42,6 +44,7 @@
av_cold int ff_h263_decode_init(AVCodecContext *avctx)
{
MpegEncContext *s = avctx->priv_data;
+ int ret;
s->avctx = avctx;
s->out_format = FMT_H263;
@@ -64,6 +67,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;
@@ -104,15 +108,15 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx)
s->h263_flv = 1;
break;
default:
- return -1;
+ return AVERROR(EINVAL);
}
s->codec_id= avctx->codec->id;
avctx->hwaccel= ff_find_hwaccel(avctx->codec->id, avctx->pix_fmt);
/* 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_MPEG4)
- if (ff_MPV_common_init(s) < 0)
- return -1;
+ 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;
ff_h263_decode_init_vlc();
@@ -150,7 +154,9 @@ static int get_consumed_bytes(MpegEncContext *s, int buf_size){
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;
s->first_slice_line= 1;
@@ -161,7 +167,7 @@ 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);
+ const uint8_t *end = ff_h263_find_resync_marker(s, 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);
}
@@ -170,8 +176,8 @@ static int decode_slice(MpegEncContext *s){
const int qscale= s->qscale;
if(CONFIG_MPEG4_DECODER && s->codec_id==AV_CODEC_ID_MPEG4){
- if(ff_mpeg4_decode_partitions(s) < 0)
- return -1;
+ if ((ret = ff_mpeg4_decode_partitions(s)) < 0)
+ return ret;
}
/* restore variables which were modified */
@@ -240,12 +246,12 @@ static int decode_slice(MpegEncContext *s){
}else if(ret==SLICE_NOEND){
av_log(s->avctx, AV_LOG_ERROR, "Slice mismatch at MB: %d\n", xy);
ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, s->mb_x+1, s->mb_y, ER_MB_END&part_mask);
- return -1;
+ return AVERROR_INVALIDDATA;
}
av_log(s->avctx, AV_LOG_ERROR, "Error at MB: %d\n", xy);
ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR&part_mask);
- return -1;
+ return AVERROR_INVALIDDATA;
}
ff_MPV_decode_mb(s, s->block);
@@ -259,7 +265,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)
@@ -272,7 +278,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){
@@ -311,7 +317,7 @@ static int decode_slice(MpegEncContext *s){
max_extra+= 17;
/* buggy padding but the frame should still end approximately at the bitstream end */
- if((s->workaround_bugs&FF_BUG_NO_PADDING) && (s->err_recognition&AV_EF_BUFFER))
+ if((s->workaround_bugs&FF_BUG_NO_PADDING) && (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;
@@ -333,7 +339,7 @@ static int decode_slice(MpegEncContext *s){
ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, ER_MB_END&part_mask);
- return -1;
+ return AVERROR_INVALIDDATA;
}
int ff_h263_decode_frame(AVCodecContext *avctx,
@@ -370,9 +376,11 @@ int ff_h263_decode_frame(AVCodecContext *avctx,
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");
- return -1;
+ return AVERROR(EINVAL);
}
if( ff_combine_frame(&s->parse_context, next, (const uint8_t **)&buf, &buf_size) < 0 )
@@ -381,6 +389,18 @@ int ff_h263_decode_frame(AVCodecContext *avctx,
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
init_get_bits(&s->gb, s->bitstream_buffer, s->bitstream_buffer_size*8);
@@ -389,8 +409,8 @@ retry:
s->bitstream_buffer_size=0;
if (!s->context_initialized) {
- if (ff_MPV_common_init(s) < 0) //we need the idct permutaton for reading a custom matrix
- return -1;
+ if ((ret = ff_MPV_common_init(s)) < 0) //we need the idct permutaton for reading a custom matrix
+ return ret;
}
/* We need to set current_picture_ptr before reading the header,
@@ -423,12 +443,20 @@ retry:
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);
/* skip if the header was thrashed */
if (ret < 0){
av_log(s->avctx, AV_LOG_ERROR, "header damaged\n");
- return -1;
+ return ret;
}
avctx->has_b_frames= !s->low_delay;
@@ -555,7 +583,7 @@ retry:
if (s->codec_id == AV_CODEC_ID_MPEG4 && s->xvid_build>=0 && avctx->idct_algo == FF_IDCT_AUTO && (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
@@ -564,7 +592,7 @@ retry:
/* FIXME: By the way H263 decoder is evolving it should have */
/* an H263EncContext */
- if (!avctx->coded_width || !avctx->coded_height) {
+ if ((!avctx->coded_width || !avctx->coded_height) && 0) {
ParseContext pc= s->parse_context; //FIXME move these demuxng hack to avformat
s->parse_context.buffer=0;
@@ -618,8 +646,8 @@ retry:
s->me.qpel_avg= s->dsp.avg_qpel_pixels_tab;
}
- if(ff_MPV_frame_start(s, avctx) < 0)
- return -1;
+ if ((ret = ff_MPV_frame_start(s, avctx)) < 0)
+ return ret;
if (!s->divx_packed && !avctx->hwaccel)
ff_thread_finish_setup(avctx);
@@ -630,8 +658,8 @@ retry:
}
if (avctx->hwaccel) {
- if (avctx->hwaccel->start_frame(avctx, s->gb.buffer, s->gb.buffer_end - s->gb.buffer) < 0)
- return -1;
+ if ((ret = avctx->hwaccel->start_frame(avctx, s->gb.buffer, s->gb.buffer_end - s->gb.buffer)) < 0)
+ return ret;
}
ff_mpeg_er_frame_start(s);
@@ -672,26 +700,22 @@ retry:
s->er.error_status_table[s->mb_num - 1] = ER_MB_ERROR;
}
- assert(s->bitstream_buffer_size==0);
+ av_assert1(s->bitstream_buffer_size==0);
frame_end:
- /* divx 5.01+ bistream reorder stuff */
+ /* divx 5.01+ bitstream reorder stuff */
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(
@@ -709,8 +733,8 @@ intrax8_decoded:
ff_er_frame_end(&s->er);
if (avctx->hwaccel) {
- if (avctx->hwaccel->end_frame(avctx) < 0)
- return -1;
+ if ((ret = avctx->hwaccel->end_frame(avctx)) < 0)
+ return ret;
}
ff_MPV_frame_end(s);
@@ -718,16 +742,18 @@ intrax8_decoded:
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){
@@ -759,6 +785,23 @@ 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,
+ .long_name = NULL_IF_CONFIG_SMALL("H.263 / H.263-1996, H.263+ / H.263-1998 / H.263 version 2"),
+ .pix_fmts = ff_h263_hwaccel_pixfmt_list_420,
+};
+
+AVCodec ff_h263p_decoder = {
+ .name = "h263p",
+ .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,
.long_name = NULL_IF_CONFIG_SMALL("H.263 / H.263-1996, H.263+ / H.263-1998 / H.263 version 2"),
.pix_fmts = ff_h263_hwaccel_pixfmt_list_420,
};
diff --git a/libavcodec/h264.c b/libavcodec/h264.c
index 38e471d..3d3746f 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,7 +25,10 @@
* @author Michael Niedermayer <michaelni@gmx.at>
*/
+#define UNCHECKED_BITSTREAM_READER 1
+
#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
#include "internal.h"
#include "cabac.h"
#include "cabac_functions.h"
@@ -53,13 +56,17 @@ 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 enum AVPixelFormat h264_hwaccel_pixfmt_list_420[] = {
@@ -96,6 +103,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)
@@ -106,19 +119,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);
}
@@ -252,6 +274,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:
@@ -326,6 +352,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;
@@ -547,21 +576,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) {
@@ -617,13 +652,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,
@@ -695,7 +730,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];
@@ -727,7 +762,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,
@@ -1062,9 +1097,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);
}
}
@@ -1089,6 +1122,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);
@@ -1205,7 +1241,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,
@@ -1365,17 +1401,20 @@ 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;
- 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 -1;
}
@@ -1387,7 +1426,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 -1;
if (decode_nal_units(h, p, nalsize, 1) < 0) {
av_log(avctx, AV_LOG_ERROR,
@@ -1400,7 +1439,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 -1;
if (decode_nal_units(h, p, nalsize, 1) < 0) {
av_log(avctx, AV_LOG_ERROR,
@@ -1410,13 +1449,13 @@ 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;
- if (decode_nal_units(h, avctx->extradata, avctx->extradata_size, 1) < 0)
+ if (decode_nal_units(h, buf, size, 1) < 0)
return -1;
}
- return 0;
+ return size;
}
av_cold int ff_h264_decode_init(AVCodecContext *avctx)
@@ -1429,12 +1468,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)
@@ -1466,17 +1510,24 @@ 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;
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 &&
- ff_h264_decode_extradata(h))
+ ff_h264_decode_extradata(h, avctx->extradata, avctx->extradata_size) < 0) {
+ ff_h264_free_context(h);
return -1;
+ }
if (h->sps.bitstream_restriction_flag &&
h->avctx->has_b_frames < h->sps.num_reorder_frames) {
@@ -1484,6 +1535,7 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)
h->low_delay = 0;
}
+ ff_init_cabac_states();
avctx->internal->allocate_progress = 1;
return 0;
@@ -1556,7 +1608,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 &&
@@ -1582,6 +1634,13 @@ 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
+ copy_parameter_set((void **)h->sps_buffers, (void **)h1->sps_buffers,
+ MAX_SPS_COUNT, sizeof(SPS));
+ h->sps = h1->sps;
+ copy_parameter_set((void **)h->pps_buffers, (void **)h1->pps_buffers,
+ MAX_PPS_COUNT, sizeof(PPS));
+ 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");
@@ -1589,14 +1648,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++)
@@ -1605,19 +1669,19 @@ 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));
+ 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;
@@ -1626,11 +1690,19 @@ static int decode_update_thread_context(AVCodecContext *dst,
h->ref_index_pool = NULL;
h->motion_val_pool = NULL;
+ 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;
+
if (ff_h264_alloc_tables(h) < 0) {
av_log(dst, AV_LOG_ERROR, "Could not allocate memory for h264\n");
return AVERROR(ENOMEM);
}
context_init(h);
+ }
for (i = 0; i < 2; i++) {
h->rbsp_buffer[i] = NULL;
@@ -1640,8 +1712,7 @@ static int decode_update_thread_context(AVCodecContext *dst,
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;
@@ -1656,7 +1727,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)
@@ -1665,19 +1736,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;
@@ -1714,7 +1779,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);
@@ -1739,6 +1804,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;
@@ -1753,24 +1829,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);
@@ -1785,22 +1869,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
@@ -1830,7 +1900,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;
@@ -1912,6 +1981,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 */
@@ -1928,107 +1999,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);
+ out_of_order = out->poc < h->next_outputed_poc;
- if (h->sps.bitstream_restriction_flag &&
- h->avctx->has_b_frames >= h->sps.num_reorder_frames) {
- } else if (out_of_order && pics - 1 == h->avctx->has_b_frames &&
- h->avctx->has_b_frames < MAX_DELAYED_PIC_COUNT) {
- if (invalid + cnt < MAX_DELAYED_PIC_COUNT) {
- h->avctx->has_b_frames = FFMAX(h->avctx->has_b_frames, cnt);
- }
- h->low_delay = 0;
- } else if (h->low_delay &&
- ((h->next_outputed_poc != INT_MIN &&
- out->poc > h->next_outputed_poc + 2) ||
- cur->f.pict_type == AV_PICTURE_TYPE_B)) {
- h->low_delay = 0;
- h->avctx->has_b_frames++;
- }
-
- if (pics > h->avctx->has_b_frames) {
+ if (out_of_order || pics > h->avctx->has_b_frames) {
out->reference &= ~DELAYED_PIC_REF;
// for frame threading, the owner must be the second field's thread or
// else the first thread can release the picture and reuse it unsafely
for (i = out_idx; h->delayed_pic[i]; i++)
h->delayed_pic[i] = h->delayed_pic[i + 1];
}
- memmove(h->last_pocs, &h->last_pocs[1],
- sizeof(*h->last_pocs) * (MAX_DELAYED_PIC_COUNT - 1));
- h->last_pocs[MAX_DELAYED_PIC_COUNT - 1] = cur->poc;
if (!out_of_order && pics > h->avctx->has_b_frames) {
h->next_output_pic = out;
- if (out->mmco_reset) {
- if (out_idx > 0) {
- h->next_outputed_poc = out->poc;
- h->delayed_pic[out_idx - 1]->mmco_reset = out->mmco_reset;
- } else {
- h->next_outputed_poc = INT_MIN;
- }
- } else {
- if (out_idx == 0 && pics > 1 && h->delayed_pic[0]->f.key_frame) {
- h->next_outputed_poc = INT_MIN;
- } else {
- h->next_outputed_poc = out->poc;
- }
- }
- h->mmco_reset = 0;
+ if (out_idx == 0 && h->delayed_pic[0] && (h->delayed_pic[0]->f.key_frame || h->delayed_pic[0]->mmco_reset)) {
+ h->next_outputed_poc = INT_MIN;
+ } else
+ h->next_outputed_poc = out->poc;
} else {
- av_log(h->avctx, AV_LOG_DEBUG, "no picture\n");
+ av_log(h->avctx, AV_LOG_DEBUG, "no picture %s\n", out_of_order ? "ooo" : "");
+ }
+
+ if (h->next_output_pic && h->next_output_pic->sync) {
+ h->sync |= 2;
}
if (setup_finished && !h->avctx->hwaccel)
@@ -2297,7 +2336,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;
@@ -2586,30 +2625,43 @@ 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;
}
/* forget old pics after a seek */
@@ -2618,7 +2670,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;
@@ -2740,19 +2792,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 ));
}
}
@@ -2762,10 +2814,6 @@ 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);
@@ -2803,12 +2851,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;
@@ -2901,7 +2951,8 @@ static int h264_set_parameter_from_sps(H264Context *h)
"VDPAU decoding does not support video colorspace.\n");
return AVERROR_INVALIDDATA;
}
- if (h->sps.bit_depth_luma >= 8 && h->sps.bit_depth_luma <= 10) {
+ 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;
@@ -2912,6 +2963,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);
@@ -2924,7 +2976,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:
@@ -2949,22 +3001,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:
@@ -2979,6 +3062,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 &&
@@ -3066,7 +3151,9 @@ static int h264_slice_header_init(H264Context *h, int reinit)
H264Context *c;
c = h->thread_context[i] = av_mallocz(sizeof(H264Context));
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;
@@ -3074,6 +3161,7 @@ static int h264_slice_header_init(H264Context *h, int reinit)
c->sps = h->sps;
c->pps = h->pps;
c->pixel_shift = h->pixel_shift;
+ c->cur_chroma_format_idc = h->cur_chroma_format_idc;
c->width = h->width;
c->height = h->height;
c->linesize = h->linesize;
@@ -3123,16 +3211,16 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
{
unsigned int first_mb_in_slice;
unsigned int pps_id;
- int num_ref_idx_active_override_flag, max_refs, ret;
+ int num_ref_idx_active_override_flag, 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;
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)) {
@@ -3153,7 +3241,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 -1;
}
if (slice_type > 4) {
@@ -3163,10 +3251,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;
@@ -3175,7 +3259,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 -1;
}
if (!h0->pps_buffers[pps_id]) {
@@ -3200,6 +3284,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;
@@ -3214,9 +3305,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);
@@ -3235,8 +3334,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;
@@ -3249,6 +3348,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) {
@@ -3259,7 +3359,7 @@ 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;
@@ -3279,7 +3379,7 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
return -1;
}
- if ((ret = get_pixel_format(h)) < 0)
+ if ((ret = get_pixel_format(h, 1)) < 0)
return ret;
h->avctx->pix_fmt = ret;
@@ -3305,6 +3405,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;
+ }
if (get_bits1(&h->gb)) { // field_pic_flag
h->picture_structure = PICT_TOP_FIELD + get_bits1(&h->gb); // bottom_field_flag
} else {
@@ -3332,7 +3436,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;
@@ -3352,12 +3456,18 @@ 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 (!last_pic_droppable && 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
@@ -3399,11 +3509,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;
if (h264_frame_start(h) < 0)
return -1;
h->prev_frame_num++;
@@ -3450,6 +3563,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. */
@@ -3473,13 +3588,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");
@@ -3489,7 +3623,7 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
h->resync_mb_y = h->mb_y = (first_mb_in_slice / h->mb_width) << 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;
@@ -3526,19 +3660,26 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
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)
@@ -3549,18 +3690,12 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
h->list_count = 0;
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;
- }
-
- 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 &&
ff_h264_decode_ref_pic_list_reordering(h) < 0) {
@@ -3696,10 +3831,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++) {
@@ -3735,6 +3876,9 @@ 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];
+
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",
@@ -3791,7 +3935,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]];
@@ -3806,7 +3950,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]);
@@ -3839,7 +3983,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);
@@ -4112,7 +4256,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,
@@ -4122,12 +4266,12 @@ 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
+ er->ref_count = h->ref_count[0];
+ ff_er_add_slice(er, startx, starty, endx, endy, status);
+ }
}
static int decode_slice(struct AVCodecContext *avctx, void *arg)
@@ -4137,16 +4281,27 @@ 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) {
+ 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);
/* init cabac */
- ff_init_cabac_states();
ff_init_cabac_decoder(&h->cabac,
h->gb.buffer + get_bits_count(&h->gb) / 8,
(get_bits_left(&h->gb) + 7) / 8);
@@ -4182,7 +4337,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,
@@ -4253,7 +4410,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);
@@ -4261,7 +4419,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 -1;
@@ -4309,9 +4467,13 @@ static int execute_decode_slices(H264Context *h, int context_count)
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,
@@ -4323,8 +4485,10 @@ 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;
@@ -4341,7 +4505,13 @@ 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;
+
+ 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;
@@ -4350,6 +4520,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;
@@ -4409,16 +4586,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,
@@ -4442,38 +4617,56 @@ 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;
+ }
+
// FIXME do not discard SEI id
if (avctx->skip_frame >= AVDISCARD_NONREF && h->nal_ref_idc == 0)
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)) {
- av_log(avctx, AV_LOG_INFO, "Ignoring NAL unit %d during "
- "extradata parsing\n", hx->nal_unit_type);
- hx->nal_unit_type = NAL_FF_IGNORE;
+ if (parse_extradata) {
+ switch (hx->nal_unit_type) {
+ case NAL_IDR_SLICE:
+ case NAL_SLICE:
+ case NAL_DPA:
+ case NAL_DPB:
+ case NAL_DPC:
+ case NAL_AUXILIARY_SLICE:
+ 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;
+ }
}
+
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");
buf_index = -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 =
@@ -4483,9 +4676,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))
@@ -4542,6 +4756,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 &&
@@ -4560,19 +4777,18 @@ again:
break;
case NAL_SPS:
init_get_bits(&h->gb, ptr, bit_length);
- if (ff_h264_decode_seq_parameter_set(h) < 0 &&
- h->is_avc && (nalsize != consumed) && nalsize) {
+ if (ff_h264_decode_seq_parameter_set(h) < 0 && (h->is_avc ? (nalsize != consumed) && 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);
}
- if (h264_set_parameter_from_sps(h) < 0) {
- buf_index = -1;
- goto end;
- }
break;
case NAL_PPS:
init_get_bits(&h->gb, ptr, bit_length);
@@ -4637,21 +4853,22 @@ 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)
+ 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;
@@ -4665,17 +4882,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];
@@ -4694,7 +4912,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;
@@ -4702,19 +4921,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 -1;
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 -1;
}
@@ -4726,14 +4968,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);
+ }
}
}
@@ -4759,6 +5005,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);
@@ -4783,6 +5030,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",
.type = AVMEDIA_TYPE_VIDEO,
@@ -4799,6 +5066,7 @@ 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
@@ -4816,5 +5084,6 @@ AVCodec ff_h264_vdpau_decoder = {
.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 484c9d3..61e1bcb 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,6 +125,7 @@ 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;
@@ -224,7 +228,7 @@ 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;
@@ -255,7 +259,6 @@ typedef struct MMCO {
*/
typedef struct H264Context {
AVCodecContext *avctx;
- DSPContext dsp;
VideoDSPContext vdsp;
H264DSPContext h264dsp;
H264ChromaContext h264chroma;
@@ -263,6 +266,7 @@ typedef struct H264Context {
MotionEstContext me;
ParseContext parse_context;
GetBitContext gb;
+ DSPContext dsp;
ERContext er;
Picture *DPB;
@@ -445,12 +449,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 +551,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 +574,7 @@ typedef struct H264Context {
enum AVPictureType pict_type;
int last_slice_type;
+ unsigned int last_ref_count[2];
/** @} */
/**
@@ -610,6 +615,18 @@ 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;
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 +637,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 +739,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);
diff --git a/libavcodec/h264_cabac.c b/libavcodec/h264_cabac.c
index c0e3356..60048e0 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 "config.h"
#include "cabac.h"
@@ -36,14 +37,12 @@
#include "h264data.h"
#include "h264_mvpred.h"
#include "golomb.h"
+#include "libavutil/avassert.h"
#if ARCH_X86
#include "x86/h264_i386.h"
#endif
-//#undef NDEBUG
-#include <assert.h>
-
/* Cabac pre state table */
static const int8_t cabac_context_init_I[1024][2] =
@@ -1619,7 +1618,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 +1666,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 +1678,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 +1708,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 +1727,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 ;
@@ -1879,6 +1878,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;
@@ -1921,7 +1921,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++;
@@ -1974,7 +1974,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;
@@ -2020,6 +2020,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 ) ) {
@@ -2088,11 +2091,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
@@ -2174,11 +2176,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
@@ -2202,11 +2204,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
@@ -2233,15 +2235,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
@@ -2279,6 +2281,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 f6abb03..dad819f 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,9 +35,8 @@
#include "h264data.h" // FIXME FIXME FIXME
#include "h264_mvpred.h"
#include "golomb.h"
+#include "libavutil/avassert.h"
-//#undef NDEBUG
-#include <assert.h>
static const uint8_t golomb_to_inter_cbp_gray[16]={
0, 1, 2, 4, 8, 3, 5,10,12,15, 7,11,13,14, 6, 9,
@@ -360,7 +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];
@@ -479,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);
@@ -511,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");
@@ -519,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;
@@ -548,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;
@@ -565,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);
}
}
@@ -581,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; \
@@ -596,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; \
@@ -609,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;
}
@@ -636,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++){
@@ -697,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;
@@ -741,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:
@@ -777,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);
@@ -843,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){
@@ -856,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)){
@@ -936,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;
}
@@ -967,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;
}
@@ -1000,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;
}
@@ -1061,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)){
@@ -1113,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;
}
}
@@ -1127,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 719ebee..2d93c2a 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
*/
@@ -209,6 +209,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;
@@ -288,8 +289,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){
@@ -478,8 +479,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 278f1f5..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,9 +34,6 @@
#include "mathops.h"
#include "rectangle.h"
-//#undef NDEBUG
-#include <assert.h>
-
/* Deblocking filter (p153) */
static const uint8_t alpha_table[52*3] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -244,7 +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);
@@ -417,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;
@@ -581,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 ) {
@@ -664,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) {
@@ -706,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 276751e..2dea933 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
*/
@@ -62,10 +62,12 @@ static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
const uint8_t *buf, int buf_size,
int keyframe) {
H264BSFContext *ctx = bsfc->priv_data;
+ int i;
uint8_t unit_type;
int32_t nal_size;
uint32_t cumul_size = 0;
const uint8_t *buf_end = buf + buf_size;
+ int ret = AVERROR(EINVAL);
/* nothing to filter */
if (!avctx->extradata || avctx->extradata_size < 6) {
@@ -84,17 +86,11 @@ static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
/* retrieve length coded size */
ctx->length_size = (*extradata++ & 0x3) + 1;
- if (ctx->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;
}
@@ -118,7 +114,7 @@ static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
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)
@@ -144,15 +140,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;
@@ -162,15 +155,15 @@ 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,
+ if ((ret=alloc_and_copy(poutbuf, poutbuf_size,
NULL, 0,
- buf, nal_size) < 0)
+ buf, nal_size)) < 0)
goto fail;
if (!ctx->first_idr && unit_type == 1)
ctx->first_idr = 1;
@@ -185,7 +178,7 @@ static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
fail:
av_freep(poutbuf);
*poutbuf_size = 0;
- return AVERROR(EINVAL);
+ return ret;
}
AVBitStreamFilter ff_h264_mp4toannexb_bsf = {
diff --git a/libavcodec/h264_mvpred.h b/libavcodec/h264_mvpred.h
index 586772f..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,9 +31,8 @@
#include "internal.h"
#include "avcodec.h"
#include "h264.h"
+#include "libavutil/avassert.h"
-//#undef NDEBUG
-#include <assert.h>
static av_always_inline int fetch_diagonal_mv(H264Context *h, const int16_t **C,
int i, int list, int part_width)
@@ -103,7 +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
@@ -482,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;
@@ -607,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;
@@ -664,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 e5d2c03..51230e2 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,40 +25,58 @@
* @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){
#if HAVE_FAST_UNALIGNED
/* we check i<buf_size instead of i+3/7 because its simpler
* and there should be FF_INPUT_BUFFER_PADDING_SIZE bytes at the end
*/
# if HAVE_FAST_64BIT
- while(i<buf_size && !((~*(const uint64_t*)(buf+i) & (*(const uint64_t*)(buf+i) - 0x0101010101010101ULL)) & 0x8080808080808080ULL))
+ while(i<next_avc && !((~*(const uint64_t*)(buf+i) & (*(const uint64_t*)(buf+i) - 0x0101010101010101ULL)) & 0x8080808080808080ULL))
i+=8;
# else
- while(i<buf_size && !((~*(const uint32_t*)(buf+i) & (*(const uint32_t*)(buf+i) - 0x01010101U)) & 0x80808080U))
+ while(i<next_avc && !((~*(const uint32_t*)(buf+i) & (*(const uint32_t*)(buf+i) - 0x01010101U)) & 0x80808080U))
i+=4;
# endif
#endif
- for(; i<buf_size; i++){
+ for(; i<next_avc; i++){
if(!buf[i]){
state=2;
break;
@@ -76,26 +94,41 @@ static int h264_find_frame_end(H264Context *h, const uint8_t *buf, int buf_size)
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);
}
/**
@@ -116,6 +149,7 @@ static inline int parse_nal_units(AVCodecParserContext *s,
unsigned int slice_type;
int state = -1;
const uint8_t *ptr;
+ int q264 = buf_size >=4 && !memcmp("Q264", buf, 4);
/* set some sane default values */
s->pict_type = AV_PICTURE_TYPE_I;
@@ -131,12 +165,25 @@ static inline int parse_nal_units(AVCodecParserContext *s,
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:
@@ -164,7 +211,7 @@ static inline int parse_nal_units(AVCodecParserContext *s,
s->key_frame = 1;
/* 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) {
@@ -232,10 +279,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;
}
@@ -252,14 +301,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);
}
}
@@ -275,7 +323,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
}
}
diff --git a/libavcodec/h264_ps.c b/libavcodec/h264_ps.c
index c6587c7..42a6903 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
*/
@@ -72,7 +72,7 @@ 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)
},
@@ -85,6 +85,36 @@ const uint8_t ff_h264_chroma_qp[3][QP_MAX_NUM+1] = {
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]={
@@ -216,7 +246,8 @@ static inline int decode_vui_parameters(H264Context *h, SPS *sps){
if(sps->nal_hrd_parameters_present_flag || 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 */
@@ -237,6 +268,7 @@ static inline int decode_vui_parameters(H264Context *h, SPS *sps){
return -1;
}
}
+
if (get_bits_left(&h->gb) < 0) {
av_log(h->avctx, AV_LOG_ERROR, "Overread VUI by %d bits\n", -get_bits_left(&h->gb));
return AVERROR_INVALIDDATA;
@@ -282,13 +314,11 @@ static void decode_scaling_matrices(H264Context *h, SPS *sps, PPS *pps, int is_s
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
}
}
@@ -306,7 +336,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);
@@ -322,10 +354,12 @@ int ff_h264_decode_seq_parameter_set(H264Context *h){
sps->profile_idc= profile_idc;
sps->constraint_set_flags = constraint_set_flags;
sps->level_idc= level_idc;
+ sps->full_range = -1;
memset(sps->scaling_matrix4, 16, sizeof(sps->scaling_matrix4));
memset(sps->scaling_matrix8, 16, sizeof(sps->scaling_matrix8));
sps->scaling_matrix_present = 0;
+ sps->colorspace = 2; //AVCOL_SPC_UNSPECIFIED
if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
sps->profile_idc == 122 || sps->profile_idc == 244 ||
@@ -333,14 +367,23 @@ 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) {
- av_log(h->avctx, AV_LOG_ERROR, "chroma_format_idc (%u) out of range\n", sps->chroma_format_idc);
+ if (sps->chroma_format_idc > 3U) {
+ av_log(h->avctx, AV_LOG_ERROR, "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);
}else{
@@ -362,7 +405,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);
@@ -382,7 +430,9 @@ int ff_h264_decode_seq_parameter_set(H264Context *h){
}
sps->ref_frame_count= get_ue_golomb_31(&h->gb);
- if(sps->ref_frame_count > MAX_PICTURE_COUNT-2 || sps->ref_frame_count >= 32U){
+ 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 > 16U){
av_log(h->avctx, AV_LOG_ERROR, "too many reference frames\n");
goto fail;
}
@@ -402,10 +452,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)
@@ -417,6 +463,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 "
@@ -441,6 +489,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;
@@ -464,7 +523,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",
+ 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 b%d reo:%d\n",
sps_id, sps->profile_idc, sps->level_idc,
sps->poc_type,
sps->ref_frame_count,
@@ -476,15 +535,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;
fail:
@@ -501,18 +560,31 @@ build_qp_table(PPS *pps, int t, int index, const int depth)
pps->chroma_qp_table[t][i] = 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 -1;
- } 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;
+ return AVERROR_INVALIDDATA;
}
pps= av_mallocz(sizeof(PPS));
@@ -523,6 +595,15 @@ 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);
+ return AVERROR_INVALIDDATA;
+ } 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);
+ return AVERROR_PATCHWELCOME;
+ }
pps->cabac= get_bits1(&h->gb);
pps->pic_order_present= get_bits1(&h->gb);
@@ -586,8 +667,7 @@ int ff_h264_decode_picture_parameter_set(H264Context *h, int bit_length){
memcpy(pps->scaling_matrix8, h->sps_buffers[pps->sps_id]->scaling_matrix8, 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);
pps->chroma_qp_index_offset[1]= get_se_golomb(&h->gb); //second_chroma_qp_index_offset
@@ -595,8 +675,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 c791973..8f6262a 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"
@@ -130,10 +131,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));
@@ -152,7 +153,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));
}
@@ -304,13 +305,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);
}
}
@@ -320,7 +327,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];
@@ -467,6 +474,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));
}
/**
@@ -508,8 +518,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;
@@ -520,10 +533,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;
@@ -542,8 +553,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;
@@ -615,7 +626,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;
@@ -642,6 +665,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);
}
@@ -680,8 +705,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
@@ -708,6 +732,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]<=1 + (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;
}
@@ -715,7 +746,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
@@ -781,6 +812,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 df4c49f..5f68a13 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
*/
@@ -45,11 +45,18 @@ 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);
h->sei_ct_type = 0;
@@ -83,8 +90,8 @@ static int decode_picture_timing(H264Context *h){
}
}
}
- if(h->sps.time_offset_length > 0)
- skip_bits(&h->gb, h->sps.time_offset_length); /* time_offset */
+ if(sps->time_offset_length > 0)
+ skip_bits(&h->gb, sps->time_offset_length); /* time_offset */
}
}
@@ -94,6 +101,42 @@ 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];
int e, build, i;
@@ -109,6 +152,8 @@ static int decode_unregistered_user_data(H264Context *h, int size){
e= sscanf(user_data+16, "x264 - core %d"/*%s - H.264/MPEG-4 AVC codec - Copyleft 2005 - http://www.videolan.org/x264.html*/, &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);
@@ -123,6 +168,9 @@ static int decode_recovery_point(H264Context *h){
h->sei_recovery_frame_cnt = get_ue_golomb(&h->gb);
skip_bits(&h->gb, 4); /* 1b exact_match_flag, 1b broken_link_flag, 2b changing_slice_group_idc */
+ 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;
}
@@ -141,13 +189,13 @@ static int decode_buffering_period(H264Context *h){
// NOTE: This is really so duplicated in the standard... See H.264, D.1.1
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);
+ h->initial_cpb_removal_delay[sched_sel_idx] = get_bits_long(&h->gb, sps->initial_cpb_removal_delay_length);
skip_bits(&h->gb, sps->initial_cpb_removal_delay_length); // initial_cpb_removal_delay_offset
}
}
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);
+ h->initial_cpb_removal_delay[sched_sel_idx] = get_bits_long(&h->gb, sps->initial_cpb_removal_delay_length);
skip_bits(&h->gb, sps->initial_cpb_removal_delay_length); // initial_cpb_removal_delay_offset
}
}
@@ -162,19 +210,30 @@ int ff_h264_decode_sei(H264Context *h){
type=0;
do{
+ if (get_bits_left(&h->gb) < 8)
+ return -1;
type+= show_bits(&h->gb, 8);
}while(get_bits(&h->gb, 8) == 255);
size=0;
do{
+ if (get_bits_left(&h->gb) < 8)
+ return -1;
size+= show_bits(&h->gb, 8);
}while(get_bits(&h->gb, 8) == 255);
+ if(h->avctx->debug&FF_DEBUG_STARTCODE)
+ av_log(h->avctx, AV_LOG_DEBUG, "SEI %d len:%d\n", type, size);
+
switch(type){
case SEI_TYPE_PIC_TIMING: // Picture timing SEI
if(decode_picture_timing(h) < 0)
return -1;
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:
if(decode_unregistered_user_data(h, size) < 0)
return -1;
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..fcc4807 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
*/
diff --git a/libavcodec/h264chroma.h b/libavcodec/h264chroma.h
index 34d9630..46fae42 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
*/
diff --git a/libavcodec/h264chroma_template.c b/libavcodec/h264chroma_template.c
index 351d9d2..93559d7 100644
--- a/libavcodec/h264chroma_template.c
+++ b/libavcodec/h264chroma_template.c
@@ -2,24 +2,24 @@
* 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"
@@ -32,9 +32,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 +63,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 +98,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 5311c21..f3fc7f9 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,14 +52,14 @@ 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,
3 + 1 * 4, 3 + 2 * 4, 2 + 3 * 4, 3 + 3 * 4,
};
-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,
@@ -93,7 +93,7 @@ static const uint8_t chroma422_dc_scan[8] = {
};
// 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,
@@ -112,7 +112,7 @@ static const uint8_t zigzag_scan8x8_cavlc[64] = {
5 + 5 * 8, 6 + 5 * 8, 6 + 6 * 8, 7 + 7 * 8,
};
-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,
@@ -131,7 +131,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,
diff --git a/libavcodec/h264dsp.c b/libavcodec/h264dsp.c
index 3ca6abe..d7238b1 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
@@ -129,7 +138,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 1f9f8fe..98ea15c 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/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..27fed9f 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
*/
@@ -153,18 +153,19 @@ 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) {
diff --git a/libavcodec/huffman.h b/libavcodec/huffman.h
index 043e6e3..4f9ccba 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
*/
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 7a58ba4..e5a9e3b 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 13c0a79..95dcb88 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,25 +55,28 @@ 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,
- int *red, int *green, int *blue)
+ const uint8_t *src, int w,
+ int *red, int *green, int *blue, int *alpha)
{
int i;
- int r,g,b;
+ int r,g,b,a;
r = *red;
g = *green;
b = *blue;
-
+ a = *alpha;
for (i = 0; i < FFMIN(w, 4); i++) {
const int rt = src[i * 4 + R];
const int gt = src[i * 4 + G];
const int bt = src[i * 4 + B];
+ const int at = src[i * 4 + A];
dst[i * 4 + R] = rt - r;
dst[i * 4 + G] = gt - g;
dst[i * 4 + B] = bt - b;
+ dst[i * 4 + A] = at - a;
r = rt;
g = gt;
b = bt;
+ a = at;
}
s->dsp.diff_bytes(dst + 16, src + 16, src + 12, w * 4 - 16);
@@ -80,6 +84,32 @@ static inline void sub_left_prediction_bgr32(HYuvContext *s, uint8_t *dst,
*red = src[(w - 1) * 4 + R];
*green = src[(w - 1) * 4 + G];
*blue = src[(w - 1) * 4 + B];
+ *alpha = src[(w - 1) * 4 + A];
+}
+
+static inline void sub_left_prediction_rgb24(HYuvContext *s, uint8_t *dst, const uint8_t *src, int w, int *red, int *green, int *blue){
+ int i;
+ int r,g,b;
+ r = *red;
+ g = *green;
+ b = *blue;
+ for (i = 0; i < FFMIN(w,16); i++) {
+ const int rt = src[i*3 + 0];
+ const int gt = src[i*3 + 1];
+ const int bt = src[i*3 + 2];
+ dst[i*3 + 0] = rt - r;
+ dst[i*3 + 1] = gt - g;
+ dst[i*3 + 2] = bt - b;
+ r = rt;
+ g = gt;
+ b = bt;
+ }
+
+ s->dsp.diff_bytes(dst + 48, src + 48, src + 48 - 3, w*3 - 48);
+
+ *red = src[(w - 1)*3 + 0];
+ *green = src[(w - 1)*3 + 1];
+ *blue = src[(w - 1)*3 + 2];
}
static int store_table(HYuvContext *s, const uint8_t *len, uint8_t *buf)
@@ -94,8 +124,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 {
@@ -115,23 +145,32 @@ 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;
switch (avctx->pix_fmt) {
case AV_PIX_FMT_YUV420P:
- s->bitstream_bpp = 12;
- break;
case AV_PIX_FMT_YUV422P:
- s->bitstream_bpp = 16;
+ if (s->width & 1) {
+ av_log(avctx, AV_LOG_ERROR, "width must be even for this colorspace\n");
+ return AVERROR(EINVAL);
+ }
+ s->bitstream_bpp = avctx->pix_fmt == AV_PIX_FMT_YUV420P ? 12 : 16;
break;
case AV_PIX_FMT_RGB32:
+ s->bitstream_bpp = 32;
+ break;
+ case AV_PIX_FMT_RGB24:
s->bitstream_bpp = 24;
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;
@@ -143,7 +182,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;
@@ -152,13 +191,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,
@@ -168,7 +207,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);
@@ -232,7 +271,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;
@@ -338,27 +380,30 @@ static int encode_gray_bitstream(HYuvContext *s, int count)
return 0;
}
-static int encode_bgr_bitstream(HYuvContext *s, int count)
+static inline int encode_bgra_bitstream(HYuvContext *s, int count, int planes)
{
int i;
- if (s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb) >> 3) < 3 * 4 * count) {
+ if (s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < 4*planes*count) {
av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
return -1;
}
#define LOAD3\
- int g = s->temp[0][4 * i + G];\
- int b = (s->temp[0][4 * i + B] - g) & 0xff;\
- int r = (s->temp[0][4 * i + R] - g) & 0xff;
+ 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 a = s->temp[0][planes*i + A];
#define STAT3\
s->stats[0][b]++;\
s->stats[1][g]++;\
- s->stats[2][r]++;
+ s->stats[2][r]++;\
+ if(planes==4) s->stats[2][a]++;
#define WRITE3\
put_bits(&s->pb, s->len[1][g], s->bits[1][g]);\
put_bits(&s->pb, s->len[0][b], s->bits[0][b]);\
- put_bits(&s->pb, s->len[2][r], s->bits[2][r]);
+ put_bits(&s->pb, s->len[2][r], s->bits[2][r]);\
+ if(planes==4) put_bits(&s->pb, s->len[2][a], s->bits[2][a]);
if ((s->flags & CODEC_FLAG_PASS1) &&
(s->avctx->flags2 & CODEC_FLAG2_NO_OUTPUT)) {
@@ -394,11 +439,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;
@@ -529,25 +571,50 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const int stride = -p->linesize[0];
const int fake_stride = -fake_ystride;
int y;
- int leftr, leftg, leftb;
+ int leftr, leftg, leftb, lefta;
+ put_bits(&s->pb, 8, lefta = data[A]);
put_bits(&s->pb, 8, leftr = data[R]);
put_bits(&s->pb, 8, leftg = data[G]);
put_bits(&s->pb, 8, leftb = data[B]);
- put_bits(&s->pb, 8, 0);
- sub_left_prediction_bgr32(s, s->temp[0], data + 4, width - 1, &leftr, &leftg, &leftb);
- encode_bgr_bitstream(s, width - 1);
+ sub_left_prediction_bgr32(s, s->temp[0], data + 4, width - 1, &leftr, &leftg, &leftb, &lefta);
+ encode_bgra_bitstream(s, width - 1, 4);
for (y = 1; y < s->height; y++) {
uint8_t *dst = data + y*stride;
if (s->predictor == PLANE && s->interlaced < y) {
s->dsp.diff_bytes(s->temp[1], dst, dst - fake_stride, width * 4);
- sub_left_prediction_bgr32(s, s->temp[0], s->temp[1], width, &leftr, &leftg, &leftb);
+ sub_left_prediction_bgr32(s, s->temp[0], s->temp[1], width, &leftr, &leftg, &leftb, &lefta);
} else {
- sub_left_prediction_bgr32(s, s->temp[0], dst, width, &leftr, &leftg, &leftb);
+ sub_left_prediction_bgr32(s, s->temp[0], dst, width, &leftr, &leftg, &leftb, &lefta);
+ }
+ encode_bgra_bitstream(s, width, 4);
+ }
+ }else if(avctx->pix_fmt == AV_PIX_FMT_RGB24){
+ uint8_t *data = p->data[0] + (height-1)*p->linesize[0];
+ const int stride = -p->linesize[0];
+ const int fake_stride = -fake_ystride;
+ int y;
+ int leftr, leftg, leftb;
+
+ put_bits(&s->pb, 8, leftr= data[0]);
+ put_bits(&s->pb, 8, leftg= data[1]);
+ put_bits(&s->pb, 8, leftb= data[2]);
+ put_bits(&s->pb, 8, 0);
+
+ sub_left_prediction_rgb24(s, s->temp[0], data+3, width-1, &leftr, &leftg, &leftb);
+ encode_bgra_bitstream(s, width-1, 3);
+
+ for(y=1; y<s->height; y++){
+ uint8_t *dst = data + y*stride;
+ if(s->predictor == PLANE && s->interlaced < y){
+ s->dsp.diff_bytes(s->temp[1], dst, dst - fake_stride, width*3);
+ sub_left_prediction_rgb24(s, s->temp[0], s->temp[1], width, &leftr, &leftg, &leftb);
+ }else{
+ sub_left_prediction_rgb24(s, s->temp[0], dst, width, &leftr, &leftg, &leftb);
}
- encode_bgr_bitstream(s, width);
+ encode_bgra_bitstream(s, width, 3);
}
} else {
av_log(avctx, AV_LOG_ERROR, "Format not supported!\n");
@@ -610,7 +677,7 @@ AVCodec ff_huffyuv_encoder = {
.encode2 = encode_frame,
.close = encode_end,
.pix_fmts = (const enum AVPixelFormat[]){
- AV_PIX_FMT_YUV422P, AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE
+ AV_PIX_FMT_YUV422P, AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE
},
.long_name = NULL_IF_CONFIG_SMALL("Huffyuv / HuffYUV"),
};
@@ -626,7 +693,7 @@ AVCodec ff_ffvhuff_encoder = {
.encode2 = encode_frame,
.close = encode_end,
.pix_fmts = (const enum AVPixelFormat[]){
- AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE
},
.long_name = NULL_IF_CONFIG_SMALL("Huffyuv FFmpeg variant"),
};
diff --git a/libavcodec/idcinvideo.c b/libavcodec/idcinvideo.c
index 9d34f3e..3596080 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 184dcab..716a731 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,19 +141,27 @@ 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;
@@ -143,6 +170,153 @@ static int cmap_read_palette(AVCodecContext *avctx, uint32_t *pal)
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;
}
@@ -152,11 +326,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;
}
@@ -168,7 +360,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;
}
@@ -183,6 +381,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);
@@ -215,6 +417,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.
*
@@ -246,110 +489,368 @@ 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; 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,
+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;
@@ -360,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",
+ .name = "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,
- .long_name = NULL_IF_CONFIG_SMALL("IFF ILBM"),
+ .long_name = NULL_IF_CONFIG_SMALL("IFF"),
};
-
+#endif
+#if CONFIG_IFF_BYTERUN1_DECODER
AVCodec ff_iff_byterun1_decoder = {
- .name = "iff_byterun1",
+ .name = "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,
- .long_name = NULL_IF_CONFIG_SMALL("IFF ByteRun1"),
+ .long_name = NULL_IF_CONFIG_SMALL("IFF"),
};
+#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 2749099..eb7c255 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"
@@ -343,7 +344,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];
@@ -803,6 +804,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;
@@ -939,10 +947,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];
@@ -977,7 +983,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",
.type = AVMEDIA_TYPE_AUDIO,
@@ -986,12 +1000,14 @@ AVCodec ff_imc_decoder = {
.init = imc_decode_init,
.close = imc_decode_close,
.decode = imc_decode_frame,
+ .flush = flush,
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("IMC (Intel Music Coder)"),
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE },
};
-
+#endif
+#if CONFIG_IAC_DECODER
AVCodec ff_iac_decoder = {
.name = "iac",
.type = AVMEDIA_TYPE_AUDIO,
@@ -1000,8 +1016,10 @@ AVCodec ff_iac_decoder = {
.init = imc_decode_init,
.close = imc_decode_close,
.decode = imc_decode_frame,
+ .flush = flush,
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("IAC (Indeo Audio Coder)"),
.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..e872035 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,220 @@
#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->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;
+
+ 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;
+ }
+ // dont 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;
}
+#if AV_HAVE_INCOMPATIBLE_FORK_ABI
enum AVPixelFormat avcodec_find_best_pix_fmt2(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(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 +363,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 +388,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 +635,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..9f276bc 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
*/
diff --git a/libavcodec/indeo2.c b/libavcodec/indeo2.c
index a33bbb1..f8e7415 100644
--- a/libavcodec/indeo2.c
+++ b/libavcodec/indeo2.c
@@ -2,20 +2,20 @@
* Intel Indeo 2 codec
* Copyright (c) 2005 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -149,10 +149,8 @@ static int ir2_decode_frame(AVCodecContext *avctx,
AVFrame * const p = &s->picture;
int start, ret;
- if ((ret = ff_reget_buffer(avctx, p)) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, p)) < 0)
return ret;
- }
start = 48; /* hardcoded for now */
@@ -215,6 +213,7 @@ static av_cold int ir2_decode_init(AVCodecContext *avctx)
Ir2Context * const ic = avctx->priv_data;
static VLC_TYPE vlc_tables[1 << CODE_VLC_BITS][2];
+ avcodec_get_frame_defaults(&ic->picture);
ic->avctx = avctx;
avctx->pix_fmt= AV_PIX_FMT_YUV410P;
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 f9bfc0e..a6658b7 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"
@@ -148,14 +149,11 @@ static av_cold void build_requant_tab(void)
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 +162,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);
@@ -206,6 +207,9 @@ 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]);
@@ -230,8 +234,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 +340,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 +352,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 +596,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 +651,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 +779,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 +804,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 +815,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 +845,7 @@ static int parse_bintree(Indeo3DecodeContext *ctx, AVCodecContext *avctx,
}
}//while
- return 0;
+ return AVERROR_INVALIDDATA;
}
@@ -845,13 +858,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 +875,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 +950,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 +1048,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 +1090,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 +1104,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 8820a2c..5b107fb 100644
--- a/libavcodec/indeo4.c
+++ b/libavcodec/indeo4.c
@@ -56,8 +56,8 @@ static const struct {
int is_2d_trans;
} transforms[18] = {
{ ff_ivi_inverse_haar_8x8, ff_ivi_dc_haar_2d, 1 },
- { NULL, NULL, 0 }, /* inverse Haar 8x1 */
- { NULL, NULL, 0 }, /* inverse Haar 1x8 */
+ { ff_ivi_inverse_haar_8x1, ff_ivi_dc_haar_2d, 1 },
+ { ff_ivi_inverse_haar_1x8, ff_ivi_dc_haar_2d, 1 },
{ ff_ivi_put_pixels_8x8, ff_ivi_put_dc_pixel_8x8, 1 },
{ ff_ivi_inverse_slant_8x8, ff_ivi_dc_slant_2d, 1 },
{ ff_ivi_row_slant8, ff_ivi_dc_row_slant, 1 },
@@ -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;
@@ -282,6 +283,7 @@ static int decode_band_hdr(IVI45DecContext *ctx, IVIBandDesc *band,
{
int plane, band_num, indx, transform_id, scan_indx;
int i;
+ int quant_mat;
plane = get_bits(&ctx->gb, 2);
band_num = get_bits(&ctx->gb, 4);
@@ -338,6 +340,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;
@@ -346,19 +352,43 @@ 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;
+ band->transform_size= (transform_id < 10) ? 8 : 4;
scan_indx = get_bits(&ctx->gb, 4);
+ if ((scan_indx>4 && scan_indx<10) != (band->blk_size==4)) {
+ av_log(avctx, AV_LOG_ERROR, "mismatching scan table!\n");
+ return AVERROR_INVALIDDATA;
+ }
if (scan_indx == 15) {
av_log(avctx, AV_LOG_ERROR, "Custom scan pattern encountered!\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 == 31) {
+ quant_mat = get_bits(&ctx->gb, 5);
+ if (quant_mat == 31) {
av_log(avctx, AV_LOG_ERROR, "Custom quant matrix encountered!\n");
return AVERROR_INVALIDDATA;
}
+ if (quant_mat > 21) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid quant matrix encountered!\n");
+ return AVERROR_INVALIDDATA;
+ }
+ band->quant_mat = quant_mat;
+ }
+ 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 */
@@ -399,6 +429,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;
}
@@ -417,7 +452,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;
@@ -432,6 +467,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;
@@ -456,7 +496,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);
@@ -467,7 +507,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 ||
ctx->frame_type == FRAMETYPE_INTRA1) {
@@ -491,7 +531,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);
@@ -514,6 +554,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/indeo5.c b/libavcodec/indeo5.c
index dc5f6f0..65bd9f2 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 -1;
@@ -120,6 +120,7 @@ static int decode_gop_header(IVI45DecContext *ctx, AVCodecContext *avctx)
return -1;
}
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;
@@ -150,30 +156,35 @@ static int decode_gop_header(IVI45DecContext *ctx, AVCodecContext *avctx)
band->inv_transform = ff_ivi_inverse_slant_8x8;
band->dc_transform = ff_ivi_dc_slant_2d;
band->scan = ff_zigzag_direct;
+ band->transform_size= 8;
break;
case 1:
band->inv_transform = ff_ivi_row_slant8;
band->dc_transform = ff_ivi_dc_row_slant;
band->scan = ff_ivi_vertical_scan_8x8;
+ band->transform_size= 8;
break;
case 2:
band->inv_transform = ff_ivi_col_slant8;
band->dc_transform = ff_ivi_dc_col_slant;
band->scan = ff_ivi_horizontal_scan_8x8;
+ band->transform_size= 8;
break;
case 3:
band->inv_transform = ff_ivi_put_pixels_8x8;
band->dc_transform = ff_ivi_put_dc_pixel_8x8;
band->scan = ff_ivi_horizontal_scan_8x8;
+ band->transform_size= 8;
break;
case 4:
band->inv_transform = ff_ivi_inverse_slant_4x4;
band->dc_transform = ff_ivi_dc_slant_2d;
band->scan = ff_ivi_direct_scan_4x4;
+ band->transform_size= 4;
break;
}
@@ -188,6 +199,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];
@@ -224,6 +239,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 */
@@ -312,6 +328,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);
@@ -418,7 +440,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;
@@ -464,7 +486,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);
@@ -475,7 +497,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 */
@@ -501,7 +523,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);
@@ -524,6 +546,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++;
@@ -632,7 +663,6 @@ static av_cold int decode_init(AVCodecContext *avctx)
return 0;
}
-
AVCodec ff_indeo5_decoder = {
.name = "indeo5",
.type = AVMEDIA_TYPE_VIDEO,
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 0701cde..ac2695e 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..4962f06 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().
+ */
+ int 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,23 @@ 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]);
+
+/**
+ * Remove and free all side data from packet.
+ */
+void ff_packet_free_side_data(AVPacket *pkt);
+
+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 +166,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 +176,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, int size);
+
int ff_alloc_packet(AVPacket *avpkt, int size);
/**
@@ -145,6 +186,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 +205,31 @@ 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 ff_get_logical_cpus(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 b76fe6d..4f710b8 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 b81a9ca..1d02ec3 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
@@ -728,7 +730,6 @@ av_cold void ff_intrax8_common_end(IntraX8Context * w)
int ff_intrax8_decode_picture(IntraX8Context * const w, int dquant, int quant_offset){
MpegEncContext * const s= w->s;
int mb_xy;
- assert(s);
w->use_quant_matrix = get_bits1(&s->gb);
w->dquant = dquant;
diff --git a/libavcodec/intrax8.h b/libavcodec/intrax8.h
index 6967317..9981785 100644
--- a/libavcodec/intrax8.h
+++ b/libavcodec/intrax8.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,6 +22,7 @@
#include "get_bits.h"
#include "mpegvideo.h"
#include "intrax8dsp.h"
+#include "wmv2dsp.h"
typedef struct IntraX8Context {
VLC * j_ac_vlc[4];//they point to the static j_mb_vlc
@@ -32,6 +33,8 @@ typedef struct IntraX8Context {
//set by ff_intrax8_common_init
uint8_t * prediction_table;//2*(mb_w*2)
ScanTable scantable[3];
+ WMV2DSPContext wdsp;
+ uint8_t idct_permutation[64];
//set by the caller codec
MpegEncContext * s;
IntraX8DSPContext dsp;
diff --git a/libavcodec/intrax8dsp.c b/libavcodec/intrax8dsp.c
index 1115945..1b34f89 100644
--- a/libavcodec/intrax8dsp.c
+++ b/libavcodec/intrax8dsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/intrax8dsp.h b/libavcodec/intrax8dsp.h
index 5c3cc4a..1e4a3af 100644
--- a/libavcodec/intrax8dsp.h
+++ b/libavcodec/intrax8dsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/intrax8huf.h b/libavcodec/intrax8huf.h
index 6bf01f3..375906b 100644
--- a/libavcodec/intrax8huf.h
+++ b/libavcodec/intrax8huf.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ituh263dec.c b/libavcodec/ituh263dec.c
index 25dd4d9..6d06a09 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);
@@ -958,6 +964,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) {
@@ -1069,6 +1077,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;
@@ -1125,7 +1137,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 f11b729..250c6da 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
*/
@@ -59,7 +59,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
@@ -168,7 +168,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)
@@ -203,6 +203,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]);
@@ -264,6 +265,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);
@@ -295,6 +297,8 @@ av_cold int ff_ivi_init_tiles(IVIPlaneDesc *planes, int tile_width, int tile_hei
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];
@@ -332,7 +336,10 @@ av_cold int ff_ivi_init_tiles(IVIPlaneDesc *planes, int tile_width, int tile_hei
tile->ref_mbs = 0;
if (p || b) {
- tile->ref_mbs = ref_tile->mbs;
+ if (tile->num_MBs <= ref_tile->num_MBs) {
+ tile->ref_mbs = ref_tile->mbs;
+ }else
+ av_log(NULL, AV_LOG_DEBUG, "Cannot use ref_tile, too few mbs\n");
ref_tile++;
}
@@ -388,10 +395,10 @@ static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band, IVITile *tile
AVCodecContext *avctx)
{
int mbn, blk, num_blocks, num_coeffs, blk_size, scan_pos, run, val,
- pos, is_intra, mc_type = 0, mv_x, mv_y, col_mask;
+ pos, is_intra, mc_type = 0, av_uninit(mv_x), av_uninit(mv_y), col_mask;
uint8_t col_flags[8];
int32_t prev_dc, trvec[64];
- uint32_t cbp, sym, lo, hi, quant, buf_offs, q;
+ uint32_t cbp, av_uninit(sym), lo, hi, quant, buf_offs, q;
IVIMbInfo *mb;
RVMapDesc *rvmap = band->rv_map;
void (*mc_with_delta_func)(int16_t *buf, const int16_t *ref_buf, uint32_t pitch, int mc_type);
@@ -490,7 +497,7 @@ static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band, IVITile *tile
/* de-zigzag and dequantize */
scan_pos += run;
- if (scan_pos >= num_coeffs)
+ if (scan_pos >= (unsigned)num_coeffs)
break;
pos = band->scan[scan_pos];
@@ -513,7 +520,10 @@ static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band, IVITile *tile
trvec[0] = prev_dc;
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 + buf_offs,
band->pitch, col_flags);
@@ -528,7 +538,6 @@ static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band, IVITile *tile
/* for intra blocks apply the dc slant transform */
/* for inter - perform the motion compensation without delta */
if (is_intra) {
- if (band->dc_transform)
band->dc_transform(&prev_dc, band->buf + buf_offs,
band->pitch, blk_size);
} else
@@ -599,7 +608,7 @@ static int ivi_process_empty_tile(AVCodecContext *avctx, IVIBandDesc *band,
if (band->inherit_qdelta && ref_mb)
mb->q_delta = ref_mb->q_delta;
- 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);
@@ -609,6 +618,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++;
@@ -743,6 +768,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);
@@ -766,7 +795,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);
@@ -789,6 +819,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
@@ -839,6 +873,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);
@@ -849,7 +884,10 @@ int ff_ivi_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
}
}
}
+ ctx->buf_invalid[ctx->dst_buf] = 0;
}
+ if (ctx->buf_invalid[ctx->dst_buf])
+ return -1;
//STOP_TIMER("decode_planes"); }
@@ -863,11 +901,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 aeb6b15..130fd12 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
@@ -161,6 +162,7 @@ typedef struct IVIBandDesc {
InvTransformPtr *inv_transform;
DCTransformPtr *dc_transform;
int is_2d_trans; ///< 1 indicates that the two-dimensional inverse transform is used
+ int transform_size; ///< block size of the transform
int32_t checksum; ///< for debug purposes
int checksum_present;
int bufsize; ///< band buffer size in bytes
@@ -246,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 f5efa65..9c35aa0 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 */
@@ -310,6 +320,60 @@ void ff_ivi_inverse_haar_8x8(const int32_t *in, int16_t *out, uint32_t pitch,
#undef COMPENSATE
}
+void ff_ivi_inverse_haar_1x8(const int32_t *in, int16_t *out, uint32_t pitch,
+ const uint8_t *flags)
+{
+ int i;
+ const int32_t *src;
+ int t0, t1, t2, t3, t4, t5, t6, t7, t8;
+
+ /* apply the InvHaar8 to all columns */
+#define COMPENSATE(x) (x)
+ src = in;
+ for (i = 0; i < 8; i++) {
+ if (flags[i]) {
+ INV_HAAR8(src[ 0], src[ 8], src[16], src[24],
+ src[32], src[40], src[48], src[56],
+ out[ 0], out[pitch], out[2*pitch], out[3*pitch],
+ out[4*pitch], out[5*pitch], out[6*pitch], out[7*pitch],
+ t0, t1, t2, t3, t4, t5, t6, t7, t8);
+ } else
+ out[ 0]= out[ pitch]= out[2*pitch]= out[3*pitch]=
+ out[4*pitch]= out[5*pitch]= out[6*pitch]= out[7*pitch]= 0;
+
+ src++;
+ out++;
+ }
+#undef COMPENSATE
+}
+
+void ff_ivi_inverse_haar_8x1(const int32_t *in, int16_t *out, uint32_t pitch,
+ const uint8_t *flags)
+{
+ int i;
+ const int32_t *src;
+ int t0, t1, t2, t3, t4, t5, t6, t7, t8;
+
+ /* apply the InvHaar8 to all rows */
+#define COMPENSATE(x) (x)
+ src = in;
+ for (i = 0; i < 8; i++) {
+ if ( !src[0] && !src[1] && !src[2] && !src[3]
+ && !src[4] && !src[5] && !src[6] && !src[7]) {
+ memset(out, 0, 8 * sizeof(out[0]));
+ } else {
+ INV_HAAR8(src[0], src[1], src[2], src[3],
+ src[4], src[5], src[6], src[7],
+ out[0], out[1], out[2], out[3],
+ out[4], out[5], out[6], out[7],
+ t0, t1, t2, t3, t4, t5, t6, t7, t8);
+ }
+ src += 8;
+ out += pitch;
+ }
+#undef COMPENSATE
+}
+
void ff_ivi_dc_haar_2d(const int32_t *in, int16_t *out, uint32_t pitch,
int blk_size)
{
diff --git a/libavcodec/ivi_dsp.h b/libavcodec/ivi_dsp.h
index c46f8b2..748b3f4 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);
/**
* DC-only two-dimensional inverse Haar transform for Indeo 4.
diff --git a/libavcodec/j2k.c b/libavcodec/j2k.c
new file mode 100644
index 0000000..e3c0c13
--- /dev/null
+++ b/libavcodec/j2k.c
@@ -0,0 +1,391 @@
+/*
+ * JPEG2000 encoder and decoder common functions
+ * 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 and decoder common functions
+ * @file
+ * @author Kamil Nowosad
+ */
+
+
+#include "avcodec.h"
+#include "j2k.h"
+
+#define SHL(a, n) ((n)>=0 ? (a) << (n) : (a) >> -(n))
+
+#if 0
+void ff_j2k_printv(int *tab, int l)
+{
+ int i;
+ for (i = 0; i < l; i++)
+ av_log(NULL, AV_LOG_DEBUG, "%.3d ", tab[i]);
+ av_log(NULL, AV_LOG_DEBUG, "\n");
+}
+
+void ff_j2k_printu(uint8_t *tab, int l)
+{
+ int i;
+ for (i = 0; i < l; i++)
+ av_log(NULL, AV_LOG_DEBUG, "%.3hd ", tab[i]);
+ av_log(NULL, AV_LOG_DEBUG, "\n");
+}
+#endif
+
+/* tag tree routines */
+
+/** allocate the memory for tag tree */
+
+static int tag_tree_size(int w, int h)
+{
+ int res = 0;
+ while (w > 1 || h > 1){
+ res += w * h;
+ w = (w+1) >> 1;
+ h = (h+1) >> 1;
+ }
+ return res + 1;
+}
+
+J2kTgtNode *ff_j2k_tag_tree_init(int w, int h)
+{
+ int pw = w, ph = h;
+ J2kTgtNode *res, *t, *t2;
+
+ t = res = av_mallocz(tag_tree_size(w, h)*sizeof(J2kTgtNode));
+
+ if (res == NULL)
+ return NULL;
+
+ while (w > 1 || h > 1){
+ int i, j;
+ pw = w;
+ ph = h;
+
+ w = (w+1) >> 1;
+ h = (h+1) >> 1;
+ t2 = t + pw*ph;
+
+ for (i = 0; i < ph; i++)
+ for (j = 0; j < pw; j++){
+ t[i*pw + j].parent = &t2[(i>>1)*w + (j>>1)];
+ }
+ t = t2;
+ }
+ t[0].parent = NULL;
+ return res;
+}
+
+static void tag_tree_zero(J2kTgtNode *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_j2k_nbctxno_lut[256][4];
+
+static int getnbctxno(int flag, int bandno, int vert_causal_ctx_csty_symbol)
+{
+ int h, v, d;
+
+ h = ((flag & J2K_T1_SIG_E) ? 1:0)+
+ ((flag & J2K_T1_SIG_W) ? 1:0);
+ v = ((flag & J2K_T1_SIG_N) ? 1:0);
+ if (!vert_causal_ctx_csty_symbol)
+ v = v + ((flag & J2K_T1_SIG_S) ? 1:0);
+ d = ((flag & J2K_T1_SIG_NE) ? 1:0)+
+ ((flag & J2K_T1_SIG_NW) ? 1:0);
+ if (!vert_causal_ctx_csty_symbol)
+ d = d + ((flag & J2K_T1_SIG_SE) ? 1:0)+
+ ((flag & J2K_T1_SIG_SW) ? 1:0);
+ if (bandno < 3){
+ if (bandno == 1)
+ FFSWAP(int, h, v);
+ if (h == 2) return 8;
+ if (h == 1){
+ 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;
+ return 0;
+ } else{
+ if (d >= 3) return 8;
+ if (d == 2){
+ if (h+v >= 1) return 7;
+ return 6;
+ }
+ if (d == 1){
+ 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;
+ return 0;
+ }
+}
+
+uint8_t ff_j2k_sgnctxno_lut[16][16], ff_j2k_xorbit_lut[16][16];
+
+static int getsgnctxno(int flag, uint8_t *xorbit)
+{
+ int vcontrib, hcontrib;
+ static const int contribtab[3][3] = {{0, -1, 1}, {-1, -1, 0}, {1, 0, 1}};
+ static const int ctxlbltab[3][3] = {{13, 12, 11}, {10, 9, 10}, {11, 12, 13}};
+ static const int xorbittab[3][3] = {{1, 1, 1,}, {1, 0, 0}, {0, 0, 0}};
+
+ hcontrib = contribtab[flag & J2K_T1_SIG_E ? flag & J2K_T1_SGN_E ? 1:2:0]
+ [flag & J2K_T1_SIG_W ? flag & J2K_T1_SGN_W ? 1:2:0]+1;
+ vcontrib = contribtab[flag & J2K_T1_SIG_S ? flag & J2K_T1_SGN_S ? 1:2:0]
+ [flag & J2K_T1_SIG_N ? flag & J2K_T1_SGN_N ? 1:2:0]+1;
+ *xorbit = xorbittab[hcontrib][vcontrib];
+ return ctxlbltab[hcontrib][vcontrib];
+}
+
+void ff_j2k_init_tier1_luts(void)
+{
+ int i, j;
+ for (i = 0; i < 256; i++)
+ for (j = 0; j < 4; j++)
+ ff_j2k_nbctxno_lut[i][j] = getnbctxno(i, j, 0);
+ for (i = 0; i < 16; i++)
+ for (j = 0; j < 16; j++)
+ ff_j2k_sgnctxno_lut[i][j] = getsgnctxno(i + (j << 8), &ff_j2k_xorbit_lut[i][j]);
+}
+
+void ff_j2k_set_significant(J2kT1Context *t1, int x, int y, int negative)
+{
+ x++; y++;
+ t1->flags[y][x] |= J2K_T1_SIG;
+ if (negative){
+ t1->flags[y][x+1] |= J2K_T1_SIG_W | J2K_T1_SGN_W;
+ t1->flags[y][x-1] |= J2K_T1_SIG_E | J2K_T1_SGN_E;
+ t1->flags[y+1][x] |= J2K_T1_SIG_N | J2K_T1_SGN_N;
+ t1->flags[y-1][x] |= J2K_T1_SIG_S | J2K_T1_SGN_S;
+ } else{
+ t1->flags[y][x+1] |= J2K_T1_SIG_W;
+ t1->flags[y][x-1] |= J2K_T1_SIG_E;
+ t1->flags[y+1][x] |= J2K_T1_SIG_N;
+ t1->flags[y-1][x] |= J2K_T1_SIG_S;
+ }
+ t1->flags[y+1][x+1] |= J2K_T1_SIG_NW;
+ t1->flags[y+1][x-1] |= J2K_T1_SIG_NE;
+ t1->flags[y-1][x+1] |= J2K_T1_SIG_SW;
+ t1->flags[y-1][x-1] |= J2K_T1_SIG_SE;
+}
+
+int ff_j2k_init_component(J2kComponent *comp, J2kCodingStyle *codsty, J2kQuantStyle *qntsty, int cbps, int dx, int dy)
+{
+ int reslevelno, bandno, gbandno = 0, ret, i, j, csize = 1;
+
+ if (ret=ff_j2k_dwt_init(&comp->dwt, comp->coord, codsty->nreslevels-1, codsty->transform))
+ return ret;
+ for (i = 0; i < 2; i++)
+ csize *= comp->coord[i][1] - comp->coord[i][0];
+
+ comp->data = av_malloc(csize * sizeof(int));
+ if (!comp->data)
+ return AVERROR(ENOMEM);
+ comp->reslevel = av_malloc(codsty->nreslevels * sizeof(J2kResLevel));
+
+ if (!comp->reslevel)
+ return AVERROR(ENOMEM);
+ for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+ int declvl = codsty->nreslevels - reslevelno;
+ J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 2; j++)
+ reslevel->coord[i][j] =
+ ff_j2k_ceildivpow2(comp->coord[i][j], declvl - 1);
+
+ if (reslevelno == 0)
+ reslevel->nbands = 1;
+ else
+ reslevel->nbands = 3;
+
+ if (reslevel->coord[0][1] == reslevel->coord[0][0])
+ reslevel->num_precincts_x = 0;
+ else
+ reslevel->num_precincts_x = ff_j2k_ceildivpow2(reslevel->coord[0][1], codsty->log2_prec_width)
+ - (reslevel->coord[0][0] >> codsty->log2_prec_width);
+
+ if (reslevel->coord[1][1] == reslevel->coord[1][0])
+ reslevel->num_precincts_y = 0;
+ else
+ reslevel->num_precincts_y = ff_j2k_ceildivpow2(reslevel->coord[1][1], codsty->log2_prec_height)
+ - (reslevel->coord[1][0] >> codsty->log2_prec_height);
+
+ reslevel->band = av_malloc(reslevel->nbands * sizeof(J2kBand));
+ if (!reslevel->band)
+ return AVERROR(ENOMEM);
+ for (bandno = 0; bandno < reslevel->nbands; bandno++, gbandno++){
+ J2kBand *band = reslevel->band + bandno;
+ int cblkno, precx, precy, precno;
+ int x0, y0, x1, y1;
+ int xi0, yi0, xi1, yi1;
+ int cblkperprecw, cblkperprech;
+
+ if (qntsty->quantsty != J2K_QSTY_NONE){
+ static const uint8_t lut_gain[2][4] = {{0, 0, 0, 0}, {0, 1, 1, 2}};
+ int numbps;
+
+ numbps = cbps + lut_gain[codsty->transform][bandno + reslevelno>0];
+ band->stepsize = SHL(2048 + qntsty->mant[gbandno], 2 + numbps - qntsty->expn[gbandno]);
+ } else
+ band->stepsize = 1 << 13;
+
+ if (reslevelno == 0){ // the same everywhere
+ band->codeblock_width = 1 << FFMIN(codsty->log2_cblk_width, codsty->log2_prec_width-1);
+ band->codeblock_height = 1 << FFMIN(codsty->log2_cblk_height, codsty->log2_prec_height-1);
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 2; j++)
+ band->coord[i][j] = ff_j2k_ceildivpow2(comp->coord[i][j], declvl-1);
+ } else{
+ band->codeblock_width = 1 << FFMIN(codsty->log2_cblk_width, codsty->log2_prec_width);
+ band->codeblock_height = 1 << FFMIN(codsty->log2_cblk_height, codsty->log2_prec_height);
+
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 2; j++)
+ band->coord[i][j] = ff_j2k_ceildivpow2(comp->coord[i][j] - (((bandno+1>>i)&1) << declvl-1), declvl);
+ }
+ band->cblknx = ff_j2k_ceildiv(band->coord[0][1], band->codeblock_width) - band->coord[0][0] / band->codeblock_width;
+ band->cblkny = ff_j2k_ceildiv(band->coord[1][1], band->codeblock_height) - band->coord[1][0] / band->codeblock_height;
+
+ for (j = 0; j < 2; j++)
+ band->coord[0][j] = ff_j2k_ceildiv(band->coord[0][j], dx);
+ for (j = 0; j < 2; j++)
+ band->coord[1][j] = ff_j2k_ceildiv(band->coord[1][j], dy);
+
+ band->cblknx = ff_j2k_ceildiv(band->cblknx, dx);
+ band->cblkny = ff_j2k_ceildiv(band->cblkny, dy);
+
+ band->cblk = av_malloc(sizeof(J2kCblk) * band->cblknx * band->cblkny);
+ if (!band->cblk)
+ return AVERROR(ENOMEM);
+ band->prec = av_malloc(sizeof(J2kCblk) * reslevel->num_precincts_x * reslevel->num_precincts_y);
+ if (!band->prec)
+ return AVERROR(ENOMEM);
+
+ for (cblkno = 0; cblkno < band->cblknx * band->cblkny; cblkno++){
+ J2kCblk *cblk = band->cblk + cblkno;
+ cblk->zero = 0;
+ cblk->lblock = 3;
+ cblk->length = 0;
+ cblk->lengthinc = 0;
+ cblk->npasses = 0;
+ }
+
+ y0 = band->coord[1][0];
+ y1 = ((band->coord[1][0] + (1<<codsty->log2_prec_height)) & ~((1<<codsty->log2_prec_height)-1)) - y0;
+ yi0 = 0;
+ yi1 = ff_j2k_ceildivpow2(y1 - y0, codsty->log2_cblk_height) << codsty->log2_cblk_height;
+ yi1 = FFMIN(yi1, band->cblkny);
+ cblkperprech = 1<<(codsty->log2_prec_height - codsty->log2_cblk_height);
+ for (precy = 0, precno = 0; precy < reslevel->num_precincts_y; precy++){
+ for (precx = 0; precx < reslevel->num_precincts_x; precx++, precno++){
+ band->prec[precno].yi0 = yi0;
+ band->prec[precno].yi1 = yi1;
+ }
+ yi1 += cblkperprech;
+ yi0 = yi1 - cblkperprech;
+ yi1 = FFMIN(yi1, band->cblkny);
+ }
+ x0 = band->coord[0][0];
+ x1 = ((band->coord[0][0] + (1<<codsty->log2_prec_width)) & ~((1<<codsty->log2_prec_width)-1)) - x0;
+ xi0 = 0;
+ xi1 = ff_j2k_ceildivpow2(x1 - x0, codsty->log2_cblk_width) << codsty->log2_cblk_width;
+ xi1 = FFMIN(xi1, band->cblknx);
+
+ cblkperprecw = 1<<(codsty->log2_prec_width - codsty->log2_cblk_width);
+ for (precx = 0, precno = 0; precx < reslevel->num_precincts_x; precx++){
+ for (precy = 0; precy < reslevel->num_precincts_y; precy++, precno = 0){
+ J2kPrec *prec = band->prec + precno;
+ prec->xi0 = xi0;
+ prec->xi1 = xi1;
+ prec->cblkincl = ff_j2k_tag_tree_init(prec->xi1 - prec->xi0,
+ prec->yi1 - prec->yi0);
+ prec->zerobits = ff_j2k_tag_tree_init(prec->xi1 - prec->xi0,
+ prec->yi1 - prec->yi0);
+ if (!prec->cblkincl || !prec->zerobits)
+ return AVERROR(ENOMEM);
+
+ }
+ xi1 += cblkperprecw;
+ xi0 = xi1 - cblkperprecw;
+ xi1 = FFMIN(xi1, band->cblknx);
+ }
+ }
+ }
+ return 0;
+}
+
+void ff_j2k_reinit(J2kComponent *comp, J2kCodingStyle *codsty)
+{
+ int reslevelno, bandno, cblkno, precno;
+ for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+ J2kResLevel *rlevel = comp->reslevel + reslevelno;
+ for (bandno = 0; bandno < rlevel->nbands; bandno++){
+ J2kBand *band = rlevel->band + bandno;
+ for(precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++){
+ J2kPrec *prec = band->prec + precno;
+ tag_tree_zero(prec->zerobits, prec->xi1 - prec->xi0, prec->yi1 - prec->yi0);
+ tag_tree_zero(prec->cblkincl, prec->xi1 - prec->xi0, prec->yi1 - prec->yi0);
+ }
+ for (cblkno = 0; cblkno < band->cblknx * band->cblkny; cblkno++){
+ J2kCblk *cblk = band->cblk + cblkno;
+ cblk->length = 0;
+ cblk->lblock = 3;
+ }
+ }
+ }
+}
+
+void ff_j2k_cleanup(J2kComponent *comp, J2kCodingStyle *codsty)
+{
+ int reslevelno, bandno, precno;
+ for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+ J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+ for (bandno = 0; bandno < reslevel->nbands ; bandno++){
+ J2kBand *band = reslevel->band + bandno;
+ for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){
+ J2kPrec *prec = band->prec + precno;
+ av_freep(&prec->zerobits);
+ av_freep(&prec->cblkincl);
+ }
+ av_freep(&band->cblk);
+ av_freep(&band->prec);
+ }
+ av_freep(&reslevel->band);
+ }
+
+ ff_j2k_dwt_destroy(&comp->dwt);
+ av_freep(&comp->reslevel);
+ av_freep(&comp->data);
+}
diff --git a/libavcodec/j2k.h b/libavcodec/j2k.h
new file mode 100644
index 0000000..85d5cd0
--- /dev/null
+++ b/libavcodec/j2k.h
@@ -0,0 +1,234 @@
+/*
+ * JPEG2000 tables
+ * 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
+ */
+
+#ifndef AVCODEC_J2K_H
+#define AVCODEC_J2K_H
+
+/**
+ * JPEG2000 tables
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include "mqc.h"
+#include "j2k_dwt.h"
+
+enum J2kMarkers{
+ J2K_SOC = 0xff4f, ///< start of codestream
+ J2K_SIZ = 0xff51, ///< image and tile size
+ J2K_COD, ///< coding style default
+ J2K_COC, ///< coding style component
+ J2K_TLM = 0xff55, ///< packed packet headers, tile-part header
+ J2K_PLM = 0xff57, ///< tile-part lengths
+ J2K_PLT, ///< packet length, main header
+ J2K_QCD = 0xff5c, ///< quantization default
+ J2K_QCC, ///< quantization component
+ J2K_RGN, ///< region of interest
+ J2K_POC, ///< progression order change
+ J2K_PPM, ///< packet length, tile-part header
+ J2K_PPT, ///< packed packet headers, main header
+ J2K_CRG = 0xff63, ///< component registration
+ J2K_COM, ///< comment
+ J2K_SOT = 0xff90, ///< start of tile-part
+ J2K_SOP, ///< start of packet
+ J2K_EPH, ///< end of packet header
+ J2K_SOD, ///< start of data
+ J2K_EOC = 0xffd9, ///< end of codestream
+};
+
+enum J2kQuantsty{ ///< quantization style
+ J2K_QSTY_NONE, ///< no quantization
+ J2K_QSTY_SI, ///< scalar derived
+ J2K_QSTY_SE ///< scalar expoounded
+};
+
+#define J2K_MAX_CBLKW 64
+#define J2K_MAX_CBLKH 64
+
+// T1 flags
+// flags determining significance of neighbour coefficients
+#define J2K_T1_SIG_N 0x0001
+#define J2K_T1_SIG_E 0x0002
+#define J2K_T1_SIG_W 0x0004
+#define J2K_T1_SIG_S 0x0008
+#define J2K_T1_SIG_NE 0x0010
+#define J2K_T1_SIG_NW 0x0020
+#define J2K_T1_SIG_SE 0x0040
+#define J2K_T1_SIG_SW 0x0080
+#define J2K_T1_SIG_NB (J2K_T1_SIG_N | J2K_T1_SIG_E | J2K_T1_SIG_S | J2K_T1_SIG_W \
+ |J2K_T1_SIG_NE | J2K_T1_SIG_NW | J2K_T1_SIG_SE | J2K_T1_SIG_SW)
+// flags determining sign bit of neighbour coefficients
+#define J2K_T1_SGN_N 0x0100
+#define J2K_T1_SGN_S 0x0200
+#define J2K_T1_SGN_W 0x0400
+#define J2K_T1_SGN_E 0x0800
+
+#define J2K_T1_VIS 0x1000
+#define J2K_T1_SIG 0x2000
+#define J2K_T1_REF 0x4000
+
+#define J2K_T1_SGN 0x8000
+
+// Codeblock coding styles
+#define J2K_CBLK_BYPASS 0x01 // Selective arithmetic coding bypass
+#define J2K_CBLK_RESET 0x02 // Reset context probabilities
+#define J2K_CBLK_TERMALL 0x04 // Terminate after each coding pass
+#define J2K_CBLK_VSC 0x08 // Vertical stripe causal context formation
+#define J2K_CBLK_PREDTERM 0x10 // Predictable termination
+#define J2K_CBLK_SEGSYM 0x20 // Segmentation symbols present
+
+// Coding styles
+#define J2K_CSTY_PREC 0x01 // Precincts defined in coding style
+#define J2K_CSTY_SOP 0x02 // SOP marker present
+#define J2K_CSTY_EPH 0x04 // EPH marker present
+
+typedef struct {
+ int data[J2K_MAX_CBLKW][J2K_MAX_CBLKH];
+ int flags[J2K_MAX_CBLKW+2][J2K_MAX_CBLKH+2];
+ MqcState mqc;
+} J2kT1Context;
+
+typedef struct J2kTgtNode {
+ uint8_t val;
+ uint8_t vis;
+ struct J2kTgtNode *parent;
+} J2kTgtNode;
+
+typedef struct {
+ uint8_t nreslevels; ///< number of resolution levels
+ uint8_t log2_cblk_width,
+ log2_cblk_height; ///< exponent of codeblock size
+ uint8_t transform; ///< DWT type
+ uint8_t csty; ///< coding style
+ uint8_t log2_prec_width,
+ log2_prec_height; ///< precinct size
+ uint8_t nlayers; ///< number of layers
+ uint8_t mct; ///< multiple component transformation
+ uint8_t cblk_style; ///< codeblock coding style
+} J2kCodingStyle;
+
+typedef struct {
+ uint8_t expn[32 * 3]; ///< quantization exponent
+ uint16_t mant[32 * 3]; ///< quantization mantissa
+ uint8_t quantsty; ///< quantization style
+ uint8_t nguardbits; ///< number of guard bits
+} J2kQuantStyle;
+
+typedef struct {
+ uint16_t rate;
+ int64_t disto;
+} J2kPass;
+
+typedef struct {
+ uint8_t npasses;
+ uint8_t ninclpasses; ///< number coding of passes included in codestream
+ uint8_t nonzerobits;
+ uint16_t length;
+ uint16_t lengthinc;
+ uint8_t lblock;
+ uint8_t zero;
+ uint8_t data[8192];
+ J2kPass passes[100];
+} J2kCblk; ///< code block
+
+typedef struct {
+ uint16_t xi0, xi1, yi0, yi1; ///< codeblock indexes ([xi0, xi1))
+ J2kTgtNode *zerobits;
+ J2kTgtNode *cblkincl;
+} J2kPrec; ///< precinct
+
+typedef struct {
+ uint16_t coord[2][2]; ///< border coordinates {{x0, x1}, {y0, y1}}
+ uint16_t codeblock_width, codeblock_height;
+ uint16_t cblknx, cblkny;
+ uint32_t stepsize; ///< quantization stepsize (* 2^13)
+ J2kPrec *prec;
+ J2kCblk *cblk;
+} J2kBand; ///< subband
+
+typedef struct {
+ uint8_t nbands;
+ uint16_t coord[2][2]; ///< border coordinates {{x0, x1}, {y0, y1}}
+ uint16_t num_precincts_x, num_precincts_y; ///< number of precincts in x/y direction
+ uint8_t log2_prec_width, log2_prec_height; ///< exponent of precinct size
+ J2kBand *band;
+} J2kResLevel; ///< resolution level
+
+typedef struct {
+ J2kResLevel *reslevel;
+ DWTContext dwt;
+ int *data;
+ uint16_t coord[2][2]; ///< border coordinates {{x0, x1}, {y0, y1}}
+} J2kComponent;
+
+/* debug routines */
+#if 0
+#undef fprintf
+#undef printf
+void ff_j2k_printv(int *tab, int l);
+void ff_j2k_printu(uint8_t *tab, int l);
+#endif
+
+/* misc tools */
+static inline int ff_j2k_ceildivpow2(int a, int b)
+{
+ return (a + (1 << b) - 1)>> b;
+}
+
+static inline int ff_j2k_ceildiv(int a, int b)
+{
+ return (a + b - 1) / b;
+}
+
+/* tag tree routines */
+J2kTgtNode *ff_j2k_tag_tree_init(int w, int h);
+
+/* TIER-1 routines */
+void ff_j2k_init_tier1_luts(void);
+
+void ff_j2k_set_significant(J2kT1Context *t1, int x, int y, int negative);
+
+extern uint8_t ff_j2k_nbctxno_lut[256][4];
+
+static inline int ff_j2k_getnbctxno(int flag, int bandno, int vert_causal_ctx_csty_symbol)
+{
+ return ff_j2k_nbctxno_lut[flag&255][bandno];
+}
+
+static inline int ff_j2k_getrefctxno(int flag)
+{
+ static const uint8_t refctxno_lut[2][2] = {{14, 15}, {16, 16}};
+ return refctxno_lut[(flag>>14)&1][(flag & 255) != 0];
+}
+
+extern uint8_t ff_j2k_sgnctxno_lut[16][16], ff_j2k_xorbit_lut[16][16];
+
+static inline int ff_j2k_getsgnctxno(int flag, int *xorbit)
+{
+ *xorbit = ff_j2k_xorbit_lut[flag&15][(flag>>8)&15];
+ return ff_j2k_sgnctxno_lut[flag&15][(flag>>8)&15];
+}
+
+int ff_j2k_init_component(J2kComponent *comp, J2kCodingStyle *codsty, J2kQuantStyle *qntsty, int cbps, int dx, int dy);
+void ff_j2k_reinit(J2kComponent *comp, J2kCodingStyle *codsty);
+void ff_j2k_cleanup(J2kComponent *comp, J2kCodingStyle *codsty);
+
+#endif /* AVCODEC_J2K_H */
diff --git a/libavcodec/j2k_dwt.c b/libavcodec/j2k_dwt.c
new file mode 100644
index 0000000..6f1457f
--- /dev/null
+++ b/libavcodec/j2k_dwt.c
@@ -0,0 +1,386 @@
+/*
+ * Discrete wavelet transform
+ * 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
+ */
+
+/**
+ * Discrete wavelet transform
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include "j2k_dwt.h"
+
+static const float scale97[] = {1.625786, 1.230174};
+
+static inline void extend53(int *p, int i0, int i1)
+{
+ p[i0 - 1] = p[i0 + 1];
+ p[i1 ] = p[i1 - 2];
+ p[i0 - 2] = p[i0 + 2];
+ p[i1 + 1] = p[i1 - 3];
+}
+
+static inline void extend97(float *p, int i0, int i1)
+{
+ int i;
+
+ for (i = 1; i <= 4; i++){
+ p[i0 - i] = p[i0 + i];
+ p[i1 + i - 1] = p[i1 - i - 1];
+ }
+}
+
+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->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 *p, int i0, int i1)
+{
+ int i;
+
+ if (i1 == i0 + 1)
+ return;
+
+ extend97(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(DWTContext *s, int *t)
+{
+ int lev,
+ w = s->linelen[s->ndeclevels-1][0];
+ float *line = s->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(line, mh, mh + lh);
+
+ // copy back and deinterleave
+ for (i = mh; i < lh; i+=2, j++)
+ t[w*lp + j] = scale97[mh] * l[i] / 2;
+ for (i = 1-mh; i < lh; i+=2, j++)
+ t[w*lp + j] = scale97[mh] * 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(line, mv, mv + lv);
+
+ // copy back and deinterleave
+ for (i = mv; i < lv; i+=2, j++)
+ t[w*j + lp] = scale97[mv] * l[i] / 2;
+ for (i = 1-mv; i < lv; i+=2, j++)
+ t[w*j + lp] = scale97[mv] * l[i] / 2;
+ }
+ }
+}
+
+static void sr_1d53(int *p, int i0, int i1)
+{
+ int i;
+
+ if (i1 == i0 + 1)
+ return;
+
+ extend53(p, i0, i1);
+
+ for (i = i0/2; i < i1/2 + 1; i++)
+ p[2*i] -= (p[2*i-1] + p[2*i+1] + 2) >> 2;
+ for (i = i0/2; i < i1/2; i++)
+ p[2*i+1] += (p[2*i] + p[2*i+2]) >> 1;
+}
+
+static void dwt_decode53(DWTContext *s, int *t)
+{
+ int lev,
+ w = s->linelen[s->ndeclevels-1][0];
+ int *line = s->linebuf;
+ line += 3;
+
+ for (lev = 0; lev < s->ndeclevels; 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;
+ // copy with interleaving
+ for (i = mh; i < lh; i+=2, j++)
+ l[i] = t[w*lp + j];
+ for (i = 1-mh; i < lh; i+=2, j++)
+ l[i] = t[w*lp + j];
+
+ sr_1d53(line, mh, mh + lh);
+
+ for (i = 0; i < lh; i++)
+ t[w*lp + i] = l[i];
+ }
+
+ // VER_SD
+ l = line + mv;
+ for (lp = 0; lp < lh; lp++){
+ int i, j = 0;
+ // copy with interleaving
+ for (i = mv; i < lv; i+=2, j++)
+ l[i] = t[w*j + lp];
+ for (i = 1-mv; i < lv; i+=2, j++)
+ l[i] = t[w*j + lp];
+
+ sr_1d53(line, mv, mv + lv);
+
+ for (i = 0; i < lv; i++)
+ t[w*i + lp] = l[i];
+ }
+ }
+}
+
+static void sr_1d97(float *p, int i0, int i1)
+{
+ int i;
+
+ if (i1 == i0 + 1)
+ return;
+
+ extend97(p, i0, i1);
+
+ for (i = i0/2 - 1; i < i1/2 + 2; i++)
+ p[2*i] -= 0.443506 * (p[2*i-1] + p[2*i+1]);
+ for (i = i0/2 - 1; i < i1/2 + 1; i++)
+ p[2*i+1] -= 0.882911 * (p[2*i] + p[2*i+2]);
+ for (i = i0/2; i < i1/2 + 1; i++)
+ p[2*i] += 0.052980 * (p[2*i-1] + p[2*i+1]);
+ for (i = i0/2; i < i1/2; i++)
+ p[2*i+1] += 1.586134 * (p[2*i] + p[2*i+2]);
+}
+
+static void dwt_decode97(DWTContext *s, int *t)
+{
+ int lev,
+ w = s->linelen[s->ndeclevels-1][0];
+ float *line = s->linebuf;
+ line += 5;
+
+ for (lev = 0; lev < s->ndeclevels; 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;
+ // copy with interleaving
+ for (i = mh; i < lh; i+=2, j++)
+ l[i] = scale97[1-mh] * t[w*lp + j];
+ for (i = 1-mh; i < lh; i+=2, j++)
+ l[i] = scale97[1-mh] * t[w*lp + j];
+
+ sr_1d97(line, mh, mh + lh);
+
+ for (i = 0; i < lh; i++)
+ t[w*lp + i] = l[i];
+ }
+
+ // VER_SD
+ l = line + mv;
+ for (lp = 0; lp < lh; lp++){
+ int i, j = 0;
+ // copy with interleaving
+ for (i = mv; i < lv; i+=2, j++)
+ l[i] = scale97[1-mv] * t[w*j + lp];
+ for (i = 1-mv; i < lv; i+=2, j++)
+ l[i] = scale97[1-mv] * t[w*j + lp];
+
+ sr_1d97(line, mv, mv + lv);
+
+ for (i = 0; i < lv; i++)
+ t[w*i + lp] = l[i];
+ }
+ }
+}
+
+int ff_j2k_dwt_init(DWTContext *s, uint16_t border[2][2], int decomp_levels, int type)
+{
+ int i, j, lev = decomp_levels, maxlen,
+ b[2][2];
+
+ if ((unsigned)decomp_levels >= FF_DWT_MAX_DECLVLS)
+ return AVERROR_INVALIDDATA;
+ s->ndeclevels = decomp_levels;
+ s->type = type;
+
+ for (i = 0; i < 2; i++)
+ for(j = 0; j < 2; j++)
+ b[i][j] = border[i][j];
+
+ maxlen = FFMAX(b[0][1] - b[0][0],
+ b[1][1] - b[1][0]);
+
+ while(--lev >= 0){
+ for (i = 0; i < 2; i++){
+ s->linelen[lev][i] = b[i][1] - b[i][0];
+ s->mod[lev][i] = b[i][0] & 1;
+ for (j = 0; j < 2; j++)
+ b[i][j] = (b[i][j] + 1) >> 1;
+ }
+ }
+ if (type == FF_DWT97)
+ s->linebuf = av_malloc((maxlen + 12) * sizeof(float));
+ else if (type == FF_DWT53)
+ s->linebuf = av_malloc((maxlen + 6) * sizeof(int));
+ else
+ return -1;
+
+ if (!s->linebuf)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+int ff_j2k_dwt_encode(DWTContext *s, int *t)
+{
+ switch(s->type){
+ case FF_DWT97:
+ dwt_encode97(s, t); break;
+ case FF_DWT53:
+ dwt_encode53(s, t); break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+int ff_j2k_dwt_decode(DWTContext *s, int *t)
+{
+ switch(s->type){
+ case FF_DWT97:
+ dwt_decode97(s, t); break;
+ case FF_DWT53:
+ dwt_decode53(s, t); break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+void ff_j2k_dwt_destroy(DWTContext *s)
+{
+ av_freep(&s->linebuf);
+}
diff --git a/libavcodec/j2k_dwt.h b/libavcodec/j2k_dwt.h
new file mode 100644
index 0000000..a2a25a6
--- /dev/null
+++ b/libavcodec/j2k_dwt.h
@@ -0,0 +1,63 @@
+/*
+ * Discrete wavelet transform
+ * 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
+ */
+
+#ifndef AVCODEC_DWT_H
+#define AVCODEC_DWT_H
+
+/**
+ * Discrete wavelet transform
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include "avcodec.h"
+
+#define FF_DWT_MAX_DECLVLS 32 ///< max number of decomposition levels
+
+enum DWTType{
+ FF_DWT97,
+ FF_DWT53
+};
+
+typedef struct {
+ ///line lengths {horizontal, vertical} in consecutive decomposition levels
+ uint16_t linelen[FF_DWT_MAX_DECLVLS][2];
+ uint8_t mod[FF_DWT_MAX_DECLVLS][2]; ///< coordinates (x0, y0) of decomp. levels mod 2
+ uint8_t ndeclevels; ///< number of decomposition levels
+ uint8_t type; ///< 0 for 9/7; 1 for 5/3
+ void *linebuf; ///< buffer used by transform (int or float)
+} DWTContext;
+
+/**
+ * initialize DWT
+ * @param s DWT context
+ * @param border coordinates of transformed region {{x0, x1}, {y0, y1}}
+ * @param decomp_levels number of decomposition levels
+ * @param type 0 for DWT 9/7; 1 for DWT 5/3
+ */
+int ff_j2k_dwt_init(DWTContext *s, uint16_t border[2][2], int decomp_levels, int type);
+
+int ff_j2k_dwt_encode(DWTContext *s, int *t);
+int ff_j2k_dwt_decode(DWTContext *s, int *t);
+
+void ff_j2k_dwt_destroy(DWTContext *s);
+
+#endif /* AVCODEC_DWT_H */
diff --git a/libavcodec/j2kdec.c b/libavcodec/j2kdec.c
new file mode 100644
index 0000000..3e78b0b
--- /dev/null
+++ b/libavcodec/j2kdec.c
@@ -0,0 +1,1095 @@
+/*
+ * JPEG2000 image decoder
+ * 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 decoder
+ * @file
+ * @author Kamil Nowosad
+ */
+
+// #define DEBUG
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "internal.h"
+#include "thread.h"
+#include "j2k.h"
+#include "libavutil/common.h"
+
+#define JP2_SIG_TYPE 0x6A502020
+#define JP2_SIG_VALUE 0x0D0A870A
+#define JP2_CODESTREAM 0x6A703263
+
+#define HAD_COC 0x01
+#define HAD_QCC 0x02
+
+typedef struct {
+ J2kComponent *comp;
+ uint8_t properties[4];
+ J2kCodingStyle codsty[4];
+ J2kQuantStyle qntsty[4];
+} J2kTile;
+
+typedef struct {
+ AVCodecContext *avctx;
+ AVFrame *picture;
+ GetByteContext g;
+
+ int width, height; ///< image width and height
+ int image_offset_x, image_offset_y;
+ int tile_offset_x, tile_offset_y;
+ uint8_t cbps[4]; ///< bits per sample in particular components
+ uint8_t sgnd[4]; ///< if a component is signed
+ uint8_t properties[4];
+ int cdx[4], cdy[4];
+ int precision;
+ int ncomponents;
+ int tile_width, tile_height; ///< tile size
+ int numXtiles, numYtiles;
+ int maxtilelen;
+
+ J2kCodingStyle codsty[4];
+ J2kQuantStyle qntsty[4];
+
+ int bit_index;
+
+ int curtileno;
+
+ J2kTile *tile;
+} J2kDecoderContext;
+
+static int get_bits(J2kDecoderContext *s, int n)
+{
+ int res = 0;
+
+ while (--n >= 0){
+ res <<= 1;
+ if (s->bit_index == 0) {
+ s->bit_index = 7 + (bytestream2_get_byte(&s->g) != 0xFFu);
+ }
+ s->bit_index--;
+ res |= (bytestream2_peek_byte(&s->g) >> s->bit_index) & 1;
+ }
+ return res;
+}
+
+static void j2k_flush(J2kDecoderContext *s)
+{
+ if (bytestream2_get_byte(&s->g) == 0xff)
+ bytestream2_skip(&s->g, 1);
+ s->bit_index = 8;
+}
+#if 0
+void printcomp(J2kComponent *comp)
+{
+ int i;
+ for (i = 0; i < comp->y1 - comp->y0; i++)
+ ff_j2k_printv(comp->data + i * (comp->x1 - comp->x0), comp->x1 - comp->x0);
+}
+
+static void nspaces(FILE *fd, int n)
+{
+ while(n--) putc(' ', fd);
+}
+
+static void dump(J2kDecoderContext *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++){
+ J2kTile *tile = s->tile + tileno;
+ nspaces(fd, 2);
+ fprintf(fd, "tile %d:\n", tileno);
+ for(compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *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 < codsty->nreslevels; reslevelno++){
+ J2kResLevel *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++){
+ J2kBand *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++){
+ J2kPrec *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
+
+/** decode the value stored in node */
+static int tag_tree_decode(J2kDecoderContext *s, J2kTgtNode *node, int threshold)
+{
+ J2kTgtNode *stack[30];
+ int sp = -1, curval = 0;
+
+ if(!node)
+ return AVERROR(EINVAL);
+
+ while(node && !node->vis){
+ stack[++sp] = node;
+ node = node->parent;
+ }
+
+ if (node)
+ curval = node->val;
+ else
+ curval = stack[sp]->val;
+
+ while(curval < threshold && sp >= 0){
+ if (curval < stack[sp]->val)
+ curval = stack[sp]->val;
+ while (curval < threshold){
+ int ret;
+ if ((ret = get_bits(s, 1)) > 0){
+ stack[sp]->vis++;
+ break;
+ } else if (!ret)
+ curval++;
+ else
+ return ret;
+ }
+ stack[sp]->val = curval;
+ sp--;
+ }
+ return curval;
+}
+
+/* marker segments */
+/** get sizes and offsets of image, tiles; number of components */
+static int get_siz(J2kDecoderContext *s)
+{
+ int i, ret;
+ ThreadFrame frame = { .f = s->picture };
+
+ if (bytestream2_get_bytes_left(&s->g) < 36)
+ return AVERROR(EINVAL);
+
+ bytestream2_get_be16u(&s->g); // Rsiz (skipped)
+ s->width = bytestream2_get_be32u(&s->g); // width
+ s->height = bytestream2_get_be32u(&s->g); // height
+ s->image_offset_x = bytestream2_get_be32u(&s->g); // X0Siz
+ s->image_offset_y = bytestream2_get_be32u(&s->g); // Y0Siz
+
+ s->tile_width = bytestream2_get_be32u(&s->g); // XTSiz
+ s->tile_height = bytestream2_get_be32u(&s->g); // YTSiz
+ s->tile_offset_x = bytestream2_get_be32u(&s->g); // XT0Siz
+ s->tile_offset_y = bytestream2_get_be32u(&s->g); // YT0Siz
+ s->ncomponents = bytestream2_get_be16u(&s->g); // CSiz
+
+ if(s->ncomponents <= 0 || s->ncomponents > 4) {
+ av_log(s->avctx, AV_LOG_ERROR, "unsupported/invalid ncomponents: %d\n", s->ncomponents);
+ return AVERROR(EINVAL);
+ }
+ if(s->tile_width<=0 || s->tile_height<=0)
+ return AVERROR(EINVAL);
+
+ if (bytestream2_get_bytes_left(&s->g) < 3 * s->ncomponents)
+ return AVERROR(EINVAL);
+
+ for (i = 0; i < s->ncomponents; i++){ // Ssiz_i XRsiz_i, YRsiz_i
+ uint8_t x = bytestream2_get_byteu(&s->g);
+ s->cbps[i] = (x & 0x7f) + 1;
+ s->precision = FFMAX(s->cbps[i], s->precision);
+ s->sgnd[i] = !!(x & 0x80);
+ s->cdx[i] = bytestream2_get_byteu(&s->g);
+ s->cdy[i] = bytestream2_get_byteu(&s->g);
+ }
+
+ s->numXtiles = ff_j2k_ceildiv(s->width - s->tile_offset_x, s->tile_width);
+ s->numYtiles = ff_j2k_ceildiv(s->height - s->tile_offset_y, s->tile_height);
+
+ if(s->numXtiles * (uint64_t)s->numYtiles > INT_MAX/sizeof(J2kTile))
+ return AVERROR(EINVAL);
+
+ s->tile = av_mallocz(s->numXtiles * s->numYtiles * sizeof(J2kTile));
+ if (!s->tile)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < s->numXtiles * s->numYtiles; i++){
+ J2kTile *tile = s->tile + i;
+
+ tile->comp = av_mallocz(s->ncomponents * sizeof(J2kComponent));
+ if (!tile->comp)
+ return AVERROR(ENOMEM);
+ }
+
+ s->avctx->width = s->width - s->image_offset_x;
+ s->avctx->height = s->height - s->image_offset_y;
+
+ 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:
+ if (s->precision > 8) {
+ s->avctx->pix_fmt = AV_PIX_FMT_RGB48;
+ } else {
+ s->avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ }
+ break;
+ case 4:
+ s->avctx->pix_fmt = AV_PIX_FMT_RGBA;
+ break;
+ }
+
+
+ if ((ret = ff_thread_get_buffer(s->avctx, &frame, 0)) < 0)
+ return ret;
+
+ s->picture->pict_type = AV_PICTURE_TYPE_I;
+ s->picture->key_frame = 1;
+
+ return 0;
+}
+
+/** get common part for COD and COC segments */
+static int get_cox(J2kDecoderContext *s, J2kCodingStyle *c)
+{
+ if (bytestream2_get_bytes_left(&s->g) < 5)
+ return AVERROR(EINVAL);
+ c->nreslevels = bytestream2_get_byteu(&s->g) + 1; // num of resolution levels - 1
+ 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->cblk_style = bytestream2_get_byteu(&s->g);
+ if (c->cblk_style != 0){ // cblk style
+ av_log(s->avctx, AV_LOG_WARNING, "extra cblk styles %X\n", c->cblk_style);
+ }
+ c->transform = bytestream2_get_byteu(&s->g); // transformation
+ if (c->csty & J2K_CSTY_PREC) {
+ int i;
+
+ for (i = 0; i < c->nreslevels; i++)
+ bytestream2_get_byte(&s->g);
+ }
+ return 0;
+}
+
+/** get coding parameters for a particular tile or whole image*/
+static int get_cod(J2kDecoderContext *s, J2kCodingStyle *c, uint8_t *properties)
+{
+ J2kCodingStyle tmp;
+ int compno;
+
+ if (bytestream2_get_bytes_left(&s->g) < 5)
+ return AVERROR(EINVAL);
+
+ tmp.log2_prec_width =
+ tmp.log2_prec_height = 15;
+
+ tmp.csty = bytestream2_get_byteu(&s->g);
+
+ if (bytestream2_get_byteu(&s->g)){ // progression level
+ av_log(s->avctx, AV_LOG_ERROR, "only LRCP progression supported\n");
+ return -1;
+ }
+
+ tmp.nlayers = bytestream2_get_be16u(&s->g);
+ tmp.mct = bytestream2_get_byteu(&s->g); // multiple component transformation
+
+ get_cox(s, &tmp);
+ for (compno = 0; compno < s->ncomponents; compno++){
+ if (!(properties[compno] & HAD_COC))
+ memcpy(c + compno, &tmp, sizeof(J2kCodingStyle));
+ }
+ return 0;
+}
+
+/** get coding parameters for a component in the whole image on a particular tile */
+static int get_coc(J2kDecoderContext *s, J2kCodingStyle *c, uint8_t *properties)
+{
+ int compno;
+
+ if (bytestream2_get_bytes_left(&s->g) < 2)
+ return AVERROR(EINVAL);
+
+ compno = bytestream2_get_byteu(&s->g);
+
+ c += compno;
+ c->csty = bytestream2_get_byte(&s->g);
+ get_cox(s, c);
+
+ properties[compno] |= HAD_COC;
+ return 0;
+}
+
+/** get common part for QCD and QCC segments */
+static int get_qcx(J2kDecoderContext *s, int n, J2kQuantStyle *q)
+{
+ int i, x;
+
+ if (bytestream2_get_bytes_left(&s->g) < 1)
+ return AVERROR(EINVAL);
+
+ x = bytestream2_get_byteu(&s->g); // Sqcd
+
+ q->nguardbits = x >> 5;
+ q->quantsty = x & 0x1f;
+
+ if (q->quantsty == J2K_QSTY_NONE){
+ n -= 3;
+ if (bytestream2_get_bytes_left(&s->g) < n || 32*3 < n)
+ return AVERROR(EINVAL);
+ for (i = 0; i < n; i++)
+ q->expn[i] = bytestream2_get_byteu(&s->g) >> 3;
+ } else if (q->quantsty == J2K_QSTY_SI){
+ if (bytestream2_get_bytes_left(&s->g) < 2)
+ return AVERROR(EINVAL);
+ x = bytestream2_get_be16u(&s->g);
+ q->expn[0] = x >> 11;
+ q->mant[0] = x & 0x7ff;
+ for (i = 1; i < 32 * 3; i++){
+ int curexpn = FFMAX(0, q->expn[0] - (i-1)/3);
+ q->expn[i] = curexpn;
+ q->mant[i] = q->mant[0];
+ }
+ } else{
+ n = (n - 3) >> 1;
+ if (bytestream2_get_bytes_left(&s->g) < 2 * n || 32*3 < n)
+ return AVERROR(EINVAL);
+ for (i = 0; i < n; i++){
+ x = bytestream2_get_be16u(&s->g);
+ q->expn[i] = x >> 11;
+ q->mant[i] = x & 0x7ff;
+ }
+ }
+ return 0;
+}
+
+/** get quantization parameters for a particular tile or a whole image */
+static int get_qcd(J2kDecoderContext *s, int n, J2kQuantStyle *q, uint8_t *properties)
+{
+ J2kQuantStyle tmp;
+ int compno;
+
+ if (get_qcx(s, n, &tmp))
+ return -1;
+ for (compno = 0; compno < s->ncomponents; compno++)
+ if (!(properties[compno] & HAD_QCC))
+ memcpy(q + compno, &tmp, sizeof(J2kQuantStyle));
+ return 0;
+}
+
+/** get quantization parameters for a component in the whole image on in a particular tile */
+static int get_qcc(J2kDecoderContext *s, int n, J2kQuantStyle *q, uint8_t *properties)
+{
+ int compno;
+
+ if (bytestream2_get_bytes_left(&s->g) < 1)
+ return AVERROR(EINVAL);
+
+ compno = bytestream2_get_byteu(&s->g);
+ properties[compno] |= HAD_QCC;
+ return get_qcx(s, n-1, q+compno);
+}
+
+/** get start of tile segment */
+static uint8_t get_sot(J2kDecoderContext *s)
+{
+ if (bytestream2_get_bytes_left(&s->g) < 8)
+ return AVERROR(EINVAL);
+
+ s->curtileno = bytestream2_get_be16u(&s->g); ///< Isot
+ if((unsigned)s->curtileno >= s->numXtiles * s->numYtiles){
+ s->curtileno=0;
+ return AVERROR(EINVAL);
+ }
+
+ bytestream2_skipu(&s->g, 4); ///< Psot (ignored)
+
+ if (!bytestream2_get_byteu(&s->g)){ ///< TPsot
+ J2kTile *tile = s->tile + s->curtileno;
+
+ /* copy defaults */
+ memcpy(tile->codsty, s->codsty, s->ncomponents * sizeof(J2kCodingStyle));
+ memcpy(tile->qntsty, s->qntsty, s->ncomponents * sizeof(J2kQuantStyle));
+ }
+ bytestream2_get_byteu(&s->g); ///< TNsot
+
+ return 0;
+}
+
+static int init_tile(J2kDecoderContext *s, int tileno)
+{
+ int compno,
+ tilex = tileno % s->numXtiles,
+ tiley = tileno / s->numXtiles;
+ J2kTile *tile = s->tile + tileno;
+
+ if (!tile->comp)
+ return AVERROR(ENOMEM);
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = tile->comp + compno;
+ J2kCodingStyle *codsty = tile->codsty + compno;
+ J2kQuantStyle *qntsty = tile->qntsty + compno;
+ int ret; // global bandno
+
+ comp->coord[0][0] = FFMAX(tilex * s->tile_width + s->tile_offset_x, s->image_offset_x);
+ comp->coord[0][1] = FFMIN((tilex+1)*s->tile_width + s->tile_offset_x, s->width);
+ comp->coord[1][0] = FFMAX(tiley * s->tile_height + s->tile_offset_y, s->image_offset_y);
+ comp->coord[1][1] = FFMIN((tiley+1)*s->tile_height + s->tile_offset_y, s->height);
+
+ if (ret = ff_j2k_init_component(comp, codsty, qntsty, s->cbps[compno], s->cdx[compno], s->cdy[compno]))
+ return ret;
+ }
+ return 0;
+}
+
+/** read the number of coding passes */
+static int getnpasses(J2kDecoderContext *s)
+{
+ int num;
+ if (!get_bits(s, 1))
+ return 1;
+ if (!get_bits(s, 1))
+ return 2;
+ if ((num = get_bits(s, 2)) != 3)
+ return num < 0 ? num : 3 + num;
+ if ((num = get_bits(s, 5)) != 31)
+ return num < 0 ? num : 6 + num;
+ num = get_bits(s, 7);
+ return num < 0 ? num : 37 + num;
+}
+
+static int getlblockinc(J2kDecoderContext *s)
+{
+ int res = 0, ret;
+ while (ret = get_bits(s, 1)){
+ if (ret < 0)
+ return ret;
+ res++;
+ }
+ return res;
+}
+
+static int decode_packet(J2kDecoderContext *s, J2kCodingStyle *codsty, J2kResLevel *rlevel, int precno,
+ int layno, uint8_t *expn, int numgbits)
+{
+ int bandno, cblkny, cblknx, cblkno, ret;
+
+ if (!(ret = get_bits(s, 1))){
+ j2k_flush(s);
+ return 0;
+ } else if (ret < 0)
+ return ret;
+
+ for (bandno = 0; bandno < rlevel->nbands; bandno++){
+ J2kBand *band = rlevel->band + bandno;
+ J2kPrec *prec = band->prec + precno;
+ int pos = 0;
+
+ if (band->coord[0][0] == band->coord[0][1]
+ || band->coord[1][0] == band->coord[1][1])
+ continue;
+
+ for (cblkny = prec->yi0; cblkny < prec->yi1; cblkny++)
+ for(cblknx = prec->xi0, cblkno = cblkny * band->cblknx + cblknx; cblknx < prec->xi1; cblknx++, cblkno++, pos++){
+ J2kCblk *cblk = band->cblk + cblkno;
+ int incl, newpasses, llen;
+
+ if (cblk->npasses)
+ incl = get_bits(s, 1);
+ else
+ incl = tag_tree_decode(s, prec->cblkincl + pos, layno+1) == layno;
+ if (!incl)
+ continue;
+ else if (incl < 0)
+ return incl;
+
+ if (!cblk->npasses)
+ cblk->nonzerobits = expn[bandno] + numgbits - 1 - tag_tree_decode(s, prec->zerobits + pos, 100);
+ if ((newpasses = getnpasses(s)) < 0)
+ return newpasses;
+ if ((llen = getlblockinc(s)) < 0)
+ return llen;
+ cblk->lblock += llen;
+ if ((ret = get_bits(s, av_log2(newpasses) + cblk->lblock)) < 0)
+ return ret;
+ cblk->lengthinc = ret;
+ cblk->npasses += newpasses;
+ }
+ }
+ j2k_flush(s);
+
+ if (codsty->csty & J2K_CSTY_EPH) {
+ if (bytestream2_peek_be16(&s->g) == J2K_EPH) {
+ bytestream2_skip(&s->g, 2);
+ } else {
+ av_log(s->avctx, AV_LOG_ERROR, "EPH marker not found.\n");
+ }
+ }
+
+ for (bandno = 0; bandno < rlevel->nbands; bandno++){
+ J2kBand *band = rlevel->band + bandno;
+ int yi, cblknw = band->prec[precno].xi1 - band->prec[precno].xi0;
+ for (yi = band->prec[precno].yi0; yi < band->prec[precno].yi1; yi++){
+ int xi;
+ for (xi = band->prec[precno].xi0; xi < band->prec[precno].xi1; xi++){
+ J2kCblk *cblk = band->cblk + yi * cblknw + xi;
+ if (bytestream2_get_bytes_left(&s->g) < cblk->lengthinc)
+ return AVERROR(EINVAL);
+ bytestream2_get_bufferu(&s->g, cblk->data, cblk->lengthinc);
+ cblk->length += cblk->lengthinc;
+ cblk->lengthinc = 0;
+ }
+ }
+ }
+ return 0;
+}
+
+static int decode_packets(J2kDecoderContext *s, J2kTile *tile)
+{
+ int layno, reslevelno, compno, precno, ok_reslevel;
+ s->bit_index = 8;
+ for (layno = 0; layno < tile->codsty[0].nlayers; layno++){
+ ok_reslevel = 1;
+ for (reslevelno = 0; ok_reslevel; reslevelno++){
+ ok_reslevel = 0;
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kCodingStyle *codsty = tile->codsty + compno;
+ J2kQuantStyle *qntsty = tile->qntsty + compno;
+ if (reslevelno < codsty->nreslevels){
+ J2kResLevel *rlevel = tile->comp[compno].reslevel + reslevelno;
+ ok_reslevel = 1;
+ for (precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++){
+ if (decode_packet(s, codsty, rlevel, precno, layno, qntsty->expn +
+ (reslevelno ? 3*(reslevelno-1)+1 : 0), qntsty->nguardbits))
+ return -1;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/* TIER-1 routines */
+static void decode_sigpass(J2kT1Context *t1, int width, int height, int bpno, int bandno, int bpass_csty_symbol,
+ int vert_causal_ctx_csty_symbol)
+{
+ int mask = 3 << (bpno - 1), y0, x, y;
+
+ 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] & J2K_T1_SIG_NB)
+ && !(t1->flags[y+1][x+1] & (J2K_T1_SIG | J2K_T1_VIS))){
+ int vert_causal_ctx_csty_loc_symbol = vert_causal_ctx_csty_symbol && (x == 3 && y == 3);
+ if (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ff_j2k_getnbctxno(t1->flags[y+1][x+1], bandno,
+ vert_causal_ctx_csty_loc_symbol))){
+ int xorbit, ctxno = ff_j2k_getsgnctxno(t1->flags[y+1][x+1], &xorbit);
+ if (bpass_csty_symbol)
+ t1->data[y][x] = ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ? -mask : mask;
+ else
+ t1->data[y][x] = (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ^ xorbit) ?
+ -mask : mask;
+
+ ff_j2k_set_significant(t1, x, y, t1->data[y][x] < 0);
+ }
+ t1->flags[y+1][x+1] |= J2K_T1_VIS;
+ }
+ }
+}
+
+static void decode_refpass(J2kT1Context *t1, int width, int height, int bpno)
+{
+ int phalf, nhalf;
+ int y0, x, y;
+
+ phalf = 1 << (bpno - 1);
+ nhalf = -phalf;
+
+ 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] & (J2K_T1_SIG | J2K_T1_VIS)) == J2K_T1_SIG){
+ int ctxno = ff_j2k_getrefctxno(t1->flags[y+1][x+1]);
+ int r = ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ? phalf : nhalf;
+ t1->data[y][x] += t1->data[y][x] < 0 ? -r : r;
+ t1->flags[y+1][x+1] |= J2K_T1_REF;
+ }
+ }
+}
+
+static void decode_clnpass(J2kDecoderContext *s, J2kT1Context *t1, int width, int height,
+ int bpno, int bandno, int seg_symbols)
+{
+ int mask = 3 << (bpno - 1), y0, x, y, runlen, dec;
+
+ for (y0 = 0; y0 < height; y0 += 4) {
+ for (x = 0; x < width; x++){
+ if (y0 + 3 < height && !(
+ (t1->flags[y0+1][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+ (t1->flags[y0+2][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+ (t1->flags[y0+3][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+ (t1->flags[y0+4][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)))){
+ if (!ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_RL))
+ continue;
+ runlen = ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI);
+ runlen = (runlen << 1) | ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI);
+ dec = 1;
+ } else{
+ runlen = 0;
+ dec = 0;
+ }
+
+ for (y = y0 + runlen; y < y0 + 4 && y < height; y++){
+ if (!dec){
+ if (!(t1->flags[y+1][x+1] & (J2K_T1_SIG | J2K_T1_VIS)))
+ dec = ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ff_j2k_getnbctxno(t1->flags[y+1][x+1],
+ bandno, 0));
+ }
+ if (dec){
+ int xorbit, ctxno = ff_j2k_getsgnctxno(t1->flags[y+1][x+1], &xorbit);
+ t1->data[y][x] = (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ^ xorbit) ? -mask : mask;
+ ff_j2k_set_significant(t1, x, y, t1->data[y][x] < 0);
+ }
+ dec = 0;
+ t1->flags[y+1][x+1] &= ~J2K_T1_VIS;
+ }
+ }
+ }
+ if (seg_symbols) {
+ int val;
+ val = ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI);
+ val = (val << 1) + ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI);
+ val = (val << 1) + ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI);
+ val = (val << 1) + ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI);
+ if (val != 0xa) {
+ av_log(s->avctx, AV_LOG_ERROR,"Segmentation symbol value incorrect\n");
+ }
+ }
+}
+
+static int decode_cblk(J2kDecoderContext *s, J2kCodingStyle *codsty, J2kT1Context *t1, J2kCblk *cblk,
+ int width, int height, int bandpos)
+{
+ int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1, y, clnpass_cnt = 0;
+ int bpass_csty_symbol = J2K_CBLK_BYPASS & codsty->cblk_style;
+ int vert_causal_ctx_csty_symbol = J2K_CBLK_VSC & codsty->cblk_style;
+
+ for (y = 0; y < height+2; y++)
+ memset(t1->flags[y], 0, (width+2)*sizeof(int));
+
+ for (y = 0; y < height; y++)
+ memset(t1->data[y], 0, width*sizeof(int));
+
+ cblk->data[cblk->length] = 0xff;
+ cblk->data[cblk->length+1] = 0xff;
+ ff_mqc_initdec(&t1->mqc, cblk->data);
+
+ while(passno--){
+ switch(pass_t){
+ case 0: decode_sigpass(t1, width, height, bpno+1, bandpos,
+ bpass_csty_symbol && (clnpass_cnt >= 4), vert_causal_ctx_csty_symbol);
+ break;
+ case 1: decode_refpass(t1, width, height, bpno+1);
+ if (bpass_csty_symbol && clnpass_cnt >= 4)
+ ff_mqc_initdec(&t1->mqc, cblk->data);
+ break;
+ case 2: decode_clnpass(s, t1, width, height, bpno+1, bandpos,
+ codsty->cblk_style & J2K_CBLK_SEGSYM);
+ clnpass_cnt = clnpass_cnt + 1;
+ if (bpass_csty_symbol && clnpass_cnt >= 4)
+ ff_mqc_initdec(&t1->mqc, cblk->data);
+ break;
+ }
+
+ pass_t++;
+ if (pass_t == 3){
+ bpno--;
+ pass_t = 0;
+ }
+ }
+ return 0;
+}
+
+static void mct_decode(J2kDecoderContext *s, J2kTile *tile)
+{
+ int i, *src[3], i0, i1, i2, csize = 1;
+
+ for (i = 0; i < 3; i++)
+ src[i] = tile->comp[i].data;
+
+ for (i = 0; i < 2; i++)
+ csize *= tile->comp[0].coord[i][1] - tile->comp[0].coord[i][0];
+
+ if (tile->codsty[0].transform == FF_DWT97){
+ for (i = 0; i < csize; i++){
+ i0 = *src[0] + (*src[2] * 46802 >> 16);
+ i1 = *src[0] - (*src[1] * 22553 + *src[2] * 46802 >> 16);
+ i2 = *src[0] + (116130 * *src[1] >> 16);
+ *src[0]++ = i0;
+ *src[1]++ = i1;
+ *src[2]++ = i2;
+ }
+ } else{
+ for (i = 0; i < csize; i++){
+ i1 = *src[0] - (*src[2] + *src[1] >> 2);
+ i0 = i1 + *src[2];
+ i2 = i1 + *src[1];
+ *src[0]++ = i0;
+ *src[1]++ = i1;
+ *src[2]++ = i2;
+ }
+ }
+}
+
+static int decode_tile(J2kDecoderContext *s, J2kTile *tile)
+{
+ int compno, reslevelno, bandno;
+ int x, y, *src[4];
+ uint8_t *line;
+ J2kT1Context t1;
+
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = tile->comp + compno;
+ J2kCodingStyle *codsty = tile->codsty + compno;
+
+ for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+ J2kResLevel *rlevel = comp->reslevel + reslevelno;
+ for (bandno = 0; bandno < rlevel->nbands; bandno++){
+ J2kBand *band = rlevel->band + bandno;
+ int cblkx, cblky, cblkno=0, xx0, x0, xx1, y0, yy0, yy1, bandpos;
+
+ bandpos = bandno + (reslevelno > 0);
+
+ yy0 = bandno == 0 ? 0 : comp->reslevel[reslevelno-1].coord[1][1] - comp->reslevel[reslevelno-1].coord[1][0];
+ y0 = yy0;
+ yy1 = FFMIN(ff_j2k_ceildiv(band->coord[1][0] + 1, band->codeblock_height) * band->codeblock_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;
+
+ for (cblky = 0; cblky < band->cblkny; 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_j2k_ceildiv(band->coord[0][0] + 1, band->codeblock_width) * band->codeblock_width,
+ band->coord[0][1]) - band->coord[0][0] + xx0;
+
+ for (cblkx = 0; cblkx < band->cblknx; cblkx++, cblkno++){
+ int y, x;
+ decode_cblk(s, codsty, &t1, band->cblk + cblkno, xx1 - xx0, yy1 - yy0, bandpos);
+ if (codsty->transform == FF_DWT53){
+ for (y = yy0; y < yy1; y+=s->cdy[compno]){
+ int *ptr = t1.data[y-yy0];
+ for (x = xx0; x < xx1; x+=s->cdx[compno]){
+ comp->data[(comp->coord[0][1] - comp->coord[0][0]) * y + x] = *ptr++ >> 1;
+ }
+ }
+ } else{
+ for (y = yy0; y < yy1; y+=s->cdy[compno]){
+ int *ptr = t1.data[y-yy0];
+ for (x = xx0; x < xx1; x+=s->cdx[compno]){
+ int tmp = ((int64_t)*ptr++) * ((int64_t)band->stepsize) >> 13, tmp2;
+ tmp2 = FFABS(tmp>>1) + (tmp&1);
+ comp->data[(comp->coord[0][1] - comp->coord[0][0]) * y + x] = tmp < 0 ? -tmp2 : tmp2;
+ }
+ }
+ }
+ xx0 = xx1;
+ xx1 = FFMIN(xx1 + band->codeblock_width, band->coord[0][1] - band->coord[0][0] + x0);
+ }
+ yy0 = yy1;
+ yy1 = FFMIN(yy1 + band->codeblock_height, band->coord[1][1] - band->coord[1][0] + y0);
+ }
+ }
+ }
+ ff_j2k_dwt_decode(&comp->dwt, comp->data);
+ src[compno] = comp->data;
+ }
+ if (tile->codsty[0].mct)
+ mct_decode(s, tile);
+
+ if (s->precision <= 8) {
+ for (compno = 0; compno < s->ncomponents; compno++){
+ y = tile->comp[compno].coord[1][0] - s->image_offset_y;
+ line = s->picture->data[0] + y * s->picture->linesize[0];
+ 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;
+
+ for (; x < tile->comp[compno].coord[0][1] - s->image_offset_x; x += s->cdx[compno]) {
+ *src[compno] += 1 << (s->cbps[compno]-1);
+ if (*src[compno] < 0)
+ *src[compno] = 0;
+ else if (*src[compno] >= (1 << s->cbps[compno]))
+ *src[compno] = (1 << s->cbps[compno]) - 1;
+ *dst = *src[compno]++;
+ dst += s->ncomponents;
+ }
+ line += s->picture->linesize[0];
+ }
+ }
+ } else {
+ for (compno = 0; compno < s->ncomponents; compno++) {
+ y = tile->comp[compno].coord[1][0] - s->image_offset_y;
+ line = s->picture->data[0] + y * s->picture->linesize[0];
+ 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 = (uint16_t *)(line + (x * s->ncomponents + compno) * 2);
+ for (; x < tile->comp[compno].coord[0][1] - s->image_offset_x; x += s-> cdx[compno]) {
+ int32_t val;
+
+ val = *src[compno]++ << (16 - s->cbps[compno]);
+ val += 1 << 15;
+ val = av_clip(val, 0, (1 << 16) - 1);
+ *dst = val;
+ dst += s->ncomponents;
+ }
+ line += s->picture->linesize[0];
+ }
+ }
+ }
+ return 0;
+}
+
+static void cleanup(J2kDecoderContext *s)
+{
+ int tileno, compno;
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = s->tile[tileno].comp + compno;
+ J2kCodingStyle *codsty = s->tile[tileno].codsty + compno;
+
+ ff_j2k_cleanup(comp, codsty);
+ }
+ av_freep(&s->tile[tileno].comp);
+ }
+ av_freep(&s->tile);
+}
+
+static int decode_codestream(J2kDecoderContext *s)
+{
+ J2kCodingStyle *codsty = s->codsty;
+ J2kQuantStyle *qntsty = s->qntsty;
+ uint8_t *properties = s->properties;
+
+ for (;;){
+ int oldpos, marker, len, ret = 0;
+
+ if (bytestream2_get_bytes_left(&s->g) < 2){
+ av_log(s->avctx, AV_LOG_ERROR, "Missing EOC\n");
+ break;
+ }
+
+ marker = bytestream2_get_be16u(&s->g);
+ av_dlog(s->avctx, "marker 0x%.4X at pos 0x%x\n", marker, bytestream2_tell(&s->g) - 4);
+ oldpos = bytestream2_tell(&s->g);
+
+ if (marker == J2K_SOD){
+ J2kTile *tile = s->tile + s->curtileno;
+ if (ret = init_tile(s, s->curtileno)) {
+ av_log(s->avctx, AV_LOG_ERROR, "tile initialization failed\n");
+ return ret;
+ }
+ if (ret = decode_packets(s, tile)) {
+ av_log(s->avctx, AV_LOG_ERROR, "packets decoding failed\n");
+ return ret;
+ }
+ continue;
+ }
+ if (marker == J2K_EOC)
+ break;
+
+ if (bytestream2_get_bytes_left(&s->g) < 2)
+ return AVERROR(EINVAL);
+ len = bytestream2_get_be16u(&s->g);
+ switch (marker){
+ case J2K_SIZ:
+ ret = get_siz(s);
+ break;
+ case J2K_COC:
+ ret = get_coc(s, codsty, properties);
+ break;
+ case J2K_COD:
+ ret = get_cod(s, codsty, properties);
+ break;
+ case J2K_QCC:
+ ret = get_qcc(s, len, qntsty, properties);
+ break;
+ case J2K_QCD:
+ ret = get_qcd(s, len, qntsty, properties);
+ break;
+ case J2K_SOT:
+ if (!(ret = get_sot(s))){
+ codsty = s->tile[s->curtileno].codsty;
+ qntsty = s->tile[s->curtileno].qntsty;
+ properties = s->tile[s->curtileno].properties;
+ }
+ break;
+ case J2K_COM:
+ // the comment is ignored
+ bytestream2_skip(&s->g, len - 2);
+ break;
+ default:
+ av_log(s->avctx, AV_LOG_ERROR, "unsupported marker 0x%.4X at pos 0x%x\n", marker, bytestream2_tell(&s->g) - 4);
+ bytestream2_skip(&s->g, len - 2);
+ break;
+ }
+ if (bytestream2_tell(&s->g) - oldpos != len || ret){
+ av_log(s->avctx, AV_LOG_ERROR, "error during processing marker segment %.4x\n", marker);
+ return ret ? ret : -1;
+ }
+ }
+ return 0;
+}
+
+static int jp2_find_codestream(J2kDecoderContext *s)
+{
+ uint32_t atom_size, atom;
+ int found_codestream = 0, search_range = 10;
+
+ while(!found_codestream && 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;
+ } else {
+ if (bytestream2_get_bytes_left(&s->g) < atom_size - 8)
+ return 0;
+ bytestream2_skipu(&s->g, atom_size - 8);
+ search_range--;
+ }
+ }
+
+ if (found_codestream)
+ return 1;
+ return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx,
+ void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ J2kDecoderContext *s = avctx->priv_data;
+ AVFrame *picture = data;
+ int tileno, ret;
+
+ s->picture = picture;
+
+ bytestream2_init(&s->g, avpkt->data, avpkt->size);
+ s->curtileno = -1;
+
+ if (bytestream2_get_bytes_left(&s->g) < 2) {
+ ret = AVERROR(EINVAL);
+ goto err_out;
+ }
+
+ // check if the image is in jp2 format
+ if (bytestream2_get_bytes_left(&s->g) >= 12 &&
+ (bytestream2_get_be32u(&s->g) == 12) &&
+ (bytestream2_get_be32u(&s->g) == JP2_SIG_TYPE) &&
+ (bytestream2_get_be32u(&s->g) == JP2_SIG_VALUE)) {
+ if(!jp2_find_codestream(s)) {
+ av_log(avctx, AV_LOG_ERROR, "couldn't find jpeg2k codestream atom\n");
+ ret = -1;
+ goto err_out;
+ }
+ } else {
+ bytestream2_seek(&s->g, 0, SEEK_SET);
+ }
+
+ if (bytestream2_get_be16u(&s->g) != J2K_SOC){
+ av_log(avctx, AV_LOG_ERROR, "SOC marker not present\n");
+ ret = -1;
+ goto err_out;
+ }
+ if (ret = decode_codestream(s))
+ goto err_out;
+
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++)
+ if (ret = decode_tile(s, s->tile + tileno))
+ goto err_out;
+
+ cleanup(s);
+
+ *got_frame = 1;
+
+ return bytestream2_tell(&s->g);
+
+err_out:
+ cleanup(s);
+ return ret;
+}
+
+static av_cold int j2kdec_init(AVCodecContext *avctx)
+{
+ J2kDecoderContext *s = avctx->priv_data;
+
+ s->avctx = avctx;
+
+ ff_j2k_init_tier1_luts();
+
+ return 0;
+}
+
+AVCodec ff_j2k_decoder = {
+ .name = "j2k",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_JPEG2000,
+ .priv_data_size = sizeof(J2kDecoderContext),
+ .init = j2kdec_init,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_EXPERIMENTAL | CODEC_CAP_FRAME_THREADS,
+ .long_name = NULL_IF_CONFIG_SMALL("JPEG 2000"),
+};
diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c
new file mode 100644
index 0000000..ffbd503
--- /dev/null
+++ b/libavcodec/j2kenc.c
@@ -0,0 +1,1046 @@
+/*
+ * 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 "j2k.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 {
+ J2kComponent *comp;
+} J2kTile;
+
+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;
+
+ J2kCodingStyle codsty;
+ J2kQuantStyle qntsty;
+
+ J2kTile *tile;
+} J2kEncoderContext;
+
+
+/* debug */
+#if 0
+#undef ifprintf
+#undef printf
+
+static void nspaces(FILE *fd, int n)
+{
+ while(n--) putc(' ', fd);
+}
+
+static void printcomp(J2kComponent *comp)
+{
+ int i;
+ for (i = 0; i < comp->y1 - comp->y0; i++)
+ ff_j2k_printv(comp->data + i * (comp->x1 - comp->x0), comp->x1 - comp->x0);
+}
+
+static void dump(J2kEncoderContext *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++){
+ J2kTile *tile = s->tile + tileno;
+ nspaces(fd, 2);
+ fprintf(fd, "tile %d:\n", tileno);
+ for(compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *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++){
+ J2kResLevel *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++){
+ J2kBand *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++){
+ J2kPrec *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(J2kEncoderContext *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(J2kEncoderContext *s, int num, int n)
+{
+ while(--n >= 0)
+ put_bits(s, (num >> n) & 1, 1);
+}
+
+/** flush the bitstream */
+static void j2k_flush(J2kEncoderContext *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(J2kEncoderContext *s, J2kTgtNode *node, int threshold)
+{
+ J2kTgtNode *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(J2kTgtNode *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(J2kEncoderContext *s)
+{
+ int i;
+
+ if (s->buf_end - s->buf < 40 + 3 * s->ncomponents)
+ return -1;
+
+ bytestream_put_be16(&s->buf, J2K_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(J2kEncoderContext *s)
+{
+ J2kCodingStyle *codsty = &s->codsty;
+
+ if (s->buf_end - s->buf < 14)
+ return -1;
+
+ bytestream_put_be16(&s->buf, J2K_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); // transformation
+ return 0;
+}
+
+static int put_qcd(J2kEncoderContext *s, int compno)
+{
+ int i, size;
+ J2kCodingStyle *codsty = &s->codsty;
+ J2kQuantStyle *qntsty = &s->qntsty;
+
+ if (qntsty->quantsty == J2K_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, J2K_QCD);
+ bytestream_put_be16(&s->buf, size); // LQcd
+ bytestream_put_byte(&s->buf, (qntsty->nguardbits << 5) | qntsty->quantsty); // Sqcd
+ if (qntsty->quantsty == J2K_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(J2kEncoderContext *s, int tileno)
+{
+ uint8_t *psotptr;
+
+ if (s->buf_end - s->buf < 12)
+ return NULL;
+
+ bytestream_put_be16(&s->buf, J2K_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(J2kEncoderContext *s)
+{
+ int tileno, tilex, tiley, compno;
+ J2kCodingStyle *codsty = &s->codsty;
+ J2kQuantStyle *qntsty = &s->qntsty;
+
+ s->numXtiles = ff_j2k_ceildiv(s->width, s->tile_width);
+ s->numYtiles = ff_j2k_ceildiv(s->height, s->tile_height);
+
+ s->tile = av_malloc(s->numXtiles * s->numYtiles * sizeof(J2kTile));
+ if (!s->tile)
+ return AVERROR(ENOMEM);
+ for (tileno = 0, tiley = 0; tiley < s->numYtiles; tiley++)
+ for (tilex = 0; tilex < s->numXtiles; tilex++, tileno++){
+ J2kTile *tile = s->tile + tileno;
+
+ tile->comp = av_malloc(s->ncomponents * sizeof(J2kComponent));
+ if (!tile->comp)
+ return AVERROR(ENOMEM);
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = tile->comp + compno;
+ int ret, i, j;
+
+ comp->coord[0][0] = tilex * s->tile_width;
+ comp->coord[0][1] = FFMIN((tilex+1)*s->tile_width, s->width);
+ comp->coord[1][0] = tiley * s->tile_height;
+ comp->coord[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] = ff_j2k_ceildivpow2(comp->coord[i][j], s->chroma_shift[i]);
+
+ if (ret = ff_j2k_init_component(comp, codsty, qntsty, s->cbps[compno], compno?1<<s->chroma_shift[0]:1, compno?1<<s->chroma_shift[1]:1))
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static void copy_frame(J2kEncoderContext *s)
+{
+ int tileno, compno, i, y, x;
+ uint8_t *line;
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ J2kTile *tile = s->tile + tileno;
+ if (s->planar){
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = tile->comp + compno;
+ int *dst = comp->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].data[i] = *ptr++ - (1 << 7);
+ }
+ }
+ line += s->picture.linesize[0];
+ }
+ }
+ }
+}
+
+static void init_quantization(J2kEncoderContext *s)
+{
+ int compno, reslevelno, bandno;
+ J2kQuantStyle *qntsty = &s->qntsty;
+ J2kCodingStyle *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 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(J2kT1Context *t1, int width, int height, int bandno, int *nmsedec, int bpno)
+{
+ int y0, x, y, mask = 1 << (bpno + NMSEDEC_FRACBITS);
+ int vert_causal_ctx_csty_loc_symbol;
+ 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] & J2K_T1_SIG) && (t1->flags[y+1][x+1] & J2K_T1_SIG_NB)){
+ int ctxno = ff_j2k_getnbctxno(t1->flags[y+1][x+1], bandno, vert_causal_ctx_csty_loc_symbol),
+ 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_j2k_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_j2k_set_significant(t1, x, y, t1->flags[y+1][x+1] >> 15);
+ }
+ t1->flags[y+1][x+1] |= J2K_T1_VIS;
+ }
+ }
+}
+
+static void encode_refpass(J2kT1Context *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] & (J2K_T1_SIG | J2K_T1_VIS)) == J2K_T1_SIG){
+ int ctxno = ff_j2k_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] |= J2K_T1_REF;
+ }
+}
+
+static void encode_clnpass(J2kT1Context *t1, int width, int height, int bandno, int *nmsedec, int bpno)
+{
+ int y0, x, y, mask = 1 << (bpno + NMSEDEC_FRACBITS);
+ int vert_causal_ctx_csty_loc_symbol;
+ for (y0 = 0; y0 < height; y0 += 4)
+ for (x = 0; x < width; x++){
+ if (y0 + 3 < height && !(
+ (t1->flags[y0+1][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+ (t1->flags[y0+2][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+ (t1->flags[y0+3][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+ (t1->flags[y0+4][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_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] & (J2K_T1_SIG | J2K_T1_VIS))){
+ int ctxno = ff_j2k_getnbctxno(t1->flags[y+1][x+1], bandno, vert_causal_ctx_csty_loc_symbol);
+ 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_j2k_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_j2k_set_significant(t1, x, y, t1->flags[y+1][x+1] >> 15);
+ }
+ }
+ t1->flags[y+1][x+1] &= ~J2K_T1_VIS;
+ }
+ } else{
+ for (y = y0; y < y0 + 4 && y < height; y++){
+ if (!(t1->flags[y+1][x+1] & (J2K_T1_SIG | J2K_T1_VIS))){
+ int ctxno = ff_j2k_getnbctxno(t1->flags[y+1][x+1], bandno, vert_causal_ctx_csty_loc_symbol);
+ 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_j2k_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_j2k_set_significant(t1, x, y, t1->flags[y+1][x+1] >> 15);
+ }
+ }
+ t1->flags[y+1][x+1] &= ~J2K_T1_VIS;
+ }
+ }
+ }
+}
+
+static void encode_cblk(J2kEncoderContext *s, J2kT1Context *t1, J2kCblk *cblk, J2kTile *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] |= J2K_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(J2kEncoderContext *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(J2kEncoderContext *s, J2kResLevel *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++){
+ J2kBand *band = rlevel->band + bandno;
+ J2kPrec *prec = band->prec + precno;
+ int yi, xi, pos;
+ int cblknw = prec->xi1 - prec->xi0;
+
+ if (band->coord[0][0] == band->coord[0][1]
+ || band->coord[1][0] == band->coord[1][1])
+ continue;
+
+ for (pos=0, yi = prec->yi0; yi < prec->yi1; yi++){
+ for (xi = prec->xi0; xi < prec->xi1; xi++, pos++){
+ prec->cblkincl[pos].val = band->cblk[yi * cblknw + xi].ninclpasses == 0;
+ tag_tree_update(prec->cblkincl + pos);
+ prec->zerobits[pos].val = expn[bandno] + numgbits - 1 - band->cblk[yi * cblknw + xi].nonzerobits;
+ tag_tree_update(prec->zerobits + pos);
+ }
+ }
+
+ for (pos=0, yi = prec->yi0; yi < prec->yi1; yi++){
+ for (xi = prec->xi0; xi < prec->xi1; xi++, pos++){
+ int pad = 0, llen, length;
+ J2kCblk *cblk = band->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++){
+ J2kBand *band = rlevel->band + bandno;
+ J2kPrec *prec = band->prec + precno;
+ int yi, cblknw = prec->xi1 - prec->xi0;
+ for (yi = prec->yi0; yi < prec->yi1; yi++){
+ int xi;
+ for (xi = prec->xi0; xi < prec->xi1; xi++){
+ J2kCblk *cblk = band->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(J2kEncoderContext *s, J2kTile *tile, int tileno)
+{
+ int compno, reslevelno, ret;
+ J2kCodingStyle *codsty = &s->codsty;
+ J2kQuantStyle *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;
+ J2kResLevel *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(J2kCblk *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(J2kEncoderContext *s, J2kTile *tile)
+{
+ int compno, reslevelno, bandno, cblkno, lev;
+ J2kCodingStyle *codsty = &s->codsty;
+
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = tile->comp + compno;
+
+ for (reslevelno = 0, lev = codsty->nreslevels-1; reslevelno < codsty->nreslevels; reslevelno++, lev--){
+ J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+ for (bandno = 0; bandno < reslevel->nbands ; bandno++){
+ int bandpos = bandno + (reslevelno > 0);
+ J2kBand *band = reslevel->band + bandno;
+
+ for (cblkno = 0; cblkno < band->cblknx * band->cblkny; cblkno++){
+ J2kCblk *cblk = band->cblk + cblkno;
+
+ cblk->ninclpasses = getcut(cblk, s->lambda,
+ (int64_t)dwt_norms[codsty->transform][bandpos][lev] * (int64_t)band->stepsize >> 13);
+ }
+ }
+ }
+ }
+}
+
+static int encode_tile(J2kEncoderContext *s, J2kTile *tile, int tileno)
+{
+ int compno, reslevelno, bandno, ret;
+ J2kT1Context t1;
+ J2kCodingStyle *codsty = &s->codsty;
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = s->tile[tileno].comp + compno;
+
+ av_log(s->avctx, AV_LOG_DEBUG,"dwt\n");
+ if (ret = ff_j2k_dwt_encode(&comp->dwt, comp->data))
+ return ret;
+ av_log(s->avctx, AV_LOG_DEBUG,"after dwt -> tier1\n");
+
+ for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+ J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+ for (bandno = 0; bandno < reslevel->nbands ; bandno++){
+ J2kBand *band = reslevel->band + bandno;
+ 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_j2k_ceildiv(band->coord[1][0] + 1, band->codeblock_height) * band->codeblock_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 < band->cblkny; 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_j2k_ceildiv(band->coord[0][0] + 1, band->codeblock_width) * band->codeblock_width,
+ band->coord[0][1]) - band->coord[0][0] + xx0;
+
+ for (cblkx = 0; cblkx < band->cblknx; 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->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->data[(comp->coord[0][1] - comp->coord[0][0]) * y + x]);
+ *ptr = (int64_t)*ptr * (int64_t)(8192 * 8192 / band->stepsize) >> 13 - NMSEDEC_FRACBITS;
+ ptr++;
+ }
+ }
+ }
+ encode_cblk(s, &t1, band->cblk + cblkno, tile, xx1 - xx0, yy1 - yy0,
+ bandpos, codsty->nreslevels - reslevelno - 1);
+ xx0 = xx1;
+ xx1 = FFMIN(xx1 + band->codeblock_width, band->coord[0][1] - band->coord[0][0] + x0);
+ }
+ yy0 = yy1;
+ yy1 = FFMIN(yy1 + band->codeblock_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(J2kEncoderContext *s)
+{
+ int tileno, compno;
+ J2kCodingStyle *codsty = &s->codsty;
+
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = s->tile[tileno].comp + compno;
+ ff_j2k_cleanup(comp, codsty);
+ }
+ av_freep(&s->tile[tileno].comp);
+ }
+ av_freep(&s->tile);
+}
+
+static void reinit(J2kEncoderContext *s)
+{
+ int tileno, compno;
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ J2kTile *tile = s->tile + tileno;
+ for (compno = 0; compno < s->ncomponents; compno++)
+ ff_j2k_reinit(tile->comp + compno, &s->codsty);
+ }
+}
+
+static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pict, int *got_packet)
+{
+ int tileno, ret;
+ J2kEncoderContext *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, J2K_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, J2K_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, J2K_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;
+ J2kEncoderContext *s = avctx->priv_data;
+ J2kCodingStyle *codsty = &s->codsty;
+ J2kQuantStyle *qntsty = &s->qntsty;
+
+ s->avctx = avctx;
+ av_log(s->avctx, AV_LOG_DEBUG, "init\n");
+
+ // defaults:
+ // TODO: implement setting non-standard precinct size
+ codsty->log2_prec_width = 15;
+ codsty->log2_prec_height = 15;
+ codsty->nreslevels = 7;
+ codsty->log2_cblk_width = 4;
+ codsty->log2_cblk_height = 4;
+ codsty->transform = 1;
+
+ qntsty->nguardbits = 1;
+
+ s->tile_width = 256;
+ s->tile_height = 256;
+
+ if (codsty->transform == FF_DWT53)
+ qntsty->quantsty = J2K_QSTY_NONE;
+ else
+ qntsty->quantsty = J2K_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_j2k_init_tier1_luts();
+
+ 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)
+{
+ J2kEncoderContext *s = avctx->priv_data;
+
+ cleanup(s);
+ return 0;
+}
+
+AVCodec ff_j2k_encoder = {
+ .name = "j2k",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_JPEG2000,
+ .priv_data_size = sizeof(J2kEncoderContext),
+ .init = j2kenc_init,
+ .encode2 = encode_frame,
+ .close = j2kenc_destroy,
+ .capabilities = CODEC_CAP_EXPERIMENTAL,
+ .long_name = NULL_IF_CONFIG_SMALL("JPEG 2000"),
+ .pix_fmts = (const enum AVPixelFormat[]) {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_YUV444P, AV_PIX_FMT_GRAY8,
+/* AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,*/
+ AV_PIX_FMT_NONE
+ }
+};
diff --git a/libavcodec/jacosub.h b/libavcodec/jacosub.h
new file mode 100644
index 0000000..c3665ae
--- /dev/null
+++ b/libavcodec/jacosub.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * JACOsub shared utils
+ */
+
+#ifndef AVCODEC_JACOSUB_H
+#define AVCODEC_JACOSUB_H
+
+#include "libavutil/common.h"
+
+#define JSS_MAX_LINESIZE 512
+
+static av_always_inline int jss_whitespace(char c)
+{
+ return c == ' ' || (c >= '\t' && c <= '\r');
+}
+
+static av_always_inline const char *jss_skip_whitespace(const char *p)
+{
+ while (jss_whitespace(*p))
+ p++;
+ return p;
+}
+
+#endif /* AVCODEC_JACOSUB_H */
diff --git a/libavcodec/jacosubdec.c b/libavcodec/jacosubdec.c
new file mode 100644
index 0000000..b64fac8
--- /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/jpeg2000.c b/libavcodec/jpeg2000.c
index 705399a..060b1fd 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
*/
diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h
index 1e46f07..c2d6d90 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
*/
diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c
index 8c49ea9..f7e6b6e 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
*/
@@ -862,6 +862,7 @@ static int decode_cblk(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty,
for (y = 0; y < height; y++)
memset(t1->data[y], 0, width * sizeof(width));
+
/* If code-block contains no compressed data: nothing to do. */
if (!cblk->length)
return 0;
@@ -1276,6 +1277,8 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, void *data,
"couldn't find jpeg2k codestream atom\n");
return -1;
}
+ } else if (AV_RB16(s->buf) != JPEG2000_SOC && AV_RB32(s->buf + 4) == JP2_CODESTREAM) {
+ s->buf += 8;
}
if (bytestream_get_be16(&s->buf) != JPEG2000_SOC) {
@@ -1298,12 +1301,14 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, void *data,
for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++)
if (ret = jpeg2000_decode_tile(s, s->tile + tileno, picture))
goto end;
+ jpeg2000_dec_cleanup(s);
*got_frame = 1;
+ return s->buf - s->buf_start;
end:
jpeg2000_dec_cleanup(s);
- return ret ? ret : s->buf - s->buf_start;
+ return ret;
}
static void jpeg2000_init_static_data(AVCodec *codec)
diff --git a/libavcodec/jpeg2000dwt.c b/libavcodec/jpeg2000dwt.c
index 0601e5a..080b0a0 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
*/
diff --git a/libavcodec/jpeg2000dwt.h b/libavcodec/jpeg2000dwt.h
index 9aaa18b..2abfd15 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
*/
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 6d884a4..b13f9ef 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;
- 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,17 +300,19 @@ 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 */
- 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++) {
@@ -319,7 +324,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);
@@ -329,12 +334,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) {
@@ -343,7 +349,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 */
av_log(s->avctx, AV_LOG_ERROR,
@@ -359,20 +365,20 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near,
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..18cc73f 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
*/
@@ -43,6 +43,7 @@ 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);
+ avcodec_get_frame_defaults(&s->frame);
return 0;
}
@@ -134,24 +135,28 @@ 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)
@@ -160,20 +165,19 @@ static int decode_frame(AVCodecContext *avctx,
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;
@@ -191,7 +195,7 @@ static int decode_frame(AVCodecContext *avctx,
*got_frame = 1;
}
- return buf_size;
+ return avpkt->size;
}
static av_cold int decode_close(AVCodecContext *avctx)
diff --git a/libavcodec/kbdwin.c b/libavcodec/kbdwin.c
index 1b7313d..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 74ae6b7..9c48239 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
*/
@@ -50,7 +50,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;
@@ -73,9 +73,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];
+ out = frame->data[0];
if (c->prev.data[0]) {
- prev = (uint16_t *) c->prev.data[0];
+ prev = c->prev.data[0];
} else {
prev = NULL;
}
@@ -83,16 +83,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 +109,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 +118,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,19 +133,12 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
count = 4 + *buf++;
}
- if (outcnt < offset)
+ if (outcnt < offset || maxcnt - outcnt < count)
break;
- inp = out;
- inp_off = outcnt - offset;
- }
-
- if (maxcnt - outcnt < count)
- break;
-
- for (i = inp_off; i < count + inp_off; i++) {
- out[outcnt++] = inp[i];
+ av_memcpy_backptr(out + 2 * outcnt, 2 * offset, 2 * count);
}
+ outcnt += count;
}
}
diff --git a/libavcodec/kmvc.c b/libavcodec/kmvc.c
index 574d053..20aae67 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
*/
@@ -106,6 +106,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) > 316*196) {
+ 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);
@@ -127,6 +131,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) > 318*198) {
+ 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);
@@ -198,6 +206,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) > 318*198) {
+ 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);
@@ -219,6 +231,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) > 318*198) {
+ 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);
@@ -255,10 +271,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);
@@ -266,7 +280,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);
@@ -284,7 +298,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);
}
}
@@ -370,7 +384,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) {
@@ -379,7 +393,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 9d84d26..4285644 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;
}
@@ -249,8 +249,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 +276,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 +294,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 +378,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 +398,7 @@ output_zeros:
dst += i;
}
}
- return src_start - src;
+ return src - src_start;
}
@@ -407,7 +411,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 +419,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 +509,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 +518,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 +530,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 +588,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 +597,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 +605,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 +645,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 +669,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 +696,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 957143d..ad7ef91 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 0fb303c..09beb98 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"
@@ -79,11 +81,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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);
+ if ((ret = ff_alloc_packet2(avctx, pkt, max_size)) < 0)
return ret;
- }
*p = *pict;
p->pict_type= AV_PICTURE_TYPE_I;
@@ -136,13 +135,14 @@ 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;
- // 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..68850c5
--- /dev/null
+++ b/libavcodec/libaacplus.c
@@ -0,0 +1,143 @@
+/*
+ * 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 -1;
+ }
+
+ 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 -1;
+ }
+
+ /* check aacplus version */
+ aacplus_cfg = aacplusEncGetCurrentConfiguration(s->aacplus_handle);
+
+ /* put the options in the configuration struct */
+ 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);
+ aacplusEncClose(s->aacplus_handle);
+ return -1;
+ }
+
+ 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 -1;
+ }
+
+ 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",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("libaacplus AAC+ (Advanced Audio Codec with SBR+PS)"),
+ .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 0e1c2e1..826a547 100644
--- a/libavcodec/libavcodec.v
+++ b/libavcodec/libavcodec.v
@@ -1,6 +1,33 @@
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*;
+ #XBMC's configure checks for ff_vdpau_vc1_decode_picture()
+ ff_vdpau_vc1_decode_picture;
+ 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..53bbb72
--- /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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("Xiph CELT decoder using libcelt"),
+};
diff --git a/libavcodec/libfaac.c b/libavcodec/libfaac.c
index 6359344..ac18fe2 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;
@@ -174,10 +173,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-aacenc.c b/libavcodec/libfdk-aacenc.c
index ef154c1..e3992e1 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
*/
@@ -329,10 +329,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 ddf7b23..8250a15 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",
.type = AVMEDIA_TYPE_AUDIO,
@@ -123,7 +127,8 @@ AVCodec ff_libgsm_encoder = {
AV_SAMPLE_FMT_NONE },
.long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"),
};
-
+#endif
+#if CONFIG_LIBGSM_MS_ENCODER
AVCodec ff_libgsm_ms_encoder = {
.name = "libgsm_ms",
.type = AVMEDIA_TYPE_AUDIO,
@@ -135,6 +140,7 @@ AVCodec ff_libgsm_ms_encoder = {
AV_SAMPLE_FMT_NONE },
.long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"),
};
+#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",
.type = AVMEDIA_TYPE_AUDIO,
@@ -231,7 +237,8 @@ AVCodec ff_libgsm_decoder = {
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"),
};
-
+#endif
+#if CONFIG_LIBGSM_MS_DECODER
AVCodec ff_libgsm_ms_decoder = {
.name = "libgsm_ms",
.type = AVMEDIA_TYPE_AUDIO,
@@ -244,3 +251,4 @@ AVCodec ff_libgsm_ms_decoder = {
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"),
};
+#endif
diff --git a/libavcodec/libilbc.c b/libavcodec/libilbc.c
index 714fdb0..b4163c6 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 5e7caf8..95771af 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);
@@ -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);
@@ -264,6 +264,7 @@ static int mp3lame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
#define AE AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
{ "reservoir", "Use bit reservoir.", OFFSET(reservoir), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AE },
+ { "joint_stereo", "Use joint stereo.", OFFSET(joint_stereo), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AE },
{ NULL },
};
diff --git a/libavcodec/libopencore-amr.c b/libavcodec/libopencore-amr.c
index 1f71a5b..c991106 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;
@@ -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,
@@ -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 9ff1429..ec6e275 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,16 +203,14 @@ 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;
-
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++;
@@ -282,9 +266,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 +292,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 +309,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,7 +389,6 @@ 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 },
};
@@ -434,6 +407,7 @@ AVCodec ff_libopenjpeg_decoder = {
.init = libopenjpeg_decode_init,
.decode = libopenjpeg_decode_frame,
.capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
+ .max_lowres = 31,
.long_name = NULL_IF_CONFIG_SMALL("OpenJPEG JPEG 2000"),
.priv_class = &class,
};
diff --git a/libavcodec/libopenjpegenc.c b/libavcodec/libopenjpegenc.c
index 09b115b..c355083 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,6 +34,12 @@
#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;
@@ -66,36 +72,40 @@ 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_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:
color_space = CLRSPC_SRGB;
break;
case AV_PIX_FMT_YUV410P:
@@ -105,15 +115,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:
@@ -125,18 +152,17 @@ static opj_image_t *libopenjpeg_create_image(AVCodecContext *avctx,
cmptparm = av_mallocz(numcomps * sizeof(*cmptparm));
if (!cmptparm) {
- av_log(avctx, AV_LOG_ERROR, "Not enough memory");
+ av_log(avctx, AV_LOG_ERROR, "Not enough memory\n");
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];
+ cmptparm[i].h = avctx->height / sub_dy[i];
}
img = opj_image_create(numcomps, cmptparm, color_space);
@@ -151,16 +177,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) {
@@ -174,15 +229,16 @@ static av_cold int libopenjpeg_encode_init(AVCodecContext *avctx)
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;
}
+ 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);
@@ -194,94 +250,131 @@ fail:
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_index;
+ 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;
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->comps[compno].data[image_index++] = frame->data[0][frame_index];
frame_index += numcomps;
}
}
}
+
+ 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_index;
+ 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;
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->comps[compno].data[image_index++] = frame_ptr[frame_index];
frame_index += numcomps;
}
}
}
+
+ 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_index;
+ 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;
frame_index = y * frame->linesize[compno];
for (x = 0; x < width; ++x)
- image->comps[compno].data[image_index++] =
- frame->data[compno][frame_index++];
+ image->comps[compno].data[image_index++] = frame->data[compno][frame_index++];
}
}
+
+ 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_index;
+ 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;
frame_index = y * (frame->linesize[compno] / 2);
for (x = 0; x < width; ++x)
- image->comps[compno].data[image_index++] =
- frame_ptr[frame_index++];
+ image->comps[compno].data[image_index++] = frame_ptr[frame_index++];
}
}
+
+ return 1;
}
static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
@@ -291,7 +384,9 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
opj_cinfo_t *compress = ctx->compress;
opj_image_t *image = ctx->image;
opj_cio_t *stream;
+ int cpyresult = 0;
int ret, len;
+ AVFrame gbrframe;
// x0, y0 is the top left corner of the image
// x1, y1 is the width, height of the reference grid
@@ -303,11 +398,31 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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_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 +432,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,6 +471,12 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
break;
}
+ if (!cpyresult) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Could not copy the frame data to the internal image buffer\n");
+ return -1;
+ }
+
opj_setup_encoder(compress, &ctx->enc_params, image);
stream = opj_cio_open((opj_common_ptr)compress, NULL, 0);
if (!stream) {
@@ -353,7 +491,7 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
len = cio_tell(stream);
- if ((ret = ff_alloc_packet(pkt, len)) < 0) {
+ if ((ret = ff_alloc_packet2(avctx, pkt, len)) < 0) {
opj_cio_close(stream);
return ret;
}
@@ -396,11 +534,11 @@ 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 },
};
@@ -421,14 +559,21 @@ 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_NONE
},
.long_name = NULL_IF_CONFIG_SMALL("OpenJPEG JPEG 2000"),
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 8c33e91..9b5cfe7 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 f124e19..59caac7 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. */
@@ -324,10 +331,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,
@@ -354,7 +359,7 @@ static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt,
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 7fedc63..2e0ce5d 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 210dd34..21af65e 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..521ac17
--- /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;
+ if (shine_find_bitrate_index(s->config.mpeg.bitr) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid bitrate\n");
+ return AVERROR(EINVAL);
+ }
+ 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;
+ s->shine = shine_initialise(&s->config);
+ if (!s->shine)
+ return AVERROR(ENOMEM);
+ avctx->frame_size = samp_per_frame;
+ 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_frame(s->shine, frame->data[0], &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",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = 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 },
+ .long_name = NULL_IF_CONFIG_SMALL("libshine MP3 (MPEG audio layer 3)"),
+};
diff --git a/libavcodec/libspeexdec.c b/libavcodec/libspeexdec.c
index 5b65696..213eee4 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
@@ -127,7 +137,7 @@ static int libspeex_decode_frame(AVCodecContext *avctx, void *data,
current packet, otherwise ignore the current packet and keep decoding
frames from the libspeex buffer. */
if (speex_bits_remaining(&s->bits) < 5 ||
- speex_bits_peek_unsigned(&s->bits, 5) == 0x1F) {
+ speex_bits_peek_unsigned(&s->bits, 5) == 0xF) {
/* check for flush packet */
if (!buf || !buf_size) {
*got_frame_ptr = 0;
diff --git a/libavcodec/libspeexenc.c b/libavcodec/libspeexenc.c
index 9469a76..b96ca1b 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);
diff --git a/libavcodec/libstagefright.cpp b/libavcodec/libstagefright.cpp
new file mode 100644
index 0000000..a6fd1b9
--- /dev/null
+++ b/libavcodec/libstagefright.cpp
@@ -0,0 +1,597 @@
+/*
+ * 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"
+}
+
+#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);
+ 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) {
+ avctx->release_buffer(avctx, s->prev_frame);
+ av_freep(&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) {
+ avctx->release_buffer(avctx, frame->vframe);
+ av_freep(&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) {
+ avctx->release_buffer(avctx, s->prev_frame);
+ av_freep(&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) {
+ avctx->release_buffer(avctx, frame->vframe);
+ av_freep(&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 3990692..a2e5b74 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..8858714
--- /dev/null
+++ b/libavcodec/libtwolame.c
@@ -0,0 +1,196 @@
+/*
+ * 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_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",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("libtwolame MP2 (MPEG audio layer 2)"),
+ .priv_class = &libtwolame_class,
+};
diff --git a/libavcodec/libutvideo.h b/libavcodec/libutvideo.h
new file mode 100644
index 0000000..b35d19c
--- /dev/null
+++ b/libavcodec/libutvideo.h
@@ -0,0 +1,61 @@
+/*
+ * 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)
+ */
+
+#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
+
+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..bc491e2
--- /dev/null
+++ b/libavcodec/libutvideodec.cpp
@@ -0,0 +1,199 @@
+/*
+ * 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)
+ */
+
+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) {
+ 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..07205f7
--- /dev/null
+++ b/libavcodec/libutvideoenc.cpp
@@ -0,0 +1,239 @@
+/*
+ * 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)
+ */
+
+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 3e5efb3..4f4cbe7 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",
.type = AVMEDIA_TYPE_AUDIO,
@@ -187,6 +192,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 af6ddf4..a068cd0 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
*/
@@ -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);
diff --git a/libavcodec/libvorbisdec.c b/libavcodec/libvorbisdec.c
new file mode 100644
index 0000000..c4142cd
--- /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 = 1;
+ 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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("libvorbis"),
+};
diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbisenc.c
index 8e02057..d3f86cc 100644
--- a/libavcodec/libvorbis.c
+++ b/libavcodec/libvorbisenc.c
@@ -1,42 +1,34 @@
/*
- * copyright (c) 2002 Mark Hills <mark@pogo.org.uk>
+ * Copyright (c) 2002 Mark Hills <mark@pogo.org.uk>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/**
- * @file
- * Vorbis encoding support via libvorbisenc.
- * @author Mark Hills <mark@pogo.org.uk>
- */
-
#include <vorbis/vorbisenc.h>
+#include "libavutil/avassert.h"
#include "libavutil/fifo.h"
#include "libavutil/opt.h"
#include "avcodec.h"
#include "audio_frame_queue.h"
-#include "bytestream.h"
#include "internal.h"
#include "vorbis.h"
#include "vorbis_parser.h"
-#undef NDEBUG
-#include <assert.h>
/* Number of samples the user should send in each call.
* This value is used because it is the LCD of all possible frame sizes, so
@@ -47,8 +39,9 @@
#define BUFFER_SIZE (1024 * 64)
-typedef struct OggVorbisContext {
+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 */
@@ -56,14 +49,13 @@ typedef struct OggVorbisContext {
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;
+} OggVorbisEncContext;
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 },
+ { "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 }
};
@@ -72,8 +64,12 @@ static const AVCodecDefault defaults[] = {
{ NULL },
};
-static const AVClass class = { "libvorbis", av_default_item_name, options, LIBAVUTIL_VERSION_INT };
-
+static const AVClass 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)
{
@@ -88,7 +84,7 @@ static int vorbis_error_to_averror(int ov_err)
static av_cold int oggvorbis_init_encoder(vorbis_info *vi,
AVCodecContext *avctx)
{
- OggVorbisContext *s = avctx->priv_data;
+ OggVorbisEncContext *s = avctx->priv_data;
double cfreq;
int ret;
@@ -118,14 +114,14 @@ static av_cold int oggvorbis_init_encoder(vorbis_info *vi,
/* variable bitrate by estimate, disable slow rate management */
if (minrate == -1 && maxrate == -1)
if ((ret = vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE2_SET, NULL)))
- goto error;
+ goto error; /* should not happen */
}
/* cutoff frequency */
if (avctx->cutoff > 0) {
cfreq = avctx->cutoff / 1000.0;
if ((ret = vorbis_encode_ctl(vi, OV_ECTL_LOWPASS_SET, &cfreq)))
- goto error;
+ goto error; /* should not happen */
}
/* impulse block bias */
@@ -134,6 +130,35 @@ static av_cold int oggvorbis_init_encoder(vorbis_info *vi,
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;
@@ -150,7 +175,7 @@ static int xiph_len(int l)
static av_cold int oggvorbis_encode_close(AVCodecContext *avctx)
{
- OggVorbisContext *s = avctx->priv_data;
+ OggVorbisEncContext *s = avctx->priv_data;
/* notify vorbisenc this is EOF */
if (s->dsp_initialized)
@@ -169,7 +194,7 @@ static av_cold int oggvorbis_encode_close(AVCodecContext *avctx)
static av_cold int oggvorbis_encode_init(AVCodecContext *avctx)
{
- OggVorbisContext *s = avctx->priv_data;
+ OggVorbisEncContext *s = avctx->priv_data;
ogg_packet header, header_comm, header_code;
uint8_t *p;
unsigned int offset;
@@ -193,7 +218,8 @@ static av_cold int oggvorbis_encode_init(AVCodecContext *avctx)
}
vorbis_comment_init(&s->vc);
- vorbis_comment_add_tag(&s->vc, "encoder", LIBAVCODEC_IDENT);
+ if (!(avctx->flags & CODEC_FLAG_BITEXACT))
+ vorbis_comment_add_tag(&s->vc, "encoder", LIBAVCODEC_IDENT);
if ((ret = vorbis_analysis_headerout(&s->vd, &s->vc, &header, &header_comm,
&header_code))) {
@@ -220,7 +246,7 @@ static av_cold int oggvorbis_encode_init(AVCodecContext *avctx)
offset += header_comm.bytes;
memcpy(&p[offset], header_code.packet, header_code.bytes);
offset += header_code.bytes;
- assert(offset == avctx->extradata_size);
+ av_assert0(offset == avctx->extradata_size);
if ((ret = avpriv_vorbis_parse_extradata(avctx, &s->vp)) < 0) {
av_log(avctx, AV_LOG_ERROR, "invalid extradata\n");
@@ -247,7 +273,7 @@ error:
static int oggvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
const AVFrame *frame, int *got_packet_ptr)
{
- OggVorbisContext *s = avctx->priv_data;
+ OggVorbisEncContext *s = avctx->priv_data;
ogg_packet op;
int ret, duration;
@@ -289,7 +315,7 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
/* add any available packets to the output packet buffer */
while ((ret = vorbis_bitrate_flushpacket(&s->vd, &op)) == 1) {
if (av_fifo_space(s->pkt_fifo) < sizeof(ogg_packet) + op.bytes) {
- av_log(avctx, AV_LOG_ERROR, "packet buffer is too small");
+ av_log(avctx, AV_LOG_ERROR, "packet buffer is too small\n");
return AVERROR_BUG;
}
av_fifo_generic_write(s->pkt_fifo, &op, sizeof(ogg_packet), NULL);
@@ -311,10 +337,8 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
av_fifo_generic_read(s->pkt_fifo, &op, sizeof(ogg_packet), NULL);
- if ((ret = ff_alloc_packet(avpkt, op.bytes))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, op.bytes)) < 0)
return ret;
- }
av_fifo_generic_read(s->pkt_fifo, avpkt->data, op.bytes, NULL);
avpkt->pts = ff_samples_to_time_base(avctx, op.granulepos);
@@ -323,9 +347,11 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
if (duration > 0) {
/* we do not know encoder delay until we get the first packet from
* libvorbis, so we have to update the AudioFrameQueue counts */
- if (!avctx->delay) {
+ if (!avctx->delay && s->afq.frames) {
avctx->delay = duration;
- s->afq.remaining_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);
@@ -339,14 +365,14 @@ AVCodec ff_libvorbis_encoder = {
.name = "libvorbis",
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_VORBIS,
- .priv_data_size = sizeof(OggVorbisContext),
+ .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 },
- .long_name = NULL_IF_CONFIG_SMALL("libvorbis Vorbis"),
+ .long_name = NULL_IF_CONFIG_SMALL("libvorbis"),
.priv_class = &class,
.defaults = defaults,
};
diff --git a/libavcodec/libvpxdec.c b/libavcodec/libvpxdec.c
index 237b0f6..5e80a9f 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
*/
diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c
index 0ecc2f9..4f1adb8 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,6 +30,7 @@
#include "avcodec.h"
#include "internal.h"
+#include "libavutil/avassert.h"
#include "libavutil/base64.h"
#include "libavutil/common.h"
#include "libavutil/mathematics.h"
@@ -47,6 +48,9 @@ struct FrameListData {
unsigned long duration; /**< duration to show frame
(in timebase units) */
uint32_t flags; /**< flags for this frame */
+ uint64_t sse[4];
+ int have_sse; /**< true if we have pending sse[] */
+ uint64_t frame_number;
struct FrameListData *next;
};
@@ -55,16 +59,30 @@ typedef struct VP8EncoderContext {
struct vpx_codec_ctx encoder;
struct vpx_image rawimg;
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 +104,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)
@@ -219,6 +238,7 @@ static av_cold int vpx_init(AVCodecContext *avctx,
{
VP8Context *ctx = avctx->priv_data;
struct vpx_codec_enc_cfg enccfg;
+ 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());
@@ -229,6 +249,13 @@ static av_cold int vpx_init(AVCodecContext *avctx,
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 +263,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 +272,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 +324,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,11 +367,11 @@ 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);
@@ -336,6 +381,8 @@ static av_cold int vpx_init(AVCodecContext *avctx,
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,6 +395,10 @@ 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,
@@ -363,13 +414,30 @@ 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,
+ 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 */
+ }
}
/**
@@ -382,7 +450,7 @@ 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);
if (ret >= 0) {
memcpy(pkt->data, cx_frame->buf, pkt->size);
pkt->pts = pkt->dts = cx_frame->pts;
@@ -394,9 +462,20 @@ 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;
+ }
} else {
- av_log(avctx, AV_LOG_ERROR,
- "Error getting output packet of size %zu.\n", cx_frame->sz);
return ret;
}
return pkt->size;
@@ -438,8 +517,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, ctx);
size = storeframe(avctx, &cx_frame, pkt_out, coded_frame);
if (size < 0)
return size;
@@ -452,13 +531,14 @@ 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, 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);
@@ -467,8 +547,8 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out,
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 +558,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;
@@ -554,6 +641,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 +649,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 }
};
diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c
index bb92110..51c28a4 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
*/
@@ -43,7 +43,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;
@@ -102,16 +105,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++){
@@ -122,22 +130,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];
}
@@ -148,7 +175,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);
}
@@ -207,6 +234,20 @@ static av_cold int X264_close(AVCodecContext *avctx)
return 0;
}
+#define OPT_STR(opt, param) \
+ do { \
+ int ret; \
+ if (param && (ret = x264_param_parse(&x4->params, opt, param)) < 0) { \
+ if(ret == X264_PARAM_BAD_NAME) \
+ av_log(avctx, AV_LOG_ERROR, \
+ "bad option '%s': '%s'\n", opt, param); \
+ else \
+ av_log(avctx, AV_LOG_ERROR, \
+ "bad value for '%s': '%s'\n", opt, param); \
+ return -1; \
+ } \
+ } while (0)
+
static int convert_pix_fmt(enum AVPixelFormat pix_fmt)
{
switch (pix_fmt) {
@@ -219,6 +260,13 @@ static int convert_pix_fmt(enum AVPixelFormat pix_fmt)
case AV_PIX_FMT_YUV444P:
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
};
return 0;
}
@@ -232,14 +280,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);
}
@@ -251,6 +311,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;
@@ -279,10 +341,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;
@@ -372,23 +447,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;
@@ -483,6 +599,13 @@ static const enum AVPixelFormat pix_fmts_10bit[] = {
AV_PIX_FMT_YUV444P10,
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)
{
@@ -501,6 +624,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 },
@@ -556,9 +683,17 @@ static const AVClass class = {
.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" },
@@ -566,6 +701,7 @@ static const AVCodecDefault x264_defaults[] = {
{ "qdiff", "-1" },
{ "qblur", "-1" },
{ "qcomp", "-1" },
+// { "rc_lookahead", "-1" },
{ "refs", "-1" },
{ "sc_threshold", "-1" },
{ "trellis", "-1" },
@@ -598,3 +734,18 @@ AVCodec ff_libx264_encoder = {
.defaults = x264_defaults,
.init_static_data = X264_init_static,
};
+
+AVCodec ff_libx264rgb_encoder = {
+ .name = "libx264rgb",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 RGB"),
+ .priv_class = &rgbclass,
+ .defaults = x264_defaults,
+ .pix_fmts = pix_fmts_8bit_rgb,
+};
diff --git a/libavcodec/libxavs.c b/libavcodec/libxavs.c
index 16026ac..442fc0ee 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" },
diff --git a/libavcodec/libxvid.c b/libavcodec/libxvid.c
index dd1e3e3..05a12db 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,6 +60,7 @@ struct xvid_context {
char *twopassbuffer; /**< Character buffer for two-pass */
char *old_twopassbuffer; /**< Old character buffer (two-pass) */
char *twopassfile; /**< second pass temp file name */
+ int twopassfd;
unsigned char *intra_matrix; /**< P-Frame Quant Matrix */
unsigned char *inter_matrix; /**< I-Frame Quant Matrix */
};
@@ -70,6 +73,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 +105,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),
@@ -354,7 +359,9 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) {
xvid_enc_create_t xvid_enc_create = { 0 };
xvid_enc_plugin_t plugins[7];
- /* Bring in VOP flags from avconv command-line */
+ x->twopassfd = -1;
+
+ /* Bring in VOP flags from ffmpeg command-line */
x->vop_flags = XVID_VOP_HALFPEL; /* Bare minimum quality */
if( xvid_flags & CODEC_FLAG_4MV )
x->vop_flags |= XVID_VOP_INTER4V; /* Level 3 */
@@ -408,7 +415,7 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) {
break;
}
- /* Bring in VOL flags from avconv command-line */
+ /* Bring in VOL flags from ffmpeg command-line */
x->vol_flags = 0;
if( xvid_flags & CODEC_FLAG_GMC ) {
x->vol_flags |= XVID_VOL_GMC;
@@ -472,7 +479,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 +490,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;
@@ -602,13 +608,16 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) {
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 +633,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,8 +669,8 @@ 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) {
+ 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_ERROR, "Invalid pixel aspect ratio %i/%i\n",
avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den);
return -1;
@@ -734,16 +740,24 @@ 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;
}
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 9084d33..5da435b 100644
--- a/libavcodec/libxvid_rc.c
+++ b/libavcodec/libxvid_rc.c
@@ -3,31 +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/file.h"
#include "avcodec.h"
#include "libxvid.h"
#include "mpegvideo.h"
@@ -35,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 = 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;
@@ -78,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;
@@ -95,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/ljpegenc.c b/libavcodec/ljpegenc.c
index c7291ad..76c3cb9 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++;
@@ -213,5 +227,10 @@ 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},
.long_name = NULL_IF_CONFIG_SMALL("Lossless JPEG"),
};
diff --git a/libavcodec/loco.c b/libavcodec/loco.c
index ec6fe2f..ffb9742 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,6 +132,9 @@ static int loco_decode_plane(LOCOContext *l, uint8_t *data, int width, int heigh
int val;
int i, j;
+ if(buf_size<=0)
+ return -1;
+
init_get_bits(&rc.gb, buf, buf_size*8);
rc.save = 0;
rc.run = 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 bada368..4149135 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,7 +180,7 @@ int ff_lpc_calc_coefs(LPCContext *s,
int i, j, pass;
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);
/* reinit LPC context if parameters have changed */
@@ -202,6 +203,9 @@ int ff_lpc_calc_coefs(LPCContext *s,
LLSModel m[2];
double var[MAX_LPC_ORDER+1], av_uninit(weight);
+ if(lpc_passes <= 0)
+ lpc_passes = 2;
+
for(pass=0; pass<lpc_passes; pass++){
avpriv_init_lls(&m[pass&1], max_order);
@@ -234,7 +238,8 @@ int ff_lpc_calc_coefs(LPCContext *s,
}
for(i=max_order-1; i>0; i--)
ref[i] = ref[i-1] - ref[i];
- }
+ } else
+ av_assert0(0);
opt_order = max_order;
if(omethod == ORDER_METHOD_EST) {
diff --git a/libavcodec/lpc.h b/libavcodec/lpc.h
index c41a1f8..8fa56ad 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
@@ -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..7e30765 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;
}
diff --git a/libavcodec/mace.c b/libavcodec/mace.c
index 559dcee..94bf2e7 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
*/
@@ -226,7 +226,7 @@ static void chomp6(ChannelData *chd, int16_t *output, uint8_t val, int tab_idx)
static av_cold int mace_decode_init(AVCodecContext * avctx)
{
- if (avctx->channels > 2)
+ if (avctx->channels > 2 || avctx->channels <= 0)
return -1;
avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
@@ -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 551017e..592f5a5 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..2232024 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
*/
diff --git a/libavcodec/mdct_fixed.c b/libavcodec/mdct_fixed.c
index 94527f9..794a3e0 100644
--- a/libavcodec/mdct_fixed.c
+++ b/libavcodec/mdct_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/mdct_float.c b/libavcodec/mdct_float.c
index e4f5549..ec4f486 100644
--- a/libavcodec/mdct_float.c
+++ b/libavcodec/mdct_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/mdec.c b/libavcodec/mdec.c
index 3a1a707..8fb29ce 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
*/
@@ -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;
diff --git a/libavcodec/microdvddec.c b/libavcodec/microdvddec.c
new file mode 100644
index 0000000..f3c640f
--- /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 84e3391..e2c9369 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..a2ea412
--- /dev/null
+++ b/libavcodec/mips/Makefile
@@ -0,0 +1,21 @@
+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
+OBJS-$(CONFIG_FFT) += mips/fft_init_table.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
--- /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
--- /dev/null
+++ b/libavcodec/mips/aacdec_mips.c
@@ -0,0 +1,831 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Authors: Darko Laus (darko@mips.com)
+ * Djordje Pesut (djordje@mips.com)
+ * Mirjana Vulin (mvulin@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/aacdec.c
+ */
+
+#include "libavcodec/aac.h"
+#include "aacdec_mips.h"
+#include "libavcodec/aactab.h"
+#include "libavcodec/sinewin.h"
+
+#if HAVE_INLINE_ASM
+static av_always_inline int lcg_random(unsigned previous_val)
+{
+ union { unsigned u; int s; } v = { previous_val * 1664525u + 1013904223 };
+ return v.s;
+}
+
+static void imdct_and_windowing_mips(AACContext *ac, SingleChannelElement *sce)
+{
+ IndividualChannelStream *ics = &sce->ics;
+ float *in = sce->coeffs;
+ float *out = sce->ret;
+ float *saved = sce->saved;
+ const float *swindow = ics->use_kb_window[0] ? ff_aac_kbd_short_128 : ff_sine_128;
+ const float *lwindow_prev = ics->use_kb_window[1] ? ff_aac_kbd_long_1024 : ff_sine_1024;
+ const float *swindow_prev = ics->use_kb_window[1] ? ff_aac_kbd_short_128 : ff_sine_128;
+ float *buf = ac->buf_mdct;
+ int i;
+
+ if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
+ for (i = 0; i < 1024; i += 128)
+ ac->mdct_small.imdct_half(&ac->mdct_small, buf + i, in + i);
+ } else
+ ac->mdct.imdct_half(&ac->mdct, buf, in);
+
+ /* window overlapping
+ * NOTE: To simplify the overlapping code, all 'meaningless' short to long
+ * and long to short transitions are considered to be short to short
+ * transitions. This leaves just two cases (long to long and short to short)
+ * with a little special sauce for EIGHT_SHORT_SEQUENCE.
+ */
+ if ((ics->window_sequence[1] == ONLY_LONG_SEQUENCE || ics->window_sequence[1] == LONG_STOP_SEQUENCE) &&
+ (ics->window_sequence[0] == ONLY_LONG_SEQUENCE || ics->window_sequence[0] == LONG_START_SEQUENCE)) {
+ ac->fdsp.vector_fmul_window( out, saved, buf, lwindow_prev, 512);
+ } else {
+ {
+ float *buf1 = saved;
+ float *buf2 = out;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ int loop_end;
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 1792 \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "lw %[temp4], 16(%[src]) \n\t"
+ "lw %[temp5], 20(%[src]) \n\t"
+ "lw %[temp6], 24(%[src]) \n\t"
+ "lw %[temp7], 28(%[src]) \n\t"
+ "addiu %[src], %[src], 32 \n\t"
+ "sw %[temp0], 0(%[dst]) \n\t"
+ "sw %[temp1], 4(%[dst]) \n\t"
+ "sw %[temp2], 8(%[dst]) \n\t"
+ "sw %[temp3], 12(%[dst]) \n\t"
+ "sw %[temp4], 16(%[dst]) \n\t"
+ "sw %[temp5], 20(%[dst]) \n\t"
+ "sw %[temp6], 24(%[dst]) \n\t"
+ "sw %[temp7], 28(%[dst]) \n\t"
+ "bne %[src], %[loop_end], 1b \n\t"
+ " addiu %[dst], %[dst], 32 \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf1),
+ [dst]"+r"(buf2)
+ :
+ : "memory"
+ );
+ }
+
+ if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
+ {
+ float wi;
+ float wj;
+ int i;
+ float temp0, temp1, temp2, temp3;
+ float *dst0 = out + 448 + 0*128;
+ float *dst1 = dst0 + 64 + 63;
+ float *dst2 = saved + 63;
+ float *win0 = (float*)swindow;
+ float *win1 = win0 + 64 + 63;
+ float *win0_prev = (float*)swindow_prev;
+ float *win1_prev = win0_prev + 64 + 63;
+ float *src0_prev = saved + 448;
+ float *src1_prev = buf + 0*128 + 63;
+ float *src0 = buf + 0*128 + 64;
+ float *src1 = buf + 1*128 + 63;
+
+ for(i = 0; i < 64; i++)
+ {
+ temp0 = src0_prev[0];
+ temp1 = src1_prev[0];
+ wi = *win0_prev;
+ wj = *win1_prev;
+ temp2 = src0[0];
+ temp3 = src1[0];
+ dst0[0] = temp0 * wj - temp1 * wi;
+ dst1[0] = temp0 * wi + temp1 * wj;
+
+ wi = *win0;
+ wj = *win1;
+
+ temp0 = src0[128];
+ temp1 = src1[128];
+ dst0[128] = temp2 * wj - temp3 * wi;
+ dst1[128] = temp2 * wi + temp3 * wj;
+
+ temp2 = src0[256];
+ temp3 = src1[256];
+ dst0[256] = temp0 * wj - temp1 * wi;
+ dst1[256] = temp0 * wi + temp1 * wj;
+ dst0[384] = temp2 * wj - temp3 * wi;
+ dst1[384] = temp2 * wi + temp3 * wj;
+
+ temp0 = src0[384];
+ temp1 = src1[384];
+ dst0[512] = temp0 * wj - temp1 * wi;
+ dst2[0] = temp0 * wi + temp1 * wj;
+
+ src0++;
+ src1--;
+ src0_prev++;
+ src1_prev--;
+ win0++;
+ win1--;
+ win0_prev++;
+ win1_prev--;
+ dst0++;
+ dst1--;
+ dst2--;
+ }
+ }
+ } else {
+ ac->fdsp.vector_fmul_window(out + 448, saved + 448, buf, swindow_prev, 64);
+ {
+ float *buf1 = buf + 64;
+ float *buf2 = out + 576;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ int loop_end;
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 1792 \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "lw %[temp4], 16(%[src]) \n\t"
+ "lw %[temp5], 20(%[src]) \n\t"
+ "lw %[temp6], 24(%[src]) \n\t"
+ "lw %[temp7], 28(%[src]) \n\t"
+ "addiu %[src], %[src], 32 \n\t"
+ "sw %[temp0], 0(%[dst]) \n\t"
+ "sw %[temp1], 4(%[dst]) \n\t"
+ "sw %[temp2], 8(%[dst]) \n\t"
+ "sw %[temp3], 12(%[dst]) \n\t"
+ "sw %[temp4], 16(%[dst]) \n\t"
+ "sw %[temp5], 20(%[dst]) \n\t"
+ "sw %[temp6], 24(%[dst]) \n\t"
+ "sw %[temp7], 28(%[dst]) \n\t"
+ "bne %[src], %[loop_end], 1b \n\t"
+ " addiu %[dst], %[dst], 32 \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf1),
+ [dst]"+r"(buf2)
+ :
+ : "memory"
+ );
+ }
+ }
+ }
+
+ // buffer update
+ if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
+ ac->fdsp.vector_fmul_window(saved + 64, buf + 4*128 + 64, buf + 5*128, swindow, 64);
+ ac->fdsp.vector_fmul_window(saved + 192, buf + 5*128 + 64, buf + 6*128, swindow, 64);
+ ac->fdsp.vector_fmul_window(saved + 320, buf + 6*128 + 64, buf + 7*128, swindow, 64);
+ {
+ float *buf1 = buf + 7*128 + 64;
+ float *buf2 = saved + 448;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ int loop_end;
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 256 \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "lw %[temp4], 16(%[src]) \n\t"
+ "lw %[temp5], 20(%[src]) \n\t"
+ "lw %[temp6], 24(%[src]) \n\t"
+ "lw %[temp7], 28(%[src]) \n\t"
+ "addiu %[src], %[src], 32 \n\t"
+ "sw %[temp0], 0(%[dst]) \n\t"
+ "sw %[temp1], 4(%[dst]) \n\t"
+ "sw %[temp2], 8(%[dst]) \n\t"
+ "sw %[temp3], 12(%[dst]) \n\t"
+ "sw %[temp4], 16(%[dst]) \n\t"
+ "sw %[temp5], 20(%[dst]) \n\t"
+ "sw %[temp6], 24(%[dst]) \n\t"
+ "sw %[temp7], 28(%[dst]) \n\t"
+ "bne %[src], %[loop_end], 1b \n\t"
+ " addiu %[dst], %[dst], 32 \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf1),
+ [dst]"+r"(buf2)
+ :
+ : "memory"
+ );
+ }
+ } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) {
+ float *buf1 = buf + 512;
+ float *buf2 = saved;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ int loop_end;
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 1792 \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "lw %[temp4], 16(%[src]) \n\t"
+ "lw %[temp5], 20(%[src]) \n\t"
+ "lw %[temp6], 24(%[src]) \n\t"
+ "lw %[temp7], 28(%[src]) \n\t"
+ "addiu %[src], %[src], 32 \n\t"
+ "sw %[temp0], 0(%[dst]) \n\t"
+ "sw %[temp1], 4(%[dst]) \n\t"
+ "sw %[temp2], 8(%[dst]) \n\t"
+ "sw %[temp3], 12(%[dst]) \n\t"
+ "sw %[temp4], 16(%[dst]) \n\t"
+ "sw %[temp5], 20(%[dst]) \n\t"
+ "sw %[temp6], 24(%[dst]) \n\t"
+ "sw %[temp7], 28(%[dst]) \n\t"
+ "bne %[src], %[loop_end], 1b \n\t"
+ " addiu %[dst], %[dst], 32 \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf1),
+ [dst]"+r"(buf2)
+ :
+ : "memory"
+ );
+ {
+ float *buf1 = buf + 7*128 + 64;
+ float *buf2 = saved + 448;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ int loop_end;
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 256 \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "lw %[temp4], 16(%[src]) \n\t"
+ "lw %[temp5], 20(%[src]) \n\t"
+ "lw %[temp6], 24(%[src]) \n\t"
+ "lw %[temp7], 28(%[src]) \n\t"
+ "addiu %[src], %[src], 32 \n\t"
+ "sw %[temp0], 0(%[dst]) \n\t"
+ "sw %[temp1], 4(%[dst]) \n\t"
+ "sw %[temp2], 8(%[dst]) \n\t"
+ "sw %[temp3], 12(%[dst]) \n\t"
+ "sw %[temp4], 16(%[dst]) \n\t"
+ "sw %[temp5], 20(%[dst]) \n\t"
+ "sw %[temp6], 24(%[dst]) \n\t"
+ "sw %[temp7], 28(%[dst]) \n\t"
+ "bne %[src], %[loop_end], 1b \n\t"
+ " addiu %[dst], %[dst], 32 \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf1),
+ [dst]"+r"(buf2)
+ :
+ : "memory"
+ );
+ }
+ } else { // LONG_STOP or ONLY_LONG
+ float *buf1 = buf + 512;
+ float *buf2 = saved;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ int loop_end;
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 2048 \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "lw %[temp4], 16(%[src]) \n\t"
+ "lw %[temp5], 20(%[src]) \n\t"
+ "lw %[temp6], 24(%[src]) \n\t"
+ "lw %[temp7], 28(%[src]) \n\t"
+ "addiu %[src], %[src], 32 \n\t"
+ "sw %[temp0], 0(%[dst]) \n\t"
+ "sw %[temp1], 4(%[dst]) \n\t"
+ "sw %[temp2], 8(%[dst]) \n\t"
+ "sw %[temp3], 12(%[dst]) \n\t"
+ "sw %[temp4], 16(%[dst]) \n\t"
+ "sw %[temp5], 20(%[dst]) \n\t"
+ "sw %[temp6], 24(%[dst]) \n\t"
+ "sw %[temp7], 28(%[dst]) \n\t"
+ "bne %[src], %[loop_end], 1b \n\t"
+ " addiu %[dst], %[dst], 32 \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf1),
+ [dst]"+r"(buf2)
+ :
+ : "memory"
+ );
+ }
+}
+
+static void apply_ltp_mips(AACContext *ac, SingleChannelElement *sce)
+{
+ const LongTermPrediction *ltp = &sce->ics.ltp;
+ const uint16_t *offsets = sce->ics.swb_offset;
+ int i, sfb;
+ int j, k;
+
+ if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) {
+ float *predTime = sce->ret;
+ float *predFreq = ac->buf_mdct;
+ float *p_predTime;
+ int16_t num_samples = 2048;
+
+ if (ltp->lag < 1024)
+ num_samples = ltp->lag + 1024;
+ j = (2048 - num_samples) >> 2;
+ k = (2048 - num_samples) & 3;
+ p_predTime = &predTime[num_samples];
+
+ for (i = 0; i < num_samples; i++)
+ predTime[i] = sce->ltp_state[i + 2048 - ltp->lag] * ltp->coef;
+ for (i = 0; i < j; i++) {
+
+ /* loop unrolled 4 times */
+ __asm__ volatile (
+ "sw $0, 0(%[p_predTime]) \n\t"
+ "sw $0, 4(%[p_predTime]) \n\t"
+ "sw $0, 8(%[p_predTime]) \n\t"
+ "sw $0, 12(%[p_predTime]) \n\t"
+ "addiu %[p_predTime], %[p_predTime], 16 \n\t"
+
+ : [p_predTime]"+r"(p_predTime)
+ :
+ : "memory"
+ );
+ }
+ for (i = 0; i < k; i++) {
+
+ __asm__ volatile (
+ "sw $0, 0(%[p_predTime]) \n\t"
+ "addiu %[p_predTime], %[p_predTime], 4 \n\t"
+
+ : [p_predTime]"+r"(p_predTime)
+ :
+ : "memory"
+ );
+ }
+
+ ac->windowing_and_mdct_ltp(ac, predFreq, predTime, &sce->ics);
+
+ if (sce->tns.present)
+ ac->apply_tns(predFreq, &sce->tns, &sce->ics, 0);
+
+ for (sfb = 0; sfb < FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB); sfb++)
+ if (ltp->used[sfb])
+ for (i = offsets[sfb]; i < offsets[sfb + 1]; i++)
+ sce->coeffs[i] += predFreq[i];
+ }
+}
+
+#if HAVE_MIPSFPU
+static void update_ltp_mips(AACContext *ac, SingleChannelElement *sce)
+{
+ IndividualChannelStream *ics = &sce->ics;
+ float *saved = sce->saved;
+ float *saved_ltp = sce->coeffs;
+ const float *lwindow = ics->use_kb_window[0] ? ff_aac_kbd_long_1024 : ff_sine_1024;
+ const float *swindow = ics->use_kb_window[0] ? ff_aac_kbd_short_128 : ff_sine_128;
+ int i;
+ int loop_end, loop_end1, loop_end2;
+ float temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp10, temp11;
+
+ if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
+ float *buf = saved;
+ float *buf0 = saved_ltp;
+ float *p_saved_ltp = saved_ltp + 576;
+ float *ptr1 = &saved_ltp[512];
+ float *ptr2 = &ac->buf_mdct[1023];
+ float *ptr3 = (float*)&swindow[63];
+ loop_end1 = (int)(p_saved_ltp + 448);
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 2048 \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "lw %[temp4], 16(%[src]) \n\t"
+ "lw %[temp5], 20(%[src]) \n\t"
+ "lw %[temp6], 24(%[src]) \n\t"
+ "lw %[temp7], 28(%[src]) \n\t"
+ "addiu %[src], %[src], 32 \n\t"
+ "sw %[temp0], 0(%[dst]) \n\t"
+ "sw %[temp1], 4(%[dst]) \n\t"
+ "sw %[temp2], 8(%[dst]) \n\t"
+ "sw %[temp3], 12(%[dst]) \n\t"
+ "sw %[temp4], 16(%[dst]) \n\t"
+ "sw %[temp5], 20(%[dst]) \n\t"
+ "sw %[temp6], 24(%[dst]) \n\t"
+ "sw %[temp7], 28(%[dst]) \n\t"
+ "bne %[src], %[loop_end], 1b \n\t"
+ " addiu %[dst], %[dst], 32 \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
+ [loop_end]"=&r"(loop_end), [src]"+r"(buf),
+ [dst]"+r"(buf0)
+ :
+ : "memory"
+ );
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ "1: \n\t"
+ "sw $0, 0(%[p_saved_ltp]) \n\t"
+ "sw $0, 4(%[p_saved_ltp]) \n\t"
+ "sw $0, 8(%[p_saved_ltp]) \n\t"
+ "sw $0, 12(%[p_saved_ltp]) \n\t"
+ "sw $0, 16(%[p_saved_ltp]) \n\t"
+ "sw $0, 20(%[p_saved_ltp]) \n\t"
+ "sw $0, 24(%[p_saved_ltp]) \n\t"
+ "sw $0, 28(%[p_saved_ltp]) \n\t"
+ "addiu %[p_saved_ltp], %[p_saved_ltp], 32 \n\t"
+ "bne %[p_saved_ltp], %[loop_end1], 1b \n\t"
+
+ : [p_saved_ltp]"+r"(p_saved_ltp)
+ : [loop_end1]"r"(loop_end1)
+ : "memory"
+ );
+
+ ac->fdsp.vector_fmul_reverse(saved_ltp + 448, ac->buf_mdct + 960, &swindow[64], 64);
+ for (i = 0; i < 16; i++){
+ /* loop unrolled 4 times */
+ __asm__ volatile (
+ "lwc1 %[temp0], 0(%[ptr2]) \n\t"
+ "lwc1 %[temp1], -4(%[ptr2]) \n\t"
+ "lwc1 %[temp2], -8(%[ptr2]) \n\t"
+ "lwc1 %[temp3], -12(%[ptr2]) \n\t"
+ "lwc1 %[temp4], 0(%[ptr3]) \n\t"
+ "lwc1 %[temp5], -4(%[ptr3]) \n\t"
+ "lwc1 %[temp6], -8(%[ptr3]) \n\t"
+ "lwc1 %[temp7], -12(%[ptr3]) \n\t"
+ "mul.s %[temp8], %[temp0], %[temp4] \n\t"
+ "mul.s %[temp9], %[temp1], %[temp5] \n\t"
+ "mul.s %[temp10], %[temp2], %[temp6] \n\t"
+ "mul.s %[temp11], %[temp3], %[temp7] \n\t"
+ "swc1 %[temp8], 0(%[ptr1]) \n\t"
+ "swc1 %[temp9], 4(%[ptr1]) \n\t"
+ "swc1 %[temp10], 8(%[ptr1]) \n\t"
+ "swc1 %[temp11], 12(%[ptr1]) \n\t"
+ "addiu %[ptr1], %[ptr1], 16 \n\t"
+ "addiu %[ptr2], %[ptr2], -16 \n\t"
+ "addiu %[ptr3], %[ptr3], -16 \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1),
+ [temp2]"=&f"(temp2), [temp3]"=&f"(temp3),
+ [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7),
+ [temp8]"=&f"(temp8), [temp9]"=&f"(temp9),
+ [temp10]"=&f"(temp10), [temp11]"=&f"(temp11),
+ [ptr1]"+r"(ptr1), [ptr2]"+r"(ptr2), [ptr3]"+r"(ptr3)
+ :
+ : "memory"
+ );
+ }
+ } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) {
+ float *buff0 = saved;
+ float *buff1 = saved_ltp;
+ float *ptr1 = &saved_ltp[512];
+ float *ptr2 = &ac->buf_mdct[1023];
+ float *ptr3 = (float*)&swindow[63];
+ loop_end = (int)(saved + 448);
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "lw %[temp4], 16(%[src]) \n\t"
+ "lw %[temp5], 20(%[src]) \n\t"
+ "lw %[temp6], 24(%[src]) \n\t"
+ "lw %[temp7], 28(%[src]) \n\t"
+ "addiu %[src], %[src], 32 \n\t"
+ "sw %[temp0], 0(%[dst]) \n\t"
+ "sw %[temp1], 4(%[dst]) \n\t"
+ "sw %[temp2], 8(%[dst]) \n\t"
+ "sw %[temp3], 12(%[dst]) \n\t"
+ "sw %[temp4], 16(%[dst]) \n\t"
+ "sw %[temp5], 20(%[dst]) \n\t"
+ "sw %[temp6], 24(%[dst]) \n\t"
+ "sw %[temp7], 28(%[dst]) \n\t"
+ "sw $0, 2304(%[dst]) \n\t"
+ "sw $0, 2308(%[dst]) \n\t"
+ "sw $0, 2312(%[dst]) \n\t"
+ "sw $0, 2316(%[dst]) \n\t"
+ "sw $0, 2320(%[dst]) \n\t"
+ "sw $0, 2324(%[dst]) \n\t"
+ "sw $0, 2328(%[dst]) \n\t"
+ "sw $0, 2332(%[dst]) \n\t"
+ "bne %[src], %[loop_end], 1b \n\t"
+ " addiu %[dst], %[dst], 32 \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
+ [src]"+r"(buff0), [dst]"+r"(buff1)
+ : [loop_end]"r"(loop_end)
+ : "memory"
+ );
+ ac->fdsp.vector_fmul_reverse(saved_ltp + 448, ac->buf_mdct + 960, &swindow[64], 64);
+ for (i = 0; i < 16; i++){
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ "lwc1 %[temp0], 0(%[ptr2]) \n\t"
+ "lwc1 %[temp1], -4(%[ptr2]) \n\t"
+ "lwc1 %[temp2], -8(%[ptr2]) \n\t"
+ "lwc1 %[temp3], -12(%[ptr2]) \n\t"
+ "lwc1 %[temp4], 0(%[ptr3]) \n\t"
+ "lwc1 %[temp5], -4(%[ptr3]) \n\t"
+ "lwc1 %[temp6], -8(%[ptr3]) \n\t"
+ "lwc1 %[temp7], -12(%[ptr3]) \n\t"
+ "mul.s %[temp8], %[temp0], %[temp4] \n\t"
+ "mul.s %[temp9], %[temp1], %[temp5] \n\t"
+ "mul.s %[temp10], %[temp2], %[temp6] \n\t"
+ "mul.s %[temp11], %[temp3], %[temp7] \n\t"
+ "swc1 %[temp8], 0(%[ptr1]) \n\t"
+ "swc1 %[temp9], 4(%[ptr1]) \n\t"
+ "swc1 %[temp10], 8(%[ptr1]) \n\t"
+ "swc1 %[temp11], 12(%[ptr1]) \n\t"
+ "addiu %[ptr1], %[ptr1], 16 \n\t"
+ "addiu %[ptr2], %[ptr2], -16 \n\t"
+ "addiu %[ptr3], %[ptr3], -16 \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1),
+ [temp2]"=&f"(temp2), [temp3]"=&f"(temp3),
+ [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7),
+ [temp8]"=&f"(temp8), [temp9]"=&f"(temp9),
+ [temp10]"=&f"(temp10), [temp11]"=&f"(temp11),
+ [ptr1]"+r"(ptr1), [ptr2]"+r"(ptr2), [ptr3]"+r"(ptr3)
+ :
+ : "memory"
+ );
+ }
+ } else { // LONG_STOP or ONLY_LONG
+ float *ptr1, *ptr2, *ptr3;
+ ac->fdsp.vector_fmul_reverse(saved_ltp, ac->buf_mdct + 512, &lwindow[512], 512);
+
+ ptr1 = &saved_ltp[512];
+ ptr2 = &ac->buf_mdct[1023];
+ ptr3 = (float*)&lwindow[511];
+
+ for (i = 0; i < 512; i+=4){
+ /* loop unrolled 4 times */
+ __asm__ volatile (
+ "lwc1 %[temp0], 0(%[ptr2]) \n\t"
+ "lwc1 %[temp1], -4(%[ptr2]) \n\t"
+ "lwc1 %[temp2], -8(%[ptr2]) \n\t"
+ "lwc1 %[temp3], -12(%[ptr2]) \n\t"
+ "lwc1 %[temp4], 0(%[ptr3]) \n\t"
+ "lwc1 %[temp5], -4(%[ptr3]) \n\t"
+ "lwc1 %[temp6], -8(%[ptr3]) \n\t"
+ "lwc1 %[temp7], -12(%[ptr3]) \n\t"
+ "mul.s %[temp8], %[temp0], %[temp4] \n\t"
+ "mul.s %[temp9], %[temp1], %[temp5] \n\t"
+ "mul.s %[temp10], %[temp2], %[temp6] \n\t"
+ "mul.s %[temp11], %[temp3], %[temp7] \n\t"
+ "swc1 %[temp8], 0(%[ptr1]) \n\t"
+ "swc1 %[temp9], 4(%[ptr1]) \n\t"
+ "swc1 %[temp10], 8(%[ptr1]) \n\t"
+ "swc1 %[temp11], 12(%[ptr1]) \n\t"
+ "addiu %[ptr1], %[ptr1], 16 \n\t"
+ "addiu %[ptr2], %[ptr2], -16 \n\t"
+ "addiu %[ptr3], %[ptr3], -16 \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1),
+ [temp2]"=&f"(temp2), [temp3]"=&f"(temp3),
+ [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7),
+ [temp8]"=&f"(temp8), [temp9]"=&f"(temp9),
+ [temp10]"=&f"(temp10), [temp11]"=&f"(temp11),
+ [ptr1]"+r"(ptr1), [ptr2]"+r"(ptr2),
+ [ptr3]"+r"(ptr3)
+ :
+ : "memory"
+ );
+ }
+ }
+
+ {
+ float *buf1 = sce->ltp_state+1024;
+ float *buf2 = sce->ltp_state;
+ float *buf3 = sce->ret;
+ float *buf4 = sce->ltp_state+1024;
+ float *buf5 = saved_ltp;
+ float *buf6 = sce->ltp_state+2048;
+
+ /* loops unrolled 8 times */
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[loop_end], %[src], 4096 \n\t"
+ "addiu %[loop_end1], %[src1], 4096 \n\t"
+ "addiu %[loop_end2], %[src2], 4096 \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "lw %[temp4], 16(%[src]) \n\t"
+ "lw %[temp5], 20(%[src]) \n\t"
+ "lw %[temp6], 24(%[src]) \n\t"
+ "lw %[temp7], 28(%[src]) \n\t"
+ "addiu %[src], %[src], 32 \n\t"
+ "sw %[temp0], 0(%[dst]) \n\t"
+ "sw %[temp1], 4(%[dst]) \n\t"
+ "sw %[temp2], 8(%[dst]) \n\t"
+ "sw %[temp3], 12(%[dst]) \n\t"
+ "sw %[temp4], 16(%[dst]) \n\t"
+ "sw %[temp5], 20(%[dst]) \n\t"
+ "sw %[temp6], 24(%[dst]) \n\t"
+ "sw %[temp7], 28(%[dst]) \n\t"
+ "bne %[src], %[loop_end], 1b \n\t"
+ " addiu %[dst], %[dst], 32 \n\t"
+ "2: \n\t"
+ "lw %[temp0], 0(%[src1]) \n\t"
+ "lw %[temp1], 4(%[src1]) \n\t"
+ "lw %[temp2], 8(%[src1]) \n\t"
+ "lw %[temp3], 12(%[src1]) \n\t"
+ "lw %[temp4], 16(%[src1]) \n\t"
+ "lw %[temp5], 20(%[src1]) \n\t"
+ "lw %[temp6], 24(%[src1]) \n\t"
+ "lw %[temp7], 28(%[src1]) \n\t"
+ "addiu %[src1], %[src1], 32 \n\t"
+ "sw %[temp0], 0(%[dst1]) \n\t"
+ "sw %[temp1], 4(%[dst1]) \n\t"
+ "sw %[temp2], 8(%[dst1]) \n\t"
+ "sw %[temp3], 12(%[dst1]) \n\t"
+ "sw %[temp4], 16(%[dst1]) \n\t"
+ "sw %[temp5], 20(%[dst1]) \n\t"
+ "sw %[temp6], 24(%[dst1]) \n\t"
+ "sw %[temp7], 28(%[dst1]) \n\t"
+ "bne %[src1], %[loop_end1], 2b \n\t"
+ " addiu %[dst1], %[dst1], 32 \n\t"
+ "3: \n\t"
+ "lw %[temp0], 0(%[src2]) \n\t"
+ "lw %[temp1], 4(%[src2]) \n\t"
+ "lw %[temp2], 8(%[src2]) \n\t"
+ "lw %[temp3], 12(%[src2]) \n\t"
+ "lw %[temp4], 16(%[src2]) \n\t"
+ "lw %[temp5], 20(%[src2]) \n\t"
+ "lw %[temp6], 24(%[src2]) \n\t"
+ "lw %[temp7], 28(%[src2]) \n\t"
+ "addiu %[src2], %[src2], 32 \n\t"
+ "sw %[temp0], 0(%[dst2]) \n\t"
+ "sw %[temp1], 4(%[dst2]) \n\t"
+ "sw %[temp2], 8(%[dst2]) \n\t"
+ "sw %[temp3], 12(%[dst2]) \n\t"
+ "sw %[temp4], 16(%[dst2]) \n\t"
+ "sw %[temp5], 20(%[dst2]) \n\t"
+ "sw %[temp6], 24(%[dst2]) \n\t"
+ "sw %[temp7], 28(%[dst2]) \n\t"
+ "bne %[src2], %[loop_end2], 3b \n\t"
+ " addiu %[dst2], %[dst2], 32 \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
+ [loop_end]"=&r"(loop_end), [loop_end1]"=&r"(loop_end1),
+ [loop_end2]"=&r"(loop_end2), [src]"+r"(buf1),
+ [dst]"+r"(buf2), [src1]"+r"(buf3), [dst1]"+r"(buf4),
+ [src2]"+r"(buf5), [dst2]"+r"(buf6)
+ :
+ : "memory"
+ );
+ }
+}
+#endif /* HAVE_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+
+void ff_aacdec_init_mips(AACContext *c)
+{
+#if HAVE_INLINE_ASM
+ c->imdct_and_windowing = imdct_and_windowing_mips;
+ c->apply_ltp = apply_ltp_mips;
+#if HAVE_MIPSFPU
+ c->update_ltp = update_ltp_mips;
+#endif /* HAVE_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/mips/aacdec_mips.h b/libavcodec/mips/aacdec_mips.h
new file mode 100644
index 0000000..9ba3079
--- /dev/null
+++ b/libavcodec/mips/aacdec_mips.h
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Authors: Darko Laus (darko@mips.com)
+ * Djordje Pesut (djordje@mips.com)
+ * Mirjana Vulin (mvulin@mips.com)
+ *
+ * AAC Spectral Band Replication decoding functions optimized for MIPS
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/aacdec.c
+ */
+
+#ifndef AVCODEC_MIPS_AACDEC_FLOAT_H
+#define AVCODEC_MIPS_AACDEC_FLOAT_H
+
+#include "libavcodec/aac.h"
+
+#if HAVE_INLINE_ASM && HAVE_MIPSFPU
+static inline float *VMUL2_mips(float *dst, const float *v, unsigned idx,
+ const float *scale)
+{
+ float temp0, temp1, temp2;
+ int temp3, temp4;
+ float *ret;
+
+ __asm__ volatile(
+ "andi %[temp3], %[idx], 15 \n\t"
+ "ext %[temp4], %[idx], 4, 4 \n\t"
+ "sll %[temp3], %[temp3], 2 \n\t"
+ "sll %[temp4], %[temp4], 2 \n\t"
+ "lwc1 %[temp2], 0(%[scale]) \n\t"
+ "lwxc1 %[temp0], %[temp3](%[v]) \n\t"
+ "lwxc1 %[temp1], %[temp4](%[v]) \n\t"
+ "mul.s %[temp0], %[temp0], %[temp2] \n\t"
+ "mul.s %[temp1], %[temp1], %[temp2] \n\t"
+ "addiu %[ret], %[dst], 8 \n\t"
+ "swc1 %[temp0], 0(%[dst]) \n\t"
+ "swc1 %[temp1], 4(%[dst]) \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1),
+ [temp2]"=&f"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [ret]"=&r"(ret)
+ : [idx]"r"(idx), [scale]"r"(scale), [v]"r"(v),
+ [dst]"r"(dst)
+ : "memory"
+ );
+ return ret;
+}
+
+static inline float *VMUL4_mips(float *dst, const float *v, unsigned idx,
+ const float *scale)
+{
+ int temp0, temp1, temp2, temp3;
+ float temp4, temp5, temp6, temp7, temp8;
+ float *ret;
+
+ __asm__ volatile(
+ "andi %[temp0], %[idx], 3 \n\t"
+ "ext %[temp1], %[idx], 2, 2 \n\t"
+ "ext %[temp2], %[idx], 4, 2 \n\t"
+ "ext %[temp3], %[idx], 6, 2 \n\t"
+ "sll %[temp0], %[temp0], 2 \n\t"
+ "sll %[temp1], %[temp1], 2 \n\t"
+ "sll %[temp2], %[temp2], 2 \n\t"
+ "sll %[temp3], %[temp3], 2 \n\t"
+ "lwc1 %[temp4], 0(%[scale]) \n\t"
+ "lwxc1 %[temp5], %[temp0](%[v]) \n\t"
+ "lwxc1 %[temp6], %[temp1](%[v]) \n\t"
+ "lwxc1 %[temp7], %[temp2](%[v]) \n\t"
+ "lwxc1 %[temp8], %[temp3](%[v]) \n\t"
+ "mul.s %[temp5], %[temp5], %[temp4] \n\t"
+ "mul.s %[temp6], %[temp6], %[temp4] \n\t"
+ "mul.s %[temp7], %[temp7], %[temp4] \n\t"
+ "mul.s %[temp8], %[temp8], %[temp4] \n\t"
+ "addiu %[ret], %[dst], 16 \n\t"
+ "swc1 %[temp5], 0(%[dst]) \n\t"
+ "swc1 %[temp6], 4(%[dst]) \n\t"
+ "swc1 %[temp7], 8(%[dst]) \n\t"
+ "swc1 %[temp8], 12(%[dst]) \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7),
+ [temp8]"=&f"(temp8), [ret]"=&r"(ret)
+ : [idx]"r"(idx), [scale]"r"(scale), [v]"r"(v),
+ [dst]"r"(dst)
+ : "memory"
+ );
+ return ret;
+}
+
+static inline float *VMUL2S_mips(float *dst, const float *v, unsigned idx,
+ unsigned sign, const float *scale)
+{
+ int temp0, temp1, temp2, temp3, temp4, temp5;
+ float temp6, temp7, temp8, temp9;
+ float *ret;
+
+ __asm__ volatile(
+ "andi %[temp0], %[idx], 15 \n\t"
+ "ext %[temp1], %[idx], 4, 4 \n\t"
+ "lw %[temp4], 0(%[scale]) \n\t"
+ "srl %[temp2], %[sign], 1 \n\t"
+ "sll %[temp3], %[sign], 31 \n\t"
+ "sll %[temp2], %[temp2], 31 \n\t"
+ "sll %[temp0], %[temp0], 2 \n\t"
+ "sll %[temp1], %[temp1], 2 \n\t"
+ "lwxc1 %[temp8], %[temp0](%[v]) \n\t"
+ "lwxc1 %[temp9], %[temp1](%[v]) \n\t"
+ "xor %[temp5], %[temp4], %[temp2] \n\t"
+ "xor %[temp4], %[temp4], %[temp3] \n\t"
+ "mtc1 %[temp5], %[temp6] \n\t"
+ "mtc1 %[temp4], %[temp7] \n\t"
+ "mul.s %[temp8], %[temp8], %[temp6] \n\t"
+ "mul.s %[temp9], %[temp9], %[temp7] \n\t"
+ "addiu %[ret], %[dst], 8 \n\t"
+ "swc1 %[temp8], 0(%[dst]) \n\t"
+ "swc1 %[temp9], 4(%[dst]) \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7),
+ [temp8]"=&f"(temp8), [temp9]"=&f"(temp9),
+ [ret]"=&r"(ret)
+ : [idx]"r"(idx), [scale]"r"(scale), [v]"r"(v),
+ [dst]"r"(dst), [sign]"r"(sign)
+ : "memory"
+ );
+ return ret;
+}
+
+static inline float *VMUL4S_mips(float *dst, const float *v, unsigned idx,
+ unsigned sign, const float *scale)
+{
+ int temp0, temp1, temp2, temp3, temp4;
+ float temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17;
+ float *ret;
+ unsigned int mask = 1U << 31;
+
+ __asm__ volatile(
+ "lw %[temp0], 0(%[scale]) \n\t"
+ "and %[temp1], %[idx], 3 \n\t"
+ "ext %[temp2], %[idx], 2, 2 \n\t"
+ "ext %[temp3], %[idx], 4, 2 \n\t"
+ "ext %[temp4], %[idx], 6, 2 \n\t"
+ "sll %[temp1], %[temp1], 2 \n\t"
+ "sll %[temp2], %[temp2], 2 \n\t"
+ "sll %[temp3], %[temp3], 2 \n\t"
+ "sll %[temp4], %[temp4], 2 \n\t"
+ "lwxc1 %[temp10], %[temp1](%[v]) \n\t"
+ "lwxc1 %[temp11], %[temp2](%[v]) \n\t"
+ "lwxc1 %[temp12], %[temp3](%[v]) \n\t"
+ "lwxc1 %[temp13], %[temp4](%[v]) \n\t"
+ "and %[temp1], %[sign], %[mask] \n\t"
+ "ext %[temp2], %[idx], 12, 1 \n\t"
+ "ext %[temp3], %[idx], 13, 1 \n\t"
+ "ext %[temp4], %[idx], 14, 1 \n\t"
+ "sllv %[sign], %[sign], %[temp2] \n\t"
+ "xor %[temp1], %[temp0], %[temp1] \n\t"
+ "and %[temp2], %[sign], %[mask] \n\t"
+ "mtc1 %[temp1], %[temp14] \n\t"
+ "xor %[temp2], %[temp0], %[temp2] \n\t"
+ "sllv %[sign], %[sign], %[temp3] \n\t"
+ "mtc1 %[temp2], %[temp15] \n\t"
+ "and %[temp3], %[sign], %[mask] \n\t"
+ "sllv %[sign], %[sign], %[temp4] \n\t"
+ "xor %[temp3], %[temp0], %[temp3] \n\t"
+ "and %[temp4], %[sign], %[mask] \n\t"
+ "mtc1 %[temp3], %[temp16] \n\t"
+ "xor %[temp4], %[temp0], %[temp4] \n\t"
+ "mtc1 %[temp4], %[temp17] \n\t"
+ "mul.s %[temp10], %[temp10], %[temp14] \n\t"
+ "mul.s %[temp11], %[temp11], %[temp15] \n\t"
+ "mul.s %[temp12], %[temp12], %[temp16] \n\t"
+ "mul.s %[temp13], %[temp13], %[temp17] \n\t"
+ "addiu %[ret], %[dst], 16 \n\t"
+ "swc1 %[temp10], 0(%[dst]) \n\t"
+ "swc1 %[temp11], 4(%[dst]) \n\t"
+ "swc1 %[temp12], 8(%[dst]) \n\t"
+ "swc1 %[temp13], 12(%[dst]) \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp10]"=&f"(temp10),
+ [temp11]"=&f"(temp11), [temp12]"=&f"(temp12),
+ [temp13]"=&f"(temp13), [temp14]"=&f"(temp14),
+ [temp15]"=&f"(temp15), [temp16]"=&f"(temp16),
+ [temp17]"=&f"(temp17), [ret]"=&r"(ret),
+ [sign]"+r"(sign)
+ : [idx]"r"(idx), [scale]"r"(scale), [v]"r"(v),
+ [dst]"r"(dst), [mask]"r"(mask)
+ : "memory"
+ );
+ return ret;
+}
+
+#define VMUL2 VMUL2_mips
+#define VMUL4 VMUL4_mips
+#define VMUL2S VMUL2S_mips
+#define VMUL4S VMUL4S_mips
+#endif /* HAVE_INLINE_ASM && HAVE_MIPSFPU */
+
+#endif /* AVCODEC_MIPS_AACDEC_FLOAT_H */
diff --git a/libavcodec/mips/aacpsdsp_mips.c b/libavcodec/mips/aacpsdsp_mips.c
new file mode 100644
index 0000000..4730a7f
--- /dev/null
+++ b/libavcodec/mips/aacpsdsp_mips.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Authors: Darko Laus (darko@mips.com)
+ * Djordje Pesut (djordje@mips.com)
+ * Mirjana Vulin (mvulin@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/aacpsdsp.c
+ */
+
+#include "config.h"
+#include "libavcodec/aacpsdsp.h"
+
+#if HAVE_INLINE_ASM
+static void ps_hybrid_analysis_ileave_mips(float (*out)[32][2], float L[2][38][64],
+ int i, int len)
+{
+ int temp0, temp1, temp2, temp3;
+ int temp4, temp5, temp6, temp7;
+ float *out1=&out[i][0][0];
+ float *L1=&L[0][0][i];
+ float *j=out1+ len*2;
+
+ for (; i < 64; i++) {
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ "1: \n\t"
+ "lw %[temp0], 0(%[L1]) \n\t"
+ "lw %[temp1], 9728(%[L1]) \n\t"
+ "lw %[temp2], 256(%[L1]) \n\t"
+ "lw %[temp3], 9984(%[L1]) \n\t"
+ "lw %[temp4], 512(%[L1]) \n\t"
+ "lw %[temp5], 10240(%[L1]) \n\t"
+ "lw %[temp6], 768(%[L1]) \n\t"
+ "lw %[temp7], 10496(%[L1]) \n\t"
+ "sw %[temp0], 0(%[out1]) \n\t"
+ "sw %[temp1], 4(%[out1]) \n\t"
+ "sw %[temp2], 8(%[out1]) \n\t"
+ "sw %[temp3], 12(%[out1]) \n\t"
+ "sw %[temp4], 16(%[out1]) \n\t"
+ "sw %[temp5], 20(%[out1]) \n\t"
+ "sw %[temp6], 24(%[out1]) \n\t"
+ "sw %[temp7], 28(%[out1]) \n\t"
+ "addiu %[out1], %[out1], 32 \n\t"
+ "addiu %[L1], %[L1], 1024 \n\t"
+ "bne %[out1], %[j], 1b \n\t"
+
+ : [out1]"+r"(out1), [L1]"+r"(L1), [j]"+r"(j),
+ [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7)
+ : [len]"r"(len)
+ : "memory"
+ );
+ out1-=(len<<1)-64;
+ L1-=(len<<6)-1;
+ j+=len*2;
+ }
+}
+
+static void ps_hybrid_synthesis_deint_mips(float out[2][38][64],
+ float (*in)[32][2],
+ int i, int len)
+{
+ int n;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ float *out1 = (float*)out + i;
+ float *out2 = (float*)out + 2432 + i;
+ float *in1 = (float*)in + 64 * i;
+ float *in2 = (float*)in + 64 * i + 1;
+
+ for (; i < 64; i++) {
+ for (n = 0; n < 7; n++) {
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ "lw %[temp0], 0(%[in1]) \n\t"
+ "lw %[temp1], 0(%[in2]) \n\t"
+ "lw %[temp2], 8(%[in1]) \n\t"
+ "lw %[temp3], 8(%[in2]) \n\t"
+ "lw %[temp4], 16(%[in1]) \n\t"
+ "lw %[temp5], 16(%[in2]) \n\t"
+ "lw %[temp6], 24(%[in1]) \n\t"
+ "lw %[temp7], 24(%[in2]) \n\t"
+ "addiu %[out1], %[out1], 1024 \n\t"
+ "addiu %[out2], %[out2], 1024 \n\t"
+ "addiu %[in1], %[in1], 32 \n\t"
+ "addiu %[in2], %[in2], 32 \n\t"
+ "sw %[temp0], -1024(%[out1]) \n\t"
+ "sw %[temp1], -1024(%[out2]) \n\t"
+ "sw %[temp2], -768(%[out1]) \n\t"
+ "sw %[temp3], -768(%[out2]) \n\t"
+ "sw %[temp4], -512(%[out1]) \n\t"
+ "sw %[temp5], -512(%[out2]) \n\t"
+ "sw %[temp6], -256(%[out1]) \n\t"
+ "sw %[temp7], -256(%[out2]) \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
+ [out1]"+r"(out1), [out2]"+r"(out2),
+ [in1]"+r"(in1), [in2]"+r"(in2)
+ :
+ : "memory"
+ );
+ }
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ "lw %[temp0], 0(%[in1]) \n\t"
+ "lw %[temp1], 0(%[in2]) \n\t"
+ "lw %[temp2], 8(%[in1]) \n\t"
+ "lw %[temp3], 8(%[in2]) \n\t"
+ "lw %[temp4], 16(%[in1]) \n\t"
+ "lw %[temp5], 16(%[in2]) \n\t"
+ "lw %[temp6], 24(%[in1]) \n\t"
+ "lw %[temp7], 24(%[in2]) \n\t"
+ "addiu %[out1], %[out1], -7164 \n\t"
+ "addiu %[out2], %[out2], -7164 \n\t"
+ "addiu %[in1], %[in1], 32 \n\t"
+ "addiu %[in2], %[in2], 32 \n\t"
+ "sw %[temp0], 7164(%[out1]) \n\t"
+ "sw %[temp1], 7164(%[out2]) \n\t"
+ "sw %[temp2], 7420(%[out1]) \n\t"
+ "sw %[temp3], 7420(%[out2]) \n\t"
+ "sw %[temp4], 7676(%[out1]) \n\t"
+ "sw %[temp5], 7676(%[out2]) \n\t"
+ "sw %[temp6], 7932(%[out1]) \n\t"
+ "sw %[temp7], 7932(%[out2]) \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
+ [out1]"+r"(out1), [out2]"+r"(out2),
+ [in1]"+r"(in1), [in2]"+r"(in2)
+ :
+ : "memory"
+ );
+ }
+}
+
+#if HAVE_MIPSFPU
+static void ps_add_squares_mips(float *dst, const float (*src)[2], int n)
+{
+ int i;
+ float temp0, temp1, temp2, temp3, temp4, temp5;
+ float temp6, temp7, temp8, temp9, temp10, temp11;
+ float *src0 = (float*)&src[0][0];
+ float *dst0 = &dst[0];
+
+ for (i = 0; i < 8; i++) {
+ /* loop unrolled 4 times */
+ __asm__ volatile (
+ "lwc1 %[temp0], 0(%[src0]) \n\t"
+ "lwc1 %[temp1], 4(%[src0]) \n\t"
+ "lwc1 %[temp2], 8(%[src0]) \n\t"
+ "lwc1 %[temp3], 12(%[src0]) \n\t"
+ "lwc1 %[temp4], 16(%[src0]) \n\t"
+ "lwc1 %[temp5], 20(%[src0]) \n\t"
+ "lwc1 %[temp6], 24(%[src0]) \n\t"
+ "lwc1 %[temp7], 28(%[src0]) \n\t"
+ "lwc1 %[temp8], 0(%[dst0]) \n\t"
+ "lwc1 %[temp9], 4(%[dst0]) \n\t"
+ "lwc1 %[temp10], 8(%[dst0]) \n\t"
+ "lwc1 %[temp11], 12(%[dst0]) \n\t"
+ "mul.s %[temp1], %[temp1], %[temp1] \n\t"
+ "mul.s %[temp3], %[temp3], %[temp3] \n\t"
+ "mul.s %[temp5], %[temp5], %[temp5] \n\t"
+ "mul.s %[temp7], %[temp7], %[temp7] \n\t"
+ "madd.s %[temp0], %[temp1], %[temp0], %[temp0] \n\t"
+ "madd.s %[temp2], %[temp3], %[temp2], %[temp2] \n\t"
+ "madd.s %[temp4], %[temp5], %[temp4], %[temp4] \n\t"
+ "madd.s %[temp6], %[temp7], %[temp6], %[temp6] \n\t"
+ "add.s %[temp0], %[temp8], %[temp0] \n\t"
+ "add.s %[temp2], %[temp9], %[temp2] \n\t"
+ "add.s %[temp4], %[temp10], %[temp4] \n\t"
+ "add.s %[temp6], %[temp11], %[temp6] \n\t"
+ "swc1 %[temp0], 0(%[dst0]) \n\t"
+ "swc1 %[temp2], 4(%[dst0]) \n\t"
+ "swc1 %[temp4], 8(%[dst0]) \n\t"
+ "swc1 %[temp6], 12(%[dst0]) \n\t"
+ "addiu %[dst0], %[dst0], 16 \n\t"
+ "addiu %[src0], %[src0], 32 \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp8]"=&f"(temp8),
+ [temp9]"=&f"(temp9), [dst0]"+r"(dst0), [src0]"+r"(src0),
+ [temp10]"=&f"(temp10), [temp11]"=&f"(temp11)
+ :
+ : "memory"
+ );
+ }
+}
+
+static void ps_mul_pair_single_mips(float (*dst)[2], float (*src0)[2], float *src1,
+ int n)
+{
+ float temp0, temp1, temp2;
+ float *p_d, *p_s0, *p_s1, *end;
+ p_d = &dst[0][0];
+ p_s0 = &src0[0][0];
+ p_s1 = &src1[0];
+ end = p_s1 + n;
+
+ __asm__ volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "1: \n\t"
+ "lwc1 %[temp2], 0(%[p_s1]) \n\t"
+ "lwc1 %[temp0], 0(%[p_s0]) \n\t"
+ "lwc1 %[temp1], 4(%[p_s0]) \n\t"
+ "addiu %[p_d], %[p_d], 8 \n\t"
+ "mul.s %[temp0], %[temp0], %[temp2] \n\t"
+ "mul.s %[temp1], %[temp1], %[temp2] \n\t"
+ "addiu %[p_s0], %[p_s0], 8 \n\t"
+ "swc1 %[temp0], -8(%[p_d]) \n\t"
+ "swc1 %[temp1], -4(%[p_d]) \n\t"
+ "bne %[p_s1], %[end], 1b \n\t"
+ " addiu %[p_s1], %[p_s1], 4 \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1),
+ [temp2]"=&f"(temp2), [p_d]"+r"(p_d),
+ [p_s0]"+r"(p_s0), [p_s1]"+r"(p_s1)
+ : [end]"r"(end)
+ : "memory"
+ );
+}
+
+static void ps_decorrelate_mips(float (*out)[2], float (*delay)[2],
+ float (*ap_delay)[PS_QMF_TIME_SLOTS + PS_MAX_AP_DELAY][2],
+ const float phi_fract[2], float (*Q_fract)[2],
+ const float *transient_gain,
+ float g_decay_slope,
+ int len)
+{
+ float *p_delay = &delay[0][0];
+ float *p_out = &out[0][0];
+ float *p_ap_delay = &ap_delay[0][0][0];
+ float *p_t_gain = (float*)transient_gain;
+ float *p_Q_fract = &Q_fract[0][0];
+ float ag0, ag1, ag2;
+ float phi_fract0 = phi_fract[0];
+ float phi_fract1 = phi_fract[1];
+ float temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9;
+
+ len = (int)((int*)p_delay + (len << 1));
+
+ /* merged 2 loops */
+ __asm__ volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "li.s %[ag0], 0.65143905753106 \n\t"
+ "li.s %[ag1], 0.56471812200776 \n\t"
+ "li.s %[ag2], 0.48954165955695 \n\t"
+ "mul.s %[ag0], %[ag0], %[g_decay_slope] \n\t"
+ "mul.s %[ag1], %[ag1], %[g_decay_slope] \n\t"
+ "mul.s %[ag2], %[ag2], %[g_decay_slope] \n\t"
+ "1: \n\t"
+ "lwc1 %[temp0], 0(%[p_delay]) \n\t"
+ "lwc1 %[temp1], 4(%[p_delay]) \n\t"
+ "lwc1 %[temp4], 16(%[p_ap_delay]) \n\t"
+ "lwc1 %[temp5], 20(%[p_ap_delay]) \n\t"
+ "mul.s %[temp3], %[temp0], %[phi_fract1] \n\t"
+ "lwc1 %[temp6], 0(%[p_Q_fract]) \n\t"
+ "mul.s %[temp2], %[temp1], %[phi_fract1] \n\t"
+ "lwc1 %[temp7], 4(%[p_Q_fract]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp1], %[phi_fract0] \n\t"
+ "msub.s %[temp2], %[temp2], %[temp0], %[phi_fract0] \n\t"
+ "mul.s %[temp8], %[temp5], %[temp7] \n\t"
+ "mul.s %[temp9], %[temp4], %[temp7] \n\t"
+ "lwc1 %[temp7], 12(%[p_Q_fract]) \n\t"
+ "mul.s %[temp0], %[ag0], %[temp2] \n\t"
+ "mul.s %[temp1], %[ag0], %[temp3] \n\t"
+ "msub.s %[temp8], %[temp8], %[temp4], %[temp6] \n\t"
+ "lwc1 %[temp4], 304(%[p_ap_delay]) \n\t"
+ "madd.s %[temp9], %[temp9], %[temp5], %[temp6] \n\t"
+ "lwc1 %[temp5], 308(%[p_ap_delay]) \n\t"
+ "sub.s %[temp0], %[temp8], %[temp0] \n\t"
+ "sub.s %[temp1], %[temp9], %[temp1] \n\t"
+ "madd.s %[temp2], %[temp2], %[ag0], %[temp0] \n\t"
+ "lwc1 %[temp6], 8(%[p_Q_fract]) \n\t"
+ "madd.s %[temp3], %[temp3], %[ag0], %[temp1] \n\t"
+ "mul.s %[temp8], %[temp5], %[temp7] \n\t"
+ "mul.s %[temp9], %[temp4], %[temp7] \n\t"
+ "lwc1 %[temp7], 20(%[p_Q_fract]) \n\t"
+ "msub.s %[temp8], %[temp8], %[temp4], %[temp6] \n\t"
+ "swc1 %[temp2], 40(%[p_ap_delay]) \n\t"
+ "mul.s %[temp2], %[ag1], %[temp0] \n\t"
+ "swc1 %[temp3], 44(%[p_ap_delay]) \n\t"
+ "mul.s %[temp3], %[ag1], %[temp1] \n\t"
+ "lwc1 %[temp4], 592(%[p_ap_delay]) \n\t"
+ "madd.s %[temp9], %[temp9], %[temp5], %[temp6] \n\t"
+ "lwc1 %[temp5], 596(%[p_ap_delay]) \n\t"
+ "sub.s %[temp2], %[temp8], %[temp2] \n\t"
+ "sub.s %[temp3], %[temp9], %[temp3] \n\t"
+ "lwc1 %[temp6], 16(%[p_Q_fract]) \n\t"
+ "madd.s %[temp0], %[temp0], %[ag1], %[temp2] \n\t"
+ "madd.s %[temp1], %[temp1], %[ag1], %[temp3] \n\t"
+ "mul.s %[temp8], %[temp5], %[temp7] \n\t"
+ "mul.s %[temp9], %[temp4], %[temp7] \n\t"
+ "msub.s %[temp8], %[temp8], %[temp4], %[temp6] \n\t"
+ "madd.s %[temp9], %[temp9], %[temp5], %[temp6] \n\t"
+ "swc1 %[temp0], 336(%[p_ap_delay]) \n\t"
+ "mul.s %[temp0], %[ag2], %[temp2] \n\t"
+ "swc1 %[temp1], 340(%[p_ap_delay]) \n\t"
+ "mul.s %[temp1], %[ag2], %[temp3] \n\t"
+ "lwc1 %[temp4], 0(%[p_t_gain]) \n\t"
+ "sub.s %[temp0], %[temp8], %[temp0] \n\t"
+ "addiu %[p_ap_delay], %[p_ap_delay], 8 \n\t"
+ "sub.s %[temp1], %[temp9], %[temp1] \n\t"
+ "addiu %[p_t_gain], %[p_t_gain], 4 \n\t"
+ "madd.s %[temp2], %[temp2], %[ag2], %[temp0] \n\t"
+ "addiu %[p_delay], %[p_delay], 8 \n\t"
+ "madd.s %[temp3], %[temp3], %[ag2], %[temp1] \n\t"
+ "addiu %[p_out], %[p_out], 8 \n\t"
+ "mul.s %[temp5], %[temp4], %[temp0] \n\t"
+ "mul.s %[temp6], %[temp4], %[temp1] \n\t"
+ "swc1 %[temp2], 624(%[p_ap_delay]) \n\t"
+ "swc1 %[temp3], 628(%[p_ap_delay]) \n\t"
+ "swc1 %[temp5], -8(%[p_out]) \n\t"
+ "swc1 %[temp6], -4(%[p_out]) \n\t"
+ "bne %[p_delay], %[len], 1b \n\t"
+ " swc1 %[temp6], -4(%[p_out]) \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp8]"=&f"(temp8),
+ [temp9]"=&f"(temp9), [p_delay]"+r"(p_delay), [p_ap_delay]"+r"(p_ap_delay),
+ [p_Q_fract]"+r"(p_Q_fract), [p_t_gain]"+r"(p_t_gain), [p_out]"+r"(p_out),
+ [ag0]"=&f"(ag0), [ag1]"=&f"(ag1), [ag2]"=&f"(ag2)
+ : [phi_fract0]"f"(phi_fract0), [phi_fract1]"f"(phi_fract1),
+ [len]"r"(len), [g_decay_slope]"f"(g_decay_slope)
+ : "memory"
+ );
+}
+
+static void ps_stereo_interpolate_mips(float (*l)[2], float (*r)[2],
+ float h[2][4], float h_step[2][4],
+ int len)
+{
+ float h0 = h[0][0];
+ float h1 = h[0][1];
+ float h2 = h[0][2];
+ float h3 = h[0][3];
+ float hs0 = h_step[0][0];
+ float hs1 = h_step[0][1];
+ float hs2 = h_step[0][2];
+ float hs3 = h_step[0][3];
+ float temp0, temp1, temp2, temp3;
+ float l_re, l_im, r_re, r_im;
+
+ len = (int)((int*)l + (len << 1));
+
+ __asm__ volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "1: \n\t"
+ "add.s %[h0], %[h0], %[hs0] \n\t"
+ "lwc1 %[l_re], 0(%[l]) \n\t"
+ "add.s %[h1], %[h1], %[hs1] \n\t"
+ "lwc1 %[r_re], 0(%[r]) \n\t"
+ "add.s %[h2], %[h2], %[hs2] \n\t"
+ "lwc1 %[l_im], 4(%[l]) \n\t"
+ "add.s %[h3], %[h3], %[hs3] \n\t"
+ "lwc1 %[r_im], 4(%[r]) \n\t"
+ "mul.s %[temp0], %[h0], %[l_re] \n\t"
+ "addiu %[l], %[l], 8 \n\t"
+ "mul.s %[temp2], %[h1], %[l_re] \n\t"
+ "addiu %[r], %[r], 8 \n\t"
+ "madd.s %[temp0], %[temp0], %[h2], %[r_re] \n\t"
+ "madd.s %[temp2], %[temp2], %[h3], %[r_re] \n\t"
+ "mul.s %[temp1], %[h0], %[l_im] \n\t"
+ "mul.s %[temp3], %[h1], %[l_im] \n\t"
+ "madd.s %[temp1], %[temp1], %[h2], %[r_im] \n\t"
+ "madd.s %[temp3], %[temp3], %[h3], %[r_im] \n\t"
+ "swc1 %[temp0], -8(%[l]) \n\t"
+ "swc1 %[temp2], -8(%[r]) \n\t"
+ "swc1 %[temp1], -4(%[l]) \n\t"
+ "bne %[l], %[len], 1b \n\t"
+ " swc1 %[temp3], -4(%[r]) \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1),
+ [temp2]"=&f"(temp2), [temp3]"=&f"(temp3),
+ [h0]"+f"(h0), [h1]"+f"(h1), [h2]"+f"(h2),
+ [h3]"+f"(h3), [l]"+r"(l), [r]"+r"(r),
+ [l_re]"=&f"(l_re), [l_im]"=&f"(l_im),
+ [r_re]"=&f"(r_re), [r_im]"=&f"(r_im)
+ : [hs0]"f"(hs0), [hs1]"f"(hs1), [hs2]"f"(hs2),
+ [hs3]"f"(hs3), [len]"r"(len)
+ : "memory"
+ );
+}
+#endif /* HAVE_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+
+void ff_psdsp_init_mips(PSDSPContext *s)
+{
+#if HAVE_INLINE_ASM
+ s->hybrid_analysis_ileave = ps_hybrid_analysis_ileave_mips;
+ s->hybrid_synthesis_deint = ps_hybrid_synthesis_deint_mips;
+#if HAVE_MIPSFPU
+ s->add_squares = ps_add_squares_mips;
+ s->mul_pair_single = ps_mul_pair_single_mips;
+ s->decorrelate = ps_decorrelate_mips;
+ s->stereo_interpolate[0] = ps_stereo_interpolate_mips;
+#endif /* HAVE_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/mips/aacpsy_mips.h b/libavcodec/mips/aacpsy_mips.h
new file mode 100644
index 0000000..d1353c4
--- /dev/null
+++ b/libavcodec/mips/aacpsy_mips.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Bojan Zivkovic (bojan@mips.com)
+ *
+ * AAC encoder psychoacoustic model routines optimized
+ * for MIPS floating-point architecture
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/aacpsy.c
+ */
+
+#ifndef AVCODEC_MIPS_AACPSY_MIPS_H
+#define AVCODEC_MIPS_AACPSY_MIPS_H
+
+#if HAVE_INLINE_ASM && HAVE_MIPSFPU && ( PSY_LAME_FIR_LEN == 21 )
+static void calc_thr_3gpp_mips(const FFPsyWindowInfo *wi, const int num_bands,
+ AacPsyChannel *pch, const uint8_t *band_sizes,
+ const float *coefs)
+{
+ int i, w, g;
+ int start = 0;
+ for (w = 0; w < wi->num_windows*16; w += 16) {
+ for (g = 0; g < num_bands; g++) {
+ AacPsyBand *band = &pch->band[w+g];
+
+ float form_factor = 0.0f;
+ float Temp;
+ band->energy = 0.0f;
+ for (i = 0; i < band_sizes[g]; i+=4) {
+ float a, b, c, d;
+ float ax, bx, cx, dx;
+ float *cf = (float *)&coefs[start+i];
+
+ __asm__ volatile (
+ "lwc1 %[a], 0(%[cf]) \n\t"
+ "lwc1 %[b], 4(%[cf]) \n\t"
+ "lwc1 %[c], 8(%[cf]) \n\t"
+ "lwc1 %[d], 12(%[cf]) \n\t"
+ "abs.s %[a], %[a] \n\t"
+ "abs.s %[b], %[b] \n\t"
+ "abs.s %[c], %[c] \n\t"
+ "abs.s %[d], %[d] \n\t"
+ "sqrt.s %[ax], %[a] \n\t"
+ "sqrt.s %[bx], %[b] \n\t"
+ "sqrt.s %[cx], %[c] \n\t"
+ "sqrt.s %[dx], %[d] \n\t"
+ "madd.s %[e], %[e], %[a], %[a] \n\t"
+ "madd.s %[e], %[e], %[b], %[b] \n\t"
+ "madd.s %[e], %[e], %[c], %[c] \n\t"
+ "madd.s %[e], %[e], %[d], %[d] \n\t"
+ "add.s %[f], %[f], %[ax] \n\t"
+ "add.s %[f], %[f], %[bx] \n\t"
+ "add.s %[f], %[f], %[cx] \n\t"
+ "add.s %[f], %[f], %[dx] \n\t"
+
+ : [a]"=&f"(a), [b]"=&f"(b),
+ [c]"=&f"(c), [d]"=&f"(d),
+ [e]"+f"(band->energy), [f]"+f"(form_factor),
+ [ax]"=&f"(ax), [bx]"=&f"(bx),
+ [cx]"=&f"(cx), [dx]"=&f"(dx)
+ : [cf]"r"(cf)
+ : "memory"
+ );
+ }
+
+ Temp = sqrtf((float)band_sizes[g] / band->energy);
+ band->thr = band->energy * 0.001258925f;
+ band->nz_lines = form_factor * sqrtf(Temp);
+ start += band_sizes[g];
+ }
+ }
+}
+
+static void psy_hp_filter_mips(const float *firbuf, float *hpfsmpl, const float * psy_fir_coeffs)
+{
+ float sum1, sum2, sum3, sum4;
+ float *fb = (float*)firbuf;
+ float *fb_end = fb + AAC_BLOCK_SIZE_LONG;
+ float *hp = hpfsmpl;
+
+ float coeff0 = psy_fir_coeffs[1];
+ float coeff1 = psy_fir_coeffs[3];
+ float coeff2 = psy_fir_coeffs[5];
+ float coeff3 = psy_fir_coeffs[7];
+ float coeff4 = psy_fir_coeffs[9];
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "li.s $f12, 32768 \n\t"
+ "1: \n\t"
+ "lwc1 $f0, 40(%[fb]) \n\t"
+ "lwc1 $f1, 4(%[fb]) \n\t"
+ "lwc1 $f2, 80(%[fb]) \n\t"
+ "lwc1 $f3, 44(%[fb]) \n\t"
+ "lwc1 $f4, 8(%[fb]) \n\t"
+ "madd.s %[sum1], $f0, $f1, %[coeff0] \n\t"
+ "lwc1 $f5, 84(%[fb]) \n\t"
+ "lwc1 $f6, 48(%[fb]) \n\t"
+ "madd.s %[sum2], $f3, $f4, %[coeff0] \n\t"
+ "lwc1 $f7, 12(%[fb]) \n\t"
+ "madd.s %[sum1], %[sum1], $f2, %[coeff0] \n\t"
+ "lwc1 $f8, 88(%[fb]) \n\t"
+ "lwc1 $f9, 52(%[fb]) \n\t"
+ "madd.s %[sum2], %[sum2], $f5, %[coeff0] \n\t"
+ "madd.s %[sum3], $f6, $f7, %[coeff0] \n\t"
+ "lwc1 $f10, 16(%[fb]) \n\t"
+ "lwc1 $f11, 92(%[fb]) \n\t"
+ "madd.s %[sum1], %[sum1], $f7, %[coeff1] \n\t"
+ "lwc1 $f1, 72(%[fb]) \n\t"
+ "madd.s %[sum3], %[sum3], $f8, %[coeff0] \n\t"
+ "madd.s %[sum4], $f9, $f10, %[coeff0] \n\t"
+ "madd.s %[sum2], %[sum2], $f10, %[coeff1] \n\t"
+ "madd.s %[sum1], %[sum1], $f1, %[coeff1] \n\t"
+ "lwc1 $f4, 76(%[fb]) \n\t"
+ "lwc1 $f8, 20(%[fb]) \n\t"
+ "madd.s %[sum4], %[sum4], $f11, %[coeff0] \n\t"
+ "lwc1 $f11, 24(%[fb]) \n\t"
+ "madd.s %[sum2], %[sum2], $f4, %[coeff1] \n\t"
+ "madd.s %[sum1], %[sum1], $f8, %[coeff2] \n\t"
+ "madd.s %[sum3], %[sum3], $f8, %[coeff1] \n\t"
+ "madd.s %[sum4], %[sum4], $f11, %[coeff1] \n\t"
+ "lwc1 $f7, 64(%[fb]) \n\t"
+ "madd.s %[sum2], %[sum2], $f11, %[coeff2] \n\t"
+ "lwc1 $f10, 68(%[fb]) \n\t"
+ "madd.s %[sum3], %[sum3], $f2, %[coeff1] \n\t"
+ "madd.s %[sum4], %[sum4], $f5, %[coeff1] \n\t"
+ "madd.s %[sum1], %[sum1], $f7, %[coeff2] \n\t"
+ "madd.s %[sum2], %[sum2], $f10, %[coeff2] \n\t"
+ "lwc1 $f2, 28(%[fb]) \n\t"
+ "lwc1 $f5, 32(%[fb]) \n\t"
+ "lwc1 $f8, 56(%[fb]) \n\t"
+ "lwc1 $f11, 60(%[fb]) \n\t"
+ "madd.s %[sum3], %[sum3], $f2, %[coeff2] \n\t"
+ "madd.s %[sum4], %[sum4], $f5, %[coeff2] \n\t"
+ "madd.s %[sum1], %[sum1], $f2, %[coeff3] \n\t"
+ "madd.s %[sum2], %[sum2], $f5, %[coeff3] \n\t"
+ "madd.s %[sum3], %[sum3], $f1, %[coeff2] \n\t"
+ "madd.s %[sum4], %[sum4], $f4, %[coeff2] \n\t"
+ "madd.s %[sum1], %[sum1], $f8, %[coeff3] \n\t"
+ "madd.s %[sum2], %[sum2], $f11, %[coeff3] \n\t"
+ "lwc1 $f1, 36(%[fb]) \n\t"
+ "addiu %[fb], %[fb], 16 \n\t"
+ "madd.s %[sum4], %[sum4], $f0, %[coeff3] \n\t"
+ "madd.s %[sum3], %[sum3], $f1, %[coeff3] \n\t"
+ "madd.s %[sum1], %[sum1], $f1, %[coeff4] \n\t"
+ "madd.s %[sum2], %[sum2], $f0, %[coeff4] \n\t"
+ "madd.s %[sum4], %[sum4], $f10, %[coeff3] \n\t"
+ "madd.s %[sum3], %[sum3], $f7, %[coeff3] \n\t"
+ "madd.s %[sum1], %[sum1], $f6, %[coeff4] \n\t"
+ "madd.s %[sum2], %[sum2], $f9, %[coeff4] \n\t"
+ "madd.s %[sum4], %[sum4], $f6, %[coeff4] \n\t"
+ "madd.s %[sum3], %[sum3], $f3, %[coeff4] \n\t"
+ "mul.s %[sum1], %[sum1], $f12 \n\t"
+ "mul.s %[sum2], %[sum2], $f12 \n\t"
+ "madd.s %[sum4], %[sum4], $f11, %[coeff4] \n\t"
+ "madd.s %[sum3], %[sum3], $f8, %[coeff4] \n\t"
+ "swc1 %[sum1], 0(%[hp]) \n\t"
+ "swc1 %[sum2], 4(%[hp]) \n\t"
+ "mul.s %[sum4], %[sum4], $f12 \n\t"
+ "mul.s %[sum3], %[sum3], $f12 \n\t"
+ "swc1 %[sum4], 12(%[hp]) \n\t"
+ "swc1 %[sum3], 8(%[hp]) \n\t"
+ "bne %[fb], %[fb_end], 1b \n\t"
+ " addiu %[hp], %[hp], 16 \n\t"
+
+ ".set pop \n\t"
+
+ : [sum1]"=&f"(sum1), [sum2]"=&f"(sum2),
+ [sum3]"=&f"(sum3), [sum4]"=&f"(sum4),
+ [fb]"+r"(fb), [hp]"+r"(hp)
+ : [coeff0]"f"(coeff0), [coeff1]"f"(coeff1),
+ [coeff2]"f"(coeff2), [coeff3]"f"(coeff3),
+ [coeff4]"f"(coeff4), [fb_end]"r"(fb_end)
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6",
+ "$f7", "$f8", "$f9", "$f10", "$f11", "$f12",
+ "memory"
+ );
+}
+
+#define calc_thr_3gpp calc_thr_3gpp_mips
+#define psy_hp_filter psy_hp_filter_mips
+
+#endif /* HAVE_INLINE_ASM && HAVE_MIPSFPU */
+#endif /* AVCODEC_MIPS_AACPSY_MIPS_H */
diff --git a/libavcodec/mips/aacsbr_mips.c b/libavcodec/mips/aacsbr_mips.c
new file mode 100644
index 0000000..53a5fd0
--- /dev/null
+++ b/libavcodec/mips/aacsbr_mips.c
@@ -0,0 +1,618 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Authors: Djordje Pesut (djordje@mips.com)
+ * Mirjana Vulin (mvulin@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/aacsbr.c
+ */
+
+#include "libavcodec/aac.h"
+#include "libavcodec/aacsbr.h"
+
+#define ENVELOPE_ADJUSTMENT_OFFSET 2
+
+#if HAVE_INLINE_ASM
+static int sbr_lf_gen_mips(AACContext *ac, SpectralBandReplication *sbr,
+ float X_low[32][40][2], const float W[2][32][32][2],
+ int buf_idx)
+{
+ int i, k;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ float *p_x_low = &X_low[0][8][0];
+ float *p_w = (float*)&W[buf_idx][0][0][0];
+ float *p_x1_low = &X_low[0][0][0];
+ float *p_w1 = (float*)&W[1-buf_idx][24][0][0];
+
+ float *loop_end=p_x1_low + 2560;
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ "1: \n\t"
+ "sw $0, 0(%[p_x1_low]) \n\t"
+ "sw $0, 4(%[p_x1_low]) \n\t"
+ "sw $0, 8(%[p_x1_low]) \n\t"
+ "sw $0, 12(%[p_x1_low]) \n\t"
+ "sw $0, 16(%[p_x1_low]) \n\t"
+ "sw $0, 20(%[p_x1_low]) \n\t"
+ "sw $0, 24(%[p_x1_low]) \n\t"
+ "sw $0, 28(%[p_x1_low]) \n\t"
+ "addiu %[p_x1_low], %[p_x1_low], 32 \n\t"
+ "bne %[p_x1_low], %[loop_end], 1b \n\t"
+ "addiu %[p_x1_low], %[p_x1_low], -10240 \n\t"
+
+ : [p_x1_low]"+r"(p_x1_low)
+ : [loop_end]"r"(loop_end)
+ : "memory"
+ );
+
+ for (k = 0; k < sbr->kx[1]; k++) {
+ for (i = 0; i < 32; i+=4) {
+ /* loop unrolled 4 times */
+ __asm__ volatile (
+ "lw %[temp0], 0(%[p_w]) \n\t"
+ "lw %[temp1], 4(%[p_w]) \n\t"
+ "lw %[temp2], 256(%[p_w]) \n\t"
+ "lw %[temp3], 260(%[p_w]) \n\t"
+ "lw %[temp4], 512(%[p_w]) \n\t"
+ "lw %[temp5], 516(%[p_w]) \n\t"
+ "lw %[temp6], 768(%[p_w]) \n\t"
+ "lw %[temp7], 772(%[p_w]) \n\t"
+ "sw %[temp0], 0(%[p_x_low]) \n\t"
+ "sw %[temp1], 4(%[p_x_low]) \n\t"
+ "sw %[temp2], 8(%[p_x_low]) \n\t"
+ "sw %[temp3], 12(%[p_x_low]) \n\t"
+ "sw %[temp4], 16(%[p_x_low]) \n\t"
+ "sw %[temp5], 20(%[p_x_low]) \n\t"
+ "sw %[temp6], 24(%[p_x_low]) \n\t"
+ "sw %[temp7], 28(%[p_x_low]) \n\t"
+ "addiu %[p_x_low], %[p_x_low], 32 \n\t"
+ "addiu %[p_w], %[p_w], 1024 \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
+ [p_w]"+r"(p_w), [p_x_low]"+r"(p_x_low)
+ :
+ : "memory"
+ );
+ }
+ p_x_low += 16;
+ p_w -= 2046;
+ }
+
+ for (k = 0; k < sbr->kx[0]; k++) {
+ for (i = 0; i < 2; i++) {
+
+ /* loop unrolled 4 times */
+ __asm__ volatile (
+ "lw %[temp0], 0(%[p_w1]) \n\t"
+ "lw %[temp1], 4(%[p_w1]) \n\t"
+ "lw %[temp2], 256(%[p_w1]) \n\t"
+ "lw %[temp3], 260(%[p_w1]) \n\t"
+ "lw %[temp4], 512(%[p_w1]) \n\t"
+ "lw %[temp5], 516(%[p_w1]) \n\t"
+ "lw %[temp6], 768(%[p_w1]) \n\t"
+ "lw %[temp7], 772(%[p_w1]) \n\t"
+ "sw %[temp0], 0(%[p_x1_low]) \n\t"
+ "sw %[temp1], 4(%[p_x1_low]) \n\t"
+ "sw %[temp2], 8(%[p_x1_low]) \n\t"
+ "sw %[temp3], 12(%[p_x1_low]) \n\t"
+ "sw %[temp4], 16(%[p_x1_low]) \n\t"
+ "sw %[temp5], 20(%[p_x1_low]) \n\t"
+ "sw %[temp6], 24(%[p_x1_low]) \n\t"
+ "sw %[temp7], 28(%[p_x1_low]) \n\t"
+ "addiu %[p_x1_low], %[p_x1_low], 32 \n\t"
+ "addiu %[p_w1], %[p_w1], 1024 \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
+ [p_w1]"+r"(p_w1), [p_x1_low]"+r"(p_x1_low)
+ :
+ : "memory"
+ );
+ }
+ p_x1_low += 64;
+ p_w1 -= 510;
+ }
+ return 0;
+}
+
+static int sbr_x_gen_mips(SpectralBandReplication *sbr, float X[2][38][64],
+ const float Y0[38][64][2], const float Y1[38][64][2],
+ const float X_low[32][40][2], int ch)
+{
+ int k, i;
+ const int i_f = 32;
+ int temp0, temp1, temp2, temp3;
+ const float *X_low1, *Y01, *Y11;
+ float *x1=&X[0][0][0];
+ float *j=x1+4864;
+ const int i_Temp = FFMAX(2*sbr->data[ch].t_env_num_env_old - i_f, 0);
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ "1: \n\t"
+ "sw $0, 0(%[x1]) \n\t"
+ "sw $0, 4(%[x1]) \n\t"
+ "sw $0, 8(%[x1]) \n\t"
+ "sw $0, 12(%[x1]) \n\t"
+ "sw $0, 16(%[x1]) \n\t"
+ "sw $0, 20(%[x1]) \n\t"
+ "sw $0, 24(%[x1]) \n\t"
+ "sw $0, 28(%[x1]) \n\t"
+ "addiu %[x1], %[x1], 32 \n\t"
+ "bne %[x1], %[j], 1b \n\t"
+ "addiu %[x1], %[x1], -19456 \n\t"
+
+ : [x1]"+r"(x1)
+ : [j]"r"(j)
+ : "memory"
+ );
+
+ if (i_Temp != 0) {
+
+ X_low1=&X_low[0][2][0];
+
+ for (k = 0; k < sbr->kx[0]; k++) {
+
+ __asm__ volatile (
+ "move %[i], $zero \n\t"
+ "2: \n\t"
+ "lw %[temp0], 0(%[X_low1]) \n\t"
+ "lw %[temp1], 4(%[X_low1]) \n\t"
+ "sw %[temp0], 0(%[x1]) \n\t"
+ "sw %[temp1], 9728(%[x1]) \n\t"
+ "addiu %[x1], %[x1], 256 \n\t"
+ "addiu %[X_low1], %[X_low1], 8 \n\t"
+ "addiu %[i], %[i], 1 \n\t"
+ "bne %[i], %[i_Temp], 2b \n\t"
+
+ : [x1]"+r"(x1), [X_low1]"+r"(X_low1), [i]"=&r"(i),
+ [temp0]"=&r"(temp0), [temp1]"=&r"(temp1)
+ : [i_Temp]"r"(i_Temp)
+ : "memory"
+ );
+ x1-=(i_Temp<<6)-1;
+ X_low1-=(i_Temp<<1)-80;
+ }
+
+ x1=&X[0][0][k];
+ Y01=(float*)&Y0[32][k][0];
+
+ for (; k < sbr->kx[0] + sbr->m[0]; k++) {
+ __asm__ volatile (
+ "move %[i], $zero \n\t"
+ "3: \n\t"
+ "lw %[temp0], 0(%[Y01]) \n\t"
+ "lw %[temp1], 4(%[Y01]) \n\t"
+ "sw %[temp0], 0(%[x1]) \n\t"
+ "sw %[temp1], 9728(%[x1]) \n\t"
+ "addiu %[x1], %[x1], 256 \n\t"
+ "addiu %[Y01], %[Y01], 512 \n\t"
+ "addiu %[i], %[i], 1 \n\t"
+ "bne %[i], %[i_Temp], 3b \n\t"
+
+ : [x1]"+r"(x1), [Y01]"+r"(Y01), [i]"=&r"(i),
+ [temp0]"=&r"(temp0), [temp1]"=&r"(temp1)
+ : [i_Temp]"r"(i_Temp)
+ : "memory"
+ );
+ x1 -=(i_Temp<<6)-1;
+ Y01 -=(i_Temp<<7)-2;
+ }
+ }
+
+ x1=&X[0][i_Temp][0];
+ X_low1=&X_low[0][i_Temp+2][0];
+ temp3=38;
+
+ for (k = 0; k < sbr->kx[1]; k++) {
+
+ __asm__ volatile (
+ "move %[i], %[i_Temp] \n\t"
+ "4: \n\t"
+ "lw %[temp0], 0(%[X_low1]) \n\t"
+ "lw %[temp1], 4(%[X_low1]) \n\t"
+ "sw %[temp0], 0(%[x1]) \n\t"
+ "sw %[temp1], 9728(%[x1]) \n\t"
+ "addiu %[x1], %[x1], 256 \n\t"
+ "addiu %[X_low1], %[X_low1], 8 \n\t"
+ "addiu %[i], %[i], 1 \n\t"
+ "bne %[i], %[temp3], 4b \n\t"
+
+ : [x1]"+r"(x1), [X_low1]"+r"(X_low1), [i]"=&r"(i),
+ [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2)
+ : [i_Temp]"r"(i_Temp), [temp3]"r"(temp3)
+ : "memory"
+ );
+ x1 -= ((38-i_Temp)<<6)-1;
+ X_low1 -= ((38-i_Temp)<<1)- 80;
+ }
+
+ x1=&X[0][i_Temp][k];
+ Y11=&Y1[i_Temp][k][0];
+ temp2=32;
+
+ for (; k < sbr->kx[1] + sbr->m[1]; k++) {
+
+ __asm__ volatile (
+ "move %[i], %[i_Temp] \n\t"
+ "5: \n\t"
+ "lw %[temp0], 0(%[Y11]) \n\t"
+ "lw %[temp1], 4(%[Y11]) \n\t"
+ "sw %[temp0], 0(%[x1]) \n\t"
+ "sw %[temp1], 9728(%[x1]) \n\t"
+ "addiu %[x1], %[x1], 256 \n\t"
+ "addiu %[Y11], %[Y11], 512 \n\t"
+ "addiu %[i], %[i], 1 \n\t"
+ "bne %[i], %[temp2], 5b \n\t"
+
+ : [x1]"+r"(x1), [Y11]"+r"(Y11), [i]"=&r"(i),
+ [temp0]"=&r"(temp0), [temp1]"=&r"(temp1)
+ : [i_Temp]"r"(i_Temp), [temp3]"r"(temp3),
+ [temp2]"r"(temp2)
+ : "memory"
+ );
+
+ x1 -= ((32-i_Temp)<<6)-1;
+ Y11 -= ((32-i_Temp)<<7)-2;
+ }
+ return 0;
+}
+
+#if HAVE_MIPSFPU
+static void sbr_hf_assemble_mips(float Y1[38][64][2],
+ const float X_high[64][40][2],
+ SpectralBandReplication *sbr, SBRData *ch_data,
+ const int e_a[2])
+{
+ int e, i, j, m;
+ const int h_SL = 4 * !sbr->bs_smoothing_mode;
+ const int kx = sbr->kx[1];
+ const int m_max = sbr->m[1];
+ static const float h_smooth[5] = {
+ 0.33333333333333,
+ 0.30150283239582,
+ 0.21816949906249,
+ 0.11516383427084,
+ 0.03183050093751,
+ };
+
+ float (*g_temp)[48] = ch_data->g_temp, (*q_temp)[48] = ch_data->q_temp;
+ int indexnoise = ch_data->f_indexnoise;
+ int indexsine = ch_data->f_indexsine;
+ float *g_temp1, *q_temp1, *pok, *pok1;
+ float temp1, temp2, temp3, temp4;
+ int size = m_max;
+
+ if (sbr->reset) {
+ for (i = 0; i < h_SL; i++) {
+ memcpy(g_temp[i + 2*ch_data->t_env[0]], sbr->gain[0], m_max * sizeof(sbr->gain[0][0]));
+ memcpy(q_temp[i + 2*ch_data->t_env[0]], sbr->q_m[0], m_max * sizeof(sbr->q_m[0][0]));
+ }
+ } else if (h_SL) {
+ memcpy(g_temp[2*ch_data->t_env[0]], g_temp[2*ch_data->t_env_num_env_old], 4*sizeof(g_temp[0]));
+ memcpy(q_temp[2*ch_data->t_env[0]], q_temp[2*ch_data->t_env_num_env_old], 4*sizeof(q_temp[0]));
+ }
+
+ for (e = 0; e < ch_data->bs_num_env; e++) {
+ for (i = 2 * ch_data->t_env[e]; i < 2 * ch_data->t_env[e + 1]; i++) {
+ g_temp1 = g_temp[h_SL + i];
+ pok = sbr->gain[e];
+ q_temp1 = q_temp[h_SL + i];
+ pok1 = sbr->q_m[e];
+
+ /* loop unrolled 4 times */
+ for (j=0; j<(size>>2); j++) {
+ __asm__ volatile (
+ "lw %[temp1], 0(%[pok]) \n\t"
+ "lw %[temp2], 4(%[pok]) \n\t"
+ "lw %[temp3], 8(%[pok]) \n\t"
+ "lw %[temp4], 12(%[pok]) \n\t"
+ "sw %[temp1], 0(%[g_temp1]) \n\t"
+ "sw %[temp2], 4(%[g_temp1]) \n\t"
+ "sw %[temp3], 8(%[g_temp1]) \n\t"
+ "sw %[temp4], 12(%[g_temp1]) \n\t"
+ "lw %[temp1], 0(%[pok1]) \n\t"
+ "lw %[temp2], 4(%[pok1]) \n\t"
+ "lw %[temp3], 8(%[pok1]) \n\t"
+ "lw %[temp4], 12(%[pok1]) \n\t"
+ "sw %[temp1], 0(%[q_temp1]) \n\t"
+ "sw %[temp2], 4(%[q_temp1]) \n\t"
+ "sw %[temp3], 8(%[q_temp1]) \n\t"
+ "sw %[temp4], 12(%[q_temp1]) \n\t"
+ "addiu %[pok], %[pok], 16 \n\t"
+ "addiu %[g_temp1], %[g_temp1], 16 \n\t"
+ "addiu %[pok1], %[pok1], 16 \n\t"
+ "addiu %[q_temp1], %[q_temp1], 16 \n\t"
+
+ : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4),
+ [pok]"+r"(pok), [g_temp1]"+r"(g_temp1),
+ [pok1]"+r"(pok1), [q_temp1]"+r"(q_temp1)
+ :
+ : "memory"
+ );
+ }
+
+ for (j=0; j<(size&3); j++) {
+ __asm__ volatile (
+ "lw %[temp1], 0(%[pok]) \n\t"
+ "lw %[temp2], 0(%[pok1]) \n\t"
+ "sw %[temp1], 0(%[g_temp1]) \n\t"
+ "sw %[temp2], 0(%[q_temp1]) \n\t"
+ "addiu %[pok], %[pok], 4 \n\t"
+ "addiu %[g_temp1], %[g_temp1], 4 \n\t"
+ "addiu %[pok1], %[pok1], 4 \n\t"
+ "addiu %[q_temp1], %[q_temp1], 4 \n\t"
+
+ : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4),
+ [pok]"+r"(pok), [g_temp1]"+r"(g_temp1),
+ [pok1]"+r"(pok1), [q_temp1]"+r"(q_temp1)
+ :
+ : "memory"
+ );
+ }
+ }
+ }
+
+ for (e = 0; e < ch_data->bs_num_env; e++) {
+ for (i = 2 * ch_data->t_env[e]; i < 2 * ch_data->t_env[e + 1]; i++) {
+ LOCAL_ALIGNED_16(float, g_filt_tab, [48]);
+ LOCAL_ALIGNED_16(float, q_filt_tab, [48]);
+ float *g_filt, *q_filt;
+
+ if (h_SL && e != e_a[0] && e != e_a[1]) {
+ g_filt = g_filt_tab;
+ q_filt = q_filt_tab;
+
+ for (m = 0; m < m_max; m++) {
+ const int idx1 = i + h_SL;
+ g_filt[m] = 0.0f;
+ q_filt[m] = 0.0f;
+
+ for (j = 0; j <= h_SL; j++) {
+ g_filt[m] += g_temp[idx1 - j][m] * h_smooth[j];
+ q_filt[m] += q_temp[idx1 - j][m] * h_smooth[j];
+ }
+ }
+ } else {
+ g_filt = g_temp[i + h_SL];
+ q_filt = q_temp[i];
+ }
+
+ sbr->dsp.hf_g_filt(Y1[i] + kx, X_high + kx, g_filt, m_max,
+ i + ENVELOPE_ADJUSTMENT_OFFSET);
+
+ if (e != e_a[0] && e != e_a[1]) {
+ sbr->dsp.hf_apply_noise[indexsine](Y1[i] + kx, sbr->s_m[e],
+ q_filt, indexnoise,
+ kx, m_max);
+ } else {
+ int idx = indexsine&1;
+ int A = (1-((indexsine+(kx & 1))&2));
+ int B = (A^(-idx)) + idx;
+ float *out = &Y1[i][kx][idx];
+ float *in = sbr->s_m[e];
+ float temp0, temp1, temp2, temp3, temp4, temp5;
+ float A_f = (float)A;
+ float B_f = (float)B;
+
+ for (m = 0; m+1 < m_max; m+=2) {
+
+ temp2 = out[0];
+ temp3 = out[2];
+
+ __asm__ volatile(
+ "lwc1 %[temp0], 0(%[in]) \n\t"
+ "lwc1 %[temp1], 4(%[in]) \n\t"
+ "madd.s %[temp4], %[temp2], %[temp0], %[A_f] \n\t"
+ "madd.s %[temp5], %[temp3], %[temp1], %[B_f] \n\t"
+ "swc1 %[temp4], 0(%[out]) \n\t"
+ "swc1 %[temp5], 8(%[out]) \n\t"
+ "addiu %[in], %[in], 8 \n\t"
+ "addiu %[out], %[out], 16 \n\t"
+
+ : [temp0]"=&f" (temp0), [temp1]"=&f"(temp1),
+ [temp4]"=&f" (temp4), [temp5]"=&f"(temp5),
+ [in]"+r"(in), [out]"+r"(out)
+ : [A_f]"f"(A_f), [B_f]"f"(B_f), [temp2]"f"(temp2),
+ [temp3]"f"(temp3)
+ : "memory"
+ );
+ }
+ if(m_max&1)
+ out[2*m ] += in[m ] * A;
+ }
+ indexnoise = (indexnoise + m_max) & 0x1ff;
+ indexsine = (indexsine + 1) & 3;
+ }
+ }
+ ch_data->f_indexnoise = indexnoise;
+ ch_data->f_indexsine = indexsine;
+}
+
+static void sbr_hf_inverse_filter_mips(SBRDSPContext *dsp,
+ float (*alpha0)[2], float (*alpha1)[2],
+ const float X_low[32][40][2], int k0)
+{
+ int k;
+ float temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, c;
+ float *phi1, *alpha_1, *alpha_0, res1, res2, temp_real, temp_im;
+
+ c = 1.000001f;
+
+ for (k = 0; k < k0; k++) {
+ LOCAL_ALIGNED_16(float, phi, [3], [2][2]);
+ float dk;
+ phi1 = &phi[0][0][0];
+ alpha_1 = &alpha1[k][0];
+ alpha_0 = &alpha0[k][0];
+ dsp->autocorrelate(X_low[k], phi);
+
+ __asm__ volatile (
+ "lwc1 %[temp0], 40(%[phi1]) \n\t"
+ "lwc1 %[temp1], 16(%[phi1]) \n\t"
+ "lwc1 %[temp2], 24(%[phi1]) \n\t"
+ "lwc1 %[temp3], 28(%[phi1]) \n\t"
+ "mul.s %[dk], %[temp0], %[temp1] \n\t"
+ "lwc1 %[temp4], 0(%[phi1]) \n\t"
+ "mul.s %[res2], %[temp2], %[temp2] \n\t"
+ "lwc1 %[temp5], 4(%[phi1]) \n\t"
+ "madd.s %[res2], %[res2], %[temp3], %[temp3] \n\t"
+ "lwc1 %[temp6], 8(%[phi1]) \n\t"
+ "div.s %[res2], %[res2], %[c] \n\t"
+ "lwc1 %[temp0], 12(%[phi1]) \n\t"
+ "sub.s %[dk], %[dk], %[res2] \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [res2]"=&f"(res2), [dk]"=&f"(dk)
+ : [phi1]"r"(phi1), [c]"f"(c)
+ : "memory"
+ );
+
+ if (!dk) {
+ alpha_1[0] = 0;
+ alpha_1[1] = 0;
+ } else {
+ __asm__ volatile (
+ "mul.s %[temp_real], %[temp4], %[temp2] \n\t"
+ "nmsub.s %[temp_real], %[temp_real], %[temp5], %[temp3] \n\t"
+ "nmsub.s %[temp_real], %[temp_real], %[temp6], %[temp1] \n\t"
+ "mul.s %[temp_im], %[temp4], %[temp3] \n\t"
+ "madd.s %[temp_im], %[temp_im], %[temp5], %[temp2] \n\t"
+ "nmsub.s %[temp_im], %[temp_im], %[temp0], %[temp1] \n\t"
+ "div.s %[temp_real], %[temp_real], %[dk] \n\t"
+ "div.s %[temp_im], %[temp_im], %[dk] \n\t"
+ "swc1 %[temp_real], 0(%[alpha_1]) \n\t"
+ "swc1 %[temp_im], 4(%[alpha_1]) \n\t"
+
+ : [temp_real]"=&f" (temp_real), [temp_im]"=&f"(temp_im)
+ : [phi1]"r"(phi1), [temp0]"f"(temp0), [temp1]"f"(temp1),
+ [temp2]"f"(temp2), [temp3]"f"(temp3), [temp4]"f"(temp4),
+ [temp5]"f"(temp5), [temp6]"f"(temp6),
+ [alpha_1]"r"(alpha_1), [dk]"f"(dk)
+ : "memory"
+ );
+ }
+
+ if (!phi1[4]) {
+ alpha_0[0] = 0;
+ alpha_0[1] = 0;
+ } else {
+ __asm__ volatile (
+ "lwc1 %[temp6], 0(%[alpha_1]) \n\t"
+ "lwc1 %[temp7], 4(%[alpha_1]) \n\t"
+ "mul.s %[temp_real], %[temp6], %[temp2] \n\t"
+ "add.s %[temp_real], %[temp_real], %[temp4] \n\t"
+ "madd.s %[temp_real], %[temp_real], %[temp7], %[temp3] \n\t"
+ "mul.s %[temp_im], %[temp7], %[temp2] \n\t"
+ "add.s %[temp_im], %[temp_im], %[temp5] \n\t"
+ "nmsub.s %[temp_im], %[temp_im], %[temp6], %[temp3] \n\t"
+ "div.s %[temp_real], %[temp_real], %[temp1] \n\t"
+ "div.s %[temp_im], %[temp_im], %[temp1] \n\t"
+ "neg.s %[temp_real], %[temp_real] \n\t"
+ "neg.s %[temp_im], %[temp_im] \n\t"
+ "swc1 %[temp_real], 0(%[alpha_0]) \n\t"
+ "swc1 %[temp_im], 4(%[alpha_0]) \n\t"
+
+ : [temp_real]"=&f"(temp_real), [temp_im]"=&f"(temp_im),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7),
+ [res1]"=&f"(res1), [res2]"=&f"(res2)
+ : [alpha_1]"r"(alpha_1), [alpha_0]"r"(alpha_0),
+ [temp0]"f"(temp0), [temp1]"f"(temp1), [temp2]"f"(temp2),
+ [temp3]"f"(temp3), [temp4]"f"(temp4), [temp5]"f"(temp5)
+ : "memory"
+ );
+ }
+
+ __asm__ volatile (
+ "lwc1 %[temp1], 0(%[alpha_1]) \n\t"
+ "lwc1 %[temp2], 4(%[alpha_1]) \n\t"
+ "lwc1 %[temp_real], 0(%[alpha_0]) \n\t"
+ "lwc1 %[temp_im], 4(%[alpha_0]) \n\t"
+ "mul.s %[res1], %[temp1], %[temp1] \n\t"
+ "madd.s %[res1], %[res1], %[temp2], %[temp2] \n\t"
+ "mul.s %[res2], %[temp_real], %[temp_real] \n\t"
+ "madd.s %[res2], %[res2], %[temp_im], %[temp_im] \n\t"
+
+ : [temp_real]"=&f"(temp_real), [temp_im]"=&f"(temp_im),
+ [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [res1]"=&f"(res1), [res2]"=&f"(res2)
+ : [alpha_1]"r"(alpha_1), [alpha_0]"r"(alpha_0)
+ : "memory"
+ );
+
+ if (res1 >= 16.0f || res2 >= 16.0f) {
+ alpha_1[0] = 0;
+ alpha_1[1] = 0;
+ alpha_0[0] = 0;
+ alpha_0[1] = 0;
+ }
+ }
+}
+#endif /* HAVE_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+
+void ff_aacsbr_func_ptr_init_mips(AACSBRContext *c)
+{
+#if HAVE_INLINE_ASM
+ c->sbr_lf_gen = sbr_lf_gen_mips;
+ c->sbr_x_gen = sbr_x_gen_mips;
+#if HAVE_MIPSFPU
+ c->sbr_hf_inverse_filter = sbr_hf_inverse_filter_mips;
+ c->sbr_hf_assemble = sbr_hf_assemble_mips;
+#endif /* HAVE_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/mips/aacsbr_mips.h b/libavcodec/mips/aacsbr_mips.h
new file mode 100644
index 0000000..8e6ad7d
--- /dev/null
+++ b/libavcodec/mips/aacsbr_mips.h
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Authors: Djordje Pesut (djordje@mips.com)
+ * Mirjana Vulin (mvulin@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/aacsbr.c
+ */
+
+#ifndef AVCODEC_MIPS_AACSBR_FLOAT_H
+#define AVCODEC_MIPS_AACSBR_FLOAT_H
+
+#include "libavcodec/aac.h"
+#include "libavcodec/sbr.h"
+
+#if HAVE_INLINE_ASM
+static void sbr_qmf_analysis_mips(AVFloatDSPContext *fdsp, FFTContext *mdct,
+ SBRDSPContext *sbrdsp, const float *in, float *x,
+ float z[320], float W[2][32][32][2], int buf_idx)
+{
+ int i;
+ float *w0;
+ float *w1;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ w0 = x;
+ w1 = x + 1024;
+ for(i = 0; i < 36; i++)
+ {
+ /* loop unrolled 8 times */
+ __asm__ volatile(
+ "lw %[temp0], 0(%[w1]) \n\t"
+ "lw %[temp1], 4(%[w1]) \n\t"
+ "lw %[temp2], 8(%[w1]) \n\t"
+ "lw %[temp3], 12(%[w1]) \n\t"
+ "lw %[temp4], 16(%[w1]) \n\t"
+ "lw %[temp5], 20(%[w1]) \n\t"
+ "lw %[temp6], 24(%[w1]) \n\t"
+ "lw %[temp7], 28(%[w1]) \n\t"
+ "sw %[temp0], 0(%[w0]) \n\t"
+ "sw %[temp1], 4(%[w0]) \n\t"
+ "sw %[temp2], 8(%[w0]) \n\t"
+ "sw %[temp3], 12(%[w0]) \n\t"
+ "sw %[temp4], 16(%[w0]) \n\t"
+ "sw %[temp5], 20(%[w0]) \n\t"
+ "sw %[temp6], 24(%[w0]) \n\t"
+ "sw %[temp7], 28(%[w0]) \n\t"
+ "addiu %[w0], %[w0], 32 \n\t"
+ "addiu %[w1], %[w1], 32 \n\t"
+
+ : [w0]"+r"(w0), [w1]"+r"(w1),
+ [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7)
+ :
+ : "memory"
+ );
+ }
+
+ w0 = x + 288;
+ w1 = (float*)in;
+ for(i = 0; i < 128; i++)
+ {
+ /* loop unrolled 8 times */
+ __asm__ volatile(
+ "lw %[temp0], 0(%[w1]) \n\t"
+ "lw %[temp1], 4(%[w1]) \n\t"
+ "lw %[temp2], 8(%[w1]) \n\t"
+ "lw %[temp3], 12(%[w1]) \n\t"
+ "lw %[temp4], 16(%[w1]) \n\t"
+ "lw %[temp5], 20(%[w1]) \n\t"
+ "lw %[temp6], 24(%[w1]) \n\t"
+ "lw %[temp7], 28(%[w1]) \n\t"
+ "sw %[temp0], 0(%[w0]) \n\t"
+ "sw %[temp1], 4(%[w0]) \n\t"
+ "sw %[temp2], 8(%[w0]) \n\t"
+ "sw %[temp3], 12(%[w0]) \n\t"
+ "sw %[temp4], 16(%[w0]) \n\t"
+ "sw %[temp5], 20(%[w0]) \n\t"
+ "sw %[temp6], 24(%[w0]) \n\t"
+ "sw %[temp7], 28(%[w0]) \n\t"
+ "addiu %[w0], %[w0], 32 \n\t"
+ "addiu %[w1], %[w1], 32 \n\t"
+
+ : [w0]"+r"(w0), [w1]"+r"(w1),
+ [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7)
+ :
+ : "memory"
+ );
+ }
+
+ for (i = 0; i < 32; i++) { // numTimeSlots*RATE = 16*2 as 960 sample frames
+ // are not supported
+ fdsp->vector_fmul_reverse(z, sbr_qmf_window_ds, x, 320);
+ sbrdsp->sum64x5(z);
+ sbrdsp->qmf_pre_shuffle(z);
+ mdct->imdct_half(mdct, z, z+64);
+ sbrdsp->qmf_post_shuffle(W[buf_idx][i], z);
+ x += 32;
+ }
+}
+
+#if HAVE_MIPSFPU
+static void sbr_qmf_synthesis_mips(FFTContext *mdct,
+ SBRDSPContext *sbrdsp, AVFloatDSPContext *fdsp,
+ float *out, float X[2][38][64],
+ float mdct_buf[2][64],
+ float *v0, int *v_off, const unsigned int div)
+{
+ int i, n;
+ const float *sbr_qmf_window = div ? sbr_qmf_window_ds : sbr_qmf_window_us;
+ const int step = 128 >> div;
+ float *v;
+ float temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp10, temp11, temp12, temp13;
+ float temp14, temp15, temp16, temp17, temp18, temp19;
+ float *vv0, *s0, *dst;
+ dst = out;
+
+ for (i = 0; i < 32; i++) {
+ if (*v_off < step) {
+ int saved_samples = (1280 - 128) >> div;
+ memcpy(&v0[SBR_SYNTHESIS_BUF_SIZE - saved_samples], v0, saved_samples * sizeof(float));
+ *v_off = SBR_SYNTHESIS_BUF_SIZE - saved_samples - step;
+ } else {
+ *v_off -= step;
+ }
+ v = v0 + *v_off;
+ if (div) {
+ for (n = 0; n < 32; n++) {
+ X[0][i][ n] = -X[0][i][n];
+ X[0][i][32+n] = X[1][i][31-n];
+ }
+ mdct->imdct_half(mdct, mdct_buf[0], X[0][i]);
+ sbrdsp->qmf_deint_neg(v, mdct_buf[0]);
+ } else {
+ sbrdsp->neg_odd_64(X[1][i]);
+ mdct->imdct_half(mdct, mdct_buf[0], X[0][i]);
+ mdct->imdct_half(mdct, mdct_buf[1], X[1][i]);
+ sbrdsp->qmf_deint_bfly(v, mdct_buf[1], mdct_buf[0]);
+ }
+
+ if(div == 0)
+ {
+ float *v0_end;
+ vv0 = v;
+ v0_end = v + 60;
+ s0 = (float*)sbr_qmf_window;
+
+ /* 10 calls of function vector_fmul_add merged into one loop
+ and loop unrolled 4 times */
+ __asm__ volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "lwc1 %[temp4], 0(%[v0]) \n\t"
+ "lwc1 %[temp5], 0(%[s0]) \n\t"
+ "lwc1 %[temp6], 4(%[v0]) \n\t"
+ "lwc1 %[temp7], 4(%[s0]) \n\t"
+ "lwc1 %[temp8], 8(%[v0]) \n\t"
+ "lwc1 %[temp9], 8(%[s0]) \n\t"
+ "lwc1 %[temp10], 12(%[v0]) \n\t"
+ "lwc1 %[temp11], 12(%[s0]) \n\t"
+ "lwc1 %[temp12], 768(%[v0]) \n\t"
+ "lwc1 %[temp13], 256(%[s0]) \n\t"
+ "lwc1 %[temp14], 772(%[v0]) \n\t"
+ "lwc1 %[temp15], 260(%[s0]) \n\t"
+ "lwc1 %[temp16], 776(%[v0]) \n\t"
+ "lwc1 %[temp17], 264(%[s0]) \n\t"
+ "lwc1 %[temp18], 780(%[v0]) \n\t"
+ "lwc1 %[temp19], 268(%[s0]) \n\t"
+ "1: \n\t"
+ "mul.s %[temp0], %[temp4], %[temp5] \n\t"
+ "lwc1 %[temp4], 1024(%[v0]) \n\t"
+ "mul.s %[temp1], %[temp6], %[temp7] \n\t"
+ "lwc1 %[temp5], 512(%[s0]) \n\t"
+ "mul.s %[temp2], %[temp8], %[temp9] \n\t"
+ "lwc1 %[temp6], 1028(%[v0]) \n\t"
+ "mul.s %[temp3], %[temp10], %[temp11] \n\t"
+ "lwc1 %[temp7], 516(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t"
+ "lwc1 %[temp8], 1032(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t"
+ "lwc1 %[temp9], 520(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t"
+ "lwc1 %[temp10], 1036(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t"
+ "lwc1 %[temp11], 524(%[s0]) \n\t"
+ "lwc1 %[temp12], 1792(%[v0]) \n\t"
+ "lwc1 %[temp13], 768(%[s0]) \n\t"
+ "lwc1 %[temp14], 1796(%[v0]) \n\t"
+ "lwc1 %[temp15], 772(%[s0]) \n\t"
+ "lwc1 %[temp16], 1800(%[v0]) \n\t"
+ "lwc1 %[temp17], 776(%[s0]) \n\t"
+ "lwc1 %[temp18], 1804(%[v0]) \n\t"
+ "lwc1 %[temp19], 780(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t"
+ "lwc1 %[temp4], 2048(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t"
+ "lwc1 %[temp5], 1024(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t"
+ "lwc1 %[temp6], 2052(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t"
+ "lwc1 %[temp7], 1028(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t"
+ "lwc1 %[temp8], 2056(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t"
+ "lwc1 %[temp9], 1032(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t"
+ "lwc1 %[temp10], 2060(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t"
+ "lwc1 %[temp11], 1036(%[s0]) \n\t"
+ "lwc1 %[temp12], 2816(%[v0]) \n\t"
+ "lwc1 %[temp13], 1280(%[s0]) \n\t"
+ "lwc1 %[temp14], 2820(%[v0]) \n\t"
+ "lwc1 %[temp15], 1284(%[s0]) \n\t"
+ "lwc1 %[temp16], 2824(%[v0]) \n\t"
+ "lwc1 %[temp17], 1288(%[s0]) \n\t"
+ "lwc1 %[temp18], 2828(%[v0]) \n\t"
+ "lwc1 %[temp19], 1292(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t"
+ "lwc1 %[temp4], 3072(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t"
+ "lwc1 %[temp5], 1536(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t"
+ "lwc1 %[temp6], 3076(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t"
+ "lwc1 %[temp7], 1540(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t"
+ "lwc1 %[temp8], 3080(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t"
+ "lwc1 %[temp9], 1544(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t"
+ "lwc1 %[temp10], 3084(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t"
+ "lwc1 %[temp11], 1548(%[s0]) \n\t"
+ "lwc1 %[temp12], 3840(%[v0]) \n\t"
+ "lwc1 %[temp13], 1792(%[s0]) \n\t"
+ "lwc1 %[temp14], 3844(%[v0]) \n\t"
+ "lwc1 %[temp15], 1796(%[s0]) \n\t"
+ "lwc1 %[temp16], 3848(%[v0]) \n\t"
+ "lwc1 %[temp17], 1800(%[s0]) \n\t"
+ "lwc1 %[temp18], 3852(%[v0]) \n\t"
+ "lwc1 %[temp19], 1804(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t"
+ "lwc1 %[temp4], 4096(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t"
+ "lwc1 %[temp5], 2048(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t"
+ "lwc1 %[temp6], 4100(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t"
+ "lwc1 %[temp7], 2052(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t"
+ "lwc1 %[temp8], 4104(%[v0]) \n\t"
+ "addiu %[dst], %[dst], 16 \n\t"
+ "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t"
+ "lwc1 %[temp9], 2056(%[s0]) \n\t"
+ "addiu %[s0], %[s0], 16 \n\t"
+ "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t"
+ "lwc1 %[temp10], 4108(%[v0]) \n\t"
+ "addiu %[v0], %[v0], 16 \n\t"
+ "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t"
+ "lwc1 %[temp11], 2044(%[s0]) \n\t"
+ "lwc1 %[temp12], 4848(%[v0]) \n\t"
+ "lwc1 %[temp13], 2288(%[s0]) \n\t"
+ "lwc1 %[temp14], 4852(%[v0]) \n\t"
+ "lwc1 %[temp15], 2292(%[s0]) \n\t"
+ "lwc1 %[temp16], 4856(%[v0]) \n\t"
+ "lwc1 %[temp17], 2296(%[s0]) \n\t"
+ "lwc1 %[temp18], 4860(%[v0]) \n\t"
+ "lwc1 %[temp19], 2300(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t"
+ "lwc1 %[temp4], 0(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t"
+ "lwc1 %[temp5], 0(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t"
+ "lwc1 %[temp6], 4(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t"
+ "lwc1 %[temp7], 4(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t"
+ "lwc1 %[temp8], 8(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t"
+ "lwc1 %[temp9], 8(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t"
+ "lwc1 %[temp10], 12(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t"
+ "lwc1 %[temp11], 12(%[s0]) \n\t"
+ "lwc1 %[temp12], 768(%[v0]) \n\t"
+ "lwc1 %[temp13], 256(%[s0]) \n\t"
+ "lwc1 %[temp14], 772(%[v0]) \n\t"
+ "lwc1 %[temp15], 260(%[s0]) \n\t"
+ "lwc1 %[temp16], 776(%[v0]) \n\t"
+ "lwc1 %[temp17], 264(%[s0]) \n\t"
+ "lwc1 %[temp18], 780(%[v0]) \n\t"
+ "lwc1 %[temp19], 268(%[s0]) \n\t"
+ "swc1 %[temp0], -16(%[dst]) \n\t"
+ "swc1 %[temp1], -12(%[dst]) \n\t"
+ "swc1 %[temp2], -8(%[dst]) \n\t"
+ "bne %[v0], %[v0_end], 1b \n\t"
+ " swc1 %[temp3], -4(%[dst]) \n\t"
+ "mul.s %[temp0], %[temp4], %[temp5] \n\t"
+ "lwc1 %[temp4], 1024(%[v0]) \n\t"
+ "mul.s %[temp1], %[temp6], %[temp7] \n\t"
+ "lwc1 %[temp5], 512(%[s0]) \n\t"
+ "mul.s %[temp2], %[temp8], %[temp9] \n\t"
+ "lwc1 %[temp6], 1028(%[v0]) \n\t"
+ "mul.s %[temp3], %[temp10], %[temp11] \n\t"
+ "lwc1 %[temp7], 516(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t"
+ "lwc1 %[temp8], 1032(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t"
+ "lwc1 %[temp9], 520(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t"
+ "lwc1 %[temp10], 1036(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t"
+ "lwc1 %[temp11], 524(%[s0]) \n\t"
+ "lwc1 %[temp12], 1792(%[v0]) \n\t"
+ "lwc1 %[temp13], 768(%[s0]) \n\t"
+ "lwc1 %[temp14], 1796(%[v0]) \n\t"
+ "lwc1 %[temp15], 772(%[s0]) \n\t"
+ "lwc1 %[temp16], 1800(%[v0]) \n\t"
+ "lwc1 %[temp17], 776(%[s0]) \n\t"
+ "lwc1 %[temp18], 1804(%[v0]) \n\t"
+ "lwc1 %[temp19], 780(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t"
+ "lwc1 %[temp4], 2048(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t"
+ "lwc1 %[temp5], 1024(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t"
+ "lwc1 %[temp6], 2052(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t"
+ "lwc1 %[temp7], 1028(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t"
+ "lwc1 %[temp8], 2056(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t"
+ "lwc1 %[temp9], 1032(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t"
+ "lwc1 %[temp10], 2060(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t"
+ "lwc1 %[temp11], 1036(%[s0]) \n\t"
+ "lwc1 %[temp12], 2816(%[v0]) \n\t"
+ "lwc1 %[temp13], 1280(%[s0]) \n\t"
+ "lwc1 %[temp14], 2820(%[v0]) \n\t"
+ "lwc1 %[temp15], 1284(%[s0]) \n\t"
+ "lwc1 %[temp16], 2824(%[v0]) \n\t"
+ "lwc1 %[temp17], 1288(%[s0]) \n\t"
+ "lwc1 %[temp18], 2828(%[v0]) \n\t"
+ "lwc1 %[temp19], 1292(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t"
+ "lwc1 %[temp4], 3072(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t"
+ "lwc1 %[temp5], 1536(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t"
+ "lwc1 %[temp6], 3076(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t"
+ "lwc1 %[temp7], 1540(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t"
+ "lwc1 %[temp8], 3080(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t"
+ "lwc1 %[temp9], 1544(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t"
+ "lwc1 %[temp10], 3084(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t"
+ "lwc1 %[temp11], 1548(%[s0]) \n\t"
+ "lwc1 %[temp12], 3840(%[v0]) \n\t"
+ "lwc1 %[temp13], 1792(%[s0]) \n\t"
+ "lwc1 %[temp14], 3844(%[v0]) \n\t"
+ "lwc1 %[temp15], 1796(%[s0]) \n\t"
+ "lwc1 %[temp16], 3848(%[v0]) \n\t"
+ "lwc1 %[temp17], 1800(%[s0]) \n\t"
+ "lwc1 %[temp18], 3852(%[v0]) \n\t"
+ "lwc1 %[temp19], 1804(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t"
+ "lwc1 %[temp4], 4096(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t"
+ "lwc1 %[temp5], 2048(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t"
+ "lwc1 %[temp6], 4100(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t"
+ "lwc1 %[temp7], 2052(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t"
+ "lwc1 %[temp8], 4104(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t"
+ "lwc1 %[temp9], 2056(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t"
+ "lwc1 %[temp10], 4108(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t"
+ "lwc1 %[temp11], 2060(%[s0]) \n\t"
+ "lwc1 %[temp12], 4864(%[v0]) \n\t"
+ "lwc1 %[temp13], 2304(%[s0]) \n\t"
+ "lwc1 %[temp14], 4868(%[v0]) \n\t"
+ "lwc1 %[temp15], 2308(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t"
+ "lwc1 %[temp16], 4872(%[v0]) \n\t"
+ "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t"
+ "lwc1 %[temp17], 2312(%[s0]) \n\t"
+ "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t"
+ "lwc1 %[temp18], 4876(%[v0]) \n\t"
+ "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t"
+ "lwc1 %[temp19], 2316(%[s0]) \n\t"
+ "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t"
+ "addiu %[dst], %[dst], 16 \n\t"
+ "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t"
+ "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t"
+ "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t"
+ "swc1 %[temp0], -16(%[dst]) \n\t"
+ "swc1 %[temp1], -12(%[dst]) \n\t"
+ "swc1 %[temp2], -8(%[dst]) \n\t"
+ "swc1 %[temp3], -4(%[dst]) \n\t"
+ ".set pop \n\t"
+
+ : [dst]"+r"(dst), [v0]"+r"(vv0), [s0]"+r"(s0),
+ [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp8]"=&f"(temp8),
+ [temp9]"=&f"(temp9), [temp10]"=&f"(temp10), [temp11]"=&f"(temp11),
+ [temp12]"=&f"(temp12), [temp13]"=&f"(temp13), [temp14]"=&f"(temp14),
+ [temp15]"=&f"(temp15), [temp16]"=&f"(temp16), [temp17]"=&f"(temp17),
+ [temp18]"=&f"(temp18), [temp19]"=&f"(temp19)
+ : [v0_end]"r"(v0_end)
+ : "memory"
+ );
+ }
+ else
+ {
+ fdsp->vector_fmul (out, v , sbr_qmf_window , 64 >> div);
+ fdsp->vector_fmul_add(out, v + ( 192 >> div), sbr_qmf_window + ( 64 >> div), out , 64 >> div);
+ fdsp->vector_fmul_add(out, v + ( 256 >> div), sbr_qmf_window + (128 >> div), out , 64 >> div);
+ fdsp->vector_fmul_add(out, v + ( 448 >> div), sbr_qmf_window + (192 >> div), out , 64 >> div);
+ fdsp->vector_fmul_add(out, v + ( 512 >> div), sbr_qmf_window + (256 >> div), out , 64 >> div);
+ fdsp->vector_fmul_add(out, v + ( 704 >> div), sbr_qmf_window + (320 >> div), out , 64 >> div);
+ fdsp->vector_fmul_add(out, v + ( 768 >> div), sbr_qmf_window + (384 >> div), out , 64 >> div);
+ fdsp->vector_fmul_add(out, v + ( 960 >> div), sbr_qmf_window + (448 >> div), out , 64 >> div);
+ fdsp->vector_fmul_add(out, v + (1024 >> div), sbr_qmf_window + (512 >> div), out , 64 >> div);
+ fdsp->vector_fmul_add(out, v + (1216 >> div), sbr_qmf_window + (576 >> div), out , 64 >> div);
+ out += 64 >> div;
+ }
+ }
+}
+
+#define sbr_qmf_analysis sbr_qmf_analysis_mips
+#define sbr_qmf_synthesis sbr_qmf_synthesis_mips
+
+#endif /* HAVE_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+
+#endif /* AVCODEC_MIPS_AACSBR_FLOAT_H */
diff --git a/libavcodec/mips/ac3dsp_mips.c b/libavcodec/mips/ac3dsp_mips.c
new file mode 100644
index 0000000..f33c6f1
--- /dev/null
+++ b/libavcodec/mips/ac3dsp_mips.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Authors: Branimir Vasic (bvasic@mips.com)
+ * Nedeljko Babic (nbabic@mips.com)
+ *
+ * Various AC-3 DSP Utils optimized for MIPS
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/ac3dsp.c
+ */
+
+#include "config.h"
+#include "libavcodec/ac3dsp.h"
+#include "libavcodec/ac3.h"
+
+
+#if HAVE_INLINE_ASM
+#if HAVE_MIPSDSPR1
+static void ac3_bit_alloc_calc_bap_mips(int16_t *mask, int16_t *psd,
+ int start, int end,
+ int snr_offset, int floor,
+ const uint8_t *bap_tab, uint8_t *bap)
+{
+ int band, band_end, cond;
+ int m, address1, address2;
+ int16_t *psd1, *psd_end;
+ uint8_t *bap1;
+
+ if (snr_offset == -960) {
+ memset(bap, 0, AC3_MAX_COEFS);
+ return;
+ }
+
+ psd1 = &psd[start];
+ bap1 = &bap[start];
+ band = ff_ac3_bin_to_band_tab[start];
+
+ do {
+ m = (FFMAX(mask[band] - snr_offset - floor, 0) & 0x1FE0) + floor;
+ band_end = ff_ac3_band_start_tab[++band];
+ band_end = FFMIN(band_end, end);
+ psd_end = psd + band_end - 1;
+
+ __asm__ volatile (
+ "slt %[cond], %[psd1], %[psd_end] \n\t"
+ "beqz %[cond], 1f \n\t"
+ "2: \n\t"
+ "lh %[address1], 0(%[psd1]) \n\t"
+ "lh %[address2], 2(%[psd1]) \n\t"
+ "addiu %[psd1], %[psd1], 4 \n\t"
+ "subu %[address1], %[address1], %[m] \n\t"
+ "sra %[address1], %[address1], 5 \n\t"
+ "addiu %[address1], %[address1], -32 \n\t"
+ "shll_s.w %[address1], %[address1], 26 \n\t"
+ "subu %[address2], %[address2], %[m] \n\t"
+ "sra %[address2], %[address2], 5 \n\t"
+ "sra %[address1], %[address1], 26 \n\t"
+ "addiu %[address1], %[address1], 32 \n\t"
+ "lbux %[address1], %[address1](%[bap_tab]) \n\t"
+ "addiu %[address2], %[address2], -32 \n\t"
+ "shll_s.w %[address2], %[address2], 26 \n\t"
+ "sb %[address1], 0(%[bap1]) \n\t"
+ "slt %[cond], %[psd1], %[psd_end] \n\t"
+ "sra %[address2], %[address2], 26 \n\t"
+ "addiu %[address2], %[address2], 32 \n\t"
+ "lbux %[address2], %[address2](%[bap_tab]) \n\t"
+ "sb %[address2], 1(%[bap1]) \n\t"
+ "addiu %[bap1], %[bap1], 2 \n\t"
+ "bnez %[cond], 2b \n\t"
+ "addiu %[psd_end], %[psd_end], 2 \n\t"
+ "slt %[cond], %[psd1], %[psd_end] \n\t"
+ "beqz %[cond], 3f \n\t"
+ "1: \n\t"
+ "lh %[address1], 0(%[psd1]) \n\t"
+ "addiu %[psd1], %[psd1], 2 \n\t"
+ "subu %[address1], %[address1], %[m] \n\t"
+ "sra %[address1], %[address1], 5 \n\t"
+ "addiu %[address1], %[address1], -32 \n\t"
+ "shll_s.w %[address1], %[address1], 26 \n\t"
+ "sra %[address1], %[address1], 26 \n\t"
+ "addiu %[address1], %[address1], 32 \n\t"
+ "lbux %[address1], %[address1](%[bap_tab]) \n\t"
+ "sb %[address1], 0(%[bap1]) \n\t"
+ "addiu %[bap1], %[bap1], 1 \n\t"
+ "3: \n\t"
+
+ : [address1]"=&r"(address1), [address2]"=&r"(address2),
+ [cond]"=&r"(cond), [bap1]"+r"(bap1),
+ [psd1]"+r"(psd1), [psd_end]"+r"(psd_end)
+ : [m]"r"(m), [bap_tab]"r"(bap_tab)
+ : "memory"
+ );
+ } while (end > band_end);
+}
+
+static void ac3_update_bap_counts_mips(uint16_t mant_cnt[16], uint8_t *bap,
+ int len)
+{
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ __asm__ volatile (
+ "andi %[temp3], %[len], 3 \n\t"
+ "addu %[temp2], %[bap], %[len] \n\t"
+ "addu %[temp4], %[bap], %[temp3] \n\t"
+ "beq %[temp2], %[temp4], 4f \n\t"
+ "1: \n\t"
+ "lbu %[temp0], -1(%[temp2]) \n\t"
+ "lbu %[temp5], -2(%[temp2]) \n\t"
+ "lbu %[temp6], -3(%[temp2]) \n\t"
+ "sll %[temp0], %[temp0], 1 \n\t"
+ "addu %[temp0], %[mant_cnt], %[temp0] \n\t"
+ "sll %[temp5], %[temp5], 1 \n\t"
+ "addu %[temp5], %[mant_cnt], %[temp5] \n\t"
+ "lhu %[temp1], 0(%[temp0]) \n\t"
+ "sll %[temp6], %[temp6], 1 \n\t"
+ "addu %[temp6], %[mant_cnt], %[temp6] \n\t"
+ "addiu %[temp1], %[temp1], 1 \n\t"
+ "sh %[temp1], 0(%[temp0]) \n\t"
+ "lhu %[temp1], 0(%[temp5]) \n\t"
+ "lbu %[temp7], -4(%[temp2]) \n\t"
+ "addiu %[temp2], %[temp2], -4 \n\t"
+ "addiu %[temp1], %[temp1], 1 \n\t"
+ "sh %[temp1], 0(%[temp5]) \n\t"
+ "lhu %[temp1], 0(%[temp6]) \n\t"
+ "sll %[temp7], %[temp7], 1 \n\t"
+ "addu %[temp7], %[mant_cnt], %[temp7] \n\t"
+ "addiu %[temp1], %[temp1],1 \n\t"
+ "sh %[temp1], 0(%[temp6]) \n\t"
+ "lhu %[temp1], 0(%[temp7]) \n\t"
+ "addiu %[temp1], %[temp1], 1 \n\t"
+ "sh %[temp1], 0(%[temp7]) \n\t"
+ "bne %[temp2], %[temp4], 1b \n\t"
+ "4: \n\t"
+ "beqz %[temp3], 2f \n\t"
+ "3: \n\t"
+ "addiu %[temp3], %[temp3], -1 \n\t"
+ "lbu %[temp0], -1(%[temp2]) \n\t"
+ "addiu %[temp2], %[temp2], -1 \n\t"
+ "sll %[temp0], %[temp0], 1 \n\t"
+ "addu %[temp0], %[mant_cnt], %[temp0] \n\t"
+ "lhu %[temp1], 0(%[temp0]) \n\t"
+ "addiu %[temp1], %[temp1], 1 \n\t"
+ "sh %[temp1], 0(%[temp0]) \n\t"
+ "bgtz %[temp3], 3b \n\t"
+ "2: \n\t"
+
+ : [temp0] "=&r" (temp0), [temp1] "=&r" (temp1),
+ [temp2] "=&r" (temp2), [temp3] "=&r" (temp3),
+ [temp4] "=&r" (temp4), [temp5] "=&r" (temp5),
+ [temp6] "=&r" (temp6), [temp7] "=&r" (temp7)
+ : [len] "r" (len), [bap] "r" (bap),
+ [mant_cnt] "r" (mant_cnt)
+ : "memory"
+ );
+}
+#endif
+
+#if HAVE_MIPSFPU && HAVE_MIPS32R2
+static void float_to_fixed24_mips(int32_t *dst, const float *src, unsigned int len)
+{
+ const float scale = 1 << 24;
+ float src0, src1, src2, src3, src4, src5, src6, src7;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ do {
+ __asm__ volatile (
+ "lwc1 %[src0], 0(%[src]) \n\t"
+ "lwc1 %[src1], 4(%[src]) \n\t"
+ "lwc1 %[src2], 8(%[src]) \n\t"
+ "lwc1 %[src3], 12(%[src]) \n\t"
+ "lwc1 %[src4], 16(%[src]) \n\t"
+ "lwc1 %[src5], 20(%[src]) \n\t"
+ "lwc1 %[src6], 24(%[src]) \n\t"
+ "lwc1 %[src7], 28(%[src]) \n\t"
+ "mul.s %[src0], %[src0], %[scale] \n\t"
+ "mul.s %[src1], %[src1], %[scale] \n\t"
+ "mul.s %[src2], %[src2], %[scale] \n\t"
+ "mul.s %[src3], %[src3], %[scale] \n\t"
+ "mul.s %[src4], %[src4], %[scale] \n\t"
+ "mul.s %[src5], %[src5], %[scale] \n\t"
+ "mul.s %[src6], %[src6], %[scale] \n\t"
+ "mul.s %[src7], %[src7], %[scale] \n\t"
+ "cvt.w.s %[src0], %[src0] \n\t"
+ "cvt.w.s %[src1], %[src1] \n\t"
+ "cvt.w.s %[src2], %[src2] \n\t"
+ "cvt.w.s %[src3], %[src3] \n\t"
+ "cvt.w.s %[src4], %[src4] \n\t"
+ "cvt.w.s %[src5], %[src5] \n\t"
+ "cvt.w.s %[src6], %[src6] \n\t"
+ "cvt.w.s %[src7], %[src7] \n\t"
+ "mfc1 %[temp0], %[src0] \n\t"
+ "mfc1 %[temp1], %[src1] \n\t"
+ "mfc1 %[temp2], %[src2] \n\t"
+ "mfc1 %[temp3], %[src3] \n\t"
+ "mfc1 %[temp4], %[src4] \n\t"
+ "mfc1 %[temp5], %[src5] \n\t"
+ "mfc1 %[temp6], %[src6] \n\t"
+ "mfc1 %[temp7], %[src7] \n\t"
+ "sw %[temp0], 0(%[dst]) \n\t"
+ "sw %[temp1], 4(%[dst]) \n\t"
+ "sw %[temp2], 8(%[dst]) \n\t"
+ "sw %[temp3], 12(%[dst]) \n\t"
+ "sw %[temp4], 16(%[dst]) \n\t"
+ "sw %[temp5], 20(%[dst]) \n\t"
+ "sw %[temp6], 24(%[dst]) \n\t"
+ "sw %[temp7], 28(%[dst]) \n\t"
+
+ : [dst] "+r" (dst), [src] "+r" (src),
+ [src0] "=&f" (src0), [src1] "=&f" (src1),
+ [src2] "=&f" (src2), [src3] "=&f" (src3),
+ [src4] "=&f" (src4), [src5] "=&f" (src5),
+ [src6] "=&f" (src6), [src7] "=&f" (src7),
+ [temp0] "=r" (temp0), [temp1] "=r" (temp1),
+ [temp2] "=r" (temp2), [temp3] "=r" (temp3),
+ [temp4] "=r" (temp4), [temp5] "=r" (temp5),
+ [temp6] "=r" (temp6), [temp7] "=r" (temp7)
+ : [scale] "f" (scale)
+ : "memory"
+ );
+ src = src + 8;
+ dst = dst + 8;
+ len -= 8;
+ } while (len > 0);
+}
+
+static void ac3_downmix_mips(float **samples, float (*matrix)[2],
+ int out_ch, int in_ch, int len)
+{
+ int i, j, i1, i2, i3;
+ float v0, v1, v2, v3;
+ float v4, v5, v6, v7;
+ float samples0, samples1, samples2, samples3, matrix_j, matrix_j2;
+ float *samples_p,*matrix_p, **samples_x, **samples_end, **samples_sw;
+
+ __asm__ volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "li %[i1], 2 \n\t"
+ "sll %[len], 2 \n\t"
+ "move %[i], $zero \n\t"
+ "sll %[j], %[in_ch], 2 \n\t"
+
+ "bne %[out_ch], %[i1], 3f \n\t" // if (out_ch == 2)
+ " li %[i2], 1 \n\t"
+
+ "2: \n\t" // start of the for loop (for (i = 0; i < len; i+=4))
+ "move %[matrix_p], %[matrix] \n\t"
+ "move %[samples_x], %[samples] \n\t"
+ "mtc1 $zero, %[v0] \n\t"
+ "mtc1 $zero, %[v1] \n\t"
+ "mtc1 $zero, %[v2] \n\t"
+ "mtc1 $zero, %[v3] \n\t"
+ "mtc1 $zero, %[v4] \n\t"
+ "mtc1 $zero, %[v5] \n\t"
+ "mtc1 $zero, %[v6] \n\t"
+ "mtc1 $zero, %[v7] \n\t"
+ "addiu %[i1], %[i], 4 \n\t"
+ "addiu %[i2], %[i], 8 \n\t"
+ "lw %[samples_p], 0(%[samples_x]) \n\t"
+ "addiu %[i3], %[i], 12 \n\t"
+ "addu %[samples_end], %[samples_x], %[j] \n\t"
+ "move %[samples_sw], %[samples_p] \n\t"
+
+ "1: \n\t" // start of the inner for loop (for (j = 0; j < in_ch; j++))
+ "lwc1 %[matrix_j], 0(%[matrix_p]) \n\t"
+ "lwc1 %[matrix_j2], 4(%[matrix_p]) \n\t"
+ "lwxc1 %[samples0], %[i](%[samples_p]) \n\t"
+ "lwxc1 %[samples1], %[i1](%[samples_p]) \n\t"
+ "lwxc1 %[samples2], %[i2](%[samples_p]) \n\t"
+ "lwxc1 %[samples3], %[i3](%[samples_p]) \n\t"
+ "addiu %[matrix_p], 8 \n\t"
+ "addiu %[samples_x], 4 \n\t"
+ "madd.s %[v0], %[v0], %[samples0], %[matrix_j] \n\t"
+ "madd.s %[v1], %[v1], %[samples1], %[matrix_j] \n\t"
+ "madd.s %[v2], %[v2], %[samples2], %[matrix_j] \n\t"
+ "madd.s %[v3], %[v3], %[samples3], %[matrix_j] \n\t"
+ "madd.s %[v4], %[v4], %[samples0], %[matrix_j2]\n\t"
+ "madd.s %[v5], %[v5], %[samples1], %[matrix_j2]\n\t"
+ "madd.s %[v6], %[v6], %[samples2], %[matrix_j2]\n\t"
+ "madd.s %[v7], %[v7], %[samples3], %[matrix_j2]\n\t"
+ "bne %[samples_x], %[samples_end], 1b \n\t"
+ " lw %[samples_p], 0(%[samples_x]) \n\t"
+
+ "lw %[samples_p], 4(%[samples]) \n\t"
+ "swxc1 %[v0], %[i](%[samples_sw]) \n\t"
+ "swxc1 %[v1], %[i1](%[samples_sw]) \n\t"
+ "swxc1 %[v2], %[i2](%[samples_sw]) \n\t"
+ "swxc1 %[v3], %[i3](%[samples_sw]) \n\t"
+ "swxc1 %[v4], %[i](%[samples_p]) \n\t"
+ "addiu %[i], 16 \n\t"
+ "swxc1 %[v5], %[i1](%[samples_p]) \n\t"
+ "swxc1 %[v6], %[i2](%[samples_p]) \n\t"
+ "bne %[i], %[len], 2b \n\t"
+ " swxc1 %[v7], %[i3](%[samples_p]) \n\t"
+
+ "3: \n\t"
+ "bne %[out_ch], %[i2], 6f \n\t" // if (out_ch == 1)
+ " nop \n\t"
+
+ "5: \n\t" // start of the outer for loop (for (i = 0; i < len; i+=4))
+ "move %[matrix_p], %[matrix] \n\t"
+ "move %[samples_x], %[samples] \n\t"
+ "mtc1 $zero, %[v0] \n\t"
+ "mtc1 $zero, %[v1] \n\t"
+ "mtc1 $zero, %[v2] \n\t"
+ "mtc1 $zero, %[v3] \n\t"
+ "addiu %[i1], %[i], 4 \n\t"
+ "addiu %[i2], %[i], 8 \n\t"
+ "lw %[samples_p], 0(%[samples_x]) \n\t"
+ "addiu %[i3], %[i], 12 \n\t"
+ "addu %[samples_end], %[samples_x], %[j] \n\t"
+ "move %[samples_sw], %[samples_p] \n\t"
+
+ "4: \n\t" // start of the inner for loop (for (j = 0; j < in_ch; j++))
+ "lwc1 %[matrix_j], 0(%[matrix_p]) \n\t"
+ "lwxc1 %[samples0], %[i](%[samples_p]) \n\t"
+ "lwxc1 %[samples1], %[i1](%[samples_p]) \n\t"
+ "lwxc1 %[samples2], %[i2](%[samples_p]) \n\t"
+ "lwxc1 %[samples3], %[i3](%[samples_p]) \n\t"
+ "addiu %[matrix_p], 8 \n\t"
+ "addiu %[samples_x], 4 \n\t"
+ "madd.s %[v0], %[v0], %[samples0], %[matrix_j] \n\t"
+ "madd.s %[v1], %[v1], %[samples1], %[matrix_j] \n\t"
+ "madd.s %[v2], %[v2], %[samples2], %[matrix_j] \n\t"
+ "madd.s %[v3], %[v3], %[samples3], %[matrix_j] \n\t"
+ "bne %[samples_x], %[samples_end], 4b \n\t"
+ " lw %[samples_p], 0(%[samples_x]) \n\t"
+
+ "swxc1 %[v0], %[i](%[samples_sw]) \n\t"
+ "addiu %[i], 16 \n\t"
+ "swxc1 %[v1], %[i1](%[samples_sw]) \n\t"
+ "swxc1 %[v2], %[i2](%[samples_sw]) \n\t"
+ "bne %[i], %[len], 5b \n\t"
+ " swxc1 %[v3], %[i3](%[samples_sw]) \n\t"
+ "6: \n\t"
+
+ ".set pop"
+ :[samples_p]"=&r"(samples_p), [matrix_j]"=&f"(matrix_j), [matrix_j2]"=&f"(matrix_j2),
+ [samples0]"=&f"(samples0), [samples1]"=&f"(samples1),
+ [samples2]"=&f"(samples2), [samples3]"=&f"(samples3),
+ [v0]"=&f"(v0), [v1]"=&f"(v1), [v2]"=&f"(v2), [v3]"=&f"(v3),
+ [v4]"=&f"(v4), [v5]"=&f"(v5), [v6]"=&f"(v6), [v7]"=&f"(v7),
+ [samples_x]"=&r"(samples_x), [matrix_p]"=&r"(matrix_p),
+ [samples_end]"=&r"(samples_end), [samples_sw]"=&r"(samples_sw),
+ [i1]"=&r"(i1), [i2]"=&r"(i2), [i3]"=&r"(i3), [i]"=&r"(i),
+ [j]"=&r"(j), [len]"+r"(len)
+ :[samples]"r"(samples), [matrix]"r"(matrix),
+ [in_ch]"r"(in_ch), [out_ch]"r"(out_ch)
+ :"memory"
+ );
+}
+#endif
+#endif /* HAVE_INLINE_ASM */
+
+void ff_ac3dsp_init_mips(AC3DSPContext *c, int bit_exact) {
+#if HAVE_INLINE_ASM
+#if HAVE_MIPSDSPR1
+ c->bit_alloc_calc_bap = ac3_bit_alloc_calc_bap_mips;
+ c->update_bap_counts = ac3_update_bap_counts_mips;
+#endif
+#if HAVE_MIPSFPU && HAVE_MIPS32R2
+ c->float_to_fixed24 = float_to_fixed24_mips;
+ c->downmix = ac3_downmix_mips;
+#endif
+#endif
+
+}
diff --git a/libavcodec/mips/acelp_filters_mips.c b/libavcodec/mips/acelp_filters_mips.c
new file mode 100644
index 0000000..c8d980a
--- /dev/null
+++ b/libavcodec/mips/acelp_filters_mips.c
@@ -0,0 +1,216 @@
+ /*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * various filters for ACELP-based codecs optimized for MIPS
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/acelp_filters.c
+ */
+#include "config.h"
+#include "libavutil/attributes.h"
+#include "libavcodec/acelp_filters.h"
+
+#if HAVE_INLINE_ASM
+static void ff_acelp_interpolatef_mips(float *out, const float *in,
+ const float *filter_coeffs, int precision,
+ int frac_pos, int filter_length, int length)
+{
+ int n, i;
+ int prec = precision * 4;
+ int fc_offset = precision - frac_pos;
+ float in_val_p, in_val_m, fc_val_p, fc_val_m;
+
+ for (n = 0; n < length; n++) {
+ /**
+ * four pointers are defined in order to minimize number of
+ * computations done in inner loop
+ */
+ const float *p_in_p = &in[n];
+ const float *p_in_m = &in[n-1];
+ const float *p_filter_coeffs_p = &filter_coeffs[frac_pos];
+ const float *p_filter_coeffs_m = filter_coeffs + fc_offset;
+ float v = 0;
+
+ for (i = 0; i < filter_length;i++) {
+ __asm__ volatile (
+ "lwc1 %[in_val_p], 0(%[p_in_p]) \n\t"
+ "lwc1 %[fc_val_p], 0(%[p_filter_coeffs_p]) \n\t"
+ "lwc1 %[in_val_m], 0(%[p_in_m]) \n\t"
+ "lwc1 %[fc_val_m], 0(%[p_filter_coeffs_m]) \n\t"
+ "addiu %[p_in_p], %[p_in_p], 4 \n\t"
+ "madd.s %[v],%[v], %[in_val_p],%[fc_val_p] \n\t"
+ "addiu %[p_in_m], %[p_in_m], -4 \n\t"
+ "addu %[p_filter_coeffs_p], %[p_filter_coeffs_p], %[prec] \n\t"
+ "addu %[p_filter_coeffs_m], %[p_filter_coeffs_m], %[prec] \n\t"
+ "madd.s %[v],%[v],%[in_val_m], %[fc_val_m] \n\t"
+
+ : [v] "=&f" (v),[p_in_p] "+r" (p_in_p), [p_in_m] "+r" (p_in_m),
+ [p_filter_coeffs_p] "+r" (p_filter_coeffs_p),
+ [in_val_p] "=&f" (in_val_p), [in_val_m] "=&f" (in_val_m),
+ [fc_val_p] "=&f" (fc_val_p), [fc_val_m] "=&f" (fc_val_m),
+ [p_filter_coeffs_m] "+r" (p_filter_coeffs_m)
+ : [prec] "r" (prec)
+ : "memory"
+ );
+ }
+ out[n] = v;
+ }
+}
+
+static void ff_acelp_apply_order_2_transfer_function_mips(float *out, const float *in,
+ const float zero_coeffs[2],
+ const float pole_coeffs[2],
+ float gain, float mem[2], int n)
+{
+ /**
+ * loop is unrolled eight times
+ */
+
+ __asm__ volatile (
+ "lwc1 $f0, 0(%[mem]) \n\t"
+ "blez %[n], ff_acelp_apply_order_2_transfer_function_end%= \n\t"
+ "lwc1 $f1, 4(%[mem]) \n\t"
+ "lwc1 $f2, 0(%[pole_coeffs]) \n\t"
+ "lwc1 $f3, 4(%[pole_coeffs]) \n\t"
+ "lwc1 $f4, 0(%[zero_coeffs]) \n\t"
+ "lwc1 $f5, 4(%[zero_coeffs]) \n\t"
+
+ "ff_acelp_apply_order_2_transfer_function_madd%=: \n\t"
+
+ "lwc1 $f6, 0(%[in]) \n\t"
+ "mul.s $f9, $f3, $f1 \n\t"
+ "mul.s $f7, $f2, $f0 \n\t"
+ "msub.s $f7, $f7, %[gain], $f6 \n\t"
+ "sub.s $f7, $f7, $f9 \n\t"
+ "madd.s $f8, $f7, $f4, $f0 \n\t"
+ "madd.s $f8, $f8, $f5, $f1 \n\t"
+ "lwc1 $f11, 4(%[in]) \n\t"
+ "mul.s $f12, $f3, $f0 \n\t"
+ "mul.s $f13, $f2, $f7 \n\t"
+ "msub.s $f13, $f13, %[gain], $f11 \n\t"
+ "sub.s $f13, $f13, $f12 \n\t"
+ "madd.s $f14, $f13, $f4, $f7 \n\t"
+ "madd.s $f14, $f14, $f5, $f0 \n\t"
+ "swc1 $f8, 0(%[out]) \n\t"
+ "lwc1 $f6, 8(%[in]) \n\t"
+ "mul.s $f9, $f3, $f7 \n\t"
+ "mul.s $f15, $f2, $f13 \n\t"
+ "msub.s $f15, $f15, %[gain], $f6 \n\t"
+ "sub.s $f15, $f15, $f9 \n\t"
+ "madd.s $f8, $f15, $f4, $f13 \n\t"
+ "madd.s $f8, $f8, $f5, $f7 \n\t"
+ "swc1 $f14, 4(%[out]) \n\t"
+ "lwc1 $f11, 12(%[in]) \n\t"
+ "mul.s $f12, $f3, $f13 \n\t"
+ "mul.s $f16, $f2, $f15 \n\t"
+ "msub.s $f16, $f16, %[gain], $f11 \n\t"
+ "sub.s $f16, $f16, $f12 \n\t"
+ "madd.s $f14, $f16, $f4, $f15 \n\t"
+ "madd.s $f14, $f14, $f5, $f13 \n\t"
+ "swc1 $f8, 8(%[out]) \n\t"
+ "lwc1 $f6, 16(%[in]) \n\t"
+ "mul.s $f9, $f3, $f15 \n\t"
+ "mul.s $f7, $f2, $f16 \n\t"
+ "msub.s $f7, $f7, %[gain], $f6 \n\t"
+ "sub.s $f7, $f7, $f9 \n\t"
+ "madd.s $f8, $f7, $f4, $f16 \n\t"
+ "madd.s $f8, $f8, $f5, $f15 \n\t"
+ "swc1 $f14, 12(%[out]) \n\t"
+ "lwc1 $f11, 20(%[in]) \n\t"
+ "mul.s $f12, $f3, $f16 \n\t"
+ "mul.s $f13, $f2, $f7 \n\t"
+ "msub.s $f13, $f13, %[gain], $f11 \n\t"
+ "sub.s $f13, $f13, $f12 \n\t"
+ "madd.s $f14, $f13, $f4, $f7 \n\t"
+ "madd.s $f14, $f14, $f5, $f16 \n\t"
+ "swc1 $f8, 16(%[out]) \n\t"
+ "lwc1 $f6, 24(%[in]) \n\t"
+ "mul.s $f9, $f3, $f7 \n\t"
+ "mul.s $f15, $f2, $f13 \n\t"
+ "msub.s $f15, $f15, %[gain], $f6 \n\t"
+ "sub.s $f1, $f15, $f9 \n\t"
+ "madd.s $f8, $f1, $f4, $f13 \n\t"
+ "madd.s $f8, $f8, $f5, $f7 \n\t"
+ "swc1 $f14, 20(%[out]) \n\t"
+ "lwc1 $f11, 28(%[in]) \n\t"
+ "mul.s $f12, $f3, $f13 \n\t"
+ "mul.s $f16, $f2, $f1 \n\t"
+ "msub.s $f16, $f16, %[gain], $f11 \n\t"
+ "sub.s $f0, $f16, $f12 \n\t"
+ "madd.s $f14, $f0, $f4, $f1 \n\t"
+ "madd.s $f14, $f14, $f5, $f13 \n\t"
+ "swc1 $f8, 24(%[out]) \n\t"
+ "addiu %[out], 32 \n\t"
+ "addiu %[in], 32 \n\t"
+ "addiu %[n], -8 \n\t"
+ "swc1 $f14, -4(%[out]) \n\t"
+ "bnez %[n], ff_acelp_apply_order_2_transfer_function_madd%= \n\t"
+ "swc1 $f1, 4(%[mem]) \n\t"
+ "swc1 $f0, 0(%[mem]) \n\t"
+
+ "ff_acelp_apply_order_2_transfer_function_end%=: \n\t"
+
+ : [out] "+r" (out),
+ [in] "+r" (in), [gain] "+f" (gain),
+ [n] "+r" (n), [mem] "+r" (mem)
+ : [zero_coeffs] "r" (zero_coeffs),
+ [pole_coeffs] "r" (pole_coeffs)
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5",
+ "$f6", "$f7", "$f8", "$f9", "$f10", "$f11",
+ "$f12", "$f13", "$f14", "$f15", "$f16", "memory"
+ );
+}
+#endif /* HAVE_INLINE_ASM */
+
+void ff_acelp_filter_init_mips(ACELPFContext *c)
+{
+#if HAVE_INLINE_ASM
+ c->acelp_interpolatef = ff_acelp_interpolatef_mips;
+ c->acelp_apply_order_2_transfer_function = ff_acelp_apply_order_2_transfer_function_mips;
+#endif
+}
diff --git a/libavcodec/mips/acelp_vectors_mips.c b/libavcodec/mips/acelp_vectors_mips.c
new file mode 100644
index 0000000..8770df8
--- /dev/null
+++ b/libavcodec/mips/acelp_vectors_mips.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * adaptive and fixed codebook vector operations for ACELP-based codecs
+ * optimized for MIPS
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/acelp_vectors.c
+ */
+#include "config.h"
+#include "libavcodec/acelp_vectors.h"
+
+#if HAVE_INLINE_ASM
+static void ff_weighted_vector_sumf_mips(
+ float *out, const float *in_a, const float *in_b,
+ float weight_coeff_a, float weight_coeff_b, int length)
+{
+ const float *a_end = in_a + length;
+
+ /* loop unrolled two times */
+ __asm__ volatile (
+ "blez %[length], ff_weighted_vector_sumf_end%= \n\t"
+
+ "ff_weighted_vector_sumf_madd%=: \n\t"
+ "lwc1 $f0, 0(%[in_a]) \n\t"
+ "lwc1 $f3, 4(%[in_a]) \n\t"
+ "lwc1 $f1, 0(%[in_b]) \n\t"
+ "lwc1 $f4, 4(%[in_b]) \n\t"
+ "mul.s $f2, %[weight_coeff_a], $f0 \n\t"
+ "mul.s $f5, %[weight_coeff_a], $f3 \n\t"
+ "madd.s $f2, $f2, %[weight_coeff_b], $f1 \n\t"
+ "madd.s $f5, $f5, %[weight_coeff_b], $f4 \n\t"
+ "addiu %[in_a], 8 \n\t"
+ "addiu %[in_b], 8 \n\t"
+ "swc1 $f2, 0(%[out]) \n\t"
+ "swc1 $f5, 4(%[out]) \n\t"
+ "addiu %[out], 8 \n\t"
+ "bne %[in_a], %[a_end], ff_weighted_vector_sumf_madd%= \n\t"
+
+ "ff_weighted_vector_sumf_end%=: \n\t"
+
+ : [out] "+r" (out), [in_a] "+r" (in_a), [in_b] "+r" (in_b)
+ : [weight_coeff_a] "f" (weight_coeff_a),
+ [weight_coeff_b] "f" (weight_coeff_b),
+ [length] "r" (length), [a_end]"r"(a_end)
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "memory"
+ );
+}
+#endif /* HAVE_INLINE_ASM */
+
+void ff_acelp_vectors_init_mips(ACELPVContext *c)
+{
+#if HAVE_INLINE_ASM
+ c->weighted_vector_sumf = ff_weighted_vector_sumf_mips;
+#endif
+}
diff --git a/libavcodec/mips/amrwbdec_mips.c b/libavcodec/mips/amrwbdec_mips.c
new file mode 100644
index 0000000..1d6ed2d
--- /dev/null
+++ b/libavcodec/mips/amrwbdec_mips.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/amrwbdec.c
+ */
+#include "libavutil/avutil.h"
+#include "libavcodec/amrwbdata.h"
+#include "amrwbdec_mips.h"
+
+#if HAVE_INLINE_ASM
+void hb_fir_filter_mips(float *out, const float fir_coef[HB_FIR_SIZE + 1],
+ float mem[HB_FIR_SIZE], const float *in)
+{
+ int i;
+ float data[AMRWB_SFR_SIZE_16k + HB_FIR_SIZE]; // past and current samples
+
+ memcpy(data, mem, HB_FIR_SIZE * sizeof(float));
+ memcpy(data + HB_FIR_SIZE, in, AMRWB_SFR_SIZE_16k * sizeof(float));
+
+ for (i = 0; i < AMRWB_SFR_SIZE_16k; i++) {
+ float output;
+ float * p_data = (data+i);
+
+ /**
+ * inner loop is entirely unrolled and instructions are scheduled
+ * to minimize pipeline stall
+ */
+ __asm__ volatile(
+ "mtc1 $zero, %[output] \n\t"
+ "lwc1 $f0, 0(%[p_data]) \n\t"
+ "lwc1 $f1, 0(%[fir_coef]) \n\t"
+ "lwc1 $f2, 4(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f3, 4(%[fir_coef]) \n\t"
+ "lwc1 $f4, 8(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+ "lwc1 $f5, 8(%[fir_coef]) \n\t"
+
+ "lwc1 $f0, 12(%[p_data]) \n\t"
+ "lwc1 $f1, 12(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f2, 16(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f3, 16(%[fir_coef]) \n\t"
+ "lwc1 $f4, 20(%[p_data]) \n\t"
+ "lwc1 $f5, 20(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+
+ "lwc1 $f0, 24(%[p_data]) \n\t"
+ "lwc1 $f1, 24(%[fir_coef]) \n\t"
+ "lwc1 $f2, 28(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f3, 28(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f4, 32(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+ "lwc1 $f5, 32(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+
+ "lwc1 $f0, 36(%[p_data]) \n\t"
+ "lwc1 $f1, 36(%[fir_coef]) \n\t"
+ "lwc1 $f2, 40(%[p_data]) \n\t"
+ "lwc1 $f3, 40(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f4, 44(%[p_data]) \n\t"
+ "lwc1 $f5, 44(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+
+ "lwc1 $f0, 48(%[p_data]) \n\t"
+ "lwc1 $f1, 48(%[fir_coef]) \n\t"
+ "lwc1 $f2, 52(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f3, 52(%[fir_coef]) \n\t"
+ "lwc1 $f4, 56(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f5, 56(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+
+ "lwc1 $f0, 60(%[p_data]) \n\t"
+ "lwc1 $f1, 60(%[fir_coef]) \n\t"
+ "lwc1 $f2, 64(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f3, 64(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f4, 68(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+ "lwc1 $f5, 68(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+
+ "lwc1 $f0, 72(%[p_data]) \n\t"
+ "lwc1 $f1, 72(%[fir_coef]) \n\t"
+ "lwc1 $f2, 76(%[p_data]) \n\t"
+ "lwc1 $f3, 76(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f4, 80(%[p_data]) \n\t"
+ "lwc1 $f5, 80(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+
+ "lwc1 $f0, 84(%[p_data]) \n\t"
+ "lwc1 $f1, 84(%[fir_coef]) \n\t"
+ "lwc1 $f2, 88(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f3, 88(%[fir_coef]) \n\t"
+ "lwc1 $f4, 92(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f5, 92(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+
+ "lwc1 $f0, 96(%[p_data]) \n\t"
+ "lwc1 $f1, 96(%[fir_coef]) \n\t"
+ "lwc1 $f2, 100(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f3, 100(%[fir_coef]) \n\t"
+ "lwc1 $f4, 104(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f5, 104(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+
+ "lwc1 $f0, 108(%[p_data]) \n\t"
+ "lwc1 $f1, 108(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f2, 112(%[p_data]) \n\t"
+ "lwc1 $f3, 112(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f4, 116(%[p_data]) \n\t"
+ "lwc1 $f5, 116(%[fir_coef]) \n\t"
+ "lwc1 $f0, 120(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+ "lwc1 $f1, 120(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+
+ : [output]"=&f"(output)
+ : [fir_coef]"r"(fir_coef), [p_data]"r"(p_data)
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "memory"
+ );
+ out[i] = output;
+ }
+ memcpy(mem, data + AMRWB_SFR_SIZE_16k, HB_FIR_SIZE * sizeof(float));
+}
+#endif /* HAVE_INLINE_ASM */
diff --git a/libavcodec/mips/amrwbdec_mips.h b/libavcodec/mips/amrwbdec_mips.h
new file mode 100644
index 0000000..a469918
--- /dev/null
+++ b/libavcodec/mips/amrwbdec_mips.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/amrwbdec.c
+ */
+#ifndef AVCODEC_AMRWBDEC_MIPS_H
+#define AVCODEC_AMRWBDEC_MIPS_H
+#include "config.h"
+
+#if HAVE_MIPSFPU && HAVE_INLINE_ASM
+void hb_fir_filter_mips(float *out, const float fir_coef[],
+ float mem[], const float *in);
+#define hb_fir_filter hb_fir_filter_mips
+#endif
+
+#endif /* AVCODEC_AMRWBDEC_MIPS_H */
diff --git a/libavcodec/mips/celp_filters_mips.c b/libavcodec/mips/celp_filters_mips.c
new file mode 100644
index 0000000..ef5b07b
--- /dev/null
+++ b/libavcodec/mips/celp_filters_mips.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * various filters for CELP-based codecs optimized for MIPS
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/celp_filters.c
+ */
+#include "config.h"
+#include "libavutil/attributes.h"
+#include "libavutil/common.h"
+#include "libavcodec/celp_filters.h"
+
+#if HAVE_INLINE_ASM
+static void ff_celp_lp_synthesis_filterf_mips(float *out,
+ const float *filter_coeffs,
+ const float* in, int buffer_length,
+ int filter_length)
+{
+ int i,n;
+
+ float out0, out1, out2, out3;
+ float old_out0, old_out1, old_out2, old_out3;
+ float a,b,c;
+ const float *p_filter_coeffs;
+ float *p_out;
+
+ a = filter_coeffs[0];
+ b = filter_coeffs[1];
+ c = filter_coeffs[2];
+ b -= filter_coeffs[0] * filter_coeffs[0];
+ c -= filter_coeffs[1] * filter_coeffs[0];
+ c -= filter_coeffs[0] * b;
+
+ old_out0 = out[-4];
+ old_out1 = out[-3];
+ old_out2 = out[-2];
+ old_out3 = out[-1];
+ for (n = 0; n <= buffer_length - 4; n+=4) {
+ p_filter_coeffs = filter_coeffs;
+ p_out = out;
+
+ out0 = in[0];
+ out1 = in[1];
+ out2 = in[2];
+ out3 = in[3];
+
+ __asm__ volatile(
+ "lwc1 $f2, 8(%[filter_coeffs]) \n\t"
+ "lwc1 $f1, 4(%[filter_coeffs]) \n\t"
+ "lwc1 $f0, 0(%[filter_coeffs]) \n\t"
+ "nmsub.s %[out0], %[out0], $f2, %[old_out1] \n\t"
+ "nmsub.s %[out1], %[out1], $f2, %[old_out2] \n\t"
+ "nmsub.s %[out2], %[out2], $f2, %[old_out3] \n\t"
+ "lwc1 $f3, 12(%[filter_coeffs]) \n\t"
+ "nmsub.s %[out0], %[out0], $f1, %[old_out2] \n\t"
+ "nmsub.s %[out1], %[out1], $f1, %[old_out3] \n\t"
+ "nmsub.s %[out2], %[out2], $f3, %[old_out2] \n\t"
+ "nmsub.s %[out0], %[out0], $f0, %[old_out3] \n\t"
+ "nmsub.s %[out3], %[out3], $f3, %[old_out3] \n\t"
+ "nmsub.s %[out1], %[out1], $f3, %[old_out1] \n\t"
+ "nmsub.s %[out0], %[out0], $f3, %[old_out0] \n\t"
+
+ : [out0]"+f"(out0), [out1]"+f"(out1),
+ [out2]"+f"(out2), [out3]"+f"(out3)
+ : [old_out0]"f"(old_out0), [old_out1]"f"(old_out1),
+ [old_out2]"f"(old_out2), [old_out3]"f"(old_out3),
+ [filter_coeffs]"r"(filter_coeffs)
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "memory"
+ );
+
+ for (i = 5; i <= filter_length; i += 2) {
+ __asm__ volatile(
+ "lwc1 %[old_out3], -20(%[p_out]) \n\t"
+ "lwc1 $f5, 16(%[p_filter_coeffs]) \n\t"
+ "addiu %[p_out], -8 \n\t"
+ "addiu %[p_filter_coeffs], 8 \n\t"
+ "nmsub.s %[out1], %[out1], $f5, %[old_out0] \n\t"
+ "nmsub.s %[out3], %[out3], $f5, %[old_out2] \n\t"
+ "lwc1 $f4, 12(%[p_filter_coeffs]) \n\t"
+ "lwc1 %[old_out2], -16(%[p_out]) \n\t"
+ "nmsub.s %[out0], %[out0], $f5, %[old_out3] \n\t"
+ "nmsub.s %[out2], %[out2], $f5, %[old_out1] \n\t"
+ "nmsub.s %[out1], %[out1], $f4, %[old_out3] \n\t"
+ "nmsub.s %[out3], %[out3], $f4, %[old_out1] \n\t"
+ "mov.s %[old_out1], %[old_out3] \n\t"
+ "nmsub.s %[out0], %[out0], $f4, %[old_out2] \n\t"
+ "nmsub.s %[out2], %[out2], $f4, %[old_out0] \n\t"
+
+ : [out0]"+f"(out0), [out1]"+f"(out1),
+ [out2]"+f"(out2), [out3]"+f"(out3), [old_out0]"+f"(old_out0),
+ [old_out1]"+f"(old_out1), [old_out2]"+f"(old_out2),
+ [old_out3]"+f"(old_out3),[p_filter_coeffs]"+r"(p_filter_coeffs),
+ [p_out]"+r"(p_out)
+ :
+ : "$f4", "$f5", "memory"
+ );
+ FFSWAP(float, old_out0, old_out2);
+ }
+
+ __asm__ volatile(
+ "nmsub.s %[out3], %[out3], %[a], %[out2] \n\t"
+ "nmsub.s %[out2], %[out2], %[a], %[out1] \n\t"
+ "nmsub.s %[out3], %[out3], %[b], %[out1] \n\t"
+ "nmsub.s %[out1], %[out1], %[a], %[out0] \n\t"
+ "nmsub.s %[out2], %[out2], %[b], %[out0] \n\t"
+ "nmsub.s %[out3], %[out3], %[c], %[out0] \n\t"
+
+ : [out0]"+f"(out0), [out1]"+f"(out1),
+ [out2]"+f"(out2), [out3]"+f"(out3)
+ : [a]"f"(a), [b]"f"(b), [c]"f"(c)
+ );
+
+ out[0] = out0;
+ out[1] = out1;
+ out[2] = out2;
+ out[3] = out3;
+
+ old_out0 = out0;
+ old_out1 = out1;
+ old_out2 = out2;
+ old_out3 = out3;
+
+ out += 4;
+ in += 4;
+ }
+
+ out -= n;
+ in -= n;
+ for (; n < buffer_length; n++) {
+ float out_val, out_val_i, fc_val;
+ p_filter_coeffs = filter_coeffs;
+ p_out = &out[n];
+ out_val = in[n];
+ for (i = 1; i <= filter_length; i++) {
+ __asm__ volatile(
+ "lwc1 %[fc_val], 0(%[p_filter_coeffs]) \n\t"
+ "lwc1 %[out_val_i], -4(%[p_out]) \n\t"
+ "addiu %[p_filter_coeffs], 4 \n\t"
+ "addiu %[p_out], -4 \n\t"
+ "nmsub.s %[out_val], %[out_val], %[fc_val], %[out_val_i] \n\t"
+
+ : [fc_val]"=&f"(fc_val), [out_val]"+f"(out_val),
+ [out_val_i]"=&f"(out_val_i), [p_out]"+r"(p_out),
+ [p_filter_coeffs]"+r"(p_filter_coeffs)
+ :
+ : "memory"
+ );
+ }
+ out[n] = out_val;
+ }
+}
+
+static void ff_celp_lp_zero_synthesis_filterf_mips(float *out,
+ const float *filter_coeffs,
+ const float *in, int buffer_length,
+ int filter_length)
+{
+ int i,n;
+ float sum_out8, sum_out7, sum_out6, sum_out5, sum_out4, fc_val;
+ float sum_out3, sum_out2, sum_out1;
+ const float *p_filter_coeffs, *p_in;
+
+ for (n = 0; n < buffer_length; n+=8) {
+ p_in = &in[n];
+ p_filter_coeffs = filter_coeffs;
+ sum_out8 = in[n+7];
+ sum_out7 = in[n+6];
+ sum_out6 = in[n+5];
+ sum_out5 = in[n+4];
+ sum_out4 = in[n+3];
+ sum_out3 = in[n+2];
+ sum_out2 = in[n+1];
+ sum_out1 = in[n];
+ i = filter_length;
+
+ /* i is always greater than 0
+ * outer loop is unrolled eight times so there is less memory access
+ * inner loop is unrolled two times
+ */
+ __asm__ volatile(
+ "filt_lp_inner%=: \n\t"
+ "lwc1 %[fc_val], 0(%[p_filter_coeffs]) \n\t"
+ "lwc1 $f7, 6*4(%[p_in]) \n\t"
+ "lwc1 $f6, 5*4(%[p_in]) \n\t"
+ "lwc1 $f5, 4*4(%[p_in]) \n\t"
+ "lwc1 $f4, 3*4(%[p_in]) \n\t"
+ "lwc1 $f3, 2*4(%[p_in]) \n\t"
+ "lwc1 $f2, 4(%[p_in]) \n\t"
+ "lwc1 $f1, 0(%[p_in]) \n\t"
+ "lwc1 $f0, -4(%[p_in]) \n\t"
+ "addiu %[i], -2 \n\t"
+ "madd.s %[sum_out8], %[sum_out8], %[fc_val], $f7 \n\t"
+ "madd.s %[sum_out7], %[sum_out7], %[fc_val], $f6 \n\t"
+ "madd.s %[sum_out6], %[sum_out6], %[fc_val], $f5 \n\t"
+ "madd.s %[sum_out5], %[sum_out5], %[fc_val], $f4 \n\t"
+ "madd.s %[sum_out4], %[sum_out4], %[fc_val], $f3 \n\t"
+ "madd.s %[sum_out3], %[sum_out3], %[fc_val], $f2 \n\t"
+ "madd.s %[sum_out2], %[sum_out2], %[fc_val], $f1 \n\t"
+ "madd.s %[sum_out1], %[sum_out1], %[fc_val], $f0 \n\t"
+ "lwc1 %[fc_val], 4(%[p_filter_coeffs]) \n\t"
+ "lwc1 $f7, -8(%[p_in]) \n\t"
+ "addiu %[p_filter_coeffs], 8 \n\t"
+ "addiu %[p_in], -8 \n\t"
+ "madd.s %[sum_out8], %[sum_out8], %[fc_val], $f6 \n\t"
+ "madd.s %[sum_out7], %[sum_out7], %[fc_val], $f5 \n\t"
+ "madd.s %[sum_out6], %[sum_out6], %[fc_val], $f4 \n\t"
+ "madd.s %[sum_out5], %[sum_out5], %[fc_val], $f3 \n\t"
+ "madd.s %[sum_out4], %[sum_out4], %[fc_val], $f2 \n\t"
+ "madd.s %[sum_out3], %[sum_out3], %[fc_val], $f1 \n\t"
+ "madd.s %[sum_out2], %[sum_out2], %[fc_val], $f0 \n\t"
+ "madd.s %[sum_out1], %[sum_out1], %[fc_val], $f7 \n\t"
+ "bgtz %[i], filt_lp_inner%= \n\t"
+
+ : [sum_out8]"+f"(sum_out8), [sum_out7]"+f"(sum_out7),
+ [sum_out6]"+f"(sum_out6), [sum_out5]"+f"(sum_out5),
+ [sum_out4]"+f"(sum_out4), [sum_out3]"+f"(sum_out3),
+ [sum_out2]"+f"(sum_out2), [sum_out1]"+f"(sum_out1),
+ [fc_val]"=&f"(fc_val), [p_filter_coeffs]"+r"(p_filter_coeffs),
+ [p_in]"+r"(p_in), [i]"+r"(i)
+ :
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "memory"
+ );
+
+ out[n+7] = sum_out8;
+ out[n+6] = sum_out7;
+ out[n+5] = sum_out6;
+ out[n+4] = sum_out5;
+ out[n+3] = sum_out4;
+ out[n+2] = sum_out3;
+ out[n+1] = sum_out2;
+ out[n] = sum_out1;
+ }
+}
+#endif /* HAVE_INLINE_ASM */
+
+void ff_celp_filter_init_mips(CELPFContext *c)
+{
+#if HAVE_INLINE_ASM
+ c->celp_lp_synthesis_filterf = ff_celp_lp_synthesis_filterf_mips;
+ c->celp_lp_zero_synthesis_filterf = ff_celp_lp_zero_synthesis_filterf_mips;
+#endif
+}
diff --git a/libavcodec/mips/celp_math_mips.c b/libavcodec/mips/celp_math_mips.c
new file mode 100644
index 0000000..d7ccc23
--- /dev/null
+++ b/libavcodec/mips/celp_math_mips.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * Math operations optimized for MIPS
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/celp_math.c
+ */
+#include "config.h"
+#include "libavcodec/celp_math.h"
+
+#if HAVE_INLINE_ASM
+static float ff_dot_productf_mips(const float* a, const float* b,
+ int length)
+{
+ float sum;
+ const float* a_end = a + length;
+
+ __asm__ volatile (
+ "mtc1 $zero, %[sum] \n\t"
+ "blez %[length], ff_dot_productf_end%= \n\t"
+ "ff_dot_productf_madd%=: \n\t"
+ "lwc1 $f2, 0(%[a]) \n\t"
+ "lwc1 $f1, 0(%[b]) \n\t"
+ "addiu %[a], %[a], 4 \n\t"
+ "addiu %[b], %[b], 4 \n\t"
+ "madd.s %[sum], %[sum], $f1, $f2 \n\t"
+ "bne %[a], %[a_end], ff_dot_productf_madd%= \n\t"
+ "ff_dot_productf_end%=: \n\t"
+
+ : [sum] "=&f" (sum), [a] "+r" (a), [b] "+r" (b)
+ : [a_end]"r"(a_end), [length] "r" (length)
+ : "$f1", "$f2", "memory"
+ );
+ return sum;
+}
+#endif /* HAVE_INLINE_ASM */
+
+void ff_celp_math_init_mips(CELPMContext *c)
+{
+#if HAVE_INLINE_ASM
+ c->dot_productf = ff_dot_productf_mips;
+#endif
+}
diff --git a/libavcodec/mips/compute_antialias_fixed.h b/libavcodec/mips/compute_antialias_fixed.h
new file mode 100644
index 0000000..a967f67
--- /dev/null
+++ b/libavcodec/mips/compute_antialias_fixed.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Bojan Zivkovic (bojan@mips.com)
+ *
+ * Compute antialias function optimised for MIPS fixed-point architecture
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/mpegaudiodec.c
+ */
+
+#ifndef AVCODEC_MIPS_COMPUTE_ANTIALIAS_FIXED_H
+#define AVCODEC_MIPS_COMPUTE_ANTIALIAS_FIXED_H
+
+#if HAVE_INLINE_ASM
+static void compute_antialias_mips_fixed(MPADecodeContext *s,
+ GranuleDef *g)
+{
+ int32_t *ptr, *csa;
+ int n, i;
+ int MAX_lo = 0xffffffff;
+
+ /* we antialias only "long" bands */
+ if (g->block_type == 2) {
+ if (!g->switch_point)
+ return;
+ /* XXX: check this for 8000Hz case */
+ n = 1;
+ } else {
+ n = SBLIMIT - 1;
+ }
+
+
+ ptr = g->sb_hybrid + 18;
+
+ for(i = n;i > 0;i--) {
+ int tmp0, tmp1, tmp2, tmp00, tmp11;
+ int temp_reg1, temp_reg2, temp_reg3, temp_reg4, temp_reg5, temp_reg6;
+ csa = &csa_table[0][0];
+
+ /**
+ * instructions are scheduled to minimize pipeline stall.
+ */
+ __asm__ volatile (
+ "lw %[tmp0], -1*4(%[ptr]) \n\t"
+ "lw %[tmp1], 0*4(%[ptr]) \n\t"
+ "lw %[temp_reg1], 0*4(%[csa]) \n\t"
+ "lw %[temp_reg2], 2*4(%[csa]) \n\t"
+ "add %[tmp2], %[tmp0], %[tmp1] \n\t"
+ "lw %[temp_reg3], 3*4(%[csa]) \n\t"
+ "mult $ac0, %[tmp2], %[temp_reg1] \n\t"
+ "mult $ac1, %[tmp2], %[temp_reg1] \n\t"
+ "lw %[tmp00], -2*4(%[ptr]) \n\t"
+ "lw %[tmp11], 1*4(%[ptr]) \n\t"
+ "lw %[temp_reg4], 4*4(%[csa]) \n\t"
+ "mtlo %[MAX_lo], $ac0 \n\t"
+ "mtlo $zero, $ac1 \n\t"
+ "msub $ac0, %[tmp1], %[temp_reg2] \n\t"
+ "madd $ac1, %[tmp0], %[temp_reg3] \n\t"
+ "add %[tmp2], %[tmp00], %[tmp11] \n\t"
+ "lw %[temp_reg5], 6*4(%[csa]) \n\t"
+ "mult $ac2, %[tmp2], %[temp_reg4] \n\t"
+ "mult $ac3, %[tmp2], %[temp_reg4] \n\t"
+ "mfhi %[temp_reg1], $ac0 \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "lw %[temp_reg6], 7*4(%[csa]) \n\t"
+ "mtlo %[MAX_lo], $ac2 \n\t"
+ "msub $ac2, %[tmp11], %[temp_reg5] \n\t"
+ "mtlo $zero, $ac3 \n\t"
+ "madd $ac3, %[tmp00], %[temp_reg6] \n\t"
+ "sll %[temp_reg1], %[temp_reg1], 2 \n\t"
+ "sw %[temp_reg1], -1*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg4], $ac2 \n\t"
+ "sll %[temp_reg2], %[temp_reg2], 2 \n\t"
+ "mfhi %[temp_reg5], $ac3 \n\t"
+ "sw %[temp_reg2], 0*4(%[ptr]) \n\t"
+ "lw %[tmp0], -3*4(%[ptr]) \n\t"
+ "lw %[tmp1], 2*4(%[ptr]) \n\t"
+ "lw %[temp_reg1], 8*4(%[csa]) \n\t"
+ "sll %[temp_reg4], %[temp_reg4], 2 \n\t"
+ "add %[tmp2], %[tmp0], %[tmp1] \n\t"
+ "sll %[temp_reg5], %[temp_reg5], 2 \n\t"
+ "mult $ac0, %[tmp2], %[temp_reg1] \n\t"
+ "mult $ac1, %[tmp2], %[temp_reg1] \n\t"
+ "sw %[temp_reg4], -2*4(%[ptr]) \n\t"
+ "sw %[temp_reg5], 1*4(%[ptr]) \n\t"
+ "lw %[temp_reg2], 10*4(%[csa]) \n\t"
+ "mtlo %[MAX_lo], $ac0 \n\t"
+ "lw %[temp_reg3], 11*4(%[csa]) \n\t"
+ "msub $ac0, %[tmp1], %[temp_reg2] \n\t"
+ "mtlo $zero, $ac1 \n\t"
+ "madd $ac1, %[tmp0], %[temp_reg3] \n\t"
+ "lw %[tmp00], -4*4(%[ptr]) \n\t"
+ "lw %[tmp11], 3*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg1], $ac0 \n\t"
+ "lw %[temp_reg4], 12*4(%[csa]) \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "add %[tmp2], %[tmp00], %[tmp11] \n\t"
+ "mult $ac2, %[tmp2], %[temp_reg4] \n\t"
+ "mult $ac3, %[tmp2], %[temp_reg4] \n\t"
+ "lw %[temp_reg5], 14*4(%[csa]) \n\t"
+ "lw %[temp_reg6], 15*4(%[csa]) \n\t"
+ "sll %[temp_reg1], %[temp_reg1], 2 \n\t"
+ "mtlo %[MAX_lo], $ac2 \n\t"
+ "msub $ac2, %[tmp11], %[temp_reg5] \n\t"
+ "mtlo $zero, $ac3 \n\t"
+ "madd $ac3, %[tmp00], %[temp_reg6] \n\t"
+ "sll %[temp_reg2], %[temp_reg2], 2 \n\t"
+ "sw %[temp_reg1], -3*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg4], $ac2 \n\t"
+ "sw %[temp_reg2], 2*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg5], $ac3 \n\t"
+ "lw %[tmp0], -5*4(%[ptr]) \n\t"
+ "lw %[tmp1], 4*4(%[ptr]) \n\t"
+ "lw %[temp_reg1], 16*4(%[csa]) \n\t"
+ "lw %[temp_reg2], 18*4(%[csa]) \n\t"
+ "add %[tmp2], %[tmp0], %[tmp1] \n\t"
+ "lw %[temp_reg3], 19*4(%[csa]) \n\t"
+ "mult $ac0, %[tmp2], %[temp_reg1] \n\t"
+ "mult $ac1, %[tmp2], %[temp_reg1] \n\t"
+ "sll %[temp_reg4], %[temp_reg4], 2 \n\t"
+ "sll %[temp_reg5], %[temp_reg5], 2 \n\t"
+ "sw %[temp_reg4], -4*4(%[ptr]) \n\t"
+ "mtlo %[MAX_lo], $ac0 \n\t"
+ "msub $ac0, %[tmp1], %[temp_reg2] \n\t"
+ "mtlo $zero, $ac1 \n\t"
+ "madd $ac1, %[tmp0], %[temp_reg3] \n\t"
+ "sw %[temp_reg5], 3*4(%[ptr]) \n\t"
+ "lw %[tmp00], -6*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg1], $ac0 \n\t"
+ "lw %[tmp11], 5*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "lw %[temp_reg4], 20*4(%[csa]) \n\t"
+ "add %[tmp2], %[tmp00], %[tmp11] \n\t"
+ "lw %[temp_reg5], 22*4(%[csa]) \n\t"
+ "mult $ac2, %[tmp2], %[temp_reg4] \n\t"
+ "mult $ac3, %[tmp2], %[temp_reg4] \n\t"
+ "lw %[temp_reg6], 23*4(%[csa]) \n\t"
+ "sll %[temp_reg1], %[temp_reg1], 2 \n\t"
+ "sll %[temp_reg2], %[temp_reg2], 2 \n\t"
+ "mtlo %[MAX_lo], $ac2 \n\t"
+ "msub $ac2, %[tmp11], %[temp_reg5] \n\t"
+ "mtlo $zero, $ac3 \n\t"
+ "madd $ac3, %[tmp00], %[temp_reg6] \n\t"
+ "sw %[temp_reg1], -5*4(%[ptr]) \n\t"
+ "sw %[temp_reg2], 4*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg4], $ac2 \n\t"
+ "lw %[tmp0], -7*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg5], $ac3 \n\t"
+ "lw %[tmp1], 6*4(%[ptr]) \n\t"
+ "lw %[temp_reg1], 24*4(%[csa]) \n\t"
+ "lw %[temp_reg2], 26*4(%[csa]) \n\t"
+ "add %[tmp2], %[tmp0], %[tmp1] \n\t"
+ "lw %[temp_reg3], 27*4(%[csa]) \n\t"
+ "mult $ac0, %[tmp2], %[temp_reg1] \n\t"
+ "mult $ac1, %[tmp2], %[temp_reg1] \n\t"
+ "sll %[temp_reg4], %[temp_reg4], 2 \n\t"
+ "sll %[temp_reg5], %[temp_reg5], 2 \n\t"
+ "sw %[temp_reg4], -6*4(%[ptr]) \n\t"
+ "mtlo %[MAX_lo], $ac0 \n\t"
+ "msub $ac0, %[tmp1], %[temp_reg2] \n\t"
+ "mtlo $zero, $ac1 \n\t"
+ "madd $ac1, %[tmp0], %[temp_reg3] \n\t"
+ "sw %[temp_reg5], 5*4(%[ptr]) \n\t"
+ "lw %[tmp00], -8*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg1], $ac0 \n\t"
+ "lw %[tmp11], 7*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "lw %[temp_reg4], 28*4(%[csa]) \n\t"
+ "add %[tmp2], %[tmp00], %[tmp11] \n\t"
+ "lw %[temp_reg5], 30*4(%[csa]) \n\t"
+ "mult $ac2, %[tmp2], %[temp_reg4] \n\t"
+ "mult $ac3, %[tmp2], %[temp_reg4] \n\t"
+ "lw %[temp_reg6], 31*4(%[csa]) \n\t"
+ "sll %[temp_reg1], %[temp_reg1], 2 \n\t"
+ "sll %[temp_reg2], %[temp_reg2], 2 \n\t"
+ "mtlo %[MAX_lo], $ac2 \n\t"
+ "msub $ac2, %[tmp11], %[temp_reg5] \n\t"
+ "mtlo $zero, $ac3 \n\t"
+ "madd $ac3, %[tmp00], %[temp_reg6] \n\t"
+ "sw %[temp_reg1], -7*4(%[ptr]) \n\t"
+ "sw %[temp_reg2], 6*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg4], $ac2 \n\t"
+ "mfhi %[temp_reg5], $ac3 \n\t"
+ "sll %[temp_reg4], %[temp_reg4], 2 \n\t"
+ "sll %[temp_reg5], %[temp_reg5], 2 \n\t"
+ "sw %[temp_reg4], -8*4(%[ptr]) \n\t"
+ "sw %[temp_reg5], 7*4(%[ptr]) \n\t"
+
+ : [tmp0] "=&r" (tmp0), [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2),
+ [tmp00] "=&r" (tmp00), [tmp11] "=&r" (tmp11),
+ [temp_reg1] "=&r" (temp_reg1), [temp_reg2] "=&r" (temp_reg2),
+ [temp_reg3] "=&r" (temp_reg3), [temp_reg4] "=&r" (temp_reg4),
+ [temp_reg5] "=&r" (temp_reg5), [temp_reg6] "=&r" (temp_reg6)
+ : [csa] "r" (csa), [ptr] "r" (ptr),
+ [MAX_lo] "r" (MAX_lo)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo",
+ "$ac3hi", "$ac3lo"
+ );
+
+ ptr += 18;
+ }
+}
+#define compute_antialias compute_antialias_mips_fixed
+#endif /* HAVE_INLINE_ASM */
+
+#endif /* AVCODEC_MIPS_COMPUTE_ANTIALIAS_FIXED_H */
diff --git a/libavcodec/mips/compute_antialias_float.h b/libavcodec/mips/compute_antialias_float.h
new file mode 100644
index 0000000..0f6f03f
--- /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_init_table.c b/libavcodec/mips/fft_init_table.c
new file mode 100644
index 0000000..9c2e998
--- /dev/null
+++ b/libavcodec/mips/fft_init_table.c
@@ -0,0 +1,67 @@
+/*
+ * 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)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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 MIPS FFT
+ */
+#include "fft_table.h"
+
+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/mips/fft_mips.c b/libavcodec/mips/fft_mips.c
new file mode 100644
index 0000000..ae4ed30
--- /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 "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/fft_table.h b/libavcodec/mips/fft_table.h
new file mode 100644
index 0000000..dd52eaf
--- /dev/null
+++ b/libavcodec/mips/fft_table.h
@@ -0,0 +1,63 @@
+/*
+ * 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)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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 LUT table for MIPS FFT
+ */
+#ifndef AVCODEC_MIPS_FFT_TABLE_H
+#define AVCODEC_MIPS_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 uint16_t fft_offsets_lut[];
+void ff_fft_lut_init(uint16_t *table, int off, int size, int *index);
+
+#endif /* AVCODEC_MIPS_FFT_TABLE_H */
diff --git a/libavcodec/mips/fmtconvert_mips.c b/libavcodec/mips/fmtconvert_mips.c
new file mode 100644
index 0000000..8a0265f
--- /dev/null
+++ b/libavcodec/mips/fmtconvert_mips.c
@@ -0,0 +1,342 @@
+/*
+ * Format Conversion Utils for MIPS
+ *
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of is
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Zoran Lukic (zoranl@mips.com)
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "config.h"
+#include "libavcodec/avcodec.h"
+#include "libavcodec/fmtconvert.h"
+
+#if HAVE_INLINE_ASM
+#if HAVE_MIPSDSPR1
+static void float_to_int16_mips(int16_t *dst, const float *src, long len)
+{
+ const float *src_end = src + len;
+ int ret0, ret1, ret2, ret3, ret4, ret5, ret6, ret7;
+ float src0, src1, src2, src3, src4, src5, src6, src7;
+
+ /*
+ * loop is 8 times unrolled in assembler in order to achieve better performance
+ */
+ __asm__ volatile(
+ "beq %[len], $zero, fti16_end%= \n\t"
+ "fti16_lp%=: \n\t"
+ "lwc1 %[src0], 0(%[src]) \n\t"
+ "lwc1 %[src1], 4(%[src]) \n\t"
+ "lwc1 %[src2], 8(%[src]) \n\t"
+ "lwc1 %[src3], 12(%[src]) \n\t"
+ "cvt.w.s %[src0], %[src0] \n\t"
+ "cvt.w.s %[src1], %[src1] \n\t"
+ "cvt.w.s %[src2], %[src2] \n\t"
+ "cvt.w.s %[src3], %[src3] \n\t"
+ "mfc1 %[ret0], %[src0] \n\t"
+ "mfc1 %[ret1], %[src1] \n\t"
+ "mfc1 %[ret2], %[src2] \n\t"
+ "mfc1 %[ret3], %[src3] \n\t"
+ "lwc1 %[src4], 16(%[src]) \n\t"
+ "lwc1 %[src5], 20(%[src]) \n\t"
+ "lwc1 %[src6], 24(%[src]) \n\t"
+ "lwc1 %[src7], 28(%[src]) \n\t"
+ "cvt.w.s %[src4], %[src4] \n\t"
+ "cvt.w.s %[src5], %[src5] \n\t"
+ "cvt.w.s %[src6], %[src6] \n\t"
+ "cvt.w.s %[src7], %[src7] \n\t"
+ "addiu %[src], 32 \n\t"
+ "shll_s.w %[ret0], %[ret0], 16 \n\t"
+ "shll_s.w %[ret1], %[ret1], 16 \n\t"
+ "shll_s.w %[ret2], %[ret2], 16 \n\t"
+ "shll_s.w %[ret3], %[ret3], 16 \n\t"
+ "srl %[ret0], %[ret0], 16 \n\t"
+ "srl %[ret1], %[ret1], 16 \n\t"
+ "srl %[ret2], %[ret2], 16 \n\t"
+ "srl %[ret3], %[ret3], 16 \n\t"
+ "sh %[ret0], 0(%[dst]) \n\t"
+ "sh %[ret1], 2(%[dst]) \n\t"
+ "sh %[ret2], 4(%[dst]) \n\t"
+ "sh %[ret3], 6(%[dst]) \n\t"
+ "mfc1 %[ret4], %[src4] \n\t"
+ "mfc1 %[ret5], %[src5] \n\t"
+ "mfc1 %[ret6], %[src6] \n\t"
+ "mfc1 %[ret7], %[src7] \n\t"
+ "shll_s.w %[ret4], %[ret4], 16 \n\t"
+ "shll_s.w %[ret5], %[ret5], 16 \n\t"
+ "shll_s.w %[ret6], %[ret6], 16 \n\t"
+ "shll_s.w %[ret7], %[ret7], 16 \n\t"
+ "srl %[ret4], %[ret4], 16 \n\t"
+ "srl %[ret5], %[ret5], 16 \n\t"
+ "srl %[ret6], %[ret6], 16 \n\t"
+ "srl %[ret7], %[ret7], 16 \n\t"
+ "sh %[ret4], 8(%[dst]) \n\t"
+ "sh %[ret5], 10(%[dst]) \n\t"
+ "sh %[ret6], 12(%[dst]) \n\t"
+ "sh %[ret7], 14(%[dst]) \n\t"
+ "addiu %[dst], 16 \n\t"
+ "bne %[src], %[src_end], fti16_lp%= \n\t"
+ "fti16_end%=: \n\t"
+ : [ret0]"=&r"(ret0), [ret1]"=&r"(ret1), [ret2]"=&r"(ret2), [ret3]"=&r"(ret3),
+ [ret4]"=&r"(ret4), [ret5]"=&r"(ret5), [ret6]"=&r"(ret6), [ret7]"=&r"(ret7),
+ [src0]"=&f"(src0), [src1]"=&f"(src1), [src2]"=&f"(src2), [src3]"=&f"(src3),
+ [src4]"=&f"(src4), [src5]"=&f"(src5), [src6]"=&f"(src6), [src7]"=&f"(src7),
+ [src]"+r"(src), [dst]"+r"(dst)
+ : [src_end]"r"(src_end), [len]"r"(len)
+ : "memory"
+ );
+}
+
+static void float_to_int16_interleave_mips(int16_t *dst, const float **src, long len,
+ int channels)
+{
+ int c, ch2 = channels <<1;
+ int ret0, ret1, ret2, ret3, ret4, ret5, ret6, ret7;
+ float src0, src1, src2, src3, src4, src5, src6, src7;
+ int16_t *dst_ptr0, *dst_ptr1, *dst_ptr2, *dst_ptr3;
+ int16_t *dst_ptr4, *dst_ptr5, *dst_ptr6, *dst_ptr7;
+ const float *src_ptr, *src_ptr2, *src_end;
+
+ if (channels == 2) {
+ src_ptr = &src[0][0];
+ src_ptr2 = &src[1][0];
+ src_end = src_ptr + len;
+
+ __asm__ volatile (
+ "fti16i2_lp%=: \n\t"
+ "lwc1 %[src0], 0(%[src_ptr]) \n\t"
+ "lwc1 %[src1], 0(%[src_ptr2]) \n\t"
+ "addiu %[src_ptr], 4 \n\t"
+ "cvt.w.s $f9, %[src0] \n\t"
+ "cvt.w.s $f10, %[src1] \n\t"
+ "mfc1 %[ret0], $f9 \n\t"
+ "mfc1 %[ret1], $f10 \n\t"
+ "shll_s.w %[ret0], %[ret0], 16 \n\t"
+ "shll_s.w %[ret1], %[ret1], 16 \n\t"
+ "addiu %[src_ptr2], 4 \n\t"
+ "srl %[ret0], %[ret0], 16 \n\t"
+ "srl %[ret1], %[ret1], 16 \n\t"
+ "sh %[ret0], 0(%[dst]) \n\t"
+ "sh %[ret1], 2(%[dst]) \n\t"
+ "addiu %[dst], 4 \n\t"
+ "bne %[src_ptr], %[src_end], fti16i2_lp%= \n\t"
+ : [ret0]"=&r"(ret0), [ret1]"=&r"(ret1),
+ [src0]"=&f"(src0), [src1]"=&f"(src1),
+ [src_ptr]"+r"(src_ptr), [src_ptr2]"+r"(src_ptr2),
+ [dst]"+r"(dst)
+ : [src_end]"r"(src_end)
+ : "memory"
+ );
+ } else {
+ for (c = 0; c < channels; c++) {
+ src_ptr = &src[c][0];
+ dst_ptr0 = &dst[c];
+ src_end = src_ptr + len;
+ /*
+ * loop is 8 times unrolled in assembler in order to achieve better performance
+ */
+ __asm__ volatile(
+ "fti16i_lp%=: \n\t"
+ "lwc1 %[src0], 0(%[src_ptr]) \n\t"
+ "lwc1 %[src1], 4(%[src_ptr]) \n\t"
+ "lwc1 %[src2], 8(%[src_ptr]) \n\t"
+ "lwc1 %[src3], 12(%[src_ptr]) \n\t"
+ "cvt.w.s %[src0], %[src0] \n\t"
+ "cvt.w.s %[src1], %[src1] \n\t"
+ "cvt.w.s %[src2], %[src2] \n\t"
+ "cvt.w.s %[src3], %[src3] \n\t"
+ "mfc1 %[ret0], %[src0] \n\t"
+ "mfc1 %[ret1], %[src1] \n\t"
+ "mfc1 %[ret2], %[src2] \n\t"
+ "mfc1 %[ret3], %[src3] \n\t"
+ "lwc1 %[src4], 16(%[src_ptr]) \n\t"
+ "lwc1 %[src5], 20(%[src_ptr]) \n\t"
+ "lwc1 %[src6], 24(%[src_ptr]) \n\t"
+ "lwc1 %[src7], 28(%[src_ptr]) \n\t"
+ "addu %[dst_ptr1], %[dst_ptr0], %[ch2] \n\t"
+ "addu %[dst_ptr2], %[dst_ptr1], %[ch2] \n\t"
+ "addu %[dst_ptr3], %[dst_ptr2], %[ch2] \n\t"
+ "addu %[dst_ptr4], %[dst_ptr3], %[ch2] \n\t"
+ "addu %[dst_ptr5], %[dst_ptr4], %[ch2] \n\t"
+ "addu %[dst_ptr6], %[dst_ptr5], %[ch2] \n\t"
+ "addu %[dst_ptr7], %[dst_ptr6], %[ch2] \n\t"
+ "addiu %[src_ptr], 32 \n\t"
+ "cvt.w.s %[src4], %[src4] \n\t"
+ "cvt.w.s %[src5], %[src5] \n\t"
+ "cvt.w.s %[src6], %[src6] \n\t"
+ "cvt.w.s %[src7], %[src7] \n\t"
+ "shll_s.w %[ret0], %[ret0], 16 \n\t"
+ "shll_s.w %[ret1], %[ret1], 16 \n\t"
+ "shll_s.w %[ret2], %[ret2], 16 \n\t"
+ "shll_s.w %[ret3], %[ret3], 16 \n\t"
+ "srl %[ret0], %[ret0], 16 \n\t"
+ "srl %[ret1], %[ret1], 16 \n\t"
+ "srl %[ret2], %[ret2], 16 \n\t"
+ "srl %[ret3], %[ret3], 16 \n\t"
+ "sh %[ret0], 0(%[dst_ptr0]) \n\t"
+ "sh %[ret1], 0(%[dst_ptr1]) \n\t"
+ "sh %[ret2], 0(%[dst_ptr2]) \n\t"
+ "sh %[ret3], 0(%[dst_ptr3]) \n\t"
+ "mfc1 %[ret4], %[src4] \n\t"
+ "mfc1 %[ret5], %[src5] \n\t"
+ "mfc1 %[ret6], %[src6] \n\t"
+ "mfc1 %[ret7], %[src7] \n\t"
+ "shll_s.w %[ret4], %[ret4], 16 \n\t"
+ "shll_s.w %[ret5], %[ret5], 16 \n\t"
+ "shll_s.w %[ret6], %[ret6], 16 \n\t"
+ "shll_s.w %[ret7], %[ret7], 16 \n\t"
+ "srl %[ret4], %[ret4], 16 \n\t"
+ "srl %[ret5], %[ret5], 16 \n\t"
+ "srl %[ret6], %[ret6], 16 \n\t"
+ "srl %[ret7], %[ret7], 16 \n\t"
+ "sh %[ret4], 0(%[dst_ptr4]) \n\t"
+ "sh %[ret5], 0(%[dst_ptr5]) \n\t"
+ "sh %[ret6], 0(%[dst_ptr6]) \n\t"
+ "sh %[ret7], 0(%[dst_ptr7]) \n\t"
+ "addu %[dst_ptr0], %[dst_ptr7], %[ch2] \n\t"
+ "bne %[src_ptr], %[src_end], fti16i_lp%= \n\t"
+ : [ret0]"=&r"(ret0), [ret1]"=&r"(ret1), [ret2]"=&r"(ret2), [ret3]"=&r"(ret3),
+ [ret4]"=&r"(ret4), [ret5]"=&r"(ret5), [ret6]"=&r"(ret6), [ret7]"=&r"(ret7),
+ [src0]"=&f"(src0), [src1]"=&f"(src1), [src2]"=&f"(src2), [src3]"=&f"(src3),
+ [src4]"=&f"(src4), [src5]"=&f"(src5), [src6]"=&f"(src6), [src7]"=&f"(src7),
+ [dst_ptr1]"=&r"(dst_ptr1), [dst_ptr2]"=&r"(dst_ptr2), [dst_ptr3]"=&r"(dst_ptr3),
+ [dst_ptr4]"=&r"(dst_ptr4), [dst_ptr5]"=&r"(dst_ptr5), [dst_ptr6]"=&r"(dst_ptr6),
+ [dst_ptr7]"=&r"(dst_ptr7), [dst_ptr0]"+r"(dst_ptr0), [src_ptr]"+r"(src_ptr)
+ : [ch2]"r"(ch2), [src_end]"r"(src_end)
+ : "memory"
+ );
+ }
+ }
+}
+#endif /* HAVE_MIPSDSPR1 */
+
+static void int32_to_float_fmul_scalar_mips(float *dst, const int *src,
+ float mul, int len)
+{
+ /*
+ * variables used in inline assembler
+ */
+ float temp1, temp3, temp5, temp7, temp9, temp11, temp13, temp15;
+
+ int rpom1, rpom2, rpom11, rpom21, rpom12, rpom22, rpom13, rpom23;
+ const int *src_end = src + len;
+ /*
+ * loop is 8 times unrolled in assembler in order to achieve better performance
+ */
+ __asm__ volatile (
+ "i32tf_lp%=: \n\t"
+ "lw %[rpom11], 0(%[src]) \n\t"
+ "lw %[rpom21], 4(%[src]) \n\t"
+ "lw %[rpom1], 8(%[src]) \n\t"
+ "lw %[rpom2], 12(%[src]) \n\t"
+ "mtc1 %[rpom11], %[temp1] \n\t"
+ "mtc1 %[rpom21], %[temp3] \n\t"
+ "mtc1 %[rpom1], %[temp5] \n\t"
+ "mtc1 %[rpom2], %[temp7] \n\t"
+
+ "lw %[rpom13], 16(%[src]) \n\t"
+ "lw %[rpom23], 20(%[src]) \n\t"
+ "lw %[rpom12], 24(%[src]) \n\t"
+ "lw %[rpom22], 28(%[src]) \n\t"
+ "mtc1 %[rpom13], %[temp9] \n\t"
+ "mtc1 %[rpom23], %[temp11] \n\t"
+ "mtc1 %[rpom12], %[temp13] \n\t"
+ "mtc1 %[rpom22], %[temp15] \n\t"
+
+ "addiu %[src], 32 \n\t"
+ "cvt.s.w %[temp1], %[temp1] \n\t"
+ "cvt.s.w %[temp3], %[temp3] \n\t"
+ "cvt.s.w %[temp5], %[temp5] \n\t"
+ "cvt.s.w %[temp7], %[temp7] \n\t"
+
+ "cvt.s.w %[temp9], %[temp9] \n\t"
+ "cvt.s.w %[temp11], %[temp11] \n\t"
+ "cvt.s.w %[temp13], %[temp13] \n\t"
+ "cvt.s.w %[temp15], %[temp15] \n\t"
+
+ "mul.s %[temp1], %[temp1], %[mul] \n\t"
+ "mul.s %[temp3], %[temp3], %[mul] \n\t"
+ "mul.s %[temp5], %[temp5], %[mul] \n\t"
+ "mul.s %[temp7], %[temp7], %[mul] \n\t"
+
+ "mul.s %[temp9], %[temp9], %[mul] \n\t"
+ "mul.s %[temp11], %[temp11], %[mul] \n\t"
+ "mul.s %[temp13], %[temp13], %[mul] \n\t"
+ "mul.s %[temp15], %[temp15], %[mul] \n\t"
+
+ "swc1 %[temp1], 0(%[dst]) \n\t" /*dst[i] = src[i] * mul; */
+ "swc1 %[temp3], 4(%[dst]) \n\t" /*dst[i+1] = src[i+1] * mul;*/
+ "swc1 %[temp5], 8(%[dst]) \n\t" /*dst[i+2] = src[i+2] * mul;*/
+ "swc1 %[temp7], 12(%[dst]) \n\t" /*dst[i+3] = src[i+3] * mul;*/
+
+ "swc1 %[temp9], 16(%[dst]) \n\t" /*dst[i+4] = src[i+4] * mul;*/
+ "swc1 %[temp11], 20(%[dst]) \n\t" /*dst[i+5] = src[i+5] * mul;*/
+ "swc1 %[temp13], 24(%[dst]) \n\t" /*dst[i+6] = src[i+6] * mul;*/
+ "swc1 %[temp15], 28(%[dst]) \n\t" /*dst[i+7] = src[i+7] * mul;*/
+ "addiu %[dst], 32 \n\t"
+ "bne %[src], %[src_end], i32tf_lp%= \n\t"
+ : [temp1]"=&f"(temp1), [temp11]"=&f"(temp11),
+ [temp13]"=&f"(temp13), [temp15]"=&f"(temp15),
+ [temp3]"=&f"(temp3), [temp5]"=&f"(temp5),
+ [temp7]"=&f"(temp7), [temp9]"=&f"(temp9),
+ [rpom1]"=&r"(rpom1), [rpom2]"=&r"(rpom2),
+ [rpom11]"=&r"(rpom11), [rpom21]"=&r"(rpom21),
+ [rpom12]"=&r"(rpom12), [rpom22]"=&r"(rpom22),
+ [rpom13]"=&r"(rpom13), [rpom23]"=&r"(rpom23),
+ [dst]"+r"(dst), [src]"+r"(src)
+ : [mul]"f"(mul), [src_end]"r"(src_end)
+ : "memory"
+ );
+}
+#endif /* HAVE_INLINE_ASM */
+
+av_cold void ff_fmt_convert_init_mips(FmtConvertContext *c)
+{
+#if HAVE_INLINE_ASM
+#if HAVE_MIPSDSPR1
+ c->float_to_int16_interleave = float_to_int16_interleave_mips;
+ c->float_to_int16 = float_to_int16_mips;
+#endif
+ c->int32_to_float_fmul_scalar = int32_to_float_fmul_scalar_mips;
+#endif
+}
diff --git a/libavcodec/mips/iirfilter_mips.c b/libavcodec/mips/iirfilter_mips.c
new file mode 100644
index 0000000..a5646cd
--- /dev/null
+++ b/libavcodec/mips/iirfilter_mips.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Bojan Zivkovic (bojan@mips.com)
+ *
+ * IIR filter optimized for MIPS floating-point architecture
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ /**
+ * @file
+ * Reference: libavcodec/iirfilter.c
+ */
+
+#include "libavcodec/iirfilter.h"
+
+#if HAVE_INLINE_ASM
+typedef struct FFIIRFilterCoeffs {
+ int order;
+ float gain;
+ int *cx;
+ float *cy;
+} FFIIRFilterCoeffs;
+
+typedef struct FFIIRFilterState {
+ float x[1];
+} FFIIRFilterState;
+
+static void ff_iir_filter_flt_mips(const struct FFIIRFilterCoeffs *c,
+ struct FFIIRFilterState *s, int size,
+ const float *src, int sstep, float *dst, int dstep)
+{
+ if (c->order == 2) {
+ int i;
+ const float *src0 = src;
+ float *dst0 = dst;
+ for (i = 0; i < size; i++) {
+ float in = *src0 * c->gain + s->x[0] * c->cy[0] + s->x[1] * c->cy[1];
+ *dst0 = s->x[0] + in + s->x[1] * c->cx[1];
+ s->x[0] = s->x[1];
+ s->x[1] = in;
+ src0 += sstep;
+ dst0 += dstep;
+ }
+ } else if (c->order == 4) {
+ int i;
+ const float *src0 = src;
+ float *dst0 = dst;
+ float four = 4.0;
+ float six = 6.0;
+ for (i = 0; i < size; i += 4) {
+ float in1, in2, in3, in4;
+ float res1, res2, res3, res4;
+ float *x = s->x;
+ float *cy = c->cy;
+ float gain = c->gain;
+ float src0_0 = src0[0 ];
+ float src0_1 = src0[sstep ];
+ float src0_2 = src0[2*sstep];
+ float src0_3 = src0[3*sstep];
+
+ __asm__ volatile (
+ "lwc1 $f0, 0(%[cy]) \n\t"
+ "lwc1 $f4, 0(%[x]) \n\t"
+ "lwc1 $f5, 4(%[x]) \n\t"
+ "lwc1 $f6, 8(%[x]) \n\t"
+ "lwc1 $f7, 12(%[x]) \n\t"
+ "mul.s %[in1], %[src0_0], %[gain] \n\t"
+ "mul.s %[in2], %[src0_1], %[gain] \n\t"
+ "mul.s %[in3], %[src0_2], %[gain] \n\t"
+ "mul.s %[in4], %[src0_3], %[gain] \n\t"
+ "lwc1 $f1, 4(%[cy]) \n\t"
+ "madd.s %[in1], %[in1], $f0, $f4 \n\t"
+ "madd.s %[in2], %[in2], $f0, $f5 \n\t"
+ "madd.s %[in3], %[in3], $f0, $f6 \n\t"
+ "madd.s %[in4], %[in4], $f0, $f7 \n\t"
+ "lwc1 $f2, 8(%[cy]) \n\t"
+ "madd.s %[in1], %[in1], $f1, $f5 \n\t"
+ "madd.s %[in2], %[in2], $f1, $f6 \n\t"
+ "madd.s %[in3], %[in3], $f1, $f7 \n\t"
+ "lwc1 $f3, 12(%[cy]) \n\t"
+ "add.s $f8, $f5, $f7 \n\t"
+ "madd.s %[in1], %[in1], $f2, $f6 \n\t"
+ "madd.s %[in2], %[in2], $f2, $f7 \n\t"
+ "mul.s $f9, $f6, %[six] \n\t"
+ "mul.s $f10, $f7, %[six] \n\t"
+ "madd.s %[in1], %[in1], $f3, $f7 \n\t"
+ "madd.s %[in2], %[in2], $f3, %[in1] \n\t"
+ "madd.s %[in3], %[in3], $f2, %[in1] \n\t"
+ "madd.s %[in4], %[in4], $f1, %[in1] \n\t"
+ "add.s %[res1], $f4, %[in1] \n\t"
+ "swc1 %[in1], 0(%[x]) \n\t"
+ "add.s $f0, $f6, %[in1] \n\t"
+ "madd.s %[in3], %[in3], $f3, %[in2] \n\t"
+ "madd.s %[in4], %[in4], $f2, %[in2] \n\t"
+ "add.s %[res2], $f5, %[in2] \n\t"
+ "madd.s %[res1], %[res1], $f8, %[four] \n\t"
+ "add.s $f8, $f7, %[in2] \n\t"
+ "swc1 %[in2], 4(%[x]) \n\t"
+ "madd.s %[in4], %[in4], $f3, %[in3] \n\t"
+ "add.s %[res3], $f6, %[in3] \n\t"
+ "add.s %[res1], %[res1], $f9 \n\t"
+ "madd.s %[res2], %[res2], $f0, %[four] \n\t"
+ "swc1 %[in3], 8(%[x]) \n\t"
+ "add.s %[res4], $f7, %[in4] \n\t"
+ "madd.s %[res3], %[res3], $f8, %[four] \n\t"
+ "swc1 %[in4], 12(%[x]) \n\t"
+ "add.s %[res2], %[res2], $f10 \n\t"
+ "add.s $f8, %[in1], %[in3] \n\t"
+ "madd.s %[res3], %[res3], %[in1], %[six] \n\t"
+ "madd.s %[res4], %[res4], $f8, %[four] \n\t"
+ "madd.s %[res4], %[res4], %[in2], %[six] \n\t"
+
+ : [in1]"=&f"(in1), [in2]"=&f"(in2),
+ [in3]"=&f"(in3), [in4]"=&f"(in4),
+ [res1]"=&f"(res1), [res2]"=&f"(res2),
+ [res3]"=&f"(res3), [res4]"=&f"(res4)
+ : [src0_0]"f"(src0_0), [src0_1]"f"(src0_1),
+ [src0_2]"f"(src0_2), [src0_3]"f"(src0_3),
+ [gain]"f"(gain), [x]"r"(x), [cy]"r"(cy),
+ [four]"f"(four), [six]"f"(six)
+ : "$f0", "$f1", "$f2", "$f3",
+ "$f4", "$f5", "$f6", "$f7",
+ "$f8", "$f9", "$f10",
+ "memory"
+ );
+
+ dst0[0 ] = res1;
+ dst0[sstep ] = res2;
+ dst0[2*sstep] = res3;
+ dst0[3*sstep] = res4;
+
+ src0 += 4*sstep;
+ dst0 += 4*dstep;
+ }
+ } else {
+ int i;
+ const float *src0 = src;
+ float *dst0 = dst;
+ for (i = 0; i < size; i++) {
+ int j;
+ float in, res;
+ in = *src0 * c->gain;
+ for(j = 0; j < c->order; j++)
+ in += c->cy[j] * s->x[j];
+ res = s->x[0] + in + s->x[c->order >> 1] * c->cx[c->order >> 1];
+ for(j = 1; j < c->order >> 1; j++)
+ res += (s->x[j] + s->x[c->order - j]) * c->cx[j];
+ for(j = 0; j < c->order - 1; j++)
+ s->x[j] = s->x[j + 1];
+ *dst0 = res;
+ s->x[c->order - 1] = in;
+ src0 += sstep;
+ dst0 += dstep;
+ }
+ }
+}
+#endif /* HAVE_INLINE_ASM */
+
+void ff_iir_filter_init_mips(FFIIRFilterContext *f) {
+#if HAVE_INLINE_ASM
+ f->filter_flt = ff_iir_filter_flt_mips;
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/mips/lsp_mips.h b/libavcodec/mips/lsp_mips.h
new file mode 100644
index 0000000..c55ef03
--- /dev/null
+++ b/libavcodec/mips/lsp_mips.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * LSP routines for ACELP-based codecs optimized for MIPS
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/lsp.c
+ */
+#ifndef AVCODEC_LSP_MIPS_H
+#define AVCODEC_LSP_MIPS_H
+
+#if HAVE_MIPSFPU && HAVE_INLINE_ASM
+static av_always_inline void ff_lsp2polyf_mips(const double *lsp, double *f, int lp_half_order)
+{
+ int i, j = 0;
+ double * p_fi = f;
+ double * p_f = 0;
+
+ f[0] = 1.0;
+ f[1] = -2 * lsp[0];
+ lsp -= 2;
+
+ for(i=2; i<=lp_half_order; i++)
+ {
+ double tmp, f_j_2, f_j_1, f_j;
+ double val = lsp[2*i];
+
+ __asm__ volatile(
+ "move %[p_f], %[p_fi] \n\t"
+ "add.d %[val], %[val], %[val] \n\t"
+ "addiu %[p_fi], 8 \n\t"
+ "ldc1 %[f_j_1], 0(%[p_f]) \n\t"
+ "ldc1 %[f_j], 8(%[p_f]) \n\t"
+ "neg.d %[val], %[val] \n\t"
+ "add.d %[tmp], %[f_j_1], %[f_j_1] \n\t"
+ "madd.d %[tmp], %[tmp], %[f_j], %[val] \n\t"
+ "addiu %[j], %[i], -2 \n\t"
+ "ldc1 %[f_j_2], -8(%[p_f]) \n\t"
+ "sdc1 %[tmp], 16(%[p_f]) \n\t"
+ "beqz %[j], ff_lsp2polyf_lp_j_end%= \n\t"
+ "ff_lsp2polyf_lp_j%=: \n\t"
+ "add.d %[tmp], %[f_j], %[f_j_2] \n\t"
+ "madd.d %[tmp], %[tmp], %[f_j_1], %[val] \n\t"
+ "mov.d %[f_j], %[f_j_1] \n\t"
+ "addiu %[j], -1 \n\t"
+ "mov.d %[f_j_1], %[f_j_2] \n\t"
+ "ldc1 %[f_j_2], -16(%[p_f]) \n\t"
+ "sdc1 %[tmp], 8(%[p_f]) \n\t"
+ "addiu %[p_f], -8 \n\t"
+ "bgtz %[j], ff_lsp2polyf_lp_j%= \n\t"
+ "ff_lsp2polyf_lp_j_end%=: \n\t"
+
+ : [f_j_2]"=&f"(f_j_2), [f_j_1]"=&f"(f_j_1), [val]"+f"(val),
+ [tmp]"=&f"(tmp), [f_j]"=&f"(f_j), [p_f]"+r"(p_f),
+ [j]"+r"(j), [p_fi]"+r"(p_fi)
+ : [i]"r"(i)
+ : "memory"
+ );
+ f[1] += val;
+ }
+}
+#define ff_lsp2polyf ff_lsp2polyf_mips
+#endif /* HAVE_MIPSFPU && HAVE_INLINE_ASM */
+#endif /* AVCODEC_LSP_MIPS_H */
diff --git a/libavcodec/mips/mathops.h b/libavcodec/mips/mathops.h
index dd80f68..368290a 100644
--- a/libavcodec/mips/mathops.h
+++ b/libavcodec/mips/mathops.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mips/mpegaudiodsp_mips_fixed.c b/libavcodec/mips/mpegaudiodsp_mips_fixed.c
new file mode 100644
index 0000000..047a833
--- /dev/null
+++ b/libavcodec/mips/mpegaudiodsp_mips_fixed.c
@@ -0,0 +1,907 @@
+ /*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Bojan Zivkovic (bojan@mips.com)
+ *
+ * MPEG Audio decoder optimized for MIPS fixed-point architecture
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/mpegaudiodsp_template.c
+ */
+
+#include <string.h>
+
+#include "libavcodec/mpegaudiodsp.h"
+
+static void ff_mpadsp_apply_window_mips_fixed(int32_t *synth_buf, int32_t *window,
+ int *dither_state, int16_t *samples, int incr)
+{
+ register const int32_t *w, *w2, *p;
+ int j;
+ int16_t *samples2;
+ int w_asm, p_asm, w_asm1, p_asm1, w_asm2, p_asm2;
+ int w2_asm, w2_asm1, *p_temp1, *p_temp2;
+ int sum1 = 0;
+ int const min_asm = -32768, max_asm = 32767;
+ int temp1, temp2 = 0, temp3 = 0;
+ int64_t sum;
+
+ /* copy to avoid wrap */
+ memcpy(synth_buf + 512, synth_buf, 32 * sizeof(*synth_buf));
+ samples2 = samples + 31 * incr;
+ w = window;
+ w2 = window + 31;
+ sum = *dither_state;
+ p = synth_buf + 16;
+ p_temp1 = synth_buf + 16;
+ p_temp2 = synth_buf + 48;
+ temp1 = sum;
+
+ /**
+ * use of round_sample function from the original code is eliminated,
+ * changed with appropriate assembly instructions.
+ */
+ __asm__ volatile (
+ "mthi $zero \n\t"
+ "mtlo %[temp1] \n\t"
+ "lw %[w_asm], 0(%[w]) \n\t"
+ "lw %[p_asm], 0(%[p]) \n\t"
+ "lw %[w_asm1], 64*4(%[w]) \n\t"
+ "lw %[p_asm1], 64*4(%[p]) \n\t"
+ "lw %[w_asm2], 128*4(%[w]) \n\t"
+ "lw %[p_asm2], 128*4(%[p]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "madd %[w_asm2], %[p_asm2] \n\t"
+ "lw %[w_asm], 192*4(%[w]) \n\t"
+ "lw %[p_asm], 192*4(%[p]) \n\t"
+ "lw %[w_asm1], 256*4(%[w]) \n\t"
+ "lw %[p_asm1], 256*4(%[p]) \n\t"
+ "lw %[w_asm2], 320*4(%[w]) \n\t"
+ "lw %[p_asm2], 320*4(%[p]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "madd %[w_asm2], %[p_asm2] \n\t"
+ "lw %[w_asm], 384*4(%[w]) \n\t"
+ "lw %[p_asm], 384*4(%[p]) \n\t"
+ "lw %[w_asm1], 448*4(%[w]) \n\t"
+ "lw %[p_asm1], 448*4(%[p]) \n\t"
+ "lw %[w_asm2], 32*4(%[w]) \n\t"
+ "lw %[p_asm2], 32*4(%[p]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "msub %[w_asm2], %[p_asm2] \n\t"
+ "lw %[w_asm], 96*4(%[w]) \n\t"
+ "lw %[p_asm], 96*4(%[p]) \n\t"
+ "lw %[w_asm1], 160*4(%[w]) \n\t"
+ "lw %[p_asm1], 160*4(%[p]) \n\t"
+ "lw %[w_asm2], 224*4(%[w]) \n\t"
+ "lw %[p_asm2], 224*4(%[p]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub %[w_asm2], %[p_asm2] \n\t"
+ "lw %[w_asm], 288*4(%[w]) \n\t"
+ "lw %[p_asm], 288*4(%[p]) \n\t"
+ "lw %[w_asm1], 352*4(%[w]) \n\t"
+ "lw %[p_asm1], 352*4(%[p]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "lw %[w_asm], 480*4(%[w]) \n\t"
+ "lw %[p_asm], 480*4(%[p]) \n\t"
+ "lw %[w_asm2], 416*4(%[w]) \n\t"
+ "lw %[p_asm2], 416*4(%[p]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub %[w_asm2], %[p_asm2] \n\t"
+
+ /*round_sample function from the original code is eliminated,
+ * changed with appropriate assembly instructions
+ * code example:
+
+ "extr.w %[sum1],$ac0,24 \n\t"
+ "mflo %[temp3], $ac0 \n\t"
+ "and %[temp1], %[temp3], 0x00ffffff \n\t"
+ "slt %[temp2], %[sum1], %[min_asm] \n\t"
+ "movn %[sum1], %[min_asm],%[temp2] \n\t"
+ "slt %[temp2], %[max_asm],%[sum1] \n\t"
+ "movn %[sum1], %[max_asm],%[temp2] \n\t"
+ "sh %[sum1], 0(%[samples]) \n\t"
+ */
+
+ "extr.w %[sum1], $ac0, 24 \n\t"
+ "mflo %[temp3] \n\t"
+ "addi %[w], %[w], 4 \n\t"
+ "and %[temp1], %[temp3], 0x00ffffff \n\t"
+ "slt %[temp2], %[sum1], %[min_asm] \n\t"
+ "movn %[sum1], %[min_asm], %[temp2] \n\t"
+ "slt %[temp2], %[max_asm], %[sum1] \n\t"
+ "movn %[sum1], %[max_asm], %[temp2] \n\t"
+ "sh %[sum1], 0(%[samples]) \n\t"
+
+ : [w_asm] "=&r" (w_asm), [p_asm] "=&r" (p_asm), [w_asm1] "=&r" (w_asm1),
+ [p_asm1] "=&r" (p_asm1), [temp1] "+r" (temp1), [temp2] "+r" (temp2),
+ [w_asm2] "=&r" (w_asm2), [p_asm2] "=&r" (p_asm2),
+ [sum1] "+r" (sum1), [w] "+r" (w), [temp3] "+r" (temp3)
+ : [p] "r" (p), [samples] "r" (samples), [min_asm] "r" (min_asm),
+ [max_asm] "r" (max_asm)
+ : "memory", "hi","lo"
+ );
+
+ samples += incr;
+
+ /* we calculate two samples at the same time to avoid one memory
+ access per two sample */
+
+ for(j = 1; j < 16; j++) {
+ __asm__ volatile (
+ "mthi $0, $ac1 \n\t"
+ "mtlo $0, $ac1 \n\t"
+ "mthi $0 \n\t"
+ "mtlo %[temp1] \n\t"
+ "addi %[p_temp1], %[p_temp1], 4 \n\t"
+ "lw %[w_asm], 0(%[w]) \n\t"
+ "lw %[p_asm], 0(%[p_temp1]) \n\t"
+ "lw %[w2_asm], 0(%[w2]) \n\t"
+ "lw %[w_asm1], 64*4(%[w]) \n\t"
+ "lw %[p_asm1], 64*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm1], 64*4(%[w2]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "lw %[w_asm], 128*4(%[w]) \n\t"
+ "lw %[p_asm], 128*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm], 128*4(%[w2]) \n\t"
+ "lw %[w_asm1], 192*4(%[w]) \n\t"
+ "lw %[p_asm1], 192*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm1], 192*4(%[w2]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "lw %[w_asm], 256*4(%[w]) \n\t"
+ "lw %[p_asm], 256*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm], 256*4(%[w2]) \n\t"
+ "lw %[w_asm1], 320*4(%[w]) \n\t"
+ "lw %[p_asm1], 320*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm1], 320*4(%[w2]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "lw %[w_asm], 384*4(%[w]) \n\t"
+ "lw %[p_asm], 384*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm], 384*4(%[w2]) \n\t"
+ "lw %[w_asm1], 448*4(%[w]) \n\t"
+ "lw %[p_asm1], 448*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm1], 448*4(%[w2]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "addi %[p_temp2], %[p_temp2], -4 \n\t"
+ "lw %[w_asm], 32*4(%[w]) \n\t"
+ "lw %[p_asm], 0(%[p_temp2]) \n\t"
+ "lw %[w2_asm], 32*4(%[w2]) \n\t"
+ "lw %[w_asm1], 96*4(%[w]) \n\t"
+ "lw %[p_asm1], 64*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm1], 96*4(%[w2]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "lw %[w_asm], 160*4(%[w]) \n\t"
+ "lw %[p_asm], 128*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm], 160*4(%[w2]) \n\t"
+ "lw %[w_asm1], 224*4(%[w]) \n\t"
+ "lw %[p_asm1], 192*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm1], 224*4(%[w2]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "lw %[w_asm], 288*4(%[w]) \n\t"
+ "lw %[p_asm], 256*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm], 288*4(%[w2]) \n\t"
+ "lw %[w_asm1], 352*4(%[w]) \n\t"
+ "lw %[p_asm1], 320*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm1], 352*4(%[w2]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "lw %[w_asm], 416*4(%[w]) \n\t"
+ "lw %[p_asm], 384*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm], 416*4(%[w2]) \n\t"
+ "lw %[w_asm1], 480*4(%[w]) \n\t"
+ "lw %[p_asm1], 448*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm1], 480*4(%[w2]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "addi %[w], %[w], 4 \n\t"
+ "addi %[w2], %[w2], -4 \n\t"
+ "mflo %[temp2] \n\t"
+ "extr.w %[sum1], $ac0, 24 \n\t"
+ "li %[temp3], 1 \n\t"
+ "and %[temp1], %[temp2], 0x00ffffff \n\t"
+ "madd $ac1, %[temp1], %[temp3] \n\t"
+ "slt %[temp2], %[sum1], %[min_asm] \n\t"
+ "movn %[sum1], %[min_asm], %[temp2] \n\t"
+ "slt %[temp2], %[max_asm], %[sum1] \n\t"
+ "movn %[sum1], %[max_asm], %[temp2] \n\t"
+ "sh %[sum1], 0(%[samples]) \n\t"
+ "mflo %[temp3], $ac1 \n\t"
+ "extr.w %[sum1], $ac1, 24 \n\t"
+ "and %[temp1], %[temp3], 0x00ffffff \n\t"
+ "slt %[temp2], %[sum1], %[min_asm] \n\t"
+ "movn %[sum1], %[min_asm], %[temp2] \n\t"
+ "slt %[temp2], %[max_asm], %[sum1] \n\t"
+ "movn %[sum1], %[max_asm], %[temp2] \n\t"
+ "sh %[sum1], 0(%[samples2]) \n\t"
+
+ : [w_asm] "=&r" (w_asm), [p_asm] "=&r" (p_asm), [w_asm1] "=&r" (w_asm1),
+ [p_asm1] "=&r" (p_asm1), [w2_asm1] "=&r" (w2_asm1),
+ [w2_asm] "=&r" (w2_asm), [temp1] "+r" (temp1), [temp2] "+r" (temp2),
+ [p_temp1] "+r" (p_temp1), [p_temp2] "+r" (p_temp2), [sum1] "+r" (sum1),
+ [w] "+r" (w), [w2] "+r" (w2), [samples] "+r" (samples),
+ [samples2] "+r" (samples2), [temp3] "+r" (temp3)
+ : [min_asm] "r" (min_asm), [max_asm] "r" (max_asm)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo"
+ );
+
+ samples += incr;
+ samples2 -= incr;
+ }
+
+ p = synth_buf + 32;
+
+ __asm__ volatile (
+ "mthi $0 \n\t"
+ "mtlo %[temp1] \n\t"
+ "lw %[w_asm], 32*4(%[w]) \n\t"
+ "lw %[p_asm], 0(%[p]) \n\t"
+ "lw %[w_asm1], 96*4(%[w]) \n\t"
+ "lw %[p_asm1], 64*4(%[p]) \n\t"
+ "lw %[w_asm2], 160*4(%[w]) \n\t"
+ "lw %[p_asm2], 128*4(%[p]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub %[w_asm2], %[p_asm2] \n\t"
+ "lw %[w_asm], 224*4(%[w]) \n\t"
+ "lw %[p_asm], 192*4(%[p]) \n\t"
+ "lw %[w_asm1], 288*4(%[w]) \n\t"
+ "lw %[p_asm1], 256*4(%[p]) \n\t"
+ "lw %[w_asm2], 352*4(%[w]) \n\t"
+ "lw %[p_asm2], 320*4(%[p]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub %[w_asm2], %[p_asm2] \n\t"
+ "lw %[w_asm], 416*4(%[w]) \n\t"
+ "lw %[p_asm], 384*4(%[p]) \n\t"
+ "lw %[w_asm1], 480*4(%[w]) \n\t"
+ "lw %[p_asm1], 448*4(%[p]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "extr.w %[sum1], $ac0, 24 \n\t"
+ "mflo %[temp2] \n\t"
+ "and %[temp1], %[temp2], 0x00ffffff \n\t"
+ "slt %[temp2], %[sum1], %[min_asm] \n\t"
+ "movn %[sum1], %[min_asm], %[temp2] \n\t"
+ "slt %[temp2], %[max_asm], %[sum1] \n\t"
+ "movn %[sum1], %[max_asm], %[temp2] \n\t"
+ "sh %[sum1], 0(%[samples]) \n\t"
+
+ : [w_asm] "=&r" (w_asm), [p_asm] "=&r" (p_asm), [w_asm1] "=&r" (w_asm1),
+ [p_asm1] "=&r" (p_asm1), [temp1] "+r" (temp1), [temp2] "+r" (temp2),
+ [w_asm2] "=&r" (w_asm2), [p_asm2] "=&r" (p_asm2), [sum1] "+r" (sum1)
+ : [w] "r" (w), [p] "r" (p), [samples] "r" (samples), [min_asm] "r" (min_asm),
+ [max_asm] "r" (max_asm)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo"
+ );
+
+ *dither_state= temp1;
+}
+
+static void imdct36_mips_fixed(int *out, int *buf, int *in, int *win)
+{
+ int j;
+ int t0, t1, t2, t3, s0, s1, s2, s3;
+ int tmp[18], *tmp1, *in1;
+ /* temporary variables */
+ int temp_reg1, temp_reg2, temp_reg3, temp_reg4, temp_reg5, temp_reg6;
+ int t4, t5, t6, t8, t7;
+
+ /* values defined in macros and tables are
+ * eliminated - they are directly loaded in appropriate variables
+ */
+ int const C_1 = 4229717092; /* cos(pi*1/18)*2 */
+ int const C_2 = 4035949074; /* cos(pi*2/18)*2 */
+ int const C_3 = 575416510; /* -cos(pi*3/18)*2 */
+ int const C_3A = 3719550786; /* cos(pi*3/18)*2 */
+ int const C_4 = 1004831466; /* -cos(pi*4/18)*2 */
+ int const C_5 = 1534215534; /* -cos(pi*5/18)*2 */
+ int const C_7 = -1468965330; /* -cos(pi*7/18)*2 */
+ int const C_8 = -745813244; /* -cos(pi*8/18)*2 */
+
+ /*
+ * instructions of the first two loops are reorganized and loops are unrolled,
+ * in order to eliminate unnecessary readings and writings in array
+ */
+
+ __asm__ volatile (
+ "lw %[t1], 17*4(%[in]) \n\t"
+ "lw %[t2], 16*4(%[in]) \n\t"
+ "lw %[t3], 15*4(%[in]) \n\t"
+ "lw %[t4], 14*4(%[in]) \n\t"
+ "addu %[t1], %[t1], %[t2] \n\t"
+ "addu %[t2], %[t2], %[t3] \n\t"
+ "addu %[t3], %[t3], %[t4] \n\t"
+ "lw %[t5], 13*4(%[in]) \n\t"
+ "addu %[t1], %[t1], %[t3] \n\t"
+ "sw %[t2], 16*4(%[in]) \n\t"
+ "lw %[t6], 12*4(%[in]) \n\t"
+ "sw %[t1], 17*4(%[in]) \n\t"
+ "addu %[t4], %[t4], %[t5] \n\t"
+ "addu %[t5], %[t5], %[t6] \n\t"
+ "lw %[t7], 11*4(%[in]) \n\t"
+ "addu %[t3], %[t3], %[t5] \n\t"
+ "sw %[t4], 14*4(%[in]) \n\t"
+ "lw %[t8], 10*4(%[in]) \n\t"
+ "sw %[t3], 15*4(%[in]) \n\t"
+ "addu %[t6], %[t6], %[t7] \n\t"
+ "addu %[t7], %[t7], %[t8] \n\t"
+ "sw %[t6], 12*4(%[in]) \n\t"
+ "addu %[t5], %[t5], %[t7] \n\t"
+ "lw %[t1], 9*4(%[in]) \n\t"
+ "lw %[t2], 8*4(%[in]) \n\t"
+ "sw %[t5], 13*4(%[in]) \n\t"
+ "addu %[t8], %[t8], %[t1] \n\t"
+ "addu %[t1], %[t1], %[t2] \n\t"
+ "sw %[t8], 10*4(%[in]) \n\t"
+ "addu %[t7], %[t7], %[t1] \n\t"
+ "lw %[t3], 7*4(%[in]) \n\t"
+ "lw %[t4], 6*4(%[in]) \n\t"
+ "sw %[t7], 11*4(%[in]) \n\t"
+ "addu %[t2], %[t2], %[t3] \n\t"
+ "addu %[t3], %[t3], %[t4] \n\t"
+ "sw %[t2], 8*4(%[in]) \n\t"
+ "addu %[t1], %[t1], %[t3] \n\t"
+ "lw %[t5], 5*4(%[in]) \n\t"
+ "lw %[t6], 4*4(%[in]) \n\t"
+ "sw %[t1], 9*4(%[in]) \n\t"
+ "addu %[t4], %[t4], %[t5] \n\t"
+ "addu %[t5], %[t5], %[t6] \n\t"
+ "sw %[t4], 6*4(%[in]) \n\t"
+ "addu %[t3], %[t3], %[t5] \n\t"
+ "lw %[t7], 3*4(%[in]) \n\t"
+ "lw %[t8], 2*4(%[in]) \n\t"
+ "sw %[t3], 7*4(%[in]) \n\t"
+ "addu %[t6], %[t6], %[t7] \n\t"
+ "addu %[t7], %[t7], %[t8] \n\t"
+ "sw %[t6], 4*4(%[in]) \n\t"
+ "addu %[t5], %[t5], %[t7] \n\t"
+ "lw %[t1], 1*4(%[in]) \n\t"
+ "lw %[t2], 0*4(%[in]) \n\t"
+ "sw %[t5], 5*4(%[in]) \n\t"
+ "addu %[t8], %[t8], %[t1] \n\t"
+ "addu %[t1], %[t1], %[t2] \n\t"
+ "sw %[t8], 2*4(%[in]) \n\t"
+ "addu %[t7], %[t7], %[t1] \n\t"
+ "sw %[t7], 3*4(%[in]) \n\t"
+ "sw %[t1], 1*4(%[in]) \n\t"
+
+ : [in] "+r" (in), [t1] "=&r" (t1), [t2] "=&r" (t2), [t3] "=&r" (t3),
+ [t4] "=&r" (t4), [t5] "=&r" (t5), [t6] "=&r" (t6),
+ [t7] "=&r" (t7), [t8] "=&r" (t8)
+ :
+ : "memory"
+ );
+
+ for(j = 0; j < 2; j++) {
+
+ tmp1 = tmp + j;
+ in1 = in + j;
+
+ /**
+ * Original constants are multiplied by two in advanced
+ * for assembly optimization (e.g. C_2 = 2 * C2).
+ * That can lead to overflow in operations where they are used.
+ *
+ * Example of the solution:
+ *
+ * in original code:
+ * t0 = ((int64_t)(in1[2*2] + in1[2*4]) * (int64_t)(2*C2))>>32
+ *
+ * in assembly:
+ * C_2 = 2 * C2;
+ * .
+ * .
+ * "lw %[t7], 4*4(%[in1]) \n\t"
+ * "lw %[t8], 8*4(%[in1]) \n\t"
+ * "addu %[temp_reg2],%[t7], %[t8] \n\t"
+ * "multu %[C_2], %[temp_reg2] \n\t"
+ * "mfhi %[temp_reg1] \n\t"
+ * "sra %[temp_reg2],%[temp_reg2],31 \n\t"
+ * "move %[t0], $0 \n\t"
+ * "movn %[t0], %[C_2], %[temp_reg2] \n\t"
+ * "sub %[t0], %[temp_reg1],%[t0] \n\t"
+ */
+
+ __asm__ volatile (
+ "lw %[t7], 4*4(%[in1]) \n\t"
+ "lw %[t8], 8*4(%[in1]) \n\t"
+ "lw %[t6], 16*4(%[in1]) \n\t"
+ "lw %[t4], 0*4(%[in1]) \n\t"
+ "addu %[temp_reg2], %[t7], %[t8] \n\t"
+ "addu %[t2], %[t6], %[t8] \n\t"
+ "multu %[C_2], %[temp_reg2] \n\t"
+ "lw %[t5], 12*4(%[in1]) \n\t"
+ "sub %[t2], %[t2], %[t7] \n\t"
+ "sub %[t1], %[t4], %[t5] \n\t"
+ "sra %[t3], %[t5], 1 \n\t"
+ "sra %[temp_reg1], %[t2], 1 \n\t"
+ "addu %[t3], %[t3], %[t4] \n\t"
+ "sub %[temp_reg1], %[t1], %[temp_reg1] \n\t"
+ "sra %[temp_reg2], %[temp_reg2], 31 \n\t"
+ "sw %[temp_reg1], 6*4(%[tmp1]) \n\t"
+ "move %[t0], $0 \n\t"
+ "movn %[t0], %[C_2], %[temp_reg2] \n\t"
+ "mfhi %[temp_reg1] \n\t"
+ "addu %[t1], %[t1], %[t2] \n\t"
+ "sw %[t1], 16*4(%[tmp1]) \n\t"
+ "sub %[temp_reg4], %[t8], %[t6] \n\t"
+ "add %[temp_reg2], %[t7], %[t6] \n\t"
+ "mult $ac1, %[C_8], %[temp_reg4] \n\t"
+ "multu $ac2, %[C_4], %[temp_reg2] \n\t"
+ "sub %[t0], %[temp_reg1], %[t0] \n\t"
+ "sra %[temp_reg1], %[temp_reg2], 31 \n\t"
+ "move %[t2], $0 \n\t"
+ "movn %[t2], %[C_4], %[temp_reg1] \n\t"
+ "mfhi %[t1], $ac1 \n\t"
+ "mfhi %[temp_reg1], $ac2 \n\t"
+ "lw %[t6], 10*4(%[in1]) \n\t"
+ "lw %[t8], 14*4(%[in1]) \n\t"
+ "lw %[t7], 2*4(%[in1]) \n\t"
+ "lw %[t4], 6*4(%[in1]) \n\t"
+ "sub %[temp_reg3], %[t3], %[t0] \n\t"
+ "add %[temp_reg4], %[t3], %[t0] \n\t"
+ "sub %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "add %[temp_reg4], %[temp_reg4], %[t1] \n\t"
+ "sub %[t2], %[temp_reg1], %[t2] \n\t"
+ "sw %[temp_reg4], 2*4(%[tmp1]) \n\t"
+ "sub %[temp_reg3], %[temp_reg3], %[t2] \n\t"
+ "add %[temp_reg1], %[t3], %[t2] \n\t"
+ "sw %[temp_reg3], 10*4(%[tmp1]) \n\t"
+ "sub %[temp_reg1], %[temp_reg1], %[t1] \n\t"
+ "addu %[temp_reg2], %[t6], %[t8] \n\t"
+ "sw %[temp_reg1], 14*4(%[tmp1]) \n\t"
+ "sub %[temp_reg2], %[temp_reg2], %[t7] \n\t"
+ "addu %[temp_reg3], %[t7], %[t6] \n\t"
+ "multu $ac3, %[C_3], %[temp_reg2] \n\t"
+ "multu %[C_1], %[temp_reg3] \n\t"
+ "sra %[temp_reg1], %[temp_reg2], 31 \n\t"
+ "move %[t1], $0 \n\t"
+ "sra %[temp_reg3], %[temp_reg3], 31 \n\t"
+ "movn %[t1], %[C_3], %[temp_reg1] \n\t"
+ "mfhi %[temp_reg1], $ac3 \n\t"
+ "mfhi %[temp_reg4] \n\t"
+ "move %[t2], $0 \n\t"
+ "movn %[t2], %[C_1], %[temp_reg3] \n\t"
+ "sub %[temp_reg3], %[t6], %[t8] \n\t"
+ "sub %[t2], %[temp_reg4], %[t2] \n\t"
+ "multu $ac1, %[C_7], %[temp_reg3] \n\t"
+ "sub %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "sra %[temp_reg4], %[temp_reg3], 31 \n\t"
+ "sub %[t1], %[temp_reg1], %[t1] \n\t"
+ "move %[t3], $0 \n\t"
+ "sw %[t1], 4*4(%[tmp1]) \n\t"
+ "movn %[t3], %[C_7], %[temp_reg4] \n\t"
+ "multu $ac2, %[C_3A], %[t4] \n\t"
+ "add %[temp_reg2], %[t7], %[t8] \n\t"
+ "move %[t1], $0 \n\t"
+ "mfhi %[temp_reg4], $ac1 \n\t"
+ "multu $ac3,%[C_5], %[temp_reg2] \n\t"
+ "move %[t0], $0 \n\t"
+ "sra %[temp_reg1], %[temp_reg2], 31 \n\t"
+ "movn %[t1],%[C_5], %[temp_reg1] \n\t"
+ "sub %[temp_reg4], %[temp_reg4], %[temp_reg3] \n\t"
+ "mfhi %[temp_reg1], $ac3 \n\t"
+ "sra %[temp_reg3], %[t4], 31 \n\t"
+ "movn %[t0], %[C_3A], %[temp_reg3] \n\t"
+ "mfhi %[temp_reg3], $ac2 \n\t"
+ "sub %[t3], %[temp_reg4], %[t3] \n\t"
+ "add %[temp_reg4], %[t3], %[t2] \n\t"
+ "sub %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "sub %[t1], %[temp_reg1], %[t1] \n\t"
+ "sub %[t0], %[temp_reg3], %[t0] \n\t"
+ "add %[temp_reg1], %[t2], %[t1] \n\t"
+ "add %[temp_reg4], %[temp_reg4], %[t0] \n\t"
+ "sub %[temp_reg2], %[t3], %[t1] \n\t"
+ "sw %[temp_reg4], 0*4(%[tmp1]) \n\t"
+ "sub %[temp_reg1], %[temp_reg1], %[t0] \n\t"
+ "sub %[temp_reg2], %[temp_reg2], %[t0] \n\t"
+ "sw %[temp_reg1], 12*4(%[tmp1]) \n\t"
+ "sw %[temp_reg2], 8*4(%[tmp1]) \n\t"
+
+ : [t7] "=&r" (t7), [temp_reg1] "=&r" (temp_reg1),
+ [temp_reg2] "=&r" (temp_reg2), [temp_reg4] "=&r" (temp_reg4),
+ [temp_reg3] "=&r" (temp_reg3), [t8] "=&r" (t8), [t0] "=&r" (t0),
+ [t4] "=&r" (t4), [t5] "=&r" (t5), [t6] "=&r"(t6), [t2] "=&r" (t2),
+ [t3] "=&r" (t3), [t1] "=&r" (t1)
+ : [C_2] "r" (C_2), [in1] "r" (in1), [tmp1] "r" (tmp1), [C_8] "r" (C_8),
+ [C_4] "r" (C_4), [C_3] "r" (C_3), [C_1] "r" (C_1), [C_7] "r" (C_7),
+ [C_3A] "r" (C_3A), [C_5] "r" (C_5)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo",
+ "$ac3hi", "$ac3lo"
+ );
+ }
+
+ /**
+ * loop is unrolled four times
+ *
+ * values defined in tables(icos36[] and icos36h[]) are not loaded from
+ * these tables - they are directly loaded in appropriate registers
+ *
+ */
+
+ __asm__ volatile (
+ "lw %[t2], 1*4(%[tmp]) \n\t"
+ "lw %[t3], 3*4(%[tmp]) \n\t"
+ "lw %[t0], 0*4(%[tmp]) \n\t"
+ "lw %[t1], 2*4(%[tmp]) \n\t"
+ "addu %[temp_reg1], %[t3], %[t2] \n\t"
+ "li %[temp_reg2], 0x807D2B1E \n\t"
+ "move %[s1], $0 \n\t"
+ "multu %[temp_reg2], %[temp_reg1] \n\t"
+ "sra %[temp_reg1], %[temp_reg1], 31 \n\t"
+ "movn %[s1], %[temp_reg2], %[temp_reg1] \n\t"
+ "sub %[temp_reg3], %[t3], %[t2] \n\t"
+ "li %[temp_reg4], 0x2de5151 \n\t"
+ "mfhi %[temp_reg2] \n\t"
+ "addu %[s0], %[t1], %[t0] \n\t"
+ "lw %[temp_reg5], 9*4(%[win]) \n\t"
+ "mult $ac1, %[temp_reg4], %[temp_reg3] \n\t"
+ "lw %[temp_reg6], 4*9*4(%[buf]) \n\t"
+ "sub %[s2], %[t1], %[t0] \n\t"
+ "lw %[temp_reg3], 29*4(%[win]) \n\t"
+ "subu %[s1], %[temp_reg2], %[s1] \n\t"
+ "lw %[temp_reg4], 28*4(%[win]) \n\t"
+ "add %[t0], %[s0], %[s1] \n\t"
+ "extr.w %[s3], $ac1,23 \n\t"
+ "mult $ac2, %[t0], %[temp_reg3] \n\t"
+ "sub %[t1], %[s0], %[s1] \n\t"
+ "lw %[temp_reg1], 4*8*4(%[buf]) \n\t"
+ "mult %[t1], %[temp_reg5] \n\t"
+ "lw %[temp_reg2], 8*4(%[win]) \n\t"
+ "mfhi %[temp_reg3], $ac2 \n\t"
+ "mult $ac3, %[t0], %[temp_reg4] \n\t"
+ "add %[t0], %[s2], %[s3] \n\t"
+ "mfhi %[temp_reg5] \n\t"
+ "mult $ac1, %[t1], %[temp_reg2] \n\t"
+ "sub %[t1], %[s2], %[s3] \n\t"
+ "sw %[temp_reg3], 4*9*4(%[buf]) \n\t"
+ "mfhi %[temp_reg4], $ac3 \n\t"
+ "lw %[temp_reg3], 37*4(%[win]) \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "add %[temp_reg5], %[temp_reg5], %[temp_reg6] \n\t"
+ "lw %[temp_reg6], 17*4(%[win]) \n\t"
+ "sw %[temp_reg5], 32*9*4(%[out]) \n\t"
+ "sw %[temp_reg4], 4*8*4(%[buf]) \n\t"
+ "mult %[t1], %[temp_reg6] \n\t"
+ "add %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "lw %[temp_reg2], 0*4(%[win]) \n\t"
+ "lw %[temp_reg5], 4*17*4(%[buf]) \n\t"
+ "sw %[temp_reg1], 8*32*4(%[out]) \n\t"
+ "mfhi %[temp_reg6] \n\t"
+ "mult $ac1, %[t1], %[temp_reg2] \n\t"
+ "lw %[temp_reg4], 20*4(%[win]) \n\t"
+ "lw %[temp_reg1], 0(%[buf]) \n\t"
+ "mult $ac2, %[t0], %[temp_reg3] \n\t"
+ "mult %[t0], %[temp_reg4] \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "lw %[t0], 4*4(%[tmp]) \n\t"
+ "add %[temp_reg5], %[temp_reg5], %[temp_reg6] \n\t"
+ "mfhi %[temp_reg3], $ac2 \n\t"
+ "mfhi %[temp_reg4] \n\t"
+ "sw %[temp_reg5], 17*32*4(%[out]) \n\t"
+ "lw %[t1], 6*4(%[tmp]) \n\t"
+ "add %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "lw %[t2], 5*4(%[tmp]) \n\t"
+ "sw %[temp_reg1], 0*32*4(%[out]) \n\t"
+ "addu %[s0], %[t1], %[t0] \n\t"
+ "sw %[temp_reg3], 4*17*4(%[buf]) \n\t"
+ "lw %[t3], 7*4(%[tmp]) \n\t"
+ "sub %[s2], %[t1], %[t0] \n\t"
+ "sw %[temp_reg4], 0(%[buf]) \n\t"
+ "addu %[temp_reg5], %[t3], %[t2] \n\t"
+ "li %[temp_reg6], 0x8483EE0C \n\t"
+ "move %[s1], $0 \n\t"
+ "multu %[temp_reg6], %[temp_reg5] \n\t"
+ "sub %[temp_reg1], %[t3], %[t2] \n\t"
+ "li %[temp_reg2], 0xf746ea \n\t"
+ "sra %[temp_reg5], %[temp_reg5], 31 \n\t"
+ "mult $ac1, %[temp_reg2], %[temp_reg1] \n\t"
+ "movn %[s1], %[temp_reg6], %[temp_reg5] \n\t"
+ "mfhi %[temp_reg5] \n\t"
+ "lw %[temp_reg3], 10*4(%[win]) \n\t"
+ "lw %[temp_reg4], 4*10*4(%[buf]) \n\t"
+ "extr.w %[s3], $ac1, 23 \n\t"
+ "lw %[temp_reg1], 4*7*4(%[buf]) \n\t"
+ "lw %[temp_reg2], 7*4(%[win]) \n\t"
+ "lw %[temp_reg6], 30*4(%[win]) \n\t"
+ "subu %[s1], %[temp_reg5], %[s1] \n\t"
+ "sub %[t1], %[s0], %[s1] \n\t"
+ "add %[t0], %[s0], %[s1] \n\t"
+ "mult $ac2, %[t1], %[temp_reg3] \n\t"
+ "mult $ac3, %[t1], %[temp_reg2] \n\t"
+ "mult %[t0], %[temp_reg6] \n\t"
+ "lw %[temp_reg5], 27*4(%[win]) \n\t"
+ "mult $ac1, %[t0], %[temp_reg5] \n\t"
+ "mfhi %[temp_reg3], $ac2 \n\t"
+ "mfhi %[temp_reg2], $ac3 \n\t"
+ "mfhi %[temp_reg6] \n\t"
+ "add %[t0], %[s2], %[s3] \n\t"
+ "sub %[t1], %[s2], %[s3] \n\t"
+ "add %[temp_reg3], %[temp_reg3], %[temp_reg4] \n\t"
+ "lw %[temp_reg4], 16*4(%[win]) \n\t"
+ "mfhi %[temp_reg5], $ac1 \n\t"
+ "sw %[temp_reg3], 32*10*4(%[out]) \n\t"
+ "add %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "lw %[temp_reg3], 4*16*4(%[buf]) \n\t"
+ "sw %[temp_reg6], 4*10*4(%[buf]) \n\t"
+ "sw %[temp_reg1], 7*32*4(%[out]) \n\t"
+ "mult $ac2, %[t1], %[temp_reg4] \n\t"
+ "sw %[temp_reg5], 4*7*4(%[buf]) \n\t"
+ "lw %[temp_reg6], 1*4(%[win]) \n\t"
+ "lw %[temp_reg5], 4*1*4(%[buf]) \n\t"
+ "lw %[temp_reg1], 36*4(%[win]) \n\t"
+ "mult $ac3, %[t1], %[temp_reg6] \n\t"
+ "lw %[temp_reg2], 21*4(%[win]) \n\t"
+ "mfhi %[temp_reg4], $ac2 \n\t"
+ "mult %[t0], %[temp_reg1] \n\t"
+ "mult $ac1, %[t0],%[temp_reg2] \n\t"
+ "lw %[t0], 8*4(%[tmp]) \n\t"
+ "mfhi %[temp_reg6], $ac3 \n\t"
+ "lw %[t1], 10*4(%[tmp]) \n\t"
+ "lw %[t3], 11*4(%[tmp]) \n\t"
+ "mfhi %[temp_reg1] \n\t"
+ "add %[temp_reg3], %[temp_reg3], %[temp_reg4] \n\t"
+ "lw %[t2], 9*4(%[tmp]) \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "add %[temp_reg5], %[temp_reg5], %[temp_reg6] \n\t"
+ "sw %[temp_reg3], 16*32*4(%[out]) \n\t"
+ "sw %[temp_reg5], 1*32*4(%[out]) \n\t"
+ "sw %[temp_reg1], 4*16*4(%[buf]) \n\t"
+ "addu %[temp_reg3], %[t3], %[t2] \n\t"
+ "li %[temp_reg4], 0x8D3B7CD6 \n\t"
+ "sw %[temp_reg2], 4*1*4(%[buf]) \n\t"
+ "multu %[temp_reg4],%[temp_reg3] \n\t"
+ "sra %[temp_reg3], %[temp_reg3], 31 \n\t"
+ "move %[s1], $0 \n\t"
+ "movn %[s1], %[temp_reg4], %[temp_reg3] \n\t"
+ "addu %[s0], %[t1], %[t0] \n\t"
+ "mfhi %[temp_reg3] \n\t"
+ "sub %[s2], %[t1], %[t0] \n\t"
+ "sub %[temp_reg5], %[t3], %[t2] \n\t"
+ "li %[temp_reg6], 0x976fd9 \n\t"
+ "lw %[temp_reg2], 11*4(%[win]) \n\t"
+ "lw %[temp_reg1], 4*11*4(%[buf]) \n\t"
+ "mult $ac1, %[temp_reg6], %[temp_reg5] \n\t"
+ "subu %[s1], %[temp_reg3], %[s1] \n\t"
+ "lw %[temp_reg5], 31*4(%[win]) \n\t"
+ "sub %[t1], %[s0], %[s1] \n\t"
+ "add %[t0], %[s0], %[s1] \n\t"
+ "mult $ac2, %[t1], %[temp_reg2] \n\t"
+ "mult %[t0], %[temp_reg5] \n\t"
+ "lw %[temp_reg4], 6*4(%[win]) \n\t"
+ "extr.w %[s3], $ac1, 23 \n\t"
+ "lw %[temp_reg3], 4*6*4(%[buf]) \n\t"
+ "mfhi %[temp_reg2], $ac2 \n\t"
+ "lw %[temp_reg6], 26*4(%[win]) \n\t"
+ "mfhi %[temp_reg5] \n\t"
+ "mult $ac3, %[t1], %[temp_reg4] \n\t"
+ "mult $ac1, %[t0], %[temp_reg6] \n\t"
+ "add %[t0], %[s2], %[s3] \n\t"
+ "sub %[t1], %[s2], %[s3] \n\t"
+ "add %[temp_reg2], %[temp_reg2], %[temp_reg1] \n\t"
+ "mfhi %[temp_reg4], $ac3 \n\t"
+ "mfhi %[temp_reg6], $ac1 \n\t"
+ "sw %[temp_reg5], 4*11*4(%[buf]) \n\t"
+ "sw %[temp_reg2], 32*11*4(%[out]) \n\t"
+ "lw %[temp_reg1], 4*15*4(%[buf]) \n\t"
+ "add %[temp_reg3], %[temp_reg3], %[temp_reg4] \n\t"
+ "lw %[temp_reg2], 15*4(%[win]) \n\t"
+ "sw %[temp_reg3], 6*32*4(%[out]) \n\t"
+ "sw %[temp_reg6], 4*6*4(%[buf]) \n\t"
+ "mult %[t1], %[temp_reg2] \n\t"
+ "lw %[temp_reg3], 2*4(%[win]) \n\t"
+ "lw %[temp_reg4], 4*2*4(%[buf]) \n\t"
+ "lw %[temp_reg5], 35*4(%[win]) \n\t"
+ "mult $ac1, %[t1], %[temp_reg3] \n\t"
+ "mfhi %[temp_reg2] \n\t"
+ "lw %[temp_reg6], 22*4(%[win]) \n\t"
+ "mult $ac2, %[t0], %[temp_reg5] \n\t"
+ "lw %[t1], 14*4(%[tmp]) \n\t"
+ "mult $ac3, %[t0], %[temp_reg6] \n\t"
+ "lw %[t0], 12*4(%[tmp]) \n\t"
+ "mfhi %[temp_reg3], $ac1 \n\t"
+ "add %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "mfhi %[temp_reg5], $ac2 \n\t"
+ "sw %[temp_reg1], 15*32*4(%[out]) \n\t"
+ "mfhi %[temp_reg6], $ac3 \n\t"
+ "lw %[t2], 13*4(%[tmp]) \n\t"
+ "lw %[t3], 15*4(%[tmp]) \n\t"
+ "add %[temp_reg4], %[temp_reg4], %[temp_reg3] \n\t"
+ "sw %[temp_reg5], 4*15*4(%[buf]) \n\t"
+ "addu %[temp_reg1], %[t3], %[t2] \n\t"
+ "li %[temp_reg2], 0x9C42577C \n\t"
+ "move %[s1], $0 \n\t"
+ "multu %[temp_reg2], %[temp_reg1] \n\t"
+ "sw %[temp_reg4], 2*32*4(%[out]) \n\t"
+ "sra %[temp_reg1], %[temp_reg1], 31 \n\t"
+ "movn %[s1], %[temp_reg2], %[temp_reg1] \n\t"
+ "sub %[temp_reg3], %[t3], %[t2] \n\t"
+ "li %[temp_reg4], 0x6f94a2 \n\t"
+ "mfhi %[temp_reg1] \n\t"
+ "addu %[s0], %[t1], %[t0] \n\t"
+ "sw %[temp_reg6], 4*2*4(%[buf]) \n\t"
+ "mult $ac1, %[temp_reg4], %[temp_reg3] \n\t"
+ "sub %[s2], %[t1], %[t0] \n\t"
+ "lw %[temp_reg5], 12*4(%[win]) \n\t"
+ "lw %[temp_reg6], 4*12*4(%[buf]) \n\t"
+ "subu %[s1], %[temp_reg1], %[s1] \n\t"
+ "sub %[t1], %[s0], %[s1] \n\t"
+ "lw %[temp_reg3], 32*4(%[win]) \n\t"
+ "mult $ac2, %[t1], %[temp_reg5] \n\t"
+ "add %[t0], %[s0], %[s1] \n\t"
+ "extr.w %[s3], $ac1, 23 \n\t"
+ "lw %[temp_reg2], 5*4(%[win]) \n\t"
+ "mult %[t0], %[temp_reg3] \n\t"
+ "mfhi %[temp_reg5], $ac2 \n\t"
+ "lw %[temp_reg4], 25*4(%[win]) \n\t"
+ "lw %[temp_reg1], 4*5*4(%[buf]) \n\t"
+ "mult $ac3, %[t1], %[temp_reg2] \n\t"
+ "mult $ac1, %[t0], %[temp_reg4] \n\t"
+ "mfhi %[temp_reg3] \n\t"
+ "add %[t0], %[s2], %[s3] \n\t"
+ "add %[temp_reg5], %[temp_reg5], %[temp_reg6] \n\t"
+ "mfhi %[temp_reg2], $ac3 \n\t"
+ "mfhi %[temp_reg4], $ac1 \n\t"
+ "sub %[t1], %[s2], %[s3] \n\t"
+ "sw %[temp_reg5], 32*12*4(%[out]) \n\t"
+ "sw %[temp_reg3], 4*12*4(%[buf]) \n\t"
+ "lw %[temp_reg6], 14*4(%[win]) \n\t"
+ "lw %[temp_reg5], 4*14*4(%[buf]) \n\t"
+ "add %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "sw %[temp_reg4], 4*5*4(%[buf]) \n\t"
+ "sw %[temp_reg1], 5*32*4(%[out]) \n\t"
+ "mult %[t1], %[temp_reg6] \n\t"
+ "lw %[temp_reg4], 34*4(%[win]) \n\t"
+ "lw %[temp_reg2], 3*4(%[win]) \n\t"
+ "lw %[temp_reg1], 4*3*4(%[buf]) \n\t"
+ "mult $ac2, %[t0], %[temp_reg4] \n\t"
+ "mfhi %[temp_reg6] \n\t"
+ "mult $ac1, %[t1], %[temp_reg2] \n\t"
+ "lw %[temp_reg3], 23*4(%[win]) \n\t"
+ "lw %[s0], 16*4(%[tmp]) \n\t"
+ "mfhi %[temp_reg4], $ac2 \n\t"
+ "lw %[t1], 17*4(%[tmp]) \n\t"
+ "mult $ac3, %[t0], %[temp_reg3] \n\t"
+ "move %[s1], $0 \n\t"
+ "add %[temp_reg5], %[temp_reg5], %[temp_reg6] \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "sw %[temp_reg5], 14*32*4(%[out]) \n\t"
+ "sw %[temp_reg4], 4*14*4(%[buf]) \n\t"
+ "mfhi %[temp_reg3], $ac3 \n\t"
+ "li %[temp_reg5], 0xB504F334 \n\t"
+ "add %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "multu %[temp_reg5], %[t1] \n\t"
+ "lw %[temp_reg2], 4*13*4(%[buf]) \n\t"
+ "sw %[temp_reg1], 3*32*4(%[out]) \n\t"
+ "sra %[t1], %[t1], 31 \n\t"
+ "mfhi %[temp_reg6] \n\t"
+ "movn %[s1], %[temp_reg5], %[t1] \n\t"
+ "sw %[temp_reg3], 4*3*4(%[buf]) \n\t"
+ "lw %[temp_reg1], 13*4(%[win]) \n\t"
+ "lw %[temp_reg4], 4*4*4(%[buf]) \n\t"
+ "lw %[temp_reg3], 4*4(%[win]) \n\t"
+ "lw %[temp_reg5], 33*4(%[win]) \n\t"
+ "subu %[s1], %[temp_reg6], %[s1] \n\t"
+ "lw %[temp_reg6], 24*4(%[win]) \n\t"
+ "sub %[t1], %[s0], %[s1] \n\t"
+ "add %[t0], %[s0], %[s1] \n\t"
+ "mult $ac1, %[t1], %[temp_reg1] \n\t"
+ "mult $ac2, %[t1], %[temp_reg3] \n\t"
+ "mult $ac3, %[t0], %[temp_reg5] \n\t"
+ "mult %[t0], %[temp_reg6] \n\t"
+ "mfhi %[temp_reg1], $ac1 \n\t"
+ "mfhi %[temp_reg3], $ac2 \n\t"
+ "mfhi %[temp_reg5], $ac3 \n\t"
+ "mfhi %[temp_reg6] \n\t"
+ "add %[temp_reg2], %[temp_reg2], %[temp_reg1] \n\t"
+ "add %[temp_reg4], %[temp_reg4], %[temp_reg3] \n\t"
+ "sw %[temp_reg2], 13*32*4(%[out]) \n\t"
+ "sw %[temp_reg4], 4*32*4(%[out]) \n\t"
+ "sw %[temp_reg5], 4*13*4(%[buf]) \n\t"
+ "sw %[temp_reg6], 4*4*4(%[buf]) \n\t"
+
+ : [t0] "=&r" (t0), [t1] "=&r" (t1), [t2] "=&r" (t2), [t3] "=&r" (t3),
+ [s0] "=&r" (s0), [s2] "=&r" (s2), [temp_reg1] "=&r" (temp_reg1),
+ [temp_reg2] "=&r" (temp_reg2), [s1] "=&r" (s1), [s3] "=&r" (s3),
+ [temp_reg3] "=&r" (temp_reg3), [temp_reg4] "=&r" (temp_reg4),
+ [temp_reg5] "=&r" (temp_reg5), [temp_reg6] "=&r" (temp_reg6),
+ [out] "+r" (out)
+ : [tmp] "r" (tmp), [win] "r" (win), [buf] "r" (buf)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo",
+ "$ac3hi", "$ac3lo"
+ );
+}
+
+static void ff_imdct36_blocks_mips_fixed(int *out, int *buf, int *in,
+ int count, int switch_point, int block_type)
+{
+ int j;
+ for (j=0 ; j < count; j++) {
+ /* apply window & overlap with previous buffer */
+
+ /* select window */
+ int win_idx = (switch_point && j < 2) ? 0 : block_type;
+ int *win = ff_mdct_win_fixed[win_idx + (4 & -(j & 1))];
+
+ imdct36_mips_fixed(out, buf, in, win);
+
+ in += 18;
+ buf += ((j&3) != 3 ? 1 : (72-3));
+ out++;
+ }
+}
+
+void ff_mpadsp_init_mipsdspr1(MPADSPContext *s)
+{
+ s->apply_window_fixed = ff_mpadsp_apply_window_mips_fixed;
+ s->imdct36_blocks_fixed = ff_imdct36_blocks_mips_fixed;
+}
diff --git a/libavcodec/mips/mpegaudiodsp_mips_float.c b/libavcodec/mips/mpegaudiodsp_mips_float.c
new file mode 100644
index 0000000..beb8e78
--- /dev/null
+++ b/libavcodec/mips/mpegaudiodsp_mips_float.c
@@ -0,0 +1,1250 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Bojan Zivkovic (bojan@mips.com)
+ *
+ * MPEG Audio decoder optimized for MIPS floating-point architecture
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/mpegaudiodsp_template.c
+ * libavcodec/dct32.c
+ */
+
+#include <string.h>
+
+#include "libavcodec/mpegaudiodsp.h"
+
+static void ff_mpadsp_apply_window_mips_float(float *synth_buf, float *window,
+ int *dither_state, float *samples, int incr)
+{
+ register const float *w, *w2, *p;
+ int j;
+ float *samples2;
+ float sum, sum2;
+ /* temporary variables */
+ int incr1 = incr << 2;
+ int t_sample;
+ float in1, in2, in3, in4, in5, in6, in7, in8;
+ float *p2;
+
+ /* copy to avoid wrap */
+ memcpy(synth_buf + 512, synth_buf, 32 * sizeof(*synth_buf));
+
+ /**
+ * instructions are scheduled to minimize pipeline stall.
+ * use of round_sample function from the original code is
+ * changed with appropriate assembly instructions.
+ */
+
+ __asm__ volatile (
+ "lwc1 %[sum], 0(%[dither_state]) \t\n"
+ "sll %[t_sample], %[incr1], 5 \t\n"
+ "sub %[t_sample], %[t_sample], %[incr1] \n\t"
+ "li %[j], 4 \t\n"
+ "lwc1 %[in1], 0(%[window]) \t\n"
+ "lwc1 %[in2], 16*4(%[synth_buf]) \t\n"
+ "sw $zero, 0(%[dither_state]) \t\n"
+ "lwc1 %[in3], 64*4(%[window]) \t\n"
+ "lwc1 %[in4], 80*4(%[synth_buf]) \t\n"
+ "addu %[samples2], %[samples], %[t_sample] \t\n"
+ "madd.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in5], 128*4(%[window]) \t\n"
+ "lwc1 %[in6], 144*4(%[synth_buf]) \t\n"
+ "lwc1 %[in7], 192*4(%[window]) \t\n"
+ "madd.s %[sum], %[sum], %[in3], %[in4] \t\n"
+ "lwc1 %[in8], 208*4(%[synth_buf]) \t\n"
+ "lwc1 %[in1], 256*4(%[window]) \t\n"
+ "lwc1 %[in2], 272*4(%[synth_buf]) \t\n"
+ "madd.s %[sum], %[sum], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 320*4(%[window]) \t\n"
+ "lwc1 %[in4], 336*4(%[synth_buf]) \t\n"
+ "lwc1 %[in5], 384*4(%[window]) \t\n"
+ "madd.s %[sum], %[sum], %[in7], %[in8] \t\n"
+ "lwc1 %[in6], 400*4(%[synth_buf]) \t\n"
+ "lwc1 %[in7], 448*4(%[window]) \t\n"
+ "lwc1 %[in8], 464*4(%[synth_buf]) \t\n"
+ "madd.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in1], 32*4(%[window]) \t\n"
+ "lwc1 %[in2], 48*4(%[synth_buf]) \t\n"
+ "madd.s %[sum], %[sum], %[in3], %[in4] \t\n"
+ "lwc1 %[in3], 96*4(%[window]) \t\n"
+ "lwc1 %[in4], 112*4(%[synth_buf]) \t\n"
+ "madd.s %[sum], %[sum], %[in5], %[in6] \t\n"
+ "lwc1 %[in5], 160*4(%[window]) \t\n"
+ "lwc1 %[in6], 176*4(%[synth_buf]) \t\n"
+ "madd.s %[sum], %[sum], %[in7], %[in8] \t\n"
+ "lwc1 %[in7], 224*4(%[window]) \t\n"
+ "lwc1 %[in8], 240*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in1], 288*4(%[window]) \t\n"
+ "lwc1 %[in2], 304*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in3], %[in4] \t\n"
+ "lwc1 %[in3], 352*4(%[window]) \t\n"
+ "lwc1 %[in4], 368*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in5], %[in6] \t\n"
+ "lwc1 %[in5], 416*4(%[window]) \t\n"
+ "lwc1 %[in6], 432*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in7], %[in8] \t\n"
+ "lwc1 %[in7], 480*4(%[window]) \t\n"
+ "lwc1 %[in8], 496*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "addu %[w], %[window], 4 \t\n"
+ "nmsub.s %[sum], %[sum], %[in3], %[in4] \t\n"
+ "addu %[w2], %[window], 124 \t\n"
+ "addiu %[p], %[synth_buf], 68 \t\n"
+ "addiu %[p2], %[synth_buf], 188 \t\n"
+ "nmsub.s %[sum], %[sum], %[in5], %[in6] \t\n"
+ "nmsub.s %[sum], %[sum], %[in7], %[in8] \t\n"
+ "swc1 %[sum], 0(%[samples]) \t\n"
+ "addu %[samples], %[samples], %[incr1] \t\n"
+
+ /* calculate two samples at the same time to avoid one memory
+ access per two sample */
+
+ "ff_mpadsp_apply_window_loop%=: \t\n"
+ "lwc1 %[in1], 0(%[w]) \t\n"
+ "lwc1 %[in2], 0(%[p]) \t\n"
+ "lwc1 %[in3], 0(%[w2]) \t\n"
+ "lwc1 %[in4], 64*4(%[w]) \t\n"
+ "lwc1 %[in5], 64*4(%[p]) \t\n"
+ "lwc1 %[in6], 64*4(%[w2]) \t\n"
+ "mul.s %[sum], %[in1], %[in2] \t\n"
+ "mul.s %[sum2], %[in2], %[in3] \t\n"
+ "lwc1 %[in1], 128*4(%[w]) \t\n"
+ "lwc1 %[in2], 128*4(%[p]) \t\n"
+ "madd.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "nmadd.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 128*4(%[w2]) \t\n"
+ "lwc1 %[in4], 192*4(%[w]) \t\n"
+ "madd.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in5], 192*4(%[p]) \t\n"
+ "lwc1 %[in6], 192*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ "lwc1 %[in1], 256*4(%[w]) \t\n"
+ "lwc1 %[in2], 256*4(%[p]) \t\n"
+ "madd.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 256*4(%[w2]) \t\n"
+ "lwc1 %[in4], 320*4(%[w]) \t\n"
+ "madd.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in5], 320*4(%[p]) \t\n"
+ "lwc1 %[in6], 320*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ "lwc1 %[in1], 384*4(%[w]) \t\n"
+ "lwc1 %[in2], 384*4(%[p]) \t\n"
+ "madd.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 384*4(%[w2]) \t\n"
+ "lwc1 %[in4], 448*4(%[w]) \t\n"
+ "madd.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in5], 448*4(%[p]) \t\n"
+ "lwc1 %[in6], 448*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ "madd.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "lwc1 %[in1], 32*4(%[w]) \t\n"
+ "lwc1 %[in2], 0(%[p2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 32*4(%[w2]) \t\n"
+ "lwc1 %[in4], 96*4(%[w]) \t\n"
+ "lwc1 %[in5], 64*4(%[p2]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in6], 96*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ "lwc1 %[in1], 160*4(%[w]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "lwc1 %[in2], 128*4(%[p2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 160*4(%[w2]) \t\n"
+ "lwc1 %[in4], 224*4(%[w]) \t\n"
+ "lwc1 %[in5], 192*4(%[p2]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in6], 224*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ "lwc1 %[in1], 288*4(%[w]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "lwc1 %[in2], 256*4(%[p2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 288*4(%[w2]) \t\n"
+ "lwc1 %[in4], 352*4(%[w]) \t\n"
+ "lwc1 %[in5], 320*4(%[p2]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in6], 352*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ "lwc1 %[in1], 416*4(%[w]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "lwc1 %[in2], 384*4(%[p2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 416*4(%[w2]) \t\n"
+ "lwc1 %[in4], 480*4(%[w]) \t\n"
+ "lwc1 %[in5], 448*4(%[p2]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in6], 480*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ "addiu %[w], %[w], 4 \t\n"
+ "nmsub.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "addiu %[w2], %[w2], -4 \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "addu %[j], %[j], 4 \t\n"
+ "addiu %[p], 4 \t\n"
+ "swc1 %[sum], 0(%[samples]) \t\n"
+ "addiu %[p2], -4 \t\n"
+ "swc1 %[sum2], 0(%[samples2]) \t\n"
+ "addu %[samples], %[samples], %[incr1] \t\n"
+ "subu %[samples2], %[samples2], %[incr1] \t\n"
+ "bne %[j], 64, ff_mpadsp_apply_window_loop%= \t\n"
+
+ "lwc1 %[in1], 48*4(%[window]) \t\n"
+ "lwc1 %[in2], 32*4(%[synth_buf]) \t\n"
+ "lwc1 %[in3], 112*4(%[window]) \t\n"
+ "lwc1 %[in4], 96*4(%[synth_buf]) \t\n"
+ "lwc1 %[in5], 176*4(%[window]) \t\n"
+ "lwc1 %[in6], 160*4(%[synth_buf]) \t\n"
+ "mul.s %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in7], 240*4(%[window]) \t\n"
+ "lwc1 %[in8], 224*4(%[synth_buf]) \t\n"
+ "lwc1 %[in1], 304*4(%[window]) \t\n"
+ "nmadd.s %[sum], %[sum], %[in3], %[in4] \t\n"
+ "lwc1 %[in2], 288*4(%[synth_buf]) \t\n"
+ "lwc1 %[in3], 368*4(%[window]) \t\n"
+ "lwc1 %[in4], 352*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in5], %[in6] \t\n"
+ "nmsub.s %[sum], %[sum], %[in7], %[in8] \t\n"
+ "lwc1 %[in5], 432*4(%[window]) \t\n"
+ "lwc1 %[in6], 416*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in7], 496*4(%[window]) \t\n"
+ "lwc1 %[in8], 480*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in3], %[in4] \t\n"
+ "nmsub.s %[sum], %[sum], %[in5], %[in6] \t\n"
+ "nmsub.s %[sum], %[sum], %[in7], %[in8] \t\n"
+ "swc1 %[sum], 0(%[samples]) \t\n"
+
+ : [sum] "=&f" (sum), [sum2] "=&f" (sum2),
+ [w2] "=&r" (w2), [w] "=&r" (w),
+ [p] "=&r" (p), [p2] "=&r" (p2), [j] "=&r" (j),
+ [samples] "+r" (samples), [samples2] "=&r" (samples2),
+ [in1] "=&f" (in1), [in2] "=&f" (in2),
+ [in3] "=&f" (in3), [in4] "=&f" (in4),
+ [in5] "=&f" (in5), [in6] "=&f" (in6),
+ [in7] "=&f" (in7), [in8] "=&f" (in8),
+ [t_sample] "=&r" (t_sample)
+ : [synth_buf] "r" (synth_buf), [window] "r" (window),
+ [dither_state] "r" (dither_state), [incr1] "r" (incr1)
+ : "memory"
+ );
+}
+
+static void ff_dct32_mips_float(float *out, const float *tab)
+{
+ float val0 , val1 , val2 , val3 , val4 , val5 , val6 , val7,
+ val8 , val9 , val10, val11, val12, val13, val14, val15,
+ val16, val17, val18, val19, val20, val21, val22, val23,
+ val24, val25, val26, val27, val28, val29, val30, val31;
+ float fTmp1, fTmp2, fTmp3, fTmp4, fTmp5, fTmp6, fTmp7, fTmp8,
+ fTmp9, fTmp10, fTmp11;
+
+ /**
+ * instructions are scheduled to minimize pipeline stall.
+ */
+ __asm__ volatile (
+ "lwc1 %[fTmp1], 0*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 31*4(%[tab]) \n\t"
+ "lwc1 %[fTmp3], 15*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 16*4(%[tab]) \n\t"
+ "li.s %[fTmp7], 0.50241928618815570551 \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp10], 0.50060299823519630134 \n\t"
+ "li.s %[fTmp11], 10.19000812354805681150 \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "add.s %[val0], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val15], %[fTmp5], %[fTmp6] \n\t"
+ "lwc1 %[fTmp1], 7*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 24*4(%[tab]) \n\t"
+ "madd.s %[val16], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val31], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "mul.s %[val15], %[val15], %[fTmp7] \n\t"
+ "lwc1 %[fTmp3], 8*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 23*4(%[tab]) \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "mul.s %[val31], %[val31], %[fTmp7] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp7], 5.10114861868916385802 \n\t"
+ "li.s %[fTmp10], 0.67480834145500574602 \n\t"
+ "li.s %[fTmp11], 0.74453627100229844977 \n\t"
+ "add.s %[val7], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val8], %[fTmp5], %[fTmp6] \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "li.s %[fTmp1], 0.50979557910415916894 \n\t"
+ "sub.s %[fTmp2], %[val0], %[val7] \n\t"
+ "mul.s %[val8], %[val8], %[fTmp7] \n\t"
+ "madd.s %[val23], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val24], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "add.s %[val0], %[val0], %[val7] \n\t"
+ "mul.s %[val7], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp2], %[val15], %[val8] \n\t"
+ "add.s %[val8], %[val15], %[val8] \n\t"
+ "mul.s %[val24], %[val24], %[fTmp7] \n\t"
+ "sub.s %[fTmp3], %[val16], %[val23] \n\t"
+ "add.s %[val16], %[val16], %[val23] \n\t"
+ "mul.s %[val15], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp4], %[val31], %[val24] \n\t"
+ "mul.s %[val23], %[fTmp1], %[fTmp3] \n\t"
+ "add.s %[val24], %[val31], %[val24] \n\t"
+ "mul.s %[val31], %[fTmp1], %[fTmp4] \n\t"
+
+ : [fTmp1] "=&f" (fTmp1), [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3),
+ [fTmp4] "=&f" (fTmp4), [fTmp5] "=&f" (fTmp5), [fTmp6] "=&f" (fTmp6),
+ [fTmp7] "=&f" (fTmp7), [fTmp8] "=&f" (fTmp8), [fTmp9] "=&f" (fTmp9),
+ [fTmp10] "=&f" (fTmp10), [fTmp11] "=&f" (fTmp11),
+ [val0] "=f" (val0), [val7] "=f" (val7),
+ [val8] "=f" (val8), [val15] "=f" (val15),
+ [val16] "=f" (val16), [val23] "=f" (val23),
+ [val24] "=f" (val24), [val31] "=f" (val31)
+ : [tab] "r" (tab)
+ : "memory"
+ );
+
+ __asm__ volatile (
+ "lwc1 %[fTmp1], 3*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 28*4(%[tab]) \n\t"
+ "lwc1 %[fTmp3], 12*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 19*4(%[tab]) \n\t"
+ "li.s %[fTmp7], 0.64682178335999012954 \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp10], 0.53104259108978417447 \n\t"
+ "li.s %[fTmp11], 1.48416461631416627724 \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "add.s %[val3], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val12], %[fTmp5], %[fTmp6] \n\t"
+ "lwc1 %[fTmp1], 4*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 27*4(%[tab]) \n\t"
+ "madd.s %[val19], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val28], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "mul.s %[val12], %[val12], %[fTmp7] \n\t"
+ "lwc1 %[fTmp3], 11*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 20*4(%[tab]) \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "mul.s %[val28], %[val28], %[fTmp7] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "li.s %[fTmp7], 0.78815462345125022473 \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp10], 0.55310389603444452782 \n\t"
+ "li.s %[fTmp11], 1.16943993343288495515 \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "add.s %[val4], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val11], %[fTmp5], %[fTmp6] \n\t"
+ "li.s %[fTmp1], 2.56291544774150617881 \n\t"
+ "madd.s %[val20], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val27], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "mul.s %[val11], %[val11], %[fTmp7] \n\t"
+ "sub.s %[fTmp2], %[val3], %[val4] \n\t"
+ "add.s %[val3], %[val3], %[val4] \n\t"
+ "sub.s %[fTmp4], %[val19], %[val20] \n\t"
+ "mul.s %[val27], %[val27], %[fTmp7] \n\t"
+ "sub.s %[fTmp3], %[val12], %[val11] \n\t"
+ "mul.s %[val4], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val11], %[val12], %[val11] \n\t"
+ "add.s %[val19], %[val19], %[val20] \n\t"
+ "mul.s %[val20], %[fTmp1], %[fTmp4] \n\t"
+ "mul.s %[val12], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val28], %[val27] \n\t"
+ "add.s %[val27], %[val28], %[val27] \n\t"
+ "mul.s %[val28], %[fTmp1], %[fTmp2] \n\t"
+
+ : [fTmp1] "=&f" (fTmp1), [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3),
+ [fTmp4] "=&f" (fTmp4), [fTmp5] "=&f" (fTmp5), [fTmp6] "=&f" (fTmp6),
+ [fTmp7] "=&f" (fTmp7), [fTmp8] "=&f" (fTmp8), [fTmp9] "=&f" (fTmp9),
+ [fTmp10] "=&f" (fTmp10), [fTmp11] "=&f" (fTmp11),
+ [val3] "=f" (val3), [val4] "=f" (val4),
+ [val11] "=f" (val11), [val12] "=f" (val12),
+ [val19] "=f" (val19), [val20] "=f" (val20),
+ [val27] "=f" (val27), [val28] "=f" (val28)
+ : [tab] "r" (tab)
+ : "memory"
+ );
+
+ __asm__ volatile (
+ "li.s %[fTmp1], 0.54119610014619698439 \n\t"
+ "sub.s %[fTmp2], %[val0], %[val3] \n\t"
+ "add.s %[val0], %[val0], %[val3] \n\t"
+ "sub.s %[fTmp3], %[val7], %[val4] \n\t"
+ "add.s %[val4], %[val7], %[val4] \n\t"
+ "sub.s %[fTmp4], %[val8], %[val11] \n\t"
+ "mul.s %[val3], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val8], %[val8], %[val11] \n\t"
+ "mul.s %[val7], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val15], %[val12] \n\t"
+ "mul.s %[val11], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val12], %[val15], %[val12] \n\t"
+ "mul.s %[val15], %[fTmp1], %[fTmp2] \n\t"
+
+ : [val0] "+f" (val0), [val3] "+f" (val3),
+ [val4] "+f" (val4), [val7] "+f" (val7),
+ [val8] "+f" (val8), [val11] "+f" (val11),
+ [val12] "+f" (val12), [val15] "+f" (val15),
+ [fTmp1] "=f" (fTmp1), [fTmp2] "=&f" (fTmp2),
+ [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4)
+ :
+ );
+
+ __asm__ volatile (
+ "sub.s %[fTmp2], %[val16], %[val19] \n\t"
+ "add.s %[val16], %[val16], %[val19] \n\t"
+ "sub.s %[fTmp3], %[val23], %[val20] \n\t"
+ "add.s %[val20], %[val23], %[val20] \n\t"
+ "sub.s %[fTmp4], %[val24], %[val27] \n\t"
+ "mul.s %[val19], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val24], %[val24], %[val27] \n\t"
+ "mul.s %[val23], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val31], %[val28] \n\t"
+ "mul.s %[val27], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val28], %[val31], %[val28] \n\t"
+ "mul.s %[val31], %[fTmp1], %[fTmp2] \n\t"
+
+ : [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val16] "+f" (val16), [val19] "+f" (val19), [val20] "+f" (val20),
+ [val23] "+f" (val23), [val24] "+f" (val24), [val27] "+f" (val27),
+ [val28] "+f" (val28), [val31] "+f" (val31)
+ : [fTmp1] "f" (fTmp1)
+ );
+
+ __asm__ volatile (
+ "lwc1 %[fTmp1], 1*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 30*4(%[tab]) \n\t"
+ "lwc1 %[fTmp3], 14*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 17*4(%[tab]) \n\t"
+ "li.s %[fTmp7], 0.52249861493968888062 \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp10], 0.50547095989754365998 \n\t"
+ "li.s %[fTmp11], 3.40760841846871878570 \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "add.s %[val1], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val14], %[fTmp5], %[fTmp6] \n\t"
+ "lwc1 %[fTmp1], 6*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 25*4(%[tab]) \n\t"
+ "madd.s %[val17], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val30], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "mul.s %[val14], %[val14], %[fTmp7] \n\t"
+ "lwc1 %[fTmp3], 9*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 22*4(%[tab]) \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "mul.s %[val30], %[val30], %[fTmp7] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp7], 1.72244709823833392782 \n\t"
+ "li.s %[fTmp10], 0.62250412303566481615 \n\t"
+ "li.s %[fTmp11], 0.83934964541552703873 \n\t"
+ "add.s %[val6], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val9], %[fTmp5], %[fTmp6] \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "li.s %[fTmp1], 0.60134488693504528054 \n\t"
+ "sub.s %[fTmp2], %[val1], %[val6] \n\t"
+ "add.s %[val1], %[val1], %[val6] \n\t"
+ "mul.s %[val9], %[val9], %[fTmp7] \n\t"
+ "madd.s %[val22], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val25], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "mul.s %[val6], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp2], %[val14], %[val9] \n\t"
+ "add.s %[val9], %[val14], %[val9] \n\t"
+ "mul.s %[val25], %[val25], %[fTmp7] \n\t"
+ "sub.s %[fTmp3], %[val17], %[val22] \n\t"
+ "add.s %[val17], %[val17], %[val22] \n\t"
+ "mul.s %[val14], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp2], %[val30], %[val25] \n\t"
+ "mul.s %[val22], %[fTmp1], %[fTmp3] \n\t"
+ "add.s %[val25], %[val30], %[val25] \n\t"
+ "mul.s %[val30], %[fTmp1], %[fTmp2] \n\t"
+
+ : [fTmp1] "=&f" (fTmp1), [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3),
+ [fTmp4] "=&f" (fTmp4), [fTmp5] "=&f" (fTmp5), [fTmp6] "=&f" (fTmp6),
+ [fTmp7] "=&f" (fTmp7), [fTmp8] "=&f" (fTmp8), [fTmp9] "=&f" (fTmp9),
+ [fTmp10] "=&f" (fTmp10), [fTmp11] "=&f" (fTmp11),
+ [val1] "=f" (val1), [val6] "=f" (val6),
+ [val9] "=f" (val9), [val14] "=f" (val14),
+ [val17] "=f" (val17), [val22] "=f" (val22),
+ [val25] "=f" (val25), [val30] "=f" (val30)
+ : [tab] "r" (tab)
+ : "memory"
+ );
+
+ __asm__ volatile (
+ "lwc1 %[fTmp1], 2*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 29*4(%[tab]) \n\t"
+ "lwc1 %[fTmp3], 13*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 18*4(%[tab]) \n\t"
+ "li.s %[fTmp7], 0.56694403481635770368 \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp10], 0.51544730992262454697 \n\t"
+ "li.s %[fTmp11], 2.05778100995341155085 \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "add.s %[val2], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val13], %[fTmp5], %[fTmp6] \n\t"
+ "lwc1 %[fTmp1], 5*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 26*4(%[tab]) \n\t"
+ "madd.s %[val18], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val29], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "mul.s %[val13], %[val13], %[fTmp7] \n\t"
+ "lwc1 %[fTmp3], 10*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 21*4(%[tab]) \n\t"
+ "mul.s %[val29], %[val29], %[fTmp7] \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp7], 1.06067768599034747134 \n\t"
+ "li.s %[fTmp10], 0.58293496820613387367 \n\t"
+ "li.s %[fTmp11], 0.97256823786196069369 \n\t"
+ "add.s %[val5], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val10], %[fTmp5], %[fTmp6] \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "li.s %[fTmp1], 0.89997622313641570463 \n\t"
+ "sub.s %[fTmp2], %[val2], %[val5] \n\t"
+ "mul.s %[val10], %[val10], %[fTmp7] \n\t"
+ "madd.s %[val21], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val26], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "add.s %[val2], %[val2], %[val5] \n\t"
+ "mul.s %[val5], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp3], %[val13], %[val10] \n\t"
+ "add.s %[val10], %[val13], %[val10] \n\t"
+ "mul.s %[val26], %[val26], %[fTmp7] \n\t"
+ "sub.s %[fTmp4], %[val18], %[val21] \n\t"
+ "add.s %[val18], %[val18], %[val21] \n\t"
+ "mul.s %[val13], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val29], %[val26] \n\t"
+ "add.s %[val26], %[val29], %[val26] \n\t"
+ "mul.s %[val21], %[fTmp1], %[fTmp4] \n\t"
+ "mul.s %[val29], %[fTmp1], %[fTmp2] \n\t"
+
+ : [fTmp1] "=&f" (fTmp1), [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3),
+ [fTmp4] "=&f" (fTmp4), [fTmp5] "=&f" (fTmp5), [fTmp6] "=&f" (fTmp6),
+ [fTmp7] "=&f" (fTmp7), [fTmp8] "=&f" (fTmp8), [fTmp9] "=&f" (fTmp9),
+ [fTmp10] "=&f" (fTmp10), [fTmp11] "=&f" (fTmp11),
+ [val2] "=f" (val2), [val5] "=f" (val5),
+ [val10] "=f" (val10), [val13] "=f" (val13),
+ [val18] "=f" (val18), [val21] "=f" (val21),
+ [val26] "=f" (val26), [val29] "=f" (val29)
+ : [tab] "r" (tab)
+ : "memory"
+ );
+
+ __asm__ volatile (
+ "li.s %[fTmp1], 1.30656296487637652785 \n\t"
+ "sub.s %[fTmp2], %[val1], %[val2] \n\t"
+ "add.s %[val1], %[val1], %[val2] \n\t"
+ "sub.s %[fTmp3], %[val6], %[val5] \n\t"
+ "add.s %[val5], %[val6], %[val5] \n\t"
+ "sub.s %[fTmp4], %[val9], %[val10] \n\t"
+ "mul.s %[val2], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val9], %[val9], %[val10] \n\t"
+ "mul.s %[val6], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val14], %[val13] \n\t"
+ "mul.s %[val10], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val13], %[val14], %[val13] \n\t"
+ "mul.s %[val14], %[fTmp1], %[fTmp2] \n\t"
+
+ : [fTmp1] "=f" (fTmp1), [fTmp2] "=&f" (fTmp2),
+ [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val1] "+f" (val1), [val2] "+f" (val2),
+ [val5] "+f" (val5), [val6] "+f" (val6),
+ [val9] "+f" (val9), [val10] "+f" (val10),
+ [val13] "+f" (val13), [val14] "+f" (val14)
+ :
+ );
+
+ __asm__ volatile (
+ "sub.s %[fTmp2], %[val17], %[val18] \n\t"
+ "add.s %[val17], %[val17], %[val18] \n\t"
+ "sub.s %[fTmp3], %[val22], %[val21] \n\t"
+ "add.s %[val21], %[val22], %[val21] \n\t"
+ "sub.s %[fTmp4], %[val25], %[val26] \n\t"
+ "mul.s %[val18], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val25], %[val25], %[val26] \n\t"
+ "mul.s %[val22], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val30], %[val29] \n\t"
+ "mul.s %[val26], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val29], %[val30], %[val29] \n\t"
+ "mul.s %[val30], %[fTmp1], %[fTmp2] \n\t"
+
+ : [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val17] "+f" (val17), [val18] "+f" (val18), [val21] "+f" (val21),
+ [val22] "+f" (val22), [val25] "+f" (val25), [val26] "+f" (val26),
+ [val29] "+f" (val29), [val30] "+f" (val30)
+ : [fTmp1] "f" (fTmp1)
+ );
+
+ __asm__ volatile (
+ "li.s %[fTmp1], 0.70710678118654752439 \n\t"
+ "sub.s %[fTmp2], %[val0], %[val1] \n\t"
+ "add.s %[val0], %[val0], %[val1] \n\t"
+ "sub.s %[fTmp3], %[val3], %[val2] \n\t"
+ "add.s %[val2], %[val3], %[val2] \n\t"
+ "sub.s %[fTmp4], %[val4], %[val5] \n\t"
+ "mul.s %[val1], %[fTmp1], %[fTmp2] \n\t"
+ "swc1 %[val0], 0(%[out]) \n\t"
+ "mul.s %[val3], %[fTmp3], %[fTmp1] \n\t"
+ "add.s %[val4], %[val4], %[val5] \n\t"
+ "mul.s %[val5], %[fTmp1], %[fTmp4] \n\t"
+ "swc1 %[val1], 16*4(%[out]) \n\t"
+ "sub.s %[fTmp2], %[val7], %[val6] \n\t"
+ "add.s %[val2], %[val2], %[val3] \n\t"
+ "swc1 %[val3], 24*4(%[out]) \n\t"
+ "add.s %[val6], %[val7], %[val6] \n\t"
+ "mul.s %[val7], %[fTmp1], %[fTmp2] \n\t"
+ "swc1 %[val2], 8*4(%[out]) \n\t"
+ "add.s %[val6], %[val6], %[val7] \n\t"
+ "swc1 %[val7], 28*4(%[out]) \n\t"
+ "add.s %[val4], %[val4], %[val6] \n\t"
+ "add.s %[val6], %[val6], %[val5] \n\t"
+ "add.s %[val5], %[val5], %[val7] \n\t"
+ "swc1 %[val4], 4*4(%[out]) \n\t"
+ "swc1 %[val5], 20*4(%[out]) \n\t"
+ "swc1 %[val6], 12*4(%[out]) \n\t"
+
+ : [fTmp1] "=f" (fTmp1), [fTmp2] "=&f" (fTmp2),
+ [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val0] "+f" (val0), [val1] "+f" (val1),
+ [val2] "+f" (val2), [val3] "+f" (val3),
+ [val4] "+f" (val4), [val5] "+f" (val5),
+ [val6] "+f" (val6), [val7] "+f" (val7)
+ : [out] "r" (out)
+ );
+
+ __asm__ volatile (
+ "sub.s %[fTmp2], %[val8], %[val9] \n\t"
+ "add.s %[val8], %[val8], %[val9] \n\t"
+ "sub.s %[fTmp3], %[val11], %[val10] \n\t"
+ "add.s %[val10], %[val11], %[val10] \n\t"
+ "sub.s %[fTmp4], %[val12], %[val13] \n\t"
+ "mul.s %[val9], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val12], %[val12], %[val13] \n\t"
+ "mul.s %[val11], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val15], %[val14] \n\t"
+ "mul.s %[val13], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val14], %[val15], %[val14] \n\t"
+ "add.s %[val10], %[val10], %[val11] \n\t"
+ "mul.s %[val15], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val14], %[val14], %[val15] \n\t"
+ "add.s %[val12], %[val12], %[val14] \n\t"
+ "add.s %[val14], %[val14], %[val13] \n\t"
+ "add.s %[val13], %[val13], %[val15] \n\t"
+ "add.s %[val8], %[val8], %[val12] \n\t"
+ "add.s %[val12], %[val12], %[val10] \n\t"
+ "add.s %[val10], %[val10], %[val14] \n\t"
+ "add.s %[val14], %[val14], %[val9] \n\t"
+ "add.s %[val9], %[val9], %[val13] \n\t"
+ "add.s %[val13], %[val13], %[val11] \n\t"
+ "add.s %[val11], %[val11], %[val15] \n\t"
+ "swc1 %[val8], 2*4(%[out]) \n\t"
+ "swc1 %[val9], 18*4(%[out]) \n\t"
+ "swc1 %[val10], 10*4(%[out]) \n\t"
+ "swc1 %[val11], 26*4(%[out]) \n\t"
+ "swc1 %[val12], 6*4(%[out]) \n\t"
+ "swc1 %[val13], 22*4(%[out]) \n\t"
+ "swc1 %[val14], 14*4(%[out]) \n\t"
+ "swc1 %[val15], 30*4(%[out]) \n\t"
+
+ : [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val8] "+f" (val8), [val9] "+f" (val9), [val10] "+f" (val10),
+ [val11] "+f" (val11), [val12] "+f" (val12), [val13] "+f" (val13),
+ [val14] "+f" (val14), [val15] "+f" (val15)
+ : [fTmp1] "f" (fTmp1), [out] "r" (out)
+ );
+
+ __asm__ volatile (
+ "sub.s %[fTmp2], %[val16], %[val17] \n\t"
+ "add.s %[val16], %[val16], %[val17] \n\t"
+ "sub.s %[fTmp3], %[val19], %[val18] \n\t"
+ "add.s %[val18], %[val19], %[val18] \n\t"
+ "sub.s %[fTmp4], %[val20], %[val21] \n\t"
+ "mul.s %[val17], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val20], %[val20], %[val21] \n\t"
+ "mul.s %[val19], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val23], %[val22] \n\t"
+ "mul.s %[val21], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val22], %[val23], %[val22] \n\t"
+ "add.s %[val18], %[val18], %[val19] \n\t"
+ "mul.s %[val23], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val22], %[val22], %[val23] \n\t"
+ "add.s %[val20], %[val20], %[val22] \n\t"
+ "add.s %[val22], %[val22], %[val21] \n\t"
+ "add.s %[val21], %[val21], %[val23] \n\t"
+
+ : [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val16] "+f" (val16), [val17] "+f" (val17), [val18] "+f" (val18),
+ [val19] "+f" (val19), [val20] "+f" (val20), [val21] "+f" (val21),
+ [val22] "+f" (val22), [val23] "+f" (val23)
+ : [fTmp1] "f" (fTmp1)
+ );
+
+ __asm__ volatile (
+ "sub.s %[fTmp2], %[val24], %[val25] \n\t"
+ "add.s %[val24], %[val24], %[val25] \n\t"
+ "sub.s %[fTmp3], %[val27], %[val26] \n\t"
+ "add.s %[val26], %[val27], %[val26] \n\t"
+ "sub.s %[fTmp4], %[val28], %[val29] \n\t"
+ "mul.s %[val25], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val28], %[val28], %[val29] \n\t"
+ "mul.s %[val27], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val31], %[val30] \n\t"
+ "mul.s %[val29], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val30], %[val31], %[val30] \n\t"
+ "add.s %[val26], %[val26], %[val27] \n\t"
+ "mul.s %[val31], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val30], %[val30], %[val31] \n\t"
+ "add.s %[val28], %[val28], %[val30] \n\t"
+ "add.s %[val30], %[val30], %[val29] \n\t"
+ "add.s %[val29], %[val29], %[val31] \n\t"
+ "add.s %[val24], %[val24], %[val28] \n\t"
+ "add.s %[val28], %[val28], %[val26] \n\t"
+ "add.s %[val26], %[val26], %[val30] \n\t"
+ "add.s %[val30], %[val30], %[val25] \n\t"
+ "add.s %[val25], %[val25], %[val29] \n\t"
+ "add.s %[val29], %[val29], %[val27] \n\t"
+ "add.s %[val27], %[val27], %[val31] \n\t"
+
+ : [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val24] "+f" (val24), [val25] "+f" (val25), [val26] "+f" (val26),
+ [val27] "+f" (val27), [val28] "+f" (val28), [val29] "+f" (val29),
+ [val30] "+f" (val30), [val31] "+f" (val31)
+ : [fTmp1] "f" (fTmp1)
+ );
+
+ out[ 1] = val16 + val24;
+ out[17] = val17 + val25;
+ out[ 9] = val18 + val26;
+ out[25] = val19 + val27;
+ out[ 5] = val20 + val28;
+ out[21] = val21 + val29;
+ out[13] = val22 + val30;
+ out[29] = val23 + val31;
+ out[ 3] = val24 + val20;
+ out[19] = val25 + val21;
+ out[11] = val26 + val22;
+ out[27] = val27 + val23;
+ out[ 7] = val28 + val18;
+ out[23] = val29 + val19;
+ out[15] = val30 + val17;
+ out[31] = val31;
+}
+
+static void imdct36_mips_float(float *out, float *buf, float *in, float *win)
+{
+ float t0, t1, t2, t3, s0, s1, s2, s3;
+ float tmp[18];
+ /* temporary variables */
+ float in1, in2, in3, in4, in5, in6;
+ float out1, out2, out3, out4, out5;
+ float c1, c2, c3, c4, c5, c6, c7, c8, c9;
+
+ /**
+ * all loops are unrolled totally, and instructions are scheduled to
+ * minimize pipeline stall. instructions of the first two loops are
+ * reorganized, in order to eliminate unnecessary readings and
+ * writings into array. values defined in macros and tables are
+ * eliminated - they are directly loaded in appropriate variables
+ */
+
+ /* loop 1 and 2 */
+ __asm__ volatile (
+ "lwc1 %[in1], 17*4(%[in]) \t\n"
+ "lwc1 %[in2], 16*4(%[in]) \t\n"
+ "lwc1 %[in3], 15*4(%[in]) \t\n"
+ "lwc1 %[in4], 14*4(%[in]) \t\n"
+ "lwc1 %[in5], 13*4(%[in]) \t\n"
+ "lwc1 %[in6], 12*4(%[in]) \t\n"
+ "add.s %[out1], %[in1], %[in2] \t\n"
+ "add.s %[out2], %[in2], %[in3] \t\n"
+ "add.s %[out3], %[in3], %[in4] \t\n"
+ "add.s %[out4], %[in4], %[in5] \t\n"
+ "add.s %[out5], %[in5], %[in6] \t\n"
+ "lwc1 %[in1], 11*4(%[in]) \t\n"
+ "swc1 %[out2], 16*4(%[in]) \t\n"
+ "add.s %[out1], %[out1], %[out3] \t\n"
+ "swc1 %[out4], 14*4(%[in]) \t\n"
+ "add.s %[out3], %[out3], %[out5] \t\n"
+ "lwc1 %[in2], 10*4(%[in]) \t\n"
+ "lwc1 %[in3], 9*4(%[in]) \t\n"
+ "swc1 %[out1], 17*4(%[in]) \t\n"
+ "lwc1 %[in4], 8*4(%[in]) \t\n"
+ "swc1 %[out3], 15*4(%[in]) \t\n"
+ "add.s %[out1], %[in6], %[in1] \t\n"
+ "add.s %[out2], %[in1], %[in2] \t\n"
+ "add.s %[out3], %[in2], %[in3] \t\n"
+ "add.s %[out4], %[in3], %[in4] \t\n"
+ "lwc1 %[in5], 7*4(%[in]) \t\n"
+ "swc1 %[out1], 12*4(%[in]) \t\n"
+ "add.s %[out5], %[out5], %[out2] \t\n"
+ "swc1 %[out3], 10*4(%[in]) \t\n"
+ "add.s %[out2], %[out2], %[out4] \t\n"
+ "lwc1 %[in6], 6*4(%[in]) \t\n"
+ "lwc1 %[in1], 5*4(%[in]) \t\n"
+ "swc1 %[out5], 13*4(%[in]) \t\n"
+ "lwc1 %[in2], 4*4(%[in]) \t\n"
+ "swc1 %[out2], 11*4(%[in]) \t\n"
+ "add.s %[out5], %[in4], %[in5] \t\n"
+ "add.s %[out1], %[in5], %[in6] \t\n"
+ "add.s %[out2], %[in6], %[in1] \t\n"
+ "add.s %[out3], %[in1], %[in2] \t\n"
+ "lwc1 %[in3], 3*4(%[in]) \t\n"
+ "swc1 %[out5], 8*4(%[in]) \t\n"
+ "add.s %[out4], %[out4], %[out1] \t\n"
+ "swc1 %[out2], 6*4(%[in]) \t\n"
+ "add.s %[out1], %[out1], %[out3] \t\n"
+ "lwc1 %[in4], 2*4(%[in]) \t\n"
+ "lwc1 %[in5], 1*4(%[in]) \t\n"
+ "swc1 %[out4], 9*4(%[in]) \t\n"
+ "lwc1 %[in6], 0(%[in]) \t\n"
+ "swc1 %[out1], 7*4(%[in]) \t\n"
+ "add.s %[out4], %[in2], %[in3] \t\n"
+ "add.s %[out5], %[in3], %[in4] \t\n"
+ "add.s %[out1], %[in4], %[in5] \t\n"
+ "add.s %[out2], %[in5], %[in6] \t\n"
+ "swc1 %[out4], 4*4(%[in]) \t\n"
+ "add.s %[out3], %[out3], %[out5] \t\n"
+ "swc1 %[out1], 2*4(%[in]) \t\n"
+ "add.s %[out5], %[out5], %[out2] \t\n"
+ "swc1 %[out2], 1*4(%[in]) \t\n"
+ "swc1 %[out3], 5*4(%[in]) \t\n"
+ "swc1 %[out5], 3*4(%[in]) \t\n"
+
+ : [in1] "=&f" (in1), [in2] "=&f" (in2),
+ [in3] "=&f" (in3), [in4] "=&f" (in4),
+ [in5] "=&f" (in5), [in6] "=&f" (in6),
+ [out1] "=&f" (out1), [out2] "=&f" (out2),
+ [out3] "=&f" (out3), [out4] "=&f" (out4),
+ [out5] "=&f" (out5)
+ : [in] "r" (in)
+ : "memory"
+ );
+
+ /* loop 3 */
+ __asm__ volatile (
+ "li.s %[c1], 0.5 \t\n"
+ "lwc1 %[in1], 8*4(%[in]) \t\n"
+ "lwc1 %[in2], 16*4(%[in]) \t\n"
+ "lwc1 %[in3], 4*4(%[in]) \t\n"
+ "lwc1 %[in4], 0(%[in]) \t\n"
+ "lwc1 %[in5], 12*4(%[in]) \t\n"
+ "li.s %[c2], 0.93969262078590838405 \t\n"
+ "add.s %[t2], %[in1], %[in2] \t\n"
+ "add.s %[t0], %[in1], %[in3] \t\n"
+ "li.s %[c3], -0.76604444311897803520 \t\n"
+ "madd.s %[t3], %[in4], %[in5], %[c1] \t\n"
+ "sub.s %[t1], %[in4], %[in5] \t\n"
+ "sub.s %[t2], %[t2], %[in3] \t\n"
+ "mul.s %[t0], %[t0], %[c2] \t\n"
+ "li.s %[c4], -0.17364817766693034885 \t\n"
+ "li.s %[c5], -0.86602540378443864676 \t\n"
+ "li.s %[c6], 0.98480775301220805936 \t\n"
+ "nmsub.s %[out1], %[t1], %[t2], %[c1] \t\n"
+ "add.s %[out2], %[t1], %[t2] \t\n"
+ "add.s %[t2], %[in2], %[in3] \t\n"
+ "sub.s %[t1], %[in1], %[in2] \t\n"
+ "sub.s %[out3], %[t3], %[t0] \t\n"
+ "swc1 %[out1], 6*4(%[tmp]) \t\n"
+ "swc1 %[out2], 16*4(%[tmp]) \t\n"
+ "mul.s %[t2], %[t2], %[c3] \t\n"
+ "mul.s %[t1], %[t1], %[c4] \t\n"
+ "add.s %[out1], %[t3], %[t0] \t\n"
+ "lwc1 %[in1], 10*4(%[in]) \t\n"
+ "lwc1 %[in2], 14*4(%[in]) \t\n"
+ "sub.s %[out3], %[out3], %[t2] \t\n"
+ "add.s %[out2], %[t3], %[t2] \t\n"
+ "add.s %[out1], %[out1], %[t1] \t\n"
+ "lwc1 %[in3], 2*4(%[in]) \t\n"
+ "lwc1 %[in4], 6*4(%[in]) \t\n"
+ "swc1 %[out3], 10*4(%[tmp]) \t\n"
+ "sub.s %[out2], %[out2], %[t1] \t\n"
+ "swc1 %[out1], 2*4(%[tmp]) \t\n"
+ "add.s %[out1], %[in1], %[in2] \t\n"
+ "add.s %[t2], %[in1], %[in3] \t\n"
+ "sub.s %[t3], %[in1], %[in2] \t\n"
+ "swc1 %[out2], 14*4(%[tmp]) \t\n"
+ "li.s %[c7], -0.34202014332566873304 \t\n"
+ "sub.s %[out1], %[out1], %[in3] \t\n"
+ "mul.s %[t2], %[t2], %[c6] \t\n"
+ "mul.s %[t3], %[t3], %[c7] \t\n"
+ "li.s %[c8], 0.86602540378443864676 \t\n"
+ "mul.s %[t0], %[in4], %[c8] \t\n"
+ "mul.s %[out1], %[out1], %[c5] \t\n"
+ "add.s %[t1], %[in2], %[in3] \t\n"
+ "li.s %[c9], -0.64278760968653932632 \t\n"
+ "add.s %[out2], %[t2], %[t3] \t\n"
+ "lwc1 %[in1], 9*4(%[in]) \t\n"
+ "swc1 %[out1], 4*4(%[tmp]) \t\n"
+ "mul.s %[t1], %[t1], %[c9] \t\n"
+ "lwc1 %[in2], 17*4(%[in]) \t\n"
+ "add.s %[out2], %[out2], %[t0] \t\n"
+ "lwc1 %[in3], 5*4(%[in]) \t\n"
+ "lwc1 %[in4], 1*4(%[in]) \t\n"
+ "add.s %[out3], %[t2], %[t1] \t\n"
+ "sub.s %[out1], %[t3], %[t1] \t\n"
+ "swc1 %[out2], 0(%[tmp]) \t\n"
+ "lwc1 %[in5], 13*4(%[in]) \t\n"
+ "add.s %[t2], %[in1], %[in2] \t\n"
+ "sub.s %[out3], %[out3], %[t0] \t\n"
+ "sub.s %[out1], %[out1], %[t0] \t\n"
+ "add.s %[t0], %[in1], %[in3] \t\n"
+ "madd.s %[t3], %[in4], %[in5], %[c1] \t\n"
+ "sub.s %[t2], %[t2], %[in3] \t\n"
+ "swc1 %[out3], 12*4(%[tmp]) \t\n"
+ "swc1 %[out1], 8*4(%[tmp]) \t\n"
+ "sub.s %[t1], %[in4], %[in5] \t\n"
+ "mul.s %[t0], %[t0], %[c2] \t\n"
+ "nmsub.s %[out1], %[t1], %[t2], %[c1] \t\n"
+ "add.s %[out2], %[t1], %[t2] \t\n"
+ "add.s %[t2], %[in2], %[in3] \t\n"
+ "sub.s %[t1], %[in1], %[in2] \t\n"
+ "sub.s %[out3], %[t3], %[t0] \t\n"
+ "swc1 %[out1], 7*4(%[tmp]) \t\n"
+ "swc1 %[out2], 17*4(%[tmp]) \t\n"
+ "mul.s %[t2], %[t2], %[c3] \t\n"
+ "mul.s %[t1], %[t1], %[c4] \t\n"
+ "add.s %[out1], %[t3], %[t0] \t\n"
+ "lwc1 %[in1], 11*4(%[in]) \t\n"
+ "lwc1 %[in2], 15*4(%[in]) \t\n"
+ "sub.s %[out3], %[out3], %[t2] \t\n"
+ "add.s %[out2], %[t3], %[t2] \t\n"
+ "add.s %[out1], %[out1], %[t1] \t\n"
+ "lwc1 %[in3], 3*4(%[in]) \t\n"
+ "lwc1 %[in4], 7*4(%[in]) \t\n"
+ "swc1 %[out3], 11*4(%[tmp]) \t\n"
+ "sub.s %[out2], %[out2], %[t1] \t\n"
+ "swc1 %[out1], 3*4(%[tmp]) \t\n"
+ "add.s %[out3], %[in1], %[in2] \t\n"
+ "add.s %[t2], %[in1], %[in3] \t\n"
+ "sub.s %[t3], %[in1], %[in2] \t\n"
+ "swc1 %[out2], 15*4(%[tmp]) \t\n"
+ "mul.s %[t0], %[in4], %[c8] \t\n"
+ "sub.s %[out3], %[out3], %[in3] \t\n"
+ "mul.s %[t2], %[t2], %[c6] \t\n"
+ "mul.s %[t3], %[t3], %[c7] \t\n"
+ "add.s %[t1], %[in2], %[in3] \t\n"
+ "mul.s %[out3], %[out3], %[c5] \t\n"
+ "add.s %[out1], %[t2], %[t3] \t\n"
+ "mul.s %[t1], %[t1], %[c9] \t\n"
+ "swc1 %[out3], 5*4(%[tmp]) \t\n"
+ "add.s %[out1], %[out1], %[t0] \t\n"
+ "add.s %[out2], %[t2], %[t1] \t\n"
+ "sub.s %[out3], %[t3], %[t1] \t\n"
+ "swc1 %[out1], 1*4(%[tmp]) \t\n"
+ "sub.s %[out2], %[out2], %[t0] \t\n"
+ "sub.s %[out3], %[out3], %[t0] \t\n"
+ "swc1 %[out2], 13*4(%[tmp]) \t\n"
+ "swc1 %[out3], 9*4(%[tmp]) \t\n"
+
+ : [t0] "=&f" (t0), [t1] "=&f" (t1),
+ [t2] "=&f" (t2), [t3] "=&f" (t3),
+ [in1] "=&f" (in1), [in2] "=&f" (in2),
+ [in3] "=&f" (in3), [in4] "=&f" (in4),
+ [in5] "=&f" (in5),
+ [out1] "=&f" (out1), [out2] "=&f" (out2),
+ [out3] "=&f" (out3),
+ [c1] "=&f" (c1), [c2] "=&f" (c2),
+ [c3] "=&f" (c3), [c4] "=&f" (c4),
+ [c5] "=&f" (c5), [c6] "=&f" (c6),
+ [c7] "=&f" (c7), [c8] "=&f" (c8),
+ [c9] "=&f" (c9)
+ : [in] "r" (in), [tmp] "r" (tmp)
+ : "memory"
+ );
+
+ /* loop 4 */
+ __asm__ volatile (
+ "lwc1 %[in1], 2*4(%[tmp]) \t\n"
+ "lwc1 %[in2], 0(%[tmp]) \t\n"
+ "lwc1 %[in3], 3*4(%[tmp]) \t\n"
+ "lwc1 %[in4], 1*4(%[tmp]) \t\n"
+ "li.s %[c1], 0.50190991877167369479 \t\n"
+ "li.s %[c2], 5.73685662283492756461 \t\n"
+ "add.s %[s0], %[in1], %[in2] \t\n"
+ "sub.s %[s2], %[in1], %[in2] \t\n"
+ "add.s %[s1], %[in3], %[in4] \t\n"
+ "sub.s %[s3], %[in3], %[in4] \t\n"
+ "lwc1 %[in1], 9*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*9*4(%[buf]) \t\n"
+ "lwc1 %[in3], 8*4(%[win]) \t\n"
+ "mul.s %[s1], %[s1], %[c1] \t\n"
+ "mul.s %[s3], %[s3], %[c2] \t\n"
+ "lwc1 %[in4], 4*8*4(%[buf]) \t\n"
+ "lwc1 %[in5], 29*4(%[win]) \t\n"
+ "lwc1 %[in6], 28*4(%[win]) \t\n"
+ "add.s %[t0], %[s0], %[s1] \t\n"
+ "sub.s %[t1], %[s0], %[s1] \t\n"
+ "li.s %[c1], 0.51763809020504152469 \t\n"
+ "li.s %[c2], 1.93185165257813657349 \t\n"
+ "mul.s %[out3], %[in5], %[t0] \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out4], %[in6], %[t0] \t\n"
+ "add.s %[t0], %[s2], %[s3] \t\n"
+ "swc1 %[out3], 4*9*4(%[buf]) \t\n"
+ "swc1 %[out1], 288*4(%[out]) \t\n"
+ "swc1 %[out2], 256*4(%[out]) \t\n"
+ "swc1 %[out4], 4*8*4(%[buf]) \t\n"
+ "sub.s %[t1], %[s2], %[s3] \t\n"
+ "lwc1 %[in1], 17*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*17*4(%[buf]) \t\n"
+ "lwc1 %[in3], 0(%[win]) \t\n"
+ "lwc1 %[in4], 0(%[buf]) \t\n"
+ "lwc1 %[in5], 37*4(%[win]) \t\n"
+ "lwc1 %[in6], 20*4(%[win]) \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "lwc1 %[in1], 6*4(%[tmp]) \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out3], %[t0], %[in5] \t\n"
+ "mul.s %[out4], %[t0], %[in6] \t\n"
+ "swc1 %[out1], 544*4(%[out]) \t\n"
+ "lwc1 %[in2], 4*4(%[tmp]) \t\n"
+ "swc1 %[out2], 0(%[out]) \t\n"
+ "swc1 %[out3], 4*17*4(%[buf]) \t\n"
+ "swc1 %[out4], 0(%[buf]) \t\n"
+ "lwc1 %[in3], 7*4(%[tmp]) \t\n"
+ "add.s %[s0], %[in1], %[in2] \t\n"
+ "sub.s %[s2], %[in1], %[in2] \t\n"
+ "lwc1 %[in4], 5*4(%[tmp]) \t\n"
+ "add.s %[s1], %[in3], %[in4] \t\n"
+ "sub.s %[s3], %[in3], %[in4] \t\n"
+ "lwc1 %[in1], 10*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*10*4(%[buf]) \t\n"
+ "lwc1 %[in3], 7*4(%[win]) \t\n"
+ "mul.s %[s1], %[s1], %[c1] \t\n"
+ "mul.s %[s3], %[s3], %[c2] \t\n"
+ "add.s %[t0], %[s0], %[s1] \t\n"
+ "sub.s %[t1], %[s0], %[s1] \t\n"
+ "lwc1 %[in4], 4*7*4(%[buf]) \t\n"
+ "lwc1 %[in5], 30*4(%[win]) \t\n"
+ "lwc1 %[in6], 27*4(%[win]) \t\n"
+ "li.s %[c1], 0.55168895948124587824 \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out3], %[t0], %[in5] \t\n"
+ "mul.s %[out4], %[t0], %[in6] \t\n"
+ "add.s %[t0], %[s2], %[s3] \t\n"
+ "swc1 %[out1], 320*4(%[out]) \t\n"
+ "swc1 %[out2], 224*4(%[out]) \t\n"
+ "swc1 %[out3], 4*10*4(%[buf]) \t\n"
+ "swc1 %[out4], 4*7*4(%[buf]) \t\n"
+ "sub.s %[t1], %[s2], %[s3] \t\n"
+ "lwc1 %[in1], 16*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*16*4(%[buf]) \t\n"
+ "lwc1 %[in3], 1*4(%[win]) \t\n"
+ "lwc1 %[in4], 4*1*4(%[buf]) \t\n"
+ "lwc1 %[in5], 36*4(%[win]) \t\n"
+ "lwc1 %[in6], 21*4(%[win]) \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "lwc1 %[in1], 10*4(%[tmp]) \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out3], %[in5], %[t0] \t\n"
+ "mul.s %[out4], %[in6], %[t0] \t\n"
+ "swc1 %[out1], 512*4(%[out]) \t\n"
+ "lwc1 %[in2], 8*4(%[tmp]) \t\n"
+ "swc1 %[out2], 32*4(%[out]) \t\n"
+ "swc1 %[out3], 4*16*4(%[buf]) \t\n"
+ "swc1 %[out4], 4*1*4(%[buf]) \t\n"
+ "li.s %[c2], 1.18310079157624925896 \t\n"
+ "add.s %[s0], %[in1], %[in2] \t\n"
+ "sub.s %[s2], %[in1], %[in2] \t\n"
+ "lwc1 %[in3], 11*4(%[tmp]) \t\n"
+ "lwc1 %[in4], 9*4(%[tmp]) \t\n"
+ "add.s %[s1], %[in3], %[in4] \t\n"
+ "sub.s %[s3], %[in3], %[in4] \t\n"
+ "lwc1 %[in1], 11*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*11*4(%[buf]) \t\n"
+ "lwc1 %[in3], 6*4(%[win]) \t\n"
+ "mul.s %[s1], %[s1], %[c1] \t\n"
+ "mul.s %[s3], %[s3], %[c2] \t\n"
+ "lwc1 %[in4], 4*6*4(%[buf]) \t\n"
+ "lwc1 %[in5], 31*4(%[win]) \t\n"
+ "lwc1 %[in6], 26*4(%[win]) \t\n"
+ "add.s %[t0], %[s0], %[s1] \t\n"
+ "sub.s %[t1], %[s0], %[s1] \t\n"
+ "mul.s %[out3], %[t0], %[in5] \t\n"
+ "mul.s %[out4], %[t0], %[in6] \t\n"
+ "add.s %[t0], %[s2], %[s3] \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "swc1 %[out3], 4*11*4(%[buf]) \t\n"
+ "swc1 %[out4], 4*6*4(%[buf]) \t\n"
+ "sub.s %[t1], %[s2], %[s3] \t\n"
+ "swc1 %[out1], 352*4(%[out]) \t\n"
+ "swc1 %[out2], 192*4(%[out]) \t\n"
+ "lwc1 %[in1], 15*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*15*4(%[buf]) \t\n"
+ "lwc1 %[in3], 2*4(%[win]) \t\n"
+ "lwc1 %[in4], 4*2*4(%[buf]) \t\n"
+ "lwc1 %[in5], 35*4(%[win]) \t\n"
+ "lwc1 %[in6], 22*4(%[win]) \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "lwc1 %[in1], 14*4(%[tmp]) \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out3], %[t0], %[in5] \t\n"
+ "mul.s %[out4], %[t0], %[in6] \t\n"
+ "swc1 %[out1], 480*4(%[out]) \t\n"
+ "lwc1 %[in2], 12*4(%[tmp]) \t\n"
+ "swc1 %[out2], 64*4(%[out]) \t\n"
+ "swc1 %[out3], 4*15*4(%[buf]) \t\n"
+ "swc1 %[out4], 4*2*4(%[buf]) \t\n"
+ "lwc1 %[in3], 15*4(%[tmp]) \t\n"
+ "add.s %[s0], %[in1], %[in2] \t\n"
+ "sub.s %[s2], %[in1], %[in2] \t\n"
+ "lwc1 %[in4], 13*4(%[tmp]) \t\n"
+ "li.s %[c1], 0.61038729438072803416 \t\n"
+ "li.s %[c2], 0.87172339781054900991 \t\n"
+ "add.s %[s1], %[in3], %[in4] \t\n"
+ "sub.s %[s3], %[in3], %[in4] \t\n"
+ "lwc1 %[in1], 12*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*12*4(%[buf]) \t\n"
+ "lwc1 %[in3], 5*4(%[win]) \t\n"
+ "mul.s %[s1], %[s1], %[c1] \t\n"
+ "mul.s %[s3], %[s3], %[c2] \t\n"
+ "lwc1 %[in4], 4*5*4(%[buf]) \t\n"
+ "lwc1 %[in5], 32*4(%[win]) \t\n"
+ "lwc1 %[in6], 25*4(%[win]) \t\n"
+ "add.s %[t0], %[s0], %[s1] \t\n"
+ "sub.s %[t1], %[s0], %[s1] \t\n"
+ "lwc1 %[s0], 16*4(%[tmp]) \t\n"
+ "lwc1 %[s1], 17*4(%[tmp]) \t\n"
+ "li.s %[c1], 0.70710678118654752439 \t\n"
+ "mul.s %[out3], %[t0], %[in5] \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out4], %[t0], %[in6] \t\n"
+ "add.s %[t0], %[s2], %[s3] \t\n"
+ "swc1 %[out3], 4*12*4(%[buf]) \t\n"
+ "swc1 %[out1], 384*4(%[out]) \t\n"
+ "swc1 %[out2], 160*4(%[out]) \t\n"
+ "swc1 %[out4], 4*5*4(%[buf]) \t\n"
+ "sub.s %[t1], %[s2], %[s3] \t\n"
+ "lwc1 %[in1], 14*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*14*4(%[buf]) \t\n"
+ "lwc1 %[in3], 3*4(%[win]) \t\n"
+ "lwc1 %[in4], 4*3*4(%[buf]) \t\n"
+ "lwc1 %[in5], 34*4(%[win]) \t\n"
+ "lwc1 %[in6], 23*4(%[win]) \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "mul.s %[s1], %[s1], %[c1] \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out3], %[in5], %[t0] \t\n"
+ "mul.s %[out4], %[in6], %[t0] \t\n"
+ "swc1 %[out1], 448*4(%[out]) \t\n"
+ "add.s %[t0], %[s0], %[s1] \t\n"
+ "swc1 %[out2], 96*4(%[out]) \t\n"
+ "swc1 %[out3], 4*14*4(%[buf]) \t\n"
+ "swc1 %[out4], 4*3*4(%[buf]) \t\n"
+ "sub.s %[t1], %[s0], %[s1] \t\n"
+ "lwc1 %[in1], 13*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*13*4(%[buf]) \t\n"
+ "lwc1 %[in3], 4*4(%[win]) \t\n"
+ "lwc1 %[in4], 4*4*4(%[buf]) \t\n"
+ "lwc1 %[in5], 33*4(%[win]) \t\n"
+ "lwc1 %[in6], 24*4(%[win]) \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out3], %[t0], %[in5] \t\n"
+ "mul.s %[out4], %[t0], %[in6] \t\n"
+ "swc1 %[out1], 416*4(%[out]) \t\n"
+ "swc1 %[out2], 128*4(%[out]) \t\n"
+ "swc1 %[out3], 4*13*4(%[buf]) \t\n"
+ "swc1 %[out4], 4*4*4(%[buf]) \t\n"
+
+ : [c1] "=&f" (c1), [c2] "=&f" (c2),
+ [in1] "=&f" (in1), [in2] "=&f" (in2),
+ [in3] "=&f" (in3), [in4] "=&f" (in4),
+ [in5] "=&f" (in5), [in6] "=&f" (in6),
+ [out1] "=&f" (out1), [out2] "=&f" (out2),
+ [out3] "=&f" (out3), [out4] "=&f" (out4),
+ [t0] "=&f" (t0), [t1] "=&f" (t1),
+ [t2] "=&f" (t2), [t3] "=&f" (t3),
+ [s0] "=&f" (s0), [s1] "=&f" (s1),
+ [s2] "=&f" (s2), [s3] "=&f" (s3)
+ : [tmp] "r" (tmp), [win] "r" (win),
+ [buf] "r" (buf), [out] "r" (out)
+ : "memory"
+ );
+}
+
+static void ff_imdct36_blocks_mips_float(float *out, float *buf, float *in,
+ int count, int switch_point, int block_type)
+{
+ int j;
+ for (j=0 ; j < count; j++) {
+ /* apply window & overlap with previous buffer */
+
+ /* select window */
+ int win_idx = (switch_point && j < 2) ? 0 : block_type;
+ float *win = ff_mdct_win_float[win_idx + (4 & -(j & 1))];
+
+ imdct36_mips_float(out, buf, in, win);
+
+ in += 18;
+ buf += ((j&3) != 3 ? 1 : (72-3));
+ out++;
+ }
+}
+
+void ff_mpadsp_init_mipsfpu(MPADSPContext *s)
+{
+ s->apply_window_float = ff_mpadsp_apply_window_mips_float;
+ s->imdct36_blocks_float = ff_imdct36_blocks_mips_float;
+ s->dct32_float = ff_dct32_mips_float;
+}
diff --git a/libavcodec/mips/sbrdsp_mips.c b/libavcodec/mips/sbrdsp_mips.c
new file mode 100644
index 0000000..d4460ba
--- /dev/null
+++ b/libavcodec/mips/sbrdsp_mips.c
@@ -0,0 +1,940 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Authors: Darko Laus (darko@mips.com)
+ * Djordje Pesut (djordje@mips.com)
+ * Mirjana Vulin (mvulin@mips.com)
+ *
+ * AAC Spectral Band Replication decoding functions optimized for MIPS
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/sbrdsp.c
+ */
+
+#include "config.h"
+#include "libavcodec/sbrdsp.h"
+
+#if HAVE_INLINE_ASM
+static void sbr_neg_odd_64_mips(float *x)
+{
+ int Temp1, Temp2, Temp3, Temp4, Temp5;
+ float *x1 = &x[1];
+ float *x_end = x1 + 64;
+
+ /* loop unrolled 4 times */
+ __asm__ volatile (
+ "lui %[Temp5], 0x8000 \n\t"
+ "1: \n\t"
+ "lw %[Temp1], 0(%[x1]) \n\t"
+ "lw %[Temp2], 8(%[x1]) \n\t"
+ "lw %[Temp3], 16(%[x1]) \n\t"
+ "lw %[Temp4], 24(%[x1]) \n\t"
+ "xor %[Temp1], %[Temp1], %[Temp5] \n\t"
+ "xor %[Temp2], %[Temp2], %[Temp5] \n\t"
+ "xor %[Temp3], %[Temp3], %[Temp5] \n\t"
+ "xor %[Temp4], %[Temp4], %[Temp5] \n\t"
+ "sw %[Temp1], 0(%[x1]) \n\t"
+ "sw %[Temp2], 8(%[x1]) \n\t"
+ "sw %[Temp3], 16(%[x1]) \n\t"
+ "sw %[Temp4], 24(%[x1]) \n\t"
+ "addiu %[x1], %[x1], 32 \n\t"
+ "bne %[x1], %[x_end], 1b \n\t"
+
+ : [Temp1]"=&r"(Temp1), [Temp2]"=&r"(Temp2),
+ [Temp3]"=&r"(Temp3), [Temp4]"=&r"(Temp4),
+ [Temp5]"=&r"(Temp5), [x1]"+r"(x1)
+ : [x_end]"r"(x_end)
+ : "memory"
+ );
+}
+
+static void sbr_qmf_pre_shuffle_mips(float *z)
+{
+ int Temp1, Temp2, Temp3, Temp4, Temp5, Temp6;
+ float *z1 = &z[66];
+ float *z2 = &z[59];
+ float *z3 = &z[2];
+ float *z4 = z1 + 60;
+
+ /* loop unrolled 5 times */
+ __asm__ volatile (
+ "lui %[Temp6], 0x8000 \n\t"
+ "1: \n\t"
+ "lw %[Temp1], 0(%[z2]) \n\t"
+ "lw %[Temp2], 4(%[z2]) \n\t"
+ "lw %[Temp3], 8(%[z2]) \n\t"
+ "lw %[Temp4], 12(%[z2]) \n\t"
+ "lw %[Temp5], 16(%[z2]) \n\t"
+ "xor %[Temp1], %[Temp1], %[Temp6] \n\t"
+ "xor %[Temp2], %[Temp2], %[Temp6] \n\t"
+ "xor %[Temp3], %[Temp3], %[Temp6] \n\t"
+ "xor %[Temp4], %[Temp4], %[Temp6] \n\t"
+ "xor %[Temp5], %[Temp5], %[Temp6] \n\t"
+ "addiu %[z2], %[z2], -20 \n\t"
+ "sw %[Temp1], 32(%[z1]) \n\t"
+ "sw %[Temp2], 24(%[z1]) \n\t"
+ "sw %[Temp3], 16(%[z1]) \n\t"
+ "sw %[Temp4], 8(%[z1]) \n\t"
+ "sw %[Temp5], 0(%[z1]) \n\t"
+ "lw %[Temp1], 0(%[z3]) \n\t"
+ "lw %[Temp2], 4(%[z3]) \n\t"
+ "lw %[Temp3], 8(%[z3]) \n\t"
+ "lw %[Temp4], 12(%[z3]) \n\t"
+ "lw %[Temp5], 16(%[z3]) \n\t"
+ "sw %[Temp1], 4(%[z1]) \n\t"
+ "sw %[Temp2], 12(%[z1]) \n\t"
+ "sw %[Temp3], 20(%[z1]) \n\t"
+ "sw %[Temp4], 28(%[z1]) \n\t"
+ "sw %[Temp5], 36(%[z1]) \n\t"
+ "addiu %[z3], %[z3], 20 \n\t"
+ "addiu %[z1], %[z1], 40 \n\t"
+ "bne %[z1], %[z4], 1b \n\t"
+ "lw %[Temp1], 132(%[z]) \n\t"
+ "lw %[Temp2], 128(%[z]) \n\t"
+ "lw %[Temp3], 0(%[z]) \n\t"
+ "lw %[Temp4], 4(%[z]) \n\t"
+ "xor %[Temp1], %[Temp1], %[Temp6] \n\t"
+ "sw %[Temp1], 504(%[z]) \n\t"
+ "sw %[Temp2], 508(%[z]) \n\t"
+ "sw %[Temp3], 256(%[z]) \n\t"
+ "sw %[Temp4], 260(%[z]) \n\t"
+
+ : [Temp1]"=&r"(Temp1), [Temp2]"=&r"(Temp2),
+ [Temp3]"=&r"(Temp3), [Temp4]"=&r"(Temp4),
+ [Temp5]"=&r"(Temp5), [Temp6]"=&r"(Temp6),
+ [z1]"+r"(z1), [z2]"+r"(z2), [z3]"+r"(z3)
+ : [z4]"r"(z4), [z]"r"(z)
+ : "memory"
+ );
+}
+
+static void sbr_qmf_post_shuffle_mips(float W[32][2], const float *z)
+{
+ int Temp1, Temp2, Temp3, Temp4, Temp5;
+ float *W_ptr = (float *)W;
+ float *z1 = (float *)z;
+ float *z2 = (float *)&z[60];
+ float *z_end = z1 + 32;
+
+ /* loop unrolled 4 times */
+ __asm__ volatile (
+ "lui %[Temp5], 0x8000 \n\t"
+ "1: \n\t"
+ "lw %[Temp1], 0(%[z2]) \n\t"
+ "lw %[Temp2], 4(%[z2]) \n\t"
+ "lw %[Temp3], 8(%[z2]) \n\t"
+ "lw %[Temp4], 12(%[z2]) \n\t"
+ "xor %[Temp1], %[Temp1], %[Temp5] \n\t"
+ "xor %[Temp2], %[Temp2], %[Temp5] \n\t"
+ "xor %[Temp3], %[Temp3], %[Temp5] \n\t"
+ "xor %[Temp4], %[Temp4], %[Temp5] \n\t"
+ "addiu %[z2], %[z2], -16 \n\t"
+ "sw %[Temp1], 24(%[W_ptr]) \n\t"
+ "sw %[Temp2], 16(%[W_ptr]) \n\t"
+ "sw %[Temp3], 8(%[W_ptr]) \n\t"
+ "sw %[Temp4], 0(%[W_ptr]) \n\t"
+ "lw %[Temp1], 0(%[z1]) \n\t"
+ "lw %[Temp2], 4(%[z1]) \n\t"
+ "lw %[Temp3], 8(%[z1]) \n\t"
+ "lw %[Temp4], 12(%[z1]) \n\t"
+ "sw %[Temp1], 4(%[W_ptr]) \n\t"
+ "sw %[Temp2], 12(%[W_ptr]) \n\t"
+ "sw %[Temp3], 20(%[W_ptr]) \n\t"
+ "sw %[Temp4], 28(%[W_ptr]) \n\t"
+ "addiu %[z1], %[z1], 16 \n\t"
+ "addiu %[W_ptr], %[W_ptr], 32 \n\t"
+ "bne %[z1], %[z_end], 1b \n\t"
+
+ : [Temp1]"=&r"(Temp1), [Temp2]"=&r"(Temp2),
+ [Temp3]"=&r"(Temp3), [Temp4]"=&r"(Temp4),
+ [Temp5]"=&r"(Temp5), [z1]"+r"(z1),
+ [z2]"+r"(z2), [W_ptr]"+r"(W_ptr)
+ : [z_end]"r"(z_end)
+ : "memory"
+ );
+}
+
+#if HAVE_MIPSFPU
+static void sbr_sum64x5_mips(float *z)
+{
+ int k;
+ float *z1;
+ float f1, f2, f3, f4, f5, f6, f7, f8;
+ for (k = 0; k < 64; k += 8) {
+
+ z1 = &z[k];
+
+ /* loop unrolled 8 times */
+ __asm__ volatile (
+ "lwc1 $f0, 0(%[z1]) \n\t"
+ "lwc1 $f1, 256(%[z1]) \n\t"
+ "lwc1 $f2, 4(%[z1]) \n\t"
+ "lwc1 $f3, 260(%[z1]) \n\t"
+ "lwc1 $f4, 8(%[z1]) \n\t"
+ "add.s %[f1], $f0, $f1 \n\t"
+ "lwc1 $f5, 264(%[z1]) \n\t"
+ "add.s %[f2], $f2, $f3 \n\t"
+ "lwc1 $f6, 12(%[z1]) \n\t"
+ "lwc1 $f7, 268(%[z1]) \n\t"
+ "add.s %[f3], $f4, $f5 \n\t"
+ "lwc1 $f8, 16(%[z1]) \n\t"
+ "lwc1 $f9, 272(%[z1]) \n\t"
+ "add.s %[f4], $f6, $f7 \n\t"
+ "lwc1 $f10, 20(%[z1]) \n\t"
+ "lwc1 $f11, 276(%[z1]) \n\t"
+ "add.s %[f5], $f8, $f9 \n\t"
+ "lwc1 $f12, 24(%[z1]) \n\t"
+ "lwc1 $f13, 280(%[z1]) \n\t"
+ "add.s %[f6], $f10, $f11 \n\t"
+ "lwc1 $f14, 28(%[z1]) \n\t"
+ "lwc1 $f15, 284(%[z1]) \n\t"
+ "add.s %[f7], $f12, $f13 \n\t"
+ "lwc1 $f0, 512(%[z1]) \n\t"
+ "lwc1 $f1, 516(%[z1]) \n\t"
+ "add.s %[f8], $f14, $f15 \n\t"
+ "lwc1 $f2, 520(%[z1]) \n\t"
+ "add.s %[f1], %[f1], $f0 \n\t"
+ "add.s %[f2], %[f2], $f1 \n\t"
+ "lwc1 $f3, 524(%[z1]) \n\t"
+ "add.s %[f3], %[f3], $f2 \n\t"
+ "lwc1 $f4, 528(%[z1]) \n\t"
+ "lwc1 $f5, 532(%[z1]) \n\t"
+ "add.s %[f4], %[f4], $f3 \n\t"
+ "lwc1 $f6, 536(%[z1]) \n\t"
+ "add.s %[f5], %[f5], $f4 \n\t"
+ "add.s %[f6], %[f6], $f5 \n\t"
+ "lwc1 $f7, 540(%[z1]) \n\t"
+ "add.s %[f7], %[f7], $f6 \n\t"
+ "lwc1 $f0, 768(%[z1]) \n\t"
+ "lwc1 $f1, 772(%[z1]) \n\t"
+ "add.s %[f8], %[f8], $f7 \n\t"
+ "lwc1 $f2, 776(%[z1]) \n\t"
+ "add.s %[f1], %[f1], $f0 \n\t"
+ "add.s %[f2], %[f2], $f1 \n\t"
+ "lwc1 $f3, 780(%[z1]) \n\t"
+ "add.s %[f3], %[f3], $f2 \n\t"
+ "lwc1 $f4, 784(%[z1]) \n\t"
+ "lwc1 $f5, 788(%[z1]) \n\t"
+ "add.s %[f4], %[f4], $f3 \n\t"
+ "lwc1 $f6, 792(%[z1]) \n\t"
+ "add.s %[f5], %[f5], $f4 \n\t"
+ "add.s %[f6], %[f6], $f5 \n\t"
+ "lwc1 $f7, 796(%[z1]) \n\t"
+ "add.s %[f7], %[f7], $f6 \n\t"
+ "lwc1 $f0, 1024(%[z1]) \n\t"
+ "lwc1 $f1, 1028(%[z1]) \n\t"
+ "add.s %[f8], %[f8], $f7 \n\t"
+ "lwc1 $f2, 1032(%[z1]) \n\t"
+ "add.s %[f1], %[f1], $f0 \n\t"
+ "add.s %[f2], %[f2], $f1 \n\t"
+ "lwc1 $f3, 1036(%[z1]) \n\t"
+ "add.s %[f3], %[f3], $f2 \n\t"
+ "lwc1 $f4, 1040(%[z1]) \n\t"
+ "lwc1 $f5, 1044(%[z1]) \n\t"
+ "add.s %[f4], %[f4], $f3 \n\t"
+ "lwc1 $f6, 1048(%[z1]) \n\t"
+ "add.s %[f5], %[f5], $f4 \n\t"
+ "add.s %[f6], %[f6], $f5 \n\t"
+ "lwc1 $f7, 1052(%[z1]) \n\t"
+ "add.s %[f7], %[f7], $f6 \n\t"
+ "swc1 %[f1], 0(%[z1]) \n\t"
+ "swc1 %[f2], 4(%[z1]) \n\t"
+ "add.s %[f8], %[f8], $f7 \n\t"
+ "swc1 %[f3], 8(%[z1]) \n\t"
+ "swc1 %[f4], 12(%[z1]) \n\t"
+ "swc1 %[f5], 16(%[z1]) \n\t"
+ "swc1 %[f6], 20(%[z1]) \n\t"
+ "swc1 %[f7], 24(%[z1]) \n\t"
+ "swc1 %[f8], 28(%[z1]) \n\t"
+
+ : [f1]"=&f"(f1), [f2]"=&f"(f2), [f3]"=&f"(f3),
+ [f4]"=&f"(f4), [f5]"=&f"(f5), [f6]"=&f"(f6),
+ [f7]"=&f"(f7), [f8]"=&f"(f8)
+ : [z1]"r"(z1)
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5",
+ "$f6", "$f7", "$f8", "$f9", "$f10", "$f11",
+ "$f12", "$f13", "$f14", "$f15",
+ "memory"
+ );
+ }
+}
+
+static float sbr_sum_square_mips(float (*x)[2], int n)
+{
+ float sum0 = 0.0f, sum1 = 0.0f;
+ float *p_x;
+ float temp0, temp1, temp2, temp3;
+ float *loop_end;
+ p_x = &x[0][0];
+ loop_end = p_x + (n >> 1)*4 - 4;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "lwc1 %[temp0], 0(%[p_x]) \n\t"
+ "lwc1 %[temp1], 4(%[p_x]) \n\t"
+ "lwc1 %[temp2], 8(%[p_x]) \n\t"
+ "lwc1 %[temp3], 12(%[p_x]) \n\t"
+ "1: \n\t"
+ "addiu %[p_x], %[p_x], 16 \n\t"
+ "madd.s %[sum0], %[sum0], %[temp0], %[temp0] \n\t"
+ "lwc1 %[temp0], 0(%[p_x]) \n\t"
+ "madd.s %[sum1], %[sum1], %[temp1], %[temp1] \n\t"
+ "lwc1 %[temp1], 4(%[p_x]) \n\t"
+ "madd.s %[sum0], %[sum0], %[temp2], %[temp2] \n\t"
+ "lwc1 %[temp2], 8(%[p_x]) \n\t"
+ "madd.s %[sum1], %[sum1], %[temp3], %[temp3] \n\t"
+ "bne %[p_x], %[loop_end], 1b \n\t"
+ " lwc1 %[temp3], 12(%[p_x]) \n\t"
+ "madd.s %[sum0], %[sum0], %[temp0], %[temp0] \n\t"
+ "madd.s %[sum1], %[sum1], %[temp1], %[temp1] \n\t"
+ "madd.s %[sum0], %[sum0], %[temp2], %[temp2] \n\t"
+ "madd.s %[sum1], %[sum1], %[temp3], %[temp3] \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [sum0]"+f"(sum0), [sum1]"+f"(sum1),
+ [p_x]"+r"(p_x)
+ : [loop_end]"r"(loop_end)
+ : "memory"
+ );
+ return sum0 + sum1;
+}
+
+static void sbr_qmf_deint_bfly_mips(float *v, const float *src0, const float *src1)
+{
+ int i;
+ float temp0, temp1, temp2, temp3, temp4, temp5;
+ float temp6, temp7, temp8, temp9, temp10, temp11;
+ float *v0 = v;
+ float *v1 = &v[127];
+ float *psrc0 = (float*)src0;
+ float *psrc1 = (float*)&src1[63];
+
+ for (i = 0; i < 4; i++) {
+
+ /* loop unrolled 16 times */
+ __asm__ volatile(
+ "lwc1 %[temp0], 0(%[src0]) \n\t"
+ "lwc1 %[temp1], 0(%[src1]) \n\t"
+ "lwc1 %[temp3], 4(%[src0]) \n\t"
+ "lwc1 %[temp4], -4(%[src1]) \n\t"
+ "lwc1 %[temp6], 8(%[src0]) \n\t"
+ "lwc1 %[temp7], -8(%[src1]) \n\t"
+ "lwc1 %[temp9], 12(%[src0]) \n\t"
+ "lwc1 %[temp10], -12(%[src1]) \n\t"
+ "add.s %[temp2], %[temp0], %[temp1] \n\t"
+ "add.s %[temp5], %[temp3], %[temp4] \n\t"
+ "add.s %[temp8], %[temp6], %[temp7] \n\t"
+ "add.s %[temp11], %[temp9], %[temp10] \n\t"
+ "sub.s %[temp0], %[temp0], %[temp1] \n\t"
+ "sub.s %[temp3], %[temp3], %[temp4] \n\t"
+ "sub.s %[temp6], %[temp6], %[temp7] \n\t"
+ "sub.s %[temp9], %[temp9], %[temp10] \n\t"
+ "swc1 %[temp2], 0(%[v1]) \n\t"
+ "swc1 %[temp0], 0(%[v0]) \n\t"
+ "swc1 %[temp5], -4(%[v1]) \n\t"
+ "swc1 %[temp3], 4(%[v0]) \n\t"
+ "swc1 %[temp8], -8(%[v1]) \n\t"
+ "swc1 %[temp6], 8(%[v0]) \n\t"
+ "swc1 %[temp11], -12(%[v1]) \n\t"
+ "swc1 %[temp9], 12(%[v0]) \n\t"
+ "lwc1 %[temp0], 16(%[src0]) \n\t"
+ "lwc1 %[temp1], -16(%[src1]) \n\t"
+ "lwc1 %[temp3], 20(%[src0]) \n\t"
+ "lwc1 %[temp4], -20(%[src1]) \n\t"
+ "lwc1 %[temp6], 24(%[src0]) \n\t"
+ "lwc1 %[temp7], -24(%[src1]) \n\t"
+ "lwc1 %[temp9], 28(%[src0]) \n\t"
+ "lwc1 %[temp10], -28(%[src1]) \n\t"
+ "add.s %[temp2], %[temp0], %[temp1] \n\t"
+ "add.s %[temp5], %[temp3], %[temp4] \n\t"
+ "add.s %[temp8], %[temp6], %[temp7] \n\t"
+ "add.s %[temp11], %[temp9], %[temp10] \n\t"
+ "sub.s %[temp0], %[temp0], %[temp1] \n\t"
+ "sub.s %[temp3], %[temp3], %[temp4] \n\t"
+ "sub.s %[temp6], %[temp6], %[temp7] \n\t"
+ "sub.s %[temp9], %[temp9], %[temp10] \n\t"
+ "swc1 %[temp2], -16(%[v1]) \n\t"
+ "swc1 %[temp0], 16(%[v0]) \n\t"
+ "swc1 %[temp5], -20(%[v1]) \n\t"
+ "swc1 %[temp3], 20(%[v0]) \n\t"
+ "swc1 %[temp8], -24(%[v1]) \n\t"
+ "swc1 %[temp6], 24(%[v0]) \n\t"
+ "swc1 %[temp11], -28(%[v1]) \n\t"
+ "swc1 %[temp9], 28(%[v0]) \n\t"
+ "lwc1 %[temp0], 32(%[src0]) \n\t"
+ "lwc1 %[temp1], -32(%[src1]) \n\t"
+ "lwc1 %[temp3], 36(%[src0]) \n\t"
+ "lwc1 %[temp4], -36(%[src1]) \n\t"
+ "lwc1 %[temp6], 40(%[src0]) \n\t"
+ "lwc1 %[temp7], -40(%[src1]) \n\t"
+ "lwc1 %[temp9], 44(%[src0]) \n\t"
+ "lwc1 %[temp10], -44(%[src1]) \n\t"
+ "add.s %[temp2], %[temp0], %[temp1] \n\t"
+ "add.s %[temp5], %[temp3], %[temp4] \n\t"
+ "add.s %[temp8], %[temp6], %[temp7] \n\t"
+ "add.s %[temp11], %[temp9], %[temp10] \n\t"
+ "sub.s %[temp0], %[temp0], %[temp1] \n\t"
+ "sub.s %[temp3], %[temp3], %[temp4] \n\t"
+ "sub.s %[temp6], %[temp6], %[temp7] \n\t"
+ "sub.s %[temp9], %[temp9], %[temp10] \n\t"
+ "swc1 %[temp2], -32(%[v1]) \n\t"
+ "swc1 %[temp0], 32(%[v0]) \n\t"
+ "swc1 %[temp5], -36(%[v1]) \n\t"
+ "swc1 %[temp3], 36(%[v0]) \n\t"
+ "swc1 %[temp8], -40(%[v1]) \n\t"
+ "swc1 %[temp6], 40(%[v0]) \n\t"
+ "swc1 %[temp11], -44(%[v1]) \n\t"
+ "swc1 %[temp9], 44(%[v0]) \n\t"
+ "lwc1 %[temp0], 48(%[src0]) \n\t"
+ "lwc1 %[temp1], -48(%[src1]) \n\t"
+ "lwc1 %[temp3], 52(%[src0]) \n\t"
+ "lwc1 %[temp4], -52(%[src1]) \n\t"
+ "lwc1 %[temp6], 56(%[src0]) \n\t"
+ "lwc1 %[temp7], -56(%[src1]) \n\t"
+ "lwc1 %[temp9], 60(%[src0]) \n\t"
+ "lwc1 %[temp10], -60(%[src1]) \n\t"
+ "add.s %[temp2], %[temp0], %[temp1] \n\t"
+ "add.s %[temp5], %[temp3], %[temp4] \n\t"
+ "add.s %[temp8], %[temp6], %[temp7] \n\t"
+ "add.s %[temp11], %[temp9], %[temp10] \n\t"
+ "sub.s %[temp0], %[temp0], %[temp1] \n\t"
+ "sub.s %[temp3], %[temp3], %[temp4] \n\t"
+ "sub.s %[temp6], %[temp6], %[temp7] \n\t"
+ "sub.s %[temp9], %[temp9], %[temp10] \n\t"
+ "swc1 %[temp2], -48(%[v1]) \n\t"
+ "swc1 %[temp0], 48(%[v0]) \n\t"
+ "swc1 %[temp5], -52(%[v1]) \n\t"
+ "swc1 %[temp3], 52(%[v0]) \n\t"
+ "swc1 %[temp8], -56(%[v1]) \n\t"
+ "swc1 %[temp6], 56(%[v0]) \n\t"
+ "swc1 %[temp11], -60(%[v1]) \n\t"
+ "swc1 %[temp9], 60(%[v0]) \n\t"
+ "addiu %[src0], %[src0], 64 \n\t"
+ "addiu %[src1], %[src1], -64 \n\t"
+ "addiu %[v0], %[v0], 64 \n\t"
+ "addiu %[v1], %[v1], -64 \n\t"
+
+ : [v0]"+r"(v0), [v1]"+r"(v1), [src0]"+r"(psrc0), [src1]"+r"(psrc1),
+ [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp8]"=&f"(temp8),
+ [temp9]"=&f"(temp9), [temp10]"=&f"(temp10), [temp11]"=&f"(temp11)
+ :
+ :"memory"
+ );
+ }
+}
+
+static void sbr_autocorrelate_mips(const float x[40][2], float phi[3][2][2])
+{
+ int i;
+ float real_sum_0 = 0.0f;
+ float real_sum_1 = 0.0f;
+ float real_sum_2 = 0.0f;
+ float imag_sum_1 = 0.0f;
+ float imag_sum_2 = 0.0f;
+ float *p_x, *p_phi;
+ float temp0, temp1, temp2, temp3, temp4, temp5, temp6;
+ float temp7, temp_r, temp_r1, temp_r2, temp_r3, temp_r4;
+ p_x = (float*)&x[0][0];
+ p_phi = &phi[0][0][0];
+
+ __asm__ volatile (
+ "lwc1 %[temp0], 8(%[p_x]) \n\t"
+ "lwc1 %[temp1], 12(%[p_x]) \n\t"
+ "lwc1 %[temp2], 16(%[p_x]) \n\t"
+ "lwc1 %[temp3], 20(%[p_x]) \n\t"
+ "lwc1 %[temp4], 24(%[p_x]) \n\t"
+ "lwc1 %[temp5], 28(%[p_x]) \n\t"
+ "mul.s %[temp_r], %[temp1], %[temp1] \n\t"
+ "mul.s %[temp_r1], %[temp1], %[temp3] \n\t"
+ "mul.s %[temp_r2], %[temp1], %[temp2] \n\t"
+ "mul.s %[temp_r3], %[temp1], %[temp5] \n\t"
+ "mul.s %[temp_r4], %[temp1], %[temp4] \n\t"
+ "madd.s %[temp_r], %[temp_r], %[temp0], %[temp0] \n\t"
+ "madd.s %[temp_r1], %[temp_r1], %[temp0], %[temp2] \n\t"
+ "msub.s %[temp_r2], %[temp_r2], %[temp0], %[temp3] \n\t"
+ "madd.s %[temp_r3], %[temp_r3], %[temp0], %[temp4] \n\t"
+ "msub.s %[temp_r4], %[temp_r4], %[temp0], %[temp5] \n\t"
+ "add.s %[real_sum_0], %[real_sum_0], %[temp_r] \n\t"
+ "add.s %[real_sum_1], %[real_sum_1], %[temp_r1] \n\t"
+ "add.s %[imag_sum_1], %[imag_sum_1], %[temp_r2] \n\t"
+ "add.s %[real_sum_2], %[real_sum_2], %[temp_r3] \n\t"
+ "add.s %[imag_sum_2], %[imag_sum_2], %[temp_r4] \n\t"
+ "addiu %[p_x], %[p_x], 8 \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [real_sum_0]"+f"(real_sum_0), [real_sum_1]"+f"(real_sum_1),
+ [imag_sum_1]"+f"(imag_sum_1), [real_sum_2]"+f"(real_sum_2),
+ [temp_r]"=&f"(temp_r), [temp_r1]"=&f"(temp_r1), [temp_r2]"=&f"(temp_r2),
+ [temp_r3]"=&f"(temp_r3), [temp_r4]"=&f"(temp_r4),
+ [p_x]"+r"(p_x), [imag_sum_2]"+f"(imag_sum_2)
+ :
+ : "memory"
+ );
+
+ for (i = 0; i < 12; i++) {
+ __asm__ volatile (
+ "lwc1 %[temp0], 8(%[p_x]) \n\t"
+ "lwc1 %[temp1], 12(%[p_x]) \n\t"
+ "lwc1 %[temp2], 16(%[p_x]) \n\t"
+ "lwc1 %[temp3], 20(%[p_x]) \n\t"
+ "lwc1 %[temp4], 24(%[p_x]) \n\t"
+ "lwc1 %[temp5], 28(%[p_x]) \n\t"
+ "mul.s %[temp_r], %[temp1], %[temp1] \n\t"
+ "mul.s %[temp_r1], %[temp1], %[temp3] \n\t"
+ "mul.s %[temp_r2], %[temp1], %[temp2] \n\t"
+ "mul.s %[temp_r3], %[temp1], %[temp5] \n\t"
+ "mul.s %[temp_r4], %[temp1], %[temp4] \n\t"
+ "madd.s %[temp_r], %[temp_r], %[temp0], %[temp0] \n\t"
+ "madd.s %[temp_r1], %[temp_r1], %[temp0], %[temp2] \n\t"
+ "msub.s %[temp_r2], %[temp_r2], %[temp0], %[temp3] \n\t"
+ "madd.s %[temp_r3], %[temp_r3], %[temp0], %[temp4] \n\t"
+ "msub.s %[temp_r4], %[temp_r4], %[temp0], %[temp5] \n\t"
+ "add.s %[real_sum_0], %[real_sum_0], %[temp_r] \n\t"
+ "add.s %[real_sum_1], %[real_sum_1], %[temp_r1] \n\t"
+ "add.s %[imag_sum_1], %[imag_sum_1], %[temp_r2] \n\t"
+ "add.s %[real_sum_2], %[real_sum_2], %[temp_r3] \n\t"
+ "add.s %[imag_sum_2], %[imag_sum_2], %[temp_r4] \n\t"
+ "lwc1 %[temp0], 32(%[p_x]) \n\t"
+ "lwc1 %[temp1], 36(%[p_x]) \n\t"
+ "mul.s %[temp_r], %[temp3], %[temp3] \n\t"
+ "mul.s %[temp_r1], %[temp3], %[temp5] \n\t"
+ "mul.s %[temp_r2], %[temp3], %[temp4] \n\t"
+ "mul.s %[temp_r3], %[temp3], %[temp1] \n\t"
+ "mul.s %[temp_r4], %[temp3], %[temp0] \n\t"
+ "madd.s %[temp_r], %[temp_r], %[temp2], %[temp2] \n\t"
+ "madd.s %[temp_r1], %[temp_r1], %[temp2], %[temp4] \n\t"
+ "msub.s %[temp_r2], %[temp_r2], %[temp2], %[temp5] \n\t"
+ "madd.s %[temp_r3], %[temp_r3], %[temp2], %[temp0] \n\t"
+ "msub.s %[temp_r4], %[temp_r4], %[temp2], %[temp1] \n\t"
+ "add.s %[real_sum_0], %[real_sum_0], %[temp_r] \n\t"
+ "add.s %[real_sum_1], %[real_sum_1], %[temp_r1] \n\t"
+ "add.s %[imag_sum_1], %[imag_sum_1], %[temp_r2] \n\t"
+ "add.s %[real_sum_2], %[real_sum_2], %[temp_r3] \n\t"
+ "add.s %[imag_sum_2], %[imag_sum_2], %[temp_r4] \n\t"
+ "lwc1 %[temp2], 40(%[p_x]) \n\t"
+ "lwc1 %[temp3], 44(%[p_x]) \n\t"
+ "mul.s %[temp_r], %[temp5], %[temp5] \n\t"
+ "mul.s %[temp_r1], %[temp5], %[temp1] \n\t"
+ "mul.s %[temp_r2], %[temp5], %[temp0] \n\t"
+ "mul.s %[temp_r3], %[temp5], %[temp3] \n\t"
+ "mul.s %[temp_r4], %[temp5], %[temp2] \n\t"
+ "madd.s %[temp_r], %[temp_r], %[temp4], %[temp4] \n\t"
+ "madd.s %[temp_r1], %[temp_r1], %[temp4], %[temp0] \n\t"
+ "msub.s %[temp_r2], %[temp_r2], %[temp4], %[temp1] \n\t"
+ "madd.s %[temp_r3], %[temp_r3], %[temp4], %[temp2] \n\t"
+ "msub.s %[temp_r4], %[temp_r4], %[temp4], %[temp3] \n\t"
+ "add.s %[real_sum_0], %[real_sum_0], %[temp_r] \n\t"
+ "add.s %[real_sum_1], %[real_sum_1], %[temp_r1] \n\t"
+ "add.s %[imag_sum_1], %[imag_sum_1], %[temp_r2] \n\t"
+ "add.s %[real_sum_2], %[real_sum_2], %[temp_r3] \n\t"
+ "add.s %[imag_sum_2], %[imag_sum_2], %[temp_r4] \n\t"
+ "addiu %[p_x], %[p_x], 24 \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [real_sum_0]"+f"(real_sum_0), [real_sum_1]"+f"(real_sum_1),
+ [imag_sum_1]"+f"(imag_sum_1), [real_sum_2]"+f"(real_sum_2),
+ [temp_r]"=&f"(temp_r), [temp_r1]"=&f"(temp_r1),
+ [temp_r2]"=&f"(temp_r2), [temp_r3]"=&f"(temp_r3),
+ [temp_r4]"=&f"(temp_r4), [p_x]"+r"(p_x),
+ [imag_sum_2]"+f"(imag_sum_2)
+ :
+ : "memory"
+ );
+ }
+ __asm__ volatile (
+ "lwc1 %[temp0], -296(%[p_x]) \n\t"
+ "lwc1 %[temp1], -292(%[p_x]) \n\t"
+ "lwc1 %[temp2], 8(%[p_x]) \n\t"
+ "lwc1 %[temp3], 12(%[p_x]) \n\t"
+ "lwc1 %[temp4], -288(%[p_x]) \n\t"
+ "lwc1 %[temp5], -284(%[p_x]) \n\t"
+ "lwc1 %[temp6], -280(%[p_x]) \n\t"
+ "lwc1 %[temp7], -276(%[p_x]) \n\t"
+ "madd.s %[temp_r], %[real_sum_0], %[temp0], %[temp0] \n\t"
+ "madd.s %[temp_r1], %[real_sum_0], %[temp2], %[temp2] \n\t"
+ "madd.s %[temp_r2], %[real_sum_1], %[temp0], %[temp4] \n\t"
+ "madd.s %[temp_r3], %[imag_sum_1], %[temp0], %[temp5] \n\t"
+ "madd.s %[temp_r], %[temp_r], %[temp1], %[temp1] \n\t"
+ "madd.s %[temp_r1], %[temp_r1], %[temp3], %[temp3] \n\t"
+ "madd.s %[temp_r2], %[temp_r2], %[temp1], %[temp5] \n\t"
+ "nmsub.s %[temp_r3], %[temp_r3], %[temp1], %[temp4] \n\t"
+ "lwc1 %[temp4], 16(%[p_x]) \n\t"
+ "lwc1 %[temp5], 20(%[p_x]) \n\t"
+ "swc1 %[temp_r], 40(%[p_phi]) \n\t"
+ "swc1 %[temp_r1], 16(%[p_phi]) \n\t"
+ "swc1 %[temp_r2], 24(%[p_phi]) \n\t"
+ "swc1 %[temp_r3], 28(%[p_phi]) \n\t"
+ "madd.s %[temp_r], %[real_sum_1], %[temp2], %[temp4] \n\t"
+ "madd.s %[temp_r1], %[imag_sum_1], %[temp2], %[temp5] \n\t"
+ "madd.s %[temp_r2], %[real_sum_2], %[temp0], %[temp6] \n\t"
+ "madd.s %[temp_r3], %[imag_sum_2], %[temp0], %[temp7] \n\t"
+ "madd.s %[temp_r], %[temp_r], %[temp3], %[temp5] \n\t"
+ "nmsub.s %[temp_r1], %[temp_r1], %[temp3], %[temp4] \n\t"
+ "madd.s %[temp_r2], %[temp_r2], %[temp1], %[temp7] \n\t"
+ "nmsub.s %[temp_r3], %[temp_r3], %[temp1], %[temp6] \n\t"
+ "swc1 %[temp_r], 0(%[p_phi]) \n\t"
+ "swc1 %[temp_r1], 4(%[p_phi]) \n\t"
+ "swc1 %[temp_r2], 8(%[p_phi]) \n\t"
+ "swc1 %[temp_r3], 12(%[p_phi]) \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp_r]"=&f"(temp_r),
+ [real_sum_0]"+f"(real_sum_0), [real_sum_1]"+f"(real_sum_1),
+ [real_sum_2]"+f"(real_sum_2), [imag_sum_1]"+f"(imag_sum_1),
+ [temp_r2]"=&f"(temp_r2), [temp_r3]"=&f"(temp_r3),
+ [temp_r1]"=&f"(temp_r1), [p_phi]"+r"(p_phi),
+ [imag_sum_2]"+f"(imag_sum_2)
+ : [p_x]"r"(p_x)
+ : "memory"
+ );
+}
+
+static void sbr_hf_gen_mips(float (*X_high)[2], const float (*X_low)[2],
+ const float alpha0[2], const float alpha1[2],
+ float bw, int start, int end)
+{
+ float alpha[4];
+ int i;
+ float *p_x_low = (float*)&X_low[0][0] + 2*start;
+ float *p_x_high = &X_high[0][0] + 2*start;
+ float temp0, temp1, temp2, temp3, temp4, temp5, temp6;
+ float temp7, temp8, temp9, temp10, temp11, temp12;
+
+ alpha[0] = alpha1[0] * bw * bw;
+ alpha[1] = alpha1[1] * bw * bw;
+ alpha[2] = alpha0[0] * bw;
+ alpha[3] = alpha0[1] * bw;
+
+ for (i = start; i < end; i++) {
+ __asm__ volatile (
+ "lwc1 %[temp0], -16(%[p_x_low]) \n\t"
+ "lwc1 %[temp1], -12(%[p_x_low]) \n\t"
+ "lwc1 %[temp2], -8(%[p_x_low]) \n\t"
+ "lwc1 %[temp3], -4(%[p_x_low]) \n\t"
+ "lwc1 %[temp5], 0(%[p_x_low]) \n\t"
+ "lwc1 %[temp6], 4(%[p_x_low]) \n\t"
+ "lwc1 %[temp7], 0(%[alpha]) \n\t"
+ "lwc1 %[temp8], 4(%[alpha]) \n\t"
+ "lwc1 %[temp9], 8(%[alpha]) \n\t"
+ "lwc1 %[temp10], 12(%[alpha]) \n\t"
+ "addiu %[p_x_high], %[p_x_high], 8 \n\t"
+ "addiu %[p_x_low], %[p_x_low], 8 \n\t"
+ "mul.s %[temp11], %[temp1], %[temp8] \n\t"
+ "msub.s %[temp11], %[temp11], %[temp0], %[temp7] \n\t"
+ "madd.s %[temp11], %[temp11], %[temp2], %[temp9] \n\t"
+ "nmsub.s %[temp11], %[temp11], %[temp3], %[temp10] \n\t"
+ "add.s %[temp11], %[temp11], %[temp5] \n\t"
+ "swc1 %[temp11], -8(%[p_x_high]) \n\t"
+ "mul.s %[temp12], %[temp1], %[temp7] \n\t"
+ "madd.s %[temp12], %[temp12], %[temp0], %[temp8] \n\t"
+ "madd.s %[temp12], %[temp12], %[temp3], %[temp9] \n\t"
+ "madd.s %[temp12], %[temp12], %[temp2], %[temp10] \n\t"
+ "add.s %[temp12], %[temp12], %[temp6] \n\t"
+ "swc1 %[temp12], -4(%[p_x_high]) \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp8]"=&f"(temp8),
+ [temp9]"=&f"(temp9), [temp10]"=&f"(temp10), [temp11]"=&f"(temp11),
+ [temp12]"=&f"(temp12), [p_x_high]"+r"(p_x_high),
+ [p_x_low]"+r"(p_x_low)
+ : [alpha]"r"(alpha)
+ : "memory"
+ );
+ }
+}
+
+static void sbr_hf_g_filt_mips(float (*Y)[2], const float (*X_high)[40][2],
+ const float *g_filt, int m_max, intptr_t ixh)
+{
+ float *p_y, *p_x, *p_g;
+ float temp0, temp1, temp2;
+ int loop_end;
+
+ p_g = (float*)&g_filt[0];
+ p_y = &Y[0][0];
+ p_x = (float*)&X_high[0][ixh][0];
+ loop_end = (int)((int*)p_g + m_max);
+
+ __asm__ volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "1: \n\t"
+ "lwc1 %[temp0], 0(%[p_g]) \n\t"
+ "lwc1 %[temp1], 0(%[p_x]) \n\t"
+ "lwc1 %[temp2], 4(%[p_x]) \n\t"
+ "mul.s %[temp1], %[temp1], %[temp0] \n\t"
+ "mul.s %[temp2], %[temp2], %[temp0] \n\t"
+ "addiu %[p_g], %[p_g], 4 \n\t"
+ "addiu %[p_x], %[p_x], 320 \n\t"
+ "swc1 %[temp1], 0(%[p_y]) \n\t"
+ "swc1 %[temp2], 4(%[p_y]) \n\t"
+ "bne %[p_g], %[loop_end], 1b \n\t"
+ " addiu %[p_y], %[p_y], 8 \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1),
+ [temp2]"=&f"(temp2), [p_x]"+r"(p_x),
+ [p_y]"+r"(p_y), [p_g]"+r"(p_g)
+ : [loop_end]"r"(loop_end)
+ : "memory"
+ );
+}
+
+static void sbr_hf_apply_noise_0_mips(float (*Y)[2], const float *s_m,
+ const float *q_filt, int noise,
+ int kx, int m_max)
+{
+ int m;
+
+ for (m = 0; m < m_max; m++){
+
+ float *Y1=&Y[m][0];
+ float *ff_table;
+ float y0,y1, temp1, temp2, temp4, temp5;
+ int temp0, temp3;
+ const float *s_m1=&s_m[m];
+ const float *q_filt1= &q_filt[m];
+
+ __asm__ volatile(
+ "lwc1 %[y0], 0(%[Y1]) \n\t"
+ "lwc1 %[temp1], 0(%[s_m1]) \n\t"
+ "addiu %[noise], %[noise], 1 \n\t"
+ "andi %[noise], %[noise], 0x1ff \n\t"
+ "sll %[temp0], %[noise], 3 \n\t"
+ "addu %[ff_table], %[ff_sbr_noise_table], %[temp0] \n\t"
+ "add.s %[y0], %[y0], %[temp1] \n\t"
+ "mfc1 %[temp3], %[temp1] \n\t"
+ "bne %[temp3], $0, 1f \n\t"
+ "lwc1 %[y1], 4(%[Y1]) \n\t"
+ "lwc1 %[temp2], 0(%[q_filt1]) \n\t"
+ "lwc1 %[temp4], 0(%[ff_table]) \n\t"
+ "lwc1 %[temp5], 4(%[ff_table]) \n\t"
+ "madd.s %[y0], %[y0], %[temp2], %[temp4] \n\t"
+ "madd.s %[y1], %[y1], %[temp2], %[temp5] \n\t"
+ "swc1 %[y1], 4(%[Y1]) \n\t"
+ "1: \n\t"
+ "swc1 %[y0], 0(%[Y1]) \n\t"
+
+ : [ff_table]"=&r"(ff_table), [y0]"=&f"(y0), [y1]"=&f"(y1),
+ [temp0]"=&r"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5)
+ : [ff_sbr_noise_table]"r"(ff_sbr_noise_table), [noise]"r"(noise),
+ [Y1]"r"(Y1), [s_m1]"r"(s_m1), [q_filt1]"r"(q_filt1)
+ : "memory"
+ );
+ }
+}
+
+static void sbr_hf_apply_noise_1_mips(float (*Y)[2], const float *s_m,
+ const float *q_filt, int noise,
+ int kx, int m_max)
+{
+ float y0,y1,temp1, temp2, temp4, temp5;
+ int temp0, temp3, m;
+ float phi_sign = 1 - 2 * (kx & 1);
+
+ for (m = 0; m < m_max; m++) {
+
+ float *ff_table;
+ float *Y1=&Y[m][0];
+ const float *s_m1=&s_m[m];
+ const float *q_filt1= &q_filt[m];
+
+ __asm__ volatile(
+ "lwc1 %[y1], 4(%[Y1]) \n\t"
+ "lwc1 %[temp1], 0(%[s_m1]) \n\t"
+ "lw %[temp3], 0(%[s_m1]) \n\t"
+ "addiu %[noise], %[noise], 1 \n\t"
+ "andi %[noise], %[noise], 0x1ff \n\t"
+ "sll %[temp0], %[noise], 3 \n\t"
+ "addu %[ff_table], %[ff_sbr_noise_table], %[temp0] \n\t"
+ "madd.s %[y1], %[y1], %[temp1], %[phi_sign] \n\t"
+ "bne %[temp3], $0, 1f \n\t"
+ "lwc1 %[y0], 0(%[Y1]) \n\t"
+ "lwc1 %[temp2], 0(%[q_filt1]) \n\t"
+ "lwc1 %[temp4], 0(%[ff_table]) \n\t"
+ "lwc1 %[temp5], 4(%[ff_table]) \n\t"
+ "madd.s %[y0], %[y0], %[temp2], %[temp4] \n\t"
+ "madd.s %[y1], %[y1], %[temp2], %[temp5] \n\t"
+ "swc1 %[y0], 0(%[Y1]) \n\t"
+ "1: \n\t"
+ "swc1 %[y1], 4(%[Y1]) \n\t"
+
+ : [ff_table] "=&r" (ff_table), [y0] "=&f" (y0), [y1] "=&f" (y1),
+ [temp0] "=&r" (temp0), [temp1] "=&f" (temp1), [temp2] "=&f" (temp2),
+ [temp3] "=&r" (temp3), [temp4] "=&f" (temp4), [temp5] "=&f" (temp5)
+ : [ff_sbr_noise_table] "r" (ff_sbr_noise_table), [noise] "r" (noise),
+ [Y1] "r" (Y1), [s_m1] "r" (s_m1), [q_filt1] "r" (q_filt1),
+ [phi_sign] "f" (phi_sign)
+ : "memory"
+ );
+ phi_sign = -phi_sign;
+ }
+}
+
+static void sbr_hf_apply_noise_2_mips(float (*Y)[2], const float *s_m,
+ const float *q_filt, int noise,
+ int kx, int m_max)
+{
+ int m;
+ float *ff_table;
+ float y0,y1, temp0, temp1, temp2, temp3, temp4, temp5;
+
+ for (m = 0; m < m_max; m++) {
+
+ float *Y1=&Y[m][0];
+ const float *s_m1=&s_m[m];
+ const float *q_filt1= &q_filt[m];
+
+ __asm__ volatile(
+ "lwc1 %[y0], 0(%[Y1]) \n\t"
+ "lwc1 %[temp1], 0(%[s_m1]) \n\t"
+ "addiu %[noise], %[noise], 1 \n\t"
+ "andi %[noise], %[noise], 0x1ff \n\t"
+ "sll %[temp0], %[noise], 3 \n\t"
+ "addu %[ff_table], %[ff_sbr_noise_table], %[temp0] \n\t"
+ "sub.s %[y0], %[y0], %[temp1] \n\t"
+ "mfc1 %[temp3], %[temp1] \n\t"
+ "bne %[temp3], $0, 1f \n\t"
+ "lwc1 %[y1], 4(%[Y1]) \n\t"
+ "lwc1 %[temp2], 0(%[q_filt1]) \n\t"
+ "lwc1 %[temp4], 0(%[ff_table]) \n\t"
+ "lwc1 %[temp5], 4(%[ff_table]) \n\t"
+ "madd.s %[y0], %[y0], %[temp2], %[temp4] \n\t"
+ "madd.s %[y1], %[y1], %[temp2], %[temp5] \n\t"
+ "swc1 %[y1], 4(%[Y1]) \n\t"
+ "1: \n\t"
+ "swc1 %[y0], 0(%[Y1]) \n\t"
+
+ : [temp0]"=&r"(temp0), [ff_table]"=&r"(ff_table), [y0]"=&f"(y0),
+ [y1]"=&f"(y1), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5)
+ : [ff_sbr_noise_table]"r"(ff_sbr_noise_table), [noise]"r"(noise),
+ [Y1]"r"(Y1), [s_m1]"r"(s_m1), [q_filt1]"r"(q_filt1)
+ : "memory"
+ );
+ }
+}
+
+static void sbr_hf_apply_noise_3_mips(float (*Y)[2], const float *s_m,
+ const float *q_filt, int noise,
+ int kx, int m_max)
+{
+ float phi_sign = 1 - 2 * (kx & 1);
+ int m;
+
+ for (m = 0; m < m_max; m++) {
+
+ float *Y1=&Y[m][0];
+ float *ff_table;
+ float y0,y1, temp1, temp2, temp4, temp5;
+ int temp0, temp3;
+ const float *s_m1=&s_m[m];
+ const float *q_filt1= &q_filt[m];
+
+ __asm__ volatile(
+ "lwc1 %[y1], 4(%[Y1]) \n\t"
+ "lwc1 %[temp1], 0(%[s_m1]) \n\t"
+ "addiu %[noise], %[noise], 1 \n\t"
+ "andi %[noise], %[noise], 0x1ff \n\t"
+ "sll %[temp0], %[noise], 3 \n\t"
+ "addu %[ff_table], %[ff_sbr_noise_table], %[temp0] \n\t"
+ "nmsub.s %[y1], %[y1], %[temp1], %[phi_sign] \n\t"
+ "mfc1 %[temp3], %[temp1] \n\t"
+ "bne %[temp3], $0, 1f \n\t"
+ "lwc1 %[y0], 0(%[Y1]) \n\t"
+ "lwc1 %[temp2], 0(%[q_filt1]) \n\t"
+ "lwc1 %[temp4], 0(%[ff_table]) \n\t"
+ "lwc1 %[temp5], 4(%[ff_table]) \n\t"
+ "madd.s %[y0], %[y0], %[temp2], %[temp4] \n\t"
+ "madd.s %[y1], %[y1], %[temp2], %[temp5] \n\t"
+ "swc1 %[y0], 0(%[Y1]) \n\t"
+ "1: \n\t"
+ "swc1 %[y1], 4(%[Y1]) \n\t"
+
+ : [ff_table]"=&r"(ff_table), [y0]"=&f"(y0), [y1]"=&f"(y1),
+ [temp0]"=&r"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5)
+ : [ff_sbr_noise_table]"r"(ff_sbr_noise_table), [noise]"r"(noise),
+ [Y1]"r"(Y1), [s_m1]"r"(s_m1), [q_filt1]"r"(q_filt1),
+ [phi_sign]"f"(phi_sign)
+ : "memory"
+ );
+ phi_sign = -phi_sign;
+ }
+}
+#endif /* HAVE_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+
+void ff_sbrdsp_init_mips(SBRDSPContext *s)
+{
+#if HAVE_INLINE_ASM
+ s->neg_odd_64 = sbr_neg_odd_64_mips;
+ s->qmf_pre_shuffle = sbr_qmf_pre_shuffle_mips;
+ s->qmf_post_shuffle = sbr_qmf_post_shuffle_mips;
+#if HAVE_MIPSFPU
+ s->sum64x5 = sbr_sum64x5_mips;
+ s->sum_square = sbr_sum_square_mips;
+ s->qmf_deint_bfly = sbr_qmf_deint_bfly_mips;
+ s->autocorrelate = sbr_autocorrelate_mips;
+ s->hf_gen = sbr_hf_gen_mips;
+ s->hf_g_filt = sbr_hf_g_filt_mips;
+
+ s->hf_apply_noise[0] = sbr_hf_apply_noise_0_mips;
+ s->hf_apply_noise[1] = sbr_hf_apply_noise_1_mips;
+ s->hf_apply_noise[2] = sbr_hf_apply_noise_2_mips;
+ s->hf_apply_noise[3] = sbr_hf_apply_noise_3_mips;
+#endif /* HAVE_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/mjpeg.c b/libavcodec/mjpeg.c
index a353851..a5b1a80 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
*/
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..9de6ac3 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
*/
diff --git a/libavcodec/mjpegbdec.c b/libavcodec/mjpegbdec.c
index 5edc0e4..4327c10 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;
@@ -157,5 +162,6 @@ AVCodec ff_mjpegb_decoder = {
.close = ff_mjpeg_decode_end,
.decode = mjpegb_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
.long_name = NULL_IF_CONFIG_SMALL("Apple MJPEG-B"),
};
diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index 61ebabc..5619c36 100644
--- a/libavcodec/mjpegdec.c
+++ b/libavcodec/mjpegdec.c
@@ -8,20 +8,20 @@
* aspecting, new decode_frame mechanism and apple mjpeg-b support
* by Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,12 +30,11 @@
* MJPEG decoder.
*/
-// #define DEBUG
-#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"
@@ -51,7 +50,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);
@@ -87,6 +86,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);
@@ -96,24 +96,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;
@@ -130,10 +130,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)
@@ -142,7 +142,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
@@ -213,6 +213,11 @@ 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);
@@ -228,6 +233,11 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
return -1;
}
+ if(s->lossless && s->avctx->lowres){
+ av_log(s->avctx, AV_LOG_ERROR, "lowres is not possible with lossless jpeg\n");
+ return -1;
+ }
+
height = get_bits(&s->gb, 16);
width = get_bits(&s->gb, 16);
@@ -243,6 +253,12 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
if (nb_components <= 0 ||
nb_components > MAX_COMPONENTS)
return -1;
+ if (s->interlaced && (s->bottom_field == !s->interlace_polarity)) {
+ if (nb_components != s->nb_components) {
+ av_log(s->avctx, AV_LOG_ERROR, "nb_components changing in interlaced picture\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
if (s->ls && !(s->bits <= 8 || nb_components == 1)) {
avpriv_report_missing_feature(s->avctx,
"JPEG-LS that is not <= 8 "
@@ -252,21 +268,29 @@ 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];
+ if (!h_count[i] || !v_count[i]) {
+ av_log(s->avctx, AV_LOG_ERROR, "h/v_count is 0\n");
+ return -1;
+ }
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;
+ }
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]);
}
@@ -275,15 +299,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 &&
@@ -301,7 +328,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)
+ 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) |
@@ -318,28 +354,90 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
switch (pix_fmt_id) {
case 0x11111100:
if (s->rgb)
- s->avctx->pix_fmt = AV_PIX_FMT_BGRA;
- else
+ s->avctx->pix_fmt = AV_PIX_FMT_BGR24;
+ else {
+ if (s->component_id[0] == 'Q' && s->component_id[1] == 'F' && s->component_id[2] == 'A') {
+ s->avctx->pix_fmt = AV_PIX_FMT_GBR24P;
+ } else {
s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P;
- assert(s->nb_components == 3);
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ }
+ }
+ av_assert0(s->nb_components == 3);
+ break;
+ case 0x12121100:
+ case 0x22122100:
+ s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ s->upscale_v = 2;
+ s->upscale_h = (pix_fmt_id == 0x22122100);
+ s->chroma_height = s->height;
+ break;
+ case 0x21211100:
+ case 0x22211200:
+ s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ s->upscale_v = (pix_fmt_id == 0x22211200);
+ s->upscale_h = 2;
+ s->chroma_height = s->height;
+ break;
+ case 0x22221100:
+ s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ s->upscale_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:
+ case 0x22211100:
+ case 0x22112100:
s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV440P : AV_PIX_FMT_YUVJ440P;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ 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;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ break;
+ case 0x22121100:
+ case 0x22111200:
+ s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV422P : AV_PIX_FMT_YUVJ422P;
+ 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;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ break;
+ case 0x41111100:
+ s->avctx->pix_fmt = AV_PIX_FMT_YUV411P;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
break;
default:
av_log(s->avctx, AV_LOG_ERROR, "Unhandled pixel format 0x%x\n", pix_fmt_id);
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)
@@ -349,10 +447,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;
@@ -368,6 +464,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);
@@ -632,25 +733,57 @@ 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 void handle_rstn(MJpegDecodeContext *s, int nb_components)
+{
+ int i;
+ 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] = 1024;
+ }
+
+ 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] = 1024;
+ } else
+ skip_bits_long(&s->gb, pos - get_bits_count(&s->gb));
+ }
+ }
+ }
+}
+
+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];
const int linesize = s->linesize[0];
const int mask = (1 << s->bits) - 1;
+ int resync_mb_y = 0;
+ int resync_mb_x = 0;
+
+ 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);
+ 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;
@@ -659,19 +792,32 @@ static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int predictor,
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<3; 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 == 0xFFFF)
+ 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) {
@@ -682,73 +828,112 @@ static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int predictor,
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];
+ for(mb_x = 0; mb_x < s->mb_width; mb_x++) {
+ ptr[3*mb_x+2-c] = buffer[mb_x][i];
+ }
}
}
}
return 0;
}
-static int ljpeg_decode_yuv_scan(MJpegDecodeContext *s, int predictor,
+static int ljpeg_decode_yuv_scan(MJpegDecodeContext *s, int nb_components, int predictor,
int point_transform)
{
int i, mb_x, mb_y;
- const int nb_components = 3;
+ int bits= (s->bits+7)&~7;
+ int resync_mb_y = 0;
+ int resync_mb_x = 0;
+
+ point_transform += bits - s->bits;
+
+ av_assert0(nb_components>=1 && nb_components<=3);
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 == 0xFFFF)
+ 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 &= (-1)<<(8-s->bits);
+ *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 &= (-1)<<(16-s->bits);
+ *ptr16= pred + (dc << point_transform);
+ }
if (++x == h) {
x = 0;
y++;
@@ -758,7 +943,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];
@@ -767,16 +953,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 == 0xFFFF)
+ 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 &= (-1)<<(8-s->bits);
+ *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 &= (-1)<<(16-s->bits);
+ *ptr16= pred + (dc << point_transform);
+ }
+
if (++x == h) {
x = 0;
y++;
@@ -793,6 +993,22 @@ 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 int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah,
int Al, const uint8_t *mb_bitmask,
const AVFrame *reference)
@@ -806,9 +1022,8 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah,
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;
}
@@ -818,7 +1033,7 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah,
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));
@@ -851,17 +1066,17 @@ 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) >> 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,
@@ -899,67 +1114,48 @@ 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;
- if (mb_bitmask)
- init_get_bits(&mb_bitmask_gb, mb_bitmask, s->mb_width * s->mb_height);
+ if (se > 63) {
+ av_log(s->avctx, AV_LOG_ERROR, "SE %d is too large\n", se);
+ return AVERROR_INVALIDDATA;
+ }
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);
@@ -971,18 +1167,12 @@ 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;
- }
+ ptr += 8 >> s->avctx->lowres;
}
+ handle_rstn(s, 0);
}
}
return 0;
@@ -996,6 +1186,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);
@@ -1025,6 +1222,11 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask,
&& nb_components == 3 && s->nb_components == 3 && i)
index = 3 - i;
+ 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->nb_blocks[i] = s->h_count[index] * s->v_count[index];
@@ -1037,15 +1239,17 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask,
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 */
@@ -1062,10 +1266,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 */
@@ -1077,6 +1281,7 @@ next_field:
s->last_dc[i] = 1024;
if (s->lossless) {
+ av_assert0(s->picture_ptr == &s->picture);
if (CONFIG_JPEGLS_DECODER && s->ls) {
// for () {
// reset_ls_coding_parameters(s, 0);
@@ -1086,22 +1291,19 @@ 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,
- point_transform)) < 0)
+ if ((ret = ljpeg_decode_yuv_scan(s, nb_components, predictor, point_transform)) < 0)
return ret;
}
}
} else {
if (s->progressive && predictor) {
+ av_assert0(s->picture_ptr == &s->picture);
if ((ret = mjpeg_decode_scan_progressive_ac(s, predictor,
ilv, prev_shift,
- point_transform,
- mb_bitmask,
- reference)) < 0)
+ point_transform)) < 0)
return ret;
} else {
if ((ret = mjpeg_decode_scan(s, nb_components,
@@ -1117,7 +1319,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;
@@ -1156,7 +1358,6 @@ 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)
@@ -1165,7 +1366,7 @@ static int mjpeg_decode_app(MJpegDecodeContext *s)
/* 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
@@ -1173,12 +1374,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);
@@ -1190,7 +1388,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);
@@ -1218,7 +1416,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 */
@@ -1229,14 +1427,14 @@ 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? */
+ 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 (get_bits(&s->gb, 8)) {
case 1:
s->rgb = 1;
@@ -1256,10 +1454,9 @@ static int mjpeg_decode_app(MJpegDecodeContext *s)
/* 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 */
@@ -1301,14 +1498,14 @@ static int mjpeg_decode_com(MJpegDecodeContext *s)
cbuf[i] = 0;
if (s->avctx->debug & FF_DEBUG_PICT_INFO)
- av_log(s->avctx, AV_LOG_INFO, "mjpeg comment: '%s'\n", cbuf);
+ av_log(s->avctx, AV_LOG_INFO, "comment: '%s'\n", cbuf);
/* buggy avid, it puts EOI only at every 10th frame */
if (!strcmp(cbuf, "AVID")) {
s->buggy_avid = 1;
} else if (!strcmp(cbuf, "CS=ITU601"))
s->cs_itu601 = 1;
- else if ((len > 20 && !strncmp(cbuf, "Intel(R) JPEG Library", 21)) ||
+ else if ((len > 31 && !strncmp(cbuf, "Intel(R) JPEG Library, version 1", 32)) ||
(len > 19 && !strncmp(cbuf, "Metasoft MJPEG Codec", 20)))
s->flipped = 1;
@@ -1326,9 +1523,7 @@ 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) {
@@ -1338,9 +1533,7 @@ static int find_marker(const uint8_t **pbuf_ptr, const uint8_t *buf_end)
val = *buf_ptr++;
goto found;
}
-#ifdef DEBUG
skipped++;
-#endif
}
val = -1;
found:
@@ -1405,7 +1598,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;
}
}
@@ -1445,11 +1638,12 @@ 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
buf_ptr = buf;
buf_end = buf + buf_size;
while (buf_ptr < buf_end) {
@@ -1460,15 +1654,17 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
/* EOF */
if (start_code < 0) {
goto the_end;
- } else if (unescaped_buf_size > (1U<<29)) {
+ } else if (unescaped_buf_size > (1U<<28)) {
av_log(avctx, AV_LOG_ERROR, "MJPEG packet 0x%x too big (0x%x/0x%x), corrupt data?\n",
start_code, unescaped_buf_size, buf_size);
return AVERROR_INVALIDDATA;
} else {
av_log(avctx, AV_LOG_DEBUG, "marker=%x avail_size_in_buf=%td\n",
start_code, buf_end - buf_ptr);
-
- init_get_bits(&s->gb, unescaped_buf_ptr, unescaped_buf_size * 8);
+ if ((ret = init_get_bits8(&s->gb, unescaped_buf_ptr, unescaped_buf_size)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid buffer\n");
+ goto fail;
+ }
s->start_code = start_code;
if (s->avctx->debug & FF_DEBUG_STARTCODE)
@@ -1485,6 +1681,7 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
else if (start_code == COM)
mjpeg_decode_com(s);
+ ret = -1;
switch (start_code) {
case SOI:
s->restart_interval = 0;
@@ -1497,7 +1694,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:
@@ -1506,39 +1703,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");
@@ -1548,34 +1743,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);
@@ -1595,7 +1789,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,
@@ -1609,8 +1802,67 @@ 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_log(avctx, AV_LOG_DEBUG, "decode frame unused %td bytes\n",
buf_end - buf_ptr);
// return buf_end - buf_ptr;
return buf_ptr - buf;
@@ -1639,6 +1891,13 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx)
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[] = {
@@ -1662,11 +1921,14 @@ AVCodec ff_mjpeg_decoder = {
.init = ff_mjpeg_decode_init,
.close = ff_mjpeg_decode_end,
.decode = ff_mjpeg_decode_frame,
+ .flush = decode_flush,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
.long_name = NULL_IF_CONFIG_SMALL("MJPEG (Motion JPEG)"),
.priv_class = &mjpegdec_class,
};
-
+#endif
+#if CONFIG_THP_DECODER
AVCodec ff_thp_decoder = {
.name = "thp",
.type = AVMEDIA_TYPE_VIDEO,
@@ -1675,6 +1937,9 @@ AVCodec ff_thp_decoder = {
.init = ff_mjpeg_decode_init,
.close = ff_mjpeg_decode_end,
.decode = ff_mjpeg_decode_frame,
+ .flush = decode_flush,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
.long_name = NULL_IF_CONFIG_SMALL("Nintendo Gamecube THP video"),
};
+#endif
diff --git a/libavcodec/mjpegdec.h b/libavcodec/mjpegdec.h
index 36598dd..17665e4 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,6 +59,9 @@ 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 */
@@ -66,7 +69,7 @@ typedef struct MJpegDecodeContext {
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;
diff --git a/libavcodec/mjpegenc.c b/libavcodec/mjpegenc.c
index 2a83a20..80a4022 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,9 +30,6 @@
* MJPEG encoder.
*/
-//#define DEBUG
-#include <assert.h>
-
#include "avcodec.h"
#include "mpegvideo.h"
#include "mjpeg.h"
@@ -47,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;
@@ -131,6 +133,12 @@ static void jpeg_table_header(MpegEncContext *s)
}
#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);
flush_put_bits(p);
@@ -155,13 +163,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);
@@ -196,9 +204,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);
@@ -206,11 +218,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 */
@@ -269,10 +283,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)
@@ -282,7 +301,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;
@@ -327,21 +346,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);
}
@@ -429,20 +457,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",
.type = AVMEDIA_TYPE_VIDEO,
@@ -451,8 +520,25 @@ 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_NONE
+ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NONE
},
.long_name = NULL_IF_CONFIG_SMALL("MJPEG (Motion JPEG)"),
};
+#endif
+#if CONFIG_AMV_ENCODER
+AVCodec ff_amv_encoder = {
+ .name = "amv",
+ .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
+ },
+ .long_name = NULL_IF_CONFIG_SMALL("AMV Video"),
+};
+#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 7f6739f..2cc4b91 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
*/
@@ -43,28 +43,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
};
@@ -107,7 +107,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;
@@ -129,7 +129,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");
@@ -157,9 +157,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;
@@ -170,15 +171,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;
@@ -245,7 +247,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;
}
@@ -263,13 +266,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;
}
@@ -320,6 +327,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
@@ -363,6 +371,7 @@ static int mlp_parse(AVCodecParserContext *s,
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 5797700..a4d5378 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
*/
@@ -131,6 +131,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
@@ -371,8 +374,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;
}
@@ -392,6 +404,7 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp,
const int max_matrix_channel = m->avctx->codec_id == AV_CODEC_ID_MLP
? MAX_MATRIX_CHANNEL_MLP
: MAX_MATRIX_CHANNEL_TRUEHD;
+ int max_channel, min_channel, matrix_channel;
sync_word = get_bits(gbp, 13);
@@ -410,18 +423,18 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp,
skip_bits(gbp, 16); /* Output timestamp */
- s->min_channel = get_bits(gbp, 4);
- s->max_channel = get_bits(gbp, 4);
- s->max_matrix_channel = get_bits(gbp, 4);
+ min_channel = get_bits(gbp, 4);
+ max_channel = get_bits(gbp, 4);
+ matrix_channel = get_bits(gbp, 4);
- if (s->max_matrix_channel > max_matrix_channel) {
+ if (matrix_channel > max_matrix_channel) {
av_log(m->avctx, AV_LOG_ERROR,
"Max matrix channel cannot be greater than %d.\n",
max_matrix_channel);
return AVERROR_INVALIDDATA;
}
- if (s->max_channel != s->max_matrix_channel) {
+ if (max_channel != matrix_channel) {
av_log(m->avctx, AV_LOG_ERROR,
"Max channel must be equal max matrix channel.\n");
return AVERROR_INVALIDDATA;
@@ -429,20 +442,24 @@ 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;
}
- if (s->min_channel > s->max_channel) {
+ if (min_channel > max_channel) {
av_log(m->avctx, AV_LOG_ERROR,
"Substream min channel cannot be greater than max channel.\n");
return AVERROR_INVALIDDATA;
}
+ s->min_channel = min_channel;
+ s->max_channel = max_channel;
+ s->max_matrix_channel = matrix_channel;
+
#if FF_API_REQUEST_CHANNELS
if (m->avctx->request_channels > 0 &&
m->avctx->request_channels <= s->max_channel + 1 &&
@@ -491,7 +508,7 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp,
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);
@@ -531,6 +548,20 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp,
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;
@@ -549,7 +580,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");
@@ -604,7 +635,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;
}
}
@@ -723,6 +754,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;
}
@@ -749,7 +781,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;
}
@@ -993,10 +1025,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];
@@ -1216,6 +1246,7 @@ error:
return AVERROR_INVALIDDATA;
}
+#if CONFIG_MLP_DECODER
AVCodec ff_mlp_decoder = {
.name = "mlp",
.type = AVMEDIA_TYPE_AUDIO,
@@ -1226,7 +1257,7 @@ AVCodec ff_mlp_decoder = {
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("MLP (Meridian Lossless Packing)"),
};
-
+#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 48d5772..292ebe6 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,13 +123,13 @@ 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)
*/
static int mm_decode_inter(MmContext * s, int half_horiz, int half_vert)
{
- int data_off = bytestream2_get_le16(&s->gb), y;
+ int data_off = bytestream2_get_le16(&s->gb), y = 0;
GetByteContext data_ptr;
if (bytestream2_get_bytes_left(&s->gb) < data_off)
@@ -151,6 +154,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;
@@ -188,13 +193,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;
@@ -215,7 +218,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
--- /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 6ef9b0b..00c1148 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);
@@ -97,38 +102,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 +231,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 +265,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 +294,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..a745190 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
*/
diff --git a/libavcodec/movtextdec.c b/libavcodec/movtextdec.c
new file mode 100644
index 0000000..05ff53a
--- /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
--- /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..3c5e2fb 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
*/
diff --git a/libavcodec/mp3_header_decompress_bsf.c b/libavcodec/mp3_header_decompress_bsf.c
index 8e086a1..adf5a7f 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
*/
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 1aed52b..85d4e09 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 d14b8f1..4d6ca89 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 528e676..f4d8abe 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"
@@ -174,7 +179,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--;
@@ -215,3 +220,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 6751864..b5ef966 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
*/
@@ -51,7 +51,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;
@@ -235,6 +235,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;
@@ -386,6 +391,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)
{
@@ -526,6 +536,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;
@@ -637,7 +652,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) {
@@ -650,10 +665,13 @@ 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)
@@ -752,11 +770,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 {
@@ -775,10 +794,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);
@@ -852,6 +871,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)) {
@@ -868,6 +888,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)) {
@@ -934,7 +958,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;
}
@@ -1067,45 +1091,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 (avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU) {
- if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO)
- return AV_PIX_FMT_VDPAU_MPEG1;
- else
- return AV_PIX_FMT_VDPAU_MPEG2;
- } 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.
@@ -1137,7 +1187,12 @@ static int mpeg_decode_postinit(AVCodecContext *avctx)
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;
@@ -1197,13 +1252,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 ||
- s->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
- 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. */
@@ -1237,19 +1286,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;
}
@@ -1369,7 +1421,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;
@@ -1410,6 +1462,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);
@@ -1422,28 +1479,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);
@@ -1550,14 +1585,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;
@@ -1664,21 +1702,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);
@@ -1692,8 +1730,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
@@ -1800,7 +1847,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)
@@ -1829,7 +1879,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);
@@ -1840,7 +1890,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++;
@@ -1850,7 +1901,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);
}
}
@@ -1875,13 +1927,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);
@@ -1927,6 +1979,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;
@@ -1959,17 +2012,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 ||
- s->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
- 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++) {
@@ -1986,9 +2032,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;
@@ -1999,8 +2052,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') {
@@ -2023,31 +2090,26 @@ static void mpeg_decode_gop(AVCodecContext *avctx,
{
Mpeg1Context *s1 = avctx->priv_data;
MpegEncContext *s = &s1->mpeg_enc_ctx;
-
- int time_code_hours, time_code_minutes;
- int time_code_seconds, time_code_pictures;
int broken_link;
+ int64_t tc;
init_get_bits(&s->gb, buf, buf_size*8);
- skip_bits1(&s->gb); /* drop_frame_flag */
-
- time_code_hours = get_bits(&s->gb, 5);
- time_code_minutes = get_bits(&s->gb, 6);
- skip_bits1(&s->gb); // marker bit
- time_code_seconds = get_bits(&s->gb, 6);
- time_code_pictures = get_bits(&s->gb, 6);
+ tc = avctx->timecode_frame_start = get_bits(&s->gb, 25);
- s1->closed_gop = get_bits1(&s->gb);
+ s->closed_gop = get_bits1(&s->gb);
/*broken_link indicate that after editing the
reference frames of the first B-Frames after GOP I-Frame
are missing (open gop)*/
broken_link = get_bits1(&s->gb);
- if (s->avctx->debug & FF_DEBUG_PICT_INFO)
- 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,
@@ -2060,6 +2122,7 @@ static int decode_chunks(AVCodecContext *avctx,
const uint8_t *buf_end = buf + buf_size;
int ret, input_size;
int last_code = 0;
+ int picture_start_code_seen = 0;
for (;;) {
/* find next start code */
@@ -2069,6 +2132,7 @@ static int decode_chunks(AVCodecContext *avctx,
if (s2->pict_type != AV_PICTURE_TYPE_B || avctx->skip_frame <= AVDISCARD_DEFAULT) {
if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_SLICE)) {
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++)
@@ -2076,7 +2140,7 @@ static int decode_chunks(AVCodecContext *avctx,
}
if ((CONFIG_MPEG_VDPAU_DECODER || CONFIG_MPEG1_VDPAU_DECODER)
- && avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
+ && uses_vdpau(avctx))
ff_vdpau_mpeg_picture_complete(s2, buf, buf_size, s->slice_count);
ret = slice_end(avctx, picture);
@@ -2102,7 +2166,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)
@@ -2111,12 +2176,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) && s->slice_count) {
int i;
@@ -2194,11 +2271,40 @@ 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++;
@@ -2210,11 +2316,11 @@ 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)
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. */
@@ -2250,7 +2356,7 @@ static int decode_chunks(AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
}
- if (avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU) {
+ if (uses_vdpau(avctx)) {
s->slice_count++;
break;
}
@@ -2259,6 +2365,7 @@ static int decode_chunks(AVCodecContext *avctx,
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];
@@ -2299,6 +2406,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;
@@ -2326,19 +2434,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;
}
@@ -2347,7 +2468,6 @@ static void flush(AVCodecContext *avctx)
Mpeg1Context *s = avctx->priv_data;
s->sync=0;
- s->closed_gop = 0;
ff_mpeg_flush(avctx);
}
@@ -2386,6 +2506,7 @@ AVCodec ff_mpeg1video_decoder = {
CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY |
CODEC_CAP_SLICE_THREADS,
.flush = flush,
+ .max_lowres = 3,
.long_name = NULL_IF_CONFIG_SMALL("MPEG-1 video"),
.update_thread_context = ONLY_IF_THREADS_ENABLED(mpeg_decode_update_thread_context)
};
@@ -2402,10 +2523,26 @@ AVCodec ff_mpeg2video_decoder = {
CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY |
CODEC_CAP_SLICE_THREADS,
.flush = flush,
+ .max_lowres = 3,
.long_name = NULL_IF_CONFIG_SMALL("MPEG-2 video"),
.profiles = NULL_IF_CONFIG_SMALL(mpeg2_video_profiles),
};
+//legacy decoder
+AVCodec ff_mpegvideo_decoder = {
+ .name = "mpegvideo",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-1 video"),
+};
+
#if CONFIG_MPEG_XVMC_DECODER
static av_cold int mpeg_mc_decode_init(AVCodecContext *avctx)
{
diff --git a/libavcodec/mpeg12decdata.h b/libavcodec/mpeg12decdata.h
index 323a902..66ca5c4 100644
--- a/libavcodec/mpeg12decdata.h
+++ b/libavcodec/mpeg12decdata.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
*/
diff --git a/libavcodec/mpeg12enc.c b/libavcodec/mpeg12enc.c
index 91077e7..7b7dd47 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
*/
@@ -36,6 +36,8 @@
#include "libavutil/attributes.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
+#include "libavutil/timecode.h"
static const uint8_t inv_non_linear_qscale[13] = {
0, 2, 4, 6, 8,
@@ -108,21 +110,34 @@ 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;
@@ -132,6 +147,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;
@@ -167,11 +185,37 @@ 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;
}
@@ -201,8 +245,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;
@@ -273,8 +317,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);
@@ -285,13 +329,9 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s)
time_code = s->current_picture_ptr->f.coded_picture_number + 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;
- //if (m < 2) m += 2; /* not needed since -2,-1 / 1798 in C returns 0 */
- 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);
@@ -314,7 +354,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);
@@ -322,7 +362,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));
put_bits(&s->pb, 3, s->mb_y >> 7); /* slice_vertical_position_extension */
} else {
@@ -386,7 +426,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 */
@@ -450,7 +490,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_x != s->mb_width - 1 || (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) ? ((s->mv[0][0][0] - s->last_mv[0][0][0])|(s->mv[0][0][1] - s->last_mv[0][0][1])) : 0) |
((s->mv_dir & MV_DIR_BACKWARD) ? ((s->mv[1][0][0] - s->last_mv[1][0][0])|(s->mv[1][0][1] - s->last_mv[1][0][1])) : 0)) == 0))) {
@@ -465,7 +505,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);
@@ -528,7 +568,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){
@@ -595,8 +635,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)
@@ -691,7 +731,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],
@@ -922,6 +962,7 @@ static void mpeg1_encode_block(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.", OFFSET(drop_frame_timecode), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE}, \
{ "scan_offset", "Reserve space for SVCD scan offset user data.", OFFSET(scan_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
@@ -975,7 +1016,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 ae3880f..400ce4d 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
*/
@@ -101,6 +101,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);
/**
*
@@ -174,7 +175,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..3cbd69d 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,7 +109,10 @@ 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;
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 8ebae2e..be4aa37 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,16 +149,20 @@ 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;
}
-static void mpeg4_decode_sprite_trajectory(MpegEncContext * s, GetBitContext *gb)
+static int mpeg4_decode_sprite_trajectory(MpegEncContext * s, GetBitContext *gb)
{
int i;
int a= 2<<s->sprite_warping_accuracy;
@@ -170,6 +178,9 @@ static void mpeg4_decode_sprite_trajectory(MpegEncContext * s, GetBitContext *gb
int h= s->height;
int min_ab;
+ if(w<=0 || h<=0)
+ return -1;
+
for(i=0; i<s->num_sprite_warping_points; i++){
int length;
int x=0, y=0;
@@ -342,6 +353,7 @@ static void mpeg4_decode_sprite_trajectory(MpegEncContext * s, GetBitContext *gb
}
s->real_sprite_warping_points= s->num_sprite_warping_points;
}
+ return 0;
}
/**
@@ -375,17 +387,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;
@@ -416,7 +417,8 @@ int ff_mpeg4_decode_video_packet_header(MpegEncContext *s)
skip_bits(&s->gb, 3); /* intra dc vlc threshold */
//FIXME don't just ignore everything
if(s->pict_type == AV_PICTURE_TYPE_S && s->vol_sprite_usage==GMC_SPRITE){
- mpeg4_decode_sprite_trajectory(s, &s->gb);
+ if(mpeg4_decode_sprite_trajectory(s, &s->gb) < 0)
+ return -1;
av_log(s->avctx, AV_LOG_ERROR, "untested\n");
}
@@ -523,7 +525,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;
}
@@ -847,7 +849,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;
@@ -993,11 +995,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;
@@ -1157,7 +1181,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{
@@ -1469,16 +1493,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;
}
}
@@ -1489,35 +1518,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 = get_bits(gb, 4);
+ s->avctx->level = get_bits(gb, 4);
- s->avctx->profile = (profile_and_level_indication & 0xf0) >> 4;
- s->avctx->level = (profile_and_level_indication & 0x0f);
-
- // 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){
@@ -1560,7 +1590,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;
}
@@ -1649,6 +1679,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;
}
@@ -1826,6 +1859,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;
}
@@ -1920,6 +1965,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
@@ -1961,7 +2009,7 @@ static int decode_vop_header(MpegEncContext *s, GetBitContext *gb){
}
if(s->avctx->time_base.num)
- s->current_picture_ptr->f.pts = (s->time + s->avctx->time_base.num / 2) / s->avctx->time_base.num;
+ s->current_picture_ptr->f.pts = ROUNDED_DIV(s->time, s->avctx->time_base.num);
else
s->current_picture_ptr->f.pts = AV_NOPTS_VALUE;
if(s->avctx->debug&FF_DEBUG_PTS)
@@ -2010,6 +2058,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);
@@ -2031,7 +2083,8 @@ static int decode_vop_header(MpegEncContext *s, GetBitContext *gb){
}
if(s->pict_type == AV_PICTURE_TYPE_S && (s->vol_sprite_usage==STATIC_SPRITE || s->vol_sprite_usage==GMC_SPRITE)){
- mpeg4_decode_sprite_trajectory(s, gb);
+ if(mpeg4_decode_sprite_trajectory(s, gb) < 0)
+ return -1;
if(s->sprite_brightness_change) av_log(s->avctx, AV_LOG_ERROR, "sprite_brightness_change not supported\n");
if(s->vol_sprite_usage==STATIC_SPRITE) av_log(s->avctx, AV_LOG_ERROR, "static sprite not supported\n");
}
@@ -2047,6 +2100,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
@@ -2054,16 +2108,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){
@@ -2121,8 +2184,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
@@ -2194,23 +2257,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]);
@@ -2229,10 +2279,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;
@@ -2259,6 +2326,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 = {
@@ -2273,10 +2361,12 @@ AVCodec ff_mpeg4_decoder = {
CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY |
CODEC_CAP_FRAME_THREADS,
.flush = ff_mpeg_flush,
+ .max_lowres = 3,
.long_name = NULL_IF_CONFIG_SMALL("MPEG-4 part 2"),
.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,
};
@@ -2294,5 +2384,6 @@ AVCodec ff_mpeg4_vdpau_decoder = {
.long_name = NULL_IF_CONFIG_SMALL("MPEG-4 part 2 (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 fd39b3f..8454edd 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 a222f2c..6c15d3c 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)
{
@@ -47,7 +48,7 @@ static void mpegaudio_tableinit(void)
double value = i / 4;
double f, fm;
int e, m;
- f = value * cbrtf(value) * pow(2, (i & 3) * 0.25);
+ f = value / IMDCT_SCALAR * cbrtf(value) * pow(2, (i & 3) * 0.25);
fm = frexp(f, &e);
m = (uint32_t)(fm * (1LL << 31) + 0.5);
e += FRAC_BITS - 31 + 5 - 100;
@@ -58,7 +59,7 @@ static void mpegaudio_tableinit(void)
}
for (exponent = 0; exponent < 512; exponent++) {
for (value = 0; value < 16; value++) {
- double f = (double)value * cbrtf(value) * pow(2, (exponent - 400) * 0.25 + FRAC_BITS + 5);
+ double f = (double)value * cbrtf(value) * pow(2, (exponent - 400) * 0.25 + FRAC_BITS + 5) / IMDCT_SCALAR;
expval_table_fixed[exponent][value] = llrint(f);
expval_table_float[exponent][value] = f;
}
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 c18f433..2834ba5 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");
@@ -1939,7 +1963,7 @@ static int decode_frame_mp3on4(AVCodecContext *avctx, void *data,
avpriv_mpegaudio_decode_header((MPADecodeHeader *)m, header);
- if (ch + m->nb_channels > avctx->channels) {
+ if (ch + m->nb_channels > avctx->channels || s->coff[fr] + m->nb_channels > avctx->channels) {
av_log(avctx, AV_LOG_ERROR, "frame channel count exceeds codec "
"channel count\n");
return AVERROR_INVALIDDATA;
diff --git a/libavcodec/mpegaudiodec_float.c b/libavcodec/mpegaudiodec_float.c
index ac8df32..17a7757 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..8153cb1 100644
--- a/libavcodec/mpegaudiodsp.h
+++ b/libavcodec/mpegaudiodsp.h
@@ -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_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 76e7b88..3a109f0 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 d958b96..d61d684 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"
@@ -153,6 +154,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);
@@ -195,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 * 2,
+ 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;
@@ -286,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);
@@ -335,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;
}
@@ -371,6 +379,11 @@ 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]);
pic->shared = 1;
@@ -477,6 +490,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;
}
@@ -639,9 +655,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) {
@@ -651,16 +669,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;
@@ -672,6 +697,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] &&
@@ -701,6 +728,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,
@@ -738,7 +766,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
@@ -864,44 +891,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);
@@ -924,15 +939,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) {
@@ -941,17 +952,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;
@@ -1017,44 +1025,34 @@ av_cold int ff_MPV_common_init(MpegEncContext *s)
s->flags = s->avctx->flags;
s->flags2 = s->avctx->flags2;
- if (s->width && s->height) {
- /* set chroma shifts */
- av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt,
- &s->chroma_x_shift,
- &s->chroma_y_shift);
+ /* set chroma shifts */
+ 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);
+ /* convert fourcc to upper case */
+ 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;
- 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);
}
}
@@ -1070,17 +1068,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));
@@ -1102,7 +1098,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:
@@ -1157,6 +1153,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);
@@ -1261,6 +1258,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);
@@ -1401,6 +1402,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))
@@ -1414,7 +1417,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 {
@@ -1424,7 +1427,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)
@@ -1473,6 +1490,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 &&
@@ -1580,12 +1602,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) *
@@ -1594,6 +1617,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);
}
@@ -1607,6 +1635,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;
@@ -1615,6 +1644,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] &&
@@ -1663,7 +1696,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);
}
@@ -1682,28 +1715,30 @@ void ff_MPV_frame_end(MpegEncContext *s)
// 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();
@@ -1744,102 +1779,773 @@ 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, int 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, 2);
+ const int s_mask = (2 << lowres) - 1;
+ int emu = 0;
+ int sx, sy;
+
+ if (s->quarter_sample) {
+ motion_x /= 2;
+ motion_y /= 2;
+ }
+
+ sx = motion_x & s_mask;
+ sy = motion_y & s_mask;
+ src_x += motion_x >> lowres + 1;
+ src_y += motion_y >> lowres + 1;
+
+ src += src_y * stride + src_x;
+
+ if ((unsigned)src_x > FFMAX( h_edge_pos - (!!sx) - w, 0) ||
+ (unsigned)src_y > FFMAX((v_edge_pos >> field_based) - (!!sy) - h, 0)) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, src, s->linesize, 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, uvlinesize, linesize, sx, sy,
+ uvsx, uvsy;
+ const int lowres = s->avctx->lowres;
+ const int op_index = FFMIN(lowres-1+s->chroma_x_shift, 2);
+ const int block_s = 8>>lowres;
+ const int s_mask = (2 << lowres) - 1;
+ const int h_edge_pos = s->h_edge_pos >> lowres;
+ const int v_edge_pos = s->v_edge_pos >> lowres;
+ linesize = s->current_picture.f.linesize[0] << field_based;
+ uvlinesize = s->current_picture.f.linesize[1] << field_based;
+
+ // FIXME obviously not perfect but qpel will not work in lowres anyway
+ if (s->quarter_sample) {
+ motion_x /= 2;
+ motion_y /= 2;
+ }
+
+ if(field_based){
+ motion_y += (bottom_field - field_select)*((1 << lowres)-1);
+ }
+
+ sx = motion_x & s_mask;
+ sy = motion_y & s_mask;
+ src_x = s->mb_x * 2 * block_s + (motion_x >> lowres + 1);
+ src_y = (mb_y * 2 * block_s >> field_based) + (motion_y >> lowres + 1);
+
+ if (s->out_format == FMT_H263) {
+ uvsx = ((motion_x >> 1) & s_mask) | (sx & 1);
+ uvsy = ((motion_y >> 1) & s_mask) | (sy & 1);
+ uvsrc_x = src_x >> 1;
+ uvsrc_y = src_y >> 1;
+ } else if (s->out_format == FMT_H261) {
+ // even chroma mv's are full pel in H261
+ mx = motion_x / 4;
+ my = motion_y / 4;
+ uvsx = (2 * mx) & s_mask;
+ uvsy = (2 * my) & s_mask;
+ uvsrc_x = s->mb_x * block_s + (mx >> lowres);
+ uvsrc_y = mb_y * block_s + (my >> lowres);
+ } else {
+ if(s->chroma_y_shift){
+ mx = motion_x / 2;
+ my = motion_y / 2;
+ uvsx = mx & s_mask;
+ uvsy = my & s_mask;
+ uvsrc_x = s->mb_x * block_s + (mx >> lowres + 1);
+ uvsrc_y = (mb_y * block_s >> field_based) + (my >> lowres + 1);
+ } else {
+ if(s->chroma_x_shift){
+ //Chroma422
+ mx = motion_x / 2;
+ uvsx = mx & s_mask;
+ uvsy = motion_y & s_mask;
+ uvsrc_y = src_y;
+ uvsrc_x = s->mb_x*block_s + (mx >> (lowres+1));
+ } else {
+ //Chroma444
+ uvsx = motion_x & s_mask;
+ uvsy = motion_y & s_mask;
+ uvsrc_x = src_x;
+ uvsrc_y = src_y;
+ }
+ }
+ }
+
+ ptr_y = ref_picture[0] + src_y * linesize + src_x;
+ ptr_cb = ref_picture[1] + uvsrc_y * uvlinesize + uvsrc_x;
+ ptr_cr = ref_picture[2] + uvsrc_y * uvlinesize + uvsrc_x;
+
+ if ((unsigned) src_x > FFMAX( h_edge_pos - (!!sx) - 2 * block_s, 0) || uvsrc_y<0 ||
+ (unsigned) src_y > FFMAX((v_edge_pos >> field_based) - (!!sy) - h, 0)) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr_y,
+ linesize >> field_based, 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 , 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, 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, 2);
+ 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, offset, sx, sy;
+ 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 (s->flags & CODEC_FLAG_EMU_EDGE) {
+ if ((unsigned) src_x > FFMAX(h_edge_pos - (!!sx) - block_s, 0) ||
+ (unsigned) src_y > FFMAX(v_edge_pos - (!!sy) - block_s, 0)) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr, s->uvlinesize,
+ 9, 9, src_x, src_y, h_edge_pos, v_edge_pos);
+ ptr = s->edge_emu_buffer;
+ emu = 1;
+ }
+ }
+ sx = (sx << 2) >> lowres;
+ sy = (sy << 2) >> lowres;
+ pix_op[op_index](dest_cb, ptr, s->uvlinesize, block_s, sx, sy);
+
+ ptr = ref_picture[2] + offset;
+ if (emu) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr, s->uvlinesize, 9, 9,
+ src_x, src_y, h_edge_pos, v_edge_pos);
+ ptr = s->edge_emu_buffer;
+ }
+ pix_op[op_index](dest_cr, ptr, s->uvlinesize, block_s, sx, sy);
+}
+
+/**
+ * motion compensation of a single macroblock
+ * @param s context
+ * @param dest_y luma destination pointer
+ * @param dest_cb chroma cb/u destination pointer
+ * @param dest_cr chroma cr/v destination pointer
+ * @param dir direction (0->forward, 1->backward)
+ * @param ref_picture array[3] of pointers to the 3 planes of the reference picture
+ * @param pix_op halfpel motion compensation function (average or put normally)
+ * the motion vectors are taken from s->mv and the MV type from s->mv_type
+ */
+static inline void MPV_motion_lowres(MpegEncContext *s,
+ uint8_t *dest_y, uint8_t *dest_cb,
+ uint8_t *dest_cr,
+ int dir, uint8_t **ref_picture,
+ h264_chroma_mc_func *pix_op)
+{
+ int mx, my;
+ int mb_x, mb_y, i;
+ const int lowres = s->avctx->lowres;
+ const int block_s = 8 >>lowres;
+
+ mb_x = s->mb_x;
+ mb_y = s->mb_y;
+
+ switch (s->mv_type) {
+ case MV_TYPE_16X16:
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 0, 0, 0,
+ ref_picture, pix_op,
+ s->mv[dir][0][0], s->mv[dir][0][1],
+ 2 * block_s, mb_y);
+ break;
+ case MV_TYPE_8X8:
+ mx = 0;
+ my = 0;
+ for (i = 0; i < 4; i++) {
+ hpel_motion_lowres(s, dest_y + ((i & 1) + (i >> 1) *
+ s->linesize) * block_s,
+ ref_picture[0], 0, 0,
+ (2 * mb_x + (i & 1)) * block_s,
+ (2 * mb_y + (i >> 1)) * block_s,
+ s->width, s->height, s->linesize,
+ s->h_edge_pos >> lowres, s->v_edge_pos >> lowres,
+ block_s, block_s, pix_op,
+ s->mv[dir][i][0], s->mv[dir][i][1]);
+
+ mx += s->mv[dir][i][0];
+ my += s->mv[dir][i][1];
+ }
+
+ if (!CONFIG_GRAY || !(s->flags & CODEC_FLAG_GRAY))
+ chroma_4mv_motion_lowres(s, dest_cb, dest_cr, ref_picture,
+ pix_op, mx, my);
+ break;
+ case MV_TYPE_FIELD:
+ if (s->picture_structure == PICT_FRAME) {
+ /* top field */
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 1, 0, s->field_select[dir][0],
+ ref_picture, pix_op,
+ s->mv[dir][0][0], s->mv[dir][0][1],
+ block_s, mb_y);
+ /* bottom field */
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 1, 1, s->field_select[dir][1],
+ ref_picture, pix_op,
+ s->mv[dir][1][0], s->mv[dir][1][1],
+ block_s, mb_y);
+ } else {
+ if (s->picture_structure != s->field_select[dir][0] + 1 &&
+ s->pict_type != AV_PICTURE_TYPE_B && !s->first_field) {
+ ref_picture = s->current_picture_ptr->f.data;
+
+ }
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 0, 0, s->field_select[dir][0],
+ ref_picture, pix_op,
+ s->mv[dir][0][0],
+ s->mv[dir][0][1], 2 * block_s, mb_y >> 1);
+ }
+ break;
+ case MV_TYPE_16X8:
+ for (i = 0; i < 2; i++) {
+ uint8_t **ref2picture;
+
+ if (s->picture_structure == s->field_select[dir][i] + 1 ||
+ s->pict_type == AV_PICTURE_TYPE_B || s->first_field) {
+ ref2picture = ref_picture;
+ } else {
+ ref2picture = s->current_picture_ptr->f.data;
+ }
+
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 0, 0, s->field_select[dir][i],
+ ref2picture, pix_op,
+ s->mv[dir][i][0], s->mv[dir][i][1] +
+ 2 * block_s * i, block_s, mb_y >> 1);
+
+ dest_y += 2 * block_s * s->linesize;
+ dest_cb += (2 * block_s >> s->chroma_y_shift) * s->uvlinesize;
+ dest_cr += (2 * block_s >> s->chroma_y_shift) * s->uvlinesize;
+ }
+ break;
+ case MV_TYPE_DMV:
+ if (s->picture_structure == PICT_FRAME) {
+ for (i = 0; i < 2; i++) {
+ int j;
+ for (j = 0; j < 2; j++) {
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 1, j, j ^ i,
+ ref_picture, pix_op,
+ s->mv[dir][2 * i + j][0],
+ s->mv[dir][2 * i + j][1],
+ block_s, mb_y);
+ }
+ pix_op = s->h264chroma.avg_h264_chroma_pixels_tab;
+ }
+ } else {
+ for (i = 0; i < 2; i++) {
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 0, 0, s->picture_structure != i + 1,
+ ref_picture, pix_op,
+ s->mv[dir][2 * i][0],s->mv[dir][2 * i][1],
+ 2 * block_s, mb_y >> 1);
+
+ // after put we make avg of the same block
+ pix_op = s->h264chroma.avg_h264_chroma_pixels_tab;
+
+ // opposite parity is always in the same
+ // frame if this is second field
+ if (!s->first_field) {
+ ref_picture = s->current_picture_ptr->f.data;
}
}
- av_log(s->avctx, AV_LOG_DEBUG, "\n");
}
+ break;
+ default:
+ av_assert2(0);
}
}
@@ -1953,7 +2659,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){
@@ -1996,8 +2702,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 */
@@ -2006,7 +2712,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;
@@ -2046,19 +2752,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);
+ }
}
}
@@ -2104,17 +2822,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
@@ -2156,17 +2874,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
@@ -2184,10 +2902,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);
}
/**
@@ -2280,7 +3000,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;
@@ -2304,7 +3024,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));
}
}
}
@@ -2354,6 +3074,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;
@@ -2373,10 +3094,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++) {
@@ -2435,10 +3153,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];
@@ -2466,10 +3181,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];
@@ -2526,15 +3239,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);
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;
@@ -2563,7 +3273,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 307ed5f..9ede096 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,10 +163,11 @@ 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
@@ -172,6 +177,10 @@ typedef struct Picture{
int reference;
int shared;
+
+ int crop;
+ int crop_left;
+ int crop_top;
} Picture;
/**
@@ -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
@@ -613,6 +629,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 +694,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 +799,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 +813,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 +834,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 +863,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 +956,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 98292fa..0db2f83 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++) {
@@ -230,6 +230,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)
{
@@ -252,7 +267,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) ||
@@ -262,10 +279,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;
@@ -279,6 +299,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;
@@ -295,8 +319,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;
@@ -336,10 +361,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) {
@@ -353,7 +403,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;
}
@@ -421,12 +471,63 @@ av_cold int ff_MPV_encode_init(AVCodecContext *avctx)
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");
@@ -484,6 +585,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");
@@ -492,14 +594,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;
@@ -526,8 +631,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;
@@ -542,8 +646,9 @@ av_cold int ff_MPV_encode_init(AVCodecContext *avctx)
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) {
@@ -570,13 +675,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;
@@ -607,13 +718,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;
}
@@ -717,16 +828,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;
@@ -881,7 +983,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;
@@ -938,18 +1040,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);
+ }
}
}
}
@@ -1029,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;
@@ -1321,7 +1436,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;
@@ -1338,8 +1453,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,
@@ -1360,7 +1474,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;
@@ -1434,6 +1549,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) {
@@ -1488,7 +1604,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;
@@ -1501,12 +1617,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)
@@ -1640,15 +1756,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;
int wrap_y, wrap_c;
@@ -1690,23 +1808,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;
+ int cw = (s->width + s->chroma_x_shift) >> s->chroma_x_shift;
+ int ch = (s->height + s->chroma_y_shift) >> s->chroma_y_shift;
s->vdsp.emulated_edge_mc(ebuf, ptr_y, wrap_y, 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, 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, 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) {
@@ -1728,8 +1848,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;
}
}
@@ -1746,11 +1868,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 {
@@ -1809,6 +1936,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;
@@ -1830,10 +1958,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 */
@@ -1860,12 +1988,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;
}
@@ -1887,17 +2015,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]) {
@@ -1943,6 +2071,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
@@ -1993,18 +2127,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){
@@ -2141,7 +2277,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;
}
@@ -2247,7 +2383,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);
@@ -2336,6 +2472,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));
@@ -2379,7 +2520,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;
}
}
@@ -2415,18 +2556,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){
@@ -2633,8 +2776,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;
@@ -2652,7 +2796,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);
@@ -2662,7 +2806,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);
@@ -3062,6 +3206,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);
@@ -3104,6 +3255,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);
}
@@ -3182,6 +3335,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 =
@@ -3192,6 +3364,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:
@@ -3223,7 +3396,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;
@@ -3314,7 +3487,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;
@@ -3360,7 +3533,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;
@@ -3394,7 +3567,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;
@@ -3543,7 +3716,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;
@@ -3659,8 +3832,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);
@@ -3726,7 +3899,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;
@@ -3769,7 +3942,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){
@@ -3797,7 +3970,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] ];
@@ -3830,7 +4003,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;
@@ -3859,7 +4032,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){
@@ -3890,7 +4063,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
@@ -3918,7 +4091,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;
@@ -3981,7 +4154,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 c8109b1..96b3780 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,13 +60,11 @@ 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, 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, motion_x&15, motion_y&15, 128 - s->no_rounding);
@@ -98,14 +97,12 @@ 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, 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;
@@ -436,7 +433,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]){
@@ -646,7 +643,7 @@ static av_always_inline void MPV_motion_internal(MpegEncContext *s,
const int mot_stride= s->b8_stride;
const int mot_xy= mb_x*2 + mb_y*2*mot_stride;
- 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]);
@@ -812,7 +809,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;
}
@@ -826,8 +824,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;
@@ -856,6 +854,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,
@@ -872,7 +873,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
--- /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 4a8ce03..288570d 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 3b849c2..a0112d1 100644
--- a/libavcodec/mqc.h
+++ b/libavcodec/mqc.h
@@ -2,20 +2,20 @@
* MQ-coder: structures, common and decoder functions
* Copyright (c) 2007 Kamil Nowosad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,6 +45,20 @@ typedef struct MqcState {
uint8_t cx_states[19];
} MqcState;
+/* encoder */
+
+/** initialize the encoder */
+void ff_mqc_initenc(MqcState *mqc, uint8_t *bp);
+
+/** code bit d with context cx */
+void ff_mqc_encode(MqcState *mqc, uint8_t *cxstate, int d);
+
+/** number of encoded bytes */
+int ff_mqc_length(MqcState *mqc);
+
+/** flush the encoder [returns number of bytes encoded] */
+int ff_mqc_flush(MqcState *mqc);
+
/* decoder */
/**
diff --git a/libavcodec/mqcdec.c b/libavcodec/mqcdec.c
index 889763a..3625069 100644
--- a/libavcodec/mqcdec.c
+++ b/libavcodec/mqcdec.c
@@ -2,20 +2,20 @@
* MQ-coder decoder
* Copyright (c) 2007 Kamil Nowosad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mqcenc.c b/libavcodec/mqcenc.c
new file mode 100644
index 0000000..97d352b
--- /dev/null
+++ b/libavcodec/mqcenc.c
@@ -0,0 +1,119 @@
+/*
+ * MQ-coder encoder
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * MQ-coder encoder
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include "mqc.h"
+
+static void byteout(MqcState *mqc)
+{
+retry:
+ if (*mqc->bp == 0xff){
+ mqc->bp++;
+ *mqc->bp = mqc->c >> 20;
+ mqc->c &= 0xfffff;
+ mqc->ct = 7;
+ } else if ((mqc->c & 0x8000000)){
+ (*mqc->bp)++;
+ mqc->c &= 0x7ffffff;
+ goto retry;
+ } else{
+ mqc->bp++;
+ *mqc->bp = mqc->c >> 19;
+ mqc->c &= 0x7ffff;
+ mqc->ct = 8;
+ }
+}
+
+static void renorme(MqcState *mqc)
+{
+ do{
+ mqc->a += mqc->a;
+ mqc->c += mqc->c;
+ if (!--mqc->ct)
+ byteout(mqc);
+ } while (!(mqc->a & 0x8000));
+}
+
+static void setbits(MqcState *mqc)
+{
+ int tmp = mqc->c + mqc->a;
+ mqc->c |= 0xffff;
+ if (mqc->c >= tmp)
+ mqc->c -= 0x8000;
+}
+
+void ff_mqc_initenc(MqcState *mqc, uint8_t *bp)
+{
+ ff_mqc_init_contexts(mqc);
+ mqc->a = 0x8000;
+ mqc->c = 0;
+ mqc->bp = bp-1;
+ mqc->bpstart = bp;
+ mqc->ct = 12 + (*mqc->bp == 0xff);
+}
+
+void ff_mqc_encode(MqcState *mqc, uint8_t *cxstate, int d)
+{
+ int qe;
+
+ qe = ff_mqc_qe[*cxstate];
+ mqc->a -= qe;
+ if ((*cxstate & 1) == d){
+ if (!(mqc->a & 0x8000)){
+ if (mqc->a < qe)
+ mqc->a = qe;
+ else
+ mqc->c += qe;
+ *cxstate = ff_mqc_nmps[*cxstate];
+ renorme(mqc);
+ } else
+ mqc->c += qe;
+ } else{
+ if (mqc->a < qe)
+ mqc->c += qe;
+ else
+ mqc->a = qe;
+ *cxstate = ff_mqc_nlps[*cxstate];
+ renorme(mqc);
+ }
+}
+
+int ff_mqc_length(MqcState *mqc)
+{
+ return mqc->bp - mqc->bpstart;
+}
+
+int ff_mqc_flush(MqcState *mqc)
+{
+ setbits(mqc);
+ mqc->c = mqc->c << mqc->ct;
+ byteout(mqc);
+ mqc->c = mqc->c << mqc->ct;
+ byteout(mqc);
+ if (*mqc->bp != 0xff)
+ mqc->bp++;
+ return mqc->bp - mqc->bpstart;
+}
diff --git a/libavcodec/msgsmdec.c b/libavcodec/msgsmdec.c
index 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..a054520 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 */
@@ -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])
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 5721d8f..50ba18c 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 ebaf2e5..768b520 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);
@@ -909,6 +916,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,
.long_name = NULL_IF_CONFIG_SMALL("MPEG-4 part 2 Microsoft variant version 1"),
.pix_fmts = ff_pixfmt_list_420,
};
@@ -922,6 +930,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,
.long_name = NULL_IF_CONFIG_SMALL("MPEG-4 part 2 Microsoft variant version 2"),
.pix_fmts = ff_pixfmt_list_420,
};
@@ -935,6 +944,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,
.long_name = NULL_IF_CONFIG_SMALL("MPEG-4 part 2 Microsoft variant version 3"),
.pix_fmts = ff_pixfmt_list_420,
};
@@ -948,6 +958,7 @@ AVCodec ff_wmv1_decoder = {
.close = ff_h263_decode_end,
.decode = ff_h263_decode_frame,
.capabilities = CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1,
+ .max_lowres = 3,
.long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 7"),
.pix_fmts = ff_pixfmt_list_420,
};
diff --git a/libavcodec/msmpeg4enc.c b/libavcodec/msmpeg4enc.c
index 45ef208..74e2c4d 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
*/
@@ -150,8 +150,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 +274,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 +495,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 fe6819c..674e586 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..83d7d13 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)) {
@@ -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);
+ for(i = 0; i < p1; i++)
+ *output++ = pix[0];
+ 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 dffdde5..bb1858d 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 2562209..54b9fb5 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
*/
@@ -598,10 +598,8 @@ static int mss2_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if (c->mvX < 0 || c->mvY < 0) {
FFSWAP(uint8_t *, c->pal_pic, c->last_pal_pic);
- if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
if (ctx->last_pic.data[0]) {
av_assert0(frame->linesize[0] == ctx->last_pic.linesize[0]);
@@ -612,10 +610,8 @@ static int mss2_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
}
} else {
- if ((ret = ff_reget_buffer(avctx, &ctx->last_pic)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, &ctx->last_pic)) < 0)
return ret;
- }
if ((ret = av_frame_ref(frame, &ctx->last_pic)) < 0)
return ret;
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 fa5b99c..3cc484f 100644
--- a/libavcodec/mss3.c
+++ b/libavcodec/mss3.c
@@ -2,20 +2,20 @@
* Microsoft Screen 3 (aka Microsoft ATC Screen) decoder
* Copyright (c) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -296,7 +296,7 @@ static void rac_normalise(RangeCoder *c)
c->low |= *c->src++;
} else if (!c->low) {
c->got_error = 1;
- return;
+ c->low = 1;
}
if (c->range >= RAC_BOTTOM)
return;
@@ -731,10 +731,8 @@ static int mss3_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return buf_size;
c->got_error = 0;
- if ((ret = ff_reget_buffer(avctx, &c->pic)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, &c->pic)) < 0)
return ret;
- }
c->pic.key_frame = keyframe;
c->pic.pict_type = keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
if (!bytestream2_get_bytes_left(&gb)) {
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 a74c363..c518fda 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 fd968bc..c5a1daa 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..e0efb48
--- /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",
+ .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},
+ .long_name = NULL_IF_CONFIG_SMALL("Microsoft Video-1"),
+};
diff --git a/libavcodec/mvcdec.c b/libavcodec/mvcdec.c
new file mode 100644
index 0000000..c4385fe
--- /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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"),
+};
+#endif
+
+#if CONFIG_MVC2_DECODER
+AVCodec ff_mvc2_decoder = {
+ .name = "mvc2",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"),
+};
+#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 cfd0709..42110a2 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 98fef23..b35820a 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..c91e85b 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++){
diff --git a/libavcodec/nuv.c b/libavcodec/nuv.c
index 4d5063f..edf777e 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,12 +121,16 @@ 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) {
+ // also reserve space for a possible additional header
+ int buf_size = 24 + height * width * 3 / 2 + AV_LZO_OUTPUT_PADDING;
+ 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;
av_fast_malloc(&c->decomp_buf, &c->decomp_size,
- c->height * c->width * 3 / 2);
+ buf_size);
if (!c->decomp_buf) {
av_log(avctx, AV_LOG_ERROR,
"Can't allocate decompression buffer.\n");
@@ -133,6 +138,7 @@ static int codec_reinit(AVCodecContext *avctx, int width, int height,
}
ff_rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height,
c->lq, c->cq);
+ return 1;
} else if (quality != c->quality)
ff_rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height,
c->lq, c->cq);
@@ -149,6 +155,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVFrame *picture = data;
int orig_size = buf_size;
int keyframe;
+ int size_change = 0;
int result, init_frame = !avctx->frame_number;
enum {
NUV_UNCOMPRESSED = '0',
@@ -178,7 +185,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;
}
@@ -195,21 +202,28 @@ 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, inlen = buf_size;
+ int outlen = c->decomp_size - AV_LZO_OUTPUT_PADDING, inlen = buf_size;
if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen))
av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
buf = c->decomp_buf;
- buf_size = c->decomp_size;
+ buf_size = c->decomp_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]);
@@ -217,20 +231,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 (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);
@@ -248,7 +265,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
--- /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 d140552..fb803f3 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
@@ -179,6 +226,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 +244,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 5595c0e..4fd6cff 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 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 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 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,7 +103,7 @@ static const AVOption 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},
{"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},
@@ -140,10 +145,13 @@ static const AVOption options[]={
{"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 = AV_EF_CRCCHECK }, 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"},
+{"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 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},
@@ -243,6 +251,10 @@ static const AVOption 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 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"},
@@ -298,6 +310,7 @@ static const AVOption 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},
@@ -306,18 +319,18 @@ static const AVOption 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},
@@ -334,7 +347,7 @@ static const AVOption 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},
@@ -357,17 +370,13 @@ static const AVOption 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 },
{NULL},
};
diff --git a/libavcodec/os2threads.h b/libavcodec/os2threads.h
new file mode 100644
index 0000000..b816bff
--- /dev/null
+++ b/libavcodec/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/libavcodec/paf.c b/libavcodec/paf.c
new file mode 100644
index 0000000..300238e
--- /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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File Video"),
+};
+
+AVCodec ff_paf_audio_decoder = {
+ .name = "paf_audio",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_PAF_AUDIO,
+ .init = paf_aud_init,
+ .decode = paf_aud_decode,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File Audio"),
+};
diff --git a/libavcodec/paf.h b/libavcodec/paf.h
new file mode 100644
index 0000000..ce8245f
--- /dev/null
+++ b/libavcodec/paf.h
@@ -0,0 +1,28 @@
+/*
+ * Packed Animation File decoder/demuxer common code
+ * Copyright (c) 2012 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_PAF_H
+#define AVCODEC_PAF_H
+
+#define PAF_SOUND_SAMPLES 2205
+#define PAF_SOUND_FRAME_SIZE ((256 + PAF_SOUND_SAMPLES) * 2)
+
+#endif /* AVCODEC_PAF_H */
diff --git a/libavcodec/pamenc.c b/libavcodec/pamenc.c
index dba4771..3e47278 100644
--- a/libavcodec/pamenc.c
+++ b/libavcodec/pamenc.c
@@ -2,25 +2,24 @@
* 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"
@@ -34,26 +33,11 @@ static int pam_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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 +48,57 @@ 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;
+
+ *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;
+
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 +107,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 {
@@ -122,8 +137,7 @@ AVCodec ff_pam_encoder = {
.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
},
.long_name = NULL_IF_CONFIG_SMALL("PAM (Portable AnyMap) image"),
};
diff --git a/libavcodec/parser.c b/libavcodec/parser.c
index 6e755f6..f7cb5cf 100644
--- a/libavcodec/parser.c
+++ b/libavcodec/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
*/
@@ -40,7 +40,7 @@ void av_register_codec_parser(AVCodecParser *parser)
AVCodecParserContext *av_parser_init(int codec_id)
{
- AVCodecParserContext *s;
+ AVCodecParserContext *s = NULL;
AVCodecParser *parser;
int ret;
@@ -59,31 +59,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){
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-mpeg.c b/libavcodec/pcm-mpeg.c
index e13e2b0..aec056a 100644
--- a/libavcodec/pcm-mpeg.c
+++ b/libavcodec/pcm-mpeg.c
@@ -2,20 +2,20 @@
* LPCM codecs for PCM formats found in MPEG streams
* Copyright (c) 2009 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
*/
@@ -70,13 +70,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 -1;
}
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) {
@@ -152,10 +153,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.c b/libavcodec/pcm.c
index c56a95e..83482dd 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
*/
@@ -79,13 +79,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 +107,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 +121,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 +149,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 +162,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 +186,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 +196,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 +243,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 +259,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,6 +281,18 @@ static av_cold int pcm_decode_init(AVCodecContext *avctx)
dst += size / 8; \
}
+#define DECODE_PLANAR(size, endian, src, dst, n, shift, offset) \
+ 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; \
+ } \
+ }
+
static int pcm_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame_ptr, AVPacket *avpkt)
{
@@ -268,7 +311,9 @@ static int pcm_decode_frame(AVCodecContext *avctx, void *data,
if (AV_CODEC_ID_PCM_DVD == avctx->codec_id) {
if (avctx->bits_per_coded_sample != 20 &&
avctx->bits_per_coded_sample != 24) {
- 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(EINVAL);
}
/* 2 samples are interleaved per block in PCM_DVD */
@@ -285,12 +330,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;
}
@@ -299,13 +356,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;
@@ -315,6 +370,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;
@@ -333,22 +391,6 @@ static int pcm_decode_frame(AVCodecContext *avctx, void *data,
samples += 2;
}
break;
- case AV_CODEC_ID_PCM_S16LE_PLANAR:
- {
- int av_unused n2;
- n /= avctx->channels;
- for (c = 0; c < avctx->channels; c++) {
- samples = frame->extended_data[c];
-#if HAVE_BIGENDIAN
- n2 = n;
- DECODE(16, le16, src, samples, n2, 0, 0)
-#else
- memcpy(samples, src, n * 2);
- src += n * 2;
-#endif
- }
- break;
- }
case AV_CODEC_ID_PCM_U16LE:
DECODE(16, le16, src, samples, n, 0, 0x8000)
break;
@@ -359,6 +401,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)
@@ -367,9 +418,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:
@@ -385,6 +442,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:
@@ -393,6 +453,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++;
@@ -521,23 +593,27 @@ 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_DECODER(PCM_DVD, AV_SAMPLE_FMT_S32, pcm_dvd, "PCM signed 20|24-bit big-endian");
PCM_CODEC (PCM_F32BE, AV_SAMPLE_FMT_FLT, pcm_f32be, "PCM 32-bit floating point big-endian");
PCM_CODEC (PCM_F32LE, AV_SAMPLE_FMT_FLT, pcm_f32le, "PCM 32-bit floating point little-endian");
PCM_CODEC (PCM_F64BE, AV_SAMPLE_FMT_DBL, pcm_f64be, "PCM 64-bit floating point big-endian");
PCM_CODEC (PCM_F64LE, AV_SAMPLE_FMT_DBL, pcm_f64le, "PCM 64-bit floating point little-endian");
-PCM_DECODER(PCM_LXF, AV_SAMPLE_FMT_S32P, pcm_lxf, "PCM signed 20-bit little-endian planar");
-PCM_CODEC (PCM_MULAW, AV_SAMPLE_FMT_S16, pcm_mulaw, "PCM mu-law");
+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_CODEC (PCM_S24LE_PLANAR, AV_SAMPLE_FMT_S32P,pcm_s24le_planar, "PCM signed 24-bit little-endian planar");
PCM_CODEC (PCM_S32BE, AV_SAMPLE_FMT_S32, pcm_s32be, "PCM signed 32-bit big-endian");
PCM_CODEC (PCM_S32LE, AV_SAMPLE_FMT_S32, pcm_s32le, "PCM signed 32-bit little-endian");
+PCM_CODEC (PCM_S32LE_PLANAR, AV_SAMPLE_FMT_S32P,pcm_s32le_planar, "PCM signed 32-bit little-endian planar");
PCM_CODEC (PCM_U8, AV_SAMPLE_FMT_U8, pcm_u8, "PCM unsigned 8-bit");
PCM_CODEC (PCM_U16BE, AV_SAMPLE_FMT_S16, pcm_u16be, "PCM unsigned 16-bit big-endian");
PCM_CODEC (PCM_U16LE, AV_SAMPLE_FMT_S16, pcm_u16le, "PCM unsigned 16-bit little-endian");
@@ -546,3 +622,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 949ea1c..ba92332 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,65 +28,66 @@
#include "get_bits.h"
#include "internal.h"
-/**
- * @return advanced src pointer
- */
-static const uint8_t *pcx_rle_decode(const uint8_t *src, 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) {
run = 1;
- value = *src++;
+ value = bytestream2_get_byte(gb);
if (value >= 0xc0) {
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) {
- unsigned int i;
+static void pcx_palette(GetByteContext *gb, uint32_t *dst, int pallen)
+{
+ 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));
}
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;
+ GetByteContext gb;
AVFrame * const p = data;
- int compressed, xmin, ymin, xmax, ymax;
+ int compressed, xmin, ymin, xmax, ymax, ret;
unsigned int w, h, bits_per_pixel, bytes_per_line, nplanes, stride, y, x,
bytes_per_scanline;
- uint8_t *ptr;
- 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");
@@ -96,12 +97,12 @@ 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) {
+ if (bytes_per_scanline < (w * bits_per_pixel * nplanes + 7) / 8) {
av_log(avctx, AV_LOG_ERROR, "PCX data is corrupted\n");
return AVERROR_INVALIDDATA;
}
@@ -124,29 +125,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, 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 ];
@@ -158,19 +157,20 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
}
} else if (nplanes == 1 && bits_per_pixel == 8) {
- const uint8_t *palstart = bufstart + buf_size - 769;
+ int palstart = avpkt->size - 769;
for (y=0; y<h; y++, ptr+=stride) {
- buf = pcx_rle_decode(buf, 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 = AVERROR_INVALIDDATA;
goto end;
}
@@ -178,9 +178,9 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
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, 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);
@@ -191,7 +191,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, 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;
@@ -205,16 +205,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 e0ee20a..7cb3af3 100644
--- a/libavcodec/pcxenc.c
+++ b/libavcodec/pcxenc.c
@@ -2,20 +2,20 @@
* PC Paintbrush PCX (.pcx) image encoder
* Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,6 +28,7 @@
#include "avcodec.h"
#include "bytestream.h"
+#include "libavutil/imgutils.h"
#include "internal.h"
typedef struct PCXContext {
@@ -104,8 +105,9 @@ static int pcx_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const uint8_t *buf_end;
uint8_t *buf;
- int bpp, nplanes, i, y, line_bytes, written, ret, max_pkt_size;
+ int bpp, nplanes, i, y, line_bytes, written, ret, max_pkt_size, sw, sh;
const uint32_t *pal = NULL;
+ uint32_t palette256[256];
const uint8_t *src;
*pict = *frame;
@@ -127,6 +129,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 +153,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 +171,8 @@ static int pcx_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
bytestream_put_le16(&buf, 0); // y min
bytestream_put_le16(&buf, avctx->width - 1); // x max
bytestream_put_le16(&buf, avctx->height - 1); // y max
- bytestream_put_le16(&buf, 0); // horizontal DPI
- bytestream_put_le16(&buf, 0); // vertical DPI
+ bytestream_put_le16(&buf, sw); // horizontal DPI
+ bytestream_put_le16(&buf, sh); // vertical DPI
for (i = 0; i < 16; i++)
bytestream_put_be24(&buf, pal ? pal[i] : 0);// palette (<= 16 color only)
bytestream_put_byte(&buf, 0); // reserved
diff --git a/libavcodec/pgssubdec.c b/libavcodec/pgssubdec.c
index f22088a..d0cff7b 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;
}
@@ -90,7 +105,7 @@ static av_cold int close_decoder(AVCodecContext *avctx)
* @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",
.type = AVMEDIA_TYPE_SUBTITLE,
@@ -488,4 +545,5 @@ AVCodec ff_pgssub_decoder = {
.close = close_decoder,
.decode = decode,
.long_name = NULL_IF_CONFIG_SMALL("HDMV Presentation Graphic Stream subtitles"),
+ .priv_class = &pgsdec_class,
};
diff --git a/libavcodec/pictordec.c b/libavcodec/pictordec.c
index 9c884ff..bf138b2 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);
@@ -123,11 +123,11 @@ static int decode_frame(AVCodecContext *avctx,
s->nb_planes = (tmp >> 4) + 1;
bpp = bits_per_plane * s->nb_planes;
if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
- avpriv_request_sample(s, "Unsupported bit depth");
+ avpriv_request_sample(avctx, "Unsupported bit depth");
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);
@@ -146,10 +146,8 @@ static int decode_frame(AVCodecContext *avctx,
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,11 +196,12 @@ 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)) {
- while (bytestream2_get_bytes_left(&s->g) >= 6) {
+ x = 0;
+ plane = 0;
+ while (y >= 0 && bytestream2_get_bytes_left(&s->g) >= 6) {
int stop_size, marker, t1, t2;
t1 = bytestream2_get_bytes_left(&s->g);
@@ -210,10 +211,10 @@ static int decode_frame(AVCodecContext *avctx,
bytestream2_skip(&s->g, 2);
marker = bytestream2_get_byte(&s->g);
- while (plane < s->nb_planes &&
+ while (plane < s->nb_planes && y >= 0 &&
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)
@@ -225,16 +226,25 @@ static int decode_frame(AVCodecContext *avctx,
if (bits_per_plane == 8) {
picmemset_8bpp(s, frame, val, run, &x, &y);
- if (y < 0)
- break;
} else {
picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane);
}
}
}
+
+ if (x < avctx->width && y >= 0) {
+ 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(s, "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--;
+ }
}
*got_frame = 1;
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
--- /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 ec44d56..8b33826 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -2,22 +2,26 @@
* 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"
@@ -26,13 +30,14 @@
#include "pngdsp.h"
/* TODO:
- * - add 2, 4 and 16 bit depth support
+ * - add 16 bit depth support
*/
#include <zlib.h>
typedef struct PNGDecContext {
PNGDSPContext dsp;
+ AVCodecContext *avctx;
GetByteContext gb;
AVFrame *prev;
@@ -62,9 +67,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 +93,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 +187,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 +203,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 +249,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 +260,21 @@ static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type,
}
}
-static av_always_inline void convert_to_rgb32_loco(uint8_t *dst,
- const uint8_t *src,
- int width, int loco)
-{
- int j;
- unsigned int r, g, b, a;
-
- for (j = 0; j < width; j++) {
- r = src[0];
- g = src[1];
- b = src[2];
- a = src[3];
- if (loco) {
- r = (r + g) & 0xff;
- b = (b + g) & 0xff;
- }
- *(uint32_t *)dst = (a << 24) | (r << 16) | (g << 8) | b;
- dst += 4;
- src += 4;
- }
-}
-
-static void convert_to_rgb32(uint8_t *dst, const uint8_t *src, int width, int loco)
-{
- if (loco)
- convert_to_rgb32_loco(dst, src, width, 1);
- else
- convert_to_rgb32_loco(dst, src, width, 0);
+/* This used to be called "deloco" in FFmpeg
+ * and is actually an inverse reversible colorspace transformation */
+#define YUV2RGB(NAME, TYPE) \
+static void deloco_ ## NAME(TYPE *dst, int size, int alpha) \
+{ \
+ int i; \
+ for (i = 0; i < size; i += 3 + alpha) { \
+ int g = dst [i+1]; \
+ dst[i+0] += g; \
+ dst[i+2] += g; \
+ } \
}
-static void deloco_rgb24(uint8_t *dst, int size)
-{
- int i;
- for (i = 0; i < size; i += 3) {
- int g = dst[i + 1];
- dst[i + 0] += g;
- dst[i + 2] += g;
- }
-}
+YUV2RGB(rgb8, uint8_t)
+YUV2RGB(rgb16, uint16_t)
/* process exactly one decompressed row */
static void png_handle_row(PNGDecContext *s)
@@ -288,14 +284,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 +291,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;
@@ -330,12 +329,12 @@ static void png_handle_row(PNGDecContext *s)
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,13 +361,14 @@ 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) {
+ av_log(s->avctx, AV_LOG_ERROR, "inflate returned %d\n", ret);
return -1;
}
if (s->zstream.avail_out == 0) {
@@ -382,6 +382,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)
@@ -390,17 +506,22 @@ static int decode_frame(AVCodecContext *avctx,
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
AVFrame *p = data;
+ AVDictionary *metadata = NULL;
uint8_t *crow_buf_base = NULL;
uint32_t tag, length;
+ int64_t sig;
int ret;
+ 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)
+ sig = bytestream2_get_be64(&s->gb);
+ if (sig != PNGSIG &&
+ sig != MNGSIG) {
+ av_log(avctx, AV_LOG_ERROR, "Missing png signature\n");
return -1;
+ }
- bytestream2_init(&s->gb, buf + 8, buf_size - 8);
s->y = s->state = 0;
/* init the zlib */
@@ -408,16 +529,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)
+ if (ret != Z_OK) {
+ av_log(avctx, AV_LOG_ERROR, "inflateInit returned %d\n", ret);
return -1;
+ }
for (;;) {
- if (bytestream2_get_bytes_left(&s->gb) <= 0)
+ if (bytestream2_get_bytes_left(&s->gb) <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "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),
@@ -430,6 +559,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);
@@ -439,14 +569,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;
@@ -457,13 +602,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 &&
@@ -472,23 +617,26 @@ 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_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF) < 0)
goto fail;
- }
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
p->interlaced_frame = !!s->interlace_type;
@@ -508,7 +656,7 @@ 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);
@@ -547,10 +695,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 */
@@ -572,9 +720,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:
@@ -585,9 +746,86 @@ 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 ( !(avpkt->flags & AV_PKT_FLAG_KEY)
+ && s->prev->width == p->width
+ && s->prev->height== p->height
+ && s->prev->format== p->format
+ ) {
int i, j;
uint8_t *pd = p->data[0];
uint8_t *pd_last = s->prev->data[0];
@@ -602,7 +840,10 @@ static int decode_frame(AVCodecContext *avctx,
}
}
- av_frame_unref(s->prev);
+ av_frame_set_metadata(p, metadata);
+ metadata = NULL;
+
+ av_frame_unref(s->prev);
if ((ret = av_frame_ref(s->prev, p)) < 0)
goto fail;
@@ -617,6 +858,7 @@ static int decode_frame(AVCodecContext *avctx,
av_freep(&s->tmp_row);
return ret;
fail:
+ av_dict_free(&metadata);
ret = -1;
goto the_end;
}
@@ -631,6 +873,8 @@ static av_cold int png_dec_init(AVCodecContext *avctx)
ff_pngdsp_init(&s->dsp);
+ s->avctx = avctx;
+
return 0;
}
diff --git a/libavcodec/pngdsp.c b/libavcodec/pngdsp.c
index afd9093..0d24775 100644
--- a/libavcodec/pngdsp.c
+++ b/libavcodec/pngdsp.c
@@ -2,20 +2,20 @@
* PNG image format
* Copyright (c) 2008 Loren Merrit <lorenm@u.washington.edu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/pngdsp.h b/libavcodec/pngdsp.h
index 98d29a8..1475b0c 100644
--- a/libavcodec/pngdsp.h
+++ b/libavcodec/pngdsp.h
@@ -2,20 +2,20 @@
* PNG image format
* Copyright (c) 2008 Loren Merrit <lorenm@u.washington.edu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c
index 7f601ca..dc86171 100644
--- a/libavcodec/pngenc.c
+++ b/libavcodec/pngenc.c
@@ -2,27 +2,31 @@
* 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"
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+
/* TODO:
* - add 2, 4 and 16 bit depth support
*/
@@ -32,6 +36,7 @@
#define IOBUF_SIZE 4096
typedef struct PNGEncContext {
+ AVClass *class;
DSPContext dsp;
uint8_t *bytestream;
@@ -43,6 +48,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 +59,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 +152,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 +178,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 +224,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 +238,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;
@@ -255,10 +254,18 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
bit_depth = 8;
color_type = PNG_COLOR_TYPE_RGB;
break;
+ case AV_PIX_FMT_GRAY16BE:
+ bit_depth = 16;
+ color_type = PNG_COLOR_TYPE_GRAY;
+ break;
case AV_PIX_FMT_GRAY8:
bit_depth = 8;
color_type = PNG_COLOR_TYPE_GRAY;
break;
+ case AV_PIX_FMT_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;
@@ -285,15 +292,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;
@@ -308,19 +313,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);
@@ -333,6 +333,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;
@@ -347,7 +358,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);
@@ -374,10 +385,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);
@@ -392,11 +399,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;
@@ -428,7 +430,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;
@@ -440,6 +441,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);
@@ -448,9 +466,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",
.type = AVMEDIA_TYPE_VIDEO,
@@ -458,9 +498,15 @@ 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
},
.long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
+ .priv_class = &pngenc_class,
};
diff --git a/libavcodec/pnm.c b/libavcodec/pnm.c
index eea30e8..308457b 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 == 255) {
avctx->pix_fmt = AV_PIX_FMT_GRAY8;
+ } else {
+ avctx->pix_fmt = AV_PIX_FMT_GRAY16BE;
+ }
+ } 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_RGB48BE;
}
} 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_RGBA64BE;
+ }
} 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) {
@@ -152,11 +163,8 @@ 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;
} 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_RGB48BE;
} else if (avctx->pix_fmt == AV_PIX_FMT_YUV420P && s->maxval < 65536) {
if (s->maxval < 512)
avctx->pix_fmt = AV_PIX_FMT_YUV420P9BE;
diff --git a/libavcodec/pnm.h b/libavcodec/pnm.h
index ec5ebdb..92edf8d 100644
--- a/libavcodec/pnm.h
+++ b/libavcodec/pnm.h
@@ -2,20 +2,20 @@
* PNM image format
* Copyright (c) 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/pnm_parser.c b/libavcodec/pnm_parser.c
index 2e00c0a..2a9e3e1 100644
--- a/libavcodec/pnm_parser.c
+++ b/libavcodec/pnm_parser.c
@@ -2,20 +2,20 @@
* PNM image parser
* Copyright (c) 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/pnmdec.c b/libavcodec/pnmdec.c
index 38056fb..d0c7295 100644
--- a/libavcodec/pnmdec.c
+++ b/libavcodec/pnmdec.c
@@ -2,25 +2,24 @@
* 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"
@@ -33,32 +32,40 @@ 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;
switch (avctx->pix_fmt) {
default:
return AVERROR(EINVAL);
+ case AV_PIX_FMT_RGBA64BE:
+ n = avctx->width * 8;
+ components=4;
+ sample_len=16;
+ goto do_read;
case AV_PIX_FMT_RGB48BE:
n = avctx->width * 6;
components=3;
sample_len=16;
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;
@@ -71,6 +78,11 @@ static int pnm_decode_frame(AVCodecContext *avctx, void *data,
if (s->maxval < 255)
upgrade = 1;
goto do_read;
+ case AV_PIX_FMT_GRAY8A:
+ n = avctx->width * 2;
+ components=2;
+ sample_len=8;
+ goto do_read;
case AV_PIX_FMT_GRAY16BE:
case AV_PIX_FMT_GRAY16LE:
n = avctx->width * 2;
@@ -84,26 +96,34 @@ 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);
+ 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);
+ }
put_bits(&pb, sample_len, (((1<<sample_len)-1)*v + (s->maxval>>1))/s->maxval);
}
flush_put_bits(&pb);
@@ -202,24 +222,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 7d8792f..8cd96be 100644
--- a/libavcodec/pnmenc.c
+++ b/libavcodec/pnmenc.c
@@ -2,26 +2,25 @@
* 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"
@@ -34,12 +33,10 @@ static int pnm_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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;
@@ -73,6 +70,10 @@ static int pnm_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
n = avctx->width * 6;
break;
case AV_PIX_FMT_YUV420P:
+ if (avctx->width & 1 || avctx->height & 1) {
+ av_log(avctx, AV_LOG_ERROR, "pgmyuv needs even width and height\n");
+ return AVERROR(EINVAL);
+ }
c = '5';
n = avctx->width;
h1 = (h * 3) / 2;
diff --git a/libavcodec/ppc/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 463bc70..6112b0c 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
*/
@@ -140,6 +140,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 HAVE_ALTIVEC
- if (av_get_cpu_flags() & AV_CPU_FLAG_ALTIVEC) {
+ if (mm_flags & AV_CPU_FLAG_ALTIVEC) {
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 b1e70d6..acab127 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 b9dd4a2..92b7adb 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 c72d0a4..bf8ead4 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..4db761d 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
*/
diff --git a/libavcodec/ppc/h264chroma_init.c b/libavcodec/ppc/h264chroma_init.c
index f36d8e9..82385cc 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 a46327f..1670ece 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 113617c..bda7b18 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 69c2777..19e2aa1 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 67d119c..4386b13 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 64a6d03..1d82f74 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 4ad24b9..4e80e3a 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 251be13..08a2b26 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 48436f3..502b8b7 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..2401d2a 100644
--- a/libavcodec/ppc/vp8dsp_altivec.c
+++ b/libavcodec/ppc/vp8dsp_altivec.c
@@ -3,20 +3,20 @@
*
* Copyright (C) 2010 David Conrad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/proresdata.h b/libavcodec/proresdata.h
index 1e5d05e..ee8278d 100644
--- a/libavcodec/proresdata.h
+++ b/libavcodec/proresdata.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010-2011 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/proresdec.h b/libavcodec/proresdec.h
new file mode 100644
index 0000000..f42c448
--- /dev/null
+++ b/libavcodec/proresdec.h
@@ -0,0 +1,54 @@
+/*
+ * 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;
+} ProresContext;
+
+#endif /* AVCODEC_PRORESDEC_H */
diff --git a/libavcodec/proresdec2.c b/libavcodec/proresdec2.c
new file mode 100644
index 0000000..bd6404a
--- /dev/null
+++ b/libavcodec/proresdec2.c
@@ -0,0 +1,597 @@
+/*
+ * 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"
+
+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 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 interlaced_scan[64] = {
+ 0, 8, 1, 9, 16, 24, 17, 25,
+ 2, 10, 3, 11, 18, 26, 19, 27,
+ 32, 40, 33, 34, 41, 48, 56, 49,
+ 42, 35, 43, 50, 57, 58, 51, 59,
+ 4, 12, 5, 6, 13, 20, 28, 21,
+ 14, 7, 15, 22, 29, 36, 44, 37,
+ 30, 23, 31, 38, 45, 52, 60, 53,
+ 46, 39, 47, 54, 61, 62, 55, 63,
+};
+
+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, progressive_scan, idct_permutation);
+ permute(ctx->interlaced_scan, 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 -1;
+ }
+
+ 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 -1;
+ }
+
+ 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 -1;
+ }
+
+ ctx->frame_type = (buf[12] >> 2) & 3;
+
+ 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;
+ }
+
+ 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 -1;
+ }
+ 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 -1;
+ }
+ 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 -1;
+ }
+
+ 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 -1;
+ }
+
+ 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 -1;
+ }
+
+ 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 -1;
+ }
+
+ // 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 -1;
+ }
+
+ 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 -1;
+ }
+ }
+
+ 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 -1;
+ }
+
+ 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 void 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;
+ }
+
+ 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);
+}
+
+static void 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;
+
+ 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);
+ decode_ac_coeffs(avctx, &gb, blocks, blocks_per_slice);
+
+ 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;
+ }
+}
+
+static void 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;
+
+ 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);
+ decode_ac_coeffs(avctx, &gb, blocks, blocks_per_slice);
+
+ 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;
+ }
+ }
+}
+
+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;
+ uint8_t *dest_y, *dest_u, *dest_v;
+ int16_t qmat_luma_scaled[64];
+ int16_t qmat_chroma_scaled[64];
+ int mb_x_shift;
+
+ 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);
+
+ 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 -1;
+ }
+
+ 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) {
+ 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);
+
+ 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];
+ }
+
+ decode_slice_luma(avctx, slice, (uint16_t*)dest_y, luma_stride,
+ buf, y_data_size, qmat_luma_scaled);
+
+ if (!(avctx->flags & CODEC_FLAG_GRAY)) {
+ 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);
+ 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);
+ }
+
+ 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;
+
+ if (buf_size < 28 || AV_RL32(buf + 4) != AV_RL32("icpf")) {
+ av_log(avctx, AV_LOG_ERROR, "invalid frame header\n");
+ return -1;
+ }
+
+ 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 -1;
+
+ buf += frame_hdr_size;
+ buf_size -= frame_hdr_size;
+
+ if (ff_get_buffer(avctx, frame, 0) < 0)
+ return -1;
+
+ 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 -1;
+ }
+
+ if (decode_picture(avctx)) {
+ av_log(avctx, AV_LOG_ERROR, "error decoding picture\n");
+ return -1;
+ }
+
+ 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",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_PRORES,
+ .priv_data_size = sizeof(ProresContext),
+ .init = decode_init,
+ .close = decode_close,
+ .decode = decode_frame,
+ .long_name = NULL_IF_CONFIG_SMALL("ProRes"),
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_SLICE_THREADS,
+};
diff --git a/libavcodec/proresdec.c b/libavcodec/proresdec_lgpl.c
index c42e444..59c9843 100644
--- a/libavcodec/proresdec.c
+++ b/libavcodec/proresdec_lgpl.c
@@ -86,7 +86,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
ctx->slice_data = NULL;
avctx->bits_per_raw_sample = PRORES_BITS_PER_SAMPLE;
- ff_proresdsp_init(&ctx->dsp);
+ ff_proresdsp_init(&ctx->dsp, avctx);
ctx->scantable_type = -1; // set scantable type to uninitialized
memset(ctx->qmat_luma, 4, 64);
@@ -655,8 +655,8 @@ static av_cold int decode_close(AVCodecContext *avctx)
}
-AVCodec ff_prores_decoder = {
- .name = "prores",
+AVCodec ff_prores_lgpl_decoder = {
+ .name = "prores_lgpl",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_PRORES,
.priv_data_size = sizeof(ProresContext),
diff --git a/libavcodec/proresdsp.c b/libavcodec/proresdsp.c
index 1c0f391..95176a5 100644
--- a/libavcodec/proresdsp.c
+++ b/libavcodec/proresdsp.c
@@ -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_anatoliy.c b/libavcodec/proresenc_anatoliy.c
new file mode 100644
index 0000000..ccd0392
--- /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",
+ .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},
+ .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes"),
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
+ .profiles = profiles
+};
+
+AVCodec ff_prores_encoder = {
+ .name = "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},
+ .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes"),
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
+ .profiles = profiles
+};
diff --git a/libavcodec/proresenc.c b/libavcodec/proresenc_kostya.c
index 5a8cea8..2d6dcce 100644
--- a/libavcodec/proresenc.c
+++ b/libavcodec/proresenc_kostya.c
@@ -3,6 +3,9 @@
*
* Copyright (c) 2012 Konstantin Shishkov
*
+ * This encoder appears to be based on Anatoliy Wassermans considering
+ * similarities in the bugs.
+ *
* This file is part of Libav.
*
* Libav is free software; you can redistribute it and/or
@@ -753,10 +756,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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");
+ if ((ret = ff_alloc_packet2(avctx, pkt, pkt_size)) < 0)
return ret;
- }
orig_buf = pkt->data;
@@ -845,10 +846,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
}
- if (ctx->pictures_per_frame == 1)
- picture_size = buf - picture_size_pos - 6;
- else
- picture_size = buf - picture_size_pos + 1;
+ picture_size = buf - (picture_size_pos - 1);
bytestream_put_be32(&picture_size_pos, picture_size);
}
@@ -893,7 +891,7 @@ static av_cold int encode_init(AVCodecContext *avctx)
if (!avctx->coded_frame)
return AVERROR(ENOMEM);
- ff_proresdsp_init(&ctx->dsp);
+ ff_proresdsp_init(&ctx->dsp, avctx);
ff_init_scantable(ctx->dsp.dct_permutation, &ctx->scantable,
interlaced ? ff_prores_interlaced_scan
: ff_prores_progressive_scan);
@@ -1062,8 +1060,8 @@ static const AVClass proresenc_class = {
.version = LIBAVUTIL_VERSION_INT,
};
-AVCodec ff_prores_encoder = {
- .name = "prores",
+AVCodec ff_prores_ks_encoder = {
+ .name = "prores_ks",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_PRORES,
.priv_data_size = sizeof(ProresContext),
diff --git a/libavcodec/psymodel.c b/libavcodec/psymodel.c
index a2af611..ea11636 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
*/
@@ -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 1dbfe3d..6942c1e 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
*/
@@ -32,7 +32,9 @@
#include "config.h"
#if HAVE_SCHED_GETAFFINITY
-#define _GNU_SOURCE
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
#include <sched.h>
#endif
#if HAVE_GETPROCESSAFFINITYMASK
@@ -43,6 +45,7 @@
#include <sys/param.h>
#endif
#include <sys/types.h>
+#include <sys/param.h>
#include <sys/sysctl.h>
#endif
#if HAVE_SYSCONF
@@ -59,6 +62,8 @@
#include <pthread.h>
#elif HAVE_W32THREADS
#include "w32pthreads.h"
+#elif HAVE_OS2THREADS
+#include "os2threads.h"
#endif
typedef int (action_func)(AVCodecContext *c, void *arg);
@@ -78,6 +83,7 @@ typedef struct ThreadContext {
pthread_cond_t current_job_cond;
pthread_mutex_t current_job_lock;
int current_job;
+ unsigned int current_execute;
int done;
} ThreadContext;
@@ -113,6 +119,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;
@@ -126,6 +136,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;
/**
@@ -153,7 +166,7 @@ typedef struct FrameThreadContext {
* limit the number of threads to 16 for automatic detection */
#define MAX_AUTO_THREADS 16
-static int get_logical_cpus(AVCodecContext *avctx)
+int ff_get_logical_cpus(AVCodecContext *avctx)
{
int ret, nb_cpus = 1;
#if HAVE_SCHED_GETAFFINITY && defined(CPU_COUNT)
@@ -183,6 +196,10 @@ static int get_logical_cpus(AVCodecContext *avctx)
nb_cpus = sysconf(_SC_NPROCESSORS_ONLN);
#endif
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);
+
return nb_cpus;
}
@@ -192,6 +209,7 @@ static void* attribute_align_arg worker(void *v)
AVCodecContext *avctx = v;
ThreadContext *c = avctx->thread_opaque;
int our_job = c->job_count;
+ int last_execute = 0;
int thread_count = avctx->thread_count;
int self_id;
@@ -202,7 +220,9 @@ static void* attribute_align_arg worker(void *v)
if (c->current_job == thread_count + c->job_count)
pthread_cond_signal(&c->last_job_cond);
- pthread_cond_wait(&c->current_job_cond, &c->current_job_lock);
+ while (last_execute == c->current_execute && !c->done)
+ pthread_cond_wait(&c->current_job_cond, &c->current_job_lock);
+ last_execute = c->current_execute;
our_job = self_id;
if (c->done) {
@@ -222,7 +242,8 @@ static void* attribute_align_arg worker(void *v)
static av_always_inline void avcodec_thread_park_workers(ThreadContext *c, int thread_count)
{
- pthread_cond_wait(&c->last_job_cond, &c->current_job_lock);
+ while (c->current_job != thread_count + c->job_count)
+ pthread_cond_wait(&c->last_job_cond, &c->current_job_lock);
pthread_mutex_unlock(&c->current_job_lock);
}
@@ -271,6 +292,7 @@ static int avcodec_thread_execute(AVCodecContext *avctx, action_func* func, void
c->rets = &dummy_ret;
c->rets_count = 1;
}
+ c->current_execute++;
pthread_cond_broadcast(&c->current_job_cond);
avcodec_thread_park_workers(c, avctx->thread_count);
@@ -292,7 +314,7 @@ static int thread_init(AVCodecContext *avctx)
int thread_count = avctx->thread_count;
if (!thread_count) {
- int nb_cpus = get_logical_cpus(avctx);
+ int nb_cpus = ff_get_logical_cpus(avctx);
// 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);
@@ -340,6 +362,9 @@ static int thread_init(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.
*
@@ -354,20 +379,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);
@@ -378,14 +399,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;
}
@@ -434,6 +462,7 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src,
}
if (for_user) {
+ dst->delay = src->thread_count - 1;
dst->coded_frame = src->coded_frame;
} else {
if (dst->codec->update_thread_context)
@@ -473,6 +502,7 @@ static int update_context_from_user(AVCodecContext *dst, AVCodecContext *src)
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) {
@@ -562,17 +592,29 @@ static int submit_packet(PerThreadContext *p, AVPacket *avpkt)
*/
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)) {
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);
}
@@ -610,7 +652,7 @@ int ff_thread_decode_frame(AVCodecContext *avctx,
*/
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;
*got_picture_ptr=0;
if (avpkt->size)
@@ -662,7 +704,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;
@@ -680,7 +722,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;
@@ -700,6 +742,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);
@@ -720,6 +766,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;
}
}
@@ -732,7 +779,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;
@@ -745,6 +796,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);
@@ -790,7 +842,9 @@ static int frame_thread_init(AVCodecContext *avctx)
int i, err = 0;
if (!thread_count) {
- int nb_cpus = get_logical_cpus(avctx);
+ int nb_cpus = ff_get_logical_cpus(avctx);
+ 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);
@@ -859,8 +913,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;
@@ -899,18 +955,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;
}
@@ -927,6 +995,7 @@ int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags)
}
pthread_mutex_lock(&p->parent->buffer_mutex);
+
if (avctx->thread_safe_callbacks || (
#if FF_API_GET_BUFFER
!avctx->get_buffer &&
@@ -934,11 +1003,11 @@ int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags)
avctx->get_buffer2 == avcodec_default_get_buffer2)) {
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);
@@ -948,7 +1017,7 @@ int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags)
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)
@@ -959,6 +1028,40 @@ int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags)
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;
diff --git a/libavcodec/ptx.c b/libavcodec/ptx.c
index 613c831..37135c5 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 6ea0592..7320443 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"
@@ -133,7 +134,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;
@@ -142,6 +143,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;
@@ -155,6 +157,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;
@@ -168,7 +171,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));
}
@@ -204,8 +207,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 ead7d90..f8fe85d 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,7 +23,7 @@
* @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
*/
@@ -695,10 +695,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 1e0811c..daf127e 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;
@@ -342,7 +342,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));
@@ -639,7 +646,8 @@ static void fill_coding_method_array (sb_int8_array tone_level_idx, sb_int8_arra
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
@@ -675,7 +683,7 @@ static void fill_coding_method_array (sb_int8_array tone_level_idx, sb_int8_arra
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++)
@@ -752,7 +760,7 @@ static void fill_coding_method_array (sb_int8_array tone_level_idx, sb_int8_arra
* @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, int length, int sb_min, int sb_max)
+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;
int joined_stereo, zero_encoding, chs;
@@ -766,7 +774,7 @@ static void synthfilt_build_sb_samples (QDM2Context *q, GetBitContext *gb, int l
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++) {
@@ -786,6 +794,11 @@ static void synthfilt_build_sb_samples (QDM2Context *q, GetBitContext *gb, int l
for (j = 0; j < 16; j++)
sign_bits[j] = get_bits1 (gb);
+ if (q->coding_method[0][sb][0] <= 0) {
+ av_log(NULL, AV_LOG_ERROR, "coding method invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
+
for (j = 0; j < 64; j++)
if (q->coding_method[1][sb][j] > q->coding_method[0][sb][j])
q->coding_method[0][sb][j] = q->coding_method[1][sb][j];
@@ -811,6 +824,11 @@ static void synthfilt_build_sb_samples (QDM2Context *q, GetBitContext *gb, int l
}
} 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]];
}
@@ -847,6 +865,11 @@ static void synthfilt_build_sb_samples (QDM2Context *q, GetBitContext *gb, int l
}
} 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]];
}
@@ -860,6 +883,11 @@ static void synthfilt_build_sb_samples (QDM2Context *q, GetBitContext *gb, int l
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 {
@@ -872,10 +900,11 @@ static void synthfilt_build_sb_samples (QDM2Context *q, GetBitContext *gb, int l
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);
@@ -891,11 +920,12 @@ static void synthfilt_build_sb_samples (QDM2Context *q, GetBitContext *gb, int l
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);
@@ -911,10 +941,10 @@ static void synthfilt_build_sb_samples (QDM2Context *q, GetBitContext *gb, int l
if (joined_stereo) {
float tmp[10][MPA_MAX_CHANNELS];
-
for (k = 0; k < run; k++) {
tmp[k][0] = samples[k];
- tmp[k][1] = (sign_bits[(j + k) / 8]) ? -samples[k] : samples[k];
+ if ((j + k) < 128)
+ tmp[k][1] = (sign_bits[(j + k) / 8]) ? -samples[k] : samples[k];
}
for (chs = 0; chs < q->nb_channels; chs++)
for (k = 0; k < run; k++)
@@ -930,6 +960,7 @@ static void synthfilt_build_sb_samples (QDM2Context *q, GetBitContext *gb, int l
} // j loop
} // channel loop
} // subband loop
+ return 0;
}
@@ -941,23 +972,26 @@ static void synthfilt_build_sb_samples (QDM2Context *q, GetBitContext *gb, int l
* @param quantized_coeffs pointer to quantized_coeffs[ch][0]
* @param gb bitreader context
*/
-static void init_quantized_coeffs_elem0 (int8_t *quantized_coeffs, GetBitContext *gb)
+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++)
@@ -966,6 +1000,7 @@ static void init_quantized_coeffs_elem0 (int8_t *quantized_coeffs, GetBitContext
level += diff;
i += run;
}
+ return 0;
}
@@ -1040,7 +1075,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;
@@ -1058,6 +1093,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));
@@ -1069,6 +1107,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;
}
@@ -1139,7 +1179,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
@@ -1173,7 +1213,7 @@ static void process_synthesis_subpackets (QDM2Context *q, QDM2SubPNode *list)
}
-/*
+/**
* Decode superblock, fill packet lists.
*
* @param q context
@@ -1334,9 +1374,14 @@ static void qdm2_fft_decode_tones (QDM2Context *q, int duration, GetBitContext *
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;
@@ -1764,8 +1809,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;
@@ -1792,6 +1839,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;
@@ -1814,18 +1862,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;
@@ -1866,6 +1905,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;
@@ -1938,10 +1980,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 0dc72d0..6970099 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 bb963ed..6015b7f 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)];
}
}
}
@@ -191,17 +193,24 @@ static void qpeg_decode_inter(QpegContext *qctx, uint8_t *dst,
filled = 0;
dst -= stride;
height--;
+ if(height < 0)
+ break;
}
}
} 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) {
filled = 0;
dst -= stride;
height--;
+ if(height < 0)
+ break;
}
}
} else if(code >= 0x80) { /* skip code: 0x80..0xBF */
@@ -246,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);
@@ -257,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);
@@ -270,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 */
@@ -288,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);
@@ -303,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;
}
@@ -318,6 +346,7 @@ AVCodec ff_qpeg_decoder = {
.init = decode_init,
.close = decode_end,
.decode = decode_frame,
+ .flush = decode_flush,
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("Q-team QPEG"),
};
diff --git a/libavcodec/qtrle.c b/libavcodec/qtrle.c
index b4667f4..c043249 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
*/
@@ -63,6 +63,14 @@ static void qtrle_decode_1bpp(QtrleContext *s, int row_ptr, int lines_to_change)
unsigned char *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://ffmpeg.org/trac/ffmpeg/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;
@@ -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;
@@ -401,10 +412,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,6 +433,8 @@ static int qtrle_decode_frame(AVCodecContext *avctx,
bytestream2_skip(&s->g, 2);
height = bytestream2_get_be16(&s->g);
bytestream2_skip(&s->g, 2);
+ if (height > s->avctx->height - start_line)
+ goto done;
} else {
start_line = 0;
height = s->avctx->height;
diff --git a/libavcodec/qtrleenc.c b/libavcodec/qtrleenc.c
index bb686f5..a25c45d 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 */
@@ -336,7 +396,7 @@ 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
},
.long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"),
};
diff --git a/libavcodec/r210dec.c b/libavcodec/r210dec.c
index 35150d8..198914c 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 = {
.long_name = NULL_IF_CONFIG_SMALL("AJA Kona 10-bit RGB Codec"),
};
#endif
+#if CONFIG_AVRP_DECODER
+AVCodec ff_avrp_decoder = {
+ .name = "avrp",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_AVRP,
+ .init = decode_init,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("Avid 1:1 10-bit RGB Packer"),
+};
+#endif
diff --git a/libavcodec/r210enc.c b/libavcodec/r210enc.c
new file mode 100644
index 0000000..e19a27e
--- /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",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed RGB 10-bit"),
+};
+#endif
+#if CONFIG_R10K_ENCODER
+AVCodec ff_r10k_encoder = {
+ .name = "r10k",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("AJA Kona 10-bit RGB Codec"),
+};
+#endif
+#if CONFIG_AVRP_ENCODER
+AVCodec ff_avrp_encoder = {
+ .name = "avrp",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("Avid 1:1 10-bit RGB Packer"),
+};
+#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..426fea3 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
*/
@@ -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 15162c3..63f77e0 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;
@@ -85,10 +85,8 @@ 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);
diff --git a/libavcodec/ra144enc.c b/libavcodec/ra144enc.c
index c05c243..2eac343 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, FRAMESIZE)) < 0)
return ret;
- }
/**
* Since the LPC coefficients are calculated on a frame centered over the
@@ -554,5 +553,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 },
.long_name = NULL_IF_CONFIG_SMALL("RealAudio 1.0 (14.4K)"),
};
diff --git a/libavcodec/ra288.c b/libavcodec/ra288.c
index 5cccbe9..393ea0b 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.);
+ sum = avpriv_scalarproduct_float_c(buffer, buffer, 5);
- sum = FFMAX(sum, 1);
+ sum = FFMAX(sum, 5. / (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,10 +198,8 @@ 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);
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 e78a9d4..0313d99 100644
--- a/libavcodec/ralf.c
+++ b/libavcodec/ralf.c
@@ -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/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..2d1baaa 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;
@@ -490,7 +504,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 +763,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 +911,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;
@@ -948,6 +967,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..e23dbea 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') },
@@ -144,9 +167,12 @@ const PixelFormatTag ff_raw_pix_fmt_tags[] = {
{ AV_PIX_FMT_YUVA444P16BE, MKTAG(16 , 0 , '4', 'Y') },
/* 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 +180,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 +191,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 66265ce..4699242 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 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);
@@ -117,6 +142,7 @@ static av_cold int raw_init_decoder(AVCodecContext *avctx)
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 +167,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,10 +178,16 @@ 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 (buf_size < context->frame_size - (avctx->pix_fmt == AV_PIX_FMT_PAL8 ?
- AVPALETTE_SIZE : 0))
- return -1;
+ if (context->tff >= 0) {
+ frame->interlaced_frame = 1;
+ frame->top_field_first = context->tff;
+ }
+
+ if ((res = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0)
+ return res;
if (need_copy)
frame->buf[0] = av_buffer_alloc(context->frame_size);
@@ -169,17 +202,20 @@ 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) {
@@ -191,9 +227,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 +247,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 +298,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 +313,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 +351,5 @@ AVCodec ff_rawvideo_decoder = {
.close = raw_close_decoder,
.decode = raw_decode,
.long_name = NULL_IF_CONFIG_SMALL("raw video"),
+ .priv_class = &class,
};
diff --git a/libavcodec/rawenc.c b/libavcodec/rawenc.c
index 3e607af..c6da6b8 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
--- /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..f0d9b45 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
*/
diff --git a/libavcodec/resample.c b/libavcodec/resample.c
new file mode 100644
index 0000000..f950288
--- /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
--- /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 4f68f7e..c8853de 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 d440fbe..b68e3f8 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 39233be..85fdab7 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 650db67..666c49d 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 45350a8..2aa0091 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
*/
@@ -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 6da7759..fe781ce 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 0d3b648..8d4f759 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;
}
@@ -438,7 +455,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;
@@ -470,7 +486,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;
@@ -516,7 +532,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;
}
@@ -548,6 +565,7 @@ static int rv10_decode_packet(AVCodecContext *avctx,
}
}
+
av_dlog(avctx, "qscale=%d\n", s->qscale);
/* default quantization values */
@@ -659,6 +677,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) {
@@ -712,11 +732,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) {
@@ -739,6 +761,7 @@ AVCodec ff_rv10_decoder = {
.close = rv10_decode_end,
.decode = rv10_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
.long_name = NULL_IF_CONFIG_SMALL("RealVideo 1.0"),
.pix_fmts = ff_pixfmt_list_420,
};
@@ -753,6 +776,7 @@ AVCodec ff_rv20_decoder = {
.decode = rv10_decode_frame,
.capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY,
.flush = ff_mpeg_flush,
+ .max_lowres = 3,
.long_name = NULL_IF_CONFIG_SMALL("RealVideo 2.0"),
.pix_fmts = ff_pixfmt_list_420,
};
diff --git a/libavcodec/rv10enc.c b/libavcodec/rv10enc.c
index d3cd12c..c4c5c53 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 c392b53..295699a 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 f1f33c5..f40870e 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;
}
@@ -255,7 +260,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 af37855..9b47d2e 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)
{
@@ -1330,7 +1331,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 +1402,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;
@@ -1576,18 +1581,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)
@@ -1649,7 +1666,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);
@@ -1661,6 +1678,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/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/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 6f8643d..d6dfc5e 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;
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 b63d238..ad985f8 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 66d25f1..5f73148 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
*/
@@ -66,6 +66,19 @@ static int s302m_parse_frame_header(AVCodecContext *avctx, const uint8_t *buf,
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) +
32 * (48000 / (buf_size * 8 /
@@ -93,10 +106,8 @@ static int s302m_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
block_size = (avctx->bits_per_coded_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;
diff --git a/libavcodec/s3tc.c b/libavcodec/s3tc.c
index 62dc356..4e791c8 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
--- /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..e6e866e
--- /dev/null
+++ b/libavcodec/sanm.c
@@ -0,0 +1,1305 @@
+/*
+ * 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);
+#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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts SMUSH video"),
+};
diff --git a/libavcodec/sanm_data.h b/libavcodec/sanm_data.h
new file mode 100644
index 0000000..8fccf38
--- /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..de961cf 100644
--- a/libavcodec/sbrdsp.c
+++ b/libavcodec/sbrdsp.c
@@ -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..3831135 100644
--- a/libavcodec/sbrdsp.h
+++ b/libavcodec/sbrdsp.h
@@ -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 a4b3128..e7f453b 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"
@@ -48,16 +49,16 @@ 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_buf + pixelstride * (count-1) >= out_end) return -1;
if (pixel & 0x80) {
while (count--) {
@@ -73,6 +74,7 @@ static int expand_rle_row(SgiState *s, uint8_t *out_buf,
}
}
}
+ return (out_buf - orig) / pixelstride;
}
/**
@@ -100,7 +102,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 +114,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.
*/
-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,17 +167,17 @@ 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");
@@ -193,8 +194,8 @@ static int decode_frame(AVCodecContext *avctx,
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;
@@ -204,10 +205,8 @@ static int decode_frame(AVCodecContext *avctx,
return -1;
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,7 +221,7 @@ 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) {
diff --git a/libavcodec/sgienc.c b/libavcodec/sgienc.c
index 2aecc59..d03ef52 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
*/
@@ -36,6 +36,11 @@ static av_cold int encode_init(AVCodecContext *avctx)
{
SgiContext *s = avctx->priv_data;
+ if (avctx->width > 65535 || avctx->height > 65535) {
+ av_log(avctx, AV_LOG_ERROR, "SGI does not support resolutions above 65535x65535\n");
+ return -1;
+ }
+
avcodec_get_frame_defaults(&s->picture);
avctx->coded_frame = &s->picture;
@@ -49,7 +54,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
AVFrame * const p = &s->picture;
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;
@@ -58,6 +63,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
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 +80,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 +118,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 +183,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];
}
@@ -178,7 +218,11 @@ AVCodec ff_sgi_encoder = {
.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
},
.long_name = NULL_IF_CONFIG_SMALL("SGI image"),
};
diff --git a/libavcodec/sgirledec.c b/libavcodec/sgirledec.c
new file mode 100644
index 0000000..a7fdac8
--- /dev/null
+++ b/libavcodec/sgirledec.c
@@ -0,0 +1,149 @@
+/*
+ * 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 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);
+ 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)
+ 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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("SGI RLE 8-bit"),
+};
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 1527946..23c5d7c 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,8 +207,9 @@ 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;
+ const uint8_t *end= header + header_size;
if (bytestream_get_le32(&header) != MKTAG('R', 'I', 'F', 'F')) {
av_log(avctx, AV_LOG_ERROR, "missing RIFF tag\n");
@@ -217,6 +225,8 @@ static int decode_wave_header(AVCodecContext *avctx, const uint8_t *header,
while (bytestream_get_le32(&header) != MKTAG('f', 'm', 't', ' ')) {
len = bytestream_get_le32(&header);
+ if (len<0 || end - header - 8 < len)
+ return AVERROR_INVALIDDATA;
header += len;
}
len = bytestream_get_le32(&header);
@@ -240,10 +250,11 @@ static int decode_wave_header(AVCodecContext *avctx, const uint8_t *header,
avctx->sample_rate = bytestream_get_le32(&header);
header += 4; // skip bit rate (represents original uncompressed bit rate)
header += 2; // skip block align (not needed)
- avctx->bits_per_coded_sample = bytestream_get_le16(&header);
+ bps = bytestream_get_le16(&header);
+ avctx->bits_per_coded_sample = bps;
- if (avctx->bits_per_coded_sample != 16) {
- av_log(avctx, AV_LOG_ERROR, "unsupported number of bits per sample\n");
+ if (bps != 16 && bps != 8) {
+ av_log(avctx, AV_LOG_ERROR, "unsupported number of bits per sample: %d\n", bps);
return AVERROR(ENOSYS);
}
@@ -254,18 +265,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][3] = {
{ 1, 0, 0 },
{ 2, -1, 0 },
@@ -423,9 +422,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);
@@ -552,7 +551,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 */
@@ -591,15 +590,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;
}
@@ -652,5 +666,6 @@ AVCodec ff_shorten_decoder = {
.capabilities = CODEC_CAP_DELAY | CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("Shorten"),
.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..d204565 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
*/
diff --git a/libavcodec/simple_idct.h b/libavcodec/simple_idct.h
index e257290..3fec5e0 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
*/
diff --git a/libavcodec/simple_idct_template.c b/libavcodec/simple_idct_template.c
index 367bc34..dabfbda 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
*/
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 2d35841..35e8bf5 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..9cc5e9b 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
*/
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 a27997f..c070150 100644
--- a/libavcodec/smacker.c
+++ b/libavcodec/smacker.c
@@ -2,20 +2,20 @@
* Smacker decoder
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -97,10 +97,14 @@ enum SmkBlockTypes {
*/
static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t prefix, int length)
{
+ if(length > 32 || length > 3*SMKTREE_BITS) {
+ av_log(NULL, AV_LOG_ERROR, "length too long\n");
+ return AVERROR_INVALIDDATA;
+ }
if(!get_bits1(gb)){ //Leaf
if(hc->current >= 256){
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;
@@ -202,38 +206,45 @@ static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int
tmp2.values = av_mallocz(256 * sizeof(int));
if(get_bits1(gb)) {
- smacker_decode_tree(gb, &tmp1, 0, 0);
+ res = smacker_decode_tree(gb, &tmp1, 0, 0);
+ if (res < 0)
+ return res;
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");
- return -1;
+ 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");
+ return AVERROR_INVALIDDATA;
+ }
}
- } else {
+ }
+ 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);
+ res = smacker_decode_tree(gb, &tmp2, 0, 0);
+ if (res < 0)
+ return res;
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");
- return -1;
+ 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");
+ return AVERROR_INVALIDDATA;
+ }
}
- } else {
+ }
+ 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;
@@ -257,6 +268,11 @@ static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int
if(ctx.last[0] == -1) ctx.last[0] = huff.current++;
if(ctx.last[1] == -1) ctx.last[1] = huff.current++;
if(ctx.last[2] == -1) ctx.last[2] = huff.current++;
+ if(huff.current > huff.length){
+ ctx.last[0] = ctx.last[1] = ctx.last[2] = 1;
+ av_log(smk->avctx, AV_LOG_ERROR, "bigtree damaged\n");
+ return AVERROR_INVALIDDATA;
+ }
*recodes = huff.values;
@@ -292,7 +308,7 @@ static int decode_header_trees(SmackVContext *smk) {
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;
+ return AVERROR_INVALIDDATA;
}
if(!get_bits1(&gb)) {
av_log(smk->avctx, AV_LOG_INFO, "Skipping MCLR tree\n");
@@ -301,7 +317,7 @@ static int decode_header_trees(SmackVContext *smk) {
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;
+ return AVERROR_INVALIDDATA;
}
if(!get_bits1(&gb)) {
av_log(smk->avctx, AV_LOG_INFO, "Skipping FULL tree\n");
@@ -310,7 +326,7 @@ static int decode_header_trees(SmackVContext *smk) {
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;
+ return AVERROR_INVALIDDATA;
}
if(!get_bits1(&gb)) {
av_log(smk->avctx, AV_LOG_INFO, "Skipping TYPE tree\n");
@@ -319,7 +335,7 @@ static int decode_header_trees(SmackVContext *smk) {
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;
+ return AVERROR_INVALIDDATA;
}
return 0;
@@ -363,12 +379,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
int flags;
if (avpkt->size <= 769)
- return 0;
+ return AVERROR_INVALIDDATA;
- if ((ret = ff_reget_buffer(avctx, &smk->pic)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, &smk->pic)) < 0)
return ret;
- }
/* make the palette available on the way out */
pal = (uint32_t*)smk->pic.data[1];
@@ -382,7 +396,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
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);
@@ -523,11 +537,11 @@ static av_cold int decode_init(AVCodecContext *avctx)
/* decode huffman trees from extradata */
if(avctx->extradata_size < 16){
av_log(avctx, AV_LOG_ERROR, "Extradata missing!\n");
- return -1;
+ return AVERROR(EINVAL);
}
if (decode_header_trees(c))
- return -1;
+ return AVERROR_INVALIDDATA;
return 0;
}
@@ -593,6 +607,11 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
unp_size = AV_RL32(buf);
+ if (unp_size > (1U<<24)) {
+ av_log(avctx, AV_LOG_ERROR, "packet is too big\n");
+ return AVERROR_INVALIDDATA;
+ }
+
init_get_bits(&gb, buf + 4, (buf_size - 4) * 8);
if(!get_bits1(&gb)){
@@ -613,10 +632,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];
@@ -629,7 +646,9 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
h[i].lengths = av_mallocz(256 * sizeof(int));
h[i].values = av_mallocz(256 * sizeof(int));
skip_bits1(&gb);
- smacker_decode_tree(&gb, &h[i], 0, 0);
+ res = smacker_decode_tree(&gb, &h[i], 0, 0);
+ if (res < 0)
+ return res;
skip_bits1(&gb);
if(h[i].current > 1) {
res = init_vlc(&vlc[i], SMKTREE_BITS, h[i].length,
@@ -637,7 +656,7 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
h[i].bits, sizeof(uint32_t), sizeof(uint32_t), INIT_VLC_LE);
if(res < 0) {
av_log(avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
}
}
@@ -647,16 +666,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++ = av_clip_int16(pred[1]);
@@ -665,11 +694,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++ = av_clip_int16(pred[0]);
@@ -681,11 +718,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++ = av_clip_uint8(pred[1]);
} else {
@@ -693,6 +736,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++ = av_clip_uint8(pred[0]);
}
diff --git a/libavcodec/smc.c b/libavcodec/smc.c
index 2fcf61f..2c7ab9a 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/snow.c b/libavcodec/snow.c
new file mode 100644
index 0000000..99cd5fb
--- /dev/null
+++ b/libavcodec/snow.c
@@ -0,0 +1,690 @@
+/*
+ * 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));
+ 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, int 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, 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);
+ avcodec_get_frame_defaults(&s->last_picture[i]);
+ }
+
+ avcodec_get_frame_defaults(&s->mconly_picture);
+ avcodec_get_frame_defaults(&s->current_picture);
+
+ 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<3; 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));
+ }
+ w= (w+1)>>1;
+ h= (h+1)>>1;
+ }
+ }
+
+ return 0;
+fail:
+ return AVERROR(ENOMEM);
+}
+
+#define USE_HALFPEL_PLANE 0
+
+static void halfpel_interpol(SnowContext *s, uint8_t *halfpel[4][4], AVFrame *frame){
+ int p,x,y;
+
+ for(p=0; p<3; 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);
+
+ 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!
+ }
+}
+
+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);
+ 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);
+
+ av_frame_move_ref(&tmp, &s->last_picture[s->max_ref_frames-1]);
+ for(i=s->max_ref_frames-1; i>0; i--)
+ av_frame_move_ref(&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])
+ halfpel_interpol(s, s->halfpel_plane[0], &s->current_picture);
+ av_frame_move_ref(&s->last_picture[0], &s->current_picture);
+ av_frame_move_ref(&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_unref(&s->last_picture[i]);
+ }
+ }
+
+ for(plane_index=0; plane_index<3; 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_unref(&s->mconly_picture);
+ av_frame_unref(&s->current_picture);
+}
diff --git a/libavcodec/snow.h b/libavcodec/snow.h
new file mode 100644
index 0000000..922a48e
--- /dev/null
+++ b/libavcodec/snow.h
@@ -0,0 +1,703 @@
+/*
+ * 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;
+ 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, int 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
--- /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
--- /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
--- /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..c8a0327
--- /dev/null
+++ b/libavcodec/snowdec.c
@@ -0,0 +1,587 @@
+/*
+ * 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"
+
+#undef NDEBUG
+#include <assert.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);
+ 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<3; 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);
+ 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->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<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<3; 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<3; 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",
+ .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*/,
+ .long_name = NULL_IF_CONFIG_SMALL("Snow"),
+};
diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c
new file mode 100644
index 0000000..7266ee1
--- /dev/null
+++ b/libavcodec/snowenc.c
@@ -0,0 +1,2112 @@
+/*
+ * Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intmath.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "avcodec.h"
+#include "internal.h"
+#include "dsputil.h"
+#include "internal.h"
+#include "snow_dwt.h"
+#include "snow.h"
+
+#include "rangecoder.h"
+#include "mathops.h"
+
+#include "mpegvideo.h"
+#include "h263.h"
+
+#undef NDEBUG
+#include <assert.h>
+
+#define QUANTIZE2 0
+
+#if QUANTIZE2==1
+#define Q2_STEP 8
+
+static void find_sse(SnowContext *s, Plane *p, int *score, int score_stride, IDWTELEM *r0, IDWTELEM *r1, int level, int orientation){
+ SubBand *b= &p->band[level][orientation];
+ int x, y;
+ int xo=0;
+ int yo=0;
+ int step= 1 << (s->spatial_decomposition_count - level);
+
+ if(orientation&1)
+ xo= step>>1;
+ if(orientation&2)
+ yo= step>>1;
+
+ //FIXME bias for nonzero ?
+ //FIXME optimize
+ memset(score, 0, sizeof(*score)*score_stride*((p->height + Q2_STEP-1)/Q2_STEP));
+ for(y=0; y<p->height; y++){
+ for(x=0; x<p->width; x++){
+ int sx= (x-xo + step/2) / step / Q2_STEP;
+ int sy= (y-yo + step/2) / step / Q2_STEP;
+ int v= r0[x + y*p->width] - r1[x + y*p->width];
+ assert(sx>=0 && sy>=0 && sx < score_stride);
+ v= ((v+8)>>4)<<4;
+ score[sx + sy*score_stride] += v*v;
+ assert(score[sx + sy*score_stride] >= 0);
+ }
+ }
+}
+
+static void dequantize_all(SnowContext *s, Plane *p, IDWTELEM *buffer, int width, int height){
+ int level, orientation;
+
+ for(level=0; level<s->spatial_decomposition_count; level++){
+ for(orientation=level ? 1 : 0; orientation<4; orientation++){
+ SubBand *b= &p->band[level][orientation];
+ IDWTELEM *dst= buffer + (b->ibuf - s->spatial_idwt_buffer);
+
+ dequantize(s, b, dst, b->stride);
+ }
+ }
+}
+
+static void dwt_quantize(SnowContext *s, Plane *p, DWTELEM *buffer, int width, int height, int stride, int type){
+ int level, orientation, ys, xs, x, y, pass;
+ IDWTELEM best_dequant[height * stride];
+ IDWTELEM idwt2_buffer[height * stride];
+ const int score_stride= (width + 10)/Q2_STEP;
+ int best_score[(width + 10)/Q2_STEP * (height + 10)/Q2_STEP]; //FIXME size
+ int score[(width + 10)/Q2_STEP * (height + 10)/Q2_STEP]; //FIXME size
+ int threshold= (s->m.lambda * s->m.lambda) >> 6;
+
+ //FIXME pass the copy cleanly ?
+
+// memcpy(dwt_buffer, buffer, height * stride * sizeof(DWTELEM));
+ ff_spatial_dwt(buffer, s->temp_dwt_buffer, width, height, stride, type, s->spatial_decomposition_count);
+
+ for(level=0; level<s->spatial_decomposition_count; level++){
+ for(orientation=level ? 1 : 0; orientation<4; orientation++){
+ SubBand *b= &p->band[level][orientation];
+ IDWTELEM *dst= best_dequant + (b->ibuf - s->spatial_idwt_buffer);
+ DWTELEM *src= buffer + (b-> buf - s->spatial_dwt_buffer);
+ assert(src == b->buf); // code does not depend on this but it is true currently
+
+ quantize(s, b, dst, src, b->stride, s->qbias);
+ }
+ }
+ for(pass=0; pass<1; pass++){
+ if(s->qbias == 0) //keyframe
+ continue;
+ for(level=0; level<s->spatial_decomposition_count; level++){
+ for(orientation=level ? 1 : 0; orientation<4; orientation++){
+ SubBand *b= &p->band[level][orientation];
+ IDWTELEM *dst= idwt2_buffer + (b->ibuf - s->spatial_idwt_buffer);
+ IDWTELEM *best_dst= best_dequant + (b->ibuf - s->spatial_idwt_buffer);
+
+ for(ys= 0; ys<Q2_STEP; ys++){
+ for(xs= 0; xs<Q2_STEP; xs++){
+ memcpy(idwt2_buffer, best_dequant, height * stride * sizeof(IDWTELEM));
+ dequantize_all(s, p, idwt2_buffer, width, height);
+ ff_spatial_idwt(idwt2_buffer, s->temp_idwt_buffer, width, height, stride, type, s->spatial_decomposition_count);
+ find_sse(s, p, best_score, score_stride, idwt2_buffer, s->spatial_idwt_buffer, level, orientation);
+ memcpy(idwt2_buffer, best_dequant, height * stride * sizeof(IDWTELEM));
+ for(y=ys; y<b->height; y+= Q2_STEP){
+ for(x=xs; x<b->width; x+= Q2_STEP){
+ if(dst[x + y*b->stride]<0) dst[x + y*b->stride]++;
+ if(dst[x + y*b->stride]>0) dst[x + y*b->stride]--;
+ //FIXME try more than just --
+ }
+ }
+ dequantize_all(s, p, idwt2_buffer, width, height);
+ ff_spatial_idwt(idwt2_buffer, s->temp_idwt_buffer, width, height, stride, type, s->spatial_decomposition_count);
+ find_sse(s, p, score, score_stride, idwt2_buffer, s->spatial_idwt_buffer, level, orientation);
+ for(y=ys; y<b->height; y+= Q2_STEP){
+ for(x=xs; x<b->width; x+= Q2_STEP){
+ int score_idx= x/Q2_STEP + (y/Q2_STEP)*score_stride;
+ if(score[score_idx] <= best_score[score_idx] + threshold){
+ best_score[score_idx]= score[score_idx];
+ if(best_dst[x + y*b->stride]<0) best_dst[x + y*b->stride]++;
+ if(best_dst[x + y*b->stride]>0) best_dst[x + y*b->stride]--;
+ //FIXME copy instead
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ memcpy(s->spatial_idwt_buffer, best_dequant, height * stride * sizeof(IDWTELEM)); //FIXME work with that directly instead of copy at the end
+}
+
+#endif /* QUANTIZE2==1 */
+
+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));
+ 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->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));
+
+ avctx->coded_frame= &s->current_picture;
+ switch(avctx->pix_fmt){
+ case AV_PIX_FMT_YUV444P:
+// case AV_PIX_FMT_YUV422P:
+ case AV_PIX_FMT_YUV420P:
+// case AV_PIX_FMT_GRAY8:
+// case AV_PIX_FMT_YUV411P:
+ case AV_PIX_FMT_YUV410P:
+ s->colorspace_type= 0;
+ 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);
+
+ 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));
+ }
+ }
+
+ 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;
+
+ assert(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;
+
+ assert(c-> stride == stride);
+ assert(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);
+
+ assert(ref_mx >= c->xmin);
+ assert(ref_mx <= c->xmax);
+ assert(ref_my >= c->ymin);
+ assert(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;
+
+ 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;
+
+ 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);
+ 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);
+ assert(iscore < 255*255*256 + s->lambda2*10);
+ assert(iscore >= 0);
+ assert(l>=0 && l<=255);
+ assert(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);
+ 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{
+ assert(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);
+ }
+
+ assert(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);
+ assert(v);
+ }else{
+ run--;
+ assert(!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;
+
+ assert(mb_x>=0 && mb_y>=0);
+ assert(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];
+
+ assert(mb_x>=0 && mb_y>=0);
+ assert(mb_x<b_stride);
+ assert(((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<3; 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<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);
+ 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<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<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;
+ assert(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,
+ const AVFrame *pict, int *got_packet)
+{
+ SnowContext *s = avctx->priv_data;
+ RangeCoder * const c= &s->c;
+ AVFrame *pic = &s->new_picture;
+ 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<3; 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);
+
+ 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];
+
+ assert(s->current_picture.data[0]);
+ assert(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--;
+
+ 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<3; 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<3; 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;
+ }
+ }
+ }
+
+ /* if(QUANTIZE2)
+ dwt_quantize(s, p, s->spatial_dwt_buffer, w, h, w, s->spatial_decomposition_type);
+ else*/
+ 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];
+
+ if(!QUANTIZE2)
+ 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);
+ assert(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);
+ av_frame_unref(&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",
+ .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_NONE
+ },
+ .long_name = NULL_IF_CONFIG_SMALL("Snow"),
+ .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..b67434f
--- /dev/null
+++ b/libavcodec/sonic.c
@@ -0,0 +1,1001 @@
+/*
+ * 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 divide(int a, int b)
+{
+ if (a < 0)
+ return -( (-a + b/2)/b );
+ else
+ return (a + b/2)/b;
+}
+
+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)?1: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_mallocz(4* entries);
+ if (!copy)
+ return -1;
+
+ 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_mallocz(4* entries*max);
+ if (!bits)
+ {
+// av_free(copy);
+ return -1;
+ }
+
+ 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_mallocz(4* entries);
+
+ if (!bits)
+ return -1;
+
+ 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_mallocz(4* window_entries);
+
+ 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]), *state_ptr = &(state[0]);
+ j = window_entries - step;
+ for (;j>=0;j--,x_ptr++,state_ptr++)
+ {
+ double x_value = *x_ptr, 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], 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, 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], 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 -1;
+}
+
+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 -1; /* 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>>5)<<5 != s->num_taps))
+ {
+ av_log(avctx, AV_LOG_ERROR, "Invalid number of taps\n");
+ return -1;
+ }
+
+ // generate taps
+ s->tap_quant = av_mallocz(4* s->num_taps);
+ for (i = 0; i < s->num_taps; i++)
+ s->tap_quant[i] = (int)(sqrt(i+1));
+
+ s->channels = avctx->channels;
+ s->samplerate = avctx->sample_rate;
+
+ s->block_align = (int)(2048.0*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_mallocz(4 * s->tail_size);
+ if (!s->tail)
+ return -1;
+
+ s->predictor_k = av_mallocz(4 * s->num_taps);
+ if (!s->predictor_k)
+ return -1;
+
+ for (i = 0; i < s->channels; i++)
+ {
+ s->coded_samples[i] = av_mallocz(4* s->block_align);
+ if (!s->coded_samples[i])
+ return -1;
+ }
+
+ s->int_samples = av_mallocz(4* s->frame_size);
+
+ s->window_size = ((2*s->tail_size)+s->frame_size);
+ s->window = av_mallocz(4* s->window_size);
+ if (!s->window)
+ return -1;
+
+ avctx->extradata = av_mallocz(16);
+ if (!avctx->extradata)
+ return -1;
+ 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->coded_frame = avcodec_alloc_frame();
+ if (!avctx->coded_frame)
+ return AVERROR(ENOMEM);
+ avctx->coded_frame->key_frame = 1;
+ 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;
+
+ av_freep(&avctx->coded_frame);
+
+ for (i = 0; i < s->channels; i++)
+ av_free(s->coded_samples[i]);
+
+ av_free(s->predictor_k);
+ av_free(s->tail);
+ av_free(s->tap_quant);
+ av_free(s->window);
+ av_free(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 (intlist_write(&pb, s->predictor_k, s->num_taps, 0) < 0)
+ return -1;
+
+ 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);
+
+ if (quant < 1)
+ quant = 1;
+ if (quant > 65534)
+ quant = 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] = divide(s->coded_samples[ch][i], quant);
+
+ if (intlist_write(&pb, s->coded_samples[ch], s->block_align, 1) < 0)
+ return -1;
+ }
+
+// 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 -1;
+ }
+
+ init_get_bits(&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 -1;
+ }
+
+ 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 -1;
+ }
+
+ 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 = (int)(2048.0*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_mallocz(4* s->num_taps);
+ for (i = 0; i < s->num_taps; i++)
+ s->tap_quant[i] = (int)(sqrt(i+1));
+
+ s->predictor_k = av_mallocz(4* s->num_taps);
+
+ for (i = 0; i < s->channels; i++)
+ {
+ s->predictor_state[i] = av_mallocz(4* s->num_taps);
+ if (!s->predictor_state[i])
+ return -1;
+ }
+
+ for (i = 0; i < s->channels; i++)
+ {
+ s->coded_samples[i] = av_mallocz(4* s->block_align);
+ if (!s->coded_samples[i])
+ return -1;
+ }
+ s->int_samples = av_mallocz(4* s->frame_size);
+
+ 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_free(s->int_samples);
+ av_free(s->tap_quant);
+ av_free(s->predictor_k);
+
+ for (i = 0; i < s->channels; i++)
+ {
+ av_free(s->predictor_state[i]);
+ av_free(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_bits(&gb, buf, buf_size*8);
+
+ 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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("Sonic"),
+};
+#endif /* CONFIG_SONIC_DECODER */
+
+#if CONFIG_SONIC_ENCODER
+AVCodec ff_sonic_encoder = {
+ .name = "sonic",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_SONIC,
+ .priv_data_size = sizeof(SonicContext),
+ .init = sonic_encode_init,
+ .encode2 = sonic_encode_frame,
+ .capabilities = CODEC_CAP_EXPERIMENTAL,
+ .close = sonic_encode_close,
+ .long_name = NULL_IF_CONFIG_SMALL("Sonic"),
+};
+#endif
+
+#if CONFIG_SONIC_LS_ENCODER
+AVCodec ff_sonic_ls_encoder = {
+ .name = "sonicls",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_SONIC_LS,
+ .priv_data_size = sizeof(SonicContext),
+ .init = sonic_encode_init,
+ .encode2 = sonic_encode_frame,
+ .capabilities = CODEC_CAP_EXPERIMENTAL,
+ .close = sonic_encode_close,
+ .long_name = NULL_IF_CONFIG_SMALL("Sonic lossless"),
+};
+#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 90c3491..b083015 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",
.type = AVMEDIA_TYPE_VIDEO,
@@ -102,9 +103,11 @@ AVCodec ff_sp5x_decoder = {
.close = ff_mjpeg_decode_end,
.decode = sp5x_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
.long_name = NULL_IF_CONFIG_SMALL("Sunplus JPEG (SP5X)"),
};
-
+#endif
+#if CONFIG_AMV_DECODER
AVCodec ff_amv_decoder = {
.name = "amv",
.type = AVMEDIA_TYPE_VIDEO,
@@ -115,3 +118,4 @@ AVCodec ff_amv_decoder = {
.decode = sp5x_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("AMV Video"),
};
+#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 04b70c3..af5b5fa 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..267561c 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;
}
@@ -213,30 +222,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
--- /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
--- /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 281913f..1e25b60 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/sunrastenc.c b/libavcodec/sunrastenc.c
index e1b5211..2c7e72f 100644
--- a/libavcodec/sunrastenc.c
+++ b/libavcodec/sunrastenc.c
@@ -56,7 +56,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 +83,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 +124,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)
@@ -189,7 +184,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 4b8b656..5f43a97 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
*/
@@ -111,12 +111,11 @@ static const uint8_t string_table[256] = {
break; \
} \
/* divide block if next bit set */ \
- if (get_bits1(bitbuf) == 0) \
+ if (!get_bits1(bitbuf)) \
break; \
/* add child nodes */ \
list[n++] = list[i]; \
- list[n++] = list[i] + \
- (((level & 1) ? pitch : 1) << (level / 2 + 1)); \
+ list[n++] = list[i] + (((level & 1) ? pitch : 1) << ((level >> 1) + 1));\
}
#define SVQ1_ADD_CODEBOOK() \
@@ -152,7 +151,7 @@ static const uint8_t string_table[256] = {
16 * j) << (level + 1); \
} \
mean -= stages * 128; \
- n4 = mean + (mean >> 31) << 16 | (mean & 0xFFFF);
+ n4 = (mean << 16) + mean;
static int svq1_decode_block_intra(GetBitContext *bitbuf, uint8_t *pixels,
int pitch)
@@ -342,8 +341,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 =
@@ -386,8 +384,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) */
@@ -399,8 +396,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) */
@@ -408,8 +404,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) */
@@ -417,8 +412,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 */
@@ -521,6 +515,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 */
@@ -571,20 +567,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) */
@@ -592,16 +588,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;
}
@@ -629,12 +627,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;
@@ -676,8 +676,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 70d1ee5..afef854 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,8 +550,10 @@ 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);
}
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 6455821..3da341e 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"
@@ -77,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;
@@ -230,14 +232,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) {
@@ -252,20 +257,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;
@@ -605,7 +609,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;
}
@@ -674,7 +678,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;
}
@@ -790,8 +794,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);
}
@@ -872,6 +876,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];
@@ -974,7 +979,7 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
int offset = get_bits_count(&gb) + 7 >> 3;
uint8_t *buf;
- if ((uint64_t)watermark_width * 4 > UINT_MAX / watermark_height)
+ if (watermark_height <= 0 || (uint64_t)watermark_width*4 > UINT_MAX/watermark_height)
return -1;
buf = av_malloc(buf_len);
@@ -1088,10 +1093,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 */
@@ -1106,10 +1112,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;
@@ -1250,7 +1267,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)
@@ -1263,6 +1280,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])
@@ -1299,6 +1328,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 81bb9af..1b39dc6 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..92dc44c 100644
--- a/libavcodec/tak.c
+++ b/libavcodec/tak.c
@@ -2,20 +2,20 @@
* 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
*/
@@ -24,6 +24,28 @@
#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,
};
@@ -108,8 +130,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 +166,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..876468d 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 {
@@ -162,5 +162,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..0f2fbc2 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
*/
@@ -67,23 +67,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) {
@@ -99,9 +98,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;
diff --git a/libavcodec/takdec.c b/libavcodec/takdec.c
index 4047513..f36cec3 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
*/
@@ -33,38 +33,42 @@
#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 +136,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 +149,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;
}
@@ -172,9 +170,11 @@ static av_cold int tak_decode_init(AVCodecContext *avctx)
{
TAKDecContext *s = avctx->priv_data;
+ ff_tak_init_crc();
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();
@@ -679,18 +679,14 @@ static int tak_decode_frame(AVCodecContext *avctx, void *data,
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) {
+ hsize = get_bits_count(gb) / 8;
if (ff_tak_check_crc(pkt->data, hsize)) {
av_log(avctx, AV_LOG_ERROR, "CRC error\n");
return AVERROR_INVALIDDATA;
@@ -723,8 +719,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;
}
@@ -743,7 +739,7 @@ static int tak_decode_frame(AVCodecContext *avctx, void *data,
if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- 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);
@@ -764,7 +760,7 @@ static int tak_decode_frame(AVCodecContext *avctx, void *data,
for (chan = 0; chan < avctx->channels; chan++) {
int32_t *decoded = s->decoded[chan];
for (i = 0; i < s->nb_samples; i++)
- decoded[i] = get_sbits(gb, avctx->bits_per_coded_sample);
+ decoded[i] = get_sbits(gb, avctx->bits_per_raw_sample);
}
} else {
if (s->ti.codec == TAK_CODEC_MONO_STEREO) {
@@ -773,9 +769,9 @@ static int tak_decode_frame(AVCodecContext *avctx, void *data,
return ret;
if (avctx->channels == 2) {
- if (get_bits1(gb)) {
- // some kind of subframe length, but it seems to be unused
- skip_bits(gb, 6);
+ s->nb_subframes = get_bits(gb, 1) + 1;
+ if (s->nb_subframes > 1) {
+ s->subframe_len[1] = get_bits(gb, 6);
}
s->dmode = get_bits(gb, 3);
@@ -908,7 +904,6 @@ 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;
}
@@ -919,7 +914,6 @@ 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,
diff --git a/libavcodec/targa.c b/libavcodec/targa.c
index 993f02c..ff4390f 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,34 @@ static int decode_frame(AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
}
+ if (colors && (colors + first_clr) > 256) {
+ av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr);
+ return AVERROR_INVALIDDATA;
+ }
+
if ((ret = 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){
+
+ 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 +204,9 @@ static int decode_frame(AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
}
pal_size = colors * pal_sample_size;
- if(avctx->pix_fmt != AV_PIX_FMT_PAL8)//should not occur but skip palette anyway
+ if (avctx->pix_fmt != AV_PIX_FMT_PAL8) //should not occur but skip palette anyway
bytestream2_skip(&s->gb, pal_size);
- else{
+ else {
int t;
uint32_t *pal = ((uint32_t *)p->data[1]) + first_clr;
@@ -185,10 +216,14 @@ static int decode_frame(AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
}
switch (pal_sample_size) {
+ case 4:
+ for (t = 0; t < colors; t++)
+ *pal++ = bytestream2_get_le32u(&s->gb);
+ break;
case 3:
/* RGB24 */
for (t = 0; t < colors; t++)
- *pal++ = bytestream2_get_le24u(&s->gb);
+ *pal++ = (0xffU<<24) | bytestream2_get_le24u(&s->gb);
break;
case 2:
/* RGB555 */
@@ -199,30 +234,59 @@ static int decode_frame(AVCodecContext *avctx,
((v & 0x001F) << 3);
/* left bit replication */
v |= (v & 0xE0E0E0U) >> 5;
- *pal++ = v;
+ *pal++ = (0xffU<<24) | v;
}
break;
}
p->palette_has_changed = 1;
}
}
+
if ((compr & (~TGA_RLE)) == TGA_NODATA) {
memset(p->data[0], 0, p->linesize[0] * h);
} else {
- if(compr & TGA_RLE){
- int res = targa_decode_rle(avctx, s, dst, w, h, stride, bpp);
+ if (compr & TGA_RLE) {
+ int res = targa_decode_rle(avctx, s, dst, w, h, stride, bpp, interleave);
if (res < 0)
return res;
} else {
size_t img_size = w * ((bpp + 1) >> 3);
+ uint8_t *line;
if (bytestream2_get_bytes_left(&s->gb) < img_size * h) {
av_log(avctx, AV_LOG_ERROR,
"Not enough data available for image\n");
return AVERROR_INVALIDDATA;
}
- for (y = 0; y < h; y++) {
- bytestream2_get_bufferu(&s->gb, dst, img_size);
- dst += stride;
+
+ line = dst;
+ y = 0;
+ do {
+ bytestream2_get_buffer(&s->gb, line, img_size);
+ line = advance_line(dst, line, stride, &y, h, interleave);
+ } while (line);
+ }
+ }
+
+ if (flags & TGA_RIGHTTOLEFT) { // right-to-left, needs horizontal flip
+ int x;
+ for (y = 0; y < h; y++) {
+ void *line = &p->data[0][y * p->linesize[0]];
+ for (x = 0; x < w >> 1; x++) {
+ switch (bpp) {
+ case 32:
+ FFSWAP(uint32_t, ((uint32_t *)line)[x], ((uint32_t *)line)[w - x - 1]);
+ break;
+ case 24:
+ FFSWAP(uint8_t, ((uint8_t *)line)[3 * x ], ((uint8_t *)line)[3 * w - 3 * x - 3]);
+ FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 1], ((uint8_t *)line)[3 * w - 3 * x - 2]);
+ FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 2], ((uint8_t *)line)[3 * w - 3 * x - 1]);
+ break;
+ case 16:
+ FFSWAP(uint16_t, ((uint16_t *)line)[x], ((uint16_t *)line)[w - x - 1]);
+ break;
+ case 8:
+ FFSWAP(uint8_t, ((uint8_t *)line)[x], ((uint8_t *)line)[w - x - 1]);
+ }
}
}
}
diff --git a/libavcodec/targa.h b/libavcodec/targa.h
index f4ef553..c2f5224 100644
--- a/libavcodec/targa.h
+++ b/libavcodec/targa.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,4 +38,11 @@ enum TargaCompr {
TGA_RLE = 8, // flag pointing that data is RLE-coded
};
+enum TargaFlags {
+ TGA_RIGHTTOLEFT = 0x10, // right-to-left (flipped horizontally)
+ TGA_TOPTOBOTTOM = 0x20, // top-to-bottom (NOT flipped vertically)
+ TGA_INTERLEAVE2 = 0x40, // 2-way interleave, odd then even lines
+ TGA_INTERLEAVE4 = 0x80, // 4-way interleave
+};
+
#endif /* AVCODEC_TARGA_H */
diff --git a/libavcodec/targa_y216dec.c b/libavcodec/targa_y216dec.c
new file mode 100644
index 0000000..38694ce
--- /dev/null
+++ b/libavcodec/targa_y216dec.c
@@ -0,0 +1,90 @@
+/*
+ * 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;
+}
+
+static av_cold int y216_decode_close(AVCodecContext *avctx)
+{
+
+ return 0;
+}
+
+AVCodec ff_targa_y216_decoder = {
+ .name = "targa_y216",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_TARGA_Y216,
+ .init = y216_decode_init,
+ .decode = y216_decode_frame,
+ .close = y216_decode_close,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("Pinnacle TARGA CineWave YUV16"),
+};
diff --git a/libavcodec/targaenc.c b/libavcodec/targaenc.c
index e13545f..b2c679d 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
*/
@@ -81,7 +81,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 +89,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 +99,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 +149,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);
@@ -172,7 +194,7 @@ AVCodec ff_targa_encoder = {
.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
},
.long_name= NULL_IF_CONFIG_SMALL("Truevision Targa image"),
diff --git a/libavcodec/textdec.c b/libavcodec/textdec.c
new file mode 100644
index 0000000..f3e6117
--- /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",
+ .priv_data_size = sizeof(TextContext),
+ .long_name = NULL_IF_CONFIG_SMALL("Raw text subtitle"),
+ .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",
+ .priv_data_size = sizeof(TextContext),
+ .long_name = NULL_IF_CONFIG_SMALL("VPlayer subtitle"),
+ .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",
+ .priv_data_size = sizeof(TextContext),
+ .long_name = NULL_IF_CONFIG_SMALL("PJS subtitle"),
+ .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",
+ .priv_data_size = sizeof(TextContext),
+ .long_name = NULL_IF_CONFIG_SMALL("SubViewer1 subtitle"),
+ .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..0dc04e0 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().
diff --git a/libavcodec/tiertexseqv.c b/libavcodec/tiertexseqv.c
index 50f8921..f892e4d 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 79c93cb..6c2dc23 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
*/
@@ -26,21 +25,25 @@
*/
#include "avcodec.h"
+#include "bytestream.h"
#include "config.h"
#if CONFIG_ZLIB
#include <zlib.h>
#endif
#include "lzw.h"
#include "tiff.h"
+#include "tiff_data.h"
#include "faxcompr.h"
#include "internal.h"
#include "mathops.h"
#include "libavutil/attributes.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/imgutils.h"
+#include "libavutil/avstring.h"
typedef struct TiffContext {
AVCodecContext *avctx;
+ GetByteContext gb;
int width, height;
unsigned int bpp, bppcount;
@@ -55,36 +58,296 @@ typedef struct TiffContext {
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 unsigned tget_short(GetByteContext *gb, int le)
{
- unsigned v = le ? AV_RL16(*p) : AV_RB16(*p);
- *p += 2;
+ unsigned v = le ? bytestream2_get_le16(gb) : bytestream2_get_be16(gb);
return v;
}
-static unsigned tget_long(const uint8_t **p, int le)
+static unsigned tget_long(GetByteContext *gb, int le)
{
- unsigned v = le ? AV_RL32(*p) : AV_RB32(*p);
- *p += 4;
+ unsigned v = le ? bytestream2_get_le32(gb) : bytestream2_get_be32(gb);
return v;
}
-static unsigned tget(const uint8_t **p, int type, int le)
+static double tget_double(GetByteContext *gb, int le)
+{
+ av_alias64 i = { .u64 = le ? bytestream2_get_le64(gb) : bytestream2_get_be64(gb)};
+ return i.f64;
+}
+
+static unsigned tget(GetByteContext *gb, int type, int le)
{
switch (type) {
- case TIFF_BYTE : return *(*p)++;
- case TIFF_SHORT: return tget_short(p, le);
- case TIFF_LONG : return tget_long(p, le);
+ case TIFF_BYTE : return bytestream2_get_byte(gb);
+ case TIFF_SHORT: return tget_short(gb, le);
+ case TIFF_LONG : return tget_long(gb, le);
default : return UINT_MAX;
}
}
+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)
+{
+ RET_GEOKEY(VERT, vert, type);
+ RET_GEOKEY(PROJ, proj, type);
+ RET_GEOKEY(GEOG, geog, type);
+ RET_GEOKEY(CONF, conf, type);
+
+ return AVERROR_INVALIDDATA;
+}
+
+static int cmp_id_key(const void *id, const void *k)
+{
+ return *(const int*)id - ((const TiffGeoTagKeyName*)k)->key;
+}
+
+static const char *search_keyval(const TiffGeoTagKeyName *keys, int n, int id)
+{
+ TiffGeoTagKeyName *r = bsearch(&id, keys, n, sizeof(keys[0]), cmp_id_key);
+ if(r)
+ return r->name;
+
+ return NULL;
+}
+
+static char *get_geokey_val(int key, int val)
+{
+ char *ap;
+
+ if (val == TIFF_GEO_KEY_UNDEFINED)
+ return av_strdup("undefined");
+ if (val == TIFF_GEO_KEY_USER_DEFINED)
+ return av_strdup("User-Defined");
+
+#define RET_GEOKEY_VAL(TYPE, array)\
+ if (val >= TIFF_##TYPE##_OFFSET &&\
+ val - TIFF_##TYPE##_OFFSET < FF_ARRAY_ELEMS(ff_tiff_##array##_codes))\
+ return av_strdup(ff_tiff_##array##_codes[val - TIFF_##TYPE##_OFFSET]);
+
+ switch (key) {
+ case TIFF_GT_MODEL_TYPE_GEOKEY:
+ RET_GEOKEY_VAL(GT_MODEL_TYPE, gt_model_type);
+ break;
+ case TIFF_GT_RASTER_TYPE_GEOKEY:
+ RET_GEOKEY_VAL(GT_RASTER_TYPE, gt_raster_type);
+ break;
+ case TIFF_GEOG_LINEAR_UNITS_GEOKEY:
+ case TIFF_PROJ_LINEAR_UNITS_GEOKEY:
+ case TIFF_VERTICAL_UNITS_GEOKEY:
+ RET_GEOKEY_VAL(LINEAR_UNIT, linear_unit);
+ break;
+ case TIFF_GEOG_ANGULAR_UNITS_GEOKEY:
+ case TIFF_GEOG_AZIMUTH_UNITS_GEOKEY:
+ RET_GEOKEY_VAL(ANGULAR_UNIT, angular_unit);
+ break;
+ case TIFF_GEOGRAPHIC_TYPE_GEOKEY:
+ RET_GEOKEY_VAL(GCS_TYPE, gcs_type);
+ RET_GEOKEY_VAL(GCSE_TYPE, gcse_type);
+ break;
+ case TIFF_GEOG_GEODETIC_DATUM_GEOKEY:
+ RET_GEOKEY_VAL(GEODETIC_DATUM, geodetic_datum);
+ RET_GEOKEY_VAL(GEODETIC_DATUM_E, geodetic_datum_e);
+ break;
+ case TIFF_GEOG_ELLIPSOID_GEOKEY:
+ RET_GEOKEY_VAL(ELLIPSOID, ellipsoid);
+ break;
+ case TIFF_GEOG_PRIME_MERIDIAN_GEOKEY:
+ RET_GEOKEY_VAL(PRIME_MERIDIAN, prime_meridian);
+ break;
+ case TIFF_PROJECTED_CS_TYPE_GEOKEY:
+ ap = av_strdup(search_keyval(ff_tiff_proj_cs_type_codes, FF_ARRAY_ELEMS(ff_tiff_proj_cs_type_codes), val));
+ if(ap) return ap;
+ break;
+ case TIFF_PROJECTION_GEOKEY:
+ ap = av_strdup(search_keyval(ff_tiff_projection_codes, FF_ARRAY_ELEMS(ff_tiff_projection_codes), val));
+ if(ap) return ap;
+ break;
+ case TIFF_PROJ_COORD_TRANS_GEOKEY:
+ RET_GEOKEY_VAL(COORD_TRANS, coord_trans);
+ break;
+ case TIFF_VERTICAL_CS_TYPE_GEOKEY:
+ RET_GEOKEY_VAL(VERT_CS, vert_cs);
+ RET_GEOKEY_VAL(ORTHO_VERT_CS, ortho_vert_cs);
+ break;
+
+ }
+
+ ap = av_malloc(14);
+ if (ap)
+ snprintf(ap, 14, "Unknown-%d", val);
+ return ap;
+}
+
+static char *doubles2str(double *dp, int count, const char *sep)
+{
+ int i;
+ char *ap, *ap0;
+ uint64_t component_len;
+ if (!sep) sep = ", ";
+ component_len = 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 char *shorts2str(int16_t *sp, int count, const char *sep)
+{
+ int i;
+ char *ap, *ap0;
+ uint64_t component_len;
+ if (!sep) sep = ", ";
+ component_len = 7LL + 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, "%d%s", sp[i], sep);
+ if (l >= component_len) {
+ av_free(ap0);
+ return NULL;
+ }
+ ap += l;
+ }
+ ap0[strlen(ap0) - strlen(sep)] = '\0';
+ return ap0;
+}
+
+static int add_doubles_metadata(int count,
+ const char *name, const char *sep,
+ TiffContext *s, AVFrame *frame)
+{
+ char *ap;
+ int i;
+ double *dp;
+
+ if (count >= INT_MAX / sizeof(int64_t) || count <= 0)
+ 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)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < count; i++)
+ dp[i] = tget_double(&s->gb, s->le);
+ ap = doubles2str(dp, count, sep);
+ av_freep(&dp);
+ if (!ap)
+ return AVERROR(ENOMEM);
+ av_dict_set(avpriv_frame_get_metadatap(frame), name, ap, AV_DICT_DONT_STRDUP_VAL);
+ return 0;
+}
+
+static int add_shorts_metadata(int count, const char *name,
+ const char *sep, TiffContext *s, AVFrame *frame)
+{
+ char *ap;
+ int i;
+ int16_t *sp;
+
+ if (count >= INT_MAX / sizeof(int16_t) || count <= 0)
+ return AVERROR_INVALIDDATA;
+ if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int16_t))
+ return AVERROR_INVALIDDATA;
+
+ sp = av_malloc(count * sizeof(int16_t));
+ if (!sp)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < count; i++)
+ sp[i] = tget_short(&s->gb, s->le);
+ ap = shorts2str(sp, count, sep);
+ av_freep(&sp);
+ if (!ap)
+ return AVERROR(ENOMEM);
+ av_dict_set(avpriv_frame_get_metadatap(frame), name, ap, AV_DICT_DONT_STRDUP_VAL);
+ return 0;
+}
+
+static int add_string_metadata(int count, const char *name,
+ TiffContext *s, AVFrame *frame)
+{
+ char *value;
+
+ if (bytestream2_get_bytes_left(&s->gb) < count || count < 0)
+ return AVERROR_INVALIDDATA;
+
+ value = av_malloc(count + 1);
+ if (!value)
+ return AVERROR(ENOMEM);
+
+ bytestream2_get_bufferu(&s->gb, value, count);
+ value[count] = 0;
+
+ av_dict_set(avpriv_frame_get_metadatap(frame), name, value, AV_DICT_DONT_STRDUP_VAL);
+ return 0;
+}
+
+static int add_metadata(int count, int type,
+ const char *name, const char *sep, TiffContext *s, AVFrame *frame)
+{
+ switch(type) {
+ case TIFF_DOUBLE: return add_doubles_metadata(count, name, sep, s, frame);
+ case TIFF_SHORT : return add_shorts_metadata(count, name, sep, s, frame);
+ case TIFF_STRING: return add_string_metadata(count, name, s, frame);
+ default : return AVERROR_INVALIDDATA;
+ };
+}
+
#if CONFIG_ZLIB
static int tiff_uncompress(uint8_t *dst, unsigned long *len, const uint8_t *src,
int size)
@@ -92,7 +355,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;
@@ -108,6 +371,46 @@ static int tiff_uncompress(uint8_t *dst, unsigned long *len, const uint8_t *src,
}
#endif
+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:
+ if (usePtr) {
+ memcpy(dst + offset, src, width);
+ } else {
+ memset(dst + offset, c, width);
+ }
+ }
+}
+
static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
const uint8_t *src, int size, int lines)
{
@@ -120,32 +423,63 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
#if CONFIG_ZLIB
if (s->compr == TIFF_DEFLATE || s->compr == TIFF_ADOBE_DEFLATE) {
- uint8_t *zbuf;
+ uint8_t *src2 = NULL, *zbuf;
unsigned long outlen;
- int ret;
+ int i, ret;
outlen = width * lines;
zbuf = av_malloc(outlen);
if (!zbuf)
return AVERROR(ENOMEM);
+ if (s->fill_order) {
+ src2 = av_malloc((unsigned)size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!src2) {
+ av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n");
+ av_free(zbuf);
+ return AVERROR(ENOMEM);
+ }
+ for (i = 0; i < size; i++)
+ src2[i] = ff_reverse[src[i]];
+ memset(src2 + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ src = src2;
+ }
ret = tiff_uncompress(zbuf, &outlen, src, size);
if (ret != Z_OK) {
av_log(s->avctx, AV_LOG_ERROR,
"Uncompressing failed (%lu of %lu) with error %d\n", outlen,
(unsigned long)width * lines, ret);
+ av_free(src2);
av_free(zbuf);
return AVERROR_UNKNOWN;
}
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;
}
+ av_free(src2);
av_free(zbuf);
return 0;
}
#endif
if (s->compr == TIFF_LZW) {
+ if (s->fill_order) {
+ 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]];
+ src = s->deinvert_buf;
+ ssrc = src;
+ }
+ 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;
@@ -183,6 +517,11 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
s->compr, s->fax_opts);
break;
}
+ 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;
}
@@ -196,7 +535,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++)
@@ -206,6 +546,10 @@ 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) {
+ av_log(s->avctx, AV_LOG_ERROR, "Read went out of bounds\n");
+ return AVERROR_INVALIDDATA;
+ }
code = (int8_t) * src++;
if (code >= 0) {
code++;
@@ -214,7 +558,12 @@ 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);
+ if (ssrc + size - src < code) {
+ av_log(s->avctx, AV_LOG_ERROR, "Read went out of bounds\n");
+ return AVERROR_INVALIDDATA;
+ }
+ horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8),
+ dst, 1, src, 0, code, pixels);
src += code;
pixels += code;
} else if (code != -128) { // -127..-1
@@ -225,7 +574,8 @@ 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;
}
}
@@ -237,6 +587,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;
@@ -251,8 +603,12 @@ static int init_image(TiffContext *s, AVFrame *frame)
switch (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;
@@ -262,12 +618,18 @@ 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;
break;
+ case 644:
+ s->avctx->pix_fmt = s->le ? AV_PIX_FMT_RGBA64LE : AV_PIX_FMT_RGBA64BE;
+ break;
default:
av_log(s->avctx, AV_LOG_ERROR,
"This format is not supported (bpp=%d, bppcount=%d)\n",
@@ -279,37 +641,34 @@ 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_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));
} else {
/* make default grayscale pal */
pal = (uint32_t *) frame->data[1];
- for (i = 0; i < 256; i++)
- pal[i] = i * 0x010101;
+ 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;
+ double *dp;
- 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);
+ tag = tget_short(&s->gb, s->le);
+ type = tget_short(&s->gb, s->le);
+ count = tget_long(&s->gb, s->le);
+ off = tget_long(&s->gb, s->le);
+ start = bytestream2_tell(&s->gb);
if (type == 0 || type >= FF_ARRAY_ELEMS(type_sizes)) {
av_log(s->avctx, AV_LOG_DEBUG, "Unknown tiff type (%u) encountered\n",
@@ -321,37 +680,29 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
switch (type) {
case TIFF_BYTE:
case TIFF_SHORT:
- buf -= 4;
- value = tget(&buf, type, s->le);
- buf = NULL;
+ bytestream2_seek(&s->gb, -4, SEEK_CUR);
+ value = tget(&s->gb, type, s->le);
break;
case TIFF_LONG:
value = off;
- buf = NULL;
break;
case TIFF_STRING:
if (count <= 4) {
- buf -= 4;
+ bytestream2_seek(&s->gb, -4, SEEK_CUR);
break;
}
default:
value = UINT_MAX;
- buf = start + off;
+ bytestream2_seek(&s->gb, off, SEEK_SET);
}
} else {
if (count <= 4 && type_sizes[type] * count <= 4) {
- buf -= 4;
+ bytestream2_seek(&s->gb, -4, SEEK_CUR);
} else {
- buf = start + off;
+ bytestream2_seek(&s->gb, off, SEEK_SET);
}
}
- 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) {
case TIFF_WIDTH:
s->width = value;
@@ -378,8 +729,10 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
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 += tget(&s->gb, type, s->le);
break;
default:
s->bpp = -1;
@@ -392,6 +745,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;
@@ -430,7 +788,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");
@@ -440,15 +798,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;
@@ -456,20 +814,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;
@@ -501,17 +866,16 @@ 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 = (tget(&s->gb, type, s->le) >> off) << (k * 8);
+ pal[i] |= j;
+ }
}
s->palette_is_set = 1;
break;
@@ -529,33 +893,165 @@ 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");\
+ return ret;\
+ }
+ 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 = 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;
+ return AVERROR(ENOMEM);
+ }
+ for (i = 0; i < s->geotag_count; i++) {
+ s->geotags[i].key = tget_short(&s->gb, s->le);
+ s->geotags[i].type = tget_short(&s->gb, s->le);
+ s->geotags[i].count = tget_short(&s->gb, s->le);
+
+ if (!s->geotags[i].type)
+ s->geotags[i].val = get_geokey_val(s->geotags[i].key, tget_short(&s->gb, s->le));
+ else
+ s->geotags[i].offset = 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");
+ return AVERROR(ENOMEM);
+ }
+ for (i = 0; i < count; i++)
+ dp[i] = 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:
av_log(s->avctx, AV_LOG_DEBUG, "Unknown or unsupported tag %d/0X%0X\n",
tag, tag);
}
+ 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;
unsigned off;
int id, le, ret;
int i, j, entries;
int 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)
+ if (avpkt->size < 8)
return AVERROR_INVALIDDATA;
- id = AV_RL16(buf);
- buf += 2;
+ id = bytestream2_get_le16u(&s->gb);
if (id == 0x4949)
le = 1;
else if (id == 0x4D4D)
@@ -565,32 +1061,55 @@ static int decode_frame(AVCodecContext *avctx,
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;
+ free_geotags(s);
+
// 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) {
+ if (tget_short(&s->gb, le) != 42) {
av_log(avctx, AV_LOG_ERROR,
"The answer to life, universe and everything is not correct!\n");
return AVERROR_INVALIDDATA;
}
- // Reset these pointers so we can tell if they were set this frame
- s->stripsizes = s->stripdata = NULL;
+ // 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) {
+ off = tget_long(&s->gb, le);
+ if (off >= UINT_MAX - 14 || avpkt->size < off + 14) {
av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n");
return AVERROR_INVALIDDATA;
}
- buf = orig_buf + off;
- entries = tget_short(&buf, le);
+ bytestream2_seek(&s->gb, off, SEEK_SET);
+ entries = tget_short(&s->gb, le);
+ if (bytestream2_get_bytes_left(&s->gb) < entries * 12)
+ return AVERROR_INVALIDDATA;
for (i = 0; i < entries; i++) {
- if ((ret = tiff_decode_tag(s, orig_buf, buf, end_buf)) < 0)
+ if ((ret = tiff_decode_tag(s, p)) < 0)
+ return ret;
+ }
+
+ for (i = 0; i<s->geotag_count; i++) {
+ const char *keyname = get_geokey_name(s->geotags[i].key);
+ if (!keyname) {
+ av_log(avctx, AV_LOG_WARNING, "Unknown or unsupported GeoTIFF key %d\n", s->geotags[i].key);
+ continue;
+ }
+ if (get_geokey_type(s->geotags[i].key) != s->geotags[i].type) {
+ av_log(avctx, AV_LOG_WARNING, "Type of GeoTIFF key %d is wrong\n", s->geotags[i].key);
+ continue;
+ }
+ ret = av_dict_set(avpriv_frame_get_metadatap(p), keyname, s->geotags[i].val, 0);
+ if (ret<0) {
+ av_log(avctx, AV_LOG_ERROR, "Writing metadata with key '%s' failed\n", keyname);
return ret;
- buf += 12;
+ }
}
- if (!s->stripdata && !s->stripoff) {
+
+ if (!s->strippos && !s->stripoff) {
av_log(avctx, AV_LOG_ERROR, "Image data is missing\n");
return AVERROR_INVALIDDATA;
}
@@ -600,30 +1119,43 @@ static int decode_frame(AVCodecContext *avctx,
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;
}
stride = p->linesize[0];
dst = p->data[0];
+
+ 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);
+ }
+
+ if (s->rps <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "rps %d invalid\n", s->rps);
+ return AVERROR_INVALIDDATA;
+ }
+
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 = 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 = 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 (tiff_unpack_strip(s, dst, stride, orig_buf + soff, ssize,
+ if (tiff_unpack_strip(s, dst, stride, avpkt->data + soff, ssize,
FFMIN(s->rps, s->height - i)) < 0)
break;
dst += s->rps * stride;
@@ -632,27 +1164,40 @@ static int decode_frame(AVCodecContext *avctx,
dst = p->data[0];
soff = s->bpp >> 3;
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) {
+ 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) {
+ 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[0];
+ for (i = 0; i < s->height; i++) {
+ for (j = 0; j < p->linesize[0]; j++)
+ dst[j] = (s->avctx->pix_fmt == AV_PIX_FMT_PAL8 ? (1<<s->bpp) - 1 : 255) - dst[j];
+ dst += p->linesize[0];
}
}
*got_frame = 1;
- return buf_size;
+ return avpkt->size;
}
static av_cold int tiff_init(AVCodecContext *avctx)
@@ -672,7 +1217,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;
}
diff --git a/libavcodec/tiff.h b/libavcodec/tiff.h
index cf890d6..6d760f0 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
*/
@@ -39,6 +41,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 +52,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 */
@@ -80,11 +103,91 @@ enum TiffTypes{
TIFF_SHORT,
TIFF_LONG,
TIFF_RATIONAL,
+ TIFF_SBYTE,
+ TIFF_UNDEFINED,
+ TIFF_SSHORT,
+ TIFF_SLONG,
+ TIFF_SRATIONAL,
+ TIFF_FLOAT,
+ TIFF_DOUBLE,
+ TIFF_IFD
+};
+
+enum TiffGeoTagKey {
+ TIFF_GT_MODEL_TYPE_GEOKEY = 1024,
+ TIFF_GT_RASTER_TYPE_GEOKEY = 1025,
+ TIFF_GT_CITATION_GEOKEY = 1026,
+ TIFF_GEOGRAPHIC_TYPE_GEOKEY = 2048,
+ TIFF_GEOG_CITATION_GEOKEY = 2049,
+ TIFF_GEOG_GEODETIC_DATUM_GEOKEY = 2050,
+ TIFF_GEOG_PRIME_MERIDIAN_GEOKEY = 2051,
+ TIFF_GEOG_LINEAR_UNITS_GEOKEY = 2052,
+ TIFF_GEOG_LINEAR_UNIT_SIZE_GEOKEY = 2053,
+ TIFF_GEOG_ANGULAR_UNITS_GEOKEY = 2054,
+ TIFF_GEOG_ANGULAR_UNIT_SIZE_GEOKEY = 2055,
+ TIFF_GEOG_ELLIPSOID_GEOKEY = 2056,
+ TIFF_GEOG_SEMI_MAJOR_AXIS_GEOKEY = 2057,
+ TIFF_GEOG_SEMI_MINOR_AXIS_GEOKEY = 2058,
+ TIFF_GEOG_INV_FLATTENING_GEOKEY = 2059,
+ TIFF_GEOG_AZIMUTH_UNITS_GEOKEY = 2060,
+ TIFF_GEOG_PRIME_MERIDIAN_LONG_GEOKEY = 2061,
+ TIFF_PROJECTED_CS_TYPE_GEOKEY = 3072,
+ TIFF_PCS_CITATION_GEOKEY = 3073,
+ TIFF_PROJECTION_GEOKEY = 3074,
+ TIFF_PROJ_COORD_TRANS_GEOKEY = 3075,
+ TIFF_PROJ_LINEAR_UNITS_GEOKEY = 3076,
+ TIFF_PROJ_LINEAR_UNIT_SIZE_GEOKEY = 3077,
+ TIFF_PROJ_STD_PARALLEL1_GEOKEY = 3078,
+ TIFF_PROJ_STD_PARALLEL2_GEOKEY = 3079,
+ TIFF_PROJ_NAT_ORIGIN_LONG_GEOKEY = 3080,
+ TIFF_PROJ_NAT_ORIGIN_LAT_GEOKEY = 3081,
+ TIFF_PROJ_FALSE_EASTING_GEOKEY = 3082,
+ TIFF_PROJ_FALSE_NORTHING_GEOKEY = 3083,
+ TIFF_PROJ_FALSE_ORIGIN_LONG_GEOKEY = 3084,
+ TIFF_PROJ_FALSE_ORIGIN_LAT_GEOKEY = 3085,
+ TIFF_PROJ_FALSE_ORIGIN_EASTING_GEOKEY = 3086,
+ TIFF_PROJ_FALSE_ORIGIN_NORTHING_GEOKEY = 3087,
+ TIFF_PROJ_CENTER_LONG_GEOKEY = 3088,
+ TIFF_PROJ_CENTER_LAT_GEOKEY = 3089,
+ TIFF_PROJ_CENTER_EASTING_GEOKEY = 3090,
+ TIFF_PROJ_CENTER_NORTHING_GEOKEY = 3091,
+ TIFF_PROJ_SCALE_AT_NAT_ORIGIN_GEOKEY = 3092,
+ TIFF_PROJ_SCALE_AT_CENTER_GEOKEY = 3093,
+ TIFF_PROJ_AZIMUTH_ANGLE_GEOKEY = 3094,
+ TIFF_PROJ_STRAIGHT_VERT_POLE_LONG_GEOKEY = 3095,
+ TIFF_VERTICAL_CS_TYPE_GEOKEY = 4096,
+ TIFF_VERTICAL_CITATION_GEOKEY = 4097,
+ TIFF_VERTICAL_DATUM_GEOKEY = 4098,
+ TIFF_VERTICAL_UNITS_GEOKEY = 4099
+};
+
+enum TiffGeoTagType {
+ GEOTIFF_SHORT = 0,
+ GEOTIFF_DOUBLE = 34736,
+ GEOTIFF_STRING = 34737
};
/** sizes of various TIFF field types (string size = 100)*/
-static const uint8_t type_sizes[6] = {
- 0, 1, 100, 2, 4, 8
+static const uint8_t type_sizes[14] = {
+ 0, 1, 100, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4
};
+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_data.c b/libavcodec/tiff_data.c
new file mode 100644
index 0000000..5bfe009
--- /dev/null
+++ b/libavcodec/tiff_data.c
@@ -0,0 +1,1870 @@
+/*
+ * TIFF data tables
+ * Copyright (c) 2011 Thomas Kuehnel
+ *
+ * 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
+ * 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..91a4e1e
--- /dev/null
+++ b/libavcodec/tiff_data.h
@@ -0,0 +1,92 @@
+/*
+ * TIFF data tables
+ * Copyright (c) 2011 Thomas Kuehnel
+ *
+ * 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
+ * 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 fc777eb..61294b9 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
*/
@@ -25,6 +25,7 @@
* @author Bartlomiej Wolowiec
*/
+#include "libavutil/imgutils.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
@@ -35,6 +36,7 @@
#include <zlib.h>
#endif
#include "bytestream.h"
+#include "internal.h"
#include "tiff.h"
#include "rle.h"
#include "lzw.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]; ///< entires in header
int num_entries; ///< number of entires
@@ -67,11 +75,13 @@ 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
@@ -87,13 +97,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)
@@ -108,11 +118,12 @@ 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,
@@ -120,17 +131,17 @@ static void add_entry(TiffEncoderContext * s,
{
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);
}
@@ -145,14 +156,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)
@@ -192,90 +203,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;
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:
s->photometric_interpretation = 6;
- av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt,
- &shift_h, &shift_v);
- s->bpp = 8 + (16 >> (shift_h + shift_v));
+ avcodec_get_chroma_sub_sample(avctx->pix_fmt, &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:
@@ -284,6 +304,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)
//best choose for DEFLATE
s->rps = s->height;
@@ -293,12 +316,9 @@ static int encode_frame(AVCodecContext * avctx, AVPacket *pkt,
strips = (s->height - 1) / s->rps + 1;
- if (!pkt->data &&
- (ret = av_new_packet(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");
+ if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width * avctx->height * s->bpp * 2 +
+ avctx->height * 4 + FF_MIN_BUFFER_SIZE)) < 0)
return ret;
- }
ptr = pkt->data;
s->buf_start = pkt->data;
s->buf = &ptr;
@@ -314,9 +334,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;
}
@@ -324,8 +345,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;
@@ -344,12 +365,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
@@ -364,7 +385,7 @@ 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
{
@@ -376,16 +397,16 @@ 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
@@ -395,11 +416,11 @@ 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 ;
+ s->strip_sizes[(i / s->rps )] += ret ;
ptr += ret;
}
}
@@ -418,13 +439,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);
@@ -443,10 +464,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);
}
bytestream_put_le32(&offset, ptr - pkt->data); // write offset to dir
@@ -464,15 +489,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" },
@@ -495,13 +529,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
},
.long_name = NULL_IF_CONFIG_SMALL("TIFF image"),
diff --git a/libavcodec/timecode.c b/libavcodec/timecode.c
new file mode 100644
index 0000000..f9862e5
--- /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
--- /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 c1e4d25..279298c 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 9c21917..5a387ca 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;
@@ -513,6 +513,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 +534,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 +556,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 +577,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 +868,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);
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 a4d01cb..7783386 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
*/
@@ -63,6 +63,9 @@ typedef struct TM2Context {
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;
@@ -214,6 +217,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 +275,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 +288,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;
}
@@ -336,7 +346,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 +373,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 +686,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);
@@ -841,36 +861,33 @@ static int decode_frame(AVCodecContext *avctx,
AVFrame * const p = &l->pic;
int offset = TM2_HEADER_SIZE;
int i, t, ret;
- uint8_t *swbuf;
- swbuf = av_malloc(buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!swbuf) {
+ av_fast_padded_malloc(&l->buffer, &l->buffer_size, buf_size);
+ if (!l->buffer) {
av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer\n");
return AVERROR(ENOMEM);
}
- if ((ret = ff_reget_buffer(avctx, p)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- av_free(swbuf);
+ if ((ret = ff_reget_buffer(avctx, p)) < 0)
return ret;
- }
- l->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;
@@ -884,7 +901,6 @@ static int decode_frame(AVCodecContext *avctx,
l->cur = !l->cur;
*got_frame = 1;
ret = av_frame_ref(data, &l->pic);
- av_free(swbuf);
return (ret < 0) ? ret : buf_size;
}
@@ -915,15 +931,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_mallocz(sizeof(*l->Y1_base) * w * h);
+ l->Y2_base = av_mallocz(sizeof(*l->Y2_base) * w * h);
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_mallocz(sizeof(*l->U1_base) * w * h);
+ l->V1_base = av_mallocz(sizeof(*l->V1_base) * w * h);
+ l->U2_base = av_mallocz(sizeof(*l->U2_base) * w * h);
+ l->V2_base = av_mallocz(sizeof(*l->V1_base) * w * h);
l->uv_stride = w;
l->cur = 0;
if (!l->Y1_base || !l->Y2_base || !l->U1_base ||
@@ -967,6 +983,8 @@ static av_cold int decode_end(AVCodecContext *avctx)
av_free(l->U2_base);
av_free(l->V2_base);
}
+ av_freep(&l->buffer);
+ l->buffer_size = 0;
av_frame_unref(pic);
diff --git a/libavcodec/truespeech.c b/libavcodec/truespeech.c
index ff39343..2eb218c 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 ce88b0e..6e1e077 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 aae7119..291693a 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 e9c4285..cd00b88 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
*/
@@ -33,6 +33,8 @@
#include "get_bits.h"
#include "internal.h"
#include "libavutil/crc.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
#define FORMAT_SIMPLE 1
#define FORMAT_ENCRYPTED 2
@@ -56,6 +58,7 @@ typedef struct TTAChannel {
} TTAChannel;
typedef struct TTAContext {
+ AVClass *class;
AVCodecContext *avctx;
GetBitContext gb;
const AVCRC *crc_table;
@@ -66,6 +69,8 @@ typedef struct TTAContext {
int32_t *decode_buffer;
+ uint8_t crc_pass[8];
+ uint8_t *pass;
TTAChannel *ch_ctx;
} TTAContext;
@@ -91,74 +96,47 @@ static const int32_t ttafilter_configs[4] = {
12
};
-static void ttafilter_init(TTAFilter *c, int32_t shift) {
+static void ttafilter_init(TTAContext *s, TTAFilter *c, int32_t shift) {
memset(c, 0, sizeof(TTAFilter));
+ if (s->format == FORMAT_ENCRYPTED) {
+ int i;
+ for (i = 0; i < 8; i++)
+ c->qm[i] = sign_extend(s->crc_pass[i], 8);
+ }
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)
@@ -179,6 +157,16 @@ static int tta_get_unary(GetBitContext *gb)
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)
{
uint32_t crc, CRC;
@@ -193,6 +181,21 @@ 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 av_cold int tta_decode_init(AVCodecContext * avctx)
{
TTAContext *s = avctx->priv_data;
@@ -202,7 +205,7 @@ static av_cold int tta_decode_init(AVCodecContext * avctx)
// 30bytes includes a seektable with one frame
if (avctx->extradata_size < 30)
- return -1;
+ return AVERROR_INVALIDDATA;
init_get_bits(&s->gb, avctx->extradata, avctx->extradata_size * 8);
if (show_bits_long(&s->gb, 32) == AV_RL32("TTA1"))
@@ -217,37 +220,42 @@ static av_cold int tta_decode_init(AVCodecContext * avctx)
s->format = get_bits(&s->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;
+ if (s->channels > 1 && s->channels < 9)
+ avctx->channel_layout = tta_channel_layouts[s->channels-2];
+ avctx->bits_per_raw_sample = get_bits(&s->gb, 16);
+ s->bps = (avctx->bits_per_raw_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
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,10 +272,10 @@ 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
@@ -283,14 +291,15 @@ static av_cold int tta_decode_init(AVCodecContext * avctx)
if(s->frame_length >= UINT_MAX / (s->channels * sizeof(int32_t))){
av_log(avctx, AV_LOG_ERROR, "frame_length too large\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
- if (s->bps == 2) {
+ 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);
@@ -298,7 +307,7 @@ static av_cold int tta_decode_init(AVCodecContext * avctx)
}
} else {
av_log(avctx, AV_LOG_ERROR, "Wrong extradata present\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
return 0;
@@ -324,10 +333,8 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data,
/* 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_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
// decode directly to output buffer for 24-bit sample format
if (s->bps == 3)
@@ -336,7 +343,7 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data,
// init per channel states
for (i = 0; i < s->channels; i++) {
s->ch_ctx[i].predictor = 0;
- ttafilter_init(&s->ch_ctx[i].filter, ttafilter_configs[s->bps-1]);
+ ttafilter_init(s, &s->ch_ctx[i].filter, ttafilter_configs[s->bps-1]);
rice_init(&s->ch_ctx[i].rice, 10, 10);
}
@@ -434,17 +441,28 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data,
skip_bits_long(&s->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++)
+ for (p = s->decode_buffer; p < s->decode_buffer + (framelen * s->channels); p++)
*samples++ <<= 8;
// reset decode buffer
s->decode_buffer = NULL;
+ break;
+ }
}
*got_frame_ptr = 1;
@@ -460,12 +478,28 @@ error:
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",
.type = AVMEDIA_TYPE_AUDIO,
@@ -476,4 +510,5 @@ AVCodec ff_tta_decoder = {
.decode = tta_decode_frame,
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("TTA (True Audio)"),
+ .priv_class = &tta_decoder_class,
};
diff --git a/libavcodec/twinvq.c b/libavcodec/twinvq.c
index a4c1e93..8b9c79f 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
*/
@@ -832,10 +832,8 @@ static int twin_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;
}
@@ -1139,6 +1137,11 @@ static av_cold int twin_decode_init(AVCodecContext *avctx)
ibps = avctx->bit_rate / (1000 * avctx->channels);
+ if (ibps > 255U) {
+ av_log(avctx, AV_LOG_ERROR, "unsupported per channel bitrate %dkbps\n", ibps);
+ return AVERROR_INVALIDDATA;
+ }
+
switch ((isampf << 8) + ibps) {
case (8 <<8) + 8: tctx->mtab = &mode_08_08; break;
case (11<<8) + 8: tctx->mtab = &mode_11_08; break;
diff --git a/libavcodec/twinvq_data.h b/libavcodec/twinvq_data.h
index a236127..63911f8 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/txd.c b/libavcodec/txd.c
index a2d123e..e8d483f 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 3825980..2120d97 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 c54af67..573bba6 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
*/
@@ -29,6 +29,7 @@
#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"
@@ -37,10 +38,12 @@
#include "libavutil/imgutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/dict.h"
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "dsputil.h"
#include "libavutil/opt.h"
#include "thread.h"
+#include "frame_thread_encoder.h"
#include "internal.h"
#include "bytestream.h"
#include "version.h"
@@ -48,7 +51,11 @@
#include <stdarg.h>
#include <limits.h>
#include <float.h>
+#if CONFIG_ICONV
+# include <iconv.h>
+#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;
@@ -73,30 +80,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 */
@@ -155,8 +179,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 (ARCH_ARM && HAVE_NEON) || ARCH_PPC || HAVE_MMX
@@ -179,6 +203,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:
@@ -194,18 +219,34 @@ 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_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_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_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;
@@ -219,15 +260,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;
}
@@ -239,16 +283,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++)
@@ -292,10 +347,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) {
@@ -355,7 +410,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,
+ CONFIG_MEMORY_POISONING ?
+ NULL :
+ av_buffer_allocz);
if (!pool->pools[i]) {
ret = AVERROR(ENOMEM);
goto fail;
@@ -369,7 +427,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;
@@ -425,8 +483,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]);
@@ -503,6 +563,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;
@@ -524,47 +607,29 @@ int avcodec_default_get_buffer2(AVCodecContext *avctx, AVFrame *frame, int flags
}
}
-#if FF_API_GET_BUFFER
-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);
-}
-#endif
-
-int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
+int ff_init_buffer_info(AVCodecContext *avctx, AVFrame *frame)
{
- 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;
break;
case AVMEDIA_TYPE_AUDIO:
if (!frame->sample_rate)
@@ -587,18 +652,52 @@ 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
+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);
+}
+#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
/*
@@ -625,7 +724,7 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
* avcodec_default_get_buffer
*/
if (frame->buf[0])
- return 0;
+ goto end;
priv = av_mallocz(sizeof(*priv));
if (!priv) {
@@ -701,6 +800,7 @@ do { \
av_buffer_unref(&dummy_buf);
+end:
frame->width = avctx->width;
frame->height = avctx->height;
@@ -724,13 +824,29 @@ fail:
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);
@@ -753,9 +869,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);
}
@@ -805,12 +931,22 @@ 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 */
@@ -819,11 +955,12 @@ void avcodec_get_frame_defaults(AVFrame *frame)
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;
@@ -844,6 +981,62 @@ void avcodec_free_frame(AVFrame **frame)
av_freep(frame);
}
+#define MAKE_ACCESSORS(str, name, type, field) \
+ type av_##name##_get_##field(const str *s) { return s->field; } \
+ void av_##name##_set_##field(str *s, type v) { s->field = v; }
+
+MAKE_ACCESSORS(AVCodecContext, codec, AVRational, pkt_timebase)
+MAKE_ACCESSORS(AVCodecContext, codec, const AVCodecDescriptor *, codec_descriptor)
+MAKE_ACCESSORS(AVCodecContext, codec, int, 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;
@@ -853,12 +1046,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)
@@ -870,18 +1063,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) {
@@ -915,15 +1099,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);
}
@@ -945,14 +1133,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;
}
@@ -963,7 +1162,19 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
avctx->time_base.den = avctx->sample_rate;
}
- if (HAVE_THREADS && !avctx->thread_opaque) {
+ 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->thread_opaque
+ && !(avctx->internal->frame_thread_encoder && (avctx->active_thread_type&FF_THREAD_FRAME))) {
ret = ff_thread_init(avctx);
if (ret < 0) {
goto free_and_end;
@@ -972,6 +1183,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) {
@@ -986,7 +1204,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;
}
@@ -995,8 +1216,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;
}
@@ -1006,55 +1232,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;
}
}
@@ -1063,14 +1324,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;
@@ -1087,10 +1380,22 @@ free_and_end:
goto end;
}
-int ff_alloc_packet(AVPacket *avpkt, int size)
+int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int size)
{
- if (size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE)
+ if (size < 0 || avpkt->size < 0 || size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE) {
+ av_log(avctx, AV_LOG_ERROR, "Size %d invalid\n", 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;
@@ -1098,8 +1403,10 @@ int ff_alloc_packet(AVPacket *avpkt, int size)
void *destruct = avpkt->destruct;
#endif
- if (avpkt->size < size)
+ if (avpkt->size < size) {
+ av_log(avctx, AV_LOG_ERROR, "User packet is too small (%d < %d)\n", avpkt->size, size);
return AVERROR(EINVAL);
+ }
av_init_packet(avpkt);
#if FF_API_DESTRUCT_PACKET
@@ -1109,10 +1416,18 @@ int ff_alloc_packet(AVPacket *avpkt, int size)
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 %d\n", size);
+ return ret;
}
}
+int ff_alloc_packet(AVPacket *avpkt, int size)
+{
+ return ff_alloc_packet2(NULL, avpkt, size);
+}
+
/**
* Pad last frame with silence.
*/
@@ -1167,7 +1482,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;
@@ -1196,8 +1512,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) {
@@ -1210,6 +1528,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;
}
@@ -1230,9 +1549,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;
}
@@ -1262,16 +1602,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 */
+ ff_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);
@@ -1285,14 +1747,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;
}
@@ -1302,6 +1786,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;
@@ -1315,13 +1801,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;
@@ -1364,19 +1881,46 @@ 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;
+ while (side_metadata < end) {
+ const uint8_t *key = side_metadata;
+ const uint8_t *val = side_metadata + strlen(key) + 1;
+ int 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->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);
@@ -1384,24 +1928,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) {
+ ff_packet_free_side_data(&tmp);
+ if(ret == tmp.size)
+ ret = avpkt->size;
+ }
+
if (ret < 0 && picture->data[0])
av_frame_unref(picture);
@@ -1413,6 +1973,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;
@@ -1424,10 +1988,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;
@@ -1435,14 +2048,14 @@ 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->type != AVMEDIA_TYPE_AUDIO) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid media type for audio\n");
+ return AVERROR(EINVAL);
+ }
avcodec_get_frame_defaults(frame);
@@ -1450,13 +2063,76 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
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);
+ uint8_t *side;
+ int side_size;
+ // 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;
+ ret = avctx->codec->decode(avctx, frame, got_frame_ptr, &tmp);
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);
+ }
+ 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;
+ }
+ }
+ avctx->pkt = NULL;
+ if (did_split) {
+ ff_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;
@@ -1471,25 +2147,167 @@ 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)
+ 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 (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 (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);
+ }
+ sub->format = !(avctx->codec_descriptor->props & AV_CODEC_PROP_BITMAP_SUB);
+ avctx->pkt = NULL;
+ }
+
+ if (did_split) {
+ ff_packet_free_side_data(&tmp);
+ if(ret == tmp.size)
+ ret = avpkt->size;
+ }
+
+ if (*got_sub_ptr)
+ avctx->frame_number++;
+ }
+
return ret;
}
@@ -1512,29 +2330,40 @@ void avsubtitle_free(AVSubtitle *sub)
memset(sub, 0, sizeof(AVSubtitle));
}
-av_cold int avcodec_close(AVCodecContext *avctx)
+av_cold int ff_codec_close_recursive(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 = 0;
- 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;
- }
+ ff_unlock_avcodec();
+
+ ret = avcodec_close(avctx);
+
+ ff_lock_avcodec(NULL);
+ return ret;
+}
+
+av_cold int avcodec_close(AVCodecContext *avctx)
+{
+ int 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++)
@@ -1551,19 +2380,28 @@ 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;
+ 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) {
@@ -1615,27 +2453,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)
@@ -1645,7 +2480,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,
@@ -1660,49 +2495,53 @@ 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) {
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)
+ snprintf(buf + strlen(buf), buf_size - strlen(buf),
+ " (%d bpc)", enc->bits_per_raw_sample);
}
if (enc->width) {
snprintf(buf + strlen(buf), buf_size - strlen(buf),
@@ -1714,7 +2553,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);
}
@@ -1731,12 +2570,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);
@@ -1749,16 +2582,15 @@ 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);
- 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 (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;
default:
- snprintf(buf, buf_size, "Invalid Codec type %d", enc->codec_type);
return;
}
if (encode) {
@@ -1791,18 +2623,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,14 +2655,20 @@ void avcodec_flush_buffers(AVCodecContext *avctx)
ff_thread_flush(avctx);
else if (avctx->codec->flush)
avctx->codec->flush(avctx);
+
+ avctx->pts_correction_last_pts =
+ avctx->pts_correction_last_dts = INT64_MIN;
}
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:
@@ -1826,10 +2676,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:
@@ -1838,11 +2690,13 @@ int av_get_exact_bits_per_sample(enum AVCodecID codec_id)
case AV_CODEC_ID_PCM_S24DAUD:
case AV_CODEC_ID_PCM_S24BE:
case AV_CODEC_ID_PCM_S24LE:
+ case AV_CODEC_ID_PCM_S24LE_PLANAR:
case AV_CODEC_ID_PCM_U24BE:
case AV_CODEC_ID_PCM_U24LE:
return 24;
case AV_CODEC_ID_PCM_S32BE:
case AV_CODEC_ID_PCM_S32LE:
+ case AV_CODEC_ID_PCM_S32LE_PLANAR:
case AV_CODEC_ID_PCM_U32BE:
case AV_CODEC_ID_PCM_U32LE:
case AV_CODEC_ID_PCM_F32BE:
@@ -1856,6 +2710,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) {
@@ -1886,8 +2761,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 */
@@ -1896,11 +2771,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;
@@ -1946,6 +2820,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 */
@@ -1956,6 +2834,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;
@@ -1977,6 +2859,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) {
@@ -1999,6 +2884,8 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
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);
}
@@ -2008,8 +2895,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;
@@ -2053,7 +2944,7 @@ int ff_match_2uint16(const uint16_t(*tab)[2], int size, int a, int b)
#if FF_API_MISSING_SAMPLE
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);
@@ -2070,8 +2961,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);
}
@@ -2124,6 +3015,36 @@ 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");
+ 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) {
@@ -2171,6 +3092,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;
@@ -2194,10 +3120,21 @@ void ff_thread_await_progress(ThreadFrame *f, int progress, int field)
{
}
+int ff_thread_can_start_frame(AVCodecContext *avctx)
+{
+ return 1;
+}
+
#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)
@@ -2215,9 +3152,27 @@ 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;
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 cf9d2d8..4efad1e 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
*/
@@ -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 0df3fb7..acb25c3 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
*/
@@ -417,7 +417,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.
@@ -515,15 +515,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 b8b647e..42e25cc 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;
@@ -106,12 +151,28 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
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",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_V210,
+ .priv_data_size = sizeof(V210DecContext),
.init = decode_init,
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"),
+ .priv_class = &v210dec_class,
};
diff --git a/libavcodec/v210dec.h b/libavcodec/v210dec.h
new file mode 100644
index 0000000..e1e3d32
--- /dev/null
+++ b/libavcodec/v210dec.h
@@ -0,0 +1,36 @@
+/*
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_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 ad8a4a5..5527686 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 75eb008..e4d5460 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..75d65e8
--- /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",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_V308,
+ .init = v308_decode_init,
+ .decode = v308_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:4:4"),
+};
diff --git a/libavcodec/v308enc.c b/libavcodec/v308enc.c
new file mode 100644
index 0000000..10437cc
--- /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",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:4:4"),
+};
diff --git a/libavcodec/v408dec.c b/libavcodec/v408dec.c
new file mode 100644
index 0000000..751650d
--- /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",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_AYUV,
+ .init = v408_decode_init,
+ .decode = v408_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed MS 4:4:4:4"),
+};
+#endif
+#if CONFIG_V408_DECODER
+AVCodec ff_v408_decoder = {
+ .name = "v408",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_V408,
+ .init = v408_decode_init,
+ .decode = v408_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed QT 4:4:4:4"),
+};
+#endif
diff --git a/libavcodec/v408enc.c b/libavcodec/v408enc.c
new file mode 100644
index 0000000..694bdbf
--- /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",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed MS 4:4:4:4"),
+};
+#endif
+#if CONFIG_V408_ENCODER
+AVCodec ff_v408_encoder = {
+ .name = "v408",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed QT 4:4:4:4"),
+};
+#endif
diff --git a/libavcodec/v410dec.c b/libavcodec/v410dec.c
index e4b2a7d..f8229e2 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 7bb70fd..9661c7c 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..a220a9d 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
*/
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_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..bcc0eba 100644
--- a/libavcodec/vaapi_mpeg4.c
+++ b/libavcodec/vaapi_mpeg4.c
@@ -3,20 +3,20 @@
*
* Copyright (C) 2008-2009 Splitted-Desktop Systems
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -124,7 +124,7 @@ static int vaapi_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer
/* 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
+ * a single slice param. So fake macroblock_number for FFmpeg so
* that we don't call vaapi_mpeg4_decode_slice() again
*/
if (avctx->codec->id == AV_CODEC_ID_H263)
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 df0fef9..29cd104 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 6cd2dfc..cbb2ffc 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 23012cd..e4b62fe 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))) {
@@ -571,7 +578,7 @@ int ff_vc1_decode_entry_point(AVCodecContext *avctx, VC1Context *v, GetBitContex
}
/* fill lookup tables for intensity compensation */
-#define INIT_LUT(lumscale, lumshift, luty, lutuv) do { \
+#define INIT_LUT(lumscale, lumshift, luty, lutuv, chain) do { \
int scale, shift, i; \
if (!lumscale) { \
scale = -64; \
@@ -586,17 +593,45 @@ int ff_vc1_decode_entry_point(AVCodecContext *avctx, VC1Context *v, GetBitContex
shift = lumshift << 6; \
} \
for (i = 0; i < 256; i++) { \
- luty[i] = av_clip_uint8((scale * i + shift + 32) >> 6); \
- lutuv[i] = av_clip_uint8((scale * (i - 128) + 128*64 + 32) >> 6); \
+ int iy = chain ? luty[i] : i; \
+ int iu = chain ? lutuv[i] : i; \
+ luty[i] = av_clip_uint8((scale * iy + shift + 32) >> 6); \
+ lutuv[i] = av_clip_uint8((scale * (iu - 128) + 128*64 + 32) >> 6);\
} \
} while(0)
+
+static void rotate_luts(VC1Context *v)
+{
+#define ROTATE(DEF, L, N, C, A) do {\
+ if (v->s.pict_type == AV_PICTURE_TYPE_BI || v->s.pict_type == AV_PICTURE_TYPE_B) {\
+ C = A;\
+ } else {\
+ DEF;\
+ memcpy(&tmp, &L , sizeof(tmp));\
+ memcpy(&L , &N , sizeof(tmp));\
+ memcpy(&N , &tmp, sizeof(tmp));\
+ C = N;\
+ }\
+ }while(0)
+
+ ROTATE(int tmp , v->last_use_ic, v->next_use_ic, v->curr_use_ic, v->aux_use_ic);
+ ROTATE(uint8_t tmp[2][256], v->last_luty , v->next_luty , v->curr_luty , v->aux_luty);
+ ROTATE(uint8_t tmp[2][256], v->last_lutuv, v->next_lutuv, v->curr_lutuv, v->aux_lutuv);
+
+ INIT_LUT(32, 0 , v->curr_luty[0] , v->curr_lutuv[0] , 0);
+ INIT_LUT(32, 0 , v->curr_luty[1] , v->curr_lutuv[1] , 0);
+ v->curr_use_ic = 0;
+}
+
int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
{
int pqindex, lowquant, status;
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 =
@@ -677,8 +712,9 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
(v->s.pict_type == AV_PICTURE_TYPE_P) ? 'P' : ((v->s.pict_type == AV_PICTURE_TYPE_I) ? 'I' : 'B'),
pqindex, v->pq, v->halfpq, v->rangeredfrm);
- if (v->s.pict_type == AV_PICTURE_TYPE_I || v->s.pict_type == AV_PICTURE_TYPE_P)
- v->use_ic = 0;
+ if(v->first_pic_header_flag) {
+ rotate_luts(v);
+ }
switch (v->s.pict_type) {
case AV_PICTURE_TYPE_P:
@@ -692,9 +728,10 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
v->mv_mode2 = ff_vc1_mv_pmode_table2[lowquant][get_unary(gb, 1, 3)];
v->lumscale = get_bits(gb, 6);
v->lumshift = get_bits(gb, 6);
- v->use_ic = 1;
+ v->last_use_ic = 1;
/* fill lookup tables for intensity compensation */
- INIT_LUT(v->lumscale, v->lumshift, v->luty, v->lutuv);
+ INIT_LUT(v->lumscale, v->lumshift , v->last_luty[0] , v->last_lutuv[0] , 1);
+ INIT_LUT(v->lumscale, v->lumshift , v->last_luty[1] , v->last_lutuv[1] , 1);
}
v->qs_last = v->s.quarter_sample;
if (v->mv_mode == MV_PMODE_1MV_HPEL || v->mv_mode == MV_PMODE_1MV_HPEL_BILIN)
@@ -812,8 +849,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;
@@ -828,9 +868,6 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
if (fcm) {
if (fcm == ILACE_FIELD)
field_mode = 1;
- if (!v->warn_interlaced++)
- av_log(v->s.avctx, AV_LOG_ERROR,
- "Interlaced frames/fields support is incomplete\n");
}
} else {
fcm = PROGRESSIVE;
@@ -874,6 +911,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");
@@ -885,6 +924,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;
@@ -942,12 +983,13 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
if (v->postprocflag)
v->postproc = get_bits(gb, 2);
- if (v->s.pict_type == AV_PICTURE_TYPE_I || v->s.pict_type == AV_PICTURE_TYPE_P)
- v->use_ic = 0;
-
if (v->parse_only)
return 0;
+ if(v->first_pic_header_flag) {
+ rotate_luts(v);
+ }
+
switch (v->s.pict_type) {
case AV_PICTURE_TYPE_I:
case AV_PICTURE_TYPE_BI:
@@ -998,7 +1040,9 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
if (v->intcomp) {
v->lumscale = get_bits(gb, 6);
v->lumshift = get_bits(gb, 6);
- INIT_LUT(v->lumscale, v->lumshift, v->luty, v->lutuv);
+ INIT_LUT(v->lumscale, v->lumshift, v->last_luty[0], v->last_lutuv[0], 1);
+ INIT_LUT(v->lumscale, v->lumshift, v->last_luty[1], v->last_lutuv[1], 1);
+ v->last_use_ic = 1;
}
status = bitplane_decoding(v->s.mbskip_table, &v->skip_is_raw, v);
av_log(v->s.avctx, AV_LOG_DEBUG, "SKIPMB plane encoding: "
@@ -1041,17 +1085,38 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
int mvmode2;
mvmode2 = get_unary(gb, 1, 3);
v->mv_mode2 = ff_vc1_mv_pmode_table2[lowquant][mvmode2];
- if (v->field_mode)
- v->intcompfield = decode210(gb);
- v->lumscale = get_bits(gb, 6);
- v->lumshift = get_bits(gb, 6);
- INIT_LUT(v->lumscale, v->lumshift, v->luty, v->lutuv);
- if ((v->field_mode) && !v->intcompfield) {
+ if (v->field_mode) {
+ v->intcompfield = decode210(gb)^3;
+ } else
+ v->intcompfield = 3;
+
+ v->lumscale2 = v->lumscale = 32;
+ v->lumshift2 = v->lumshift = 0;
+ if (v->intcompfield & 1) {
+ v->lumscale = get_bits(gb, 6);
+ v->lumshift = get_bits(gb, 6);
+ }
+ if ((v->intcompfield & 2) && v->field_mode) {
v->lumscale2 = get_bits(gb, 6);
v->lumshift2 = get_bits(gb, 6);
- INIT_LUT(v->lumscale2, v->lumshift2, v->luty2, v->lutuv2);
+ } else if(!v->field_mode) {
+ v->lumscale2 = v->lumscale;
+ v->lumshift2 = v->lumshift;
+ }
+ if (v->field_mode && v->second_field) {
+ if (v->cur_field_type) {
+ INIT_LUT(v->lumscale , v->lumshift , v->curr_luty[v->cur_field_type^1], v->curr_lutuv[v->cur_field_type^1], 0);
+ INIT_LUT(v->lumscale2, v->lumshift2, v->last_luty[v->cur_field_type ], v->last_lutuv[v->cur_field_type ], 1);
+ } else {
+ INIT_LUT(v->lumscale2, v->lumshift2, v->curr_luty[v->cur_field_type^1], v->curr_lutuv[v->cur_field_type^1], 0);
+ INIT_LUT(v->lumscale , v->lumshift , v->last_luty[v->cur_field_type ], v->last_lutuv[v->cur_field_type ], 1);
+ }
+ v->next_use_ic = v->curr_use_ic = 1;
+ } else {
+ INIT_LUT(v->lumscale , v->lumshift , v->last_luty[0], v->last_lutuv[0], 1);
+ INIT_LUT(v->lumscale2, v->lumshift2, v->last_luty[1], v->last_lutuv[1], 1);
}
- v->use_ic = 1;
+ v->last_use_ic = 1;
}
v->qs_last = v->s.quarter_sample;
if (v->mv_mode == MV_PMODE_1MV_HPEL || v->mv_mode == MV_PMODE_1MV_HPEL_BILIN)
@@ -1134,7 +1199,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);
@@ -1154,6 +1218,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 88980d4..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)
@@ -298,8 +296,11 @@ typedef struct VC1Context{
int dmb_is_raw; ///< direct mb plane is raw
int fmb_is_raw; ///< forward mb plane is raw
int skip_is_raw; ///< skip mb plane is not coded
- uint8_t luty[256], lutuv[256]; ///< lookup tables used for intensity compensation
- int use_ic; ///< use intensity compensation in B-frames
+ uint8_t last_luty[2][256], last_lutuv[2][256]; ///< lookup tables used for intensity compensation
+ uint8_t aux_luty[2][256], aux_lutuv[2][256]; ///< lookup tables used for intensity compensation
+ uint8_t next_luty[2][256], next_lutuv[2][256]; ///< lookup tables used for intensity compensation
+ uint8_t (*curr_luty)[256] ,(*curr_lutuv)[256];
+ int last_use_ic, curr_use_ic, next_use_ic, aux_use_ic;
int rnd; ///< rounding control
/** Frame decoding info for S/M profiles only */
@@ -342,7 +343,6 @@ typedef struct VC1Context{
int intcomp;
uint8_t lumscale2; ///< for interlaced field P picture
uint8_t lumshift2;
- uint8_t luty2[256], lutuv2[256]; // lookup tables used for intensity compensation
VLC* mbmode_vlc;
VLC* imv_vlc;
VLC* twomvbp_vlc;
@@ -351,10 +351,9 @@ 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_last_base, *mv_f_last[2];
uint8_t *mv_f_next_base, *mv_f_next[2];
int field_mode; ///< 1 for interlaced field pictures
int fptype;
@@ -400,8 +399,6 @@ typedef struct VC1Context{
int end_mb_x; ///< Horizontal macroblock limit (used only by mss2)
int parse_only; ///< Context is used within parser
-
- int warn_interlaced;
} VC1Context;
/** Find VC-1 marker in buffer
diff --git a/libavcodec/vc1_parser.c b/libavcodec/vc1_parser.c
index 1bedd98..0438b30 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
*/
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 ea08bdd..4cdf470 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
*/
@@ -39,6 +39,7 @@
#include "unary.h"
#include "mathops.h"
#include "vdpau_internal.h"
+#include "libavutil/avassert.h"
#undef NDEBUG
#include <assert.h>
@@ -347,6 +348,9 @@ static void vc1_mc_1mv(VC1Context *v, int dir)
uint8_t *srcY, *srcU, *srcV;
int dxy, mx, my, uvmx, uvmy, src_x, src_y, uvsrc_x, uvsrc_y;
int v_edge_pos = s->v_edge_pos >> v->field_mode;
+ int i;
+ uint8_t (*luty)[256], (*lutuv)[256];
+ int use_ic;
if ((!v->field_mode ||
(v->ref_field_type[dir] == 1 && v->cur_field_type == 1)) &&
@@ -358,8 +362,10 @@ static void vc1_mc_1mv(VC1Context *v, int dir)
// store motion vectors for further use in B frames
if (s->pict_type == AV_PICTURE_TYPE_P) {
- s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][0] = mx;
- s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][1] = my;
+ for (i = 0; i < 4; i++) {
+ s->current_picture.motion_val[1][s->block_index[i] + v->blocks_off][0] = mx;
+ s->current_picture.motion_val[1][s->block_index[i] + v->blocks_off][1] = my;
+ }
}
uvmx = (mx + ((mx & 3) == 3)) >> 1;
@@ -383,17 +389,29 @@ static void vc1_mc_1mv(VC1Context *v, int dir)
srcY = s->current_picture.f.data[0];
srcU = s->current_picture.f.data[1];
srcV = s->current_picture.f.data[2];
+ luty = v->curr_luty;
+ lutuv= v->curr_lutuv;
+ use_ic=v->curr_use_ic;
} else {
srcY = s->last_picture.f.data[0];
srcU = s->last_picture.f.data[1];
srcV = s->last_picture.f.data[2];
+ luty = v->last_luty ;
+ lutuv= v->last_lutuv;
+ use_ic=v->last_use_ic;
}
} else {
srcY = s->next_picture.f.data[0];
srcU = s->next_picture.f.data[1];
srcV = s->next_picture.f.data[2];
+ luty = v->next_luty ;
+ lutuv= v->next_lutuv;
+ use_ic=v->next_use_ic;
}
+ if(!srcY)
+ return;
+
src_x = s->mb_x * 16 + (mx >> 2);
src_y = s->mb_y * 16 + (my >> 2);
uvsrc_x = s->mb_x * 8 + (uvmx >> 2);
@@ -427,7 +445,7 @@ static void vc1_mc_1mv(VC1Context *v, int dir)
srcV = s->edge_emu_buffer + 18 * s->linesize;
}
- if (v->rangeredfrm || (v->mv_mode == MV_PMODE_INTENSITY_COMP)
+ if (v->rangeredfrm || use_ic
|| s->h_edge_pos < 22 || v_edge_pos < 22
|| (unsigned)(src_x - s->mspel) > s->h_edge_pos - (mx&3) - 16 - s->mspel * 3
|| (unsigned)(src_y - 1) > v_edge_pos - (my&3) - 16 - 3) {
@@ -468,22 +486,24 @@ static void vc1_mc_1mv(VC1Context *v, int dir)
}
}
/* if we deal with intensity compensation we need to scale source blocks */
- if (v->mv_mode == MV_PMODE_INTENSITY_COMP) {
+ if (use_ic) {
int i, j;
uint8_t *src, *src2;
src = srcY;
for (j = 0; j < 17 + s->mspel * 2; j++) {
+ int f = v->field_mode ? v->ref_field_type[dir] : ((j + src_y - s->mspel)&1) ;
for (i = 0; i < 17 + s->mspel * 2; i++)
- src[i] = v->luty[src[i]];
+ src[i] = luty[f][src[i]];
src += s->linesize;
}
src = srcU;
src2 = srcV;
for (j = 0; j < 9; j++) {
+ int f = v->field_mode ? v->ref_field_type[dir] : ((j + uvsrc_y)&1);
for (i = 0; i < 9; i++) {
- src[i] = v->lutuv[src[i]];
- src2[i] = v->lutuv[src2[i]];
+ src[i] = lutuv[f][src[i]];
+ src2[i] = lutuv[f][src2[i]];
}
src += s->uvlinesize;
src2 += s->uvlinesize;
@@ -533,7 +553,7 @@ static inline int median4(int a, int b, int c, int d)
/** Do motion compensation for 4-MV macroblock - luminance block
*/
-static void vc1_mc_4mv_luma(VC1Context *v, int n, int dir)
+static void vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg)
{
MpegEncContext *s = &v->s;
uint8_t *srcY;
@@ -541,6 +561,8 @@ static void vc1_mc_4mv_luma(VC1Context *v, int n, int dir)
int off;
int fieldmv = (v->fcm == ILACE_FRAME) ? v->blk_mv_type[s->block_index[n]] : 0;
int v_edge_pos = s->v_edge_pos >> v->field_mode;
+ uint8_t (*luty)[256];
+ int use_ic;
if ((!v->field_mode ||
(v->ref_field_type[dir] == 1 && v->cur_field_type == 1)) &&
@@ -553,10 +575,21 @@ static void vc1_mc_4mv_luma(VC1Context *v, int n, int dir)
if (!dir) {
if (v->field_mode && (v->cur_field_type != v->ref_field_type[dir]) && v->second_field) {
srcY = s->current_picture.f.data[0];
- } else
+ luty = v->curr_luty;
+ use_ic=v->curr_use_ic;
+ } else {
srcY = s->last_picture.f.data[0];
- } else
+ luty = v->last_luty;
+ use_ic=v->last_use_ic;
+ }
+ } else {
srcY = s->next_picture.f.data[0];
+ luty = v->next_luty;
+ use_ic=v->next_use_ic;
+ }
+
+ if(!srcY)
+ return;
if (v->field_mode) {
if (v->cur_field_type != v->ref_field_type[dir])
@@ -590,6 +623,8 @@ static void vc1_mc_4mv_luma(VC1Context *v, int n, int dir)
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_assert2(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;
@@ -601,6 +636,10 @@ static void vc1_mc_4mv_luma(VC1Context *v, int n, int dir)
int qx, qy;
int width = s->avctx->coded_width;
int height = s->avctx->coded_height >> 1;
+ if (s->pict_type == AV_PICTURE_TYPE_P) {
+ s->current_picture.motion_val[1][s->block_index[n] + v->blocks_off][0] = mx;
+ s->current_picture.motion_val[1][s->block_index[n] + v->blocks_off][1] = my;
+ }
qx = (s->mb_x * 16) + (mx >> 2);
qy = (s->mb_y * 8) + (my >> 3);
@@ -648,7 +687,7 @@ static void vc1_mc_4mv_luma(VC1Context *v, int n, int dir)
v_edge_pos--;
if (fieldmv && (src_y & 1) && src_y < 4)
src_y--;
- if (v->rangeredfrm || (v->mv_mode == MV_PMODE_INTENSITY_COMP)
+ if (v->rangeredfrm || use_ic
|| s->h_edge_pos < 13 || v_edge_pos < 23
|| (unsigned)(src_x - s->mspel) > s->h_edge_pos - (mx & 3) - 8 - s->mspel * 2
|| (unsigned)(src_y - (s->mspel << fieldmv)) > v_edge_pos - (my & 3) - ((8 + s->mspel * 2) << fieldmv)) {
@@ -672,14 +711,15 @@ static void vc1_mc_4mv_luma(VC1Context *v, int n, int dir)
}
}
/* if we deal with intensity compensation we need to scale source blocks */
- if (v->mv_mode == MV_PMODE_INTENSITY_COMP) {
+ if (use_ic) {
int i, j;
uint8_t *src;
src = srcY;
for (j = 0; j < 9 + s->mspel * 2; j++) {
+ int f = v->field_mode ? v->ref_field_type[dir] : (((j<<fieldmv)+src_y - (s->mspel << fieldmv))&1);
for (i = 0; i < 9 + s->mspel * 2; i++)
- src[i] = v->luty[src[i]];
+ src[i] = luty[f][src[i]];
src += s->linesize << fieldmv;
}
}
@@ -688,7 +728,10 @@ static void vc1_mc_4mv_luma(VC1Context *v, int n, int dir)
if (s->mspel) {
dxy = ((my & 3) << 2) | (mx & 3);
- v->vc1dsp.put_vc1_mspel_pixels_tab[dxy](s->dest[0] + off, srcY, s->linesize << fieldmv, v->rnd);
+ if (avg)
+ v->vc1dsp.avg_vc1_mspel_pixels_tab[dxy](s->dest[0] + off, srcY, s->linesize << fieldmv, v->rnd);
+ else
+ v->vc1dsp.put_vc1_mspel_pixels_tab[dxy](s->dest[0] + off, srcY, s->linesize << fieldmv, v->rnd);
} else { // hpel mc - always used for luma
dxy = (my & 2) | ((mx & 2) >> 1);
if (!v->rnd)
@@ -764,6 +807,8 @@ static void vc1_mc_4mv_chroma(VC1Context *v, int dir)
int valid_count;
int chroma_ref_type = v->cur_field_type;
int v_edge_pos = s->v_edge_pos >> v->field_mode;
+ uint8_t (*lutuv)[256];
+ int use_ic;
if (!v->field_mode && !v->s.last_picture.f.data[0])
return;
@@ -829,15 +874,24 @@ static void vc1_mc_4mv_chroma(VC1Context *v, int dir)
if (v->field_mode && (v->cur_field_type != chroma_ref_type) && v->second_field) {
srcU = s->current_picture.f.data[1];
srcV = s->current_picture.f.data[2];
+ lutuv= v->curr_lutuv;
+ use_ic=v->curr_use_ic;
} else {
srcU = s->last_picture.f.data[1];
srcV = s->last_picture.f.data[2];
+ lutuv= v->last_lutuv;
+ use_ic=v->last_use_ic;
}
} else {
srcU = s->next_picture.f.data[1];
srcV = s->next_picture.f.data[2];
+ lutuv= v->next_lutuv;
+ use_ic=v->next_use_ic;
}
+ if(!srcU)
+ return;
+
srcU += uvsrc_y * s->uvlinesize + uvsrc_x;
srcV += uvsrc_y * s->uvlinesize + uvsrc_x;
@@ -848,7 +902,7 @@ static void vc1_mc_4mv_chroma(VC1Context *v, int dir)
}
}
- if (v->rangeredfrm || (v->mv_mode == MV_PMODE_INTENSITY_COMP)
+ if (v->rangeredfrm || use_ic
|| 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) {
@@ -878,16 +932,17 @@ static void vc1_mc_4mv_chroma(VC1Context *v, int dir)
}
}
/* if we deal with intensity compensation we need to scale source blocks */
- if (v->mv_mode == MV_PMODE_INTENSITY_COMP) {
+ if (use_ic) {
int i, j;
uint8_t *src, *src2;
src = srcU;
src2 = srcV;
for (j = 0; j < 9; j++) {
+ int f = v->field_mode ? chroma_ref_type : ((j + uvsrc_y)&1);
for (i = 0; i < 9; i++) {
- src[i] = v->lutuv[src[i]];
- src2[i] = v->lutuv[src2[i]];
+ src[i] = lutuv[f][src[i]];
+ src2[i] = lutuv[f][src2[i]];
}
src += s->uvlinesize;
src2 += s->uvlinesize;
@@ -907,9 +962,9 @@ static void vc1_mc_4mv_chroma(VC1Context *v, int dir)
}
}
-/** Do motion compensation for 4-MV field chroma macroblock (both U and V)
+/** Do motion compensation for 4-MV interlaced frame chroma macroblock (both U and V)
*/
-static void vc1_mc_4mv_chroma4(VC1Context *v)
+static void vc1_mc_4mv_chroma4(VC1Context *v, int dir, int dir2, int avg)
{
MpegEncContext *s = &v->s;
H264ChromaContext *h264chroma = &v->h264chroma;
@@ -921,16 +976,17 @@ static void vc1_mc_4mv_chroma4(VC1Context *v)
static const int s_rndtblfield[16] = { 0, 0, 1, 2, 4, 4, 5, 6, 2, 2, 3, 8, 6, 6, 7, 12 };
int v_dist = fieldmv ? 1 : 4; // vertical offset for lower sub-blocks
int v_edge_pos = s->v_edge_pos >> 1;
+ int use_ic;
+ uint8_t (*lutuv)[256];
- if (!v->s.last_picture.f.data[0])
- return;
if (s->flags & CODEC_FLAG_GRAY)
return;
for (i = 0; i < 4; i++) {
- tx = s->mv[0][i][0];
+ int d = i<2 ? dir: dir2;
+ tx = s->mv[d][i][0];
uvmx_field[i] = (tx + ((tx & 3) == 3)) >> 1;
- ty = s->mv[0][i][1];
+ ty = s->mv[d][i][1];
if (fieldmv)
uvmy_field[i] = (ty >> 4) * 8 + s_rndtblfield[ty & 0xF];
else
@@ -944,16 +1000,26 @@ static void vc1_mc_4mv_chroma4(VC1Context *v)
// FIXME: implement proper pull-back (see vc1cropmv.c, vc1CROPMV_ChromaPullBack())
uvsrc_x = av_clip(uvsrc_x, -8, s->avctx->coded_width >> 1);
uvsrc_y = av_clip(uvsrc_y, -8, s->avctx->coded_height >> 1);
- 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;
+ 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;
+ 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;
+ lutuv = v->last_lutuv;
+ use_ic = v->last_use_ic;
+ }
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 ((v->mv_mode == MV_PMODE_INTENSITY_COMP)
+ 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)) {
@@ -967,22 +1033,32 @@ static void vc1_mc_4mv_chroma4(VC1Context *v)
srcV = s->edge_emu_buffer + 16;
/* if we deal with intensity compensation we need to scale source blocks */
- if (v->mv_mode == MV_PMODE_INTENSITY_COMP) {
+ if (use_ic) {
int i, j;
uint8_t *src, *src2;
src = srcU;
src2 = srcV;
for (j = 0; j < 5; j++) {
+ int f = (uvsrc_y + (j<<fieldmv))&1;
for (i = 0; i < 5; i++) {
- src[i] = v->lutuv[src[i]];
- src2[i] = v->lutuv[src2[i]];
+ src[i] = lutuv[f][src[i]];
+ src2[i] = lutuv[f][src2[i]];
}
- src += s->uvlinesize << 1;
- src2 += s->uvlinesize << 1;
+ src += s->uvlinesize << fieldmv;
+ src2 += s->uvlinesize << fieldmv;
}
}
}
+ if (avg) {
+ if (!v->rnd) {
+ h264chroma->avg_h264_chroma_pixels_tab[1](s->dest[1] + off, srcU, s->uvlinesize << fieldmv, 4, uvmx_field[i], uvmy_field[i]);
+ h264chroma->avg_h264_chroma_pixels_tab[1](s->dest[2] + off, srcV, s->uvlinesize << fieldmv, 4, uvmx_field[i], uvmy_field[i]);
+ } else {
+ v->vc1dsp.avg_no_rnd_vc1_chroma_pixels_tab[1](s->dest[1] + off, srcU, s->uvlinesize << fieldmv, 4, uvmx_field[i], uvmy_field[i]);
+ v->vc1dsp.avg_no_rnd_vc1_chroma_pixels_tab[1](s->dest[2] + off, srcV, s->uvlinesize << fieldmv, 4, uvmx_field[i], uvmy_field[i]);
+ }
+ } else {
if (!v->rnd) {
h264chroma->put_h264_chroma_pixels_tab[1](s->dest[1] + off, srcU, s->uvlinesize << fieldmv, 4, uvmx_field[i], uvmy_field[i]);
h264chroma->put_h264_chroma_pixels_tab[1](s->dest[2] + off, srcV, s->uvlinesize << fieldmv, 4, uvmx_field[i], uvmy_field[i]);
@@ -990,6 +1066,7 @@ static void vc1_mc_4mv_chroma4(VC1Context *v)
v->vc1dsp.put_no_rnd_vc1_chroma_pixels_tab[1](s->dest[1] + off, srcU, s->uvlinesize << fieldmv, 4, uvmx_field[i], uvmy_field[i]);
v->vc1dsp.put_no_rnd_vc1_chroma_pixels_tab[1](s->dest[2] + off, srcV, s->uvlinesize << fieldmv, 4, uvmx_field[i], uvmy_field[i]);
}
+ }
}
}
@@ -1126,6 +1203,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
@@ -1583,7 +1661,7 @@ static inline void vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y,
/** Predict and set motion vector for interlaced frame picture MBs
*/
static inline void vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y,
- int mvn, int r_x, int r_y, uint8_t* is_intra)
+ int mvn, int r_x, int r_y, uint8_t* is_intra, int dir)
{
MpegEncContext *s = &v->s;
int xy, wrap, off = 0;
@@ -1625,14 +1703,14 @@ static inline void vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y,
if (s->mb_x || (n == 1) || (n == 3)) {
if ((v->blk_mv_type[xy]) // current block (MB) has a field MV
|| (!v->blk_mv_type[xy] && !v->blk_mv_type[xy - 1])) { // or both have frame MV
- A[0] = s->current_picture.motion_val[0][xy - 1][0];
- A[1] = s->current_picture.motion_val[0][xy - 1][1];
+ A[0] = s->current_picture.motion_val[dir][xy - 1][0];
+ A[1] = s->current_picture.motion_val[dir][xy - 1][1];
a_valid = 1;
} else { // current block has frame mv and cand. has field MV (so average)
- A[0] = (s->current_picture.motion_val[0][xy - 1][0]
- + s->current_picture.motion_val[0][xy - 1 + off * wrap][0] + 1) >> 1;
- A[1] = (s->current_picture.motion_val[0][xy - 1][1]
- + s->current_picture.motion_val[0][xy - 1 + off * wrap][1] + 1) >> 1;
+ A[0] = (s->current_picture.motion_val[dir][xy - 1][0]
+ + s->current_picture.motion_val[dir][xy - 1 + off * wrap][0] + 1) >> 1;
+ A[1] = (s->current_picture.motion_val[dir][xy - 1][1]
+ + s->current_picture.motion_val[dir][xy - 1 + off * wrap][1] + 1) >> 1;
a_valid = 1;
}
if (!(n & 1) && v->is_intra[s->mb_x - 1]) {
@@ -1652,11 +1730,11 @@ static inline void vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y,
if (v->blk_mv_type[pos_b] && v->blk_mv_type[xy]) {
n_adj = (n & 2) | (n & 1);
}
- B[0] = s->current_picture.motion_val[0][s->block_index[n_adj] - 2 * wrap][0];
- B[1] = s->current_picture.motion_val[0][s->block_index[n_adj] - 2 * wrap][1];
+ B[0] = s->current_picture.motion_val[dir][s->block_index[n_adj] - 2 * wrap][0];
+ B[1] = s->current_picture.motion_val[dir][s->block_index[n_adj] - 2 * wrap][1];
if (v->blk_mv_type[pos_b] && !v->blk_mv_type[xy]) {
- B[0] = (B[0] + s->current_picture.motion_val[0][s->block_index[n_adj ^ 2] - 2 * wrap][0] + 1) >> 1;
- B[1] = (B[1] + s->current_picture.motion_val[0][s->block_index[n_adj ^ 2] - 2 * wrap][1] + 1) >> 1;
+ B[0] = (B[0] + s->current_picture.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap][0] + 1) >> 1;
+ B[1] = (B[1] + s->current_picture.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap][1] + 1) >> 1;
}
}
if (s->mb_width > 1) {
@@ -1667,11 +1745,11 @@ static inline void vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y,
if (v->blk_mv_type[pos_c] && v->blk_mv_type[xy]) {
n_adj = n & 2;
}
- C[0] = s->current_picture.motion_val[0][s->block_index[n_adj] - 2 * wrap + 2][0];
- C[1] = s->current_picture.motion_val[0][s->block_index[n_adj] - 2 * wrap + 2][1];
+ C[0] = s->current_picture.motion_val[dir][s->block_index[n_adj] - 2 * wrap + 2][0];
+ C[1] = s->current_picture.motion_val[dir][s->block_index[n_adj] - 2 * wrap + 2][1];
if (v->blk_mv_type[pos_c] && !v->blk_mv_type[xy]) {
- C[0] = (1 + C[0] + (s->current_picture.motion_val[0][s->block_index[n_adj ^ 2] - 2 * wrap + 2][0])) >> 1;
- C[1] = (1 + C[1] + (s->current_picture.motion_val[0][s->block_index[n_adj ^ 2] - 2 * wrap + 2][1])) >> 1;
+ C[0] = (1 + C[0] + (s->current_picture.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap + 2][0])) >> 1;
+ C[1] = (1 + C[1] + (s->current_picture.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap + 2][1])) >> 1;
}
if (s->mb_x == s->mb_width - 1) {
if (!v->is_intra[s->mb_x - s->mb_stride - 1]) {
@@ -1681,11 +1759,11 @@ static inline void vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y,
if (v->blk_mv_type[pos_c] && v->blk_mv_type[xy]) {
n_adj = n | 1;
}
- C[0] = s->current_picture.motion_val[0][s->block_index[n_adj] - 2 * wrap - 2][0];
- C[1] = s->current_picture.motion_val[0][s->block_index[n_adj] - 2 * wrap - 2][1];
+ C[0] = s->current_picture.motion_val[dir][s->block_index[n_adj] - 2 * wrap - 2][0];
+ C[1] = s->current_picture.motion_val[dir][s->block_index[n_adj] - 2 * wrap - 2][1];
if (v->blk_mv_type[pos_c] && !v->blk_mv_type[xy]) {
- C[0] = (1 + C[0] + s->current_picture.motion_val[0][s->block_index[1] - 2 * wrap - 2][0]) >> 1;
- C[1] = (1 + C[1] + s->current_picture.motion_val[0][s->block_index[1] - 2 * wrap - 2][1]) >> 1;
+ C[0] = (1 + C[0] + s->current_picture.motion_val[dir][s->block_index[1] - 2 * wrap - 2][0]) >> 1;
+ C[1] = (1 + C[1] + s->current_picture.motion_val[dir][s->block_index[1] - 2 * wrap - 2][1]) >> 1;
}
} else
c_valid = 0;
@@ -1696,12 +1774,12 @@ static inline void vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y,
} else {
pos_b = s->block_index[1];
b_valid = 1;
- B[0] = s->current_picture.motion_val[0][pos_b][0];
- B[1] = s->current_picture.motion_val[0][pos_b][1];
+ B[0] = s->current_picture.motion_val[dir][pos_b][0];
+ B[1] = s->current_picture.motion_val[dir][pos_b][1];
pos_c = s->block_index[0];
c_valid = 1;
- C[0] = s->current_picture.motion_val[0][pos_c][0];
- C[1] = s->current_picture.motion_val[0][pos_c][1];
+ C[0] = s->current_picture.motion_val[dir][pos_c][0];
+ C[1] = s->current_picture.motion_val[dir][pos_c][1];
}
total_valid = a_valid + b_valid + c_valid;
@@ -1722,9 +1800,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]; }
+ if (a_valid) { px = A[0]; py = A[1]; }
+ else if (b_valid) { px = B[0]; py = B[1]; }
+ else if (c_valid) { px = C[0]; py = C[1]; }
+ else av_assert2(0);
} else
px = py = 0;
}
@@ -1779,7 +1858,7 @@ static inline void vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y,
} else if (c_valid) {
px = C[0];
py = C[1];
- }
+ } else px = py = 0;
}
} else if (total_valid == 1) {
px = (a_valid) ? A[0] : ((b_valid) ? B[0] : C[0]);
@@ -1789,20 +1868,20 @@ static inline void vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y,
}
/* store MV using signed modulus of MV range defined in 4.11 */
- s->mv[0][n][0] = s->current_picture.motion_val[0][xy][0] = ((px + dmv_x + r_x) & ((r_x << 1) - 1)) - r_x;
- s->mv[0][n][1] = s->current_picture.motion_val[0][xy][1] = ((py + dmv_y + r_y) & ((r_y << 1) - 1)) - r_y;
+ s->mv[dir][n][0] = s->current_picture.motion_val[dir][xy][0] = ((px + dmv_x + r_x) & ((r_x << 1) - 1)) - r_x;
+ s->mv[dir][n][1] = s->current_picture.motion_val[dir][xy][1] = ((py + dmv_y + r_y) & ((r_y << 1) - 1)) - r_y;
if (mvn == 1) { /* duplicate motion data for 1-MV block */
- s->current_picture.motion_val[0][xy + 1 ][0] = s->current_picture.motion_val[0][xy][0];
- s->current_picture.motion_val[0][xy + 1 ][1] = s->current_picture.motion_val[0][xy][1];
- s->current_picture.motion_val[0][xy + wrap ][0] = s->current_picture.motion_val[0][xy][0];
- s->current_picture.motion_val[0][xy + wrap ][1] = s->current_picture.motion_val[0][xy][1];
- s->current_picture.motion_val[0][xy + wrap + 1][0] = s->current_picture.motion_val[0][xy][0];
- s->current_picture.motion_val[0][xy + wrap + 1][1] = s->current_picture.motion_val[0][xy][1];
+ s->current_picture.motion_val[dir][xy + 1 ][0] = s->current_picture.motion_val[dir][xy][0];
+ s->current_picture.motion_val[dir][xy + 1 ][1] = s->current_picture.motion_val[dir][xy][1];
+ s->current_picture.motion_val[dir][xy + wrap ][0] = s->current_picture.motion_val[dir][xy][0];
+ s->current_picture.motion_val[dir][xy + wrap ][1] = s->current_picture.motion_val[dir][xy][1];
+ s->current_picture.motion_val[dir][xy + wrap + 1][0] = s->current_picture.motion_val[dir][xy][0];
+ s->current_picture.motion_val[dir][xy + wrap + 1][1] = s->current_picture.motion_val[dir][xy][1];
} else if (mvn == 2) { /* duplicate motion data for 2-Field MV block */
- s->current_picture.motion_val[0][xy + 1][0] = s->current_picture.motion_val[0][xy][0];
- s->current_picture.motion_val[0][xy + 1][1] = s->current_picture.motion_val[0][xy][1];
- s->mv[0][n + 1][0] = s->mv[0][n][0];
- s->mv[0][n + 1][1] = s->mv[0][n][1];
+ s->current_picture.motion_val[dir][xy + 1][0] = s->current_picture.motion_val[dir][xy][0];
+ s->current_picture.motion_val[dir][xy + 1][1] = s->current_picture.motion_val[dir][xy][1];
+ s->mv[dir][n + 1][0] = s->mv[dir][n][0];
+ s->mv[dir][n + 1][1] = s->mv[dir][n][1];
}
}
@@ -1816,6 +1895,7 @@ static void vc1_interp_mc(VC1Context *v)
int dxy, mx, my, uvmx, uvmy, src_x, src_y, uvsrc_x, uvsrc_y;
int off, off_uv;
int v_edge_pos = s->v_edge_pos >> v->field_mode;
+ int use_ic = v->next_use_ic;
if (!v->field_mode && !v->s.next_picture.f.data[0])
return;
@@ -1870,7 +1950,7 @@ static void vc1_interp_mc(VC1Context *v)
srcV = s->edge_emu_buffer + 18 * s->linesize;
}
- if (v->rangeredfrm || s->h_edge_pos < 22 || v_edge_pos < 22
+ if (v->rangeredfrm || s->h_edge_pos < 22 || v_edge_pos < 22 || use_ic
|| (unsigned)(src_x - 1) > s->h_edge_pos - (mx & 3) - 16 - 3
|| (unsigned)(src_y - 1) > v_edge_pos - (my & 3) - 16 - 3) {
uint8_t *uvbuf = s->edge_emu_buffer + 19 * s->linesize;
@@ -1909,6 +1989,32 @@ static void vc1_interp_mc(VC1Context *v)
src2 += s->uvlinesize;
}
}
+
+ if (use_ic) {
+ uint8_t (*luty )[256] = v->next_luty;
+ uint8_t (*lutuv)[256] = v->next_lutuv;
+ int i, j;
+ uint8_t *src, *src2;
+
+ src = srcY;
+ for (j = 0; j < 17 + s->mspel * 2; j++) {
+ int f = v->field_mode ? v->ref_field_type[1] : ((j+src_y - s->mspel)&1);
+ for (i = 0; i < 17 + s->mspel * 2; i++)
+ src[i] = luty[f][src[i]];
+ src += s->linesize;
+ }
+ src = srcU;
+ src2 = srcV;
+ for (j = 0; j < 9; j++) {
+ int f = v->field_mode ? v->ref_field_type[1] : ((j+uvsrc_y)&1);
+ for (i = 0; i < 9; i++) {
+ src[i] = lutuv[f][src[i]];
+ src2[i] = lutuv[f][src2[i]];
+ }
+ src += s->uvlinesize;
+ src2 += s->uvlinesize;
+ }
+ }
srcY += s->mspel * (1 + s->linesize);
}
@@ -1968,30 +2074,18 @@ static av_always_inline int scale_mv(int value, int bfrac, int inv, int qs)
static inline void vc1_b_mc(VC1Context *v, int dmv_x[2], int dmv_y[2],
int direct, int mode)
{
- if (v->use_ic) {
- v->mv_mode2 = v->mv_mode;
- v->mv_mode = MV_PMODE_INTENSITY_COMP;
- }
if (direct) {
vc1_mc_1mv(v, 0);
vc1_interp_mc(v);
- if (v->use_ic)
- v->mv_mode = v->mv_mode2;
return;
}
if (mode == BMV_TYPE_INTERPOLATED) {
vc1_mc_1mv(v, 0);
vc1_interp_mc(v);
- if (v->use_ic)
- v->mv_mode = v->mv_mode2;
return;
}
- if (v->use_ic && (mode == BMV_TYPE_BACKWARD))
- v->mv_mode = v->mv_mode2;
vc1_mc_1mv(v, (mode == BMV_TYPE_BACKWARD));
- if (v->use_ic)
- v->mv_mode = v->mv_mode2;
}
static inline void vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2],
@@ -2687,7 +2781,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;
@@ -2899,7 +2993,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;
@@ -3548,7 +3642,7 @@ static int vc1_decode_p_mb(VC1Context *v)
}
vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type[0], 0, 0);
if (!s->mb_intra)
- vc1_mc_4mv_luma(v, i, 0);
+ vc1_mc_4mv_luma(v, i, 0, 0);
intra_count += s->mb_intra;
is_intra[i] = s->mb_intra;
is_coded[i] = mb_has_coeffs;
@@ -3638,7 +3732,7 @@ static int vc1_decode_p_mb(VC1Context *v)
}
for (i = 0; i < 4; i++) {
vc1_pred_mv(v, i, 0, 0, 0, v->range_x, v->range_y, v->mb_type[0], 0, 0);
- vc1_mc_4mv_luma(v, i, 0);
+ vc1_mc_4mv_luma(v, i, 0, 0);
}
vc1_mc_4mv_chroma(v, 0);
s->current_picture.qscale_table[mb_pos] = 0;
@@ -3674,7 +3768,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);
@@ -3716,8 +3810,10 @@ static int vc1_decode_p_mb_intfr(VC1Context *v)
break;
}
if (ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][0] == MV_PMODE_INTFR_INTRA) { // intra MB
- s->current_picture.motion_val[1][s->block_index[0]][0] = 0;
- s->current_picture.motion_val[1][s->block_index[0]][1] = 0;
+ for (i = 0; i < 4; i++) {
+ s->current_picture.motion_val[1][s->block_index[i]][0] = 0;
+ s->current_picture.motion_val[1][s->block_index[i]][1] = 0;
+ }
s->current_picture.mb_type[mb_pos] = MB_TYPE_INTRA;
s->mb_intra = v->is_intra[s->mb_x] = 1;
for (i = 0; i < 6; i++)
@@ -3786,10 +3882,10 @@ static int vc1_decode_p_mb_intfr(VC1Context *v)
if (val) {
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
}
- vc1_pred_mv_intfr(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type[0]);
- vc1_mc_4mv_luma(v, i, 0);
+ vc1_pred_mv_intfr(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type[0], 0);
+ vc1_mc_4mv_luma(v, i, 0, 0);
} else if (i == 4) {
- vc1_mc_4mv_chroma4(v);
+ vc1_mc_4mv_chroma4(v, 0, 0, 0);
}
}
} else if (twomv) {
@@ -3798,24 +3894,24 @@ static int vc1_decode_p_mb_intfr(VC1Context *v)
if (mvbp & 2) {
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
}
- vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 2, v->range_x, v->range_y, v->mb_type[0]);
- vc1_mc_4mv_luma(v, 0, 0);
- vc1_mc_4mv_luma(v, 1, 0);
+ vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 2, v->range_x, v->range_y, v->mb_type[0], 0);
+ vc1_mc_4mv_luma(v, 0, 0, 0);
+ vc1_mc_4mv_luma(v, 1, 0, 0);
dmv_x = dmv_y = 0;
if (mvbp & 1) {
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
}
- vc1_pred_mv_intfr(v, 2, dmv_x, dmv_y, 2, v->range_x, v->range_y, v->mb_type[0]);
- vc1_mc_4mv_luma(v, 2, 0);
- vc1_mc_4mv_luma(v, 3, 0);
- vc1_mc_4mv_chroma4(v);
+ vc1_pred_mv_intfr(v, 2, dmv_x, dmv_y, 2, v->range_x, v->range_y, v->mb_type[0], 0);
+ vc1_mc_4mv_luma(v, 2, 0, 0);
+ vc1_mc_4mv_luma(v, 3, 0, 0);
+ vc1_mc_4mv_chroma4(v, 0, 0, 0);
} else {
mvbp = ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][2];
dmv_x = dmv_y = 0;
if (mvbp) {
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
}
- vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type[0]);
+ vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type[0], 0);
vc1_mc_1mv(v, 0);
}
if (cbp)
@@ -3855,7 +3951,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v)
v->blk_mv_type[s->block_index[1]] = 0;
v->blk_mv_type[s->block_index[2]] = 0;
v->blk_mv_type[s->block_index[3]] = 0;
- vc1_pred_mv_intfr(v, 0, 0, 0, 1, v->range_x, v->range_y, v->mb_type[0]);
+ vc1_pred_mv_intfr(v, 0, 0, 0, 1, v->range_x, v->range_y, v->mb_type[0], 0);
vc1_mc_1mv(v, 0);
}
if (s->mb_x == s->mb_width - 1)
@@ -3878,11 +3974,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
@@ -3942,7 +4038,7 @@ static int vc1_decode_p_mb_intfi(VC1Context *v)
get_mvdata_interlaced(v, &dmv_x, &dmv_y, &pred_flag);
}
vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type[0], pred_flag, 0);
- vc1_mc_4mv_luma(v, i, 0);
+ vc1_mc_4mv_luma(v, i, 0, 0);
} else if (i == 4)
vc1_mc_4mv_chroma(v, 0);
}
@@ -4152,7 +4248,7 @@ static void vc1_decode_b_mb_intfi(VC1Context *v)
int bmvtype = BMV_TYPE_BACKWARD;
int idx_mbmode, interpmvp;
- 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);
@@ -4251,7 +4347,7 @@ static void vc1_decode_b_mb_intfi(VC1Context *v)
&pred_flag[bmvtype == BMV_TYPE_BACKWARD]);
}
vc1_pred_b_mv_intfi(v, i, dmv_x, dmv_y, 0, pred_flag);
- vc1_mc_4mv_luma(v, i, bmvtype == BMV_TYPE_BACKWARD);
+ vc1_mc_4mv_luma(v, i, bmvtype == BMV_TYPE_BACKWARD, 0);
} else if (i == 4)
vc1_mc_4mv_chroma(v, bmvtype == BMV_TYPE_BACKWARD);
}
@@ -4285,6 +4381,357 @@ static void vc1_decode_b_mb_intfi(VC1Context *v)
}
}
+/** Decode one B-frame MB (in interlaced frame B picture)
+ */
+static int vc1_decode_b_mb_intfr(VC1Context *v)
+{
+ MpegEncContext *s = &v->s;
+ GetBitContext *gb = &s->gb;
+ int i, j;
+ int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
+ int cbp = 0; /* cbp decoding stuff */
+ int mqdiff, mquant; /* MB quantization */
+ int ttmb = v->ttfrm; /* MB Transform type */
+ int mvsw = 0; /* motion vector switch */
+ int mb_has_coeffs = 1; /* last_flag */
+ int dmv_x, dmv_y; /* Differential MV components */
+ int val; /* temp value */
+ int first_block = 1;
+ int dst_idx, off;
+ int skipped, direct, twomv = 0;
+ int block_cbp = 0, pat, block_tt = 0;
+ int idx_mbmode = 0, mvbp;
+ int stride_y, fieldtx;
+ int bmvtype = BMV_TYPE_BACKWARD;
+ int dir, dir2;
+
+ mquant = v->pq; /* Lossy initialization */
+ s->mb_intra = 0;
+ if (v->skip_is_raw)
+ skipped = get_bits1(gb);
+ else
+ skipped = v->s.mbskip_table[mb_pos];
+
+ if (!skipped) {
+ idx_mbmode = get_vlc2(gb, v->mbmode_vlc->table, VC1_INTFR_NON4MV_MBMODE_VLC_BITS, 2);
+ if (ff_vc1_mbmode_intfrp[0][idx_mbmode][0] == MV_PMODE_INTFR_2MV_FIELD)
+ {
+ twomv = 1;
+ v->blk_mv_type[s->block_index[0]] = 1;
+ v->blk_mv_type[s->block_index[1]] = 1;
+ v->blk_mv_type[s->block_index[2]] = 1;
+ v->blk_mv_type[s->block_index[3]] = 1;
+ } else {
+ v->blk_mv_type[s->block_index[0]] = 0;
+ v->blk_mv_type[s->block_index[1]] = 0;
+ v->blk_mv_type[s->block_index[2]] = 0;
+ v->blk_mv_type[s->block_index[3]] = 0;
+ }
+ }
+
+ if (v->dmb_is_raw)
+ direct = get_bits1(gb);
+ else
+ direct = v->direct_mb_plane[mb_pos];
+
+ if (direct) {
+ s->mv[0][0][0] = s->current_picture.motion_val[0][s->block_index[0]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][0], v->bfraction, 0, s->quarter_sample);
+ s->mv[0][0][1] = s->current_picture.motion_val[0][s->block_index[0]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][1], v->bfraction, 0, s->quarter_sample);
+ s->mv[1][0][0] = s->current_picture.motion_val[1][s->block_index[0]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][0], v->bfraction, 1, s->quarter_sample);
+ s->mv[1][0][1] = s->current_picture.motion_val[1][s->block_index[0]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][1], v->bfraction, 1, s->quarter_sample);
+
+ if (twomv) {
+ s->mv[0][2][0] = s->current_picture.motion_val[0][s->block_index[2]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][0], v->bfraction, 0, s->quarter_sample);
+ s->mv[0][2][1] = s->current_picture.motion_val[0][s->block_index[2]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][1], v->bfraction, 0, s->quarter_sample);
+ s->mv[1][2][0] = s->current_picture.motion_val[1][s->block_index[2]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][0], v->bfraction, 1, s->quarter_sample);
+ s->mv[1][2][1] = s->current_picture.motion_val[1][s->block_index[2]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][1], v->bfraction, 1, s->quarter_sample);
+
+ for (i = 1; i < 4; i+=2) {
+ s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0] = s->mv[0][i-1][0];
+ s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1] = s->mv[0][i-1][1];
+ s->mv[1][i][0] = s->current_picture.motion_val[1][s->block_index[i]][0] = s->mv[1][i-1][0];
+ s->mv[1][i][1] = s->current_picture.motion_val[1][s->block_index[i]][1] = s->mv[1][i-1][1];
+ }
+ } else {
+ for (i = 1; i < 4; i++) {
+ s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0] = s->mv[0][0][0];
+ s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1] = s->mv[0][0][1];
+ s->mv[1][i][0] = s->current_picture.motion_val[1][s->block_index[i]][0] = s->mv[1][0][0];
+ s->mv[1][i][1] = s->current_picture.motion_val[1][s->block_index[i]][1] = s->mv[1][0][1];
+ }
+ }
+ }
+
+ if (ff_vc1_mbmode_intfrp[0][idx_mbmode][0] == MV_PMODE_INTFR_INTRA) { // intra MB
+ for (i = 0; i < 4; i++) {
+ s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0] = 0;
+ s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1] = 0;
+ s->mv[1][i][0] = s->current_picture.motion_val[1][s->block_index[i]][0] = 0;
+ s->mv[1][i][1] = s->current_picture.motion_val[1][s->block_index[i]][1] = 0;
+ }
+ s->current_picture.mb_type[mb_pos] = MB_TYPE_INTRA;
+ s->mb_intra = v->is_intra[s->mb_x] = 1;
+ for (i = 0; i < 6; i++)
+ v->mb_type[0][s->block_index[i]] = 1;
+ fieldtx = v->fieldtx_plane[mb_pos] = get_bits1(gb);
+ mb_has_coeffs = get_bits1(gb);
+ if (mb_has_coeffs)
+ cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc->table, VC1_CBPCY_P_VLC_BITS, 2);
+ v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb);
+ GET_MQUANT();
+ s->current_picture.qscale_table[mb_pos] = mquant;
+ /* Set DC scale - y and c use the same (not sure if necessary here) */
+ s->y_dc_scale = s->y_dc_scale_table[mquant];
+ s->c_dc_scale = s->c_dc_scale_table[mquant];
+ dst_idx = 0;
+ for (i = 0; i < 6; i++) {
+ s->dc_val[0][s->block_index[i]] = 0;
+ dst_idx += i >> 2;
+ val = ((cbp >> (5 - i)) & 1);
+ v->mb_type[0][s->block_index[i]] = s->mb_intra;
+ v->a_avail = v->c_avail = 0;
+ if (i == 2 || i == 3 || !s->first_slice_line)
+ v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]];
+ if (i == 1 || i == 3 || s->mb_x)
+ v->c_avail = v->mb_type[0][s->block_index[i] - 1];
+
+ vc1_decode_intra_block(v, s->block[i], i, val, mquant,
+ (i & 4) ? v->codingset2 : v->codingset);
+ if ((i>3) && (s->flags & CODEC_FLAG_GRAY)) continue;
+ v->vc1dsp.vc1_inv_trans_8x8(s->block[i]);
+ if (i < 4) {
+ stride_y = s->linesize << fieldtx;
+ off = (fieldtx) ? ((i & 1) * 8) + ((i & 2) >> 1) * s->linesize : (i & 1) * 8 + 4 * (i & 2) * s->linesize;
+ } else {
+ stride_y = s->uvlinesize;
+ off = 0;
+ }
+ s->dsp.put_signed_pixels_clamped(s->block[i], s->dest[dst_idx] + off, stride_y);
+ }
+ } else {
+ s->mb_intra = v->is_intra[s->mb_x] = 0;
+ if (!direct) {
+ if (skipped || !s->mb_intra) {
+ bmvtype = decode012(gb);
+ switch (bmvtype) {
+ case 0:
+ bmvtype = (v->bfraction >= (B_FRACTION_DEN/2)) ? BMV_TYPE_BACKWARD : BMV_TYPE_FORWARD;
+ break;
+ case 1:
+ bmvtype = (v->bfraction >= (B_FRACTION_DEN/2)) ? BMV_TYPE_FORWARD : BMV_TYPE_BACKWARD;
+ break;
+ case 2:
+ bmvtype = BMV_TYPE_INTERPOLATED;
+ }
+ }
+
+ if (twomv && bmvtype != BMV_TYPE_INTERPOLATED)
+ mvsw = get_bits1(gb);
+ }
+
+ if (!skipped) { // inter MB
+ mb_has_coeffs = ff_vc1_mbmode_intfrp[0][idx_mbmode][3];
+ if (mb_has_coeffs)
+ cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc->table, VC1_CBPCY_P_VLC_BITS, 2);
+ if (!direct) {
+ 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) {
+ v->twomvbp = get_vlc2(gb, v->twomvbp_vlc->table, VC1_2MV_BLOCK_PATTERN_VLC_BITS, 1);
+ }
+ }
+
+ for (i = 0; i < 6; i++)
+ v->mb_type[0][s->block_index[i]] = 0;
+ fieldtx = v->fieldtx_plane[mb_pos] = ff_vc1_mbmode_intfrp[0][idx_mbmode][1];
+ /* for all motion vector read MVDATA and motion compensate each block */
+ dst_idx = 0;
+ if (direct) {
+ if (twomv) {
+ for (i = 0; i < 4; i++) {
+ vc1_mc_4mv_luma(v, i, 0, 0);
+ vc1_mc_4mv_luma(v, i, 1, 1);
+ }
+ vc1_mc_4mv_chroma4(v, 0, 0, 0);
+ vc1_mc_4mv_chroma4(v, 1, 1, 1);
+ } else {
+ vc1_mc_1mv(v, 0);
+ vc1_interp_mc(v);
+ }
+ } else if (twomv && bmvtype == BMV_TYPE_INTERPOLATED) {
+ mvbp = v->fourmvbp;
+ for (i = 0; i < 4; i++) {
+ dir = i==1 || i==3;
+ dmv_x = dmv_y = 0;
+ val = ((mvbp >> (3 - i)) & 1);
+ if (val) {
+ get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
+ }
+ j = i > 1 ? 2 : 0;
+ vc1_pred_mv_intfr(v, j, dmv_x, dmv_y, 2, v->range_x, v->range_y, v->mb_type[0], dir);
+ vc1_mc_4mv_luma(v, j, dir, dir);
+ vc1_mc_4mv_luma(v, j+1, dir, dir);
+ }
+
+ vc1_mc_4mv_chroma4(v, 0, 0, 0);
+ vc1_mc_4mv_chroma4(v, 1, 1, 1);
+ } else if (bmvtype == BMV_TYPE_INTERPOLATED) {
+ mvbp = v->twomvbp;
+ dmv_x = dmv_y = 0;
+ if (mvbp & 2) {
+ get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
+ }
+
+ vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type[0], 0);
+ vc1_mc_1mv(v, 0);
+
+ dmv_x = dmv_y = 0;
+ if (mvbp & 1) {
+ get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
+ }
+
+ vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type[0], 1);
+ vc1_interp_mc(v);
+ } else if (twomv) {
+ dir = bmvtype == BMV_TYPE_BACKWARD;
+ dir2 = dir;
+ if (mvsw)
+ dir2 = !dir;
+ mvbp = v->twomvbp;
+ dmv_x = dmv_y = 0;
+ if (mvbp & 2) {
+ get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
+ }
+ vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 2, v->range_x, v->range_y, v->mb_type[0], dir);
+
+ dmv_x = dmv_y = 0;
+ if (mvbp & 1) {
+ get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
+ }
+ vc1_pred_mv_intfr(v, 2, dmv_x, dmv_y, 2, v->range_x, v->range_y, v->mb_type[0], dir2);
+
+ if (mvsw) {
+ for (i = 0; i<2; i++) {
+ s->mv[dir][i+2][0] = s->mv[dir][i][0] = s->current_picture.motion_val[dir][s->block_index[i+2]][0] = s->current_picture.motion_val[dir][s->block_index[i]][0];
+ s->mv[dir][i+2][1] = s->mv[dir][i][1] = s->current_picture.motion_val[dir][s->block_index[i+2]][1] = s->current_picture.motion_val[dir][s->block_index[i]][1];
+ s->mv[dir2][i+2][0] = s->mv[dir2][i][0] = s->current_picture.motion_val[dir2][s->block_index[i]][0] = s->current_picture.motion_val[dir2][s->block_index[i+2]][0];
+ s->mv[dir2][i+2][1] = s->mv[dir2][i][1] = s->current_picture.motion_val[dir2][s->block_index[i]][1] = s->current_picture.motion_val[dir2][s->block_index[i+2]][1];
+ }
+ } else {
+ vc1_pred_mv_intfr(v, 0, 0, 0, 2, v->range_x, v->range_y, v->mb_type[0], !dir);
+ vc1_pred_mv_intfr(v, 2, 0, 0, 2, v->range_x, v->range_y, v->mb_type[0], !dir);
+ }
+
+ vc1_mc_4mv_luma(v, 0, dir, 0);
+ vc1_mc_4mv_luma(v, 1, dir, 0);
+ vc1_mc_4mv_luma(v, 2, dir2, 0);
+ vc1_mc_4mv_luma(v, 3, dir2, 0);
+ vc1_mc_4mv_chroma4(v, dir, dir2, 0);
+ } else {
+ dir = bmvtype == BMV_TYPE_BACKWARD;
+
+ mvbp = ff_vc1_mbmode_intfrp[0][idx_mbmode][2];
+ dmv_x = dmv_y = 0;
+ if (mvbp) {
+ get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
+ }
+
+ vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type[0], dir);
+ v->blk_mv_type[s->block_index[0]] = 1;
+ v->blk_mv_type[s->block_index[1]] = 1;
+ v->blk_mv_type[s->block_index[2]] = 1;
+ v->blk_mv_type[s->block_index[3]] = 1;
+ vc1_pred_mv_intfr(v, 0, 0, 0, 2, v->range_x, v->range_y, 0, !dir);
+ for (i = 0; i<2; i++) {
+ s->mv[!dir][i+2][0] = s->mv[!dir][i][0] = s->current_picture.motion_val[!dir][s->block_index[i+2]][0] = s->current_picture.motion_val[!dir][s->block_index[i]][0];
+ s->mv[!dir][i+2][1] = s->mv[!dir][i][1] = s->current_picture.motion_val[!dir][s->block_index[i+2]][1] = s->current_picture.motion_val[!dir][s->block_index[i]][1];
+ }
+ vc1_mc_1mv(v, dir);
+ }
+
+ if (cbp)
+ GET_MQUANT(); // p. 227
+ s->current_picture.qscale_table[mb_pos] = mquant;
+ if (!v->ttmbf && cbp)
+ ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index].table, VC1_TTMB_VLC_BITS, 2);
+ for (i = 0; i < 6; i++) {
+ s->dc_val[0][s->block_index[i]] = 0;
+ dst_idx += i >> 2;
+ val = ((cbp >> (5 - i)) & 1);
+ if (!fieldtx)
+ off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize);
+ else
+ off = (i & 4) ? 0 : ((i & 1) * 8 + ((i > 1) * s->linesize));
+ if (val) {
+ pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb,
+ first_block, s->dest[dst_idx] + off,
+ (i & 4) ? s->uvlinesize : (s->linesize << fieldtx),
+ (i & 4) && (s->flags & CODEC_FLAG_GRAY), &block_tt);
+ block_cbp |= pat << (i << 2);
+ if (!v->ttmbf && ttmb < 8)
+ ttmb = -1;
+ first_block = 0;
+ }
+ }
+
+ } else { // skipped
+ dir = 0;
+ for (i = 0; i < 6; i++) {
+ v->mb_type[0][s->block_index[i]] = 0;
+ s->dc_val[0][s->block_index[i]] = 0;
+ }
+ s->current_picture.mb_type[mb_pos] = MB_TYPE_SKIP;
+ s->current_picture.qscale_table[mb_pos] = 0;
+ v->blk_mv_type[s->block_index[0]] = 0;
+ v->blk_mv_type[s->block_index[1]] = 0;
+ v->blk_mv_type[s->block_index[2]] = 0;
+ v->blk_mv_type[s->block_index[3]] = 0;
+
+ if (!direct) {
+ if (bmvtype == BMV_TYPE_INTERPOLATED) {
+ vc1_pred_mv_intfr(v, 0, 0, 0, 1, v->range_x, v->range_y, v->mb_type[0], 0);
+ vc1_pred_mv_intfr(v, 0, 0, 0, 1, v->range_x, v->range_y, v->mb_type[0], 1);
+ } else {
+ dir = bmvtype == BMV_TYPE_BACKWARD;
+ vc1_pred_mv_intfr(v, 0, 0, 0, 1, v->range_x, v->range_y, v->mb_type[0], dir);
+ if (mvsw) {
+ int dir2 = dir;
+ if (mvsw)
+ dir2 = !dir;
+ for (i = 0; i<2; i++) {
+ s->mv[dir][i+2][0] = s->mv[dir][i][0] = s->current_picture.motion_val[dir][s->block_index[i+2]][0] = s->current_picture.motion_val[dir][s->block_index[i]][0];
+ s->mv[dir][i+2][1] = s->mv[dir][i][1] = s->current_picture.motion_val[dir][s->block_index[i+2]][1] = s->current_picture.motion_val[dir][s->block_index[i]][1];
+ s->mv[dir2][i+2][0] = s->mv[dir2][i][0] = s->current_picture.motion_val[dir2][s->block_index[i]][0] = s->current_picture.motion_val[dir2][s->block_index[i+2]][0];
+ s->mv[dir2][i+2][1] = s->mv[dir2][i][1] = s->current_picture.motion_val[dir2][s->block_index[i]][1] = s->current_picture.motion_val[dir2][s->block_index[i+2]][1];
+ }
+ } else {
+ v->blk_mv_type[s->block_index[0]] = 1;
+ v->blk_mv_type[s->block_index[1]] = 1;
+ v->blk_mv_type[s->block_index[2]] = 1;
+ v->blk_mv_type[s->block_index[3]] = 1;
+ vc1_pred_mv_intfr(v, 0, 0, 0, 2, v->range_x, v->range_y, 0, !dir);
+ for (i = 0; i<2; i++) {
+ s->mv[!dir][i+2][0] = s->mv[!dir][i][0] = s->current_picture.motion_val[!dir][s->block_index[i+2]][0] = s->current_picture.motion_val[!dir][s->block_index[i]][0];
+ s->mv[!dir][i+2][1] = s->mv[!dir][i][1] = s->current_picture.motion_val[!dir][s->block_index[i+2]][1] = s->current_picture.motion_val[!dir][s->block_index[i]][1];
+ }
+ }
+ }
+ }
+
+ vc1_mc_1mv(v, dir);
+ if (direct || bmvtype == BMV_TYPE_INTERPOLATED) {
+ vc1_interp_mc(v);
+ }
+ }
+ }
+ if (s->mb_x == s->mb_width - 1)
+ memmove(v->is_intra_base, v->is_intra, sizeof(v->is_intra_base[0])*s->mb_stride);
+ v->cbp[s->mb_x] = block_cbp;
+ v->ttblk[s->mb_x] = block_tt;
+ return 0;
+}
+
/** Decode blocks of I-frame
*/
static void vc1_decode_i_blocks(VC1Context *v)
@@ -4675,6 +5122,8 @@ static void vc1_decode_b_blocks(VC1Context *v)
if (v->fcm == ILACE_FIELD)
vc1_decode_b_mb_intfi(v);
+ else if (v->fcm == ILACE_FRAME)
+ vc1_decode_b_mb_intfr(v);
else
vc1_decode_b_mb(v);
if (get_bits_count(&s->gb) > v->bits || get_bits_count(&s->gb) < 0) {
@@ -4708,9 +5157,11 @@ static void vc1_decode_skip_blocks(VC1Context *v)
s->mb_x = 0;
init_block_index(v);
ff_update_block_index(s);
- memcpy(s->dest[0], s->last_picture.f.data[0] + s->mb_y * 16 * s->linesize, s->linesize * 16);
- memcpy(s->dest[1], s->last_picture.f.data[1] + s->mb_y * 8 * s->uvlinesize, s->uvlinesize * 8);
- memcpy(s->dest[2], s->last_picture.f.data[2] + s->mb_y * 8 * s->uvlinesize, s->uvlinesize * 8);
+ if (s->last_picture.f.data[0]) {
+ memcpy(s->dest[0], s->last_picture.f.data[0] + s->mb_y * 16 * s->linesize, s->linesize * 16);
+ memcpy(s->dest[1], s->last_picture.f.data[1] + s->mb_y * 8 * s->uvlinesize, s->uvlinesize * 8);
+ memcpy(s->dest[2], s->last_picture.f.data[2] + s->mb_y * 8 * s->uvlinesize, s->uvlinesize * 8);
+ }
ff_mpeg_draw_horiz_band(s, s->mb_y * 16, 16);
s->first_slice_line = 0;
}
@@ -4980,6 +5431,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;
@@ -4997,10 +5449,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);
@@ -5063,9 +5513,6 @@ av_cold int ff_vc1_decode_init_alloc_tables(VC1Context *v)
v->mv_f_base = av_mallocz(2 * (s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2));
v->mv_f[0] = v->mv_f_base + s->b8_stride + 1;
v->mv_f[1] = v->mv_f[0] + (s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2);
- v->mv_f_last_base = av_mallocz(2 * (s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2));
- v->mv_f_last[0] = v->mv_f_last_base + s->b8_stride + 1;
- v->mv_f_last[1] = v->mv_f_last[0] + (s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2);
v->mv_f_next_base = av_mallocz(2 * (s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2));
v->mv_f_next[0] = v->mv_f_next_base + s->b8_stride + 1;
v->mv_f_next[1] = v->mv_f_next[0] + (s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2);
@@ -5135,6 +5582,16 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx)
if (ff_vc1_init_common(v) < 0)
return -1;
+ // ensure static VLC tables are initialized
+ if (ff_msmpeg4_decode_init(avctx) < 0)
+ return -1;
+ if (ff_vc1_decode_init_alloc_tables(v) < 0)
+ return -1;
+ // 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);
@@ -5235,6 +5692,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;
}
@@ -5263,7 +5725,6 @@ av_cold int ff_vc1_decode_end(AVCodecContext *avctx)
av_freep(&v->mb_type_base);
av_freep(&v->blk_mv_type_base);
av_freep(&v->mv_f_base);
- av_freep(&v->mv_f_last_base);
av_freep(&v->mv_f_next_base);
av_freep(&v->block);
av_freep(&v->cbp_base);
@@ -5287,14 +5748,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 */
@@ -5306,7 +5772,7 @@ 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) {
@@ -5339,6 +5805,9 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
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;
@@ -5390,6 +5859,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;
@@ -5443,6 +5915,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;
}
@@ -5471,12 +5945,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.
@@ -5514,39 +5996,71 @@ 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 ((CONFIG_VC1_VDPAU_DECODER)
- &&s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
- ff_vdpau_vc1_decode_picture(s, buf_start, (buf + buf_size) - buf_start);
- else 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;
+ &&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;
+
+
ff_mpeg_er_frame_start(s);
v->bits = buf_size * 8;
v->end_mb_x = s->mb_width;
if (v->field_mode) {
- uint8_t *tmp[2];
s->current_picture.f.linesize[0] <<= 1;
s->current_picture.f.linesize[1] <<= 1;
s->current_picture.f.linesize[2] <<= 1;
s->linesize <<= 1;
s->uvlinesize <<= 1;
- tmp[0] = v->mv_f_last[0];
- tmp[1] = v->mv_f_last[1];
- v->mv_f_last[0] = v->mv_f_next[0];
- v->mv_f_last[1] = v->mv_f_next[1];
- v->mv_f_next[0] = v->mv_f[0];
- v->mv_f_next[1] = v->mv_f[1];
- v->mv_f[0] = tmp[0];
- v->mv_f[1] = tmp[1];
}
mb_height = s->mb_height >> v->field_mode;
for (i = 0; i <= n_slices; i++) {
@@ -5558,7 +6072,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;
@@ -5568,43 +6082,60 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
if (i) {
v->pic_header_flag = 0;
if (v->field_mode && i == n_slices1 + 2) {
- if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) {
+ if ((header_ret = ff_vc1_parse_frame_header_adv(v, &s->gb)) < 0) {
av_log(v->s.avctx, AV_LOG_ERROR, "Field header damaged\n");
continue;
}
} else if (get_bits1(&s->gb)) {
v->pic_header_flag = 1;
- if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) {
+ if ((header_ret = ff_vc1_parse_frame_header_adv(v, &s->gb)) < 0) {
av_log(v->s.avctx, AV_LOG_ERROR, "Slice header damaged\n");
continue;
}
}
}
+ if (header_ret < 0)
+ continue;
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;
}
if (v->field_mode) {
v->second_field = 0;
- if (s->pict_type == AV_PICTURE_TYPE_B) {
- memcpy(v->mv_f_base, v->mv_f_next_base,
- 2 * (s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2));
- }
s->current_picture.f.linesize[0] >>= 1;
s->current_picture.f.linesize[1] >>= 1;
s->current_picture.f.linesize[2] >>= 1;
s->linesize >>= 1;
s->uvlinesize >>= 1;
+ if (v->s.pict_type != AV_PICTURE_TYPE_BI && v->s.pict_type != AV_PICTURE_TYPE_B) {
+ FFSWAP(uint8_t *, v->mv_f_next[0], v->mv_f[0]);
+ FFSWAP(uint8_t *, v->mv_f_next[1], v->mv_f[1]);
+ }
}
av_dlog(s->avctx, "Consumed %i/%i bits\n",
get_bits_count(&s->gb), s->gb.size_in_bits);
// if (get_bits_count(&s->gb) > buf_size * 8)
// 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);
}
@@ -5628,11 +6159,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;
diff --git a/libavcodec/vc1dsp.c b/libavcodec/vc1dsp.c
index 9ebea68..39e9441 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 c4b817e..60bfcce 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
*/
@@ -37,6 +37,10 @@ static av_cold int vcr1_decode_init(AVCodecContext *avctx)
{
avctx->pix_fmt = AV_PIX_FMT_YUV410P;
+ if (avctx->width % 8 || avctx->height%4) {
+ avpriv_request_sample(avctx, "odd dimensions support");
+ return AVERROR_PATCHWELCOME;
+ }
return 0;
}
@@ -50,10 +54,13 @@ static int vcr1_decode_frame(AVCodecContext *avctx, void *data,
const uint8_t *bytestream = buf;
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(buf_size < 16 + avctx->height + avctx->width*avctx->height*5/8){
+ av_log(avctx, AV_LOG_ERROR, "Insufficient input data.\n");
+ 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;
diff --git a/libavcodec/vda.h b/libavcodec/vda.h
index 987b94f..281785f 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,16 +113,25 @@ 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;
};
diff --git a/libavcodec/vda_h264.c b/libavcodec/vda_h264.c
index 6c1845a..d0237c2 100644
--- a/libavcodec/vda_h264.c
+++ b/libavcodec/vda_h264.c
@@ -1,39 +1,40 @@
/*
- * 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)
+
+/* 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 +72,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 +86,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)
@@ -130,7 +131,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 +141,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 +186,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..4e60de0
--- /dev/null
+++ b/libavcodec/vda_h264_dec.c
@@ -0,0 +1,271 @@
+/*
+ * 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];
+ 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 check_format(AVCodecContext *avctx)
+{
+ AVCodecParserContext *parser;
+ uint8_t *pout;
+ int psize;
+ int index;
+ H264Context *h;
+ int ret = -1;
+
+ /* init parser & parse file */
+ parser = av_parser_init(avctx->codec->id);
+ if (!parser) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 parser.\n");
+ goto final;
+ }
+ parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
+ index = av_parser_parse2(parser, avctx, &pout, &psize, NULL, 0, 0, 0, 0);
+ if (index < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to parse this file.\n");
+ goto release_parser;
+ }
+
+ /* check if support */
+ h = parser->priv_data;
+ switch (h->sps.bit_depth_luma) {
+ case 8:
+ if (!CHROMA444(h) && !CHROMA422(h)) {
+ // only this will H.264 decoder switch to hwaccel
+ ret = 0;
+ break;
+ }
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n");
+ }
+
+release_parser:
+ av_parser_close(parser);
+
+final:
+ return ret;
+}
+
+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;
+ }
+
+ /* check if VDA supports this file */
+ if (check_format(avctx) < 0)
+ goto failed;
+
+ /* 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;
+ 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 bf1f81e..04355b0 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
*/
@@ -307,7 +307,7 @@ void ff_vdpau_vc1_decode_picture(MpegEncContext *s, const uint8_t *buf,
assert(render);
/* fill LvPictureInfoVC1 struct */
- render->info.vc1.frame_coding_mode = v->fcm;
+ 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;
diff --git a/libavcodec/vdpau.h b/libavcodec/vdpau.h
index 7e692f7..f5b2317 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,8 +51,9 @@
#include <vdpau/vdpau.h>
#include <vdpau/vdpau_x11.h>
+#include "libavutil/avconfig.h"
-union VdpPictureInfo {
+union FFVdpPictureInfo {
VdpPictureInfoH264 h264;
VdpPictureInfoMPEG1Or2 mpeg;
VdpPictureInfoVC1 vc1;
@@ -88,7 +89,7 @@ typedef struct AVVDPAUContext {
*
* Set by libavcodec.
*/
- union VdpPictureInfo info;
+ union FFVdpPictureInfo info;
/**
* Allocated size of the bitstream_buffers table.
@@ -124,19 +125,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_FORK_ABI
/** picture parameter information for all supported codecs */
- union VdpPictureInfo info;
+ union FFVdpPictureInfo info;
+#endif
/** Describe size/location of the compressed video data.
Set to 0 when freeing bitstream_buffers. */
@@ -144,6 +147,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_FORK_ABI
+ /** picture parameter information for all supported codecs */
+ union FFVdpPictureInfo info;
+#endif
};
/* @}*/
diff --git a/libavcodec/vdpau_h264.c b/libavcodec/vdpau_h264.c
index e787762..ad1aff0 100644
--- a/libavcodec/vdpau_h264.c
+++ b/libavcodec/vdpau_h264.c
@@ -4,20 +4,20 @@
* Copyright (c) 2008 NVIDIA
* Copyright (c) 2013 RĂ©mi Denis-Courmont
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software Foundation,
+ * License along with FFmpeg; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vdpau_internal.h b/libavcodec/vdpau_internal.h
index 4dbda79..790b3ef 100644
--- a/libavcodec/vdpau_internal.h
+++ b/libavcodec/vdpau_internal.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
*/
diff --git a/libavcodec/vdpau_mpeg12.c b/libavcodec/vdpau_mpeg12.c
index 20031ea..74e3f16 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 6555872..cb8ee0a 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 4d84cd2..993ef26 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
*/
@@ -59,7 +59,7 @@ static int vdpau_vc1_start_frame(AVCodecContext *avctx,
else
info->picture_type = s->pict_type - 1 + s->pict_type / 3;
- info->frame_coding_mode = v->fcm;
+ info->frame_coding_mode = v->fcm ? v->fcm + 1 : 0;
info->postprocflag = v->postprocflag;
info->pulldown = v->broadcast;
info->interlace = v->interlace;
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 2dc0f4d..f5aa53b 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 4
-#define LIBAVCODEC_VERSION_MICRO 0
+#define LIBAVCODEC_VERSION_MINOR 9
+#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 7d78593..e397720 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,6 +29,14 @@
#include <stddef.h>
#include <stdint.h>
+#define EMULATED_EDGE(depth) \
+void ff_emulated_edge_mc_ ## depth (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);
+
+EMULATED_EDGE(8)
+EMULATED_EDGE(16)
+
typedef struct VideoDSPContext {
/**
* Copy a rectangular area of samples to a temporary buffer and replicate
diff --git a/libavcodec/videodsp_template.c b/libavcodec/videodsp_template.c
index 5d5a32f..44f6a4d 100644
--- a/libavcodec/videodsp_template.c
+++ b/libavcodec/videodsp_template.c
@@ -1,39 +1,44 @@
/*
- * Copyright (c) 2002-2004 Michael Niedermayer
+ * Copyright (c) 2002-2012 Michael Niedermayer
* Copyright (C) 2012 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "bit_depth_template.c"
-
-static void FUNC(ff_emulated_edge_mc)(uint8_t *buf, const uint8_t *src,
- ptrdiff_t linesize,
+void FUNC(ff_emulated_edge_mc)(uint8_t *buf, const uint8_t *src,
+ ptrdiff_t linesize_arg,
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;
+ int linesize = linesize_arg;
+
+ if (!w || !h)
+ return;
if (src_y >= h) {
- src += (h - 1 - src_y) * linesize;
+ src -= src_y * linesize;
+ src += (h - 1) * linesize;
src_y = h - 1;
} else if (src_y <= -block_h) {
- src += (1 - block_h - src_y) * linesize;
+ src -= src_y * linesize;
+ src += (1 - block_h) * linesize;
src_y = 1 - block_h;
}
if (src_x >= w) {
@@ -48,8 +53,8 @@ static void FUNC(ff_emulated_edge_mc)(uint8_t *buf, const uint8_t *src,
start_x = FFMAX(0, -src_x);
end_y = FFMIN(block_h, h-src_y);
end_x = FFMIN(block_w, w-src_x);
- assert(start_y < end_y && block_h);
- assert(start_x < end_x && block_w);
+ av_assert2(start_y < end_y && block_h);
+ av_assert2(start_x < end_x && block_w);
w = end_x - start_x;
src += start_y * linesize + start_x * sizeof(pixel);
diff --git a/libavcodec/vima.c b/libavcodec/vima.c
new file mode 100644
index 0000000..0513ee2
--- /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",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_VIMA,
+ .init = decode_init,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts VIMA audio"),
+};
diff --git a/libavcodec/vmdav.c b/libavcodec/vmdav.c
index e6c7586..3e376e3 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
*/
@@ -98,7 +98,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 +109,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 +121,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 +133,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,12 +147,11 @@ 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;
+ int i, j, l;
unsigned char *dest_end = dest + dest_len;
GetByteContext gb;
@@ -172,18 +171,20 @@ 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 + i > dest_end || bytestream2_get_bytes_left(&gb) < 2)
+ int ps[2];
+ if (dest_end - pd < 2*l || bytestream2_get_bytes_left(&gb) < 2)
return bytestream2_tell(&gb);
- for (i = 0; i < l; i++) {
- *pd++ = bytestream2_get_byteu(&gb);
- *pd++ = bytestream2_get_byteu(&gb);
+ ps[0] = bytestream2_get_byteu(&gb);
+ ps[1] = bytestream2_get_byteu(&gb);
+ for (j = 0; j < l; j++) {
+ *pd++ = ps[0];
+ *pd++ = ps[1];
}
- bytestream2_skip(&gb, 2);
}
i += l;
} while (i < src_count);
@@ -191,7 +192,7 @@ static int rle_unpack(const unsigned char *src, unsigned char *dest,
return bytestream2_tell(&gb);
}
-static void vmd_decode(VmdVideoContext *s, AVFrame *frame)
+static int vmd_decode(VmdVideoContext *s, AVFrame *frame)
{
int i;
unsigned int *palette32;
@@ -212,16 +213,6 @@ static void 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_x < 0 || frame_width < 0 ||
- frame_x >= s->avctx->width ||
- frame_width > s->avctx->width ||
- frame_x + frame_width > s->avctx->width)
- return;
- if (frame_y < 0 || frame_height < 0 ||
- frame_y >= s->avctx->height ||
- frame_height > s->avctx->height ||
- frame_y + frame_height > s->avctx->height)
- return;
if ((frame_width == s->avctx->width && frame_height == s->avctx->height) &&
(frame_x || frame_y)) {
@@ -232,6 +223,19 @@ static void vmd_decode(VmdVideoContext *s, AVFrame *frame)
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 ||
+ frame_x + frame_width > s->avctx->width) {
+ return AVERROR_INVALIDDATA;
+ }
+ if (frame_y < 0 || frame_height < 0 ||
+ frame_y >= s->avctx->height ||
+ frame_height > s->avctx->height ||
+ frame_y + frame_height > s->avctx->height) {
+ return AVERROR_INVALIDDATA;
+ }
+
/* if only a certain region will be updated, copy the entire previous
* frame before the decode */
if (s->prev_frame.data[0] &&
@@ -252,16 +256,16 @@ static void 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;
}
}
- s->size -= (256 * 3 + 2);
}
if (s->size > 0) {
/* originally UnpackFrame in VAG's code */
bytestream2_init(&gb, gb.buffer, s->buf + s->size - gb.buffer);
if (bytestream2_get_bytes_left(&gb) < 1)
- return;
+ return AVERROR_INVALIDDATA;
meth = bytestream2_get_byteu(&gb);
if (meth & 0x80) {
lz_unpack(gb.buffer, bytestream2_get_bytes_left(&gb),
@@ -281,19 +285,19 @@ static void vmd_decode(VmdVideoContext *s, AVFrame *frame)
if (len & 0x80) {
len = (len & 0x7F) + 1;
if (ofs + len > frame_width || bytestream2_get_bytes_left(&gb) < len)
- return;
- bytestream2_get_buffer(&gb, &dp[ofs], len);
+ return AVERROR_INVALIDDATA;
+ bytestream2_get_bufferu(&gb, &dp[ofs], len);
ofs += len;
} else {
/* interframe pixel copy */
if (ofs + len + 1 > frame_width || !s->prev_frame.data[0])
- return;
+ return AVERROR_INVALIDDATA;
memcpy(&dp[ofs], &pp[ofs], len + 1);
ofs += len + 1;
}
} while (ofs < frame_width);
if (ofs > frame_width) {
- av_log(s->avctx, AV_LOG_ERROR, "VMD video: offset > width (%d > %d)\n",
+ av_log(s->avctx, AV_LOG_ERROR, "offset > width (%d > %d)\n",
ofs, frame_width);
break;
}
@@ -327,13 +331,13 @@ static void vmd_decode(VmdVideoContext *s, AVFrame *frame)
} else {
/* interframe pixel copy */
if (ofs + len + 1 > frame_width || !s->prev_frame.data[0])
- return;
+ return AVERROR_INVALIDDATA;
memcpy(&dp[ofs], &pp[ofs], len + 1);
ofs += len + 1;
}
} while (ofs < frame_width);
if (ofs > frame_width) {
- av_log(s->avctx, AV_LOG_ERROR, "VMD video: offset > width (%d > %d)\n",
+ av_log(s->avctx, AV_LOG_ERROR, "offset > width (%d > %d)\n",
ofs, frame_width);
}
dp += frame->linesize[0];
@@ -342,6 +346,8 @@ static void vmd_decode(VmdVideoContext *s, AVFrame *frame)
break;
}
}
+
+ return 0;
}
static av_cold int vmdvideo_decode_init(AVCodecContext *avctx)
@@ -359,16 +365,16 @@ 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;
s->unpack_buffer_size = AV_RL32(&vmd_header[800]);
s->unpack_buffer = av_malloc(s->unpack_buffer_size);
if (!s->unpack_buffer)
- return -1;
+ return AVERROR(ENOMEM);
/* load up the initial palette */
raw_palette = &vmd_header[28];
@@ -380,6 +386,8 @@ static av_cold int vmdvideo_decode_init(AVCodecContext *avctx)
palette32[i] = (r << 16) | (g << 8) | (b);
}
+ avcodec_get_frame_defaults(&s->prev_frame);
+
return 0;
}
@@ -399,12 +407,11 @@ static int vmdvideo_decode_frame(AVCodecContext *avctx,
if (buf_size < 16)
return buf_size;
- 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;
- }
- vmd_decode(s, frame);
+ if (vmd_decode(s, frame) < 0)
+ av_log(avctx, AV_LOG_WARNING, "decode error\n");
/* make the palette available on the way out */
memcpy(frame->data[1], s->palette, PALETTE_COUNT * 4);
@@ -468,7 +475,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);
}
@@ -571,10 +578,8 @@ 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];
@@ -593,7 +598,7 @@ static int vmdaudio_decode_frame(AVCodecContext *avctx, void *data,
/* decode audio chunks */
if (audio_chunks > 0) {
buf_end = buf + buf_size;
- while (buf + s->chunk_size <= buf_end) {
+ 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 d060d5b..99571a1 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
*/
@@ -296,10 +296,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
const uint8_t *src = buf;
int dx, dy, w, h, depth, enc, chunks, res, size_left, ret;
- if ((ret = ff_reget_buffer(avctx, &c->pic)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, &c->pic)) < 0)
return ret;
- }
c->pic.key_frame = 0;
c->pic.pict_type = AV_PICTURE_TYPE_P;
@@ -332,6 +330,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
src += 2;
chunks = AV_RB16(src); src += 2;
while(chunks--) {
+ if(buf_size - (src - buf) < 12) {
+ av_log(avctx, AV_LOG_ERROR, "Premature end of data!\n");
+ return -1;
+ }
dx = AV_RB16(src); src += 2;
dy = AV_RB16(src); src += 2;
w = AV_RB16(src); src += 2;
@@ -341,6 +343,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
size_left = buf_size - (src - buf);
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", 2 + w * h * c->bpp2 * 2, size_left);
return -1;
@@ -472,6 +478,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
c->bpp = avctx->bits_per_coded_sample;
c->bpp2 = c->bpp/8;
+ avcodec_get_frame_defaults(&c->pic);
switch(c->bpp){
case 8:
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..22e0461 100644
--- a/libavcodec/vorbis_parser.c
+++ b/libavcodec/vorbis_parser.c
@@ -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/vorbisdec.c b/libavcodec/vorbisdec.c
index be2e38d..ba5b1a3 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"
@@ -42,9 +47,6 @@
#define V_MAX_VLCS (1 << 16)
#define V_MAX_PARTITIONS (1 << 20)
-#undef NDEBUG
-#include <assert.h>
-
typedef struct {
uint8_t dimensions;
uint8_t lookup_type;
@@ -192,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);
}
@@ -416,6 +422,11 @@ static int vorbis_parse_setup_hdr_codebooks(vorbis_context *vc)
}
// Initialize VLC table
+ if (entries <= 0) {
+ av_log(vc->avctx, AV_LOG_ERROR, "Invalid codebook entry count\n");
+ ret = AVERROR_INVALIDDATA;
+ goto error;
+ }
if (ff_vorbis_len2vlc(tmp_vlc_bits, tmp_vlc_codes, entries)) {
av_log(vc->avctx, AV_LOG_ERROR, " Invalid code lengths while generating vlcs. \n");
ret = AVERROR_INVALIDDATA;
@@ -695,7 +706,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",
@@ -964,12 +975,12 @@ static int vorbis_parse_id_hdr(vorbis_context *vc)
vc->bitrate_minimum = get_bits_long(gb, 32);
bl0 = get_bits(gb, 4);
bl1 = get_bits(gb, 4);
- vc->blocksize[0] = (1 << bl0);
- vc->blocksize[1] = (1 << bl1);
if (bl0 > 13 || bl0 < 6 || bl1 > 13 || bl1 < 6 || bl1 < bl0) {
av_log(vc->avctx, AV_LOG_ERROR, " Vorbis id header packet corrupt (illegal blocksize). \n");
return AVERROR_INVALIDDATA;
}
+ vc->blocksize[0] = (1 << bl0);
+ vc->blocksize[1] = (1 << bl1);
vc->win[0] = ff_vorbis_vwin[bl0 - 6];
vc->win[1] = ff_vorbis_vwin[bl1 - 6];
@@ -1188,7 +1199,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;
@@ -1204,20 +1215,20 @@ 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));
@@ -1353,7 +1364,7 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc,
av_dlog(NULL, "Classword: %u\n", temp);
- assert(vr->classifications > 1 && temp <= 65536); //needed for inverse[]
+ av_assert0(vr->classifications > 1 && temp <= 65536); //needed for inverse[]
for (i = 0; i < c_p_c; ++i) {
unsigned temp2;
@@ -1682,12 +1693,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 34cfe32..5842cfd 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 db0394a..d685996 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
*/
@@ -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 0211537..5bf2fee 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));
@@ -1573,19 +1579,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,
@@ -1693,7 +1693,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 +1712,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 +1958,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 +2028,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 +2058,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;
@@ -2198,7 +2225,7 @@ static int theora_decode_header(AVCodecContext *avctx, GetBitContext *gb)
fps.num = get_bits_long(gb, 32);
fps.den = get_bits_long(gb, 32);
- if (fps.num && fps.den) {
+ if (fps.num>0 && fps.den>0) {
av_reduce(&avctx->time_base.num, &avctx->time_base.den,
fps.den, fps.num, 1<<30);
}
@@ -2222,6 +2249,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 */
}
@@ -2363,6 +2394,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)
@@ -2396,7 +2429,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 1415428..4eecbe3 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 b0ca926..c707295 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
*/
@@ -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;
@@ -485,9 +485,14 @@ static int vp56_size_changed(AVCodecContext *avctx)
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 +500,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,150 +513,177 @@ 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, 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 (s->has_alpha) {
+ 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 (s->has_alpha) {
+ 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, s->has_alpha + 1);
+
+ if ((res = av_frame_ref(data, p)) < 0)
+ return res;
+ *got_frame = 1;
- if (s->parse_coeff_models(s))
- goto next;
+ return avpkt->size;
+}
- 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;
+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, stride_y, stride_uv;
+ int res;
- 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;
+ if (p->key_frame) {
+ p->pict_type = AV_PICTURE_TYPE_I;
+ s->default_models_init(s);
+ for (block=0; block<s->mb_height*s->mb_width; block++)
+ s->macroblocks[block].type = VP56_MB_INTRA;
+ } else {
+ p->pict_type = AV_PICTURE_TYPE_P;
+ vp56_parse_mb_type_models(s);
+ s->parse_vector_models(s);
+ s->mb_type = VP56_MB_INTER_NOVEC_PF;
+ }
+
+ if (s->parse_coeff_models(s))
+ goto next;
+
+ 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];
- 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;
@@ -680,10 +713,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;
@@ -700,6 +737,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 553a625..4b0f5e1 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
*/
@@ -55,7 +55,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;
@@ -111,6 +111,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 */
@@ -165,8 +166,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;
@@ -179,7 +183,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);
@@ -340,15 +347,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);
@@ -356,15 +361,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 90e2f36..5500fe0 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 ee38322..3cafaaf 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 9929530..8c17fd9 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 034e2e9..51e8c16 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 54dc378..6e385ce 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;
@@ -99,6 +98,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;
@@ -110,7 +110,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)
@@ -589,6 +589,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;
@@ -598,6 +600,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;
@@ -605,16 +622,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]);
@@ -623,7 +653,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 = {
@@ -660,6 +689,6 @@ 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,
.long_name = NULL_IF_CONFIG_SMALL("On2 VP6 (Flash version, with alpha channel)"),
};
diff --git a/libavcodec/vp6data.h b/libavcodec/vp6data.h
index 9a11f89..3ebfd0e 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 0687648..553e5c8 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
*/
@@ -116,7 +116,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 +384,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 +700,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;
@@ -1912,10 +1913,8 @@ static int 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) {
@@ -2099,6 +2098,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 vp8_decode_frame(avctx, data, data_size, &pkt);
+}
+
AVCodec ff_vp8_decoder = {
.name = "vp8",
.type = AVMEDIA_TYPE_VIDEO,
@@ -2113,3 +2158,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",
+ .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,
+ .long_name = NULL_IF_CONFIG_SMALL("WebP"),
+ .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 8631c8f..90109ad 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
*/
@@ -37,6 +37,8 @@
#include <pthread.h>
#elif HAVE_W32THREADS
#include "w32pthreads.h"
+#elif HAVE_OS2THREADS
+#include "os2threads.h"
#endif
#define VP8_MAX_QUANT 127
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 b0e54b6..39d8038 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
*/
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/vqavideo.c b/libavcodec/vqavideo.c
index ed4d814..a47e2db 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,12 +128,16 @@ 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);
}
/* load up the VQA parameters from the header */
s->vqa_version = s->avctx->extradata[0];
+ if (s->vqa_version < 1 || s->vqa_version > 3) {
+ av_log(s->avctx, AV_LOG_ERROR, "unsupported version %d\n", s->vqa_version);
+ return AVERROR_PATCHWELCOME;
+ }
s->width = AV_RL16(&s->avctx->extradata[6]);
s->height = AV_RL16(&s->avctx->extradata[8]);
if ((ret = av_image_check_size(s->width, s->height, 0, avctx)) < 0) {
@@ -151,8 +155,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;
}
@@ -197,22 +200,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;
@@ -221,26 +224,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++)
@@ -249,9 +252,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;
@@ -259,8 +262,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++)
@@ -270,16 +273,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++)
@@ -294,7 +297,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
@@ -366,7 +369,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,
@@ -383,7 +386,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;
}
@@ -401,7 +404,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;
}
@@ -410,7 +413,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;
}
}
@@ -418,7 +422,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;
}
@@ -427,7 +431,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;
}
@@ -439,7 +443,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;
}
@@ -451,13 +455,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;
@@ -520,7 +524,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;
}
@@ -541,7 +545,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,
@@ -570,12 +574,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;
@@ -596,10 +598,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/w32pthreads.h b/libavcodec/w32pthreads.h
index 91e7353..29185c7 100644
--- a/libavcodec/w32pthreads.h
+++ b/libavcodec/w32pthreads.h
@@ -39,6 +39,7 @@
#include <windows.h>
#include <process.h>
+#include "libavutil/common.h"
#include "libavutil/internal.h"
#include "libavutil/mem.h"
diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c
index 37e8768..481d323 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
*/
@@ -47,6 +47,8 @@
#define WV_FLT_ZERO_SENT 0x08
#define WV_FLT_ZERO_SIGN 0x10
+#define WV_MAX_SAMPLES 131072
+
enum WP_ID_Flags {
WP_IDF_MASK = 0x1F,
WP_IDF_IGNORE = 0x20,
@@ -371,6 +373,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;
@@ -784,6 +790,11 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
return -1;
}
+ if (wc->ch_offset >= avctx->channels) {
+ av_log(avctx, AV_LOG_ERROR, "too many channels\n");
+ return -1;
+ }
+
memset(s->decorr, 0, MAX_TERMS * sizeof(Decorr));
memset(s->ch, 0, sizeof(s->ch));
s->extra_bits = 0;
@@ -796,6 +807,10 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
*got_frame_ptr = 0;
return 0;
}
+ if (s->samples > wc->samples) {
+ av_log(avctx, AV_LOG_ERROR, "too many samples in block");
+ return -1;
+ }
} else {
s->samples = wc->samples;
}
@@ -891,7 +906,7 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
continue;
}
t = 0;
- for (i = s->terms - 1; (i >= 0) && (t < size); i--) {
+ for (i = s->terms - 1; (i >= 0) && (t < size) && buf <= buf_end; i--) {
if (s->decorr[i].value > 8) {
s->decorr[i].samplesA[0] = wp_exp2(AV_RL16(buf)); buf += 2;
s->decorr[i].samplesA[1] = wp_exp2(AV_RL16(buf)); buf += 2;
@@ -906,7 +921,7 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
s->decorr[i].samplesB[0] = wp_exp2(AV_RL16(buf)); buf += 2;
t += 4;
} else {
- for (j = 0; j < s->decorr[i].value; j++) {
+ for (j = 0; j < s->decorr[i].value && buf+1<buf_end; j++) {
s->decorr[i].samplesA[j] = wp_exp2(AV_RL16(buf)); buf += 2;
if (s->stereo_in) {
s->decorr[i].samplesB[j] = wp_exp2(AV_RL16(buf)); buf += 2;
@@ -1188,7 +1203,7 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
frame_flags = AV_RL32(buf + 4);
}
}
- 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(EINVAL);
@@ -1204,11 +1219,10 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
}
/* 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_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
+ frame->nb_samples = s->samples;
while (buf_size > 0) {
if (!s->multichannel) {
@@ -1226,13 +1240,13 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
av_log(avctx, AV_LOG_ERROR, "Block %d has invalid size (size %d "
"vs. %d bytes left)\n", s->block, frame_size, buf_size);
wavpack_decode_flush(avctx);
- return -1;
+ return AVERROR_INVALIDDATA;
}
if ((samplecount = wavpack_decode_block(avctx, s->block,
frame->data[0], got_frame_ptr,
buf, frame_size)) < 0) {
wavpack_decode_flush(avctx);
- return -1;
+ return AVERROR_INVALIDDATA;
}
s->block++;
buf += frame_size; buf_size -= frame_size;
diff --git a/libavcodec/webvttdec.c b/libavcodec/webvttdec.c
new file mode 100644
index 0000000..6b86bed
--- /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 db27646..b6dab4b 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.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 b9b176e..d46eb33 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){
@@ -812,7 +824,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 +833,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 +926,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 +941,7 @@ static av_cold void flush(AVCodecContext *avctx)
s->last_superframe_len= 0;
}
+#if CONFIG_WMAV1_DECODER
AVCodec ff_wmav1_decoder = {
.name = "wmav1",
.type = AVMEDIA_TYPE_AUDIO,
@@ -940,7 +956,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",
.type = AVMEDIA_TYPE_AUDIO,
@@ -955,3 +972,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 f5bdb67..d061cde 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;
@@ -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,27 @@ 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");
- return AVERROR(EINVAL);
- }
- assert((put_bits_count(&s->pb) & 7) == 0);
- while (i++)
+ while(total_gain <= 128 && error > 0)
+ error = encode_frame(s, s->coefs, avpkt->data, avpkt->size, total_gain++);
+ 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 +393,7 @@ static int encode_superframe(AVCodecContext *avctx, AVPacket *avpkt,
return 0;
}
+#if CONFIG_WMAV1_ENCODER
AVCodec ff_wmav1_encoder = {
.name = "wmav1",
.type = AVMEDIA_TYPE_AUDIO,
@@ -427,7 +406,8 @@ AVCodec ff_wmav1_encoder = {
AV_SAMPLE_FMT_NONE },
.long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio 1"),
};
-
+#endif
+#if CONFIG_WMAV2_ENCODER
AVCodec ff_wmav2_encoder = {
.name = "wmav2",
.type = AVMEDIA_TYPE_AUDIO,
@@ -440,3 +420,4 @@ AVCodec ff_wmav2_encoder = {
AV_SAMPLE_FMT_NONE },
.long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio 2"),
};
+#endif
diff --git a/libavcodec/wmalosslessdec.c b/libavcodec/wmalosslessdec.c
index 7c08f1b..90a0109 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;
@@ -501,9 +501,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++) {
@@ -521,7 +521,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;
}
@@ -951,7 +951,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]) {
@@ -1018,8 +1018,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;
}
@@ -1265,8 +1263,9 @@ static int decode_packet(AVCodecContext *avctx, void *data, int *got_frame_ptr,
save_bits(s, gb, remaining_bits(s, gb), 0);
}
- *(AVFrame *)data = s->frame;
*got_frame_ptr = s->frame.nb_samples > 0;
+ av_frame_move_ref(data, &s->frame);
+
s->packet_offset = get_bits_count(gb) & 7;
return (s->packet_loss) ? AVERROR_INVALIDDATA : get_bits_count(gb) >> 3;
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 6a64641..a71a67e 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
*/
@@ -336,6 +336,12 @@ static av_cold int decode_init(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
}
+ if (s->min_samples_per_subframe < (1<<WMAPRO_BLOCK_MIN_BITS)) {
+ av_log(avctx, AV_LOG_ERROR, "min_samples_per_subframe of %d too small\n",
+ s->min_samples_per_subframe);
+ return AVERROR_INVALIDDATA;
+ }
+
if (s->avctx->sample_rate <= 0) {
av_log(avctx, AV_LOG_ERROR, "invalid sample rate\n");
return AVERROR_INVALIDDATA;
@@ -412,6 +418,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;
+ }
}
@@ -1133,7 +1143,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) {
@@ -1163,6 +1173,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;
@@ -1173,7 +1184,7 @@ 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 > WMAPRO_BLOCK_MAX_SIZE) {
+ 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;
}
@@ -1369,7 +1380,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;
}
@@ -1442,7 +1452,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) {
@@ -1451,7 +1461,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");
@@ -1571,7 +1581,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 b9a4ad9..1bf2497 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"
@@ -515,7 +513,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 {
@@ -775,7 +773,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);
@@ -1242,7 +1240,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) {
@@ -1278,7 +1276,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;
@@ -1438,8 +1436,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;
@@ -1656,7 +1654,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)
@@ -1801,10 +1799,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];
@@ -1936,7 +1932,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. */
@@ -1991,7 +1987,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 4420f49..918d438 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
*/
@@ -116,7 +116,6 @@ 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,
@@ -124,7 +123,6 @@ void ff_mspel_motion(MpegEncContext *s,
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);
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 f16b6de..099cc36 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 930ee9a..23b64a7 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 418c5f7..162dd1f 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
*/
@@ -70,6 +70,11 @@ 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, "buf_size %d is too small\n", buf_size);
+ return AVERROR_INVALIDDATA;
+ }
+
rbuf = av_malloc(buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
if (!rbuf) {
av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer\n");
@@ -77,7 +82,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;
}
diff --git a/libavcodec/ws-snd1.c b/libavcodec/ws-snd1.c
index 14a9335..d27df75 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 d58ec84..4295744 100644
--- a/libavcodec/x86/Makefile
+++ b/libavcodec/x86/Makefile
@@ -18,9 +18,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
@@ -29,6 +31,7 @@ OBJS-$(CONFIG_VP3DSP) += x86/vp3dsp_init.o
OBJS-$(CONFIG_VP5_DECODER) += x86/vp56dsp_init.o
OBJS-$(CONFIG_VP6_DECODER) += x86/vp56dsp_init.o
OBJS-$(CONFIG_VP8_DECODER) += x86/vp8dsp_init.o
+OBJS-$(CONFIG_WEBP_DECODER) += x86/vp8dsp_init.o
OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o
MMX-OBJS-$(CONFIG_DSPUTIL) += x86/dsputil_init.o \
@@ -42,14 +45,19 @@ MMX-OBJS-$(CONFIG_DSPUTIL) += x86/dsputil_init.o \
MMX-OBJS-$(CONFIG_ENCODERS) += x86/dsputilenc_mmx.o \
x86/motion_est.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-$(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 \
@@ -77,15 +85,18 @@ 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/vp56dsp.o
YASM-OBJS-$(CONFIG_VP8_DECODER) += x86/vp8dsp.o
+YASM-OBJS-$(CONFIG_WEBP_DECODER) += x86/vp8dsp.o
YASM-OBJS += x86/deinterlace.o \
x86/fmtconvert.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 a6f9340..db1505e 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 a74cf0b..2c9f77e 100644
--- a/libavcodec/x86/cabac.h
+++ b/libavcodec/x86/cabac.h
@@ -73,10 +73,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 +90,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 +132,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"\
@@ -155,7 +150,8 @@
#endif /* BROKEN_RELOCATIONS */
-#if HAVE_7REGS
+#if HAVE_7REGS && !(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 get_cabac_inline get_cabac_inline_x86
static av_always_inline int get_cabac_inline_x86(CABACContext *c,
uint8_t *const state)
@@ -178,11 +174,12 @@ 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;
@@ -211,10 +208,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"
diff --git a/libavcodec/x86/cavsdsp.c b/libavcodec/x86/cavsdsp.c
index 6827346..0354333 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/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
--- /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
--- /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
--- /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
--- /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
--- /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 9f71c82..349fbb0 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 c2bf403..7b49fd6 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
*/
@@ -542,24 +545,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 */
@@ -577,16 +567,6 @@ static av_cold void dsputil_init_mmx(DSPContext *c, AVCodecContext *avctx,
static av_cold void dsputil_init_mmxext(DSPContext *c, AVCodecContext *avctx,
int mm_flags)
{
-#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) {
- c->idct_put = ff_idct_xvid_mmxext_put;
- c->idct_add = ff_idct_xvid_mmxext_add;
- c->idct = ff_idct_xvid_mmxext;
- }
-#endif /* HAVE_MMXEXT_INLINE */
-
#if HAVE_MMXEXT_EXTERNAL
SET_QPEL_FUNCS(avg_qpel, 0, 16, mmxext, );
SET_QPEL_FUNCS(avg_qpel, 1, 8, mmxext, );
@@ -627,6 +607,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,
@@ -695,8 +681,37 @@ av_cold void ff_dsputil_init_mmx(DSPContext *c, AVCodecContext *avctx)
c->add_hfyu_median_prediction = ff_add_hfyu_median_prediction_cmov;
#endif
- if (mm_flags & AV_CPU_FLAG_MMX)
+ if (mm_flags & AV_CPU_FLAG_MMX) {
+#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) {
+ if (mm_flags & AV_CPU_FLAG_SSE2) {
+ c->idct_put = ff_idct_xvid_sse2_put;
+ c->idct_add = ff_idct_xvid_sse2_add;
+ c->idct = ff_idct_xvid_sse2;
+ c->idct_permutation_type = FF_SSE2_IDCT_PERM;
+ } else if (mm_flags & AV_CPU_FLAG_MMXEXT) {
+ c->idct_put = ff_idct_xvid_mmxext_put;
+ c->idct_add = ff_idct_xvid_mmxext_add;
+ c->idct = ff_idct_xvid_mmxext;
+ } else {
+ 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, mm_flags);
+ }
if (mm_flags & AV_CPU_FLAG_MMXEXT)
dsputil_init_mmxext(c, avctx, mm_flags);
diff --git a/libavcodec/x86/dsputil_mmx.c b/libavcodec/x86/dsputil_mmx.c
index b0e48e3..421a6c2 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
@@ -317,7 +320,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"
@@ -338,6 +341,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) */
@@ -383,10 +405,15 @@ 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, const uint8_t *src,
+ ptrdiff_t 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);
@@ -401,19 +428,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);
@@ -421,6 +453,10 @@ void ff_gmc_mmx(uint8_t *dst, uint8_t *src,
}
src += ix + iy * stride;
+ if (need_emu) {
+ emu_edge_fn(edge_buf, src, stride, w + 1, h + 1, ix, iy, width, height);
+ src = edge_buf;
+ }
__asm__ volatile (
"movd %0, %%mm6 \n\t"
@@ -499,6 +535,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.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 8537f7a..51026d1 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
--- /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 bd76648..d35245d 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 c87752b..5071741 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
+
struc FFTContext
.nbits: resd 1
.reverse: resd 1
@@ -51,8 +53,6 @@ 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
@@ -305,6 +305,7 @@ IF%1 mova Z(1), m5
INIT_YMM avx
+%if HAVE_AVX_EXTERNAL
align 16
fft8_avx:
mova m0, Z(0)
@@ -394,6 +395,8 @@ fft32_interleave_avx:
jg .deint_loop
ret
+%endif
+
INIT_XMM sse
align 16
@@ -537,6 +540,7 @@ DEFINE_ARGS zc, w, n, o1, o3
INIT_YMM avx
+%if HAVE_AVX_EXTERNAL
%macro INTERL_AVX 5
vunpckhps %3, %2, %1
vunpcklps %2, %2, %1
@@ -558,6 +562,7 @@ cglobal fft_calc, 2,5,8
FFT_DISPATCH _interleave %+ SUFFIX, r1
REP_RET
+%endif
INIT_XMM sse
@@ -776,9 +781,11 @@ align 8
dispatch_tab %+ fullsuffix: pointer list_of_fft
%endmacro ; DECL_FFT
+%if HAVE_AVX_EXTERNAL
INIT_YMM avx
DECL_FFT 6
DECL_FFT 6, _interleave
+%endif
INIT_XMM sse
DECL_FFT 5
DECL_FFT 5, _interleave
@@ -1080,4 +1087,7 @@ DECL_IMDCT POSROTATESHUF_3DNOW
%endif
INIT_YMM avx
+
+%if HAVE_AVX_EXTERNAL
DECL_IMDCT POSROTATESHUF_AVX
+%endif
diff --git a/libavcodec/x86/fft.h b/libavcodec/x86/fft.h
index 6e80b95..3f8b21d 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 77f5ba9..bfa7947 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 8267bd4..1bd13fc 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 24c81bd..91a4cb7 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..b850551 100644
--- a/libavcodec/x86/h264_chromamc_10bit.asm
+++ b/libavcodec/x86/h264_chromamc_10bit.asm
@@ -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 fc6c983..d58e16c 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
;******************************************************************************
@@ -389,8 +389,10 @@ cglobal deblock_h_luma_8, 5,9
INIT_XMM sse2
DEBLOCK_LUMA
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
DEBLOCK_LUMA
+%endif
%else
@@ -502,8 +504,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
@@ -773,8 +777,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
@@ -835,7 +841,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..d63ca02 100644
--- a/libavcodec/x86/h264_deblock_10bit.asm
+++ b/libavcodec/x86/h264_deblock_10bit.asm
@@ -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 3ced8af..17bf794 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..88fdb84 100644
--- a/libavcodec/x86/h264_idct_10bit.asm
+++ b/libavcodec/x86/h264_idct_10bit.asm
@@ -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..db2b25c 100644
--- a/libavcodec/x86/h264_intrapred_10bit.asm
+++ b/libavcodec/x86/h264_intrapred_10bit.asm
@@ -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 84ffd4f..f5b5e3e 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 b00983e..c4fdf5b 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_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/h264chroma_init.c b/libavcodec/x86/h264chroma_init.c
index 1ed34c0..c07fe94 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 cfd8bb9..0255c03 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 mm_flags = av_get_cpu_flags();
if (chroma_format_idc == 1 && EXTERNAL_MMXEXT(mm_flags))
@@ -370,4 +371,5 @@ av_cold void ff_h264dsp_init_x86(H264DSPContext *c, const int bit_depth,
}
}
}
+#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 14be9a5..b3e0d11 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>
@@ -254,7 +254,7 @@ void ff_hpeldsp_init_x86(HpelDSPContext *c, int flags)
{
int mm_flags = av_get_cpu_flags();
- if (mm_flags & AV_CPU_FLAG_MMX)
+ if (HAVE_MMX && mm_flags & AV_CPU_FLAG_MMX)
hpeldsp_init_mmx(c, flags, mm_flags);
if (mm_flags & AV_CPU_FLAG_MMXEXT)
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 7c97b95..f66519b 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 da2c772..ee2a08d 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 7a37b88..7dd35d4c 100644
--- a/libavcodec/x86/lpc.c
+++ b/libavcodec/x86/lpc.c
@@ -2,27 +2,26 @@
* 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/x86/asm.h"
#include "libavutil/attributes.h"
#include "libavutil/cpu.h"
-#include "libavutil/internal.h"
#include "libavutil/mem.h"
#include "libavcodec/lpc.h"
diff --git a/libavcodec/x86/mathops.h b/libavcodec/x86/mathops.h
index 32c8870..e8eb274 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 7bd2c12..81cab5a 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/x86/asm.h"
#include "libavcodec/mlpdsp.h"
#include "libavcodec/mlp.h"
diff --git a/libavcodec/x86/motion_est.c b/libavcodec/x86/motion_est.c
index 8ef7211..416cbb0 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 "dsputil_x86.h"
@@ -40,7 +40,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"
@@ -203,7 +203,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"
@@ -241,7 +241,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"
@@ -331,7 +331,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":);\
\
@@ -341,7 +341,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"\
@@ -355,7 +355,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"\
@@ -369,7 +369,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"\
::);\
@@ -466,7 +466,7 @@ av_cold void ff_dsputil_init_pix_mmx(DSPContext *c, AVCodecContext *avctx)
c->pix_abs[1][3] = sad8_xy2_mmxext;
}
}
- if ((mm_flags & AV_CPU_FLAG_SSE2) && !(mm_flags & AV_CPU_FLAG_3DNOW)) {
+ if ((mm_flags & AV_CPU_FLAG_SSE2) && !(mm_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 79a29ce..287d8ff 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 68f3b62..f8cabe5 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
*/
@@ -35,7 +35,7 @@ static void dct_unquantize_h263_intra_mmx(MpegEncContext *s,
qmul = qscale << 1;
- assert(s->block_last_index[n]>=0 || s->h263_aic);
+ av_assert2(s->block_last_index[n]>=0 || s->h263_aic);
if (!s->h263_aic) {
if (n < 4)
@@ -111,7 +111,7 @@ static void dct_unquantize_h263_inter_mmx(MpegEncContext *s,
qmul = qscale << 1;
qadd = (qscale - 1) | 1;
- assert(s->block_last_index[n]>=0 || s->h263_aic);
+ av_assert2(s->block_last_index[n]>=0 || s->h263_aic);
nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ];
@@ -171,7 +171,7 @@ static void dct_unquantize_mpeg1_intra_mmx(MpegEncContext *s,
const uint16_t *quant_matrix;
int block0;
- assert(s->block_last_index[n]>=0);
+ av_assert2(s->block_last_index[n]>=0);
nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]+1;
@@ -239,7 +239,7 @@ static void dct_unquantize_mpeg1_inter_mmx(MpegEncContext *s,
x86_reg nCoeffs;
const uint16_t *quant_matrix;
- assert(s->block_last_index[n]>=0);
+ av_assert2(s->block_last_index[n]>=0);
nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]+1;
@@ -306,7 +306,7 @@ static void dct_unquantize_mpeg2_intra_mmx(MpegEncContext *s,
const uint16_t *quant_matrix;
int block0;
- assert(s->block_last_index[n]>=0);
+ av_assert2(s->block_last_index[n]>=0);
if(s->alternate_scan) nCoeffs= 63; //FIXME
else nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ];
@@ -371,7 +371,7 @@ static void dct_unquantize_mpeg2_inter_mmx(MpegEncContext *s,
x86_reg nCoeffs;
const uint16_t *quant_matrix;
- assert(s->block_last_index[n]>=0);
+ av_assert2(s->block_last_index[n]>=0);
if(s->alternate_scan) nCoeffs= 63; //FIXME
else nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ];
diff --git a/libavcodec/x86/mpegvideoenc.c b/libavcodec/x86/mpegvideoenc.c
index b1b22f5..c841bcc 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_init.c b/libavcodec/x86/pngdsp_init.c
index ec6c238..4c54ed3 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 8bff85f..47fe7a4 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 flags = av_get_cpu_flags();
+ if(avctx->flags & CODEC_FLAG_BITEXACT)
+ return;
+
if (EXTERNAL_SSE2(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/rv40dsp_init.c b/libavcodec/x86/rv40dsp_init.c
index a90f57f..6e0f69e 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..fc519bf 100644
--- a/libavcodec/x86/sbrdsp.asm
+++ b/libavcodec/x86/sbrdsp.asm
@@ -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 e2eaa70..0bc4a61 100644
--- a/libavcodec/x86/sbrdsp_init.c
+++ b/libavcodec/x86/sbrdsp_init.c
@@ -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 mm_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(mm_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..c790ef5 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"
diff --git a/libavcodec/x86/snowdsp.c b/libavcodec/x86/snowdsp.c
new file mode 100644
index 0000000..735e790
--- /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
--- /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..5473126
--- /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 Libav.
+;*
+;* Libav is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* Libav is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with Libav; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+
+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 adf08d7d..546688c 100644
--- a/libavcodec/x86/vc1dsp.asm
+++ b/libavcodec/x86/vc1dsp.asm
@@ -2,20 +2,20 @@
;* VC1 deblocking optimizations
;* Copyright (c) 2009 David Conrad
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavcodec/x86/vc1dsp.h b/libavcodec/x86/vc1dsp.h
index 9b6c8ad..fdd4de1 100644
--- a/libavcodec/x86/vc1dsp.h
+++ b/libavcodec/x86/vc1dsp.h
@@ -1,20 +1,20 @@
/*
* VC-1 and WMV3 decoder - X86 DSP init functions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/vc1dsp_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..3f2f01a 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
;******************************************************************************
diff --git a/libavcodec/x86/videodsp_init.c b/libavcodec/x86/videodsp_init.c
index 48f42d5..902450e 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"
@@ -36,19 +38,25 @@ 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,
+ ptrdiff_t linesize_arg,
int block_w, int block_h,
int src_x, int src_y,
int w, int h,
emu_edge_core_func *core_fn)
{
int start_y, start_x, end_y, end_x, src_y_add = 0;
+ int linesize = linesize_arg;
+
+ if(!w || !h)
+ return;
if (src_y >= h) {
- src_y_add = h - 1 - src_y;
+ src -= src_y*linesize;
+ 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*linesize;
+ src_y_add = 1 - block_h;
src_y = 1 - block_h;
}
if (src_x >= w) {
@@ -63,8 +71,8 @@ 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;
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 762d3ee..08a2c09 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 cc52fbc..252b40a 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_INLINE_ASM
+
+#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_INLINE_ASM */
+
av_cold void ff_vp3dsp_init_x86(VP3DSPContext *c, int flags)
{
int cpuflags = av_get_cpu_flags();
+#if HAVE_INLINE_ASM
+ c->put_no_rnd_pixels_l2 = put_vp_no_rnd_pixels8_l2_mmx;
+#endif /* HAVE_INLINE_ASM */
+
#if ARCH_X86_32
if (EXTERNAL_MMX(cpuflags)) {
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/vp56dsp.asm b/libavcodec/x86/vp56dsp.asm
index 80f8ca5..3d874ea 100644
--- a/libavcodec/x86/vp56dsp.asm
+++ b/libavcodec/x86/vp56dsp.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/vp56dsp_init.c b/libavcodec/x86/vp56dsp_init.c
index 689ae35..defc63b 100644
--- a/libavcodec/x86/vp56dsp_init.c
+++ b/libavcodec/x86/vp56dsp_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 629a7bc..745d95a 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
*/
diff --git a/libavcodec/x86/w64xmmtest.c b/libavcodec/x86/w64xmmtest.c
index a8b6803..f6e3de9 100644
--- a/libavcodec/x86/w64xmmtest.c
+++ b/libavcodec/x86/w64xmmtest.c
@@ -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 ca2e8e0..41925aa 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,7 +52,7 @@
typedef struct XanContext {
AVCodecContext *avctx;
- AVFrame last_frame;
+ AVFrame *last_frame;
const unsigned char *buf;
int size;
@@ -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,6 +92,11 @@ 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;
}
@@ -233,7 +240,7 @@ static inline void xan_wc3_copy_pixel_run(XanContext *s, AVFrame *frame,
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];
@@ -242,6 +249,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) {
@@ -290,6 +303,7 @@ static int xan_wc3_decode_frame(XanContext *s, AVFrame *frame)
const unsigned char *size_segment;
const unsigned char *vector_segment;
const unsigned char *imagedata_segment;
+ const unsigned char *buf_end = s->buf + s->size;
int huffman_offset, size_offset, vector_offset, imagedata_offset,
imagedata_size;
@@ -361,17 +375,29 @@ static int xan_wc3_decode_frame(XanContext *s, AVFrame *frame)
case 9:
case 19:
+ if (buf_end - size_segment < 1) {
+ av_log(s->avctx, AV_LOG_ERROR, "size_segment overread\n");
+ return AVERROR_INVALIDDATA;
+ }
size = *size_segment++;
break;
case 10:
case 20:
+ if (buf_end - size_segment < 2) {
+ av_log(s->avctx, AV_LOG_ERROR, "size_segment overread\n");
+ return AVERROR_INVALIDDATA;
+ }
size = AV_RB16(&size_segment[0]);
size_segment += 2;
break;
case 11:
case 21:
+ if (buf_end - size_segment < 3) {
+ av_log(s->avctx, AV_LOG_ERROR, "size_segment overread\n");
+ return AVERROR_INVALIDDATA;
+ }
size = AV_RB24(size_segment);
size_segment += 3;
break;
@@ -394,6 +420,10 @@ static int xan_wc3_decode_frame(XanContext *s, AVFrame *frame)
imagedata_size -= size;
}
} else {
+ if (vector_segment >= buf_end) {
+ av_log(s->avctx, AV_LOG_ERROR, "vector_segment overread\n");
+ return AVERROR_INVALIDDATA;
+ }
/* run-based motion compensation from last frame */
motion_x = sign_extend(*vector_segment >> 4, 4);
motion_y = sign_extend(*vector_segment & 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..6b189c0
--- /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",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_XBM,
+ .init = xbm_decode_init,
+ .decode = xbm_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("XBM (X BitMap) image"),
+};
diff --git a/libavcodec/xbmenc.c b/libavcodec/xbmenc.c
index e12debe..e7cec1d 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",
.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 },
.long_name = NULL_IF_CONFIG_SMALL("XBM (X BitMap) image"),
};
diff --git a/libavcodec/xface.c b/libavcodec/xface.c
new file mode 100644
index 0000000..0ebf2f2
--- /dev/null
+++ b/libavcodec/xface.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 1990 James Ashton - Sydney University
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * X-Face common data and utilities definition.
+ */
+
+#include "xface.h"
+
+void ff_big_add(BigInt *b, uint8_t a)
+{
+ int i;
+ uint8_t *w;
+ uint16_t c;
+
+ a &= XFACE_WORDMASK;
+ if (a == 0)
+ return;
+ w = b->words;
+ c = a;
+ for (i = 0; i < b->nb_words && c; i++) {
+ c += *w;
+ *w++ = c & XFACE_WORDMASK;
+ c >>= XFACE_BITSPERWORD;
+ }
+ if (i == b->nb_words && c) {
+ b->nb_words++;
+ *w = c & XFACE_WORDMASK;
+ }
+}
+
+void ff_big_div(BigInt *b, uint8_t a, uint8_t *r)
+{
+ int i;
+ uint8_t *w;
+ uint16_t c, d;
+
+ a &= XFACE_WORDMASK;
+ if (a == 1 || b->nb_words == 0) {
+ *r = 0;
+ return;
+ }
+
+ /* treat this as a == WORDCARRY and just shift everything right a WORD */
+ if (a == 0) {
+ i = --b->nb_words;
+ w = b->words;
+ *r = *w;
+ while (i--) {
+ *w = *(w + 1);
+ w++;
+ }
+ *w = 0;
+ return;
+ }
+ i = b->nb_words;
+ w = b->words + i;
+ c = 0;
+ while (i--) {
+ c <<= XFACE_BITSPERWORD;
+ c += *--w;
+ d = c / (uint16_t)a;
+ c = c % (uint16_t)a;
+ *w = d & XFACE_WORDMASK;
+ }
+ *r = c;
+ if (b->words[b->nb_words - 1] == 0)
+ b->nb_words--;
+}
+
+void ff_big_mul(BigInt *b, uint8_t a)
+{
+ int i;
+ uint8_t *w;
+ uint16_t c;
+
+ a &= XFACE_WORDMASK;
+ if (a == 1 || b->nb_words == 0)
+ return;
+ if (a == 0) {
+ /* treat this as a == WORDCARRY and just shift everything left a WORD */
+ i = b->nb_words++;
+ w = b->words + i;
+ while (i--) {
+ *w = *(w - 1);
+ w--;
+ }
+ *w = 0;
+ return;
+ }
+ i = b->nb_words;
+ w = b->words;
+ c = 0;
+ while (i--) {
+ c += (uint16_t)*w * (uint16_t)a;
+ *(w++) = c & XFACE_WORDMASK;
+ c >>= XFACE_BITSPERWORD;
+ }
+ if (c) {
+ b->nb_words++;
+ *w = c & XFACE_WORDMASK;
+ }
+}
+
+const ProbRange ff_xface_probranges_per_level[4][3] = {
+ // black grey white
+ { { 1, 255}, {251, 0}, { 4, 251} }, /* Top of tree almost always grey */
+ { { 1, 255}, {200, 0}, { 55, 200} },
+ { { 33, 223}, {159, 0}, { 64, 159} },
+ { {131, 0}, { 0, 0}, {125, 131} }, /* Grey disallowed at bottom */
+};
+
+const ProbRange ff_xface_probranges_2x2[16] = {
+ { 0, 0}, {38, 0}, {38, 38}, {13, 152},
+ {38, 76}, {13, 165}, {13, 178}, { 6, 230},
+ {38, 114}, {13, 191}, {13, 204}, { 6, 236},
+ {13, 217}, { 6, 242}, { 5, 248}, { 3, 253},
+};
+
+/*
+ * The "guess the next pixel" tables follow. Normally there are 12
+ * neighbour pixels used to give 1<<12 cases as we get closer to the
+ * upper left corner lesser numbers of neighbours are available.
+ *
+ * Each byte in the tables represents 8 boolean values starting from
+ * the most significant bit.
+ */
+
+static const uint8_t g_00[] = {
+ 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0xe3, 0xdf, 0x05, 0x17,
+ 0x05, 0x0f, 0x00, 0x1b, 0x0f, 0xdf, 0x00, 0x04, 0x00, 0x00,
+ 0x0d, 0x0f, 0x03, 0x7f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1d,
+ 0x45, 0x2f, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x0a, 0xff, 0xff,
+ 0x00, 0x04, 0x00, 0x05, 0x01, 0x3f, 0xcf, 0xff, 0x10, 0x01,
+ 0x80, 0xc9, 0x0f, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x1b, 0x1f, 0xff, 0xff, 0x4f, 0x54, 0x07, 0x1f, 0x57, 0x47,
+ 0xd7, 0x3d, 0xff, 0xff, 0x5f, 0x1f, 0x7f, 0xff, 0x7f, 0x7f,
+ 0x05, 0x0f, 0x01, 0x0f, 0x0f, 0x5f, 0x9b, 0xdf, 0x7f, 0xff,
+ 0x5f, 0x1d, 0x5f, 0xff, 0x0f, 0x1f, 0x0f, 0x5f, 0x03, 0x1f,
+ 0x4f, 0x5f, 0xf7, 0x7f, 0x7f, 0xff, 0x0d, 0x0f, 0xfb, 0xff,
+ 0xf7, 0xbf, 0x0f, 0x4f, 0xd7, 0x3f, 0x4f, 0x7f, 0xff, 0xff,
+ 0x67, 0xbf, 0x56, 0x25, 0x1f, 0x7f, 0x9f, 0xff, 0x00, 0x00,
+ 0x00, 0x05, 0x5f, 0x7f, 0x01, 0xdf, 0x14, 0x00, 0x05, 0x0f,
+ 0x07, 0xa2, 0x09, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x5f,
+ 0x18, 0xd7, 0x94, 0x71, 0x00, 0x05, 0x1f, 0xb7, 0x0c, 0x07,
+ 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x1f, 0x84, 0x8f, 0x05, 0x15,
+ 0x05, 0x0f, 0x4f, 0xff, 0x87, 0xdf, 0x05, 0x01, 0x10, 0x00,
+ 0x0f, 0x0f, 0x00, 0x08, 0x05, 0x04, 0x04, 0x01, 0x4f, 0xff,
+ 0x9f, 0x8f, 0x4a, 0x40, 0x5f, 0x5f, 0xff, 0xfe, 0xdf, 0xff,
+ 0x7f, 0xf7, 0xff, 0x7f, 0xff, 0xff, 0x7b, 0xff, 0x0f, 0xfd,
+ 0xd7, 0x5f, 0x4f, 0x7f, 0x7f, 0xdf, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x77, 0xdf, 0x7f, 0x4f, 0xef, 0xff, 0xff, 0x77, 0xff,
+ 0xff, 0xff, 0x6f, 0xff, 0x0f, 0x4f, 0xff, 0xff, 0x9d, 0xff,
+ 0x0f, 0xef, 0xff, 0xdf, 0x6f, 0xff, 0xff, 0xff, 0x4f, 0xff,
+ 0xcd, 0x0f, 0x4f, 0xff, 0xff, 0xdf, 0x00, 0x00, 0x00, 0x0b,
+ 0x05, 0x02, 0x02, 0x0f, 0x04, 0x00, 0x00, 0x0c, 0x01, 0x06,
+ 0x00, 0x0f, 0x20, 0x03, 0x00, 0x00, 0x05, 0x0f, 0x40, 0x08,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x0c, 0x0f, 0x01, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x14, 0x01, 0x05,
+ 0x01, 0x15, 0xaf, 0x0f, 0x00, 0x01, 0x10, 0x00, 0x08, 0x00,
+ 0x46, 0x0c, 0x20, 0x00, 0x88, 0x00, 0x0f, 0x15, 0xff, 0xdf,
+ 0x02, 0x00, 0x00, 0x0f, 0x7f, 0x5f, 0xdb, 0xff, 0x4f, 0x3e,
+ 0x05, 0x0f, 0x7f, 0xf7, 0x95, 0x4f, 0x0d, 0x0f, 0x01, 0x0f,
+ 0x4f, 0x5f, 0x9f, 0xdf, 0x25, 0x0e, 0x0d, 0x0d, 0x4f, 0x7f,
+ 0x8f, 0x0f, 0x0f, 0xfa, 0x04, 0x4f, 0x4f, 0xff, 0xf7, 0x77,
+ 0x47, 0xed, 0x05, 0x0f, 0xff, 0xff, 0xdf, 0xff, 0x4f, 0x6f,
+ 0xd8, 0x5f, 0x0f, 0x7f, 0xdf, 0x5f, 0x07, 0x0f, 0x94, 0x0d,
+ 0x1f, 0xff, 0xff, 0xff, 0x00, 0x02, 0x00, 0x03, 0x46, 0x57,
+ 0x01, 0x0d, 0x01, 0x08, 0x01, 0x0f, 0x47, 0x6c, 0x0d, 0x0f,
+ 0x02, 0x00, 0x00, 0x00, 0x0b, 0x4f, 0x00, 0x08, 0x05, 0x00,
+ 0x95, 0x01, 0x0f, 0x7f, 0x0c, 0x0f, 0x01, 0x0e, 0x00, 0x00,
+ 0x0f, 0x41, 0x00, 0x00, 0x04, 0x24, 0x0d, 0x0f, 0x0f, 0x7f,
+ 0xcf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00,
+ 0x06, 0x26, 0xcf, 0x05, 0xcf, 0x7f, 0xdf, 0xdf, 0x00, 0x00,
+ 0x17, 0x5f, 0xff, 0xfd, 0xff, 0xff, 0x46, 0x09, 0x4f, 0x5f,
+ 0x7f, 0xfd, 0xdf, 0xff, 0x0a, 0x88, 0xa7, 0x7f, 0x7f, 0xff,
+ 0xff, 0xff, 0x0f, 0x04, 0xdf, 0x7f, 0x4f, 0xff, 0x9f, 0xff,
+ 0x0e, 0xe6, 0xdf, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x0f, 0xec,
+ 0x8f, 0x4f, 0x7f, 0xff, 0xdf, 0xff, 0x0f, 0xcf, 0xdf, 0xff,
+ 0x6f, 0x7f, 0xff, 0xff, 0x03, 0x0c, 0x9d, 0x0f, 0x7f, 0xff,
+ 0xff, 0xff,
+};
+
+static const uint8_t g_01[] = {
+ 0x37, 0x73, 0x00, 0x19, 0x57, 0x7f, 0xf5, 0xfb, 0x70, 0x33,
+ 0xf0, 0xf9, 0x7f, 0xff, 0xff, 0xff,
+};
+
+static const uint8_t g_02[] = {
+ 0x50,
+};
+
+static const uint8_t g_10[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0xf3, 0x5f, 0x84, 0x04,
+ 0x17, 0x9f, 0x04, 0x23, 0x05, 0xff, 0x00, 0x00, 0x00, 0x02,
+ 0x03, 0x03, 0x33, 0xd7, 0x05, 0x03, 0x5f, 0x3f, 0x17, 0x33,
+ 0xff, 0xff, 0x00, 0x80, 0x02, 0x04, 0x12, 0x00, 0x11, 0x57,
+ 0x05, 0x25, 0x05, 0x03, 0x35, 0xbf, 0x9f, 0xff, 0x07, 0x6f,
+ 0x20, 0x40, 0x17, 0x06, 0xfa, 0xe8, 0x01, 0x07, 0x1f, 0x9f,
+ 0x1f, 0xff, 0xff, 0xff,
+};
+
+static const uint8_t g_20[] = {
+ 0x04, 0x00, 0x01, 0x01, 0x43, 0x2e, 0xff, 0x3f,
+};
+
+static const uint8_t g_30[] = {
+ 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, 0x13, 0x11, 0x11, 0x11,
+ 0x13, 0x11, 0x11, 0x11, 0x33, 0x11, 0x13, 0x11, 0x13, 0x13,
+ 0x13, 0x13, 0x31, 0x31, 0x11, 0x01, 0x11, 0x11, 0x71, 0x11,
+ 0x11, 0x75,
+};
+
+static const uint8_t g_40[] = {
+ 0x00, 0x0f, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0f,
+ 0x00, 0x4e, 0xe4, 0x0d, 0x10, 0x0f, 0x00, 0x0f, 0x44, 0x4f,
+ 0x00, 0x1e, 0x0f, 0x0f, 0xae, 0xaf, 0x45, 0x7f, 0xef, 0xff,
+ 0x0f, 0xff, 0x00, 0x09, 0x01, 0x11, 0x00, 0x01, 0x1c, 0xdd,
+ 0x00, 0x15, 0x00, 0xff, 0x00, 0x10, 0x00, 0xfd, 0x00, 0x0f,
+ 0x4f, 0x5f, 0x3d, 0xff, 0xff, 0xff, 0x4f, 0xff, 0x1c, 0xff,
+ 0xdf, 0xff, 0x8f, 0xff, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x15,
+ 0x01, 0x07, 0x00, 0x01, 0x02, 0x1f, 0x01, 0x11, 0x05, 0x7f,
+ 0x00, 0x1f, 0x41, 0x57, 0x1f, 0xff, 0x05, 0x77, 0x0d, 0x5f,
+ 0x4d, 0xff, 0x4f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x02, 0x05,
+ 0x00, 0x11, 0x05, 0x7d, 0x10, 0x15, 0x2f, 0xff, 0x40, 0x50,
+ 0x0d, 0xfd, 0x04, 0x0f, 0x07, 0x1f, 0x07, 0x7f, 0x0f, 0xbf,
+ 0x0d, 0x7f, 0x0f, 0xff, 0x4d, 0x7d, 0x0f, 0xff,
+};
+
+static const uint8_t g_11[] = {
+ 0x01, 0x13, 0x03, 0x7f,
+};
+
+static const uint8_t g_21[] = {
+ 0x17,
+};
+
+static const uint8_t g_31[] = {
+ 0x55, 0x57, 0x57, 0x7f,
+};
+
+static const uint8_t g_41[] = {
+ 0x01, 0x01, 0x01, 0x1f, 0x03, 0x1f, 0x3f, 0xff,
+};
+
+static const uint8_t g_12[] = {
+ 0x40,
+};
+
+static const uint8_t g_22[] = {
+ 0x00,
+};
+
+static const uint8_t g_32[] = {
+ 0x10,
+};
+
+static const uint8_t g_42[] = {
+ 0x10,
+};
+
+void ff_xface_generate_face(uint8_t *dst, uint8_t * const src)
+{
+ int h, i, j, k, l, m;
+
+ for (j = 0; j < XFACE_HEIGHT; j++) {
+ for (i = 0; i < XFACE_WIDTH; i++) {
+ h = i + j * XFACE_WIDTH;
+ k = 0;
+
+ /*
+ Compute k, encoding the bits *before* the current one, contained in the
+ image buffer. That is, given the grid:
+
+ l i
+ | |
+ v v
+ +--+--+--+--+--+
+ m -> | 1| 2| 3| 4| 5|
+ +--+--+--+--+--+
+ | 6| 7| 8| 9|10|
+ +--+--+--+--+--+
+ j -> |11|12| *| | |
+ +--+--+--+--+--+
+
+ the value k for the pixel marked as "*" will contain the bit encoding of
+ the values in the matrix marked from "1" to "12". In case the pixel is
+ near the border of the grid, the number of values contained within the
+ grid will be lesser than 12.
+ */
+
+ for (l = i - 2; l <= i + 2; l++) {
+ for (m = j - 2; m <= j; m++) {
+ if (l >= i && m == j)
+ continue;
+ if (l > 0 && l <= XFACE_WIDTH && m > 0)
+ k = 2*k + src[l + m * XFACE_WIDTH];
+ }
+ }
+
+ /*
+ Use the guess for the given position and the computed value of k.
+
+ The following table shows the number of digits in k, depending on
+ the position of the pixel, and shows the corresponding guess table
+ to use:
+
+ i=1 i=2 i=3 i=w-1 i=w
+ +----+----+----+ ... +----+----+
+ j=1 | 0 | 1 | 2 | | 2 | 2 |
+ |g22 |g12 |g02 | |g42 |g32 |
+ +----+----+----+ ... +----+----+
+ j=2 | 3 | 5 | 7 | | 6 | 5 |
+ |g21 |g11 |g01 | |g41 |g31 |
+ +----+----+----+ ... +----+----+
+ j=3 | 5 | 9 | 12 | | 10 | 8 |
+ |g20 |g10 |g00 | |g40 |g30 |
+ +----+----+----+ ... +----+----+
+ */
+
+#define GEN(table) dst[h] ^= (table[k>>3]>>(7-(k&7)))&1
+
+ switch (i) {
+ case 1:
+ switch (j) {
+ case 1: GEN(g_22); break;
+ case 2: GEN(g_21); break;
+ default: GEN(g_20); break;
+ }
+ break;
+ case 2:
+ switch (j) {
+ case 1: GEN(g_12); break;
+ case 2: GEN(g_11); break;
+ default: GEN(g_10); break;
+ }
+ break;
+ case XFACE_WIDTH - 1:
+ switch (j) {
+ case 1: GEN(g_42); break;
+ case 2: GEN(g_41); break;
+ default: GEN(g_40); break;
+ }
+ break;
+ case XFACE_WIDTH:
+ switch (j) {
+ case 1: GEN(g_32); break;
+ case 2: GEN(g_31); break;
+ default: GEN(g_30); break;
+ }
+ break;
+ default:
+ switch (j) {
+ case 1: GEN(g_02); break;
+ case 2: GEN(g_01); break;
+ default: GEN(g_00); break;
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/libavcodec/xface.h b/libavcodec/xface.h
new file mode 100644
index 0000000..cd59ba0
--- /dev/null
+++ b/libavcodec/xface.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1990 James Ashton - Sydney University
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * X-Face common definitions.
+ */
+
+#include <stdint.h>
+
+/* define the face size - 48x48x1 */
+#define XFACE_WIDTH 48
+#define XFACE_HEIGHT 48
+#define XFACE_PIXELS (XFACE_WIDTH * XFACE_HEIGHT)
+
+/* compressed output uses the full range of printable characters.
+ * In ASCII these are in a contiguous block so we just need to know
+ * the first and last. The total number of printables is needed too. */
+#define XFACE_FIRST_PRINT '!'
+#define XFACE_LAST_PRINT '~'
+#define XFACE_PRINTS (XFACE_LAST_PRINT - XFACE_FIRST_PRINT + 1)
+
+/*
+ * Image is encoded as a big integer, using characters from '~' to
+ * '!', for a total of 92 symbols. In order to express 48x48=2304
+ * bits, we need a total of 354 digits, as given by:
+ * ceil(lg_92(2^2304)) = 354
+ */
+#define XFACE_MAX_DIGITS 354
+
+#define XFACE_BITSPERWORD 8
+#define XFACE_WORDCARRY (1 << XFACE_BITSPERWORD)
+#define XFACE_WORDMASK (XFACE_WORDCARRY - 1)
+
+#define XFACE_MAX_WORDS ((XFACE_PIXELS * 2 + XFACE_BITSPERWORD - 1) / XFACE_BITSPERWORD)
+
+/* Portable, very large unsigned integer arithmetic is needed.
+ * Implementation uses arrays of WORDs. */
+typedef struct {
+ int nb_words;
+ uint8_t words[XFACE_MAX_WORDS];
+} BigInt;
+
+/**
+ * Add a to b storing the result in b.
+ */
+void ff_big_add(BigInt *b, uint8_t a);
+
+/**
+ * Divide b by a storing the result in b and the remainder in the word
+ * pointed to by r.
+ */
+void ff_big_div(BigInt *b, uint8_t a, uint8_t *r);
+
+/**
+ * Multiply a by b storing the result in b.
+ */
+void ff_big_mul(BigInt *b, uint8_t a);
+
+/* Each face is encoded using 9 octrees of 16x16 each. Each level of the
+ * trees has varying probabilities of being white, grey or black.
+ * The table below is based on sampling many faces */
+enum XFaceColor { XFACE_COLOR_BLACK = 0, XFACE_COLOR_GREY, XFACE_COLOR_WHITE };
+
+/* Data of varying probabilities are encoded by a value in the range 0 - 255.
+ * The probability of the data determines the range of possible encodings.
+ * Offset gives the first possible encoding of the range. */
+typedef struct {
+ int range;
+ int offset;
+} ProbRange;
+
+extern const ProbRange ff_xface_probranges_per_level[4][3];
+
+extern const ProbRange ff_xface_probranges_2x2[16];
+
+void ff_xface_generate_face(uint8_t *dst, uint8_t * const src);
diff --git a/libavcodec/xfacedec.c b/libavcodec/xfacedec.c
new file mode 100644
index 0000000..fbaabdb
--- /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",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("X-face image"),
+};
diff --git a/libavcodec/xfaceenc.c b/libavcodec/xfaceenc.c
new file mode 100644
index 0000000..5206afd
--- /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",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("X-face image"),
+};
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 e7948a0..f50b650 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
*/
@@ -33,7 +33,8 @@ static const int xl_table[32] = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 12, 15, 20, 25, 34, 46,
64, 82, 94, 103, 108, 113, 116, 119,
- 120, 121, 122, 123, 124, 125, 126, 127};
+ 120, 121, 122, 123, 124, 125, 126, 127
+};
static int decode_frame(AVCodecContext *avctx,
void *data, int *got_frame,
@@ -48,12 +49,20 @@ static int decode_frame(AVCodecContext *avctx,
uint32_t val;
int y0, y1, y2, y3 = 0, c0 = 0, c1 = 0;
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0){
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return ret;
+ if (avctx->width & 3) {
+ 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;
}
- p->pict_type= AV_PICTURE_TYPE_I;
- p->key_frame= 1;
+
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
+ return ret;
+ p->pict_type = AV_PICTURE_TYPE_I;
+ p->key_frame = 1;
Y = p->data[0];
U = p->data[1];
@@ -61,11 +70,6 @@ static int decode_frame(AVCodecContext *avctx,
stride = avctx->width - 4;
- if (buf_size < avctx->width * avctx->height) {
- av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
- return AVERROR_INVALIDDATA;
- }
-
for (i = 0; i < avctx->height; i++) {
/* lines are stored in reversed order */
buf += stride;
@@ -117,8 +121,9 @@ static int decode_frame(AVCodecContext *avctx,
return buf_size;
}
-static av_cold int decode_init(AVCodecContext *avctx){
- avctx->pix_fmt= AV_PIX_FMT_YUV411P;
+static av_cold int decode_init(AVCodecContext *avctx)
+{
+ avctx->pix_fmt = AV_PIX_FMT_YUV411P;
return 0;
}
diff --git a/libavcodec/xsubdec.c b/libavcodec/xsubdec.c
index 11e1d57..d3367b0 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 816e651..cb2a908 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
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 aa91b3b..66a2fe9 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
*/
@@ -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 c101463..e98de5e 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;
@@ -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,20 +208,11 @@ 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",
.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,
@@ -246,6 +232,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 },
.long_name = NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"),
diff --git a/libavcodec/xxan.c b/libavcodec/xxan.c
index 2bc9ff6..cb913da 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;
@@ -57,7 +59,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);
}
@@ -195,39 +203,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;
@@ -235,16 +249,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]);
}
}
@@ -266,7 +280,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;
}
@@ -286,7 +300,8 @@ static int xan_decode_frame_type0(AVCodecContext *avctx)
ybuf[j+1] = cur << 1;
last = cur;
}
- ybuf[j] = last << 1;
+ if(j < avctx->width)
+ ybuf[j] = last << 1;
prev_buf = ybuf;
ybuf += avctx->width;
@@ -299,7 +314,8 @@ static int xan_decode_frame_type0(AVCodecContext *avctx)
ybuf[j+1] = cur << 1;
last = cur;
}
- ybuf[j] = last << 1;
+ if(j < avctx->width)
+ ybuf[j] = last << 1;
prev_buf = ybuf;
ybuf += avctx->width;
}
@@ -311,17 +327,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;
@@ -356,17 +375,18 @@ static int xan_decode_frame_type1(AVCodecContext *avctx)
ybuf[j+1] = cur;
last = cur;
}
- ybuf[j] = last;
+ if(j < avctx->width)
+ ybuf[j] = last;
ybuf += avctx->width;
}
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;
@@ -380,10 +400,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);
@@ -401,7 +419,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;
@@ -413,7 +431,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..70b68aa
--- /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",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_Y41P,
+ .init = y41p_decode_init,
+ .decode = y41p_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed YUV 4:1:1 12-bit"),
+};
diff --git a/libavcodec/y41penc.c b/libavcodec/y41penc.c
new file mode 100644
index 0000000..1a8f0fb
--- /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",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed YUV 4:1:1 12-bit"),
+};
diff --git a/libavcodec/yop.c b/libavcodec/yop.c
index 3a760c5..807e170 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,12 @@ 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();
+
return 0;
}
@@ -144,8 +156,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 +190,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 +200,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 +213,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 +254,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;
}
@@ -249,7 +267,7 @@ 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,
.long_name = NULL_IF_CONFIG_SMALL("Psygnosis YOP Video"),
- .capabilities = CODEC_CAP_DR1,
};
diff --git a/libavcodec/yuv4dec.c b/libavcodec/yuv4dec.c
new file mode 100644
index 0000000..1d1fdd0
--- /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",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_YUV4,
+ .init = yuv4_decode_init,
+ .decode = yuv4_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:2:0"),
+};
diff --git a/libavcodec/yuv4enc.c b/libavcodec/yuv4enc.c
new file mode 100644
index 0000000..6e2f9bc
--- /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",
+ .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 },
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:2:0"),
+};
diff --git a/libavcodec/zerocodec.c b/libavcodec/zerocodec.c
index e503aa7..4a23b67 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 0b38926..7f3b326 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
*/
@@ -64,6 +64,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 +407,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 +444,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 +488,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)
- return AVERROR(ENOMEM);
- c->prev = tmp;
- c->bx = (c->width + c->bw - 1) / c->bw;
- c->by = (c->height + c->bh - 1) / c->bh;
+ 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 -1;
+ 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,12 +504,18 @@ 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, "decomp buffer too small\n");
+ return AVERROR_INVALIDDATA;
+ }
memcpy(c->decomp_buf, buf, len);
- c->decomp_size = 1;
} 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;
@@ -528,62 +540,23 @@ 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);
- }
+ memcpy(out, src, c->stride);
+ src += c->stride;
out += frame->linesize[0];
}
break;
@@ -613,12 +586,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 9ac7d6d..fb782a4 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
*/
@@ -229,10 +229,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
pkt_size = c->zstream.total_out + 1 + 6*keyframe;
- if ((ret = ff_alloc_packet(pkt, pkt_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting packet of size %d.\n", pkt_size);
+ if ((ret = ff_alloc_packet2(avctx, pkt, pkt_size)) < 0)
return ret;
- }
buf = pkt->data;
fl = (keyframe ? ZMBV_KEYFRAME : 0) | (chpal ? ZMBV_DELTAPAL : 0);
diff --git a/libavdevice/Makefile b/libavdevice/Makefile
index 76d11c1..efffa8b 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 \
@@ -9,19 +12,28 @@ OBJS = alldevices.o \
# input/output devices
OBJS-$(CONFIG_ALSA_INDEV) += alsa-audio-common.o \
- alsa-audio-dec.o
+ alsa-audio-dec.o timefilter.o
OBJS-$(CONFIG_ALSA_OUTDEV) += alsa-audio-common.o \
alsa-audio-enc.o
OBJS-$(CONFIG_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_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_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 timefilter.o
+OBJS-$(CONFIG_V4L_INDEV) += v4l.o
OBJS-$(CONFIG_VFWCAP_INDEV) += vfwcap.o
OBJS-$(CONFIG_X11GRAB_INDEV) += x11grab.o
@@ -29,6 +41,7 @@ OBJS-$(CONFIG_X11GRAB_INDEV) += x11grab.o
OBJS-$(CONFIG_LIBCDIO_INDEV) += libcdio.o
OBJS-$(CONFIG_LIBDC1394_INDEV) += libdc1394.o
+SKIPHEADERS-$(CONFIG_DSHOW_INDEV) += dshow_capture.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..daa6638 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,13 +48,20 @@ 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_INDEV (IEC61883, iec61883);
REGISTER_INDEV (JACK, jack);
+ REGISTER_INDEV (LAVFI, lavfi);
+ REGISTER_INDEV (OPENAL, openal);
REGISTER_INOUTDEV(OSS, oss);
REGISTER_INDEV (PULSE, pulse);
+ REGISTER_OUTDEV (SDL, sdl);
REGISTER_INOUTDEV(SNDIO, sndio);
REGISTER_INDEV (V4L2, v4l2);
+// REGISTER_INDEV (V4L, v4l
REGISTER_INDEV (VFWCAP, vfwcap);
REGISTER_INDEV (X11GRAB, x11grab);
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 a147d38..b0dbe60 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/log.h"
#include "libavutil/opt.h"
@@ -49,6 +48,7 @@
#include <sys/time.h>
#include <signal.h>
#include <stdint.h>
+#include "avdevice.h"
typedef struct {
AVClass *class;
@@ -57,7 +57,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;
@@ -103,7 +102,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)
{
@@ -247,15 +246,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;
@@ -278,20 +271,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;
@@ -332,7 +323,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
--- /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..8cc12f5
--- /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;
+ 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
--- /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
--- /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
--- /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
--- /dev/null
+++ b/libavdevice/dshow_enumpins.c
@@ -0,0 +1,105 @@
+/*
+ * DirectShow capture interface
+ * Copyright (c) 2010 Ramiro Polla
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dshow_capture.h"
+
+DECLARE_QUERYINTERFACE(libAVEnumPins,
+ { {&IID_IUnknown,0}, {&IID_IEnumPins,0} })
+DECLARE_ADDREF(libAVEnumPins)
+DECLARE_RELEASE(libAVEnumPins)
+
+long WINAPI
+libAVEnumPins_Next(libAVEnumPins *this, unsigned long n, IPin **pins,
+ unsigned long *fetched)
+{
+ int count = 0;
+ dshowdebug("libAVEnumPins_Next(%p)\n", this);
+ if (!pins)
+ return E_POINTER;
+ if (!this->pos && n == 1) {
+ libAVPin_AddRef(this->pin);
+ *pins = (IPin *) this->pin;
+ count = 1;
+ this->pos = 1;
+ }
+ if (fetched)
+ *fetched = count;
+ if (!count)
+ return S_FALSE;
+ return S_OK;
+}
+long WINAPI
+libAVEnumPins_Skip(libAVEnumPins *this, unsigned long n)
+{
+ dshowdebug("libAVEnumPins_Skip(%p)\n", this);
+ if (n) /* Any skip will always fall outside of the only valid pin. */
+ return S_FALSE;
+ return S_OK;
+}
+long WINAPI
+libAVEnumPins_Reset(libAVEnumPins *this)
+{
+ dshowdebug("libAVEnumPins_Reset(%p)\n", this);
+ this->pos = 0;
+ return S_OK;
+}
+long WINAPI
+libAVEnumPins_Clone(libAVEnumPins *this, libAVEnumPins **pins)
+{
+ libAVEnumPins *new;
+ dshowdebug("libAVEnumPins_Clone(%p)\n", this);
+ if (!pins)
+ return E_POINTER;
+ new = libAVEnumPins_Create(this->pin, this->filter);
+ if (!new)
+ return E_OUTOFMEMORY;
+ new->pos = this->pos;
+ *pins = new;
+ return S_OK;
+}
+
+static int
+libAVEnumPins_Setup(libAVEnumPins *this, libAVPin *pin, libAVFilter *filter)
+{
+ IEnumPinsVtbl *vtbl = this->vtbl;
+ SETVTBL(vtbl, libAVEnumPins, QueryInterface);
+ SETVTBL(vtbl, libAVEnumPins, AddRef);
+ SETVTBL(vtbl, libAVEnumPins, Release);
+ SETVTBL(vtbl, libAVEnumPins, Next);
+ SETVTBL(vtbl, libAVEnumPins, Skip);
+ SETVTBL(vtbl, libAVEnumPins, Reset);
+ SETVTBL(vtbl, libAVEnumPins, Clone);
+
+ this->pin = pin;
+ this->filter = filter;
+ libAVFilter_AddRef(this->filter);
+
+ return 1;
+}
+static int
+libAVEnumPins_Cleanup(libAVEnumPins *this)
+{
+ libAVFilter_Release(this->filter);
+ return 1;
+}
+DECLARE_CREATE(libAVEnumPins, libAVEnumPins_Setup(this, pin, filter),
+ libAVPin *pin, libAVFilter *filter)
+DECLARE_DESTROY(libAVEnumPins, libAVEnumPins_Cleanup)
diff --git a/libavdevice/dshow_filter.c b/libavdevice/dshow_filter.c
new file mode 100644
index 0000000..7360adc
--- /dev/null
+++ b/libavdevice/dshow_filter.c
@@ -0,0 +1,202 @@
+/*
+ * DirectShow capture interface
+ * Copyright (c) 2010 Ramiro Polla
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dshow_capture.h"
+
+DECLARE_QUERYINTERFACE(libAVFilter,
+ { {&IID_IUnknown,0}, {&IID_IBaseFilter,0} })
+DECLARE_ADDREF(libAVFilter)
+DECLARE_RELEASE(libAVFilter)
+
+long WINAPI
+libAVFilter_GetClassID(libAVFilter *this, CLSID *id)
+{
+ dshowdebug("libAVFilter_GetClassID(%p)\n", this);
+ /* I'm not creating a ClassID just for this. */
+ return E_FAIL;
+}
+long WINAPI
+libAVFilter_Stop(libAVFilter *this)
+{
+ dshowdebug("libAVFilter_Stop(%p)\n", this);
+ this->state = State_Stopped;
+ return S_OK;
+}
+long WINAPI
+libAVFilter_Pause(libAVFilter *this)
+{
+ dshowdebug("libAVFilter_Pause(%p)\n", this);
+ this->state = State_Paused;
+ return S_OK;
+}
+long WINAPI
+libAVFilter_Run(libAVFilter *this, REFERENCE_TIME start)
+{
+ dshowdebug("libAVFilter_Run(%p) %"PRId64"\n", this, start);
+ this->state = State_Running;
+ this->start_time = start;
+ return S_OK;
+}
+long WINAPI
+libAVFilter_GetState(libAVFilter *this, DWORD ms, FILTER_STATE *state)
+{
+ dshowdebug("libAVFilter_GetState(%p)\n", this);
+ if (!state)
+ return E_POINTER;
+ *state = this->state;
+ return S_OK;
+}
+long WINAPI
+libAVFilter_SetSyncSource(libAVFilter *this, IReferenceClock *clock)
+{
+ dshowdebug("libAVFilter_SetSyncSource(%p)\n", this);
+
+ if (this->clock != clock) {
+ if (this->clock)
+ IReferenceClock_Release(this->clock);
+ this->clock = clock;
+ if (clock)
+ IReferenceClock_AddRef(clock);
+ }
+
+ return S_OK;
+}
+long WINAPI
+libAVFilter_GetSyncSource(libAVFilter *this, IReferenceClock **clock)
+{
+ dshowdebug("libAVFilter_GetSyncSource(%p)\n", this);
+
+ if (!clock)
+ return E_POINTER;
+ if (this->clock)
+ IReferenceClock_AddRef(this->clock);
+ *clock = this->clock;
+
+ return S_OK;
+}
+long WINAPI
+libAVFilter_EnumPins(libAVFilter *this, IEnumPins **enumpin)
+{
+ libAVEnumPins *new;
+ dshowdebug("libAVFilter_EnumPins(%p)\n", this);
+
+ if (!enumpin)
+ return E_POINTER;
+ new = libAVEnumPins_Create(this->pin, this);
+ if (!new)
+ return E_OUTOFMEMORY;
+
+ *enumpin = (IEnumPins *) new;
+ return S_OK;
+}
+long WINAPI
+libAVFilter_FindPin(libAVFilter *this, const wchar_t *id, IPin **pin)
+{
+ libAVPin *found = NULL;
+ dshowdebug("libAVFilter_FindPin(%p)\n", this);
+
+ if (!id || !pin)
+ return E_POINTER;
+ if (!wcscmp(id, L"In")) {
+ found = this->pin;
+ libAVPin_AddRef(found);
+ }
+ *pin = (IPin *) found;
+ if (!found)
+ return VFW_E_NOT_FOUND;
+
+ return S_OK;
+}
+long WINAPI
+libAVFilter_QueryFilterInfo(libAVFilter *this, FILTER_INFO *info)
+{
+ dshowdebug("libAVFilter_QueryFilterInfo(%p)\n", this);
+
+ if (!info)
+ return E_POINTER;
+ if (this->info.pGraph)
+ IFilterGraph_AddRef(this->info.pGraph);
+ *info = this->info;
+
+ return S_OK;
+}
+long WINAPI
+libAVFilter_JoinFilterGraph(libAVFilter *this, IFilterGraph *graph,
+ const wchar_t *name)
+{
+ dshowdebug("libAVFilter_JoinFilterGraph(%p)\n", this);
+
+ this->info.pGraph = graph;
+ if (name)
+ wcscpy(this->info.achName, name);
+
+ return S_OK;
+}
+long WINAPI
+libAVFilter_QueryVendorInfo(libAVFilter *this, wchar_t **info)
+{
+ dshowdebug("libAVFilter_QueryVendorInfo(%p)\n", this);
+
+ if (!info)
+ return E_POINTER;
+ *info = wcsdup(L"libAV");
+
+ return S_OK;
+}
+
+static int
+libAVFilter_Setup(libAVFilter *this, void *priv_data, void *callback,
+ enum dshowDeviceType type)
+{
+ IBaseFilterVtbl *vtbl = this->vtbl;
+ SETVTBL(vtbl, libAVFilter, QueryInterface);
+ SETVTBL(vtbl, libAVFilter, AddRef);
+ SETVTBL(vtbl, libAVFilter, Release);
+ SETVTBL(vtbl, libAVFilter, GetClassID);
+ SETVTBL(vtbl, libAVFilter, Stop);
+ SETVTBL(vtbl, libAVFilter, Pause);
+ SETVTBL(vtbl, libAVFilter, Run);
+ SETVTBL(vtbl, libAVFilter, GetState);
+ SETVTBL(vtbl, libAVFilter, SetSyncSource);
+ SETVTBL(vtbl, libAVFilter, GetSyncSource);
+ SETVTBL(vtbl, libAVFilter, EnumPins);
+ SETVTBL(vtbl, libAVFilter, FindPin);
+ SETVTBL(vtbl, libAVFilter, QueryFilterInfo);
+ SETVTBL(vtbl, libAVFilter, JoinFilterGraph);
+ SETVTBL(vtbl, libAVFilter, QueryVendorInfo);
+
+ this->pin = libAVPin_Create(this);
+
+ this->priv_data = priv_data;
+ this->callback = callback;
+ this->type = type;
+
+ return 1;
+}
+static int
+libAVFilter_Cleanup(libAVFilter *this)
+{
+ libAVPin_Release(this->pin);
+ return 1;
+}
+DECLARE_CREATE(libAVFilter, libAVFilter_Setup(this, priv_data, callback, type),
+ void *priv_data, void *callback, enum dshowDeviceType type)
+DECLARE_DESTROY(libAVFilter, libAVFilter_Cleanup)
diff --git a/libavdevice/dshow_pin.c b/libavdevice/dshow_pin.c
new file mode 100644
index 0000000..30e4d95
--- /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 ce8efa6..5d94f5c 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
*/
@@ -29,7 +29,7 @@
#include "libavutil/log.h"
#include "libavutil/opt.h"
-#include "libavformat/avformat.h"
+#include "avdevice.h"
#include "libavformat/dv.h"
#include "dv1394.h"
@@ -185,7 +185,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
index b820a4a..02efdf9 100644
--- a/libavdevice/fbdev.c
+++ b/libavdevice/fbdev.c
@@ -3,20 +3,20 @@
* Copyright (c) 2009 Giliard B. de Freitas <giliarde@gmail.com>
* Copyright (C) 2002 Gunnar Monell <gmo@linux.nu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,7 +40,7 @@
#include "libavutil/time.h"
#include "libavutil/parseutils.h"
#include "libavutil/pixdesc.h"
-#include "libavformat/avformat.h"
+#include "avdevice.h"
#include "libavformat/internal.h"
struct rgb_pixfmt_map_entry {
@@ -49,7 +49,7 @@ struct rgb_pixfmt_map_entry {
enum AVPixelFormat pixfmt;
};
-static struct rgb_pixfmt_map_entry rgb_pixfmt_map[] = {
+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 },
@@ -64,7 +64,7 @@ static enum AVPixelFormat get_pixfmt_from_fb_varinfo(struct fb_var_screeninfo *v
int i;
for (i = 0; i < FF_ARRAY_ELEMS(rgb_pixfmt_map); i++) {
- struct rgb_pixfmt_map_entry *entry = &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 &&
@@ -162,7 +162,7 @@ static av_cold int fbdev_read_header(AVFormatContext *avctx)
st->codec->width = fbdev->width;
st->codec->height = fbdev->height;
st->codec->pix_fmt = pix_fmt;
- st->codec->time_base = (AVRational){fbdev->framerate_q.den, fbdev->framerate_q.num};
+ st->codec->time_base = av_inv_q(fbdev->framerate_q);
st->codec->bit_rate =
fbdev->width * fbdev->height * fbdev->bytes_per_pixel * av_q2d(fbdev->framerate_q) * 8;
@@ -191,20 +191,22 @@ static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
fbdev->time_frame = av_gettime();
/* wait based on the frame rate */
- curtime = av_gettime();
- delay = fbdev->time_frame - curtime;
- av_dlog(avctx,
- "time_frame:%"PRId64" curtime:%"PRId64" delay:%"PRId64"\n",
- fbdev->time_frame, curtime, delay);
- if (delay > 0) {
+ while (1) {
+ curtime = av_gettime();
+ delay = fbdev->time_frame - curtime;
+ av_dlog(avctx,
+ "time_frame:%"PRId64" curtime:%"PRId64" delay:%"PRId64"\n",
+ fbdev->time_frame, curtime, delay);
+ if (delay <= 0) {
+ fbdev->time_frame += INT64_C(1000000) / av_q2d(fbdev->framerate_q);
+ break;
+ }
if (avctx->flags & AVFMT_FLAG_NONBLOCK)
return AVERROR(EAGAIN);
ts.tv_sec = delay / 1000000;
ts.tv_nsec = (delay % 1000000) * 1000;
while (nanosleep(&ts, &ts) < 0 && errno == EINTR);
}
- /* compute the time of the next frame */
- fbdev->time_frame += INT64_C(1000000) / av_q2d(fbdev->framerate_q);
if ((ret = av_new_packet(pkt, fbdev->frame_size)) < 0)
return ret;
@@ -221,7 +223,6 @@ static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
fbdev->varinfo.yoffset * fbdev->fixinfo.line_length;
pout = pkt->data;
- // TODO it'd be nice if the lines were aligned
for (i = 0; i < fbdev->height; i++) {
memcpy(pout, pin, fbdev->frame_linesize);
pin += fbdev->fixinfo.line_length;
diff --git a/libavdevice/iec61883.c b/libavdevice/iec61883.c
new file mode 100644
index 0000000..a63566e
--- /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 280f24d..bd6a770 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);
/* Create FIFO buffers */
self->filled_pkts = av_fifo_alloc(FIFO_PACKETS_NUM * sizeof(AVPacket));
diff --git a/libavdevice/lavfi.c b/libavdevice/lavfi.c
new file mode 100644
index 0000000..bcfba8b
--- /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(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 = av_get_channel_layout_nb_channels(link->channel_layout);
+ 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..a824bc3 100644
--- a/libavdevice/libcdio.c
+++ b/libavdevice/libcdio.c
@@ -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
--- /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 e3b9d67..aa40034 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
*/
@@ -38,7 +38,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
@@ -76,8 +76,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
index a8e710d..86fdc22 100644
--- a/libavdevice/pulse.c
+++ b/libavdevice/pulse.c
@@ -162,7 +162,7 @@ static av_cold int pulse_close(AVFormatContext *s)
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 },
+ { "name", "application name", OFFSET(name), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 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 },
diff --git a/libavdevice/sdl.c b/libavdevice/sdl.c
new file mode 100644
index 0000000..e708dfd
--- /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 8b98d33..ba2e54e 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,14 +37,21 @@ 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)
+{
+ 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));
- self->clock_period = clock_period;
- self->feedback2_factor = feedback2_factor;
- self->feedback3_factor = feedback3_factor;
+ double o = 2 * M_PI * bandwidth * period * time_base;
+ self->clock_period = time_base;
+ self->feedback2_factor = qexpneg(M_SQRT2 * o);
+ self->feedback3_factor = qexpneg(o * o) / period;
return self;
}
@@ -69,11 +76,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)
@@ -85,17 +97,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 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 {
@@ -107,7 +123,9 @@ int main(void)
TimeFilter *tf = ff_timefilter_new(1, par0, par1);
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);
diff --git a/libavdevice/timefilter.h b/libavdevice/timefilter.h
index 8cadd8b..6662959 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
*
* For more details about these parameters and background concepts please see:
* http://www.kokkinizita.net/papers/usingdll.pdf
@@ -80,6 +82,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..e2f37d6
--- /dev/null
+++ b/libavdevice/v4l.c
@@ -0,0 +1,363 @@
+/*
+ * Linux video grab interface
+ * Copyright (c) 2000,2001 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avdevice.h"
+
+#undef __STRICT_ANSI__ //workaround due to broken kernel headers
+#include "config.h"
+#include "libavutil/rational.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "libavformat/internal.h"
+#include "libavcodec/dsputil.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#define _LINUX_TIME_H 1
+#include <linux/videodev.h>
+#include <time.h>
+#include "avdevice.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.c b/libavdevice/v4l2.c
index d163cbe..7c6c1bc 100644
--- a/libavdevice/v4l2.c
+++ b/libavdevice/v4l2.c
@@ -1,45 +1,49 @@
/*
- * Video4Linux2 grab interface
* Copyright (c) 2000,2001 Fabrice Bellard
* Copyright (c) 2006 Luca Abeni
*
- * Part of this file is based on the V4L2 video capture example
- * (http://v4l2spec.bytesex.org/v4l2spec/capture.c)
- *
- * Thanks to Michael Niedermayer for providing the mapping between
- * V4L2_PIX_FMT_* and AV_PIX_FMT_*
- *
+ * This file is part of FFmpeg.
*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+/**
+ * @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_*
+ */
+
#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
+#if HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
#include <linux/videodev2.h>
#endif
#include "libavutil/atomic.h"
@@ -47,10 +51,24 @@
#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"
-#include "libavutil/mathematics.h"
+
+#if CONFIG_LIBV4L2
+#include <libv4l2.h>
+#else
+#define v4l2_open open
+#define v4l2_close close
+#define v4l2_dup dup
+#define v4l2_ioctl ioctl
+#define v4l2_read read
+#define v4l2_mmap mmap
+#define v4l2_munmap munmap
+#endif
static const int desired_video_buffers = 256;
@@ -58,33 +76,56 @@ 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. */
};
struct buff_data {
struct video_data *s;
int index;
- int fd;
};
struct fmt_map {
@@ -96,75 +137,83 @@ struct fmt_map {
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_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_RGB555, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB555 },
- { AV_PIX_FMT_RGB565, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB565 },
+ { 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_BGRA, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_BGR32 },
+ { 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
};
static int device_open(AVFormatContext *ctx)
{
struct v4l2_capability cap;
int fd;
- int res, err;
+ int ret;
int flags = O_RDWR;
if (ctx->flags & AVFMT_FLAG_NONBLOCK) {
flags |= O_NONBLOCK;
}
- fd = open(ctx->filename, flags, 0);
+ 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,
@@ -175,14 +224,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,
@@ -197,11 +247,12 @@ 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;
}
@@ -213,7 +264,7 @@ static int first_field(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;
}
@@ -272,7 +323,7 @@ static void list_framesizes(AVFormatContext *ctx, int fd, uint32_t pixelformat)
{
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",
@@ -297,7 +348,7 @@ static void list_formats(AVFormatContext *ctx, int fd, int type)
{
struct v4l2_fmtdesc vfd = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
- while(!ioctl(fd, VIDIOC_ENUM_FMT, &vfd)) {
+ while(!v4l2_ioctl(fd, VIDIOC_ENUM_FMT, &vfd)) {
enum AVCodecID codec_id = fmt_v4l2codec(vfd.pixelformat);
enum AVPixelFormat pix_fmt = fmt_v4l2ff(vfd.pixelformat, codec_id);
@@ -306,13 +357,13 @@ static void list_formats(AVFormatContext *ctx, int fd, int type)
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 {
@@ -320,10 +371,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);
@@ -332,6 +381,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, %16llx, %s\n",
+ standard.index, standard.id, standard.name);
+ }
+}
+
static int mmap_init(AVFormatContext *ctx)
{
int i, res;
@@ -342,34 +415,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);
}
@@ -379,30 +444,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;
}
}
@@ -419,23 +481,84 @@ 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);
+ 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;
@@ -443,28 +566,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) {
@@ -475,11 +588,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;
}
@@ -489,15 +607,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 {
@@ -515,22 +635,26 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt)
* 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];
}
@@ -548,23 +672,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;
@@ -579,9 +699,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);
@@ -590,15 +710,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",
@@ -606,120 +723,149 @@ 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);
+ 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: %"PRIu64", 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;
+
+ *desired_format = fmt_ff2v4l(pix_fmt, s1->video_codec_id);
- if (desired_format == 0 ||
- device_init(s1, width, height, desired_format) < 0) {
- int i;
+ if (*desired_format) {
+ ret = device_init(s1, width, height, *desired_format);
+ if (ret < 0) {
+ *desired_format = 0;
+ if (ret != AVERROR(EINVAL))
+ return ret;
+ }
+ }
- desired_format = 0;
+ if (!*desired_format) {
for (i = 0; i<FF_ARRAY_ELEMS(fmt_conversion_table); i++) {
if (s1->video_codec_id == AV_CODEC_ID_NONE ||
fmt_conversion_table[i].codec_id == s1->video_codec_id) {
- desired_format = fmt_conversion_table[i].v4l2_fmt;
- if (device_init(s1, width, height, desired_format) >= 0) {
+ av_log(s1, AV_LOG_DEBUG, "Trying to set codec:%s pix_fmt:%s\n",
+ avcodec_get_name(fmt_conversion_table[i].codec_id),
+ (char *)av_x_if_null(av_get_pix_fmt_name(fmt_conversion_table[i].ff_fmt), "none"));
+
+ *desired_format = 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 = fmt_v4l2codec(*desired_format);
+ av_assert0(*codec_id != AV_CODEC_ID_NONE);
+ return ret;
}
static int v4l2_read_header(AVFormatContext *s1)
@@ -728,31 +874,64 @@ 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 */
+ 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\n",
+ s->channel, input.name);
+
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);
@@ -770,15 +949,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;
@@ -787,22 +965,25 @@ 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);
@@ -811,7 +992,7 @@ static int v4l2_read_header(AVFormatContext *s1)
if ((res = mmap_init(s1)) ||
(res = mmap_start(s1)) < 0) {
- close(s->fd);
+ v4l2_close(s->fd);
return res;
}
@@ -822,6 +1003,10 @@ static int v4l2_read_header(AVFormatContext *s1)
if (codec_id == AV_CODEC_ID_RAWVIDEO)
st->codec->codec_tag =
avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt);
+ 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;
@@ -858,23 +1043,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" },
+
{ NULL },
};
@@ -886,7 +1083,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/version.h b/libavdevice/version.h
index 9731606..c03e733 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 0
+#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..66b02be 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 {
@@ -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..6124006 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 */
@@ -164,33 +164,35 @@ 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;
- 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 +223,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);
@@ -296,7 +298,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 +308,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(framerate);
x11grab->time_frame = av_gettime() / av_q2d(x11grab->time_base);
x11grab->x_off = x_off;
x11grab->y_off = y_off;
@@ -322,7 +324,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 +353,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;
+ Cursor c;
+ 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;
+ c = XCreateFontCursor(dpy, XC_left_ptr);
+ w = DefaultRootWindow(dpy);
+ attr.cursor = c;
+ XChangeWindowAttributes(dpy, w, CWCursor, &attr);
+
xcim = XFixesGetCursorImage(dpy);
x = xcim->x - xcim->xhot;
@@ -585,13 +595,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_STRING, {.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/libavfilter/Makefile b/libavfilter/Makefile
index 7555b49..9279775 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -1,11 +1,28 @@
+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_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_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,76 +38,211 @@ 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_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_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_LOWPASS_FILTER) += af_biquads.o
+OBJS-$(CONFIG_PAN_FILTER) += af_pan.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
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_drawgrid.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_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_LUT_FILTER) += vf_lut.o
OBJS-$(CONFIG_LUTRGB_FILTER) += vf_lut.o
OBJS-$(CONFIG_LUTYUV_FILTER) += vf_lut.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_OPENCL) += deshake_opencl.o unsharp_opencl.o
OBJS-$(CONFIG_OVERLAY_FILTER) += vf_overlay.o
+OBJS-$(CONFIG_OWDENOISE_FILTER) += vf_owdenoise.o
OBJS-$(CONFIG_PAD_FILTER) += vf_pad.o
+OBJS-$(CONFIG_PERMS_FILTER) += f_perms.o
OBJS-$(CONFIG_PIXDESCTEST_FILTER) += vf_pixdesctest.o
+OBJS-$(CONFIG_PP_FILTER) += vf_pp.o
+OBJS-$(CONFIG_REMOVELOGO_FILTER) += bbox.o lswsutils.o lavfutils.o vf_removelogo.o
+OBJS-$(CONFIG_SEPARATEFIELDS_FILTER) += vf_separatefields.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_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_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_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_dint.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_eq2.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_eq.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_fil.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_fspp.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_ilpack.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_mcdeint.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_perspective.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_phase.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_pp7.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_pullup.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_qp.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_sab.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_softpulldown.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_spp.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/vf_uspp.o
+OBJS-$(CONFIG_MP_FILTER) += libmpcodecs/pullup.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
+
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..8a9dc6f
--- /dev/null
+++ b/libavfilter/af_aconvert.c
@@ -0,0 +1,189 @@
+/*
+ * 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/avstring.h"
+#include "libavutil/channel_layout.h"
+#include "libswresample/swresample.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "internal.h"
+
+typedef struct {
+ enum AVSampleFormat out_sample_fmt;
+ int64_t out_chlayout;
+ struct SwrContext *swr;
+} AConvertContext;
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ AConvertContext *aconvert = ctx->priv;
+ char *arg, *ptr = NULL;
+ int ret = 0;
+ char *args = av_strdup(NULL);
+
+ 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 ((arg = av_strtok(args, ":", &ptr)) && strcmp(arg, "auto")) {
+ if ((ret = ff_parse_sample_format(&aconvert->out_sample_fmt, arg, ctx)) < 0)
+ goto end;
+ }
+ if ((arg = av_strtok(NULL, ":", &ptr)) && strcmp(arg, "auto")) {
+ if ((ret = ff_parse_channel_layout(&aconvert->out_chlayout, arg, ctx)) < 0)
+ goto end;
+ }
+
+end:
+ av_freep(&args);
+ 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 avfilter_af_aconvert = {
+ .name = "aconvert",
+ .description = NULL_IF_CONFIG_SMALL("Convert the input audio to sample_fmt:channel_layout."),
+ .priv_size = sizeof(AConvertContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = aconvert_inputs,
+ .outputs = aconvert_outputs,
+};
diff --git a/libavfilter/af_afade.c b/libavfilter/af_afade.c
new file mode 100644
index 0000000..a6805b5
--- /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 *afade = ctx->priv;
+
+ if (INT64_MAX - afade->nb_samples < afade->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_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AudioFadeContext *afade = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+
+ switch (inlink->format) {
+ case AV_SAMPLE_FMT_DBL: afade->fade_samples = fade_samples_dbl; break;
+ case AV_SAMPLE_FMT_DBLP: afade->fade_samples = fade_samples_dblp; break;
+ case AV_SAMPLE_FMT_FLT: afade->fade_samples = fade_samples_flt; break;
+ case AV_SAMPLE_FMT_FLTP: afade->fade_samples = fade_samples_fltp; break;
+ case AV_SAMPLE_FMT_S16: afade->fade_samples = fade_samples_s16; break;
+ case AV_SAMPLE_FMT_S16P: afade->fade_samples = fade_samples_s16p; break;
+ case AV_SAMPLE_FMT_S32: afade->fade_samples = fade_samples_s32; break;
+ case AV_SAMPLE_FMT_S32P: afade->fade_samples = fade_samples_s32p; break;
+ }
+
+ if (afade->duration)
+ afade->nb_samples = afade->duration * inlink->sample_rate / AV_TIME_BASE;
+ if (afade->start_time)
+ afade->start_sample = afade->start_time * inlink->sample_rate / AV_TIME_BASE;
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
+{
+ AudioFadeContext *afade = 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 ((!afade->type && (afade->start_sample + afade->nb_samples < cur_sample)) ||
+ ( afade->type && (cur_sample + afade->nb_samples < afade->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 ((!afade->type && (cur_sample + nb_samples < afade->start_sample)) ||
+ ( afade->type && (afade->start_sample + afade->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 (!afade->type)
+ start = cur_sample - afade->start_sample;
+ else
+ start = afade->start_sample + afade->nb_samples - cur_sample;
+
+ afade->fade_samples(out_buf->extended_data, buf->extended_data,
+ nb_samples, av_frame_get_channels(buf),
+ afade->type ? -1 : 1, start,
+ afade->nb_samples, afade->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,
+ },
+ { NULL }
+};
+
+static const AVFilterPad avfilter_af_afade_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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,
+};
diff --git a/libavfilter/af_aformat.c b/libavfilter/af_aformat.c
index 085b4d0..39bd850 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 },
+#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;
}
diff --git a/libavfilter/af_amerge.c b/libavfilter/af_amerge.c
new file mode 100644
index 0000000..6244423
--- /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 },
+ {0}
+};
+
+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 avfilter_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 2df0507..8cecdaf 100644
--- a/libavfilter/af_amix.c
+++ b/libavfilter/af_amix.c
@@ -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 },
+ OFFSET(dropout_transition), AV_OPT_TYPE_FLOAT, { .dbl = 2.0 }, 0, INT_MAX, A|F },
{ NULL },
};
-static const AVClass amix_class = {
- .class_name = "amix filter",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
+AVFILTER_DEFINE_CLASS(amix);
/**
* Update the scaling factors to apply to each input during mixing.
diff --git a/libavfilter/af_anull.c b/libavfilter/af_anull.c
index a791064..7a0b3f7 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
*/
@@ -30,7 +31,6 @@ static const AVFilterPad avfilter_af_anull_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
- .get_audio_buffer = ff_null_get_audio_buffer,
},
{ NULL }
};
@@ -46,10 +46,7 @@ static const AVFilterPad avfilter_af_anull_outputs[] = {
AVFilter avfilter_af_anull = {
.name = "anull",
.description = NULL_IF_CONFIG_SMALL("Pass the source unchanged to the output."),
-
- .priv_size = 0,
-
+ .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..710baaa
--- /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 avfilter_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..b1043b0
--- /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 avfilter_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..b88c5f8
--- /dev/null
+++ b/libavfilter/af_aresample.c
@@ -0,0 +1,311 @@
+/*
+ * 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))) {
+ const char *token = e->key;
+ const char *value = e->value;
+ if ((ret = av_opt_set(aresample->swr, token, 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 avfilter_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..25e062a
--- /dev/null
+++ b/libavfilter/af_asetnsamples.c
@@ -0,0 +1,198 @@
+/*
+ * 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;
+ int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout);
+
+ asns->fifo = av_audio_fifo_alloc(outlink->format, nb_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, av_get_channel_layout_nb_channels(outlink->channel_layout),
+ 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,
+ .needs_writable = 1,
+ },
+ { NULL }
+};
+
+static const AVFilterPad asetnsamples_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .request_frame = request_frame,
+ .config_props = config_props_output,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_af_asetnsamples = {
+ .name = "asetnsamples",
+ .description = NULL_IF_CONFIG_SMALL("Set the number of samples for each output audio frames."),
+ .priv_size = sizeof(ASNSContext),
+ .init = init,
+ .uninit = uninit,
+ .inputs = asetnsamples_inputs,
+ .outputs = asetnsamples_outputs,
+ .priv_class = &asetnsamples_class,
+};
diff --git a/libavfilter/af_asetrate.c b/libavfilter/af_asetrate.c
new file mode 100644
index 0000000..e031b89
--- /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 avfilter_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 c347391..7770c27 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"
@@ -49,17 +50,6 @@ typedef struct AShowInfoContext {
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;
@@ -78,6 +68,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
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 +86,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:%"PRIu64" 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,
+ s->frame,
+ 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);
@@ -113,7 +110,6 @@ 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,
},
{ NULL },
diff --git a/libavfilter/af_astats.c b/libavfilter/af_astats.c
new file mode 100644
index 0000000..e1baa3c
--- /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 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++)
+ 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++)
+ 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 avfilter_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..1ea3a8a
--- /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 avfilter_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 0ddd8b6..a30ce3d 100644
--- a/libavfilter/af_asyncts.c
+++ b/libavfilter/af_asyncts.c
@@ -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 },
+ "(in seconds) to trigger padding/trimmin the data.", OFFSET(min_delta_sec), AV_OPT_TYPE_FLOAT, { .dbl = 0.1 }, 0, INT_MAX, A|F },
+ { "max_comp", "Maximum compensation in samples per second.", OFFSET(max_comp), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, INT_MAX, A|F },
+ { "first_pts", "Assume the first pts should be this value.", OFFSET(first_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, A|F },
{ NULL },
};
-static const AVClass async_class = {
- .class_name = "asyncts filter",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(asyncts);
static av_cold int init(AVFilterContext *ctx)
{
@@ -298,7 +294,7 @@ static const AVFilterPad avfilter_af_asyncts_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
- .filter_frame = filter_frame,
+ .filter_frame = filter_frame
},
{ NULL }
};
@@ -321,7 +317,7 @@ AVFilter avfilter_af_asyncts = {
.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..ad12786
--- /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 avfilter_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..0141ffd
--- /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/opt.h"
+#include "libavutil/avassert.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,
+ HZ,
+ 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 HZ:
+ 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 avfilter_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}, HZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HZ}, 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}, HZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HZ}, 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}, HZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HZ}, 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}, HZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HZ}, 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}, HZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HZ}, 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}, HZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HZ}, 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}, HZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HZ}, 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=HZ}, HZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HZ}, 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 34d2457..50e961c 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,11 +68,12 @@ typedef struct ChannelMapContext {
#define OFFSET(x) offsetof(ChannelMapContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM
+#define F AV_OPT_FLAG_FILTERING_PARAM
static const AVOption 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 },
+ OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A|F },
{ NULL },
};
@@ -387,7 +388,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 }
};
diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c
index 819a0b3..42c8156 100644
--- a/libavfilter/af_channelsplit.c
+++ b/libavfilter/af_channelsplit.c
@@ -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 },
+#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)
@@ -141,7 +138,7 @@ static const AVFilterPad avfilter_af_channelsplit_inputs[] = {
AVFilter avfilter_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,
diff --git a/libavfilter/af_earwax.c b/libavfilter/af_earwax.c
new file mode 100644
index 0000000..189243a
--- /dev/null
+++ b/libavfilter/af_earwax.c
@@ -0,0 +1,167 @@
+/*
+ * 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);
+
+ 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];
+
+ // copy part of new input and process with saved input
+ memcpy(taps+NUMTAPS, in, NUMTAPS * sizeof(*taps));
+ out = scalarproduct(taps, taps + NUMTAPS, out);
+
+ // process current input
+ endin = in + insamples->nb_samples * 2 - NUMTAPS;
+ scalarproduct(in, endin, out);
+
+ // save part of input for next round
+ memcpy(taps, endin, 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 avfilter_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 e3dc5a5..b8e9e85 100644
--- a/libavfilter/af_join.c
+++ b/libavfilter/af_join.c
@@ -66,13 +66,14 @@ 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 },
+ OFFSET(map), AV_OPT_TYPE_STRING, .flags = A|F },
{ NULL },
};
@@ -479,6 +480,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,7 +515,7 @@ static const AVFilterPad avfilter_af_join_outputs[] = {
AVFilter avfilter_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,
diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c
new file mode 100644
index 0000000..800c40a
--- /dev/null
+++ b/libavfilter/af_pan.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2002 Anders Johansson <ajh@atri.curtin.edu.au>
+ * Copyright (c) 2011 ClĂ©ment BÅ“sch <ubitux@gmail.com>
+ * 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 avfilter_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_silencedetect.c b/libavfilter/af_silencedetect.c
new file mode 100644
index 0000000..eb4718b
--- /dev/null
+++ b/libavfilter/af_silencedetect.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch <ubitux@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
+ * Audio silence detector
+ */
+
+#include <float.h> /* DBL_MAX */
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libavutil/timestamp.h"
+#include "audio.h"
+#include "formats.h"
+#include "avfilter.h"
+#include "internal.h"
+
+typedef struct {
+ 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
+} 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 int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ int i;
+ SilenceDetectContext *silence = inlink->dst->priv;
+ const int nb_channels = av_get_channel_layout_nb_channels(inlink->channel_layout);
+ const int srate = inlink->sample_rate;
+ const int nb_samples = insamples->nb_samples * nb_channels;
+ const int64_t nb_samples_notify = srate * silence->duration * nb_channels;
+
+ // scale number of null samples to the new sample rate
+ if (silence->last_sample_rate && silence->last_sample_rate != srate)
+ silence->nb_null_samples =
+ srate * silence->nb_null_samples / silence->last_sample_rate;
+ silence->last_sample_rate = srate;
+
+ // TODO: support more sample formats
+ // TODO: document metadata
+ if (insamples->format == AV_SAMPLE_FMT_DBL) {
+ double *p = (double *)insamples->data[0];
+
+ for (i = 0; i < nb_samples; i++, p++) {
+ if (*p < silence->noise && *p > -silence->noise) {
+ if (!silence->start) {
+ silence->nb_null_samples++;
+ if (silence->nb_null_samples >= nb_samples_notify) {
+ silence->start = insamples->pts - (int64_t)(silence->duration / av_q2d(inlink->time_base) + .5);
+ av_dict_set(&insamples->metadata, "lavfi.silence_start",
+ av_ts2timestr(silence->start, &inlink->time_base), 0);
+ av_log(silence, AV_LOG_INFO, "silence_start: %s\n",
+ get_metadata_val(insamples, "lavfi.silence_start"));
+ }
+ }
+ } else {
+ if (silence->start) {
+ av_dict_set(&insamples->metadata, "lavfi.silence_end",
+ av_ts2timestr(insamples->pts, &inlink->time_base), 0);
+ av_dict_set(&insamples->metadata, "lavfi.silence_duration",
+ av_ts2timestr(insamples->pts - silence->start, &inlink->time_base), 0);
+ av_log(silence, AV_LOG_INFO,
+ "silence_end: %s | silence_duration: %s\n",
+ get_metadata_val(insamples, "lavfi.silence_end"),
+ get_metadata_val(insamples, "lavfi.silence_duration"));
+ }
+ silence->nb_null_samples = silence->start = 0;
+ }
+ }
+ }
+
+ 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_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,
+ .get_audio_buffer = ff_null_get_audio_buffer,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad silencedetect_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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 fc878f9..a2ac1e2 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" },
+#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 avfilter_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..f00836f
--- /dev/null
+++ b/libavfilter/af_volumedetect.c
@@ -0,0 +1,161 @@
+/*
+ * 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,
+ .get_audio_buffer = ff_null_get_audio_buffer,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad volumedetect_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_af_volumedetect = {
+ .name = "volumedetect",
+ .description = NULL_IF_CONFIG_SMALL("Detect audio volume."),
+
+ .priv_size = sizeof(VolDetectContext),
+ .query_formats = query_formats,
+ .uninit = uninit,
+ .inputs = volumedetect_inputs,
+ .outputs = volumedetect_outputs,
+};
diff --git a/libavfilter/all_channel_layouts.inc b/libavfilter/all_channel_layouts.inc
new file mode 100644
index 0000000..878e1f5
--- /dev/null
+++ b/libavfilter/all_channel_layouts.inc
@@ -0,0 +1,68 @@
+AV_CH_FRONT_CENTER,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY,
+AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_CENTER,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER,
+AV_CH_FRONT_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 20407ce..07d7da0 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,179 @@ void avfilter_register_all(void)
return;
initialized = 1;
+#if FF_API_ACONVERT_FILTER
+ REGISTER_FILTER(ACONVERT, aconvert, af);
+#endif
+ 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(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(LOWPASS, lowpass, af);
+ REGISTER_FILTER(PAN, pan, 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(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(LUT, lut, vf);
REGISTER_FILTER(LUTRGB, lutrgb, vf);
REGISTER_FILTER(LUTYUV, lutyuv, 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(PIXDESCTEST, pixdesctest, vf);
+ REGISTER_FILTER(PP, pp, vf);
+ REGISTER_FILTER(REMOVELOGO, removelogo, 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(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(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(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 +226,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 756dff0..8015da2 100644
--- a/libavfilter/asink_anullsink.c
+++ b/libavfilter/asink_anullsink.c
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram <smeenaks@ucsd.edu>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavfilter/asrc_abuffer.h b/libavfilter/asrc_abuffer.h
new file mode 100644
index 0000000..aa34461
--- /dev/null
+++ b/libavfilter/asrc_abuffer.h
@@ -0,0 +1,91 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFILTER_ASRC_ABUFFER_H
+#define AVFILTER_ASRC_ABUFFER_H
+
+#include "avfilter.h"
+
+/**
+ * @file
+ * memory buffer source for audio
+ *
+ * @deprecated use buffersrc.h instead.
+ */
+
+/**
+ * Queue an audio buffer to the audio buffer source.
+ *
+ * @param abuffersrc audio source buffer context
+ * @param data pointers to the samples planes
+ * @param linesize linesizes of each audio buffer plane
+ * @param nb_samples number of samples per channel
+ * @param sample_fmt sample format of the audio data
+ * @param ch_layout channel layout of the audio data
+ * @param planar flag to indicate if audio data is planar or packed
+ * @param pts presentation timestamp of the audio buffer
+ * @param flags unused
+ *
+ * @deprecated use av_buffersrc_add_ref() instead.
+ */
+attribute_deprecated
+int av_asrc_buffer_add_samples(AVFilterContext *abuffersrc,
+ uint8_t *data[8], int linesize[8],
+ int nb_samples, int sample_rate,
+ int sample_fmt, int64_t ch_layout, int planar,
+ int64_t pts, int av_unused flags);
+
+/**
+ * Queue an audio buffer to the audio buffer source.
+ *
+ * This is similar to av_asrc_buffer_add_samples(), but the samples
+ * are stored in a buffer with known size.
+ *
+ * @param abuffersrc audio source buffer context
+ * @param buf pointer to the samples data, packed is assumed
+ * @param size the size in bytes of the buffer, it must contain an
+ * integer number of samples
+ * @param sample_fmt sample format of the audio data
+ * @param ch_layout channel layout of the audio data
+ * @param pts presentation timestamp of the audio buffer
+ * @param flags unused
+ *
+ * @deprecated use av_buffersrc_add_ref() instead.
+ */
+attribute_deprecated
+int av_asrc_buffer_add_buffer(AVFilterContext *abuffersrc,
+ uint8_t *buf, int buf_size,
+ int sample_rate,
+ int sample_fmt, int64_t ch_layout, int planar,
+ int64_t pts, int av_unused flags);
+
+/**
+ * Queue an audio buffer to the audio buffer source.
+ *
+ * @param abuffersrc audio source buffer context
+ * @param samplesref buffer ref to queue
+ * @param flags unused
+ *
+ * @deprecated use av_buffersrc_add_ref() instead.
+ */
+attribute_deprecated
+int av_asrc_buffer_add_audio_buffer_ref(AVFilterContext *abuffersrc,
+ AVFilterBufferRef *samplesref,
+ int av_unused flags);
+
+#endif /* AVFILTER_ASRC_ABUFFER_H */
diff --git a/libavfilter/asrc_aevalsrc.c b/libavfilter/asrc_aevalsrc.c
new file mode 100644
index 0000000..9d2ac9c
--- /dev/null
+++ b/libavfilter/asrc_aevalsrc.c
@@ -0,0 +1,255 @@
+/*
+ * 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[8];
+ char *exprs;
+ int nb_samples; ///< number of samples per requested frame
+ char *duration_str; ///< total duration of the generated audio
+ double 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_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "d", "set audio duration", OFFSET(duration_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "channel_layout", "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "c", "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+{NULL},
+};
+
+AVFILTER_DEFINE_CLASS(aevalsrc);
+
+static int init(AVFilterContext *ctx)
+{
+ EvalContext *eval = ctx->priv;
+ char *args1 = av_strdup(eval->exprs);
+ char *expr, *buf;
+ int ret, i;
+
+ 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;
+ i = 0;
+ while (i < FF_ARRAY_ELEMS(eval->expr) && (expr = av_strtok(buf, "|", &buf))) {
+ ret = av_expr_parse(&eval->expr[i], expr, var_names,
+ NULL, NULL, NULL, NULL, 0, ctx);
+ if (ret < 0)
+ goto end;
+ i++;
+ }
+ eval->nb_channels = i;
+
+ 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) {
+ 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->duration = -1;
+ if (eval->duration_str) {
+ int64_t us = -1;
+ if ((ret = av_parse_time(&us, eval->duration_str, 1)) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid duration: '%s'\n", eval->duration_str);
+ goto end;
+ }
+ eval->duration = (double)us / 1000000;
+ }
+ 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 < 8; i++) {
+ av_expr_free(eval->expr[i]);
+ eval->expr[i] = NULL;
+ }
+ av_freep(&eval->chlayout_str);
+ av_freep(&eval->duration_str);
+ av_freep(&eval->sample_rate_str);
+}
+
+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:%f\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, -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;
+ double t = eval->n * (double)1/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 avfilter_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 140ad46..5a009c3 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,18 +29,106 @@
#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 int init(AVFilterContext *ctx)
+{
+ 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)
{
- return AVERROR_EOF;
+ 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 }
@@ -45,9 +136,14 @@ static const AVFilterPad avfilter_asrc_anullsrc_outputs[] = {
AVFilter avfilter_asrc_anullsrc = {
.name = "anullsrc",
- .description = NULL_IF_CONFIG_SMALL("Null audio source, never return audio frames."),
+ .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..1d5b9e6
--- /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 avfilter_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..86af7cc
--- /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 avfilter_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 5295423..1075217 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,9 +41,11 @@ 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 buf_size, 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;
@@ -57,6 +69,7 @@ AVFrame *ff_default_get_audio_buffer(AVFilterLink *link, int nb_samples)
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;
@@ -82,11 +95,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));
@@ -95,6 +109,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))))
@@ -102,9 +120,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;
@@ -151,4 +169,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
--- /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..ae55df7
--- /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..f5c7e31
--- /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 vector scope 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 avfilter_avf_avectorscope = {
+ .name = "avectorscope",
+ .description = NULL_IF_CONFIG_SMALL("Display audio vector scope."),
+ .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..04812aa
--- /dev/null
+++ b/libavfilter/avf_concat.c
@@ -0,0 +1,423 @@
+/*
+ * 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, A|A|F},
+ { 0 }
+};
+
+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];
+ /* 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 ||
+ 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 avfilter_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..7cd75df
--- /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 *showspectrum = ctx->priv;
+ int i;
+
+ av_freep(&showspectrum->combine_buffer);
+ av_rdft_end(showspectrum->rdft);
+ for (i = 0; i < showspectrum->nb_display_channels; i++)
+ av_freep(&showspectrum->rdft_data[i]);
+ av_freep(&showspectrum->rdft_data);
+ av_freep(&showspectrum->window_func_lut);
+ av_frame_free(&showspectrum->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 *showspectrum = ctx->priv;
+ int i, rdft_bits, win_size, h;
+
+ outlink->w = showspectrum->w;
+ outlink->h = showspectrum->h;
+
+ h = (showspectrum->mode == COMBINED) ? outlink->h : outlink->h / inlink->channels;
+ showspectrum->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 != showspectrum->rdft_bits) {
+ size_t rdft_size, rdft_listsize;
+ AVFrame *outpicref;
+
+ av_rdft_end(showspectrum->rdft);
+ showspectrum->rdft = av_rdft_init(rdft_bits, DFT_R2C);
+ showspectrum->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 < showspectrum->nb_display_channels; i++)
+ av_freep(&showspectrum->rdft_data[i]);
+ av_freep(&showspectrum->rdft_data);
+ showspectrum->nb_display_channels = inlink->channels;
+
+ if (av_size_mult(sizeof(*showspectrum->rdft_data),
+ showspectrum->nb_display_channels, &rdft_listsize) < 0)
+ return AVERROR(EINVAL);
+ if (av_size_mult(sizeof(**showspectrum->rdft_data),
+ win_size, &rdft_size) < 0)
+ return AVERROR(EINVAL);
+ showspectrum->rdft_data = av_malloc(rdft_listsize);
+ if (!showspectrum->rdft_data)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < showspectrum->nb_display_channels; i++) {
+ showspectrum->rdft_data[i] = av_malloc(rdft_size);
+ if (!showspectrum->rdft_data[i])
+ return AVERROR(ENOMEM);
+ }
+ showspectrum->filled = 0;
+
+ /* pre-calc windowing function (hann here) */
+ showspectrum->window_func_lut =
+ av_realloc_f(showspectrum->window_func_lut, win_size,
+ sizeof(*showspectrum->window_func_lut));
+ if (!showspectrum->window_func_lut)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < win_size; i++)
+ showspectrum->window_func_lut[i] = .5f * (1 - cos(2*M_PI*i / (win_size-1)));
+
+ /* prepare the initial picref buffer (black frame) */
+ av_frame_free(&showspectrum->outpicref);
+ showspectrum->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 (showspectrum->xpos >= outlink->w)
+ showspectrum->xpos = 0;
+
+ showspectrum->combine_buffer =
+ av_realloc_f(showspectrum->combine_buffer, outlink->h * 3,
+ sizeof(*showspectrum->combine_buffer));
+
+ av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d RDFT window size:%d\n",
+ showspectrum->w, showspectrum->h, win_size);
+ return 0;
+}
+
+inline static int push_frame(AVFilterLink *outlink)
+{
+ ShowSpectrumContext *showspectrum = outlink->src->priv;
+
+ showspectrum->xpos++;
+ if (showspectrum->xpos >= outlink->w)
+ showspectrum->xpos = 0;
+ showspectrum->filled = 0;
+ showspectrum->req_fullfilled = 1;
+
+ return ff_filter_frame(outlink, av_frame_clone(showspectrum->outpicref));
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ ShowSpectrumContext *showspectrum = outlink->src->priv;
+ AVFilterLink *inlink = outlink->src->inputs[0];
+ int ret;
+
+ showspectrum->req_fullfilled = 0;
+ do {
+ ret = ff_request_frame(inlink);
+ } while (!showspectrum->req_fullfilled && ret >= 0);
+
+ if (ret == AVERROR_EOF && showspectrum->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 *showspectrum = ctx->priv;
+ AVFrame *outpicref = showspectrum->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 << (showspectrum->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 = showspectrum->filled;
+ const int add_samples = FFMIN(win_size - start, nb_samples);
+
+ /* fill RDFT input with the number of samples available */
+ for (ch = 0; ch < showspectrum->nb_display_channels; ch++) {
+ const int16_t *p = (int16_t *)insamples->extended_data[ch];
+
+ p += showspectrum->consumed;
+ for (n = 0; n < add_samples; n++)
+ showspectrum->rdft_data[ch][start + n] = p[n] * showspectrum->window_func_lut[start + n];
+ }
+ showspectrum->filled += add_samples;
+
+ /* complete RDFT window size? */
+ if (showspectrum->filled == win_size) {
+
+ /* channel height */
+ int h = showspectrum->channel_height;
+
+ /* run RDFT on each samples set */
+ for (ch = 0; ch < showspectrum->nb_display_channels; ch++)
+ av_rdft_calc(showspectrum->rdft, showspectrum->rdft_data[ch]);
+
+ /* fill a new spectrum column */
+#define RE(y, ch) showspectrum->rdft_data[ch][2 * y + 0]
+#define IM(y, ch) showspectrum->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++) {
+ showspectrum->combine_buffer[3 * y ] = 0;
+ showspectrum->combine_buffer[3 * y + 1] = 127.5;
+ showspectrum->combine_buffer[3 * y + 2] = 127.5;
+ }
+
+ for (ch = 0; ch < showspectrum->nb_display_channels; ch++) {
+ float yf, uf, vf;
+
+ /* decide color range */
+ switch (showspectrum->mode) {
+ case COMBINED:
+ // reduce range by channel count
+ yf = 256.0f / showspectrum->nb_display_channels;
+ switch (showspectrum->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 (showspectrum->color_mode == CHANNEL) {
+ if (showspectrum->nb_display_channels > 1) {
+ uf *= 0.5 * sin((2 * M_PI * ch) / showspectrum->nb_display_channels);
+ vf *= 0.5 * cos((2 * M_PI * ch) / showspectrum->nb_display_channels);
+ } else {
+ uf = 0.0f;
+ vf = 0.0f;
+ }
+ }
+ uf *= showspectrum->saturation;
+ vf *= showspectrum->saturation;
+
+ /* draw the channel */
+ for (y = 0; y < h; y++) {
+ int row = (showspectrum->mode == COMBINED) ? y : ch * h + y;
+ float *out = &showspectrum->combine_buffer[3 * row];
+
+ /* get magnitude */
+ float a = w * MAGNITUDE(y, ch);
+
+ /* apply scale */
+ switch (showspectrum->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 (showspectrum->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 (showspectrum->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);
+ }
+ }
+ showspectrum->xpos = outlink->w - 1;
+ }
+ for (plane = 0; plane < 3; plane++) {
+ uint8_t *p = outpicref->data[plane] +
+ (outlink->h - 1) * outpicref->linesize[plane] +
+ showspectrum->xpos;
+ for (y = 0; y < outlink->h; y++) {
+ *p = rint(FFMAX(0, FFMIN(showspectrum->combine_buffer[3 * y + plane], 255)));
+ p -= outpicref->linesize[plane];
+ }
+ }
+
+ outpicref->pts = insamples->pts +
+ av_rescale_q(showspectrum->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 *showspectrum = ctx->priv;
+ int ret = 0, left_samples = insamples->nb_samples;
+
+ showspectrum->consumed = 0;
+ while (left_samples) {
+ int ret = plot_spectrum_column(inlink, insamples, left_samples);
+ if (ret < 0)
+ break;
+ showspectrum->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 avfilter_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..e9d3062
--- /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 = av_get_channel_layout_nb_channels(insamples->channel_layout);
+ 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 avfilter_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 b9939a0..b61b706 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -2,26 +2,28 @@
* 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/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/opt.h"
#include "libavutil/pixdesc.h"
@@ -32,21 +34,61 @@
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
-#include "video.h"
+#include "audio.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_command_queue_pop(AVFilterContext *filter)
+{
+ AVFilterCommand *c= filter->command_queue;
+ av_freep(&c->arg);
+ av_freep(&c->command);
+ filter->command_queue= c->next;
+ av_free(c);
}
void ff_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
@@ -81,8 +123,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);
}
@@ -94,12 +137,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)
{
@@ -127,6 +190,7 @@ int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt,
if (link->out_formats)
ff_formats_changeref(&link->out_formats,
&filt->outputs[filt_dstpad_idx]->out_formats);
+
if (link->out_samplerates)
ff_formats_changeref(&link->out_samplerates,
&filt->outputs[filt_dstpad_idx]->out_samplerates);
@@ -145,9 +209,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;
@@ -175,26 +243,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 (inlink && !link->frame_rate.num && !link->frame_rate.den)
+ link->frame_rate = inlink->frame_rate;
- if (link->src->nb_inputs) {
+ if (inlink) {
if (!link->w)
- link->w = link->src->inputs[0]->w;
+ link->w = inlink->w;
if (!link->h)
- link->h = link->src->inputs[0]->h;
+ link->h = inlink->h;
} else if (!link->w || !link->h) {
av_log(link->src, AV_LOG_ERROR,
"Video source filters must set their output link's "
"width and height\n");
return AVERROR(EINVAL);
}
+ break;
+
+ case AVMEDIA_TYPE_AUDIO:
+ if (inlink) {
+ if (!link->time_base.num && !link->time_base.den)
+ link->time_base = inlink->time_base;
+ }
+
+ if (!link->time_base.num && !link->time_base.den)
+ link->time_base = (AVRational) {1, link->sample_rate};
}
if ((config_link = link->dstpad->config_props))
@@ -212,11 +293,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 : "",
@@ -226,9 +307,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 : "",
@@ -238,13 +319,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)
@@ -265,6 +366,72 @@ 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")){
+ av_strlcatf(res, res_len, "pong from:%s %s\n", filter->filter->name, filter->name);
+ 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;
AVFilter *avfilter_get_by_name(const char *name)
@@ -284,10 +451,22 @@ AVFilter *avfilter_get_by_name(const char *name)
int avfilter_register(AVFilter *filter)
{
AVFilter **f = &first_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));
+ }
+
while (*f)
f = &(*f)->next;
*f = filter;
filter->next = NULL;
+
return 0;
}
@@ -318,10 +497,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)
@@ -334,12 +513,18 @@ static void *filter_child_next(void *obj, void *prev)
static const AVClass *filter_child_class_next(const AVClass *prev)
{
- AVFilter *f = NULL;
+ 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;
@@ -347,11 +532,20 @@ static const AVClass *filter_child_class_next(const AVClass *prev)
return NULL;
}
+#define OFFSET(x) offsetof(AVFilterContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption filters_common_options[] = {
+ { "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,
+ .option = filters_common_options,
.child_class_next = filter_child_class_next,
};
@@ -433,6 +627,9 @@ void avfilter_free(AVFilterContext *filter)
int i;
AVFilterLink *link;
+ if (!filter)
+ return;
+
if (filter->graph)
ff_filter_graph_remove_filter(filter->graph, filter);
@@ -450,7 +647,7 @@ void avfilter_free(AVFilterContext *filter)
ff_channel_layouts_unref(&link->in_channel_layouts);
ff_channel_layouts_unref(&link->out_channel_layouts);
}
- av_freep(&link);
+ avfilter_link_free(&link);
}
for (i = 0; i < filter->nb_outputs; i++) {
if ((link = filter->outputs[i])) {
@@ -463,7 +660,7 @@ void avfilter_free(AVFilterContext *filter)
ff_channel_layouts_unref(&link->in_channel_layouts);
ff_channel_layouts_unref(&link->out_channel_layouts);
}
- av_freep(&link);
+ avfilter_link_free(&link);
}
if (filter->filter->priv_class)
@@ -475,40 +672,91 @@ 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_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;
+
+ av_opt_set_defaults(ctx);
+
+ if (!args)
+ return 0;
+
+ while (*args) {
+ const char *shorthand = NULL;
- while (*p) {
o = av_opt_next(ctx->priv, o);
- if (!o) {
- av_log(ctx, AV_LOG_ERROR, "More options provided than "
- "this filter supports.\n");
- return AVERROR(EINVAL);
+ if (o) {
+ if (o->type == AV_OPT_TYPE_CONST || o->offset == offset)
+ continue;
+ offset = o->offset;
+ shorthand = o->name;
}
- if (o->type == AV_OPT_TYPE_CONST)
- continue;
- val = av_get_token(&p, ":");
- if (!val)
- return AVERROR(ENOMEM);
+ ret = av_opt_get_key_value(&args, "=", ":",
+ shorthand ? AV_OPT_FLAG_IMPLICIT_KEY : 0,
+ &parsed_key, &value);
+ if (ret < 0) {
+ if (ret == AVERROR(EINVAL))
+ av_log(ctx, AV_LOG_ERROR, "No option name near '%s'\n", args);
+ else
+ av_log(ctx, AV_LOG_ERROR, "Unable to parse '%s': %s\n", args,
+ av_err2str(ret));
+ return ret;
+ }
+ if (*args)
+ args++;
+ if (parsed_key) {
+ key = parsed_key;
+ while ((o = av_opt_next(ctx->priv, o))); /* discard all remaining shorthand */
+ } else {
+ key = shorthand;
+ }
+
+ av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value);
- av_dict_set(options, o->name, val, 0);
+ if (av_opt_find(ctx, key, NULL, 0, 0)) {
+ ret = av_opt_set(ctx, key, value, 0);
+ if (ret < 0)
+ return ret;
+ } else {
+ av_dict_set(options, key, value, 0);
+ if ((ret = av_opt_set(ctx->priv, key, value, 0)) < 0) {
+ if (!av_opt_find(ctx->priv, key, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) {
+ if (ret == AVERROR_OPTION_NOT_FOUND)
+ av_log(ctx, AV_LOG_ERROR, "Option '%s' not found\n", key);
+ av_free(value);
+ av_free(parsed_key);
+ return ret;
+ }
+ }
+ }
- av_freep(&val);
- if (*p)
- p++;
+ av_free(value);
+ av_free(parsed_key);
+ count++;
}
- return 0;
+ if (ctx->enable_str) {
+ ret = set_enable_expr(ctx, ctx->enable_str);
+ if (ret < 0)
+ return ret;
+ }
+ return count;
}
#if FF_API_AVFILTER_INIT_FILTER
@@ -530,7 +778,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);
@@ -552,51 +802,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);
@@ -618,22 +837,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;
}
@@ -670,14 +925,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;
@@ -686,6 +947,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);
@@ -703,7 +965,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:
@@ -719,7 +981,103 @@ 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 = !av_expr_eval(dstctx->enable, dstctx->var_values, NULL);
+ 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 +
+ 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 51d0fb5..822eca7 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -2,35 +2,46 @@
* 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
*/
#ifndef AVFILTER_AVFILTER_H
#define AVFILTER_AVFILTER_H
+/**
+ * @file
+ * @ingroup lavfi
+ * external API header
+ */
+
+/**
+ * @defgroup lavfi Libavfilter
+ * @{
+ */
+
+#include <stddef.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"
@@ -49,7 +60,6 @@ const char *avfilter_configuration(void);
*/
const char *avfilter_license(void);
-
typedef struct AVFilterContext AVFilterContext;
typedef struct AVFilterLink AVFilterLink;
typedef struct AVFilterPad AVFilterPad;
@@ -102,6 +112,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
@@ -110,9 +123,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;
/**
@@ -123,11 +136,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;
/**
@@ -174,6 +190,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;
/**
@@ -217,11 +235,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.
@@ -240,22 +266,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;
@@ -266,7 +299,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.
*/
@@ -274,7 +307,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.
*/
@@ -297,7 +330,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);
@@ -317,6 +350,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.
*/
@@ -325,15 +360,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);
@@ -390,6 +428,28 @@ enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx);
* the options supplied to it.
*/
#define AVFILTER_FLAG_DYNAMIC_OUTPUTS (1 << 1)
+/**
+ * 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
@@ -447,9 +507,9 @@ typedef struct AVFilter {
void (*uninit)(AVFilterContext *ctx);
/**
- * Queries formats supported by the filter and its pads, and sets the
- * in_formats for links connected to its output pads, and out_formats
- * for links connected to its input pads.
+ * Queries formats/layouts supported by the filter and its pads, and sets
+ * the in_formats/in_chlayouts for links connected to its output pads,
+ * and out_formats/out_chlayouts for links connected to its input pads.
*
* @return zero on success, a negative value corresponding to an
* AVERROR code otherwise
@@ -459,11 +519,32 @@ typedef struct AVFilter {
int priv_size; ///< size of private data to allocate for the filter
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;
/** 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
@@ -486,6 +567,13 @@ struct AVFilterContext {
void *priv; ///< private data for use by the filter
struct AVFilterGraph *graph; ///< filtergraph this filter belongs to
+
+ 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
};
/**
@@ -508,7 +596,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
@@ -531,9 +619,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;
@@ -562,6 +652,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;
};
/**
@@ -577,6 +765,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
@@ -598,13 +801,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
@@ -619,8 +825,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);
@@ -637,7 +875,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);
@@ -786,7 +1024,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
@@ -798,6 +1036,19 @@ typedef struct AVFilterGraph {
#if FF_API_FOO_COUNT
unsigned nb_filters;
#endif
+ 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;
/**
@@ -863,6 +1114,21 @@ int avfilter_graph_create_filter(AVFilterContext **filt_ctx, AVFilter *filt,
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
@@ -918,12 +1184,16 @@ void avfilter_inout_free(AVFilterInOut **inout);
*
* @param graph the filter graph where to link the parsed graph context
* @param filters string to be parsed
- * @param inputs linked list to the inputs of the graph
- * @param outputs linked list to the outputs of the graph
- * @return zero on success, a negative AVERROR code on error
+ * @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(AVFilterGraph *graph, const char *filters,
- AVFilterInOut *inputs, AVFilterInOut *outputs,
+ AVFilterInOut **inputs, AVFilterInOut **outputs,
void *log_ctx);
/**
@@ -960,4 +1230,72 @@ int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
AVFilterInOut **inputs,
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);
+
+/**
+ * @}
+ */
#endif /* AVFILTER_AVFILTER_H */
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 9131026..7ae8a37 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
*/
@@ -24,17 +24,30 @@
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
#include "libavutil/channel_layout.h"
-#include "libavutil/common.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"
#include "internal.h"
+#define OFFSET(x) offsetof(AVFilterGraph,x)
+
+static const AVOption options[]={
+{"scale_sws_opts" , "default scale filter options" , OFFSET(scale_sws_opts) , AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, 0 },
+{"aresample_swr_opts" , "default aresample filter options" , OFFSET(aresample_swr_opts) , AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, 0 },
+{0}
+};
+
+
static const AVClass filtergraph_class = {
.class_name = "AVFilterGraph",
.item_name = av_default_item_name,
+ .option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_FILTER,
};
AVFilterGraph *avfilter_graph_alloc(void)
@@ -67,7 +80,9 @@ void avfilter_graph_free(AVFilterGraph **graph)
while ((*graph)->nb_filters)
avfilter_free((*graph)->filters[0]);
+ 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);
@@ -85,7 +100,7 @@ int avfilter_graph_add_filter(AVFilterGraph *graph, AVFilterContext *filter)
graph->filters[graph->nb_filters++] = filter;
#if FF_API_FOO_COUNT
- graph->filter_count = graph->nb_filters;
+ graph->filter_count_unused = graph->nb_filters;
#endif
filter->graph = graph;
@@ -117,6 +132,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)
@@ -137,7 +157,7 @@ AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph,
graph->filters[graph->nb_filters++] = s;
#if FF_API_FOO_COUNT
- graph->filter_count = graph->nb_filters;
+ graph->filter_count_unused = graph->nb_filters;
#endif
s->graph = graph;
@@ -159,22 +179,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);
}
}
@@ -216,17 +239,114 @@ 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;
+}
+
+/**
+ * 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 */
@@ -240,20 +360,33 @@ 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))
+#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 { \
+ count_merged++; \
+ statement \
+ }
+ MERGE_DISPATCH(formats,
+ if (!ff_merge_formats(link->in_formats, link->out_formats,
+ link->type))
convert_needed = 1;
+ )
+ 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;
+ )
}
+#undef MERGE_DISPATCH
if (convert_needed) {
AVFilterContext *convert;
@@ -280,8 +413,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);
}
@@ -289,11 +422,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;
@@ -304,11 +437,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,
@@ -333,14 +466,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->format_count; 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->format_count,
+ av_get_pix_fmt_name(ref->format), has_alpha);
+ link->in_formats->formats[0] = best;
+ }
+ }
+
link->in_formats->format_count = 1;
link->format = link->in_formats->formats[0];
@@ -354,14 +527,18 @@ static int pick_format(AVFilterLink *link)
link->in_samplerates->format_count = 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);
@@ -417,8 +594,42 @@ static int reduce_formats_on_filter(AVFilterContext *filter)
format_count, ff_add_format);
REDUCE_FORMATS(int, AVFilterFormats, samplerates, formats,
format_count, 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;
}
@@ -546,7 +757,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++) {
@@ -669,15 +896,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->format_count == 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->format_count == 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;
@@ -691,7 +953,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
@@ -711,6 +975,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;
@@ -761,6 +1067,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
--- /dev/null
+++ b/libavfilter/bbox.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2005 Robert Edele <yartrebo@earthlink.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "bbox.h"
+
+int ff_calculate_bounding_box(FFBoundingBox *bbox,
+ const uint8_t *data, int linesize, int w, int h,
+ int min_val)
+{
+ int x, y;
+ int start_x;
+ int start_y;
+ int end_x;
+ int end_y;
+ const uint8_t *line;
+
+ /* left bound */
+ for (start_x = 0; start_x < w; start_x++)
+ for (y = 0; y < h; y++)
+ if ((data[y * linesize + start_x] > min_val))
+ goto outl;
+outl:
+ if (start_x == w) /* no points found */
+ return 0;
+
+ /* right bound */
+ for (end_x = w - 1; end_x >= start_x; end_x--)
+ for (y = 0; y < h; y++)
+ if ((data[y * linesize + end_x] > min_val))
+ goto outr;
+outr:
+
+ /* top bound */
+ line = data;
+ for (start_y = 0; start_y < h; start_y++) {
+ for (x = 0; x < w; x++)
+ if (line[x] > min_val)
+ goto outt;
+ line += linesize;
+ }
+outt:
+
+ /* bottom bound */
+ line = data + (h-1)*linesize;
+ for (end_y = h - 1; end_y >= start_y; end_y--) {
+ for (x = 0; x < w; x++)
+ if (line[x] > min_val)
+ goto outb;
+ line -= linesize;
+ }
+outb:
+
+ bbox->x1 = start_x;
+ bbox->y1 = start_y;
+ bbox->x2 = end_x;
+ bbox->y2 = end_y;
+ return 1;
+}
diff --git a/libavfilter/bbox.h b/libavfilter/bbox.h
new file mode 100644
index 0000000..eb73154
--- /dev/null
+++ b/libavfilter/bbox.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005 Robert Edele <yartrebo@earthlink.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFILTER_BBOX_H
+#define AVFILTER_BBOX_H
+
+#include <stdint.h>
+
+typedef struct {
+ int x1, x2, y1, y2;
+} FFBoundingBox;
+
+/**
+ * Calculate the smallest rectangle that will encompass the
+ * region with values > min_val.
+ *
+ * @param bbox bounding box structure which is updated with the found values.
+ * If no pixels could be found with value > min_val, the
+ * structure is not modified.
+ * @return 1 in case at least one pixel with value > min_val was found,
+ * 0 otherwise
+ */
+int ff_calculate_bounding_box(FFBoundingBox *bbox,
+ const uint8_t *data, int linesize,
+ int w, int h, int min_val);
+
+#endif /* AVFILTER_BBOX_H */
diff --git a/libavfilter/buffer.c b/libavfilter/buffer.c
index 8eb3ce3..29fedc4 100644
--- a/libavfilter/buffer.c
+++ b/libavfilter/buffer.c
@@ -1,29 +1,36 @@
/*
- * 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"
-/* 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)
@@ -32,19 +39,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));
@@ -54,7 +74,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))) {
@@ -76,12 +96,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);
}
@@ -94,13 +118,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;
@@ -117,50 +145,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
@@ -168,8 +152,16 @@ 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);
}
diff --git a/libavfilter/bufferqueue.h b/libavfilter/bufferqueue.h
new file mode 100644
index 0000000..adbc0fd
--- /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 94e7366..bd07c58 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
*/
@@ -28,6 +28,7 @@
#include "libavutil/channel_layout.h"
#include "libavutil/common.h"
#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
#include "audio.h"
#include "avfilter.h"
@@ -35,44 +36,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;
+}
+
+int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame)
+{
+ return av_buffersink_get_frame_flags(ctx, frame, 0);
+}
- if (!s->cur_frame)
+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;
}
@@ -104,10 +181,11 @@ int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
{
BufferSinkContext *s = ctx->priv;
AVFilterLink *link = ctx->inputs[0];
+ AVFrame *cur_frame;
int ret = 0;
if (!s->audio_fifo) {
- int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
+ int nb_channels = link->channels;
if (!(s->audio_fifo = av_audio_fifo_alloc(link->format, nb_channels, nb_samples)))
return AVERROR(ENOMEM);
}
@@ -116,28 +194,76 @@ int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
if (av_audio_fifo_size(s->audio_fifo) >= nb_samples)
return read_from_fifo(ctx, frame, nb_samples);
- ret = ff_request_frame(link);
- if (ret == AVERROR_EOF && av_audio_fifo_size(s->audio_fifo))
+ if (!(cur_frame = av_frame_alloc()))
+ return AVERROR(ENOMEM);
+ ret = av_buffersink_get_frame_flags(ctx, cur_frame, 0);
+ if (ret == AVERROR_EOF && av_audio_fifo_size(s->audio_fifo)) {
+ av_frame_free(&cur_frame);
return read_from_fifo(ctx, frame, av_audio_fifo_size(s->audio_fifo));
- else if (ret < 0)
+ } else if (ret < 0) {
+ av_frame_free(&cur_frame);
return ret;
+ }
- if (s->cur_frame->pts != AV_NOPTS_VALUE) {
- s->next_pts = s->cur_frame->pts -
+ if (cur_frame->pts != AV_NOPTS_VALUE) {
+ s->next_pts = cur_frame->pts -
av_rescale_q(av_audio_fifo_size(s->audio_fifo),
(AVRational){ 1, link->sample_rate },
link->time_base);
}
- ret = av_audio_fifo_write(s->audio_fifo, (void**)s->cur_frame->extended_data,
- s->cur_frame->nb_samples);
- av_frame_free(&s->cur_frame);
+ ret = av_audio_fifo_write(s->audio_fifo, (void**)cur_frame->extended_data,
+ cur_frame->nb_samples);
+ av_frame_free(&cur_frame);
}
return ret;
}
+AVBufferSinkParams *av_buffersink_params_alloc(void)
+{
+ static const int pixel_fmts[] = { AV_PIX_FMT_NONE };
+ AVBufferSinkParams *params = av_malloc(sizeof(AVBufferSinkParams));
+ if (!params)
+ return NULL;
+
+ params->pixel_fmts = pixel_fmts;
+ return params;
+}
+
+AVABufferSinkParams *av_abuffersink_params_alloc(void)
+{
+ AVABufferSinkParams *params = av_mallocz(sizeof(AVABufferSinkParams));
+
+ if (!params)
+ return NULL;
+ return params;
+}
+
+#define FIFO_INIT_SIZE 8
+
+static av_cold int common_init(AVFilterContext *ctx)
+{
+ BufferSinkContext *buf = ctx->priv;
+
+ buf->fifo = av_fifo_alloc(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;
+ 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
static void compat_free_buffer(AVFilterBuffer *buf)
{
@@ -147,7 +273,7 @@ static void compat_free_buffer(AVFilterBuffer *buf)
}
static int attribute_align_arg compat_read(AVFilterContext *ctx,
- AVFilterBufferRef **pbuf, int nb_samples)
+ AVFilterBufferRef **pbuf, int nb_samples, int flags)
{
AVFilterBufferRef *buf;
AVFrame *frame;
@@ -161,13 +287,14 @@ static int attribute_align_arg 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 +313,7 @@ static int attribute_align_arg compat_read(AVFilterContext *ctx,
}
avfilter_copy_frame_props(buf, frame);
+ )
buf->buf->priv = frame;
buf->buf->free = compat_free_buffer;
@@ -200,22 +328,244 @@ fail:
int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
{
- return compat_read(ctx, buf, 0);
+ return compat_read(ctx, buf, 0, 0);
}
int 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 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);
}
#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 avfilter_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 avfilter_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 }
};
@@ -224,8 +574,11 @@ AVFilter avfilter_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,
};
@@ -235,7 +588,6 @@ static const AVFilterPad avfilter_asink_abuffer_inputs[] = {
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.filter_frame = filter_frame,
- .needs_fifo = 1
},
{ NULL }
};
@@ -243,9 +595,12 @@ static const AVFilterPad avfilter_asink_abuffer_inputs[] = {
AVFilter avfilter_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 5e982ea..5d834b5 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
*/
@@ -38,22 +38,28 @@
#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;
@@ -62,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 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 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 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 attribute_align_arg 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)
@@ -129,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;
}
@@ -136,16 +177,21 @@ int attribute_align_arg av_buffersrc_add_frame(AVFilterContext *ctx,
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;
@@ -162,14 +208,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 { \
@@ -179,7 +228,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); \
@@ -227,7 +276,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);
@@ -235,41 +284,47 @@ fail:
return ret;
}
+
+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 */
@@ -279,31 +334,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)
{
@@ -312,17 +361,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);
@@ -330,9 +398,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;
}
@@ -368,7 +438,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:
@@ -389,14 +461,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;
}
@@ -404,18 +477,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)
@@ -442,7 +513,6 @@ AVFilter avfilter_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,
@@ -450,6 +520,7 @@ AVFilter avfilter_vsrc_buffer = {
.inputs = NULL,
.outputs = avfilter_vsrc_buffer_outputs,
+ .priv_class = &buffer_class,
};
static const AVFilterPad avfilter_asrc_abuffer_outputs[] = {
@@ -467,7 +538,6 @@ AVFilter avfilter_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,
@@ -475,4 +545,5 @@ AVFilter avfilter_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..66361b3 100644
--- a/libavfilter/buffersrc.h
+++ b/libavfilter/buffersrc.h
@@ -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
--- /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
--- /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
--- /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
--- /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..272d9df 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;
@@ -118,3 +141,422 @@ void ff_copy_rectangle(uint8_t *dst[4], int dst_linesize[4],
}
}
}
+
+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));
+ if (nb_planes >= 3 && !(desc->flags & AV_PIX_FMT_FLAG_RGB)) {
+ 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) && draw->nb_planes == 1 &&
+ ff_fill_rgba_map(rgba_map, draw->format) >= 0) {
+ for (i = 0; i < 4; i++)
+ color->comp[0].u8[rgba_map[i]] = 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 = (w >> draw->hsub[plane]) * draw->pixelstep[plane];
+ hp = (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 = (w >> draw->hsub[plane]);
+ hp = (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/f_ebur128.c b/libavfilter/f_ebur128.c
new file mode 100644
index 0000000..88d37e8
--- /dev/null
+++ b/libavfilter/f_ebur128.c
@@ -0,0 +1,800 @@
+/*
+ * 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)
+
+/**
+ * An 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 negociation */
+ 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,
+ .get_audio_buffer = ff_null_get_audio_buffer,
+ .filter_frame = filter_frame,
+ .config_props = config_audio_input,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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..33cb8cd
--- /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 *interleave = 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 = &interleave->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(&interleave->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 *interleave = 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, interleave->queues[in_no].available);
+ ff_bufqueue_add(ctx, &interleave->queues[in_no], frame);
+
+ return push_frame(ctx);
+}
+
+static int init(AVFilterContext *ctx)
+{
+ InterleaveContext *interleave = ctx->priv;
+ const AVFilterPad *outpad = &ctx->filter->outputs[0];
+ int i;
+
+ interleave->queues = av_calloc(interleave->nb_inputs, sizeof(interleave->queues[0]));
+ if (!interleave->queues)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < interleave->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 *interleave = ctx->priv;
+ int i;
+
+ for (i = 0; i < ctx->nb_inputs; i++) {
+ ff_bufqueue_discard_all(&interleave->queues[i]);
+ av_freep(&interleave->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 *interleave = ctx->priv;
+ int i, ret;
+
+ for (i = 0; i < ctx->nb_inputs; i++) {
+ if (!interleave->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 avfilter_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 avfilter_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..8dc2ed8
--- /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 avfilter_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 avfilter_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..07a64f3
--- /dev/null
+++ b/libavfilter/f_select.c
@@ -0,0 +1,537 @@
+/*
+ * 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,
+ .get_audio_buffer = ff_null_get_audio_buffer,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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,
+ .get_video_buffer = ff_null_get_video_buffer,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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..9c7c5f5
--- /dev/null
+++ b/libavfilter/f_sendcmd.c
@@ -0,0 +1,578 @@
+/*
+ * 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)
+{
+ const char *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,
+ .get_video_buffer = ff_null_get_video_buffer,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad sendcmd_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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,
+ .get_audio_buffer = ff_null_get_audio_buffer,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad asendcmd_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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/vf_settb.c b/libavfilter/f_settb.c
index bf1f633..b1eac71 100644
--- a/libavfilter/vf_settb.c
+++ b/libavfilter/f_settb.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Stefano Sabatini
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,23 +34,20 @@
#include "libavutil/rational.h"
#include "avfilter.h"
#include "internal.h"
+#include "audio.h"
#include "video.h"
static const char *const var_names[] = {
- "E",
- "PHI",
- "PI",
"AVTB", /* default timebase 1/AV_TIME_BASE */
"intb", /* input timebase */
+ "sr", /* sample rate */
NULL
};
enum var_name {
- VAR_E,
- VAR_PHI,
- VAR_PI,
VAR_AVTB,
VAR_INTB,
+ VAR_SR,
VAR_VARS_NB
};
@@ -60,6 +57,16 @@ typedef struct {
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;
@@ -69,11 +76,9 @@ static int config_output_props(AVFilterLink *outlink)
int ret;
double res;
- settb->var_values[VAR_E] = M_E;
- settb->var_values[VAR_PHI] = M_PHI;
- settb->var_values[VAR_PI] = M_PI;
settb->var_values[VAR_AVTB] = av_q2d(AV_TIME_BASE_Q);
settb->var_values[VAR_INTB] = av_q2d(inlink->time_base);
+ settb->var_values[VAR_SR] = inlink->sample_rate;
outlink->w = inlink->w;
outlink->h = inlink->h;
@@ -115,19 +120,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
return ff_filter_frame(outlink, frame);
}
-#define OFFSET(x) offsetof(SetTBContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "expr", "Expression determining the output timebase", OFFSET(tb_expr), AV_OPT_TYPE_STRING, { .str = "intb" }, .flags = FLAGS },
- { NULL },
-};
+#if CONFIG_SETTB_FILTER
-static const AVClass settb_class = {
- .class_name = "settb",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+DEFINE_OPTIONS(settb, VIDEO);
+AVFILTER_DEFINE_CLASS(settb);
static const AVFilterPad avfilter_vf_settb_inputs[] = {
{
@@ -150,12 +146,47 @@ static const AVFilterPad avfilter_vf_settb_outputs[] = {
AVFilter avfilter_vf_settb = {
.name = "settb",
- .description = NULL_IF_CONFIG_SMALL("Set timebase for the output link."),
+ .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,
+ .get_audio_buffer = ff_null_get_audio_buffer,
+ .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 avfilter_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..547e1a3
--- /dev/null
+++ b/libavfilter/f_zmq.c
@@ -0,0 +1,276 @@
+/*
+ * 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 avfilter_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,
+ .get_audio_buffer = ff_null_get_audio_buffer,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad azmq_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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 8d981ce..b06720e 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
*/
@@ -229,6 +229,7 @@ static int request_frame(AVFilterLink *outlink)
if (!fifo->root.next) {
if ((ret = ff_request_frame(outlink->src->inputs[0])) < 0)
return ret;
+ av_assert0(fifo->root.next);
}
if (outlink->request_samples) {
diff --git a/libavfilter/filtfmts.c b/libavfilter/filtfmts.c
index 1ac3116..61b002d 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,26 +22,66 @@
#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->inout##put_count; 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->format_count; 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->format_count; 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;
AVFilterContext *filter_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];
avfilter_register_all();
@@ -80,23 +120,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->format_count; 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->format_count; 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);
fflush(stdout);
diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index c7b8075..016aecd 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->format_count; i++)
+ for (j = 0; j < b->format_count; 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, format_count, 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,72 @@ 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; \
+ } \
+}
+
+int *ff_copy_int_list(const int * const list)
+{
+ int *ret = NULL;
+ COPY_INT_LIST(ret, list, int);
+ return ret;
+}
+
+int64_t *ff_copy_int64_list(const int64_t * const list)
+{
+ int64_t *ret = NULL;
+ COPY_INT_LIST(ret, list, int64_t);
+ return ret;
+}
+
+#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, format_count);
+ 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->format_count = count;
- memcpy(formats->formats, fmts, sizeof(*formats->formats) * count);
+ memcpy(formats->channel_layouts, fmts,
+ sizeof(*formats->channel_layouts) * count);
return formats;
}
@@ -193,17 +339,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, format_count);
+ 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 +371,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 +402,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 +504,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 +548,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 +557,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 0e1628c..c06f6df 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/gradfun.h b/libavfilter/gradfun.h
index 01e9eed..7b1140f 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.washignton.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..756f63d
--- /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->input_count; 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->output_count; 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->input_count, filter->output_count);
+ 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->input_count ) / 2;
+ unsigned out_no = j - (height - filter->output_count) / 2;
+
+ /* Input link */
+ if (in_no < filter->input_count) {
+ 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->output_count) {
+ 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..9241cf3 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
*/
@@ -99,7 +99,7 @@ static int create_filter(AVFilterContext **filt_ctx, AVFilterGraph *ctx, int ind
char tmp_args[256];
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);
@@ -383,7 +383,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 +398,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 +423,17 @@ int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
"Unable to parse graph description substring: \"%s\"\n",
filters - 1);
ret = AVERROR(EINVAL);
- goto fail;
+ goto end;
}
append_inout(&open_outputs, &curr_inputs);
+
*inputs = open_inputs;
*outputs = open_outputs;
return 0;
- fail:
+ fail:end:
while (graph->nb_filters)
avfilter_free(graph->filters[0]);
av_freep(&graph->filters);
@@ -448,10 +448,13 @@ int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
}
int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
- AVFilterInOut *open_inputs,
- AVFilterInOut *open_outputs, void *log_ctx)
+ AVFilterInOut **open_inputs_ptr, AVFilterInOut **open_outputs_ptr,
+ void *log_ctx)
{
+#if 0
int ret;
+ AVFilterInOut *open_inputs = open_inputs_ptr ? *open_inputs_ptr : NULL;
+ AVFilterInOut *open_outputs = open_outputs_ptr ? *open_outputs_ptr : NULL;
AVFilterInOut *cur, *match, *inputs = NULL, *outputs = NULL;
if ((ret = avfilter_graph_parse2(graph, filters, &inputs, &outputs)) < 0)
@@ -505,7 +508,92 @@ int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
}
avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs);
- avfilter_inout_free(&open_inputs);
- avfilter_inout_free(&open_outputs);
+ /* 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);
return ret;
}
+#else
+ 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->input_count == 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;
+}
+
+#endif
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index 8e8a13f..fbe9356 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
*/
@@ -25,6 +25,30 @@
*/
#include "avfilter.h"
+#include "avfiltergraph.h"
+#include "formats.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
/**
@@ -45,7 +69,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.
*/
@@ -53,7 +77,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.
*/
@@ -123,9 +147,91 @@ 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)
+/**
+ * Return a copy of a list of integers terminated by -1, or NULL in
+ * case of copy failure.
+ */
+int *ff_copy_int_list(const int * const list);
+
+/**
+ * Return a copy of a list of 64-bit integers, or NULL in case of
+ * copy failure.
+ */
+int64_t *ff_copy_int64_list(const int64_t * const list);
+
+/* 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 */
-void ff_dlog_link(void *ctx, AVFilterLink *link, int end);
+/* #define FF_AVFILTER_TRACE */
+
+#ifdef FF_AVFILTER_TRACE
+# define ff_tlog(pctx, ...) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__)
+#else
+# define ff_tlog(pctx, ...) do { if (0) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0)
+#endif
+
+#define FF_TPRINTF_START(ctx, func) ff_tlog(NULL, "%-16s: ", #func)
+
+char *ff_get_ref_perms_string(char *buf, size_t buf_size, int perms);
+
+void ff_tlog_ref(void *ctx, AVFrame *ref, int end);
+
+void ff_tlog_link(void *ctx, AVFilterLink *link, int end);
/**
* Insert a new pad.
@@ -183,6 +289,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.
*
@@ -197,6 +326,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..8b6b114
--- /dev/null
+++ b/libavfilter/lavfutils.c
@@ -0,0 +1,95 @@
+/*
+ * 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_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:
+ 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..a310e83
--- /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
--- /dev/null
+++ b/libavfilter/libmpcodecs/av_helpers.h
@@ -0,0 +1,27 @@
+/*
+ * Generic libav* helpers
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_AV_HELPERS_H
+#define MPLAYER_AV_HELPERS_H
+
+void ff_init_avcodec(void);
+void ff_init_avformat(void);
+
+#endif /* MPLAYER_AV_HELPERS_H */
diff --git a/libavfilter/libmpcodecs/cpudetect.h b/libavfilter/libmpcodecs/cpudetect.h
new file mode 100644
index 0000000..710f6e6
--- /dev/null
+++ b/libavfilter/libmpcodecs/cpudetect.h
@@ -0,0 +1,60 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_CPUDETECT_H
+#define MPLAYER_CPUDETECT_H
+
+#define CPUTYPE_I386 3
+#define CPUTYPE_I486 4
+#define CPUTYPE_I586 5
+#define CPUTYPE_I686 6
+
+#include "libavutil/x86_cpu.h"
+
+typedef struct cpucaps_s {
+ int cpuType;
+ int cpuModel;
+ int cpuStepping;
+ int hasMMX;
+ int hasMMX2;
+ int has3DNow;
+ int has3DNowExt;
+ int hasSSE;
+ int hasSSE2;
+ int hasSSE3;
+ int hasSSSE3;
+ int hasSSE4;
+ int hasSSE42;
+ int hasSSE4a;
+ int hasAVX;
+ int isX86;
+ unsigned cl_size; /* size of cache line */
+ int hasAltiVec;
+ int hasTSC;
+} CpuCaps;
+
+extern CpuCaps ff_gCpuCaps;
+
+void ff_do_cpuid(unsigned int ax, unsigned int *p);
+
+void ff_GetCpuCaps(CpuCaps *caps);
+
+/* returned value is malloc()'ed so free() it after use */
+char *ff_GetCpuFriendlyName(unsigned int regs[], unsigned int regs2[]);
+
+#endif /* MPLAYER_CPUDETECT_H */
diff --git a/libavfilter/libmpcodecs/help_mp.h b/libavfilter/libmpcodecs/help_mp.h
new file mode 100644
index 0000000..6ceb630
--- /dev/null
+++ b/libavfilter/libmpcodecs/help_mp.h
@@ -0,0 +1,2126 @@
+/* WARNING! This is a generated file, do NOT edit.
+ * See the help/ subdirectory for the editable files. */
+
+#ifndef MPLAYER_HELP_MP_H
+#define MPLAYER_HELP_MP_H
+
+// $Revision: 32397 $
+// MASTER FILE. Use this file as base for translations.
+// Translated files should be sent to the mplayer-DOCS mailing list or
+// to the help messages maintainer, see DOCS/tech/MAINTAINERS.
+// The header of the translated file should contain credits and contact
+// information. Before major releases we will notify all translators to update
+// their files. Please do not simply translate and forget this, outdated
+// translations quickly become worthless. To help us spot outdated files put a
+// note like "sync'ed with help_mp-en.h XXX" in the header of the translation.
+// Do NOT translate the above lines, just follow the instructions.
+
+
+// ========================= MPlayer help ===========================
+
+static const char help_text[]=
+"Usage: mplayer [options] [url|path/]filename\n"
+"\n"
+"Basic options: (complete list in the man page)\n"
+" -vo <drv> select video output driver ('-vo help' for a list)\n"
+" -ao <drv> select audio output driver ('-ao help' for a list)\n"
+#ifdef CONFIG_VCD
+" vcd://<trackno> play (S)VCD (Super Video CD) track (raw device, no mount)\n"
+#endif
+#ifdef CONFIG_DVDREAD
+" dvd://<titleno> play DVD title from device instead of plain file\n"
+#endif
+" -alang/-slang select DVD audio/subtitle language (by 2-char country code)\n"
+" -ss <position> seek to given (seconds or hh:mm:ss) position\n"
+" -nosound do not play sound\n"
+" -fs fullscreen playback (or -vm, -zoom, details in the man page)\n"
+" -x <x> -y <y> set display resolution (for use with -vm or -zoom)\n"
+" -sub <file> specify subtitle file to use (also see -subfps, -subdelay)\n"
+" -playlist <file> specify playlist file\n"
+" -vid x -aid y select video (x) and audio (y) stream to play\n"
+" -fps x -srate y change video (x fps) and audio (y Hz) rate\n"
+" -pp <quality> enable postprocessing filter (details in the man page)\n"
+" -framedrop enable frame dropping (for slow machines)\n"
+"\n"
+"Basic keys: (complete list in the man page, also check input.conf)\n"
+" <- or -> seek backward/forward 10 seconds\n"
+" down or up seek backward/forward 1 minute\n"
+" pgdown or pgup seek backward/forward 10 minutes\n"
+" < or > step backward/forward in playlist\n"
+" p or SPACE pause movie (press any key to continue)\n"
+" q or ESC stop playing and quit program\n"
+" + or - adjust audio delay by +/- 0.1 second\n"
+" o cycle OSD mode: none / seekbar / seekbar + timer\n"
+" * or / increase or decrease PCM volume\n"
+" x or z adjust subtitle delay by +/- 0.1 second\n"
+" r or t adjust subtitle position up/down, also see -vf expand\n"
+"\n"
+" * * * SEE THE MAN PAGE FOR DETAILS, FURTHER (ADVANCED) OPTIONS AND KEYS * * *\n"
+"\n";
+
+// ========================= MPlayer messages ===========================
+
+// mplayer.c
+#define MSGTR_Exiting "\nExiting...\n"
+#define MSGTR_ExitingHow "\nExiting... (%s)\n"
+#define MSGTR_Exit_quit "Quit"
+#define MSGTR_Exit_eof "End of file"
+#define MSGTR_Exit_error "Fatal error"
+#define MSGTR_IntBySignal "\nMPlayer interrupted by signal %d in module: %s\n"
+#define MSGTR_NoHomeDir "Cannot find HOME directory.\n"
+#define MSGTR_GetpathProblem "get_path(\"config\") problem\n"
+#define MSGTR_CreatingCfgFile "Creating config file: %s\n"
+#define MSGTR_CantLoadFont "Cannot load bitmap font '%s'.\n"
+#define MSGTR_CantLoadSub "Cannot load subtitles '%s'.\n"
+#define MSGTR_DumpSelectedStreamMissing "dump: FATAL: Selected stream missing!\n"
+#define MSGTR_CantOpenDumpfile "Cannot open dump file.\n"
+#define MSGTR_CoreDumped "Core dumped ;)\n"
+#define MSGTR_DumpBytesWrittenPercent "dump: %"PRIu64" bytes written (~%.1f%%)\r"
+#define MSGTR_DumpBytesWritten "dump: %"PRIu64" bytes written\r"
+#define MSGTR_DumpBytesWrittenTo "dump: %"PRIu64" bytes written to '%s'.\n"
+#define MSGTR_FPSnotspecified "FPS not specified in the header or invalid, use the -fps option.\n"
+#define MSGTR_TryForceAudioFmtStr "Trying to force audio codec driver family %s...\n"
+#define MSGTR_CantFindAudioCodec "Cannot find codec for audio format 0x%X.\n"
+#define MSGTR_TryForceVideoFmtStr "Trying to force video codec driver family %s...\n"
+#define MSGTR_CantFindVideoCodec "Cannot find codec matching selected -vo and video format 0x%X.\n"
+#define MSGTR_CannotInitVO "FATAL: Cannot initialize video driver.\n"
+#define MSGTR_CannotInitAO "Could not open/initialize audio device -> no sound.\n"
+#define MSGTR_StartPlaying "Starting playback...\n"
+
+#define MSGTR_SystemTooSlow "\n\n"\
+" ************************************************\n"\
+" **** Your system is too SLOW to play this! ****\n"\
+" ************************************************\n\n"\
+"Possible reasons, problems, workarounds:\n"\
+"- Most common: broken/buggy _audio_ driver\n"\
+" - Try -ao sdl or use the OSS emulation of ALSA.\n"\
+" - Experiment with different values for -autosync, 30 is a good start.\n"\
+"- Slow video output\n"\
+" - Try a different -vo driver (-vo help for a list) or try -framedrop!\n"\
+"- Slow CPU\n"\
+" - Don't try to play a big DVD/DivX on a slow CPU! Try some of the lavdopts,\n"\
+" e.g. -vfm ffmpeg -lavdopts lowres=1:fast:skiploopfilter=all.\n"\
+"- Broken file\n"\
+" - Try various combinations of -nobps -ni -forceidx -mc 0.\n"\
+"- Slow media (NFS/SMB mounts, DVD, VCD etc)\n"\
+" - Try -cache 8192.\n"\
+"- Are you using -cache to play a non-interleaved AVI file?\n"\
+" - Try -nocache.\n"\
+"Read DOCS/HTML/en/video.html for tuning/speedup tips.\n"\
+"If none of this helps you, read DOCS/HTML/en/bugreports.html.\n\n"
+
+#define MSGTR_NoGui "MPlayer was compiled WITHOUT GUI support.\n"
+#define MSGTR_GuiNeedsX "MPlayer GUI requires X11.\n"
+#define MSGTR_Playing "\nPlaying %s.\n"
+#define MSGTR_NoSound "Audio: no sound\n"
+#define MSGTR_FPSforced "FPS forced to be %5.3f (ftime: %5.3f).\n"
+#define MSGTR_AvailableVideoOutputDrivers "Available video output drivers:\n"
+#define MSGTR_AvailableAudioOutputDrivers "Available audio output drivers:\n"
+#define MSGTR_AvailableAudioCodecs "Available audio codecs:\n"
+#define MSGTR_AvailableVideoCodecs "Available video codecs:\n"
+#define MSGTR_AvailableAudioFm "Available (compiled-in) audio codec families/drivers:\n"
+#define MSGTR_AvailableVideoFm "Available (compiled-in) video codec families/drivers:\n"
+#define MSGTR_AvailableFsType "Available fullscreen layer change modes:\n"
+#define MSGTR_CannotReadVideoProperties "Video: Cannot read properties.\n"
+#define MSGTR_NoStreamFound "No stream found.\n"
+#define MSGTR_ErrorInitializingVODevice "Error opening/initializing the selected video_out (-vo) device.\n"
+#define MSGTR_ForcedVideoCodec "Forced video codec: %s\n"
+#define MSGTR_ForcedAudioCodec "Forced audio codec: %s\n"
+#define MSGTR_Video_NoVideo "Video: no video\n"
+#define MSGTR_NotInitializeVOPorVO "\nFATAL: Could not initialize video filters (-vf) or video output (-vo).\n"
+#define MSGTR_Paused " ===== PAUSE =====" // no more than 23 characters (status line for audio files)
+#define MSGTR_PlaylistLoadUnable "\nUnable to load playlist %s.\n"
+#define MSGTR_Exit_SIGILL_RTCpuSel \
+"- MPlayer crashed by an 'Illegal Instruction'.\n"\
+" It may be a bug in our new runtime CPU-detection code...\n"\
+" Please read DOCS/HTML/en/bugreports.html.\n"
+#define MSGTR_Exit_SIGILL \
+"- MPlayer crashed by an 'Illegal Instruction'.\n"\
+" It usually happens when you run it on a CPU different than the one it was\n"\
+" compiled/optimized for.\n"\
+" Verify this!\n"
+#define MSGTR_Exit_SIGSEGV_SIGFPE \
+"- MPlayer crashed by bad usage of CPU/FPU/RAM.\n"\
+" Recompile MPlayer with --enable-debug and make a 'gdb' backtrace and\n"\
+" disassembly. Details in DOCS/HTML/en/bugreports_what.html#bugreports_crash.\n"
+#define MSGTR_Exit_SIGCRASH \
+"- MPlayer crashed. This shouldn't happen.\n"\
+" It can be a bug in the MPlayer code _or_ in your drivers _or_ in your\n"\
+" gcc version. If you think it's MPlayer's fault, please read\n"\
+" DOCS/HTML/en/bugreports.html and follow the instructions there. We can't and\n"\
+" won't help unless you provide this information when reporting a possible bug.\n"
+#define MSGTR_LoadingConfig "Loading config '%s'\n"
+#define MSGTR_LoadingProtocolProfile "Loading protocol-related profile '%s'\n"
+#define MSGTR_LoadingExtensionProfile "Loading extension-related profile '%s'\n"
+#define MSGTR_AddedSubtitleFile "SUB: Added subtitle file (%d): %s\n"
+#define MSGTR_RemovedSubtitleFile "SUB: Removed subtitle file (%d): %s\n"
+#define MSGTR_ErrorOpeningOutputFile "Error opening file [%s] for writing!\n"
+#define MSGTR_RTCDeviceNotOpenable "Failed to open %s: %s (it should be readable by the user.)\n"
+#define MSGTR_LinuxRTCInitErrorIrqpSet "Linux RTC init error in ioctl (rtc_irqp_set %lu): %s\n"
+#define MSGTR_IncreaseRTCMaxUserFreq "Try adding \"echo %lu > /proc/sys/dev/rtc/max-user-freq\" to your system startup scripts.\n"
+#define MSGTR_LinuxRTCInitErrorPieOn "Linux RTC init error in ioctl (rtc_pie_on): %s\n"
+#define MSGTR_UsingTimingType "Using %s timing.\n"
+#define MSGTR_Getch2InitializedTwice "WARNING: getch2_init called twice!\n"
+#define MSGTR_DumpstreamFdUnavailable "Cannot dump this stream - no file descriptor available.\n"
+#define MSGTR_CantOpenLibmenuFilterWithThisRootMenu "Can't open libmenu video filter with root menu %s.\n"
+#define MSGTR_AudioFilterChainPreinitError "Error at audio filter chain pre-init!\n"
+#define MSGTR_LinuxRTCReadError "Linux RTC read error: %s\n"
+#define MSGTR_SoftsleepUnderflow "Warning! Softsleep underflow!\n"
+#define MSGTR_DvdnavNullEvent "DVDNAV Event NULL?!\n"
+#define MSGTR_DvdnavHighlightEventBroken "DVDNAV Event: Highlight event broken\n"
+#define MSGTR_DvdnavEvent "DVDNAV Event: %s\n"
+#define MSGTR_DvdnavHighlightHide "DVDNAV Event: Highlight Hide\n"
+#define MSGTR_DvdnavStillFrame "######################################## DVDNAV Event: Still Frame: %d sec(s)\n"
+#define MSGTR_DvdnavNavStop "DVDNAV Event: Nav Stop\n"
+#define MSGTR_DvdnavNavNOP "DVDNAV Event: Nav NOP\n"
+#define MSGTR_DvdnavNavSpuStreamChangeVerbose "DVDNAV Event: Nav SPU Stream Change: phys: %d/%d/%d logical: %d\n"
+#define MSGTR_DvdnavNavSpuStreamChange "DVDNAV Event: Nav SPU Stream Change: phys: %d logical: %d\n"
+#define MSGTR_DvdnavNavAudioStreamChange "DVDNAV Event: Nav Audio Stream Change: phys: %d logical: %d\n"
+#define MSGTR_DvdnavNavVTSChange "DVDNAV Event: Nav VTS Change\n"
+#define MSGTR_DvdnavNavCellChange "DVDNAV Event: Nav Cell Change\n"
+#define MSGTR_DvdnavNavSpuClutChange "DVDNAV Event: Nav SPU CLUT Change\n"
+#define MSGTR_DvdnavNavSeekDone "DVDNAV Event: Nav Seek Done\n"
+#define MSGTR_MenuCall "Menu call\n"
+#define MSGTR_MasterQuit "Option -udp-slave: exiting because master exited\n"
+#define MSGTR_InvalidIP "Option -udp-ip: invalid IP address\n"
+#define MSGTR_Forking "Forking...\n"
+#define MSGTR_Forked "Forked...\n"
+#define MSGTR_CouldntStartGdb "Couldn't start gdb\n"
+#define MSGTR_CouldntFork "Couldn't fork\n"
+#define MSGTR_FilenameTooLong "Filename is too long, can not load file or directory specific config files\n"
+#define MSGTR_AudioDeviceStuck "Audio device got stuck!\n"
+#define MSGTR_AudioOutputTruncated "Audio output truncated at end.\n"
+#define MSGTR_ASSCannotAddVideoFilter "ASS: cannot add video filter\n"
+#define MSGTR_PtsAfterFiltersMissing "pts after filters MISSING\n"
+#define MSGTR_CommandLine "CommandLine:"
+#define MSGTR_MenuInitFailed "Menu init failed.\n"
+
+// --- edit decision lists
+#define MSGTR_EdlOutOfMem "Can't allocate enough memory to hold EDL data.\n"
+#define MSGTR_EdlOutOfMemFile "Can't allocate enough memory to hold EDL file name [%s].\n"
+#define MSGTR_EdlRecordsNo "Read %d EDL actions.\n"
+#define MSGTR_EdlQueueEmpty "There are no EDL actions to take care of.\n"
+#define MSGTR_EdlCantOpenForWrite "Can't open EDL file [%s] for writing.\n"
+#define MSGTR_EdlCantOpenForRead "Can't open EDL file [%s] for reading.\n"
+#define MSGTR_EdlNOsh_video "Cannot use EDL without video, disabling.\n"
+#define MSGTR_EdlNOValidLine "Invalid EDL line: %s\n"
+#define MSGTR_EdlBadlyFormattedLine "Badly formatted EDL line [%d], discarding.\n"
+#define MSGTR_EdlBadLineOverlap "Last stop position was [%f]; next start is [%f].\n"\
+"Entries must be in chronological order, cannot overlap. Discarding.\n"
+#define MSGTR_EdlBadLineBadStop "Stop time has to be after start time.\n"
+#define MSGTR_EdloutBadStop "EDL skip canceled, last start > stop\n"
+#define MSGTR_EdloutStartSkip "EDL skip start, press 'i' again to end block.\n"
+#define MSGTR_EdloutEndSkip "EDL skip end, line written.\n"
+
+// mplayer.c OSD
+#define MSGTR_OSDenabled "enabled"
+#define MSGTR_OSDdisabled "disabled"
+#define MSGTR_OSDAudio "Audio: %s"
+#define MSGTR_OSDVideo "Video: %s"
+#define MSGTR_OSDChannel "Channel: %s"
+#define MSGTR_OSDSubDelay "Sub delay: %d ms"
+#define MSGTR_OSDSpeed "Speed: x %6.2f"
+#define MSGTR_OSDosd "OSD: %s"
+#define MSGTR_OSDChapter "Chapter: (%d) %s"
+#define MSGTR_OSDAngle "Angle: %d/%d"
+#define MSGTR_OSDDeinterlace "Deinterlace: %s"
+#define MSGTR_OSDCapturing "Capturing: %s"
+#define MSGTR_OSDCapturingFailure "Capturing failed"
+
+// property values
+#define MSGTR_Enabled "enabled"
+#define MSGTR_EnabledEdl "enabled (EDL)"
+#define MSGTR_Disabled "disabled"
+#define MSGTR_HardFrameDrop "hard"
+#define MSGTR_Unknown "unknown"
+#define MSGTR_Bottom "bottom"
+#define MSGTR_Center "center"
+#define MSGTR_Top "top"
+#define MSGTR_SubSourceFile "file"
+#define MSGTR_SubSourceVobsub "vobsub"
+#define MSGTR_SubSourceDemux "embedded"
+
+// OSD bar names
+#define MSGTR_Volume "Volume"
+#define MSGTR_Panscan "Panscan"
+#define MSGTR_Gamma "Gamma"
+#define MSGTR_Brightness "Brightness"
+#define MSGTR_Contrast "Contrast"
+#define MSGTR_Saturation "Saturation"
+#define MSGTR_Hue "Hue"
+#define MSGTR_Balance "Balance"
+
+// property state
+#define MSGTR_LoopStatus "Loop: %s"
+#define MSGTR_MuteStatus "Mute: %s"
+#define MSGTR_AVDelayStatus "A-V delay: %s"
+#define MSGTR_OnTopStatus "Stay on top: %s"
+#define MSGTR_RootwinStatus "Rootwin: %s"
+#define MSGTR_BorderStatus "Border: %s"
+#define MSGTR_FramedroppingStatus "Framedropping: %s"
+#define MSGTR_VSyncStatus "VSync: %s"
+#define MSGTR_SubSelectStatus "Subtitles: %s"
+#define MSGTR_SubSourceStatus "Sub source: %s"
+#define MSGTR_SubPosStatus "Sub position: %s/100"
+#define MSGTR_SubAlignStatus "Sub alignment: %s"
+#define MSGTR_SubDelayStatus "Sub delay: %s"
+#define MSGTR_SubScale "Sub Scale: %s"
+#define MSGTR_SubVisibleStatus "Subtitles: %s"
+#define MSGTR_SubForcedOnlyStatus "Forced sub only: %s"
+
+// mencoder.c
+#define MSGTR_UsingPass3ControlFile "Using pass3 control file: %s\n"
+#define MSGTR_MissingFilename "\nFilename missing.\n\n"
+#define MSGTR_CannotOpenFile_Device "Cannot open file/device.\n"
+#define MSGTR_CannotOpenDemuxer "Cannot open demuxer.\n"
+#define MSGTR_NoAudioEncoderSelected "\nNo audio encoder (-oac) selected. Select one (see -oac help) or use -nosound.\n"
+#define MSGTR_NoVideoEncoderSelected "\nNo video encoder (-ovc) selected. Select one (see -ovc help).\n"
+#define MSGTR_CannotOpenOutputFile "Cannot open output file '%s'.\n"
+#define MSGTR_EncoderOpenFailed "Failed to open the encoder.\n"
+#define MSGTR_MencoderWrongFormatAVI "\nWARNING: OUTPUT FILE FORMAT IS _AVI_. See -of help.\n"
+#define MSGTR_MencoderWrongFormatMPG "\nWARNING: OUTPUT FILE FORMAT IS _MPEG_. See -of help.\n"
+#define MSGTR_MissingOutputFilename "No output file specified, please see the -o option."
+#define MSGTR_ForcingOutputFourcc "Forcing output FourCC to %x [%.4s].\n"
+#define MSGTR_ForcingOutputAudiofmtTag "Forcing output audio format tag to 0x%x.\n"
+#define MSGTR_DuplicateFrames "\n%d duplicate frame(s)!\n"
+#define MSGTR_SkipFrame "\nSkipping frame!\n"
+#define MSGTR_ResolutionDoesntMatch "\nNew video file has different resolution or colorspace than the previous one.\n"
+#define MSGTR_FrameCopyFileMismatch "\nAll video files must have identical fps, resolution, and codec for -ovc copy.\n"
+#define MSGTR_AudioCopyFileMismatch "\nAll files must have identical audio codec and format for -oac copy.\n"
+#define MSGTR_NoAudioFileMismatch "\nCannot mix video-only files with audio and video files. Try -nosound.\n"
+#define MSGTR_NoSpeedWithFrameCopy "WARNING: -speed is not guaranteed to work correctly with -oac copy!\n"\
+"Your encode might be broken!\n"
+#define MSGTR_ErrorWritingFile "%s: Error writing file.\n"
+#define MSGTR_FlushingVideoFrames "\nFlushing video frames.\n"
+#define MSGTR_FiltersHaveNotBeenConfiguredEmptyFile "Filters have not been configured! Empty file?\n"
+#define MSGTR_RecommendedVideoBitrate "Recommended video bitrate for %s CD: %d\n"
+#define MSGTR_VideoStreamResult "\nVideo stream: %8.3f kbit/s (%d B/s) size: %"PRIu64" bytes %5.3f secs %d frames\n"
+#define MSGTR_AudioStreamResult "\nAudio stream: %8.3f kbit/s (%d B/s) size: %"PRIu64" bytes %5.3f secs\n"
+#define MSGTR_EdlSkipStartEndCurrent "EDL SKIP: Start: %.2f End: %.2f Current: V: %.2f A: %.2f \r"
+#define MSGTR_OpenedStream "success: format: %d data: 0x%X - 0x%x\n"
+#define MSGTR_VCodecFramecopy "videocodec: framecopy (%dx%d %dbpp fourcc=%x)\n"
+#define MSGTR_ACodecFramecopy "audiocodec: framecopy (format=%x chans=%d rate=%d bits=%d B/s=%d sample-%d)\n"
+#define MSGTR_CBRPCMAudioSelected "CBR PCM audio selected.\n"
+#define MSGTR_MP3AudioSelected "MP3 audio selected.\n"
+#define MSGTR_CannotAllocateBytes "Couldn't allocate %d bytes.\n"
+#define MSGTR_SettingAudioDelay "Setting audio delay to %5.3fs.\n"
+#define MSGTR_SettingVideoDelay "Setting video delay to %5.3fs.\n"
+#define MSGTR_LimitingAudioPreload "Limiting audio preload to 0.4s.\n"
+#define MSGTR_IncreasingAudioDensity "Increasing audio density to 4.\n"
+#define MSGTR_ZeroingAudioPreloadAndMaxPtsCorrection "Forcing audio preload to 0, max pts correction to 0.\n"
+#define MSGTR_LameVersion "LAME version %s (%s)\n\n"
+#define MSGTR_InvalidBitrateForLamePreset "Error: The bitrate specified is out of the valid range for this preset.\n"\
+"\n"\
+"When using this mode you must enter a value between \"8\" and \"320\".\n"\
+"\n"\
+"For further information try: \"-lameopts preset=help\"\n"
+#define MSGTR_InvalidLamePresetOptions "Error: You did not enter a valid profile and/or options with preset.\n"\
+"\n"\
+"Available profiles are:\n"\
+"\n"\
+" <fast> standard\n"\
+" <fast> extreme\n"\
+" insane\n"\
+" <cbr> (ABR Mode) - The ABR Mode is implied. To use it,\n"\
+" simply specify a bitrate. For example:\n"\
+" \"preset=185\" activates this\n"\
+" preset and uses 185 as an average kbps.\n"\
+"\n"\
+" Some examples:\n"\
+"\n"\
+" \"-lameopts fast:preset=standard \"\n"\
+" or \"-lameopts cbr:preset=192 \"\n"\
+" or \"-lameopts preset=172 \"\n"\
+" or \"-lameopts preset=extreme \"\n"\
+"\n"\
+"For further information try: \"-lameopts preset=help\"\n"
+#define MSGTR_LamePresetsLongInfo "\n"\
+"The preset switches are designed to provide the highest possible quality.\n"\
+"\n"\
+"They have for the most part been subjected to and tuned via rigorous double\n"\
+"blind listening tests to verify and achieve this objective.\n"\
+"\n"\
+"These are continually updated to coincide with the latest developments that\n"\
+"occur and as a result should provide you with nearly the best quality\n"\
+"currently possible from LAME.\n"\
+"\n"\
+"To activate these presets:\n"\
+"\n"\
+" For VBR modes (generally highest quality):\n"\
+"\n"\
+" \"preset=standard\" This preset should generally be transparent\n"\
+" to most people on most music and is already\n"\
+" quite high in quality.\n"\
+"\n"\
+" \"preset=extreme\" If you have extremely good hearing and similar\n"\
+" equipment, this preset will generally provide\n"\
+" slightly higher quality than the \"standard\"\n"\
+" mode.\n"\
+"\n"\
+" For CBR 320kbps (highest quality possible from the preset switches):\n"\
+"\n"\
+" \"preset=insane\" This preset will usually be overkill for most\n"\
+" people and most situations, but if you must\n"\
+" have the absolute highest quality with no\n"\
+" regard to filesize, this is the way to go.\n"\
+"\n"\
+" For ABR modes (high quality per given bitrate but not as high as VBR):\n"\
+"\n"\
+" \"preset=<kbps>\" Using this preset will usually give you good\n"\
+" quality at a specified bitrate. Depending on the\n"\
+" bitrate entered, this preset will determine the\n"\
+" optimal settings for that particular situation.\n"\
+" While this approach works, it is not nearly as\n"\
+" flexible as VBR, and usually will not attain the\n"\
+" same level of quality as VBR at higher bitrates.\n"\
+"\n"\
+"The following options are also available for the corresponding profiles:\n"\
+"\n"\
+" <fast> standard\n"\
+" <fast> extreme\n"\
+" insane\n"\
+" <cbr> (ABR Mode) - The ABR Mode is implied. To use it,\n"\
+" simply specify a bitrate. For example:\n"\
+" \"preset=185\" activates this\n"\
+" preset and uses 185 as an average kbps.\n"\
+"\n"\
+" \"fast\" - Enables the new fast VBR for a particular profile. The\n"\
+" disadvantage to the speed switch is that often times the\n"\
+" bitrate will be slightly higher than with the normal mode\n"\
+" and quality may be slightly lower also.\n"\
+" Warning: with the current version fast presets might result in too\n"\
+" high bitrate compared to regular presets.\n"\
+"\n"\
+" \"cbr\" - If you use the ABR mode (read above) with a significant\n"\
+" bitrate such as 80, 96, 112, 128, 160, 192, 224, 256, 320,\n"\
+" you can use the \"cbr\" option to force CBR mode encoding\n"\
+" instead of the standard abr mode. ABR does provide higher\n"\
+" quality but CBR may be useful in situations such as when\n"\
+" streaming an MP3 over the internet may be important.\n"\
+"\n"\
+" For example:\n"\
+"\n"\
+" \"-lameopts fast:preset=standard \"\n"\
+" or \"-lameopts cbr:preset=192 \"\n"\
+" or \"-lameopts preset=172 \"\n"\
+" or \"-lameopts preset=extreme \"\n"\
+"\n"\
+"\n"\
+"A few aliases are available for ABR mode:\n"\
+"phone => 16kbps/mono phon+/lw/mw-eu/sw => 24kbps/mono\n"\
+"mw-us => 40kbps/mono voice => 56kbps/mono\n"\
+"fm/radio/tape => 112kbps hifi => 160kbps\n"\
+"cd => 192kbps studio => 256kbps"
+#define MSGTR_LameCantInit \
+"Cannot set LAME options, check bitrate/samplerate, some very low bitrates\n"\
+"(<32) need lower samplerates (i.e. -srate 8000).\n"\
+"If everything else fails, try a preset."
+#define MSGTR_ConfigFileError "Config file error"
+#define MSGTR_ErrorParsingCommandLine "error parsing command line"
+#define MSGTR_VideoStreamRequired "Video stream is mandatory!\n"
+#define MSGTR_ForcingInputFPS "Input fps will be interpreted as %5.3f instead.\n"
+#define MSGTR_RawvideoDoesNotSupportAudio "Output file format RAWVIDEO does not support audio - disabling audio.\n"
+#define MSGTR_DemuxerDoesntSupportNosound "This demuxer doesn't support -nosound yet.\n"
+#define MSGTR_MemAllocFailed "Memory allocation failed.\n"
+#define MSGTR_NoMatchingFilter "Couldn't find matching filter/ao format!\n"
+#define MSGTR_MP3WaveFormatSizeNot30 "sizeof(MPEGLAYER3WAVEFORMAT)==%d!=30, maybe broken C compiler?\n"
+#define MSGTR_NoLavcAudioCodecName "Audio LAVC, Missing codec name!\n"
+#define MSGTR_LavcAudioCodecNotFound "Audio LAVC, couldn't find encoder for codec %s.\n"
+#define MSGTR_CouldntAllocateLavcContext "Audio LAVC, couldn't allocate context!\n"
+#define MSGTR_CouldntOpenCodec "Couldn't open codec %s, br=%d.\n"
+#define MSGTR_CantCopyAudioFormat "Audio format 0x%x is incompatible with '-oac copy', please try '-oac pcm' instead or use '-fafmttag' to override it.\n"
+
+// cfg-mencoder.h
+#define MSGTR_MEncoderMP3LameHelp "\n\n"\
+" vbr=<0-4> variable bitrate method\n"\
+" 0: cbr (constant bitrate)\n"\
+" 1: mt (Mark Taylor VBR algorithm)\n"\
+" 2: rh (Robert Hegemann VBR algorithm - default)\n"\
+" 3: abr (average bitrate)\n"\
+" 4: mtrh (Mark Taylor Robert Hegemann VBR algorithm)\n"\
+"\n"\
+" abr average bitrate\n"\
+"\n"\
+" cbr constant bitrate\n"\
+" Also forces CBR mode encoding on subsequent ABR presets modes.\n"\
+"\n"\
+" br=<0-1024> specify bitrate in kBit (CBR and ABR only)\n"\
+"\n"\
+" q=<0-9> quality (0-highest, 9-lowest) (only for VBR)\n"\
+"\n"\
+" aq=<0-9> algorithmic quality (0-best/slowest, 9-worst/fastest)\n"\
+"\n"\
+" ratio=<1-100> compression ratio\n"\
+"\n"\
+" vol=<0-10> set audio input gain\n"\
+"\n"\
+" mode=<0-3> (default: auto)\n"\
+" 0: stereo\n"\
+" 1: joint-stereo\n"\
+" 2: dualchannel\n"\
+" 3: mono\n"\
+"\n"\
+" padding=<0-2>\n"\
+" 0: no\n"\
+" 1: all\n"\
+" 2: adjust\n"\
+"\n"\
+" fast Switch on faster encoding on subsequent VBR presets modes,\n"\
+" slightly lower quality and higher bitrates.\n"\
+"\n"\
+" preset=<value> Provide the highest possible quality settings.\n"\
+" medium: VBR encoding, good quality\n"\
+" (150-180 kbps bitrate range)\n"\
+" standard: VBR encoding, high quality\n"\
+" (170-210 kbps bitrate range)\n"\
+" extreme: VBR encoding, very high quality\n"\
+" (200-240 kbps bitrate range)\n"\
+" insane: CBR encoding, highest preset quality\n"\
+" (320 kbps bitrate)\n"\
+" <8-320>: ABR encoding at average given kbps bitrate.\n\n"
+
+// codec-cfg.c
+#define MSGTR_DuplicateFourcc "duplicated FourCC"
+#define MSGTR_TooManyFourccs "too many FourCCs/formats..."
+#define MSGTR_ParseError "parse error"
+#define MSGTR_ParseErrorFIDNotNumber "parse error (format ID not a number?)"
+#define MSGTR_ParseErrorFIDAliasNotNumber "parse error (format ID alias not a number?)"
+#define MSGTR_DuplicateFID "duplicated format ID"
+#define MSGTR_TooManyOut "too many out..."
+#define MSGTR_InvalidCodecName "\ncodec(%s) name is not valid!\n"
+#define MSGTR_CodecLacksFourcc "\ncodec(%s) does not have FourCC/format!\n"
+#define MSGTR_CodecLacksDriver "\ncodec(%s) does not have a driver!\n"
+#define MSGTR_CodecNeedsDLL "\ncodec(%s) needs a 'dll'!\n"
+#define MSGTR_CodecNeedsOutfmt "\ncodec(%s) needs an 'outfmt'!\n"
+#define MSGTR_CantAllocateComment "Can't allocate memory for comment. "
+#define MSGTR_GetTokenMaxNotLessThanMAX_NR_TOKEN "get_token(): max >= MAX_MR_TOKEN!"
+#define MSGTR_CantGetMemoryForLine "Can't get memory for 'line': %s\n"
+#define MSGTR_CantReallocCodecsp "Can't realloc '*codecsp': %s\n"
+#define MSGTR_CodecNameNotUnique "Codec name '%s' isn't unique."
+#define MSGTR_CantStrdupName "Can't strdup -> 'name': %s\n"
+#define MSGTR_CantStrdupInfo "Can't strdup -> 'info': %s\n"
+#define MSGTR_CantStrdupDriver "Can't strdup -> 'driver': %s\n"
+#define MSGTR_CantStrdupDLL "Can't strdup -> 'dll': %s"
+#define MSGTR_AudioVideoCodecTotals "%d audio & %d video codecs\n"
+#define MSGTR_CodecDefinitionIncorrect "Codec is not defined correctly."
+#define MSGTR_OutdatedCodecsConf "This codecs.conf is too old and incompatible with this MPlayer release!"
+
+// fifo.c
+#define MSGTR_CannotMakePipe "Cannot make PIPE!\n"
+
+// parser-mecmd.c, parser-mpcmd.c
+#define MSGTR_NoFileGivenOnCommandLine "'--' indicates no more options, but no filename was given on the command line.\n"
+#define MSGTR_TheLoopOptionMustBeAnInteger "The loop option must be an integer: %s\n"
+#define MSGTR_UnknownOptionOnCommandLine "Unknown option on the command line: -%s\n"
+#define MSGTR_ErrorParsingOptionOnCommandLine "Error parsing option on the command line: -%s\n"
+#define MSGTR_InvalidPlayEntry "Invalid play entry %s\n"
+#define MSGTR_NotAnMEncoderOption "-%s is not an MEncoder option\n"
+#define MSGTR_NoFileGiven "No file given\n"
+
+// m_config.c
+#define MSGTR_SaveSlotTooOld "Save slot found from lvl %d is too old: %d !!!\n"
+#define MSGTR_InvalidCfgfileOption "The %s option can't be used in a config file.\n"
+#define MSGTR_InvalidCmdlineOption "The %s option can't be used on the command line.\n"
+#define MSGTR_InvalidSuboption "Error: option '%s' has no suboption '%s'.\n"
+#define MSGTR_MissingSuboptionParameter "Error: suboption '%s' of '%s' must have a parameter!\n"
+#define MSGTR_MissingOptionParameter "Error: option '%s' must have a parameter!\n"
+#define MSGTR_OptionListHeader "\n Name Type Min Max Global CL Cfg\n\n"
+#define MSGTR_TotalOptions "\nTotal: %d options\n"
+#define MSGTR_ProfileInclusionTooDeep "WARNING: Profile inclusion too deep.\n"
+#define MSGTR_NoProfileDefined "No profiles have been defined.\n"
+#define MSGTR_AvailableProfiles "Available profiles:\n"
+#define MSGTR_UnknownProfile "Unknown profile '%s'.\n"
+#define MSGTR_Profile "Profile %s: %s\n"
+
+// m_property.c
+#define MSGTR_PropertyListHeader "\n Name Type Min Max\n\n"
+#define MSGTR_TotalProperties "\nTotal: %d properties\n"
+
+// loader/ldt_keeper.c
+#define MSGTR_LOADER_DYLD_Warning "WARNING: Attempting to use DLL codecs but environment variable\n DYLD_BIND_AT_LAUNCH not set. This will likely crash.\n"
+
+
+// ====================== GUI messages/buttons ========================
+
+// --- labels ---
+#define MSGTR_About "About"
+#define MSGTR_FileSelect "Select file..."
+#define MSGTR_SubtitleSelect "Select subtitle..."
+#define MSGTR_OtherSelect "Select..."
+#define MSGTR_AudioFileSelect "Select external audio channel..."
+#define MSGTR_FontSelect "Select font..."
+// Note: If you change MSGTR_PlayList please see if it still fits MSGTR_MENU_PlayList
+#define MSGTR_PlayList "Playlist"
+#define MSGTR_Equalizer "Equalizer"
+#define MSGTR_ConfigureEqualizer "Configure Equalizer"
+#define MSGTR_SkinBrowser "Skin Browser"
+#define MSGTR_Network "Network streaming..."
+// Note: If you change MSGTR_Preferences please see if it still fits MSGTR_MENU_Preferences
+#define MSGTR_Preferences "Preferences"
+#define MSGTR_AudioPreferences "Audio driver configuration"
+#define MSGTR_NoMediaOpened "No media opened."
+#define MSGTR_Title "Title %d"
+#define MSGTR_NoChapter "No chapter"
+#define MSGTR_Chapter "Chapter %d"
+#define MSGTR_NoFileLoaded "No file loaded."
+#define MSGTR_Filter_UTF8Subtitles "UTF-8 encoded subtitles (*.utf, *.utf-8, *.utf8)"
+#define MSGTR_Filter_AllSubtitles "All subtitles"
+#define MSGTR_Filter_AllFiles "All files"
+#define MSGTR_Filter_TTF "True Type fonts (*.ttf)"
+#define MSGTR_Filter_Type1 "Type1 fonts (*.pfb)"
+#define MSGTR_Filter_AllFonts "All fonts"
+#define MSGTR_Filter_FontFiles "Font files (*.desc)"
+#define MSGTR_Filter_DDRawAudio "Dolby Digital / PCM (*.ac3, *.pcm)"
+#define MSGTR_Filter_MPEGAudio "MPEG audio (*.mp2, *.mp3, *.mpga, *.m4a, *.aac, *.f4a)"
+#define MSGTR_Filter_MatroskaAudio "Matroska audio (*.mka)"
+#define MSGTR_Filter_OGGAudio "Ogg audio (*.oga, *.ogg, *.spx)"
+#define MSGTR_Filter_WAVAudio "WAV audio (*.wav)"
+#define MSGTR_Filter_WMAAudio "Windows Media audio (*.wma)"
+#define MSGTR_Filter_AllAudioFiles "All audio files"
+#define MSGTR_Filter_AllVideoFiles "All video files"
+#define MSGTR_Filter_AVIFiles "AVI files"
+#define MSGTR_Filter_DivXFiles "DivX files"
+#define MSGTR_Filter_FlashVideo "Flash Video"
+#define MSGTR_Filter_MP3Files "MP3 files"
+#define MSGTR_Filter_MP4Files "MP4 files"
+#define MSGTR_Filter_MPEGFiles "MPEG files"
+#define MSGTR_Filter_MP2TS "MPEG-2 transport streams"
+#define MSGTR_Filter_MatroskaMedia "Matroska media"
+#define MSGTR_Filter_OGGMedia "Ogg media"
+#define MSGTR_Filter_QTMedia "QuickTime media"
+#define MSGTR_Filter_RNMedia "RealNetworks media"
+#define MSGTR_Filter_VideoCDImages "VCD/SVCD images"
+#define MSGTR_Filter_WAVFiles "WAV files"
+#define MSGTR_Filter_WindowsMedia "Windows media"
+#define MSGTR_Filter_Playlists "Playlists"
+
+// --- buttons ---
+#define MSGTR_Ok "OK"
+#define MSGTR_Cancel "Cancel"
+#define MSGTR_Add "Add"
+#define MSGTR_Remove "Remove"
+#define MSGTR_Clear "Clear"
+#define MSGTR_Config "Config"
+#define MSGTR_ConfigDriver "Configure driver"
+#define MSGTR_Browse "Browse"
+
+// --- error messages ---
+#define MSGTR_NEMDB "Sorry, not enough memory to draw buffer.\n"
+#define MSGTR_NEMFMR "Sorry, not enough memory for menu rendering."
+#define MSGTR_IDFGCVD "Sorry, no GUI-compatible video output driver found.\n"
+#define MSGTR_NEEDLAVC "Sorry, you cannot play non-MPEG files with your DXR3/H+ device without reencoding.\nPlease enable lavc in the DXR3/H+ configuration box."
+#define MSGTR_ICONERROR "Icon '%s' (size %d) not found or unsupported format.\n"
+
+// --- skin loader error messages
+#define MSGTR_SKIN_ERRORMESSAGE "Error in skin config file on line %d: %s"
+#define MSGTR_SKIN_ERROR_SECTION "No section specified for '%s'.\n"
+#define MSGTR_SKIN_ERROR_WINDOW "No window specified for '%s'.\n"
+#define MSGTR_SKIN_ERROR_ITEM "This item is not supported by '%s'.\n"
+#define MSGTR_SKIN_UNKNOWN_ITEM "Unknown item '%s'\n"
+#define MSGTR_SKIN_UNKNOWN_NAME "Unknown name '%s'\n"
+#define MSGTR_SKIN_SkinFileNotFound "Skin file %s not found.\n"
+#define MSGTR_SKIN_SkinFileNotReadable "Skin file %s not readable.\n"
+#define MSGTR_SKIN_BITMAP_16bit "Color depth of bitmap %s is 16 bits or less which is not supported.\n"
+#define MSGTR_SKIN_BITMAP_FileNotFound "Bitmap %s not found.\n"
+#define MSGTR_SKIN_BITMAP_PNGReadError "PNG read error in %s\n"
+#define MSGTR_SKIN_BITMAP_ConversionError "24 bit to 32 bit conversion error in %s\n"
+#define MSGTR_SKIN_UnknownMessage "Unknown message '%s'\n"
+#define MSGTR_SKIN_NotEnoughMemory "Not enough memory\n"
+#define MSGTR_SKIN_TooManyItemsDeclared "Too many items declared.\n"
+#define MSGTR_SKIN_FONT_TooManyFontsDeclared "Too many fonts declared.\n"
+#define MSGTR_SKIN_FONT_FontFileNotFound "Font description file not found.\n"
+#define MSGTR_SKIN_FONT_FontImageNotFound "Font image file not found.\n"
+#define MSGTR_SKIN_FONT_NonExistentFont "Font '%s' not found.\n"
+#define MSGTR_SKIN_UnknownParameter "Unknown parameter '%s'\n"
+#define MSGTR_SKIN_SKINCFG_SkinNotFound "Skin '%s' not found.\n"
+#define MSGTR_SKIN_SKINCFG_SelectedSkinNotFound "Selected skin '%s' not found, trying skin 'default'...\n"
+#define MSGTR_SKIN_SKINCFG_SkinCfgError "Config file processing error with skin '%s'\n"
+#define MSGTR_SKIN_LABEL "Skins:"
+
+// --- GTK menus
+#define MSGTR_MENU_AboutMPlayer "About MPlayer"
+#define MSGTR_MENU_Open "Open..."
+#define MSGTR_MENU_PlayFile "Play file..."
+#define MSGTR_MENU_PlayCD "Play CD..."
+#define MSGTR_MENU_PlayVCD "Play VCD..."
+#define MSGTR_MENU_PlayDVD "Play DVD..."
+#define MSGTR_MENU_PlayURL "Play URL..."
+#define MSGTR_MENU_LoadSubtitle "Load subtitle..."
+#define MSGTR_MENU_DropSubtitle "Drop subtitle..."
+#define MSGTR_MENU_LoadExternAudioFile "Load external audio file..."
+#define MSGTR_MENU_Playing "Playing"
+#define MSGTR_MENU_Play "Play"
+#define MSGTR_MENU_Pause "Pause"
+#define MSGTR_MENU_Stop "Stop"
+#define MSGTR_MENU_NextStream "Next stream"
+#define MSGTR_MENU_PrevStream "Prev stream"
+#define MSGTR_MENU_Size "Size"
+#define MSGTR_MENU_HalfSize "Half size"
+#define MSGTR_MENU_NormalSize "Normal size"
+#define MSGTR_MENU_DoubleSize "Double size"
+#define MSGTR_MENU_FullScreen "Fullscreen"
+#define MSGTR_MENU_CD "CD"
+#define MSGTR_MENU_DVD "DVD"
+#define MSGTR_MENU_VCD "VCD"
+#define MSGTR_MENU_PlayDisc "Open disc..."
+#define MSGTR_MENU_ShowDVDMenu "Show DVD menu"
+#define MSGTR_MENU_Titles "Titles"
+#define MSGTR_MENU_Title "Title %2d"
+#define MSGTR_MENU_None "(none)"
+#define MSGTR_MENU_Chapters "Chapters"
+#define MSGTR_MENU_Chapter "Chapter %2d"
+#define MSGTR_MENU_AudioLanguages "Audio languages"
+#define MSGTR_MENU_SubtitleLanguages "Subtitle languages"
+#define MSGTR_MENU_PlayList MSGTR_PlayList
+#define MSGTR_MENU_SkinBrowser "Skin browser"
+#define MSGTR_MENU_Preferences MSGTR_Preferences
+#define MSGTR_MENU_Exit "Exit"
+#define MSGTR_MENU_Mute "Mute"
+#define MSGTR_MENU_Original "Original"
+#define MSGTR_MENU_AspectRatio "Aspect ratio"
+#define MSGTR_MENU_AudioTrack "Audio track"
+#define MSGTR_MENU_Track "Track %d"
+#define MSGTR_MENU_VideoTrack "Video track"
+#define MSGTR_MENU_Subtitles "Subtitles"
+
+// --- equalizer
+// Note: If you change MSGTR_EQU_Audio please see if it still fits MSGTR_PREFERENCES_Audio
+#define MSGTR_EQU_Audio "Audio"
+// Note: If you change MSGTR_EQU_Video please see if it still fits MSGTR_PREFERENCES_Video
+#define MSGTR_EQU_Video "Video"
+#define MSGTR_EQU_Contrast "Contrast: "
+#define MSGTR_EQU_Brightness "Brightness: "
+#define MSGTR_EQU_Hue "Hue: "
+#define MSGTR_EQU_Saturation "Saturation: "
+#define MSGTR_EQU_Front_Left "Front Left"
+#define MSGTR_EQU_Front_Right "Front Right"
+#define MSGTR_EQU_Back_Left "Rear Left"
+#define MSGTR_EQU_Back_Right "Rear Right"
+#define MSGTR_EQU_Center "Center"
+#define MSGTR_EQU_Bass "Bass"
+#define MSGTR_EQU_All "All"
+#define MSGTR_EQU_Channel1 "Channel 1:"
+#define MSGTR_EQU_Channel2 "Channel 2:"
+#define MSGTR_EQU_Channel3 "Channel 3:"
+#define MSGTR_EQU_Channel4 "Channel 4:"
+#define MSGTR_EQU_Channel5 "Channel 5:"
+#define MSGTR_EQU_Channel6 "Channel 6:"
+
+// --- playlist
+#define MSGTR_PLAYLIST_Path "Path"
+#define MSGTR_PLAYLIST_Selected "Selected files"
+#define MSGTR_PLAYLIST_Files "Files"
+#define MSGTR_PLAYLIST_DirectoryTree "Directory tree"
+
+// --- preferences
+#define MSGTR_PREFERENCES_Audio MSGTR_EQU_Audio
+#define MSGTR_PREFERENCES_Video MSGTR_EQU_Video
+#define MSGTR_PREFERENCES_SubtitleOSD "Subtitles & OSD"
+#define MSGTR_PREFERENCES_Codecs "Codecs & demuxer"
+// Note: If you change MSGTR_PREFERENCES_Misc see if it still fits MSGTR_PREFERENCES_FRAME_Misc
+#define MSGTR_PREFERENCES_Misc "Misc"
+#define MSGTR_PREFERENCES_None "None"
+#define MSGTR_PREFERENCES_DriverDefault "driver default"
+#define MSGTR_PREFERENCES_AvailableDrivers "Available drivers:"
+#define MSGTR_PREFERENCES_DoNotPlaySound "Do not play sound"
+#define MSGTR_PREFERENCES_NormalizeSound "Normalize sound"
+#define MSGTR_PREFERENCES_EnableEqualizer "Enable equalizer"
+#define MSGTR_PREFERENCES_SoftwareMixer "Enable Software Mixer"
+#define MSGTR_PREFERENCES_ExtraStereo "Enable extra stereo"
+#define MSGTR_PREFERENCES_Coefficient "Coefficient:"
+#define MSGTR_PREFERENCES_AudioDelay "Audio delay"
+#define MSGTR_PREFERENCES_DoubleBuffer "Enable double buffering"
+#define MSGTR_PREFERENCES_DirectRender "Enable direct rendering"
+#define MSGTR_PREFERENCES_FrameDrop "Enable frame dropping"
+#define MSGTR_PREFERENCES_HFrameDrop "Enable HARD frame dropping (dangerous)"
+#define MSGTR_PREFERENCES_Flip "Flip image upside down"
+#define MSGTR_PREFERENCES_Panscan "Panscan: "
+#define MSGTR_PREFERENCES_OSD_LEVEL0 "Subtitles only"
+#define MSGTR_PREFERENCES_OSD_LEVEL1 "Volume and seek"
+#define MSGTR_PREFERENCES_OSD_LEVEL2 "Volume, seek, timer and percentage"
+#define MSGTR_PREFERENCES_OSD_LEVEL3 "Volume, seek, timer, percentage and total time"
+#define MSGTR_PREFERENCES_Subtitle "Subtitle:"
+#define MSGTR_PREFERENCES_SUB_Delay "Delay: "
+#define MSGTR_PREFERENCES_SUB_FPS "FPS:"
+#define MSGTR_PREFERENCES_SUB_POS "Position: "
+#define MSGTR_PREFERENCES_SUB_AutoLoad "Disable subtitle autoloading"
+#define MSGTR_PREFERENCES_SUB_Unicode "Unicode subtitle"
+#define MSGTR_PREFERENCES_SUB_MPSUB "Convert the given subtitle to MPlayer's subtitle format"
+#define MSGTR_PREFERENCES_SUB_SRT "Convert the given subtitle to the time based SubViewer (SRT) format"
+#define MSGTR_PREFERENCES_SUB_Overlap "Toggle subtitle overlapping"
+#define MSGTR_PREFERENCES_SUB_USE_ASS "SSA/ASS subtitle rendering"
+#define MSGTR_PREFERENCES_SUB_ASS_USE_MARGINS "Use margins"
+#define MSGTR_PREFERENCES_SUB_ASS_TOP_MARGIN "Top: "
+#define MSGTR_PREFERENCES_SUB_ASS_BOTTOM_MARGIN "Bottom: "
+#define MSGTR_PREFERENCES_Font "Font:"
+#define MSGTR_PREFERENCES_FontFactor "Font factor:"
+#define MSGTR_PREFERENCES_PostProcess "Enable postprocessing"
+#define MSGTR_PREFERENCES_AutoQuality "Auto quality: "
+#define MSGTR_PREFERENCES_NI "Use non-interleaved AVI parser"
+#define MSGTR_PREFERENCES_IDX "Rebuild index table, if needed"
+#define MSGTR_PREFERENCES_VideoCodecFamily "Video codec family:"
+#define MSGTR_PREFERENCES_AudioCodecFamily "Audio codec family:"
+#define MSGTR_PREFERENCES_FRAME_OSD_Level "OSD level"
+#define MSGTR_PREFERENCES_FRAME_Subtitle "Subtitle"
+#define MSGTR_PREFERENCES_FRAME_Font "Font"
+#define MSGTR_PREFERENCES_FRAME_PostProcess "Postprocessing"
+#define MSGTR_PREFERENCES_FRAME_CodecDemuxer "Codec & demuxer"
+#define MSGTR_PREFERENCES_FRAME_Cache "Cache"
+#define MSGTR_PREFERENCES_FRAME_Misc MSGTR_PREFERENCES_Misc
+#define MSGTR_PREFERENCES_Audio_Device "Device:"
+#define MSGTR_PREFERENCES_Audio_Mixer "Mixer:"
+#define MSGTR_PREFERENCES_Audio_MixerChannel "Mixer channel:"
+#define MSGTR_PREFERENCES_Message "Please remember that you need to restart playback for some options to take effect!"
+#define MSGTR_PREFERENCES_DXR3_VENC "Video encoder:"
+#define MSGTR_PREFERENCES_DXR3_LAVC "Use LAVC (FFmpeg)"
+#define MSGTR_PREFERENCES_FontEncoding1 "Unicode"
+#define MSGTR_PREFERENCES_FontEncoding2 "Western European Languages (ISO-8859-1)"
+#define MSGTR_PREFERENCES_FontEncoding3 "Western European Languages with Euro (ISO-8859-15)"
+#define MSGTR_PREFERENCES_FontEncoding4 "Slavic/Central European Languages (ISO-8859-2)"
+#define MSGTR_PREFERENCES_FontEncoding5 "Esperanto, Galician, Maltese, Turkish (ISO-8859-3)"
+#define MSGTR_PREFERENCES_FontEncoding6 "Old Baltic charset (ISO-8859-4)"
+#define MSGTR_PREFERENCES_FontEncoding7 "Cyrillic (ISO-8859-5)"
+#define MSGTR_PREFERENCES_FontEncoding8 "Arabic (ISO-8859-6)"
+#define MSGTR_PREFERENCES_FontEncoding9 "Modern Greek (ISO-8859-7)"
+#define MSGTR_PREFERENCES_FontEncoding10 "Turkish (ISO-8859-9)"
+#define MSGTR_PREFERENCES_FontEncoding11 "Baltic (ISO-8859-13)"
+#define MSGTR_PREFERENCES_FontEncoding12 "Celtic (ISO-8859-14)"
+#define MSGTR_PREFERENCES_FontEncoding13 "Hebrew charsets (ISO-8859-8)"
+#define MSGTR_PREFERENCES_FontEncoding14 "Russian (KOI8-R)"
+#define MSGTR_PREFERENCES_FontEncoding15 "Ukrainian, Belarusian (KOI8-U/RU)"
+#define MSGTR_PREFERENCES_FontEncoding16 "Simplified Chinese charset (CP936)"
+#define MSGTR_PREFERENCES_FontEncoding17 "Traditional Chinese charset (BIG5)"
+#define MSGTR_PREFERENCES_FontEncoding18 "Japanese charsets (SHIFT-JIS)"
+#define MSGTR_PREFERENCES_FontEncoding19 "Korean charset (CP949)"
+#define MSGTR_PREFERENCES_FontEncoding20 "Thai charset (CP874)"
+#define MSGTR_PREFERENCES_FontEncoding21 "Cyrillic Windows (CP1251)"
+#define MSGTR_PREFERENCES_FontEncoding22 "Slavic/Central European Windows (CP1250)"
+#define MSGTR_PREFERENCES_FontEncoding23 "Arabic Windows (CP1256)"
+#define MSGTR_PREFERENCES_FontNoAutoScale "No autoscale"
+#define MSGTR_PREFERENCES_FontPropWidth "Proportional to movie width"
+#define MSGTR_PREFERENCES_FontPropHeight "Proportional to movie height"
+#define MSGTR_PREFERENCES_FontPropDiagonal "Proportional to movie diagonal"
+#define MSGTR_PREFERENCES_FontEncoding "Encoding:"
+#define MSGTR_PREFERENCES_FontBlur "Blur:"
+#define MSGTR_PREFERENCES_FontOutLine "Outline:"
+#define MSGTR_PREFERENCES_FontTextScale "Text scale:"
+#define MSGTR_PREFERENCES_FontOSDScale "OSD scale:"
+#define MSGTR_PREFERENCES_Cache "Cache on/off"
+#define MSGTR_PREFERENCES_CacheSize "Cache size: "
+#define MSGTR_PREFERENCES_LoadFullscreen "Start in fullscreen"
+#define MSGTR_PREFERENCES_SaveWinPos "Save window position"
+#define MSGTR_PREFERENCES_XSCREENSAVER "Stop XScreenSaver"
+#define MSGTR_PREFERENCES_PlayBar "Enable playbar"
+#define MSGTR_PREFERENCES_NoIdle "Quit after playing"
+#define MSGTR_PREFERENCES_AutoSync "AutoSync on/off"
+#define MSGTR_PREFERENCES_AutoSyncValue "Autosync: "
+#define MSGTR_PREFERENCES_CDROMDevice "CD-ROM device:"
+#define MSGTR_PREFERENCES_DVDDevice "DVD device:"
+#define MSGTR_PREFERENCES_FPS "Movie FPS:"
+#define MSGTR_PREFERENCES_ShowVideoWindow "Show video window when inactive"
+#define MSGTR_PREFERENCES_ArtsBroken "Newer aRts versions are incompatible "\
+ "with GTK 1.x and will crash GMPlayer!"
+
+// -- aboutbox
+#define MSGTR_ABOUT_UHU "GUI development sponsored by UHU Linux\n"
+#define MSGTR_ABOUT_Contributors "Code and documentation contributors\n"
+#define MSGTR_ABOUT_Codecs_libs_contributions "Codecs and third party libraries\n"
+#define MSGTR_ABOUT_Translations "Translations\n"
+#define MSGTR_ABOUT_Skins "Skins\n"
+
+// --- messagebox
+#define MSGTR_MSGBOX_LABEL_FatalError "Fatal error!"
+#define MSGTR_MSGBOX_LABEL_Error "Error!"
+#define MSGTR_MSGBOX_LABEL_Warning "Warning!"
+
+// cfg.c
+#define MSGTR_UnableToSaveOption "Unable to save option '%s'.\n"
+
+// interface.c
+#define MSGTR_DeletingSubtitles "Deleting subtitles.\n"
+#define MSGTR_LoadingSubtitles "Loading subtitles '%s'.\n"
+#define MSGTR_AddingVideoFilter "Adding video filter '%s'.\n"
+
+// mw.c
+#define MSGTR_NotAFile "This does not seem to be a file: %s !\n"
+
+// ws.c
+#define MSGTR_WS_RemoteDisplay "Remote display, disabling XMITSHM.\n"
+#define MSGTR_WS_NoXshm "Sorry, your system does not support the X shared memory extension.\n"
+#define MSGTR_WS_NoXshape "Sorry, your system does not support the XShape extension.\n"
+#define MSGTR_WS_ColorDepthTooLow "Sorry, the color depth is too low.\n"
+#define MSGTR_WS_TooManyOpenWindows "There are too many open windows.\n"
+#define MSGTR_WS_ShmError "shared memory extension error\n"
+#define MSGTR_WS_NotEnoughMemoryDrawBuffer "Sorry, not enough memory to draw buffer.\n"
+#define MSGTR_WS_DpmsUnavailable "DPMS not available?\n"
+#define MSGTR_WS_DpmsNotEnabled "Could not enable DPMS.\n"
+#define MSGTR_WS_XError "An X11 Error has occurred!\n"
+
+// wsxdnd.c
+#define MSGTR_WS_NotAFile "This does not seem to be a file...\n"
+#define MSGTR_WS_DDNothing "D&D: Nothing returned!\n"
+
+// Win32 GUI
+#define MSGTR_Close "Close"
+#define MSGTR_Default "Defaults"
+#define MSGTR_Down "Down"
+#define MSGTR_Load "Load"
+#define MSGTR_Save "Save"
+#define MSGTR_Up "Up"
+#define MSGTR_DirectorySelect "Select directory..."
+#define MSGTR_PlaylistSave "Save playlist..."
+#define MSGTR_PlaylistSelect "Select playlist..."
+#define MSGTR_SelectTitleChapter "Select title/chapter..."
+#define MSGTR_MENU_DebugConsole "Debug Console"
+#define MSGTR_MENU_OnlineHelp "Online Help"
+#define MSGTR_MENU_PlayDirectory "Play directory..."
+#define MSGTR_MENU_SeekBack "Seek Backwards"
+#define MSGTR_MENU_SeekForw "Seek Forwards"
+#define MSGTR_MENU_ShowHide "Show/Hide"
+#define MSGTR_MENU_SubtitlesOnOff "Subtitle Visibility On/Off"
+#define MSGTR_PLAYLIST_AddFile "Add File..."
+#define MSGTR_PLAYLIST_AddURL "Add URL..."
+#define MSGTR_PREFERENCES_Priority "Priority:"
+#define MSGTR_PREFERENCES_PriorityHigh "high"
+#define MSGTR_PREFERENCES_PriorityLow "low"
+#define MSGTR_PREFERENCES_PriorityNormal "normal"
+#define MSGTR_PREFERENCES_PriorityNormalAbove "above normal"
+#define MSGTR_PREFERENCES_PriorityNormalBelow "below normal"
+#define MSGTR_PREFERENCES_ShowInVideoWin "Display in the video window (DirectX only)"
+
+
+// ======================= video output drivers ========================
+
+#define MSGTR_VOincompCodec "The selected video_out device is incompatible with this codec.\n"\
+ "Try appending the scale filter to your filter list,\n"\
+ "e.g. -vf spp,scale instead of -vf spp.\n"
+#define MSGTR_VO_GenericError "This error has occurred"
+#define MSGTR_VO_UnableToAccess "Unable to access"
+#define MSGTR_VO_ExistsButNoDirectory "already exists, but is not a directory."
+#define MSGTR_VO_DirExistsButNotWritable "Output directory already exists, but is not writable."
+#define MSGTR_VO_DirExistsAndIsWritable "Output directory already exists and is writable."
+#define MSGTR_VO_CantCreateDirectory "Unable to create output directory."
+#define MSGTR_VO_CantCreateFile "Unable to create output file."
+#define MSGTR_VO_DirectoryCreateSuccess "Output directory successfully created."
+#define MSGTR_VO_ValueOutOfRange "value out of range"
+#define MSGTR_VO_NoValueSpecified "No value specified."
+#define MSGTR_VO_UnknownSuboptions "unknown suboption(s)"
+
+// aspect.c
+#define MSGTR_LIBVO_ASPECT_NoSuitableNewResFound "[ASPECT] Warning: No suitable new res found!\n"
+#define MSGTR_LIBVO_ASPECT_NoNewSizeFoundThatFitsIntoRes "[ASPECT] Error: No new size found that fits into res!\n"
+
+// font_load_ft.c
+#define MSGTR_LIBVO_FONT_LOAD_FT_NewFaceFailed "New_Face failed. Maybe the font path is wrong.\nPlease supply the text font file (~/.mplayer/subfont.ttf).\n"
+#define MSGTR_LIBVO_FONT_LOAD_FT_NewMemoryFaceFailed "New_Memory_Face failed..\n"
+#define MSGTR_LIBVO_FONT_LOAD_FT_SubFaceFailed "subtitle font: load_sub_face failed.\n"
+#define MSGTR_LIBVO_FONT_LOAD_FT_SubFontCharsetFailed "subtitle font: prepare_charset failed.\n"
+#define MSGTR_LIBVO_FONT_LOAD_FT_CannotPrepareSubtitleFont "Cannot prepare subtitle font.\n"
+#define MSGTR_LIBVO_FONT_LOAD_FT_CannotPrepareOSDFont "Cannot prepare OSD font.\n"
+#define MSGTR_LIBVO_FONT_LOAD_FT_CannotGenerateTables "Cannot generate tables.\n"
+#define MSGTR_LIBVO_FONT_LOAD_FT_DoneFreeTypeFailed "FT_Done_FreeType failed.\n"
+#define MSGTR_LIBVO_FONT_LOAD_FT_FontconfigNoMatch "Fontconfig failed to select a font. Trying without fontconfig...\n"
+
+// sub.c
+#define MSGTR_VO_SUB_Seekbar "Seekbar"
+#define MSGTR_VO_SUB_Play "Play"
+#define MSGTR_VO_SUB_Pause "Pause"
+#define MSGTR_VO_SUB_Stop "Stop"
+#define MSGTR_VO_SUB_Rewind "Rewind"
+#define MSGTR_VO_SUB_Forward "Forward"
+#define MSGTR_VO_SUB_Clock "Clock"
+#define MSGTR_VO_SUB_Contrast "Contrast"
+#define MSGTR_VO_SUB_Saturation "Saturation"
+#define MSGTR_VO_SUB_Volume "Volume"
+#define MSGTR_VO_SUB_Brightness "Brightness"
+#define MSGTR_VO_SUB_Hue "Hue"
+#define MSGTR_VO_SUB_Balance "Balance"
+
+// vo_3dfx.c
+#define MSGTR_LIBVO_3DFX_Only16BppSupported "[VO_3DFX] Only 16bpp supported!"
+#define MSGTR_LIBVO_3DFX_VisualIdIs "[VO_3DFX] Visual ID is %lx.\n"
+#define MSGTR_LIBVO_3DFX_UnableToOpenDevice "[VO_3DFX] Unable to open /dev/3dfx.\n"
+#define MSGTR_LIBVO_3DFX_Error "[VO_3DFX] Error: %d.\n"
+#define MSGTR_LIBVO_3DFX_CouldntMapMemoryArea "[VO_3DFX] Couldn't map 3dfx memory areas: %p,%p,%d.\n"
+#define MSGTR_LIBVO_3DFX_DisplayInitialized "[VO_3DFX] Initialized: %p.\n"
+#define MSGTR_LIBVO_3DFX_UnknownSubdevice "[VO_3DFX] Unknown subdevice: %s.\n"
+
+// vo_aa.c
+#define MSGTR_VO_AA_HelpHeader "\n\nHere are the aalib vo_aa suboptions:\n"
+#define MSGTR_VO_AA_AdditionalOptions "Additional options vo_aa provides:\n" \
+" help print this help message\n" \
+" osdcolor set OSD color\n subcolor set subtitle color\n" \
+" the color parameters are:\n 0 : normal\n" \
+" 1 : dim\n 2 : bold\n 3 : boldfont\n" \
+" 4 : reverse\n 5 : special\n\n\n"
+
+// vo_dxr3.c
+#define MSGTR_LIBVO_DXR3_UnableToLoadNewSPUPalette "[VO_DXR3] Unable to load new SPU palette!\n"
+#define MSGTR_LIBVO_DXR3_UnableToSetPlaymode "[VO_DXR3] Unable to set playmode!\n"
+#define MSGTR_LIBVO_DXR3_UnableToSetSubpictureMode "[VO_DXR3] Unable to set subpicture mode!\n"
+#define MSGTR_LIBVO_DXR3_UnableToGetTVNorm "[VO_DXR3] Unable to get TV norm!\n"
+#define MSGTR_LIBVO_DXR3_AutoSelectedTVNormByFrameRate "[VO_DXR3] Auto-selected TV norm by framerate: "
+#define MSGTR_LIBVO_DXR3_UnableToSetTVNorm "[VO_DXR3] Unable to set TV norm!\n"
+#define MSGTR_LIBVO_DXR3_SettingUpForNTSC "[VO_DXR3] Setting up for NTSC.\n"
+#define MSGTR_LIBVO_DXR3_SettingUpForPALSECAM "[VO_DXR3] Setting up for PAL/SECAM.\n"
+#define MSGTR_LIBVO_DXR3_SettingAspectRatioTo43 "[VO_DXR3] Setting aspect ratio to 4:3.\n"
+#define MSGTR_LIBVO_DXR3_SettingAspectRatioTo169 "[VO_DXR3] Setting aspect ratio to 16:9.\n"
+#define MSGTR_LIBVO_DXR3_OutOfMemory "[VO_DXR3] out of memory\n"
+#define MSGTR_LIBVO_DXR3_UnableToAllocateKeycolor "[VO_DXR3] Unable to allocate keycolor!\n"
+#define MSGTR_LIBVO_DXR3_UnableToAllocateExactKeycolor "[VO_DXR3] Unable to allocate exact keycolor, using closest match (0x%lx).\n"
+#define MSGTR_LIBVO_DXR3_Uninitializing "[VO_DXR3] Uninitializing.\n"
+#define MSGTR_LIBVO_DXR3_FailedRestoringTVNorm "[VO_DXR3] Failed restoring TV norm!\n"
+#define MSGTR_LIBVO_DXR3_EnablingPrebuffering "[VO_DXR3] Enabling prebuffering.\n"
+#define MSGTR_LIBVO_DXR3_UsingNewSyncEngine "[VO_DXR3] Using new sync engine.\n"
+#define MSGTR_LIBVO_DXR3_UsingOverlay "[VO_DXR3] Using overlay.\n"
+#define MSGTR_LIBVO_DXR3_ErrorYouNeedToCompileMplayerWithX11 "[VO_DXR3] Error: Overlay requires compiling with X11 libs/headers installed.\n"
+#define MSGTR_LIBVO_DXR3_WillSetTVNormTo "[VO_DXR3] Will set TV norm to: "
+#define MSGTR_LIBVO_DXR3_AutoAdjustToMovieFrameRatePALPAL60 "auto-adjust to movie framerate (PAL/PAL-60)"
+#define MSGTR_LIBVO_DXR3_AutoAdjustToMovieFrameRatePALNTSC "auto-adjust to movie framerate (PAL/NTSC)"
+#define MSGTR_LIBVO_DXR3_UseCurrentNorm "Use current norm."
+#define MSGTR_LIBVO_DXR3_UseUnknownNormSuppliedCurrentNorm "Unknown norm supplied. Use current norm."
+#define MSGTR_LIBVO_DXR3_ErrorOpeningForWritingTrying "[VO_DXR3] Error opening %s for writing, trying /dev/em8300 instead.\n"
+#define MSGTR_LIBVO_DXR3_ErrorOpeningForWritingTryingMV "[VO_DXR3] Error opening %s for writing, trying /dev/em8300_mv instead.\n"
+#define MSGTR_LIBVO_DXR3_ErrorOpeningForWritingAsWell "[VO_DXR3] Error opening /dev/em8300 for writing as well!\nBailing out.\n"
+#define MSGTR_LIBVO_DXR3_ErrorOpeningForWritingAsWellMV "[VO_DXR3] Error opening /dev/em8300_mv for writing as well!\nBailing out.\n"
+#define MSGTR_LIBVO_DXR3_Opened "[VO_DXR3] Opened: %s.\n"
+#define MSGTR_LIBVO_DXR3_ErrorOpeningForWritingTryingSP "[VO_DXR3] Error opening %s for writing, trying /dev/em8300_sp instead.\n"
+#define MSGTR_LIBVO_DXR3_ErrorOpeningForWritingAsWellSP "[VO_DXR3] Error opening /dev/em8300_sp for writing as well!\nBailing out.\n"
+#define MSGTR_LIBVO_DXR3_UnableToOpenDisplayDuringHackSetup "[VO_DXR3] Unable to open display during overlay hack setup!\n"
+#define MSGTR_LIBVO_DXR3_UnableToInitX11 "[VO_DXR3] Unable to init X11!\n"
+#define MSGTR_LIBVO_DXR3_FailedSettingOverlayAttribute "[VO_DXR3] Failed setting overlay attribute.\n"
+#define MSGTR_LIBVO_DXR3_FailedSettingOverlayScreen "[VO_DXR3] Failed setting overlay screen!\nExiting.\n"
+#define MSGTR_LIBVO_DXR3_FailedEnablingOverlay "[VO_DXR3] Failed enabling overlay!\nExiting.\n"
+#define MSGTR_LIBVO_DXR3_FailedResizingOverlayWindow "[VO_DXR3] Failed resizing overlay window!\n"
+#define MSGTR_LIBVO_DXR3_FailedSettingOverlayBcs "[VO_DXR3] Failed setting overlay bcs!\n"
+#define MSGTR_LIBVO_DXR3_FailedGettingOverlayYOffsetValues "[VO_DXR3] Failed getting overlay Y-offset values!\nExiting.\n"
+#define MSGTR_LIBVO_DXR3_FailedGettingOverlayXOffsetValues "[VO_DXR3] Failed getting overlay X-offset values!\nExiting.\n"
+#define MSGTR_LIBVO_DXR3_FailedGettingOverlayXScaleCorrection "[VO_DXR3] Failed getting overlay X scale correction!\nExiting.\n"
+#define MSGTR_LIBVO_DXR3_YOffset "[VO_DXR3] Yoffset: %d.\n"
+#define MSGTR_LIBVO_DXR3_XOffset "[VO_DXR3] Xoffset: %d.\n"
+#define MSGTR_LIBVO_DXR3_XCorrection "[VO_DXR3] Xcorrection: %d.\n"
+#define MSGTR_LIBVO_DXR3_FailedSetSignalMix "[VO_DXR3] Failed to set signal mix!\n"
+
+// vo_jpeg.c
+#define MSGTR_VO_JPEG_ProgressiveJPEG "Progressive JPEG enabled."
+#define MSGTR_VO_JPEG_NoProgressiveJPEG "Progressive JPEG disabled."
+#define MSGTR_VO_JPEG_BaselineJPEG "Baseline JPEG enabled."
+#define MSGTR_VO_JPEG_NoBaselineJPEG "Baseline JPEG disabled."
+
+// vo_mga.c
+#define MSGTR_LIBVO_MGA_AspectResized "[VO_MGA] aspect(): resized to %dx%d.\n"
+#define MSGTR_LIBVO_MGA_Uninit "[VO] uninit!\n"
+
+// mga_template.c
+#define MSGTR_LIBVO_MGA_ErrorInConfigIoctl "[MGA] error in mga_vid_config ioctl (wrong mga_vid.o version?)"
+#define MSGTR_LIBVO_MGA_CouldNotGetLumaValuesFromTheKernelModule "[MGA] Could not get luma values from the kernel module!\n"
+#define MSGTR_LIBVO_MGA_CouldNotSetLumaValuesFromTheKernelModule "[MGA] Could not set luma values from the kernel module!\n"
+#define MSGTR_LIBVO_MGA_ScreenWidthHeightUnknown "[MGA] Screen width/height unknown!\n"
+#define MSGTR_LIBVO_MGA_InvalidOutputFormat "[MGA] invalid output format %0X\n"
+#define MSGTR_LIBVO_MGA_IncompatibleDriverVersion "[MGA] Your mga_vid driver version is incompatible with this MPlayer version!\n"
+#define MSGTR_LIBVO_MGA_CouldntOpen "[MGA] Couldn't open: %s\n"
+#define MSGTR_LIBVO_MGA_ResolutionTooHigh "[MGA] Source resolution exceeds 1023x1023 in at least one dimension.\n[MGA] Rescale in software or use -lavdopts lowres=1.\n"
+#define MSGTR_LIBVO_MGA_mgavidVersionMismatch "[MGA] mismatch between kernel (%u) and MPlayer (%u) mga_vid driver versions\n"
+
+// vo_null.c
+#define MSGTR_LIBVO_NULL_UnknownSubdevice "[VO_NULL] Unknown subdevice: %s.\n"
+
+// vo_png.c
+#define MSGTR_LIBVO_PNG_Warning1 "[VO_PNG] Warning: compression level set to 0, compression disabled!\n"
+#define MSGTR_LIBVO_PNG_Warning2 "[VO_PNG] Info: Use -vo png:z=<n> to set compression level from 0 to 9.\n"
+#define MSGTR_LIBVO_PNG_Warning3 "[VO_PNG] Info: (0 = no compression, 1 = fastest, lowest - 9 best, slowest compression)\n"
+#define MSGTR_LIBVO_PNG_ErrorOpeningForWriting "\n[VO_PNG] Error opening '%s' for writing!\n"
+#define MSGTR_LIBVO_PNG_ErrorInCreatePng "[VO_PNG] Error in create_png.\n"
+
+// vo_pnm.c
+#define MSGTR_VO_PNM_ASCIIMode "ASCII mode enabled."
+#define MSGTR_VO_PNM_RawMode "Raw mode enabled."
+#define MSGTR_VO_PNM_PPMType "Will write PPM files."
+#define MSGTR_VO_PNM_PGMType "Will write PGM files."
+#define MSGTR_VO_PNM_PGMYUVType "Will write PGMYUV files."
+
+// vo_sdl.c
+#define MSGTR_LIBVO_SDL_CouldntGetAnyAcceptableSDLModeForOutput "[VO_SDL] Couldn't get any acceptable SDL Mode for output.\n"
+#define MSGTR_LIBVO_SDL_SetVideoModeFailed "[VO_SDL] set_video_mode: SDL_SetVideoMode failed: %s.\n"
+#define MSGTR_LIBVO_SDL_MappingI420ToIYUV "[VO_SDL] Mapping I420 to IYUV.\n"
+#define MSGTR_LIBVO_SDL_UnsupportedImageFormat "[VO_SDL] Unsupported image format (0x%X).\n"
+#define MSGTR_LIBVO_SDL_InfoPleaseUseVmOrZoom "[VO_SDL] Info - please use -vm or -zoom to switch to the best resolution.\n"
+#define MSGTR_LIBVO_SDL_FailedToSetVideoMode "[VO_SDL] Failed to set video mode: %s.\n"
+#define MSGTR_LIBVO_SDL_CouldntCreateAYUVOverlay "[VO_SDL] Couldn't create a YUV overlay: %s.\n"
+#define MSGTR_LIBVO_SDL_CouldntCreateARGBSurface "[VO_SDL] Couldn't create an RGB surface: %s.\n"
+#define MSGTR_LIBVO_SDL_UsingDepthColorspaceConversion "[VO_SDL] Using depth/colorspace conversion, this will slow things down (%ibpp -> %ibpp).\n"
+#define MSGTR_LIBVO_SDL_UnsupportedImageFormatInDrawslice "[VO_SDL] Unsupported image format in draw_slice, contact MPlayer developers!\n"
+#define MSGTR_LIBVO_SDL_BlitFailed "[VO_SDL] Blit failed: %s.\n"
+#define MSGTR_LIBVO_SDL_InitializationFailed "[VO_SDL] SDL initialization failed: %s.\n"
+#define MSGTR_LIBVO_SDL_UsingDriver "[VO_SDL] Using driver: %s.\n"
+
+// vo_svga.c
+#define MSGTR_LIBVO_SVGA_ForcedVidmodeNotAvailable "[VO_SVGA] Forced vid_mode %d (%s) not available.\n"
+#define MSGTR_LIBVO_SVGA_ForcedVidmodeTooSmall "[VO_SVGA] Forced vid_mode %d (%s) too small.\n"
+#define MSGTR_LIBVO_SVGA_Vidmode "[VO_SVGA] Vid_mode: %d, %dx%d %dbpp.\n"
+#define MSGTR_LIBVO_SVGA_VgasetmodeFailed "[VO_SVGA] Vga_setmode(%d) failed.\n"
+#define MSGTR_LIBVO_SVGA_VideoModeIsLinearAndMemcpyCouldBeUsed "[VO_SVGA] Video mode is linear and memcpy could be used for image transfer.\n"
+#define MSGTR_LIBVO_SVGA_VideoModeHasHardwareAcceleration "[VO_SVGA] Video mode has hardware acceleration and put_image could be used.\n"
+#define MSGTR_LIBVO_SVGA_IfItWorksForYouIWouldLikeToKnow "[VO_SVGA] If it works for you I would like to know.\n[VO_SVGA] (send log with `mplayer test.avi -v -v -v -v &> svga.log`). Thx!\n"
+#define MSGTR_LIBVO_SVGA_VideoModeHas "[VO_SVGA] Video mode has %d page(s).\n"
+#define MSGTR_LIBVO_SVGA_CenteringImageStartAt "[VO_SVGA] Centering image. Starting at (%d,%d)\n"
+#define MSGTR_LIBVO_SVGA_UsingVidix "[VO_SVGA] Using VIDIX. w=%i h=%i mw=%i mh=%i\n"
+
+// vo_tdfx_vid.c
+#define MSGTR_LIBVO_TDFXVID_Move "[VO_TDXVID] Move %d(%d) x %d => %d.\n"
+#define MSGTR_LIBVO_TDFXVID_AGPMoveFailedToClearTheScreen "[VO_TDFXVID] AGP move failed to clear the screen.\n"
+#define MSGTR_LIBVO_TDFXVID_BlitFailed "[VO_TDFXVID] Blit failed.\n"
+#define MSGTR_LIBVO_TDFXVID_NonNativeOverlayFormatNeedConversion "[VO_TDFXVID] Non-native overlay format needs conversion.\n"
+#define MSGTR_LIBVO_TDFXVID_UnsupportedInputFormat "[VO_TDFXVID] Unsupported input format 0x%x.\n"
+#define MSGTR_LIBVO_TDFXVID_OverlaySetupFailed "[VO_TDFXVID] Overlay setup failed.\n"
+#define MSGTR_LIBVO_TDFXVID_OverlayOnFailed "[VO_TDFXVID] Overlay on failed.\n"
+#define MSGTR_LIBVO_TDFXVID_OverlayReady "[VO_TDFXVID] Overlay ready: %d(%d) x %d @ %d => %d(%d) x %d @ %d.\n"
+#define MSGTR_LIBVO_TDFXVID_TextureBlitReady "[VO_TDFXVID] Texture blit ready: %d(%d) x %d @ %d => %d(%d) x %d @ %d.\n"
+#define MSGTR_LIBVO_TDFXVID_OverlayOffFailed "[VO_TDFXVID] Overlay off failed\n"
+#define MSGTR_LIBVO_TDFXVID_CantOpen "[VO_TDFXVID] Can't open %s: %s.\n"
+#define MSGTR_LIBVO_TDFXVID_CantGetCurrentCfg "[VO_TDFXVID] Can't get current configuration: %s.\n"
+#define MSGTR_LIBVO_TDFXVID_MemmapFailed "[VO_TDFXVID] Memmap failed !!!!!\n"
+#define MSGTR_LIBVO_TDFXVID_GetImageTodo "Get image todo.\n"
+#define MSGTR_LIBVO_TDFXVID_AgpMoveFailed "[VO_TDFXVID] AGP move failed.\n"
+#define MSGTR_LIBVO_TDFXVID_SetYuvFailed "[VO_TDFXVID] Set YUV failed.\n"
+#define MSGTR_LIBVO_TDFXVID_AgpMoveFailedOnYPlane "[VO_TDFXVID] AGP move failed on Y plane.\n"
+#define MSGTR_LIBVO_TDFXVID_AgpMoveFailedOnUPlane "[VO_TDFXVID] AGP move failed on U plane.\n"
+#define MSGTR_LIBVO_TDFXVID_AgpMoveFailedOnVPlane "[VO_TDFXVID] AGP move failed on V plane.\n"
+#define MSGTR_LIBVO_TDFXVID_UnknownFormat "[VO_TDFXVID] unknown format: 0x%x.\n"
+
+// vo_tdfxfb.c
+#define MSGTR_LIBVO_TDFXFB_CantOpen "[VO_TDFXFB] Can't open %s: %s.\n"
+#define MSGTR_LIBVO_TDFXFB_ProblemWithFbitgetFscreenInfo "[VO_TDFXFB] Problem with FBITGET_FSCREENINFO ioctl: %s.\n"
+#define MSGTR_LIBVO_TDFXFB_ProblemWithFbitgetVscreenInfo "[VO_TDFXFB] Problem with FBITGET_VSCREENINFO ioctl: %s.\n"
+#define MSGTR_LIBVO_TDFXFB_ThisDriverOnlySupports "[VO_TDFXFB] This driver only supports the 3Dfx Banshee, Voodoo3 and Voodoo 5.\n"
+#define MSGTR_LIBVO_TDFXFB_OutputIsNotSupported "[VO_TDFXFB] %d bpp output is not supported.\n"
+#define MSGTR_LIBVO_TDFXFB_CouldntMapMemoryAreas "[VO_TDFXFB] Couldn't map memory areas: %s.\n"
+#define MSGTR_LIBVO_TDFXFB_BppOutputIsNotSupported "[VO_TDFXFB] %d bpp output is not supported (This should never have happened).\n"
+#define MSGTR_LIBVO_TDFXFB_SomethingIsWrongWithControl "[VO_TDFXFB] Eik! Something's wrong with control().\n"
+#define MSGTR_LIBVO_TDFXFB_NotEnoughVideoMemoryToPlay "[VO_TDFXFB] Not enough video memory to play this movie. Try at a lower resolution.\n"
+#define MSGTR_LIBVO_TDFXFB_ScreenIs "[VO_TDFXFB] Screen is %dx%d at %d bpp, in is %dx%d at %d bpp, norm is %dx%d.\n"
+
+// vo_tga.c
+#define MSGTR_LIBVO_TGA_UnknownSubdevice "[VO_TGA] Unknown subdevice: %s.\n"
+
+// vo_vesa.c
+#define MSGTR_LIBVO_VESA_FatalErrorOccurred "[VO_VESA] Fatal error occurred! Can't continue.\n"
+#define MSGTR_LIBVO_VESA_UnknownSubdevice "[VO_VESA] unknown subdevice: '%s'.\n"
+#define MSGTR_LIBVO_VESA_YouHaveTooLittleVideoMemory "[VO_VESA] You have too little video memory for this mode:\n[VO_VESA] Required: %08lX present: %08lX.\n"
+#define MSGTR_LIBVO_VESA_YouHaveToSpecifyTheCapabilitiesOfTheMonitor "[VO_VESA] You have to specify the capabilities of the monitor. Not changing refresh rate.\n"
+#define MSGTR_LIBVO_VESA_UnableToFitTheMode "[VO_VESA] The mode does not fit the monitor limits. Not changing refresh rate.\n"
+#define MSGTR_LIBVO_VESA_DetectedInternalFatalError "[VO_VESA] Detected internal fatal error: init is called before preinit.\n"
+#define MSGTR_LIBVO_VESA_SwitchFlipIsNotSupported "[VO_VESA] The -flip option is not supported.\n"
+#define MSGTR_LIBVO_VESA_PossibleReasonNoVbe2BiosFound "[VO_VESA] Possible reason: No VBE2 BIOS found.\n"
+#define MSGTR_LIBVO_VESA_FoundVesaVbeBiosVersion "[VO_VESA] Found VESA VBE BIOS Version %x.%x Revision: %x.\n"
+#define MSGTR_LIBVO_VESA_VideoMemory "[VO_VESA] Video memory: %u Kb.\n"
+#define MSGTR_LIBVO_VESA_Capabilites "[VO_VESA] VESA Capabilities: %s %s %s %s %s.\n"
+#define MSGTR_LIBVO_VESA_BelowWillBePrintedOemInfo "[VO_VESA] !!! OEM info will be printed below !!!\n"
+#define MSGTR_LIBVO_VESA_YouShouldSee5OemRelatedLines "[VO_VESA] You should see 5 OEM related lines below; If not, you've broken vm86.\n"
+#define MSGTR_LIBVO_VESA_OemInfo "[VO_VESA] OEM info: %s.\n"
+#define MSGTR_LIBVO_VESA_OemRevision "[VO_VESA] OEM Revision: %x.\n"
+#define MSGTR_LIBVO_VESA_OemVendor "[VO_VESA] OEM vendor: %s.\n"
+#define MSGTR_LIBVO_VESA_OemProductName "[VO_VESA] OEM Product Name: %s.\n"
+#define MSGTR_LIBVO_VESA_OemProductRev "[VO_VESA] OEM Product Rev: %s.\n"
+#define MSGTR_LIBVO_VESA_Hint "[VO_VESA] Hint: For working TV-Out you should have plugged in the TV connector\n"\
+"[VO_VESA] before booting since VESA BIOS initializes itself only during POST.\n"
+#define MSGTR_LIBVO_VESA_UsingVesaMode "[VO_VESA] Using VESA mode (%u) = %x [%ux%u@%u]\n"
+#define MSGTR_LIBVO_VESA_CantInitializeSwscaler "[VO_VESA] Can't initialize software scaler.\n"
+#define MSGTR_LIBVO_VESA_CantUseDga "[VO_VESA] Can't use DGA. Force bank switching mode. :(\n"
+#define MSGTR_LIBVO_VESA_UsingDga "[VO_VESA] Using DGA (physical resources: %08lXh, %08lXh)"
+#define MSGTR_LIBVO_VESA_CantUseDoubleBuffering "[VO_VESA] Can't use double buffering: not enough video memory.\n"
+#define MSGTR_LIBVO_VESA_CantFindNeitherDga "[VO_VESA] Can find neither DGA nor relocatable window frame.\n"
+#define MSGTR_LIBVO_VESA_YouveForcedDga "[VO_VESA] You've forced DGA. Exiting\n"
+#define MSGTR_LIBVO_VESA_CantFindValidWindowAddress "[VO_VESA] Can't find valid window address.\n"
+#define MSGTR_LIBVO_VESA_UsingBankSwitchingMode "[VO_VESA] Using bank switching mode (physical resources: %08lXh, %08lXh).\n"
+#define MSGTR_LIBVO_VESA_CantAllocateTemporaryBuffer "[VO_VESA] Can't allocate temporary buffer.\n"
+#define MSGTR_LIBVO_VESA_SorryUnsupportedMode "[VO_VESA] Sorry, unsupported mode -- try -x 640 -zoom.\n"
+#define MSGTR_LIBVO_VESA_OhYouReallyHavePictureOnTv "[VO_VESA] Oh you really have a picture on the TV!\n"
+#define MSGTR_LIBVO_VESA_CantInitialozeLinuxVideoOverlay "[VO_VESA] Can't initialize Linux Video Overlay.\n"
+#define MSGTR_LIBVO_VESA_UsingVideoOverlay "[VO_VESA] Using video overlay: %s.\n"
+#define MSGTR_LIBVO_VESA_CantInitializeVidixDriver "[VO_VESA] Can't initialize VIDIX driver.\n"
+#define MSGTR_LIBVO_VESA_UsingVidix "[VO_VESA] Using VIDIX.\n"
+#define MSGTR_LIBVO_VESA_CantFindModeFor "[VO_VESA] Can't find mode for: %ux%u@%u.\n"
+#define MSGTR_LIBVO_VESA_InitializationComplete "[VO_VESA] VESA initialization complete.\n"
+
+// vesa_lvo.c
+#define MSGTR_LIBVO_VESA_ThisBranchIsNoLongerSupported "[VESA_LVO] This branch is no longer supported.\n[VESA_LVO] Please use -vo vesa:vidix instead.\n"
+#define MSGTR_LIBVO_VESA_CouldntOpen "[VESA_LVO] Couldn't open: '%s'\n"
+#define MSGTR_LIBVO_VESA_InvalidOutputFormat "[VESA_LVI] Invalid output format: %s(%0X)\n"
+#define MSGTR_LIBVO_VESA_IncompatibleDriverVersion "[VESA_LVO] Your fb_vid driver version is incompatible with this MPlayer version!\n"
+
+// vo_x11.c
+#define MSGTR_LIBVO_X11_DrawFrameCalled "[VO_X11] draw_frame() called!!!!!!\n"
+
+// vo_xv.c
+#define MSGTR_LIBVO_XV_DrawFrameCalled "[VO_XV] draw_frame() called!!!!!!\n"
+#define MSGTR_LIBVO_XV_SharedMemoryNotSupported "[VO_XV] Shared memory not supported\nReverting to normal Xv.\n"
+#define MSGTR_LIBVO_XV_XvNotSupportedByX11 "[VO_XV] Sorry, Xv not supported by this X11 version/driver\n[VO_XV] ******** Try with -vo x11 or -vo sdl *********\n"
+#define MSGTR_LIBVO_XV_XvQueryAdaptorsFailed "[VO_XV] XvQueryAdaptors failed.\n"
+#define MSGTR_LIBVO_XV_InvalidPortParameter "[VO_XV] Invalid port parameter, overriding with port 0.\n"
+#define MSGTR_LIBVO_XV_CouldNotGrabPort "[VO_XV] Could not grab port %i.\n"
+#define MSGTR_LIBVO_XV_CouldNotFindFreePort "[VO_XV] Could not find free Xvideo port - maybe another process is already\n"\
+"[VO_XV] using it. Close all video applications, and try again. If that does\n"\
+"[VO_XV] not help, see 'mplayer -vo help' for other (non-xv) video out drivers.\n"
+#define MSGTR_LIBVO_XV_NoXvideoSupport "[VO_XV] It seems there is no Xvideo support for your video card available.\n"\
+"[VO_XV] Run 'xvinfo' to verify its Xv support and read\n"\
+"[VO_XV] DOCS/HTML/en/video.html#xv!\n"\
+"[VO_XV] See 'mplayer -vo help' for other (non-xv) video out drivers.\n"\
+"[VO_XV] Try -vo x11.\n"
+#define MSGTR_VO_XV_ImagedimTooHigh "Source image dimensions are too high: %ux%u (maximum is %ux%u)\n"
+
+// vo_yuv4mpeg.c
+#define MSGTR_VO_YUV4MPEG_InterlacedHeightDivisibleBy4 "Interlaced mode requires image height to be divisible by 4."
+#define MSGTR_VO_YUV4MPEG_InterlacedLineBufAllocFail "Unable to allocate line buffer for interlaced mode."
+#define MSGTR_VO_YUV4MPEG_WidthDivisibleBy2 "Image width must be divisible by 2."
+#define MSGTR_VO_YUV4MPEG_OutFileOpenError "Can't get memory or file handle to write \"%s\"!"
+#define MSGTR_VO_YUV4MPEG_OutFileWriteError "Error writing image to output!"
+#define MSGTR_VO_YUV4MPEG_UnknownSubDev "Unknown subdevice: %s"
+#define MSGTR_VO_YUV4MPEG_InterlacedTFFMode "Using interlaced output mode, top-field first."
+#define MSGTR_VO_YUV4MPEG_InterlacedBFFMode "Using interlaced output mode, bottom-field first."
+#define MSGTR_VO_YUV4MPEG_ProgressiveMode "Using (default) progressive frame mode."
+
+// vosub_vidix.c
+#define MSGTR_LIBVO_SUB_VIDIX_CantStartPlayback "[VO_SUB_VIDIX] Can't start playback: %s\n"
+#define MSGTR_LIBVO_SUB_VIDIX_CantStopPlayback "[VO_SUB_VIDIX] Can't stop playback: %s\n"
+#define MSGTR_LIBVO_SUB_VIDIX_InterleavedUvForYuv410pNotSupported "[VO_SUB_VIDIX] Interleaved UV for YUV410P not supported.\n"
+#define MSGTR_LIBVO_SUB_VIDIX_DummyVidixdrawsliceWasCalled "[VO_SUB_VIDIX] Dummy vidix_draw_slice() was called.\n"
+#define MSGTR_LIBVO_SUB_VIDIX_DummyVidixdrawframeWasCalled "[VO_SUB_VIDIX] Dummy vidix_draw_frame() was called.\n"
+#define MSGTR_LIBVO_SUB_VIDIX_UnsupportedFourccForThisVidixDriver "[VO_SUB_VIDIX] Unsupported FourCC for this VIDIX driver: %x (%s).\n"
+#define MSGTR_LIBVO_SUB_VIDIX_VideoServerHasUnsupportedResolution "[VO_SUB_VIDIX] Video server has unsupported resolution (%dx%d), supported: %dx%d-%dx%d.\n"
+#define MSGTR_LIBVO_SUB_VIDIX_VideoServerHasUnsupportedColorDepth "[VO_SUB_VIDIX] Video server has unsupported color depth by vidix (%d).\n"
+#define MSGTR_LIBVO_SUB_VIDIX_DriverCantUpscaleImage "[VO_SUB_VIDIX] VIDIX driver can't upscale image (%d%d -> %d%d).\n"
+#define MSGTR_LIBVO_SUB_VIDIX_DriverCantDownscaleImage "[VO_SUB_VIDIX] VIDIX driver can't downscale image (%d%d -> %d%d).\n"
+#define MSGTR_LIBVO_SUB_VIDIX_CantConfigurePlayback "[VO_SUB_VIDIX] Can't configure playback: %s.\n"
+#define MSGTR_LIBVO_SUB_VIDIX_YouHaveWrongVersionOfVidixLibrary "[VO_SUB_VIDIX] You have the wrong version of the VIDIX library.\n"
+#define MSGTR_LIBVO_SUB_VIDIX_CouldntFindWorkingVidixDriver "[VO_SUB_VIDIX] Couldn't find working VIDIX driver.\n"
+#define MSGTR_LIBVO_SUB_VIDIX_CouldntGetCapability "[VO_SUB_VIDIX] Couldn't get capability: %s.\n"
+
+// x11_common.c
+#define MSGTR_EwmhFullscreenStateFailed "\nX11: Couldn't send EWMH fullscreen event!\n"
+#define MSGTR_CouldNotFindXScreenSaver "xscreensaver_disable: Could not find XScreenSaver window.\n"
+#define MSGTR_SelectedVideoMode "XF86VM: Selected video mode %dx%d for image size %dx%d.\n"
+
+#define MSGTR_InsertingAfVolume "[Mixer] No hardware mixing, inserting volume filter.\n"
+#define MSGTR_NoVolume "[Mixer] No volume control available.\n"
+#define MSGTR_NoBalance "[Mixer] No balance control available.\n"
+
+// old vo drivers that have been replaced
+#define MSGTR_VO_PGM_HasBeenReplaced "The pgm video output driver has been replaced by -vo pnm:pgmyuv.\n"
+#define MSGTR_VO_MD5_HasBeenReplaced "The md5 video output driver has been replaced by -vo md5sum.\n"
+#define MSGTR_VO_GL2_HasBeenRenamed "The gl2 video output driver has been renamed to -vo gl_tiled, but you really should be using -vo gl instead.\n"
+
+
+// ======================= audio output drivers ========================
+
+// audio_out.c
+#define MSGTR_AO_ALSA9_1x_Removed "audio_out: alsa9 and alsa1x modules were removed, use -ao alsa instead.\n"
+#define MSGTR_AO_NoSuchDriver "No such audio driver '%.*s'\n"
+#define MSGTR_AO_FailedInit "Failed to initialize audio driver '%s'\n"
+
+// ao_oss.c
+#define MSGTR_AO_OSS_CantOpenMixer "[AO OSS] audio_setup: Can't open mixer device %s: %s\n"
+#define MSGTR_AO_OSS_ChanNotFound "[AO OSS] audio_setup: Audio card mixer does not have channel '%s', using default.\n"
+#define MSGTR_AO_OSS_CantOpenDev "[AO OSS] audio_setup: Can't open audio device %s: %s\n"
+#define MSGTR_AO_OSS_CantMakeFd "[AO OSS] audio_setup: Can't make file descriptor blocking: %s\n"
+#define MSGTR_AO_OSS_CantSet "[AO OSS] Can't set audio device %s to %s output, trying %s...\n"
+#define MSGTR_AO_OSS_CantSetChans "[AO OSS] audio_setup: Failed to set audio device to %d channels.\n"
+#define MSGTR_AO_OSS_CantUseGetospace "[AO OSS] audio_setup: driver doesn't support SNDCTL_DSP_GETOSPACE :-(\n"
+#define MSGTR_AO_OSS_CantUseSelect "[AO OSS]\n *** Your audio driver DOES NOT support select() ***\n Recompile MPlayer with #undef HAVE_AUDIO_SELECT in config.h !\n\n"
+#define MSGTR_AO_OSS_CantReopen "[AO OSS]\nFatal error: *** CANNOT RE-OPEN / RESET AUDIO DEVICE *** %s\n"
+#define MSGTR_AO_OSS_UnknownUnsupportedFormat "[AO OSS] Unknown/Unsupported OSS format: %x.\n"
+
+// ao_arts.c
+#define MSGTR_AO_ARTS_CantInit "[AO ARTS] %s\n"
+#define MSGTR_AO_ARTS_ServerConnect "[AO ARTS] Connected to sound server.\n"
+#define MSGTR_AO_ARTS_CantOpenStream "[AO ARTS] Unable to open a stream.\n"
+#define MSGTR_AO_ARTS_StreamOpen "[AO ARTS] Stream opened.\n"
+#define MSGTR_AO_ARTS_BufferSize "[AO ARTS] buffer size: %d\n"
+
+// ao_dxr2.c
+#define MSGTR_AO_DXR2_SetVolFailed "[AO DXR2] Setting volume to %d failed.\n"
+#define MSGTR_AO_DXR2_UnsupSamplerate "[AO DXR2] %d Hz not supported, try to resample.\n"
+
+// ao_esd.c
+#define MSGTR_AO_ESD_CantOpenSound "[AO ESD] esd_open_sound failed: %s\n"
+#define MSGTR_AO_ESD_LatencyInfo "[AO ESD] latency: [server: %0.2fs, net: %0.2fs] (adjust %0.2fs)\n"
+#define MSGTR_AO_ESD_CantOpenPBStream "[AO ESD] failed to open ESD playback stream: %s\n"
+
+// ao_mpegpes.c
+#define MSGTR_AO_MPEGPES_CantSetMixer "[AO MPEGPES] DVB audio set mixer failed: %s.\n"
+#define MSGTR_AO_MPEGPES_UnsupSamplerate "[AO MPEGPES] %d Hz not supported, try to resample.\n"
+
+// ao_pcm.c
+#define MSGTR_AO_PCM_FileInfo "[AO PCM] File: %s (%s)\nPCM: Samplerate: %iHz Channels: %s Format %s\n"
+#define MSGTR_AO_PCM_HintInfo "[AO PCM] Info: Faster dumping is achieved with -benchmark -vc null -vo null -ao pcm:fast\n[AO PCM] Info: To write WAVE files use -ao pcm:waveheader (default).\n"
+#define MSGTR_AO_PCM_CantOpenOutputFile "[AO PCM] Failed to open %s for writing!\n"
+
+// ao_sdl.c
+#define MSGTR_AO_SDL_INFO "[AO SDL] Samplerate: %iHz Channels: %s Format %s\n"
+#define MSGTR_AO_SDL_DriverInfo "[AO SDL] using %s audio driver.\n"
+#define MSGTR_AO_SDL_UnsupportedAudioFmt "[AO SDL] Unsupported audio format: 0x%x.\n"
+#define MSGTR_AO_SDL_CantInit "[AO SDL] SDL Audio initialization failed: %s\n"
+#define MSGTR_AO_SDL_CantOpenAudio "[AO SDL] Unable to open audio: %s\n"
+
+// ao_sgi.c
+#define MSGTR_AO_SGI_INFO "[AO SGI] control.\n"
+#define MSGTR_AO_SGI_InitInfo "[AO SGI] init: Samplerate: %iHz Channels: %s Format %s\n"
+#define MSGTR_AO_SGI_InvalidDevice "[AO SGI] play: invalid device.\n"
+#define MSGTR_AO_SGI_CantSetParms_Samplerate "[AO SGI] init: setparams failed: %s\nCould not set desired samplerate.\n"
+#define MSGTR_AO_SGI_CantSetAlRate "[AO SGI] init: AL_RATE was not accepted on the given resource.\n"
+#define MSGTR_AO_SGI_CantGetParms "[AO SGI] init: getparams failed: %s\n"
+#define MSGTR_AO_SGI_SampleRateInfo "[AO SGI] init: samplerate is now %f (desired rate is %f)\n"
+#define MSGTR_AO_SGI_InitConfigError "[AO SGI] init: %s\n"
+#define MSGTR_AO_SGI_InitOpenAudioFailed "[AO SGI] init: Unable to open audio channel: %s\n"
+#define MSGTR_AO_SGI_Uninit "[AO SGI] uninit: ...\n"
+#define MSGTR_AO_SGI_Reset "[AO SGI] reset: ...\n"
+#define MSGTR_AO_SGI_PauseInfo "[AO SGI] audio_pause: ...\n"
+#define MSGTR_AO_SGI_ResumeInfo "[AO SGI] audio_resume: ...\n"
+
+// ao_sun.c
+#define MSGTR_AO_SUN_RtscSetinfoFailed "[AO SUN] rtsc: SETINFO failed.\n"
+#define MSGTR_AO_SUN_RtscWriteFailed "[AO SUN] rtsc: write failed.\n"
+#define MSGTR_AO_SUN_CantOpenAudioDev "[AO SUN] Can't open audio device %s, %s -> nosound.\n"
+#define MSGTR_AO_SUN_UnsupSampleRate "[AO SUN] audio_setup: your card doesn't support %d channel, %s, %d Hz samplerate.\n"
+#define MSGTR_AO_SUN_CantUseSelect "[AO SUN]\n *** Your audio driver DOES NOT support select() ***\nRecompile MPlayer with #undef HAVE_AUDIO_SELECT in config.h !\n\n"
+#define MSGTR_AO_SUN_CantReopenReset "[AO SUN]\nFatal error: *** CANNOT REOPEN / RESET AUDIO DEVICE (%s) ***\n"
+
+// ao_alsa.c
+#define MSGTR_AO_ALSA_InvalidMixerIndexDefaultingToZero "[AO_ALSA] Invalid mixer index. Defaulting to 0.\n"
+#define MSGTR_AO_ALSA_MixerOpenError "[AO_ALSA] Mixer open error: %s\n"
+#define MSGTR_AO_ALSA_MixerAttachError "[AO_ALSA] Mixer attach %s error: %s\n"
+#define MSGTR_AO_ALSA_MixerRegisterError "[AO_ALSA] Mixer register error: %s\n"
+#define MSGTR_AO_ALSA_MixerLoadError "[AO_ALSA] Mixer load error: %s\n"
+#define MSGTR_AO_ALSA_UnableToFindSimpleControl "[AO_ALSA] Unable to find simple control '%s',%i.\n"
+#define MSGTR_AO_ALSA_ErrorSettingLeftChannel "[AO_ALSA] Error setting left channel, %s\n"
+#define MSGTR_AO_ALSA_ErrorSettingRightChannel "[AO_ALSA] Error setting right channel, %s\n"
+#define MSGTR_AO_ALSA_CommandlineHelp "\n[AO_ALSA] -ao alsa commandline help:\n"\
+"[AO_ALSA] Example: mplayer -ao alsa:device=hw=0.3\n"\
+"[AO_ALSA] Sets first card fourth hardware device.\n\n"\
+"[AO_ALSA] Options:\n"\
+"[AO_ALSA] noblock\n"\
+"[AO_ALSA] Opens device in non-blocking mode.\n"\
+"[AO_ALSA] device=<device-name>\n"\
+"[AO_ALSA] Sets device (change , to . and : to =)\n"
+#define MSGTR_AO_ALSA_ChannelsNotSupported "[AO_ALSA] %d channels are not supported.\n"
+#define MSGTR_AO_ALSA_OpenInNonblockModeFailed "[AO_ALSA] Open in nonblock-mode failed, trying to open in block-mode.\n"
+#define MSGTR_AO_ALSA_PlaybackOpenError "[AO_ALSA] Playback open error: %s\n"
+#define MSGTR_AO_ALSA_ErrorSetBlockMode "[AL_ALSA] Error setting block-mode %s.\n"
+#define MSGTR_AO_ALSA_UnableToGetInitialParameters "[AO_ALSA] Unable to get initial parameters: %s\n"
+#define MSGTR_AO_ALSA_UnableToSetAccessType "[AO_ALSA] Unable to set access type: %s\n"
+#define MSGTR_AO_ALSA_FormatNotSupportedByHardware "[AO_ALSA] Format %s is not supported by hardware, trying default.\n"
+#define MSGTR_AO_ALSA_UnableToSetFormat "[AO_ALSA] Unable to set format: %s\n"
+#define MSGTR_AO_ALSA_UnableToSetChannels "[AO_ALSA] Unable to set channels: %s\n"
+#define MSGTR_AO_ALSA_UnableToDisableResampling "[AO_ALSA] Unable to disable resampling: %s\n"
+#define MSGTR_AO_ALSA_UnableToSetSamplerate2 "[AO_ALSA] Unable to set samplerate-2: %s\n"
+#define MSGTR_AO_ALSA_UnableToSetBufferTimeNear "[AO_ALSA] Unable to set buffer time near: %s\n"
+#define MSGTR_AO_ALSA_UnableToGetPeriodSize "[AO ALSA] Unable to get period size: %s\n"
+#define MSGTR_AO_ALSA_UnableToSetPeriods "[AO_ALSA] Unable to set periods: %s\n"
+#define MSGTR_AO_ALSA_UnableToSetHwParameters "[AO_ALSA] Unable to set hw-parameters: %s\n"
+#define MSGTR_AO_ALSA_UnableToGetBufferSize "[AO_ALSA] Unable to get buffersize: %s\n"
+#define MSGTR_AO_ALSA_UnableToGetSwParameters "[AO_ALSA] Unable to get sw-parameters: %s\n"
+#define MSGTR_AO_ALSA_UnableToSetSwParameters "[AO_ALSA] Unable to set sw-parameters: %s\n"
+#define MSGTR_AO_ALSA_UnableToGetBoundary "[AO_ALSA] Unable to get boundary: %s\n"
+#define MSGTR_AO_ALSA_UnableToSetStartThreshold "[AO_ALSA] Unable to set start threshold: %s\n"
+#define MSGTR_AO_ALSA_UnableToSetStopThreshold "[AO_ALSA] Unable to set stop threshold: %s\n"
+#define MSGTR_AO_ALSA_UnableToSetSilenceSize "[AO_ALSA] Unable to set silence size: %s\n"
+#define MSGTR_AO_ALSA_PcmCloseError "[AO_ALSA] pcm close error: %s\n"
+#define MSGTR_AO_ALSA_NoHandlerDefined "[AO_ALSA] No handler defined!\n"
+#define MSGTR_AO_ALSA_PcmPrepareError "[AO_ALSA] pcm prepare error: %s\n"
+#define MSGTR_AO_ALSA_PcmPauseError "[AO_ALSA] pcm pause error: %s\n"
+#define MSGTR_AO_ALSA_PcmDropError "[AO_ALSA] pcm drop error: %s\n"
+#define MSGTR_AO_ALSA_PcmResumeError "[AO_ALSA] pcm resume error: %s\n"
+#define MSGTR_AO_ALSA_DeviceConfigurationError "[AO_ALSA] Device configuration error."
+#define MSGTR_AO_ALSA_PcmInSuspendModeTryingResume "[AO_ALSA] Pcm in suspend mode, trying to resume.\n"
+#define MSGTR_AO_ALSA_WriteError "[AO_ALSA] Write error: %s\n"
+#define MSGTR_AO_ALSA_TryingToResetSoundcard "[AO_ALSA] Trying to reset soundcard.\n"
+#define MSGTR_AO_ALSA_CannotGetPcmStatus "[AO_ALSA] Cannot get pcm status: %s\n"
+
+// ao_plugin.c
+#define MSGTR_AO_PLUGIN_InvalidPlugin "[AO PLUGIN] invalid plugin: %s\n"
+
+
+// ======================= audio filters ================================
+
+// af_scaletempo.c
+#define MSGTR_AF_ValueOutOfRange MSGTR_VO_ValueOutOfRange
+
+// af_ladspa.c
+#define MSGTR_AF_LADSPA_AvailableLabels "available labels in"
+#define MSGTR_AF_LADSPA_WarnNoInputs "WARNING! This LADSPA plugin has no audio inputs.\n The incoming audio signal will be lost."
+#define MSGTR_AF_LADSPA_ErrMultiChannel "Multi-channel (>2) plugins are not supported (yet).\n Use only mono and stereo plugins."
+#define MSGTR_AF_LADSPA_ErrNoOutputs "This LADSPA plugin has no audio outputs."
+#define MSGTR_AF_LADSPA_ErrInOutDiff "The number of audio inputs and audio outputs of the LADSPA plugin differ."
+#define MSGTR_AF_LADSPA_ErrFailedToLoad "failed to load"
+#define MSGTR_AF_LADSPA_ErrNoDescriptor "Couldn't find ladspa_descriptor() function in the specified library file."
+#define MSGTR_AF_LADSPA_ErrLabelNotFound "Couldn't find label in plugin library."
+#define MSGTR_AF_LADSPA_ErrNoSuboptions "No suboptions specified."
+#define MSGTR_AF_LADSPA_ErrNoLibFile "No library file specified."
+#define MSGTR_AF_LADSPA_ErrNoLabel "No filter label specified."
+#define MSGTR_AF_LADSPA_ErrNotEnoughControls "Not enough controls specified on the command line."
+#define MSGTR_AF_LADSPA_ErrControlBelow "%s: Input control #%d is below lower boundary of %0.4f.\n"
+#define MSGTR_AF_LADSPA_ErrControlAbove "%s: Input control #%d is above upper boundary of %0.4f.\n"
+
+// format.c
+#define MSGTR_AF_FORMAT_UnknownFormat "unknown format "
+
+
+// ========================== INPUT =========================================
+
+// joystick.c
+#define MSGTR_INPUT_JOYSTICK_CantOpen "Can't open joystick device %s: %s\n"
+#define MSGTR_INPUT_JOYSTICK_ErrReading "Error while reading joystick device: %s\n"
+#define MSGTR_INPUT_JOYSTICK_LoosingBytes "Joystick: We lose %d bytes of data\n"
+#define MSGTR_INPUT_JOYSTICK_WarnLostSync "Joystick: warning init event, we have lost sync with driver.\n"
+#define MSGTR_INPUT_JOYSTICK_WarnUnknownEvent "Joystick warning unknown event type %d\n"
+
+// appleir.c
+#define MSGTR_INPUT_APPLE_IR_CantOpen "Can't open Apple IR device: %s\n"
+
+// input.c
+#define MSGTR_INPUT_INPUT_ErrCantRegister2ManyCmdFds "Too many command file descriptors, cannot register file descriptor %d.\n"
+#define MSGTR_INPUT_INPUT_ErrCantRegister2ManyKeyFds "Too many key file descriptors, cannot register file descriptor %d.\n"
+#define MSGTR_INPUT_INPUT_ErrArgMustBeInt "Command %s: argument %d isn't an integer.\n"
+#define MSGTR_INPUT_INPUT_ErrArgMustBeFloat "Command %s: argument %d isn't a float.\n"
+#define MSGTR_INPUT_INPUT_ErrUnterminatedArg "Command %s: argument %d is unterminated.\n"
+#define MSGTR_INPUT_INPUT_ErrUnknownArg "Unknown argument %d\n"
+#define MSGTR_INPUT_INPUT_Err2FewArgs "Command %s requires at least %d arguments, we found only %d so far.\n"
+#define MSGTR_INPUT_INPUT_ErrReadingCmdFd "Error while reading command file descriptor %d: %s\n"
+#define MSGTR_INPUT_INPUT_ErrCmdBufferFullDroppingContent "Command buffer of file descriptor %d is full: dropping content.\n"
+#define MSGTR_INPUT_INPUT_ErrInvalidCommandForKey "Invalid command for bound key %s"
+#define MSGTR_INPUT_INPUT_ErrSelect "Select error: %s\n"
+#define MSGTR_INPUT_INPUT_ErrOnKeyInFd "Error on key input file descriptor %d\n"
+#define MSGTR_INPUT_INPUT_ErrDeadKeyOnFd "Dead key input on file descriptor %d\n"
+#define MSGTR_INPUT_INPUT_Err2ManyKeyDowns "Too many key down events at the same time\n"
+#define MSGTR_INPUT_INPUT_ErrOnCmdFd "Error on command file descriptor %d\n"
+#define MSGTR_INPUT_INPUT_ErrReadingInputConfig "Error while reading input config file %s: %s\n"
+#define MSGTR_INPUT_INPUT_ErrUnknownKey "Unknown key '%s'\n"
+#define MSGTR_INPUT_INPUT_ErrUnfinishedBinding "Unfinished binding %s\n"
+#define MSGTR_INPUT_INPUT_ErrBuffer2SmallForKeyName "Buffer is too small for this key name: %s\n"
+#define MSGTR_INPUT_INPUT_ErrNoCmdForKey "No command found for key %s"
+#define MSGTR_INPUT_INPUT_ErrBuffer2SmallForCmd "Buffer is too small for command %s\n"
+#define MSGTR_INPUT_INPUT_ErrWhyHere "What are we doing here?\n"
+#define MSGTR_INPUT_INPUT_ErrCantInitJoystick "Can't init input joystick\n"
+#define MSGTR_INPUT_INPUT_ErrCantOpenFile "Can't open %s: %s\n"
+#define MSGTR_INPUT_INPUT_ErrCantInitAppleRemote "Can't init Apple Remote.\n"
+
+// lirc.c
+#define MSGTR_LIRCopenfailed "Failed to open LIRC support. You will not be able to use your remote control.\n"
+#define MSGTR_LIRCcfgerr "Failed to read LIRC config file %s.\n"
+
+
+// ========================== LIBMPDEMUX ===================================
+
+// muxer.c, muxer_*.c
+#define MSGTR_TooManyStreams "Too many streams!"
+#define MSGTR_RawMuxerOnlyOneStream "Rawaudio muxer supports only one audio stream!\n"
+#define MSGTR_IgnoringVideoStream "Ignoring video stream!\n"
+#define MSGTR_UnknownStreamType "Warning, unknown stream type: %d\n"
+#define MSGTR_WarningLenIsntDivisible "Warning, len isn't divisible by samplesize!\n"
+#define MSGTR_MuxbufMallocErr "Muxer frame buffer cannot allocate memory!\n"
+#define MSGTR_MuxbufReallocErr "Muxer frame buffer cannot reallocate memory!\n"
+#define MSGTR_WritingHeader "Writing header...\n"
+#define MSGTR_WritingTrailer "Writing index...\n"
+
+// demuxer.c, demux_*.c
+#define MSGTR_AudioStreamRedefined "WARNING: Audio stream header %d redefined.\n"
+#define MSGTR_VideoStreamRedefined "WARNING: Video stream header %d redefined.\n"
+#define MSGTR_TooManyAudioInBuffer "\nToo many audio packets in the buffer: (%d in %d bytes).\n"
+#define MSGTR_TooManyVideoInBuffer "\nToo many video packets in the buffer: (%d in %d bytes).\n"
+#define MSGTR_MaybeNI "Maybe you are playing a non-interleaved stream/file or the codec failed?\n" \
+ "For AVI files, try to force non-interleaved mode with the -ni option.\n"
+#define MSGTR_WorkAroundBlockAlignHeaderBug "AVI: Working around CBR-MP3 nBlockAlign header bug!\n"
+#define MSGTR_SwitchToNi "\nBadly interleaved AVI file detected - switching to -ni mode...\n"
+#define MSGTR_InvalidAudioStreamNosound "AVI: invalid audio stream ID: %d - ignoring (nosound)\n"
+#define MSGTR_InvalidAudioStreamUsingDefault "AVI: invalid video stream ID: %d - ignoring (using default)\n"
+#define MSGTR_ON2AviFormat "ON2 AVI format"
+#define MSGTR_Detected_XXX_FileFormat "%s file format detected.\n"
+#define MSGTR_DetectedAudiofile "Audio file detected.\n"
+#define MSGTR_InvalidMPEGES "Invalid MPEG-ES stream??? Contact the author, it may be a bug :(\n"
+#define MSGTR_FormatNotRecognized "============ Sorry, this file format is not recognized/supported =============\n"\
+ "=== If this file is an AVI, ASF or MPEG stream, please contact the author! ===\n"
+#define MSGTR_SettingProcessPriority "Setting process priority: %s\n"
+#define MSGTR_FilefmtFourccSizeFpsFtime "[V] filefmt:%d fourcc:0x%X size:%dx%d fps:%5.3f ftime:=%6.4f\n"
+#define MSGTR_CannotInitializeMuxer "Cannot initialize muxer."
+#define MSGTR_MissingVideoStream "No video stream found.\n"
+#define MSGTR_MissingAudioStream "No audio stream found -> no sound.\n"
+#define MSGTR_MissingVideoStreamBug "Missing video stream!? Contact the author, it may be a bug :(\n"
+
+#define MSGTR_DoesntContainSelectedStream "demux: File doesn't contain the selected audio or video stream.\n"
+
+#define MSGTR_NI_Forced "Forced"
+#define MSGTR_NI_Detected "Detected"
+#define MSGTR_NI_Message "%s NON-INTERLEAVED AVI file format.\n"
+
+#define MSGTR_UsingNINI "Using NON-INTERLEAVED broken AVI file format.\n"
+#define MSGTR_CouldntDetFNo "Could not determine number of frames (for absolute seek).\n"
+#define MSGTR_CantSeekRawAVI "Cannot seek in raw AVI streams. (Index required, try with the -idx switch.)\n"
+#define MSGTR_CantSeekFile "Cannot seek in this file.\n"
+
+#define MSGTR_MOVcomprhdr "MOV: Compressed headers support requires ZLIB!\n"
+#define MSGTR_MOVvariableFourCC "MOV: WARNING: Variable FourCC detected!?\n"
+#define MSGTR_MOVtooManyTrk "MOV: WARNING: too many tracks"
+#define MSGTR_DetectedTV "TV detected! ;-)\n"
+#define MSGTR_ErrorOpeningOGGDemuxer "Unable to open the Ogg demuxer.\n"
+#define MSGTR_CannotOpenAudioStream "Cannot open audio stream: %s\n"
+#define MSGTR_CannotOpenSubtitlesStream "Cannot open subtitle stream: %s\n"
+#define MSGTR_OpeningAudioDemuxerFailed "Failed to open audio demuxer: %s\n"
+#define MSGTR_OpeningSubtitlesDemuxerFailed "Failed to open subtitle demuxer: %s\n"
+#define MSGTR_TVInputNotSeekable "TV input is not seekable! (Seeking will probably be for changing channels ;)\n"
+#define MSGTR_DemuxerInfoChanged "Demuxer info %s changed to %s\n"
+#define MSGTR_ClipInfo "Clip info:\n"
+
+#define MSGTR_LeaveTelecineMode "\ndemux_mpg: 30000/1001fps NTSC content detected, switching framerate.\n"
+#define MSGTR_EnterTelecineMode "\ndemux_mpg: 24000/1001fps progressive NTSC content detected, switching framerate.\n"
+
+#define MSGTR_CacheFill "\rCache fill: %5.2f%% (%"PRId64" bytes) "
+#define MSGTR_NoBindFound "No bind found for key '%s'.\n"
+#define MSGTR_FailedToOpen "Failed to open %s.\n"
+
+#define MSGTR_VideoID "[%s] Video stream found, -vid %d\n"
+#define MSGTR_AudioID "[%s] Audio stream found, -aid %d\n"
+#define MSGTR_SubtitleID "[%s] Subtitle stream found, -sid %d\n"
+
+// asfheader.c
+#define MSGTR_MPDEMUX_ASFHDR_HeaderSizeOver1MB "FATAL: header size bigger than 1 MB (%d)!\nPlease contact MPlayer authors, and upload/send this file.\n"
+#define MSGTR_MPDEMUX_ASFHDR_HeaderMallocFailed "Could not allocate %d bytes for header.\n"
+#define MSGTR_MPDEMUX_ASFHDR_EOFWhileReadingHeader "EOF while reading ASF header, broken/incomplete file?\n"
+#define MSGTR_MPDEMUX_ASFHDR_DVRWantsLibavformat "DVR will probably only work with libavformat, try -demuxer 35 if you have problems\n"
+#define MSGTR_MPDEMUX_ASFHDR_NoDataChunkAfterHeader "No data chunk following header!\n"
+#define MSGTR_MPDEMUX_ASFHDR_AudioVideoHeaderNotFound "ASF: no audio or video headers found - broken file?\n"
+#define MSGTR_MPDEMUX_ASFHDR_InvalidLengthInASFHeader "Invalid length in ASF header!\n"
+#define MSGTR_MPDEMUX_ASFHDR_DRMLicenseURL "DRM License URL: %s\n"
+#define MSGTR_MPDEMUX_ASFHDR_DRMProtected "This file has been encumbered with DRM encryption, it will not play in MPlayer!\n"
+
+// aviheader.c
+#define MSGTR_MPDEMUX_AVIHDR_EmptyList "** empty list?!\n"
+#define MSGTR_MPDEMUX_AVIHDR_WarnNotExtendedAVIHdr "** Warning: this is no extended AVI header..\n"
+#define MSGTR_MPDEMUX_AVIHDR_BuildingODMLidx "AVI: ODML: Building ODML index (%d superindexchunks).\n"
+#define MSGTR_MPDEMUX_AVIHDR_BrokenODMLfile "AVI: ODML: Broken (incomplete?) file detected. Will use traditional index.\n"
+#define MSGTR_MPDEMUX_AVIHDR_CantReadIdxFile "Can't read index file %s: %s\n"
+#define MSGTR_MPDEMUX_AVIHDR_NotValidMPidxFile "%s is not a valid MPlayer index file.\n"
+#define MSGTR_MPDEMUX_AVIHDR_FailedMallocForIdxFile "Could not allocate memory for index data from %s.\n"
+#define MSGTR_MPDEMUX_AVIHDR_PrematureEOF "premature end of index file %s\n"
+#define MSGTR_MPDEMUX_AVIHDR_IdxFileLoaded "Loaded index file: %s\n"
+#define MSGTR_MPDEMUX_AVIHDR_GeneratingIdx "Generating Index: %3lu %s \r"
+#define MSGTR_MPDEMUX_AVIHDR_IdxGeneratedForHowManyChunks "AVI: Generated index table for %d chunks!\n"
+#define MSGTR_MPDEMUX_AVIHDR_Failed2WriteIdxFile "Couldn't write index file %s: %s\n"
+#define MSGTR_MPDEMUX_AVIHDR_IdxFileSaved "Saved index file: %s\n"
+
+// demux_audio.c
+#define MSGTR_MPDEMUX_AUDIO_BadID3v2TagSize "Audio demuxer: bad ID3v2 tag size: larger than stream (%u).\n"
+#define MSGTR_MPDEMUX_AUDIO_DamagedAppendedID3v2Tag "Audio demuxer: damaged appended ID3v2 tag detected.\n"
+#define MSGTR_MPDEMUX_AUDIO_UnknownFormat "Audio demuxer: unknown format %d.\n"
+
+// demux_demuxers.c
+#define MSGTR_MPDEMUX_DEMUXERS_FillBufferError "fill_buffer error: bad demuxer: not vd, ad or sd.\n"
+
+// demux_mkv.c
+#define MSGTR_MPDEMUX_MKV_ZlibInitializationFailed "[mkv] zlib initialization failed.\n"
+#define MSGTR_MPDEMUX_MKV_ZlibDecompressionFailed "[mkv] zlib decompression failed.\n"
+#define MSGTR_MPDEMUX_MKV_LzoInitializationFailed "[mkv] lzo initialization failed.\n"
+#define MSGTR_MPDEMUX_MKV_LzoDecompressionFailed "[mkv] lzo decompression failed.\n"
+#define MSGTR_MPDEMUX_MKV_TrackEncrypted "[mkv] Track number %u has been encrypted and decryption has not yet been\n[mkv] implemented. Skipping track.\n"
+#define MSGTR_MPDEMUX_MKV_UnknownContentEncoding "[mkv] Unknown content encoding type for track %u. Skipping track.\n"
+#define MSGTR_MPDEMUX_MKV_UnknownCompression "[mkv] Track %u has been compressed with an unknown/unsupported compression\n[mkv] algorithm (%u). Skipping track.\n"
+#define MSGTR_MPDEMUX_MKV_ZlibCompressionUnsupported "[mkv] Track %u was compressed with zlib but mplayer has not been compiled\n[mkv] with support for zlib compression. Skipping track.\n"
+#define MSGTR_MPDEMUX_MKV_TrackIDName "[mkv] Track ID %u: %s (%s) \"%s\", %s\n"
+#define MSGTR_MPDEMUX_MKV_TrackID "[mkv] Track ID %u: %s (%s), %s\n"
+#define MSGTR_MPDEMUX_MKV_UnknownCodecID "[mkv] Unknown/unsupported CodecID (%s) or missing/bad CodecPrivate\n[mkv] data (track %u).\n"
+#define MSGTR_MPDEMUX_MKV_FlacTrackDoesNotContainValidHeaders "[mkv] FLAC track does not contain valid headers.\n"
+#define MSGTR_MPDEMUX_MKV_UnknownAudioCodec "[mkv] Unknown/unsupported audio codec ID '%s' for track %u or missing/faulty\n[mkv] private codec data.\n"
+#define MSGTR_MPDEMUX_MKV_SubtitleTypeNotSupported "[mkv] Subtitle type '%s' is not supported.\n"
+#define MSGTR_MPDEMUX_MKV_WillPlayVideoTrack "[mkv] Will play video track %u.\n"
+#define MSGTR_MPDEMUX_MKV_NoVideoTrackFound "[mkv] No video track found/wanted.\n"
+#define MSGTR_MPDEMUX_MKV_NoAudioTrackFound "[mkv] No audio track found/wanted.\n"
+#define MSGTR_MPDEMUX_MKV_WillDisplaySubtitleTrack "[mkv] Will display subtitle track %u.\n"
+#define MSGTR_MPDEMUX_MKV_NoBlockDurationForSubtitleTrackFound "[mkv] Warning: No BlockDuration for subtitle track found.\n"
+#define MSGTR_MPDEMUX_MKV_TooManySublines "[mkv] Warning: too many sublines to render, skipping.\n"
+#define MSGTR_MPDEMUX_MKV_TooManySublinesSkippingAfterFirst "\n[mkv] Warning: too many sublines to render, skipping after first %i.\n"
+
+// demux_nuv.c
+#define MSGTR_MPDEMUX_NUV_NoVideoBlocksInFile "No video blocks in file.\n"
+
+// demux_xmms.c
+#define MSGTR_MPDEMUX_XMMS_FoundPlugin "Found plugin: %s (%s).\n"
+#define MSGTR_MPDEMUX_XMMS_ClosingPlugin "Closing plugin: %s.\n"
+#define MSGTR_MPDEMUX_XMMS_WaitForStart "Waiting for the XMMS plugin to start playback of '%s'...\n"
+
+
+// ========================== LIBMENU ===================================
+
+// common
+#define MSGTR_LIBMENU_NoEntryFoundInTheMenuDefinition "[MENU] No entry found in the menu definition.\n"
+
+// libmenu/menu.c
+#define MSGTR_LIBMENU_SyntaxErrorAtLine "[MENU] syntax error at line: %d\n"
+#define MSGTR_LIBMENU_MenuDefinitionsNeedANameAttrib "[MENU] Menu definitions need a name attribute (line %d).\n"
+#define MSGTR_LIBMENU_BadAttrib "[MENU] bad attribute %s=%s in menu '%s' at line %d\n"
+#define MSGTR_LIBMENU_UnknownMenuType "[MENU] unknown menu type '%s' at line %d\n"
+#define MSGTR_LIBMENU_CantOpenConfigFile "[MENU] Can't open menu config file: %s\n"
+#define MSGTR_LIBMENU_ConfigFileIsTooBig "[MENU] Config file is too big (> %d KB)\n"
+#define MSGTR_LIBMENU_ConfigFileIsEmpty "[MENU] Config file is empty.\n"
+#define MSGTR_LIBMENU_MenuNotFound "[MENU] Menu %s not found.\n"
+#define MSGTR_LIBMENU_MenuInitFailed "[MENU] Menu '%s': Init failed.\n"
+#define MSGTR_LIBMENU_UnsupportedOutformat "[MENU] Unsupported output format!!!!\n"
+
+// libmenu/menu_cmdlist.c
+#define MSGTR_LIBMENU_ListMenuEntryDefinitionsNeedAName "[MENU] List menu entry definitions need a name (line %d).\n"
+#define MSGTR_LIBMENU_ListMenuNeedsAnArgument "[MENU] List menu needs an argument.\n"
+
+// libmenu/menu_console.c
+#define MSGTR_LIBMENU_WaitPidError "[MENU] Waitpid error: %s.\n"
+#define MSGTR_LIBMENU_SelectError "[MENU] Select error.\n"
+#define MSGTR_LIBMENU_ReadErrorOnChildFD "[MENU] Read error on child's file descriptor: %s.\n"
+#define MSGTR_LIBMENU_ConsoleRun "[MENU] Console run: %s ...\n"
+#define MSGTR_LIBMENU_AChildIsAlreadyRunning "[MENU] A child is already running.\n"
+#define MSGTR_LIBMENU_ForkFailed "[MENU] Fork failed !!!\n"
+#define MSGTR_LIBMENU_WriteError "[MENU] write error\n"
+
+// libmenu/menu_filesel.c
+#define MSGTR_LIBMENU_OpendirError "[MENU] opendir error: %s\n"
+#define MSGTR_LIBMENU_ReallocError "[MENU] realloc error: %s\n"
+#define MSGTR_LIBMENU_MallocError "[MENU] memory allocation error: %s\n"
+#define MSGTR_LIBMENU_ReaddirError "[MENU] readdir error: %s\n"
+#define MSGTR_LIBMENU_CantOpenDirectory "[MENU] Can't open directory %s.\n"
+
+// libmenu/menu_param.c
+#define MSGTR_LIBMENU_SubmenuDefinitionNeedAMenuAttribut "[MENU] Submenu definition needs a 'menu' attribute.\n"
+#define MSGTR_LIBMENU_InvalidProperty "[MENU] Invalid property '%s' in pref menu entry. (line %d).\n"
+#define MSGTR_LIBMENU_PrefMenuEntryDefinitionsNeed "[MENU] Pref menu entry definitions need a valid 'property' or 'txt' attribute (line %d).\n"
+#define MSGTR_LIBMENU_PrefMenuNeedsAnArgument "[MENU] Pref menu needs an argument.\n"
+
+// libmenu/menu_pt.c
+#define MSGTR_LIBMENU_CantfindTheTargetItem "[MENU] Can't find the target item ????\n"
+#define MSGTR_LIBMENU_FailedToBuildCommand "[MENU] Failed to build command: %s.\n"
+
+// libmenu/menu_txt.c
+#define MSGTR_LIBMENU_MenuTxtNeedATxtFileName "[MENU] Text menu needs a textfile name (parameter file).\n"
+#define MSGTR_LIBMENU_MenuTxtCantOpen "[MENU] Can't open %s.\n"
+#define MSGTR_LIBMENU_WarningTooLongLineSplitting "[MENU] Warning, line too long. Splitting it.\n"
+#define MSGTR_LIBMENU_ParsedLines "[MENU] Parsed %d lines.\n"
+
+// libmenu/vf_menu.c
+#define MSGTR_LIBMENU_UnknownMenuCommand "[MENU] Unknown command: '%s'.\n"
+#define MSGTR_LIBMENU_FailedToOpenMenu "[MENU] Failed to open menu: '%s'.\n"
+
+
+// ========================== LIBMPCODECS ===================================
+
+// dec_video.c & dec_audio.c:
+#define MSGTR_CantOpenCodec "Could not open codec.\n"
+#define MSGTR_CantCloseCodec "Could not close codec.\n"
+
+#define MSGTR_MissingDLLcodec "ERROR: Could not open required DirectShow codec %s.\n"
+#define MSGTR_ACMiniterror "Could not load/initialize Win32/ACM audio codec (missing DLL file?).\n"
+#define MSGTR_MissingLAVCcodec "Cannot find codec '%s' in libavcodec...\n"
+
+#define MSGTR_MpegNoSequHdr "MPEG: FATAL: EOF while searching for sequence header.\n"
+#define MSGTR_CannotReadMpegSequHdr "FATAL: Cannot read sequence header.\n"
+#define MSGTR_CannotReadMpegSequHdrEx "FATAL: Cannot read sequence header extension.\n"
+#define MSGTR_BadMpegSequHdr "MPEG: bad sequence header\n"
+#define MSGTR_BadMpegSequHdrEx "MPEG: bad sequence header extension\n"
+
+#define MSGTR_ShMemAllocFail "Cannot allocate shared memory.\n"
+#define MSGTR_CantAllocAudioBuf "Cannot allocate audio out buffer.\n"
+
+#define MSGTR_UnknownAudio "Unknown/missing audio format -> no sound\n"
+
+#define MSGTR_UsingExternalPP "[PP] Using external postprocessing filter, max q = %d.\n"
+#define MSGTR_UsingCodecPP "[PP] Using codec's postprocessing, max q = %d.\n"
+#define MSGTR_VideoCodecFamilyNotAvailableStr "Requested video codec family [%s] (vfm=%s) not available.\nEnable it at compilation.\n"
+#define MSGTR_AudioCodecFamilyNotAvailableStr "Requested audio codec family [%s] (afm=%s) not available.\nEnable it at compilation.\n"
+#define MSGTR_OpeningVideoDecoder "Opening video decoder: [%s] %s\n"
+#define MSGTR_SelectedVideoCodec "Selected video codec: [%s] vfm: %s (%s)\n"
+#define MSGTR_OpeningAudioDecoder "Opening audio decoder: [%s] %s\n"
+#define MSGTR_SelectedAudioCodec "Selected audio codec: [%s] afm: %s (%s)\n"
+#define MSGTR_VDecoderInitFailed "VDecoder init failed :(\n"
+#define MSGTR_ADecoderInitFailed "ADecoder init failed :(\n"
+#define MSGTR_ADecoderPreinitFailed "ADecoder preinit failed :(\n"
+
+// ad_dvdpcm.c:
+#define MSGTR_SamplesWanted "Samples of this format are needed to improve support. Please contact the developers.\n"
+
+// libmpcodecs/ad_libdv.c
+#define MSGTR_MPCODECS_AudioFramesizeDiffers "[AD_LIBDV] Warning! Audio framesize differs! read=%d hdr=%d.\n"
+
+// vd.c
+#define MSGTR_CodecDidNotSet "VDec: Codec did not set sh->disp_w and sh->disp_h, trying workaround.\n"
+#define MSGTR_CouldNotFindColorspace "Could not find matching colorspace - retrying with -vf scale...\n"
+#define MSGTR_MovieAspectIsSet "Movie-Aspect is %.2f:1 - prescaling to correct movie aspect.\n"
+#define MSGTR_MovieAspectUndefined "Movie-Aspect is undefined - no prescaling applied.\n"
+
+// vd_dshow.c, vd_dmo.c
+#define MSGTR_DownloadCodecPackage "You need to upgrade/install the binary codecs package.\nGo to http://www.mplayerhq.hu/dload.html\n"
+
+// libmpcodecs/vd_dmo.c vd_dshow.c vd_vfw.c
+#define MSGTR_MPCODECS_CouldntAllocateImageForCinepakCodec "[VD_DMO] Couldn't allocate image for cinepak codec.\n"
+
+// libmpcodecs/vd_ffmpeg.c
+#define MSGTR_MPCODECS_XVMCAcceleratedCodec "[VD_FFMPEG] XVMC accelerated codec.\n"
+#define MSGTR_MPCODECS_ArithmeticMeanOfQP "[VD_FFMPEG] Arithmetic mean of QP: %2.4f, Harmonic mean of QP: %2.4f\n"
+#define MSGTR_MPCODECS_DRIFailure "[VD_FFMPEG] DRI failure.\n"
+#define MSGTR_MPCODECS_CouldntAllocateImageForCodec "[VD_FFMPEG] Couldn't allocate image for codec.\n"
+#define MSGTR_MPCODECS_XVMCAcceleratedMPEG2 "[VD_FFMPEG] XVMC-accelerated MPEG-2.\n"
+#define MSGTR_MPCODECS_TryingPixfmt "[VD_FFMPEG] Trying pixfmt=%d.\n"
+#define MSGTR_MPCODECS_McGetBufferShouldWorkOnlyWithXVMC "[VD_FFMPEG] The mc_get_buffer should work only with XVMC acceleration!!"
+#define MSGTR_MPCODECS_UnexpectedInitVoError "[VD_FFMPEG] Unexpected init_vo error.\n"
+#define MSGTR_MPCODECS_UnrecoverableErrorRenderBuffersNotTaken "[VD_FFMPEG] Unrecoverable error, render buffers not taken.\n"
+#define MSGTR_MPCODECS_OnlyBuffersAllocatedByVoXvmcAllowed "[VD_FFMPEG] Only buffers allocated by vo_xvmc allowed.\n"
+
+// libmpcodecs/ve_lavc.c
+#define MSGTR_MPCODECS_HighQualityEncodingSelected "[VE_LAVC] High quality encoding selected (non-realtime)!\n"
+#define MSGTR_MPCODECS_UsingConstantQscale "[VE_LAVC] Using constant qscale = %f (VBR).\n"
+
+// libmpcodecs/ve_raw.c
+#define MSGTR_MPCODECS_OutputWithFourccNotSupported "[VE_RAW] Raw output with FourCC [%x] not supported!\n"
+#define MSGTR_MPCODECS_NoVfwCodecSpecified "[VE_RAW] Required VfW codec not specified!!\n"
+
+// vf.c
+#define MSGTR_CouldNotFindVideoFilter "Couldn't find video filter '%s'.\n"
+#define MSGTR_CouldNotOpenVideoFilter "Couldn't open video filter '%s'.\n"
+#define MSGTR_OpeningVideoFilter "Opening video filter: "
+#define MSGTR_CannotFindColorspace "Cannot find matching colorspace, even by inserting 'scale' :(\n"
+
+// libmpcodecs/vf_crop.c
+#define MSGTR_MPCODECS_CropBadPositionWidthHeight "[CROP] Bad position/width/height - cropped area outside of the original!\n"
+
+// libmpcodecs/vf_cropdetect.c
+#define MSGTR_MPCODECS_CropArea "[CROP] Crop area: X: %d..%d Y: %d..%d (-vf crop=%d:%d:%d:%d).\n"
+
+// libmpcodecs/vf_format.c, vf_palette.c, vf_noformat.c
+#define MSGTR_MPCODECS_UnknownFormatName "[VF_FORMAT] Unknown format name: '%s'.\n"
+
+// libmpcodecs/vf_framestep.c vf_noformat.c vf_palette.c vf_tile.c
+#define MSGTR_MPCODECS_ErrorParsingArgument "[VF_FRAMESTEP] Error parsing argument.\n"
+
+// libmpcodecs/ve_vfw.c
+#define MSGTR_MPCODECS_CompressorType "Compressor type: %.4lx\n"
+#define MSGTR_MPCODECS_CompressorSubtype "Compressor subtype: %.4lx\n"
+#define MSGTR_MPCODECS_CompressorFlags "Compressor flags: %lu, version %lu, ICM version: %lu\n"
+#define MSGTR_MPCODECS_Flags "Flags:"
+#define MSGTR_MPCODECS_Quality " quality"
+
+// libmpcodecs/vf_expand.c
+#define MSGTR_MPCODECS_FullDRNotPossible "Full DR not possible, trying SLICES instead!\n"
+#define MSGTR_MPCODECS_WarnNextFilterDoesntSupportSlices "WARNING! Next filter doesn't support SLICES, get ready for sig11...\n"
+#define MSGTR_MPCODECS_FunWhydowegetNULL "Why do we get NULL??\n"
+
+// libmpcodecs/vf_test.c, vf_yuy2.c, vf_yvu9.c
+#define MSGTR_MPCODECS_WarnNextFilterDoesntSupport "%s not supported by next filter/vo :(\n"
+
+
+// ================================== LIBASS ====================================
+
+// ass_bitmap.c
+#define MSGTR_LIBASS_FT_Glyph_To_BitmapError "[ass] FT_Glyph_To_Bitmap error %d \n"
+#define MSGTR_LIBASS_UnsupportedPixelMode "[ass] Unsupported pixel mode: %d\n"
+#define MSGTR_LIBASS_GlyphBBoxTooLarge "[ass] Glyph bounding box too large: %dx%dpx\n"
+
+// ass.c
+#define MSGTR_LIBASS_NoStyleNamedXFoundUsingY "[ass] [%p] Warning: no style named '%s' found, using '%s'\n"
+#define MSGTR_LIBASS_BadTimestamp "[ass] bad timestamp\n"
+#define MSGTR_LIBASS_BadEncodedDataSize "[ass] bad encoded data size\n"
+#define MSGTR_LIBASS_FontLineTooLong "[ass] Font line too long: %d, %s\n"
+#define MSGTR_LIBASS_EventFormatHeaderMissing "[ass] Event format header missing\n"
+#define MSGTR_LIBASS_ErrorOpeningIconvDescriptor "[ass] error opening iconv descriptor.\n"
+#define MSGTR_LIBASS_ErrorRecodingFile "[ass] error recoding file.\n"
+#define MSGTR_LIBASS_FopenFailed "[ass] ass_read_file(%s): fopen failed\n"
+#define MSGTR_LIBASS_FseekFailed "[ass] ass_read_file(%s): fseek failed\n"
+#define MSGTR_LIBASS_RefusingToLoadSubtitlesLargerThan100M "[ass] ass_read_file(%s): Refusing to load subtitles larger than 100M\n"
+#define MSGTR_LIBASS_ReadFailed "Read failed, %d: %s\n"
+#define MSGTR_LIBASS_AddedSubtitleFileMemory "[ass] Added subtitle file: <memory> (%d styles, %d events)\n"
+#define MSGTR_LIBASS_AddedSubtitleFileFname "[ass] Added subtitle file: %s (%d styles, %d events)\n"
+#define MSGTR_LIBASS_FailedToCreateDirectory "[ass] Failed to create directory %s\n"
+#define MSGTR_LIBASS_NotADirectory "[ass] Not a directory: %s\n"
+
+// ass_cache.c
+#define MSGTR_LIBASS_TooManyFonts "[ass] Too many fonts\n"
+#define MSGTR_LIBASS_ErrorOpeningFont "[ass] Error opening font: %s, %d\n"
+
+// ass_fontconfig.c
+#define MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne "[ass] fontconfig: Selected font is not the requested one: '%s' != '%s'\n"
+#define MSGTR_LIBASS_UsingDefaultFontFamily "[ass] fontconfig_select: Using default font family: (%s, %d, %d) -> %s, %d\n"
+#define MSGTR_LIBASS_UsingDefaultFont "[ass] fontconfig_select: Using default font: (%s, %d, %d) -> %s, %d\n"
+#define MSGTR_LIBASS_UsingArialFontFamily "[ass] fontconfig_select: Using 'Arial' font family: (%s, %d, %d) -> %s, %d\n"
+#define MSGTR_LIBASS_FcInitLoadConfigAndFontsFailed "[ass] FcInitLoadConfigAndFonts failed.\n"
+#define MSGTR_LIBASS_UpdatingFontCache "[ass] Updating font cache.\n"
+#define MSGTR_LIBASS_BetaVersionsOfFontconfigAreNotSupported "[ass] Beta versions of fontconfig are not supported.\n[ass] Update before reporting any bugs.\n"
+#define MSGTR_LIBASS_FcStrSetAddFailed "[ass] FcStrSetAdd failed.\n"
+#define MSGTR_LIBASS_FcDirScanFailed "[ass] FcDirScan failed.\n"
+#define MSGTR_LIBASS_FcDirSave "[ass] FcDirSave failed.\n"
+#define MSGTR_LIBASS_FcConfigAppFontAddDirFailed "[ass] FcConfigAppFontAddDir failed\n"
+#define MSGTR_LIBASS_FontconfigDisabledDefaultFontWillBeUsed "[ass] Fontconfig disabled, only default font will be used.\n"
+#define MSGTR_LIBASS_FunctionCallFailed "[ass] %s failed\n"
+
+// ass_render.c
+#define MSGTR_LIBASS_NeitherPlayResXNorPlayResYDefined "[ass] Neither PlayResX nor PlayResY defined. Assuming 384x288.\n"
+#define MSGTR_LIBASS_PlayResYUndefinedSettingY "[ass] PlayResY undefined, setting %d.\n"
+#define MSGTR_LIBASS_PlayResXUndefinedSettingX "[ass] PlayResX undefined, setting %d.\n"
+#define MSGTR_LIBASS_FT_Init_FreeTypeFailed "[ass] FT_Init_FreeType failed.\n"
+#define MSGTR_LIBASS_Init "[ass] Init\n"
+#define MSGTR_LIBASS_InitFailed "[ass] Init failed.\n"
+#define MSGTR_LIBASS_BadCommand "[ass] Bad command: %c%c\n"
+#define MSGTR_LIBASS_ErrorLoadingGlyph "[ass] Error loading glyph.\n"
+#define MSGTR_LIBASS_FT_Glyph_Stroke_Error "[ass] FT_Glyph_Stroke error %d \n"
+#define MSGTR_LIBASS_UnknownEffectType_InternalError "[ass] Unknown effect type (internal error)\n"
+#define MSGTR_LIBASS_NoStyleFound "[ass] No style found!\n"
+#define MSGTR_LIBASS_EmptyEvent "[ass] Empty event!\n"
+#define MSGTR_LIBASS_MAX_GLYPHS_Reached "[ass] MAX_GLYPHS reached: event %d, start = %llu, duration = %llu\n Text = %s\n"
+#define MSGTR_LIBASS_EventHeightHasChanged "[ass] Warning! Event height has changed! \n"
+
+// ass_font.c
+#define MSGTR_LIBASS_GlyphNotFoundReselectingFont "[ass] Glyph 0x%X not found, selecting one more font for (%s, %d, %d)\n"
+#define MSGTR_LIBASS_GlyphNotFound "[ass] Glyph 0x%X not found in font for (%s, %d, %d)\n"
+#define MSGTR_LIBASS_ErrorOpeningMemoryFont "[ass] Error opening memory font: %s\n"
+#define MSGTR_LIBASS_NoCharmaps "[ass] font face with no charmaps\n"
+#define MSGTR_LIBASS_NoCharmapAutodetected "[ass] no charmap autodetected, trying the first one\n"
+
+
+// ================================== stream ====================================
+
+// ai_alsa.c
+#define MSGTR_MPDEMUX_AIALSA_CannotSetSamplerate "Cannot set samplerate.\n"
+#define MSGTR_MPDEMUX_AIALSA_CannotSetBufferTime "Cannot set buffer time.\n"
+#define MSGTR_MPDEMUX_AIALSA_CannotSetPeriodTime "Cannot set period time.\n"
+
+// ai_alsa.c
+#define MSGTR_MPDEMUX_AIALSA_PcmBrokenConfig "Broken configuration for this PCM: no configurations available.\n"
+#define MSGTR_MPDEMUX_AIALSA_UnavailableAccessType "Access type not available.\n"
+#define MSGTR_MPDEMUX_AIALSA_UnavailableSampleFmt "Sample format not available.\n"
+#define MSGTR_MPDEMUX_AIALSA_UnavailableChanCount "Channel count not available - reverting to default: %d\n"
+#define MSGTR_MPDEMUX_AIALSA_CannotInstallHWParams "Unable to install hardware parameters: %s"
+#define MSGTR_MPDEMUX_AIALSA_PeriodEqualsBufferSize "Can't use period equal to buffer size (%u == %lu)\n"
+#define MSGTR_MPDEMUX_AIALSA_CannotInstallSWParams "Unable to install software parameters:\n"
+#define MSGTR_MPDEMUX_AIALSA_ErrorOpeningAudio "Error opening audio: %s\n"
+#define MSGTR_MPDEMUX_AIALSA_AlsaStatusError "ALSA status error: %s"
+#define MSGTR_MPDEMUX_AIALSA_AlsaXRUN "ALSA xrun!!! (at least %.3f ms long)\n"
+#define MSGTR_MPDEMUX_AIALSA_AlsaXRUNPrepareError "ALSA xrun: prepare error: %s"
+#define MSGTR_MPDEMUX_AIALSA_AlsaReadWriteError "ALSA read/write error"
+
+// ai_oss.c
+#define MSGTR_MPDEMUX_AIOSS_Unable2SetChanCount "Unable to set channel count: %d\n"
+#define MSGTR_MPDEMUX_AIOSS_Unable2SetStereo "Unable to set stereo: %d\n"
+#define MSGTR_MPDEMUX_AIOSS_Unable2Open "Unable to open '%s': %s\n"
+#define MSGTR_MPDEMUX_AIOSS_UnsupportedFmt "unsupported format\n"
+#define MSGTR_MPDEMUX_AIOSS_Unable2SetAudioFmt "Unable to set audio format."
+#define MSGTR_MPDEMUX_AIOSS_Unable2SetSamplerate "Unable to set samplerate: %d\n"
+#define MSGTR_MPDEMUX_AIOSS_Unable2SetTrigger "Unable to set trigger: %d\n"
+#define MSGTR_MPDEMUX_AIOSS_Unable2GetBlockSize "Unable to get block size!\n"
+#define MSGTR_MPDEMUX_AIOSS_AudioBlockSizeZero "Audio block size is zero, setting to %d!\n"
+#define MSGTR_MPDEMUX_AIOSS_AudioBlockSize2Low "Audio block size too low, setting to %d!\n"
+
+// asf_mmst_streaming.c
+#define MSGTR_MPDEMUX_MMST_WriteError "write error\n"
+#define MSGTR_MPDEMUX_MMST_EOFAlert "\nAlert! EOF\n"
+#define MSGTR_MPDEMUX_MMST_PreHeaderReadFailed "pre-header read failed\n"
+#define MSGTR_MPDEMUX_MMST_InvalidHeaderSize "Invalid header size, giving up.\n"
+#define MSGTR_MPDEMUX_MMST_HeaderDataReadFailed "Header data read failed.\n"
+#define MSGTR_MPDEMUX_MMST_packet_lenReadFailed "packet_len read failed.\n"
+#define MSGTR_MPDEMUX_MMST_InvalidRTSPPacketSize "Invalid RTSP packet size, giving up.\n"
+#define MSGTR_MPDEMUX_MMST_CmdDataReadFailed "Command data read failed.\n"
+#define MSGTR_MPDEMUX_MMST_HeaderObject "header object\n"
+#define MSGTR_MPDEMUX_MMST_DataObject "data object\n"
+#define MSGTR_MPDEMUX_MMST_FileObjectPacketLen "file object, packet length = %d (%d)\n"
+#define MSGTR_MPDEMUX_MMST_StreamObjectStreamID "stream object, stream ID: %d\n"
+#define MSGTR_MPDEMUX_MMST_2ManyStreamID "Too many IDs, stream skipped."
+#define MSGTR_MPDEMUX_MMST_UnknownObject "unknown object\n"
+#define MSGTR_MPDEMUX_MMST_MediaDataReadFailed "Media data read failed.\n"
+#define MSGTR_MPDEMUX_MMST_MissingSignature "missing signature\n"
+#define MSGTR_MPDEMUX_MMST_PatentedTechnologyJoke "Everything done. Thank you for downloading a media file containing proprietary and patented technology.\n"
+#define MSGTR_MPDEMUX_MMST_UnknownCmd "unknown command %02x\n"
+#define MSGTR_MPDEMUX_MMST_GetMediaPacketErr "get_media_packet error : %s\n"
+#define MSGTR_MPDEMUX_MMST_Connected "Connected\n"
+
+// asf_streaming.c
+#define MSGTR_MPDEMUX_ASF_StreamChunkSize2Small "Ahhhh, stream_chunck size is too small: %d\n"
+#define MSGTR_MPDEMUX_ASF_SizeConfirmMismatch "size_confirm mismatch!: %d %d\n"
+#define MSGTR_MPDEMUX_ASF_WarnDropHeader "Warning: drop header ????\n"
+#define MSGTR_MPDEMUX_ASF_ErrorParsingChunkHeader "Error while parsing chunk header\n"
+#define MSGTR_MPDEMUX_ASF_NoHeaderAtFirstChunk "Didn't get a header as first chunk !!!!\n"
+#define MSGTR_MPDEMUX_ASF_BufferMallocFailed "Error: Can't allocate %d bytes buffer.\n"
+#define MSGTR_MPDEMUX_ASF_ErrReadingNetworkStream "Error while reading network stream.\n"
+#define MSGTR_MPDEMUX_ASF_ErrChunk2Small "Error: Chunk is too small.\n"
+#define MSGTR_MPDEMUX_ASF_ErrSubChunkNumberInvalid "Error: Subchunk number is invalid.\n"
+#define MSGTR_MPDEMUX_ASF_Bandwidth2SmallCannotPlay "Bandwidth too small, file cannot be played!\n"
+#define MSGTR_MPDEMUX_ASF_Bandwidth2SmallDeselectedAudio "Bandwidth too small, deselected audio stream.\n"
+#define MSGTR_MPDEMUX_ASF_Bandwidth2SmallDeselectedVideo "Bandwidth too small, deselected video stream.\n"
+#define MSGTR_MPDEMUX_ASF_InvalidLenInHeader "Invalid length in ASF header!\n"
+#define MSGTR_MPDEMUX_ASF_ErrReadingChunkHeader "Error while reading chunk header.\n"
+#define MSGTR_MPDEMUX_ASF_ErrChunkBiggerThanPacket "Error: chunk_size > packet_size\n"
+#define MSGTR_MPDEMUX_ASF_ErrReadingChunk "Error while reading chunk.\n"
+#define MSGTR_MPDEMUX_ASF_ASFRedirector "=====> ASF Redirector\n"
+#define MSGTR_MPDEMUX_ASF_InvalidProxyURL "invalid proxy URL\n"
+#define MSGTR_MPDEMUX_ASF_UnknownASFStreamType "unknown ASF stream type\n"
+#define MSGTR_MPDEMUX_ASF_Failed2ParseHTTPResponse "Failed to parse HTTP response.\n"
+#define MSGTR_MPDEMUX_ASF_ServerReturn "Server returned %d:%s\n"
+#define MSGTR_MPDEMUX_ASF_ASFHTTPParseWarnCuttedPragma "ASF HTTP PARSE WARNING : Pragma %s cut from %zu bytes to %zu\n"
+#define MSGTR_MPDEMUX_ASF_SocketWriteError "socket write error: %s\n"
+#define MSGTR_MPDEMUX_ASF_HeaderParseFailed "Failed to parse header.\n"
+#define MSGTR_MPDEMUX_ASF_NoStreamFound "No stream found.\n"
+#define MSGTR_MPDEMUX_ASF_UnknownASFStreamingType "unknown ASF streaming type\n"
+#define MSGTR_MPDEMUX_ASF_InfoStreamASFURL "STREAM_ASF, URL: %s\n"
+#define MSGTR_MPDEMUX_ASF_StreamingFailed "Failed, exiting.\n"
+
+// audio_in.c
+#define MSGTR_MPDEMUX_AUDIOIN_ErrReadingAudio "\nError reading audio: %s\n"
+#define MSGTR_MPDEMUX_AUDIOIN_XRUNSomeFramesMayBeLeftOut "Recovered from cross-run, some frames may be left out!\n"
+#define MSGTR_MPDEMUX_AUDIOIN_ErrFatalCannotRecover "Fatal error, cannot recover!\n"
+#define MSGTR_MPDEMUX_AUDIOIN_NotEnoughSamples "\nNot enough audio samples!\n"
+
+// cache2.c
+#define MSGTR_MPDEMUX_CACHE2_NonCacheableStream "\rThis stream is non-cacheable.\n"
+#define MSGTR_MPDEMUX_CACHE2_ReadFileposDiffers "!!! read_filepos differs!!! Report this bug...\n"
+
+// network.c
+#define MSGTR_MPDEMUX_NW_UnknownAF "Unknown address family %d\n"
+#define MSGTR_MPDEMUX_NW_ResolvingHostForAF "Resolving %s for %s...\n"
+#define MSGTR_MPDEMUX_NW_CantResolv "Couldn't resolve name for %s: %s\n"
+#define MSGTR_MPDEMUX_NW_ConnectingToServer "Connecting to server %s[%s]: %d...\n"
+#define MSGTR_MPDEMUX_NW_CantConnect2Server "Failed to connect to server with %s\n"
+#define MSGTR_MPDEMUX_NW_SelectFailed "Select failed.\n"
+#define MSGTR_MPDEMUX_NW_ConnTimeout "connection timeout\n"
+#define MSGTR_MPDEMUX_NW_GetSockOptFailed "getsockopt failed: %s\n"
+#define MSGTR_MPDEMUX_NW_ConnectError "connect error: %s\n"
+#define MSGTR_MPDEMUX_NW_InvalidProxySettingTryingWithout "Invalid proxy setting... Trying without proxy.\n"
+#define MSGTR_MPDEMUX_NW_CantResolvTryingWithoutProxy "Could not resolve remote hostname for AF_INET. Trying without proxy.\n"
+#define MSGTR_MPDEMUX_NW_ErrSendingHTTPRequest "Error while sending HTTP request: Didn't send all the request.\n"
+#define MSGTR_MPDEMUX_NW_ReadFailed "Read failed.\n"
+#define MSGTR_MPDEMUX_NW_Read0CouldBeEOF "http_read_response read 0 (i.e. EOF).\n"
+#define MSGTR_MPDEMUX_NW_AuthFailed "Authentication failed. Please use the -user and -passwd options to provide your\n"\
+"username/password for a list of URLs, or form an URL like:\n"\
+"http://username:password@hostname/file\n"
+#define MSGTR_MPDEMUX_NW_AuthRequiredFor "Authentication required for %s\n"
+#define MSGTR_MPDEMUX_NW_AuthRequired "Authentication required.\n"
+#define MSGTR_MPDEMUX_NW_NoPasswdProvidedTryingBlank "No password provided, trying blank password.\n"
+#define MSGTR_MPDEMUX_NW_ErrServerReturned "Server returns %d: %s\n"
+#define MSGTR_MPDEMUX_NW_CacheSizeSetTo "Cache size set to %d KBytes\n"
+
+// open.c, stream.c:
+#define MSGTR_CdDevNotfound "CD-ROM Device '%s' not found.\n"
+#define MSGTR_ErrTrackSelect "Error selecting VCD track."
+#define MSGTR_ReadSTDIN "Reading from stdin...\n"
+#define MSGTR_UnableOpenURL "Unable to open URL: %s\n"
+#define MSGTR_ConnToServer "Connected to server: %s\n"
+#define MSGTR_FileNotFound "File not found: '%s'\n"
+
+#define MSGTR_SMBInitError "Cannot init the libsmbclient library: %d\n"
+#define MSGTR_SMBFileNotFound "Could not open from LAN: '%s'\n"
+#define MSGTR_SMBNotCompiled "MPlayer was not compiled with SMB reading support.\n"
+
+#define MSGTR_CantOpenBluray "Couldn't open Blu-ray device: %s\n"
+#define MSGTR_CantOpenDVD "Couldn't open DVD device: %s (%s)\n"
+
+#define MSGTR_URLParsingFailed "URL parsing failed on url %s\n"
+#define MSGTR_FailedSetStreamOption "Failed to set stream option %s=%s\n"
+#define MSGTR_StreamNeedType "Streams need a type!\n"
+#define MSGTR_StreamProtocolNULL "Stream type %s has protocols == NULL, it's a bug\n"
+#define MSGTR_StreamCantHandleURL "No stream found to handle url %s\n"
+#define MSGTR_StreamNULLFilename "open_output_stream(), NULL filename, report this bug\n"
+#define MSGTR_StreamErrorWritingCapture "Error writing capture file: %s\n"
+#define MSGTR_StreamSeekFailed "Seek failed\n"
+#define MSGTR_StreamNotSeekable "Stream not seekable!\n"
+#define MSGTR_StreamCannotSeekBackward "Cannot seek backward in linear streams!\n"
+
+// stream_cdda.c
+#define MSGTR_MPDEMUX_CDDA_CantOpenCDDADevice "Can't open CDDA device.\n"
+#define MSGTR_MPDEMUX_CDDA_CantOpenDisc "Can't open disc.\n"
+#define MSGTR_MPDEMUX_CDDA_AudioCDFoundWithNTracks "Found audio CD with %d tracks.\n"
+
+// stream_cddb.c
+#define MSGTR_MPDEMUX_CDDB_FailedToReadTOC "Failed to read TOC.\n"
+#define MSGTR_MPDEMUX_CDDB_FailedToOpenDevice "Failed to open %s device.\n"
+#define MSGTR_MPDEMUX_CDDB_NotAValidURL "not a valid URL\n"
+#define MSGTR_MPDEMUX_CDDB_FailedToSendHTTPRequest "Failed to send the HTTP request.\n"
+#define MSGTR_MPDEMUX_CDDB_FailedToReadHTTPResponse "Failed to read the HTTP response.\n"
+#define MSGTR_MPDEMUX_CDDB_HTTPErrorNOTFOUND "Not Found.\n"
+#define MSGTR_MPDEMUX_CDDB_HTTPErrorUnknown "unknown error code\n"
+#define MSGTR_MPDEMUX_CDDB_NoCacheFound "No cache found.\n"
+#define MSGTR_MPDEMUX_CDDB_NotAllXMCDFileHasBeenRead "Not all the xmcd file has been read.\n"
+#define MSGTR_MPDEMUX_CDDB_FailedToCreateDirectory "Failed to create directory %s.\n"
+#define MSGTR_MPDEMUX_CDDB_NotAllXMCDFileHasBeenWritten "Not all of the xmcd file has been written.\n"
+#define MSGTR_MPDEMUX_CDDB_InvalidXMCDDatabaseReturned "Invalid xmcd database file returned.\n"
+#define MSGTR_MPDEMUX_CDDB_UnexpectedFIXME "unexpected FIXME\n"
+#define MSGTR_MPDEMUX_CDDB_UnhandledCode "unhandled code\n"
+#define MSGTR_MPDEMUX_CDDB_UnableToFindEOL "Unable to find end of line.\n"
+#define MSGTR_MPDEMUX_CDDB_ParseOKFoundAlbumTitle "Parse OK, found: %s\n"
+#define MSGTR_MPDEMUX_CDDB_AlbumNotFound "Album not found.\n"
+#define MSGTR_MPDEMUX_CDDB_ServerReturnsCommandSyntaxErr "Server returns: Command syntax error\n"
+#define MSGTR_MPDEMUX_CDDB_NoSitesInfoAvailable "No sites information available.\n"
+#define MSGTR_MPDEMUX_CDDB_FailedToGetProtocolLevel "Failed to get the protocol level.\n"
+#define MSGTR_MPDEMUX_CDDB_NoCDInDrive "No CD in the drive.\n"
+
+// stream_cue.c
+#define MSGTR_MPDEMUX_CUEREAD_UnexpectedCuefileLine "[bincue] Unexpected cuefile line: %s\n"
+#define MSGTR_MPDEMUX_CUEREAD_BinFilenameTested "[bincue] bin filename tested: %s\n"
+#define MSGTR_MPDEMUX_CUEREAD_CannotFindBinFile "[bincue] Couldn't find the bin file - giving up.\n"
+#define MSGTR_MPDEMUX_CUEREAD_UsingBinFile "[bincue] Using bin file %s.\n"
+#define MSGTR_MPDEMUX_CUEREAD_UnknownModeForBinfile "[bincue] unknown mode for binfile. Should not happen. Aborting.\n"
+#define MSGTR_MPDEMUX_CUEREAD_CannotOpenCueFile "[bincue] Cannot open %s.\n"
+#define MSGTR_MPDEMUX_CUEREAD_ErrReadingFromCueFile "[bincue] Error reading from %s\n"
+#define MSGTR_MPDEMUX_CUEREAD_ErrGettingBinFileSize "[bincue] Error getting size of bin file.\n"
+#define MSGTR_MPDEMUX_CUEREAD_InfoTrackFormat "track %02d: format=%d %02d:%02d:%02d\n"
+#define MSGTR_MPDEMUX_CUEREAD_UnexpectedBinFileEOF "[bincue] unexpected end of bin file\n"
+#define MSGTR_MPDEMUX_CUEREAD_CannotReadNBytesOfPayload "[bincue] Couldn't read %d bytes of payload.\n"
+#define MSGTR_MPDEMUX_CUEREAD_CueStreamInfo_FilenameTrackTracksavail "CUE stream_open, filename=%s, track=%d, available tracks: %d -> %d\n"
+
+// stream_dvd.c
+#define MSGTR_DVDspeedCantOpen "Couldn't open DVD device for writing, changing DVD speed needs write access.\n"
+#define MSGTR_DVDrestoreSpeed "Restoring DVD speed... "
+#define MSGTR_DVDlimitSpeed "Limiting DVD speed to %dKB/s... "
+#define MSGTR_DVDlimitFail "failed\n"
+#define MSGTR_DVDlimitOk "successful\n"
+#define MSGTR_NoDVDSupport "MPlayer was compiled without DVD support, exiting.\n"
+#define MSGTR_DVDnumTitles "There are %d titles on this DVD.\n"
+#define MSGTR_DVDinvalidTitle "Invalid DVD title number: %d\n"
+#define MSGTR_DVDnumChapters "There are %d chapters in this DVD title.\n"
+#define MSGTR_DVDinvalidChapter "Invalid DVD chapter number: %d\n"
+#define MSGTR_DVDinvalidChapterRange "Invalid chapter range specification %s\n"
+#define MSGTR_DVDinvalidLastChapter "Invalid DVD last chapter number: %d\n"
+#define MSGTR_DVDnumAngles "There are %d angles in this DVD title.\n"
+#define MSGTR_DVDinvalidAngle "Invalid DVD angle number: %d\n"
+#define MSGTR_DVDnoIFO "Cannot open the IFO file for DVD title %d.\n"
+#define MSGTR_DVDnoVMG "Can't open VMG info!\n"
+#define MSGTR_DVDnoVOBs "Cannot open title VOBS (VTS_%02d_1.VOB).\n"
+#define MSGTR_DVDnoMatchingAudio "No matching DVD audio language found!\n"
+#define MSGTR_DVDaudioChannel "Selected DVD audio channel: %d language: %c%c\n"
+#define MSGTR_DVDaudioStreamInfo "audio stream: %d format: %s (%s) language: %s aid: %d.\n"
+#define MSGTR_DVDnumAudioChannels "number of audio channels on disk: %d.\n"
+#define MSGTR_DVDnoMatchingSubtitle "No matching DVD subtitle language found!\n"
+#define MSGTR_DVDsubtitleChannel "Selected DVD subtitle channel: %d language: %c%c\n"
+#define MSGTR_DVDsubtitleLanguage "subtitle ( sid ): %d language: %s\n"
+#define MSGTR_DVDnumSubtitles "number of subtitles on disk: %d\n"
+
+// stream_bluray.c
+#define MSGTR_BlurayNoDevice "No Blu-ray device/location was specified ...\n"
+#define MSGTR_BlurayNoTitles "Can't find any Blu-ray-compatible title here.\n"
+
+// stream_radio.c
+#define MSGTR_RADIO_ChannelNamesDetected "[radio] Radio channel names detected.\n"
+#define MSGTR_RADIO_WrongFreqForChannel "[radio] Wrong frequency for channel %s\n"
+#define MSGTR_RADIO_WrongChannelNumberFloat "[radio] Wrong channel number: %.2f\n"
+#define MSGTR_RADIO_WrongChannelNumberInt "[radio] Wrong channel number: %d\n"
+#define MSGTR_RADIO_WrongChannelName "[radio] Wrong channel name: %s\n"
+#define MSGTR_RADIO_FreqParameterDetected "[radio] Radio frequency parameter detected.\n"
+#define MSGTR_RADIO_GetTunerFailed "[radio] Warning: ioctl get tuner failed: %s. Setting frac to %d.\n"
+#define MSGTR_RADIO_NotRadioDevice "[radio] %s is no radio device!\n"
+#define MSGTR_RADIO_SetFreqFailed "[radio] ioctl set frequency 0x%x (%.2f) failed: %s\n"
+#define MSGTR_RADIO_GetFreqFailed "[radio] ioctl get frequency failed: %s\n"
+#define MSGTR_RADIO_SetMuteFailed "[radio] ioctl set mute failed: %s\n"
+#define MSGTR_RADIO_QueryControlFailed "[radio] ioctl query control failed: %s\n"
+#define MSGTR_RADIO_GetVolumeFailed "[radio] ioctl get volume failed: %s\n"
+#define MSGTR_RADIO_SetVolumeFailed "[radio] ioctl set volume failed: %s\n"
+#define MSGTR_RADIO_DroppingFrame "\n[radio] too bad - dropping audio frame (%d bytes)!\n"
+#define MSGTR_RADIO_BufferEmpty "[radio] grab_audio_frame: buffer empty, waiting for %d data bytes.\n"
+#define MSGTR_RADIO_AudioInitFailed "[radio] audio_in_init failed: %s\n"
+#define MSGTR_RADIO_AllocateBufferFailed "[radio] cannot allocate audio buffer (block=%d,buf=%d): %s\n"
+#define MSGTR_RADIO_CurrentFreq "[radio] Current frequency: %.2f\n"
+#define MSGTR_RADIO_SelectedChannel "[radio] Selected channel: %d - %s (freq: %.2f)\n"
+#define MSGTR_RADIO_ChangeChannelNoChannelList "[radio] Can not change channel: no channel list given.\n"
+#define MSGTR_RADIO_UnableOpenDevice "[radio] Unable to open '%s': %s\n"
+#define MSGTR_RADIO_InitFracFailed "[radio] init_frac failed.\n"
+#define MSGTR_RADIO_WrongFreq "[radio] Wrong frequency: %.2f\n"
+#define MSGTR_RADIO_UsingFreq "[radio] Using frequency: %.2f.\n"
+#define MSGTR_RADIO_AudioInInitFailed "[radio] audio_in_init failed.\n"
+#define MSGTR_RADIO_AudioInSetupFailed "[radio] audio_in_setup call failed: %s\n"
+#define MSGTR_RADIO_ClearBufferFailed "[radio] Clearing buffer failed: %s\n"
+#define MSGTR_RADIO_StreamEnableCacheFailed "[radio] Call to stream_enable_cache failed: %s\n"
+#define MSGTR_RADIO_DriverUnknownStr "[radio] Unknown driver name: %s\n"
+#define MSGTR_RADIO_DriverV4L2 "[radio] Using V4Lv2 radio interface.\n"
+#define MSGTR_RADIO_DriverV4L "[radio] Using V4Lv1 radio interface.\n"
+#define MSGTR_RADIO_DriverBSDBT848 "[radio] Using *BSD BT848 radio interface.\n"
+
+//tv.c
+#define MSGTR_TV_BogusNormParameter "tv.c: norm_from_string(%s): Bogus norm parameter, setting %s.\n"
+#define MSGTR_TV_NoVideoInputPresent "Error: No video input present!\n"
+#define MSGTR_TV_UnknownImageFormat ""\
+"==================================================================\n"\
+" WARNING: UNTESTED OR UNKNOWN OUTPUT IMAGE FORMAT REQUESTED (0x%x)\n"\
+" This may cause buggy playback or program crash! Bug reports will\n"\
+" be ignored! You should try again with YV12 (which is the default\n"\
+" colorspace) and read the documentation!\n"\
+"==================================================================\n"
+#define MSGTR_TV_CannotSetNorm "Error: Cannot set norm!\n"
+#define MSGTR_TV_MJP_WidthHeight " MJP: width %d height %d\n"
+#define MSGTR_TV_UnableToSetWidth "Unable to set requested width: %d\n"
+#define MSGTR_TV_UnableToSetHeight "Unable to set requested height: %d\n"
+#define MSGTR_TV_NoTuner "Selected input hasn't got a tuner!\n"
+#define MSGTR_TV_UnableFindChanlist "Unable to find selected channel list! (%s)\n"
+#define MSGTR_TV_ChannelFreqParamConflict "You can't set frequency and channel simultaneously!\n"
+#define MSGTR_TV_ChannelNamesDetected "TV channel names detected.\n"
+#define MSGTR_TV_NoFreqForChannel "Couldn't find frequency for channel %s (%s)\n"
+#define MSGTR_TV_SelectedChannel3 "Selected channel: %s - %s (freq: %.3f)\n"
+#define MSGTR_TV_SelectedChannel2 "Selected channel: %s (freq: %.3f)\n"
+#define MSGTR_TV_UnsupportedAudioType "Audio type '%s (%x)' unsupported!\n"
+#define MSGTR_TV_AvailableDrivers "Available drivers:\n"
+#define MSGTR_TV_DriverInfo "Selected driver: %s\n name: %s\n author: %s\n comment: %s\n"
+#define MSGTR_TV_NoSuchDriver "No such driver: %s\n"
+#define MSGTR_TV_DriverAutoDetectionFailed "TV driver autodetection failed.\n"
+#define MSGTR_TV_UnknownColorOption "Unknown color option (%d) specified!\n"
+#define MSGTR_TV_NoTeletext "No teletext"
+#define MSGTR_TV_Bt848IoctlFailed "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n"
+#define MSGTR_TV_Bt848InvalidAudioRate "tvi_bsdbt848: Invalid audio rate. Error: %s\n"
+#define MSGTR_TV_Bt848ErrorOpeningBktrDev "tvi_bsdbt848: Unable to open bktr device. Error: %s\n"
+#define MSGTR_TV_Bt848ErrorOpeningTunerDev "tvi_bsdbt848: Unable to open tuner device. Error: %s\n"
+#define MSGTR_TV_Bt848ErrorOpeningDspDev "tvi_bsdbt848: Unable to open dsp device. Error: %s\n"
+#define MSGTR_TV_Bt848ErrorConfiguringDsp "tvi_bsdbt848: Configuration of dsp failed. Error: %s\n"
+#define MSGTR_TV_Bt848ErrorReadingAudio "tvi_bsdbt848: Error reading audio data. Error: %s\n"
+#define MSGTR_TV_Bt848MmapFailed "tvi_bsdbt848: mmap failed. Error: %s\n"
+#define MSGTR_TV_Bt848FrameBufAllocFailed "tvi_bsdbt848: Frame buffer allocation failed. Error: %s\n"
+#define MSGTR_TV_Bt848ErrorSettingWidth "tvi_bsdbt848: Error setting picture width. Error: %s\n"
+#define MSGTR_TV_Bt848ErrorSettingHeight "tvi_bsdbt848: Error setting picture height. Error: %s\n"
+#define MSGTR_TV_Bt848UnableToStopCapture "tvi_bsdbt848: Unable to stop capture. Error: %s\n"
+#define MSGTR_TV_TTSupportedLanguages "Supported Teletext languages:\n"
+#define MSGTR_TV_TTSelectedLanguage "Selected default teletext language: %s\n"
+#define MSGTR_TV_ScannerNotAvailableWithoutTuner "Channel scanner is not available without tuner\n"
+
+//tvi_dshow.c
+#define MSGTR_TVI_DS_UnableConnectInputVideoDecoder "Unable to connect given input to video decoder. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableConnectInputAudioDecoder "Unable to connect given input to audio decoder. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableSelectVideoFormat "tvi_dshow: Unable to select video format. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableSelectAudioFormat "tvi_dshow: Unable to select audio format. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableGetMediaControlInterface "tvi_dshow: Unable to get IMediaControl interface. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableStartGraph "tvi_dshow: Unable to start graph! Error:0x%x\n"
+#define MSGTR_TVI_DS_DeviceNotFound "tvi_dshow: Device #%d not found\n"
+#define MSGTR_TVI_DS_UnableGetDeviceName "tvi_dshow: Unable to get name for device #%d\n"
+#define MSGTR_TVI_DS_UsingDevice "tvi_dshow: Using device #%d: %s\n"
+#define MSGTR_TVI_DS_DirectGetFreqFailed "tvi_dshow: Unable to get frequency directly. OS built-in channels table will be used.\n"
+#define MSGTR_TVI_DS_UnableExtractFreqTable "tvi_dshow: Unable to load frequency table from kstvtune.ax\n"
+#define MSGTR_TVI_DS_WrongDeviceParam "tvi_dshow: Wrong device parameter: %s\n"
+#define MSGTR_TVI_DS_WrongDeviceIndex "tvi_dshow: Wrong device index: %d\n"
+#define MSGTR_TVI_DS_WrongADeviceParam "tvi_dshow: Wrong adevice parameter: %s\n"
+#define MSGTR_TVI_DS_WrongADeviceIndex "tvi_dshow: Wrong adevice index: %d\n"
+
+#define MSGTR_TVI_DS_SamplerateNotsupported "tvi_dshow: Samplerate %d is not supported by device. Failing back to first available.\n"
+#define MSGTR_TVI_DS_VideoAdjustigNotSupported "tvi_dshow: Adjusting of brightness/hue/saturation/contrast is not supported by device\n"
+
+#define MSGTR_TVI_DS_ChangingWidthHeightNotSupported "tvi_dshow: Changing video width/height is not supported by device.\n"
+#define MSGTR_TVI_DS_SelectingInputNotSupported "tvi_dshow: Selection of capture source is not supported by device\n"
+#define MSGTR_TVI_DS_ErrorParsingAudioFormatStruct "tvi_dshow: Unable to parse audio format structure.\n"
+#define MSGTR_TVI_DS_ErrorParsingVideoFormatStruct "tvi_dshow: Unable to parse video format structure.\n"
+#define MSGTR_TVI_DS_UnableSetAudioMode "tvi_dshow: Unable to set audio mode %d. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnsupportedMediaType "tvi_dshow: Unsupported media type passed to %s\n"
+#define MSGTR_TVI_DS_UnableGetsupportedVideoFormats "tvi_dshow: Unable to get supported media formats from video pin. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableGetsupportedAudioFormats "tvi_dshow: Unable to get supported media formats from audio pin. Error:0x%x Disabling audio.\n"
+#define MSGTR_TVI_DS_UnableFindNearestChannel "tvi_dshow: Unable to find nearest channel in system frequency table\n"
+#define MSGTR_TVI_DS_UnableToSetChannel "tvi_dshow: Unable to switch to nearest channel from system frequency table. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableTerminateVPPin "tvi_dshow: Unable to terminate VideoPort pin with any filter in graph. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableBuildVideoSubGraph "tvi_dshow: Unable to build video chain of capture graph. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableBuildAudioSubGraph "tvi_dshow: Unable to build audio chain of capture graph. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableBuildVBISubGraph "tvi_dshow: Unable to build VBI chain of capture graph. Error:0x%x\n"
+#define MSGTR_TVI_DS_GraphInitFailure "tvi_dshow: Directshow graph initialization failure.\n"
+#define MSGTR_TVI_DS_NoVideoCaptureDevice "tvi_dshow: Unable to find video capture device\n"
+#define MSGTR_TVI_DS_NoAudioCaptureDevice "tvi_dshow: Unable to find audio capture device\n"
+#define MSGTR_TVI_DS_GetActualMediatypeFailed "tvi_dshow: Unable to get actual mediatype (Error:0x%x). Assuming equal to requested.\n"
+
+// url.c
+#define MSGTR_MPDEMUX_URL_StringAlreadyEscaped "String appears to be already escaped in url_escape %c%c1%c2\n"
+
+// subtitles
+#define MSGTR_SUBTITLES_SubRip_UnknownFontColor "SubRip: unknown font color in subtitle: %s\n"
+
+
+/* untranslated messages from the English master file */
+
+
+#endif /* MPLAYER_HELP_MP_H */
diff --git a/libavfilter/libmpcodecs/img_format.c b/libavfilter/libmpcodecs/img_format.c
new file mode 100644
index 0000000..61bf898
--- /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
--- /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
--- /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
--- /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
--- /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
--- /dev/null
+++ b/libavfilter/libmpcodecs/mp_image.h
@@ -0,0 +1,159 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_MP_IMAGE_H
+#define MPLAYER_MP_IMAGE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#undef printf //FIXME
+#undef fprintf //FIXME
+#include "mp_msg.h"
+#include "libavutil/avutil.h"
+#include "libavutil/avassert.h"
+#undef realloc
+#undef malloc
+#undef free
+#undef rand
+#undef srand
+#undef printf
+#undef strncpy
+#define ASMALIGN(ZEROBITS) ".p2align " #ZEROBITS "\n\t"
+#define CODEC_FLAG2_MEMC_ONLY 0x00001000 ///< Only do ME/MC (I frames -> ref, P frame -> ME+MC).
+
+enum AVPixelFormat ff_mp2ff_pix_fmt(int mp);
+
+//--------- codec's requirements (filled by the codec/vf) ---------
+
+//--- buffer content restrictions:
+// set if buffer content shouldn't be modified:
+#define MP_IMGFLAG_PRESERVE 0x01
+// set if buffer content will be READ.
+// This can be e.g. for next frame's MC: (I/P mpeg frames) -
+// then in combination with MP_IMGFLAG_PRESERVE - or it
+// can be because a video filter or codec will read a significant
+// amount of data while processing that frame (e.g. blending something
+// onto the frame, MV based intra prediction).
+// A frame marked like this should not be placed in to uncachable
+// video RAM for example.
+#define MP_IMGFLAG_READABLE 0x02
+
+//--- buffer width/stride/plane restrictions: (used for direct rendering)
+// stride _have_to_ be aligned to MB boundary: [for DR restrictions]
+#define MP_IMGFLAG_ACCEPT_ALIGNED_STRIDE 0x4
+// stride should be aligned to MB boundary: [for buffer allocation]
+#define MP_IMGFLAG_PREFER_ALIGNED_STRIDE 0x8
+// codec accept any stride (>=width):
+#define MP_IMGFLAG_ACCEPT_STRIDE 0x10
+// codec accept any width (width*bpp=stride -> stride%bpp==0) (>=width):
+#define MP_IMGFLAG_ACCEPT_WIDTH 0x20
+//--- for planar formats only:
+// uses only stride[0], and stride[1]=stride[2]=stride[0]>>mpi->chroma_x_shift
+#define MP_IMGFLAG_COMMON_STRIDE 0x40
+// uses only planes[0], and calculates planes[1,2] from width,height,imgfmt
+#define MP_IMGFLAG_COMMON_PLANE 0x80
+
+#define MP_IMGFLAGMASK_RESTRICTIONS 0xFF
+
+//--------- color info (filled by ff_mp_image_setfmt() ) -----------
+// set if number of planes > 1
+#define MP_IMGFLAG_PLANAR 0x100
+// set if it's YUV colorspace
+#define MP_IMGFLAG_YUV 0x200
+// set if it's swapped (BGR or YVU) plane/byteorder
+#define MP_IMGFLAG_SWAPPED 0x400
+// set if you want memory for palette allocated and managed by ff_vf_get_image etc.
+#define MP_IMGFLAG_RGB_PALETTE 0x800
+
+#define MP_IMGFLAGMASK_COLORS 0xF00
+
+// codec uses drawing/rendering callbacks (draw_slice()-like thing, DR method 2)
+// [the codec will set this flag if it supports callbacks, and the vo _may_
+// clear it in get_image() if draw_slice() not implemented]
+#define MP_IMGFLAG_DRAW_CALLBACK 0x1000
+// set if it's in video buffer/memory: [set by vo/vf's get_image() !!!]
+#define MP_IMGFLAG_DIRECT 0x2000
+// set if buffer is allocated (used in destination images):
+#define MP_IMGFLAG_ALLOCATED 0x4000
+
+// buffer type was printed (do NOT set this flag - it's for INTERNAL USE!!!)
+#define MP_IMGFLAG_TYPE_DISPLAYED 0x8000
+
+// codec doesn't support any form of direct rendering - it has own buffer
+// allocation. so we just export its buffer pointers:
+#define MP_IMGTYPE_EXPORT 0
+// codec requires a static WO buffer, but it does only partial updates later:
+#define MP_IMGTYPE_STATIC 1
+// codec just needs some WO memory, where it writes/copies the whole frame to:
+#define MP_IMGTYPE_TEMP 2
+// I+P type, requires 2+ independent static R/W buffers
+#define MP_IMGTYPE_IP 3
+// I+P+B type, requires 2+ independent static R/W and 1+ temp WO buffers
+#define MP_IMGTYPE_IPB 4
+// Upper 16 bits give desired buffer number, -1 means get next available
+#define MP_IMGTYPE_NUMBERED 5
+// Doesn't need any buffer, incomplete image (probably a first field only)
+// we need this type to be able to differentiate between half frames and
+// all other cases
+#define MP_IMGTYPE_INCOMPLETE 6
+
+#define MP_MAX_PLANES 4
+
+#define MP_IMGFIELD_ORDERED 0x01
+#define MP_IMGFIELD_TOP_FIRST 0x02
+#define MP_IMGFIELD_REPEAT_FIRST 0x04
+#define MP_IMGFIELD_TOP 0x08
+#define MP_IMGFIELD_BOTTOM 0x10
+#define MP_IMGFIELD_INTERLACED 0x20
+
+typedef struct mp_image {
+ unsigned int flags;
+ unsigned char type;
+ int number;
+ unsigned char bpp; // bits/pixel. NOT depth! for RGB it will be n*8
+ unsigned int imgfmt;
+ int width,height; // stored dimensions
+ int x,y,w,h; // visible dimensions
+ unsigned char* planes[MP_MAX_PLANES];
+ int stride[MP_MAX_PLANES];
+ char * qscale;
+ int qstride;
+ int pict_type; // 0->unknown, 1->I, 2->P, 3->B
+ int fields;
+ int qscale_type; // 0->mpeg1/4/h263, 1->mpeg2
+ int num_planes;
+ /* these are only used by planar formats Y,U(Cb),V(Cr) */
+ int chroma_width;
+ int chroma_height;
+ int chroma_x_shift; // horizontal
+ int chroma_y_shift; // vertical
+ int usage_count;
+ /* for private use by filter or vo driver (to store buffer id or dmpi) */
+ void* priv;
+} mp_image_t;
+
+void ff_mp_image_setfmt(mp_image_t* mpi,unsigned int out_fmt);
+mp_image_t* ff_new_mp_image(int w,int h);
+void ff_free_mp_image(mp_image_t* mpi);
+
+mp_image_t* ff_alloc_mpi(int w, int h, unsigned long int fmt);
+void ff_mp_image_alloc_planes(mp_image_t *mpi);
+void ff_copy_mpi(mp_image_t *dmpi, mp_image_t *mpi);
+
+#endif /* MPLAYER_MP_IMAGE_H */
diff --git a/libavfilter/libmpcodecs/mp_msg.h b/libavfilter/libmpcodecs/mp_msg.h
new file mode 100644
index 0000000..51cdff3
--- /dev/null
+++ b/libavfilter/libmpcodecs/mp_msg.h
@@ -0,0 +1,166 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_MP_MSG_H
+#define MPLAYER_MP_MSG_H
+
+#include <stdarg.h>
+
+// defined in mplayer.c and mencoder.c
+extern int verbose;
+
+// verbosity elevel:
+
+/* Only messages level MSGL_FATAL-MSGL_STATUS should be translated,
+ * messages level MSGL_V and above should not be translated. */
+
+#define MSGL_FATAL 0 // will exit/abort
+#define MSGL_ERR 1 // continues
+#define MSGL_WARN 2 // only warning
+#define MSGL_HINT 3 // short help message
+#define MSGL_INFO 4 // -quiet
+#define MSGL_STATUS 5 // v=0
+#define MSGL_V 6 // v=1
+#define MSGL_DBG2 7 // v=2
+#define MSGL_DBG3 8 // v=3
+#define MSGL_DBG4 9 // v=4
+#define MSGL_DBG5 10 // v=5
+
+#define MSGL_FIXME 1 // for conversions from printf where the appropriate MSGL is not known; set equal to ERR for obtrusiveness
+#define MSGT_FIXME 0 // for conversions from printf where the appropriate MSGT is not known; set equal to GLOBAL for obtrusiveness
+
+// code/module:
+
+#define MSGT_GLOBAL 0 // common player stuff errors
+#define MSGT_CPLAYER 1 // console player (mplayer.c)
+#define MSGT_GPLAYER 2 // gui player
+
+#define MSGT_VO 3 // libvo
+#define MSGT_AO 4 // libao
+
+#define MSGT_DEMUXER 5 // demuxer.c (general stuff)
+#define MSGT_DS 6 // demux stream (add/read packet etc)
+#define MSGT_DEMUX 7 // fileformat-specific stuff (demux_*.c)
+#define MSGT_HEADER 8 // fileformat-specific header (*header.c)
+
+#define MSGT_AVSYNC 9 // mplayer.c timer stuff
+#define MSGT_AUTOQ 10 // mplayer.c auto-quality stuff
+
+#define MSGT_CFGPARSER 11 // cfgparser.c
+
+#define MSGT_DECAUDIO 12 // av decoder
+#define MSGT_DECVIDEO 13
+
+#define MSGT_SEEK 14 // seeking code
+#define MSGT_WIN32 15 // win32 dll stuff
+#define MSGT_OPEN 16 // open.c (stream opening)
+#define MSGT_DVD 17 // open.c (DVD init/read/seek)
+
+#define MSGT_PARSEES 18 // parse_es.c (mpeg stream parser)
+#define MSGT_LIRC 19 // lirc_mp.c and input lirc driver
+
+#define MSGT_STREAM 20 // stream.c
+#define MSGT_CACHE 21 // cache2.c
+
+#define MSGT_MENCODER 22
+
+#define MSGT_XACODEC 23 // XAnim codecs
+
+#define MSGT_TV 24 // TV input subsystem
+
+#define MSGT_OSDEP 25 // OS-dependent parts
+
+#define MSGT_SPUDEC 26 // spudec.c
+
+#define MSGT_PLAYTREE 27 // Playtree handeling (playtree.c, playtreeparser.c)
+
+#define MSGT_INPUT 28
+
+#define MSGT_VFILTER 29
+
+#define MSGT_OSD 30
+
+#define MSGT_NETWORK 31
+
+#define MSGT_CPUDETECT 32
+
+#define MSGT_CODECCFG 33
+
+#define MSGT_SWS 34
+
+#define MSGT_VOBSUB 35
+#define MSGT_SUBREADER 36
+
+#define MSGT_AFILTER 37 // Audio filter messages
+
+#define MSGT_NETST 38 // Netstream
+
+#define MSGT_MUXER 39 // muxer layer
+
+#define MSGT_OSD_MENU 40
+
+#define MSGT_IDENTIFY 41 // -identify output
+
+#define MSGT_RADIO 42
+
+#define MSGT_ASS 43 // libass messages
+
+#define MSGT_LOADER 44 // dll loader messages
+
+#define MSGT_STATUSLINE 45 // playback/encoding status line
+
+#define MSGT_TELETEXT 46 // Teletext decoder
+
+#define MSGT_MAX 64
+
+
+extern char *ff_mp_msg_charset;
+extern int ff_mp_msg_color;
+extern int ff_mp_msg_module;
+
+extern int ff_mp_msg_levels[MSGT_MAX];
+extern int ff_mp_msg_level_all;
+
+
+void ff_mp_msg_init(void);
+int ff_mp_msg_test(int mod, int lev);
+
+#include "config.h"
+
+void ff_mp_msg_va(int mod, int lev, const char *format, va_list va);
+#ifdef __GNUC__
+void ff_mp_msg(int mod, int lev, const char *format, ... ) __attribute__ ((format (printf, 3, 4)));
+# ifdef MP_DEBUG
+# define mp_dbg(mod,lev, args... ) ff_mp_msg(mod, lev, ## args )
+# else
+ // only useful for developers, disable but check syntax
+# define mp_dbg(mod,lev, args... ) do { if (0) ff_mp_msg(mod, lev, ## args ); } while (0)
+# endif
+#else // not GNU C
+void ff_mp_msg(int mod, int lev, const char *format, ... );
+# ifdef MP_DEBUG
+# define mp_dbg(mod,lev, ... ) ff_mp_msg(mod, lev, __VA_ARGS__)
+# else
+ // only useful for developers, disable but check syntax
+# define mp_dbg(mod,lev, ... ) do { if (0) ff_mp_msg(mod, lev, __VA_ARGS__); } while (0)
+# endif
+#endif /* __GNUC__ */
+
+const char* ff_filename_recode(const char* filename);
+
+#endif /* MPLAYER_MP_MSG_H */
diff --git a/libavfilter/libmpcodecs/mpbswap.h b/libavfilter/libmpcodecs/mpbswap.h
new file mode 100644
index 0000000..28f7337
--- /dev/null
+++ b/libavfilter/libmpcodecs/mpbswap.h
@@ -0,0 +1,34 @@
+/*
+ * 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_MPBSWAP_H
+#define MPLAYER_MPBSWAP_H
+
+#include <sys/types.h>
+#include "config.h"
+#include "libavutil/bswap.h"
+
+#define bswap_16(v) av_bswap16(v)
+#define bswap_32(v) av_bswap32(v)
+#define le2me_16(v) av_le2ne16(v)
+#define le2me_32(v) av_le2ne32(v)
+#define le2me_64(v) av_le2ne64(v)
+#define be2me_16(v) av_be2ne16(v)
+#define be2me_32(v) av_be2ne32(v)
+
+#endif /* MPLAYER_MPBSWAP_H */
diff --git a/libavfilter/libmpcodecs/mpc_info.h b/libavfilter/libmpcodecs/mpc_info.h
new file mode 100644
index 0000000..8554699
--- /dev/null
+++ b/libavfilter/libmpcodecs/mpc_info.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_MPC_INFO_H
+#define MPLAYER_MPC_INFO_H
+
+typedef struct mp_codec_info_s
+{
+ /* codec long name ("Autodesk FLI/FLC Animation decoder" */
+ const char *name;
+ /* short name (same as driver name in codecs.conf) ("dshow") */
+ const char *short_name;
+ /* interface author/maintainer */
+ const char *maintainer;
+ /* codec author ("Aaron Holtzman <aholtzma@ess.engr.uvic.ca>") */
+ const char *author;
+ /* any additional comments */
+ const char *comment;
+} mp_codec_info_t;
+
+#define CONTROL_OK 1
+#define CONTROL_TRUE 1
+#define CONTROL_FALSE 0
+#define CONTROL_UNKNOWN -1
+#define CONTROL_ERROR -2
+#define CONTROL_NA -3
+
+#endif /* MPLAYER_MPC_INFO_H */
diff --git a/libavfilter/libmpcodecs/pullup.c b/libavfilter/libmpcodecs/pullup.c
new file mode 100644
index 0000000..b5fae9b
--- /dev/null
+++ b/libavfilter/libmpcodecs/pullup.c
@@ -0,0 +1,823 @@
+/*
+ * 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 "libavutil/x86/asm.h"
+#include "config.h"
+#include "pullup.h"
+
+
+
+#if ARCH_X86
+#if HAVE_MMX
+static int diff_y_mmx(unsigned char *a, unsigned char *b, int s)
+{
+ int ret;
+ __asm__ volatile (
+ "movl $4, %%ecx \n\t"
+ "pxor %%mm4, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+
+ "1: \n\t"
+
+ "movq (%%"REG_S"), %%mm0 \n\t"
+ "movq (%%"REG_S"), %%mm2 \n\t"
+ "add %%"REG_a", %%"REG_S" \n\t"
+ "movq (%%"REG_D"), %%mm1 \n\t"
+ "add %%"REG_a", %%"REG_D" \n\t"
+ "psubusb %%mm1, %%mm2 \n\t"
+ "psubusb %%mm0, %%mm1 \n\t"
+ "movq %%mm2, %%mm0 \n\t"
+ "movq %%mm1, %%mm3 \n\t"
+ "punpcklbw %%mm7, %%mm0 \n\t"
+ "punpcklbw %%mm7, %%mm1 \n\t"
+ "punpckhbw %%mm7, %%mm2 \n\t"
+ "punpckhbw %%mm7, %%mm3 \n\t"
+ "paddw %%mm0, %%mm4 \n\t"
+ "paddw %%mm1, %%mm4 \n\t"
+ "paddw %%mm2, %%mm4 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+
+ "decl %%ecx \n\t"
+ "jnz 1b \n\t"
+
+ "movq %%mm4, %%mm3 \n\t"
+ "punpcklwd %%mm7, %%mm4 \n\t"
+ "punpckhwd %%mm7, %%mm3 \n\t"
+ "paddd %%mm4, %%mm3 \n\t"
+ "movd %%mm3, %%eax \n\t"
+ "psrlq $32, %%mm3 \n\t"
+ "movd %%mm3, %%edx \n\t"
+ "addl %%edx, %%eax \n\t"
+ "emms \n\t"
+ : "=a" (ret)
+ : "S" (a), "D" (b), "a" (s)
+ : "%ecx", "%edx"
+ );
+ return ret;
+}
+
+static int licomb_y_mmx(unsigned char *a, unsigned char *b, int s)
+{
+ int ret;
+ __asm__ volatile (
+ "movl $4, %%ecx \n\t"
+ "pxor %%mm6, %%mm6 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ "sub %%"REG_a", %%"REG_D" \n\t"
+
+ "2: \n\t"
+
+ "movq (%%"REG_D"), %%mm0 \n\t"
+ "movq (%%"REG_D"), %%mm1 \n\t"
+ "punpcklbw %%mm7, %%mm0 \n\t"
+ "movq (%%"REG_D",%%"REG_a"), %%mm2 \n\t"
+ "punpcklbw %%mm7, %%mm1 \n\t"
+ "punpcklbw %%mm7, %%mm2 \n\t"
+ "paddw %%mm0, %%mm0 \n\t"
+ "paddw %%mm2, %%mm1 \n\t"
+ "movq %%mm0, %%mm2 \n\t"
+ "psubusw %%mm1, %%mm0 \n\t"
+ "psubusw %%mm2, %%mm1 \n\t"
+ "paddw %%mm0, %%mm6 \n\t"
+ "paddw %%mm1, %%mm6 \n\t"
+
+ "movq (%%"REG_S"), %%mm0 \n\t"
+ "movq (%%"REG_D"), %%mm1 \n\t"
+ "punpckhbw %%mm7, %%mm0 \n\t"
+ "movq (%%"REG_D",%%"REG_a"), %%mm2 \n\t"
+ "punpckhbw %%mm7, %%mm1 \n\t"
+ "punpckhbw %%mm7, %%mm2 \n\t"
+ "paddw %%mm0, %%mm0 \n\t"
+ "paddw %%mm2, %%mm1 \n\t"
+ "movq %%mm0, %%mm2 \n\t"
+ "psubusw %%mm1, %%mm0 \n\t"
+ "psubusw %%mm2, %%mm1 \n\t"
+ "paddw %%mm0, %%mm6 \n\t"
+ "paddw %%mm1, %%mm6 \n\t"
+
+ "movq (%%"REG_D",%%"REG_a"), %%mm0 \n\t"
+ "movq (%%"REG_S"), %%mm1 \n\t"
+ "punpcklbw %%mm7, %%mm0 \n\t"
+ "movq (%%"REG_S",%%"REG_a"), %%mm2 \n\t"
+ "punpcklbw %%mm7, %%mm1 \n\t"
+ "punpcklbw %%mm7, %%mm2 \n\t"
+ "paddw %%mm0, %%mm0 \n\t"
+ "paddw %%mm2, %%mm1 \n\t"
+ "movq %%mm0, %%mm2 \n\t"
+ "psubusw %%mm1, %%mm0 \n\t"
+ "psubusw %%mm2, %%mm1 \n\t"
+ "paddw %%mm0, %%mm6 \n\t"
+ "paddw %%mm1, %%mm6 \n\t"
+
+ "movq (%%"REG_D",%%"REG_a"), %%mm0 \n\t"
+ "movq (%%"REG_S"), %%mm1 \n\t"
+ "punpckhbw %%mm7, %%mm0 \n\t"
+ "movq (%%"REG_S",%%"REG_a"), %%mm2 \n\t"
+ "punpckhbw %%mm7, %%mm1 \n\t"
+ "punpckhbw %%mm7, %%mm2 \n\t"
+ "paddw %%mm0, %%mm0 \n\t"
+ "paddw %%mm2, %%mm1 \n\t"
+ "movq %%mm0, %%mm2 \n\t"
+ "psubusw %%mm1, %%mm0 \n\t"
+ "psubusw %%mm2, %%mm1 \n\t"
+ "paddw %%mm0, %%mm6 \n\t"
+ "paddw %%mm1, %%mm6 \n\t"
+
+ "add %%"REG_a", %%"REG_S" \n\t"
+ "add %%"REG_a", %%"REG_D" \n\t"
+ "decl %%ecx \n\t"
+ "jnz 2b \n\t"
+
+ "movq %%mm6, %%mm5 \n\t"
+ "punpcklwd %%mm7, %%mm6 \n\t"
+ "punpckhwd %%mm7, %%mm5 \n\t"
+ "paddd %%mm6, %%mm5 \n\t"
+ "movd %%mm5, %%eax \n\t"
+ "psrlq $32, %%mm5 \n\t"
+ "movd %%mm5, %%edx \n\t"
+ "addl %%edx, %%eax \n\t"
+
+ "emms \n\t"
+ : "=a" (ret)
+ : "S" (a), "D" (b), "a" (s)
+ : "%ecx", "%edx"
+ );
+ return ret;
+}
+
+static int var_y_mmx(unsigned char *a, unsigned char *b, int s)
+{
+ int ret;
+ __asm__ volatile (
+ "movl $3, %%ecx \n\t"
+ "pxor %%mm4, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+
+ "1: \n\t"
+
+ "movq (%%"REG_S"), %%mm0 \n\t"
+ "movq (%%"REG_S"), %%mm2 \n\t"
+ "movq (%%"REG_S",%%"REG_a"), %%mm1 \n\t"
+ "add %%"REG_a", %%"REG_S" \n\t"
+ "psubusb %%mm1, %%mm2 \n\t"
+ "psubusb %%mm0, %%mm1 \n\t"
+ "movq %%mm2, %%mm0 \n\t"
+ "movq %%mm1, %%mm3 \n\t"
+ "punpcklbw %%mm7, %%mm0 \n\t"
+ "punpcklbw %%mm7, %%mm1 \n\t"
+ "punpckhbw %%mm7, %%mm2 \n\t"
+ "punpckhbw %%mm7, %%mm3 \n\t"
+ "paddw %%mm0, %%mm4 \n\t"
+ "paddw %%mm1, %%mm4 \n\t"
+ "paddw %%mm2, %%mm4 \n\t"
+ "paddw %%mm3, %%mm4 \n\t"
+
+ "decl %%ecx \n\t"
+ "jnz 1b \n\t"
+
+ "movq %%mm4, %%mm3 \n\t"
+ "punpcklwd %%mm7, %%mm4 \n\t"
+ "punpckhwd %%mm7, %%mm3 \n\t"
+ "paddd %%mm4, %%mm3 \n\t"
+ "movd %%mm3, %%eax \n\t"
+ "psrlq $32, %%mm3 \n\t"
+ "movd %%mm3, %%edx \n\t"
+ "addl %%edx, %%eax \n\t"
+ "emms \n\t"
+ : "=a" (ret)
+ : "S" (a), "a" (s)
+ : "%ecx", "%edx"
+ );
+ return 4*ret;
+}
+#endif
+#endif
+
+#define ABS(a) (((a)^((a)>>31))-((a)>>31))
+
+static int diff_y(unsigned char *a, unsigned char *b, int s)
+{
+ int i, j, diff=0;
+ for (i=4; i; i--) {
+ for (j=0; j<8; j++) diff += ABS(a[j]-b[j]);
+ a+=s; b+=s;
+ }
+ return diff;
+}
+
+static int licomb_y(unsigned char *a, unsigned char *b, int s)
+{
+ int i, j, diff=0;
+ for (i=4; i; i--) {
+ for (j=0; j<8; j++)
+ diff += ABS((a[j]<<1) - b[j-s] - b[j])
+ + ABS((b[j]<<1) - a[j] - a[j+s]);
+ a+=s; b+=s;
+ }
+ return diff;
+}
+
+#if 0
+static int qpcomb_y(unsigned char *a, unsigned char *b, int s)
+{
+ int i, j, diff=0;
+ for (i=4; i; i--) {
+ for (j=0; j<8; j++)
+ diff += ABS(a[j] - 3*b[j-s] + 3*a[j+s] - b[j]);
+ a+=s; b+=s;
+ }
+ return diff;
+}
+
+static int licomb_y_test(unsigned char *a, unsigned char *b, int s)
+{
+ int c = licomb_y(a,b,s);
+ int m = licomb_y_mmx(a,b,s);
+ if (c != m) printf("%d != %d\n", c, m);
+ return m;
+}
+#endif
+
+static int var_y(unsigned char *a, unsigned char *b, int s)
+{
+ int i, j, var=0;
+ for (i=3; i; i--) {
+ for (j=0; j<8; j++) {
+ var += ABS(a[j]-a[j+s]);
+ }
+ a+=s; b+=s;
+ }
+ return 4*var; /* match comb scaling */
+}
+
+
+
+
+
+
+
+
+
+static void alloc_buffer(struct pullup_context *c, struct pullup_buffer *b)
+{
+ int i;
+ if (b->planes) return;
+ b->planes = calloc(c->nplanes, sizeof(unsigned char *));
+ for (i = 0; i < c->nplanes; i++) {
+ b->planes[i] = malloc(c->h[i]*c->stride[i]);
+ /* Deal with idiotic 128=0 for chroma: */
+ memset(b->planes[i], c->background[i], c->h[i]*c->stride[i]);
+ }
+}
+
+struct pullup_buffer *ff_pullup_lock_buffer(struct pullup_buffer *b, int parity)
+{
+ if (!b) return 0;
+ if ((parity+1) & 1) b->lock[0]++;
+ if ((parity+1) & 2) b->lock[1]++;
+ return b;
+}
+
+void ff_pullup_release_buffer(struct pullup_buffer *b, int parity)
+{
+ if (!b) return;
+ if ((parity+1) & 1) b->lock[0]--;
+ if ((parity+1) & 2) b->lock[1]--;
+}
+
+struct pullup_buffer *ff_pullup_get_buffer(struct pullup_context *c, int parity)
+{
+ int i;
+
+ /* Try first to get the sister buffer for the previous field */
+ if (parity < 2 && c->last && parity != c->last->parity
+ && !c->last->buffer->lock[parity]) {
+ alloc_buffer(c, c->last->buffer);
+ return ff_pullup_lock_buffer(c->last->buffer, parity);
+ }
+
+ /* Prefer a buffer with both fields open */
+ for (i = 0; i < c->nbuffers; i++) {
+ if (c->buffers[i].lock[0]) continue;
+ if (c->buffers[i].lock[1]) continue;
+ alloc_buffer(c, &c->buffers[i]);
+ return ff_pullup_lock_buffer(&c->buffers[i], parity);
+ }
+
+ if (parity == 2) return 0;
+
+ /* Search for any half-free buffer */
+ for (i = 0; i < c->nbuffers; i++) {
+ if (((parity+1) & 1) && c->buffers[i].lock[0]) continue;
+ if (((parity+1) & 2) && c->buffers[i].lock[1]) continue;
+ alloc_buffer(c, &c->buffers[i]);
+ return ff_pullup_lock_buffer(&c->buffers[i], parity);
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+static void compute_metric(struct pullup_context *c,
+ struct pullup_field *fa, int pa,
+ struct pullup_field *fb, int pb,
+ int (*func)(unsigned char *, unsigned char *, int), int *dest)
+{
+ unsigned char *a, *b;
+ int x, y;
+ int mp = c->metric_plane;
+ int xstep = c->bpp[mp];
+ int ystep = c->stride[mp]<<3;
+ int s = c->stride[mp]<<1; /* field stride */
+ int w = c->metric_w*xstep;
+
+ 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, c->metric_len * sizeof(int));
+ return;
+ }
+
+ a = fa->buffer->planes[mp] + pa * c->stride[mp] + c->metric_offset;
+ b = fb->buffer->planes[mp] + pb * c->stride[mp] + c->metric_offset;
+
+ for (y = c->metric_h; y; y--) {
+ for (x = 0; x < w; x += xstep) {
+ *dest++ = func(a + x, b + x, s);
+ }
+ a += ystep; b += ystep;
+ }
+}
+
+
+
+
+
+static void alloc_metrics(struct pullup_context *c, struct pullup_field *f)
+{
+ f->diffs = calloc(c->metric_len, sizeof(int));
+ f->comb = calloc(c->metric_len, sizeof(int));
+ f->var = calloc(c->metric_len, sizeof(int));
+ /* add more metrics here as needed */
+}
+
+static struct pullup_field *make_field_queue(struct pullup_context *c, int len)
+{
+ struct pullup_field *head, *f;
+ f = head = calloc(1, sizeof(struct pullup_field));
+ alloc_metrics(c, f);
+ for (; len > 0; len--) {
+ f->next = calloc(1, sizeof(struct pullup_field));
+ f->next->prev = f;
+ f = f->next;
+ alloc_metrics(c, f);
+ }
+ f->next = head;
+ head->prev = f;
+ return head;
+}
+
+static void check_field_queue(struct pullup_context *c)
+{
+ if (c->head->next == c->first) {
+ struct pullup_field *f = calloc(1, sizeof(struct pullup_field));
+ alloc_metrics(c, f);
+ f->prev = c->head;
+ f->next = c->first;
+ c->head->next = f;
+ c->first->prev = f;
+ }
+}
+
+void ff_pullup_submit_field(struct pullup_context *c, struct pullup_buffer *b, int parity)
+{
+ struct pullup_field *f;
+
+ /* Grow the circular list if needed */
+ check_field_queue(c);
+
+ /* Cannot have two fields of same parity in a row; drop the new one */
+ if (c->last && c->last->parity == parity) return;
+
+ f = c->head;
+ f->parity = parity;
+ f->buffer = ff_pullup_lock_buffer(b, parity);
+ f->flags = 0;
+ f->breaks = 0;
+ f->affinity = 0;
+
+ compute_metric(c, f, parity, f->prev->prev, parity, c->diff, f->diffs);
+ compute_metric(c, parity?f->prev:f, 0, parity?f:f->prev, 1, c->comb, f->comb);
+ compute_metric(c, f, parity, f, -1, c->var, f->var);
+
+ /* Advance the circular list */
+ if (!c->first) c->first = c->head;
+ c->last = c->head;
+ c->head = c->head->next;
+}
+
+void ff_pullup_flush_fields(struct pullup_context *c)
+{
+ struct pullup_field *f;
+
+ for (f = c->first; f && f != c->head; f = f->next) {
+ ff_pullup_release_buffer(f->buffer, f->parity);
+ f->buffer = 0;
+ }
+ c->first = c->last = 0;
+}
+
+
+
+
+
+
+
+
+#define F_HAVE_BREAKS 1
+#define F_HAVE_AFFINITY 2
+
+
+#define BREAK_LEFT 1
+#define BREAK_RIGHT 2
+
+
+
+
+static int queue_length(struct pullup_field *begin, struct pullup_field *end)
+{
+ int count = 1;
+ struct pullup_field *f;
+
+ if (!begin || !end) return 0;
+ for (f = begin; f != end; f = f->next) count++;
+ return count;
+}
+
+static int find_first_break(struct pullup_field *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(struct pullup_context *c, struct pullup_field *f0)
+{
+ int i;
+ struct pullup_field *f1 = f0->next;
+ struct pullup_field *f2 = f1->next;
+ struct pullup_field *f3 = f2->next;
+ int l, max_l=0, max_r=0;
+ //struct pullup_field *ff;
+ //for (i=0, ff=c->first; ff != f0; i++, ff=ff->next);
+
+ if (f0->flags & F_HAVE_BREAKS) return;
+ //printf("\n%d: ", i);
+ 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 < c->metric_len; 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 */
+ //printf("%d %d\n", max_l, max_r);
+ 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(struct pullup_context *c, struct pullup_field *f)
+{
+ int i;
+ int 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;
+ }
+ if (1) {
+ for (i = 0; i < c->metric_len; i++) {
+ int lv = f->prev->var[i];
+ int rv = f->next->var[i];
+ int v = f->var[i];
+ int lc = f->comb[i] - (v+lv) + ABS(v-lv);
+ int rc = f->next->comb[i] - (v+rv) + ABS(v-rv);
+ lc = lc>0 ? lc : 0;
+ rc = rc>0 ? 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;
+ } else {
+ for (i = 0; i < c->metric_len; i++) {
+ l = f->comb[i] - f->next->comb[i];
+ if (l > max_l) max_l = l;
+ if (-l > max_r) max_r = -l;
+ }
+ if (max_l + max_r < 64) return;
+ if (max_r > 2*max_l) f->affinity = -1;
+ else if (max_l > 2*max_r) f->affinity = 1;
+ }
+}
+
+static void foo(struct pullup_context *c)
+{
+ struct pullup_field *f = c->first;
+ int i, n = queue_length(f, c->last);
+ for (i = 0; i < n-1; i++) {
+ if (i < n-3) compute_breaks(c, f);
+ compute_affinity(c, f);
+ f = f->next;
+ }
+}
+
+static int decide_frame_length(struct pullup_context *c)
+{
+ struct pullup_field *f0 = c->first;
+ struct pullup_field *f1 = f0->next;
+ struct pullup_field *f2 = f1->next;
+ int l;
+
+ if (queue_length(c->first, c->last) < 4) return 0;
+ foo(c);
+
+ if (f0->affinity == -1) return 1;
+
+ l = find_first_break(f0, 3);
+ if (l == 1 && c->strict_breaks < 0) l = 0;
+
+ switch (l) {
+ case 1:
+ if (c->strict_breaks < 1 && f0->affinity == 1 && f1->affinity == -1)
+ return 2;
+ else return 1;
+ case 2:
+ /* FIXME: strictly speaking, f0->prev is no longer valid... :) */
+ if (c->strict_pairs
+ && (f0->prev->breaks & BREAK_RIGHT) && (f2->breaks & BREAK_LEFT)
+ && (f0->affinity != 1 || f1->affinity != -1) )
+ return 1;
+ if (f1->affinity == 1) return 1;
+ else return 2;
+ case 3:
+ if (f2->affinity == 1) return 2;
+ else return 3;
+ 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 */
+ if (f0->affinity == 1) return 3;
+ else return 1;
+ }
+ else return 2; /* the remaining 6 */
+ }
+}
+
+
+static void print_aff_and_breaks(struct pullup_context *c, struct pullup_field *f)
+{
+ int i;
+ struct pullup_field *f0 = f;
+ const char aff_l[] = "+..", aff_r[] = "..+";
+ printf("\naffinity: ");
+ for (i = 0; i < 4; i++) {
+ printf("%c%d%c", aff_l[1+f->affinity], i, aff_r[1+f->affinity]);
+ f = f->next;
+ }
+ f = f0;
+ printf("\nbreaks: ");
+ for (i=0; i<4; i++) {
+ printf("%c%d%c", f->breaks & BREAK_LEFT ? '|' : '.', i, f->breaks & BREAK_RIGHT ? '|' : '.');
+ f = f->next;
+ }
+ printf("\n");
+}
+
+
+
+
+
+struct pullup_frame *ff_pullup_get_frame(struct pullup_context *c)
+{
+ int i;
+ struct pullup_frame *fr = c->frame;
+ int n = decide_frame_length(c);
+ int aff = c->first->next->affinity;
+
+ if (!n) return 0;
+ if (fr->lock) return 0;
+
+ if (c->verbose) {
+ print_aff_and_breaks(c, c->first);
+ printf("duration: %d \n", n);
+ }
+
+ fr->lock++;
+ fr->length = n;
+ fr->parity = c->first->parity;
+ fr->buffer = 0;
+ for (i = 0; i < n; i++) {
+ /* We cheat and steal the buffer without release+relock */
+ fr->ifields[i] = c->first->buffer;
+ c->first->buffer = 0;
+ c->first = c->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 == 0)
+ aff = (fr->ifields[0] == fr->ifields[1]) ? -1 : 1;
+ /* else if (c->verbose) printf("forced aff: %d \n", aff); */
+ fr->ofields[fr->parity] = fr->ifields[1+aff];
+ fr->ofields[fr->parity^1] = fr->ifields[1];
+ }
+ ff_pullup_lock_buffer(fr->ofields[0], 0);
+ ff_pullup_lock_buffer(fr->ofields[1], 1);
+
+ if (fr->ofields[0] == fr->ofields[1]) {
+ fr->buffer = fr->ofields[0];
+ ff_pullup_lock_buffer(fr->buffer, 2);
+ return fr;
+ }
+ return fr;
+}
+
+static void copy_field(struct pullup_context *c, struct pullup_buffer *dest,
+ struct pullup_buffer *src, int parity)
+{
+ int i, j;
+ unsigned char *d, *s;
+ for (i = 0; i < c->nplanes; i++) {
+ s = src->planes[i] + parity*c->stride[i];
+ d = dest->planes[i] + parity*c->stride[i];
+ for (j = c->h[i]>>1; j; j--) {
+ memcpy(d, s, c->stride[i]);
+ s += c->stride[i]<<1;
+ d += c->stride[i]<<1;
+ }
+ }
+}
+
+void ff_pullup_pack_frame(struct pullup_context *c, struct pullup_frame *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];
+ ff_pullup_lock_buffer(fr->buffer, 2);
+ copy_field(c, fr->buffer, fr->ofields[i^1], i^1);
+ return;
+ }
+ fr->buffer = ff_pullup_get_buffer(c, 2);
+ copy_field(c, fr->buffer, fr->ofields[0], 0);
+ copy_field(c, fr->buffer, fr->ofields[1], 1);
+}
+
+void ff_pullup_release_frame(struct pullup_frame *fr)
+{
+ int i;
+ for (i = 0; i < fr->length; i++)
+ ff_pullup_release_buffer(fr->ifields[i], fr->parity ^ (i&1));
+ ff_pullup_release_buffer(fr->ofields[0], 0);
+ ff_pullup_release_buffer(fr->ofields[1], 1);
+ if (fr->buffer) ff_pullup_release_buffer(fr->buffer, 2);
+ fr->lock--;
+}
+
+
+
+
+
+
+struct pullup_context *ff_pullup_alloc_context(void)
+{
+ struct pullup_context *c;
+
+ c = calloc(1, sizeof(struct pullup_context));
+
+ return c;
+}
+
+void ff_pullup_preinit_context(struct pullup_context *c)
+{
+ c->bpp = calloc(c->nplanes, sizeof(int));
+ c->w = calloc(c->nplanes, sizeof(int));
+ c->h = calloc(c->nplanes, sizeof(int));
+ c->stride = calloc(c->nplanes, sizeof(int));
+ c->background = calloc(c->nplanes, sizeof(int));
+}
+
+void ff_pullup_init_context(struct pullup_context *c)
+{
+ int mp = c->metric_plane;
+ if (c->nbuffers < 10) c->nbuffers = 10;
+ c->buffers = calloc(c->nbuffers, sizeof (struct pullup_buffer));
+
+ c->metric_w = (c->w[mp] - ((c->junk_left + c->junk_right) << 3)) >> 3;
+ c->metric_h = (c->h[mp] - ((c->junk_top + c->junk_bottom) << 1)) >> 3;
+ c->metric_offset = c->junk_left*c->bpp[mp] + (c->junk_top<<1)*c->stride[mp];
+ c->metric_len = c->metric_w * c->metric_h;
+
+ c->head = make_field_queue(c, 8);
+
+ c->frame = calloc(1, sizeof (struct pullup_frame));
+ c->frame->ifields = calloc(3, sizeof (struct pullup_buffer *));
+
+ switch(c->format) {
+ case PULLUP_FMT_Y:
+ c->diff = diff_y;
+ c->comb = licomb_y;
+ c->var = var_y;
+#if ARCH_X86
+#if HAVE_MMX
+ if (c->cpu & PULLUP_CPU_MMX) {
+ c->diff = diff_y_mmx;
+ c->comb = licomb_y_mmx;
+ c->var = var_y_mmx;
+ }
+#endif
+#endif
+ /* c->comb = qpcomb_y; */
+ break;
+#if 0
+ case PULLUP_FMT_YUY2:
+ c->diff = diff_yuy2;
+ break;
+ case PULLUP_FMT_RGB32:
+ c->diff = diff_rgb32;
+ break;
+#endif
+ }
+}
+
+void ff_pullup_free_context(struct pullup_context *c)
+{
+ struct pullup_field *f;
+ free(c->buffers);
+ f = c->head;
+ do {
+ if (!f) break;
+ free(f->diffs);
+ free(f->comb);
+ f = f->next;
+ free(f->prev);
+ } while (f != c->head);
+ free(c->frame);
+ free(c);
+}
diff --git a/libavfilter/libmpcodecs/pullup.h b/libavfilter/libmpcodecs/pullup.h
new file mode 100644
index 0000000..cd6ec00
--- /dev/null
+++ b/libavfilter/libmpcodecs/pullup.h
@@ -0,0 +1,102 @@
+/*
+ * 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_PULLUP_H
+#define MPLAYER_PULLUP_H
+
+#define PULLUP_CPU_MMX 1
+#define PULLUP_CPU_MMX2 2
+#define PULLUP_CPU_3DNOW 4
+#define PULLUP_CPU_3DNOWEXT 8
+#define PULLUP_CPU_SSE 16
+#define PULLUP_CPU_SSE2 32
+
+#define PULLUP_FMT_Y 1
+#define PULLUP_FMT_YUY2 2
+#define PULLUP_FMT_UYVY 3
+#define PULLUP_FMT_RGB32 4
+
+struct pullup_buffer
+{
+ int lock[2];
+ unsigned char **planes;
+};
+
+struct pullup_field
+{
+ int parity;
+ struct pullup_buffer *buffer;
+ unsigned int flags;
+ int breaks;
+ int affinity;
+ int *diffs;
+ int *comb;
+ int *var;
+ struct pullup_field *prev, *next;
+};
+
+struct pullup_frame
+{
+ int lock;
+ int length;
+ int parity;
+ struct pullup_buffer **ifields, *ofields[2];
+ struct pullup_buffer *buffer;
+};
+
+struct pullup_context
+{
+ /* Public interface */
+ int format;
+ int nplanes;
+ int *bpp, *w, *h, *stride, *background;
+ unsigned int cpu;
+ int junk_left, junk_right, junk_top, junk_bottom;
+ int verbose;
+ int metric_plane;
+ int strict_breaks;
+ int strict_pairs;
+ /* Internal data */
+ struct pullup_field *first, *last, *head;
+ struct pullup_buffer *buffers;
+ int nbuffers;
+ int (*diff)(unsigned char *, unsigned char *, int);
+ int (*comb)(unsigned char *, unsigned char *, int);
+ int (*var)(unsigned char *, unsigned char *, int);
+ int metric_w, metric_h, metric_len, metric_offset;
+ struct pullup_frame *frame;
+};
+
+
+struct pullup_buffer *ff_pullup_lock_buffer(struct pullup_buffer *b, int parity);
+void ff_pullup_release_buffer(struct pullup_buffer *b, int parity);
+struct pullup_buffer *ff_pullup_get_buffer(struct pullup_context *c, int parity);
+
+void ff_pullup_submit_field(struct pullup_context *c, struct pullup_buffer *b, int parity);
+void ff_pullup_flush_fields(struct pullup_context *c);
+
+struct pullup_frame *ff_pullup_get_frame(struct pullup_context *c);
+void ff_pullup_pack_frame(struct pullup_context *c, struct pullup_frame *fr);
+void ff_pullup_release_frame(struct pullup_frame *fr);
+
+struct pullup_context *ff_pullup_alloc_context(void);
+void ff_pullup_preinit_context(struct pullup_context *c);
+void ff_pullup_init_context(struct pullup_context *c);
+void ff_pullup_free_context(struct pullup_context *c);
+
+#endif /* MPLAYER_PULLUP_H */
diff --git a/libavfilter/libmpcodecs/vf.h b/libavfilter/libmpcodecs/vf.h
new file mode 100644
index 0000000..0d26296
--- /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_dint.c b/libavfilter/libmpcodecs/vf_dint.c
new file mode 100644
index 0000000..950e835
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_dint.c
@@ -0,0 +1,214 @@
+/*
+ * 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 "mp_image.h"
+#include "img_format.h"
+#include "vf.h"
+
+struct vf_priv_s {
+ float sense; // first parameter
+ float level; // second parameter
+ unsigned int imgfmt;
+ int diff;
+ uint32_t max;
+// int dfr;
+// int rdfr;
+ int was_dint;
+ mp_image_t *pmpi; // previous mpi
+};
+
+#define MAXROWSIZE 1200
+
+static int config (struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt)
+{
+ int rowsize;
+
+ vf->priv->pmpi = ff_vf_get_image (vf->next, outfmt, MP_IMGTYPE_TEMP,
+ 0, width, height);
+ if (!(vf->priv->pmpi->flags & MP_IMGFLAG_PLANAR) &&
+ outfmt != IMGFMT_RGB32 && outfmt != IMGFMT_BGR32 &&
+ outfmt != IMGFMT_RGB24 && outfmt != IMGFMT_BGR24 &&
+ outfmt != IMGFMT_RGB16 && outfmt != IMGFMT_BGR16)
+ {
+ ff_mp_msg (MSGT_VFILTER, MSGL_WARN, "Drop-interlaced filter doesn't support this outfmt :(\n");
+ return 0;
+ }
+ vf->priv->imgfmt = outfmt;
+ // recalculate internal values
+ rowsize = vf->priv->pmpi->width;
+ if (rowsize > MAXROWSIZE) rowsize = MAXROWSIZE;
+ vf->priv->max = vf->priv->level * vf->priv->pmpi->height * rowsize / 2;
+ if (vf->priv->pmpi->flags & MP_IMGFLAG_PLANAR) // planar YUV
+ vf->priv->diff = vf->priv->sense * 256;
+ else
+ vf->priv->diff = vf->priv->sense * (1 << (vf->priv->pmpi->bpp/3));
+ if (vf->priv->diff < 0) vf->priv->diff = 0;
+ if (!(vf->priv->pmpi->flags & MP_IMGFLAG_PLANAR) &&
+ vf->priv->pmpi->bpp < 24 && vf->priv->diff > 31)
+ vf->priv->diff = 31;
+ ff_mp_msg (MSGT_VFILTER, MSGL_INFO, "Drop-interlaced: %dx%d diff %d / level %u\n",
+ vf->priv->pmpi->width, vf->priv->pmpi->height,
+ vf->priv->diff, (unsigned int)vf->priv->max);
+// vf->priv->rdfr = vf->priv->dfr = 0;
+ vf->priv->was_dint = 0;
+ return ff_vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
+}
+
+static int put_image (struct vf_instance *vf, mp_image_t *mpi, double pts)
+{
+ int8_t rrow0[MAXROWSIZE];
+ int8_t rrow1[MAXROWSIZE];
+ int8_t rrow2[MAXROWSIZE];
+ int8_t *row0 = rrow0, *row1 = rrow1, *row2 = rrow2/*, *row3 = rrow3*/;
+ int rowsize = mpi->width;
+ uint32_t nok = 0, max = vf->priv->max;
+ int diff = vf->priv->diff;
+ int i, j;
+ register int n1, n2;
+ unsigned char *cur0, *prv0;
+ register unsigned char *cur, *prv;
+
+ if (rowsize > MAXROWSIZE) rowsize = MAXROWSIZE;
+ // check if nothing to do
+ if (mpi->imgfmt == vf->priv->imgfmt)
+ {
+ cur0 = mpi->planes[0] + mpi->stride[0];
+ prv0 = mpi->planes[0];
+ for (j = 1; j < mpi->height && nok <= max; j++)
+ {
+ cur = cur0;
+ prv = prv0;
+ // analyse row (row0)
+ if (mpi->flags & MP_IMGFLAG_PLANAR) // planar YUV - check luminance
+ for (i = 0; i < rowsize; i++)
+ {
+ if (cur[0] - prv[0] > diff)
+ row0[i] = 1;
+ else if (cur[0] - prv[0] < -diff)
+ row0[i] = -1;
+ else
+ row0[i] = 0;
+ cur++;
+ prv++;
+ // check if row0 is 1 but row1 is 0, and row2 is 1 or row2 is 0
+ // but row3 is 1 so it's interlaced ptr (nok++)
+ if (j > 2 && row0[i] > 0 && (row1[i] < 0 || (!row1[i] && row2[i] < 0)) &&
+ (++nok) > max)
+ break;
+ }
+ else if (mpi->bpp < 24) // RGB/BGR 16 - check all colors
+ for (i = 0; i < rowsize; i++)
+ {
+ n1 = cur[0] + (cur[1]<<8);
+ n2 = prv[0] + (prv[1]<<8);
+ if ((n1&0x1f) - (n2&0x1f) > diff ||
+ ((n1>>5)&0x3f) - ((n2>>5)&0x3f) > diff ||
+ ((n1>>11)&0x1f) - ((n2>>11)&0x1f) > diff)
+ row0[i] = 1;
+ else if ((n1&0x1f) - (n2&0x1f) < -diff ||
+ ((n1>>5)&0x3f) - ((n2>>5)&0x3f) < -diff ||
+ ((n1>>11)&0x1f) - ((n2>>11)&0x1f) < -diff)
+ row0[i] = -1;
+ else
+ row0[i] = 0;
+ cur += 2;
+ prv += 2;
+ // check if row0 is 1 but row1 is 0, and row2 is 1 or row2 is 0
+ // but row3 is 1 so it's interlaced ptr (nok++)
+ if (j > 2 && row0[i] > 0 && (row1[i] < 0 || (!row1[i] && row2[i] < 0)) &&
+ (++nok) > max)
+ break;
+ }
+ else // RGB/BGR 24/32
+ for (i = 0; i < rowsize; i++)
+ {
+ if (cur[0] - prv[0] > diff ||
+ cur[1] - prv[1] > diff ||
+ cur[2] - prv[2] > diff)
+ row0[i] = 1;
+ else if (prv[0] - cur[0] > diff ||
+ prv[1] - cur[1] > diff ||
+ prv[2] - cur[2] > diff)
+ row0[i] = -1;
+ else
+ row0[i] = 0;
+ cur += mpi->bpp/8;
+ prv += mpi->bpp/8;
+ // check if row0 is 1 but row1 is 0, and row2 is 1 or row2 is 0
+ // but row3 is 1 so it's interlaced ptr (nok++)
+ if (j > 2 && row0[i] > 0 && (row1[i] < 0 || (!row1[i] && row2[i] < 0)) &&
+ (++nok) > max)
+ break;
+ }
+ cur0 += mpi->stride[0];
+ prv0 += mpi->stride[0];
+ // rotate rows
+ cur = row2;
+ row2 = row1;
+ row1 = row0;
+ row0 = cur;
+ }
+ }
+ // check if number of interlaced is above of max
+ if (nok > max)
+ {
+// vf->priv->dfr++;
+ if (vf->priv->was_dint < 1) // can skip at most one frame!
+ {
+ vf->priv->was_dint++;
+// vf->priv->rdfr++;
+// ff_mp_msg (MSGT_VFILTER, MSGL_INFO, "DI:%d/%d ", vf->priv->rdfr, vf->priv->dfr);
+ return 0;
+ }
+ }
+ vf->priv->was_dint = 0;
+// ff_mp_msg (MSGT_VFILTER, MSGL_INFO, "DI:%d/%d ", vf->priv->rdfr, vf->priv->dfr);
+ return ff_vf_next_put_image (vf, mpi, pts);
+}
+
+static int vf_open(vf_instance_t *vf, char *args){
+ vf->config = config;
+ vf->put_image = put_image;
+// vf->default_reqs=VFCAP_ACCEPT_STRIDE;
+ vf->priv = malloc (sizeof(struct vf_priv_s));
+ vf->priv->sense = 0.1;
+ vf->priv->level = 0.15;
+ vf->priv->pmpi = NULL;
+ if (args)
+ sscanf (args, "%f:%f", &vf->priv->sense, &vf->priv->level);
+ return 1;
+}
+
+const vf_info_t ff_vf_info_dint = {
+ "drop interlaced frames",
+ "dint",
+ "A.G.",
+ "",
+ vf_open,
+ NULL
+};
diff --git a/libavfilter/libmpcodecs/vf_eq.c b/libavfilter/libmpcodecs/vf_eq.c
new file mode 100644
index 0000000..4e256d9
--- /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"
+
+static 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
--- /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_fil.c b/libavfilter/libmpcodecs/vf_fil.c
new file mode 100644
index 0000000..80c6648
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_fil.c
@@ -0,0 +1,116 @@
+/*
+ * 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 "mp_image.h"
+#include "vf.h"
+
+struct vf_priv_s {
+ int interleave;
+ int height;
+ int width;
+ int stridefactor;
+};
+
+//===========================================================================//
+
+static int config(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt){
+ int pixel_stride= (width+15)&~15; //FIXME this is ust a guess ... especially for non planar its somewhat bad one
+
+#if 0
+ if(mpi->flags&MP_IMGFLAG_PLANAR)
+ pixel_stride= mpi->stride[0];
+ else
+ pixel_stride= 8*mpi->stride[0] / mpi->bpp;
+
+#endif
+
+ if(vf->priv->interleave){
+ vf->priv->height= 2*height;
+ vf->priv->width= width - (pixel_stride/2);
+ vf->priv->stridefactor=1;
+ }else{
+ vf->priv->height= height/2;
+ vf->priv->width= width + pixel_stride;
+ vf->priv->stridefactor=4;
+ }
+//printf("hX %d %d %d\n", vf->priv->width,vf->priv->height,vf->priv->stridefactor);
+
+ return ff_vf_next_config(vf, vf->priv->width, vf->priv->height,
+ (d_width*vf->priv->stridefactor)>>1, 2*d_height/vf->priv->stridefactor, flags, outfmt);
+}
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
+ if(mpi->flags&MP_IMGFLAG_DIRECT){
+ // we've used DR, so we're ready...
+ return ff_vf_next_put_image(vf,(mp_image_t*)mpi->priv, pts);
+ }
+
+ vf->dmpi=ff_vf_get_image(vf->next,mpi->imgfmt,
+ MP_IMGTYPE_EXPORT, MP_IMGFLAG_ACCEPT_STRIDE,
+ vf->priv->width, vf->priv->height);
+
+ // set up mpi as a double-stride image of dmpi:
+ vf->dmpi->planes[0]=mpi->planes[0];
+ vf->dmpi->stride[0]=(mpi->stride[0]*vf->priv->stridefactor)>>1;
+ if(vf->dmpi->flags&MP_IMGFLAG_PLANAR){
+ vf->dmpi->planes[1]=mpi->planes[1];
+ vf->dmpi->stride[1]=(mpi->stride[1]*vf->priv->stridefactor)>>1;
+ vf->dmpi->planes[2]=mpi->planes[2];
+ vf->dmpi->stride[2]=(mpi->stride[2]*vf->priv->stridefactor)>>1;
+ } else
+ vf->dmpi->planes[1]=mpi->planes[1]; // passthru bgr8 palette!!!
+
+ return ff_vf_next_put_image(vf,vf->dmpi, pts);
+}
+
+//===========================================================================//
+
+static void uninit(struct vf_instance *vf)
+{
+ 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->interleave= args && (*args == 'i');
+ return 1;
+}
+
+const vf_info_t ff_vf_info_fil = {
+ "fast (de)interleaver",
+ "fil",
+ "Michael Niedermayer",
+ "",
+ vf_open,
+ NULL
+};
+
+//===========================================================================//
diff --git a/libavfilter/libmpcodecs/vf_fspp.c b/libavfilter/libmpcodecs/vf_fspp.c
new file mode 100644
index 0000000..a8a33e2
--- /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
--- /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_mcdeint.c b/libavfilter/libmpcodecs/vf_mcdeint.c
new file mode 100644
index 0000000..b9ffaf2
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_mcdeint.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+
+/*
+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: completly ignoring the "unavailable" lines during motion estimation
+ didnt 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 interresting idea but the current filter framework is FAR from
+ supporting such things
+
+* combining the motion compensated image with the input image also isnt
+ as trivial as it seems, simple blindly taking even lines from one and
+ odd ones from the other doesnt work at all as ME/MC sometimes simple
+ has nothing in the previous frames which matches the current, the current
+ algo has been found by trial and error and almost certainly can be
+ improved ...
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <math.h>
+
+#include "mp_msg.h"
+#include "cpudetect.h"
+
+#include "libavutil/common.h"
+#include "libavutil/internal.h"
+#include "libavutil/intreadwrite.h"
+#include "libavcodec/avcodec.h"
+#include "libavcodec/dsputil.h"
+
+#undef fprintf
+#undef free
+#undef malloc
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+#include "av_helpers.h"
+
+#define MIN(a,b) ((a) > (b) ? (b) : (a))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define ABS(a) ((a) > 0 ? (a) : (-(a)))
+
+//===========================================================================//
+
+struct vf_priv_s {
+ int mode;
+ int qp;
+ int parity;
+#if 0
+ int temp_stride[3];
+ uint8_t *src[3];
+ int16_t *temp[3];
+#endif
+ int outbuf_size;
+ uint8_t *outbuf;
+ AVCodecContext *avctx_enc;
+ AVFrame *frame;
+ AVFrame *frame_dec;
+};
+
+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){
+ int x, y, i;
+
+ for(i=0; i<3; i++){
+ p->frame->data[i]= src[i];
+ p->frame->linesize[i]= src_stride[i];
+ }
+
+ p->avctx_enc->me_cmp=
+ p->avctx_enc->me_sub_cmp= FF_CMP_SAD /*| (p->parity ? FF_CMP_ODD : FF_CMP_EVEN)*/;
+ p->frame->quality= p->qp*FF_QP2LAMBDA;
+ avcodec_encode_video(p->avctx_enc, p->outbuf, p->outbuf_size, p->frame);
+ p->frame_dec = p->avctx_enc->coded_frame;
+
+ for(i=0; i<3; i++){
+ int is_chroma= !!i;
+ int w= width >>is_chroma;
+ int h= height>>is_chroma;
+ int fils= p->frame_dec->linesize[i];
+ int srcs= src_stride[i];
+
+ for(y=0; y<h; y++){
+ if((y ^ p->parity) & 1){
+ for(x=0; x<w; x++){
+ if((x-2)+(y-1)*w>=0 && (x+2)+(y+1)*w<w*h){ //FIXME either alloc larger images or optimize this
+ uint8_t *filp= &p->frame_dec->data[i][x + y*fils];
+ uint8_t *srcp= &src[i][x + y*srcs];
+ int diff0= filp[-fils] - srcp[-srcs];
+ int diff1= filp[+fils] - srcp[+srcs];
+ int spatial_score= ABS(srcp[-srcs-1] - srcp[+srcs-1])
+ +ABS(srcp[-srcs ] - srcp[+srcs ])
+ +ABS(srcp[-srcs+1] - srcp[+srcs+1]) - 1;
+ int temp= filp[0];
+
+#define CHECK(j)\
+ { int score= ABS(srcp[-srcs-1+(j)] - srcp[+srcs-1-(j)])\
+ + ABS(srcp[-srcs +(j)] - srcp[+srcs -(j)])\
+ + ABS(srcp[-srcs+1+(j)] - srcp[+srcs+1-(j)]);\
+ if(score < spatial_score){\
+ spatial_score= score;\
+ diff0= filp[-fils+(j)] - srcp[-srcs+(j)];\
+ diff1= filp[+fils-(j)] - srcp[+srcs-(j)];
+
+ CHECK(-1) CHECK(-2) }} }}
+ CHECK( 1) CHECK( 2) }} }}
+#if 0
+ if((diff0 ^ diff1) > 0){
+ int mindiff= ABS(diff0) > ABS(diff1) ? diff1 : diff0;
+ temp-= mindiff;
+ }
+#elif 1
+ if(diff0 + diff1 > 0)
+ temp-= (diff0 + diff1 - ABS( ABS(diff0) - ABS(diff1) )/2)/2;
+ else
+ temp-= (diff0 + diff1 + ABS( ABS(diff0) - ABS(diff1) )/2)/2;
+#else
+ temp-= (diff0 + diff1)/2;
+#endif
+#if 1
+ filp[0]=
+ dst[i][x + y*dst_stride[i]]= temp > 255U ? ~(temp>>31) : temp;
+#else
+ dst[i][x + y*dst_stride[i]]= filp[0];
+ filp[0]= temp > 255U ? ~(temp>>31) : temp;
+#endif
+ }else
+ dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
+ }
+ }
+ }
+ for(y=0; y<h; y++){
+ if(!((y ^ p->parity) & 1)){
+ for(x=0; x<w; x++){
+#if 1
+ p->frame_dec->data[i][x + y*fils]=
+ dst[i][x + y*dst_stride[i]]= src[i][x + y*srcs];
+#else
+ dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
+ p->frame_dec->data[i][x + y*fils]= src[i][x + y*srcs];
+#endif
+ }
+ }
+ }
+ }
+ p->parity ^= 1;
+
+}
+
+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++){
+ AVCodecContext *avctx_enc;
+ AVDictionary *opts = NULL;
+#if 0
+ int is_chroma= !!i;
+ int w= ((width + 31) & (~31))>>is_chroma;
+ int h= ((height + 31) & (~31))>>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));
+#endif
+ avctx_enc=
+ vf->priv->avctx_enc= avcodec_alloc_context3(enc);
+ avctx_enc->width = width;
+ avctx_enc->height = height;
+ 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= 1;
+ av_dict_set(&opts, "memc_only", "1", 0);
+ avctx_enc->me_cmp=
+ avctx_enc->me_sub_cmp= FF_CMP_SAD; //SSE;
+ avctx_enc->mb_cmp= FF_CMP_SSE;
+
+ switch(vf->priv->mode){
+ case 3:
+ avctx_enc->refs= 3;
+ case 2:
+ avctx_enc->me_method= ME_ITER;
+ case 1:
+ avctx_enc->flags |= CODEC_FLAG_4MV;
+ avctx_enc->dia_size=2;
+// avctx_enc->mb_decision = MB_DECISION_RD;
+ case 0:
+ avctx_enc->flags |= CODEC_FLAG_QPEL;
+ }
+
+ avcodec_open2(avctx_enc, enc, &opts);
+ av_dict_free(&opts);
+
+ }
+ vf->priv->frame= avcodec_alloc_frame();
+
+ vf->priv->outbuf_size= width*height*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
+return; //caused problems, dunno why
+ // 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;
+ }
+
+ filter(vf->priv, dmpi->planes, mpi->planes, dmpi->stride, mpi->stride, mpi->w, mpi->h);
+
+ return ff_vf_next_put_image(vf,dmpi, pts);
+}
+
+static void uninit(struct vf_instance *vf){
+ if(!vf->priv) return;
+
+#if 0
+ 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;
+ }
+#endif
+ if (vf->priv->avctx_enc) {
+ avcodec_close(vf->priv->avctx_enc);
+ av_freep(&vf->priv->avctx_enc);
+ }
+
+ free(vf->priv->outbuf);
+ 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 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->priv=malloc(sizeof(struct vf_priv_s));
+ memset(vf->priv, 0, sizeof(struct vf_priv_s));
+
+ ff_init_avcodec();
+
+ vf->priv->mode=0;
+ vf->priv->parity= -1;
+ vf->priv->qp=1;
+
+ if (args) sscanf(args, "%d:%d:%d", &vf->priv->mode, &vf->priv->parity, &vf->priv->qp);
+
+ return 1;
+}
+
+const vf_info_t ff_vf_info_mcdeint = {
+ "motion compensating deinterlacer",
+ "mcdeint",
+ "Michael Niedermayer",
+ "",
+ vf_open,
+ NULL
+};
diff --git a/libavfilter/libmpcodecs/vf_perspective.c b/libavfilter/libmpcodecs/vf_perspective.c
new file mode 100644
index 0000000..aed5c4d
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_perspective.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2002 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 <assert.h>
+#include <math.h>
+
+#include "config.h"
+#include "mp_msg.h"
+
+#if HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#include "libavutil/mem.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+
+#define SUB_PIXEL_BITS 8
+#define SUB_PIXELS (1<<SUB_PIXEL_BITS)
+#define COEFF_BITS 11
+
+//===========================================================================//
+
+struct vf_priv_s {
+ double ref[4][2];
+ int32_t coeff[1<<SUB_PIXEL_BITS][4];
+ int32_t (*pv)[2];
+ int pvStride;
+ int cubic;
+};
+
+
+/***************************************************************************/
+
+static void initPv(struct vf_priv_s *priv, int W, int H){
+ double a,b,c,d,e,f,g,h,D;
+ double (*ref)[2]= priv->ref;
+ int x,y;
+
+ g= ( (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;
+ h= ( (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;
+ D= (ref[1][0] - ref[3][0])*(ref[2][1] - ref[3][1])
+ - (ref[2][0] - ref[3][0])*(ref[1][1] - ref[3][1]);
+
+ a= D*(ref[1][0] - ref[0][0])*H + g*ref[1][0];
+ b= D*(ref[2][0] - ref[0][0])*W + h*ref[2][0];
+ c= D*ref[0][0]*W*H;
+ d= D*(ref[1][1] - ref[0][1])*H + g*ref[1][1];
+ e= D*(ref[2][1] - ref[0][1])*W + h*ref[2][1];
+ f= D*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*(a*x + b*y + c)/(g*x + h*y + D*W*H) + 0.5);
+ v= (int)floor( SUB_PIXELS*(d*x + e*y + f)/(g*x + h*y + D*W*H) + 0.5);
+
+ priv->pv[x + y*W][0]= u;
+ priv->pv[x + y*W][1]= v;
+ }
+ }
+}
+
+static double getCoeff(double d){
+ double A= -0.60;
+ double coeff;
+
+ d= fabs(d);
+
+ // Equation is from VirtualDub
+ 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 int config(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt){
+ int i, j;
+
+ vf->priv->pvStride= width;
+ vf->priv->pv= av_malloc(width*height*2*sizeof(int32_t));
+ initPv(vf->priv, width, height);
+
+ 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]= getCoeff(j - d - 1);
+
+ for(j=0; j<4; j++)
+ sum+= temp[j];
+
+ for(j=0; j<4; j++)
+ vf->priv->coeff[i][j]= (int)floor((1<<COEFF_BITS)*temp[j]/sum + 0.5);
+ }
+
+ return ff_vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
+}
+
+static void uninit(struct vf_instance *vf){
+ if(!vf->priv) return;
+
+ av_free(vf->priv->pv);
+ vf->priv->pv= NULL;
+
+ free(vf->priv);
+ vf->priv=NULL;
+}
+
+static inline void resampleCubic(uint8_t *dst, uint8_t *src, int w, int h, int dstStride, int srcStride, struct vf_priv_s *privParam, int xShift, int yShift){
+ int x, y;
+ struct vf_priv_s priv= *privParam;
+
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ int u, v, subU, subV, sum, sx, sy;
+
+ sx= x << xShift;
+ sy= y << yShift;
+ u= priv.pv[sx + sy*priv.pvStride][0]>>xShift;
+ v= priv.pv[sx + sy*priv.pvStride][1]>>yShift;
+ 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*srcStride;
+ const int a= priv.coeff[subU][0];
+ const int b= priv.coeff[subU][1];
+ const int c= priv.coeff[subU][2];
+ const int d= priv.coeff[subU][3];
+
+ sum=
+ priv.coeff[subV][0]*( a*src[index - 1 - srcStride] + b*src[index - 0 - srcStride]
+ + c*src[index + 1 - srcStride] + d*src[index + 2 - srcStride])
+ +priv.coeff[subV][1]*( a*src[index - 1 ] + b*src[index - 0 ]
+ + c*src[index + 1 ] + d*src[index + 2 ])
+ +priv.coeff[subV][2]*( a*src[index - 1 + srcStride] + b*src[index - 0 + srcStride]
+ + c*src[index + 1 + srcStride] + d*src[index + 2 + srcStride])
+ +priv.coeff[subV][3]*( a*src[index - 1+2*srcStride] + b*src[index - 0+2*srcStride]
+ + c*src[index + 1+2*srcStride] + d*src[index + 2+2*srcStride]);
+ }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+= priv.coeff[subU][dx]*priv.coeff[subV][dy]
+ *src[ ix + iy*srcStride];
+ }
+ }
+ }
+ sum= (sum + (1<<(COEFF_BITS*2-1)) ) >> (COEFF_BITS*2);
+ if(sum&~255){
+ if(sum<0) sum=0;
+ else sum=255;
+ }
+ dst[ x + y*dstStride]= sum;
+ }
+ }
+}
+
+static inline void resampleLinear(uint8_t *dst, uint8_t *src, int w, int h, int dstStride, int srcStride,
+ struct vf_priv_s *privParam, int xShift, int yShift){
+ int x, y;
+ struct vf_priv_s priv= *privParam;
+
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ int u, v, subU, subV, sum, sx, sy, index, subUI, subVI;
+
+ sx= x << xShift;
+ sy= y << yShift;
+ u= priv.pv[sx + sy*priv.pvStride][0]>>xShift;
+ v= priv.pv[sx + sy*priv.pvStride][1]>>yShift;
+ subU= u & (SUB_PIXELS-1);
+ subV= v & (SUB_PIXELS-1);
+ u >>= SUB_PIXEL_BITS;
+ v >>= SUB_PIXEL_BITS;
+ index= u + v*srcStride;
+ 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+srcStride] + subU*src[index+srcStride+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*srcStride;
+ sum= subUI*src[index] + subU*src[index+1];
+ sum= (sum + (1<<(SUB_PIXEL_BITS-1)) ) >> SUB_PIXEL_BITS;
+ }
+ }else{
+ if((unsigned)v < (unsigned)(h - 1)){
+ if(u<0) u= 0;
+ else u= w-1;
+ index= u + v*srcStride;
+ sum= subVI*src[index] + subV*src[index+srcStride];
+ sum= (sum + (1<<(SUB_PIXEL_BITS-1)) ) >> SUB_PIXEL_BITS;
+ }else{
+ if(u<0) u= 0;
+ else u= w-1;
+ if(v<0) v= 0;
+ else v= h-1;
+ index= u + v*srcStride;
+ sum= src[index];
+ }
+ }
+ if(sum&~255){
+ if(sum<0) sum=0;
+ else sum=255;
+ }
+ dst[ x + y*dstStride]= sum;
+ }
+ }
+}
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
+ int cw= mpi->w >> mpi->chroma_x_shift;
+ int ch= mpi->h >> mpi->chroma_y_shift;
+
+ mp_image_t *dmpi=ff_vf_get_image(vf->next,mpi->imgfmt,
+ MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
+ mpi->w,mpi->h);
+
+ assert(mpi->flags&MP_IMGFLAG_PLANAR);
+
+ if(vf->priv->cubic){
+ resampleCubic(dmpi->planes[0], mpi->planes[0], mpi->w,mpi->h, dmpi->stride[0], mpi->stride[0],
+ vf->priv, 0, 0);
+ resampleCubic(dmpi->planes[1], mpi->planes[1], cw , ch , dmpi->stride[1], mpi->stride[1],
+ vf->priv, mpi->chroma_x_shift, mpi->chroma_y_shift);
+ resampleCubic(dmpi->planes[2], mpi->planes[2], cw , ch , dmpi->stride[2], mpi->stride[2],
+ vf->priv, mpi->chroma_x_shift, mpi->chroma_y_shift);
+ }else{
+ resampleLinear(dmpi->planes[0], mpi->planes[0], mpi->w,mpi->h, dmpi->stride[0], mpi->stride[0],
+ vf->priv, 0, 0);
+ resampleLinear(dmpi->planes[1], mpi->planes[1], cw , ch , dmpi->stride[1], mpi->stride[1],
+ vf->priv, mpi->chroma_x_shift, mpi->chroma_y_shift);
+ resampleLinear(dmpi->planes[2], mpi->planes[2], cw , ch , dmpi->stride[2], mpi->stride[2],
+ vf->priv, mpi->chroma_x_shift, mpi->chroma_y_shift);
+ }
+
+ return ff_vf_next_put_image(vf,dmpi, pts);
+}
+
+//===========================================================================//
+
+static int query_format(struct vf_instance *vf, unsigned int fmt){
+ switch(fmt)
+ {
+ case IMGFMT_YV12:
+ case IMGFMT_I420:
+ case IMGFMT_IYUV:
+ case IMGFMT_YVU9:
+ case IMGFMT_444P:
+ case IMGFMT_422P:
+ case IMGFMT_411P:
+ return ff_vf_next_query_format(vf, fmt);
+ }
+ return 0;
+}
+
+static int vf_open(vf_instance_t *vf, char *args){
+ int e;
+
+ vf->config=config;
+ vf->put_image=put_image;
+// vf->get_image=get_image;
+ vf->query_format=query_format;
+ vf->uninit=uninit;
+ vf->priv=malloc(sizeof(struct vf_priv_s));
+ memset(vf->priv, 0, sizeof(struct vf_priv_s));
+
+ if(args==NULL) return 0;
+
+ e=sscanf(args, "%lf:%lf:%lf:%lf:%lf:%lf:%lf:%lf:%d",
+ &vf->priv->ref[0][0], &vf->priv->ref[0][1],
+ &vf->priv->ref[1][0], &vf->priv->ref[1][1],
+ &vf->priv->ref[2][0], &vf->priv->ref[2][1],
+ &vf->priv->ref[3][0], &vf->priv->ref[3][1],
+ &vf->priv->cubic
+ );
+
+ if(e!=9)
+ return 0;
+
+ return 1;
+}
+
+const vf_info_t ff_vf_info_perspective = {
+ "perspective correcture",
+ "perspective",
+ "Michael Niedermayer",
+ "",
+ vf_open,
+ NULL
+};
+
+//===========================================================================//
diff --git a/libavfilter/libmpcodecs/vf_phase.c b/libavfilter/libmpcodecs/vf_phase.c
new file mode 100644
index 0000000..25abc5b
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_phase.c
@@ -0,0 +1,303 @@
+/*
+ * 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 <limits.h>
+
+#include "config.h"
+#include "mp_msg.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+
+#include "libvo/fastmemcpy.h"
+
+enum mode { PROGRESSIVE, TOP_FIRST, BOTTOM_FIRST,
+ TOP_FIRST_ANALYZE, BOTTOM_FIRST_ANALYZE,
+ ANALYZE, FULL_ANALYZE, AUTO, AUTO_ANALYZE };
+
+#define fixed_mode(p) ((p)<=BOTTOM_FIRST)
+
+struct vf_priv_s
+ {
+ enum mode mode;
+ int verbose;
+ unsigned char *buf[3];
+ };
+
+/*
+ * Copy fields from either current or buffered previous frame to the
+ * output and store the current frame unmodified to the buffer.
+ */
+
+static void do_plane(unsigned char *to, unsigned char *from,
+ int w, int h, int ts, int fs,
+ unsigned char **bufp, enum mode mode)
+ {
+ unsigned char *buf, *end;
+ int top;
+
+ if(!*bufp)
+ {
+ mode=PROGRESSIVE;
+ if(!(*bufp=malloc(h*w))) return;
+ }
+
+ for(end=to+h*ts, buf=*bufp, top=1; to<end; from+=fs, to+=ts, buf+=w, top^=1)
+ {
+ fast_memcpy(to, mode==(top?BOTTOM_FIRST:TOP_FIRST)?buf:from, w);
+ fast_memcpy(buf, from, w);
+ }
+ }
+
+/*
+ * 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 mode analyze_plane(unsigned char *old, unsigned char *new,
+ int w, int h, int os, int ns, enum mode mode,
+ int verbose, int fields)
+ {
+ double bdiff, pdiff, tdiff, scale;
+ int bdif, tdif, pdif;
+ int top, t;
+ unsigned char *end, *rend;
+
+ if(mode==AUTO)
+ mode=fields&MP_IMGFIELD_ORDERED?fields&MP_IMGFIELD_TOP_FIRST?
+ TOP_FIRST:BOTTOM_FIRST:PROGRESSIVE;
+ else if(mode==AUTO_ANALYZE)
+ mode=fields&MP_IMGFIELD_ORDERED?fields&MP_IMGFIELD_TOP_FIRST?
+ TOP_FIRST_ANALYZE:BOTTOM_FIRST_ANALYZE:FULL_ANALYZE;
+
+ if(fixed_mode(mode))
+ bdiff=pdiff=tdiff=65536.0;
+ else
+ {
+ bdiff=pdiff=tdiff=0.0;
+
+ for(end=new+(h-2)*ns, new+=ns, old+=os, top=0;
+ new<end; new+=ns-w, old+=os-w, top^=1)
+ {
+ pdif=tdif=bdif=0;
+
+ switch(mode)
+ {
+ case TOP_FIRST_ANALYZE:
+ if(top)
+ for(rend=new+w; new<rend; new++, old++)
+ pdif+=diff(new, ns, new, ns),
+ tdif+=diff(new, ns, old, os);
+ else
+ for(rend=new+w; new<rend; new++, old++)
+ pdif+=diff(new, ns, new, ns),
+ tdif+=diff(old, os, new, ns);
+ break;
+
+ case BOTTOM_FIRST_ANALYZE:
+ if(top)
+ for(rend=new+w; new<rend; new++, old++)
+ pdif+=diff(new, ns, new, ns),
+ bdif+=diff(old, os, new, ns);
+ else
+ for(rend=new+w; new<rend; new++, old++)
+ pdif+=diff(new, ns, new, ns),
+ bdif+=diff(new, ns, old, os);
+ break;
+
+ case ANALYZE:
+ if(top)
+ for(rend=new+w; new<rend; new++, old++)
+ tdif+=diff(new, ns, old, os),
+ bdif+=diff(old, os, new, ns);
+ else
+ for(rend=new+w; new<rend; new++, old++)
+ bdif+=diff(new, ns, old, os),
+ tdif+=diff(old, os, new, ns);
+ break;
+
+ default: /* FULL_ANALYZE */
+ if(top)
+ for(rend=new+w; new<rend; new++, old++)
+ pdif+=diff(new, ns, new, ns),
+ tdif+=diff(new, ns, old, os),
+ bdif+=diff(old, os, new, ns);
+ else
+ for(rend=new+w; new<rend; new++, old++)
+ pdif+=diff(new, ns, new, ns),
+ bdif+=diff(new, ns, old, os),
+ tdif+=diff(old, os, new, ns);
+ }
+
+ 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;
+ }
+
+ if( ff_mp_msg_test(MSGT_VFILTER,MSGL_V) )
+ {
+ ff_mp_msg(MSGT_VFILTER, MSGL_INFO, "%c", mode==BOTTOM_FIRST?'b':mode==TOP_FIRST?'t':'p');
+ if(tdiff==65536.0) ff_mp_msg(MSGT_VFILTER, MSGL_INFO," N/A "); else ff_mp_msg(MSGT_VFILTER, MSGL_INFO," %8.2f", tdiff);
+ if(bdiff==65536.0) ff_mp_msg(MSGT_VFILTER, MSGL_INFO," N/A "); else ff_mp_msg(MSGT_VFILTER, MSGL_INFO," %8.2f", bdiff);
+ if(pdiff==65536.0) ff_mp_msg(MSGT_VFILTER, MSGL_INFO," N/A "); else ff_mp_msg(MSGT_VFILTER, MSGL_INFO," %8.2f", pdiff);
+ ff_mp_msg(MSGT_VFILTER, MSGL_INFO," \n");
+ }
+
+ return mode;
+ }
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
+ {
+ mp_image_t *dmpi;
+ int w;
+ enum mode mode;
+
+ if(!(dmpi=ff_vf_get_image(vf->next, mpi->imgfmt,
+ MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
+ mpi->w, mpi->h)))
+ return 0;
+
+ w=dmpi->w;
+ if(!(dmpi->flags&MP_IMGFLAG_PLANAR))
+ w*=dmpi->bpp/8;
+
+ mode=vf->priv->mode;
+
+ if(!vf->priv->buf[0])
+ mode=PROGRESSIVE;
+ else
+ mode=analyze_plane(vf->priv->buf[0], mpi->planes[0],
+ w, dmpi->h, w, mpi->stride[0], mode,
+ vf->priv->verbose, mpi->fields);
+
+ do_plane(dmpi->planes[0], mpi->planes[0],
+ w, dmpi->h,
+ dmpi->stride[0], mpi->stride[0],
+ &vf->priv->buf[0], mode);
+
+ if(dmpi->flags&MP_IMGFLAG_PLANAR)
+ {
+ do_plane(dmpi->planes[1], mpi->planes[1],
+ dmpi->chroma_width, dmpi->chroma_height,
+ dmpi->stride[1], mpi->stride[1],
+ &vf->priv->buf[1], mode);
+ do_plane(dmpi->planes[2], mpi->planes[2],
+ dmpi->chroma_width, dmpi->chroma_height,
+ dmpi->stride[2], mpi->stride[2],
+ &vf->priv->buf[2], mode);
+ }
+
+ return ff_vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
+ }
+
+static void uninit(struct vf_instance *vf)
+ {
+ if (!vf->priv)
+ return;
+ free(vf->priv->buf[0]);
+ free(vf->priv->buf[1]);
+ free(vf->priv->buf[2]);
+ free(vf->priv);
+ }
+
+static int vf_open(vf_instance_t *vf, char *args)
+ {
+ vf->put_image = put_image;
+ vf->uninit = uninit;
+ vf->default_reqs = VFCAP_ACCEPT_STRIDE;
+
+ if(!(vf->priv = calloc(1, sizeof(struct vf_priv_s))))
+ {
+ uninit(vf);
+ return 0;
+ }
+
+ vf->priv->mode=AUTO_ANALYZE;
+ vf->priv->verbose=0;
+
+ while(args && *args)
+ {
+ switch(*args)
+ {
+ case 't': vf->priv->mode=TOP_FIRST; break;
+ case 'a': vf->priv->mode=AUTO; break;
+ case 'b': vf->priv->mode=BOTTOM_FIRST; break;
+ case 'u': vf->priv->mode=ANALYZE; break;
+ case 'T': vf->priv->mode=TOP_FIRST_ANALYZE; break;
+ case 'A': vf->priv->mode=AUTO_ANALYZE; break;
+ case 'B': vf->priv->mode=BOTTOM_FIRST_ANALYZE; break;
+ case 'U': vf->priv->mode=FULL_ANALYZE; break;
+ case 'p': vf->priv->mode=PROGRESSIVE; break;
+ case 'v': vf->priv->verbose=1; break;
+ case ':': break;
+
+ default:
+ uninit(vf);
+ return 0; /* bad args */
+ }
+
+ if( (args=strchr(args, ':')) ) args++;
+ }
+
+ return 1;
+ }
+
+const vf_info_t ff_vf_info_phase =
+ {
+ "phase shift fields",
+ "phase",
+ "Ville Saari",
+ "",
+ vf_open,
+ NULL
+ };
diff --git a/libavfilter/libmpcodecs/vf_pp7.c b/libavfilter/libmpcodecs/vf_pp7.c
new file mode 100644
index 0000000..30f9530
--- /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_pullup.c b/libavfilter/libmpcodecs/vf_pullup.c
new file mode 100644
index 0000000..e4a28c4
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_pullup.c
@@ -0,0 +1,316 @@
+/*
+ * 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 "cpudetect.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+
+#include "libvo/fastmemcpy.h"
+
+#include "pullup.h"
+
+#undef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+struct vf_priv_s {
+ struct pullup_context *ctx;
+ int init;
+ int fakecount;
+ char *qbuf;
+};
+
+static void init_pullup(struct vf_instance *vf, mp_image_t *mpi)
+{
+ struct pullup_context *c = vf->priv->ctx;
+
+ if (mpi->flags & MP_IMGFLAG_PLANAR) {
+ c->format = PULLUP_FMT_Y;
+ c->nplanes = 4;
+ ff_pullup_preinit_context(c);
+ c->bpp[0] = c->bpp[1] = c->bpp[2] = 8;
+ c->w[0] = mpi->w;
+ c->h[0] = mpi->h;
+ c->w[1] = c->w[2] = mpi->chroma_width;
+ c->h[1] = c->h[2] = mpi->chroma_height;
+ c->w[3] = ((mpi->w+15)/16) * ((mpi->h+15)/16);
+ c->h[3] = 2;
+ c->stride[0] = mpi->width;
+ c->stride[1] = c->stride[2] = mpi->chroma_width;
+ c->stride[3] = c->w[3];
+ c->background[1] = c->background[2] = 128;
+ }
+
+ if (ff_gCpuCaps.hasMMX) c->cpu |= PULLUP_CPU_MMX;
+ if (ff_gCpuCaps.hasMMX2) c->cpu |= PULLUP_CPU_MMX2;
+ if (ff_gCpuCaps.has3DNow) c->cpu |= PULLUP_CPU_3DNOW;
+ if (ff_gCpuCaps.has3DNowExt) c->cpu |= PULLUP_CPU_3DNOWEXT;
+ if (ff_gCpuCaps.hasSSE) c->cpu |= PULLUP_CPU_SSE;
+ if (ff_gCpuCaps.hasSSE2) c->cpu |= PULLUP_CPU_SSE2;
+
+ ff_pullup_init_context(c);
+
+ vf->priv->init = 1;
+ vf->priv->qbuf = malloc(c->w[3]);
+}
+
+
+#if 0
+static void get_image(struct vf_instance *vf, mp_image_t *mpi)
+{
+ struct pullup_context *c = vf->priv->ctx;
+ struct pullup_buffer *b;
+
+ if (mpi->type == MP_IMGTYPE_STATIC) return;
+
+ if (!vf->priv->init) init_pullup(vf, mpi);
+
+ b = ff_pullup_get_buffer(c, 2);
+ if (!b) return; /* shouldn't happen... */
+
+ mpi->priv = b;
+
+ mpi->planes[0] = b->planes[0];
+ mpi->planes[1] = b->planes[1];
+ mpi->planes[2] = b->planes[2];
+ mpi->stride[0] = c->stride[0];
+ mpi->stride[1] = c->stride[1];
+ mpi->stride[2] = c->stride[2];
+
+ mpi->flags |= MP_IMGFLAG_DIRECT;
+ mpi->flags &= ~MP_IMGFLAG_DRAW_CALLBACK;
+}
+#endif
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
+{
+ struct pullup_context *c = vf->priv->ctx;
+ struct pullup_buffer *b;
+ struct pullup_frame *f;
+ mp_image_t *dmpi;
+ int ret;
+ int p;
+ int i;
+
+ if (!vf->priv->init) init_pullup(vf, mpi);
+
+ if (mpi->flags & MP_IMGFLAG_DIRECT) {
+ b = mpi->priv;
+ mpi->priv = 0;
+ } else {
+ b = ff_pullup_get_buffer(c, 2);
+ if (!b) {
+ ff_mp_msg(MSGT_VFILTER,MSGL_ERR,"Could not get buffer from pullup!\n");
+ f = ff_pullup_get_frame(c);
+ ff_pullup_release_frame(f);
+ return 0;
+ }
+ memcpy_pic(b->planes[0], mpi->planes[0], mpi->w, mpi->h,
+ c->stride[0], mpi->stride[0]);
+ if (mpi->flags & MP_IMGFLAG_PLANAR) {
+ memcpy_pic(b->planes[1], mpi->planes[1],
+ mpi->chroma_width, mpi->chroma_height,
+ c->stride[1], mpi->stride[1]);
+ memcpy_pic(b->planes[2], mpi->planes[2],
+ mpi->chroma_width, mpi->chroma_height,
+ c->stride[2], mpi->stride[2]);
+ }
+ }
+ if (mpi->qscale) {
+ fast_memcpy(b->planes[3], mpi->qscale, c->w[3]);
+ fast_memcpy(b->planes[3]+c->w[3], mpi->qscale, c->w[3]);
+ }
+
+ p = mpi->fields & MP_IMGFIELD_TOP_FIRST ? 0 :
+ (mpi->fields & MP_IMGFIELD_ORDERED ? 1 : 0);
+ ff_pullup_submit_field(c, b, p);
+ ff_pullup_submit_field(c, b, p^1);
+ if (mpi->fields & MP_IMGFIELD_REPEAT_FIRST)
+ ff_pullup_submit_field(c, b, p);
+
+ ff_pullup_release_buffer(b, 2);
+
+ f = ff_pullup_get_frame(c);
+
+ /* Fake yes for first few frames (buffer depth) to keep from
+ * breaking A/V sync with G1's bad architecture... */
+ if (!f) return vf->priv->fakecount ? (--vf->priv->fakecount,1) : 0;
+
+ if (f->length < 2) {
+ ff_pullup_release_frame(f);
+ f = ff_pullup_get_frame(c);
+ if (!f) return 0;
+ if (f->length < 2) {
+ ff_pullup_release_frame(f);
+ if (!(mpi->fields & MP_IMGFIELD_REPEAT_FIRST))
+ return 0;
+ f = ff_pullup_get_frame(c);
+ if (!f) return 0;
+ if (f->length < 2) {
+ ff_pullup_release_frame(f);
+ return 0;
+ }
+ }
+ }
+
+#if 0
+ /* Average qscale tables from both frames. */
+ if (mpi->qscale) {
+ for (i=0; i<c->w[3]; i++) {
+ vf->priv->qbuf[i] = (f->ofields[0]->planes[3][i]
+ + f->ofields[1]->planes[3][i+c->w[3]])>>1;
+ }
+ }
+#else
+ /* Take worst of qscale tables from both frames. */
+ if (mpi->qscale) {
+ for (i=0; i<c->w[3]; i++) {
+ vf->priv->qbuf[i] = MAX(f->ofields[0]->planes[3][i], f->ofields[1]->planes[3][i+c->w[3]]);
+ }
+ }
+#endif
+
+ /* If the frame isn't already exportable... */
+ while (!f->buffer) {
+ dmpi = ff_vf_get_image(vf->next, mpi->imgfmt,
+ MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
+ mpi->width, mpi->height);
+ /* FIXME: Is it ok to discard dmpi if it's not direct? */
+ if (!(dmpi->flags & MP_IMGFLAG_DIRECT)) {
+ ff_pullup_pack_frame(c, f);
+ break;
+ }
+ /* Direct render fields into output buffer */
+ my_memcpy_pic(dmpi->planes[0], f->ofields[0]->planes[0],
+ mpi->w, mpi->h/2, dmpi->stride[0]*2, c->stride[0]*2);
+ my_memcpy_pic(dmpi->planes[0] + dmpi->stride[0],
+ f->ofields[1]->planes[0] + c->stride[0],
+ mpi->w, mpi->h/2, dmpi->stride[0]*2, c->stride[0]*2);
+ if (mpi->flags & MP_IMGFLAG_PLANAR) {
+ my_memcpy_pic(dmpi->planes[1], f->ofields[0]->planes[1],
+ mpi->chroma_width, mpi->chroma_height/2,
+ dmpi->stride[1]*2, c->stride[1]*2);
+ my_memcpy_pic(dmpi->planes[1] + dmpi->stride[1],
+ f->ofields[1]->planes[1] + c->stride[1],
+ mpi->chroma_width, mpi->chroma_height/2,
+ dmpi->stride[1]*2, c->stride[1]*2);
+ my_memcpy_pic(dmpi->planes[2], f->ofields[0]->planes[2],
+ mpi->chroma_width, mpi->chroma_height/2,
+ dmpi->stride[2]*2, c->stride[2]*2);
+ my_memcpy_pic(dmpi->planes[2] + dmpi->stride[2],
+ f->ofields[1]->planes[2] + c->stride[2],
+ mpi->chroma_width, mpi->chroma_height/2,
+ dmpi->stride[2]*2, c->stride[2]*2);
+ }
+ ff_pullup_release_frame(f);
+ if (mpi->qscale) {
+ dmpi->qscale = vf->priv->qbuf;
+ dmpi->qstride = mpi->qstride;
+ dmpi->qscale_type = mpi->qscale_type;
+ }
+ return ff_vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
+ }
+ dmpi = ff_vf_get_image(vf->next, mpi->imgfmt,
+ MP_IMGTYPE_EXPORT, MP_IMGFLAG_ACCEPT_STRIDE,
+ mpi->width, mpi->height);
+
+ dmpi->planes[0] = f->buffer->planes[0];
+ dmpi->planes[1] = f->buffer->planes[1];
+ dmpi->planes[2] = f->buffer->planes[2];
+
+ dmpi->stride[0] = c->stride[0];
+ dmpi->stride[1] = c->stride[1];
+ dmpi->stride[2] = c->stride[2];
+
+ if (mpi->qscale) {
+ dmpi->qscale = vf->priv->qbuf;
+ dmpi->qstride = mpi->qstride;
+ dmpi->qscale_type = mpi->qscale_type;
+ }
+ ret = ff_vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
+ ff_pullup_release_frame(f);
+ return ret;
+}
+
+static int query_format(struct vf_instance *vf, unsigned int fmt)
+{
+ /* FIXME - support more formats */
+ switch (fmt) {
+ case IMGFMT_YV12:
+ case IMGFMT_IYUV:
+ case IMGFMT_I420:
+ return ff_vf_next_query_format(vf, fmt);
+ }
+ return 0;
+}
+
+static int config(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt)
+{
+ if (height&3) {
+ ff_mp_msg(MSGT_VFILTER, MSGL_ERR, "height must be divisible by four\n");
+ return 0;
+ }
+ return ff_vf_next_config(vf, width, height, d_width, d_height, flags, outfmt);
+}
+
+static void uninit(struct vf_instance *vf)
+{
+ ff_pullup_free_context(vf->priv->ctx);
+ free(vf->priv);
+}
+
+static int vf_open(vf_instance_t *vf, char *args)
+{
+ struct vf_priv_s *p;
+ struct pullup_context *c;
+ //vf->get_image = get_image;
+ vf->put_image = put_image;
+ vf->config = config;
+ vf->query_format = query_format;
+ vf->uninit = uninit;
+ vf->default_reqs = VFCAP_ACCEPT_STRIDE;
+ vf->priv = p = calloc(1, sizeof(struct vf_priv_s));
+ p->ctx = c = ff_pullup_alloc_context();
+ p->fakecount = 1;
+ c->junk_left = c->junk_right = 1;
+ c->junk_top = c->junk_bottom = 4;
+ c->strict_breaks = 0;
+ c->metric_plane = 0;
+ if (args) {
+ sscanf(args, "%d:%d:%d:%d:%d:%d", &c->junk_left, &c->junk_right, &c->junk_top, &c->junk_bottom, &c->strict_breaks, &c->metric_plane);
+ }
+ return 1;
+}
+
+const vf_info_t ff_vf_info_pullup = {
+ "pullup (from field sequence to frames)",
+ "pullup",
+ "Rich Felker",
+ "",
+ vf_open,
+ NULL
+};
diff --git a/libavfilter/libmpcodecs/vf_qp.c b/libavfilter/libmpcodecs/vf_qp.c
new file mode 100644
index 0000000..579ec1c
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_qp.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2004 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 <math.h>
+#include <inttypes.h>
+
+#include "mp_msg.h"
+#include "cpudetect.h"
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+#include "libvo/fastmemcpy.h"
+
+#include "libavcodec/avcodec.h"
+#include "libavutil/eval.h"
+#include "libavutil/mem.h"
+
+
+struct vf_priv_s {
+ char eq[200];
+ int8_t *qp;
+ int8_t lut[257];
+ int qp_stride;
+};
+
+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+15)>>4;
+ int i;
+
+ vf->priv->qp_stride= (width+15)>>4;
+ vf->priv->qp= av_malloc(vf->priv->qp_stride*h*sizeof(int8_t));
+
+ for(i=-129; i<128; i++){
+ double const_values[]={
+ M_PI,
+ M_E,
+ i != -129,
+ i,
+ 0
+ };
+ static const char *const_names[]={
+ "PI",
+ "E",
+ "known",
+ "qp",
+ NULL
+ };
+ double temp_val;
+ int res;
+
+ res= av_expr_parse_and_eval(&temp_val, vf->priv->eq, const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, NULL);
+
+ if (res < 0){
+ ff_mp_msg(MSGT_VFILTER, MSGL_ERR, "qp: Error evaluating \"%s\" \n", vf->priv->eq);
+ return 0;
+ }
+ vf->priv->lut[i+129]= lrintf(temp_val);
+ }
+
+ 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->w, mpi->h);
+ 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;
+ int x,y;
+
+ if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
+ // no DR, so get a new image! hope we'll get DR buffer:
+ vf->dmpi=ff_vf_get_image(vf->next,mpi->imgfmt,
+ MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
+ mpi->w,mpi->h);
+ }
+
+ dmpi= vf->dmpi;
+
+ if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
+ memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, dmpi->stride[0], mpi->stride[0]);
+ if(mpi->flags&MP_IMGFLAG_PLANAR){
+ 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]);
+ }
+ }
+ ff_vf_clone_mpi_attributes(dmpi, mpi);
+
+ dmpi->qscale = vf->priv->qp;
+ dmpi->qstride= vf->priv->qp_stride;
+ if(mpi->qscale){
+ for(y=0; y<((dmpi->h+15)>>4); y++){
+ for(x=0; x<vf->priv->qp_stride; x++){
+ dmpi->qscale[x + dmpi->qstride*y]=
+ vf->priv->lut[ 129 + ((int8_t)mpi->qscale[x + mpi->qstride*y]) ];
+ }
+ }
+ }else{
+ int qp= vf->priv->lut[0];
+ for(y=0; y<((dmpi->h+15)>>4); y++){
+ for(x=0; x<vf->priv->qp_stride; x++){
+ dmpi->qscale[x + dmpi->qstride*y]= qp;
+ }
+ }
+ }
+
+ return ff_vf_next_put_image(vf,dmpi, pts);
+}
+
+static void uninit(struct vf_instance *vf){
+ if(!vf->priv) return;
+
+ av_free(vf->priv->qp);
+ vf->priv->qp= NULL;
+
+ av_free(vf->priv);
+ vf->priv=NULL;
+}
+
+//===========================================================================//
+static int vf_open(vf_instance_t *vf, char *args){
+ vf->config=config;
+ vf->put_image=put_image;
+ vf->get_image=get_image;
+ vf->uninit=uninit;
+ vf->priv=av_malloc(sizeof(struct vf_priv_s));
+ memset(vf->priv, 0, sizeof(struct vf_priv_s));
+
+// avcodec_init();
+
+ if (args) strncpy(vf->priv->eq, args, 199);
+
+ return 1;
+}
+
+const vf_info_t ff_vf_info_qp = {
+ "QP changer",
+ "qp",
+ "Michael Niedermayer",
+ "",
+ vf_open,
+ NULL
+};
diff --git a/libavfilter/libmpcodecs/vf_sab.c b/libavfilter/libmpcodecs/vf_sab.c
new file mode 100644
index 0000000..2928a85
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_sab.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2002 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 <assert.h>
+
+#include "config.h"
+#include "mp_msg.h"
+
+#if HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#include "libavutil/avutil.h"
+#include "libavutil/mem.h"
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+#include "libswscale/swscale.h"
+#include "vf_scale.h"
+
+
+//===========================================================================//
+
+typedef struct FilterParam{
+ float radius;
+ float preFilterRadius;
+ float strength;
+ float quality;
+ struct SwsContext *preFilterContext;
+ uint8_t *preFilterBuf;
+ int preFilterStride;
+ int distWidth;
+ int distStride;
+ int *distCoeff;
+ int colorDiffCoeff[512];
+}FilterParam;
+
+struct vf_priv_s {
+ FilterParam luma;
+ FilterParam chroma;
+};
+
+
+/***************************************************************************/
+
+//FIXME stupid code duplication
+static void getSubSampleFactors(int *h, int *v, int format){
+ switch(format){
+ default:
+ assert(0);
+ case IMGFMT_YV12:
+ case IMGFMT_I420:
+ *h=1;
+ *v=1;
+ break;
+ case IMGFMT_YVU9:
+ *h=2;
+ *v=2;
+ break;
+ case IMGFMT_444P:
+ *h=0;
+ *v=0;
+ break;
+ case IMGFMT_422P:
+ *h=1;
+ *v=0;
+ break;
+ case IMGFMT_411P:
+ *h=2;
+ *v=0;
+ break;
+ }
+}
+
+static int allocStuff(FilterParam *f, int width, int height){
+ int stride= (width+7)&~7;
+ SwsVector *vec;
+ SwsFilter swsF;
+ int i,x,y;
+ f->preFilterBuf= av_malloc(stride*height);
+ f->preFilterStride= stride;
+
+ vec = sws_getGaussianVec(f->preFilterRadius, f->quality);
+ swsF.lumH= swsF.lumV= vec;
+ swsF.chrH= swsF.chrV= NULL;
+ f->preFilterContext= sws_getContext(
+ width, height, AV_PIX_FMT_GRAY8, width, height, AV_PIX_FMT_GRAY8, SWS_POINT, &swsF, NULL, NULL);
+
+ sws_freeVec(vec);
+ vec = sws_getGaussianVec(f->strength, 5.0);
+ for(i=0; i<512; i++){
+ double d;
+ int index= i-256 + vec->length/2;
+
+ if(index<0 || index>=vec->length) d= 0.0;
+ else d= vec->coeff[index];
+
+ f->colorDiffCoeff[i]= (int)(d/vec->coeff[vec->length/2]*(1<<12) + 0.5);
+ }
+ sws_freeVec(vec);
+ vec = sws_getGaussianVec(f->radius, f->quality);
+ f->distWidth= vec->length;
+ f->distStride= (vec->length+7)&~7;
+ f->distCoeff= av_malloc(f->distWidth*f->distStride*sizeof(int32_t));
+
+ for(y=0; y<vec->length; y++){
+ for(x=0; x<vec->length; x++){
+ double d= vec->coeff[x] * vec->coeff[y];
+
+ f->distCoeff[x + y*f->distStride]= (int)(d*(1<<10) + 0.5);
+// if(y==vec->length/2)
+// printf("%6d ", f->distCoeff[x + y*f->distStride]);
+ }
+ }
+ sws_freeVec(vec);
+
+ return 0;
+}
+
+static int config(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt){
+
+ int sw, sh;
+//__asm__ volatile("emms\n\t");
+ allocStuff(&vf->priv->luma, width, height);
+
+ getSubSampleFactors(&sw, &sh, outfmt);
+ allocStuff(&vf->priv->chroma, width>>sw, height>>sh);
+
+ return ff_vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
+}
+
+static void freeBuffers(FilterParam *f){
+ if(f->preFilterContext) sws_freeContext(f->preFilterContext);
+ f->preFilterContext=NULL;
+
+ av_free(f->preFilterBuf);
+ f->preFilterBuf=NULL;
+
+ av_free(f->distCoeff);
+ f->distCoeff=NULL;
+}
+
+static void uninit(struct vf_instance *vf){
+ if(!vf->priv) return;
+
+ freeBuffers(&vf->priv->luma);
+ freeBuffers(&vf->priv->chroma);
+
+ free(vf->priv);
+ vf->priv=NULL;
+}
+
+static inline void blur(uint8_t *dst, uint8_t *src, int w, int h, int dstStride, int srcStride, FilterParam *fp){
+ int x, y;
+ FilterParam f= *fp;
+ const int radius= f.distWidth/2;
+ const uint8_t* const srcArray[MP_MAX_PLANES] = {src};
+ uint8_t *dstArray[MP_MAX_PLANES]= {f.preFilterBuf};
+ int srcStrideArray[MP_MAX_PLANES]= {srcStride};
+ int dstStrideArray[MP_MAX_PLANES]= {f.preFilterStride};
+
+// f.preFilterContext->swScale(f.preFilterContext, srcArray, srcStrideArray, 0, h, dstArray, dstStrideArray);
+ sws_scale(f.preFilterContext, srcArray, srcStrideArray, 0, h, dstArray, dstStrideArray);
+
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ int sum=0;
+ int div=0;
+ int dy;
+ const int preVal= f.preFilterBuf[x + y*f.preFilterStride];
+#if 0
+ const int srcVal= src[x + y*srcStride];
+if((x/32)&1){
+ dst[x + y*dstStride]= srcVal;
+ if(y%32==0) dst[x + y*dstStride]= 0;
+ continue;
+}
+#endif
+ 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;
+ int factor;
+
+ factor= f.colorDiffCoeff[256+preVal - f.preFilterBuf[ix + iy*f.preFilterStride] ]
+ *f.distCoeff[dx + dy*f.distStride];
+ sum+= src[ix + iy*srcStride] *factor;
+ div+= 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;
+ int factor;
+ if (ix<0) ix= -ix;
+ else if(ix>=w) ix= w+w-ix-1;
+
+ factor= f.colorDiffCoeff[256+preVal - f.preFilterBuf[ix + iy*f.preFilterStride] ]
+ *f.distCoeff[dx + dy*f.distStride];
+ sum+= src[ix + iy*srcStride] *factor;
+ div+= factor;
+ }
+ }
+ }
+ dst[x + y*dstStride]= (sum + div/2)/div;
+ }
+ }
+}
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
+ int cw= mpi->w >> mpi->chroma_x_shift;
+ int ch= mpi->h >> mpi->chroma_y_shift;
+
+ mp_image_t *dmpi=ff_vf_get_image(vf->next,mpi->imgfmt,
+ MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
+ mpi->w,mpi->h);
+
+ assert(mpi->flags&MP_IMGFLAG_PLANAR);
+
+ blur(dmpi->planes[0], mpi->planes[0], mpi->w,mpi->h, dmpi->stride[0], mpi->stride[0], &vf->priv->luma);
+ blur(dmpi->planes[1], mpi->planes[1], cw , ch , dmpi->stride[1], mpi->stride[1], &vf->priv->chroma);
+ blur(dmpi->planes[2], mpi->planes[2], cw , ch , dmpi->stride[2], mpi->stride[2], &vf->priv->chroma);
+
+ return ff_vf_next_put_image(vf,dmpi, pts);
+}
+
+//===========================================================================//
+
+static int query_format(struct vf_instance *vf, unsigned int fmt){
+ switch(fmt)
+ {
+ case IMGFMT_YV12:
+ case IMGFMT_I420:
+ case IMGFMT_IYUV:
+ case IMGFMT_YVU9:
+ case IMGFMT_444P:
+ case IMGFMT_422P:
+ case IMGFMT_411P:
+ return ff_vf_next_query_format(vf, fmt);
+ }
+ return 0;
+}
+
+static int vf_open(vf_instance_t *vf, char *args){
+ int e;
+
+ vf->config=config;
+ vf->put_image=put_image;
+// vf->get_image=get_image;
+ vf->query_format=query_format;
+ vf->uninit=uninit;
+ vf->priv=malloc(sizeof(struct vf_priv_s));
+ memset(vf->priv, 0, sizeof(struct vf_priv_s));
+
+ if(args==NULL) return 0;
+
+ e=sscanf(args, "%f:%f:%f:%f:%f:%f",
+ &vf->priv->luma.radius,
+ &vf->priv->luma.preFilterRadius,
+ &vf->priv->luma.strength,
+ &vf->priv->chroma.radius,
+ &vf->priv->chroma.preFilterRadius,
+ &vf->priv->chroma.strength
+ );
+
+ vf->priv->luma.quality = vf->priv->chroma.quality= 3.0;
+
+ if(e==3){
+ vf->priv->chroma.radius= vf->priv->luma.radius;
+ vf->priv->chroma.preFilterRadius = vf->priv->luma.preFilterRadius;
+ vf->priv->chroma.strength= vf->priv->luma.strength;
+ }else if(e!=6)
+ return 0;
+
+// if(vf->priv->luma.radius < 0) return 0;
+// if(vf->priv->chroma.radius < 0) return 0;
+
+ return 1;
+}
+
+const vf_info_t ff_vf_info_sab = {
+ "shape adaptive blur",
+ "sab",
+ "Michael Niedermayer",
+ "",
+ vf_open,
+ NULL
+};
+
+//===========================================================================//
diff --git a/libavfilter/libmpcodecs/vf_scale.h b/libavfilter/libmpcodecs/vf_scale.h
new file mode 100644
index 0000000..177fbe5
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_scale.h
@@ -0,0 +1,34 @@
+/*
+ * 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_SCALE_H
+#define MPLAYER_VF_SCALE_H
+
+extern int ff_sws_chr_vshift;
+extern int ff_sws_chr_hshift;
+
+extern float ff_sws_chr_gblur;
+extern float ff_sws_lum_gblur;
+extern float ff_sws_chr_sharpen;
+extern float ff_sws_lum_sharpen;
+
+extern int ff_sws_flags;
+
+struct SwsContext *ff_sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat);
+
+#endif /* MPLAYER_VF_SCALE_H */
diff --git a/libavfilter/libmpcodecs/vf_softpulldown.c b/libavfilter/libmpcodecs/vf_softpulldown.c
new file mode 100644
index 0000000..556374e
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_softpulldown.c
@@ -0,0 +1,163 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "mp_msg.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+
+#include "libvo/fastmemcpy.h"
+
+struct vf_priv_s {
+ int state;
+ long long in;
+ long long out;
+};
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
+{
+ mp_image_t *dmpi;
+ int ret = 0;
+ int flags = mpi->fields;
+ int state = vf->priv->state;
+
+ dmpi = ff_vf_get_image(vf->next, mpi->imgfmt,
+ MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE |
+ MP_IMGFLAG_PRESERVE, mpi->width, mpi->height);
+
+ vf->priv->in++;
+
+ if ((state == 0 &&
+ !(flags & MP_IMGFIELD_TOP_FIRST)) ||
+ (state == 1 &&
+ flags & MP_IMGFIELD_TOP_FIRST)) {
+ ff_mp_msg(MSGT_VFILTER, MSGL_WARN,
+ "softpulldown: Unexpected field flags: state=%d top_field_first=%d repeat_first_field=%d\n",
+ state,
+ (flags & MP_IMGFIELD_TOP_FIRST) != 0,
+ (flags & MP_IMGFIELD_REPEAT_FIRST) != 0);
+ state ^= 1;
+ }
+
+ if (state == 0) {
+ ret = ff_vf_next_put_image(vf, mpi, MP_NOPTS_VALUE);
+ vf->priv->out++;
+ if (flags & MP_IMGFIELD_REPEAT_FIRST) {
+ my_memcpy_pic(dmpi->planes[0],
+ mpi->planes[0], mpi->w, mpi->h/2,
+ dmpi->stride[0]*2, mpi->stride[0]*2);
+ if (mpi->flags & MP_IMGFLAG_PLANAR) {
+ my_memcpy_pic(dmpi->planes[1],
+ mpi->planes[1],
+ mpi->chroma_width,
+ mpi->chroma_height/2,
+ dmpi->stride[1]*2,
+ mpi->stride[1]*2);
+ my_memcpy_pic(dmpi->planes[2],
+ mpi->planes[2],
+ mpi->chroma_width,
+ mpi->chroma_height/2,
+ dmpi->stride[2]*2,
+ mpi->stride[2]*2);
+ }
+ state=1;
+ }
+ } else {
+ my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0],
+ mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2,
+ dmpi->stride[0]*2, mpi->stride[0]*2);
+ if (mpi->flags & MP_IMGFLAG_PLANAR) {
+ my_memcpy_pic(dmpi->planes[1]+dmpi->stride[1],
+ mpi->planes[1]+mpi->stride[1],
+ mpi->chroma_width, mpi->chroma_height/2,
+ dmpi->stride[1]*2, mpi->stride[1]*2);
+ my_memcpy_pic(dmpi->planes[2]+dmpi->stride[2],
+ mpi->planes[2]+mpi->stride[2],
+ mpi->chroma_width, mpi->chroma_height/2,
+ dmpi->stride[2]*2, mpi->stride[2]*2);
+ }
+ ret = ff_vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
+ vf->priv->out++;
+ if (flags & MP_IMGFIELD_REPEAT_FIRST) {
+ ret |= ff_vf_next_put_image(vf, mpi, MP_NOPTS_VALUE);
+ vf->priv->out++;
+ state=0;
+ } else {
+ my_memcpy_pic(dmpi->planes[0],
+ mpi->planes[0], mpi->w, mpi->h/2,
+ dmpi->stride[0]*2, mpi->stride[0]*2);
+ if (mpi->flags & MP_IMGFLAG_PLANAR) {
+ my_memcpy_pic(dmpi->planes[1],
+ mpi->planes[1],
+ mpi->chroma_width,
+ mpi->chroma_height/2,
+ dmpi->stride[1]*2,
+ mpi->stride[1]*2);
+ my_memcpy_pic(dmpi->planes[2],
+ mpi->planes[2],
+ mpi->chroma_width,
+ mpi->chroma_height/2,
+ dmpi->stride[2]*2,
+ mpi->stride[2]*2);
+ }
+ }
+ }
+
+ vf->priv->state = state;
+
+ return ret;
+}
+
+static int config(struct vf_instance *vf,
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt)
+{
+ return ff_vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
+}
+
+static void uninit(struct vf_instance *vf)
+{
+ ff_mp_msg(MSGT_VFILTER, MSGL_INFO, "softpulldown: %lld frames in, %lld frames out\n", vf->priv->in, vf->priv->out);
+ free(vf->priv);
+}
+
+static int vf_open(vf_instance_t *vf, char *args)
+{
+ vf->config = config;
+ vf->put_image = put_image;
+ vf->uninit = uninit;
+ vf->default_reqs = VFCAP_ACCEPT_STRIDE;
+ vf->priv = calloc(1, sizeof(struct vf_priv_s));
+ vf->priv->state = 0;
+ return 1;
+}
+
+const vf_info_t ff_vf_info_softpulldown = {
+ "mpeg2 soft 3:2 pulldown",
+ "softpulldown",
+ "Tobias Diedrich <ranma+mplayer@tdiedrich.de>",
+ "",
+ vf_open,
+ NULL
+};
diff --git a/libavfilter/libmpcodecs/vf_spp.c b/libavfilter/libmpcodecs/vf_spp.c
new file mode 100644
index 0000000..75ede23
--- /dev/null
+++ b/libavfilter/libmpcodecs/vf_spp.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright (C) 2003 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.
+ */
+
+/*
+ * 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)
+ */
+
+
+#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 "libavutil/common.h"
+#include "libavutil/internal.h"
+#include "libavutil/intreadwrite.h"
+#include "libavcodec/avcodec.h"
+#include "libavcodec/dsputil.h"
+
+#undef fprintf
+#undef free
+#undef malloc
+
+#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))
+
+//===========================================================================//
+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, },
+};
+
+static const uint8_t offset[127][2]= {
+{0,0},
+{0,0}, {4,4},
+{0,0}, {2,2}, {6,4}, {4,6},
+{0,0}, {5,1}, {2,2}, {7,3}, {4,4}, {1,5}, {6,6}, {3,7},
+
+{0,0}, {4,0}, {1,1}, {5,1}, {3,2}, {7,2}, {2,3}, {6,3},
+{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},
+{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},
+{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},
+};
+
+struct vf_priv_s {
+ int log2_count;
+ int qp;
+ int mode;
+ int mpeg2;
+ int temp_stride;
+ uint8_t *src;
+ int16_t *temp;
+ AVCodecContext *avctx;
+ DSPContext dsp;
+ char *non_b_qp;
+};
+
+#define SHIFT 22
+
+static void hardthresh_c(int16_t dst[64], int16_t src[64], int qp, uint8_t *permutation){
+ int i;
+ int bias= 0; //FIXME
+ unsigned int threshold1, threshold2;
+
+ threshold1= qp*((1<<4) - bias) - 1;
+ threshold2= (threshold1<<1);
+
+ memset(dst, 0, 64*sizeof(int16_t));
+ 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], int16_t src[64], int qp, uint8_t *permutation){
+ int i;
+ int bias= 0; //FIXME
+ unsigned int threshold1, threshold2;
+
+ threshold1= qp*((1<<4) - bias) - 1;
+ threshold2= (threshold1<<1);
+
+ memset(dst, 0, 64*sizeof(int16_t));
+ 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;
+ }
+ }
+}
+
+#if HAVE_MMX
+static void hardthresh_mmx(int16_t dst[64], int16_t src[64], int qp, uint8_t *permutation){
+ int bias= 0; //FIXME
+ unsigned int threshold1;
+
+ threshold1= qp*((1<<4) - bias) - 1;
+
+ __asm__ volatile(
+#define REQUANT_CORE(dst0, dst1, dst2, dst3, src0, src1, src2, src3) \
+ "movq " #src0 ", %%mm0 \n\t"\
+ "movq " #src1 ", %%mm1 \n\t"\
+ "movq " #src2 ", %%mm2 \n\t"\
+ "movq " #src3 ", %%mm3 \n\t"\
+ "psubw %%mm4, %%mm0 \n\t"\
+ "psubw %%mm4, %%mm1 \n\t"\
+ "psubw %%mm4, %%mm2 \n\t"\
+ "psubw %%mm4, %%mm3 \n\t"\
+ "paddusw %%mm5, %%mm0 \n\t"\
+ "paddusw %%mm5, %%mm1 \n\t"\
+ "paddusw %%mm5, %%mm2 \n\t"\
+ "paddusw %%mm5, %%mm3 \n\t"\
+ "paddw %%mm6, %%mm0 \n\t"\
+ "paddw %%mm6, %%mm1 \n\t"\
+ "paddw %%mm6, %%mm2 \n\t"\
+ "paddw %%mm6, %%mm3 \n\t"\
+ "psubusw %%mm6, %%mm0 \n\t"\
+ "psubusw %%mm6, %%mm1 \n\t"\
+ "psubusw %%mm6, %%mm2 \n\t"\
+ "psubusw %%mm6, %%mm3 \n\t"\
+ "psraw $3, %%mm0 \n\t"\
+ "psraw $3, %%mm1 \n\t"\
+ "psraw $3, %%mm2 \n\t"\
+ "psraw $3, %%mm3 \n\t"\
+\
+ "movq %%mm0, %%mm7 \n\t"\
+ "punpcklwd %%mm2, %%mm0 \n\t" /*A*/\
+ "punpckhwd %%mm2, %%mm7 \n\t" /*C*/\
+ "movq %%mm1, %%mm2 \n\t"\
+ "punpcklwd %%mm3, %%mm1 \n\t" /*B*/\
+ "punpckhwd %%mm3, %%mm2 \n\t" /*D*/\
+ "movq %%mm0, %%mm3 \n\t"\
+ "punpcklwd %%mm1, %%mm0 \n\t" /*A*/\
+ "punpckhwd %%mm7, %%mm3 \n\t" /*C*/\
+ "punpcklwd %%mm2, %%mm7 \n\t" /*B*/\
+ "punpckhwd %%mm2, %%mm1 \n\t" /*D*/\
+\
+ "movq %%mm0, " #dst0 " \n\t"\
+ "movq %%mm7, " #dst1 " \n\t"\
+ "movq %%mm3, " #dst2 " \n\t"\
+ "movq %%mm1, " #dst3 " \n\t"
+
+ "movd %2, %%mm4 \n\t"
+ "movd %3, %%mm5 \n\t"
+ "movd %4, %%mm6 \n\t"
+ "packssdw %%mm4, %%mm4 \n\t"
+ "packssdw %%mm5, %%mm5 \n\t"
+ "packssdw %%mm6, %%mm6 \n\t"
+ "packssdw %%mm4, %%mm4 \n\t"
+ "packssdw %%mm5, %%mm5 \n\t"
+ "packssdw %%mm6, %%mm6 \n\t"
+ 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], int16_t src[64], int qp, uint8_t *permutation){
+ int bias= 0; //FIXME
+ unsigned int threshold1;
+
+ threshold1= qp*((1<<4) - bias) - 1;
+
+ __asm__ volatile(
+#undef REQUANT_CORE
+#define REQUANT_CORE(dst0, dst1, dst2, dst3, src0, src1, src2, src3) \
+ "movq " #src0 ", %%mm0 \n\t"\
+ "movq " #src1 ", %%mm1 \n\t"\
+ "pxor %%mm6, %%mm6 \n\t"\
+ "pxor %%mm7, %%mm7 \n\t"\
+ "pcmpgtw %%mm0, %%mm6 \n\t"\
+ "pcmpgtw %%mm1, %%mm7 \n\t"\
+ "pxor %%mm6, %%mm0 \n\t"\
+ "pxor %%mm7, %%mm1 \n\t"\
+ "psubusw %%mm4, %%mm0 \n\t"\
+ "psubusw %%mm4, %%mm1 \n\t"\
+ "pxor %%mm6, %%mm0 \n\t"\
+ "pxor %%mm7, %%mm1 \n\t"\
+ "movq " #src2 ", %%mm2 \n\t"\
+ "movq " #src3 ", %%mm3 \n\t"\
+ "pxor %%mm6, %%mm6 \n\t"\
+ "pxor %%mm7, %%mm7 \n\t"\
+ "pcmpgtw %%mm2, %%mm6 \n\t"\
+ "pcmpgtw %%mm3, %%mm7 \n\t"\
+ "pxor %%mm6, %%mm2 \n\t"\
+ "pxor %%mm7, %%mm3 \n\t"\
+ "psubusw %%mm4, %%mm2 \n\t"\
+ "psubusw %%mm4, %%mm3 \n\t"\
+ "pxor %%mm6, %%mm2 \n\t"\
+ "pxor %%mm7, %%mm3 \n\t"\
+\
+ "paddsw %%mm5, %%mm0 \n\t"\
+ "paddsw %%mm5, %%mm1 \n\t"\
+ "paddsw %%mm5, %%mm2 \n\t"\
+ "paddsw %%mm5, %%mm3 \n\t"\
+ "psraw $3, %%mm0 \n\t"\
+ "psraw $3, %%mm1 \n\t"\
+ "psraw $3, %%mm2 \n\t"\
+ "psraw $3, %%mm3 \n\t"\
+\
+ "movq %%mm0, %%mm7 \n\t"\
+ "punpcklwd %%mm2, %%mm0 \n\t" /*A*/\
+ "punpckhwd %%mm2, %%mm7 \n\t" /*C*/\
+ "movq %%mm1, %%mm2 \n\t"\
+ "punpcklwd %%mm3, %%mm1 \n\t" /*B*/\
+ "punpckhwd %%mm3, %%mm2 \n\t" /*D*/\
+ "movq %%mm0, %%mm3 \n\t"\
+ "punpcklwd %%mm1, %%mm0 \n\t" /*A*/\
+ "punpckhwd %%mm7, %%mm3 \n\t" /*C*/\
+ "punpcklwd %%mm2, %%mm7 \n\t" /*B*/\
+ "punpckhwd %%mm2, %%mm1 \n\t" /*D*/\
+\
+ "movq %%mm0, " #dst0 " \n\t"\
+ "movq %%mm7, " #dst1 " \n\t"\
+ "movq %%mm3, " #dst2 " \n\t"\
+ "movq %%mm1, " #dst3 " \n\t"
+
+ "movd %2, %%mm4 \n\t"
+ "movd %3, %%mm5 \n\t"
+ "packssdw %%mm4, %%mm4 \n\t"
+ "packssdw %%mm5, %%mm5 \n\t"
+ "packssdw %%mm4, %%mm4 \n\t"
+ "packssdw %%mm5, %%mm5 \n\t"
+ 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;
+}
+#endif
+
+static inline void add_block(int16_t *dst, int stride, int16_t block[64]){
+ int y;
+
+ for(y=0; y<8; y++){
+ *(uint32_t*)&dst[0 + y*stride]+= *(uint32_t*)&block[0 + y*8];
+ *(uint32_t*)&dst[2 + y*stride]+= *(uint32_t*)&block[2 + y*8];
+ *(uint32_t*)&dst[4 + y*stride]+= *(uint32_t*)&block[4 + y*8];
+ *(uint32_t*)&dst[6 + y*stride]+= *(uint32_t*)&block[6 + y*8];
+ }
+}
+
+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])>>6;\
+ 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];
+ 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);
+ }
+ }
+}
+
+#if HAVE_MMX
+static void store_slice_mmx(uint8_t *dst, int16_t *src, int dst_stride, int src_stride, int width, int height, int log2_scale){
+ int y;
+
+ for(y=0; y<height; y++){
+ uint8_t *dst1= dst;
+ int16_t *src1= src;
+ __asm__ volatile(
+ "movq (%3), %%mm3 \n\t"
+ "movq (%3), %%mm4 \n\t"
+ "movd %4, %%mm2 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "punpcklbw %%mm0, %%mm3 \n\t"
+ "punpckhbw %%mm0, %%mm4 \n\t"
+ "psraw %%mm2, %%mm3 \n\t"
+ "psraw %%mm2, %%mm4 \n\t"
+ "movd %5, %%mm2 \n\t"
+ "1: \n\t"
+ "movq (%0), %%mm0 \n\t"
+ "movq 8(%0), %%mm1 \n\t"
+ "paddw %%mm3, %%mm0 \n\t"
+ "paddw %%mm4, %%mm1 \n\t"
+ "psraw %%mm2, %%mm0 \n\t"
+ "psraw %%mm2, %%mm1 \n\t"
+ "packuswb %%mm1, %%mm0 \n\t"
+ "movq %%mm0, (%1) \n\t"
+ "add $16, %0 \n\t"
+ "add $8, %1 \n\t"
+ "cmp %2, %1 \n\t"
+ " jb 1b \n\t"
+ : "+r" (src1), "+r"(dst1)
+ : "r"(dst + width), "r"(dither[y]), "g"(log2_scale), "g"(6-log2_scale)
+ );
+ src += src_stride;
+ dst += dst_stride;
+ }
+// if(width != mmxw)
+// store_slice_c(dst + mmxw, src + mmxw, dst_stride, src_stride, width - mmxw, log2_scale);
+}
+#endif
+
+static void (*store_slice)(uint8_t *dst, int16_t *src, int dst_stride, int src_stride, int width, int height, int log2_scale)= store_slice_c;
+
+static void (*requantize)(int16_t dst[64], int16_t src[64], int qp, uint8_t *permutation)= 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, i;
+ const int count= 1<<p->log2_count;
+ const int stride= is_luma ? p->temp_stride : ((width+16+15)&(~15));
+ uint64_t __attribute__((aligned(16))) block_align[32];
+ int16_t *block = (int16_t *)block_align;
+ int16_t *block2= (int16_t *)(block_align+16);
+
+ 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+8; y+=8){
+ memset(p->temp + (8+y)*stride, 0, 8*stride*sizeof(int16_t));
+ for(x=0; x<width+8; x+=8){
+ const int qps= 3 + is_luma;
+ int qp;
+
+ if(p->qp)
+ qp= p->qp;
+ else{
+ qp= qp_store[ (XMIN(x, width-1)>>qps) + (XMIN(y, height-1)>>qps) * qp_stride];
+ qp = FFMAX(1, norm_qscale(qp, p->mpeg2));
+ }
+ 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*stride;
+ p->dsp.get_pixels(block, p->src + index, stride);
+ p->dsp.fdct(block);
+ requantize(block2, block, qp, p->dsp.idct_permutation);
+ p->dsp.idct(block2);
+ add_block(p->temp + index, stride, block2);
+ }
+ }
+ if(y)
+ store_slice(dst + (y-8)*dst_stride, p->temp + 8 + y*stride, dst_stride, stride, width, XMIN(8, height+8-y), 6-p->log2_count);
+ }
+#if 0
+ for(y=0; y<height; y++){
+ for(x=0; x<width; x++){
+ if((((x>>6) ^ (y>>6)) & 1) == 0)
+ dst[x + y*dst_stride]= p->src[8 + 8*stride + x + y*stride];
+ if((x&63) == 0 || (y&63)==0)
+ dst[x + y*dst_stride] += 128;
+ }
+ }
+#endif
+ //FIXME reorder for better caching
+}
+
+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= malloc(vf->priv->temp_stride*h*sizeof(int16_t));
+ vf->priv->src = 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 | 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(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->mode&4) || !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;
+
+ free(vf->priv->temp);
+ vf->priv->temp= NULL;
+ 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;
+
+ 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 6;
+ case VFCTRL_SET_PP_LEVEL:
+ vf->priv->log2_count= *((unsigned int*)data);
+ 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->avctx= avcodec_alloc_context3(NULL);
+ ff_dsputil_init(&vf->priv->dsp, vf->priv->avctx);
+
+ vf->priv->log2_count= 3;
+
+ if (args) sscanf(args, "%d:%d:%d", &log2c, &vf->priv->qp, &vf->priv->mode);
+
+ if( log2c >=0 && log2c <=6 )
+ vf->priv->log2_count = log2c;
+
+ if(vf->priv->qp < 0)
+ vf->priv->qp = 0;
+
+ switch(vf->priv->mode&3){
+ default:
+ case 0: requantize= hardthresh_c; break;
+ case 1: requantize= softthresh_c; break;
+ }
+
+#if HAVE_MMX
+ if(ff_gCpuCaps.hasMMX){
+ store_slice= store_slice_mmx;
+ switch(vf->priv->mode&3){
+ case 0: requantize= hardthresh_mmx; break;
+ case 1: requantize= softthresh_mmx; break;
+ }
+ }
+#endif
+
+ return 1;
+}
+
+const vf_info_t ff_vf_info_spp = {
+ "simple postprocess",
+ "spp",
+ "Michael Niedermayer",
+ "",
+ vf_open,
+ NULL
+};
diff --git a/libavfilter/libmpcodecs/vf_uspp.c b/libavfilter/libmpcodecs/vf_uspp.c
new file mode 100644
index 0000000..54cc0f9
--- /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
--- /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..6902ee9
--- /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,
+ SWS_BILINEAR, NULL, NULL, NULL);
+ if (!sws_ctx) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Impossible to create scale context for the conversion "
+ "fmt:%s s:%dx%d -> fmt:%s s:%dx%d\n",
+ av_get_pix_fmt_name(src_pix_fmt), src_w, src_h,
+ av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ if ((ret = av_image_alloc(dst_data, dst_linesize, dst_w, dst_h, dst_pix_fmt, 16)) < 0)
+ goto end;
+ ret = 0;
+ sws_scale(sws_ctx, (const uint8_t * const*)src_data, src_linesize, 0, src_h, dst_data, dst_linesize);
+
+end:
+ sws_freeContext(sws_ctx);
+ return ret;
+}
diff --git a/libavfilter/lswsutils.h b/libavfilter/lswsutils.h
new file mode 100644
index 0000000..f5f5320
--- /dev/null
+++ b/libavfilter/lswsutils.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Miscellaneous utilities which make use of the libswscale library
+ */
+
+#ifndef AVFILTER_LSWSUTILS_H
+#define AVFILTER_LSWSUTILS_H
+
+#include "libswscale/swscale.h"
+
+/**
+ * Scale image using libswscale.
+ */
+int ff_scale_image(uint8_t *dst_data[4], int dst_linesize[4],
+ int dst_w, int dst_h, enum AVPixelFormat dst_pix_fmt,
+ uint8_t *const src_data[4], int src_linesize[4],
+ int src_w, int src_h, enum AVPixelFormat src_pix_fmt,
+ void *log_ctx);
+
+#endif /* AVFILTER_LSWSUTILS_H */
diff --git a/libavfilter/opencl_allkernels.c b/libavfilter/opencl_allkernels.c
new file mode 100644
index 0000000..6d80fa8
--- /dev/null
+++ b/libavfilter/opencl_allkernels.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 Wei Gao <weigao@multicorewareinc.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "opencl_allkernels.h"
+#if CONFIG_OPENCL
+#include "libavutil/opencl.h"
+#include "deshake_opencl_kernel.h"
+#include "unsharp_opencl_kernel.h"
+#endif
+
+#define OPENCL_REGISTER_KERNEL_CODE(X, x) \
+ { \
+ if (CONFIG_##X##_FILTER) { \
+ av_opencl_register_kernel_code(ff_kernel_##x##_opencl); \
+ } \
+ }
+
+void ff_opencl_register_filter_kernel_code_all(void)
+{
+ #if CONFIG_OPENCL
+ OPENCL_REGISTER_KERNEL_CODE(DESHAKE, deshake);
+ OPENCL_REGISTER_KERNEL_CODE(UNSHARP, unsharp);
+ #endif
+}
diff --git a/libavfilter/opencl_allkernels.h b/libavfilter/opencl_allkernels.h
new file mode 100644
index 0000000..aca02e0
--- /dev/null
+++ b/libavfilter/opencl_allkernels.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013 Wei Gao <weigao@multicorewareinc.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFILTER_OPENCL_ALLKERNEL_H
+#define AVFILTER_OPENCL_ALLKERNEL_H
+
+#include "avfilter.h"
+#include "config.h"
+
+void ff_opencl_register_filter_kernel_code_all(void);
+
+#endif /* AVFILTER_OPENCL_ALLKERNEL_H */
diff --git a/libavfilter/setpts.c b/libavfilter/setpts.c
index 9fa1df5..97f2621 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;
- av_log(inlink->src, AV_LOG_VERBOSE, "TB:%f\n", setpts->var_values[VAR_TB]);
+ 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 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,7 +218,7 @@ 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 },
@@ -215,9 +263,10 @@ AVFilter avfilter_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,
@@ -249,11 +298,9 @@ AVFilter avfilter_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 3da19b1..f3fe233 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,23 +94,15 @@ 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 },
+ { "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[] = {
{
diff --git a/libavfilter/src_movie.c b/libavfilter/src_movie.c
new file mode 100644
index 0000000..af5db7a
--- /dev/null
+++ b/libavfilter/src_movie.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright (c) 2010 Stefano Sabatini
+ * Copyright (c) 2008 Victor Paesa
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * movie video source
+ *
+ * @todo use direct rendering (no allocation of a new frame)
+ * @todo support a PTS correction mechanism
+ */
+
+#include <float.h>
+
+#include "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->file_name);
+ 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);
+ return 0;
+ }
+ if (!ret)
+ 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);
+
+static av_cold int movie_init(AVFilterContext *ctx)
+{
+ return movie_common_init(ctx);
+}
+
+AVFilter avfilter_avsrc_movie = {
+ .name = "movie",
+ .description = NULL_IF_CONFIG_SMALL("Read from a movie source."),
+ .priv_size = sizeof(MovieContext),
+ .priv_class = &movie_class,
+ .init = movie_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);
+
+static av_cold int amovie_init(AVFilterContext *ctx)
+{
+ return movie_common_init(ctx);
+}
+
+AVFilter avfilter_avsrc_amovie = {
+ .name = "amovie",
+ .description = NULL_IF_CONFIG_SMALL("Read audio from a movie source."),
+ .priv_size = sizeof(MovieContext),
+ .init = amovie_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/transform.c b/libavfilter/transform.c
new file mode 100644
index 0000000..1db8c08
--- /dev/null
+++ b/libavfilter/transform.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2010 Georg Martius <georg.martius@web.de>
+ * Copyright (C) 2010 Daniel G. Taylor <dan@programmer-art.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * transform input video
+ */
+
+#include "libavutil/common.h"
+#include "libavutil/avassert.h"
+
+#include "transform.h"
+
+#define INTERPOLATE_METHOD(name) \
+ static uint8_t name(float x, float y, const uint8_t *src, \
+ int width, int height, int stride, uint8_t def)
+
+#define PIXEL(img, x, y, w, h, stride, def) \
+ ((x) < 0 || (y) < 0) ? (def) : \
+ (((x) >= (w) || (y) >= (h)) ? (def) : \
+ img[(x) + (y) * (stride)])
+
+/**
+ * Nearest neighbor interpolation
+ */
+INTERPOLATE_METHOD(interpolate_nearest)
+{
+ return PIXEL(src, (int)(x + 0.5), (int)(y + 0.5), width, height, stride, def);
+}
+
+/**
+ * Bilinear interpolation
+ */
+INTERPOLATE_METHOD(interpolate_bilinear)
+{
+ int x_c, x_f, y_c, y_f;
+ int v1, v2, v3, v4;
+
+ if (x < -1 || x > width || y < -1 || y > height) {
+ return def;
+ } else {
+ x_f = (int)x;
+ x_c = x_f + 1;
+
+ y_f = (int)y;
+ y_c = y_f + 1;
+
+ v1 = PIXEL(src, x_c, y_c, width, height, stride, def);
+ v2 = PIXEL(src, x_c, y_f, width, height, stride, def);
+ v3 = PIXEL(src, x_f, y_c, width, height, stride, def);
+ v4 = PIXEL(src, x_f, y_f, width, height, stride, def);
+
+ return (v1*(x - x_f)*(y - y_f) + v2*((x - x_f)*(y_c - y)) +
+ v3*(x_c - x)*(y - y_f) + v4*((x_c - x)*(y_c - y)));
+ }
+}
+
+/**
+ * Biquadratic interpolation
+ */
+INTERPOLATE_METHOD(interpolate_biquadratic)
+{
+ int x_c, x_f, y_c, y_f;
+ uint8_t v1, v2, v3, v4;
+ float f1, f2, f3, f4;
+
+ if (x < - 1 || x > width || y < -1 || y > height)
+ return def;
+ else {
+ x_f = (int)x;
+ x_c = x_f + 1;
+ y_f = (int)y;
+ y_c = y_f + 1;
+
+ v1 = PIXEL(src, x_c, y_c, width, height, stride, def);
+ v2 = PIXEL(src, x_c, y_f, width, height, stride, def);
+ v3 = PIXEL(src, x_f, y_c, width, height, stride, def);
+ v4 = PIXEL(src, x_f, y_f, width, height, stride, def);
+
+ f1 = 1 - sqrt((x_c - x) * (y_c - y));
+ f2 = 1 - sqrt((x_c - x) * (y - y_f));
+ f3 = 1 - sqrt((x - x_f) * (y_c - y));
+ f4 = 1 - sqrt((x - x_f) * (y - y_f));
+ return (v1 * f1 + v2 * f2 + v3 * f3 + v4 * f4) / (f1 + f2 + f3 + f4);
+ }
+}
+
+void avfilter_get_matrix(float x_shift, float y_shift, float angle, float zoom, float *matrix) {
+ matrix[0] = zoom * cos(angle);
+ matrix[1] = -sin(angle);
+ matrix[2] = x_shift;
+ matrix[3] = -matrix[1];
+ matrix[4] = matrix[0];
+ matrix[5] = y_shift;
+ matrix[6] = 0;
+ matrix[7] = 0;
+ matrix[8] = 1;
+}
+
+void avfilter_add_matrix(const float *m1, const float *m2, float *result)
+{
+ int i;
+ for (i = 0; i < 9; i++)
+ result[i] = m1[i] + m2[i];
+}
+
+void avfilter_sub_matrix(const float *m1, const float *m2, float *result)
+{
+ int i;
+ for (i = 0; i < 9; i++)
+ result[i] = m1[i] - m2[i];
+}
+
+void avfilter_mul_matrix(const float *m1, float scalar, float *result)
+{
+ int i;
+ for (i = 0; i < 9; i++)
+ result[i] = m1[i] * scalar;
+}
+
+static inline int mirror(int v, int m)
+{
+ while ((unsigned)v > (unsigned)m) {
+ v = -v;
+ if (v < 0)
+ v += 2 * m;
+ }
+ return v;
+}
+
+int avfilter_transform(const uint8_t *src, uint8_t *dst,
+ int src_stride, int dst_stride,
+ int width, int height, const float *matrix,
+ enum InterpolateMethod interpolate,
+ enum FillMethod fill)
+{
+ int x, y;
+ float x_s, y_s;
+ uint8_t def = 0;
+ uint8_t (*func)(float, float, const uint8_t *, int, int, int, uint8_t) = NULL;
+
+ switch(interpolate) {
+ case INTERPOLATE_NEAREST:
+ func = interpolate_nearest;
+ break;
+ case INTERPOLATE_BILINEAR:
+ func = interpolate_bilinear;
+ break;
+ case INTERPOLATE_BIQUADRATIC:
+ func = interpolate_biquadratic;
+ break;
+ default:
+ return AVERROR(EINVAL);
+ }
+
+ for (y = 0; y < height; y++) {
+ for(x = 0; x < width; x++) {
+ x_s = x * matrix[0] + y * matrix[1] + matrix[2];
+ y_s = x * matrix[3] + y * matrix[4] + matrix[5];
+
+ switch(fill) {
+ case FILL_ORIGINAL:
+ def = src[y * src_stride + x];
+ break;
+ case FILL_CLAMP:
+ y_s = av_clipf(y_s, 0, height - 1);
+ x_s = av_clipf(x_s, 0, width - 1);
+ def = src[(int)y_s * src_stride + (int)x_s];
+ break;
+ case FILL_MIRROR:
+ x_s = mirror(x_s, width-1);
+ y_s = mirror(y_s, height-1);
+
+ av_assert2(x_s >= 0 && y_s >= 0);
+ av_assert2(x_s < width && y_s < height);
+ def = src[(int)y_s * src_stride + (int)x_s];
+ }
+
+ dst[y * dst_stride + x] = func(x_s, y_s, src, width, height, src_stride, def);
+ }
+ }
+ return 0;
+}
+
diff --git a/libavfilter/transform.h b/libavfilter/transform.h
new file mode 100644
index 0000000..07436bf
--- /dev/null
+++ b/libavfilter/transform.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2010 Georg Martius <georg.martius@web.de>
+ * Copyright (C) 2010 Daniel G. Taylor <dan@programmer-art.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFILTER_TRANSFORM_H
+#define AVFILTER_TRANSFORM_H
+
+#include <stdint.h>
+
+/**
+ * @file
+ * transform input video
+ *
+ * All matrices are defined as a single 9-item block of contiguous memory. For
+ * example, the identity matrix would be:
+ *
+ * float *matrix = {1, 0, 0,
+ * 0, 1, 0,
+ * 0, 0, 1};
+ */
+
+enum InterpolateMethod {
+ INTERPOLATE_NEAREST, //< Nearest-neighbor (fast)
+ INTERPOLATE_BILINEAR, //< Bilinear
+ INTERPOLATE_BIQUADRATIC, //< Biquadratic (best)
+ INTERPOLATE_COUNT, //< Number of interpolation methods
+};
+
+// Shortcuts for the fastest and best interpolation methods
+#define INTERPOLATE_DEFAULT INTERPOLATE_BILINEAR
+#define INTERPOLATE_FAST INTERPOLATE_NEAREST
+#define INTERPOLATE_BEST INTERPOLATE_BIQUADRATIC
+
+enum FillMethod {
+ FILL_BLANK, //< Fill zeroes at blank locations
+ FILL_ORIGINAL, //< Original image at blank locations
+ FILL_CLAMP, //< Extruded edge value at blank locations
+ FILL_MIRROR, //< Mirrored edge at blank locations
+ FILL_COUNT, //< Number of edge fill methods
+};
+
+// Shortcuts for fill methods
+#define FILL_DEFAULT FILL_ORIGINAL
+
+/**
+ * Get an affine transformation matrix from a given translation, rotation, and
+ * zoom factor. The matrix will look like:
+ *
+ * [ zoom * cos(angle), -sin(angle), x_shift,
+ * sin(angle), zoom * cos(angle), y_shift,
+ * 0, 0, 1 ]
+ *
+ * @param x_shift horizontal translation
+ * @param y_shift vertical translation
+ * @param angle rotation in radians
+ * @param zoom scale percent (1.0 = 100%)
+ * @param matrix 9-item affine transformation matrix
+ */
+void avfilter_get_matrix(float x_shift, float y_shift, float angle, float zoom, float *matrix);
+
+/**
+ * Add two matrices together. result = m1 + m2.
+ *
+ * @param m1 9-item transformation matrix
+ * @param m2 9-item transformation matrix
+ * @param result 9-item transformation matrix
+ */
+void avfilter_add_matrix(const float *m1, const float *m2, float *result);
+
+/**
+ * Subtract one matrix from another. result = m1 - m2.
+ *
+ * @param m1 9-item transformation matrix
+ * @param m2 9-item transformation matrix
+ * @param result 9-item transformation matrix
+ */
+void avfilter_sub_matrix(const float *m1, const float *m2, float *result);
+
+/**
+ * Multiply a matrix by a scalar value. result = m1 * scalar.
+ *
+ * @param m1 9-item transformation matrix
+ * @param scalar a number
+ * @param result 9-item transformation matrix
+ */
+void avfilter_mul_matrix(const float *m1, float scalar, float *result);
+
+/**
+ * Do an affine transformation with the given interpolation method. This
+ * multiplies each vector [x,y,1] by the matrix and then interpolates to
+ * get the final value.
+ *
+ * @param src source image
+ * @param dst destination image
+ * @param src_stride source image line size in bytes
+ * @param dst_stride destination image line size in bytes
+ * @param width image width in pixels
+ * @param height image height in pixels
+ * @param matrix 9-item affine transformation matrix
+ * @param interpolate pixel interpolation method
+ * @param fill edge fill method
+ * @return negative on error
+ */
+int avfilter_transform(const uint8_t *src, uint8_t *dst,
+ int src_stride, int dst_stride,
+ int width, int height, const float *matrix,
+ enum InterpolateMethod interpolate,
+ enum FillMethod fill);
+
+#endif /* AVFILTER_TRANSFORM_H */
diff --git a/libavfilter/trim.c b/libavfilter/trim.c
index 9a0544d..34963ae 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
*/
@@ -89,17 +89,17 @@ static int config_input(AVFilterLink *inlink)
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));
+ int64_t start_pts = lrint(s->start_time / av_q2d(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));
+ int64_t end_pts = lrint(s->end_time / av_q2d(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 = lrint(s->duration / av_q2d(tb));
return 0;
}
@@ -192,7 +192,7 @@ 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 "
@@ -355,7 +355,7 @@ 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 "
diff --git a/libavfilter/unsharp.h b/libavfilter/unsharp.h
new file mode 100644
index 0000000..c225929
--- /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
--- /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
--- /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
--- /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 e8dc875..19e2389 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
*/
@@ -29,8 +29,8 @@
#include "libavutil/avutil.h"
#define LIBAVFILTER_VERSION_MAJOR 3
-#define LIBAVFILTER_VERSION_MINOR 9
-#define LIBAVFILTER_VERSION_MICRO 0
+#define LIBAVFILTER_VERSION_MINOR 68
+#define LIBAVFILTER_VERSION_MICRO 101
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
LIBAVFILTER_VERSION_MINOR, \
@@ -40,6 +40,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
@@ -52,12 +54,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
diff --git a/libavfilter/vf_alphamerge.c b/libavfilter/vf_alphamerge.c
new file mode 100644
index 0000000..644c7f4
--- /dev/null
+++ b/libavfilter/vf_alphamerge.c
@@ -0,0 +1,208 @@
+/*
+ * 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,
+ .get_video_buffer = ff_null_get_video_buffer,
+ .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 avfilter_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 50b4a7f..f8ed427 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"
@@ -36,25 +38,42 @@
typedef struct {
const AVClass *class;
AVRational aspect;
+ 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->aspect = 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->aspect = av_d2q(num / s->aspect_den, s->max);
+ } else
+#endif
+ if (s->ratio_str) {
+ ret = av_parse_ratio(&s->aspect, s->ratio_str, s->max, 0, ctx);
+ if (ret < 0 || s->aspect.num < 0 || s->aspect.den <= 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Invalid string '%s' for aspect ratio\n", s->ratio_str);
+ return AVERROR(EINVAL);
+ }
}
-
return 0;
}
-#endif
static int filter_frame(AVFilterLink *link, AVFrame *frame)
{
@@ -65,47 +84,55 @@ 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 = s->aspect;
+ AVRational dar = s->aspect, old_dar;
+ AVRational old_sar = inlink->sample_aspect_ratio;
if (s->aspect.num && s->aspect.den) {
av_reduce(&s->aspect.num, &s->aspect.den,
s->aspect.num * inlink->h,
- s->aspect.den * inlink->w, 100);
+ s->aspect.den * inlink->w, INT_MAX);
inlink->sample_aspect_ratio = s->aspect;
} else {
inlink->sample_aspect_ratio = (AVRational){ 1, 1 };
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(aspect), 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[] = {
{
@@ -129,11 +156,7 @@ static const AVFilterPad avfilter_vf_setdar_outputs[] = {
AVFilter avfilter_vf_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,
@@ -141,34 +164,40 @@ AVFilter avfilter_vf_setdar = {
.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->aspect;
+ compute_dar(&old_dar, old_sar, inlink->w, inlink->h);
+ compute_dar(&dar, s->aspect, 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(aspect), 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[] = {
{
@@ -192,11 +221,7 @@ static const AVFilterPad avfilter_vf_setsar_outputs[] = {
AVFilter avfilter_vf_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,
@@ -204,4 +229,5 @@ AVFilter avfilter_vf_setsar = {
.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..6b4cdd0
--- /dev/null
+++ b/libavfilter/vf_bbox.c
@@ -0,0 +1,107 @@
+/*
+ * 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/pixdesc.h"
+#include "libavutil/timestamp.h"
+#include "avfilter.h"
+#include "bbox.h"
+#include "internal.h"
+
+typedef struct {
+ unsigned int frame;
+} BBoxContext;
+
+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;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ BBoxContext *bbox = ctx->priv;
+ FFBoundingBox box;
+ int has_bbox, w, h;
+
+ has_bbox =
+ ff_calculate_bounding_box(&box,
+ frame->data[0], frame->linesize[0],
+ inlink->w, inlink->h, 16);
+ w = box.x2 - box.x1 + 1;
+ h = box.y2 - box.y1 + 1;
+
+ av_log(ctx, AV_LOG_INFO,
+ "n:%d pts:%s pts_time:%s", bbox->frame,
+ av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base));
+
+ if (has_bbox) {
+ 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");
+
+ bbox->frame++;
+ 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 avfilter_vf_bbox = {
+ .name = "bbox",
+ .description = NULL_IF_CONFIG_SMALL("Compute bounding box for each frame."),
+ .priv_size = sizeof(BBoxContext),
+ .query_formats = query_formats,
+ .inputs = bbox_inputs,
+ .outputs = bbox_outputs,
+};
diff --git a/libavfilter/vf_blackdetect.c b/libavfilter/vf_blackdetect.c
new file mode 100644
index 0000000..ddbf082
--- /dev/null
+++ b/libavfilter/vf_blackdetect.c
@@ -0,0 +1,202 @@
+/*
+ * 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_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_YUV410P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NV12,
+ AV_PIX_FMT_NV21, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV411P,
+ 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,
+ .get_video_buffer = ff_null_get_video_buffer,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad blackdetect_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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 1b1e796..b83e1f8 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,8 +32,8 @@
#include "libavutil/internal.h"
#include "libavutil/opt.h"
-
#include "avfilter.h"
+#include "internal.h"
#include "formats.h"
#include "internal.h"
#include "video.h"
@@ -44,6 +44,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 +73,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,21 +90,18 @@ 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 },
+ 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[] = {
{
diff --git a/libavfilter/vf_blend.c b/libavfilter/vf_blend.c
new file mode 100644
index 0000000..b0987ef
--- /dev/null
+++ b/libavfilter/vf_blend.c
@@ -0,0 +1,469 @@
+/*
+ * 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 "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 values[VAR_VARS_NB];
+ 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 height, struct FilterParams *param);
+} FilterParams;
+
+typedef struct {
+ const AVClass *class;
+ struct FFBufQueue queue_top;
+ struct FFBufQueue queue_bottom;
+ int hsub, vsub; ///< chroma subsampling values
+ int nb_planes;
+ int frame_requested;
+ 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},
+ { 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 height, FilterParams *param)
+{
+ av_image_copy_plane(dst, dst_linesize, top, top_linesize, width, height);
+}
+
+#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 height, FilterParams *param) \
+{ \
+ double opacity = param->opacity; \
+ int i, j; \
+ \
+ for (i = 0; i < height; 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 height,
+ FilterParams *param)
+{
+ AVExpr *e = param->e;
+ double *values = param->values;
+ int y, x;
+
+ for (y = 0; y < height; 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 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;
+ }
+ }
+
+ 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_YUV444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, 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);
+
+ 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);
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ BlendContext *b = ctx->priv;
+ int i;
+
+ ff_bufqueue_discard_all(&b->queue_top);
+ ff_bufqueue_discard_all(&b->queue_bottom);
+
+ for (i = 0; i < FF_ARRAY_ELEMS(b->params); i++)
+ av_expr_free(b->params[i].e);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ BlendContext *b = ctx->priv;
+ int in, ret;
+
+ b->frame_requested = 1;
+ while (b->frame_requested) {
+ in = ff_bufqueue_peek(&b->queue_top, 0) ? BOTTOM : TOP;
+ ret = ff_request_frame(ctx->inputs[in]);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static void blend_frame(AVFilterContext *ctx,
+ AVFrame *top_buf,
+ AVFrame *bottom_buf,
+ AVFrame *dst_buf)
+{
+ BlendContext *b = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ FilterParams *param;
+ int plane;
+
+ 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);
+ uint8_t *dst = dst_buf->data[plane];
+ uint8_t *top = top_buf->data[plane];
+ uint8_t *bottom = bottom_buf->data[plane];
+
+ param = &b->params[plane];
+ param->values[VAR_N] = inlink->frame_count;
+ param->values[VAR_T] = dst_buf->pts == AV_NOPTS_VALUE ? NAN : dst_buf->pts * av_q2d(inlink->time_base);
+ param->values[VAR_W] = outw;
+ param->values[VAR_H] = outh;
+ param->values[VAR_SW] = outw / dst_buf->width;
+ param->values[VAR_SH] = outh / dst_buf->height;
+ param->blend(top, top_buf->linesize[plane],
+ bottom, bottom_buf->linesize[plane],
+ dst, dst_buf->linesize[plane], outw, outh, param);
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ BlendContext *b = ctx->priv;
+
+ int ret = 0;
+ int is_bottom = (inlink == ctx->inputs[BOTTOM]);
+ struct FFBufQueue *queue =
+ (is_bottom ? &b->queue_bottom : &b->queue_top);
+ ff_bufqueue_add(ctx, queue, buf);
+
+ while (1) {
+ AVFrame *top_buf, *bottom_buf, *out_buf;
+
+ if (!ff_bufqueue_peek(&b->queue_top, 0) ||
+ !ff_bufqueue_peek(&b->queue_bottom, 0)) break;
+
+ top_buf = ff_bufqueue_get(&b->queue_top);
+ bottom_buf = ff_bufqueue_get(&b->queue_bottom);
+
+ if (!ctx->is_disabled) {
+ out_buf = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out_buf)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out_buf, top_buf);
+ blend_frame(ctx, top_buf, bottom_buf, out_buf);
+ } else {
+ out_buf = av_frame_clone(top_buf);
+ if (!out_buf)
+ return AVERROR(ENOMEM);
+ }
+
+ b->frame_requested = 0;
+ ret = ff_filter_frame(outlink, out_buf);
+ av_frame_free(&top_buf);
+ av_frame_free(&bottom_buf);
+ }
+ return ret;
+}
+
+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 avfilter_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,
+};
diff --git a/libavfilter/vf_boxblur.c b/libavfilter/vf_boxblur.c
index 44c148b..8a59890 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 };
@@ -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 },
-static const AVClass boxblur_class = {
- .class_name = "boxblur",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
+ { "alpha_radius", "Radius of the alpha blurring box", OFFSET(alpha_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "ar", "Radius of the alpha blurring box", OFFSET(alpha_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "alpha_power", "How many times should the boxblur be applied to alpha", OFFSET(alpha_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
+ { "ap", "How many times should the boxblur be applied to alpha", OFFSET(alpha_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
+
+ { NULL }
};
+AVFILTER_DEFINE_CLASS(boxblur);
+
static const AVFilterPad avfilter_vf_boxblur_inputs[] = {
{
.name = "default",
@@ -384,4 +383,5 @@ AVFilter avfilter_vf_boxblur = {
.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..ca6c781
--- /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 avfilter_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..9c0044d
--- /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 avfilter_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..7db0bd8
--- /dev/null
+++ b/libavfilter/vf_colormatrix.c
@@ -0,0 +1,389 @@
+/*
+ * 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 avfilter_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 f533959..b9859c4 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);
diff --git a/libavfilter/vf_crop.c b/libavfilter/vf_crop.c
index bf9e85f..4edb7cf 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,9 +80,12 @@ 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;
@@ -149,34 +157,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 +198,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);
@@ -199,8 +210,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) {
@@ -228,6 +248,7 @@ static int config_output(AVFilterLink *link)
link->w = s->w;
link->h = s->h;
+ link->sample_aspect_ratio = s->out_sar;
return 0;
}
@@ -242,8 +263,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);
@@ -262,9 +286,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];
@@ -284,29 +308,24 @@ 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[] = {
{
diff --git a/libavfilter/vf_cropdetect.c b/libavfilter/vf_cropdetect.c
index 60b2004..28ae887 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"
@@ -194,20 +192,17 @@ 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 },
+ { "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[] = {
{
@@ -235,10 +230,8 @@ AVFilter avfilter_vf_cropdetect = {
.priv_size = sizeof(CropDetectContext),
.priv_class = &cropdetect_class,
.init = init,
-
.query_formats = query_formats,
-
.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..6356cef
--- /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 avfilter_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..8de203c
--- /dev/null
+++ b/libavfilter/vf_dctdnoiz.c
@@ -0,0 +1,431 @@
+/*
+ * 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;
+ for (x = 0; x < BSIZE; x++) {
+ *line *= x == 0 ? 1. / sqrt(BSIZE) : sqrt(2. / BSIZE);
+ *column = *line++;
+ column += BSIZE;
+ }
+ }
+
+ column = ctx->tmp_block;
+ for (x = 0; x < BSIZE; x++) {
+ av_dct_calc(ctx->dct, column);
+ for (y = 0; y < BSIZE; y++)
+ column[y] *= y == 0 ? 1. / sqrt(BSIZE) : 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++) {
+ for (x = 0; x < BSIZE; x++)
+ block[x] *= x == 0 ? sqrt(BSIZE) : 1./sqrt(2. / BSIZE);
+ av_dct_calc(ctx->idct, block);
+ block += BSIZE;
+ }
+
+ block = ctx->block;
+ for (y = 0; y < BSIZE; y++) {
+ for (x = 0; x < BSIZE; x++) {
+ tmp[x] = block[x*BSIZE + y];
+ tmp[x] *= x == 0 ? sqrt(BSIZE) : 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 avfilter_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..8767d5f
--- /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 ? 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_YUV411P, AV_PIX_FMT_YUV410P,
+ 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;
+ 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 avfilter_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 4c917ba..4bf0867 100644
--- a/libavfilter/vf_delogo.c
+++ b/libavfilter/vf_delogo.c
@@ -2,20 +2,20 @@
* Copyright (c) 2002 Jindrich Makovicka <makovick@gmail.com>
* 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.
*/
@@ -90,18 +90,22 @@ static void apply_delogo(uint8_t *dst, int dst_linesize,
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 =
+ (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;
if (y >= logo_y+band && y < logo_y+logo_h-band &&
@@ -136,7 +140,7 @@ 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 },
@@ -149,20 +153,11 @@ static const AVOption delogo_options[]= {
{ 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 +182,12 @@ static av_cold int init(AVFilterContext *ctx)
CHECK_UNSET_OPT(w);
CHECK_UNSET_OPT(h);
- if (s->show)
+ if (s->band < 0 || s->show) {
+ s->show = 1;
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;
@@ -223,8 +220,6 @@ 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++) {
@@ -233,9 +228,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
apply_delogo(out->data[plane], out->linesize[plane],
in ->data[plane], in ->linesize[plane],
- inlink->w>>hsub, inlink->h>>vsub,
+ FF_CEIL_RSHIFT(inlink->w, hsub),
+ FF_CEIL_RSHIFT(inlink->h, vsub),
s->x>>hsub, s->y>>vsub,
- s->w>>hsub, s->h>>vsub,
+ FF_CEIL_RSHIFT(s->w, hsub),
+ FF_CEIL_RSHIFT(s->h, vsub),
s->band>>FFMIN(hsub, vsub),
s->show, direct);
}
@@ -274,4 +271,5 @@ AVFilter avfilter_vf_delogo = {
.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..fd72132
--- /dev/null
+++ b/libavfilter/vf_deshake.c
@@ -0,0 +1,575 @@
+/*
+ * Copyright (C) 2010 Georg Martius <georg.martius@web.de>
+ * Copyright (C) 2010 Daniel G. Taylor <dan@programmer-art.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * fast deshake / depan video filter
+ *
+ * SAD block-matching motion compensation to fix small changes in
+ * horizontal and/or vertical shift. This filter helps remove camera shake
+ * from hand-holding a camera, bumping a tripod, moving on a vehicle, etc.
+ *
+ * Algorithm:
+ * - For each frame with one previous reference frame
+ * - For each block in the frame
+ * - If contrast > threshold then find likely motion vector
+ * - For all found motion vectors
+ * - Find most common, store as global motion vector
+ * - Find most likely rotation angle
+ * - Transform image along global motion
+ *
+ * TODO:
+ * - Fill frame edges based on previous/next reference frames
+ * - Fill frame edges by stretching image near the edges?
+ * - Can this be done quickly and look decent?
+ *
+ * Dark Shikari links to http://wiki.videolan.org/SoC_x264_2010#GPU_Motion_Estimation_2
+ * for an algorithm similar to what could be used here to get the gmv
+ * It requires only a couple diamond searches + fast downscaling
+ *
+ * Special thanks to Jason Kotenko for his help with the algorithm and my
+ * inability to see simple errors in C code.
+ */
+
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+#include "libavutil/common.h"
+#include "libavutil/mem.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "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 = 0;
+ 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; i <= 15; i++) {
+ 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->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 avfilter_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 ab4537a..9189e4d 100644
--- a/libavfilter/vf_drawbox.c
+++ b/libavfilter/vf_drawbox.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Affine Systems, Inc (Michael Sullivan, Bobby Impollonia)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,9 +38,10 @@ enum { Y, U, V, A };
typedef struct {
const AVClass *class;
- int x, y, w, h;
+ int x, y, w, h, thickness;
char *color_str;
unsigned char yuv_color[4];
+ int invert_color; ///< invert luma color
int vsub, hsub; ///< chroma subsampling
} DrawBoxContext;
@@ -49,20 +50,24 @@ 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,
@@ -86,7 +91,7 @@ static int config_input(AVFilterLink *inlink)
if (s->h == 0) s->h = inlink->h;
av_log(inlink->dst, AV_LOG_VERBOSE, "x:%d y:%d w:%d h:%d color:0x%02X%02X%02X%02X\n",
- s->w, s->y, s->w, s->h,
+ 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;
@@ -105,14 +110,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 ((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 (s->invert_color) {
+ for (x = FFMAX(xb, 0); x < xb + s->w && x < frame->width; x++)
+ if ((y - yb < s->thickness-1) || (yb + s->h - y < s->thickness) ||
+ (x - xb < s->thickness-1) || (xb + s->w - 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 < s->thickness-1) || (yb + s->h - y < s->thickness) ||
+ (x - xb < s->thickness-1) || (xb + s->w - 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,22 +133,23 @@ 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[] = {
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption drawbox_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), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
+ { "w", "Width of the box", OFFSET(w), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
{ "height", "Height of the box", OFFSET(h), 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 },
+ { "h", "Height of the box", OFFSET(h), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
+ { "color", "Color of the box", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, .flags = FLAGS },
+ { "c", "Color of the box", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, .flags = FLAGS },
+ { "thickness", "set the box maximum thickness", OFFSET(thickness), AV_OPT_TYPE_INT, {.i64=4}, 0, INT_MAX, FLAGS },
+ { "t", "set the box maximum thickness", OFFSET(thickness), AV_OPT_TYPE_INT, {.i64=4}, 0, INT_MAX, FLAGS },
{ NULL },
};
-static const AVClass drawbox_class = {
- .class_name = "drawbox",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(drawbox);
static const AVFilterPad avfilter_vf_drawbox_inputs[] = {
{
@@ -168,4 +181,5 @@ AVFilter avfilter_vf_drawbox = {
.query_formats = query_formats,
.inputs = avfilter_vf_drawbox_inputs,
.outputs = avfilter_vf_drawbox_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
};
diff --git a/libavfilter/vf_drawgrid.c b/libavfilter/vf_drawgrid.c
new file mode 100644
index 0000000..f1ab6c4
--- /dev/null
+++ b/libavfilter/vf_drawgrid.c
@@ -0,0 +1,206 @@
+/*
+ * 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 FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Grid drawing filter.
+ * Code derived from drawbox filter.
+ */
+
+#include "libavutil/colorspace.h"
+#include "libavutil/common.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/parseutils.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+enum { Y, U, V, A };
+
+typedef struct {
+ const AVClass *class;
+ int x, y, w, h, thickness;
+ char *color_str;
+ unsigned char yuv_color[4];
+ int invert_color; ///< invert luma color
+ int vsub, hsub; ///< chroma subsampling
+} DrawGridContext;
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ DrawGridContext *drawgrid = ctx->priv;
+ uint8_t rgba_color[4];
+
+ if (!strcmp(drawgrid->color_str, "invert"))
+ drawgrid->invert_color = 1;
+ else if (av_parse_color(rgba_color, drawgrid->color_str, -1, ctx) < 0)
+ return AVERROR(EINVAL);
+
+ if (!drawgrid->invert_color) {
+ drawgrid->yuv_color[Y] = RGB_TO_Y_CCIR(rgba_color[0], rgba_color[1], rgba_color[2]);
+ drawgrid->yuv_color[U] = RGB_TO_U_CCIR(rgba_color[0], rgba_color[1], rgba_color[2], 0);
+ drawgrid->yuv_color[V] = RGB_TO_V_CCIR(rgba_color[0], rgba_color[1], rgba_color[2], 0);
+ drawgrid->yuv_color[A] = rgba_color[3];
+ }
+
+ return 0;
+}
+
+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_YUVJ444P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
+ AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUVJ440P,
+ AV_PIX_FMT_NONE
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ return 0;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ DrawGridContext *drawgrid = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ drawgrid->hsub = desc->log2_chroma_w;
+ drawgrid->vsub = desc->log2_chroma_h;
+
+ if (drawgrid->w == 0) drawgrid->w = inlink->w - drawgrid->thickness;
+ if (drawgrid->h == 0) drawgrid->h = inlink->h - drawgrid->thickness;
+
+ av_log(inlink->dst, AV_LOG_VERBOSE, "x:%d y:%d w:%d h:%d color:0x%02X%02X%02X%02X\n",
+ drawgrid->x, drawgrid->y, drawgrid->w, drawgrid->h,
+ drawgrid->yuv_color[Y], drawgrid->yuv_color[U], drawgrid->yuv_color[V], drawgrid->yuv_color[A]);
+
+ return 0;
+}
+
+static av_pure av_always_inline int pixel_belongs_to_grid(DrawGridContext *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 filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ DrawGridContext *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);
+}
+
+#define OFFSET(x) offsetof(DrawGridContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption drawgrid_options[] = {
+ { "x", "set horizontal offset", OFFSET(x), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
+ { "y", "set vertical offset", OFFSET(y), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
+ { "width", "set width of grid cell", OFFSET(w), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
+ { "w", "set width of grid cell", OFFSET(w), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
+ { "height", "set height of grid cell", OFFSET(h), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
+ { "h", "set height of grid cell", OFFSET(h), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_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(thickness), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, FLAGS },
+ { "t", "set grid line thickness", OFFSET(thickness), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(drawgrid);
+
+static const AVFilterPad avfilter_vf_drawgrid_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ .needs_writable = 1,
+ },
+ { NULL }
+};
+
+static const AVFilterPad avfilter_vf_drawgrid_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_vf_drawgrid = {
+ .name = "drawgrid",
+ .description = NULL_IF_CONFIG_SMALL("Draw a colored grid on the input video."),
+ .priv_size = sizeof(DrawGridContext),
+ .priv_class = &drawgrid_class,
+ .init = init,
+ .query_formats = query_formats,
+ .inputs = avfilter_vf_drawgrid_inputs,
+ .outputs = avfilter_vf_drawgrid_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index ab867be..f0ff5aa 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,114 @@ 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;
+ char *draw_expr; ///< expression for draw
+ AVExpr *draw_pexpr; ///< parsed expression for draw
int draw; ///< set to zero to prevent drawing
AVLFG prng; ///< random
+ char *tc_opt_string; ///< specified timecode option string
+ AVRational tc_rate; ///< frame rate for timecode
+ AVTimecode tc; ///< timecode context
+ int tc24hmax; ///< 1 if timecode is wrapped to 24 hours, 0 otherwise
+ int reload; ///< reload text file for each frame
} 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_string), AV_OPT_TYPE_STRING, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"boxcolor", "set box color", OFFSET(boxcolor_string), AV_OPT_TYPE_STRING, {.str="white"}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"shadowcolor", "set shadow color", OFFSET(shadowcolor_string), AV_OPT_TYPE_STRING, {.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},
+ {"draw", "if false do not draw", OFFSET(draw_expr), AV_OPT_TYPE_STRING, {.str="1"}, CHAR_MIN, CHAR_MAX, FLAGS},
+
+ {"expansion", "set the expansion mode", OFFSET(exp_mode), AV_OPT_TYPE_INT, {.i64=EXP_NORMAL}, 0, 2, FLAGS, "expansion"},
+ {"none", "set no expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NONE}, 0, 0, FLAGS, "expansion"},
+ {"normal", "set normal expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NORMAL}, 0, 0, FLAGS, "expansion"},
+ {"strftime", "set strftime expansion (deprecated)", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_STRFTIME}, 0, 0, FLAGS, "expansion"},
+
+ {"timecode", "set initial timecode", OFFSET(tc_opt_string), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"tc24hmax", "set 24 hours max (timecode only)", OFFSET(tc24hmax), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
+ {"timecode_rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
+ {"r", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
+ {"rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
+ {"reload", "reload text file for each frame", OFFSET(reload), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
+ {"fix_bounds", "if true, check and fix text coords to avoid clipping", OFFSET(fix_bounds), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS},
/* 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" },
@@ -184,16 +222,7 @@ static const AVOption drawtext_options[]= {
{ 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,59 +309,168 @@ 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 (!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->reload && !s->textfile)
+ av_log(ctx, AV_LOG_WARNING, "No file to reload\n");
+
+ 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 (!s->text) {
av_log(ctx, AV_LOG_ERROR,
- "Either text or a valid file must be provided\n");
+ "Either text, a valid file or a timecode must be provided\n");
return AVERROR(EINVAL);
}
- if ((err = av_parse_color(s->fontcolor_rgba, s->fontcolor_string, -1, ctx))) {
+ 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 ((err = av_parse_color(s->boxcolor_rgba, s->boxcolor_string, -1, ctx))) {
+ 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 ((err = av_parse_color(s->shadowcolor_rgba, s->shadowcolor_string, -1, ctx))) {
+ if ((err = av_parse_color(s->shadowcolor.rgba, s->shadowcolor_string, -1, ctx))) {
av_log(ctx, AV_LOG_ERROR,
"Invalid shadow color '%s'\n", s->shadowcolor_string);
return err;
@@ -344,12 +482,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 +499,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,21 +533,23 @@ static int glyph_enu_free(void *opaque, void *elem)
static av_cold void uninit(AVFilterContext *ctx)
{
DrawTextContext *s = ctx->priv;
- int i;
- av_freep(&s->expanded_text);
+ av_expr_free(s->x_pexpr); s->x_pexpr = NULL;
+ av_expr_free(s->y_pexpr); s->y_pexpr = NULL;
+ av_expr_free(s->draw_pexpr); s->draw_pexpr = NULL;
+
av_freep(&s->positions);
+ s->nb_positions = 0;
+
+
av_tree_enumerate(s->glyphs, NULL, NULL, glyph_enu_free);
av_tree_destroy(s->glyphs);
- s->glyphs = 0;
+ s->glyphs = NULL;
+
FT_Done_Face(s->face);
FT_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)
@@ -422,295 +557,244 @@ 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;
+ if (!s->reinit)
+ s->var_values[VAR_N] = 0;
+ 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;
-#endif
+ 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->draw_pexpr, s->draw_expr, var_names,
+ NULL, NULL, fun2_names, fun2, 0, ctx)) < 0)
- 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;
- }
- }
+ return AVERROR(EINVAL);
- /* load and cache glyphs */
- for (i = 0, p = text; *p; i++) {
- GET_UTF8(code, *p++, continue;);
+ return 0;
+}
- /* 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;
- }
+static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
+{
+ DrawTextContext *s = ctx->priv;
- y_min = FFMIN(glyph->bbox.yMin, y_min);
- y_max = FFMAX(glyph->bbox.yMax, y_max);
+ if (!strcmp(cmd, "reinit")) {
+ int ret;
+ uninit(ctx);
+ s->reinit = 1;
+ if ((ret = init(ctx)) < 0)
+ return ret;
+ return config_input(ctx->inputs[0]);
}
- text_height = y_max - y_min;
- baseline = y_max;
- /* compute and save position for each glyph */
- glyph = NULL;
- for (i = 0, p = text; *p; i++) {
- GET_UTF8(code, *p++, continue;);
-
- /* skip the \n in the sequence \r\n */
- if (prev_code == '\r' && code == '\n')
- continue;
+ return AVERROR(ENOSYS);
+}
- prev_code = code;
- if (is_newline(code)) {
- str_w = FFMAX(str_w, x - s->x);
- y += text_height;
- x = 0;
- continue;
- }
+static int func_pict_type(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
+{
+ DrawTextContext *s = ctx->priv;
- /* get glyph */
- prev_glyph = glyph;
- dummy.code = code;
- glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
+ av_bprintf(bp, "%c", av_get_picture_type_char(s->var_values[VAR_PICT_TYPE]));
+ return 0;
+}
- /* 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;
- }
+static int func_pts(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
+{
+ DrawTextContext *s = ctx->priv;
- if (x + glyph->bbox.xMax >= width) {
- str_w = FFMAX(str_w, x);
- y += text_height;
- x = 0;
- }
+ av_bprintf(bp, "%.6f", s->var_values[VAR_T]);
+ return 0;
+}
- /* 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;
- }
+static int func_frame_num(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
+{
+ DrawTextContext *s = ctx->priv;
- str_w = FFMIN(width - 1, FFMAX(str_w, x));
- y = FFMIN(y + text_height, height - 1);
+ av_bprintf(bp, "%d", (int)s->var_values[VAR_N]);
+ return 0;
+}
- s->w = str_w;
- s->var_values[VAR_TEXT_W] = s->var_values[VAR_TW] = s->w;
- s->h = y;
- s->var_values[VAR_TEXT_H] = s->var_values[VAR_TH] = s->h;
+#if !HAVE_LOCALTIME_R
+static void localtime_r(const time_t *t, struct tm *tm)
+{
+ *tm = *localtime(t);
+}
+#endif
+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;
}
-
-static int config_input(AVFilterLink *inlink)
+static int func_eval_expr(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
{
- AVFilterContext *ctx = inlink->dst;
DrawTextContext *s = ctx->priv;
- const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
+ double res;
int ret;
- s->hsub = pix_desc->log2_chroma_w;
- s->vsub = pix_desc->log2_chroma_h;
-
- 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_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;
-
- s->var_values[VAR_X] = 0;
- s->var_values[VAR_Y] = 0;
- s->var_values[VAR_N] = 0;
- s->var_values[VAR_T] = NAN;
-
- av_lfg_init(&s->prng, av_get_random_seed());
-
- 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 ((ret =
- ff_fill_line_with_color(s->box_line, s->pixel_step,
- inlink->w, s->boxcolor,
- inlink->format, s->boxcolor_rgba,
- &s->is_packed_rgb, s->rgba_map)) < 0)
- return ret;
-
- if (!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];
- }
-
- 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 },
+};
-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;
@@ -729,15 +813,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;
@@ -747,97 +831,186 @@ 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 = s->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);
+ s->draw = av_expr_eval(s->draw_pexpr, s->var_values, &s->prng);
+
+ if(!s->draw)
+ return 0;
+
+ 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->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;
- 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[] = {
@@ -871,4 +1044,5 @@ AVFilter avfilter_vf_drawtext = {
.inputs = avfilter_vf_drawtext_inputs,
.outputs = avfilter_vf_drawtext_outputs,
+ .process_command = command,
};
diff --git a/libavfilter/vf_edgedetect.c b/libavfilter/vf_edgedetect.c
new file mode 100644
index 0000000..4c50d9f
--- /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 avfilter_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..3c629d7
--- /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->format_count) {
+ 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->format_count; 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 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 avfilter_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 int init_alphaextract(AVFilterContext *ctx)
+{
+ ExtractPlanesContext *e = ctx->priv;
+
+ e->requested_planes = PLANE_A;
+
+ return init(ctx);
+}
+
+AVFilter avfilter_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 9f3a602..a24fb2a 100644
--- a/libavfilter/vf_fade.c
+++ b/libavfilter/vf_fade.c
@@ -2,20 +2,20 @@
* Copyright (c) 2010 Brandon Mintern
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,14 +25,27 @@
* based heavily on vf_negate.c by Bobby Bingham
*/
+#include "libavutil/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 "internal.h"
#include "formats.h"
#include "internal.h"
#include "video.h"
+#define R 0
+#define G 1
+#define B 2
+#define A 3
+
+#define Y 0
+#define U 1
+#define V 2
+
#define FADE_IN 0
#define FADE_OUT 1
@@ -41,8 +54,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 +69,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 +100,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 +111,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,73 +127,162 @@ static int config_props(AVFilterLink *inlink)
s->vsub = pixdesc->log2_chroma_h;
s->bpp = av_get_bits_per_pixel(pixdesc) >> 3;
+ s->alpha &= pixdesc->flags & AV_PIX_FMT_FLAG_ALPHA;
+ s->is_packed_rgb = ff_fill_rgba_map(s->rgba_map, inlink->format) >= 0;
+
+ /* use CCIR601/709 black level for studio-level pixel non-alpha components */
+ s->black_level =
+ ff_fmt_is_in(inlink->format, studio_level_pix_fmts) && !s->alpha ? 16 : 0;
+ /* 32768 = 1 << 15, it is an integer representation
+ * of 0.5 and is for rounding. */
+ s->black_level_scaled = (s->black_level << 16) + 32768;
return 0;
}
+static void fade_plane(int y, int h, int w,
+ int fade_factor, int black_level, int black_level_scaled,
+ uint8_t offset, uint8_t step, int bytes_per_plane,
+ uint8_t *data, int line_size)
+{
+ uint8_t *p;
+ int i, j;
+
+ /* luma, alpha or rgb plane */
+ for (i = 0; i < h; i++) {
+ p = data + offset + (y+i) * line_size;
+ for (j = 0; j < w * bytes_per_plane; j++) {
+ /* s->factor is using 16 lower-order bits for decimal places. */
+ *p = ((*p - black_level) * fade_factor + black_level_scaled) >> 16;
+ p+=step;
+ }
+ }
+}
+
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
{
FadeContext *s = inlink->dst->priv;
uint8_t *p;
int i, j, plane;
+ 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 */
- for (i = 0; i < frame->height; i++) {
- p = frame->data[0] + i * frame->linesize[0];
- for (j = 0; j < inlink->w * s->bpp; 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->factor + 32768) >> 16;
- p++;
+ // 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 (frame->data[1] && frame->data[2]) {
- /* chroma planes */
- for (plane = 1; plane < 3; plane++) {
- for (i = 0; i < frame->height; i++) {
- p = frame->data[plane] + (i >> s->vsub) * frame->linesize[plane];
- for (j = 0; j < inlink->w >> s->hsub; j++) {
- /* 8421367 = ((128 << 1) + 1) << 15. It is an integer
- * representation of 128.5. The .5 is for rounding
- * purposes. */
- *p = ((*p - 128) * s->factor + 8421367) >> 16;
- p++;
+ 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) {
+ // alpha only
+ plane = s->is_packed_rgb ? 0 : A; // alpha is on plane 0 for packed formats
+ // or plane 3 for planar formats
+ fade_plane(0, frame->height, inlink->w,
+ s->factor, s->black_level, s->black_level_scaled,
+ s->is_packed_rgb ? s->rgba_map[A] : 0, // alpha offset for packed formats
+ s->is_packed_rgb ? 4 : 1, // pixstep for 8 bit packed formats
+ 1, frame->data[plane], frame->linesize[plane]);
+ } else {
+ /* luma or rgb plane */
+ fade_plane(0, frame->height, inlink->w,
+ s->factor, s->black_level, s->black_level_scaled,
+ 0, 1, // offset & pixstep for Y plane or RGB packed format
+ s->bpp, frame->data[0], frame->linesize[0]);
+ if (frame->data[1] && frame->data[2]) {
+ /* chroma planes */
+ for (plane = 1; plane < 3; plane++) {
+ for (i = 0; i < frame->height; i++) {
+ const int width = FF_CEIL_RSHIFT(inlink->w, s->hsub);
+ p = frame->data[plane] + (i >> s->vsub) * 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. */
+ *p = ((*p - 128) * s->factor + 8421367) >> 16;
+ p++;
+ }
}
}
}
}
}
- if (s->frame_index >= s->start_frame &&
- s->frame_index <= s->stop_frame)
- s->factor += s->fade_per_frame;
- s->factor = av_clip_uint16(s->factor);
s->frame_index++;
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 },
+ 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[] = {
{
@@ -179,7 +306,7 @@ static const AVFilterPad avfilter_vf_fade_outputs[] = {
AVFilter avfilter_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,
diff --git a/libavfilter/vf_field.c b/libavfilter/vf_field.c
new file mode 100644
index 0000000..bbe66de
--- /dev/null
+++ b/libavfilter/vf_field.c
@@ -0,0 +1,118 @@
+/*
+ * 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];
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int i;
+
+ for (i = 0; i < desc->nb_components; i++)
+ field->nb_planes = FFMAX(field->nb_planes, desc->comp[i].plane);
+ field->nb_planes++;
+
+ 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,
+ .get_video_buffer = ff_null_get_video_buffer,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad field_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_props_output,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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..3a6f806
--- /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]; 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 avfilter_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 19b07b1..3a19500 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,7 @@
* video field order filter, heavily influenced by vf_pad.c
*/
-#include <stdio.h>
-#include <string.h>
-
+#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
#include "libavutil/opt.h"
@@ -149,20 +147,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
}
#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" },
+ { "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[] = {
{
diff --git a/libavfilter/vf_format.c b/libavfilter/vf_format.c
index 339dbcc..6d3f58a 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
*/
@@ -31,6 +31,7 @@
#include "libavutil/opt.h"
#include "avfilter.h"
+#include "internal.h"
#include "formats.h"
#include "internal.h"
#include "video.h"
@@ -52,7 +53,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 +69,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;
}
diff --git a/libavfilter/vf_fps.c b/libavfilter/vf_fps.c
index eb201fa..6a67158 100644
--- a/libavfilter/vf_fps.c
+++ b/libavfilter/vf_fps.c
@@ -1,18 +1,22 @@
/*
- * This file is part of Libav.
+ * Copyright 2007 Bobby Bingham
+ * Copyright 2012 Robert Nagy <ronag89 gmail com>
+ * Copyright 2012 Anton Khirnov <anton khirnov net>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,7 +45,7 @@ typedef struct FPSContext {
int64_t pts; ///< pts of the first frame currently in the fifo
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
@@ -52,27 +56,23 @@ 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 },
+ { "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);
@@ -94,7 +94,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);
}
@@ -107,7 +107,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;
s->pts = AV_NOPTS_VALUE;
@@ -192,8 +193,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *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 */
@@ -274,13 +275,13 @@ static const AVFilterPad avfilter_vf_fps_outputs[] = {
AVFilter avfilter_vf_fps = {
.name = "fps",
- .description = NULL_IF_CONFIG_SMALL("Force constant framerate"),
+ .description = NULL_IF_CONFIG_SMALL("Force constant framerate."),
.init = init,
.uninit = uninit,
.priv_size = sizeof(FPSContext),
- .priv_class = &class,
+ .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..fb20411
--- /dev/null
+++ b/libavfilter/vf_framestep.c
@@ -0,0 +1,100 @@
+/*
+ * 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 avfilter_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,
+};
diff --git a/libavfilter/vf_frei0r.c b/libavfilter/vf_frei0r.c
index ff7e308..8602d3f 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
*/
@@ -139,6 +139,9 @@ static int set_params(AVFilterContext *ctx, const char *params)
Frei0rContext *s = ctx->priv;
int i;
+ if (!params)
+ return 0;
+
for (i = 0; i < s->plugin_info.num_params; i++) {
f0r_param_info_t info;
char *param;
@@ -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);
}
@@ -318,7 +354,7 @@ static int config_input_props(AVFilterLink *inlink)
Frei0rContext *s = ctx->priv;
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);
}
@@ -371,7 +407,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
#define OFFSET(x) offsetof(Frei0rContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
static const AVOption filter_options[] = {
{ "filter_name", NULL, OFFSET(dl_name), AV_OPT_TYPE_STRING, .flags = FLAGS },
{ "filter_params", NULL, OFFSET(params), AV_OPT_TYPE_STRING, .flags = FLAGS },
@@ -429,8 +465,7 @@ static av_cold int source_init(AVFilterContext *ctx)
return AVERROR(EINVAL);
}
- if (av_parse_video_rate(&frame_rate_q, s->framerate) < 0 ||
- frame_rate_q.den <= 0 || frame_rate_q.num <= 0) {
+ if (av_parse_video_rate(&frame_rate_q, s->framerate) < 0) {
av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: '%s'\n", s->framerate);
return AVERROR(EINVAL);
}
@@ -450,9 +485,10 @@ 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->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);
}
diff --git a/libavfilter/vf_geq.c b/libavfilter/vf_geq.c
new file mode 100644
index 0000000..5ee75d1
--- /dev/null
+++ b/libavfilter/vf_geq.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2012 ClĂ©ment BÅ“sch <ubitux@gmail.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/**
+ * @file
+ * 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;
+
+#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[0]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "cb_expr", "set chroma blue expression", OFFSET(expr_str[1]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "cr_expr", "set chroma red expression", OFFSET(expr_str[2]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "alpha_expr", "set alpha expression", OFFSET(expr_str[3]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+
+ { "r", "set red expression", OFFSET(expr_str[6]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "g", "set green expression", OFFSET(expr_str[4]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "b", "set blue expression", OFFSET(expr_str[5]), 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[0] && !geq->expr_str[4] && !geq->expr_str[5] && !geq->expr_str[6]) {
+ 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[0];
+
+ if ((geq->expr_str[0] || geq->expr_str[1] || geq->expr_str[2]) && (geq->expr_str[4] || geq->expr_str[5] || geq->expr_str[6])) {
+ 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[1] && !geq->expr_str[2]) {
+ /* No chroma at all: fallback on luma */
+ geq->expr_str[1] = av_strdup(geq->expr_str[0]);
+ geq->expr_str[2] = av_strdup(geq->expr_str[0]);
+ } else {
+ /* One chroma unspecified, fallback on the other */
+ if (!geq->expr_str[1]) geq->expr_str[1] = av_strdup(geq->expr_str[2]);
+ if (!geq->expr_str[2]) geq->expr_str[2] = av_strdup(geq->expr_str[1]);
+ }
+
+ if (!geq->expr_str[3])
+ geq->expr_str[3] = av_strdup("255");
+ if (!geq->expr_str[4])
+ geq->expr_str[4] = av_strdup("g(X,Y)");
+ if (!geq->expr_str[5])
+ geq->expr_str[5] = av_strdup("b(X,Y)");
+ if (!geq->expr_str[6])
+ geq->expr_str[6] = av_strdup("r(X,Y)");
+
+ if (geq->is_rgb ?
+ (!geq->expr_str[4] || !geq->expr_str[5] || !geq->expr_str[6])
+ :
+ (!geq->expr_str[1] || !geq->expr_str[2] || !geq->expr_str[3])) {
+ 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 avfilter_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,
+};
diff --git a/libavfilter/vf_gradfun.c b/libavfilter/vf_gradfun.c
index e519a37..299cbf5 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.washignton.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
*/
@@ -37,6 +37,7 @@
#include "libavutil/cpu.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/opt.h"
#include "avfilter.h"
#include "formats.h"
#include "gradfun.h"
@@ -54,7 +55,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 +69,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 +80,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 +126,9 @@ static av_cold int init(AVFilterContext *ctx)
GradFunContext *gf = ctx->priv;
gf->thresh = (1 << 15) / gf->strength;
- gf->radius &= ~1;
+ gf->radius = av_clip((gf->radius + 1) & ~1, 4, 32);
- gf->blur_line = ff_gradfun_blur_line_c;
+ gf->blur_line = ff_gradfun_blur_line_c;
gf->filter_line = ff_gradfun_filter_line_c;
if (ARCH_X86)
@@ -151,6 +152,7 @@ static int query_formats(AVFilterContext *ctx)
AV_PIX_FMT_GRAY8, AV_PIX_FMT_NV12,
AV_PIX_FMT_NV21, AV_PIX_FMT_YUV444P,
AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_YUV440P,
AV_PIX_FMT_NONE
};
@@ -170,8 +172,8 @@ static int config_input(AVFilterLink *inlink)
if (!gf->buf)
return AVERROR(ENOMEM);
- gf->chroma_w = -((-inlink->w) >> hsub);
- gf->chroma_h = -((-inlink->h) >> vsub);
+ gf->chroma_w = FF_CEIL_RSHIFT(inlink->w, hsub);
+ gf->chroma_h = FF_CEIL_RSHIFT(inlink->h, vsub);
gf->chroma_r = av_clip(((((gf->radius >> hsub) + (gf->radius >> vsub)) / 2 ) + 1) & ~1, 4, 32);
return 0;
@@ -194,10 +196,7 @@ 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++) {
@@ -223,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 },
};
-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[] = {
{
@@ -263,7 +258,7 @@ AVFilter avfilter_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 c8a1ca2..0ee6589 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
*/
@@ -42,33 +42,19 @@ typedef struct {
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;
}
@@ -91,7 +77,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
AVFilterLink *outlink = ctx->outputs[0];
AVFrame *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) {
@@ -100,17 +86,21 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
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);
+
for (plane = 0; plane < 4 && in->data[plane]; plane++) {
+ const int width = (plane == 1 || plane == 2) ? FF_CEIL_RSHIFT(inlink->w, flip->hsub) : inlink->w;
+ const int height = (plane == 1 || plane == 2) ? FF_CEIL_RSHIFT(inlink->h, flip->vsub) : inlink->h;
step = flip->max_step[plane];
- hsub = (plane == 1 || plane == 2) ? flip->hsub : 0;
- vsub = (plane == 1 || plane == 2) ? flip->vsub : 0;
outrow = out->data[plane];
- inrow = in ->data[plane] + ((inlink->w >> hsub) - 1) * step;
- for (i = 0; i < in->height >> vsub; i++) {
+ inrow = in ->data[plane] + (width - 1) * step;
+ for (i = 0; i < height; i++) {
switch (step) {
case 1:
- for (j = 0; j < (inlink->w >> hsub); j++)
+ for (j = 0; j < width; j++)
outrow[j] = inrow[-j];
break;
@@ -118,7 +108,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{
uint16_t *outrow16 = (uint16_t *)outrow;
uint16_t * inrow16 = (uint16_t *) inrow;
- for (j = 0; j < (inlink->w >> hsub); j++)
+ for (j = 0; j < width; j++)
outrow16[j] = inrow16[-j];
}
break;
@@ -127,7 +117,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{
uint8_t *in = inrow;
uint8_t *out = outrow;
- for (j = 0; j < (inlink->w >> hsub); j++, out += 3, in -= 3) {
+ for (j = 0; j < width; j++, out += 3, in -= 3) {
int32_t v = AV_RB24(in);
AV_WB24(out, v);
}
@@ -138,13 +128,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{
uint32_t *outrow32 = (uint32_t *)outrow;
uint32_t * inrow32 = (uint32_t *) inrow;
- for (j = 0; j < (inlink->w >> hsub); j++)
+ for (j = 0; j < width; j++)
outrow32[j] = inrow32[-j];
}
break;
default:
- for (j = 0; j < (inlink->w >> hsub); j++)
+ for (j = 0; j < width; j++)
memcpy(outrow + j*step, inrow - j*step, step);
}
diff --git a/libavfilter/vf_histeq.c b/libavfilter/vf_histeq.c
new file mode 100644
index 0000000..659b696
--- /dev/null
+++ b/libavfilter/vf_histeq.c
@@ -0,0 +1,283 @@
+/*
+ * 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;
+ char* antibanding_str;
+ 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 avfilter_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..40afe1f
--- /dev/null
+++ b/libavfilter/vf_histogram.c
@@ -0,0 +1,329 @@
+/*
+ * 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];
+ unsigned max_hval;
+ int ncomp;
+ const uint8_t *bg_color;
+ const uint8_t *fg_color;
+ int level_height;
+ int scale_height;
+ int step;
+ int waveform_mode;
+ int display_mode;
+ int levels_mode;
+} 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" },
+ { "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 int query_formats(AVFilterContext *ctx)
+{
+ HistogramContext *h = ctx->priv;
+ const enum AVPixelFormat *pix_fmts;
+
+ switch (h->mode) {
+ case MODE_WAVEFORM:
+ 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;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ h->ncomp = 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 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++)
+ for (i = 0; i < outlink->h; i++)
+ memset(out->data[k] + i * out->linesize[k], h->bg_color[k], outlink->w);
+
+ switch (h->mode) {
+ case MODE_LEVELS:
+ for (k = 0; k < h->ncomp; k++) {
+ int start = k * (h->level_height + h->scale_height) * h->display_mode;
+
+ for (i = 0; i < in->height; i++) {
+ src = in->data[k] + i * in->linesize[k];
+ for (j = 0; j < in->width; j++)
+ h->histogram[src[j]]++;
+ }
+
+ for (i = 0; i < 256; i++)
+ h->max_hval = FFMAX(h->max_hval, h->histogram[i]);
+
+ 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) / log2(h->max_hval + 1))));
+ else
+ col_height = h->level_height - (h->histogram[i] * (int64_t)h->level_height + h->max_hval - 1) / h->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[k][(j + start) * out->linesize[k] + i] = 255;
+ }
+ }
+ for (j = h->level_height + h->scale_height - 1; j >= h->level_height; j--)
+ out->data[k][(j + start) * out->linesize[k] + i] = i;
+ }
+
+ memset(h->histogram, 0, 256 * sizeof(unsigned));
+ h->max_hval = 0;
+ }
+ break;
+ case MODE_WAVEFORM:
+ if (h->waveform_mode) {
+ for (k = 0; k < h->ncomp; k++) {
+ int offset = k * 256 * h->display_mode;
+ for (i = 0; i < inlink->w; i++) {
+ for (j = 0; j < inlink->h; j++) {
+ int pos = (offset +
+ in->data[k][j * in->linesize[k] + i]) *
+ out->linesize[k] + i;
+ unsigned value = out->data[k][pos];
+ value = FFMIN(value + h->step, 255);
+ out->data[k][pos] = value;
+ }
+ }
+ }
+ } else {
+ for (k = 0; k < h->ncomp; k++) {
+ int offset = k * 256 * h->display_mode;
+ for (i = 0; i < inlink->h; i++) {
+ src = in ->data[k] + i * in ->linesize[k];
+ dst = out->data[k] + i * out->linesize[k];
+ for (j = 0; j < inlink->w; j++) {
+ int pos = src[j] + offset;
+ unsigned value = dst[pos];
+ value = FFMIN(value + h->step, 255);
+ dst[pos] = value;
+ }
+ }
+ }
+ }
+ break;
+ case MODE_COLOR:
+ for (i = 0; i < inlink->h; i++) {
+ int iw1 = i * in->linesize[1];
+ int iw2 = i * in->linesize[2];
+ for (j = 0; j < inlink->w; j++) {
+ 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++) {
+ int iw1 = i * in->linesize[1];
+ int iw2 = i * in->linesize[2];
+ for (j = 0; j < inlink->w; j++) {
+ int u = in->data[1][iw1 + j];
+ int v = in->data[2][iw2 + j];
+ 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 avfilter_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 d60219a..d8a8586 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.
*/
@@ -274,12 +274,14 @@ static int config_input(AVFilterLink *inlink)
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{
- HQDN3DContext *hqdn3d = inlink->dst->priv;
- AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFilterContext *ctx = inlink->dst;
+ HQDN3DContext *hqdn3d = 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 {
@@ -291,17 +293,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(hqdn3d, in->data[c], out->data[c],
hqdn3d->line, &hqdn3d->frame_prev[c],
- in->width >> (!!c * hqdn3d->hsub),
- in->height >> (!!c * hqdn3d->vsub),
+ FF_CEIL_RSHIFT(in->width, (!!c * hqdn3d->hsub)),
+ FF_CEIL_RSHIFT(in->height, (!!c * hqdn3d->vsub)),
in->linesize[c], out->linesize[c],
- hqdn3d->coefs[c?2:0], hqdn3d->coefs[c?3:1]);
+ hqdn3d->coefs[c ? CHROMA_SPATIAL : LUMA_SPATIAL],
+ hqdn3d->coefs[c ? CHROMA_TMP : LUMA_TMP]);
+ }
+
+ if (ctx->is_disabled) {
+ av_frame_free(&out);
+ return ff_filter_frame(outlink, in);
}
if (!direct)
@@ -311,7 +317,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
#define OFFSET(x) offsetof(HQDN3DContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
static const AVOption 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 },
@@ -337,6 +343,7 @@ static const AVFilterPad avfilter_vf_hqdn3d_inputs[] = {
{ NULL }
};
+
static const AVFilterPad avfilter_vf_hqdn3d_outputs[] = {
{
.name = "default",
@@ -356,6 +363,6 @@ AVFilter avfilter_vf_hqdn3d = {
.query_formats = query_formats,
.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..cc8ac78
--- /dev/null
+++ b/libavfilter/vf_hue.c
@@ -0,0 +1,377 @@
+/*
+ * 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 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 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;
+ int hsub;
+ int vsub;
+ int32_t hue_sin;
+ int32_t hue_cos;
+ double var_values[VAR_NB];
+} 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 },
+ { 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 process_chrominance function.
+ */
+ hue->hue_sin = rint(sin(hue->hue) * (1 << 16) * hue->saturation);
+ hue->hue_cos = rint(cos(hue->hue) * (1 << 16) * hue->saturation);
+}
+
+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(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\n",
+ hue->hue_expr, hue->hue_deg_expr, hue->saturation_expr);
+ compute_sin_and_cos(hue);
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ HueContext *hue = ctx->priv;
+
+ 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 process_chrominance(uint8_t *udst, uint8_t *vdst, const int dst_linesize,
+ uint8_t *usrc, uint8_t *vsrc, const int src_linesize,
+ int w, int h,
+ const int32_t c, const int32_t s)
+{
+ int32_t u, v, new_u, new_v;
+ int i;
+
+ /*
+ * 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
+ */
+ while (h--) {
+ for (i = 0; i < w; i++) {
+ /* Normalize the components from range [16;140] to [-112;112] */
+ u = usrc[i] - 128;
+ v = vsrc[i] - 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 */
+ udst[i] = av_clip_uint8_c(new_u);
+ vdst[i] = av_clip_uint8_c(new_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;
+ 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->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 t:%0.1f n:%d\n",
+ hue->hue/M_PI, hue->hue_deg, hue->saturation,
+ hue->var_values[VAR_T], (int)hue->var_values[VAR_N]);
+
+ compute_sin_and_cos(hue);
+
+ if (!direct) {
+ 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);
+ }
+
+ process_chrominance(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),
+ hue->hue_cos, hue->hue_sin);
+
+ 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
+ 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 avfilter_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..cd8bbe3
--- /dev/null
+++ b/libavfilter/vf_idet.c
@@ -0,0 +1,318 @@
+/*
+ * 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 >>= idet->csp->log2_chroma_w;
+ 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 int request_frame(AVFilterLink *link)
+{
+ AVFilterContext *ctx = link->src;
+ IDETContext *idet = ctx->priv;
+
+ do {
+ int ret;
+
+ if ((ret = ff_request_frame(link->src->inputs[0])))
+ return ret;
+ } while (!idet->cur);
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ IDETContext *idet = ctx->priv;
+
+ av_log(ctx, AV_LOG_INFO, "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_NE( AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY16LE ),
+ 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_YUVA420P,
+ AV_PIX_FMT_NONE
+ };
+
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+
+ 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,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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..c2ed6ab
--- /dev/null
+++ b/libavfilter/vf_il.c
@@ -0,0 +1,214 @@
+/*
+ * 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 i, ret;
+
+ for (i = 0; i < desc->nb_components; i++)
+ il->nb_planes = FFMAX(il->nb_planes, desc->comp[i].plane);
+ il->nb_planes++;
+
+ 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,
+ .get_video_buffer = ff_null_get_video_buffer,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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,
+};
diff --git a/libavfilter/vf_interlace.c b/libavfilter/vf_interlace.c
index d3c3d4d..3315fb0 100755..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.
*/
@@ -90,8 +95,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 +111,10 @@ static int config_out_props(AVFilterLink *outlink)
outlink->w = inlink->w;
outlink->h = inlink->h;
outlink->time_base = inlink->time_base;
+ outlink->frame_rate = inlink->frame_rate;
// half framerate
outlink->time_base.num *= 2;
+ outlink->frame_rate.den *= 2;
av_log(ctx, AV_LOG_VERBOSE, "%s interlacing %s lowpass filter\n",
s->scan == MODE_TFF ? "tff" : "bff", (s->lowpass) ? "with" : "without");
@@ -126,7 +131,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];
diff --git a/libavfilter/vf_kerndeint.c b/libavfilter/vf_kerndeint.c
new file mode 100644
index 0000000..5f99d88
--- /dev/null
+++ b/libavfilter/vf_kerndeint.c
@@ -0,0 +1,320 @@
+/*
+ * 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; inpic->data[plane] && plane < 4; 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 avfilter_vf_kerndeint = {
+ .name = "kerndeint",
+ .description = NULL_IF_CONFIG_SMALL("Apply kernel deinterlacing to the input."),
+ .priv_size = sizeof(KerndeintContext),
+ .uninit = uninit,
+ .query_formats = query_formats,
+
+ .inputs = kerndeint_inputs,
+ .outputs = kerndeint_outputs,
+
+ .priv_class = &kerndeint_class,
+};
diff --git a/libavfilter/vf_libopencv.c b/libavfilter/vf_libopencv.c
index fff9a44..22d2407 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 *ocv = ctx->priv;
int i;
+ if (!ocv->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(ocv->name, entry->name)) {
@@ -372,7 +377,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
#define OFFSET(x) offsetof(OCVContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
static const AVOption options[] = {
{ "filter_name", NULL, OFFSET(name), AV_OPT_TYPE_STRING, .flags = FLAGS },
{ "filter_params", NULL, OFFSET(params), AV_OPT_TYPE_STRING, .flags = FLAGS },
diff --git a/libavfilter/vf_lut.c b/libavfilter/vf_lut.c
index 87c028a..f57c284 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 },
@@ -102,20 +95,6 @@ static const AVOption lut_options[] = {
{ NULL },
};
-static av_cold int init(AVFilterContext *ctx)
-{
- LutContext *lut = ctx->priv;
-
- lut->var_values[VAR_PHI] = M_PHI;
- lut->var_values[VAR_PI] = M_PI;
- lut->var_values[VAR_E ] = M_E;
-
- lut->is_rgb = !strcmp(ctx->filter->name, "lutrgb");
- lut->is_yuv = !strcmp(ctx->filter->name, "lutyuv");
-
- return 0;
-}
-
static av_cold void uninit(AVFilterContext *ctx)
{
LutContext *lut = 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
@@ -140,16 +119,16 @@ static av_cold void uninit(AVFilterContext *ctx)
AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA, \
AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24
-static enum AVPixelFormat yuv_pix_fmts[] = { YUV_FORMATS, AV_PIX_FMT_NONE };
-static enum AVPixelFormat rgb_pix_fmts[] = { RGB_FORMATS, AV_PIX_FMT_NONE };
-static enum AVPixelFormat all_pix_fmts[] = { RGB_FORMATS, YUV_FORMATS, AV_PIX_FMT_NONE };
+static const enum AVPixelFormat yuv_pix_fmts[] = { YUV_FORMATS, AV_PIX_FMT_NONE };
+static const enum AVPixelFormat rgb_pix_fmts[] = { RGB_FORMATS, AV_PIX_FMT_NONE };
+static const enum AVPixelFormat all_pix_fmts[] = { RGB_FORMATS, YUV_FORMATS, AV_PIX_FMT_NONE };
static int query_formats(AVFilterContext *ctx)
{
LutContext *lut = ctx->priv;
- enum AVPixelFormat *pix_fmts = lut->is_rgb ? rgb_pix_fmts :
- lut->is_yuv ? yuv_pix_fmts : all_pix_fmts;
+ const enum AVPixelFormat *pix_fmts = lut->is_rgb ? rgb_pix_fmts :
+ lut->is_yuv ? yuv_pix_fmts : all_pix_fmts;
ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
return 0;
@@ -182,8 +161,8 @@ static double compute_gammaval(void *opaque, double gamma)
}
static double (* const funcs1[])(void *, double) = {
- clip,
- compute_gammaval,
+ (void *)clip,
+ (void *)compute_gammaval,
NULL
};
@@ -198,8 +177,9 @@ static int config_props(AVFilterLink *inlink)
AVFilterContext *ctx = inlink->dst;
LutContext *lut = 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;
lut->hsub = desc->log2_chroma_w;
lut->vsub = desc->log2_chroma_h;
@@ -215,6 +195,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;
@@ -230,49 +212,43 @@ static int config_props(AVFilterLink *inlink)
else if (ff_fmt_is_in(inlink->format, rgb_pix_fmts)) lut->is_rgb = 1;
if (lut->is_rgb) {
- switch (inlink->format) {
- case AV_PIX_FMT_ARGB: lut->rgba_map[A] = 0; lut->rgba_map[R] = 1; lut->rgba_map[G] = 2; lut->rgba_map[B] = 3; break;
- case AV_PIX_FMT_ABGR: lut->rgba_map[A] = 0; lut->rgba_map[B] = 1; lut->rgba_map[G] = 2; lut->rgba_map[R] = 3; break;
- case AV_PIX_FMT_RGBA:
- case AV_PIX_FMT_RGB24: lut->rgba_map[R] = 0; lut->rgba_map[G] = 1; lut->rgba_map[B] = 2; lut->rgba_map[A] = 3; break;
- case AV_PIX_FMT_BGRA:
- case AV_PIX_FMT_BGR24: lut->rgba_map[B] = 0; lut->rgba_map[G] = 1; lut->rgba_map[R] = 2; lut->rgba_map[A] = 3; break;
- }
+ ff_fill_rgba_map(rgba_map, inlink->format);
lut->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 = lut->is_rgb ? rgba_map[color] : color;
/* create the parsed expression */
- ret = av_expr_parse(&lut->comp_expr[comp], lut->comp_expr_str[comp],
+ ret = av_expr_parse(&lut->comp_expr[color], lut->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",
- lut->comp_expr_str[comp], comp);
+ "Error when parsing the expression '%s' for the component %d and color %d.\n",
+ lut->comp_expr_str[comp], comp, color);
return AVERROR(EINVAL);
}
/* compute the lut */
- lut->var_values[VAR_MAXVAL] = max[comp];
- lut->var_values[VAR_MINVAL] = min[comp];
+ lut->var_values[VAR_MAXVAL] = max[color];
+ lut->var_values[VAR_MINVAL] = min[color];
for (val = 0; val < 256; val++) {
lut->var_values[VAR_VAL] = val;
- lut->var_values[VAR_CLIPVAL] = av_clip(val, min[comp], max[comp]);
+ lut->var_values[VAR_CLIPVAL] = av_clip(val, min[color], max[color]);
lut->var_values[VAR_NEGVAL] =
- av_clip(min[comp] + max[comp] - lut->var_values[VAR_VAL],
- min[comp], max[comp]);
+ av_clip(min[color] + max[color] - lut->var_values[VAR_VAL],
+ min[color], max[color]);
- res = av_expr_eval(lut->comp_expr[comp], lut->var_values, lut);
+ res = av_expr_eval(lut->comp_expr[color], lut->var_values, lut);
if (isnan(res)) {
av_log(ctx, AV_LOG_ERROR,
- "Error when evaluating the expression '%s' for the value %d for the component #%d.\n",
- lut->comp_expr_str[comp], val, comp);
+ "Error when evaluating the expression '%s' for the value %d for the component %d.\n",
+ lut->comp_expr_str[color], val, comp);
return AVERROR(EINVAL);
}
- lut->lut[comp][val] = av_clip((int)res, min[comp], max[comp]);
+ lut->lut[comp][val] = av_clip((int)res, min[color], max[color]);
av_log(ctx, AV_LOG_DEBUG, "val[%d][%d] = %d\n", comp, val, lut->lut[comp][val]);
}
}
@@ -287,14 +263,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 (lut->is_rgb) {
/* packed */
@@ -302,11 +283,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])lut->lut;
inrow = inrow0;
outrow = outrow0;
- for (j = 0; j < inlink->w; j++) {
- for (k = 0; k < lut->step; k++)
- outrow[k] = lut->lut[lut->rgba_map[k]][inrow[k]];
+ for (j = 0; j < w; j++) {
+ switch (lut->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 += lut->step;
inrow += lut->step;
}
@@ -318,20 +305,25 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
for (plane = 0; plane < 4 && in->data[plane]; plane++) {
int vsub = plane == 1 || plane == 2 ? lut->vsub : 0;
int hsub = plane == 1 || plane == 2 ? lut->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] = lut->lut[plane][inrow[j]];
+ for (i = 0; i < h; i++) {
+ const uint8_t *tab = lut->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);
}
@@ -348,44 +340,79 @@ static const AVFilterPad outputs[] = {
.type = AVMEDIA_TYPE_VIDEO, },
{ .name = 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 avfilter_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 *lut = ctx->priv;
+
+ lut->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 *lut = ctx->priv;
+
+ lut->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 },
+ { "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 *lut = ctx->priv;
@@ -394,7 +421,7 @@ static av_cold int negate_init(AVFilterContext *ctx)
av_log(ctx, AV_LOG_DEBUG, "negate_alpha:%d\n", lut->negate_alpha);
for (i = 0; i < 4; i++) {
- lut->comp_expr_str[i] = av_strdup((i == 3 && lut->negate_alpha) ?
+ lut->comp_expr_str[i] = av_strdup((i == 3 && !lut->negate_alpha) ?
"val" : "negval");
if (!lut->comp_expr_str[i]) {
uninit(ctx);
@@ -402,9 +429,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_mp.c b/libavfilter/vf_mp.c
new file mode 100644
index 0000000..0f4a113
--- /dev/null
+++ b/libavfilter/vf_mp.c
@@ -0,0 +1,854 @@
+/*
+ * 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/vf_scale.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_dint;
+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_fil;
+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_mcdeint;
+extern const vf_info_t ff_vf_info_perspective;
+extern const vf_info_t ff_vf_info_phase;
+extern const vf_info_t ff_vf_info_pp7;
+extern const vf_info_t ff_vf_info_pullup;
+extern const vf_info_t ff_vf_info_qp;
+extern const vf_info_t ff_vf_info_sab;
+extern const vf_info_t ff_vf_info_softpulldown;
+extern const vf_info_t ff_vf_info_spp;
+extern const vf_info_t ff_vf_info_uspp;
+
+
+static const vf_info_t* const filters[]={
+ &ff_vf_info_dint,
+ &ff_vf_info_eq2,
+ &ff_vf_info_eq,
+ &ff_vf_info_fil,
+ &ff_vf_info_fspp,
+ &ff_vf_info_ilpack,
+ &ff_vf_info_mcdeint,
+ &ff_vf_info_perspective,
+ &ff_vf_info_phase,
+ &ff_vf_info_pp7,
+ &ff_vf_info_pullup,
+ &ff_vf_info_qp,
+ &ff_vf_info_sab,
+ &ff_vf_info_softpulldown,
+ &ff_vf_info_spp,
+ &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;
+}
+
+static void ff_sws_getFlagsAndFilterFromCmdLine(int *flags, SwsFilter **srcFilterParam, SwsFilter **dstFilterParam)
+{
+ static int firstTime=1;
+ *flags=0;
+
+#if ARCH_X86
+ if(ff_gCpuCaps.hasMMX)
+ __asm__ volatile("emms\n\t"::: "memory"); //FIXME this should not be required but it IS (even for non-MMX versions)
+#endif
+ if(firstTime)
+ {
+ firstTime=0;
+ *flags= SWS_PRINT_INFO;
+ }
+ else if( ff_mp_msg_test(MSGT_VFILTER,MSGL_DBG2) ) *flags= SWS_PRINT_INFO;
+
+ switch(SWS_BILINEAR)
+ {
+ case 0: *flags|= SWS_FAST_BILINEAR; break;
+ case 1: *flags|= SWS_BILINEAR; break;
+ case 2: *flags|= SWS_BICUBIC; break;
+ case 3: *flags|= SWS_X; break;
+ case 4: *flags|= SWS_POINT; break;
+ case 5: *flags|= SWS_AREA; break;
+ case 6: *flags|= SWS_BICUBLIN; break;
+ case 7: *flags|= SWS_GAUSS; break;
+ case 8: *flags|= SWS_SINC; break;
+ case 9: *flags|= SWS_LANCZOS; break;
+ case 10:*flags|= SWS_SPLINE; break;
+ default:*flags|= SWS_BILINEAR; break;
+ }
+
+ *srcFilterParam= NULL;
+ *dstFilterParam= NULL;
+}
+
+//exact copy from vf_scale.c
+// will use sws_flags & src_filter (from cmd line)
+struct SwsContext *ff_sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat)
+{
+ int flags, i;
+ SwsFilter *dstFilterParam, *srcFilterParam;
+ enum AVPixelFormat dfmt, sfmt;
+
+ for(i=0; conversion_map[i].fmt && dstFormat != conversion_map[i].fmt; i++);
+ dfmt= conversion_map[i].pix_fmt;
+ for(i=0; conversion_map[i].fmt && srcFormat != conversion_map[i].fmt; i++);
+ sfmt= conversion_map[i].pix_fmt;
+
+ if (srcFormat == IMGFMT_RGB8 || srcFormat == IMGFMT_BGR8) sfmt = AV_PIX_FMT_PAL8;
+ ff_sws_getFlagsAndFilterFromCmdLine(&flags, &srcFilterParam, &dstFilterParam);
+
+ return sws_getContext(srcW, srcH, sfmt, dstW, dstH, dfmt, flags , srcFilterParam, dstFilterParam, NULL);
+}
+
+typedef struct {
+ const AVClass *class;
+ vf_instance_t vf;
+ vf_instance_t next_vf;
+ AVFilterContext *avfctx;
+ int frame_returned;
+ char *filter;
+} 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;
+
+ 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);
+
+ memcpy(mpi->planes, inpic->data, FFMIN(sizeof(inpic->data) , sizeof(mpi->planes)));
+ memcpy(mpi->stride, inpic->linesize, FFMIN(sizeof(inpic->linesize), sizeof(mpi->stride)));
+
+ //FIXME pass interleced & tff flags around
+
+ // 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 avfilter_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..45d510b
--- /dev/null
+++ b/libavfilter/vf_mpdecimate.c
@@ -0,0 +1,259 @@
+/*
+ * 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,
+ .get_video_buffer = ff_null_get_video_buffer,
+ .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 avfilter_vf_mpdecimate = {
+ .name = "mpdecimate",
+ .description = NULL_IF_CONFIG_SMALL("Remove near-duplicate frames."),
+ .init = init,
+ .uninit = uninit,
+
+ .priv_size = sizeof(DecimateContext),
+ .query_formats = query_formats,
+ .inputs = mpdecimate_inputs,
+ .outputs = mpdecimate_outputs,
+ .priv_class = &mpdecimate_class,
+};
diff --git a/libavfilter/vf_noise.c b/libavfilter/vf_noise.c
new file mode 100644
index 0000000..15f5fcf
--- /dev/null
+++ b/libavfilter/vf_noise.c
@@ -0,0 +1,475 @@
+/*
+ * 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
+ */
+
+/**
+ * @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 4096
+#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;
+ int shiftptr;
+ AVLFG lfg;
+ int seed;
+ int8_t *noise;
+ int8_t *prev_shift[MAX_RES][3];
+} FilterParams;
+
+typedef struct {
+ const AVClass *class;
+ int nb_planes;
+ int linesize[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;
+
+#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 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;
+ fp->shiftptr = 0;
+ 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 i, ret;
+
+ for (i = 0; i < desc->nb_components; i++)
+ n->nb_planes = FFMAX(n->nb_planes, desc->comp[i].plane);
+ n->nb_planes++;
+
+ if ((ret = av_image_fill_linesizes(n->linesize, 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 height, NoiseContext *n, int comp)
+{
+ int8_t *noise = n->param[comp].noise;
+ int flags = n->param[comp].flags;
+ AVLFG *lfg = &n->param[comp].lfg;
+ int shift, y;
+
+ if (!noise) {
+ if (dst != src) {
+ for (y = 0; y < height; y++) {
+ memcpy(dst, src, width);
+ dst += dst_linesize;
+ src += src_linesize;
+ }
+ }
+
+ return;
+ }
+
+ for (y = 0; y < height; y++) {
+ if (flags & NOISE_TEMPORAL)
+ shift = av_lfg_get(lfg) & (MAX_SHIFT - 1);
+ else
+ shift = n->rand_shift[y];
+
+ if (flags & NOISE_AVERAGED) {
+ n->line_noise_avg(dst, src, width, n->param[comp].prev_shift[y]);
+ n->param[comp].prev_shift[y][n->param[comp].shiftptr] = noise + shift;
+ } else {
+ n->line_noise(dst, src, noise, width, shift);
+ }
+ dst += dst_linesize;
+ src += src_linesize;
+ }
+
+ n->param[comp].shiftptr++;
+ if (n->param[comp].shiftptr == 3)
+ n->param[comp].shiftptr = 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
+{
+ NoiseContext *n = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *out;
+ int i;
+
+ if (av_frame_is_writable(inpicref)) {
+ out = inpicref;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&inpicref);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, inpicref);
+ }
+
+ for (i = 0; i < n->nb_planes; i++)
+ noise(out->data[i], inpicref->data[i], out->linesize[i],
+ inpicref->linesize[i], n->linesize[i], n->height[i], n, i);
+ 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;
+ }
+
+ 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 avfilter_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,
+};
diff --git a/libavfilter/vf_null.c b/libavfilter/vf_null.c
index a7abb7a..0bafbf8 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
*/
@@ -30,7 +30,6 @@ static const AVFilterPad avfilter_vf_null_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = ff_null_get_video_buffer,
},
{ NULL }
};
@@ -46,10 +45,6 @@ static const AVFilterPad avfilter_vf_null_outputs[] = {
AVFilter avfilter_vf_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,
};
diff --git a/libavfilter/vf_overlay.c b/libavfilter/vf_overlay.c
index da2ddbe..ec58dc4 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
*/
@@ -25,89 +25,261 @@
* overlay one video on top of another
*/
+/* #define DEBUG */
+
#include "avfilter.h"
#include "formats.h"
#include "libavutil/common.h"
#include "libavutil/eval.h"
#include "libavutil/avstring.h"
-#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
+#include "libavutil/timestamp.h"
#include "internal.h"
+#include "bufferqueue.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 frame_requested;
+ uint8_t overlay_eof;
+ 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;
+
+ AVFrame *overpicref;
+ struct FFBufQueue queue_main;
+ struct FFBufQueue queue_over;
+
+ 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
+ int shortest; ///< terminate stream when the shortest input terminates
+ int repeatlast; ///< repeat last overlay frame
+ 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 int init(AVFilterContext *ctx)
+{
+ OverlayContext *over = ctx->priv;
+
+ if (over->allow_packed_rgb) {
+ av_log(ctx, AV_LOG_WARNING,
+ "The rgb option is deprecated and is overriding the format option, use format instead\n");
+ over->format = OVERLAY_FORMAT_RGB;
+ }
+ return 0;
+}
+
static av_cold void uninit(AVFilterContext *ctx)
{
- OverlayContext *s = ctx->priv;
+ OverlayContext *over = ctx->priv;
- av_frame_free(&s->main);
- av_frame_free(&s->over_prev);
- av_frame_free(&s->over_next);
+ av_frame_free(&over->overpicref);
+ ff_bufqueue_discard_all(&over->queue_main);
+ ff_bufqueue_discard_all(&over->queue_over);
+ av_expr_free(over->x_pexpr); over->x_pexpr = NULL;
+ av_expr_free(over->y_pexpr); over->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 *over = ctx->priv;
+
+ over->var_values[VAR_X] = av_expr_eval(over->x_pexpr, over->var_values, NULL);
+ over->var_values[VAR_Y] = av_expr_eval(over->y_pexpr, over->var_values, NULL);
+ over->var_values[VAR_X] = av_expr_eval(over->x_pexpr, over->var_values, NULL);
+ over->x = normalize_xy(over->var_values[VAR_X], over->hsub);
+ over->y = normalize_xy(over->var_values[VAR_Y], over->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 *over = ctx->priv;
+ int ret;
+
+ if (!strcmp(cmd, "x"))
+ ret = set_expr(&over->x_pexpr, args, cmd, ctx);
+ else if (!strcmp(cmd, "y"))
+ ret = set_expr(&over->y_pexpr, args, cmd, ctx);
+ else
+ ret = AVERROR(ENOSYS);
+
+ if (ret < 0)
+ return ret;
+
+ if (over->eval_mode == EVAL_MODE_INIT) {
+ eval_expr(ctx);
+ av_log(ctx, AV_LOG_VERBOSE, "x:%f xi:%d y:%f yi:%d\n",
+ over->var_values[VAR_X], over->x,
+ over->var_values[VAR_Y], over->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 *over = ctx->priv;
+
+ /* 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 (over->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(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 );
+ 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 *over = inlink->dst->priv;
const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
- av_image_fill_max_pixsteps(over->max_plane_step, NULL, pix_desc);
+ av_image_fill_max_pixsteps(over->main_pix_step, NULL, pix_desc);
+
over->hsub = pix_desc->log2_chroma_w;
over->vsub = pix_desc->log2_chroma_h;
+ over->main_is_packed_rgb =
+ ff_fill_rgba_map(over->main_rgba_map, inlink->format) >= 0;
+ over->main_has_alpha = ff_fmt_is_in(inlink->format, alpha_pix_fmts);
return 0;
}
@@ -115,60 +287,47 @@ static int config_input_overlay(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
OverlayContext *over = 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(over->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 = over->x_expr), var_names, var_values,
- NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
- goto fail;
- over->x = res;
- if ((ret = av_expr_parse_and_eval(&res, (expr = over->y_expr), var_names, var_values,
- NULL, NULL, NULL, NULL, NULL, 0, ctx)))
- goto fail;
- over->y = res;
- /* x may depend on y */
- if ((ret = av_expr_parse_and_eval(&res, (expr = over->x_expr), var_names, var_values,
- NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
- goto fail;
- over->x = res;
+ over->var_values[VAR_MAIN_W ] = over->var_values[VAR_MW] = ctx->inputs[MAIN ]->w;
+ over->var_values[VAR_MAIN_H ] = over->var_values[VAR_MH] = ctx->inputs[MAIN ]->h;
+ over->var_values[VAR_OVERLAY_W] = over->var_values[VAR_OW] = ctx->inputs[OVERLAY]->w;
+ over->var_values[VAR_OVERLAY_H] = over->var_values[VAR_OH] = ctx->inputs[OVERLAY]->h;
+ over->var_values[VAR_HSUB] = 1<<pix_desc->log2_chroma_w;
+ over->var_values[VAR_VSUB] = 1<<pix_desc->log2_chroma_h;
+ over->var_values[VAR_X] = NAN;
+ over->var_values[VAR_Y] = NAN;
+ over->var_values[VAR_N] = 0;
+ over->var_values[VAR_T] = NAN;
+ over->var_values[VAR_POS] = NAN;
+
+ if ((ret = set_expr(&over->x_pexpr, over->x_expr, "x", ctx)) < 0 ||
+ (ret = set_expr(&over->y_pexpr, over->y_expr, "y", ctx)) < 0)
+ return ret;
+
+ over->overlay_is_packed_rgb =
+ ff_fill_rgba_map(over->overlay_rgba_map, inlink->format) >= 0;
+ over->overlay_has_alpha = ff_fmt_is_in(inlink->format, alpha_pix_fmts);
+
+ if (over->eval_mode == EVAL_MODE_INIT) {
+ eval_expr(ctx);
+ av_log(ctx, AV_LOG_VERBOSE, "x:%f xi:%d y:%f yi:%d\n",
+ over->var_values[VAR_X], over->x,
+ over->var_values[VAR_Y], over->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),
- over->x, over->y,
ctx->inputs[OVERLAY]->w, ctx->inputs[OVERLAY]->h,
av_get_pix_fmt_name(ctx->inputs[OVERLAY]->format));
-
- if (over->x < 0 || over->y < 0 ||
- over->x + var_values[VAR_OVERLAY_W] > var_values[VAR_MAIN_W] ||
- over->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",
- over->x, over->y,
- (int)(over->x + var_values[VAR_OVERLAY_W]),
- (int)(over->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)
@@ -182,71 +341,196 @@ static int config_output(AVFilterLink *outlink)
return 0;
}
-static void blend_frame(AVFilterContext *ctx,
+// 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, AVFrame *src,
int x, int y)
{
OverlayContext *over = 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+dst_w < 0 ||
+ y >= dst_h || y+dst_h < 0)
+ return; /* no intersection */
+
+ if (over->main_is_packed_rgb) {
+ uint8_t alpha; ///< the amount of overlay to blend on to main
+ const int dr = over->main_rgba_map[R];
+ const int dg = over->main_rgba_map[G];
+ const int db = over->main_rgba_map[B];
+ const int da = over->main_rgba_map[A];
+ const int dstep = over->main_pix_step[0];
+ const int sr = over->overlay_rgba_map[R];
+ const int sg = over->overlay_rgba_map[G];
+ const int sb = over->overlay_rgba_map[B];
+ const int sa = over->overlay_rgba_map[A];
+ const int sstep = over->overlay_pix_step[0];
+ const int main_has_alpha = over->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 = over->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 ? over->hsub : 0;
int vsub = i ? over->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 +542,191 @@ static void blend_frame(AVFilterContext *ctx,
}
}
-static int filter_frame_main(AVFilterLink *inlink, AVFrame *frame)
+static int try_filter_frame(AVFilterContext *ctx, AVFrame *mainpic)
{
- OverlayContext *s = inlink->dst->priv;
+ OverlayContext *over = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFrame *next_overpic;
+ int ret;
- av_assert0(!s->main);
- s->main = frame;
+ /* Discard obsolete overlay frames: if there is a next overlay frame with pts
+ * before the main frame, we can drop the current overlay. */
+ while (1) {
+ next_overpic = ff_bufqueue_peek(&over->queue_over, 0);
+ if (!next_overpic && over->overlay_eof && !over->repeatlast) {
+ av_frame_free(&over->overpicref);
+ break;
+ }
+ if (!next_overpic || av_compare_ts(next_overpic->pts, ctx->inputs[OVERLAY]->time_base,
+ mainpic->pts , ctx->inputs[MAIN]->time_base) > 0)
+ break;
+ ff_bufqueue_get(&over->queue_over);
+ av_frame_free(&over->overpicref);
+ over->overpicref = next_overpic;
+ }
- return 0;
+ /* If there is no next frame and no EOF and the overlay frame is before
+ * the main frame, we can not know yet if it will be superseded. */
+ if (!over->queue_over.available && !over->overlay_eof &&
+ (!over->overpicref || av_compare_ts(over->overpicref->pts, ctx->inputs[OVERLAY]->time_base,
+ mainpic->pts , ctx->inputs[MAIN]->time_base) < 0))
+ return AVERROR(EAGAIN);
+
+ /* At this point, we know that the current overlay frame extends to the
+ * time of the main frame. */
+ av_dlog(ctx, "main_pts:%s main_pts_time:%s",
+ av_ts2str(mainpic->pts), av_ts2timestr(mainpic->pts, &ctx->inputs[MAIN]->time_base));
+ if (over->overpicref)
+ av_dlog(ctx, " over_pts:%s over_pts_time:%s",
+ av_ts2str(over->overpicref->pts), av_ts2timestr(over->overpicref->pts, &ctx->inputs[OVERLAY]->time_base));
+ av_dlog(ctx, "\n");
+
+ if (over->overpicref) {
+ if (over->eval_mode == EVAL_MODE_FRAME) {
+ int64_t pos = av_frame_get_pkt_pos(mainpic);
+
+ over->var_values[VAR_N] = inlink->frame_count;
+ over->var_values[VAR_T] = mainpic->pts == AV_NOPTS_VALUE ?
+ NAN : mainpic->pts * av_q2d(inlink->time_base);
+ over->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",
+ over->var_values[VAR_N], over->var_values[VAR_T], over->var_values[VAR_POS],
+ over->var_values[VAR_X], over->x,
+ over->var_values[VAR_Y], over->y);
+ }
+ if (!ctx->is_disabled)
+ blend_image(ctx, mainpic, over->overpicref, over->x, over->y);
+
+ }
+ ret = ff_filter_frame(ctx->outputs[0], mainpic);
+ av_assert1(ret != AVERROR(EAGAIN));
+ over->frame_requested = 0;
+ return ret;
}
-static int filter_frame_overlay(AVFilterLink *inlink, AVFrame *frame)
+static int try_filter_next_frame(AVFilterContext *ctx)
{
- OverlayContext *s = inlink->dst->priv;
+ OverlayContext *over = ctx->priv;
+ AVFrame *next_mainpic = ff_bufqueue_peek(&over->queue_main, 0);
+ int ret;
- av_assert0(!s->over_next);
- s->over_next = frame;
+ if (!next_mainpic)
+ return AVERROR(EAGAIN);
+ if ((ret = try_filter_frame(ctx, next_mainpic)) == AVERROR(EAGAIN))
+ return ret;
+ ff_bufqueue_get(&over->queue_main);
+ return ret;
+}
- return 0;
+static int flush_frames(AVFilterContext *ctx)
+{
+ int ret;
+
+ while (!(ret = try_filter_next_frame(ctx)));
+ return ret == AVERROR(EAGAIN) ? 0 : ret;
}
-static int output_frame(AVFilterContext *ctx)
+static int filter_frame_main(AVFilterLink *inlink, AVFrame *inpicref)
{
- OverlayContext *s = ctx->priv;
- AVFilterLink *outlink = ctx->outputs[0];
- int ret = ff_filter_frame(outlink, s->main);
- s->main = NULL;
+ AVFilterContext *ctx = inlink->dst;
+ OverlayContext *over = ctx->priv;
+ int ret;
- return ret;
+ if ((ret = flush_frames(ctx)) < 0)
+ return ret;
+ if ((ret = try_filter_frame(ctx, inpicref)) < 0) {
+ if (ret != AVERROR(EAGAIN))
+ return ret;
+ ff_bufqueue_add(ctx, &over->queue_main, inpicref);
+ }
+
+ if (!over->overpicref)
+ return 0;
+ flush_frames(ctx);
+
+ return 0;
}
-static int handle_overlay_eof(AVFilterContext *ctx)
+static int filter_frame_over(AVFilterLink *inlink, AVFrame *inpicref)
{
- OverlayContext *s = ctx->priv;
- if (s->over_prev)
- blend_frame(ctx, s->main, s->over_prev, s->x, s->y);
- return output_frame(ctx);
+ AVFilterContext *ctx = inlink->dst;
+ OverlayContext *over = ctx->priv;
+ int ret;
+
+ if ((ret = flush_frames(ctx)) < 0)
+ return ret;
+ ff_bufqueue_add(ctx, &over->queue_over, inpicref);
+ ret = try_filter_next_frame(ctx);
+ return ret == AVERROR(EAGAIN) ? 0 : ret;
}
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]);
+ OverlayContext *over = ctx->priv;
+ int input, ret;
+
+ if (!try_filter_next_frame(ctx))
+ return 0;
+ over->frame_requested = 1;
+ while (over->frame_requested) {
+ /* TODO if we had a frame duration, we could guess more accurately */
+ input = !over->overlay_eof && (over->queue_main.available ||
+ over->queue_over.available < 2) ?
+ OVERLAY : MAIN;
+ ret = ff_request_frame(ctx->inputs[input]);
+ /* EOF on main is reported immediately */
+ if (ret == AVERROR_EOF && input == OVERLAY) {
+ over->overlay_eof = 1;
+ if (over->shortest)
+ return ret;
+ if ((ret = try_filter_next_frame(ctx)) != AVERROR(EAGAIN))
+ return ret;
+ ret = 0; /* continue requesting frames on 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);
- }
-
- return output_frame(ctx);
+ 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(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(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,
+ .get_video_buffer = ff_null_get_video_buffer,
.config_props = config_input_main,
.filter_frame = filter_frame_main,
.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_over,
},
{ NULL }
};
@@ -397,13 +745,16 @@ AVFilter avfilter_vf_overlay = {
.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,
+ .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..cdc0e7c
--- /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 <ubitux@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.
+ */
+
+/**
+ * @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 avfilter_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 791a561..3407679 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
*/
@@ -35,6 +35,7 @@
#include "libavutil/colorspace.h"
#include "libavutil/avassert.h"
#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
@@ -42,9 +43,6 @@
#include "drawutils.h"
static const char *const var_names[] = {
- "PI",
- "PHI",
- "E",
"in_w", "iw",
"in_h", "ih",
"out_w", "ow",
@@ -52,15 +50,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 +65,8 @@ enum var_name {
VAR_X,
VAR_Y,
VAR_A,
+ VAR_SAR,
+ VAR_DAR,
VAR_HSUB,
VAR_VSUB,
VARS_NB
@@ -75,22 +74,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;
}
@@ -105,57 +89,42 @@ typedef struct {
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 *pad = ctx->priv;
- if (av_parse_color(pad->color, pad->color_str, -1, ctx) < 0)
+ if (av_parse_color(pad->rgba_color, pad->color_str, -1, ctx) < 0)
return AVERROR(EINVAL);
return 0;
}
-static av_cold void uninit(AVFilterContext *ctx)
-{
- PadContext *pad = ctx->priv;
- int i;
-
- for (i = 0; i < 4; i++) {
- av_freep(&pad->line[i]);
- pad->line_step[i] = 0;
- }
-}
-
static int config_input(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
PadContext *pad = 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;
- pad->hsub = pix_desc->log2_chroma_w;
- pad->vsub = pix_desc->log2_chroma_h;
+ ff_draw_init(&pad->draw, inlink->format, 0);
+ ff_draw_color(&pad->draw, &pad->color, pad->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<<pad->hsub;
- var_values[VAR_VSUB] = 1<<pad->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 << pad->draw.hsub_max;
+ var_values[VAR_VSUB] = 1 << pad->draw.vsub_max;
/* evaluate width and height */
av_expr_parse_and_eval(&res, (expr = pad->w_expr),
@@ -202,22 +171,16 @@ static int config_input(AVFilterLink *inlink)
if (!pad->h)
pad->h = inlink->h;
- pad->w &= ~((1 << pad->hsub) - 1);
- pad->h &= ~((1 << pad->vsub) - 1);
- pad->x &= ~((1 << pad->hsub) - 1);
- pad->y &= ~((1 << pad->vsub) - 1);
-
- pad->in_w = inlink->w & ~((1 << pad->hsub) - 1);
- pad->in_h = inlink->h & ~((1 << pad->vsub) - 1);
+ pad->w = ff_draw_round_to_sub(&pad->draw, 0, -1, pad->w);
+ pad->h = ff_draw_round_to_sub(&pad->draw, 1, -1, pad->h);
+ pad->x = ff_draw_round_to_sub(&pad->draw, 0, -1, pad->x);
+ pad->y = ff_draw_round_to_sub(&pad->draw, 1, -1, pad->y);
+ pad->in_w = ff_draw_round_to_sub(&pad->draw, 0, -1, inlink->w);
+ pad->in_h = ff_draw_round_to_sub(&pad->draw, 1, -1, inlink->h);
- memcpy(rgba_color, pad->color, sizeof(rgba_color));
- ff_fill_line_with_color(pad->line, pad->line_step, pad->w, pad->color,
- inlink->format, rgba_color, &is_packed_rgba, NULL);
-
- av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d -> w:%d h:%d x:%d y:%d color:0x%02X%02X%02X%02X[%s]\n",
+ av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d -> w:%d h:%d x:%d y:%d color:0x%02X%02X%02X%02X\n",
inlink->w, inlink->h, pad->w, pad->h, pad->x, pad->y,
- pad->color[0], pad->color[1], pad->color[2], pad->color[3],
- is_packed_rgba ? "rgba" : "yuva");
+ pad->rgba_color[0], pad->rgba_color[1], pad->rgba_color[2], pad->rgba_color[3]);
if (pad->x < 0 || pad->y < 0 ||
pad->w <= 0 || pad->h <= 0 ||
@@ -263,11 +226,10 @@ static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
frame->height = h;
for (plane = 0; plane < 4 && frame->data[plane]; plane++) {
- int hsub = (plane == 1 || plane == 2) ? pad->hsub : 0;
- int vsub = (plane == 1 || plane == 2) ? pad->vsub : 0;
-
- frame->data[plane] += (pad->x >> hsub) * pad->line_step[plane] +
- (pad->y >> vsub) * frame->linesize[plane];
+ int hsub = pad->draw.hsub[plane];
+ int vsub = pad->draw.vsub[plane];
+ frame->data[plane] += (pad->x >> hsub) * pad->draw.pixelstep[plane] +
+ (pad->y >> vsub) * frame->linesize[plane];
}
return frame;
@@ -288,22 +250,22 @@ 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)
@@ -311,9 +273,9 @@ static int buffer_needs_copy(PadContext *s, AVFrame *frame, AVBufferRef *buf)
#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;
@@ -334,7 +296,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 +323,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) ? pad->hsub : 0;
- int vsub = (i == 1 || i == 2) ? pad->vsub : 0;
- out->data[i] -= (pad->x >> hsub) * pad->line_step[i] +
+ for (i = 0; i < 4 && out->data[i]; i++) {
+ int hsub = pad->draw.hsub[i];
+ int vsub = pad->draw.vsub[i];
+ out->data[i] -= (pad->x >> hsub) * pad->draw.pixelstep[i] +
(pad->y >> vsub) * out->linesize[i];
}
}
/* top bar */
if (pad->y) {
- ff_draw_rectangle(out->data, out->linesize,
- pad->line, pad->line_step, pad->hsub, pad->vsub,
+ ff_fill_rectangle(&pad->draw, &pad->color,
+ out->data, out->linesize,
0, 0, pad->w, pad->y);
}
/* bottom bar */
if (pad->h > pad->y + pad->in_h) {
- ff_draw_rectangle(out->data, out->linesize,
- pad->line, pad->line_step, pad->hsub, pad->vsub,
+ ff_fill_rectangle(&pad->draw, &pad->color,
+ out->data, out->linesize,
0, pad->y + pad->in_h, pad->w, pad->h - pad->y - pad->in_h);
}
/* left border */
- ff_draw_rectangle(out->data, out->linesize, pad->line, pad->line_step,
- pad->hsub, pad->vsub, 0, pad->y, pad->x, in->height);
+ ff_fill_rectangle(&pad->draw, &pad->color, out->data, out->linesize,
+ 0, pad->y, pad->x, in->height);
if (needs_copy) {
- ff_copy_rectangle(out->data, out->linesize, in->data, in->linesize,
- pad->line_step, pad->hsub, pad->vsub,
- pad->x, pad->y, 0, in->width, in->height);
+ ff_copy_rectangle2(&pad->draw,
+ out->data, out->linesize, in->data, in->linesize,
+ pad->x, pad->y, 0, 0, in->width, in->height);
}
/* right border */
- ff_draw_rectangle(out->data, out->linesize,
- pad->line, pad->line_step, pad->hsub, pad->vsub,
+ ff_fill_rectangle(&pad->draw, &pad->color, out->data, out->linesize,
pad->x + pad->in_w, pad->y, pad->w - pad->x - pad->in_w,
in->height);
@@ -408,24 +369,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 },
+#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(color_str), AV_OPT_TYPE_STRING, {.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[] = {
{
@@ -454,7 +411,6 @@ AVFilter avfilter_vf_pad = {
.priv_size = sizeof(PadContext),
.priv_class = &pad_class,
.init = init,
- .uninit = uninit,
.query_formats = query_formats,
.inputs = avfilter_vf_pad_inputs,
diff --git a/libavfilter/vf_pixdesctest.c b/libavfilter/vf_pixdesctest.c
index 5407ec6..7fd2c78 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
*/
@@ -80,7 +80,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
/* 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;
@@ -88,7 +88,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
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);
diff --git a/libavfilter/vf_pp.c b/libavfilter/vf_pp.c
new file mode 100644
index 0000000..3ab46b8
--- /dev/null
+++ b/libavfilter/vf_pp.c
@@ -0,0 +1,184 @@
+/*
+ * 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);
+ 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 avfilter_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_removelogo.c b/libavfilter/vf_removelogo.c
new file mode 100644
index 0000000..2b385fc
--- /dev/null
+++ b/libavfilter/vf_removelogo.c
@@ -0,0 +1,582 @@
+/*
+ * 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, *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 + w) >= current_pass &&
+ *(current_pixel - w) >= 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_free(src_data[0]);
+ av_free(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 *removelogo = ctx->priv;
+ int ***mask;
+ int ret = 0;
+ int a, b, c, w, h;
+ int full_max_mask_size, half_max_mask_size;
+
+ if (!removelogo->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(&removelogo->full_mask_data, &w, &h, removelogo->filename, ctx)) < 0)
+ return ret;
+ removelogo->mask_w = w;
+ removelogo->mask_h = h;
+
+ convert_mask_to_strength_mask(removelogo->full_mask_data, w, w, h,
+ 16, &full_max_mask_size);
+
+ /* Create the scaled down mask image for the chroma planes. */
+ if (!(removelogo->half_mask_data = av_mallocz(w/2 * h/2)))
+ return AVERROR(ENOMEM);
+ generate_half_size_image(removelogo->full_mask_data, w,
+ removelogo->half_mask_data, w/2,
+ w, h, &half_max_mask_size);
+
+ removelogo->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 **) * (removelogo->max_mask_size + 1));
+ if (!mask)
+ return AVERROR(ENOMEM);
+
+ for (a = 0; a <= removelogo->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;
+ }
+ }
+ }
+ removelogo->mask = mask;
+
+ /* Calculate our bounding rectangles, which determine in what
+ * region the logo resides for faster processing. */
+ ff_calculate_bounding_box(&removelogo->full_mask_bbox, removelogo->full_mask_data, w, w, h, 0);
+ ff_calculate_bounding_box(&removelogo->half_mask_bbox, removelogo->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", \
+ removelogo->mask_type##_mask_bbox.x1, removelogo->mask_type##_mask_bbox.x2, \
+ removelogo->mask_type##_mask_bbox.y1, removelogo->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 *removelogo = ctx->priv;
+
+ if (inlink->w != removelogo->mask_w || inlink->h != removelogo->mask_h) {
+ av_log(ctx, AV_LOG_INFO,
+ "Mask image size %dx%d does not match with the input video size %dx%d\n",
+ removelogo->mask_w, removelogo->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 *removelogo = 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(removelogo->mask,
+ inpicref ->data[0], inpicref ->linesize[0],
+ outpicref->data[0], outpicref->linesize[0],
+ removelogo->full_mask_data, inlink->w,
+ inlink->w, inlink->h, direct, &removelogo->full_mask_bbox);
+ blur_image(removelogo->mask,
+ inpicref ->data[1], inpicref ->linesize[1],
+ outpicref->data[1], outpicref->linesize[1],
+ removelogo->half_mask_data, inlink->w/2,
+ inlink->w/2, inlink->h/2, direct, &removelogo->half_mask_bbox);
+ blur_image(removelogo->mask,
+ inpicref ->data[2], inpicref ->linesize[2],
+ outpicref->data[2], outpicref->linesize[2],
+ removelogo->half_mask_data, inlink->w/2,
+ inlink->w/2, inlink->h/2, direct, &removelogo->half_mask_bbox);
+
+ if (!direct)
+ av_frame_free(&inpicref);
+
+ return ff_filter_frame(outlink, outpicref);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ RemovelogoContext *removelogo = ctx->priv;
+ int a, b;
+
+ av_freep(&removelogo->full_mask_data);
+ av_freep(&removelogo->half_mask_data);
+
+ if (removelogo->mask) {
+ /* Loop through each mask. */
+ for (a = 0; a <= removelogo->max_mask_size; a++) {
+ /* Loop through each scanline in a mask. */
+ for (b = -a; b <= a; b++) {
+ av_free(removelogo->mask[a][b + a]); /* Free a scanline. */
+ }
+ av_free(removelogo->mask[a]);
+ }
+ /* Free the array of pointers pointing to the masks. */
+ av_freep(&removelogo->mask);
+ }
+}
+
+static const AVFilterPad removelogo_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .get_video_buffer = ff_null_get_video_buffer,
+ .config_props = config_props_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad removelogo_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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_scale.c b/libavfilter/vf_scale.c
index 573e0b1..b1246fe 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,7 @@ enum var_name {
typedef struct {
const AVClass *class;
struct SwsContext *sws; ///< software scaler context
+ struct SwsContext *isws[2]; ///< software scaler context for interlaced material
/**
* New dimensions. Special values are:
@@ -78,11 +78,14 @@ 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
@@ -92,13 +95,44 @@ typedef struct {
static av_cold int init(AVFilterContext *ctx)
{
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 = SWS_BILINEAR;
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;
}
@@ -110,7 +144,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_opt_free(scale);
}
static int query_formats(AVFilterContext *ctx)
@@ -133,7 +170,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);
@@ -149,6 +186,7 @@ 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 +194,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;
@@ -215,13 +251,12 @@ 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);
@@ -230,34 +265,91 @@ static int config_props(AVFilterLink *outlink)
scale->sws = NULL;
else {
scale->sws = sws_getContext(inlink ->w, inlink ->h, inlink ->format,
- outlink->w, outlink->h, outlink->format,
+ outlink->w, outlink->h, outfmt,
scale->flags, NULL, NULL, NULL);
- if (!scale->sws)
+ if (scale->isws[0])
+ sws_freeContext(scale->isws[0]);
+ scale->isws[0] = sws_getContext(inlink ->w, inlink ->h/2, inlink ->format,
+ outlink->w, outlink->h/2, outfmt,
+ scale->flags, NULL, NULL, NULL);
+ if (scale->isws[1])
+ sws_freeContext(scale->isws[1]);
+ scale->isws[1] = sws_getContext(inlink ->w, inlink ->h/2, inlink ->format,
+ outlink->w, outlink->h/2, outfmt,
+ scale->flags, NULL, NULL, NULL);
+ if (!scale->sws || !scale->isws[0] || !scale->isws[1])
return AVERROR(EINVAL);
}
-
- if (inlink->sample_aspect_ratio.num)
- outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w,
- outlink->w*inlink->h},
- inlink->sample_aspect_ratio);
- else
+ if (inlink->sample_aspect_ratio.num){
+ outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink->w, outlink->w * inlink->h}, inlink->sample_aspect_ratio);
+ } else
outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
+ av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d fmt:%s sar:%d/%d flags:0x%0x\n",
+ inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format),
+ inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den,
+ outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format),
+ outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den,
+ scale->flags);
return 0;
fail:
av_log(NULL, AV_LOG_ERROR,
- "Error when evaluating the expression '%s'\n", expr);
+ "Error when evaluating the expression '%s'.\n"
+ "Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing.\n",
+ expr, scale->w_expr, scale->h_expr);
return ret;
}
+static int scale_slice(AVFilterLink *link, AVFrame *out_buf, AVFrame *cur_pic, struct SwsContext *sws, int y, int h, int mul, int field)
+{
+ ScaleContext *scale = link->dst->priv;
+ const uint8_t *in[4];
+ uint8_t *out[4];
+ int in_stride[4],out_stride[4];
+ int i;
+
+ for(i=0; i<4; i++){
+ int vsub= ((i+1)&2) ? scale->vsub : 0;
+ in_stride[i] = cur_pic->linesize[i] * mul;
+ out_stride[i] = out_buf->linesize[i] * mul;
+ in[i] = cur_pic->data[i] + ((y>>vsub)+field) * cur_pic->linesize[i];
+ out[i] = out_buf->data[i] + field * out_buf->linesize[i];
+ }
+ if(scale->input_is_pal)
+ in[1] = cur_pic->data[1];
+ if(scale->output_is_pal)
+ out[1] = out_buf->data[1];
+
+ return sws_scale(sws, in, in_stride, y/mul, h,
+ out,out_stride);
+}
+
static int filter_frame(AVFilterLink *link, AVFrame *in)
{
ScaleContext *scale = link->dst->priv;
AVFilterLink *outlink = link->dst->outputs[0];
AVFrame *out;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
+ char buf[32];
+
+ 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,33 +367,41 @@ 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);
+
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);
}
#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 },
+ { "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 },
{ NULL },
};
-static const AVClass scale_class = {
- .class_name = "scale",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(scale);
static const AVFilterPad avfilter_vf_scale_inputs[] = {
{
diff --git a/libavfilter/vf_select.c b/libavfilter/vf_select.c
deleted file mode 100644
index c9b2b92..0000000
--- a/libavfilter/vf_select.c
+++ /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 avfilter_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..c91c0c1
--- /dev/null
+++ b/libavfilter/vf_separatefields.c
@@ -0,0 +1,111 @@
+/*
+ * 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;
+ double ts_unit;
+} 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;
+ sf->ts_unit = av_q2d(av_inv_q(av_mul_q(outlink->frame_rate, outlink->time_base)));
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
+{
+ AVFilterContext *ctx = inlink->dst;
+ SeparateFieldsContext *sf = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *second;
+ int i, ret;
+
+ inpicref->height = outlink->h;
+ inpicref->interlaced_frame = 0;
+
+ second = av_frame_clone(inpicref);
+ if (!second)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < sf->nb_planes; i++) {
+ if (!inpicref->top_field_first)
+ inpicref->data[i] = inpicref->data[i] + inpicref->linesize[i];
+ else
+ second->data[i] = second->data[i] + second->linesize[i];
+ inpicref->linesize[i] *= 2;
+ second->linesize[i] *= 2;
+ }
+
+ inpicref->pts = outlink->frame_count * sf->ts_unit;
+ ret = ff_filter_frame(outlink, inpicref);
+ if (ret < 0)
+ return ret;
+
+ second->pts = outlink->frame_count * sf->ts_unit;
+ return ff_filter_frame(outlink, second);
+}
+
+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,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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..4d42cfa
--- /dev/null
+++ b/libavfilter/vf_setfield.c
@@ -0,0 +1,95 @@
+/*
+ * 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,
+ .get_video_buffer = ff_null_get_video_buffer,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad setfield_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_vf_setfield = {
+ .name = "setfield",
+ .description = NULL_IF_CONFIG_SMALL("Force field for the output video frame."),
+ .priv_size = sizeof(SetFieldContext),
+ .inputs = setfield_inputs,
+ .outputs = setfield_outputs,
+ .priv_class = &setfield_class,
+};
diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c
index 04b436d..9acadcf 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,6 +26,7 @@
#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"
@@ -42,10 +43,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
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]; 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 +59,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
}
av_log(ctx, AV_LOG_INFO,
- "n:%d pts:%"PRId64" pts_time:%f "
+ "n:%d 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",
+ "checksum:%08X plane_checksum:[%08X",
showinfo->frame,
- frame->pts, frame->pts * av_q2d(inlink->time_base),
+ 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,7 +71,11 @@ 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]; 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);
diff --git a/libavfilter/vf_smartblur.c b/libavfilter/vf_smartblur.c
new file mode 100644
index 0000000..a0013a2
--- /dev/null
+++ b/libavfilter/vf_smartblur.c
@@ -0,0 +1,306 @@
+/*
+ * 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 avfilter_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_stereo3d.c b/libavfilter/vf_stereo3d.c
new file mode 100644
index 0000000..ec3ab47
--- /dev/null
+++ b/libavfilter/vf_stereo3d.c
@@ -0,0 +1,623 @@
+/*
+ * 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 "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;
+ int ana_matrix[3][6];
+ int nb_planes;
+ int linesize[4];
+ 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_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_YUV444P, AV_PIX_FMT_YUVA444P,
+ AV_PIX_FMT_YUVJ444P,
+ AV_PIX_FMT_YUV444P9LE, AV_PIX_FMT_YUVA444P9LE,
+ AV_PIX_FMT_YUV444P9BE, AV_PIX_FMT_YUVA444P9BE,
+ AV_PIX_FMT_YUV444P10LE, AV_PIX_FMT_YUVA444P10LE,
+ AV_PIX_FMT_YUV444P10BE, AV_PIX_FMT_YUVA444P10BE,
+ AV_PIX_FMT_YUV444P12BE, AV_PIX_FMT_YUV444P12LE,
+ AV_PIX_FMT_YUV444P14BE, AV_PIX_FMT_YUV444P14LE,
+ 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:
+ memcpy(s->ana_matrix, ana_coeff[s->out.format], sizeof(s->ana_matrix));
+ 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)));
+
+ return 0;
+}
+
+static inline uint8_t ana_convert(const int *coeff, uint8_t *left, 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++) {
+ in_off_left[i] = (s->in.row_left + s->in.off_lstep) * ileft->linesize[i] + s->in.off_left * s->pixstep[i];
+ in_off_right[i] = (s->in.row_right + s->in.off_rstep) * iright->linesize[i] + s->in.off_right * s->pixstep[i];
+ out_off_left[i] = (s->out.row_left + s->out.off_lstep) * oleft->linesize[i] + s->out.off_left * s->pixstep[i];
+ out_off_right[i] = (s->out.row_right + s->out.off_rstep) * oright->linesize[i] + s->out.off_right * s->pixstep[i];
+ }
+
+ 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->height);
+ 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->height);
+ }
+ 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->height);
+ }
+ 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 i, x, y, il, ir, o;
+ uint8_t *lsrc = ileft->data[0];
+ uint8_t *rsrc = iright->data[0];
+ uint8_t *dst = out->data[0];
+ int out_width = s->out.width;
+ int *ana_matrix[3];
+
+ for (i = 0; i < 3; i++)
+ ana_matrix[i] = s->ana_matrix[i];
+
+ 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 avfilter_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..b5f5bc9
--- /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 avfilter_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 avfilter_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..4f25968
--- /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 avfilter_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..daa73f2
--- /dev/null
+++ b/libavfilter/vf_swapuv.c
@@ -0,0 +1,111 @@
+/*
+ * 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 avfilter_vf_swapuv = {
+ .name = "swapuv",
+ .description = NULL_IF_CONFIG_SMALL("Swap U and V components."),
+ .priv_size = 0,
+ .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..6e14548
--- /dev/null
+++ b/libavfilter/vf_telecine.c
@@ -0,0 +1,284 @@
+/*
+ * 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))
+ 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);
+ }
+
+ av_frame_copy_props(frame, inpicref);
+ 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 avfilter_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..f0bb3db
--- /dev/null
+++ b/libavfilter/vf_thumbnail.c
@@ -0,0 +1,240 @@
+/*
+ * 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,
+ .get_video_buffer = ff_null_get_video_buffer,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad thumbnail_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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..f5eb763
--- /dev/null
+++ b/libavfilter/vf_tile.c
@@ -0,0 +1,242 @@
+/*
+ * 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;
+} 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 },
+ {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);
+ /* TODO make the color an option, or find an unified way of choosing it */
+ ff_draw_color(&tile->draw, &tile->blank, (uint8_t[]){ 0, 0, 0, -1 });
+
+ 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)
+ 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 avfilter_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..5e89162
--- /dev/null
+++ b/libavfilter/vf_tinterlace.c
@@ -0,0 +1,397 @@
+/*
+ * 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_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUVA420P,
+ 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->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 int request_frame(AVFilterLink *outlink)
+{
+ TInterlaceContext *tinterlace = outlink->src->priv;
+ AVFilterLink *inlink = outlink->src->inputs[0];
+
+ do {
+ int ret;
+
+ if ((ret = ff_request_frame(inlink)) < 0)
+ return ret;
+ } while (!tinterlace->cur);
+
+ return 0;
+}
+
+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,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter avfilter_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 dca12f5..3ee9c6d 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
*/
@@ -28,6 +28,7 @@
#include <stdio.h>
#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
@@ -37,6 +38,12 @@
#include "internal.h"
#include "video.h"
+typedef enum {
+ TRANSPOSE_PT_TYPE_NONE,
+ TRANSPOSE_PT_TYPE_LANDSCAPE,
+ TRANSPOSE_PT_TYPE_PORTRAIT,
+} PassthroughType;
+
enum TransposeDir {
TRANSPOSE_CCLOCK_FLIP,
TRANSPOSE_CLOCK,
@@ -49,36 +56,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 +87,23 @@ static int config_props_output(AVFilterLink *outlink)
const AVPixFmtDescriptor *desc_out = av_pix_fmt_desc_get(outlink->format);
const AVPixFmtDescriptor *desc_in = av_pix_fmt_desc_get(inlink->format);
+ if (trans->dir&4) {
+ av_log(ctx, AV_LOG_WARNING,
+ "dir values greater than 3 are deprecated, use the passthrough option instead\n");
+ trans->dir &= 3;
+ trans->passthrough = TRANSPOSE_PT_TYPE_LANDSCAPE;
+ }
+
+ if ((inlink->w >= inlink->h && trans->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) ||
+ (inlink->w <= inlink->h && trans->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) {
+ av_log(ctx, AV_LOG_VERBOSE,
+ "w:%d h:%d -> w:%d h:%d (passthrough mode)\n",
+ inlink->w, inlink->h, inlink->w, inlink->h);
+ return 0;
+ } else {
+ trans->passthrough = TRANSPOSE_PT_TYPE_NONE;
+ }
+
trans->hsub = desc_in->log2_chroma_w;
trans->vsub = desc_in->log2_chroma_h;
@@ -110,13 +124,25 @@ static int config_props_output(AVFilterLink *outlink)
return 0;
}
+static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
+{
+ TransContext *trans = inlink->dst->priv;
+
+ return trans->passthrough ?
+ ff_null_get_video_buffer (inlink, w, h) :
+ ff_default_get_video_buffer(inlink, w, h);
+}
+
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{
- AVFilterLink *outlink = inlink->dst->outputs[0];
TransContext *trans = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
AVFrame *out;
int plane;
+ 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);
@@ -137,8 +163,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
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);
uint8_t *dst, *src;
int dstlinesize, srclinesize;
int x, y;
@@ -178,6 +204,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
for (x = 0; x < outw; x++)
*((uint32_t *)(dst + 4*x)) = *((uint32_t *)(src + x*srclinesize + y*4));
break;
+ case 6:
+ 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 (x = 0; x < outw; x++)
+ *((uint64_t *)(dst + 8*x)) = *((uint64_t *)(src + x*srclinesize + y*8));
+ break;
}
dst += dstlinesize;
}
@@ -188,28 +224,31 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
#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" },
+#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" },
+
+ { "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 },
};
-static const AVClass transpose_class = {
- .class_name = "transpose",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(transpose);
static const AVFilterPad avfilter_vf_transpose_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
+ .get_video_buffer= get_video_buffer,
.filter_frame = filter_frame,
},
{ NULL }
diff --git a/libavfilter/vf_unsharp.c b/libavfilter/vf_unsharp.c
index 0153edc..9b659bd 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 },
+#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[] = {
{
@@ -275,6 +310,6 @@ AVFilter avfilter_vf_unsharp = {
.query_formats = query_formats,
.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 589a059..fc05e61 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];
}
}
diff --git a/libavfilter/vf_vidstabdetect.c b/libavfilter/vf_vidstabdetect.c
new file mode 100644
index 0000000..d96ca8e
--- /dev/null
+++ b/libavfilter/vf_vidstabdetect.c
@@ -0,0 +1,218 @@
+/*
+ * 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 avfilter_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..eee3da7
--- /dev/null
+++ b/libavfilter/vf_vidstabtransform.c
@@ -0,0 +1,292 @@
+/*
+ * 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}, 0, 100, FLAGS},
+ {"optzoom", "0: nothing, 1: determine optimal zoom (added to 'zoom')", OFFSETC(optZoom),
+ AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, 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 avfilter_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_yadif.c b/libavfilter/vf_yadif.c
index 2b89048..5d8934b 100644
--- a/libavfilter/vf_yadif.c
+++ b/libavfilter/vf_yadif.c
@@ -1,24 +1,23 @@
/*
- * 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"
@@ -222,24 +221,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;
@@ -285,6 +266,8 @@ 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);
@@ -297,7 +280,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame)
if (!yadif->cur)
return 0;
- if (yadif->auto_enable && !yadif->cur->interlaced_frame) {
+ if (yadif->deint && !yadif->cur->interlaced_frame) {
yadif->out = av_frame_clone(yadif->cur);
if (!yadif->out)
return AVERROR(ENOMEM);
@@ -343,7 +326,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)
@@ -361,41 +344,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)
@@ -413,13 +368,24 @@ static int query_formats(AVFilterContext *ctx)
AV_NE( AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY16LE ),
AV_PIX_FMT_YUV440P,
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_YUV420P12BE, AV_PIX_FMT_YUV420P12LE ),
+ AV_NE( AV_PIX_FMT_YUV422P12BE, AV_PIX_FMT_YUV422P12LE ),
+ AV_NE( AV_PIX_FMT_YUV444P12BE, AV_PIX_FMT_YUV444P12LE ),
+ AV_NE( AV_PIX_FMT_YUV420P14BE, AV_PIX_FMT_YUV420P14LE ),
+ AV_NE( AV_PIX_FMT_YUV422P14BE, AV_PIX_FMT_YUV422P14LE ),
+ AV_NE( AV_PIX_FMT_YUV444P14BE, AV_PIX_FMT_YUV444P14LE ),
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_YUVA420P,
+ AV_PIX_FMT_YUVA422P,
+ AV_PIX_FMT_YUVA444P,
AV_PIX_FMT_NONE
};
@@ -430,6 +396,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;
@@ -437,6 +404,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;
@@ -444,38 +419,45 @@ static int config_props(AVFilterLink *link)
} else {
s->filter_line = filter_line_c;
s->filter_edges = filter_edges;
-
- if (ARCH_X86)
- ff_yadif_init_x86(s);
}
+ if (ARCH_X86)
+ ff_yadif_init_x86(s);
+
return 0;
}
+
#define OFFSET(x) offsetof(YADIFContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "mode", NULL, OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 3, FLAGS },
- { "parity", NULL, OFFSET(parity), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, FLAGS, "parity" },
- { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, .unit = "parity" },
- { "tff", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, .unit = "parity" },
- { "bff", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, .unit = "parity" },
- { "auto", NULL, OFFSET(auto_enable), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
- { NULL },
-};
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+#define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, INT_MIN, INT_MAX, FLAGS, unit }
+
+static const AVOption yadif_options[] = {
+ { "mode", "specify the interlacing mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=YADIF_MODE_SEND_FRAME}, 0, 3, FLAGS, "mode"},
+ CONST("send_frame", "send one frame for each frame", YADIF_MODE_SEND_FRAME, "mode"),
+ CONST("send_field", "send one frame for each field", YADIF_MODE_SEND_FIELD, "mode"),
+ CONST("send_frame_nospatial", "send one frame for each frame, but skip spatial interlacing check", YADIF_MODE_SEND_FRAME_NOSPATIAL, "mode"),
+ CONST("send_field_nospatial", "send one frame for each field, but skip spatial interlacing check", YADIF_MODE_SEND_FIELD_NOSPATIAL, "mode"),
-static const AVClass yadif_class = {
- .class_name = "yadif",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
+ { "parity", "specify the assumed picture field parity", OFFSET(parity), AV_OPT_TYPE_INT, {.i64=YADIF_PARITY_AUTO}, -1, 1, FLAGS, "parity" },
+ CONST("tff", "assume top field first", YADIF_PARITY_TFF, "parity"),
+ CONST("bff", "assume bottom field first", YADIF_PARITY_BFF, "parity"),
+ CONST("auto", "auto detect parity", YADIF_PARITY_AUTO, "parity"),
+
+ { "deint", "specify which frames to deinterlace", OFFSET(deint), AV_OPT_TYPE_INT, {.i64=YADIF_DEINT_ALL}, 0, 1, FLAGS, "deint" },
+ CONST("all", "deinterlace all frames", YADIF_DEINT_ALL, "deint"),
+ CONST("interlaced", "only deinterlace frames marked as interlaced", YADIF_DEINT_INTERLACED, "deint"),
+
+ {NULL},
};
+AVFILTER_DEFINE_CLASS(yadif);
+
static const AVFilterPad avfilter_vf_yadif_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = get_video_buffer,
.filter_frame = filter_frame,
},
{ NULL }
@@ -485,7 +467,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,
},
@@ -494,7 +475,7 @@ static const AVFilterPad avfilter_vf_yadif_outputs[] = {
AVFilter avfilter_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,
@@ -502,6 +483,5 @@ AVFilter avfilter_vf_yadif = {
.query_formats = query_formats,
.inputs = avfilter_vf_yadif_inputs,
-
.outputs = avfilter_vf_yadif_outputs,
};
diff --git a/libavfilter/video.c b/libavfilter/video.c
index 23bf867..b274070 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"
@@ -40,6 +45,32 @@ AVFrame *ff_default_get_video_buffer(AVFilterLink *link, int w, int h)
AVFrame *frame = av_frame_alloc();
int ret;
+#if 0 //POOL
+ AVFilterPool *pool = link->pool;
+ if (pool) {
+ for (i = 0; i < POOL_SIZE; i++) {
+ picref = pool->pic[i];
+ if (picref && picref->buf->format == link->format && picref->buf->w == w && picref->buf->h == h) {
+ AVFilterBuffer *pic = picref->buf;
+ pool->pic[i] = NULL;
+ pool->count--;
+ av_assert0(!picref->video->qp_table);
+ picref->video->w = w;
+ picref->video->h = h;
+ picref->perms = full_perms;
+ picref->format = link->format;
+ pic->refcount = 1;
+ memcpy(picref->data, pic->data, sizeof(picref->data));
+ memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize));
+ pool->refcount++;
+ return picref;
+ }
+ }
+ } else {
+ pool = link->pool = av_mallocz(sizeof(AVFilterPool));
+ pool->refcount = 1;
+ }
+#endif
if (!frame)
return NULL;
@@ -51,12 +82,20 @@ AVFrame *ff_default_get_video_buffer(AVFilterLink *link, int w, int h)
if (ret < 0)
av_frame_free(&frame);
+#if 0 //POOL
+ memset(data[0], 128, i);
+
+ picref->buf->priv = pool;
+ picref->buf->free = NULL;
+ pool->refcount++;
+#endif
+
return frame;
}
#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 +145,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
--- /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
--- /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 9ab67e1..d498aab 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..a51cda3
--- /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 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 avfilter_vsrc_cellauto = {
+ .name = "cellauto",
+ .description = NULL_IF_CONFIG_SMALL("Create pattern generated by an elementary cellular automaton."),
+ .priv_size = sizeof(CellAutoContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = NULL,
+ .outputs = cellauto_outputs,
+ .priv_class = &cellauto_class,
+};
diff --git a/libavfilter/vsrc_color.c b/libavfilter/vsrc_color.c
deleted file mode 100644
index 3834ec4..0000000
--- a/libavfilter/vsrc_color.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (c) 2010 Stefano Sabatini
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * color source
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include "avfilter.h"
-#include "formats.h"
-#include "internal.h"
-#include "video.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/colorspace.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/internal.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/mem.h"
-#include "libavutil/opt.h"
-#include "libavutil/parseutils.h"
-#include "drawutils.h"
-
-typedef struct {
- 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 avfilter_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..85f0989
--- /dev/null
+++ b/libavfilter/vsrc_life.c
@@ -0,0 +1,466 @@
+/*
+ * 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;
+ char *life_color_str;
+ char *death_color_str;
+ char *mold_color_str;
+ 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_str), AV_OPT_TYPE_STRING, {.str="white"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "death_color", "set death color", OFFSET(death_color_str), AV_OPT_TYPE_STRING, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "mold_color", "set mold color", OFFSET( mold_color_str), AV_OPT_TYPE_STRING, {.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_mallocz(sizeof(char) * life->h * life->w)) ||
+ !(life->buf[1] = av_mallocz(sizeof(char) * life->h * life->w))) {
+ 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 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;
+
+#define PARSE_COLOR(name) do { \
+ if ((ret = av_parse_color(life->name ## _color, life->name ## _color_str, -1, ctx))) { \
+ av_log(ctx, AV_LOG_ERROR, "Invalid " #name " color '%s'\n", \
+ life->name ## _color_str); \
+ return ret; \
+ } \
+ av_freep(&life->name ## _color_str); \
+} while (0)
+
+ PARSE_COLOR(life);
+ PARSE_COLOR(death);
+ PARSE_COLOR(mold);
+
+ 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_mallocz(sizeof(char) * life->h * life->w)) ||
+ !(life->buf[1] = av_mallocz(sizeof(char) * life->h * life->w))) {
+ 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 avfilter_vsrc_life = {
+ .name = "life",
+ .description = NULL_IF_CONFIG_SMALL("Create life."),
+ .priv_size = sizeof(LifeContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = NULL,
+ .outputs = life_outputs,
+ .priv_class = &life_class,
+};
diff --git a/libavfilter/vsrc_mandelbrot.c b/libavfilter/vsrc_mandelbrot.c
new file mode 100644
index 0000000..2633c39
--- /dev/null
+++ b/libavfilter/vsrc_mandelbrot.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2011 Michael Niedermayer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * The vsrc_color filter from Stefano Sabatini was used as template to create
+ * this
+ */
+
+/**
+ * @file
+ * Mandelbrot fraktal renderer
+ */
+
+#include "avfilter.h"
+#include "formats.h"
+#include "video.h"
+#include "internal.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include <float.h>
+#include <math.h>
+
+#define SQR(a) ((a)*(a))
+
+enum Outer{
+ ITERATION_COUNT,
+ NORMALIZED_ITERATION_COUNT,
+ WHITE,
+ OUTZ,
+};
+
+enum Inner{
+ BLACK,
+ PERIOD,
+ CONVTIME,
+ MINCOL,
+};
+
+typedef struct Point {
+ double p[2];
+ uint32_t val;
+} Point;
+
+typedef struct {
+ const AVClass *class;
+ int w, h;
+ AVRational frame_rate;
+ uint64_t pts;
+ int maxiter;
+ double start_x;
+ double start_y;
+ double start_scale;
+ double end_scale;
+ double end_pts;
+ double bailout;
+ 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 avfilter_vsrc_mandelbrot = {
+ .name = "mandelbrot",
+ .description = NULL_IF_CONFIG_SMALL("Render a Mandelbrot fractal."),
+
+ .priv_size = sizeof(MBContext),
+ .init = init,
+ .uninit = uninit,
+
+ .query_formats = query_formats,
+ .inputs = NULL,
+ .outputs = mandelbrot_outputs,
+ .priv_class = &mandelbrot_class,
+};
diff --git a/libavfilter/vsrc_movie.c b/libavfilter/vsrc_movie.c
deleted file mode 100644
index 9cde9d4..0000000
--- a/libavfilter/vsrc_movie.c
+++ /dev/null
@@ -1,287 +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;
-
- av_free(movie->file_name);
- av_free(movie->format_name);
- 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 avfilter_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..e931c76
--- /dev/null
+++ b/libavfilter/vsrc_mptestsrc.c
@@ -0,0 +1,365 @@
+/*
+ * 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;
+ unsigned int frame_nb;
+ 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->frame_nb = 0;
+ 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 = w>>test->hsub, ch = h>>test->vsub;
+ unsigned int frame = test->frame_nb;
+ 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;
+ }
+
+ test->frame_nb++;
+ 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 avfilter_vsrc_mptestsrc = {
+ .name = "mptestsrc",
+ .description = NULL_IF_CONFIG_SMALL("Generate various test pattern."),
+ .priv_size = sizeof(MPTestContext),
+ .init = init,
+
+ .query_formats = query_formats,
+
+ .inputs = NULL,
+ .outputs = mptestsrc_outputs,
+ .priv_class = &mptestsrc_class,
+};
diff --git a/libavfilter/vsrc_nullsrc.c b/libavfilter/vsrc_nullsrc.c
deleted file mode 100644
index 85fb420..0000000
--- a/libavfilter/vsrc_nullsrc.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * null video source
- */
-
-#include <stdio.h>
-
-#include "libavutil/avstring.h"
-#include "libavutil/eval.h"
-#include "libavutil/internal.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/opt.h"
-#include "libavutil/parseutils.h"
-#include "avfilter.h"
-#include "formats.h"
-#include "internal.h"
-
-static const char *const var_names[] = {
- "E",
- "PHI",
- "PI",
- "AVTB", /* default timebase 1/AV_TIME_BASE */
- NULL
-};
-
-enum var_name {
- VAR_E,
- VAR_PHI,
- VAR_PI,
- VAR_AVTB,
- VAR_VARS_NB
-};
-
-typedef struct {
- 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 avfilter_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 e958a7b..dc8984a 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,121 @@
*
* 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 nb_decimals;
+ 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 color */
+ char *color_str;
+ FFDrawContext draw;
+ FFDrawColor color;
+ uint8_t color_rgba[4];
+
/* only used by rgbtest */
- int rgba_map[4];
+ uint8_t rgba_map[4];
} TestSourceContext;
#define OFFSET(x) offsetof(TestSourceContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_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 },
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+#define COMMON_OPTIONS \
+ { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS },\
+ { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS },\
+ { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 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 },
+
+
+static const AVOption color_options[] = {
+ /* only used by color */
+ { "color", "set color", OFFSET(color_str), AV_OPT_TYPE_STRING, {.str = "black"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "c", "set color", OFFSET(color_str), AV_OPT_TYPE_STRING, {.str = "black"}, CHAR_MIN, CHAR_MAX, FLAGS },
+
+ COMMON_OPTIONS
+ { NULL },
+};
+
+static const AVOption options[] = {
+ COMMON_OPTIONS
+ /* only used by testsrc */
+ { "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 },
};
-static av_cold int init_common(AVFilterContext *ctx)
+static av_cold int init(AVFilterContext *ctx)
{
TestSourceContext *test = ctx->priv;
- AVRational frame_rate_q;
- int64_t duration = -1;
int ret = 0;
- 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;
+ if (test->nb_decimals && strcmp(ctx->filter->name, "testsrc")) {
+ av_log(ctx, AV_LOG_WARNING,
+ "Option 'decimals' is ignored with source '%s'\n",
+ ctx->filter->name);
}
- 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;
- }
-
- 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;
+ if (test->color_str) {
+ if (!strcmp(ctx->filter->name, "color")) {
+ ret = av_parse_color(test->color_rgba, test->color_str, -1, ctx);
+ if (ret < 0)
+ return ret;
+ } else {
+ av_log(ctx, AV_LOG_WARNING,
+ "Option 'color' is ignored with source '%s'\n",
+ ctx->filter->name);
+ }
}
- 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 +151,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 +162,188 @@ 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
+
+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;
+
+ av_log(ctx, AV_LOG_VERBOSE, "color:0x%02x%02x%02x%02x\n",
+ test->color_rgba[0], test->color_rgba[1], test->color_rgba[2], test->color_rgba[3]);
+ 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")) {
+ char *color_str;
+ uint8_t color_rgba[4];
+
+ ret = av_parse_color(color_rgba, args, -1, ctx);
+ if (ret < 0)
+ return ret;
+ color_str = av_strdup(args);
+ if (!color_str)
+ return AVERROR(ENOMEM);
+ av_free(test->color_str);
+ test->color_str = color_str;
+
+ 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 avfilter_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_NULLSRC_FILTER
-static const char *testsrc_get_name(void *ctx)
+#define nullsrc_options options
+AVFILTER_DEFINE_CLASS(nullsrc);
+
+static void nullsrc_fill_picture(AVFilterContext *ctx, AVFrame *picref) { }
+
+static av_cold int nullsrc_init(AVFilterContext *ctx)
{
- 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 avfilter_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
+
+#define testsrc_options options
+AVFILTER_DEFINE_CLASS(testsrc);
+
/**
* Fill a rectangle with value val.
*
@@ -168,8 +356,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 +371,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 +466,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 +494,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 +531,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,11 +559,11 @@ AVFilter avfilter_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,
};
@@ -373,16 +571,8 @@ AVFilter avfilter_vsrc_testsrc = {
#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 +581,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 +603,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 +634,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 +657,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,6 +677,7 @@ AVFilter avfilter_vsrc_rgbtestsrc = {
.priv_size = sizeof(TestSourceContext),
.priv_class = &rgbtestsrc_class,
.init = rgbtest_init,
+ .uninit = uninit,
.query_formats = rgbtest_query_formats,
@@ -503,3 +687,263 @@ AVFilter avfilter_vsrc_rgbtestsrc = {
};
#endif /* CONFIG_RGBTESTSRC_FILTER */
+
+#if CONFIG_SMPTEBARS_FILTER || CONFIG_SMPTEHDBARS_FILTER
+
+static const uint8_t rainbow[7][4] = {
+ { 191, 191, 191, 255 }, /* gray */
+ { 191, 191, 0, 255 }, /* yellow */
+ { 0, 191, 191, 255 }, /* cyan */
+ { 0, 191, 0, 255 }, /* green */
+ { 191, 0, 191, 255 }, /* magenta */
+ { 191, 0, 0, 255 }, /* red */
+ { 0, 0, 191, 255 }, /* blue */
+};
+
+static const uint8_t wobnair[7][4] = {
+ { 0, 0, 191, 255 }, /* blue */
+ { 19, 19, 19, 255 }, /* 7.5% intensity black */
+ { 191, 0, 191, 255 }, /* magenta */
+ { 19, 19, 19, 255 }, /* 7.5% intensity black */
+ { 0, 191, 191, 255 }, /* cyan */
+ { 19, 19, 19, 255 }, /* 7.5% intensity black */
+ { 191, 191, 191, 255 }, /* gray */
+};
+
+static const uint8_t white[4] = { 255, 255, 255, 255 };
+static const uint8_t black[4] = { 19, 19, 19, 255 }; /* 7.5% intensity black */
+
+/* pluge pulses */
+static const uint8_t neg4ire[4] = { 9, 9, 9, 255 }; /* 3.5% intensity black */
+static const uint8_t pos4ire[4] = { 29, 29, 29, 255 }; /* 11.5% intensity black */
+
+/* fudged Q/-I */
+static const uint8_t i_pixel[4] = { 0, 68, 130, 255 };
+static const uint8_t q_pixel[4] = { 67, 0, 130, 255 };
+
+static const uint8_t gray40[4] = { 102, 102, 102, 255 };
+static const uint8_t gray15[4] = { 38, 38, 38, 255 };
+static const uint8_t cyan[4] = { 0, 255, 255, 255 };
+static const uint8_t yellow[4] = { 255, 255, 0, 255 };
+static const uint8_t blue[4] = { 0, 0, 255, 255 };
+static const uint8_t red[4] = { 255, 0, 0, 255 };
+static const uint8_t black0[4] = { 5, 5, 5, 255 };
+static const uint8_t black2[4] = { 10, 10, 10, 255 };
+static const uint8_t black4[4] = { 15, 15, 15, 255 };
+static const uint8_t neg2[4] = { 0, 0, 0, 255 };
+
+static void inline draw_bar(TestSourceContext *test, const uint8_t *color,
+ unsigned x, unsigned y, unsigned w, unsigned h,
+ AVFrame *frame)
+{
+ FFDrawColor draw_color;
+
+ 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);
+
+ ff_draw_color(&test->draw, &draw_color, color);
+ ff_fill_rectangle(&test->draw, &draw_color,
+ frame->data, frame->linesize, x, y, w, h);
+}
+
+static int smptebars_query_formats(AVFilterContext *ctx)
+{
+ ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
+ return 0;
+}
+
+static int smptebars_config_props(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ TestSourceContext *test = ctx->priv;
+
+ ff_draw_init(&test->draw, outlink->format, 0);
+
+ return config_props(outlink);
+}
+
+static const AVFilterPad smptebars_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = smptebars_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);
+
+ 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 avfilter_vsrc_smptebars = {
+ .name = "smptebars",
+ .description = NULL_IF_CONFIG_SMALL("Generate SMPTE color bars."),
+ .priv_size = sizeof(TestSourceContext),
+ .init = smptebars_init,
+ .uninit = uninit,
+
+ .query_formats = smptebars_query_formats,
+ .inputs = NULL,
+ .outputs = smptebars_outputs,
+ .priv_class = &smptebars_class,
+};
+
+#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);
+
+ 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] =
+ yramp[1] =
+ yramp[2] = i * 255 / tmp;
+ 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 avfilter_vsrc_smptehdbars = {
+ .name = "smptehdbars",
+ .description = NULL_IF_CONFIG_SMALL("Generate SMPTE HD color bars."),
+ .priv_size = sizeof(TestSourceContext),
+ .init = smptehdbars_init,
+ .uninit = uninit,
+
+ .query_formats = smptebars_query_formats,
+ .inputs = NULL,
+ .outputs = smptebars_outputs,
+ .priv_class = &smptehdbars_class,
+};
+
+#endif /* CONFIG_SMPTEHDBARS_FILTER */
+#endif /* CONFIG_SMPTEBARS_FILTER || CONFIG_SMPTEHDBARS_FILTER */
diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile
index 59cefe8..cd97347 100644
--- a/libavfilter/x86/Makefile
+++ b/libavfilter/x86/Makefile
@@ -5,4 +5,4 @@ OBJS-$(CONFIG_YADIF_FILTER) += x86/vf_yadif_init.o
YASM-OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d.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 bc51dc9..81d605f 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.c b/libavfilter/x86/vf_gradfun.c
index e571af7..10accca 100644
--- a/libavfilter/x86/vf_gradfun.c
+++ b/libavfilter/x86/vf_gradfun.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2009 Loren Merritt <lorenm@u.washignton.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
*/
@@ -30,7 +30,7 @@ DECLARE_ALIGNED(16, static const uint16_t, pw_7f)[8] = {0x7F,0x7F,0x7F,0x7F,0x7F
DECLARE_ALIGNED(16, static const uint16_t, pw_ff)[8] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
#if HAVE_MMXEXT_INLINE
-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)
{
@@ -107,7 +107,7 @@ static void gradfun_filter_line_mmxext(uint8_t *dst, uint8_t *src, uint16_t *dc,
#endif
#if HAVE_SSSE3_INLINE
-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) {
@@ -154,7 +154,7 @@ static void gradfun_filter_line_ssse3(uint8_t *dst, uint8_t *src, uint16_t *dc,
#endif /* HAVE_SSSE3_INLINE */
#if HAVE_SSE2_INLINE
-static void gradfun_blur_line_sse2(uint16_t *dc, uint16_t *buf, uint16_t *buf1, uint8_t *src, int src_linesize, int width)
+static void gradfun_blur_line_sse2(uint16_t *dc, uint16_t *buf, const uint16_t *buf1, const uint8_t *src, int src_linesize, int width)
{
#define BLURV(load)\
intptr_t x = -2*width;\
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_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
--- /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
--- /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 e530c34..1e142f5 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
*/
@@ -128,8 +128,16 @@ 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");
+ return AVERROR_INVALIDDATA;
+ }
fourxm->fps = av_int2float(AV_RL32(&header[i + 12]));
} else if (fourcc_tag == vtrk_TAG) {
/* check that there is enough data */
@@ -169,12 +177,13 @@ static int fourxm_read_header(AVFormatContext *s)
current_track = AV_RL32(&header[i + 8]);
if((unsigned)current_track >= UINT_MAX / sizeof(AudioTrack) - 1){
av_log(s, AV_LOG_ERROR, "current_track too large\n");
- ret= -1;
+ ret = AVERROR_INVALIDDATA;
goto fail;
}
if (current_track + 1 > fourxm->track_count) {
- fourxm->tracks = av_realloc(fourxm->tracks,
- (current_track + 1) * sizeof(AudioTrack));
+ fourxm->tracks = av_realloc_f(fourxm->tracks,
+ sizeof(AudioTrack),
+ current_track + 1);
if (!fourxm->tracks) {
ret = AVERROR(ENOMEM);
goto fail;
@@ -192,7 +201,12 @@ static int fourxm_read_header(AVFormatContext *s)
|| fourxm->tracks[current_track].sample_rate <= 0
|| fourxm->tracks[current_track].bits < 0){
av_log(s, AV_LOG_ERROR, "audio header invalid\n");
- ret= -1;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ if(!fourxm->tracks[current_track].adpcm && fourxm->tracks[current_track].bits<8){
+ av_log(s, AV_LOG_ERROR, "bits unspecified for non ADPCM\n");
+ ret = AVERROR_INVALIDDATA;
goto fail;
}
i += 8 + size;
@@ -263,7 +277,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) {
diff --git a/libavformat/Makefile b/libavformat/Makefile
index d459bdf..24dd3cd 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -1,3 +1,5 @@
+include $(SUBDIR)../config.mak
+
NAME = avformat
FFLIBS = avcodec avutil
@@ -11,7 +13,6 @@ OBJS = allformats.o \
cutils.o \
id3v1.o \
id3v2.o \
- log2_tab.o \
metadata.o \
mux.o \
options.o \
@@ -45,47 +46,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_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_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
@@ -94,6 +114,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
@@ -103,6 +124,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
@@ -120,13 +142,17 @@ 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
@@ -135,7 +161,10 @@ OBJS-$(CONFIG_H264_DEMUXER) += h264dec.o rawdec.o
OBJS-$(CONFIG_H264_MUXER) += rawenc.o
OBJS-$(CONFIG_HLS_DEMUXER) += hls.o
OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o mpegtsenc.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
@@ -145,14 +174,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
@@ -162,16 +197,19 @@ OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \
isom.o avc.o \
flacenc_header.o avlanguage.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
@@ -189,13 +227,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
@@ -206,6 +248,7 @@ OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \
oggparsedirac.o \
oggparseflac.o \
oggparseogm.o \
+ oggparseopus.o \
oggparseskeleton.o \
oggparsespeex.o \
oggparsetheora.o \
@@ -215,6 +258,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
@@ -255,17 +299,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
@@ -286,8 +335,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
@@ -297,19 +348,25 @@ 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
@@ -319,23 +376,31 @@ OBJS-$(CONFIG_TXD_DEMUXER) += txd.o
OBJS-$(CONFIG_VC1_DEMUXER) += rawdec.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
+OBJS-$(CONFIG_WEBVTT_DEMUXER) += webvttdec.o subtitles.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.o asfdec.o asf.o asfcrypt.o \
avlanguage.o mpegts.o isom.o
+OBJS-$(CONFIG_WTV_MUXER) += wtvenc.o wtv.o asf.o asfenc.o
OBJS-$(CONFIG_WV_DEMUXER) += wv.o apetag.o img2.o
+OBJS-$(CONFIG_WV_MUXER) += wvenc.o apetagenc.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
@@ -343,12 +408,19 @@ OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg.o
OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpeg.o
# external libraries
+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
# 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
@@ -376,10 +448,6 @@ OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o
SKIPHEADERS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh.h
SKIPHEADERS-$(CONFIG_NETWORK) += network.h rtsp.h
-
-EXAMPLES = metadata \
- output \
-
TESTPROGS = noproxy \
seek \
srtp \
@@ -389,5 +457,4 @@ TOOLS = aviocat \
ismindex \
pktdumper \
probetest \
-
-$(SUBDIR)output-example$(EXESUF): ELIBS = $(patsubst %,$(LD_LIB),swscale avutil)
+ 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..9d7c6d7 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
*/
@@ -31,10 +31,10 @@ 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,7 +72,7 @@ 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);
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..78f1d3b
--- /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 cant 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
--- /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 0c91944..60d7b07 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
*/
@@ -158,7 +158,6 @@ static int adts_write_packet(AVFormatContext *s, AVPacket *pkt)
}
}
avio_write(pb, pkt->data, pkt->size);
- avio_flush(pb);
return 0;
}
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..183a8e0
--- /dev/null
+++ b/libavformat/afc.c
@@ -0,0 +1,81 @@
+/*
+ * 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;
+ st->codec->extradata_size = 1;
+
+ st->codec->extradata = av_mallocz(1 + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codec->extradata)
+ 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..b3ef577 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,12 +33,15 @@
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',' ') },
diff --git a/libavformat/aiffdec.c b/libavformat/aiffdec.c
index 6243bcb..62af3dc 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 */
@@ -142,10 +147,8 @@ static unsigned int get_aiff_header(AVFormatContext *s, int size,
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 +159,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 +188,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 +232,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 +264,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");
@@ -264,6 +280,29 @@ static int aiff_read_header(AVFormatContext *s)
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 +344,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 +353,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 6dbf9fd..2b2d46d 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,59 @@ 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);
REGISTER_MUXDEMUX(FILMSTRIP, filmstrip);
@@ -109,16 +125,20 @@ 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_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);
@@ -126,18 +146,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);
@@ -160,19 +186,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);
@@ -193,20 +224,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
av_register_rtp_dynamic_payload_handlers();
@@ -214,49 +252,64 @@ 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_DEMUXER (WEBVTT, webvtt);
REGISTER_DEMUXER (WSAUD, wsaud);
REGISTER_DEMUXER (WSVQA, wsvqa);
- REGISTER_DEMUXER (WTV, wtv);
- REGISTER_DEMUXER (WV, wv);
+ 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);
@@ -283,6 +336,9 @@ void av_register_all(void)
REGISTER_PROTOCOL(UDP, udp);
/* external libraries */
+ REGISTER_DEMUXER (LIBMODPLUG, libmodplug);
+ REGISTER_MUXDEMUX(LIBNUT, libnut);
+ REGISTER_DEMUXER (LIBQUVI, libquvi);
REGISTER_PROTOCOL(LIBRTMP, librtmp);
REGISTER_PROTOCOL(LIBRTMPE, librtmpe);
REGISTER_PROTOCOL(LIBRTMPS, librtmps);
diff --git a/libavformat/amr.c b/libavformat/amr.c
index ba91d7c..7201ac3 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"
@@ -55,7 +56,6 @@ static int amr_write_header(AVFormatContext *s)
static int amr_write_packet(AVFormatContext *s, AVPacket *pkt)
{
avio_write(s->pb, pkt->data, pkt->size);
- avio_flush(s->pb);
return 0;
}
#endif /* CONFIG_AMR_MUXER */
@@ -112,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);
}
@@ -133,7 +133,7 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt)
size = packed_size[mode];
} else {
- assert(0);
+ av_assert0(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..bb28a62 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
*/
@@ -82,6 +82,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 c4ce6ac..e2b8ada 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 && (ape->seektablelength / sizeof(*ape->seektable)) < ape->totalframes) {
av_log(s, AV_LOG_ERROR,
@@ -292,6 +290,9 @@ static int ape_read_header(AVFormatContext * s)
for (i = 0; i < ape->totalframes; i++)
ape->bittable[i] = avio_r8(pb);
}
+ }else{
+ av_log(s, AV_LOG_ERROR, "Missing seektable\n");
+ return AVERROR_INVALIDDATA;
}
ape->frames[0].pos = ape->firstframe;
@@ -340,7 +341,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,8 +354,8 @@ 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;
@@ -366,7 +367,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 +386,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;
diff --git a/libavformat/apetag.c b/libavformat/apetag.c
index 0d2cb97..a445c84 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
*/
@@ -26,8 +26,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_IS_HEADER (1 << 29)
#define APE_TAG_FLAG_IS_BINARY (1 << 1)
@@ -128,7 +126,7 @@ int64_t ff_ape_parse_tag(AVFormatContext *s)
avio_seek(pb, file_size - APE_TAG_FOOTER_BYTES, SEEK_SET);
avio_read(pb, buf, 8); /* APETAGEX */
- if (strncmp(buf, "APETAGEX", 8)) {
+ if (strncmp(buf, APE_TAG_PREAMBLE, 8)) {
return 0;
}
diff --git a/libavformat/apetag.h b/libavformat/apetag.h
index 279972f..0330c89 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
*
@@ -32,4 +36,9 @@
*/
int64_t ff_ape_parse_tag(AVFormatContext *s);
+/**
+ * Write an APEv2 tag
+ */
+void ff_ape_write(AVFormatContext *s);
+
#endif /* AVFORMAT_APETAG_H */
diff --git a/libavformat/apetagenc.c b/libavformat/apetagenc.c
new file mode 100644
index 0000000..42f5836
--- /dev/null
+++ b/libavformat/apetagenc.c
@@ -0,0 +1,65 @@
+/*
+ * APE tag writer
+ * 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/dict.h"
+#include "avio_internal.h"
+#include "avformat.h"
+#include "apetag.h"
+
+static int string_is_ascii(const uint8_t *str)
+{
+ while (*str && *str >= 0x20 && *str <= 0x7e ) str++;
+ return !*str;
+}
+
+void ff_ape_write(AVFormatContext *s)
+{
+ int64_t tag_bytes;
+ AVDictionaryEntry *t = NULL;
+ AVIOContext *pb = s->pb;
+ int tags = 0, vlen;
+
+ tag_bytes = avio_tell(s->pb);
+ while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
+ if (!string_is_ascii(t->key)) {
+ av_log(s, AV_LOG_WARNING, "Non ASCII keys are not allowed\n");
+ continue;
+ }
+
+ vlen = strlen(t->value);
+ avio_wl32(pb, vlen + 1);
+ avio_wl32(pb, 0); // flags
+ avio_put_str(pb, t->key);
+ avio_put_str(pb, t->value);
+ tags++;
+ }
+ tag_bytes = avio_tell(s->pb) - tag_bytes;
+
+ if (!tags)
+ return;
+
+ avio_write(pb, APE_TAG_PREAMBLE, 8);
+ avio_wl32(pb, APE_TAG_VERSION);
+ avio_wl32(pb, tag_bytes + APE_TAG_FOOTER_BYTES);
+ avio_wl32(pb, tags); // item count
+ avio_wl32(pb, 0); // global flags
+ ffio_fill(pb, 0, 8); // reserved
+}
diff --git a/libavformat/aqtitledec.c b/libavformat/aqtitledec.c
new file mode 100644
index 0000000..810f95b
--- /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 52afa09..dd64a3f 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
*/
@@ -155,7 +155,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 6d418e8..5ffc746 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,6 +28,11 @@
#define PACKET_SIZE 3200
+typedef struct ASFPayload {
+ uint8_t type;
+ uint16_t size;
+} ASFPayload;
+
typedef struct ASFStream {
int num;
unsigned char seq;
@@ -47,6 +52,9 @@ typedef struct ASFStream {
int palette_changed;
uint32_t palette[256];
+
+ int payload_ext_ct;
+ ASFPayload payload[8];
} ASFStream;
typedef struct ASFMainHeader {
@@ -175,4 +183,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 a7fdc9e..5aff1c5 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
*/
@@ -95,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) */
@@ -126,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);
@@ -280,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);
@@ -301,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;
@@ -370,13 +370,14 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
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);
@@ -429,7 +430,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)
@@ -466,7 +467,7 @@ 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);
avio_read(pb, st->codec->extradata, st->codec->extradata_size);
@@ -537,8 +538,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);
@@ -547,10 +550,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;
@@ -712,7 +723,7 @@ 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);
@@ -734,7 +745,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)
@@ -763,19 +774,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");
}
}
}
@@ -789,8 +811,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;
@@ -889,20 +911,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
}
@@ -918,12 +940,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);
@@ -943,7 +965,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)
@@ -961,13 +983,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);
@@ -975,26 +1000,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) {
+ int64_t end = avio_tell(pb) + asf->packet_replic_size;
+ AVRational aspect;
asf->packet_obj_size = avio_rl32(pb);
if (asf->packet_obj_size >= (1 << 24) || asf->packet_obj_size <= 0) {
av_log(s, AV_LOG_ERROR, "packet_obj_size invalid\n");
- return -1;
+ asf->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
@@ -1007,18 +1068,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;
@@ -1026,16 +1087,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;
@@ -1057,8 +1114,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 ||
@@ -1346,11 +1402,12 @@ 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;
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;
}
@@ -1385,17 +1442,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);
@@ -1405,6 +1466,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);
@@ -1427,7 +1489,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);
}
@@ -1437,8 +1499,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;
@@ -1455,15 +1515,16 @@ 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);
return 0;
}
diff --git a/libavformat/asfenc.c b/libavformat/asfenc.c
index a523b3a..6daf238 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 "avformat.h"
#include "avio_internal.h"
@@ -31,7 +32,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 \
@@ -192,33 +193,35 @@ 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;
+ 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));
}
@@ -242,7 +245,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;
}
@@ -325,7 +328,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); /* ??? */
@@ -334,7 +337,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));
@@ -350,7 +353,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);
@@ -394,7 +397,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:
@@ -412,11 +415,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);
@@ -463,7 +466,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;
@@ -533,9 +536,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); /* ??? */
@@ -549,10 +552,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, which is data_size - asf->data_offset
@@ -571,6 +572,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;
}
@@ -597,7 +601,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++)
@@ -636,20 +640,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);
@@ -664,7 +667,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;
@@ -687,7 +690,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
@@ -695,7 +698,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;
@@ -757,14 +760,42 @@ static void put_frame(AVFormatContext *s, ASFStream *stream, AVStream *avst,
stream->seq++;
}
+static void update_index(AVFormatContext *s, int start_sec,
+ uint32_t packet_number, uint16_t packet_count)
+{
+ 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;
+ }
+
+ if (start_sec > asf->nb_index_memory_alloc) {
+ asf->nb_index_memory_alloc = (start_sec + ASF_INDEX_BLOCK) & ~(ASF_INDEX_BLOCK - 1);
+ asf->index_ptr = av_realloc( asf->index_ptr, sizeof(ASFIndex) * asf->nb_index_memory_alloc );
+ }
+ 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->maximum_packet = FFMAX(asf->maximum_packet, packet_count);
+ asf->next_packet_number = packet_number;
+ asf->next_packet_count = packet_count;
+ asf->next_start_sec = start_sec;
+}
+
static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
{
ASFContext *asf = s->priv_data;
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;
codec = s->streams[pkt->stream_index]->codec;
@@ -774,35 +805,24 @@ 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) {
- asf->nb_index_memory_alloc += ASF_INDEX_BLOCK;
- asf->index_ptr = (ASFIndex *)av_realloc(asf->index_ptr,
- sizeof(ASFIndex) *
- asf->nb_index_memory_alloc);
- }
- // 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->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;
+ update_index(s, start_sec, packet_number, packet_count);
}
+ asf->end_sec = start_sec;
+
return 0;
}
@@ -812,9 +832,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);
@@ -837,8 +857,10 @@ 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) {
+ update_index(s, asf->end_sec + 1, 0, 0);
+ 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) {
@@ -861,7 +883,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,
@@ -880,7 +902,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 5bf2e20..f2e904a 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,10 +62,31 @@ static int write_header(AVFormatContext *s)
static int write_packet(AVFormatContext *s, AVPacket *pkt)
{
- avio_write(s->pb, pkt->data, pkt->size);
-
- avio_flush(s->pb);
+ 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;
}
@@ -85,5 +111,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
--- /dev/null
+++ b/libavformat/ast.c
@@ -0,0 +1,29 @@
+/*
+ * AST common code
+ * Copyright (c) 2012 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avformat.h"
+#include "internal.h"
+
+const AVCodecTag ff_codec_ast_tags[] = {
+ { AV_CODEC_ID_ADPCM_AFC, 0 },
+ { AV_CODEC_ID_PCM_S16BE_PLANAR, 1 },
+ { AV_CODEC_ID_NONE, 0 },
+};
diff --git a/libavformat/ast.h b/libavformat/ast.h
new file mode 100644
index 0000000..4a399ea
--- /dev/null
+++ b/libavformat/ast.h
@@ -0,0 +1,30 @@
+/*
+ * AST common code
+ * Copyright (c) 2012 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFORMAT_AST_H
+#define AVFORMAT_AST_H
+
+#include "avformat.h"
+#include "internal.h"
+
+extern const AVCodecTag ff_codec_ast_tags[];
+
+#endif /* AVFORMAT_AST_H */
diff --git a/libavformat/astdec.c b/libavformat/astdec.c
new file mode 100644
index 0000000..8862744
--- /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
--- /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..22004d0 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
*/
@@ -32,6 +32,11 @@
#include "avio_internal.h"
#include "pcm.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 },
{ AV_CODEC_ID_PCM_S8, 2 },
@@ -40,6 +45,7 @@ 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_G722,24 },
{ AV_CODEC_ID_PCM_ALAW, 27 },
{ AV_CODEC_ID_NONE, 0 },
};
@@ -59,7 +65,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 +77,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);
@@ -114,7 +125,9 @@ static int au_read_header(AVFormatContext *s)
st->codec->channels = channels;
st->codec->sample_rate = rate;
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 +135,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 +151,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 +182,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 5d224c4..1d7ba45 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,13 @@ typedef struct AVIndexEntry {
#define AV_DISPOSITION_ATTACHED_PIC 0x0400
/**
+ * 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 +688,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;
@@ -701,6 +733,19 @@ typedef struct AVStream {
*/
AVPacket attached_pic;
+ /**
+ * 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;
+
/*****************************************************************
* 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
@@ -712,11 +757,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.
*/
@@ -754,6 +806,16 @@ typedef struct AVStream {
*/
int codec_info_nb_frames;
+ /**
+ * 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;
+
/* av_read_frame() support */
enum AVStreamParseType need_parsing;
struct AVCodecParserContext *parser;
@@ -770,8 +832,60 @@ typedef struct AVStream {
support seeking natively. */
int nb_index_entries;
unsigned int index_entries_allocated_size;
+
+ /**
+ * 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
/**
@@ -787,6 +901,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
@@ -799,6 +930,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.
@@ -877,7 +1019,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;
@@ -894,6 +1036,10 @@ typedef struct AVFormatContext {
#define AVFMT_FLAG_NOBUFFER 0x0040 ///< Do not buffer frames when possible
#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_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.
@@ -991,6 +1137,99 @@ 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;
+
/*****************************************************************
* 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
@@ -1032,6 +1271,7 @@ typedef struct AVFormatContext {
/**
* Offset to remap timestamps to be non-negative.
* Expressed in timebase units.
+ * @see AVStream.mux_ts_offset
*/
int64_t offset;
@@ -1040,8 +1280,22 @@ 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;
} AVFormatContext;
+/**
+ * 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;
@@ -1079,7 +1333,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);
@@ -1151,7 +1404,7 @@ const AVClass *avformat_get_class(void);
*
* @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);
@@ -1160,6 +1413,41 @@ AVProgram *av_new_program(AVFormatContext *s, int id);
*/
+#if FF_API_PKT_DUMP
+attribute_deprecated void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload);
+attribute_deprecated void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt,
+ int dump_payload);
+#endif
+
+#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
* @{
@@ -1192,6 +1480,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
@@ -1231,6 +1528,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
@@ -1255,6 +1575,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.
@@ -1285,6 +1617,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
@@ -1339,6 +1689,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
@@ -1366,6 +1717,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.
@@ -1375,6 +1737,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
@@ -1482,6 +1868,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);
+
+
+/**
* @}
*/
@@ -1563,6 +1968,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);
/**
@@ -1697,11 +2114,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 cf24e8c..b80effc 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -2,37 +2,36 @@
* 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/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/bswap.h"
+#include "libavutil/opt.h"
#include "libavutil/dict.h"
#include "libavutil/avstring.h"
+#include "libavutil/avassert.h"
#include "avformat.h"
#include "internal.h"
#include "avi.h"
#include "dv.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) */
@@ -54,12 +53,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;
@@ -68,9 +71,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' },
@@ -143,7 +163,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 chunk_id:%X base:%16"PRIX64"\n",
longs_pre_entry,index_type, entries_in_use, chunk_id, base);
@@ -178,9 +198,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)
@@ -197,7 +218,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);
@@ -207,16 +228,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;
}
@@ -339,6 +365,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;
@@ -346,8 +373,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 */
@@ -355,7 +384,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);
@@ -373,7 +402,7 @@ static int avi_read_header(AVFormatContext *s)
if (tag1 == MKTAG('m', 'o', 'v', 'i')) {
avi->movi_list = avio_tell(pb) - 4;
if(size) avi->movi_end = avi->movi_list + size + (size & 1);
- else avi->movi_end = avio_size(pb);
+ else avi->movi_end = avi->fsize;
av_dlog(NULL, "movi end=%"PRIx64"\n", avi->movi_end);
goto end_of_header;
}
@@ -401,7 +430,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;
@@ -457,6 +486,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) {
@@ -485,7 +517,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 */
@@ -512,6 +544,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",
@@ -533,20 +569,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];
@@ -560,7 +603,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')) {
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
@@ -569,8 +612,9 @@ static int avi_read_header(AVFormatContext *s)
break;
}
- if(size > 10*4 && size<(1<<30)){
- st->codec->extradata_size= size - 10*4;
+ 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;
st->codec->extradata= av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
if (!st->codec->extradata) {
st->codec->extradata_size= 0;
@@ -584,19 +628,15 @@ 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. */
+ /* This is true for all paletted codecs implemented in FFmpeg. */
if (st->codec->extradata_size && (st->codec->bits_per_coded_sample <= 8)) {
int pal_size = (1 << st->codec->bits_per_coded_sample) << 2;
const uint8_t *pal_src;
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;
}
@@ -606,15 +646,10 @@ static int avi_read_header(AVFormatContext *s)
st->codec->codec_tag = tag1;
st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag1);
st->need_parsing = AVSTREAM_PARSE_HEADERS; // This is needed to get the pict type which is necessary for generating correct pts.
- // 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){
st->codec->extradata_size+= 9;
- st->codec->extradata= av_realloc(st->codec->extradata, st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ st->codec->extradata= av_realloc_f(st->codec->extradata, 1, st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
if(st->codec->extradata)
memcpy(st->codec->extradata + st->codec->extradata_size - 9, "BottomUp", 9);
}
@@ -646,15 +681,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;
@@ -665,11 +712,35 @@ static int avi_read_header(AVFormatContext *s)
}
}
break;
+ case MKTAG('s', 't', 'r', 'd'):
+ if (stream_index >= (unsigned)s->nb_streams
+ || s->streams[stream_index]->codec->extradata_size
+ || s->streams[stream_index]->codec->codec_tag == MKTAG('H','2','6','4')) {
+ avio_skip(pb, size);
+ } else {
+ uint64_t cur_pos = avio_tell(pb);
+ if (cur_pos < list_end)
+ size = FFMIN(size, list_end - cur_pos);
+ st = s->streams[stream_index];
+
+ if(size<(1<<30)){
+ st->codec->extradata_size= size;
+ 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_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) &&
- read_braindead_odml_indx(s, 0) < 0 &&
- (s->error_recognition & AV_EF_EXPLODE))
+ 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;
avio_seek(pb, i+size, SEEK_SET);
break;
@@ -714,7 +785,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 */
@@ -732,13 +803,27 @@ static int avi_read_header(AVFormatContext *s)
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");
avi->non_interleaved=0;
@@ -756,7 +841,7 @@ static int avi_read_header(AVFormatContext *s)
}
static int read_gab2_sub(AVStream *st, AVPacket *pkt) {
- if (!strcmp(pkt->data, "GAB2") && AV_RL16(pkt->data+5) == 2) {
+ if (pkt->data && !strcmp(pkt->data, "GAB2") && AV_RL16(pkt->data+5) == 2) {
uint8_t desc[256];
int score = AVPROBE_SCORE_EXTENSION, ret;
AVIStream *ast = st->priv_data;
@@ -845,6 +930,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;
@@ -856,7 +945,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++)
@@ -868,7 +957,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##
@@ -904,6 +993,11 @@ 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;
@@ -940,7 +1034,7 @@ start_sync:
avio_rl16(pb); //flags
for (; k <= last; k++)
- ast->pal[k] = avio_rb32(pb)>>8;// b + (g << 8) + (r << 16);
+ ast->pal[k] = 0xFFU<<24 | avio_rb32(pb)>>8;// b + (g << 8) + (r << 16);
ast->has_pal= 1;
goto start_sync;
} else if( ((ast->prefix_count<5 || sync+9 > i) && d[2]<128 && d[3]<128) ||
@@ -972,6 +1066,8 @@ start_sync:
}
}
+ if(pb->error)
+ return pb->error;
return AVERROR_EOF;
}
@@ -1024,7 +1120,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, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
else{
@@ -1036,15 +1132,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:
@@ -1070,8 +1169,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, AVPALETTE_SIZE);
if(!pal){
@@ -1088,7 +1188,7 @@ resync:
dstr = pkt->destruct;
#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
pkt->destruct = dstr;
#endif
@@ -1116,12 +1216,29 @@ resync:
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 == 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;
}
@@ -1136,6 +1253,22 @@ resync:
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;
}
@@ -1155,7 +1288,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)
@@ -1169,8 +1304,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);
@@ -1193,15 +1336,24 @@ 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;
}
@@ -1211,6 +1363,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];
@@ -1234,7 +1388,32 @@ 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_mallocz(sizeof(*idx) * s->nb_streams);
+ 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];
+ 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, 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, 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)
@@ -1243,16 +1422,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,
@@ -1262,12 +1444,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
}
the_end:
@@ -1290,21 +1477,27 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
AVIContext *avi = s->priv_data;
AVStream *st;
int i, index;
- int64_t pos;
+ int64_t pos, pos_min;
AVIStream *ast;
if (!avi->index_loaded) {
/* we only load the index on demand */
avi_load_index(s);
- avi->index_loaded = 1;
+ avi->index_loaded |= 1;
}
- assert(stream_index>= 0);
+ 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;
@@ -1317,17 +1510,20 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
/* One and only one real stream for DV in AVI, and it has video */
/* offsets. Calling with other stream indexes should have failed */
/* the av_index_search_timestamp call above. */
- assert(stream_index == 0);
+ av_assert0(stream_index == 0);
+
+ 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;
@@ -1343,31 +1539,42 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
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;
}
@@ -1416,4 +1623,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 9d1f510..f2fa9dc 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){
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++;
@@ -537,12 +566,12 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE;
int id = idx->entry % AVI_INDEX_CLUSTER_SIZE;
if (idx->ents_allocated <= idx->entry) {
- idx->cluster = av_realloc(idx->cluster, (cl+1)*sizeof(void*));
+ idx->cluster = av_realloc_f(idx->cluster, sizeof(void*), cl+1);
if (!idx->cluster)
- return -1;
+ 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;
}
@@ -558,7 +587,6 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
if (size & 1)
avio_w8(pb, 0);
- avio_flush(pb);
return 0;
}
diff --git a/libavformat/avio.c b/libavformat/avio.c
index a43b241..f6af0cb 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
*/
@@ -119,6 +119,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);
@@ -134,8 +144,33 @@ static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up,
if (up->priv_data_size) {
uc->priv_data = av_mallocz(up->priv_data_size);
if (up->priv_data_class) {
+ int proto_len= strlen(up->name);
+ char *start = strchr(uc->filename, ',');
*(const AVClass**)uc->priv_data = up->priv_data_class;
av_opt_set_defaults(uc->priv_data);
+ if(!strncmp(up->name, uc->filename, proto_len) && uc->filename + proto_len == start){
+ int ret= 0;
+ char *p= start;
+ char sep= *++p;
+ char *key, *val;
+ p++;
+ while(ret >= 0 && (key= strchr(p, sep)) && p<key && (val = strchr(key+1, sep))){
+ *val= *key= 0;
+ ret= av_opt_set(uc->priv_data, p, key+1, 0);
+ if (ret == AVERROR_OPTION_NOT_FOUND)
+ av_log(uc, AV_LOG_ERROR, "Key '%s' not found.\n", p);
+ *val= *key= sep;
+ p= val+1;
+ }
+ if(ret<0 || p!=key){
+ av_log(uc, AV_LOG_ERROR, "Error parsing options string %s\n", start);
+ av_freep(&uc->priv_data);
+ av_freep(&uc);
+ err = AVERROR(EINVAL);
+ goto fail;
+ }
+ memmove(start, key+1, strlen(key));
+ }
}
}
if (int_cb)
@@ -180,11 +215,20 @@ 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';
@@ -197,7 +241,7 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags,
return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
}
*puc = NULL;
- return AVERROR(ENOENT);
+ return AVERROR_PROTOCOL_NOT_FOUND;
}
int ffurl_open(URLContext **puc, const char *filename, int flags,
@@ -223,6 +267,7 @@ static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int
{
int ret, len;
int fast_retries = 5;
+ int64_t wait_since = 0;
len = 0;
while (len < size_min) {
@@ -233,16 +278,23 @@ static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int
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 : len;
if (ret)
fast_retries = FFMAX(fast_retries, 2);
len += ret;
- if (ff_check_interrupt(&h->interrupt_callback))
+ if (len < size && ff_check_interrupt(&h->interrupt_callback))
return AVERROR_EXIT;
}
return len;
@@ -270,7 +322,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)
@@ -283,8 +335,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 */
@@ -297,12 +350,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;
@@ -349,7 +408,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..5bdbc62 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
@@ -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 3da2fc8..cf36764 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
*/
@@ -64,13 +64,15 @@ static av_always_inline void ffio_wfourcc(AVIOContext *pb, const uint8_t *s)
* @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);
+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);
diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
index d2eaf36..966e0e6 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,26 +366,26 @@ 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 */
@@ -384,7 +415,7 @@ static void fill_buffer(AVIOContext *s)
}
/* make buffer smaller in case it ended up large after probing */
- if (s->buffer_size > max_buffer_size) {
+ if (s->read_packet && s->buffer_size > max_buffer_size) {
ffio_set_buf_size(s, max_buffer_size);
s->checksum_ptr = dst = s->buffer;
@@ -405,6 +436,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 +485,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 +497,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 +517,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;
}
@@ -521,8 +554,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;
}
@@ -674,11 +707,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) {
@@ -706,7 +740,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;
@@ -718,27 +752,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) {
@@ -789,6 +828,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);
}
@@ -867,7 +910,7 @@ static int dyn_buf_write(void *opaque, uint8_t *buf, int buf_size)
}
if (new_allocated_size > d->allocated_size) {
- d->buffer = av_realloc(d->buffer, new_allocated_size);
+ d->buffer = av_realloc_f(d->buffer, 1, new_allocated_size);
if(d->buffer == NULL)
return AVERROR(ENOMEM);
d->allocated_size = new_allocated_size;
diff --git a/libavformat/avisynth.c b/libavformat/avisynth.c
index 43b3da5..a5a4fcc 100644
--- a/libavformat/avisynth.c
+++ b/libavformat/avisynth.c
@@ -1,224 +1,636 @@
/*
- * 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 "avformat.h"
#include "internal.h"
-#include "riff.h"
-
-#include <windows.h>
-#include <vfw.h>
+#include "libavcodec/internal.h"
+
+// Enable function pointer definitions for runtime loading.
+#define AVSC_NO_DECLSPEC
+
+// Shut up ffmpeg error messages.
+// avisynth_c.h contains inline functions that call these functions.
+#undef malloc
+#undef free
+#undef printf
+
+// Platform-specific directives for AviSynth vs AvxSynth.
+#ifdef _WIN32
+ #include <windows.h>
+ #undef EXTERN_C
+ #include "compat/avisynth/avisynth_c.h"
+ #define AVISYNTH_LIB "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
+
+// AvxSynth doesn't have these colorspaces, so disable them
+#ifndef _WIN32
+#define avs_is_yv24(vi) 0
+#define avs_is_yv16(vi) 0
+#define avs_is_yv411(vi) 0
+#define avs_is_y8(vi) 0
+#endif
typedef struct {
- PAVISTREAM handle;
- AVISTREAMINFO info;
- DWORD read;
- LONG chunck_size;
- LONG chunck_samples;
-} AVISynthStream;
+ void *library;
+#define AVSC_DECLARE_FUNC(name) name##_func name
+ AVSC_DECLARE_FUNC(avs_create_script_environment);
+ AVSC_DECLARE_FUNC(avs_delete_script_environment);
+ AVSC_DECLARE_FUNC(avs_get_error);
+ AVSC_DECLARE_FUNC(avs_clip_get_error);
+ AVSC_DECLARE_FUNC(avs_invoke);
+ AVSC_DECLARE_FUNC(avs_release_value);
+ AVSC_DECLARE_FUNC(avs_get_video_info);
+ AVSC_DECLARE_FUNC(avs_take_clip);
+ AVSC_DECLARE_FUNC(avs_release_clip);
+ AVSC_DECLARE_FUNC(avs_bit_blt);
+ AVSC_DECLARE_FUNC(avs_get_audio);
+ AVSC_DECLARE_FUNC(avs_get_frame);
+ AVSC_DECLARE_FUNC(avs_release_video_frame);
+#undef AVSC_DECLARE_FUNC
+} AviSynthLibrary;
+
+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;
+};
+typedef struct AviSynthContext AviSynthContext;
-typedef struct {
- PAVIFILE file;
- AVISynthStream *streams;
- int nb_streams;
- int next_stream;
-} AVISynthContext;
-
-static int avisynth_read_header(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 can't accept UTF-8 filename */
- 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)
- {
- if (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;
- }
+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_create_script_environment, 0);
+ LOAD_AVS_FUNC(avs_delete_script_environment, 0);
+ LOAD_AVS_FUNC(avs_get_error, 1); // New to AviSynth 2.6
+ LOAD_AVS_FUNC(avs_clip_get_error, 0);
+ LOAD_AVS_FUNC(avs_invoke, 0);
+ LOAD_AVS_FUNC(avs_release_value, 0);
+ LOAD_AVS_FUNC(avs_get_video_info, 0);
+ LOAD_AVS_FUNC(avs_take_clip, 0);
+ LOAD_AVS_FUNC(avs_release_clip, 0);
+ LOAD_AVS_FUNC(avs_bit_blt, 0);
+ LOAD_AVS_FUNC(avs_get_audio, 0);
+ LOAD_AVS_FUNC(avs_get_frame, 0);
+ LOAD_AVS_FUNC(avs_release_video_frame, 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 = (AviSynthContext *)s->priv_data;
+ 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;
}
}
- return 0;
+ if (!avs_ctx_list) {
+ avs_ctx_list = avs;
+ } else {
+ avs->next = avs_ctx_list;
+ avs_ctx_list = avs;
+ }
+
+ return 0;
+}
+
+static av_cold void avisynth_context_destroy(AviSynthContext *avs) {
+ if (avs_atexit_called)
+ return;
+
+ if (avs == avs_ctx_list) {
+ avs_ctx_list = avs->next;
+ } else {
+ AviSynthContext *prev = avs_ctx_list;
+ while (prev->next != avs)
+ prev = prev->next;
+ prev->next = avs->next;
+ }
+
+ if (avs->clip) {
+ avs_library->avs_release_clip(avs->clip);
+ avs->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;
+ int planar = 0; // 0: packed, 1: YUV, 2: Y8
+
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = 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 _WIN32
+ case AVS_CS_YV24:
+ st->codec->pix_fmt = PIX_FMT_YUV444P;
+ planar = 1;
+ break;
+ case AVS_CS_YV16:
+ st->codec->pix_fmt = PIX_FMT_YUV422P;
+ planar = 1;
+ break;
+ case AVS_CS_YV411:
+ st->codec->pix_fmt = PIX_FMT_YUV411P;
+ planar = 1;
+ break;
+ case AVS_CS_Y8:
+ st->codec->pix_fmt = PIX_FMT_GRAY8;
+ planar = 2;
+ break;
+#endif
+ case AVS_CS_BGR24:
+ st->codec->pix_fmt = PIX_FMT_BGR24;
+ break;
+ case AVS_CS_BGR32:
+ st->codec->pix_fmt = PIX_FMT_RGB32;
+ break;
+ case AVS_CS_YUY2:
+ st->codec->pix_fmt = PIX_FMT_YUYV422;
+ break;
+ case AVS_CS_YV12:
+ st->codec->pix_fmt = PIX_FMT_YUV420P;
+ planar = 1;
+ break;
+ case AVS_CS_I420: // Is this even used anywhere?
+ st->codec->pix_fmt = 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;
+ }
+
+ 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;
+}
+
+static int avisynth_create_stream_audio(AVFormatContext *s, AVStream *st) {
+ AviSynthContext *avs = s->priv_data;
+
+ 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 = CODEC_ID_PCM_U8;
+ break;
+ case AVS_SAMPLE_INT16:
+ st->codec->codec_id = CODEC_ID_PCM_S16LE;
+ break;
+ case AVS_SAMPLE_INT24:
+ st->codec->codec_id = CODEC_ID_PCM_S24LE;
+ break;
+ case AVS_SAMPLE_INT32:
+ st->codec->codec_id = CODEC_ID_PCM_S32LE;
+ break;
+ case AVS_SAMPLE_FLOAT:
+ st->codec->codec_id = 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;
+}
+
+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;
}
-static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt)
-{
- AVISynthContext *avs = s->priv_data;
- HRESULT res;
- AVISynthStream *stream;
- int stream_id = avs->next_stream;
- LONG read_size;
+static int avisynth_open_file(AVFormatContext *s) {
+ AviSynthContext *avs = (AviSynthContext *)s->priv_data;
+ AVS_Value arg, val;
+ int ret;
+
+ if (ret = avisynth_context_create(s))
+ return ret;
+
+ arg = avs_new_value_string(s->filename);
+ 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, "%s\n", "AviSynth script did not return a clip");
+ 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);
+
+ // Release the AVS_Value as it will go out of scope.
+ avs_library->avs_release_value(val);
+
+ if (ret = avisynth_create_stream(s))
+ goto fail;
- // handle interleaving manually...
- stream = &avs->streams[stream_id];
+ return 0;
+
+fail:
+ avisynth_context_destroy(avs);
+ return ret;
+}
+
+static void avisynth_next_stream(AVFormatContext *s, AVStream **st, AVPacket *pkt, int *discard) {
+ AviSynthContext *avs = s->priv_data;
+
+ 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;
+
+ // Define the bpp values for the new AviSynth 2.6 colorspaces
+ 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 {
+ bits = avs_bits_per_pixel(avs->vi);
+ }
- if (stream->read >= stream->info.dwLength)
- return AVERROR(EIO);
+ // Without 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_UNKNOWN;
+
+ 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;
+ }
- 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;
+ 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);
+ rowsize = avs_get_row_size_p(frame, plane);
+ planeheight = avs_get_height_p(frame, plane);
+ pitch = avs_get_pitch_p(frame, plane);
+
+ // Flip RGB video.
+ if (avs_is_rgb24(avs->vi) || avs_is_rgb(avs->vi)) {
+ src_p = src_p + (planeheight - 1) * pitch;
+ pitch = -pitch;
+ }
- res = AVIStreamRead(stream->handle, stream->read, stream->chunck_samples, pkt->data, stream->chunck_size, &read_size, NULL);
+ avs_library->avs_bit_blt(avs->env, dst_p, rowsize, src_p, pitch, rowsize, planeheight);
+ dst_p += rowsize * planeheight;
+ }
- pkt->pts = stream->read;
- pkt->size = read_size;
+ avs_library->avs_release_video_frame(frame);
+ return 0;
+}
- stream->read += stream->chunck_samples;
+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;
+ }
- // 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);
+ // After seeking, audio may catch up with video.
+ if (samples <= 0) {
+ pkt->size = 0;
+ pkt->data = NULL;
+ return 0;
+ }
- return (res == S_OK) ? pkt->size : -1;
+ 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_UNKNOWN;
+
+ 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 int avisynth_read_close(AVFormatContext *s)
-{
- AVISynthContext *avs = s->priv_data;
- int i;
+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;
- for (i=0;i<avs->nb_streams;i++)
- {
- AVIStreamRelease(avs->streams[i].handle);
+ if (ret = avisynth_open_file(s)) {
+ avpriv_unlock_avformat();
+ return ret;
}
- av_free(avs->streams);
- AVIFileRelease(avs->file);
- AVIFileExit();
- return 0;
+ avpriv_unlock_avformat();
+ return 0;
}
-static int avisynth_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags)
-{
- AVISynthContext *avs = s->priv_data;
- int stream_id;
+static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) {
+ AviSynthContext *avs = s->priv_data;
+ AVStream *st;
+ int discard = 0;
+ int ret;
+
+ if (avs->error)
+ return AVERROR_UNKNOWN;
+
+ pkt->destruct = av_destruct_packet;
- for (stream_id = 0; stream_id < avs->nb_streams; stream_id++)
- {
- avs->streams[stream_id].read = pts * avs->streams[stream_id].chunck_samples;
+ // 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);
+ }
+ return ret;
+ } 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);
+ }
+ 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;
+ return 0;
}
AVInputFormat ff_avisynth_demuxer = {
.name = "avisynth",
- .long_name = NULL_IF_CONFIG_SMALL("AVISynth"),
- .priv_data_size = sizeof(AVISynthContext),
+ .long_name = NULL_IF_CONFIG_SMALL("AviSynth script"),
+ .priv_data_size = sizeof(AviSynthContext),
.read_header = avisynth_read_header,
.read_packet = avisynth_read_packet,
.read_close = avisynth_read_close,
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..e03f1a4
--- /dev/null
+++ b/libavformat/avr.c
@@ -0,0 +1,100 @@
+/*
+ * 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);
+
+ if (!sign && bps == 8) {
+ st->codec->codec_id = AV_CODEC_ID_PCM_U8;
+ } else if (!sign && bps == 16) {
+ st->codec->codec_id = AV_CODEC_ID_PCM_U16BE;
+ } else if (sign == 0xFFFFu && bps == 8) {
+ st->codec->codec_id = AV_CODEC_ID_PCM_S8;
+ } else if (sign == 0xFFFFu && bps == 16) {
+ st->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
+ } else {
+ avpriv_request_sample(s, "bits per sample %d", bps);
+ 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 e60bbf4..a28e09a 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
*/
@@ -92,6 +92,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 +114,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);
}
@@ -150,7 +152,7 @@ static int bfi_read_packet(AVFormatContext * s, AVPacket * pkt)
return ret;
pkt->pts = bfi->video_frame;
- bfi->video_frame += ret / bfi->video_size;
+ bfi->video_frame += bfi->video_size ? ret / bfi->video_size : 1;
/* One less frame to read. A cursory decrement. */
bfi->nframes--;
diff --git a/libavformat/bink.c b/libavformat/bink.c
index f093e7c..887f70a 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
*/
@@ -202,7 +202,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..c1c6c00
--- /dev/null
+++ b/libavformat/bintext.c
@@ -0,0 +1,395 @@
+/*
+ * 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 = FFMAX(av_q2d(st->time_base) * bin->chars_per_frame, 1);
+
+ 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;
+
+ st->codec->extradata_size = 2;
+ st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codec->extradata)
+ 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;
+
+ st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codec->extradata)
+ 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;
+
+ st->codec->extradata_size = 2 + 48 + 4096;
+ st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codec->extradata)
+ 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;
+
+ st->codec->extradata_size = 2 + 48 + 4096;
+ st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codec->extradata)
+ 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
--- /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
--- /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/boadec.c b/libavformat/boadec.c
new file mode 100644
index 0000000..45f6b39
--- /dev/null
+++ b/libavformat/boadec.c
@@ -0,0 +1,78 @@
+/*
+ * Black ops audio demuxer
+ * Copyright (c) 2013 Michael Niedermayer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+
+static int probe(AVProbeData *p)
+{
+ if (p->buf_size < 2096)
+ return 0;
+ if ( AV_RL32(p->buf ) != 1
+ || AV_RL32(p->buf + 8) > 100000
+ || AV_RL32(p->buf + 12) > 8
+ || AV_RL32(p->buf + 16) != 2096
+ ||!AV_RL32(p->buf + 21)
+ || AV_RL16(p->buf + 25) != 2096
+ || AV_RL32(p->buf + 48) % AV_RL32(p->buf + 21)
+ )
+ return 0;
+ return AVPROBE_SCORE_EXTENSION;
+}
+
+
+static int read_header(AVFormatContext *s)
+{
+ AVStream *st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_ADPCM_MS;
+
+ avio_rl32(s->pb);
+ avio_rl32(s->pb);
+ st->codec->sample_rate = avio_rl32(s->pb);
+ st->codec->channels = avio_rl32(s->pb);
+ s->data_offset = avio_rl32(s->pb);
+ avio_r8(s->pb);
+ st->codec->block_align = st->codec->channels * avio_rl32(s->pb);
+
+ avio_seek(s->pb, s->data_offset, SEEK_SET);
+
+ return 0;
+}
+
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVStream *st = s->streams[0];
+
+ return av_get_packet(s->pb, pkt, st->codec->block_align);
+}
+
+AVInputFormat ff_boa_demuxer = {
+ .name = "boa",
+ .long_name = NULL_IF_CONFIG_SMALL("Black Ops Audio"),
+ .read_probe = probe,
+ .read_header = read_header,
+ .read_packet = read_packet,
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/brstm.c b/libavformat/brstm.c
new file mode 100644
index 0000000..7781b3c
--- /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
--- /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..337758e 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);
@@ -211,7 +211,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 +224,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 +244,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 +253,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 +290,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 +312,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 +341,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 +400,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..11bb055
--- /dev/null
+++ b/libavformat/cafenc.c
@@ -0,0 +1,279 @@
+/*
+ * 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_ALAC:
+ case AV_CODEC_ID_QDM2:
+ 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 24c50c1..f97354c 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
*/
diff --git a/libavformat/concatdec.c b/libavformat/concatdec.c
new file mode 100644
index 0000000..79fb394
--- /dev/null
+++ b/libavformat/concatdec.c
@@ -0,0 +1,407 @@
+/*
+ * 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"
+
+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..5d518be 100644
--- a/libavformat/crypto.c
+++ b/libavformat/crypto.c
@@ -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
--- /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 3ceb958..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
@@ -68,7 +68,6 @@ static int daud_write_packet(struct AVFormatContext *s, AVPacket *pkt)
avio_wb16(s->pb, pkt->size);
avio_wb16(s->pb, 0x8010); // unknown
avio_write(s->pb, pkt->data, pkt->size);
- avio_flush(s->pb);
return 0;
}
@@ -78,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..5799d98 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;
+ st->codec->extradata = av_malloc(2);
+ st->codec->extradata_size = 2;
+ 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 ecc8c0b..b8ca57c 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)
@@ -181,6 +182,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..cdbfc0c 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
*/
diff --git a/libavformat/dtshddec.c b/libavformat/dtshddec.c
new file mode 100644
index 0000000..55c4ca6
--- /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 1730972..a04735a 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[4],
* 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[4],
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;
@@ -269,11 +280,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);
@@ -288,6 +294,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
*/
@@ -333,7 +355,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[4] = {0};
@@ -348,6 +370,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;
ppcm[i] = c->audio_buf[i];
@@ -372,6 +395,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;
@@ -402,9 +426,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;
}
@@ -418,6 +446,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;
@@ -429,7 +489,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;
}
@@ -444,7 +504,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);
@@ -457,6 +517,9 @@ static int dv_read_header(AVFormatContext *s)
s->bit_rate = av_rescale_q(c->dv_demux->sys->frame_size, (AVRational){8,1},
c->dv_demux->sys->time_base);
+ if (s->pb->seekable)
+ dv_read_timecode(s);
+
return 0;
}
@@ -469,13 +532,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 a991cc6..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)
@@ -388,7 +390,6 @@ static int dv_write_packet(struct AVFormatContext *s, AVPacket *pkt)
pkt->data, pkt->size, &frame);
if (fsize > 0) {
avio_write(s->pb, frame, fsize);
- avio_flush(s->pb);
}
return 0;
}
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 8f595df..dae40b1 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;
@@ -109,7 +110,7 @@ static int process_audio_header_elements(AVFormatContext *s)
ea->sample_rate = -1;
ea->num_channels = 1;
- while (!pb->eof_reached && inHeader) {
+ while (!url_feof(pb) && inHeader) {
int inSubheader;
uint8_t byte;
byte = avio_r8(pb);
@@ -118,7 +119,7 @@ static int process_audio_header_elements(AVFormatContext *s)
case 0xFD:
av_log (s, AV_LOG_DEBUG, "entered audio subheader\n");
inSubheader = 1;
- while (!pb->eof_reached && inSubheader) {
+ while (!url_feof(pb) && inSubheader) {
uint8_t subbyte;
subbyte = avio_r8(pb);
@@ -183,22 +184,31 @@ static int process_audio_header_elements(AVFormatContext *s)
case 3: ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R3; break;
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) {
case 8: ea->audio_codec = AV_CODEC_ID_PCM_S16LE_PLANAR; break;
- case 10: ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R2; break;
+ case 10:
+ 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; break;
case -1: 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;
}
@@ -234,7 +244,7 @@ static int process_audio_header_eacs(AVFormatContext *s)
case 1: ea->audio_codec = AV_CODEC_ID_PCM_MULAW; ea->bytes = 1; break;
case 2: 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);
}
return 1;
@@ -274,9 +284,15 @@ 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;
@@ -320,7 +336,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;
}
err = process_audio_header_eacs(s);
@@ -332,7 +348,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);
@@ -348,7 +364,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 :
@@ -417,7 +432,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) {
@@ -428,11 +443,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) {
@@ -480,11 +501,12 @@ static int ea_read_packet(AVFormatContext *s,
AVIOContext *pb = s->pb;
int ret = 0;
int packet_read = 0;
+ int partial_packet = 0;
unsigned int chunk_type, chunk_size;
int 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)
@@ -512,6 +534,11 @@ static int ea_read_packet(AVFormatContext *s,
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;
@@ -522,10 +549,12 @@ static int ea_read_packet(AVFormatContext *s,
case AV_CODEC_ID_ADPCM_EA_R1:
case AV_CODEC_ID_ADPCM_EA_R2:
case AV_CODEC_ID_ADPCM_IMA_EA_EACS:
- pkt->duration = AV_RL32(pkt->data);
+ if (pkt->size >= 4)
+ pkt->duration = AV_RL32(pkt->data);
break;
case AV_CODEC_ID_ADPCM_EA_R3:
- pkt->duration = AV_RB32(pkt->data);
+ if (pkt->size >= 4)
+ pkt->duration = AV_RB32(pkt->data);
break;
case AV_CODEC_ID_ADPCM_IMA_EA_SEAD:
pkt->duration = ret * 2 / ea->num_channels;
@@ -576,9 +605,15 @@ static int ea_read_packet(AVFormatContext *s,
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;
@@ -590,6 +625,8 @@ get_video_packet:
}
}
+ if (ret < 0 && partial_packet)
+ av_free_packet(pkt);
return ret;
}
diff --git a/libavformat/epafdec.c b/libavformat/epafdec.c
new file mode 100644
index 0000000..c737892
--- /dev/null
+++ b/libavformat/epafdec.c
@@ -0,0 +1,104 @@
+/*
+ * Ensoniq Paris Audio File demuxer
+ * Copyright (c) 2012 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+#include "pcm.h"
+
+static int epaf_probe(AVProbeData *p)
+{
+ if (((AV_RL32(p->buf) == MKTAG('f','a','p',' ') &&
+ AV_RL32(p->buf + 8) == 1) ||
+ (AV_RL32(p->buf) == MKTAG(' ','p','a','f') &&
+ AV_RN32(p->buf + 8) == 0)) &&
+ !AV_RN32(p->buf + 4) && AV_RN32(p->buf + 12) &&
+ AV_RN32(p->buf + 20))
+ return AVPROBE_SCORE_MAX / 4 * 3;
+ return 0;
+}
+
+static int epaf_read_header(AVFormatContext *s)
+{
+ int le, sample_rate, codec, channels;
+ AVStream *st;
+
+ avio_skip(s->pb, 4);
+ if (avio_rl32(s->pb))
+ return AVERROR_INVALIDDATA;
+
+ le = avio_rl32(s->pb);
+ if (le && le != 1)
+ return AVERROR_INVALIDDATA;
+
+ if (le) {
+ sample_rate = avio_rl32(s->pb);
+ codec = avio_rl32(s->pb);
+ channels = avio_rl32(s->pb);
+ } else {
+ sample_rate = avio_rb32(s->pb);
+ codec = avio_rb32(s->pb);
+ channels = avio_rb32(s->pb);
+ }
+
+ if (!channels || !sample_rate)
+ return AVERROR_INVALIDDATA;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->channels = channels;
+ st->codec->sample_rate = sample_rate;
+ switch (codec) {
+ case 0:
+ st->codec->codec_id = le ? AV_CODEC_ID_PCM_S16LE : AV_CODEC_ID_PCM_S16BE;
+ break;
+ case 2:
+ st->codec->codec_id = AV_CODEC_ID_PCM_S8;
+ break;
+ case 1:
+ avpriv_request_sample(s, "24-bit Paris PCM format");
+ default:
+ return AVERROR_INVALIDDATA;
+ }
+
+ st->codec->bits_per_coded_sample = av_get_bits_per_sample(st->codec->codec_id);
+ st->codec->block_align = st->codec->bits_per_coded_sample * st->codec->channels / 8;
+
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+
+ if (avio_skip(s->pb, 2024) < 0)
+ return AVERROR_INVALIDDATA;
+ return 0;
+}
+
+AVInputFormat ff_epaf_demuxer = {
+ .name = "epaf",
+ .long_name = NULL_IF_CONFIG_SMALL("Ensoniq Paris Audio File"),
+ .read_probe = epaf_probe,
+ .read_header = epaf_read_header,
+ .read_packet = ff_pcm_read_packet,
+ .read_seek = ff_pcm_read_seek,
+ .extensions = "paf,fap",
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/ffm.h b/libavformat/ffm.h
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..02cf790 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,140 @@ 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) {
+ codec->extradata_size = avio_rb32(pb);
+ codec->extradata = av_malloc(codec->extradata_size);
+ if (!codec->extradata)
+ 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 +374,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 +385,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;
@@ -380,7 +522,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 +566,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 +622,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..4bdc98a 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,7 +128,7 @@ 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))) {
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 c552a9e..e09a64b 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
*/
@@ -34,6 +34,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 */
@@ -58,13 +66,15 @@ static const AVClass file_class = {
static int file_read(URLContext *h, unsigned char *buf, int size)
{
FileContext *c = h->priv_data;
- return read(c->fd, buf, size);
+ int 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 = write(c->fd, buf, size);
+ return (-1 == r)?AVERROR(errno):r;
}
static int file_get_handle(URLContext *h)
@@ -75,6 +85,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)
@@ -82,7 +103,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;
}
@@ -93,6 +114,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);
@@ -114,6 +136,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;
}
@@ -125,9 +150,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);
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/flacdec.c b/libavformat/flacdec.c
index 9737095..7caa7a7 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
*/
@@ -28,6 +28,8 @@
#include "vorbiscomment.h"
#include "libavcodec/bytestream.h"
+#define RETURN_ERROR(code) do { ret = (code); goto fail; } while (0)
+
static int parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
{
const CodecMime *mime = ff_id3v2_mime_tags;
@@ -48,8 +50,7 @@ static int 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;
}
@@ -85,8 +86,7 @@ static int 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) {
@@ -112,8 +112,7 @@ static int 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");
@@ -124,8 +123,7 @@ static int 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);
@@ -166,7 +164,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 */
@@ -176,7 +174,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);
@@ -191,8 +189,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 */
@@ -206,12 +203,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;
@@ -233,24 +228,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 = parse_picture(s, buffer, metadata_size);
av_freep(&buffer);
@@ -261,8 +257,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) {
@@ -275,6 +270,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 b770623..8c1a1bb 100644
--- a/libavformat/flacenc.c
+++ b/libavformat/flacenc.c
@@ -2,20 +2,20 @@
* raw FLAC muxer
* Copyright (c) 2006-2009 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,7 +41,7 @@ static int flac_write_block_padding(AVIOContext *pb, unsigned int n_padding_byte
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 +69,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;
@@ -113,7 +122,6 @@ static int flac_write_trailer(struct AVFormatContext *s)
static int flac_write_packet(struct AVFormatContext *s, AVPacket *pkt)
{
avio_write(s->pb, pkt->data, pkt->size);
- avio_flush(s->pb);
return 0;
}
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..2835cf5 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;
@@ -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;
@@ -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 2f68653..8bb56e8 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)
@@ -76,6 +73,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;
}
@@ -125,8 +127,6 @@ static int flv_same_audio_codec(AVCodecContext *acodec, int flags)
default:
return acodec->codec_tag == (flv_codecid >> FLV_AUDIO_CODECID_OFFSET);
}
-
- return 0;
}
static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream, AVCodecContext *acodec, int flv_codecid) {
@@ -197,14 +197,13 @@ static int flv_same_video_codec(AVCodecContext *vcodec, int flags)
default:
return vcodec->codec_tag == flv_codecid;
}
-
- return 0;
}
static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream, int flv_codecid, int read) {
AVCodecContext *vcodec = vstream->codec;
switch(flv_codecid) {
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;
case FLV_CODECID_SCREEN2: vcodec->codec_id = AV_CODEC_ID_FLASHSV2; break;
case FLV_CODECID_VP6 : vcodec->codec_id = AV_CODEC_ID_VP6F ;
@@ -213,7 +212,7 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream, int flv_co
vcodec->codec_id = AV_CODEC_ID_VP6A;
if (read) {
if (vcodec->extradata_size != 1) {
- vcodec->extradata = av_malloc(1);
+ vcodec->extradata = av_malloc(1 + FF_INPUT_BUFFER_PADDING_SIZE);
if (vcodec->extradata)
vcodec->extradata_size = 1;
}
@@ -226,6 +225,9 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream, int flv_co
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);
vcodec->codec_tag = flv_codecid;
@@ -250,54 +252,51 @@ static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize) {
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;
- }
- 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;
- }
- fileposlen = arraylen;
- current_array = filepositions;
- } else // unexpected metatag inside keyframes, will not use such metadata for indexing
+ if (!strcmp(KEYFRAMES_TIMESTAMP_TAG , str_val) && !times){
+ current_array= &times;
+ timeslen= arraylen;
+ }else if (!strcmp(KEYFRAMES_BYTEOFFSET_TAG, str_val) && !filepositions){
+ current_array= &filepositions;
+ fileposlen= arraylen;
+ }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
@@ -307,7 +306,7 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream
}
}
- 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);
@@ -317,16 +316,15 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream
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;
}
@@ -353,10 +351,10 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst
return -1;
break;
case AMF_DATA_TYPE_OBJECT:
- if ((vstream || astream) && key && !strcmp(KEYFRAMES_TAG, key) && depth == 1)
+ if ((vstream || astream) && ioc->seekable && key && !strcmp(KEYFRAMES_TAG, key) && depth == 1)
if (parse_keyframes_index(s, ioc, vstream ? vstream : astream,
max_pos) < 0)
- return -1;
+ av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n");
while (avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) {
if (amf_parse_object(s, astream, vstream, str_val, max_pos, depth + 1) < 0)
@@ -439,6 +437,11 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst
}
}
+ 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") ||
@@ -468,13 +471,12 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst
static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) {
AMFDataType type;
- AVStream *stream, *astream, *vstream;
+ AVStream *stream, *astream, *vstream, *dstream;
AVIOContext *ioc;
int i;
char buffer[11]; //only needs to hold the string "onMetaData". Anything longer is something we don't want.
- astream = NULL;
- vstream = NULL;
+ vstream = astream = dstream = NULL;
ioc = s->pb;
//first object needs to be "onMetaData" string
@@ -492,8 +494,9 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) {
//find the streams now so that amf_parse_object doesn't need to do the lookup every time it is called.
for(i = 0; i < s->nb_streams; i++) {
stream = s->streams[i];
- if (stream->codec->codec_type == AVMEDIA_TYPE_AUDIO) astream = stream;
- else if(stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) vstream = stream;
+ 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)
@@ -526,6 +529,8 @@ static int flv_read_header(AVFormatContext *s)
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);
@@ -538,9 +543,10 @@ 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;
}
@@ -645,10 +651,12 @@ out:
static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
FLVContext *flv = s->priv_data;
- int ret, i, type, size, flags, is_audio;
+ int ret, i, type, size, flags;
+ int stream_type=-1;
int64_t next, 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;
for(;;avio_skip(s->pb, 4)){ /* pkt size is repeated at end. skip it */
@@ -658,7 +666,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;
@@ -685,22 +693,26 @@ 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) {
+ if (size > 13+1+4 && dts == 0) { // Header-type metadata stuff
+ flv_read_metabody(s, next);
+ goto skip;
+ } else if (dts != 0) { // Script-data "special" metadata frames - don't skip
+ stream_type=FLV_STREAM_TYPE_DATA;
+ } else {
goto skip;
+ }
} 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;
@@ -713,51 +725,69 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
/* 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)) {
+ 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){
+ 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,
- is_audio ? AVMEDIA_TYPE_AUDIO : AVMEDIA_TYPE_VIDEO);
+ stream_types[stream_type]);
+ if (!st)
+ return AVERROR(ENOMEM);
+
}
- 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))
+ 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) >> FLV_AUDIO_SAMPLERATE_OFFSET) >> 3);
@@ -779,15 +809,16 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
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) {
int32_t cts = (avio_rb24(s->pb)+0xff800000)^0xff800000; // sign extension
pts = dts + cts;
if (cts < 0) { // dts are wrong
@@ -797,19 +828,19 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
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)
@@ -818,6 +849,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
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);
@@ -832,33 +864,31 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
}
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;
+ if (ret < 0)
+ 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:
diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
index 37f3777..b0f8a41 100644
--- a/libavformat/flvenc.c
+++ b/libavformat/flvenc.c
@@ -1,41 +1,44 @@
/*
* FLV muxer
- * Copyright (c) 2003 The Libav Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "libavutil/intfloat.h"
+#include "libavutil/avassert.h"
#include "avc.h"
#include "avformat.h"
#include "flv.h"
#include "internal.h"
#include "metadata.h"
-#undef NDEBUG
-#include <assert.h>
static const AVCodecTag flv_video_codec_ids[] = {
{ AV_CODEC_ID_FLV1, FLV_CODECID_H263 },
+ { AV_CODEC_ID_H263, FLV_CODECID_REALH263 },
+ { AV_CODEC_ID_MPEG4, FLV_CODECID_MPEG4 },
{ AV_CODEC_ID_FLASHSV, FLV_CODECID_SCREEN },
{ AV_CODEC_ID_FLASHSV2, FLV_CODECID_SCREEN2 },
{ AV_CODEC_ID_VP6F, FLV_CODECID_VP6 },
{ AV_CODEC_ID_VP6, FLV_CODECID_VP6 },
+ { AV_CODEC_ID_VP6A, FLV_CODECID_VP6A },
{ AV_CODEC_ID_H264, FLV_CODECID_H264 },
{ AV_CODEC_ID_NONE, 0 }
};
@@ -77,12 +80,12 @@ static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc)
else if (enc->codec_id == AV_CODEC_ID_SPEEX) {
if (enc->sample_rate != 16000) {
av_log(s, AV_LOG_ERROR,
- "flv only supports wideband (16kHz) Speex audio\n");
- return -1;
+ "FLV only supports wideband (16kHz) Speex audio\n");
+ return AVERROR(EINVAL);
}
if (enc->channels != 1) {
- av_log(s, AV_LOG_ERROR, "flv only supports mono Speex audio\n");
- return -1;
+ av_log(s, AV_LOG_ERROR, "FLV only supports mono Speex audio\n");
+ return AVERROR(EINVAL);
}
return FLV_CODECID_SPEEX | FLV_SAMPLERATE_11025HZ | FLV_SAMPLESSIZE_16BIT;
} else {
@@ -105,9 +108,9 @@ static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc)
}
default:
av_log(s, AV_LOG_ERROR,
- "flv does not support that sample rate, "
- "choose from (44100, 22050, 11025).\n");
- return -1;
+ "FLV does not support sample rate %d, "
+ "choose from (44100, 22050, 11025)\n", enc->sample_rate);
+ return AVERROR(EINVAL);
}
}
@@ -148,8 +151,9 @@ static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc)
flags |= enc->codec_tag << 4;
break;
default:
- av_log(s, AV_LOG_ERROR, "codec not compatible with flv\n");
- return -1;
+ av_log(s, AV_LOG_ERROR, "Audio codec '%s' not compatible with FLV\n",
+ avcodec_get_name(enc->codec_id));
+ return AVERROR(EINVAL);
}
return flags;
@@ -215,8 +219,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 +236,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 +344,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 +386,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 +429,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 +458,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_VP6 || enc->codec_id == AV_CODEC_ID_VP6F ||
- enc->codec_id == AV_CODEC_ID_AAC)
+ 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 +475,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 +485,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 +496,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,16 +559,17 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_seek(pb, data_size + 10 - 3, SEEK_CUR);
avio_wb32(pb, data_size + 11);
} else {
+ av_assert1(flags>=0);
avio_w8(pb,flags);
if (enc->codec_id == AV_CODEC_ID_VP6)
- avio_w8(pb, 0);
- if (enc->codec_id == AV_CODEC_ID_VP6F)
+ avio_w8(pb,0);
+ if (enc->codec_id == AV_CODEC_ID_VP6F || enc->codec_id == AV_CODEC_ID_VP6A)
avio_w8(pb, enc->extradata_size ? enc->extradata[0] : 0);
else if (enc->codec_id == AV_CODEC_ID_AAC)
- avio_w8(pb, 1); // AAC raw
- else if (enc->codec_id == AV_CODEC_ID_H264) {
- avio_w8(pb, 1); // AVC NALU
- avio_wb24(pb, pkt->pts - pkt->dts);
+ avio_w8(pb,1); // AAC raw
+ 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);
}
avio_write(pb, data ? data : pkt->data, size);
@@ -545,7 +579,6 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
pkt->pts + flv->delay + pkt->duration);
}
- avio_flush(pb);
av_free(data);
return pb->error;
diff --git a/libavformat/framecrcenc.c b/libavformat/framecrcenc.c
index fed0cca..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,17 +29,38 @@ 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));
- avio_flush(s->pb);
return 0;
}
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/frmdec.c b/libavformat/frmdec.c
new file mode 100644
index 0000000..a6f19af
--- /dev/null
+++ b/libavformat/frmdec.c
@@ -0,0 +1,110 @@
+/*
+ * Megalux Frame demuxer
+ * Copyright (c) 2010 Peter Ross <pross@xvid.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Megalux Frame demuxer
+ */
+
+#include "libavcodec/raw.h"
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+
+static const PixelFormatTag frm_pix_fmt_tags[] = {
+ { AV_PIX_FMT_RGB555, 1 },
+ { AV_PIX_FMT_RGB0, 2 },
+ { AV_PIX_FMT_RGB24, 3 },
+ { AV_PIX_FMT_BGR0, 4 },
+ { AV_PIX_FMT_BGRA, 5 },
+ { AV_PIX_FMT_NONE, 0 },
+};
+
+typedef struct {
+ int count;
+} FrmContext;
+
+static int frm_read_probe(AVProbeData *p)
+{
+ if (p->buf_size > 8 &&
+ p->buf[0] == 'F' && p->buf[1] == 'R' && p->buf[2] == 'M' &&
+ AV_RL16(&p->buf[4]) && AV_RL16(&p->buf[6]))
+ return AVPROBE_SCORE_MAX / 4;
+ return 0;
+}
+
+static int frm_read_header(AVFormatContext *avctx)
+{
+ AVIOContext *pb = avctx->pb;
+ AVStream *st = avformat_new_stream(avctx, 0);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ avio_skip(pb, 3);
+
+ st->codec->pix_fmt = avpriv_find_pix_fmt(frm_pix_fmt_tags, avio_r8(pb));
+ if (!st->codec->pix_fmt)
+ return AVERROR_INVALIDDATA;
+
+ st->codec->codec_tag = 0;
+ st->codec->width = avio_rl16(pb);
+ st->codec->height = avio_rl16(pb);
+ return 0;
+}
+
+static int frm_read_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ FrmContext *s = avctx->priv_data;
+ AVCodecContext *stc = avctx->streams[0]->codec;
+ int packet_size, ret;
+
+ if (s->count)
+ return AVERROR_EOF;
+
+ packet_size = avpicture_get_size(stc->pix_fmt, stc->width, stc->height);
+ if (packet_size < 0)
+ return AVERROR_INVALIDDATA;
+
+ ret = av_get_packet(avctx->pb, pkt, packet_size);
+ if (ret < 0)
+ return ret;
+
+ if (stc->pix_fmt == AV_PIX_FMT_BGRA) {
+ int i;
+ for (i = 3; i + 1 <= pkt->size; i += 4)
+ pkt->data[i] = 0xFF - pkt->data[i];
+ }
+
+ pkt->stream_index = 0;
+ s->count++;
+
+ return 0;
+}
+
+AVInputFormat ff_frm_demuxer = {
+ .name = "frm",
+ .priv_data_size = sizeof(FrmContext),
+ .long_name = NULL_IF_CONFIG_SMALL("Megalux Frame"),
+ .read_probe = frm_read_probe,
+ .read_header = frm_read_header,
+ .read_packet = frm_read_packet,
+};
diff --git a/libavformat/g722.c b/libavformat/g722.c
index 8052939..1a87c7d 100644
--- a/libavformat/g722.c
+++ b/libavformat/g722.c
@@ -2,23 +2,24 @@
* g722 raw demuxer
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/avassert.h"
#include "avformat.h"
#include "internal.h"
#include "rawdec.h"
@@ -39,7 +40,7 @@ static int g722_read_header(AVFormatContext *s)
st->codec->bits_per_coded_sample =
av_get_bits_per_sample(st->codec->codec_id);
- assert(st->codec->bits_per_coded_sample > 0);
+ av_assert0(st->codec->bits_per_coded_sample > 0);
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
return 0;
diff --git a/libavformat/g723_1.c b/libavformat/g723_1.c
index b67c07c..4f3ce8f 100644
--- a/libavformat/g723_1.c
+++ b/libavformat/g723_1.c
@@ -2,20 +2,20 @@
* G.723.1 demuxer
* Copyright (c) 2010 Mohamed Naufal Basheer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -81,6 +81,6 @@ AVInputFormat ff_g723_1_demuxer = {
.long_name = NULL_IF_CONFIG_SMALL("G.723.1"),
.read_header = g723_1_init,
.read_packet = g723_1_read_packet,
- .extensions = "tco",
+ .extensions = "tco,rco,g723_1",
.flags = AVFMT_GENERIC_INDEX
};
diff --git a/libavformat/g729dec.c b/libavformat/g729dec.c
new file mode 100644
index 0000000..794558e
--- /dev/null
+++ b/libavformat/g729dec.c
@@ -0,0 +1,103 @@
+/*
+ * G.729 raw format demuxer
+ * Copyright (c) 2011 Vladimir Voroshilov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+
+typedef struct G729DemuxerContext {
+ AVClass *class;
+ int bit_rate;
+} G729DemuxerContext;
+
+static int g729_read_header(AVFormatContext *s)
+{
+ AVStream* st;
+ G729DemuxerContext *s1 = s->priv_data;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_G729;
+ st->codec->sample_rate = 8000;
+ st->codec->channels = 1;
+
+ if (s1 && s1->bit_rate) {
+ s->bit_rate = s1->bit_rate;
+ }
+
+ if (s->bit_rate == 0) {
+ av_log(s, AV_LOG_DEBUG, "No bitrate specified. Assuming 8000 b/s\n");
+ s->bit_rate = 8000;
+ }
+
+ if (s->bit_rate == 6400) {
+ st->codec->block_align = 8;
+ } else if (s->bit_rate == 8000) {
+ st->codec->block_align = 10;
+ } else {
+ av_log(s, AV_LOG_ERROR, "Only 8000 b/s and 6400 b/s bitrates are supported. Provided: %d b/s\n", s->bit_rate);
+ return AVERROR_INVALIDDATA;
+ }
+
+ avpriv_set_pts_info(st, st->codec->block_align << 3, 1, st->codec->sample_rate);
+ return 0;
+}
+static int g729_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ int ret;
+
+ ret = av_get_packet(s->pb, pkt, s->streams[0]->codec->block_align);
+
+ pkt->stream_index = 0;
+ if (ret < 0)
+ return ret;
+
+ pkt->dts = pkt->pts = pkt->pos / s->streams[0]->codec->block_align;
+
+ return ret;
+}
+
+static const AVOption g729_options[] = {
+ { "bit_rate", "", offsetof(G729DemuxerContext, bit_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
+ { NULL },
+};
+
+static const AVClass g729_demuxer_class = {
+ .class_name = "g729 demuxer",
+ .item_name = av_default_item_name,
+ .option = g729_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_g729_demuxer = {
+ .name = "g729",
+ .long_name = NULL_IF_CONFIG_SMALL("G.729 raw format demuxer"),
+ .priv_data_size = sizeof(G729DemuxerContext),
+ .read_header = g729_read_header,
+ .read_packet = g729_read_packet,
+ .flags = AVFMT_GENERIC_INDEX,
+ .extensions = "g729",
+ .priv_class = &g729_demuxer_class,
+};
diff --git a/libavformat/gif.c b/libavformat/gif.c
index 2b1e93a..d459bd6 100644
--- a/libavformat/gif.c
+++ b/libavformat/gif.c
@@ -4,348 +4,183 @@
*
* 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
- avio_write(pb, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1);
- avio_w8(pb, 0x03); // byte 15
- avio_w8(pb, 0x01); // byte 16
- avio_wl16(pb, (uint16_t)loop_count);
- avio_w8(pb, 0x00); // byte 19
- }
-#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 */
+ /* "NETSCAPE EXTENSION" for looped animation GIF */
+ avio_w8(pb, 0x21); /* GIF Extension code */
+ avio_w8(pb, 0xff); /* Application Extension Label */
+ avio_w8(pb, 0x0b); /* Length of Application Block */
+ avio_write(pb, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1);
+ avio_w8(pb, 0x03); /* Length of Data Sub-Block */
+ avio_w8(pb, 0x01);
+ avio_wl16(pb, (uint16_t)loop_count);
+ avio_w8(pb, 0x00); /* Data Sub-block Terminator */
return 0;
}
typedef struct {
AVClass *class; /** Class for private options. */
- int64_t time, file_time;
- uint8_t buffer[100]; /* data chunks */
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);
- avio_flush(s->pb);
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;
@@ -356,6 +191,8 @@ static int gif_write_trailer(AVFormatContext *s)
static const AVOption options[] = {
{ "loop", "Number of times to loop the output.", OFFSET(loop),
AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 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 },
};
@@ -373,9 +210,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..e05dc41
--- /dev/null
+++ b/libavformat/gifdec.c
@@ -0,0 +1,324 @@
+/*
+ * 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 netscape_ext[sizeof(NETSCAPE_EXT_STR)-1 + 2];
+
+ if ((sb_size = avio_r8(pb)) != strlen(NETSCAPE_EXT_STR))
+ return 0;
+ ret = avio_read(pb, netscape_ext, sizeof(netscape_ext));
+ if (ret < sizeof(netscape_ext))
+ return ret;
+ gdc->total_iter = avio_rl16(pb);
+ 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..9899266 100644
--- a/libavformat/gsmdec.c
+++ b/libavformat/gsmdec.c
@@ -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;
diff --git a/libavformat/gxf.c b/libavformat/gxf.c
index 6feb3c3..86e6291 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
@@ -226,6 +248,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 +262,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 +274,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 +343,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 +353,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 +397,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 +430,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 +492,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 +544,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 128122f..9322f7b 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,30 +205,33 @@ 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_timecode_auxiliary(AVIOContext *pb, GXFContext *gxf)
{
- avio_w8(pb, 0); /* fields */
- avio_w8(pb, 0); /* seconds */
- avio_w8(pb, 0); /* minutes */
- avio_w8(pb, 0); /* flags + hours */
+ uint32_t timecode = GXF_TIMECODE(gxf->tc.color, gxf->tc.drop,
+ gxf->tc.hh, gxf->tc.mm,
+ gxf->tc.ss, gxf->tc.ff);
+
+ 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;
@@ -235,7 +255,7 @@ static int gxf_write_track_description(AVFormatContext *s, GXFStreamContext *sc,
avio_w8(pb, TRACK_AUX);
avio_w8(pb, 8);
if (sc->track_type == 3)
- gxf_write_timecode_auxiliary(pb, sc);
+ gxf_write_timecode_auxiliary(pb, gxf);
else
avio_wl64(pb, 0);
}
@@ -342,8 +362,9 @@ static int gxf_write_map_packet(AVFormatContext *s, int rewrite)
if (!rewrite) {
if (!(gxf->map_offsets_nb % 30)) {
- gxf->map_offsets = av_realloc(gxf->map_offsets,
- (gxf->map_offsets_nb+30)*sizeof(*gxf->map_offsets));
+ gxf->map_offsets = av_realloc_f(gxf->map_offsets,
+ sizeof(*gxf->map_offsets),
+ gxf->map_offsets_nb+30);
if (!gxf->map_offsets) {
av_log(s, AV_LOG_ERROR, "could not realloc map offsets\n");
return -1;
@@ -396,25 +417,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 */
@@ -489,9 +521,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 */
@@ -560,7 +592,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) {
@@ -623,6 +655,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;
@@ -630,9 +681,10 @@ static int gxf_write_header(AVFormatContext *s)
GXFStreamContext *vsc = NULL;
uint8_t tracks[255] = {0};
int i, media_info = 0;
+ 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;
}
@@ -690,6 +742,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;
@@ -741,6 +795,9 @@ 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
@@ -873,8 +930,9 @@ static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt)
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
if (!(gxf->flt_entries_nb % 500)) {
- gxf->flt_entries = av_realloc(gxf->flt_entries,
- (gxf->flt_entries_nb+500)*sizeof(*gxf->flt_entries));
+ gxf->flt_entries = av_realloc_f(gxf->flt_entries,
+ sizeof(*gxf->flt_entries),
+ gxf->flt_entries_nb+500);
if (!gxf->flt_entries) {
av_log(s, AV_LOG_ERROR, "could not reallocate flt entries\n");
return -1;
@@ -892,8 +950,6 @@ static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt)
gxf->packet_count = 0;
}
- avio_flush(pb);
-
return 0;
}
diff --git a/libavformat/h261dec.c b/libavformat/h261dec.c
index 4a58050..1474a16 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
*/
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 7d3bb47..5de582b 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/hls.c b/libavformat/hls.c
index 0d691ec..7de6059 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;
}
@@ -212,9 +216,19 @@ static int parse_playlist(HLSContext *c, const char *url,
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 dont 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;
}
@@ -228,7 +242,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}};
@@ -323,19 +337,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",
@@ -357,17 +379,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)
@@ -393,7 +423,7 @@ reload:
/* If we need to reload the playlist again below (if
* there's still no more segments), switch to a reload
* interval of half the target duration. */
- reload_interval = v->target_duration * 500000;
+ reload_interval = v->target_duration * 500000LL;
}
if (v->cur_seq_no < v->start_seq_no) {
av_log(NULL, AV_LOG_WARNING,
@@ -413,7 +443,7 @@ reload:
goto reload;
}
- ret = open_input(v);
+ ret = open_input(c, v);
if (ret < 0)
return ret;
}
@@ -427,7 +457,7 @@ reload:
c->end_of_segment = 1;
c->cur_seq_no = v->cur_seq_no;
- if (v->ctx && v->ctx->nb_streams) {
+ if (v->ctx && v->ctx->nb_streams && v->parent->nb_streams >= v->stream_offset + v->ctx->nb_streams) {
v->needed = 0;
for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams;
i++) {
@@ -445,11 +475,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;
@@ -488,6 +534,7 @@ static int hls_read_header(AVFormatContext *s)
struct variant *v = c->variants[i];
AVInputFormat *in_fmt = NULL;
char bitrate_str[20];
+ AVProgram *program = NULL;
if (v->n_segments == 0)
continue;
@@ -517,6 +564,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;
@@ -525,16 +573,31 @@ static int hls_read_header(AVFormatContext *s)
ret = avformat_open_input(&v->ctx, v->segments[0]->url, in_fmt, NULL);
if (ret < 0)
goto fail;
+
v->stream_offset = stream_offset;
+ v->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER;
+ ret = avformat_find_stream_info(v->ctx, NULL);
+ if (ret < 0)
+ goto fail;
snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth);
+
+ /* Create new AVprogram for variant i */
+ program = av_new_program(s, i);
+ if (!program)
+ goto fail;
+ av_dict_set(&program->metadata, "variant_bitrate", bitrate_str, 0);
+
/* Create new AVStreams for each stream in this variant */
for (j = 0; j < v->ctx->nb_streams; j++) {
AVStream *st = avformat_new_stream(s, NULL);
+ AVStream *ist = v->ctx->streams[j];
if (!st) {
ret = AVERROR(ENOMEM);
goto fail;
}
+ ff_program_add_stream_index(s, i, stream_offset + j);
st->id = i;
+ avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den);
avcodec_copy_context(st->codec, v->ctx->streams[j]->codec);
if (v->bandwidth)
av_dict_set(&st->metadata, "variant_bitrate", bitrate_str,
@@ -560,7 +623,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];
@@ -610,7 +673,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;
@@ -640,9 +703,21 @@ start:
}
/* Check if this stream has the packet with the lowest dts */
if (var->pkt.data) {
- if (minvariant < 0 ||
- var->pkt.dts < c->variants[minvariant]->pkt.dts)
+ if(minvariant < 0) {
minvariant = i;
+ } else {
+ struct variant *minvar = c->variants[minvariant];
+ int64_t dts = var->pkt.dts;
+ int64_t mindts = minvar->pkt.dts;
+ AVStream *st = var->ctx->streams[ var->pkt.stream_index];
+ AVStream *minst= minvar->ctx->streams[minvar->pkt.stream_index];
+
+ if( st->start_time != AV_NOPTS_VALUE) dts -= st->start_time;
+ if(minst->start_time != AV_NOPTS_VALUE) mindts -= minst->start_time;
+
+ if (av_compare_ts(dts, st->time_base, mindts, minst->time_base) < 0)
+ minvariant = i;
+ }
}
}
if (c->end_of_segment) {
@@ -696,10 +771,11 @@ static int hls_read_seek(AVFormatContext *s, int stream_index,
/* Reset reading */
struct variant *var = c->variants[i];
int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? 0 :
- av_rescale_rnd(c->first_timestamp, 1,
- stream_index >= 0 ? s->streams[stream_index]->time_base.den : AV_TIME_BASE,
- flags & AVSEEK_FLAG_BACKWARD ? AV_ROUND_DOWN : AV_ROUND_UP);
- if (var->input) {
+ av_rescale_rnd(c->first_timestamp, 1, stream_index >= 0 ?
+ s->streams[stream_index]->time_base.den :
+ AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ?
+ AV_ROUND_DOWN : AV_ROUND_UP);
+ if (var->input) {
ffurl_close(var->input);
var->input = NULL;
}
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index caf878f..e97b4e0 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
*/
@@ -49,6 +49,7 @@ typedef struct HLSContext {
int has_video;
int64_t start_pts;
int64_t end_pts;
+ int64_t duration; ///< last segment duration computed so far, in seconds
int nb_entries;
ListEntry *list;
ListEntry *end_list;
@@ -167,8 +168,10 @@ static int hls_start(AVFormatContext *s)
c->number %= c->wrap;
if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
- c->basename, c->number++) < 0)
+ c->basename, c->number++) < 0) {
+ av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->basename);
return AVERROR(EINVAL);
+ }
if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
&s->interrupt_callback, NULL)) < 0)
@@ -250,6 +253,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) {
@@ -260,17 +264,23 @@ 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)
+ 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);
if (can_split && av_compare_ts(pkt->pts - hls->start_pts, st->time_base,
end_pts, AV_TIME_BASE_Q) >= 0) {
- ret = append_entry(hls, av_rescale(pkt->pts - hls->end_pts,
- st->time_base.num,
- st->time_base.den));
+ ret = append_entry(hls, hls->duration);
if (ret)
return ret;
hls->end_pts = pkt->pts;
+ hls->duration = 0;
av_write_frame(oc, NULL); /* Flush any buffered data */
avio_close(oc->pb);
@@ -300,6 +310,7 @@ static int hls_write_trailer(struct AVFormatContext *s)
avio_closep(&oc->pb);
avformat_free_context(oc);
av_free(hls->basename);
+ append_entry(hls, hls->duration);
hls_window(s, 1);
free_entries(hls);
@@ -310,10 +321,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 72b6c72..4e35043 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
*/
@@ -125,7 +125,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}};
@@ -280,7 +280,7 @@ retry:
/* If we need to reload the playlist again below (if
* there's still no more segments), switch to a reload
* interval of half the target duration. */
- reload_interval = s->target_duration * 500000;
+ reload_interval = s->target_duration * 500000LL;
}
}
if (s->cur_seq_no < s->start_seq_no) {
diff --git a/libavformat/http.c b/libavformat/http.c
index 730a5b1..7f33eca 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
*/
@@ -29,7 +29,7 @@
#include "url.h"
#include "libavutil/opt.h"
-/* XXX: POST protocol is not completely implemented because avconv uses
+/* XXX: POST protocol is not completely implemented because ffmpeg uses
only a subset of it. */
/* The IO buffer size is unrelated to the max URL size in itself, but needs
@@ -46,28 +46,42 @@ 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;
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;
+ int rw_timeout;
+ char *mime_type;
+ char *cookies; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
} HTTPContext;
#define OFFSET(x) offsetof(HTTPContext, x)
#define D AV_OPT_FLAG_DECODING_PARAM
#define E AV_OPT_FLAG_ENCODING_PARAM
+#define DEFAULT_USER_AGENT "Mozilla/5.0 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 },
+{"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, 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 },
{NULL}
};
#define HTTP_CLASS(flavor)\
@@ -145,8 +159,15 @@ static int http_open_cnx(URLContext *h)
ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL);
if (!s->hd) {
+ AVDictionary *opts = NULL;
+ char opts_format[20];
+ 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->hd, buf, AVIO_FLAG_READ_WRITE,
- &h->interrupt_callback, NULL);
+ &h->interrupt_callback, &opts);
+ av_dict_free(&opts);
if (err < 0)
goto fail;
}
@@ -159,8 +180,7 @@ static int http_open_cnx(URLContext *h)
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;
@@ -168,8 +188,7 @@ static int http_open_cnx(URLContext *h)
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;
@@ -177,8 +196,7 @@ static int http_open_cnx(URLContext *h)
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
@@ -191,8 +209,7 @@ static int http_open_cnx(URLContext *h)
return 0;
fail:
if (s->hd)
- ffurl_close(s->hd);
- s->hd = NULL;
+ ffurl_closep(&s->hd);
return AVERROR(EIO);
}
@@ -210,7 +227,10 @@ static int http_open(URLContext *h, const char *uri, int flags)
{
HTTPContext *s = h->priv_data;
- 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));
@@ -321,8 +341,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;
@@ -336,11 +357,124 @@ 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);
+ }
}
}
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);
+ }
+ }
+
+ // 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!) */
@@ -380,7 +514,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;
@@ -405,12 +539,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);
@@ -430,6 +567,17 @@ 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);
+ }
+ }
/* now add in custom headers */
if (s->headers)
@@ -600,7 +748,7 @@ static int http_close(URLContext *h)
}
if (s->hd)
- ffurl_close(s->hd);
+ ffurl_closep(&s->hd);
return ret;
}
@@ -683,7 +831,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;
}
@@ -697,8 +845,13 @@ static int http_proxy_open(URLContext *h, const char *uri, int flags)
HTTPAuthType cur_auth_type;
char *authstr;
int new_loc;
+ AVDictionary *opts = NULL;
+ char opts_format[20];
- 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);
@@ -710,8 +863,13 @@ static int http_proxy_open(URLContext *h, const char *uri, int flags)
ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port,
NULL);
redo:
+ 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 */
ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
- &h->interrupt_callback, NULL);
+ &h->interrupt_callback, &opts);
+ av_dict_free(&opts);
if (ret < 0)
return ret;
@@ -754,8 +912,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
--- /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
--- /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..e585f0e 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"
@@ -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,42 @@ fail:
avio_seek(pb, end, SEEK_SET);
}
+static void read_chapter(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta)
+{
+ AVRational time_base = {1, 1000};
+ uint32_t start, end;
+ uint8_t *dst = NULL;
+ int encoding;
+
+ decode_str(s, pb, 0, &dst, &taglen);
+ if (taglen < 16)
+ return;
+
+ start = avio_rb32(pb);
+ end = avio_rb32(pb);
+ taglen -= 27;
+ if (taglen > 0) {
+ char tag[4];
+
+ avio_skip(pb, 8);
+ avio_read(pb, tag, 4);
+ if (!memcmp(tag, "TIT2", 4)) {
+ taglen = FFMIN(taglen, avio_rb32(pb));
+ if (taglen < 0) {
+ av_free(dst);
+ return;
+ }
+ avio_skip(pb, 2);
+ encoding = avio_r8(pb);
+ av_freep(&dst);
+ decode_str(s, pb, encoding, &dst, &taglen);
+ }
+ }
+
+ avpriv_new_chapter(s, s->nb_chapters + 1, time_base, start, end, dst);
+ av_free(dst);
+}
+
typedef struct ID3v2EMFunc {
const char *tag3;
const char *tag4;
@@ -516,6 +565,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 +578,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 +591,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 +601,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 +641,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 +669,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 +686,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,9 +739,39 @@ 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);
@@ -667,7 +780,7 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
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 +799,7 @@ error:
version, reason);
avio_seek(s->pb, end, SEEK_SET);
av_free(buffer);
+ av_free(uncompressed_buffer);
return;
}
@@ -701,8 +815,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..a10d679 100644
--- a/libavformat/id3v2enc.c
+++ b/libavformat/id3v2enc.c
@@ -1,26 +1,27 @@
/*
* 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"
@@ -109,6 +110,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)
{
@@ -130,7 +169,9 @@ int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3)
ID3v2_ENCODING_UTF8;
ff_metadata_conv(&s->metadata, ff_id3v2_34_metadata_conv, NULL);
- if (id3->version == 4)
+ if (id3->version == 3)
+ id3v2_3_metadata_split_date(&s->metadata);
+ else if (id3->version == 4)
ff_metadata_conv(&s->metadata, ff_id3v2_4_metadata_conv, NULL);
while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
diff --git a/libavformat/idcin.c b/libavformat/idcin.c
index 2536e8b..a4085a9 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
*/
@@ -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 eeaafec..6f843d7 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..1efc147 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,
};
diff --git a/libavformat/ilbc.c b/libavformat/ilbc.c
index c01eb6f..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
*/
@@ -56,7 +56,6 @@ static int ilbc_write_header(AVFormatContext *s)
static int ilbc_write_packet(AVFormatContext *s, AVPacket *pkt)
{
avio_write(s->pb, pkt->data, pkt->size);
- avio_flush(s->pb);
return 0;
}
diff --git a/libavformat/img2.c b/libavformat/img2.c
index 23176d2..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,27 +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..e32c951 100644
--- a/libavformat/img2dec.c
+++ b/libavformat/img2dec.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
*/
@@ -27,20 +27,42 @@
#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;
} VideoDemuxData;
static const int sizes[][2] = {
@@ -70,15 +92,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 +140,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 +180,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 +193,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 +210,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,17 +223,75 @@ static int img_read_header(AVFormatContext *s1)
st->need_parsing = AVSTREAM_PARSE_FULL;
}
- avpriv_set_pts_info(st, 60, framerate.den, framerate.num);
+ avpriv_set_pts_info(st, 60, 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 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;
@@ -207,8 +307,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 +324,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 +338,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 +359,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 +368,21 @@ 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->is_pipe)
+ pkt->pts = s->pts;
pkt->size = 0;
for (i = 0; i < 3; i++) {
@@ -283,18 +401,49 @@ 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;
+
+ 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 },
{ NULL },
};
@@ -312,6 +461,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..551d880 100644
--- a/libavformat/img2enc.c
+++ b/libavformat/img2enc.c
@@ -3,26 +3,28 @@
* 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"
@@ -32,6 +34,7 @@ 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;
} VideoMuxData;
@@ -39,6 +42,9 @@ typedef struct {
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,15 +54,24 @@ 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) {
@@ -65,57 +80,42 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
} 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 = ((-codec->width)>>desc->log2_chroma_w) * ((-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 +130,9 @@ 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 }, 1, INT_MAX, ENC },
{ NULL },
};
@@ -146,9 +147,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 7367369..4d56388 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
*/
@@ -42,20 +42,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 +76,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);
@@ -241,7 +240,7 @@ AVChapter *avpriv_new_chapter(AVFormatContext *s, int id, AVRational time_base,
*/
void ff_reduce_index(AVFormatContext *s, int stream_index);
-/*
+/**
* Convert a relative url into an absolute url, given a base url.
*
* @param buf the buffer where output absolute url is written
@@ -348,6 +347,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.
*/
@@ -375,6 +376,20 @@ enum AVCodecID ff_codec_get_id(const AVCodecTag *tags, unsigned int tag);
*/
enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags);
+/**
+ * Chooses a timebase for muxing the specified stream.
+ *
+ * The 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);
+
int ff_http_match_no_proxy(const char *no_proxy, const char *hostname);
#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
--- /dev/null
+++ b/libavformat/ircam.c
@@ -0,0 +1,47 @@
+/*
+ * IRCAM common code
+ * Copyright (c) 2012 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avformat.h"
+#include "internal.h"
+
+const AVCodecTag ff_codec_ircam_le_tags[] = {
+ { AV_CODEC_ID_PCM_ALAW, 0x10001 },
+ { AV_CODEC_ID_PCM_F32LE, 0x00004 },
+ { AV_CODEC_ID_PCM_F64LE, 0x00008 },
+ { AV_CODEC_ID_PCM_MULAW, 0x20001 },
+ { AV_CODEC_ID_PCM_S16LE, 0x00002 },
+ { AV_CODEC_ID_PCM_S24LE, 0x00003 },
+ { AV_CODEC_ID_PCM_S32LE, 0x40004 },
+ { AV_CODEC_ID_PCM_S8, 0x00001 },
+ { AV_CODEC_ID_NONE, 0 },
+};
+
+const AVCodecTag ff_codec_ircam_be_tags[] = {
+ { AV_CODEC_ID_PCM_ALAW, 0x10001 },
+ { AV_CODEC_ID_PCM_F32BE, 0x00004 },
+ { AV_CODEC_ID_PCM_F64BE, 0x00008 },
+ { AV_CODEC_ID_PCM_MULAW, 0x20001 },
+ { AV_CODEC_ID_PCM_S16BE, 0x00002 },
+ { AV_CODEC_ID_PCM_S24BE, 0x00003 },
+ { AV_CODEC_ID_PCM_S32BE, 0x40004 },
+ { AV_CODEC_ID_PCM_S8, 0x00001 },
+ { AV_CODEC_ID_NONE, 0 },
+};
diff --git a/libavformat/ircam.h b/libavformat/ircam.h
new file mode 100644
index 0000000..f7f9c84
--- /dev/null
+++ b/libavformat/ircam.h
@@ -0,0 +1,30 @@
+/*
+ * IRCAM common code
+ * Copyright (c) 2012 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFORMAT_IRCAM_H
+#define AVFORMAT_IRCAM_H
+
+#include "internal.h"
+
+extern const AVCodecTag ff_codec_ircam_be_tags[];
+extern const AVCodecTag ff_codec_ircam_le_tags[];
+
+#endif /* AVFORMAT_IRCAM_H */
diff --git a/libavformat/ircamdec.c b/libavformat/ircamdec.c
new file mode 100644
index 0000000..f9533ec
--- /dev/null
+++ b/libavformat/ircamdec.c
@@ -0,0 +1,115 @@
+/*
+ * IRCAM demuxer
+ * Copyright (c) 2012 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+#include "pcm.h"
+#include "ircam.h"
+
+static int ircam_probe(AVProbeData *p)
+{
+ if ((p->buf[0] == 0x64 && p->buf[1] == 0xA3 && p->buf[3] == 0x00 &&
+ p->buf[2] >= 1 && p->buf[2] <= 4) ||
+ (p->buf[3] == 0x64 && p->buf[2] == 0xA3 && p->buf[0] == 0x00 &&
+ p->buf[1] >= 1 && p->buf[1] <= 3) &&
+ AV_RN32(p->buf + 4) && AV_RN32(p->buf + 8))
+ return AVPROBE_SCORE_MAX / 4 * 3;
+ return 0;
+}
+
+static const struct endianess {
+ uint32_t magic;
+ int is_le;
+} table[] = {
+ { 0x64A30100, 0 },
+ { 0x64A30200, 1 },
+ { 0x64A30300, 0 },
+ { 0x64A30400, 1 },
+ { 0x0001A364, 1 },
+ { 0x0002A364, 0 },
+ { 0x0003A364, 1 },
+};
+
+static int ircam_read_header(AVFormatContext *s)
+{
+ uint32_t magic, sample_rate, channels, tag;
+ const AVCodecTag *tags;
+ int le = -1, i;
+ AVStream *st;
+
+ magic = avio_rl32(s->pb);
+ for (i = 0; i < 7; i++) {
+ if (magic == table[i].magic) {
+ le = table[i].is_le;
+ break;
+ }
+ }
+
+ if (le == 1) {
+ sample_rate = av_int2float(avio_rl32(s->pb));
+ channels = avio_rl32(s->pb);
+ tag = avio_rl32(s->pb);
+ tags = ff_codec_ircam_le_tags;
+ } else if (le == 0) {
+ sample_rate = av_int2float(avio_rb32(s->pb));
+ channels = avio_rb32(s->pb);
+ tag = avio_rb32(s->pb);
+ tags = ff_codec_ircam_be_tags;
+ } else {
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (!channels || !sample_rate)
+ return AVERROR_INVALIDDATA;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->channels = channels;
+ st->codec->sample_rate = sample_rate;
+
+ st->codec->codec_id = ff_codec_get_id(tags, tag);
+ if (st->codec->codec_id == AV_CODEC_ID_NONE) {
+ av_log(s, AV_LOG_ERROR, "unknown tag %X\n", tag);
+ return AVERROR_INVALIDDATA;
+ }
+
+ st->codec->bits_per_coded_sample = av_get_bits_per_sample(st->codec->codec_id);
+ st->codec->block_align = st->codec->bits_per_coded_sample * st->codec->channels / 8;
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ avio_skip(s->pb, 1008);
+
+ return 0;
+}
+
+AVInputFormat ff_ircam_demuxer = {
+ .name = "ircam",
+ .long_name = NULL_IF_CONFIG_SMALL("Berkeley/IRCAM/CARL Sound Format"),
+ .read_probe = ircam_probe,
+ .read_header = ircam_read_header,
+ .read_packet = ff_pcm_read_packet,
+ .read_seek = ff_pcm_read_seek,
+ .extensions = "sf,ircam",
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/ircamenc.c b/libavformat/ircamenc.c
new file mode 100644
index 0000000..38f15fb
--- /dev/null
+++ b/libavformat/ircamenc.c
@@ -0,0 +1,62 @@
+/*
+ * IRCAM muxer
+ * Copyright (c) 2012 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "avio_internal.h"
+#include "internal.h"
+#include "rawenc.h"
+#include "ircam.h"
+
+static int ircam_write_header(AVFormatContext *s)
+{
+ AVCodecContext *codec = s->streams[0]->codec;
+ uint32_t tag;
+
+ if (s->nb_streams != 1) {
+ av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
+ return AVERROR(EINVAL);
+ }
+
+ tag = ff_codec_get_tag(ff_codec_ircam_le_tags, codec->codec_id);
+ if (!tag) {
+ av_log(s, AV_LOG_ERROR, "unsupported codec\n");
+ return AVERROR(EINVAL);
+ }
+
+ avio_wl32(s->pb, 0x0001A364);
+ avio_wl32(s->pb, av_float2int(codec->sample_rate));
+ avio_wl32(s->pb, codec->channels);
+ avio_wl32(s->pb, tag);
+ ffio_fill(s->pb, 0, 1008);
+ return 0;
+}
+
+AVOutputFormat ff_ircam_muxer = {
+ .name = "ircam",
+ .extensions = "sf,ircam",
+ .long_name = NULL_IF_CONFIG_SMALL("Berkeley/IRCAM/CARL Sound Format"),
+ .audio_codec = AV_CODEC_ID_PCM_S16LE,
+ .video_codec = AV_CODEC_ID_NONE,
+ .write_header = ircam_write_header,
+ .write_packet = ff_raw_write_packet,
+ .codec_tag = (const AVCodecTag *const []){ ff_codec_ircam_le_tags, 0 },
+};
diff --git a/libavformat/isom.c b/libavformat/isom.c
index 0d4e32f..4475846 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,6 +145,7 @@ 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 */
@@ -149,9 +164,11 @@ 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', '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 */
@@ -203,6 +220,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 +233,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_NONE, 0 },
};
@@ -271,13 +291,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 },
};
@@ -340,7 +364,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;
@@ -412,6 +436,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);
@@ -447,3 +476,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 932b1d0..4154baf 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 alt_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,6 +159,8 @@ 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
} MOVContext;
@@ -194,5 +204,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 e045597..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"
@@ -53,7 +53,6 @@ static int ivf_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_wl32(pb, pkt->size);
avio_wl64(pb, pkt->pts);
avio_write(pb, pkt->data, pkt->size);
- avio_flush(pb);
return 0;
}
diff --git a/libavformat/jacosubdec.c b/libavformat/jacosubdec.c
new file mode 100644
index 0000000..da1afad
--- /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 += strcspn(ptr, "\n") + 1;
+ }
+ 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
--- /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..e941492 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
*/
@@ -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..9dfb4e4 100644
--- a/libavformat/latmenc.c
+++ b/libavformat/latmenc.c
@@ -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_bits(&gb, avctx->extradata, avctx->extradata_size * 8);
+ 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/libmodplug.c b/libavformat/libmodplug.c
new file mode 100644
index 0000000..aa8edcc
--- /dev/null
+++ b/libavformat/libmodplug.c
@@ -0,0 +1,368 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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;
+ int 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 %dB "
+ "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 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_header = modplug_read_header,
+ .read_packet = modplug_read_packet,
+ .read_close = modplug_read_close,
+ .read_seek = modplug_read_seek,
+ .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", // compressed mods
+ .priv_class = &modplug_class,
+};
diff --git a/libavformat/libnut.c b/libavformat/libnut.c
new file mode 100644
index 0000000..838c55a
--- /dev/null
+++ b/libavformat/libnut.c
@@ -0,0 +1,322 @@
+/*
+ * 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;
+
+ 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) {
+ st->codec->extradata = av_mallocz(st->codec->extradata_size);
+ if(!st->codec->extradata){
+ 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
--- /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/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
--- /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
--- /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 a10dcca..876f988 100644
--- a/libavformat/lxfdec.c
+++ b/libavformat/lxfdec.c
@@ -2,28 +2,29 @@
* 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
*/
#include "libavutil/intreadwrite.h"
+#include "libavcodec/bytestream.h"
#include "avformat.h"
#include "internal.h"
-#define LXF_PACKET_HEADER_SIZE 60
+#define LXF_MAX_PACKET_HEADER_SIZE 256
#define LXF_HEADER_DATA_SIZE 120
#define LXF_IDENT "LEITCH\0"
#define LXF_IDENT_LENGTH 8
@@ -46,8 +47,8 @@ static const AVCodecTag lxf_tags[] = {
typedef struct {
int channels; ///< number of audio channels. zero means no audio
- uint8_t temp[LXF_MAX_AUDIO_PACKET]; ///< temp buffer for de-planarizing the audio data
int frame_number; ///< current video frame
+ uint32_t video_format, packet_type, extended_size;
} LXFDemuxContext;
static int lxf_probe(AVProbeData *p)
@@ -64,12 +65,12 @@ static int lxf_probe(AVProbeData *p)
* @param[in] header the packet header to check
* @return zero if the checksum is OK, non-zero otherwise
*/
-static int check_checksum(const uint8_t *header)
+static int check_checksum(const uint8_t *header, int size)
{
int x;
uint32_t sum = 0;
- for (x = 0; x < LXF_PACKET_HEADER_SIZE; x += 4)
+ for (x = 0; x < size; x += 4)
sum += AV_RL32(&header[x]);
return sum;
@@ -90,7 +91,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);
@@ -105,70 +106,93 @@ static int sync(AVFormatContext *s, uint8_t *header)
/**
* Read and checksum the next packet header
*
- * @param[out] header the read packet header
- * @param[out] format context dependent format information
* @return the size of the payload following the header or < 0 on failure
*/
-static int get_packet_header(AVFormatContext *s, uint8_t *header, uint32_t *format)
+static int get_packet_header(AVFormatContext *s)
{
+ LXFDemuxContext *lxf = s->priv_data;
AVIOContext *pb = s->pb;
int track_size, samples, ret;
+ uint32_t version, audio_format, header_size, channels, tmp;
AVStream *st;
+ uint8_t header[LXF_MAX_PACKET_HEADER_SIZE];
+ const uint8_t *p;
//find and read the ident
if ((ret = sync(s, header)) < 0)
return ret;
+ ret = avio_read(pb, header + LXF_IDENT_LENGTH, 8);
+ if (ret != 8)
+ return ret < 0 ? ret : AVERROR_EOF;
+
+ p = header + LXF_IDENT_LENGTH;
+ version = bytestream_get_le32(&p);
+ header_size = bytestream_get_le32(&p);
+ if (version > 1)
+ avpriv_request_sample(s, "format version %i", version);
+ if (header_size < (version ? 72 : 60) ||
+ header_size > LXF_MAX_PACKET_HEADER_SIZE ||
+ (header_size & 3)) {
+ av_log(s, AV_LOG_ERROR, "Invalid header size 0x%x\n", header_size);
+ return AVERROR_INVALIDDATA;
+ }
+
//read the rest of the packet header
- if ((ret = avio_read(pb, header + LXF_IDENT_LENGTH,
- LXF_PACKET_HEADER_SIZE - LXF_IDENT_LENGTH)) !=
- LXF_PACKET_HEADER_SIZE - LXF_IDENT_LENGTH) {
+ 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))
+ if (check_checksum(header, header_size))
av_log(s, AV_LOG_ERROR, "checksum error\n");
- *format = AV_RL32(&header[32]);
- ret = AV_RL32(&header[36]);
+ lxf->packet_type = bytestream_get_le32(&p);
+ p += version ? 20 : 12;
- //type
- switch (AV_RL32(&header[16])) {
+ lxf->extended_size = 0;
+ switch (lxf->packet_type) {
case 0:
//video
+ lxf->video_format = bytestream_get_le32(&p);
+ ret = bytestream_get_le32(&p);
//skip VBI data and metadata
- avio_skip(pb, (int64_t)(uint32_t)AV_RL32(&header[44]) +
- (int64_t)(uint32_t)AV_RL32(&header[52]));
+ avio_skip(pb, (int64_t)(uint32_t)AV_RL32(p + 4) +
+ (int64_t)(uint32_t)AV_RL32(p + 12));
break;
case 1:
//audio
- if (!(st = s->streams[1])) {
+ if (!s->streams || !(st = s->streams[1])) {
av_log(s, AV_LOG_INFO, "got audio packet, but no audio stream present\n");
break;
}
+ if (version == 0) p += 8;
+ audio_format = bytestream_get_le32(&p);
+ channels = bytestream_get_le32(&p);
+ track_size = bytestream_get_le32(&p);
+
//set codec based on specified audio bitdepth
//we only support tightly packed 16-, 20-, 24- and 32-bit PCM at the moment
- *format = AV_RL32(&header[40]);
- st->codec->bits_per_coded_sample = (*format >> 6) & 0x3F;
+ st->codec->bits_per_coded_sample = (audio_format >> 6) & 0x3F;
- if (st->codec->bits_per_coded_sample != (*format & 0x3F)) {
+ if (st->codec->bits_per_coded_sample != (audio_format & 0x3F)) {
av_log(s, AV_LOG_WARNING, "only tightly packed PCM currently supported\n");
return AVERROR_PATCHWELCOME;
}
switch (st->codec->bits_per_coded_sample) {
- case 16: st->codec->codec_id = AV_CODEC_ID_PCM_S16LE; break;
+ case 16: st->codec->codec_id = AV_CODEC_ID_PCM_S16LE_PLANAR; break;
case 20: st->codec->codec_id = AV_CODEC_ID_PCM_LXF; break;
- case 24: st->codec->codec_id = AV_CODEC_ID_PCM_S24LE; break;
- case 32: st->codec->codec_id = AV_CODEC_ID_PCM_S32LE; break;
+ case 24: st->codec->codec_id = AV_CODEC_ID_PCM_S24LE_PLANAR; break;
+ case 32: st->codec->codec_id = AV_CODEC_ID_PCM_S32LE_PLANAR; break;
default:
av_log(s, AV_LOG_WARNING,
"only 16-, 20-, 24- and 32-bit PCM currently supported\n");
return AVERROR_PATCHWELCOME;
}
- track_size = AV_RL32(&header[48]);
samples = track_size * 8 / st->codec->bits_per_coded_sample;
//use audio packet size to determine video standard
@@ -185,10 +209,14 @@ static int get_packet_header(AVFormatContext *s, uint8_t *header, uint32_t *form
}
//TODO: warning if track mask != (1 << channels) - 1?
- ret = av_popcount(AV_RL32(&header[44])) * track_size;
+ ret = av_popcount(channels) * track_size;
break;
default:
+ tmp = bytestream_get_le32(&p);
+ ret = bytestream_get_le32(&p);
+ if (tmp == 1)
+ lxf->extended_size = bytestream_get_le32(&p);
break;
}
@@ -199,13 +227,13 @@ static int lxf_read_header(AVFormatContext *s)
{
LXFDemuxContext *lxf = s->priv_data;
AVIOContext *pb = s->pb;
- uint8_t header[LXF_PACKET_HEADER_SIZE], header_data[LXF_HEADER_DATA_SIZE];
+ uint8_t header_data[LXF_HEADER_DATA_SIZE];
int ret;
AVStream *st;
- uint32_t format, video_params, disk_params;
+ uint32_t video_params, disk_params;
uint16_t record_date, expiration_date;
- if ((ret = get_packet_header(s, header, &format)) < 0)
+ if ((ret = get_packet_header(s)) < 0)
return ret;
if (ret != LXF_HEADER_DATA_SIZE) {
@@ -242,7 +270,7 @@ static int lxf_read_header(AVFormatContext *s)
if ((video_params >> 22) & 1)
av_log(s, AV_LOG_WARNING, "VBI data not yet supported\n");
- if ((lxf->channels = (disk_params >> 2) & 0xF)) {
+ if ((lxf->channels = 1 << (disk_params >> 4 & 3) + 1)) {
if (!(st = avformat_new_stream(s, NULL)))
return AVERROR(ENOMEM);
@@ -253,44 +281,23 @@ static int lxf_read_header(AVFormatContext *s)
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
}
- if (format == 1) {
- //skip extended field data
- avio_skip(s->pb, (uint32_t)AV_RL32(&header[40]));
- }
+ avio_skip(s->pb, lxf->extended_size);
return 0;
}
-/**
- * De-planerize the PCM data in lxf->temp
- * FIXME: remove this once support for planar audio is added to libavcodec
- *
- * @param[out] out where to write the de-planerized data to
- * @param[in] bytes the total size of the PCM data
- */
-static void deplanarize(LXFDemuxContext *lxf, AVStream *ast, uint8_t *out, int bytes)
-{
- int x, y, z, i, bytes_per_sample = ast->codec->bits_per_coded_sample >> 3;
-
- for (z = i = 0; z < lxf->channels; z++)
- for (y = 0; y < bytes / bytes_per_sample / lxf->channels; y++)
- for (x = 0; x < bytes_per_sample; x++, i++)
- out[x + bytes_per_sample*(z + y*lxf->channels)] = lxf->temp[i];
-}
-
static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
LXFDemuxContext *lxf = s->priv_data;
AVIOContext *pb = s->pb;
- uint8_t header[LXF_PACKET_HEADER_SIZE], *buf;
AVStream *ast = NULL;
- uint32_t stream, format;
+ uint32_t stream;
int ret, ret2;
- if ((ret = get_packet_header(s, header, &format)) < 0)
+ if ((ret = get_packet_header(s)) < 0)
return ret;
- stream = AV_RL32(&header[16]);
+ stream = lxf->packet_type;
if (stream > 1) {
av_log(s, AV_LOG_WARNING, "got packet with illegal stream index %u\n", stream);
@@ -312,22 +319,16 @@ static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt)
if ((ret2 = av_new_packet(pkt, ret)) < 0)
return ret2;
- //read non-20-bit audio data into lxf->temp so we can deplanarize it
- buf = ast && ast->codec->codec_id != AV_CODEC_ID_PCM_LXF ? lxf->temp : pkt->data;
-
- if ((ret2 = avio_read(pb, buf, ret)) != ret) {
+ if ((ret2 = avio_read(pb, pkt->data, ret)) != ret) {
av_free_packet(pkt);
return ret2 < 0 ? ret2 : AVERROR_EOF;
}
pkt->stream_index = stream;
- if (ast) {
- if(ast->codec->codec_id != AV_CODEC_ID_PCM_LXF)
- deplanarize(lxf, ast, pkt->data, ret);
- } else {
+ if (!ast) {
//picture type (0 = closed I, 1 = open I, 2 = P, 3 = B)
- if (((format >> 22) & 0x3) < 2)
+ if (((lxf->video_format >> 22) & 0x3) < 2)
pkt->flags |= AV_PKT_FLAG_KEY;
pkt->dts = lxf->frame_number++;
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..ee57c18 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/EXPERIMENTAL",AV_CODEC_ID_OPUS},
+ {"A_OPUS", 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,22 @@ const CodecTags ff_mkv_codec_tags[]={
{"A_VORBIS" , AV_CODEC_ID_VORBIS},
{"A_WAVPACK4" , AV_CODEC_ID_WAVPACK},
+ {"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},
@@ -76,6 +89,7 @@ const CodecTags ff_mkv_codec_tags[]={
{"V_REAL/RV20" , AV_CODEC_ID_RV20},
{"V_REAL/RV30" , AV_CODEC_ID_RV30},
{"V_REAL/RV40" , AV_CODEC_ID_RV40},
+ {"V_SNOW" , AV_CODEC_ID_SNOW},
{"V_THEORA" , AV_CODEC_ID_THEORA},
{"V_UNCOMPRESSED" , AV_CODEC_ID_RAWVIDEO},
{"V_VP8" , AV_CODEC_ID_VP8},
@@ -92,6 +106,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 +116,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 b1f7ae4..8a7e10b 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,8 +78,13 @@
#define MATROSKA_ID_TRACKNUMBER 0xD7
#define MATROSKA_ID_TRACKUID 0x73C5
#define MATROSKA_ID_TRACKTYPE 0x83
-#define MATROSKA_ID_TRACKAUDIO 0xE1
-#define MATROSKA_ID_TRACKVIDEO 0xE0
+#define MATROSKA_ID_TRACKVIDEO 0xE0
+#define MATROSKA_ID_TRACKAUDIO 0xE1
+#define MATROSKA_ID_TRACKOPERATION 0xE2
+#define MATROSKA_ID_TRACKCOMBINEPLANES 0xE3
+#define MATROSKA_ID_TRACKPLANE 0xE4
+#define MATROSKA_ID_TRACKPLANEUID 0xE5
+#define MATROSKA_ID_TRACKPLANETYPE 0xE6
#define MATROSKA_ID_CODECID 0x86
#define MATROSKA_ID_CODECPRIVATE 0x63A2
#define MATROSKA_ID_CODECNAME 0x258688
@@ -113,6 +118,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 +137,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
@@ -170,6 +185,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 */
@@ -249,8 +268,13 @@ typedef struct 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 744f7c0..648941e 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;
@@ -147,11 +165,13 @@ typedef struct {
uint64_t flag_forced;
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 +250,7 @@ typedef struct {
uint64_t time_scale;
double duration;
char *title;
+ EbmlBin date_utc;
EbmlList tracks;
EbmlList attachments;
EbmlList chapters;
@@ -267,6 +288,8 @@ typedef struct {
int64_t reference;
uint64_t non_simple;
EbmlBin bin;
+ uint64_t additional_id;
+ EbmlBin additional;
} MatroskaBlock;
static EbmlSyntax ebml_header[] = {
@@ -291,25 +314,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 +352,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 +376,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 +406,9 @@ 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_TRACKFLAGENABLED, EBML_NONE },
{ MATROSKA_ID_TRACKFLAGLACING, EBML_NONE },
{ MATROSKA_ID_CODECNAME, EBML_NONE },
@@ -364,7 +417,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 }
};
@@ -495,10 +547,22 @@ 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_BLOCKREFERENCE, EBML_UINT, 0, offsetof(MatroskaBlock,reference) },
{ 1, EBML_UINT, 0, offsetof(MatroskaBlock,non_simple), {.u=1} },
{ 0 }
@@ -556,6 +620,36 @@ static EbmlSyntax matroska_clusters_incremental[] = {
static const char *const matroska_doctypes[] = { "matroska", "webm" };
+static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos)
+{
+ AVIOContext *pb = matroska->ctx->pb;
+ uint32_t id;
+ matroska->current_id = 0;
+ matroska->num_levels = 0;
+
+ // seek to next position to resync from
+ if (avio_seek(pb, last_pos + 1, SEEK_SET) < 0 || avio_tell(pb) <= last_pos)
+ goto eof;
+
+ id = avio_rb32(pb);
+
+ // try to find a toplevel element
+ 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 ||
+ id == MATROSKA_ID_CLUSTER || id == MATROSKA_ID_CHAPTERS)
+ {
+ matroska->current_id = id;
+ return 0;
+ }
+ id = (id << 8) | avio_r8(pb);
+ }
+eof:
+ matroska->done = 1;
+ return AVERROR_EOF;
+}
+
/*
* Return: Whether we reached the end of a level in the hierarchy or not.
*/
@@ -593,7 +687,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",
@@ -703,14 +797,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);
}
@@ -887,7 +982,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");
@@ -991,7 +1089,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) {
@@ -999,6 +1097,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;
@@ -1047,7 +1150,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);
@@ -1078,7 +1184,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);
@@ -1104,6 +1213,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)
{
@@ -1111,7 +1221,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;
@@ -1139,17 +1250,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)
@@ -1159,7 +1270,7 @@ static void matroska_convert_tag(AVFormatContext *s, EbmlList *list,
int i;
for (i=0; i < list->nb_elem; i++) {
- const char *lang = strcmp(tags[i].lang, "und") ? tags[i].lang : NULL;
+ const char *lang= (tags[i].lang && strcmp(tags[i].lang, "und")) ? tags[i].lang : NULL;
if (!tags[i].name) {
av_log(s, AV_LOG_WARNING, "Skipping invalid tag with no TagName.\n");
@@ -1290,26 +1401,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
@@ -1331,6 +1436,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" };
@@ -1352,6 +1472,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;
@@ -1361,22 +1492,28 @@ static int matroska_read_header(AVFormatContext *s)
MatroskaChapter *chapters;
MatroskaTrack *tracks;
uint64_t max_start = 0;
+ 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]))
@@ -1391,8 +1528,16 @@ static int matroska_read_header(AVFormatContext *s)
ebml_free(ebml_syntax, &ebml);
/* The next thing is a segment. */
- if ((res = ebml_parse(matroska, matroska_segments, matroska)) < 0)
- return res;
+ pos = avio_tell(matroska->ctx->pb);
+ res = ebml_parse(matroska, matroska_segments, matroska);
+ // try resyncing until we find a EBML_STOP type element.
+ while (res != 1) {
+ res = matroska_resync(matroska, pos);
+ if (res < 0)
+ return res;
+ pos = avio_tell(matroska->ctx->pb);
+ res = ebml_parse(matroska, matroska_segment, matroska);
+ }
matroska_execute_seekhead(matroska);
if (!matroska->time_scale)
@@ -1402,16 +1547,21 @@ 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 &&
@@ -1428,10 +1578,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;
@@ -1440,8 +1592,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
@@ -1451,7 +1619,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");
@@ -1481,15 +1649,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
@@ -1505,8 +1681,20 @@ 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_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. */
+ extradata_size = 12 + track->codec_priv.size;
+ extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (extradata == NULL)
+ return AVERROR(ENOMEM);
+ AV_WB32(extradata, extradata_size);
+ memcpy(&extradata[4], "alac", 4);
+ AV_WB32(&extradata[8], 0);
+ memcpy(&extradata[12], track->codec_priv.data, track->codec_priv.size);
} else if (codec_id == AV_CODEC_ID_PCM_S16BE) {
switch (track->audio.bitdepth) {
case 8: codec_id = AV_CODEC_ID_PCM_U8; break;
@@ -1537,22 +1725,9 @@ 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) {
- /* 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. */
- extradata_size = 12 + track->codec_priv.size;
- extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (extradata == NULL)
- return AVERROR(ENOMEM);
- AV_WB32(extradata, extradata_size);
- memcpy(&extradata[4], "alac", 4);
- AV_WB32(&extradata[8], 0);
- memcpy(&extradata[12], track->codec_priv.data,
- 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,
@@ -1569,9 +1744,11 @@ static int matroska_read_header(AVFormatContext *s)
} else if (codec_id == AV_CODEC_ID_RA_144) {
track->audio.out_samplerate = 8000;
track->audio.channels = 1;
- } else if (codec_id == AV_CODEC_ID_RA_288 || codec_id == AV_CODEC_ID_COOK ||
- codec_id == AV_CODEC_ID_ATRAC3 || codec_id == AV_CODEC_ID_SIPR) {
+ } else if ((codec_id == AV_CODEC_ID_RA_288 || codec_id == AV_CODEC_ID_COOK ||
+ codec_id == AV_CODEC_ID_ATRAC3 || codec_id == AV_CODEC_ID_SIPR)
+ && track->codec_priv.data) {
int flavor;
+
ffio_init_context(&b, track->codec_priv.data,track->codec_priv.size,
0, NULL, NULL, NULL, NULL);
avio_skip(&b, 22);
@@ -1633,8 +1810,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,
@@ -1642,21 +1821,52 @@ 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 (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
+ 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;
} 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;
}
}
@@ -1674,7 +1884,7 @@ 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);
+ st->codec->extradata = av_malloc(attachements[j].bin.size + FF_INPUT_BUFFER_PADDING_SIZE);
if(st->codec->extradata == NULL)
break;
st->codec->extradata_size = attachements[j].bin.size;
@@ -1704,6 +1914,8 @@ static int matroska_read_header(AVFormatContext *s)
max_start = chapters[i].start;
}
+ matroska_add_index_entries(matroska);
+
matroska_convert_tags(s);
return 0;
@@ -1773,7 +1985,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;
@@ -1787,18 +1999,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;
@@ -1822,10 +2034,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;
@@ -1835,10 +2047,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;
@@ -1866,7 +2078,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;
@@ -1897,7 +2109,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;
@@ -1915,8 +2127,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;
@@ -1932,15 +2147,16 @@ 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)
{
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;
@@ -1970,18 +2186,51 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
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 (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 &&
@@ -1993,6 +2242,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;
}
@@ -2000,6 +2253,7 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
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,
+ uint8_t *additional, uint64_t additional_id, int additional_size,
int64_t cluster_pos)
{
uint64_t timecode = AV_NOPTS_VALUE;
@@ -2009,7 +2263,7 @@ 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;
if ((n = matroska_ebmlnum_uint(matroska, data, size, &num)) < 0) {
av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n");
@@ -2028,6 +2282,7 @@ 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);
data += 2;
@@ -2047,9 +2302,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 (!st->skip_to_keyframe) {
+ av_log(matroska->ctx, AV_LOG_ERROR, "File is broken, keyframes not correctly marked!\n");
+ matroska->skip_to_keyframe = 0;
+ }
+ if (is_keyframe)
+ matroska->skip_to_keyframe = 0;
}
res = matroska_parse_laces(matroska, &data, &size, (flags & 0x06) >> 1,
@@ -2058,22 +2318,21 @@ 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");
- }
- } else {
- duration = track->default_duration / matroska->time_scale;
- block_duration = duration * laces;
- }
+ if (!block_duration)
+ block_duration = track->default_duration * laces / matroska->time_scale;
- if (timecode != AV_NOPTS_VALUE)
+ 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 ||
@@ -2082,21 +2341,23 @@ 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 {
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);
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:
@@ -2144,18 +2405,21 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska)
i = blocks_list->nb_elem - 1;
if (blocks[i].bin.size > 0 && blocks[i].bin.data) {
int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1;
+ uint8_t* additional = blocks[i].additional.size > 0 ?
+ blocks[i].additional.data : NULL;
if (!blocks[i].non_simple)
- blocks[i].duration = AV_NOPTS_VALUE;
+ blocks[i].duration = 0;
res = matroska_parse_block(matroska,
blocks[i].bin.data, blocks[i].bin.size,
blocks[i].bin.pos,
matroska->current_cluster.timecode,
blocks[i].duration, is_keyframe,
+ additional, blocks[i].additional_id,
+ blocks[i].additional.size,
matroska->current_cluster_pos);
}
}
- if (res < 0) matroska->done = 1;
return res;
}
@@ -2175,39 +2439,32 @@ 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,
+ blocks[i].duration, is_keyframe, NULL, 0, 0,
pos);
}
ebml_free(matroska_cluster, &cluster);
- if (res < 0) matroska->done = 1;
return res;
}
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;
- ret = matroska_parse_cluster(matroska);
+ if (matroska_parse_cluster(matroska) < 0)
+ 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,
@@ -2219,13 +2476,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) {
@@ -2239,8 +2496,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++) {
@@ -2249,7 +2506,7 @@ 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
@@ -2260,11 +2517,28 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index,
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 c521ed3..371b9d0 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -2,20 +2,20 @@
* Matroska muxer
* Copyright (c) 2007 David Conrad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,6 +37,7 @@
#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"
@@ -74,6 +75,7 @@ typedef struct {
typedef struct {
int write_dts;
+ int has_cue;
} mkv_track;
#define MODE_MATROSKAv2 0x01
@@ -124,7 +126,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)));
}
/**
@@ -134,7 +136,7 @@ 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);
@@ -161,18 +163,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)
@@ -184,7 +186,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)
@@ -217,7 +219,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
@@ -389,7 +391,7 @@ static int mkv_add_cuepoint(mkv_cues *cues, int stream, int64_t ts, int64_t clus
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;
@@ -408,7 +410,14 @@ 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);
@@ -491,7 +500,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) {
@@ -503,8 +512,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);
@@ -514,8 +524,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;
@@ -535,7 +546,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;
@@ -543,6 +554,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;
@@ -559,6 +574,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);
@@ -573,8 +590,11 @@ static int mkv_write_tracks(AVFormatContext *s)
tag = av_dict_get(st->metadata, "language", NULL, 0);
put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, tag ? tag->value:"und");
- if (st->disposition)
+ if (default_stream_exists) {
put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGDEFAULT, !!(st->disposition & AV_DISPOSITION_DEFAULT));
+ }
+ if (st->disposition & AV_DISPOSITION_FORCED)
+ put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGFORCED, 1);
// look for a codec ID string specific to mkv to use,
// if none are found, use AVI codes
@@ -596,7 +616,10 @@ static int mkv_write_tracks(AVFormatContext *s)
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) &&
@@ -618,30 +641,40 @@ 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;
- break;
- case MODE_MATROSKAv2:
- if (stereo_fmt <= MATROSKA_VIDEO_STEREOMODE_TYPE_BOTH_EYES_BLOCK_RL)
- valid_fmt = 1;
- break;
- }
- if (valid_fmt)
- put_ebml_uint (pb, MATROSKA_ID_VIDEOSTEREOMODE, stereo_fmt);
+ 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);
}
+
if (st->sample_aspect_ratio.num) {
- int d_width = codec->width*av_q2d(st->sample_aspect_ratio);
+ 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);
put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, codec->height);
- put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYUNIT, 3);
+ }
+
+ 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;
@@ -672,7 +705,7 @@ static int mkv_write_tracks(AVFormatContext *s)
break;
default:
av_log(s, AV_LOG_ERROR, "Only audio, video, and subtitles are supported for Matroska.\n");
- break;
+ return AVERROR(EINVAL);
}
ret = mkv_write_codecprivate(s, pb, codec, native_id, qt_id);
if (ret < 0) return ret;
@@ -782,7 +815,7 @@ 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);
@@ -849,6 +882,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;
@@ -878,9 +912,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);
@@ -899,6 +949,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);
@@ -946,6 +1012,14 @@ static int mkv_write_header(AVFormatContext *s)
put_ebml_binary(pb, MATROSKA_ID_SEGMENTUID, segment_uid, 16);
}
+ if (tag = av_dict_get(s->metadata, "creation_time", NULL, 0)) {
+ // Adjust time so it's relative to 2001-01-01 and convert to nanoseconds.
+ int64_t date_utc = (ff_iso8601_to_unix_time(tag->value) - 978307200) * 1000000000;
+ uint8_t date_utc_buf[8];
+ AV_WB64(date_utc_buf, date_utc);
+ put_ebml_binary(pb, MATROSKA_ID_DATEUTC, date_utc_buf, 8);
+ }
+
// reserve space for the duration
mkv->duration = 0;
mkv->duration_offset = avio_tell(pb);
@@ -980,6 +1054,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);
return 0;
@@ -1004,11 +1079,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;
@@ -1053,6 +1129,7 @@ static int mkv_write_ass_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *p
return max_duration;
}
+#endif
static void mkv_write_block(AVFormatContext *s, AVIOContext *pb,
unsigned int blockid, AVPacket *pkt, int flags)
@@ -1155,12 +1232,16 @@ 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));
@@ -1169,13 +1250,18 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
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 {
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);
@@ -1201,14 +1287,14 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
// start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming or
// after 4k and on a keyframe
- if (mkv->cluster_pos &&
+ if (mkv->cluster_pos != -1 &&
((!s->pb->seekable && (cluster_size > 32*1024 || ts > mkv->cluster_pts + 1000))
|| cluster_size > 5*1024*1024 || ts > mkv->cluster_pts + 5000
|| (codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe && cluster_size > 4*1024))) {
av_log(s, AV_LOG_DEBUG, "Starting new cluster at offset %" PRIu64
" bytes, pts %" PRIu64 "\n", avio_tell(pb), ts);
end_ebml_master(pb, mkv->cluster);
- mkv->cluster_pos = 0;
+ mkv->cluster_pos = -1;
if (mkv->dyn_bc)
mkv_flush_dynbuf(s);
}
@@ -1254,7 +1340,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);
}
@@ -1266,7 +1352,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 "
@@ -1280,7 +1366,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);
@@ -1322,6 +1408,33 @@ static int mkv_query_codec(enum AVCodecID codec_id, int std_compliance)
return 0;
}
+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_WAVPACK, 0xFFFFFFFF },
+ { AV_CODEC_ID_NONE, 0xFFFFFFFF }
+};
+
+const AVCodecTag additional_video_tags[] = {
+ { AV_CODEC_ID_PRORES, 0xFFFFFFFF },
+ { 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[] = {
@@ -1354,9 +1467,14 @@ AVOutputFormat ff_matroska_muxer = {
.flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS |
AVFMT_TS_NONSTRICT,
.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,
};
@@ -1407,7 +1525,9 @@ AVOutputFormat ff_matroska_audio_muxer = {
.write_packet = mkv_write_packet,
.write_trailer = mkv_write_trailer,
.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NONSTRICT,
- .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..cb92c0c 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[32];
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[128];
+ av_strlcpy(buf, av_hash_get_name(c->hash), sizeof(buf) - 100);
+ av_strlcat(buf, "=", sizeof(buf) - 100);
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,9 +114,9 @@ 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);
+ int res = av_hash_alloc(&c->hash, c->hash_name);
+ if (res < 0)
+ return res;
return ff_framehash_write_header(s);
}
@@ -101,8 +124,8 @@ 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 +136,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 = "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 +158,6 @@ AVOutputFormat ff_framemd5_muxer = {
.write_trailer = framemd5_write_trailer,
.flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
AVFMT_TS_NEGATIVE,
+ .priv_class = &framemd5_class,
};
#endif
diff --git a/libavformat/md5proto.c b/libavformat/md5proto.c
index 12ddde3..6af0a6e 100644
--- a/libavformat/md5proto.c
+++ b/libavformat/md5proto.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/metadata.c b/libavformat/metadata.c
index 77fb298..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
--- /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..4b42846
--- /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 <ubitux@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 "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 += strcspn(ptr, "\n") + 1;
+ }
+ 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
--- /dev/null
+++ b/libavformat/microdvdenc.c
@@ -0,0 +1,67 @@
+/*
+ * MicroDVD subtitle muxer
+ * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <inttypes.h>
+#include "avformat.h"
+#include "internal.h"
+
+static int microdvd_write_header(struct AVFormatContext *s)
+{
+ AVCodecContext *avctx = s->streams[0]->codec;
+ AVRational tb = avctx->time_base;
+
+ if (s->nb_streams != 1 || avctx->codec_id != AV_CODEC_ID_MICRODVD) {
+ av_log(s, AV_LOG_ERROR, "Exactly one MicroDVD stream is needed.\n");
+ return -1;
+ }
+
+ if (avctx->extradata && avctx->extradata_size > 0) {
+ avio_write(s->pb, "{DEFAULT}{}", 11);
+ avio_write(s->pb, avctx->extradata, avctx->extradata_size);
+ avio_flush(s->pb);
+ }
+
+ avpriv_set_pts_info(s->streams[0], 64, tb.num, tb.den);
+ return 0;
+}
+
+static int microdvd_write_packet(AVFormatContext *avf, AVPacket *pkt)
+{
+ avio_printf(avf->pb, "{%"PRId64"}", pkt->pts);
+ if (pkt->duration < 0)
+ avio_write(avf->pb, "{}", 2);
+ else
+ avio_printf(avf->pb, "{%"PRId64"}", pkt->pts + pkt->duration);
+ avio_write(avf->pb, pkt->data, pkt->size);
+ avio_write(avf->pb, "\n", 1);
+ return 0;
+}
+
+AVOutputFormat ff_microdvd_muxer = {
+ .name = "microdvd",
+ .long_name = NULL_IF_CONFIG_SMALL("MicroDVD subtitle format"),
+ .mime_type = "text/x-microdvd",
+ .extensions = "sub",
+ .write_header = microdvd_write_header,
+ .write_packet = microdvd_write_packet,
+ .flags = AVFMT_NOTIMESTAMPS,
+ .subtitle_codec = AV_CODEC_ID_MICRODVD,
+};
diff --git a/libavformat/mkvtimestamp_v2.c b/libavformat/mkvtimestamp_v2.c
new file mode 100644
index 0000000..7ba6691
--- /dev/null
+++ b/libavformat/mkvtimestamp_v2.c
@@ -0,0 +1,50 @@
+/*
+ * extract pts as timecode v2, as defined by mkvtoolnix
+ * Copyright (c) 2009 David Conrad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avformat.h"
+#include "internal.h"
+
+static int write_header(AVFormatContext *s)
+{
+ static const char *header = "# timecode format v2\n";
+ avio_write(s->pb, header, strlen(header));
+ avpriv_set_pts_info(s->streams[0], 64, 1, 1000);
+ return 0;
+}
+
+static int write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ char buf[256];
+ if (pkt->stream_index)
+ av_log(s, AV_LOG_WARNING, "More than one stream unsupported\n");
+ snprintf(buf, sizeof(buf), "%" PRId64 "\n", pkt->dts);
+ avio_write(s->pb, buf, strlen(buf));
+ return 0;
+}
+
+AVOutputFormat ff_mkvtimestamp_v2_muxer = {
+ .name = "mkvtimestamp_v2",
+ .long_name = NULL_IF_CONFIG_SMALL("extract pts as timecode v2 format, as defined by mkvtoolnix"),
+ .audio_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_RAWVIDEO,
+ .write_header = write_header,
+ .write_packet = write_packet,
+};
diff --git a/libavformat/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..86a0575 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;
@@ -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,46 @@ 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 = h->priv_data;
+ MMSContext *mms = &mmsh->mms;
+ int ret;
+
+ ret= mmsh_open_internal(h, mmsh->location, 0, FFMAX(timestamp, 0), 0);
+
+ if(ret>=0){
+ if (mms->mms_hd)
+ ffurl_close(mms->mms_hd);
+ av_freep(&mms->streams);
+ av_freep(&mms->asf_header);
+ av_free(mmsh);
+ mmsh = h->priv_data;
+ mms = &mmsh->mms;
+ mms->asf_header_read_size= mms->asf_header_size;
+ }else
+ h->priv_data= 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 4b96f5d..c3d2ebb 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 2d87a08..389f786 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;
}
@@ -686,13 +800,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 +823,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;
@@ -741,7 +858,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 */
@@ -758,6 +875,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->fc->duration = av_rescale(c->duration, AV_TIME_BASE, c->time_scale);
avio_rb32(pb); /* preferred scale */
avio_rb16(pb); /* preferred volume */
@@ -773,31 +894,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;
}
@@ -810,7 +906,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) {
@@ -868,7 +964,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;
@@ -877,6 +974,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;
@@ -892,6 +993,32 @@ 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_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;
@@ -903,9 +1030,12 @@ 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_size = 0;
st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE);
if (!st->codec->extradata)
return AVERROR(ENOMEM);
@@ -945,6 +1075,7 @@ 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_size = 0;
st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE);
if (!st->codec->extradata)
return AVERROR(ENOMEM);
@@ -970,6 +1101,7 @@ static int mov_read_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
av_free(st->codec->extradata);
+ st->codec->extradata_size = 0;
st->codec->extradata = av_mallocz(atom.size - 7 + FF_INPUT_BUFFER_PADDING_SIZE);
if (!st->codec->extradata)
return AVERROR(ENOMEM);
@@ -998,6 +1130,7 @@ static int mov_read_strf(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return AVERROR_INVALIDDATA;
av_free(st->codec->extradata);
+ st->codec->extradata_size = 0;
st->codec->extradata = av_mallocz(atom.size - 40 + FF_INPUT_BUFFER_PADDING_SIZE);
if (!st->codec->extradata)
return AVERROR(ENOMEM);
@@ -1083,15 +1216,15 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
int 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;
}
@@ -1103,14 +1236,13 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
/* 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. */
- multiple_stsd:
av_log(c->fc, AV_LOG_WARNING, "multiple fourcc not supported\n");
avio_skip(pb, size - (avio_tell(pb) - start_pos));
continue;
}
/* we cannot demux concatenated h264 streams because of different extradata */
if (st->codec->codec_tag && st->codec->codec_tag == AV_RL32("avc1"))
- goto multiple_stsd;
+ av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 might not play corrently.\n");
sc->pseudo_stream_id = st->codec->codec_tag ? -1 : pseudo_stream_id;
sc->dref_id= dref_id;
@@ -1128,14 +1260,16 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
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;
}
}
- 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);
@@ -1166,8 +1300,11 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
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 (format == MKTAG('H','2','6','3') &&
!memcmp(st->codec->codec_name, "Sorenson H263", 13))
@@ -1186,7 +1323,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
(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;
@@ -1196,9 +1333,12 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
color_index = 255;
color_dec = 256 / (color_count - 1);
for (j = 0; j < color_count; j++) {
+ if (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);
+ (0xFFU << 24) | (r << 16) | (g << 8) | (b);
color_index -= color_dec;
if (color_index < 0)
color_index = 0;
@@ -1219,7 +1359,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
g = color_table[j * 3 + 1];
b = color_table[j * 3 + 2];
sc->palette[j] =
- (r << 16) | (g << 8) | (b);
+ (0xFFU << 24) | (r << 16) | (g << 8) | (b);
}
} else {
/* load the palette from the file */
@@ -1229,10 +1369,9 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
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);
@@ -1241,7 +1380,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
b = avio_r8(pb);
avio_r8(pb);
sc->palette[j] =
- (r << 16) | (g << 8) | (b);
+ (a << 24 ) | (r << 16) | (g << 8) | (b);
}
}
}
@@ -1250,6 +1389,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
} else if (st->codec->codec_type==AVMEDIA_TYPE_AUDIO) {
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);
st->codec->codec_id = id;
avio_rb16(pb); /* revision level */
@@ -1266,7 +1406,8 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
//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 */
@@ -1337,7 +1478,20 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
st->codec->width = sc->width;
st->codec->height = sc->height;
} else {
- /* other codec type, just skip (rtp, mp4s, tmcd ...) */
+ if (st->codec->codec_tag == MKTAG('t','m','c','d')) {
+ MOVStreamContext *tmcd_ctx = st->priv_data;
+ int val;
+ avio_rb32(pb); /* reserved */
+ val = avio_rb32(pb); /* flags */
+ tmcd_ctx->tmcd_flags = val;
+ if (val & 1)
+ st->codec->flags2 |= CODEC_FLAG2_DROP_FRAME_TIMECODE;
+ avio_rb32(pb); /* time scale */
+ avio_rb32(pb); /* frame duration */
+ st->codec->time_base.den = avio_r8(pb); /* number of frame */
+ st->codec->time_base.num = 1;
+ }
+ /* other codec type, just skip (rtp, mp4s, ...) */
avio_skip(pb, size - (avio_tell(pb) - start_pos));
}
/* this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...) */
@@ -1403,6 +1557,12 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
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;
@@ -1559,6 +1719,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->alt_sample_size = sample_size;
field_size = 32;
} else {
sample_size = 0;
@@ -1636,10 +1797,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)
@@ -1651,6 +1810,11 @@ 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;
+ }
sc->stts_data[i].count= sample_count;
sc->stts_data[i].duration= sample_duration;
@@ -1704,7 +1868,18 @@ 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)
+
+ 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 (duration < 0 && i+2<entries)
sc->dts_shift = FFMAX(sc->dts_shift, -duration);
}
@@ -1772,12 +1947,13 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
AVIndexEntry *mem;
/* 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;
@@ -1795,11 +1971,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;
@@ -1840,7 +2016,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->alt_sample_size > 0 ? sc->alt_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++];
@@ -1955,14 +2131,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 */
@@ -1994,11 +2170,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;
@@ -2026,12 +2217,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);
@@ -2039,14 +2225,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 &&
@@ -2055,9 +2244,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)
+ 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) {
@@ -2169,6 +2370,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
@@ -2245,6 +2461,9 @@ static int mov_read_trex(MOVContext *c, AVIOContext *pb, MOVAtom atom)
trex = av_realloc(c->trex_data, (c->trex_count+1)*sizeof(*c->trex_data));
if (!trex)
return AVERROR(ENOMEM);
+
+ c->fc->duration = AV_NOPTS_VALUE; // the duration from mvhd is not representing the whole file when fragments are used.
+
c->trex_data = trex;
trex = &c->trex_data[c->trex_count++];
avio_r8(pb); /* version */
@@ -2393,7 +2612,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 */
@@ -2432,9 +2651,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;
@@ -2445,9 +2665,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);
@@ -2455,22 +2677,43 @@ 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 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_avid },
+{ 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 */
@@ -2484,7 +2727,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 },
@@ -2494,8 +2737,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 },
@@ -2513,6 +2756,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 },
@@ -2538,25 +2782,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)
@@ -2592,6 +2844,10 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
left = a.size - avio_tell(pb) + start_pos;
if (left > 0) /* skip garbage at atom end */
avio_skip(pb, left);
+ else if(left < 0) {
+ av_log(c->fc, AV_LOG_DEBUG, "undoing overread of %"PRId64" in '%.4s'\n", -left, (char*)&a.type);
+ avio_seek(pb, left, SEEK_CUR);
+ }
}
total_size += a.size;
@@ -2605,46 +2861,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
@@ -2706,7 +2997,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);
}
}
@@ -2717,6 +3008,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;
@@ -2732,8 +3066,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) {
@@ -2750,11 +3091,45 @@ static int mov_read_close(AVFormatContext *s)
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;
@@ -2777,11 +3152,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;
@@ -2826,6 +3235,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) {
@@ -2835,7 +3245,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;
@@ -2866,7 +3276,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);
@@ -2943,8 +3353,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);
@@ -2955,7 +3363,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;
@@ -2965,6 +3376,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 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"),
@@ -2974,4 +3402,6 @@ AVInputFormat ff_mov_demuxer = {
.read_packet = mov_read_packet,
.read_close = mov_read_close,
.read_seek = mov_read_seek,
+ .priv_class = &class,
+ .flags = AVFMT_NO_BYTE_SEEK,
};
diff --git a/libavformat/mov_chan.c b/libavformat/mov_chan.c
index aa7ba10..7078b4a 100644
--- a/libavformat/mov_chan.c
+++ b/libavformat/mov_chan.c
@@ -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/movenc.c b/libavformat/movenc.c
index 496158c..8b3ad7f 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,19 +46,22 @@
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" },
{ "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
+ { "faststart", "Run a second pass to put the moov 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" },
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},
{ NULL },
};
@@ -81,21 +84,41 @@ 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 dont know the duration when its written
+ return (mov->use_editlist<0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) || mov->use_editlist>0;
+}
+
+static int is_co64_required(const MOVTrack *track)
+{
+ int i;
+
+ for (i = 0; i < track->entry; i++) {
+ if (!track->cluster[i].chunkNum)
+ continue;
+ if (track->cluster[i].pos + track->data_offset > UINT32_MAX)
+ return 1;
+ }
+ return 0;
+}
+
/* Chunk offset atom */
static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
{
int i;
- int mode64 = 0; // use 32 bit size variant if possible
+ int mode64 = is_co64_required(track); // use 32 bit size variant if possible
int64_t pos = avio_tell(pb);
avio_wb32(pb, 0); /* size */
- if (pos > UINT32_MAX) {
- mode64 = 1;
+ 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
@@ -153,11 +176,11 @@ 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)
+ if (oldval != track->cluster[i].samples_in_chunk && track->cluster[i].chunkNum)
{
- avio_wb32(pb, i+1); // first chunk
+ 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;
@@ -264,6 +287,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;
@@ -273,10 +312,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");
@@ -307,11 +358,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
@@ -325,6 +375,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);
@@ -376,9 +442,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 */
@@ -386,11 +454,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) {
@@ -551,6 +624,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;
@@ -573,9 +648,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 */
@@ -604,10 +687,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 ?
@@ -615,13 +707,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);
@@ -654,19 +760,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);
@@ -775,20 +868,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;
}
@@ -801,6 +894,7 @@ static const struct {
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 },
@@ -826,7 +920,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;
}
}
@@ -882,6 +977,14 @@ static const AVCodecTag codec_3gp_tags[] = {
{ AV_CODEC_ID_NONE, 0 },
};
+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') },
+ { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
+ { AV_CODEC_ID_NONE, 0 },
+};
+
static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
{
int tag;
@@ -896,6 +999,8 @@ static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
tag = ipod_get_codec_tag(s, track);
else if (track->mode & MODE_3GP)
tag = ff_codec_get_tag(codec_3gp_tags, track->enc->codec_id);
+ else if (track->mode & MODE_F4V)
+ tag = ff_codec_get_tag(codec_f4v_tags, track->enc->codec_id);
else
tag = mov_get_codec_tag(s, track);
@@ -1012,21 +1117,27 @@ 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->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);
@@ -1035,6 +1146,31 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
return update_size(pb, pos);
}
+static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
+{
+ int64_t pos = avio_tell(pb);
+ 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 */
+ return update_size(pb, pos);
+}
+
static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
@@ -1070,6 +1206,8 @@ static int mov_write_stsd_tag(AVIOContext *pb, MOVTrack *track)
mov_write_subtitle_tag(pb, track);
else if (track->enc->codec_tag == MKTAG('r','t','p',' '))
mov_write_rtp_tag(pb, track);
+ else if (track->enc->codec_tag == MKTAG('t','m','c','d'))
+ mov_write_tmcd_tag(pb, track);
return update_size(pb, pos);
}
@@ -1156,6 +1294,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 */
@@ -1201,9 +1340,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 */
@@ -1214,7 +1376,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)
@@ -1254,12 +1445,24 @@ 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('t','m','c','d')) {
+ hdlr_type = "tmcd";
+ descr = "TimeCodeHandler";
} else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) {
hdlr_type = "hint";
descr = "HintHandler";
+ } else {
+ hdlr = "dhlr";
+ hdlr_type = "url ";
+ descr = "DataHandler";
}
}
@@ -1304,8 +1507,13 @@ 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('t','m','c','d')) {
+ mov_write_gmhd_tag(pb, track);
} else if (track->tag == MKTAG('r','t','p',' ')) {
mov_write_hmhd_tag(pb);
}
@@ -1363,11 +1571,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;
@@ -1375,7 +1602,7 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st)
(version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
ffio_wfourcc(pb, "tkhd");
avio_w8(pb, version);
- avio_wb24(pb, 0xf); /* flags (track enabled) */
+ avio_wb24(pb, track->secondary ? 0x2 : 0xf); /* flags (first track enabled) */
if (version == 1) {
avio_wb64(pb, track->time);
avio_wb64(pb, track->time);
@@ -1402,16 +1629,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)) {
@@ -1450,6 +1680,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);
@@ -1492,6 +1728,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 */
@@ -1564,11 +1804,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);
@@ -1578,7 +1815,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);
@@ -1678,15 +1915,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) */
@@ -1770,6 +1999,24 @@ static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
return mov_write_string_tag(pb, name, t->value, lang, long_style);
}
+/* 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 number */
static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
AVFormatContext *s)
@@ -1792,6 +2039,24 @@ static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
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;
+
+ if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
+ return 0;
+ num = atoi(t->value);
+
+ avio_wb32(pb, len+8);
+ ffio_wfourcc(pb, name);
+ if (len==4) avio_wb32(pb, num);
+ else avio_w8 (pb, num);
+ return len+8;
+}
+
/* iTunes meta data list */
static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
AVFormatContext *s)
@@ -1816,7 +2081,13 @@ 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_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);
+ mov_write_tmpo_tag(pb, s);
return update_size(pb, pos);
}
@@ -1926,32 +2197,35 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
if(ret < 0)
return ret;
- if (mov->mode & MODE_3GP) {
- mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
- mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
- mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
- mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
- mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
- mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
- mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
- mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
- } else if (mov->mode == MODE_MOV) { // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4
- mov_write_string_metadata(s, pb_buf, "\251ART", "artist" , 0);
- mov_write_string_metadata(s, pb_buf, "\251nam", "title" , 0);
- mov_write_string_metadata(s, pb_buf, "\251aut", "author" , 0);
- 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);
- mov_write_string_metadata(s, pb_buf, "\251des", "comment" , 0);
- mov_write_string_metadata(s, pb_buf, "\251gen", "genre" , 0);
- mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright" , 0);
- } else {
- /* iTunes meta data */
- mov_write_meta_tag(pb_buf, mov, s);
- }
+ if (mov->mode & MODE_3GP) {
+ mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
+ mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
+ mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
+ mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
+ mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
+ mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
+ mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
+ mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
+ } else if (mov->mode == MODE_MOV) { // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4
+ mov_write_string_metadata(s, pb_buf, "\251ART", "artist" , 0);
+ mov_write_string_metadata(s, pb_buf, "\251nam", "title" , 0);
+ mov_write_string_metadata(s, pb_buf, "\251aut", "author" , 0);
+ 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 {
+ /* iTunes meta data */
+ mov_write_meta_tag(pb_buf, mov, s);
+ }
- if (s->nb_chapters)
- mov_write_chpl_tag(pb_buf, s);
+ if (s->nb_chapters)
+ mov_write_chpl_tag(pb_buf, s);
if ((size = avio_close_dyn_buf(pb_buf, &buf)) > 0) {
avio_wb32(pb, size+8);
@@ -2013,11 +2287,35 @@ 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)
{
int i;
int64_t pos = avio_tell(pb);
+ int not_first[AVMEDIA_TYPE_NB]={0};
avio_wb32(pb, 0); /* size placeholder*/
ffio_wfourcc(pb, "moov");
@@ -2027,6 +2325,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)
@@ -2041,12 +2342,27 @@ 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)
mov_write_iods_tag(pb, mov);
for (i=0; i<mov->nb_streams; i++) {
if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT) {
+ if(i < s->nb_streams){
+ int codec_type= s->streams[i]->codec->codec_type;
+ if(codec_type==AVMEDIA_TYPE_AUDIO || codec_type==AVMEDIA_TYPE_SUBTITLE){
+ mov->tracks[i].secondary= not_first[codec_type];
+ not_first[codec_type]= 1;
+ }
+ }
mov_write_trak_tag(pb, mov, &(mov->tracks[i]), i < s->nb_streams ? s->streams[i] : NULL);
}
}
@@ -2497,6 +2813,8 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
else if (mov->mode == MODE_ISM)
ffio_wfourcc(pb, "isml");
+ else if (mov->mode == MODE_F4V)
+ ffio_wfourcc(pb, "f4v ");
else
ffio_wfourcc(pb, "qt ");
@@ -2664,6 +2982,21 @@ static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk, int fragment)
}
}
+static int get_moov_size(AVFormatContext *s)
+{
+ int ret;
+ uint8_t *buf;
+ AVIOContext *moov_buf;
+ MOVMuxContext *mov = s->priv_data;
+
+ if ((ret = avio_open_dyn_buf(&moov_buf)) < 0)
+ return ret;
+ mov_write_moov_tag(moov_buf, mov, s);
+ ret = avio_close_dyn_buf(moov_buf, &buf);
+ av_free(buf);
+ return ret;
+}
+
static int mov_flush_fragment(AVFormatContext *s)
{
MOVMuxContext *mov = s->priv_data;
@@ -2675,10 +3008,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)
@@ -2687,13 +3018,9 @@ static int mov_flush_fragment(AVFormatContext *s)
if (i < mov->nb_streams)
return 0;
- if ((ret = avio_open_dyn_buf(&moov_buf)) < 0)
- return ret;
- mov_write_moov_tag(moov_buf, mov, s);
- buf_size = avio_close_dyn_buf(moov_buf, &buf);
- av_free(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);
@@ -2831,6 +3158,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
@@ -2843,6 +3173,14 @@ 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, "malformated aac bitstream, use -absf aac_adtstoasc\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 */
@@ -2868,13 +3206,14 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
}
if (!(trk->entry % MOV_INDEX_CLUSTER_SIZE)) {
- trk->cluster = av_realloc(trk->cluster, (trk->entry + MOV_INDEX_CLUSTER_SIZE) * sizeof(*trk->cluster));
+ trk->cluster = av_realloc_f(trk->cluster, sizeof(*trk->cluster), (trk->entry + MOV_INDEX_CLUSTER_SIZE));
if (!trk->cluster)
return -1;
}
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;
@@ -2885,9 +3224,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");
@@ -2924,12 +3267,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;
@@ -2938,7 +3277,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);
@@ -2953,6 +3292,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);
}
}
@@ -2960,6 +3366,8 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
// as samples, and a tref pointing from the other tracks to the chapter one.
static void 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 };
@@ -2971,6 +3379,50 @@ static void mov_create_chapter_track(AVFormatContext *s, int tracknum)
track->enc = avcodec_alloc_context3(NULL);
track->enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ 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);
+ }
+ }
+
for (i = 0; i < s->nb_chapters; i++) {
AVChapter *c = s->chapters[i];
AVDictionaryEntry *t;
@@ -2991,12 +3443,56 @@ static void mov_create_chapter_track(AVFormatContext *s, int tracknum)
}
}
+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 = {src_st->codec->time_base.den, src_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, src_st->avg_frame_rate.num, src_st->avg_frame_rate.den);
+ rate = src_st->avg_frame_rate;
+ }
+
+ /* 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 = src_st->codec->time_base;
+
+ /* 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;
+}
+
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;
/* Set the FRAGMENT flag if any of the fragmentation methods are
* enabled. */
@@ -3006,6 +3502,18 @@ static int mov_write_header(AVFormatContext *s)
FF_MOV_FLAG_FRAG_CUSTOM))
mov->flags |= FF_MOV_FLAG_FRAGMENT;
+ /* faststart: moov at the beginning of the file, if supported */
+ if (mov->flags & FF_MOV_FLAG_FASTSTART) {
+ if (mov->flags & FF_MOV_FLAG_FRAGMENT)
+ 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
* is enabled, we don't support non-seekable output at all. */
if (!s->pb->seekable &&
@@ -3026,6 +3534,7 @@ static int mov_write_header(AVFormatContext *s)
else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP;
else if (!strcmp("ipod",s->oformat->name)) mov->mode = MODE_IPOD;
else if (!strcmp("ismv",s->oformat->name)) mov->mode = MODE_ISM;
+ else if (!strcmp("f4v", s->oformat->name)) mov->mode = MODE_F4V;
mov_write_ftyp_tag(pb,s);
if (mov->mode == MODE_PSP) {
@@ -3053,6 +3562,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;
+ }
+
mov->tracks = av_mallocz(mov->nb_streams*sizeof(*mov->tracks));
if (!mov->tracks)
return AVERROR(ENOMEM);
@@ -3088,6 +3623,8 @@ static int mov_write_header(AVFormatContext *s)
track->height = track->tag>>24 == 'n' ? 486 : 576;
}
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"
@@ -3095,18 +3632,21 @@ 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;
- }
- /* set audio_vbr for compressed audio */
- if (av_get_bits_per_sample(st->codec->codec_id) < 8) {
+ }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;
}
if (track->mode != MODE_MOV &&
track->enc->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) {
@@ -3116,6 +3656,8 @@ static int mov_write_header(AVFormatContext *s)
}
}else if(st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE){
track->timescale = st->codec->time_base.den;
+ }else{
+ track->timescale = MOV_TIMESCALE;
}
if (!track->height)
track->height = st->codec->height;
@@ -3144,6 +3686,12 @@ static int mov_write_header(AVFormatContext *s)
FF_MOV_FLAG_FRAGMENT;
}
+ 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))
mov_write_mdat_tag(pb, mov);
@@ -3167,6 +3715,24 @@ static int mov_write_header(AVFormatContext *s)
}
}
+ 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)
@@ -3183,14 +3749,122 @@ static int mov_write_header(AVFormatContext *s)
return -1;
}
+/**
+ * This function gets the moov size if moved to the top of the file: the chunk
+ * offset table can switch between stco (32-bit entries) to co64 (64-bit
+ * entries) when the moov is moved to the top, so the size of the moov would
+ * change. It also updates the chunk offset tables.
+ */
+static int compute_moov_size(AVFormatContext *s)
+{
+ int i, moov_size, moov_size2;
+ MOVMuxContext *mov = s->priv_data;
+
+ moov_size = get_moov_size(s);
+ if (moov_size < 0)
+ return moov_size;
+
+ for (i = 0; i < mov->nb_streams; i++)
+ mov->tracks[i].data_offset += moov_size;
+
+ moov_size2 = get_moov_size(s);
+ if (moov_size2 < 0)
+ return moov_size2;
+
+ /* if the size changed, we just switched from stco to co64 and needs to
+ * update the offsets */
+ if (moov_size2 != moov_size)
+ for (i = 0; i < mov->nb_streams; i++)
+ mov->tracks[i].data_offset += moov_size2 - moov_size;
+
+ return moov_size2;
+}
+
+static int shift_data(AVFormatContext *s)
+{
+ int ret = 0, moov_size;
+ MOVMuxContext *mov = s->priv_data;
+ int64_t pos, pos_end = avio_tell(s->pb);
+ uint8_t *buf, *read_buf[2];
+ int read_buf_id = 0;
+ int read_size[2];
+ AVIOContext *read_pb;
+
+ moov_size = compute_moov_size(s);
+ if (moov_size < 0)
+ return moov_size;
+
+ buf = av_malloc(moov_size * 2);
+ if (!buf)
+ return AVERROR(ENOMEM);
+ read_buf[0] = buf;
+ read_buf[1] = buf + moov_size;
+
+ /* Shift the data: the AVIO context of the output can only be used for
+ * writing, so we re-open the same output, but for reading. It also avoids
+ * a read/seek/write/seek back and forth. */
+ avio_flush(s->pb);
+ ret = avio_open(&read_pb, s->filename, AVIO_FLAG_READ);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Unable to re-open %s output file for "
+ "the second pass (faststart)\n", s->filename);
+ goto end;
+ }
+
+ /* mark the end of the shift to up to the last data we wrote, and get ready
+ * for writing */
+ pos_end = avio_tell(s->pb);
+ avio_seek(s->pb, mov->reserved_moov_pos + moov_size, SEEK_SET);
+
+ /* start reading at where the new moov will be placed */
+ avio_seek(read_pb, mov->reserved_moov_pos, SEEK_SET);
+ pos = avio_tell(read_pb);
+
+#define READ_BLOCK do { \
+ read_size[read_buf_id] = avio_read(read_pb, read_buf[read_buf_id], moov_size); \
+ read_buf_id ^= 1; \
+} while (0)
+
+ /* shift data by chunk of at most moov_size */
+ READ_BLOCK;
+ do {
+ int n;
+ READ_BLOCK;
+ n = read_size[read_buf_id];
+ if (n <= 0)
+ break;
+ avio_write(s->pb, read_buf[read_buf_id], n);
+ pos += n;
+ } while (pos < pos_end);
+ avio_close(read_pb);
+
+end:
+ av_free(buf);
+ return ret;
+}
+
static int mov_write_trailer(AVFormatContext *s)
{
MOVMuxContext *mov = s->priv_data;
AVIOContext *pb = s->pb;
+ int64_t moov_pos;
int res = 0;
int i;
- int64_t moov_pos = avio_tell(pb);
+ /*
+ * 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;
+ }
+ }
+
+ moov_pos = avio_tell(pb);
if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
/* Write size of mdat tag */
@@ -3206,9 +3880,31 @@ 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);
-
- mov_write_moov_tag(pb, mov, s);
+ avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_moov_pos : moov_pos, SEEK_SET);
+
+ if (mov->reserved_moov_size == -1) {
+ av_log(s, AV_LOG_INFO, "Starting second pass: moving header on top of the file\n");
+ res = shift_data(s);
+ if (res == 0) {
+ 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);
+ }
} else {
mov_flush_fragment(s);
mov_write_mfra_tag(pb, mov);
@@ -3220,6 +3916,8 @@ static int mov_write_trailer(AVFormatContext *s)
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);
if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
mov->tracks[i].vc1_info.struct_offset && s->pb->seekable) {
int64_t off = avio_tell(pb);
@@ -3256,7 +3954,7 @@ AVOutputFormat ff_mov_muxer = {
.write_header = mov_write_header,
.write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
.codec_tag = (const AVCodecTag* const []){
ff_codec_movvideo_tags, ff_codec_movaudio_tags, 0
},
@@ -3275,7 +3973,7 @@ AVOutputFormat ff_tgp_muxer = {
.write_header = mov_write_header,
.write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
.codec_tag = (const AVCodecTag* const []){ codec_3gp_tags, 0 },
.priv_class = &tgp_muxer_class,
};
@@ -3294,7 +3992,7 @@ AVOutputFormat ff_mp4_muxer = {
.write_header = mov_write_header,
.write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
.codec_tag = (const AVCodecTag* const []){ ff_mp4_obj_type, 0 },
.priv_class = &mp4_muxer_class,
};
@@ -3329,7 +4027,7 @@ AVOutputFormat ff_tg2_muxer = {
.write_header = mov_write_header,
.write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
.codec_tag = (const AVCodecTag* const []){ codec_3gp_tags, 0 },
.priv_class = &tg2_muxer_class,
};
@@ -3370,3 +4068,21 @@ AVOutputFormat ff_ismv_muxer = {
.priv_class = &ismv_muxer_class,
};
#endif
+#if CONFIG_F4V_MUXER
+MOV_CLASS(f4v)
+AVOutputFormat ff_f4v_muxer = {
+ .name = "f4v",
+ .long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
+ .mime_type = "application/f4v",
+ .extensions = "f4v",
+ .priv_data_size = sizeof(MOVMuxContext),
+ .audio_codec = AV_CODEC_ID_AAC,
+ .video_codec = AV_CODEC_ID_H264,
+ .write_header = mov_write_header,
+ .write_packet = mov_write_packet,
+ .write_trailer = mov_write_trailer,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
+ .priv_class = &f4v_muxer_class,
+};
+#endif
diff --git a/libavformat/movenc.h b/libavformat/movenc.h
index e20ef14..a5db895 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
*/
@@ -35,16 +35,18 @@
#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
+#define MODE_F4V 0x80
typedef struct MOVIentry {
uint64_t pos;
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
@@ -79,13 +81,20 @@ typedef struct MOVIndex {
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
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 secondary;
int track_id;
int tag; ///< stsd fourcc
AVCodecContext *enc;
@@ -100,7 +109,7 @@ typedef struct MOVIndex {
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;
@@ -136,6 +145,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;
@@ -143,6 +153,9 @@ typedef struct MOVMuxContext {
int flags;
int rtp_flags;
+ int reserved_moov_size; ///< 0 for disabled, -1 for automatic, size otherwise
+ int64_t reserved_moov_pos;
+
int iods_skip;
int iods_video_profile;
int iods_audio_profile;
@@ -153,6 +166,8 @@ typedef struct MOVMuxContext {
int max_fragment_size;
int ism_lookahead;
AVIOContext *mdat_buf;
+
+ int use_editlist;
} MOVMuxContext;
#define FF_MOV_FLAG_RTP_HINT 1
@@ -162,6 +177,7 @@ typedef struct MOVMuxContext {
#define FF_MOV_FLAG_SEPARATE_MOOF 16
#define FF_MOV_FLAG_FRAG_CUSTOM 32
#define FF_MOV_FLAG_ISML 64
+#define FF_MOV_FLAG_FASTSTART 128
int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt);
diff --git a/libavformat/movenchint.c b/libavformat/movenchint.c
index 02391b5..cc90f0b 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
*/
diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c
index 14edc4a..644ffe4 100644
--- a/libavformat/mp3dec.c
+++ b/libavformat/mp3dec.c
@@ -2,20 +2,20 @@
* 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
*/
@@ -35,8 +35,11 @@
#define XING_TOC_COUNT 100
-typedef struct MP3DecContext {
+typedef struct {
+ int64_t filesize;
int xing_toc;
+ int start_pad;
+ int end_pad;
} MP3DecContext;
/* mp3 read */
@@ -46,7 +49,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 +76,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 AVPROBE_SCORE_EXTENSION / 4;
+ else if(max_frames>=1) return 1;
+ else return 0;
//mpegps_mp3_unrecognized_format.mpg has max_frames=3
}
@@ -128,6 +113,7 @@ 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 */
@@ -160,6 +146,18 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base)
if (v & XING_FLAG_TOC && frames)
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) */
@@ -192,6 +190,7 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base)
static int mp3_read_header(AVFormatContext *s)
{
+ MP3DecContext *mp3 = s->priv_data;
AVStream *st;
int64_t off;
@@ -201,17 +200,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 +226,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,6 +255,21 @@ 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)
{
@@ -248,10 +277,13 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
AVIndexEntry *ie;
AVStream *st = s->streams[0];
int64_t ret = av_index_search_timestamp(st, timestamp, flags);
- uint32_t header = 0;
+ int i, j;
- if (!mp3->xing_toc)
- return AVERROR(ENOSYS);
+ if (!mp3->xing_toc) {
+ st->skip_samples = timestamp <= 0 ? mp3->start_pad + 528 + 1 : 0;
+
+ return -1;
+ }
if (ret < 0)
return ret;
@@ -261,16 +293,27 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
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;
+ 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, 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;
}
AVInputFormat ff_mp3_demuxer = {
diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c
index 4d7c798..ee0956e 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
*/
@@ -30,6 +30,10 @@
#include "libavcodec/mpegaudiodecheader.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/opt.h"
+#include "libavcodec/mpegaudio.h"
+#include "libavcodec/mpegaudiodata.h"
+#include "libavcodec/mpegaudiodecheader.h"
+#include "libavformat/avio_internal.h"
#include "libavutil/dict.h"
#include "libavutil/avassert.h"
@@ -51,11 +55,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 +115,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 +144,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 +153,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));
+
+ 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);
- mpah.frame_size -= 4 + xing_offset + 4 + 4 + 4 + 4 + XING_TOC_SIZE;
- ffio_fill(s->pb, 0, mpah.frame_size);
+ ffio_fill(s->pb, 0, c.frame_size - needed);
+
+ return 0;
}
/*
@@ -201,7 +243,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 +259,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 +369,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 +515,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..b0f6f53 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
*/
@@ -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 c3c70e0..73b7eb7 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)
@@ -139,12 +139,21 @@ static void mpc8_parse_seektable(AVFormatContext *s, int64_t off)
int i, t, seekd;
GetBitContext gb;
+ if (s->nb_streams<=0) {
+ av_log(s, AV_LOG_ERROR, "cannot parse stream table before stream header\n");
+ return;
+ }
+
avio_seek(s->pb, off, SEEK_SET);
mpc8_get_chunk_header(s->pb, &tag, &size);
if(tag != TAG_SEEKTABLE){
av_log(s, AV_LOG_ERROR, "No seek table at given position\n");
return;
}
+ if (size > INT_MAX/10 || size<=0) {
+ av_log(s, AV_LOG_ERROR, "Seek table size is invalid\n");
+ return;
+ }
if(!(buf = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE)))
return;
avio_read(s->pb, buf, size);
@@ -204,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)
@@ -242,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);
@@ -258,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 8a4c6d7..5d5b09f 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;
+#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,8 +532,12 @@ static int mpegps_read_packet(AVFormatContext *s,
codec_id = AV_CODEC_ID_DTS;
} else if (startcode >= 0xa0 && startcode <= 0xaf) {
type = AVMEDIA_TYPE_AUDIO;
- /* 16 bit form will be handled as AV_CODEC_ID_PCM_S16BE */
- codec_id = AV_CODEC_ID_PCM_DVD;
+ if(lpcm_header_len == 6) {
+ codec_id = AV_CODEC_ID_MLP;
+ } else {
+ /* 16 bit form will be handled as AV_CODEC_ID_PCM_S16BE */
+ codec_id = AV_CODEC_ID_PCM_DVD;
+ }
} else if (startcode >= 0xb0 && startcode <= 0xbf) {
type = AVMEDIA_TYPE_AUDIO;
codec_id = AV_CODEC_ID_TRUEHD;
@@ -468,19 +551,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 */
@@ -494,13 +564,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;
if (codec_id != AV_CODEC_ID_PCM_S16BE)
st->need_parsing = AVSTREAM_PARSE_FULL;
found:
if(st->discard >= AVDISCARD_ALL)
goto skip;
- if ((startcode >= 0xa0 && startcode <= 0xaf) ||
- (startcode == 0x1bd && ((dvdaudio_substream_type & 0xe0) == 0xa0))) {
+ 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;
+ } else {
int b1, freq;
/* for LPCM, we just skip the header and consider it is raw
@@ -522,6 +603,7 @@ static int mpegps_read_packet(AVFormatContext *s,
st->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
else if (st->codec->bits_per_coded_sample == 28)
return AVERROR(EINVAL);
+ }
}
ret = av_get_packet(s->pb, pkt, len);
pkt->pts = pts;
@@ -573,3 +655,263 @@ 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;
+ }
+
+ 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;
+ 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 (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, "", 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;
+
+ ff_subtitles_queue_finalize(&vobsub->q);
+
+ 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 = &vobsub->q;
+ AVIOContext *pb = vobsub->sub_ctx->pb;
+ int ret, psize, len16 = -1;
+ AVPacket idx_pkt;
+
+ 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;
+
+ ret = mpegps_read_pes_header(vobsub->sub_ctx, NULL, &startcode, &pts, &dts);
+ if (ret < 0)
+ FAIL(ret);
+ to_read = ret & 0xffff;
+
+ /* this prevents reads above the current packet */
+ if (pkt->size + to_read > psize)
+ break;
+
+ /* if the len is computed, we check for overread */
+ if (len16 != -1 && pkt->size + to_read > len16)
+ break;
+
+ /* 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;
+
+ /* first chunk contains the total len of the packet to raise */
+ if (len16 == -1 && n > 2)
+ len16 = AV_RB16(pkt->data);
+ } while (len16 != -1 && pkt->size != len16);
+
+ 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(&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;
+ return ff_subtitles_queue_seek(&vobsub->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int vobsub_read_close(AVFormatContext *s)
+{
+ MpegDemuxContext *vobsub = s->priv_data;
+ ff_subtitles_queue_clean(&vobsub->q);
+ 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..a1e8980 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
*/
diff --git a/libavformat/mpegenc.c b/libavformat/mpegenc.c
index 85a12d6..6f6da5c 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;
@@ -416,7 +417,9 @@ 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;
@@ -480,7 +483,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 +841,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=
@@ -935,7 +938,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,
@@ -1059,13 +1062,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 +1145,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, INT_MAX, 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 1540a8d..85b5146 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 "avformat.h"
@@ -123,9 +124,11 @@ 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[] = {
@@ -180,10 +183,25 @@ typedef struct 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;
@@ -226,6 +244,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
@@ -266,6 +295,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;
@@ -293,10 +323,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);
}
}
@@ -386,7 +425,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];
@@ -521,7 +560,11 @@ static const StreamType ISO_types[] = {
{ 0x04, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 },
{ 0x0f, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC },
{ 0x10, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG4 },
+ /* Makito encoder sets stream type 0x11 for AAC,
+ * so auto-detect LOAS/LATM instead of hardcoding it. */
+#if !CONFIG_LOAS_DEMUXER
{ 0x11, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC_LATM }, /* LATM syntax */
+#endif
{ 0x1b, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 },
{ 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS },
{ 0xd1, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC },
@@ -537,6 +580,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 },
};
@@ -555,6 +600,7 @@ 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('K','L','V','A'), AVMEDIA_TYPE_DATA, AV_CODEC_ID_SMPTE_KLV },
{ MKTAG('V','C','-','1'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 },
{ 0 },
};
@@ -572,10 +618,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;
}
}
@@ -584,6 +636,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;
@@ -599,7 +659,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) {
@@ -629,6 +690,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;
}
@@ -667,6 +732,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;
@@ -674,6 +746,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)
@@ -712,9 +785,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)
@@ -805,10 +878,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;
@@ -1278,15 +1351,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 */
@@ -1348,6 +1423,9 @@ 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;
default:
break;
}
@@ -1390,6 +1468,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);
@@ -1426,7 +1505,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;
@@ -1438,12 +1517,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;
@@ -1452,6 +1535,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 {
@@ -1460,6 +1545,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;
}
@@ -1506,6 +1593,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);
@@ -1517,6 +1605,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);
@@ -1527,12 +1617,17 @@ 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);
+ program = av_new_program(ts->stream, sid);
+ program->program_num = sid;
+ program->pmt_pid = pmt_pid;
if (ts->pids[pmt_pid])
mpegts_close_filter(ts, ts->pids[pmt_pid]);
mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1);
@@ -1541,6 +1636,17 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
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)
@@ -1641,6 +1747,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 */
@@ -1661,7 +1768,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) {
@@ -1730,7 +1837,7 @@ 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);
@@ -1773,7 +1880,7 @@ static int read_packet(AVFormatContext *s, uint8_t *buf, 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];
int packet_num, ret = 0;
if (avio_tell(s->pb) != ts->last_pos) {
@@ -1797,11 +1904,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);
if (ret != 0)
break;
@@ -1816,24 +1927,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
@@ -1869,18 +1990,18 @@ 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 */
+ /* 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;
@@ -1888,8 +2009,11 @@ 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");
+ /* 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");
mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
@@ -2013,6 +2137,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) {
@@ -2049,66 +2174,65 @@ 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)
+ 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) {
+ 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;
+ pos = ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->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){
+ *ppos= pkt.pos;
+ return pkt.dts;
+ }
+ }
+ pos = pkt.pos;
}
- avio_seek(s->pb, pos, SEEK_SET);
- return 0;
+ return AV_NOPTS_VALUE;
}
/**************************************************************/
@@ -2125,6 +2249,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;
}
@@ -2137,10 +2264,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) {
@@ -2150,6 +2275,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;
@@ -2169,8 +2296,7 @@ AVInputFormat ff_mpegts_demuxer = {
.read_header = mpegts_read_header,
.read_packet = mpegts_read_packet,
.read_close = mpegts_read_close,
- .read_seek = read_seek,
- .read_timestamp = mpegts_get_pcr,
+ .read_timestamp = mpegts_get_dts,
.flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT,
};
@@ -2181,8 +2307,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..0ddae65 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,14 @@ 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;
} MpegTSWrite;
/* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */
@@ -96,9 +99,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 +119,8 @@ 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", "dont offset dts/pts",
+ offsetof(MpegTSWrite, copyts), AV_OPT_TYPE_INT, {.i64=-1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
{ NULL },
};
@@ -191,7 +199,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 +217,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 +231,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;
@@ -311,6 +320,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;
@@ -458,9 +481,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 +643,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 +663,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 +681,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 +712,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 +721,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 +730,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 +756,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 +782,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 +804,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 +820,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 +850,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 +925,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 +958,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++;
@@ -935,6 +1001,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 +1047,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 +1062,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 +1077,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 +1095,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 +1123,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 +1132,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 +1155,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 +1260,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 6c8bd0c..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,13 +38,15 @@ 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));
- avio_flush(s->pb);
return 0;
}
diff --git a/libavformat/mpl2dec.c b/libavformat/mpl2dec.c
new file mode 100644
index 0000000..b152cc8
--- /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 += strcspn(ptr, "\r\n") + 1;
+ 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..6a0cefb
--- /dev/null
+++ b/libavformat/mpsubdec.c
@@ -0,0 +1,139 @@
+/*
+ * 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) {
+ if (!memcmp(ptr, "FORMAT=TIME", 11))
+ return AVPROBE_SCORE_EXTENSION;
+ if (!memcmp(ptr, "FORMAT=", 7))
+ return AVPROBE_SCORE_EXTENSION / 3;
+ ptr += strcspn(ptr, "\n") + 1;
+ }
+ 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..2b85a20 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
*/
@@ -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){
+ av_log(s, AV_LOG_ERROR, "width or height 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 b51f906..9de8e69 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"
@@ -47,7 +48,7 @@
/**
* @file
- * muxing functions for use within Libav
+ * muxing functions for use within libavformat
*/
/* fraction handling */
@@ -100,6 +101,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;
@@ -147,6 +230,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)) {
@@ -184,9 +270,9 @@ 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)
+ ) {
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,
@@ -199,21 +285,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], cortag[32];
av_get_codec_tag_string(tagbuf, sizeof(tagbuf), codec->codec_tag);
+ av_get_codec_tag_string(cortag, sizeof(cortag), 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, cortag);
ret = AVERROR_INVALIDDATA;
goto fail;
}
@@ -299,6 +387,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;
}
@@ -306,20 +396,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) {
@@ -334,6 +428,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;
@@ -354,17 +453,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;
@@ -389,32 +489,51 @@ 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)
{
- 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);
}
- return s->oformat->write_packet(s, pkt);
+
+ did_split = av_packet_split_side_data(pkt);
+ ret = s->oformat->write_packet(s, pkt);
+ if (s->flush_packets && s->pb && s->pb->error >= 0)
+ avio_flush(s->pb);
+ if (did_split)
+ av_packet_merge_side_data(pkt);
+ return ret;
}
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
@@ -422,8 +541,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;
}
@@ -433,40 +558,72 @@ 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
pkt->destruct = NULL; // do not free original but only the copy
#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
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:
@@ -475,6 +632,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,
@@ -484,6 +642,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;
@@ -494,27 +662,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);
@@ -553,8 +753,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;
@@ -580,6 +780,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;
}
}
@@ -603,15 +805,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);
@@ -621,3 +826,12 @@ fail:
av_freep(&s->priv_data);
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;
+}
diff --git a/libavformat/mvdec.c b/libavformat/mvdec.c
new file mode 100644
index 0000000..5525233
--- /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 7fb163b..953c182 100644
--- a/libavformat/mvi.c
+++ b/libavformat/mvi.c
@@ -2,20 +2,20 @@
* Motion Pixels MVI Demuxer
* Copyright (c) 2008 Gregory Montoir (cyx@users.sourceforge.net)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -54,6 +54,8 @@ static int read_header(AVFormatContext *s)
vst->codec->extradata_size = 2;
vst->codec->extradata = av_mallocz(2 + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!vst->codec->extradata)
+ return AVERROR(ENOMEM);
version = avio_r8(pb);
vst->codec->extradata[0] = avio_r8(pb);
@@ -94,6 +96,10 @@ static int read_header(AVFormatContext *s)
mvi->get_int = (vst->codec->width * vst->codec->height < (1 << 16)) ? avio_rl16 : avio_rl24;
mvi->audio_frame_size = ((uint64_t)mvi->audio_data_size << MVI_FRAC_BITS) / frames_count;
+ if (!mvi->audio_frame_size) {
+ av_log(s, AV_LOG_ERROR, "audio_frame_size is 0\n");
+ return AVERROR_INVALIDDATA;
+ }
mvi->audio_size_counter = (ast->codec->sample_rate * 830 / mvi->audio_frame_size - 1) * mvi->audio_frame_size;
mvi->audio_size_left = mvi->audio_data_size;
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 d2039f6..e59bcfc 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;
@@ -228,6 +242,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 };
@@ -260,7 +276,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 +326,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 +413,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;
}
@@ -506,7 +524,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:
@@ -517,10 +535,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
@@ -533,7 +549,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;
@@ -574,9 +590,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 */
@@ -614,9 +628,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 */
@@ -626,6 +638,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;
@@ -659,9 +688,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 */
@@ -677,9 +704,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 */
@@ -702,29 +727,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);
@@ -776,17 +785,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);
@@ -799,9 +809,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 */
@@ -829,6 +837,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;
@@ -857,7 +868,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;
@@ -950,9 +965,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);
@@ -967,19 +981,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;
}
}
@@ -1120,14 +1138,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);
}
@@ -1232,9 +1244,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;
@@ -1253,12 +1263,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;
}
@@ -1302,12 +1308,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)
@@ -1334,25 +1348,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;
@@ -1410,12 +1447,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;
@@ -1460,51 +1506,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 */
@@ -1519,13 +1565,24 @@ 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;
- if (descriptor->sample_rate.den > 0)
+ if (descriptor->sample_rate.den > 0) {
+ avpriv_set_pts_info(st, 64, descriptor->sample_rate.den, descriptor->sample_rate.num);
st->codec->sample_rate = descriptor->sample_rate.num / descriptor->sample_rate.den;
+ } else {
+ av_log(mxf->fc, AV_LOG_WARNING, "invalid sample rate (%d/%d) found for stream #%d, time base forced to 1/48000\n",
+ descriptor->sample_rate.num, descriptor->sample_rate.den, st->index);
+ 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) {
@@ -1542,6 +1599,13 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
st->need_parsing = AVSTREAM_PARSE_FULL;
}
}
+ if (descriptor->extradata) {
+ st->codec->extradata = av_mallocz(descriptor->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (st->codec->extradata)
+ 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;
@@ -1553,6 +1617,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 },
@@ -1565,6 +1747,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 },
@@ -1579,6 +1762,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 },
@@ -1592,7 +1776,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 */
@@ -1623,6 +1807,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);
@@ -1706,8 +1893,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)
{
@@ -1747,38 +1933,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 */
@@ -1833,7 +1987,7 @@ static int mxf_read_header(AVFormatContext *s)
mxf->fc = s;
mxf->run_in = avio_tell(s->pb);
- while (!s->pb->eof_reached) {
+ while (!url_feof(s->pb)) {
const MXFMetadataReadTableEntry *metadata;
if (klv_read_packet(&klv, s->pb) < 0) {
@@ -1852,13 +2006,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)
@@ -1918,10 +2091,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 */
@@ -1929,12 +2102,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;
}
/**
@@ -1951,11 +2129,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) {
@@ -1973,29 +2149,74 @@ 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)
+ 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;
}
@@ -2005,6 +2226,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));
@@ -2021,9 +2243,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 "
@@ -2036,31 +2257,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 */
@@ -2071,7 +2294,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)
@@ -2115,22 +2338,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;
@@ -2144,6 +2371,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;
@@ -2170,10 +2400,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);
@@ -2181,8 +2413,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;
@@ -2204,8 +2436,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)
@@ -2214,9 +2452,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];
@@ -2231,7 +2470,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)
@@ -2241,6 +2480,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 a4403d5..367b6e4 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,17 @@
#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 "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,6 +70,8 @@ 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
@@ -87,6 +91,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 +169,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 +271,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 +285,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 +380,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 +528,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 +556,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 +585,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 +608,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 +773,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 +781,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 +829,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 +893,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 +920,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 +932,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 +959,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)
@@ -1053,8 +1171,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
@@ -1178,7 +1296,7 @@ static void mxf_write_klv_fill(AVFormatContext *s)
klv_encode_ber4_length(s->pb, pad);
for (; pad; pad--)
avio_w8(s->pb, 0);
- assert(!(avio_tell(s->pb) & (KAG_SIZE-1)));
+ av_assert1(!(avio_tell(s->pb) & (KAG_SIZE-1)));
}
}
@@ -1214,7 +1332,7 @@ static void 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
@@ -1275,6 +1393,154 @@ static void mxf_write_partition(AVFormatContext *s, int bodysid,
avio_flush(pb);
}
+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
@@ -1312,7 +1578,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;
@@ -1324,6 +1589,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
@@ -1332,21 +1599,6 @@ static int mxf_parse_mpeg2_frame(AVFormatContext *s, AVStream *st,
if (e->flags & 0x40) // sequence header present
e->flags |= 0x80; // random access
}
- if (!mxf->header_written) {
- unsigned hours = (pkt->data[i+1]>>2) & 0x1f;
- unsigned minutes = ((pkt->data[i+1] & 0x03) << 4) | (pkt->data[i+2]>>4);
- unsigned seconds = ((pkt->data[i+2] & 0x07) << 3) | (pkt->data[i+3]>>5);
- unsigned frames = ((pkt->data[i+3] & 0x1f) << 1) | (pkt->data[i+4]>>7);
- mxf->timecode_drop_frame = !!(pkt->data[i+1] & 0x80);
- mxf->timecode_start = (hours*3600 + minutes*60 + seconds) *
- mxf->timecode_base + frames;
- if (mxf->timecode_drop_frame) {
- unsigned tminutes = 60 * hours + minutes;
- mxf->timecode_start -= 2 * (tminutes - tminutes / 10);
- }
- av_log(s, AV_LOG_DEBUG, "frame %d %d:%d:%d%c%d\n", mxf->timecode_start,
- hours, minutes, seconds, mxf->timecode_drop_frame ? ';':':', frames);
- }
} else if (c == 0x1b3) { // seq
e->flags |= 0x40;
switch ((pkt->data[i+4]>>4) & 0xf) {
@@ -1408,11 +1660,12 @@ static void mxf_gen_umid(AVFormatContext *s)
static int mxf_write_header(AVFormatContext *s)
{
MXFContext *mxf = s->priv_data;
- int i;
+ int i, ret;
uint8_t present[FF_ARRAY_ELEMS(mxf_essence_container_uls)] = {0};
- const int *samples_per_frame = NULL;
+ const MXFSamplesPerFrame *spf = NULL;
AVDictionaryEntry *t;
int64_t timestamp = 0;
+ AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
if (!s->nb_streams)
return -1;
@@ -1424,35 +1677,44 @@ 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;
if (s->oformat == &ff_mxf_d10_muxer) {
- if (st->codec->bit_rate == 50000000)
+ if (st->codec->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 (st->codec->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 (st->codec->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;
}
@@ -1461,7 +1723,7 @@ static int mxf_write_header(AVFormatContext *s)
mxf->edit_unit_byte_count += 16 + 4 + (uint64_t)st->codec->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) {
@@ -1515,7 +1777,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))
@@ -1532,10 +1797,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;
@@ -1544,24 +1809,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;
@@ -1569,7 +1816,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);
@@ -1578,7 +1825,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 {
@@ -1590,8 +1837,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);
@@ -1626,7 +1872,7 @@ static void mxf_write_d10_video_packet(AVFormatContext *s, AVStream *st, AVPacke
klv_encode_ber4_length(s->pb, pad);
for (; pad; pad--)
avio_w8(s->pb, 0);
- assert(!(avio_tell(s->pb) & (KAG_SIZE-1)));
+ 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--)
@@ -1688,6 +1934,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) {
@@ -1753,7 +2009,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 ea54fe2..604be78 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
*/
@@ -101,17 +101,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;
@@ -133,7 +135,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 1f6bc10..ceed719 100644
--- a/libavformat/network.c
+++ b/libavformat/network.c
@@ -18,13 +18,18 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/avutil.h"
#include "network.h"
#include "libavcodec/internal.h"
#include "libavutil/mem.h"
+#include "url.h"
+#include "libavutil/time.h"
#if HAVE_THREADS
#if HAVE_PTHREADS
#include <pthread.h>
+#elif HAVE_OS2THREADS
+#include "libavcodec/os2threads.h"
#else
#include "libavcodec/w32pthreads.h"
#endif
@@ -145,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) {
+ ret = ff_network_wait_fd(fd, write);
+ if (ret != AVERROR(EAGAIN))
+ return ret;
+ if (ff_check_interrupt(int_cb))
+ return AVERROR_EXIT;
+ if (timeout) {
+ 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
diff --git a/libavformat/network.h b/libavformat/network.h
index 5160767..f8b4dee 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"
#if HAVE_UNISTD_H
#include <unistd.h>
@@ -81,6 +82,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 after 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
--- /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 59a435e..a156620 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 ffe43cf..21300a3 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"
//#define DEBUG_DUMP_INDEX // XXX dumbdriving-271.nsv breaks with it commented!!
#define CHECK_SUBSEQUENT_NSVS
@@ -73,11 +74,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
*/
/*
@@ -103,8 +100,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;
};
@@ -196,6 +193,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') },
@@ -209,6 +207,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 },
@@ -237,7 +236,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;
@@ -304,7 +303,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));
@@ -341,7 +340,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));
@@ -392,7 +391,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;
@@ -574,7 +573,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++)
@@ -609,7 +608,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;
@@ -654,7 +653,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 */
@@ -759,10 +761,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 */
@@ -774,19 +774,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 e8dbc54..32035d5 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') },
@@ -124,35 +147,43 @@ const AVCodecTag ff_nut_video_tags[] = {
{ 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_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)
@@ -168,7 +199,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;
}
@@ -188,6 +219,8 @@ void ff_nut_add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts)
Syncpoint *sp = av_mallocz(sizeof(Syncpoint));
struct AVTreeNode *node = av_tree_node_alloc();
+ 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 6eddc96..dc5af15 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 cc5869e..30bdefd9 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;
@@ -297,7 +310,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 +330,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)) {
@@ -514,6 +527,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 +552,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;
nut->last_syncpoint_pos = avio_tell(bc) - 8;
@@ -541,7 +563,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);
@@ -551,13 +573,32 @@ 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;
ff_nut_add_sp(nut, nut->last_syncpoint_pos, *back_ptr, *ts);
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;
+
+ int64_t pos = FFMAX(0, filesize - 2*nut->max_distance);
+ for(;;){
+ int64_t ts = nut_read_timestamp(s, -1, &pos, INT64_MAX);
+ if(ts < 0)
+ break;
+ duration = FFMAX(duration, ts);
+ pos++;
+ }
+ 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;
@@ -566,20 +607,32 @@ 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));
@@ -602,7 +655,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--)
@@ -622,7 +675,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);
@@ -709,7 +762,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);
@@ -754,7 +807,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)
@@ -819,7 +872,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);
@@ -848,7 +902,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;
@@ -902,21 +956,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,
@@ -933,6 +984,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;
@@ -965,7 +1018,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);
@@ -997,6 +1050,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 7234cd9..1947e32 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_mallocz(sizeof(StreamContext ) * s->nb_streams);
+ 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 || !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.
@@ -816,8 +859,19 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE);
ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts);
+
+ if ((1ll<<60) % nut->sp_count == 0)
+ for (i=0; i<s->nb_streams; i++) {
+ int j;
+ StreamContext *nus = &nut->stream[i];
+ nus->keyframe_pts = av_realloc(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)
@@ -861,9 +915,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;
}
@@ -882,7 +935,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);
@@ -894,27 +947,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,
@@ -922,6 +968,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;
}
@@ -929,12 +983,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..fc9e916 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);
@@ -195,6 +195,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 +239,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 +265,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 +305,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 +387,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 d8f89b8..fd954b8 100644
--- a/libavformat/oggdec.c
+++ b/libavformat/oggdec.c
@@ -28,8 +28,8 @@
DEALINGS IN THE SOFTWARE.
*/
-
#include <stdio.h>
+#include "libavutil/avassert.h"
#include "oggdec.h"
#include "avformat.h"
#include "internal.h"
@@ -46,6 +46,7 @@ static const struct ogg_codec * const ogg_codecs[] = {
&ff_theora_codec,
&ff_flac_codec,
&ff_celt_codec,
+ &ff_opus_codec,
&ff_old_dirac_codec,
&ff_old_flac_codec,
&ff_ogm_video_codec,
@@ -55,6 +56,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)
{
@@ -98,6 +102,7 @@ static int ogg_restore(AVFormatContext *s, int discard)
av_free(ogg->streams[i].buf);
avio_seek(bc, ost->pos, SEEK_SET);
+ ogg->page_pos = -1;
ogg->curidx = ost->curidx;
ogg->nstreams = ost->nstreams;
ogg->streams = av_realloc(ogg->streams,
@@ -117,9 +122,11 @@ static int ogg_restore(AVFormatContext *s, int discard)
return 0;
}
-static int ogg_reset(struct ogg *ogg)
+static int ogg_reset(AVFormatContext *s)
{
+ struct ogg *ogg = s->priv_data;
int i;
+ int64_t start_pos = avio_tell(s->pb);
for (i = 0; i < ogg->nstreams; i++) {
struct ogg_stream *os = ogg->streams + i;
@@ -134,8 +141,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;
@@ -153,38 +165,105 @@ static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
return NULL;
}
-static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
+/**
+ * Replace the current stream with a new one. This is a typical webradio
+ * situation where a new audio stream spawn (identified with a new serial) and
+ * must replace the previous one (track switch).
+ */
+static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
{
struct ogg *ogg = s->priv_data;
- int idx = ogg->nstreams++;
- AVStream *st;
struct ogg_stream *os;
+ const struct ogg_codec *codec;
+ int i = 0;
+
+ if (s->pb->seekable) {
+ uint8_t magic[8];
+ int64_t pos = avio_tell(s->pb);
+ avio_skip(s->pb, nsegs);
+ avio_read(s->pb, magic, sizeof(magic));
+ avio_seek(s->pb, pos, SEEK_SET);
+ codec = ogg_find_codec(magic, sizeof(magic));
+ if (!codec) {
+ av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (i = 0; i < ogg->nstreams; i++) {
+ if (ogg->streams[i].codec == codec)
+ break;
+ }
+ if (i >= ogg->nstreams)
+ return ogg_new_stream(s, serial);
+ } else if (ogg->nstreams != 1) {
+ avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
+ return AVERROR_PATCHWELCOME;
+ }
- os = av_realloc(ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
+ os = &ogg->streams[i];
- if (!os)
- return AVERROR(ENOMEM);
+ os->serial = serial;
+ return i;
- ogg->streams = os;
+#if 0
+ buf = os->buf;
+ bufsize = os->bufsize;
+ codec = os->codec;
+
+ if (!ogg->state || ogg->state->streams[i].private != os->private)
+ av_freep(&ogg->streams[i].private);
- memset(ogg->streams + idx, 0, sizeof(*ogg->streams));
+ /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We
+ * also re-use the ogg_stream allocated buffer */
+ memset(os, 0, sizeof(*os));
+ os->serial = serial;
+ os->bufsize = bufsize;
+ os->buf = buf;
+ os->header = -1;
+ os->codec = codec;
- os = ogg->streams + idx;
+ return i;
+#endif
+}
+
+static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
+{
+ struct ogg *ogg = s->priv_data;
+ int idx = ogg->nstreams;
+ AVStream *st;
+ struct ogg_stream *os;
+ size_t size;
+
+ if (ogg->state) {
+ av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
+ "in between Ogg context save/restore operations.\n");
+ return AVERROR_BUG;
+ }
+
+ /* Allocate and init a new Ogg Stream */
+ if (av_size_mult(ogg->nstreams + 1, sizeof(*ogg->streams), &size) < 0 ||
+ !(os = av_realloc(ogg->streams, size)))
+ return AVERROR(ENOMEM);
+ ogg->streams = os;
+ os = ogg->streams + idx;
+ memset(os, 0, sizeof(*os));
os->serial = serial;
os->bufsize = DECODER_BUFFER_SIZE;
os->buf = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
os->header = -1;
os->start_granule = OGG_NOGRANULE_VALUE;
+ if (!os->buf)
+ return AVERROR(ENOMEM);
- if (new_avstream) {
- st = avformat_new_stream(s, NULL);
- if (!st)
- return AVERROR(ENOMEM);
-
- st->id = idx;
- avpriv_set_pts_info(st, 64, 1, 1000000);
+ /* Create the associated AVStream */
+ st = avformat_new_stream(s, NULL);
+ if (!st) {
+ av_freep(&os->buf);
+ return AVERROR(ENOMEM);
}
+ st->id = idx;
+ avpriv_set_pts_info(st, 64, 1, 1000000);
+ ogg->nstreams++;
return idx;
}
@@ -206,7 +285,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;
@@ -231,9 +320,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;
@@ -244,8 +339,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);
@@ -255,28 +352,19 @@ static int ogg_read_page(AVFormatContext *s, int *str)
idx = ogg_find_stream(ogg, serial);
if (idx < 0) {
- if (ogg->headers) {
- int n;
-
- for (n = 0; n < ogg->nstreams; n++) {
- av_freep(&ogg->streams[n].buf);
- if (!ogg->state ||
- ogg->state->streams[n].private != ogg->streams[n].private)
- av_freep(&ogg->streams[n].private);
- }
+ if (data_packets_seen(ogg))
+ idx = ogg_replace_stream(s, serial, nsegs);
+ else
+ idx = ogg_new_stream(s, serial);
- ogg->curidx = -1;
- ogg->nstreams = 0;
-
- idx = ogg_new_stream(s, serial, 0);
- } else {
- idx = ogg_new_stream(s, serial, 1);
- }
- if (idx < 0)
+ if (idx < 0) {
+ av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
return idx;
+ }
}
os = ogg->streams + idx;
+ ogg->page_pos =
os->page_pos = avio_tell(bc) - 27;
if (os->psize > 0)
@@ -293,8 +381,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;
@@ -326,13 +420,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;
@@ -342,6 +443,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;
@@ -384,12 +487,14 @@ static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
if (!complete && os->segp == os->nsegs) {
ogg->curidx = -1;
- os->incomplete = 1;
+ // Do not set incomplete for empty packets.
+ // Together with the code in ogg_read_page
+ // that discards all continuation of empty packets
+ // we would get an infinite loop.
+ os->incomplete = !!os->psize;
}
} 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,
@@ -433,8 +538,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)
@@ -443,6 +548,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;
}
@@ -461,40 +568,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\n", i);
- 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;
@@ -510,19 +589,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;
}
@@ -547,22 +651,36 @@ 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, "Number of headers (%d) mismatch for stream %d\n", os->nb_header, i);
+ }
+ 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;
}
@@ -596,14 +714,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 {
@@ -617,6 +753,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;
@@ -644,22 +781,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;
}
@@ -670,6 +818,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
@@ -701,5 +854,5 @@ AVInputFormat ff_ogg_demuxer = {
.read_seek = ogg_read_seek,
.read_timestamp = ogg_read_timestamp,
.extensions = "ogg",
- .flags = AVFMT_GENERIC_INDEX,
+ .flags = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT,
};
diff --git a/libavformat/oggdec.h b/libavformat/oggdec.h
index d11ff9f..e9a300d 100644
--- a/libavformat/oggdec.h
+++ b/libavformat/oggdec.h
@@ -81,6 +81,8 @@ 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
void *private;
};
@@ -98,6 +100,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 +108,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;
@@ -116,6 +119,7 @@ extern const struct ogg_codec ff_ogm_text_codec;
extern const struct ogg_codec ff_ogm_video_codec;
extern const struct ogg_codec ff_old_dirac_codec;
extern const struct ogg_codec ff_old_flac_codec;
+extern const struct ogg_codec ff_opus_codec;
extern const struct ogg_codec ff_skeleton_codec;
extern const struct ogg_codec ff_speex_codec;
extern const struct ogg_codec ff_theora_codec;
diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c
index e01c365..1255364 100644
--- a/libavformat/oggenc.c
+++ b/libavformat/oggenc.c
@@ -2,24 +2,25 @@
* 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
*/
#include "libavutil/crc.h"
+#include "libavutil/opt.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libavutil/random_seed.h"
@@ -75,10 +76,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 +140,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 +215,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 +281,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 +402,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 +412,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 &&
@@ -508,7 +521,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 +613,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..afc4392 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
*/
@@ -62,18 +62,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;
+ av_free(st->codec->extradata);
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);
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..3ff594e 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
*/
diff --git a/libavformat/oggparseogm.c b/libavformat/oggparseogm.c
index 7b3cda2..a3caac0 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)
const uint8_t *p = os->buf + os->pstart;
uint64_t time_unit;
uint64_t spu;
+ uint32_t size;
if(!(*p & 1))
return 0;
@@ -67,11 +69,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;
}
- p += 4; /* useless size field */
-
+ size = bytestream_get_le32(&p);
+ size = FFMIN(size, os->psize);
time_unit = bytestream_get_le64(&p);
spu = bytestream_get_le64(&p);
p += 4; /* default_len */
@@ -85,8 +89,19 @@ ogm_header(AVFormatContext *s, int idx)
st->codec->channels = bytestream_get_le16(&p);
p += 2; /* block_align */
st->codec->bit_rate = bytestream_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) {
+ p += 4;
+ size -= 4;
+ }
+ if (size > 52) {
+ av_assert0(FF_INPUT_BUFFER_PADDING_SIZE <= 52);
+ size -= 52;
+ st->codec->extradata_size = size;
+ st->codec->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
+ bytestream_get_buffer(&p, st->codec->extradata, size);
+ }
}
} else if (*p == 3) {
if (os->psize > 8)
diff --git a/libavformat/oggparseopus.c b/libavformat/oggparseopus.c
new file mode 100644
index 0000000..0e8f1ca
--- /dev/null
+++ b/libavformat/oggparseopus.c
@@ -0,0 +1,135 @@
+/*
+ * Opus parser for Ogg
+ * 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/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+#include "oggdec.h"
+
+struct oggopus_private {
+ int need_comments;
+ unsigned pre_skip;
+ int64_t cur_dts;
+};
+
+#define OPUS_HEAD_SIZE 19
+
+static int opus_header(AVFormatContext *avf, int idx)
+{
+ struct ogg *ogg = avf->priv_data;
+ struct ogg_stream *os = &ogg->streams[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);
+ 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)
+ return AVERROR(ENOMEM);
+ memcpy(extradata, packet, os->psize);
+ st->codec->extradata = extradata;
+ st->codec->extradata_size = os->psize;
+
+ st->codec->sample_rate = 48000;
+ avpriv_set_pts_info(st, 64, 1, 48000);
+ priv->need_comments = 1;
+ return 1;
+ }
+
+ if (priv->need_comments) {
+ if (os->psize < 8 || memcmp(packet, "OpusTags", 8))
+ return AVERROR_INVALIDDATA;
+ ff_vorbis_comment(avf, &st->metadata, packet + 8, os->psize - 8);
+ priv->need_comments--;
+ return 1;
+ }
+ return 0;
+}
+
+static int opus_packet(AVFormatContext *avf, int idx)
+{
+ struct ogg *ogg = avf->priv_data;
+ struct ogg_stream *os = &ogg->streams[idx];
+ AVStream *st = avf->streams[idx];
+ struct oggopus_private *priv = os->private;
+ uint8_t *packet = os->buf + os->pstart;
+ unsigned toc, toc_config, toc_count, frame_size, nb_frames = 1;
+
+ if (!os->psize)
+ return AVERROR_INVALIDDATA;
+ toc = *packet;
+ toc_config = toc >> 3;
+ toc_count = toc & 3;
+ frame_size = toc_config < 12 ? FFMAX(480, 960 * (toc_config & 3)) :
+ toc_config < 16 ? 480 << (toc_config & 1) :
+ 120 << (toc_config & 3);
+ if (toc_count == 3) {
+ if (os->psize < 2)
+ return AVERROR_INVALIDDATA;
+ nb_frames = packet[1] & 0x3F;
+ } else if (toc_count) {
+ nb_frames = 2;
+ }
+ os->pduration = frame_size * nb_frames;
+ if (os->lastpts != AV_NOPTS_VALUE) {
+ if (st->start_time == AV_NOPTS_VALUE)
+ st->start_time = os->lastpts;
+ priv->cur_dts = os->lastdts = os->lastpts -= priv->pre_skip;
+ }
+ priv->cur_dts += os->pduration;
+ if ((os->flags & OGG_FLAG_EOS)) {
+ int64_t skip = priv->cur_dts - os->granule + priv->pre_skip;
+ 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 must be truncated to %d (unimplemented).\n",
+ os->pduration);
+ }
+ }
+ return 0;
+}
+
+const struct ogg_codec ff_opus_codec = {
+ .name = "Opus",
+ .magic = "OpusHead",
+ .magicsize = 8,
+ .header = opus_header,
+ .packet = opus_packet,
+};
diff --git a/libavformat/oggparseskeleton.c b/libavformat/oggparseskeleton.c
index f437c69..307387d 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
*/
@@ -47,7 +47,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 +61,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);
diff --git a/libavformat/oggparsespeex.c b/libavformat/oggparsespeex.c
index 42480a3..63e6370 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) {
diff --git a/libavformat/oggparsetheora.c b/libavformat/oggparsetheora.c
index ed31d53..6877d1e 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;
}
@@ -160,10 +160,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 db462fc..da029a4 100644
--- a/libavformat/oggparsevorbis.c
+++ b/libavformat/oggparsevorbis.c
@@ -173,11 +173,15 @@ static unsigned int
fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv,
uint8_t **buf)
{
- int i,offset, len;
+ int i,offset, len, 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 (!*buf)
+ return 0;
+ memset(*buf, '\0', buf_len);
ptr[0] = 2;
offset = 1;
@@ -213,12 +217,12 @@ vorbis_header (AVFormatContext * s, int idx)
int pkt_type = os->buf[os->pstart];
if (!(pkt_type & 1))
- return 0;
+ return os->private ? 0 : -1;
if (!os->private) {
os->private = av_mallocz(sizeof(struct oggvorbis_private));
if (!os->private)
- return 0;
+ return -1;
}
if (os->psize < 1 || pkt_type > 5)
@@ -233,11 +237,14 @@ vorbis_header (AVFormatContext * s, int idx)
priv->len[pkt_type >> 1] = os->psize;
priv->packet[pkt_type >> 1] = av_mallocz(os->psize);
+ if (!priv->packet[pkt_type >> 1])
+ return AVERROR(ENOMEM);
memcpy(priv->packet[pkt_type >> 1], os->buf + os->pstart, os->psize);
if (os->buf[os->pstart] == 1) {
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 -1;
@@ -245,7 +252,12 @@ vorbis_header (AVFormatContext * s, int idx)
if (bytestream_get_le32(&p) != 0) /* vorbis_version */
return -1;
- 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
@@ -306,33 +318,39 @@ 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];
}
next_pkt += os->segments[seg];
}
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);
}
@@ -340,7 +358,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 aaaf0b2..fc926bf 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
*/
@@ -31,3 +31,4 @@ const AVCodecTag ff_oma_codec_tags[] = {
{ AV_CODEC_ID_PCM_S16BE, OMA_CODECID_LPCM },
{ 0 },
};
+
diff --git a/libavformat/omadec.c b/libavformat/omadec.c
index 9452c61..e571495 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"
@@ -162,7 +161,7 @@ static int nprobe(AVFormatContext *s, uint8_t *enc_header, int size,
taglen = AV_RB32(&enc_header[pos + 32]);
datalen = AV_RB32(&enc_header[pos + 36]) >> 4;
- if (taglen + (((uint64_t)datalen) << 4) + 44 > size)
+ if (pos + (uint64_t)taglen + (((uint64_t)datalen) << 4) + 44 > size)
return -1;
pos += 44 + taglen;
@@ -223,6 +222,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);
@@ -249,7 +254,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;
}
@@ -363,7 +368,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:
@@ -406,7 +411,7 @@ static int oma_read_packet(AVFormatContext *s, AVPacket *pkt)
/* previous unencrypted block saved in IV for
* the next packet (CBC mode) */
av_des_crypt(&oc->av_des, pkt->data, pkt->data,
- (packet_size >> 3), oc->iv, 1);
+ (ret >> 3), oc->iv, 1);
}
return ret;
diff --git a/libavformat/omaenc.c b/libavformat/omaenc.c
index ea28e10..5c5aff7 100644
--- a/libavformat/omaenc.c
+++ b/libavformat/omaenc.c
@@ -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 3399dd4..42307d1 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 d1e2a0c..9f86137 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 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 = DEFAULT }, INT_MIN, INT_MAX, D|E, "fflags"},
@@ -40,8 +44,12 @@ static const AVOption 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", "dont 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", "forces seeking to enable seek to any mode", 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 */
@@ -49,6 +57,9 @@ static const AVOption 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"},
@@ -57,6 +68,14 @@ static const AVOption 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 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 shouldnt 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 positive. 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", "skip initial bytes", 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 2d8a903..dc88834 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 39d4cb6..e5f31e0 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__) */
diff --git a/libavformat/paf.c b/libavformat/paf.c
new file mode 100644
index 0000000..09786eb
--- /dev/null
+++ b/libavformat/paf.c
@@ -0,0 +1,261 @@
+/*
+ * 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++;
+ }
+
+ size = p->video_size - p->frames_offset_table[p->current_frame];
+ if (size < 1)
+ return AVERROR_INVALIDDATA;
+
+ 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
--- /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 712dbc9..e7956c0 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
*/
@@ -65,11 +65,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;
@@ -81,20 +83,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)
@@ -254,7 +288,7 @@ static int str_read_packet(AVFormatContext *s,
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
--- /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 1da8b88..8459cdd 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 && framerate.den) {
+#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);
@@ -281,6 +283,10 @@ static int r3d_read_reda(AVFormatContext *s, AVPacket *pkt, Atom *atom)
dts = avio_rb32(s->pb);
st->codec->sample_rate = avio_rb32(s->pb);
+ if (st->codec->sample_rate < 0) {
+ av_log(s, AV_LOG_ERROR, "negative sample rate\n");
+ return AVERROR_INVALIDDATA;
+ }
samples = avio_rb32(s->pb);
@@ -308,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);
@@ -365,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 171c603..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
*/
@@ -26,7 +26,6 @@
int ff_raw_write_packet(AVFormatContext *s, AVPacket *pkt)
{
avio_write(s->pb, pkt->data, pkt->size);
- avio_flush(s->pb);
return 0;
}
@@ -69,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",
@@ -132,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",
@@ -244,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",
@@ -267,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 a8367e5..6ac81d5 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
*/
@@ -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 a393299..c2ec94b 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
--- /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..44d5da7
--- /dev/null
+++ b/libavformat/redspark.c
@@ -0,0 +1,167 @@
+/*
+ * 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;
+
+ codec->extradata_size = 32 * codec->channels;
+ codec->extradata = av_malloc(codec->extradata_size);
+ if (!codec->extradata) {
+ 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 eae1f64..7ad96a8 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,9 +25,13 @@
#include "avio_internal.h"
#include "riff.h"
#include "libavcodec/bytestream.h"
+#include "libavutil/avassert.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') },
@@ -35,7 +39,10 @@ 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_H263, MKTAG('H', '2', '6', '3') },
{ AV_CODEC_ID_H263, MKTAG('X', '2', '6', '3') },
{ AV_CODEC_ID_H263, MKTAG('T', '2', '6', '3') },
@@ -43,11 +50,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') },
@@ -94,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') },
@@ -112,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') },
@@ -127,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') },
@@ -146,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') },
@@ -160,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 */
@@ -215,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') },
@@ -253,8 +275,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') },
@@ -270,6 +294,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') },
@@ -283,6 +309,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') },
@@ -298,13 +325,21 @@ 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_G2M, MKTAG('G', '2', 'M', '2') },
+ { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '3') },
+ { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '4') },
+ { AV_CODEC_ID_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') },
{ 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_EXR, MKTAG('e', 'x', 'r', ' ') },
{ 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') },
@@ -312,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_NONE, 0 }
};
@@ -328,12 +365,16 @@ 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_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 },
@@ -363,9 +404,13 @@ 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_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' },
@@ -393,10 +438,18 @@ const AVMetadataConv ff_riff_info_conv[] = {
{ "IPRD", "album" },
{ "IPRT", "track" },
{ "ISFT", "encoder" },
+ { "ISMP", "timecode" },
{ "ITCH", "encoded_by" },
{ 0 },
};
+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;
@@ -418,10 +471,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 */
@@ -456,8 +513,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 {
@@ -483,6 +542,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
@@ -494,6 +557,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;
}
@@ -525,6 +590,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;
@@ -576,7 +646,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);
@@ -636,7 +706,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", "ISBJ", "ISFT", "ISHP", "ISMP", "ISRC", "ISRF", "ITCH",
{ 0 }
};
@@ -686,7 +756,10 @@ void ff_riff_write_info(AVFormatContext *s)
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);
@@ -756,7 +829,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;
@@ -779,10 +852,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 */
@@ -813,12 +887,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);
@@ -833,7 +918,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");
@@ -843,14 +928,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/riff.h b/libavformat/riff.h
index b4f1cac..cb83789 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
*/
@@ -44,14 +44,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);
@@ -92,10 +92,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/rl2.c b/libavformat/rl2.c
index ac0532f..800e12e 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
*/
@@ -136,6 +136,9 @@ static av_cold int rl2_read_header(AVFormatContext *s)
/** setup audio stream if present */
if(sound_rate){
+ if(channels <= 0)
+ return AVERROR_INVALIDDATA;
+
pts_num = def_sound_size;
pts_den = rate;
@@ -229,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 3dafa39..13d1d25 100644
--- a/libavformat/rmdec.c
+++ b/libavformat/rmdec.c
@@ -2,28 +2,30 @@
* "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/intreadwrite.h"
#include "libavutil/dict.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "internal.h"
#include "rmsipr.h"
#include "rm.h"
@@ -126,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, 0);
if ((startpos + header_size) >= avio_tell(pb) + 2) {
// fourcc (should always be "lpcJ")
@@ -138,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;
@@ -147,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 */
@@ -156,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 */
@@ -195,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;
@@ -221,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);
@@ -268,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;
}
@@ -284,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;
@@ -307,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);
@@ -333,6 +377,9 @@ ff_rm_read_mdpr_codecdata (AVFormatContext *s, AVIOContext *pb,
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
}
skip:
@@ -423,7 +470,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);
@@ -438,7 +485,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);
@@ -460,7 +507,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 */
@@ -484,12 +532,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'):
@@ -542,7 +592,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){
@@ -609,8 +659,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;
@@ -639,18 +691,26 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb,
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);
+ 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;
@@ -803,13 +863,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);
@@ -828,7 +889,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;
@@ -837,7 +898,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) {
@@ -856,7 +919,7 @@ 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,
@@ -912,7 +975,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;
@@ -944,6 +1009,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"),
@@ -953,6 +1030,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 ed1ba7c..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;
@@ -369,7 +374,6 @@ static int rm_write_audio(AVFormatContext *s, const uint8_t *buf, int size, int
} else {
avio_write(pb, buf, size);
}
- avio_flush(pb);
stream->nb_frames++;
av_free(buf1);
return 0;
@@ -414,7 +418,6 @@ static int rm_write_video(AVFormatContext *s, const uint8_t *buf, int size, int
avio_w8(pb, stream->nb_frames & 0xff);
avio_write(pb, buf, size);
- avio_flush(pb);
stream->nb_frames++;
return 0;
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 a5b1e6e..0bc4b97 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;
}
@@ -164,11 +164,9 @@ static int rpl_read_header(AVFormatContext *s)
// The header is wrong here, at least sometimes
vst->codec->bits_per_coded_sample = 16;
break;
-#if 0
case 130:
vst->codec->codec_id = AV_CODEC_ID_ESCAPE130;
break;
-#endif
default:
av_log(s, AV_LOG_WARNING,
"RPL video format %i not supported yet!\n",
@@ -254,10 +252,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,
@@ -289,7 +287,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..5b53cef
--- /dev/null
+++ b/libavformat/rsd.c
@@ -0,0 +1,170 @@
+/*
+ * 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. */
+
+ codec->extradata_size = 32;
+ codec->extradata = av_malloc(codec->extradata_size);
+ if (!codec->extradata)
+ 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 b9c5f1e..7c9bb6d 100644
--- a/libavformat/rtmp.h
+++ b/libavformat/rtmp.h
@@ -2,20 +2,20 @@
* RTMP definitions
* Copyright (c) 2009 Kostya Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
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 e67abba..3a51f7c 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 35534b1..c2015a5 100644
--- a/libavformat/rtmppkt.c
+++ b/libavformat/rtmppkt.c
@@ -2,20 +2,20 @@
* RTMP input format
* Copyright (c) 2009 Kostya Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtmppkt.h b/libavformat/rtmppkt.h
index 276c560..a942295 100644
--- a/libavformat/rtmppkt.h
+++ b/libavformat/rtmppkt.h
@@ -2,20 +2,20 @@
* RTMP packet utilities
* Copyright (c) 2009 Kostya Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
index 94f7aae..5164931 100644
--- a/libavformat/rtmpproto.c
+++ b/libavformat/rtmpproto.c
@@ -2,20 +2,20 @@
* RTMP network protocol
* Copyright (c) 2009 Kostya Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -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
@@ -264,9 +264,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;
@@ -313,7 +310,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;
@@ -1143,7 +1140,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. */
@@ -1221,7 +1218,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,
@@ -1251,7 +1248,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,
@@ -1263,13 +1260,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,
@@ -1287,7 +1284,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;
@@ -2143,7 +2140,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;
@@ -2368,16 +2365,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..c4dcf6a 100644
--- a/libavformat/rtp.c
+++ b/libavformat/rtp.c
@@ -2,20 +2,20 @@
* 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
*/
diff --git a/libavformat/rtp.h b/libavformat/rtp.h
index f8d406e..1732af8 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 6652842..b512b89 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 6e923d9..623d911 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 e425650..35603f2 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_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..a2ad071 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
*/
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..571b739 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
*/
@@ -139,7 +139,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..6ce776d 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,6 +26,7 @@
*/
#include <string.h>
+#include "libavutil/avassert.h"
#include "libavutil/intreadwrite.h"
#include "libavcodec/avcodec.h"
#include "rtp.h"
@@ -193,7 +194,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 af5a5e9..8e887a5 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..106b785 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
*/
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..52a94b3 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,11 @@
*/
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/base64.h"
#include "libavcodec/bytestream.h"
-#include <assert.h>
-
#include "rtpdec.h"
#include "rtpdec_formats.h"
@@ -192,7 +191,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
diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c
index c82a73a..2c93c20 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 d19b0fd..72a5fa4 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
@@ -92,7 +92,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 935dd6c..70d68ce 100644
--- a/libavformat/rtpenc_chain.c
+++ b/libavformat/rtpenc_chain.c
@@ -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
*/
@@ -59,6 +59,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 +68,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_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..7535a0f 100644
--- a/libavformat/rtpenc_latm.c
+++ b/libavformat/rtpenc_latm.c
@@ -2,9 +2,9 @@
* 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.
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 190dff4..62ec4c9 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
*/
@@ -110,6 +110,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");
}
/**
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 761aa11..6310d79 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"
@@ -88,6 +89,7 @@ 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(),
{ NULL },
};
@@ -641,7 +643,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);
@@ -1243,10 +1245,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. */
@@ -1300,7 +1298,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;
@@ -1620,7 +1617,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 44240c1..4af3507 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,6 +391,11 @@ typedef struct RTSPState {
int initial_timeout;
/**
+ * timeout of socket i/o operations.
+ */
+ int stimeout;
+
+ /**
* Size of RTP packet reordering queue.
*/
int reordering_queue_size;
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 7e7fb2d..da571a8 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
*/
@@ -737,7 +737,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 9b3c7c9..bad6fbd 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
--- /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..6b1cd18 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
*/
@@ -26,6 +26,7 @@
#include "libavutil/dict.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/time.h"
+#include "libavutil/dict.h"
#include "internal.h"
#include "network.h"
#include "os_support.h"
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..30c3b49
--- /dev/null
+++ b/libavformat/sbgdec.c
@@ -0,0 +1,1513 @@
+/*
+ * 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);
+ }
+ edata = av_malloc(edata_size);
+ if (!edata)
+ return AVERROR(ENOMEM);
+ avc->extradata = edata;
+ avc->extradata_size = edata_size;
+
+#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 42dd547..f9ddb9f 100644
--- a/libavformat/sctp.c
+++ b/libavformat/sctp.c
@@ -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..34ac4de 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,25 @@ 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;
+
+ 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 {
+ argc = 1;
+ }
+ }
av_dict_set(&format_opts, "channels", "1", 0);
av_dict_set(&format_opts, "sample_rate", "22050", 0);
@@ -68,7 +84,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 +105,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,6 +127,7 @@ int main(int argc, char **argv)
} else
printf("ret:%s", ret_str(ret)); // necessary to avoid trailing whitespace
printf("\n");
+ }
}
if(i>25) break;
diff --git a/libavformat/seek.c b/libavformat/seek.c
index 524cd87..0ae99eb 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 e79d7bd..b27cb42 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 068d432..a33ad85 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')
@@ -112,7 +113,7 @@ static int film_read_header(AVFormatContext *s)
film->audio_samplerate = AV_RB16(&scratch[24]);
film->audio_channels = scratch[21];
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)
@@ -247,7 +248,7 @@ static int film_read_packet(AVFormatContext *s,
int left, right;
if (film->current_sample >= film->sample_count)
- return AVERROR(EIO);
+ return AVERROR_EOF;
sample = &film->sample_table[film->current_sample];
@@ -266,6 +267,8 @@ static int film_read_packet(AVFormatContext *s,
(film->audio_type != AV_CODEC_ID_ADPCM_ADX)) {
/* stereo PCM needs to be interleaved */
+ if (ffio_limit(pb, sample->sample_size) != sample->sample_size)
+ return AVERROR(EIO);
if (av_new_packet(pkt, sample->sample_size))
return AVERROR(ENOMEM);
@@ -287,7 +290,7 @@ static int film_read_packet(AVFormatContext *s,
left = 0;
right = sample->sample_size / 2;
- for (i = 0; i < sample->sample_size; ) {
+ for (i = 0; i + 1 + 2*(film->audio_bits != 8) < sample->sample_size; ) {
if (film->audio_bits == 8) {
pkt->data[i++] = film->stereo_buffer[left++];
pkt->data[i++] = film->stereo_buffer[right++];
diff --git a/libavformat/segment.c b/libavformat/segment.c
index d79a327..dbcfe89 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -1,5 +1,4 @@
/*
- * Generic segmenter
* Copyright (c) 2011, Luca Barbato
*
* This file is part of Libav.
@@ -19,40 +18,104 @@
* 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;
+ 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;
+
+ char *time_delta_str; ///< approximation value duration used for the segment times
+ 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
+ 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 +129,64 @@ 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;
-
- 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));
+ AVFormatContext *oc = seg->avf;
- 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;
+ seg->segment_count++;
if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
&s->interrupt_callback, NULL)) < 0)
@@ -141,21 +200,248 @@ 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);
+ }
+
+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 +462,126 @@ 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->time_delta_str) {
+ if ((ret = av_parse_time(&seg->time_delta, seg->time_delta_str, 1)) < 0) {
+ av_log(s, AV_LOG_ERROR,
+ "Invalid time duration specification '%s' for delta option\n",
+ seg->time_delta_str);
+ return ret;
+ }
+ }
+
+ 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 +600,9 @@ 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;
- }
+ seg->segment_count++;
if (seg->write_header_trailer) {
if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
@@ -238,6 +617,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 +629,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,20 +644,32 @@ 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;
+ 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-1] : INT64_MAX;
+ } else if (seg->frames) {
+ start_frame = seg->segment_count <= seg->nb_frames ?
+ seg->frames[seg->segment_count-1] : INT_MAX;
+ } else {
+ end_pts = seg->time * seg->segment_count;
}
- 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);
+ 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);
- ret = segment_end(oc, seg->individual_header_trailer);
+ 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))) {
+ ret = segment_end(s, seg->individual_header_trailer, 0);
if (!ret)
ret = segment_start(s, seg->individual_header_trailer);
@@ -294,29 +679,48 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
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;
+ }
+
+ if (seg->reset_timestamps) {
+ 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 */
+ if (pkt->pts != AV_NOPTS_VALUE)
+ pkt->pts -= av_rescale_q(seg->cur_entry.start_pts, AV_TIME_BASE_Q, st->time_base);
+ if (pkt->dts != AV_NOPTS_VALUE)
+ pkt->dts -= av_rescale_q(seg->cur_entry.start_pts, AV_TIME_BASE_Q, st->time_base);
+
+ 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 +731,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 +765,34 @@ 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_str), AV_OPT_TYPE_STRING, {.str = "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 },
{ NULL },
};
@@ -375,14 +803,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 645b99b..b2d1e5d 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,12 @@ 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;
+ int i, j, width, height;
unsigned int total_frames;
int64_t current_audio_pts = 0;
unsigned char chunk[BYTES_PER_FRAME_RECORD];
@@ -100,28 +103,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;
+ }
+ 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);
}
- 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 +162,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);
}
@@ -246,12 +255,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);
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 17c7c52..84481e2 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,7 +140,7 @@ 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_flags = av_malloc(smk->frames);
@@ -158,7 +158,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;
@@ -210,13 +210,13 @@ static int smacker_read_header(AVFormatContext *s)
/* load trees to extradata, they will be unpacked by decoder */
- st->codec->extradata = av_malloc(smk->treesize + 16);
+ st->codec->extradata = av_malloc(smk->treesize + 16 + FF_INPUT_BUFFER_PADDING_SIZE);
st->codec->extradata_size = smk->treesize + 16;
if(!st->codec->extradata){
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;
+ return AVERROR(ENOMEM);
}
ret = avio_read(pb, st->codec->extradata + 16, st->codec->extradata_size - 16);
if(ret != st->codec->extradata_size - 16){
@@ -245,7 +245,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 */
@@ -262,6 +262,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;
@@ -274,7 +276,7 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
} else if(t & 0x40){ /* copy with offset */
off = avio_r8(s->pb);
j = (t & 0x3F) + 1;
- if (off + j > 0xff) {
+ if (off + j - 1 > 0xff) {
av_log(s, AV_LOG_ERROR,
"Invalid palette update, offset=%d length=%d extends beyond palette size\n",
off, j);
@@ -303,10 +305,12 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
/* if audio chunks are present, put them to stack and retrieve later */
for(i = 0; i < 7; i++) {
if(flags & 1) {
- int size;
+ unsigned int size;
uint8_t *tmpbuf;
size = avio_rl32(s->pb) - 4;
+ if(size + 4L > frame_size)
+ return AVERROR_INVALIDDATA;
frame_size -= size;
frame_size -= 4;
smk->curstream++;
@@ -366,7 +370,7 @@ static int smacker_read_close(AVFormatContext *s)
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 5c64e84..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);
@@ -109,7 +109,6 @@ static int smjpeg_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_wb32(pb, pkt->pts);
avio_wb32(pb, pkt->size);
avio_write(pb, pkt->data, pkt->size);
- avio_flush(pb);
smc->duration = FFMAX(smc->duration, pkt->pts + pkt->duration);
return 0;
diff --git a/libavformat/smoothstreamingenc.c b/libavformat/smoothstreamingenc.c
index d26af05..096bf79 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
*/
@@ -287,7 +287,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) {
@@ -314,7 +318,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) {
@@ -559,7 +567,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..9c8997c
--- /dev/null
+++ b/libavformat/smush.c
@@ -0,0 +1,240 @@
+/*
+ * 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) {
+ vst->codec->extradata = av_malloc(1024 + 2 + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!vst->codec->extradata)
+ return AVERROR(ENOMEM);
+
+ vst->codec->extradata_size = 1024 + 2;
+ 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 b2a6b63..0a0d962 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 1f37340..857c20d 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
*/
@@ -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 */
@@ -538,7 +538,6 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt)
av_log(s, AV_LOG_DEBUG, "type=%x len=%i pkt_offset=%i\n",
ctx->data_type, ctx->out_bytes, ctx->pkt_offset);
- avio_flush(s->pb);
return 0;
}
diff --git a/libavformat/srtdec.c b/libavformat/srtdec.c
index 9db5133..dbf1866 100644
--- a/libavformat/srtdec.c
+++ b/libavformat/srtdec.c
@@ -2,37 +2,44 @@
* 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 */
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;
@@ -40,63 +47,119 @@ static int srt_probe(AVProbeData *p)
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 += strcspn(*buf, "\n");
+ *buf += !!**buf;
+ return start;
+ }
+ *buf += strcspn(*buf, "\n");
+ *buf += !!**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
--- /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..2af0450
--- /dev/null
+++ b/libavformat/subtitles.c
@@ -0,0 +1,231 @@
+/*
+ * 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
+ */
+
+#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(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;
+}
+
+void ff_subtitles_queue_finalize(FFDemuxSubtitlesQueue *q)
+{
+ int i;
+
+ qsort(q->subs, q->nb_subs, sizeof(*q->subs), cmp_pkt_sub);
+ 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;
+ av_copy_packet(pkt, sub);
+
+ pkt->dts = pkt->pts;
+ q->current_sub_idx++;
+ return 0;
+}
+
+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 = -1;
+ int64_t min_ts_diff = INT64_MAX;
+ int64_t ts_selected;
+ /* TODO: q->subs[] is sorted by pts so we could do a binary search */
+ for (i = 0; i < q->nb_subs; i++) {
+ int64_t pts = q->subs[i].pts;
+ uint64_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);
+ /* look back in the latest subtitles for overlapping subtitles */
+ ts_selected = q->subs[idx].pts;
+ for (i = idx - 1; i >= 0; i--) {
+ if (q->subs[i].duration <= 0)
+ continue;
+ if (q->subs[i].pts > ts_selected - q->subs[i].duration)
+ idx = i;
+ else
+ break;
+ }
+ 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];
+ 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';
+ if (nb_eol == 2)
+ break;
+ eol_buf[i++] = c;
+ if (i == sizeof(eol_buf) - 1)
+ break;
+ 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..455b374
--- /dev/null
+++ b/libavformat/subtitles.h
@@ -0,0 +1,99 @@
+/*
+ * 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"
+
+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
+} 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);
+
+#endif /* AVFORMAT_SUBTITLES_H */
diff --git a/libavformat/subviewer1dec.c b/libavformat/subviewer1dec.c
new file mode 100644
index 0000000..1b831b7
--- /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
--- /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..b9722c1 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
@@ -76,6 +135,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 31f405d..7018362 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 */
@@ -436,8 +441,6 @@ static int swf_write_video(AVFormatContext *s,
put_swf_tag(s, TAG_SHOWFRAME);
put_swf_end_tag(s);
- avio_flush(s->pb);
-
return 0;
}
@@ -456,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)
@@ -486,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);
@@ -500,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..18c2be2 100644
--- a/libavformat/takdec.c
+++ b/libavformat/takdec.c
@@ -2,20 +2,20 @@
* 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
*/
@@ -52,7 +52,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 +60,7 @@ static int tak_read_header(AVFormatContext *s)
return 0;
}
- while (!pb->eof_reached) {
+ while (!url_feof(pb)) {
enum TAKMetaDataType type;
int size;
diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index bdaab7f..0d792e7 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,23 +31,43 @@
#endif
typedef struct TCPContext {
+ const AVClass *class;
int fd;
+ int listen;
+ 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 = 0}, 0, 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;
socklen_t optlen;
- int timeout = 100, listen_timeout = -1;
char hostname[1024],proto[1024],path[1024];
char portstr[10];
+ h->rw_timeout = 5000000;
av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
&port, path, sizeof(path), uri);
@@ -58,18 +80,19 @@ 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);
}
}
+ 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);
@@ -90,7 +113,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
if (fd < 0)
goto fail;
- if (listen_socket) {
+ if (s->listen) {
int fd1;
int reuse = 1;
struct pollfd lp = { fd, POLLIN, 0 };
@@ -105,7 +128,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
ret = ff_neterrno();
goto fail1;
}
- ret = poll(&lp, 1, listen_timeout >= 0 ? listen_timeout : -1);
+ ret = poll(&lp, 1, s->listen_timeout >= 0 ? s->listen_timeout : -1);
if (ret <= 0) {
ret = AVERROR(ETIMEDOUT);
goto fail1;
@@ -126,6 +149,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
if (ret < 0) {
struct pollfd p = {fd, POLLOUT, 0};
+ int64_t wait_started;
ret = ff_neterrno();
if (ret == AVERROR(EINTR)) {
if (ff_check_interrupt(&h->interrupt_callback)) {
@@ -139,7 +163,8 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
goto fail;
/* wait until we are connected or until abort */
- while(timeout--) {
+ wait_started = av_gettime();
+ do {
if (ff_check_interrupt(&h->interrupt_callback)) {
ret = AVERROR_EXIT;
goto fail1;
@@ -147,7 +172,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
ret = poll(&p, 1, 100);
if (ret > 0)
break;
- }
+ } while (!h->rw_timeout || (av_gettime() - wait_started < h->rw_timeout));
if (ret <= 0) {
ret = AVERROR(ETIMEDOUT);
goto fail;
@@ -192,8 +217,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);
@@ -206,8 +231,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);
@@ -252,5 +277,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..b468969
--- /dev/null
+++ b/libavformat/tedcaptionsdec.c
@@ -0,0 +1,365 @@
+/*
+ * 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)
+{
+ const char *text[] = { "false", "true" }, *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..10787ca
--- /dev/null
+++ b/libavformat/tee.c
@@ -0,0 +1,278 @@
+/*
+ * Tee pesudo-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 TeeContext {
+ const AVClass *class;
+ unsigned nb_slaves;
+ AVFormatContext *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 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;
+}
+
+static int open_slave(AVFormatContext *avf, char *slave, AVFormatContext **ravf)
+{
+ int i, ret;
+ AVDictionary *options = NULL;
+ AVDictionaryEntry *entry;
+ char *filename;
+ char *format = NULL;
+ AVFormatContext *avf2 = NULL;
+ AVStream *st, *st2;
+
+ if ((ret = parse_slave_options(avf, slave, &options, &filename)) < 0)
+ return ret;
+ if ((entry = av_dict_get(options, "f", NULL, 0))) {
+ format = entry->value;
+ entry->value = NULL; /* prevent it from being freed */
+ av_dict_set(&options, "f", NULL, 0);
+ }
+
+ ret = avformat_alloc_output_context2(&avf2, NULL, format, filename);
+ if (ret < 0)
+ goto fail;
+ av_free(format);
+
+ for (i = 0; i < avf->nb_streams; i++) {
+ st = avf->streams[i];
+ if (!(st2 = avformat_new_stream(avf2, NULL))) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ 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 fail;
+ }
+
+ 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 fail;
+ }
+ }
+
+ 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 fail;
+ }
+ 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 fail;
+ }
+
+ *ravf = avf2;
+ return 0;
+
+fail:
+ av_dict_free(&options);
+ return ret;
+}
+
+static void close_slaves(AVFormatContext *avf)
+{
+ TeeContext *tee = avf->priv_data;
+ AVFormatContext *avf2;
+ unsigned i;
+
+ for (i = 0; i < tee->nb_slaves; i++) {
+ avf2 = tee->slaves[i];
+ avio_close(avf2->pb);
+ avf2->pb = NULL;
+ avformat_free_context(avf2);
+ tee->slaves[i] = NULL;
+ }
+}
+
+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;
+ av_freep(&slaves[i]);
+ }
+
+ tee->nb_slaves = nb_slaves;
+ return 0;
+
+fail:
+ for (i = 0; i < nb_slaves; i++)
+ av_freep(&slaves[i]);
+ close_slaves(avf);
+ 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];
+ 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;
+ AVRational tb, tb2;
+
+ for (i = 0; i < tee->nb_slaves; i++) {
+ avf2 = tee->slaves[i];
+ s = pkt->stream_index;
+ if (s >= avf2->nb_streams) {
+ if (!ret_all)
+ ret_all = AVERROR(EINVAL);
+ 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[s]->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);
+ 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 fecf096..2c85d1d 100644
--- a/libavformat/tls.c
+++ b/libavformat/tls.c
@@ -22,6 +22,7 @@
#include "avformat.h"
#include "url.h"
#include "libavutil/avstring.h"
+#include "libavutil/parseutils.h"
#if CONFIG_GNUTLS
#include <gnutls/gnutls.h>
#define TLS_read(c, buf, size) gnutls_record_recv(c->session, buf, size)
@@ -103,21 +104,76 @@ 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], key[1024];
+ int has_cert, has_key, verify = 0;
+#if CONFIG_GNUTLS
+ int ret;
+#endif
+ const char *p = strchr(uri, '?');
+ if (!p)
+ return;
+
+ if (av_find_info_tag(buf, sizeof(buf), "cafile", p)) {
+#if CONFIG_GNUTLS
+ ret = gnutls_certificate_set_x509_trust_file(c->cred, buf, GNUTLS_X509_FMT_PEM);
+ if (ret < 0)
+ av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
+#elif CONFIG_OPENSSL
+ if (!SSL_CTX_load_verify_locations(c->ctx, buf, NULL))
+ av_log(h, AV_LOG_ERROR, "SSL_CTX_load_verify_locations %s\n", ERR_error_string(ERR_get_error(), NULL));
+#endif
+ }
+
+ if (av_find_info_tag(buf, sizeof(buf), "verify", p)) {
+ char *endptr = NULL;
+ verify = strtol(buf, &endptr, 10);
+ if (buf == endptr)
+ verify = 1;
+ }
+
+ has_cert = av_find_info_tag(buf, sizeof(buf), "cert", p);
+ has_key = av_find_info_tag(key, sizeof(key), "key", p);
+#if CONFIG_GNUTLS
+ if (has_cert && has_key) {
+ ret = gnutls_certificate_set_x509_key_file(c->cred, buf, key, GNUTLS_X509_FMT_PEM);
+ if (ret < 0)
+ av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
+ } else if (has_cert ^ has_key) {
+ av_log(h, AV_LOG_ERROR, "cert and key required\n");
+ }
+ gnutls_certificate_set_verify_flags(c->cred, verify);
+#elif CONFIG_OPENSSL
+ if (has_cert && !SSL_CTX_use_certificate_chain_file(c->ctx, buf))
+ av_log(h, AV_LOG_ERROR, "SSL_CTX_use_certificate_chain_file %s\n", ERR_error_string(ERR_get_error(), NULL));
+ if (has_key && !SSL_CTX_use_PrivateKey_file(c->ctx, key, SSL_FILETYPE_PEM))
+ av_log(h, AV_LOG_ERROR, "SSL_CTX_use_PrivateKey_file %s\n", ERR_error_string(ERR_get_error(), NULL));
+ if (verify)
+ SSL_CTX_set_verify(c->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
+#endif
+}
+
static int tls_open(URLContext *h, const char *uri, int flags)
{
TLSContext *c = h->priv_data;
int ret;
int port;
- char buf[200], host[200];
+ char buf[200], host[200], path[1024];
int numerichost = 0;
struct addrinfo hints = { 0 }, *ai = NULL;
const char *proxy_path;
int use_proxy;
+ int server = 0;
+ const char *p = strchr(uri, '?');
+ if (p && av_find_info_tag(buf, sizeof(buf), "listen", p))
+ server = 1;
ff_tls_init();
- av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0, uri);
- ff_url_join(buf, sizeof(buf), "tcp", NULL, host, port, NULL);
+ av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, path, sizeof(path), uri);
+ ff_url_join(buf, sizeof(buf), "tcp", NULL, host, port, "%s", path);
hints.ai_flags = AI_NUMERICHOST;
if (!getaddrinfo(host, NULL, &hints, &ai)) {
@@ -147,11 +203,11 @@ static int tls_open(URLContext *h, const char *uri, int flags)
c->fd = ffurl_get_file_handle(c->tcp);
#if CONFIG_GNUTLS
- gnutls_init(&c->session, GNUTLS_CLIENT);
+ gnutls_init(&c->session, server ? GNUTLS_SERVER : GNUTLS_CLIENT);
if (!numerichost)
gnutls_server_name_set(c->session, GNUTLS_NAME_DNS, host, strlen(host));
gnutls_certificate_allocate_credentials(&c->cred);
- gnutls_certificate_set_verify_flags(c->cred, 0);
+ set_options(h, uri);
gnutls_credentials_set(c->session, GNUTLS_CRD_CERTIFICATE, c->cred);
gnutls_transport_set_ptr(c->session, (gnutls_transport_ptr_t)
(intptr_t) c->fd);
@@ -164,12 +220,13 @@ static int tls_open(URLContext *h, const char *uri, int flags)
goto fail;
}
#elif CONFIG_OPENSSL
- c->ctx = SSL_CTX_new(TLSv1_client_method());
+ c->ctx = SSL_CTX_new(server ? TLSv1_server_method() : TLSv1_client_method());
if (!c->ctx) {
av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL));
ret = AVERROR(EIO);
goto fail;
}
+ set_options(h, uri);
c->ssl = SSL_new(c->ctx);
if (!c->ssl) {
av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL));
@@ -177,10 +234,10 @@ static int tls_open(URLContext *h, const char *uri, int flags)
goto fail;
}
SSL_set_fd(c->ssl, c->fd);
- if (!numerichost)
+ if (!server && !numerichost)
SSL_set_tlsext_host_name(c->ssl, host);
while (1) {
- ret = SSL_connect(c->ssl);
+ ret = server ? SSL_accept(c->ssl) : SSL_connect(c->ssl);
if (ret > 0)
break;
if (ret == 0) {
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..e6ded52 100644
--- a/libavformat/tta.c
+++ b/libavformat/tta.c
@@ -2,20 +2,20 @@
* 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
*/
@@ -44,8 +44,9 @@ 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 datalen;
if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX))
ff_id3v1_read(s);
@@ -64,9 +65,9 @@ static int tta_read_header(AVFormatContext *s)
}
datalen = avio_rl32(s->pb);
- if(datalen < 0){
- av_log(s, AV_LOG_ERROR, "nonsense datalen\n");
- return -1;
+ if (!datalen) {
+ av_log(s, AV_LOG_ERROR, "invalid datalen\n");
+ return AVERROR_INVALIDDATA;
}
avio_skip(s->pb, 4); // header crc
@@ -78,8 +79,8 @@ static int tta_read_header(AVFormatContext *s)
c->totalframes = datalen / 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");
+ if(c->totalframes >= UINT_MAX/sizeof(uint32_t) || c->totalframes <= 0){
+ av_log(s, AV_LOG_ERROR, "totalframes %d invalid\n", c->totalframes);
return -1;
}
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 373a4c9..e8a01db 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
+
/* put it in UDP context */
/* return non zero if error */
static int udp_open(URLContext *h, const char *uri, int flags)
@@ -395,12 +511,10 @@ static int udp_open(URLContext *h, const char *uri, int flags)
char *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) {
@@ -412,6 +526,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);
}
@@ -419,7 +544,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);
@@ -427,6 +552,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));
}
@@ -449,7 +581,13 @@ static int udp_open(URLContext *h, const char *uri, int flags)
break;
}
}
+ 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;
+ h->max_packet_size = s->packet_size;
+ h->rw_timeout = s->timeout;
/* fill the dest addr */
av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
@@ -466,7 +604,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;
@@ -549,15 +687,48 @@ static int udp_open(URLContext *h, const char *uri, int flags)
}
for (i = 0; i < num_sources; i++)
- av_free(sources[i]);
+ av_freep(&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_sources; i++)
- av_free(sources[i]);
+ av_freep(&sources[i]);
return AVERROR(EIO);
}
@@ -565,6 +736,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);
@@ -572,6 +787,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;
}
@@ -599,10 +815,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;
}
@@ -614,5 +842,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/url-test.c b/libavformat/url-test.c
index 6639ccf..ee5f06e 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.h b/libavformat/url.h
index 195a8ff..5f75dc9 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 {
@@ -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);
/**
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 eb01886..0c40aa9 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,7 +23,9 @@
#include "avio_internal.h"
#include "internal.h"
#include "libavcodec/internal.h"
+#include "libavcodec/raw.h"
#include "libavcodec/bytestream.h"
+#include "libavutil/avassert.h"
#include "libavutil/opt.h"
#include "libavutil/dict.h"
#include "libavutil/pixdesc.h"
@@ -34,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"
@@ -47,25 +50,59 @@
/**
* @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;
}
+#define MAKE_ACCESSORS(str, name, type, field) \
+ type av_##name##_get_##field(const str *s) { return s->field; } \
+ void av_##name##_set_##field(str *s, type v) { s->field = v; }
+
+MAKE_ACCESSORS(AVStream, stream, AVRational, r_frame_rate)
+
/** head of registered input format linked list */
static AVInputFormat *first_iformat = NULL;
/** head of registered output format linked list */
@@ -165,7 +202,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;
@@ -183,6 +220,10 @@ AVOutputFormat *av_guess_format(const char *short_name, const char *filename,
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;
@@ -215,16 +256,35 @@ AVInputFormat *av_find_input_format(const char *short_name)
/* 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;
@@ -234,11 +294,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)
@@ -252,6 +314,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)
@@ -283,19 +347,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;
@@ -305,44 +373,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;
@@ -352,14 +419,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);
@@ -371,12 +440,28 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeDa
}
}
}
- return !!fmt;
+ return score;
}
/************************************************************/
/* input media file */
+int av_demuxer_open(AVFormatContext *ic){
+ int err;
+
+ 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;
+}
+
+
/** size of probe buffer, for guessing file type from file contents */
#define PROBE_BUF_MIN 2048
#define PROBE_BUF_MAX (1<<20)
@@ -387,13 +472,16 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
{
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;
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);
}
@@ -401,17 +489,29 @@ 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;
+ int score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0;
+ void *buftmp;
if (probe_size < offset) {
continue;
}
/* read probe data */
- buf = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE);
+ buftmp = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE);
+ if(!buftmp){
+ av_free(buf);
+ return AVERROR(ENOMEM);
+ }
+ buf=buftmp;
if ((ret = avio_read(pb, buf + buf_offset, probe_size - buf_offset)) < 0) {
/* fail if error was not end of file, otherwise, lower score */
if (ret != AVERROR_EOF) {
@@ -421,7 +521,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);
@@ -429,10 +529,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);
}
}
@@ -442,8 +542,7 @@ 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;
}
@@ -453,21 +552,23 @@ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **o
{
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);
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))))
+ (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
return 0;
- 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)
@@ -492,7 +593,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++)
@@ -517,6 +618,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;
@@ -528,6 +633,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma
if ((ret = init_input(s, filename, &tmp)) < 0)
goto fail;
+ avio_skip(s->pb, s->skip_initial_bytes);
/* check filename in case an image number is expected */
if (s->iformat->flags & AVFMT_NEEDNUMBER) {
@@ -558,19 +664,23 @@ 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")) {
+ 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;
@@ -594,35 +704,62 @@ 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 void 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) {
- pd->buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE);
+ uint8_t *new_buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE);
+ if(!new_buf)
+ 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;
}
}
- 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);
}
}
}
@@ -638,15 +775,9 @@ 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) {
- probe_codec(s, st, NULL);
- }
- pd = &st->probe_data;
- av_freep(&pd->buf);
- pd->buf_size = 0;
+ if (s->raw_packet_buffer_remaining_size <= 0)
+ probe_codec(s, st, NULL);
+ if(st->request_probe <= 0){
s->raw_packet_buffer = pktl->next;
s->raw_packet_buffer_remaining_size += pkt->size;
av_free(pktl);
@@ -666,6 +797,7 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
if (st->probe_packets) {
probe_codec(s, st, NULL);
}
+ av_assert0(st->request_probe <= 0);
}
continue;
}
@@ -679,22 +811,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);
@@ -704,8 +839,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.
*/
@@ -724,6 +878,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;
}
@@ -740,9 +901,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;
@@ -774,41 +935,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 wont 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 (i=0; i<MAX_REORDER_DELAY+1; i++)
+ pts_buffer[i] = AV_NOPTS_VALUE;
+
+ if (is_relative(pts))
+ pts += shift;
- for(; pktl; pktl= pktl->next){
+ 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;
}
@@ -816,38 +1097,46 @@ 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 in the queue\n", av_ts2str(st->first_dts), av_ts2str(pktl->pkt.dts));
+ 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;
}
@@ -863,6 +1152,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;
@@ -873,28 +1166,30 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
pc && pc->pict_type != AV_PICTURE_TYPE_B)
presentation_delayed = 1;
- if(pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && pkt->dts > pkt->pts && st->pts_wrap_bits<63
- /*&& pkt->dts-(1LL<<st->pts_wrap_bits) < pkt->pts*/){
- pkt->dts -= 1LL<<st->pts_wrap_bits;
+ 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){
+ 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 */
@@ -930,10 +1225,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){
@@ -942,7 +1235,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;
@@ -958,57 +1251,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;
@@ -1042,6 +1318,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)) {
@@ -1053,6 +1332,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;
@@ -1084,19 +1364,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;
@@ -1174,17 +1453,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);
@@ -1192,12 +1471,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;
}
}
@@ -1218,16 +1502,22 @@ 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);
+ 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);
@@ -1239,15 +1529,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) {
@@ -1255,22 +1549,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);
@@ -1286,6 +1598,28 @@ 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);
+ 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 */
@@ -1340,7 +1674,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->reference_dts = AV_NOPTS_VALUE;
st->probe_packets = MAX_PROBE_PACKETS;
@@ -1387,6 +1722,12 @@ 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 (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) *
@@ -1401,7 +1742,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){
@@ -1425,6 +1766,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);
@@ -1471,6 +1813,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;
@@ -1483,7 +1834,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;
@@ -1500,22 +1851,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));
}
}
@@ -1527,6 +1878,7 @@ 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;
@@ -1541,30 +1893,35 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
int64_t start_pos, filesize;
int no_change;
- 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_min >= target_ts){
+ *ts_ret= ts_min;
+ return pos_min;
+ }
+
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);
+ pos_max = FFMAX(0, pos_max - step);
+ ts_max = ff_read_timestamp(s, stream_index, &pos_max, pos_max + step, read_timestamp);
step += step;
- }while(ts_max == AV_NOPTS_VALUE && pos_max >= step);
+ }while(ts_max == AV_NOPTS_VALUE && pos_max > 0);
if (ts_max == AV_NOPTS_VALUE)
return -1;
for(;;){
int64_t tmp_pos= pos_max + 1;
- int64_t tmp_ts= read_timestamp(s, stream_index, &tmp_pos, INT64_MAX);
+ int64_t tmp_ts= ff_read_timestamp(s, stream_index, &tmp_pos, INT64_MAX, read_timestamp);
if(tmp_ts == AV_NOPTS_VALUE)
break;
ts_max= tmp_ts;
@@ -1575,6 +1932,11 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
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){
@@ -1583,8 +1945,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){
@@ -1606,13 +1968,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");
@@ -1632,12 +1995,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;
}
@@ -1653,6 +2018,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;
}
@@ -1673,9 +2040,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;
@@ -1692,9 +2060,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);
@@ -1761,10 +2133,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;
}
@@ -1773,14 +2157,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;
}
@@ -1790,10 +2192,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
}
/*******************************************************/
@@ -1825,43 +2236,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)
@@ -1884,7 +2323,7 @@ static void fill_all_stream_timings(AVFormatContext *ic)
static void estimate_timings_from_bit_rate(AVFormatContext *ic)
{
int64_t filesize, duration;
- int bit_rate, i;
+ int bit_rate, i, show_warning = 0;
AVStream *st;
/* if bit_rate is already set, we believe it */
@@ -1905,16 +2344,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)
@@ -1970,11 +2414,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);
@@ -2011,14 +2455,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);
@@ -2038,32 +2484,49 @@ 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 */
@@ -2072,6 +2535,7 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option
const AVCodec *codec;
int got_picture = 1, ret = 0;
AVFrame *frame = avcodec_alloc_frame();
+ AVSubtitle subtitle;
AVPacket pkt = *avpkt;
if (!frame)
@@ -2110,7 +2574,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;
@@ -2123,18 +2587,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;
@@ -2173,6 +2645,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) {
@@ -2196,10 +2669,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;
}
@@ -2236,8 +2724,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;
}
/*
@@ -2253,6 +2741,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
)
@@ -2260,24 +2749,51 @@ 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 avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
{
- int i, count, ret, read_size, j;
+ int i, count, ret, 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 :
@@ -2294,7 +2810,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);
@@ -2304,6 +2820,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;
}
@@ -2322,7 +2841,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
@@ -2331,9 +2850,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)
@@ -2351,13 +2872,20 @@ 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)
+ av_log(ic, AV_LOG_WARNING,
+ "Stream #%d: not enough frames to estimate rate; "
+ "consider increasing probesize\n", i);
break;
}
@@ -2369,35 +2897,6 @@ 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;
}
@@ -2417,7 +2916,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);
@@ -2444,14 +2943,56 @@ 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 >= ic->max_analyze_duration) {
+ av_log(ic, AV_LOG_WARNING, "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->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->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) {
@@ -2479,6 +3020,44 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
count++;
}
+ if (flush_codecs) {
+ AVPacket empty_pkt = { 0 };
+ int err = 0;
+ av_init_packet(&empty_pkt);
+
+ 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];
+
+ /* 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, NULL));
+
+ if (err < 0) {
+ av_log(ic, AV_LOG_INFO,
+ "decoding for stream %d failed\n", st->index);
+ }
+ }
+
+ 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;
+ }
+ }
+ }
+
// close codecs which were opened in try_decode_frame()
for(i=0;i<ic->nb_streams;i++) {
st = ic->streams[i];
@@ -2487,16 +3066,20 @@ 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;
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*/
@@ -2514,6 +3097,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);
@@ -2533,27 +3161,39 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
}
}
+ if(ic->probesize)
estimate_timings(ic, old_offset);
compute_chapters_end(ic);
find_stream_info_err:
for (i=0; i < ic->nb_streams; i++) {
+ st = ic->streams[i];
if (ic->streams[i]->codec)
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;
}
@@ -2565,12 +3205,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;
@@ -2594,9 +3234,16 @@ int av_find_best_stream(AVFormatContext *ic,
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) {
@@ -2630,32 +3277,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);
@@ -2666,7 +3322,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);
@@ -2674,6 +3330,13 @@ 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;
@@ -2697,7 +3360,17 @@ 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;
@@ -2717,6 +3390,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) {
@@ -2730,9 +3404,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);
@@ -2743,6 +3419,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;
@@ -2769,6 +3448,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;
}
@@ -2839,8 +3523,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");
+ }
}
}
}
@@ -2854,7 +3551,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)
@@ -2870,13 +3567,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)
@@ -2926,8 +3627,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;
@@ -3109,11 +3811,27 @@ static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt, int
av_hex_dump(f, pkt->data, pkt->size);
}
+#if FF_API_PKT_DUMP
+void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload)
+{
+ AVRational tb = { 1, AV_TIME_BASE };
+ pkt_dump_internal(NULL, f, 0, pkt, dump_payload, tb);
+}
+#endif
+
void av_pkt_dump2(FILE *f, AVPacket *pkt, int dump_payload, AVStream *st)
{
pkt_dump_internal(NULL, f, 0, pkt, dump_payload, st->time_base);
}
+#if FF_API_PKT_DUMP
+void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt, int dump_payload)
+{
+ AVRational tb = { 1, AV_TIME_BASE };
+ pkt_dump_internal(avcl, NULL, level, pkt, dump_payload, tb);
+}
+#endif
+
void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload,
AVStream *st)
{
@@ -3127,7 +3845,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;
@@ -3149,8 +3867,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
@@ -3159,9 +3880,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 '@' */
}
@@ -3230,6 +3952,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)
{
@@ -3241,10 +3971,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;
}
@@ -3307,6 +4038,10 @@ 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);
}
@@ -3445,20 +4180,14 @@ void ff_make_absolute_url(char *buf, int size, const char *base,
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)
@@ -3547,6 +4276,201 @@ const struct AVCodecTag *avformat_get_riff_audio_tags(void)
return ff_codec_wav_tags;
}
+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);
+ st->codec->extradata_size = 0;
+ st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codec->extradata)
+ return;
+ memcpy(st->codec->extradata, data, size);
+ st->codec->extradata_size = size;
+}
+
static int match_host_pattern(const char *pattern, const char *hostname)
{
int len_p, len_h;
diff --git a/libavformat/vc1test.c b/libavformat/vc1test.c
index 859188f..7c6bcde 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
*/
@@ -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 abe8c6b..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"
@@ -63,7 +63,6 @@ static int vc1test_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_wl32(pb, pkt->size | ((pkt->flags & AV_PKT_FLAG_KEY) ? 0x80000000 : 0));
avio_wl32(pb, pkt->pts);
avio_write(pb, pkt->data, pkt->size);
- avio_flush(pb);
ctx->frames++;
return 0;
@@ -83,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 4ebf078..e9fd748 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 0
-#define LIBAVFORMAT_VERSION_MICRO 1
+#define LIBAVFORMAT_VERSION_MINOR 7
+#define LIBAVFORMAT_VERSION_MICRO 100
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \
@@ -49,4 +49,34 @@
* the public API and may change, break or disappear at any time.
*/
+#ifndef FF_API_OLD_AVIO
+#define FF_API_OLD_AVIO (LIBAVFORMAT_VERSION_MAJOR < 55)
+#endif
+#ifndef FF_API_PKT_DUMP
+#define FF_API_PKT_DUMP (LIBAVFORMAT_VERSION_MAJOR < 54)
+#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
--- /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 4e06513..62215fc 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
*/
@@ -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..9b38e6a 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
*/
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
--- /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 ab1042a..1ce5359 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
@@ -175,6 +180,10 @@ static int vqf_read_header(AVFormatContext *s)
break;
default:
st->codec->sample_rate = rate_flag*1000;
+ if (st->codec->sample_rate <= 0) {
+ av_log(s, AV_LOG_ERROR, "sample rate %d is invalid\n", st->codec->sample_rate);
+ return -1;
+ }
break;
}
diff --git a/libavformat/w64.c b/libavformat/w64.c
new file mode 100644
index 0000000..ef2d90a
--- /dev/null
+++ b/libavformat/w64.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2009 Daniel Verkamp
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "w64.h"
+
+const uint8_t ff_w64_guid_riff[16] = {
+ 'r', 'i', 'f', 'f',
+ 0x2E, 0x91, 0xCF, 0x11, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00
+};
+
+const uint8_t ff_w64_guid_wave[16] = {
+ 'w', 'a', 'v', 'e',
+ 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
+
+const uint8_t ff_w64_guid_fmt [16] = {
+ 'f', 'm', 't', ' ',
+ 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
+
+const uint8_t ff_w64_guid_fact[16] = { 'f', 'a', 'c', 't',
+ 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
+
+const uint8_t ff_w64_guid_data[16] = {
+ 'd', 'a', 't', 'a',
+ 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
+
+const uint8_t ff_w64_guid_summarylist[16] = {
+ 0xBC, 0x94, 0x5F, 0x92,
+ 0x5A, 0x52, 0xD2, 0x11, 0x86, 0xDC, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
diff --git a/libavformat/w64.h b/libavformat/w64.h
new file mode 100644
index 0000000..0ec3fa9
--- /dev/null
+++ b/libavformat/w64.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFORMAT_W64_H
+#define AVFORMAT_W64_H
+
+#include <stdint.h>
+
+extern const uint8_t ff_w64_guid_riff[16];
+extern const uint8_t ff_w64_guid_wave[16];
+extern const uint8_t ff_w64_guid_fmt [16];
+extern const uint8_t ff_w64_guid_fact[16];
+extern const uint8_t ff_w64_guid_data[16];
+extern const uint8_t ff_w64_guid_summarylist[16];
+
+#endif /* AVFORMAT_W64_H */
diff --git a/libavformat/wavdec.c b/libavformat/wavdec.c
index a3471fd..874847e 100644
--- a/libavformat/wavdec.c
+++ b/libavformat/wavdec.c
@@ -6,20 +6,20 @@
* RF64 demuxer
* Copyright (c) 2009 Daniel Verkamp
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,10 +35,22 @@
#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;
} WAVDemuxContext;
#if CONFIG_WAV_DEMUXER
@@ -52,7 +64,9 @@ static int64_t next_tag(AVIOContext *pb, uint32_t *tag)
/* RIFF chunks are always on a even offset. */
static int64_t wav_seek_tag(AVIOContext *s, int64_t offset, int whence)
{
- return avio_seek(s, offset + (offset & 1), whence);
+ offset += offset < INT64_MAX && offset & 1;
+
+ return avio_seek(s, offset, whence);
}
/* return the size of the found tag */
@@ -62,8 +76,8 @@ static int64_t find_tag(AVIOContext *pb, uint32_t tag1)
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;
@@ -90,6 +104,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 +125,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 +189,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 +244,8 @@ static int wav_read_header(AVFormatContext *s)
int ret, got_fmt = 0;
int64_t next_tag_ofs, data_ofs = -1;
+ wav->smv_data_ofs = -1;
+
/* check RIFF header */
tag = avio_rl32(pb);
@@ -235,7 +261,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 +274,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,15 +326,44 @@ 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");
+ 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_MJPEG;
+ vst->codec->width = avio_rl24(pb);
+ vst->codec->height = avio_rl24(pb);
+ 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);
+ 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;
}
@@ -327,7 +384,7 @@ break_loop:
avio_seek(pb, data_ofs, SEEK_SET);
if (!sample_count && st->codec->channels &&
- av_get_bits_per_sample(st->codec->codec_id))
+ 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));
@@ -349,23 +406,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 +427,76 @@ 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 = s->streams[0]->cur_dts;
+ video_dts = s->streams[1]->cur_dts;
+ if (audio_dts != AV_NOPTS_VALUE && video_dts != AV_NOPTS_VALUE) {
+ audio_dts = av_rescale_q(audio_dts, s->streams[0]->time_base, AV_TIME_BASE_Q);
+ video_dts = av_rescale_q(video_dts, s->streams[1]->time_base, AV_TIME_BASE_Q);
+ wav->smv_last_stream = video_dts >= audio_dts;
+ }
+ 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_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)
+ 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 +518,18 @@ 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);
+ wav->smv_block = smv_timestamp / wav->smv_frames_per_jpeg;
+ }
st = s->streams[0];
switch (st->codec->codec_id) {
@@ -422,6 +545,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 +568,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 +586,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 +594,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 +602,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;
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ if (!memcmp(guid, ff_w64_guid_fmt, 16)) {
+ /* subtract chunk header size - normal wav file doesn't count it */
+ ret = ff_get_wav_header(pb, st->codec, size - 24);
+ if (ret < 0)
+ return ret;
+ avio_skip(pb, FFALIGN(size, INT64_C(8)) - size);
- avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ } else if (!memcmp(guid, ff_w64_guid_fact, 16)) {
+ int64_t samples;
- size = find_guid(pb, guid_data);
- if (size < 0) {
- av_log(s, AV_LOG_ERROR, "could not find data guid\n");
- return AVERROR_INVALIDDATA;
+ samples = avio_rl64(pb);
+ if (samples > 0)
+ st->duration = samples;
+ } else if (!memcmp(guid, ff_w64_guid_data, 16)) {
+ wav->data_end = avio_tell(pb) + size - 24;
+
+ data_ofs = avio_tell(pb);
+ if (!pb->seekable)
+ break;
+
+ avio_skip(pb, size - 24);
+ } else if (!memcmp(guid, ff_w64_guid_summarylist, 16)) {
+ int64_t start, end, cur;
+ uint32_t count, chunk_size, i;
+
+ start = avio_tell(pb);
+ end = start + size;
+ 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, size - 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..694a020
--- /dev/null
+++ b/libavformat/webvttdec.c
@@ -0,0 +1,176 @@
+/*
+ * 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"
+
+typedef struct {
+ FFDemuxSubtitlesQueue q;
+} 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;
+
+ 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;
+ //const char *settings = NULL;
+ 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), silently skip it */
+ for (i = 0; p[i] && p[i] != '\n'; i++) {
+ if (!strncmp(p + i, "-->", 3)) {
+ identifier = NULL;
+ break;
+ }
+ }
+ if (identifier)
+ p += strcspn(p, "\n");
+
+ /* 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, TODO: store in side_data */
+ p += strcspn(p, "\n\t ");
+ while (*p == '\t' || *p == ' ')
+ p++;
+ if (*p != '\n') {
+ //settings = p;
+ p += strcspn(p, "\n");
+ }
+ 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;
+ }
+
+ 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;
+}
+
+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",
+};
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 7c9cb0d..c996dad 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
*/
@@ -131,10 +131,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) {
- av_free(st->codec->extradata);
+ 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]);
@@ -177,18 +175,15 @@ static int wsvqa_read_packet(AVFormatContext *s,
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:
@@ -238,7 +233,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
index 23b662d..5b1e61b 100644
--- a/libavformat/wtv.c
+++ b/libavformat/wtv.c
@@ -1,1102 +1,82 @@
/*
- * Windows Television (WTV) demuxer
+ * Windows Television (WTV)
* Copyright (c) 2010-2011 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/**
- * @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
+#include "wtv.h"
-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;
-
-/**
- * @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)) &&
- avio_seek(pb, (int64_t)wf->sectors[i] << WTV_SECTOR_BITS, SEEK_SET) < 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 ||
- avio_seek(pb, ((int64_t)wf->sectors[offset >> wf->sector_bits] << WTV_SECTOR_BITS)
- + (offset & ((1 << wf->sector_bits) - 1)), SEEK_SET) < 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 (avio_seek(s->pb, first_sector << WTV_SECTOR_BITS, SEEK_SET) < 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(nb_sectors1 << WTV_SECTOR_BITS);
- if (!wf->sectors) {
- av_free(wf);
- return NULL;
- }
- wf->nb_sectors = 0;
- for (i = 0; i < nb_sectors1; i++) {
- if (avio_seek(s->pb, (int64_t)sectors1[i] << WTV_SECTOR_BITS, SEEK_SET) < 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 (avio_seek(s->pb, (int64_t)wf->sectors[0] << WTV_SECTOR_BITS, SEEK_SET) < 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 =
+/* 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};
-
-/**
- * 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 (buf + 48 + name_size > buf_end) {
- 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 =
+const ff_asf_guid ff_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 =
+const ff_asf_guid ff_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 =
+const ff_asf_guid ff_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 =
+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};
-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 =
+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};
-static const ff_asf_guid mediatype_video =
+const ff_asf_guid ff_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 =
+const ff_asf_guid ff_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);
- 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[] =
+const uint8_t ff_timeline_le16[] =
{'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e', 0};
-static const uint8_t table_0_entries_legacy_attrib_le16[] =
+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};
-static const uint8_t table_0_entries_time_le16[] =
+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};
-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);
-
- avio_seek(s->pb, root_sector << WTV_SECTOR_BITS, SEEK_SET);
- 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;
+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};
- 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;
-}
+/* 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};
-static int read_close(AVFormatContext *s)
-{
- WtvContext *wtv = s->priv_data;
- av_free(wtv->index_entries);
- wtvfile_close(wtv->pb);
- return 0;
-}
+/* 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};
-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,
+const AVCodecGuid ff_video_guids[] = {
+ {AV_CODEC_ID_MPEG2VIDEO, {0x26,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}},
+ {AV_CODEC_ID_NONE}
};
diff --git a/libavformat/wtv.h b/libavformat/wtv.h
new file mode 100644
index 0000000..efe90d6
--- /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/wtvdec.c b/libavformat/wtvdec.c
new file mode 100644
index 0000000..e423370
--- /dev/null
+++ b/libavformat/wtvdec.c
@@ -0,0 +1,1084 @@
+/*
+ * 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;
+
+/**
+ * @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)) &&
+ avio_seek(pb, (int64_t)wf->sectors[i] << WTV_SECTOR_BITS, SEEK_SET) < 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 ||
+ avio_seek(pb, ((int64_t)wf->sectors[offset >> wf->sector_bits] << WTV_SECTOR_BITS)
+ + (offset & ((1 << wf->sector_bits) - 1)), SEEK_SET) < 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 (avio_seek(s->pb, (int64_t)first_sector << WTV_SECTOR_BITS, SEEK_SET) < 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(nb_sectors1 << WTV_SECTOR_BITS);
+ if (!wf->sectors) {
+ av_free(wf);
+ return NULL;
+ }
+ wf->nb_sectors = 0;
+ for (i = 0; i < nb_sectors1; i++) {
+ if (avio_seek(s->pb, (int64_t)sectors1[i] << WTV_SECTOR_BITS, SEEK_SET) < 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 (avio_seek(s->pb, (int64_t)wf->sectors[0] << WTV_SECTOR_BITS, SEEK_SET) < 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 (buf + 48 + (int64_t)name_size > buf_end || name_size<0) {
+ 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;
+ 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);
+
+ avio_seek(s->pb, (int64_t)root_sector << WTV_SECTOR_BITS, SEEK_SET);
+ 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..410a2dc
--- /dev/null
+++ b/libavformat/wtvenc.c
@@ -0,0 +1,809 @@
+/*
+ * 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 "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;
+
+static int write_pad(AVIOContext *pb, int size)
+{
+ for (; size > 0; size--)
+ avio_w8(pb, 0);
+ return 0;
+}
+
+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 f6b96d5..ad6e8ac 100644
--- a/libavformat/wv.c
+++ b/libavformat/wv.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
*/
@@ -73,8 +73,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;
@@ -255,7 +258,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->samples;
+ if (wc->samples != 0xFFFFFFFFu)
+ st->duration = wc->samples;
if (s->pb->seekable) {
int64_t cur = avio_tell(s->pb);
@@ -276,7 +280,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)) < 0)
@@ -340,7 +344,7 @@ static int wv_read_packet(AVFormatContext *s, AVPacket *pkt)
pkt->stream_index = 0;
wc->block_parsed = 1;
pkt->pts = wc->soff;
- block_samples = AV_RN32(wc->extra);
+ block_samples = AV_RL32(wc->extra);
if (block_samples > INT32_MAX)
av_log(s, AV_LOG_WARNING,
"Too many samples in block: %"PRIu32"\n", block_samples);
diff --git a/libavformat/wvenc.c b/libavformat/wvenc.c
new file mode 100644
index 0000000..c33d430
--- /dev/null
+++ b/libavformat/wvenc.c
@@ -0,0 +1,143 @@
+/*
+ * WavPack 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 "internal.h"
+#include "avio_internal.h"
+#include "apetag.h"
+
+#define WV_EXTRA_SIZE 12
+#define WV_END_BLOCK 0x1000
+
+typedef struct{
+ uint32_t duration;
+} WVMuxContext;
+
+static int write_header(AVFormatContext *s)
+{
+ 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_WAVPACK) {
+ av_log(s, AV_LOG_ERROR, "unsupported codec\n");
+ return AVERROR(EINVAL);
+ }
+ if (codec->extradata_size > 0) {
+ avpriv_report_missing_feature(s, "remuxing from matroska container");
+ return AVERROR_PATCHWELCOME;
+ }
+ avpriv_set_pts_info(s->streams[0], 64, 1, codec->sample_rate);
+
+ return 0;
+}
+
+static int write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ WVMuxContext *wc = s->priv_data;
+ AVCodecContext *codec = s->streams[0]->codec;
+ AVIOContext *pb = s->pb;
+ uint64_t size;
+ uint32_t flags;
+ uint32_t left = pkt->size;
+ uint8_t *ptr = pkt->data;
+ int off = codec->channels > 2 ? 4 : 0;
+
+ /* FIXME: Simplify decoder/demuxer so bellow code can support midstream
+ * change of stream parameters */
+ wc->duration += pkt->duration;
+ ffio_wfourcc(pb, "wvpk");
+ if (off) {
+ size = AV_RL32(pkt->data);
+ if (size <= 12)
+ return AVERROR_INVALIDDATA;
+ size -= 12;
+ } else {
+ size = pkt->size;
+ }
+
+ if (size + off > left)
+ return AVERROR_INVALIDDATA;
+
+ avio_wl32(pb, size + 12);
+ avio_wl16(pb, 0x410);
+ avio_w8(pb, 0);
+ avio_w8(pb, 0);
+ avio_wl32(pb, -1);
+ avio_wl32(pb, pkt->pts);
+ ptr += off; left -= off;
+ flags = AV_RL32(ptr + 4);
+ avio_write(pb, ptr, size);
+ ptr += size; left -= size;
+
+ while (!(flags & WV_END_BLOCK) &&
+ (left >= 4 + WV_EXTRA_SIZE)) {
+ ffio_wfourcc(pb, "wvpk");
+ size = AV_RL32(ptr);
+ ptr += 4; left -= 4;
+ if (size < 24 || size - 24 > left)
+ return AVERROR_INVALIDDATA;
+ avio_wl32(pb, size);
+ avio_wl16(pb, 0x410);
+ avio_w8(pb, 0);
+ avio_w8(pb, 0);
+ avio_wl32(pb, -1);
+ avio_wl32(pb, pkt->pts);
+ flags = AV_RL32(ptr + 4);
+ avio_write(pb, ptr, WV_EXTRA_SIZE);
+ ptr += WV_EXTRA_SIZE; left -= WV_EXTRA_SIZE;
+ avio_write(pb, ptr, size - 24);
+ ptr += size - 24; left -= size - 24;
+ }
+
+ return 0;
+}
+
+static int write_trailer(AVFormatContext *s)
+{
+ WVMuxContext *wc = s->priv_data;
+ AVIOContext *pb = s->pb;
+
+ ff_ape_write(s);
+
+ if (pb->seekable) {
+ avio_seek(pb, 12, SEEK_SET);
+ avio_wl32(pb, wc->duration);
+ avio_flush(pb);
+ }
+
+ return 0;
+}
+
+AVOutputFormat ff_wv_muxer = {
+ .name = "wv",
+ .long_name = NULL_IF_CONFIG_SMALL("WavPack"),
+ .priv_data_size = sizeof(WVMuxContext),
+ .extensions = "wv",
+ .audio_codec = AV_CODEC_ID_WAVPACK,
+ .video_codec = AV_CODEC_ID_NONE,
+ .write_header = write_header,
+ .write_packet = write_packet,
+ .write_trailer = write_trailer,
+};
diff --git a/libavformat/xa.c b/libavformat/xa.c
index 57a36bc..437de3f 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
*/
diff --git a/libavformat/xmv.c b/libavformat/xmv.c
index bc7c3c9..672b6d9 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,81 +32,79 @@
#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)
-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)
@@ -130,8 +128,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;
}
@@ -183,10 +180,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);
@@ -194,25 +187,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 = 36 * 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 = 36 * 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;
@@ -220,11 +211,11 @@ 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) {
+ if (!packet->channels || !packet->sample_rate) {
av_log(s, AV_LOG_ERROR, "Invalid parameters for audio track %d.\n",
audio_track);
ret = AVERROR_INVALIDDATA;
@@ -238,15 +229,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;
@@ -254,7 +245,7 @@ static int xmv_read_header(AVFormatContext *s)
}
- /** Initialize the packet context */
+ /* Initialize the packet context */
xmv->next_packet_offset = avio_tell(pb);
xmv->next_packet_size = this_packet_size - xmv->next_packet_offset;
@@ -303,7 +294,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);
@@ -334,7 +325,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 */
@@ -354,9 +345,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 */
@@ -384,7 +375,7 @@ 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);
@@ -408,6 +399,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)
@@ -460,7 +454,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;
@@ -485,7 +479,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)
@@ -500,17 +494,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 52e423c..0d40bd7 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
*/
@@ -198,6 +198,12 @@ static int xwma_read_header(AVFormatContext *s)
/* Estimate the duration from the total number of output bytes. */
const uint64_t total_decoded_bytes = dpds_table[dpds_table_size - 1];
+
+ if(!bytes_per_sample) {
+ av_log(s, AV_LOG_ERROR, "bytes_per_sample is 0\n");
+ return AVERROR_INVALIDDATA;
+ }
+
st->duration = total_decoded_bytes / bytes_per_sample;
/* Use the dpds data to build a seek table. We can only do this after
diff --git a/libavformat/yop.c b/libavformat/yop.c
index 5fe6bdc..c84deea 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,6 +65,8 @@ 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;
@@ -99,6 +106,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) {
@@ -126,8 +135,7 @@ static int yop_read_packet(AVFormatContext *s, AVPacket *pkt)
if (yop->video_packet.data) {
*pkt = yop->video_packet;
- yop->video_packet.data = NULL;
- yop->video_packet.size = 0;
+ memset(&yop->video_packet, 0, sizeof(yop->video_packet));
pkt->data[0] = yop->odd_frame;
pkt->flags |= AV_PKT_FLAG_KEY;
yop->odd_frame ^= 1;
diff --git a/libavformat/yuv4mpeg.c b/libavformat/yuv4mpeg.c
index 699a63a..bf48230 100644
--- a/libavformat/yuv4mpeg.c
+++ b/libavformat/yuv4mpeg.c
@@ -2,36 +2,32 @@
* 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
*/
#include "libavutil/pixdesc.h"
#include "avformat.h"
#include "internal.h"
+#include "libavutil/pixdesc.h"
#define Y4M_MAGIC "YUV4MPEG2"
#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 +53,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 +84,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 +143,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 +151,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,12 +175,45 @@ 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);
@@ -146,7 +231,7 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
ptr2 += picture->linesize[2];
}
}
- avio_flush(pb);
+
return 0;
}
@@ -162,15 +247,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 +302,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 +320,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 +328,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 +343,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 +367,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 +423,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 +445,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 +524,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 +554,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 +585,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 +602,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/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 b79def9..c159e33 100644
--- a/libavresample/utils.c
+++ b/libavresample/utils.c
@@ -20,7 +20,7 @@
#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"
@@ -626,10 +626,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/x86/audio_convert.asm b/libavresample/x86/audio_convert.asm
index 1af1429..1d125c2 100644
--- a/libavresample/x86/audio_convert.asm
+++ b/libavresample/x86/audio_convert.asm
@@ -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_mix.asm b/libavresample/x86/audio_mix.asm
index 8a298e2..9353593 100644
--- a/libavresample/x86/audio_mix.asm
+++ b/libavresample/x86/audio_mix.asm
@@ -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/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 cc7e4dc..e9411c5 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/libavutil/Makefile b/libavutil/Makefile
index 910f6f0..f7852ee 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 \
@@ -42,11 +46,15 @@ HEADERS = adler32.h \
samplefmt.h \
sha.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 +69,7 @@ OBJS = adler32.o \
avstring.o \
base64.o \
blowfish.o \
+ bprint.o \
buffer.o \
channel_layout.o \
cpu.o \
@@ -72,6 +81,7 @@ OBJS = adler32.o \
file.o \
float_dsp.o \
frame.o \
+ hash.o \
hmac.o \
imgutils.o \
intfloat_readwrite.o \
@@ -83,6 +93,7 @@ OBJS = adler32.o \
mathematics.o \
md5.o \
mem.o \
+ murmur3.o \
dict.o \
opt.o \
parseutils.o \
@@ -93,11 +104,14 @@ OBJS = adler32.o \
samplefmt.o \
sha.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/%)
@@ -106,6 +120,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 \
@@ -113,17 +128,30 @@ TESTPROGS = adler32 \
avstring \
base64 \
blowfish \
+ bprint \
cpu \
crc \
des \
+ error \
eval \
+ file \
fifo \
hmac \
lfg \
lls \
md5 \
+ murmur3 \
opt \
+ pca \
parseutils \
+ random_seed \
+ rational \
sha \
tree \
xtea \
+
+TESTPROGS-$(HAVE_LZO1X_999_COMPRESS) += lzo
+
+TOOLS = ffadler ffeval ffescape
+
+$(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..e926ef6 100644
--- a/libavutil/adler32.h
+++ b/libavutil/adler32.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/aes.c b/libavutil/aes.c
index 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 a181789..6061e47 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/float_dsp_arm.h b/libavutil/arm/float_dsp_arm.h
index 81fad3e..f3fafe3 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 e45969e..94d9c2b 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_vfp.c b/libavutil/arm/float_dsp_init_vfp.c
index b6a226a..21db094 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_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 292a0a1..64b46f6 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))
@@ -52,6 +62,10 @@
# define av_pure
#endif
+#ifndef av_restrict
+#define av_restrict restrict
+#endif
+
#if AV_GCC_VERSION_AT_LEAST(2,6)
# define av_const __attribute__((const))
#else
@@ -76,6 +90,24 @@
# 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")
+#else
+# define AV_NOWARN_DEPRECATED(code) code
+#endif
+#endif
+
+
#if defined(__GNUC__)
# define av_unused __attribute__((unused))
#else
@@ -99,7 +131,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.h b/libavutil/audio_fifo.h
index 8c76388..55a538e 100644
--- a/libavutil/audio_fifo.h
+++ b/libavutil/audio_fifo.h
@@ -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 818fbdb..cf9be2a 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';
@@ -270,7 +343,8 @@ int main(void)
printf("Testing av_get_token()\n");
for (i = 0; i < FF_ARRAY_ELEMS(strings); i++) {
- const char *p = strings[i], *q;
+ const char *p = strings[i];
+ char *q;
printf("|%s|", p);
q = av_get_token(&p, ":");
printf(" -> |%s|", q);
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 33f9bea..6f307d6 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,25 +29,26 @@
/**
* @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 @subpage libavfilter graph based frame editing 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
*/
/**
* @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
@@ -109,43 +110,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
* @{
*/
@@ -185,6 +149,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
* @{
*
@@ -205,7 +175,7 @@ enum AVMediaType {
* @}
* @defgroup lavu_time Timestamp specific
*
- * Libav internal timebase and timestamp definitions
+ * FFmpeg internal timebase and timestamp definitions
*
* @{
*/
@@ -217,7 +187,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
@@ -242,7 +212,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
@@ -264,8 +235,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 d16195f..87e2dfd 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,12 +244,34 @@ 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")
+ }
+ }
+
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 63cc404..5ad74c1 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
*/
@@ -294,24 +294,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)
{
@@ -358,17 +346,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..fd7611a
--- /dev/null
+++ b/libavutil/bprint.c
@@ -0,0 +1,339 @@
+/*
+ * 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 "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_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_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..df78916
--- /dev/null
+++ b/libavutil/bprint.h
@@ -0,0 +1,200 @@
+/*
+ * 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 "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 char c n times to a print buffer.
+ */
+void av_bprint_chars(AVBPrint *buf, char c, unsigned n);
+
+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..e582760 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,11 +97,10 @@ 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 }
};
static uint64_t get_channel_layout_single(const char *name, int name_len)
@@ -105,15 +109,15 @@ static uint64_t get_channel_layout_single(const char *name, int name_len)
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 ||
@@ -141,58 +145,60 @@ 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)
+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 +222,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 +246,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..2906098 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
@@ -141,6 +149,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 +163,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 +190,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..c7c32fd 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;
@@ -148,7 +176,7 @@ 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;
+ 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(x >> 32);
}
#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))
@@ -252,7 +300,7 @@ static av_always_inline av_const int av_popcount64_c(uint64_t x)
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 +418,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 +448,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 23016d6..a1d1547 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
*/
@@ -20,12 +20,15 @@
#include "config.h"
#include "opt.h"
-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;
@@ -33,16 +36,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)
@@ -109,6 +111,68 @@ 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);
+}
#ifdef TEST
#include <stdio.h>
diff --git a/libavutil/cpu.h b/libavutil/cpu.h
index 4929512..c8f34e0 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
@@ -45,7 +43,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_ALTIVEC 0x0001 ///< standard
@@ -58,24 +60,46 @@
/**
* 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);
+
/* The following CPU-specific functions shall not be called directly. */
int ff_get_cpu_flags_arm(void);
int ff_get_cpu_flags_ppc(void);
diff --git a/libavutil/crc.c b/libavutil/crc.c
index 2cdf588..9ee5efe 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
*/
diff --git a/libavutil/crc.h b/libavutil/crc.h
index 0540619..2bdfca8 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
*/
diff --git a/libavutil/des.c b/libavutil/des.c
index 01cb10b..a7a5074 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;
@@ -411,10 +411,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 0ca7472..3abc3e5 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,11 +26,13 @@
* see http://joe.hotchkiss.com/programming/eval/eval.html
*/
+#include <float.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 {
@@ -47,7 +49,7 @@ 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) };
@@ -75,11 +77,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') {
@@ -127,10 +141,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 {
@@ -139,9 +154,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) {
@@ -159,29 +180,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);
}
}
}
@@ -195,6 +304,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);
}
@@ -227,6 +338,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) {
@@ -257,6 +377,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);
@@ -277,6 +401,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;
@@ -285,18 +410,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])) {
@@ -325,7 +462,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)
@@ -350,7 +487,7 @@ static int parse_dB(AVExpr **e, Parser *p, int *sign)
for example, -3dB is not the same as -(3dB) */
if (*p->s == '-') {
char *next;
- strtod(p->s, &next);
+ double av_unused v = strtod(p->s, &next);
if (next != p->s && next[0] == 'd' && next[1] == 'B') {
*sign = 0;
return parse_primary(e, p);
@@ -372,7 +509,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);
@@ -399,7 +536,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);
@@ -422,7 +559,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);
@@ -451,7 +588,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);
@@ -482,8 +619,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];
}
}
@@ -531,6 +681,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);
@@ -540,6 +691,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;
@@ -651,6 +803,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..a1d1fe3 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
*/
diff --git a/libavutil/fifo.c b/libavutil/fifo.c
index 2684899..bafa9e9 100644
--- a/libavutil/fifo.c
+++ b/libavutil/fifo.c
@@ -3,20 +3,20 @@
* 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 "common.h"
@@ -25,7 +25,7 @@
AVFifoBuffer *av_fifo_alloc(unsigned int size)
{
AVFifoBuffer *f= av_mallocz(sizeof(AVFifoBuffer));
- if(!f)
+ if (!f)
return NULL;
f->buffer = av_malloc(size);
f->end = f->buffer + size;
@@ -37,8 +37,8 @@ AVFifoBuffer *av_fifo_alloc(unsigned int size)
void av_fifo_free(AVFifoBuffer *f)
{
- if(f){
- av_free(f->buffer);
+ if (f) {
+ av_freep(&f->buffer);
av_free(f);
}
}
@@ -59,45 +59,64 @@ int av_fifo_space(AVFifoBuffer *f)
return f->end - f->buffer - av_fifo_size(f);
}
-int av_fifo_realloc2(AVFifoBuffer *f, unsigned int new_size) {
- unsigned int old_size= f->end - f->buffer;
+int av_fifo_realloc2(AVFifoBuffer *f, unsigned int new_size)
+{
+ unsigned int old_size = f->end - f->buffer;
- if(old_size < new_size){
- int len= av_fifo_size(f);
- AVFifoBuffer *f2= av_fifo_alloc(new_size);
+ if (old_size < new_size) {
+ int len = av_fifo_size(f);
+ 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;
av_free(f->buffer);
- *f= *f2;
+ *f = *f2;
av_free(f2);
}
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);
- if(func) {
- if(func(src, f->wptr, len) <= 0)
+ int len = FFMIN(f->end - wptr, size);
+ if (func) {
+ 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;
}
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 ce02487..41850f8 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
*/
@@ -135,3 +135,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..b47ef80 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() cant 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/float_dsp.c b/libavutil/float_dsp.c
index 3eda27a..64bd2e6 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 cf60eb3..11601ad 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,51 @@
#include "mem.h"
#include "samplefmt.h"
+#define MAKE_ACCESSORS(str, name, type, field) \
+ type av_##name##_get_##field(const str *s) { return s->field; } \
+ void av_##name##_set_##field(str *s, type v) { s->field = v; }
+
+MAKE_ACCESSORS(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)
+
+#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;
+}
+
static void get_frame_defaults(AVFrame *frame)
{
if (frame->extended_data != frame->data)
@@ -33,7 +79,13 @@ static void get_frame_defaults(AVFrame *frame)
memset(frame, 0, sizeof(*frame));
- frame->pts = AV_NOPTS_VALUE;
+ frame->pts =
+ frame->pkt_dts =
+ frame->pkt_pts = AV_NOPTS_VALUE;
+ av_frame_set_best_effort_timestamp(frame, AV_NOPTS_VALUE);
+ av_frame_set_pkt_duration (frame, 0);
+ av_frame_set_pkt_pos (frame, -1);
+ av_frame_set_pkt_size (frame, -1);
frame->key_frame = 1;
frame->sample_aspect_ratio = (AVRational){ 0, 1 };
frame->format = -1; /* unknown */
@@ -47,6 +99,7 @@ AVFrame *av_frame_alloc(void)
if (!frame)
return NULL;
+ frame->extended_data = NULL;
get_frame_defaults(frame);
return frame;
@@ -83,11 +136,11 @@ static int get_video_buffer(AVFrame *frame, int 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 +164,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,
@@ -178,6 +232,7 @@ int av_frame_ref(AVFrame *dst, 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 +247,8 @@ int av_frame_ref(AVFrame *dst, 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 {
@@ -231,12 +287,13 @@ int av_frame_ref(AVFrame *dst, 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 +343,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);
}
@@ -329,6 +389,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 +397,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 +435,22 @@ 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;
+
+ av_dict_copy(&dst->metadata, src->metadata, 0);
memcpy(dst->error, src->error, sizeof(dst->error));
@@ -399,6 +471,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 +492,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 adc23b2..39a664f 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
*/
@@ -47,7 +47,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 +69,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];
@@ -84,6 +92,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.
*/
int linesize[AV_NUM_DATA_POINTERS];
@@ -151,7 +164,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;
@@ -347,9 +362,110 @@ 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;
+
+ /**
+ * 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);
+
+/**
* Allocate an AVFrame and set its fields to default values. The resulting
* struct must be freed using av_frame_free().
*
diff --git a/libavutil/hash.c b/libavutil/hash.c
new file mode 100644
index 0000000..03c7ca3
--- /dev/null
+++ b/libavutil/hash.c
@@ -0,0 +1,154 @@
+/*
+ * 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 "sha.h"
+
+#include "avstring.h"
+#include "error.h"
+#include "intreadwrite.h"
+#include "mem.h"
+
+enum hashtype {
+ MD5,
+ MURMUR3,
+ SHA160,
+ SHA224,
+ SHA256,
+ 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},
+ [SHA160] = {"SHA160", 20},
+ [SHA224] = {"SHA224", 28},
+ [SHA256] = {"SHA256", 32},
+ [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 SHA160:
+ case SHA224:
+ case SHA256: res->ctx = av_sha_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 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 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 SHA160:
+ case SHA224:
+ case SHA256: av_sha_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 SHA160:
+ case SHA224:
+ case SHA256: av_sha_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..7ecb3e7
--- /dev/null
+++ b/libavutil/hash.h
@@ -0,0 +1,78 @@
+/*
+ * 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);
+
+/**
+ * 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..c5a1c89 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
*/
diff --git a/libavutil/hmac.h b/libavutil/hmac.h
index 28c2062..aef84c6 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
*/
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
--- /dev/null
+++ b/libavutil/integer.c
@@ -0,0 +1,196 @@
+/*
+ * arbitrary precision integers
+ * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * arbitrary precision integers
+ * @author Michael Niedermayer <michaelni@gmx.at>
+ */
+
+#include "common.h"
+#include "integer.h"
+#include "avassert.h"
+
+AVInteger av_add_i(AVInteger a, AVInteger b){
+ int i, carry=0;
+
+ for(i=0; i<AV_INTEGER_SIZE; i++){
+ carry= (carry>>16) + a.v[i] + b.v[i];
+ a.v[i]= carry;
+ }
+ return a;
+}
+
+AVInteger av_sub_i(AVInteger a, AVInteger b){
+ int i, carry=0;
+
+ for(i=0; i<AV_INTEGER_SIZE; i++){
+ carry= (carry>>16) + a.v[i] - b.v[i];
+ a.v[i]= carry;
+ }
+ return a;
+}
+
+int av_log2_i(AVInteger a){
+ int i;
+
+ for(i=AV_INTEGER_SIZE-1; i>=0; i--){
+ if(a.v[i])
+ return av_log2_16bit(a.v[i]) + 16*i;
+ }
+ return -1;
+}
+
+AVInteger av_mul_i(AVInteger a, AVInteger b){
+ AVInteger out;
+ int i, j;
+ int na= (av_log2_i(a)+16) >> 4;
+ int nb= (av_log2_i(b)+16) >> 4;
+
+ memset(&out, 0, sizeof(out));
+
+ for(i=0; i<na; i++){
+ unsigned int carry=0;
+
+ if(a.v[i])
+ for(j=i; j<AV_INTEGER_SIZE && j-i<=nb; j++){
+ carry= (carry>>16) + out.v[j] + a.v[i]*b.v[j-i];
+ out.v[j]= carry;
+ }
+ }
+
+ return out;
+}
+
+int av_cmp_i(AVInteger a, AVInteger b){
+ int i;
+ int v= (int16_t)a.v[AV_INTEGER_SIZE-1] - (int16_t)b.v[AV_INTEGER_SIZE-1];
+ if(v) return (v>>16)|1;
+
+ for(i=AV_INTEGER_SIZE-2; i>=0; i--){
+ int v= a.v[i] - b.v[i];
+ if(v) return (v>>16)|1;
+ }
+ return 0;
+}
+
+AVInteger av_shr_i(AVInteger a, int s){
+ AVInteger out;
+ int i;
+
+ for(i=0; i<AV_INTEGER_SIZE; i++){
+ unsigned int index= i + (s>>4);
+ unsigned int v=0;
+ if(index+1<AV_INTEGER_SIZE) v = a.v[index+1]<<16;
+ if(index <AV_INTEGER_SIZE) v+= a.v[index ];
+ out.v[i]= v >> (s&15);
+ }
+ return out;
+}
+
+AVInteger av_mod_i(AVInteger *quot, AVInteger a, AVInteger b){
+ int i= av_log2_i(a) - av_log2_i(b);
+ AVInteger quot_temp;
+ if(!quot) quot = &quot_temp;
+
+ av_assert2((int16_t)a.v[AV_INTEGER_SIZE-1] >= 0 && (int16_t)b.v[AV_INTEGER_SIZE-1] >= 0);
+ av_assert2(av_log2_i(b)>=0);
+
+ if(i > 0)
+ b= av_shr_i(b, -i);
+
+ memset(quot, 0, sizeof(AVInteger));
+
+ while(i-- >= 0){
+ *quot= av_shr_i(*quot, -1);
+ if(av_cmp_i(a, b) >= 0){
+ a= av_sub_i(a, b);
+ quot->v[0] += 1;
+ }
+ b= av_shr_i(b, 1);
+ }
+ return a;
+}
+
+AVInteger av_div_i(AVInteger a, AVInteger b){
+ AVInteger quot;
+ av_mod_i(&quot, a, b);
+ return quot;
+}
+
+AVInteger av_int2i(int64_t a){
+ AVInteger out;
+ int i;
+
+ for(i=0; i<AV_INTEGER_SIZE; i++){
+ out.v[i]= a;
+ a>>=16;
+ }
+ return out;
+}
+
+int64_t av_i2int(AVInteger a){
+ int i;
+ int64_t out=(int8_t)a.v[AV_INTEGER_SIZE-1];
+
+ for(i= AV_INTEGER_SIZE-2; i>=0; i--){
+ out = (out<<16) + a.v[i];
+ }
+ return out;
+}
+
+#ifdef TEST
+
+const uint8_t ff_log2_tab[256]={
+ 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+};
+
+int main(void){
+ int64_t a,b;
+
+ for(a=7; a<256*256*256; a+=13215){
+ for(b=3; b<256*256*256; b+=27118){
+ AVInteger ai= av_int2i(a);
+ AVInteger bi= av_int2i(b);
+
+ av_assert0(av_i2int(ai) == a);
+ av_assert0(av_i2int(bi) == b);
+ av_assert0(av_i2int(av_add_i(ai,bi)) == a+b);
+ av_assert0(av_i2int(av_sub_i(ai,bi)) == a-b);
+ av_assert0(av_i2int(av_mul_i(ai,bi)) == a*b);
+ av_assert0(av_i2int(av_shr_i(ai, 9)) == a>>9);
+ av_assert0(av_i2int(av_shr_i(ai,-9)) == a<<9);
+ av_assert0(av_i2int(av_shr_i(ai, 17)) == a>>17);
+ av_assert0(av_i2int(av_shr_i(ai,-17)) == a<<17);
+ av_assert0(av_log2_i(ai) == av_log2(a));
+ av_assert0(av_i2int(av_div_i(ai,bi)) == a/b);
+ }
+ }
+ return 0;
+}
+#endif
diff --git a/libavutil/integer.h b/libavutil/integer.h
new file mode 100644
index 0000000..45f733c
--- /dev/null
+++ b/libavutil/integer.h
@@ -0,0 +1,86 @@
+/*
+ * arbitrary precision integers
+ * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * arbitrary precision integers
+ * @author Michael Niedermayer <michaelni@gmx.at>
+ */
+
+#ifndef AVUTIL_INTEGER_H
+#define AVUTIL_INTEGER_H
+
+#include <stdint.h>
+#include "common.h"
+
+#define AV_INTEGER_SIZE 8
+
+typedef struct AVInteger{
+ uint16_t v[AV_INTEGER_SIZE];
+} AVInteger;
+
+AVInteger av_add_i(AVInteger a, AVInteger b) av_const;
+AVInteger av_sub_i(AVInteger a, AVInteger b) av_const;
+
+/**
+ * Return the rounded-down value of the base 2 logarithm of the given
+ * AVInteger. This is simply the index of the most significant bit
+ * which is 1, or 0 if all bits are 0.
+ */
+int av_log2_i(AVInteger a) av_const;
+AVInteger av_mul_i(AVInteger a, AVInteger b) av_const;
+
+/**
+ * Return 0 if a==b, 1 if a>b and -1 if a<b.
+ */
+int av_cmp_i(AVInteger a, AVInteger b) av_const;
+
+/**
+ * bitwise shift
+ * @param s the number of bits by which the value should be shifted right,
+ may be negative for shifting left
+ */
+AVInteger av_shr_i(AVInteger a, int s) av_const;
+
+/**
+ * Return a % b.
+ * @param quot a/b will be stored here.
+ */
+AVInteger av_mod_i(AVInteger *quot, AVInteger a, AVInteger b);
+
+/**
+ * Return a/b.
+ */
+AVInteger av_div_i(AVInteger a, AVInteger b) av_const;
+
+/**
+ * Convert the given int64_t to an AVInteger.
+ */
+AVInteger av_int2i(int64_t a) av_const;
+
+/**
+ * Convert the given AVInteger to an int64_t.
+ * If the AVInteger is too large to fit into an int64_t,
+ * then only the least significant 64 bits will be used.
+ */
+int64_t av_i2int(AVInteger a) av_const;
+
+#endif /* AVUTIL_INTEGER_H */
diff --git a/libavutil/internal.h b/libavutil/internal.h
index 49534d4..c5835fb 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,6 +37,7 @@
#include "config.h"
#include "attributes.h"
#include "timer.h"
+#include "cpu.h"
#include "dict.h"
#if ARCH_X86
@@ -65,6 +66,8 @@
# define INT_BIT (CHAR_BIT * sizeof(int))
#endif
+#define FF_MEMORY_POISON 0x2a
+
// Some broken preprocessors need a second expansion
// to be forced to tokenize __VA_ARGS__
#define E1(x) x
@@ -127,12 +130,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.
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 246189b..dd6442a 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 f493076..c785d44 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 bd46b0c..15ff5f8 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,69 @@
#endif
#include <stdarg.h>
#include <stdlib.h>
-#include "avstring.h"
#include "avutil.h"
#include "common.h"
#include "internal.h"
#include "log.h"
+#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 +118,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,41 +141,88 @@ 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,
+ char part[3][LINE_SZ], int part_size, 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) {
+ part[0][0] = part[1][0] = part[2][0] = 0;
+ 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] ",
+ snprintf(part[0], part_size, "[%s @ %p] ",
(*parent)->item_name(parent), parent);
+ if(type) type[0] = get_category(parent);
}
}
- snprintf(line + strlen(line), sizeof(line) - strlen(line), "[%s @ %p] ",
+ snprintf(part[1], part_size, "[%s @ %p] ",
avc->item_name(ptr), ptr);
+ if(type) type[1] = get_category(ptr);
}
- vsnprintf(line + strlen(line), sizeof(line) - strlen(line), fmt, vl);
+ vsnprintf(part[2], part_size, fmt, vl);
+
+ if(*part[0] || *part[1] || *part[2])
+ *print_prefix = strlen(part[2]) && part[2][strlen(part[2]) - 1] == '\n';
+}
+
+void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl,
+ char *line, int line_size, int *print_prefix)
+{
+ char part[3][LINE_SZ];
+ format_line(ptr, level, fmt, vl, part, sizeof(part[0]), print_prefix, NULL);
+ snprintf(line, line_size, "%s%s%s", part[0], part[1], part[2]);
+}
+
+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];
+ char part[3][LINE_SZ];
+ char line[LINE_SZ];
+ static int is_atty;
+ int type[2];
- print_prefix = strlen(line) && line[strlen(line) - 1] == '\n';
+ if (level > av_log_level)
+ return;
+ format_line(ptr, level, fmt, vl, part, sizeof(part[0]), &print_prefix, type);
+ snprintf(line, sizeof(line), "%s%s%s", part[0], part[1], part[2]);
#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){
count++;
if (is_atty == 1)
fprintf(stderr, " Last message repeated %d times\r", count);
@@ -138,8 +232,13 @@ void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl)
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]);
+ colored_fputs(type[0], part[0]);
+ sanitize(part[1]);
+ colored_fputs(type[1], part[1]);
+ sanitize(part[2]);
+ colored_fputs(av_clip(level >> 3, 0, 6), part[2]);
}
static void (*av_log_callback)(void*, int, const char*, va_list) =
@@ -159,7 +258,8 @@ 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);
+ if(av_log_callback)
+ av_log_callback(avcl, level, fmt, vl);
}
int av_log_get_level(void)
@@ -182,23 +282,17 @@ void av_log_set_callback(void (*callback)(void*, int, const char*, va_list))
av_log_callback = callback;
}
-static void missing_feature_sample(int sample, void *avc, const char *msg, ...)
+static void missing_feature_sample(int sample, void *avc, const char *msg, va_list argument_list)
{
- va_list argument_list;
-
- va_start(argument_list, msg);
-
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");
-
- va_end(argument_list);
+ "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 7b17330..7ea95fa 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;
/* av_log API */
@@ -125,6 +161,8 @@ typedef struct AVClass {
*/
#define AV_LOG_DEBUG 48
+#define AV_LOG_MAX_OFFSET (AV_LOG_DEBUG - AV_LOG_QUIET)
+
/**
* Send the specified message to the log if the level is less than or equal
* to the current av_log_level. By default, all logging messages are sent to
@@ -147,6 +185,17 @@ void av_log_set_level(int);
void av_log_set_callback(void (*)(void*, int, const char*, va_list));
void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl);
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
@@ -156,7 +205,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
/**
@@ -165,7 +214,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..f8f08f1 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)
{
@@ -96,12 +94,12 @@ static const uint32_t T[64] = { // T[i]= fabs(sin(i+1)<<32)
static void body(uint32_t ABCD[4], uint32_t X[16])
{
- 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];
+ uint32_t t;
+ uint32_t a = ABCD[3];
+ uint32_t b = ABCD[2];
+ uint32_t c = ABCD[1];
+ uint32_t d = ABCD[0];
#if HAVE_BIGENDIAN
for (i = 0; i < 16; i++)
diff --git a/libavutil/md5.h b/libavutil/md5.h
index 29e4e7c..1d7be9f 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,9 +32,7 @@
* @{
*/
-#if FF_API_CONTEXT_SIZE
-extern attribute_deprecated const int av_md5_size;
-#endif
+extern const int av_md5_size;
struct AVMD5;
diff --git a/libavutil/mem.c b/libavutil/mem.c
index 391eb7d..66502eb 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 possible 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 possible ambiguous cases */
- if (size > (INT_MAX - 16))
+ if (size > (max_alloc_size - 32))
return NULL;
#if CONFIG_MEMALIGN_HACK
@@ -128,19 +153,41 @@ 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;
+}
+
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
@@ -163,6 +210,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;
@@ -175,6 +229,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);
@@ -298,3 +426,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 8f47224..a329469 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__)
@@ -112,6 +113,16 @@ av_alloc_size(1, 2) static inline void *av_malloc_array(size_t nmemb, size_t siz
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);
+
+/**
* Free a memory block which has been allocated with av_malloc(z)() or
* av_realloc().
* @param ptr Pointer to the memory block which should be freed.
@@ -132,6 +143,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;
+
+/**
* Helper function to allocate a block of size * nmemb bytes with
* using av_mallocz()
* @param nmemb Number of elements
@@ -157,6 +180,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
@@ -166,9 +197,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);
+
+/**
* @brief deliberately overlapping memcpy implementation
* @param dst destination buffer
- * @param back how many bytes back we start (the initial size of the overlapping window)
+ * @param back how many bytes back we start (the initial size of the overlapping window), must be > 0
* @param cnt number of bytes to copy, must be >= 0
*
* cnt > back is valid, this will copy the bytes we just copied,
diff --git a/libavutil/mips/Makefile b/libavutil/mips/Makefile
new file mode 100644
index 0000000..dbfa5aa
--- /dev/null
+++ b/libavutil/mips/Makefile
@@ -0,0 +1 @@
+OBJS += mips/float_dsp_mips.o
diff --git a/libavutil/mips/float_dsp_mips.c b/libavutil/mips/float_dsp_mips.c
new file mode 100644
index 0000000..06d52dc
--- /dev/null
+++ b/libavutil/mips/float_dsp_mips.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Branimir Vasic (bvasic@mips.com)
+ * Author: Zoran Lukic (zoranl@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavutil/float_dsp.c
+ */
+
+#include "config.h"
+#include "libavutil/float_dsp.h"
+
+#if HAVE_INLINE_ASM && HAVE_MIPSFPU
+static void vector_fmul_mips(float *dst, const float *src0, const float *src1,
+ int len)
+{
+ int i;
+
+ if (len & 3) {
+ for (i = 0; i < len; i++)
+ dst[i] = src0[i] * src1[i];
+ } else {
+ float *d = (float *)dst;
+ float *d_end = d + len;
+ float *s0 = (float *)src0;
+ float *s1 = (float *)src1;
+
+ float src0_0, src0_1, src0_2, src0_3;
+ float src1_0, src1_1, src1_2, src1_3;
+
+ __asm__ volatile (
+ "1: \n\t"
+ "lwc1 %[src0_0], 0(%[s0]) \n\t"
+ "lwc1 %[src1_0], 0(%[s1]) \n\t"
+ "lwc1 %[src0_1], 4(%[s0]) \n\t"
+ "lwc1 %[src1_1], 4(%[s1]) \n\t"
+ "lwc1 %[src0_2], 8(%[s0]) \n\t"
+ "lwc1 %[src1_2], 8(%[s1]) \n\t"
+ "lwc1 %[src0_3], 12(%[s0]) \n\t"
+ "lwc1 %[src1_3], 12(%[s1]) \n\t"
+ "mul.s %[src0_0], %[src0_0], %[src1_0] \n\t"
+ "mul.s %[src0_1], %[src0_1], %[src1_1] \n\t"
+ "mul.s %[src0_2], %[src0_2], %[src1_2] \n\t"
+ "mul.s %[src0_3], %[src0_3], %[src1_3] \n\t"
+ "swc1 %[src0_0], 0(%[d]) \n\t"
+ "swc1 %[src0_1], 4(%[d]) \n\t"
+ "swc1 %[src0_2], 8(%[d]) \n\t"
+ "swc1 %[src0_3], 12(%[d]) \n\t"
+ "addiu %[s0], %[s0], 16 \n\t"
+ "addiu %[s1], %[s1], 16 \n\t"
+ "addiu %[d], %[d], 16 \n\t"
+ "bne %[d], %[d_end], 1b \n\t"
+
+ : [src0_0]"=&f"(src0_0), [src0_1]"=&f"(src0_1),
+ [src0_2]"=&f"(src0_2), [src0_3]"=&f"(src0_3),
+ [src1_0]"=&f"(src1_0), [src1_1]"=&f"(src1_1),
+ [src1_2]"=&f"(src1_2), [src1_3]"=&f"(src1_3),
+ [d]"+r"(d), [s0]"+r"(s0), [s1]"+r"(s1)
+ : [d_end]"r"(d_end)
+ : "memory"
+ );
+ }
+}
+
+static void vector_fmul_scalar_mips(float *dst, const float *src, float mul,
+ int len)
+{
+ float temp0, temp1, temp2, temp3;
+ float *local_src = (float*)src;
+ float *end = local_src + len;
+
+ /* loop unrolled 4 times */
+ __asm__ volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "1: \n\t"
+ "lwc1 %[temp0], 0(%[src]) \n\t"
+ "lwc1 %[temp1], 4(%[src]) \n\t"
+ "lwc1 %[temp2], 8(%[src]) \n\t"
+ "lwc1 %[temp3], 12(%[src]) \n\t"
+ "addiu %[dst], %[dst], 16 \n\t"
+ "mul.s %[temp0], %[temp0], %[mul] \n\t"
+ "mul.s %[temp1], %[temp1], %[mul] \n\t"
+ "mul.s %[temp2], %[temp2], %[mul] \n\t"
+ "mul.s %[temp3], %[temp3], %[mul] \n\t"
+ "addiu %[src], %[src], 16 \n\t"
+ "swc1 %[temp0], -16(%[dst]) \n\t"
+ "swc1 %[temp1], -12(%[dst]) \n\t"
+ "swc1 %[temp2], -8(%[dst]) \n\t"
+ "bne %[src], %[end], 1b \n\t"
+ " swc1 %[temp3], -4(%[dst]) \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1),
+ [temp2]"=&f"(temp2), [temp3]"=&f"(temp3),
+ [dst]"+r"(dst), [src]"+r"(local_src)
+ : [end]"r"(end), [mul]"f"(mul)
+ : "memory"
+ );
+}
+
+static void vector_fmul_window_mips(float *dst, const float *src0,
+ const float *src1, const float *win, int len)
+{
+ int i, j;
+ /*
+ * variables used in inline assembler
+ */
+ float * dst_i, * dst_j, * dst_i2, * dst_j2;
+ float temp, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ dst += len;
+ win += len;
+ src0 += len;
+
+ for (i = -len, j = len - 1; i < 0; i += 8, j -= 8) {
+
+ dst_i = dst + i;
+ dst_j = dst + j;
+
+ dst_i2 = dst + i + 4;
+ dst_j2 = dst + j - 4;
+
+ __asm__ volatile (
+ "mul.s %[temp], %[s1], %[wi] \n\t"
+ "mul.s %[temp1], %[s1], %[wj] \n\t"
+ "mul.s %[temp2], %[s11], %[wi1] \n\t"
+ "mul.s %[temp3], %[s11], %[wj1] \n\t"
+
+ "msub.s %[temp], %[temp], %[s0], %[wj] \n\t"
+ "madd.s %[temp1], %[temp1], %[s0], %[wi] \n\t"
+ "msub.s %[temp2], %[temp2], %[s01], %[wj1] \n\t"
+ "madd.s %[temp3], %[temp3], %[s01], %[wi1] \n\t"
+
+ "swc1 %[temp], 0(%[dst_i]) \n\t" /* dst[i] = s0*wj - s1*wi; */
+ "swc1 %[temp1], 0(%[dst_j]) \n\t" /* dst[j] = s0*wi + s1*wj; */
+ "swc1 %[temp2], 4(%[dst_i]) \n\t" /* dst[i+1] = s01*wj1 - s11*wi1; */
+ "swc1 %[temp3], -4(%[dst_j]) \n\t" /* dst[j-1] = s01*wi1 + s11*wj1; */
+
+ "mul.s %[temp4], %[s12], %[wi2] \n\t"
+ "mul.s %[temp5], %[s12], %[wj2] \n\t"
+ "mul.s %[temp6], %[s13], %[wi3] \n\t"
+ "mul.s %[temp7], %[s13], %[wj3] \n\t"
+
+ "msub.s %[temp4], %[temp4], %[s02], %[wj2] \n\t"
+ "madd.s %[temp5], %[temp5], %[s02], %[wi2] \n\t"
+ "msub.s %[temp6], %[temp6], %[s03], %[wj3] \n\t"
+ "madd.s %[temp7], %[temp7], %[s03], %[wi3] \n\t"
+
+ "swc1 %[temp4], 8(%[dst_i]) \n\t" /* dst[i+2] = s02*wj2 - s12*wi2; */
+ "swc1 %[temp5], -8(%[dst_j]) \n\t" /* dst[j-2] = s02*wi2 + s12*wj2; */
+ "swc1 %[temp6], 12(%[dst_i]) \n\t" /* dst[i+2] = s03*wj3 - s13*wi3; */
+ "swc1 %[temp7], -12(%[dst_j]) \n\t" /* dst[j-3] = s03*wi3 + s13*wj3; */
+ : [temp]"=&f"(temp), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7)
+ : [dst_j]"r"(dst_j), [dst_i]"r" (dst_i),
+ [s0] "f"(src0[i]), [wj] "f"(win[j]), [s1] "f"(src1[j]),
+ [wi] "f"(win[i]), [s01]"f"(src0[i + 1]),[wj1]"f"(win[j - 1]),
+ [s11]"f"(src1[j - 1]), [wi1]"f"(win[i + 1]), [s02]"f"(src0[i + 2]),
+ [wj2]"f"(win[j - 2]), [s12]"f"(src1[j - 2]),[wi2]"f"(win[i + 2]),
+ [s03]"f"(src0[i + 3]), [wj3]"f"(win[j - 3]), [s13]"f"(src1[j - 3]),
+ [wi3]"f"(win[i + 3])
+ : "memory"
+ );
+
+ __asm__ volatile (
+ "mul.s %[temp], %[s1], %[wi] \n\t"
+ "mul.s %[temp1], %[s1], %[wj] \n\t"
+ "mul.s %[temp2], %[s11], %[wi1] \n\t"
+ "mul.s %[temp3], %[s11], %[wj1] \n\t"
+
+ "msub.s %[temp], %[temp], %[s0], %[wj] \n\t"
+ "madd.s %[temp1], %[temp1], %[s0], %[wi] \n\t"
+ "msub.s %[temp2], %[temp2], %[s01], %[wj1] \n\t"
+ "madd.s %[temp3], %[temp3], %[s01], %[wi1] \n\t"
+
+ "swc1 %[temp], 0(%[dst_i2]) \n\t" /* dst[i] = s0*wj - s1*wi; */
+ "swc1 %[temp1], 0(%[dst_j2]) \n\t" /* dst[j] = s0*wi + s1*wj; */
+ "swc1 %[temp2], 4(%[dst_i2]) \n\t" /* dst[i+1] = s01*wj1 - s11*wi1; */
+ "swc1 %[temp3], -4(%[dst_j2]) \n\t" /* dst[j-1] = s01*wi1 + s11*wj1; */
+
+ "mul.s %[temp4], %[s12], %[wi2] \n\t"
+ "mul.s %[temp5], %[s12], %[wj2] \n\t"
+ "mul.s %[temp6], %[s13], %[wi3] \n\t"
+ "mul.s %[temp7], %[s13], %[wj3] \n\t"
+
+ "msub.s %[temp4], %[temp4], %[s02], %[wj2] \n\t"
+ "madd.s %[temp5], %[temp5], %[s02], %[wi2] \n\t"
+ "msub.s %[temp6], %[temp6], %[s03], %[wj3] \n\t"
+ "madd.s %[temp7], %[temp7], %[s03], %[wi3] \n\t"
+
+ "swc1 %[temp4], 8(%[dst_i2]) \n\t" /* dst[i+2] = s02*wj2 - s12*wi2; */
+ "swc1 %[temp5], -8(%[dst_j2]) \n\t" /* dst[j-2] = s02*wi2 + s12*wj2; */
+ "swc1 %[temp6], 12(%[dst_i2]) \n\t" /* dst[i+2] = s03*wj3 - s13*wi3; */
+ "swc1 %[temp7], -12(%[dst_j2]) \n\t" /* dst[j-3] = s03*wi3 + s13*wj3; */
+ : [temp]"=&f"(temp),
+ [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), [temp3]"=&f"(temp3),
+ [temp4]"=&f"(temp4), [temp5]"=&f"(temp5), [temp6]"=&f"(temp6),
+ [temp7] "=&f" (temp7)
+ : [dst_j2]"r"(dst_j2), [dst_i2]"r"(dst_i2),
+ [s0] "f"(src0[i + 4]), [wj] "f"(win[j - 4]), [s1] "f"(src1[j - 4]),
+ [wi] "f"(win[i + 4]), [s01]"f"(src0[i + 5]),[wj1]"f"(win[j - 5]),
+ [s11]"f"(src1[j - 5]), [wi1]"f"(win[i + 5]), [s02]"f"(src0[i + 6]),
+ [wj2]"f"(win[j - 6]), [s12]"f"(src1[j - 6]),[wi2]"f"(win[i + 6]),
+ [s03]"f"(src0[i + 7]), [wj3]"f"(win[j - 7]), [s13]"f"(src1[j - 7]),
+ [wi3]"f"(win[i + 7])
+ : "memory"
+ );
+ }
+}
+
+static void butterflies_float_mips(float *av_restrict v1, float *av_restrict v2,
+ int len)
+{
+ float temp0, temp1, temp2, temp3, temp4;
+ float temp5, temp6, temp7, temp8, temp9;
+ float temp10, temp11, temp12, temp13, temp14, temp15;
+ int pom;
+ pom = (len >> 2)-1;
+
+ /* loop unrolled 4 times */
+ __asm__ volatile (
+ "lwc1 %[temp0], 0(%[v1]) \n\t"
+ "lwc1 %[temp1], 4(%[v1]) \n\t"
+ "lwc1 %[temp2], 8(%[v1]) \n\t"
+ "lwc1 %[temp3], 12(%[v1]) \n\t"
+ "lwc1 %[temp4], 0(%[v2]) \n\t"
+ "lwc1 %[temp5], 4(%[v2]) \n\t"
+ "lwc1 %[temp6], 8(%[v2]) \n\t"
+ "lwc1 %[temp7], 12(%[v2]) \n\t"
+ "beq %[pom], $zero, 2f \n\t"
+ "1: \n\t"
+ "sub.s %[temp8], %[temp0], %[temp4] \n\t"
+ "add.s %[temp9], %[temp0], %[temp4] \n\t"
+ "sub.s %[temp10], %[temp1], %[temp5] \n\t"
+ "add.s %[temp11], %[temp1], %[temp5] \n\t"
+ "sub.s %[temp12], %[temp2], %[temp6] \n\t"
+ "add.s %[temp13], %[temp2], %[temp6] \n\t"
+ "sub.s %[temp14], %[temp3], %[temp7] \n\t"
+ "add.s %[temp15], %[temp3], %[temp7] \n\t"
+ "addiu %[v1], %[v1], 16 \n\t"
+ "addiu %[v2], %[v2], 16 \n\t"
+ "addiu %[pom], %[pom], -1 \n\t"
+ "lwc1 %[temp0], 0(%[v1]) \n\t"
+ "lwc1 %[temp1], 4(%[v1]) \n\t"
+ "lwc1 %[temp2], 8(%[v1]) \n\t"
+ "lwc1 %[temp3], 12(%[v1]) \n\t"
+ "lwc1 %[temp4], 0(%[v2]) \n\t"
+ "lwc1 %[temp5], 4(%[v2]) \n\t"
+ "lwc1 %[temp6], 8(%[v2]) \n\t"
+ "lwc1 %[temp7], 12(%[v2]) \n\t"
+ "swc1 %[temp9], -16(%[v1]) \n\t"
+ "swc1 %[temp8], -16(%[v2]) \n\t"
+ "swc1 %[temp11], -12(%[v1]) \n\t"
+ "swc1 %[temp10], -12(%[v2]) \n\t"
+ "swc1 %[temp13], -8(%[v1]) \n\t"
+ "swc1 %[temp12], -8(%[v2]) \n\t"
+ "swc1 %[temp15], -4(%[v1]) \n\t"
+ "swc1 %[temp14], -4(%[v2]) \n\t"
+ "bgtz %[pom], 1b \n\t"
+ "2: \n\t"
+ "sub.s %[temp8], %[temp0], %[temp4] \n\t"
+ "add.s %[temp9], %[temp0], %[temp4] \n\t"
+ "sub.s %[temp10], %[temp1], %[temp5] \n\t"
+ "add.s %[temp11], %[temp1], %[temp5] \n\t"
+ "sub.s %[temp12], %[temp2], %[temp6] \n\t"
+ "add.s %[temp13], %[temp2], %[temp6] \n\t"
+ "sub.s %[temp14], %[temp3], %[temp7] \n\t"
+ "add.s %[temp15], %[temp3], %[temp7] \n\t"
+ "swc1 %[temp9], 0(%[v1]) \n\t"
+ "swc1 %[temp8], 0(%[v2]) \n\t"
+ "swc1 %[temp11], 4(%[v1]) \n\t"
+ "swc1 %[temp10], 4(%[v2]) \n\t"
+ "swc1 %[temp13], 8(%[v1]) \n\t"
+ "swc1 %[temp12], 8(%[v2]) \n\t"
+ "swc1 %[temp15], 12(%[v1]) \n\t"
+ "swc1 %[temp14], 12(%[v2]) \n\t"
+
+ : [v1]"+r"(v1), [v2]"+r"(v2), [pom]"+r"(pom), [temp0] "=&f" (temp0),
+ [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), [temp3]"=&f"(temp3),
+ [temp4]"=&f"(temp4), [temp5]"=&f"(temp5), [temp6]"=&f"(temp6),
+ [temp7]"=&f"(temp7), [temp8]"=&f"(temp8), [temp9]"=&f"(temp9),
+ [temp10]"=&f"(temp10), [temp11]"=&f"(temp11), [temp12]"=&f"(temp12),
+ [temp13]"=&f"(temp13), [temp14]"=&f"(temp14), [temp15]"=&f"(temp15)
+ :
+ : "memory"
+ );
+}
+
+static void vector_fmul_reverse_mips(float *dst, const float *src0, const float *src1, int len){
+ int i;
+ float temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ src1 += len-1;
+
+ for(i=0; i<(len>>2); i++)
+ {
+ /* loop unrolled 4 times */
+ __asm__ volatile(
+ "lwc1 %[temp0], 0(%[src0]) \n\t"
+ "lwc1 %[temp1], 0(%[src1]) \n\t"
+ "lwc1 %[temp2], 4(%[src0]) \n\t"
+ "lwc1 %[temp3], -4(%[src1]) \n\t"
+ "lwc1 %[temp4], 8(%[src0]) \n\t"
+ "lwc1 %[temp5], -8(%[src1]) \n\t"
+ "lwc1 %[temp6], 12(%[src0]) \n\t"
+ "lwc1 %[temp7], -12(%[src1]) \n\t"
+ "mul.s %[temp0], %[temp1], %[temp0] \n\t"
+ "mul.s %[temp2], %[temp3], %[temp2] \n\t"
+ "mul.s %[temp4], %[temp5], %[temp4] \n\t"
+ "mul.s %[temp6], %[temp7], %[temp6] \n\t"
+ "addiu %[src0], %[src0], 16 \n\t"
+ "addiu %[src1], %[src1], -16 \n\t"
+ "addiu %[dst], %[dst], 16 \n\t"
+ "swc1 %[temp0], -16(%[dst]) \n\t"
+ "swc1 %[temp2], -12(%[dst]) \n\t"
+ "swc1 %[temp4], -8(%[dst]) \n\t"
+ "swc1 %[temp6], -4(%[dst]) \n\t"
+
+ : [dst]"+r"(dst), [src0]"+r"(src0), [src1]"+r"(src1),
+ [temp0]"=&f"(temp0), [temp1]"=&f"(temp1),[temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7)
+ :
+ : "memory"
+ );
+ }
+}
+#endif /* HAVE_INLINE_ASM && HAVE_MIPSFPU */
+
+void ff_float_dsp_init_mips(AVFloatDSPContext *fdsp) {
+#if HAVE_INLINE_ASM && HAVE_MIPSFPU
+ fdsp->vector_fmul = vector_fmul_mips;
+ fdsp->vector_fmul_scalar = vector_fmul_scalar_mips;
+ fdsp->vector_fmul_window = vector_fmul_window_mips;
+ fdsp->butterflies_float = butterflies_float_mips;
+ fdsp->vector_fmul_reverse = vector_fmul_reverse_mips;
+#endif /* HAVE_INLINE_ASM && HAVE_MIPSFPU */
+}
diff --git a/libavutil/mips/intreadwrite.h b/libavutil/mips/intreadwrite.h
index 4dabbe6..9ba0491 100644
--- a/libavutil/mips/intreadwrite.h
+++ b/libavutil/mips/intreadwrite.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/mips/libm_mips.h b/libavutil/mips/libm_mips.h
new file mode 100644
index 0000000..8853bbc
--- /dev/null
+++ b/libavutil/mips/libm_mips.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * MIPS optimization for some libm functions
+ */
+
+#ifndef AVUTIL_LIBM_MIPS_H
+#define AVUTIL_LIBM_MIPS_H
+
+static av_always_inline av_const long int lrintf_mips(float x)
+{
+ register int ret_int;
+
+ __asm__ volatile (
+ "cvt.w.s %[x], %[x] \n\t"
+ "mfc1 %[ret_int], %[x] \n\t"
+
+ :[x]"+f"(x), [ret_int]"=r"(ret_int)
+ );
+ return ret_int;
+}
+
+#undef lrintf
+#define lrintf(x) lrintf_mips(x)
+
+#define HAVE_LRINTF 1
+#endif /* AVUTIL_LIBM_MIPS_H */
diff --git a/libavutil/murmur3.c b/libavutil/murmur3.c
new file mode 100644
index 0000000..701fa6a
--- /dev/null
+++ b/libavutil/murmur3.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2013 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <stdint.h>
+#include "mem.h"
+#include "intreadwrite.h"
+#include "murmur3.h"
+
+typedef struct AVMurMur3 {
+ uint64_t h1, h2;
+ uint8_t state[16];
+ int state_pos;
+ uint64_t len;
+} AVMurMur3;
+
+AVMurMur3 *av_murmur3_alloc(void)
+{
+ return av_mallocz(sizeof(AVMurMur3));
+}
+
+void av_murmur3_init_seeded(AVMurMur3 *c, uint64_t seed)
+{
+ memset(c, 0, sizeof(*c));
+ c->h1 = c->h2 = seed;
+}
+
+void av_murmur3_init(AVMurMur3 *c)
+{
+ // arbitrary random number as seed
+ av_murmur3_init_seeded(c, 0x725acc55daddca55);
+}
+
+static const uint64_t c1 = UINT64_C(0x87c37b91114253d5);
+static const uint64_t c2 = UINT64_C(0x4cf5ad432745937f);
+
+#define ROT(a, b) ((a << b) | (a >> (64 - b)))
+
+static uint64_t inline get_k1(const uint8_t *src)
+{
+ uint64_t k = AV_RL64(src);
+ k *= c1;
+ k = ROT(k, 31);
+ k *= c2;
+ return k;
+}
+
+static uint64_t inline get_k2(const uint8_t *src)
+{
+ uint64_t k = AV_RL64(src + 8);
+ k *= c2;
+ k = ROT(k, 33);
+ k *= c1;
+ return k;
+}
+
+static uint64_t inline update_h1(uint64_t k, uint64_t h1, uint64_t h2)
+{
+ k ^= h1;
+ k = ROT(k, 27);
+ k += h2;
+ k *= 5;
+ k += 0x52dce729;
+ return k;
+}
+
+static uint64_t inline update_h2(uint64_t k, uint64_t h1, uint64_t h2)
+{
+ k ^= h2;
+ k = ROT(k, 31);
+ k += h1;
+ k *= 5;
+ k += 0x38495ab5;
+ return k;
+}
+
+void av_murmur3_update(AVMurMur3 *c, const uint8_t *src, int len)
+{
+ const uint8_t *end;
+ uint64_t h1 = c->h1, h2 = c->h2;
+ uint64_t k1, k2;
+ if (len <= 0) return;
+ c->len += len;
+ if (c->state_pos > 0) {
+ while (c->state_pos < 16) {
+ c->state[c->state_pos++] = *src++;
+ if (--len <= 0) return;
+ }
+ c->state_pos = 0;
+ k1 = get_k1(c->state);
+ k2 = get_k2(c->state);
+ h1 = update_h1(k1, h1, h2);
+ h2 = update_h2(k2, h1, h2);
+ }
+
+ end = src + (len & ~15);
+ while (src < end) {
+ // These could be done sequentially instead
+ // of interleaved, but like this is over 10% faster
+ k1 = get_k1(src);
+ k2 = get_k2(src);
+ h1 = update_h1(k1, h1, h2);
+ h2 = update_h2(k2, h1, h2);
+ src += 16;
+ }
+ c->h1 = h1;
+ c->h2 = h2;
+
+ len &= 15;
+ if (len > 0) {
+ memcpy(c->state, src, len);
+ c->state_pos = len;
+ }
+}
+
+static inline uint64_t fmix(uint64_t k)
+{
+ k ^= k >> 33;
+ k *= UINT64_C(0xff51afd7ed558ccd);
+ k ^= k >> 33;
+ k *= UINT64_C(0xc4ceb9fe1a85ec53);
+ k ^= k >> 33;
+ return k;
+}
+
+void av_murmur3_final(AVMurMur3 *c, uint8_t dst[16])
+{
+ uint64_t h1 = c->h1, h2 = c->h2;
+ memset(c->state + c->state_pos, 0, sizeof(c->state) - c->state_pos);
+ h1 ^= get_k1(c->state) ^ c->len;
+ h2 ^= get_k2(c->state) ^ c->len;
+ h1 += h2;
+ h2 += h1;
+ h1 = fmix(h1);
+ h2 = fmix(h2);
+ h1 += h2;
+ h2 += h1;
+ AV_WL64(dst, h1);
+ AV_WL64(dst + 8, h2);
+}
+
+#ifdef TEST
+int main(void)
+{
+ int i;
+ uint8_t hash_result[16] = {0};
+ AVMurMur3 *ctx = av_murmur3_alloc();
+#if 1
+ uint8_t in[256] = {0};
+ uint8_t *hashes = av_mallocz(256 * 16);
+ for (i = 0; i < 256; i++)
+ {
+ in[i] = i;
+ av_murmur3_init_seeded(ctx, 256 - i);
+ // Note: this actually tests hashing 0 bytes
+ av_murmur3_update(ctx, in, i);
+ av_murmur3_final(ctx, hashes + 16 * i);
+ }
+ av_murmur3_init_seeded(ctx, 0);
+ av_murmur3_update(ctx, hashes, 256 * 16);
+ av_murmur3_final(ctx, hash_result);
+ av_free(hashes);
+ av_freep(&ctx);
+ printf("result: 0x%"PRIx64" 0x%"PRIx64"\n", AV_RL64(hash_result), AV_RL64(hash_result + 8));
+ // official reference value is 32 bit
+ return AV_RL32(hash_result) != 0x6384ba69;
+#else
+ uint8_t *in = av_mallocz(512*1024);
+ av_murmur3_init(ctx);
+ for (i = 0; i < 40*1024; i++)
+ av_murmur3_update(ctx, in, 512*1024);
+ av_murmur3_final(ctx, hash_result);
+ av_free(in);
+ return hash_result[0];
+#endif
+}
+#endif
diff --git a/libavutil/murmur3.h b/libavutil/murmur3.h
new file mode 100644
index 0000000..f29ed97
--- /dev/null
+++ b/libavutil/murmur3.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2013 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_MURMUR3_H
+#define AVUTIL_MURMUR3_H
+
+#include <stdint.h>
+
+struct AVMurMur3 *av_murmur3_alloc(void);
+void av_murmur3_init_seeded(struct AVMurMur3 *c, uint64_t seed);
+void av_murmur3_init(struct AVMurMur3 *c);
+void av_murmur3_update(struct AVMurMur3 *c, const uint8_t *src, int len);
+void av_murmur3_final(struct AVMurMur3 *c, uint8_t dst[16]);
+
+#endif /* AVUTIL_MURMUR3_H */
diff --git a/libavutil/old_pix_fmts.h b/libavutil/old_pix_fmts.h
index 31765ae..57b6992 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
*/
@@ -100,9 +102,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
@@ -116,6 +122,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
@@ -123,6 +136,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..f00ae9c
--- /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 id: 0x%x\n",
+ opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_name,
+ (unsigned int)opencl_ctx->device_id);
+ 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
--- /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
--- /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
--- /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 f2b9473..0e7a3a8 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
*/
@@ -32,7 +32,33 @@
#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)
{
@@ -48,13 +74,17 @@ 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_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);
}
@@ -62,14 +92,17 @@ static int read_number(const AVOption *o, void *dst, double *num, int *den, int6
static int write_number(void *obj, const AVOption *o, void *dst, double num, int den, int64_t intnum)
{
if (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);
}
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_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;
@@ -206,13 +239,27 @@ 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;
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))
return AVERROR(EINVAL);
dst = ((uint8_t*)target_obj) + o->offset;
@@ -225,6 +272,65 @@ 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;
+ }
}
av_log(obj, AV_LOG_ERROR, "Invalid option type.\n");
@@ -259,6 +365,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);
@@ -288,8 +420,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);
@@ -298,19 +430,148 @@ 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);
+}
+
+#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;
@@ -322,7 +583,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);
@@ -339,6 +602,21 @@ 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;
default:
return AVERROR(EINVAL);
}
@@ -349,7 +627,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;
@@ -359,6 +637,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:
@@ -366,13 +646,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;
@@ -384,7 +702,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;
@@ -396,7 +714,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)
@@ -406,6 +758,34 @@ 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_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);
@@ -419,10 +799,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))
@@ -439,48 +840,86 @@ 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_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);
+ }
+
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);
@@ -502,8 +941,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 */
@@ -511,6 +962,7 @@ 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:
av_opt_set_int(s, opt->name, opt->default_val.i64, 0);
break;
case AV_OPT_TYPE_DOUBLE:
@@ -527,8 +979,26 @@ void av_opt_set_defaults(void *s)
}
break;
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;
@@ -578,7 +1048,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)
@@ -609,6 +1079,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;
@@ -647,9 +1229,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 (search_flags & AV_OPT_SEARCH_CHILDREN) {
if (search_flags & AV_OPT_SEARCH_FAKE_OBJ) {
const AVClass *child = NULL;
@@ -667,7 +1254,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;
@@ -695,6 +1282,109 @@ 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:
+ 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
@@ -705,6 +1395,11 @@ 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;
} TestContext;
#define OFFSET(x) offsetof(TestContext, x)
@@ -716,12 +1411,17 @@ 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},
{NULL},
};
@@ -742,7 +1442,7 @@ int main(void)
printf("\nTesting av_set_options_string()\n");
{
- TestContext test_ctx;
+ TestContext test_ctx = { 0 };
const char *options[] = {
"",
":",
@@ -763,11 +1463,27 @@ 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",
};
test_ctx.class = &test_class;
av_opt_set_defaults(&test_ctx);
- test_ctx.string = av_strdup("default");
av_log_set_level(AV_LOG_DEBUG);
@@ -777,6 +1493,38 @@ int main(void)
av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]);
printf("\n");
}
+ av_freep(&test_ctx.string);
+ }
+
+ printf("\nTesting av_opt_set_from_string()\n");
+ {
+ TestContext test_ctx = { 0 };
+ const char *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"
+ };
+ const char *shorthand[] = { "num", "string", NULL };
+
+ test_ctx.class = &test_class;
+ av_opt_set_defaults(&test_ctx);
+ test_ctx.string = av_strdup("default");
+
+ 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_freep(&test_ctx.string);
}
return 0;
diff --git a/libavutil/opt.h b/libavutil/opt.h
index 2d3cc73..7f7b54e 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.
*
@@ -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,22 @@ 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',' '),
+#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 +284,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 +296,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 +392,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 +418,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 +462,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 +479,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 +652,26 @@ 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);
+
+/**
+ * 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))
/**
* @}
*/
@@ -508,8 +695,58 @@ int av_opt_get (void *obj, const char *name, int search_flags, uint8_t *
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);
/**
* @}
+ */
+/**
+ * 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..f2f8f18 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,12 @@ 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 },
};
static const VideoRateAbbr video_rate_abbrs[]= {
@@ -96,7 +132,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 +143,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 +163,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 +172,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 +184,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 +252,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 +396,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) {
@@ -399,19 +440,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 +519,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 +529,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 +543,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 +586,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 +685,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 +739,8 @@ int main(void)
int i;
uint8_t rgba[4];
static const char *const color_names[] = {
+ "bikeshed",
+ "RaNdOm",
"foo",
"red",
"Red ",
@@ -731,6 +783,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";
+ const char *time_string[] = {
+ "now",
+ "12:35:46",
+ "2000-12-20 0:02:47.5z",
+ "2000-12-20T010247.6",
+ };
+ const char *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..3eb35fc 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
@@ -88,7 +112,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,7 +122,7 @@ 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
@@ -109,6 +133,32 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
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
--- /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
--- /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 7127d5c..8ec6c53 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 "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,
},
@@ -231,6 +233,7 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.comp = {
{ 0, 0, 1, 0, 7 }, /* Y */
},
+ .flags = AV_PIX_FMT_FLAG_PSEUDOPAL,
},
[AV_PIX_FMT_MONOWHITE] = {
.name = "monow",
@@ -292,9 +295,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,
},
@@ -334,9 +337,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,
},
@@ -346,9 +349,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,
},
@@ -358,9 +361,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,
},
@@ -419,8 +422,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,
},
@@ -430,10 +433,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,
},
@@ -456,10 +459,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,
},
@@ -469,13 +472,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,
@@ -532,7 +583,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,
@@ -569,7 +620,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",
@@ -852,6 +903,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,
@@ -930,9 +1007,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,
},
@@ -942,21 +1019,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,
},
@@ -966,9 +1069,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,
},
@@ -978,9 +1081,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,
},
@@ -990,9 +1093,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,
},
@@ -1002,9 +1105,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,
},
@@ -1014,9 +1117,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,
},
@@ -1038,12 +1141,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,
@@ -1092,6 +1189,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,
@@ -1164,6 +1309,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,
@@ -1260,14 +1453,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 */
@@ -1281,9 +1528,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,
},
@@ -1293,9 +1540,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,
},
@@ -1305,9 +1552,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,
},
@@ -1317,9 +1564,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,
},
@@ -1329,9 +1576,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,
},
@@ -1341,9 +1636,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,
},
@@ -1353,12 +1648,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,
@@ -1447,6 +1781,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 */
@@ -1472,8 +1826,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;
}
@@ -1513,50 +1870,60 @@ 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];
- 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);
+ if (!d->name && !d->nb_components && !d->log2_chroma_w && !d->log2_chroma_h && !d->flags)
+ continue;
+// av_log(NULL, AV_LOG_DEBUG, "Checking: %s\n", d->name);
+ av_assert0(d->log2_chroma_w <= 3);
+ av_assert0(d->log2_chroma_h <= 3);
+ av_assert0(d->nb_components <= 4);
+ av_assert0(d->name && d->name[0]);
+ av_assert0((d->nb_components==4 || d->nb_components==2) == !!(d->flags & AV_PIX_FMT_FLAG_ALPHA));
+ av_assert2(av_get_pix_fmt(d->name) == i);
+
+ for (j=0; j<FF_ARRAY_ELEMS(d->comp); j++) {
+ const AVComponentDescriptor *c = &d->comp[j];
+ if(j>=d->nb_components) {
+ av_assert0(!c->plane && !c->step_minus1 && !c->offset_plus1 && !c->shift && !c->depth_minus1);
+ continue;
+ }
+ if (d->flags & AV_PIX_FMT_FLAG_BITSTREAM) {
+ av_assert0(c->step_minus1 >= c->depth_minus1);
+ } else {
+ av_assert0(8*(c->step_minus1+1) >= c->depth_minus1+1);
+ }
+ 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 143c0fa..f4482e8 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
*/
@@ -76,9 +76,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;
@@ -108,7 +111,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.
*/
@@ -184,7 +187,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);
@@ -220,6 +223,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.
*/
@@ -244,9 +253,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
*/
@@ -259,6 +273,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 ed20720..1760ab1 100644
--- a/libavutil/pixfmt.h
+++ b/libavutil/pixfmt.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,9 @@
#include "libavutil/avconfig.h"
#include "libavutil/version.h"
+#define AVPALETTE_SIZE 1024
+#define AVPALETTE_COUNT 256
+
/**
* Pixel format.
*
@@ -135,9 +138,13 @@ 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 10 formats have the disadvantage of needing 1 format for each bit depth, thus
+ //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
@@ -151,6 +158,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
@@ -158,8 +172,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
@@ -178,9 +199,44 @@ 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
+
+#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_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
@@ -188,6 +244,15 @@ enum AVPixelFormat {
#endif
};
+#if AV_HAVE_INCOMPATIBLE_FORK_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
@@ -198,6 +263,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)
@@ -215,12 +282,22 @@ 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_YUVA420P9 AV_PIX_FMT_NE(YUVA420P9BE , YUVA420P9LE)
@@ -238,12 +315,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
@@ -261,12 +343,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 0025711..20837da 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
*/
@@ -61,7 +61,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/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 4ed2787..00e93cf 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 0981d0c..155fc01 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
*/
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
--- /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 ec9caa7..c674704 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,8 +30,16 @@
#include <fcntl.h>
#include <math.h>
#include <time.h>
+#include <string.h>
+#include "avassert.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)
{
@@ -52,34 +60,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)
@@ -103,3 +123,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..e333f62 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
*/
@@ -143,3 +143,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..417e29e 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
*/
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/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..a1f92f4 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)
{
@@ -220,7 +218,7 @@ static void sha256_transform(uint32_t *state, const uint8_t buffer[64])
a = T1 + T2;
}
#else
- for (i = 0; i < 16;) {
+ for (i = 0; i < 16 - 7;) {
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);
@@ -231,7 +229,7 @@ static void sha256_transform(uint32_t *state, const uint8_t buffer[64])
ROUND256_0_TO_15(b, c, d, e, f, g, h, a);
}
- for (; i < 64;) {
+ for (; i < 64 - 7;) {
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);
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/softfloat.c b/libavutil/softfloat.c
new file mode 100644
index 0000000..efa0420
--- /dev/null
+++ b/libavutil/softfloat.c
@@ -0,0 +1,72 @@
+/*
+ * 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 <assert.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
--- /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 51779c5..27feb0b 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
--- /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
--- /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..c7348d8
--- /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 fd51a74..c6ae23d 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
*/
@@ -28,9 +28,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)
{
@@ -212,13 +210,13 @@ int main (void)
av_lfg_init(&prng, 1);
for (i = 0; i < 10000; i++) {
- int j = av_lfg_get(&prng) % 86294;
+ intptr_t j = av_lfg_get(&prng) % 86294;
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_ERROR, "inserting %4d\n", j);
+ av_log(NULL, AV_LOG_ERROR, "inserting %4d\n", (int)j);
if (!node)
node = av_tree_node_alloc();
av_tree_insert(&root, (void *) (j + 1), cmp, &node);
@@ -226,7 +224,7 @@ int main (void)
j = av_lfg_get(&prng) % 86294;
{
AVTreeNode *node2 = NULL;
- av_log(NULL, AV_LOG_ERROR, "removing %4d\n", j);
+ av_log(NULL, AV_LOG_ERROR, "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)
diff --git a/libavutil/tree.h b/libavutil/tree.h
index 623280f..13fb91b 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.
@@ -65,18 +63,21 @@ void *av_tree_find(const struct AVTreeNode *root, void *key, int (*cmp)(void *ke
/**
* 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.
@@ -91,6 +92,7 @@ void *av_tree_find(const struct AVTreeNode *root, void *key, int (*cmp)(void *ke
* 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..c157aa8 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,48 @@
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);
+
+ 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();
+ }
+
+ 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 +86,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 = 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 066c061..44f4315 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 11
-#define LIBAVUTIL_VERSION_MICRO 0
+#define LIBAVUTIL_VERSION_MAJOR 52
+#define LIBAVUTIL_VERSION_MINOR 32
+#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
@@ -91,3 +141,4 @@
*/
#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 3b36fd0..a3a5239 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 e4f6f0b..601476e 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 03925da..a041b46 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/timer.h b/libavutil/x86/timer.h
index 35e614d..5969876 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/x86inc.asm b/libavutil/x86/x86inc.asm
index f4be5d3..636213b 100644
--- a/libavutil/x86/x86inc.asm
+++ b/libavutil/x86/x86inc.asm
@@ -61,19 +61,38 @@
%endif
; Name of the .rodata section.
-; Kludge: Something on OS X fails to align .rodata even given an align attribute,
-; so use a different read-only section.
%macro SECTION_RODATA 0-1 16
- %ifidn __OUTPUT_FORMAT__,macho64
- SECTION .text align=%1
- %elifidn __OUTPUT_FORMAT__,macho
- SECTION .text align=%1
- fakegot:
- %elifidn __OUTPUT_FORMAT__,aout
+ ; Kludge: Something on OS X fails to align .rodata even given an align
+ ; attribute, so use a different read-only section. This has been fixed in
+ ; yasm 0.8.0 and nasm 2.6.
+ %ifdef __YASM_VERSION_ID__
+ %if __YASM_VERSION_ID__ < 00080000h
+ %define NEED_MACHO_RODATA_KLUDGE
+ %endif
+ %elifdef __NASM_VERSION_ID__
+ %if __NASM_VERSION_ID__ < 02060000h
+ %define NEED_MACHO_RODATA_KLUDGE
+ %endif
+ %endif
+
+ %ifidn __OUTPUT_FORMAT__,aout
section .text
%else
- SECTION .rodata align=%1
+ %ifndef NEED_MACHO_RODATA_KLUDGE
+ SECTION .rodata align=%1
+ %else
+ %ifidn __OUTPUT_FORMAT__,macho64
+ SECTION .text align=%1
+ %elifidn __OUTPUT_FORMAT__,macho
+ SECTION .text align=%1
+ fakegot:
+ %else
+ SECTION .rodata align=%1
+ %endif
+ %endif
%endif
+
+ %undef NEED_MACHO_RODATA_KLUDGE
%endmacro
; aout does not support align=
@@ -816,6 +835,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 79a023f..8908444 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
--- /dev/null
+++ b/libavutil/x86_cpu.h
@@ -0,0 +1 @@
+#include "libavutil/x86/asm.h"
diff --git a/libavutil/xga_font_data.c b/libavutil/xga_font_data.c
new file mode 100644
index 0000000..3aed314
--- /dev/null
+++ b/libavutil/xga_font_data.c
@@ -0,0 +1,417 @@
+/*
+ * CGA/EGA/VGA ROM font data
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * CGA/EGA/VGA ROM font data
+ */
+
+#include <stdint.h>
+#include "xga_font_data.h"
+
+const uint8_t avpriv_cga_font[2048] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
+ 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
+ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+ 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
+ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+ 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0, 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
+ 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+ 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+ 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+ 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
+ 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00, 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
+ 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+ 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
+ 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00, 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00, 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
+ 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00, 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
+ 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
+ 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00, 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
+ 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
+ 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
+ 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
+ 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
+ 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
+ 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+ 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
+ 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
+ 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
+ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
+ 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
+ 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
+ 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
+ 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
+ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
+ 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78, 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00,
+ 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38,
+ 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00,
+ 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00, 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00,
+ 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00, 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00,
+ 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18,
+ 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00, 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30,
+ 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7, 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
+ 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00, 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00,
+ 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
+ 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f,
+ 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00, 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00, 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0,
+ 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00,
+ 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00, 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0,
+ 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00,
+ 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00,
+ 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
+ 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c,
+ 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+const uint8_t avpriv_vga16_font[4096] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
diff --git a/libavutil/xga_font_data.h b/libavutil/xga_font_data.h
new file mode 100644
index 0000000..5e40f54
--- /dev/null
+++ b/libavutil/xga_font_data.h
@@ -0,0 +1,35 @@
+/*
+ * CGA/EGA/VGA ROM font data
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * CGA/EGA/VGA ROM font data
+ */
+
+#ifndef AVUTIL_XGA_FONT_DATA_H
+#define AVUTIL_XGA_FONT_DATA_H
+
+#include <stdint.h>
+#include "internal.h"
+
+extern av_export const uint8_t avpriv_cga_font[2048];
+extern av_export const uint8_t avpriv_vga16_font[4096];
+
+#endif /* AVUTIL_XGA_FONT_DATA_H */
diff --git a/libavutil/xtea.c b/libavutil/xtea.c
index 1187662..e729c91 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
*/
@@ -39,32 +39,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);
@@ -181,6 +265,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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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..3db49b6
--- /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
+ );
+#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
--- /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 88d33dc..78c437e 100644
--- a/library.mak
+++ b/library.mak
@@ -27,7 +27,7 @@ $(SUBDIR)x86/%.o: $(SUBDIR)x86/%.asm
$(YASM) $(YASMFLAGS) -I $(<D)/ -o $@ $<
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)
@@ -50,11 +50,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)/%)
@@ -65,7 +69,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)")
@@ -79,7 +84,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"
@@ -87,13 +92,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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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..d0193dd
--- /dev/null
+++ b/libswresample/dither.c
@@ -0,0 +1,147 @@
+/*
+ * 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_S16) scale = 1L<<16;
+ if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<24;
+ if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<8;
+
+ scale *= s->dither.scale;
+
+ if (out_fmt == AV_SAMPLE_FMT_S32 && s->dither.output_sample_bits)
+ scale *= 1<<(32-s->dither.output_sample_bits);
+
+ s->dither.ns_pos = 0;
+ s->dither.noise_scale= scale;
+ s->dither.ns_scale = scale;
+ s->dither.ns_scale_1 = scale ? 1/scale : 0;
+ memset(s->dither.ns_errors, 0, sizeof(s->dither.ns_errors));
+ for (i=0; filters[i].coefs; i++) {
+ const filter_t *f = &filters[i];
+ if (fabs(s->out_sample_rate - f->rate) / f->rate <= .05 && f->name == s->dither.method) {
+ int j;
+ s->dither.ns_taps = f->len;
+ for (j=0; j<f->len; j++)
+ s->dither.ns_coeffs[j] = f->coefs[j];
+ s->dither.ns_scale_1 *= 1 - exp(f->gain_cB * M_LN10 * 0.005) * 2 / (1<<(8*av_get_bytes_per_sample(out_fmt)));
+ break;
+ }
+ }
+ if (!filters[i].coefs && s->dither.method > SWR_DITHER_NS) {
+ av_log(s, AV_LOG_WARNING, "Requested noise shaping dither not available at this sampling rate, using triangular hp dither\n");
+ s->dither.method = SWR_DITHER_TRIANGULAR_HIGHPASS;
+ }
+
+ av_assert0(!s->preout.count);
+ s->dither.noise = s->preout;
+ s->dither.temp = s->preout;
+ if (s->dither.method > SWR_DITHER_NS) {
+ s->dither.noise.bps = 4;
+ s->dither.noise.fmt = AV_SAMPLE_FMT_FLTP;
+ s->dither.noise_scale = 1;
+ }
+
+ return 0;
+}
+
+#define TEMPLATE_DITHER_S16
+#include "dither_template.c"
+#undef TEMPLATE_DITHER_S16
+
+#define TEMPLATE_DITHER_S32
+#include "dither_template.c"
+#undef TEMPLATE_DITHER_S32
+
+#define TEMPLATE_DITHER_FLT
+#include "dither_template.c"
+#undef TEMPLATE_DITHER_FLT
+
+#define TEMPLATE_DITHER_DBL
+#include "dither_template.c"
+#undef TEMPLATE_DITHER_DBL
diff --git a/libswresample/dither_template.c b/libswresample/dither_template.c
new file mode 100644
index 0000000..4af7312
--- /dev/null
+++ b/libswresample/dither_template.c
@@ -0,0 +1,67 @@
+
+#if defined(TEMPLATE_DITHER_DBL)
+# define RENAME(N) N ## _double
+# define DELEM double
+# define CLIP(v)
+
+#elif defined(TEMPLATE_DITHER_FLT)
+# define RENAME(N) N ## _float
+# define DELEM float
+# define CLIP(v)
+
+#elif defined(TEMPLATE_DITHER_S32)
+# define RENAME(N) N ## _int32
+# define DELEM int32_t
+# define CLIP(v) v = FFMAX(FFMIN(v, INT32_MAX), INT32_MIN)
+
+#elif defined(TEMPLATE_DITHER_S16)
+# define RENAME(N) N ## _int16
+# define DELEM int16_t
+# define CLIP(v) v = FFMAX(FFMIN(v, INT16_MAX), INT16_MIN)
+
+#else
+ERROR
+#endif
+
+void RENAME(swri_noise_shaping)(SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count){
+ int pos = s->dither.ns_pos;
+ int i, j, ch;
+ int taps = s->dither.ns_taps;
+ float S = s->dither.ns_scale;
+ float S_1 = s->dither.ns_scale_1;
+
+ av_assert2((taps&3) != 2);
+ av_assert2((taps&3) != 3 || s->dither.ns_coeffs[taps] == 0);
+
+ for (ch=0; ch<srcs->ch_count; ch++) {
+ const float *noise = ((const float *)noises->ch[ch]) + s->dither.noise_pos;
+ const DELEM *src = (const DELEM*)srcs->ch[ch];
+ DELEM *dst = (DELEM*)dsts->ch[ch];
+ float *ns_errors = s->dither.ns_errors[ch];
+ const float *ns_coeffs = s->dither.ns_coeffs;
+ pos = s->dither.ns_pos;
+ for (i=0; i<count; i++) {
+ double d1, d = src[i]*S_1;
+ for(j=0; j<taps-2; j+=4) {
+ d -= ns_coeffs[j ] * ns_errors[pos + j ]
+ +ns_coeffs[j + 1] * ns_errors[pos + j + 1]
+ +ns_coeffs[j + 2] * ns_errors[pos + j + 2]
+ +ns_coeffs[j + 3] * ns_errors[pos + j + 3];
+ }
+ if(j < taps)
+ d -= ns_coeffs[j] * ns_errors[pos + j];
+ pos = pos ? pos - 1 : taps - 1;
+ d1 = rint(d + noise[i]);
+ ns_errors[pos + taps] = ns_errors[pos] = d1 - d;
+ d1 *= S;
+ CLIP(d1);
+ dst[i] = d1;
+ }
+ }
+
+ s->dither.ns_pos = pos;
+}
+
+#undef RENAME
+#undef DELEM
+#undef CLIP
diff --git a/libswresample/libswresample.v b/libswresample/libswresample.v
new file mode 100644
index 0000000..9b797bd
--- /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
--- /dev/null
+++ b/libswresample/log2_tab.c
@@ -0,0 +1 @@
+#include "libavutil/log2_tab.c"
diff --git a/libswresample/noise_shaping_data.c b/libswresample/noise_shaping_data.c
new file mode 100644
index 0000000..77e0f2e
--- /dev/null
+++ b/libswresample/noise_shaping_data.c
@@ -0,0 +1,224 @@
+/* Effect: dither/noise-shape Copyright (c) 2008-9 robs@users.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+typedef struct {
+ int rate;
+ enum {fir, iir} type;
+ size_t len;
+ int gain_cB; /* Chosen so clips are few if any, but not guaranteed none. */
+ double const * coefs;
+ enum SwrDitherType name;
+} filter_t;
+
+static double const lip44[] = {2.033, -2.165, 1.959, -1.590, .6149};
+static double const fwe44[] = {
+ 2.412, -3.370, 3.937, -4.174, 3.353, -2.205, 1.281, -.569, .0847};
+static double const mew44[] = {
+ 1.662, -1.263, .4827, -.2913, .1268, -.1124, .03252, -.01265, -.03524};
+static double const iew44[] = {
+ 2.847, -4.685, 6.214, -7.184, 6.639, -5.032, 3.263, -1.632, .4191};
+static double const ges44[] = {
+ 2.2061, -.4706, -.2534, -.6214, 1.0587, .0676, -.6054, -.2738};
+static double const ges48[] = {
+ 2.2374, -.7339, -.1251, -.6033, .903, .0116, -.5853, -.2571};
+
+static double const shi48[] = {
+ 2.8720729351043701172, -5.0413231849670410156, 6.2442994117736816406,
+ -5.8483986854553222656, 3.7067542076110839844, -1.0495119094848632812,
+ -1.1830236911773681641, 2.1126792430877685547, -1.9094531536102294922,
+ 0.99913084506988525391, -0.17090806365013122559, -0.32615602016448974609,
+ 0.39127644896507263184, -0.26876461505889892578, 0.097676105797290802002,
+ -0.023473845794796943665,
+};
+static double const shi44[] = {
+ 2.6773197650909423828, -4.8308925628662109375, 6.570110321044921875,
+ -7.4572014808654785156, 6.7263274192810058594, -4.8481650352478027344,
+ 2.0412089824676513672, 0.7006359100341796875, -2.9537565708160400391,
+ 4.0800385475158691406, -4.1845216751098632812, 3.3311812877655029297,
+ -2.1179926395416259766, 0.879302978515625, -0.031759146600961685181,
+ -0.42382788658142089844, 0.47882103919982910156, -0.35490813851356506348,
+ 0.17496839165687561035, -0.060908168554306030273,
+};
+static double const shi38[] = {
+ 1.6335992813110351562, -2.2615492343902587891, 2.4077029228210449219,
+ -2.6341717243194580078, 2.1440362930297851562, -1.8153258562088012695,
+ 1.0816224813461303711, -0.70302653312683105469, 0.15991993248462677002,
+ 0.041549518704414367676, -0.29416576027870178223, 0.2518316805362701416,
+ -0.27766478061676025391, 0.15785403549671173096, -0.10165894031524658203,
+ 0.016833892092108726501,
+};
+static double const shi32[] =
+{ /* dmaker 32000: bestmax=4.99659 (inverted) */
+0.82118552923202515,
+-1.0063692331314087,
+0.62341964244842529,
+-1.0447187423706055,
+0.64532512426376343,
+-0.87615132331848145,
+0.52219754457473755,
+-0.67434263229370117,
+0.44954317808151245,
+-0.52557498216629028,
+0.34567299485206604,
+-0.39618203043937683,
+0.26791760325431824,
+-0.28936097025871277,
+0.1883765310049057,
+-0.19097308814525604,
+0.10431359708309174,
+-0.10633844882249832,
+0.046832218766212463,
+-0.039653312414884567,
+};
+static double const shi22[] =
+{ /* dmaker 22050: bestmax=5.77762 (inverted) */
+0.056581053882837296,
+-0.56956905126571655,
+-0.40727734565734863,
+-0.33870288729667664,
+-0.29810553789138794,
+-0.19039161503314972,
+-0.16510021686553955,
+-0.13468159735202789,
+-0.096633769571781158,
+-0.081049129366874695,
+-0.064953058958053589,
+-0.054459091275930405,
+-0.043378707021474838,
+-0.03660014271736145,
+-0.026256965473294258,
+-0.018786206841468811,
+-0.013387725688517094,
+-0.0090983230620622635,
+-0.0026585909072309732,
+-0.00042083300650119781,
+};
+static double const shi16[] =
+{ /* dmaker 16000: bestmax=5.97128 (inverted) */
+-0.37251132726669312,
+-0.81423574686050415,
+-0.55010956525802612,
+-0.47405767440795898,
+-0.32624706625938416,
+-0.3161766529083252,
+-0.2286367267370224,
+-0.22916607558727264,
+-0.19565616548061371,
+-0.18160104751586914,
+-0.15423151850700378,
+-0.14104481041431427,
+-0.11844276636838913,
+-0.097583092749118805,
+-0.076493598520755768,
+-0.068106919527053833,
+-0.041881654411554337,
+-0.036922425031661987,
+-0.019364040344953537,
+-0.014994367957115173,
+};
+static double const shi11[] =
+{ /* dmaker 11025: bestmax=5.9406 (inverted) */
+-0.9264228343963623,
+-0.98695987462997437,
+-0.631156325340271,
+-0.51966935396194458,
+-0.39738872647285461,
+-0.35679301619529724,
+-0.29720726609230042,
+-0.26310476660728455,
+-0.21719355881214142,
+-0.18561814725399017,
+-0.15404847264289856,
+-0.12687471508979797,
+-0.10339745879173279,
+-0.083688631653785706,
+-0.05875682458281517,
+-0.046893671154975891,
+-0.027950936928391457,
+-0.020740609616041183,
+-0.009366452693939209,
+-0.0060260160826146603,
+};
+static double const shi08[] =
+{ /* dmaker 8000: bestmax=5.56234 (inverted) */
+-1.202863335609436,
+-0.94103097915649414,
+-0.67878556251525879,
+-0.57650017738342285,
+-0.50004476308822632,
+-0.44349345564842224,
+-0.37833768129348755,
+-0.34028723835945129,
+-0.29413089156150818,
+-0.24994957447052002,
+-0.21715600788593292,
+-0.18792112171649933,
+-0.15268312394618988,
+-0.12135542929172516,
+-0.099610626697540283,
+-0.075273610651493073,
+-0.048787496984004974,
+-0.042586319148540497,
+-0.028991291299462318,
+-0.011869125068187714,
+};
+static double const shl48[] = {
+ 2.3925774097442626953, -3.4350297451019287109, 3.1853709220886230469,
+ -1.8117271661758422852, -0.20124770700931549072, 1.4759907722473144531,
+ -1.7210904359817504883, 0.97746700048446655273, -0.13790138065814971924,
+ -0.38185903429985046387, 0.27421241998672485352, 0.066584214568138122559,
+ -0.35223302245140075684, 0.37672343850135803223, -0.23964276909828186035,
+ 0.068674825131893157959,
+};
+static double const shl44[] = {
+ 2.0833916664123535156, -3.0418450832366943359, 3.2047898769378662109,
+ -2.7571926116943359375, 1.4978630542755126953, -0.3427594602108001709,
+ -0.71733748912811279297, 1.0737057924270629883, -1.0225815773010253906,
+ 0.56649994850158691406, -0.20968692004680633545, -0.065378531813621520996,
+ 0.10322438180446624756, -0.067442022264003753662, -0.00495197344571352005,
+ 0,
+};
+static double const shh44[] = {
+ 3.0259189605712890625, -6.0268716812133789062, 9.195003509521484375,
+ -11.824929237365722656, 12.767142295837402344, -11.917946815490722656,
+ 9.1739168167114257812, -5.3712320327758789062, 1.1393624544143676758,
+ 2.4484779834747314453, -4.9719839096069335938, 6.0392003059387207031,
+ -5.9359521865844726562, 4.903278350830078125, -3.5527443885803222656,
+ 2.1909697055816650391, -1.1672389507293701172, 0.4903914332389831543,
+ -0.16519790887832641602, 0.023217858746647834778,
+};
+
+static const filter_t filters[] = {
+ {44100, fir, 5, 210, lip44, SWR_DITHER_NS_LIPSHITZ},
+ {46000, fir, 9, 276, fwe44, SWR_DITHER_NS_F_WEIGHTED},
+ {46000, fir, 9, 160, mew44, SWR_DITHER_NS_MODIFIED_E_WEIGHTED},
+ {46000, fir, 9, 321, iew44, SWR_DITHER_NS_IMPROVED_E_WEIGHTED},
+// {48000, iir, 4, 220, ges48, SWR_DITHER_NS_GESEMANN},
+// {44100, iir, 4, 230, ges44, SWR_DITHER_NS_GESEMANN},
+ {48000, fir, 16, 301, shi48, SWR_DITHER_NS_SHIBATA},
+ {44100, fir, 20, 333, shi44, SWR_DITHER_NS_SHIBATA},
+ {37800, fir, 16, 240, shi38, SWR_DITHER_NS_SHIBATA},
+ {32000, fir, 20, 240/*TBD*/, shi32, SWR_DITHER_NS_SHIBATA},
+ {22050, fir, 20, 240/*TBD*/, shi22, SWR_DITHER_NS_SHIBATA},
+ {16000, fir, 20, 240/*TBD*/, shi16, SWR_DITHER_NS_SHIBATA},
+ {11025, fir, 20, 240/*TBD*/, shi11, SWR_DITHER_NS_SHIBATA},
+ { 8000, fir, 20, 240/*TBD*/, shi08, SWR_DITHER_NS_SHIBATA},
+ {48000, fir, 16, 250, shl48, SWR_DITHER_NS_LOW_SHIBATA},
+ {44100, fir, 15, 250, shl44, SWR_DITHER_NS_LOW_SHIBATA},
+ {44100, fir, 20, 383, shh44, SWR_DITHER_NS_HIGH_SHIBATA},
+ { 0, fir, 0, 0, NULL, SWR_DITHER_NONE},
+};
diff --git a/libswresample/rematrix.c b/libswresample/rematrix.c
new file mode 100644
index 0000000..84c55ee
--- /dev/null
+++ b/libswresample/rematrix.c
@@ -0,0 +1,472 @@
+/*
+ * 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 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 & AV_CH_LAYOUT_STEREO_DOWNMIX) == AV_CH_LAYOUT_STEREO_DOWNMIX)
+ return AV_CH_LAYOUT_STEREO;
+
+ 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;
+
+ in_ch_layout = clean_layout(s, s->in_ch_layout);
+ 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);
+ }
+
+ out_ch_layout = clean_layout(s, s->out_ch_layout);
+ 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(( 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) && maxcoef > 1.0){
+ 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
+ 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);
+}
+
+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..b8ca901
--- /dev/null
+++ b/libswresample/rematrix_template.c
@@ -0,0 +1,100 @@
+/*
+ * 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
+#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;
+ COEFF coeff1 = coeffp[index1];
+ COEFF 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;
+ COEFF 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]*coeffp[0*6+2] + in[3][i]*coeffp[0*6+3];
+ out[0][i] = R(t + in[0][i]*coeffp[0*6+0] + in[4][i]*coeffp[0*6+4]);
+ out[1][i] = R(t + in[1][i]*coeffp[1*6+1] + in[5][i]*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]*coeffp[0*8+2] + in[3][i]*coeffp[0*8+3];
+ out[0][i] = R(t + in[0][i]*coeffp[0*8+0] + in[4][i]*coeffp[0*8+4] + in[6][i]*coeffp[0*8+6]);
+ out[1][i] = R(t + in[1][i]*coeffp[1*8+1] + in[5][i]*coeffp[1*8+5] + in[7][i]*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..fb9da7c
--- /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_free(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
--- /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
--- /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
--- /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..9b71b2e
--- /dev/null
+++ b/libswresample/swresample.c
@@ -0,0 +1,932 @@
+/*
+ * 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_INT64, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"},
+{"in_channel_layout" , "set input channel layout" , OFFSET( in_ch_layout ), AV_OPT_TYPE_INT64, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"},
+{"ocl" , "set output channel layout" , OFFSET(out_ch_layout ), AV_OPT_TYPE_INT64, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"},
+{"out_channel_layout" , "set output channel layout" , OFFSET(out_ch_layout ), AV_OPT_TYPE_INT64, {.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},
+
+{"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" , "" , OFFSET(dither.output_sample_bits) , AV_OPT_TYPE_INT , {.i64=0 }, 0 , 64 , 0 },
+{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_free(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){
+ 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_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 doesnt 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 doesnt 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..95e8a5a
--- /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_int(swr, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0);
+ * av_opt_set_int(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..17b85d5
--- /dev/null
+++ b/libswresample/swresample_internal.h
@@ -0,0 +1,197 @@
+/*
+ * 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
+ 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_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..df9df48
--- /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 102
+
+#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
--- /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..ad46977
--- /dev/null
+++ b/libswresample/x86/audio_convert.asm
@@ -0,0 +1,461 @@
+;******************************************************************************
+;* 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
+align 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
+ REP_RET
+%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..84448e8
--- /dev/null
+++ b/libswresample/x86/rematrix.asm
@@ -0,0 +1,251 @@
+;******************************************************************************
+;* 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
+align 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
--- /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..e18f0c5
--- /dev/null
+++ b/libswresample/x86/swresample_x86.c
@@ -0,0 +1,195 @@
+/*
+ * 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));
+ 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;
+ }
+ }
+ } 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));
+ }
+}
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 9d0bbe3..2b93858 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 5b74c7a..e1b7afa 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"
@@ -195,7 +196,7 @@ SwsFunc ff_yuv2rgb_get_func_ptr_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..35caa32 100644
--- a/libswscale/input.c
+++ b/libswscale/input.c
@@ -1,20 +1,20 @@
/*
- * 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
*/
@@ -30,38 +30,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 +147,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 +169,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 +184,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 +196,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 +248,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 +256,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 +269,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 +282,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 +296,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 +310,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 +338,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 +347,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 +391,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 +519,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 +527,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 +540,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 +555,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 +563,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 +571,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 +585,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 +600,211 @@ 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];
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 + bpc - 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];
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 + bpc - 14);
+ dstV[i] = (rv*r + gv*g + bv*b + (257 << (RGB2YUV_SHIFT + bpc - 9))) >> (RGB2YUV_SHIFT + bpc - 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 +837,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 +853,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 +874,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 +902,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 +927,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 +966,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 +1006,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 +1090,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 +1106,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 +1128,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 +1160,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 +1272,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 +1298,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 daf013c..fc571ac 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
*/
@@ -51,6 +51,7 @@ static const AVOption 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 },
@@ -66,7 +67,13 @@ static const AVOption options[] = {
{ NULL }
};
-const AVClass sws_context_class = { "SWScaler", sws_context_to_name, options };
+const AVClass sws_context_class = {
+ .class_name = "SWScaler",
+ .item_name = sws_context_to_name,
+ .option = 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 ba7b580..9c7284b 100644
--- a/libswscale/output.c
+++ b/libswscale/output.c
@@ -1,20 +1,20 @@
/*
- * 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
*/
@@ -26,6 +26,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 +37,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, 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, 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, dither_4x4_16)[4][8]={
+DECLARE_ALIGNED(8, const uint8_t, 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, dither_8x8_32)[8][8]={
+DECLARE_ALIGNED(8, const uint8_t, 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 +66,10 @@ DECLARE_ALIGNED(8, const uint8_t, 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, dither_8x8_73)[8][8]={
+DECLARE_ALIGNED(8, const uint8_t, 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 +78,11 @@ DECLARE_ALIGNED(8, const uint8_t, 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, dither_8x8_220)[8][8]={
+DECLARE_ALIGNED(8, const uint8_t, 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 +91,11 @@ DECLARE_ALIGNED(8, const uint8_t, 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, dither_8x8_220)[8][8]={
+DECLARE_ALIGNED(8, const uint8_t, 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 +104,11 @@ DECLARE_ALIGNED(8, const uint8_t, 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, dither_8x8_220)[8][8]={
+DECLARE_ALIGNED(8, const uint8_t, 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 +117,11 @@ DECLARE_ALIGNED(8, const uint8_t, 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, dither_8x8_220)[8][8]={
+DECLARE_ALIGNED(8, const uint8_t, 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 +130,7 @@ DECLARE_ALIGNED(8, const uint8_t, 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 +146,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 +161,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 +175,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 +212,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 +244,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 +333,7 @@ yuv2mono_X_c_template(SwsContext *c, const int16_t *lumFilter,
const uint8_t * const d128=dither_8x8_220[y&7];
int i;
unsigned acc = 0;
+ int err = 0;
for (i = 0; i < dstW; i += 2) {
int j;
@@ -333,12 +350,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->flags & SWS_ERROR_DIFFUSION) {
+ 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 +387,29 @@ yuv2mono_2_c_template(SwsContext *c, const int16_t *buf[2],
int yalpha1 = 4096 - yalpha;
int i;
+ if (c->flags & SWS_ERROR_DIFFUSION) {
+ 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 +432,7 @@ yuv2mono_2_c_template(SwsContext *c, const int16_t *buf[2],
output_pixel(*dest++, acc);
}
+ }
}
static av_always_inline void
@@ -390,20 +444,43 @@ yuv2mono_1_c_template(SwsContext *c, const int16_t *buf0,
const uint8_t * const d128 = dither_8x8_220[y & 7];
int i;
+ if (c->flags & SWS_ERROR_DIFFUSION) {
+ 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 +593,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 +615,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 +637,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 +674,230 @@ 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;
+
+ for (i = 0; i < ((dstW + 1) >> 1); i++) {
+ int j, A1 = 0, A2 = 0;
+ 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 = 0, A2 = 0; // Init to avoid compiler warnings
+
+ 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;
+
+ 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;
+ int A1, A2;
+
+ 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];
+ 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;
+ int A1, A2;
+
+ 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)
@@ -848,6 +1163,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];
@@ -953,12 +1269,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 +1284,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 +1315,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 +1343,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 +1365,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 +1399,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 +1409,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 +1442,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 +1544,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 +1568,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 +1576,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 +1717,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 +1770,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 +1785,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 +1810,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 +1833,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 b0e25d0..9ca2868 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
*/
@@ -292,7 +292,7 @@ av_cold void ff_sws_init_swScale_altivec(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 df435fc..a2fc884 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"
#undef PROFILE_THE_BEAST
@@ -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]; \
@@ -736,7 +732,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;
@@ -824,7 +820,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 5aa1820..792deb9 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 c261fe6..c8c430d 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 42f468f..c6d514f 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 4fb6d6c..c5bba82 100644
--- a/libswscale/swscale.c
+++ b/libswscale/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
*/
@@ -24,6 +24,7 @@
#include <stdio.h>
#include <string.h>
+#include "libavutil/avassert.h"
#include "libavutil/avutil.h"
#include "libavutil/bswap.h"
#include "libavutil/cpu.h"
@@ -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_c(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_c(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,287 @@ 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;
+ }
+}
+
+/**
+ * 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->flags & SWS_ERROR_DIFFUSION) && 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);
+ }
+
+ 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 9544309..3d5d2af 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
@@ -351,10 +354,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 +378,10 @@ 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 yuv2rgb_y_offset;
int yuv2rgb_y_coeff;
int yuv2rgb_v2r_coeff;
@@ -418,8 +438,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 +473,14 @@ 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 xyz2rgb_matrix[3][4];
/* function pointers for swScale() */
yuv2planar1_fn yuv2plane1;
@@ -464,24 +492,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);
/** @} */
/**
@@ -576,7 +605,13 @@ SwsFunc ff_yuv2rgb_init_altivec(SwsContext *c);
SwsFunc ff_yuv2rgb_get_func_ptr_bfin(SwsContext *c);
void ff_bfin_get_unscaled_swscale(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)
{
@@ -589,9 +624,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);
@@ -622,8 +659,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 || \
@@ -632,9 +669,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 || \
@@ -648,11 +688,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 || \
@@ -666,19 +709,52 @@ 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;
+ 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);
@@ -687,6 +763,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);
@@ -713,12 +790,14 @@ 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 dithers[8][8][8];
+extern const uint16_t dither_scale[15][16];
+
extern const AVClass sws_context_class;
@@ -748,4 +827,24 @@ void ff_sws_init_output_funcs(SwsContext *c,
void ff_sws_init_swScale_altivec(SwsContext *c);
void ff_sws_init_swScale_mmx(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 9e7beb2..cdd8401 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,59 +32,101 @@
#include "libavutil/mathematics.h"
#include "libavutil/bswap.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/avassert.h"
-DECLARE_ALIGNED(8, 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, 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, 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,},
-};
-extern const uint8_t dither_8x8_128[8][8];
-DECLARE_ALIGNED(8, 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, 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,},
+}};
+
+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)
@@ -98,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)
@@ -301,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;
@@ -331,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;
@@ -353,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);
@@ -468,6 +492,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)
@@ -549,6 +589,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)
@@ -558,17 +612,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)) {
@@ -584,6 +632,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)) ||
@@ -625,6 +699,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;
}
@@ -636,16 +713,21 @@ 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;
@@ -655,15 +737,23 @@ static int rgbToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
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];
}
@@ -676,13 +766,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;
@@ -721,7 +812,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);
@@ -732,25 +823,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[],
@@ -761,174 +852,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, \
- 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)) {
@@ -985,7 +1034,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|SWS_ERROR_DIFFUSION)) && !(dstH & 1)) {
c->swScale = ff_yuv2rgb_get_func_ptr(c);
}
@@ -1006,6 +1055,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 || \
@@ -1024,23 +1077,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) {
@@ -1071,13 +1141,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 &&
@@ -1096,177 +1167,6 @@ void ff_get_unscaled_swscale(SwsContext *c)
ff_swscale_get_unscaled_altivec(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 e20a5f1..6bcd226 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"
@@ -53,18 +54,19 @@
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
@@ -105,6 +107,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 },
@@ -132,6 +138,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 },
@@ -153,27 +161,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, 0, 1 },
+ [AV_PIX_FMT_XYZ12LE] = { 1, 0, 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)
@@ -196,6 +225,7 @@ int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt)
extern const int32_t ff_yuv2rgb_coeffs[8][4];
+#if FF_API_SWS_FORMAT_NAME
const char *sws_format_name(enum AVPixelFormat format)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
@@ -204,6 +234,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)
@@ -223,7 +254,7 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
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 i;
int filterSize;
@@ -231,7 +262,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)
@@ -251,7 +282,7 @@ 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);
@@ -267,7 +298,7 @@ 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);
@@ -280,8 +311,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;
@@ -310,8 +340,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)
@@ -359,7 +388,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) {
@@ -410,8 +439,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;
@@ -424,13 +452,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++) {
@@ -512,13 +540,15 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
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)
@@ -542,29 +572,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;
}
}
@@ -605,6 +633,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;
@@ -783,6 +813,125 @@ static void getSubSampleFactors(int *h, int *v, enum AVPixelFormat format)
*v = desc->log2_chroma_h;
}
+static void fill_rgb2yuv_table(SwsContext *c, const int table[4], int dstRange)
+{
+ 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 && */table == 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;
+ static const int16_t xyz2rgb_matrix[3][4] = {
+ {13270, -6295, -2041},
+ {-3969, 7682, 170},
+ { 228, -835, 4329} };
+ static int16_t xyzgamma_tab[4096], rgbgamma_tab[4096];
+
+ memcpy(c->xyz2rgb_matrix, xyz2rgb_matrix, sizeof(c->xyz2rgb_matrix));
+ c->xyzgamma = xyzgamma_tab;
+ c->rgbgamma = rgbgamma_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);
+ }
+}
+
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)
@@ -792,17 +941,26 @@ int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4],
memcpy(c->srcColorspaceTable, inv_table, sizeof(int) * 4);
memcpy(c->dstColorspaceTable, table, sizeof(int) * 4);
+ 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);
+ if (!isYUV(c->dstFormat) && !isGray(c->dstFormat)) {
ff_yuv2rgb_c_init_tables(c, inv_table, srcRange, brightness,
contrast, saturation);
// FIXME factorize
@@ -810,6 +968,10 @@ int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4],
if (HAVE_ALTIVEC && av_get_cpu_flags() & AV_CPU_FLAG_ALTIVEC)
ff_yuv2rgb_init_tables_altivec(c, inv_table, brightness,
contrast, saturation);
+ }
+
+ fill_rgb2yuv_table(c, table, dstRange);
+
return 0;
}
@@ -817,7 +979,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 || isYUV(c->dstFormat) || isGray(c->dstFormat))
return -1;
*inv_table = c->srcColorspaceTable;
@@ -851,6 +1013,26 @@ static int handle_jpeg(enum AVPixelFormat *format)
}
}
+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;
+ }
+}
+
SwsContext *sws_alloc_context(void)
{
SwsContext *c = av_mallocz(sizeof(SwsContext));
@@ -866,7 +1048,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 };
@@ -874,8 +1056,7 @@ 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;
@@ -890,16 +1071,30 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
unscaled = (srcW == dstW && srcH == dstH);
+ handle_jpeg(&srcFormat);
+ handle_jpeg(&dstFormat);
+ if(srcFormat!=c->srcFormat || dstFormat!=c->dstFormat)
+ av_log(c, AV_LOG_WARNING, "deprecated pixel format used, make sure you did set range correctly\n");
+ handle_0alpha(&srcFormat);
+ handle_0alpha(&dstFormat);
+ handle_xyz(&srcFormat);
+ handle_xyz(&dstFormat);
+
+ if(srcFormat!=c->srcFormat || dstFormat!=c->dstFormat){
+ c->srcFormat= srcFormat;
+ c->dstFormat= 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);
}
}
@@ -916,12 +1111,11 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
SWS_SPLINE |
SWS_BICUBLIN);
if (!i || (i & (i - 1))) {
- av_log(c, AV_LOG_ERROR,
- "Exactly one scaler algorithm must be chosen\n");
+ av_log(c, AV_LOG_ERROR, "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",
@@ -952,6 +1146,33 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
getSubSampleFactors(&c->chrSrcHSubSample, &c->chrSrcVSubSample, srcFormat);
getSubSampleFactors(&c->chrDstHSubSample, &c->chrDstVSubSample, dstFormat);
+ 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(dstFormat == AV_PIX_FMT_BGR4_BYTE ||
+ dstFormat == AV_PIX_FMT_RGB4_BYTE ||
+ dstFormat == AV_PIX_FMT_BGR8 ||
+ dstFormat == AV_PIX_FMT_RGB8) {
+ if (flags & SWS_ERROR_DIFFUSION && !(flags & SWS_FULL_CHR_H_INT)) {
+ av_log(c, AV_LOG_DEBUG,
+ "Error diffusion dither is 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_ERROR_DIFFUSION) && (flags & SWS_FULL_CHR_H_INT)) {
+ 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));
+ flags |= SWS_ERROR_DIFFUSION;
+ c->flags = flags;
+ }
+ }
if (isPlanarRGB(dstFormat)) {
if (!(flags & SWS_FULL_CHR_H_INT)) {
av_log(c, AV_LOG_DEBUG,
@@ -972,10 +1193,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;
}
@@ -995,16 +1221,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 &&
@@ -1015,7 +1245,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;
}
}
@@ -1026,21 +1256,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;
@@ -1061,7 +1292,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;
}
@@ -1102,17 +1333,25 @@ 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);
@@ -1131,14 +1370,14 @@ 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) < 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) < 0)
goto fail;
}
} // initialize horizontal stuff
@@ -1154,14 +1393,14 @@ 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) < 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) < 0)
goto fail;
#if HAVE_ALTIVEC
@@ -1203,6 +1442,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);
@@ -1218,9 +1460,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);
@@ -1237,9 +1479,15 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
// try to avoid drawing green stuff between the right end and the stride end
for (i = 0; i < c->vChrBufSize; i++)
- memset(c->chrUPixBuf[i], 64, dst_stride * 2 + 1);
+ if(desc_dst->comp[0].depth_minus1 == 15){
+ av_assert0(c->dstBpc > 14);
+ for(j=0; j<dst_stride/2+1; j++)
+ ((int32_t*)(c->chrUPixBuf[i]))[j] = 1<<18;
+ } else
+ for(j=0; j<dst_stride+1; j++)
+ ((int16_t*)(c->chrUPixBuf[i]))[j] = 1<<14;
- assert(c->chrDstH <= dstH);
+ av_assert0(c->chrDstH <= dstH);
if (flags & SWS_PRINT_INFO) {
if (flags & SWS_FAST_BILINEAR)
@@ -1268,7 +1516,7 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
av_log(c, AV_LOG_INFO, "ehh flags invalid?! ");
av_log(c, AV_LOG_INFO, "from %s to %s%s ",
- sws_format_name(srcFormat),
+ 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 ||
@@ -1277,7 +1525,7 @@ 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");
@@ -1324,6 +1572,10 @@ SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat,
c->dstH = dstH;
c->srcRange = handle_jpeg(&srcFormat);
c->dstRange = handle_jpeg(&dstFormat);
+ c->src0Alpha = handle_0alpha(&srcFormat);
+ c->dst0Alpha = handle_0alpha(&dstFormat);
+ c->srcXYZ = handle_xyz(&srcFormat);
+ c->dstXYZ = handle_xyz(&dstFormat);
c->srcFormat = srcFormat;
c->dstFormat = dstFormat;
@@ -1408,7 +1660,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;
@@ -1423,7 +1680,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;
@@ -1678,6 +1940,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);
@@ -1712,7 +1977,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);
}
@@ -1751,10 +2016,14 @@ struct SwsContext *sws_getCachedContext(struct SwsContext *context, int srcW,
context->srcW = srcW;
context->srcH = srcH;
context->srcRange = handle_jpeg(&srcFormat);
+ context->src0Alpha = handle_0alpha(&srcFormat);
+ context->srcXYZ = handle_xyz(&srcFormat);
context->srcFormat = srcFormat;
context->dstW = dstW;
context->dstH = dstH;
context->dstRange = handle_jpeg(&dstFormat);
+ context->dst0Alpha = handle_0alpha(&dstFormat);
+ context->dstXYZ = handle_xyz(&dstFormat);
context->dstFormat = dstFormat;
context->flags = flags;
context->param[0] = param[0];
diff --git a/libswscale/version.h b/libswscale/version.h
index 5483673..f635e3d 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 3
+#define LIBSWSCALE_VERSION_MICRO 100
#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 5416d48..7d219b4 100644
--- a/libswscale/x86/Makefile
+++ b/libswscale/x86/Makefile
@@ -1,3 +1,5 @@
+$(SUBDIR)x86/swscale_mmx.o: CFLAGS += $(NOREDZONE_FLAGS)
+
OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o
MMX-OBJS += x86/rgb2rgb.o \
diff --git a/libswscale/x86/input.asm b/libswscale/x86/input.asm
index 6f5677e..48d533e8 100644
--- a/libswscale/x86/input.asm
+++ b/libswscale/x86/input.asm
@@ -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..f9add35 100644
--- a/libswscale/x86/output.asm
+++ b/libswscale/x86/output.asm
@@ -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..c6dafde 100644
--- a/libswscale/x86/scale.asm
+++ b/libswscale/x86/scale.asm
@@ -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 059589f..961b622 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)
@@ -312,21 +387,32 @@ av_cold void ff_sws_init_swScale_mmx(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
#endif /* HAVE_INLINE_ASM */
#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 d89a26f..f2567c1 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/yuv2rgb.c b/libswscale/x86/yuv2rgb.c
index 419d513..3938e6b 100644
--- a/libswscale/x86/yuv2rgb.c
+++ b/libswscale/x86/yuv2rgb.c
@@ -7,20 +7,20 @@
* 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
*/
@@ -74,10 +74,6 @@ av_cold SwsFunc ff_yuv2rgb_init_mmx(SwsContext *c)
#if HAVE_INLINE_ASM
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 6c65cc2..6d54293 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,11 +33,14 @@
#include "rgb2rgb.h"
#include "swscale.h"
#include "swscale_internal.h"
+#include "libavutil/pixdesc.h"
-extern const uint8_t dither_4x4_16[4][8];
-extern const uint8_t dither_8x8_32[8][8];
-extern const uint8_t dither_8x8_73[8][8];
-extern const uint8_t dither_8x8_220[8][8];
+extern const uint8_t dither_2x2_4[3][8];
+extern const uint8_t dither_2x2_8[3][8];
+extern const uint8_t dither_4x4_16[5][8];
+extern const uint8_t dither_8x8_32[9][8];
+extern const uint8_t dither_8x8_73[9][8];
+extern const uint8_t dither_8x8_220[9][8];
const int32_t ff_yuv2rgb_coeffs[8][4] = {
{ 117504, 138453, 13954, 34903 }, /* no sequence_display_extension */
@@ -61,9 +63,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]; \
@@ -387,24 +389,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 = dither_2x2_8[y & 1];
+ const uint8_t *e16 = dither_2x2_4[y & 1];
+ const uint8_t *f16 = 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 = dither_2x2_8[y & 1];
+ const uint8_t *e16 = 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
@@ -537,7 +580,7 @@ CLOSEYUV2RGBFUNC(8)
YUV2RGBFUNC(yuv2rgb_c_1_ordered_dither, uint8_t, 0)
const uint8_t *d128 = 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]; \
@@ -579,7 +622,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:
@@ -590,23 +633,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;
@@ -621,36 +662,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;
}
}
@@ -693,7 +730,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];
@@ -856,6 +893,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);
diff --git a/presets/libvpx-1080p.avpreset b/presets/libvpx-1080p.ffpreset
index 5c7da6f..cf25932 100644
--- a/presets/libvpx-1080p.avpreset
+++ b/presets/libvpx-1080p.ffpreset
@@ -1,8 +1,10 @@
+vcodec=libvpx
+
g=120
lag-in-frames=16
deadline=good
cpu-used=0
-profile=1
+vprofile=1
qmax=51
qmin=11
slices=4
diff --git a/presets/libvpx-1080p50_60.avpreset b/presets/libvpx-1080p50_60.ffpreset
index f85d3d6..4a88040 100644
--- a/presets/libvpx-1080p50_60.avpreset
+++ b/presets/libvpx-1080p50_60.ffpreset
@@ -1,8 +1,10 @@
+vcodec=libvpx
+
g=120
lag-in-frames=25
deadline=good
cpu-used=0
-profile=1
+vprofile=1
qmax=51
qmin=11
slices=4
diff --git a/presets/libvpx-360p.avpreset b/presets/libvpx-360p.ffpreset
index 2cb9e38..f9729ba 100644
--- a/presets/libvpx-360p.avpreset
+++ b/presets/libvpx-360p.ffpreset
@@ -1,8 +1,10 @@
+vcodec=libvpx
+
g=120
lag-in-frames=16
deadline=good
cpu-used=0
-profile=0
+vprofile=0
qmax=63
qmin=0
b=768k
diff --git a/presets/libvpx-720p.avpreset b/presets/libvpx-720p.ffpreset
index 3c7e396..e84cc15 100644
--- a/presets/libvpx-720p.avpreset
+++ b/presets/libvpx-720p.ffpreset
@@ -1,8 +1,10 @@
+vcodec=libvpx
+
g=120
lag-in-frames=16
deadline=good
cpu-used=0
-profile=0
+vprofile=0
qmax=51
qmin=11
slices=4
diff --git a/presets/libvpx-720p50_60.avpreset b/presets/libvpx-720p50_60.ffpreset
index 6139300..8fce2bf 100644
--- a/presets/libvpx-720p50_60.avpreset
+++ b/presets/libvpx-720p50_60.ffpreset
@@ -1,8 +1,10 @@
+vcodec=libvpx
+
g=120
lag-in-frames=25
deadline=good
cpu-used=0
-profile=0
+vprofile=0
qmax=51
qmin=11
slices=4
diff --git a/presets/libx264-baseline.avpreset b/presets/libx264-baseline.avpreset
deleted file mode 100644
index 0626e28..0000000
--- a/presets/libx264-baseline.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-profile=baseline
diff --git a/presets/libx264-fast.avpreset b/presets/libx264-fast.avpreset
deleted file mode 100644
index a8c526e..0000000
--- a/presets/libx264-fast.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=fast
diff --git a/presets/libx264-fast_firstpass.avpreset b/presets/libx264-fast_firstpass.avpreset
deleted file mode 100644
index d9cf5af..0000000
--- a/presets/libx264-fast_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=fast
-fastfirstpass=1
diff --git a/presets/libx264-faster.avpreset b/presets/libx264-faster.avpreset
deleted file mode 100644
index e311989..0000000
--- a/presets/libx264-faster.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=faster
diff --git a/presets/libx264-faster_firstpass.avpreset b/presets/libx264-faster_firstpass.avpreset
deleted file mode 100644
index 48a2d44..0000000
--- a/presets/libx264-faster_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=faster
-fastfirstpass=1
diff --git a/presets/libx264-ipod320.avpreset b/presets/libx264-ipod320.ffpreset
index 6323191..76722bd 100644
--- a/presets/libx264-ipod320.avpreset
+++ b/presets/libx264-ipod320.ffpreset
@@ -1,4 +1,6 @@
-profile=baseline
+vcodec=libx264
+
+vprofile=baseline
level=13
maxrate=768000
bufsize=3000000
diff --git a/presets/libx264-ipod640.avpreset b/presets/libx264-ipod640.ffpreset
index c2c3e1a..51f7564 100644
--- a/presets/libx264-ipod640.avpreset
+++ b/presets/libx264-ipod640.ffpreset
@@ -1,4 +1,6 @@
-profile=baseline
+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
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=fast
-qp=0
diff --git a/presets/libx264-lossless_max.avpreset b/presets/libx264-lossless_max.avpreset
deleted file mode 100644
index c25ff32..0000000
--- a/presets/libx264-lossless_max.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=placebo
-qp=0
diff --git a/presets/libx264-lossless_medium.avpreset b/presets/libx264-lossless_medium.avpreset
deleted file mode 100644
index f7b1d81..0000000
--- a/presets/libx264-lossless_medium.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=medium
-qp=0
diff --git a/presets/libx264-lossless_slow.avpreset b/presets/libx264-lossless_slow.avpreset
deleted file mode 100644
index a15ff4c..0000000
--- a/presets/libx264-lossless_slow.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=slow
-qp=0
diff --git a/presets/libx264-lossless_slower.avpreset b/presets/libx264-lossless_slower.avpreset
deleted file mode 100644
index bd71f03..0000000
--- a/presets/libx264-lossless_slower.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=slower
-qp=0
diff --git a/presets/libx264-lossless_ultrafast.avpreset b/presets/libx264-lossless_ultrafast.avpreset
deleted file mode 100644
index 4d71eb7..0000000
--- a/presets/libx264-lossless_ultrafast.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=ultrafast
-qp=0
diff --git a/presets/libx264-main.avpreset b/presets/libx264-main.avpreset
deleted file mode 100644
index 336c69b..0000000
--- a/presets/libx264-main.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-profile=main
diff --git a/presets/libx264-medium.avpreset b/presets/libx264-medium.avpreset
deleted file mode 100644
index 261d584..0000000
--- a/presets/libx264-medium.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=medium
diff --git a/presets/libx264-medium_firstpass.avpreset b/presets/libx264-medium_firstpass.avpreset
deleted file mode 100644
index 06c8f9f..0000000
--- a/presets/libx264-medium_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=medium
-fastfirstpass=1
diff --git a/presets/libx264-placebo.avpreset b/presets/libx264-placebo.avpreset
deleted file mode 100644
index 93d721d..0000000
--- a/presets/libx264-placebo.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=placebo
diff --git a/presets/libx264-placebo_firstpass.avpreset b/presets/libx264-placebo_firstpass.avpreset
deleted file mode 100644
index c8099e5..0000000
--- a/presets/libx264-placebo_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=placebo
-fastfirstpass=1
diff --git a/presets/libx264-slow.avpreset b/presets/libx264-slow.avpreset
deleted file mode 100644
index 85778ec..0000000
--- a/presets/libx264-slow.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=slow
diff --git a/presets/libx264-slow_firstpass.avpreset b/presets/libx264-slow_firstpass.avpreset
deleted file mode 100644
index 9998bc9..0000000
--- a/presets/libx264-slow_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=slow
-fastfirstpass=1
diff --git a/presets/libx264-slower.avpreset b/presets/libx264-slower.avpreset
deleted file mode 100644
index 87d6989..0000000
--- a/presets/libx264-slower.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=slower
diff --git a/presets/libx264-slower_firstpass.avpreset b/presets/libx264-slower_firstpass.avpreset
deleted file mode 100644
index c798b82..0000000
--- a/presets/libx264-slower_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=slower
-fastfirstpass=1
diff --git a/presets/libx264-superfast.avpreset b/presets/libx264-superfast.avpreset
deleted file mode 100644
index 1c117ec..0000000
--- a/presets/libx264-superfast.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=superfast
diff --git a/presets/libx264-superfast_firstpass.avpreset b/presets/libx264-superfast_firstpass.avpreset
deleted file mode 100644
index fc70e09..0000000
--- a/presets/libx264-superfast_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=superfast
-fastfirstpass=1
diff --git a/presets/libx264-ultrafast.avpreset b/presets/libx264-ultrafast.avpreset
deleted file mode 100644
index 9103301..0000000
--- a/presets/libx264-ultrafast.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=ultrafast
diff --git a/presets/libx264-ultrafast_firstpass.avpreset b/presets/libx264-ultrafast_firstpass.avpreset
deleted file mode 100644
index e3aaa17..0000000
--- a/presets/libx264-ultrafast_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=ultrafast
-fastfirstpass=1
diff --git a/presets/libx264-veryfast.avpreset b/presets/libx264-veryfast.avpreset
deleted file mode 100644
index fa49629..0000000
--- a/presets/libx264-veryfast.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=veryfast
diff --git a/presets/libx264-veryfast_firstpass.avpreset b/presets/libx264-veryfast_firstpass.avpreset
deleted file mode 100644
index 4909030..0000000
--- a/presets/libx264-veryfast_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=veryfast
-fastfirstpass=1
diff --git a/presets/libx264-veryslow.avpreset b/presets/libx264-veryslow.avpreset
deleted file mode 100644
index 7e01c8f..0000000
--- a/presets/libx264-veryslow.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=veryslow
diff --git a/presets/libx264-veryslow_firstpass.avpreset b/presets/libx264-veryslow_firstpass.avpreset
deleted file mode 100644
index daf5a8f..0000000
--- a/presets/libx264-veryslow_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=veryslow
-fastfirstpass=1
diff --git a/tests/Makefile b/tests/Makefile
index 939490b..99be14f 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
$(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
CHKCFG = $(if $($(1))$(!$(1)),$($(1)), $(error No such config: $(1)))
@@ -63,10 +84,13 @@ 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/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/image.mak
include $(SRC_PATH)/tests/fate/indeo.mak
@@ -85,6 +109,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
@@ -94,33 +119,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)'
@@ -131,7 +168,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
@@ -145,7 +182,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 4fa4656..09cf429 100644
--- a/tests/audiogen.c
+++ b/tests/audiogen.c
@@ -4,20 +4,20 @@
*
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/tests/base64.c b/tests/base64.c
index 6462d9a..5035ad9 100644
--- a/tests/base64.c
+++ b/tests/base64.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/tests/copycooker.sh b/tests/copycooker.sh
new file mode 100755
index 0000000..4b5811d
--- /dev/null
+++ b/tests/copycooker.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+datadir="tests/data"
+
+logfile="$datadir/copy.regression"
+reffile="$1"
+
+list=$(grep -oh ' ./tests/data/.*' tests/ref/{acodec,lavf,vsynth1}/*| sort)
+rm -f $logfile
+for i in $list ; do
+ echo ---------------- >> $logfile
+ echo $i >> $logfile
+ ./ffmpeg_g -flags +bitexact -i $i -acodec copy -vcodec copy -y first.nut
+ ./ffmpeg_g -flags +bitexact -i first.nut -acodec copy -vcodec copy -y second.nut
+ cmp first.nut second.nut >> $logfile
+ md5sum first.nut >> $logfile
+done
+
+if diff -u -w "$reffile" "$logfile" ; then
+ echo
+ echo copy regression test: success
+ exit 0
+else
+ echo
+ echo copy regression test: error
+ exit 1
+fi
diff --git a/tests/fate-run.sh b/tests/fate-run.sh
index b6c7384..9f5690d 100755
--- a/tests/fate-run.sh
+++ b/tests/fate-run.sh
@@ -72,37 +72,37 @@ 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(){
+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 "$@" -f framecrc -
}
framemd5(){
- avconv "$@" -f framemd5 -
+ ffmpeg "$@" -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 +114,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 +136,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 +164,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 +178,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 +243,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
--- /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
--- /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 86e4178..1f70e79 100755
--- a/tests/fate.sh
+++ b/tests/fate.sh
@@ -41,10 +41,11 @@ update()(
configure()(
cd ${build} || return
- ${src}/configure \
+ ${shell} ${src}/configure \
--prefix="${inst}" \
--samples="${samples}" \
--enable-gpl \
+ --enable-memory-poisoning \
${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 e840bf0..0b3999d 100644
--- a/tests/fate/aac.mak
+++ b/tests/fate/aac.mak
@@ -64,6 +64,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 $(SAMPLES)/aac/latm_000000001180bc60.mpg
fate-aac-latm_000000001180bc60: REF = $(SAMPLES)/aac/latm_000000001180bc60.s16
@@ -81,7 +98,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 23974ba..cc14c2a 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 $(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 bb4745b..c87d7c9 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 $(SAMPLES)/4xm/dracula.4xm -vn -map 0:6
+
+FATE_ADPCM-$(call DEMDEC, AST, ADPCM_AFC) += fate-adpcm-afc
+fate-adpcm-afc: CMD = framecrc -i $(SAMPLES)/ast/demo11_02_partial.ast
+
FATE_ADPCM-$(call DEMDEC, WAV, ADPCM_CT) += fate-adpcm-creative
fate-adpcm-creative: CMD = md5 -i $(SAMPLES)/creative/intro-partial.wav -f s16le
@@ -10,6 +16,9 @@ fate-adpcm-creative-8-2.6bit: CMD = md5 -i $(SAMPLES)/creative/BBC_3BIT.VOC -f s
FATE_ADPCM-$(call DEMDEC, VOC, ADPCM_SBPRO_4) += fate-adpcm-creative-8-4bit
fate-adpcm-creative-8-4bit: CMD = md5 -i $(SAMPLES)/creative/BBC_4BIT.VOC -f s16le
+FATE_ADPCM-$(call DEMDEC, ADP, ADPCM_DTK) += fate-adpcm-dtk
+fate-adpcm-dtk: CMD = framecrc -i $(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 $(SAMPLES)/ea-wve/networkBackbone-partial.wve -frames:a 26 -vn
@@ -49,6 +58,12 @@ fate-adpcm-ima-ea-sead: CMD = framecrc -i $(SAMPLES)/ea-tgv/INTEL_S.TGV -vn
FATE_ADPCM-$(call DEMDEC, ISS, ADPCM_IMA_ISS) += fate-adpcm-ima-iss
fate-adpcm-ima-iss: CMD = md5 -i $(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 $(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 $(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 $(SAMPLES)/smjpeg/scenwin.mjpg -vn
diff --git a/tests/fate/audio.mak b/tests/fate/audio.mak
index 7e08c2a..65bb146 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 $(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 $(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 $(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 $(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 $(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 $(SAMPLES)/paf/hod1-partial.paf -vn
+
+FATE_SAMPLES_AUDIO-$(call DEMDEC, VMD, VMDAUDIO) += fate-sierra-vmd-audio
fate-sierra-vmd-audio: CMD = framecrc -i $(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 $(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 $(SAMPLES)/smush/ronin_part.znm -vn
+
+FATE_SAMPLES_AUDIO-$(call DEMDEC, WSVQA, WS_SND1) += fate-ws_snd
fate-ws_snd: CMD = md5 -i $(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 56a384e..b175c3e 100644
--- a/tests/fate/cover-art.mak
+++ b/tests/fate/cover-art.mak
@@ -1,31 +1,33 @@
-FATE_COVER_ART += fate-cover-art-ape
+FATE_COVER_ART-$(CONFIG_APE_DEMUXER) += fate-cover-art-ape
fate-cover-art-ape: CMD = md5 -i $(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 $(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 $(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-wma
+FATE_COVER_ART-$(CONFIG_ASF_DEMUXER) += fate-cover-art-wma
fate-cover-art-wma: CMD = md5 -i $(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 $(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 $(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 $(SAMPLES)/cover_art/luckynight_cover.wv -an -c:v copy -f rawvideo
fate-cover-art-wv: REF = 45333c983c45af54449dff10af144317
+FATE_COVER_ART = $(FATE_COVER_ART-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 52b5515..ce54f8f 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 $(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 $(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 $(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 $(SAMPLES)/ast/demo11_02_partial.ast -c copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_BINK_DEMUXER) += fate-bink-demux
fate-bink-demux: CMD = crc -i $(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 $(SAMPLES)/brstm/lozswd_partial.brstm -acodec copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_CAF_DEMUXER) += fate-caf
fate-caf: CMD = crc -i $(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 $(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 $(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 $(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 $(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 $(SAMPLES)/jv/intro.jv -vcodec copy -acodec copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_LMLM4_DEMUXER) += fate-lmlm4-demux
fate-lmlm4-demux: CMD = framecrc -i $(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 $(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 $(SAMPLES)/mkv/test7_cut.mkv -c copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_MTV_DEMUXER) += fate-mtv
fate-mtv: CMD = framecrc -i $(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 $(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 $(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 $(SAMPLES)/nistsphere/nist-ulaw.nist -acodec copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_NSV_DEMUXER) += fate-nsv-demux
fate-nsv-demux: CMD = framecrc -i $(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 $(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 $(SAMPLES)/paf/hod1-partial.paf -vcodec copy -acodec copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_PMP_DEMUXER) += fate-pmp-demux
+fate-pmp-demux: CMD = framecrc -i $(SAMPLES)/pmp/demo.pmp -vn -c:a copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_RSD_DEMUXER) += fate-rsd-demux
+fate-rsd-demux: CMD = crc -i $(SAMPLES)/rsd/hum01_partial.rsd -c:a copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_REDSPARK_DEMUXER) += fate-redspark-demux
+fate-redspark-demux: CMD = crc -i $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 d333042..81e14b8 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 $(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 $(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 $(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 $(SAMPLES)/ea-tgq/v27.tgq -an
FATE_EA_TGV += fate-ea-tgv-1
@@ -16,8 +16,11 @@ fate-ea-tgv-1: CMD = framecrc -i $(SAMPLES)/ea-tgv/INTRO8K-partial.TGV -pix_fmt
FATE_EA_TGV += fate-ea-tgv-2
fate-ea-tgv-2: CMD = framecrc -i $(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 $(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/ffmpeg.mak b/tests/fate/ffmpeg.mak
new file mode 100644
index 0000000..21cdd5f
--- /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
--- /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/filter-audio.mak b/tests/fate/filter-audio.mak
index ac025c4..a4168ee 100644
--- a/tests/fate/filter-audio.mak
+++ b/tests/fate/filter-audio.mak
@@ -1,15 +1,15 @@
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 +23,13 @@ FATE_AFILTER-$(call FILTERDEMDECMUX, ASYNCTS, FLV, NELLYMOSER, PCM_S16LE) += fat
fate-filter-asyncts: SRC = $(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-v2.pcm
+
+FATE_FILTER-$(CONFIG_ARESAMPLE_FILTER) += fate-filter-aresample
+fate-filter-aresample: SRC = $(SAMPLES)/nellymoser/nellymoser-discont.flv
+fate-filter-aresample: CMD = pcm -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
@@ -46,7 +52,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 $(SRC_PATH)/tests/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
@@ -61,12 +67,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 f4e813c..2df9cc8 100644
--- a/tests/fate/filter-video.mak
+++ b/tests/fate/filter-video.mak
@@ -1,25 +1,38 @@
-FATE_FILTER-$(call FILTERDEMDEC, DELOGO, RM, RV30) += fate-filter-delogo
-fate-filter-delogo: CMD = framecrc -i $(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 $(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 $(SAMPLES)/mpeg2/mpeg2_field_encoding.ts -vf yadif=0
+fate-filter-yadif-mode0: CMD = framecrc -flags bitexact -idct simple -i $(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 $(SAMPLES)/mpeg2/mpeg2_field_encoding.ts -vf yadif=1
+fate-filter-yadif-mode1: CMD = framecrc -flags bitexact -idct simple -i $(SAMPLES)/mpeg2/mpeg2_field_encoding.ts -vframes 59 -vf yadif=1
FATE_FILTER-$(call FILTERDEMDEC, YADIF, MPEGTS, MPEG2VIDEO) += $(FATE_YADIF)
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-$(CONFIG_GRADFUN_FILTER) += fate-filter-gradfun
fate-filter-gradfun: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf gradfun
@@ -30,15 +43,36 @@ 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 histogram=mode=waveform -flags +bitexact -sws_flags +accurate_rnd+bitexact
FATE_FILTER_VSYNTH-$(CONFIG_OVERLAY_FILTER) += fate-filter-overlay
fate-filter-overlay: CMD = framecrc -c:v pgmyuv -i $(SRC) -c:v pgmyuv -i $(SRC) -filter_complex_script $(SRC_PATH)/tests/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_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: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_script $(SRC_PATH)/tests/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
@@ -57,8 +91,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 $(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 $(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 $(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"
@@ -84,47 +135,149 @@ fate-filter-scale500: CMD = video_filter "scale=500: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_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_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_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 92eb743..172f661 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 $(REF) -c flac $(OPTS)
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..110a067
--- /dev/null
+++ b/tests/fate/gif.mak
@@ -0,0 +1,27 @@
+FATE_GIF += fate-gif-color
+fate-gif-color: CMD = framecrc -i $(SAMPLES)/gif/tc217.gif -pix_fmt bgra
+
+FATE_GIF += fate-gif-disposal-background
+fate-gif-disposal-background: CMD = framecrc -trans_color 0 -i $(SAMPLES)/gif/m4nb.gif -pix_fmt bgra
+
+FATE_GIF += fate-gif-disposal-restore
+fate-gif-disposal-restore: CMD = framecrc -i $(SAMPLES)/gif/banner2.gif -pix_fmt bgra
+
+FATE_GIF += fate-gif-gray
+fate-gif-gray: CMD = framecrc -i $(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 d43db3f..0b336fc 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 $(SAMPLES)/h264-conformance/AUD_MW_E.264
-fate-h264-conformance-ba1_ft_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/BA1_FT_C.264
-fate-h264-conformance-ba1_sony_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/BA1_Sony_D.jsv
-fate-h264-conformance-ba2_sony_f: CMD = framecrc -i $(SAMPLES)/h264-conformance/BA2_Sony_F.jsv
-fate-h264-conformance-ba3_sva_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/BA3_SVA_C.264
-fate-h264-conformance-ba_mw_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/BA_MW_D.264
-fate-h264-conformance-bamq1_jvc_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/BAMQ1_JVC_C.264
-fate-h264-conformance-bamq2_jvc_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/BAMQ2_JVC_C.264
-fate-h264-conformance-banm_mw_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/BANM_MW_D.264
-fate-h264-conformance-basqp1_sony_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/BASQP1_Sony_C.jsv
-fate-h264-conformance-caba1_sony_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/CABA1_Sony_D.jsv
-fate-h264-conformance-caba1_sva_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CABA1_SVA_B.264
-fate-h264-conformance-caba2_sony_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CABA2_Sony_E.jsv
-fate-h264-conformance-caba2_sva_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CABA2_SVA_B.264
-fate-h264-conformance-caba3_sony_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CABA3_Sony_C.jsv
-fate-h264-conformance-caba3_sva_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CABA3_SVA_B.264
-fate-h264-conformance-caba3_toshiba_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CABA3_TOSHIBA_E.264
-fate-h264-conformance-cabac_mot_fld0_full: CMD = framecrc -i $(SAMPLES)/h264-conformance/camp_mot_fld0_full.26l
-fate-h264-conformance-cabac_mot_frm0_full: CMD = framecrc -i $(SAMPLES)/h264-conformance/camp_mot_frm0_full.26l
-fate-h264-conformance-cabac_mot_mbaff0_full: CMD = framecrc -i $(SAMPLES)/h264-conformance/camp_mot_mbaff0_full.26l
-fate-h264-conformance-cabac_mot_picaff0_full: CMD = framecrc -i $(SAMPLES)/h264-conformance/camp_mot_picaff0_full.26l
-fate-h264-conformance-cabaci3_sony_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CABACI3_Sony_B.jsv
-fate-h264-conformance-cabast3_sony_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CABAST3_Sony_E.jsv
-fate-h264-conformance-cabastbr3_sony_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CABASTBR3_Sony_B.jsv
-fate-h264-conformance-cabref3_sand_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/CABREF3_Sand_D.264
-fate-h264-conformance-cacqp3_sony_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/CACQP3_Sony_D.jsv
-fate-h264-conformance-cafi1_sva_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAFI1_SVA_C.264
-fate-h264-conformance-cama1_sony_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAMA1_Sony_C.jsv
-fate-h264-conformance-cama1_toshiba_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAMA1_TOSHIBA_B.264
-fate-h264-conformance-cama1_vtc_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/cama1_vtc_c.avc
-fate-h264-conformance-cama2_vtc_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/cama2_vtc_b.avc
-fate-h264-conformance-cama3_sand_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAMA3_Sand_E.264
-fate-h264-conformance-cama3_vtc_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/cama3_vtc_b.avc
-fate-h264-conformance-camaci3_sony_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAMACI3_Sony_C.jsv
-fate-h264-conformance-camanl1_toshiba_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAMANL1_TOSHIBA_B.264
-fate-h264-conformance-camanl2_toshiba_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAMANL2_TOSHIBA_B.264
-fate-h264-conformance-camanl3_sand_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAMANL3_Sand_E.264
-fate-h264-conformance-camasl3_sony_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAMASL3_Sony_B.jsv
-fate-h264-conformance-camp_mot_mbaff_l30: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAMP_MOT_MBAFF_L30.26l
-fate-h264-conformance-camp_mot_mbaff_l31: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAMP_MOT_MBAFF_L31.26l
-fate-h264-conformance-canl1_sony_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CANL1_Sony_E.jsv
-fate-h264-conformance-canl1_sva_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CANL1_SVA_B.264
-fate-h264-conformance-canl1_toshiba_g: CMD = framecrc -i $(SAMPLES)/h264-conformance/CANL1_TOSHIBA_G.264
-fate-h264-conformance-canl2_sony_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CANL2_Sony_E.jsv
-fate-h264-conformance-canl2_sva_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CANL2_SVA_B.264
-fate-h264-conformance-canl3_sony_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CANL3_Sony_C.jsv
-fate-h264-conformance-canl3_sva_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CANL3_SVA_B.264
-fate-h264-conformance-canl4_sva_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CANL4_SVA_B.264
-fate-h264-conformance-canlma2_sony_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CANLMA2_Sony_C.jsv
-fate-h264-conformance-canlma3_sony_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CANLMA3_Sony_C.jsv
-fate-h264-conformance-capa1_toshiba_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAPA1_TOSHIBA_B.264
-fate-h264-conformance-capama3_sand_f: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAPAMA3_Sand_F.264
-fate-h264-conformance-capcm1_sand_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAPCM1_Sand_E.264
-fate-h264-conformance-capcmnl1_sand_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAPCMNL1_Sand_E.264
-fate-h264-conformance-capm3_sony_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAPM3_Sony_D.jsv
-fate-h264-conformance-caqp1_sony_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAQP1_Sony_B.jsv
-fate-h264-conformance-cavlc_mot_fld0_full_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/cvmp_mot_fld0_full_B.26l
-fate-h264-conformance-cavlc_mot_frm0_full_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/cvmp_mot_frm0_full_B.26l
-fate-h264-conformance-cavlc_mot_mbaff0_full_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/cvmp_mot_mbaff0_full_B.26l
-fate-h264-conformance-cavlc_mot_picaff0_full_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/cvmp_mot_picaff0_full_B.26l
-fate-h264-conformance-cawp1_toshiba_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAWP1_TOSHIBA_E.264
-fate-h264-conformance-cawp5_toshiba_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CAWP5_TOSHIBA_E.264
-fate-h264-conformance-ci1_ft_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CI1_FT_B.264
-fate-h264-conformance-ci_mw_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/CI_MW_D.264
-fate-h264-conformance-cvbs3_sony_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVBS3_Sony_C.jsv
-fate-h264-conformance-cvcanlma2_sony_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVCANLMA2_Sony_C.jsv
+fate-h264-conformance-aud_mw_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/AUD_MW_E.264
+fate-h264-conformance-ba1_ft_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/BA1_FT_C.264
+fate-h264-conformance-ba1_sony_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/BA1_Sony_D.jsv
+fate-h264-conformance-ba2_sony_f: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/BA2_Sony_F.jsv
+fate-h264-conformance-ba3_sva_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/BA3_SVA_C.264
+fate-h264-conformance-ba_mw_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/BA_MW_D.264
+fate-h264-conformance-bamq1_jvc_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/BAMQ1_JVC_C.264
+fate-h264-conformance-bamq2_jvc_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/BAMQ2_JVC_C.264
+fate-h264-conformance-banm_mw_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/BANM_MW_D.264
+fate-h264-conformance-basqp1_sony_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/BASQP1_Sony_C.jsv
+fate-h264-conformance-caba1_sony_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CABA1_Sony_D.jsv
+fate-h264-conformance-caba1_sva_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CABA1_SVA_B.264
+fate-h264-conformance-caba2_sony_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CABA2_Sony_E.jsv
+fate-h264-conformance-caba2_sva_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CABA2_SVA_B.264
+fate-h264-conformance-caba3_sony_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CABA3_Sony_C.jsv
+fate-h264-conformance-caba3_sva_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CABA3_SVA_B.264
+fate-h264-conformance-caba3_toshiba_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CABA3_TOSHIBA_E.264
+fate-h264-conformance-cabac_mot_fld0_full: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/camp_mot_fld0_full.26l
+fate-h264-conformance-cabac_mot_frm0_full: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/camp_mot_frm0_full.26l
+fate-h264-conformance-cabac_mot_mbaff0_full: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/camp_mot_mbaff0_full.26l
+fate-h264-conformance-cabac_mot_picaff0_full: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/camp_mot_picaff0_full.26l
+fate-h264-conformance-cabaci3_sony_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CABACI3_Sony_B.jsv
+fate-h264-conformance-cabast3_sony_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CABAST3_Sony_E.jsv
+fate-h264-conformance-cabastbr3_sony_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CABASTBR3_Sony_B.jsv
+fate-h264-conformance-cabref3_sand_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CABREF3_Sand_D.264
+fate-h264-conformance-cacqp3_sony_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CACQP3_Sony_D.jsv
+fate-h264-conformance-cafi1_sva_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAFI1_SVA_C.264
+fate-h264-conformance-cama1_sony_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAMA1_Sony_C.jsv
+fate-h264-conformance-cama1_toshiba_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAMA1_TOSHIBA_B.264
+fate-h264-conformance-cama1_vtc_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/cama1_vtc_c.avc
+fate-h264-conformance-cama2_vtc_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/cama2_vtc_b.avc
+fate-h264-conformance-cama3_sand_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAMA3_Sand_E.264
+fate-h264-conformance-cama3_vtc_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/cama3_vtc_b.avc
+fate-h264-conformance-camaci3_sony_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAMACI3_Sony_C.jsv
+fate-h264-conformance-camanl1_toshiba_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAMANL1_TOSHIBA_B.264
+fate-h264-conformance-camanl2_toshiba_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAMANL2_TOSHIBA_B.264
+fate-h264-conformance-camanl3_sand_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAMANL3_Sand_E.264
+fate-h264-conformance-camasl3_sony_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAMASL3_Sony_B.jsv
+fate-h264-conformance-camp_mot_mbaff_l30: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAMP_MOT_MBAFF_L30.26l
+fate-h264-conformance-camp_mot_mbaff_l31: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAMP_MOT_MBAFF_L31.26l
+fate-h264-conformance-canl1_sony_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CANL1_Sony_E.jsv
+fate-h264-conformance-canl1_sva_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CANL1_SVA_B.264
+fate-h264-conformance-canl1_toshiba_g: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CANL1_TOSHIBA_G.264
+fate-h264-conformance-canl2_sony_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CANL2_Sony_E.jsv
+fate-h264-conformance-canl2_sva_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CANL2_SVA_B.264
+fate-h264-conformance-canl3_sony_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CANL3_Sony_C.jsv
+fate-h264-conformance-canl3_sva_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CANL3_SVA_B.264
+fate-h264-conformance-canl4_sva_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CANL4_SVA_B.264
+fate-h264-conformance-canlma2_sony_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CANLMA2_Sony_C.jsv
+fate-h264-conformance-canlma3_sony_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CANLMA3_Sony_C.jsv
+fate-h264-conformance-capa1_toshiba_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAPA1_TOSHIBA_B.264
+fate-h264-conformance-capama3_sand_f: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAPAMA3_Sand_F.264
+fate-h264-conformance-capcm1_sand_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAPCM1_Sand_E.264
+fate-h264-conformance-capcmnl1_sand_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAPCMNL1_Sand_E.264
+fate-h264-conformance-capm3_sony_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAPM3_Sony_D.jsv
+fate-h264-conformance-caqp1_sony_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAQP1_Sony_B.jsv
+fate-h264-conformance-cavlc_mot_fld0_full_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/cvmp_mot_fld0_full_B.26l
+fate-h264-conformance-cavlc_mot_frm0_full_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/cvmp_mot_frm0_full_B.26l
+fate-h264-conformance-cavlc_mot_mbaff0_full_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/cvmp_mot_mbaff0_full_B.26l
+fate-h264-conformance-cavlc_mot_picaff0_full_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/cvmp_mot_picaff0_full_B.26l
+fate-h264-conformance-cawp1_toshiba_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAWP1_TOSHIBA_E.264
+fate-h264-conformance-cawp5_toshiba_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CAWP5_TOSHIBA_E.264
+fate-h264-conformance-ci1_ft_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CI1_FT_B.264
+fate-h264-conformance-ci_mw_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CI_MW_D.264
+fate-h264-conformance-cvbs3_sony_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVBS3_Sony_C.jsv
+fate-h264-conformance-cvcanlma2_sony_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVCANLMA2_Sony_C.jsv
fate-h264-conformance-cvfc1_sony_c: CMD = framecrc -flags unaligned -i $(SAMPLES)/h264-conformance/CVFC1_Sony_C.jsv
-fate-h264-conformance-cvfi1_sony_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVFI1_Sony_D.jsv
-fate-h264-conformance-cvfi1_sva_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVFI1_SVA_C.264
-fate-h264-conformance-cvfi2_sony_h: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVFI2_Sony_H.jsv
-fate-h264-conformance-cvfi2_sva_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVFI2_SVA_C.264
-fate-h264-conformance-cvma1_sony_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVMA1_Sony_D.jsv
-fate-h264-conformance-cvma1_toshiba_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVMA1_TOSHIBA_B.264
-fate-h264-conformance-cvmanl1_toshiba_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVMANL1_TOSHIBA_B.264
-fate-h264-conformance-cvmanl2_toshiba_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVMANL2_TOSHIBA_B.264
-fate-h264-conformance-cvmapaqp3_sony_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVMAPAQP3_Sony_E.jsv
-fate-h264-conformance-cvmaqp2_sony_g: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVMAQP2_Sony_G.jsv
-fate-h264-conformance-cvmaqp3_sony_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVMAQP3_Sony_D.jsv
-fate-h264-conformance-cvmp_mot_fld_l30_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVMP_MOT_FLD_L30_B.26l
-fate-h264-conformance-cvmp_mot_frm_l31_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVMP_MOT_FRM_L31_B.26l
-fate-h264-conformance-cvnlfi1_sony_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVNLFI1_Sony_C.jsv
-fate-h264-conformance-cvnlfi2_sony_h: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVNLFI2_Sony_H.jsv
-fate-h264-conformance-cvpa1_toshiba_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVPA1_TOSHIBA_B.264
-fate-h264-conformance-cvpcmnl1_sva_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVPCMNL1_SVA_C.264
-fate-h264-conformance-cvpcmnl2_sva_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVPCMNL2_SVA_C.264
-fate-h264-conformance-cvwp1_toshiba_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVWP1_TOSHIBA_E.264
-fate-h264-conformance-cvwp2_toshiba_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVWP2_TOSHIBA_E.264
-fate-h264-conformance-cvwp3_toshiba_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVWP3_TOSHIBA_E.264
-fate-h264-conformance-cvwp5_toshiba_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/CVWP5_TOSHIBA_E.264
-fate-h264-conformance-fi1_sony_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/FI1_Sony_E.jsv
-fate-h264-conformance-frext-alphaconformanceg: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/test8b43.264
-fate-h264-conformance-frext-bcrm_freh10: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/freh10.264 -vsync 0
-fate-h264-conformance-frext-brcm_freh11: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/freh11.264 -vsync 0
-fate-h264-conformance-frext-brcm_freh3: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/freh3.264
-fate-h264-conformance-frext-brcm_freh4: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/freh4.264 -vsync 0
-fate-h264-conformance-frext-brcm_freh5: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/freh5.264
-fate-h264-conformance-frext-brcm_freh8: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/freh8.264
-fate-h264-conformance-frext-brcm_freh9: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/freh9.264
-fate-h264-conformance-frext-freh12_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/Freh12_B.264
-fate-h264-conformance-frext-freh1_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/Freh1_B.264
-fate-h264-conformance-frext-freh2_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/Freh2_B.264
-fate-h264-conformance-frext-freh6: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/freh6.264 -vsync 0
-fate-h264-conformance-frext-freh7_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/Freh7_B.264 -vsync 0
-fate-h264-conformance-frext-frext01_jvc_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/FREXT01_JVC_D.264
-fate-h264-conformance-frext-frext02_jvc_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/FREXT02_JVC_C.264
-fate-h264-conformance-frext-frext1_panasonic_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/FRExt1_Panasonic.avc
-fate-h264-conformance-frext-frext2_panasonic_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/FRExt2_Panasonic.avc -vsync 0
-fate-h264-conformance-frext-frext3_panasonic_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/FRExt3_Panasonic.avc
-fate-h264-conformance-frext-frext4_panasonic_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/FRExt4_Panasonic.avc
-fate-h264-conformance-frext-frext_mmco4_sony_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/FRExt_MMCO4_Sony_B.264
-fate-h264-conformance-frext-hcaff1_hhi_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HCAFF1_HHI.264
-fate-h264-conformance-frext-hcafr1_hhi_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HCAFR1_HHI.264
-fate-h264-conformance-frext-hcafr2_hhi_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HCAFR2_HHI.264
-fate-h264-conformance-frext-hcafr3_hhi_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HCAFR3_HHI.264
-fate-h264-conformance-frext-hcafr4_hhi_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HCAFR4_HHI.264
-fate-h264-conformance-frext-hcamff1_hhi_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HCAMFF1_HHI.264
-fate-h264-conformance-frext-hpca_brcm_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCA_BRCM_C.264
-fate-h264-conformance-frext-hpcadq_brcm_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCADQ_BRCM_B.264
-fate-h264-conformance-frext-hpcafl_bcrm_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCAFL_BRCM_C.264 -vsync 0
-fate-h264-conformance-frext-hpcaflnl_bcrm_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCAFLNL_BRCM_C.264 -vsync 0
-fate-h264-conformance-frext-hpcalq_brcm_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCALQ_BRCM_B.264
-fate-h264-conformance-frext-hpcamapalq_bcrm_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCAMAPALQ_BRCM_B.264 -vsync 0
-fate-h264-conformance-frext-hpcamolq_brcm_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCAMOLQ_BRCM_B.264
-fate-h264-conformance-frext-hpcanl_brcm_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCANL_BRCM_C.264
-fate-h264-conformance-frext-hpcaq2lq_brcm_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCAQ2LQ_BRCM_B.264
-fate-h264-conformance-frext-hpcv_brcm_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCV_BRCM_A.264
-fate-h264-conformance-frext-hpcvfl_bcrm_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCVFL_BRCM_A.264 -vsync 0
-fate-h264-conformance-frext-hpcvflnl_bcrm_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCVFLNL_BRCM_A.264 -vsync 0
-fate-h264-conformance-frext-hpcvmolq_brcm_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCVMOLQ_BRCM_B.264
-fate-h264-conformance-frext-hpcvnl_brcm_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/HPCVNL_BRCM_A.264
-fate-h264-conformance-frext-pph10i1_panasonic_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/PPH10I1_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-frext-pph10i2_panasonic_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/PPH10I2_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-frext-pph10i3_panasonic_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/PPH10I3_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-frext-pph10i4_panasonic_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/PPH10I4_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-frext-pph10i5_panasonic_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/PPH10I5_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-frext-pph10i6_panasonic_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/PPH10I6_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-frext-pph10i7_panasonic_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/FRext/PPH10I7_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-hcbp2_hhi_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/HCBP2_HHI_A.264
-fate-h264-conformance-hcmp1_hhi_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/HCMP1_HHI_A.264
-fate-h264-conformance-ls_sva_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/LS_SVA_D.264
-fate-h264-conformance-midr_mw_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/MIDR_MW_D.264
-fate-h264-conformance-mps_mw_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/MPS_MW_A.264
-fate-h264-conformance-mr1_bt_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/MR1_BT_A.h264
-fate-h264-conformance-mr1_mw_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/MR1_MW_A.264
-fate-h264-conformance-mr2_mw_a: CMD = framecrc -i $(SAMPLES)/h264-conformance/MR2_MW_A.264
-fate-h264-conformance-mr2_tandberg_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/MR2_TANDBERG_E.264
-fate-h264-conformance-mr3_tandberg_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/MR3_TANDBERG_B.264
-fate-h264-conformance-mr4_tandberg_c: CMD = framecrc -strict 1 -i $(SAMPLES)/h264-conformance/MR4_TANDBERG_C.264
-fate-h264-conformance-mr5_tandberg_c: CMD = framecrc -strict 1 -i $(SAMPLES)/h264-conformance/MR5_TANDBERG_C.264
-fate-h264-conformance-mr6_bt_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/MR6_BT_B.h264
-fate-h264-conformance-mr7_bt_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/MR7_BT_B.h264
-fate-h264-conformance-mr8_bt_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/MR8_BT_B.h264
-fate-h264-conformance-mr9_bt_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/MR9_BT_B.h264
-fate-h264-conformance-mv1_brcm_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/src19td.IBP.264
-fate-h264-conformance-nl1_sony_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/NL1_Sony_D.jsv
-fate-h264-conformance-nl2_sony_h: CMD = framecrc -i $(SAMPLES)/h264-conformance/NL2_Sony_H.jsv
-fate-h264-conformance-nl3_sva_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/NL3_SVA_E.264
-fate-h264-conformance-nlmq1_jvc_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/NLMQ1_JVC_C.264
-fate-h264-conformance-nlmq2_jvc_c: CMD = framecrc -i $(SAMPLES)/h264-conformance/NLMQ2_JVC_C.264
-fate-h264-conformance-nrf_mw_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/NRF_MW_E.264
-fate-h264-conformance-sharp_mp_field_1_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/Sharp_MP_Field_1_B.jvt
-fate-h264-conformance-sharp_mp_field_2_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/Sharp_MP_Field_2_B.jvt
-fate-h264-conformance-sharp_mp_field_3_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/Sharp_MP_Field_3_B.jvt
-fate-h264-conformance-sharp_mp_paff_1r2: CMD = framecrc -i $(SAMPLES)/h264-conformance/Sharp_MP_PAFF_1r2.jvt
-fate-h264-conformance-sharp_mp_paff_2r: CMD = framecrc -i $(SAMPLES)/h264-conformance/Sharp_MP_PAFF_2.jvt
-fate-h264-conformance-sl1_sva_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/SL1_SVA_B.264
-fate-h264-conformance-sva_ba1_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/SVA_BA1_B.264
-fate-h264-conformance-sva_ba2_d: CMD = framecrc -i $(SAMPLES)/h264-conformance/SVA_BA2_D.264
-fate-h264-conformance-sva_base_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/SVA_Base_B.264
-fate-h264-conformance-sva_cl1_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/SVA_CL1_E.264
-fate-h264-conformance-sva_fm1_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/SVA_FM1_E.264
-fate-h264-conformance-sva_nl1_b: CMD = framecrc -i $(SAMPLES)/h264-conformance/SVA_NL1_B.264
-fate-h264-conformance-sva_nl2_e: CMD = framecrc -i $(SAMPLES)/h264-conformance/SVA_NL2_E.264
+fate-h264-conformance-cvfi1_sony_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVFI1_Sony_D.jsv
+fate-h264-conformance-cvfi1_sva_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVFI1_SVA_C.264
+fate-h264-conformance-cvfi2_sony_h: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVFI2_Sony_H.jsv
+fate-h264-conformance-cvfi2_sva_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVFI2_SVA_C.264
+fate-h264-conformance-cvma1_sony_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVMA1_Sony_D.jsv
+fate-h264-conformance-cvma1_toshiba_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVMA1_TOSHIBA_B.264
+fate-h264-conformance-cvmanl1_toshiba_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVMANL1_TOSHIBA_B.264
+fate-h264-conformance-cvmanl2_toshiba_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVMANL2_TOSHIBA_B.264
+fate-h264-conformance-cvmapaqp3_sony_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVMAPAQP3_Sony_E.jsv
+fate-h264-conformance-cvmaqp2_sony_g: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVMAQP2_Sony_G.jsv
+fate-h264-conformance-cvmaqp3_sony_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVMAQP3_Sony_D.jsv
+fate-h264-conformance-cvmp_mot_fld_l30_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVMP_MOT_FLD_L30_B.26l
+fate-h264-conformance-cvmp_mot_frm_l31_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVMP_MOT_FRM_L31_B.26l
+fate-h264-conformance-cvnlfi1_sony_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVNLFI1_Sony_C.jsv
+fate-h264-conformance-cvnlfi2_sony_h: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVNLFI2_Sony_H.jsv
+fate-h264-conformance-cvpa1_toshiba_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVPA1_TOSHIBA_B.264
+fate-h264-conformance-cvpcmnl1_sva_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVPCMNL1_SVA_C.264
+fate-h264-conformance-cvpcmnl2_sva_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVPCMNL2_SVA_C.264
+fate-h264-conformance-cvwp1_toshiba_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVWP1_TOSHIBA_E.264
+fate-h264-conformance-cvwp2_toshiba_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVWP2_TOSHIBA_E.264
+fate-h264-conformance-cvwp3_toshiba_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVWP3_TOSHIBA_E.264
+fate-h264-conformance-cvwp5_toshiba_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/CVWP5_TOSHIBA_E.264
+fate-h264-conformance-fi1_sony_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FI1_Sony_E.jsv
+fate-h264-conformance-frext-alphaconformanceg: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/test8b43.264
+fate-h264-conformance-frext-bcrm_freh10: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/freh10.264 -vsync drop
+fate-h264-conformance-frext-brcm_freh11: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/freh11.264 -vsync drop
+fate-h264-conformance-frext-brcm_freh3: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/freh3.264
+fate-h264-conformance-frext-brcm_freh4: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/freh4.264 -vsync drop
+fate-h264-conformance-frext-brcm_freh5: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/freh5.264
+fate-h264-conformance-frext-brcm_freh8: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/freh8.264
+fate-h264-conformance-frext-brcm_freh9: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/freh9.264
+fate-h264-conformance-frext-freh12_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/Freh12_B.264
+fate-h264-conformance-frext-freh1_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/Freh1_B.264
+fate-h264-conformance-frext-freh2_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/Freh2_B.264
+fate-h264-conformance-frext-freh6: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/freh6.264 -vsync drop
+fate-h264-conformance-frext-freh7_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/Freh7_B.264 -vsync drop
+fate-h264-conformance-frext-frext01_jvc_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/FREXT01_JVC_D.264
+fate-h264-conformance-frext-frext02_jvc_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/FREXT02_JVC_C.264
+fate-h264-conformance-frext-frext1_panasonic_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/FRExt1_Panasonic.avc
+fate-h264-conformance-frext-frext2_panasonic_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/FRExt2_Panasonic.avc -vsync 0
+fate-h264-conformance-frext-frext3_panasonic_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/FRExt3_Panasonic.avc
+fate-h264-conformance-frext-frext4_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/FRExt4_Panasonic.avc
+fate-h264-conformance-frext-frext_mmco4_sony_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/FRExt_MMCO4_Sony_B.264
+fate-h264-conformance-frext-hcaff1_hhi_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HCAFF1_HHI.264
+fate-h264-conformance-frext-hcafr1_hhi_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HCAFR1_HHI.264
+fate-h264-conformance-frext-hcafr2_hhi_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HCAFR2_HHI.264
+fate-h264-conformance-frext-hcafr3_hhi_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HCAFR3_HHI.264
+fate-h264-conformance-frext-hcafr4_hhi_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HCAFR4_HHI.264
+fate-h264-conformance-frext-hcamff1_hhi_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HCAMFF1_HHI.264
+fate-h264-conformance-frext-hi422fr10_sony_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/Hi422FR10_SONY_B.264
+fate-h264-conformance-frext-hi422fr13_sony_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/Hi422FR13_SONY_B.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-hi422fr1_sony_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/Hi422FR1_SONY_A.jsv
+fate-h264-conformance-frext-hi422fr6_sony_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/Hi422FR6_SONY_A.jsv -pix_fmt yuv422p10le
+fate-h264-conformance-frext-hpca_brcm_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCA_BRCM_C.264
+fate-h264-conformance-frext-hpcadq_brcm_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCADQ_BRCM_B.264
+fate-h264-conformance-frext-hpcafl_bcrm_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCAFL_BRCM_C.264 -vsync drop
+fate-h264-conformance-frext-hpcaflnl_bcrm_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCAFLNL_BRCM_C.264 -vsync drop
+fate-h264-conformance-frext-hpcalq_brcm_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCALQ_BRCM_B.264
+fate-h264-conformance-frext-hpcamapalq_bcrm_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCAMAPALQ_BRCM_B.264 -vsync 0
+fate-h264-conformance-frext-hpcamolq_brcm_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCAMOLQ_BRCM_B.264
+fate-h264-conformance-frext-hpcanl_brcm_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCANL_BRCM_C.264
+fate-h264-conformance-frext-hpcaq2lq_brcm_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCAQ2LQ_BRCM_B.264
+fate-h264-conformance-frext-hpcv_brcm_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCV_BRCM_A.264
+fate-h264-conformance-frext-hpcvfl_bcrm_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCVFL_BRCM_A.264 -vsync drop
+fate-h264-conformance-frext-hpcvflnl_bcrm_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCVFLNL_BRCM_A.264 -vsync drop
+fate-h264-conformance-frext-hpcvmolq_brcm_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCVMOLQ_BRCM_B.264
+fate-h264-conformance-frext-hpcvnl_brcm_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/HPCVNL_BRCM_A.264
+fate-h264-conformance-frext-pph10i1_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH10I1_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph10i2_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH10I2_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph10i3_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH10I3_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph10i4_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH10I4_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph10i5_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH10I5_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph10i6_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH10I6_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph10i7_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH10I7_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph422i1_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH422I1_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-pph422i2_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH422I2_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-pph422i3_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH422I3_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-pph422i4_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH422I4_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-pph422i5_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH422I5_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-pph422i6_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH422I6_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-pph422i7_panasonic_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/FRext/PPH422I7_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-hcbp2_hhi_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/HCBP2_HHI_A.264
+fate-h264-conformance-hcmp1_hhi_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/HCMP1_HHI_A.264
+fate-h264-conformance-ls_sva_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/LS_SVA_D.264
+fate-h264-conformance-midr_mw_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/MIDR_MW_D.264
+fate-h264-conformance-mps_mw_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/MPS_MW_A.264
+fate-h264-conformance-mr1_bt_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/MR1_BT_A.h264
+fate-h264-conformance-mr1_mw_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/MR1_MW_A.264
+fate-h264-conformance-mr2_mw_a: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/MR2_MW_A.264
+fate-h264-conformance-mr2_tandberg_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/MR2_TANDBERG_E.264
+fate-h264-conformance-mr3_tandberg_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/MR3_TANDBERG_B.264
+fate-h264-conformance-mr4_tandberg_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/MR4_TANDBERG_C.264
+fate-h264-conformance-mr5_tandberg_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/MR5_TANDBERG_C.264
+fate-h264-conformance-mr6_bt_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/MR6_BT_B.h264
+fate-h264-conformance-mr7_bt_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/MR7_BT_B.h264
+fate-h264-conformance-mr8_bt_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/MR8_BT_B.h264
+fate-h264-conformance-mr9_bt_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/MR9_BT_B.h264
+fate-h264-conformance-mv1_brcm_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/src19td.IBP.264
+fate-h264-conformance-nl1_sony_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/NL1_Sony_D.jsv
+fate-h264-conformance-nl2_sony_h: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/NL2_Sony_H.jsv
+fate-h264-conformance-nl3_sva_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/NL3_SVA_E.264
+fate-h264-conformance-nlmq1_jvc_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/NLMQ1_JVC_C.264
+fate-h264-conformance-nlmq2_jvc_c: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/NLMQ2_JVC_C.264
+fate-h264-conformance-nrf_mw_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/NRF_MW_E.264
+fate-h264-conformance-sharp_mp_field_1_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/Sharp_MP_Field_1_B.jvt
+fate-h264-conformance-sharp_mp_field_2_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/Sharp_MP_Field_2_B.jvt
+fate-h264-conformance-sharp_mp_field_3_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/Sharp_MP_Field_3_B.jvt
+fate-h264-conformance-sharp_mp_paff_1r2: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/Sharp_MP_PAFF_1r2.jvt
+fate-h264-conformance-sharp_mp_paff_2r: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/Sharp_MP_PAFF_2.jvt
+fate-h264-conformance-sl1_sva_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/SL1_SVA_B.264
+fate-h264-conformance-sva_ba1_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/SVA_BA1_B.264
+fate-h264-conformance-sva_ba2_d: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/SVA_BA2_D.264
+fate-h264-conformance-sva_base_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/SVA_Base_B.264
+fate-h264-conformance-sva_cl1_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/SVA_CL1_E.264
+fate-h264-conformance-sva_fm1_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/SVA_FM1_E.264
+fate-h264-conformance-sva_nl1_b: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/SVA_NL1_B.264
+fate-h264-conformance-sva_nl2_e: CMD = framecrc -vsync drop -i $(SAMPLES)/h264-conformance/SVA_NL2_E.264
fate-h264-bsf-mp4toannexb: CMD = md5 -i $(SAMPLES)/h264/interlaced_crop.mp4 -vcodec copy -bsf h264_mp4toannexb -f h264
fate-h264-crop-to-container: CMD = framemd5 -i $(SAMPLES)/h264/crop-to-container-dims-canon.mov
diff --git a/tests/fate/image.mak b/tests/fate/image.mak
index 1e4bc56..06af970 100644
--- a/tests/fate/image.mak
+++ b/tests/fate/image.mak
@@ -1,10 +1,27 @@
-FATE_SAMPLES_AVCONV-$(call DEMDEC, IMAGE2, DPX) += fate-dpx
+FATE_IMAGE-$(call DEMDEC, IMAGE2, DPX) += fate-dpx
fate-dpx: CMD = framecrc -i $(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 $(SAMPLES)/exr/rgba_slice_raw.exr -pix_fmt rgba64le
+
+FATE_EXR += fate-exr-slice-rle
+fate-exr-slice-rle: CMD = framecrc -i $(SAMPLES)/exr/rgba_slice_rle.exr -pix_fmt rgba64le
+
+FATE_EXR += fate-exr-slice-zip1
+fate-exr-slice-zip1: CMD = framecrc -i $(SAMPLES)/exr/rgba_slice_zip1.exr -pix_fmt rgba64le
+
+FATE_EXR += fate-exr-slice-zip16
+fate-exr-slice-zip16: CMD = framecrc -i $(SAMPLES)/exr/rgba_slice_zip16.exr -pix_fmt rgba64le
+
+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 $(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 $(SAMPLES)/ptx/_113kw_pic.ptx -pix_fmt rgb24
FATE_SUNRASTER += fate-sunraster-1bit-raw
@@ -30,7 +47,7 @@ fate-sunraster-24bit-rle: CMD = framecrc -i $(SAMPLES)/sunraster/lena-24bit-rle.
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 +66,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 $(SAMPLES)/targa-conformance/CBW8.TGA
@@ -73,5 +90,13 @@ fate-tiff-fax-g3s: CMD = framecrc -i $(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 $(SAMPLES)/xface/lena.xface
+
+FATE_IMAGE += $(FATE_IMAGE-yes)
+
+FATE_SAMPLES_FFMPEG += $(FATE_IMAGE)
+fate-image: $(FATE_IMAGE)
diff --git a/tests/fate/libavutil.mak b/tests/fate/libavutil.mak
index 3777625..d086a66 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,10 +54,18 @@ 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-sha
fate-sha: libavutil/sha-test$(EXESUF)
fate-sha: CMD = run libavutil/sha-test
diff --git a/tests/fate/lossless-audio.mak b/tests/fate/lossless-audio.mak
index 0794241..8dc0f06 100644
--- a/tests/fate/lossless-audio.mak
+++ b/tests/fate/lossless-audio.mak
@@ -1,20 +1,32 @@
-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 $(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 $(SAMPLES)/lossless-audio/luckynight-partial.mlp -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, APE, APE) += fate-lossless-monkeysaudio
+FATE_SAMPLES_LOSSLESS_AUDIO-$(call DEMDEC, APE, APE) += fate-lossless-monkeysaudio
fate-lossless-monkeysaudio: CMD = md5 -i $(SAMPLES)/lossless-audio/luckynight-partial.ape -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 $(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 $(SAMPLES)/lossless-audio/luckynight-partial.shn -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, TTA, TTA) += fate-lossless-tta
+FATE_SAMPLES_LOSSLESS_AUDIO-$(call DEMDEC, TAK, TAK) += fate-lossless-tak
+fate-lossless-tak: CMD = crc -i $(SAMPLES)/lossless-audio/luckynight-partial.tak
+
+FATE_SAMPLES_LOSSLESS_AUDIO-$(call DEMDEC, TTA, TTA) += fate-lossless-tta
fate-lossless-tta: CMD = crc -i $(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 $(SAMPLES)/lossless-audio/encrypted.tta
+
+FATE_SAMPLES_LOSSLESS_AUDIO-$(call DEMDEC, ASF, WMALOSSLESS) += fate-lossless-wma
fate-lossless-wma: CMD = md5 -i $(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 1c52111..f018d6a 100644
--- a/tests/fate/lossless-video.mak
+++ b/tests/fate/lossless-video.mak
@@ -4,7 +4,7 @@ fate-cllc-argb: CMD = framecrc -i $(SAMPLES)/cllc/sample-cllc-argb.avi
FATE_CLLC += fate-cllc-rgb
fate-cllc-rgb: CMD = framecrc -i $(SAMPLES)/cllc/sample-cllc-rgb.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
@@ -19,7 +19,10 @@ fate-lagarith-yuy2: CMD = framecrc -i $(SAMPLES)/lagarith/lag-yuy2.avi
FATE_LAGARITH += fate-lagarith-yv12
fate-lagarith-yv12: CMD = framecrc -i $(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 $(SAMPLES)/lagarith/lagarith-red.avi
+
+FATE_LOSSLESS_VIDEO-$(call DEMDEC, AVI, LAGARITH) += $(FATE_LAGARITH)
fate-lagarith: $(FATE_LAGARITH)
FATE_LOCO += fate-loco-rgb
@@ -28,20 +31,25 @@ fate-loco-rgb: CMD = framecrc -i $(SAMPLES)/loco/pig-loco-rgb.avi
FATE_LOCO += fate-loco-yuy2
fate-loco-yuy2: CMD = framecrc -i $(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 $(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 $(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 $(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 $(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 $(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 a3d6fc4..6347f20 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 $(SAMPLES)/msmpeg4v1/mpg4.avi -an
FATE_MSVIDEO1 += fate-msvideo1-8bit
@@ -7,7 +7,7 @@ fate-msvideo1-8bit: CMD = framecrc -i $(SAMPLES)/cram/skating.avi -t 1 -pix_fmt
FATE_MSVIDEO1 += fate-msvideo1-16bit
fate-msvideo1-16bit: CMD = framecrc -i $(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 $(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 $(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 $(SAMPLES)/vc1/SA20021.vc1
FATE_VC1-$(CONFIG_MOV_DEMUXER) += fate-vc1-ism
fate-vc1-ism: CMD = framecrc -i $(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 663f14e..1986061 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 c84de9e..4a3822f 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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 73bc5cb..1166de4 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 $(SAMPLES)/probe-format/$(@:fate-probe-format-%=%)
diff --git a/tests/fate/prores.mak b/tests/fate/prores.mak
index 9c1a1b1..00e2159 100644
--- a/tests/fate/prores.mak
+++ b/tests/fate/prores.mak
@@ -7,8 +7,8 @@ FATE_PRORES = fate-prores-422 \
FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, PRORES) += $(FATE_PRORES)
fate-prores: $(FATE_PRORES)
-fate-prores-422: CMD = framecrc -i $(SAMPLES)/prores/Sequence_1-Apple_ProRes_422.mov -pix_fmt yuv422p10le
-fate-prores-422_hq: CMD = framecrc -i $(SAMPLES)/prores/Sequence_1-Apple_ProRes_422_HQ.mov -pix_fmt yuv422p10le
-fate-prores-422_lt: CMD = framecrc -i $(SAMPLES)/prores/Sequence_1-Apple_ProRes_422_LT.mov -pix_fmt yuv422p10le
-fate-prores-422_proxy: CMD = framecrc -i $(SAMPLES)/prores/Sequence_1-Apple_ProRes_422_Proxy.mov -pix_fmt yuv422p10le
-fate-prores-alpha: CMD = framecrc -i $(SAMPLES)/prores/Sequence_1-Apple_ProRes_with_Alpha.mov -pix_fmt yuv444p10le
+fate-prores-422: CMD = framecrc -flags +bitexact -i $(SAMPLES)/prores/Sequence_1-Apple_ProRes_422.mov -pix_fmt yuv422p10le
+fate-prores-422_hq: CMD = framecrc -flags +bitexact -i $(SAMPLES)/prores/Sequence_1-Apple_ProRes_422_HQ.mov -pix_fmt yuv422p10le
+fate-prores-422_lt: CMD = framecrc -flags +bitexact -i $(SAMPLES)/prores/Sequence_1-Apple_ProRes_422_LT.mov -pix_fmt yuv422p10le
+fate-prores-422_proxy: CMD = framecrc -flags +bitexact -i $(SAMPLES)/prores/Sequence_1-Apple_ProRes_422_Proxy.mov -pix_fmt yuv422p10le
+fate-prores-alpha: CMD = framecrc -flags +bitexact -i $(SAMPLES)/prores/Sequence_1-Apple_ProRes_with_Alpha.mov -pix_fmt yuv444p10le
diff --git a/tests/fate/qt.mak b/tests/fate/qt.mak
index 79155f5..03b2fce 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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 2666be6..6c640ad 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 $(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 $(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 $(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 $(SAMPLES)/real/rv30.rm -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, RM, RV40) += fate-rv40
-fate-rv40: CMD = framecrc -i $(SAMPLES)/real/spygames-2MB.rmvb -t 10 -an -vsync 0
+FATE_REAL-$(call DEMDEC, RM, RV40) += fate-rv40
+fate-rv40: CMD = framecrc -i $(SAMPLES)/real/spygames-2MB.rmvb -t 10 -an
FATE_SIPR += fate-sipr-5k0
fate-sipr-5k0: CMD = pcm -i $(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 150829e..e1b854e 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 $(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 $(SAMPLES)/dxtory/dxtory_mic.avi
FATE_FRAPS += fate-fraps-v0
@@ -23,7 +23,7 @@ fate-fraps-v4: CMD = framecrc -i $(SAMPLES)/fraps/WoW_2006-11-03_14-58-17-19-nos
FATE_FRAPS += fate-fraps-v5
fate-fraps-v5: CMD = framecrc -i $(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 $(SAMPLES)/tscc/oneminute.avi -t 15 -pix_fmt
FATE_TSCC += fate-tscc-32bit
fate-tscc-32bit: CMD = framecrc -i $(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 $(SAMPLES)/VMnc/test.avi -pix_fmt rgb24
FATE_VMNC += fate-vmnc-32bit
fate-vmnc-32bit: CMD = framecrc -i $(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 $(SAMPLES)/zmbv/zmbv_16bit.avi -pix_fmt rgb24
FATE_ZMBV += fate-zmbv-32bit
fate-zmbv-32bit: CMD = framecrc -i $(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..ac1f4ca
--- /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 $(SAMPLES)/sub/AQTitle_capability_tester.aqt -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, JACOSUB, JACOSUB) += fate-sub-jacosub
+fate-sub-jacosub: CMD = md5 -i $(SAMPLES)/sub/JACOsub_capability_tester.jss -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, MICRODVD, MICRODVD) += fate-sub-microdvd
+fate-sub-microdvd: CMD = md5 -i $(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 $(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 $(SAMPLES)/sub/MovText_capability_tester.mp4 -f ass
+
+FATE_SUBTITLES-$(call ENCDEC, MOVTEXT, MOV) += fate-sub-movtextenc
+fate-sub-movtextenc: CMD = md5 -i $(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 $(SAMPLES)/sub/MPL2_capability_tester.txt -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, MPSUB, TEXT) += fate-sub-mpsub
+fate-sub-mpsub: CMD = md5 -i $(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 $(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 $(SAMPLES)/sub/PJS_capability_tester.pjs -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, REALTEXT, REALTEXT) += fate-sub-realtext
+fate-sub-realtext: CMD = md5 -i $(SAMPLES)/sub/RealText_capability_tester.rt -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, SAMI, SAMI) += fate-sub-sami
+fate-sub-sami: CMD = md5 -i $(SAMPLES)/sub/SAMI_capability_tester.smi -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, SRT, SUBRIP) += fate-sub-srt
+fate-sub-srt: CMD = md5 -i $(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 $(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 $(SAMPLES)/sub/SubViewer1_capability_tester.sub -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, SUBVIEWER, SUBVIEWER) += fate-sub-subviewer
+fate-sub-subviewer: CMD = md5 -i $(SAMPLES)/sub/SubViewer_capability_tester.sub -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, VPLAYER, VPLAYER) += fate-sub-vplayer
+fate-sub-vplayer: CMD = md5 -i $(SAMPLES)/sub/VPlayer_capability_tester.txt -f ass
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, WEBVTT, WEBVTT) += fate-sub-webvtt
+fate-sub-webvtt: CMD = md5 -i $(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 $(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 68a0a79..64d3896 100644
--- a/tests/fate/utvideo.mak
+++ b/tests/fate/utvideo.mak
@@ -28,7 +28,7 @@ fate-utvideo_yuv422_median: CMD = framecrc -i $(SAMPLES)/utvideo/utvideo_yuv422_
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..cc2ad28 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
@@ -62,6 +64,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 +89,17 @@ 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, J2K, AVI) += j2k
+fate-vsynth%-j2k: ENCOPTS = -qscale 7 -strict experimental -pix_fmt rgb24
+fate-vsynth%-j2k: DECINOPTS = -vcodec j2k -strict experimental
+
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 +197,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 +222,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 +233,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 +273,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 618776f..7e3c97b 100644
--- a/tests/fate/video.mak
+++ b/tests/fate/video.mak
@@ -4,34 +4,37 @@ fate-4xm-1: CMD = framecrc -i $(SAMPLES)/4xm/version1.4xm -pix_fmt rgb24 -an
FATE_4XM += fate-4xm-2
fate-4xm-2: CMD = framecrc -i $(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 $(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 $(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 $(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 $(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 $(SAMPLES)/ansi/ansi256.ans -pix_fmt rgb24
+
+FATE_VIDEO-$(call DEMDEC, RPL, ESCAPE124) += fate-armovie-escape124
fate-armovie-escape124: CMD = framecrc -i $(SAMPLES)/rpl/ESCAPE.RPL -pix_fmt rgb24
-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 $(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 $(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 $(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 $(SAMPLES)/bfi/2287.bfi -pix_fmt rgb24
FATE_BINK_VIDEO += fate-bink-video-b
@@ -43,25 +46,24 @@ fate-bink-video-f: CMD = framecrc -i $(SAMPLES)/bink/hol2br.bik
FATE_BINK_VIDEO += fate-bink-video-i
fate-bink-video-i: CMD = framecrc -i $(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 $(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 $(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 $(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 $(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 $(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 $(SAMPLES)/creatureshock-avs/OUTATIME.AVS -pix_fmt rgb24
FATE_CVID-$(CONFIG_MOV_DEMUXER) += fate-cvid-palette
@@ -73,31 +75,34 @@ fate-cvid-partial: CMD = framecrc -i $(SAMPLES)/cvid/laracroft-cinepak-partial.a
FATE_CVID-$(CONFIG_AVI_DEMUXER) += fate-cvid-grayscale
fate-cvid-grayscale: CMD = framecrc -i $(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 $(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 $(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 $(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 $(SAMPLES)/deluxepaint-anm/INTRO1.ANM -pix_fmt rgb24
+FATE_VIDEO-$(call DEMDEC, DIRAC, DIRAC) += fate-dirac
+fate-dirac: CMD = framecrc -i $(SAMPLES)/dirac/vts.profile-main.drc
+
FATE_TRUEMOTION1 += fate-truemotion1-15
fate-truemotion1-15: CMD = framecrc -i $(SAMPLES)/duck/phant2-940.duk -pix_fmt rgb24 -an
FATE_TRUEMOTION1 += fate-truemotion1-24
fate-truemotion1-24: CMD = framecrc -i $(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 $(SAMPLES)/duck/tm20.avi
FATE_DXA += fate-dxa-feeble
@@ -106,10 +111,10 @@ fate-dxa-feeble: CMD = framecrc -i $(SAMPLES)/dxa/meetsquid.dxa -t 2 -pix_fmt rg
FATE_DXA += fate-dxa-scummvm
fate-dxa-scummvm: CMD = framecrc -i $(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 $(SAMPLES)/film/logo-capcom.cpk -an
FATE_FLIC += fate-flic-af11-palette-change
@@ -121,16 +126,16 @@ fate-flic-af12: CMD = framecrc -i $(SAMPLES)/fli/jj00c2.fli -pix_fmt rgb24
FATE_FLIC += fate-flic-magiccarpet
fate-flic-magiccarpet: CMD = framecrc -i $(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 $(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 $(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 $(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
@@ -142,42 +147,48 @@ fate-iff-fibonacci: CMD = md5 -i $(SAMPLES)/iff/dasboot-in-compressed -f s16le
FATE_IFF-$(CONFIG_IFF_ILBM_DECODER) += fate-iff-ilbm
fate-iff-ilbm: CMD = framecrc -i $(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 $(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 $(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 $(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 $(SAMPLES)/jv/intro.jv -pix_fmt rgb24 -an
+
+FATE_VIDEO-$(call DEMDEC, AVI, KGV1) += fate-kgv1
fate-kgv1: CMD = framecrc -i $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(SAMPLES)/nuv/Today.nuv -an
@@ -185,43 +196,46 @@ fate-nuv-rtjpeg: CMD = framecrc -idct simple -i $(SAMPLES)/nuv/Today.nuv -an
FATE_NUV += fate-nuv-rtjpeg-fh
fate-nuv-rtjpeg-fh: CMD = framecrc -idct simple -i $(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 $(SAMPLES)/paf/hod1-partial.paf -pix_fmt rgb24 -an
+
+FATE_VIDEO-$(call DEMDEC, AVI, QPEG) += fate-qpeg
fate-qpeg: CMD = framecrc -i $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(SAMPLES)/sp5x/sp5x_problem.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, SRT, SRT) += fate-sub-srt
-fate-sub-srt: CMD = md5 -i $(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 $(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 $(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 $(SAMPLES)/tmv/pop-partial.tmv -pix_fmt rgb24
FATE_TXD += fate-txd-16bpp
@@ -230,42 +244,47 @@ fate-txd-16bpp: CMD = framecrc -i $(SAMPLES)/txd/misc.txd -pix_fmt bgra -an
FATE_TXD += fate-txd-pal8
fate-txd-pal8: CMD = framecrc -i $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(SAMPLES)/wc4-xan/wc4trailer-partial.avi -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 8fe445a..f27be18 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 $(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 $(SAMPLES)/g723_1/dtx63b.tco
FATE_G723_1 += fate-g723_1-dec-8
fate-g723_1-dec-8: CMD = framecrc -postfilter 1 -i $(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 $(SAMPLES)/gsm/ciao.wav
-FATE_GSM += fate-gsm-toast
+FATE_GSM-$(call DEMDEC, MOV, GSM) += fate-gsm-toast
fate-gsm-toast: CMD = framecrc -i $(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 $(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 $(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 6d6728e..bb20dda 100644
--- a/tests/fate/vpx.mak
+++ b/tests/fate/vpx.mak
@@ -22,6 +22,9 @@ fate-vp6a: CMD = framecrc -flags +bitexact -i $(SAMPLES)/flash-vp6/300x180-Scr-f
FATE_VP6-$(call DEMDEC, FLV, VP6F) += fate-vp6f
fate-vp6f: CMD = framecrc -flags +bitexact -i $(SAMPLES)/flash-vp6/clip1024.flv
+FATE_VP8-$(call DEMDEC, FLV, VP8) += fate-vp8-alpha
+fate-vp8-alpha: CMD = framecrc -i $(SAMPLES)/vp8_alpha/vp8_video_with_alpha.webm -vcodec copy
+
FATE_SAMPLES_AVCONV += $(FATE_VP6-yes)
fate-vp6: $(FATE_VP6-yes)
@@ -37,13 +40,13 @@ 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 $(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 $(SAMPLES)/vp8/frame_size_change.webm -frames:v 30
+fate-vp8-size-change$(1): CMD = framemd5 $(2) -flags +bitexact -i $(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
diff --git a/tests/fate/vqf.mak b/tests/fate/vqf.mak
index 6256941..67ee61f 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 $(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-$(CONFIG_VQF_DEMUXER) += fate-vqf-demux
fate-vqf-demux: CMD = md5 -i $(SAMPLES)/vqf/achterba.vqf -acodec copy -f framecrc
+
+FATE_VQF += $(FATE_VQF-yes)
+
+FATE_SAMPLES_FFMPEG += $(FATE_VQF)
+fate-vqf: $(FATE_VQF)
diff --git a/tests/ffserver-regression.sh b/tests/ffserver-regression.sh
new file mode 100755
index 0000000..11e4a54
--- /dev/null
+++ b/tests/ffserver-regression.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+#perl -e 'chomp($wd = `pwd`); print map { s!tests/data/!!; "<Stream $_>\nFile $wd/tests/data/$_\n</Stream>\n\n" } @ARGV' tests/data/a* >> tests/data/ffserver.conf
+#perl -e 'chomp($wd = `pwd`); print map { s!tests/data/!!; "<Stream $_.asf>\nFile $wd/tests/data/$_\n</Stream>\n\n" } @ARGV' tests/data/a* >> tests/data/ffserver.conf
+
+. $(dirname $0)/md5.sh
+
+FILES=$(sed -n 's/^[^#]*<Stream \(.*\)>.*/\1/p' $2 | grep -v html)
+
+rm -f tests/feed1.ffm
+./ffserver -d -f "$2" 2> /dev/null &
+FFSERVER_PID=$!
+echo "Waiting for feeds to startup..."
+sleep 2
+(
+ cd tests/data || exit $?
+ rm -f ff-* ffserver.regression
+ WGET_OPTIONS="--user-agent=NSPlayer -q --proxy=off -e verbose=off -e server_response=off"
+ for file in $FILES; do
+ if [ $(expr $file : "a-*") != 0 ]; then
+ wget $WGET_OPTIONS -O - http://localhost:9999/$file > ff-$file
+ else
+ wget $WGET_OPTIONS -O - http://localhost:9999/$file?date=19700101T000000Z | dd bs=1 count=20000 > ff-$file 2>/dev/null
+ fi
+ do_md5sum ff-$file >>ffserver.regression
+ done
+)
+kill $FFSERVER_PID
+wait > /dev/null 2>&1
+rm -f tests/feed1.ffm
+if diff -u "$1" tests/data/ffserver.regression; then
+ echo
+ echo Server regression test succeeded.
+ exit 0
+else
+ echo
+ echo Server regression test: Error.
+ exit 1
+fi
diff --git a/tests/ffserver.conf b/tests/ffserver.conf
new file mode 100644
index 0000000..1e6994a
--- /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
--- /dev/null
+++ b/tests/ffserver.regression.ref
@@ -0,0 +1,10 @@
+18c4ba0e8e7adb781216e38de61c2e39 ff-test_h.avi
+f84767c7af61f360f4b443c2c73f322f ff-test_l.avi
+d976848a9e4d5d8fc2659e4841cdece5 ff-test.swf
+28fd87d5075b9b011aad57292f271a04 ff-test_h.asf
+a31ccd3aba2551e60b9fb1c156fca2f8 ff-test_l.asf
+3279d3ed0ef2d1347b5eda84db2cf3e6 ff-test_h.rm
+440231fe3cf0849887390b4d67d6894a ff-test_l.rm
+e0dc91430660c619e97b5c82e0f398fc ff-test.jpg
+0d6c98fc8a4f00560fe34e94e26880a9 ff-test_small.jpg
+e2a315d7ac0576279f8b4d917999615a ff-test.mjpg
diff --git a/tests/filtergraphs/alphamerge_alphaextract_rgb b/tests/filtergraphs/alphamerge_alphaextract_rgb
new file mode 100644
index 0000000..1aa302d
--- /dev/null
+++ b/tests/filtergraphs/alphamerge_alphaextract_rgb
@@ -0,0 +1,4 @@
+sws_flags=+accurate_rnd+bitexact;
+format=bgra, split, alphamerge, split [x][y];
+[y] alphaextract [alpha];
+[x][alpha] alphamerge
diff --git a/tests/filtergraphs/alphamerge_alphaextract_yuv b/tests/filtergraphs/alphamerge_alphaextract_yuv
new file mode 100644
index 0000000..ef3ea14
--- /dev/null
+++ b/tests/filtergraphs/alphamerge_alphaextract_yuv
@@ -0,0 +1,4 @@
+sws_flags=+accurate_rnd+bitexact;
+format=yuv420p, split, alphamerge, split [x][y];
+[y] alphaextract [alpha];
+[x][alpha] alphamerge
diff --git a/tests/filtergraphs/concat b/tests/filtergraphs/concat
new file mode 100644
index 0000000..26bca14
--- /dev/null
+++ b/tests/filtergraphs/concat
@@ -0,0 +1,8 @@
+testsrc=r=5:n=1:d=2 [v1];
+sine=440:b=2:d=1 [a1];
+testsrc=r=5:n=1:d=1 [v2];
+sine=622:b=2:d=2 [a2];
+testsrc=r=5:n=1:d=1 [v3];
+sine=880:b=2:d=1 [a3];
+
+[v1][a1][v2][a2][v3][a3] concat=v=1:a=1:n=3
diff --git a/tests/filtergraphs/gradfun b/tests/filtergraphs/gradfun
new file mode 100644
index 0000000..d93dcaf
--- /dev/null
+++ b/tests/filtergraphs/gradfun
@@ -0,0 +1,2 @@
+sws_flags=+accurate_rnd+bitexact;
+format=gray, perms=random, gradfun=10:8:enable='not(between(n,5,10))'
diff --git a/tests/filtergraphs/hqdn3d b/tests/filtergraphs/hqdn3d
new file mode 100644
index 0000000..7591822
--- /dev/null
+++ b/tests/filtergraphs/hqdn3d
@@ -0,0 +1 @@
+perms=random, hqdn3d=enable='not(between(t,5,6))'
diff --git a/tests/filtergraphs/overlay b/tests/filtergraphs/overlay
index d646463..f648274 100644
--- a/tests/filtergraphs/overlay
+++ b/tests/filtergraphs/overlay
@@ -1,2 +1,3 @@
+sws_flags=+accurate_rnd+bitexact;
[1:v] scale=50:50 [over];
[0:v][over] overlay=20:20
diff --git a/tests/filtergraphs/overlay_rgb b/tests/filtergraphs/overlay_rgb
new file mode 100644
index 0000000..b060c01
--- /dev/null
+++ b/tests/filtergraphs/overlay_rgb
@@ -0,0 +1,4 @@
+sws_flags=+accurate_rnd+bitexact;
+split [main][over];
+[over] scale=88:72, pad=96:80:4:4 [overf];
+[main][overf] overlay=240:16:format=rgb
diff --git a/tests/filtergraphs/overlay_yuv420 b/tests/filtergraphs/overlay_yuv420
new file mode 100644
index 0000000..9ed1b2a
--- /dev/null
+++ b/tests/filtergraphs/overlay_yuv420
@@ -0,0 +1,4 @@
+sws_flags=+accurate_rnd+bitexact;
+split [main][over];
+[over] scale=88:72, pad=96:80:4:4 [overf];
+[main][overf] overlay=240:16:format=yuv420
diff --git a/tests/filtergraphs/overlay_yuv444 b/tests/filtergraphs/overlay_yuv444
new file mode 100644
index 0000000..bda0fd6
--- /dev/null
+++ b/tests/filtergraphs/overlay_yuv444
@@ -0,0 +1,4 @@
+sws_flags=+accurate_rnd+bitexact;
+split [main][over];
+[over] scale=88:72, pad=96:80:4:4 [overf];
+[main][overf] overlay=240:16:format=yuv444
diff --git a/tests/filtergraphs/scalenorm b/tests/filtergraphs/scalenorm
new file mode 100644
index 0000000..17b69de
--- /dev/null
+++ b/tests/filtergraphs/scalenorm
@@ -0,0 +1,4 @@
+sws_flags=+accurate_rnd+bitexact;
+testsrc=s=128x96 : d=1:r=5, format=yuv420p [a];
+testsrc=s=160x120 : d=1:r=5 [b];
+[a][b] concat=unsafe=1, scale=flags=+accurate_rnd+bitexact
diff --git a/tests/lavf-regression.sh b/tests/lavf-regression.sh
index d9c8a8f..4d5c7dc 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"
+do_image_formats pam "-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"
+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
--- /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 bb7a202..d923719 100644
--- a/tests/ref/acodec/alac
+++ b/tests/ref/acodec/alac
@@ -1,4 +1,4 @@
-8ad790d3a0bbda81cd23c15ab8ba760d *tests/data/fate/acodec-alac.mov
-389258 tests/data/fate/acodec-alac.mov
+f01f453dd13c4e88266409cddf2a7177 *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
--- /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 39c3838..6f7222a 100644
--- a/tests/ref/acodec/pcm-s16be
+++ b/tests/ref/acodec/pcm-s16be
@@ -1,4 +1,4 @@
-009a446579dd4cba793723b5e2b93c39 *tests/data/fate/acodec-pcm-s16be.mov
-1060097 tests/data/fate/acodec-pcm-s16be.mov
+d00ca427a66be2e33ca8d63bcde41316 *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
--- /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
--- /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 20bc4e0..3ebe02a 100644
--- a/tests/ref/acodec/pcm-s24be
+++ b/tests/ref/acodec/pcm-s24be
@@ -1,4 +1,4 @@
-de27dae0dff0359d8f39449b17d5607f *tests/data/fate/acodec-pcm-s24be.mov
-1589297 tests/data/fate/acodec-pcm-s24be.mov
+f65a7ae3b70ca53ffa354b1e7ff3a33d *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
--- /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 302bc1a..9075083 100644
--- a/tests/ref/acodec/pcm-s32be
+++ b/tests/ref/acodec/pcm-s32be
@@ -1,4 +1,4 @@
-2db1e7fe92d4006103691a4b59064dc6 *tests/data/fate/acodec-pcm-s32be.mov
-2118497 tests/data/fate/acodec-pcm-s32be.mov
+f9e16fafeefb2285e943f53133e9cfd5 *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
--- /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 f830d2f..247c46c 100644
--- a/tests/ref/acodec/pcm-s8
+++ b/tests/ref/acodec/pcm-s8
@@ -1,4 +1,4 @@
-9ee95a7fff38831a1cad3b49c33e6ed9 *tests/data/fate/acodec-pcm-s8.mov
-530897 tests/data/fate/acodec-pcm-s8.mov
+d931dc4fffa2d3398e0f31f97e7d6c3a *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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /dev/null
+++ b/tests/ref/fate/acodec-aref
@@ -0,0 +1,4 @@
+64151e4bcc2b717aa5a8454d424d6a1f *./tests/data/acodec.ref.wav
+1058446 ./tests/data/acodec.ref.wav
+ce524631c2ad0a40aaab46e3a80a1176 *./tests/data/acodec-16000-1.ref.wav
+192046 ./tests/data/acodec-16000-1.ref.wav
diff --git a/tests/ref/fate/adpcm-4xm b/tests/ref/fate/adpcm-4xm
new file mode 100644
index 0000000..eb5cfe6
--- /dev/null
+++ b/tests/ref/fate/adpcm-4xm
@@ -0,0 +1,27 @@
+#tb 0: 1/22050
+0, 0, 0, 1472, 5888, 0x9086e310
+0, 1476, 1476, 1472, 5888, 0xac8491f5
+0, 2952, 2952, 1472, 5888, 0xc9a08b6b
+0, 4428, 4428, 1472, 5888, 0x4cff893b
+0, 5904, 5904, 1464, 5856, 0xfb914624
+0, 7372, 7372, 1472, 5888, 0x1dd9781f
+0, 8848, 8848, 1472, 5888, 0x75937688
+0, 10324, 10324, 1472, 5888, 0x6c93a266
+0, 11800, 11800, 1464, 5856, 0xb14e6783
+0, 13268, 13268, 1472, 5888, 0x4d268759
+0, 14744, 14744, 1472, 5888, 0xce44b8c6
+0, 16220, 16220, 1472, 5888, 0xf99f7347
+0, 17696, 17696, 1464, 5856, 0x35591adc
+0, 19164, 19164, 1472, 5888, 0x67692338
+0, 20640, 20640, 1472, 5888, 0x6465addd
+0, 22116, 22116, 1472, 5888, 0x22c66aaf
+0, 23592, 23592, 1464, 5856, 0x016b78d9
+0, 25060, 25060, 1472, 5888, 0xa9a03855
+0, 26536, 26536, 1472, 5888, 0x1aa0603f
+0, 28012, 28012, 1472, 5888, 0x190a25a1
+0, 29488, 29488, 1464, 5856, 0xc6ad8bc0
+0, 30956, 30956, 1472, 5888, 0x42bb9d6b
+0, 32432, 32432, 1472, 5888, 0x797694d7
+0, 33908, 33908, 1472, 5888, 0xd2d1fa69
+0, 35384, 35384, 1464, 5856, 0x61624e9b
+0, 36852, 36852, 1472, 5888, 0x14bf8ec0
diff --git a/tests/ref/fate/adpcm-afc b/tests/ref/fate/adpcm-afc
new file mode 100644
index 0000000..d1a1c36
--- /dev/null
+++ b/tests/ref/fate/adpcm-afc
@@ -0,0 +1,13 @@
+#tb 0: 1/44100
+0, 0, 0, 17920, 71680, 0x52373bc9
+0, 17920, 17920, 17920, 71680, 0x1f854b27
+0, 35840, 35840, 17920, 71680, 0x3d265a6d
+0, 53760, 53760, 17920, 71680, 0x7e38d624
+0, 71680, 71680, 17920, 71680, 0x003b7616
+0, 89600, 89600, 17920, 71680, 0x9fed7ca7
+0, 107520, 107520, 17920, 71680, 0x22af668c
+0, 125440, 125440, 17920, 71680, 0xefd95c4a
+0, 143360, 143360, 17920, 71680, 0x8b68142e
+0, 161280, 161280, 17920, 71680, 0x0a0614fa
+0, 179200, 179200, 17920, 71680, 0x22ababa3
+0, 197120, 197120, 17920, 71680, 0xda4b1708
diff --git a/tests/ref/fate/adpcm-dtk b/tests/ref/fate/adpcm-dtk
new file mode 100644
index 0000000..3640e1c
--- /dev/null
+++ b/tests/ref/fate/adpcm-dtk
@@ -0,0 +1,33 @@
+#tb 0: 1/48000
+0, 0, 0, 896, 3584, 0xdae789d5
+0, 896, 896, 896, 3584, 0x168ed9b6
+0, 1792, 1792, 896, 3584, 0x8920c8d5
+0, 2688, 2688, 896, 3584, 0xaf0a3245
+0, 3584, 3584, 896, 3584, 0x884ee935
+0, 4480, 4480, 896, 3584, 0xe6a832ad
+0, 5376, 5376, 896, 3584, 0x1fa12ea2
+0, 6272, 6272, 896, 3584, 0xf119198c
+0, 7168, 7168, 896, 3584, 0x0a6dbf72
+0, 8064, 8064, 896, 3584, 0xd3467881
+0, 8960, 8960, 896, 3584, 0x25d504ec
+0, 9856, 9856, 896, 3584, 0x452730c9
+0, 10752, 10752, 896, 3584, 0x42b92ff1
+0, 11648, 11648, 896, 3584, 0x85c67bf3
+0, 12544, 12544, 896, 3584, 0xab4d99e9
+0, 13440, 13440, 896, 3584, 0xe5bfc4da
+0, 14336, 14336, 896, 3584, 0x7a5210e9
+0, 15232, 15232, 896, 3584, 0x5265fcd3
+0, 16128, 16128, 896, 3584, 0x76531427
+0, 17024, 17024, 896, 3584, 0xb2b8d7ab
+0, 17920, 17920, 896, 3584, 0x05a453e8
+0, 18816, 18816, 896, 3584, 0x742c45bb
+0, 19712, 19712, 896, 3584, 0x57aaee3b
+0, 20608, 20608, 896, 3584, 0x997bf703
+0, 21504, 21504, 896, 3584, 0xe2d14b13
+0, 22400, 22400, 896, 3584, 0xdafbdd2f
+0, 23296, 23296, 896, 3584, 0x448cec3a
+0, 24192, 24192, 896, 3584, 0xe6f6fb9c
+0, 25088, 25088, 896, 3584, 0x0310276a
+0, 25984, 25984, 896, 3584, 0x44bf04e9
+0, 26880, 26880, 896, 3584, 0xe2105d33
+0, 27776, 27776, 896, 3584, 0x08b7d5e0
diff --git a/tests/ref/fate/adpcm-ima-amv b/tests/ref/fate/adpcm-ima-amv
index 6c2fa32..ca7a168 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, 1378, 2756, 0x58754b3a
diff --git a/tests/ref/fate/adpcm-ima-oki b/tests/ref/fate/adpcm-ima-oki
new file mode 100644
index 0000000..c6f1ee1
--- /dev/null
+++ b/tests/ref/fate/adpcm-ima-oki
@@ -0,0 +1 @@
+641049800e735b62e975baacc9a011a4
diff --git a/tests/ref/fate/adpcm-ima-rad b/tests/ref/fate/adpcm-ima-rad
new file mode 100644
index 0000000..c5de1a6
--- /dev/null
+++ b/tests/ref/fate/adpcm-ima-rad
@@ -0,0 +1 @@
+495f0ae514c28c6bdcbd40811a17e2a5
diff --git a/tests/ref/fate/adpcm-ima-smjpeg b/tests/ref/fate/adpcm-ima-smjpeg
index 45cb97b..3a746b6 100644
--- a/tests/ref/fate/adpcm-ima-smjpeg
+++ b/tests/ref/fate/adpcm-ima-smjpeg
@@ -1,351 +1,351 @@
#tb 0: 1/22050
0, 0, 0, 512, 1024, 0x00000000
-0, 507, 507, 512, 1024, 0x00000000
-0, 1014, 1014, 512, 1024, 0xd89a448e
-0, 1521, 1521, 512, 1024, 0x695b369c
-0, 2029, 2029, 512, 1024, 0xc8ba5707
-0, 2558, 2558, 512, 1024, 0xdf241fc6
-0, 3065, 3065, 512, 1024, 0x61cf4166
-0, 3572, 3572, 512, 1024, 0x97cbc386
-0, 4079, 4079, 512, 1024, 0x44899d04
-0, 4586, 4586, 512, 1024, 0xa7cbaa62
-0, 5116, 5116, 512, 1024, 0xa7aea60c
-0, 5623, 5623, 512, 1024, 0xd7b18a89
-0, 6130, 6130, 512, 1024, 0x268e81f6
-0, 6637, 6637, 512, 1024, 0x9cf83a2f
-0, 7166, 7166, 512, 1024, 0x5559b508
-0, 7673, 7673, 512, 1024, 0xe1b9e71c
-0, 8181, 8181, 512, 1024, 0xdcee733e
-0, 8688, 8688, 512, 1024, 0xe5918f60
-0, 9195, 9195, 512, 1024, 0x29dbd209
-0, 9724, 9724, 512, 1024, 0x9bcbcf16
-0, 10231, 10231, 512, 1024, 0x86f5f458
-0, 10738, 10738, 512, 1024, 0xabcbda86
-0, 11246, 11246, 512, 1024, 0xc51f77b9
-0, 11775, 11775, 512, 1024, 0xf6b3a504
-0, 12282, 12282, 512, 1024, 0x1af3e40e
-0, 12789, 12789, 512, 1024, 0x3866b03b
-0, 13296, 13296, 512, 1024, 0xbc005403
-0, 13803, 13803, 512, 1024, 0xe9dfcc51
-0, 14333, 14333, 512, 1024, 0x83c837cb
-0, 14840, 14840, 512, 1024, 0xfa649580
-0, 15347, 15347, 512, 1024, 0x519452ea
-0, 15854, 15854, 512, 1024, 0xd4978774
-0, 16383, 16383, 512, 1024, 0xe2a3b1cd
-0, 16890, 16890, 512, 1024, 0x9a9472ad
-0, 17397, 17397, 512, 1024, 0xa12d4060
-0, 17905, 17905, 512, 1024, 0x31fb0646
-0, 18412, 18412, 512, 1024, 0xfc44343f
-0, 18941, 18941, 512, 1024, 0x0847751a
-0, 19448, 19448, 512, 1024, 0x227968a2
-0, 19955, 19955, 512, 1024, 0x7cce9f1c
-0, 20462, 20462, 512, 1024, 0xb8356713
-0, 20992, 20992, 512, 1024, 0xb29f6e6f
-0, 21499, 21499, 512, 1024, 0x9e1430ab
-0, 22006, 22006, 512, 1024, 0x26d85423
-0, 22513, 22513, 512, 1024, 0x6496547d
-0, 23020, 23020, 512, 1024, 0x316b1a86
-0, 23549, 23549, 512, 1024, 0x3cd83afc
-0, 24057, 24057, 512, 1024, 0x993ff633
-0, 24564, 24564, 512, 1024, 0x0708d1a2
-0, 25071, 25071, 512, 1024, 0xd7230db9
-0, 25578, 25578, 512, 1024, 0xbb0779ca
-0, 26107, 26107, 512, 1024, 0xc6094e1b
-0, 26614, 26614, 512, 1024, 0x15a8b039
-0, 27122, 27122, 512, 1024, 0xd6dbe88c
-0, 27629, 27629, 512, 1024, 0x7e8d1140
-0, 28158, 28158, 512, 1024, 0xef88e525
-0, 28665, 28665, 512, 1024, 0x44e21149
-0, 29172, 29172, 512, 1024, 0x65b0f5f4
-0, 29679, 29679, 512, 1024, 0xb955f687
-0, 30186, 30186, 512, 1024, 0xc85fba9c
-0, 30716, 30716, 512, 1024, 0xf59655ad
-0, 31223, 31223, 512, 1024, 0x6de80bf1
-0, 31730, 31730, 512, 1024, 0x2dcf6e41
-0, 32237, 32237, 512, 1024, 0xd0ddcf8a
-0, 32766, 32766, 512, 1024, 0x00135c2d
-0, 33273, 33273, 512, 1024, 0x697f8efd
-0, 33781, 33781, 512, 1024, 0x7a9bada5
-0, 34288, 34288, 512, 1024, 0x0d22783c
-0, 34795, 34795, 512, 1024, 0x7726d07d
-0, 35324, 35324, 512, 1024, 0xa2f14f67
-0, 35831, 35831, 512, 1024, 0x7f51060d
-0, 36338, 36338, 512, 1024, 0xc4ec6aea
-0, 36846, 36846, 512, 1024, 0x9bb37ca4
-0, 37375, 37375, 512, 1024, 0x9b085577
-0, 37882, 37882, 512, 1024, 0x8812f8af
-0, 38389, 38389, 512, 1024, 0x788f5221
-0, 38896, 38896, 512, 1024, 0x3a2ce642
-0, 39403, 39403, 512, 1024, 0x72415692
-0, 39933, 39933, 512, 1024, 0xe3dcc105
-0, 40440, 40440, 512, 1024, 0xb26c0599
-0, 40947, 40947, 512, 1024, 0x5c9e55eb
-0, 41454, 41454, 512, 1024, 0x8fe88707
-0, 41983, 41983, 512, 1024, 0xc5d7beb6
-0, 42490, 42490, 512, 1024, 0xe1d3a3b4
-0, 42998, 42998, 512, 1024, 0x012da0c6
-0, 43505, 43505, 512, 1024, 0x8d010922
-0, 44012, 44012, 512, 1024, 0x3366eb0d
-0, 44541, 44541, 512, 1024, 0xc9381a27
-0, 45048, 45048, 512, 1024, 0x0774f685
-0, 45555, 45555, 512, 1024, 0xc5cae0a5
-0, 46062, 46062, 512, 1024, 0xa6f4737c
-0, 46592, 46592, 512, 1024, 0x8fb6d0d1
-0, 47099, 47099, 512, 1024, 0x05f579c2
-0, 47606, 47606, 512, 1024, 0x56905d99
-0, 48113, 48113, 512, 1024, 0x002ee18d
-0, 48620, 48620, 512, 1024, 0xeb37ef51
-0, 49149, 49149, 512, 1024, 0x38025635
-0, 49657, 49657, 512, 1024, 0x4fe643c8
-0, 50164, 50164, 512, 1024, 0x11d66ab1
-0, 50671, 50671, 512, 1024, 0xcc3051e9
-0, 51178, 51178, 512, 1024, 0xcd93e854
-0, 51707, 51707, 512, 1024, 0x38f1196d
-0, 52214, 52214, 512, 1024, 0x657a15fc
-0, 52722, 52722, 512, 1024, 0x669ce2a9
-0, 53229, 53229, 512, 1024, 0x95862dda
-0, 53758, 53758, 512, 1024, 0x1726a7b2
-0, 54265, 54265, 512, 1024, 0xd6ece2a1
-0, 54772, 54772, 512, 1024, 0x33ab9553
-0, 55279, 55279, 512, 1024, 0xd50c73a6
-0, 55787, 55787, 512, 1024, 0xfe25b63a
-0, 56316, 56316, 512, 1024, 0x7e2959e3
-0, 56823, 56823, 512, 1024, 0xa4c07b34
-0, 57330, 57330, 512, 1024, 0xd6d8f15c
-0, 57837, 57837, 512, 1024, 0x1eccddd7
-0, 58366, 58366, 512, 1024, 0x2b69f9cb
-0, 58874, 58874, 512, 1024, 0x667b775f
-0, 59381, 59381, 512, 1024, 0xad3b84e9
-0, 59888, 59888, 512, 1024, 0x4f29fc67
-0, 60395, 60395, 512, 1024, 0x8d611ab7
-0, 60924, 60924, 512, 1024, 0x278966ea
-0, 61431, 61431, 512, 1024, 0xaf33812b
-0, 61938, 61938, 512, 1024, 0xa55f4265
-0, 62446, 62446, 512, 1024, 0x023cb51c
-0, 62975, 62975, 512, 1024, 0x1d1f1005
-0, 63482, 63482, 512, 1024, 0x874cccf7
-0, 63989, 63989, 512, 1024, 0xda705428
-0, 64496, 64496, 512, 1024, 0x48d9b440
-0, 65003, 65003, 512, 1024, 0xa14e0712
-0, 65533, 65533, 512, 1024, 0x7efbad1f
-0, 66040, 66040, 512, 1024, 0xdb82c17f
-0, 66547, 66547, 512, 1024, 0xcbe87613
-0, 67054, 67054, 512, 1024, 0x3a63df1d
-0, 67583, 67583, 512, 1024, 0xd5636bba
-0, 68090, 68090, 512, 1024, 0x9397af23
-0, 68598, 68598, 512, 1024, 0x32a07c98
-0, 69105, 69105, 512, 1024, 0x202ca667
-0, 69612, 69612, 512, 1024, 0xdf969011
-0, 70141, 70141, 512, 1024, 0xc434d238
-0, 70648, 70648, 512, 1024, 0xe9ad7562
-0, 71155, 71155, 512, 1024, 0xb51b6b50
-0, 71663, 71663, 512, 1024, 0xe70aecd3
-0, 72192, 72192, 512, 1024, 0x03c816b2
-0, 72699, 72699, 512, 1024, 0x869fdf25
-0, 73206, 73206, 512, 1024, 0xd40a0a62
-0, 73713, 73713, 512, 1024, 0x5af7dd35
-0, 74220, 74220, 512, 1024, 0x891ffc72
-0, 74750, 74750, 512, 1024, 0x1ff68a08
-0, 75257, 75257, 512, 1024, 0x5a7517a9
-0, 75764, 75764, 512, 1024, 0x0f959f74
-0, 76271, 76271, 512, 1024, 0xe92a12a2
-0, 76778, 76778, 512, 1024, 0x38000e55
-0, 77307, 77307, 512, 1024, 0x39fbdd70
-0, 77814, 77814, 512, 1024, 0xca3d9184
-0, 78322, 78322, 512, 1024, 0x66c8995b
-0, 78829, 78829, 512, 1024, 0xac25acea
-0, 79358, 79358, 512, 1024, 0x3cd1046c
-0, 79865, 79865, 512, 1024, 0x6a1df31c
-0, 80372, 80372, 512, 1024, 0x21ca10a1
-0, 80879, 80879, 512, 1024, 0x1aeccedc
-0, 81387, 81387, 512, 1024, 0xddea1335
-0, 81916, 81916, 512, 1024, 0x19f5ca9f
-0, 82423, 82423, 512, 1024, 0x88e95e43
-0, 82930, 82930, 512, 1024, 0x726284fe
-0, 83437, 83437, 512, 1024, 0x6b85b40e
-0, 83966, 83966, 512, 1024, 0x111fee2a
-0, 84474, 84474, 512, 1024, 0x3656b588
-0, 84981, 84981, 512, 1024, 0xa5a2b552
-0, 85488, 85488, 512, 1024, 0x38fb2467
-0, 85995, 85995, 512, 1024, 0xaa919ccc
-0, 86524, 86524, 512, 1024, 0x15993dbc
-0, 87031, 87031, 512, 1024, 0xbe01a7b9
-0, 87539, 87539, 512, 1024, 0xefe93c09
-0, 88046, 88046, 512, 1024, 0x1bb566e5
-0, 88575, 88575, 512, 1024, 0x15ce6237
-0, 89082, 89082, 512, 1024, 0xa8552e66
-0, 89589, 89589, 512, 1024, 0x9d80187e
-0, 90096, 90096, 512, 1024, 0x5df3fc30
-0, 90603, 90603, 512, 1024, 0x1a312aa5
-0, 91133, 91133, 512, 1024, 0x6bb8e302
-0, 91640, 91640, 512, 1024, 0xbd9684bb
-0, 92147, 92147, 512, 1024, 0x78b0b166
-0, 92654, 92654, 512, 1024, 0xd9af5eae
-0, 93183, 93183, 512, 1024, 0xdb90fe82
-0, 93690, 93690, 512, 1024, 0x327614e9
-0, 94198, 94198, 512, 1024, 0x1f19b7fe
-0, 94705, 94705, 512, 1024, 0x46c53f96
-0, 95212, 95212, 512, 1024, 0x921b2189
-0, 95741, 95741, 512, 1024, 0xa8fbc85a
-0, 96248, 96248, 512, 1024, 0xabfdaaae
-0, 96755, 96755, 512, 1024, 0x6acc7387
-0, 97263, 97263, 512, 1024, 0x0d9c27b5
-0, 97792, 97792, 512, 1024, 0xba4dd809
-0, 98299, 98299, 512, 1024, 0x2a2ad521
-0, 98806, 98806, 512, 1024, 0x892de38a
-0, 99313, 99313, 512, 1024, 0xdc97a2eb
-0, 99820, 99820, 512, 1024, 0x4f614ca4
-0, 100350, 100350, 512, 1024, 0x9c8a77ea
-0, 100857, 100857, 512, 1024, 0x2d30e646
-0, 101364, 101364, 512, 1024, 0x74e800a7
-0, 101871, 101871, 512, 1024, 0x1e01fb02
-0, 102378, 102378, 512, 1024, 0x4ed2c1d8
-0, 102907, 102907, 512, 1024, 0xf2fdbe63
-0, 103415, 103415, 512, 1024, 0x8d6f63a1
-0, 103922, 103922, 512, 1024, 0xded468d9
-0, 104429, 104429, 512, 1024, 0xccad839e
-0, 104958, 104958, 512, 1024, 0xdde7c082
-0, 105465, 105465, 512, 1024, 0x548613c5
-0, 105972, 105972, 512, 1024, 0x383909bd
-0, 106479, 106479, 512, 1024, 0xfd37627b
-0, 106987, 106987, 512, 1024, 0x6d95a481
-0, 107516, 107516, 512, 1024, 0x56aa87fa
-0, 108023, 108023, 512, 1024, 0x7b67258c
-0, 108530, 108530, 512, 1024, 0x7dd99a92
-0, 109037, 109037, 512, 1024, 0x4a66d102
-0, 109566, 109566, 512, 1024, 0x7b3fce51
-0, 110074, 110074, 512, 1024, 0xbbd968aa
-0, 110581, 110581, 512, 1024, 0x8283ec36
-0, 111088, 111088, 512, 1024, 0x3c96493d
-0, 111595, 111595, 512, 1024, 0xfa4f8cf8
-0, 112124, 112124, 512, 1024, 0xe2cf872d
-0, 112631, 112631, 512, 1024, 0x0a9e7aa6
-0, 113139, 113139, 512, 1024, 0x6e7a0550
-0, 113646, 113646, 512, 1024, 0x3acfea2f
-0, 114175, 114175, 512, 1024, 0x7111d0fa
-0, 114682, 114682, 512, 1024, 0xe9a1eca9
-0, 115189, 115189, 512, 1024, 0x24da6c46
-0, 115696, 115696, 512, 1024, 0x117cff37
-0, 116204, 116204, 512, 1024, 0x0f27cab6
-0, 116733, 116733, 512, 1024, 0x69b6b4e6
-0, 117240, 117240, 512, 1024, 0x1e6cc841
-0, 117747, 117747, 512, 1024, 0xb01e2365
-0, 118254, 118254, 512, 1024, 0x14e200d3
-0, 118783, 118783, 512, 1024, 0xd1184c98
-0, 119291, 119291, 512, 1024, 0xef9140e9
-0, 119798, 119798, 512, 1024, 0x4cbb645e
-0, 120305, 120305, 512, 1024, 0xe7fe2f06
-0, 120812, 120812, 512, 1024, 0xf8c45028
-0, 121341, 121341, 512, 1024, 0x561358f4
-0, 121848, 121848, 512, 1024, 0xd0129b77
-0, 122355, 122355, 512, 1024, 0xcc636e88
-0, 122863, 122863, 512, 1024, 0xe9406321
-0, 123392, 123392, 512, 1024, 0x9f16a041
-0, 123899, 123899, 512, 1024, 0x468bf409
-0, 124406, 124406, 512, 1024, 0x3df70f7b
-0, 124913, 124913, 512, 1024, 0xa880b11b
-0, 125420, 125420, 512, 1024, 0x3286c489
-0, 125950, 125950, 512, 1024, 0x39fe9ebc
-0, 126457, 126457, 512, 1024, 0xc533d83b
-0, 126964, 126964, 512, 1024, 0x153b195d
-0, 127471, 127471, 512, 1024, 0xd84786a1
-0, 127978, 127978, 512, 1024, 0xdc295aaa
-0, 128507, 128507, 512, 1024, 0xfb764d8c
-0, 129015, 129015, 512, 1024, 0xeebc9db9
-0, 129522, 129522, 512, 1024, 0x7ba9403e
-0, 130029, 130029, 512, 1024, 0x4e5571ec
-0, 130558, 130558, 512, 1024, 0xd965fad4
-0, 131065, 131065, 512, 1024, 0x87e259f2
-0, 131572, 131572, 512, 1024, 0xae7e533b
-0, 132080, 132080, 512, 1024, 0x313cf4d6
-0, 132587, 132587, 512, 1024, 0xe1844c90
-0, 133116, 133116, 512, 1024, 0xbb057b44
-0, 133623, 133623, 512, 1024, 0xa5099687
-0, 134130, 134130, 512, 1024, 0xbff10707
-0, 134637, 134637, 512, 1024, 0x37c4ffc0
-0, 135167, 135167, 512, 1024, 0xf9fb6caa
-0, 135674, 135674, 512, 1024, 0x3b6a3a1f
-0, 136181, 136181, 512, 1024, 0x83431edb
-0, 136688, 136688, 512, 1024, 0x1eb713cf
-0, 137195, 137195, 512, 1024, 0xd7b07a6d
-0, 137724, 137724, 512, 1024, 0x81ae3391
-0, 138231, 138231, 512, 1024, 0xf150130a
-0, 138739, 138739, 512, 1024, 0x09678eaa
-0, 139246, 139246, 512, 1024, 0xb94e06f1
-0, 139775, 139775, 512, 1024, 0x67b1dbc9
-0, 140282, 140282, 512, 1024, 0xd6edc235
-0, 140789, 140789, 512, 1024, 0x34e4c499
-0, 141296, 141296, 512, 1024, 0xeefd89c0
-0, 141804, 141804, 512, 1024, 0x38afdaf1
-0, 142333, 142333, 512, 1024, 0x29a60d76
-0, 142840, 142840, 512, 1024, 0xe28a4372
-0, 143347, 143347, 512, 1024, 0x7089454d
-0, 143854, 143854, 512, 1024, 0x0c01bb7b
-0, 144383, 144383, 512, 1024, 0xbd776a72
-0, 144891, 144891, 512, 1024, 0x86776fd0
-0, 145398, 145398, 512, 1024, 0xb37c88f7
-0, 145905, 145905, 512, 1024, 0x5f90aaf8
-0, 146412, 146412, 512, 1024, 0x203d4222
-0, 146941, 146941, 512, 1024, 0x382692a6
-0, 147448, 147448, 512, 1024, 0xf37c95fd
-0, 147956, 147956, 512, 1024, 0x6c0b8877
-0, 148463, 148463, 512, 1024, 0x2e54a8b6
-0, 148992, 148992, 512, 1024, 0x7f266488
-0, 149499, 149499, 512, 1024, 0xfbf20f9a
-0, 150006, 150006, 512, 1024, 0xf2985cc0
-0, 150513, 150513, 512, 1024, 0xc7075340
-0, 151020, 151020, 512, 1024, 0xe4585695
-0, 151550, 151550, 512, 1024, 0xbdffa380
-0, 152057, 152057, 512, 1024, 0x2422a8a9
-0, 152564, 152564, 512, 1024, 0x59cbd75f
-0, 153071, 153071, 512, 1024, 0x04ad1a8c
-0, 153578, 153578, 512, 1024, 0x33c09191
-0, 154107, 154107, 512, 1024, 0x55efa6fd
-0, 154615, 154615, 512, 1024, 0xf73d0e5d
-0, 155122, 155122, 512, 1024, 0x6141ebae
-0, 155629, 155629, 512, 1024, 0x7db17a68
-0, 156158, 156158, 512, 1024, 0xa6c690b6
-0, 156665, 156665, 512, 1024, 0xa6fd6725
-0, 157172, 157172, 512, 1024, 0x50a90b9b
-0, 157680, 157680, 512, 1024, 0xef990dc8
-0, 158187, 158187, 512, 1024, 0x75adf6b5
-0, 158716, 158716, 512, 1024, 0x61eac43e
-0, 159223, 159223, 512, 1024, 0x67797a19
-0, 159730, 159730, 512, 1024, 0xf325277a
-0, 160237, 160237, 512, 1024, 0x18bf254a
-0, 160767, 160767, 512, 1024, 0x2ce6bee3
-0, 161274, 161274, 512, 1024, 0x8d320860
-0, 161781, 161781, 512, 1024, 0xc979b6e8
-0, 162288, 162288, 512, 1024, 0xdb644b41
-0, 162795, 162795, 512, 1024, 0xe1b368ba
-0, 163324, 163324, 512, 1024, 0xacc53d15
-0, 163832, 163832, 512, 1024, 0x42ea8c18
-0, 164339, 164339, 512, 1024, 0xe52c99a4
-0, 164846, 164846, 512, 1024, 0xd7db54a6
-0, 165375, 165375, 512, 1024, 0x7f27a7e3
-0, 165882, 165882, 512, 1024, 0xf7ffeaa9
-0, 166389, 166389, 512, 1024, 0x792b6088
-0, 166896, 166896, 512, 1024, 0x61d99724
-0, 167404, 167404, 512, 1024, 0x5213720e
-0, 167933, 167933, 512, 1024, 0xac09dd30
-0, 168440, 168440, 512, 1024, 0x960bf6bb
-0, 168947, 168947, 512, 1024, 0xc90168e1
-0, 169454, 169454, 512, 1024, 0x43b45768
-0, 169983, 169983, 512, 1024, 0x935d60a1
-0, 170491, 170491, 512, 1024, 0x9a342ef2
-0, 170998, 170998, 512, 1024, 0xc894709f
-0, 171505, 171505, 512, 1024, 0x59b43b07
-0, 172012, 172012, 512, 1024, 0x36a1a98d
-0, 172541, 172541, 512, 1024, 0x9e1a121c
-0, 173048, 173048, 512, 1024, 0x02208b78
-0, 173556, 173556, 512, 1024, 0xd1d7b274
-0, 174063, 174063, 512, 1024, 0xdacd5096
-0, 174592, 174592, 512, 1024, 0x51b71ead
-0, 175099, 175099, 512, 1024, 0xd009a7ca
-0, 175606, 175606, 512, 1024, 0xb6d5a938
-0, 176113, 176113, 512, 1024, 0xf3d45e47
-0, 176621, 176621, 512, 1024, 0xea8e04fc
-0, 177150, 177150, 512, 1024, 0x0b928bd8
-0, 177657, 177657, 512, 1024, 0x0f02caec
-0, 178164, 178164, 512, 1024, 0xe2b137a8
-0, 178671, 178671, 512, 1024, 0xd5f94892
+0, 512, 512, 512, 1024, 0x00000000
+0, 1024, 1024, 512, 1024, 0xed2d3f6b
+0, 1533, 1533, 512, 1024, 0x51f6ccb3
+0, 2040, 2040, 512, 1024, 0x58bd75aa
+0, 2552, 2552, 512, 1024, 0xd857a310
+0, 3064, 3064, 512, 1024, 0xc483a5b8
+0, 3576, 3576, 512, 1024, 0x923ecf67
+0, 4088, 4088, 512, 1024, 0xf87dcd53
+0, 4598, 4598, 512, 1024, 0xdc32c002
+0, 5110, 5110, 512, 1024, 0xb760def1
+0, 5622, 5622, 512, 1024, 0x6838d2b2
+0, 6134, 6134, 512, 1024, 0xe45aca1e
+0, 6646, 6646, 512, 1024, 0xde1fb955
+0, 7158, 7158, 512, 1024, 0x9e23b949
+0, 7670, 7670, 512, 1024, 0x840cc000
+0, 8182, 8182, 512, 1024, 0x0a29cbfa
+0, 8694, 8694, 512, 1024, 0x9871d4c4
+0, 9206, 9206, 512, 1024, 0xb35dc9f2
+0, 9718, 9718, 512, 1024, 0xf37fda0a
+0, 10230, 10230, 512, 1024, 0xa640f990
+0, 10742, 10742, 512, 1024, 0x516fe6f5
+0, 11254, 11254, 512, 1024, 0xc78bc6a6
+0, 11766, 11766, 512, 1024, 0x700fd6ee
+0, 12278, 12278, 512, 1024, 0x5383d5ad
+0, 12790, 12790, 512, 1024, 0xbe01d091
+0, 13302, 13302, 512, 1024, 0x72dfcfc7
+0, 13814, 13814, 512, 1024, 0xd8fecea9
+0, 14326, 14326, 512, 1024, 0xa464d79b
+0, 14838, 14838, 512, 1024, 0xf394e2cb
+0, 15350, 15350, 512, 1024, 0xa301ec49
+0, 15862, 15862, 512, 1024, 0x5e09d60f
+0, 16374, 16374, 512, 1024, 0xd13edd6f
+0, 16886, 16886, 512, 1024, 0x7423ef39
+0, 17398, 17398, 512, 1024, 0x96e2f083
+0, 17910, 17910, 512, 1024, 0x5ed7dbee
+0, 18422, 18422, 512, 1024, 0x3874f714
+0, 18934, 18934, 512, 1024, 0xa5e6edab
+0, 19446, 19446, 512, 1024, 0x0a04ee3a
+0, 19958, 19958, 512, 1024, 0xadfee6b9
+0, 20470, 20470, 512, 1024, 0xd0bbe6d2
+0, 20982, 20982, 512, 1024, 0x223eebb7
+0, 21494, 21494, 512, 1024, 0x0473e479
+0, 22006, 22006, 512, 1024, 0xdf15e51e
+0, 22518, 22518, 512, 1024, 0xa954e483
+0, 23030, 23030, 512, 1024, 0x6df3ed03
+0, 23542, 23542, 512, 1024, 0x0860e544
+0, 24054, 24054, 512, 1024, 0xc241e8dc
+0, 24566, 24566, 512, 1024, 0xd0e1d6a4
+0, 25078, 25078, 512, 1024, 0xcb2ff988
+0, 25590, 25590, 512, 1024, 0x51fae08e
+0, 26102, 26102, 512, 1024, 0xae39f2fc
+0, 26614, 26614, 512, 1024, 0xfd74f07c
+0, 27126, 27126, 512, 1024, 0x1936edc1
+0, 27638, 27638, 512, 1024, 0x95f8deae
+0, 28150, 28150, 512, 1024, 0x93bdf605
+0, 28662, 28662, 512, 1024, 0x7a07dd32
+0, 29174, 29174, 512, 1024, 0x6889fdc1
+0, 29686, 29686, 512, 1024, 0x989bf024
+0, 30198, 30198, 512, 1024, 0xc764ce80
+0, 30710, 30710, 512, 1024, 0x0e62d721
+0, 31222, 31222, 512, 1024, 0x59c2fbe3
+0, 31734, 31734, 512, 1024, 0xf14ee29d
+0, 32246, 32246, 512, 1024, 0x02a0f21b
+0, 32758, 32758, 512, 1024, 0xadb3d361
+0, 33270, 33270, 512, 1024, 0xdcb3d1fc
+0, 33782, 33782, 512, 1024, 0x2924f9dc
+0, 34294, 34294, 512, 1024, 0x7507ebec
+0, 34806, 34806, 512, 1024, 0xe009f343
+0, 35318, 35318, 512, 1024, 0x21e9e7ac
+0, 35830, 35830, 512, 1024, 0x845bda9e
+0, 36342, 36342, 512, 1024, 0xb1b3e632
+0, 36854, 36854, 512, 1024, 0x61ccf593
+0, 37366, 37366, 512, 1024, 0x8cdbf603
+0, 37878, 37878, 512, 1024, 0xf8f7e673
+0, 38390, 38390, 512, 1024, 0x55efdd24
+0, 38902, 38902, 512, 1024, 0x4059e8ff
+0, 39414, 39414, 512, 1024, 0xb3afe5be
+0, 39926, 39926, 512, 1024, 0x7236e965
+0, 40438, 40438, 512, 1024, 0xe683db69
+0, 40950, 40950, 512, 1024, 0x29e3d93c
+0, 41462, 41462, 512, 1024, 0x74f2f27f
+0, 41974, 41974, 512, 1024, 0x32cde3ba
+0, 42486, 42486, 512, 1024, 0xe907f171
+0, 42998, 42998, 512, 1024, 0x206ae2a5
+0, 43510, 43510, 512, 1024, 0x6379efa1
+0, 44022, 44022, 512, 1024, 0x0f0fee85
+0, 44534, 44534, 512, 1024, 0x3195e314
+0, 45046, 45046, 512, 1024, 0x4646ead3
+0, 45558, 45558, 512, 1024, 0x5635dcf5
+0, 46070, 46070, 512, 1024, 0xd76fc780
+0, 46582, 46582, 512, 1024, 0x847ff8a5
+0, 47094, 47094, 512, 1024, 0xaca8eda3
+0, 47606, 47606, 512, 1024, 0x9a2de1ea
+0, 48118, 48118, 512, 1024, 0xc92ff23a
+0, 48630, 48630, 512, 1024, 0x0e0ef038
+0, 49142, 49142, 512, 1024, 0xc32cf495
+0, 49654, 49654, 512, 1024, 0x6ab1ec79
+0, 50166, 50166, 512, 1024, 0xe43cd8d6
+0, 50678, 50678, 512, 1024, 0x4ba2deab
+0, 51190, 51190, 512, 1024, 0x6d16ea0e
+0, 51702, 51702, 512, 1024, 0xe5b0ee70
+0, 52214, 52214, 512, 1024, 0xcf6cf074
+0, 52726, 52726, 512, 1024, 0x2206e61d
+0, 53238, 53238, 512, 1024, 0xfbb9e7e7
+0, 53750, 53750, 512, 1024, 0x2bc1e115
+0, 54262, 54262, 512, 1024, 0x4ca6e5c5
+0, 54774, 54774, 512, 1024, 0x061cead0
+0, 55286, 55286, 512, 1024, 0x3dc9f950
+0, 55798, 55798, 512, 1024, 0x9399f10d
+0, 56310, 56310, 512, 1024, 0xa2bff5ae
+0, 56822, 56822, 512, 1024, 0xd21de569
+0, 57334, 57334, 512, 1024, 0x1c45e3be
+0, 57846, 57846, 512, 1024, 0xff5dff1c
+0, 58358, 58358, 512, 1024, 0x992df5d3
+0, 58870, 58870, 512, 1024, 0xafedea2f
+0, 59382, 59382, 512, 1024, 0x6e73d6a8
+0, 59894, 59894, 512, 1024, 0x72dff283
+0, 60406, 60406, 512, 1024, 0x50b5f1a6
+0, 60918, 60918, 512, 1024, 0xffe1decb
+0, 61430, 61430, 512, 1024, 0x8993ecff
+0, 61942, 61942, 512, 1024, 0x954bd63a
+0, 62454, 62454, 512, 1024, 0x4707f577
+0, 62966, 62966, 512, 1024, 0x7a88f81f
+0, 63478, 63478, 512, 1024, 0xc771f537
+0, 63990, 63990, 512, 1024, 0x7aade6af
+0, 64502, 64502, 512, 1024, 0x8af5ede5
+0, 65014, 65014, 512, 1024, 0x7500f3f1
+0, 65526, 65526, 512, 1024, 0xea36f707
+0, 66038, 66038, 512, 1024, 0x1a26e39a
+0, 66550, 66550, 512, 1024, 0xa04cf00d
+0, 67062, 67062, 512, 1024, 0xc362f182
+0, 67574, 67574, 512, 1024, 0x79c8f82c
+0, 68086, 68086, 512, 1024, 0x6480eee1
+0, 68598, 68598, 512, 1024, 0x7152eaa0
+0, 69110, 69110, 512, 1024, 0x5dfee6a9
+0, 69622, 69622, 512, 1024, 0x0afae660
+0, 70134, 70134, 512, 1024, 0xdc98e9fc
+0, 70646, 70646, 512, 1024, 0x10b7da06
+0, 71158, 71158, 512, 1024, 0x0571e585
+0, 71670, 71670, 512, 1024, 0x18ddf45e
+0, 72182, 72182, 512, 1024, 0x2cbef242
+0, 72694, 72694, 512, 1024, 0xf5380845
+0, 73206, 73206, 512, 1024, 0x34fff45e
+0, 73718, 73718, 512, 1024, 0x6f97e490
+0, 74230, 74230, 512, 1024, 0x77d6f0db
+0, 74742, 74742, 512, 1024, 0xa25ce2db
+0, 75254, 75254, 512, 1024, 0x8260e4e9
+0, 75766, 75766, 512, 1024, 0xc3b2f7d2
+0, 76278, 76278, 512, 1024, 0x82a7edae
+0, 76790, 76790, 512, 1024, 0x7d08dd54
+0, 77302, 77302, 512, 1024, 0x9059eda6
+0, 77814, 77814, 512, 1024, 0xbebaec88
+0, 78326, 78326, 512, 1024, 0xd9afd586
+0, 78838, 78838, 512, 1024, 0x0ca3e622
+0, 79350, 79350, 512, 1024, 0x4123e9e6
+0, 79862, 79862, 512, 1024, 0x2ff9f95c
+0, 80374, 80374, 512, 1024, 0x8522e261
+0, 80886, 80886, 512, 1024, 0xe4f8f499
+0, 81398, 81398, 512, 1024, 0x34f3f2bd
+0, 81910, 81910, 512, 1024, 0x82efe863
+0, 82422, 82422, 512, 1024, 0x9966fcea
+0, 82934, 82934, 512, 1024, 0xe94de3fd
+0, 83446, 83446, 512, 1024, 0x1ce0e27b
+0, 83958, 83958, 512, 1024, 0xd718dcde
+0, 84470, 84470, 512, 1024, 0xd503e724
+0, 84982, 84982, 512, 1024, 0x427ee3b2
+0, 85494, 85494, 512, 1024, 0x4512dcc4
+0, 86006, 86006, 512, 1024, 0xcf31e77c
+0, 86518, 86518, 512, 1024, 0xeb41ea81
+0, 87030, 87030, 512, 1024, 0xfa43e67c
+0, 87542, 87542, 512, 1024, 0x8162f3c9
+0, 88054, 88054, 512, 1024, 0x1b55f6b0
+0, 88566, 88566, 512, 1024, 0x3ebeec44
+0, 89078, 89078, 512, 1024, 0x740fe0c4
+0, 89590, 89590, 512, 1024, 0x8fb4e8b2
+0, 90102, 90102, 512, 1024, 0xe49de6a2
+0, 90614, 90614, 512, 1024, 0xd64febdf
+0, 91126, 91126, 512, 1024, 0x0e74ee08
+0, 91638, 91638, 512, 1024, 0x6c0ddf07
+0, 92150, 92150, 512, 1024, 0x7fb8e3c9
+0, 92662, 92662, 512, 1024, 0x52bfe96c
+0, 93174, 93174, 512, 1024, 0xfc22ee64
+0, 93686, 93686, 512, 1024, 0xe20ae718
+0, 94198, 94198, 512, 1024, 0xa94be395
+0, 94710, 94710, 512, 1024, 0xded306d0
+0, 95222, 95222, 512, 1024, 0x31f7c831
+0, 95734, 95734, 512, 1024, 0x0ffde0a8
+0, 96246, 96246, 512, 1024, 0xc692e3e0
+0, 96758, 96758, 512, 1024, 0x1d8ff7c7
+0, 97270, 97270, 512, 1024, 0x038ee172
+0, 97782, 97782, 512, 1024, 0x9a1eef59
+0, 98294, 98294, 512, 1024, 0x158fe750
+0, 98806, 98806, 512, 1024, 0xac15e42c
+0, 99318, 99318, 512, 1024, 0x6323ed44
+0, 99830, 99830, 512, 1024, 0xd10ce4bb
+0, 100342, 100342, 512, 1024, 0xc1cce296
+0, 100854, 100854, 512, 1024, 0x0782f094
+0, 101366, 101366, 512, 1024, 0xd109de36
+0, 101878, 101878, 512, 1024, 0x175600fb
+0, 102390, 102390, 512, 1024, 0x95d5e8d9
+0, 102902, 102902, 512, 1024, 0xebb6eee1
+0, 103414, 103414, 512, 1024, 0x187cfadc
+0, 103926, 103926, 512, 1024, 0xce35fa5c
+0, 104438, 104438, 512, 1024, 0x8327eea2
+0, 104950, 104950, 512, 1024, 0x5543f219
+0, 105462, 105462, 512, 1024, 0xaacbe0dc
+0, 105974, 105974, 512, 1024, 0xa538e9fb
+0, 106486, 106486, 512, 1024, 0x4dcbe655
+0, 106998, 106998, 512, 1024, 0x86b6d93b
+0, 107510, 107510, 512, 1024, 0x1a06f878
+0, 108022, 108022, 512, 1024, 0xd926e8ef
+0, 108534, 108534, 512, 1024, 0xc624db2f
+0, 109046, 109046, 512, 1024, 0x2153e20d
+0, 109558, 109558, 512, 1024, 0x01dce868
+0, 110070, 110070, 512, 1024, 0xfa5fd3cd
+0, 110582, 110582, 512, 1024, 0x2adef2d5
+0, 111094, 111094, 512, 1024, 0x4f48f8e2
+0, 111606, 111606, 512, 1024, 0x613feeee
+0, 112118, 112118, 512, 1024, 0x3780de8a
+0, 112630, 112630, 512, 1024, 0x2093eb65
+0, 113142, 113142, 512, 1024, 0x54baebbb
+0, 113654, 113654, 512, 1024, 0x8686dd7c
+0, 114166, 114166, 512, 1024, 0x7f8ae80c
+0, 114678, 114678, 512, 1024, 0x7aede972
+0, 115190, 115190, 512, 1024, 0x971bebc0
+0, 115702, 115702, 512, 1024, 0x2dd5fd4b
+0, 116214, 116214, 512, 1024, 0xb1b3e4a3
+0, 116726, 116726, 512, 1024, 0x192defc6
+0, 117238, 117238, 512, 1024, 0x5e46ec44
+0, 117750, 117750, 512, 1024, 0xe6d8e05a
+0, 118262, 118262, 512, 1024, 0x7e2fe2b0
+0, 118774, 118774, 512, 1024, 0x9e3bdf80
+0, 119286, 119286, 512, 1024, 0xa98cd85e
+0, 119798, 119798, 512, 1024, 0x6061e0c4
+0, 120310, 120310, 512, 1024, 0x6112f3fc
+0, 120822, 120822, 512, 1024, 0x99bdfb01
+0, 121334, 121334, 512, 1024, 0x3f5df3ca
+0, 121846, 121846, 512, 1024, 0xf5ebeb05
+0, 122358, 122358, 512, 1024, 0x8498e565
+0, 122870, 122870, 512, 1024, 0x0497f0b7
+0, 123382, 123382, 512, 1024, 0x626ae800
+0, 123894, 123894, 512, 1024, 0xfb71eec4
+0, 124406, 124406, 512, 1024, 0xa86ee739
+0, 124918, 124918, 512, 1024, 0x25c0e050
+0, 125430, 125430, 512, 1024, 0x6027e91e
+0, 125942, 125942, 512, 1024, 0x6772df6e
+0, 126454, 126454, 512, 1024, 0xfefff844
+0, 126966, 126966, 512, 1024, 0x547be862
+0, 127478, 127478, 512, 1024, 0xca84e795
+0, 127990, 127990, 512, 1024, 0xd124db3e
+0, 128502, 128502, 512, 1024, 0xcaf3deb5
+0, 129014, 129014, 512, 1024, 0x487ce92d
+0, 129526, 129526, 512, 1024, 0x117feb95
+0, 130038, 130038, 512, 1024, 0x7b63de3d
+0, 130550, 130550, 512, 1024, 0xa529d8e1
+0, 131062, 131062, 512, 1024, 0x56f6da26
+0, 131574, 131574, 512, 1024, 0xffb8d5af
+0, 132086, 132086, 512, 1024, 0xeecbdc04
+0, 132598, 132598, 512, 1024, 0xfc59d2d2
+0, 133110, 133110, 512, 1024, 0xaf7acef7
+0, 133622, 133622, 512, 1024, 0x3f9bf258
+0, 134134, 134134, 512, 1024, 0xcf54e9d6
+0, 134646, 134646, 512, 1024, 0x680cd0aa
+0, 135158, 135158, 512, 1024, 0x3c1bdc1f
+0, 135670, 135670, 512, 1024, 0x8c8ffe22
+0, 136182, 136182, 512, 1024, 0xf415d362
+0, 136694, 136694, 512, 1024, 0x8c8cdaa9
+0, 137206, 137206, 512, 1024, 0x9531e9f1
+0, 137718, 137718, 512, 1024, 0x223ce536
+0, 138230, 138230, 512, 1024, 0xdfbce5f9
+0, 138742, 138742, 512, 1024, 0x20b6ed7d
+0, 139254, 139254, 512, 1024, 0x1a17e109
+0, 139766, 139766, 512, 1024, 0xc672eaea
+0, 140278, 140278, 512, 1024, 0x12a7dc5e
+0, 140790, 140790, 512, 1024, 0x4497f342
+0, 141302, 141302, 512, 1024, 0xdfb5db4b
+0, 141814, 141814, 512, 1024, 0xde48ef6c
+0, 142326, 142326, 512, 1024, 0x1d98e316
+0, 142838, 142838, 512, 1024, 0xbd2ad72f
+0, 143350, 143350, 512, 1024, 0xf1aad776
+0, 143862, 143862, 512, 1024, 0x4db3e3c0
+0, 144374, 144374, 512, 1024, 0x832de0a0
+0, 144886, 144886, 512, 1024, 0xc5f0ef25
+0, 145398, 145398, 512, 1024, 0x419bda6e
+0, 145910, 145910, 512, 1024, 0x5de7f77e
+0, 146422, 146422, 512, 1024, 0x0063ec9a
+0, 146934, 146934, 512, 1024, 0x10c3d470
+0, 147446, 147446, 512, 1024, 0xba66d226
+0, 147958, 147958, 512, 1024, 0xea47ded3
+0, 148470, 148470, 512, 1024, 0x6202d67b
+0, 148982, 148982, 512, 1024, 0x3f80e7cf
+0, 149494, 149494, 512, 1024, 0x4e64eaae
+0, 150006, 150006, 512, 1024, 0x2108e83d
+0, 150518, 150518, 512, 1024, 0x38c3dec1
+0, 151030, 151030, 512, 1024, 0x46d3f77a
+0, 151542, 151542, 512, 1024, 0x4838e787
+0, 152054, 152054, 512, 1024, 0xc71df16d
+0, 152566, 152566, 512, 1024, 0xdbe4ebbd
+0, 153078, 153078, 512, 1024, 0xa156d07b
+0, 153590, 153590, 512, 1024, 0x34eddc80
+0, 154102, 154102, 512, 1024, 0xe840e87c
+0, 154614, 154614, 512, 1024, 0x6accf8f5
+0, 155126, 155126, 512, 1024, 0xa1dbebb9
+0, 155638, 155638, 512, 1024, 0x6d07d98c
+0, 156150, 156150, 512, 1024, 0x94c7e805
+0, 156662, 156662, 512, 1024, 0x5199e586
+0, 157174, 157174, 512, 1024, 0xe797e1aa
+0, 157686, 157686, 512, 1024, 0xff19eda7
+0, 158198, 158198, 512, 1024, 0x9cb9d040
+0, 158710, 158710, 512, 1024, 0xaeedd325
+0, 159222, 159222, 512, 1024, 0xf5ade306
+0, 159734, 159734, 512, 1024, 0x54a5e129
+0, 160246, 160246, 512, 1024, 0x6665ddeb
+0, 160758, 160758, 512, 1024, 0x9d18e033
+0, 161270, 161270, 512, 1024, 0x7f23df74
+0, 161782, 161782, 512, 1024, 0x7c34f158
+0, 162294, 162294, 512, 1024, 0x47f6dae2
+0, 162806, 162806, 512, 1024, 0x5ffdd903
+0, 163318, 163318, 512, 1024, 0x8233d108
+0, 163830, 163830, 512, 1024, 0x45c6e20d
+0, 164342, 164342, 512, 1024, 0xae11fa6e
+0, 164854, 164854, 512, 1024, 0xa30defd2
+0, 165366, 165366, 512, 1024, 0xfc1ecccf
+0, 165878, 165878, 512, 1024, 0x920edc94
+0, 166390, 166390, 512, 1024, 0xd7f3dc58
+0, 166902, 166902, 512, 1024, 0x4972d37d
+0, 167414, 167414, 512, 1024, 0xfefef358
+0, 167926, 167926, 512, 1024, 0x3648e473
+0, 168438, 168438, 512, 1024, 0x58dee6c3
+0, 168950, 168950, 512, 1024, 0x9cc6df27
+0, 169462, 169462, 512, 1024, 0x6adfe99c
+0, 169974, 169974, 512, 1024, 0x6a56e11f
+0, 170486, 170486, 512, 1024, 0x4860edf1
+0, 170998, 170998, 512, 1024, 0x9132f10a
+0, 171510, 171510, 512, 1024, 0x3e09d209
+0, 172022, 172022, 512, 1024, 0x4b6bf4d8
+0, 172534, 172534, 512, 1024, 0x0cd5e838
+0, 173046, 173046, 512, 1024, 0x080be078
+0, 173558, 173558, 512, 1024, 0xfdb0e31c
+0, 174070, 174070, 512, 1024, 0xced5e7bd
+0, 174582, 174582, 512, 1024, 0x65b3e435
+0, 175094, 175094, 512, 1024, 0x5b5bfe2e
+0, 175606, 175606, 512, 1024, 0xa8bde3cb
+0, 176118, 176118, 512, 1024, 0xfd0fdefa
+0, 176630, 176630, 512, 1024, 0xbec4ef95
+0, 177142, 177142, 512, 1024, 0x683ad8dd
+0, 177654, 177654, 512, 1024, 0x8eefeb77
+0, 178166, 178166, 512, 1024, 0x84fc5878
+0, 178678, 178678, 512, 1024, 0x9a0ded60
diff --git a/tests/ref/fate/adpcm-ms-mono b/tests/ref/fate/adpcm-ms-mono
index c456708..3bf44f8 100644
--- a/tests/ref/fate/adpcm-ms-mono
+++ b/tests/ref/fate/adpcm-ms-mono
@@ -43,4 +43,4 @@
0, 20500, 20500, 500, 1000, 0xf195eb44
0, 21000, 21000, 500, 1000, 0xa491f3ef
0, 21500, 21500, 500, 1000, 0x2c036e18
-0, 22000, 22000, 50, 100, 0x0bd81f05
+0, 22000, 22000, 500, 1000, 0x52d65e2a
diff --git a/tests/ref/fate/ansi256 b/tests/ref/fate/ansi256
new file mode 100644
index 0000000..94acd45
--- /dev/null
+++ b/tests/ref/fate/ansi256
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 768000, 0x4dfbb6d0
+0, 1, 1, 1, 768000, 0x22652a22
+0, 2, 2, 1, 768000, 0x6c613e8c
+0, 3, 3, 1, 768000, 0x82471f25
+0, 4, 4, 1, 768000, 0xd8dc5ac6
+0, 5, 5, 1, 768000, 0x1afdc026
+0, 6, 6, 1, 768000, 0x518f3ba1
+0, 7, 7, 1, 768000, 0xa82a8e4b
diff --git a/tests/ref/fate/armovie-escape124 b/tests/ref/fate/armovie-escape124
index c686327..83614c2 100644
--- a/tests/ref/fate/armovie-escape124
+++ b/tests/ref/fate/armovie-escape124
@@ -1,106 +1,106 @@
#tb 0: 1/25
#tb 1: 1/44100
-0, 0, 0, 1, 230400, 0x5288d70f
+0, 0, 0, 1, 230400, 0xd133e177
1, 0, 0, 44100, 176400, 0xdd61578c
-0, 1, 1, 1, 230400, 0x2d3c1066
-0, 2, 2, 1, 230400, 0x89eb5b4a
-0, 3, 3, 1, 230400, 0x24c2d2e7
-0, 4, 4, 1, 230400, 0x9271cb38
-0, 5, 5, 1, 230400, 0xc74a5009
-0, 6, 6, 1, 230400, 0x61d70705
-0, 7, 7, 1, 230400, 0x6bb2c252
-0, 8, 8, 1, 230400, 0x6b3ac910
-0, 9, 9, 1, 230400, 0x44071f28
-0, 10, 10, 1, 230400, 0x8abd00fe
-0, 11, 11, 1, 230400, 0xcbe3395d
-0, 12, 12, 1, 230400, 0x603e7b7a
-0, 13, 13, 1, 230400, 0x2ca8865b
-0, 14, 14, 1, 230400, 0x11b4c665
-0, 15, 15, 1, 230400, 0x3f19787c
-0, 16, 16, 1, 230400, 0x651d24b6
-0, 17, 17, 1, 230400, 0x325d05af
-0, 18, 18, 1, 230400, 0x4f89d8a8
-0, 19, 19, 1, 230400, 0xb07647f0
-0, 20, 20, 1, 230400, 0x71141237
-0, 21, 21, 1, 230400, 0xa848a2d2
-0, 22, 22, 1, 230400, 0x3fbe4b58
-0, 23, 23, 1, 230400, 0xa1e235a0
-0, 24, 24, 1, 230400, 0x9bcf607a
-0, 25, 25, 1, 230400, 0x3302e9eb
+0, 1, 1, 1, 230400, 0xe3501bb2
+0, 2, 2, 1, 230400, 0x44da84f0
+0, 3, 3, 1, 230400, 0xe0fd17ed
+0, 4, 4, 1, 230400, 0xef4e08c7
+0, 5, 5, 1, 230400, 0xf52f82b5
+0, 6, 6, 1, 230400, 0x05eb186c
+0, 7, 7, 1, 230400, 0x0653f05d
+0, 8, 8, 1, 230400, 0xde1a0735
+0, 9, 9, 1, 230400, 0x6045576e
+0, 10, 10, 1, 230400, 0xac9444c4
+0, 11, 11, 1, 230400, 0x5f7f82fb
+0, 12, 12, 1, 230400, 0xaf4718ce
+0, 13, 13, 1, 230400, 0x117d5787
+0, 14, 14, 1, 230400, 0x319ac1f5
+0, 15, 15, 1, 230400, 0xd05cb30a
+0, 16, 16, 1, 230400, 0x96107c72
+0, 17, 17, 1, 230400, 0x73ff0a30
+0, 18, 18, 1, 230400, 0x865d0f3e
+0, 19, 19, 1, 230400, 0x3384ad55
+0, 20, 20, 1, 230400, 0x6694b2ea
+0, 21, 21, 1, 230400, 0x324f5cb8
+0, 22, 22, 1, 230400, 0x2de7c12f
+0, 23, 23, 1, 230400, 0x57fedb1a
+0, 24, 24, 1, 230400, 0xf46f2abf
+0, 25, 25, 1, 230400, 0xe5fead9b
1, 44100, 44100, 44100, 176400, 0x0b9e6d67
-0, 26, 26, 1, 230400, 0xd731ba90
-0, 27, 27, 1, 230400, 0x821eedcf
-0, 28, 28, 1, 230400, 0xd068a93d
-0, 29, 29, 1, 230400, 0x2811d46e
-0, 30, 30, 1, 230400, 0xd9740446
-0, 31, 31, 1, 230400, 0x1bce0df6
-0, 32, 32, 1, 230400, 0x44bc60ad
-0, 33, 33, 1, 230400, 0xf56f6200
-0, 34, 34, 1, 230400, 0x874a2264
-0, 35, 35, 1, 230400, 0xaa155c0e
-0, 36, 36, 1, 230400, 0x595392d4
-0, 37, 37, 1, 230400, 0x58dc57de
-0, 38, 38, 1, 230400, 0x1c06733e
-0, 39, 39, 1, 230400, 0x6807b1db
-0, 40, 40, 1, 230400, 0x3fedff87
-0, 41, 41, 1, 230400, 0x3e38cc13
-0, 42, 42, 1, 230400, 0x6685ec35
-0, 43, 43, 1, 230400, 0x6c0742fd
-0, 44, 44, 1, 230400, 0x8108f83c
-0, 45, 45, 1, 230400, 0xc0e217c8
-0, 46, 46, 1, 230400, 0xb22ca65d
-0, 47, 47, 1, 230400, 0xd54cec93
-0, 48, 48, 1, 230400, 0xd9d61de3
-0, 49, 49, 1, 230400, 0x7e0f9675
-0, 50, 50, 1, 230400, 0x9869f5b7
+0, 26, 26, 1, 230400, 0x65764edb
+0, 27, 27, 1, 230400, 0xeabdcf53
+0, 28, 28, 1, 230400, 0xaeb659fc
+0, 29, 29, 1, 230400, 0x5ec97eb1
+0, 30, 30, 1, 230400, 0x2482abae
+0, 31, 31, 1, 230400, 0x297fb0c8
+0, 32, 32, 1, 230400, 0x57a52a3d
+0, 33, 33, 1, 230400, 0x44040e98
+0, 34, 34, 1, 230400, 0xa150e542
+0, 35, 35, 1, 230400, 0x0a1e1296
+0, 36, 36, 1, 230400, 0xf1085864
+0, 37, 37, 1, 230400, 0xe7a13b40
+0, 38, 38, 1, 230400, 0x759d384d
+0, 39, 39, 1, 230400, 0x72e08991
+0, 40, 40, 1, 230400, 0x10a4bbc9
+0, 41, 41, 1, 230400, 0xb258ac16
+0, 42, 42, 1, 230400, 0xde06facb
+0, 43, 43, 1, 230400, 0x94284e11
+0, 44, 44, 1, 230400, 0xedf23092
+0, 45, 45, 1, 230400, 0xc2be6319
+0, 46, 46, 1, 230400, 0x103a0b7b
+0, 47, 47, 1, 230400, 0x3415888b
+0, 48, 48, 1, 230400, 0x5ecaac75
+0, 49, 49, 1, 230400, 0xb9ba503e
+0, 50, 50, 1, 230400, 0xb20ccf57
1, 88200, 88200, 44100, 176400, 0x2793fad7
-0, 51, 51, 1, 230400, 0x22f33400
-0, 52, 52, 1, 230400, 0x31b999bd
-0, 53, 53, 1, 230400, 0x36c23878
-0, 54, 54, 1, 230400, 0x06093a30
-0, 55, 55, 1, 230400, 0x213f1718
-0, 56, 56, 1, 230400, 0x83683006
-0, 57, 57, 1, 230400, 0x0bfcec36
-0, 58, 58, 1, 230400, 0x01b77825
-0, 59, 59, 1, 230400, 0x650a5ea2
-0, 60, 60, 1, 230400, 0xd8b2c559
-0, 61, 61, 1, 230400, 0xb012eb10
-0, 62, 62, 1, 230400, 0x135d53a4
-0, 63, 63, 1, 230400, 0x98dd0712
-0, 64, 64, 1, 230400, 0x75240ac0
-0, 65, 65, 1, 230400, 0xa16769d5
-0, 66, 66, 1, 230400, 0x3e08cda3
-0, 67, 67, 1, 230400, 0xcd20d561
-0, 68, 68, 1, 230400, 0x3531577d
-0, 69, 69, 1, 230400, 0x65ff4c82
-0, 70, 70, 1, 230400, 0x8fd4a580
-0, 71, 71, 1, 230400, 0x3cf7af4c
-0, 72, 72, 1, 230400, 0xda7a9202
-0, 73, 73, 1, 230400, 0x4bebc138
-0, 74, 74, 1, 230400, 0x5517e685
-0, 75, 75, 1, 230400, 0x95f6c7a3
+0, 51, 51, 1, 230400, 0x0dba31ed
+0, 52, 52, 1, 230400, 0x91c5e7d4
+0, 53, 53, 1, 230400, 0x09ac954b
+0, 54, 54, 1, 230400, 0xe9c3d563
+0, 55, 55, 1, 230400, 0xf46eef67
+0, 56, 56, 1, 230400, 0x117f4b80
+0, 57, 57, 1, 230400, 0x61714860
+0, 58, 58, 1, 230400, 0x5c7112d0
+0, 59, 59, 1, 230400, 0xd42c51e7
+0, 60, 60, 1, 230400, 0x425f0c99
+0, 61, 61, 1, 230400, 0x4c398834
+0, 62, 62, 1, 230400, 0x237f89c2
+0, 63, 63, 1, 230400, 0xd2e29b05
+0, 64, 64, 1, 230400, 0x204a054b
+0, 65, 65, 1, 230400, 0x25a9faf7
+0, 66, 66, 1, 230400, 0x83f6c1a8
+0, 67, 67, 1, 230400, 0xe48321b9
+0, 68, 68, 1, 230400, 0x714c1005
+0, 69, 69, 1, 230400, 0x36cc58e9
+0, 70, 70, 1, 230400, 0x5e9ffdd9
+0, 71, 71, 1, 230400, 0x582b55dc
+0, 72, 72, 1, 230400, 0x139a7f39
+0, 73, 73, 1, 230400, 0xefb5f998
+0, 74, 74, 1, 230400, 0xeb736da8
+0, 75, 75, 1, 230400, 0x488f9847
1, 132300, 132300, 44100, 176400, 0xe2649a4a
-0, 76, 76, 1, 230400, 0x9849ebf9
-0, 77, 77, 1, 230400, 0xd77e1c7d
-0, 78, 78, 1, 230400, 0x4dc6c923
-0, 79, 79, 1, 230400, 0x7ce817c8
-0, 80, 80, 1, 230400, 0xafb4acde
-0, 81, 81, 1, 230400, 0xd0030b2c
-0, 82, 82, 1, 230400, 0xb3acb77c
-0, 83, 83, 1, 230400, 0x4d32b61c
-0, 84, 84, 1, 230400, 0x2436a915
-0, 85, 85, 1, 230400, 0xa6fd831f
-0, 86, 86, 1, 230400, 0x6c6edfca
-0, 87, 87, 1, 230400, 0x4b30d72e
-0, 88, 88, 1, 230400, 0x59f46a8a
-0, 89, 89, 1, 230400, 0xa2d0435f
-0, 90, 90, 1, 230400, 0x463872c4
-0, 91, 91, 1, 230400, 0x1d7e870a
-0, 92, 92, 1, 230400, 0x74f4e530
-0, 93, 93, 1, 230400, 0xbc61053d
-0, 94, 94, 1, 230400, 0x5fb238dc
-0, 95, 95, 1, 230400, 0x14a29d83
-0, 96, 96, 1, 230400, 0x3fd1d09b
-0, 97, 97, 1, 230400, 0x098afc13
-0, 98, 98, 1, 230400, 0x9bd12a62
-0, 99, 99, 1, 230400, 0x7bf71419
+0, 76, 76, 1, 230400, 0x6ab20741
+0, 77, 77, 1, 230400, 0xa73686f0
+0, 78, 78, 1, 230400, 0x67878643
+0, 79, 79, 1, 230400, 0x83bb241b
+0, 80, 80, 1, 230400, 0xe6b70660
+0, 81, 81, 1, 230400, 0x87f5aca3
+0, 82, 82, 1, 230400, 0x29c79bc3
+0, 83, 83, 1, 230400, 0xcadbd70b
+0, 84, 84, 1, 230400, 0x8cdcfdee
+0, 85, 85, 1, 230400, 0x90aa0442
+0, 86, 86, 1, 230400, 0xa68e87b7
+0, 87, 87, 1, 230400, 0xa2c49e58
+0, 88, 88, 1, 230400, 0x9a9a4c55
+0, 89, 89, 1, 230400, 0x06b53aed
+0, 90, 90, 1, 230400, 0x79e1808a
+0, 91, 91, 1, 230400, 0x3e53a411
+0, 92, 92, 1, 230400, 0xfebc13ca
+0, 93, 93, 1, 230400, 0x1f1f443b
+0, 94, 94, 1, 230400, 0xd0db806a
+0, 95, 95, 1, 230400, 0x6f2aee94
+0, 96, 96, 1, 230400, 0xe8cc23ba
+0, 97, 97, 1, 230400, 0x2edf510b
+0, 98, 98, 1, 230400, 0x87118129
+0, 99, 99, 1, 230400, 0x1dd1709a
diff --git a/tests/ref/fate/ast b/tests/ref/fate/ast
new file mode 100644
index 0000000..5b89c2b
--- /dev/null
+++ b/tests/ref/fate/ast
@@ -0,0 +1 @@
+CRC=0x87713611
diff --git a/tests/ref/fate/avio-direct b/tests/ref/fate/avio-direct
new file mode 100644
index 0000000..599683a
--- /dev/null
+++ b/tests/ref/fate/avio-direct
@@ -0,0 +1,59 @@
+#tb 0: 1/30
+0, 0, 0, 1, 145152, 0x8458d4cb
+0, 1, 1, 1, 145152, 0xa694d7c7
+0, 2, 2, 1, 145152, 0x2bd4bfc9
+0, 3, 3, 1, 145152, 0xe53b1616
+0, 4, 4, 1, 145152, 0x6a0a806a
+0, 5, 5, 1, 145152, 0x45f7b8e6
+0, 6, 6, 1, 145152, 0x4e14150e
+0, 7, 7, 1, 145152, 0xe1cd9b6f
+0, 8, 8, 1, 145152, 0x5b5802d7
+0, 9, 9, 1, 145152, 0xb03da5e7
+0, 10, 10, 1, 145152, 0x3436b06e
+0, 11, 11, 1, 145152, 0x4535e638
+0, 12, 12, 1, 145152, 0x72934af1
+0, 13, 13, 1, 145152, 0xb672d459
+0, 14, 14, 1, 145152, 0xab57491b
+0, 15, 15, 1, 145152, 0xdbac3480
+0, 16, 16, 1, 145152, 0x54215962
+0, 17, 17, 1, 145152, 0x451f456e
+0, 18, 18, 1, 145152, 0xa17655d1
+0, 19, 19, 1, 145152, 0xce95422c
+0, 20, 20, 1, 145152, 0xe0ee8e77
+0, 21, 21, 1, 145152, 0xdaabe277
+0, 22, 22, 1, 145152, 0xc21bb665
+0, 23, 23, 1, 145152, 0x1e74270e
+0, 24, 24, 1, 145152, 0xae7bac5f
+0, 25, 25, 1, 145152, 0xf62442ed
+0, 26, 26, 1, 145152, 0x5c8d8984
+0, 27, 27, 1, 145152, 0x97a69fe7
+0, 28, 28, 1, 145152, 0x1f244d19
+0, 29, 29, 1, 145152, 0x2758bc25
+0, 30, 30, 1, 145152, 0xf43ddb89
+0, 31, 31, 1, 145152, 0x086a524e
+0, 32, 32, 1, 145152, 0x8b464d4d
+0, 33, 33, 1, 145152, 0xb77b63d2
+0, 34, 34, 1, 145152, 0xfd842fa8
+0, 35, 35, 1, 145152, 0xa98b6dbe
+0, 36, 36, 1, 145152, 0xdedbab2c
+0, 37, 37, 1, 145152, 0x24e19172
+0, 38, 38, 1, 145152, 0x1ef456f6
+0, 39, 39, 1, 145152, 0xaceabdf0
+0, 40, 40, 1, 145152, 0xb54de3d9
+0, 41, 41, 1, 145152, 0x3af0df9b
+0, 42, 42, 1, 145152, 0xf89fbd9a
+0, 43, 43, 1, 145152, 0xc6a9673c
+0, 44, 44, 1, 145152, 0x6d5a929e
+0, 45, 45, 1, 145152, 0x879e7d9b
+0, 46, 46, 1, 145152, 0x233c14eb
+0, 47, 47, 1, 145152, 0x8246f081
+0, 48, 48, 1, 145152, 0x3366c4bf
+0, 49, 49, 1, 145152, 0x6b0203da
+0, 50, 50, 1, 145152, 0x48a00163
+0, 51, 51, 1, 145152, 0xe956ac2c
+0, 52, 52, 1, 145152, 0xa2511283
+0, 53, 53, 1, 145152, 0x7e03222d
+0, 54, 54, 1, 145152, 0xc31a7a40
+0, 55, 55, 1, 145152, 0x80448031
+0, 56, 56, 1, 145152, 0xe3b1fbf7
+0, 57, 57, 1, 145152, 0xa00395a4
diff --git a/tests/ref/fate/bethsoft-vid b/tests/ref/fate/bethsoft-vid
index 535888b..f59823c 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
-1, 55297, 55297, 258, 516, 0x98885b26
+0, 69, 69, 1, 192000, 0x159313a8
+1, 55297, 55297, 925, 1850, 0x7ff682f7
diff --git a/tests/ref/fate/bprint b/tests/ref/fate/bprint
new file mode 100644
index 0000000..b33c1ae
--- /dev/null
+++ b/tests/ref/fate/bprint
@@ -0,0 +1,16 @@
+Short text in unlimited buffer: 174/174
+ 1
+ 1 1
+ 1 2 1
+ 1 3 3 1
+ 1 4 6 4 1
+ 1 5 10 10 5 1
+
+Long text in unlimited buffer: 2834/2834
+Long text in limited buffer: 2047/2834
+Short text in automatic buffer: 174/174
+Long text in automatic buffer: 1000/2834
+Long text count only buffer: 0/2834
+Long text count only buffer: 255/2834
+strftime full: 255/10 "2000-12-20"
+strftime truncated: 255/10 "2000-12"
diff --git a/tests/ref/fate/brstm b/tests/ref/fate/brstm
new file mode 100644
index 0000000..d183b3f
--- /dev/null
+++ b/tests/ref/fate/brstm
@@ -0,0 +1 @@
+CRC=0x1feb92a8
diff --git a/tests/ref/fate/cavs b/tests/ref/fate/cavs
index c96468a..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/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/cyberia-c93 b/tests/ref/fate/cyberia-c93
index f02435c..2c71e50 100644
--- a/tests/ref/fate/cyberia-c93
+++ b/tests/ref/fate/cyberia-c93
@@ -36,7 +36,7 @@
0, 30, 30, 1, 184320, 0x54975910
0, 31, 31, 1, 184320, 0xf4857db9
0, 32, 32, 1, 184320, 0x82d18161
-1, 42552, 42552, 5835, 11670, 0x04aa0b1e
+1, 42552, 42552, 14184, 28368, 0x9101e519
0, 33, 33, 1, 184320, 0x06d93bd0
0, 34, 34, 1, 184320, 0xa4304c00
0, 35, 35, 1, 184320, 0x5f77d9cd
diff --git a/tests/ref/fate/d-cinema-demux b/tests/ref/fate/d-cinema-demux
index f663040..2f28e46 100644
--- a/tests/ref/fate/d-cinema-demux
+++ b/tests/ref/fate/d-cinema-demux
@@ -2,4 +2,4 @@
0, 0, 0, 1875, 36000, 0xd592781d
0, 1875, 1875, 1875, 36000, 0xd592781d
0, 3750, 3750, 1875, 36000, 0xd592781d
-0, 5625, 5625, 1200, 23056, 0xde81f0d6
+0, 5625, 5625, 1200, 23056, 0xde81f0d6, F=0x3
diff --git a/tests/ref/fate/dfa1 b/tests/ref/fate/dfa1
index 92a7cce..7bc5bf1 100644
--- a/tests/ref/fate/dfa1
+++ b/tests/ref/fate/dfa1
@@ -1,26 +1,26 @@
#tb 0: 16/125
-0, 0, 0, 1, 921600, 0x2e2b3ca4
-0, 1, 1, 1, 921600, 0x0ff7a368
-0, 2, 2, 1, 921600, 0xf5f0dc50
-0, 3, 3, 1, 921600, 0x56cb0c9d
-0, 4, 4, 1, 921600, 0xb253228f
-0, 5, 5, 1, 921600, 0xefd3419e
-0, 6, 6, 1, 921600, 0x708c0ce7
-0, 7, 7, 1, 921600, 0x0b3a7f6d
-0, 8, 8, 1, 921600, 0x72db4eac
-0, 9, 9, 1, 921600, 0x94328111
-0, 10, 10, 1, 921600, 0x95f7b2f0
-0, 11, 11, 1, 921600, 0xdc3c9655
-0, 12, 12, 1, 921600, 0xfe03dec6
-0, 13, 13, 1, 921600, 0x2551dffb
-0, 14, 14, 1, 921600, 0xe8b37d9e
-0, 15, 15, 1, 921600, 0xad93508b
-0, 16, 16, 1, 921600, 0x5a1c4890
-0, 17, 17, 1, 921600, 0x6f972fb4
-0, 18, 18, 1, 921600, 0xa1d5ff95
-0, 19, 19, 1, 921600, 0x7bc5d07c
-0, 20, 20, 1, 921600, 0xc0311e4e
-0, 21, 21, 1, 921600, 0x5b02cc48
-0, 22, 22, 1, 921600, 0x8db4d5fa
-0, 23, 23, 1, 921600, 0x31aae769
-0, 24, 24, 1, 921600, 0xab62b9a7
+0, 0, 0, 1, 921600, 0xb69faa34
+0, 1, 1, 1, 921600, 0x38680829
+0, 2, 2, 1, 921600, 0xa7263c5a
+0, 3, 3, 1, 921600, 0xa784626a
+0, 4, 4, 1, 921600, 0xb4c47212
+0, 5, 5, 1, 921600, 0xd17285ea
+0, 6, 6, 1, 921600, 0xe9b33902
+0, 7, 7, 1, 921600, 0x215ea693
+0, 8, 8, 1, 921600, 0xe2ab6c7a
+0, 9, 9, 1, 921600, 0xf2867624
+0, 10, 10, 1, 921600, 0x607d78c1
+0, 11, 11, 1, 921600, 0x6e743bb7
+0, 12, 12, 1, 921600, 0x1fbf8f5a
+0, 13, 13, 1, 921600, 0xac6c912e
+0, 14, 14, 1, 921600, 0x556933bc
+0, 15, 15, 1, 921600, 0xda4c242b
+0, 16, 16, 1, 921600, 0xa6b32f83
+0, 17, 17, 1, 921600, 0x1ecc2996
+0, 18, 18, 1, 921600, 0xf1c3fc0f
+0, 19, 19, 1, 921600, 0x3f1db909
+0, 20, 20, 1, 921600, 0x7582fb93
+0, 21, 21, 1, 921600, 0x102ba261
+0, 22, 22, 1, 921600, 0xfbcf9de0
+0, 23, 23, 1, 921600, 0xe9ecb4d9
+0, 24, 24, 1, 921600, 0x7ee36a42
diff --git a/tests/ref/fate/dfa10 b/tests/ref/fate/dfa10
index a140e5c..a799f03 100644
--- a/tests/ref/fate/dfa10
+++ b/tests/ref/fate/dfa10
@@ -1,9 +1,9 @@
#tb 0: 71/1000
-0, 0, 0, 1, 192000, 0xbabcbd55
-0, 1, 1, 1, 192000, 0xf00a5683
-0, 2, 2, 1, 192000, 0xcce90589
-0, 3, 3, 1, 192000, 0x8545631f
-0, 4, 4, 1, 192000, 0xd3ab654c
-0, 5, 5, 1, 192000, 0x5e0dda12
-0, 6, 6, 1, 192000, 0x7e94b053
-0, 7, 7, 1, 192000, 0x8027e68b
+0, 0, 0, 1, 192000, 0x7384f9b2
+0, 1, 1, 1, 192000, 0xd1f61c71
+0, 2, 2, 1, 192000, 0x0c6937d1
+0, 3, 3, 1, 192000, 0x56459a3a
+0, 4, 4, 1, 192000, 0x6d011790
+0, 5, 5, 1, 192000, 0xb5347ce8
+0, 6, 6, 1, 192000, 0xcd422568
+0, 7, 7, 1, 192000, 0xde4fef2d
diff --git a/tests/ref/fate/dfa11 b/tests/ref/fate/dfa11
index 3990d24..30b4b71 100644
--- a/tests/ref/fate/dfa11
+++ b/tests/ref/fate/dfa11
@@ -1,10 +1,10 @@
#tb 0: 71/1000
-0, 0, 0, 1, 192000, 0x8b8bd8de
-0, 1, 1, 1, 192000, 0xdac26ec2
-0, 2, 2, 1, 192000, 0x0fc01c28
-0, 3, 3, 1, 192000, 0x1251eef7
-0, 4, 4, 1, 192000, 0x89eced0e
-0, 5, 5, 1, 192000, 0x4943d821
-0, 6, 6, 1, 192000, 0x49258ec9
-0, 7, 7, 1, 192000, 0x9afd5881
-0, 8, 8, 1, 192000, 0xb322b901
+0, 0, 0, 1, 192000, 0x4269d703
+0, 1, 1, 1, 192000, 0xdf8667e7
+0, 2, 2, 1, 192000, 0x450026ad
+0, 3, 3, 1, 192000, 0x2528ea52
+0, 4, 4, 1, 192000, 0x83bcd1ec
+0, 5, 5, 1, 192000, 0x88d5ba27
+0, 6, 6, 1, 192000, 0x44424577
+0, 7, 7, 1, 192000, 0xd93f12a3
+0, 8, 8, 1, 192000, 0xcd625f3e
diff --git a/tests/ref/fate/dfa2 b/tests/ref/fate/dfa2
index a050c97..cc4b454 100644
--- a/tests/ref/fate/dfa2
+++ b/tests/ref/fate/dfa2
@@ -1,18 +1,18 @@
#tb 0: 71/1000
-0, 0, 0, 1, 921600, 0x713f2da1
-0, 1, 1, 1, 921600, 0x9e772ec9
-0, 2, 2, 1, 921600, 0x9420310f
-0, 3, 3, 1, 921600, 0xd68f294f
-0, 4, 4, 1, 921600, 0xe25a1bcf
-0, 5, 5, 1, 921600, 0x32f903ec
-0, 6, 6, 1, 921600, 0xdb290b1c
-0, 7, 7, 1, 921600, 0x0b0d1b0f
-0, 8, 8, 1, 921600, 0x58430921
-0, 9, 9, 1, 921600, 0xe65dd39e
-0, 10, 10, 1, 921600, 0x146b3068
-0, 11, 11, 1, 921600, 0x6e1e7f78
-0, 12, 12, 1, 921600, 0x0166e01c
-0, 13, 13, 1, 921600, 0x83b86b56
-0, 14, 14, 1, 921600, 0xd52a1697
-0, 15, 15, 1, 921600, 0x5b38adc8
-0, 16, 16, 1, 921600, 0x457f6cea
+0, 0, 0, 1, 921600, 0x8a5d15df
+0, 1, 1, 1, 921600, 0x92c01362
+0, 2, 2, 1, 921600, 0xe1a31643
+0, 3, 3, 1, 921600, 0x37a90fe2
+0, 4, 4, 1, 921600, 0x74410783
+0, 5, 5, 1, 921600, 0xecf4ef1a
+0, 6, 6, 1, 921600, 0x4d7ff3d4
+0, 7, 7, 1, 921600, 0xac820317
+0, 8, 8, 1, 921600, 0xbe5ff56e
+0, 9, 9, 1, 921600, 0x8e59c329
+0, 10, 10, 1, 921600, 0x73bf23f3
+0, 11, 11, 1, 921600, 0xb90c780f
+0, 12, 12, 1, 921600, 0xfbd9dc32
+0, 13, 13, 1, 921600, 0x30586821
+0, 14, 14, 1, 921600, 0x6695195b
+0, 15, 15, 1, 921600, 0xc449aa85
+0, 16, 16, 1, 921600, 0xca6a391c
diff --git a/tests/ref/fate/dfa3 b/tests/ref/fate/dfa3
index 8c91faa..9b170ec 100644
--- a/tests/ref/fate/dfa3
+++ b/tests/ref/fate/dfa3
@@ -1,11 +1,11 @@
#tb 0: 1/10
-0, 0, 0, 1, 192000, 0x10380cf0
-0, 1, 1, 1, 192000, 0x1d74af4c
-0, 2, 2, 1, 192000, 0xd665492d
-0, 3, 3, 1, 192000, 0xbf544565
-0, 4, 4, 1, 192000, 0xf8a33b00
-0, 5, 5, 1, 192000, 0x7d08bbad
-0, 6, 6, 1, 192000, 0x10685a90
-0, 7, 7, 1, 192000, 0x0a1a9ef6
-0, 8, 8, 1, 192000, 0x3e967980
-0, 9, 9, 1, 192000, 0x9849f751
+0, 0, 0, 1, 192000, 0x236a1b54
+0, 1, 1, 1, 192000, 0xfb438b68
+0, 2, 2, 1, 192000, 0xde504563
+0, 3, 3, 1, 192000, 0xfaf88e05
+0, 4, 4, 1, 192000, 0xe15de5af
+0, 5, 5, 1, 192000, 0x641fcca4
+0, 6, 6, 1, 192000, 0x74899cb6
+0, 7, 7, 1, 192000, 0x93fdb1b4
+0, 8, 8, 1, 192000, 0x58d83456
+0, 9, 9, 1, 192000, 0x7d3012ac
diff --git a/tests/ref/fate/dfa4 b/tests/ref/fate/dfa4
index 67b5722..0e0dc02 100644
--- a/tests/ref/fate/dfa4
+++ b/tests/ref/fate/dfa4
@@ -1,14 +1,15 @@
#tb 0: 71/500
-0, 1, 1, 1, 921600, 0xe6309638
-0, 2, 2, 1, 921600, 0xa99a7665
-0, 3, 3, 1, 921600, 0x172ccfbb
-0, 4, 4, 1, 921600, 0xcf676571
-0, 5, 5, 1, 921600, 0x6a5077f2
-0, 6, 6, 1, 921600, 0x6a5077f2
-0, 7, 7, 1, 921600, 0x6a5077f2
-0, 8, 8, 1, 921600, 0x6a5077f2
-0, 9, 9, 1, 921600, 0x6a5077f2
-0, 10, 10, 1, 921600, 0x6a5077f2
-0, 11, 11, 1, 921600, 0xb83db404
-0, 12, 12, 1, 921600, 0x997ceb90
-0, 13, 13, 1, 921600, 0xd707157c
+0, 0, 0, 1, 921600, 0x00000000
+0, 1, 1, 1, 921600, 0xd9e060e3
+0, 2, 2, 1, 921600, 0x15e28dc7
+0, 3, 3, 1, 921600, 0x78e8bfbc
+0, 4, 4, 1, 921600, 0xe9407075
+0, 5, 5, 1, 921600, 0xab818b8a
+0, 6, 6, 1, 921600, 0xab818b8a
+0, 7, 7, 1, 921600, 0xab818b8a
+0, 8, 8, 1, 921600, 0xab818b8a
+0, 9, 9, 1, 921600, 0xab818b8a
+0, 10, 10, 1, 921600, 0xab818b8a
+0, 11, 11, 1, 921600, 0xad5ad11c
+0, 12, 12, 1, 921600, 0xe6e50f8c
+0, 13, 13, 1, 921600, 0x9f127099
diff --git a/tests/ref/fate/dfa5 b/tests/ref/fate/dfa5
index b9f7727..3be3c52 100644
--- a/tests/ref/fate/dfa5
+++ b/tests/ref/fate/dfa5
@@ -1,16 +1,16 @@
#tb 0: 1/10
-0, 0, 0, 1, 192000, 0xc0941c10
-0, 1, 1, 1, 192000, 0xe2fe3ae5
-0, 2, 2, 1, 192000, 0x4a352d98
-0, 3, 3, 1, 192000, 0x7b78e0bb
-0, 4, 4, 1, 192000, 0x855c6675
-0, 5, 5, 1, 192000, 0xf443dad6
-0, 6, 6, 1, 192000, 0xe7e2a2e1
-0, 7, 7, 1, 192000, 0xa9009c58
-0, 8, 8, 1, 192000, 0x551855ab
-0, 9, 9, 1, 192000, 0x253908c7
-0, 10, 10, 1, 192000, 0x616213c4
-0, 11, 11, 1, 192000, 0xa381c3b1
-0, 12, 12, 1, 192000, 0xa2d64152
-0, 13, 13, 1, 192000, 0x34ed0f72
-0, 14, 14, 1, 192000, 0x05be63b4
+0, 0, 0, 1, 192000, 0x9754890f
+0, 1, 1, 1, 192000, 0x01668965
+0, 2, 2, 1, 192000, 0xbd1b5e12
+0, 3, 3, 1, 192000, 0x2e97fb9f
+0, 4, 4, 1, 192000, 0xf8b452e2
+0, 5, 5, 1, 192000, 0xc6859449
+0, 6, 6, 1, 192000, 0x910844f7
+0, 7, 7, 1, 192000, 0x99443581
+0, 8, 8, 1, 192000, 0xec52d1e5
+0, 9, 9, 1, 192000, 0x2fc66c35
+0, 10, 10, 1, 192000, 0xd9af7379
+0, 11, 11, 1, 192000, 0x947a26ef
+0, 12, 12, 1, 192000, 0x7b77ab28
+0, 13, 13, 1, 192000, 0x2507637e
+0, 14, 14, 1, 192000, 0x6ce8c0ea
diff --git a/tests/ref/fate/dfa6 b/tests/ref/fate/dfa6
index 92ed259..535f98b 100644
--- a/tests/ref/fate/dfa6
+++ b/tests/ref/fate/dfa6
@@ -1,13 +1,13 @@
#tb 0: 71/1000
-0, 0, 0, 1, 192000, 0x69f6a5f6
-0, 1, 1, 1, 192000, 0xc741d0a6
-0, 2, 2, 1, 192000, 0xba31e7a4
-0, 3, 3, 1, 192000, 0x7dc45080
-0, 4, 4, 1, 192000, 0x1c91dad5
-0, 5, 5, 1, 192000, 0x564b69b1
-0, 6, 6, 1, 192000, 0xdd9d9ae8
-0, 7, 7, 1, 192000, 0x605c05e1
-0, 8, 8, 1, 192000, 0xa5341ddb
-0, 9, 9, 1, 192000, 0x1ebff8ba
-0, 10, 10, 1, 192000, 0x240df237
-0, 11, 11, 1, 192000, 0xac641867
+0, 0, 0, 1, 192000, 0xb718dc63
+0, 1, 1, 1, 192000, 0x2efb7b89
+0, 2, 2, 1, 192000, 0x70827047
+0, 3, 3, 1, 192000, 0x61e1fd2f
+0, 4, 4, 1, 192000, 0x06f8bccd
+0, 5, 5, 1, 192000, 0xf0362404
+0, 6, 6, 1, 192000, 0xc00fc1b8
+0, 7, 7, 1, 192000, 0x94265476
+0, 8, 8, 1, 192000, 0x4b50ad23
+0, 9, 9, 1, 192000, 0x4d578b60
+0, 10, 10, 1, 192000, 0xfb14b875
+0, 11, 11, 1, 192000, 0x81682338
diff --git a/tests/ref/fate/dfa7 b/tests/ref/fate/dfa7
index 7dd40f2..28122c5 100644
--- a/tests/ref/fate/dfa7
+++ b/tests/ref/fate/dfa7
@@ -1,13 +1,13 @@
#tb 0: 71/1000
-0, 0, 0, 1, 7866, 0xa0056fdb
-0, 1, 1, 1, 7866, 0xed906c7a
-0, 2, 2, 1, 7866, 0x1c6e6f7d
-0, 3, 3, 1, 7866, 0xa2c460f7
-0, 4, 4, 1, 7866, 0xcf2166d4
-0, 5, 5, 1, 7866, 0xea545432
-0, 6, 6, 1, 7866, 0x604a5a9e
-0, 7, 7, 1, 7866, 0xbbc95c89
-0, 8, 8, 1, 7866, 0x80b16b5b
-0, 9, 9, 1, 7866, 0x9a1660ae
-0, 10, 10, 1, 7866, 0x6f886b10
-0, 11, 11, 1, 7866, 0xad8b5c99
+0, 0, 0, 1, 7866, 0xab73dae7
+0, 1, 1, 1, 7866, 0x100adec8
+0, 2, 2, 1, 7866, 0x1a20ddfa
+0, 3, 3, 1, 7866, 0xc358cd16
+0, 4, 4, 1, 7866, 0xee0bd20e
+0, 5, 5, 1, 7866, 0xef26bef9
+0, 6, 6, 1, 7866, 0xa9d0c755
+0, 7, 7, 1, 7866, 0x6c11cc7c
+0, 8, 8, 1, 7866, 0x4d6ed988
+0, 9, 9, 1, 7866, 0x9965cf24
+0, 10, 10, 1, 7866, 0x9a12db24
+0, 11, 11, 1, 7866, 0x2e85cfeb
diff --git a/tests/ref/fate/dfa8 b/tests/ref/fate/dfa8
index 39dde05..866260a 100644
--- a/tests/ref/fate/dfa8
+++ b/tests/ref/fate/dfa8
@@ -1,37 +1,37 @@
#tb 0: 71/1000
-0, 0, 0, 1, 134724, 0x2ab217de
-0, 1, 1, 1, 134724, 0xbf240f9a
-0, 2, 2, 1, 134724, 0x020a6010
-0, 3, 3, 1, 134724, 0x9a5f9374
-0, 4, 4, 1, 134724, 0x1e93a7e9
-0, 5, 5, 1, 134724, 0x9e4a4c55
-0, 6, 6, 1, 134724, 0x8f9d1bab
-0, 7, 7, 1, 134724, 0xb26ac45b
-0, 8, 8, 1, 134724, 0xc08706d2
-0, 9, 9, 1, 134724, 0x0806b031
-0, 10, 10, 1, 134724, 0x234dbb33
-0, 11, 11, 1, 134724, 0xe4cbfb2f
-0, 12, 12, 1, 134724, 0xf603f3fd
-0, 13, 13, 1, 134724, 0x205669d1
-0, 14, 14, 1, 134724, 0x7ddbb5e3
-0, 15, 15, 1, 134724, 0x8dfbb45a
-0, 16, 16, 1, 134724, 0x9632f681
-0, 17, 17, 1, 134724, 0x259e462c
-0, 18, 18, 1, 134724, 0x14f2bac1
-0, 19, 19, 1, 134724, 0xac3de7ed
-0, 20, 20, 1, 134724, 0x6b8af396
-0, 21, 21, 1, 134724, 0xd1e4bc1c
-0, 22, 22, 1, 134724, 0x716d1c73
-0, 23, 23, 1, 134724, 0x610956c8
-0, 24, 24, 1, 134724, 0x89ff8e86
-0, 25, 25, 1, 134724, 0xc3ea6b6f
-0, 26, 26, 1, 134724, 0x886688ef
-0, 27, 27, 1, 134724, 0xe60fc8c1
-0, 28, 28, 1, 134724, 0x22bd3131
-0, 29, 29, 1, 134724, 0xb1d74561
-0, 30, 30, 1, 134724, 0x61b069bc
-0, 31, 31, 1, 134724, 0x50b665c1
-0, 32, 32, 1, 134724, 0x027e5144
-0, 33, 33, 1, 134724, 0xfe0c31b4
-0, 34, 34, 1, 134724, 0x1e7a1f2d
-0, 35, 35, 1, 134724, 0x48bff03d
+0, 0, 0, 1, 134724, 0x53784ca9
+0, 1, 1, 1, 134724, 0x14c345b7
+0, 2, 2, 1, 134724, 0xe0d0dd51
+0, 3, 3, 1, 134724, 0xd53b5610
+0, 4, 4, 1, 134724, 0x7cbb8d47
+0, 5, 5, 1, 134724, 0x875d67c4
+0, 6, 6, 1, 134724, 0x9811c085
+0, 7, 7, 1, 134724, 0x25f6d228
+0, 8, 8, 1, 134724, 0x349495a0
+0, 9, 9, 1, 134724, 0xd0d75311
+0, 10, 10, 1, 134724, 0xb49cdfbb
+0, 11, 11, 1, 134724, 0x9fa69518
+0, 12, 12, 1, 134724, 0x28a1f58c
+0, 13, 13, 1, 134724, 0xb8dab657
+0, 14, 14, 1, 134724, 0x8c7e3b3b
+0, 15, 15, 1, 134724, 0x37268acf
+0, 16, 16, 1, 134724, 0xcce8ca02
+0, 17, 17, 1, 134724, 0xe0fd0c28
+0, 18, 18, 1, 134724, 0x5bdac906
+0, 19, 19, 1, 134724, 0xdd850bf0
+0, 20, 20, 1, 134724, 0x2002a228
+0, 21, 21, 1, 134724, 0x633617ea
+0, 22, 22, 1, 134724, 0x2a3ef337
+0, 23, 23, 1, 134724, 0x507886c3
+0, 24, 24, 1, 134724, 0x51c0f07b
+0, 25, 25, 1, 134724, 0x5e73dce1
+0, 26, 26, 1, 134724, 0x26acc6f0
+0, 27, 27, 1, 134724, 0x360c4349
+0, 28, 28, 1, 134724, 0xc7dbabd4
+0, 29, 29, 1, 134724, 0x671bbf66
+0, 30, 30, 1, 134724, 0x4d44df79
+0, 31, 31, 1, 134724, 0x69eade5b
+0, 32, 32, 1, 134724, 0x2b1bca82
+0, 33, 33, 1, 134724, 0x8b16af47
+0, 34, 34, 1, 134724, 0xb59fa1bd
+0, 35, 35, 1, 134724, 0x2ec17c24
diff --git a/tests/ref/fate/dfa9 b/tests/ref/fate/dfa9
index cf24e3e..99eb3f6 100644
--- a/tests/ref/fate/dfa9
+++ b/tests/ref/fate/dfa9
@@ -1,7 +1,7 @@
#tb 0: 71/1000
-0, 0, 0, 1, 228150, 0x188c6d9b
-0, 1, 1, 1, 228150, 0x658dbf2f
-0, 2, 2, 1, 228150, 0xc09a4b2e
-0, 3, 3, 1, 228150, 0x8777bc7d
-0, 4, 4, 1, 228150, 0xa388f0ce
-0, 5, 5, 1, 228150, 0x4e06666e
+0, 0, 0, 1, 228150, 0xde68df49
+0, 1, 1, 1, 228150, 0x8e12bcaf
+0, 2, 2, 1, 228150, 0x851b04f7
+0, 3, 3, 1, 228150, 0x7e5e0950
+0, 4, 4, 1, 228150, 0x1d92219f
+0, 5, 5, 1, 228150, 0x93caa693
diff --git a/tests/ref/fate/dirac b/tests/ref/fate/dirac
new file mode 100644
index 0000000..7781b4e
--- /dev/null
+++ b/tests/ref/fate/dirac
@@ -0,0 +1,3 @@
+#tb 0: 1/30
+0, 0, 0, 1, 115200, 0xf73819e8
+0, 1, 1, 1, 115200, 0x082e3788
diff --git a/tests/ref/fate/ea-cmv b/tests/ref/fate/ea-cmv
index 18f2b3a..8f9049e 100644
--- a/tests/ref/fate/ea-cmv
+++ b/tests/ref/fate/ea-cmv
@@ -1,195 +1,195 @@
#tb 0: 1/10
-0, 1, 1, 1, 120000, 0x34ac91d2
-0, 2, 2, 1, 120000, 0x17150729
-0, 3, 3, 1, 120000, 0xc3f510bb
-0, 4, 4, 1, 120000, 0xb3b14a3b
-0, 5, 5, 1, 120000, 0x26a7f3d1
-0, 6, 6, 1, 120000, 0xd161af6f
-0, 7, 7, 1, 120000, 0x459fc92d
-0, 8, 8, 1, 120000, 0x05c3fa94
-0, 9, 9, 1, 120000, 0x6630cd8c
-0, 10, 10, 1, 120000, 0x60cd39d4
-0, 11, 11, 1, 120000, 0xc8854d1c
-0, 12, 12, 1, 120000, 0xe55e8e6d
-0, 13, 13, 1, 120000, 0xbeab201f
-0, 14, 14, 1, 120000, 0x70744b0b
-0, 15, 15, 1, 120000, 0x80dea5d0
-0, 16, 16, 1, 120000, 0x769bfa1c
-0, 17, 17, 1, 120000, 0x04e25bbe
-0, 18, 18, 1, 120000, 0x48abc5a5
-0, 19, 19, 1, 120000, 0xda5c4e2a
-0, 20, 20, 1, 120000, 0x8de96d38
-0, 21, 21, 1, 120000, 0xe96418b0
-0, 22, 22, 1, 120000, 0x1c2f272b
-0, 23, 23, 1, 120000, 0x4b755804
-0, 24, 24, 1, 120000, 0xc92f96fd
-0, 25, 25, 1, 120000, 0x69e90ebb
-0, 26, 26, 1, 120000, 0x78d4bd1a
-0, 27, 27, 1, 120000, 0xaf2edf55
-0, 28, 28, 1, 120000, 0x94161c78
-0, 29, 29, 1, 120000, 0x1109094d
-0, 30, 30, 1, 120000, 0xc61b0392
-0, 31, 31, 1, 120000, 0xc157d003
-0, 32, 32, 1, 120000, 0xf2747e7b
-0, 33, 33, 1, 120000, 0xa36299c2
-0, 34, 34, 1, 120000, 0x49bc788c
-0, 35, 35, 1, 120000, 0x3bee336e
-0, 36, 36, 1, 120000, 0xa316b9d1
-0, 37, 37, 1, 120000, 0x5cc32e9c
-0, 38, 38, 1, 120000, 0x9f7eca16
-0, 39, 39, 1, 120000, 0x958e2988
-0, 40, 40, 1, 120000, 0xebcba2f1
-0, 41, 41, 1, 120000, 0x281f1e60
-0, 42, 42, 1, 120000, 0x82256c4d
-0, 43, 43, 1, 120000, 0xddc8be56
-0, 44, 44, 1, 120000, 0x64ff2ed0
-0, 45, 45, 1, 120000, 0x3e63ab02
-0, 46, 46, 1, 120000, 0x43f78b37
-0, 47, 47, 1, 120000, 0xb7cc62d4
-0, 48, 48, 1, 120000, 0x694f1764
-0, 49, 49, 1, 120000, 0x2264c483
-0, 51, 51, 1, 120000, 0xb6680b4a
-0, 52, 52, 1, 120000, 0x2a92626a
-0, 53, 53, 1, 120000, 0x8da02509
-0, 54, 54, 1, 120000, 0xa976c382
-0, 55, 55, 1, 120000, 0x749e822b
-0, 56, 56, 1, 120000, 0xe9e7fc8c
-0, 57, 57, 1, 120000, 0xfdc05a0c
-0, 58, 58, 1, 120000, 0x7d5a856d
-0, 59, 59, 1, 120000, 0xcc344937
-0, 60, 60, 1, 120000, 0x9d90bc67
-0, 61, 61, 1, 120000, 0x3f527712
-0, 62, 62, 1, 120000, 0xf0f57f97
-0, 63, 63, 1, 120000, 0xc29535cd
-0, 64, 64, 1, 120000, 0x9a64598b
-0, 65, 65, 1, 120000, 0x0d1ddf7c
-0, 66, 66, 1, 120000, 0xb580ec24
-0, 67, 67, 1, 120000, 0xf0db5bbc
-0, 68, 68, 1, 120000, 0x6b980b61
-0, 69, 69, 1, 120000, 0xc29f30b5
-0, 70, 70, 1, 120000, 0xaf2c4bcd
-0, 71, 71, 1, 120000, 0x1e725645
-0, 72, 72, 1, 120000, 0x295c4c96
-0, 73, 73, 1, 120000, 0x7ea121a2
-0, 74, 74, 1, 120000, 0xdb9e9cec
-0, 75, 75, 1, 120000, 0x1da47c80
-0, 76, 76, 1, 120000, 0x9d0c1345
-0, 77, 77, 1, 120000, 0x88058527
-0, 78, 78, 1, 120000, 0x46766aed
-0, 79, 79, 1, 120000, 0xba520bd3
-0, 80, 80, 1, 120000, 0x7fb6373c
-0, 81, 81, 1, 120000, 0x05a86f4d
-0, 82, 82, 1, 120000, 0x7fb47cbd
-0, 83, 83, 1, 120000, 0x6814d8ca
-0, 84, 84, 1, 120000, 0x9c13acb8
-0, 85, 85, 1, 120000, 0xad0edbfe
-0, 86, 86, 1, 120000, 0x352fde81
-0, 87, 87, 1, 120000, 0xa654b386
-0, 88, 88, 1, 120000, 0xd3b3dc72
-0, 89, 89, 1, 120000, 0x01572668
-0, 90, 90, 1, 120000, 0x30189e03
-0, 91, 91, 1, 120000, 0x26126d30
-0, 92, 92, 1, 120000, 0x4f376c7d
-0, 93, 93, 1, 120000, 0xd3667bcf
-0, 94, 94, 1, 120000, 0x0b46b3d5
-0, 95, 95, 1, 120000, 0x893415ef
-0, 96, 96, 1, 120000, 0x99a78749
-0, 97, 97, 1, 120000, 0x6da0d8e9
-0, 98, 98, 1, 120000, 0x22d8ceb6
-0, 99, 99, 1, 120000, 0x67ef9be8
-0, 100, 100, 1, 120000, 0xb696fb53
-0, 101, 101, 1, 120000, 0x70339dab
-0, 102, 102, 1, 120000, 0xc1876efa
-0, 103, 103, 1, 120000, 0x80e78c92
-0, 104, 104, 1, 120000, 0x18d2f2ac
-0, 105, 105, 1, 120000, 0x28be9ae4
-0, 106, 106, 1, 120000, 0xc3c2c190
-0, 107, 107, 1, 120000, 0xd6a859d8
-0, 108, 108, 1, 120000, 0x40b9046d
-0, 109, 109, 1, 120000, 0x7f8d5999
-0, 110, 110, 1, 120000, 0x89724027
-0, 111, 111, 1, 120000, 0x4c15c988
-0, 112, 112, 1, 120000, 0x812ebe08
-0, 113, 113, 1, 120000, 0x273ef8e2
-0, 114, 114, 1, 120000, 0xe029de06
-0, 115, 115, 1, 120000, 0x5846127c
-0, 116, 116, 1, 120000, 0x6c5df8e3
-0, 117, 117, 1, 120000, 0x7424919f
-0, 118, 118, 1, 120000, 0xa8313015
-0, 119, 119, 1, 120000, 0x28878ab4
-0, 120, 120, 1, 120000, 0x126d0746
-0, 121, 121, 1, 120000, 0xee3f7138
-0, 122, 122, 1, 120000, 0xd4b2e0a1
-0, 123, 123, 1, 120000, 0x8d60bfff
-0, 124, 124, 1, 120000, 0x701c23d0
-0, 125, 125, 1, 120000, 0x1cbb5654
-0, 126, 126, 1, 120000, 0x0f5853e9
-0, 127, 127, 1, 120000, 0x2a5c3339
-0, 128, 128, 1, 120000, 0x86b00350
-0, 129, 129, 1, 120000, 0xe8cc6931
-0, 130, 130, 1, 120000, 0xf1cad983
-0, 131, 131, 1, 120000, 0xabcd8704
-0, 132, 132, 1, 120000, 0x89592f94
-0, 133, 133, 1, 120000, 0x100486d9
-0, 134, 134, 1, 120000, 0x60ef9e2d
-0, 135, 135, 1, 120000, 0x2485176a
-0, 136, 136, 1, 120000, 0x6b8c360d
-0, 137, 137, 1, 120000, 0xe2e1bf4f
-0, 138, 138, 1, 120000, 0xe17b65c3
-0, 139, 139, 1, 120000, 0x2a42821a
-0, 140, 140, 1, 120000, 0xbe9ddba7
-0, 141, 141, 1, 120000, 0x19f937fe
-0, 142, 142, 1, 120000, 0xb7e0c600
-0, 143, 143, 1, 120000, 0xfbf8c5f6
-0, 144, 144, 1, 120000, 0x93b62f93
-0, 145, 145, 1, 120000, 0xb6ddec93
-0, 146, 146, 1, 120000, 0xa04d031b
-0, 147, 147, 1, 120000, 0x61c986c0
-0, 148, 148, 1, 120000, 0x3516e54a
-0, 149, 149, 1, 120000, 0x3489eb2c
-0, 150, 150, 1, 120000, 0xb75a4827
-0, 151, 151, 1, 120000, 0x76031a80
-0, 152, 152, 1, 120000, 0x867c3969
-0, 153, 153, 1, 120000, 0x9b63a093
-0, 154, 154, 1, 120000, 0xcb253d8a
-0, 155, 155, 1, 120000, 0x354ba3b2
-0, 156, 156, 1, 120000, 0x4d5ead8c
-0, 157, 157, 1, 120000, 0x7b7029ae
-0, 158, 158, 1, 120000, 0x4765ab9d
-0, 159, 159, 1, 120000, 0x747cdee9
-0, 160, 160, 1, 120000, 0x20989b08
-0, 161, 161, 1, 120000, 0x3a957085
-0, 162, 162, 1, 120000, 0xdd49e8ad
-0, 163, 163, 1, 120000, 0x00e89719
-0, 164, 164, 1, 120000, 0x2822aa76
-0, 165, 165, 1, 120000, 0x492388f3
-0, 166, 166, 1, 120000, 0x4dffa6ee
-0, 167, 167, 1, 120000, 0xc382bb83
-0, 168, 168, 1, 120000, 0xb59aaa74
-0, 169, 169, 1, 120000, 0x7c7885d3
-0, 170, 170, 1, 120000, 0xc05ee219
-0, 171, 171, 1, 120000, 0xc3df6b73
-0, 172, 172, 1, 120000, 0x8ae31170
-0, 173, 173, 1, 120000, 0xb979fdce
-0, 174, 174, 1, 120000, 0xb8f9e407
-0, 175, 175, 1, 120000, 0x56675b80
-0, 176, 176, 1, 120000, 0x1aad1ce2
-0, 177, 177, 1, 120000, 0xa050a52b
-0, 178, 178, 1, 120000, 0x49f8c32f
-0, 179, 179, 1, 120000, 0x8e7f4d2c
-0, 180, 180, 1, 120000, 0x5c07f751
-0, 181, 181, 1, 120000, 0x67fa5523
-0, 182, 182, 1, 120000, 0xf38b933a
-0, 183, 183, 1, 120000, 0xb113e202
-0, 184, 184, 1, 120000, 0xb8d99ff4
-0, 185, 185, 1, 120000, 0x15ab6cc6
-0, 186, 186, 1, 120000, 0xd64a51c9
-0, 187, 187, 1, 120000, 0x2088b53c
-0, 188, 188, 1, 120000, 0xdd78d40a
-0, 189, 189, 1, 120000, 0x2fb58848
-0, 190, 190, 1, 120000, 0xf775d36a
-0, 191, 191, 1, 120000, 0xa03987e9
-0, 192, 192, 1, 120000, 0x457322ad
-0, 193, 193, 1, 120000, 0x0f6c3d1c
-0, 194, 194, 1, 120000, 0xbdf2f1a5
-0, 195, 195, 1, 120000, 0x5828ee1d
+0, 0, 0, 1, 120000, 0x34ac91d2
+0, 1, 1, 1, 120000, 0x17150729
+0, 2, 2, 1, 120000, 0xc3f510bb
+0, 3, 3, 1, 120000, 0xb3b14a3b
+0, 4, 4, 1, 120000, 0x26a7f3d1
+0, 5, 5, 1, 120000, 0xd161af6f
+0, 6, 6, 1, 120000, 0x459fc92d
+0, 7, 7, 1, 120000, 0x05c3fa94
+0, 8, 8, 1, 120000, 0x6630cd8c
+0, 9, 9, 1, 120000, 0x60cd39d4
+0, 10, 10, 1, 120000, 0xc8854d1c
+0, 11, 11, 1, 120000, 0xe55e8e6d
+0, 12, 12, 1, 120000, 0xbeab201f
+0, 13, 13, 1, 120000, 0x70744b0b
+0, 14, 14, 1, 120000, 0x80dea5d0
+0, 15, 15, 1, 120000, 0x769bfa1c
+0, 16, 16, 1, 120000, 0x04e25bbe
+0, 17, 17, 1, 120000, 0x48abc5a5
+0, 18, 18, 1, 120000, 0xda5c4e2a
+0, 19, 19, 1, 120000, 0x8de96d38
+0, 20, 20, 1, 120000, 0xe96418b0
+0, 21, 21, 1, 120000, 0x1c2f272b
+0, 22, 22, 1, 120000, 0x4b755804
+0, 23, 23, 1, 120000, 0xc92f96fd
+0, 24, 24, 1, 120000, 0x69e90ebb
+0, 25, 25, 1, 120000, 0x78d4bd1a
+0, 26, 26, 1, 120000, 0xaf2edf55
+0, 27, 27, 1, 120000, 0x94161c78
+0, 28, 28, 1, 120000, 0x1109094d
+0, 29, 29, 1, 120000, 0xc61b0392
+0, 30, 30, 1, 120000, 0xc157d003
+0, 31, 31, 1, 120000, 0xf2747e7b
+0, 32, 32, 1, 120000, 0xa36299c2
+0, 33, 33, 1, 120000, 0x49bc788c
+0, 34, 34, 1, 120000, 0x3bee336e
+0, 35, 35, 1, 120000, 0xa316b9d1
+0, 36, 36, 1, 120000, 0x5cc32e9c
+0, 37, 37, 1, 120000, 0x9f7eca16
+0, 38, 38, 1, 120000, 0x958e2988
+0, 39, 39, 1, 120000, 0xebcba2f1
+0, 40, 40, 1, 120000, 0x281f1e60
+0, 41, 41, 1, 120000, 0x82256c4d
+0, 42, 42, 1, 120000, 0xddc8be56
+0, 43, 43, 1, 120000, 0x64ff2ed0
+0, 44, 44, 1, 120000, 0x3e63ab02
+0, 45, 45, 1, 120000, 0x43f78b37
+0, 46, 46, 1, 120000, 0xb7cc62d4
+0, 47, 47, 1, 120000, 0x694f1764
+0, 48, 48, 1, 120000, 0x2264c483
+0, 49, 49, 1, 120000, 0xb6680b4a
+0, 50, 50, 1, 120000, 0x2a92626a
+0, 51, 51, 1, 120000, 0x8da02509
+0, 52, 52, 1, 120000, 0xa976c382
+0, 53, 53, 1, 120000, 0x749e822b
+0, 54, 54, 1, 120000, 0xe9e7fc8c
+0, 55, 55, 1, 120000, 0xfdc05a0c
+0, 56, 56, 1, 120000, 0x7d5a856d
+0, 57, 57, 1, 120000, 0xcc344937
+0, 58, 58, 1, 120000, 0x9d90bc67
+0, 59, 59, 1, 120000, 0x3f527712
+0, 60, 60, 1, 120000, 0xf0f57f97
+0, 61, 61, 1, 120000, 0xc29535cd
+0, 62, 62, 1, 120000, 0x9a64598b
+0, 63, 63, 1, 120000, 0x0d1ddf7c
+0, 64, 64, 1, 120000, 0xb580ec24
+0, 65, 65, 1, 120000, 0xf0db5bbc
+0, 66, 66, 1, 120000, 0x6b980b61
+0, 67, 67, 1, 120000, 0xc29f30b5
+0, 68, 68, 1, 120000, 0xaf2c4bcd
+0, 69, 69, 1, 120000, 0x1e725645
+0, 70, 70, 1, 120000, 0x295c4c96
+0, 71, 71, 1, 120000, 0x7ea121a2
+0, 72, 72, 1, 120000, 0xdb9e9cec
+0, 73, 73, 1, 120000, 0x1da47c80
+0, 74, 74, 1, 120000, 0x9d0c1345
+0, 75, 75, 1, 120000, 0x88058527
+0, 76, 76, 1, 120000, 0x46766aed
+0, 77, 77, 1, 120000, 0xba520bd3
+0, 78, 78, 1, 120000, 0x7fb6373c
+0, 79, 79, 1, 120000, 0x05a86f4d
+0, 80, 80, 1, 120000, 0x7fb47cbd
+0, 81, 81, 1, 120000, 0x6814d8ca
+0, 82, 82, 1, 120000, 0x9c13acb8
+0, 83, 83, 1, 120000, 0xad0edbfe
+0, 84, 84, 1, 120000, 0x352fde81
+0, 85, 85, 1, 120000, 0xa654b386
+0, 86, 86, 1, 120000, 0xd3b3dc72
+0, 87, 87, 1, 120000, 0x01572668
+0, 88, 88, 1, 120000, 0x30189e03
+0, 89, 89, 1, 120000, 0x26126d30
+0, 90, 90, 1, 120000, 0x4f376c7d
+0, 91, 91, 1, 120000, 0xd3667bcf
+0, 92, 92, 1, 120000, 0x0b46b3d5
+0, 93, 93, 1, 120000, 0x893415ef
+0, 94, 94, 1, 120000, 0x99a78749
+0, 95, 95, 1, 120000, 0x6da0d8e9
+0, 96, 96, 1, 120000, 0x22d8ceb6
+0, 97, 97, 1, 120000, 0x67ef9be8
+0, 98, 98, 1, 120000, 0xb696fb53
+0, 99, 99, 1, 120000, 0x70339dab
+0, 100, 100, 1, 120000, 0xc1876efa
+0, 101, 101, 1, 120000, 0x80e78c92
+0, 102, 102, 1, 120000, 0x18d2f2ac
+0, 103, 103, 1, 120000, 0x28be9ae4
+0, 104, 104, 1, 120000, 0xc3c2c190
+0, 105, 105, 1, 120000, 0xd6a859d8
+0, 106, 106, 1, 120000, 0x40b9046d
+0, 107, 107, 1, 120000, 0x7f8d5999
+0, 108, 108, 1, 120000, 0x89724027
+0, 109, 109, 1, 120000, 0x4c15c988
+0, 110, 110, 1, 120000, 0x812ebe08
+0, 111, 111, 1, 120000, 0x273ef8e2
+0, 112, 112, 1, 120000, 0xe029de06
+0, 113, 113, 1, 120000, 0x5846127c
+0, 114, 114, 1, 120000, 0x6c5df8e3
+0, 115, 115, 1, 120000, 0x7424919f
+0, 116, 116, 1, 120000, 0xa8313015
+0, 117, 117, 1, 120000, 0x28878ab4
+0, 118, 118, 1, 120000, 0x126d0746
+0, 119, 119, 1, 120000, 0xee3f7138
+0, 120, 120, 1, 120000, 0xd4b2e0a1
+0, 121, 121, 1, 120000, 0x8d60bfff
+0, 122, 122, 1, 120000, 0x701c23d0
+0, 123, 123, 1, 120000, 0x1cbb5654
+0, 124, 124, 1, 120000, 0x0f5853e9
+0, 125, 125, 1, 120000, 0x2a5c3339
+0, 126, 126, 1, 120000, 0x86b00350
+0, 127, 127, 1, 120000, 0xe8cc6931
+0, 128, 128, 1, 120000, 0xf1cad983
+0, 129, 129, 1, 120000, 0xabcd8704
+0, 130, 130, 1, 120000, 0x89592f94
+0, 131, 131, 1, 120000, 0x100486d9
+0, 132, 132, 1, 120000, 0x60ef9e2d
+0, 133, 133, 1, 120000, 0x2485176a
+0, 134, 134, 1, 120000, 0x6b8c360d
+0, 135, 135, 1, 120000, 0xe2e1bf4f
+0, 136, 136, 1, 120000, 0xe17b65c3
+0, 137, 137, 1, 120000, 0x2a42821a
+0, 138, 138, 1, 120000, 0xbe9ddba7
+0, 139, 139, 1, 120000, 0x19f937fe
+0, 140, 140, 1, 120000, 0xb7e0c600
+0, 141, 141, 1, 120000, 0xfbf8c5f6
+0, 142, 142, 1, 120000, 0x93b62f93
+0, 143, 143, 1, 120000, 0xb6ddec93
+0, 144, 144, 1, 120000, 0xa04d031b
+0, 145, 145, 1, 120000, 0x61c986c0
+0, 146, 146, 1, 120000, 0x3516e54a
+0, 147, 147, 1, 120000, 0x3489eb2c
+0, 148, 148, 1, 120000, 0xb75a4827
+0, 149, 149, 1, 120000, 0x76031a80
+0, 150, 150, 1, 120000, 0x867c3969
+0, 151, 151, 1, 120000, 0x9b63a093
+0, 152, 152, 1, 120000, 0xcb253d8a
+0, 153, 153, 1, 120000, 0x354ba3b2
+0, 154, 154, 1, 120000, 0x4d5ead8c
+0, 155, 155, 1, 120000, 0x7b7029ae
+0, 156, 156, 1, 120000, 0x4765ab9d
+0, 157, 157, 1, 120000, 0x747cdee9
+0, 158, 158, 1, 120000, 0x20989b08
+0, 159, 159, 1, 120000, 0x3a957085
+0, 160, 160, 1, 120000, 0xdd49e8ad
+0, 161, 161, 1, 120000, 0x00e89719
+0, 162, 162, 1, 120000, 0x2822aa76
+0, 163, 163, 1, 120000, 0x492388f3
+0, 164, 164, 1, 120000, 0x4dffa6ee
+0, 165, 165, 1, 120000, 0xc382bb83
+0, 166, 166, 1, 120000, 0xb59aaa74
+0, 167, 167, 1, 120000, 0x7c7885d3
+0, 168, 168, 1, 120000, 0xc05ee219
+0, 169, 169, 1, 120000, 0xc3df6b73
+0, 170, 170, 1, 120000, 0x8ae31170
+0, 171, 171, 1, 120000, 0xb979fdce
+0, 172, 172, 1, 120000, 0xb8f9e407
+0, 173, 173, 1, 120000, 0x56675b80
+0, 174, 174, 1, 120000, 0x1aad1ce2
+0, 175, 175, 1, 120000, 0xa050a52b
+0, 176, 176, 1, 120000, 0x49f8c32f
+0, 177, 177, 1, 120000, 0x8e7f4d2c
+0, 178, 178, 1, 120000, 0x5c07f751
+0, 179, 179, 1, 120000, 0x67fa5523
+0, 180, 180, 1, 120000, 0xf38b933a
+0, 181, 181, 1, 120000, 0xb113e202
+0, 182, 182, 1, 120000, 0xb8d99ff4
+0, 183, 183, 1, 120000, 0x15ab6cc6
+0, 184, 184, 1, 120000, 0xd64a51c9
+0, 185, 185, 1, 120000, 0x2088b53c
+0, 186, 186, 1, 120000, 0xdd78d40a
+0, 187, 187, 1, 120000, 0x2fb58848
+0, 188, 188, 1, 120000, 0xf775d36a
+0, 189, 189, 1, 120000, 0xa03987e9
+0, 190, 190, 1, 120000, 0x457322ad
+0, 191, 191, 1, 120000, 0x0f6c3d1c
+0, 192, 192, 1, 120000, 0xbdf2f1a5
+0, 193, 193, 1, 120000, 0x5828ee1d
diff --git a/tests/ref/fate/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/exr-slice-raw b/tests/ref/fate/exr-slice-raw
new file mode 100644
index 0000000..a8b4b27
--- /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
--- /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
--- /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
--- /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
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-filter_complex
@@ -0,0 +1,6 @@
+#tb 0: 1/5
+0, 0, 0, 1, 115200, 0x375ec573
+0, 1, 1, 1, 115200, 0x375ec573
+0, 2, 2, 1, 115200, 0x375ec573
+0, 3, 3, 1, 115200, 0x375ec573
+0, 4, 4, 1, 115200, 0x375ec573
diff --git a/tests/ref/fate/ffmpeg-lavfi b/tests/ref/fate/ffmpeg-lavfi
new file mode 100644
index 0000000..54d318d
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-lavfi
@@ -0,0 +1,6 @@
+#tb 0: 1/5
+0, 0, 0, 1, 115200, 0x375ec573
+0, 1, 1, 1, 115200, 0x375ec573
+0, 2, 2, 1, 115200, 0x375ec573
+0, 3, 3, 1, 115200, 0x375ec573
+0, 4, 4, 1, 115200, 0x375ec573
diff --git a/tests/ref/fate/ffprobe_compact b/tests/ref/fate/ffprobe_compact
new file mode 100644
index 0000000..409ac9c
--- /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|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|format_name=nut|start_time=0.000000|duration=0.120000|size=1054812|bit_rate=70320800|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..0094c39
--- /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,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,nut,0.000000,0.120000,1054812,70320800,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..9f523fd
--- /dev/null
+++ b/tests/ref/fate/ffprobe_default
@@ -0,0 +1,613 @@
+[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
+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
+format_name=nut
+start_time=0.000000
+duration=0.120000
+size=1054812
+bit_rate=70320800
+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..c08ca0f
--- /dev/null
+++ b/tests/ref/fate/ffprobe_flat
@@ -0,0 +1,549 @@
+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.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.format_name="nut"
+format.start_time="0.000000"
+format.duration="0.120000"
+format.size="1054812"
+format.bit_rate="70320800"
+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..1bc46d0
--- /dev/null
+++ b/tests/ref/fate/ffprobe_ini
@@ -0,0 +1,626 @@
+# 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
+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
+format_name=nut
+start_time=0.000000
+duration=0.120000
+size=1054812
+bit_rate=70320800
+
+[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..fc3d22e
--- /dev/null
+++ b/tests/ref/fate/ffprobe_json
@@ -0,0 +1,598 @@
+{
+ "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,
+ "format_name": "nut",
+ "start_time": "0.000000",
+ "duration": "0.120000",
+ "size": "1054812",
+ "bit_rate": "70320800",
+ "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..1f2715a
--- /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" format_name="nut" start_time="0.000000" duration="0.120000" size="1054812" bit_rate="70320800">
+ <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-alphaextract_alphamerge_rgb b/tests/ref/fate/filter-alphaextract_alphamerge_rgb
new file mode 100644
index 0000000..b28c037
--- /dev/null
+++ b/tests/ref/fate/filter-alphaextract_alphamerge_rgb
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 405504, 0x42f434a6
+0, 1, 1, 1, 405504, 0x9e7eb468
+0, 2, 2, 1, 405504, 0xcad920cc
+0, 3, 3, 1, 405504, 0x0c079acb
+0, 4, 4, 1, 405504, 0xf31cbd03
+0, 5, 5, 1, 405504, 0x19eb3488
+0, 6, 6, 1, 405504, 0x5aafdb12
+0, 7, 7, 1, 405504, 0xc0018f08
+0, 8, 8, 1, 405504, 0x2e4df8b1
+0, 9, 9, 1, 405504, 0xd7b7abe0
+0, 10, 10, 1, 405504, 0xa4525378
+0, 11, 11, 1, 405504, 0x5752931e
+0, 12, 12, 1, 405504, 0xaf53d44c
+0, 13, 13, 1, 405504, 0xedfdd248
+0, 14, 14, 1, 405504, 0xac8b7d5c
+0, 15, 15, 1, 405504, 0x118b95ef
+0, 16, 16, 1, 405504, 0xa7635fe9
+0, 17, 17, 1, 405504, 0x457d1492
+0, 18, 18, 1, 405504, 0x4695141c
+0, 19, 19, 1, 405504, 0xfe29184f
+0, 20, 20, 1, 405504, 0xcdaa6f1d
+0, 21, 21, 1, 405504, 0xe69739ae
+0, 22, 22, 1, 405504, 0x06e01db7
+0, 23, 23, 1, 405504, 0xdecb4fcf
+0, 24, 24, 1, 405504, 0xae6faec7
+0, 25, 25, 1, 405504, 0x43ba1609
+0, 26, 26, 1, 405504, 0xb6280a41
+0, 27, 27, 1, 405504, 0xf8604f4a
+0, 28, 28, 1, 405504, 0x36874db6
+0, 29, 29, 1, 405504, 0x66bed0d7
+0, 30, 30, 1, 405504, 0x136b1d8f
+0, 31, 31, 1, 405504, 0x5b740a9b
+0, 32, 32, 1, 405504, 0x02617fc5
+0, 33, 33, 1, 405504, 0x12819730
+0, 34, 34, 1, 405504, 0xc3f8377b
+0, 35, 35, 1, 405504, 0x8b8f9c97
+0, 36, 36, 1, 405504, 0xf08f9cee
+0, 37, 37, 1, 405504, 0x19e16387
+0, 38, 38, 1, 405504, 0x976601a1
+0, 39, 39, 1, 405504, 0xa8350aa5
+0, 40, 40, 1, 405504, 0x671d2f83
+0, 41, 41, 1, 405504, 0xfd3c4a1d
+0, 42, 42, 1, 405504, 0x9074f9ee
+0, 43, 43, 1, 405504, 0x132fa190
+0, 44, 44, 1, 405504, 0x8e3c229d
+0, 45, 45, 1, 405504, 0x8202aee0
+0, 46, 46, 1, 405504, 0x5d5adf1a
+0, 47, 47, 1, 405504, 0x4e03a394
+0, 48, 48, 1, 405504, 0xbae3ee9e
+0, 49, 49, 1, 405504, 0x28f290fe
diff --git a/tests/ref/fate/filter-alphaextract_alphamerge_yuv b/tests/ref/fate/filter-alphaextract_alphamerge_yuv
new file mode 100644
index 0000000..9285cef
--- /dev/null
+++ b/tests/ref/fate/filter-alphaextract_alphamerge_yuv
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 253440, 0x9022e010
+0, 1, 1, 1, 253440, 0x97dba833
+0, 2, 2, 1, 253440, 0x7f24bea0
+0, 3, 3, 1, 253440, 0x7cfd0cde
+0, 4, 4, 1, 253440, 0x14eda178
+0, 5, 5, 1, 253440, 0x7fe9349b
+0, 6, 6, 1, 253440, 0x4833e264
+0, 7, 7, 1, 253440, 0x350513b1
+0, 8, 8, 1, 253440, 0xd226079b
+0, 9, 9, 1, 253440, 0xced95e1a
+0, 10, 10, 1, 253440, 0xb8d4245d
+0, 11, 11, 1, 253440, 0x60ae8c55
+0, 12, 12, 1, 253440, 0x4edd6b42
+0, 13, 13, 1, 253440, 0x13fb471a
+0, 14, 14, 1, 253440, 0x2d8f1578
+0, 15, 15, 1, 253440, 0x1d16012b
+0, 16, 16, 1, 253440, 0x6c19b661
+0, 17, 17, 1, 253440, 0x402d916a
+0, 18, 18, 1, 253440, 0x1dd4a963
+0, 19, 19, 1, 253440, 0x221ee04d
+0, 20, 20, 1, 253440, 0xb069c690
+0, 21, 21, 1, 253440, 0xb5ef43fd
+0, 22, 22, 1, 253440, 0x602115eb
+0, 23, 23, 1, 253440, 0x1467aed9
+0, 24, 24, 1, 253440, 0x37680a1c
+0, 25, 25, 1, 253440, 0x3fa825d5
+0, 26, 26, 1, 253440, 0xfb0b654a
+0, 27, 27, 1, 253440, 0x0cea074b
+0, 28, 28, 1, 253440, 0xdb20b79a
+0, 29, 29, 1, 253440, 0xb08848f0
+0, 30, 30, 1, 253440, 0xa06d6774
+0, 31, 31, 1, 253440, 0x452d1ba3
+0, 32, 32, 1, 253440, 0x96bea378
+0, 33, 33, 1, 253440, 0x16b5a370
+0, 34, 34, 1, 253440, 0x433b9208
+0, 35, 35, 1, 253440, 0x1f475d36
+0, 36, 36, 1, 253440, 0x66dc3561
+0, 37, 37, 1, 253440, 0x7edadddd
+0, 38, 38, 1, 253440, 0xf6fc858a
+0, 39, 39, 1, 253440, 0xf1f369d8
+0, 40, 40, 1, 253440, 0x3877f958
+0, 41, 41, 1, 253440, 0x22ef4692
+0, 42, 42, 1, 253440, 0x6ff4614a
+0, 43, 43, 1, 253440, 0x49712513
+0, 44, 44, 1, 253440, 0x438213e5
+0, 45, 45, 1, 253440, 0x54da2895
+0, 46, 46, 1, 253440, 0xb478205e
+0, 47, 47, 1, 253440, 0xffcfe69a
+0, 48, 48, 1, 253440, 0x1639fafd
+0, 49, 49, 1, 253440, 0x59d18f46
diff --git a/tests/ref/fate/filter-colorchannelmixer b/tests/ref/fate/filter-colorchannelmixer
new file mode 100644
index 0000000..4e9e9d3
--- /dev/null
+++ b/tests/ref/fate/filter-colorchannelmixer
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 304128, 0x42900c13
+0, 1, 1, 1, 304128, 0xfb0439bc
+0, 2, 2, 1, 304128, 0x967b9f0d
+0, 3, 3, 1, 304128, 0xc2c92489
+0, 4, 4, 1, 304128, 0x024499b1
+0, 5, 5, 1, 304128, 0x66144785
+0, 6, 6, 1, 304128, 0x0e505bcd
+0, 7, 7, 1, 304128, 0xc8b26ed2
+0, 8, 8, 1, 304128, 0x14b5717b
+0, 9, 9, 1, 304128, 0x2ba3144a
+0, 10, 10, 1, 304128, 0x1185992b
+0, 11, 11, 1, 304128, 0xd55b289a
+0, 12, 12, 1, 304128, 0x59f2f3be
+0, 13, 13, 1, 304128, 0xfe4d6adf
+0, 14, 14, 1, 304128, 0x630806cc
+0, 15, 15, 1, 304128, 0x2deb2f19
+0, 16, 16, 1, 304128, 0xfbffa923
+0, 17, 17, 1, 304128, 0xb7770d46
+0, 18, 18, 1, 304128, 0xda09bd0e
+0, 19, 19, 1, 304128, 0x17a422d2
+0, 20, 20, 1, 304128, 0xbb6172f5
+0, 21, 21, 1, 304128, 0xcf639456
+0, 22, 22, 1, 304128, 0xdb0ae1ac
+0, 23, 23, 1, 304128, 0x850d6a68
+0, 24, 24, 1, 304128, 0xdc8409fb
+0, 25, 25, 1, 304128, 0x26216c51
+0, 26, 26, 1, 304128, 0x1d0004de
+0, 27, 27, 1, 304128, 0xed019a70
+0, 28, 28, 1, 304128, 0xb1abd985
+0, 29, 29, 1, 304128, 0xec1c14b2
+0, 30, 30, 1, 304128, 0x046db068
+0, 31, 31, 1, 304128, 0xa4fb1029
+0, 32, 32, 1, 304128, 0x49e05e61
+0, 33, 33, 1, 304128, 0x7668d6d1
+0, 34, 34, 1, 304128, 0x6dd0ce9d
+0, 35, 35, 1, 304128, 0x87983f5e
+0, 36, 36, 1, 304128, 0xb98278cf
+0, 37, 37, 1, 304128, 0x55186244
+0, 38, 38, 1, 304128, 0x3135e7ea
+0, 39, 39, 1, 304128, 0xdbf59a2c
+0, 40, 40, 1, 304128, 0x944cdc92
+0, 41, 41, 1, 304128, 0x5849dfe8
+0, 42, 42, 1, 304128, 0xaf9075ba
+0, 43, 43, 1, 304128, 0xb4f01118
+0, 44, 44, 1, 304128, 0x4dfb711f
+0, 45, 45, 1, 304128, 0xb558e732
+0, 46, 46, 1, 304128, 0xb23a171e
+0, 47, 47, 1, 304128, 0xb5c68065
+0, 48, 48, 1, 304128, 0xcf1b122e
+0, 49, 49, 1, 304128, 0x1e2d38e5
diff --git a/tests/ref/fate/filter-colormatrix1 b/tests/ref/fate/filter-colormatrix1
new file mode 100644
index 0000000..9ec093d
--- /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
--- /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
--- /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
--- /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..bc58777 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, 0x689de87e
+0, 1, 1, 1, 126720, 0x3db9e91c
+0, 2, 2, 1, 126720, 0x3db9e91c
+0, 3, 3, 1, 126720, 0x3db9e91c
+0, 4, 4, 1, 126720, 0xfa6ae95e
+0, 5, 5, 1, 126720, 0x5bcbf0e6
+0, 6, 6, 1, 126720, 0x94a0f126
+0, 7, 7, 1, 126720, 0x0250f106
+0, 8, 8, 1, 126720, 0xcf6ab4bc
+0, 9, 9, 1, 126720, 0x429eb57c
+0, 10, 10, 1, 126720, 0x3bf0b5bc
+0, 11, 11, 1, 126720, 0xcaedb591
+0, 12, 12, 1, 126720, 0xa492b5ec
+0, 13, 13, 1, 126720, 0x2431b85c
+0, 14, 14, 1, 126720, 0x8283b8dc
+0, 15, 15, 1, 126720, 0xd71bb871
+0, 16, 16, 1, 126720, 0x698eb5cc
+0, 17, 17, 1, 126720, 0x4719aa98
+0, 18, 18, 1, 126720, 0x9ca1962c
+0, 19, 19, 1, 126720, 0x18cda460
+0, 20, 20, 1, 126720, 0xc230b716
+0, 21, 21, 1, 126720, 0x8451a4e2
+0, 22, 22, 1, 126720, 0x59e9a7ea
+0, 23, 23, 1, 126720, 0xc77ca73d
+0, 24, 24, 1, 126720, 0x725fb976
+0, 25, 25, 1, 126720, 0xb30da3b3
+0, 26, 26, 1, 126720, 0x7af2ea86
+0, 27, 27, 1, 126720, 0x40d4b4eb
+0, 28, 28, 1, 126720, 0x49d00307
+0, 29, 29, 1, 126720, 0x0654849c
+0, 30, 30, 1, 126720, 0xe46d0107
+0, 31, 31, 1, 126720, 0xa483b963
+0, 32, 32, 1, 126720, 0xd0e903f0
+0, 33, 33, 1, 126720, 0x964ed592
+0, 34, 34, 1, 126720, 0x23fbdb3c
+0, 35, 35, 1, 126720, 0x59fdace5
+0, 36, 36, 1, 126720, 0xb1e37954
+0, 37, 37, 1, 126720, 0x8ed9c554
+0, 38, 38, 1, 126720, 0xe3c4b39f
+0, 39, 39, 1, 126720, 0xfd17e0ce
+0, 40, 40, 1, 126720, 0xf26e1dcc
+0, 41, 41, 1, 126720, 0x13cc783c
+0, 42, 42, 1, 126720, 0x47ad47a1
+0, 43, 43, 1, 126720, 0x427c8b0d
+0, 44, 44, 1, 126720, 0x59d99901
+0, 45, 45, 1, 126720, 0xc40707da
+0, 46, 46, 1, 126720, 0xcd060dce
+0, 47, 47, 1, 126720, 0xed4024f6
+0, 48, 48, 1, 126720, 0x7decd2b4
+0, 49, 49, 1, 126720, 0xd1d2e730
+0, 50, 50, 1, 126720, 0x77cee457
+0, 51, 51, 1, 126720, 0xe78d02c0
+0, 52, 52, 1, 126720, 0xad0beb29
+0, 53, 53, 1, 126720, 0xc414eea2
+0, 54, 54, 1, 126720, 0x6a15f17d
+0, 55, 55, 1, 126720, 0x516027f6
+0, 56, 56, 1, 126720, 0x4eda9dce
+0, 57, 57, 1, 126720, 0x7d9bdba3
+0, 58, 58, 1, 126720, 0x7aa3d5c0
+0, 59, 59, 1, 126720, 0x7c7a04f9
+0, 60, 60, 1, 126720, 0x3e8fb6cc
+0, 61, 61, 1, 126720, 0xd5474916
+0, 62, 62, 1, 126720, 0xf3f62bab
+0, 63, 63, 1, 126720, 0x2f054987
+0, 64, 64, 1, 126720, 0x974c2e81
+0, 65, 65, 1, 126720, 0xe7e28a97
+0, 66, 66, 1, 126720, 0x45e38b41
+0, 67, 67, 1, 126720, 0x169c7f19
+0, 68, 68, 1, 126720, 0x91d90ee8
+0, 69, 69, 1, 126720, 0xdd653e24
+0, 70, 70, 1, 126720, 0x0da598c4
+0, 71, 71, 1, 126720, 0x687e62cc
+0, 72, 72, 1, 126720, 0x7631232d
+0, 73, 73, 1, 126720, 0xbd1ea826
+0, 74, 74, 1, 126720, 0xb55f7f4b
+0, 75, 75, 1, 126720, 0x923f3fc9
+0, 76, 76, 1, 126720, 0x15515301
+0, 77, 77, 1, 126720, 0x9ee066e5
+0, 78, 78, 1, 126720, 0x7c21664b
+0, 79, 79, 1, 126720, 0x36849100
+0, 80, 80, 1, 126720, 0x08b1f61a
+0, 81, 81, 1, 126720, 0x5bfca6e2
+0, 82, 82, 1, 126720, 0x929f60e3
+0, 83, 83, 1, 126720, 0xa2b55c29
+0, 84, 84, 1, 126720, 0x68bd3ff3
+0, 85, 85, 1, 126720, 0x30db5b29
+0, 86, 86, 1, 126720, 0x00578f9b
+0, 87, 87, 1, 126720, 0x18368642
+0, 88, 88, 1, 126720, 0xbcb83a80
+0, 89, 89, 1, 126720, 0x90f36b72
+0, 90, 90, 1, 126720, 0x85e46522
+0, 91, 91, 1, 126720, 0x2429660a
+0, 92, 92, 1, 126720, 0xf283dfe2
+0, 93, 93, 1, 126720, 0x896b27dc
+0, 94, 94, 1, 126720, 0x5af4f961
+0, 95, 95, 1, 126720, 0x31897085
+0, 96, 96, 1, 126720, 0x441ce33e
+0, 97, 97, 1, 126720, 0x903f8009
+0, 98, 98, 1, 126720, 0xbdf33dba
+0, 99, 99, 1, 126720, 0x8a364f36
+0, 100, 100, 1, 126720, 0xda5513f6
+0, 101, 101, 1, 126720, 0xd60012b3
+0, 102, 102, 1, 126720, 0x67bce7be
+0, 103, 103, 1, 126720, 0x697e6174
+0, 104, 104, 1, 126720, 0xbe3e3e90
+0, 105, 105, 1, 126720, 0xf3e4bba6
+0, 106, 106, 1, 126720, 0x8124a679
+0, 107, 107, 1, 126720, 0x58d1acde
+0, 108, 108, 1, 126720, 0xd8a15ba3
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..6db0e72
--- /dev/null
+++ b/tests/ref/fate/filter-edgedetect
@@ -0,0 +1 @@
+edgedetect 9d396de52d56b63a77ea6933a323f61f
diff --git a/tests/ref/fate/filter-fade b/tests/ref/fate/filter-fade
index 131b614..446db77 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, 0x54bae320
+0, 7, 7, 1, 152064, 0x53b60b7e
+0, 8, 8, 1, 152064, 0x8bed0304
+0, 9, 9, 1, 152064, 0x509c4b78
+0, 10, 10, 1, 152064, 0x4cf869a4
+0, 11, 11, 1, 152064, 0x958b7c66
+0, 12, 12, 1, 152064, 0x45841fbf
+0, 13, 13, 1, 152064, 0xcfee57ea
+0, 14, 14, 1, 152064, 0x979ff709
+0, 15, 15, 1, 152064, 0xf7ffd5e2
+0, 16, 16, 1, 152064, 0xc42f4370
+0, 17, 17, 1, 152064, 0x71ae098f
+0, 18, 18, 1, 152064, 0x64146a42
+0, 19, 19, 1, 152064, 0xdb3068fd
+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, 0x11446a9b
+0, 32, 32, 1, 152064, 0x00be684c
+0, 33, 33, 1, 152064, 0xe5f9ee52
+0, 34, 34, 1, 152064, 0x21ecafb8
+0, 35, 35, 1, 152064, 0xd42c962c
+0, 36, 36, 1, 152064, 0xe00a270d
+0, 37, 37, 1, 152064, 0xc1b53878
+0, 38, 38, 1, 152064, 0xfc4e28dd
+0, 39, 39, 1, 152064, 0x9c574e39
+0, 40, 40, 1, 152064, 0xdd25cf9d
+0, 41, 41, 1, 152064, 0x32959e70
+0, 42, 42, 1, 152064, 0xac6498d5
+0, 43, 43, 1, 152064, 0xcd595d21
+0, 44, 44, 1, 152064, 0x2953ff74
+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..3c31bde
--- /dev/null
+++ b/tests/ref/fate/filter-gradfun-sample
@@ -0,0 +1,21 @@
+#tb 0: 1/10
+0, 0, 0, 1, 76800, 0xc87b6728
+0, 1, 1, 1, 76800, 0xb0b24bc8
+0, 2, 2, 1, 76800, 0x45a22d68
+0, 3, 3, 1, 76800, 0x1821013b
+0, 4, 4, 1, 76800, 0xfb17dc4f
+0, 5, 5, 1, 76800, 0x07714cf0
+0, 6, 6, 1, 76800, 0x7a5f14df
+0, 7, 7, 1, 76800, 0x421fe837
+0, 8, 8, 1, 76800, 0x39b9af40
+0, 9, 9, 1, 76800, 0x42b47d6b
+0, 10, 10, 1, 76800, 0xb1084cc8
+0, 11, 11, 1, 76800, 0x0772794c
+0, 12, 12, 1, 76800, 0x99544be0
+0, 13, 13, 1, 76800, 0x5f1a16c1
+0, 14, 14, 1, 76800, 0x90bfe8ac
+0, 15, 15, 1, 76800, 0xbd9bb834
+0, 16, 16, 1, 76800, 0x658d8053
+0, 17, 17, 1, 76800, 0x21cc5656
+0, 18, 18, 1, 76800, 0x6d39208b
+0, 19, 19, 1, 76800, 0x17b0f8cb
diff --git a/tests/ref/fate/filter-histogram-levels b/tests/ref/fate/filter-histogram-levels
new file mode 100644
index 0000000..df9f6b2
--- /dev/null
+++ b/tests/ref/fate/filter-histogram-levels
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 488448, 0x0d7343b9
+0, 1, 1, 1, 488448, 0x118e3ade
+0, 2, 2, 1, 488448, 0x778f1ba9
+0, 3, 3, 1, 488448, 0x153bf44e
+0, 4, 4, 1, 488448, 0x2d83c1ab
+0, 5, 5, 1, 488448, 0xa3e95f8f
+0, 6, 6, 1, 488448, 0x91aad31b
+0, 7, 7, 1, 488448, 0x90b92c09
+0, 8, 8, 1, 488448, 0x1e4c9f41
+0, 9, 9, 1, 488448, 0xa88c1882
+0, 10, 10, 1, 488448, 0x1aa04274
+0, 11, 11, 1, 488448, 0x49c45de8
+0, 12, 12, 1, 488448, 0xe799c29f
+0, 13, 13, 1, 488448, 0x789e233f
+0, 14, 14, 1, 488448, 0x9f753404
+0, 15, 15, 1, 488448, 0x83050c2c
+0, 16, 16, 1, 488448, 0xddf7ccbf
+0, 17, 17, 1, 488448, 0xe3128531
+0, 18, 18, 1, 488448, 0xcc6596af
+0, 19, 19, 1, 488448, 0x6e19754f
+0, 20, 20, 1, 488448, 0xc3b32c7c
+0, 21, 21, 1, 488448, 0x40b4853f
+0, 22, 22, 1, 488448, 0x6e492674
+0, 23, 23, 1, 488448, 0x7f867236
+0, 24, 24, 1, 488448, 0x22094365
+0, 25, 25, 1, 488448, 0x45f30fc3
+0, 26, 26, 1, 488448, 0xe6cbad09
+0, 27, 27, 1, 488448, 0x0c44836b
+0, 28, 28, 1, 488448, 0xa7f04271
+0, 29, 29, 1, 488448, 0xd222ba88
+0, 30, 30, 1, 488448, 0xc96a9749
+0, 31, 31, 1, 488448, 0x82e25bbd
+0, 32, 32, 1, 488448, 0xf79d1882
+0, 33, 33, 1, 488448, 0x6d7fdd68
+0, 34, 34, 1, 488448, 0xeb5c9b1b
+0, 35, 35, 1, 488448, 0x9014f9f4
+0, 36, 36, 1, 488448, 0x96c6ab5f
+0, 37, 37, 1, 488448, 0x03911af0
+0, 38, 38, 1, 488448, 0xbf9dd8eb
+0, 39, 39, 1, 488448, 0x73509963
+0, 40, 40, 1, 488448, 0xf2ecb068
+0, 41, 41, 1, 488448, 0xec2fb311
+0, 42, 42, 1, 488448, 0xf4c7ba26
+0, 43, 43, 1, 488448, 0x23f56543
+0, 44, 44, 1, 488448, 0x25f8c48c
+0, 45, 45, 1, 488448, 0xf1ccd38b
+0, 46, 46, 1, 488448, 0x10780667
+0, 47, 47, 1, 488448, 0xbeb70431
+0, 48, 48, 1, 488448, 0xbc950678
+0, 49, 49, 1, 488448, 0xfedf5d83
diff --git a/tests/ref/fate/filter-histogram-waveform b/tests/ref/fate/filter-histogram-waveform
new file mode 100644
index 0000000..da6bbc4
--- /dev/null
+++ b/tests/ref/fate/filter-histogram-waveform
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 663552, 0x8a55d4d9
+0, 1, 1, 1, 663552, 0xf4c4d42d
+0, 2, 2, 1, 663552, 0x291cd441
+0, 3, 3, 1, 663552, 0xce5bd56b
+0, 4, 4, 1, 663552, 0x1dc0d637
+0, 5, 5, 1, 663552, 0x4676d387
+0, 6, 6, 1, 663552, 0x8064d607
+0, 7, 7, 1, 663552, 0x1981d54f
+0, 8, 8, 1, 663552, 0x8fffd4a3
+0, 9, 9, 1, 663552, 0x5041d2f7
+0, 10, 10, 1, 663552, 0x03bbd401
+0, 11, 11, 1, 663552, 0x965bd2f3
+0, 12, 12, 1, 663552, 0x0d39d27d
+0, 13, 13, 1, 663552, 0xad39d1fb
+0, 14, 14, 1, 663552, 0x1809d195
+0, 15, 15, 1, 663552, 0xe083cf2f
+0, 16, 16, 1, 663552, 0x0d6fd3b3
+0, 17, 17, 1, 663552, 0x3a8ed3f3
+0, 18, 18, 1, 663552, 0xbbb5d00d
+0, 19, 19, 1, 663552, 0xe6ead0df
+0, 20, 20, 1, 663552, 0xf5dcd35f
+0, 21, 21, 1, 663552, 0x9cd9d32b
+0, 22, 22, 1, 663552, 0xcb91d1b9
+0, 23, 23, 1, 663552, 0x5640cfd7
+0, 24, 24, 1, 663552, 0x5370d285
+0, 25, 25, 1, 663552, 0xd894d1dd
+0, 26, 26, 1, 663552, 0xace4ce65
+0, 27, 27, 1, 663552, 0x6e15ce17
+0, 28, 28, 1, 663552, 0xd21cce21
+0, 29, 29, 1, 663552, 0xec1ecd83
+0, 30, 30, 1, 663552, 0x9852ce0f
+0, 31, 31, 1, 663552, 0xe488cba3
+0, 32, 32, 1, 663552, 0x2e15cbed
+0, 33, 33, 1, 663552, 0x5e59ca97
+0, 34, 34, 1, 663552, 0x7cefcd7d
+0, 35, 35, 1, 663552, 0xcb99ccfb
+0, 36, 36, 1, 663552, 0xce32cf29
+0, 37, 37, 1, 663552, 0x7fb8ceef
+0, 38, 38, 1, 663552, 0x4014d18f
+0, 39, 39, 1, 663552, 0x224dd381
+0, 40, 40, 1, 663552, 0x5347d125
+0, 41, 41, 1, 663552, 0xec83ce79
+0, 42, 42, 1, 663552, 0x4d24ce8b
+0, 43, 43, 1, 663552, 0xfdc5ccbd
+0, 44, 44, 1, 663552, 0x592cd18b
+0, 45, 45, 1, 663552, 0xff06d43b
+0, 46, 46, 1, 663552, 0x7f69d4ef
+0, 47, 47, 1, 663552, 0x1607d3f1
+0, 48, 48, 1, 663552, 0x33e0d211
+0, 49, 49, 1, 663552, 0xe1b1d2cd
diff --git a/tests/ref/fate/filter-hqdn3d-sample b/tests/ref/fate/filter-hqdn3d-sample
new file mode 100644
index 0000000..97718f9
--- /dev/null
+++ b/tests/ref/fate/filter-hqdn3d-sample
@@ -0,0 +1,74 @@
+#tb 0: 1/9
+0, 0, 0, 1, 115200, 0x2c810465
+0, 1, 1, 1, 115200, 0x957c0563
+0, 2, 2, 1, 115200, 0x786c6d5b
+0, 3, 3, 1, 115200, 0xd5ef87d3
+0, 4, 4, 1, 115200, 0x3a2158e2
+0, 5, 5, 1, 115200, 0x19d7d048
+0, 6, 6, 1, 115200, 0x16d5e09a
+0, 7, 7, 1, 115200, 0x73cca454
+0, 8, 8, 1, 115200, 0x4d6be3bc
+0, 9, 9, 1, 115200, 0x672aad0f
+0, 10, 10, 1, 115200, 0x1bd103b7
+0, 11, 11, 1, 115200, 0xbc3a9c02
+0, 12, 12, 1, 115200, 0xa19cb68c
+0, 13, 13, 1, 115200, 0x83477b6c
+0, 14, 14, 1, 115200, 0x68b6898e
+0, 15, 15, 1, 115200, 0xebbc5701
+0, 16, 16, 1, 115200, 0x37e873db
+0, 17, 17, 1, 115200, 0xcf9e7ad1
+0, 18, 18, 1, 115200, 0x3fdffd3a
+0, 19, 19, 1, 115200, 0x413da058
+0, 20, 20, 1, 115200, 0xa432b2f6
+0, 21, 21, 1, 115200, 0x9c532b61
+0, 22, 22, 1, 115200, 0x40c03856
+0, 23, 23, 1, 115200, 0xf8310ec7
+0, 24, 24, 1, 115200, 0x89246da7
+0, 25, 25, 1, 115200, 0x501d4dd0
+0, 26, 26, 1, 115200, 0xe5151ebf
+0, 27, 27, 1, 115200, 0xc166e201
+0, 28, 28, 1, 115200, 0xded25b69
+0, 29, 29, 1, 115200, 0xb51ec43f
+0, 30, 30, 1, 115200, 0x9bba20eb
+0, 31, 31, 1, 115200, 0x7a7b9278
+0, 32, 32, 1, 115200, 0xe98475d0
+0, 33, 33, 1, 115200, 0x960dc933
+0, 34, 34, 1, 115200, 0xe93f558b
+0, 35, 35, 1, 115200, 0x37ae3e42
+0, 36, 36, 1, 115200, 0x0ecaf64a
+0, 37, 37, 1, 115200, 0xd5938191
+0, 38, 38, 1, 115200, 0xeb04510a
+0, 39, 39, 1, 115200, 0xf5729201
+0, 40, 40, 1, 115200, 0xb2c04015
+0, 41, 41, 1, 115200, 0xd883143e
+0, 42, 42, 1, 115200, 0x5e04197b
+0, 43, 43, 1, 115200, 0x6b846e24
+0, 44, 44, 1, 115200, 0x026e7a0b
+0, 45, 45, 1, 115200, 0xef23db9d
+0, 46, 46, 1, 115200, 0x9e94265d
+0, 47, 47, 1, 115200, 0x2830098a
+0, 48, 48, 1, 115200, 0xf5d211d6
+0, 49, 49, 1, 115200, 0xb96b22b0
+0, 50, 50, 1, 115200, 0x9acda7c9
+0, 51, 51, 1, 115200, 0xed7b40f6
+0, 52, 52, 1, 115200, 0x8250278f
+0, 53, 53, 1, 115200, 0xa10003e0
+0, 54, 54, 1, 115200, 0xe67b5513
+0, 55, 55, 1, 115200, 0x2c581d60
+0, 56, 56, 1, 115200, 0xd7a506ed
+0, 57, 57, 1, 115200, 0x35e09799
+0, 58, 58, 1, 115200, 0x2d4f5499
+0, 59, 59, 1, 115200, 0x92fdc85b
+0, 60, 60, 1, 115200, 0x33f4888a
+0, 61, 61, 1, 115200, 0x65e04e05
+0, 62, 62, 1, 115200, 0x14766728
+0, 63, 63, 1, 115200, 0x2a432c3f
+0, 64, 64, 1, 115200, 0x136a1362
+0, 65, 65, 1, 115200, 0xfbf4cb01
+0, 66, 66, 1, 115200, 0x7dcaff69
+0, 67, 67, 1, 115200, 0x5afd3b9e
+0, 68, 68, 1, 115200, 0x86fcb122
+0, 69, 69, 1, 115200, 0xc988b519
+0, 70, 70, 1, 115200, 0x48fd3e75
+0, 71, 71, 1, 115200, 0x2728a2d7
+0, 72, 72, 1, 115200, 0xa2ac6418
diff --git a/tests/ref/fate/filter-hue b/tests/ref/fate/filter-hue
new file mode 100644
index 0000000..ab412a7
--- /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
--- /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
--- /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..4d09a0d
--- /dev/null
+++ b/tests/ref/fate/filter-lavd-scalenorm
@@ -0,0 +1,11 @@
+#tb 0: 1/5
+0, 0, 0, 1, 18432, 0xdd8a4db8
+0, 1, 1, 1, 18432, 0xc0144dbe
+0, 2, 2, 1, 18432, 0x1d264db6
+0, 3, 3, 1, 18432, 0x49e44dcb
+0, 4, 4, 1, 18432, 0x81404dc1
+0, 5, 5, 1, 18432, 0xd163688e
+0, 6, 6, 1, 18432, 0x63f869bb
+0, 7, 7, 1, 18432, 0xee606528
+0, 8, 8, 1, 18432, 0x44445e77
+0, 9, 9, 1, 18432, 0x830a57b4
diff --git a/tests/ref/fate/filter-lavd-testsrc b/tests/ref/fate/filter-lavd-testsrc
new file mode 100644
index 0000000..0ea5a49
--- /dev/null
+++ b/tests/ref/fate/filter-lavd-testsrc
@@ -0,0 +1,71 @@
+#tb 0: 1/7
+0, 0, 0, 1, 230400, 0x88c4d19a
+0, 1, 1, 1, 230400, 0xcc930a2e
+0, 2, 2, 1, 230400, 0x8e1b0e23
+0, 3, 3, 1, 230400, 0xff3b5a72
+0, 4, 4, 1, 230400, 0xb0ad3760
+0, 5, 5, 1, 230400, 0x8013eaaf
+0, 6, 6, 1, 230400, 0xa6eaa9c3
+0, 7, 7, 1, 230400, 0xef4695a2
+0, 8, 8, 1, 230400, 0x8f144889
+0, 9, 9, 1, 230400, 0x693779f9
+0, 10, 10, 1, 230400, 0xedaf92f0
+0, 11, 11, 1, 230400, 0x1c39d7c4
+0, 12, 12, 1, 230400, 0xb72589bb
+0, 13, 13, 1, 230400, 0x61c2de4a
+0, 14, 14, 1, 230400, 0xc46085ae
+0, 15, 15, 1, 230400, 0xad059d62
+0, 16, 16, 1, 230400, 0xe82ea157
+0, 17, 17, 1, 230400, 0xa30aeda6
+0, 18, 18, 1, 230400, 0x7f86ca94
+0, 19, 19, 1, 230400, 0x4c4f7df2
+0, 20, 20, 1, 230400, 0x535a3d06
+0, 21, 21, 1, 230400, 0x449262ff
+0, 22, 22, 1, 230400, 0x971c15e6
+0, 23, 23, 1, 230400, 0xda1d4756
+0, 24, 24, 1, 230400, 0x78ad604d
+0, 25, 25, 1, 230400, 0x72d8a521
+0, 26, 26, 1, 230400, 0x8f395718
+0, 27, 27, 1, 230400, 0x6e57aba7
+0, 28, 28, 1, 230400, 0x54ad968f
+0, 29, 29, 1, 230400, 0x59d9ae43
+0, 30, 30, 1, 230400, 0x843fb238
+0, 31, 31, 1, 230400, 0x0f77fe87
+0, 32, 32, 1, 230400, 0x8c8adb75
+0, 33, 33, 1, 230400, 0xdd568ed3
+0, 34, 34, 1, 230400, 0x38bd4de7
+0, 35, 35, 1, 230400, 0x62ad62ff
+0, 36, 36, 1, 230400, 0x1f0215e6
+0, 37, 37, 1, 230400, 0xe8534756
+0, 38, 38, 1, 230400, 0x3d36604d
+0, 39, 39, 1, 230400, 0x0c57a521
+0, 40, 40, 1, 230400, 0x2b555718
+0, 41, 41, 1, 230400, 0x2a3faba7
+0, 42, 42, 1, 230400, 0x4e0a74cd
+0, 43, 43, 1, 230400, 0xa06b8c81
+0, 44, 44, 1, 230400, 0x61f39076
+0, 45, 45, 1, 230400, 0xd313dcc5
+0, 46, 46, 1, 230400, 0x8485b9b3
+0, 47, 47, 1, 230400, 0x53eb6d11
+0, 48, 48, 1, 230400, 0x7ac22c25
+0, 49, 49, 1, 230400, 0xce7b84c1
+0, 50, 50, 1, 230400, 0x6e4937a8
+0, 51, 51, 1, 230400, 0x486c6918
+0, 52, 52, 1, 230400, 0xcce4820f
+0, 53, 53, 1, 230400, 0xfb5fc6e3
+0, 54, 54, 1, 230400, 0x965a78da
+0, 55, 55, 1, 230400, 0x40f7cd69
+0, 56, 56, 1, 230400, 0x68db63ec
+0, 57, 57, 1, 230400, 0x51807ba0
+0, 58, 58, 1, 230400, 0x8ca97f95
+0, 59, 59, 1, 230400, 0x4785cbe4
+0, 60, 60, 1, 230400, 0x2401a8d2
+0, 61, 61, 1, 230400, 0xf0bb5c30
+0, 62, 62, 1, 230400, 0xf7c61b44
+0, 63, 63, 1, 230400, 0x7d7e521e
+0, 64, 64, 1, 230400, 0xd0080505
+0, 65, 65, 1, 230400, 0x13183675
+0, 66, 66, 1, 230400, 0xb1994f6c
+0, 67, 67, 1, 230400, 0xabc49440
+0, 68, 68, 1, 230400, 0xc8254637
+0, 69, 69, 1, 230400, 0xa7439ac6
diff --git a/tests/ref/fate/filter-metadata-ebur128 b/tests/ref/fate/filter-metadata-ebur128
new file mode 100644
index 0000000..7a060bd
--- /dev/null
+++ b/tests/ref/fate/filter-metadata-ebur128
@@ -0,0 +1,280 @@
+pkt_pts=0|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=4800|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=9600|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=14400|tag:lavfi.r128.M=-21.333|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.340|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=19200|tag:lavfi.r128.M=-21.249|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.295|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=24000|tag:lavfi.r128.M=-21.235|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.276|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=28800|tag:lavfi.r128.M=-21.587|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.353|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=33600|tag:lavfi.r128.M=-21.999|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.475|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=38400|tag:lavfi.r128.M=-22.371|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.613|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=43200|tag:lavfi.r128.M=-23.195|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.807|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=48000|tag:lavfi.r128.M=-23.550|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.991|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=52800|tag:lavfi.r128.M=-23.901|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-22.167|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=57600|tag:lavfi.r128.M=-24.461|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-22.350|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=62400|tag:lavfi.r128.M=-24.984|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-22.533|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=67200|tag:lavfi.r128.M=-25.448|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-22.714|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=72000|tag:lavfi.r128.M=-25.847|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-22.889|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=76800|tag:lavfi.r128.M=-26.187|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.058|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=81600|tag:lavfi.r128.M=-26.229|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.210|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=86400|tag:lavfi.r128.M=-26.132|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.346|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=91200|tag:lavfi.r128.M=-26.164|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.470|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=96000|tag:lavfi.r128.M=-26.282|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.586|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=100800|tag:lavfi.r128.M=-26.371|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.696|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=105600|tag:lavfi.r128.M=-26.421|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.799|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=110400|tag:lavfi.r128.M=-26.362|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.892|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=115200|tag:lavfi.r128.M=-26.278|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.977|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=120000|tag:lavfi.r128.M=-26.524|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-24.061|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=124800|tag:lavfi.r128.M=-26.867|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-24.148|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=129600|tag:lavfi.r128.M=-27.286|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-24.239|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=134400|tag:lavfi.r128.M=-27.372|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-24.326|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=139200|tag:lavfi.r128.M=-27.449|tag:lavfi.r128.S=-24.296|tag:lavfi.r128.I=-24.409|tag:lavfi.r128.LRA=20.000|tag:lavfi.r128.LRA.low=-44.300|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=144000|tag:lavfi.r128.M=-27.083|tag:lavfi.r128.S=-24.455|tag:lavfi.r128.I=-24.481|tag:lavfi.r128.LRA=20.080|tag:lavfi.r128.LRA.low=-44.380|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=148800|tag:lavfi.r128.M=-26.899|tag:lavfi.r128.S=-24.719|tag:lavfi.r128.I=-24.545|tag:lavfi.r128.LRA=20.190|tag:lavfi.r128.LRA.low=-44.490|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=153600|tag:lavfi.r128.M=-26.880|tag:lavfi.r128.S=-24.962|tag:lavfi.r128.I=-24.606|tag:lavfi.r128.LRA=20.310|tag:lavfi.r128.LRA.low=-44.610|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=158400|tag:lavfi.r128.M=-26.886|tag:lavfi.r128.S=-25.214|tag:lavfi.r128.I=-24.664|tag:lavfi.r128.LRA=0.920|tag:lavfi.r128.LRA.low=-25.220|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=163200|tag:lavfi.r128.M=-27.096|tag:lavfi.r128.S=-25.459|tag:lavfi.r128.I=-24.722|tag:lavfi.r128.LRA=1.160|tag:lavfi.r128.LRA.low=-25.460|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=168000|tag:lavfi.r128.M=-26.430|tag:lavfi.r128.S=-25.729|tag:lavfi.r128.I=-24.765|tag:lavfi.r128.LRA=1.430|tag:lavfi.r128.LRA.low=-25.730|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=172800|tag:lavfi.r128.M=-25.736|tag:lavfi.r128.S=-25.816|tag:lavfi.r128.I=-24.791|tag:lavfi.r128.LRA=1.520|tag:lavfi.r128.LRA.low=-25.820|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=177600|tag:lavfi.r128.M=-25.976|tag:lavfi.r128.S=-26.011|tag:lavfi.r128.I=-24.821|tag:lavfi.r128.LRA=1.720|tag:lavfi.r128.LRA.low=-26.020|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=182400|tag:lavfi.r128.M=-26.417|tag:lavfi.r128.S=-26.240|tag:lavfi.r128.I=-24.858|tag:lavfi.r128.LRA=1.940|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=187200|tag:lavfi.r128.M=-27.102|tag:lavfi.r128.S=-26.393|tag:lavfi.r128.I=-24.906|tag:lavfi.r128.LRA=1.940|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=192000|tag:lavfi.r128.M=-28.221|tag:lavfi.r128.S=-26.511|tag:lavfi.r128.I=-24.968|tag:lavfi.r128.LRA=2.060|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=196800|tag:lavfi.r128.M=-27.900|tag:lavfi.r128.S=-26.618|tag:lavfi.r128.I=-25.023|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=201600|tag:lavfi.r128.M=-27.179|tag:lavfi.r128.S=-26.666|tag:lavfi.r128.I=-25.065|tag:lavfi.r128.LRA=2.210|tag:lavfi.r128.LRA.low=-26.670|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=206400|tag:lavfi.r128.M=-26.274|tag:lavfi.r128.S=-26.604|tag:lavfi.r128.I=-25.091|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=211200|tag:lavfi.r128.M=-25.385|tag:lavfi.r128.S=-26.501|tag:lavfi.r128.I=-25.098|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=216000|tag:lavfi.r128.M=-25.220|tag:lavfi.r128.S=-26.511|tag:lavfi.r128.I=-25.101|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=220800|tag:lavfi.r128.M=-23.888|tag:lavfi.r128.S=-26.237|tag:lavfi.r128.I=-25.069|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=225600|tag:lavfi.r128.M=-24.544|tag:lavfi.r128.S=-26.315|tag:lavfi.r128.I=-25.057|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=230400|tag:lavfi.r128.M=-25.042|tag:lavfi.r128.S=-26.325|tag:lavfi.r128.I=-25.057|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=235200|tag:lavfi.r128.M=-25.146|tag:lavfi.r128.S=-26.349|tag:lavfi.r128.I=-25.059|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=240000|tag:lavfi.r128.M=-27.510|tag:lavfi.r128.S=-26.380|tag:lavfi.r128.I=-25.098|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=244800|tag:lavfi.r128.M=-26.266|tag:lavfi.r128.S=-26.301|tag:lavfi.r128.I=-25.119|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=249600|tag:lavfi.r128.M=-26.455|tag:lavfi.r128.S=-26.329|tag:lavfi.r128.I=-25.142|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=254400|tag:lavfi.r128.M=-26.169|tag:lavfi.r128.S=-26.323|tag:lavfi.r128.I=-25.160|tag:lavfi.r128.LRA=2.150|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=259200|tag:lavfi.r128.M=-25.834|tag:lavfi.r128.S=-26.317|tag:lavfi.r128.I=-25.172|tag:lavfi.r128.LRA=2.150|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=264000|tag:lavfi.r128.M=-26.461|tag:lavfi.r128.S=-26.293|tag:lavfi.r128.I=-25.194|tag:lavfi.r128.LRA=2.150|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=268800|tag:lavfi.r128.M=-26.327|tag:lavfi.r128.S=-26.262|tag:lavfi.r128.I=-25.212|tag:lavfi.r128.LRA=2.150|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=273600|tag:lavfi.r128.M=-26.559|tag:lavfi.r128.S=-26.239|tag:lavfi.r128.I=-25.233|tag:lavfi.r128.LRA=2.150|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=278400|tag:lavfi.r128.M=-26.657|tag:lavfi.r128.S=-26.236|tag:lavfi.r128.I=-25.255|tag:lavfi.r128.LRA=2.150|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=283200|tag:lavfi.r128.M=-26.563|tag:lavfi.r128.S=-26.193|tag:lavfi.r128.I=-25.275|tag:lavfi.r128.LRA=1.890|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=288000|tag:lavfi.r128.M=-26.632|tag:lavfi.r128.S=-26.210|tag:lavfi.r128.I=-25.295|tag:lavfi.r128.LRA=1.890|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=292800|tag:lavfi.r128.M=-26.750|tag:lavfi.r128.S=-26.222|tag:lavfi.r128.I=-25.316|tag:lavfi.r128.LRA=1.890|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=297600|tag:lavfi.r128.M=-26.727|tag:lavfi.r128.S=-26.218|tag:lavfi.r128.I=-25.336|tag:lavfi.r128.LRA=1.890|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=302400|tag:lavfi.r128.M=-26.945|tag:lavfi.r128.S=-26.200|tag:lavfi.r128.I=-25.358|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=307200|tag:lavfi.r128.M=-26.839|tag:lavfi.r128.S=-26.181|tag:lavfi.r128.I=-25.379|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=312000|tag:lavfi.r128.M=-26.056|tag:lavfi.r128.S=-26.172|tag:lavfi.r128.I=-25.389|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=316800|tag:lavfi.r128.M=-26.589|tag:lavfi.r128.S=-26.335|tag:lavfi.r128.I=-25.405|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=321600|tag:lavfi.r128.M=-27.190|tag:lavfi.r128.S=-26.351|tag:lavfi.r128.I=-25.428|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=326400|tag:lavfi.r128.M=-28.078|tag:lavfi.r128.S=-26.359|tag:lavfi.r128.I=-25.458|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=331200|tag:lavfi.r128.M=-27.878|tag:lavfi.r128.S=-26.250|tag:lavfi.r128.I=-25.486|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=336000|tag:lavfi.r128.M=-26.604|tag:lavfi.r128.S=-26.169|tag:lavfi.r128.I=-25.500|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=340800|tag:lavfi.r128.M=-26.289|tag:lavfi.r128.S=-26.173|tag:lavfi.r128.I=-25.511|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=345600|tag:lavfi.r128.M=-24.672|tag:lavfi.r128.S=-26.000|tag:lavfi.r128.I=-25.498|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=350400|tag:lavfi.r128.M=-25.114|tag:lavfi.r128.S=-26.077|tag:lavfi.r128.I=-25.492|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=355200|tag:lavfi.r128.M=-24.561|tag:lavfi.r128.S=-26.027|tag:lavfi.r128.I=-25.478|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=360000|tag:lavfi.r128.M=-23.558|tag:lavfi.r128.S=-25.849|tag:lavfi.r128.I=-25.445|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=364800|tag:lavfi.r128.M=-24.650|tag:lavfi.r128.S=-26.154|tag:lavfi.r128.I=-25.433|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=369600|tag:lavfi.r128.M=-23.700|tag:lavfi.r128.S=-25.903|tag:lavfi.r128.I=-25.405|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=374400|tag:lavfi.r128.M=-24.144|tag:lavfi.r128.S=-25.863|tag:lavfi.r128.I=-25.386|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=379200|tag:lavfi.r128.M=-23.935|tag:lavfi.r128.S=-25.635|tag:lavfi.r128.I=-25.364|tag:lavfi.r128.LRA=1.550|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=384000|tag:lavfi.r128.M=-22.202|tag:lavfi.r128.S=-25.242|tag:lavfi.r128.I=-25.305|tag:lavfi.r128.LRA=1.550|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=388800|tag:lavfi.r128.M=-22.634|tag:lavfi.r128.S=-25.257|tag:lavfi.r128.I=-25.258|tag:lavfi.r128.LRA=1.550|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=393600|tag:lavfi.r128.M=-22.480|tag:lavfi.r128.S=-25.165|tag:lavfi.r128.I=-25.210|tag:lavfi.r128.LRA=1.550|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=398400|tag:lavfi.r128.M=-23.030|tag:lavfi.r128.S=-25.124|tag:lavfi.r128.I=-25.176|tag:lavfi.r128.LRA=1.540|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=403200|tag:lavfi.r128.M=-24.357|tag:lavfi.r128.S=-25.042|tag:lavfi.r128.I=-25.165|tag:lavfi.r128.LRA=1.540|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=408000|tag:lavfi.r128.M=-24.346|tag:lavfi.r128.S=-24.990|tag:lavfi.r128.I=-25.154|tag:lavfi.r128.LRA=1.540|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=412800|tag:lavfi.r128.M=-24.868|tag:lavfi.r128.S=-24.992|tag:lavfi.r128.I=-25.151|tag:lavfi.r128.LRA=1.540|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=417600|tag:lavfi.r128.M=-25.190|tag:lavfi.r128.S=-24.972|tag:lavfi.r128.I=-25.151|tag:lavfi.r128.LRA=1.540|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=422400|tag:lavfi.r128.M=-26.094|tag:lavfi.r128.S=-24.987|tag:lavfi.r128.I=-25.161|tag:lavfi.r128.LRA=1.540|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=427200|tag:lavfi.r128.M=-26.093|tag:lavfi.r128.S=-24.944|tag:lavfi.r128.I=-25.171|tag:lavfi.r128.LRA=1.560|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.950
+pkt_pts=432000|tag:lavfi.r128.M=-26.243|tag:lavfi.r128.S=-24.955|tag:lavfi.r128.I=-25.182|tag:lavfi.r128.LRA=1.560|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.950
+pkt_pts=436800|tag:lavfi.r128.M=-25.959|tag:lavfi.r128.S=-24.896|tag:lavfi.r128.I=-25.190|tag:lavfi.r128.LRA=1.610|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.900
+pkt_pts=441600|tag:lavfi.r128.M=-24.870|tag:lavfi.r128.S=-24.785|tag:lavfi.r128.I=-25.186|tag:lavfi.r128.LRA=1.720|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.790
+pkt_pts=446400|tag:lavfi.r128.M=-24.644|tag:lavfi.r128.S=-24.696|tag:lavfi.r128.I=-25.180|tag:lavfi.r128.LRA=1.680|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=451200|tag:lavfi.r128.M=-24.141|tag:lavfi.r128.S=-24.643|tag:lavfi.r128.I=-25.167|tag:lavfi.r128.LRA=1.700|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.700
+pkt_pts=456000|tag:lavfi.r128.M=-23.990|tag:lavfi.r128.S=-24.634|tag:lavfi.r128.I=-25.153|tag:lavfi.r128.LRA=1.750|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.650
+pkt_pts=460800|tag:lavfi.r128.M=-24.020|tag:lavfi.r128.S=-24.487|tag:lavfi.r128.I=-25.139|tag:lavfi.r128.LRA=1.760|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.640
+pkt_pts=465600|tag:lavfi.r128.M=-24.627|tag:lavfi.r128.S=-24.442|tag:lavfi.r128.I=-25.133|tag:lavfi.r128.LRA=1.910|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.490
+pkt_pts=470400|tag:lavfi.r128.M=-25.115|tag:lavfi.r128.S=-24.394|tag:lavfi.r128.I=-25.133|tag:lavfi.r128.LRA=1.940|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=475200|tag:lavfi.r128.M=-25.672|tag:lavfi.r128.S=-24.456|tag:lavfi.r128.I=-25.138|tag:lavfi.r128.LRA=1.940|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=480000|tag:lavfi.r128.M=-26.632|tag:lavfi.r128.S=-24.490|tag:lavfi.r128.I=-25.151|tag:lavfi.r128.LRA=1.940|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=484800|tag:lavfi.r128.M=-25.996|tag:lavfi.r128.S=-24.416|tag:lavfi.r128.I=-25.159|tag:lavfi.r128.LRA=1.940|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=489600|tag:lavfi.r128.M=-24.937|tag:lavfi.r128.S=-24.426|tag:lavfi.r128.I=-25.157|tag:lavfi.r128.LRA=1.950|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.450
+pkt_pts=494400|tag:lavfi.r128.M=-22.685|tag:lavfi.r128.S=-24.098|tag:lavfi.r128.I=-25.124|tag:lavfi.r128.LRA=1.960|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.430
+pkt_pts=499200|tag:lavfi.r128.M=-21.913|tag:lavfi.r128.S=-24.036|tag:lavfi.r128.I=-25.078|tag:lavfi.r128.LRA=1.970|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.420
+pkt_pts=504000|tag:lavfi.r128.M=-21.524|tag:lavfi.r128.S=-24.013|tag:lavfi.r128.I=-25.025|tag:lavfi.r128.LRA=1.990|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.400
+pkt_pts=508800|tag:lavfi.r128.M=-21.267|tag:lavfi.r128.S=-23.821|tag:lavfi.r128.I=-24.968|tag:lavfi.r128.LRA=2.090|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=513600|tag:lavfi.r128.M=-22.730|tag:lavfi.r128.S=-23.942|tag:lavfi.r128.I=-24.940|tag:lavfi.r128.LRA=2.290|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.100
+pkt_pts=518400|tag:lavfi.r128.M=-23.373|tag:lavfi.r128.S=-23.927|tag:lavfi.r128.I=-24.923|tag:lavfi.r128.LRA=2.350|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=523200|tag:lavfi.r128.M=-24.172|tag:lavfi.r128.S=-24.045|tag:lavfi.r128.I=-24.915|tag:lavfi.r128.LRA=2.350|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=528000|tag:lavfi.r128.M=-25.060|tag:lavfi.r128.S=-24.247|tag:lavfi.r128.I=-24.916|tag:lavfi.r128.LRA=2.350|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=532800|tag:lavfi.r128.M=-24.555|tag:lavfi.r128.S=-24.232|tag:lavfi.r128.I=-24.913|tag:lavfi.r128.LRA=2.350|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=537600|tag:lavfi.r128.M=-25.070|tag:lavfi.r128.S=-24.306|tag:lavfi.r128.I=-24.915|tag:lavfi.r128.LRA=2.350|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=542400|tag:lavfi.r128.M=-25.104|tag:lavfi.r128.S=-24.332|tag:lavfi.r128.I=-24.916|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=547200|tag:lavfi.r128.M=-25.813|tag:lavfi.r128.S=-24.411|tag:lavfi.r128.I=-24.924|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=552000|tag:lavfi.r128.M=-25.950|tag:lavfi.r128.S=-24.409|tag:lavfi.r128.I=-24.932|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=556800|tag:lavfi.r128.M=-25.759|tag:lavfi.r128.S=-24.402|tag:lavfi.r128.I=-24.938|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=561600|tag:lavfi.r128.M=-25.702|tag:lavfi.r128.S=-24.385|tag:lavfi.r128.I=-24.944|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=566400|tag:lavfi.r128.M=-24.540|tag:lavfi.r128.S=-24.245|tag:lavfi.r128.I=-24.941|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=571200|tag:lavfi.r128.M=-23.455|tag:lavfi.r128.S=-24.093|tag:lavfi.r128.I=-24.926|tag:lavfi.r128.LRA=2.310|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.050
+pkt_pts=576000|tag:lavfi.r128.M=-22.161|tag:lavfi.r128.S=-23.848|tag:lavfi.r128.I=-24.893|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=580800|tag:lavfi.r128.M=-21.752|tag:lavfi.r128.S=-23.772|tag:lavfi.r128.I=-24.855|tag:lavfi.r128.LRA=2.340|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.020
+pkt_pts=585600|tag:lavfi.r128.M=-21.869|tag:lavfi.r128.S=-23.772|tag:lavfi.r128.I=-24.819|tag:lavfi.r128.LRA=2.410|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.950
+pkt_pts=590400|tag:lavfi.r128.M=-22.553|tag:lavfi.r128.S=-23.788|tag:lavfi.r128.I=-24.795|tag:lavfi.r128.LRA=2.430|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.930
+pkt_pts=595200|tag:lavfi.r128.M=-23.563|tag:lavfi.r128.S=-23.771|tag:lavfi.r128.I=-24.783|tag:lavfi.r128.LRA=2.510|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.850
+pkt_pts=600000|tag:lavfi.r128.M=-23.930|tag:lavfi.r128.S=-23.764|tag:lavfi.r128.I=-24.776|tag:lavfi.r128.LRA=2.530|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.830
+pkt_pts=604800|tag:lavfi.r128.M=-24.599|tag:lavfi.r128.S=-23.841|tag:lavfi.r128.I=-24.774|tag:lavfi.r128.LRA=2.530|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.830
+pkt_pts=609600|tag:lavfi.r128.M=-24.476|tag:lavfi.r128.S=-23.772|tag:lavfi.r128.I=-24.772|tag:lavfi.r128.LRA=2.570|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.790
+pkt_pts=614400|tag:lavfi.r128.M=-24.380|tag:lavfi.r128.S=-23.694|tag:lavfi.r128.I=-24.769|tag:lavfi.r128.LRA=2.580|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.780
+pkt_pts=619200|tag:lavfi.r128.M=-23.440|tag:lavfi.r128.S=-23.520|tag:lavfi.r128.I=-24.756|tag:lavfi.r128.LRA=2.580|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.780
+pkt_pts=624000|tag:lavfi.r128.M=-22.290|tag:lavfi.r128.S=-23.347|tag:lavfi.r128.I=-24.731|tag:lavfi.r128.LRA=2.580|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.780
+pkt_pts=628800|tag:lavfi.r128.M=-21.092|tag:lavfi.r128.S=-23.100|tag:lavfi.r128.I=-24.687|tag:lavfi.r128.LRA=2.580|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.780
+pkt_pts=633600|tag:lavfi.r128.M=-20.607|tag:lavfi.r128.S=-23.007|tag:lavfi.r128.I=-24.635|tag:lavfi.r128.LRA=2.590|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.770
+pkt_pts=638400|tag:lavfi.r128.M=-20.608|tag:lavfi.r128.S=-23.110|tag:lavfi.r128.I=-24.585|tag:lavfi.r128.LRA=2.650|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.700
+pkt_pts=643200|tag:lavfi.r128.M=-20.622|tag:lavfi.r128.S=-23.077|tag:lavfi.r128.I=-24.536|tag:lavfi.r128.LRA=2.820|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.530
+pkt_pts=648000|tag:lavfi.r128.M=-21.543|tag:lavfi.r128.S=-23.104|tag:lavfi.r128.I=-24.504|tag:lavfi.r128.LRA=3.000|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.350
+pkt_pts=652800|tag:lavfi.r128.M=-22.071|tag:lavfi.r128.S=-23.156|tag:lavfi.r128.I=-24.480|tag:lavfi.r128.LRA=3.190|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.160
+pkt_pts=657600|tag:lavfi.r128.M=-22.327|tag:lavfi.r128.S=-23.049|tag:lavfi.r128.I=-24.459|tag:lavfi.r128.LRA=3.240|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.110
+pkt_pts=662400|tag:lavfi.r128.M=-22.810|tag:lavfi.r128.S=-23.003|tag:lavfi.r128.I=-24.445|tag:lavfi.r128.LRA=3.240|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.110
+pkt_pts=667200|tag:lavfi.r128.M=-22.676|tag:lavfi.r128.S=-22.921|tag:lavfi.r128.I=-24.429|tag:lavfi.r128.LRA=3.240|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.110
+pkt_pts=672000|tag:lavfi.r128.M=-22.942|tag:lavfi.r128.S=-22.927|tag:lavfi.r128.I=-24.416|tag:lavfi.r128.LRA=3.250|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.100
+pkt_pts=676800|tag:lavfi.r128.M=-23.165|tag:lavfi.r128.S=-22.897|tag:lavfi.r128.I=-24.406|tag:lavfi.r128.LRA=3.270|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.080
+pkt_pts=681600|tag:lavfi.r128.M=-23.339|tag:lavfi.r128.S=-22.830|tag:lavfi.r128.I=-24.397|tag:lavfi.r128.LRA=3.300|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.050
+pkt_pts=686400|tag:lavfi.r128.M=-23.672|tag:lavfi.r128.S=-22.786|tag:lavfi.r128.I=-24.392|tag:lavfi.r128.LRA=3.330|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-23.010
+pkt_pts=691200|tag:lavfi.r128.M=-23.306|tag:lavfi.r128.S=-22.701|tag:lavfi.r128.I=-24.383|tag:lavfi.r128.LRA=3.330|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-23.010
+pkt_pts=696000|tag:lavfi.r128.M=-23.384|tag:lavfi.r128.S=-22.672|tag:lavfi.r128.I=-24.375|tag:lavfi.r128.LRA=3.410|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.930
+pkt_pts=700800|tag:lavfi.r128.M=-23.531|tag:lavfi.r128.S=-22.637|tag:lavfi.r128.I=-24.369|tag:lavfi.r128.LRA=3.410|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.930
+pkt_pts=705600|tag:lavfi.r128.M=-23.311|tag:lavfi.r128.S=-22.574|tag:lavfi.r128.I=-24.361|tag:lavfi.r128.LRA=3.440|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.900
+pkt_pts=710400|tag:lavfi.r128.M=-23.705|tag:lavfi.r128.S=-22.621|tag:lavfi.r128.I=-24.356|tag:lavfi.r128.LRA=3.500|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.840
+pkt_pts=715200|tag:lavfi.r128.M=-24.104|tag:lavfi.r128.S=-22.740|tag:lavfi.r128.I=-24.354|tag:lavfi.r128.LRA=3.550|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.790
+pkt_pts=720000|tag:lavfi.r128.M=-24.403|tag:lavfi.r128.S=-22.905|tag:lavfi.r128.I=-24.355|tag:lavfi.r128.LRA=3.550|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.790
+pkt_pts=724800|tag:lavfi.r128.M=-24.337|tag:lavfi.r128.S=-22.900|tag:lavfi.r128.I=-24.354|tag:lavfi.r128.LRA=3.550|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.790
+pkt_pts=729600|tag:lavfi.r128.M=-23.538|tag:lavfi.r128.S=-22.846|tag:lavfi.r128.I=-24.348|tag:lavfi.r128.LRA=3.550|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.790
+pkt_pts=734400|tag:lavfi.r128.M=-22.774|tag:lavfi.r128.S=-22.770|tag:lavfi.r128.I=-24.336|tag:lavfi.r128.LRA=3.560|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.770
+pkt_pts=739200|tag:lavfi.r128.M=-21.589|tag:lavfi.r128.S=-22.628|tag:lavfi.r128.I=-24.311|tag:lavfi.r128.LRA=3.590|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.740
+pkt_pts=744000|tag:lavfi.r128.M=-21.003|tag:lavfi.r128.S=-22.482|tag:lavfi.r128.I=-24.279|tag:lavfi.r128.LRA=3.620|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.710
+pkt_pts=748800|tag:lavfi.r128.M=-21.057|tag:lavfi.r128.S=-22.384|tag:lavfi.r128.I=-24.248|tag:lavfi.r128.LRA=3.650|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.680
+pkt_pts=753600|tag:lavfi.r128.M=-20.378|tag:lavfi.r128.S=-22.196|tag:lavfi.r128.I=-24.208|tag:lavfi.r128.LRA=3.690|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.640
+pkt_pts=758400|tag:lavfi.r128.M=-20.735|tag:lavfi.r128.S=-22.147|tag:lavfi.r128.I=-24.174|tag:lavfi.r128.LRA=3.700|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.630
+pkt_pts=763200|tag:lavfi.r128.M=-21.502|tag:lavfi.r128.S=-22.228|tag:lavfi.r128.I=-24.150|tag:lavfi.r128.LRA=3.700|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.630
+pkt_pts=768000|tag:lavfi.r128.M=-21.158|tag:lavfi.r128.S=-22.211|tag:lavfi.r128.I=-24.123|tag:lavfi.r128.LRA=3.700|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.630
+pkt_pts=772800|tag:lavfi.r128.M=-22.252|tag:lavfi.r128.S=-22.375|tag:lavfi.r128.I=-24.109|tag:lavfi.r128.LRA=3.750|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.580
+pkt_pts=777600|tag:lavfi.r128.M=-22.753|tag:lavfi.r128.S=-22.481|tag:lavfi.r128.I=-24.099|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=782400|tag:lavfi.r128.M=-22.726|tag:lavfi.r128.S=-22.565|tag:lavfi.r128.I=-24.089|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=787200|tag:lavfi.r128.M=-23.676|tag:lavfi.r128.S=-22.655|tag:lavfi.r128.I=-24.086|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=792000|tag:lavfi.r128.M=-23.719|tag:lavfi.r128.S=-22.660|tag:lavfi.r128.I=-24.084|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=796800|tag:lavfi.r128.M=-23.765|tag:lavfi.r128.S=-22.692|tag:lavfi.r128.I=-24.082|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=801600|tag:lavfi.r128.M=-22.760|tag:lavfi.r128.S=-22.624|tag:lavfi.r128.I=-24.073|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=806400|tag:lavfi.r128.M=-21.532|tag:lavfi.r128.S=-22.468|tag:lavfi.r128.I=-24.052|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=811200|tag:lavfi.r128.M=-21.329|tag:lavfi.r128.S=-22.455|tag:lavfi.r128.I=-24.029|tag:lavfi.r128.LRA=3.860|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.470
+pkt_pts=816000|tag:lavfi.r128.M=-20.701|tag:lavfi.r128.S=-22.338|tag:lavfi.r128.I=-24.000|tag:lavfi.r128.LRA=3.870|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.460
+pkt_pts=820800|tag:lavfi.r128.M=-20.533|tag:lavfi.r128.S=-22.218|tag:lavfi.r128.I=-23.969|tag:lavfi.r128.LRA=3.940|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.390
+pkt_pts=825600|tag:lavfi.r128.M=-21.049|tag:lavfi.r128.S=-22.151|tag:lavfi.r128.I=-23.944|tag:lavfi.r128.LRA=3.950|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.380
+pkt_pts=830400|tag:lavfi.r128.M=-21.066|tag:lavfi.r128.S=-22.110|tag:lavfi.r128.I=-23.920|tag:lavfi.r128.LRA=3.990|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.340
+pkt_pts=835200|tag:lavfi.r128.M=-20.990|tag:lavfi.r128.S=-22.023|tag:lavfi.r128.I=-23.896|tag:lavfi.r128.LRA=4.100|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.230
+pkt_pts=840000|tag:lavfi.r128.M=-21.658|tag:lavfi.r128.S=-22.007|tag:lavfi.r128.I=-23.879|tag:lavfi.r128.LRA=4.110|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.220
+pkt_pts=844800|tag:lavfi.r128.M=-21.649|tag:lavfi.r128.S=-21.928|tag:lavfi.r128.I=-23.863|tag:lavfi.r128.LRA=4.110|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.220
+pkt_pts=849600|tag:lavfi.r128.M=-22.120|tag:lavfi.r128.S=-21.973|tag:lavfi.r128.I=-23.850|tag:lavfi.r128.LRA=4.130|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.200
+pkt_pts=854400|tag:lavfi.r128.M=-23.297|tag:lavfi.r128.S=-21.984|tag:lavfi.r128.I=-23.847|tag:lavfi.r128.LRA=4.170|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.160
+pkt_pts=859200|tag:lavfi.r128.M=-22.936|tag:lavfi.r128.S=-21.898|tag:lavfi.r128.I=-23.841|tag:lavfi.r128.LRA=4.170|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.160
+pkt_pts=864000|tag:lavfi.r128.M=-22.360|tag:lavfi.r128.S=-21.736|tag:lavfi.r128.I=-23.831|tag:lavfi.r128.LRA=4.180|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.150
+pkt_pts=868800|tag:lavfi.r128.M=-20.997|tag:lavfi.r128.S=-21.601|tag:lavfi.r128.I=-23.809|tag:lavfi.r128.LRA=4.220|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.110
+pkt_pts=873600|tag:lavfi.r128.M=-20.852|tag:lavfi.r128.S=-21.651|tag:lavfi.r128.I=-23.786|tag:lavfi.r128.LRA=4.300|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.030
+pkt_pts=878400|tag:lavfi.r128.M=-21.194|tag:lavfi.r128.S=-21.695|tag:lavfi.r128.I=-23.766|tag:lavfi.r128.LRA=4.310|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-22.010
+pkt_pts=883200|tag:lavfi.r128.M=-22.598|tag:lavfi.r128.S=-21.862|tag:lavfi.r128.I=-23.759|tag:lavfi.r128.LRA=4.330|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.990
+pkt_pts=888000|tag:lavfi.r128.M=-24.897|tag:lavfi.r128.S=-22.013|tag:lavfi.r128.I=-23.764|tag:lavfi.r128.LRA=4.330|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.990
+pkt_pts=892800|tag:lavfi.r128.M=-25.212|tag:lavfi.r128.S=-22.080|tag:lavfi.r128.I=-23.771|tag:lavfi.r128.LRA=4.330|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.990
+pkt_pts=897600|tag:lavfi.r128.M=-24.334|tag:lavfi.r128.S=-22.191|tag:lavfi.r128.I=-23.774|tag:lavfi.r128.LRA=4.330|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.990
+pkt_pts=902400|tag:lavfi.r128.M=-22.984|tag:lavfi.r128.S=-22.176|tag:lavfi.r128.I=-23.769|tag:lavfi.r128.LRA=4.330|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.990
+pkt_pts=907200|tag:lavfi.r128.M=-21.388|tag:lavfi.r128.S=-21.996|tag:lavfi.r128.I=-23.753|tag:lavfi.r128.LRA=4.330|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.990
+pkt_pts=912000|tag:lavfi.r128.M=-20.307|tag:lavfi.r128.S=-21.928|tag:lavfi.r128.I=-23.725|tag:lavfi.r128.LRA=4.340|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.980
+pkt_pts=916800|tag:lavfi.r128.M=-20.094|tag:lavfi.r128.S=-21.838|tag:lavfi.r128.I=-23.695|tag:lavfi.r128.LRA=4.390|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.930
+pkt_pts=921600|tag:lavfi.r128.M=-20.032|tag:lavfi.r128.S=-21.756|tag:lavfi.r128.I=-23.665|tag:lavfi.r128.LRA=4.390|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.930
+pkt_pts=926400|tag:lavfi.r128.M=-20.060|tag:lavfi.r128.S=-21.599|tag:lavfi.r128.I=-23.635|tag:lavfi.r128.LRA=4.420|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.900
+pkt_pts=931200|tag:lavfi.r128.M=-20.372|tag:lavfi.r128.S=-21.507|tag:lavfi.r128.I=-23.610|tag:lavfi.r128.LRA=4.450|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.870
+pkt_pts=936000|tag:lavfi.r128.M=-20.643|tag:lavfi.r128.S=-21.468|tag:lavfi.r128.I=-23.588|tag:lavfi.r128.LRA=4.480|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.840
+pkt_pts=940800|tag:lavfi.r128.M=-20.647|tag:lavfi.r128.S=-21.389|tag:lavfi.r128.I=-23.567|tag:lavfi.r128.LRA=4.560|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.760
+pkt_pts=945600|tag:lavfi.r128.M=-21.341|tag:lavfi.r128.S=-21.431|tag:lavfi.r128.I=-23.552|tag:lavfi.r128.LRA=4.580|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.740
+pkt_pts=950400|tag:lavfi.r128.M=-21.704|tag:lavfi.r128.S=-21.530|tag:lavfi.r128.I=-23.540|tag:lavfi.r128.LRA=4.620|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.700
+pkt_pts=955200|tag:lavfi.r128.M=-21.778|tag:lavfi.r128.S=-21.527|tag:lavfi.r128.I=-23.529|tag:lavfi.r128.LRA=4.620|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.700
+pkt_pts=960000|tag:lavfi.r128.M=-22.390|tag:lavfi.r128.S=-21.613|tag:lavfi.r128.I=-23.523|tag:lavfi.r128.LRA=4.660|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=964800|tag:lavfi.r128.M=-22.355|tag:lavfi.r128.S=-21.682|tag:lavfi.r128.I=-23.516|tag:lavfi.r128.LRA=4.660|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=969600|tag:lavfi.r128.M=-22.697|tag:lavfi.r128.S=-21.739|tag:lavfi.r128.I=-23.512|tag:lavfi.r128.LRA=4.660|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=974400|tag:lavfi.r128.M=-22.814|tag:lavfi.r128.S=-21.745|tag:lavfi.r128.I=-23.508|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=979200|tag:lavfi.r128.M=-22.749|tag:lavfi.r128.S=-21.842|tag:lavfi.r128.I=-23.504|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=984000|tag:lavfi.r128.M=-23.155|tag:lavfi.r128.S=-21.856|tag:lavfi.r128.I=-23.502|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=988800|tag:lavfi.r128.M=-22.927|tag:lavfi.r128.S=-21.893|tag:lavfi.r128.I=-23.499|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=993600|tag:lavfi.r128.M=-22.583|tag:lavfi.r128.S=-21.800|tag:lavfi.r128.I=-23.494|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=998400|tag:lavfi.r128.M=-22.022|tag:lavfi.r128.S=-21.702|tag:lavfi.r128.I=-23.486|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1003200|tag:lavfi.r128.M=-21.852|tag:lavfi.r128.S=-21.729|tag:lavfi.r128.I=-23.476|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1008000|tag:lavfi.r128.M=-21.746|tag:lavfi.r128.S=-21.814|tag:lavfi.r128.I=-23.466|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1012800|tag:lavfi.r128.M=-21.751|tag:lavfi.r128.S=-21.912|tag:lavfi.r128.I=-23.456|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1017600|tag:lavfi.r128.M=-21.891|tag:lavfi.r128.S=-21.855|tag:lavfi.r128.I=-23.447|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1022400|tag:lavfi.r128.M=-21.392|tag:lavfi.r128.S=-21.759|tag:lavfi.r128.I=-23.435|tag:lavfi.r128.LRA=4.640|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1027200|tag:lavfi.r128.M=-21.375|tag:lavfi.r128.S=-21.660|tag:lavfi.r128.I=-23.422|tag:lavfi.r128.LRA=4.640|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1032000|tag:lavfi.r128.M=-21.806|tag:lavfi.r128.S=-21.620|tag:lavfi.r128.I=-23.413|tag:lavfi.r128.LRA=4.680|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1036800|tag:lavfi.r128.M=-21.826|tag:lavfi.r128.S=-21.550|tag:lavfi.r128.I=-23.404|tag:lavfi.r128.LRA=4.680|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1041600|tag:lavfi.r128.M=-22.447|tag:lavfi.r128.S=-21.588|tag:lavfi.r128.I=-23.399|tag:lavfi.r128.LRA=4.690|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.610
+pkt_pts=1046400|tag:lavfi.r128.M=-22.717|tag:lavfi.r128.S=-21.633|tag:lavfi.r128.I=-23.396|tag:lavfi.r128.LRA=4.690|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.610
+pkt_pts=1051200|tag:lavfi.r128.M=-23.325|tag:lavfi.r128.S=-21.845|tag:lavfi.r128.I=-23.396|tag:lavfi.r128.LRA=4.680|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1056000|tag:lavfi.r128.M=-23.105|tag:lavfi.r128.S=-21.933|tag:lavfi.r128.I=-23.394|tag:lavfi.r128.LRA=4.680|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1060800|tag:lavfi.r128.M=-23.086|tag:lavfi.r128.S=-22.015|tag:lavfi.r128.I=-23.393|tag:lavfi.r128.LRA=4.680|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1065600|tag:lavfi.r128.M=-22.412|tag:lavfi.r128.S=-22.001|tag:lavfi.r128.I=-23.388|tag:lavfi.r128.LRA=4.680|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1070400|tag:lavfi.r128.M=-20.845|tag:lavfi.r128.S=-21.992|tag:lavfi.r128.I=-23.372|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1075200|tag:lavfi.r128.M=-20.738|tag:lavfi.r128.S=-22.001|tag:lavfi.r128.I=-23.356|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1080000|tag:lavfi.r128.M=-20.165|tag:lavfi.r128.S=-21.924|tag:lavfi.r128.I=-23.335|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1084800|tag:lavfi.r128.M=-19.829|tag:lavfi.r128.S=-21.840|tag:lavfi.r128.I=-23.311|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1089600|tag:lavfi.r128.M=-20.699|tag:lavfi.r128.S=-21.887|tag:lavfi.r128.I=-23.295|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1094400|tag:lavfi.r128.M=-20.677|tag:lavfi.r128.S=-21.838|tag:lavfi.r128.I=-23.279|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1099200|tag:lavfi.r128.M=-20.121|tag:lavfi.r128.S=-21.654|tag:lavfi.r128.I=-23.259|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1104000|tag:lavfi.r128.M=-20.893|tag:lavfi.r128.S=-21.635|tag:lavfi.r128.I=-23.245|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1108800|tag:lavfi.r128.M=-19.603|tag:lavfi.r128.S=-21.450|tag:lavfi.r128.I=-23.220|tag:lavfi.r128.LRA=4.660|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.610
+pkt_pts=1113600|tag:lavfi.r128.M=-19.675|tag:lavfi.r128.S=-21.385|tag:lavfi.r128.I=-23.197|tag:lavfi.r128.LRA=4.670|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.600
+pkt_pts=1118400|tag:lavfi.r128.M=-20.415|tag:lavfi.r128.S=-21.339|tag:lavfi.r128.I=-23.180|tag:lavfi.r128.LRA=4.660|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.590
+pkt_pts=1123200|tag:lavfi.r128.M=-20.446|tag:lavfi.r128.S=-21.333|tag:lavfi.r128.I=-23.164|tag:lavfi.r128.LRA=4.690|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.560
+pkt_pts=1128000|tag:lavfi.r128.M=-21.361|tag:lavfi.r128.S=-21.254|tag:lavfi.r128.I=-23.154|tag:lavfi.r128.LRA=4.720|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.530
+pkt_pts=1132800|tag:lavfi.r128.M=-21.725|tag:lavfi.r128.S=-21.257|tag:lavfi.r128.I=-23.147|tag:lavfi.r128.LRA=4.720|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.530
+pkt_pts=1137600|tag:lavfi.r128.M=-22.311|tag:lavfi.r128.S=-21.311|tag:lavfi.r128.I=-23.143|tag:lavfi.r128.LRA=4.740|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.510
+pkt_pts=1142400|tag:lavfi.r128.M=-21.973|tag:lavfi.r128.S=-21.327|tag:lavfi.r128.I=-23.137|tag:lavfi.r128.LRA=4.780|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.470
+pkt_pts=1147200|tag:lavfi.r128.M=-22.032|tag:lavfi.r128.S=-21.275|tag:lavfi.r128.I=-23.132|tag:lavfi.r128.LRA=4.780|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.470
+pkt_pts=1152000|tag:lavfi.r128.M=-21.631|tag:lavfi.r128.S=-21.243|tag:lavfi.r128.I=-23.125|tag:lavfi.r128.LRA=4.800|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.450
+pkt_pts=1156800|tag:lavfi.r128.M=-20.494|tag:lavfi.r128.S=-21.139|tag:lavfi.r128.I=-23.110|tag:lavfi.r128.LRA=4.810|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.440
+pkt_pts=1161600|tag:lavfi.r128.M=-19.902|tag:lavfi.r128.S=-21.041|tag:lavfi.r128.I=-23.090|tag:lavfi.r128.LRA=4.860|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.390
+pkt_pts=1166400|tag:lavfi.r128.M=-20.221|tag:lavfi.r128.S=-21.104|tag:lavfi.r128.I=-23.073|tag:lavfi.r128.LRA=4.850|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.390
+pkt_pts=1171200|tag:lavfi.r128.M=-20.245|tag:lavfi.r128.S=-21.080|tag:lavfi.r128.I=-23.057|tag:lavfi.r128.LRA=4.900|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.340
+pkt_pts=1176000|tag:lavfi.r128.M=-21.470|tag:lavfi.r128.S=-21.099|tag:lavfi.r128.I=-23.049|tag:lavfi.r128.LRA=4.900|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.340
+pkt_pts=1180800|tag:lavfi.r128.M=-22.623|tag:lavfi.r128.S=-21.123|tag:lavfi.r128.I=-23.047|tag:lavfi.r128.LRA=4.910|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.330
+pkt_pts=1185600|tag:lavfi.r128.M=-22.312|tag:lavfi.r128.S=-21.090|tag:lavfi.r128.I=-23.044|tag:lavfi.r128.LRA=4.920|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.320
+pkt_pts=1190400|tag:lavfi.r128.M=-22.937|tag:lavfi.r128.S=-21.099|tag:lavfi.r128.I=-23.043|tag:lavfi.r128.LRA=4.960|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.280
+pkt_pts=1195200|tag:lavfi.r128.M=-22.401|tag:lavfi.r128.S=-21.017|tag:lavfi.r128.I=-23.041|tag:lavfi.r128.LRA=4.980|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.260
+pkt_pts=1200000|tag:lavfi.r128.M=-22.004|tag:lavfi.r128.S=-21.018|tag:lavfi.r128.I=-23.036|tag:lavfi.r128.LRA=4.980|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.260
+pkt_pts=1204800|tag:lavfi.r128.M=-22.416|tag:lavfi.r128.S=-21.030|tag:lavfi.r128.I=-23.033|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1209600|tag:lavfi.r128.M=-22.481|tag:lavfi.r128.S=-21.106|tag:lavfi.r128.I=-23.031|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1214400|tag:lavfi.r128.M=-22.841|tag:lavfi.r128.S=-21.245|tag:lavfi.r128.I=-23.030|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1219200|tag:lavfi.r128.M=-23.663|tag:lavfi.r128.S=-21.332|tag:lavfi.r128.I=-23.033|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1224000|tag:lavfi.r128.M=-22.728|tag:lavfi.r128.S=-21.357|tag:lavfi.r128.I=-23.031|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1228800|tag:lavfi.r128.M=-23.016|tag:lavfi.r128.S=-21.530|tag:lavfi.r128.I=-23.031|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1233600|tag:lavfi.r128.M=-22.934|tag:lavfi.r128.S=-21.518|tag:lavfi.r128.I=-23.031|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1238400|tag:lavfi.r128.M=-21.320|tag:lavfi.r128.S=-21.426|tag:lavfi.r128.I=-23.023|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1243200|tag:lavfi.r128.M=-21.282|tag:lavfi.r128.S=-21.541|tag:lavfi.r128.I=-23.015|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1248000|tag:lavfi.r128.M=-20.639|tag:lavfi.r128.S=-21.490|tag:lavfi.r128.I=-23.002|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1252800|tag:lavfi.r128.M=-20.626|tag:lavfi.r128.S=-21.711|tag:lavfi.r128.I=-22.990|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1257600|tag:lavfi.r128.M=-21.333|tag:lavfi.r128.S=-21.710|tag:lavfi.r128.I=-22.982|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1262400|tag:lavfi.r128.M=-21.384|tag:lavfi.r128.S=-21.694|tag:lavfi.r128.I=-22.975|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1267200|tag:lavfi.r128.M=-21.410|tag:lavfi.r128.S=-21.639|tag:lavfi.r128.I=-22.968|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1272000|tag:lavfi.r128.M=-21.461|tag:lavfi.r128.S=-21.725|tag:lavfi.r128.I=-22.961|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1276800|tag:lavfi.r128.M=-21.846|tag:lavfi.r128.S=-21.726|tag:lavfi.r128.I=-22.956|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1281600|tag:lavfi.r128.M=-22.482|tag:lavfi.r128.S=-21.713|tag:lavfi.r128.I=-22.954|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1286400|tag:lavfi.r128.M=-22.681|tag:lavfi.r128.S=-21.720|tag:lavfi.r128.I=-22.953|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1291200|tag:lavfi.r128.M=-22.718|tag:lavfi.r128.S=-21.804|tag:lavfi.r128.I=-22.952|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1296000|tag:lavfi.r128.M=-22.849|tag:lavfi.r128.S=-21.873|tag:lavfi.r128.I=-22.952|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1300800|tag:lavfi.r128.M=-23.041|tag:lavfi.r128.S=-22.068|tag:lavfi.r128.I=-22.952|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1305600|tag:lavfi.r128.M=-23.898|tag:lavfi.r128.S=-22.285|tag:lavfi.r128.I=-22.956|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1310400|tag:lavfi.r128.M=-24.280|tag:lavfi.r128.S=-22.343|tag:lavfi.r128.I=-22.960|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1315200|tag:lavfi.r128.M=-25.072|tag:lavfi.r128.S=-22.479|tag:lavfi.r128.I=-22.966|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1320000|tag:lavfi.r128.M=-25.530|tag:lavfi.r128.S=-22.491|tag:lavfi.r128.I=-22.973|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1324800|tag:lavfi.r128.M=-25.269|tag:lavfi.r128.S=-22.536|tag:lavfi.r128.I=-22.980|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1329600|tag:lavfi.r128.M=-25.127|tag:lavfi.r128.S=-22.630|tag:lavfi.r128.I=-22.986|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1334400|tag:lavfi.r128.M=-24.909|tag:lavfi.r128.S=-22.673|tag:lavfi.r128.I=-22.991|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1339200
diff --git a/tests/ref/fate/filter-metadata-scenedetect b/tests/ref/fate/filter-metadata-scenedetect
new file mode 100644
index 0000000..67251df
--- /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
--- /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..874a991 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, 0x57a27a9b
+0, 1, 1, 1, 152064, 0x25c16856
+0, 2, 2, 1, 152064, 0x19adf9cc
+0, 3, 3, 1, 152064, 0x974e9a66
+0, 4, 4, 1, 152064, 0x3c68cbb8
+0, 5, 5, 1, 152064, 0x56c397f9
+0, 6, 6, 1, 152064, 0x9be92877
+0, 7, 7, 1, 152064, 0x53d12880
+0, 8, 8, 1, 152064, 0x31eb35a2
+0, 9, 9, 1, 152064, 0x86cd1566
+0, 10, 10, 1, 152064, 0xcf5951f5
+0, 11, 11, 1, 152064, 0x35c30986
+0, 12, 12, 1, 152064, 0x58e8eb9a
+0, 13, 13, 1, 152064, 0x63dfce6a
+0, 14, 14, 1, 152064, 0xbd2e4cc7
+0, 15, 15, 1, 152064, 0x3320ba14
+0, 16, 16, 1, 152064, 0xc757dd0a
+0, 17, 17, 1, 152064, 0x9f05ed64
+0, 18, 18, 1, 152064, 0x0f292094
+0, 19, 19, 1, 152064, 0x3ef899fc
+0, 20, 20, 1, 152064, 0x9a09b168
+0, 21, 21, 1, 152064, 0x6e2de51e
+0, 22, 22, 1, 152064, 0x6dcae8ee
+0, 23, 23, 1, 152064, 0x8a5e29d8
+0, 24, 24, 1, 152064, 0x91cce46b
+0, 25, 25, 1, 152064, 0xf576ab0d
+0, 26, 26, 1, 152064, 0x3301a89b
+0, 27, 27, 1, 152064, 0xc4b6130c
+0, 28, 28, 1, 152064, 0x37c00be0
+0, 29, 29, 1, 152064, 0xd210b7ca
+0, 30, 30, 1, 152064, 0x9eb783f2
+0, 31, 31, 1, 152064, 0xfe9e9f79
+0, 32, 32, 1, 152064, 0xcedbb511
+0, 33, 33, 1, 152064, 0xf14efe8d
+0, 34, 34, 1, 152064, 0x603fbef5
+0, 35, 35, 1, 152064, 0x82a36887
+0, 36, 36, 1, 152064, 0x8494465a
+0, 37, 37, 1, 152064, 0x5ae9429a
+0, 38, 38, 1, 152064, 0x7533853b
+0, 39, 39, 1, 152064, 0xcf7b8cb2
+0, 40, 40, 1, 152064, 0x9b297e6d
+0, 41, 41, 1, 152064, 0x0182b2db
+0, 42, 42, 1, 152064, 0xa2a9bcf0
+0, 43, 43, 1, 152064, 0xc77c11f8
+0, 44, 44, 1, 152064, 0xf0add83a
+0, 45, 45, 1, 152064, 0x81315436
+0, 46, 46, 1, 152064, 0x662e18cf
+0, 47, 47, 1, 152064, 0x6d5c96e6
+0, 48, 48, 1, 152064, 0x3ca384c3
+0, 49, 49, 1, 152064, 0x6688c0e0
diff --git a/tests/ref/fate/filter-overlay_rgb b/tests/ref/fate/filter-overlay_rgb
new file mode 100644
index 0000000..2b1ce18
--- /dev/null
+++ b/tests/ref/fate/filter-overlay_rgb
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 304128, 0xd4531e28
+0, 1, 1, 1, 304128, 0xfb069ecd
+0, 2, 2, 1, 304128, 0x4c376898
+0, 3, 3, 1, 304128, 0x5a0c7282
+0, 4, 4, 1, 304128, 0x4802850a
+0, 5, 5, 1, 304128, 0xf670e9cc
+0, 6, 6, 1, 304128, 0x5189c380
+0, 7, 7, 1, 304128, 0x14d6de42
+0, 8, 8, 1, 304128, 0xb65df5f1
+0, 9, 9, 1, 304128, 0xc2f89ef5
+0, 10, 10, 1, 304128, 0xde29db6b
+0, 11, 11, 1, 304128, 0x10a71aae
+0, 12, 12, 1, 304128, 0xf53d02ef
+0, 13, 13, 1, 304128, 0x4b3632ca
+0, 14, 14, 1, 304128, 0xce140f66
+0, 15, 15, 1, 304128, 0x4bedf6f1
+0, 16, 16, 1, 304128, 0xcc5edbd0
+0, 17, 17, 1, 304128, 0x836a556a
+0, 18, 18, 1, 304128, 0x3537c635
+0, 19, 19, 1, 304128, 0x400df2dd
+0, 20, 20, 1, 304128, 0x4292ccb3
+0, 21, 21, 1, 304128, 0x2f71db21
+0, 22, 22, 1, 304128, 0xa40b997c
+0, 23, 23, 1, 304128, 0xeee30551
+0, 24, 24, 1, 304128, 0x4f7bf0cb
+0, 25, 25, 1, 304128, 0x9a70dfe0
+0, 26, 26, 1, 304128, 0xc140124f
+0, 27, 27, 1, 304128, 0x275bca59
+0, 28, 28, 1, 304128, 0x4c62ceee
+0, 29, 29, 1, 304128, 0xc1d54279
+0, 30, 30, 1, 304128, 0xae7ef047
+0, 31, 31, 1, 304128, 0x331570a8
+0, 32, 32, 1, 304128, 0x10db2de2
+0, 33, 33, 1, 304128, 0xcc60fdfb
+0, 34, 34, 1, 304128, 0xe2cffcfa
+0, 35, 35, 1, 304128, 0x5a7ff1fb
+0, 36, 36, 1, 304128, 0xa39a4e47
+0, 37, 37, 1, 304128, 0x79e40e52
+0, 38, 38, 1, 304128, 0x53d0d393
+0, 39, 39, 1, 304128, 0xeb5fcfc1
+0, 40, 40, 1, 304128, 0x8923f95f
+0, 41, 41, 1, 304128, 0xd27a2b71
+0, 42, 42, 1, 304128, 0xe4fdd79e
+0, 43, 43, 1, 304128, 0xcd8fb238
+0, 44, 44, 1, 304128, 0x65e6eaaf
+0, 45, 45, 1, 304128, 0x41bfcb1b
+0, 46, 46, 1, 304128, 0xbecabb09
+0, 47, 47, 1, 304128, 0xfa04a0ef
+0, 48, 48, 1, 304128, 0xa43d9356
+0, 49, 49, 1, 304128, 0x56fd6ae0
diff --git a/tests/ref/fate/filter-overlay_yuv420 b/tests/ref/fate/filter-overlay_yuv420
new file mode 100644
index 0000000..c79518e
--- /dev/null
+++ b/tests/ref/fate/filter-overlay_yuv420
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 152064, 0xd5ac29f3
+0, 1, 1, 1, 152064, 0x95110a80
+0, 2, 2, 1, 152064, 0xe5c59adc
+0, 3, 3, 1, 152064, 0xe54df17c
+0, 4, 4, 1, 152064, 0xab22e1ac
+0, 5, 5, 1, 152064, 0x1a5db284
+0, 6, 6, 1, 152064, 0x6ee1895d
+0, 7, 7, 1, 152064, 0xb091cdff
+0, 8, 8, 1, 152064, 0x4df4dcd3
+0, 9, 9, 1, 152064, 0xb00ef49e
+0, 10, 10, 1, 152064, 0x11b61be4
+0, 11, 11, 1, 152064, 0x4e6d0b38
+0, 12, 12, 1, 152064, 0x029d65db
+0, 13, 13, 1, 152064, 0x8123d3a6
+0, 14, 14, 1, 152064, 0xbdd3701f
+0, 15, 15, 1, 152064, 0x958916e7
+0, 16, 16, 1, 152064, 0xe7973608
+0, 17, 17, 1, 152064, 0xd6be4edf
+0, 18, 18, 1, 152064, 0x3571a14f
+0, 19, 19, 1, 152064, 0xde150ddd
+0, 20, 20, 1, 152064, 0xb5e33eb1
+0, 21, 21, 1, 152064, 0xdd258601
+0, 22, 22, 1, 152064, 0x4335a59d
+0, 23, 23, 1, 152064, 0xa652cb99
+0, 24, 24, 1, 152064, 0x42cc6e6e
+0, 25, 25, 1, 152064, 0xc7540c4b
+0, 26, 26, 1, 152064, 0xb495dc85
+0, 27, 27, 1, 152064, 0x2aa11cfa
+0, 28, 28, 1, 152064, 0x8e4d44de
+0, 29, 29, 1, 152064, 0x2e9e550f
+0, 30, 30, 1, 152064, 0x995839ee
+0, 31, 31, 1, 152064, 0xb55647d7
+0, 32, 32, 1, 152064, 0x7fc556f7
+0, 33, 33, 1, 152064, 0x894f9acf
+0, 34, 34, 1, 152064, 0x5ea68479
+0, 35, 35, 1, 152064, 0x9d0fdb97
+0, 36, 36, 1, 152064, 0x8e6d4cff
+0, 37, 37, 1, 152064, 0xb315621c
+0, 38, 38, 1, 152064, 0x307b23a1
+0, 39, 39, 1, 152064, 0x41f246da
+0, 40, 40, 1, 152064, 0x8af934d5
+0, 41, 41, 1, 152064, 0x5d327ac0
+0, 42, 42, 1, 152064, 0x49b46cdf
+0, 43, 43, 1, 152064, 0x799eb970
+0, 44, 44, 1, 152064, 0x424b88cc
+0, 45, 45, 1, 152064, 0xfbcff8df
+0, 46, 46, 1, 152064, 0x70f7c722
+0, 47, 47, 1, 152064, 0x29a55d83
+0, 48, 48, 1, 152064, 0xff2430be
+0, 49, 49, 1, 152064, 0x02438701
diff --git a/tests/ref/fate/filter-overlay_yuv444 b/tests/ref/fate/filter-overlay_yuv444
new file mode 100644
index 0000000..01b92dc
--- /dev/null
+++ b/tests/ref/fate/filter-overlay_yuv444
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 405504, 0xbbfccc5d
+0, 1, 1, 1, 405504, 0xac9682d3
+0, 2, 2, 1, 405504, 0x6f7426c4
+0, 3, 3, 1, 405504, 0x43469a25
+0, 4, 4, 1, 405504, 0x75f7e902
+0, 5, 5, 1, 405504, 0xad19a433
+0, 6, 6, 1, 405504, 0xf11090f3
+0, 7, 7, 1, 405504, 0xe8ce9d18
+0, 8, 8, 1, 405504, 0xcf24926c
+0, 9, 9, 1, 405504, 0x740999d2
+0, 10, 10, 1, 405504, 0xb588dabd
+0, 11, 11, 1, 405504, 0x3e49d8d1
+0, 12, 12, 1, 405504, 0xe3d980ae
+0, 13, 13, 1, 405504, 0x70c9c2a3
+0, 14, 14, 1, 405504, 0x6b704efc
+0, 15, 15, 1, 405504, 0x43e92e97
+0, 16, 16, 1, 405504, 0x36c884fa
+0, 17, 17, 1, 405504, 0xaf19b6d7
+0, 18, 18, 1, 405504, 0x5478dbb2
+0, 19, 19, 1, 405504, 0xb09f552c
+0, 20, 20, 1, 405504, 0x0bb97177
+0, 21, 21, 1, 405504, 0xaf2b8660
+0, 22, 22, 1, 405504, 0xe0ef2941
+0, 23, 23, 1, 405504, 0x5d934bc5
+0, 24, 24, 1, 405504, 0x5fff55ec
+0, 25, 25, 1, 405504, 0xcdf4359f
+0, 26, 26, 1, 405504, 0x3a773cd9
+0, 27, 27, 1, 405504, 0x73991118
+0, 28, 28, 1, 405504, 0x7dc1088b
+0, 29, 29, 1, 405504, 0x878e06c8
+0, 30, 30, 1, 405504, 0xcfee8070
+0, 31, 31, 1, 405504, 0x563a6a8b
+0, 32, 32, 1, 405504, 0xb6af32d8
+0, 33, 33, 1, 405504, 0x7a0e3783
+0, 34, 34, 1, 405504, 0xcd3e3835
+0, 35, 35, 1, 405504, 0x0e7df06c
+0, 36, 36, 1, 405504, 0x61aaa4ff
+0, 37, 37, 1, 405504, 0x3c5998cc
+0, 38, 38, 1, 405504, 0x81b5c32a
+0, 39, 39, 1, 405504, 0xf8ca41ad
+0, 40, 40, 1, 405504, 0x109aa08e
+0, 41, 41, 1, 405504, 0xb9c6a26f
+0, 42, 42, 1, 405504, 0xd221a69f
+0, 43, 43, 1, 405504, 0x670bda84
+0, 44, 44, 1, 405504, 0xf9903d5b
+0, 45, 45, 1, 405504, 0xe19d1db4
+0, 46, 46, 1, 405504, 0xcefa1fea
+0, 47, 47, 1, 405504, 0x00b9fe31
+0, 48, 48, 1, 405504, 0x051a319f
+0, 49, 49, 1, 405504, 0x2d73bdd5
diff --git a/tests/ref/fate/filter-pad b/tests/ref/fate/filter-pad
new file mode 100644
index 0000000..7a6f61e
--- /dev/null
+++ b/tests/ref/fate/filter-pad
@@ -0,0 +1 @@
+pad 8122d716097523d0875e2d55b0926105
diff --git a/tests/ref/fate/filter-pixdesc b/tests/ref/fate/filter-pixdesc
index 23452ae..1ab928b 100644
--- a/tests/ref/fate/filter-pixdesc
+++ b/tests/ref/fate/filter-pixdesc
@@ -1,89 +1,112 @@
-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 89d6e4b116e3bd542fa09a19a977ad16
+gbrp10be 5dc62e2d01fa7c19a57abe48246f2232
+gbrp10le 0cac205a304b59811ce30fcad49b3527
+gbrp12be de1d2a6b1d189bce9b9a2cf322c31c24
+gbrp12le e3267ef00bb48778df21a386416d2e14
+gbrp14be 7979d158b30c0b45db97aba2228d15fc
+gbrp14le d32b6c73a820f9d03a779a996924893d
+gbrp9be 2478d1c27ae4ec94ec4b5e439128af0c
+gbrp9le 640240ca2663e48f0bacd8edb5242c7d
+gray 1e5e2b8548843a6898eedd9c974c422c
+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 d5729f8c76250a9b18cb149b396f1bfb
+rgba64le fae0a6afdaee94cb98e3ab9a702c8ecc
+uyvy422 3f411f947e3ac8f842c88e717d68bd9a
+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
+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..dba8fec 100644
--- a/tests/ref/fate/filter-pixfmts-copy
+++ b/tests/ref/fate/filter-pixfmts-copy
@@ -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 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 89d6e4b116e3bd542fa09a19a977ad16
+gbrp10be 5dc62e2d01fa7c19a57abe48246f2232
+gbrp10le 0cac205a304b59811ce30fcad49b3527
+gbrp12be de1d2a6b1d189bce9b9a2cf322c31c24
+gbrp12le e3267ef00bb48778df21a386416d2e14
+gbrp14be 7979d158b30c0b45db97aba2228d15fc
+gbrp14le d32b6c73a820f9d03a779a996924893d
+gbrp9be 2478d1c27ae4ec94ec4b5e439128af0c
+gbrp9le 640240ca2663e48f0bacd8edb5242c7d
+gray 1e5e2b8548843a6898eedd9c974c422c
+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 d5729f8c76250a9b18cb149b396f1bfb
+rgba64le fae0a6afdaee94cb98e3ab9a702c8ecc
+uyvy422 3f411f947e3ac8f842c88e717d68bd9a
+xyz12be e1e6718ae1c83e904fbdf903d62e5808
+xyz12le 24e8a22c1bd7d637edb731d10b7c54d0
+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
+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..797aedc 100644
--- a/tests/ref/fate/filter-pixfmts-crop
+++ b/tests/ref/fate/filter-pixfmts-crop
@@ -1,42 +1,43 @@
-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
+abgr ef31d9057f6e65a7c3308a1b1daa98fa
+argb 5e5e261c4870e0de05d56ff640b9550a
+bgr24 44bec15f35513de7e957b3d59b53cb7b
+bgr48be 0b5ebce3c48eb8614d79e204b5268603
+bgr48le c4ab61a8b9d502132730c6abb6ffd84c
+bgr4_byte cab930dbe1fe77d58b41837ecdcb8460
+bgr555be 67162782fdb86813f446d8e1c21c73e9
+bgr555le 85913cfa8dab465f7dcfcfe7f9001a01
+bgr565be ee9a1debb896d41c53a026f9e6ce006b
+bgr565le ab7b6055bc3b6b7edc9a5e4de43ec90d
+bgr8 f85ff16e21d922ad6d32648ef3acfbfb
+bgra 9f2e37d73ad3b759fc9d6b12ee668c38
+gray 3266b99065a17cbd647f2339addc5303
+gray16be 02ac848ad4e28c06938599563ba81ff7
+gray16le 672aebfeb8a0f4067b3c6064340056e4
+pal8 e1fd50b8a8a67fb5abd8b44abc778bbb
+rgb24 d044123f1fe50f656f2101dd3f091ead
+rgb48be ef5507f88948b54218911d12e1dbef36
+rgb48le 6d045d5990d6ada64a112e3b581a7b38
+rgb4_byte 0f0f9ee31c65dc60da49bf98a1b06dcf
+rgb555be 48fa619bfd04f6dee05416b02605c031
+rgb555le 292cff1f824e49076bad50a07ab1c749
+rgb565be 0dd6f6a5a8713bd1c3d9826bb7a88eab
+rgb565le 6afd85faa8c6f0f330969539178eb9a2
+rgb8 87cf541b110e35a6f9a983e9cde85e15
+rgba 7abe1af7b97f5b9a7aa5ad3e4bf32f76
+yuv410p 126e0da1da4fd89be28087b8367bbb36
+yuv411p b94f0af107fc4796aca70c0a36d374c5
+yuv420p 74c6b331bd30f005e6c75a192423ad90
+yuv420p16be 2d3c84ebff77479e8c5b6e3e59ec4e45
+yuv420p16le e2c906f2751609bf8cbcbeb2f629319a
+yuv422p 124bc8d668072de1bb3b894cc4bae859
+yuv422p16be 3ec47e2709107fcc388b5e0abebf7eaf
+yuv422p16le a4183a62917bf8568fe11ff446dd18f9
+yuv440p 15c81c685fa5b9db95150caff14ff83f
+yuv444p 12b752f78af72666627cea2d0c274cdb
+yuv444p16be f2bf0e22a1d184e37eaa199a76cf22ba
+yuv444p16le c11b151dced5c8854d385373fa4dcc8f
+yuva420p 920c5d1b965eeb72e3a0e343696face3
+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..c1c7ea7
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-field
@@ -0,0 +1,115 @@
+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 55eab469e3e02ccc5a358565d9b1eaa7
+gbrp10be 38753e9ac21e13d76d1a83bd7272c026
+gbrp10le a65ff11ee79ae698550218549288e6cc
+gbrp12be 5f49bf3190b98221dab95056ab46bd96
+gbrp12le 3d1cd386205bc690407c81a007a79170
+gbrp14be 60e2efec11a36e7cb0db95e01603d9eb
+gbrp14le fdcdecdd2c8dc13561a3788ce0487c85
+gbrp9be 86380bf8eaeee32ec40d776f699394e5
+gbrp9le 1286d4558d9bc7c3d68261f4b43e3ba9
+gray 66a09b53f7d3f79dcb6096f3ec3740c5
+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 963f5e716b6de4cacf06c3ca9d02bee0
+rgba64le b333503ba90d51d0cd21ff7e60acd492
+uyvy422 a6a52504a16f09b8f2ec2405bc8190b5
+xyz12be 9d904fb640dd024e668acb9dc7b3f11f
+xyz12le 7f93c7d2981f1976108e941afa1363f8
+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
+yuvj420p 762dc6a157d0bee72da3e3d852668aef
+yuvj422p 8cec955c1c62b00b6798361ef82962b7
+yuvj440p 7b469444994d8b52766ee461bcb795ea
+yuvj444p b395162325af489c465a3e6a31fbb0e7
+yuyv422 1efb17cd0a48d2e956fd574ea6f412e7
diff --git a/tests/ref/fate/filter-pixfmts-hflip b/tests/ref/fate/filter-pixfmts-hflip
index 3741713..84a3519 100644
--- a/tests/ref/fate/filter-pixfmts-hflip
+++ b/tests/ref/fate/filter-pixfmts-hflip
@@ -1,42 +1,111 @@
-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 95fde5b6a767cf8d2679a4a6d18fdbe7
+gbrp10be 5ddc834dbf2198f6b1af36c66b185e2c
+gbrp10le 04814cbb805b66e8e085c7db4a548deb
+gbrp12be 8184b00342421c366764c091e9174260
+gbrp12le 1519cba0b6ddd7ee3df7c97670f1cbd5
+gbrp14be 10872df155aab67a13b98ad162908896
+gbrp14le 5fd363517fca5ef0ac725d1c047f2e75
+gbrp9be 187c83736d4fe1d7c8491609debc8f86
+gbrp9le 5476b0787da2d928d98d4cda60537fb5
+gray 35b50e78d5d27255f43e642a404dd708
+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 d5562166a3fef8a65c15898b8e792300
+rgba64le babf9eb683b2886289562cf465da6738
+xyz12be 4738d2cb5321376d5eed70930f47a953
+xyz12le 51288f3440c8584406b332545d69c5a9
+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
+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
--- /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..5e7dc5f
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-il
@@ -0,0 +1,114 @@
+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 b85cfeb0e34559ffb4b2e4f1209a3712
+gbrp10be 5487219fee31607d6b19aa0d302fb42f
+gbrp10le 7975e53a9e03a8acfa877334ae5e9d1d
+gbrp12be 34bd529e3b085e813e7471e5a5951423
+gbrp12le 14716b36ee4043158f24b49b6a723213
+gbrp14be 426ac36ea666041afd39f842dbdd683c
+gbrp14le e0823115de7b2e44c25e1c59dd204ac1
+gbrp9be 0db6ce2fe6a7fc2d5c7d6d4f0decd112
+gbrp9le 00a1a9fe310753a28c0512568a317c67
+gray 4dd4ea934fdbf689fdcf665856c402ff
+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 ca82ddd3f4182c21f8708cbe5368b57a
+rgba64le 53236255cdc370f549484008f61c04e8
+uyvy422 8be40aded4b407ff66305911ba5ce2ce
+xyz12be 1cbb1f72c6875934e66f50f499a62cc3
+xyz12le ba8c6eab49e58eace392ef0aeedbf677
+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
+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
--- /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..387464be2
--- /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..dba8fec 100644
--- a/tests/ref/fate/filter-pixfmts-null
+++ b/tests/ref/fate/filter-pixfmts-null
@@ -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 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 89d6e4b116e3bd542fa09a19a977ad16
+gbrp10be 5dc62e2d01fa7c19a57abe48246f2232
+gbrp10le 0cac205a304b59811ce30fcad49b3527
+gbrp12be de1d2a6b1d189bce9b9a2cf322c31c24
+gbrp12le e3267ef00bb48778df21a386416d2e14
+gbrp14be 7979d158b30c0b45db97aba2228d15fc
+gbrp14le d32b6c73a820f9d03a779a996924893d
+gbrp9be 2478d1c27ae4ec94ec4b5e439128af0c
+gbrp9le 640240ca2663e48f0bacd8edb5242c7d
+gray 1e5e2b8548843a6898eedd9c974c422c
+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 d5729f8c76250a9b18cb149b396f1bfb
+rgba64le fae0a6afdaee94cb98e3ab9a702c8ecc
+uyvy422 3f411f947e3ac8f842c88e717d68bd9a
+xyz12be e1e6718ae1c83e904fbdf903d62e5808
+xyz12le 24e8a22c1bd7d637edb731d10b7c54d0
+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
+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..f8f8dd4 100644
--- a/tests/ref/fate/filter-pixfmts-pad
+++ b/tests/ref/fate/filter-pixfmts-pad
@@ -1,17 +1,26 @@
-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 23e8ef832c4aef52c6183f429ac86b32
+gbrp 74f83deee9866bbdce3f91fa2aeddaaa
+gray b1abadae3718522aa57a7972da8cbe17
+rgb0 b1977b45634c4db58a183a07feb2acff
+rgb24 e73de9dc0fdd78f4853c168603cc7aba
+rgba 5a36df3c5ba623b589728a5a442e98e2
+yuv410p ff246b8b41d3d4a3eb90414ae3031123
+yuv411p a82c606c665fa747679aa8bfffa8a5db
+yuv420p 0fe4d9031999f83ca96292ec2025f272
+yuv422p 5e0bffdac30b39f1bae9ec54fd9a6a34
+yuv440p 5e338303cd89d1d76ab918e5bec1e90d
+yuv444p 248bdf9747d5c3718580dc2279e2e273
+yuva420p b5bdefbb0c5b302b6d18ee4df7c1d7c7
+yuva422p 8b56b36d9eb3c382d2a5a695107e759d
+yuva444p 389cf95e98bf24684a42d5d67b913e16
+yuvj420p d182ac937d312e4894c1bc548883bf1c
+yuvj422p 26ac91b5daf6f2f1f3c22be489e994a3
+yuvj440p 63e2b94f81e0a6f2868055a4c8258b63
+yuvj444p 64f103c7db8fc803d062db7ed2b8dc76
diff --git a/tests/ref/fate/filter-pixfmts-scale b/tests/ref/fate/filter-pixfmts-scale
index 80816ec..b354ddd 100644
--- a/tests/ref/fate/filter-pixfmts-scale
+++ b/tests/ref/fate/filter-pixfmts-scale
@@ -1,89 +1,115 @@
-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 710350573339f608b23e5bf8ea3327d0
+0rgb ba87d80ccd24ffb20ac711511132adb8
+abgr e448ff50225b119979987e55399e49e2
+argb ef03d804e0de6315fd59e3d2edaddb9d
+bgr0 93cd61cfcbef1789d2d5ccae4de75f79
+bgr24 793fc4c2b1c92ad4f7f4dca157e624d1
+bgr444be 9af6abe0bc74cdcc75b4ab2f441f5f67
+bgr444le b8c0e693ae2cbd7c03abcc3aeb4bf7b4
+bgr48be 3aa33b667b9baefe3f17ef44360688cd
+bgr48le eaf353ab363fbb279fd72d6c6e3b8855
+bgr4_byte a6e269daf7085504a01113ce5e8bff57
+bgr555be 9d71206c1a5373b8978126e5f5779726
+bgr555le 025caaa21fed9d14c382cac26af778c8
+bgr565be fca6f07daf23d9dd84381dd4c9afd959
+bgr565le f524e9f16bdd68b247dbcb621e543fc0
+bgr8 68a3a395043dc57335ad1f8e891229c5
+bgra 3eaf5489b8aa13a3388aad3751b597bf
+gbrap 76ddf2bedea40c8743f4117b786d4773
+gbrp 7b83ae32c1f76bd634e50f4797a74e92
+gbrp10be 77dae432c42fad019c286753b0e4b0a8
+gbrp10le 7d3e7341423b1206e8a6a3a02b48b5d7
+gbrp12be 2c237c413e765024eb3f73d8c5e03df8
+gbrp12le 9a0c9eda1f16d640663c729d4bb88024
+gbrp14be 2b4f1928a5ef53d0a216b3b10fa11ca0
+gbrp14le 47100ec39fad45579de1dff56fe17117
+gbrp9be c345137de0aa4b0536a00009e8e11267
+gbrp9le b798662b2ba4cdf21ad6a6d4c1fe1b72
+gray 045c35e6cc7d41460f2b96b3e254deab
+gray16be 70064f9acdc5e3935ccda67e765bf2fb
+gray16le 578241fb43029e5ae841a3c94d940dce
+monob 91ec2a25b13f6ca34d42da778b217de0
+monow a991455fda8f60f373aeb744456996b9
+nv12 0617f1e13ae4a43d4cb49282b9c02f71
+nv21 8a00d5d29766c1251eeda74c0ddee3f2
+pal8 7849884994cf99604f025b053332d08d
+rgb0 6a9d26ebf674f02b5a8830583ba7a171
+rgb24 1de2978e23ad10b9b4ca2777688b4546
+rgb444be 88f534c5d07ebf5a4374484aed540893
+rgb444le c243685bfad7c243a78892a0dafe2b9f
+rgb48be 874c8e2305ce9d82165ffddf2854d1f2
+rgb48le 877075f2ff2d9a0aec6fec843385f126
+rgb4_byte 4a8b119cf1996efe273302da29cbfbfb
+rgb555be 8aeefa1fc4eba200abee3b1eb52186af
+rgb555le 0495a7c13f9b0d0253379d5ae90cf6c4
+rgb565be 5168b66e69c25351948085e5fc51bb3a
+rgb565le 301a4d41f0db3aaed341d812ed0d7927
+rgb8 8e5786e83099bc89d2e38a76e6dfcc52
+rgba de6a65b8c01bdad84e575202ca8b66a0
+rgba64be fdc6467660a45d6e9dad59339be2ec4c
+rgba64le b208b8fdd403c1a24bbef0473a89d978
+uyvy422 479105bc4c7fbb4a33ca8745aa8c2de8
+xyz12be e9be06091b6dd0b67598eaf8bd86a78e
+xyz12le 05a9bbd16d81183ef3db04447648e3b1
+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
+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
--- /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..2474171
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-swapuv
@@ -0,0 +1,61 @@
+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
+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..300713f
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-tinterlace_merge
@@ -0,0 +1,10 @@
+gray c996e583bbc5a6f380463142eb77b7c6
+yuv410p c9bad1317b496071d6d895238638e07d
+yuv420p 9794d11e59ec7bcdf9e30a433e4137b1
+yuv422p e852e61e455db8ee3981ea942d510b0f
+yuv444p a38a3f65d2f358cde5e9547c897cfcd5
+yuva420p c1dc15d6ee78587d9f825acd795673d7
+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..722ac85
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-tinterlace_pad
@@ -0,0 +1,10 @@
+gray 25a7d1ccf1a06c1a8a0520c1e6cb30ff
+yuv410p 17163d1b4f21d894598fc62e6aeb8141
+yuv420p f8bbae33295741c1c17d33ff8ee16f7f
+yuv422p 4fa67d1580d3453942bb0950c5784f6e
+yuv444p f0558305fb7ca65b5b86d3ee88c4201e
+yuva420p 7c76c0ca03a62275d25e8140c68da2b9
+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..70f5d5d 100644
--- a/tests/ref/fate/filter-pixfmts-vflip
+++ b/tests/ref/fate/filter-pixfmts-vflip
@@ -1,89 +1,115 @@
-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 7852e9bbe52cfad9bab8081a5c7a5a31
+gbrp10be f591c6c98396baf3242837827081f2f7
+gbrp10le c5edb9bb566edbc8c478595ac6ab070f
+gbrp12be c61c19ad1bcca18719dd071e2cb77287
+gbrp12le 334a6c802ae0e15d9e0950c27ce4a457
+gbrp14be e24459d3b4a1e9c56ec3658c525b7a32
+gbrp14le 99207ef7c7dcb1d1369dc3fe3b5dc261
+gbrp9be 1daea1677f8a62c5a1ef8959c5e0e4b0
+gbrp9le e3cca50b844e7dd326eadf6e38fab84b
+gray a53528cdf80ed31c9897042a2ea16618
+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 d438e49304f65a5b7c5f09fcc1b979df
+rgba64le 9acbefa0f25441491d780b57aac11346
+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
+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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /dev/null
+++ b/tests/ref/fate/filter-setsar
@@ -0,0 +1 @@
+setsar 04b06d4622b116cdae756d4b475b9d5d
diff --git a/tests/ref/fate/filter-telecine b/tests/ref/fate/filter-telecine
new file mode 100644
index 0000000..b8a13a9
--- /dev/null
+++ b/tests/ref/fate/filter-telecine
@@ -0,0 +1,63 @@
+#tb 0: 4/125
+0, 0, 0, 1, 152064, 0x05b789ef
+0, 1, 1, 1, 152064, 0x4bb46551
+0, 2, 2, 1, 152064, 0x40692c80
+0, 3, 3, 1, 152064, 0xd7ad04cb
+0, 4, 4, 1, 152064, 0x2a8380b0
+0, 5, 5, 1, 152064, 0x4de3b652
+0, 6, 6, 1, 152064, 0xedb5a8e6
+0, 7, 7, 1, 152064, 0x549dfa8a
+0, 8, 8, 1, 152064, 0x447bc7b9
+0, 9, 9, 1, 152064, 0x5ab58bac
+0, 10, 10, 1, 152064, 0x1f1b8026
+0, 11, 11, 1, 152064, 0x91373915
+0, 12, 12, 1, 152064, 0x90895a6e
+0, 13, 13, 1, 152064, 0x793d075e
+0, 14, 14, 1, 152064, 0x30f5fcd5
+0, 15, 15, 1, 152064, 0xc711ad61
+0, 16, 16, 1, 152064, 0x24eca223
+0, 17, 17, 1, 152064, 0x0a4073dc
+0, 18, 18, 1, 152064, 0x06e34d70
+0, 19, 19, 1, 152064, 0xa91c0f05
+0, 20, 20, 1, 152064, 0x8e364e18
+0, 21, 21, 1, 152064, 0xb15d38c8
+0, 22, 22, 1, 152064, 0x6b2b2e46
+0, 23, 23, 1, 152064, 0xbd2320cb
+0, 24, 24, 1, 152064, 0xf34ddbff
+0, 25, 25, 1, 152064, 0xfc7bf570
+0, 26, 26, 1, 152064, 0x9dc72412
+0, 27, 27, 1, 152064, 0xa1242020
+0, 28, 28, 1, 152064, 0x1f939e6a
+0, 29, 29, 1, 152064, 0x2f2768ef
+0, 30, 30, 1, 152064, 0xce09f9d6
+0, 31, 31, 1, 152064, 0x95579936
+0, 32, 32, 1, 152064, 0x41181cbd
+0, 33, 33, 1, 152064, 0xe9cec847
+0, 34, 34, 1, 152064, 0xd780d887
+0, 35, 35, 1, 152064, 0x76d2a455
+0, 36, 36, 1, 152064, 0x6dc3650e
+0, 37, 37, 1, 152064, 0x8d165d23
+0, 38, 38, 1, 152064, 0x64f10efa
+0, 39, 39, 1, 152064, 0xe295c51e
+0, 40, 40, 1, 152064, 0xd766fc8d
+0, 41, 41, 1, 152064, 0xe22f7a30
+0, 42, 42, 1, 152064, 0xd8c68892
+0, 43, 43, 1, 152064, 0x26516b0e
+0, 44, 44, 1, 152064, 0xfa8d94fb
+0, 45, 45, 1, 152064, 0x4c9737ab
+0, 46, 46, 1, 152064, 0xa50d01f8
+0, 47, 47, 1, 152064, 0x82f12165
+0, 48, 48, 1, 152064, 0x113fadc0
+0, 49, 49, 1, 152064, 0x88734edd
+0, 50, 50, 1, 152064, 0xd2735925
+0, 51, 51, 1, 152064, 0xd4e49e08
+0, 52, 52, 1, 152064, 0x8cd54fc5
+0, 53, 53, 1, 152064, 0xae821cac
+0, 54, 54, 1, 152064, 0x575c20ec
+0, 55, 55, 1, 152064, 0xfd500471
+0, 56, 56, 1, 152064, 0x61b47e73
+0, 57, 57, 1, 152064, 0x213d5314
+0, 58, 58, 1, 152064, 0xb4ddd391
+0, 59, 59, 1, 152064, 0x6e88c5c2
+0, 60, 60, 1, 152064, 0xbb87b483
+0, 61, 61, 1, 152064, 0x4bbad8ea
diff --git a/tests/ref/fate/filter-thumbnail b/tests/ref/fate/filter-thumbnail
new file mode 100644
index 0000000..5cfbf50
--- /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
--- /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
--- /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
--- /dev/null
+++ b/tests/ref/fate/g729-0
@@ -0,0 +1,1000 @@
+0, 0, 160, 0xbb6d5aa0
+0, 900, 160, 0x91563d8d
+0, 1800, 160, 0x10a7535b
+0, 2700, 160, 0xa4f35594
+0, 3600, 160, 0x7f8e54e0
+0, 4500, 160, 0x85275000
+0, 5400, 160, 0x00734c7b
+0, 6300, 160, 0x8a2d544d
+0, 7200, 160, 0x97dc533c
+0, 8100, 160, 0xa7064ec4
+0, 9000, 160, 0xb7984a3c
+0, 9900, 160, 0x28334db6
+0, 10800, 160, 0x5838521f
+0, 11700, 160, 0x2337502c
+0, 12600, 160, 0x4a1e4599
+0, 13500, 160, 0x0d3858a8
+0, 14400, 160, 0xa0974b46
+0, 15300, 160, 0xc3254b93
+0, 16200, 160, 0x42b75231
+0, 17100, 160, 0x93634662
+0, 18000, 160, 0x11674fa1
+0, 18900, 160, 0xf2da5414
+0, 19800, 160, 0x97754dbc
+0, 20700, 160, 0x40a24d94
+0, 21600, 160, 0x26b34ebf
+0, 22500, 160, 0x7730542f
+0, 23400, 160, 0xb45254aa
+0, 24300, 160, 0xd8d752c3
+0, 25200, 160, 0x655c4a81
+0, 26100, 160, 0xa5da4f35
+0, 27000, 160, 0xd43551a1
+0, 27900, 160, 0x72a74e7d
+0, 28800, 160, 0xdb2150b3
+0, 29700, 160, 0x972852a1
+0, 30600, 160, 0xbae14c07
+0, 31500, 160, 0x23b54d57
+0, 32400, 160, 0x2d9650a5
+0, 33300, 160, 0xaf755107
+0, 34200, 160, 0xdb054f0e
+0, 35100, 160, 0x9f084cc0
+0, 36000, 160, 0x64ca5760
+0, 36900, 160, 0x3ea24be2
+0, 37800, 160, 0x93ea503b
+0, 38700, 160, 0xb6694afa
+0, 39600, 160, 0xf94c52e7
+0, 40500, 160, 0x2b7156b8
+0, 41400, 160, 0xbbdf414c
+0, 42300, 160, 0x10cd4ac8
+0, 43200, 160, 0x39885453
+0, 44100, 160, 0xa1505568
+0, 45000, 160, 0x86124ec1
+0, 45900, 160, 0xe2ab5489
+0, 46800, 160, 0x406254bc
+0, 47700, 160, 0x09044629
+0, 48600, 160, 0xb2ed5702
+0, 49500, 160, 0xd9ee5188
+0, 50400, 160, 0x59f7592a
+0, 51300, 160, 0x8f144c08
+0, 52200, 160, 0x90394e61
+0, 53100, 160, 0x79524df7
+0, 54000, 160, 0x58044674
+0, 54900, 160, 0x73b24d90
+0, 55800, 160, 0x80e257a1
+0, 56700, 160, 0xe8ff4caf
+0, 57600, 160, 0x1db84e3e
+0, 58500, 160, 0xd7db59d9
+0, 59400, 160, 0x43244c15
+0, 60300, 160, 0x1f63558f
+0, 61200, 160, 0xf0d851c6
+0, 62100, 160, 0x76484f3a
+0, 63000, 160, 0x5746551e
+0, 63900, 160, 0x83b54cd7
+0, 64800, 160, 0x97f550a1
+0, 65700, 160, 0x77c45340
+0, 66600, 160, 0xfd7b520a
+0, 67500, 160, 0x989a4e13
+0, 68400, 160, 0x9a8551c0
+0, 69300, 160, 0xa0cb4f93
+0, 70200, 160, 0xc568536f
+0, 71100, 160, 0x6fa74a95
+0, 72000, 160, 0xd550568b
+0, 72900, 160, 0xf88f4de5
+0, 73800, 160, 0x91285517
+0, 74700, 160, 0xdb675270
+0, 75600, 160, 0x606c53f9
+0, 76500, 160, 0x43f64601
+0, 77400, 160, 0x28b94b45
+0, 78300, 160, 0x7f2347f5
+0, 79200, 160, 0x84ba55db
+0, 80100, 160, 0x3ca3477c
+0, 81000, 160, 0x57d158ba
+0, 81900, 160, 0x2c3c506d
+0, 82800, 160, 0x59b34e5f
+0, 83700, 160, 0x014f530a
+0, 84600, 160, 0x877f4f76
+0, 85500, 160, 0x97a65c5f
+0, 86400, 160, 0xf643516d
+0, 87300, 160, 0x6ccc5242
+0, 88200, 160, 0x895450bd
+0, 89100, 160, 0xe246570e
+0, 90000, 160, 0xbb9f4a0c
+0, 90900, 160, 0x60e646fe
+0, 91800, 160, 0x546f515b
+0, 92700, 160, 0xc59254f0
+0, 93600, 160, 0xcad6551f
+0, 94500, 160, 0x14e14fac
+0, 95400, 160, 0x3cf94c52
+0, 96300, 160, 0x99b14f45
+0, 97200, 160, 0xfdb14dc7
+0, 98100, 160, 0x48f359e7
+0, 99000, 160, 0x186153e3
+0, 99900, 160, 0x047d4a78
+0, 100800, 160, 0x992f462b
+0, 101700, 160, 0x4a0e504d
+0, 102600, 160, 0x1f245275
+0, 103500, 160, 0x026959a9
+0, 104400, 160, 0x648846e7
+0, 105300, 160, 0xcac94cb3
+0, 106200, 160, 0x55e551a4
+0, 107100, 160, 0x767a5315
+0, 108000, 160, 0xbfde4d2b
+0, 108900, 160, 0x29bf4613
+0, 109800, 160, 0x8a8d5394
+0, 110700, 160, 0x36f94dae
+0, 111600, 160, 0x4cbf50ba
+0, 112500, 160, 0x9af44d8b
+0, 113400, 160, 0x6e8a519e
+0, 114300, 160, 0x496348b7
+0, 115200, 160, 0x95324eb2
+0, 116100, 160, 0x5bfe5118
+0, 117000, 160, 0xa1ff4c88
+0, 117900, 160, 0x86c2500a
+0, 118800, 160, 0xc53353c5
+0, 119700, 160, 0x062f52ee
+0, 120600, 160, 0x11cf522d
+0, 121500, 160, 0x054f5855
+0, 122400, 160, 0x8c4e44e9
+0, 123300, 160, 0x4d514fda
+0, 124200, 160, 0x5726568e
+0, 125100, 160, 0x281859ad
+0, 126000, 160, 0x3f3344f8
+0, 126900, 160, 0x2cbb3ee5
+0, 127800, 160, 0xa075551c
+0, 128700, 160, 0xafb25528
+0, 129600, 160, 0x9221478a
+0, 130500, 160, 0x6cb15634
+0, 131400, 160, 0xb5cf4523
+0, 132300, 160, 0x8a7a4f2c
+0, 133200, 160, 0x278e553d
+0, 134100, 160, 0x49054ad3
+0, 135000, 160, 0x5d7449bb
+0, 135900, 160, 0x67c346a0
+0, 136800, 160, 0x5d915bf8
+0, 137700, 160, 0x671355b2
+0, 138600, 160, 0xdfa84ee6
+0, 139500, 160, 0x4c3552d0
+0, 140400, 160, 0x63a1483c
+0, 141300, 160, 0x14c151ba
+0, 142200, 160, 0xf7434d78
+0, 143100, 160, 0x1c3652c9
+0, 144000, 160, 0x035b51da
+0, 144900, 160, 0x2bf6496b
+0, 145800, 160, 0x50a14f14
+0, 146700, 160, 0x518948f8
+0, 147600, 160, 0x7e784331
+0, 148500, 160, 0x73384dce
+0, 149400, 160, 0x11015066
+0, 150300, 160, 0xacc5525c
+0, 151200, 160, 0xf75a5431
+0, 152100, 160, 0xa78e4b8a
+0, 153000, 160, 0xd07955b0
+0, 153900, 160, 0x63164a03
+0, 154800, 160, 0x952f519e
+0, 155700, 160, 0xe5764f77
+0, 156600, 160, 0xa9255738
+0, 157500, 160, 0x65d64ce5
+0, 158400, 160, 0x8ab7507c
+0, 159300, 160, 0xf5265251
+0, 160200, 160, 0xa6a84d74
+0, 161100, 160, 0xc2594fee
+0, 162000, 160, 0xdfae5056
+0, 162900, 160, 0xa5a74c11
+0, 163800, 160, 0x5fdf4a21
+0, 164700, 160, 0x11014f8d
+0, 165600, 160, 0x08d0553f
+0, 166500, 160, 0x3036520e
+0, 167400, 160, 0xee3a464e
+0, 168300, 160, 0xbfd94949
+0, 169200, 160, 0x21625176
+0, 170100, 160, 0x6c714e8d
+0, 171000, 160, 0x055a4c05
+0, 171900, 160, 0xc7f35347
+0, 172800, 160, 0x82344b60
+0, 173700, 160, 0x99854ce4
+0, 174600, 160, 0x95504ec3
+0, 175500, 160, 0xe245502a
+0, 176400, 160, 0xb0e14a4c
+0, 177300, 160, 0x09835b86
+0, 178200, 160, 0xe9495220
+0, 179100, 160, 0xce9b514f
+0, 180000, 160, 0xbaf85695
+0, 180900, 160, 0x69aa3f1d
+0, 181800, 160, 0xd6a551b8
+0, 182700, 160, 0x4eb956e6
+0, 183600, 160, 0xdd6d4e58
+0, 184500, 160, 0xba1f4814
+0, 185400, 160, 0x4a604f48
+0, 186300, 160, 0xa8995890
+0, 187200, 160, 0x3a80616b
+0, 188100, 160, 0xfb796013
+0, 189000, 160, 0x8eba5c12
+0, 189900, 160, 0xd37859b9
+0, 190800, 160, 0x19a857c8
+0, 191700, 160, 0xec0e5a16
+0, 192600, 160, 0xd5335159
+0, 193500, 160, 0x560f4de7
+0, 194400, 160, 0x06d354c8
+0, 195300, 160, 0xdade5860
+0, 196200, 160, 0x093a512c
+0, 197100, 160, 0xb37b5098
+0, 198000, 160, 0x3eea537c
+0, 198900, 160, 0xf5c94f06
+0, 199800, 160, 0x552c4bb2
+0, 200700, 160, 0xea9a5a79
+0, 201600, 160, 0xd2645494
+0, 202500, 160, 0x5ba958ea
+0, 203400, 160, 0x54b559cf
+0, 204300, 160, 0x86bf5bba
+0, 205200, 160, 0xb89b6149
+0, 206100, 160, 0x1e825314
+0, 207000, 160, 0xf0d250cc
+0, 207900, 160, 0xc7ad53ba
+0, 208800, 160, 0x320c552f
+0, 209700, 160, 0xc62756f7
+0, 210600, 160, 0xa41351f7
+0, 211500, 160, 0x27ed4e78
+0, 212400, 160, 0x8d6047bc
+0, 213300, 160, 0xa45c48d0
+0, 214200, 160, 0x14da5400
+0, 215100, 160, 0x48514dd2
+0, 216000, 160, 0xec395318
+0, 216900, 160, 0xf3c85e4a
+0, 217800, 160, 0x657a63ed
+0, 218700, 160, 0xcc975c4d
+0, 219600, 160, 0x86125dd4
+0, 220500, 160, 0x6a3f6019
+0, 221400, 160, 0x84c05aeb
+0, 222300, 160, 0xe68561f7
+0, 223200, 160, 0x7ec763ae
+0, 224100, 160, 0x91bd5792
+0, 225000, 160, 0xb9365c8e
+0, 225900, 160, 0x42d7587a
+0, 226800, 160, 0x80a45453
+0, 227700, 160, 0x9ecf50c2
+0, 228600, 160, 0xc8de5173
+0, 229500, 160, 0x776952f7
+0, 230400, 160, 0x45f856c0
+0, 231300, 160, 0x729c4d73
+0, 232200, 160, 0xfd364a18
+0, 233100, 160, 0x709e587d
+0, 234000, 160, 0x288240e5
+0, 234900, 160, 0x16a6493f
+0, 235800, 160, 0x76db596f
+0, 236700, 160, 0x16c24a51
+0, 237600, 160, 0xc55b5a8f
+0, 238500, 160, 0x19024a2e
+0, 239400, 160, 0x16514d1b
+0, 240300, 160, 0x48bb5b82
+0, 241200, 160, 0x5a6e4d80
+0, 242100, 160, 0x6d404b0f
+0, 243000, 160, 0x57bc4e4a
+0, 243900, 160, 0xc10c5381
+0, 244800, 160, 0x34bd51d9
+0, 245700, 160, 0x5dcf52b7
+0, 246600, 160, 0xf61f57a7
+0, 247500, 160, 0x4e204934
+0, 248400, 160, 0xe18b4a3f
+0, 249300, 160, 0xb81256e3
+0, 250200, 160, 0x294047b2
+0, 251100, 160, 0x3ad559df
+0, 252000, 160, 0xd28d4d86
+0, 252900, 160, 0x67b75895
+0, 253800, 160, 0x191357b0
+0, 254700, 160, 0x8016556f
+0, 255600, 160, 0x62475c86
+0, 256500, 160, 0x0c975bc9
+0, 257400, 160, 0x901c5909
+0, 258300, 160, 0x9909567d
+0, 259200, 160, 0xce715b99
+0, 260100, 160, 0xae5062b1
+0, 261000, 160, 0x5bd056d6
+0, 261900, 160, 0xe3d3555a
+0, 262800, 160, 0xc4b1555c
+0, 263700, 160, 0x39c95649
+0, 264600, 160, 0x50145d11
+0, 265500, 160, 0xc0ba5307
+0, 266400, 160, 0x182455a3
+0, 267300, 160, 0x36c24e98
+0, 268200, 160, 0x1b5b52d0
+0, 269100, 160, 0xd38352d1
+0, 270000, 160, 0x6a1d5d2a
+0, 270900, 160, 0x50f05c44
+0, 271800, 160, 0xb2365dc1
+0, 272700, 160, 0x10825934
+0, 273600, 160, 0xcb4c61c2
+0, 274500, 160, 0x578252ab
+0, 275400, 160, 0xed99596c
+0, 276300, 160, 0xdfec6305
+0, 277200, 160, 0x97e2550a
+0, 278100, 160, 0xd60a56e1
+0, 279000, 160, 0xb6c4535e
+0, 279900, 160, 0x4d2e536c
+0, 280800, 160, 0xdef85cc7
+0, 281700, 160, 0xee985a98
+0, 282600, 160, 0x006a4cdb
+0, 283500, 160, 0xd06652ad
+0, 284400, 160, 0xeeee4ed6
+0, 285300, 160, 0xcb8b586d
+0, 286200, 160, 0x2ee4556e
+0, 287100, 160, 0x6d924c01
+0, 288000, 160, 0x7ff257cc
+0, 288900, 160, 0x67df5710
+0, 289800, 160, 0x0f704f29
+0, 290700, 160, 0x19dc53a7
+0, 291600, 160, 0xfbf44bc0
+0, 292500, 160, 0x640b5718
+0, 293400, 160, 0x2bfd4b91
+0, 294300, 160, 0xaae049bf
+0, 295200, 160, 0xca3154f6
+0, 296100, 160, 0x36064f2c
+0, 297000, 160, 0x28404919
+0, 297900, 160, 0x9c944fe3
+0, 298800, 160, 0xb4214c82
+0, 299700, 160, 0x442c514d
+0, 300600, 160, 0x44434ea5
+0, 301500, 160, 0x82a05aae
+0, 302400, 160, 0x4b86510d
+0, 303300, 160, 0x46844eab
+0, 304200, 160, 0xe5455deb
+0, 305100, 160, 0x60826550
+0, 306000, 160, 0x3c5a5448
+0, 306900, 160, 0x2db860c9
+0, 307800, 160, 0x4d845b78
+0, 308700, 160, 0x81dc5e23
+0, 309600, 160, 0x78c95932
+0, 310500, 160, 0xb5be57cd
+0, 311400, 160, 0x6fa45c65
+0, 312300, 160, 0x4e085e2a
+0, 313200, 160, 0x50ee530c
+0, 314100, 160, 0x2bb85587
+0, 315000, 160, 0x6d58614e
+0, 315900, 160, 0xcf4c5d69
+0, 316800, 160, 0x3cbf5ffb
+0, 317700, 160, 0x452157d3
+0, 318600, 160, 0x3cb55cd8
+0, 319500, 160, 0x2bba5735
+0, 320400, 160, 0x36a45670
+0, 321300, 160, 0x23b85b8a
+0, 322200, 160, 0x9a255457
+0, 323100, 160, 0x4e6956f3
+0, 324000, 160, 0xa0714edc
+0, 324900, 160, 0x7dee4a3d
+0, 325800, 160, 0x86404bc9
+0, 326700, 160, 0x358c50cd
+0, 327600, 160, 0x9eda47e8
+0, 328500, 160, 0x3cfe522e
+0, 329400, 160, 0xddb95758
+0, 330300, 160, 0x1a434a83
+0, 331200, 160, 0xa8a450bb
+0, 332100, 160, 0x44e7530e
+0, 333000, 160, 0x59b5555a
+0, 333900, 160, 0x65404db1
+0, 334800, 160, 0xcac15945
+0, 335700, 160, 0x38864f17
+0, 336600, 160, 0x61114f30
+0, 337500, 160, 0x195542d8
+0, 338400, 160, 0xacbb4c69
+0, 339300, 160, 0xd0da4ab9
+0, 340200, 160, 0x563d4eb6
+0, 341100, 160, 0xd0ce503c
+0, 342000, 160, 0x8b684e15
+0, 342900, 160, 0x711541d3
+0, 343800, 160, 0xb28b5b9b
+0, 344700, 160, 0x48b145e4
+0, 345600, 160, 0x908f5606
+0, 346500, 160, 0x22c74f02
+0, 347400, 160, 0x87274716
+0, 348300, 160, 0xaa2351e6
+0, 349200, 160, 0x2df5505a
+0, 350100, 160, 0x7999525c
+0, 351000, 160, 0x728a4b73
+0, 351900, 160, 0xa67447ff
+0, 352800, 160, 0x28884a20
+0, 353700, 160, 0x3ffa5840
+0, 354600, 160, 0xd6265047
+0, 355500, 160, 0x2f1553a8
+0, 356400, 160, 0xac0653ec
+0, 357300, 160, 0x35844368
+0, 358200, 160, 0x6e1553ba
+0, 359100, 160, 0xb62a4c88
+0, 360000, 160, 0x88a04ffc
+0, 360900, 160, 0x947e525e
+0, 361800, 160, 0x3dd24f98
+0, 362700, 160, 0x942e542e
+0, 363600, 160, 0xdb985211
+0, 364500, 160, 0x615a5022
+0, 365400, 160, 0x71c04569
+0, 366300, 160, 0xbbbe4f41
+0, 367200, 160, 0x62074e0b
+0, 368100, 160, 0x2c5d56c7
+0, 369000, 160, 0x34344c18
+0, 369900, 160, 0xc57d4c22
+0, 370800, 160, 0xb273560d
+0, 371700, 160, 0x7e985229
+0, 372600, 160, 0x2dd3542d
+0, 373500, 160, 0x39645000
+0, 374400, 160, 0x1b3f4d9e
+0, 375300, 160, 0x0bbf5ed2
+0, 376200, 160, 0xc81f5608
+0, 377100, 160, 0xe82e569e
+0, 378000, 160, 0x34df537d
+0, 378900, 160, 0x53175837
+0, 379800, 160, 0xbb76517f
+0, 380700, 160, 0xd5a25737
+0, 381600, 160, 0x58eb4f3d
+0, 382500, 160, 0x8f6e51d3
+0, 383400, 160, 0x1fd85602
+0, 384300, 160, 0xef2a4ee7
+0, 385200, 160, 0x0e6e58f4
+0, 386100, 160, 0x80345497
+0, 387000, 160, 0x710150a1
+0, 387900, 160, 0x32fb51db
+0, 388800, 160, 0x7efd564c
+0, 389700, 160, 0xf6604f26
+0, 390600, 160, 0xc0954d7e
+0, 391500, 160, 0x27705072
+0, 392400, 160, 0xd26f5958
+0, 393300, 160, 0x2c2552cd
+0, 394200, 160, 0xd14056b1
+0, 395100, 160, 0x11f356d2
+0, 396000, 160, 0x93b35efd
+0, 396900, 160, 0xa6d65ae7
+0, 397800, 160, 0x95015177
+0, 398700, 160, 0x2e6157e8
+0, 399600, 160, 0xb90c5021
+0, 400500, 160, 0xf39155c9
+0, 401400, 160, 0xd6ad544b
+0, 402300, 160, 0x4b8a5b98
+0, 403200, 160, 0x90a94f2d
+0, 404100, 160, 0x46a04f3f
+0, 405000, 160, 0x542b5cd1
+0, 405900, 160, 0xebaa5710
+0, 406800, 160, 0x504854a0
+0, 407700, 160, 0xbd9d53b5
+0, 408600, 160, 0x91524fed
+0, 409500, 160, 0x9b7a582d
+0, 410400, 160, 0xa4f258cf
+0, 411300, 160, 0x46274dda
+0, 412200, 160, 0xc0335ba9
+0, 413100, 160, 0xe59c5c74
+0, 414000, 160, 0xc2ee5ab0
+0, 414900, 160, 0x3e035996
+0, 415800, 160, 0x63e25521
+0, 416700, 160, 0xc09851af
+0, 417600, 160, 0xb8225715
+0, 418500, 160, 0x74355bfb
+0, 419400, 160, 0xf4c75adf
+0, 420300, 160, 0x2f8b56cd
+0, 421200, 160, 0xb4705795
+0, 422100, 160, 0xb4b25506
+0, 423000, 160, 0xaadb54f8
+0, 423900, 160, 0xe6d158aa
+0, 424800, 160, 0xed64614f
+0, 425700, 160, 0x80195732
+0, 426600, 160, 0xa8995f0e
+0, 427500, 160, 0xdc4a520d
+0, 428400, 160, 0x071a5bae
+0, 429300, 160, 0xce1b5ae9
+0, 430200, 160, 0x85e25804
+0, 431100, 160, 0x435e555f
+0, 432000, 160, 0xe4154ef4
+0, 432900, 160, 0xeff857b4
+0, 433800, 160, 0xc9e25868
+0, 434700, 160, 0x6e6961eb
+0, 435600, 160, 0x361e45e6
+0, 436500, 160, 0xf8a94988
+0, 437400, 160, 0x9de758b3
+0, 438300, 160, 0x2e65533e
+0, 439200, 160, 0x3f89422d
+0, 440100, 160, 0x77fd56a5
+0, 441000, 160, 0x91104845
+0, 441900, 160, 0x2eeb5491
+0, 442800, 160, 0x6a5348c4
+0, 443700, 160, 0xe0954882
+0, 444600, 160, 0x7e915761
+0, 445500, 160, 0x2cb5531f
+0, 446400, 160, 0xe1dc4ecd
+0, 447300, 160, 0xbf6b4e61
+0, 448200, 160, 0x3d6b5746
+0, 449100, 160, 0xe8bd5077
+0, 450000, 160, 0xd38d5921
+0, 450900, 160, 0xfc534e38
+0, 451800, 160, 0xd361475b
+0, 452700, 160, 0x4d5152c7
+0, 453600, 160, 0xb6684d11
+0, 454500, 160, 0xd2e25864
+0, 455400, 160, 0x02ec536a
+0, 456300, 160, 0x27ac550e
+0, 457200, 160, 0xe8d44e2d
+0, 458100, 160, 0x520152c8
+0, 459000, 160, 0xace747ea
+0, 459900, 160, 0x773a4ee3
+0, 460800, 160, 0x7dd1559f
+0, 461700, 160, 0x124453a8
+0, 462600, 160, 0x04154991
+0, 463500, 160, 0x3c794d98
+0, 464400, 160, 0x309f4e47
+0, 465300, 160, 0x98c74a48
+0, 466200, 160, 0xd0c34bcc
+0, 467100, 160, 0xfa304e19
+0, 468000, 160, 0x69505201
+0, 468900, 160, 0x2e714ac7
+0, 469800, 160, 0x076654a3
+0, 470700, 160, 0xc6674e27
+0, 471600, 160, 0x1adf4dd9
+0, 472500, 160, 0x4408507e
+0, 473400, 160, 0xd2654d94
+0, 474300, 160, 0x97a65cc0
+0, 475200, 160, 0xb53251f9
+0, 476100, 160, 0xd498584b
+0, 477000, 160, 0x46a058c8
+0, 477900, 160, 0xa2f85cbd
+0, 478800, 160, 0x43b856fb
+0, 479700, 160, 0xdeb957ba
+0, 480600, 160, 0x3064580a
+0, 481500, 160, 0xe86357a5
+0, 482400, 160, 0x9b974d00
+0, 483300, 160, 0x66ee4ff3
+0, 484200, 160, 0x0b9958f7
+0, 485100, 160, 0xc3754d0a
+0, 486000, 160, 0x42314c33
+0, 486900, 160, 0x4550555f
+0, 487800, 160, 0x0f064e4c
+0, 488700, 160, 0xe569596d
+0, 489600, 160, 0x056c4751
+0, 490500, 160, 0xdc1049fc
+0, 491400, 160, 0x63c54a1e
+0, 492300, 160, 0xb402518e
+0, 493200, 160, 0xaf0d4b19
+0, 494100, 160, 0xa22b4c5b
+0, 495000, 160, 0x28084bbf
+0, 495900, 160, 0x10495224
+0, 496800, 160, 0x4cb94993
+0, 497700, 160, 0x17c15457
+0, 498600, 160, 0xbd834d6d
+0, 499500, 160, 0x6ca25235
+0, 500400, 160, 0x84b74f89
+0, 501300, 160, 0xdeef4e76
+0, 502200, 160, 0x6ab05188
+0, 503100, 160, 0xa91c4646
+0, 504000, 160, 0xad574e7d
+0, 504900, 160, 0xba264d69
+0, 505800, 160, 0xd8734dd0
+0, 506700, 160, 0x69f25581
+0, 507600, 160, 0x3b8e4ae9
+0, 508500, 160, 0xb1124607
+0, 509400, 160, 0xd78e4e4f
+0, 510300, 160, 0x05a1504f
+0, 511200, 160, 0x3e705270
+0, 512100, 160, 0x1e144b3b
+0, 513000, 160, 0xbb0b5416
+0, 513900, 160, 0xc26f5b45
+0, 514800, 160, 0x14224ab9
+0, 515700, 160, 0x2bbd4837
+0, 516600, 160, 0xd2bf4e60
+0, 517500, 160, 0xbeec506c
+0, 518400, 160, 0x2cd34d3a
+0, 519300, 160, 0x85134fc6
+0, 520200, 160, 0xdb9a4ac2
+0, 521100, 160, 0x92715256
+0, 522000, 160, 0xff395098
+0, 522900, 160, 0xa5ec560c
+0, 523800, 160, 0xce95534b
+0, 524700, 160, 0xe36f46f1
+0, 525600, 160, 0x45f74a58
+0, 526500, 160, 0x02d05440
+0, 527400, 160, 0xa005529f
+0, 528300, 160, 0xae0f3f22
+0, 529200, 160, 0x3f984eb0
+0, 530100, 160, 0xc5bd5015
+0, 531000, 160, 0xf4504c53
+0, 531900, 160, 0x7f4044c5
+0, 532800, 160, 0x82dd4bab
+0, 533700, 160, 0x7a0d5122
+0, 534600, 160, 0xd0da5271
+0, 535500, 160, 0x67d14e3e
+0, 536400, 160, 0x54564f42
+0, 537300, 160, 0x77df4e0a
+0, 538200, 160, 0x0c4a4f70
+0, 539100, 160, 0xb2944f40
+0, 540000, 160, 0xe57a52de
+0, 540900, 160, 0x7d994ed1
+0, 541800, 160, 0x9dc35763
+0, 542700, 160, 0x8d0a4da9
+0, 543600, 160, 0x0c6449a4
+0, 544500, 160, 0xc73c503a
+0, 545400, 160, 0x52904cbe
+0, 546300, 160, 0x49824c2e
+0, 547200, 160, 0xb7e14e0b
+0, 548100, 160, 0x9745548e
+0, 549000, 160, 0xdafb4c20
+0, 549900, 160, 0x1aa84d67
+0, 550800, 160, 0x64bc5033
+0, 551700, 160, 0x9e2e5a05
+0, 552600, 160, 0x69144bc5
+0, 553500, 160, 0xce1253fa
+0, 554400, 160, 0x359f4c15
+0, 555300, 160, 0xdba74ed0
+0, 556200, 160, 0xea1453b8
+0, 557100, 160, 0xccdf49d3
+0, 558000, 160, 0xeb324750
+0, 558900, 160, 0x62b14ad4
+0, 559800, 160, 0x446e50c0
+0, 560700, 160, 0x111e5151
+0, 561600, 160, 0x6be84f3a
+0, 562500, 160, 0xf5cf4e42
+0, 563400, 160, 0xcc995459
+0, 564300, 160, 0x0faf5172
+0, 565200, 160, 0x31334f66
+0, 566100, 160, 0x20ba52c0
+0, 567000, 160, 0xc7cc4975
+0, 567900, 160, 0x9e7a51ba
+0, 568800, 160, 0x52884ff1
+0, 569700, 160, 0xc7a84cfd
+0, 570600, 160, 0x5ae64c22
+0, 571500, 160, 0x68125a92
+0, 572400, 160, 0x39ed54f1
+0, 573300, 160, 0xfa0a4ad1
+0, 574200, 160, 0xe8c8590c
+0, 575100, 160, 0x5f555576
+0, 576000, 160, 0xaf7a57a1
+0, 576900, 160, 0x858257e9
+0, 577800, 160, 0x1223523e
+0, 578700, 160, 0x446954a1
+0, 579600, 160, 0xfbe952d9
+0, 580500, 160, 0xd56259ff
+0, 581400, 160, 0xc4fa4f44
+0, 582300, 160, 0x77cc57f6
+0, 583200, 160, 0x53d3573d
+0, 584100, 160, 0x085e4ff9
+0, 585000, 160, 0x7a4e5410
+0, 585900, 160, 0xb4ad5794
+0, 586800, 160, 0x71255738
+0, 587700, 160, 0x36724918
+0, 588600, 160, 0x370e5974
+0, 589500, 160, 0xb709596c
+0, 590400, 160, 0x89b05052
+0, 591300, 160, 0x74e550ce
+0, 592200, 160, 0x6e2c5a49
+0, 593100, 160, 0x4dfa5b50
+0, 594000, 160, 0x80764c70
+0, 594900, 160, 0xc1d14fc6
+0, 595800, 160, 0x53e746b3
+0, 596700, 160, 0x728350c0
+0, 597600, 160, 0x9aa6500e
+0, 598500, 160, 0x60985454
+0, 599400, 160, 0xa0c54b6f
+0, 600300, 160, 0xe3b157ea
+0, 601200, 160, 0xce86573b
+0, 602100, 160, 0x9dad5535
+0, 603000, 160, 0xb3094af9
+0, 603900, 160, 0x2d1456ed
+0, 604800, 160, 0x328248b9
+0, 605700, 160, 0x4ffb4f52
+0, 606600, 160, 0x71fe53de
+0, 607500, 160, 0x0d114e92
+0, 608400, 160, 0x37065510
+0, 609300, 160, 0x426c4c07
+0, 610200, 160, 0x58e3528b
+0, 611100, 160, 0x71674484
+0, 612000, 160, 0x45934ee1
+0, 612900, 160, 0x4e914b31
+0, 613800, 160, 0x525b4ec2
+0, 614700, 160, 0x4393563d
+0, 615600, 160, 0xb10154e9
+0, 616500, 160, 0x23b15a4d
+0, 617400, 160, 0x6d995220
+0, 618300, 160, 0xcd2949fd
+0, 619200, 160, 0x67234f75
+0, 620100, 160, 0x00cc4cdb
+0, 621000, 160, 0x97c35574
+0, 621900, 160, 0xc0855753
+0, 622800, 160, 0xf4e650a5
+0, 623700, 160, 0x95b14bc2
+0, 624600, 160, 0x04d948dc
+0, 625500, 160, 0x284d4d02
+0, 626400, 160, 0xfb0d4cd9
+0, 627300, 160, 0x0e515126
+0, 628200, 160, 0xb4055a86
+0, 629100, 160, 0x0bbe4f68
+0, 630000, 160, 0xf1b848af
+0, 630900, 160, 0x7d154853
+0, 631800, 160, 0x78225418
+0, 632700, 160, 0xfb2f523e
+0, 633600, 160, 0xa6d34ea6
+0, 634500, 160, 0xe4264e30
+0, 635400, 160, 0x113750aa
+0, 636300, 160, 0x4073529b
+0, 637200, 160, 0xd1754dda
+0, 638100, 160, 0x1b495413
+0, 639000, 160, 0x29f94cd8
+0, 639900, 160, 0x49004a53
+0, 640800, 160, 0x1fec4de4
+0, 641700, 160, 0x7d6b4670
+0, 642600, 160, 0x626c4c9f
+0, 643500, 160, 0x79265234
+0, 644400, 160, 0xab765b86
+0, 645300, 160, 0xe9ae4d26
+0, 646200, 160, 0xeee1481f
+0, 647100, 160, 0x289d5287
+0, 648000, 160, 0xb5524e8b
+0, 648900, 160, 0x7e715764
+0, 649800, 160, 0xb1b25091
+0, 650700, 160, 0xf1a946f6
+0, 651600, 160, 0x57dc51bd
+0, 652500, 160, 0x4c0b4f14
+0, 653400, 160, 0xdc1f4930
+0, 654300, 160, 0x79d75057
+0, 655200, 160, 0x22bd52df
+0, 656100, 160, 0x963a5562
+0, 657000, 160, 0x7e475303
+0, 657900, 160, 0x2c065494
+0, 658800, 160, 0xb0514720
+0, 659700, 160, 0xbc734849
+0, 660600, 160, 0xf4924e4d
+0, 661500, 160, 0xe50f44c9
+0, 662400, 160, 0x978c4ce8
+0, 663300, 160, 0x302e51c2
+0, 664200, 160, 0x262b4a60
+0, 665100, 160, 0xf95f4e99
+0, 666000, 160, 0x7465504a
+0, 666900, 160, 0xab0e5108
+0, 667800, 160, 0xbec15395
+0, 668700, 160, 0x4f2c5139
+0, 669600, 160, 0x26444deb
+0, 670500, 160, 0xee4c4b15
+0, 671400, 160, 0x8bc350e1
+0, 672300, 160, 0xd0744a5a
+0, 673200, 160, 0xfee64d9d
+0, 674100, 160, 0x234c50b6
+0, 675000, 160, 0x8592482c
+0, 675900, 160, 0x5e8b5308
+0, 676800, 160, 0x4f9848c7
+0, 677700, 160, 0x939d4faa
+0, 678600, 160, 0x797654f1
+0, 679500, 160, 0x15d24d9b
+0, 680400, 160, 0xa6e54bd2
+0, 681300, 160, 0x755e4c90
+0, 682200, 160, 0xcd334bce
+0, 683100, 160, 0xfc1746e9
+0, 684000, 160, 0x81f04dd5
+0, 684900, 160, 0x44b35080
+0, 685800, 160, 0x91e65217
+0, 686700, 160, 0x492150af
+0, 687600, 160, 0xf73e58ec
+0, 688500, 160, 0xf988538a
+0, 689400, 160, 0x0dee4c10
+0, 690300, 160, 0x2c9f4c23
+0, 691200, 160, 0x8c1e4e08
+0, 692100, 160, 0x25bb5286
+0, 693000, 160, 0xd0ed469b
+0, 693900, 160, 0x71eb50e8
+0, 694800, 160, 0x249f4d26
+0, 695700, 160, 0x9662498f
+0, 696600, 160, 0x49ee55e2
+0, 697500, 160, 0x54d9491b
+0, 698400, 160, 0x4c675649
+0, 699300, 160, 0x0e4b4b34
+0, 700200, 160, 0x776f4995
+0, 701100, 160, 0x722656b2
+0, 702000, 160, 0x081d4b6f
+0, 702900, 160, 0xf70746fe
+0, 703800, 160, 0x08b151da
+0, 704700, 160, 0x6b255328
+0, 705600, 160, 0xeb2b586a
+0, 706500, 160, 0x812b4444
+0, 707400, 160, 0x1e16533f
+0, 708300, 160, 0xc1244760
+0, 709200, 160, 0x67584d87
+0, 710100, 160, 0xde8b5726
+0, 711000, 160, 0xe96d4e3e
+0, 711900, 160, 0x41174c98
+0, 712800, 160, 0x4cdd4cd8
+0, 713700, 160, 0xfb724b64
+0, 714600, 160, 0x78f154df
+0, 715500, 160, 0x97e1476d
+0, 716400, 160, 0x6f034e7f
+0, 717300, 160, 0x93b240df
+0, 718200, 160, 0xc4d040e6
+0, 719100, 160, 0xe47744a4
+0, 720000, 160, 0x87a950ff
+0, 720900, 160, 0x7079491b
+0, 721800, 160, 0x89f0491a
+0, 722700, 160, 0x70b8467e
+0, 723600, 160, 0x20945294
+0, 724500, 160, 0x2d5c4919
+0, 725400, 160, 0x1ed44c78
+0, 726300, 160, 0x93d74a5f
+0, 727200, 160, 0x300e490e
+0, 728100, 160, 0x8249558d
+0, 729000, 160, 0x630a4f57
+0, 729900, 160, 0xdd6e475f
+0, 730800, 160, 0xf50941e5
+0, 731700, 160, 0x1fe44bea
+0, 732600, 160, 0x03be5469
+0, 733500, 160, 0x7ece4f4c
+0, 734400, 160, 0x31f953dd
+0, 735300, 160, 0x22a44b7d
+0, 736200, 160, 0x1f5e5562
+0, 737100, 160, 0x771b5688
+0, 738000, 160, 0x7d1c4d45
+0, 738900, 160, 0x6bc45cd0
+0, 739800, 160, 0x8f714c36
+0, 740700, 160, 0xfb1f4c87
+0, 741600, 160, 0x1f8a4b36
+0, 742500, 160, 0xee5c451a
+0, 743400, 160, 0xd56950ac
+0, 744300, 160, 0x529057f6
+0, 745200, 160, 0x336641fd
+0, 746100, 160, 0xa0dd5a66
+0, 747000, 160, 0x5f4b5248
+0, 747900, 160, 0xb6ef49a3
+0, 748800, 160, 0x07705f19
+0, 749700, 160, 0x3fce4bbb
+0, 750600, 160, 0xda395511
+0, 751500, 160, 0x1ecf5145
+0, 752400, 160, 0x88a547ab
+0, 753300, 160, 0x6c6849be
+0, 754200, 160, 0x979c4e97
+0, 755100, 160, 0x171854b3
+0, 756000, 160, 0x9a715283
+0, 756900, 160, 0x064e50ac
+0, 757800, 160, 0xc2fb4e94
+0, 758700, 160, 0x708146f5
+0, 759600, 160, 0x1ca45198
+0, 760500, 160, 0x332d4869
+0, 761400, 160, 0xc2ff4656
+0, 762300, 160, 0x0747552e
+0, 763200, 160, 0x0c3d4ba8
+0, 764100, 160, 0x72934dab
+0, 765000, 160, 0xbb1e5860
+0, 765900, 160, 0x526d4cea
+0, 766800, 160, 0xa4c445d6
+0, 767700, 160, 0x70cd49ba
+0, 768600, 160, 0x008c53a7
+0, 769500, 160, 0xf7174bca
+0, 770400, 160, 0x0bab4936
+0, 771300, 160, 0x59e5564d
+0, 772200, 160, 0x33045087
+0, 773100, 160, 0xde7454f0
+0, 774000, 160, 0x31184cc3
+0, 774900, 160, 0x37984bb3
+0, 775800, 160, 0xf5e052d4
+0, 776700, 160, 0x23ca4b42
+0, 777600, 160, 0xbe2a572b
+0, 778500, 160, 0x9a91538d
+0, 779400, 160, 0x8a994c40
+0, 780300, 160, 0x5dea51ee
+0, 781200, 160, 0x1b53524c
+0, 782100, 160, 0xd9e75227
+0, 783000, 160, 0x58384c3b
+0, 783900, 160, 0x4a1b53b2
+0, 784800, 160, 0xc2a3458a
+0, 785700, 160, 0x7f68502d
+0, 786600, 160, 0x85475559
+0, 787500, 160, 0xd0d25472
+0, 788400, 160, 0x4c0d4bbf
+0, 789300, 160, 0xcad352df
+0, 790200, 160, 0x17904c97
+0, 791100, 160, 0x4e774b8e
+0, 792000, 160, 0x21905952
+0, 792900, 160, 0xc2d950cd
+0, 793800, 160, 0xfdea55e6
+0, 794700, 160, 0x22ca4e37
+0, 795600, 160, 0x1143562a
+0, 796500, 160, 0xe83c583e
+0, 797400, 160, 0xba544b27
+0, 798300, 160, 0x1e8c50e4
+0, 799200, 160, 0xf7ca4d2a
+0, 800100, 160, 0x67764579
+0, 801000, 160, 0x40d74f42
+0, 801900, 160, 0x88e35360
+0, 802800, 160, 0xda3f4f5b
+0, 803700, 160, 0x19c1522f
+0, 804600, 160, 0x93ce4f78
+0, 805500, 160, 0xf65447ba
+0, 806400, 160, 0xc0bc4e5a
+0, 807300, 160, 0x4915572b
+0, 808200, 160, 0x1651460b
+0, 809100, 160, 0xffe552a5
+0, 810000, 160, 0x5bd351ab
+0, 810900, 160, 0xbbd85034
+0, 811800, 160, 0xb9ff505f
+0, 812700, 160, 0xfc104eaf
+0, 813600, 160, 0xdaa74d6c
+0, 814500, 160, 0x34b04d78
+0, 815400, 160, 0x1e924f70
+0, 816300, 160, 0x0d46512d
+0, 817200, 160, 0x0d115950
+0, 818100, 160, 0x62de55a4
+0, 819000, 160, 0x58d652ab
+0, 819900, 160, 0x1776584e
+0, 820800, 160, 0x60175a2b
+0, 821700, 160, 0x4d714c82
+0, 822600, 160, 0xe13c4ce0
+0, 823500, 160, 0x7cd15464
+0, 824400, 160, 0x6c87571a
+0, 825300, 160, 0x1abe4f07
+0, 826200, 160, 0x039d5661
+0, 827100, 160, 0x0eba5909
+0, 828000, 160, 0xa46e51ec
+0, 828900, 160, 0x9be44eb7
+0, 829800, 160, 0xe0634aad
+0, 830700, 160, 0xcd53530b
+0, 831600, 160, 0x12cd482c
+0, 832500, 160, 0x71884634
+0, 833400, 160, 0xd5845743
+0, 834300, 160, 0xacd1502c
+0, 835200, 160, 0x04795031
+0, 836100, 160, 0xf0df54b9
+0, 837000, 160, 0x43aa5155
+0, 837900, 160, 0x316a4988
+0, 838800, 160, 0xfbc64f8a
+0, 839700, 160, 0xda084e8e
+0, 840600, 160, 0x3cc34ce2
+0, 841500, 160, 0xbfc055d8
+0, 842400, 160, 0x20ef4876
+0, 843300, 160, 0x035a5660
+0, 844200, 160, 0xbc7255be
+0, 845100, 160, 0xba514f44
+0, 846000, 160, 0x868c4c9c
+0, 846900, 160, 0x83494f04
+0, 847800, 160, 0xa452521a
+0, 848700, 160, 0x2ed04f65
+0, 849600, 160, 0x2e3e592d
+0, 850500, 160, 0x82bc4763
+0, 851400, 160, 0x339950db
+0, 852300, 160, 0x5bb64eff
+0, 853200, 160, 0x347c4d85
+0, 854100, 160, 0x25e949a3
+0, 855000, 160, 0xbdf649a8
+0, 855900, 160, 0x498650f3
+0, 856800, 160, 0x2a6f4e60
+0, 857700, 160, 0x661e5697
+0, 858600, 160, 0x5d6150ca
+0, 859500, 160, 0xe7c74b8f
+0, 860400, 160, 0x1ae148da
+0, 861300, 160, 0xaeef485d
+0, 862200, 160, 0x105650c6
+0, 863100, 160, 0xc1c45376
+0, 864000, 160, 0x83c55011
+0, 864900, 160, 0x77025597
+0, 865800, 160, 0x324250b7
+0, 866700, 160, 0x5cdc570f
+0, 867600, 160, 0x292e52a1
+0, 868500, 160, 0x8d7a5090
+0, 869400, 160, 0x32fc54e4
+0, 870300, 160, 0x50984e8b
+0, 871200, 160, 0x07f442a0
+0, 872100, 160, 0xc91c4fc3
+0, 873000, 160, 0x06cf53d7
+0, 873900, 160, 0xa66c5923
+0, 874800, 160, 0xc2015120
+0, 875700, 160, 0xedfa50c4
+0, 876600, 160, 0xe4c85fb5
+0, 877500, 160, 0xcd7b4c65
+0, 878400, 160, 0xb22353c1
+0, 879300, 160, 0x298c5996
+0, 880200, 160, 0xefce51db
+0, 881100, 160, 0x6df74ee3
+0, 882000, 160, 0x7c46496b
+0, 882900, 160, 0x910a48a4
+0, 883800, 160, 0xbf504b1e
+0, 884700, 160, 0x096947e8
+0, 885600, 160, 0x4a07629d
+0, 886500, 160, 0x577b43c1
+0, 887400, 160, 0x939e4d6d
+0, 888300, 160, 0x486e48ac
+0, 889200, 160, 0x50064871
+0, 890100, 160, 0x4a255534
+0, 891000, 160, 0xc80d4618
+0, 891900, 160, 0xf18a4780
+0, 892800, 160, 0x1c274dd4
+0, 893700, 160, 0x2f3e4f7c
+0, 894600, 160, 0x44b24cc2
+0, 895500, 160, 0x89b451f4
+0, 896400, 160, 0x06515b65
+0, 897300, 160, 0xc5b857ce
+0, 898200, 160, 0xa47b47a7
+0, 899100, 160, 0xfb375448
diff --git a/tests/ref/fate/g729-1 b/tests/ref/fate/g729-1
new file mode 100644
index 0000000..6bf05c5
--- /dev/null
+++ b/tests/ref/fate/g729-1
@@ -0,0 +1,1000 @@
+0, 0, 160, 0xf7e550f0
+0, 900, 160, 0x42794ea8
+0, 1800, 160, 0xfe023e42
+0, 2700, 160, 0xc1ae40e3
+0, 3600, 160, 0xee6d4bf1
+0, 4500, 160, 0x107451d7
+0, 5400, 160, 0x40cb4ba4
+0, 6300, 160, 0x90504e5e
+0, 7200, 160, 0xf6f3531d
+0, 8100, 160, 0x48664ea0
+0, 9000, 160, 0xa30458e1
+0, 9900, 160, 0x00b74aa2
+0, 10800, 160, 0x95234e49
+0, 11700, 160, 0x9cf24a94
+0, 12600, 160, 0x4f2952f4
+0, 13500, 160, 0x658353db
+0, 14400, 160, 0x98ef4d79
+0, 15300, 160, 0x765d5472
+0, 16200, 160, 0xc6e25262
+0, 17100, 160, 0x33334993
+0, 18000, 160, 0xfa104dc5
+0, 18900, 160, 0x03ee5530
+0, 19800, 160, 0x52c54e0e
+0, 20700, 160, 0xbd744638
+0, 21600, 160, 0x7775519f
+0, 22500, 160, 0xd22f499e
+0, 23400, 160, 0x26af4eec
+0, 24300, 160, 0x37474ed9
+0, 25200, 160, 0x6b19548d
+0, 26100, 160, 0x4a3449b7
+0, 27000, 160, 0x2bed5231
+0, 27900, 160, 0x556d5349
+0, 28800, 160, 0xbb6c5227
+0, 29700, 160, 0xea354b4d
+0, 30600, 160, 0xf35f4b7d
+0, 31500, 160, 0x9dcb4e9d
+0, 32400, 160, 0xc81f5ac2
+0, 33300, 160, 0xfa054cfd
+0, 34200, 160, 0x0c554e62
+0, 35100, 160, 0x7ffa5250
+0, 36000, 160, 0x7e5148ec
+0, 36900, 160, 0x95bc4d69
+0, 37800, 160, 0xf34a5644
+0, 38700, 160, 0xcaa3493d
+0, 39600, 160, 0xa44745dc
+0, 40500, 160, 0x320355c0
+0, 41400, 160, 0xbd1e5670
+0, 42300, 160, 0xfe3250cd
+0, 43200, 160, 0xce7a574c
+0, 44100, 160, 0x09b04f6e
+0, 45000, 160, 0x035759c8
+0, 45900, 160, 0x713458c7
+0, 46800, 160, 0x9a75494b
+0, 47700, 160, 0x99114fef
+0, 48600, 160, 0x129251f0
+0, 49500, 160, 0x4eb845f2
+0, 50400, 160, 0x5d064da5
+0, 51300, 160, 0x5a8e4a34
+0, 52200, 160, 0x5b784608
+0, 53100, 160, 0x1ca7546a
+0, 54000, 160, 0x327e5cbf
+0, 54900, 160, 0xd7ae4bc3
+0, 55800, 160, 0xba3f55b4
+0, 56700, 160, 0x09fe4ca7
+0, 57600, 160, 0x347248ba
+0, 58500, 160, 0xf0bf52ff
+0, 59400, 160, 0x3500507e
+0, 60300, 160, 0x30e65135
+0, 61200, 160, 0x390a5201
+0, 62100, 160, 0xf0dc5bca
+0, 63000, 160, 0x69b94f64
+0, 63900, 160, 0x6ac04cf6
+0, 64800, 160, 0xbc014cf4
+0, 65700, 160, 0x4b564eca
+0, 66600, 160, 0x33e44e85
+0, 67500, 160, 0xe39e5343
+0, 68400, 160, 0xebf64c80
+0, 69300, 160, 0x5a92562b
+0, 70200, 160, 0xe0075c88
+0, 71100, 160, 0x59bd55e8
+0, 72000, 160, 0xe6ca4ef2
+0, 72900, 160, 0xea9a4df2
+0, 73800, 160, 0xf53c4bf6
+0, 74700, 160, 0x977a4f32
+0, 75600, 160, 0xe5894eb2
+0, 76500, 160, 0x956c4c28
+0, 77400, 160, 0xdff74c3d
+0, 78300, 160, 0xace74db7
+0, 79200, 160, 0x00e74ef5
+0, 80100, 160, 0x6633560a
+0, 81000, 160, 0xd63647c5
+0, 81900, 160, 0xff144eef
+0, 82800, 160, 0xc5fe4d51
+0, 83700, 160, 0x5c244c7c
+0, 84600, 160, 0x95be50f1
+0, 85500, 160, 0x74d84b77
+0, 86400, 160, 0x1e965711
+0, 87300, 160, 0x7ae45ad7
+0, 88200, 160, 0xf9cd5920
+0, 89100, 160, 0xf0064ea9
+0, 90000, 160, 0xec645244
+0, 90900, 160, 0x8330539a
+0, 91800, 160, 0x4a5d5023
+0, 92700, 160, 0x706153d7
+0, 93600, 160, 0xd6e0520f
+0, 94500, 160, 0x0bd9586f
+0, 95400, 160, 0xc1554dec
+0, 96300, 160, 0x89be4bde
+0, 97200, 160, 0x0c2a49c0
+0, 98100, 160, 0xc18d498a
+0, 99000, 160, 0xc36147e1
+0, 99900, 160, 0x99de4d4b
+0, 100800, 160, 0x2b9d542b
+0, 101700, 160, 0x062b52c9
+0, 102600, 160, 0x9dcf542e
+0, 103500, 160, 0x641f58b9
+0, 104400, 160, 0x114c51ff
+0, 105300, 160, 0x78e04b0e
+0, 106200, 160, 0xfec74535
+0, 107100, 160, 0x71d54cd3
+0, 108000, 160, 0xee9e5289
+0, 108900, 160, 0x142354d9
+0, 109800, 160, 0x051e4ddc
+0, 110700, 160, 0x358146b8
+0, 111600, 160, 0x4dec58eb
+0, 112500, 160, 0xd0944f04
+0, 113400, 160, 0xdc025a99
+0, 114300, 160, 0x6b355402
+0, 115200, 160, 0x1c0b5a6d
+0, 116100, 160, 0xa3b34bc8
+0, 117000, 160, 0x92604eb7
+0, 117900, 160, 0x6f2f5465
+0, 118800, 160, 0xcb565361
+0, 119700, 160, 0x8bfb50a3
+0, 120600, 160, 0xf9114e99
+0, 121500, 160, 0x11065580
+0, 122400, 160, 0x903550c8
+0, 123300, 160, 0xe7aa3da8
+0, 124200, 160, 0x13f34e01
+0, 125100, 160, 0x4c3b4c0a
+0, 126000, 160, 0x08e64c60
+0, 126900, 160, 0xffcd6176
+0, 127800, 160, 0x09684f13
+0, 128700, 160, 0xd8a646b5
+0, 129600, 160, 0xc07355f0
+0, 130500, 160, 0xe836515b
+0, 131400, 160, 0x935741a5
+0, 132300, 160, 0x68f85160
+0, 133200, 160, 0x669a4ed0
+0, 134100, 160, 0xce9f4883
+0, 135000, 160, 0xd94c42de
+0, 135900, 160, 0xf1874b54
+0, 136800, 160, 0x42da46ce
+0, 137700, 160, 0xe99a4da5
+0, 138600, 160, 0x94934f16
+0, 139500, 160, 0x8571437f
+0, 140400, 160, 0xe4774dc2
+0, 141300, 160, 0x743f4f89
+0, 142200, 160, 0x3b3e50ba
+0, 143100, 160, 0x439355e9
+0, 144000, 160, 0x3e4d5178
+0, 144900, 160, 0x64595524
+0, 145800, 160, 0x42d14702
+0, 146700, 160, 0x051e4b1d
+0, 147600, 160, 0x5db84cee
+0, 148500, 160, 0x4d875136
+0, 149400, 160, 0x33b75996
+0, 150300, 160, 0xd5094d76
+0, 151200, 160, 0x6a7052b7
+0, 152100, 160, 0x77264c8f
+0, 153000, 160, 0xcf7e4ccf
+0, 153900, 160, 0x5f7c568b
+0, 154800, 160, 0x8886578b
+0, 155700, 160, 0xd33a4e52
+0, 156600, 160, 0xeefe5c23
+0, 157500, 160, 0xa9c94e38
+0, 158400, 160, 0x67845aa0
+0, 159300, 160, 0xbe91498f
+0, 160200, 160, 0x843d46e3
+0, 161100, 160, 0xbd215999
+0, 162000, 160, 0x1a2e5f2c
+0, 162900, 160, 0x6a344a63
+0, 163800, 160, 0xd80d5743
+0, 164700, 160, 0x80964879
+0, 165600, 160, 0xaafb5e35
+0, 166500, 160, 0x3b855ff3
+0, 167400, 160, 0x770b51d0
+0, 168300, 160, 0x623a5312
+0, 169200, 160, 0x0c235b56
+0, 170100, 160, 0xc8c25724
+0, 171000, 160, 0xb44650e2
+0, 171900, 160, 0xab964d47
+0, 172800, 160, 0x7aa35107
+0, 173700, 160, 0xf12d4780
+0, 174600, 160, 0x77e64f92
+0, 175500, 160, 0x34ee4fa0
+0, 176400, 160, 0x6701466b
+0, 177300, 160, 0xa79d4b4c
+0, 178200, 160, 0xbb7f557b
+0, 179100, 160, 0xaeb253c4
+0, 180000, 160, 0xe7255029
+0, 180900, 160, 0xa5f1505c
+0, 181800, 160, 0x4ae54f09
+0, 182700, 160, 0x6a2b4bc9
+0, 183600, 160, 0xf8724ea5
+0, 184500, 160, 0x4ab35317
+0, 185400, 160, 0xc8d350fb
+0, 186300, 160, 0x73a74994
+0, 187200, 160, 0x9cd1596d
+0, 188100, 160, 0x5ba16005
+0, 189000, 160, 0xb17e4fcc
+0, 189900, 160, 0x8ac958cd
+0, 190800, 160, 0x7919557f
+0, 191700, 160, 0x0be35121
+0, 192600, 160, 0xf8f752f2
+0, 193500, 160, 0xae894d40
+0, 194400, 160, 0x03d94c10
+0, 195300, 160, 0xf12c4917
+0, 196200, 160, 0x3c94534e
+0, 197100, 160, 0x111d51c3
+0, 198000, 160, 0x0a285304
+0, 198900, 160, 0xc3ac4ab1
+0, 199800, 160, 0x5576579d
+0, 200700, 160, 0x9cd04f10
+0, 201600, 160, 0x38a04bf9
+0, 202500, 160, 0xbd0d4d6d
+0, 203400, 160, 0x4db24510
+0, 204300, 160, 0x968753de
+0, 205200, 160, 0x1fa35c67
+0, 206100, 160, 0xc9c048bc
+0, 207000, 160, 0x221d629e
+0, 207900, 160, 0xbb864b0e
+0, 208800, 160, 0xe2964bcd
+0, 209700, 160, 0x20ff4b23
+0, 210600, 160, 0x01dc53e7
+0, 211500, 160, 0x522b56aa
+0, 212400, 160, 0x1e6a495a
+0, 213300, 160, 0x0dcf5731
+0, 214200, 160, 0x241f448d
+0, 215100, 160, 0xdafa55b6
+0, 216000, 160, 0x40584e43
+0, 216900, 160, 0xb73850ab
+0, 217800, 160, 0x7cff593a
+0, 218700, 160, 0x2796515a
+0, 219600, 160, 0x872c5454
+0, 220500, 160, 0xa13058e7
+0, 221400, 160, 0xd8a65261
+0, 222300, 160, 0x48a75601
+0, 223200, 160, 0xb1e7584c
+0, 224100, 160, 0x29cd53fa
+0, 225000, 160, 0xba514d84
+0, 225900, 160, 0x747f4f99
+0, 226800, 160, 0x5819526e
+0, 227700, 160, 0x10185413
+0, 228600, 160, 0x4d084cdc
+0, 229500, 160, 0x8313530b
+0, 230400, 160, 0xd26c5583
+0, 231300, 160, 0x76d749f9
+0, 232200, 160, 0x7cf847a5
+0, 233100, 160, 0xa642590c
+0, 234000, 160, 0x7fef56f2
+0, 234900, 160, 0xf6ea49b9
+0, 235800, 160, 0x6c654e89
+0, 236700, 160, 0x164f56e9
+0, 237600, 160, 0x84cf6139
+0, 238500, 160, 0x20c753ef
+0, 239400, 160, 0x3f3a485f
+0, 240300, 160, 0xee0c5f4b
+0, 241200, 160, 0x706b5313
+0, 242100, 160, 0x47da5af3
+0, 243000, 160, 0x05504b25
+0, 243900, 160, 0x584e59d8
+0, 244800, 160, 0xe9cc4e37
+0, 245700, 160, 0xf33b518a
+0, 246600, 160, 0xb9ac58b7
+0, 247500, 160, 0xed5c57f0
+0, 248400, 160, 0x4cf1579d
+0, 249300, 160, 0x96f94792
+0, 250200, 160, 0x7c455836
+0, 251100, 160, 0xad6652ce
+0, 252000, 160, 0x1ba95cab
+0, 252900, 160, 0xd86755bb
+0, 253800, 160, 0x2f9e51b4
+0, 254700, 160, 0x084e5119
+0, 255600, 160, 0x54ad5449
+0, 256500, 160, 0xff7c5b86
+0, 257400, 160, 0x29a94fff
+0, 258300, 160, 0x679c55ff
+0, 259200, 160, 0x9a415b81
+0, 260100, 160, 0x3ea5528a
+0, 261000, 160, 0x54e15d3f
+0, 261900, 160, 0x122b5c28
+0, 262800, 160, 0xdc0f4e7f
+0, 263700, 160, 0xdc304acd
+0, 264600, 160, 0xe55e5407
+0, 265500, 160, 0x8d07485f
+0, 266400, 160, 0xdc0b5333
+0, 267300, 160, 0xfaed4a90
+0, 268200, 160, 0xb0625538
+0, 269100, 160, 0x1ef3526b
+0, 270000, 160, 0xb48c48e9
+0, 270900, 160, 0x8c945190
+0, 271800, 160, 0x7f9a58b3
+0, 272700, 160, 0x55735499
+0, 273600, 160, 0xeba34a71
+0, 274500, 160, 0xbaa94a6d
+0, 275400, 160, 0x15ab484f
+0, 276300, 160, 0xdc675509
+0, 277200, 160, 0xc2e94f0e
+0, 278100, 160, 0xd7f348ac
+0, 279000, 160, 0x14884e8f
+0, 279900, 160, 0x2d274a97
+0, 280800, 160, 0x578c5834
+0, 281700, 160, 0x12074dab
+0, 282600, 160, 0x74c55067
+0, 283500, 160, 0x7c904e0f
+0, 284400, 160, 0x81d45735
+0, 285300, 160, 0x766f4d71
+0, 286200, 160, 0x9c915273
+0, 287100, 160, 0xf37f4d04
+0, 288000, 160, 0x1ac74d66
+0, 288900, 160, 0xf9b253ab
+0, 289800, 160, 0x6e0c5bb2
+0, 290700, 160, 0x603d629e
+0, 291600, 160, 0xbb674faf
+0, 292500, 160, 0x5d8d51c6
+0, 293400, 160, 0xae7350b9
+0, 294300, 160, 0xfde859ec
+0, 295200, 160, 0x900d50a4
+0, 296100, 160, 0x003551b2
+0, 297000, 160, 0xf8ae4c9d
+0, 297900, 160, 0x66ea508f
+0, 298800, 160, 0xd45b4c51
+0, 299700, 160, 0xb64451a3
+0, 300600, 160, 0x6d2a5621
+0, 301500, 160, 0x71db4d36
+0, 302400, 160, 0x06704647
+0, 303300, 160, 0x1f124cf9
+0, 304200, 160, 0x10d14b46
+0, 305100, 160, 0x421b59d8
+0, 306000, 160, 0x84ba4cae
+0, 306900, 160, 0x4fba48e1
+0, 307800, 160, 0xec294a6b
+0, 308700, 160, 0x2f1752a7
+0, 309600, 160, 0x8d665570
+0, 310500, 160, 0x586e537d
+0, 311400, 160, 0x18d54a49
+0, 312300, 160, 0xa895566d
+0, 313200, 160, 0xb9b35255
+0, 314100, 160, 0x2e194e1f
+0, 315000, 160, 0x4810594b
+0, 315900, 160, 0xb82557ee
+0, 316800, 160, 0x35d84d67
+0, 317700, 160, 0x5ee95128
+0, 318600, 160, 0x24f05747
+0, 319500, 160, 0x434d53f6
+0, 320400, 160, 0x3c894f3e
+0, 321300, 160, 0x81c34896
+0, 322200, 160, 0x7540543c
+0, 323100, 160, 0x35bc5504
+0, 324000, 160, 0x546943dc
+0, 324900, 160, 0x084d46e9
+0, 325800, 160, 0x983852ba
+0, 326700, 160, 0xefac4e15
+0, 327600, 160, 0xc9294430
+0, 328500, 160, 0xe9e74de1
+0, 329400, 160, 0x4ca1516a
+0, 330300, 160, 0x44014ceb
+0, 331200, 160, 0x1dbc5ad1
+0, 332100, 160, 0x98be4efd
+0, 333000, 160, 0x2dc75c7a
+0, 333900, 160, 0x46275852
+0, 334800, 160, 0x61c15d30
+0, 335700, 160, 0x1f605adc
+0, 336600, 160, 0xf08659ac
+0, 337500, 160, 0xb7656021
+0, 338400, 160, 0x1f4a5a72
+0, 339300, 160, 0xf8175275
+0, 340200, 160, 0xbbf4564d
+0, 341100, 160, 0x6fdc5a7d
+0, 342000, 160, 0x082f5250
+0, 342900, 160, 0x84cb55b5
+0, 343800, 160, 0x0e1a51ba
+0, 344700, 160, 0xa84e52fc
+0, 345600, 160, 0xcb5a55c9
+0, 346500, 160, 0x9ce6570d
+0, 347400, 160, 0x82b253cc
+0, 348300, 160, 0x34c4594b
+0, 349200, 160, 0xff5c5854
+0, 350100, 160, 0xd5da4ea0
+0, 351000, 160, 0xc86e5553
+0, 351900, 160, 0x7ecb55c6
+0, 352800, 160, 0xb08b5338
+0, 353700, 160, 0xd601573c
+0, 354600, 160, 0x93305092
+0, 355500, 160, 0x352d4912
+0, 356400, 160, 0xddba4d29
+0, 357300, 160, 0xc79c50b7
+0, 358200, 160, 0xe67d4e8e
+0, 359100, 160, 0xdbfd4bbc
+0, 360000, 160, 0xb2f746fb
+0, 360900, 160, 0x835b5539
+0, 361800, 160, 0x612049e9
+0, 362700, 160, 0x91a6503c
+0, 363600, 160, 0x762e4f0e
+0, 364500, 160, 0x2b2153f9
+0, 365400, 160, 0xdcfe5804
+0, 366300, 160, 0x79144cae
+0, 367200, 160, 0xd6394d99
+0, 368100, 160, 0x22395292
+0, 369000, 160, 0x50b04fa0
+0, 369900, 160, 0x846b49a5
+0, 370800, 160, 0x1f554dff
+0, 371700, 160, 0x0aa458dd
+0, 372600, 160, 0x62154dde
+0, 373500, 160, 0xe69847ac
+0, 374400, 160, 0x75855425
+0, 375300, 160, 0x49125665
+0, 376200, 160, 0xa8605945
+0, 377100, 160, 0xc02a5083
+0, 378000, 160, 0x6198537c
+0, 378900, 160, 0x90f25711
+0, 379800, 160, 0x32da51f1
+0, 380700, 160, 0x96c3474d
+0, 381600, 160, 0x82ae4579
+0, 382500, 160, 0xbabf5919
+0, 383400, 160, 0x78095772
+0, 384300, 160, 0x46964abb
+0, 385200, 160, 0x5fcb5ba3
+0, 386100, 160, 0x4a775585
+0, 387000, 160, 0xc41f53af
+0, 387900, 160, 0x457251bc
+0, 388800, 160, 0x8f864fb3
+0, 389700, 160, 0x439d526c
+0, 390600, 160, 0x5cf6503f
+0, 391500, 160, 0x90b7534f
+0, 392400, 160, 0xecc45253
+0, 393300, 160, 0x533b4ee3
+0, 394200, 160, 0x4cc44f27
+0, 395100, 160, 0x6ff35096
+0, 396000, 160, 0x141e4a80
+0, 396900, 160, 0x9e075461
+0, 397800, 160, 0xc4b55791
+0, 398700, 160, 0x40955666
+0, 399600, 160, 0x6255462f
+0, 400500, 160, 0x2cec55d6
+0, 401400, 160, 0xd71652e9
+0, 402300, 160, 0xe65e530c
+0, 403200, 160, 0xeeb9556d
+0, 404100, 160, 0x558f523e
+0, 405000, 160, 0x76e14b00
+0, 405900, 160, 0x3f9f4e9b
+0, 406800, 160, 0x0d7b492a
+0, 407700, 160, 0xdd6e51bd
+0, 408600, 160, 0x5ab353b9
+0, 409500, 160, 0x5b934f33
+0, 410400, 160, 0x36bb57a0
+0, 411300, 160, 0x455d54d3
+0, 412200, 160, 0x7e6853d7
+0, 413100, 160, 0xdcb85ed4
+0, 414000, 160, 0x3a8d5860
+0, 414900, 160, 0x5c90558f
+0, 415800, 160, 0x25504d46
+0, 416700, 160, 0x0fc55413
+0, 417600, 160, 0x98545409
+0, 418500, 160, 0x963b550e
+0, 419400, 160, 0x544a569c
+0, 420300, 160, 0x7ab65f77
+0, 421200, 160, 0x14c257e2
+0, 422100, 160, 0x6cac6262
+0, 423000, 160, 0x2f7f5091
+0, 423900, 160, 0xc2655462
+0, 424800, 160, 0xbb4b4744
+0, 425700, 160, 0x4c5f54db
+0, 426600, 160, 0x9e694ab5
+0, 427500, 160, 0xc2c95173
+0, 428400, 160, 0xf4ae553f
+0, 429300, 160, 0xb4c04ed1
+0, 430200, 160, 0xf3095128
+0, 431100, 160, 0x73b04de1
+0, 432000, 160, 0xff4951c7
+0, 432900, 160, 0x28c156bd
+0, 433800, 160, 0x17b652aa
+0, 434700, 160, 0xb9ce528b
+0, 435600, 160, 0x3cc558be
+0, 436500, 160, 0xdf385905
+0, 437400, 160, 0xe2de4fe2
+0, 438300, 160, 0xc2a6582d
+0, 439200, 160, 0xe5715bc9
+0, 440100, 160, 0x741b6416
+0, 441000, 160, 0xf9b1544f
+0, 441900, 160, 0x012e5f01
+0, 442800, 160, 0x5ab65a49
+0, 443700, 160, 0xfe1e5b1a
+0, 444600, 160, 0x370056ef
+0, 445500, 160, 0xfde45ed4
+0, 446400, 160, 0xa34f6053
+0, 447300, 160, 0x31755604
+0, 448200, 160, 0xc3415bfe
+0, 449100, 160, 0xe5dd5b58
+0, 450000, 160, 0xb6cf5295
+0, 450900, 160, 0x3d81538b
+0, 451800, 160, 0xc00255d2
+0, 452700, 160, 0xb0714f71
+0, 453600, 160, 0x9c9756ac
+0, 454500, 160, 0x4de053a0
+0, 455400, 160, 0x6706500c
+0, 456300, 160, 0x34e4511d
+0, 457200, 160, 0xe4224e3e
+0, 458100, 160, 0xdf695529
+0, 459000, 160, 0xeb1f54e0
+0, 459900, 160, 0x2870550e
+0, 460800, 160, 0x08465464
+0, 461700, 160, 0xe34150e6
+0, 462600, 160, 0xb77556e0
+0, 463500, 160, 0xb23e46ab
+0, 464400, 160, 0x83884a7b
+0, 465300, 160, 0xa0284b16
+0, 466200, 160, 0x87b749e1
+0, 467100, 160, 0x4b276444
+0, 468000, 160, 0x92f95091
+0, 468900, 160, 0x2b1056c2
+0, 469800, 160, 0xd5d5590a
+0, 470700, 160, 0x5a454fac
+0, 471600, 160, 0x0ab05b13
+0, 472500, 160, 0xd98e56ca
+0, 473400, 160, 0x183d5892
+0, 474300, 160, 0x8ba951e4
+0, 475200, 160, 0x487054ff
+0, 476100, 160, 0xc0d05562
+0, 477000, 160, 0x166c590f
+0, 477900, 160, 0x3e254cc0
+0, 478800, 160, 0xd2784ab4
+0, 479700, 160, 0x9f7b4ef6
+0, 480600, 160, 0xdd7653b6
+0, 481500, 160, 0x7ae453b7
+0, 482400, 160, 0xff6c50ec
+0, 483300, 160, 0xfa0d51a9
+0, 484200, 160, 0x29ab583b
+0, 485100, 160, 0x671d5437
+0, 486000, 160, 0x6867569f
+0, 486900, 160, 0xdd775e05
+0, 487800, 160, 0xbafa65ed
+0, 488700, 160, 0xd33f5aea
+0, 489600, 160, 0x851455a8
+0, 490500, 160, 0x044c4d45
+0, 491400, 160, 0xcd7c5d84
+0, 492300, 160, 0xd6565e61
+0, 493200, 160, 0x2f345a92
+0, 494100, 160, 0x50e05530
+0, 495000, 160, 0x787f516a
+0, 495900, 160, 0x75cd5ade
+0, 496800, 160, 0x55b558ad
+0, 497700, 160, 0x55255b01
+0, 498600, 160, 0xfc5b5945
+0, 499500, 160, 0x33914e05
+0, 500400, 160, 0x1f4a5c31
+0, 501300, 160, 0x542f4bf2
+0, 502200, 160, 0xd8b2573f
+0, 503100, 160, 0x127758b0
+0, 504000, 160, 0x18dd5a30
+0, 504900, 160, 0xe8ce61c4
+0, 505800, 160, 0x9a225b47
+0, 506700, 160, 0xd4436314
+0, 507600, 160, 0x2bf06310
+0, 508500, 160, 0x0de35e82
+0, 509400, 160, 0x76cb56f2
+0, 510300, 160, 0x65bc569b
+0, 511200, 160, 0x00a45461
+0, 512100, 160, 0xb5c55019
+0, 513000, 160, 0x5eb04b4d
+0, 513900, 160, 0xf1224c39
+0, 514800, 160, 0x4d135288
+0, 515700, 160, 0x9bc34ba7
+0, 516600, 160, 0xbde3510e
+0, 517500, 160, 0xefaf4fa4
+0, 518400, 160, 0x584950e2
+0, 519300, 160, 0x1e844e27
+0, 520200, 160, 0x38634315
+0, 521100, 160, 0x6b9b4a0b
+0, 522000, 160, 0xd491512a
+0, 522900, 160, 0x8624478c
+0, 523800, 160, 0x67ab45c7
+0, 524700, 160, 0xf78e4c53
+0, 525600, 160, 0xb1654f0d
+0, 526500, 160, 0x17bb4e96
+0, 527400, 160, 0xf3165e7c
+0, 528300, 160, 0xf7914633
+0, 529200, 160, 0x3421530f
+0, 530100, 160, 0x492e572c
+0, 531000, 160, 0xa3185319
+0, 531900, 160, 0x92d054c0
+0, 532800, 160, 0x1cc24ce1
+0, 533700, 160, 0x2ebc519e
+0, 534600, 160, 0x946b53e7
+0, 535500, 160, 0xf85c4fe6
+0, 536400, 160, 0x2974534c
+0, 537300, 160, 0xef7e4a28
+0, 538200, 160, 0x01a74c6e
+0, 539100, 160, 0x2a865674
+0, 540000, 160, 0x70474faf
+0, 540900, 160, 0x2df75014
+0, 541800, 160, 0xf1f3574e
+0, 542700, 160, 0x741b5308
+0, 543600, 160, 0xcb34513e
+0, 544500, 160, 0x7b5e50c7
+0, 545400, 160, 0x0165553b
+0, 546300, 160, 0x04b85450
+0, 547200, 160, 0x795d5873
+0, 548100, 160, 0x508859fb
+0, 549000, 160, 0xca09587d
+0, 549900, 160, 0x86a65ac8
+0, 550800, 160, 0x447353fe
+0, 551700, 160, 0x48ca54a5
+0, 552600, 160, 0x1b3e5f3e
+0, 553500, 160, 0x270a5aa2
+0, 554400, 160, 0x48a45c29
+0, 555300, 160, 0xfbf75a0b
+0, 556200, 160, 0xe65161e5
+0, 557100, 160, 0xf47c6701
+0, 558000, 160, 0xc12058bc
+0, 558900, 160, 0xdb17520c
+0, 559800, 160, 0x860455bd
+0, 560700, 160, 0xa02d56de
+0, 561600, 160, 0xf5574c7d
+0, 562500, 160, 0x500e59b3
+0, 563400, 160, 0xf0b75894
+0, 564300, 160, 0x9d454a04
+0, 565200, 160, 0x0b0554a4
+0, 566100, 160, 0x3fc34d98
+0, 567000, 160, 0x538550b8
+0, 567900, 160, 0xd84e495e
+0, 568800, 160, 0x736c4e17
+0, 569700, 160, 0xa59e5607
+0, 570600, 160, 0xe7485609
+0, 571500, 160, 0x20185a67
+0, 572400, 160, 0x9aa5576f
+0, 573300, 160, 0xed8c5d11
+0, 574200, 160, 0xecef5494
+0, 575100, 160, 0x76f75a5c
+0, 576000, 160, 0xa8fa5322
+0, 576900, 160, 0xd1945734
+0, 577800, 160, 0x817f5c82
+0, 578700, 160, 0x40756063
+0, 579600, 160, 0x524454c7
+0, 580500, 160, 0x5a776106
+0, 581400, 160, 0xd16e5d9d
+0, 582300, 160, 0x8522524c
+0, 583200, 160, 0x4a115bb9
+0, 584100, 160, 0xbf5c5c27
+0, 585000, 160, 0x48905da4
+0, 585900, 160, 0x58735040
+0, 586800, 160, 0x48635631
+0, 587700, 160, 0xf1305eaf
+0, 588600, 160, 0xd34451bd
+0, 589500, 160, 0x1a244fcf
+0, 590400, 160, 0xdb995ca0
+0, 591300, 160, 0xe38e52bb
+0, 592200, 160, 0x00715069
+0, 593100, 160, 0x72a95190
+0, 594000, 160, 0xea7d50b7
+0, 594900, 160, 0xb4094a9c
+0, 595800, 160, 0xd5284d79
+0, 596700, 160, 0x3c4349e5
+0, 597600, 160, 0x65d34e92
+0, 598500, 160, 0x67805756
+0, 599400, 160, 0x1b96502f
+0, 600300, 160, 0x395250ae
+0, 601200, 160, 0x4dc74976
+0, 602100, 160, 0x2666486e
+0, 603000, 160, 0x41924d01
+0, 603900, 160, 0x94a845f5
+0, 604800, 160, 0x1b264cf9
+0, 605700, 160, 0x63ea4aab
+0, 606600, 160, 0x9c0d4a82
+0, 607500, 160, 0x02ba4cf6
+0, 608400, 160, 0x9cd54b87
+0, 609300, 160, 0x24624c5b
+0, 610200, 160, 0x14cf54b1
+0, 611100, 160, 0xce54544b
+0, 612000, 160, 0x459b4fc9
+0, 612900, 160, 0xcc2453f1
+0, 613800, 160, 0xa4ab53bc
+0, 614700, 160, 0x92235013
+0, 615600, 160, 0xbfa257b3
+0, 616500, 160, 0xd32d51f5
+0, 617400, 160, 0x7d5d47e6
+0, 618300, 160, 0xe23d43ed
+0, 619200, 160, 0x51d8514f
+0, 620100, 160, 0x0fa04240
+0, 621000, 160, 0x233c4dce
+0, 621900, 160, 0xcd30466f
+0, 622800, 160, 0x4435546a
+0, 623700, 160, 0x3eb6445b
+0, 624600, 160, 0xcaed4ef9
+0, 625500, 160, 0xf0174da8
+0, 626400, 160, 0x60e756a0
+0, 627300, 160, 0x72ba457d
+0, 628200, 160, 0x84ce4f0f
+0, 629100, 160, 0x660d45ae
+0, 630000, 160, 0xac8446e2
+0, 630900, 160, 0xeeb153b4
+0, 631800, 160, 0x6a634c23
+0, 632700, 160, 0x890f4af8
+0, 633600, 160, 0x1d3743a7
+0, 634500, 160, 0xa37e4ee8
+0, 635400, 160, 0xb9334d56
+0, 636300, 160, 0xc1384bef
+0, 637200, 160, 0x52964f6e
+0, 638100, 160, 0xe36e57e2
+0, 639000, 160, 0x62114a53
+0, 639900, 160, 0xb1f855bb
+0, 640800, 160, 0xf0934da0
+0, 641700, 160, 0xb454494a
+0, 642600, 160, 0xb6e04b15
+0, 643500, 160, 0x933e488e
+0, 644400, 160, 0x762d5ce8
+0, 645300, 160, 0x1c4a4f85
+0, 646200, 160, 0xaaa25313
+0, 647100, 160, 0xd3655979
+0, 648000, 160, 0x8ff149e5
+0, 648900, 160, 0x5d5e51fb
+0, 649800, 160, 0x0a354c51
+0, 650700, 160, 0x79ea52ee
+0, 651600, 160, 0x306e5365
+0, 652500, 160, 0x7e03546a
+0, 653400, 160, 0x71575ddf
+0, 654300, 160, 0x08da523d
+0, 655200, 160, 0x2a2152b2
+0, 656100, 160, 0x50e55447
+0, 657000, 160, 0xf3b55758
+0, 657900, 160, 0xc29d5f12
+0, 658800, 160, 0x0c0b5778
+0, 659700, 160, 0x1b07593a
+0, 660600, 160, 0x946f562d
+0, 661500, 160, 0xcdc85636
+0, 662400, 160, 0x2421589b
+0, 663300, 160, 0x8e3b5451
+0, 664200, 160, 0xd565536a
+0, 665100, 160, 0x8d225557
+0, 666000, 160, 0xa0084e44
+0, 666900, 160, 0x85bd5413
+0, 667800, 160, 0xa4be4c3b
+0, 668700, 160, 0x332957c8
+0, 669600, 160, 0x60505225
+0, 670500, 160, 0x3d154eb3
+0, 671400, 160, 0xd85359f4
+0, 672300, 160, 0xf95b4f6b
+0, 673200, 160, 0x8bea5846
+0, 674100, 160, 0x43835a02
+0, 675000, 160, 0x340b5732
+0, 675900, 160, 0x8b6d5005
+0, 676800, 160, 0xa4995aca
+0, 677700, 160, 0x88d34efc
+0, 678600, 160, 0x078e5003
+0, 679500, 160, 0x09964b19
+0, 680400, 160, 0x2eaf5120
+0, 681300, 160, 0x52514d52
+0, 682200, 160, 0x08f84d4c
+0, 683100, 160, 0x4a9b4cc7
+0, 684000, 160, 0x947f4ca6
+0, 684900, 160, 0x086a4f32
+0, 685800, 160, 0x0e0857a6
+0, 686700, 160, 0x38145bf7
+0, 687600, 160, 0xc6e156bf
+0, 688500, 160, 0xb07853b2
+0, 689400, 160, 0xaeda5172
+0, 690300, 160, 0xc4e54d07
+0, 691200, 160, 0x0b075a61
+0, 692100, 160, 0x09f05c1f
+0, 693000, 160, 0xf5415796
+0, 693900, 160, 0xe3be584e
+0, 694800, 160, 0x6e1656f9
+0, 695700, 160, 0xd6d85599
+0, 696600, 160, 0xd9b4502e
+0, 697500, 160, 0x1186598c
+0, 698400, 160, 0x879c543d
+0, 699300, 160, 0x5b2551a3
+0, 700200, 160, 0xcf50528d
+0, 701100, 160, 0x95d059b2
+0, 702000, 160, 0x34ba5515
+0, 702900, 160, 0x7a014ba8
+0, 703800, 160, 0x27725169
+0, 704700, 160, 0x2fd14ca4
+0, 705600, 160, 0xd5ad542a
+0, 706500, 160, 0xddc24d2e
+0, 707400, 160, 0x8a4b48b4
+0, 708300, 160, 0x915e4a29
+0, 709200, 160, 0xd56d4cae
+0, 710100, 160, 0x59594eea
+0, 711000, 160, 0x87085338
+0, 711900, 160, 0xa5ee538f
+0, 712800, 160, 0xf34e5030
+0, 713700, 160, 0x6bef4da7
+0, 714600, 160, 0x05a14c52
+0, 715500, 160, 0x67bc49ce
+0, 716400, 160, 0xb18f4cff
+0, 717300, 160, 0x5d744e6d
+0, 718200, 160, 0xcb7c5973
+0, 719100, 160, 0x6df056f0
+0, 720000, 160, 0xd62c4e00
+0, 720900, 160, 0xa54d4d1e
+0, 721800, 160, 0xdaa250b0
+0, 722700, 160, 0x350e475f
+0, 723600, 160, 0x0e454bb2
+0, 724500, 160, 0xe37949ca
+0, 725400, 160, 0x551453bf
+0, 726300, 160, 0x35d04c27
+0, 727200, 160, 0x6749469d
+0, 728100, 160, 0x544752e9
+0, 729000, 160, 0xf23b4888
+0, 729900, 160, 0x6f0a5519
+0, 730800, 160, 0x808a58df
+0, 731700, 160, 0x8e674c88
+0, 732600, 160, 0xd3ab51f7
+0, 733500, 160, 0x985d500f
+0, 734400, 160, 0x734e52d8
+0, 735300, 160, 0xb0da5227
+0, 736200, 160, 0xcc7d4a21
+0, 737100, 160, 0xb1354baf
+0, 738000, 160, 0xfc8d4f9a
+0, 738900, 160, 0x6f044d82
+0, 739800, 160, 0x41e7546b
+0, 740700, 160, 0x67014682
+0, 741600, 160, 0x5516575b
+0, 742500, 160, 0x26254693
+0, 743400, 160, 0x81ce4af5
+0, 744300, 160, 0x77f152a0
+0, 745200, 160, 0x995a5096
+0, 746100, 160, 0x6114532e
+0, 747000, 160, 0x4df457f3
+0, 747900, 160, 0xbcd94804
+0, 748800, 160, 0x1e544fd2
+0, 749700, 160, 0xa70b5954
+0, 750600, 160, 0x1c77484c
+0, 751500, 160, 0xb07f4c42
+0, 752400, 160, 0x62074f1f
+0, 753300, 160, 0xf3b656a1
+0, 754200, 160, 0x65734ac0
+0, 755100, 160, 0x2a9752cd
+0, 756000, 160, 0x15ff4ef0
+0, 756900, 160, 0xabd4532c
+0, 757800, 160, 0x8a44503a
+0, 758700, 160, 0xbf4250f3
+0, 759600, 160, 0x17594ac5
+0, 760500, 160, 0x7b5e4b24
+0, 761400, 160, 0x24684cb5
+0, 762300, 160, 0xc4d54b42
+0, 763200, 160, 0xd48f58af
+0, 764100, 160, 0x0374593a
+0, 765000, 160, 0x398a5b0d
+0, 765900, 160, 0xf60855e6
+0, 766800, 160, 0x6fbb5587
+0, 767700, 160, 0x44405c2b
+0, 768600, 160, 0xa6345d70
+0, 769500, 160, 0x464557d5
+0, 770400, 160, 0x0c3153ca
+0, 771300, 160, 0x15ec50c4
+0, 772200, 160, 0xd5e559da
+0, 773100, 160, 0x999757b9
+0, 774000, 160, 0x7a5d5754
+0, 774900, 160, 0xf85b5f18
+0, 775800, 160, 0xa66d5c72
+0, 776700, 160, 0xd8f55981
+0, 777600, 160, 0xe6364f64
+0, 778500, 160, 0x528a5785
+0, 779400, 160, 0xdefe5332
+0, 780300, 160, 0x4bc4532e
+0, 781200, 160, 0x505a4eb3
+0, 782100, 160, 0xa28d589d
+0, 783000, 160, 0x092d511f
+0, 783900, 160, 0x3079591e
+0, 784800, 160, 0x2b1d5339
+0, 785700, 160, 0xf8d849d1
+0, 786600, 160, 0xadb056a6
+0, 787500, 160, 0x2ee74c4f
+0, 788400, 160, 0x35c34c9f
+0, 789300, 160, 0xb6ae53d3
+0, 790200, 160, 0x7258534e
+0, 791100, 160, 0xb76d4b1b
+0, 792000, 160, 0x99a14a0f
+0, 792900, 160, 0x88365944
+0, 793800, 160, 0x97cf4aed
+0, 794700, 160, 0x444b56f6
+0, 795600, 160, 0x1d1f4b01
+0, 796500, 160, 0x3dcd417e
+0, 797400, 160, 0xa4985140
+0, 798300, 160, 0x86f94c4d
+0, 799200, 160, 0xc3635436
+0, 800100, 160, 0x198b432b
+0, 801000, 160, 0xae5253e4
+0, 801900, 160, 0x248c4f1a
+0, 802800, 160, 0x787a45df
+0, 803700, 160, 0x5fd44cad
+0, 804600, 160, 0x68be581c
+0, 805500, 160, 0x5ff5531b
+0, 806400, 160, 0x2bcd4aa1
+0, 807300, 160, 0x0d134a7c
+0, 808200, 160, 0x28af5885
+0, 809100, 160, 0xc09f4d65
+0, 810000, 160, 0x7468552d
+0, 810900, 160, 0x82df49ac
+0, 811800, 160, 0xe3725fdc
+0, 812700, 160, 0x0ec74d11
+0, 813600, 160, 0xfc2a5355
+0, 814500, 160, 0x41df4d4f
+0, 815400, 160, 0x4ebe473d
+0, 816300, 160, 0xd8734bf2
+0, 817200, 160, 0x4acd5056
+0, 818100, 160, 0x47805700
+0, 819000, 160, 0xe4f25135
+0, 819900, 160, 0x9f195649
+0, 820800, 160, 0x8b055f64
+0, 821700, 160, 0xc4b751c8
+0, 822600, 160, 0x95e55ba4
+0, 823500, 160, 0xf0955494
+0, 824400, 160, 0xca1a47b9
+0, 825300, 160, 0x9d025711
+0, 826200, 160, 0xf6cb4a0a
+0, 827100, 160, 0xd8385b4d
+0, 828000, 160, 0x7b2852b6
+0, 828900, 160, 0x90a35643
+0, 829800, 160, 0x63105d0a
+0, 830700, 160, 0x55414083
+0, 831600, 160, 0xc94554a9
+0, 832500, 160, 0xa88f4a36
+0, 833400, 160, 0xda5d52bc
+0, 834300, 160, 0x5b3943da
+0, 835200, 160, 0xd2314755
+0, 836100, 160, 0x743c4cdc
+0, 837000, 160, 0x7c3e4dc2
+0, 837900, 160, 0x12644715
+0, 838800, 160, 0x1050480b
+0, 839700, 160, 0x73645906
+0, 840600, 160, 0x28ef4a9e
+0, 841500, 160, 0xf72440bc
+0, 842400, 160, 0x41964bda
+0, 843300, 160, 0x2afb4d9b
+0, 844200, 160, 0xf74b4c5a
+0, 845100, 160, 0xcf165e2e
+0, 846000, 160, 0x3dbb4d06
+0, 846900, 160, 0xbd9755f9
+0, 847800, 160, 0x3248581d
+0, 848700, 160, 0xc00c559d
+0, 849600, 160, 0xff6c4b0a
+0, 850500, 160, 0x154157e3
+0, 851400, 160, 0xb996499c
+0, 852300, 160, 0xe1a059ba
+0, 853200, 160, 0x98015946
+0, 854100, 160, 0x168b4ceb
+0, 855000, 160, 0x567b4f83
+0, 855900, 160, 0x903e52f8
+0, 856800, 160, 0xc0a252dc
+0, 857700, 160, 0x08cb4b70
+0, 858600, 160, 0x3d9a5be6
+0, 859500, 160, 0x904b4907
+0, 860400, 160, 0x738847b1
+0, 861300, 160, 0x10405c19
+0, 862200, 160, 0x8c134f27
+0, 863100, 160, 0xdfe34d7f
+0, 864000, 160, 0x9d0948a8
+0, 864900, 160, 0x67755611
+0, 865800, 160, 0x46734258
+0, 866700, 160, 0x76f449fa
+0, 867600, 160, 0xfad64d30
+0, 868500, 160, 0x7f4357f4
+0, 869400, 160, 0xd20e5079
+0, 870300, 160, 0xdf7857ec
+0, 871200, 160, 0x46ff4891
+0, 872100, 160, 0x1b724ffc
+0, 873000, 160, 0xdf20545a
+0, 873900, 160, 0xeb5254e0
+0, 874800, 160, 0x794b4a96
+0, 875700, 160, 0x86a15147
+0, 876600, 160, 0x30f75504
+0, 877500, 160, 0x39575354
+0, 878400, 160, 0xb6a35351
+0, 879300, 160, 0x9da34c3a
+0, 880200, 160, 0xcf2d5386
+0, 881100, 160, 0xa7f353f6
+0, 882000, 160, 0xa6e34e95
+0, 882900, 160, 0x98174400
+0, 883800, 160, 0x13685641
+0, 884700, 160, 0x99215154
+0, 885600, 160, 0x5be75237
+0, 886500, 160, 0x4cb64942
+0, 887400, 160, 0x15de4e03
+0, 888300, 160, 0x613a4fd5
+0, 889200, 160, 0xc97c4821
+0, 890100, 160, 0xbf1558f2
+0, 891000, 160, 0x651d4cf4
+0, 891900, 160, 0xbee44a56
+0, 892800, 160, 0x6cbd4c20
+0, 893700, 160, 0xcf45493d
+0, 894600, 160, 0x73e74d2a
+0, 895500, 160, 0x6a3256e4
+0, 896400, 160, 0x89ac4a68
+0, 897300, 160, 0x0d2652aa
+0, 898200, 160, 0x56ce4b78
+0, 899100, 160, 0xb7b24bcb
diff --git a/tests/ref/fate/gif-color b/tests/ref/fate/gif-color
new file mode 100644
index 0000000..6abb565
--- /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
--- /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
--- /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
--- /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
--- /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..67b32af
--- /dev/null
+++ b/tests/ref/fate/gifenc-bgr4_byte
@@ -0,0 +1,174 @@
+#tb 0: 1/100
+0, 0, 0, 1, 507, 0x91080fbf
+0, 10, 10, 1, 213, 0x4f554bd7, S=1, 1024, 0xb6327c81
+0, 20, 20, 1, 130, 0xfe2d2987, 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, 517, 0xefb5d826, S=1, 1024, 0x9e4a7c81
+0, 70, 70, 1, 535, 0x326ce62a, S=1, 1024, 0x9e4a7c81
+0, 80, 80, 1, 437, 0x7c5db7bf, S=1, 1024, 0xb6327c81
+0, 90, 90, 1, 923, 0x9fb1a37c, S=1, 1024, 0xb6327c81
+0, 100, 100, 1, 693, 0xa7b549a4, 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, 1275, 0xf0f438db, S=1, 1024, 0xb6327c81
+0, 160, 160, 1, 1474, 0xb41c97ee, S=1, 1024, 0xb6327c81
+0, 170, 170, 1, 1783, 0x86164ae5, 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, 1717, 0x1d251ebd, S=1, 1024, 0xde0a7c81
+0, 240, 240, 1, 1900, 0x2ea879d1, S=1, 1024, 0xde0a7c81
+0, 250, 250, 1, 1806, 0xb071522f, 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, 2894, 0x62d9484c, 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, 3599, 0xd65f7633, S=1, 1024, 0xde0a7c81
+0, 350, 350, 1, 3698, 0x0b9e9fe2, S=1, 1024, 0xde0a7c81
+0, 360, 360, 1, 3814, 0x1869d3f4, S=1, 1024, 0xde0a7c81
+0, 370, 370, 1, 3626, 0x9be87da6, 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, 3093, 0x94cc8552, S=1, 1024, 0xde0a7c81
+0, 410, 410, 1, 3456, 0x01432c82, S=1, 1024, 0xde0a7c81
+0, 420, 420, 1, 4107, 0x9bea5c65, S=1, 1024, 0xde0a7c81
+0, 430, 430, 1, 4216, 0x23875ba3, S=1, 1024, 0xde0a7c81
+0, 440, 440, 1, 3613, 0xd0684d83, S=1, 1024, 0xde0a7c81
+0, 450, 450, 1, 3909, 0x1995e691, S=1, 1024, 0xde0a7c81
+0, 460, 460, 1, 4460, 0x791ce33c, S=1, 1024, 0xde0a7c81
+0, 470, 470, 1, 4592, 0x04ed2dd0, S=1, 1024, 0xde0a7c81
+0, 480, 480, 1, 4821, 0xbff89882, S=1, 1024, 0xde0a7c81
+0, 490, 490, 1, 5397, 0xf483c31d, S=1, 1024, 0xde0a7c81
+0, 500, 500, 1, 5266, 0x21c695aa, S=1, 1024, 0xde0a7c81
+0, 510, 510, 1, 5415, 0x0efce3ec, 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, 7595, 0x0ba1e430, 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, 11482, 0x6521f3c4, 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, 11927, 0x8135c9a6, S=1, 1024, 0xde0a7c81
+0, 1070, 1070, 1, 11932, 0x722abcbe, S=1, 1024, 0xde0a7c81
+0, 1080, 1080, 1, 12280, 0x9cc46f52, 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, 12667, 0x31c94f78, S=1, 1024, 0xde0a7c81
+0, 1130, 1130, 1, 12957, 0x4da59f8c, S=1, 1024, 0xde0a7c81
+0, 1140, 1140, 1, 13053, 0x9a63df59, 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, 13197, 0xd32858d3, 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, 17396, 0x02ec1121, S=1, 1024, 0xde0a7c81
+0, 1490, 1490, 1, 17430, 0xdb5cf2d2, 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..040c233
--- /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, 437, 0xc31bce1a, 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, 613, 0x47b82005, 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, 2247, 0xdf2725b0, 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, 2686, 0x8e0b00e5, 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, 2981, 0x050d7ad4, S=1, 1024, 0xf351799f
+0, 250, 250, 1, 3101, 0xbcc89bec, S=1, 1024, 0xf351799f
+0, 260, 260, 1, 3252, 0xdb80f3f9, S=1, 1024, 0xf351799f
+0, 270, 270, 1, 3329, 0xe4d42430, S=1, 1024, 0xf351799f
+0, 280, 280, 1, 3571, 0x6c7d8a9f, S=1, 1024, 0xf351799f
+0, 290, 290, 1, 3806, 0x4255f9f2, S=1, 1024, 0xf351799f
+0, 300, 300, 1, 2749, 0x64681c32, 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, 4294, 0xeb280b37, 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, 2280, 0x1a394d2f, S=1, 1024, 0xf351799f
+0, 370, 370, 1, 3632, 0x66ad992e, S=1, 1024, 0xf351799f
+0, 380, 380, 1, 3552, 0x23697490, S=1, 1024, 0xf351799f
+0, 390, 390, 1, 3689, 0x868adbb7, S=1, 1024, 0xf351799f
+0, 400, 400, 1, 1558, 0x7a13e53b, S=1, 1024, 0xf351799f
+0, 410, 410, 1, 939, 0xe565cba1, S=1, 1024, 0xf351799f
+0, 420, 420, 1, 273, 0x3687799b, S=1, 1024, 0xf351799f
+0, 430, 430, 1, 929, 0x788ab0c3, 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, 4894, 0x7315406b, S=1, 1024, 0xf351799f
+0, 480, 480, 1, 4927, 0x092e19d6, S=1, 1024, 0xf351799f
+0, 490, 490, 1, 4941, 0x58a357da, S=1, 1024, 0xf351799f
+0, 500, 500, 1, 4153, 0x7582ac32, S=1, 1024, 0xf351799f
+0, 510, 510, 1, 4677, 0xeaa3c04f, S=1, 1024, 0xf351799f
+0, 520, 520, 1, 4740, 0x636bb580, S=1, 1024, 0xf351799f
+0, 530, 530, 1, 4981, 0x31d556d4, 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, 4288, 0xbc3af716, 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, 4644, 0x7cc08935, 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, 5216, 0x65f09bd1, S=1, 1024, 0xf351799f
+0, 650, 650, 1, 5394, 0x1293ff65, S=1, 1024, 0xf351799f
+0, 660, 660, 1, 5219, 0x9aa2dcc4, 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, 7540, 0xdc032153, 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, 7617, 0x574430d4, 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, 11226, 0x74889117, 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, 18390, 0xb8319208, 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, 23164, 0x755347ac, 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..404237d
--- /dev/null
+++ b/tests/ref/fate/gifenc-gray
@@ -0,0 +1,174 @@
+#tb 0: 1/100
+0, 0, 0, 1, 568, 0xe1d43487
+0, 10, 10, 1, 142, 0x92d43281, S=1, 1024, 0xc2f67c9f
+0, 20, 20, 1, 130, 0x29383852, S=1, 1024, 0xc2f67c9f
+0, 30, 30, 1, 129, 0x036732fa, S=1, 1024, 0xc2f67c9f
+0, 40, 40, 1, 145, 0xcbc036bb, S=1, 1024, 0xc2f67c9f
+0, 50, 50, 1, 135, 0x6e4536d1, S=1, 1024, 0xc2f67c9f
+0, 60, 60, 1, 127, 0xe73f2f55, S=1, 1024, 0xc2f67c9f
+0, 70, 70, 1, 119, 0x7912307f, S=1, 1024, 0xc2f67c9f
+0, 80, 80, 1, 132, 0xce58343c, S=1, 1024, 0xc2f67c9f
+0, 90, 90, 1, 126, 0x1fcd2b9c, S=1, 1024, 0xc2f67c9f
+0, 100, 100, 1, 127, 0x6c293369, S=1, 1024, 0xc2f67c9f
+0, 110, 110, 1, 126, 0x19162e3f, S=1, 1024, 0xc2f67c9f
+0, 120, 120, 1, 119, 0x06602dec, S=1, 1024, 0xc2f67c9f
+0, 130, 130, 1, 118, 0x8b083037, S=1, 1024, 0xc2f67c9f
+0, 140, 140, 1, 115, 0xa8372c6d, S=1, 1024, 0xc2f67c9f
+0, 150, 150, 1, 114, 0x8d0f2dbd, S=1, 1024, 0xc2f67c9f
+0, 160, 160, 1, 129, 0xb5ab318d, S=1, 1024, 0xc2f67c9f
+0, 170, 170, 1, 129, 0x278e34bd, S=1, 1024, 0xc2f67c9f
+0, 180, 180, 1, 119, 0x408e3131, S=1, 1024, 0xc2f67c9f
+0, 190, 190, 1, 121, 0x069a2c25, S=1, 1024, 0xc2f67c9f
+0, 200, 200, 1, 127, 0x24793635, S=1, 1024, 0xc2f67c9f
+0, 210, 210, 1, 110, 0xe30a29cc, S=1, 1024, 0xc2f67c9f
+0, 220, 220, 1, 116, 0xf7b827f0, S=1, 1024, 0xc2f67c9f
+0, 230, 230, 1, 118, 0xf5f62ff6, S=1, 1024, 0xc2f67c9f
+0, 240, 240, 1, 115, 0xb7c92c27, S=1, 1024, 0xc2f67c9f
+0, 250, 250, 1, 114, 0x0a642b7e, S=1, 1024, 0xc2f67c9f
+0, 260, 260, 1, 114, 0x07b32c7c, S=1, 1024, 0xc2f67c9f
+0, 270, 270, 1, 118, 0x1f4432b8, S=1, 1024, 0xc2f67c9f
+0, 280, 280, 1, 144, 0xa81e3c75, S=1, 1024, 0xc2f67c9f
+0, 290, 290, 1, 121, 0xacb828d6, S=1, 1024, 0xc2f67c9f
+0, 300, 300, 1, 148, 0xb245426a, S=1, 1024, 0xc2f67c9f
+0, 310, 310, 1, 124, 0x3d173009, S=1, 1024, 0xc2f67c9f
+0, 320, 320, 1, 151, 0xa57c443d, S=1, 1024, 0xc2f67c9f
+0, 330, 330, 1, 121, 0x93da2d00, S=1, 1024, 0xc2f67c9f
+0, 340, 340, 1, 124, 0x1dd02f53, S=1, 1024, 0xc2f67c9f
+0, 350, 350, 1, 117, 0xb0942d05, S=1, 1024, 0xc2f67c9f
+0, 360, 360, 1, 117, 0xb5af292b, S=1, 1024, 0xc2f67c9f
+0, 370, 370, 1, 116, 0x731a30ff, S=1, 1024, 0xc2f67c9f
+0, 380, 380, 1, 123, 0x16342dde, S=1, 1024, 0xc2f67c9f
+0, 390, 390, 1, 117, 0xef9e2f92, S=1, 1024, 0xc2f67c9f
+0, 400, 400, 1, 110, 0x646e2a4a, S=1, 1024, 0xc2f67c9f
+0, 410, 410, 1, 110, 0xe44f2be1, S=1, 1024, 0xc2f67c9f
+0, 420, 420, 1, 108, 0x58f22c11, S=1, 1024, 0xc2f67c9f
+0, 430, 430, 1, 112, 0x2c702d3e, S=1, 1024, 0xc2f67c9f
+0, 440, 440, 1, 111, 0x7b412ab9, S=1, 1024, 0xc2f67c9f
+0, 450, 450, 1, 112, 0xe95d2dfb, S=1, 1024, 0xc2f67c9f
+0, 460, 460, 1, 109, 0x2baf2bde, S=1, 1024, 0xc2f67c9f
+0, 470, 470, 1, 114, 0x3a772c6a, S=1, 1024, 0xc2f67c9f
+0, 480, 480, 1, 110, 0xfe702831, S=1, 1024, 0xc2f67c9f
+0, 490, 490, 1, 125, 0xa31f344b, S=1, 1024, 0xc2f67c9f
+0, 500, 500, 1, 119, 0xbc31318d, S=1, 1024, 0xc2f67c9f
+0, 510, 510, 1, 115, 0xc7b62b8f, S=1, 1024, 0xc2f67c9f
+0, 520, 520, 1, 118, 0x7cf22dcb, S=1, 1024, 0xc2f67c9f
+0, 530, 530, 1, 119, 0xe16c2f96, S=1, 1024, 0xc2f67c9f
+0, 540, 540, 1, 119, 0x86d43604, S=1, 1024, 0xc2f67c9f
+0, 550, 550, 1, 109, 0x22b72af1, S=1, 1024, 0xc2f67c9f
+0, 560, 560, 1, 103, 0x12982731, S=1, 1024, 0xc2f67c9f
+0, 570, 570, 1, 114, 0x6ef22e10, S=1, 1024, 0xc2f67c9f
+0, 580, 580, 1, 109, 0x621b26dd, S=1, 1024, 0xc2f67c9f
+0, 590, 590, 1, 110, 0xfe062836, S=1, 1024, 0xc2f67c9f
+0, 600, 600, 1, 112, 0x4a8e2ce3, S=1, 1024, 0xc2f67c9f
+0, 610, 610, 1, 111, 0xa7ae2865, S=1, 1024, 0xc2f67c9f
+0, 620, 620, 1, 103, 0x80bc2b33, S=1, 1024, 0xc2f67c9f
+0, 630, 630, 1, 114, 0xc2f92f3f, S=1, 1024, 0xc2f67c9f
+0, 640, 640, 1, 108, 0x81332cdf, S=1, 1024, 0xc2f67c9f
+0, 650, 650, 1, 121, 0x0d1133ad, S=1, 1024, 0xc2f67c9f
+0, 660, 660, 1, 136, 0x2c0c3481, S=1, 1024, 0xc2f67c9f
+0, 670, 670, 1, 108, 0x55222d1f, S=1, 1024, 0xc2f67c9f
+0, 680, 680, 1, 125, 0x9cc536df, S=1, 1024, 0xc2f67c9f
+0, 690, 690, 1, 114, 0x04602ae4, S=1, 1024, 0xc2f67c9f
+0, 700, 700, 1, 99, 0xd58f291d, S=1, 1024, 0xc2f67c9f
+0, 710, 710, 1, 98, 0xcb8f2807, S=1, 1024, 0xc2f67c9f
+0, 720, 720, 1, 109, 0x7f292c9b, S=1, 1024, 0xc2f67c9f
+0, 730, 730, 1, 106, 0x3daa297f, S=1, 1024, 0xc2f67c9f
+0, 740, 740, 1, 100, 0xb7032b73, S=1, 1024, 0xc2f67c9f
+0, 750, 750, 1, 88, 0xd56b218e, S=1, 1024, 0xc2f67c9f
+0, 760, 760, 1, 93, 0xdcfd2353, S=1, 1024, 0xc2f67c9f
+0, 770, 770, 1, 112, 0x35322b03, S=1, 1024, 0xc2f67c9f
+0, 780, 780, 1, 112, 0x7c2b2d67, S=1, 1024, 0xc2f67c9f
+0, 790, 790, 1, 204, 0xd02c5bd9, S=1, 1024, 0xc2f67c9f
+0, 800, 800, 1, 204, 0x82055f0a, S=1, 1024, 0xc2f67c9f
+0, 810, 810, 1, 115, 0x76472e9b, S=1, 1024, 0xc2f67c9f
+0, 820, 820, 1, 110, 0x22b12abc, S=1, 1024, 0xc2f67c9f
+0, 830, 830, 1, 116, 0x50a0318e, S=1, 1024, 0xc2f67c9f
+0, 840, 840, 1, 115, 0x10632f57, S=1, 1024, 0xc2f67c9f
+0, 850, 850, 1, 120, 0x9c5631e3, S=1, 1024, 0xc2f67c9f
+0, 860, 860, 1, 114, 0x0e192ed8, S=1, 1024, 0xc2f67c9f
+0, 870, 870, 1, 109, 0xdedb2a99, S=1, 1024, 0xc2f67c9f
+0, 880, 880, 1, 105, 0x639c2cf5, S=1, 1024, 0xc2f67c9f
+0, 890, 890, 1, 117, 0x4aff2afa, S=1, 1024, 0xc2f67c9f
+0, 900, 900, 1, 103, 0x44842781, S=1, 1024, 0xc2f67c9f
+0, 910, 910, 1, 147, 0x22493e48, S=1, 1024, 0xc2f67c9f
+0, 920, 920, 1, 117, 0x3cb02d86, S=1, 1024, 0xc2f67c9f
+0, 930, 930, 1, 111, 0x813d2e1f, S=1, 1024, 0xc2f67c9f
+0, 940, 940, 1, 83, 0xb6961b02, S=1, 1024, 0xc2f67c9f
+0, 950, 950, 1, 159, 0x5f2e43d0, S=1, 1024, 0xc2f67c9f
+0, 960, 960, 1, 126, 0x56d42d1d, S=1, 1024, 0xc2f67c9f
+0, 970, 970, 1, 164, 0xea6c464d, S=1, 1024, 0xc2f67c9f
+0, 980, 980, 1, 133, 0x21113425, S=1, 1024, 0xc2f67c9f
+0, 990, 990, 1, 125, 0xfc6e322e, S=1, 1024, 0xc2f67c9f
+0, 1000, 1000, 1, 116, 0x226830da, S=1, 1024, 0xc2f67c9f
+0, 1010, 1010, 1, 130, 0xa71a317d, S=1, 1024, 0xc2f67c9f
+0, 1020, 1020, 1, 127, 0x5b5433af, S=1, 1024, 0xc2f67c9f
+0, 1030, 1030, 1, 172, 0x0ed64b21, S=1, 1024, 0xc2f67c9f
+0, 1040, 1040, 1, 142, 0x9733380f, S=1, 1024, 0xc2f67c9f
+0, 1050, 1050, 1, 184, 0x358b533c, S=1, 1024, 0xc2f67c9f
+0, 1060, 1060, 1, 155, 0x5304441c, S=1, 1024, 0xc2f67c9f
+0, 1070, 1070, 1, 139, 0x15743a98, S=1, 1024, 0xc2f67c9f
+0, 1080, 1080, 1, 129, 0xc5782f81, S=1, 1024, 0xc2f67c9f
+0, 1090, 1090, 1, 144, 0x1ee637c8, S=1, 1024, 0xc2f67c9f
+0, 1100, 1100, 1, 133, 0x69403297, S=1, 1024, 0xc2f67c9f
+0, 1110, 1110, 1, 192, 0x128553a4, S=1, 1024, 0xc2f67c9f
+0, 1120, 1120, 1, 159, 0xea783f5a, S=1, 1024, 0xc2f67c9f
+0, 1130, 1130, 1, 201, 0xc04252a1, S=1, 1024, 0xc2f67c9f
+0, 1140, 1140, 1, 161, 0xb56b44f6, S=1, 1024, 0xc2f67c9f
+0, 1150, 1150, 1, 136, 0x402130e8, S=1, 1024, 0xc2f67c9f
+0, 1160, 1160, 1, 117, 0x694c3490, S=1, 1024, 0xc2f67c9f
+0, 1170, 1170, 1, 151, 0x96803b5d, S=1, 1024, 0xc2f67c9f
+0, 1180, 1180, 1, 135, 0x9a9b399f, S=1, 1024, 0xc2f67c9f
+0, 1190, 1190, 1, 147, 0x7e83348d, S=1, 1024, 0xc2f67c9f
+0, 1200, 1200, 1, 135, 0x932e3720, S=1, 1024, 0xc2f67c9f
+0, 1210, 1210, 1, 183, 0x822946e2, S=1, 1024, 0xc2f67c9f
+0, 1220, 1220, 1, 116, 0x93652e25, S=1, 1024, 0xc2f67c9f
+0, 1230, 1230, 1, 117, 0x77063135, S=1, 1024, 0xc2f67c9f
+0, 1240, 1240, 1, 109, 0x12752965, S=1, 1024, 0xc2f67c9f
+0, 1250, 1250, 1, 111, 0x8fd62b54, S=1, 1024, 0xc2f67c9f
+0, 1260, 1260, 1, 188, 0x6c1850e5, S=1, 1024, 0xc2f67c9f
+0, 1270, 1270, 1, 121, 0x15003168, S=1, 1024, 0xc2f67c9f
+0, 1280, 1280, 1, 115, 0x93482f77, S=1, 1024, 0xc2f67c9f
+0, 1290, 1290, 1, 120, 0x36552de5, S=1, 1024, 0xc2f67c9f
+0, 1300, 1300, 1, 117, 0x74472f78, S=1, 1024, 0xc2f67c9f
+0, 1310, 1310, 1, 188, 0xadac5400, S=1, 1024, 0xc2f67c9f
+0, 1320, 1320, 1, 125, 0xccb83070, S=1, 1024, 0xc2f67c9f
+0, 1330, 1330, 1, 118, 0x606e2d29, S=1, 1024, 0xc2f67c9f
+0, 1340, 1340, 1, 130, 0x77eb3516, S=1, 1024, 0xc2f67c9f
+0, 1350, 1350, 1, 120, 0x500f3045, S=1, 1024, 0xc2f67c9f
+0, 1360, 1360, 1, 164, 0x729244f4, S=1, 1024, 0xc2f67c9f
+0, 1370, 1370, 1, 234, 0xff2969ee, S=1, 1024, 0xc2f67c9f
+0, 1380, 1380, 1, 207, 0xf9366155, S=1, 1024, 0xc2f67c9f
+0, 1390, 1390, 1, 210, 0x31555d58, S=1, 1024, 0xc2f67c9f
+0, 1400, 1400, 1, 118, 0x7f9a32bd, S=1, 1024, 0xc2f67c9f
+0, 1410, 1410, 1, 120, 0xfba63099, S=1, 1024, 0xc2f67c9f
+0, 1420, 1420, 1, 114, 0xcb382d23, S=1, 1024, 0xc2f67c9f
+0, 1430, 1430, 1, 115, 0x10f32bad, S=1, 1024, 0xc2f67c9f
+0, 1440, 1440, 1, 206, 0x405e630e, S=1, 1024, 0xc2f67c9f
+0, 1450, 1450, 1, 216, 0xf6e6635f, S=1, 1024, 0xc2f67c9f
+0, 1460, 1460, 1, 123, 0x43aa33b8, S=1, 1024, 0xc2f67c9f
+0, 1470, 1470, 1, 121, 0x780d3018, S=1, 1024, 0xc2f67c9f
+0, 1480, 1480, 1, 121, 0xdba92f73, S=1, 1024, 0xc2f67c9f
+0, 1490, 1490, 1, 118, 0x35b32e26, S=1, 1024, 0xc2f67c9f
+0, 1500, 1500, 1, 116, 0x79ff2c29, S=1, 1024, 0xc2f67c9f
+0, 1510, 1510, 1, 110, 0xb0552ba1, S=1, 1024, 0xc2f67c9f
+0, 1520, 1520, 1, 117, 0x08f62fd4, S=1, 1024, 0xc2f67c9f
+0, 1530, 1530, 1, 112, 0x0dac2e9d, S=1, 1024, 0xc2f67c9f
+0, 1540, 1540, 1, 142, 0x092138a5, S=1, 1024, 0xc2f67c9f
+0, 1550, 1550, 1, 119, 0x752a2fc6, S=1, 1024, 0xc2f67c9f
+0, 1560, 1560, 1, 105, 0xec5824cd, S=1, 1024, 0xc2f67c9f
+0, 1570, 1570, 1, 115, 0xea282f22, S=1, 1024, 0xc2f67c9f
+0, 1580, 1580, 1, 108, 0x60b72ece, S=1, 1024, 0xc2f67c9f
+0, 1590, 1590, 1, 139, 0x6ec63b92, S=1, 1024, 0xc2f67c9f
+0, 1600, 1600, 1, 216, 0x2c906371, S=1, 1024, 0xc2f67c9f
+0, 1610, 1610, 1, 226, 0x77b1687d, S=1, 1024, 0xc2f67c9f
+0, 1620, 1620, 1, 155, 0x8180455a, S=1, 1024, 0xc2f67c9f
+0, 1630, 1630, 1, 121, 0x66092c73, S=1, 1024, 0xc2f67c9f
+0, 1640, 1640, 1, 123, 0xf9f22cb9, S=1, 1024, 0xc2f67c9f
+0, 1650, 1650, 1, 220, 0x65525fcb, S=1, 1024, 0xc2f67c9f
+0, 1660, 1660, 1, 153, 0x4b9f414c, S=1, 1024, 0xc2f67c9f
+0, 1670, 1670, 1, 120, 0x072e3379, S=1, 1024, 0xc2f67c9f
+0, 1680, 1680, 1, 109, 0xe46a2b38, S=1, 1024, 0xc2f67c9f
+0, 1690, 1690, 1, 118, 0xf0f12d62, S=1, 1024, 0xc2f67c9f
+0, 1700, 1700, 1, 117, 0xcb9e2cbb, S=1, 1024, 0xc2f67c9f
+0, 1710, 1710, 1, 137, 0x1ae83718, S=1, 1024, 0xc2f67c9f
+0, 1720, 1720, 1, 161, 0x87364667, S=1, 1024, 0xc2f67c9f
diff --git a/tests/ref/fate/gifenc-pal8 b/tests/ref/fate/gifenc-pal8
new file mode 100644
index 0000000..4ae4d17
--- /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, 1637, 0x294d54f9, 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, 2441, 0x2076ec47, 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, 3081, 0x0b2a4aeb, S=1, 1024, 0xec907a9e
+0, 140, 140, 1, 3200, 0x35227f42, S=1, 1024, 0xec907a9e
+0, 150, 150, 1, 3315, 0x35edc001, S=1, 1024, 0xec907a9e
+0, 160, 160, 1, 3462, 0x27a20d23, S=1, 1024, 0xec907a9e
+0, 170, 170, 1, 3599, 0x83c52b01, 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, 3948, 0x5203eede, S=1, 1024, 0xec907a9e
+0, 210, 210, 1, 4083, 0x32101e33, S=1, 1024, 0xec907a9e
+0, 220, 220, 1, 4186, 0x6b0e5a13, 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, 5071, 0x25e830c7, S=1, 1024, 0xec907a9e
+0, 300, 300, 1, 5246, 0x452e945c, S=1, 1024, 0xec907a9e
+0, 310, 310, 1, 5353, 0x27eec140, S=1, 1024, 0xec907a9e
+0, 320, 320, 1, 5535, 0xda38038c, 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, 5966, 0xfbee1fed, S=1, 1024, 0xec907a9e
+0, 360, 360, 1, 6082, 0xd4b88e90, S=1, 1024, 0xec907a9e
+0, 370, 370, 1, 6276, 0x1b02e684, 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, 7513, 0x96d12666, 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, 11949, 0x87c86fb9, S=1, 1024, 0xec907a9e
+0, 910, 910, 1, 12088, 0x1b99c82b, S=1, 1024, 0xec907a9e
+0, 920, 920, 1, 12160, 0x72fbf4ac, S=1, 1024, 0xec907a9e
+0, 930, 930, 1, 12305, 0x9f62069a, S=1, 1024, 0xec907a9e
+0, 940, 940, 1, 12295, 0x0625d96b, S=1, 1024, 0xec907a9e
+0, 950, 950, 1, 12496, 0xe67cb2cf, 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, 12916, 0x37c444db, 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, 13336, 0x128254ee, 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, 13821, 0xfe4e97eb, 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..8a0595a
--- /dev/null
+++ b/tests/ref/fate/gifenc-rgb4_byte
@@ -0,0 +1,174 @@
+#tb 0: 1/100
+0, 0, 0, 1, 507, 0xde1f113a
+0, 10, 10, 1, 213, 0x23c24d3d, S=1, 1024, 0xf7700427
+0, 20, 20, 1, 130, 0x2c222a38, 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, 517, 0x411ad737, S=1, 1024, 0xf3740427
+0, 70, 70, 1, 535, 0x12cde6b7, S=1, 1024, 0xf3740427
+0, 80, 80, 1, 437, 0xec54b945, S=1, 1024, 0x0b6b0427
+0, 90, 90, 1, 923, 0xd2e2a35f, S=1, 1024, 0x0b6b0427
+0, 100, 100, 1, 693, 0x97064a1e, 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, 1275, 0x353c3913, S=1, 1024, 0x0b6b0427
+0, 160, 160, 1, 1474, 0x27399754, S=1, 1024, 0x0b6b0427
+0, 170, 170, 1, 1783, 0x9e024aa6, 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, 1717, 0x4b8d1cb7, S=1, 1024, 0xecb30526
+0, 240, 240, 1, 1900, 0xd7737a09, S=1, 1024, 0xecb30526
+0, 250, 250, 1, 1806, 0xfe1a513f, 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, 2894, 0x47eb484a, 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, 3599, 0x8c2d75d6, S=1, 1024, 0xecb30526
+0, 350, 350, 1, 3698, 0x5a59a042, S=1, 1024, 0xecb30526
+0, 360, 360, 1, 3814, 0x96a8d57e, S=1, 1024, 0xecb30526
+0, 370, 370, 1, 3626, 0xb3e67f8e, 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, 3093, 0xa248861e, S=1, 1024, 0xecb30526
+0, 410, 410, 1, 3456, 0x6d232a96, S=1, 1024, 0xecb30526
+0, 420, 420, 1, 4107, 0xe70d5eba, S=1, 1024, 0xecb30526
+0, 430, 430, 1, 4216, 0xab3258f3, S=1, 1024, 0xecb30526
+0, 440, 440, 1, 3613, 0x667f4ff8, S=1, 1024, 0xecb30526
+0, 450, 450, 1, 3909, 0xa7b0e73d, S=1, 1024, 0xecb30526
+0, 460, 460, 1, 4460, 0x7c8ae0be, S=1, 1024, 0xecb30526
+0, 470, 470, 1, 4592, 0x58112f48, S=1, 1024, 0xecb30526
+0, 480, 480, 1, 4821, 0x678d9b72, S=1, 1024, 0xecb30526
+0, 490, 490, 1, 5397, 0x79eabff3, S=1, 1024, 0xecb30526
+0, 500, 500, 1, 5266, 0xd5ab9630, S=1, 1024, 0xecb30526
+0, 510, 510, 1, 5415, 0x76dce16e, 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, 7595, 0x4ce5e56c, 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, 11482, 0xb938f4f9, 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, 11927, 0x4ab8c884, S=1, 1024, 0xecb30526
+0, 1070, 1070, 1, 11932, 0xecb5bdf7, S=1, 1024, 0xecb30526
+0, 1080, 1080, 1, 12280, 0xa0ea76d4, 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, 12667, 0xc75b5175, S=1, 1024, 0xecb30526
+0, 1130, 1130, 1, 12957, 0x3b839f0d, S=1, 1024, 0xecb30526
+0, 1140, 1140, 1, 13053, 0xd3c9e3da, 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, 13197, 0xa5eb5717, 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, 17396, 0xe8ef15b5, S=1, 1024, 0xecb30526
+0, 1490, 1490, 1, 17430, 0x6f58f8bf, 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..63789b7
--- /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, 437, 0x736bd351, 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, 613, 0xef4c2026, 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, 2247, 0x72982a87, 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, 2686, 0xfa990310, 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, 2981, 0x92507824, S=1, 1024, 0xcfc8799f
+0, 250, 250, 1, 3101, 0x3e029e0e, S=1, 1024, 0xcfc8799f
+0, 260, 260, 1, 3252, 0x8d3af677, S=1, 1024, 0xcfc8799f
+0, 270, 270, 1, 3329, 0x29a81b71, S=1, 1024, 0xcfc8799f
+0, 280, 280, 1, 3571, 0x18a68a51, S=1, 1024, 0xcfc8799f
+0, 290, 290, 1, 3806, 0x192dfed1, S=1, 1024, 0xcfc8799f
+0, 300, 300, 1, 2749, 0xdf1e1f9d, 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, 4294, 0xb64a0a7f, 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, 2280, 0x1ec34aa0, S=1, 1024, 0xcfc8799f
+0, 370, 370, 1, 3632, 0x11af9aa2, S=1, 1024, 0xcfc8799f
+0, 380, 380, 1, 3552, 0xed2c75b2, S=1, 1024, 0xcfc8799f
+0, 390, 390, 1, 3689, 0x42a6dd0c, S=1, 1024, 0xcfc8799f
+0, 400, 400, 1, 1558, 0x2c14e4b2, S=1, 1024, 0xcfc8799f
+0, 410, 410, 1, 939, 0x7ae8cd8f, S=1, 1024, 0xcfc8799f
+0, 420, 420, 1, 273, 0x138c7831, S=1, 1024, 0xcfc8799f
+0, 430, 430, 1, 929, 0x42eeae3e, 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, 4894, 0x8a7d39a5, S=1, 1024, 0xcfc8799f
+0, 480, 480, 1, 4927, 0xdd6113e7, S=1, 1024, 0xcfc8799f
+0, 490, 490, 1, 4941, 0x71915520, S=1, 1024, 0xcfc8799f
+0, 500, 500, 1, 4153, 0x0f8cb8a5, S=1, 1024, 0xcfc8799f
+0, 510, 510, 1, 4677, 0x62cfc338, S=1, 1024, 0xcfc8799f
+0, 520, 520, 1, 4740, 0x4418bb44, S=1, 1024, 0xcfc8799f
+0, 530, 530, 1, 4981, 0xb93c5976, 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, 4288, 0x7eb6fbbf, 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, 4644, 0x66f889e0, 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, 5216, 0xf3399cfa, S=1, 1024, 0xcfc8799f
+0, 650, 650, 1, 5394, 0xe0c801ca, S=1, 1024, 0xcfc8799f
+0, 660, 660, 1, 5219, 0xff22e354, 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, 7540, 0x32fe19c0, 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, 7617, 0xa2c2340e, 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, 11226, 0x9ac08eb8, 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, 18390, 0x888fc489, 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, 23164, 0x899866a2, 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
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-hi422fr10_sony_b
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 202752, 0xffa1c502
+0, 1, 1, 1, 202752, 0x51752f3c
+0, 2, 2, 1, 202752, 0xe683991d
+0, 3, 3, 1, 202752, 0xf70200a4
+0, 4, 4, 1, 202752, 0x1a4d63ef
diff --git a/tests/ref/fate/h264-conformance-frext-hi422fr13_sony_b b/tests/ref/fate/h264-conformance-frext-hi422fr13_sony_b
new file mode 100644
index 0000000..016abbc
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-hi422fr13_sony_b
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 405504, 0xe0f40e71
+0, 1, 1, 1, 405504, 0x9bdb5900
+0, 2, 2, 1, 405504, 0x527003ca
+0, 3, 3, 1, 405504, 0x1fbf8ba6
+0, 4, 4, 1, 405504, 0x455e2a4e
diff --git a/tests/ref/fate/h264-conformance-frext-hi422fr1_sony_a b/tests/ref/fate/h264-conformance-frext-hi422fr1_sony_a
new file mode 100644
index 0000000..93a3aa4
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-hi422fr1_sony_a
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 202752, 0xd5a1e49f
+0, 1, 1, 1, 202752, 0x08352d61
+0, 2, 2, 1, 202752, 0x43f78f47
+0, 3, 3, 1, 202752, 0xfb5910f4
+0, 4, 4, 1, 202752, 0xd98e8739
diff --git a/tests/ref/fate/h264-conformance-frext-hi422fr6_sony_a b/tests/ref/fate/h264-conformance-frext-hi422fr6_sony_a
new file mode 100644
index 0000000..4141eee
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-hi422fr6_sony_a
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 405504, 0x049ab58e
+0, 1, 1, 1, 405504, 0x4f6226cb
+0, 2, 2, 1, 405504, 0xaa5fcb44
+0, 3, 3, 1, 405504, 0xbfc09965
+0, 4, 4, 1, 405504, 0xa30acb90
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i1_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i1_panasonic_a
new file mode 100644
index 0000000..0957654
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i1_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3686400, 0x1f9b5bee
+0, 1, 1, 1, 3686400, 0x657c3609
+0, 2, 2, 1, 3686400, 0x75753934
+0, 3, 3, 1, 3686400, 0xf434d8e1
+0, 4, 4, 1, 3686400, 0x40679c77
+0, 5, 5, 1, 3686400, 0x5734d8db
+0, 6, 6, 1, 3686400, 0x4a3d8269
+0, 7, 7, 1, 3686400, 0xd20b6cf6
+0, 8, 8, 1, 3686400, 0x31956bca
+0, 9, 9, 1, 3686400, 0xd28d9758
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i2_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i2_panasonic_a
new file mode 100644
index 0000000..79e69eb
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i2_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3686400, 0x8b3ff360
+0, 1, 1, 1, 3686400, 0x422dead1
+0, 2, 2, 1, 3686400, 0xbdd0e431
+0, 3, 3, 1, 3686400, 0x1e3cc216
+0, 4, 4, 1, 3686400, 0x1a80b718
+0, 5, 5, 1, 3686400, 0xc7e3c0a2
+0, 6, 6, 1, 3686400, 0xffc99142
+0, 7, 7, 1, 3686400, 0x8b3bdf1e
+0, 8, 8, 1, 3686400, 0xff1bccfb
+0, 9, 9, 1, 3686400, 0x781fc45b
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i3_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i3_panasonic_a
new file mode 100644
index 0000000..fc4cc50
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i3_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3686400, 0x97c36ae3
+0, 1, 1, 1, 3686400, 0x6a0aa629
+0, 2, 2, 1, 3686400, 0xc658d722
+0, 3, 3, 1, 3686400, 0x713bc774
+0, 4, 4, 1, 3686400, 0x8d0b3afe
+0, 5, 5, 1, 3686400, 0x62bf24cd
+0, 6, 6, 1, 3686400, 0x77e80436
+0, 7, 7, 1, 3686400, 0x4f258e07
+0, 8, 8, 1, 3686400, 0x8426bc53
+0, 9, 9, 1, 3686400, 0xd33b58c8
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i4_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i4_panasonic_a
new file mode 100644
index 0000000..0aae9fe
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i4_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 8294400, 0xf50992f3
+0, 1, 1, 1, 8294400, 0xd34cdf98
+0, 2, 2, 1, 8294400, 0x76bced00
+0, 3, 3, 1, 8294400, 0xf9ffd9b1
+0, 4, 4, 1, 8294400, 0x303231aa
+0, 5, 5, 1, 8294400, 0x0ca57c6a
+0, 6, 6, 1, 8294400, 0xaa056bd5
+0, 7, 7, 1, 8294400, 0x785c9a12
+0, 8, 8, 1, 8294400, 0xe535750e
+0, 9, 9, 1, 8294400, 0x78fd76bb
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i5_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i5_panasonic_a
new file mode 100644
index 0000000..c74483c
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i5_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 8294400, 0x96d051a1
+0, 1, 1, 1, 8294400, 0xf3c2974e
+0, 2, 2, 1, 8294400, 0xb18f3ed0
+0, 3, 3, 1, 8294400, 0xb5ba9998
+0, 4, 4, 1, 8294400, 0x96327a34
+0, 5, 5, 1, 8294400, 0xe24d7b61
+0, 6, 6, 1, 8294400, 0xc45d5a16
+0, 7, 7, 1, 8294400, 0x13b4a537
+0, 8, 8, 1, 8294400, 0xa81dae90
+0, 9, 9, 1, 8294400, 0x2820bbe9
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i6_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i6_panasonic_a
new file mode 100644
index 0000000..26d41d4
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i6_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 8294400, 0x1b2f1079
+0, 1, 1, 1, 8294400, 0x6646f91c
+0, 2, 2, 1, 8294400, 0x17dc9f51
+0, 3, 3, 1, 8294400, 0x4aad9b3a
+0, 4, 4, 1, 8294400, 0x8a422d34
+0, 5, 5, 1, 8294400, 0x8fd76d87
+0, 6, 6, 1, 8294400, 0xc7c75f18
+0, 7, 7, 1, 8294400, 0x4a1c2643
+0, 8, 8, 1, 8294400, 0xfe225709
+0, 9, 9, 1, 8294400, 0x032ad2e5
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i7_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i7_panasonic_a
new file mode 100644
index 0000000..3f9bfed
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i7_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 8294400, 0xaa37ceea
+0, 1, 1, 1, 8294400, 0xa7546d5c
+0, 2, 2, 1, 8294400, 0xf2abaace
+0, 3, 3, 1, 8294400, 0x36f4d47e
+0, 4, 4, 1, 8294400, 0x1cdf917d
+0, 5, 5, 1, 8294400, 0xa9377ba3
+0, 6, 6, 1, 8294400, 0x21c9db51
+0, 7, 7, 1, 8294400, 0x07d7936e
+0, 8, 8, 1, 8294400, 0x7878ab94
+0, 9, 9, 1, 8294400, 0x77e40921
diff --git a/tests/ref/fate/h264-crop-to-container b/tests/ref/fate/h264-crop-to-container
index 5dfa441..0f435ea 100644
--- a/tests/ref/fate/h264-crop-to-container
+++ b/tests/ref/fate/h264-crop-to-container
@@ -1,2 +1,2 @@
-#tb 0: 1/30000
-0, 0, 0, 0, 3110400, 43a312e1eebc7dca1bd23456302a44e3
+#tb 0: 1001/30000
+0, 0, 0, 1, 3110400, 43a312e1eebc7dca1bd23456302a44e3
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/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
--- /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
--- /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
--- /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
--- /dev/null
+++ b/tests/ref/fate/lossless-tak
@@ -0,0 +1 @@
+CRC=0x4ec0971f
diff --git a/tests/ref/fate/lossless-tta-encrypted b/tests/ref/fate/lossless-tta-encrypted
new file mode 100644
index 0000000..39aec95
--- /dev/null
+++ b/tests/ref/fate/lossless-tta-encrypted
@@ -0,0 +1 @@
+CRC=0x4563745f
diff --git a/tests/ref/fate/mapchan-6ch-extract-2 b/tests/ref/fate/mapchan-6ch-extract-2
new file mode 100644
index 0000000..98c8540
--- /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
--- /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
--- /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
--- /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/msvideo1-8bit b/tests/ref/fate/msvideo1-8bit
index 74d54e8..6e6bc0b 100644
--- a/tests/ref/fate/msvideo1-8bit
+++ b/tests/ref/fate/msvideo1-8bit
@@ -29,3 +29,4 @@
0, 27, 27, 1, 57600, 0x4ec4a868
0, 28, 28, 1, 57600, 0x7db370a1
0, 29, 29, 1, 57600, 0x2b1e52f6
+0, 30, 30, 1, 57600, 0x2141467c
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
--- /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 e162775..454722e 100644
--- a/tests/ref/fate/mxf-demux
+++ b/tests/ref/fate/mxf-demux
@@ -1,99 +1,99 @@
#tb 0: 1/25
-#tb 1: 1/25
+#tb 1: 1/8000
0, 0, -9223372036854775808, 1, 8468, 0xc0855553
-1, 0, 0, 50, 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
+1, 0, 0, 16000, 32000, 0x479155e6
+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, 50, 50, 50, 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
+1, 16000, 16000, 16000, 32000, 0x8f7e5009
+0, 51, -9223372036854775808, 1, 3733, 0xa3e2a9a0, F=0x0
+0, 52, -9223372036854775808, 1, 3773, 0x27769caa, F=0x0
+0, 53, -9223372036854775808, 1, 3670, 0xc8335e98, F=0x0
+0, 54, -9223372036854775808, 1, 3596, 0xd6512fb0, F=0x0
+0, 55, -9223372036854775808, 1, 3579, 0xa621fbc2, F=0x0
+0, 56, -9223372036854775808, 1, 3641, 0x2f4f46ca, F=0x0
+0, 57, -9223372036854775808, 1, 3686, 0x0a92385a, F=0x0
+0, 58, -9223372036854775808, 1, 3672, 0xe65137b9, F=0x0
+0, 59, -9223372036854775808, 1, 39065, 0xc723bf8b, F=0x0
0, 60, -9223372036854775808, 1, 8611, 0x5d177f40
-0, 61, -9223372036854775808, 1, 3758, 0x33d59966
-0, 62, -9223372036854775808, 1, 3674, 0x54f37902
-0, 63, -9223372036854775808, 1, 3615, 0xa0f045fa
-0, 64, -9223372036854775808, 1, 3719, 0x41cf93ff
-0, 65, -9223372036854775808, 1, 3757, 0x3a1b7e8f
-0, 66, -9223372036854775808, 1, 3762, 0xe7f9714d
-0, 67, -9223372036854775808, 1, 3738, 0x8121805b
-0, 68, -9223372036854775808, 1, 3733, 0x13e262db
-0, 69, -9223372036854775808, 1, 38433, 0x3d58c500
+0, 61, -9223372036854775808, 1, 3758, 0x33d59966, F=0x0
+0, 62, -9223372036854775808, 1, 3674, 0x54f37902, F=0x0
+0, 63, -9223372036854775808, 1, 3615, 0xa0f045fa, F=0x0
+0, 64, -9223372036854775808, 1, 3719, 0x41cf93ff, F=0x0
+0, 65, -9223372036854775808, 1, 3757, 0x3a1b7e8f, F=0x0
+0, 66, -9223372036854775808, 1, 3762, 0xe7f9714d, F=0x0
+0, 67, -9223372036854775808, 1, 3738, 0x8121805b, F=0x0
+0, 68, -9223372036854775808, 1, 3733, 0x13e262db, F=0x0
+0, 69, -9223372036854775808, 1, 38433, 0x3d58c500, F=0x0
0, 70, -9223372036854775808, 1, 8410, 0xa4f7fd2e
-0, 71, -9223372036854775808, 1, 3711, 0x0e112d3c
-0, 72, -9223372036854775808, 1, 3692, 0xb46574b2
-0, 73, -9223372036854775808, 1, 3563, 0xad43343d
-0, 74, -9223372036854775808, 1, 3613, 0x5cd85c4f
-0, 75, -9223372036854775808, 1, 3653, 0xe15a2853
-0, 76, -9223372036854775808, 1, 3684, 0x9ddd58cb
-0, 77, -9223372036854775808, 1, 3256, 0xd7f89f2e
-0, 78, -9223372036854775808, 1, 3698, 0x2b82624a
-0, 79, -9223372036854775808, 1, 39520, 0xd3f2b7c5
+0, 71, -9223372036854775808, 1, 3711, 0x0e112d3c, F=0x0
+0, 72, -9223372036854775808, 1, 3692, 0xb46574b2, F=0x0
+0, 73, -9223372036854775808, 1, 3563, 0xad43343d, F=0x0
+0, 74, -9223372036854775808, 1, 3613, 0x5cd85c4f, F=0x0
+0, 75, -9223372036854775808, 1, 3653, 0xe15a2853, F=0x0
+0, 76, -9223372036854775808, 1, 3684, 0x9ddd58cb, F=0x0
+0, 77, -9223372036854775808, 1, 3256, 0xd7f89f2e, F=0x0
+0, 78, -9223372036854775808, 1, 3698, 0x2b82624a, F=0x0
+0, 79, -9223372036854775808, 1, 39520, 0xd3f2b7c5, F=0x0
0, 80, -9223372036854775808, 1, 8493, 0x163559be
-0, 81, -9223372036854775808, 1, 3719, 0x6fa0916f
-0, 82, -9223372036854775808, 1, 3655, 0xa9233de1
-0, 83, -9223372036854775808, 1, 3684, 0xa6125737
-0, 84, -9223372036854775808, 1, 3688, 0xa9da6686
-0, 85, -9223372036854775808, 1, 3685, 0x674d634e
-0, 86, -9223372036854775808, 1, 3677, 0x7a85535d
-0, 87, -9223372036854775808, 1, 3666, 0xce3600a2
-0, 88, -9223372036854775808, 1, 3837, 0x3a7090e1
-0, 89, -9223372036854775808, 1, 38696, 0x12c59cd2
+0, 81, -9223372036854775808, 1, 3719, 0x6fa0916f, F=0x0
+0, 82, -9223372036854775808, 1, 3655, 0xa9233de1, F=0x0
+0, 83, -9223372036854775808, 1, 3684, 0xa6125737, F=0x0
+0, 84, -9223372036854775808, 1, 3688, 0xa9da6686, F=0x0
+0, 85, -9223372036854775808, 1, 3685, 0x674d634e, F=0x0
+0, 86, -9223372036854775808, 1, 3677, 0x7a85535d, F=0x0
+0, 87, -9223372036854775808, 1, 3666, 0xce3600a2, F=0x0
+0, 88, -9223372036854775808, 1, 3837, 0x3a7090e1, F=0x0
+0, 89, -9223372036854775808, 1, 38696, 0x12c59cd2, F=0x0
0, 90, -9223372036854775808, 1, 8022, 0xd343433f
-0, 91, -9223372036854775808, 1, 5157, 0x440c14e5
-0, 92, -9223372036854775808, 1, 5003, 0xf8e1daff
-0, 93, -9223372036854775808, 1, 4954, 0x89866344
-0, 94, -9223372036854775808, 1, 53664, 0xeb0c4c42
+0, 91, -9223372036854775808, 1, 5157, 0x440c14e5, F=0x0
+0, 92, -9223372036854775808, 1, 5003, 0xf8e1daff, F=0x0
+0, 93, -9223372036854775808, 1, 4954, 0x89866344, F=0x0
+0, 94, -9223372036854775808, 1, 53664, 0xeb0c4c42, F=0x0
diff --git a/tests/ref/fate/mxpeg b/tests/ref/fate/mxpeg
new file mode 100644
index 0000000..90af90f
--- /dev/null
+++ b/tests/ref/fate/mxpeg
@@ -0,0 +1,31 @@
+#tb 0: 4/63
+0, 0, 0, 1, 1843200, 0x868a4e64
+0, 4, 4, 1, 1843200, 0x8dda4373
+0, 6, 6, 1, 1843200, 0xfcde3afc
+0, 8, 8, 1, 1843200, 0xeb4048a7
+0, 12, 12, 1, 1843200, 0xe2aa5718
+0, 14, 14, 1, 1843200, 0x86c35765
+0, 16, 16, 1, 1843200, 0x05c66542
+0, 18, 18, 1, 1843200, 0x020967f8
+0, 22, 22, 1, 1843200, 0x57757510
+0, 24, 24, 1, 1843200, 0xb91c61be
+0, 26, 26, 1, 1843200, 0x702381e9
+0, 30, 30, 1, 1843200, 0xe28c6851
+0, 32, 32, 1, 1843200, 0x7f806daa
+0, 34, 34, 1, 1843200, 0xc0758a39
+0, 38, 38, 1, 1843200, 0x3af87be2
+0, 40, 40, 1, 1843200, 0x1d1876eb
+0, 42, 42, 1, 1843200, 0x720e81dd
+0, 44, 44, 1, 1843200, 0xd85b7556
+0, 48, 48, 1, 1843200, 0xb9968314
+0, 50, 50, 1, 1843200, 0x946b9d34
+0, 52, 52, 1, 1843200, 0xd2d87d03
+0, 54, 54, 1, 1843200, 0xdd1b8056
+0, 58, 58, 1, 1843200, 0x436b7937
+0, 60, 60, 1, 1843200, 0xe87a6e42
+0, 62, 62, 1, 1843200, 0x57475c09
+0, 64, 64, 1, 1843200, 0xc3b45a77
+0, 68, 68, 1, 1843200, 0x0308494c
+0, 70, 70, 1, 1843200, 0x1ed02c80
+0, 72, 72, 1, 1843200, 0x48602e92
+0, 74, 74, 1, 1843200, 0xcf332caa
diff --git a/tests/ref/fate/nc-demux b/tests/ref/fate/nc-demux
index 1d00f8e..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
--- /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 e9286d6..8838fbb 100644
--- a/tests/ref/fate/nuv-rtjpeg
+++ b/tests/ref/fate/nuv-rtjpeg
@@ -1,10 +1,10 @@
-#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
-0, 369, 369, 0, 460800, 0xb30eb322
+#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
+0, 12, 12, 1, 460800, 0xa57f20d0
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
--- /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
--- /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
--- /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..5fa3bf4 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
@@ -26,20 +26,57 @@ Testing av_parse_video_rate()
' -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
--- /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 80442fe..bdb5c6e 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, 12441600, 0x254d8f95
-0, 100, 100, 0, 12441600, 0x254d8f95
+#tb 0: 100/2997
+0, 0, 0, 1, 12441600, 0x254d8f95
+0, 1, 1, 1, 12441600, 0x254d8f95
diff --git a/tests/ref/fate/ptx b/tests/ref/fate/ptx
index fad2a50..7edbbdd 100644
--- a/tests/ref/fate/ptx
+++ b/tests/ref/fate/ptx
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 393216, 0xda280efc
+0, 0, 0, 1, 393216, 0x30479950
diff --git a/tests/ref/fate/pva-demux b/tests/ref/fate/pva-demux
index 69b1d40..67d4844 100644
--- a/tests/ref/fate/pva-demux
+++ b/tests/ref/fate/pva-demux
@@ -1,26 +1,27 @@
-#tb 0: 1/90000
-0, 0, 0, 2160, 384, 0x071abcc8
-0, 2160, 2160, 2160, 384, 0x31c9aee0
-0, 4320, 4320, 2160, 384, 0xa50eaa94
-0, 6480, 6480, 2160, 384, 0x9e86ba0e
-0, 8640, 8640, 2160, 384, 0x2321b800
-0, 10800, 10800, 2160, 384, 0x2347afa8
-0, 12960, 12960, 2160, 384, 0x0831b8d3
-0, 15120, 15120, 2160, 384, 0xd5acafa1
-0, 17280, 17280, 2160, 384, 0xc975b9d2
-0, 19440, 19440, 2160, 384, 0x2e10b02a
-0, 21600, 21600, 2160, 384, 0x501eadd0
-0, 23760, 23760, 2160, 384, 0x153fc171
-0, 25920, 25920, 2160, 384, 0xc5f0b3c2
-0, 28080, 28080, 2160, 384, 0xf731b200
-0, 30240, 30240, 2160, 384, 0x2e16b713
-0, 32400, 32400, 2160, 384, 0x61f6bba9
-0, 34560, 34560, 2160, 384, 0x1b9eb0ff
-0, 36720, 36720, 2160, 384, 0x2ab4b7bd
-0, 38880, 38880, 2160, 384, 0xd66eb45c
-0, 41040, 41040, 2160, 384, 0x145ab426
-0, 43200, 43200, 2160, 384, 0x297cb370
-0, 45360, 45360, 2160, 384, 0x287bb6b7
-0, 47520, 47520, 2160, 384, 0xfddbb7df
-0, 49680, 49680, 2160, 384, 0xbbb2af0c
-0, 51840, 51840, 2160, 384, 0x8f03b5fc
+#tb 0: 1/25
+#tb 1: 1/90000
+1, 0, 0, 2160, 384, 0x071abcc8
+1, 2160, 2160, 2160, 384, 0x31c9aee0
+1, 4320, 4320, 2160, 384, 0xa50eaa94
+1, 6480, 6480, 2160, 384, 0x9e86ba0e
+1, 8640, 8640, 2160, 384, 0x2321b800
+1, 10800, 10800, 2160, 384, 0x2347afa8
+1, 12960, 12960, 2160, 384, 0x0831b8d3
+1, 15120, 15120, 2160, 384, 0xd5acafa1
+1, 17280, 17280, 2160, 384, 0xc975b9d2
+1, 19440, 19440, 2160, 384, 0x2e10b02a
+1, 21600, 21600, 2160, 384, 0x501eadd0
+1, 23760, 23760, 2160, 384, 0x153fc171
+1, 25920, 25920, 2160, 384, 0xc5f0b3c2
+1, 28080, 28080, 2160, 384, 0xf731b200
+1, 30240, 30240, 2160, 384, 0x2e16b713
+1, 32400, 32400, 2160, 384, 0x61f6bba9
+1, 34560, 34560, 2160, 384, 0x1b9eb0ff
+1, 36720, 36720, 2160, 384, 0x2ab4b7bd
+1, 38880, 38880, 2160, 384, 0xd66eb45c
+1, 41040, 41040, 2160, 384, 0x145ab426
+1, 43200, 43200, 2160, 384, 0x297cb370
+1, 45360, 45360, 2160, 384, 0x287bb6b7
+1, 47520, 47520, 2160, 384, 0xfddbb7df
+1, 49680, 49680, 2160, 384, 0xbbb2af0c
+1, 51840, 51840, 2160, 384, 0x8f03b5fc
diff --git a/tests/ref/fate/qtrle-16bit b/tests/ref/fate/qtrle-16bit
index d0d71b5..2021f2a 100644
--- a/tests/ref/fate/qtrle-16bit
+++ b/tests/ref/fate/qtrle-16bit
@@ -1,84 +1,84 @@
-#tb 0: 1/600
-0, 0, 0, 1, 57600, 0xe6b0a48c
-0, 40, 40, 1, 57600, 0xe064d51c
-0, 80, 80, 1, 57600, 0xbfce6b33
-0, 120, 120, 1, 57600, 0x371bab02
-0, 160, 160, 1, 57600, 0x0d2d7456
-0, 200, 200, 1, 57600, 0x9184eecb
-0, 240, 240, 1, 57600, 0xb482e8db
-0, 280, 280, 1, 57600, 0x0f4cd4be
-0, 320, 320, 1, 57600, 0xe276cccb
-0, 360, 360, 1, 57600, 0x04c21c62
-0, 400, 400, 1, 57600, 0x848960a2
-0, 440, 440, 1, 57600, 0xc4c8cf03
-0, 480, 480, 1, 57600, 0xb4094866
-0, 520, 520, 1, 57600, 0xf22da043
-0, 560, 560, 1, 57600, 0x6517b67b
-0, 600, 600, 1, 57600, 0x23e39ccb
-0, 640, 640, 1, 57600, 0x41525ca3
-0, 680, 680, 1, 57600, 0xc3edc5f3
-0, 720, 720, 1, 57600, 0x8ce81c7e
-0, 760, 760, 1, 57600, 0x56829443
-0, 800, 800, 1, 57600, 0x511ce287
-0, 840, 840, 1, 57600, 0x8f029a5b
-0, 880, 880, 1, 57600, 0x2b47cf43
-0, 920, 920, 1, 57600, 0x8e7ecf4b
-0, 960, 960, 1, 57600, 0xd620317e
-0, 1000, 1000, 1, 57600, 0x5987646e
-0, 1040, 1040, 1, 57600, 0xcfedb7df
-0, 1080, 1080, 1, 57600, 0x33746e7b
-0, 1120, 1120, 1, 57600, 0x1d318573
-0, 1160, 1160, 1, 57600, 0xc851848b
-0, 1200, 1200, 1, 57600, 0x939db1d7
-0, 1240, 1240, 1, 57600, 0x1719aed3
-0, 1280, 1280, 1, 57600, 0x1ba3e18c
-0, 1320, 1320, 1, 57600, 0x04f355fb
-0, 1360, 1360, 1, 57600, 0x6fafd5f4
-0, 1400, 1400, 1, 57600, 0x434f800b
-0, 1440, 1440, 1, 57600, 0xed42179b
-0, 1480, 1480, 1, 57600, 0x3b33118b
-0, 1520, 1520, 1, 57600, 0xf81880cb
-0, 1560, 1560, 1, 57600, 0xd2c58e1b
-0, 1600, 1600, 1, 57600, 0xd96f50eb
-0, 1640, 1640, 1, 57600, 0x64ef63fb
-0, 1680, 1680, 1, 57600, 0x7b14b6fc
-0, 1720, 1720, 1, 57600, 0xeb1c9054
-0, 1760, 1760, 1, 57600, 0x3b30c97c
-0, 1800, 1800, 1, 57600, 0xc93e9484
-0, 1840, 1840, 1, 57600, 0xe012c0cc
-0, 1880, 1880, 1, 57600, 0x48e2dda4
-0, 1920, 1920, 1, 57600, 0x13eb55fb
-0, 1960, 1960, 1, 57600, 0xa5edbedc
-0, 2000, 2000, 1, 57600, 0x0123a484
-0, 2040, 2040, 1, 57600, 0xc624a7ac
-0, 2080, 2080, 1, 57600, 0xd83cf45c
-0, 2120, 2120, 1, 57600, 0x8f9bf4b4
-0, 2160, 2160, 1, 57600, 0x2d494b8c
-0, 2200, 2200, 1, 57600, 0xb246f07c
-0, 2240, 2240, 1, 57600, 0x5750e67c
-0, 2280, 2280, 1, 57600, 0x6643e9ac
-0, 2320, 2320, 1, 57600, 0x8d3b86b3
-0, 2360, 2360, 1, 57600, 0x4bb0546b
-0, 2400, 2400, 1, 57600, 0xfe439333
-0, 2440, 2440, 1, 57600, 0x0cc76233
-0, 2480, 2480, 1, 57600, 0xb6fe40ae
-0, 2520, 2520, 1, 57600, 0xf79fe0d7
-0, 2560, 2560, 1, 57600, 0xdc90dcbb
-0, 2600, 2600, 1, 57600, 0x371e7c2b
-0, 2640, 2640, 1, 57600, 0x7c4590bb
-0, 2680, 2680, 1, 57600, 0x66f5454b
-0, 2720, 2720, 1, 57600, 0x1678ae5b
-0, 2760, 2760, 1, 57600, 0x1ee8fdec
-0, 2800, 2800, 1, 57600, 0x98d2a083
-0, 2840, 2840, 1, 57600, 0x86d29e5b
-0, 2880, 2880, 1, 57600, 0x23d2bc83
-0, 2920, 2920, 1, 57600, 0x3fc729f2
-0, 2960, 2960, 1, 57600, 0x821d61da
-0, 3000, 3000, 1, 57600, 0xdd549e0e
-0, 3040, 3040, 1, 57600, 0x641234e2
-0, 3080, 3080, 1, 57600, 0x9a282112
-0, 3120, 3120, 1, 57600, 0x6587e2fb
-0, 3160, 3160, 1, 57600, 0x043d0cb2
-0, 3200, 3200, 1, 57600, 0x90328707
-0, 3240, 3240, 1, 57600, 0x5744d313
-0, 3280, 3280, 1, 57600, 0x6e1b95cb
+#tb 0: 1/15
+0, 0, 0, 1, 57600, 0xcf2d39fc
+0, 1, 1, 1, 57600, 0xfc9f6bed
+0, 2, 2, 1, 57600, 0x3f5805bb
+0, 3, 3, 1, 57600, 0xcb34504e
+0, 4, 4, 1, 57600, 0x66b6f6e9
+0, 5, 5, 1, 57600, 0x18698e4d
+0, 6, 6, 1, 57600, 0x233288d7
+0, 7, 7, 1, 57600, 0x6b195ac5
+0, 8, 8, 1, 57600, 0x3b466b45
+0, 9, 9, 1, 57600, 0x9e3dbd75
+0, 10, 10, 1, 57600, 0x90ee04b7
+0, 11, 11, 1, 57600, 0x81096dda
+0, 12, 12, 1, 57600, 0xef24ca50
+0, 13, 13, 1, 57600, 0xea7a3da8
+0, 14, 14, 1, 57600, 0xc3f054c2
+0, 15, 15, 1, 57600, 0x34af39ec
+0, 16, 16, 1, 57600, 0xfc31f846
+0, 17, 17, 1, 57600, 0xa4606399
+0, 18, 18, 1, 57600, 0x4b8a9c88
+0, 19, 19, 1, 57600, 0x87db3195
+0, 20, 20, 1, 57600, 0x443b618d
+0, 21, 21, 1, 57600, 0x601e380e
+0, 22, 22, 1, 57600, 0x405c6e6f
+0, 23, 23, 1, 57600, 0xe6b66f29
+0, 24, 24, 1, 57600, 0xb8e4b2d1
+0, 25, 25, 1, 57600, 0x9fc8e7da
+0, 26, 26, 1, 57600, 0x3bdb363b
+0, 27, 27, 1, 57600, 0xacac0b6a
+0, 28, 28, 1, 57600, 0xff3022fb
+0, 29, 29, 1, 57600, 0x1e5721f3
+0, 30, 30, 1, 57600, 0x511a3071
+0, 31, 31, 1, 57600, 0xff6d4dc0
+0, 32, 32, 1, 57600, 0x5df97a35
+0, 33, 33, 1, 57600, 0x3877f1b1
+0, 34, 34, 1, 57600, 0xa9096dd2
+0, 35, 35, 1, 57600, 0xd36e1ccc
+0, 36, 36, 1, 57600, 0xdc94b124
+0, 37, 37, 1, 57600, 0x873fab49
+0, 38, 38, 1, 57600, 0x7f081dca
+0, 39, 39, 1, 57600, 0x7df52bc3
+0, 40, 40, 1, 57600, 0xf41feb99
+0, 41, 41, 1, 57600, 0xcf59ffeb
+0, 42, 42, 1, 57600, 0x0dd94dfe
+0, 43, 43, 1, 57600, 0xfbc52500
+0, 44, 44, 1, 57600, 0xc300606e
+0, 45, 45, 1, 57600, 0x01e529b4
+0, 46, 46, 1, 57600, 0x359a57b0
+0, 47, 47, 1, 57600, 0xcfee7511
+0, 48, 48, 1, 57600, 0x2189f139
+0, 49, 49, 1, 57600, 0xcc535558
+0, 50, 50, 1, 57600, 0xeed13a76
+0, 51, 51, 1, 57600, 0xfb5c3ddd
+0, 52, 52, 1, 57600, 0x36a98c53
+0, 53, 53, 1, 57600, 0xf4c38c4b
+0, 54, 54, 1, 57600, 0x53d5df15
+0, 55, 55, 1, 57600, 0x336d890c
+0, 56, 56, 1, 57600, 0x19967f1c
+0, 57, 57, 1, 57600, 0xa36b8224
+0, 58, 58, 1, 57600, 0xf6ec2490
+0, 59, 59, 1, 57600, 0x6ffff0d1
+0, 60, 60, 1, 57600, 0xfcb73114
+0, 61, 61, 1, 57600, 0x5f5fff35
+0, 62, 62, 1, 57600, 0xf113c4a0
+0, 63, 63, 1, 57600, 0x64ca6175
+0, 64, 64, 1, 57600, 0x3f6f7d15
+0, 65, 65, 1, 57600, 0x18b619df
+0, 66, 66, 1, 57600, 0xe6872ed7
+0, 67, 67, 1, 57600, 0x3641e174
+0, 68, 68, 1, 57600, 0x4c144d8c
+0, 69, 69, 1, 57600, 0x82529776
+0, 70, 70, 1, 57600, 0xd96f3ead
+0, 71, 71, 1, 57600, 0xce183c4e
+0, 72, 72, 1, 57600, 0xaa475b24
+0, 73, 73, 1, 57600, 0xf7c5cbf3
+0, 74, 74, 1, 57600, 0x798e0548
+0, 75, 75, 1, 57600, 0x1233241a
+0, 76, 76, 1, 57600, 0x1424d758
+0, 77, 77, 1, 57600, 0xa446c264
+0, 78, 78, 1, 57600, 0x66e082ae
+0, 79, 79, 1, 57600, 0xb58cacc8
+0, 80, 80, 1, 57600, 0x3d86431c
+0, 81, 81, 1, 57600, 0x601b724e
+0, 82, 82, 1, 57600, 0xbe9a32c8
diff --git a/tests/ref/fate/qtrle-1bit b/tests/ref/fate/qtrle-1bit
index a424e47..f191169 100644
--- a/tests/ref/fate/qtrle-1bit
+++ b/tests/ref/fate/qtrle-1bit
@@ -1,39 +1,39 @@
-#tb 0: 1/1200
-0, 0, 0, 0, 9600, 0xc5921aa2
-0, 100, 100, 0, 9600, 0x9032fc52
-0, 200, 200, 0, 9600, 0x7db0038e
-0, 300, 300, 0, 9600, 0x95b73c41
-0, 400, 400, 0, 9600, 0x531e4189
-0, 500, 500, 0, 9600, 0xb73390ec
-0, 600, 600, 0, 9600, 0x958e8221
-0, 700, 700, 0, 9600, 0xd393f8a6
-0, 800, 800, 0, 9600, 0xa085da1c
-0, 900, 900, 0, 9600, 0x57ace74f
-0, 1000, 1000, 0, 9600, 0x5d11a308
-0, 1100, 1100, 0, 9600, 0x13e133b7
-0, 1200, 1200, 0, 9600, 0x494edb86
-0, 1300, 1300, 0, 9600, 0x43a448ea
-0, 1400, 1400, 0, 9600, 0x3562d35b
-0, 1500, 1500, 0, 9600, 0x0bc655d2
-0, 1600, 1600, 0, 9600, 0xbece73a1
-0, 1700, 1700, 0, 9600, 0x82e7cfa1
-0, 1800, 1800, 0, 9600, 0xda29fd8f
-0, 1900, 1900, 0, 9600, 0x70fb700b
-0, 2000, 2000, 0, 9600, 0xaf57a6b0
-0, 2100, 2100, 0, 9600, 0x0a5ed9b9
-0, 2200, 2200, 0, 9600, 0xf7c62c38
-0, 2300, 2300, 0, 9600, 0x0aa2ccfd
-0, 2400, 2400, 0, 9600, 0xc9adabae
-0, 2500, 2500, 0, 9600, 0x67ff0aba
-0, 2600, 2600, 0, 9600, 0xea79a465
-0, 2700, 2700, 0, 9600, 0x8928c626
-0, 2800, 2800, 0, 9600, 0x8dab4111
-0, 2900, 2900, 0, 9600, 0x81ef63f9
-0, 3000, 3000, 0, 9600, 0xf977bc5e
-0, 3100, 3100, 0, 9600, 0x9e6a3f4a
-0, 3200, 3200, 0, 9600, 0x77c92865
-0, 3300, 3300, 0, 9600, 0x3915170d
-0, 3400, 3400, 0, 9600, 0xbe19b995
-0, 3500, 3500, 0, 9600, 0x3e8a3077
-0, 3600, 3600, 0, 9600, 0x1331342e
-0, 3700, 3700, 0, 9600, 0x4d692175
+#tb 0: 1/12
+0, 0, 0, 1, 9600, 0xc5921aa2
+0, 1, 1, 1, 9600, 0x9032fc52
+0, 2, 2, 1, 9600, 0x7db0038e
+0, 3, 3, 1, 9600, 0x95b73c41
+0, 4, 4, 1, 9600, 0x531e4189
+0, 5, 5, 1, 9600, 0xb73390ec
+0, 6, 6, 1, 9600, 0x958e8221
+0, 7, 7, 1, 9600, 0xd393f8a6
+0, 8, 8, 1, 9600, 0xa085da1c
+0, 9, 9, 1, 9600, 0x57ace74f
+0, 10, 10, 1, 9600, 0x5d11a308
+0, 11, 11, 1, 9600, 0x13e133b7
+0, 12, 12, 1, 9600, 0x494edb86
+0, 13, 13, 1, 9600, 0x43a448ea
+0, 14, 14, 1, 9600, 0x3562d35b
+0, 15, 15, 1, 9600, 0x0bc655d2
+0, 16, 16, 1, 9600, 0xbece73a1
+0, 17, 17, 1, 9600, 0x82e7cfa1
+0, 18, 18, 1, 9600, 0xda29fd8f
+0, 19, 19, 1, 9600, 0x70fb700b
+0, 20, 20, 1, 9600, 0xaf57a6b0
+0, 21, 21, 1, 9600, 0x0a5ed9b9
+0, 22, 22, 1, 9600, 0xf7c62c38
+0, 23, 23, 1, 9600, 0x0aa2ccfd
+0, 24, 24, 1, 9600, 0xc9adabae
+0, 25, 25, 1, 9600, 0x67ff0aba
+0, 26, 26, 1, 9600, 0xea79a465
+0, 27, 27, 1, 9600, 0x8928c626
+0, 28, 28, 1, 9600, 0x8dab4111
+0, 29, 29, 1, 9600, 0x81ef63f9
+0, 30, 30, 1, 9600, 0xf977bc5e
+0, 31, 31, 1, 9600, 0x9e6a3f4a
+0, 32, 32, 1, 9600, 0x77c92865
+0, 33, 33, 1, 9600, 0x3915170d
+0, 34, 34, 1, 9600, 0xbe19b995
+0, 35, 35, 1, 9600, 0x3e8a3077
+0, 36, 36, 1, 9600, 0x1331342e
+0, 37, 37, 1, 9600, 0x4d692175
diff --git a/tests/ref/fate/qtrle-24bit b/tests/ref/fate/qtrle-24bit
index 7a162b8..a21b099 100644
--- a/tests/ref/fate/qtrle-24bit
+++ b/tests/ref/fate/qtrle-24bit
@@ -1,35 +1,35 @@
-#tb 0: 1/600
+#tb 0: 1/10
0, 0, 0, 1, 57600, 0x3718ad00
-0, 60, 60, 1, 57600, 0x54861558
-0, 120, 120, 1, 57600, 0xea1d6233
-0, 180, 180, 1, 57600, 0xf669a2fd
-0, 240, 240, 1, 57600, 0xc9f76f31
-0, 300, 300, 1, 57600, 0xe23c6d7b
-0, 360, 360, 1, 57600, 0xbc9d6167
-0, 420, 420, 1, 57600, 0x0ca63477
-0, 480, 480, 1, 57600, 0xc0850d22
-0, 540, 540, 1, 57600, 0x735d10b2
-0, 600, 600, 1, 57600, 0x561f3c4a
-0, 660, 660, 1, 57600, 0x84db9cf1
-0, 720, 720, 1, 57600, 0x9fb841f4
-0, 780, 780, 1, 57600, 0xeaf262ab
-0, 840, 840, 1, 57600, 0x264886b4
-0, 900, 900, 1, 57600, 0x5edc5518
-0, 960, 960, 1, 57600, 0xd3e60c72
-0, 1020, 1020, 1, 57600, 0x9cabaed7
-0, 1080, 1080, 1, 57600, 0x616716cf
-0, 1140, 1140, 1, 57600, 0xa43f61aa
-0, 1200, 1200, 1, 57600, 0xdba3a0bd
-0, 1260, 1260, 1, 57600, 0xa7dd6dfa
-0, 1320, 1320, 1, 57600, 0xc3fa6c84
-0, 1380, 1380, 1, 57600, 0xb1275fb8
-0, 1440, 1440, 1, 57600, 0x2e39331f
-0, 1500, 1500, 1, 57600, 0x5b9e0bca
-0, 1560, 1560, 1, 57600, 0x0e760f5a
-0, 1620, 1620, 1, 57600, 0xc56c3e69
-0, 1680, 1680, 1, 57600, 0x51da9fb8
-0, 1740, 1740, 1, 57600, 0xe3a1432b
-0, 1800, 1800, 1, 57600, 0xe1b360a3
-0, 1860, 1860, 1, 57600, 0x30b383cd
-0, 1920, 1920, 1, 57600, 0x950c5439
-0, 1980, 1980, 1, 57600, 0x8f9d0ca2
+0, 1, 1, 1, 57600, 0x54861558
+0, 2, 2, 1, 57600, 0xea1d6233
+0, 3, 3, 1, 57600, 0xf669a2fd
+0, 4, 4, 1, 57600, 0xc9f76f31
+0, 5, 5, 1, 57600, 0xe23c6d7b
+0, 6, 6, 1, 57600, 0xbc9d6167
+0, 7, 7, 1, 57600, 0x0ca63477
+0, 8, 8, 1, 57600, 0xc0850d22
+0, 9, 9, 1, 57600, 0x735d10b2
+0, 10, 10, 1, 57600, 0x561f3c4a
+0, 11, 11, 1, 57600, 0x84db9cf1
+0, 12, 12, 1, 57600, 0x9fb841f4
+0, 13, 13, 1, 57600, 0xeaf262ab
+0, 14, 14, 1, 57600, 0x264886b4
+0, 15, 15, 1, 57600, 0x5edc5518
+0, 16, 16, 1, 57600, 0xd3e60c72
+0, 17, 17, 1, 57600, 0x9cabaed7
+0, 18, 18, 1, 57600, 0x616716cf
+0, 19, 19, 1, 57600, 0xa43f61aa
+0, 20, 20, 1, 57600, 0xdba3a0bd
+0, 21, 21, 1, 57600, 0xa7dd6dfa
+0, 22, 22, 1, 57600, 0xc3fa6c84
+0, 23, 23, 1, 57600, 0xb1275fb8
+0, 24, 24, 1, 57600, 0x2e39331f
+0, 25, 25, 1, 57600, 0x5b9e0bca
+0, 26, 26, 1, 57600, 0x0e760f5a
+0, 27, 27, 1, 57600, 0xc56c3e69
+0, 28, 28, 1, 57600, 0x51da9fb8
+0, 29, 29, 1, 57600, 0xe3a1432b
+0, 30, 30, 1, 57600, 0xe1b360a3
+0, 31, 31, 1, 57600, 0x30b383cd
+0, 32, 32, 1, 57600, 0x950c5439
+0, 33, 33, 1, 57600, 0x8f9d0ca2
diff --git a/tests/ref/fate/qtrle-2bit b/tests/ref/fate/qtrle-2bit
index 5866db5..95c0f7c 100644
--- a/tests/ref/fate/qtrle-2bit
+++ b/tests/ref/fate/qtrle-2bit
@@ -1,39 +1,39 @@
-#tb 0: 1/1200
-0, 0, 0, 0, 230400, 0xb1ee55dc
-0, 100, 100, 0, 230400, 0x97c580bf
-0, 200, 200, 0, 230400, 0xd4bd57e8
-0, 300, 300, 0, 230400, 0x412b79aa
-0, 400, 400, 0, 230400, 0x928a44d1
-0, 500, 500, 0, 230400, 0x6bbdc0e4
-0, 600, 600, 0, 230400, 0x382e960f
-0, 700, 700, 0, 230400, 0x62c863ea
-0, 800, 800, 0, 230400, 0xbfccd3ce
-0, 900, 900, 0, 230400, 0x1987cdd4
-0, 1000, 1000, 0, 230400, 0x40279727
-0, 1100, 1100, 0, 230400, 0x9d4f6746
-0, 1200, 1200, 0, 230400, 0x7b8a77ec
-0, 1300, 1300, 0, 230400, 0x2ce7a781
-0, 1400, 1400, 0, 230400, 0xb749815e
-0, 1500, 1500, 0, 230400, 0x61c88610
-0, 1600, 1600, 0, 230400, 0x8449114d
-0, 1700, 1700, 0, 230400, 0x5f73e666
-0, 1800, 1800, 0, 230400, 0xbde53ce6
-0, 1900, 1900, 0, 230400, 0x8c7406fd
-0, 2000, 2000, 0, 230400, 0xf9e9a3ef
-0, 2100, 2100, 0, 230400, 0x7e0a3077
-0, 2200, 2200, 0, 230400, 0xd9245c5f
-0, 2300, 2300, 0, 230400, 0x6d077ea2
-0, 2400, 2400, 0, 230400, 0xf622bb2a
-0, 2500, 2500, 0, 230400, 0x35292dc8
-0, 2600, 2600, 0, 230400, 0xc0cea946
-0, 2700, 2700, 0, 230400, 0x98b27b60
-0, 2800, 2800, 0, 230400, 0x668ef6bd
-0, 2900, 2900, 0, 230400, 0x6c07a31c
-0, 3000, 3000, 0, 230400, 0x0b4a6ae1
-0, 3100, 3100, 0, 230400, 0x945b9878
-0, 3200, 3200, 0, 230400, 0xab28031c
-0, 3300, 3300, 0, 230400, 0x977252b0
-0, 3400, 3400, 0, 230400, 0x6c3d9706
-0, 3500, 3500, 0, 230400, 0xe053bc2a
-0, 3600, 3600, 0, 230400, 0x4cf2fc7c
-0, 3700, 3700, 0, 230400, 0x610beda7
+#tb 0: 1/12
+0, 0, 0, 1, 230400, 0xb1ee55dc
+0, 1, 1, 1, 230400, 0x97c580bf
+0, 2, 2, 1, 230400, 0xd4bd57e8
+0, 3, 3, 1, 230400, 0x412b79aa
+0, 4, 4, 1, 230400, 0x928a44d1
+0, 5, 5, 1, 230400, 0x6bbdc0e4
+0, 6, 6, 1, 230400, 0x382e960f
+0, 7, 7, 1, 230400, 0x62c863ea
+0, 8, 8, 1, 230400, 0xbfccd3ce
+0, 9, 9, 1, 230400, 0x1987cdd4
+0, 10, 10, 1, 230400, 0x40279727
+0, 11, 11, 1, 230400, 0x9d4f6746
+0, 12, 12, 1, 230400, 0x7b8a77ec
+0, 13, 13, 1, 230400, 0x2ce7a781
+0, 14, 14, 1, 230400, 0xb749815e
+0, 15, 15, 1, 230400, 0x61c88610
+0, 16, 16, 1, 230400, 0x8449114d
+0, 17, 17, 1, 230400, 0x5f73e666
+0, 18, 18, 1, 230400, 0xbde53ce6
+0, 19, 19, 1, 230400, 0x8c7406fd
+0, 20, 20, 1, 230400, 0xf9e9a3ef
+0, 21, 21, 1, 230400, 0x7e0a3077
+0, 22, 22, 1, 230400, 0xd9245c5f
+0, 23, 23, 1, 230400, 0x6d077ea2
+0, 24, 24, 1, 230400, 0xf622bb2a
+0, 25, 25, 1, 230400, 0x35292dc8
+0, 26, 26, 1, 230400, 0xc0cea946
+0, 27, 27, 1, 230400, 0x98b27b60
+0, 28, 28, 1, 230400, 0x668ef6bd
+0, 29, 29, 1, 230400, 0x6c07a31c
+0, 30, 30, 1, 230400, 0x0b4a6ae1
+0, 31, 31, 1, 230400, 0x945b9878
+0, 32, 32, 1, 230400, 0xab28031c
+0, 33, 33, 1, 230400, 0x977252b0
+0, 34, 34, 1, 230400, 0x6c3d9706
+0, 35, 35, 1, 230400, 0xe053bc2a
+0, 36, 36, 1, 230400, 0x4cf2fc7c
+0, 37, 37, 1, 230400, 0x610beda7
diff --git a/tests/ref/fate/qtrle-32bit b/tests/ref/fate/qtrle-32bit
index bbdd464..ed6dc03 100644
--- a/tests/ref/fate/qtrle-32bit
+++ b/tests/ref/fate/qtrle-32bit
@@ -1,27 +1,27 @@
-#tb 0: 1/2997
-0, 0, 0, 0, 1036800, 0x2a90d062
-0, 100, 100, 0, 1036800, 0x6565aded
-0, 200, 200, 0, 1036800, 0xf0b587d2
-0, 300, 300, 0, 1036800, 0xf0b4e53f
-0, 400, 400, 0, 1036800, 0x5ba4b96a
-0, 500, 500, 0, 1036800, 0x501df9c1
-0, 600, 600, 0, 1036800, 0xcf45b940
-0, 700, 700, 0, 1036800, 0xa454df07
-0, 800, 800, 0, 1036800, 0xc504d152
-0, 900, 900, 0, 1036800, 0xd90ecac7
-0, 1000, 1000, 0, 1036800, 0xe30368df
-0, 1100, 1100, 0, 1036800, 0x0ca35522
-0, 1200, 1200, 0, 1036800, 0xe76b8d43
-0, 1300, 1300, 0, 1036800, 0x7c85a447
-0, 1400, 1400, 0, 1036800, 0x3e2d1b5f
-0, 1500, 1500, 0, 1036800, 0x230fa5a6
-0, 1600, 1600, 0, 1036800, 0x4fad025e
-0, 1700, 1700, 0, 1036800, 0x7d3366ae
-0, 1800, 1800, 0, 1036800, 0xa83720f7
-0, 1900, 1900, 0, 1036800, 0x5dbd13b1
-0, 2000, 2000, 0, 1036800, 0xd0ebd56d
-0, 2100, 2100, 0, 1036800, 0x4d7c67f3
-0, 2200, 2200, 0, 1036800, 0x226baa3f
-0, 2300, 2300, 0, 1036800, 0xc0e93acf
-0, 2400, 2400, 0, 1036800, 0x5a466c17
-0, 2500, 2500, 0, 1036800, 0xfdb7d2ea
+#tb 0: 100/2997
+0, 0, 0, 1, 1036800, 0x2a90d062
+0, 1, 1, 1, 1036800, 0x6565aded
+0, 2, 2, 1, 1036800, 0xf0b587d2
+0, 3, 3, 1, 1036800, 0xf0b4e53f
+0, 4, 4, 1, 1036800, 0x5ba4b96a
+0, 5, 5, 1, 1036800, 0x501df9c1
+0, 6, 6, 1, 1036800, 0xcf45b940
+0, 7, 7, 1, 1036800, 0xa454df07
+0, 8, 8, 1, 1036800, 0xc504d152
+0, 9, 9, 1, 1036800, 0xd90ecac7
+0, 10, 10, 1, 1036800, 0xe30368df
+0, 11, 11, 1, 1036800, 0x0ca35522
+0, 12, 12, 1, 1036800, 0xe76b8d43
+0, 13, 13, 1, 1036800, 0x7c85a447
+0, 14, 14, 1, 1036800, 0x3e2d1b5f
+0, 15, 15, 1, 1036800, 0x230fa5a6
+0, 16, 16, 1, 1036800, 0x4fad025e
+0, 17, 17, 1, 1036800, 0x7d3366ae
+0, 18, 18, 1, 1036800, 0xa83720f7
+0, 19, 19, 1, 1036800, 0x5dbd13b1
+0, 20, 20, 1, 1036800, 0xd0ebd56d
+0, 21, 21, 1, 1036800, 0x4d7c67f3
+0, 22, 22, 1, 1036800, 0x226baa3f
+0, 23, 23, 1, 1036800, 0xc0e93acf
+0, 24, 24, 1, 1036800, 0x5a466c17
+0, 25, 25, 1, 1036800, 0xfdb7d2ea
diff --git a/tests/ref/fate/qtrle-4bit b/tests/ref/fate/qtrle-4bit
index cc09e78..74eb4ab 100644
--- a/tests/ref/fate/qtrle-4bit
+++ b/tests/ref/fate/qtrle-4bit
@@ -1,39 +1,39 @@
-#tb 0: 1/1200
-0, 0, 0, 0, 230400, 0x0655b3d9
-0, 100, 100, 0, 230400, 0x9c626fd3
-0, 200, 200, 0, 230400, 0x5bc95868
-0, 300, 300, 0, 230400, 0x55a38387
-0, 400, 400, 0, 230400, 0xd3495b60
-0, 500, 500, 0, 230400, 0xecdb2d15
-0, 600, 600, 0, 230400, 0x7f9b373e
-0, 700, 700, 0, 230400, 0x51caac22
-0, 800, 800, 0, 230400, 0x0f2ac153
-0, 900, 900, 0, 230400, 0xe5a6f9e7
-0, 1000, 1000, 0, 230400, 0xfc2b2250
-0, 1100, 1100, 0, 230400, 0x24e2da1b
-0, 1200, 1200, 0, 230400, 0x2723d7dd
-0, 1300, 1300, 0, 230400, 0x024a4989
-0, 1400, 1400, 0, 230400, 0xdbafb92d
-0, 1500, 1500, 0, 230400, 0x6b9b5056
-0, 1600, 1600, 0, 230400, 0x010cabb4
-0, 1700, 1700, 0, 230400, 0xf75bc1c0
-0, 1800, 1800, 0, 230400, 0x6c7fd744
-0, 1900, 1900, 0, 230400, 0xabe4371a
-0, 2000, 2000, 0, 230400, 0xe41fb781
-0, 2100, 2100, 0, 230400, 0x42c5649e
-0, 2200, 2200, 0, 230400, 0xf5511deb
-0, 2300, 2300, 0, 230400, 0xebf5ab32
-0, 2400, 2400, 0, 230400, 0x44398194
-0, 2500, 2500, 0, 230400, 0xfd63510c
-0, 2600, 2600, 0, 230400, 0xa013975e
-0, 2700, 2700, 0, 230400, 0xe0aa028d
-0, 2800, 2800, 0, 230400, 0x349f6f3b
-0, 2900, 2900, 0, 230400, 0x2446032c
-0, 3000, 3000, 0, 230400, 0x648f122c
-0, 3100, 3100, 0, 230400, 0xbda221fd
-0, 3200, 3200, 0, 230400, 0xf0f97642
-0, 3300, 3300, 0, 230400, 0x6a1737de
-0, 3400, 3400, 0, 230400, 0x808a8179
-0, 3500, 3500, 0, 230400, 0x121641cf
-0, 3600, 3600, 0, 230400, 0x275d11ea
-0, 3700, 3700, 0, 230400, 0x92adf2cf
+#tb 0: 1/12
+0, 0, 0, 1, 230400, 0x0655b3d9
+0, 1, 1, 1, 230400, 0x9c626fd3
+0, 2, 2, 1, 230400, 0x5bc95868
+0, 3, 3, 1, 230400, 0x55a38387
+0, 4, 4, 1, 230400, 0xd3495b60
+0, 5, 5, 1, 230400, 0xecdb2d15
+0, 6, 6, 1, 230400, 0x7f9b373e
+0, 7, 7, 1, 230400, 0x51caac22
+0, 8, 8, 1, 230400, 0x0f2ac153
+0, 9, 9, 1, 230400, 0xe5a6f9e7
+0, 10, 10, 1, 230400, 0xfc2b2250
+0, 11, 11, 1, 230400, 0x24e2da1b
+0, 12, 12, 1, 230400, 0x2723d7dd
+0, 13, 13, 1, 230400, 0x024a4989
+0, 14, 14, 1, 230400, 0xdbafb92d
+0, 15, 15, 1, 230400, 0x6b9b5056
+0, 16, 16, 1, 230400, 0x010cabb4
+0, 17, 17, 1, 230400, 0xf75bc1c0
+0, 18, 18, 1, 230400, 0x6c7fd744
+0, 19, 19, 1, 230400, 0xabe4371a
+0, 20, 20, 1, 230400, 0xe41fb781
+0, 21, 21, 1, 230400, 0x42c5649e
+0, 22, 22, 1, 230400, 0xf5511deb
+0, 23, 23, 1, 230400, 0xebf5ab32
+0, 24, 24, 1, 230400, 0x44398194
+0, 25, 25, 1, 230400, 0xfd63510c
+0, 26, 26, 1, 230400, 0xa013975e
+0, 27, 27, 1, 230400, 0xe0aa028d
+0, 28, 28, 1, 230400, 0x349f6f3b
+0, 29, 29, 1, 230400, 0x2446032c
+0, 30, 30, 1, 230400, 0x648f122c
+0, 31, 31, 1, 230400, 0xbda221fd
+0, 32, 32, 1, 230400, 0xf0f97642
+0, 33, 33, 1, 230400, 0x6a1737de
+0, 34, 34, 1, 230400, 0x808a8179
+0, 35, 35, 1, 230400, 0x121641cf
+0, 36, 36, 1, 230400, 0x275d11ea
+0, 37, 37, 1, 230400, 0x92adf2cf
diff --git a/tests/ref/fate/qtrle-8bit b/tests/ref/fate/qtrle-8bit
index bef2358..5b30fbb 100644
--- a/tests/ref/fate/qtrle-8bit
+++ b/tests/ref/fate/qtrle-8bit
@@ -1,168 +1,168 @@
-#tb 0: 1/600
+#tb 0: 1/15
0, 0, 0, 1, 921600, 0x1492e3ed
-0, 40, 40, 1, 921600, 0x1492e3ed
-0, 80, 80, 1, 921600, 0x1492e3ed
-0, 120, 120, 1, 921600, 0x23ef4fc7
-0, 160, 160, 1, 921600, 0x23ef4fc7
-0, 200, 200, 1, 921600, 0xe406d4be
-0, 240, 240, 1, 921600, 0xe406d4be
-0, 280, 280, 1, 921600, 0xe406d4be
-0, 320, 320, 1, 921600, 0x62b8b5a1
-0, 360, 360, 1, 921600, 0x62b8b5a1
-0, 400, 400, 1, 921600, 0x7d8ba674
-0, 440, 440, 1, 921600, 0x7d8ba674
-0, 480, 480, 1, 921600, 0x7d8ba674
-0, 520, 520, 1, 921600, 0xfe666be7
-0, 560, 560, 1, 921600, 0xfe666be7
-0, 600, 600, 1, 921600, 0x721baec0
-0, 640, 640, 1, 921600, 0x721baec0
-0, 680, 680, 1, 921600, 0x721baec0
-0, 720, 720, 1, 921600, 0xc237180a
-0, 760, 760, 1, 921600, 0xc237180a
-0, 800, 800, 1, 921600, 0xf03a7482
-0, 840, 840, 1, 921600, 0xf03a7482
-0, 880, 880, 1, 921600, 0xf03a7482
-0, 920, 920, 1, 921600, 0x5612a391
-0, 960, 960, 1, 921600, 0x5612a391
-0, 1000, 1000, 1, 921600, 0x9dbcc46a
-0, 1040, 1040, 1, 921600, 0x9dbcc46a
-0, 1080, 1080, 1, 921600, 0x9dbcc46a
-0, 1120, 1120, 1, 921600, 0xa128a5d5
-0, 1160, 1160, 1, 921600, 0xa128a5d5
-0, 1200, 1200, 1, 921600, 0x63e0025c
-0, 1240, 1240, 1, 921600, 0x63e0025c
-0, 1280, 1280, 1, 921600, 0x63e0025c
-0, 1320, 1320, 1, 921600, 0x262359ed
-0, 1360, 1360, 1, 921600, 0x262359ed
-0, 1400, 1400, 1, 921600, 0x343688e8
-0, 1440, 1440, 1, 921600, 0x343688e8
-0, 1480, 1480, 1, 921600, 0x343688e8
-0, 1520, 1520, 1, 921600, 0x343688e8
-0, 1560, 1560, 1, 921600, 0x343688e8
-0, 1600, 1600, 1, 921600, 0x343688e8
-0, 1640, 1640, 1, 921600, 0x343688e8
-0, 1680, 1680, 1, 921600, 0x343688e8
-0, 1720, 1720, 1, 921600, 0x343688e8
-0, 1760, 1760, 1, 921600, 0x343688e8
-0, 1800, 1800, 1, 921600, 0xe4b29d57
-0, 1840, 1840, 1, 921600, 0xe4b29d57
-0, 1880, 1880, 1, 921600, 0xe4b29d57
-0, 1920, 1920, 1, 921600, 0x198e8a4a
-0, 1960, 1960, 1, 921600, 0x198e8a4a
-0, 2000, 2000, 1, 921600, 0x0cad8dc9
-0, 2040, 2040, 1, 921600, 0x0cad8dc9
-0, 2080, 2080, 1, 921600, 0x0cad8dc9
-0, 2120, 2120, 1, 921600, 0x1f74cf3d
-0, 2160, 2160, 1, 921600, 0x1f74cf3d
-0, 2200, 2200, 1, 921600, 0xec5b5449
-0, 2240, 2240, 1, 921600, 0xec5b5449
-0, 2280, 2280, 1, 921600, 0xec5b5449
-0, 2320, 2320, 1, 921600, 0x39829711
-0, 2360, 2360, 1, 921600, 0x39829711
-0, 2400, 2400, 1, 921600, 0x6de5b9c6
-0, 2440, 2440, 1, 921600, 0x6de5b9c6
-0, 2480, 2480, 1, 921600, 0x6de5b9c6
-0, 2520, 2520, 1, 921600, 0x47b0e9d4
-0, 2560, 2560, 1, 921600, 0x47b0e9d4
-0, 2600, 2600, 1, 921600, 0x756452b8
-0, 2640, 2640, 1, 921600, 0x756452b8
-0, 2680, 2680, 1, 921600, 0x756452b8
-0, 2720, 2720, 1, 921600, 0x6fce3478
-0, 2760, 2760, 1, 921600, 0x6fce3478
-0, 2800, 2800, 1, 921600, 0x372397cd
-0, 2840, 2840, 1, 921600, 0x372397cd
-0, 2880, 2880, 1, 921600, 0x372397cd
-0, 2920, 2920, 1, 921600, 0xe3999ba1
-0, 2960, 2960, 1, 921600, 0xe3999ba1
-0, 3000, 3000, 1, 921600, 0x6ba26b43
-0, 3040, 3040, 1, 921600, 0x6ba26b43
-0, 3080, 3080, 1, 921600, 0x6ba26b43
-0, 3120, 3120, 1, 921600, 0x4e9ee49e
-0, 3160, 3160, 1, 921600, 0x4e9ee49e
-0, 3200, 3200, 1, 921600, 0xdb5fd6e7
-0, 3240, 3240, 1, 921600, 0xdb5fd6e7
-0, 3280, 3280, 1, 921600, 0xdb5fd6e7
-0, 3320, 3320, 1, 921600, 0x8f2254a5
-0, 3360, 3360, 1, 921600, 0x8f2254a5
-0, 3400, 3400, 1, 921600, 0x8f2254a5
-0, 3440, 3440, 1, 921600, 0x8f2254a5
-0, 3480, 3480, 1, 921600, 0x8f2254a5
-0, 3520, 3520, 1, 921600, 0x8f2254a5
-0, 3560, 3560, 1, 921600, 0x8f2254a5
-0, 3600, 3600, 1, 921600, 0x8f2254a5
-0, 3640, 3640, 1, 921600, 0x8f2254a5
-0, 3680, 3680, 1, 921600, 0x8f2254a5
-0, 3720, 3720, 1, 921600, 0x57e95c32
-0, 3760, 3760, 1, 921600, 0x57e95c32
-0, 3800, 3800, 1, 921600, 0x41627a9b
-0, 3840, 3840, 1, 921600, 0x41627a9b
-0, 3880, 3880, 1, 921600, 0x41627a9b
-0, 3920, 3920, 1, 921600, 0x7412dcee
-0, 3960, 3960, 1, 921600, 0x7412dcee
-0, 4000, 4000, 1, 921600, 0xaebe10ed
-0, 4040, 4040, 1, 921600, 0xaebe10ed
-0, 4080, 4080, 1, 921600, 0xaebe10ed
-0, 4120, 4120, 1, 921600, 0x411a91f6
-0, 4160, 4160, 1, 921600, 0x411a91f6
-0, 4200, 4200, 1, 921600, 0xb059df3f
-0, 4240, 4240, 1, 921600, 0xb059df3f
-0, 4280, 4280, 1, 921600, 0xb059df3f
-0, 4320, 4320, 1, 921600, 0x4d6f5a77
-0, 4360, 4360, 1, 921600, 0x4d6f5a77
-0, 4400, 4400, 1, 921600, 0xbbf06df4
-0, 4440, 4440, 1, 921600, 0xbbf06df4
-0, 4480, 4480, 1, 921600, 0xbbf06df4
-0, 4520, 4520, 1, 921600, 0xe27f7bf6
-0, 4560, 4560, 1, 921600, 0xe27f7bf6
-0, 4600, 4600, 1, 921600, 0xd7e8360e
-0, 4640, 4640, 1, 921600, 0xd7e8360e
-0, 4680, 4680, 1, 921600, 0xd7e8360e
-0, 4720, 4720, 1, 921600, 0x1dd4c344
-0, 4760, 4760, 1, 921600, 0x1dd4c344
-0, 4800, 4800, 1, 921600, 0x7995a7ce
-0, 4840, 4840, 1, 921600, 0x7995a7ce
-0, 4880, 4880, 1, 921600, 0x7995a7ce
-0, 4920, 4920, 1, 921600, 0x2ef3c566
-0, 4960, 4960, 1, 921600, 0x2ef3c566
-0, 5000, 5000, 1, 921600, 0xf296736e
-0, 5040, 5040, 1, 921600, 0xf296736e
-0, 5080, 5080, 1, 921600, 0xf296736e
-0, 5120, 5120, 1, 921600, 0xf296736e
-0, 5160, 5160, 1, 921600, 0xf296736e
-0, 5200, 5200, 1, 921600, 0xf296736e
-0, 5240, 5240, 1, 921600, 0xf296736e
-0, 5280, 5280, 1, 921600, 0xf296736e
-0, 5320, 5320, 1, 921600, 0xf296736e
-0, 5360, 5360, 1, 921600, 0xf296736e
-0, 5400, 5400, 1, 921600, 0x1a488311
-0, 5440, 5440, 1, 921600, 0x1a488311
-0, 5480, 5480, 1, 921600, 0x1a488311
-0, 5520, 5520, 1, 921600, 0x9e28011b
-0, 5560, 5560, 1, 921600, 0x9e28011b
-0, 5600, 5600, 1, 921600, 0x84d1ea80
-0, 5640, 5640, 1, 921600, 0x84d1ea80
-0, 5680, 5680, 1, 921600, 0x84d1ea80
-0, 5720, 5720, 1, 921600, 0x9ed41052
-0, 5760, 5760, 1, 921600, 0x9ed41052
-0, 5800, 5800, 1, 921600, 0xd4db7206
-0, 5840, 5840, 1, 921600, 0xd4db7206
-0, 5880, 5880, 1, 921600, 0xd4db7206
-0, 5920, 5920, 1, 921600, 0x55f695a9
-0, 5960, 5960, 1, 921600, 0x55f695a9
-0, 6000, 6000, 1, 921600, 0x9d8c667f
-0, 6040, 6040, 1, 921600, 0x9d8c667f
-0, 6080, 6080, 1, 921600, 0x9d8c667f
-0, 6120, 6120, 1, 921600, 0x9b6037ec
-0, 6160, 6160, 1, 921600, 0x9b6037ec
-0, 6200, 6200, 1, 921600, 0x57c5e835
-0, 6240, 6240, 1, 921600, 0x57c5e835
-0, 6280, 6280, 1, 921600, 0x57c5e835
-0, 6320, 6320, 1, 921600, 0x476dad89
-0, 6360, 6360, 1, 921600, 0x476dad89
-0, 6400, 6400, 1, 921600, 0xcfd6ad2b
-0, 6440, 6440, 1, 921600, 0xcfd6ad2b
-0, 6480, 6480, 1, 921600, 0xcfd6ad2b
-0, 6520, 6520, 1, 921600, 0x3b372379
-0, 6560, 6560, 1, 921600, 0x3b372379
-0, 6600, 6600, 1, 921600, 0x36f245f5
-0, 6620, 6620, 1, 921600, 0x36f245f5
+0, 1, 1, 1, 921600, 0x1492e3ed
+0, 2, 2, 1, 921600, 0x1492e3ed
+0, 3, 3, 1, 921600, 0x23ef4fc7
+0, 4, 4, 1, 921600, 0x23ef4fc7
+0, 5, 5, 1, 921600, 0xe406d4be
+0, 6, 6, 1, 921600, 0xe406d4be
+0, 7, 7, 1, 921600, 0xe406d4be
+0, 8, 8, 1, 921600, 0x62b8b5a1
+0, 9, 9, 1, 921600, 0x62b8b5a1
+0, 10, 10, 1, 921600, 0x7d8ba674
+0, 11, 11, 1, 921600, 0x7d8ba674
+0, 12, 12, 1, 921600, 0x7d8ba674
+0, 13, 13, 1, 921600, 0xfe666be7
+0, 14, 14, 1, 921600, 0xfe666be7
+0, 15, 15, 1, 921600, 0x721baec0
+0, 16, 16, 1, 921600, 0x721baec0
+0, 17, 17, 1, 921600, 0x721baec0
+0, 18, 18, 1, 921600, 0xc237180a
+0, 19, 19, 1, 921600, 0xc237180a
+0, 20, 20, 1, 921600, 0xf03a7482
+0, 21, 21, 1, 921600, 0xf03a7482
+0, 22, 22, 1, 921600, 0xf03a7482
+0, 23, 23, 1, 921600, 0x5612a391
+0, 24, 24, 1, 921600, 0x5612a391
+0, 25, 25, 1, 921600, 0x9dbcc46a
+0, 26, 26, 1, 921600, 0x9dbcc46a
+0, 27, 27, 1, 921600, 0x9dbcc46a
+0, 28, 28, 1, 921600, 0xa128a5d5
+0, 29, 29, 1, 921600, 0xa128a5d5
+0, 30, 30, 1, 921600, 0x63e0025c
+0, 31, 31, 1, 921600, 0x63e0025c
+0, 32, 32, 1, 921600, 0x63e0025c
+0, 33, 33, 1, 921600, 0x262359ed
+0, 34, 34, 1, 921600, 0x262359ed
+0, 35, 35, 1, 921600, 0x343688e8
+0, 36, 36, 1, 921600, 0x343688e8
+0, 37, 37, 1, 921600, 0x343688e8
+0, 38, 38, 1, 921600, 0x343688e8
+0, 39, 39, 1, 921600, 0x343688e8
+0, 40, 40, 1, 921600, 0x343688e8
+0, 41, 41, 1, 921600, 0x343688e8
+0, 42, 42, 1, 921600, 0x343688e8
+0, 43, 43, 1, 921600, 0x343688e8
+0, 44, 44, 1, 921600, 0x343688e8
+0, 45, 45, 1, 921600, 0xe4b29d57
+0, 46, 46, 1, 921600, 0xe4b29d57
+0, 47, 47, 1, 921600, 0xe4b29d57
+0, 48, 48, 1, 921600, 0x198e8a4a
+0, 49, 49, 1, 921600, 0x198e8a4a
+0, 50, 50, 1, 921600, 0x0cad8dc9
+0, 51, 51, 1, 921600, 0x0cad8dc9
+0, 52, 52, 1, 921600, 0x0cad8dc9
+0, 53, 53, 1, 921600, 0x1f74cf3d
+0, 54, 54, 1, 921600, 0x1f74cf3d
+0, 55, 55, 1, 921600, 0xec5b5449
+0, 56, 56, 1, 921600, 0xec5b5449
+0, 57, 57, 1, 921600, 0xec5b5449
+0, 58, 58, 1, 921600, 0x39829711
+0, 59, 59, 1, 921600, 0x39829711
+0, 60, 60, 1, 921600, 0x6de5b9c6
+0, 61, 61, 1, 921600, 0x6de5b9c6
+0, 62, 62, 1, 921600, 0x6de5b9c6
+0, 63, 63, 1, 921600, 0x47b0e9d4
+0, 64, 64, 1, 921600, 0x47b0e9d4
+0, 65, 65, 1, 921600, 0x756452b8
+0, 66, 66, 1, 921600, 0x756452b8
+0, 67, 67, 1, 921600, 0x756452b8
+0, 68, 68, 1, 921600, 0x6fce3478
+0, 69, 69, 1, 921600, 0x6fce3478
+0, 70, 70, 1, 921600, 0x372397cd
+0, 71, 71, 1, 921600, 0x372397cd
+0, 72, 72, 1, 921600, 0x372397cd
+0, 73, 73, 1, 921600, 0xe3999ba1
+0, 74, 74, 1, 921600, 0xe3999ba1
+0, 75, 75, 1, 921600, 0x6ba26b43
+0, 76, 76, 1, 921600, 0x6ba26b43
+0, 77, 77, 1, 921600, 0x6ba26b43
+0, 78, 78, 1, 921600, 0x4e9ee49e
+0, 79, 79, 1, 921600, 0x4e9ee49e
+0, 80, 80, 1, 921600, 0xdb5fd6e7
+0, 81, 81, 1, 921600, 0xdb5fd6e7
+0, 82, 82, 1, 921600, 0xdb5fd6e7
+0, 83, 83, 1, 921600, 0x8f2254a5
+0, 84, 84, 1, 921600, 0x8f2254a5
+0, 85, 85, 1, 921600, 0x8f2254a5
+0, 86, 86, 1, 921600, 0x8f2254a5
+0, 87, 87, 1, 921600, 0x8f2254a5
+0, 88, 88, 1, 921600, 0x8f2254a5
+0, 89, 89, 1, 921600, 0x8f2254a5
+0, 90, 90, 1, 921600, 0x8f2254a5
+0, 91, 91, 1, 921600, 0x8f2254a5
+0, 92, 92, 1, 921600, 0x8f2254a5
+0, 93, 93, 1, 921600, 0x57e95c32
+0, 94, 94, 1, 921600, 0x57e95c32
+0, 95, 95, 1, 921600, 0x41627a9b
+0, 96, 96, 1, 921600, 0x41627a9b
+0, 97, 97, 1, 921600, 0x41627a9b
+0, 98, 98, 1, 921600, 0x7412dcee
+0, 99, 99, 1, 921600, 0x7412dcee
+0, 100, 100, 1, 921600, 0xaebe10ed
+0, 101, 101, 1, 921600, 0xaebe10ed
+0, 102, 102, 1, 921600, 0xaebe10ed
+0, 103, 103, 1, 921600, 0x411a91f6
+0, 104, 104, 1, 921600, 0x411a91f6
+0, 105, 105, 1, 921600, 0xb059df3f
+0, 106, 106, 1, 921600, 0xb059df3f
+0, 107, 107, 1, 921600, 0xb059df3f
+0, 108, 108, 1, 921600, 0x4d6f5a77
+0, 109, 109, 1, 921600, 0x4d6f5a77
+0, 110, 110, 1, 921600, 0xbbf06df4
+0, 111, 111, 1, 921600, 0xbbf06df4
+0, 112, 112, 1, 921600, 0xbbf06df4
+0, 113, 113, 1, 921600, 0xe27f7bf6
+0, 114, 114, 1, 921600, 0xe27f7bf6
+0, 115, 115, 1, 921600, 0xd7e8360e
+0, 116, 116, 1, 921600, 0xd7e8360e
+0, 117, 117, 1, 921600, 0xd7e8360e
+0, 118, 118, 1, 921600, 0x1dd4c344
+0, 119, 119, 1, 921600, 0x1dd4c344
+0, 120, 120, 1, 921600, 0x7995a7ce
+0, 121, 121, 1, 921600, 0x7995a7ce
+0, 122, 122, 1, 921600, 0x7995a7ce
+0, 123, 123, 1, 921600, 0x2ef3c566
+0, 124, 124, 1, 921600, 0x2ef3c566
+0, 125, 125, 1, 921600, 0xf296736e
+0, 126, 126, 1, 921600, 0xf296736e
+0, 127, 127, 1, 921600, 0xf296736e
+0, 128, 128, 1, 921600, 0xf296736e
+0, 129, 129, 1, 921600, 0xf296736e
+0, 130, 130, 1, 921600, 0xf296736e
+0, 131, 131, 1, 921600, 0xf296736e
+0, 132, 132, 1, 921600, 0xf296736e
+0, 133, 133, 1, 921600, 0xf296736e
+0, 134, 134, 1, 921600, 0xf296736e
+0, 135, 135, 1, 921600, 0x1a488311
+0, 136, 136, 1, 921600, 0x1a488311
+0, 137, 137, 1, 921600, 0x1a488311
+0, 138, 138, 1, 921600, 0x9e28011b
+0, 139, 139, 1, 921600, 0x9e28011b
+0, 140, 140, 1, 921600, 0x84d1ea80
+0, 141, 141, 1, 921600, 0x84d1ea80
+0, 142, 142, 1, 921600, 0x84d1ea80
+0, 143, 143, 1, 921600, 0x9ed41052
+0, 144, 144, 1, 921600, 0x9ed41052
+0, 145, 145, 1, 921600, 0xd4db7206
+0, 146, 146, 1, 921600, 0xd4db7206
+0, 147, 147, 1, 921600, 0xd4db7206
+0, 148, 148, 1, 921600, 0x55f695a9
+0, 149, 149, 1, 921600, 0x55f695a9
+0, 150, 150, 1, 921600, 0x9d8c667f
+0, 151, 151, 1, 921600, 0x9d8c667f
+0, 152, 152, 1, 921600, 0x9d8c667f
+0, 153, 153, 1, 921600, 0x9b6037ec
+0, 154, 154, 1, 921600, 0x9b6037ec
+0, 155, 155, 1, 921600, 0x57c5e835
+0, 156, 156, 1, 921600, 0x57c5e835
+0, 157, 157, 1, 921600, 0x57c5e835
+0, 158, 158, 1, 921600, 0x476dad89
+0, 159, 159, 1, 921600, 0x476dad89
+0, 160, 160, 1, 921600, 0xcfd6ad2b
+0, 161, 161, 1, 921600, 0xcfd6ad2b
+0, 162, 162, 1, 921600, 0xcfd6ad2b
+0, 163, 163, 1, 921600, 0x3b372379
+0, 164, 164, 1, 921600, 0x3b372379
+0, 165, 165, 1, 921600, 0x36f245f5
+0, 166, 166, 1, 921600, 0x36f245f5
diff --git a/tests/ref/fate/quickdraw b/tests/ref/fate/quickdraw
index 9a55ad5..eccb477 100644
--- a/tests/ref/fate/quickdraw
+++ b/tests/ref/fate/quickdraw
@@ -1,3 +1,3 @@
-#tb 0: 1/600
+#tb 0: 1/15
0, 0, 0, 1, 921600, 0xc0e68764
-0, 80, 80, 1, 921600, 0x01a16629
+0, 2, 2, 1, 921600, 0x01a16629
diff --git a/tests/ref/fate/random_seed b/tests/ref/fate/random_seed
new file mode 100644
index 0000000..2b5b3af
--- /dev/null
+++ b/tests/ref/fate/random_seed
@@ -0,0 +1 @@
+seeds OK
diff --git a/tests/ref/fate/redcode-demux b/tests/ref/fate/redcode-demux
index 34a2924..a7e2838 100644
--- a/tests/ref/fate/redcode-demux
+++ b/tests/ref/fate/redcode-demux
@@ -4,4 +4,4 @@
1, 0, 0, 18140, 14816, 0xd185e8c7
0, 10010, 10010, 10010, 1626092, 0x070bd882
1, 18140, 18140, 40920, 32736, 0x791b737a
-0, 20020, 20020, 10010, 893932, 0x8c7cd0a6
+0, 20020, 20020, 10010, 893932, 0x8c7cd0a6, F=0x3
diff --git a/tests/ref/fate/redspark-demux b/tests/ref/fate/redspark-demux
new file mode 100644
index 0000000..fadfe93
--- /dev/null
+++ b/tests/ref/fate/redspark-demux
@@ -0,0 +1 @@
+CRC=0xc0fd1aa2
diff --git a/tests/ref/fate/rpza b/tests/ref/fate/rpza
index a1c5333..a9ae3bb 100644
--- a/tests/ref/fate/rpza
+++ b/tests/ref/fate/rpza
@@ -1,31 +1,31 @@
-#tb 0: 1/600
-0, 0, 0, 1, 230400, 0x4aec80a3
-0, 40, 40, 1, 230400, 0xb6c41452
-0, 80, 80, 1, 230400, 0xa6c27f12
-0, 120, 120, 1, 230400, 0x309bd2d2
-0, 160, 160, 1, 230400, 0x597a7341
-0, 200, 200, 1, 230400, 0x597a7341
-0, 240, 240, 1, 230400, 0xd6d6c569
-0, 280, 280, 1, 230400, 0x31413d89
-0, 320, 320, 1, 230400, 0x464e42e9
-0, 360, 360, 1, 230400, 0x502d7c71
-0, 400, 400, 1, 230400, 0x502d7c71
-0, 440, 440, 1, 230400, 0xc96f23d1
-0, 480, 480, 1, 230400, 0xc96f23d1
-0, 520, 520, 1, 230400, 0x5bfd2bc7
-0, 560, 560, 1, 230400, 0x821640a7
-0, 600, 600, 1, 230400, 0x8f001967
-0, 640, 640, 1, 230400, 0x406ba109
-0, 680, 680, 1, 230400, 0x85d99b50
-0, 720, 720, 1, 230400, 0x2fdb4018
-0, 760, 760, 1, 230400, 0xfa127259
-0, 800, 800, 1, 230400, 0xe6427b9b
-0, 840, 840, 1, 230400, 0xe6427b9b
-0, 880, 880, 1, 230400, 0x3a279000
-0, 920, 920, 1, 230400, 0x710755ee
-0, 960, 960, 1, 230400, 0x76549d35
-0, 1000, 1000, 1, 230400, 0xf4d0132c
-0, 1040, 1040, 1, 230400, 0xf4d0132c
-0, 1080, 1080, 1, 230400, 0x19d7ec14
-0, 1120, 1120, 1, 230400, 0x19d7ec14
-0, 1160, 1160, 1, 230400, 0x5f24b7e1
+#tb 0: 1/15
+0, 0, 0, 1, 230400, 0x26a4728c
+0, 1, 1, 1, 230400, 0xa5ff0a21
+0, 2, 2, 1, 230400, 0x479d767d
+0, 3, 3, 1, 230400, 0xc619cd01
+0, 4, 4, 1, 230400, 0x1d377157
+0, 5, 5, 1, 230400, 0x1d377157
+0, 6, 6, 1, 230400, 0x0941c629
+0, 7, 7, 1, 230400, 0xe64b3a93
+0, 8, 8, 1, 230400, 0x28493fd7
+0, 9, 9, 1, 230400, 0x18c77af2
+0, 10, 10, 1, 230400, 0x18c77af2
+0, 11, 11, 1, 230400, 0x5a542008
+0, 12, 12, 1, 230400, 0x5a542008
+0, 13, 13, 1, 230400, 0x3b1a34fd
+0, 14, 14, 1, 230400, 0x77d34944
+0, 15, 15, 1, 230400, 0x50ac218c
+0, 16, 16, 1, 230400, 0xcb999f16
+0, 17, 17, 1, 230400, 0xe1ce9f19
+0, 18, 18, 1, 230400, 0xb10b4264
+0, 19, 19, 1, 230400, 0x61207031
+0, 20, 20, 1, 230400, 0x81626d5b
+0, 21, 21, 1, 230400, 0x81626d5b
+0, 22, 22, 1, 230400, 0x1cb59751
+0, 23, 23, 1, 230400, 0x316e6962
+0, 24, 24, 1, 230400, 0x4c01b829
+0, 25, 25, 1, 230400, 0x276e32bc
+0, 26, 26, 1, 230400, 0x276e32bc
+0, 27, 27, 1, 230400, 0xe251117a
+0, 28, 28, 1, 230400, 0xe251117a
+0, 29, 29, 1, 230400, 0x41b7f098
diff --git a/tests/ref/fate/rsd-demux b/tests/ref/fate/rsd-demux
new file mode 100644
index 0000000..3aa2573
--- /dev/null
+++ b/tests/ref/fate/rsd-demux
@@ -0,0 +1 @@
+CRC=0x7b7807d8
diff --git a/tests/ref/fate/rv30 b/tests/ref/fate/rv30
index 89a9d8c..70db647 100644
--- a/tests/ref/fate/rv30
+++ b/tests/ref/fate/rv30
@@ -1,110 +1,110 @@
-#tb 0: 1/1000
-0, 1, 1, 0, 126720, 0xcefaec47
-0, 33, 33, 0, 126720, 0xa416ece5
-0, 66, 66, 0, 126720, 0xa416ece5
-0, 100, 100, 0, 126720, 0xa416ece5
-0, 133, 133, 0, 126720, 0x60d6ed27
-0, 166, 166, 0, 126720, 0x259af497
-0, 200, 200, 0, 126720, 0x5e6ff4d7
-0, 233, 233, 0, 126720, 0xcc10f4b7
-0, 266, 266, 0, 126720, 0x763ab817
-0, 300, 300, 0, 126720, 0xe95fb8d7
-0, 333, 333, 0, 126720, 0xe2b1b917
-0, 367, 367, 0, 126720, 0x11abb8f7
-0, 400, 400, 0, 126720, 0x4b62b947
-0, 433, 433, 0, 126720, 0xcaf2bbb7
-0, 467, 467, 0, 126720, 0x2953bc37
-0, 500, 500, 0, 126720, 0x1dd9bbd7
-0, 533, 533, 0, 126720, 0x105eb927
-0, 567, 567, 0, 126720, 0x7fa3ae27
-0, 600, 600, 0, 126720, 0x722e99f7
-0, 633, 633, 0, 126720, 0x5ac9a827
-0, 667, 667, 0, 126720, 0x07beba77
-0, 700, 700, 0, 126720, 0x29d6a887
-0, 734, 734, 0, 126720, 0xa5caab87
-0, 767, 767, 0, 126720, 0x9ca7aac7
-0, 800, 800, 0, 126720, 0xb7debcd7
-0, 834, 834, 0, 126720, 0xd115a757
-0, 867, 867, 0, 126720, 0x6ddaef32
-0, 900, 900, 0, 126720, 0xde1bb900
-0, 934, 934, 0, 126720, 0xac6c071b
-0, 967, 967, 0, 126720, 0x4a9f897c
-0, 1000, 1000, 0, 126720, 0xd8fa050f
-0, 1034, 1034, 0, 126720, 0x5d06be59
-0, 1067, 1067, 0, 126720, 0xdc3e0837
-0, 1101, 1101, 0, 126720, 0xcac6da2b
-0, 1134, 1134, 0, 126720, 0x6672dfc9
-0, 1167, 1167, 0, 126720, 0x7491b176
-0, 1201, 1201, 0, 126720, 0xa9477df0
-0, 1234, 1234, 0, 126720, 0xe976c34f
-0, 1267, 1267, 0, 126720, 0xdb7ab0e2
-0, 1301, 1301, 0, 126720, 0x1b42db35
-0, 1334, 1334, 0, 126720, 0xc6e10f9f
-0, 1368, 1368, 0, 126720, 0x169d61b6
-0, 1401, 1401, 0, 126720, 0xc7623119
-0, 1434, 1434, 0, 126720, 0x5b9b7543
-0, 1468, 1468, 0, 126720, 0x68c27aca
-0, 1501, 1501, 0, 126720, 0xa0e4e1c9
-0, 1534, 1534, 0, 126720, 0xbbdae87e
-0, 1568, 1568, 0, 126720, 0xe67e00a1
-0, 1601, 1601, 0, 126720, 0x648ea605
-0, 1634, 1634, 0, 126720, 0x5becb718
-0, 1668, 1668, 0, 126720, 0xb79ab1da
-0, 1701, 1701, 0, 126720, 0x0d52d1dc
-0, 1735, 1735, 0, 126720, 0x1277b853
-0, 1768, 1768, 0, 126720, 0xc57cbc83
-0, 1801, 1801, 0, 126720, 0x2126bdc3
-0, 1835, 1835, 0, 126720, 0x4c1ef41f
-0, 1868, 1868, 0, 126720, 0x185f6a2c
-0, 1901, 1901, 0, 126720, 0xb2b5a7d3
-0, 1935, 1935, 0, 126720, 0x32d7a26d
-0, 1968, 1968, 0, 126720, 0x0bffd118
-0, 2001, 2001, 0, 126720, 0x2eed823a
-0, 2035, 2035, 0, 126720, 0xc4c0147c
-0, 2068, 2068, 0, 126720, 0x1f8bf8ac
-0, 2102, 2102, 0, 126720, 0xfcb715e8
-0, 2135, 2135, 0, 126720, 0xc3e9fa9c
-0, 2168, 2168, 0, 126720, 0x9ad8572c
-0, 2202, 2202, 0, 126720, 0x2800596d
-0, 2235, 2235, 0, 126720, 0x3caa5094
-0, 2268, 2268, 0, 126720, 0x6162e000
-0, 2302, 2302, 0, 126720, 0x18200f2c
-0, 2335, 2335, 0, 126720, 0x649e699f
-0, 2369, 2369, 0, 126720, 0x5f513367
-0, 2402, 2402, 0, 126720, 0x71fbf4a8
-0, 2435, 2435, 0, 126720, 0x5bff7b97
-0, 2469, 2469, 0, 126720, 0xbad453d4
-0, 2502, 2502, 0, 126720, 0x56e6161d
-0, 2535, 2535, 0, 126720, 0x524f2980
-0, 2569, 2569, 0, 126720, 0x0589405a
-0, 2602, 2602, 0, 126720, 0x5c264043
-0, 2635, 2635, 0, 126720, 0x2394696f
-0, 2669, 2669, 0, 126720, 0x1aa0cd15
-0, 2702, 2702, 0, 126720, 0xd6ec7840
-0, 2736, 2736, 0, 126720, 0xde5531f0
-0, 2769, 2769, 0, 126720, 0x03a42c3a
-0, 2802, 2802, 0, 126720, 0xbdee0efb
-0, 2836, 2836, 0, 126720, 0xa6012736
-0, 2869, 2869, 0, 126720, 0x448f5ae6
-0, 2902, 2902, 0, 126720, 0x8a2550c3
-0, 2936, 2936, 0, 126720, 0x143104e7
-0, 2969, 2969, 0, 126720, 0x75db363d
-0, 3002, 3002, 0, 126720, 0x906d2f9d
-0, 3036, 3036, 0, 126720, 0xfc7b30ab
-0, 3069, 3069, 0, 126720, 0xd3edaa62
-0, 3103, 3103, 0, 126720, 0x6267f3fc
-0, 3136, 3136, 0, 126720, 0x87b6c67f
-0, 3169, 3169, 0, 126720, 0x84da3b79
-0, 3203, 3203, 0, 126720, 0x72fbae15
-0, 3236, 3236, 0, 126720, 0xb8474a80
-0, 3269, 3269, 0, 126720, 0xbeae088b
-0, 3303, 3303, 0, 126720, 0x538b1a14
-0, 3336, 3336, 0, 126720, 0x07bbddcd
-0, 3370, 3370, 0, 126720, 0x807ddf8f
-0, 3403, 3403, 0, 126720, 0x325bb46d
-0, 3436, 3436, 0, 126720, 0xd80c2f2a
-0, 3470, 3470, 0, 126720, 0xfc1b0dec
-0, 3503, 3503, 0, 126720, 0x46068ebc
-0, 3536, 3536, 0, 126720, 0xcd987941
-0, 3570, 3570, 0, 126720, 0x52f37f2e
-0, 3603, 3603, 0, 126720, 0xc96931a2
+#tb 0: 32768/982057
+0, 0, 0, 1, 126720, 0xcefaec47
+0, 1, 1, 1, 126720, 0xa416ece5
+0, 2, 2, 1, 126720, 0xa416ece5
+0, 3, 3, 1, 126720, 0xa416ece5
+0, 4, 4, 1, 126720, 0x60d6ed27
+0, 5, 5, 1, 126720, 0x259af497
+0, 6, 6, 1, 126720, 0x5e6ff4d7
+0, 7, 7, 1, 126720, 0xcc10f4b7
+0, 8, 8, 1, 126720, 0x763ab817
+0, 9, 9, 1, 126720, 0xe95fb8d7
+0, 10, 10, 1, 126720, 0xe2b1b917
+0, 11, 11, 1, 126720, 0x11abb8f7
+0, 12, 12, 1, 126720, 0x4b62b947
+0, 13, 13, 1, 126720, 0xcaf2bbb7
+0, 14, 14, 1, 126720, 0x2953bc37
+0, 15, 15, 1, 126720, 0x1dd9bbd7
+0, 16, 16, 1, 126720, 0x105eb927
+0, 17, 17, 1, 126720, 0x7fa3ae27
+0, 18, 18, 1, 126720, 0x722e99f7
+0, 19, 19, 1, 126720, 0x5ac9a827
+0, 20, 20, 1, 126720, 0x07beba77
+0, 21, 21, 1, 126720, 0x29d6a887
+0, 22, 22, 1, 126720, 0xa5caab87
+0, 23, 23, 1, 126720, 0x9ca7aac7
+0, 24, 24, 1, 126720, 0xb7debcd7
+0, 25, 25, 1, 126720, 0xd115a757
+0, 26, 26, 1, 126720, 0x6ddaef32
+0, 27, 27, 1, 126720, 0xde1bb900
+0, 28, 28, 1, 126720, 0xac6c071b
+0, 29, 29, 1, 126720, 0x4a9f897c
+0, 30, 30, 1, 126720, 0xd8fa050f
+0, 31, 31, 1, 126720, 0x5d06be59
+0, 32, 32, 1, 126720, 0xdc3e0837
+0, 33, 33, 1, 126720, 0xcac6da2b
+0, 34, 34, 1, 126720, 0x6672dfc9
+0, 35, 35, 1, 126720, 0x7491b176
+0, 36, 36, 1, 126720, 0xa9477df0
+0, 37, 37, 1, 126720, 0xe976c34f
+0, 38, 38, 1, 126720, 0xdb7ab0e2
+0, 39, 39, 1, 126720, 0x1b42db35
+0, 40, 40, 1, 126720, 0xc6e10f9f
+0, 41, 41, 1, 126720, 0x169d61b6
+0, 42, 42, 1, 126720, 0xc7623119
+0, 43, 43, 1, 126720, 0x5b9b7543
+0, 44, 44, 1, 126720, 0x68c27aca
+0, 45, 45, 1, 126720, 0xa0e4e1c9
+0, 46, 46, 1, 126720, 0xbbdae87e
+0, 47, 47, 1, 126720, 0xe67e00a1
+0, 48, 48, 1, 126720, 0x648ea605
+0, 49, 49, 1, 126720, 0x5becb718
+0, 50, 50, 1, 126720, 0xb79ab1da
+0, 51, 51, 1, 126720, 0x0d52d1dc
+0, 52, 52, 1, 126720, 0x1277b853
+0, 53, 53, 1, 126720, 0xc57cbc83
+0, 54, 54, 1, 126720, 0x2126bdc3
+0, 55, 55, 1, 126720, 0x4c1ef41f
+0, 56, 56, 1, 126720, 0x185f6a2c
+0, 57, 57, 1, 126720, 0xb2b5a7d3
+0, 58, 58, 1, 126720, 0x32d7a26d
+0, 59, 59, 1, 126720, 0x0bffd118
+0, 60, 60, 1, 126720, 0x2eed823a
+0, 61, 61, 1, 126720, 0xc4c0147c
+0, 62, 62, 1, 126720, 0x1f8bf8ac
+0, 63, 63, 1, 126720, 0xfcb715e8
+0, 64, 64, 1, 126720, 0xc3e9fa9c
+0, 65, 65, 1, 126720, 0x9ad8572c
+0, 66, 66, 1, 126720, 0x2800596d
+0, 67, 67, 1, 126720, 0x3caa5094
+0, 68, 68, 1, 126720, 0x6162e000
+0, 69, 69, 1, 126720, 0x18200f2c
+0, 70, 70, 1, 126720, 0x649e699f
+0, 71, 71, 1, 126720, 0x5f513367
+0, 72, 72, 1, 126720, 0x71fbf4a8
+0, 73, 73, 1, 126720, 0x5bff7b97
+0, 74, 74, 1, 126720, 0xbad453d4
+0, 75, 75, 1, 126720, 0x56e6161d
+0, 76, 76, 1, 126720, 0x524f2980
+0, 77, 77, 1, 126720, 0x0589405a
+0, 78, 78, 1, 126720, 0x5c264043
+0, 79, 79, 1, 126720, 0x2394696f
+0, 80, 80, 1, 126720, 0x1aa0cd15
+0, 81, 81, 1, 126720, 0xd6ec7840
+0, 82, 82, 1, 126720, 0xde5531f0
+0, 83, 83, 1, 126720, 0x03a42c3a
+0, 84, 84, 1, 126720, 0xbdee0efb
+0, 85, 85, 1, 126720, 0xa6012736
+0, 86, 86, 1, 126720, 0x448f5ae6
+0, 87, 87, 1, 126720, 0x8a2550c3
+0, 88, 88, 1, 126720, 0x143104e7
+0, 89, 89, 1, 126720, 0x75db363d
+0, 90, 90, 1, 126720, 0x906d2f9d
+0, 91, 91, 1, 126720, 0xfc7b30ab
+0, 92, 92, 1, 126720, 0xd3edaa62
+0, 93, 93, 1, 126720, 0x6267f3fc
+0, 94, 94, 1, 126720, 0x87b6c67f
+0, 95, 95, 1, 126720, 0x84da3b79
+0, 96, 96, 1, 126720, 0x72fbae15
+0, 97, 97, 1, 126720, 0xb8474a80
+0, 98, 98, 1, 126720, 0xbeae088b
+0, 99, 99, 1, 126720, 0x538b1a14
+0, 100, 100, 1, 126720, 0x07bbddcd
+0, 101, 101, 1, 126720, 0x807ddf8f
+0, 102, 102, 1, 126720, 0x325bb46d
+0, 103, 103, 1, 126720, 0xd80c2f2a
+0, 104, 104, 1, 126720, 0xfc1b0dec
+0, 105, 105, 1, 126720, 0x46068ebc
+0, 106, 106, 1, 126720, 0xcd987941
+0, 107, 107, 1, 126720, 0x52f37f2e
+0, 108, 108, 1, 126720, 0xc96931a2
diff --git a/tests/ref/fate/rv40 b/tests/ref/fate/rv40
index d5cb265..6159859 100644
--- a/tests/ref/fate/rv40
+++ b/tests/ref/fate/rv40
@@ -1,240 +1,241 @@
-#tb 0: 1/1000
-0, -41, -41, 0, 276480, 0x5f7a0d4f
-0, 42, 42, 0, 276480, 0x5f7a0d4f
-0, 83, 83, 0, 276480, 0x5f7a0d4f
-0, 125, 125, 0, 276480, 0x5f7a0d4f
-0, 167, 167, 0, 276480, 0x5f7a0d4f
-0, 209, 209, 0, 276480, 0x5f7a0d4f
-0, 250, 250, 0, 276480, 0x5f7a0d4f
-0, 292, 292, 0, 276480, 0x5f7a0d4f
-0, 334, 334, 0, 276480, 0x5f7a0d4f
-0, 375, 375, 0, 276480, 0x5f7a0d4f
-0, 417, 417, 0, 276480, 0x5f7a0d4f
-0, 459, 459, 0, 276480, 0x5f7a0d4f
-0, 501, 501, 0, 276480, 0x5f7a0d4f
-0, 542, 542, 0, 276480, 0x5f7a0d4f
-0, 584, 584, 0, 276480, 0x5f7a0d4f
-0, 626, 626, 0, 276480, 0x5f7a0d4f
-0, 667, 667, 0, 276480, 0x5f7a0d4f
-0, 709, 709, 0, 276480, 0x5f7a0d4f
-0, 751, 751, 0, 276480, 0x5f7a0d4f
-0, 792, 792, 0, 276480, 0x5f7a0d4f
-0, 834, 834, 0, 276480, 0x5f7a0d4f
-0, 876, 876, 0, 276480, 0x5f7a0d4f
-0, 918, 918, 0, 276480, 0x5f7a0d4f
-0, 959, 959, 0, 276480, 0x5f7a0d4f
-0, 1001, 1001, 0, 276480, 0x5f7a0d4f
-0, 1043, 1043, 0, 276480, 0x5f7a0d4f
-0, 1084, 1084, 0, 276480, 0x5f7a0d4f
-0, 1126, 1126, 0, 276480, 0x5f7a0d4f
-0, 1168, 1168, 0, 276480, 0x5f7a0d4f
-0, 1210, 1210, 0, 276480, 0x5f7a0d4f
-0, 1251, 1251, 0, 276480, 0x5f7a0d4f
-0, 1293, 1293, 0, 276480, 0x5f7a0d4f
-0, 1335, 1335, 0, 276480, 0x5f7a0d4f
-0, 1376, 1376, 0, 276480, 0x75641594
-0, 1418, 1418, 0, 276480, 0x32ee3526
-0, 1460, 1460, 0, 276480, 0xcb53479a
-0, 1502, 1502, 0, 276480, 0x7ca9658e
-0, 1543, 1543, 0, 276480, 0x5ce39368
-0, 1585, 1585, 0, 276480, 0x4ec1e418
-0, 1627, 1627, 0, 276480, 0xb3790499
-0, 1668, 1668, 0, 276480, 0xa9f1506f
-0, 1710, 1710, 0, 276480, 0x85cbc3b5
-0, 1752, 1752, 0, 276480, 0x377c7b46
-0, 1793, 1793, 0, 276480, 0x1a61d8db
-0, 1835, 1835, 0, 276480, 0xe1de7f0a
-0, 1877, 1877, 0, 276480, 0x756a4a2e
-0, 1919, 1919, 0, 276480, 0xcb379547
-0, 1960, 1960, 0, 276480, 0xbae14484
-0, 2002, 2002, 0, 276480, 0x8e12331c
-0, 2044, 2044, 0, 276480, 0x99c085be
-0, 2085, 2085, 0, 276480, 0xe479ffed
-0, 2127, 2127, 0, 276480, 0x99c82949
-0, 2169, 2169, 0, 276480, 0xac7672dd
-0, 2211, 2211, 0, 276480, 0x1e4fae19
-0, 2252, 2252, 0, 276480, 0x776412ef
-0, 2294, 2294, 0, 276480, 0x7d9b579f
-0, 2336, 2336, 0, 276480, 0x1cd1ab29
-0, 2377, 2377, 0, 276480, 0x58ce0f38
-0, 2419, 2419, 0, 276480, 0x5ab69b27
-0, 2461, 2461, 0, 276480, 0x0afad610
-0, 2503, 2503, 0, 276480, 0x9eca3f11
-0, 2544, 2544, 0, 276480, 0xc3db9706
-0, 2586, 2586, 0, 276480, 0xc9c57884
-0, 2628, 2628, 0, 276480, 0xd9fbb2cf
-0, 2669, 2669, 0, 276480, 0xdc07f3c9
-0, 2711, 2711, 0, 276480, 0x000b5269
-0, 2753, 2753, 0, 276480, 0x27ff7a5d
-0, 2794, 2794, 0, 276480, 0xd92e2017
-0, 2836, 2836, 0, 276480, 0x18d4b27d
-0, 2878, 2878, 0, 276480, 0x70647530
-0, 2920, 2920, 0, 276480, 0x97612c4b
-0, 2961, 2961, 0, 276480, 0xc9d4ac78
-0, 3003, 3003, 0, 276480, 0x4ec4d57f
-0, 3045, 3045, 0, 276480, 0xdf4e04d7
-0, 3086, 3086, 0, 276480, 0xbd98f57c
-0, 3128, 3128, 0, 276480, 0x7247ea3e
-0, 3170, 3170, 0, 276480, 0xa5d670ec
-0, 3212, 3212, 0, 276480, 0x5163b29b
-0, 3253, 3253, 0, 276480, 0x99170e64
-0, 3295, 3295, 0, 276480, 0x37f4c0b0
-0, 3337, 3337, 0, 276480, 0x7a4f2561
-0, 3378, 3378, 0, 276480, 0x8a4e991f
-0, 3420, 3420, 0, 276480, 0x6a45425f
-0, 3462, 3462, 0, 276480, 0x1f0e2bb6
-0, 3504, 3504, 0, 276480, 0xd75482c6
-0, 3545, 3545, 0, 276480, 0x7bf6b1ef
-0, 3587, 3587, 0, 276480, 0x6de1e34b
-0, 3629, 3629, 0, 276480, 0x4526c89b
-0, 3670, 3670, 0, 276480, 0xf964e18e
-0, 3712, 3712, 0, 276480, 0xdcaaa99a
-0, 3754, 3754, 0, 276480, 0xd1e98808
-0, 3795, 3795, 0, 276480, 0x556b2365
-0, 3837, 3837, 0, 276480, 0x0cf65540
-0, 3879, 3879, 0, 276480, 0x6e2d524e
-0, 3921, 3921, 0, 276480, 0x22c50a3d
-0, 3962, 3962, 0, 276480, 0x293f19af
-0, 4004, 4004, 0, 276480, 0xf4b1c461
-0, 4046, 4046, 0, 276480, 0x62b76407
-0, 4087, 4087, 0, 276480, 0x51e9b3eb
-0, 4129, 4129, 0, 276480, 0x7b910bc7
-0, 4171, 4171, 0, 276480, 0x6dd14ca6
-0, 4213, 4213, 0, 276480, 0x441f7afd
-0, 4254, 4254, 0, 276480, 0xfb01efc6
-0, 4296, 4296, 0, 276480, 0x4f73ccea
-0, 4338, 4338, 0, 276480, 0x5ac8e06f
-0, 4379, 4379, 0, 276480, 0x294bb441
-0, 4421, 4421, 0, 276480, 0xe04ac45e
-0, 4463, 4463, 0, 276480, 0xa7a38d41
-0, 4505, 4505, 0, 276480, 0xf688a3ed
-0, 4546, 4546, 0, 276480, 0x58f275ea
-0, 4588, 4588, 0, 276480, 0xf0b3b71b
-0, 4630, 4630, 0, 276480, 0x3ce773bf
-0, 4671, 4671, 0, 276480, 0x01840548
-0, 4713, 4713, 0, 276480, 0x674e34e4
-0, 4755, 4755, 0, 276480, 0x41dda2d9
-0, 4796, 4796, 0, 276480, 0xc5b60838
-0, 4838, 4838, 0, 276480, 0x9b209f41
-0, 4880, 4880, 0, 276480, 0xf46ba7fb
-0, 4922, 4922, 0, 276480, 0x28b54815
-0, 4963, 4963, 0, 276480, 0xb605a933
-0, 5005, 5005, 0, 276480, 0x34484aff
-0, 5047, 5047, 0, 276480, 0xaf2b5d89
-0, 5088, 5088, 0, 276480, 0x8facba58
-0, 5130, 5130, 0, 276480, 0xbbe3e99f
-0, 5172, 5172, 0, 276480, 0x02162c7c
-0, 5214, 5214, 0, 276480, 0x28a63236
-0, 5255, 5255, 0, 276480, 0x1ad43fd7
-0, 5297, 5297, 0, 276480, 0xe37883e5
-0, 5339, 5339, 0, 276480, 0x2b8a89c5
-0, 5380, 5380, 0, 276480, 0x71507bd2
-0, 5422, 5422, 0, 276480, 0x35626022
-0, 5464, 5464, 0, 276480, 0x461fc3e7
-0, 5506, 5506, 0, 276480, 0xce5af1ec
-0, 5547, 5547, 0, 276480, 0x7c1139b3
-0, 5589, 5589, 0, 276480, 0x7fd73a99
-0, 5631, 5631, 0, 276480, 0x4ae4c3a6
-0, 5672, 5672, 0, 276480, 0xcb60725a
-0, 5714, 5714, 0, 276480, 0xb52e1aa2
-0, 5756, 5756, 0, 276480, 0xd6f82cae
-0, 5797, 5797, 0, 276480, 0x6310e665
-0, 5839, 5839, 0, 276480, 0xfa88a483
-0, 5881, 5881, 0, 276480, 0xf88f75d4
-0, 5923, 5923, 0, 276480, 0x04a8e3ee
-0, 5964, 5964, 0, 276480, 0x54766a12
-0, 6006, 6006, 0, 276480, 0x0b41f0d7
-0, 6048, 6048, 0, 276480, 0xa29f5b01
-0, 6089, 6089, 0, 276480, 0x754ceaf5
-0, 6131, 6131, 0, 276480, 0x150c0423
-0, 6173, 6173, 0, 276480, 0xde084059
-0, 6215, 6215, 0, 276480, 0x5a38b4af
-0, 6256, 6256, 0, 276480, 0xfcebc261
-0, 6298, 6298, 0, 276480, 0x0eb9770d
-0, 6340, 6340, 0, 276480, 0x046394ae
-0, 6381, 6381, 0, 276480, 0x3d3ca985
-0, 6423, 6423, 0, 276480, 0x94a03c75
-0, 6465, 6465, 0, 276480, 0x800eea2d
-0, 6507, 6507, 0, 276480, 0x6a841f41
-0, 6548, 6548, 0, 276480, 0x2f98911c
-0, 6590, 6590, 0, 276480, 0x923b9937
-0, 6632, 6632, 0, 276480, 0xe82f8e0f
-0, 6673, 6673, 0, 276480, 0xee82d657
-0, 6715, 6715, 0, 276480, 0xefab7ffd
-0, 6757, 6757, 0, 276480, 0x6b9fbc80
-0, 6798, 6798, 0, 276480, 0x4a1ada47
-0, 6840, 6840, 0, 276480, 0x6d4b49d7
-0, 6882, 6882, 0, 276480, 0xe4bdbd1e
-0, 6924, 6924, 0, 276480, 0x225a56c0
-0, 6965, 6965, 0, 276480, 0xd4adadad
-0, 7007, 7007, 0, 276480, 0xff4e1a8c
-0, 7049, 7049, 0, 276480, 0xf58b1b7c
-0, 7090, 7090, 0, 276480, 0xbaffcdcc
-0, 7132, 7132, 0, 276480, 0x374f88f0
-0, 7174, 7174, 0, 276480, 0x3d861ae6
-0, 7216, 7216, 0, 276480, 0xeb6eb88f
-0, 7257, 7257, 0, 276480, 0xdb753d35
-0, 7299, 7299, 0, 276480, 0x9aa543af
-0, 7341, 7341, 0, 276480, 0xb24c8016
-0, 7382, 7382, 0, 276480, 0xea80a82e
-0, 7424, 7424, 0, 276480, 0x2aae902a
-0, 7466, 7466, 0, 276480, 0x5bba3cfb
-0, 7508, 7508, 0, 276480, 0x5c6e97a9
-0, 7549, 7549, 0, 276480, 0x9b9ee961
-0, 7591, 7591, 0, 276480, 0xaa12b6fd
-0, 7633, 7633, 0, 276480, 0xe9d2439f
-0, 7674, 7674, 0, 276480, 0xbf09053c
-0, 7716, 7716, 0, 276480, 0x50c31e73
-0, 7758, 7758, 0, 276480, 0xdd9fb89f
-0, 7799, 7799, 0, 276480, 0x3e4e5aec
-0, 7841, 7841, 0, 276480, 0x0b752d28
-0, 7883, 7883, 0, 276480, 0xaf82399a
-0, 7925, 7925, 0, 276480, 0x7ce5f23c
-0, 7966, 7966, 0, 276480, 0xad135d0f
-0, 8008, 8008, 0, 276480, 0x55dadd30
-0, 8050, 8050, 0, 276480, 0x5aaa7519
-0, 8091, 8091, 0, 276480, 0xe45a5599
-0, 8133, 8133, 0, 276480, 0xc8e89913
-0, 8175, 8175, 0, 276480, 0x2f447fd3
-0, 8217, 8217, 0, 276480, 0x704411fb
-0, 8258, 8258, 0, 276480, 0x9d7430a1
-0, 8300, 8300, 0, 276480, 0x24dd5fd3
-0, 8342, 8342, 0, 276480, 0x51cb657c
-0, 8383, 8383, 0, 276480, 0x2c230702
-0, 8425, 8425, 0, 276480, 0x4a4f76cd
-0, 8467, 8467, 0, 276480, 0xdcd71e88
-0, 8509, 8509, 0, 276480, 0x87160f99
-0, 8550, 8550, 0, 276480, 0x27f54854
-0, 8592, 8592, 0, 276480, 0x694d76e3
-0, 8634, 8634, 0, 276480, 0xcbe93c19
-0, 8675, 8675, 0, 276480, 0x50742e1b
-0, 8717, 8717, 0, 276480, 0x525463e2
-0, 8759, 8759, 0, 276480, 0x819898f9
-0, 8800, 8800, 0, 276480, 0x08fac755
-0, 8842, 8842, 0, 276480, 0x35c46927
-0, 8884, 8884, 0, 276480, 0xeeed00fc
-0, 8926, 8926, 0, 276480, 0xb6f99ee3
-0, 8967, 8967, 0, 276480, 0xd87f4c73
-0, 9009, 9009, 0, 276480, 0xde97d9fd
-0, 9051, 9051, 0, 276480, 0xefc83107
-0, 9092, 9092, 0, 276480, 0xbb22e024
-0, 9134, 9134, 0, 276480, 0x53a7cfcb
-0, 9176, 9176, 0, 276480, 0xbe1fbb19
-0, 9218, 9218, 0, 276480, 0x300f922a
-0, 9259, 9259, 0, 276480, 0x826fc3bd
-0, 9301, 9301, 0, 276480, 0x679aa57a
-0, 9343, 9343, 0, 276480, 0x5497097b
-0, 9384, 9384, 0, 276480, 0x679a53f8
-0, 9426, 9426, 0, 276480, 0x976c9e93
-0, 9468, 9468, 0, 276480, 0xe80f87f2
-0, 9510, 9510, 0, 276480, 0xdc2d7c6c
-0, 9551, 9551, 0, 276480, 0xb194656e
-0, 9593, 9593, 0, 276480, 0xf002c5ca
-0, 9635, 9635, 0, 276480, 0x43fc1c64
-0, 9676, 9676, 0, 276480, 0xf62d8581
-0, 9718, 9718, 0, 276480, 0xb243dda5
-0, 9760, 9760, 0, 276480, 0x1700efbb
-0, 9801, 9801, 0, 276480, 0x9ebe6ba2
-0, 9843, 9843, 0, 276480, 0x8f316c66
-0, 9885, 9885, 0, 276480, 0x6348ecf5
-0, 9927, 9927, 0, 276480, 0x34b5b78a
+#tb 0: 32768/785647
+0, 0, 0, 1, 276480, 0x5f7a0d4f
+0, 1, 1, 1, 276480, 0x5f7a0d4f
+0, 2, 2, 1, 276480, 0x5f7a0d4f
+0, 3, 3, 1, 276480, 0x5f7a0d4f
+0, 4, 4, 1, 276480, 0x5f7a0d4f
+0, 5, 5, 1, 276480, 0x5f7a0d4f
+0, 6, 6, 1, 276480, 0x5f7a0d4f
+0, 7, 7, 1, 276480, 0x5f7a0d4f
+0, 8, 8, 1, 276480, 0x5f7a0d4f
+0, 9, 9, 1, 276480, 0x5f7a0d4f
+0, 10, 10, 1, 276480, 0x5f7a0d4f
+0, 11, 11, 1, 276480, 0x5f7a0d4f
+0, 12, 12, 1, 276480, 0x5f7a0d4f
+0, 13, 13, 1, 276480, 0x5f7a0d4f
+0, 14, 14, 1, 276480, 0x5f7a0d4f
+0, 15, 15, 1, 276480, 0x5f7a0d4f
+0, 16, 16, 1, 276480, 0x5f7a0d4f
+0, 17, 17, 1, 276480, 0x5f7a0d4f
+0, 18, 18, 1, 276480, 0x5f7a0d4f
+0, 19, 19, 1, 276480, 0x5f7a0d4f
+0, 20, 20, 1, 276480, 0x5f7a0d4f
+0, 21, 21, 1, 276480, 0x5f7a0d4f
+0, 22, 22, 1, 276480, 0x5f7a0d4f
+0, 23, 23, 1, 276480, 0x5f7a0d4f
+0, 24, 24, 1, 276480, 0x5f7a0d4f
+0, 25, 25, 1, 276480, 0x5f7a0d4f
+0, 26, 26, 1, 276480, 0x5f7a0d4f
+0, 27, 27, 1, 276480, 0x5f7a0d4f
+0, 28, 28, 1, 276480, 0x5f7a0d4f
+0, 29, 29, 1, 276480, 0x5f7a0d4f
+0, 30, 30, 1, 276480, 0x5f7a0d4f
+0, 31, 31, 1, 276480, 0x5f7a0d4f
+0, 32, 32, 1, 276480, 0x5f7a0d4f
+0, 33, 33, 1, 276480, 0x75641594
+0, 34, 34, 1, 276480, 0x32ee3526
+0, 35, 35, 1, 276480, 0xcb53479a
+0, 36, 36, 1, 276480, 0x7ca9658e
+0, 37, 37, 1, 276480, 0x5ce39368
+0, 38, 38, 1, 276480, 0x4ec1e418
+0, 39, 39, 1, 276480, 0xb3790499
+0, 40, 40, 1, 276480, 0xa9f1506f
+0, 41, 41, 1, 276480, 0x85cbc3b5
+0, 42, 42, 1, 276480, 0x377c7b46
+0, 43, 43, 1, 276480, 0x1a61d8db
+0, 44, 44, 1, 276480, 0xe1de7f0a
+0, 45, 45, 1, 276480, 0x756a4a2e
+0, 46, 46, 1, 276480, 0xcb379547
+0, 47, 47, 1, 276480, 0xbae14484
+0, 48, 48, 1, 276480, 0x8e12331c
+0, 49, 49, 1, 276480, 0x99c085be
+0, 50, 50, 1, 276480, 0xe479ffed
+0, 51, 51, 1, 276480, 0x99c82949
+0, 52, 52, 1, 276480, 0xac7672dd
+0, 53, 53, 1, 276480, 0x1e4fae19
+0, 54, 54, 1, 276480, 0x776412ef
+0, 55, 55, 1, 276480, 0x7d9b579f
+0, 56, 56, 1, 276480, 0x1cd1ab29
+0, 57, 57, 1, 276480, 0x58ce0f38
+0, 58, 58, 1, 276480, 0x5ab69b27
+0, 59, 59, 1, 276480, 0x0afad610
+0, 60, 60, 1, 276480, 0x9eca3f11
+0, 61, 61, 1, 276480, 0xc3db9706
+0, 62, 62, 1, 276480, 0xc9c57884
+0, 63, 63, 1, 276480, 0xd9fbb2cf
+0, 64, 64, 1, 276480, 0xdc07f3c9
+0, 65, 65, 1, 276480, 0x000b5269
+0, 66, 66, 1, 276480, 0x27ff7a5d
+0, 67, 67, 1, 276480, 0xd92e2017
+0, 68, 68, 1, 276480, 0x18d4b27d
+0, 69, 69, 1, 276480, 0x70647530
+0, 70, 70, 1, 276480, 0x97612c4b
+0, 71, 71, 1, 276480, 0xc9d4ac78
+0, 72, 72, 1, 276480, 0x4ec4d57f
+0, 73, 73, 1, 276480, 0xdf4e04d7
+0, 74, 74, 1, 276480, 0xbd98f57c
+0, 75, 75, 1, 276480, 0x7247ea3e
+0, 76, 76, 1, 276480, 0xa5d670ec
+0, 77, 77, 1, 276480, 0x5163b29b
+0, 78, 78, 1, 276480, 0x99170e64
+0, 79, 79, 1, 276480, 0x37f4c0b0
+0, 80, 80, 1, 276480, 0x7a4f2561
+0, 81, 81, 1, 276480, 0x8a4e991f
+0, 82, 82, 1, 276480, 0x6a45425f
+0, 83, 83, 1, 276480, 0x1f0e2bb6
+0, 84, 84, 1, 276480, 0xd75482c6
+0, 85, 85, 1, 276480, 0x7bf6b1ef
+0, 86, 86, 1, 276480, 0x6de1e34b
+0, 87, 87, 1, 276480, 0x4526c89b
+0, 88, 88, 1, 276480, 0xf964e18e
+0, 89, 89, 1, 276480, 0xdcaaa99a
+0, 90, 90, 1, 276480, 0xd1e98808
+0, 91, 91, 1, 276480, 0x556b2365
+0, 92, 92, 1, 276480, 0x0cf65540
+0, 93, 93, 1, 276480, 0x6e2d524e
+0, 94, 94, 1, 276480, 0x22c50a3d
+0, 95, 95, 1, 276480, 0x293f19af
+0, 96, 96, 1, 276480, 0xf4b1c461
+0, 97, 97, 1, 276480, 0x62b76407
+0, 98, 98, 1, 276480, 0x51e9b3eb
+0, 99, 99, 1, 276480, 0x7b910bc7
+0, 100, 100, 1, 276480, 0x6dd14ca6
+0, 101, 101, 1, 276480, 0x441f7afd
+0, 102, 102, 1, 276480, 0xfb01efc6
+0, 103, 103, 1, 276480, 0x4f73ccea
+0, 104, 104, 1, 276480, 0x5ac8e06f
+0, 105, 105, 1, 276480, 0x294bb441
+0, 106, 106, 1, 276480, 0xe04ac45e
+0, 107, 107, 1, 276480, 0xa7a38d41
+0, 108, 108, 1, 276480, 0xf688a3ed
+0, 109, 109, 1, 276480, 0x58f275ea
+0, 110, 110, 1, 276480, 0xf0b3b71b
+0, 111, 111, 1, 276480, 0x3ce773bf
+0, 112, 112, 1, 276480, 0x01840548
+0, 113, 113, 1, 276480, 0x674e34e4
+0, 114, 114, 1, 276480, 0x41dda2d9
+0, 115, 115, 1, 276480, 0xc5b60838
+0, 116, 116, 1, 276480, 0x9b209f41
+0, 117, 117, 1, 276480, 0xf46ba7fb
+0, 118, 118, 1, 276480, 0x28b54815
+0, 119, 119, 1, 276480, 0xb605a933
+0, 120, 120, 1, 276480, 0x34484aff
+0, 121, 121, 1, 276480, 0xaf2b5d89
+0, 122, 122, 1, 276480, 0x8facba58
+0, 123, 123, 1, 276480, 0xbbe3e99f
+0, 124, 124, 1, 276480, 0x02162c7c
+0, 125, 125, 1, 276480, 0x28a63236
+0, 126, 126, 1, 276480, 0x1ad43fd7
+0, 127, 127, 1, 276480, 0xe37883e5
+0, 128, 128, 1, 276480, 0x2b8a89c5
+0, 129, 129, 1, 276480, 0x71507bd2
+0, 130, 130, 1, 276480, 0x35626022
+0, 131, 131, 1, 276480, 0x461fc3e7
+0, 132, 132, 1, 276480, 0xce5af1ec
+0, 133, 133, 1, 276480, 0x7c1139b3
+0, 134, 134, 1, 276480, 0x7fd73a99
+0, 135, 135, 1, 276480, 0x4ae4c3a6
+0, 136, 136, 1, 276480, 0xcb60725a
+0, 137, 137, 1, 276480, 0xb52e1aa2
+0, 138, 138, 1, 276480, 0xd6f82cae
+0, 139, 139, 1, 276480, 0x6310e665
+0, 140, 140, 1, 276480, 0xfa88a483
+0, 141, 141, 1, 276480, 0xf88f75d4
+0, 142, 142, 1, 276480, 0x04a8e3ee
+0, 143, 143, 1, 276480, 0x54766a12
+0, 144, 144, 1, 276480, 0x0b41f0d7
+0, 145, 145, 1, 276480, 0xa29f5b01
+0, 146, 146, 1, 276480, 0x754ceaf5
+0, 147, 147, 1, 276480, 0x150c0423
+0, 148, 148, 1, 276480, 0xde084059
+0, 149, 149, 1, 276480, 0x5a38b4af
+0, 150, 150, 1, 276480, 0xfcebc261
+0, 151, 151, 1, 276480, 0x0eb9770d
+0, 152, 152, 1, 276480, 0x046394ae
+0, 153, 153, 1, 276480, 0x3d3ca985
+0, 154, 154, 1, 276480, 0x94a03c75
+0, 155, 155, 1, 276480, 0x800eea2d
+0, 156, 156, 1, 276480, 0x6a841f41
+0, 157, 157, 1, 276480, 0x2f98911c
+0, 158, 158, 1, 276480, 0x923b9937
+0, 159, 159, 1, 276480, 0xe82f8e0f
+0, 160, 160, 1, 276480, 0xee82d657
+0, 161, 161, 1, 276480, 0xefab7ffd
+0, 162, 162, 1, 276480, 0x6b9fbc80
+0, 163, 163, 1, 276480, 0x4a1ada47
+0, 164, 164, 1, 276480, 0x6d4b49d7
+0, 165, 165, 1, 276480, 0xe4bdbd1e
+0, 166, 166, 1, 276480, 0x225a56c0
+0, 167, 167, 1, 276480, 0xd4adadad
+0, 168, 168, 1, 276480, 0xff4e1a8c
+0, 169, 169, 1, 276480, 0xf58b1b7c
+0, 170, 170, 1, 276480, 0xbaffcdcc
+0, 171, 171, 1, 276480, 0x374f88f0
+0, 172, 172, 1, 276480, 0x3d861ae6
+0, 173, 173, 1, 276480, 0xeb6eb88f
+0, 174, 174, 1, 276480, 0xdb753d35
+0, 175, 175, 1, 276480, 0x9aa543af
+0, 176, 176, 1, 276480, 0xb24c8016
+0, 177, 177, 1, 276480, 0xea80a82e
+0, 178, 178, 1, 276480, 0x2aae902a
+0, 179, 179, 1, 276480, 0x5bba3cfb
+0, 180, 180, 1, 276480, 0x5c6e97a9
+0, 181, 181, 1, 276480, 0x9b9ee961
+0, 182, 182, 1, 276480, 0xaa12b6fd
+0, 183, 183, 1, 276480, 0xe9d2439f
+0, 184, 184, 1, 276480, 0xbf09053c
+0, 185, 185, 1, 276480, 0x50c31e73
+0, 186, 186, 1, 276480, 0xdd9fb89f
+0, 187, 187, 1, 276480, 0x3e4e5aec
+0, 188, 188, 1, 276480, 0x0b752d28
+0, 189, 189, 1, 276480, 0xaf82399a
+0, 190, 190, 1, 276480, 0x7ce5f23c
+0, 191, 191, 1, 276480, 0xad135d0f
+0, 192, 192, 1, 276480, 0x55dadd30
+0, 193, 193, 1, 276480, 0x5aaa7519
+0, 194, 194, 1, 276480, 0xe45a5599
+0, 195, 195, 1, 276480, 0xc8e89913
+0, 196, 196, 1, 276480, 0x2f447fd3
+0, 197, 197, 1, 276480, 0x704411fb
+0, 198, 198, 1, 276480, 0x9d7430a1
+0, 199, 199, 1, 276480, 0x24dd5fd3
+0, 200, 200, 1, 276480, 0x51cb657c
+0, 201, 201, 1, 276480, 0x2c230702
+0, 202, 202, 1, 276480, 0x4a4f76cd
+0, 203, 203, 1, 276480, 0xdcd71e88
+0, 204, 204, 1, 276480, 0x87160f99
+0, 205, 205, 1, 276480, 0x27f54854
+0, 206, 206, 1, 276480, 0x694d76e3
+0, 207, 207, 1, 276480, 0xcbe93c19
+0, 208, 208, 1, 276480, 0x50742e1b
+0, 209, 209, 1, 276480, 0x525463e2
+0, 210, 210, 1, 276480, 0x819898f9
+0, 211, 211, 1, 276480, 0x08fac755
+0, 212, 212, 1, 276480, 0x35c46927
+0, 213, 213, 1, 276480, 0xeeed00fc
+0, 214, 214, 1, 276480, 0xb6f99ee3
+0, 215, 215, 1, 276480, 0xd87f4c73
+0, 216, 216, 1, 276480, 0xde97d9fd
+0, 217, 217, 1, 276480, 0xefc83107
+0, 218, 218, 1, 276480, 0xbb22e024
+0, 219, 219, 1, 276480, 0x53a7cfcb
+0, 220, 220, 1, 276480, 0xbe1fbb19
+0, 221, 221, 1, 276480, 0x300f922a
+0, 222, 222, 1, 276480, 0x826fc3bd
+0, 223, 223, 1, 276480, 0x679aa57a
+0, 224, 224, 1, 276480, 0x5497097b
+0, 225, 225, 1, 276480, 0x679a53f8
+0, 226, 226, 1, 276480, 0x976c9e93
+0, 227, 227, 1, 276480, 0xe80f87f2
+0, 228, 228, 1, 276480, 0xdc2d7c6c
+0, 229, 229, 1, 276480, 0xb194656e
+0, 230, 230, 1, 276480, 0xf002c5ca
+0, 231, 231, 1, 276480, 0x43fc1c64
+0, 232, 232, 1, 276480, 0xf62d8581
+0, 233, 233, 1, 276480, 0xb243dda5
+0, 234, 234, 1, 276480, 0x1700efbb
+0, 235, 235, 1, 276480, 0x9ebe6ba2
+0, 236, 236, 1, 276480, 0x8f316c66
+0, 237, 237, 1, 276480, 0x6348ecf5
+0, 238, 238, 1, 276480, 0x34b5b78a
+0, 239, 239, 1, 276480, 0xcbf66922
diff --git a/tests/ref/fate/sanm b/tests/ref/fate/sanm
new file mode 100644
index 0000000..8b6f903
--- /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/smc b/tests/ref/fate/smc
index cdfc3d5..1635b37 100644
--- a/tests/ref/fate/smc
+++ b/tests/ref/fate/smc
@@ -1,121 +1,121 @@
-#tb 0: 1/30
+#tb 0: 1/10
0, 0, 0, 1, 230400, 0xf814fc90
-0, 3, 3, 1, 230400, 0xe1b13137
-0, 6, 6, 1, 230400, 0xa7f4d408
-0, 9, 9, 1, 230400, 0x4b86e1d5
-0, 12, 12, 1, 230400, 0xc663af5a
-0, 15, 15, 1, 230400, 0x943b5757
-0, 18, 18, 1, 230400, 0x0d7ee496
-0, 21, 21, 1, 230400, 0x78792de4
-0, 24, 24, 1, 230400, 0xd102fb8d
-0, 27, 27, 1, 230400, 0xf9006139
-0, 30, 30, 1, 230400, 0x216bd87d
-0, 33, 33, 1, 230400, 0x1e4c902c
-0, 36, 36, 1, 230400, 0x5aaa7742
-0, 39, 39, 1, 230400, 0x48699d93
-0, 42, 42, 1, 230400, 0xd1e22a5c
-0, 45, 45, 1, 230400, 0x18929315
-0, 48, 48, 1, 230400, 0x680dd4d3
-0, 51, 51, 1, 230400, 0x4cdbcbcb
-0, 54, 54, 1, 230400, 0x6f810d98
-0, 57, 57, 1, 230400, 0xb4f68204
-0, 60, 60, 1, 230400, 0xbd3bb19e
-0, 63, 63, 1, 230400, 0xab27b424
-0, 66, 66, 1, 230400, 0xe5dd675d
-0, 69, 69, 1, 230400, 0x811e45a1
-0, 72, 72, 1, 230400, 0x951011f7
-0, 75, 75, 1, 230400, 0x2f1e2b99
-0, 78, 78, 1, 230400, 0x6657c0d6
-0, 81, 81, 1, 230400, 0xfd29177d
-0, 84, 84, 1, 230400, 0x4b4c01d7
-0, 87, 87, 1, 230400, 0x9af286aa
-0, 90, 90, 1, 230400, 0xc4e9b193
-0, 93, 93, 1, 230400, 0x05dc28ec
-0, 96, 96, 1, 230400, 0x68352119
-0, 99, 99, 1, 230400, 0x0b87e79c
-0, 102, 102, 1, 230400, 0x8358b180
-0, 105, 105, 1, 230400, 0x8debbc9d
-0, 108, 108, 1, 230400, 0x961c58ce
-0, 111, 111, 1, 230400, 0xd8a809c8
-0, 114, 114, 1, 230400, 0x5351789d
-0, 117, 117, 1, 230400, 0xa7ca598c
-0, 120, 120, 1, 230400, 0xc5ce1812
-0, 123, 123, 1, 230400, 0x74496550
-0, 126, 126, 1, 230400, 0x326e366e
-0, 129, 129, 1, 230400, 0x27ae9a92
-0, 132, 132, 1, 230400, 0xadbc8794
-0, 135, 135, 1, 230400, 0x7f3587d8
-0, 138, 138, 1, 230400, 0xf0400ca6
-0, 141, 141, 1, 230400, 0x59a5138e
-0, 144, 144, 1, 230400, 0x456d62a5
-0, 147, 147, 1, 230400, 0xf1a5e5f1
-0, 150, 150, 1, 230400, 0x75c712e4
-0, 153, 153, 1, 230400, 0xd160780a
-0, 156, 156, 1, 230400, 0xc6c23cf0
-0, 159, 159, 1, 230400, 0x0339a2ac
-0, 162, 162, 1, 230400, 0x0e27a2e2
-0, 165, 165, 1, 230400, 0x84976300
-0, 168, 168, 1, 230400, 0xb368f3c4
-0, 171, 171, 1, 230400, 0xa5231fb8
-0, 174, 174, 1, 230400, 0x17c036d4
-0, 177, 177, 1, 230400, 0xfc81a2c0
-0, 180, 180, 1, 230400, 0x99faa403
-0, 183, 183, 1, 230400, 0xff59efd3
-0, 186, 186, 1, 230400, 0xcece1d23
-0, 189, 189, 1, 230400, 0x56c785d9
-0, 192, 192, 1, 230400, 0xe5a9f222
-0, 195, 195, 1, 230400, 0xb80946f8
-0, 198, 198, 1, 230400, 0xf6b642c6
-0, 201, 201, 1, 230400, 0x69573aed
-0, 204, 204, 1, 230400, 0xfb69a1fd
-0, 207, 207, 1, 230400, 0x100b47f4
-0, 210, 210, 1, 230400, 0x6edf9543
-0, 213, 213, 1, 230400, 0x11fdf43c
-0, 216, 216, 1, 230400, 0xd143bf2a
-0, 219, 219, 1, 230400, 0x7ca747c4
-0, 222, 222, 1, 230400, 0xd984bd73
-0, 225, 225, 1, 230400, 0xc5477e8d
-0, 228, 228, 1, 230400, 0xf7d58300
-0, 231, 231, 1, 230400, 0x7a1b9463
-0, 234, 234, 1, 230400, 0x47a29342
-0, 237, 237, 1, 230400, 0xdf437f9d
-0, 240, 240, 1, 230400, 0xf836ef5d
-0, 243, 243, 1, 230400, 0xc98937af
-0, 246, 246, 1, 230400, 0x9258695b
-0, 249, 249, 1, 230400, 0xd4fe179c
-0, 252, 252, 1, 230400, 0x35d524d3
-0, 255, 255, 1, 230400, 0xd9ce5484
-0, 258, 258, 1, 230400, 0xdef776ed
-0, 261, 261, 1, 230400, 0x154c4057
-0, 264, 264, 1, 230400, 0xf5c764f1
-0, 267, 267, 1, 230400, 0x41979b13
-0, 270, 270, 1, 230400, 0xae4e83db
-0, 273, 273, 1, 230400, 0x09fc0f83
-0, 276, 276, 1, 230400, 0x60267fdf
-0, 279, 279, 1, 230400, 0xeaafc525
-0, 282, 282, 1, 230400, 0x80cc35e5
-0, 285, 285, 1, 230400, 0xd82c6164
-0, 288, 288, 1, 230400, 0xd68b8111
-0, 291, 291, 1, 230400, 0x96f874a3
-0, 294, 294, 1, 230400, 0x7fc861c4
-0, 297, 297, 1, 230400, 0xb911f310
-0, 300, 300, 1, 230400, 0x35bbf5aa
-0, 303, 303, 1, 230400, 0xa922b683
-0, 306, 306, 1, 230400, 0xbf6ae353
-0, 309, 309, 1, 230400, 0x6bd3984c
-0, 312, 312, 1, 230400, 0xe51768c0
-0, 315, 315, 1, 230400, 0xee691624
-0, 318, 318, 1, 230400, 0xd546fed7
-0, 321, 321, 1, 230400, 0x98d375e6
-0, 324, 324, 1, 230400, 0x3b9ca990
-0, 327, 327, 1, 230400, 0x27128ad1
-0, 330, 330, 1, 230400, 0x2788e38c
-0, 333, 333, 1, 230400, 0xb0cf3381
-0, 336, 336, 1, 230400, 0x4fc86d39
-0, 339, 339, 1, 230400, 0xf5632fff
-0, 342, 342, 1, 230400, 0x7fa1e6c2
-0, 345, 345, 1, 230400, 0xffeef044
-0, 348, 348, 1, 230400, 0x932af385
-0, 351, 351, 1, 230400, 0x76738428
-0, 354, 354, 1, 230400, 0xf6771ba2
-0, 357, 357, 1, 230400, 0x17e2ff27
+0, 1, 1, 1, 230400, 0xe1b13137
+0, 2, 2, 1, 230400, 0xa7f4d408
+0, 3, 3, 1, 230400, 0x4b86e1d5
+0, 4, 4, 1, 230400, 0xc663af5a
+0, 5, 5, 1, 230400, 0x943b5757
+0, 6, 6, 1, 230400, 0x0d7ee496
+0, 7, 7, 1, 230400, 0x78792de4
+0, 8, 8, 1, 230400, 0xd102fb8d
+0, 9, 9, 1, 230400, 0xf9006139
+0, 10, 10, 1, 230400, 0x216bd87d
+0, 11, 11, 1, 230400, 0x1e4c902c
+0, 12, 12, 1, 230400, 0x5aaa7742
+0, 13, 13, 1, 230400, 0x48699d93
+0, 14, 14, 1, 230400, 0xd1e22a5c
+0, 15, 15, 1, 230400, 0x18929315
+0, 16, 16, 1, 230400, 0x680dd4d3
+0, 17, 17, 1, 230400, 0x4cdbcbcb
+0, 18, 18, 1, 230400, 0x6f810d98
+0, 19, 19, 1, 230400, 0xb4f68204
+0, 20, 20, 1, 230400, 0xbd3bb19e
+0, 21, 21, 1, 230400, 0xab27b424
+0, 22, 22, 1, 230400, 0xe5dd675d
+0, 23, 23, 1, 230400, 0x811e45a1
+0, 24, 24, 1, 230400, 0x951011f7
+0, 25, 25, 1, 230400, 0x2f1e2b99
+0, 26, 26, 1, 230400, 0x6657c0d6
+0, 27, 27, 1, 230400, 0xfd29177d
+0, 28, 28, 1, 230400, 0x4b4c01d7
+0, 29, 29, 1, 230400, 0x9af286aa
+0, 30, 30, 1, 230400, 0xc4e9b193
+0, 31, 31, 1, 230400, 0x05dc28ec
+0, 32, 32, 1, 230400, 0x68352119
+0, 33, 33, 1, 230400, 0x0b87e79c
+0, 34, 34, 1, 230400, 0x8358b180
+0, 35, 35, 1, 230400, 0x8debbc9d
+0, 36, 36, 1, 230400, 0x961c58ce
+0, 37, 37, 1, 230400, 0xd8a809c8
+0, 38, 38, 1, 230400, 0x5351789d
+0, 39, 39, 1, 230400, 0xa7ca598c
+0, 40, 40, 1, 230400, 0xc5ce1812
+0, 41, 41, 1, 230400, 0x74496550
+0, 42, 42, 1, 230400, 0x326e366e
+0, 43, 43, 1, 230400, 0x27ae9a92
+0, 44, 44, 1, 230400, 0xadbc8794
+0, 45, 45, 1, 230400, 0x7f3587d8
+0, 46, 46, 1, 230400, 0xf0400ca6
+0, 47, 47, 1, 230400, 0x59a5138e
+0, 48, 48, 1, 230400, 0x456d62a5
+0, 49, 49, 1, 230400, 0xf1a5e5f1
+0, 50, 50, 1, 230400, 0x75c712e4
+0, 51, 51, 1, 230400, 0xd160780a
+0, 52, 52, 1, 230400, 0xc6c23cf0
+0, 53, 53, 1, 230400, 0x0339a2ac
+0, 54, 54, 1, 230400, 0x0e27a2e2
+0, 55, 55, 1, 230400, 0x84976300
+0, 56, 56, 1, 230400, 0xb368f3c4
+0, 57, 57, 1, 230400, 0xa5231fb8
+0, 58, 58, 1, 230400, 0x17c036d4
+0, 59, 59, 1, 230400, 0xfc81a2c0
+0, 60, 60, 1, 230400, 0x99faa403
+0, 61, 61, 1, 230400, 0xff59efd3
+0, 62, 62, 1, 230400, 0xcece1d23
+0, 63, 63, 1, 230400, 0x56c785d9
+0, 64, 64, 1, 230400, 0xe5a9f222
+0, 65, 65, 1, 230400, 0xb80946f8
+0, 66, 66, 1, 230400, 0xf6b642c6
+0, 67, 67, 1, 230400, 0x69573aed
+0, 68, 68, 1, 230400, 0xfb69a1fd
+0, 69, 69, 1, 230400, 0x100b47f4
+0, 70, 70, 1, 230400, 0x6edf9543
+0, 71, 71, 1, 230400, 0x11fdf43c
+0, 72, 72, 1, 230400, 0xd143bf2a
+0, 73, 73, 1, 230400, 0x7ca747c4
+0, 74, 74, 1, 230400, 0xd984bd73
+0, 75, 75, 1, 230400, 0xc5477e8d
+0, 76, 76, 1, 230400, 0xf7d58300
+0, 77, 77, 1, 230400, 0x7a1b9463
+0, 78, 78, 1, 230400, 0x47a29342
+0, 79, 79, 1, 230400, 0xdf437f9d
+0, 80, 80, 1, 230400, 0xf836ef5d
+0, 81, 81, 1, 230400, 0xc98937af
+0, 82, 82, 1, 230400, 0x9258695b
+0, 83, 83, 1, 230400, 0xd4fe179c
+0, 84, 84, 1, 230400, 0x35d524d3
+0, 85, 85, 1, 230400, 0xd9ce5484
+0, 86, 86, 1, 230400, 0xdef776ed
+0, 87, 87, 1, 230400, 0x154c4057
+0, 88, 88, 1, 230400, 0xf5c764f1
+0, 89, 89, 1, 230400, 0x41979b13
+0, 90, 90, 1, 230400, 0xae4e83db
+0, 91, 91, 1, 230400, 0x09fc0f83
+0, 92, 92, 1, 230400, 0x60267fdf
+0, 93, 93, 1, 230400, 0xeaafc525
+0, 94, 94, 1, 230400, 0x80cc35e5
+0, 95, 95, 1, 230400, 0xd82c6164
+0, 96, 96, 1, 230400, 0xd68b8111
+0, 97, 97, 1, 230400, 0x96f874a3
+0, 98, 98, 1, 230400, 0x7fc861c4
+0, 99, 99, 1, 230400, 0xb911f310
+0, 100, 100, 1, 230400, 0x35bbf5aa
+0, 101, 101, 1, 230400, 0xa922b683
+0, 102, 102, 1, 230400, 0xbf6ae353
+0, 103, 103, 1, 230400, 0x6bd3984c
+0, 104, 104, 1, 230400, 0xe51768c0
+0, 105, 105, 1, 230400, 0xee691624
+0, 106, 106, 1, 230400, 0xd546fed7
+0, 107, 107, 1, 230400, 0x98d375e6
+0, 108, 108, 1, 230400, 0x3b9ca990
+0, 109, 109, 1, 230400, 0x27128ad1
+0, 110, 110, 1, 230400, 0x2788e38c
+0, 111, 111, 1, 230400, 0xb0cf3381
+0, 112, 112, 1, 230400, 0x4fc86d39
+0, 113, 113, 1, 230400, 0xf5632fff
+0, 114, 114, 1, 230400, 0x7fa1e6c2
+0, 115, 115, 1, 230400, 0xffeef044
+0, 116, 116, 1, 230400, 0x932af385
+0, 117, 117, 1, 230400, 0x76738428
+0, 118, 118, 1, 230400, 0xf6771ba2
+0, 119, 119, 1, 230400, 0x17e2ff27
diff --git a/tests/ref/fate/smjpeg b/tests/ref/fate/smjpeg
new file mode 100644
index 0000000..7aac52f
--- /dev/null
+++ b/tests/ref/fate/smjpeg
@@ -0,0 +1,425 @@
+#tb 0: 1/1000
+#tb 1: 1/22050
+0, 0, 0, 0, 734, 0x5a042c2c
+1, 0, 0, 512, 1024, 0x00000000
+1, 507, 507, 512, 1024, 0x00000000
+1, 1014, 1014, 512, 1024, 0xd89a448e
+1, 1521, 1521, 512, 1024, 0x695b369c
+1, 2029, 2029, 512, 1024, 0xc8ba5707
+0, 111, 111, 0, 763, 0xb5893f2f
+1, 2558, 2558, 512, 1024, 0xdf241fc6
+1, 3065, 3065, 512, 1024, 0x61cf4166
+1, 3572, 3572, 512, 1024, 0x97cbc386
+1, 4079, 4079, 512, 1024, 0x44899d04
+1, 4586, 4586, 512, 1024, 0xa7cbaa62
+0, 222, 222, 0, 3023, 0x0f3907d3
+1, 5116, 5116, 512, 1024, 0xa7aea60c
+1, 5623, 5623, 512, 1024, 0xd7b18a89
+1, 6130, 6130, 512, 1024, 0x268e81f6
+1, 6637, 6637, 512, 1024, 0x9cf83a2f
+1, 7166, 7166, 512, 1024, 0x5559b508
+0, 333, 333, 0, 4800, 0x22e6e18a
+1, 7673, 7673, 512, 1024, 0xe1b9e71c
+1, 8181, 8181, 512, 1024, 0xdcee733e
+1, 8688, 8688, 512, 1024, 0xe5918f60
+1, 9195, 9195, 512, 1024, 0x29dbd209
+1, 9724, 9724, 512, 1024, 0x9bcbcf16
+0, 444, 444, 0, 6417, 0x427adde5
+1, 10231, 10231, 512, 1024, 0x86f5f458
+1, 10738, 10738, 512, 1024, 0xabcbda86
+1, 11246, 11246, 512, 1024, 0xc51f77b9
+1, 11775, 11775, 512, 1024, 0xf6b3a504
+0, 555, 555, 0, 6776, 0x7a74c6ad
+1, 12282, 12282, 512, 1024, 0x1af3e40e
+1, 12789, 12789, 512, 1024, 0x3866b03b
+1, 13296, 13296, 512, 1024, 0xbc005403
+1, 13803, 13803, 512, 1024, 0xe9dfcc51
+1, 14333, 14333, 512, 1024, 0x83c837cb
+0, 666, 666, 0, 6808, 0x1f6eb7c3
+1, 14840, 14840, 512, 1024, 0xfa649580
+1, 15347, 15347, 512, 1024, 0x519452ea
+1, 15854, 15854, 512, 1024, 0xd4978774
+1, 16383, 16383, 512, 1024, 0xe2a3b1cd
+1, 16890, 16890, 512, 1024, 0x9a9472ad
+0, 777, 777, 0, 6726, 0x452087e6
+1, 17397, 17397, 512, 1024, 0xa12d4060
+1, 17905, 17905, 512, 1024, 0x31fb0646
+1, 18412, 18412, 512, 1024, 0xfc44343f
+1, 18941, 18941, 512, 1024, 0x0847751a
+1, 19448, 19448, 512, 1024, 0x227968a2
+0, 888, 888, 0, 6829, 0xee82b109
+1, 19955, 19955, 512, 1024, 0x7cce9f1c
+1, 20462, 20462, 512, 1024, 0xb8356713
+1, 20992, 20992, 512, 1024, 0xb29f6e6f
+1, 21499, 21499, 512, 1024, 0x9e1430ab
+1, 22006, 22006, 512, 1024, 0x26d85423
+0, 999, 999, 0, 7055, 0xf41f1108
+1, 22513, 22513, 512, 1024, 0x6496547d
+1, 23020, 23020, 512, 1024, 0x316b1a86
+1, 23549, 23549, 512, 1024, 0x3cd83afc
+1, 24057, 24057, 512, 1024, 0x993ff633
+0, 1111, 1111, 0, 6977, 0xf8fe1ede
+1, 24564, 24564, 512, 1024, 0x0708d1a2
+1, 25071, 25071, 512, 1024, 0xd7230db9
+1, 25578, 25578, 512, 1024, 0xbb0779ca
+1, 26107, 26107, 512, 1024, 0xc6094e1b
+1, 26614, 26614, 512, 1024, 0x15a8b039
+0, 1222, 1222, 0, 6942, 0x9ad105c6
+1, 27122, 27122, 512, 1024, 0xd6dbe88c
+1, 27629, 27629, 512, 1024, 0x7e8d1140
+1, 28158, 28158, 512, 1024, 0xef88e525
+1, 28665, 28665, 512, 1024, 0x44e21149
+1, 29172, 29172, 512, 1024, 0x65b0f5f4
+0, 1333, 1333, 0, 6926, 0xe239dad6
+1, 29679, 29679, 512, 1024, 0xb955f687
+1, 30186, 30186, 512, 1024, 0xc85fba9c
+1, 30716, 30716, 512, 1024, 0xf59655ad
+1, 31223, 31223, 512, 1024, 0x6de80bf1
+1, 31730, 31730, 512, 1024, 0x2dcf6e41
+0, 1444, 1444, 0, 6966, 0x81dcfab1
+1, 32237, 32237, 512, 1024, 0xd0ddcf8a
+1, 32766, 32766, 512, 1024, 0x00135c2d
+1, 33273, 33273, 512, 1024, 0x697f8efd
+1, 33781, 33781, 512, 1024, 0x7a9bada5
+0, 1555, 1555, 0, 6896, 0x31e6cc02
+1, 34288, 34288, 512, 1024, 0x0d22783c
+1, 34795, 34795, 512, 1024, 0x7726d07d
+1, 35324, 35324, 512, 1024, 0xa2f14f67
+1, 35831, 35831, 512, 1024, 0x7f51060d
+1, 36338, 36338, 512, 1024, 0xc4ec6aea
+0, 1666, 1666, 0, 6889, 0x1cc1006e
+1, 36846, 36846, 512, 1024, 0x9bb37ca4
+1, 37375, 37375, 512, 1024, 0x9b085577
+1, 37882, 37882, 512, 1024, 0x8812f8af
+1, 38389, 38389, 512, 1024, 0x788f5221
+1, 38896, 38896, 512, 1024, 0x3a2ce642
+0, 1777, 1777, 0, 6933, 0xc303f87f
+1, 39403, 39403, 512, 1024, 0x72415692
+1, 39933, 39933, 512, 1024, 0xe3dcc105
+1, 40440, 40440, 512, 1024, 0xb26c0599
+1, 40947, 40947, 512, 1024, 0x5c9e55eb
+1, 41454, 41454, 512, 1024, 0x8fe88707
+0, 1888, 1888, 0, 7034, 0xb4970a20
+1, 41983, 41983, 512, 1024, 0xc5d7beb6
+1, 42490, 42490, 512, 1024, 0xe1d3a3b4
+1, 42998, 42998, 512, 1024, 0x012da0c6
+1, 43505, 43505, 512, 1024, 0x8d010922
+1, 44012, 44012, 512, 1024, 0x3366eb0d
+0, 1999, 1999, 0, 6961, 0xf064095d
+1, 44541, 44541, 512, 1024, 0xc9381a27
+1, 45048, 45048, 512, 1024, 0x0774f685
+1, 45555, 45555, 512, 1024, 0xc5cae0a5
+1, 46062, 46062, 512, 1024, 0xa6f4737c
+0, 2111, 2111, 0, 7089, 0x5ba350f9
+1, 46592, 46592, 512, 1024, 0x8fb6d0d1
+1, 47099, 47099, 512, 1024, 0x05f579c2
+1, 47606, 47606, 512, 1024, 0x56905d99
+1, 48113, 48113, 512, 1024, 0x002ee18d
+1, 48620, 48620, 512, 1024, 0xeb37ef51
+0, 2222, 2222, 0, 7078, 0xa83f3e88
+1, 49149, 49149, 512, 1024, 0x38025635
+1, 49657, 49657, 512, 1024, 0x4fe643c8
+1, 50164, 50164, 512, 1024, 0x11d66ab1
+1, 50671, 50671, 512, 1024, 0xcc3051e9
+1, 51178, 51178, 512, 1024, 0xcd93e854
+0, 2333, 2333, 0, 7147, 0xcda66cfc
+1, 51707, 51707, 512, 1024, 0x38f1196d
+1, 52214, 52214, 512, 1024, 0x657a15fc
+1, 52722, 52722, 512, 1024, 0x669ce2a9
+1, 53229, 53229, 512, 1024, 0x95862dda
+1, 53758, 53758, 512, 1024, 0x1726a7b2
+0, 2444, 2444, 0, 7173, 0xb7455859
+1, 54265, 54265, 512, 1024, 0xd6ece2a1
+1, 54772, 54772, 512, 1024, 0x33ab9553
+1, 55279, 55279, 512, 1024, 0xd50c73a6
+1, 55787, 55787, 512, 1024, 0xfe25b63a
+1, 56316, 56316, 512, 1024, 0x7e2959e3
+0, 2555, 2555, 0, 7213, 0x97b89994
+1, 56823, 56823, 512, 1024, 0xa4c07b34
+1, 57330, 57330, 512, 1024, 0xd6d8f15c
+1, 57837, 57837, 512, 1024, 0x1eccddd7
+1, 58366, 58366, 512, 1024, 0x2b69f9cb
+0, 2666, 2666, 0, 7170, 0xca8b2948
+1, 58874, 58874, 512, 1024, 0x667b775f
+1, 59381, 59381, 512, 1024, 0xad3b84e9
+1, 59888, 59888, 512, 1024, 0x4f29fc67
+1, 60395, 60395, 512, 1024, 0x8d611ab7
+1, 60924, 60924, 512, 1024, 0x278966ea
+0, 2777, 2777, 0, 7174, 0xc7cc6bbb
+1, 61431, 61431, 512, 1024, 0xaf33812b
+1, 61938, 61938, 512, 1024, 0xa55f4265
+1, 62446, 62446, 512, 1024, 0x023cb51c
+1, 62975, 62975, 512, 1024, 0x1d1f1005
+1, 63482, 63482, 512, 1024, 0x874cccf7
+0, 2888, 2888, 0, 7235, 0xc2e68d2b
+1, 63989, 63989, 512, 1024, 0xda705428
+1, 64496, 64496, 512, 1024, 0x48d9b440
+1, 65003, 65003, 512, 1024, 0xa14e0712
+1, 65533, 65533, 512, 1024, 0x7efbad1f
+1, 66040, 66040, 512, 1024, 0xdb82c17f
+0, 3000, 3000, 0, 7261, 0x8204a423
+1, 66547, 66547, 512, 1024, 0xcbe87613
+1, 67054, 67054, 512, 1024, 0x3a63df1d
+1, 67583, 67583, 512, 1024, 0xd5636bba
+1, 68090, 68090, 512, 1024, 0x9397af23
+0, 3111, 3111, 0, 7353, 0xacc7e7c0
+1, 68598, 68598, 512, 1024, 0x32a07c98
+1, 69105, 69105, 512, 1024, 0x202ca667
+1, 69612, 69612, 512, 1024, 0xdf969011
+1, 70141, 70141, 512, 1024, 0xc434d238
+1, 70648, 70648, 512, 1024, 0xe9ad7562
+0, 3222, 3222, 0, 7065, 0x45035c5c
+1, 71155, 71155, 512, 1024, 0xb51b6b50
+1, 71663, 71663, 512, 1024, 0xe70aecd3
+1, 72192, 72192, 512, 1024, 0x03c816b2
+1, 72699, 72699, 512, 1024, 0x869fdf25
+1, 73206, 73206, 512, 1024, 0xd40a0a62
+0, 3333, 3333, 0, 7269, 0x72edbb76
+1, 73713, 73713, 512, 1024, 0x5af7dd35
+1, 74220, 74220, 512, 1024, 0x891ffc72
+1, 74750, 74750, 512, 1024, 0x1ff68a08
+1, 75257, 75257, 512, 1024, 0x5a7517a9
+1, 75764, 75764, 512, 1024, 0x0f959f74
+0, 3444, 3444, 0, 7220, 0xb926772f
+1, 76271, 76271, 512, 1024, 0xe92a12a2
+1, 76778, 76778, 512, 1024, 0x38000e55
+1, 77307, 77307, 512, 1024, 0x39fbdd70
+1, 77814, 77814, 512, 1024, 0xca3d9184
+1, 78322, 78322, 512, 1024, 0x66c8995b
+0, 3555, 3555, 0, 7326, 0x0a66c632
+1, 78829, 78829, 512, 1024, 0xac25acea
+1, 79358, 79358, 512, 1024, 0x3cd1046c
+1, 79865, 79865, 512, 1024, 0x6a1df31c
+1, 80372, 80372, 512, 1024, 0x21ca10a1
+0, 3666, 3666, 0, 7225, 0xe39076ab
+1, 80879, 80879, 512, 1024, 0x1aeccedc
+1, 81387, 81387, 512, 1024, 0xddea1335
+1, 81916, 81916, 512, 1024, 0x19f5ca9f
+1, 82423, 82423, 512, 1024, 0x88e95e43
+1, 82930, 82930, 512, 1024, 0x726284fe
+0, 3777, 3777, 0, 7265, 0xe0209036
+1, 83437, 83437, 512, 1024, 0x6b85b40e
+1, 83966, 83966, 512, 1024, 0x111fee2a
+1, 84474, 84474, 512, 1024, 0x3656b588
+1, 84981, 84981, 512, 1024, 0xa5a2b552
+1, 85488, 85488, 512, 1024, 0x38fb2467
+0, 3888, 3888, 0, 7337, 0x7a5dc093
+1, 85995, 85995, 512, 1024, 0xaa919ccc
+1, 86524, 86524, 512, 1024, 0x15993dbc
+1, 87031, 87031, 512, 1024, 0xbe01a7b9
+1, 87539, 87539, 512, 1024, 0xefe93c09
+1, 88046, 88046, 512, 1024, 0x1bb566e5
+0, 4000, 4000, 0, 7246, 0x519a7a3c
+1, 88575, 88575, 512, 1024, 0x15ce6237
+1, 89082, 89082, 512, 1024, 0xa8552e66
+1, 89589, 89589, 512, 1024, 0x9d80187e
+1, 90096, 90096, 512, 1024, 0x5df3fc30
+1, 90603, 90603, 512, 1024, 0x1a312aa5
+0, 4111, 4111, 0, 7266, 0x352c8078
+1, 91133, 91133, 512, 1024, 0x6bb8e302
+1, 91640, 91640, 512, 1024, 0xbd9684bb
+1, 92147, 92147, 512, 1024, 0x78b0b166
+1, 92654, 92654, 512, 1024, 0xd9af5eae
+0, 4222, 4222, 0, 7323, 0xcaf69d7c
+1, 93183, 93183, 512, 1024, 0xdb90fe82
+1, 93690, 93690, 512, 1024, 0x327614e9
+1, 94198, 94198, 512, 1024, 0x1f19b7fe
+1, 94705, 94705, 512, 1024, 0x46c53f96
+1, 95212, 95212, 512, 1024, 0x921b2189
+0, 4333, 4333, 0, 7309, 0x98c1e6f7
+1, 95741, 95741, 512, 1024, 0xa8fbc85a
+1, 96248, 96248, 512, 1024, 0xabfdaaae
+1, 96755, 96755, 512, 1024, 0x6acc7387
+1, 97263, 97263, 512, 1024, 0x0d9c27b5
+1, 97792, 97792, 512, 1024, 0xba4dd809
+0, 4444, 4444, 0, 7121, 0x913d5bd6
+1, 98299, 98299, 512, 1024, 0x2a2ad521
+1, 98806, 98806, 512, 1024, 0x892de38a
+1, 99313, 99313, 512, 1024, 0xdc97a2eb
+1, 99820, 99820, 512, 1024, 0x4f614ca4
+1, 100350, 100350, 512, 1024, 0x9c8a77ea
+0, 4555, 4555, 111, 7088, 0x56302362
+1, 100857, 100857, 512, 1024, 0x2d30e646
+1, 101364, 101364, 512, 1024, 0x74e800a7
+1, 101871, 101871, 512, 1024, 0x1e01fb02
+1, 102378, 102378, 512, 1024, 0x4ed2c1d8
+0, 4666, 4666, 111, 7104, 0xc0d14f78
+1, 102907, 102907, 512, 1024, 0xf2fdbe63
+1, 103415, 103415, 512, 1024, 0x8d6f63a1
+1, 103922, 103922, 512, 1024, 0xded468d9
+1, 104429, 104429, 512, 1024, 0xccad839e
+1, 104958, 104958, 512, 1024, 0xdde7c082
+0, 4777, 4777, 111, 7169, 0xd03c825b
+1, 105465, 105465, 512, 1024, 0x548613c5
+1, 105972, 105972, 512, 1024, 0x383909bd
+1, 106479, 106479, 512, 1024, 0xfd37627b
+1, 106987, 106987, 512, 1024, 0x6d95a481
+1, 107516, 107516, 512, 1024, 0x56aa87fa
+0, 4888, 4888, 111, 7038, 0x1ecc201d
+1, 108023, 108023, 512, 1024, 0x7b67258c
+1, 108530, 108530, 512, 1024, 0x7dd99a92
+1, 109037, 109037, 512, 1024, 0x4a66d102
+1, 109566, 109566, 512, 1024, 0x7b3fce51
+1, 110074, 110074, 512, 1024, 0xbbd968aa
+0, 5000, 5000, 111, 7015, 0x83c94454
+1, 110581, 110581, 512, 1024, 0x8283ec36
+1, 111088, 111088, 512, 1024, 0x3c96493d
+1, 111595, 111595, 512, 1024, 0xfa4f8cf8
+1, 112124, 112124, 512, 1024, 0xe2cf872d
+1, 112631, 112631, 512, 1024, 0x0a9e7aa6
+0, 5111, 5111, 111, 6983, 0x9e51f54d
+1, 113139, 113139, 512, 1024, 0x6e7a0550
+1, 113646, 113646, 512, 1024, 0x3acfea2f
+1, 114175, 114175, 512, 1024, 0x7111d0fa
+1, 114682, 114682, 512, 1024, 0xe9a1eca9
+0, 5222, 5222, 111, 7088, 0x70d33de1
+1, 115189, 115189, 512, 1024, 0x24da6c46
+1, 115696, 115696, 512, 1024, 0x117cff37
+1, 116204, 116204, 512, 1024, 0x0f27cab6
+1, 116733, 116733, 512, 1024, 0x69b6b4e6
+1, 117240, 117240, 512, 1024, 0x1e6cc841
+0, 5333, 5333, 111, 7096, 0x4d0f81b5
+1, 117747, 117747, 512, 1024, 0xb01e2365
+1, 118254, 118254, 512, 1024, 0x14e200d3
+1, 118783, 118783, 512, 1024, 0xd1184c98
+1, 119291, 119291, 512, 1024, 0xef9140e9
+1, 119798, 119798, 512, 1024, 0x4cbb645e
+0, 5444, 5444, 111, 7106, 0xd1a83ddc
+1, 120305, 120305, 512, 1024, 0xe7fe2f06
+1, 120812, 120812, 512, 1024, 0xf8c45028
+1, 121341, 121341, 512, 1024, 0x561358f4
+1, 121848, 121848, 512, 1024, 0xd0129b77
+1, 122355, 122355, 512, 1024, 0xcc636e88
+0, 5555, 5555, 111, 7219, 0x20f47fe4
+1, 122863, 122863, 512, 1024, 0xe9406321
+1, 123392, 123392, 512, 1024, 0x9f16a041
+1, 123899, 123899, 512, 1024, 0x468bf409
+1, 124406, 124406, 512, 1024, 0x3df70f7b
+1, 124913, 124913, 512, 1024, 0xa880b11b
+0, 5666, 5666, 111, 7184, 0x45dc6a0e
+1, 125420, 125420, 512, 1024, 0x3286c489
+1, 125950, 125950, 512, 1024, 0x39fe9ebc
+1, 126457, 126457, 512, 1024, 0xc533d83b
+1, 126964, 126964, 512, 1024, 0x153b195d
+0, 5777, 5777, 111, 7222, 0x488c6499
+1, 127471, 127471, 512, 1024, 0xd84786a1
+1, 127978, 127978, 512, 1024, 0xdc295aaa
+1, 128507, 128507, 512, 1024, 0xfb764d8c
+1, 129015, 129015, 512, 1024, 0xeebc9db9
+1, 129522, 129522, 512, 1024, 0x7ba9403e
+0, 5888, 5888, 111, 7254, 0xbd097ba7
+1, 130029, 130029, 512, 1024, 0x4e5571ec
+1, 130558, 130558, 512, 1024, 0xd965fad4
+1, 131065, 131065, 512, 1024, 0x87e259f2
+1, 131572, 131572, 512, 1024, 0xae7e533b
+1, 132080, 132080, 512, 1024, 0x313cf4d6
+0, 6000, 6000, 111, 7189, 0x46e06d43
+1, 132587, 132587, 512, 1024, 0xe1844c90
+1, 133116, 133116, 512, 1024, 0xbb057b44
+1, 133623, 133623, 512, 1024, 0xa5099687
+1, 134130, 134130, 512, 1024, 0xbff10707
+1, 134637, 134637, 512, 1024, 0x37c4ffc0
+0, 6111, 6111, 111, 7283, 0x19dd7319
+1, 135167, 135167, 512, 1024, 0xf9fb6caa
+1, 135674, 135674, 512, 1024, 0x3b6a3a1f
+1, 136181, 136181, 512, 1024, 0x83431edb
+1, 136688, 136688, 512, 1024, 0x1eb713cf
+1, 137195, 137195, 512, 1024, 0xd7b07a6d
+0, 6222, 6222, 111, 7161, 0x23171d02
+1, 137724, 137724, 512, 1024, 0x81ae3391
+1, 138231, 138231, 512, 1024, 0xf150130a
+1, 138739, 138739, 512, 1024, 0x09678eaa
+1, 139246, 139246, 512, 1024, 0xb94e06f1
+0, 6333, 6333, 111, 6976, 0xcc610c26
+1, 139775, 139775, 512, 1024, 0x67b1dbc9
+1, 140282, 140282, 512, 1024, 0xd6edc235
+1, 140789, 140789, 512, 1024, 0x34e4c499
+1, 141296, 141296, 512, 1024, 0xeefd89c0
+1, 141804, 141804, 512, 1024, 0x38afdaf1
+0, 6444, 6444, 111, 7056, 0x6cd917b0
+1, 142333, 142333, 512, 1024, 0x29a60d76
+1, 142840, 142840, 512, 1024, 0xe28a4372
+1, 143347, 143347, 512, 1024, 0x7089454d
+1, 143854, 143854, 512, 1024, 0x0c01bb7b
+1, 144383, 144383, 512, 1024, 0xbd776a72
+0, 6555, 6555, 111, 6736, 0x02b78951
+1, 144891, 144891, 512, 1024, 0x86776fd0
+1, 145398, 145398, 512, 1024, 0xb37c88f7
+1, 145905, 145905, 512, 1024, 0x5f90aaf8
+1, 146412, 146412, 512, 1024, 0x203d4222
+1, 146941, 146941, 512, 1024, 0x382692a6
+0, 6666, 6666, 111, 6540, 0x767e0854
+1, 147448, 147448, 512, 1024, 0xf37c95fd
+1, 147956, 147956, 512, 1024, 0x6c0b8877
+1, 148463, 148463, 512, 1024, 0x2e54a8b6
+1, 148992, 148992, 512, 1024, 0x7f266488
+0, 6777, 6777, 111, 6170, 0xc84962fb
+1, 149499, 149499, 512, 1024, 0xfbf20f9a
+1, 150006, 150006, 512, 1024, 0xf2985cc0
+1, 150513, 150513, 512, 1024, 0xc7075340
+1, 151020, 151020, 512, 1024, 0xe4585695
+1, 151550, 151550, 512, 1024, 0xbdffa380
+0, 6888, 6888, 111, 6169, 0x27e06c03
+1, 152057, 152057, 512, 1024, 0x2422a8a9
+1, 152564, 152564, 512, 1024, 0x59cbd75f
+1, 153071, 153071, 512, 1024, 0x04ad1a8c
+1, 153578, 153578, 512, 1024, 0x33c09191
+1, 154107, 154107, 512, 1024, 0x55efa6fd
+0, 7000, 7000, 111, 5864, 0xd14db83f
+1, 154615, 154615, 512, 1024, 0xf73d0e5d
+1, 155122, 155122, 512, 1024, 0x6141ebae
+1, 155629, 155629, 512, 1024, 0x7db17a68
+1, 156158, 156158, 512, 1024, 0xa6c690b6
+1, 156665, 156665, 512, 1024, 0xa6fd6725
+0, 7111, 7111, 111, 5375, 0x4a21055d
+1, 157172, 157172, 512, 1024, 0x50a90b9b
+1, 157680, 157680, 512, 1024, 0xef990dc8
+1, 158187, 158187, 512, 1024, 0x75adf6b5
+1, 158716, 158716, 512, 1024, 0x61eac43e
+1, 159223, 159223, 512, 1024, 0x67797a19
+0, 7222, 7222, 111, 5206, 0x95ead3cb
+1, 159730, 159730, 512, 1024, 0xf325277a
+1, 160237, 160237, 512, 1024, 0x18bf254a
+1, 160767, 160767, 512, 1024, 0x2ce6bee3
+1, 161274, 161274, 512, 1024, 0x8d320860
+0, 7333, 7333, 111, 5220, 0xcfdcc37e
+1, 161781, 161781, 512, 1024, 0xc979b6e8
+1, 162288, 162288, 512, 1024, 0xdb644b41
+1, 162795, 162795, 512, 1024, 0xe1b368ba
+1, 163324, 163324, 512, 1024, 0xacc53d15
+1, 163832, 163832, 512, 1024, 0x42ea8c18
+0, 7444, 7444, 111, 4946, 0x2d864a77
+1, 164339, 164339, 512, 1024, 0xe52c99a4
+1, 164846, 164846, 512, 1024, 0xd7db54a6
+1, 165375, 165375, 512, 1024, 0x7f27a7e3
+1, 165882, 165882, 512, 1024, 0xf7ffeaa9
+1, 166389, 166389, 512, 1024, 0x792b6088
+0, 7555, 7555, 111, 4390, 0x2ab9f462
+1, 166896, 166896, 512, 1024, 0x61d99724
+1, 167404, 167404, 512, 1024, 0x5213720e
+1, 167933, 167933, 512, 1024, 0xac09dd30
+1, 168440, 168440, 512, 1024, 0x960bf6bb
+1, 168947, 168947, 512, 1024, 0xc90168e1
+0, 7666, 7666, 111, 4051, 0x1d09592e
+1, 169454, 169454, 512, 1024, 0x43b45768
+1, 169983, 169983, 512, 1024, 0x935d60a1
+1, 170491, 170491, 512, 1024, 0x9a342ef2
+1, 170998, 170998, 512, 1024, 0xc894709f
+0, 7777, 7777, 111, 3680, 0x39bd6a12
+1, 171505, 171505, 512, 1024, 0x59b43b07
+1, 172012, 172012, 512, 1024, 0x36a1a98d
+1, 172541, 172541, 512, 1024, 0x9e1a121c
+1, 173048, 173048, 512, 1024, 0x02208b78
+1, 173556, 173556, 512, 1024, 0xd1d7b274
+0, 7888, 7888, 111, 2910, 0x6337ece9
+1, 174063, 174063, 512, 1024, 0xdacd5096
+1, 174592, 174592, 512, 1024, 0x51b71ead
+1, 175099, 175099, 512, 1024, 0xd009a7ca
+1, 175606, 175606, 512, 1024, 0xb6d5a938
+1, 176113, 176113, 512, 1024, 0xf3d45e47
+0, 8000, 8000, 111, 2153, 0xf4e3bc17
+1, 176621, 176621, 512, 1024, 0xea8e04fc
+1, 177150, 177150, 512, 1024, 0x0b928bd8
+1, 177657, 177657, 512, 1024, 0x0f02caec
+1, 178164, 178164, 512, 1024, 0xe2b137a8
+1, 178671, 178671, 512, 1024, 0xd5f94892
diff --git a/tests/ref/fate/smjpeg-demux b/tests/ref/fate/smjpeg-demux
index 4fcd614..637f28c 100644
--- a/tests/ref/fate/smjpeg-demux
+++ b/tests/ref/fate/smjpeg-demux
@@ -232,7 +232,7 @@
1, 4388, 4388, 23, 260, 0x06ad6a93
1, 4411, 4411, 23, 260, 0xdd1b6c91
1, 4435, 4435, 23, 260, 0x05b94d27
-0, 4444, 4444, 111, 7121, 0x913d5bd6
+0, 4444, 4444, 0, 7121, 0x913d5bd6
1, 4458, 4458, 23, 260, 0x12cc5062
1, 4481, 4481, 23, 260, 0x44526d0f
1, 4504, 4504, 23, 260, 0xf2ac6d95
diff --git a/tests/ref/fate/sub-aqtitle b/tests/ref/fate/sub-aqtitle
new file mode 100644
index 0000000..c477b0a
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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..8f97497
--- /dev/null
+++ b/tests/ref/fate/sub-movtextenc
@@ -0,0 +1 @@
+0435265a76ab2f6e66627089d76845f4
diff --git a/tests/ref/fate/sub-mpl2 b/tests/ref/fate/sub-mpl2
new file mode 100644
index 0000000..8835dd2
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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..f866c21
--- /dev/null
+++ b/tests/ref/fate/sub2video
@@ -0,0 +1,94 @@
+#tb 0: 1/5
+#tb 1: 1/1000
+0, 0, 0, 1, 518400, 0x46c47f38
+0, 1, 1, 1, 518400, 0xa814ca60
+0, 2, 2, 1, 518400, 0xa771e1af
+1, 499, 499, 4960, 1015, 0x19e092d2, F=0x0
+0, 3, 3, 1, 518400, 0x267abb76
+0, 4, 4, 1, 518400, 0x184ca91f
+0, 5, 5, 1, 518400, 0xc348bfee
+0, 6, 6, 1, 518400, 0x80451196
+0, 7, 7, 1, 518400, 0xfeb1781b
+0, 8, 8, 1, 518400, 0xa7e1b76c
+0, 9, 9, 1, 518400, 0x1fa10b77
+0, 10, 10, 1, 518400, 0xbbeaa20e
+0, 11, 11, 1, 518400, 0x5b5ba97f
+0, 12, 12, 1, 518400, 0xe189fbdd
+0, 13, 13, 1, 518400, 0xe143a932
+0, 14, 14, 1, 518400, 0x13f18190
+0, 15, 15, 1, 518400, 0x7eed3662
+0, 16, 16, 1, 518400, 0x2c79137b
+0, 17, 17, 1, 518400, 0xe08c0c5b
+0, 18, 18, 1, 518400, 0x87b62f9d
+0, 19, 19, 1, 518400, 0xe93d71ae
+0, 20, 20, 1, 518400, 0x3038eca5
+0, 21, 21, 1, 518400, 0xd77054bb
+0, 22, 22, 1, 518400, 0x077ca600
+0, 23, 23, 1, 518400, 0xf0ceba79
+0, 24, 24, 1, 518400, 0x4acb661d
+0, 25, 25, 1, 518400, 0xc28ae50a
+0, 26, 26, 1, 518400, 0xa5381dd1
+0, 27, 27, 1, 518400, 0x259f15e5
+0, 28, 28, 1, 518400, 0xe1487038
+0, 29, 29, 1, 518400, 0x7b5e5ec3
+0, 30, 30, 1, 518400, 0x6b638cee
+0, 31, 31, 1, 518400, 0x791da218
+0, 32, 32, 1, 518400, 0xd1e4980c
+0, 33, 33, 1, 518400, 0xce9aa6f8
+0, 34, 34, 1, 518400, 0x9abe6cac
+0, 35, 35, 1, 518400, 0xb472272a
+0, 36, 36, 1, 518400, 0x730bfc44
+0, 37, 37, 1, 518400, 0xf3e0b969
+0, 38, 38, 1, 518400, 0x96a77064
+0, 39, 39, 1, 518400, 0x16e94bf0
+0, 40, 40, 1, 518400, 0x0ba93871
+0, 41, 41, 1, 518400, 0x5e004779
+0, 42, 42, 1, 518400, 0xc87864d5
+0, 43, 43, 1, 518400, 0xa4b7c331
+0, 44, 44, 1, 518400, 0xb8ec424a
+0, 45, 45, 1, 518400, 0x4fa12b83
+0, 46, 46, 1, 518400, 0x55acfb38
+0, 47, 47, 1, 518400, 0xa4d66b64
+0, 48, 48, 1, 518400, 0xd4008e86
+0, 49, 49, 1, 518400, 0x88729869
+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, 53919, 53919, 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, 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, 196369, 196369, 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/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
--- /dev/null
+++ b/tests/ref/fate/unknown_layout-ac3
@@ -0,0 +1 @@
+bbb7550d6d93973c10f4ee13c87cf799
diff --git a/tests/ref/fate/unknown_layout-pcm b/tests/ref/fate/unknown_layout-pcm
new file mode 100644
index 0000000..73c6a2d
--- /dev/null
+++ b/tests/ref/fate/unknown_layout-pcm
@@ -0,0 +1 @@
+4dada0795adf50f7a0e60861658f86ea
diff --git a/tests/ref/fate/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
--- /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/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
--- /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..38843c0 100644
--- a/tests/ref/fate/vp8-sign-bias
+++ b/tests/ref/fate/vp8-sign-bias
@@ -6,4 +6,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..1fba74e 100644
--- a/tests/ref/fate/vp8-size-change
+++ b/tests/ref/fate/vp8-size-change
@@ -1,31 +1,31 @@
-#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
+#tb 0: 1/30
+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/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
--- /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
--- /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
--- /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..361314b
--- /dev/null
+++ b/tests/ref/lavf-fate/mp3
@@ -0,0 +1,3 @@
+7fcf80c2059b5c058a6cdd2e2f798b6c *./tests/data/lavf-fate/lavf.mp3
+96366 ./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
--- /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..2a5cd81 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
-./tests/data/lavf/lavf.aif CRC=0x3a1da17e
+b0d42747a6fc99a5cd1ab0e861671f3a *./tests/data/lavf/lavf.aif
+90182 ./tests/data/lavf/lavf.aif
+./tests/data/lavf/lavf.aif CRC=0xf1ae5536
diff --git a/tests/ref/lavf/alaw b/tests/ref/lavf/alaw
index d93d6fc..65bcf99 100644
--- a/tests/ref/lavf/alaw
+++ b/tests/ref/lavf/alaw
@@ -1,3 +1,3 @@
-652d96e474869ddb01403743deb35117 *./tests/data/lavf/lavf.al
-44100 ./tests/data/lavf/lavf.al
-./tests/data/lavf/lavf.al CRC=0xf9643112
+8bce9c3758b0d38da2e0718b6ab57fb4 *./tests/data/lavf/lavf.al
+45056 ./tests/data/lavf/lavf.al
+./tests/data/lavf/lavf.al CRC=0x5e6d372b
diff --git a/tests/ref/lavf/asf b/tests/ref/lavf/asf
index 572cfc5..cfa53dc 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
-./tests/data/lavf/lavf.asf CRC=0xf6340a10
+3937dfece4b48c0cdd8f44bcab3cdd2d *./tests/data/lavf/lavf.asf
+333581 ./tests/data/lavf/lavf.asf
+./tests/data/lavf/lavf.asf CRC=0x51485213
diff --git a/tests/ref/lavf/ast b/tests/ref/lavf/ast
new file mode 100644
index 0000000..72a9824
--- /dev/null
+++ b/tests/ref/lavf/ast
@@ -0,0 +1,3 @@
+7fa8cd2dd7453428e71930a7c65f7b62 *./tests/data/lavf/lavf.ast
+181696 ./tests/data/lavf/lavf.ast
+./tests/data/lavf/lavf.ast CRC=0x7bd585ff
diff --git a/tests/ref/lavf/au b/tests/ref/lavf/au
index 71cfdcb..b9b70a1 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
-./tests/data/lavf/lavf.au CRC=0x3a1da17e
+dc54f834a23ddc0c086a86f0cef898d7 *./tests/data/lavf/lavf.au
+90144 ./tests/data/lavf/lavf.au
+./tests/data/lavf/lavf.au CRC=0xf1ae5536
diff --git a/tests/ref/lavf/avi b/tests/ref/lavf/avi
index 08ae042..056d0c7 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
+feb26a85f820ede7e521a55be565f3b1 *./tests/data/lavf/lavf.avi
+330806 ./tests/data/lavf/lavf.avi
+./tests/data/lavf/lavf.avi CRC=0x4780846b
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..f2ae9c3
--- /dev/null
+++ b/tests/ref/lavf/caf
@@ -0,0 +1,3 @@
+6c97bfc8e455d5fb8b3b45806857a953 *./tests/data/lavf/lavf.caf
+90235 ./tests/data/lavf/lavf.caf
+./tests/data/lavf/lavf.caf CRC=0xf1ae5536
diff --git a/tests/ref/lavf/dpx b/tests/ref/lavf/dpx
index a9f1169..ddf9a2b 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=0xb6310a70
+407168 ./tests/data/images/dpx/02.dpx
+b3058eff9f0862a8e91747b8f5e5bd51 *./tests/data/images/dpx/02.dpx
+./tests/data/images/dpx/%02d.dpx CRC=0x4630c023
+812672 ./tests/data/images/dpx/02.dpx
diff --git a/tests/ref/lavf/dv_fmt b/tests/ref/lavf/dv_fmt
index c2b7335..ed8c5cc 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
+78db8504eefb660ed205b417157d4f44 *./tests/data/lavf/lavf.dv
+3600000 ./tests/data/lavf/lavf.dv
+./tests/data/lavf/lavf.dv CRC=0x1cec8738
+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..6f67365 100644
--- a/tests/ref/lavf/ffm
+++ b/tests/ref/lavf/ffm
@@ -1,3 +1,3 @@
-f3f0c42283b75bc826f499f048085c27 *./tests/data/lavf/lavf.ffm
+d33fae310a7f6db1dc7fb74d1a9e0e6a *./tests/data/lavf/lavf.ffm
376832 ./tests/data/lavf/lavf.ffm
-./tests/data/lavf/lavf.ffm CRC=0xdd24439e
+./tests/data/lavf/lavf.ffm CRC=0x5b136bb1
diff --git a/tests/ref/lavf/flm b/tests/ref/lavf/flm
new file mode 100644
index 0000000..59aac92
--- /dev/null
+++ b/tests/ref/lavf/flm
@@ -0,0 +1,3 @@
+ef4783171ebbc38855331c9ead978322 *./tests/data/lavf/lavf.flm
+10137636 ./tests/data/lavf/lavf.flm
+./tests/data/lavf/lavf.flm CRC=0xcdf15757
diff --git a/tests/ref/lavf/flv_fmt b/tests/ref/lavf/flv_fmt
index 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..531cd1e 100644
--- a/tests/ref/lavf/gif
+++ b/tests/ref/lavf/gif
@@ -1,3 +1,3 @@
-e6089fd4ef3b9df44090ab3650bdd810 *./tests/data/lavf/lavf.gif
-2906401 ./tests/data/lavf/lavf.gif
-./tests/data/lavf/lavf.gif CRC=0xe5605ff6
+e35f5ea283bbcb249818e0078ec72664 *./tests/data/lavf/lavf.gif
+2011766 ./tests/data/lavf/lavf.gif
+./tests/data/lavf/lavf.gif CRC=0x0dc5477c
diff --git a/tests/ref/lavf/gxf b/tests/ref/lavf/gxf
index e25d4f2..9e7871d 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
+c8b3a8e3ba0185ce39122ac150c12bc3 *./tests/data/lavf/lavf.gxf
+795876 ./tests/data/lavf/lavf.gxf
+./tests/data/lavf/lavf.gxf CRC=0x147ff044
+b26bd3cb439dff8b33cd74a27a3fc2d6 *./tests/data/lavf/lavf.gxf
+794656 ./tests/data/lavf/lavf.gxf
+./tests/data/lavf/lavf.gxf CRC=0xe0199511
+e4721383461d7a9feae41435567c9257 *./tests/data/lavf/lavf.gxf
+795876 ./tests/data/lavf/lavf.gxf
+./tests/data/lavf/lavf.gxf CRC=0xd9d58865
diff --git a/tests/ref/lavf/ircam b/tests/ref/lavf/ircam
new file mode 100644
index 0000000..e29a7ad
--- /dev/null
+++ b/tests/ref/lavf/ircam
@@ -0,0 +1,3 @@
+2cfae025de1b13098ef84a5e7f9947aa *./tests/data/lavf/lavf.ircam
+91136 ./tests/data/lavf/lavf.ircam
+./tests/data/lavf/lavf.ircam CRC=0xf1ae5536
diff --git a/tests/ref/lavf/ismv b/tests/ref/lavf/ismv
new file mode 100644
index 0000000..6f9f57b
--- /dev/null
+++ b/tests/ref/lavf/ismv
@@ -0,0 +1,9 @@
+a24a0426b5f8dc896daaf18502e38790 *./tests/data/lavf/lavf.ismv
+312263 ./tests/data/lavf/lavf.ismv
+./tests/data/lavf/lavf.ismv CRC=0x9d9a638a
+1b98502911dd19a9792777de67922db2 *./tests/data/lavf/lavf.ismv
+321189 ./tests/data/lavf/lavf.ismv
+./tests/data/lavf/lavf.ismv CRC=0xe8130120
+a24a0426b5f8dc896daaf18502e38790 *./tests/data/lavf/lavf.ismv
+312263 ./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 4a12f89..64979b2 100644
--- a/tests/ref/lavf/mkv
+++ b/tests/ref/lavf/mkv
@@ -1,3 +1,6 @@
-7aa1846929e5fa4f5f2b1a0bc243218f *./tests/data/lavf/lavf.mkv
-320262 ./tests/data/lavf/lavf.mkv
-./tests/data/lavf/lavf.mkv CRC=0x7d5d3cda
+b53f31e572394f225aff0bc82b5d1cc9 *./tests/data/lavf/lavf.mkv
+472553 ./tests/data/lavf/lavf.mkv
+./tests/data/lavf/lavf.mkv CRC=0x4780846b
+84dcb326fe85aeeb5768beb44372f248 *./tests/data/lavf/lavf.mkv
+320297 ./tests/data/lavf/lavf.mkv
+./tests/data/lavf/lavf.mkv CRC=0x4780846b
diff --git a/tests/ref/lavf/mmf b/tests/ref/lavf/mmf
index 947abc7..fea8015 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
-./tests/data/lavf/lavf.mmf CRC=0x8dea1388
+b165af6f2e5c6c1de733e9d3848bcebb *./tests/data/lavf/lavf.mmf
+22611 ./tests/data/lavf/lavf.mmf
+./tests/data/lavf/lavf.mmf CRC=0x03633476
diff --git a/tests/ref/lavf/mov b/tests/ref/lavf/mov
index f73cd4f..2ed8ad0 100644
--- a/tests/ref/lavf/mov
+++ b/tests/ref/lavf/mov
@@ -1,3 +1,12 @@
-8404cccff020ab07fbfe9c713bc98c33 *./tests/data/lavf/lavf.mov
-356797 ./tests/data/lavf/lavf.mov
-./tests/data/lavf/lavf.mov CRC=0xe3f4950d
+fcbe7806047914d9751fd9053009df69 *./tests/data/lavf/lavf.mov
+367365 ./tests/data/lavf/lavf.mov
+./tests/data/lavf/lavf.mov CRC=0xb2f59ab4
+72eac0051107a16e41d5263dab640f26 *./tests/data/lavf/lavf.mov
+358455 ./tests/data/lavf/lavf.mov
+./tests/data/lavf/lavf.mov CRC=0xb2f59ab4
+cf6ea2e8d4d16626d9dbd9e3fb802ce6 *./tests/data/lavf/lavf.mov
+367549 ./tests/data/lavf/lavf.mov
+./tests/data/lavf/lavf.mov CRC=0x6e82384a
+7c932d24837f46ef57d3e40a61331565 *./tests/data/lavf/lavf.mov
+357837 ./tests/data/lavf/lavf.mov
+./tests/data/lavf/lavf.mov CRC=0xb2f59ab4
diff --git a/tests/ref/lavf/mpg b/tests/ref/lavf/mpg
index e4c8ae0..798ee03 100644
--- a/tests/ref/lavf/mpg
+++ b/tests/ref/lavf/mpg
@@ -1,3 +1,9 @@
-7df31ba8a5909e3c88b1d1a3f93c4ec2 *./tests/data/lavf/lavf.mpg
+ddc5cd5469eb8a0500f8a725baead5e5 *./tests/data/lavf/lavf.mpg
372736 ./tests/data/lavf/lavf.mpg
-./tests/data/lavf/lavf.mpg CRC=0xdd24439e
+./tests/data/lavf/lavf.mpg CRC=0x5b136bb1
+7962eab004026dd7a8c0417470cdf574 *./tests/data/lavf/lavf.mpg
+389120 ./tests/data/lavf/lavf.mpg
+./tests/data/lavf/lavf.mpg CRC=0xbbbf92bc
+bb22933de60193bce9032f67ce6fcc23 *./tests/data/lavf/lavf.mpg
+372736 ./tests/data/lavf/lavf.mpg
+./tests/data/lavf/lavf.mpg CRC=0x5b136bb1
diff --git a/tests/ref/lavf/mulaw b/tests/ref/lavf/mulaw
index bd54084..c6fa058 100644
--- a/tests/ref/lavf/mulaw
+++ b/tests/ref/lavf/mulaw
@@ -1,3 +1,3 @@
-ad492935e361f830f2f8302aa102701d *./tests/data/lavf/lavf.ul
-44100 ./tests/data/lavf/lavf.ul
-./tests/data/lavf/lavf.ul CRC=0x4515fa26
+e64027a96ad5907ee281deff3286da0a *./tests/data/lavf/lavf.ul
+45056 ./tests/data/lavf/lavf.ul
+./tests/data/lavf/lavf.ul CRC=0xe028b50a
diff --git a/tests/ref/lavf/mxf b/tests/ref/lavf/mxf
index c69e278..b1e46e9 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
+7788939d349d09a7f9b546e59376a496 *./tests/data/lavf/lavf.mxf
+560697 ./tests/data/lavf/lavf.mxf
+./tests/data/lavf/lavf.mxf CRC=0xb69f428b
+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..72e59e8 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
+56c403dd91ae1dd4569348381b2b43a4 *./tests/data/lavf/lavf.nut
+319902 ./tests/data/lavf/lavf.nut
+./tests/data/lavf/lavf.nut CRC=0x4780846b
diff --git a/tests/ref/lavf/ogg b/tests/ref/lavf/ogg
index ea827ac..584e09b 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
-./tests/data/lavf/lavf.ogg CRC=0x3a1da17e
+ce1734741fa50c6c85f9cc8f410a720c *./tests/data/lavf/lavf.ogg
+13985 ./tests/data/lavf/lavf.ogg
+./tests/data/lavf/lavf.ogg CRC=0x37a143ea
diff --git a/tests/ref/lavf/pam b/tests/ref/lavf/pam
index 636a419..d21ccd7 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
+587284e40b78accd54fa92fdb7ca29f4 *./tests/data/images/pam/02.pam
+./tests/data/images/pam/%02d.pam CRC=0x418d2963
+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..4043f7a 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
+./tests/data/images/pgm/%02d.pgm CRC=0x418d2963
101391 ./tests/data/images/pgm/02.pgm
diff --git a/tests/ref/lavf/pixfmt b/tests/ref/lavf/pixfmt
index 186dde5..bf62d90 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
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..d396e00 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
+a3a875be9c528a2a4534a5a31230fdae *./tests/data/lavf/lavf.rm
+346424 ./tests/data/lavf/lavf.rm
diff --git a/tests/ref/lavf/rso b/tests/ref/lavf/rso
index 5878f43..648c248 100644
--- a/tests/ref/lavf/rso
+++ b/tests/ref/lavf/rso
@@ -1,3 +1,3 @@
-443b72346065d6318ca18c8395aa1d87 *./tests/data/lavf/lavf.rso
-44108 ./tests/data/lavf/lavf.rso
-./tests/data/lavf/lavf.rso CRC=0x298fd284
+f41fd78f7df981802e7caeb23648b8c0 *./tests/data/lavf/lavf.rso
+45064 ./tests/data/lavf/lavf.rso
+./tests/data/lavf/lavf.rso CRC=0x74b2b546
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..3e7e8ed
--- /dev/null
+++ b/tests/ref/lavf/smjpeg
@@ -0,0 +1,3 @@
+2f6e613e9e257545e1048d57de92ba92 *./tests/data/lavf/lavf.smjpeg
+791463 ./tests/data/lavf/lavf.smjpeg
+./tests/data/lavf/lavf.smjpeg CRC=0x557714ff
diff --git a/tests/ref/lavf/sox b/tests/ref/lavf/sox
index fc368b1..0026480 100644
--- a/tests/ref/lavf/sox
+++ b/tests/ref/lavf/sox
@@ -1,3 +1,3 @@
-683635d5cb1344e44fa96df90c3a993c *./tests/data/lavf/lavf.sox
-176432 ./tests/data/lavf/lavf.sox
-./tests/data/lavf/lavf.sox CRC=0x3a1da17e
+e6f278256f145b69ed06f35b8d3585c1 *./tests/data/lavf/lavf.sox
+180256 ./tests/data/lavf/lavf.sox
+./tests/data/lavf/lavf.sox CRC=0xf1ae5536
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..d795c27 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
+04ba219e6f56f7b0fa4a47765323d204 *./tests/data/lavf/lavf.ts
+407020 ./tests/data/lavf/lavf.ts
+./tests/data/lavf/lavf.ts CRC=0xcc2dc628
diff --git a/tests/ref/lavf/voc b/tests/ref/lavf/voc
index 3131960..062da63 100644
--- a/tests/ref/lavf/voc
+++ b/tests/ref/lavf/voc
@@ -1,3 +1,3 @@
-ae01db5200e569371d4c27316575344c *./tests/data/lavf/lavf.voc
-44305 ./tests/data/lavf/lavf.voc
-./tests/data/lavf/lavf.voc CRC=0x298fd284
+e4cefbeb4c20f5735de1877fbcfd8d1d *./tests/data/lavf/lavf.voc
+45261 ./tests/data/lavf/lavf.voc
+./tests/data/lavf/lavf.voc CRC=0x74b2b546
diff --git a/tests/ref/lavf/voc_s16 b/tests/ref/lavf/voc_s16
index deb7999..23e5aab 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
-./tests/data/lavf/lavf.s16.voc CRC=0xe61e3bd0
+a8225786fdbf5a2a19d1eeaf15f28632 *./tests/data/lavf/lavf.s16.voc
+180439 ./tests/data/lavf/lavf.s16.voc
+./tests/data/lavf/lavf.s16.voc CRC=0x7bd585ff
diff --git a/tests/ref/lavf/w64 b/tests/ref/lavf/w64
new file mode 100644
index 0000000..9acda83
--- /dev/null
+++ b/tests/ref/lavf/w64
@@ -0,0 +1,3 @@
+420bf38762386ae2ba8bf2e85b6cc7f2 *./tests/data/lavf/lavf.w64
+90224 ./tests/data/lavf/lavf.w64
+./tests/data/lavf/lavf.w64 CRC=0xf1ae5536
diff --git a/tests/ref/lavf/wav b/tests/ref/lavf/wav
index fa8a859..cc8ec1d 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
-./tests/data/lavf/lavf.wav CRC=0x3a1da17e
+c4afa6eafac5243aa1c202397789ccb8 *./tests/data/lavf/lavf.wav
+90188 ./tests/data/lavf/lavf.wav
+./tests/data/lavf/lavf.wav CRC=0xf1ae5536
diff --git a/tests/ref/lavf/wtv b/tests/ref/lavf/wtv
new file mode 100644
index 0000000..f54f862
--- /dev/null
+++ b/tests/ref/lavf/wtv
@@ -0,0 +1,3 @@
+237211f6aa3df9da2dfe0f7d5b8ba85c *./tests/data/lavf/lavf.wtv
+413696 ./tests/data/lavf/lavf.wtv
+./tests/data/lavf/lavf.wtv CRC=0xcc2dc628
diff --git a/tests/ref/lavf/xbm b/tests/ref/lavf/xbm
new file mode 100644
index 0000000..4cc4be6
--- /dev/null
+++ b/tests/ref/lavf/xbm
@@ -0,0 +1,3 @@
+99c20fff5d17b698b4a25282aebc3c51 *./tests/data/images/xbm/02.xbm
+./tests/data/images/xbm/%02d.xbm CRC=0x0f5aa5cb
+76411 ./tests/data/images/xbm/02.xbm
diff --git a/tests/ref/lavf/xwd b/tests/ref/lavf/xwd
index 3fd20c8..73f859d 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
+9e2f3d455566897692cdfda88ff10112 *./tests/data/images/xwd/02.xwd
+./tests/data/images/xwd/%02d.xwd CRC=0x418d2963
+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-alaw b/tests/ref/seek/lavf-alaw
index 4b1f8fb..84661ec 100644
--- a/tests/ref/seek/lavf-alaw
+++ b/tests/ref/seek/lavf-alaw
@@ -38,7 +38,7 @@ ret: 0 st: 0 flags:1 dts: 0.200816 pts: 0.200816 pos: 4428 size: 1024
ret: 0 st: 0 flags:0 ts:-0.904989
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024
ret: 0 st: 0 flags:1 ts: 1.989161
-ret: 0 st: 0 flags:1 dts: 1.989161 pts: 1.989161 pos: 43861 size: 239
+ret: 0 st: 0 flags:1 dts: 1.989161 pts: 1.989161 pos: 43861 size: 1024
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.883356 pts: 0.883356 pos: 19478 size: 1024
ret: 0 st:-1 flags:1 ts:-0.222493
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 1324739..681462c 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: 512 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 555 size: 208
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 728 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 771 size: 27837
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292150 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292185 size: 27834
ret: 0 st: 0 flags:0 ts: 0.788000
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292150 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292185 size: 27834
ret: 0 st: 0 flags:1 ts:-0.317000
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 728 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: 771 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: 319991 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320026 size: 209
ret: 0 st:-1 flags:0 ts: 0.365002
-ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146703 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146738 size: 27925
ret: 0 st:-1 flags:1 ts:-0.740831
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 728 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: 771 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: 292150 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292185 size: 27834
ret: 0 st: 1 flags:0 ts:-0.058000
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 512 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 555 size: 208
ret: 0 st: 1 flags:1 ts: 2.836000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 319991 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: 320026 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: 146703 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146738 size: 27925
ret: 0 st: 0 flags:0 ts:-0.482000
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 728 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 771 size: 27837
ret: 0 st: 0 flags:1 ts: 2.413000
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292150 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: 292185 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: 512 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 555 size: 208
ret: 0 st:-1 flags:0 ts:-0.904994
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 728 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 771 size: 27837
ret: 0 st:-1 flags:1 ts: 1.989173
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292150 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292185 size: 27834
ret: 0 st: 0 flags:0 ts: 0.883000
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292150 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292185 size: 27834
ret: 0 st: 0 flags:1 ts:-0.222000
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 728 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: 771 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: 319991 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320026 size: 209
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146703 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146738 size: 27925
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 728 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 771 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..9563a0d 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: 1727 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: 1727 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: 326931 size: 1024
+ret: 0 st: 0 flags:0 ts: 0.788359
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 327955 size: 27834
+ret: 0 st: 0 flags:1 ts:-0.317500
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1727 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: 327955 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: 165209 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: 1727 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: 326931 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: 1727 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: 327955 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: 164185 size: 1024
+ret: 0 st: 0 flags:0 ts:-0.481641
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1727 size: 27837
+ret: 0 st: 0 flags:1 ts: 2.412500
+ret: 0 st: 1 flags:1 dts: 0.952018 pts: 0.952018 pos: 326931 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: 1727 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: 1727 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: 326931 size: 1024
+ret: 0 st: 0 flags:0 ts: 0.883359
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 327955 size: 27834
+ret: 0 st: 0 flags:1 ts:-0.222500
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1727 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: 327955 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: 165209 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: 1727 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-mulaw b/tests/ref/seek/lavf-mulaw
index 4b1f8fb..84661ec 100644
--- a/tests/ref/seek/lavf-mulaw
+++ b/tests/ref/seek/lavf-mulaw
@@ -38,7 +38,7 @@ ret: 0 st: 0 flags:1 dts: 0.200816 pts: 0.200816 pos: 4428 size: 1024
ret: 0 st: 0 flags:0 ts:-0.904989
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024
ret: 0 st: 0 flags:1 ts: 1.989161
-ret: 0 st: 0 flags:1 dts: 1.989161 pts: 1.989161 pos: 43861 size: 239
+ret: 0 st: 0 flags:1 dts: 1.989161 pts: 1.989161 pos: 43861 size: 1024
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.883356 pts: 0.883356 pos: 19478 size: 1024
ret: 0 st:-1 flags:1 ts:-0.222493
diff --git a/tests/ref/seek/lavf-mxf b/tests/ref/seek/lavf-mxf
index cc634a8..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.560000
-ret: 0 st: 1 flags:1 ts: 1.480000
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712
+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: 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: 1 flags:0 ts:-0.040000
+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.840000
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712
+ret: 0 st: 1 flags:1 ts: 2.835833
+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:-1 st: 1 flags:0 ts: 1.320000
-ret: 0 st: 1 flags:1 ts: 0.200000
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460288 size: 24711
+ret:-1 st: 1 flags:0 ts: 1.306667
+ret: 0 st: 1 flags:1 ts: 0.200833
ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 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.680000
-ret: 0 st: 1 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712
+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: 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 4cfe595..17cca29 100644
--- a/tests/ref/seek/lavf-mxf_d10
+++ b/tests/ref/seek/lavf-mxf_d10
@@ -7,10 +7,10 @@ ret: 0 st: 0 flags:0 ts: 0.800000
ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:4265984 size:150000
ret: 0 st: 0 flags:1 ts:-0.320000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000
-ret: 0 st: 1 flags:0 ts: 2.560000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000
-ret: 0 st: 1 flags:1 ts: 1.480000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000
+ret: 0 st: 1 flags:0 ts: 2.576667
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000
+ret: 0 st: 1 flags:1 ts: 1.470833
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000
ret: 0 st:-1 flags:0 ts: 0.365002
ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1923072 size:150000
ret: 0 st:-1 flags:1 ts:-0.740831
@@ -19,10 +19,10 @@ ret: 0 st: 0 flags:0 ts: 2.160000
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000
ret: 0 st: 0 flags:1 ts: 1.040000
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000
-ret: 0 st: 1 flags:0 ts:-0.040000
+ret: 0 st: 1 flags:0 ts:-0.058333
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000
-ret: 0 st: 1 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000
+ret: 0 st: 1 flags:1 ts: 2.835833
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000
ret: 0 st:-1 flags:0 ts: 1.730004
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000
ret: 0 st:-1 flags:1 ts: 0.624171
@@ -31,9 +31,9 @@ ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000
ret: 0 st: 0 flags:1 ts: 2.400000
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000
-ret: 0 st: 1 flags:0 ts: 1.320000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000
-ret: 0 st: 1 flags:1 ts: 0.200000
+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.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
@@ -43,10 +43,10 @@ ret: 0 st: 0 flags:0 ts: 0.880000
ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:4691968 size:150000
ret: 0 st: 0 flags:1 ts:-0.240000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000
-ret: 0 st: 1 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000
-ret: 0 st: 1 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000
+ret: 0 st: 1 flags:0 ts: 2.671667
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000
+ret: 0 st: 1 flags:1 ts: 1.565833
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000
ret: 0 st:-1 flags:0 ts: 0.460008
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:2562048 size:150000
ret: 0 st:-1 flags:1 ts:-0.645825
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 ea8eb8b..583526e 100644
--- a/tests/ref/seek/lavf-ogg
+++ b/tests/ref/seek/lavf-ogg
@@ -1,27 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 124 size: 1364
-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:-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:-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:-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:-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:-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:-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:0 ts:-1.000000
+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: 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: 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: 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: 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: 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: 143 size: 1364
+ret: 0 st: 0 flags:1 ts: 2.835828
+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: 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: 143 size: 1364
+ret: 0 st: 0 flags:1 ts: 2.412494
+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: 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: 143 size: 1364
+ret: 0 st: 0 flags:1 ts: 1.989184
+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: 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: 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: 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
--- /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-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-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
--- /dev/null
+++ b/tests/ref/seek/vsynth2-snow
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39714 size: 3640
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 27434 size: 3494
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39714 size: 3640
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 16124 size: 3244
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 27434 size: 3494
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52604 size: 3582
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52604 size: 3582
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 16124 size: 3244
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52604 size: 3582
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39714 size: 3640
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 3035
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52604 size: 3582
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 27434 size: 3494
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39714 size: 3640
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 16124 size: 3244
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-snow-ll b/tests/ref/seek/vsynth2-snow-ll
new file mode 100644
index 0000000..95a4a79
--- /dev/null
+++ b/tests/ref/seek/vsynth2-snow-ll
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902788 size: 78837
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1239090 size: 74994
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902788 size: 78837
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 605628 size: 71059
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1239090 size: 74994
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585614 size: 79731
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585614 size: 79731
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 605628 size: 71059
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585614 size: 79731
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902788 size: 78837
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 72476
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585614 size: 79731
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1239090 size: 74994
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902788 size: 78837
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 605628 size: 71059
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-svq1 b/tests/ref/seek/vsynth2-svq1
index 17bb99e..33fe33e 100644
--- a/tests/ref/seek/vsynth2-svq1
+++ b/tests/ref/seek/vsynth2-svq1
@@ -3,46 +3,46 @@ ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
ret: 0 st:-1 flags:1 ts: 1.894167
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 517568 size: 25636
-ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:0 ts: 0.788359
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 326556 size: 23552
-ret: 0 st: 0 flags:1 ts:-0.320000
+ret: 0 st: 0 flags:1 ts:-0.317500
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
ret:-1 st:-1 flags:0 ts: 2.576668
ret: 0 st:-1 flags:1 ts: 1.470835
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 517568 size: 25636
-ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:0 ts: 0.365000
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 157040 size: 21896
-ret: 0 st: 0 flags:1 ts:-0.760000
+ret: 0 st: 0 flags:1 ts:-0.740859
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
ret:-1 st:-1 flags:0 ts: 2.153336
ret: 0 st:-1 flags:1 ts: 1.047503
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 326556 size: 23552
-ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:0 ts:-0.058359
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
-ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 ts: 2.835859
ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 722804 size: 25888
ret: 0 st:-1 flags:0 ts: 1.730004
ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 722804 size: 25888
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 157040 size: 21896
-ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:0 ts:-0.481641
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
-ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 ts: 2.412500
ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 722804 size: 25888
ret: 0 st:-1 flags:0 ts: 1.306672
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 517568 size: 25636
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
-ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:0 ts:-0.905000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
-ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 ts: 1.989141
ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 722804 size: 25888
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 326556 size: 23552
ret: 0 st:-1 flags:1 ts:-0.222493
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
+ret:-1 st: 0 flags:0 ts: 2.671641
+ret: 0 st: 0 flags:1 ts: 1.565859
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 517568 size: 25636
ret: 0 st:-1 flags:0 ts: 0.460008
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 157040 size: 21896
diff --git a/tests/ref/seek/vsynth2-wmv1 b/tests/ref/seek/vsynth2-wmv1
index 85465b3..0f073b2 100644
--- a/tests/ref/seek/vsynth2-wmv1
+++ b/tests/ref/seek/vsynth2-wmv1
@@ -18,15 +18,15 @@ ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54758 size: 9931
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 8990
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115812 size: 11487
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115806 size: 11486
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115812 size: 11487
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115806 size: 11486
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29794 size: 8796
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 8990
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115812 size: 11487
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115806 size: 11486
ret: 0 st:-1 flags:0 ts: 1.306672
ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83742 size: 11099
ret: 0 st:-1 flags:1 ts: 0.200839
@@ -34,7 +34,7 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 8990
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 8990
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115812 size: 11487
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115806 size: 11486
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54758 size: 9931
ret:-1 st:-1 flags:1 ts:-0.222493
diff --git a/tests/ref/seek/vsynth2-wmv2 b/tests/ref/seek/vsynth2-wmv2
index 53680d0..a29f0d4 100644
--- a/tests/ref/seek/vsynth2-wmv2
+++ b/tests/ref/seek/vsynth2-wmv2
@@ -2,13 +2,13 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8917
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8917
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11170
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11169
ret: 0 st: 0 flags:0 ts: 0.800000
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54534 size: 9989
ret:-1 st: 0 flags:1 ts:-0.320000
ret:-1 st:-1 flags:0 ts: 2.576668
ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11170
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11169
ret: 0 st: 0 flags:0 ts: 0.360000
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29588 size: 8839
ret:-1 st: 0 flags:1 ts:-0.760000
@@ -18,29 +18,29 @@ ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54534 size: 9989
ret: 0 st: 0 flags:0 ts:-0.040000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8917
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116062 size: 11554
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116066 size: 11554
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116062 size: 11554
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116066 size: 11554
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29588 size: 8839
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8917
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116062 size: 11554
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116066 size: 11554
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11170
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11169
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8917
ret: 0 st: 0 flags:0 ts:-0.920000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8917
ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116062 size: 11554
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116066 size: 11554
ret: 0 st:-1 flags:0 ts: 0.883340
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54534 size: 9989
ret:-1 st:-1 flags:1 ts:-0.222493
ret:-1 st: 0 flags:0 ts: 2.680000
ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11170
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83764 size: 11169
ret: 0 st:-1 flags:0 ts: 0.460008
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29588 size: 8839
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/vsynth/vsynth1-amv b/tests/ref/vsynth/vsynth1-amv
new file mode 100644
index 0000000..f7c7f57
--- /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..e4434e8
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-avui
@@ -0,0 +1,4 @@
+0e71be51f4e0701d91ff7fa4d9ea0533 *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 3a990c5..dbe2c37 100644
--- a/tests/ref/vsynth/vsynth1-dnxhd-1080i
+++ b/tests/ref/vsynth/vsynth1-dnxhd-1080i
@@ -1,4 +1,4 @@
-2412f206f5efcbbcc3f2bba0c86b73d4 *tests/data/fate/vsynth1-dnxhd-1080i.mov
-3031875 tests/data/fate/vsynth1-dnxhd-1080i.mov
-34076f61254997c8157eafed1c916472 *tests/data/fate/vsynth1-dnxhd-1080i.out.rawvideo
+124c991ee3ac0caef39a58a45287a762 *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
--- /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
--- /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-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
--- /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-j2k b/tests/ref/vsynth/vsynth1-j2k
new file mode 100644
index 0000000..1e2f3f2
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-j2k
@@ -0,0 +1,4 @@
+e6e3d338eeb394d6fadc7bbb55fa9e6e *tests/data/fate/vsynth1-j2k.avi
+2306902 tests/data/fate/vsynth1-j2k.avi
+ee9b245b3b07eed90bc6f2147bbd916c *tests/data/fate/vsynth1-j2k.out.rawvideo
+stddev: 5.47 PSNR: 33.37 MAXDIFF: 64 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-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
--- /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
--- /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 9a917d0..b6da11c 100644
--- a/tests/ref/vsynth/vsynth1-mpeg4
+++ b/tests/ref/vsynth/vsynth1-mpeg4
@@ -1,4 +1,4 @@
-59a9e2eed314abface66aaf1b45eb8f2 *tests/data/fate/vsynth1-mpeg4.mp4
-540180 tests/data/fate/vsynth1-mpeg4.mp4
-8828a375448dc5c2215163ba70656f89 *tests/data/fate/vsynth1-mpeg4.out.rawvideo
+a2acdf772bf7b7641079d8a03ea03ccf *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
--- /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
--- /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 ac30a6a..16517ee 100644
--- a/tests/ref/vsynth/vsynth1-prores
+++ b/tests/ref/vsynth/vsynth1-prores
@@ -1,4 +1,4 @@
-2566517b15c62887bd94daaab1b1a85b *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
+6f7ce83099b35e5af0cf484f2e9f1f4f *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..4e33ec7
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-prores_ks
@@ -0,0 +1,4 @@
+2f760d0e579bbbe24a922e9cbcf3294c *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 c9c8ccf..9bd79cc 100644
--- a/tests/ref/vsynth/vsynth1-qtrle
+++ b/tests/ref/vsynth/vsynth1-qtrle
@@ -1,4 +1,4 @@
-7d75328a17e04796a39fe9be3a322946 *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
+4eaa59011403ce3e53f8abb5cf6d26e5 *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..425c11f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-qtrlegray
@@ -0,0 +1,4 @@
+d010ff7be190f4cd053d79ee7f601ce2 *tests/data/fate/vsynth1-qtrlegray.mov
+5113294 tests/data/fate/vsynth1-qtrlegray.mov
+29def4aed035ed65d3a89f7d382fccbe *tests/data/fate/vsynth1-qtrlegray.out.rawvideo
+stddev: 25.95 PSNR: 19.85 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
--- /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
--- /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
--- /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
--- /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 0f8a6b2..6be76e1 100644
--- a/tests/ref/vsynth/vsynth1-svq1
+++ b/tests/ref/vsynth/vsynth1-svq1
@@ -1,4 +1,4 @@
-5c9d8734693f3cab57f61e76b5b6da7d *tests/data/fate/vsynth1-svq1.mov
-1334367 tests/data/fate/vsynth1-svq1.mov
+ea441979fa5bf694d1f6cee958d56560 *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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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..743c6ff
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-avui
@@ -0,0 +1,4 @@
+ec8b12fd9f1f7737f7e23419457fe431 *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 27c79a5..f657eb4 100644
--- a/tests/ref/vsynth/vsynth2-dnxhd-1080i
+++ b/tests/ref/vsynth/vsynth2-dnxhd-1080i
@@ -1,4 +1,4 @@
-65ca6385b565b6ea9a2e28150eef1d46 *tests/data/fate/vsynth2-dnxhd-1080i.mov
-3031875 tests/data/fate/vsynth2-dnxhd-1080i.mov
-42262a2325441b38b3b3c8a42d888e7d *tests/data/fate/vsynth2-dnxhd-1080i.out.rawvideo
+5d7ab75ce6e547ed63a7a0eacf18f078 *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
--- /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
--- /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-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
--- /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-j2k b/tests/ref/vsynth/vsynth2-j2k
new file mode 100644
index 0000000..4f038fe
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-j2k
@@ -0,0 +1,4 @@
+fc49816ba28731689872f5c87ca91c10 *tests/data/fate/vsynth2-j2k.avi
+1151144 tests/data/fate/vsynth2-j2k.avi
+ec5218eec33a021945c28c72093382a5 *tests/data/fate/vsynth2-j2k.out.rawvideo
+stddev: 4.54 PSNR: 34.99 MAXDIFF: 61 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-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
--- /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
--- /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 4d96557..399ef58 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4
+++ b/tests/ref/vsynth/vsynth2-mpeg4
@@ -1,4 +1,4 @@
-8c9afbf564008a8ce6719cc3546deae1 *tests/data/fate/vsynth2-mpeg4.mp4
-119833 tests/data/fate/vsynth2-mpeg4.mp4
-90a3577850239083a9042bef33c50e85 *tests/data/fate/vsynth2-mpeg4.out.rawvideo
+04f74c54f4db25e1d454ede9216632c1 *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
--- /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
--- /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 9a834ed..b5c80e2 100644
--- a/tests/ref/vsynth/vsynth2-prores
+++ b/tests/ref/vsynth/vsynth2-prores
@@ -1,4 +1,4 @@
-28755ce05e812adbb8b7c180318ffba8 *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
+a6351254cccdbc7147600951a798172a *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..b9902db
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-prores_ks
@@ -0,0 +1,4 @@
+12c24e7305e131388d5beb2a980293f4 *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 ceee854..5f53608 100644
--- a/tests/ref/vsynth/vsynth2-qtrle
+++ b/tests/ref/vsynth/vsynth2-qtrle
@@ -1,4 +1,4 @@
-4805f35ca6e03b9279cc18f3f7356366 *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
+f2aea57de225cccadb936bba4086a836 *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..4568391
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-qtrlegray
@@ -0,0 +1,4 @@
+fa10a87e9cf648d635340b90e41d2d38 *tests/data/fate/vsynth2-qtrlegray.mov
+5111283 tests/data/fate/vsynth2-qtrlegray.mov
+f63b5ebdfdba750e547c25131b0a3fd1 *tests/data/fate/vsynth2-qtrlegray.out.rawvideo
+stddev: 19.42 PSNR: 22.36 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
--- /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
--- /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
--- /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
--- /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 251f72d..bdde55e 100644
--- a/tests/ref/vsynth/vsynth2-svq1
+++ b/tests/ref/vsynth/vsynth2-svq1
@@ -1,4 +1,4 @@
-138ad38281570f1a3b68d63ed896435d *tests/data/fate/vsynth2-svq1.mov
-766851 tests/data/fate/vsynth2-svq1.mov
+11da7948184b3fee455f66cc5f6f8ca5 *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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /dev/null
+++ b/tests/ref/vsynth1/cljr
@@ -0,0 +1,4 @@
+041982e4fa83428c621a127647d47b3f *./tests/data/vsynth1/cljr.avi
+5075660 ./tests/data/vsynth1/cljr.avi
+e1c4c96c74de3435d0f9f6118c5ed9b5 *./tests/data/cljr.vsynth1.out.yuv
+stddev: 30.53 PSNR: 18.43 MAXDIFF: 225 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth1/yuv b/tests/ref/vsynth1/yuv
new file mode 100644
index 0000000..6d8b143
--- /dev/null
+++ b/tests/ref/vsynth1/yuv
@@ -0,0 +1,4 @@
+eaa66c3b27a2602e882befe154a8b119 *./tests/data/vsynth1/yuv.avi
+7610060 ./tests/data/vsynth1/yuv.avi
+c5ccac874dbf808e9088bc3107860042 *./tests/data/yuv.vsynth1.out.yuv
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth2/cljr b/tests/ref/vsynth2/cljr
new file mode 100644
index 0000000..f4cf7d1
--- /dev/null
+++ b/tests/ref/vsynth2/cljr
@@ -0,0 +1,4 @@
+fdc1926e0a599de94513f0a3472b598f *./tests/data/vsynth2/cljr.avi
+5075660 ./tests/data/vsynth2/cljr.avi
+7df03229ee6361ea11a0d83d4926cb10 *./tests/data/cljr.vsynth2.out.yuv
+stddev: 10.30 PSNR: 27.87 MAXDIFF: 65 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth2/huffyuv b/tests/ref/vsynth2/huffyuv
new file mode 100644
index 0000000..e59b53c
--- /dev/null
+++ b/tests/ref/vsynth2/huffyuv
@@ -0,0 +1,4 @@
+ed66182be0d515e8b6cb970ad63162da *./tests/data/vsynth2/huffyuv.avi
+6455232 ./tests/data/vsynth2/huffyuv.avi
+dde5895817ad9d219f79a52d0bdfb001 *./tests/data/huffyuv.vsynth2.out.yuv
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth2/yuv b/tests/ref/vsynth2/yuv
new file mode 100644
index 0000000..699ebc9
--- /dev/null
+++ b/tests/ref/vsynth2/yuv
@@ -0,0 +1,4 @@
+3d5ee6d2023bc15bba898819e4977e46 *./tests/data/vsynth2/yuv.avi
+7610060 ./tests/data/vsynth2/yuv.avi
+dde5895817ad9d219f79a52d0bdfb001 *./tests/data/yuv.vsynth2.out.yuv
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/regression-funcs.sh b/tests/regression-funcs.sh
index 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
--- /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 b1bcc16..264aa4d 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
*/
@@ -54,6 +54,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)
{
@@ -107,77 +122,47 @@ static float get_f32l(uint8_t *p)
return v.f;
}
-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;
uint64_t dev;
- FILE *f[2];
uint8_t buf[2][SIZE];
uint64_t psnr;
- 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;
int maxdist = 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 {
- 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;
-
- 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;
- }
+ noseek = fseek(f[0], 0, SEEK_SET) ||
+ fseek(f[1], 0, SEEK_SET);
- 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]);
@@ -222,5 +207,58 @@ int main(int argc, char *argv[])
(int)(dev / F), (int)(dev % F),
(int)(psnr / F), (int)(psnr % F),
maxdist, size0, size1);
+ return psnr;
+}
+
+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 {
+ 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
--- /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/bisect-create b/tools/bisect-create
new file mode 100755
index 0000000..fc60e86
--- /dev/null
+++ b/tools/bisect-create
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+set -e
+
+if test "bisect-create" = "`basename $0`" ; then
+ echo tools/ffbisect created
+ git show master:tools/bisect-create > tools/ffbisect
+ chmod u+x tools/ffbisect
+ exit 1
+fi
+
+if ! git show master:tools/bisect-create | diff - tools/ffbisect > /dev/null ; then
+ echo updating tools/ffbisect script to HEAD.
+ git show master:tools/bisect-create > tools/ffbisect
+ chmod u+x tools/ffbisect
+ tools/ffbisect $*
+ exit 0
+fi
+
+case "$1" in
+ need)
+ case $2 in
+ ffmpeg|ffplay|ffprobe|ffserver)
+ echo $2.c >> tools/bisect.need
+ ;;
+ esac
+ ;;
+ start|reset)
+ echo . > tools/bisect.need
+ git bisect $*
+ ;;
+ skip)
+ git bisect $*
+ ;;
+ good|bad)
+ git bisect $*
+
+ until ls `cat tools/bisect.need` > /dev/null 2> /dev/null; do
+ git bisect skip || break
+ done
+ ;;
+ run)
+ shift # remove "run" from arguments
+ git bisect run sh -c "ls \`cat tools/bisect.need\` > /dev/null 2> /dev/null || exit 125; \"\$@\"" sh "$@"
+ ;;
+esac
diff --git a/tools/bookmarklets.html b/tools/bookmarklets.html
new file mode 100644
index 0000000..9800ab5
--- /dev/null
+++ b/tools/bookmarklets.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!--
+ This file is part of FFmpeg.
+
+ All scripts contained in this file can be considered public domain.
+ -->
+<title>FFmpeg bookmarklets</title>
+<meta charset="UTF-8">
+<script type="text/javascript">
+function convert(js) {
+ js = js.replace(/\/\*.*?\*\//g, ""); /* comments */
+ js = js.replace(/\s+/g, " ");
+ js = js.replace(/\s+\z/, "");
+ js = "(function(){" + js + "})();void 0";
+ return "javascript:" + escape(js);
+}
+function init() {
+ var pre = document.getElementsByTagName("pre");
+ for (var i = 0; pre.length > i; i++) {
+ document.getElementById(pre[i].id + "-link").href = convert(pre[i].textContent);
+ }
+}
+</script>
+<style type="text/css">
+pre { border: solid black 1px; padding: 0.2ex; font-size: 80% }
+</style>
+</head>
+<body onload="init()">
+
+<h1>Introduction</h1>
+
+The scripts in this page are
+<a href="http://en.wikipedia.org/wiki/Bookmarklet">bookmarklets</a>: store
+their link version in a bookmark, and later activate the bookmark on a page
+to run the script.
+
+<h1>TED Talks captions</h1>
+
+<p><a id="ted_talks_captions-link" href="#">Get links to the captions</a></p>
+
+<pre id="ted_talks_captions">
+d = window.open("", "sub", "width=256,height=512,resizable=yes,scrollbars=yes").document;
+l = document.getElementById("languageCode").getElementsByTagName("option");
+for (i = 1; i &lt; l.length ; i++) {
+ d.body.appendChild(p = d.createElement("p"));
+ p.appendChild(a = d.createElement("a"));
+ a.appendChild(d.createTextNode(l[i].textContent));
+ a.href="http://www.ted.com/talks/subtitles/id/" + talkID+"/lang/" + l[i].value;
+}
+</pre>
+
+</body>
+</html>
diff --git a/tools/build_libstagefright b/tools/build_libstagefright
new file mode 100644
index 0000000..8b3a093
--- /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
--- /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/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..45ac727
--- /dev/null
+++ b/tools/enum_options.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2011 Anton Khirnov
+ *
+ * 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
+ */
+
+/*
+ * 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/ffadler.c b/tools/ffadler.c
new file mode 100644
index 0000000..97e6257
--- /dev/null
+++ b/tools/ffadler.c
@@ -0,0 +1,87 @@
+/*
+* Copyright (c) 2002 Fabrice Bellard
+* 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 "config.h"
+#include "libavutil/adler32.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 int check(char *file)
+{
+ uint8_t buffer[SIZE];
+ uint32_t checksum = 1;
+ int fd;
+ int ret = 0;
+
+ if (file) fd = open(file, O_RDONLY);
+ else fd = 0;
+ if (fd == -1) {
+ printf("A32=OPEN-FAILED-%d", errno);
+ ret = 1;
+ goto end;
+ }
+
+ for (;;) {
+ ssize_t size = read(fd, buffer, SIZE);
+ if (size < 0) {
+ printf("A32=0x%08x+READ-FAILED-%d", checksum, errno);
+ ret = 2;
+ goto end;
+ } else if(!size)
+ break;
+ checksum = av_adler32_update(checksum, buffer, size);
+ }
+ close(fd);
+
+ printf("A32=0x%08x", checksum);
+end:
+ if (file)
+ printf(" *%s", file);
+ printf("\n");
+
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+ int ret = 0;
+
+ for (i = 1; i<argc; i++)
+ ret |= check(argv[i]);
+
+ if (argc == 1)
+ ret |= check(NULL);
+
+ return ret;
+}
diff --git a/tools/ffescape.c b/tools/ffescape.c
new file mode 100644
index 0000000..0530d28
--- /dev/null
+++ b/tools/ffescape.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#if HAVE_UNISTD_H
+#include <unistd.h> /* getopt */
+#endif
+
+#include "libavutil/log.h"
+#include "libavutil/bprint.h"
+
+#if !HAVE_GETOPT
+#include "compat/getopt.c"
+#endif
+
+/**
+ * @file
+ * escaping utility
+ */
+
+static void usage(void)
+{
+ printf("Escape an input string, adopting the av_get_token() escaping logic\n");
+ printf("usage: ffescape [OPTIONS]\n");
+ printf("\n"
+ "Options:\n"
+ "-e echo each input line on output\n"
+ "-f flag select an escape flag, can assume the values 'whitespace' and 'strict'\n"
+ "-h print this help\n"
+ "-i INFILE set INFILE as input file, stdin if omitted\n"
+ "-l LEVEL set the number of escaping levels, 1 if omitted\n"
+ "-m ESCAPE_MODE select escape mode between 'auto', 'backslash', 'quote'\n"
+ "-o OUTFILE set OUTFILE as output file, stdout if omitted\n"
+ "-p PROMPT set output prompt, is '=> ' by default\n"
+ "-s SPECIAL_CHARS set the list of special characters\n");
+}
+
+int main(int argc, char **argv)
+{
+ AVBPrint src;
+ char *src_buf, *dst_buf;
+ const char *outfilename = NULL, *infilename = NULL;
+ FILE *outfile = NULL, *infile = NULL;
+ const char *prompt = "=> ";
+ enum AVEscapeMode escape_mode = AV_ESCAPE_MODE_AUTO;
+ int escape_flags = 0;
+ int level = 1;
+ int echo = 0;
+ char *special_chars = NULL;
+ int c;
+
+ while ((c = getopt(argc, argv, "ef:hi:l:o:m:p:s:")) != -1) {
+ switch (c) {
+ case 'e':
+ echo = 1;
+ break;
+ case 'h':
+ usage();
+ return 0;
+ case 'i':
+ infilename = optarg;
+ break;
+ case 'f':
+ if (!strcmp(optarg, "whitespace")) escape_flags |= AV_ESCAPE_FLAG_WHITESPACE;
+ else if (!strcmp(optarg, "strict")) escape_flags |= AV_ESCAPE_FLAG_STRICT;
+ else {
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid value '%s' for option -f, "
+ "valid arguments are 'whitespace', and 'strict'\n", optarg);
+ return 1;
+ }
+ break;
+ case 'l':
+ {
+ char *tail;
+ long int li = strtol(optarg, &tail, 10);
+ if (*tail || li > INT_MAX || li < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid value '%s' for option -l, argument must be a non negative integer\n",
+ optarg);
+ return 1;
+ }
+ level = li;
+ break;
+ }
+ case 'm':
+ if (!strcmp(optarg, "auto")) escape_mode = AV_ESCAPE_MODE_AUTO;
+ else if (!strcmp(optarg, "backslash")) escape_mode = AV_ESCAPE_MODE_BACKSLASH;
+ else if (!strcmp(optarg, "quote")) escape_mode = AV_ESCAPE_MODE_QUOTE;
+ else {
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid value '%s' for option -m, "
+ "valid arguments are 'backslash', and 'quote'\n", optarg);
+ return 1;
+ }
+ break;
+ case 'o':
+ outfilename = optarg;
+ break;
+ case 'p':
+ prompt = optarg;
+ break;
+ case 's':
+ special_chars = optarg;
+ break;
+ case '?':
+ return 1;
+ }
+ }
+
+ if (!infilename || !strcmp(infilename, "-")) {
+ infilename = "stdin";
+ infile = stdin;
+ } else {
+ infile = fopen(infilename, "r");
+ }
+ if (!infile) {
+ av_log(NULL, AV_LOG_ERROR, "Impossible to open input file '%s': %s\n", infilename, strerror(errno));
+ return 1;
+ }
+
+ if (!outfilename || !strcmp(outfilename, "-")) {
+ outfilename = "stdout";
+ outfile = stdout;
+ } else {
+ outfile = fopen(outfilename, "w");
+ }
+ if (!outfile) {
+ av_log(NULL, AV_LOG_ERROR, "Impossible to open output file '%s': %s\n", outfilename, strerror(errno));
+ return 1;
+ }
+
+ /* grab the input and store it in src */
+ av_bprint_init(&src, 1, AV_BPRINT_SIZE_UNLIMITED);
+ while ((c = fgetc(infile)) != EOF)
+ av_bprint_chars(&src, c, 1);
+ av_bprint_chars(&src, 0, 1);
+
+ if (!av_bprint_is_complete(&src)) {
+ av_log(NULL, AV_LOG_ERROR, "Could not allocate a buffer for the source string\n");
+ av_bprint_finalize(&src, NULL);
+ return 1;
+ }
+ av_bprint_finalize(&src, &src_buf);
+
+ if (echo)
+ fprintf(outfile, "%s", src_buf);
+
+ /* escape */
+ dst_buf = src_buf;
+ while (level--) {
+ if (av_escape(&dst_buf, src_buf, special_chars, escape_mode, escape_flags) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Could not escape string\n");
+ return 1;
+ }
+ av_free(src_buf);
+ src_buf = dst_buf;
+ }
+
+ fprintf(outfile, "%s%s", prompt, dst_buf);
+ av_free(dst_buf);
+ return 0;
+}
diff --git a/tools/ffeval.c b/tools/ffeval.c
new file mode 100644
index 0000000..4f60688
--- /dev/null
+++ b/tools/ffeval.c
@@ -0,0 +1,138 @@
+/*
+ * 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] != '#') {
+ av_expr_parse_and_eval(&d, buf,
+ NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, 0, NULL);
+ if (echo)
+ fprintf(outfile, "%s ", buf);
+ fprintf(outfile, "%s%f\n", prompt, d);
+ }
+ count = 0;
+ } else {
+ if (count >= buf_size-1)
+ GROW_ARRAY();
+ buf[count++] = c;
+ }
+ }
+
+ av_free(buf);
+ return 0;
+}
diff --git a/tools/fourcc2pixfmt.c b/tools/fourcc2pixfmt.c
new file mode 100644
index 0000000..1a653ed
--- /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 26cb28b..167c49b 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,11 +58,11 @@ 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);
@@ -73,28 +73,32 @@ static void print_digraph(FILE *outfile, AVFilterGraph *graph)
const AVFilterContext *dst_filter_ctx = link->dst;
snprintf(dst_filter_ctx_label, sizeof(dst_filter_ctx_label),
- "%s (%s)",
+ "%s\\n(%s)",
dst_filter_ctx->name,
dst_filter_ctx->filter->name);
- fprintf(outfile, "\"%s\" -> \"%s\"",
- filter_ctx_label, dst_filter_ctx_label);
+ fprintf(outfile, "\"%s\" -> \"%s\" [ label= \"inpad:%s -> outpad:%s\\n",
+ filter_ctx_label, dst_filter_ctx_label,
+ link->srcpad->name, link->dstpad->name);
+
if (link->type == AVMEDIA_TYPE_VIDEO) {
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
fprintf(outfile,
- " [ label= \"fmt:%s w:%d h:%d tb:%d/%d\" ]",
- desc->name, link->w, link->h, link->time_base.num,
- link->time_base.den);
+ "fmt:%s w:%d h:%d tb:%d/%d",
+ desc->name,
+ link->w, link->h,
+ link->time_base.num, link->time_base.den);
} else if (link->type == AVMEDIA_TYPE_AUDIO) {
char buf[255];
av_get_channel_layout_string(buf, sizeof(buf), -1,
link->channel_layout);
fprintf(outfile,
- " [ label= \"fmt:%s sr:%d cl:%s\" ]",
+ "fmt:%s sr:%d cl:%s tb:%d/%d",
av_get_sample_fmt_name(link->format),
- link->sample_rate, buf);
+ link->sample_rate, buf,
+ link->time_base.num, link->time_base.den);
}
- fprintf(outfile, ";\n");
+ fprintf(outfile, "\" ];\n");
}
}
}
diff --git a/tools/ismindex.c b/tools/ismindex.c
index ad1f3a8..67a1927 100644
--- a/tools/ismindex.c
+++ b/tools/ismindex.c
@@ -20,7 +20,7 @@
/*
* 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.
@@ -40,6 +40,8 @@
#define mkdir(a, b) _mkdir(a)
#endif
+#include "cmdutils.h"
+
#include "libavformat/avformat.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
@@ -130,7 +132,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);
@@ -222,7 +225,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)
@@ -251,7 +254,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
--- /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
--- /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
--- /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..924a90d 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_]*'
@@ -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 98b9327..920397b 100644
--- a/tools/pktdumper.c
+++ b/tools/pktdumper.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2005 Francois Revol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/tools/plotframes b/tools/plotframes
new file mode 100755
index 0000000..f379723
--- /dev/null
+++ b/tools/plotframes
@@ -0,0 +1,164 @@
+#!/usr/bin/env perl
+
+# Copyright (c) 2007-2013 Stefano Sabatini
+#
+# This file is part of FFmpeg.
+#
+# FFmpeg is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# FFmpeg is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+=head1 NAME
+
+plotframes - Plot video frame sizes using ffprobe and gnuplot
+
+=head1 SYNOPSIS
+
+plotframes [I<options>] [I<input>]
+
+=head1 DESCRIPTION
+
+plotframes reads a multimedia files with ffprobe, and plots the
+collected video sizes with gnuplot.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--input|-i> I<infile>
+
+Specify multimedia file to read. This is the file passed to the
+ffprobe command. If not specified it is the first argument passed to
+the script.
+
+=item B<--help|--usage|-h|-?>
+
+Print a brief help message and exit.
+
+=item B<--manpage|-m>
+
+Print the man page.
+
+=item B<--output|-o> I<outfile>
+
+Set the name of the output used by gnuplot. If not specified no output
+is created. Must be used in conjunction with the B<terminal> option.
+
+=item B<--stream|--s> I<stream_specifier>
+
+Specify stream. The value must be a string containing a stream
+specifier. Default value is "v".
+
+=item B<--terminal|-t> I<terminal>
+
+Set the name of the terminal used by gnuplot. By default it is
+"x11". Must be used in conjunction with the B<output> option. Check
+the gnuplot manual for the valid values.
+
+=back
+
+=cut
+
+=head1 SEE ALSO
+
+ffprobe(1), gnuplot(1)
+
+=cut
+
+use warnings;
+use strict;
+
+use File::Temp;
+use JSON -support_by_pp;
+use Getopt::Long;
+use Pod::Usage;
+
+my $input = $ARGV[0];
+my $stream_specifier = "v";
+my $gnuplot_terminal = "x11";
+my $gnuplot_output;
+
+GetOptions (
+ 'input|i=s' => \$input,
+ 'help|usage|?|h' => sub { pod2usage ( { -verbose => 1, -exitval => 0 }) },
+ 'manpage|m' => sub { pod2usage ( { -verbose => 2, -exitval => 0 }) },
+ 'stream|s=s' => \$stream_specifier,
+ 'terminal|t=s' => \$gnuplot_terminal,
+ 'output|o=s' => \$gnuplot_output,
+ ) or pod2usage( { -message=> "Parsing error", -verbose => 1, -exitval => 1 });
+
+die "You must specify an input file\n" unless $input;
+
+# fetch data
+my @cmd = (qw{ffprobe -show_entries frame -select_streams}, $stream_specifier, "-of", "json", $input);
+print STDERR "Executing command: @cmd\n";
+my $json_struct;
+{
+ open(FH, "-|", @cmd) or die "ffprobe command failed: $!\n";
+ local $/;
+ my $json_text = <FH>;
+ close FH;
+ die "ffprobe command failed" if $?;
+ eval { $json_struct = decode_json($json_text); };
+ die "JSON parsing error: $@\n" if $@;
+}
+
+# collect and print frame statistics per pict_type
+my %stats;
+my $frames = $json_struct->{frames};
+my $frame_count = 0;
+foreach my $frame (@{$frames}) {
+ my $type = $frame->{pict_type};
+ $frame->{count} = $frame_count++;
+ if (not $stats{$type}) {
+ $stats{$type}->{tmpfile} = File::Temp->new(SUFFIX => '.dat');
+ my $fn = $stats{$type}->{tmpfile}->filename;
+ open($stats{$type}->{fh}, ">", $fn) or die "Can't open $fn";
+ }
+
+ print { $stats{$type}->{fh} }
+ "$frame->{count} ", $frame->{pkt_size} * 8 / 1000, "\n";
+}
+foreach (keys %stats) { close $stats{$_}->{fh}; }
+
+# write gnuplot script
+my %type_color_map = (
+ "I" => "red",
+ "P" => "green",
+ "B" => "blue"
+ );
+
+my $gnuplot_script_tmpfile = File::Temp->new(SUFFIX => '.gnuplot');
+my $fn = $gnuplot_script_tmpfile->filename;
+open(FH, ">", $fn) or die "Couldn't open $fn: $!";
+print FH << "EOF";
+set title "video frame sizes"
+set xlabel "frame time"
+set ylabel "frame size (Kbits)"
+set grid
+set terminal "$gnuplot_terminal"
+EOF
+
+print FH "set output \"$gnuplot_output\"\n" if $gnuplot_output;
+print FH "plot";
+my $sep = "";
+foreach my $type (keys %stats) {
+ my $fn = $stats{$type}->{tmpfile}->filename;
+ print FH "$sep\"$fn\" title \"$type frames\" with impulses";
+ print FH " linecolor rgb \"$type_color_map{$type}\"" if $type_color_map{$type};
+ $sep = ", ";
+}
+close FH;
+
+# launch gnuplot with the generated script
+system ("gnuplot", "--persist", $gnuplot_script_tmpfile->filename);
diff --git a/tools/probetest.c b/tools/probetest.c
index 678f4dd..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..c9aa6e8 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);
@@ -225,6 +235,10 @@ int main(int argc, char *argv[])
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 += moov_atom_size;
@@ -242,6 +256,10 @@ int main(int argc, char *argv[])
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..8eb7627
--- /dev/null
+++ b/tools/seek_print.c
@@ -0,0 +1,107 @@
+/*
+ * 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 <unistd.h>
+
+#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
--- /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
--- /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
--- /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/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
OpenPOWER on IntegriCloud